fix(security): audit batch B — SPA CSP/security headers + vite upgrade
Implements AUDIT_REPORT.md M-2 and M-5: - M-2: CSP (script-src 'self'; frame-ancestors 'none'; object-src 'none'; ...), nosniff, X-Frame-Options DENY, Referrer-Policy on the SPA nginx, plus gzip for the bundle. The inline theme bootstrap moved to /theme-init.js so script-src 'self' holds with no inline scripts. - M-5: vite 5 -> 8 (+ plugin-react 6) — clears the dev-only esbuild advisories; npm audit now reports 0 vulnerabilities including dev deps. Build verified. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+2
-10
@@ -5,16 +5,8 @@
|
|||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>InboxIntel — Gmail analytics & cleanup</title>
|
<title>InboxIntel — Gmail analytics & cleanup</title>
|
||||||
<script>
|
<!-- Theme applied before first paint; external file so CSP can use script-src 'self'. -->
|
||||||
// Apply the saved theme before first paint to avoid a flash of the wrong mode.
|
<script src="/theme-init.js"></script>
|
||||||
(function () {
|
|
||||||
try {
|
|
||||||
// Dark-first: default new users to dark unless they've chosen light.
|
|
||||||
var t = localStorage.getItem('ii:theme') || 'dark';
|
|
||||||
if (t === 'dark') document.documentElement.classList.add('dark');
|
|
||||||
} catch (e) {}
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -4,6 +4,19 @@ server {
|
|||||||
root /usr/share/nginx/html;
|
root /usr/share/nginx/html;
|
||||||
index index.html;
|
index index.html;
|
||||||
|
|
||||||
|
# AUDIT M-2: security headers on the SPA. script-src 'self' works because the theme
|
||||||
|
# bootstrap lives in /theme-init.js (no inline scripts); style-src needs 'unsafe-inline'
|
||||||
|
# for React/Chart.js/grid-layout inline style attributes (low risk with script-src locked).
|
||||||
|
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'" always;
|
||||||
|
add_header X-Content-Type-Options "nosniff" always;
|
||||||
|
add_header X-Frame-Options "DENY" always;
|
||||||
|
add_header Referrer-Policy "no-referrer" always;
|
||||||
|
|
||||||
|
# Compress the SPA bundle (AUDIT perf note: ~680 KB JS).
|
||||||
|
gzip on;
|
||||||
|
gzip_types text/css application/javascript application/json image/svg+xml;
|
||||||
|
gzip_min_length 1024;
|
||||||
|
|
||||||
# SPA fallback.
|
# SPA fallback.
|
||||||
location / {
|
location / {
|
||||||
try_files $uri $uri/ /index.html;
|
try_files $uri $uri/ /index.html;
|
||||||
|
|||||||
Generated
+535
-1113
File diff suppressed because it is too large
Load Diff
@@ -35,10 +35,10 @@
|
|||||||
"tailwind-merge": "^3.6.0"
|
"tailwind-merge": "^3.6.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-react": "^4.3.1",
|
"@vitejs/plugin-react": "^6.0.3",
|
||||||
"autoprefixer": "^10.5.2",
|
"autoprefixer": "^10.5.2",
|
||||||
"postcss": "^8.5.16",
|
"postcss": "^8.5.16",
|
||||||
"tailwindcss": "^3.4.19",
|
"tailwindcss": "^3.4.19",
|
||||||
"vite": "^5.3.1"
|
"vite": "^8.1.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// Applied before first paint to avoid a flash of the wrong theme. Lives in a file (not
|
||||||
|
// inline) so the SPA can ship a CSP with script-src 'self' (AUDIT M-2).
|
||||||
|
(function () {
|
||||||
|
try {
|
||||||
|
// Dark-first: default new users to dark unless they've chosen light.
|
||||||
|
var t = localStorage.getItem('ii:theme') || 'dark';
|
||||||
|
if (t === 'dark') document.documentElement.classList.add('dark');
|
||||||
|
} catch (e) {}
|
||||||
|
})();
|
||||||
Reference in New Issue
Block a user