router.js 36 KB

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