Files
overleaf-cep/services/web/app/src/Features/History/HistoryRouter.mjs
Jakob Ackermann d56477565c [web] deduplicate getting the project when loading the editor (#32762)
* [web] enable async local storage on all the endpoints

Co-authored-by: Brian Gough <brian.gough@overleaf.com>

* [web] deduplicate getting the project when loading the editor

Co-authored-by: Brian Gough <brian.gough@overleaf.com>

* [web] use ProjectAccess state for computing analytics segmentation

Co-authored-by: Brian Gough <brian.gough@overleaf.com>

* [web] restore ownership of active flag and deferredTpdsFlushCounter

* [web] add missing await

* [web] update unit tests

* [web] add metrics for project access caching

* [web] add missing test mock

* [web] invalidate async local storage when changing project access

* [web] deduplicate project lookup when checking for token access

* [web] add helper function for getting cached ProjectAccess

* [web] add acceptance test for caching of ProjectAccess

* [web] account for saas-only project access in tests

* Revert "[web] enable async local storage on all the endpoints"

This reverts commit 1b82f3b935040e8cfd180d1f6bf4183a655580e2.

* [web] add async local storage to project endpoints in top-50

* [web] invalidate async local storage for project access from modules

Co-authored-by: Jessica Lawshe <jessica.lawshe@overleaf.com>

---------

Co-authored-by: Brian Gough <brian.gough@overleaf.com>
Co-authored-by: Jessica Lawshe <jessica.lawshe@overleaf.com>
GitOrigin-RevId: 3eea7956b24e6f937dc1c17948681063d4dca3ea
2026-04-17 08:07:08 +00:00

163 lines
5.0 KiB
JavaScript

// @ts-check
import Settings from '@overleaf/settings'
import { RateLimiter } from '../../infrastructure/RateLimiter.mjs'
import AuthenticationController from '../Authentication/AuthenticationController.mjs'
import AuthorizationMiddleware from '../Authorization/AuthorizationMiddleware.mjs'
import RateLimiterMiddleware from '../Security/RateLimiterMiddleware.mjs'
import HistoryController from './HistoryController.mjs'
import AsyncLocalStorage from '../../infrastructure/AsyncLocalStorage.mjs'
const rateLimiters = {
downloadProjectRevision: new RateLimiter('download-project-revision', {
points: 30,
duration: 60 * 60,
}),
getProjectBlob: new RateLimiter('get-project-blob', {
// Download project in full once per hour
points: Settings.maxEntitiesPerProject,
duration: 60 * 60,
}),
flushHistory: new RateLimiter('flush-project-history', {
points: 30,
duration: 60,
}),
}
/**
* @param {any} webRouter
* @param {any} privateApiRouter
*/
function apply(webRouter, privateApiRouter) {
// Blobs
webRouter.head(
'/project/:project_id/blob/:hash',
RateLimiterMiddleware.rateLimit(rateLimiters.getProjectBlob),
AsyncLocalStorage.middleware,
AuthorizationMiddleware.ensureUserCanReadProject,
HistoryController.headBlob
)
webRouter.get(
'/project/:project_id/blob/:hash',
RateLimiterMiddleware.rateLimit(rateLimiters.getProjectBlob),
AsyncLocalStorage.middleware,
AuthorizationMiddleware.ensureUserCanReadProject,
HistoryController.getBlob
)
// History diffs
webRouter.get(
'/project/:Project_id/updates',
AsyncLocalStorage.middleware,
AuthorizationMiddleware.blockRestrictedUserFromProject,
AuthorizationMiddleware.ensureUserCanReadProject,
HistoryController.proxyToHistoryApiAndInjectUserDetails
)
webRouter.get(
'/project/:Project_id/doc/:doc_id/diff',
AsyncLocalStorage.middleware,
AuthorizationMiddleware.blockRestrictedUserFromProject,
AuthorizationMiddleware.ensureUserCanReadProject,
HistoryController.proxyToHistoryApi
)
webRouter.get(
'/project/:Project_id/diff',
AsyncLocalStorage.middleware,
AuthorizationMiddleware.blockRestrictedUserFromProject,
AuthorizationMiddleware.ensureUserCanReadProject,
HistoryController.proxyToHistoryApiAndInjectUserDetails
)
webRouter.get(
'/project/:Project_id/filetree/diff',
AsyncLocalStorage.middleware,
AuthorizationMiddleware.blockRestrictedUserFromProject,
AuthorizationMiddleware.ensureUserCanReadProject,
HistoryController.proxyToHistoryApi
)
// File and project restore
webRouter.post(
'/project/:project_id/restore_file',
AuthorizationMiddleware.ensureUserCanWriteProjectContent,
HistoryController.restoreFileFromV2
)
webRouter.post(
'/project/:project_id/revert_file',
AuthorizationMiddleware.ensureUserCanWriteProjectContent,
HistoryController.revertFile
)
webRouter.post(
'/project/:project_id/revert-project',
AuthorizationMiddleware.ensureUserCanWriteProjectContent,
HistoryController.revertProject
)
// History download
webRouter.get(
'/project/:project_id/version/:version/zip',
RateLimiterMiddleware.rateLimit(rateLimiters.downloadProjectRevision),
AuthorizationMiddleware.blockRestrictedUserFromProject,
AuthorizationMiddleware.ensureUserCanReadProject,
HistoryController.downloadZipOfVersion
)
// History flush and resync
webRouter.post(
'/project/:Project_id/flush',
RateLimiterMiddleware.rateLimit(rateLimiters.flushHistory),
AsyncLocalStorage.middleware,
AuthorizationMiddleware.blockRestrictedUserFromProject,
AuthorizationMiddleware.ensureUserCanReadProject,
HistoryController.proxyToHistoryApi
)
privateApiRouter.post(
'/project/:Project_id/history/resync',
AuthenticationController.requirePrivateApiAuth(),
HistoryController.resyncProjectHistory
)
// History labels
webRouter.get(
'/project/:Project_id/labels',
AsyncLocalStorage.middleware,
AuthorizationMiddleware.blockRestrictedUserFromProject,
AuthorizationMiddleware.ensureUserCanReadProject,
HistoryController.getLabels
)
webRouter.post(
'/project/:Project_id/labels',
AuthorizationMiddleware.ensureUserCanWriteOrReviewProjectContent,
HistoryController.createLabel
)
webRouter.delete(
'/project/:Project_id/labels/:label_id',
AuthorizationMiddleware.ensureUserCanWriteOrReviewProjectContent,
HistoryController.deleteLabel
)
// History snapshot
webRouter.get(
'/project/:project_id/latest/history',
AsyncLocalStorage.middleware,
AuthorizationMiddleware.blockRestrictedUserFromProject,
AuthorizationMiddleware.ensureUserCanReadProject,
HistoryController.getLatestHistory
)
webRouter.get(
'/project/:project_id/changes',
AsyncLocalStorage.middleware,
AuthorizationMiddleware.blockRestrictedUserFromProject,
AuthorizationMiddleware.ensureUserCanReadProject,
HistoryController.getChanges
)
}
export default { apply }