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}