Skip to content

Commit

Permalink
fix: assert behavior
Browse files Browse the repository at this point in the history
Signed-off-by: Andres Correa Casablanca <[email protected]>
  • Loading branch information
castarco committed Mar 26, 2024
1 parent 7a1bc63 commit 3fa577e
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 16 deletions.
33 changes: 22 additions & 11 deletions src/headers.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* @typedef {import('./core.d.ts').PerPageHashes} PerPageHashes
* @typedef {import('./main.d.ts').CSPDirectiveNames} CSPDirectiveNames
* @typedef {import('./main.d.ts').CSPDirectives} CSPDirectives
* @typedef {import('./main.d.ts').CSPOptions} CSPOptions
* @typedef {import('./main.d.ts').SecurityHeadersOptions} SecurityHeadersOptions
*/

Expand Down Expand Up @@ -79,23 +80,19 @@ export const parseCspDirectives = cspHeader => {
}

/**
* @param {Headers} headers
* @param {Record<string, string>} plainHeaders
* @param {PerPageHashes} pageHashes
* @param {SecurityHeadersOptions} securityHeadersOpts
* @returns {Headers}
* @param {CSPOptions} cspOpts
*/
export const patchHeaders = (headers, pageHashes, securityHeadersOpts) => {
const directives = headers.has('content-security-policy')
export const patchCspHeader = (plainHeaders, pageHashes, cspOpts) => {
const directives = Object.hasOwn(plainHeaders, 'content-security-policy')
? {
...securityHeadersOpts.contentSecurityPolicy?.cspDirectives,
...cspOpts.cspDirectives,
...parseCspDirectives(
/** @type {string} */ (headers.get('content-security-policy')),
/** @type {string} */ (plainHeaders['content-security-policy']),
),
}
: securityHeadersOpts.contentSecurityPolicy?.cspDirectives ??
/** @type {CSPDirectives} */ ({})

const plainHeaders = Object.fromEntries(headers.entries())
: cspOpts.cspDirectives ?? /** @type {CSPDirectives} */ ({})

if (pageHashes.scripts.size > 0) {
setSrcDirective(directives, 'script-src', pageHashes.scripts)
Expand All @@ -106,6 +103,20 @@ export const patchHeaders = (headers, pageHashes, securityHeadersOpts) => {
if (Object.keys(directives).length > 0) {
plainHeaders['content-security-policy'] = serialiseCspDirectives(directives)
}
}

/**
* @param {Headers} headers
* @param {PerPageHashes} pageHashes
* @param {SecurityHeadersOptions} securityHeadersOpts
* @returns {Headers}
*/
export const patchHeaders = (headers, pageHashes, securityHeadersOpts) => {
const plainHeaders = Object.fromEntries(headers.entries())

if (securityHeadersOpts.contentSecurityPolicy !== undefined) {
patchCspHeader(plainHeaders, pageHashes, securityHeadersOpts.contentSecurityPolicy)
}

return new Headers(plainHeaders)
}
5 changes: 5 additions & 0 deletions src/main.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ export type CSPOptions = {
*/
// sriHashesStrategy?: 'all' | 'perPage' // TODO: Enable in the future

/**
* - If set, it controls the "default" CSP directives (they can be overriden
* at runtime).
* - If not set, the middleware will use a minimal set of default directives.
*/
cspDirectives?: CSPDirectives
}

Expand Down
14 changes: 13 additions & 1 deletion tests/headers.test.mts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,18 @@ describe('patchHeaders', () => {
expect(patchedHeaders.has('content-security-policy')).toBe(false)
})

it('does not set csp header if no contentSecurityPolicy option is set', () => {
const headers = new Headers()
const pageHashes = {
scripts: new Set<string>(['abc1', 'xyz2']),
styles: new Set<string>(['dbc1', 'xyz3', 'abc2']),
}
const settings: SecurityHeadersOptions = { /* contentSecurityPolicy: {} */ }

const patchedHeaders = patchHeaders(headers, pageHashes, settings)
expect(patchedHeaders.has('content-security-policy')).toBe(false)
})

it('sets csp header based on settings', () => {
const headers = new Headers()
const pageHashes = { scripts: new Set<string>(), styles: new Set<string>() }
Expand All @@ -150,7 +162,7 @@ describe('patchHeaders', () => {
scripts: new Set<string>(['abc1', 'xyz2']),
styles: new Set<string>(['dbc1', 'xyz3', 'abc2']),
}
const settings: SecurityHeadersOptions = {}
const settings: SecurityHeadersOptions = { contentSecurityPolicy: {} }

const patchedHeaders = patchHeaders(headers, pageHashes, settings)
expect(patchedHeaders.get('content-security-policy')).toBe(
Expand Down
8 changes: 4 additions & 4 deletions vitest.config.unit.mts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ export default defineConfig({
'coverage-unit/**/*',
],
thresholds: {
statements: 70.0,
branches: 75.0,
functions: 70.0,
lines: 70.0,
statements: 72.0,
branches: 77.0,
functions: 80.0,
lines: 72.0,
},
reportsDirectory: 'coverage-unit',
},
Expand Down

0 comments on commit 3fa577e

Please sign in to comment.