-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix CSP override issue and integrate with SvelteKit's nonce (#7)
This commit addresses issue #7, where the library was overriding SvelteKit's CSP directives without using the nonce value. The changes include: - Modified securityHeaders.ts to integrate with SvelteKit's CSP - Updated types and utilities to support nonce integration - Adjusted demo app configuration to demonstrate proper CSP usage - Renamed and reorganized files for better structure
- Loading branch information
1 parent
81bb6ac
commit 7e4bad5
Showing
12 changed files
with
205 additions
and
85 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,59 +1,3 @@ | ||
import { Handle } from '@sveltejs/kit'; | ||
import { Config } from './types'; | ||
import { normalizeCspValue, normalizeHeaderValue } from './utils'; | ||
import { rules } from './headers'; | ||
|
||
/** | ||
* sets HTTP response security headers based on the provided configuration. | ||
* | ||
* @param {Config} [config] - Configuration object for secure headers. | ||
* @param {Object} [config.headers] - Custom headers to set. | ||
* @param {boolean} [config.debug] - Enables debug logging if true. | ||
* @param {Object} [config.csp] - Content Security Policy directives. | ||
* @returns {Object} An object containing the handle function to process requests. | ||
*/ | ||
export const securityHeaders = ( | ||
config: Config = { | ||
headers: { | ||
...rules.defaultHeaders, | ||
}, | ||
debug: false, | ||
csp: undefined, | ||
}, | ||
) => { | ||
const headers = new Map<string, string>(); | ||
|
||
if (config?.headers) { | ||
Object.entries(config.headers).forEach(([key, value]) => { | ||
value && headers.set(key, normalizeHeaderValue(value)); | ||
}); | ||
} | ||
|
||
if (config?.csp) { | ||
const cspDirectives = Object.entries(config.csp.directives) | ||
.map(([key, value]) => `${key} ${normalizeCspValue(value)}`) | ||
.join('; '); | ||
headers.set('Content-Security-Policy', cspDirectives); | ||
} | ||
|
||
const handle: Handle = async ({ event, resolve }) => { | ||
if (config?.debug) { | ||
console.log( | ||
'[DEBUG] securekit Headers:', | ||
JSON.stringify(Object.fromEntries(headers), null, 2), | ||
); | ||
} | ||
|
||
const response = await resolve(event); | ||
|
||
headers.forEach((value, key) => { | ||
response.headers.set(key, value); | ||
}); | ||
|
||
return response; | ||
}; | ||
|
||
return { handle }; | ||
}; | ||
|
||
export { rules } from './headers'; | ||
export { securityHeaders } from './securityHeaders'; | ||
export { default as rules } from './constants/rules'; | ||
export * from './types'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
import { Handle } from '@sveltejs/kit'; | ||
import rules from './constants/rules'; | ||
import { Config } from './types'; | ||
import { | ||
normalizeCspValue, | ||
normalizeHeaderValue, | ||
} from './utils/headerNormalizers'; | ||
import { combineCspHeaders } from './utils/cspHelpers'; | ||
|
||
/** | ||
* Sets HTTP response security headers based on the provided configuration. | ||
* | ||
* @param {Config} [config] - Configuration object for secure headers. | ||
* @param {HTTPResponseHeaders} [config.headers] - Custom headers to set. Defaults to predefined security headers. | ||
* @param {boolean} [config.debug=false] - Enables debug logging if true. | ||
* @param {Csp} [config.csp] - Content Security Policy directives. | ||
* | ||
* @returns {Object} An object containing the handle function to process requests. | ||
* @property {Handle} handle - A SvelteKit handle function that applies the configured security headers to each response. | ||
* | ||
* @example | ||
* // Basic usage with default settings | ||
* export const handle = securityHeaders().handle; | ||
* | ||
* @example | ||
* // Custom configuration | ||
* export const handle = securityHeaders({ | ||
* headers: { | ||
* 'Access-Control-Allow-Origin': 'https://example.com', | ||
* 'X-Frame-Options': 'SAMEORIGIN' | ||
* }, | ||
* debug: true, | ||
* csp: { | ||
* directives: { | ||
* 'default-src': ["'self'"], | ||
* 'script-src': ["'self'", 'https://trusted-cdn.com'] | ||
* } | ||
* } | ||
* }).handle; | ||
*/ | ||
export const securityHeaders = ( | ||
config: Config = { | ||
headers: { | ||
...rules.defaultHeaders, | ||
}, | ||
debug: false, | ||
csp: undefined, | ||
}, | ||
) => { | ||
const headers = new Map<string, string | null>(); | ||
|
||
if (config?.headers) { | ||
Object.entries(config.headers).forEach(([key, value]) => { | ||
if (value !== undefined) | ||
headers.set(key, normalizeHeaderValue(value)); | ||
}); | ||
} | ||
|
||
if (config?.csp) { | ||
const cspDirectives = Object.entries(config.csp.directives) | ||
.map(([key, value]) => `${key} ${normalizeCspValue(value)}`) | ||
.join('; '); | ||
headers.set('Content-Security-Policy', cspDirectives); | ||
} | ||
|
||
const handle: Handle = async ({ event, resolve }) => { | ||
const response = await resolve(event); | ||
|
||
headers.forEach((value, key) => { | ||
if (key.toLocaleLowerCase() === 'content-security-policy') { | ||
const existingCsp = response.headers.get( | ||
'Content-Security-Policy', | ||
); | ||
const combinedCsp = combineCspHeaders(existingCsp, value); | ||
if (combinedCsp) { | ||
response.headers.set( | ||
'Content-Security-Policy', | ||
combinedCsp, | ||
); | ||
} | ||
} else { | ||
if (value) response.headers.set(key, value); | ||
else response.headers.delete(key); | ||
} | ||
}); | ||
|
||
if (config?.debug) { | ||
console.log( | ||
'[DEBUG] securekit Headers:\n', | ||
JSON.stringify(Object.fromEntries(response.headers), null, 2), | ||
); | ||
} | ||
|
||
return response; | ||
}; | ||
|
||
return { handle }; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.