nx_video_sniff.nx source
↩ module page · 473 lines · 26634 B
1// nx_video_sniff.nx -- the DISCOVERY->DOWNLOAD bridge for JS-hardened video sites. Runs a page's JS on the
2// sovereign engine (via nx_media_jsexec), captures the stream/media URLs its obfuscated code CONSTRUCTS and
3// fetches, RANKS them (a manifest beats a raw segment beats nothing), and emits a DOWNLOAD PLAN routing the
4// best target to the EXISTING X-DLP engine: .m3u8 -> nx_hls_get (handles master/variant + #EXT-X-KEY AES-128
5// decrypt + TS->fMP4), .mp4/.webm -> nx_video_get. This is the "sniff the video URL" step a browser
6// video-download extension does, made native.
7//
8// HONEST CAPABILITY LINE (what this + the X-DLP engine actually beat, and what they don't):
9// * OBFUSCATION -> BEATEN by EXECUTING the bundle (we run its JS) rather than reading it. The URL the code
10// builds at runtime surfaces regardless of how the source is mangled.
11// * SIGNED/TOKENED URLs -> captured WHEN the page builds them client-side from page data (id/hash/consts).
12// If a signed URL requires a SERVER round-trip (fetch config -> server returns signed manifest), round-1
13// pending-capture does NOT have it -> that needs the MULTI-ROUND real-network capture (next rung; here the
14// fetches PEND, no network). Named honestly, not overclaimed.
15// * #EXT-X-KEY AES-128 HLS encryption -> BEATEN (nx_hls_get + nx_aes_cbc, NIST-KAT'd, live-verified).
16// * WIDEVINE / PLAYREADY / FAIRPLAY EME DRM -> the REAL WALL. Content is decrypted by a closed CDM blob with
17// keys from a license server; decrypted frames never touch JS. NOT defeatable natively (needs a CDM) and
18// legally fraught. (ClearKey EME, which puts keys in JS, is the one EME variant that IS reachable -- a
19// later rung.) A site with genuine Widevine is out of reach no matter how good discovery is; MANY sites
20// that LOOK DRM'd are actually just obfuscation + signing + AES-128 = fully in reach.
21import "nx_syscalls.nx"
22import "nx_js_eval.nx"
23import "nx_media_jsexec.nx" // mjx_harvest_js, mjx_contains, mjx_is_media_url
24import "nx_yt_basejs.nx" // bjs_find_nfunc_name (NATIVE name-find -- no JS engine)
25import "nx_yt_nsolve.nx" // ns_solve (LAST-MILE: runs the site's own fn on the browser engine)
26const VSK_MAGIC_2048: i64 = 2048
27const VSK_MAGIC_2047: i64 = 2047
28const VSK_MAGIC_2560: i64 = 2560
29const VSK_MAGIC_8589934592: i64 = 8589934592
30const VSK_MAGIC_8192: i64 = 8192
31const VSK_MAGIC_4096: i64 = 4096
32const VSK_MAGIC_262144: i64 = 262144
33const VSK_MAGIC_1048576: i64 = 1048576
34
35const VSK_KILLED: i64 = 0 - 1 // the guard tripped: the page's JS was runaway/hostile and got killed
36const VSK_NONE: i64 = 0
37const VSK_HLS: i64 = 1 // .m3u8 -> nx_hls_get
38const VSK_DASH: i64 = 2 // .mpd -> DASH downloader (future rung; nx_hls_get is HLS-only)
39const VSK_DIRECT: i64 = 3 // .mp4/.webm/.mkv/.mov -> nx_video_get
40const VSK_SEGMENT: i64 = 4 // .ts/.m4s alone (no manifest) -> incomplete without the playlist
41
42// classify ONE url by extension (substring, so a ?token query doesn't defeat it).
43func vs_url_kind(u: *u8, ul: i64) -> i64 {
44 if mjx_contains(u, ul, ".m3u8" as *u8, 5) == 1 { return VSK_HLS }
45 if mjx_contains(u, ul, ".mpd" as *u8, 4) == 1 { return VSK_DASH }
46 if mjx_contains(u, ul, ".mp4" as *u8, 4) == 1 { return VSK_DIRECT }
47 if mjx_contains(u, ul, ".webm" as *u8, 5) == 1 { return VSK_DIRECT }
48 if mjx_contains(u, ul, ".mkv" as *u8, 4) == 1 { return VSK_DIRECT }
49 if mjx_contains(u, ul, ".mov" as *u8, 4) == 1 { return VSK_DIRECT }
50 if mjx_contains(u, ul, ".m4s" as *u8, 4) == 1 { return VSK_SEGMENT }
51 if mjx_contains(u, ul, ".ts" as *u8, 3) == 1 { return VSK_SEGMENT }
52 return VSK_NONE
53}
54// download preference: a MANIFEST (all qualities + segments) beats a direct file beats a bare segment.
55// HLS > DIRECT > DASH > SEGMENT. (DASH ranks below direct only because our downloader can't fetch it yet.)
56func vs_kind_rank(k: i64) -> i64 {
57 if k == VSK_HLS { return 5 }
58 if k == VSK_DIRECT { return 4 }
59 if k == VSK_DASH { return 3 }
60 if k == VSK_SEGMENT { return 2 }
61 return 0
62}
63// the X-DLP route name for a kind (what engine downloads it).
64func vs_route_name(k: i64) -> *u8 {
65 if k == VSK_HLS { return "hls\x00" as *u8 } // nx_hls_get (master/variant + AES-128 + TS->fMP4)
66 if k == VSK_DIRECT { return "direct\x00" as *u8 } // nx_video_get
67 if k == VSK_DASH { return "dash-todo\x00" as *u8 } // not yet downloadable (HLS-only engine)
68 if k == VSK_SEGMENT { return "segment-only\x00" as *u8 } // bare segment, no manifest captured
69 return "none\x00" as *u8
70}
71func vs_puts(dst: *u8, off: i64, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { dst[off] = s[i]; off = off + 1; i = i + 1 } return off }
72func vs_putn(dst: *u8, off: i64, v: i64) -> i64 { var m: i64 = v; if m == 0 { dst[off] = 48 as u8; return off + 1 } let t: *u8 = sys_mmap(24); var k: i64 = 0; while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } var j: i64 = 0; while j < k { dst[off] = t[k - 1 - j]; off = off + 1; j = j + 1 } return off }
73func vs_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
74func vs_find(hay: *u8, hl: i64, needle: *u8, nl: i64) -> i64 {
75 if nl == 0 { return 0 }
76 if nl > hl { return 0 - 1 }
77 var i: i64 = 0; let last: i64 = hl - nl
78 while i <= last { var j: i64 = 0; var m: i64 = 1; while j < nl { if (hay[i + j] & 0xff) != (needle[j] & 0xff) { m = 0; j = nl } else { j = j + 1 } } if m == 1 { return i } i = i + 1 }
79 return 0 - 1
80}
81func vs_hexval(c: i64) -> i64 { if c >= 48 { if c <= 57 { return c - 48 } } if c >= 97 { if c <= 102 { return c - 87 } } if c >= 65 { if c <= 70 { return c - 55 } } return 0 }
82
83// ============ API layer: the sniff RESULT as JSON + request URL parsing (what a daemon route / MCP tool uses) ============
84// Format a sniff result (kind + its "ROUTE=<r> URL=<u>" plan) as a JSON API response:
85// {"found":true,"route":"hls","url":"https://.../master.m3u8"} (kind > 0)
86// {"found":false,"route":"none","url":null} (none/killed)
87func vs_result_json(kind: i64, plan: *u8, out: *u8, cap: i64) -> i64 {
88 let plen: i64 = vs_slen(plan)
89 let ui: i64 = vs_find(plan, plen, " URL=" as *u8, 5) // splits ROUTE=<r> | URL=<u>
90 var rend: i64 = plen; if ui >= 0 { rend = ui }
91 var o: i64 = 0
92 o = vs_puts(out, o, "{\"found\":" as *u8)
93 if kind > 0 { o = vs_puts(out, o, "true" as *u8) } else { o = vs_puts(out, o, "false" as *u8) }
94 o = vs_puts(out, o, ",\"route\":\"" as *u8)
95 var p: i64 = 6 // skip "ROUTE="
96 while p < rend { if o < (cap - 2) { out[o] = plan[p]; o = o + 1 } p = p + 1 }
97 o = vs_puts(out, o, "\",\"url\":" as *u8)
98 if kind > 0 {
99 if o < (cap - 1) { out[o] = 34 as u8; o = o + 1 } // opening quote
100 var q: i64 = ui + 5
101 while q < plen { let c: i64 = plan[q] & 0xff; if c == 34 { } else { if o < (cap - 2) { out[o] = c as u8; o = o + 1 } } q = q + 1 } // drop stray '"'
102 if o < (cap - 1) { out[o] = 34 as u8; o = o + 1 }
103 } else { o = vs_puts(out, o, "null" as *u8) }
104 o = vs_puts(out, o, "}" as *u8)
105 out[o] = 0 as u8
106 return o
107}
108// Extract the `url=` parameter from an HTTP query string, URL-decoded (%XX + '+'->space). Returns length.
109// The request-parsing half of the API: `GET /media/sniff?url=<percent-encoded page url>`.
110func vs_query_url(q: *u8, qlen: i64, out: *u8, cap: i64) -> i64 {
111 // find "url=" as a PARAMETER (at position 0 or right after '&'), not any substring (else "noturl=" matches).
112 var start: i64 = 0 - 1
113 var si: i64 = 0
114 while si < qlen {
115 var isp: i64 = 0
116 if si == 0 { isp = 1 } else { let pc: i64 = q[si - 1] & 0xff; if pc == 38 { isp = 1 } if pc == 63 { isp = 1 } } // '&' or '?' boundary
117 if isp == 1 { if (si + 4) <= qlen { if (q[si] & 0xff) == 117 { if (q[si + 1] & 0xff) == 114 { if (q[si + 2] & 0xff) == 108 { if (q[si + 3] & 0xff) == 61 { start = si; si = qlen } } } } } }
118 si = si + 1
119 }
120 if start < 0 { out[0] = 0 as u8; return 0 }
121 var i: i64 = start + 4
122 var o: i64 = 0
123 var go: i64 = 1
124 while go == 1 {
125 if i >= qlen { go = 0 }
126 else {
127 let c: i64 = q[i] & 0xff
128 if c == 38 { go = 0 } // '&' ends the value
129 else {
130 if c == 37 { // '%XX'
131 if (i + 2) < qlen { let hi: i64 = vs_hexval(q[i + 1] & 0xff); let lo: i64 = vs_hexval(q[i + 2] & 0xff); if o < (cap - 1) { out[o] = (hi * 16 + lo) as u8; o = o + 1 } i = i + 3 } else { i = i + 1 }
132 } else {
133 if c == 43 { if o < (cap - 1) { out[o] = 32 as u8; o = o + 1 } i = i + 1 } // '+' -> space
134 else { if o < (cap - 1) { out[o] = c as u8; o = o + 1 } i = i + 1 }
135 }
136 }
137 }
138 }
139 out[o] = 0 as u8
140 return o
141}
142
143// N-THROTTLE de-throttle, as a BROWSER-SNIFFER capability (per the JS = last-mile-only rule): given the player
144// `basejs` and a throttled `nval`, find the transform function's name NATIVELY (bjs_find_nfunc_name = text
145// analysis, no engine) then RUN that function -- the site's OWN code -- via ns_solve on the browser's JS engine
146// (the last mile). Writes n' to `out`, returns its length (or a negative ns_solve error / 0 if no name found).
147// This lives in the sniffer so the JS engine stays confined to the browser layer; the native extraction core
148// (nx_media_extract/signal/state/heal) never imports it. Callers: the sniffer/daemon turning a throttled
149// googlevideo URL into a full-speed one.
150func vs_solve_n(basejs: *u8, bl: i64, nval: *u8, nl: i64, out: *u8, cap: i64) -> i64 {
151 let name: *u8 = sys_mmap(256)
152 let namelen: i64 = bjs_find_nfunc_name(basejs, bl, name, 256)
153 if namelen == 0 { out[0] = 0 as u8; return 0 } // no name -> a self-heal LEARN signal
154 return ns_solve(basejs, bl, name, namelen, nval, nl, out, cap)
155}
156
157// SNIFF: run page JS, capture media URLs (into listbuf, \n-sep), pick the best download target, and write a
158// one-line PLAN into planbuf ("ROUTE=<route> URL=<besturl>"). Returns the primary kind (VSK_*). planbuf>=2560.
159func vs_sniff(js: *u8, jslen: i64, listbuf: *u8, listcap: i64, planbuf: *u8, plancap: i64) -> i64 {
160 let obx: *i64 = sys_mmap(16) as *i64
161 mjx_harvest_js(js, jslen, listbuf, listcap, obx) // listbuf = '\n'-separated deduped media URLs
162 let line: *u8 = sys_mmap(VSK_MAGIC_2048)
163 let best: *u8 = sys_mmap(VSK_MAGIC_2048)
164 best[0] = 0 as u8
165 var bestrank: i64 = 0
166 var bestkind: i64 = VSK_NONE
167 var p: i64 = 0
168 var go: i64 = 1
169 while go == 1 {
170 if listbuf[p] == (0 as u8) { go = 0 }
171 else {
172 // pull one line into `line`
173 var q: i64 = 0
174 var inl: i64 = 1
175 while inl == 1 {
176 let c: i64 = listbuf[p] & 0xff
177 if c == 0 { inl = 0 }
178 else {
179 if c == 10 { inl = 0; p = p + 1 }
180 else { if q < VSK_MAGIC_2047 { line[q] = c as u8; q = q + 1 } p = p + 1 }
181 }
182 }
183 line[q] = 0 as u8
184 if q > 0 {
185 let k: i64 = vs_url_kind(line, q)
186 let r: i64 = vs_kind_rank(k)
187 if r > bestrank { bestrank = r; bestkind = k; var j: i64 = 0; while j < q { best[j] = line[j]; j = j + 1 } best[q] = 0 as u8 }
188 }
189 }
190 }
191 var o: i64 = 0
192 o = vs_puts(planbuf, o, "ROUTE=" as *u8)
193 o = vs_puts(planbuf, o, vs_route_name(bestkind))
194 o = vs_puts(planbuf, o, " URL=" as *u8)
195 if bestkind != VSK_NONE { o = vs_puts(planbuf, o, best) } else { o = vs_puts(planbuf, o, "-" as *u8) }
196 planbuf[o] = 0 as u8
197 return bestkind
198}
199
200// vs_sniff + DOM: identical harvest+plan, but seeds `dochtml` as the DOM so DOM-reading player JS (a plugin that
201// reads a data-* stream token off document.getElementById(...)) resolves its element and builds the real URL.
202func vs_sniff_dom(js: *u8, jslen: i64, dochtml: *u8, doclen: i64, listbuf: *u8, listcap: i64, planbuf: *u8, plancap: i64) -> i64 {
203 let obx: *i64 = sys_mmap(16) as *i64
204 mjx_harvest_js_dom(js, jslen, dochtml, doclen, listbuf, listcap, obx)
205 let line: *u8 = sys_mmap(VSK_MAGIC_2048)
206 let best: *u8 = sys_mmap(VSK_MAGIC_2048)
207 best[0] = 0 as u8
208 var bestrank: i64 = 0
209 var bestkind: i64 = VSK_NONE
210 var p: i64 = 0
211 var go: i64 = 1
212 while go == 1 {
213 if listbuf[p] == (0 as u8) { go = 0 }
214 else {
215 var q: i64 = 0
216 var inl: i64 = 1
217 while inl == 1 {
218 let c: i64 = listbuf[p] & 0xff
219 if c == 0 { inl = 0 }
220 else {
221 if c == 10 { inl = 0; p = p + 1 }
222 else { if q < VSK_MAGIC_2047 { line[q] = c as u8; q = q + 1 } p = p + 1 }
223 }
224 }
225 line[q] = 0 as u8
226 if q > 0 {
227 let k: i64 = vs_url_kind(line, q)
228 let r: i64 = vs_kind_rank(k)
229 if r > bestrank { bestrank = r; bestkind = k; var j: i64 = 0; while j < q { best[j] = line[j]; j = j + 1 } best[q] = 0 as u8 }
230 }
231 }
232 }
233 var o: i64 = 0
234 o = vs_puts(planbuf, o, "ROUTE=" as *u8)
235 o = vs_puts(planbuf, o, vs_route_name(bestkind))
236 o = vs_puts(planbuf, o, " URL=" as *u8)
237 if bestkind != VSK_NONE { o = vs_puts(planbuf, o, best) } else { o = vs_puts(planbuf, o, "-" as *u8) }
238 planbuf[o] = 0 as u8
239 return bestkind
240}
241
242// GUARDED SNIFF -- run vs_sniff on UNTRUSTED page JS inside a FORKED CHILD that self-caps CPU-seconds
243// (RLIMIT_CPU) and virtual memory (RLIMIT_AS) BEFORE executing it. A hostile `while(true){}` (CPU spin) or
244// an alloc-bomb is KILLED by the KERNEL; the parent's blocking wait4 returns in ~cpu_secs and NEVER hangs or
245// OOMs. This is process-isolation safety -- it needs NO interpreter fuel budget (so it does NOT touch the
246// contended nx_js_eval hot loop) and makes running arbitrary LIVE bundles safe by construction. The child
247// hands the plan back through SHARED memory; a signaled (killed) child -> VSK_KILLED + a guard plan.
248// planbuf >= 2560. cpu_secs = the CPU budget (e.g. 5). Returns the primary kind, or VSK_KILLED.
249func vs_sniff_guarded(js: *u8, jslen: i64, planbuf: *u8, plancap: i64, cpu_secs: i64) -> i64 {
250 let shplan: *u8 = sys_mmap_shared(VSK_MAGIC_2560) // child writes the plan here, parent reads it
251 let shkind: *i64 = sys_mmap_shared(16) as *i64
252 shkind[0] = VSK_KILLED // default (child overwrites on clean completion)
253 shplan[0] = 0 as u8
254 let pid: i64 = sys_fork()
255 if pid < 0 { // fork failed -> FAIL SAFE (never run untrusted JS unguarded)
256 var e: i64 = vs_puts(planbuf, 0, "ROUTE=guard-unavailable URL=- (fork failed)" as *u8)
257 planbuf[e] = 0 as u8
258 return VSK_KILLED
259 }
260 if pid == 0 {
261 // CHILD: cap CPU + address space, THEN run the untrusted page JS.
262 let rl: *i64 = sys_mmap(16) as *i64
263 rl[0] = cpu_secs; rl[1] = cpu_secs + 1 // rlimit64{soft,hard}; SIGXCPU at soft, SIGKILL at hard
264 nx_prlimit(0, RLIMIT_CPU, rl as *u8, 0 as *u8)
265 let ra: *i64 = sys_mmap(16) as *i64
266 ra[0] = VSK_MAGIC_8589934592; ra[1] = VSK_MAGIC_8589934592 // 8 GiB virtual-memory cap (alloc-bomb backstop; generous
267 nx_prlimit(0, RLIMIT_AS, ra as *u8, 0 as *u8) // so the parent's TLS-stack footprint can't false-trip it)
268 let lb: *u8 = sys_mmap(VSK_MAGIC_8192)
269 let k: i64 = vs_sniff(js, jslen, lb, VSK_MAGIC_8192, shplan, VSK_MAGIC_2560)
270 shkind[0] = k
271 sys_exit(0)
272 }
273 // PARENT: block until the child exits or the kernel kills it (bounded by cpu_secs) -- never an infinite wait.
274 let st: *i64 = sys_mmap(16) as *i64
275 sys_wait4(pid, st, 0)
276 // copy the shared plan into the caller's buffer
277 var i: i64 = 0; var go: i64 = 1
278 while go == 1 {
279 if i >= (plancap - 1) { go = 0 }
280 else { let c: i64 = shplan[i] & 0xff; planbuf[i] = c as u8; if c == 0 { go = 0 } else { i = i + 1 } }
281 }
282 planbuf[i] = 0 as u8
283 // WIFSIGNALED: low 7 status bits != 0 => killed by a signal (SIGXCPU/SIGKILL/SIGSEGV) => the guard tripped.
284 if (st[0] & 0x7f) != 0 {
285 var o: i64 = vs_puts(planbuf, 0, "ROUTE=guard-killed URL=- (page JS killed by signal " as *u8)
286 o = vs_putn(planbuf, o, st[0] & 0x7f) // 24=SIGXCPU(cpu cap), 9=SIGKILL, 11=SIGSEGV
287 o = vs_puts(planbuf, o, ")" as *u8)
288 planbuf[o] = 0 as u8
289 return VSK_KILLED
290 }
291 return shkind[0]
292}
293
294// vs_sniff_guarded + DOM: same forked-child CPU/mem-capped guard, but seeds `dochtml` as the DOM for the run so
295// DOM-reading player JS resolves (fork copies dochtml into the child; safe by construction, identical guard).
296func vs_sniff_guarded_dom(js: *u8, jslen: i64, dochtml: *u8, doclen: i64, planbuf: *u8, plancap: i64, cpu_secs: i64) -> i64 {
297 let shplan: *u8 = sys_mmap_shared(VSK_MAGIC_2560)
298 let shkind: *i64 = sys_mmap_shared(16) as *i64
299 shkind[0] = VSK_KILLED
300 shplan[0] = 0 as u8
301 let pid: i64 = sys_fork()
302 if pid < 0 {
303 var e: i64 = vs_puts(planbuf, 0, "ROUTE=guard-unavailable URL=- (fork failed)" as *u8)
304 planbuf[e] = 0 as u8
305 return VSK_KILLED
306 }
307 if pid == 0 {
308 let rl: *i64 = sys_mmap(16) as *i64
309 rl[0] = cpu_secs; rl[1] = cpu_secs + 1
310 nx_prlimit(0, RLIMIT_CPU, rl as *u8, 0 as *u8)
311 let ra: *i64 = sys_mmap(16) as *i64
312 ra[0] = VSK_MAGIC_8589934592; ra[1] = VSK_MAGIC_8589934592
313 nx_prlimit(0, RLIMIT_AS, ra as *u8, 0 as *u8)
314 let lb: *u8 = sys_mmap(VSK_MAGIC_8192)
315 let k: i64 = vs_sniff_dom(js, jslen, dochtml, doclen, lb, VSK_MAGIC_8192, shplan, VSK_MAGIC_2560)
316 shkind[0] = k
317 sys_exit(0)
318 }
319 let st: *i64 = sys_mmap(16) as *i64
320 sys_wait4(pid, st, 0)
321 var i: i64 = 0; var go: i64 = 1
322 while go == 1 {
323 if i >= (plancap - 1) { go = 0 }
324 else { let c: i64 = shplan[i] & 0xff; planbuf[i] = c as u8; if c == 0 { go = 0 } else { i = i + 1 } }
325 }
326 planbuf[i] = 0 as u8
327 if (st[0] & 0x7f) != 0 {
328 var o: i64 = vs_puts(planbuf, 0, "ROUTE=guard-killed URL=- (page JS killed by signal " as *u8)
329 o = vs_putn(planbuf, o, st[0] & 0x7f)
330 o = vs_puts(planbuf, o, ")" as *u8)
331 planbuf[o] = 0 as u8
332 return VSK_KILLED
333 }
334 return shkind[0]
335}
336
337// lowercase one byte (for case-insensitive HTML tag matching -- <SCRIPT>, <Script>, <script> all match).
338func vs_lc(c: i64) -> i64 { if c >= 65 { if c <= 90 { return c + 32 } } return c }
339func vs_ci_at(buf: *u8, pos: i64, hlen: i64, lit: *u8, litlen: i64) -> i64 {
340 if (pos + litlen) > hlen { return 0 }
341 var j: i64 = 0
342 while j < litlen { if vs_lc(buf[pos + j] & 0xff) != (lit[j] & 0xff) { return 0 } j = j + 1 }
343 return 1
344}
345// extract every INLINE <script>...</script> body from HTML into `out`, ';'+newline separated so the scripts
346// run as one program (top-level vars shared across scripts, as in a real page). External <script src=...>
347// bodies are empty here -> contribute nothing (the live wire fetches those bundles separately + appends).
348// Returns bytes written. Case-insensitive tag match; tolerant of a missing close tag (body runs to EOF).
349func vs_extract_scripts(html: *u8, hlen: i64, out: *u8, cap: i64) -> i64 {
350 var o: i64 = 0
351 var i: i64 = 0
352 while i < hlen {
353 if vs_ci_at(html, i, hlen, "<script" as *u8, 7) == 1 {
354 var j: i64 = i + 7 // scan to end of the open tag '>'
355 var gt: i64 = 0
356 while gt == 0 {
357 if j >= hlen { gt = 1 } else { if (html[j] & 0xff) == 62 { gt = 1 } else { j = j + 1 } }
358 }
359 let b: i64 = j + 1 // body starts after '>'
360 var k: i64 = b // scan to "</script"
361 var cl: i64 = 0
362 while cl == 0 {
363 if k >= hlen { cl = 1 } else { if vs_ci_at(html, k, hlen, "</script" as *u8, 8) == 1 { cl = 1 } else { k = k + 1 } }
364 }
365 var p: i64 = b
366 while p < k { if o < (cap - 3) { out[o] = html[p]; o = o + 1 } p = p + 1 }
367 if o < (cap - 3) { out[o] = 59 as u8; o = o + 1; out[o] = 10 as u8; o = o + 1 } // ";\n"
368 i = k
369 } else { i = i + 1 }
370 }
371 out[o] = 0 as u8
372 return o
373}
374// scan the <script...> open tag starting at `ts` (the '<') for a src="..."/src='...' attribute; copy the
375// URL into `out`, set endbox[0] = index just past '>', and return the URL length (or -1 if no src). Handles
376// double/single quotes, src anywhere in the tag (after type=, etc.), case-insensitive.
377func vs_script_src(html: *u8, ts: i64, hlen: i64, out: *u8, urlcap: i64, endbox: *i64) -> i64 {
378 var j: i64 = ts + 7
379 var urllen: i64 = 0 - 1
380 var scanning: i64 = 1
381 while scanning == 1 {
382 if j >= hlen { scanning = 0; endbox[0] = hlen }
383 else {
384 let c: i64 = html[j] & 0xff
385 if c == 62 { scanning = 0; endbox[0] = j + 1 } // '>' ends the open tag
386 else {
387 var q: i64 = 0 - 1
388 if vs_ci_at(html, j, hlen, "src=\"" as *u8, 5) == 1 { q = 34 }
389 else { if vs_ci_at(html, j, hlen, "src='" as *u8, 5) == 1 { q = 39 } }
390 if q >= 0 {
391 let s: i64 = j + 5
392 var e: i64 = s
393 var fe: i64 = 0
394 while fe == 0 { if e >= hlen { fe = 1 } else { if (html[e] & 0xff) == q { fe = 1 } else { e = e + 1 } } }
395 var w: i64 = 0
396 var p: i64 = s
397 while p < e {
398 if vs_ci_at(html, p, e, "&" as *u8, 5) == 1 { if w < (urlcap - 1) { out[w] = 38 as u8; w = w + 1 } p = p + 5 } // & -> &
399 else { if w < (urlcap - 1) { out[w] = html[p]; w = w + 1 } p = p + 1 }
400 }
401 out[w] = 0 as u8
402 urllen = w
403 j = e // keep scanning to '>' (don't miss it)
404 } else { j = j + 1 }
405 }
406 }
407 }
408 return urllen
409}
410// extract every EXTERNAL <script src=...> URL into `out` (newline-separated); returns the count. The live
411// wire fetches each (resolving relative->absolute) + appends before the guarded sniff -- a hardened SPA's
412// real code lives in an external bundle, so this is what tells the wire what to pull.
413func vs_extract_script_srcs(html: *u8, hlen: i64, out: *u8, cap: i64) -> i64 {
414 let urlbuf: *u8 = sys_mmap(VSK_MAGIC_4096)
415 let endbox: *i64 = sys_mmap(8) as *i64
416 var o: i64 = 0
417 var count: i64 = 0
418 var i: i64 = 0
419 while i < hlen {
420 if vs_ci_at(html, i, hlen, "<script" as *u8, 7) == 1 {
421 endbox[0] = i + 7
422 let ul: i64 = vs_script_src(html, i, hlen, urlbuf, VSK_MAGIC_4096, endbox)
423 if ul > 0 {
424 var p: i64 = 0
425 while p < ul { if o < (cap - 2) { out[o] = urlbuf[p]; o = o + 1 } p = p + 1 }
426 if o < (cap - 2) { out[o] = 10 as u8; o = o + 1 }
427 count = count + 1
428 }
429 i = endbox[0]
430 } else { i = i + 1 }
431 }
432 out[o] = 0 as u8
433 return count
434}
435// PAGE SNIFF: extract a page's inline scripts and run them through the GUARDED sniff -> download plan.
436// This is "paste a video-page URL, get the stream": the live wire fetches the HTML over sovereign TLS
437// (nx_video_fetch) and any external <script src> bundles, then calls this. Untrusted-JS-safe by the guard.
438func vs_sniff_page(html: *u8, hlen: i64, planbuf: *u8, plancap: i64, cpu_secs: i64) -> i64 {
439 let js: *u8 = sys_mmap(VSK_MAGIC_262144) // 256KB for concatenated inline scripts
440 let n: i64 = vs_extract_scripts(html, hlen, js, VSK_MAGIC_262144)
441 return vs_sniff_guarded_dom(js, n, html, hlen, planbuf, plancap, cpu_secs) // seed the page HTML as the DOM
442}
443// PAGE SNIFF WITH EXTERNAL BUNDLE(S): inline scripts FIRST, then the already-fetched external bundle bytes
444// appended (';'+newline separated), then guarded-sniff. This is exactly the live wire's assembly (the only
445// live part it adds is the TLS GET of each <script src>); gateable by passing a synthetic fetched bundle.
446// `extjs`/`extlen` = the concatenation of every external bundle the wire fetched (in <script src> order).
447func vs_sniff_page_bundled(html: *u8, hlen: i64, extjs: *u8, extlen: i64, planbuf: *u8, plancap: i64, cpu_secs: i64) -> i64 {
448 let cap: i64 = VSK_MAGIC_1048576 // 1MB combined (inline + external bundles)
449 let js: *u8 = sys_mmap(cap)
450 var o: i64 = vs_extract_scripts(html, hlen, js, cap) // inline first (shares top-level scope w/ bundles)
451 var p: i64 = 0
452 while p < extlen { if o < (cap - 3) { js[o] = extjs[p]; o = o + 1 } p = p + 1 }
453 if o < (cap - 3) { js[o] = 59 as u8; o = o + 1; js[o] = 10 as u8; o = o + 1 } // ";\n"
454 js[o] = 0 as u8
455 return vs_sniff_guarded_dom(js, o, html, hlen, planbuf, plancap, cpu_secs) // seed the page HTML as the DOM
456}
457// PREAMBLE variant: a surrogate scriptlet PREAMBLE (from nx_surrogate) runs FIRST, before the page's own inline
458// scripts + external bundles -- so the page's anti-adblock / tracker gates read back as success and the gated
459// media fetch fires. Same guarded (fork+rlimit) execution; the preamble shares top-level scope with the page.
460func vs_sniff_page_bundled_pre(preamble: *u8, plen: i64, html: *u8, hlen: i64, extjs: *u8, extlen: i64, planbuf: *u8, plancap: i64, cpu_secs: i64) -> i64 {
461 let cap: i64 = VSK_MAGIC_1048576
462 let js: *u8 = sys_mmap(cap)
463 var o: i64 = 0
464 var i: i64 = 0
465 while i < plen { if o < (cap - 3) { js[o] = preamble[i]; o = o + 1 } i = i + 1 } // preamble FIRST
466 if o < (cap - 3) { js[o] = 59 as u8; o = o + 1; js[o] = 10 as u8; o = o + 1 } // ";\n"
467 o = o + vs_extract_scripts(html, hlen, ((js as i64) + o) as *u8, cap - o) // then inline scripts
468 var p: i64 = 0
469 while p < extlen { if o < (cap - 3) { js[o] = extjs[p]; o = o + 1 } p = p + 1 } // then external bundles
470 if o < (cap - 3) { js[o] = 59 as u8; o = o + 1; js[o] = 10 as u8; o = o + 1 }
471 js[o] = 0 as u8
472 return vs_sniff_guarded_dom(js, o, html, hlen, planbuf, plancap, cpu_secs) // seed the page HTML as the DOM
473}