code wiki / _hdl_build / nx_profile_backup_run.nx
nx_profile_backup_run.nx source
↩ module page · 137 lines · 6569 B
1// nx_profile_backup_run.nx -- RUNNER: encrypted OS backup of the REAL browser profile store.
2// Composes nx_browser_profile_store (seeds the live store on first run) + nx_profile_backup (machine-bound
3// ChaCha20-Poly1305 blobs, built-in restore-verify). Destination from knowledge/hosting/profile_backup.conf
4// (rule 17: config, not hardcode; default = /mnt/c/Users/elder/.nishi/profile_backup = the Windows OS side,
5// outside the repo). Enumerates knowledge/store/browser_profile-* via getdents (no shell). Appends ONE
6// receipt line to knowledge/status/profile_backup.log. Exit 0 iff every store file backed up + verified.
7// expect_exit: 0 license_tier: ORIGINAL
8import "nx_browser_profile_store.nx"
9import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc)
10import "nx_profile_backup.nx"
11const K_MAGIC_1024: i64 = 1024
12const K_MAGIC_262144: i64 = 262144
13const K_MAGIC_2048: i64 = 2048
14const K_MAGIC_4096: i64 = 4096
15
16func r_pw(s: *u8) -> i64 { sys_write(1, s, pb_slen(s)); return 0 }
17// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch
18// buffer per call and never freed it -- 4096B leaked PER CALL at page granularity,
19// the defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M
20// calls). nxi_* is MSB-first, allocates NOTHING, emits identical bytes incl. sign.
21func r_pn(v: i64) -> i64 { nxi_out(v); return 0 }
22func r_apps(b: *u8, n: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){b[n+i]=s[i];i=i+1} return n+i }
23func r_appn(b: *u8, n: i64, v: i64) -> i64 {
24 let t: *u8=sys_mmap(28); var m: i64=v; var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1}
25 var i: i64=0; var p: i64=n; while i<k{b[p]=t[k-1-i];p=p+1;i=i+1} return p }
26
27func main() -> i64 {
28 r_pw("=== nx_profile_backup_run: encrypted OS backup of the live browser profile store ===\n" as *u8)
29 // machine-bound key material
30 let ikm: *u8 = sys_mmap(256)
31 let ilen: i64 = pb_machine_ikm(ikm, 256)
32 if ilen <= 0 { r_pw("no /etc/machine-id -> cannot derive machine-bound key\n" as *u8); return 1 }
33
34 // seed the live store on first run (so the profile store EXISTS as a real artifact)
35 if bp_exists(BP_PROFILE_PREFIX, "setting:profile_created" as *u8) == 0 {
36 let ep: *u8 = sys_mmap(64)
37 var en: i64 = 0
38 en = r_appn(ep, en, sys_now_realtime_sec())
39 ep[en] = 0 as u8
40 bp_put(BP_PROFILE_PREFIX, "setting:profile_created" as *u8, ep, en)
41 r_pw("seeded live profile store (setting:profile_created)\n" as *u8)
42 }
43
44 // destination (simple parse: last line of conf that starts with '/')
45 let dest: *u8 = sys_mmap(K_MAGIC_1024)
46 var dlen: i64 = 0 - 1
47 let cbox: *i64 = sys_mmap(16) as *i64
48 let cb: *u8 = sys_read_file("knowledge/hosting/profile_backup.conf" as *u8, cbox)
49 if (cb as i64) != 0 {
50 var i: i64 = 0
51 var ls: i64 = 0
52 while i <= cbox[0] {
53 var eol: i64 = 0
54 if i == cbox[0] { eol = 1 } else { if (cb[i] as i64) == 10 { eol = 1 } }
55 if eol == 1 {
56 if i > ls { if (cb[ls] as i64) == 47 {
57 var k: i64 = 0
58 while ls + k < i { dest[k] = cb[ls + k]; k = k + 1 }
59 dest[k] = 0 as u8
60 dlen = k
61 } }
62 ls = i + 1
63 }
64 i = i + 1
65 }
66 }
67 if dlen <= 0 { r_pw("no dest in knowledge/hosting/profile_backup.conf -> RED\n" as *u8); return 1 }
68 r_pw("dest = " as *u8); r_pw(dest); r_pw("\n" as *u8)
69 // ensure the dest dirs exist (parent then dest; EEXIST is fine)
70 sys_mkdir("/mnt/c/Users/elder/.nishi" as *u8, 0x1c0)
71 sys_mkdir(dest, 0x1c0)
72
73 // enumerate knowledge/store/browser_profile-* and back each file up
74 let dfd: i64 = sys_openat_rd("knowledge/store" as *u8)
75 if dfd < 0 { r_pw("cannot open knowledge/store\n" as *u8); return 1 }
76 let buf: *u8 = sys_mmap(K_MAGIC_262144)
77 let stem: *u8 = "browser_profile-"
78 var files: i64 = 0
79 var okc: i64 = 0
80 let src: *u8 = sys_mmap(K_MAGIC_2048)
81 let dst: *u8 = sys_mmap(K_MAGIC_2048)
82 var go: i64 = 1
83 while go == 1 {
84 let n: i64 = sys_getdents64(dfd, buf, K_MAGIC_262144)
85 if n <= 0 { go = 0 } else {
86 var off: i64 = 0
87 while off < n {
88 let reclen: i64 = (buf[off+16] as i64) + ((buf[off+17] as i64) * 256)
89 let name: *u8 = buf + off + 19
90 var m: i64 = 1
91 var i: i64 = 0
92 while stem[i] != (0 as u8) { if name[i] != stem[i] { m = 0; i = pb_slen(stem) } else { i = i + 1 } }
93 if m == 1 {
94 files = files + 1
95 var o: i64 = 0
96 o = r_apps(src, 0, "knowledge/store/" as *u8)
97 o = r_apps(src, o, name)
98 src[o] = 0 as u8
99 o = r_apps(dst, 0, dest)
100 o = r_apps(dst, o, "/" as *u8)
101 o = r_apps(dst, o, name)
102 o = r_apps(dst, o, ".nxpb" as *u8)
103 dst[o] = 0 as u8
104 let rc: i64 = pb_backup_file(src, dst, ikm, ilen)
105 r_pw(" " as *u8); r_pw(name)
106 if rc == 0 { r_pw(" -> backed up + restore-verified\n" as *u8); okc = okc + 1 } else { r_pw(" -> FAILED rc=" as *u8); r_pn(rc); r_pw("\n" as *u8) }
107 }
108 off = off + reclen
109 }
110 }
111 }
112 sys_close(dfd)
113
114 // receipt (one line, appended)
115 let bb: *u8 = sys_mmap(K_MAGIC_4096)
116 var bn: i64 = 0
117 bn = r_apps(bb, bn, "PROFILE-BACKUP epoch=" as *u8)
118 bn = r_appn(bb, bn, sys_now_realtime_sec())
119 bn = r_apps(bb, bn, " files=" as *u8)
120 bn = r_appn(bb, bn, files)
121 bn = r_apps(bb, bn, " ok=" as *u8)
122 bn = r_appn(bb, bn, okc)
123 bn = r_apps(bb, bn, " dest=" as *u8)
124 bn = r_apps(bb, bn, dest)
125 var green: i64 = 0
126 if files > 0 { if okc == files { green = 1 } }
127 if green == 1 { bn = r_apps(bb, bn, " verdict=GREEN" as *u8) } else { bn = r_apps(bb, bn, " verdict=RED" as *u8) }
128 bb[bn] = 10 as u8
129 bn = bn + 1
130 let lf: i64 = sys_openat_append("knowledge/status/profile_backup.log" as *u8, 0x1a4)
131 if lf >= 0 { sys_write(lf, bb, bn); sys_close(lf) }
132
133 r_pw("PROFILE-BACKUP files=" as *u8); r_pn(files); r_pw(" ok=" as *u8); r_pn(okc)
134 if green == 1 { r_pw(" verdict=GREEN -- second copy encrypted on the OS, every blob restore-verified\n" as *u8); return 0 }
135 r_pw(" verdict=RED\n" as *u8)
136 return 1
137}