router.mjs 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381
  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. FileStoreController.getFileHead
  508. )
  509. webRouter.get(
  510. '/Project/:Project_id/file/:File_id',
  511. AuthorizationMiddleware.ensureUserCanReadProject,
  512. FileStoreController.getFile
  513. )
  514. webRouter.get(
  515. '/Project/:Project_id/doc/:Doc_id/download', // "download" suffix to avoid conflict with private API route at doc/:doc_id
  516. AuthorizationMiddleware.ensureUserCanReadProject,
  517. DocumentUpdaterController.getDoc
  518. )
  519. webRouter.post(
  520. '/project/:Project_id/settings',
  521. validate({
  522. body: Joi.object({
  523. publicAccessLevel: Joi.string()
  524. .valid(PublicAccessLevels.PRIVATE, PublicAccessLevels.TOKEN_BASED)
  525. .optional(),
  526. }),
  527. }),
  528. AuthorizationMiddleware.ensureUserCanWriteProjectSettings,
  529. ProjectController.updateProjectSettings
  530. )
  531. webRouter.post(
  532. '/project/:Project_id/settings/admin',
  533. AuthenticationController.requireLogin(),
  534. AuthorizationMiddleware.ensureUserCanAdminProject,
  535. ProjectController.updateProjectAdminSettings
  536. )
  537. webRouter.post(
  538. '/project/:Project_id/compile',
  539. RateLimiterMiddleware.rateLimit(rateLimiters.compileProjectHttp, {
  540. params: ['Project_id'],
  541. }),
  542. AuthorizationMiddleware.ensureUserCanReadProject,
  543. CompileController.compile
  544. )
  545. webRouter.post(
  546. '/project/:Project_id/compile/stop',
  547. AuthorizationMiddleware.ensureUserCanReadProject,
  548. CompileController.stopCompile
  549. )
  550. // LEGACY: Used by the web download buttons, adds filename header, TODO: remove at some future date
  551. webRouter.get(
  552. '/project/:Project_id/output/output.pdf',
  553. AuthorizationMiddleware.ensureUserCanReadProject,
  554. CompileController.downloadPdf
  555. )
  556. // PDF Download button
  557. webRouter.get(
  558. /^\/download\/project\/([^/]*)\/output\/output\.pdf$/,
  559. function (req, res, next) {
  560. const params = { Project_id: req.params[0] }
  561. req.params = params
  562. next()
  563. },
  564. AuthorizationMiddleware.ensureUserCanReadProject,
  565. CompileController.downloadPdf
  566. )
  567. // PDF Download button for specific build
  568. webRouter.get(
  569. /^\/download\/project\/([^/]*)\/build\/([0-9a-f-]+)\/output\/output\.pdf$/,
  570. function (req, res, next) {
  571. const params = {
  572. Project_id: req.params[0],
  573. build_id: req.params[1],
  574. }
  575. req.params = params
  576. next()
  577. },
  578. AuthorizationMiddleware.ensureUserCanReadProject,
  579. CompileController.downloadPdf
  580. )
  581. // Align with limits defined in CompileController.downloadPdf
  582. const rateLimiterMiddlewareOutputFiles = RateLimiterMiddleware.rateLimit(
  583. rateLimiters.miscOutputDownload,
  584. { params: ['Project_id'] }
  585. )
  586. // Used by the pdf viewers
  587. webRouter.get(
  588. /^\/project\/([^/]*)\/output\/(.*)$/,
  589. function (req, res, next) {
  590. const params = {
  591. Project_id: req.params[0],
  592. file: req.params[1],
  593. }
  594. req.params = params
  595. next()
  596. },
  597. rateLimiterMiddlewareOutputFiles,
  598. AuthorizationMiddleware.ensureUserCanReadProject,
  599. CompileController.getFileFromClsi
  600. )
  601. // direct url access to output files for a specific build (query string not required)
  602. webRouter.get(
  603. /^\/project\/([^/]*)\/build\/([0-9a-f-]+)\/output\/(.*)$/,
  604. function (req, res, next) {
  605. const params = {
  606. Project_id: req.params[0],
  607. build_id: req.params[1],
  608. file: req.params[2],
  609. }
  610. req.params = params
  611. next()
  612. },
  613. rateLimiterMiddlewareOutputFiles,
  614. AuthorizationMiddleware.ensureUserCanReadProject,
  615. CompileController.getFileFromClsi
  616. )
  617. // direct url access to output files for user but no build, to retrieve files when build fails
  618. webRouter.get(
  619. /^\/project\/([^/]*)\/user\/([0-9a-f-]+)\/output\/(.*)$/,
  620. function (req, res, next) {
  621. const params = {
  622. Project_id: req.params[0],
  623. user_id: req.params[1],
  624. file: req.params[2],
  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 user and build (query string not required)
  634. webRouter.get(
  635. /^\/project\/([^/]*)\/user\/([0-9a-f]+)\/build\/([0-9a-f-]+)\/output\/(.*)$/,
  636. function (req, res, next) {
  637. const params = {
  638. Project_id: req.params[0],
  639. user_id: req.params[1],
  640. build_id: req.params[2],
  641. file: req.params[3],
  642. }
  643. req.params = params
  644. next()
  645. },
  646. rateLimiterMiddlewareOutputFiles,
  647. AuthorizationMiddleware.ensureUserCanReadProject,
  648. CompileController.getFileFromClsi
  649. )
  650. webRouter.delete(
  651. '/project/:Project_id/output',
  652. validate({ query: { clsiserverid: Joi.string() } }),
  653. AuthorizationMiddleware.ensureUserCanReadProject,
  654. CompileController.deleteAuxFiles
  655. )
  656. webRouter.get(
  657. '/project/:Project_id/sync/code',
  658. AuthorizationMiddleware.ensureUserCanReadProject,
  659. CompileController.proxySyncCode
  660. )
  661. webRouter.get(
  662. '/project/:Project_id/sync/pdf',
  663. AuthorizationMiddleware.ensureUserCanReadProject,
  664. CompileController.proxySyncPdf
  665. )
  666. webRouter.get(
  667. '/project/:Project_id/wordcount',
  668. validate({ query: { clsiserverid: Joi.string() } }),
  669. AuthorizationMiddleware.ensureUserCanReadProject,
  670. CompileController.wordCount
  671. )
  672. webRouter.post(
  673. '/Project/:Project_id/archive',
  674. AuthenticationController.requireLogin(),
  675. AuthorizationMiddleware.ensureUserCanReadProject,
  676. ProjectController.archiveProject
  677. )
  678. webRouter.delete(
  679. '/Project/:Project_id/archive',
  680. AuthenticationController.requireLogin(),
  681. AuthorizationMiddleware.ensureUserCanReadProject,
  682. ProjectController.unarchiveProject
  683. )
  684. webRouter.post(
  685. '/project/:project_id/trash',
  686. AuthenticationController.requireLogin(),
  687. AuthorizationMiddleware.ensureUserCanReadProject,
  688. ProjectController.trashProject
  689. )
  690. webRouter.delete(
  691. '/project/:project_id/trash',
  692. AuthenticationController.requireLogin(),
  693. AuthorizationMiddleware.ensureUserCanReadProject,
  694. ProjectController.untrashProject
  695. )
  696. webRouter.delete(
  697. '/Project/:Project_id',
  698. AuthenticationController.requireLogin(),
  699. AuthorizationMiddleware.ensureUserCanAdminProject,
  700. ProjectController.deleteProject
  701. )
  702. webRouter.post(
  703. '/Project/:Project_id/restore',
  704. AuthenticationController.requireLogin(),
  705. AuthorizationMiddleware.ensureUserCanAdminProject,
  706. ProjectController.restoreProject
  707. )
  708. webRouter.post(
  709. '/Project/:Project_id/clone',
  710. AuthorizationMiddleware.ensureUserCanReadProject,
  711. ProjectController.cloneProject
  712. )
  713. webRouter.post(
  714. '/project/:Project_id/rename',
  715. AuthenticationController.requireLogin(),
  716. AuthorizationMiddleware.ensureUserCanAdminProject,
  717. ProjectController.renameProject
  718. )
  719. webRouter.get(
  720. '/project/:Project_id/updates',
  721. AuthorizationMiddleware.blockRestrictedUserFromProject,
  722. AuthorizationMiddleware.ensureUserCanReadProject,
  723. HistoryController.proxyToHistoryApiAndInjectUserDetails
  724. )
  725. webRouter.get(
  726. '/project/:Project_id/doc/:doc_id/diff',
  727. AuthorizationMiddleware.blockRestrictedUserFromProject,
  728. AuthorizationMiddleware.ensureUserCanReadProject,
  729. HistoryController.proxyToHistoryApi
  730. )
  731. webRouter.get(
  732. '/project/:Project_id/diff',
  733. AuthorizationMiddleware.blockRestrictedUserFromProject,
  734. AuthorizationMiddleware.ensureUserCanReadProject,
  735. HistoryController.proxyToHistoryApiAndInjectUserDetails
  736. )
  737. webRouter.get(
  738. '/project/:Project_id/filetree/diff',
  739. AuthorizationMiddleware.blockRestrictedUserFromProject,
  740. AuthorizationMiddleware.ensureUserCanReadProject,
  741. HistoryController.proxyToHistoryApi
  742. )
  743. webRouter.post(
  744. '/project/:project_id/restore_file',
  745. AuthorizationMiddleware.ensureUserCanWriteProjectContent,
  746. HistoryController.restoreFileFromV2
  747. )
  748. webRouter.post(
  749. '/project/:project_id/revert_file',
  750. AuthorizationMiddleware.ensureUserCanWriteProjectContent,
  751. HistoryController.revertFile
  752. )
  753. webRouter.post(
  754. '/project/:project_id/revert-project',
  755. AuthorizationMiddleware.ensureUserCanWriteProjectContent,
  756. HistoryController.revertProject
  757. )
  758. webRouter.get(
  759. '/project/:project_id/version/:version/zip',
  760. RateLimiterMiddleware.rateLimit(rateLimiters.downloadProjectRevision),
  761. AuthorizationMiddleware.blockRestrictedUserFromProject,
  762. AuthorizationMiddleware.ensureUserCanReadProject,
  763. HistoryController.downloadZipOfVersion
  764. )
  765. privateApiRouter.post(
  766. '/project/:Project_id/history/resync',
  767. AuthenticationController.requirePrivateApiAuth(),
  768. HistoryController.resyncProjectHistory
  769. )
  770. webRouter.get(
  771. '/project/:Project_id/labels',
  772. AuthorizationMiddleware.blockRestrictedUserFromProject,
  773. AuthorizationMiddleware.ensureUserCanReadProject,
  774. HistoryController.getLabels
  775. )
  776. webRouter.post(
  777. '/project/:Project_id/labels',
  778. AuthorizationMiddleware.ensureUserCanWriteProjectContent,
  779. HistoryController.createLabel
  780. )
  781. webRouter.delete(
  782. '/project/:Project_id/labels/:label_id',
  783. AuthorizationMiddleware.ensureUserCanWriteProjectContent,
  784. HistoryController.deleteLabel
  785. )
  786. webRouter.post(
  787. '/project/:project_id/export/:brand_variation_id',
  788. AuthorizationMiddleware.ensureUserCanWriteProjectContent,
  789. ExportsController.exportProject
  790. )
  791. webRouter.get(
  792. '/project/:project_id/export/:export_id',
  793. AuthorizationMiddleware.ensureUserCanWriteProjectContent,
  794. ExportsController.exportStatus
  795. )
  796. webRouter.get(
  797. '/project/:project_id/export/:export_id/:type',
  798. AuthorizationMiddleware.ensureUserCanWriteProjectContent,
  799. ExportsController.exportDownload
  800. )
  801. webRouter.get(
  802. '/Project/:Project_id/download/zip',
  803. RateLimiterMiddleware.rateLimit(rateLimiters.zipDownload, {
  804. params: ['Project_id'],
  805. }),
  806. AuthorizationMiddleware.ensureUserCanReadProject,
  807. ProjectDownloadsController.downloadProject
  808. )
  809. webRouter.get(
  810. '/project/download/zip',
  811. AuthenticationController.requireLogin(),
  812. RateLimiterMiddleware.rateLimit(rateLimiters.multipleProjectsZipDownload),
  813. AuthorizationMiddleware.ensureUserCanReadMultipleProjects,
  814. ProjectDownloadsController.downloadMultipleProjects
  815. )
  816. webRouter.get(
  817. '/project/:project_id/metadata',
  818. AuthorizationMiddleware.ensureUserCanReadProject,
  819. Settings.allowAnonymousReadAndWriteSharing
  820. ? (req, res, next) => {
  821. next()
  822. }
  823. : AuthenticationController.requireLogin(),
  824. MetaController.getMetadata
  825. )
  826. webRouter.post(
  827. '/project/:project_id/doc/:doc_id/metadata',
  828. AuthorizationMiddleware.ensureUserCanReadProject,
  829. Settings.allowAnonymousReadAndWriteSharing
  830. ? (req, res, next) => {
  831. next()
  832. }
  833. : AuthenticationController.requireLogin(),
  834. MetaController.broadcastMetadataForDoc
  835. )
  836. privateApiRouter.post(
  837. '/internal/expire-deleted-projects-after-duration',
  838. AuthenticationController.requirePrivateApiAuth(),
  839. ProjectController.expireDeletedProjectsAfterDuration
  840. )
  841. privateApiRouter.post(
  842. '/internal/expire-deleted-users-after-duration',
  843. AuthenticationController.requirePrivateApiAuth(),
  844. UserController.expireDeletedUsersAfterDuration
  845. )
  846. privateApiRouter.post(
  847. '/internal/project/:projectId/expire-deleted-project',
  848. AuthenticationController.requirePrivateApiAuth(),
  849. ProjectController.expireDeletedProject
  850. )
  851. privateApiRouter.post(
  852. '/internal/users/:userId/expire',
  853. AuthenticationController.requirePrivateApiAuth(),
  854. UserController.expireDeletedUser
  855. )
  856. privateApiRouter.get(
  857. '/user/:userId/tag',
  858. AuthenticationController.requirePrivateApiAuth(),
  859. TagsController.apiGetAllTags
  860. )
  861. webRouter.get(
  862. '/tag',
  863. AuthenticationController.requireLogin(),
  864. TagsController.getAllTags
  865. )
  866. webRouter.post(
  867. '/tag',
  868. AuthenticationController.requireLogin(),
  869. RateLimiterMiddleware.rateLimit(rateLimiters.createTag),
  870. validate({
  871. body: Joi.object({
  872. name: Joi.string().required(),
  873. color: Joi.string(),
  874. }),
  875. }),
  876. TagsController.createTag
  877. )
  878. webRouter.post(
  879. '/tag/:tagId/rename',
  880. AuthenticationController.requireLogin(),
  881. RateLimiterMiddleware.rateLimit(rateLimiters.renameTag),
  882. validate({
  883. body: Joi.object({
  884. name: Joi.string().required(),
  885. }),
  886. }),
  887. TagsController.renameTag
  888. )
  889. webRouter.post(
  890. '/tag/:tagId/edit',
  891. AuthenticationController.requireLogin(),
  892. RateLimiterMiddleware.rateLimit(rateLimiters.renameTag),
  893. validate({
  894. body: Joi.object({
  895. name: Joi.string().required(),
  896. color: Joi.string(),
  897. }),
  898. }),
  899. TagsController.editTag
  900. )
  901. webRouter.delete(
  902. '/tag/:tagId',
  903. AuthenticationController.requireLogin(),
  904. RateLimiterMiddleware.rateLimit(rateLimiters.deleteTag),
  905. TagsController.deleteTag
  906. )
  907. webRouter.post(
  908. '/tag/:tagId/project/:projectId',
  909. AuthenticationController.requireLogin(),
  910. RateLimiterMiddleware.rateLimit(rateLimiters.addProjectToTag),
  911. TagsController.addProjectToTag
  912. )
  913. webRouter.post(
  914. '/tag/:tagId/projects',
  915. AuthenticationController.requireLogin(),
  916. RateLimiterMiddleware.rateLimit(rateLimiters.addProjectsToTag),
  917. validate({
  918. body: Joi.object({
  919. projectIds: Joi.array().items(Joi.string()).required(),
  920. }),
  921. }),
  922. TagsController.addProjectsToTag
  923. )
  924. webRouter.delete(
  925. '/tag/:tagId/project/:projectId',
  926. AuthenticationController.requireLogin(),
  927. RateLimiterMiddleware.rateLimit(rateLimiters.removeProjectFromTag),
  928. TagsController.removeProjectFromTag
  929. )
  930. webRouter.post(
  931. '/tag/:tagId/projects/remove',
  932. AuthenticationController.requireLogin(),
  933. RateLimiterMiddleware.rateLimit(rateLimiters.removeProjectsFromTag),
  934. validate({
  935. body: Joi.object({
  936. projectIds: Joi.array().items(Joi.string()).required(),
  937. }),
  938. }),
  939. TagsController.removeProjectsFromTag
  940. )
  941. webRouter.get(
  942. '/notifications',
  943. AuthenticationController.requireLogin(),
  944. NotificationsController.getAllUnreadNotifications
  945. )
  946. webRouter.delete(
  947. '/notifications/:notificationId',
  948. AuthenticationController.requireLogin(),
  949. NotificationsController.markNotificationAsRead
  950. )
  951. // Deprecated in favour of /internal/project/:project_id but still used by versioning
  952. privateApiRouter.get(
  953. '/project/:project_id/details',
  954. AuthenticationController.requirePrivateApiAuth(),
  955. ProjectApiController.getProjectDetails
  956. )
  957. // New 'stable' /internal API end points
  958. privateApiRouter.get(
  959. '/internal/project/:project_id',
  960. AuthenticationController.requirePrivateApiAuth(),
  961. ProjectApiController.getProjectDetails
  962. )
  963. privateApiRouter.get(
  964. '/internal/project/:Project_id/zip',
  965. AuthenticationController.requirePrivateApiAuth(),
  966. ProjectDownloadsController.downloadProject
  967. )
  968. privateApiRouter.get(
  969. '/internal/project/:project_id/compile/pdf',
  970. AuthenticationController.requirePrivateApiAuth(),
  971. CompileController.compileAndDownloadPdf
  972. )
  973. privateApiRouter.post(
  974. '/internal/deactivateOldProjects',
  975. AuthenticationController.requirePrivateApiAuth(),
  976. InactiveProjectController.deactivateOldProjects
  977. )
  978. privateApiRouter.post(
  979. '/internal/project/:project_id/deactivate',
  980. AuthenticationController.requirePrivateApiAuth(),
  981. InactiveProjectController.deactivateProject
  982. )
  983. privateApiRouter.get(
  984. /^\/internal\/project\/([^/]*)\/output\/(.*)$/,
  985. function (req, res, next) {
  986. const params = {
  987. Project_id: req.params[0],
  988. file: req.params[1],
  989. }
  990. req.params = params
  991. next()
  992. },
  993. AuthenticationController.requirePrivateApiAuth(),
  994. CompileController.getFileFromClsi
  995. )
  996. privateApiRouter.get(
  997. '/project/:Project_id/doc/:doc_id',
  998. AuthenticationController.requirePrivateApiAuth(),
  999. DocumentController.getDocument
  1000. )
  1001. privateApiRouter.post(
  1002. '/project/:Project_id/doc/:doc_id',
  1003. AuthenticationController.requirePrivateApiAuth(),
  1004. DocumentController.setDocument
  1005. )
  1006. privateApiRouter.post(
  1007. '/user/:user_id/project/new',
  1008. AuthenticationController.requirePrivateApiAuth(),
  1009. TpdsController.createProject
  1010. )
  1011. privateApiRouter.post(
  1012. '/tpds/folder-update',
  1013. AuthenticationController.requirePrivateApiAuth(),
  1014. TpdsController.updateFolder
  1015. )
  1016. privateApiRouter.post(
  1017. '/user/:user_id/update/*',
  1018. AuthenticationController.requirePrivateApiAuth(),
  1019. TpdsController.mergeUpdate
  1020. )
  1021. privateApiRouter.delete(
  1022. '/user/:user_id/update/*',
  1023. AuthenticationController.requirePrivateApiAuth(),
  1024. TpdsController.deleteUpdate
  1025. )
  1026. privateApiRouter.post(
  1027. '/project/:project_id/user/:user_id/update/*',
  1028. AuthenticationController.requirePrivateApiAuth(),
  1029. TpdsController.mergeUpdate
  1030. )
  1031. privateApiRouter.delete(
  1032. '/project/:project_id/user/:user_id/update/*',
  1033. AuthenticationController.requirePrivateApiAuth(),
  1034. TpdsController.deleteUpdate
  1035. )
  1036. privateApiRouter.post(
  1037. '/project/:project_id/contents/*',
  1038. AuthenticationController.requirePrivateApiAuth(),
  1039. TpdsController.updateProjectContents
  1040. )
  1041. privateApiRouter.delete(
  1042. '/project/:project_id/contents/*',
  1043. AuthenticationController.requirePrivateApiAuth(),
  1044. TpdsController.deleteProjectContents
  1045. )
  1046. webRouter.post(
  1047. '/spelling/check',
  1048. AuthenticationController.requireLogin(),
  1049. SpellingController.proxyCheckRequestToSpellingApi
  1050. )
  1051. webRouter.post(
  1052. '/spelling/learn',
  1053. validate({
  1054. body: Joi.object({
  1055. word: Joi.string().required(),
  1056. }),
  1057. }),
  1058. AuthenticationController.requireLogin(),
  1059. SpellingController.learn
  1060. )
  1061. webRouter.post(
  1062. '/spelling/unlearn',
  1063. validate({
  1064. body: Joi.object({
  1065. word: Joi.string().required(),
  1066. }),
  1067. }),
  1068. AuthenticationController.requireLogin(),
  1069. SpellingController.unlearn
  1070. )
  1071. if (Features.hasFeature('chat')) {
  1072. webRouter.get(
  1073. '/project/:project_id/messages',
  1074. AuthorizationMiddleware.blockRestrictedUserFromProject,
  1075. AuthorizationMiddleware.ensureUserCanReadProject,
  1076. ChatController.getMessages
  1077. )
  1078. webRouter.post(
  1079. '/project/:project_id/messages',
  1080. AuthorizationMiddleware.blockRestrictedUserFromProject,
  1081. AuthorizationMiddleware.ensureUserCanReadProject,
  1082. RateLimiterMiddleware.rateLimit(rateLimiters.sendChatMessage),
  1083. ChatController.sendMessage
  1084. )
  1085. }
  1086. webRouter.post(
  1087. '/project/:Project_id/references/indexAll',
  1088. AuthorizationMiddleware.ensureUserCanReadProject,
  1089. RateLimiterMiddleware.rateLimit(rateLimiters.indexAllProjectReferences),
  1090. ReferencesController.indexAll
  1091. )
  1092. // disable beta program while v2 is in beta
  1093. webRouter.get(
  1094. '/beta/participate',
  1095. AuthenticationController.requireLogin(),
  1096. BetaProgramController.optInPage
  1097. )
  1098. webRouter.post(
  1099. '/beta/opt-in',
  1100. AuthenticationController.requireLogin(),
  1101. BetaProgramController.optIn
  1102. )
  1103. webRouter.post(
  1104. '/beta/opt-out',
  1105. AuthenticationController.requireLogin(),
  1106. BetaProgramController.optOut
  1107. )
  1108. webRouter.get('/chrome', function (req, res, next) {
  1109. // Match v1 behaviour - this is used for a Chrome web app
  1110. if (SessionManager.isUserLoggedIn(req.session)) {
  1111. res.redirect('/project')
  1112. } else {
  1113. res.redirect('/register')
  1114. }
  1115. })
  1116. webRouter.get(
  1117. '/admin',
  1118. AuthorizationMiddleware.ensureUserIsSiteAdmin,
  1119. AdminController.index
  1120. )
  1121. if (!Features.hasFeature('saas')) {
  1122. webRouter.post(
  1123. '/admin/openEditor',
  1124. AuthorizationMiddleware.ensureUserIsSiteAdmin,
  1125. AdminController.openEditor
  1126. )
  1127. webRouter.post(
  1128. '/admin/closeEditor',
  1129. AuthorizationMiddleware.ensureUserIsSiteAdmin,
  1130. AdminController.closeEditor
  1131. )
  1132. webRouter.post(
  1133. '/admin/disconnectAllUsers',
  1134. AuthorizationMiddleware.ensureUserIsSiteAdmin,
  1135. AdminController.disconnectAllUsers
  1136. )
  1137. }
  1138. webRouter.post(
  1139. '/admin/flushProjectToTpds',
  1140. AuthorizationMiddleware.ensureUserIsSiteAdmin,
  1141. AdminController.flushProjectToTpds
  1142. )
  1143. webRouter.post(
  1144. '/admin/pollDropboxForUser',
  1145. AuthorizationMiddleware.ensureUserIsSiteAdmin,
  1146. AdminController.pollDropboxForUser
  1147. )
  1148. webRouter.post(
  1149. '/admin/messages',
  1150. AuthorizationMiddleware.ensureUserIsSiteAdmin,
  1151. AdminController.createMessage
  1152. )
  1153. webRouter.post(
  1154. '/admin/messages/clear',
  1155. AuthorizationMiddleware.ensureUserIsSiteAdmin,
  1156. AdminController.clearMessages
  1157. )
  1158. privateApiRouter.get('/perfTest', (req, res) => {
  1159. plainTextResponse(res, 'hello')
  1160. })
  1161. publicApiRouter.get('/status', (req, res) => {
  1162. if (Settings.shuttingDown) {
  1163. res.sendStatus(503) // Service unavailable
  1164. } else if (!Settings.siteIsOpen) {
  1165. plainTextResponse(res, 'web site is closed (web)')
  1166. } else if (!Settings.editorIsOpen) {
  1167. plainTextResponse(res, 'web editor is closed (web)')
  1168. } else {
  1169. plainTextResponse(res, 'web is alive (web)')
  1170. }
  1171. })
  1172. privateApiRouter.get('/status', (req, res) => {
  1173. plainTextResponse(res, 'web is alive (api)')
  1174. })
  1175. // used by kubernetes health-check and acceptance tests
  1176. webRouter.get('/dev/csrf', (req, res) => {
  1177. plainTextResponse(res, res.locals.csrfToken)
  1178. })
  1179. publicApiRouter.get(
  1180. '/health_check',
  1181. HealthCheckController.checkActiveHandles,
  1182. HealthCheckController.check
  1183. )
  1184. privateApiRouter.get(
  1185. '/health_check',
  1186. HealthCheckController.checkActiveHandles,
  1187. HealthCheckController.checkApi
  1188. )
  1189. publicApiRouter.get(
  1190. '/health_check/api',
  1191. HealthCheckController.checkActiveHandles,
  1192. HealthCheckController.checkApi
  1193. )
  1194. privateApiRouter.get(
  1195. '/health_check/api',
  1196. HealthCheckController.checkActiveHandles,
  1197. HealthCheckController.checkApi
  1198. )
  1199. publicApiRouter.get(
  1200. '/health_check/full',
  1201. HealthCheckController.checkActiveHandles,
  1202. HealthCheckController.check
  1203. )
  1204. privateApiRouter.get(
  1205. '/health_check/full',
  1206. HealthCheckController.checkActiveHandles,
  1207. HealthCheckController.check
  1208. )
  1209. publicApiRouter.get('/health_check/redis', HealthCheckController.checkRedis)
  1210. privateApiRouter.get('/health_check/redis', HealthCheckController.checkRedis)
  1211. publicApiRouter.get('/health_check/mongo', HealthCheckController.checkMongo)
  1212. privateApiRouter.get('/health_check/mongo', HealthCheckController.checkMongo)
  1213. webRouter.get(
  1214. '/status/compiler/:Project_id',
  1215. RateLimiterMiddleware.rateLimit(rateLimiters.statusCompiler),
  1216. AuthorizationMiddleware.ensureUserCanReadProject,
  1217. function (req, res) {
  1218. const projectId = req.params.Project_id
  1219. // use a valid user id for testing
  1220. const testUserId = '123456789012345678901234'
  1221. const sendRes = _.once(function (statusCode, message) {
  1222. res.status(statusCode)
  1223. plainTextResponse(res, message)
  1224. ClsiCookieManager.clearServerId(projectId, testUserId, () => {})
  1225. }) // force every compile to a new server
  1226. // set a timeout
  1227. let handler = setTimeout(function () {
  1228. sendRes(500, 'Compiler timed out')
  1229. handler = null
  1230. }, 10000)
  1231. // run the compile
  1232. CompileManager.compile(
  1233. projectId,
  1234. testUserId,
  1235. {},
  1236. function (error, status) {
  1237. if (handler) {
  1238. clearTimeout(handler)
  1239. }
  1240. if (error) {
  1241. sendRes(500, `Compiler returned error ${error.message}`)
  1242. } else if (status === 'success') {
  1243. sendRes(200, 'Compiler returned in less than 10 seconds')
  1244. } else {
  1245. sendRes(500, `Compiler returned failure ${status}`)
  1246. }
  1247. }
  1248. )
  1249. }
  1250. )
  1251. webRouter.post('/error/client', function (req, res, next) {
  1252. logger.warn(
  1253. { err: req.body.error, meta: req.body.meta },
  1254. 'client side error'
  1255. )
  1256. metrics.inc('client-side-error')
  1257. res.sendStatus(204)
  1258. })
  1259. webRouter.get(
  1260. `/read/:token(${TokenAccessController.READ_ONLY_TOKEN_PATTERN})`,
  1261. RateLimiterMiddleware.rateLimit(rateLimiters.readOnlyToken),
  1262. AnalyticsRegistrationSourceMiddleware.setSource(
  1263. 'collaboration',
  1264. 'link-sharing'
  1265. ),
  1266. TokenAccessController.tokenAccessPage,
  1267. AnalyticsRegistrationSourceMiddleware.clearSource()
  1268. )
  1269. webRouter.get(
  1270. `/:token(${TokenAccessController.READ_AND_WRITE_TOKEN_PATTERN})`,
  1271. RateLimiterMiddleware.rateLimit(rateLimiters.readAndWriteToken),
  1272. AnalyticsRegistrationSourceMiddleware.setSource(
  1273. 'collaboration',
  1274. 'link-sharing'
  1275. ),
  1276. TokenAccessController.tokenAccessPage,
  1277. AnalyticsRegistrationSourceMiddleware.clearSource()
  1278. )
  1279. webRouter.post(
  1280. `/:token(${TokenAccessController.READ_AND_WRITE_TOKEN_PATTERN})/grant`,
  1281. RateLimiterMiddleware.rateLimit(rateLimiters.grantTokenAccessReadWrite),
  1282. TokenAccessController.grantTokenAccessReadAndWrite
  1283. )
  1284. webRouter.post(
  1285. `/read/:token(${TokenAccessController.READ_ONLY_TOKEN_PATTERN})/grant`,
  1286. RateLimiterMiddleware.rateLimit(rateLimiters.grantTokenAccessReadOnly),
  1287. TokenAccessController.grantTokenAccessReadOnly
  1288. )
  1289. webRouter.get('/unsupported-browser', renderUnsupportedBrowserPage)
  1290. webRouter.get('*', ErrorController.notFound)
  1291. }
  1292. export default { initialize, rateLimiters }