Skip to content

Commit

Permalink
Overhaul origin option to allow regex, function, boolean, string and …
Browse files Browse the repository at this point in the history
…array and remove original implementation
  • Loading branch information
timdown committed Jan 31, 2025
1 parent d44882d commit 1d6488a
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 179 deletions.
8 changes: 8 additions & 0 deletions History.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
0.9.19-overleaf-11 / 2025-01-24
===============================

* Overleaf: Overhaul origins option to allow a regex, function, string or boolean, or an array of any mix of these
* Overleaf: Change origins option default to disallow any origin
* Overleaf: Remove htmlfile transport
* Overleaf: Remove flashsocket transport

0.9.19-overleaf-10 / 2023-04-25
===============================

Expand Down
59 changes: 32 additions & 27 deletions lib/manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ function Manager (server, options) {
this.namespaces = {};
this.sockets = this.of('');
this.settings = {
origins: '*:*'
origins: []
, log: true
, store: new MemoryStore
, logger: new Logger
Expand Down Expand Up @@ -870,40 +870,45 @@ Manager.prototype.handshakeData = function (data, connection) {
};
};

function isString(s) {
return typeof s === 'string' || s instanceof String;
}

// Adapted from Express's CORS module
// (https://github.com/expressjs/cors/blob/1cfb3709dec33dfa7ae95a3a554f2dd10498c7f9/lib/index.js)
Manager.prototype.isOriginAllowed = function (origin) {
var allowedOrigin = this.get('origins');
if (typeof allowedOrigin === 'function') {
return allowedOrigin(origin);
} else if (Array.isArray(allowedOrigin)) {
for (var i = 0; i < allowedOrigin.length; ++i) {
if (this.isOriginAllowed(origin, allowedOrigin[i])) {
return true;
}
}
return false;
} else if (isString(allowedOrigin)) {
return allowedOrigin === '*' || origin === allowedOrigin;
} else if (allowedOrigin instanceof RegExp) {
return allowedOrigin.test(origin);
} else {
return !!allowedOrigin;
}
};

/**
* Verifies the origin of a request.
*
* @api private
*/

Manager.prototype.verifyOrigin = function (request) {
var origin = request.headers.origin || request.headers.referer
, origins = this.get('origins');

if (origin === 'null') origin = '*';

if (origins.indexOf('*:*') !== -1) {
return true;
var origin = request.headers.origin || request.headers.referer;
var allowed = this.isOriginAllowed(origin);
if (!origin && !allowed) {
this.log.warn('origin missing from handshake, yet required by config', { headers: request.headers });
}

if (origin) {
try {
var parts = url.parse(origin);
parts.port = parts.port || 80;
var ok =
~origins.indexOf(parts.hostname + ':' + parts.port) ||
~origins.indexOf(parts.hostname + ':*') ||
~origins.indexOf('*:' + parts.port);
if (!ok) this.log.warn('illegal origin: ' + origin);
return ok;
} catch (ex) {
this.log.warn('error parsing origin');
}
}
else {
this.log.warn('origin missing from handshake, yet required by config');
}
return false;
return allowed;
};

/**
Expand Down
29 changes: 4 additions & 25 deletions lib/transports/websocket/hybi-07-12.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,32 +155,11 @@ WebSocket.prototype.onSocketConnect = function () {
*/

WebSocket.prototype.verifyOrigin = function (origin) {
var origins = this.manager.get('origins');

if (origin === 'null') origin = '*';

if (origins.indexOf('*:*') !== -1) {
return true;
}

if (origin) {
try {
var parts = url.parse(origin);
parts.port = parts.port || 80;
var ok =
~origins.indexOf(parts.hostname + ':' + parts.port) ||
~origins.indexOf(parts.hostname + ':*') ||
~origins.indexOf('*:' + parts.port);
if (!ok) this.log.warn('illegal origin: ' + origin);
return ok;
} catch (ex) {
this.log.warn('error parsing origin');
}
}
else {
this.log.warn('origin missing from websocket call, yet required by config');
var allowed = this.manager.isOriginAllowed(origin);
if (!origin && !allowed) {
this.log.warn('origin missing from websocket call, yet required by config', { headers: this.req.headers });
}
return false;
return allowed;
};

/**
Expand Down
29 changes: 4 additions & 25 deletions lib/transports/websocket/hybi-16.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,32 +154,11 @@ WebSocket.prototype.onSocketConnect = function () {
*/

WebSocket.prototype.verifyOrigin = function (origin) {
var origins = this.manager.get('origins');

if (origin === 'null') origin = '*';

if (origins.indexOf('*:*') !== -1) {
return true;
}

if (origin) {
try {
var parts = url.parse(origin);
parts.port = parts.port || 80;
var ok =
~origins.indexOf(parts.hostname + ':' + parts.port) ||
~origins.indexOf(parts.hostname + ':*') ||
~origins.indexOf('*:' + parts.port);
if (!ok) this.log.warn('illegal origin: ' + origin);
return ok;
} catch (ex) {
this.log.warn('error parsing origin');
}
}
else {
this.log.warn('origin missing from websocket call, yet required by config');
var allowed = this.manager.isOriginAllowed(origin);
if (!origin && !allowed) {
this.log.warn('origin missing from websocket call, yet required by config', { headers: this.req.headers });
}
return false;
return allowed;
};

/**
Expand Down
102 changes: 0 additions & 102 deletions test/manager.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -243,108 +243,6 @@ module.exports = {
});
},

'test that a referer is accepted for *:* origin': function (done) {
var port = ++ports
, io = sio.listen(port)
, cl = client(port);

io.configure(function () {
io.set('origins', '*:*');
});

cl.get('/socket.io/{protocol}', { headers: { referer: 'http://foo.bar.com:82/something' } }, function (res, data) {
res.statusCode.should.eql(200);
cl.end();
io.server.close();
done();
});
},

'test that valid referer is accepted for addr:* origin': function (done) {
var port = ++ports
, io = sio.listen(port)
, cl = client(port);

io.configure(function () {
io.set('origins', 'foo.bar.com:*');
});

cl.get('/socket.io/{protocol}', { headers: { referer: 'http://foo.bar.com/something' } }, function (res, data) {
res.statusCode.should.eql(200);
cl.end();
io.server.close();
done();
});
},

'test that a referer with implicit port 80 is accepted for foo.bar.com:80 origin': function (done) {
var port = ++ports
, io = sio.listen(port)
, cl = client(port);

io.configure(function () {
io.set('origins', 'foo.bar.com:80');
});

cl.get('/socket.io/{protocol}', { headers: { referer: 'http://foo.bar.com/something' } }, function (res, data) {
res.statusCode.should.eql(200);
cl.end();
io.server.close();
done();
});
},

'test that erroneous referer is denied for addr:* origin': function (done) {
var port = ++ports
, io = sio.listen(port)
, cl = client(port);

io.configure(function () {
io.set('origins', 'foo.bar.com:*');
});

cl.get('/socket.io/{protocol}', { headers: { referer: 'http://baz.bar.com/something' } }, function (res, data) {
res.statusCode.should.eql(403);
cl.end();
io.server.close();
done();
});
},

'test that valid referer port is accepted for addr:port origin': function (done) {
var port = ++ports
, io = sio.listen(port)
, cl = client(port);

io.configure(function () {
io.set('origins', 'foo.bar.com:81');
});

cl.get('/socket.io/{protocol}', { headers: { referer: 'http://foo.bar.com:81/something' } }, function (res, data) {
res.statusCode.should.eql(200);
cl.end();
io.server.close();
done();
});
},

'test that erroneous referer port is denied for addr:port origin': function (done) {
var port = ++ports
, io = sio.listen(port)
, cl = client(port);

io.configure(function () {
io.set('origins', 'foo.bar.com:81');
});

cl.get('/socket.io/{protocol}', { headers: { referer: 'http://foo.bar.com/something' } }, function (res, data) {
res.statusCode.should.eql(403);
cl.end();
io.server.close();
done();
});
},

'test handshake cross domain access control': function (done) {
var port = ++ports
, io = sio.listen(port)
Expand Down

0 comments on commit 1d6488a

Please sign in to comment.