Download sentinel_solver/vm.js from zlcy/study: direct link, hf CLI and curl.
- Browser
- Download file 5.57 kB
-
https://huggingface.co/spaces/zlcy/study/resolve/main/sentinel_solver/vm.js
- Command line
-
hf download hf://spaces/zlcy/study/sentinel_solver/vm.js
-
curl -L -o vm.js https://huggingface.co/spaces/zlcy/study/resolve/main/sentinel_solver/vm.js
5.57 kB
| // chatgpt.com sentinel 挑战程序的执行器(Turnstile 与 SO)。 | |
| // | |
| // 移植自 chatgpt.com 前端 bundle 里的两套同构 VM(2026-10 版本,指令编号 0-35)。 | |
| // 挑战程序会读取真实页面里的 window/document/navigator 等属性,结果只在真正的 | |
| // chatgpt.com 页面上下文里才会被服务端接受,所以这段脚本通过 add_init_script | |
| // 注入到常驻页面,由求解服务按需调用 window.__sentinelVM。 | |
| (() => { | |
| const xor = (text, key) => { | |
| let out = ""; | |
| for (let i = 0; i < text.length; i++) out += String.fromCharCode(text.charCodeAt(i) ^ key.charCodeAt(i % key.length)); | |
| return out; | |
| }; | |
| function makeVM() { | |
| const Q = new Map(); | |
| let steps = 0; | |
| async function run() { | |
| while (Q.get(9).length > 0) { | |
| const [op, ...args] = Q.get(9).shift(); | |
| const result = Q.get(op)(...args); | |
| if (result && typeof result.then === "function") await result; | |
| steps++; | |
| } | |
| } | |
| function reset() { | |
| Q.clear(); | |
| Q.set(0, (dx) => exec(dx, undefined, 60000)); | |
| Q.set(1, (e, t) => Q.set(e, xor("" + Q.get(e), "" + Q.get(t)))); | |
| Q.set(2, (e, t) => Q.set(e, t)); | |
| Q.set(5, (e, t) => { const n = Q.get(e); Array.isArray(n) ? n.push(Q.get(t)) : Q.set(e, n + Q.get(t)); }); | |
| Q.set(6, (e, t, n) => Q.set(e, Q.get(t)[Q.get(n)])); | |
| Q.set(7, (e, ...t) => Q.get(e)(...t.map((x) => Q.get(x)))); | |
| Q.set(8, (e, t) => Q.set(e, Q.get(t))); | |
| Q.set(10, window); | |
| Q.set(11, (e, t) => Q.set(e, (Array.from(document.scripts || []).map((s) => s?.src?.match(Q.get(t))).filter((m) => m?.length)[0] ?? [])[0] ?? null)); | |
| Q.set(12, (e) => Q.set(e, Q)); | |
| Q.set(13, (e, t, ...n) => { try { Q.get(t)(...n); } catch (err) { Q.set(e, "" + err); } }); | |
| Q.set(14, (e, t) => Q.set(e, JSON.parse("" + Q.get(t)))); | |
| Q.set(15, (e, t) => Q.set(e, JSON.stringify(Q.get(t)))); | |
| Q.set(17, (e, t, ...n) => { | |
| try { | |
| const r = Q.get(t)(...n.map((x) => Q.get(x))); | |
| if (r && typeof r.then === "function") return r.then((v) => { Q.set(e, v); }).catch((v) => { Q.set(e, "" + v); }); | |
| Q.set(e, r); | |
| } catch (err) { | |
| Q.set(e, "" + err); | |
| } | |
| }); | |
| Q.set(18, (e) => Q.set(e, atob("" + Q.get(e)))); | |
| Q.set(19, (e) => Q.set(e, btoa("" + Q.get(e)))); | |
| Q.set(20, (e, t, n, ...r) => (Q.get(e) === Q.get(t) ? Q.get(n)(...r) : null)); | |
| Q.set(21, (e, t, n, r, ...i) => (Math.abs(Q.get(e) - Q.get(t)) > Q.get(n) ? Q.get(r)(...i) : null)); | |
| Q.set(22, (e, t) => { | |
| const saved = [...Q.get(9)]; | |
| Q.set(9, [...t]); | |
| return run().catch((v) => { Q.set(e, "" + v); }).finally(() => { Q.set(9, saved); }); | |
| }); | |
| Q.set(23, (e, t, ...n) => (Q.get(e) === void 0 ? null : Q.get(t)(...n))); | |
| Q.set(24, (e, t, n) => Q.set(e, Q.get(t)[Q.get(n)].bind(Q.get(t)))); | |
| Q.set(25, () => {}); | |
| Q.set(26, () => {}); | |
| Q.set(27, (e, t) => { const n = Q.get(e); Array.isArray(n) ? n.splice(n.indexOf(Q.get(t)), 1) : Q.set(e, n - Q.get(t)); }); | |
| Q.set(28, () => {}); | |
| Q.set(29, (e, t, n) => Q.set(e, Q.get(t) < Q.get(n))); | |
| Q.set(33, (e, t, n) => Q.set(e, Number(Q.get(t)) * Number(Q.get(n)))); | |
| Q.set(34, (e, t) => { try { return Promise.resolve(Q.get(t)).then((v) => { Q.set(e, v); }); } catch { return; } }); | |
| Q.set(35, (e, t, n) => { const r = Number(Q.get(t)), i = Number(Q.get(n)); Q.set(e, i === 0 ? 0 : r / i); }); | |
| } | |
| // key 为 undefined 时沿用上一次的状态(SO 的 snapshot 依赖 collector 留下的寄存器)。 | |
| // softTimeout 对应前端 Turnstile 的行为:超时不报错,而是返回已执行步数。 | |
| function exec(dx, key, timeoutMs, softTimeout) { | |
| return new Promise((resolve, reject) => { | |
| if (key !== undefined) { | |
| reset(); | |
| steps = 0; | |
| Q.set(16, key); | |
| } | |
| let done = false; | |
| const timer = setTimeout(() => { | |
| if (done) return; | |
| done = true; | |
| softTimeout ? resolve("" + steps) : reject(new Error("vm_timeout")); | |
| }, timeoutMs); | |
| const ok = (v) => { if (!done) { done = true; clearTimeout(timer); resolve(v); } }; | |
| const fail = (v) => { if (!done) { done = true; clearTimeout(timer); reject(v); } }; | |
| Q.set(3, (v) => ok(btoa("" + v))); | |
| Q.set(4, (v) => fail(btoa("" + v))); | |
| Q.set(30, (e, t, n, r) => { | |
| const hasParams = Array.isArray(r); | |
| const params = hasParams ? n : []; | |
| const body = (hasParams ? r : n) || []; | |
| Q.set(e, (...args) => { | |
| if (done) return; | |
| const saved = [...Q.get(9)]; | |
| if (hasParams) for (let i = 0; i < params.length; i++) Q.set(params[i], args[i]); | |
| Q.set(9, [...body]); | |
| return run().then(() => Q.get(t)).catch((v) => "" + v).finally(() => { Q.set(9, saved); }); | |
| }); | |
| }); | |
| try { | |
| Q.set(9, JSON.parse(xor(atob(dx), "" + Q.get(16)))); | |
| run().catch((v) => ok(btoa(steps + ": " + v))); | |
| } catch (err) { | |
| ok(btoa(steps + ": " + err)); | |
| } | |
| }); | |
| } | |
| return { exec }; | |
| } | |
| window.__sentinelVM = { | |
| // key 是 chat-requirements/prepare 请求里提交的 p(requirements token)。 | |
| turnstile: (dx, key) => makeVM().exec(dx, key, 500, true), | |
| so: async (collectorDx, snapshotDx, key) => { | |
| const vm = makeVM(); | |
| await vm.exec(collectorDx, key, 60000); | |
| return vm.exec(snapshotDx, undefined, 60000); | |
| }, | |
| }; | |
| })(); | |