From 3c4d4c2b59dc83a513d7fbceef4fca23f0774397 Mon Sep 17 00:00:00 2001 From: kbkn3 Date: Mon, 9 Sep 2024 21:54:27 +0900 Subject: [PATCH] fix(secure-headers): optimize getPermissionsPolicyDirectives function (#3398) --- src/middleware/secure-headers/index.test.ts | 11 +++++++++-- src/middleware/secure-headers/secure-headers.ts | 12 +++++++++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/middleware/secure-headers/index.test.ts b/src/middleware/secure-headers/index.test.ts index 2f3d9ad5..5d055830 100644 --- a/src/middleware/secure-headers/index.test.ts +++ b/src/middleware/secure-headers/index.test.ts @@ -160,7 +160,7 @@ describe('Secure Headers Middleware', () => { expect(res.headers.get('X-XSS-Protection')).toEqual('1') }) - it('should set Permission-Policy header', async () => { + it('should set Permission-Policy header correctly', async () => { const app = new Hono() app.use( '/test', @@ -173,13 +173,20 @@ describe('Secure Headers Middleware', () => { camera: false, microphone: true, geolocation: ['*'], + usb: ['self', 'https://a.example.com', 'https://b.example.com'], + accelerometer: ['https://*.example.com'], + gyroscope: ['src'], + magnetometer: ['https://a.example.com', 'https://b.example.com'], }, }) ) const res = await app.request('/test') expect(res.headers.get('Permissions-Policy')).toEqual( - 'fullscreen=(self), bluetooth=(none), payment=(self example.com), sync-xhr=(), camera=none, microphone=(), geolocation=(*)' + 'fullscreen=(self), bluetooth=none, payment=(self "example.com"), sync-xhr=(), camera=none, microphone=*, ' + + 'geolocation=*, usb=(self "https://a.example.com" "https://b.example.com"), ' + + 'accelerometer=("https://*.example.com"), gyroscope=(src), ' + + 'magnetometer=("https://a.example.com" "https://b.example.com")' ) }) it('CSP Setting', async () => { diff --git a/src/middleware/secure-headers/secure-headers.ts b/src/middleware/secure-headers/secure-headers.ts index 902b45f7..c29515d5 100644 --- a/src/middleware/secure-headers/secure-headers.ts +++ b/src/middleware/secure-headers/secure-headers.ts @@ -278,12 +278,18 @@ function getPermissionsPolicyDirectives(policy: PermissionsPolicyOptions): strin const kebabDirective = camelToKebab(directive) if (typeof value === 'boolean') { - return `${kebabDirective}=${value ? '()' : 'none'}` + return `${kebabDirective}=${value ? '*' : 'none'}` } if (Array.isArray(value)) { - const allowlist = value.length === 0 ? '()' : `(${value.join(' ')})` - return `${kebabDirective}=${allowlist}` + if (value.length === 0) { + return `${kebabDirective}=()` + } + if (value.length === 1 && (value[0] === '*' || value[0] === 'none')) { + return `${kebabDirective}=${value[0]}` + } + const allowlist = value.map((item) => (['self', 'src'].includes(item) ? item : `"${item}"`)) + return `${kebabDirective}=(${allowlist.join(' ')})` } return ''