code wiki / _hdl_build / nx_office_closed_gate.nx
nx_office_closed_gate.nx source
↩ module page · 203 lines · 12262 B
1// nx_office_closed_gate.nx -- END-TO-END GATE for the CLOSED, realm-bound office instance (LP3 of /compare/legalpractice):
2// ONE nx_office_daemon binary, a tenant instance that accepts ONLY sessions of ITS realm, owns its documents through ITS
3// own ReBAC plane, resolves handles from a docportal-shaped uidmap, and never exposes the open-mode namespace.
4// The gate builds a FRESH realm under /tmp/<gate>/<now_us> (its own OPAQUE keys + account store, two registered users, a
5// uidmap it writes itself), spawns the DEPLOYED ./nx_office_daemon.elf on a probe port it first proves FREE, and drives
6// it over a real loopback socket. Inherits nx_gate_verdict: gv_check per tooth, gv_bite on the closed-mode gate, the
7// verdict in the EXIT CODE; the daemon is killed and reaped before the verdict. license_tier: ORIGINAL
8import "nx_office_serve.nx"
9import "nx_opaque_login.nx"
10import "nx_gate_verdict.nx"
11
12const OC_SCRATCH: *u8 = "/tmp/nx_office_closed_gate"
13const OC_DAEMON: *u8 = "./nx_office_daemon.elf"
14const OC_DIRMODE: i64 = 493
15const OC_SMALL: i64 = 256
16const OC_TOK: i64 = 600
17const OC_OUT: i64 = 1048576
18const OC_REQ: i64 = 65536
19const OC_CTX: i64 = 256
20const OC_MN: i64 = 512
21const OC_I64: i64 = 16
22const OC_REALM: *u8 = "officegate_realm"
23const OC_LABEL: *u8 = "Office gate realm"
24const OC_USER1: *u8 = "firmtest"
25const OC_USER2: *u8 = "otherlawyer"
26const OC_PW1: *u8 = "correct horse battery staple 1"
27const OC_PW2: *u8 = "another long passphrase 2"
28// light argon2id KSF for the gate (the daemon validates only; register/login run here, in-process)
29const OC_KSF_M: i64 = 256
30const OC_KSF_T: i64 = 2
31const OC_KSF_P: i64 = 1
32// probe port: a window of loopback ports, the pick DERIVED from the clock and proven FREE before the spawn
33const OC_PORT_BASE: i64 = 18600
34const OC_PORT_SPAN: i64 = 100
35const OC_CONNECT_MS: i64 = 1500
36const OC_SPAWN_TRIES: i64 = 40
37const OC_SPAWN_WAIT_MS: i64 = 250
38const OC_LOOPBACK_A: i64 = 127
39const OC_SIGKILL: i64 = 9
40const OC_DOC: *u8 = "closed-doc"
41
42func oc_path(out: *u8, root: *u8, tail: *u8) -> i64 {
43 var o: i64 = of_cat(out, 0, root)
44 o = of_cat(out, o, tail)
45 out[o] = 0 as u8
46 return o
47}
48func oc_status_is(out: *u8, n: i64, code: *u8) -> i64 {
49 if n < 12 { return 0 }
50 return of_memhas(out, 13, code)
51}
52// one HTTP exchange over loopback: connect (bounded), send, drain. Returns bytes read, -1 if it could not connect.
53func oc_send(port: i64, req: *u8, n: i64, out: *u8, cap: i64) -> i64 {
54 let addr: *u8 = sys_mmap(16)
55 nx_http_client_sockaddr_ipv4(addr, OC_LOOPBACK_A, 0, 0, 1, port)
56 let fd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0)
57 if fd < 0 { sys_munmap(addr, 16); return 0 - 1 }
58 if nx_connect_bounded(fd, addr, 16, OC_CONNECT_MS) < 0 { sys_close(fd); sys_munmap(addr, 16); return 0 - 1 }
59 let wr: i64 = sys_write(fd, req, n)
60 var got: i64 = 0 - 1
61 if wr == n { got = _drain(fd, out, cap) }
62 sys_close(fd)
63 sys_munmap(addr, 16)
64 return got
65}
66func oc_get(port: i64, path: *u8, tok: *u8, req: *u8, out: *u8) -> i64 {
67 var ro: i64 = of_cat(req, 0, "GET " as *u8)
68 ro = of_cat(req, ro, path)
69 ro = of_cat(req, ro, " HTTP/1.1\r\nHost: office.local\r\n" as *u8)
70 if tok[0] != (0 as u8) { ro = of_cat(req, ro, "X-Nishi-Session: " as *u8); ro = of_cat(req, ro, tok); ro = of_cat(req, ro, "\r\n" as *u8) }
71 ro = of_cat(req, ro, "Connection: close\r\n\r\n" as *u8)
72 return oc_send(port, req, ro, out, OC_OUT)
73}
74func oc_post(port: i64, path: *u8, tok: *u8, body: *u8, req: *u8, out: *u8) -> i64 {
75 var ro: i64 = of_cat(req, 0, "POST " as *u8)
76 ro = of_cat(req, ro, path)
77 ro = of_cat(req, ro, " HTTP/1.1\r\nHost: office.local\r\n" as *u8)
78 if tok[0] != (0 as u8) { ro = of_cat(req, ro, "X-Nishi-Session: " as *u8); ro = of_cat(req, ro, tok); ro = of_cat(req, ro, "\r\n" as *u8) }
79 ro = of_cat(req, ro, "Content-Length: " as *u8)
80 ro = of_catn(req, ro, of_slen(body))
81 ro = of_cat(req, ro, "\r\nConnection: close\r\n\r\n" as *u8)
82 ro = of_cat(req, ro, body)
83 return oc_send(port, req, ro, out, OC_OUT)
84}
85// register + login one user in the fixture realm; writes the base64 token (NUL-terminated) to tok; appends the
86// docportal-shaped uidmap row for it. Returns 1 on success.
87func oc_user(ctx: *NxAuthContext, handle: *u8, pw: *u8, uidmap: *u8, tok: *u8) -> i64 {
88 let mn: *u8 = sys_mmap(OC_MN)
89 let mnn: *i64 = sys_mmap(OC_I64) as *i64
90 if olg_register(ctx, handle, of_slen(handle), pw, of_slen(pw), mn, OC_MN, mnn) != NX_MAUTH_OK { return 0 }
91 let tn: *i64 = sys_mmap(OC_I64) as *i64
92 if olg_login(ctx, handle, of_slen(handle), pw, of_slen(pw), tok, OC_TOK, tn) != NX_MAUTH_OK { return 0 }
93 tok[tn[0]] = 0 as u8
94 let uid: *u8 = sys_mmap(OC_SMALL)
95 let uidn: *i64 = sys_mmap(OC_I64) as *i64
96 if olg_whoami(ctx, tok, tn[0], sys_now_realtime_sec(), uid, OC_SMALL, uidn) != NX_MAUTH_OK { return 0 }
97 let hx: *u8 = sys_mmap(OC_SMALL)
98 rb_hex(hx, uid, uidn[0])
99 let row: *u8 = sys_mmap(OC_SMALL + OC_SMALL)
100 var o: i64 = of_cat(row, 0, "MAP " as *u8)
101 o = of_cat(row, o, hx)
102 o = of_cat(row, o, " " as *u8)
103 o = of_cat(row, o, handle)
104 o = of_catc(row, o, 10)
105 if of_append_line(uidmap, row, o) != 0 { return 0 }
106 return 1
107}
108
109func main() -> i64 {
110 gv_head("NX-OFFICE-CLOSED-GATE -- LP3: the realm-bound CLOSED office instance over a real loopback socket (fresh OPAQUE realm, two users, own ReBAC plane, docportal-shaped uidmap; the deployed daemon binary is spawned on a port proven free)" as *u8)
111 let ctr: *i64 = gv_ctr()
112 sys_mkdir(OC_SCRATCH, OC_DIRMODE)
113 let fx: *u8 = sys_mmap(OC_SMALL)
114 var fo: i64 = of_cat(fx, 0, OC_SCRATCH)
115 fo = of_cat(fx, fo, "/" as *u8)
116 fo = of_catn(fx, fo, sys_now_us())
117 fx[fo] = 0 as u8
118 sys_mkdir(fx, OC_DIRMODE)
119 let keys: *u8 = sys_mmap(OC_SMALL); oc_path(keys, fx, "/keys.bin" as *u8)
120 let store: *u8 = sys_mmap(OC_SMALL); oc_path(store, fx, "/store.log" as *u8)
121 let uidmap: *u8 = sys_mmap(OC_SMALL); oc_path(uidmap, fx, "/store.log.uidmap" as *u8)
122 let root: *u8 = sys_mmap(OC_SMALL); oc_path(root, fx, "/root" as *u8)
123 let az: *u8 = sys_mmap(OC_SMALL); oc_path(az, fx, "/az_" as *u8)
124 gv_puts(" fixture: " as *u8); gv_puts(fx); gv_puts("\n" as *u8)
125 // ---- the fixture realm: keys + store + two users ----
126 let ctx: *NxAuthContext = sys_mmap(OC_CTX) as *NxAuthContext
127 let ctxok: i64 = olg_ctx_setup(ctx, keys, store, OC_REALM, of_slen(OC_REALM), OC_LABEL, of_slen(OC_LABEL), OC_KSF_M, OC_KSF_T, OC_KSF_P)
128 gv_check("fixture-realm-keys-and-store-initialised" as *u8, (ctxok == 0) as i64, ctr)
129 let tok1: *u8 = sys_mmap(OC_TOK)
130 let tok2: *u8 = sys_mmap(OC_TOK)
131 tok1[0] = 0 as u8; tok2[0] = 0 as u8
132 gv_check("user-1-registered-logged-in-and-mapped-in-the-uidmap" as *u8, oc_user(ctx, OC_USER1, OC_PW1, uidmap, tok1), ctr)
133 gv_check("user-2-registered-logged-in-and-mapped-in-the-uidmap" as *u8, oc_user(ctx, OC_USER2, OC_PW2, uidmap, tok2), ctr)
134 // ---- probe port: derived, then PROVEN free (a refused connect) before anything listens on it ----
135 let port: i64 = OC_PORT_BASE + (sys_now_us() % OC_PORT_SPAN)
136 let req: *u8 = sys_mmap(OC_REQ)
137 let out: *u8 = sys_mmap(OC_OUT)
138 let notok: *u8 = sys_mmap(4); notok[0] = 0 as u8
139 let pre: i64 = oc_get(port, "/office" as *u8, notok, req, out)
140 gv_puts(" probe port=" as *u8); gv_num(port); gv_puts(" pre-spawn connect=" as *u8); gv_num(pre); gv_puts("\n" as *u8)
141 if gv_need("probe-port-free-before-spawn (connect must be refused)" as *u8, (pre < 0) as i64, ctr) == 1 {
142 // ---- spawn the DEPLOYED daemon as a closed, realm-bound tenant instance ----
143 let pstr: *u8 = sys_mmap(OC_SMALL)
144 var po: i64 = of_catn(pstr, 0, port); pstr[po] = 0 as u8
145 let av: *i64 = sys_mmap(8 * 12) as *i64
146 av[0] = OC_DAEMON as i64; av[1] = pstr as i64; av[2] = keys as i64; av[3] = store as i64; av[4] = OC_REALM as i64
147 av[5] = root as i64; av[6] = ("/office" as *u8) as i64; av[7] = uidmap as i64; av[8] = ("closed" as *u8) as i64; av[9] = az as i64; av[10] = 0
148 let kid: i64 = sys_fork()
149 if kid == 0 {
150 sys_execve_clean(OC_DAEMON, av, 0 as *i64)
151 sys_exit(127)
152 }
153 var up: i64 = 0
154 var tries: i64 = 0
155 var n: i64 = 0 - 1
156 while tries < OC_SPAWN_TRIES { if up == 0 {
157 sys_sleep_ms(OC_SPAWN_WAIT_MS)
158 n = oc_get(port, "/office" as *u8, notok, req, out)
159 if n > 0 { up = 1 }
160 } tries = tries + 1 }
161 gv_puts(" daemon pid=" as *u8); gv_num(kid); gv_puts(" up=" as *u8); gv_num(up); gv_puts(" after tries=" as *u8); gv_num(tries); gv_puts("\n" as *u8)
162 gv_check("deployed-daemon-listens-on-the-probe-port" as *u8, up, ctr)
163 // ---- closed mode ----
164 let no_sess_401: i64 = oc_status_is(out, n, "401" as *u8)
165 gv_check("neg-control-no-session-refused-401-naming-the-login-surface" as *u8, (no_sess_401) & ((of_memhas(out, n, "closed" as *u8)) as i64), ctr)
166 let bad: *u8 = sys_mmap(OC_TOK)
167 var bi: i64 = 0
168 while tok1[bi] != (0 as u8) { bad[bi] = tok1[bi]; bi = bi + 1 }
169 bad[bi] = 0 as u8
170 if bi > 8 { if bad[8] == (65 as u8) { bad[8] = 66 as u8 } else { bad[8] = 65 as u8 } }
171 n = oc_get(port, "/office" as *u8, bad, req, out)
172 gv_check("neg-control-tampered-token-refused-401" as *u8, oc_status_is(out, n, "401" as *u8), ctr)
173 n = oc_get(port, "/office" as *u8, tok1, req, out)
174 let sess_200: i64 = oc_status_is(out, n, "200" as *u8)
175 let sess_401: i64 = oc_status_is(out, n, "401" as *u8)
176 gv_check("realm-session-opens-the-office-200" as *u8, (sess_200) & ((of_memhas(out, n, "Nishi Office" as *u8)) as i64), ctr)
177 gv_bite("closed-mode-gate" as *u8, no_sess_401, sess_401, ctr)
178 // ---- ownership claimed by the realm handle, through THIS instance's own ReBAC plane ----
179 n = oc_post(port, "/office/save" as *u8, tok1, "name=closed-doc&kind=doc&spec=H+Closed+Doc%0AP+Owned+by+the+firm+user." as *u8, req, out)
180 gv_check("authenticated-save-answers-303" as *u8, oc_status_is(out, n, "303" as *u8), ctr)
181 let dref: *u8 = sys_mmap(OC_SMALL); of_docref(dref, OC_DOC)
182 let owned: i64 = rb_obj_has_owner(az, dref)
183 let by1: i64 = rb_tuple_current(az, dref, "owner" as *u8, "user:firmtest" as *u8)
184 gv_puts(" owner tuple present=" as *u8); gv_num(owned); gv_puts(" by user:firmtest=" as *u8); gv_num(by1); gv_puts("\n" as *u8)
185 gv_check("save-claims-ownership-for-the-handle-resolved-from-the-uidmap" as *u8, ((owned == 1) as i64) & ((by1 == 1) as i64), ctr)
186 gv_check("neg-control-ownership-lands-on-the-tenant-plane-not-the-default-office-plane" as *u8, (rb_obj_has_owner(OF_AUTHZ, dref) == 0) as i64, ctr)
187 n = oc_get(port, "/office/doc/closed-doc" as *u8, notok, req, out)
188 gv_check("neg-control-unauthenticated-read-of-the-owned-document-refused-401" as *u8, oc_status_is(out, n, "401" as *u8), ctr)
189 n = oc_get(port, "/office/doc/closed-doc" as *u8, tok2, req, out)
190 gv_check("neg-control-another-realm-user-without-a-share-is-denied-the-owned-document" as *u8, oc_status_is(out, n, "404" as *u8), ctr)
191 n = oc_get(port, "/office/doc/closed-doc" as *u8, tok1, req, out)
192 gv_check("owner-reads-the-document-200" as *u8, (oc_status_is(out, n, "200" as *u8)) & ((of_memhas(out, n, "Closed Doc" as *u8)) as i64), ctr)
193 // ---- the open-mode namespace is not this instance: a document of the shared office root is absent here ----
194 n = oc_get(port, "/office/doc/agenda" as *u8, tok1, req, out)
195 gv_check("open-mode-namespace-not-exposed-to-the-tenant-404" as *u8, oc_status_is(out, n, "404" as *u8), ctr)
196 // ---- teardown: kill + reap the daemon (the restore is part of the experiment) ----
197 nx_kill(kid, OC_SIGKILL)
198 let wst: *i64 = sys_mmap(OC_I64) as *i64
199 let reaped: i64 = sys_wait4(kid, wst, 0)
200 gv_check("daemon-killed-and-reaped" as *u8, (reaped == kid) as i64, ctr)
201 }
202 return gv_verdict("OFFICE-CLOSED-GATE" as *u8, ctr, "LP3: one binary, a closed realm-bound tenant instance driven over loopback with its own realm, plane and uidmap" as *u8)
203}