| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279 |
- import AdminController from './Features/ServerAdmin/AdminController.mjs'
- import ErrorController from './Features/Errors/ErrorController.mjs'
- import Features from './infrastructure/Features.mjs'
- import ProjectController from './Features/Project/ProjectController.mjs'
- import ProjectApiController from './Features/Project/ProjectApiController.mjs'
- import ProjectListController from './Features/Project/ProjectListController.mjs'
- import SpellingController from './Features/Spelling/SpellingController.mjs'
- import EditorRouter from './Features/Editor/EditorRouter.mjs'
- import Settings from '@overleaf/settings'
- import TpdsController from './Features/ThirdPartyDataStore/TpdsController.mjs'
- import SubscriptionRouter from './Features/Subscription/SubscriptionRouter.mjs'
- import UploadsRouter from './Features/Uploads/UploadsRouter.mjs'
- import metrics from '@overleaf/metrics'
- import ReferalController from './Features/Referal/ReferalController.mjs'
- import AuthenticationController from './Features/Authentication/AuthenticationController.mjs'
- import PermissionsController from './Features/Authorization/PermissionsController.mjs'
- import SessionManager from './Features/Authentication/SessionManager.mjs'
- import TagsController from './Features/Tags/TagsController.mjs'
- import NotificationsController from './Features/Notifications/NotificationsController.mjs'
- import CollaboratorsRouter from './Features/Collaborators/CollaboratorsRouter.mjs'
- import UserInfoController from './Features/User/UserInfoController.mjs'
- import UserController from './Features/User/UserController.mjs'
- import UserEmailsController from './Features/User/UserEmailsController.mjs'
- import UserPagesController from './Features/User/UserPagesController.mjs'
- import TutorialController from './Features/Tutorial/TutorialController.mjs'
- import DocumentController from './Features/Documents/DocumentController.mjs'
- import CompileManager from './Features/Compile/CompileManager.mjs'
- import CompileController from './Features/Compile/CompileController.mjs'
- import HealthCheckController from './Features/HealthCheck/HealthCheckController.mjs'
- import ProjectDownloadsController from './Features/Downloads/ProjectDownloadsController.mjs'
- import FileStoreController from './Features/FileStore/FileStoreController.mjs'
- import DocumentUpdaterController from './Features/DocumentUpdater/DocumentUpdaterController.mjs'
- import HistoryRouter from './Features/History/HistoryRouter.mjs'
- import ExportsController from './Features/Exports/ExportsController.mjs'
- import PasswordResetRouter from './Features/PasswordReset/PasswordResetRouter.mjs'
- import StaticPagesRouter from './Features/StaticPages/StaticPagesRouter.mjs'
- import ChatController from './Features/Chat/ChatController.mjs'
- import Modules from './infrastructure/Modules.mjs'
- import {
- RateLimiter,
- openProjectRateLimiter,
- overleafLoginRateLimiter,
- } from './infrastructure/RateLimiter.mjs'
- import RateLimiterMiddleware from './Features/Security/RateLimiterMiddleware.mjs'
- import InactiveProjectController from './Features/InactiveData/InactiveProjectController.mjs'
- import ContactRouter from './Features/Contacts/ContactRouter.mjs'
- import ReferencesController from './Features/References/ReferencesController.mjs'
- import AuthorizationMiddleware from './Features/Authorization/AuthorizationMiddleware.mjs'
- import BetaProgramController from './Features/BetaProgram/BetaProgramController.mjs'
- import AnalyticsRouter from './Features/Analytics/AnalyticsRouter.mjs'
- import MetaController from './Features/Metadata/MetaController.mjs'
- import TokenAccessController from './Features/TokenAccess/TokenAccessController.mjs'
- import TokenAccessRouter from './Features/TokenAccess/TokenAccessRouter.mjs'
- import LinkedFilesRouter from './Features/LinkedFiles/LinkedFilesRouter.mjs'
- import TemplatesRouter from './Features/Templates/TemplatesRouter.mjs'
- import UserMembershipRouter from './Features/UserMembership/UserMembershipRouter.mjs'
- import SystemMessageController from './Features/SystemMessages/SystemMessageController.mjs'
- import AnalyticsRegistrationSourceMiddleware from './Features/Analytics/AnalyticsRegistrationSourceMiddleware.mjs'
- import AnalyticsUTMTrackingMiddleware from './Features/Analytics/AnalyticsUTMTrackingMiddleware.mjs'
- import CaptchaMiddleware from './Features/Captcha/CaptchaMiddleware.mjs'
- import UnsupportedBrowserMiddleware from './infrastructure/UnsupportedBrowserMiddleware.mjs'
- import logger from '@overleaf/logger'
- import _ from 'lodash'
- import { plainTextResponse } from './infrastructure/Response.mjs'
- import SocketDiagnostics from './Features/SocketDiagnostics/SocketDiagnostics.mjs'
- import ClsiCacheController from './Features/Compile/ClsiCacheController.mjs'
- import AsyncLocalStorage from './infrastructure/AsyncLocalStorage.mjs'
- const { renderUnsupportedBrowserPage, unsupportedBrowserMiddleware } =
- UnsupportedBrowserMiddleware
- const rateLimiters = {
- addEmail: new RateLimiter('add-email', {
- points: 10,
- duration: 60,
- }),
- addProjectToTag: new RateLimiter('add-project-to-tag', {
- points: 30,
- duration: 60,
- }),
- addProjectsToTag: new RateLimiter('add-projects-to-tag', {
- points: 30,
- duration: 60,
- }),
- canSkipCaptcha: new RateLimiter('can-skip-captcha', {
- points: 20,
- duration: 60,
- }),
- changePassword: new RateLimiter('change-password', {
- points: 10,
- duration: 60,
- }),
- compileProjectHttp: new RateLimiter('compile-project-http', {
- points: 200,
- duration: 10 * 60,
- }),
- confirmEmail: new RateLimiter('confirm-email', {
- points: 10,
- duration: 60,
- }),
- createProject: new RateLimiter('create-project', {
- points: 20,
- duration: 60,
- }),
- createTag: new RateLimiter('create-tag', {
- points: 30,
- duration: 60,
- }),
- deleteEmail: new RateLimiter('delete-email', {
- points: 10,
- duration: 60,
- }),
- deleteTag: new RateLimiter('delete-tag', {
- points: 30,
- duration: 60,
- }),
- deleteUser: new RateLimiter('delete-user', {
- points: 10,
- duration: 60,
- }),
- endorseEmail: new RateLimiter('endorse-email', {
- points: 30,
- duration: 60,
- }),
- getProjects: new RateLimiter('get-projects', {
- points: 30,
- duration: 60,
- }),
- grantTokenAccessReadOnly: new RateLimiter('grant-token-access-read-only', {
- points: 10,
- duration: 60,
- }),
- grantTokenAccessReadWrite: new RateLimiter('grant-token-access-read-write', {
- points: 10,
- duration: 60,
- }),
- indexAllProjectReferences: new RateLimiter('index-all-project-references', {
- points: 30,
- duration: 60,
- }),
- miscOutputDownload: new RateLimiter('misc-output-download', {
- points: 1000,
- duration: 60 * 60,
- }),
- multipleProjectsZipDownload: new RateLimiter(
- 'multiple-projects-zip-download',
- {
- points: 10,
- duration: 60,
- }
- ),
- openDashboard: new RateLimiter('open-dashboard', {
- points: 30,
- duration: 60,
- }),
- readAndWriteToken: new RateLimiter('read-and-write-token', {
- points: 15,
- duration: 60,
- }),
- readOnlyToken: new RateLimiter('read-only-token', {
- points: 15,
- duration: 60,
- }),
- removeProjectFromTag: new RateLimiter('remove-project-from-tag', {
- points: 30,
- duration: 60,
- }),
- removeProjectsFromTag: new RateLimiter('remove-projects-from-tag', {
- points: 30,
- duration: 60,
- }),
- renameTag: new RateLimiter('rename-tag', {
- points: 30,
- duration: 60,
- }),
- resendConfirmation: new RateLimiter('resend-confirmation', {
- points: 1,
- duration: 60,
- }),
- sendConfirmation: new RateLimiter('send-confirmation', {
- points: 2,
- duration: 60,
- }),
- sendChatMessage: new RateLimiter('send-chat-message', {
- points: 100,
- duration: 60,
- }),
- statusCompiler: new RateLimiter('status-compiler', {
- points: 10,
- duration: 60,
- }),
- zipDownload: new RateLimiter('zip-download', {
- points: 10,
- duration: 60,
- }),
- documentExport: new RateLimiter('document-export', {
- points: 5,
- duration: 60,
- }),
- documentExportDownload: new RateLimiter('document-export-download', {
- points: 30,
- duration: 60,
- }),
- }
- async function initialize(webRouter, privateApiRouter, publicApiRouter) {
- webRouter.use(unsupportedBrowserMiddleware)
- if (!Settings.allowPublicAccess) {
- webRouter.all('*', AuthenticationController.requireGlobalLogin)
- }
- webRouter.get('*', AnalyticsRegistrationSourceMiddleware.setInbound())
- webRouter.get('*', AnalyticsUTMTrackingMiddleware.recordUTMTags())
- if (process.env.NODE_ENV === 'development' && global.__coverage__) {
- // Expose code coverage via an endpoint when running with code coverage enabled
- webRouter.get('/coverage', (req, res) => {
- const coverage = {}
- for (const [key, value] of Object.entries(global.__coverage__)) {
- coverage[key] = {
- ...value,
- // Transform for Jenkins sourcemap
- path: value.path.replace('/overleaf/', '/workspace/'),
- }
- }
- res.json({ coverage })
- })
- }
- // Mount onto /login in order to get the deviceHistory cookie.
- webRouter.post(
- '/login/can-skip-captcha',
- // Keep in sync with the overleaf-login options.
- RateLimiterMiddleware.rateLimit(rateLimiters.canSkipCaptcha),
- CaptchaMiddleware.canSkipCaptcha
- )
- webRouter.get('/login', UserPagesController.loginPage)
- AuthenticationController.addEndpointToLoginWhitelist('/login')
- webRouter.post(
- '/login',
- RateLimiterMiddleware.rateLimit(overleafLoginRateLimiter), // rate limit IP (20 / 60s)
- RateLimiterMiddleware.loginRateLimitEmail(), // rate limit email (10 / 120s)
- CaptchaMiddleware.validateCaptcha('login'),
- AuthenticationController.passportLogin
- )
- webRouter.get(
- '/compromised-password',
- AuthenticationController.requireLogin(),
- UserPagesController.compromisedPasswordPage
- )
- webRouter.get('/account-suspended', UserPagesController.accountSuspended)
- webRouter.get(
- '/socket-diagnostics',
- AuthenticationController.requireLogin(),
- SocketDiagnostics.index
- )
- if (Settings.enableLegacyLogin) {
- AuthenticationController.addEndpointToLoginWhitelist('/login/legacy')
- webRouter.get('/login/legacy', UserPagesController.loginPage)
- webRouter.post(
- '/login/legacy',
- RateLimiterMiddleware.rateLimit(overleafLoginRateLimiter), // rate limit IP (20 / 60s)
- RateLimiterMiddleware.loginRateLimitEmail(), // rate limit email (10 / 120s)
- CaptchaMiddleware.validateCaptcha('login'),
- AuthenticationController.passportLogin
- )
- }
- webRouter.get(
- '/read-only/one-time-login',
- UserPagesController.oneTimeLoginPage
- )
- AuthenticationController.addEndpointToLoginWhitelist(
- '/read-only/one-time-login'
- )
- webRouter.get('/logout', UserPagesController.logout)
- webRouter.post('/logout', UserController.logout)
- webRouter.get('/restricted', AuthorizationMiddleware.restricted)
- if (Features.hasFeature('registration-page')) {
- webRouter.get('/register', UserPagesController.registerPage)
- AuthenticationController.addEndpointToLoginWhitelist('/register')
- }
- EditorRouter.apply(webRouter, privateApiRouter)
- CollaboratorsRouter.apply(webRouter, privateApiRouter)
- SubscriptionRouter.apply(webRouter, privateApiRouter, publicApiRouter)
- UploadsRouter.apply(webRouter, privateApiRouter)
- PasswordResetRouter.apply(webRouter, privateApiRouter)
- StaticPagesRouter.apply(webRouter, privateApiRouter)
- ContactRouter.apply(webRouter, privateApiRouter)
- AnalyticsRouter.apply(webRouter, privateApiRouter, publicApiRouter)
- LinkedFilesRouter.apply(webRouter, privateApiRouter, publicApiRouter)
- TemplatesRouter.apply(webRouter)
- UserMembershipRouter.apply(webRouter)
- TokenAccessRouter.apply(webRouter)
- HistoryRouter.apply(webRouter, privateApiRouter)
- await Modules.applyRouter(webRouter, privateApiRouter, publicApiRouter)
- if (Settings.enableSubscriptions) {
- webRouter.get(
- '/user/bonus',
- AuthenticationController.requireLogin(),
- ReferalController.bonus
- )
- }
- // .getMessages will generate an empty response for anonymous users.
- webRouter.get('/system/messages', SystemMessageController.getMessages)
- webRouter.get(
- '/user/settings',
- AuthenticationController.requireLogin(),
- PermissionsController.useCapabilities(),
- UserPagesController.settingsPage
- )
- webRouter.post(
- '/user/settings',
- AuthenticationController.requireLogin(),
- UserController.updateUserSettings
- )
- webRouter.post(
- '/user/password/update',
- AuthenticationController.requireLogin(),
- RateLimiterMiddleware.rateLimit(rateLimiters.changePassword),
- PermissionsController.requirePermission('change-password'),
- UserController.changePassword
- )
- webRouter.get(
- '/user/emails',
- AuthenticationController.requireLogin(),
- AsyncLocalStorage.middleware,
- PermissionsController.useCapabilities(),
- UserController.ensureAffiliationMiddleware,
- UserEmailsController.list
- )
- webRouter.get(
- '/user/emails/confirm',
- AuthenticationController.requireLogin(),
- UserEmailsController.showConfirm
- )
- webRouter.post(
- '/user/emails/confirm',
- AuthenticationController.requireLogin(),
- RateLimiterMiddleware.rateLimit(rateLimiters.confirmEmail),
- UserEmailsController.confirm
- )
- webRouter.post(
- '/user/emails/send-confirmation-code',
- AuthenticationController.requireLogin(),
- RateLimiterMiddleware.rateLimit(rateLimiters.sendConfirmation),
- await Modules.middleware('confirmationEmailMiddleware'),
- UserEmailsController.sendExistingEmailConfirmationCode
- )
- webRouter.post(
- '/user/emails/resend-confirmation-code',
- AuthenticationController.requireLogin(),
- RateLimiterMiddleware.rateLimit(rateLimiters.resendConfirmation),
- UserEmailsController.resendExistingSecondaryEmailConfirmationCode
- )
- webRouter.post(
- '/user/emails/confirm-code',
- AuthenticationController.requireLogin(),
- RateLimiterMiddleware.rateLimit(rateLimiters.confirmEmail),
- UserEmailsController.checkExistingEmailConfirmationCode
- )
- webRouter.get(
- '/user/emails/primary-email-check',
- AuthenticationController.requireLogin(),
- UserEmailsController.primaryEmailCheckPage
- )
- webRouter.post(
- '/user/emails/primary-email-check',
- AuthenticationController.requireLogin(),
- PermissionsController.useCapabilities(),
- UserEmailsController.primaryEmailCheck
- )
- if (Features.hasFeature('affiliations')) {
- webRouter.post(
- '/user/emails/delete',
- AuthenticationController.requireLogin(),
- RateLimiterMiddleware.rateLimit(rateLimiters.deleteEmail),
- await Modules.middleware('userDeleteEmail'),
- UserEmailsController.remove
- )
- webRouter.post(
- '/user/emails/default',
- AuthenticationController.requireLogin(),
- UserEmailsController.setDefault
- )
- webRouter.post(
- '/user/emails/endorse',
- AuthenticationController.requireLogin(),
- PermissionsController.requirePermission('endorse-email'),
- RateLimiterMiddleware.rateLimit(rateLimiters.endorseEmail),
- UserEmailsController.endorse
- )
- }
- if (Features.hasFeature('saas')) {
- webRouter.get(
- '/user/emails/add-secondary',
- AuthenticationController.requireLogin(),
- PermissionsController.requirePermission('add-secondary-email'),
- UserEmailsController.addSecondaryEmailPage
- )
- webRouter.get(
- '/user/emails/confirm-secondary',
- AuthenticationController.requireLogin(),
- PermissionsController.requirePermission('add-secondary-email'),
- UserEmailsController.confirmSecondaryEmailPage
- )
- }
- webRouter.get(
- '/user/sessions',
- AuthenticationController.requireLogin(),
- UserPagesController.sessionsPage
- )
- webRouter.post(
- '/user/sessions/clear',
- AuthenticationController.requireLogin(),
- UserController.clearSessions
- )
- // deprecated
- webRouter.delete(
- '/user/newsletter/unsubscribe',
- AuthenticationController.requireLogin(),
- UserController.unsubscribe
- )
- webRouter.post(
- '/user/newsletter/unsubscribe',
- AuthenticationController.requireLogin(),
- UserController.unsubscribe
- )
- webRouter.post(
- '/user/newsletter/subscribe',
- AuthenticationController.requireLogin(),
- UserController.subscribe
- )
- webRouter.get(
- '/user/email-preferences',
- AuthenticationController.requireLogin(),
- UserPagesController.emailPreferencesPage
- )
- webRouter.post(
- '/user/delete',
- RateLimiterMiddleware.rateLimit(rateLimiters.deleteUser),
- AuthenticationController.requireLogin(),
- PermissionsController.requirePermission('delete-own-account'),
- UserController.tryDeleteUser
- )
- webRouter.get(
- '/user/personal_info',
- AuthenticationController.requireLogin(),
- UserInfoController.getLoggedInUsersPersonalInfo
- )
- privateApiRouter.get(
- '/user/:user_id/personal_info',
- AuthenticationController.requirePrivateApiAuth(),
- UserInfoController.getPersonalInfo
- )
- webRouter.get(
- '/user/features',
- AuthenticationController.requireLogin(),
- UserInfoController.getUserFeatures
- )
- webRouter.get(
- '/user/reconfirm',
- UserPagesController.renderReconfirmAccountPage
- )
- // for /user/reconfirm POST, see password router
- webRouter.get(
- '/user/tpds/queues',
- AuthenticationController.requireLogin(),
- TpdsController.getQueues
- )
- webRouter.post(
- '/tutorial/:tutorialKey/complete',
- AuthenticationController.requireLogin(),
- TutorialController.completeTutorial
- )
- webRouter.post(
- '/tutorial/:tutorialKey/postpone',
- AuthenticationController.requireLogin(),
- TutorialController.postponeTutorial
- )
- webRouter.get(
- '/user/projects',
- AuthenticationController.requireLogin(),
- ProjectController.userProjectsJson
- )
- webRouter.get(
- '/project/:Project_id/entities',
- AuthenticationController.requireLogin(),
- AuthorizationMiddleware.ensureUserCanReadProject,
- ProjectController.projectEntitiesJson
- )
- webRouter.get(
- '/project',
- AuthenticationController.requireLogin(),
- RateLimiterMiddleware.rateLimit(rateLimiters.openDashboard),
- AsyncLocalStorage.middleware,
- await Modules.middleware('domainCaptureTestSession'),
- PermissionsController.useCapabilities(),
- ProjectListController.projectListPage
- )
- webRouter.post(
- '/project/new',
- AuthenticationController.requireLogin(),
- RateLimiterMiddleware.rateLimit(rateLimiters.createProject),
- ProjectController.newProject
- )
- webRouter.post(
- '/api/project',
- AuthenticationController.requireLogin(),
- RateLimiterMiddleware.rateLimit(rateLimiters.getProjects),
- ProjectListController.getProjectsJson
- )
- for (const route of [
- // Keep the old route for continuous metrics
- '/Project/:Project_id',
- // New route for pdf-detach
- '/Project/:Project_id/:detachRole(detacher|detached)',
- ]) {
- webRouter.get(
- route,
- RateLimiterMiddleware.rateLimit(openProjectRateLimiter, {
- params: ['Project_id'],
- }),
- AsyncLocalStorage.middleware,
- PermissionsController.useCapabilities(),
- AuthorizationMiddleware.ensureUserCanReadProject,
- ProjectController.loadEditor
- )
- }
- webRouter.head(
- '/Project/:Project_id/file/:File_id',
- AuthorizationMiddleware.ensureUserCanReadProject,
- FileStoreController.getFileHead
- )
- webRouter.get(
- '/Project/:Project_id/file/:File_id',
- AuthorizationMiddleware.ensureUserCanReadProject,
- FileStoreController.getFile
- )
- webRouter.get(
- '/Project/:Project_id/doc/:Doc_id/download', // "download" suffix to avoid conflict with private API route at doc/:doc_id
- AuthorizationMiddleware.ensureUserCanReadProject,
- DocumentUpdaterController.getDoc
- )
- webRouter.post(
- '/project/:Project_id/settings',
- AuthorizationMiddleware.ensureUserCanWriteProjectSettings,
- ProjectController.updateProjectSettings
- )
- webRouter.post(
- '/project/:Project_id/settings/admin',
- AuthenticationController.requireLogin(),
- AuthorizationMiddleware.ensureUserCanAdminProject,
- ProjectController.updateProjectAdminSettings
- )
- webRouter.post(
- '/project/:Project_id/compile',
- RateLimiterMiddleware.rateLimit(rateLimiters.compileProjectHttp, {
- params: ['Project_id'],
- }),
- AsyncLocalStorage.middleware,
- AuthorizationMiddleware.ensureUserCanReadProject,
- CompileController.compile
- )
- webRouter.post(
- '/project/:Project_id/compile/stop',
- AuthorizationMiddleware.ensureUserCanReadProject,
- CompileController.stopCompile
- )
- webRouter.get(
- '/project/:Project_id/output/cached/output.overleaf.json',
- AsyncLocalStorage.middleware,
- AuthorizationMiddleware.ensureUserCanReadProject,
- ClsiCacheController.getLatestBuildFromCache
- )
- webRouter.get(
- '/download/project/:Project_id/build/:editorBuildId/output/cached/:filename(.*)',
- AuthorizationMiddleware.ensureUserCanReadProject,
- ClsiCacheController.downloadFromCache
- )
- // PDF Download button for specific build
- webRouter.get(
- '/download/project/:Project_id/build/:build_id/output/output.pdf',
- AuthorizationMiddleware.ensureUserCanReadProject,
- CompileController.downloadPdf
- )
- // Align with limits defined in CompileController.downloadPdf
- const rateLimiterMiddlewareOutputFiles = RateLimiterMiddleware.rateLimit(
- rateLimiters.miscOutputDownload,
- { params: ['Project_id'] }
- )
- // Download all the output files of a specific build
- webRouter.get(
- '/project/:Project_id/build/:build_id/output/output.zip',
- rateLimiterMiddlewareOutputFiles,
- AuthorizationMiddleware.ensureUserCanReadProject,
- CompileController.getOutputZipFromClsi
- )
- webRouter.get(
- '/project/:Project_id/user/:user_id/build/:build_id/output/output.zip',
- rateLimiterMiddlewareOutputFiles,
- AuthorizationMiddleware.ensureUserCanReadProject,
- CompileController.getOutputZipFromClsi
- )
- // direct url access to output files for a specific build
- webRouter.get(
- '/project/:Project_id/build/:build_id/output/:file(.*)',
- rateLimiterMiddlewareOutputFiles,
- AuthorizationMiddleware.ensureUserCanReadProject,
- CompileController.getFileFromClsi
- )
- // direct url access to output files for a specific user and build
- webRouter.get(
- '/project/:Project_id/user/:user_id/build/:build_id/output/:file(.*)',
- rateLimiterMiddlewareOutputFiles,
- AuthorizationMiddleware.ensureUserCanReadProject,
- CompileController.getFileFromClsi
- )
- webRouter.delete(
- '/project/:Project_id/output',
- AuthorizationMiddleware.ensureUserCanReadProject,
- CompileController.deleteAuxFiles
- )
- webRouter.get(
- '/project/:Project_id/sync/code',
- AsyncLocalStorage.middleware,
- AuthorizationMiddleware.ensureUserCanReadProject,
- CompileController.proxySyncCode
- )
- webRouter.get(
- '/project/:Project_id/sync/pdf',
- AsyncLocalStorage.middleware,
- AuthorizationMiddleware.ensureUserCanReadProject,
- CompileController.proxySyncPdf
- )
- webRouter.get(
- '/project/:Project_id/wordcount',
- AuthorizationMiddleware.ensureUserCanReadProject,
- CompileController.wordCount
- )
- webRouter.post(
- '/Project/:Project_id/archive',
- AuthenticationController.requireLogin(),
- AuthorizationMiddleware.ensureUserCanReadProject,
- ProjectController.archiveProject
- )
- webRouter.delete(
- '/Project/:Project_id/archive',
- AuthenticationController.requireLogin(),
- AuthorizationMiddleware.ensureUserCanReadProject,
- ProjectController.unarchiveProject
- )
- webRouter.post(
- '/project/:project_id/trash',
- AuthenticationController.requireLogin(),
- AuthorizationMiddleware.ensureUserCanReadProject,
- ProjectController.trashProject
- )
- webRouter.delete(
- '/project/:project_id/trash',
- AuthenticationController.requireLogin(),
- AuthorizationMiddleware.ensureUserCanReadProject,
- ProjectController.untrashProject
- )
- webRouter.delete(
- '/Project/:Project_id',
- AuthenticationController.requireLogin(),
- AuthorizationMiddleware.ensureUserCanAdminProject,
- ProjectController.deleteProject
- )
- webRouter.post(
- '/Project/:Project_id/restore',
- AuthenticationController.requireLogin(),
- AuthorizationMiddleware.ensureUserCanAdminProject,
- ProjectController.restoreProject
- )
- webRouter.post(
- '/Project/:Project_id/clone',
- AuthorizationMiddleware.ensureUserCanReadProject,
- ProjectController.cloneProject
- )
- webRouter.post(
- '/project/:Project_id/rename',
- AuthenticationController.requireLogin(),
- AuthorizationMiddleware.ensureUserCanAdminProject,
- ProjectController.renameProject
- )
- webRouter.post(
- '/project/:project_id/export/:brand_variation_id',
- AuthorizationMiddleware.ensureUserCanWriteProjectContent,
- ExportsController.exportProject
- )
- webRouter.get(
- '/project/:project_id/export/:export_id',
- AuthorizationMiddleware.ensureUserCanWriteProjectContent,
- ExportsController.exportStatus
- )
- webRouter.get(
- '/project/:project_id/export/:export_id/:type',
- AuthorizationMiddleware.ensureUserCanWriteProjectContent,
- ExportsController.exportDownload
- )
- if (Settings.enablePandocConversions) {
- webRouter.get(
- '/project/:Project_id/download/conversion/:type',
- AuthenticationController.requireLogin(),
- RateLimiterMiddleware.rateLimit(rateLimiters.documentExport, {
- params: ['Project_id'],
- }),
- AuthorizationMiddleware.ensureUserCanReadProject,
- ProjectDownloadsController.exportProjectConversion
- )
- webRouter.get(
- '/project/:Project_id/download/conversion/:conversionId/:type/build/:buildId/output/:file(.*)',
- AuthenticationController.requireLogin(),
- RateLimiterMiddleware.rateLimit(rateLimiters.documentExportDownload, {
- params: ['Project_id'],
- }),
- AuthorizationMiddleware.ensureUserCanReadProject,
- ProjectDownloadsController.downloadPreparedProjectExport
- )
- }
- webRouter.get(
- '/Project/:Project_id/download/zip',
- RateLimiterMiddleware.rateLimit(rateLimiters.zipDownload, {
- params: ['Project_id'],
- }),
- AuthorizationMiddleware.ensureUserCanReadProject,
- ProjectDownloadsController.downloadProject
- )
- webRouter.get(
- '/project/download/zip',
- AuthenticationController.requireLogin(),
- RateLimiterMiddleware.rateLimit(rateLimiters.multipleProjectsZipDownload),
- AuthorizationMiddleware.ensureUserCanReadMultipleProjects,
- ProjectDownloadsController.downloadMultipleProjects
- )
- webRouter.get(
- '/project/:project_id/metadata',
- AsyncLocalStorage.middleware,
- AuthorizationMiddleware.ensureUserCanReadProject,
- Settings.allowAnonymousReadAndWriteSharing
- ? (req, res, next) => {
- next()
- }
- : AuthenticationController.requireLogin(),
- MetaController.getMetadata
- )
- webRouter.post(
- '/project/:project_id/doc/:doc_id/metadata',
- AsyncLocalStorage.middleware,
- AuthorizationMiddleware.ensureUserCanReadProject,
- Settings.allowAnonymousReadAndWriteSharing
- ? (req, res, next) => {
- next()
- }
- : AuthenticationController.requireLogin(),
- MetaController.broadcastMetadataForDoc
- )
- privateApiRouter.post(
- '/internal/expire-deleted-projects-after-duration',
- AuthenticationController.requirePrivateApiAuth(),
- ProjectController.expireDeletedProjectsAfterDuration
- )
- privateApiRouter.post(
- '/internal/expire-deleted-users-after-duration',
- AuthenticationController.requirePrivateApiAuth(),
- UserController.expireDeletedUsersAfterDuration
- )
- privateApiRouter.post(
- '/internal/project/:projectId/expire-deleted-project',
- AuthenticationController.requirePrivateApiAuth(),
- ProjectController.expireDeletedProject
- )
- privateApiRouter.post(
- '/internal/users/:userId/expire',
- AuthenticationController.requirePrivateApiAuth(),
- UserController.expireDeletedUser
- )
- privateApiRouter.get(
- '/user/:userId/tag',
- AuthenticationController.requirePrivateApiAuth(),
- TagsController.apiGetAllTags
- )
- webRouter.get(
- '/tag',
- AuthenticationController.requireLogin(),
- TagsController.getAllTags
- )
- webRouter.post(
- '/tag',
- AuthenticationController.requireLogin(),
- RateLimiterMiddleware.rateLimit(rateLimiters.createTag),
- TagsController.createTag
- )
- webRouter.post(
- '/tag/:tagId/rename',
- AuthenticationController.requireLogin(),
- RateLimiterMiddleware.rateLimit(rateLimiters.renameTag),
- TagsController.renameTag
- )
- webRouter.post(
- '/tag/:tagId/edit',
- AuthenticationController.requireLogin(),
- RateLimiterMiddleware.rateLimit(rateLimiters.renameTag),
- TagsController.editTag
- )
- webRouter.delete(
- '/tag/:tagId',
- AuthenticationController.requireLogin(),
- RateLimiterMiddleware.rateLimit(rateLimiters.deleteTag),
- TagsController.deleteTag
- )
- webRouter.post(
- '/tag/:tagId/project/:projectId',
- AuthenticationController.requireLogin(),
- RateLimiterMiddleware.rateLimit(rateLimiters.addProjectToTag),
- TagsController.addProjectToTag
- )
- webRouter.post(
- '/tag/:tagId/projects',
- AuthenticationController.requireLogin(),
- RateLimiterMiddleware.rateLimit(rateLimiters.addProjectsToTag),
- TagsController.addProjectsToTag
- )
- webRouter.delete(
- '/tag/:tagId/project/:projectId',
- AuthenticationController.requireLogin(),
- RateLimiterMiddleware.rateLimit(rateLimiters.removeProjectFromTag),
- TagsController.removeProjectFromTag
- )
- webRouter.post(
- '/tag/:tagId/projects/remove',
- AuthenticationController.requireLogin(),
- RateLimiterMiddleware.rateLimit(rateLimiters.removeProjectsFromTag),
- TagsController.removeProjectsFromTag
- )
- webRouter.get(
- '/notifications',
- AuthenticationController.requireLogin(),
- NotificationsController.getAllUnreadNotifications
- )
- webRouter.delete(
- '/notifications/:notificationId',
- AuthenticationController.requireLogin(),
- NotificationsController.markNotificationAsRead
- )
- webRouter.get(
- '/user/notification/:notificationId',
- AuthenticationController.requireLogin(),
- NotificationsController.getNotification
- )
- // Deprecated in favour of /internal/project/:project_id but still used by versioning
- privateApiRouter.get(
- '/project/:project_id/details',
- AuthenticationController.requirePrivateApiAuth(),
- ProjectApiController.getProjectDetails
- )
- // New 'stable' /internal API end points
- privateApiRouter.get(
- '/internal/project/:project_id',
- AuthenticationController.requirePrivateApiAuth(),
- ProjectApiController.getProjectDetails
- )
- privateApiRouter.get(
- '/internal/project/:Project_id/zip',
- AuthenticationController.requirePrivateApiAuth(),
- ProjectDownloadsController.downloadProject
- )
- privateApiRouter.get(
- '/internal/project/:project_id/compile/pdf',
- AuthenticationController.requirePrivateApiAuth(),
- CompileController.compileAndDownloadPdf
- )
- privateApiRouter.post(
- '/internal/deactivateOldProjects',
- AuthenticationController.requirePrivateApiAuth(),
- InactiveProjectController.deactivateOldProjects
- )
- privateApiRouter.post(
- '/internal/project/:project_id/deactivate',
- AuthenticationController.requirePrivateApiAuth(),
- InactiveProjectController.deactivateProject
- )
- privateApiRouter.get(
- '/project/:Project_id/doc/:doc_id',
- AuthenticationController.requirePrivateApiAuth(),
- DocumentController.getDocument
- )
- privateApiRouter.post(
- '/project/:Project_id/doc/:doc_id',
- AuthenticationController.requirePrivateApiAuth(),
- DocumentController.setDocument
- )
- privateApiRouter.post(
- '/project/:Project_id/doc/:doc_id/changes/reject',
- AuthenticationController.requirePrivateApiAuth(),
- DocumentController.trackChangesRejected
- )
- privateApiRouter.post(
- '/user/:user_id/project/new',
- AuthenticationController.requirePrivateApiAuth(),
- TpdsController.createProject
- )
- privateApiRouter.post(
- '/tpds/folder-update',
- AuthenticationController.requirePrivateApiAuth(),
- TpdsController.updateFolder
- )
- privateApiRouter.post(
- '/user/:user_id/update/*',
- AuthenticationController.requirePrivateApiAuth(),
- TpdsController.mergeUpdate
- )
- privateApiRouter.delete(
- '/user/:user_id/update/*',
- AuthenticationController.requirePrivateApiAuth(),
- TpdsController.deleteUpdate
- )
- privateApiRouter.post(
- '/project/:project_id/user/:user_id/update/*',
- AuthenticationController.requirePrivateApiAuth(),
- TpdsController.mergeUpdate
- )
- privateApiRouter.delete(
- '/project/:project_id/user/:user_id/update/*',
- AuthenticationController.requirePrivateApiAuth(),
- TpdsController.deleteUpdate
- )
- privateApiRouter.post(
- '/project/:project_id/contents/*',
- AuthenticationController.requirePrivateApiAuth(),
- TpdsController.updateProjectContents
- )
- privateApiRouter.delete(
- '/project/:project_id/contents/*',
- AuthenticationController.requirePrivateApiAuth(),
- TpdsController.deleteProjectContents
- )
- webRouter.post(
- '/spelling/learn',
- AuthenticationController.requireLogin(),
- SpellingController.learn
- )
- webRouter.post(
- '/spelling/unlearn',
- AuthenticationController.requireLogin(),
- SpellingController.unlearn
- )
- if (Features.hasFeature('chat')) {
- webRouter.get(
- '/project/:project_id/messages',
- AuthorizationMiddleware.blockRestrictedUserFromProject,
- AuthorizationMiddleware.ensureUserCanReadProject,
- PermissionsController.requirePermission('chat'),
- ChatController.getMessages
- )
- webRouter.post(
- '/project/:project_id/messages',
- AuthorizationMiddleware.blockRestrictedUserFromProject,
- AuthorizationMiddleware.ensureUserCanReadProject,
- PermissionsController.requirePermission('chat'),
- RateLimiterMiddleware.rateLimit(rateLimiters.sendChatMessage),
- ChatController.sendMessage
- )
- webRouter.delete(
- '/project/:project_id/messages/:message_id',
- AuthorizationMiddleware.blockRestrictedUserFromProject,
- AuthorizationMiddleware.ensureUserCanReadProject,
- AuthorizationMiddleware.ensureUserIsMessageAuthor,
- PermissionsController.requirePermission('chat'),
- ChatController.deleteMessage
- )
- webRouter.post(
- '/project/:project_id/messages/:message_id/edit',
- AuthorizationMiddleware.blockRestrictedUserFromProject,
- AuthorizationMiddleware.ensureUserCanReadProject,
- AuthorizationMiddleware.ensureUserIsMessageAuthor,
- PermissionsController.requirePermission('chat'),
- ChatController.editMessage
- )
- }
- webRouter.post(
- '/project/:Project_id/references/indexAll',
- AuthorizationMiddleware.ensureUserCanReadProject,
- RateLimiterMiddleware.rateLimit(rateLimiters.indexAllProjectReferences),
- ReferencesController.indexAll
- )
- // disable beta program while v2 is in beta
- webRouter.get(
- '/beta/participate',
- AuthenticationController.requireLogin(),
- BetaProgramController.optInPage
- )
- webRouter.post(
- '/beta/opt-in',
- AuthenticationController.requireLogin(),
- BetaProgramController.optIn
- )
- webRouter.post(
- '/beta/opt-out',
- AuthenticationController.requireLogin(),
- BetaProgramController.optOut
- )
- webRouter.get('/chrome', function (req, res, next) {
- // Match v1 behaviour - this is used for a Chrome web app
- if (SessionManager.isUserLoggedIn(req.session)) {
- res.redirect('/project')
- } else {
- res.redirect('/register')
- }
- })
- webRouter.get(
- '/admin',
- AuthorizationMiddleware.ensureUserIsSiteAdmin,
- AdminController.index
- )
- if (!Features.hasFeature('saas')) {
- webRouter.post(
- '/admin/openEditor',
- AuthorizationMiddleware.ensureUserIsSiteAdmin,
- AdminController.openEditor
- )
- webRouter.post(
- '/admin/closeEditor',
- AuthorizationMiddleware.ensureUserIsSiteAdmin,
- AdminController.closeEditor
- )
- webRouter.post(
- '/admin/disconnectAllUsers',
- AuthorizationMiddleware.ensureUserIsSiteAdmin,
- AdminController.disconnectAllUsers
- )
- }
- webRouter.post(
- '/admin/flushProjectToTpds',
- AuthorizationMiddleware.ensureUserIsSiteAdmin,
- AdminController.flushProjectToTpds
- )
- webRouter.post(
- '/admin/pollDropboxForUser',
- AuthorizationMiddleware.ensureUserIsSiteAdmin,
- AdminController.pollDropboxForUser
- )
- webRouter.post(
- '/admin/messages',
- AuthorizationMiddleware.ensureUserIsSiteAdmin,
- AdminController.createMessage
- )
- webRouter.post(
- '/admin/messages/clear',
- AuthorizationMiddleware.ensureUserIsSiteAdmin,
- AdminController.clearMessages
- )
- privateApiRouter.get('/perfTest', (req, res) => {
- plainTextResponse(res, 'hello')
- })
- publicApiRouter.get('/status', (req, res) => {
- if (Settings.shuttingDown) {
- res.sendStatus(503) // Service unavailable
- } else if (!Settings.siteIsOpen) {
- plainTextResponse(res, 'web site is closed (web)')
- } else if (!Settings.editorIsOpen) {
- plainTextResponse(res, 'web editor is closed (web)')
- } else {
- plainTextResponse(res, 'web is alive (web)')
- }
- })
- privateApiRouter.get('/status', (req, res) => {
- plainTextResponse(res, 'web is alive (api)')
- })
- // used by kubernetes health-check and acceptance tests
- webRouter.get('/dev/csrf', (req, res) => {
- plainTextResponse(res, res.locals.csrfToken)
- })
- privateApiRouter.get(
- '/health_check',
- HealthCheckController.checkActiveHandles,
- HealthCheckController.checkApi
- )
- publicApiRouter.get(
- '/health_check/api',
- HealthCheckController.checkActiveHandles,
- HealthCheckController.checkApi
- )
- privateApiRouter.get(
- '/health_check/api',
- HealthCheckController.checkActiveHandles,
- HealthCheckController.checkApi
- )
- publicApiRouter.get('/health_check/redis', HealthCheckController.checkRedis)
- privateApiRouter.get('/health_check/redis', HealthCheckController.checkRedis)
- publicApiRouter.get('/health_check/mongo', HealthCheckController.checkMongo)
- privateApiRouter.get('/health_check/mongo', HealthCheckController.checkMongo)
- webRouter.get(
- '/status/compiler/:Project_id',
- RateLimiterMiddleware.rateLimit(rateLimiters.statusCompiler),
- AuthorizationMiddleware.ensureUserCanReadProject,
- function (req, res) {
- const projectId = req.params.Project_id
- // use a valid user id for testing
- const testUserId = '123456789012345678901234'
- const sendRes = _.once(function (statusCode, message, clsiServerId) {
- res.status(statusCode)
- plainTextResponse(res, message)
- // Force every compile to a new server and do not leave cruft behind.
- CompileManager.promises
- .deleteAuxFiles(projectId, testUserId, clsiServerId)
- .catch(() => {})
- })
- let handler = setTimeout(function () {
- CompileManager.promises
- .stopCompile(projectId, testUserId)
- .catch(() => {})
- sendRes(500, 'Compiler timed out')
- handler = null
- }, 10000)
- CompileManager.compile(
- projectId,
- testUserId,
- {
- metricsPath: 'health-check',
- compileFromHistory: true,
- rootResourcePath: 'main.tex',
- },
- function (error, status, _outputFiles, clsiServerId) {
- if (handler) {
- clearTimeout(handler)
- }
- if (error) {
- sendRes(
- 500,
- `Compiler returned error ${error.message}`,
- clsiServerId
- )
- } else if (status === 'success') {
- sendRes(
- 200,
- 'Compiler returned in less than 10 seconds',
- clsiServerId
- )
- } else {
- sendRes(500, `Compiler returned failure ${status}`, clsiServerId)
- }
- }
- )
- }
- )
- webRouter.post('/error/client', function (req, res, next) {
- logger.warn(
- { err: req.body.error, meta: req.body.meta },
- 'client side error'
- )
- metrics.inc('client-side-error')
- res.sendStatus(204)
- })
- if (Features.hasFeature('link-sharing')) {
- webRouter.get(
- `/read/:token(${TokenAccessController.READ_ONLY_TOKEN_PATTERN})`,
- RateLimiterMiddleware.rateLimit(rateLimiters.readOnlyToken),
- AnalyticsRegistrationSourceMiddleware.setSource(
- 'collaboration',
- 'link-sharing'
- ),
- TokenAccessController.tokenAccessPage,
- AnalyticsRegistrationSourceMiddleware.clearSource()
- )
- webRouter.get(
- `/:token(${TokenAccessController.READ_AND_WRITE_TOKEN_PATTERN})`,
- RateLimiterMiddleware.rateLimit(rateLimiters.readAndWriteToken),
- AnalyticsRegistrationSourceMiddleware.setSource(
- 'collaboration',
- 'link-sharing'
- ),
- TokenAccessController.tokenAccessPage,
- AnalyticsRegistrationSourceMiddleware.clearSource()
- )
- webRouter.post(
- `/:token(${TokenAccessController.READ_AND_WRITE_TOKEN_PATTERN})/grant`,
- RateLimiterMiddleware.rateLimit(rateLimiters.grantTokenAccessReadWrite),
- TokenAccessController.grantTokenAccessReadAndWrite
- )
- webRouter.post(
- `/read/:token(${TokenAccessController.READ_ONLY_TOKEN_PATTERN})/grant`,
- RateLimiterMiddleware.rateLimit(rateLimiters.grantTokenAccessReadOnly),
- TokenAccessController.grantTokenAccessReadOnly
- )
- }
- webRouter.get('/unsupported-browser', renderUnsupportedBrowserPage)
- webRouter.get('*', ErrorController.notFound)
- }
- export default { initialize, rateLimiters }
|