From 1b4e8add2603af43f25a1e17575453ba84db26d2 Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Wed, 20 Apr 2016 17:48:12 +0000 Subject: [PATCH 01/13] use in memory cache and JWT --- package.json | 1 + plugins/c9.preview/preview.handler.js | 77 +++++++++++++++------------ 2 files changed, 44 insertions(+), 34 deletions(-) diff --git a/package.json b/package.json index 0cf1512a..5ad953a6 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ ], "c9plugins": { "c9.ide.language": "#ebc064ef16", + "c9.ide.language.core": "#undefined", "c9.ide.language.css": "#be07d72209", "c9.ide.language.generic": "#3949510863", "c9.ide.language.html": "#22fdc74869", diff --git a/plugins/c9.preview/preview.handler.js b/plugins/c9.preview/preview.handler.js index 41539219..237479ff 100644 --- a/plugins/c9.preview/preview.handler.js +++ b/plugins/c9.preview/preview.handler.js @@ -17,6 +17,8 @@ define(function(require, exports, module) { var https = require("https"); var http = require("http"); var mime = require("mime"); + var jwt = require("jsonwebtoken"); + var Cache = require("c9/cache"); var metrics = imports.metrics; var parseUrl = require("url").parse; var debug = require("debug")("preview"); @@ -26,41 +28,46 @@ define(function(require, exports, module) { function getProjectSession() { return function(req, res, next) { - var session = req.session; - - req.user = req.user || { id: -1 }; - - var username = req.params.username; - var projectname = req.params.projectname; - - var ws = req.ws = username + "/" + projectname; + var cookieName = options.session.prefix + ".sso"; + var secret = options.session.secret; - if (!session.ws) - session.ws = {}; - - req.projectSession = session.ws[ws]; - - if ( - !req.projectSession || - !req.projectSession.expires || - req.projectSession.expires <= Date.now() || - req.projectSession.uid != req.user.id - ) { - req.projectSession = session.ws[ws] = { - expires: Date.now() + 10000 + var token = req.cookies && req.cookies[cookieName]; + if (token) { + jwt.verify(token, secret, function(err, user) { + if (err) { + if (err instanceof jwt.JsonWebTokenError || err instanceof jwt.TokenExpiredError) + return next(); + + return next(err); + } + + req.session = { + uid: user.id + }; + next(); + }); + } else { + req.session = { + uid: 0 }; + next(); } - next(); }; } function getRole(db) { + var roleCache = new Cache(5000, 5000); + return function(req, res, next) { - if (req.projectSession.role) { + var key = req.params.username + "/" + req.params.projectname + ":" + req.session.uid; + + var wsSession = roleCache.get(key); + if (wsSession) { + req.projectSession = wsSession; return next(); } - + db.Project.findOne({ username: req.params.username, name: req.params.projectname @@ -81,15 +88,19 @@ define(function(require, exports, module) { else return next(new error.Forbidden("You don't have access rights to preview this workspace")); } - req.projectSession.role = role; - req.projectSession.pid = project.id; - req.projectSession.uid = req.user.id; - var type = project.scm; - req.projectSession.type = type; + var wsSession = { + role: role, + pid: project.id, + uid: req.user.id, + type: project.scm, + }; - if (type != "docker" || project.state != db.Project.STATE_READY) + if (wsSession.type != "docker" || project.state != db.Project.STATE_READY) return next(); + + roleCache.set(key, wsSession); + req.projectSession = wsSession; project.populate("remote", function(err) { if (err) return next(err); @@ -100,10 +111,8 @@ define(function(require, exports, module) { if (err) return next(err); if (container.state == db.Container.STATE_RUNNING) - req.projectSession.proxyUrl = "http://" + meta.host + ":9000/" + meta.cid + "/home/ubuntu/workspace"; - else - req.projectSession.expires = Date.now() + 1000; - + wsSession.proxyUrl = "http://" + meta.host + ":9000/" + meta.cid + "/home/ubuntu/workspace"; + next(); }); } else { From 1139ff255d37b8978b574ad374427a4989b8a823 Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Fri, 27 May 2016 13:51:19 +0000 Subject: [PATCH 02/13] don't depend on session --- plugins/c9.preview/preview.handler.js | 19 +++++++++---------- plugins/c9.preview/preview.js | 6 +++--- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/plugins/c9.preview/preview.handler.js b/plugins/c9.preview/preview.handler.js index 237479ff..1f6695ee 100644 --- a/plugins/c9.preview/preview.handler.js +++ b/plugins/c9.preview/preview.handler.js @@ -52,7 +52,6 @@ define(function(require, exports, module) { }; next(); } - next(); }; } @@ -61,13 +60,13 @@ define(function(require, exports, module) { return function(req, res, next) { var key = req.params.username + "/" + req.params.projectname + ":" + req.session.uid; - + var wsSession = roleCache.get(key); if (wsSession) { req.projectSession = wsSession; return next(); } - + db.Project.findOne({ username: req.params.username, name: req.params.projectname @@ -77,13 +76,13 @@ define(function(require, exports, module) { if (err) return next(err); - project.getRole(req.user, function(err, role) { + project.getRole(req.session.uid, function(err, role) { if (err) return next(err); if (role == db.Project.ROLE_NONE) { if (project.isPublicPreview()) role = db.Project.ROLE_VISITOR; - else if (req.user.id == -1) + else if (req.session.uid == -1) return next(new error.Unauthorized()); else return next(new error.Forbidden("You don't have access rights to preview this workspace")); @@ -92,8 +91,8 @@ define(function(require, exports, module) { var wsSession = { role: role, pid: project.id, - uid: req.user.id, - type: project.scm, + uid: req.session.uid, + type: project.scm }; if (wsSession.type != "docker" || project.state != db.Project.STATE_READY) @@ -141,7 +140,7 @@ define(function(require, exports, module) { server = req.projectSession.vfsServer = server.internalUrl || server.url; } - var url = server + "/" + req.projectSession.pid + "/preview"; + var url = server + "/internal/" + req.projectSession.pid + "/preview"; req.proxyUrl = url; next(); @@ -153,8 +152,8 @@ define(function(require, exports, module) { var path = req.params.path; var url = req.proxyUrl + path; - if (req.user.code) - url += "?access_token=" + encodeURIComponent(req.user.code); + // if (req.user.code) + // url += "?access_token=" + encodeURIComponent(req.user.code); var parsedUrl = parseUrl(url); var httpModule = parsedUrl.protocol == "https:" ? https : http; diff --git a/plugins/c9.preview/preview.js b/plugins/c9.preview/preview.js index 657df128..3f0a5010 100644 --- a/plugins/c9.preview/preview.js +++ b/plugins/c9.preview/preview.js @@ -2,7 +2,7 @@ define(function(require, exports, module) { "use strict"; main.consumes = [ - "session", + "connect", "db", "c9.login", "preview.handler", @@ -14,7 +14,7 @@ define(function(require, exports, module) { return main; function main(options, imports, register) { - var session = imports.session; + var connect = imports.connect; var db = imports.db; var ensureLoggedIn = imports["c9.login"].ensureLoggedIn(); var handler = imports["preview.handler"]; @@ -38,7 +38,7 @@ define(function(require, exports, module) { api.use(userContent.redirectPreview()); - session.use(api); + connect.use(api); api.get("/:username/:projectname/:path*", { params: { From 435c2915c56cc675cd3818da8b3e4dc0b261514c Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Fri, 27 May 2016 14:13:31 +0000 Subject: [PATCH 03/13] anonymous user is -1 --- plugins/c9.preview/preview.handler.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/plugins/c9.preview/preview.handler.js b/plugins/c9.preview/preview.handler.js index 1f6695ee..b10df48b 100644 --- a/plugins/c9.preview/preview.handler.js +++ b/plugins/c9.preview/preview.handler.js @@ -48,7 +48,7 @@ define(function(require, exports, module) { }); } else { req.session = { - uid: 0 + uid: -1 }; next(); } @@ -125,7 +125,7 @@ define(function(require, exports, module) { function getProxyUrl(getServer) { return function(req, res, next) { - + if (req.projectSession.proxyUrl) { req.proxyUrl = req.projectSession.proxyUrl; return next(); @@ -140,7 +140,7 @@ define(function(require, exports, module) { server = req.projectSession.vfsServer = server.internalUrl || server.url; } - var url = server + "/internal/" + req.projectSession.pid + "/preview"; + var url = server.replace(/\/vfs$/, "/internal/vfs/") + req.session.uid + "/" + req.projectSession.pid + "/preview"; req.proxyUrl = url; next(); @@ -152,9 +152,7 @@ define(function(require, exports, module) { var path = req.params.path; var url = req.proxyUrl + path; - // if (req.user.code) - // url += "?access_token=" + encodeURIComponent(req.user.code); - + var parsedUrl = parseUrl(url); var httpModule = parsedUrl.protocol == "https:" ? https : http; From c2e82981b7cb2e027e4738d0d9ba4edb1b7a4d68 Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Mon, 30 May 2016 14:34:50 +0000 Subject: [PATCH 04/13] split computing the role and enforcing it so we can cache more --- plugins/c9.preview/preview.handler.js | 38 ++++++++++++++++++--------- plugins/c9.preview/preview.js | 1 + 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/plugins/c9.preview/preview.handler.js b/plugins/c9.preview/preview.handler.js index b10df48b..db108e8c 100644 --- a/plugins/c9.preview/preview.handler.js +++ b/plugins/c9.preview/preview.handler.js @@ -79,15 +79,6 @@ define(function(require, exports, module) { project.getRole(req.session.uid, function(err, role) { if (err) return next(err); - if (role == db.Project.ROLE_NONE) { - if (project.isPublicPreview()) - role = db.Project.ROLE_VISITOR; - else if (req.session.uid == -1) - return next(new error.Unauthorized()); - else - return next(new error.Forbidden("You don't have access rights to preview this workspace")); - } - var wsSession = { role: role, pid: project.id, @@ -95,12 +86,19 @@ define(function(require, exports, module) { type: project.scm }; - if (wsSession.type != "docker" || project.state != db.Project.STATE_READY) - return next(); - roleCache.set(key, wsSession); req.projectSession = wsSession; + if (role == db.Project.ROLE_NONE) { + if (project.isPublicPreview()) + role = db.Project.ROLE_VISITOR; + else + return next(); + } + + if (wsSession.type != "docker" || project.state != db.Project.STATE_READY) + return next(); + project.populate("remote", function(err) { if (err) return next(err); @@ -122,6 +120,21 @@ define(function(require, exports, module) { }); }; } + + function checkRole(db) { + return function(req, res, next) { + var role = req.projectSession.role; + + if (role == db.Project.ROLE_NONE) { + if (req.session.uid == -1) + return next(new error.Unauthorized()); + else + return next(new error.Forbidden("You don't have access rights to preview this workspace")); + } + + return next(); + }; + } function getProxyUrl(getServer) { return function(req, res, next) { @@ -363,6 +376,7 @@ define(function(require, exports, module) { "preview.handler": { getProjectSession: getProjectSession, getRole: getRole, + checkRole: checkRole, getProxyUrl: getProxyUrl, proxyCall: proxyCall } diff --git a/plugins/c9.preview/preview.js b/plugins/c9.preview/preview.js index b47957f3..9c222818 100644 --- a/plugins/c9.preview/preview.js +++ b/plugins/c9.preview/preview.js @@ -55,6 +55,7 @@ define(function(require, exports, module) { require("./lib/middleware/block-dot-files"), handler.getProjectSession(), handler.getRole(db), + handler.checkRole(db), handler.getProxyUrl(function() { return getVfsServers()[0] || null; }), From 77f826bdc6e3db90ba1d67670947c15de5d196e1 Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Mon, 30 May 2016 14:43:03 +0000 Subject: [PATCH 05/13] increase cache size and add to SDK config --- plugins/c9.preview/preview.handler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/c9.preview/preview.handler.js b/plugins/c9.preview/preview.handler.js index db108e8c..bc6bbcd3 100644 --- a/plugins/c9.preview/preview.handler.js +++ b/plugins/c9.preview/preview.handler.js @@ -56,7 +56,7 @@ define(function(require, exports, module) { } function getRole(db) { - var roleCache = new Cache(5000, 5000); + var roleCache = new Cache(10000, 10000); return function(req, res, next) { var key = req.params.username + "/" + req.params.projectname + ":" + req.session.uid; From 4ad158f031bb3bdfe29a493b033c5b6e0bc8349f Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Mon, 30 May 2016 14:45:09 +0000 Subject: [PATCH 06/13] remove hack --- .../connect-architect/connect.session/session-ext.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/node_modules/connect-architect/connect.session/session-ext.js b/node_modules/connect-architect/connect.session/session-ext.js index 3b8fc9e9..dd8cf6ea 100644 --- a/node_modules/connect-architect/connect.session/session-ext.js +++ b/node_modules/connect-architect/connect.session/session-ext.js @@ -30,15 +30,6 @@ module.exports = function startup(options, imports, register) { var sessionRoutes = connectModule(); connect.useSession(sessionRoutes); - - sessionRoutes.use( - function(req, res, next) { - if (/^\/geckolala\//.test(req.url)) - return next(new error.TooManyRequests("Rate limit exceeded")); - next(); - } - ); - sessionRoutes.use(Session(sessionOptions, cookie)); register(null, { From 290550f86e0d465f79cdc81fc019a0ae564c1516 Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Tue, 31 May 2016 09:19:28 +0000 Subject: [PATCH 07/13] address review comments --- plugins/c9.preview/preview.handler.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/plugins/c9.preview/preview.handler.js b/plugins/c9.preview/preview.handler.js index bc6bbcd3..4a7667de 100644 --- a/plugins/c9.preview/preview.handler.js +++ b/plugins/c9.preview/preview.handler.js @@ -31,6 +31,10 @@ define(function(require, exports, module) { var cookieName = options.session.prefix + ".sso"; var secret = options.session.secret; + req.session = { + uid: -1 + }; + var token = req.cookies && req.cookies[cookieName]; if (token) { jwt.verify(token, secret, function(err, user) { @@ -47,9 +51,6 @@ define(function(require, exports, module) { next(); }); } else { - req.session = { - uid: -1 - }; next(); } }; @@ -91,7 +92,7 @@ define(function(require, exports, module) { if (role == db.Project.ROLE_NONE) { if (project.isPublicPreview()) - role = db.Project.ROLE_VISITOR; + wsSession.role = db.Project.ROLE_VISITOR; else return next(); } From 09736fa7bb805556cd2dc1ee44d86d1cc63e59d0 Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Tue, 31 May 2016 14:52:03 +0000 Subject: [PATCH 08/13] no need to compromise security. We have the code in the cookie --- plugins/c9.preview/preview.handler.js | 23 ++++++++++++----------- plugins/c9.preview/preview.js | 1 - 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/plugins/c9.preview/preview.handler.js b/plugins/c9.preview/preview.handler.js index 4a7667de..339e6b29 100644 --- a/plugins/c9.preview/preview.handler.js +++ b/plugins/c9.preview/preview.handler.js @@ -31,7 +31,8 @@ define(function(require, exports, module) { var cookieName = options.session.prefix + ".sso"; var secret = options.session.secret; - req.session = { + req.session = {}; + req.user = { uid: -1 }; @@ -45,9 +46,7 @@ define(function(require, exports, module) { return next(err); } - req.session = { - uid: user.id - }; + req.user = user; next(); }); } else { @@ -60,7 +59,7 @@ define(function(require, exports, module) { var roleCache = new Cache(10000, 10000); return function(req, res, next) { - var key = req.params.username + "/" + req.params.projectname + ":" + req.session.uid; + var key = req.params.username + "/" + req.params.projectname + ":" + req.user.id; var wsSession = roleCache.get(key); if (wsSession) { @@ -77,13 +76,13 @@ define(function(require, exports, module) { if (err) return next(err); - project.getRole(req.session.uid, function(err, role) { + project.getRole(req.user.id, function(err, role) { if (err) return next(err); var wsSession = { role: role, pid: project.id, - uid: req.session.uid, + uid: req.user.id, type: project.scm }; @@ -127,7 +126,7 @@ define(function(require, exports, module) { var role = req.projectSession.role; if (role == db.Project.ROLE_NONE) { - if (req.session.uid == -1) + if (req.user.id == -1) return next(new error.Unauthorized()); else return next(new error.Forbidden("You don't have access rights to preview this workspace")); @@ -154,8 +153,8 @@ define(function(require, exports, module) { server = req.projectSession.vfsServer = server.internalUrl || server.url; } - var url = server.replace(/\/vfs$/, "/internal/vfs/") + req.session.uid + "/" + req.projectSession.pid + "/preview"; - + var url = server + "/" + req.projectSession.pid + "/preview"; + req.proxyUrl = url; next(); }; @@ -166,7 +165,9 @@ define(function(require, exports, module) { var path = req.params.path; var url = req.proxyUrl + path; - + if (req.user.code) + url += "?access_token=" + encodeURIComponent(req.user.code); + var parsedUrl = parseUrl(url); var httpModule = parsedUrl.protocol == "https:" ? https : http; diff --git a/plugins/c9.preview/preview.js b/plugins/c9.preview/preview.js index 9c222818..ab2b64b0 100644 --- a/plugins/c9.preview/preview.js +++ b/plugins/c9.preview/preview.js @@ -20,7 +20,6 @@ define(function(require, exports, module) { var handler = imports["preview.handler"]; var userContent = imports["user-content.redirect"]; var getVfsServers = imports["vfs.serverlist"].getServers; - var ratelimit = require("c9/ratelimit"); var frontdoor = require("frontdoor"); var error = require("http-error"); From d1e1c5fce09ba51856536c7e318d72e5590bc7d1 Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Tue, 31 May 2016 14:52:39 +0000 Subject: [PATCH 09/13] handle --exclude properly apps-proxy would also exclude proxy --- server.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/server.js b/server.js index dd92d9dc..ddda7ec9 100755 --- a/server.js +++ b/server.js @@ -91,8 +91,10 @@ function main(argv, config, onLoaded) { var configs = options.argv._; if (!configs.length) configs = [config || DEFAULT_CONFIG]; - if (options.argv.exclude && !Array.isArray(options.argv.exclude.length)) - options.argv.exclude = [options.argv.exclude]; + + var exclude = options.argv.exclude || []; + if (typeof exclude == "string") + exclude = exclude.split(","); var expanded = expandShortCuts(configs); @@ -120,7 +122,7 @@ function main(argv, config, onLoaded) { function startConfigs(configs, done) { async.each(configs, function(config, next) { - if (options.argv.exclude && options.argv.exclude.indexOf(config) > -1) + if (exclude && exclude.indexOf(config) > -1) return next(); start(config, options, function(err, result, path) { onLoaded && onLoaded(err, result, path); From 889dd2ccee67d049022d58047d2a1c37a8521415 Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Wed, 1 Jun 2016 10:12:32 +0000 Subject: [PATCH 10/13] only parse JWT once --- plugins/c9.preview/preview.handler.js | 66 ++++++++------------------- plugins/c9.preview/preview.js | 3 -- 2 files changed, 19 insertions(+), 50 deletions(-) diff --git a/plugins/c9.preview/preview.handler.js b/plugins/c9.preview/preview.handler.js index 339e6b29..51b8ca2f 100644 --- a/plugins/c9.preview/preview.handler.js +++ b/plugins/c9.preview/preview.handler.js @@ -17,7 +17,6 @@ define(function(require, exports, module) { var https = require("https"); var http = require("http"); var mime = require("mime"); - var jwt = require("jsonwebtoken"); var Cache = require("c9/cache"); var metrics = imports.metrics; var parseUrl = require("url").parse; @@ -26,44 +25,21 @@ define(function(require, exports, module) { var staticPrefix = imports["connect.static"].getStaticPrefix(); - function getProjectSession() { - return function(req, res, next) { - var cookieName = options.session.prefix + ".sso"; - var secret = options.session.secret; - - req.session = {}; - req.user = { - uid: -1 - }; - - var token = req.cookies && req.cookies[cookieName]; - if (token) { - jwt.verify(token, secret, function(err, user) { - if (err) { - if (err instanceof jwt.JsonWebTokenError || err instanceof jwt.TokenExpiredError) - return next(); - - return next(err); - } - - req.user = user; - next(); - }); - } else { - next(); - } - }; - } - function getRole(db) { var roleCache = new Cache(10000, 10000); return function(req, res, next) { + if (!req.user) { + req.user = { + id: -1 + }; + } + var key = req.params.username + "/" + req.params.projectname + ":" + req.user.id; var wsSession = roleCache.get(key); if (wsSession) { - req.projectSession = wsSession; + req.session = wsSession; return next(); } @@ -87,13 +63,13 @@ define(function(require, exports, module) { }; roleCache.set(key, wsSession); - req.projectSession = wsSession; + req.session = wsSession; if (role == db.Project.ROLE_NONE) { - if (project.isPublicPreview()) - wsSession.role = db.Project.ROLE_VISITOR; - else + if (!project.isPublicPreview()) return next(); + + wsSession.role = db.Project.ROLE_VISITOR; } if (wsSession.type != "docker" || project.state != db.Project.STATE_READY) @@ -123,7 +99,7 @@ define(function(require, exports, module) { function checkRole(db) { return function(req, res, next) { - var role = req.projectSession.role; + var role = req.session.role; if (role == db.Project.ROLE_NONE) { if (req.user.id == -1) @@ -139,21 +115,21 @@ define(function(require, exports, module) { function getProxyUrl(getServer) { return function(req, res, next) { - if (req.projectSession.proxyUrl) { - req.proxyUrl = req.projectSession.proxyUrl; + if (req.session.proxyUrl) { + req.proxyUrl = req.session.proxyUrl; return next(); } - var server = req.projectSession.vfsServer; + var server = req.session.vfsServer; if (!server) { server = getServer(); if (!server || !server.url) return next(new error.ServiceUnavailable("No VFS server found")); - server = req.projectSession.vfsServer = server.internalUrl || server.url; + server = req.session.vfsServer = server.internalUrl || server.url; } - var url = server + "/" + req.projectSession.pid + "/preview"; + var url = server + "/" + req.session.pid + "/preview"; req.proxyUrl = url; next(); @@ -165,9 +141,9 @@ define(function(require, exports, module) { var path = req.params.path; var url = req.proxyUrl + path; - if (req.user.code) + if (req.user.code) url += "?access_token=" + encodeURIComponent(req.user.code); - + var parsedUrl = parseUrl(url); var httpModule = parsedUrl.protocol == "https:" ? https : http; @@ -233,9 +209,6 @@ define(function(require, exports, module) { } else if (body.indexOf("ENOENT") !== -1 || statusCode == 404) { next(new error.NotFound("File '" + path + "' could not be found!")); } else { - if (req.session.ws) - delete req.session.ws[req.ws]; - var json; try { json = JSON.parse(body); @@ -376,7 +349,6 @@ define(function(require, exports, module) { register(null, { "preview.handler": { - getProjectSession: getProjectSession, getRole: getRole, checkRole: checkRole, getProxyUrl: getProxyUrl, diff --git a/plugins/c9.preview/preview.js b/plugins/c9.preview/preview.js index ab2b64b0..27b84391 100644 --- a/plugins/c9.preview/preview.js +++ b/plugins/c9.preview/preview.js @@ -52,7 +52,6 @@ define(function(require, exports, module) { requestTimeout(15*60*1000), require("./lib/middleware/sanitize-path-param"), require("./lib/middleware/block-dot-files"), - handler.getProjectSession(), handler.getRole(db), handler.checkRole(db), handler.getProxyUrl(function() { @@ -63,8 +62,6 @@ define(function(require, exports, module) { api.error(function(err, req, res, next) { if (err instanceof error.Unauthorized) { - req.logout(); - delete req.session.token; return ensureLoggedIn(req, res, next); } return next(err); From 1f04a3aec315ac0fe930a85457edee9917427821 Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Wed, 1 Jun 2016 11:42:38 +0000 Subject: [PATCH 11/13] cleanups --- plugins/c9.preview/preview.handler.js | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/c9.preview/preview.handler.js b/plugins/c9.preview/preview.handler.js index 51b8ca2f..ba05e5b1 100644 --- a/plugins/c9.preview/preview.handler.js +++ b/plugins/c9.preview/preview.handler.js @@ -34,6 +34,7 @@ define(function(require, exports, module) { id: -1 }; } + req.session = {}; var key = req.params.username + "/" + req.params.projectname + ":" + req.user.id; From babf7a171b9272fff4499cfe983bd9246fe03665 Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Thu, 23 Jun 2016 11:01:27 +0000 Subject: [PATCH 12/13] add preview unit test --- plugins/c9.preview/preview_test.js | 159 +++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 plugins/c9.preview/preview_test.js diff --git a/plugins/c9.preview/preview_test.js b/plugins/c9.preview/preview_test.js new file mode 100644 index 00000000..2030fe59 --- /dev/null +++ b/plugins/c9.preview/preview_test.js @@ -0,0 +1,159 @@ +#!/usr/bin/env node +/*global describe it before after beforeEach afterEach */ + +"use strict"; +"use server"; + +require("c9/inline-mocha")(module); +require("c9/setup_paths"); + +var async = require("async"); +var assert = require("assert"); +var nock = require("nock"); + +var RestClient = require("c9/rest_client"); +var baseTest = require('../c9.api/base_test'); +var testDb = require("../c9.db.redis/test_redis"); +var setupFixtures = require("test/lib/integration/setup"); + +describe(__filename, function() { + + var db, serverList, client; + var testUser, testProject, testRemote, testContainer; + var loggedInUser = null; + + before(function(next) { + baseTest({ + config: "preview", + }, function(err, services) { + db = services.db; + serverList = services["vfs.serverlist"]; + + services.connect.useSetup(function(req, res, next) { + req.user = loggedInUser; + next(); + }); + + client = new RestClient("localhost", services.apiPort, { + debug: false + }); + + testUser = require("test/lib/integration/db/user")(db); + testProject = require("test/lib/integration/db/project")(db); + testRemote = require("test/lib/integration/db/mock-remote")(db); + testContainer = require("test/lib/integration/db/mock-container")(db); + + next(err); + }); + }); + + after(function(next) { + testDb.stop(next); + }); + + beforeEach(function(next) { + serverList._testSetServerList([{ + url: "http://vfs.c9.dev", + internalUrl: "http://vfs.c9.dev" + }]); + testDb.reset(next); + }); + + describe("preview", function() { + it("should do stuff", function(next) { + var user1, user2; + var public1, private1, private2; + + // user1 user2 + // user2/public + // user2/private1 user1 has no access + // user2/private2 user1 is collaborator + + setupFixtures( + testUser.create(), + testUser.create(), + testProject.create(), + testRemote.create({type: "docker"}), + testContainer.create(), + testProject.create(), + testRemote.create({type: "docker"}), + testContainer.create(), + testProject.create(), + testRemote.create({type: "docker"}), + testContainer.create(), + function(ctx, next) { + user1 = ctx.users[0]; + user2 = ctx.users[1]; + public1 = ctx.projects[0]; + private1 = ctx.projects[1]; + private2 = ctx.projects[2]; + next(); + }, + function(ctx, next) { + public1.owner = user2; + public1.visibility = "public"; + public1.save(next); + }, + function(ctx, next) { + private1.owner = user2; + private1.visibility = "private"; + private1.save(next); + }, + function(ctx, next) { + private2.owner = user2; + private2.visibility = "private"; + private2.save(next); + }, + function(ctx, next) { + db.WorkspaceMember.create( + private2, + user1.id, + db.WorkspaceMember.ACL_R, + db.Project.ROLE_COLLABORATOR, null, next + ); + }, + function(fixtures, teardown) { + /* + * Logged in Role Visibility ACTION + * ================================================================= + * true none public view + * false none public view + * true none private forbidden + * false none private unauthorized + * true visitor/collaborator/admin public view + * true visitor/collaborator/admin private view + */ + + var expect = [ + { uid: user1.id, role: db.Project.ROLE_NONE, p: public1, code: 200 }, + { uid: -1, role: db.Project.ROLE_NONE, p: public1, code: 200 }, + { uid: user1.id, role: db.Project.ROLE_NONE, p: private1, code: 403 }, + { uid: -1, role: db.Project.ROLE_NONE, p: private1, code: 302 }, // redirect to login page + { uid: user1.id, role: db.Project.ROLE_COLLABORATOR, p: private2, code: 200 }, + { uid: user2.id, role: db.Project.ROLE_ADMIN, p: private2, code: 200 } + ]; + + async.eachSeries(expect, function(expect, next) { + var path = "/" + expect.p.owner.name + "/" + expect.p.name + "/"; + + nock('http://vfs.c9.dev') + .get("/" + expect.p.id + "/preview/") + .reply(200, []); + + loggedInUser = { + id: expect.uid + }; + + client.get(path, function (err, res) { + assert((err && err.code) == expect.code || expect.code == 200, "Wrong return code"); + next(); + }); + }, function(err) { + if (err) return next(err); + teardown(next); + }); + } + ); + }); + }); +}); \ No newline at end of file From 5bf513c80adf30ba12f7bb1e14a56a0964e684b5 Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Thu, 23 Jun 2016 16:52:13 +0200 Subject: [PATCH 13/13] process review --- plugins/c9.preview/preview_test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/c9.preview/preview_test.js b/plugins/c9.preview/preview_test.js index 2030fe59..3a0f774a 100644 --- a/plugins/c9.preview/preview_test.js +++ b/plugins/c9.preview/preview_test.js @@ -60,7 +60,7 @@ describe(__filename, function() { }); describe("preview", function() { - it("should do stuff", function(next) { + it("Should authorize users correctly", function(next) { var user1, user2; var public1, private1, private2; @@ -129,7 +129,7 @@ describe(__filename, function() { { uid: -1, role: db.Project.ROLE_NONE, p: public1, code: 200 }, { uid: user1.id, role: db.Project.ROLE_NONE, p: private1, code: 403 }, { uid: -1, role: db.Project.ROLE_NONE, p: private1, code: 302 }, // redirect to login page - { uid: user1.id, role: db.Project.ROLE_COLLABORATOR, p: private2, code: 200 }, + { uid: user1.id, role: db.Project.ROLE_COLLABORATOR, p: public1, code: 200 }, { uid: user2.id, role: db.Project.ROLE_ADMIN, p: private2, code: 200 } ]; @@ -156,4 +156,4 @@ describe(__filename, function() { ); }); }); -}); \ No newline at end of file +});