Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: csp headers generation #79

Merged
merged 2 commits into from
Apr 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions @kindspells/astro-shield/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@kindspells/astro-shield",
"version": "1.3.5",
"version": "1.3.6",
"description": "Astro integration to enhance your website's security with SubResource Integrity hashes, Content-Security-Policy headers, and other techniques.",
"private": false,
"type": "module",
Expand Down Expand Up @@ -80,7 +80,7 @@
"url": "https://ko-fi.com/coderspirit"
}
],
"packageManager": "pnpm@8.15.6",
"packageManager": "pnpm@9.0.6",
"engines": {
"node": ">= 18.0.0"
},
Expand Down
13 changes: 4 additions & 9 deletions @kindspells/astro-shield/src/headers.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,8 @@ export const serialiseHashes = hashes =>
* @param {Set<string>} hashes
* @returns {string}
*/
export const safeSerialiseHashes = hashes =>
Array.from(hashes)
.sort()
.map(h => (h.match(/^'[^']+'$/i) ? h : `'${h}'`))
.join(' ')
export const serializeCspDirectiveSources = hashes =>
Array.from(hashes).sort().join(' ')

/**
* @param {CSPDirectives} directives
Expand All @@ -45,13 +42,11 @@ export const serialiseCspDirectives = directives =>
export const setSrcDirective = (directives, srcType, hashes) => {
const baseSrcDirective = directives[srcType]
if (baseSrcDirective) {
const srcDirective = new Set(
baseSrcDirective.split(/\s+/).filter(v => v !== "'self'"),
)
const srcDirective = new Set(baseSrcDirective.split(/\s+/))
for (const hash of hashes) {
srcDirective.add(`'${hash}'`)
}
directives[srcType] = `'self' ${safeSerialiseHashes(srcDirective)}`
directives[srcType] = serializeCspDirectiveSources(srcDirective)
} else {
directives[srcType] = `'self' ${serialiseHashes(hashes)}`
}
Expand Down
19 changes: 1 addition & 18 deletions @kindspells/astro-shield/tests/headers.test.mts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { describe, expect, it } from 'vitest'
import {
parseCspDirectives,
patchHeaders,
safeSerialiseHashes,
serialiseCspDirectives,
serialiseHashes,
setSrcDirective,
Expand All @@ -35,22 +34,6 @@ describe('serialiseHashes', () => {
})
})

describe('safeSerialiseHashes', () => {
it('returns an empty string for an empty set', () => {
expect(safeSerialiseHashes(new Set())).toBe('')
})

it('returns a string with sorted hashes', () => {
const hashes = new Set(['d', 'c', 'a', 'b'])
expect(safeSerialiseHashes(hashes)).toBe("'a' 'b' 'c' 'd'")
})

it('avoids duplicated single quotes', () => {
const hashes = new Set(["'a'", "'b'", "'c'", "'d'"])
expect(safeSerialiseHashes(hashes)).toBe("'a' 'b' 'c' 'd'")
})
})

describe('serialiseCspDirectives', () => {
it('returns an empty string for an empty object', () => {
expect(serialiseCspDirectives({})).toBe('')
Expand Down Expand Up @@ -92,7 +75,7 @@ describe('setSrcDirective', () => {
)

expect(directives['script-src']).toBe(
"'self' 'abc1' 'abc2' 'dbc1' 'xyz2' 'xyz3'",
"'abc1' 'abc2' 'dbc1' 'self' 'xyz2' 'xyz3'",
)
})
})
Expand Down
8 changes: 8 additions & 0 deletions docs/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ export default defineConfig({
image: {
service: passthroughImageService(),
},
i18n: {
locales: ['en'],
defaultLocale: 'en',
},
integrations: [
shield({}),
starlight({
Expand All @@ -26,6 +30,10 @@ export default defineConfig({
label: 'English',
lang: 'en',
},
en: {
label: 'English',
lang: 'en',
},
},
social: {
github: 'https://github.com/kindspells/astro-shield',
Expand Down
7 changes: 4 additions & 3 deletions docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
"type": "module",
"version": "1.4.0",
"scripts": {
"dev": "sst dev astro dev",
"start": "astro dev",
"astro": "astro",
"build": "moon run build",
"deploy":"sst deploy --stage prod",
"dev": "sst dev astro dev",
"preview": "astro preview",
"astro": "astro"
"start": "astro dev"
},
"dependencies": {
"astro-sst": "^2.41.5",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ export default defineConfig({
`}
/>

<Aside type='tip'>
By default, Astro-Shield will add `'self`' to the `script-src` directive. You
can override this behavior by setting your own `script-src` directive (which
can be an empty string).
</Aside>

<Aside type="caution">
When enabling CSP headers, you must also set the `sri.enableMiddleware` option
to `true`. It is also recommended to set the `sri.hashesModule` option.
Expand Down
4 changes: 2 additions & 2 deletions docs/sst.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ export default $config({
async run() {
new sst.aws.Astro("AstroShield", {
domain: {
hostedZone: 'kindspells.dev',
domainName: 'astro-shield.kindspells.dev'
dns: sst.aws.dns(),
name: 'astro-shield.kindspells.dev'
}
});
},
Expand Down
3 changes: 2 additions & 1 deletion docs/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
*
* SPDX-License-Identifier: MIT
*/
"extends": "astro/tsconfigs/strictest"
"extends": "astro/tsconfigs/strictest",
"exclude": ["dist/**/*", "node_modules/**/*"]
}
Loading
Loading