router.mjs 40 KB

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