router.mjs 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279
  1. import AdminController from './Features/ServerAdmin/AdminController.mjs'
  2. import ErrorController from './Features/Errors/ErrorController.mjs'
  3. import Features from './infrastructure/Features.mjs'
  4. import ProjectController from './Features/Project/ProjectController.mjs'
  5. import ProjectApiController from './Features/Project/ProjectApiController.mjs'
  6. import ProjectListController from './Features/Project/ProjectListController.mjs'
  7. import SpellingController from './Features/Spelling/SpellingController.mjs'
  8. import EditorRouter from './Features/Editor/EditorRouter.mjs'
  9. import Settings from '@overleaf/settings'
  10. import TpdsController from './Features/ThirdPartyDataStore/TpdsController.mjs'
  11. import SubscriptionRouter from './Features/Subscription/SubscriptionRouter.mjs'
  12. import UploadsRouter from './Features/Uploads/UploadsRouter.mjs'
  13. import metrics from '@overleaf/metrics'
  14. import ReferalController from './Features/Referal/ReferalController.mjs'
  15. import AuthenticationController from './Features/Authentication/AuthenticationController.mjs'
  16. import PermissionsController from './Features/Authorization/PermissionsController.mjs'
  17. import SessionManager from './Features/Authentication/SessionManager.mjs'
  18. import TagsController from './Features/Tags/TagsController.mjs'
  19. import NotificationsController from './Features/Notifications/NotificationsController.mjs'
  20. import CollaboratorsRouter from './Features/Collaborators/CollaboratorsRouter.mjs'
  21. import UserInfoController from './Features/User/UserInfoController.mjs'
  22. import UserController from './Features/User/UserController.mjs'
  23. import UserEmailsController from './Features/User/UserEmailsController.mjs'
  24. import UserPagesController from './Features/User/UserPagesController.mjs'
  25. import TutorialController from './Features/Tutorial/TutorialController.mjs'
  26. import DocumentController from './Features/Documents/DocumentController.mjs'
  27. import CompileManager from './Features/Compile/CompileManager.mjs'
  28. import CompileController from './Features/Compile/CompileController.mjs'
  29. import HealthCheckController from './Features/HealthCheck/HealthCheckController.mjs'
  30. import ProjectDownloadsController from './Features/Downloads/ProjectDownloadsController.mjs'
  31. import FileStoreController from './Features/FileStore/FileStoreController.mjs'
  32. import DocumentUpdaterController from './Features/DocumentUpdater/DocumentUpdaterController.mjs'
  33. import HistoryRouter from './Features/History/HistoryRouter.mjs'
  34. import ExportsController from './Features/Exports/ExportsController.mjs'
  35. import PasswordResetRouter from './Features/PasswordReset/PasswordResetRouter.mjs'
  36. import StaticPagesRouter from './Features/StaticPages/StaticPagesRouter.mjs'
  37. import ChatController from './Features/Chat/ChatController.mjs'
  38. import Modules from './infrastructure/Modules.mjs'
  39. import {
  40. RateLimiter,
  41. openProjectRateLimiter,
  42. overleafLoginRateLimiter,
  43. } from './infrastructure/RateLimiter.mjs'
  44. import RateLimiterMiddleware from './Features/Security/RateLimiterMiddleware.mjs'
  45. import InactiveProjectController from './Features/InactiveData/InactiveProjectController.mjs'
  46. import ContactRouter from './Features/Contacts/ContactRouter.mjs'
  47. import ReferencesController from './Features/References/ReferencesController.mjs'
  48. import AuthorizationMiddleware from './Features/Authorization/AuthorizationMiddleware.mjs'
  49. import BetaProgramController from './Features/BetaProgram/BetaProgramController.mjs'
  50. import AnalyticsRouter from './Features/Analytics/AnalyticsRouter.mjs'
  51. import MetaController from './Features/Metadata/MetaController.mjs'
  52. import TokenAccessController from './Features/TokenAccess/TokenAccessController.mjs'
  53. import TokenAccessRouter from './Features/TokenAccess/TokenAccessRouter.mjs'
  54. import LinkedFilesRouter from './Features/LinkedFiles/LinkedFilesRouter.mjs'
  55. import TemplatesRouter from './Features/Templates/TemplatesRouter.mjs'
  56. import UserMembershipRouter from './Features/UserMembership/UserMembershipRouter.mjs'
  57. import SystemMessageController from './Features/SystemMessages/SystemMessageController.mjs'
  58. import AnalyticsRegistrationSourceMiddleware from './Features/Analytics/AnalyticsRegistrationSourceMiddleware.mjs'
  59. import AnalyticsUTMTrackingMiddleware from './Features/Analytics/AnalyticsUTMTrackingMiddleware.mjs'
  60. import CaptchaMiddleware from './Features/Captcha/CaptchaMiddleware.mjs'
  61. import UnsupportedBrowserMiddleware from './infrastructure/UnsupportedBrowserMiddleware.mjs'
  62. import logger from '@overleaf/logger'
  63. import _ from 'lodash'
  64. import { plainTextResponse } from './infrastructure/Response.mjs'
  65. import SocketDiagnostics from './Features/SocketDiagnostics/SocketDiagnostics.mjs'
  66. import ClsiCacheController from './Features/Compile/ClsiCacheController.mjs'
  67. import AsyncLocalStorage from './infrastructure/AsyncLocalStorage.mjs'
  68. const { renderUnsupportedBrowserPage, unsupportedBrowserMiddleware } =
  69. UnsupportedBrowserMiddleware
  70. const rateLimiters = {
  71. addEmail: new RateLimiter('add-email', {
  72. points: 10,
  73. duration: 60,
  74. }),
  75. addProjectToTag: new RateLimiter('add-project-to-tag', {
  76. points: 30,
  77. duration: 60,
  78. }),
  79. addProjectsToTag: new RateLimiter('add-projects-to-tag', {
  80. points: 30,
  81. duration: 60,
  82. }),
  83. canSkipCaptcha: new RateLimiter('can-skip-captcha', {
  84. points: 20,
  85. duration: 60,
  86. }),
  87. changePassword: new RateLimiter('change-password', {
  88. points: 10,
  89. duration: 60,
  90. }),
  91. compileProjectHttp: new RateLimiter('compile-project-http', {
  92. points: 200,
  93. duration: 10 * 60,
  94. }),
  95. confirmEmail: new RateLimiter('confirm-email', {
  96. points: 10,
  97. duration: 60,
  98. }),
  99. createProject: new RateLimiter('create-project', {
  100. points: 20,
  101. duration: 60,
  102. }),
  103. createTag: new RateLimiter('create-tag', {
  104. points: 30,
  105. duration: 60,
  106. }),
  107. deleteEmail: new RateLimiter('delete-email', {
  108. points: 10,
  109. duration: 60,
  110. }),
  111. deleteTag: new RateLimiter('delete-tag', {
  112. points: 30,
  113. duration: 60,
  114. }),
  115. deleteUser: new RateLimiter('delete-user', {
  116. points: 10,
  117. duration: 60,
  118. }),
  119. endorseEmail: new RateLimiter('endorse-email', {
  120. points: 30,
  121. duration: 60,
  122. }),
  123. getProjects: new RateLimiter('get-projects', {
  124. points: 30,
  125. duration: 60,
  126. }),
  127. grantTokenAccessReadOnly: new RateLimiter('grant-token-access-read-only', {
  128. points: 10,
  129. duration: 60,
  130. }),
  131. grantTokenAccessReadWrite: new RateLimiter('grant-token-access-read-write', {
  132. points: 10,
  133. duration: 60,
  134. }),
  135. indexAllProjectReferences: new RateLimiter('index-all-project-references', {
  136. points: 30,
  137. duration: 60,
  138. }),
  139. miscOutputDownload: new RateLimiter('misc-output-download', {
  140. points: 1000,
  141. duration: 60 * 60,
  142. }),
  143. multipleProjectsZipDownload: new RateLimiter(
  144. 'multiple-projects-zip-download',
  145. {
  146. points: 10,
  147. duration: 60,
  148. }
  149. ),
  150. openDashboard: new RateLimiter('open-dashboard', {
  151. points: 30,
  152. duration: 60,
  153. }),
  154. readAndWriteToken: new RateLimiter('read-and-write-token', {
  155. points: 15,
  156. duration: 60,
  157. }),
  158. readOnlyToken: new RateLimiter('read-only-token', {
  159. points: 15,
  160. duration: 60,
  161. }),
  162. removeProjectFromTag: new RateLimiter('remove-project-from-tag', {
  163. points: 30,
  164. duration: 60,
  165. }),
  166. removeProjectsFromTag: new RateLimiter('remove-projects-from-tag', {
  167. points: 30,
  168. duration: 60,
  169. }),
  170. renameTag: new RateLimiter('rename-tag', {
  171. points: 30,
  172. duration: 60,
  173. }),
  174. resendConfirmation: new RateLimiter('resend-confirmation', {
  175. points: 1,
  176. duration: 60,
  177. }),
  178. sendConfirmation: new RateLimiter('send-confirmation', {
  179. points: 2,
  180. duration: 60,
  181. }),
  182. sendChatMessage: new RateLimiter('send-chat-message', {
  183. points: 100,
  184. duration: 60,
  185. }),
  186. statusCompiler: new RateLimiter('status-compiler', {
  187. points: 10,
  188. duration: 60,
  189. }),
  190. zipDownload: new RateLimiter('zip-download', {
  191. points: 10,
  192. duration: 60,
  193. }),
  194. documentExport: new RateLimiter('document-export', {
  195. points: 5,
  196. duration: 60,
  197. }),
  198. documentExportDownload: new RateLimiter('document-export-download', {
  199. points: 30,
  200. duration: 60,
  201. }),
  202. }
  203. async function initialize(webRouter, privateApiRouter, publicApiRouter) {
  204. webRouter.use(unsupportedBrowserMiddleware)
  205. if (!Settings.allowPublicAccess) {
  206. webRouter.all('*', AuthenticationController.requireGlobalLogin)
  207. }
  208. webRouter.get('*', AnalyticsRegistrationSourceMiddleware.setInbound())
  209. webRouter.get('*', AnalyticsUTMTrackingMiddleware.recordUTMTags())
  210. if (process.env.NODE_ENV === 'development' && global.__coverage__) {
  211. // Expose code coverage via an endpoint when running with code coverage enabled
  212. webRouter.get('/coverage', (req, res) => {
  213. const coverage = {}
  214. for (const [key, value] of Object.entries(global.__coverage__)) {
  215. coverage[key] = {
  216. ...value,
  217. // Transform for Jenkins sourcemap
  218. path: value.path.replace('/overleaf/', '/workspace/'),
  219. }
  220. }
  221. res.json({ coverage })
  222. })
  223. }
  224. // Mount onto /login in order to get the deviceHistory cookie.
  225. webRouter.post(
  226. '/login/can-skip-captcha',
  227. // Keep in sync with the overleaf-login options.
  228. RateLimiterMiddleware.rateLimit(rateLimiters.canSkipCaptcha),
  229. CaptchaMiddleware.canSkipCaptcha
  230. )
  231. webRouter.get('/login', UserPagesController.loginPage)
  232. AuthenticationController.addEndpointToLoginWhitelist('/login')
  233. webRouter.post(
  234. '/login',
  235. RateLimiterMiddleware.rateLimit(overleafLoginRateLimiter), // rate limit IP (20 / 60s)
  236. RateLimiterMiddleware.loginRateLimitEmail(), // rate limit email (10 / 120s)
  237. CaptchaMiddleware.validateCaptcha('login'),
  238. AuthenticationController.passportLogin
  239. )
  240. webRouter.get(
  241. '/compromised-password',
  242. AuthenticationController.requireLogin(),
  243. UserPagesController.compromisedPasswordPage
  244. )
  245. webRouter.get('/account-suspended', UserPagesController.accountSuspended)
  246. webRouter.get(
  247. '/socket-diagnostics',
  248. AuthenticationController.requireLogin(),
  249. SocketDiagnostics.index
  250. )
  251. if (Settings.enableLegacyLogin) {
  252. AuthenticationController.addEndpointToLoginWhitelist('/login/legacy')
  253. webRouter.get('/login/legacy', UserPagesController.loginPage)
  254. webRouter.post(
  255. '/login/legacy',
  256. RateLimiterMiddleware.rateLimit(overleafLoginRateLimiter), // rate limit IP (20 / 60s)
  257. RateLimiterMiddleware.loginRateLimitEmail(), // rate limit email (10 / 120s)
  258. CaptchaMiddleware.validateCaptcha('login'),
  259. AuthenticationController.passportLogin
  260. )
  261. }
  262. webRouter.get(
  263. '/read-only/one-time-login',
  264. UserPagesController.oneTimeLoginPage
  265. )
  266. AuthenticationController.addEndpointToLoginWhitelist(
  267. '/read-only/one-time-login'
  268. )
  269. webRouter.get('/logout', UserPagesController.logout)
  270. webRouter.post('/logout', UserController.logout)
  271. webRouter.get('/restricted', AuthorizationMiddleware.restricted)
  272. if (Features.hasFeature('registration-page')) {
  273. webRouter.get('/register', UserPagesController.registerPage)
  274. AuthenticationController.addEndpointToLoginWhitelist('/register')
  275. }
  276. EditorRouter.apply(webRouter, privateApiRouter)
  277. CollaboratorsRouter.apply(webRouter, privateApiRouter)
  278. SubscriptionRouter.apply(webRouter, privateApiRouter, publicApiRouter)
  279. UploadsRouter.apply(webRouter, privateApiRouter)
  280. PasswordResetRouter.apply(webRouter, privateApiRouter)
  281. StaticPagesRouter.apply(webRouter, privateApiRouter)
  282. ContactRouter.apply(webRouter, privateApiRouter)
  283. AnalyticsRouter.apply(webRouter, privateApiRouter, publicApiRouter)
  284. LinkedFilesRouter.apply(webRouter, privateApiRouter, publicApiRouter)
  285. TemplatesRouter.apply(webRouter)
  286. UserMembershipRouter.apply(webRouter)
  287. TokenAccessRouter.apply(webRouter)
  288. HistoryRouter.apply(webRouter, privateApiRouter)
  289. await Modules.applyRouter(webRouter, privateApiRouter, publicApiRouter)
  290. if (Settings.enableSubscriptions) {
  291. webRouter.get(
  292. '/user/bonus',
  293. AuthenticationController.requireLogin(),
  294. ReferalController.bonus
  295. )
  296. }
  297. // .getMessages will generate an empty response for anonymous users.
  298. webRouter.get('/system/messages', SystemMessageController.getMessages)
  299. webRouter.get(
  300. '/user/settings',
  301. AuthenticationController.requireLogin(),
  302. PermissionsController.useCapabilities(),
  303. UserPagesController.settingsPage
  304. )
  305. webRouter.post(
  306. '/user/settings',
  307. AuthenticationController.requireLogin(),
  308. UserController.updateUserSettings
  309. )
  310. webRouter.post(
  311. '/user/password/update',
  312. AuthenticationController.requireLogin(),
  313. RateLimiterMiddleware.rateLimit(rateLimiters.changePassword),
  314. PermissionsController.requirePermission('change-password'),
  315. UserController.changePassword
  316. )
  317. webRouter.get(
  318. '/user/emails',
  319. AuthenticationController.requireLogin(),
  320. AsyncLocalStorage.middleware,
  321. PermissionsController.useCapabilities(),
  322. UserController.ensureAffiliationMiddleware,
  323. UserEmailsController.list
  324. )
  325. webRouter.get(
  326. '/user/emails/confirm',
  327. AuthenticationController.requireLogin(),
  328. UserEmailsController.showConfirm
  329. )
  330. webRouter.post(
  331. '/user/emails/confirm',
  332. AuthenticationController.requireLogin(),
  333. RateLimiterMiddleware.rateLimit(rateLimiters.confirmEmail),
  334. UserEmailsController.confirm
  335. )
  336. webRouter.post(
  337. '/user/emails/send-confirmation-code',
  338. AuthenticationController.requireLogin(),
  339. RateLimiterMiddleware.rateLimit(rateLimiters.sendConfirmation),
  340. await Modules.middleware('confirmationEmailMiddleware'),
  341. UserEmailsController.sendExistingEmailConfirmationCode
  342. )
  343. webRouter.post(
  344. '/user/emails/resend-confirmation-code',
  345. AuthenticationController.requireLogin(),
  346. RateLimiterMiddleware.rateLimit(rateLimiters.resendConfirmation),
  347. UserEmailsController.resendExistingSecondaryEmailConfirmationCode
  348. )
  349. webRouter.post(
  350. '/user/emails/confirm-code',
  351. AuthenticationController.requireLogin(),
  352. RateLimiterMiddleware.rateLimit(rateLimiters.confirmEmail),
  353. UserEmailsController.checkExistingEmailConfirmationCode
  354. )
  355. webRouter.get(
  356. '/user/emails/primary-email-check',
  357. AuthenticationController.requireLogin(),
  358. UserEmailsController.primaryEmailCheckPage
  359. )
  360. webRouter.post(
  361. '/user/emails/primary-email-check',
  362. AuthenticationController.requireLogin(),
  363. PermissionsController.useCapabilities(),
  364. UserEmailsController.primaryEmailCheck
  365. )
  366. if (Features.hasFeature('affiliations')) {
  367. webRouter.post(
  368. '/user/emails/delete',
  369. AuthenticationController.requireLogin(),
  370. RateLimiterMiddleware.rateLimit(rateLimiters.deleteEmail),
  371. await Modules.middleware('userDeleteEmail'),
  372. UserEmailsController.remove
  373. )
  374. webRouter.post(
  375. '/user/emails/default',
  376. AuthenticationController.requireLogin(),
  377. UserEmailsController.setDefault
  378. )
  379. webRouter.post(
  380. '/user/emails/endorse',
  381. AuthenticationController.requireLogin(),
  382. PermissionsController.requirePermission('endorse-email'),
  383. RateLimiterMiddleware.rateLimit(rateLimiters.endorseEmail),
  384. UserEmailsController.endorse
  385. )
  386. }
  387. if (Features.hasFeature('saas')) {
  388. webRouter.get(
  389. '/user/emails/add-secondary',
  390. AuthenticationController.requireLogin(),
  391. PermissionsController.requirePermission('add-secondary-email'),
  392. UserEmailsController.addSecondaryEmailPage
  393. )
  394. webRouter.get(
  395. '/user/emails/confirm-secondary',
  396. AuthenticationController.requireLogin(),
  397. PermissionsController.requirePermission('add-secondary-email'),
  398. UserEmailsController.confirmSecondaryEmailPage
  399. )
  400. }
  401. webRouter.get(
  402. '/user/sessions',
  403. AuthenticationController.requireLogin(),
  404. UserPagesController.sessionsPage
  405. )
  406. webRouter.post(
  407. '/user/sessions/clear',
  408. AuthenticationController.requireLogin(),
  409. UserController.clearSessions
  410. )
  411. // deprecated
  412. webRouter.delete(
  413. '/user/newsletter/unsubscribe',
  414. AuthenticationController.requireLogin(),
  415. UserController.unsubscribe
  416. )
  417. webRouter.post(
  418. '/user/newsletter/unsubscribe',
  419. AuthenticationController.requireLogin(),
  420. UserController.unsubscribe
  421. )
  422. webRouter.post(
  423. '/user/newsletter/subscribe',
  424. AuthenticationController.requireLogin(),
  425. UserController.subscribe
  426. )
  427. webRouter.get(
  428. '/user/email-preferences',
  429. AuthenticationController.requireLogin(),
  430. UserPagesController.emailPreferencesPage
  431. )
  432. webRouter.post(
  433. '/user/delete',
  434. RateLimiterMiddleware.rateLimit(rateLimiters.deleteUser),
  435. AuthenticationController.requireLogin(),
  436. PermissionsController.requirePermission('delete-own-account'),
  437. UserController.tryDeleteUser
  438. )
  439. webRouter.get(
  440. '/user/personal_info',
  441. AuthenticationController.requireLogin(),
  442. UserInfoController.getLoggedInUsersPersonalInfo
  443. )
  444. privateApiRouter.get(
  445. '/user/:user_id/personal_info',
  446. AuthenticationController.requirePrivateApiAuth(),
  447. UserInfoController.getPersonalInfo
  448. )
  449. webRouter.get(
  450. '/user/features',
  451. AuthenticationController.requireLogin(),
  452. UserInfoController.getUserFeatures
  453. )
  454. webRouter.get(
  455. '/user/reconfirm',
  456. UserPagesController.renderReconfirmAccountPage
  457. )
  458. // for /user/reconfirm POST, see password router
  459. webRouter.get(
  460. '/user/tpds/queues',
  461. AuthenticationController.requireLogin(),
  462. TpdsController.getQueues
  463. )
  464. webRouter.post(
  465. '/tutorial/:tutorialKey/complete',
  466. AuthenticationController.requireLogin(),
  467. TutorialController.completeTutorial
  468. )
  469. webRouter.post(
  470. '/tutorial/:tutorialKey/postpone',
  471. AuthenticationController.requireLogin(),
  472. TutorialController.postponeTutorial
  473. )
  474. webRouter.get(
  475. '/user/projects',
  476. AuthenticationController.requireLogin(),
  477. ProjectController.userProjectsJson
  478. )
  479. webRouter.get(
  480. '/project/:Project_id/entities',
  481. AuthenticationController.requireLogin(),
  482. AuthorizationMiddleware.ensureUserCanReadProject,
  483. ProjectController.projectEntitiesJson
  484. )
  485. webRouter.get(
  486. '/project',
  487. AuthenticationController.requireLogin(),
  488. RateLimiterMiddleware.rateLimit(rateLimiters.openDashboard),
  489. AsyncLocalStorage.middleware,
  490. await Modules.middleware('domainCaptureTestSession'),
  491. PermissionsController.useCapabilities(),
  492. ProjectListController.projectListPage
  493. )
  494. webRouter.post(
  495. '/project/new',
  496. AuthenticationController.requireLogin(),
  497. RateLimiterMiddleware.rateLimit(rateLimiters.createProject),
  498. ProjectController.newProject
  499. )
  500. webRouter.post(
  501. '/api/project',
  502. AuthenticationController.requireLogin(),
  503. RateLimiterMiddleware.rateLimit(rateLimiters.getProjects),
  504. ProjectListController.getProjectsJson
  505. )
  506. for (const route of [
  507. // Keep the old route for continuous metrics
  508. '/Project/:Project_id',
  509. // New route for pdf-detach
  510. '/Project/:Project_id/:detachRole(detacher|detached)',
  511. ]) {
  512. webRouter.get(
  513. route,
  514. RateLimiterMiddleware.rateLimit(openProjectRateLimiter, {
  515. params: ['Project_id'],
  516. }),
  517. AsyncLocalStorage.middleware,
  518. PermissionsController.useCapabilities(),
  519. AuthorizationMiddleware.ensureUserCanReadProject,
  520. ProjectController.loadEditor
  521. )
  522. }
  523. webRouter.head(
  524. '/Project/:Project_id/file/:File_id',
  525. AuthorizationMiddleware.ensureUserCanReadProject,
  526. FileStoreController.getFileHead
  527. )
  528. webRouter.get(
  529. '/Project/:Project_id/file/:File_id',
  530. AuthorizationMiddleware.ensureUserCanReadProject,
  531. FileStoreController.getFile
  532. )
  533. webRouter.get(
  534. '/Project/:Project_id/doc/:Doc_id/download', // "download" suffix to avoid conflict with private API route at doc/:doc_id
  535. AuthorizationMiddleware.ensureUserCanReadProject,
  536. DocumentUpdaterController.getDoc
  537. )
  538. webRouter.post(
  539. '/project/:Project_id/settings',
  540. AuthorizationMiddleware.ensureUserCanWriteProjectSettings,
  541. ProjectController.updateProjectSettings
  542. )
  543. webRouter.post(
  544. '/project/:Project_id/settings/admin',
  545. AuthenticationController.requireLogin(),
  546. AuthorizationMiddleware.ensureUserCanAdminProject,
  547. ProjectController.updateProjectAdminSettings
  548. )
  549. webRouter.post(
  550. '/project/:Project_id/compile',
  551. RateLimiterMiddleware.rateLimit(rateLimiters.compileProjectHttp, {
  552. params: ['Project_id'],
  553. }),
  554. AsyncLocalStorage.middleware,
  555. AuthorizationMiddleware.ensureUserCanReadProject,
  556. CompileController.compile
  557. )
  558. webRouter.post(
  559. '/project/:Project_id/compile/stop',
  560. AuthorizationMiddleware.ensureUserCanReadProject,
  561. CompileController.stopCompile
  562. )
  563. webRouter.get(
  564. '/project/:Project_id/output/cached/output.overleaf.json',
  565. AsyncLocalStorage.middleware,
  566. AuthorizationMiddleware.ensureUserCanReadProject,
  567. ClsiCacheController.getLatestBuildFromCache
  568. )
  569. webRouter.get(
  570. '/download/project/:Project_id/build/:editorBuildId/output/cached/:filename(.*)',
  571. AuthorizationMiddleware.ensureUserCanReadProject,
  572. ClsiCacheController.downloadFromCache
  573. )
  574. // PDF Download button for specific build
  575. webRouter.get(
  576. '/download/project/:Project_id/build/:build_id/output/output.pdf',
  577. AuthorizationMiddleware.ensureUserCanReadProject,
  578. CompileController.downloadPdf
  579. )
  580. // Align with limits defined in CompileController.downloadPdf
  581. const rateLimiterMiddlewareOutputFiles = RateLimiterMiddleware.rateLimit(
  582. rateLimiters.miscOutputDownload,
  583. { params: ['Project_id'] }
  584. )
  585. // Download all the output files of a specific build
  586. webRouter.get(
  587. '/project/:Project_id/build/:build_id/output/output.zip',
  588. rateLimiterMiddlewareOutputFiles,
  589. AuthorizationMiddleware.ensureUserCanReadProject,
  590. CompileController.getOutputZipFromClsi
  591. )
  592. webRouter.get(
  593. '/project/:Project_id/user/:user_id/build/:build_id/output/output.zip',
  594. rateLimiterMiddlewareOutputFiles,
  595. AuthorizationMiddleware.ensureUserCanReadProject,
  596. CompileController.getOutputZipFromClsi
  597. )
  598. // direct url access to output files for a specific build
  599. webRouter.get(
  600. '/project/:Project_id/build/:build_id/output/:file(.*)',
  601. rateLimiterMiddlewareOutputFiles,
  602. AuthorizationMiddleware.ensureUserCanReadProject,
  603. CompileController.getFileFromClsi
  604. )
  605. // direct url access to output files for a specific user and build
  606. webRouter.get(
  607. '/project/:Project_id/user/:user_id/build/:build_id/output/:file(.*)',
  608. rateLimiterMiddlewareOutputFiles,
  609. AuthorizationMiddleware.ensureUserCanReadProject,
  610. CompileController.getFileFromClsi
  611. )
  612. webRouter.delete(
  613. '/project/:Project_id/output',
  614. AuthorizationMiddleware.ensureUserCanReadProject,
  615. CompileController.deleteAuxFiles
  616. )
  617. webRouter.get(
  618. '/project/:Project_id/sync/code',
  619. AsyncLocalStorage.middleware,
  620. AuthorizationMiddleware.ensureUserCanReadProject,
  621. CompileController.proxySyncCode
  622. )
  623. webRouter.get(
  624. '/project/:Project_id/sync/pdf',
  625. AsyncLocalStorage.middleware,
  626. AuthorizationMiddleware.ensureUserCanReadProject,
  627. CompileController.proxySyncPdf
  628. )
  629. webRouter.get(
  630. '/project/:Project_id/wordcount',
  631. AuthorizationMiddleware.ensureUserCanReadProject,
  632. CompileController.wordCount
  633. )
  634. webRouter.post(
  635. '/Project/:Project_id/archive',
  636. AuthenticationController.requireLogin(),
  637. AuthorizationMiddleware.ensureUserCanReadProject,
  638. ProjectController.archiveProject
  639. )
  640. webRouter.delete(
  641. '/Project/:Project_id/archive',
  642. AuthenticationController.requireLogin(),
  643. AuthorizationMiddleware.ensureUserCanReadProject,
  644. ProjectController.unarchiveProject
  645. )
  646. webRouter.post(
  647. '/project/:project_id/trash',
  648. AuthenticationController.requireLogin(),
  649. AuthorizationMiddleware.ensureUserCanReadProject,
  650. ProjectController.trashProject
  651. )
  652. webRouter.delete(
  653. '/project/:project_id/trash',
  654. AuthenticationController.requireLogin(),
  655. AuthorizationMiddleware.ensureUserCanReadProject,
  656. ProjectController.untrashProject
  657. )
  658. webRouter.delete(
  659. '/Project/:Project_id',
  660. AuthenticationController.requireLogin(),
  661. AuthorizationMiddleware.ensureUserCanAdminProject,
  662. ProjectController.deleteProject
  663. )
  664. webRouter.post(
  665. '/Project/:Project_id/restore',
  666. AuthenticationController.requireLogin(),
  667. AuthorizationMiddleware.ensureUserCanAdminProject,
  668. ProjectController.restoreProject
  669. )
  670. webRouter.post(
  671. '/Project/:Project_id/clone',
  672. AuthorizationMiddleware.ensureUserCanReadProject,
  673. ProjectController.cloneProject
  674. )
  675. webRouter.post(
  676. '/project/:Project_id/rename',
  677. AuthenticationController.requireLogin(),
  678. AuthorizationMiddleware.ensureUserCanAdminProject,
  679. ProjectController.renameProject
  680. )
  681. webRouter.post(
  682. '/project/:project_id/export/:brand_variation_id',
  683. AuthorizationMiddleware.ensureUserCanWriteProjectContent,
  684. ExportsController.exportProject
  685. )
  686. webRouter.get(
  687. '/project/:project_id/export/:export_id',
  688. AuthorizationMiddleware.ensureUserCanWriteProjectContent,
  689. ExportsController.exportStatus
  690. )
  691. webRouter.get(
  692. '/project/:project_id/export/:export_id/:type',
  693. AuthorizationMiddleware.ensureUserCanWriteProjectContent,
  694. ExportsController.exportDownload
  695. )
  696. if (Settings.enablePandocConversions) {
  697. webRouter.get(
  698. '/project/:Project_id/download/conversion/:type',
  699. AuthenticationController.requireLogin(),
  700. RateLimiterMiddleware.rateLimit(rateLimiters.documentExport, {
  701. params: ['Project_id'],
  702. }),
  703. AuthorizationMiddleware.ensureUserCanReadProject,
  704. ProjectDownloadsController.exportProjectConversion
  705. )
  706. webRouter.get(
  707. '/project/:Project_id/download/conversion/:conversionId/:type/build/:buildId/output/:file(.*)',
  708. AuthenticationController.requireLogin(),
  709. RateLimiterMiddleware.rateLimit(rateLimiters.documentExportDownload, {
  710. params: ['Project_id'],
  711. }),
  712. AuthorizationMiddleware.ensureUserCanReadProject,
  713. ProjectDownloadsController.downloadPreparedProjectExport
  714. )
  715. }
  716. webRouter.get(
  717. '/Project/:Project_id/download/zip',
  718. RateLimiterMiddleware.rateLimit(rateLimiters.zipDownload, {
  719. params: ['Project_id'],
  720. }),
  721. AuthorizationMiddleware.ensureUserCanReadProject,
  722. ProjectDownloadsController.downloadProject
  723. )
  724. webRouter.get(
  725. '/project/download/zip',
  726. AuthenticationController.requireLogin(),
  727. RateLimiterMiddleware.rateLimit(rateLimiters.multipleProjectsZipDownload),
  728. AuthorizationMiddleware.ensureUserCanReadMultipleProjects,
  729. ProjectDownloadsController.downloadMultipleProjects
  730. )
  731. webRouter.get(
  732. '/project/:project_id/metadata',
  733. AsyncLocalStorage.middleware,
  734. AuthorizationMiddleware.ensureUserCanReadProject,
  735. Settings.allowAnonymousReadAndWriteSharing
  736. ? (req, res, next) => {
  737. next()
  738. }
  739. : AuthenticationController.requireLogin(),
  740. MetaController.getMetadata
  741. )
  742. webRouter.post(
  743. '/project/:project_id/doc/:doc_id/metadata',
  744. AsyncLocalStorage.middleware,
  745. AuthorizationMiddleware.ensureUserCanReadProject,
  746. Settings.allowAnonymousReadAndWriteSharing
  747. ? (req, res, next) => {
  748. next()
  749. }
  750. : AuthenticationController.requireLogin(),
  751. MetaController.broadcastMetadataForDoc
  752. )
  753. privateApiRouter.post(
  754. '/internal/expire-deleted-projects-after-duration',
  755. AuthenticationController.requirePrivateApiAuth(),
  756. ProjectController.expireDeletedProjectsAfterDuration
  757. )
  758. privateApiRouter.post(
  759. '/internal/expire-deleted-users-after-duration',
  760. AuthenticationController.requirePrivateApiAuth(),
  761. UserController.expireDeletedUsersAfterDuration
  762. )
  763. privateApiRouter.post(
  764. '/internal/project/:projectId/expire-deleted-project',
  765. AuthenticationController.requirePrivateApiAuth(),
  766. ProjectController.expireDeletedProject
  767. )
  768. privateApiRouter.post(
  769. '/internal/users/:userId/expire',
  770. AuthenticationController.requirePrivateApiAuth(),
  771. UserController.expireDeletedUser
  772. )
  773. privateApiRouter.get(
  774. '/user/:userId/tag',
  775. AuthenticationController.requirePrivateApiAuth(),
  776. TagsController.apiGetAllTags
  777. )
  778. webRouter.get(
  779. '/tag',
  780. AuthenticationController.requireLogin(),
  781. TagsController.getAllTags
  782. )
  783. webRouter.post(
  784. '/tag',
  785. AuthenticationController.requireLogin(),
  786. RateLimiterMiddleware.rateLimit(rateLimiters.createTag),
  787. TagsController.createTag
  788. )
  789. webRouter.post(
  790. '/tag/:tagId/rename',
  791. AuthenticationController.requireLogin(),
  792. RateLimiterMiddleware.rateLimit(rateLimiters.renameTag),
  793. TagsController.renameTag
  794. )
  795. webRouter.post(
  796. '/tag/:tagId/edit',
  797. AuthenticationController.requireLogin(),
  798. RateLimiterMiddleware.rateLimit(rateLimiters.renameTag),
  799. TagsController.editTag
  800. )
  801. webRouter.delete(
  802. '/tag/:tagId',
  803. AuthenticationController.requireLogin(),
  804. RateLimiterMiddleware.rateLimit(rateLimiters.deleteTag),
  805. TagsController.deleteTag
  806. )
  807. webRouter.post(
  808. '/tag/:tagId/project/:projectId',
  809. AuthenticationController.requireLogin(),
  810. RateLimiterMiddleware.rateLimit(rateLimiters.addProjectToTag),
  811. TagsController.addProjectToTag
  812. )
  813. webRouter.post(
  814. '/tag/:tagId/projects',
  815. AuthenticationController.requireLogin(),
  816. RateLimiterMiddleware.rateLimit(rateLimiters.addProjectsToTag),
  817. TagsController.addProjectsToTag
  818. )
  819. webRouter.delete(
  820. '/tag/:tagId/project/:projectId',
  821. AuthenticationController.requireLogin(),
  822. RateLimiterMiddleware.rateLimit(rateLimiters.removeProjectFromTag),
  823. TagsController.removeProjectFromTag
  824. )
  825. webRouter.post(
  826. '/tag/:tagId/projects/remove',
  827. AuthenticationController.requireLogin(),
  828. RateLimiterMiddleware.rateLimit(rateLimiters.removeProjectsFromTag),
  829. TagsController.removeProjectsFromTag
  830. )
  831. webRouter.get(
  832. '/notifications',
  833. AuthenticationController.requireLogin(),
  834. NotificationsController.getAllUnreadNotifications
  835. )
  836. webRouter.delete(
  837. '/notifications/:notificationId',
  838. AuthenticationController.requireLogin(),
  839. NotificationsController.markNotificationAsRead
  840. )
  841. webRouter.get(
  842. '/user/notification/:notificationId',
  843. AuthenticationController.requireLogin(),
  844. NotificationsController.getNotification
  845. )
  846. // Deprecated in favour of /internal/project/:project_id but still used by versioning
  847. privateApiRouter.get(
  848. '/project/:project_id/details',
  849. AuthenticationController.requirePrivateApiAuth(),
  850. ProjectApiController.getProjectDetails
  851. )
  852. // New 'stable' /internal API end points
  853. privateApiRouter.get(
  854. '/internal/project/:project_id',
  855. AuthenticationController.requirePrivateApiAuth(),
  856. ProjectApiController.getProjectDetails
  857. )
  858. privateApiRouter.get(
  859. '/internal/project/:Project_id/zip',
  860. AuthenticationController.requirePrivateApiAuth(),
  861. ProjectDownloadsController.downloadProject
  862. )
  863. privateApiRouter.get(
  864. '/internal/project/:project_id/compile/pdf',
  865. AuthenticationController.requirePrivateApiAuth(),
  866. CompileController.compileAndDownloadPdf
  867. )
  868. privateApiRouter.post(
  869. '/internal/deactivateOldProjects',
  870. AuthenticationController.requirePrivateApiAuth(),
  871. InactiveProjectController.deactivateOldProjects
  872. )
  873. privateApiRouter.post(
  874. '/internal/project/:project_id/deactivate',
  875. AuthenticationController.requirePrivateApiAuth(),
  876. InactiveProjectController.deactivateProject
  877. )
  878. privateApiRouter.get(
  879. '/project/:Project_id/doc/:doc_id',
  880. AuthenticationController.requirePrivateApiAuth(),
  881. DocumentController.getDocument
  882. )
  883. privateApiRouter.post(
  884. '/project/:Project_id/doc/:doc_id',
  885. AuthenticationController.requirePrivateApiAuth(),
  886. DocumentController.setDocument
  887. )
  888. privateApiRouter.post(
  889. '/project/:Project_id/doc/:doc_id/changes/reject',
  890. AuthenticationController.requirePrivateApiAuth(),
  891. DocumentController.trackChangesRejected
  892. )
  893. privateApiRouter.post(
  894. '/user/:user_id/project/new',
  895. AuthenticationController.requirePrivateApiAuth(),
  896. TpdsController.createProject
  897. )
  898. privateApiRouter.post(
  899. '/tpds/folder-update',
  900. AuthenticationController.requirePrivateApiAuth(),
  901. TpdsController.updateFolder
  902. )
  903. privateApiRouter.post(
  904. '/user/:user_id/update/*',
  905. AuthenticationController.requirePrivateApiAuth(),
  906. TpdsController.mergeUpdate
  907. )
  908. privateApiRouter.delete(
  909. '/user/:user_id/update/*',
  910. AuthenticationController.requirePrivateApiAuth(),
  911. TpdsController.deleteUpdate
  912. )
  913. privateApiRouter.post(
  914. '/project/:project_id/user/:user_id/update/*',
  915. AuthenticationController.requirePrivateApiAuth(),
  916. TpdsController.mergeUpdate
  917. )
  918. privateApiRouter.delete(
  919. '/project/:project_id/user/:user_id/update/*',
  920. AuthenticationController.requirePrivateApiAuth(),
  921. TpdsController.deleteUpdate
  922. )
  923. privateApiRouter.post(
  924. '/project/:project_id/contents/*',
  925. AuthenticationController.requirePrivateApiAuth(),
  926. TpdsController.updateProjectContents
  927. )
  928. privateApiRouter.delete(
  929. '/project/:project_id/contents/*',
  930. AuthenticationController.requirePrivateApiAuth(),
  931. TpdsController.deleteProjectContents
  932. )
  933. webRouter.post(
  934. '/spelling/learn',
  935. AuthenticationController.requireLogin(),
  936. SpellingController.learn
  937. )
  938. webRouter.post(
  939. '/spelling/unlearn',
  940. AuthenticationController.requireLogin(),
  941. SpellingController.unlearn
  942. )
  943. if (Features.hasFeature('chat')) {
  944. webRouter.get(
  945. '/project/:project_id/messages',
  946. AuthorizationMiddleware.blockRestrictedUserFromProject,
  947. AuthorizationMiddleware.ensureUserCanReadProject,
  948. PermissionsController.requirePermission('chat'),
  949. ChatController.getMessages
  950. )
  951. webRouter.post(
  952. '/project/:project_id/messages',
  953. AuthorizationMiddleware.blockRestrictedUserFromProject,
  954. AuthorizationMiddleware.ensureUserCanReadProject,
  955. PermissionsController.requirePermission('chat'),
  956. RateLimiterMiddleware.rateLimit(rateLimiters.sendChatMessage),
  957. ChatController.sendMessage
  958. )
  959. webRouter.delete(
  960. '/project/:project_id/messages/:message_id',
  961. AuthorizationMiddleware.blockRestrictedUserFromProject,
  962. AuthorizationMiddleware.ensureUserCanReadProject,
  963. AuthorizationMiddleware.ensureUserIsMessageAuthor,
  964. PermissionsController.requirePermission('chat'),
  965. ChatController.deleteMessage
  966. )
  967. webRouter.post(
  968. '/project/:project_id/messages/:message_id/edit',
  969. AuthorizationMiddleware.blockRestrictedUserFromProject,
  970. AuthorizationMiddleware.ensureUserCanReadProject,
  971. AuthorizationMiddleware.ensureUserIsMessageAuthor,
  972. PermissionsController.requirePermission('chat'),
  973. ChatController.editMessage
  974. )
  975. }
  976. webRouter.post(
  977. '/project/:Project_id/references/indexAll',
  978. AuthorizationMiddleware.ensureUserCanReadProject,
  979. RateLimiterMiddleware.rateLimit(rateLimiters.indexAllProjectReferences),
  980. ReferencesController.indexAll
  981. )
  982. // disable beta program while v2 is in beta
  983. webRouter.get(
  984. '/beta/participate',
  985. AuthenticationController.requireLogin(),
  986. BetaProgramController.optInPage
  987. )
  988. webRouter.post(
  989. '/beta/opt-in',
  990. AuthenticationController.requireLogin(),
  991. BetaProgramController.optIn
  992. )
  993. webRouter.post(
  994. '/beta/opt-out',
  995. AuthenticationController.requireLogin(),
  996. BetaProgramController.optOut
  997. )
  998. webRouter.get('/chrome', function (req, res, next) {
  999. // Match v1 behaviour - this is used for a Chrome web app
  1000. if (SessionManager.isUserLoggedIn(req.session)) {
  1001. res.redirect('/project')
  1002. } else {
  1003. res.redirect('/register')
  1004. }
  1005. })
  1006. webRouter.get(
  1007. '/admin',
  1008. AuthorizationMiddleware.ensureUserIsSiteAdmin,
  1009. AdminController.index
  1010. )
  1011. if (!Features.hasFeature('saas')) {
  1012. webRouter.post(
  1013. '/admin/openEditor',
  1014. AuthorizationMiddleware.ensureUserIsSiteAdmin,
  1015. AdminController.openEditor
  1016. )
  1017. webRouter.post(
  1018. '/admin/closeEditor',
  1019. AuthorizationMiddleware.ensureUserIsSiteAdmin,
  1020. AdminController.closeEditor
  1021. )
  1022. webRouter.post(
  1023. '/admin/disconnectAllUsers',
  1024. AuthorizationMiddleware.ensureUserIsSiteAdmin,
  1025. AdminController.disconnectAllUsers
  1026. )
  1027. }
  1028. webRouter.post(
  1029. '/admin/flushProjectToTpds',
  1030. AuthorizationMiddleware.ensureUserIsSiteAdmin,
  1031. AdminController.flushProjectToTpds
  1032. )
  1033. webRouter.post(
  1034. '/admin/pollDropboxForUser',
  1035. AuthorizationMiddleware.ensureUserIsSiteAdmin,
  1036. AdminController.pollDropboxForUser
  1037. )
  1038. webRouter.post(
  1039. '/admin/messages',
  1040. AuthorizationMiddleware.ensureUserIsSiteAdmin,
  1041. AdminController.createMessage
  1042. )
  1043. webRouter.post(
  1044. '/admin/messages/clear',
  1045. AuthorizationMiddleware.ensureUserIsSiteAdmin,
  1046. AdminController.clearMessages
  1047. )
  1048. privateApiRouter.get('/perfTest', (req, res) => {
  1049. plainTextResponse(res, 'hello')
  1050. })
  1051. publicApiRouter.get('/status', (req, res) => {
  1052. if (Settings.shuttingDown) {
  1053. res.sendStatus(503) // Service unavailable
  1054. } else if (!Settings.siteIsOpen) {
  1055. plainTextResponse(res, 'web site is closed (web)')
  1056. } else if (!Settings.editorIsOpen) {
  1057. plainTextResponse(res, 'web editor is closed (web)')
  1058. } else {
  1059. plainTextResponse(res, 'web is alive (web)')
  1060. }
  1061. })
  1062. privateApiRouter.get('/status', (req, res) => {
  1063. plainTextResponse(res, 'web is alive (api)')
  1064. })
  1065. // used by kubernetes health-check and acceptance tests
  1066. webRouter.get('/dev/csrf', (req, res) => {
  1067. plainTextResponse(res, res.locals.csrfToken)
  1068. })
  1069. privateApiRouter.get(
  1070. '/health_check',
  1071. HealthCheckController.checkActiveHandles,
  1072. HealthCheckController.checkApi
  1073. )
  1074. publicApiRouter.get(
  1075. '/health_check/api',
  1076. HealthCheckController.checkActiveHandles,
  1077. HealthCheckController.checkApi
  1078. )
  1079. privateApiRouter.get(
  1080. '/health_check/api',
  1081. HealthCheckController.checkActiveHandles,
  1082. HealthCheckController.checkApi
  1083. )
  1084. publicApiRouter.get('/health_check/redis', HealthCheckController.checkRedis)
  1085. privateApiRouter.get('/health_check/redis', HealthCheckController.checkRedis)
  1086. publicApiRouter.get('/health_check/mongo', HealthCheckController.checkMongo)
  1087. privateApiRouter.get('/health_check/mongo', HealthCheckController.checkMongo)
  1088. webRouter.get(
  1089. '/status/compiler/:Project_id',
  1090. RateLimiterMiddleware.rateLimit(rateLimiters.statusCompiler),
  1091. AuthorizationMiddleware.ensureUserCanReadProject,
  1092. function (req, res) {
  1093. const projectId = req.params.Project_id
  1094. // use a valid user id for testing
  1095. const testUserId = '123456789012345678901234'
  1096. const sendRes = _.once(function (statusCode, message, clsiServerId) {
  1097. res.status(statusCode)
  1098. plainTextResponse(res, message)
  1099. // Force every compile to a new server and do not leave cruft behind.
  1100. CompileManager.promises
  1101. .deleteAuxFiles(projectId, testUserId, clsiServerId)
  1102. .catch(() => {})
  1103. })
  1104. let handler = setTimeout(function () {
  1105. CompileManager.promises
  1106. .stopCompile(projectId, testUserId)
  1107. .catch(() => {})
  1108. sendRes(500, 'Compiler timed out')
  1109. handler = null
  1110. }, 10000)
  1111. CompileManager.compile(
  1112. projectId,
  1113. testUserId,
  1114. {
  1115. metricsPath: 'health-check',
  1116. compileFromHistory: true,
  1117. rootResourcePath: 'main.tex',
  1118. },
  1119. function (error, status, _outputFiles, clsiServerId) {
  1120. if (handler) {
  1121. clearTimeout(handler)
  1122. }
  1123. if (error) {
  1124. sendRes(
  1125. 500,
  1126. `Compiler returned error ${error.message}`,
  1127. clsiServerId
  1128. )
  1129. } else if (status === 'success') {
  1130. sendRes(
  1131. 200,
  1132. 'Compiler returned in less than 10 seconds',
  1133. clsiServerId
  1134. )
  1135. } else {
  1136. sendRes(500, `Compiler returned failure ${status}`, clsiServerId)
  1137. }
  1138. }
  1139. )
  1140. }
  1141. )
  1142. webRouter.post('/error/client', function (req, res, next) {
  1143. logger.warn(
  1144. { err: req.body.error, meta: req.body.meta },
  1145. 'client side error'
  1146. )
  1147. metrics.inc('client-side-error')
  1148. res.sendStatus(204)
  1149. })
  1150. if (Features.hasFeature('link-sharing')) {
  1151. webRouter.get(
  1152. `/read/:token(${TokenAccessController.READ_ONLY_TOKEN_PATTERN})`,
  1153. RateLimiterMiddleware.rateLimit(rateLimiters.readOnlyToken),
  1154. AnalyticsRegistrationSourceMiddleware.setSource(
  1155. 'collaboration',
  1156. 'link-sharing'
  1157. ),
  1158. TokenAccessController.tokenAccessPage,
  1159. AnalyticsRegistrationSourceMiddleware.clearSource()
  1160. )
  1161. webRouter.get(
  1162. `/:token(${TokenAccessController.READ_AND_WRITE_TOKEN_PATTERN})`,
  1163. RateLimiterMiddleware.rateLimit(rateLimiters.readAndWriteToken),
  1164. AnalyticsRegistrationSourceMiddleware.setSource(
  1165. 'collaboration',
  1166. 'link-sharing'
  1167. ),
  1168. TokenAccessController.tokenAccessPage,
  1169. AnalyticsRegistrationSourceMiddleware.clearSource()
  1170. )
  1171. webRouter.post(
  1172. `/:token(${TokenAccessController.READ_AND_WRITE_TOKEN_PATTERN})/grant`,
  1173. RateLimiterMiddleware.rateLimit(rateLimiters.grantTokenAccessReadWrite),
  1174. TokenAccessController.grantTokenAccessReadAndWrite
  1175. )
  1176. webRouter.post(
  1177. `/read/:token(${TokenAccessController.READ_ONLY_TOKEN_PATTERN})/grant`,
  1178. RateLimiterMiddleware.rateLimit(rateLimiters.grantTokenAccessReadOnly),
  1179. TokenAccessController.grantTokenAccessReadOnly
  1180. )
  1181. }
  1182. webRouter.get('/unsupported-browser', renderUnsupportedBrowserPage)
  1183. webRouter.get('*', ErrorController.notFound)
  1184. }
  1185. export default { initialize, rateLimiters }