code wiki / _hdl_build / nx_torrent_authn.nx

nx_torrent_authn.nx source

↩ module page · 91 lines · 6137 B

1// nx_torrent_authn.nx -- R3: resolve a request's VIEWER LEVEL from its OPAQUE session, DENY-BY-DEFAULT. 2// The torrent daemon's d_viewer_level was a stub returning OWNER (it was the operator's LOCAL single-user 3// daemon). This wires the REAL auth so it can serve family-vs-operator on the hub: extract the session token 4// (X-Nishi-Session header, else the ngs cookie -- media tags can't send headers) -> olg_whoami (validate the 5// Ed25519-signed token against the realm's keys) -> handle -> ag_resolve_level over the roles registry 6// (handle<TAB>level) -> level. ANY failure -- no token, tampered/expired token, or a handle absent from the 7// roles registry -- returns 0 (ANON), so nx_taccess_allow then denies every gated area. Mirrors the proven 8// gallery-gateway pattern (header-then-cookie -> olg_whoami). The realm keys/store + the roles registry are 9// PATHS the daemon supplies (operator-provisioned -- accounts + role assignments never come from Claude). 10// license_tier: ORIGINAL 11import "nx_opaque_login.nx" // olg_ctx_setup / olg_whoami + NxAuthContext + NX_MAUTH_OK 12import "nx_hr.nx" // NISHI HR: hr_resolve_level (the user-management SSOT) + hr_cred_id (provision by handle) 13import "nx_syscalls.nx" 14const K_MAGIC_1024: i64 = 1024 15const K_MAGIC_65536: i64 = 65536 16 17// first index of pat[0..pl) in buf[0..n), or -1. 18func tau_find(buf: *u8, n: i64, pat: *u8, pl: i64) -> i64 { 19 if pl <= 0 { return 0 - 1 } 20 var i: i64 = 0 21 while i + pl <= n { 22 var j: i64 = 0; var m: i64 = 1 23 while j < pl { if buf[i+j] != pat[j] { m = 0; j = pl } else { j = j + 1 } } 24 if m == 1 { return i } 25 i = i + 1 26 } 27 return 0 - 1 28} 29// header value for `name` (include the trailing ':') over req[0..n) -> len into out (NUL-term). 0 if absent. 30func tau_hdr_val(req: *u8, n: i64, name: *u8, nl: i64, out: *u8, cap: i64) -> i64 { 31 let p: i64 = tau_find(req, n, name, nl) 32 if p < 0 { out[0]=0 as u8; return 0 } 33 var i: i64 = p + nl 34 if i < n { if req[i]==(32 as u8) { i=i+1 } } 35 var o: i64 = 0 36 while i < n { let c: u8 = req[i]; if c==(13 as u8){i=n} else { if c==(10 as u8){i=n} else { if o<cap-1 {out[o]=c; o=o+1} i=i+1 } } } 37 out[o]=0 as u8; return o 38} 39// `ngs=` cookie value over req[0..n) -> len into out. 0 if absent. 40func tau_cookie_val(req: *u8, n: i64, out: *u8, cap: i64) -> i64 { 41 let p: i64 = tau_find(req, n, "ngs=" as *u8, 4) 42 if p < 0 { out[0]=0 as u8; return 0 } 43 var i: i64 = p + 4; var o: i64 = 0 44 while i < n { let c: u8 = req[i]; if c==(59 as u8){i=n} else { if c==(13 as u8){i=n} else { if c==(10 as u8){i=n} else { if c==(32 as u8){i=n} else { if o<cap-1 {out[o]=c; o=o+1} i=i+1 } } } } } 45 out[o]=0 as u8; return o 46} 47// the session token: X-Nishi-Session header first, else ngs cookie. len (0 if neither present). 48func tau_token(req: *u8, n: i64, out: *u8, cap: i64) -> i64 { 49 let l: i64 = tau_hdr_val(req, n, "X-Nishi-Session:" as *u8, 16, out, cap) 50 if l > 0 { return l } 51 return tau_cookie_val(req, n, out, cap) 52} 53// lowercase-hex encode in[0..n) -> out (NUL-terminated). returns 2*n. (the validated session yields the 54// stable 32-byte user-id hash; its hex is the printable credential-id the roles registry is keyed by.) 55func tau_hex(inp: *u8, n: i64, out: *u8) -> i64 { 56 let hx: *u8 = "0123456789abcdef" as *u8 57 var i: i64 = 0 58 while i < n { out[i*2] = hx[((inp[i] as i64)>>4)&15]; out[i*2+1] = hx[(inp[i] as i64)&15]; i = i + 1 } 59 out[n*2] = 0 as u8 60 return n*2 61} 62// derive the printable credential-id (64-char lowercase hex of the STABLE user-id hash) for (realm, handle) 63// WITHOUT a login -- so the operator provisions the roles registry BY HANDLE: write "<out_hex><TAB><level>". 64// The runtime (tau_level) computes the IDENTICAL id from a login token, so a by-handle-provisioned row matches. 65func tau_cred_id(realm: *u8, realm_n: i64, handle: *u8, hn: i64, out_hex: *u8) -> i64 { return hr_cred_id(realm, realm_n, handle, hn, out_hex) } 66// read a file into buf (bounded); return len or 0. 67func tau_read(path: *u8, buf: *u8, cap: i64) -> i64 { 68 let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 } 69 var off: i64 = 0; var go: i64 = 1 70 while go == 1 { if off >= cap { go = 0 } else { let r: i64 = sys_read(fd, buf+off, cap-off); if r <= 0 { go = 0 } else { off = off + r } } } 71 sys_close(fd); return off 72} 73// THE RESOLVER -> viewer level, deny-by-default. `realm` must match the token-issuing realm. `now_s` from the clock. 74func tau_level(req: *u8, n: i64, keys_path: *u8, store_path: *u8, hr_store: *u8, realm: *u8, realm_n: i64, now_s: i64) -> i64 { 75 let tok: *u8 = sys_mmap(K_MAGIC_1024); let tn: i64 = tau_token(req, n, tok, 1023) 76 if tn <= 0 { return 0 } // no session -> ANON(0) 77 let ctx: *NxAuthContext = sys_mmap(256) as *NxAuthContext 78 if olg_ctx_setup(ctx, keys_path, store_path, realm, realm_n, realm, realm_n, K_MAGIC_65536, 3, 4) != 0 { return 0 } // realm keys unloadable -> deny 79 let h: *u8 = sys_mmap(128); let hn: *i64 = sys_mmap(16) as *i64; hn[0] = 0 80 if olg_whoami(ctx, tok, tn, now_s, h, 127, hn) != NX_MAUTH_OK { return 0 } // tampered/expired/bad -> ANON(0) 81 // The validated session yields the STABLE 32-byte user-id hash (per realm+handle), NOT a plaintext name. 82 // The roles registry is keyed by its lowercase-hex credential-id (stable + printable; operator provisions 83 // <hex-id><TAB>level). Hex-encode, then look up; an id absent from the registry -> 0 (deny-by-default). 84 let hexid: *u8 = sys_mmap(160); let hexn: i64 = tau_hex(h, hn[0], hexid) 85 return hr_resolve_level(hr_store, hexid, hexn) // NISHI HR is the SSOT; unknown/suspended/no-record -> 0 86} 87// daemon convenience: stamp now from the hardware clock, then resolve. 88func tau_level_now(req: *u8, n: i64, keys_path: *u8, store_path: *u8, hr_store: *u8, realm: *u8, realm_n: i64) -> i64 { 89 let tsb: *i64 = sys_mmap(16) as *i64; tsb[0] = 0; sys_clock_gettime_real(tsb) 90 return tau_level(req, n, keys_path, store_path, hr_store, realm, realm_n, tsb[0]) 91}