code wiki / _hdl_build / nx_media_jsexec_gate.nx
nx_media_jsexec_gate.nx source
↩ module page · 105 lines · 6976 B
1import "nx_gate_gn.nx"
2import "nx_gate_base.nx"
3// nx_media_jsexec_gate.nx -- proves the JS-EXECUTION media harvester surfaces media URLs that page JS
4// CONSTRUCTS AT RUNTIME (function return, template literal, class method, regex extraction) and hands to
5// fetch() -- exactly the URLs a STATIC byte/urlfold scan cannot compute. Also proves the media-extension
6// FILTER (api/config fetches ignored) and de-dup. Fetches PEND (no network) -> safe. license_tier: ORIGINAL expect_exit: 0
7import "nx_syscalls.nx"
8import "nx_js_eval.nx"
9import "nx_media_jsexec.nx"
10import "nx_gate_verdict.nx"
11
12func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw("
13" as *u8); return ok }
14func gsl(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
15
16func has_url(outbuf: *u8, want: *u8) -> i64 { return mjx_contains(outbuf, gsl(outbuf), want, gsl(want)) }
17
18// run page JS `src`, expect EXACTLY `wantcnt` media URLs collected AND `wanturl` among them.
19func run_expect(src: *u8, wanturl: *u8, wantcnt: i64) -> i64 {
20 let outbuf: *u8 = sys_mmap(4096)
21 let outbox: *i64 = sys_mmap(16) as *i64
22 let cnt: i64 = mjx_harvest_js(src, gsl(src), outbuf, 4096, outbox)
23 if cnt != wantcnt { gw(" (got cnt=" as *u8); gn(cnt); gw(" urls=[" as *u8); gw(outbuf); gw("])\n" as *u8); return 0 }
24 if has_url(outbuf, wanturl) == 0 { gw(" (missing '" as *u8); gw(wanturl); gw("' in [" as *u8); gw(outbuf); gw("])\n" as *u8); return 0 }
25 return 1
26}
27
28func main() -> i64 {
29 gw("media-jsexec SOVEREIGN gate (run page JS -> capture RUNTIME-BUILT fetch URLs a static scan misses)\n" as *u8)
30 var pass: i64 = 0
31 var ttl: i64 = 0
32
33 // M1: FUNCTION-built URL -- static folding cannot evaluate cdn(vid).
34 ttl=ttl+1; pass=pass+grow("M1 function-built https://media.example.com/ABC123/master.m3u8\x00" as *u8,
35 run_expect("function cdn(id){return 'https://media.example.com/'+id+'/master.m3u8';} var vid='ABC123'; fetch(cdn(vid));" as *u8,
36 "https://media.example.com/ABC123/master.m3u8\x00" as *u8, 1))
37 // M2: TEMPLATE-LITERAL URL with two interpolations.
38 ttl=ttl+1; pass=pass+grow("M2 template `https://cdn.host/${vid}/hls/${q}/index.m3u8`\x00" as *u8,
39 run_expect("var vid='XY9'; var q='720'; fetch(`https://cdn.host/${vid}/hls/${q}/index.m3u8`);" as *u8,
40 "https://cdn.host/XY9/hls/720/index.m3u8\x00" as *u8, 1))
41 // M3: CLASS-METHOD-built URL (this.id in a method).
42 ttl=ttl+1; pass=pass+grow("M3 class method https://v.cdn/42.mp4\x00" as *u8,
43 run_expect("class Player{constructor(id){this.id=id;} url(){return 'https://v.cdn/'+this.id+'.mp4';}} var p=new Player('42'); fetch(p.url());" as *u8,
44 "https://v.cdn/42.mp4\x00" as *u8, 1))
45 // M4: REGEX-EXTRACTED id then fetch -- the real pattern (pull an id out of page text, build the URL).
46 ttl=ttl+1; pass=pass+grow("M4 regex-extracted id -> https://cdn/98765/stream.m3u8\x00" as *u8,
47 run_expect("var page='...video_id=98765&more...'; var m=page.match(/video_id=(\\d+)/); fetch('https://cdn/'+m[1]+'/stream.m3u8');" as *u8,
48 "https://cdn/98765/stream.m3u8\x00" as *u8, 1))
49 // M5: MEDIA FILTER -- a config/api fetch is IGNORED, only the .mp4 is collected.
50 ttl=ttl+1
51 let ob5: *i64 = sys_mmap(16) as *i64
52 let buf5: *u8 = sys_mmap(4096)
53 let src5: *u8 = "fetch('https://api.host/config.json'); fetch('https://v.cdn/movie.mp4');" as *u8
54 let c5: i64 = mjx_harvest_js(src5, gsl(src5), buf5, 4096, ob5)
55 var m5ok: i64 = 1
56 if c5 != 1 { m5ok = 0 }
57 if has_url(buf5, "https://v.cdn/movie.mp4\x00" as *u8) == 0 { m5ok = 0 }
58 if has_url(buf5, "config.json\x00" as *u8) == 1 { m5ok = 0 } // the non-media fetch must be filtered out
59 pass=pass+grow("M5 filter: .mp4 kept, config.json dropped (cnt=1)\x00" as *u8, m5ok)
60 // M6: DE-DUP -- same manifest fetched twice + one segment = 2 unique.
61 ttl=ttl+1; pass=pass+grow("M6 dedup: 2x same .m3u8 + 1 .mp4 -> 2 unique\x00" as *u8,
62 run_expect("fetch('https://c/a.m3u8'); fetch('https://c/a.m3u8'); fetch('https://c/b.mp4');" as *u8,
63 "https://c/b.mp4\x00" as *u8, 2))
64 // M7: NO media (only an api call) -> 0 collected (harvester is quiet, not noisy).
65 ttl=ttl+1
66 let ob7: *i64 = sys_mmap(16) as *i64
67 let buf7: *u8 = sys_mmap(4096)
68 let src7: *u8 = "fetch('https://api.host/ping'); var x=1+1;" as *u8
69 let c7: i64 = mjx_harvest_js(src7, gsl(src7), buf7, 4096, ob7)
70 pass=pass+grow("M7 no-media page -> 0 collected\x00" as *u8, (c7 == 0) as i64)
71 // --- the ACTUAL patterns real video sites use (arrow fns, forEach ladders) ---
72 // M8: ARROW-function-built URL (arrows dominate modern bundles).
73 ttl=ttl+1; pass=pass+grow("M8 arrow-built https://cdn/99/v.mp4\x00" as *u8,
74 run_expect("var mk = id => 'https://cdn/'+id+'/v.mp4'; fetch(mk('99'));" as *u8,
75 "https://cdn/99/v.mp4\x00" as *u8, 1))
76 // M9: forEach over an id list -> multiple media (the "fetch each segment" shape).
77 ttl=ttl+1; pass=pass+grow("M9 forEach id-list -> 2 media (a.mp4,b.mp4)\x00" as *u8,
78 run_expect("var ids=['a','b']; ids.forEach(function(x){ fetch('https://cdn/'+x+'.mp4'); });" as *u8,
79 "https://cdn/b.mp4\x00" as *u8, 2))
80 // M10: QUALITY LADDER -- arrow + forEach + template (exactly how HLS/DASH variant lists get built).
81 ttl=ttl+1; pass=pass+grow("M10 quality ladder 720/1080 .m3u8 -> 2\x00" as *u8,
82 run_expect("['720','1080'].forEach(q => fetch(`https://cdn/vid/${q}.m3u8`));" as *u8,
83 "https://cdn/vid/1080.m3u8\x00" as *u8, 2))
84 // M11: DIRECT proof the js_pending_total two-step-cast FIX holds -- 3 fetches must return EXACTLY 3
85 // (the inline-cast bug returned a pointer-magnitude garbage value ~1.4e14; this asserts it's gone).
86 ttl=ttl+1
87 let obT: *i64 = sys_mmap(16) as *i64
88 let srcT: *u8 = "fetch('https://a/1.mp4'); fetch('https://b/2.mp4'); fetch('https://c/3.mp4');" as *u8
89 js_run_source_keep(srcT, gsl(srcT), obT)
90 let genvT: *i64 = (obT[1]) as *i64
91 var totT: i64 = 0 - 1
92 if (genvT as i64) != 0 { totT = js_pending_total(genvT) }
93 pass=pass+grow("M11 js_pending_total==3 (inline-cast fix verified, not garbage)\x00" as *u8, (totT == 3) as i64)
94
95 gw("pass=" as *u8); gn(pass); gw("/" as *u8); gn(ttl); gw("\n" as *u8)
96 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
97 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
98 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
99 let ctr__dry: *i64 = gv_ctr()
100 ctr__dry[0] = pass
101 ctr__dry[1] = ttl
102 let rc__dry: i64 = gv_verdict("MEDIA-JSEXEC-GATE" as *u8, ctr__dry, "JS execution surfaces runtime-built media URLs a static scan misses)" as *u8)
103 sys_exit(rc__dry)
104 return rc__dry
105}