code wiki / _hdl_build / nx_cms_admin.nx
nx_cms_admin.nx
buildroot/runtime/_hdl_build/nx_cms_admin.nx
about
nx_cms_admin.nx -- CMS C3+C4+C5: the WYSIWYG (field-based v1) ADMIN DAEMON. The human-engagement
surface: legal staff edit labelled fields in the browser; publish is atomic + revisioned; the
rendered page goes hot. Composes the session's proven CMS rungs:
nx_cms_store (C2: content as data, atomic + .prev revision) [gated]
nx_cms_render (C2: render-from-data, escape-on-render) [gated]
nx_html_sanitize(step 9: allowlist sanitize ON WRITE, 19/19 XSS) [gated]
nx_secure_token (step 3: 128-bit urandom session + CSRF, ct-eq)
_pe_pub (step 12: TEAM-AUTHORED publish state machine, CAPREG241)
nx_http_form (step 6: urlencoded body parse -- existing runtime rung)
nx_http_server (listen helper -- existing runtime rung)
Routes (the ONLY untrusted-input surface, rule 12 defensive-at-boundary):
GET / serve <site>/page.html (the published render)
GET /admin login form (no session) | field editor w/ CSRF (session)
POST /admin/login pw -> argon2id vs <site>/admin_pw.ar2 (C10, params live IN the file;
sha256 file = legacy migration fallback ONLY, .ar2 always wins);
5-strike lockout; session cookie HttpOnly+SameSite=Strict (Secure = TLS rung)
POST /admin/save session + CSRF -> _html fields SANITIZED, store ATOMIC, render, publish;
mode=draft -> _pe_draft guard, draft.txt only, public page UNTOUCHED (C9)
GET /admin/preview session -> render of the PENDING DRAFT (no-store); 404 when no draft
POST /admin/publish session + CSRF -> _pe_draft guard (409 from CLEAN), draft promoted atomic
POST /admin/discard session + CSRF -> _pe_draft guard (409 from CLEAN), draft set aside additive
POST /admin/rollback session + CSRF -> _pe_pub guard (refuses from DRAFT), .prev swap, render
argv: [1]=port [2]=site dir [3]=request budget (exit 0 after N requests -- deterministic gates,
no orphan daemons). Plain HTTP loopback v1; TLS termination = the sites-daemon integration rung.
license_tier: ORIGINAL
dependencies 13 imports · 2 importers
diagram shows first 10 each side; +3 more imports, +0 more importers in the complete lists below.
imports: nx_cms_render.nxnx_secure_token.nx_pe_pub.nx_pe_draft.nx_pe_blockr.nx_pe_seohead.nxnx_cms_pw.nxnx_session_ttl.nxnx_mfa.nxnx_http_form.nxnx_cms_multipart.nxnx_cms_snapshot.nxnx_sha256.nx
imported by: nx_cms_mfa_gate.nxnx_cms_session_gate.nx
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 39 | const CA_MAGIC_65536: i64 = 65536 |
| 40 | const CA_MAGIC_65535: i64 = 65535 |
| 41 | const CA_MAGIC_8192: i64 = 8192 |
| 42 | const CA_MAGIC_8191: i64 = 8191 |
| 43 | const CA_MAGIC_131072: i64 = 131072 |
| 44 | const CA_MAGIC_131071: i64 = 131071 |
| 45 | const CA_MAGIC_200000: i64 = 200000 |
| 46 | const CA_MAGIC_4096: i64 = 4096 |
| 47 | const CA_MAGIC_3600: i64 = 3600 |
| 48 | const CA_MAGIC_2048: i64 = 2048 |
| 49 | const CA_MAGIC_2047: i64 = 2047 |
| 50 | const CA_MAGIC_4095: i64 = 4095 |
| 51 | const CA_MAGIC_131080: i64 = 131080 |
| 54 | const CA_REQCAP: i64 = 262144 |
| 55 | const CA_OUTCAP: i64 = 524288 |
| 56 | const CA_LOCKOUT: i64 = 5 |
functions
| 58 | func ca_len(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } called by 1: ca_save_field |
| 59 | func ca_cat(dst: *u8, off: i64, s: *u8) -> i64 |
| 65 | func ca_catn(dst: *u8, off: i64, s: *u8, n: i64) -> i64 |
| 71 | func ca_catnum(dst: *u8, off: i64, v: i64) -> i64 |
| 84 | func ca_index(hay: *u8, n: i64, needle: *u8, nl: i64) -> i64 |
| 96 | func ca_atoi(s: *u8) -> i64 called by 1: main |
| 108 | func ca_conf_int(buf: *u8, n: i64, key: *u8, klen: i64, dflt: i64) -> i64 |
| 127 | func ca_path(dst: *u8, sitedir: *u8, leaf: *u8) -> i64 |
| 136 | func ca_send(cfd: i64, buf: *u8, n: i64) -> i64 |
| 148 | func ca_resp(cfd: i64, status: *u8, extra: *u8, body: *u8, bn: i64) -> i64 |
| 163 | func ca_content_length(buf: *u8, hend: i64) -> i64 |
| 180 | func ca_read_req(cfd: i64, buf: *u8, cap: i64, hend_out: *i64) -> i64 |
| 215 | func ca_session_ok(buf: *u8, hend: i64, sess: *u8) -> i64 |
| 227 | func ca_mfa_ok(body: *u8, bn: i64, totpsec: *u8, totpseclen: i64, now_unix: i64) -> i64 |
| 234 | func ca_csrf_ok(body: *u8, bn: i64, csrf: *u8) -> i64 |
| 244 | func ca_esc_into(dst: *u8, off: i64, val: *u8, vl: i64) -> i64 |
| 249 | func ca_editor_page(out: *u8, store: *u8, sn: i64, csrf: *u8) -> i64 |
| 318 | func ca_login_page(out: *u8, locked: i64) -> i64 calls 1: ca_cat |
| 327 | func ca_client_ok(buf: *u8, hend: i64, csess: *u8) -> i64 |
| 334 | func ca_client_login_page(out: *u8, bad: i64) -> i64 |
| 340 | func ca_portal_page(out: *u8) -> i64 |
| 345 | func ca_render_publish(sitedir: *u8) -> i64 |
| 382 | func ca_resp_ct(cfd: i64, status: *u8, ctype: *u8, body: *u8, bn: i64) -> i64 |
| 397 | func ca_sane_name(s: *u8, n: i64) -> i64 called by 1: main |
| 418 | func ca_lc(c: i64) -> i64 called by 1: ca_img_type |
| 424 | func ca_img_type(name: *u8, n: i64) -> i64 |
| 449 | func ca_magic_ok(t: i64, body: *u8, n: i64) -> i64 called by 1: main |
| 476 | func ca_img_ctype(t: i64) -> *u8 |
| 485 | func ca_seo_get(store: *u8, sn: i64, k1: *u8, k2: *u8, out: *u8, cap: i64) -> i64 |
| 492 | func ca_seo_head(store: *u8, sn: i64, out: *u8, cap: i64) -> i64 |
| 521 | func ca_path_key(req: *u8, rn: i64, key: *u8, cap: i64) -> i64 calls 1: ca_index |
| 549 | func ca_analytics_hit(apath: *u8, key: *u8) -> i64 |
| 576 | func ca_stats_page(out: *u8, apath: *u8) -> i64 |
| 613 | func ca_rate_ok(ip_arr: *i64, cnt_arr: *i64, ws_arr: *i64, nbox: *i64, ip: i64, now: i64, window: i64, maxn: i64) -> i64 called by 1: main |
| 633 | func ca_submit_append(spath: *u8, ts: i64, fname: *u8, fnl: i64, body: *u8, bn: i64) -> i64 |
| 652 | func ca_subs_page(out: *u8, spath: *u8) -> i64 |
| 678 | func ca_blocks_html(store: *u8, sn: i64, out: *u8, cap: i64) -> i64 |
| 703 | func ca_blocks_mut(old: *u8, on: i64, op: i64, idx: i64, line: *u8, ln2: i64, out: *u8, cap: i64) -> i64 |
| 737 | func ca_mkdir(path: *u8, mode: i64) -> i64 called by 1: main |
| 744 | func ca_blocks_editor(out: *u8, store: *u8, sn: i64, csrf: *u8) -> i64 |
| 791 | func ca_render_draft(sitedir: *u8, out: *u8) -> i64 |
| 815 | func ca_save_field(body: *u8, bn: i64, key: *u8, ishtml: i64, s_in: *u8, n_in: i64, s_out: *u8) -> i64 |
| 832 | func main(argc: i64, argv: *i64) -> i64 |