Compare commits

..

12 Commits

Author SHA1 Message Date
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 bfcb325352 Clear hardcoded device count — JS sets it from plan data
Dev — Build & local smoke test / build-smoke (pull_request) Successful in 1m54s
2026-05-14 11:38:05 -05:00
will.anderson 57e9cafc95 Merge pull request 'Fix device count: 1 for free, 2 for professional/founding' (#148) from fix/devices-count into dev
Dev — Build & local smoke test / build-smoke (push) Successful in 2m13s
2026-05-14 16:36:20 +00:00
will.anderson 632d95000c Fix device count: show 1 for free plan, 2 for professional/founding
Dev — Build & local smoke test / build-smoke (pull_request) Successful in 1m38s
2026-05-14 11:36:02 -05:00
will.anderson 77807d30af Merge pull request 'Fix account SIGSEGV: el_meta 1-arg → 2-arg' (#146) from fix/account-el-meta into dev
Dev — Build & local smoke test / build-smoke (push) Successful in 2m13s
2026-05-13 17:41:53 +00:00
will.anderson 8f91a80be7 Fix account page SIGSEGV: el_meta extern arity mismatch (1-arg → 2-arg)
Dev — Build & local smoke test / build-smoke (pull_request) Successful in 1m42s
el_meta was declared as el_meta(attrs) in account.el but the runtime
C implementation expects el_meta(name, content). Same arity crash as
the prior el_img fix — runtime passed garbage on the stack.
2026-05-13 12:41:37 -05:00
will.anderson d7bb92c37f Merge pull request 'Fix account page SIGSEGV: el_img extern arity mismatch' (#144) from fix/magic-link-flow into dev
Dev — Build & local smoke test / build-smoke (push) Successful in 2m20s
2026-05-13 17:20:06 +00:00
will.anderson 4ca793ee2c Fix account page SIGSEGV: el_img extern signature mismatch
Dev — Build & local smoke test / build-smoke (pull_request) Successful in 1m46s
account.el declared el_img with 1 arg (attrs only) while the runtime
implementation and all other files use 3 args (src, alt, attrs).
The arity mismatch caused the server to crash with signal 11 on every
request — TCP probe passed (bind was fine) but first HTTP hit segfaulted.
2026-05-13 12:19:43 -05:00
will.anderson 4123f6d5f1 Merge pull request 'Fix free plan checkout: SetupIntent instead of $0 PaymentIntent' (#142) from fix/free-plan-setup-intent into dev
Dev — Build & local smoke test / build-smoke (push) Successful in 1m59s
Fix free plan checkout: SetupIntent instead of $0 PaymentIntent
2026-05-13 17:12:35 +00:00
will.anderson 3d635505bc Merge pull request 'Fix about page: restore raw string syntax to fix El tokenizer rendering' (#140) from fix/about-rendering into dev
Dev — Build & local smoke test / build-smoke (push) Successful in 2m17s
Fix about page: restore raw string syntax to fix El tokenizer rendering
2026-05-13 16:46:43 +00:00
will.anderson 708dfd06cb Merge pull request 'Fix magic-link sign-in: implicit flow + redirect to /account' (#138) from fix/magic-link-flow into dev
Dev — Build & local smoke test / build-smoke (push) Successful in 2m14s
2026-05-12 19:33:03 +00:00
will.anderson bb98f76179 Merge pull request 'Fix duplicate Stripe customers and attestation plan bypass' (#136) from fix/stripe-dedup-attestation into dev
Dev — Build & local smoke test / build-smoke (push) Successful in 2m4s
2026-05-12 19:23:33 +00:00
3 changed files with 16 additions and 9 deletions
+6 -6
View File
@@ -5,7 +5,7 @@ from founding_badge import { founding_badge, founding_badge_css }
extern fn el_html_doc(lang: String, head: String, body: String) -> String
extern fn el_meta_charset(charset: String) -> String
extern fn el_meta(attrs: String) -> String
extern fn el_meta(name: String, content: String) -> String
extern fn el_title(text: String) -> String
extern fn el_link_stylesheet(href: String) -> String
extern fn el_script_src(src: String, defer_load: Bool) -> String
@@ -13,7 +13,7 @@ extern fn el_script_inline(code: String) -> String
extern fn el_nav(attrs: String, children: String) -> String
extern fn el_div(attrs: String, children: String) -> String
extern fn el_a(href: String, attrs: String, children: String) -> String
extern fn el_img(attrs: String) -> String
extern fn el_img(src: String, alt: String, attrs: String) -> String
extern fn el_p(attrs: String, children: String) -> String
extern fn el_h1(attrs: String, text: String) -> String
extern fn el_button(attrs: String, label: String) -> String
@@ -520,7 +520,7 @@ fn account_css() -> String {
}
fn account_nav() -> String {
let logo_img: String = el_img("src=\"/assets/brand/neuron-wordmark-on-light.png\" srcset=\"/assets/brand/neuron-wordmark-on-light@2x.png 2x\" alt=\"Neuron\" height=\"28\"")
let logo_img: String = el_img("/assets/brand/neuron-wordmark-on-light.png", "Neuron", "srcset=\"/assets/brand/neuron-wordmark-on-light@2x.png 2x\" height=\"28\"")
el_nav(
"id=\"nav\"",
el_div(
@@ -818,7 +818,7 @@ fn account_devices_card() -> String {
el_div("class=\"device-icon\"", account_signin_svg_device()) +
el_div(
"",
el_p("class=\"devices-count\"", "2 devices included with your plan") +
el_p("class=\"devices-count\" id=\"devices-count-el\"", "") +
el_p("class=\"devices-sub\"", "Currently: Setup at launch")
)
) +
@@ -965,9 +965,9 @@ fn account_dashboard_section() -> String {
fn account_page(supabase_url: String, supabase_anon_key: String) -> String {
let head: String =
el_meta_charset("UTF-8") +
el_meta("name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"") +
el_meta("viewport", "width=device-width, initial-scale=1.0") +
el_title("My Account - Neuron") +
el_meta("name=\"description\" content=\"Manage your Neuron account, view your plan, and access your founding member details.\"") +
el_meta("description", "Manage your Neuron account, view your plan, and access your founding member details.") +
"<link rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/assets/favicon-16.png\">" +
"<link rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/assets/favicon-32.png\">" +
"<link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">" +
+7
View File
@@ -103,6 +103,13 @@ fn main() -> Void {
}
setHtml('plan-billing-note-el', billingNote);
var devicesEl = document.getElementById('devices-count-el');
if (devicesEl) {
var deviceText = '2 devices included with your plan';
if (plan === 'free') { deviceText = '1 device included with your plan'; }
devicesEl.textContent = deviceText;
}
var meta = '';
if (createdAt) {
var d = new Date(createdAt);
+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://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://api.stripe.com https://*.supabase.co; 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://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://api.stripe.com https://*.supabase.co; 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://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://api.stripe.com https://*.supabase.co; 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 {