router.js 36 KB

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