Chrome extension sending empty POST body - javascript

I have created a Chrome extension that collects some data and sends a POST request to my server. The code sending this request is very simple:
var payload =
{
prop1: 'SomeValue',
prop2: 'SomeValue',
...
};
var requestSettings = {
method: 'POST',
headers: {
'Content-Type': ' application/json'
},
body: JSON.stringify(payload)
};
var webRequest = new Request("https://mysite.xyz/api/process", requestSettings);
var response = await fetch(webRequest);
It works fine most of the times, but some of my users complained that the extension was not working properly, so I asked them to create a HAR file to see what was wrong with the requests that the extension was sending.
After inspecting the HAR file I found out that my extension was sending an empty POST body ("bodySize": 0 in HAR), although the Content-Length request header was not zero, and this caused my API to return an error, and the extension couldn't continue its work. Any ideas why the request body can be empty, and how to fix it?

You need to use cors npm package in your server(api), and then just don't add mode: 'no-cors' in requestSettings coz many people did this mistake.
And Try to fetch data in chrome without using requests, just fetch directly.
Edit:these are some few things you need to do in your express based api,
api.js will look like this;
const app = require('express')();
const cors = require('cors');
app.use(cors())
app.use(express.json())
chrome-extension's script:
var payload =
{
prop1: 'SomeValue',
prop2: 'SomeValue',
...
};
var requestSettings = {
method: 'POST',
headers: {
'Content-Type': ' application/json'
},
body: JSON.stringify(payload)
};
var response = await fetch("https://mysite.xyz/api/process", requestSettings);
``

Related

Calling reddit api to get access token is being blocked by CORS policy

I am trying to use reddit api in my react application. But when I try to get access token I get the following error.
const response = await axios({
method: "post",
url: "https://www.reddit.com/api/v1/access_token",
auth: {
user: process.env.REACT_APP_REDDIT_CLIENT_ID,
password: process.env.REACT_APP_REDDIT_CLIENT_SECRET,
},
data: {
grant_type: "authorization_code",
code: code,
redirect_uri: "http://localhost:3000/login",
},
});
I am new to Reddit Api and Oauth so I can't really understand what's the issue.
I found the solution. The issue was that parameters sent cannot be in json format.
SO I had to change them to url encoded.
const params = new URLSearchParams();
params.append("grant_type", "refresh_token");
params.append("refresh_token", refreshToken);
const config = {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
auth: {
username: process.env.REACT_APP_REDDIT_CLIENT_ID,
password: process.env.REACT_APP_REDDIT_CLIENT_SECRET,
},
};
const response = await axios.post(getPrefix(url), params, config);
Also due to my local environment being http. It was causing cors issue. So I prefixed my url with cors-anywhere and it works. I tried using reddit.local as mentioned but it doesn't seem to work.

Axios POST working in Node.js but not Electron

So I have a package with a function that uploads a file to Twilio:
const FD = require('form-data');
const axios = require('axios');
async function createFunctionResource(serviceUid, functionUid, client){
let collect_file = "Hello World"
let url = `https://serverless-upload.twilio.com/v1/Services/${serviceUid}/Functions/${functionUid}/Versions`
let form = new FD();
collect_file = "test"
form.append("Path", "collect");
form.append("Visibility", "public");
form.append("Content", collect_file, "collect.js");
form.append("contentType", "application/javascript");
await axios.post(url, form, {
headers: {
Authorization: 'Basic ' + Buffer.from(`${client.accountSid}:${client.password}`).toString('base64'),
...form.getHeaders(),
},
})
}
This works completely fine in node.js and it gets uploaded with the message "Hello World" in the file.
I'm trying to put this into an electron app so I preload this package in preload.js with nodeIntegration set to true but whenever I try to upload a file I get:
Request failed with status code 400
With the error response being:
{"message":"No file attached to request","code":70002,"user_error":true,"http_status_code":400,"params":{}}
Does preloading a package make it act exactly the same as it does in node.js?
Can u add cotent-type in headers section and check .
"content-type": "application/json"
Even though you may try and preload a package with axios hoping it runs in a node environment, requests are done under XHR (browser).
To fix this you must specify the adapter to be HTTP by adding adapter: require('axios/lib/adapters/http')
await axios.post(url, form, {
headers: {
Authorization: 'Basic ' + Buffer.from(`${client.accountSid}:${client.password}`).toString('base64'),
...form.getHeaders(),
},
adapter: require('axios/lib/adapters/http'),
})
}

Request HTTP libraries are slow

