From d6e4ca8c2979b67a01b79c568334aef2de03bf6a Mon Sep 17 00:00:00 2001 From: Viorel Mocanu Date: Tue, 30 Jan 2024 20:05:10 +0200 Subject: [PATCH] chore: add csp and other vercel configs --- .gitignore | 4 + astro.config.mjs | 15 +++ eslint.config.js | 4 + package.json | 11 +- pnpm-lock.yaml | 301 +++++++++++++++++++++++++++++++++++++++++- src/utils/csp-hash.ts | 39 ++++++ vercel.json | 80 +++++++++++ 7 files changed, 445 insertions(+), 9 deletions(-) create mode 100644 src/utils/csp-hash.ts create mode 100644 vercel.json diff --git a/.gitignore b/.gitignore index d9dac40..4b0d916 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,7 @@ Thumbs.db # Hosting provider adapters .netlify .vercel +.vercel/* .turbo lambda @@ -71,3 +72,6 @@ coverage # nyc test coverage .nyc_output + +# Sentry Config File +.env.sentry-build-plugin diff --git a/astro.config.mjs b/astro.config.mjs index 207b755..e1319eb 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -1,15 +1,19 @@ import { ENV, LANGUAGE_EXTENDED, SITE_DESCRIPTION, SITE_NAME, ACCENT_COLOR, URL, DEBUG } from './src/config'; import { defineConfig, squooshImageService } from 'astro/config'; +import { astroCSPHashGenerator } from './src/utils/csp-hash'; import { fileURLToPath } from 'url'; +import { loadEnv } from 'vite'; //import compress from 'astro-compress'; import mdx from '@astrojs/mdx'; import path from 'path'; import partytown from '@astrojs/partytown'; +import sentry from "@sentry/astro"; import sitemap from '@astrojs/sitemap'; import vercel from '@astrojs/vercel/serverless'; import webmanifest from 'astro-webmanifest'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const { VITE_SENTRY_AUTH_TOKEN } = loadEnv(import.meta.env.PUBLIC_SENTRY_AUTH_TOKEN ?? process.env.PUBLIC_SENTRY_AUTH_TOKEN, process.cwd(), ""); // https://astro.build/config export default defineConfig({ @@ -119,5 +123,16 @@ export default defineConfig({ SVG: true, Logger: 1, }),*/ + astroCSPHashGenerator, + sentry({ + dsn: "https://344f761c5efeb4b9ea6b08942c01f5b6@o4506599007911936.ingest.sentry.io/4506661195808768", + // @ts-ignore + sourceMapsUploadOptions: { + project: "resurse-dev", + // @ts-ignore + authToken: VITE_SENTRY_AUTH_TOKEN, + telemetry: false, + }, + }), ], }); diff --git a/eslint.config.js b/eslint.config.js index 79d29ea..f0e4ea5 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -12,6 +12,7 @@ const ignoreArray = [ '.idea/**', '.netlify/**', '.vercel/**', + '/.vercel/**', 'build/**', 'coverage/**', 'demo/**', @@ -20,6 +21,9 @@ const ignoreArray = [ 'node_modules/**', 'static/**', 'src/env.d.ts', + '.vercel', + '**/.vercel/**', + '/.vercel/**', ]; export default [ diff --git a/package.json b/package.json index 7d76c07..9533832 100644 --- a/package.json +++ b/package.json @@ -35,10 +35,10 @@ "astro": "astro", "format": "prettier --check ./**/*.{html,css,js,cjs,ts,astro,md,json,yaml} --plugin=prettier-plugin-astro", "format:fix": "prettier --write ./**/*.{html,css,js,cjs,ts,astro,md,json,yaml} --plugin=prettier-plugin-astro", - "lint:js": "eslint ./**/*.js ./**/*.ts ./**/*.astro", + "lint:js": "eslint ./**/*.js ./**/*.ts ./**/*.astro --ignore-pattern '.vercel/*' --ignore-pattern '.astro/*' --ignore-pattern 'build/*' --ignore-pattern 'coverage/*' --ignore-pattern 'dist/*' --ignore-pattern 'node_modules/*'", "lint:md": "markdownlint ./src/**/*.md", - "lint:fix": "pnpm lint:js --fix . && pnpm lint:md --fix", - "lint": "pnpm lint:js . && pnpm lint:md", + "lint:fix": "pnpm lint:js --fix && pnpm lint:md --fix", + "lint": "pnpm lint:js && pnpm lint:md", "postinstall": "husky", "coverage": "pnpm test:unit --coverage", "test:unit": "vitest run", @@ -54,12 +54,14 @@ "@astrojs/rss": "4.0.4", "@astrojs/sitemap": "3.0.5", "@astrojs/vercel": "7.0.2", - "@vercel/analytics": "1.1.2", + "@sentry/astro": "^7.99.0", + "@vercel/analytics": "^1.1.2", "astro": "4.2.7", "astro-compress": "2.2.8", "astro-simpleanalytics-plugin": "^0.3.11", "astro-webmanifest": "1.0.0", "lite-youtube-embed": "0.3.0", + "node-html-parser": "6.1.12", "sass": "1.70.0", "sharp": "0.33.2" }, @@ -79,6 +81,7 @@ "prettier": "3.2.4", "prettier-plugin-astro": "0.13.0", "typescript": "5.3.3", + "vite": "^5.0.12", "vitest": "1.2.2" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 846346e..c354036 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,8 +20,11 @@ dependencies: '@astrojs/vercel': specifier: 7.0.2 version: 7.0.2(astro@4.2.7) + '@sentry/astro': + specifier: ^7.99.0 + version: 7.99.0(astro@4.2.7) '@vercel/analytics': - specifier: 1.1.2 + specifier: ^1.1.2 version: 1.1.2 astro: specifier: 4.2.7 @@ -38,6 +41,9 @@ dependencies: lite-youtube-embed: specifier: 0.3.0 version: 0.3.0 + node-html-parser: + specifier: 6.1.12 + version: 6.1.12 sass: specifier: 1.70.0 version: 1.70.0 @@ -91,6 +97,9 @@ devDependencies: typescript: specifier: 5.3.3 version: 5.3.3 + vite: + specifier: ^5.0.12 + version: 5.0.12(@types/node@20.11.10)(sass@1.70.0) vitest: specifier: 1.2.2 version: 1.2.2(@types/node@20.11.10)(sass@1.70.0) @@ -1375,6 +1384,219 @@ packages: requiresBuild: true optional: true + /@sentry-internal/feedback@7.99.0: + resolution: {integrity: sha512-exIO1o+bE0MW4z30FxC0cYzJ4ZHSMlDPMHCBDPzU+MWGQc/fb8s58QUrx5Dnm6HTh9G3H+YlroCxIo9u0GSwGQ==} + engines: {node: '>=12'} + dependencies: + '@sentry/core': 7.99.0 + '@sentry/types': 7.99.0 + '@sentry/utils': 7.99.0 + dev: false + + /@sentry-internal/replay-canvas@7.99.0: + resolution: {integrity: sha512-PoIkfusToDq0snfl2M6HJx/1KJYtXxYhQplrn11kYadO04SdG0XGXf4h7wBTMEQ7LDEAtQyvsOu4nEQtTO3YjQ==} + engines: {node: '>=12'} + dependencies: + '@sentry/core': 7.99.0 + '@sentry/replay': 7.99.0 + '@sentry/types': 7.99.0 + '@sentry/utils': 7.99.0 + dev: false + + /@sentry-internal/tracing@7.99.0: + resolution: {integrity: sha512-z3JQhHjoM1KdM20qrHwRClKJrNLr2CcKtCluq7xevLtXHJWNAQQbafnWD+Aoj85EWXBzKt9yJMv2ltcXJ+at+w==} + engines: {node: '>=8'} + dependencies: + '@sentry/core': 7.99.0 + '@sentry/types': 7.99.0 + '@sentry/utils': 7.99.0 + dev: false + + /@sentry/astro@7.99.0(astro@4.2.7): + resolution: {integrity: sha512-b+ZY5AZnlUnvS3nDeCdP/DHCGlvcxBe+NK43T4qdbtONHPcVpv1PytW6qGGOpMoDYdt7Iv+uYjrIZfNo3tTyiA==} + engines: {node: '>=18.14.1'} + peerDependencies: + astro: '>=3.x || >=4.0.0-beta' + dependencies: + '@sentry/browser': 7.99.0 + '@sentry/core': 7.99.0 + '@sentry/node': 7.99.0 + '@sentry/types': 7.99.0 + '@sentry/utils': 7.99.0 + '@sentry/vite-plugin': 2.10.3 + astro: 4.2.7(@types/node@20.11.10)(sass@1.70.0)(typescript@5.3.3) + transitivePeerDependencies: + - encoding + - supports-color + dev: false + + /@sentry/browser@7.99.0: + resolution: {integrity: sha512-bgfoUv3wkwwLgN5YUOe0ibB3y268ZCnamZh6nLFqnY/UBKC1+FXWFdvzVON/XKUm62LF8wlpCybOf08ebNj2yg==} + engines: {node: '>=8'} + dependencies: + '@sentry-internal/feedback': 7.99.0 + '@sentry-internal/replay-canvas': 7.99.0 + '@sentry-internal/tracing': 7.99.0 + '@sentry/core': 7.99.0 + '@sentry/replay': 7.99.0 + '@sentry/types': 7.99.0 + '@sentry/utils': 7.99.0 + dev: false + + /@sentry/bundler-plugin-core@2.10.3: + resolution: {integrity: sha512-glokZ9O6m3l5OlVk/2C9EPI3Fy7rAxwWQZixItLmrVJnJAf0lDX7bTNJUvZKKDrMRoCypL6WpM/QeSe1i3i8ig==} + engines: {node: '>= 14'} + dependencies: + '@sentry/cli': 2.27.0 + '@sentry/node': 7.99.0 + '@sentry/utils': 7.99.0 + dotenv: 16.4.1 + find-up: 5.0.0 + glob: 9.3.2 + magic-string: 0.27.0 + unplugin: 1.0.1 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + + /@sentry/cli-darwin@2.27.0: + resolution: {integrity: sha512-/DOZlN5rK19g7YP2OaVNauQhUrRfJ88RDr6qURFiqdxYHDc3isPFGHZJmeZBTwOnDDepyZb4XLaOyfwvAOxHig==} + engines: {node: '>=10'} + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@sentry/cli-linux-arm64@2.27.0: + resolution: {integrity: sha512-f+zuB9XGfB8pNamNgSDhqsavuLuzi6saZxbr3uQf30bA5AESI5hspOd1zPcidOORCVZxiPzQe3+T7avBI1XLuw==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux, freebsd] + requiresBuild: true + dev: false + optional: true + + /@sentry/cli-linux-arm@2.27.0: + resolution: {integrity: sha512-JmMQ9zgFhkZUEN5WIYuJisu4Jif/ThRHDjbsbXBRbUkkgRn88hgUfg299djMvlZZxjpl3K9AEua+1TIUeQd0Sg==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux, freebsd] + requiresBuild: true + dev: false + optional: true + + /@sentry/cli-linux-i686@2.27.0: + resolution: {integrity: sha512-/4eyz7jnYp20mZqNtpvCEBkxFW0nEjEZRo2BiASQ5/7K8CmoJRe1vhpDA0WOfzi1zTFIfpdE1/RZm2CjHS6DHQ==} + engines: {node: '>=10'} + cpu: [x86, ia32] + os: [linux, freebsd] + requiresBuild: true + dev: false + optional: true + + /@sentry/cli-linux-x64@2.27.0: + resolution: {integrity: sha512-ptu7wXecnYssihzHlxEOaqbFHWmNEfbepBKGXTdWK2kC+D51+7yHsR9xRdThwVID1bisFgjAveKmBQjmKuXjHQ==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux, freebsd] + requiresBuild: true + dev: false + optional: true + + /@sentry/cli-win32-i686@2.27.0: + resolution: {integrity: sha512-Db4/xmdE5qV4Aq7Yc8vRw22Y46JJdGMdsMsl5jIf0GVSQPgO23O/2uTiDGpPOdeq91K9EtvpH1zQfDLIfLMaXw==} + engines: {node: '>=10'} + cpu: [x86, ia32] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@sentry/cli-win32-x64@2.27.0: + resolution: {integrity: sha512-q7y/BH4iGfs0TD5PXh2Q8oqnTbOIufoT1NWJcKqvZcOiqCLK3PNUiq7xUeX1PMTrFYAh3Bm6EekOnMavqvbGmg==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@sentry/cli@2.27.0: + resolution: {integrity: sha512-pc0opd71W8lGhYvmB1keQtJkarxzCS9f9ErKYv6TfXOOX6drvwkyA6vD/6xEnpzyvqGAuGRU4T4sEeLD3irwUQ==} + engines: {node: '>= 10'} + hasBin: true + requiresBuild: true + dependencies: + https-proxy-agent: 5.0.1 + node-fetch: 2.7.0 + progress: 2.0.3 + proxy-from-env: 1.1.0 + which: 2.0.2 + optionalDependencies: + '@sentry/cli-darwin': 2.27.0 + '@sentry/cli-linux-arm': 2.27.0 + '@sentry/cli-linux-arm64': 2.27.0 + '@sentry/cli-linux-i686': 2.27.0 + '@sentry/cli-linux-x64': 2.27.0 + '@sentry/cli-win32-i686': 2.27.0 + '@sentry/cli-win32-x64': 2.27.0 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + + /@sentry/core@7.99.0: + resolution: {integrity: sha512-vOAtzcAXEUtS/oW7wi3wMkZ3hsb5Ch96gKyrrj/mXdOp2zrcwdNV6N9/pawq2E9P/7Pw8AXw4CeDZztZrjQLuA==} + engines: {node: '>=8'} + dependencies: + '@sentry/types': 7.99.0 + '@sentry/utils': 7.99.0 + dev: false + + /@sentry/node@7.99.0: + resolution: {integrity: sha512-34wYtLddnPcQ8qvKq62AfxowaMFw+GMUZGv7fIs9FxeBqqqn6Ckl0gFCTADudIIBQ3rSbmN7sHJIXdyiQv+pcw==} + engines: {node: '>=8'} + dependencies: + '@sentry-internal/tracing': 7.99.0 + '@sentry/core': 7.99.0 + '@sentry/types': 7.99.0 + '@sentry/utils': 7.99.0 + dev: false + + /@sentry/replay@7.99.0: + resolution: {integrity: sha512-gyN/I2WpQrLAZDT+rScB/0jnFL2knEVBo8U8/OVt8gNP20Pq8T/rDZKO/TG0cBfvULDUbJj2P4CJryn2p/O2rA==} + engines: {node: '>=12'} + dependencies: + '@sentry-internal/tracing': 7.99.0 + '@sentry/core': 7.99.0 + '@sentry/types': 7.99.0 + '@sentry/utils': 7.99.0 + dev: false + + /@sentry/types@7.99.0: + resolution: {integrity: sha512-94qwOw4w40sAs5mCmzcGyj8ZUu/KhnWnuMZARRq96k+SjRW/tHFAOlIdnFSrt3BLPvSOK7R3bVAskZQ0N4FTmA==} + engines: {node: '>=8'} + dev: false + + /@sentry/utils@7.99.0: + resolution: {integrity: sha512-cYZy5WNTkWs5GgggGnjfGqC44CWir0pAv4GVVSx0fsup4D4pMKBJPrtub15f9uC+QkUf3vVkqwpBqeFxtmJQTQ==} + engines: {node: '>=8'} + dependencies: + '@sentry/types': 7.99.0 + dev: false + + /@sentry/vite-plugin@2.10.3: + resolution: {integrity: sha512-IOt49G3KM189a2M3ISrctY0b8PlSnUZFnfNKYyaa6ojTjhkVekPopUg3vCp93cxCWRlw6D1UzX9j2i4fXi9k/g==} + engines: {node: '>= 14'} + dependencies: + '@sentry/bundler-plugin-core': 2.10.3 + unplugin: 1.0.1 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + /@sinclair/typebox@0.27.8: resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} dev: true @@ -2374,7 +2596,6 @@ packages: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} dependencies: balanced-match: 1.0.2 - dev: true /braces@3.0.2: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} @@ -2977,6 +3198,11 @@ packages: is-obj: 2.0.0 dev: true + /dotenv@16.4.1: + resolution: {integrity: sha512-CjA3y+Dr3FyFDOAMnxZEGtnW9KBR2M0JvvUtXNW+dYJL5ROWxP9DUHCwgFqpMk0OXCc0ljhaNTr2w/kutYIcHQ==} + engines: {node: '>=12'} + dev: false + /dset@3.1.3: resolution: {integrity: sha512-20TuZZHCEZ2O71q9/+8BwKwZ0QtD9D8ObhrihJPr+vLLYlSuAU3/zL4cSlgbfeoGHTjCSJBa7NGcrF9/Bx/WJQ==} engines: {node: '>=4'} @@ -3690,6 +3916,16 @@ packages: once: 1.4.0 path-is-absolute: 1.0.1 + /glob@9.3.2: + resolution: {integrity: sha512-BTv/JhKXFEHsErMte/AnfiSv8yYOLLiyH2lTg8vn02O21zWFgHPTfxtgn1QRe7NRgggUhC8hacR2Re94svHqeA==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + fs.realpath: 1.0.0 + minimatch: 7.4.6 + minipass: 4.2.8 + path-scurry: 1.10.1 + dev: false + /global-dirs@0.1.1: resolution: {integrity: sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg==} engines: {node: '>=4'} @@ -3930,6 +4166,11 @@ packages: property-information: 6.4.1 space-separated-tokens: 2.0.2 + /he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + dev: false + /hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} dev: true @@ -4712,7 +4953,6 @@ packages: /lru-cache@10.2.0: resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==} engines: {node: 14 || >=16.14} - dev: true /lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -4725,6 +4965,13 @@ packages: dependencies: yallist: 4.0.0 + /magic-string@0.27.0: + resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/sourcemap-codec': 1.4.15 + dev: false + /magic-string@0.30.5: resolution: {integrity: sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==} engines: {node: '>=12'} @@ -5396,6 +5643,13 @@ packages: dependencies: brace-expansion: 1.1.11 + /minimatch@7.4.6: + resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + dev: false + /minimatch@9.0.3: resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} engines: {node: '>=16 || 14 >=14.17'} @@ -5422,6 +5676,11 @@ packages: yallist: 4.0.0 dev: false + /minipass@4.2.8: + resolution: {integrity: sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==} + engines: {node: '>=8'} + dev: false + /minipass@5.0.0: resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} engines: {node: '>=8'} @@ -5430,7 +5689,6 @@ packages: /minipass@7.0.4: resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} engines: {node: '>=16 || 14 >=14.17'} - dev: true /minizlib@2.1.2: resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} @@ -5541,6 +5799,13 @@ packages: hasBin: true dev: false + /node-html-parser@6.1.12: + resolution: {integrity: sha512-/bT/Ncmv+fbMGX96XG9g05vFt43m/+SYKIs9oAemQVYyVcZmDAI2Xq/SbNcpOA35eF0Zk2av3Ksf+Xk8Vt8abA==} + dependencies: + css-select: 5.1.0 + he: 1.2.0 + dev: false + /node-releases@2.0.14: resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} @@ -5827,7 +6092,6 @@ packages: dependencies: lru-cache: 10.2.0 minipass: 7.0.4 - dev: true /path-to-regexp@6.2.1: resolution: {integrity: sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==} @@ -5962,6 +6226,11 @@ packages: transitivePeerDependencies: - supports-color + /progress@2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} + dev: false + /prompts@2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} @@ -5972,6 +6241,10 @@ packages: /property-information@6.4.1: resolution: {integrity: sha512-OHYtXfu5aI2sS2LWFSN5rgJjrQ4pCy8i1jubJLe2QvMF8JJ++HXTUIVWFLfXJoaOfvYYjk2SN8J2wFUWIGXT4w==} + /proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + dev: false + /pump@3.0.0: resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} requiresBuild: true @@ -7151,6 +7424,15 @@ packages: unist-util-is: 6.0.0 unist-util-visit-parents: 6.0.1 + /unplugin@1.0.1: + resolution: {integrity: sha512-aqrHaVBWW1JVKBHmGo33T5TxeL0qWzfvjWokObHA9bYmN7eNDkwOxmLjhioHl9878qDFMAaT51XNroRyuz7WxA==} + dependencies: + acorn: 8.11.3 + chokidar: 3.5.3 + webpack-sources: 3.2.3 + webpack-virtual-modules: 0.5.0 + dev: false + /update-browserslist-db@1.0.13(browserslist@4.22.3): resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} hasBin: true @@ -7502,6 +7784,15 @@ packages: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} dev: false + /webpack-sources@3.2.3: + resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==} + engines: {node: '>=10.13.0'} + dev: false + + /webpack-virtual-modules@0.5.0: + resolution: {integrity: sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==} + dev: false + /whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} dependencies: diff --git a/src/utils/csp-hash.ts b/src/utils/csp-hash.ts new file mode 100644 index 0000000..ff4bffb --- /dev/null +++ b/src/utils/csp-hash.ts @@ -0,0 +1,39 @@ +import type { AstroIntegration } from 'astro'; +import { fileURLToPath } from 'node:url'; +import { parse } from 'node-html-parser'; +import { readFile } from 'node:fs/promises'; + +const createCspHash = async (s: string) => { + const hashBuffer = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(s)); + const hashBase64 = btoa(String.fromCharCode(...new Uint8Array(hashBuffer))); + + return `'sha256-${hashBase64}'`; +}; + +export const astroCSPHashGenerator: AstroIntegration = { + name: 'astro-csp-hash-generator', + hooks: { + 'astro:build:done': async ({ dir, pages, logger }) => { + let hashes = []; + for (let i = 0; i < pages.length; i++) { + const filePath = fileURLToPath(`${dir.href}${pages[i]?.pathname}index.html`); + + try { + const root = parse(await readFile(filePath, { encoding: 'utf-8' })); + const scripts = root.querySelectorAll('script'); + + for (let j = 0; j < scripts.length; j++) { + const s = scripts[j]; + if (s !== undefined && s?.textContent !== undefined) { + const hash = await createCspHash(s?.textContent); + hashes.push(hash); + } + } + } catch (e) { + logger.error(`Cannot read file ${filePath}: ${e}`); + } + } + logger.info(hashes.join(' ')); + }, + }, +}; diff --git a/vercel.json b/vercel.json new file mode 100644 index 0000000..1d855d6 --- /dev/null +++ b/vercel.json @@ -0,0 +1,80 @@ +{ + "framework": "astro", + "cleanUrls": true, + "trailingSlash": false, + "headers": [ + { + "source": "/service-worker.js", + "headers": [ + { + "key": "Cache-Control", + "value": "public, max-age=0, must-revalidate" + } + ] + }, + { + "source": "/(.*)", + "headers": [ + { + "key": "Content-Security-Policy", + "value": "base-uri 'self'; font-src 'self' data: https://*.resurse.dev https://assets.vercel.com; form-action 'self' https://resurse.dev https://*.resurse.dev; frame-ancestors 'self' https://*.resurse.dev; img-src 'self' https: data: https://*.resurse.dev; media-src 'self' https: data: https://*.resurse.dev https://*.youtube.com https://*.youtube-nocookie.com; object-src 'none'; script-src-attr 'none'; style-src 'self' https://*.resurse.dev; script-src 'self' 'https://mir.aculo.us/' 'sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=' 'sha256-lqmxBU0DSNZSjDq7cbo8xTfsaMru8pCfYf7WgXwuD9E=' 'sha256-ipVu24fJB4N9VK6cLL0TmioKXqjvYwd6zJ/Sn+5suLg=' https://*.resurse.dev https://*.simpleanalyticscdn.com/ https://*.googletagmanager.com https://*.google-analytics.com https://*.google.com https://*.googleadservices.com https://vercel.live https://cdn.vercel-insights.com https://va.vercel-scripts.com https://*.sentry.com https://*.sentry-cdn.com https://*.usefathom.com; upgrade-insecure-requests; default-src 'self' https://*.resurse.dev; worker-src 'self' blob:; connect-src 'self' ws: wss: https://*.resurse.dev https://*.simpleanalyticscdn.com https://google-analytics.com https://*.google-analytics.com https://analytics.google.com https://*.analytics.google.com https://googletagmanager.com https://*.googletagmanager.com https://stats.g.doubleclick.net https://adservice.google.com https://www.google.co.in https://www.google.com https://www.google.id https://www.google.com.br https://www.google.co.uk https://www.google.ca https://www.google.com.au https://www.google.ro https://vitals.vercel-insights.com https://vitals.vercel-analytics.com https://vercel.live https://*.sentry.io https://*.usefathom.com; frame-src 'self' https://*.resurse.dev https://*.googletagmanager.com https://*.youtube.com https://*.youtube-nocookie.com https://td.doubleclick.net https://vars.hotjar.com https://vercel.live https://*.linkedin.com; report-uri https://o4506599007911936.ingest.sentry.io/api/4506661195808768/security/?sentry_key=344f761c5efeb4b9ea6b08942c01f5b6&sentry_environment=production;" + }, + { + "key": "Permissions-Policy", + "value": "accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), cross-origin-isolated=(), display-capture=(), document-domain=(), encrypted-media=(), execution-while-not-rendered=(), execution-while-out-of-viewport=(), fullscreen=(self), geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), navigation-override=(), payment=(), picture-in-picture=(self), publickey-credentials-get=(), screen-wake-lock=(), sync-xhr=(self), usb=(), web-share=(self), xr-spatial-tracking=(), clipboard-read=(self), clipboard-write=(self), gamepad=(), speaker-selection=(self), conversion-measurement=(self), focus-without-user-activation=(), hid=(self), idle-detection=(), interest-cohort=(), serial=(), sync-script=()" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "https://resurse.dev, https://*.resurse.dev, https://*.simpleanalyticscdn.com, https://vercel.live, https://*.vercel-insights.com, https://*.vercel-scripts.com, https://*.sentry.com, https://*.sentry-cdn.com" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "GET, POST, OPTIONS" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=63072000; includeSubDomains; preload" + }, + { + "key": "Referrer-Policy", + "value": "no-referrer, same-origin, origin-when-cross-origin" + }, + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-Frame-Options", + "value": "SAMEORIGIN" + }, + { + "key": "X-XSS-Protection", + "value": "1; mode=block" + }, + { + "key": "Cross-Origin-Opener-Policy", + "value": "same-origin" + }, + { + "key": "Cross-Origin-Embedder-Policy", + "value": "credentialless" + }, + { + "key": "Cross-Origin-Resource-Policy", + "value": "same-origin" + } + ] + } + ], + "redirects": [ + { + "source": "/old-url-path/", + "destination": "/new-url-path", + "permanent": true + }, + { + "source": "/view-source", + "destination": "https://github.com/ViorelMocanu/digital-resources" + } + ] +}