code wiki / (root) / nx_redirect_resolve_test.nx

nx_redirect_resolve_test.nx source

↩ module page · 91 lines · 3626 B

1// nx_redirect_resolve_test.nx -- X-HTTP-RELLOC-001 KAT: redirect-Location 2// resolution + https-only safety gate for the sovereign nish browser. 3// 4// Base mirrors the RFC3986 ยง5.2 normative example (https + a.com authority) 5// so the path arithmetic is the already-proven nx_url_resolve behaviour; 6// this gate proves the WIRING (relative refs followed, downgrades refused). 7// 8// base = "https://a.com/b/c/d;p?q" 9// C1 absolute https "https://x.com/y" -> follow "https://x.com/y" 10// C2 path-absolute "/g" -> follow "https://a.com/g" 11// C3 path-relative "g" -> follow "https://a.com/b/c/g" 12// C4 scheme-relative "//h.com/p" -> follow "https://h.com/p" 13// C5 dot-segments "../g" -> follow "https://a.com/b/g" 14// C6 http downgrade "http://evil/x" -> REFUSE (0) [no downgrade] 15// C7 cross-scheme "ftp://x/y" -> REFUSE (0) [https-only] 16// C8 google live case "/webhp" -> follow "https://www.google.com/webhp" 17// C9 empty Location "" -> REFUSE (0) 18// 19// C6/C7/C9 are the negative controls: the gate must DISCRIMINATE, not just 20// pass everything. expect_exit: 0 21// license_tier: ORIGINAL 22 23import "nx_syscalls.nx" 24import "nx_redirect_resolve.nx" 25 26func _strlen(s: *u8) -> i64 { 27 var i: i64 = 0 28 while (s[i] & 0xff) != 0 { i = i + 1 } 29 return i 30} 31 32func _eq(a: *u8, an: i64, b: *u8, bn: i64) -> i64 { 33 if an != bn { return 0 } 34 var i: i64 = 0 35 while i < an { 36 if (a[i] & 0xff) != (b[i] & 0xff) { return 0 } 37 i = i + 1 38 } 39 return 1 40} 41 42// Returns 0 on pass, base_id on follow-flag mismatch, base_id+1 on 43// resolved-target mismatch. 44func _ck(base_id: i64, base: *u8, loc: *u8, expect_follow: i64, exp_target: *u8) -> i64 { 45 let out: *u8 = sys_mmap(512) 46 let olp: *i64 = sys_mmap(8) as *i64 47 let f: i64 = nx_redirect_resolve(base, _strlen(base), loc, _strlen(loc), out, 512, olp) 48 if f != expect_follow { return base_id } 49 if expect_follow == 1 { 50 if _eq(out, olp[0], exp_target, _strlen(exp_target)) != 1 { 51 sys_write(2, out, olp[0]) 52 let nl: *u8 = sys_mmap(4); nl[0]=0x0a as u8; sys_write(2, nl, 1) 53 return base_id + 1 54 } 55 } 56 return 0 57} 58 59func main() -> i64 { 60 let base: *u8 = "https://a.com/b/c/d;p?q" as *u8 61 var r: i64 = 0 62 63 r = _ck(10, base, "https://x.com/y" as *u8, 1, "https://x.com/y" as *u8) 64 if r != 0 { return r } 65 r = _ck(20, base, "/g" as *u8, 1, "https://a.com/g" as *u8) 66 if r != 0 { return r } 67 r = _ck(30, base, "g" as *u8, 1, "https://a.com/b/c/g" as *u8) 68 if r != 0 { return r } 69 r = _ck(40, base, "//h.com/p" as *u8, 1, "https://h.com/p" as *u8) 70 if r != 0 { return r } 71 r = _ck(50, base, "../g" as *u8, 1, "https://a.com/b/g" as *u8) 72 if r != 0 { return r } 73 74 // Negative controls: must REFUSE (https-only). 75 r = _ck(60, base, "http://evil/x" as *u8, 0, "" as *u8) 76 if r != 0 { return r } 77 r = _ck(70, base, "ftp://x/y" as *u8, 0, "" as *u8) 78 if r != 0 { return r } 79 // Empty Location via an explicit NUL buffer (empty string literals are 80 // not a clean NUL under this compiler; this exercises loc_len<=0). 81 let eloc: *u8 = sys_mmap(8); eloc[0] = 0 as u8 82 r = _ck(90, base, eloc, 0, eloc) 83 if r != 0 { return r } 84 85 // Google's real cookie-less bounce, as a relative Location. 86 let gbase: *u8 = "https://www.google.com/search?q=cats" as *u8 87 r = _ck(80, gbase, "/webhp" as *u8, 1, "https://www.google.com/webhp" as *u8) 88 if r != 0 { return r } 89 90 return 0 91}