Files
overleaf-cep/services/web/app/src/infrastructure/HttpPermissionsPolicy.js
roo hutton 8644e239c6 Merge pull request #17596 from overleaf/rh-permissions-policy
[web] Add Permissions-Policy header

GitOrigin-RevId: 8934bbbda411102580d9ef8af135dcdc147627f9
2024-04-08 08:04:29 +00:00

89 lines
2.2 KiB
JavaScript

// @ts-check
const Settings = require('@overleaf/settings')
/**
* @typedef {import('./types').HttpPermissionsPolicy} HttpPermissionsPolicy
* */
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(', ')
}
middleware(req, res, next) {
if (this.policy && Settings.useHttpPermissionsPolicy) {
const originalRender = res.render
res.render = (...args) => {
res.setHeader('Permissions-Policy', this.policy)
originalRender.apply(res, args)
}
}
next()
}
}
module.exports = HttpPermissionsPolicyMiddleware