code wiki / _hdl_build / nx_gallery_gateway_smoke.nx
nx_gallery_gateway_smoke.nx source
↩ module page · 138 lines · 7637 B
1// nx_gallery_gateway_smoke.nx -- R1 GATE PROOF. Forks the gallery gateway and drives it as a real HTTP
2// client over the wire: register -> login -> GET /gallery/api/list (no token)=401 -> (valid token)=200
3// PROXIED from the live gallery (:18090) -> (bad token)=401 -> GET /gallery/sw.js=200 -> /gallery/login=200.
4// Proves the OPAQUE session gate + the reverse-proxy. Requires /tmp/nx_gallery_gateway.sov.elf built in the
5// same WSL session AND the gallery backend live on 127.0.0.1:18090. exit 0 = GREEN, N = assertion N failed.
6import "nx_syscalls.nx"
7import "nx_connect.nx" // bounded connect: a raw sys_connect hangs ~127s on a black-holed host
8import "nx_assert.nx"
9const SMK_MAGIC_8388608: i64 = 8388608
10const SMK_MAGIC_4096: i64 = 4096
11const SMK_MAGIC_8388607: i64 = 8388607
12
13const SMK_PORT: i64 = 18091
14const DAEMON_ELF: *u8 = "/tmp/nx_gallery_gateway.sov.elf" as *u8
15
16func smk_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
17func smk_find(buf: *u8, n: i64, needle: *u8, nl: i64) -> i64 {
18 if nl==0 { return 0 }
19 var i: i64=0
20 while i+nl<=n { var j: i64=0; var ok: i64=1; while j<nl { if buf[i+j]!=needle[j]{ok=0;j=nl} else {j=j+1} } if ok==1 {return i} i=i+1 }
21 return 0-1
22}
23func smk_http(req: *u8, reqn: i64, resp: *u8, cap: i64) -> i64 {
24 let fd: i64 = sys_socket(2, 1, 0); if fd < 0 { return 0-1 }
25 sys_set_socket_timeout(fd, 20)
26 let a: *u8 = sys_mmap(16)
27 a[0]=2 as u8; a[1]=0 as u8; a[2]=((SMK_PORT>>8)&0xff) as u8; a[3]=(SMK_PORT&0xff) as u8
28 a[4]=127 as u8; a[5]=0 as u8; a[6]=0 as u8; a[7]=1 as u8
29 var zi: i64=8; while zi<16 { a[zi]=0 as u8; zi=zi+1 }
30 if nx_connect_bounded(fd, a, 16, NX_CONN_DEFAULT_MS) != 0 { sys_close(fd); return 0-2 }
31 sys_write(fd, req, reqn)
32 var off: i64=0; var go: i64=1
33 while go==1 { let r: i64=sys_read(fd, ((resp as i64)+off) as *u8, cap-off); if r<=0 {go=0} else { off=off+r; if off>=cap {go=0} } }
34 sys_close(fd); return off
35}
36func smk_post(reqbuf: *u8, path: *u8, body: *u8) -> i64 {
37 let bl: i64 = smk_slen(body)
38 var o: i64=0
39 let p1: *u8="POST " as *u8; var i: i64=0; while p1[i]!=(0 as u8){reqbuf[o]=p1[i];o=o+1;i=i+1}
40 i=0; while path[i]!=(0 as u8){reqbuf[o]=path[i];o=o+1;i=i+1}
41 let p2: *u8=" HTTP/1.1\r\nHost: x\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: " as *u8; i=0; while p2[i]!=(0 as u8){reqbuf[o]=p2[i];o=o+1;i=i+1}
42 let t: *u8=sys_mmap(28); var m: i64=bl; var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var q: i64=k-1; while q>=0{reqbuf[o]=t[q];o=o+1;q=q-1}
43 let p3: *u8="\r\nConnection: close\r\n\r\n" as *u8; i=0; while p3[i]!=(0 as u8){reqbuf[o]=p3[i];o=o+1;i=i+1}
44 i=0; while body[i]!=(0 as u8){reqbuf[o]=body[i];o=o+1;i=i+1}
45 return o
46}
47// GET with optional X-Nishi-Session header (tok[0]==0 -> no header).
48func smk_get(reqbuf: *u8, path: *u8, tok: *u8) -> i64 {
49 var o: i64=0; var i: i64=0
50 let g: *u8="GET " as *u8; i=0; while g[i]!=(0 as u8){reqbuf[o]=g[i];o=o+1;i=i+1}
51 i=0; while path[i]!=(0 as u8){reqbuf[o]=path[i];o=o+1;i=i+1}
52 let h: *u8=" HTTP/1.1\r\nHost: x\r\n" as *u8; i=0; while h[i]!=(0 as u8){reqbuf[o]=h[i];o=o+1;i=i+1}
53 if tok[0]!=(0 as u8) {
54 let xs: *u8="X-Nishi-Session: " as *u8; i=0; while xs[i]!=(0 as u8){reqbuf[o]=xs[i];o=o+1;i=i+1}
55 i=0; while tok[i]!=(0 as u8){reqbuf[o]=tok[i];o=o+1;i=i+1}
56 reqbuf[o]=13 as u8; o=o+1; reqbuf[o]=10 as u8; o=o+1
57 }
58 let c: *u8="Connection: close\r\n\r\n" as *u8; i=0; while c[i]!=(0 as u8){reqbuf[o]=c[i];o=o+1;i=i+1}
59 return o
60}
61
62func main() -> i64 {
63 let kfd: i64=sys_openat_wr("/tmp/ggw_keys.log" as *u8, 0x1a4); if kfd>=0 {sys_close(kfd)}
64 let sfd: i64=sys_openat_wr("/tmp/ggw_store.log" as *u8, 0x1a4); if sfd>=0 {sys_close(sfd)}
65
66 let pid: i64 = sys_fork()
67 if pid == 0 {
68 let argv: *i64 = sys_mmap(96) as *i64
69 argv[0]=DAEMON_ELF as i64
70 argv[1]="18091" as *u8 as i64
71 argv[2]="/tmp/ggw_keys.log" as *u8 as i64
72 argv[3]="/tmp/ggw_store.log" as *u8 as i64
73 argv[4]="50" as *u8 as i64
74 argv[5]="18090" as *u8 as i64
75 argv[6]="1" as *u8 as i64
76 argv[7]="8192" as *u8 as i64
77 argv[8]="1" as *u8 as i64
78 argv[9]="1" as *u8 as i64
79 argv[10]=0
80 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
81 sys_execve(DAEMON_ELF, argv, envp)
82 sys_exit(127)
83 }
84 sys_sleep_ms(700)
85
86 let resp: *u8 = sys_mmap(SMK_MAGIC_8388608)
87 let req: *u8 = sys_mmap(SMK_MAGIC_4096)
88 let empty: *u8 = sys_mmap(4); empty[0]=0 as u8
89
90 let rqn: i64 = smk_post(req, "/gallery/auth/register" as *u8, "handle=tester&pw=testpass123" as *u8)
91 let r1: i64 = smk_http(req, rqn, resp, SMK_MAGIC_8388607)
92 nx_puts_err("register bytes=" as *u8); nx_puti_err(r1); nx_puts_err("\n" as *u8)
93 if smk_find(resp, r1, "200 OK" as *u8, 6) < 0 { nx_kill(pid,9); return 1 }
94 if smk_find(resp, r1, "mnemonic" as *u8, 8) < 0 { nx_kill(pid,9); return 2 }
95
96 let lqn: i64 = smk_post(req, "/gallery/auth/login" as *u8, "handle=tester&pw=testpass123" as *u8)
97 let r2: i64 = smk_http(req, lqn, resp, SMK_MAGIC_8388607)
98 if smk_find(resp, r2, "200 OK" as *u8, 6) < 0 { nx_kill(pid,9); return 3 }
99 let tp: i64 = smk_find(resp, r2, "\"token\":\"" as *u8, 9)
100 if tp < 0 { nx_kill(pid,9); return 4 }
101 let tok: *u8 = sys_mmap(512); var ti: i64=0; var si: i64=tp+9
102 while si < r2 { if resp[si]==(34 as u8) { si=r2 } else { tok[ti]=resp[si]; ti=ti+1; si=si+1 } }
103 tok[ti]=0 as u8
104 nx_puts_err("login token chars=" as *u8); nx_puti_err(ti); nx_puts_err("\n" as *u8)
105
106 let q3: i64 = smk_get(req, "/gallery/api/list" as *u8, empty)
107 let r3: i64 = smk_http(req, q3, resp, SMK_MAGIC_8388607)
108 if smk_find(resp, r3, "401" as *u8, 3) < 0 { nx_kill(pid,9); return 5 }
109 nx_puts_err("api/list(no token) -> 401 OK\n" as *u8)
110
111 let q4: i64 = smk_get(req, "/gallery/api/list?filter=recordings" as *u8, tok)
112 let r4: i64 = smk_http(req, q4, resp, SMK_MAGIC_8388607)
113 if smk_find(resp, r4, "200 OK" as *u8, 6) < 0 { nx_kill(pid,9); return 6 }
114 if smk_find(resp, r4, "items" as *u8, 5) < 0 { if smk_find(resp, r4, "kind" as *u8, 4) < 0 { nx_kill(pid,9); return 7 } }
115 nx_puts_err("api/list(valid) -> 200 PROXIED from :18090 OK\n" as *u8)
116
117 let bad: *u8 = sys_mmap(64); var bi: i64=0; while bi<40 { bad[bi]=65 as u8; bi=bi+1 } bad[40]=0 as u8
118 let q5: i64 = smk_get(req, "/gallery/api/list" as *u8, bad)
119 let r5: i64 = smk_http(req, q5, resp, SMK_MAGIC_8388607)
120 if smk_find(resp, r5, "401" as *u8, 3) < 0 { nx_kill(pid,9); return 8 }
121 nx_puts_err("api/list(bad token) -> 401 OK\n" as *u8)
122
123 let q6: i64 = smk_get(req, "/gallery/sw.js" as *u8, empty)
124 let r6: i64 = smk_http(req, q6, resp, SMK_MAGIC_8388607)
125 if smk_find(resp, r6, "200 OK" as *u8, 6) < 0 { nx_kill(pid,9); return 9 }
126 if smk_find(resp, r6, "respondWith" as *u8, 11) < 0 { nx_kill(pid,9); return 10 }
127 nx_puts_err("sw.js -> 200 + respondWith OK\n" as *u8)
128
129 let q7: i64 = smk_get(req, "/gallery/login" as *u8, empty)
130 let r7: i64 = smk_http(req, q7, resp, SMK_MAGIC_8388607)
131 if smk_find(resp, r7, "200 OK" as *u8, 6) < 0 { nx_kill(pid,9); return 11 }
132 if smk_find(resp, r7, "Nishi Gallery" as *u8, 13) < 0 { nx_kill(pid,9); return 12 }
133 nx_puts_err("login page -> 200 OK\n" as *u8)
134
135 let st: *i64 = sys_mmap(16) as *i64; nx_kill(pid, 9); sys_wait4(pid, st, 0)
136 nx_puts_err("nx_gallery_gateway_smoke verdict=GREEN pass=7 (register/login/gate401/proxy200/bad401/sw.js/loginpage)\n" as *u8)
137 return 0
138}