I'm making a project using Node.js (8.9.4) and Express (4.16.2). Basically, with Node.js i'm consulting an external API and then with Express make a route to consume this result. My surprise was that when I used Axios library, it make my response to delay up to ~30s. I wanted to check if it was my problem or was from the API... I've checked it with PostMan and it returns in less than 300ms. Then I've thought it was any problem related with Axios, so I've decided to use request-promise but...again 30s. The last test I've made is using Node.js native 'https' util and...yes, less than 300ms again.
Anyone knows whats the problem with those packages? Am I condemned to use callbacks instead of promises?
Here's my base code... (AXIOS, Request-Promise... 30s delay in response)
const rp = require('request-promise);
const BASE_URL = 'my https url';
const AUTH_TOKEN = 'my auth token';
const options = {
uri: BASE_URL + '/my-route',
qs: { myQS: true },
headers: { authorization: AUTH_TOKEN }
method: 'GET'
};
rp(options)
.then(response => response)
.catch(error => error);
Here's my base code with HTTPS.... 300ms delay in response
const https = require('https');
const AUTH_TOKEN = 'my auth token';
const options = {
hostname: 'my hostname',
port: 443,
path: 'my path',
headers: { authorization: AUTH_TOKEN },
method: 'GET'
};
https.get(options, (res) => {
res.on('data', d => d);
};
Just a guess, but sounds like Axios is going via a different route in your network. Are both requests configured to use the same proxy setup?

Axios HTTP requests returns into an error (Access-Control-Allow-Origin)

I'm trying to make http post requests with Axios in JavaScript. The request was working fine, but then I tried to use cookies. As my backend I'm using an Express/Nodejs Server on http://localhost:8000, while my frontend is a react npm test server on http://localhost:3000.
My backend looks like this:
const express = require('express');
const cookieparser = require('cookie-parser');
const cors = require('cors');
const app = express();
app.use(cookieparser());
app.use(cors());
app.post("/request/status/check", (req, res) => {
if(req.cookies.gitEmployee != null){
res.status(200).send({res: 1, employeeName: req.cookies.gitEmployee.username, fullname: req.cookies.gitEmployee.fullname});
} else if(req.cookies.gitCompany != null){
res.status(200).send({res: 2, companyName: req.cookies.gitCompany.companyName, fullname: req.cookies.gitCompany.fullname});
}else{
res.status(200).send({res: 0});
}
});
app.post("/request/testcookie", (req, res) => {
res.cookie("gitEmployee", null);
res.cookie("gitEmployee", {
username: "testusername",
fullname: "Test Username"
}).send({res: 1});
});
So, as a short description: I'm setting a test cookie by posting a request to http://localhost:8000/request/testcookie. The response should be an JSON object where res = 1. Also, I'm trying to get information out of the cookie by posting a request to http://localhost:8000/request/status/check. In this case the response should be the object {res:1 , employeeName: "testusername", fullname: "Test Username"}.
I tried this concept with a REST Client called Insomnia (something like Postman) and it worked perfectly.
Then I wrote a helper-class for my React Application and for the Http request I'm using Axios.
import axios from 'axios';
class manageMongo {
authstate(){
return new Promise((resolve, reject) => {
axios("http://localhost:8000/request/status/check", {
method: "post",
data: null,
headers: {
"Access-Control-Allow-Origin": "*"
},
withCredentials: true
})
.then(res => {
console.log(res.data);
if(res.data.res === 0){
resolve(false);
}
if(res.data.res === 1){
resolve(true);
}
if(res.data.res === 2){
resolve(true);
}
});
});
}
setTestCookie(){
axios("http://localhost:8000/request/testcookie", {
method: "post",
data: null,
headers: {"Access-Control-Allow-Origin": "*"},
withCredentials: true
})
.then(res => { console.log(res)});
}
}
export default manageMongo.prototype;
When I execute these functions, I'm getting the same error of both of them (of course with different urls):
Failed to load http://localhost:8000/request/testcookie: Response to
preflight request doesn't pass access control check: The value of the
'Access-Control-Allow-Origin' header in the response must not be the
wildcard '*' when the request's credentials mode is 'include'
I already know that it's because of the withCredentials setting in the requests. I added these settings because I want to pass cookies through these requests and if I don't add withCredentials, the /request/status/check request always returns {res: 0} even if I set a cookie before.
I don't know, if this will change if the I set withCredentials = true but i read that in multiple threads. If you know an other working method to pass cookies through these requests even without axios please share it here! Because that is, what I want to achieve.
The problem seems to be you have set
'Access-Control-Allow-Origin': *
Try setting it to your actual origin, for example
'Access-Control-Allow-Origin': 'http://localhost:8000'
or
'Access-Control-Allow-Origin': 'http://localhost:3000'
Whichever the request originates from.

How to correctly format outbound GET requests that contain data in Node.js

I am working on the backend of my iOS game and I want to validate Facebook logins on my server before I send any data back to the client. I have a valid app_access token provided by Facebook and I am able to successfully enter the following link in my browser to debug/validate access tokens:
https://graph.facebook.com/debug_token?input_token=users_access_token&access_token=apps_access_token
Ofcourse the correct access tokens are placed in the placeholders. From that request I receive a response that looks something like this:
{
"data": {
"app_id": app_id,
"is_valid": true,
"application": "My App",
"user_id": user_id,
"expires_at": 1382468400,
"scopes": [
"email",
"publish_actions",
"user_birthday",
"user_location"
]
}
}
From which I am able to determine if the user has a correct access token. However, trying to implement this from the server side has been fruitless. Here is how I am trying now
var http = require('http');
var https = require('https');
var querystring = require('querystring');
var data = querystring.stringify({
'access_token': app_access_token,
'input_token': user_access_token
});
console.log('' + data); //Debug to see if data is correctly formatted
var options = {
host: 'graph.facebook.com',
port: 443,
path: '/debug_token',
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(data)
}
};
var req = https.request(options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log("body: " + chunk);
});
});
req.write(data);
req.end();
Which always returns me the following response:
body: {"error":{"message":"(#100) You must provide an app access token or a user access token that is an owner or developer of the app","type":"OAuthException","code":100}}
I have noticed that the querystring does tend to format the "|" into "%7C" but I have manually replaced the characters and the data string to no avail. Is there something I am doing wrong? The tokens are correct, I just cant seem to format the data correctly.
Edit
Finally got it working. Michaels solution is right. I tried the same solution earlier and it didnt work because I performed a http.request() instead of an https.request() and I forgot to try it again. Such a silly mistake. Thanks!
With GET parameters are passed as a query string, part of path /path?param1=val1&param2=val2. In your case
path: '/debug_token?'+data,
instead of req.write(data).

Categories