code wiki / _hdl_build / nx_invite_token.nx

nx_invite_token.nx

buildroot/runtime/_hdl_build/nx_invite_token.nx

15008 B346 linesdepth 5pulls 7 transitivereach 11 importersview sourcekind library
docsdependenciesstructsconstsfunctions

about

nx_invite_token.nx -- SECRET single-use, expiring, realm+level-scoped INVITE TOKEN store. Purpose: let a remote party (e.g. a law firm) self-register their OWN credential on an admin.<domain> portal WITHOUT a guessable handle being the only gate -- they present a secret single-use invite token that an owner minted out-of-band. The token is the bearer secret; the server stores ONLY sha256(token) so a stolen store cannot reconstruct any live token (rule: secrets never at rest in the clear). Storage doctrine (ADDITIVE-ONLY, per global rule 13), modeled on hub/nx_user_account_store.nx (nx_uas_append): append-only text log, one row per line, a single sys_write of < 512 bytes => atomic on the substrate (O_APPEND). LATEST row for a token-hash WINS. Single-use = consume appends a superseding "consumed" row; history is never deleted. THE TOKEN: inv_issue mints 32 CSPRNG bytes -> 64 lowercase-hex chars (out_token_hex) = the bearer secret returned to the caller. The STORED identity is sha256(out_token_hex) hex-encoded. inv_check/inv_consume re-hash the presented hex token the SAME way (sha256 of the 64-hex bytes), so issue and check agree by construction. (Hashing the printable hex token -- not re-decoding to raw -- keeps the wire contract one opaque string and avoids a decode step on the hot path.) Row formats (space-delimited, '\n'-terminated; realm is a space/newline-free realm id): issued: INV issued <hash:64hex> <realm> <level:dec> <expiry:hex16>\n consumed: INV consumed <hash:64hex> <ts:hex16>\n COMPOSES: nx_syscalls (openat_append/read_file/fsync/write), nx_csprng (nx_csprng_fill), nx_sha256 (sha256_digest -- the canonical substrate SHA-256 one-shot). COMPOSED BY: _hdl_build/nx_docportal_admin_daemon (POST /admin/register invite gate). license_tier: ORIGINAL

dependencies 3 imports · 6 importers

nx_syscalls.nx nx_csprng.nx nx_sha256.nx nx_invite_token.nx nx_docportal_admin_daemon.nx nx_email_invite.nx nx_email_invite_gate.nx nx_email_portal_daemon.nx nx_invite_issue_cli.nx nx_invite_token_gate.nx

imports: nx_syscalls.nxnx_csprng.nxnx_sha256.nx

imported by: nx_docportal_admin_daemon.nxnx_email_invite.nxnx_email_invite_gate.nxnx_email_portal_daemon.nxnx_invite_issue_cli.nxnx_invite_token_gate.nx

structs

none

consts

33const NX_INV_OK: i64 = 0
34const NX_INV_BAD_INPUT: i64 = 1480
35const NX_INV_IO_FAILED: i64 = 1481
36const NX_INV_RNG_FAILED: i64 = 1482
39const NX_INV_TOKEN_BYTES: i64 = 32 // CSPRNG entropy per token
40const NX_INV_TOKEN_HEX: i64 = 64 // = 2 * NX_INV_TOKEN_BYTES (the wire token width)
41const NX_INV_HASH_HEX: i64 = 64 // = 2 * 32 (hex of sha256(token))
42const NX_INV_ISSUED_HASH_OFF: i64 = 11 // strlen("INV issued ")
43const NX_INV_CONSUMED_HASH_OFF: i64 = 13 // strlen("INV consumed ")
44const NX_INV_LINE_CAP: i64 = 512 // one row, comfortably < 512 (atomic append)
45const NX_INV_MAX_REALM_BYTES: i64 = 128 // realm-id upper bound (stays inside one row)
46const NX_INV_EXPIRY_HEX: i64 = 16 // 64-bit unix expiry, fixed-width hex
47const NX_INV_MAX_STORE_BYTES: i64 = 16777216 // 16 MiB scan cap

functions

51func _inv_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 }
52func _inv_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 }
54func _inv_hex_enc(src: *u8, n: i64, out: *u8) -> i64
65func _inv_i64_hex16(v: i64, out: *u8) -> i64
76func _inv_i64_dec(v: i64, out: *u8) -> i64
called by 1: inv_issue calls 1: sys_mmap
87func _inv_nib(c: i64) -> i64
called by 1: _inv_parse_hex16
95func _inv_parse_hex16(data: *u8, start: i64) -> i64
called by 1: _inv_parse_issued calls 1: _inv_nib
108func _inv_parse_dec(data: *u8, start: i64, end: i64) -> i64
called by 1: _inv_parse_issued
125func _inv_match_hash(data: *u8, off: i64, want_hex: *u8) -> i64
called by 1: inv_check
137func _inv_parse_issued(data: *u8, after_hash: i64, eol: i64, realm: *u8, realm_n: i64,
186func inv_issue(store_path: *u8, realm: *u8, realm_n: i64, level: i64, ttl_s: i64, now_s: i64,
243func inv_check(store_path: *u8, token_hex: *u8, token_n: i64, realm: *u8, realm_n: i64, now_s: i64) -> i64
321func inv_consume(store_path: *u8, token_hex: *u8, token_n: i64, now_s: i64) -> i64