code wiki / _hdl_build / nx_browser_forms_gate.nx
nx_browser_forms_gate.nx source
↩ module page · 121 lines · 8523 B
1import "nx_gate_base.nx"
2// nx_browser_forms_gate.nx -- SOVEREIGN referee for nx_browser_forms: proves the Nishi browser can OPERATE
3// the real nishi-first no-JS portal forms (parse the SERVED markup -> type into fields -> submit produces
4// the exact HTTP request the daemon expects). If GREEN, the docportal/mail/siteedit logins + editor are
5// operable in the Nishi browser, not just structurally present. GREEN iff 6/6. license_tier: ORIGINAL
6import "nx_browser_forms.nx"
7import "nx_syscalls.nx"
8
9func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw("
10" as *u8); return ok }
11func gln(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
12func gstreq(a: *u8, b: *u8) -> i64 { var i: i64=0; while 1==1 { if (a[i] as i64)!=(b[i] as i64){return 0} if (a[i] as i64)==0 {return 1} i=i+1 } return 0 }
13func gbufeq(buf: *u8, n: i64, lit: *u8) -> i64 { let ll: i64=gln(lit); if n!=ll {return 0} var i: i64=0; while i<n { if (buf[i] as i64)!=(lit[i] as i64){return 0} i=i+1 } return 1 }
14func gcontains(hay: *u8, n: i64, needle: *u8) -> i64 { let nn: i64=gln(needle); var i: i64=0; while i+nn<=n { var m: i64=1; var j: i64=0; while j<nn { if (hay[i+j] as i64)!=(needle[j] as i64){m=0;j=nn} else {j=j+1} } if m==1 {return 1} i=i+1 } return 0 }
15func gcell(ok: i64, id: *u8, txt: *u8) -> i64 { if ok==1 {gw(" PASS " as *u8)} else {gw(" FAIL " as *u8)} gw(id); gw(" " as *u8); gw(txt); gw("\n" as *u8); return ok }
16
17func main() -> i64 {
18 gw("=== NX-BROWSER-FORMS-GATE -- can the Nishi browser OPERATE the no-JS portal forms? (measured) ===\n" as *u8)
19 var pass: i64 = 0
20
21 // ---- G1: docportal login (the exact served markup) -> fill -> submit ----
22 let h1: *u8 = "<form id=lf method=post action=/admin/login><input type=hidden name=ui value=1><input id=h name=handle placeholder=\"handle\" autocomplete=username autofocus><input id=p name=passphrase type=password placeholder=\"passphrase\"><button type=submit id=b>Sign in</button></form>" as *u8
23 let forms: *BrForm = sys_mmap(NX_BRFORM_BYTES * 8) as *BrForm
24 let fields: *BrField = sys_mmap(NX_BRFIELD_BYTES * 32) as *BrField
25 let nf1: i64 = bf_parse(h1, gln(h1), forms, 8, fields, 32)
26 let fm1: *BrForm = bf_form(forms, 0)
27 var g1: i64 = 0
28 if nf1 == 1 { if gstreq(fm1.action, "/admin/login" as *u8) == 1 { if fm1.method_post == 1 { if fm1.field_count == 3 { g1 = 1 } } } }
29 // field names: ui / handle / passphrase; hidden ui already = "1"
30 let f_ui: *BrField = bf_field(fields, 0)
31 let f_h: *BrField = bf_field(fields, 1)
32 let f_p: *BrField = bf_field(fields, 2)
33 if gstreq(f_ui.name, "ui" as *u8) == 0 { g1 = 0 }
34 if gstreq(f_h.name, "handle" as *u8) == 0 { g1 = 0 }
35 if gstreq(f_p.name, "passphrase" as *u8) == 0 { g1 = 0 }
36 if f_ui.kind != BF_K_HIDDEN { g1 = 0 }
37 if f_p.kind != BF_K_PASSWORD { g1 = 0 }
38 if gbufeq(f_ui.val, f_ui.val_len, "1" as *u8) == 0 { g1 = 0 }
39 pass = pass + gcell(g1, "G1" as *u8, "docportal login: 1 form action=/admin/login POST, fields ui(hidden=1)/handle/passphrase(pw)" as *u8)
40
41 // ---- G2: TYPE into the fields, submit -> the EXACT body the daemon parses ----
42 bf_set(f_h, "elder" as *u8)
43 bf_set(f_p, "s3cret" as *u8)
44 let body: *u8 = sys_mmap(4096)
45 let bl2: i64 = bf_submit_body(forms, 0, fields, body)
46 var g2: i64 = 0
47 if gbufeq(body, bl2, "ui=1&handle=elder&passphrase=s3cret" as *u8) == 1 { g2 = 1 }
48 pass = pass + gcell(g2, "G2" as *u8, "typed handle=elder + passphrase=s3cret -> submit body ui=1&handle=elder&passphrase=s3cret" as *u8)
49
50 // ---- G3: urlencoding of a passphrase with spaces + reserved chars ----
51 bf_set(f_p, "a b&c=d" as *u8)
52 let body3: *u8 = sys_mmap(4096)
53 let bl3: i64 = bf_submit_body(forms, 0, fields, body3)
54 var g3: i64 = 0
55 if gcontains(body3, bl3, "passphrase=a%20b%26c%3Dd" as *u8) == 1 { g3 = 1 }
56 pass = pass + gcell(g3, "G3" as *u8, "reserved chars urlencoded (space->%20, &->%26, =->%3D) so the body can't be forged/split" as *u8)
57
58 // ---- G4: siteedit textarea editor (seeded value, then edited) ----
59 let h4: *u8 = "<form method=post action=\"/site/save2?s=TOK\"><textarea name=cfg>title|Old</textarea><button type=submit>Save</button></form>" as *u8
60 let forms4: *BrForm = sys_mmap(NX_BRFORM_BYTES * 4) as *BrForm
61 let fields4: *BrField = sys_mmap(NX_BRFIELD_BYTES * 8) as *BrField
62 let nf4: i64 = bf_parse(h4, gln(h4), forms4, 4, fields4, 8)
63 let fc: *BrField = bf_field(fields4, 0)
64 var g4a: i64 = 0
65 if nf4 == 1 { if fc.kind == BF_K_TEXTAREA { if gbufeq(fc.val, fc.val_len, "title|Old" as *u8) == 1 { g4a = 1 } } }
66 bf_set(fc, "title|New" as *u8)
67 let body4: *u8 = sys_mmap(4096)
68 let bl4: i64 = bf_submit_body(forms4, 0, fields4, body4)
69 var g4: i64 = 0
70 let fm4: *BrForm = bf_form(forms4, 0)
71 if g4a == 1 { if gstreq(fm4.action, "/site/save2?s=TOK" as *u8) == 1 { if gcontains(body4, bl4, "cfg=title%7CNew" as *u8) == 1 { g4 = 1 } } }
72 pass = pass + gcell(g4, "G4" as *u8, "siteedit <textarea> seeds from inner text, edits, submits cfg=title%7CNew ('|'->%7C)" as *u8)
73
74 // ---- G5: mail compose (3 fields incl textarea) ----
75 let h5: *u8 = "<form method=post action=\"/mail/xsend?s=T\"><input name=to><input name=subject><textarea name=body></textarea><button type=submit>Send</button></form>" as *u8
76 let forms5: *BrForm = sys_mmap(NX_BRFORM_BYTES * 4) as *BrForm
77 let fields5: *BrField = sys_mmap(NX_BRFIELD_BYTES * 8) as *BrField
78 let nf5: i64 = bf_parse(h5, gln(h5), forms5, 4, fields5, 8)
79 let fm5: *BrForm = bf_form(forms5, 0)
80 let f5a: *BrField = bf_field(fields5, 0)
81 let f5b: *BrField = bf_field(fields5, 1)
82 let f5c: *BrField = bf_field(fields5, 2)
83 bf_set(f5a, "bob" as *u8)
84 bf_set(f5b, "hi" as *u8)
85 bf_set(f5c, "hello" as *u8)
86 let body5: *u8 = sys_mmap(4096)
87 let bl5: i64 = bf_submit_body(forms5, 0, fields5, body5)
88 var g5: i64 = 0
89 if fm5.field_count == 3 { if gbufeq(body5, bl5, "to=bob&subject=hi&body=hello" as *u8) == 1 { g5 = 1 } }
90 pass = pass + gcell(g5, "G5" as *u8, "mail compose: to/subject/body fields -> body to=bob&subject=hi&body=hello" as *u8)
91
92 // ---- G6: NEG -- two forms on a page keep their fields SEPARATE (no cross-form leak) ----
93 let h6: *u8 = "<form method=post action=/one><input name=a value=1></form><form method=post action=/two><input name=b value=2></form>" as *u8
94 let forms6: *BrForm = sys_mmap(NX_BRFORM_BYTES * 4) as *BrForm
95 let fields6: *BrField = sys_mmap(NX_BRFIELD_BYTES * 8) as *BrField
96 let nf6: i64 = bf_parse(h6, gln(h6), forms6, 4, fields6, 8)
97 let b6a: *u8 = sys_mmap(256)
98 let l6a: i64 = bf_submit_body(forms6, 0, fields6, b6a)
99 let b6b: *u8 = sys_mmap(256)
100 let l6b: i64 = bf_submit_body(forms6, 1, fields6, b6b)
101 var g6: i64 = 0
102 if nf6 == 2 { if gbufeq(b6a, l6a, "a=1" as *u8) == 1 { if gbufeq(b6b, l6b, "b=2" as *u8) == 1 { g6 = 1 } } }
103 pass = pass + gcell(g6, "G6" as *u8, "two forms submit ONLY their own fields (form0=a=1, form1=b=2; no cross-leak)" as *u8)
104
105 // ---- G7: a submit produces a REAL HTTP POST request (the actual browser action, not just a body) ----
106 bf_set(f_h, "elder" as *u8)
107 bf_set(f_p, "s3cret" as *u8)
108 let reqb: *u8 = sys_mmap(8192)
109 let rl7: i64 = bf_submit_request("admin.andelinwest.com" as *u8, 21, forms, 0, fields, reqb)
110 var g7: i64 = 0
111 var s7: i64 = 0
112 if gcontains(reqb, 26, "POST /admin/login HTTP/1.1" as *u8) == 1 { s7 = 1 }
113 if s7 == 1 { if gcontains(reqb, rl7, "Content-Type: application/x-www-form-urlencoded" as *u8) == 1 { if gcontains(reqb, rl7, "Content-Length: 35" as *u8) == 1 { if gcontains(reqb, rl7, "\r\n\r\nui=1&handle=elder&passphrase=s3cret" as *u8) == 1 { g7 = 1 } } } }
114 pass = pass + gcell(g7, "G7" as *u8, "submit -> full HTTP POST: request-line + Host + Content-Type + Content-Length: 35 + urlencoded body" as *u8)
115
116 gw("NX-BROWSER-FORMS-GATE pass=" as *u8); gwn(pass); gw("/7 verdict=" as *u8)
117 if pass == 7 { gw("GREEN (the Nishi browser can fill + submit every no-JS portal form as a real HTTP POST; render+keyboard compose this)\n" as *u8); sys_exit(0); return 0 }
118 gw("RED\n" as *u8); sys_exit(1)
119 return 1
120}
121func gwn(v: i64) -> i64 { var m: i64=v; if m<0 {gw("-" as *u8);m=0-m} let t: *u8=sys_mmap(24); 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} let o: *u8=sys_mmap(24); var i: i64=0; while i<k {o[i]=t[k-1-i];i=i+1} sys_write(1,o,k); return 0 }