socket.io, vTiger, and csrf-magic.js. CORS issues - javascript

I'm attempting to create and add a socket.io module to my vTiger 7.0 so that I can update fields in real-time to multiple users.
We are have issues with users changing fields that should be locked while our quality control is attempting to check the record. This is causes things to get approved that should not. Node.js with vTiger will be awesome add-on.
The only problem is that vTiger uses csrf-magic.js to create a token that need to be included in the header to allow CORS
I have the middleware setup in my node project to allow my vtiger to make a request
vTiger is on vtiger.example.com
The node server is on node.example.com:3010
//server code node.example.com:3010
const fs = require("fs");
const config = require("./core/config").config();
var options = {
key: fs.readFileSync(config.key),
cert: fs.readFileSync(config.cert),
ca: fs.readFileSync(config.ca),
requestCert: true,
rejectUnauthorized: false,
};
const app = require("express")();
const server = require("https").Server(options, app);
const io = require("socket.io")(server);
// Need to send io to socket module
module.exports = io;
app.use(function (req, res, next) {
var allowedOrigins = [
"https://node.example.com",
"https://vtiger.example.com"
];
var origin = req.headers.origin;
if (allowedOrigins.indexOf(origin) > -1) {
res.setHeader("Access-Control-Allow-Origin", origin);
}
res.header("Access-Control-Allow-Methods", "GET, OPTIONS");
res.header("Access-Control-Allow-Headers", "Content-Type, Authorization");
res.header("Access-Control-Allow-Credentials", true);
return next();
});
io.sockets.on("connection", require("./sockets/socket.js"));
const qc = require('./models/qc_model');
app.get('/', (req,res) => {
res.json({message: 'No Access'});
})
qc.pullLeadInfo(13622196, 10730, (data) => {
console.log(data.lead.lsloa_ver_by);
});
//Start the server
server.listen(config.port, () => {
console.log("server listening on port: " + config.port);
});
\\client side vtiger.example.com
var socket = io.connect('https://node.example.com:3010');
I get this error
Access to XMLHttpRequest at 'https://node.example.com:3010/socket.io/?EIO=4&transport=polling&t=NmEEc_r' from origin 'https://vtiger.example.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
csrf-magic.js:41 GET https://node.example.com:3010/socket.io/?EIO=4&transport=polling&t=NmEEc_r net::ERR_FAILED
I cannot find any good documentation dealing with this issue. Any help would be great!

Found the information here
https://github.com/socketio/socket.io/issues/3929
// Server
io.engine.on("headers", (headers) => {
headers["Access-Control-Allow-Private-Network"] = true;
});
// Client
const socket = io({
extraHeaders: {
"Access-Control-Request-Private-Network": true
}
});

Related

Why am I getting a No 'Access-Control-Allow-Origin' error?

Chrome authorization Headers
I believe I have cors configured correctly in my backend. The API is hosted on Heroku if that helps. Here is the server.js file:
const express = require("express");
const helmet = require("helmet");
const cors = require("cors");
const bodyParser = require("body-parser");
const productsRouter = require("./products/products-router");
const ordersRouter = require("./orders/orders-router");
const emailsRouter = require("./emails/emails-router");
const corsOptions = {
origin: "*",
credentials: true,
optionSuccessStatus: 200,
};
const server = express();
server.use(express.json());
server.use(helmet());
server.use(cors(corsOptions));
server.use("/api/products", productsRouter);
server.use("/api/orders", ordersRouter);
server.use("/api/emails", emailsRouter);
server.use((err, req, res, next) => {
res.status(err.status || 500).json({
message: err.message,
});I
});
module.exports = server;
I get a cors error when my front-end tries to make HTTP requests to the backend. It reads as follows:
Access to XMLHttpRequest at
'https://nanasoapsbackend.herokuapp.com/api/products/categories' from
origin 'http://localhost:3000' has been blocked by CORS policy: No
'Access-Control-Allow-Origin' header is present on the requested
resource.
Yes, my back and and front end are on different domains. This just happened all of a sudden, it was working fine with no cors errors for the past few months, and suddenly it stopped working. Any help would be greatly appreciated.
The problem is: You can't have origin * (allow everything) with allow credentials. See: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSNotSupportingCredentials
You have to set up a white list (list of domains that are allowed)
const whitelist = ['http://www.example.com', 'http://www.otherexample.com']
const corsOptions = {
origin: function (origin, callback) {
if (whitelist.includes(origin)) {
callback(null, true)
} else {
callback(new Error('Not allowed'))
}
}
}
Then on your client side (frontend) make sure you use withCredientals flag on your http agent (axios, superagent, fetc, etc)

