code wiki / _hdl_build / nx_docportal_multipart_gate.nx

nx_docportal_multipart_gate.nx source

↩ module page · 125 lines · 8934 B

1import "nx_gate_base.nx" 2// nx_docportal_multipart_gate.nx -- SOVEREIGN referee for REAL multipart/form-data file upload on the doc 3// portal: craft the exact bytes an <input type=file> form submits, drive the pure router dad_handle, and 4// assert the file stores through the SAME /admin/upload path (binary-safe, session-gated, ?s= OR header). 5// GREEN iff 6/6. license_tier: ORIGINAL 6import "nx_docportal_admin_daemon.nx" 7import "hub/nx_modern_auth_flow.nx" 8import "nx_syscalls.nx" 9 10func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw(" 11" as *u8); return ok } 12func gln(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 13func gcat(d: *u8, o: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){d[o+i]=s[i];i=i+1} return o+i } 14func gcatn(d: *u8, o: i64, s: *u8, n: i64) -> i64 { var i: i64=0; while i<n {d[o+i]=s[i];i=i+1} return o+n } 15func 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 } 16func gtoken(resp: *u8, n: i64, out: *u8) -> i64 { let key: *u8="{\"token\":\"" as *u8; let kn: i64=10; var st: i64=0-1; var i: i64=0; while i+kn<=n { var m: i64=1; var j: i64=0; while j<kn { if (resp[i+j] as i64)!=(key[j] as i64){m=0;j=kn} else {j=j+1} } if m==1 {st=i+kn;i=n} i=i+1 } if st<0 {return 0} var w: i64=0; var k: i64=st; while k<n { if (resp[k] as i64)==34 {k=n} else {out[w]=resp[k];w=w+1;k=k+1} } return w } 17func 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 } 18 19// build a multipart body (boundary ----B) with domain/visibility/pub_search parts + a `file` part whose 20// content INCLUDES an embedded blank line (\r\n\r\n) to prove binary/whitespace-safety. Returns length. 21func gbuild_body(out: *u8) -> i64 { 22 var o: i64 = 0 23 o = gcat(out, o, "------B\r\nContent-Disposition: form-data; name=\"domain\"\r\n\r\nandelinwest.com\r\n" as *u8) 24 o = gcat(out, o, "------B\r\nContent-Disposition: form-data; name=\"visibility\"\r\n\r\npublic\r\n" as *u8) 25 o = gcat(out, o, "------B\r\nContent-Disposition: form-data; name=\"pub_search\"\r\n\r\n1\r\n" as *u8) 26 o = gcat(out, o, "------B\r\nContent-Disposition: form-data; name=\"file\"; filename=\"deed.txt\"\r\nContent-Type: text/plain\r\n\r\n" as *u8) 27 o = gcat(out, o, "ESTATE PLANNING deed\r\n\r\nprobate clause: living trusts survive the blank line\r\n" as *u8) 28 o = gcat(out, o, "------B--\r\n" as *u8) 29 return o 30} 31 32func main() -> i64 { 33 gw("=== NX-DOCPORTAL-MULTIPART-GATE -- real <input type=file> upload stores through /admin/upload ===\n" as *u8) 34 let sp: *u8 = "/tmp/nx_mpg_store.log" as *u8 35 let kp: *u8 = "/tmp/nx_mpg_keys.log" as *u8 36 let f1: i64 = sys_openat_wr(sp, 0x180); if f1>=0 {sys_close(f1)} 37 let f2: i64 = sys_openat_wr(kp, 0x180); if f2>=0 {sys_close(f2)} 38 let oprf: *u8=sys_mmap(32); let akp: *u8=sys_mmap(32); let akb: *u8=sys_mmap(33); let edp: *u8=sys_mmap(32); let edb: *u8=sys_mmap(32) 39 if nx_uas_server_keys_load_or_init(kp, oprf, akp, akb, edp, edb) != NX_UAS_OK { gw("KEYS FAIL\n" as *u8); sys_exit(1) } 40 let realm: *u8="nishi_docportal" as *u8; let rn: i64=gln(realm) 41 let ctx: *NxAuthContext = sys_mmap(256) as *NxAuthContext 42 if nx_auth_context_init(ctx, realm, rn, realm, rn, sp as i64, oprf, edp, edb, 900, 8192, 1, 1, 5, 1) != NX_MAUTH_OK { gw("CTX FAIL\n" as *u8); sys_exit(1) } 43 let mnb: *u8=sys_mmap(512); let mnn: *i64=sys_mmap(16) as *i64 44 if nx_modern_auth_register(ctx, "elder" as *u8, 5, "correct horse battery staple" as *u8, 28, mnb, 512, mnn) != NX_MAUTH_OK { gw("REG FAIL\n" as *u8); sys_exit(1) } 45 // mint a token 46 let tok: *u8=sys_mmap(NX_MAUTH_SESSION_TOKEN_BYTES); let tn: *i64=sys_mmap(8) as *i64; tn[0]=0 47 if nx_modern_auth_login(ctx, "elder" as *u8, 5, "correct horse battery staple" as *u8, 28, tok, NX_MAUTH_SESSION_TOKEN_BYTES, tn) != NX_MAUTH_OK { gw("LOGIN FAIL\n" as *u8); sys_exit(1) } 48 let b64: *u8=sys_mmap(256); let b64n: i64=b64_encode(tok, NX_MAUTH_SESSION_TOKEN_BYTES, b64) 49 50 let body: *u8 = sys_mmap(4096) 51 let blen: i64 = gbuild_body(body) 52 let out: *u8 = sys_mmap(DAD_OUTCAP) 53 var pass: i64 = 0 54 55 // M1: header-auth multipart upload -> 200 UPLOADED domain=andelinwest.com 56 let req: *u8 = sys_mmap(8192) 57 var r: i64 = gcat(req, 0, "POST /admin/uploadfile HTTP/1.1\r\nHost: admin.andelinwest.com\r\nX-Nishi-Session: " as *u8) 58 r = gcatn(req, r, b64, b64n) 59 r = gcat(req, r, "\r\nContent-Type: multipart/form-data; boundary=----B\r\nContent-Length: " as *u8) 60 r = gcatn(req, r, mnb, 0) // (no-op; keep req buffer hot) 61 r = gcat(req, r, "999\r\n\r\n" as *u8) 62 r = gcatn(req, r, body, blen) 63 let o1: i64 = dad_handle(ctx, req, r, out) 64 var m1: i64 = 0 65 if gcontains(out, o1, "UPLOADED domain=andelinwest.com" as *u8) == 1 { if gcontains(out, o1, "cid=" as *u8) == 1 { m1 = 1 } } 66 pass = pass + gcell(m1, "M1" as *u8, "header-auth multipart upload -> 200 UPLOADED domain=andelinwest.com + cid" as *u8) 67 68 // M2: binary/whitespace-safe -- the text AFTER the file's embedded blank line was stored (searchable) 69 let sreq: *u8 = sys_mmap(1024) 70 let sr: i64 = gcat(sreq, 0, "GET /search?q=probate HTTP/1.1\r\nHost: andelinwest.com\r\n\r\n" as *u8) 71 let o2: i64 = dad_handle(ctx, sreq, sr, out) 72 var m2: i64 = 0 73 if gcontains(out, o2, "probate" as *u8) == 1 { m2 = 1 } 74 if gcontains(out, o2, "Estate" as *u8) == 1 { m2 = 1 } 75 if gcontains(out, o2, "estate" as *u8) == 1 { m2 = 1 } 76 pass = pass + gcell(m2, "M2" as *u8, "file stored binary-safe (text AFTER the embedded blank line indexed + searchable)" as *u8) 77 78 // M3: ?s= query-auth multipart upload -> 200 UPLOADED (nishi-first path) 79 let req3: *u8 = sys_mmap(8192) 80 var r3: i64 = gcat(req3, 0, "POST /admin/uploadfile?s=" as *u8) 81 r3 = nx_sa_tok_urlenc(b64, b64n, req3, r3) 82 r3 = gcat(req3, r3, " HTTP/1.1\r\nHost: admin.andelinwest.com\r\nContent-Type: multipart/form-data; boundary=----B\r\n\r\n" as *u8) 83 r3 = gcatn(req3, r3, body, blen) 84 let o3: i64 = dad_handle(ctx, req3, r3, out) 85 var m3: i64 = 0 86 if gcontains(out, o3, "UPLOADED domain=andelinwest.com" as *u8) == 1 { m3 = 1 } 87 pass = pass + gcell(m3, "M3" as *u8, "?s= query-auth multipart upload -> 200 UPLOADED (nishi-first no-cookie path)" as *u8) 88 89 // M4: NEG no session -> 401 (deny-by-default before any store) 90 let req4: *u8 = sys_mmap(8192) 91 var r4: i64 = gcat(req4, 0, "POST /admin/uploadfile HTTP/1.1\r\nHost: admin.andelinwest.com\r\nContent-Type: multipart/form-data; boundary=----B\r\n\r\n" as *u8) 92 r4 = gcatn(req4, r4, body, blen) 93 let o4: i64 = dad_handle(ctx, req4, r4, out) 94 var m4: i64 = 0 95 if gcontains(out, o4, "401" as *u8) == 1 { m4 = 1 } 96 pass = pass + gcell(m4, "M4" as *u8, "no-session multipart upload -> 401 (deny-by-default, nothing stored)" as *u8) 97 98 // M5: NEG multipart with NO file part -> 400 99 let nofile: *u8 = sys_mmap(512) 100 var nfo: i64 = gcat(nofile, 0, "------B\r\nContent-Disposition: form-data; name=\"domain\"\r\n\r\nandelinwest.com\r\n------B--\r\n" as *u8) 101 let req5: *u8 = sys_mmap(2048) 102 var r5: i64 = gcat(req5, 0, "POST /admin/uploadfile HTTP/1.1\r\nHost: x\r\nX-Nishi-Session: " as *u8) 103 r5 = gcatn(req5, r5, b64, b64n) 104 r5 = gcat(req5, r5, "\r\nContent-Type: multipart/form-data; boundary=----B\r\n\r\n" as *u8) 105 r5 = gcatn(req5, r5, nofile, nfo) 106 let o5: i64 = dad_handle(ctx, req5, r5, out) 107 var m5: i64 = 0 108 if gcontains(out, o5, "400" as *u8) == 1 { if gcontains(out, o5, "no file part" as *u8) == 1 { m5 = 1 } } 109 pass = pass + gcell(m5, "M5" as *u8, "multipart with no file part -> 400 (honest error, not a fake success)" as *u8) 110 111 // M6: NEG missing Content-Type boundary -> 400 112 let req6: *u8 = sys_mmap(2048) 113 var r6: i64 = gcat(req6, 0, "POST /admin/uploadfile HTTP/1.1\r\nHost: x\r\nX-Nishi-Session: " as *u8) 114 r6 = gcatn(req6, r6, b64, b64n) 115 r6 = gcat(req6, r6, "\r\nContent-Type: application/octet-stream\r\n\r\nrawbytes" as *u8) 116 let o6: i64 = dad_handle(ctx, req6, r6, out) 117 var m6: i64 = 0 118 if gcontains(out, o6, "400" as *u8) == 1 { if gcontains(out, o6, "boundary" as *u8) == 1 { m6 = 1 } } 119 pass = pass + gcell(m6, "M6" as *u8, "missing multipart boundary -> 400 (no silent mis-store)" as *u8) 120 121 gw("NX-DOCPORTAL-MULTIPART-GATE pass=" as *u8); let d: *u8=sys_mmap(8); d[0]=(48+pass) as u8; sys_write(1,d,1); gw("/6 verdict=" as *u8) 122 if pass == 6 { gw("GREEN (real file upload stores binary-safe through the unified path; ?s= + header auth; honest errors)\n" as *u8); sys_exit(0); return 0 } 123 gw("RED\n" as *u8); sys_exit(1) 124 return 1 125}