Compare commits

..

5 Commits

Author SHA1 Message Date
will.anderson c30e5903a4 Merge pull request 'Allow Google Analytics and Ads domains in CSP' (#154) from fix/csp-analytics into dev
Dev — Build & local smoke test / build-smoke (push) Successful in 2m5s
2026-05-19 17:53:52 +00:00
will.anderson c526e76d3b Allow Google Analytics and Ads domains in CSP
Dev — Build & local smoke test / build-smoke (pull_request) Successful in 1m34s
Add to connect-src: analytics.google.com, www.google.com,
www.googletagmanager.com — required for GA event beacons and
Google Ads conversion/remarketing collect endpoints.

Add to script-src: googleads.g.doubleclick.net — required for
Google Ads conversion tag script injection via GTM.
2026-05-19 12:53:36 -05:00
will.anderson 6a7b8382ea Merge pull request 'Fix SyntaxError in account-dashboard and expand CSP' (#152) from fix/syntax-error-and-csp into dev
Dev — Build & local smoke test / build-smoke (push) Successful in 2m7s
2026-05-19 17:13:39 +00:00
will.anderson d2ae0b4b60 Fix SyntaxError in account-dashboard and expand CSP
Dev — Build & local smoke test / build-smoke (pull_request) Successful in 1m37s
Replace ternary operator in native_js block with explicit if-else —
El's parser chokes on '?' adjacent to single-quoted strings inside
native_js(), causing an Uncaught SyntaxError that prevents the entire
IIFE from running and leaves signInWith undefined.

Add missing CSP entries to all three header functions:
- js.stripe.com → script-src and frame-src (Stripe JS and Elements iframe)
- fonts.googleapis.com → style-src (Google Fonts CSS)
- fonts.gstatic.com → font-src (Google Fonts files)
- static.cloudflareinsights.com → script-src (Cloudflare beacon)
2026-05-19 12:13:05 -05:00
will.anderson 5c8987ef59 Merge pull request 'Clear hardcoded device count — JS owns it' (#150) from fix/devices-count-v2 into dev
Dev — Build & local smoke test / build-smoke (push) Successful in 2m35s
2026-05-14 16:38:26 +00:00
2 changed files with 6 additions and 6 deletions
+3 -3
View File
@@ -105,9 +105,9 @@ fn main() -> Void {
var devicesEl = document.getElementById('devices-count-el');
if (devicesEl) {
devicesEl.textContent = (plan === 'free')
? '1 device included with your plan'
: '2 devices included with your plan';
var deviceText = '2 devices included with your plan';
if (plan === 'free') { deviceText = '1 device included with your plan'; }
devicesEl.textContent = deviceText;
}
var meta = '';
+3 -3
View File
@@ -2317,7 +2317,7 @@ fn sec_headers_json() -> String {
+ "\"X-Frame-Options\":\"SAMEORIGIN\","
+ "\"Referrer-Policy\":\"strict-origin-when-cross-origin\","
+ "\"Permissions-Policy\":\"geolocation=(), microphone=(), camera=()\","
+ "\"Content-Security-Policy\":\"default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://challenges.cloudflare.com https://cdn.jsdelivr.net https://www.googletagmanager.com https://www.google-analytics.com; style-src 'self' 'unsafe-inline'; frame-src https://challenges.cloudflare.com; connect-src 'self' https://api.stripe.com https://*.supabase.co; img-src 'self' data: https:; font-src 'self' data:\"}"
+ "\"Content-Security-Policy\":\"default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://challenges.cloudflare.com https://cdn.jsdelivr.net https://googleads.g.doubleclick.net https://js.stripe.com https://static.cloudflareinsights.com https://www.googletagmanager.com https://www.google-analytics.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; frame-src https://challenges.cloudflare.com https://js.stripe.com; connect-src 'self' https://analytics.google.com https://api.stripe.com https://*.supabase.co https://www.google.com https://www.googletagmanager.com; img-src 'self' data: https:; font-src 'self' data: https://fonts.gstatic.com\"}"
}
// Headers for compiled JS assets. Explicitly sets Content-Type so the browser
@@ -2333,7 +2333,7 @@ fn js_headers_json() -> String {
+ "\"X-Frame-Options\":\"SAMEORIGIN\","
+ "\"Referrer-Policy\":\"strict-origin-when-cross-origin\","
+ "\"Permissions-Policy\":\"geolocation=(), microphone=(), camera=()\","
+ "\"Content-Security-Policy\":\"default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://challenges.cloudflare.com https://cdn.jsdelivr.net https://www.googletagmanager.com https://www.google-analytics.com; style-src 'self' 'unsafe-inline'; frame-src https://challenges.cloudflare.com; connect-src 'self' https://api.stripe.com https://*.supabase.co; img-src 'self' data: https:; font-src 'self' data:\"}"
+ "\"Content-Security-Policy\":\"default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://challenges.cloudflare.com https://cdn.jsdelivr.net https://googleads.g.doubleclick.net https://js.stripe.com https://static.cloudflareinsights.com https://www.googletagmanager.com https://www.google-analytics.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; frame-src https://challenges.cloudflare.com https://js.stripe.com; connect-src 'self' https://analytics.google.com https://api.stripe.com https://*.supabase.co https://www.google.com https://www.googletagmanager.com; img-src 'self' data: https:; font-src 'self' data: https://fonts.gstatic.com\"}"
}
// Headers for static assets under /assets/ and /brand/.
@@ -2349,7 +2349,7 @@ fn static_asset_headers_json() -> String {
+ "\"X-Frame-Options\":\"SAMEORIGIN\","
+ "\"Referrer-Policy\":\"strict-origin-when-cross-origin\","
+ "\"Permissions-Policy\":\"geolocation=(), microphone=(), camera=()\","
+ "\"Content-Security-Policy\":\"default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://challenges.cloudflare.com https://cdn.jsdelivr.net https://www.googletagmanager.com https://www.google-analytics.com; style-src 'self' 'unsafe-inline'; frame-src https://challenges.cloudflare.com; connect-src 'self' https://api.stripe.com https://*.supabase.co; img-src 'self' data: https:; font-src 'self' data:\"}"
+ "\"Content-Security-Policy\":\"default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://challenges.cloudflare.com https://cdn.jsdelivr.net https://googleads.g.doubleclick.net https://js.stripe.com https://static.cloudflareinsights.com https://www.googletagmanager.com https://www.google-analytics.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; frame-src https://challenges.cloudflare.com https://js.stripe.com; connect-src 'self' https://analytics.google.com https://api.stripe.com https://*.supabase.co https://www.google.com https://www.googletagmanager.com; img-src 'self' data: https:; font-src 'self' data: https://fonts.gstatic.com\"}"
}
fn handle_request(method: String, path: String, headers: Map, body: String) -> String {