From 554ab9c1f64d61b3e0978cf7c0fdfad7d11cbf99 Mon Sep 17 00:00:00 2001 From: Chris Zuber Date: Tue, 9 Dec 2025 11:12:22 -0800 Subject: [PATCH] Remove custom CSP handler and update importmap usage Deleted the local csp.js file and replaced its usage with direct importmap handling in home.js and http.config.js. Updated Content Security Policy logic to use importmap and integrity from @shgysk8zer0/importmap, and set CSP headers directly in responsePostprocessors. Bumped package version to 1.0.5 and removed @aegisjsproject/http-utils from dependencies. --- CHANGELOG.md | 5 ++++ csp.js | 67 ----------------------------------------------- home.js | 6 +++-- http.config.js | 17 ++++++++++-- package-lock.json | 55 +++++++++++++------------------------- package.json | 5 ++-- 6 files changed, 44 insertions(+), 111 deletions(-) delete mode 100644 csp.js diff --git a/CHANGELOG.md b/CHANGELOG.md index aa4b184..41202e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [v1.0.5] - 2025-12-09 + +### Removed +- Remove own version of CSP handler + ## [v1.0.4] - 2025-11-26 ### Changed diff --git a/csp.js b/csp.js deleted file mode 100644 index d19782f..0000000 --- a/csp.js +++ /dev/null @@ -1,67 +0,0 @@ -import { readFile } from 'node:fs/promises'; -import { imports } from '@shgysk8zer0/importmap'; -import { useCSP as CSP } from '@aegisjsproject/http-utils/csp.js'; - -const pkg = JSON.parse(await readFile(process.cwd() + '/package.json', { encoding: 'utf8' })); - -export const importmap = JSON.stringify({ - imports: { - ...imports, - [pkg.name]: pkg.exports['.'].import, - [`${pkg.name}/`]: './', - } -}); - -const sri = async (input) => await Promise.resolve(input) - .then(json => new TextEncoder().encode(json)) - .then(bytes => crypto.subtle.digest('SHA-384', bytes)) - .then(hash => 'sha384-' + new Uint8Array(hash).toBase64()); - -export const integrity = await sri(importmap); - -const DEFAULT_SRC = ['\'self\'']; -const SCRIPT_SRC = ['\'self\'', 'https://unpkg.com/@shgysk8zer0/', 'https://unpkg.com/@kernvalley/', 'https://unpkg.com/@aegisjsproject/', `'${integrity}'`]; -const STYLE_SRC = ['\'self\'', 'https://unpkg.com/@agisjsproject/', 'blob:']; -const IMAGE_SRC = ['\'self\'', 'https://i.imgur.com/', 'https://secure.gravatar.com/avatar/', 'blob:', 'data:']; -const MEDIA_SRC = ['\'self\'', 'blob:']; -const CONNECT_SRC = ['\'self\'']; -const FONT_SRC = ['\'self\'']; -const FRAME_SRC = ['\'self\'', 'https://www.youtube-nocookie.com']; -const TRUSTED_TYPES = ['aegis-sanitizer#html']; - -export const addDefaultSrc = (...srcs) => DEFAULT_SRC.push(...srcs); -export const addScriptSrc = (...srcs) => SCRIPT_SRC.push(...srcs); -export const addStyleSrc = (...srcs) => STYLE_SRC.push(...srcs); -export const addImageSrc = (...srcs) => IMAGE_SRC.push(...srcs); -export const addMediaSrc = (...srcs) => MEDIA_SRC.push(...srcs); -export const addConnectSrc = (...srcs) => CONNECT_SRC.push(...srcs); -export const addFontSrc = (...srcs) => FONT_SRC.push(...srcs); -export const addFrameSrc = (...srcs) => FRAME_SRC.push(...srcs); -export const addTrustedType = (...policies) => TRUSTED_TYPES.push(...policies); - -export const getCSP = () => [ - 'default-src ' + DEFAULT_SRC.join(' '), - 'script-src ' + SCRIPT_SRC.join(' '), - 'style-src ' + STYLE_SRC.join(' '), - 'img-src ' + IMAGE_SRC.join(' '), - 'media-src ' + MEDIA_SRC.join(' '), - 'font-src ' + FONT_SRC.join(' '), - 'frame-src ' + FRAME_SRC.join(' '), - 'connect-src ' + CONNECT_SRC.join(' '), - 'tusted-types ' + TRUSTED_TYPES.join(' '), - 'require-trusted-types-for \'script\'', -].join('; '); - -export const useCSP = ({ ...rest } = {}) => CSP({ - 'default-src': DEFAULT_SRC, - 'script-src': SCRIPT_SRC, - 'style-src': STYLE_SRC, - 'img-src': IMAGE_SRC, - 'media-src': MEDIA_SRC, - 'font-src': FONT_SRC, - 'frame-src': FRAME_SRC, - 'connect-src': CONNECT_SRC, - 'tusted-types': TRUSTED_TYPES, - 'require-trusted-types-for': '\'script\'', - ...rest -}); diff --git a/home.js b/home.js index fcff65b..c538a6b 100644 --- a/home.js +++ b/home.js @@ -1,6 +1,8 @@ import { readFile } from 'node:fs/promises'; -import { imports } from '@shgysk8zer0/importmap'; -import { importmap, integrity } from './csp.js'; +import { Importmap, imports, scopes } from '@shgysk8zer0/importmap'; +const importmap = new Importmap({ imports, scopes }); +await importmap.importLocalPackage(); +const integrity = await importmap.getIntegrity(); const NO_MAP = ['controller', 'socket', 'reject', 'signal', 'resolve']; diff --git a/http.config.js b/http.config.js index 3d0b5d7..c2abf5d 100644 --- a/http.config.js +++ b/http.config.js @@ -1,6 +1,12 @@ import home from '@aegisjsproject/dev-server'; import favicon from '@aegisjsproject/dev-server/favicon'; -import { useCSP } from './csp.js'; +import { Importmap, imports, scopes } from '@shgysk8zer0/importmap'; + +const importmap = new Importmap({ imports, scopes }); +await importmap.importLocalPackage(); +const integrity = await importmap.getIntegrity(); + +const csp = `default-src 'none'; script-src ${imports['@shgysk8zer0/polyfills']} '${integrity}'; style-src 'self'; img-src 'self'; require-trusted-types-for 'script';`; export default { open: true, @@ -8,5 +14,12 @@ export default { '/': home, '/favicon.svg': favicon, }, - responsePostprocessors: [useCSP()], + responsePostprocessors: [ + (response, { request }) => { + if (request.destination === 'document') { + response.headers.set('Content-Type', 'text/html'); + response.headers.set('Content-Security-Policy', csp); + } + } + ], }; diff --git a/package-lock.json b/package-lock.json index 047202c..29fd26a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@aegisjsproject/dev-server", - "version": "1.0.4", + "version": "1.0.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@aegisjsproject/dev-server", - "version": "1.0.4", + "version": "1.0.5", "funding": [ { "type": "librepay", @@ -20,10 +20,9 @@ "license": "MIT", "dependencies": { "@shgysk8zer0/http-server": "^1.1.1", - "@shgysk8zer0/importmap": "^1.4.88" + "@shgysk8zer0/importmap": "^1.5.1" }, "devDependencies": { - "@aegisjsproject/http-utils": "^1.0.0", "@shgysk8zer0/eslint-config": "^1.0.4", "eslint": "^9.39.1" }, @@ -31,25 +30,6 @@ "node": ">=24.10.0" } }, - "node_modules/@aegisjsproject/http-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@aegisjsproject/http-utils/-/http-utils-1.0.1.tgz", - "integrity": "sha512-qQTo3ZVJri5puWj4Rv+F/rBh59kVqKNjR6zJ5JKtyGb6BLZaRGi6u32LKwY/oQ7Hb7YpKcpdWxxB7jys36UPiA==", - "dev": true, - "funding": [ - { - "type": "librepay", - "url": "https://liberapay.com/shgysk8zer0" - }, - { - "type": "github", - "url": "https://github.com/sponsors/shgysk8zer0" - } - ], - "engines": { - "node": ">=24.10.0" - } - }, "node_modules/@aegisjsproject/sanitizer": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/@aegisjsproject/sanitizer/-/sanitizer-0.2.1.tgz", @@ -743,9 +723,10 @@ } }, "node_modules/@shgysk8zer0/importmap": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@shgysk8zer0/importmap/-/importmap-1.5.0.tgz", - "integrity": "sha512-JPHuqc5Qzqfg/5And17hjy8lFWz7JfE2R2m58mxbMpDgdt0Y78dye4kzD+XFOWgyYM2u99ZruX/TXSXF5jQunA==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@shgysk8zer0/importmap/-/importmap-1.5.1.tgz", + "integrity": "sha512-sxHyY2THBsN3i/TZOXYqkMuUErESvg9KlY+LirX0tuD+JG6Cfq+AU3EJ2vNcwnXc5DdpGEoQ41u+OkdXxq2i7Q==", + "license": "MIT", "dependencies": { "@shgysk8zer0/npm-utils": "^1.1.3", "@shgysk8zer0/polyfills": "^0.5.1", @@ -755,7 +736,7 @@ "importmap-utils": "cli.mjs" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.10.0" } }, "node_modules/@shgysk8zer0/importmap/node_modules/commander": { @@ -826,6 +807,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1006,6 +988,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz", "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", "dev": true, + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -1612,6 +1595,7 @@ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.3.tgz", "integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==", "dev": true, + "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -1767,12 +1751,6 @@ } }, "dependencies": { - "@aegisjsproject/http-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@aegisjsproject/http-utils/-/http-utils-1.0.1.tgz", - "integrity": "sha512-qQTo3ZVJri5puWj4Rv+F/rBh59kVqKNjR6zJ5JKtyGb6BLZaRGi6u32LKwY/oQ7Hb7YpKcpdWxxB7jys36UPiA==", - "dev": true - }, "@aegisjsproject/sanitizer": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/@aegisjsproject/sanitizer/-/sanitizer-0.2.1.tgz", @@ -2137,9 +2115,9 @@ } }, "@shgysk8zer0/importmap": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@shgysk8zer0/importmap/-/importmap-1.5.0.tgz", - "integrity": "sha512-JPHuqc5Qzqfg/5And17hjy8lFWz7JfE2R2m58mxbMpDgdt0Y78dye4kzD+XFOWgyYM2u99ZruX/TXSXF5jQunA==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@shgysk8zer0/importmap/-/importmap-1.5.1.tgz", + "integrity": "sha512-sxHyY2THBsN3i/TZOXYqkMuUErESvg9KlY+LirX0tuD+JG6Cfq+AU3EJ2vNcwnXc5DdpGEoQ41u+OkdXxq2i7Q==", "requires": { "@shgysk8zer0/npm-utils": "^1.1.3", "@shgysk8zer0/polyfills": "^0.5.1", @@ -2193,7 +2171,8 @@ "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true + "dev": true, + "peer": true }, "acorn-jsx": { "version": "5.3.2", @@ -2322,6 +2301,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz", "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", "dev": true, + "peer": true, "requires": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -2756,6 +2736,7 @@ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.3.tgz", "integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==", "dev": true, + "peer": true, "requires": { "@rollup/rollup-android-arm-eabi": "4.53.3", "@rollup/rollup-android-arm64": "4.53.3", diff --git a/package.json b/package.json index bef0b5f..80f1fb9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@aegisjsproject/dev-server", - "version": "1.0.4", + "version": "1.0.5", "description": "Dev server setup for `@shgysk8zer0/http-server`", "keywords": [ "dev-server", @@ -66,12 +66,11 @@ }, "homepage": "https://github.com/AegisJSProject/dev-server#readme", "devDependencies": { - "@aegisjsproject/http-utils": "^1.0.0", "@shgysk8zer0/eslint-config": "^1.0.4", "eslint": "^9.39.1" }, "dependencies": { "@shgysk8zer0/http-server": "^1.1.1", - "@shgysk8zer0/importmap": "^1.4.88" + "@shgysk8zer0/importmap": "^1.5.1" } }