nx_chat_demo_api_gate.nx source
↩ module page · 148 lines · 7565 B
1// nx_chat_demo_api_gate.nx -- REFEREE for the SAFE public chat front (nx_chat_demo_api). Forks the
2// PROMOTED elf and proves the security boundary: only post/list, rooms forced into demo_, inputs
3// sanitized and capped, injection-safe JSON, budgets/errors surfaced. Fixture rooms are epoch-suffixed
4// so each run is fresh (they live in the real demo_ store, tiny + budget-bounded, the whole point).
5// license_tier: ORIGINAL expect_exit: 0
6import "nx_syscalls.nx"
7import "nx_tool_run.nx"
8import "nx_gate_verdict.nx"
9const CG_CAP: i64 = 65536
10func cg_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
11func cg_count(buf: *u8, n: i64, needle: *u8) -> i64 {
12 let m: i64 = cg_len(needle)
13 if m <= 0 { return 0 }
14 var c: i64 = 0
15 var i: i64 = 0
16 while i + m <= n {
17 var k: i64 = 0
18 var hit: i64 = 1
19 while k < m { if buf[i+k] != needle[k] { hit = 0; k = m } else { k = k + 1 } }
20 if hit == 1 { c = c + 1; i = i + m } else { i = i + 1 }
21 }
22 return c
23}
24func cg_run(elf: *u8, av: *i64, out: *u8, ol: *i64) -> i64 { return tr_run_capture(elf, av, out, CG_CAP, ol) }
25func main(argc: i64, argv: *i64) -> i64 {
26 let ctr: *i64 = gv_ctr()
27 gv_head("nx_chat_demo_api -- the safe browser<->store boundary: post/list only, demo_ forced, inputs sanitized, injection-safe" as *u8)
28 let ELF: *u8 = "/volume1/homes/elderwesto/nishihost/nx_chat_demo_api.elf" as *u8
29 let out: *u8 = sys_mmap(CG_CAP)
30 let ol: *i64 = sys_mmap(16) as *i64
31 let av: *i64 = sys_mmap(64) as *i64
32 let ms: i64 = sys_now_realtime_ms()
33 // room base 'g<ms>' -- deterministic sanitize target
34 let rm: *u8 = sys_mmap(64)
35 var o: i64 = gv_cat(rm, 0, "g" as *u8)
36 o = gv_catn(rm, o, ms)
37 rm[o] = 0 as u8
38 // ---- T1 post ------------------------------------------------------------------------------
39 av[0] = ELF as i64
40 av[1] = "post" as i64
41 av[2] = rm as i64
42 av[3] = "alice" as i64
43 av[4] = "hello from the gate" as i64
44 av[5] = 0
45 let p1: i64 = cg_run(ELF, av, out, ol)
46 var t1: i64 = 0
47 if p1 == 0 { if cg_count(out, ol[0], "{\"ok\":1" as *u8) == 1 { if cg_count(out, ol[0], "\"seq\":" as *u8) == 1 { t1 = 1 } } }
48 gv_check("T1 BITE: post returns ok:1 with a seq (message stored through the real C1 store)" as *u8, t1, ctr)
49 // ---- T2 list returns it, demo_ forced ------------------------------------------------------
50 av[1] = "list" as i64
51 av[2] = rm as i64
52 av[3] = 0
53 let l1: i64 = cg_run(ELF, av, out, ol)
54 var t2: i64 = 0
55 if l1 == 0 { if cg_count(out, ol[0], "\"from\":\"alice\"" as *u8) == 1 { if cg_count(out, ol[0], "\"text\":\"hello from the gate\"" as *u8) == 1 { t2 = 1 } } }
56 gv_check("T2 list returns the posted message with correct sender and text" as *u8, t2, ctr)
57 var t3: i64 = 0
58 if l1 == 0 { if cg_count(out, ol[0], "\"room\":\"demo_g" as *u8) == 1 { t3 = 1 } }
59 gv_check("T3 DEMO NAMESPACE FORCED: the stored room is always demo_<name> -- no way to address a non-demo room" as *u8, t3, ctr)
60 // ---- T4 sanitize: uppercase + special chars are stripped, deterministically ----------------
61 let rmx: *u8 = sys_mmap(64)
62 o = gv_cat(rmx, 0, "Hall Way!" as *u8) // -> hallway
63 rmx[o] = 0 as u8
64 av[1] = "post" as i64
65 av[2] = rmx as i64
66 av[3] = "Bob..007" as i64 // -> bob007
67 av[4] = "sanitized ok" as i64
68 av[5] = 0
69 let p2: i64 = cg_run(ELF, av, out, ol)
70 var t4: i64 = 0
71 if p2 == 0 { if cg_count(out, ol[0], "\"room\":\"demo_hallway\"" as *u8) == 1 { t4 = 1 } }
72 gv_check("T4 SANITIZE: 'Hall Way!' becomes demo_hallway -- spaces/case/punctuation stripped, no injection into the room path" as *u8, t4, ctr)
73 av[1] = "list" as i64
74 av[2] = "hallway" as i64
75 av[3] = 0
76 let l2: i64 = cg_run(ELF, av, out, ol)
77 var t5: i64 = 0
78 if l2 == 0 { if cg_count(out, ol[0], "\"from\":\"bob007\"" as *u8) == 1 { t5 = 1 } }
79 gv_check("T5 the sanitized name is deterministic: listing 'hallway' finds what 'Hall Way!' posted, sender folded to bob007" as *u8, t5, ctr)
80 // ---- T6 INJECTION-SAFE JSON ----------------------------------------------------------------
81 let ri: *u8 = sys_mmap(64)
82 o = gv_cat(ri, 0, "inj" as *u8)
83 o = gv_catn(ri, o, ms)
84 ri[o] = 0 as u8
85 av[1] = "post" as i64
86 av[2] = ri as i64
87 av[3] = "eve" as i64
88 av[4] = "say hi and pipe | quote and end" as i64
89 av[5] = 0
90 cg_run(ELF, av, out, ol)
91 av[1] = "list" as i64
92 av[2] = ri as i64
93 av[3] = 0
94 let l3: i64 = cg_run(ELF, av, out, ol)
95 var t6: i64 = 0
96 if l3 == 0 { if cg_count(out, ol[0], "{\"ok\":1" as *u8) == 1 { if cg_count(out, ol[0], "pipe | quote" as *u8) == 1 { t6 = 1 } } }
97 gv_check("T6 INJECTION-SAFE: a body with a pipe (the store row delimiter) round-trips intact and the JSON stays valid -- C1 hex-armors the body, the delimiter cannot break parsing" as *u8, t6, ctr)
98 // ---- T7 neg-control-empty-text -------------------------------------------------------------
99 av[1] = "post" as i64
100 av[2] = rm as i64
101 av[3] = "alice" as i64
102 av[4] = "" as i64
103 av[5] = 0
104 let p3: i64 = cg_run(ELF, av, out, ol)
105 var t7: i64 = 0
106 if p3 != 0 { if cg_count(out, ol[0], "empty-text" as *u8) == 1 { t7 = 1 } }
107 gv_check("T7 neg-control-empty: an empty message is refused, not stored" as *u8, t7, ctr)
108 // ---- T8 neg-control-bad-room (all-special sanitizes to empty) -------------------------------
109 av[1] = "post" as i64
110 av[2] = "!!!___" as i64 // wait: underscores survive; use pure punctuation below
111 av[3] = "alice" as i64
112 av[4] = "x" as i64
113 av[5] = 0
114 av[2] = "!@#$%" as i64
115 let p4: i64 = cg_run(ELF, av, out, ol)
116 var t8: i64 = 0
117 if p4 != 0 { if cg_count(out, ol[0], "bad-room" as *u8) == 1 { t8 = 1 } }
118 gv_check("T8 neg-control-bad-room: a room name that sanitizes to nothing is refused -- cannot post to an empty/ambiguous room" as *u8, t8, ctr)
119 // ---- T9 neg-control-verb-whitelist ---------------------------------------------------------
120 av[1] = "purge" as i64
121 av[2] = rm as i64
122 av[3] = "alice" as i64
123 av[4] = "x" as i64
124 av[5] = 0
125 let p5: i64 = cg_run(ELF, av, out, ol)
126 var t9: i64 = 0
127 if p5 != 0 { if cg_count(out, ol[0], "usage" as *u8) == 1 { if cg_count(out, ol[0], "CHAT-PURGE" as *u8) == 0 { t9 = 1 } } }
128 gv_check("T9 VERB WHITELIST: only post/list exist -- 'purge' (and open/del/retention) are unreachable through this front; the destructive verbs cannot be invoked by a browser" as *u8, t9, ctr)
129 // ---- T10 text cap: a 400-char body is capped, still valid ----------------------------------
130 let big: *u8 = sys_mmap(512)
131 var bi: i64 = 0
132 while bi < 400 { big[bi] = 97 as u8; bi = bi + 1 }
133 big[400] = 0 as u8
134 let rc2: *u8 = sys_mmap(64)
135 o = gv_cat(rc2, 0, "cap" as *u8)
136 o = gv_catn(rc2, o, ms)
137 rc2[o] = 0 as u8
138 av[1] = "post" as i64
139 av[2] = rc2 as i64
140 av[3] = "alice" as i64
141 av[4] = big as i64
142 av[5] = 0
143 let p6: i64 = cg_run(ELF, av, out, ol)
144 var t10: i64 = 0
145 if p6 == 0 { if cg_count(out, ol[0], "{\"ok\":1" as *u8) == 1 { t10 = 1 } }
146 gv_check("T10 a 400-char body is accepted but capped at 280 by the boundary (no unbounded write reaches the store)" as *u8, t10, ctr)
147 return gv_verdict("CHAT-DEMO-API-GATE" as *u8, ctr, "post/list only, demo_ namespace forced, inputs sanitized and capped, injection-safe JSON, destructive verbs unreachable -- a safe browser front to the real C1 store" as *u8)
148}