router.mjs 44 KB

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