From 1cc0cbe8fc4f89709417305de9d2ba9bac9492be Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 30 Jun 2015 14:38:32 +0100 Subject: [PATCH] split site into 2 routers, webRouter and apiRouter web router has things like sessions etc added onto it. Api router is minimal, doesn't include things like csrf --- .../Features/Analytics/AnalyticsRouter.coffee | 5 + .../Collaborators/CollaboratorsRouter.coffee | 10 +- .../Features/Editor/EditorRouter.coffee | 21 +- .../PasswordReset/PasswordResetRouter.coffee | 10 +- .../RealTimeProxy/RealTimeProxyRouter.coffee | 4 +- .../StaticPages/StaticPagesRouter.coffee | 24 +-- .../Subscription/SubscriptionRouter.coffee | 45 ++-- .../Features/Uploads/UploadsRouter.coffee | 6 +- .../infrastructure/ExpressLocals.coffee | 6 +- .../app/coffee/infrastructure/Modules.coffee | 4 +- .../app/coffee/infrastructure/Server.coffee | 65 +++--- services/web/app/coffee/router.coffee | 201 +++++++++--------- 12 files changed, 206 insertions(+), 195 deletions(-) create mode 100644 services/web/app/coffee/Features/Analytics/AnalyticsRouter.coffee diff --git a/services/web/app/coffee/Features/Analytics/AnalyticsRouter.coffee b/services/web/app/coffee/Features/Analytics/AnalyticsRouter.coffee new file mode 100644 index 0000000000..a9e0a0028b --- /dev/null +++ b/services/web/app/coffee/Features/Analytics/AnalyticsRouter.coffee @@ -0,0 +1,5 @@ +AnalyticsController = require('./AnalyticsController') + +module.exports = + apply: (webRouter, apiRouter) -> + webRouter.post '/event/:event', AnalyticsController.recordEvent diff --git a/services/web/app/coffee/Features/Collaborators/CollaboratorsRouter.coffee b/services/web/app/coffee/Features/Collaborators/CollaboratorsRouter.coffee index d7df1f299b..b327c50e9d 100644 --- a/services/web/app/coffee/Features/Collaborators/CollaboratorsRouter.coffee +++ b/services/web/app/coffee/Features/Collaborators/CollaboratorsRouter.coffee @@ -3,9 +3,9 @@ SecurityManager = require('../../managers/SecurityManager') AuthenticationController = require('../Authentication/AuthenticationController') module.exports = - apply: (app) -> - app.post '/project/:project_id/leave', AuthenticationController.requireLogin(), CollaboratorsController.removeSelfFromProject - app.get '/project/:Project_id/collaborators', SecurityManager.requestCanAccessProject(allow_auth_token: true), CollaboratorsController.getCollaborators + apply: (webRouter, apiRouter) -> + webRouter.post '/project/:project_id/leave', AuthenticationController.requireLogin(), CollaboratorsController.removeSelfFromProject + apiRouter.get '/project/:Project_id/collaborators', SecurityManager.requestCanAccessProject(allow_auth_token: true), CollaboratorsController.getCollaborators - app.post '/project/:Project_id/users', SecurityManager.requestIsOwner, CollaboratorsController.addUserToProject - app.delete '/project/:Project_id/users/:user_id', SecurityManager.requestIsOwner, CollaboratorsController.removeUserFromProject + webRouter.post '/project/:Project_id/users', SecurityManager.requestIsOwner, CollaboratorsController.addUserToProject + webRouter.delete '/project/:Project_id/users/:user_id', SecurityManager.requestIsOwner, CollaboratorsController.removeUserFromProject diff --git a/services/web/app/coffee/Features/Editor/EditorRouter.coffee b/services/web/app/coffee/Features/Editor/EditorRouter.coffee index 1902506948..0576a4adce 100644 --- a/services/web/app/coffee/Features/Editor/EditorRouter.coffee +++ b/services/web/app/coffee/Features/Editor/EditorRouter.coffee @@ -3,21 +3,20 @@ SecurityManager = require('../../managers/SecurityManager') AuthenticationController = require "../Authentication/AuthenticationController" module.exports = - apply: (app) -> - app.post '/project/:Project_id/doc', SecurityManager.requestCanModifyProject, EditorHttpController.addDoc - app.post '/project/:Project_id/folder', SecurityManager.requestCanModifyProject, EditorHttpController.addFolder + apply: (webRouter, apiRouter) -> + webRouter.post '/project/:Project_id/doc', SecurityManager.requestCanModifyProject, EditorHttpController.addDoc + webRouter.post '/project/:Project_id/folder', SecurityManager.requestCanModifyProject, EditorHttpController.addFolder - app.post '/project/:Project_id/:entity_type/:entity_id/rename', SecurityManager.requestCanModifyProject, EditorHttpController.renameEntity - app.post '/project/:Project_id/:entity_type/:entity_id/move', SecurityManager.requestCanModifyProject, EditorHttpController.moveEntity + webRouter.post '/project/:Project_id/:entity_type/:entity_id/rename', SecurityManager.requestCanModifyProject, EditorHttpController.renameEntity + webRouter.post '/project/:Project_id/:entity_type/:entity_id/move', SecurityManager.requestCanModifyProject, EditorHttpController.moveEntity - app.delete '/project/:Project_id/file/:entity_id', SecurityManager.requestCanModifyProject, EditorHttpController.deleteFile - app.delete '/project/:Project_id/doc/:entity_id', SecurityManager.requestCanModifyProject, EditorHttpController.deleteDoc - app.delete '/project/:Project_id/folder/:entity_id', SecurityManager.requestCanModifyProject, EditorHttpController.deleteFolder + webRouter.delete '/project/:Project_id/file/:entity_id', SecurityManager.requestCanModifyProject, EditorHttpController.deleteFile + webRouter.delete '/project/:Project_id/doc/:entity_id', SecurityManager.requestCanModifyProject, EditorHttpController.deleteDoc + webRouter.delete '/project/:Project_id/folder/:entity_id', SecurityManager.requestCanModifyProject, EditorHttpController.deleteFolder - app.post '/project/:Project_id/doc/:doc_id/restore', SecurityManager.requestCanModifyProject, EditorHttpController.restoreDoc + webRouter.post '/project/:Project_id/doc/:doc_id/restore', SecurityManager.requestCanModifyProject, EditorHttpController.restoreDoc # Called by the real-time API to load up the current project state. # This is a post request because it's more than just a getting of data. We take actions # whenever a user joins a project, like updating the deleted status. - app.post '/project/:Project_id/join', AuthenticationController.httpAuth, EditorHttpController.joinProject - app.ignoreCsrf('post', '/project/:Project_id/join') \ No newline at end of file + apiRouter.post '/project/:Project_id/join', AuthenticationController.httpAuth, EditorHttpController.joinProject diff --git a/services/web/app/coffee/Features/PasswordReset/PasswordResetRouter.coffee b/services/web/app/coffee/Features/PasswordReset/PasswordResetRouter.coffee index 057304d458..e049d43075 100644 --- a/services/web/app/coffee/Features/PasswordReset/PasswordResetRouter.coffee +++ b/services/web/app/coffee/Features/PasswordReset/PasswordResetRouter.coffee @@ -2,13 +2,13 @@ PasswordResetController = require("./PasswordResetController") AuthenticationController = require('../Authentication/AuthenticationController') module.exports = - apply: (app) -> + apply: (webRouter, apiRouter) -> - app.get '/user/password/reset', PasswordResetController.renderRequestResetForm - app.post '/user/password/reset', PasswordResetController.requestReset + webRouter.get '/user/password/reset', PasswordResetController.renderRequestResetForm + webRouter.post '/user/password/reset', PasswordResetController.requestReset AuthenticationController.addEndpointToLoginWhitelist '/user/password/reset' - app.get '/user/password/set', PasswordResetController.renderSetPasswordForm - app.post '/user/password/set', PasswordResetController.setNewUserPassword + webRouter.get '/user/password/set', PasswordResetController.renderSetPasswordForm + webRouter.post '/user/password/set', PasswordResetController.setNewUserPassword AuthenticationController.addEndpointToLoginWhitelist '/user/password/set' diff --git a/services/web/app/coffee/Features/RealTimeProxy/RealTimeProxyRouter.coffee b/services/web/app/coffee/Features/RealTimeProxy/RealTimeProxyRouter.coffee index 4fbf06c091..0672520f31 100644 --- a/services/web/app/coffee/Features/RealTimeProxy/RealTimeProxyRouter.coffee +++ b/services/web/app/coffee/Features/RealTimeProxy/RealTimeProxyRouter.coffee @@ -10,8 +10,8 @@ wsProxy = httpProxy.createProxyServer({ }) module.exports = - apply: (app) -> - app.all /\/socket\.io\/.*/, (req, res, next) -> + apply: (webRouter, apiRouter) -> + webRouter.all /\/socket\.io\/.*/, (req, res, next) -> proxy.web req, res, next setTimeout () -> diff --git a/services/web/app/coffee/Features/StaticPages/StaticPagesRouter.coffee b/services/web/app/coffee/Features/StaticPages/StaticPagesRouter.coffee index ab68fd7469..f1079cc5b7 100644 --- a/services/web/app/coffee/Features/StaticPages/StaticPagesRouter.coffee +++ b/services/web/app/coffee/Features/StaticPages/StaticPagesRouter.coffee @@ -3,18 +3,18 @@ UniversityController = require("./UniversityController") module.exports = - apply: (app) -> - app.get '/', HomeController.index - app.get '/home', HomeController.home + apply: (webRouter, apiRouter) -> + webRouter.get '/', HomeController.index + webRouter.get '/home', HomeController.home - app.get '/tos', HomeController.externalPage("tos", "Terms of Service") - app.get '/about', HomeController.externalPage("about", "About Us") - app.get '/security', HomeController.externalPage("security", "Security") - app.get '/privacy_policy', HomeController.externalPage("privacy", "Privacy Policy") - app.get '/planned_maintenance', HomeController.externalPage("planned_maintenance", "Planned Maintenance") - app.get '/style', HomeController.externalPage("style_guide", "Style Guide") + webRouter.get '/tos', HomeController.externalPage("tos", "Terms of Service") + webRouter.get '/about', HomeController.externalPage("about", "About Us") + webRouter.get '/security', HomeController.externalPage("security", "Security") + webRouter.get '/privacy_policy', HomeController.externalPage("privacy", "Privacy Policy") + webRouter.get '/planned_maintenance', HomeController.externalPage("planned_maintenance", "Planned Maintenance") + webRouter.get '/style', HomeController.externalPage("style_guide", "Style Guide") - app.get '/dropbox', HomeController.externalPage("dropbox", "Dropbox and ShareLaTeX") + webRouter.get '/dropbox', HomeController.externalPage("dropbox", "Dropbox and ShareLaTeX") - app.get '/university', UniversityController.getIndexPage - app.get '/university/*', UniversityController.getPage \ No newline at end of file + webRouter.get '/university', UniversityController.getIndexPage + webRouter.get '/university/*', UniversityController.getPage \ No newline at end of file diff --git a/services/web/app/coffee/Features/Subscription/SubscriptionRouter.coffee b/services/web/app/coffee/Features/Subscription/SubscriptionRouter.coffee index 2db399152f..76dded3f4d 100644 --- a/services/web/app/coffee/Features/Subscription/SubscriptionRouter.coffee +++ b/services/web/app/coffee/Features/Subscription/SubscriptionRouter.coffee @@ -4,44 +4,43 @@ SubscriptionGroupController = require './SubscriptionGroupController' Settings = require "settings-sharelatex" module.exports = - apply: (app) -> + apply: (webRouter, apiRouter) -> return unless Settings.enableSubscriptions - app.get '/user/subscription/plans', SubscriptionController.plansPage + webRouter.get '/user/subscription/plans', SubscriptionController.plansPage - app.get '/user/subscription', AuthenticationController.requireLogin(), SubscriptionController.userSubscriptionPage + webRouter.get '/user/subscription', AuthenticationController.requireLogin(), SubscriptionController.userSubscriptionPage - app.get '/user/subscription/custom_account', AuthenticationController.requireLogin(), SubscriptionController.userCustomSubscriptionPage + webRouter.get '/user/subscription/custom_account', AuthenticationController.requireLogin(), SubscriptionController.userCustomSubscriptionPage - app.get '/user/subscription/new', AuthenticationController.requireLogin(), SubscriptionController.paymentPage - app.get '/user/subscription/billing-details/edit', AuthenticationController.requireLogin(), SubscriptionController.editBillingDetailsPage + webRouter.get '/user/subscription/new', AuthenticationController.requireLogin(), SubscriptionController.paymentPage + webRouter.get '/user/subscription/billing-details/edit', AuthenticationController.requireLogin(), SubscriptionController.editBillingDetailsPage - app.get '/user/subscription/thank-you', AuthenticationController.requireLogin(), SubscriptionController.successful_subscription + webRouter.get '/user/subscription/thank-you', AuthenticationController.requireLogin(), SubscriptionController.successful_subscription - app.get '/subscription/group', AuthenticationController.requireLogin(), SubscriptionGroupController.renderSubscriptionGroupAdminPage - app.post '/subscription/group/user', AuthenticationController.requireLogin(), SubscriptionGroupController.addUserToGroup - app.get '/subscription/group/export', AuthenticationController.requireLogin(), SubscriptionGroupController.exportGroupCsv - app.delete '/subscription/group/user/:user_id', AuthenticationController.requireLogin(), SubscriptionGroupController.removeUserFromGroup + webRouter.get '/subscription/group', AuthenticationController.requireLogin(), SubscriptionGroupController.renderSubscriptionGroupAdminPage + webRouter.post '/subscription/group/user', AuthenticationController.requireLogin(), SubscriptionGroupController.addUserToGroup + webRouter.get '/subscription/group/export', AuthenticationController.requireLogin(), SubscriptionGroupController.exportGroupCsv + webRouter.delete '/subscription/group/user/:user_id', AuthenticationController.requireLogin(), SubscriptionGroupController.removeUserFromGroup - app.get '/user/subscription/:subscription_id/group/invited', AuthenticationController.requireLogin(), SubscriptionGroupController.renderGroupInvitePage - app.post '/user/subscription/:subscription_id/group/begin-join', AuthenticationController.requireLogin(), SubscriptionGroupController.beginJoinGroup - app.get '/user/subscription/:subscription_id/group/complete-join', AuthenticationController.requireLogin(), SubscriptionGroupController.completeJoin - app.get '/user/subscription/:subscription_id/group/successful-join', AuthenticationController.requireLogin(), SubscriptionGroupController.renderSuccessfulJoinPage + webRouter.get '/user/subscription/:subscription_id/group/invited', AuthenticationController.requireLogin(), SubscriptionGroupController.renderGroupInvitePage + webRouter.post '/user/subscription/:subscription_id/group/begin-join', AuthenticationController.requireLogin(), SubscriptionGroupController.beginJoinGroup + webRouter.get '/user/subscription/:subscription_id/group/complete-join', AuthenticationController.requireLogin(), SubscriptionGroupController.completeJoin + webRouter.get '/user/subscription/:subscription_id/group/successful-join', AuthenticationController.requireLogin(), SubscriptionGroupController.renderSuccessfulJoinPage #recurly callback - app.post '/user/subscription/callback', SubscriptionController.recurlyNotificationParser, SubscriptionController.recurlyCallback - app.ignoreCsrf("post", '/user/subscription/callback') + apiRouter.post '/user/subscription/callback', SubscriptionController.recurlyNotificationParser, SubscriptionController.recurlyCallback #user changes their account state - app.post '/user/subscription/create', AuthenticationController.requireLogin(), SubscriptionController.createSubscription - app.post '/user/subscription/update', AuthenticationController.requireLogin(), SubscriptionController.updateSubscription - app.post '/user/subscription/cancel', AuthenticationController.requireLogin(), SubscriptionController.cancelSubscription - app.post '/user/subscription/reactivate', AuthenticationController.requireLogin(), SubscriptionController.reactivateSubscription + webRouter.post '/user/subscription/create', AuthenticationController.requireLogin(), SubscriptionController.createSubscription + webRouter.post '/user/subscription/update', AuthenticationController.requireLogin(), SubscriptionController.updateSubscription + webRouter.post '/user/subscription/cancel', AuthenticationController.requireLogin(), SubscriptionController.cancelSubscription + webRouter.post '/user/subscription/reactivate', AuthenticationController.requireLogin(), SubscriptionController.reactivateSubscription - app.get "/user/subscription/upgrade-annual", AuthenticationController.requireLogin(), SubscriptionController.renderUpgradeToAnnualPlanPage - app.post "/user/subscription/upgrade-annual", AuthenticationController.requireLogin(), SubscriptionController.processUpgradeToAnnualPlan + webRouter.get "/user/subscription/upgrade-annual", AuthenticationController.requireLogin(), SubscriptionController.renderUpgradeToAnnualPlanPage + webRouter.post "/user/subscription/upgrade-annual", AuthenticationController.requireLogin(), SubscriptionController.processUpgradeToAnnualPlan diff --git a/services/web/app/coffee/Features/Uploads/UploadsRouter.coffee b/services/web/app/coffee/Features/Uploads/UploadsRouter.coffee index f77cb4bfc5..bf4b9f3ea4 100644 --- a/services/web/app/coffee/Features/Uploads/UploadsRouter.coffee +++ b/services/web/app/coffee/Features/Uploads/UploadsRouter.coffee @@ -3,11 +3,11 @@ AuthenticationController = require('../Authentication/AuthenticationController') ProjectUploadController = require "./ProjectUploadController" module.exports = - apply: (app) -> - app.post '/project/new/upload', + apply: (webRouter, apiRouter) -> + webRouter.post '/project/new/upload', AuthenticationController.requireLogin(), ProjectUploadController.uploadProject - app.post '/Project/:Project_id/upload', + webRouter.post '/Project/:Project_id/upload', SecurityManager.requestCanModifyProject, ProjectUploadController.uploadFile diff --git a/services/web/app/coffee/infrastructure/ExpressLocals.coffee b/services/web/app/coffee/infrastructure/ExpressLocals.coffee index 947070f532..e11d22db94 100644 --- a/services/web/app/coffee/infrastructure/ExpressLocals.coffee +++ b/services/web/app/coffee/infrastructure/ExpressLocals.coffee @@ -39,7 +39,7 @@ for path in [ logger.log filePath:filePath, "file does not exist for fingerprints" -module.exports = (app)-> +module.exports = (app, webRouter, apiRouter)-> app.use (req, res, next)-> res.locals.session = req.session next() @@ -94,8 +94,8 @@ module.exports = (app)-> return "" next() - app.use (req, res, next) -> - res.locals.csrfToken = req.csrfToken() + webRouter.use (req, res, next) -> + res.locals.csrfToken = req?.csrfToken() next() app.use (req, res, next) -> diff --git a/services/web/app/coffee/infrastructure/Modules.coffee b/services/web/app/coffee/infrastructure/Modules.coffee index 0aedf6bbf0..720819e503 100644 --- a/services/web/app/coffee/infrastructure/Modules.coffee +++ b/services/web/app/coffee/infrastructure/Modules.coffee @@ -13,9 +13,9 @@ module.exports = Modules = loadedModule.name = moduleName @modules.push loadedModule - applyRouter: (app) -> + applyRouter: (webRouter, apiRouter) -> for module in @modules - module.router?.apply(app) + module.router?.apply(webRouter, apiRouter) viewIncludes: {} loadViewIncludes: (app) -> diff --git a/services/web/app/coffee/infrastructure/Server.coffee b/services/web/app/coffee/infrastructure/Server.coffee index 6ae27dc0eb..b7a441bfce 100644 --- a/services/web/app/coffee/infrastructure/Server.coffee +++ b/services/web/app/coffee/infrastructure/Server.coffee @@ -44,19 +44,31 @@ else app = express() -ignoreCsrfRoutes = [] -app.ignoreCsrf = (method, route) -> - ignoreCsrfRoutes.push new express.Route(method, route) - +webRouter = express.Router() +apiRouter = express.Router() if Settings.behindProxy app.enable('trust proxy') -app.use express.static(__dirname + '/../../../public', {maxAge: staticCacheAge }) + +webRouter.use express.static(__dirname + '/../../../public', {maxAge: staticCacheAge }) app.set 'views', __dirname + '/../../views' app.set 'view engine', 'jade' Modules.loadViewIncludes app -app.use cookieParser(Settings.security.sessionSecret) -app.use session + + + +app.use bodyParser.urlencoded({ extended: true }) +app.use bodyParser.json() +app.use multer(dest: Settings.path.uploadFolder) +app.use methodOverride() + +app.use metrics.http.monitor(logger) +app.use RedirectManager +app.use OldAssetProxy + + +webRouter.use cookieParser(Settings.security.sessionSecret) +webRouter.use session resave: false secret:Settings.security.sessionSecret proxy: Settings.behindProxy @@ -66,36 +78,23 @@ app.use session secure: Settings.secureCookie store: sessionStore key: Settings.cookieName - -app.use bodyParser.urlencoded({ extended: true }) -app.use bodyParser.json() -app.use multer(dest: Settings.path.uploadFolder) -app.use translations.expressMiddlewear -app.use translations.setLangBasedOnDomainMiddlewear +webRouter.use csrfProtection +webRouter.use translations.expressMiddlewear +webRouter.use translations.setLangBasedOnDomainMiddlewear # Measure expiry from last request, not last login -app.use (req, res, next) -> +webRouter.use (req, res, next) -> req.session.touch() next() -app.use (req, res, next) -> - for route in ignoreCsrfRoutes - if route.method == req.method?.toLowerCase() and route.match(req.path) - return next() - csrfProtection(req, res, next) - -app.use ReferalConnect.use -app.use methodOverride() - -expressLocals(app) +webRouter.use ReferalConnect.use +expressLocals(app, webRouter, apiRouter) if app.get('env') == 'production' logger.info "Production Enviroment" app.enable('view cache') -app.use metrics.http.monitor(logger) -app.use RedirectManager -app.use OldAssetProxy + app.use (req, res, next)-> metrics.inc "http-request" @@ -109,12 +108,11 @@ app.use (req, res, next) -> else next() -app.get "/status", (req, res)-> +apiRouter.get "/status", (req, res)-> res.send("web sharelatex is alive") - req.session.destroy() profiler = require "v8-profiler" -app.get "/profile", (req, res) -> +apiRouter.get "/profile", (req, res) -> time = parseInt(req.query.time || "1000") profiler.startProfiling("test") setTimeout () -> @@ -125,7 +123,12 @@ app.get "/profile", (req, res) -> logger.info ("creating HTTP server").yellow server = require('http').createServer(app) -router = new Router(app) +# process api routes first, if nothing matched fall though and use +# web middlewear + routes +app.use(apiRouter) +app.use(webRouter) + +router = new Router(webRouter, apiRouter) module.exports = app: app diff --git a/services/web/app/coffee/router.coffee b/services/web/app/coffee/router.coffee index 529f8a51d3..d9ff55a0a3 100644 --- a/services/web/app/coffee/router.coffee +++ b/services/web/app/coffee/router.coffee @@ -40,65 +40,67 @@ logger = require("logger-sharelatex") _ = require("underscore") module.exports = class Router - constructor: (app)-> + constructor: (webRouter, apiRouter)-> if !Settings.allowPublicAccess - app.all '*', AuthenticationController.requireGlobalLogin + webRouter.all '*', AuthenticationController.requireGlobalLogin - app.get '/login', UserPagesController.loginPage + webRouter.get '/login', UserPagesController.loginPage AuthenticationController.addEndpointToLoginWhitelist '/login' - app.post '/login', AuthenticationController.login - app.get '/logout', UserController.logout - app.get '/restricted', SecurityManager.restricted + webRouter.post '/login', AuthenticationController.login + webRouter.get '/logout', UserController.logout + webRouter.get '/restricted', SecurityManager.restricted # Left as a placeholder for implementing a public register page - app.get '/register', UserPagesController.registerPage + webRouter.get '/register', UserPagesController.registerPage AuthenticationController.addEndpointToLoginWhitelist '/register' - EditorRouter.apply(app) - CollaboratorsRouter.apply(app) - SubscriptionRouter.apply(app) - UploadsRouter.apply(app) - PasswordResetRouter.apply(app) - StaticPagesRouter.apply(app) - RealTimeProxyRouter.apply(app) - - Modules.applyRouter(app) - app.get '/blog', BlogController.getIndexPage - app.get '/blog/*', BlogController.getPage + EditorRouter.apply(webRouter, apiRouter) + CollaboratorsRouter.apply(webRouter, apiRouter) + SubscriptionRouter.apply(webRouter, apiRouter) + UploadsRouter.apply(webRouter, apiRouter) + PasswordResetRouter.apply(webRouter, apiRouter) + StaticPagesRouter.apply(webRouter, apiRouter) + RealTimeProxyRouter.apply(webRouter, apiRouter) + AnalyticsRouter.apply(webRouter, apiRouter) + + Modules.applyRouter(webRouter, apiRouter) + if Settings.enableSubscriptions - app.get '/user/bonus', AuthenticationController.requireLogin(), ReferalMiddleware.getUserReferalId, ReferalController.bonus + webRouter.get '/user/bonus', AuthenticationController.requireLogin(), ReferalMiddleware.getUserReferalId, ReferalController.bonus + + webRouter.get '/blog', BlogController.getIndexPage + webRouter.get '/blog/*', BlogController.getPage + + webRouter.get '/user/settings', AuthenticationController.requireLogin(), UserPagesController.settingsPage + webRouter.post '/user/settings', AuthenticationController.requireLogin(), UserController.updateUserSettings + webRouter.post '/user/password/update', AuthenticationController.requireLogin(), UserController.changePassword - app.get '/user/settings', AuthenticationController.requireLogin(), UserPagesController.settingsPage - app.post '/user/settings', AuthenticationController.requireLogin(), UserController.updateUserSettings - app.post '/user/password/update', AuthenticationController.requireLogin(), UserController.changePassword + webRouter.delete '/user/newsletter/unsubscribe', AuthenticationController.requireLogin(), UserController.unsubscribe + webRouter.delete '/user', AuthenticationController.requireLogin(), UserController.deleteUser - app.delete '/user/newsletter/unsubscribe', AuthenticationController.requireLogin(), UserController.unsubscribe - app.delete '/user', AuthenticationController.requireLogin(), UserController.deleteUser + webRouter.get '/user/auth_token', AuthenticationController.requireLogin(), AuthenticationController.getAuthToken + webRouter.get '/user/personal_info', AuthenticationController.requireLogin(allow_auth_token: true), UserInfoController.getLoggedInUsersPersonalInfo + apiRouter.get '/user/:user_id/personal_info', AuthenticationController.httpAuth, UserInfoController.getPersonalInfo - app.get '/user/auth_token', AuthenticationController.requireLogin(), AuthenticationController.getAuthToken - app.get '/user/personal_info', AuthenticationController.requireLogin(allow_auth_token: true), UserInfoController.getLoggedInUsersPersonalInfo - app.get '/user/:user_id/personal_info', AuthenticationController.httpAuth, UserInfoController.getPersonalInfo + webRouter.get '/project', AuthenticationController.requireLogin(), ProjectController.projectListPage + webRouter.post '/project/new', AuthenticationController.requireLogin(), ProjectController.newProject - app.get '/project', AuthenticationController.requireLogin(), ProjectController.projectListPage - app.post '/project/new', AuthenticationController.requireLogin(), ProjectController.newProject - - app.get '/Project/:Project_id', RateLimiterMiddlewear.rateLimit({ + webRouter.get '/Project/:Project_id', RateLimiterMiddlewear.rateLimit({ endpointName: "open-project" params: ["Project_id"] maxRequests: 10 timeInterval: 60 }), SecurityManager.requestCanAccessProject, ProjectController.loadEditor - app.get '/Project/:Project_id/file/:File_id', SecurityManager.requestCanAccessProject, FileStoreController.getFile + webRouter.get '/Project/:Project_id/file/:File_id', SecurityManager.requestCanAccessProject, FileStoreController.getFile + webRouter.post '/project/:Project_id/settings', SecurityManager.requestCanModifyProject, ProjectController.updateProjectSettings - app.post '/project/:Project_id/settings', SecurityManager.requestCanModifyProject, ProjectController.updateProjectSettings - - app.post '/project/:Project_id/compile', SecurityManager.requestCanAccessProject, CompileController.compile - app.get '/Project/:Project_id/output/output.pdf', SecurityManager.requestCanAccessProject, CompileController.downloadPdf - app.get /^\/project\/([^\/]*)\/output\/(.*)$/, + webRouter.post '/project/:Project_id/compile', SecurityManager.requestCanAccessProject, CompileController.compile + webRouter.get '/Project/:Project_id/output/output.pdf', SecurityManager.requestCanAccessProject, CompileController.downloadPdf + webRouter.get /^\/project\/([^\/]*)\/output\/(.*)$/, ((req, res, next) -> params = "Project_id": req.params[0] @@ -106,78 +108,82 @@ module.exports = class Router req.params = params next() ), SecurityManager.requestCanAccessProject, CompileController.getFileFromClsi - app.delete "/project/:Project_id/output", SecurityManager.requestCanAccessProject, CompileController.deleteAuxFiles - app.get "/project/:Project_id/sync/code", SecurityManager.requestCanAccessProject, CompileController.proxySync - app.get "/project/:Project_id/sync/pdf", SecurityManager.requestCanAccessProject, CompileController.proxySync + webRouter.delete "/project/:Project_id/output", SecurityManager.requestCanAccessProject, CompileController.deleteAuxFiles + webRouter.get "/project/:Project_id/sync/code", SecurityManager.requestCanAccessProject, CompileController.proxySync + webRouter.get "/project/:Project_id/sync/pdf", SecurityManager.requestCanAccessProject, CompileController.proxySync - app.delete '/Project/:Project_id', SecurityManager.requestIsOwner, ProjectController.deleteProject - app.post '/Project/:Project_id/restore', SecurityManager.requestIsOwner, ProjectController.restoreProject - app.post '/Project/:Project_id/clone', SecurityManager.requestCanAccessProject, ProjectController.cloneProject + webRouter.delete '/Project/:Project_id', SecurityManager.requestIsOwner, ProjectController.deleteProject + webRouter.post '/Project/:Project_id/restore', SecurityManager.requestIsOwner, ProjectController.restoreProject + webRouter.post '/Project/:Project_id/clone', SecurityManager.requestCanAccessProject, ProjectController.cloneProject - app.post '/project/:Project_id/rename', SecurityManager.requestIsOwner, ProjectController.renameProject + webRouter.post '/project/:Project_id/rename', SecurityManager.requestIsOwner, ProjectController.renameProject - app.get "/project/:Project_id/updates", SecurityManager.requestCanAccessProject, TrackChangesController.proxyToTrackChangesApi - app.get "/project/:Project_id/doc/:doc_id/diff", SecurityManager.requestCanAccessProject, TrackChangesController.proxyToTrackChangesApi - app.post "/project/:Project_id/doc/:doc_id/version/:version_id/restore", SecurityManager.requestCanAccessProject, TrackChangesController.proxyToTrackChangesApi + webRouter.get "/project/:Project_id/updates", SecurityManager.requestCanAccessProject, TrackChangesController.proxyToTrackChangesApi + webRouter.get "/project/:Project_id/doc/:doc_id/diff", SecurityManager.requestCanAccessProject, TrackChangesController.proxyToTrackChangesApi + webRouter.post "/project/:Project_id/doc/:doc_id/version/:version_id/restore", SecurityManager.requestCanAccessProject, TrackChangesController.proxyToTrackChangesApi - app.get '/Project/:Project_id/download/zip', SecurityManager.requestCanAccessProject, ProjectDownloadsController.downloadProject - app.get '/project/download/zip', SecurityManager.requestCanAccessMultipleProjects, ProjectDownloadsController.downloadMultipleProjects + webRouter.get '/Project/:Project_id/download/zip', SecurityManager.requestCanAccessProject, ProjectDownloadsController.downloadProject + webRouter.get '/project/download/zip', SecurityManager.requestCanAccessMultipleProjects, ProjectDownloadsController.downloadMultipleProjects - app.get '/tag', AuthenticationController.requireLogin(), TagsController.getAllTags - app.post '/project/:project_id/tag', AuthenticationController.requireLogin(), TagsController.processTagsUpdate + webRouter.get '/tag', AuthenticationController.requireLogin(), TagsController.getAllTags + webRouter.post '/project/:project_id/tag', AuthenticationController.requireLogin(), TagsController.processTagsUpdate - app.get '/project/:project_id/details', AuthenticationController.httpAuth, ProjectApiController.getProjectDetails + # Deprecated in favour of /internal/project/:project_id but still used by versioning + apiRouter.get '/project/:project_id/details', AuthenticationController.httpAuth, ProjectApiController.getProjectDetails - app.get '/internal/project/:Project_id/zip', AuthenticationController.httpAuth, ProjectDownloadsController.downloadProject - app.get '/internal/project/:project_id/compile/pdf', AuthenticationController.httpAuth, CompileController.compileAndDownloadPdf - - - app.get '/project/:Project_id/doc/:doc_id', AuthenticationController.httpAuth, DocumentController.getDocument - app.post '/project/:Project_id/doc/:doc_id', AuthenticationController.httpAuth, DocumentController.setDocument - app.ignoreCsrf('post', '/project/:Project_id/doc/:doc_id') - - app.post '/user/:user_id/update/*', AuthenticationController.httpAuth, TpdsController.mergeUpdate - app.delete '/user/:user_id/update/*', AuthenticationController.httpAuth, TpdsController.deleteUpdate - app.ignoreCsrf('post', '/user/:user_id/update/*') - app.ignoreCsrf('delete', '/user/:user_id/update/*') + # New 'stable' /internal API end points + apiRouter.get '/internal/project/:project_id', AuthenticationController.httpAuth, ProjectApiController.getProjectDetails + apiRouter.get '/internal/project/:Project_id/zip', AuthenticationController.httpAuth, ProjectDownloadsController.downloadProject - app.post '/project/:project_id/contents/*', AuthenticationController.httpAuth, TpdsController.updateProjectContents - app.delete '/project/:project_id/contents/*', AuthenticationController.httpAuth, TpdsController.deleteProjectContents - app.ignoreCsrf('post', '/project/:project_id/contents/*') - app.ignoreCsrf('delete', '/project/:project_id/contents/*') + webRouter.get /^\/internal\/project\/([^\/]*)\/output\/(.*)$/, + ((req, res, next) -> + params = + "Project_id": req.params[0] + "file": req.params[1] + req.params = params + next() + ), AuthenticationController.httpAuth, CompileController.getFileFromClsi - app.post "/spelling/check", AuthenticationController.requireLogin(), SpellingController.proxyRequestToSpellingApi - app.post "/spelling/learn", AuthenticationController.requireLogin(), SpellingController.proxyRequestToSpellingApi + apiRouter.get '/project/:Project_id/doc/:doc_id', AuthenticationController.httpAuth, DocumentController.getDocument + apiRouter.post '/project/:Project_id/doc/:doc_id', AuthenticationController.httpAuth, DocumentController.setDocument - app.get "/project/:Project_id/messages", SecurityManager.requestCanAccessProject, ChatController.getMessages - app.post "/project/:Project_id/messages", SecurityManager.requestCanAccessProject, ChatController.sendMessage + apiRouter.post '/user/:user_id/update/*', AuthenticationController.httpAuth, TpdsController.mergeUpdate + apiRouter.delete '/user/:user_id/update/*', AuthenticationController.httpAuth, TpdsController.deleteUpdate - app.get /learn(\/.*)?/, WikiController.getPage + apiRouter.post '/project/:project_id/contents/*', AuthenticationController.httpAuth, TpdsController.updateProjectContents + apiRouter.delete '/project/:project_id/contents/*', AuthenticationController.httpAuth, TpdsController.deleteProjectContents + + webRouter.post "/spelling/check", AuthenticationController.requireLogin(), SpellingController.proxyRequestToSpellingApi + webRouter.post "/spelling/learn", AuthenticationController.requireLogin(), SpellingController.proxyRequestToSpellingApi + + webRouter.get "/project/:Project_id/messages", SecurityManager.requestCanAccessProject, ChatController.getMessages + webRouter.post "/project/:Project_id/messages", SecurityManager.requestCanAccessProject, ChatController.sendMessage + + webRouter.get /learn(\/.*)?/, WikiController.getPage #Admin Stuff - app.get '/admin', SecurityManager.requestIsAdmin, AdminController.index - app.get '/admin/register', SecurityManager.requestIsAdmin, AdminController.registerNewUser - app.post '/admin/register', SecurityManager.requestIsAdmin, UserController.register - app.post '/admin/closeEditor', SecurityManager.requestIsAdmin, AdminController.closeEditor - app.post '/admin/dissconectAllUsers', SecurityManager.requestIsAdmin, AdminController.dissconectAllUsers - app.post '/admin/syncUserToSubscription', SecurityManager.requestIsAdmin, AdminController.syncUserToSubscription - app.post '/admin/flushProjectToTpds', SecurityManager.requestIsAdmin, AdminController.flushProjectToTpds - app.post '/admin/pollDropboxForUser', SecurityManager.requestIsAdmin, AdminController.pollDropboxForUser - app.post '/admin/messages', SecurityManager.requestIsAdmin, AdminController.createMessage - app.post '/admin/messages/clear', SecurityManager.requestIsAdmin, AdminController.clearMessages + webRouter.get '/admin', SecurityManager.requestIsAdmin, AdminController.index + webRouter.get '/admin/register', SecurityManager.requestIsAdmin, AdminController.registerNewUser + webRouter.post '/admin/register', SecurityManager.requestIsAdmin, UserController.register + webRouter.post '/admin/closeEditor', SecurityManager.requestIsAdmin, AdminController.closeEditor + webRouter.post '/admin/dissconectAllUsers', SecurityManager.requestIsAdmin, AdminController.dissconectAllUsers + webRouter.post '/admin/syncUserToSubscription', SecurityManager.requestIsAdmin, AdminController.syncUserToSubscription + webRouter.post '/admin/flushProjectToTpds', SecurityManager.requestIsAdmin, AdminController.flushProjectToTpds + webRouter.post '/admin/pollDropboxForUser', SecurityManager.requestIsAdmin, AdminController.pollDropboxForUser + webRouter.post '/admin/messages', SecurityManager.requestIsAdmin, AdminController.createMessage + webRouter.post '/admin/messages/clear', SecurityManager.requestIsAdmin, AdminController.clearMessages - app.get '/perfTest', (req,res)-> + apiRouter.get '/perfTest', (req,res)-> res.send("hello") - req.session.destroy() - app.get '/status', (req,res)-> + apiRouter.get '/status', (req,res)-> res.send("websharelatex is up") - req.session.destroy() + - app.get '/health_check', HealthCheckController.check - app.get '/health_check/redis', HealthCheckController.checkRedis + webRouter.get '/health_check', HealthCheckController.check + webRouter.get '/health_check/redis', HealthCheckController.checkRedis - app.get "/status/compiler/:Project_id", SecurityManager.requestCanAccessProject, (req, res) -> + apiRouter.get "/status/compiler/:Project_id", SecurityManager.requestCanAccessProject, (req, res) -> sendRes = _.once (statusCode, message)-> res.writeHead statusCode res.end message @@ -186,27 +192,26 @@ module.exports = class Router setTimeout (() -> sendRes 500, "Compiler timed out" ), 10000 - req.session.destroy() - app.get "/ip", (req, res, next) -> + apiRouter.get "/ip", (req, res, next) -> res.send({ ip: req.ip ips: req.ips headers: req.headers }) - app.get '/oops-express', (req, res, next) -> next(new Error("Test error")) - app.get '/oops-internal', (req, res, next) -> throw new Error("Test error") - app.get '/oops-mongo', (req, res, next) -> + apiRouter.get '/oops-express', (req, res, next) -> next(new Error("Test error")) + apiRouter.get '/oops-internal', (req, res, next) -> throw new Error("Test error") + apiRouter.get '/oops-mongo', (req, res, next) -> require("./models/Project").Project.findOne {}, () -> throw new Error("Test error") - app.get '/opps-small', (req, res, next)-> + apiRouter.get '/opps-small', (req, res, next)-> logger.err "test error occured" res.send() - app.post '/error/client', (req, res, next) -> + webRouter.post '/error/client', (req, res, next) -> logger.error err: req.body.error, meta: req.body.meta, "client side error" res.send(204) - app.get '*', ErrorController.notFound + webRouter.get '*', ErrorController.notFound