code wiki / _hdl_build / nx_authz_session_gate.nx
nx_authz_session_gate.nx source
↩ module page · 165 lines · 8992 B
1// nx_authz_session_gate.nx -- proves the FULL per-request authorization chain a daemon runs, end-to-end and
2// sovereign: a real no-cookie OPAQUE session token (X-Nishi-Session) -> nx_sa_validate_handle (authn -> the
3// user's HANDLE) -> authz_level_of (handle -> permission LEVEL) -> authz_level_allow (LEVEL vs the gallery
4// policy) -> the NSFW section is served ONLY to a private-level user. Uses REAL Modern Auth (register + login
5// for genuine 152B tokens) + the gallery policy (/ ->0 public, /gallery/private/ ->2 NSFW). This is exactly
6// what nx_media_server will call per request. license_tier: ORIGINAL
7import "nx_site_auth.nx"
8import "nx_authz.nx"
9import "hub/nx_modern_auth_flow.nx"
10import "nx_base64.nx"
11import "nx_syscalls.nx"
12
13func sg_w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
14func sg_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
15func sg_row(name: *u8, ok: i64) -> i64 { if ok == 1 { sg_w(" PASS " as *u8) } if ok != 1 { sg_w(" FAIL " as *u8) } sg_w(name); sg_w("\n" as *u8); return ok }
16func sg_trunc(p: *u8) -> i64 { let fd: i64 = sys_openat_wr(p, 0x180); if fd >= 0 { sys_close(fd) } return 0 }
17func sg_cat(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 }
18func sg_catn(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 }
19func sg_streq_n(a: *u8, an: i64, b: *u8) -> i64 {
20 if an != sg_len(b) { return 0 }
21 var i: i64 = 0
22 while i < an { if (a[i] as i64) != (b[i] as i64) { return 0 } i = i + 1 }
23 return 1
24}
25
26// build "GET <path> HTTP/1.1\r\nHost: x\r\nX-Nishi-Session: <b64tok>\r\n\r\n" into req; return length
27func sg_req(req: *u8, path: *u8, b64: *u8, b64n: i64) -> i64 {
28 var o: i64 = sg_cat(req, 0, "GET " as *u8)
29 o = sg_cat(req, o, path)
30 o = sg_cat(req, o, " HTTP/1.1\r\nHost: x\r\nX-Nishi-Session: " as *u8)
31 o = sg_catn(req, o, b64, b64n)
32 o = sg_cat(req, o, "\r\n\r\n" as *u8)
33 return o
34}
35
36// the per-request chain: validate session -> handle -> level -> authz. returns 1 ALLOW, 0 authz-DENY, -1 auth-FAIL.
37func sg_decide(ctx: *NxAuthContext, req: *u8, rl: i64, now_s: i64, hbuf: *u8, hn: *i64, uh: *i64, uhl: *i64, ul: *i64, un: i64, pp: *i64, pl: *i64, pv: *i64, np: i64, path: *u8) -> i64 {
38 let rc: i64 = nx_sa_validate_handle(ctx, req, rl, now_s, hbuf, 64, hn)
39 if rc != NX_MAUTH_OK { return 0 - 1 }
40 let lv: i64 = authz_level_of(hbuf, hn[0], uh, uhl, ul, un)
41 return authz_level_allow(lv, pp, pl, pv, np, path, sg_len(path))
42}
43
44func main() -> i64 {
45 sg_w("authz-session chain gate: OPAQUE token -> handle -> level -> NSFW decision (end-to-end)\n" as *u8)
46 sg_trunc("/tmp/nx_azs_keys.log" as *u8)
47 sg_trunc("/tmp/nx_azs_store.log" as *u8)
48
49 let oprf: *u8 = sys_mmap(32)
50 let akp: *u8 = sys_mmap(32)
51 let akb: *u8 = sys_mmap(33)
52 let edp: *u8 = sys_mmap(32)
53 let edb: *u8 = sys_mmap(32)
54 if nx_uas_server_keys_load_or_init("/tmp/nx_azs_keys.log" as *u8, oprf, akp, akb, edp, edb) != NX_UAS_OK { sg_w("KEYS FAIL\n" as *u8); sys_exit(1) }
55 let ctx: *NxAuthContext = sys_mmap(256) as *NxAuthContext
56 let store_p: *u8 = "/tmp/nx_azs_store.log" as *u8
57 let realm_p: *u8 = "nishifamily" as *u8
58 if nx_auth_context_init(ctx, realm_p, 11, realm_p, 11, store_p as i64, oprf, edp, edb, 900, 8192, 1, 1, 5, 1) != NX_MAUTH_OK { sg_w("CTX FAIL\n" as *u8); sys_exit(1) }
59 let mn: *u8 = sys_mmap(512)
60 let mnn: *i64 = sys_mmap(8) as *i64
61 if nx_modern_auth_register(ctx, "carol" as *u8, 5, "carol-secret-passphrase" as *u8, 23, mn, 512, mnn) != NX_MAUTH_OK { sg_w("REG carol FAIL\n" as *u8); sys_exit(1) }
62 if nx_modern_auth_register(ctx, "bob" as *u8, 3, "bob-secret-passphrase" as *u8, 21, mn, 512, mnn) != NX_MAUTH_OK { sg_w("REG bob FAIL\n" as *u8); sys_exit(1) }
63
64 let raw: *u8 = sys_mmap(NX_MAUTH_SESSION_TOKEN_BYTES)
65 let rawn: *i64 = sys_mmap(8) as *i64
66 let carol_b64: *u8 = sys_mmap(512)
67 rawn[0] = 0
68 if nx_modern_auth_login(ctx, "carol" as *u8, 5, "carol-secret-passphrase" as *u8, 23, raw, NX_MAUTH_SESSION_TOKEN_BYTES, rawn) != NX_MAUTH_OK { sg_w("LOGIN carol FAIL\n" as *u8); sys_exit(1) }
69 let carol_b64n: i64 = b64_encode(raw, NX_MAUTH_SESSION_TOKEN_BYTES, carol_b64)
70 let bob_b64: *u8 = sys_mmap(512)
71 rawn[0] = 0
72 if nx_modern_auth_login(ctx, "bob" as *u8, 3, "bob-secret-passphrase" as *u8, 21, raw, NX_MAUTH_SESSION_TOKEN_BYTES, rawn) != NX_MAUTH_OK { sg_w("LOGIN bob FAIL\n" as *u8); sys_exit(1) }
73 let bob_b64n: i64 = b64_encode(raw, NX_MAUTH_SESSION_TOKEN_BYTES, bob_b64)
74
75 // the session token carries the user-id-HASH (not the plaintext handle), so the level table is keyed by hash
76 let carol_hash: *u8 = sys_mmap(32)
77 nx_ncs_derive_user_id_hash(realm_p, 11, "carol" as *u8, 5, carol_hash)
78 let bob_hash: *u8 = sys_mmap(32)
79 nx_ncs_derive_user_id_hash(realm_p, 11, "bob" as *u8, 3, bob_hash)
80
81 let pp: *i64 = sys_mmap(8*8) as *i64
82 let pl: *i64 = sys_mmap(8*8) as *i64
83 let pv: *i64 = sys_mmap(8*8) as *i64
84 pp[0] = "/" as *u8 as i64
85 pl[0] = 1
86 pv[0] = 0
87 pp[1] = "/gallery/private/" as *u8 as i64
88 pl[1] = sg_len("/gallery/private/" as *u8)
89 pv[1] = 2
90 let np: i64 = 2
91 let uh: *i64 = sys_mmap(8*8) as *i64
92 let uhl: *i64 = sys_mmap(8*8) as *i64
93 let ul: *i64 = sys_mmap(8*8) as *i64
94 uh[0] = carol_hash as i64
95 uhl[0] = 32
96 ul[0] = 2
97 uh[1] = bob_hash as i64
98 uhl[1] = 32
99 ul[1] = 1
100 let un: i64 = 2
101
102 let req: *u8 = sys_mmap(4096)
103 let hbuf: *u8 = sys_mmap(64)
104 let hn: *i64 = sys_mmap(8) as *i64
105 let now_s: i64 = sys_now_realtime_sec()
106 var pass: i64 = 0
107
108 // T1: carol (private) -> NSFW ALLOW
109 let rl1: i64 = sg_req(req, "/gallery/private/p1" as *u8, carol_b64, carol_b64n)
110 let d1: i64 = sg_decide(ctx, req, rl1, now_s, hbuf, hn, uh, uhl, ul, un, pp, pl, pv, np, "/gallery/private/p1" as *u8)
111 var t1: i64 = 0
112 if d1 == 1 { t1 = 1 }
113 pass = pass + sg_row("T1 carol session -> level 2 -> NSFW ALLOWED" as *u8, t1)
114
115 // T2: bob (family) -> auth OK but NSFW DENY (decide == 0)
116 let rl2: i64 = sg_req(req, "/gallery/private/p1" as *u8, bob_b64, bob_b64n)
117 let d2: i64 = sg_decide(ctx, req, rl2, now_s, hbuf, hn, uh, uhl, ul, un, pp, pl, pv, np, "/gallery/private/p1" as *u8)
118 var t2: i64 = 0
119 if d2 == 0 { t2 = 1 }
120 pass = pass + sg_row("T2 bob session -> level 1 -> NSFW DENIED (not shared by all)" as *u8, t2)
121
122 // T3: NO session header -> auth FAIL (decide == -1)
123 let rl3: i64 = sg_cat(req, 0, "GET /gallery/private/p1 HTTP/1.1\r\nHost: x\r\n\r\n" as *u8)
124 let d3: i64 = sg_decide(ctx, req, rl3, now_s, hbuf, hn, uh, uhl, ul, un, pp, pl, pv, np, "/gallery/private/p1" as *u8)
125 var t3: i64 = 0
126 if d3 == (0 - 1) { t3 = 1 }
127 pass = pass + sg_row("T3 no X-Nishi-Session -> auth DENY (no token, no access)" as *u8, t3)
128
129 // T4: tampered token -> auth FAIL
130 let bad: *u8 = sys_mmap(512)
131 var bi: i64 = 0
132 while bi < carol_b64n { bad[bi] = carol_b64[bi]; bi = bi + 1 }
133 if (bad[0] as i64) == 65 { bad[0] = 66 as u8 }
134 if (bad[0] as i64) != 66 { bad[0] = 65 as u8 }
135 let rl4: i64 = sg_req(req, "/gallery/private/p1" as *u8, bad, carol_b64n)
136 let d4: i64 = sg_decide(ctx, req, rl4, now_s, hbuf, hn, uh, uhl, ul, un, pp, pl, pv, np, "/gallery/private/p1" as *u8)
137 var t4: i64 = 0
138 if d4 == (0 - 1) { t4 = 1 }
139 pass = pass + sg_row("T4 tampered token -> auth DENY (forged rejected)" as *u8, t4)
140
141 // T5: the session's user-id-hash resolves to carol's level (the chain keys on the stable hash, not plaintext)
142 let rl5: i64 = sg_req(req, "/gallery/x" as *u8, carol_b64, carol_b64n)
143 let rc5: i64 = nx_sa_validate_handle(ctx, req, rl5, now_s, hbuf, 64, hn)
144 var t5: i64 = 0
145 if rc5 == NX_MAUTH_OK { if authz_level_of(hbuf, hn[0], uh, uhl, ul, un) == 2 { t5 = 1 } }
146 pass = pass + sg_row("T5 session user-id-hash resolves to carol's level (2)" as *u8, t5)
147
148 // T6: the rest is exposed -- bob can view a public gallery item (decide == 1)
149 let rl6: i64 = sg_req(req, "/gallery/sunset.jpg" as *u8, bob_b64, bob_b64n)
150 let d6: i64 = sg_decide(ctx, req, rl6, now_s, hbuf, hn, uh, uhl, ul, un, pp, pl, pv, np, "/gallery/sunset.jpg" as *u8)
151 var t6: i64 = 0
152 if d6 == 1 { t6 = 1 }
153 pass = pass + sg_row("T6 public gallery item allowed (the rest is exposed)" as *u8, t6)
154
155 if pass == 6 {
156 let line: *u8 = "CMSGATE row=nx_authz_session session-to-level-to-nsfw-chain rows=6 pass=6 verdict=PASS\n" as *u8
157 let gf: i64 = sys_openat_append("knowledge/status/cms_gate.log" as *u8, 0x1a4)
158 if gf >= 0 { sys_write(gf, line, sg_len(line)); sys_close(gf) }
159 sg_w("AUTHZ-SESSION GATE GREEN 6/6 (OPAQUE token -> handle -> level -> NSFW gate, end-to-end)\n" as *u8)
160 sys_exit(0)
161 }
162 sg_w("AUTHZ-SESSION GATE RED\n" as *u8)
163 sys_exit(1)
164 return 1
165}