Cross-domain connections via Socket.io on Nodejitsu - websocket

I am having a cross domain problem connecting from localhost to a remote server at Nodejitsu via Socket.io. I get an error "...header contains multiple values 'http://evil.com/, *', but only one is allowed". More details below:
I have an Express/Mongoose/Socket.io app running at Nodejistu serving as a REST API, it serves no HTML files.
Locally I have an Angularjs+Requirejs app (running at http://localhost:8000) trying to connect to the remote API and I can't get access. While I can test the API methods with POSTMAN and am able to read the socket.io script frontend from the Angular RequireJS app, the connection is not granted access and cause server crash looping.
In my NodeJS/Express app on Nodejitsu, I have set the following:
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var morgan = require('morgan');
var port = process.env.PORT || 80; // set our port the same as Nodejitsu
// ATTACHING SOCKET.IO
var server = require('http').createServer(app);
var io = require('socket.io')(server);
app.set('socketio', io); // socket instance of the app
app.set('server', server);
// CONFIGURE BODY PARSER
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
//CORS SETTING
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "http://localhost:8000");
res.header("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE,OPTIONS");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.header("Access-Control-Allow-Credentials", "false");
next();
});
// START SERVER
app.get('server').listen(port);
---------
// package.json
"dependencies": {
"express": "4.11.1",
"morgan": "1.5.1",
"mongoose": "3.8.21",
"body-parser": "1.10.2",
"grunt-release": "0.10.0",
"socket.io": "1.3.2"
},
In the Angular app on localhost:8000, I checked that Header is not duplicated, as the attached png shows.
// main.js
"use strict";
require.config({
paths: {
...
'socketio': 'http://<MYAPP>.jit.su/socket.io/socket.io';,
...
// SocketFactory.js
var socket = io.connect('http://<MYAPP>.jit.su:80/api/boards');
However I get this error message, even when I set Origin to be localhost://8000:
XMLHttpRequest cannot load http://<MYAPP>.jit.su/socket.io/?EIO=3&transport=polling&t=1423052553506-7.
The 'Access-Control-Allow-Origin' header contains multiple values
'http://evil.com/, *', but only one is allowed.
Origin 'http://localhost:8000'; is therefore not allowed access.

I got the same error, but it wasn't even a CORS issue in the end. When using socket.io with express, listen on the server, not the app, as stated in socket.io's docs.
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
server.listen(80);
(...)

Related

Apollo GraphQL: How to Set Up Secure Websockets?

I'm setting up my dev system to use https, and Chrome is complaining about my websocket not begin secure:
VM4965:161 Mixed Content: The page at 'https://mywebsite.io/' was
loaded over HTTPS, but attempted to connect to the insecure WebSocket
endpoint 'ws://mywebsite.io:4000/subscriptions'. This request has
been blocked; this endpoint must be available over WSS.
Here's my current server-side setup for WS, based on the Apollo docs:
const localHostString = 'mywebsite.io';
const pubsub = new PubSub();
// additional context you use for your resolvers, if any
const context = {connectors: connectors};
//SET UP APOLLO QUERY / MUTATIONS / PUBSUB
//start a graphql server with Express handling a possible Meteor current user
createApolloServer({
schema,
context
});
const METEOR_PORT = 3000;
const GRAPHQL_PORT = 4000;
const server = express();
server.use('*', cors({ origin: `https://${localHostString}:${METEOR_PORT}` }));
server.use('/graphql', bodyParser.json(), graphqlExpress({
schema,
context
}));
server.use('/graphiql', graphiqlExpress({
endpointURL: '/graphql',
subscriptionsEndpoint: `ws://${localHostString}:${GRAPHQL_PORT}/subscriptions`
}));
// Wrap the Express server
const ws = createServer(server);
ws.listen(GRAPHQL_PORT, () => {
console.log(`GraphQL Server is now running on http://${localHostString}:${GRAPHQL_PORT}`);
console.log(`GraphiQL available at http://${localHostString}:${GRAPHQL_PORT}/graphiql`);
// Set up the WebSocket for handling GraphQL subscriptions
new SubscriptionServer({
execute,
subscribe,
schema
}, {
server: ws,
path: '/subscriptions',
});
});
How can I update this so as to use WSS rather than WS websockets?
Thanks in advance to all for any info.
It looks like you're doing
subscriptionsEndpoint: `ws://${localHostString}:${GRAPHQL_PORT}/subscriptions
Maybe instead, change ws to wss. ie:
subscriptionsEndpoint: `wss://${localHostString}:${GRAPHQL_PORT}/subscriptions

Local Parse Server throwing 'unauthorised' despite correct keys

I'm setting up a local Parse Server: https://github.com/ParsePlatform/parse-server
I'm setting my keys as per the link above yet still getting 'Unauthorised'. Any ideas why this is?
Here's the snippet where I create the server var:
var express = require('express');
var ParseServer = require('parse-server').ParseServer;
var app = express();
var port = process.env.PORT || 1337;
// Specify the connection string for your mongodb database
// and the location to your Parse cloud code
var api = new ParseServer({
databaseURI: 'mongodb://localhost:27017',
cloud: '/Users/jack/Desktop/dev/node_modules/parse-server/lib/cloud/main.js', // Provide an absolute path
appId: 'jack1234',
masterKey: 'jack1234',
serverURL: 'http://localhost:' + port + '/parse'
});
// Serve the Parse API on the /parse URL prefix
app.use('/parse', api);
// Hello world
app.get('/', function(req, res) {
res.status(200).send('Express is running here.');
});
app.listen(port, function() {
console.log('parse-server-example running on port ' + port + '.');
});
Here's a screenshot of the Unauthorised:
You need to wirte the value in the header without '' (Apostrophe).
like:
X-Parse-Application-Id : jack1234
I think the issue might be from the headers you are sending to the ending. this is why you get the 403 code. I'm guessing the server does not recognize requests with these headers.
// Serve the Parse API on the /parse URL prefix
app.use('/parse', api);
On this line shown above you are injecting the arguments in which the express app needs to be authenticated with. So why not just make a request to it without the Headers ?

CORS with Node.js Express running as Windows Service with NSSM

When I run node app.js myself, I do not get a CORS error in the browser. When I run it as a service, I do not get the error on the OPTIONS request, but I do get the error on the POST request.
I created the service using nssm. I configured the service to log in with the same account I use to run the node process.
var express = require('express');
// The `socket` module initializes socket.io for other endpoints
var io = require('./modules/socket');
var upload = require('./routes/upload');
var app = express();
app.configure(function () {
app.use(express.cookieParser());
app.use(express.session({secret: 'secret', key: 'express.sid'}));
});
app.set('port', 5000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(express.json());
app.use(express.urlencoded());
app.use(express.methodOverride());
app.use(app.router);
app.all('/up', function(req, res, next) {
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Origin', 'https://####.###');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
if (req.method == "OPTIONS") {
res.send(200);
} else {
next();
}
});
app.post('/up', upload.upload);
Can you think of a reason why the error on POST will only occur when it is running as a service?
Found the problem. When creating the service with NSSM, the Startup Directory needed to be the location of the app's main javascript file, not the node executable's location.
It looks like it was permissions problem when writing to disk.

HTTPS express.js server and routes

I just changed my server to use HTTPS. I have a very boiler plate code. When I go to localhost:8888, the browser hangs and my route never gets called. Curl from the command line is the same.
I am wondering I am defining my route incorrectly.
THe code is the following:
var express = require('express');
var routes = require('./routes');
var user = require('./routes/user');
var https = require('https');
var path = require('path');
var app = express();
var fs = require('fs');
// all environments
app.set('port', process.env.PORT || 8888);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.methodOverride());
app.use(app.router);
//app.use(logErrors);
app.use(express.static(path.join(__dirname, 'public')));
var options = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem')};
app.get('/', routes.index);
app.get('/users', user.list);
https.createServer(options, app.handle).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
Anyone sees what the issue is?
I think you want just app where you have app.handle:
https.createServer(options, app)....
Also note for cURL testing you'll need to do curl --insecure https://localhost:8888 since you are presumably using a non-commercial self-signed certificate which neither curl nor browsers will trust without a user explicit override.
You need to go to https://localhost:8888.
The browser can't automatically figure out that you're listening for SSL connections on that port.

Socket.io connection url?

I have the current setup:
Nodejs Proxy (running http-reverse-proxy) running on port 80.
Rails server running on port 3000
Nodejs web server running on port 8888
So any request starting with /nodejs/ will be redirected to nodejs web server on 8888.
Anything else will be redirected to the rails server on port 3000.
Currently Socket.io requires a connection url for io.connect.
Note that /nodejs/socket.io/socket.io.js is valid and returns the required socket.io client js library.
However, I am not able to specify connection_url to /nodejs/ on my server.
I have tried http://myapp.com/nodejs and other variants but I am still getting a 404 error with the following url http://myapp/socket.io/1/?t=1331851089106
Is it possible to tell io.connect to prefix each connection url with /nodejs/ ?
As of Socket.io version 1, resource has been replaced by path. Use :
var socket = io('http://localhost', {path: '/nodejs/socket.io'});
See: http://blog.seafuj.com/migrating-to-socketio-1-0
you can specify resource like this:
var socket = io.connect('http://localhost', {resource: 'nodejs'});
by default resource = "socket.io"
If you are using express with nodejs:
Server side:
var io = require('socket.io')(server, {path: '/octagon/socket.io'});
then
io.on('connection', function(socket) {
console.log('a user connected, id ' + socket.id);
socket.on('disconnect', function() {
console.log('a user disconnected, id ' + socket.id);
})
})
socket.on('publish message ' + clientId, function(msg) {
console.log('got message')
})
Client side:
var socket = io('https://dev.octagon.com:8443', {path: '/octagon/socket.io'})
then
socket.emit('publish message ' + clientId, msg)
I use below approach to achieve this goal:
client side:
var socket = io.connect('http://localhost:8183/?clientId='+clientId,{"force new connection":true});
server side:
var io = require('socket.io').listen(server);
io.sockets.on('connection', function(socket) {
console.log("url"+socket.handshake.url);
clientId=socket.handshake.query.clientId;
console.log("connected clientId:"+clientId);
});
reference:https://github.com/LearnBoost/socket.io/wiki/Authorizing#global-authorization
If you are serving your app with express, then maybe you can check this out. Remember express uses http to serve your application.
const express = require('express'),
http = require('http'),
socketIo = require('socket.io'),
app = express()
var server = http.createServer(app);
var io = socketIo(server);
io.on('connection', (socket)=>{
// run your code here
})
server.listen(process.env.PORT, ()=> {
console.log('chat-app inintated succesfully')
})

Resources