code wiki / (root) / nx_fin_route_gate.nx

nx_fin_route_gate.nx source

↩ module page · 166 lines · 9487 B

1// nx_fin_route_gate.nx -- proves nishifamily.com/finance is correctly served BEHIND THE OPAQUE WALL. 2// Drives the shared route table (olg_route) in-process, exactly as the daemon would, with a real OPAQUE 3// ctx (temp /tmp keys/store; light KSF for test speed, like nx_opaque_login_gate): 4// (a) GET /finance with NO session -> 401, and the page does NOT leak (no brand bytes in the response) 5// (b) GET /finance with a VALID Ed25519 no-cookie token -> 200 OK + the zero-JS dashboard (brand + live 6// engine output present, NO <script over the wire, served as text/html) 7// This is the integration proof of "finance behind the opaque system" AND a compile-check of the new 8// route. It does NOT touch the live daemon -- activation in production = an operator-coordinated daemon 9// rebuild/restart (the daemon imports this same route table). Exits 0 iff ALL pass. license_tier: ORIGINAL 10import "nx_opaque_login_routes.nx" 11import "nx_opaque_login.nx" 12import "nx_syscalls.nx" 13 14func g_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 15func g_putn(v: i64) -> i64 { 16 if v == 0 { sys_write(1, "0" as *u8, 1); return 0 } 17 var m: i64 = v; if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m } 18 let d: *u8 = sys_mmap(24); var k: i64 = 0 19 while m > 0 { d[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 20 var j: i64 = k - 1 21 while j >= 0 { sys_write(1, ((d as i64)+j) as *u8, 1); j = j - 1 } 22 return 0 23} 24func chk(name: *u8, got: i64, want: i64, st: *i64) -> i64 { 25 if got == want { st[0] = st[0] + 1; g_puts(" PASS "); g_puts(name); g_puts("\n") } 26 else { st[1] = st[1] + 1; g_puts(" FAIL "); g_puts(name); g_puts(" got="); g_putn(got); g_puts(" want="); g_putn(want); g_puts("\n") } 27 return 0 28} 29func rfind(hay: *u8, n: i64, needle: *u8) -> i64 { 30 var nl: i64 = 0; while needle[nl] != (0 as u8) { nl = nl + 1 } 31 if nl == 0 { return 0 } 32 var i: i64 = 0 33 while i + nl <= n { 34 var j: i64 = 0; var ok: i64 = 1 35 while j < nl { if hay[i + j] != needle[j] { ok = 0; j = nl } else { j = j + 1 } } 36 if ok == 1 { return i } 37 i = i + 1 38 } 39 return 0 - 1 40} 41func cpstr(dst: *u8, off: i64, s: *u8) -> i64 { var o: i64 = off; var i: i64 = 0; while s[i] != (0 as u8) { dst[o] = s[i]; o = o + 1; i = i + 1 } return o } 42func cpbuf(dst: *u8, off: i64, src: *u8, n: i64) -> i64 { var o: i64 = off; var i: i64 = 0; while i < n { dst[o] = src[i]; o = o + 1; i = i + 1 } return o } 43func olg_trunc(path: *u8) -> i64 { let fd: i64 = sys_openat_wr(path, 0x1a4); if fd >= 0 { sys_close(fd) } return 0 } 44 45func main() -> i64 { 46 let st: *i64 = sys_mmap(16) as *i64 47 st[0] = 0; st[1] = 0 48 49 let keys: *u8 = "/tmp/nx_finroute_keys.log\x00" as *u8 50 let store: *u8 = "/tmp/nx_finroute_store.log\x00" as *u8 51 olg_trunc(keys); olg_trunc(store) 52 let ctx: *NxAuthContext = sys_mmap(256) as *NxAuthContext 53 if olg_ctx_setup(ctx, keys, store, "nishi_site_admin" as *u8, 16, "Nishi site admin" as *u8, 16, 8192, 1, 1) != 0 { 54 g_puts("ctx-setup FAIL\n"); return 1 55 } 56 let pw: *u8 = "correct horse battery staple" as *u8 57 let mn: *u8 = sys_mmap(512); let mnn: *i64 = sys_mmap(16) as *i64 58 if olg_register(ctx, "elder" as *u8, 5, pw, 28, mn, 512, mnn) != NX_MAUTH_OK { g_puts("register FAIL\n"); return 2 } 59 let b64: *u8 = sys_mmap(512); let b64n: *i64 = sys_mmap(16) as *i64 60 if olg_login(ctx, "elder" as *u8, 5, pw, 28, b64, 512, b64n) != NX_MAUTH_OK { g_puts("login FAIL\n"); return 3 } 61 let now: i64 = sys_now_realtime_sec() 62 let resp: *u8 = sys_mmap(262144) 63 64 // (a) NO session -> 401, no page leak 65 let req1: *u8 = "GET /finance HTTP/1.1\r\nHost: nishifamily\r\n\r\n\x00" as *u8 66 var r1n: i64 = 0; while req1[r1n] != (0 as u8) { r1n = r1n + 1 } 67 let n1: i64 = olg_route(ctx, req1, r1n, now, resp, 262144) 68 var is401: i64 = 0 69 if rfind(resp, n1, "401\x00" as *u8) >= 0 { is401 = 1 } 70 chk("no-session /finance -> 401 Unauthorized", is401, 1, st) 71 var leak: i64 = 0 72 if rfind(resp, n1, "Nishi Finance\x00" as *u8) >= 0 { leak = 1 } 73 chk("no-session /finance leaks NO dashboard bytes", leak, 0, st) 74 75 // (b) valid session -> 200 + the zero-JS dashboard 76 let req2: *u8 = sys_mmap(2048) 77 var o: i64 = 0 78 o = cpstr(req2, o, "GET /finance HTTP/1.1\r\nX-Nishi-Session: \x00" as *u8) 79 o = cpbuf(req2, o, b64, b64n[0]) 80 o = cpstr(req2, o, "\r\nHost: nishifamily\r\n\r\n\x00" as *u8) 81 let r2n: i64 = o 82 let n2: i64 = olg_route(ctx, req2, r2n, now, resp, 262144) 83 var is200: i64 = 0 84 if rfind(resp, n2, "200 OK\x00" as *u8) >= 0 { is200 = 1 } 85 chk("valid-session /finance -> 200 OK", is200, 1, st) 86 var brand: i64 = 0 87 if rfind(resp, n2, "Nishi Finance\x00" as *u8) >= 0 { brand = 1 } 88 chk("valid-session serves the dashboard (brand present)", brand, 1, st) 89 var av: i64 = 0 90 if rfind(resp, n2, "Avalanche\x00" as *u8) >= 0 { av = 1 } 91 chk("served page carries live engine output", av, 1, st) 92 var nojs: i64 = 0 93 if rfind(resp, n2, "<script\x00" as *u8) < 0 { nojs = 1 } 94 chk("served page is zero-JS over the wire", nojs, 1, st) 95 var html: i64 = 0 96 if rfind(resp, n2, "text/html\x00" as *u8) >= 0 { html = 1 } 97 chk("served as text/html", html, 1, st) 98 99 // ---- GET /finance/intake -> the intake form (more-specific route, before /finance) ---- 100 let req3: *u8 = sys_mmap(2048) 101 var o3: i64 = cpstr(req3, 0, "GET /finance/intake HTTP/1.1\r\nX-Nishi-Session: \x00" as *u8) 102 o3 = cpbuf(req3, o3, b64, b64n[0]) 103 o3 = cpstr(req3, o3, "\r\nHost: nishifamily\r\n\r\n\x00" as *u8) 104 let n3: i64 = olg_route(ctx, req3, o3, now, resp, 262144) 105 var hasform: i64 = 0 106 if rfind(resp, n3, "Save my situation\x00" as *u8) >= 0 { hasform = 1 } 107 chk("GET /finance/intake -> serves the intake form", hasform, 1, st) 108 109 // ---- POST /finance/intake -> records the submission + Saved ---- 110 let req4: *u8 = sys_mmap(2048) 111 var o4: i64 = cpstr(req4, 0, "POST /finance/intake HTTP/1.1\r\nX-Nishi-Session: \x00" as *u8) 112 o4 = cpbuf(req4, o4, b64, b64n[0]) 113 o4 = cpstr(req4, o4, "\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\nincome_monthly=4000&debt_balance=20000&hourly_wage=25&has_adhd=1\x00" as *u8) 114 let n4: i64 = olg_route(ctx, req4, o4, now, resp, 262144) 115 var post200: i64 = 0 116 if rfind(resp, n4, "200 OK\x00" as *u8) >= 0 { post200 = 1 } 117 chk("POST /finance/intake -> 200 OK", post200, 1, st) 118 var saved: i64 = 0 119 if rfind(resp, n4, "Saved\x00" as *u8) >= 0 { saved = 1 } 120 chk("POST /finance/intake -> recorded the submission (Saved)", saved, 1, st) 121 122 // ---- POST /finance/progress: mark the user's next climb step done -> 303 back to /finance ---- 123 // no session -> 401 (you cannot advance someone's progress unauthenticated) 124 let req5: *u8 = "POST /finance/progress HTTP/1.1\r\nContent-Length: 0\r\nHost: nishifamily\r\n\r\n\x00" as *u8 125 var r5n: i64 = 0; while req5[r5n] != (0 as u8) { r5n = r5n + 1 } 126 let n5: i64 = olg_route(ctx, req5, r5n, now, resp, 262144) 127 var pg401: i64 = 0 128 if rfind(resp, n5, "401\x00" as *u8) >= 0 { pg401 = 1 } 129 chk("no-session /finance/progress -> 401 (session-gated)", pg401, 1, st) 130 // valid session -> 303 See Other, Location: /finance (post-redirect-get) 131 let req6: *u8 = sys_mmap(2048) 132 var o6: i64 = cpstr(req6, 0, "POST /finance/progress HTTP/1.1\r\nX-Nishi-Session: \x00" as *u8) 133 o6 = cpbuf(req6, o6, b64, b64n[0]) 134 o6 = cpstr(req6, o6, "\r\nContent-Length: 0\r\nHost: nishifamily\r\n\r\n\x00" as *u8) 135 let n6: i64 = olg_route(ctx, req6, o6, now, resp, 262144) 136 var pg303: i64 = 0 137 if rfind(resp, n6, "303 See Other\x00" as *u8) >= 0 { pg303 = 1 } 138 chk("valid-session /finance/progress -> 303 (marks a step, redirects)", pg303, 1, st) 139 var pgloc: i64 = 0 140 if rfind(resp, n6, "Location: /finance\x00" as *u8) >= 0 { pgloc = 1 } 141 chk("/finance/progress redirects to /finance (post-redirect-get)", pgloc, 1, st) 142 143 // ---- POST /finance/bills: record one bill -> 303 back to /finance ---- 144 let req7: *u8 = "POST /finance/bills HTTP/1.1\r\nContent-Length: 0\r\nHost: nishifamily\r\n\r\n\x00" as *u8 145 var r7n: i64 = 0; while req7[r7n] != (0 as u8) { r7n = r7n + 1 } 146 let n7: i64 = olg_route(ctx, req7, r7n, now, resp, 262144) 147 var pb401: i64 = 0 148 if rfind(resp, n7, "401\x00" as *u8) >= 0 { pb401 = 1 } 149 chk("no-session /finance/bills -> 401 (session-gated)", pb401, 1, st) 150 let req8: *u8 = sys_mmap(2048) 151 var o8: i64 = cpstr(req8, 0, "POST /finance/bills HTTP/1.1\r\nX-Nishi-Session: \x00" as *u8) 152 o8 = cpbuf(req8, o8, b64, b64n[0]) 153 o8 = cpstr(req8, o8, "\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\nbill_amount=180&bill_cadence=1&bill_due_day=5&bill_category=1&bill_paid=0\x00" as *u8) 154 let n8: i64 = olg_route(ctx, req8, o8, now, resp, 262144) 155 var pb303: i64 = 0 156 if rfind(resp, n8, "303 See Other\x00" as *u8) >= 0 { pb303 = 1 } 157 chk("valid-session /finance/bills -> 303 (records the bill, redirects)", pb303, 1, st) 158 var pbloc: i64 = 0 159 if rfind(resp, n8, "Location: /finance\x00" as *u8) >= 0 { pbloc = 1 } 160 chk("/finance/bills redirects to /finance (post-redirect-get)", pbloc, 1, st) 161 162 g_puts("nx_fin_route_gate: PASS="); g_putn(st[0]); g_puts(" FAIL="); g_putn(st[1]); g_puts("\n") 163 if st[1] == 0 { g_puts("FINANCE BEHIND OPAQUE: GREEN\n"); return 0 } 164 g_puts("FINANCE BEHIND OPAQUE: RED\n") 165 return 1 166}