nx_https_get_cli.nx source
↩ module page · 105 lines · 4984 B
1// nx_https_get_cli.nx -- the OPERATOR/MCP-facing sovereign HTTPS fetch (replaces WebFetch + curl).
2// nx_https_get <url> [connect-host:port]
3// <url> fetched over OUR TLS 1.3 + Mozilla trust store; raw response (status+headers+body) to stdout.
4// [connect-host:port] OPTIONAL connect override (curl --connect-to): open the TCP+TLS to THIS endpoint while
5// keeping SNI + Host + cert-name = the URL's host. Lets us fetch our OWN vhosts straight
6// from the sovereign edge (sites.elf 127.0.0.1:8443), bypassing the DSM nginx that also
7// squats :443 for unclaimed SNIs (andelinwest.com internally hit DSM's self-signed cert).
8// The tools daemon fork-execs this on a GREEN tool_allowlist.conf row, cap-gated to nx_https_get, and returns
9// stdout as the tools/call result. Uses PRODUCTION entropy (nx_csprng_fill from /dev/urandom). license_tier: ORIGINAL
10import "nx_syscalls.nx"
11import "nx_csprng.nx"
12import "nx_x509_trust_store.nx"
13import "nx_trust_store_load_from_certdata.nx"
14import "nx_tls13_client_validate_certificate.nx"
15import "nx_tls13_client_session_run.nx"
16import "nx_tls13_chrome_session.nx" // Chrome-JA3 ClientHello runner (beats anti-bot CDN TLS walls; inherits the recv_hs reassembly fix)
17import "nx_https_url_for_fetch.nx"
18import "nx_https_url_connect.nx"
19import "nx_https_get_complete.nx"
20import "nx_tls_cert_cache.nx"
21import "nx_https_fetch_lib.nx" // the shared fetch composition (one implementation, shared with nx_mvault_fetch)
22const HGC_MAGIC_4194304: i64 = 4194304
23const HGC_MAGIC_65535: i64 = 65535
24
25const HGC_CERTDATA: *u8 = "data/mozilla_certdata.txt" as *u8
26const HGC_OUTCAP: i64 = 4194304 // 4 MiB response cap
27
28func hgc_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
29func hgc_put(s: *u8) -> i64 { sys_write(1, s, hgc_slen(s)); return 0 }
30func hgc_putn(v: i64) -> i64 {
31 let b: *u8 = sys_mmap(24)
32 var m: i64 = v
33 if m == 0 { b[0] = 48 as u8; sys_write(1, b, 1); return 0 }
34 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m }
35 var nd: i64 = 0
36 var t: i64 = m
37 while t > 0 { nd = nd + 1; t = t / 10 }
38 var i: i64 = nd - 1
39 while i >= 0 { b[i] = (48 + (m % 10)) as u8; m = m / 10; i = i - 1 }
40 sys_write(1, b, nd)
41 return 0
42}
43
44func main(argc: i64, argv: *i64) -> i64 {
45 if argc < 2 { hgc_put("ERROR: usage: nx_https_get <url> [connect-host:port]\n" as *u8); return 2 }
46 let url: *u8 = argv[1] as *u8
47 let now: i64 = sys_now_realtime_sec()
48
49 // ---- trust store (loaded once; the fetch composition now lives in
50 // nx_https_fetch_lib so the album downloader shares ONE implementation
51 // instead of duplicating ~90 lines of crypto setup -- 2026-07-31) ----
52 let store_i: i64 = hf_store_load()
53 if store_i <= 0 { hgc_put("ERROR: trust-store load failed (data/mozilla_certdata.txt on daemon CWD?)\n" as *u8); return 3 }
54
55 var cip: i64 = 0
56 var cport: i64 = 0
57 if argc >= 3 {
58 let ipbox: *i64 = sys_mmap(8) as *i64
59 let portbox: *i64 = sys_mmap(8) as *i64
60 if hgc_parse_ipport(argv[2] as *u8, ipbox, portbox) != 1 { hgc_put("ERROR: bad connect-override (want a.b.c.d:port)\n" as *u8); return 2 }
61 cip = ipbox[0]
62 cport = portbox[0]
63 }
64
65 let out: *u8 = sys_mmap(HGC_OUTCAP)
66 let n: i64 = hf_fetch(store_i, url, cip, cport, out, HGC_OUTCAP)
67 if n == HF_ERR_URL { hgc_put("ERROR: bad url\n" as *u8); return 2 }
68 if n == HF_ERR_CONNECT { hgc_put("ERROR: connect failed\n" as *u8); return 3 }
69 if n == HF_ERR_TLS { hgc_put("ERROR: TLS handshake failed\n" as *u8); return 4 }
70 if n == HF_ERR_HTTP { hgc_put("ERROR: HTTP fetch failed\n" as *u8); return 5 }
71 if n < 0 { hgc_put("ERROR: fetch failed\n" as *u8); return 5 }
72 sys_write(1, out, n)
73 return 0
74}
75
76
77// parse "a.b.c.d:port" -> ip_out (big-endian packed u32, e.g. 127.0.0.1 -> 0x7F000001) + port_out. 1 ok / 0 bad.
78func hgc_parse_ipport(s: *u8, ip_out: *i64, port_out: *i64) -> i64 {
79 var packed: i64 = 0
80 var val: i64 = 0
81 var nocts: i64 = 0
82 var port: i64 = 0
83 var indots: i64 = 1
84 var i: i64 = 0
85 while s[i] != (0 as u8) {
86 let c: i64 = s[i] as i64
87 if indots == 1 {
88 if c == 46 { packed = (packed << 8) | (val & 0xff); nocts = nocts + 1; val = 0 }
89 else { if c == 58 { packed = (packed << 8) | (val & 0xff); nocts = nocts + 1; val = 0; indots = 0 }
90 else { if c < 48 { return 0 } if c > 57 { return 0 } val = val * 10 + (c - 48) } }
91 } else {
92 if c < 48 { return 0 }
93 if c > 57 { return 0 }
94 port = port * 10 + (c - 48)
95 }
96 i = i + 1
97 }
98 if indots == 1 { return 0 } // no ':' -> no port given
99 if nocts != 4 { return 0 } // need exactly 4 octets
100 if port <= 0 { return 0 }
101 if port > HGC_MAGIC_65535 { return 0 }
102 ip_out[0] = packed
103 port_out[0] = port
104 return 1
105}