code wiki / (root) / nx_login_gate.nx

nx_login_gate.nx source

↩ module page · 90 lines · 4270 B

1// nx_login_gate.nx -- ★NISHI LOGIN: the UNIFIED sovereign auth gate. Validates a request's credential in ANY 2// presentation -- `X-Nishi-Cap: <cap>` (API), `Authorization: Bearer <cap>` (OAuth/MCP), or `Authorization: Basic 3// <user:cap>` (git, curl, browsers) -- against the ocap capability system for a REQUIRED SCOPE. This is the shared 4// validator behind the edge `auth=` switch AND the git gate: one credential (a scoped, attenuable, revocable cap), 5// three wire forms. Composes capt_verify (nx_cap_token) + basic_auth_decode (nx_basic_auth) + b64_decode. The OPAQUE 6// session path (browser SSO) layers on top via nx_site_auth. license_tier: ORIGINAL 7import "nx_syscalls.nx" 8import "nx_cap_token.nx" 9import "nx_basic_auth.nx" 10 11// case-insensitive: does s[0..len] equal `lower` (already lowercase)? 12func lg_ci_eq(s: *u8, lower: *u8, len: i64) -> i64 { 13 var i: i64 = 0 14 while i < len { 15 var c: i64 = s[i] as i64 16 if c >= 65 { if c <= 90 { c = c + 32 } } 17 if c != (lower[i] as i64) { return 0 } 18 i = i + 1 19 } 20 return 1 21} 22 23// find header <name> (lowercase, no colon). On success write value offset+len (trimmed) and return 1; else 0. 24func lg_header(req: *u8, n: i64, name: *u8, namelen: i64, voff: *i64, vlen: *i64) -> i64 { 25 var i: i64 = 0 26 var found: i64 = 0 27 while i < n { 28 if found == 0 { 29 var linestart: i64 = 0 30 if i == 0 { linestart = 1 } 31 if i > 0 { if req[i - 1] == (10 as u8) { linestart = 1 } } 32 if linestart == 1 { if i + namelen + 1 <= n { 33 if lg_ci_eq((req as i64 + i) as *u8, name, namelen) == 1 { if req[i + namelen] == (58 as u8) { 34 var v: i64 = i + namelen + 1 35 var sk: i64 = 1 36 while sk == 1 { if v < n { if req[v] == (32 as u8) { v = v + 1 } else { sk = 0 } } else { sk = 0 } } 37 var e: i64 = v 38 var go: i64 = 1 39 while go == 1 { if e < n { let c: i64 = req[e] as i64; if c == 13 { go = 0 } else { if c == 10 { go = 0 } else { e = e + 1 } } } else { go = 0 } } 40 voff[0] = v; vlen[0] = e - v 41 found = 1 42 } } 43 } } 44 i = i + 1 45 } else { i = n } 46 } 47 return found 48} 49 50// extract the cap token from the request (X-Nishi-Cap | Authorization: Bearer | Authorization: Basic <user:cap>). 51// writes the token to `out` (cap bytes) and returns its length, or 0 if no credential present. 52func lg_extract_cap(req: *u8, n: i64, out: *u8, cap: i64) -> i64 { 53 let voff: *i64 = sys_mmap(16) as *i64 54 let vlen: *i64 = sys_mmap(16) as *i64 55 // 1) X-Nishi-Cap 56 if lg_header(req, n, "x-nishi-cap" as *u8, 11, voff, vlen) == 1 { 57 let l: i64 = vlen[0] 58 if l > 0 { if l <= cap { var i: i64 = 0; while i < l { out[i] = req[voff[0] + i]; i = i + 1 } return l } } 59 } 60 // 2) Authorization 61 if lg_header(req, n, "authorization" as *u8, 13, voff, vlen) == 1 { 62 let av: *u8 = (req as i64 + voff[0]) as *u8 63 let al: i64 = vlen[0] 64 // Bearer <cap> 65 if al > 7 { if lg_ci_eq(av, "bearer " as *u8, 7) == 1 { 66 let bl: i64 = al - 7 67 if bl <= cap { var i: i64 = 0; while i < bl { out[i] = av[7 + i]; i = i + 1 } return bl } 68 } } 69 // Basic <user:cap> -> cap is the password half 70 if al > 6 { if lg_ci_eq(av, "basic " as *u8, 6) == 1 { 71 let ub: *u8 = sys_mmap(256) 72 let ul: *i64 = sys_mmap(16) as *i64 73 let pl: *i64 = sys_mmap(16) as *i64 74 if basic_auth_decode(av, al, ub, 256, ul, out, cap, pl) == 0 { return pl[0] } 75 } } 76 } 77 return 0 78} 79 80// THE GATE: is the request authorized for `scope`? secret = cap signing key (tools_cap_secret.key). now = epoch. 81// returns 1 (authorized) / 0 (deny -- absent/invalid/expired/wrong-scope/revoked via capt_verify). 82func login_gate_cap(req: *u8, n: i64, secret: *u8, seclen: i64, scope: *u8, scopelen: i64, now: i64) -> i64 { 83 let tok: *u8 = sys_mmap(4096) 84 let tl: i64 = lg_extract_cap(req, n, tok, 4096) 85 if tl <= 0 { return 0 } 86 if capt_verify(secret, seclen, tok, tl, scope, scopelen, now) == 1 { return 1 } 87 return 0 88} 89 90func main() -> i64 { return 0 }