Files
overleaf-cep/services/web/app/src/infrastructure/HttpPermissionsPolicy.mjs
T
Anna Claire Fields 6113c6c291 Enable TS noImplicitAny in web (#31636)
GitOrigin-RevId: 18881694770f2476c475f8fef4c6a2678a2a12fe
2026-03-27 09:05:30 +00:00

94 lines
2.2 KiB
JavaScript

// @ts-check
import Settings from '@overleaf/settings'
/**
* @import { HttpPermissionsPolicy } from './types'
*/
class HttpPermissionsPolicyMiddleware {
/**
* Initialise the middleware with a Permissions Policy config
* @param {HttpPermissionsPolicy} policy
*/
constructor(policy) {
this.middleware = this.middleware.bind(this)
if (policy) {
this.policy = this.buildPermissionsPolicy(policy)
}
}
/**
* Checks the provided policy is valid
* @param {HttpPermissionsPolicy} policy
* @returns {boolean}
*/
validatePermissionsPolicy(policy) {
let policyIsValid = true
if (!policy.allowed) {
return true
}
for (const [directive, origins] of Object.entries(policy.allowed)) {
// Do any directives in the allowlist clash with the denylist?
if (policy.blocked && policy.blocked.includes(directive)) {
policyIsValid = false
}
if (!origins) {
policyIsValid = false
}
}
return policyIsValid
}
/**
* Constructs a Permissions-Policy header string from the given policy configuration
* @param {HttpPermissionsPolicy} policy
* @returns {string}
*/
buildPermissionsPolicy(policy) {
if (!this.validatePermissionsPolicy(policy)) {
throw new Error('Invalid Permissions-Policy header configuration')
}
const policyElements = []
if (policy.blocked && policy.blocked.length > 0) {
policyElements.push(
policy.blocked.map(policyElement => `${policyElement}=()`).join(', ')
)
}
if (policy.allowed && Object.entries(policy.allowed).length > 0) {
policyElements.push(
Object.keys(policy.allowed)
.map(allowKey => `${allowKey}=(${policy.allowed[allowKey]})`)
.join(', ')
)
}
return policyElements.join(', ')
}
/**
* @param {any} req
* @param {any} res
* @param {any} next
*/
middleware(req, res, next) {
if (this.policy && Settings.useHttpPermissionsPolicy) {
const originalRender = res.render
res.render = (/** @type {any} */ ...args) => {
res.setHeader('Permissions-Policy', this.policy)
originalRender.apply(res, args)
}
}
next()
}
}
export default HttpPermissionsPolicyMiddleware