feat: define secure static hosting contract

This commit is contained in:
2026-09-02 09:44:15 +03:00
parent 672ba80d9b
commit 847e6e4da9
8 changed files with 638 additions and 27 deletions

View File

@@ -311,15 +311,18 @@ const assertMetadata = (html, inputs) => {
const assertSecurityHeaders = (headers, inputs, serializedJsonLd) => {
const required = [
"default-src 'self'", "script-src 'self'", "style-src 'self'", "img-src 'self'", "media-src 'self'",
"default-src 'self'", "script-src 'self'", "style-src 'self'", "img-src 'self' data:", "media-src 'self'",
"font-src 'self'", "connect-src 'none'", "object-src 'none'", "base-uri 'none'", "frame-ancestors 'none'",
"form-action 'none'", 'upgrade-insecure-requests', 'X-Content-Type-Options: nosniff',
"form-action 'self'", 'upgrade-insecure-requests', 'X-Content-Type-Options: nosniff',
'Referrer-Policy: no-referrer', 'X-Frame-Options: DENY',
'Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(), usb=(), accelerometer=(), gyroscope=(), magnetometer=()',
];
for (const value of required) {
if (!headers.includes(value)) throw new Error(`Missing security header policy: ${value}`);
}
if (/unsafe-inline|unsafe-eval|(?:^|[;\s])\*(?:[;\s]|$)|https?:\/\//iu.test(headers)) {
throw new Error('Security header policy contains an unsafe or external source expression.');
}
const expectedHash = `sha256-${createHash('sha256').update(serializedJsonLd).digest('base64')}`;
const hashes = headers.match(/sha256-[A-Za-z0-9+/=]+/gu) ?? [];
if (hashes.length !== 1 || hashes[0] !== expectedHash) {