CORS header ‘Access-Control-Allow-Origin’ missing on response in addon but not on request - express

I am creating a Firefox extension which posts some data to a database.
I made all parts in a modular fashion and am now combining everything piece by piece.
As such I know that my code to POST data to the database works.
Now here is the part that stumps me :
When I then add this code to my firefox extension
I get the following error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:3003/timed_shot_create. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 400.
Now ofcourse CORS was nothing new and to be expected when dealing with Cross Origin Resource Sharing, it is even in the name.
But the reason why I am here is because this pertains only to the response of the POST request. The request itself is fine and allowed with the following piece of config in the server:
app.use(
cors({
//todo change to proper origin when live
origin: "moz-extension://d07f1e99-96a0-4934-8ff4-1ce222c06d0d",
method: ["GET", "POST"],
})
);
Which was later changed to:
app.use(
cors({
origin: "*",
method: ["GET", "POST"],
})
);
And then simplified even more to:
app.use(cors())
This is in Nodejs btw using cors middleware.
But none of this seems to work when it is used inside a firefox extension, as a local client page works as intended but as soon as I add this to a firefox extension I get a CORS error specifically pertaining to the reponse message.
The client side post (in the background script of the extension) is:
async function postTimedShot(post_options) {
const response = await fetch(post_endpoint, post_options);
//console.log(response);
const json_response = await response.json();
console.log(json_response);
}
let post_options = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(response_data),
};
postTimedShot(post_options);
And the api looks like this:
app.post("/timed_shot_create", (req, res) => {
console.log("Received POST request");
const data = req.body;
console.log(data);
const timeStamp = data.time_stamp;
//TODO add screenshot and Description text maybe??
//const lastName = data.last_name
const queryString =
"INSERT INTO " + timed_shots_database + " (time_stamp) VALUES (?)";
getConnection().query(queryString, [timeStamp], (err, results, fields) => {
if (err) {
console.log("Failed to insert new user: " + err);
res.sendStatus(500);
return;
}
//Todo change this message when adding more data in body
//res.header("Access-Control-Allow-Origin", "moz-extension://d07f1e99-96a0-4934-8ff4-1ce222c06d0d");
res.json({
status: "Success!!!",
time_stamp: timeStamp,
});
console.log("Inserted a new user with id: ", results.insertId);
});
});
Furthermore, this extension is only for personal use and will work with a local server under my complete control so complications due to security or cloud usage that people want to mention are appreciated but not necessary (I think, I am a bit of novice).
I will be happy to clarify anything that is unclear, or change this post if necessary, but I think it is a unique question as far as I could see on SO. Additionally if I need to provide more of the codebase I will.
I will also update this post if I find out more about this problem.
Thank you for reading :3.

After reading about this post https://stackoverflow.com/a/53025865/5055963
on SO I found out that it had to do with the permissions in the manifest of the extension.
Adding this line: "://.localhost/*".
Solved the issue for me.

Related

Get a JSON file from an AppScript backend, using an AppScript front end, without getting a CORS error?

