code wiki / _hdl_build / nx_modauth_arm.nx

nx_modauth_arm.nx source

↩ module page · 88 lines · 4846 B

1// nx_modauth_arm.nx -- PROVISION an admin into the canonical Modern Auth (the arming step that makes 2// "all sites use modern_auth" deployable). File-driven by construction so the operator's passphrase NEVER 3// touches chat / argv / stdout: it is read from a STAGED file, used to register the admin, and the one-time 4// BIP39 24-word recovery mnemonic is written to an out-file for the operator to save then DELETE (it is 5// never echoed). Idempotent: re-running supersedes the admin (additive-only store -- old passphrase dies, 6// new lives; rows 8-9 of nx_modauth_e2e_gate prove this). ONE server-key bundle + ONE store serve every 7// realm; realm+handle decide WHICH site+admin (a status token can't validate a wiki ctx -- realm-scoped hash). 8// 9// argv: [1]=keysfile [2]=storefile [3]=realm [4]=handle [5]=passphrase-file [6]=mnemonic-outfile 10// e.g. nx_modauth_arm /vault/nishi_auth_keys /vault/nishi_auth_store nishi_status_adm elder /tmp/pw /tmp/mn 11// Sovereign: nx_modern_auth_flow + nx_syscalls (no gcc, no 3rd-party). license_tier: ORIGINAL 12import "hub/nx_modern_auth_flow.nx" 13import "nx_syscalls.nx" 14const K_MAGIC_8192: i64 = 8192 15 16func arm_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 17func arm_w(s: *u8) -> i64 { sys_write(1, s, arm_len(s)); return 0 } 18 19func main(argc: i64, argv: *i64) -> i64 { 20 if argc < 7 { 21 sys_write(2, "usage: nx_modauth_arm <keysfile> <storefile> <realm> <handle> <passphrase-file> <mnemonic-outfile>\n" as *u8, 98) 22 return 1 23 } 24 let keysfile: *u8 = argv[1] as *u8 25 let storefile: *u8 = argv[2] as *u8 26 let realm: *u8 = argv[3] as *u8 27 let handle: *u8 = argv[4] as *u8 28 let pwfile: *u8 = argv[5] as *u8 29 let mnout: *u8 = argv[6] as *u8 30 let realm_n: i64 = arm_len(realm) 31 let handle_n: i64 = arm_len(handle) 32 33 // ---- read the operator passphrase from the staged file; trim trailing CR/LF (editors add them) ---- 34 let pwlen: *i64 = sys_mmap(16) as *i64 35 pwlen[0] = 0 36 let pwbuf: *u8 = sys_read_file(pwfile, pwlen) 37 if (pwbuf as i64) == 0 { arm_w("ARM FAIL: cannot read passphrase file\n" as *u8); return 2 } 38 // strip a leading UTF-8 BOM (EF BB BF) -- editors / shell pipes prepend one and it would 39 // silently become part of the passphrase, so login with the typed passphrase would never match. 40 var pw_start: i64 = 0 41 if pwlen[0] >= 3 { 42 if (pwbuf[0] as i64) == 239 { if (pwbuf[1] as i64) == 187 { if (pwbuf[2] as i64) == 191 { pw_start = 3 } } } 43 } 44 var pw_n: i64 = pwlen[0] 45 var trimming: i64 = 1 46 while trimming == 1 { 47 trimming = 0 48 if pw_n > pw_start { 49 let c: i64 = pwbuf[pw_n - 1] as i64 50 if c == 10 { pw_n = pw_n - 1; trimming = 1 } 51 if c == 13 { pw_n = pw_n - 1; trimming = 1 } 52 } 53 } 54 let pw_ptr: *u8 = ((pwbuf as i64) + pw_start) as *u8 55 let pw_eff: i64 = pw_n - pw_start 56 if pw_eff < 1 { arm_w("ARM FAIL: passphrase file is empty\n" as *u8); return 2 } 57 58 // ---- arm the server-key bundle (idempotent, persists to keysfile) + the realm context ---- 59 let oprf_seed: *u8 = sys_mmap(32) 60 let akp: *u8 = sys_mmap(32) 61 let akb: *u8 = sys_mmap(33) 62 let edp: *u8 = sys_mmap(32) 63 let edb: *u8 = sys_mmap(32) 64 if nx_uas_server_keys_load_or_init(keysfile, oprf_seed, akp, akb, edp, edb) != NX_UAS_OK { arm_w("ARM FAIL: server-key bundle\n" as *u8); return 3 } 65 let ctx: *NxAuthContext = sys_mmap(256) as *NxAuthContext 66 if nx_auth_context_init(ctx, realm, realm_n, realm, realm_n, storefile as i64, oprf_seed, edp, edb, 900, K_MAGIC_8192, 1, 1, 5, 1) != NX_MAUTH_OK { arm_w("ARM FAIL: context init\n" as *u8); return 4 } 67 68 // ---- register the admin -> one-time BIP39 mnemonic (additive-only; re-run supersedes) ---- 69 let mn: *u8 = sys_mmap(512) 70 let mn_n: *i64 = sys_mmap(16) as *i64 71 mn_n[0] = 0 72 if nx_modern_auth_register(ctx, handle, handle_n, pw_ptr, pw_eff, mn, 512, mn_n) != NX_MAUTH_OK { arm_w("ARM FAIL: register\n" as *u8); return 5 } 73 if mn_n[0] < 1 { arm_w("ARM FAIL: empty mnemonic\n" as *u8); return 6 } 74 75 // ---- write the recovery mnemonic to the out-file (0600), never to stdout ---- 76 let fd: i64 = sys_openat_wr(mnout, 0x180) 77 if fd < 0 { arm_w("ARM FAIL: cannot open mnemonic out-file\n" as *u8); return 7 } 78 sys_write(fd, mn, mn_n[0]) 79 sys_write(fd, "\n" as *u8, 1) 80 sys_close(fd) 81 82 arm_w("ARM OK: admin provisioned for realm '" as *u8) 83 sys_write(1, realm, realm_n) 84 arm_w("'. 24-word BIP39 recovery mnemonic written to the out-file (0600).\n" as *u8) 85 arm_w(" -> SAVE the mnemonic somewhere safe, then DELETE the passphrase file AND the mnemonic out-file.\n" as *u8) 86 arm_w(" -> Login from now on: POST handle+passphrase; the server mints a no-cookie X-Nishi-Session token.\n" as *u8) 87 return 0 88}