code wiki / (root) / nx_video_sniff.nx

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, "&amp;" as *u8, 5) == 1 { if w < (urlcap - 1) { out[w] = 38 as u8; w = w + 1 } p = p + 5 } // &amp; -> & 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}