I'm trying to build a an API-driven front end in Google AppsScript that calls a REST API hosted on AppScript to make some database queries.
I am currently simply trying to retrieve a JSON file with a GET request.
Everything I try, I get "CORS Missing Allow Origin".
My understand of CORS is that I might experience this with POST request (but maybe there's some people who have phrased their requests to get work this?)
I have a sense that the situation has changed over time, and what has worked in previous SO threads, doesn't seem to work for me now.
Sigh. I feel like Google's Documentation Team would benefit from a dedicated article to explaining how this is supposed to work.
If anyone can shed light on how I can get this to work, I've be most grateful:
client side code:
useEffect(() => {
fetch('https://script.google.com/macros/s/AKfycbz3_hgjZe0E35ZI2mw7aNs3ASkYCct77qIzL_WTOQMu_ZZeax9WpHpPIwm-MFPhZAW77g/exec/get/all', {
redirect: "follow",
headers: {
"Content-Type": "text/plain",
},
})
.then(result => result.json())
.then(rowData => setRowData(rowData))
}, []);
Server side code:
export function doGet(e) {
if (e.pathInfo.startsWith('get/all')) {
return getAllRecords(e);
}
else if (e.pathInfo.startsWith('get')) {
return getRecord(e);
}
else {
return getAllRecords(e);
//return HtmlService.createHtmlOutput('Error: invalid path- ' + e.pathInfo + '\n\n' + e.parameter + e);
}
}
function getAllRecords(e) {
// Connect to the MySQL database using the JDBC connector
const conn = Jdbc.getConnection(url, username, password);
// Construct the SELECT statement
const sql = `SELECT * FROM cars LIMIT 100`;
// Execute the INSERT statement
const stmt = conn.prepareStatement(sql);
const results = stmt.executeQuery();
// Return the inserted record with the generated id
const records = [];
while (results.next()) {
const record = {
id: results.getInt('id'),
name: results.getString('name'),
make: results.getString('make'),
price: results.getInt('price')
};
records.push(record);
}
return ContentService.createTextOutput(JSON.stringify(records)).setMimeType(ContentService.MimeType.TEXT);
// return ContentService.createTextOutput(JSON.stringify(records)).setMimeType(ContentService.MimeType.JAVASCRIPT);
}
I've tried various combination of MIME Type, and request headers and I'll try any combinations people suggest.
In order to use pathInfo, in this case, it is required to use the access token. I thought that this might be the reason for your current issue. But, when the access token is used, I'm worried that is might not be useful for your actual situation. So, in this answer, I would like to propose the following 2 patterns.
Pattern 1:
In this pattern, your script is modified using the access token. In this case, please modify your Javascript as follows.
From:
fetch('https://script.google.com/macros/s/AKfycbz3_hgjZe0E35ZI2mw7aNs3ASkYCct77qIzL_WTOQMu_ZZeax9WpHpPIwm-MFPhZAW77g/exec/get/all', {
redirect: "follow",
headers: {
"Content-Type": "text/plain",
},
})
.then(result => result.json())
.then(rowData => setRowData(rowData))
To:
const accessToken = "###"; // Please set your access token.
fetch('https://script.google.com/macros/s/AKfycbz3_hgjZe0E35ZI2mw7aNs3ASkYCct77qIzL_WTOQMu_ZZeax9WpHpPIwm-MFPhZAW77g/exec/get/all?access_token=' + accessToken)
.then(result => result.json())
.then(rowData => setRowData(rowData))
When you use the access token, please include the scopes of Drive API. Please be careful about this.
Pattern 2:
In this pattern, I would like to propose the modification without using the access token. When the access token cannot be used, unfortunately, pathInfo cannot be used. So, in this pattern, the query parameter is used instead of pathInfo.
Please modify your Javascript as follows.
From:
fetch('https://script.google.com/macros/s/AKfycbz3_hgjZe0E35ZI2mw7aNs3ASkYCct77qIzL_WTOQMu_ZZeax9WpHpPIwm-MFPhZAW77g/exec/get/all', {
redirect: "follow",
headers: {
"Content-Type": "text/plain",
},
})
.then(result => result.json())
.then(rowData => setRowData(rowData))
To:
fetch('https://script.google.com/macros/s/AKfycbz3_hgjZe0E35ZI2mw7aNs3ASkYCct77qIzL_WTOQMu_ZZeax9WpHpPIwm-MFPhZAW77g/exec?value=get%2Fall') // or ?value=get
.then(result => result.json())
.then(rowData => setRowData(rowData))
And also, please modify doGet of your Google Apps Script as follows.
Modified script:
function doGet(e) {
if (e.parameter.value == "get/all") {
return getAllRecords(e);
} else if (e.parameter.value = "get") {
return getRecord(e);
} else {
return getAllRecords(e);
}
}
Note:
In this modification, it supposes that your getAllRecords(e) works fine. Please be careful about this.
And, in this modification, it supposes that your Web Apps is deployed as Execute as: Me and Who has access to the app: Anyone. Please be careful about this.
When you modified the Google Apps Script of Web Apps, please modify the deployment as a new version. By this, the modified script is reflected in Web Apps. Please be careful about this.
You can see the detail of this in my report "Redeploying Web Apps without Changing URL of Web Apps for new IDE (Author: me)".
Thit is a sample modification. So, please modify this for your actual situation.
Reference:
Taking advantage of Web Apps with Google Apps Script (Author: me)

CORS 400 Bad Request with fetch, express server

I'm trying to send a POST request from 127.0.0.1:8080 to my express server in localhost:3000/trips
I'm having a lot of problem with the cors configuration
First, this is my method to do the POST request
async modifyTrip() {
let json = {
data: "test",
mezzo: "test",
coordinate: ["test"],
tappe: ["test"],
};
let modifyform = document.getElementById("add-form");
modifyform.onsubmit = async (e) => {
e.preventDefault();
await fetch("http://localhost:3000/trips", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: json,
});
};
}
On the server side if I put cors options at that point returns me that error:
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(
cors({
"Access-Control-Allow-Origin": "*",
"Allow-Methods": "GET, POST, DELETE, FETCH",
})
);
app.use("/user", userRoutes);
app.use("/trips", tripsRoutes);
If I try to change the position the error is different my it always gives me problem
app.use(
cors({
"Access-Control-Allow-Origin": "*",
"Allow-Methods": "GET, POST, DELETE, FETCH",
})
);
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use("/user", userRoutes);
app.use("/trips", tripsRoutes);
I don't think the matter is of where I put it, but I can't fix this problem anyway. Maybe I have to change some headers in my client side, but i really can't figure it out
Thank you.
It's a 400 Bad Request error, so look up what that means:
The HyperText Transfer Protocol (HTTP) 400 Bad Request response status code indicates that the server cannot or will not process the request due to something that is perceived to be a client error (for example, malformed request syntax, invalid request message framing, or deceptive request routing).
So something is wrong with the request and the server is complaining (before it gets to the bit of code which would add the CORS response headers). The CORS error is a side-effect, not the main problem.
If you look at the Network tab of your browser's developer tools, you will be able to examine the request.
The body will look something like this:
[object Object]
Now, you said (using a Content-Type header) you were POSTing JSON, but [object Object] is not JSON (or even a usable representation of your data).
You need to pass JSON to body and not an object. Since you are passing an object, it gets stringified using the default JS mechanism (which gives "[object Object]").
Use JSON.stringify(your_object) to convert it to JSON.

