router.js 35 KB

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