react client wont follow redirect CORS localhost

front end: localhost:3000 (react app) App.js (client) on load call api '/'
function fetch_redirect() {
fetch("http://localhost:8082")
}
function App() {
return <div className="App">{fetch_redirect()}</div>;
}
export default App;
backend: localhost:8082 (nodejs express app) send redirect to /test endpoint on client
const express = require('express')
const app = express()
const cors = require('cors');
const whitelist = ['http://localhost:3000']
const corsOptions = {
origin: function (origin, callback) {
console.log(origin, whitelist.indexOf(origin) !== -1);
if (whitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
}
}
app.use(cors(corsOptions))
app.get('/', function (req, res) {
res.redirect('http://localhost:3000/test')
})
app.listen(8082)
The main issue is on the client (react) once the API call is made, the redirect is blocked... how can I make the client react app follow this redirect to 'http://localhost:3000/test' I already have cors on my backend with an enabled whitelist of localhost:3000 to allow me to make the API call not blocked... however the redirect is now blocked from the fetch frontend!
error details:
Access to fetch at 'http://localhost:3000/test' (redirected from 'http://localhost:8082/') from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
In order to facilitate the development and have a development environment closer to what the production environment should be (no need to decrease the security level with Access-Control-Allow-Origin), you should have a unique entry point to your frontend and backend, with a unique origin (http://localhost:3000 in your case).
To achieve that, remove all of the Access-Control-* headers, create a src/setupProxy.js file and fill it like this:
const { createProxyMiddleware } = require("http-proxy-middleware");
module.exports = app => {
app.use(
"/api",
createProxyMiddleware ({
target: "http://localhost:8082",
changeOrigin: true
})
);
};
Then install the needed express middleware as a development dependency with npm install --save-dev http-proxy-middleware
Note: this feature is available with react-scripts#2.0.0 and higher.
Finally, replace all of the fetch from the frontend with relative URLs starting with /api
fetch("http://localhost:8082") becomes fetch('/api'))
Something like fetch('http://localhost:8082/some-endpoint') would become fetch('/api/some-endpoint')
For more information about this, please refer to the docs.
Try to refactor your code like this:
const express = require('express')
const app = express()
const cors = require('cors');
const whitelist = ['http://localhost:3000', 'http://localhost:8082'];
const corsOptionsDelegate = (req, callback) => {
var corsOptions;
if (whitelist.indexOf(req.header('Origin')) !== -1) {
corsOptions = { origin: true };
} else {
corsOptions = { origin: false };
}
callback(null, corsOptions);
};
const corsWithOptions = cors(corsOptionsDelegate);
app.route('/')
.options(corsWithOptions, (req, res) => { res.sendStatus(200); })
.get(cors(), (req, res)=>{
res.redirect('http://localhost:3000/test')
});
app.listen(8082)
Try using next function inside app.get:
app.get('/', function (req, res, next) {
res.redirect('http://localhost:3000/test');
next();
})
Also for your ReactJS application (I'm not sure about your implementation, CSR or SSR) you should add two things:
Webpack: proxy for passing CORS
CSR:
devServer: {
...
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
"Access-Control-Allow-Headers": "X-Requested-With, content-type, Authorization"
}
}
SSR: add the above header to webpackDevMiddleware options.
Route:
CSR: for running the project in the dev side use:
devServer: {
historyApiFallback:{
index:'build/index.html'
},
},
for the prod side use spa flag for running, for example for serve use serve -s ./dist or for pm2 run pm2 start ./dist --spa.
SSR: no need to add extra configuration.
try something like this instead:
whitelistedOrigins = ['http://localhost:3000'];
app.use(cors({
origin: whitelistedOrigins,
methods: ['GET', 'PATCH', 'PUT', 'POST', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'],
}));
you can modify the methods/allowedHeaders keys as you want...
Edit: your backend is :3000, isn't it the problem? the client can't be at 3000 at the same time.

HTTPS Redirect in next js

I'm trying to do a http to https redirect using next,
so if the user enters the site at http://www.example.com redirect to https://www.example.com
I'm using GraphQL Yoga on the server side, so not sure how I could accomplish this in my index file on the server side.
I've tried using the meta tag and changing the protocol in the window object but no luck with doing so in server-side rendering.
Is there any way I can accomplish this redirect on the client side using next js or on the server side?
const cookieParser = require('cookie-parser')
const jwt = require('jsonwebtoken')
require('dotenv').config({path: '.env'})
const createServer = require('./createServer')
const db = require('./db')
const sslRedirect = require('heroku-ssl-redirect');
const server = createServer()
//Express middleware to handle cookies
server.express.use(cookieParser())
//decode JWT
server.express.use((req, res, next) => {
const { token } = req.cookies;
if (token) {
const { userId } = jwt.verify(token, process.env.APP_SECRET);
req.userId = userId;
}
next()
})
//Populates user on request
server.express.use(async (req, res, next) => {
if(!req.userId) return next()
const user = await db.query.user({
where: {id: req.userId}
}, `{id, permissions, email, name}`)
req.user = user
next()
})
//start
server.start({
cors: {
credentials: true,
origin: process.env.FRONTEND_URL
},
}, starting => {
console.log(`server is running on port ${starting.port}`)
})
What I have done in the past is started both a HTTP and a HTTPS server with express.
The HTTPS is the server with all the routes\API's configured.
The HTTP server simply to redirects all GET requests to HTTPS. See the following code which could be used setup the HTTP server to do the redirect.
let httpRedirectServer = express();
// set up a route to redirect http to https
httpRedirectServer.get('*', (request, response) => {
response.redirect('https://' + request.headers.host + request.url);
});
httpRedirectServer.listen(80);
httpRedirectServer.on('listening', () => {
console.log("Listening to redirect http to https");
});
Alternatively on the client side a quick fix is to redirect in javascript by running something like.
// Check the URL starts with 'http://xxxxx' protocol, if it does then redirect to 'https://xxxxx' url of same resource
var httpTokens = /^http:\/\/(.*)$/.exec(window.location.href);
if(httpTokens) {
window.location.replace('https://' + httpTokens[1]);
}

express + cors() is not working properly

I'm building a React application and I'm trying to make a call to https://itunes.apple.com/search?term=jack+johnson
I have a helper called requestHelper.js which looks like :
import 'whatwg-fetch';
function parseJSON(response) {
return response.json();
}
function checkStatus(response) {
if (response.status >= 200 && response.status < 300) {
return response;
}
const error = new Error(response.statusText);
error.response = response;
throw error;
}
export default function request(url, options) {
return fetch(url, options)
.then(checkStatus)
.then(parseJSON);
}
So I get:
XMLHttpRequest cannot load
https://itunes.apple.com/search?term=jack%20johnson. No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:3000' is therefore not allowed
access.
My express server looks like this:
const ip = require('ip');
const cors = require('cors');
const path = require('path');
const express = require('express');
const port = process.env.PORT || 3000;
const resolve = require('path').resolve;
const app = express();
app.use(cors());
app.use('/', express.static(resolve(process.cwd(), 'dist')));
app.get('*', function(req, res) {
res.sendFile(path.resolve(resolve(process.cwd(), 'dist'), 'index.html'))
});
// Start app
app.listen(port, (err) => {
if (err) {
console.error(err.message);
return false;
}
const divider = '\n-----------------------------------';
console.log('Server started ✓');
console.log(`Access URLs:${divider}\n
Localhost: http://localhost:${port}
LAN: http://${ip.address()}:${port}
${divider}
`);
});
I have tried using mode: 'no-cors' but is not actually what I need since the response is empty.
Am I doing something wrong with this configuration?
The same origin policy kicks in when code hosted on A makes a request to B.
In this case A is your Express app and B is iTunes.
CORS is used to allow B to grant permission to the code on A to read the response.
You are setting up CORS on A. This does nothing useful since your site cannot grant your client side code permission to read data from a different site.
You need to set it up on B. Since you (presumably) do not work for Apple, you can't do this. Only Apple can grant your client side code permission to read data from its servers.
Read the data with server side code instead.

Socket.io No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access

I'm trying to learn nodejs with socket.io and at the moment I'm using this tutorial by GianlucaGuarini. When entering my client.html file I get the following error. I know what it means and that it´s there for preventing Cross browser scripts but I don´t know how to allow my nodejs script to access the client.html file.
XMLHttpRequest cannot load http://localhost:8000/socket.io/?EIO=3&transport=polling&t=1422653081432-10. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.
Here is a part of my code with socket.
var app = require('http').createServer(handler),
io = require('socket.io').listen(app),
fs = require('fs'),
mysql = require('mysql'),
connectionsArray = [],
connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'database',
port: 3306
}),
POLLING_INTERVAL = 3000,
pollingTimer;
// If there is an error connecting to the database
connection.connect(function(err) {
// connected! (unless `err` is set)
console.log(err);
});
// creating the server ( localhost:8000 )
app.listen(8000);
// on server started we can load our client.html page
function handler(req, res) {
res.writeHead(200, {
/// ...
'Access-Control-Allow-Origin' : '*'
});
fs.readFile(__dirname + '/client.html', function(err, data) {
if (err) {
console.log(err);
res.writeHead(500);
return res.end('Error loading client.html');
}
res.writeHead(200);
res.end(data);
});
}
Does anyone know how I can solve my problem?
Kind regard / H
First of all - stop use writeHead everywhere. Because it rewrite completely response headers.
If tour write like this:
res.writeHead(200,{"coolHeader":"YesIAm"});
res.writeHead(500);
then node.js will sent response just with status 500 and without header "coolHeader";
If you wanna change Status Code, then use
res.statusCode = ###;
If you wanna add new header use
res.setHeader("key", "value");
And if you wanna rewrite all headers then use writeHeader(...)
Second. Add this code
res.statusCode = 200;
//...
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
instead of your
res.writeHead(200, {
/// ...
'Access-Control-Allow-Origin' : '*'
});
and replace all writeHead(###) with res.statusCode = ###;
Try setting the `Access-Control-Allow-Origin' header on your response object in Node.
response.writeHead(200, {
/// ...
'Access-Control-Allow-Origin' : '*'
});
Looks like you are calling .listen for both the app and the socket.io (I believe that is redundant since you are extending your server with socket.io)
I have a little piece that works fine for me using socket.io 1.x
I like to use https since it kills some issues with firewalls and antiviruses, but this example is rewritten to http.
var http = require('http'),
socketio = require('socket.io'),
options={},
port=8080;
//start http
var app = http.createServer(options, handler),
io = socketio(app, {
log: false,
agent: false,
origins: '*:*'
// 'transports': ['websocket', 'htmlfile', 'xhr-polling', 'jsonp-polling']
});
app.listen(port);
console.log('listening on port ' + port);

Categories

Resources