From 1c782750064f93c02aa7f92552dd2e188ee0da1f Mon Sep 17 00:00:00 2001 From: CodeWithMaBot <310216433+CodeWithMaBot@users.noreply.github.com> Date: Sat, 5 Sep 2026 11:25:56 +0200 Subject: [PATCH] feat: add CSP and security headers for web deployments --- Dockerfile | 1 + angular.json | 8 ++++++++ nginx.conf | 31 +++++++++++++++++++++++++++++++ src/index.html | 9 +++++++++ 4 files changed, 49 insertions(+) create mode 100644 nginx.conf diff --git a/Dockerfile b/Dockerfile index 91e325c..21ccace 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,6 +20,7 @@ RUN bun run build FROM nginx:alpine-slim AS prod +COPY nginx.conf /etc/nginx/conf.d/default.conf COPY --from=builder /app/builder/dist/watch-list/browser /usr/share/nginx/html EXPOSE 80 diff --git a/angular.json b/angular.json index 91e40c3..0094e88 100644 --- a/angular.json +++ b/angular.json @@ -39,6 +39,14 @@ }, "configurations": { "production": { + "optimization": { + "scripts": true, + "styles": { + "minify": true, + "inlineCritical": false + }, + "fonts": true + }, "budgets": [ { "type": "initial", diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..9bc5bd6 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,31 @@ +# Production server for the Docker image (copied to +# /etc/nginx/conf.d/default.conf in the Dockerfile). +# +# The Content-Security-Policy here must stay in sync with the fallback +# in src/index.html (GitHub Pages cannot send custom HTTP headers, so the meta +# tag is its only enforcement). If the inline theme script in index.html +# changes, recompute its sha256 and update script-src in both places. +# +# Policy notes: +# - img-src allows blob:/data:/https: (IndexedDB posters via object URLs, +# inline SVG placeholder, TMDB/MyAnimeList/AniList CDN posters). +# - connect-src enumerates the API + image origins the app fetches from +# (poster save uses fetch() on image CDN URLs, so those need connect-src). +# - style-src 'unsafe-inline' is required: Angular injects component styles +# at runtime. No external stylesheets are used. +server { + listen 80; + server_name _; + + root /usr/share/nginx/html; + index index.html; + + add_header Content-Security-Policy "default-src 'self'; base-uri 'self'; form-action 'self'; object-src 'none'; frame-ancestors 'none'; script-src 'self' 'sha256-MEU5LmGgErYBNZ8qIkvEKZWSLfoRWEtbAbW+YA5ToCE='; style-src 'self' 'unsafe-inline'; img-src 'self' blob: data: https:; connect-src 'self' https://api.themoviedb.org https://api.jikan.moe https://graphql.anilist.co https://image.tmdb.org https://cdn.myanimelist.net https://s4.anilist.co; font-src 'self' data:; manifest-src 'self'; worker-src 'self'" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-Frame-Options "DENY" always; + add_header Referrer-Policy "no-referrer" always; + + location / { + try_files $uri $uri/ /index.html; + } +} diff --git a/src/index.html b/src/index.html index 80ffada..8a153da 100644 --- a/src/index.html +++ b/src/index.html @@ -2,6 +2,15 @@
+ + +