Shopify API Cross Domain Ajax Request

I am using the below code to get the customer details from shopify. I have redirected my domain to the other domain from the shopify admin.
function setEmailWithLoggedInUser(callback) {
$.ajax({
url: 'https://new-website-shopify.myshopify.com/admin/customers/'+__st.cid+'.json',
crossDomain: true,
beforeSend: function(xhr) {
xhr.setRequestHeader("Authorization", "Basic XXXXXXXXXXXX")
}, success: function(data){
console.log(data);
if(callback)
callback();
}
})
I have done a lot of work around but unable to find the solution.
I am getting this error:
Failed to load resource: the server responded with a status of 404
(Not Found)
XMLHttpRequest cannot load
https://new-website-shopify.myshopify.com/admin/customers/7094124372.json.
Response to preflight request doesn't pass access control check:
No 'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'https://www.beirutshopping.com' is therefore not
allowed access. The response had HTTP status code 404.
I will save you some headaches with this answer. You cannot call /admin from the front-end of a store, as that exposes your access token to the public. Instead, if you want to access the API from the front-end, use the App Proxy pattern, allowing you to securely make Ajax calls to accomplish your goals.
As it is, you are almost certain to fail, and any success you hack into existence will quickly expose your shop to horrors. Like being replaced with sad pandas, or otherwise being reckd.
var cors = require('cors');
router.use(cors({
origin: '*'
}));
//var config = require('../config/config.json');
//testing /* GET home page. */
router.get('/', function (req, res, next) {
res.setHeader("Content-Type", "application/liquid");
res.setHeader("Access-Control-Allow-Origin", "*");
res.render('index', {
title: 'Store Locator'
});
});

Loading Data from Behance API in React Component

I am trying to load Behance project data via their API. Whether its localhost or prod, I am getting the following error --
Fetch API cannot load XXX. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:5000' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
Not sure how to solve for this.
My code in the Portfolio component below --
getPortfolio = () => {
const USER_ID = `XXX`,
PROJECT_ID = `XXX`,
API_KEY = `XXX`;
const BEHANCE_URL = `https://api.behance.net/v2/users/${USER_ID}/projects?client_id=${API_KEY}`;
console.log(BEHANCE_URL);
fetch(BEHANCE_URL, {
method: 'get',
dataType: 'jsonp',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
}).then((response) => {
return response.json();
}).then((responseData) => {
return responseData;
}).catch((err) => {
return err;
});
}
UPDATE: Instead of fetch, using jQuery ajax works. --
$.ajax({
url: BEHANCE_URL,
type: "get",
data: {projects: {}},
dataType: "jsonp"
}).done((response) => {
this.setState({
portfolioData: response['projects']
});
}).fail((error) => {
console.log("Ajax request fails")
console.log(error);
});
This seems to have do less with React and more with Behance. What you are getting is a CORS error as you probably figured out. The short explanation is that CORS is a security measure put in on the browser so that websites cannot request other websites from the browser to appear to be the second website. It is a safety measure in place to protect from some phishing attacks.
CORS can be disabled by the server (in this case, Behance) but they decide not to, for legitimate reasons.
Behance would probably allow you to make the request you are trying to make from a server instead. Once you do that, you will need to get the information from your server to your React application, and you will be good to go!

Vue Resource Cross-site HTTP request

Normally, when I make a jQuery request to a non-local server, it applies Cross-site HTTP request rules and initially sends an OPTIONS request to verify the existence of an endpoint and then it sends the request, i.e.
GET to domain.tld/api/get/user/data/user_id
jQuery works fine, however I would like to use Vue Resource to deal with requests. In my network log, I see only the actual request being made (no OPTIONS request initially), and no data is being received.
Anybody has an idea how to solve this?
Sample Code:
var options = {
headers: {
'Authorization': 'Bearer xxx'
}
};
this.$http.get(config.api.base_url + 'open/cities',[options])
.then(function(response){
console.log('new request');
vm.cities = response;
}, function(error){
console.log('error in .js:');
console.log(error);
});
jquery-request
Solution:
As #Anton mentioned, it's not necessary to have both requests (environment negligible). Not sure what I have changed to make it work, but the request gave me an error. It consisted in setting the headers correctly. Headers should not be passed as options but as a property of http:
this.$http({
root: config.api.base_url + 'open/cities', // url, endpoint
method: 'GET',
headers: {
'Authorization': 'Bearer xxx'
}
}).then(function(response){
console.log('new request');
vm.cities = response;
}, function(error){
console.log('error in .js:');
console.log(error);
});
Thank you guys, it was a team effort :)
Is it a requirement that an additional OPTIONS request is being made? I have created a small (32 LOC) example which works fine and retrieves the data:
https://jsfiddle.net/ct372m7x/2/
As you can see, the data is being loaded from a non-local server. The example is located on jsfiddle.net and the request is made to httpbin.org - this leads to CORS being applied (you can see the Access-Control-Allow-Origin header in the screenshot below).
What you also see is that only the GET request has been executed, no OPTIONS before that.