specific-ai-cli 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.en.md +177 -0
- package/README.ja.md +177 -0
- package/README.ko.md +177 -0
- package/README.md +174 -2
- package/README.zh-TW.md +177 -0
- package/assets/banner.txt +3 -0
- package/dist/cli/argv.js +98 -0
- package/dist/cli/commands/auth.js +11 -0
- package/dist/cli/commands/config.js +23 -0
- package/dist/cli/commands/doctor.js +134 -0
- package/dist/cli/commands/platforms.js +24 -0
- package/dist/cli/commands/version.js +4 -0
- package/dist/cli/confirm.js +22 -0
- package/dist/cli/dispatch.js +440 -0
- package/dist/cli/help.js +223 -0
- package/dist/cli/hints.js +60 -0
- package/dist/cli/main.js +18 -0
- package/dist/cli/output.js +66 -0
- package/dist/core/auth-handlers.js +41 -0
- package/dist/core/auth-store.js +119 -0
- package/dist/core/capabilities.js +163 -0
- package/dist/core/config.js +121 -0
- package/dist/core/cookies.js +164 -0
- package/dist/core/errors.js +37 -0
- package/dist/core/files.js +89 -0
- package/dist/core/fsutil.js +52 -0
- package/dist/core/hash.js +4 -0
- package/dist/core/http.js +331 -0
- package/dist/core/image.js +280 -0
- package/dist/core/log.js +40 -0
- package/dist/core/login.js +191 -0
- package/dist/core/mp4.js +130 -0
- package/dist/core/normalize.js +207 -0
- package/dist/core/options.js +110 -0
- package/dist/core/paths.js +38 -0
- package/dist/core/pb.js +59 -0
- package/dist/core/py.js +181 -0
- package/dist/core/rand.js +131 -0
- package/dist/core/registry.js +129 -0
- package/dist/core/schemas.js +41 -0
- package/dist/core/stream.js +104 -0
- package/dist/core/toolkit.js +35 -0
- package/dist/core/vm.js +73 -0
- package/dist/core/vocab.js +157 -0
- package/dist/platforms/_shared/impaas.js +410 -0
- package/dist/platforms/bilibili/index.js +216 -0
- package/dist/platforms/bilibili/web/api.js +806 -0
- package/dist/platforms/bilibili/web/client.js +311 -0
- package/dist/platforms/bilibili/web/commands.js +783 -0
- package/dist/platforms/bilibili/web/ddddocr.js +342 -0
- package/dist/platforms/bilibili/web/gaia.js +130 -0
- package/dist/platforms/bilibili/web/geetest-manual.js +154 -0
- package/dist/platforms/bilibili/web/geetest-vision.js +232 -0
- package/dist/platforms/bilibili/web/geetest.js +450 -0
- package/dist/platforms/bilibili/web/normalize.js +234 -0
- package/dist/platforms/bilibili/web/profile.js +135 -0
- package/dist/platforms/bilibili/web/resolve.js +112 -0
- package/dist/platforms/bilibili/web/sign.js +223 -0
- package/dist/platforms/bilibili/web/upos.js +102 -0
- package/dist/platforms/douyin/index.js +142 -0
- package/dist/platforms/douyin/web/api.js +863 -0
- package/dist/platforms/douyin/web/client.js +413 -0
- package/dist/platforms/douyin/web/commands.js +712 -0
- package/dist/platforms/douyin/web/creator.js +601 -0
- package/dist/platforms/douyin/web/crypto.js +247 -0
- package/dist/platforms/douyin/web/dtrait.js +190 -0
- package/dist/platforms/douyin/web/im.js +502 -0
- package/dist/platforms/douyin/web/image.js +5 -0
- package/dist/platforms/douyin/web/live.js +225 -0
- package/dist/platforms/douyin/web/mssdk.js +148 -0
- package/dist/platforms/douyin/web/normalize.js +326 -0
- package/dist/platforms/douyin/web/passport.js +1247 -0
- package/dist/platforms/douyin/web/profile.js +221 -0
- package/dist/platforms/douyin/web/proto.js +26 -0
- package/dist/platforms/douyin/web/resolve.js +88 -0
- package/dist/platforms/douyin/web/sign.js +436 -0
- package/dist/platforms/douyin/web/tos.js +78 -0
- package/dist/platforms/index.js +17 -0
- package/dist/platforms/jd/index.js +67 -0
- package/dist/platforms/jd/web/aks.js +115 -0
- package/dist/platforms/jd/web/api.js +549 -0
- package/dist/platforms/jd/web/chat.js +132 -0
- package/dist/platforms/jd/web/client.js +470 -0
- package/dist/platforms/jd/web/commands.js +557 -0
- package/dist/platforms/jd/web/jcap/helper.js +90 -0
- package/dist/platforms/jd/web/jcap/host.js +107 -0
- package/dist/platforms/jd/web/jcap/lsd.js +300 -0
- package/dist/platforms/jd/web/jcap/solver.js +995 -0
- package/dist/platforms/jd/web/jcap.js +150 -0
- package/dist/platforms/jd/web/js.js +420 -0
- package/dist/platforms/jd/web/login.js +775 -0
- package/dist/platforms/jd/web/normalize.js +297 -0
- package/dist/platforms/jd/web/profile.js +256 -0
- package/dist/platforms/jd/web/util.js +175 -0
- package/dist/platforms/jd/web/webm.js +133 -0
- package/dist/platforms/kuaishou/index.js +98 -0
- package/dist/platforms/kuaishou/web/api.js +694 -0
- package/dist/platforms/kuaishou/web/captcha-crypto.js +134 -0
- package/dist/platforms/kuaishou/web/captcha-fp.js +180 -0
- package/dist/platforms/kuaishou/web/captcha.js +273 -0
- package/dist/platforms/kuaishou/web/client.js +487 -0
- package/dist/platforms/kuaishou/web/commands.js +863 -0
- package/dist/platforms/kuaishou/web/gap.js +144 -0
- package/dist/platforms/kuaishou/web/gdfp.js +376 -0
- package/dist/platforms/kuaishou/web/gql.js +11 -0
- package/dist/platforms/kuaishou/web/live.js +125 -0
- package/dist/platforms/kuaishou/web/normalize.js +241 -0
- package/dist/platforms/kuaishou/web/oracle.js +329 -0
- package/dist/platforms/kuaishou/web/profile.js +259 -0
- package/dist/platforms/kuaishou/web/resolve.js +84 -0
- package/dist/platforms/kuaishou/web/session.js +592 -0
- package/dist/platforms/kuaishou/web/sign.js +568 -0
- package/dist/platforms/taobao/index.js +56 -0
- package/dist/platforms/taobao/web/api.js +96 -0
- package/dist/platforms/taobao/web/client.js +102 -0
- package/dist/platforms/taobao/web/commands.js +172 -0
- package/dist/platforms/taobao/web/im.js +68 -0
- package/dist/platforms/taobao/web/normalize.js +103 -0
- package/dist/platforms/taobao/web/profile.js +85 -0
- package/dist/platforms/taobao/web/resolve.js +51 -0
- package/dist/platforms/taobao/web/sign.js +35 -0
- package/dist/platforms/tiktok/index.js +120 -0
- package/dist/platforms/tiktok/web/api.js +1234 -0
- package/dist/platforms/tiktok/web/client.js +362 -0
- package/dist/platforms/tiktok/web/commands.js +821 -0
- package/dist/platforms/tiktok/web/im.js +133 -0
- package/dist/platforms/tiktok/web/jsrun.js +126 -0
- package/dist/platforms/tiktok/web/normalize.js +286 -0
- package/dist/platforms/tiktok/web/profile.js +169 -0
- package/dist/platforms/tiktok/web/resolve.js +156 -0
- package/dist/platforms/tiktok/web/sign.js +585 -0
- package/dist/platforms/tiktok/web/upload.js +805 -0
- package/dist/platforms/tiktok/web/wire.js +490 -0
- package/dist/platforms/weibo/index.js +91 -0
- package/dist/platforms/weibo/web/api.js +206 -0
- package/dist/platforms/weibo/web/client.js +155 -0
- package/dist/platforms/weibo/web/commands.js +202 -0
- package/dist/platforms/weibo/web/normalize.js +137 -0
- package/dist/platforms/weibo/web/profile.js +246 -0
- package/dist/platforms/weibo/web/resolve.js +60 -0
- package/dist/platforms/weibo/web/sign.js +85 -0
- package/dist/platforms/x/index.js +107 -0
- package/dist/platforms/x/web/api.js +443 -0
- package/dist/platforms/x/web/article.js +212 -0
- package/dist/platforms/x/web/client.js +202 -0
- package/dist/platforms/x/web/commands.js +363 -0
- package/dist/platforms/x/web/graphql.js +108 -0
- package/dist/platforms/x/web/normalize.js +235 -0
- package/dist/platforms/x/web/profile.js +99 -0
- package/dist/platforms/x/web/resolve.js +44 -0
- package/dist/platforms/x/web/transaction.js +171 -0
- package/dist/platforms/xhs/index.js +101 -0
- package/dist/platforms/xhs/web/api.js +278 -0
- package/dist/platforms/xhs/web/client.js +540 -0
- package/dist/platforms/xhs/web/commands.js +1046 -0
- package/dist/platforms/xhs/web/creator-api.js +609 -0
- package/dist/platforms/xhs/web/creator.js +203 -0
- package/dist/platforms/xhs/web/js.js +194 -0
- package/dist/platforms/xhs/web/login.js +230 -0
- package/dist/platforms/xhs/web/normalize.js +166 -0
- package/dist/platforms/xhs/web/profile.js +127 -0
- package/dist/platforms/xhs/web/push.js +361 -0
- package/dist/platforms/xhs/web/resolve.js +69 -0
- package/dist/platforms/xhs/web/state.js +368 -0
- package/dist/platforms/xianyu/index.js +59 -0
- package/dist/platforms/xianyu/web/api.js +312 -0
- package/dist/platforms/xianyu/web/client.js +134 -0
- package/dist/platforms/xianyu/web/commands.js +305 -0
- package/dist/platforms/xianyu/web/im.js +73 -0
- package/dist/platforms/xianyu/web/normalize.js +123 -0
- package/dist/platforms/xianyu/web/profile.js +146 -0
- package/dist/platforms/xianyu/web/resolve.js +48 -0
- package/dist/platforms/xianyu/web/sign.js +79 -0
- package/package.json +77 -4
- package/static/douyin/Live.proto +194 -0
- package/static/douyin/Request.proto +89 -0
- package/static/douyin/Response.proto +46 -0
- package/static/douyin/acrawler_runtime/ac_vm.js +2 -0
- package/static/douyin/acrawler_runtime/browser_window_shape.json +1 -0
- package/static/douyin/acrawler_runtime/canvas_actual_exact.json +1 -0
- package/static/douyin/acrawler_runtime/run_ac_node.js +1005 -0
- package/static/douyin/acrawler_runtime/runner_window_keys_baseline.txt +240 -0
- package/static/douyin/challenge_profile.json +801 -0
- package/static/douyin/challenge_template_runner.js +217 -0
- package/static/douyin/dtrait_profile.json +66 -0
- package/static/douyin/mstoken_common_profile.json +1 -0
- package/static/douyin/mstoken_profile.json +214 -0
- package/static/jd/h5st5_env.js +750 -0
- package/static/jd/h5st5_lib.js +5 -0
- package/static/jd/h5st5_server.js +49 -0
- package/static/jd/jcap/env/env_core.js +512 -0
- package/static/jd/jcap/env/run.js +1307 -0
- package/static/jd/jcap/run/jcap_ujb96b.js +39 -0
- package/static/jd/package.json +4 -0
- package/static/jd/pc_tk_lib.js +1 -0
- package/static/jd/pc_tk_server.js +63 -0
- package/static/jd/summer_cryptico_runner.js +50 -0
- package/static/jd/webm/env/run.js +453 -0
- package/static/jd/webm/run/jdwebm-riskhandle.js +49 -0
- package/static/kuaishou/bundles/weapon/kwf-0.0.2.2cee19b4b7dec496.js +1 -0
- package/static/kuaishou/bundles/weapon/kws-0-0.0.1-obfuscated.4b7f3de1ab0ddcc2.js +1 -0
- package/static/kuaishou/bundles/weapon/kws-1-0.0.1-obfuscated.346ebdb1c78df316.js +1 -0
- package/static/kuaishou/bundles/weapon/kws-10-0.0.1-obfuscated.a33db41897b983af.js +1 -0
- package/static/kuaishou/bundles/weapon/kws-11-0.0.1-obfuscated.5e0a90af726d8a7e.js +1 -0
- package/static/kuaishou/bundles/weapon/kws-12-0.0.1-obfuscated.20ea29345706ec8c.js +1 -0
- package/static/kuaishou/bundles/weapon/kws-13-0.0.1-obfuscated.6b74e9640ff18648.js +1 -0
- package/static/kuaishou/bundles/weapon/kws-14-0.0.1-obfuscated.551e4429d156bf66.js +1 -0
- package/static/kuaishou/bundles/weapon/kws-15-0.0.1-obfuscated.8625b087aaba4a60.js +1 -0
- package/static/kuaishou/bundles/weapon/kws-16-0.0.1-obfuscated.d5ffa4020f3be99a.js +1 -0
- package/static/kuaishou/bundles/weapon/kws-17-0.0.1-obfuscated.6d13e19b22f50a80.js +1 -0
- package/static/kuaishou/bundles/weapon/kws-18-0.0.1-obfuscated.6d31405044166289.js +1 -0
- package/static/kuaishou/bundles/weapon/kws-19-0.0.1-obfuscated.a9a8d925942f19e4.js +1 -0
- package/static/kuaishou/bundles/weapon/kws-2-0.0.1-obfuscated.b849a136ae4a6b3e.js +1 -0
- package/static/kuaishou/bundles/weapon/kws-3-0.0.1-obfuscated.f9e77ebf6186e2ac.js +1 -0
- package/static/kuaishou/bundles/weapon/kws-4-0.0.1-obfuscated.2c3c155aa52ceb0e.js +1 -0
- package/static/kuaishou/bundles/weapon/kws-5-0.0.1-obfuscated.4e553d17691b3c5a.js +1 -0
- package/static/kuaishou/bundles/weapon/kws-6-0.0.1-obfuscated.f73ddd3ff13e1217.js +1 -0
- package/static/kuaishou/bundles/weapon/kws-7-0.0.1-obfuscated.1628b8729beaab7e.js +1 -0
- package/static/kuaishou/bundles/weapon/kws-8-0.0.1-obfuscated.6da6baef7aa81fff.js +1 -0
- package/static/kuaishou/bundles/weapon/kws-9-0.0.1-obfuscated.8645d55e5323b743.js +1 -0
- package/static/kuaishou/fixtures/current_follow_script_813.network-response +2 -0
- package/static/kuaishou/fixtures/live_ws_maps.json +61 -0
- package/static/kuaishou/fixtures/live_ws_proto.json +1342 -0
- package/static/kuaishou/js/cp-kwf.js +1 -0
- package/static/kuaishou/tools/kwf_oracle.js +799 -0
- package/static/kuaishou/tools/kws_oracle.js +885 -0
- package/static/kuaishou/tools/like_token_oracle.js +70 -0
- package/static/taobao/taobao_js_20260407.js +570 -0
- package/static/tiktok/Tiktok_Request.json +597 -0
- package/static/tiktok/package.json +3 -0
- package/static/tiktok/shop_bsid/core.js +1 -0
- package/static/tiktok/shop_bsid/env_core.js +512 -0
- package/static/tiktok/shop_bsid/loader.js +1 -0
- package/static/tiktok/shop_bsid/run.js +753 -0
- package/static/tiktok/shop_bsid/sign.js +100 -0
- package/static/tiktok/shop_bsid/webmssdk.js +1 -0
- package/static/tiktok/shop_bsid/webmssdk_ex.js +1 -0
- package/static/tiktok/signing/env/env_core.js +512 -0
- package/static/tiktok/signing/env/sign.js +455 -0
- package/static/tiktok/signing/sdk_config.json +230 -0
- package/static/tiktok/signing/source/webmssdk.js +1 -0
- package/static/tiktok/signing/source/webmssdk_ex.js +1 -0
- package/static/tiktok/signing/source/webmssdk_legacy.js +1 -0
- package/static/x/graphql.json +7777 -0
- package/static/x/transaction_l1.json +12 -0
- package/static/xhs/package.json +3 -0
- package/static/xhs/xhs_core/js/b1.js +210 -0
- package/static/xhs/xhs_core/js/mns.js +340 -0
- package/static/xhs/xhs_core/js/mns_0101_keystream.json +5 -0
- package/static/xhs/xhs_core/js/mns_keystreams.json +1 -0
- package/static/xhs/xhs_core/js/sign.js +225 -0
- package/static/xhs/xhs_core/js/websectiga_cli.js +220 -0
- package/static/xhs/xhs_core/js/websectiga_env.js +512 -0
- package/static/xhs/xhs_core/js/xs_common.js +79 -0
- package/static/xhs/xhs_creator/js/profile.js +115 -0
- package/static/xhs/xhs_creator/js/rap_fingerprint_creator.json +6 -0
- package/static/xhs/xhs_creator/js/reference_profile.json +282 -0
- package/static/xhs/xhs_creator/js/xhs_creator_sign.js +29 -0
- package/static/xhs/xhs_creator/js/xhs_creator_signature.js +23 -0
- package/static/xhs/xhs_pc/js/aes_decrypt.js +22 -0
- package/static/xhs/xhs_pc/js/aes_encrypt.js +30 -0
- package/static/xhs/xhs_pc/js/b1.js +9 -0
- package/static/xhs/xhs_pc/js/deflate.js +320 -0
- package/static/xhs/xhs_pc/js/mns.js +4 -0
- package/static/xhs/xhs_pc/js/profile.js +141 -0
- package/static/xhs/xhs_pc/js/rap.js +173 -0
- package/static/xhs/xhs_pc/js/rap_cli.js +30 -0
- package/static/xhs/xhs_pc/js/rap_crypto.js +73 -0
- package/static/xhs/xhs_pc/js/rap_fingerprint_template.json +8 -0
- package/static/xhs/xhs_pc/js/reference_profile.json +262 -0
- package/static/xhs/xhs_pc/js/sign.js +6 -0
- package/static/xhs/xhs_pc/js/web_ssk.js +82 -0
- package/static/xhs/xhs_pc/js/xs_common.js +4 -0
- package/static/xianyu/et_f.js +2 -0
- package/static/xianyu/gen_tfstk.js +410 -0
- package/static/xianyu/goofish_js_version_2.js +568 -0
|
@@ -0,0 +1,1005 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const vm = require('vm');
|
|
3
|
+
|
|
4
|
+
const nativeSourceMap = new WeakMap();
|
|
5
|
+
const originalFunctionToString = Function.prototype.toString;
|
|
6
|
+
const rawObjectToString = Object.prototype.toString;
|
|
7
|
+
const functionTrace = [];
|
|
8
|
+
Function.prototype.toString = function() {
|
|
9
|
+
const mapped = nativeSourceMap.get(this);
|
|
10
|
+
if (process.env.AC_TRACE && functionTrace.length < 100) {
|
|
11
|
+
functionTrace.push({name:this && this.name, len:this && this.length, mapped:!!mapped, src:(mapped || originalFunctionToString.call(this)).slice(0,120)});
|
|
12
|
+
}
|
|
13
|
+
return mapped || originalFunctionToString.call(this);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const cookieStore = {
|
|
17
|
+
// Production callers pass the complete Cookie header through AC_COOKIE_ONLY.
|
|
18
|
+
// Keep standalone defaults deliberately empty; never ship captured session
|
|
19
|
+
// material in the runtime bundle.
|
|
20
|
+
__ac_nonce: process.env.AC_NONCE || '00000000000000000000',
|
|
21
|
+
UIFID_TEMP: process.env.AC_UIFID_TEMP || '',
|
|
22
|
+
bit_env: process.env.AC_BIT_ENV || '',
|
|
23
|
+
};
|
|
24
|
+
if (String(process.env.AC_VARIANT || '').split(',').includes('cookie-extra')) cookieStore.foo = 'bar';
|
|
25
|
+
if (String(process.env.AC_VARIANT || '').split(',').includes('cookie-ui-bit-nonce')) {
|
|
26
|
+
const vals = {UIFID_TEMP: cookieStore.UIFID_TEMP, bit_env: cookieStore.bit_env,
|
|
27
|
+
__ac_nonce: cookieStore.__ac_nonce};
|
|
28
|
+
delete cookieStore.__ac_nonce; delete cookieStore.UIFID_TEMP; delete cookieStore.bit_env;
|
|
29
|
+
Object.assign(cookieStore, vals);
|
|
30
|
+
}
|
|
31
|
+
if (process.env.AC_COOKIE_EXTRA) {
|
|
32
|
+
for (const part of String(process.env.AC_COOKIE_EXTRA).split(';')) {
|
|
33
|
+
const i = part.indexOf('=');
|
|
34
|
+
if (i > 0) cookieStore[part.slice(0, i)] = part.slice(i + 1);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// Preserve an exact browser cookie serialization when supplied. This avoids
|
|
38
|
+
// normalizing flag-like entries or changing the original cookie order.
|
|
39
|
+
const rawCookieOverride = process.env.AC_COOKIE_ONLY ? String(process.env.AC_COOKIE_ONLY) : null;
|
|
40
|
+
const signNonce = process.env.AC_SIGN_NONCE || cookieStore.__ac_nonce || '';
|
|
41
|
+
const storage = new Map();
|
|
42
|
+
const sessionStorage = {
|
|
43
|
+
getItem(k){ return storage.has('s:'+k) ? storage.get('s:'+k) : null; },
|
|
44
|
+
setItem(k,v){ storage.set('s:'+k, String(v)); },
|
|
45
|
+
removeItem(k){ storage.delete('s:'+k); },
|
|
46
|
+
};
|
|
47
|
+
const localStorage = {
|
|
48
|
+
getItem(k){ return storage.has('l:'+k) ? storage.get('l:'+k) : null; },
|
|
49
|
+
setItem(k,v){ storage.set('l:'+k, String(v)); },
|
|
50
|
+
removeItem(k){ storage.delete('l:'+k); },
|
|
51
|
+
};
|
|
52
|
+
const FONT_BASE_WIDTHS = {monospace:468, 'sans-serif':727, serif:773};
|
|
53
|
+
const FONT_INSTALLED_WIDTHS = {
|
|
54
|
+
'Trebuchet MS': 661,
|
|
55
|
+
'Wingdings': 850,
|
|
56
|
+
'Sylfaen': 653,
|
|
57
|
+
'Segoe UI': 672,
|
|
58
|
+
'Constantia': 685,
|
|
59
|
+
};
|
|
60
|
+
function makeSpan() {
|
|
61
|
+
const style = {fontSize:'', fontFamily:'', position:'', left:''};
|
|
62
|
+
const span = {
|
|
63
|
+
style,
|
|
64
|
+
innerHTML:'',
|
|
65
|
+
get offsetWidth() {
|
|
66
|
+
const family = String(style.fontFamily || '').split(',')[0].trim().replace(/^['"]|['"]$/g, '');
|
|
67
|
+
if (Object.prototype.hasOwnProperty.call(FONT_INSTALLED_WIDTHS, family)) return FONT_INSTALLED_WIDTHS[family];
|
|
68
|
+
if (Object.prototype.hasOwnProperty.call(FONT_BASE_WIDTHS, family)) return FONT_BASE_WIDTHS[family];
|
|
69
|
+
const base = String(style.fontFamily || '').split(',').slice(-1)[0].trim().replace(/^['"]|['"]$/g, '');
|
|
70
|
+
return FONT_BASE_WIDTHS[base] || 0;
|
|
71
|
+
},
|
|
72
|
+
get offsetHeight() { return 83; },
|
|
73
|
+
remove() {},
|
|
74
|
+
};
|
|
75
|
+
return span;
|
|
76
|
+
}
|
|
77
|
+
const document = {
|
|
78
|
+
referrer: process.env.AC_REFERRER || '',
|
|
79
|
+
documentMode: undefined,
|
|
80
|
+
characterSet: 'UTF-8',
|
|
81
|
+
compatMode: 'CSS1Compat',
|
|
82
|
+
cookie: '',
|
|
83
|
+
body: {appendChild(){}, removeChild(){}},
|
|
84
|
+
head: {appendChild(){}, removeChild(){}},
|
|
85
|
+
// Chrome page 11 evidence: document.images.length === 81.
|
|
86
|
+
images: Array.from({length:81}, (_, i) => ({__index:i})),
|
|
87
|
+
getElementsByTagName(tag){
|
|
88
|
+
if (String(tag).toLowerCase() === 'body') return [this.body];
|
|
89
|
+
if (String(tag).toLowerCase() === 'head') return [this.head];
|
|
90
|
+
return [];
|
|
91
|
+
},
|
|
92
|
+
createElement(tag){
|
|
93
|
+
if (tag === 'canvas') return {
|
|
94
|
+
width: 300, height: 150,
|
|
95
|
+
getContext(type){
|
|
96
|
+
if (type === 'webgl' || type === 'experimental-webgl') return makeWebGLContext();
|
|
97
|
+
if (type === '2d') return {
|
|
98
|
+
font:'', shadowBlur:0, shadowOffsetX:0, shadowColor:'', showOffsetX:0, showColor:'', fillStyle:'',
|
|
99
|
+
fillText(_text, _x, _y){}, arc(_x, _y, _radius, _startAngle, _endAngle){}, stroke(){},
|
|
100
|
+
// Chrome probe captured the deterministic prefix and total length.
|
|
101
|
+
toDataURL: makeNativeFunction('toDataURL', 0, () => CANVAS_DATA_URL),
|
|
102
|
+
};
|
|
103
|
+
return null;
|
|
104
|
+
},
|
|
105
|
+
toDataURL: makeNativeFunction('toDataURL', 0, () => CANVAS_DATA_URL),
|
|
106
|
+
};
|
|
107
|
+
if (tag === 'span') return makeSpan();
|
|
108
|
+
if (tag === 'script') return {src:'', async:false};
|
|
109
|
+
return {style:{}, appendChild(){}, removeChild(){}};
|
|
110
|
+
},
|
|
111
|
+
createEvent(type){
|
|
112
|
+
if (String(type) === 'TouchEvent') {
|
|
113
|
+
const err = new Error("Failed to execute 'createEvent' on 'Document': The provided event type ('TouchEvent') is invalid.");
|
|
114
|
+
err.name = 'NotSupportedError';
|
|
115
|
+
throw err;
|
|
116
|
+
}
|
|
117
|
+
return {initEvent(){}};
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
// Values captured from the real Chrome WebGL context (page 12 canvas probe).
|
|
122
|
+
const WEBGL_VENDOR = 'Google Inc. (NVIDIA)';
|
|
123
|
+
const WEBGL_RENDERER = 'ANGLE (NVIDIA, NVIDIA GeForce RTX 5060 Ti (0x00002D04) Direct3D11 vs_5_0 ps_5_0, D3D11)';
|
|
124
|
+
const WEBGL_VERSION = 'WebGL 1.0 (OpenGL ES 2.0 Chromium)';
|
|
125
|
+
const WEBGL_SHADING_LANGUAGE_VERSION = 'WebGL GLSL ES 1.0 (OpenGL ES GLSL ES 1.0 Chromium)';
|
|
126
|
+
const WEBGL_EXTENSIONS = [
|
|
127
|
+
'ANGLE_instanced_arrays','EXT_blend_minmax','EXT_clip_control','EXT_color_buffer_half_float',
|
|
128
|
+
'EXT_depth_clamp','EXT_disjoint_timer_query','EXT_float_blend','EXT_frag_depth',
|
|
129
|
+
'EXT_polygon_offset_clamp','EXT_shader_texture_lod','EXT_texture_compression_bptc',
|
|
130
|
+
'EXT_texture_compression_rgtc','EXT_texture_filter_anisotropic','EXT_texture_mirror_clamp_to_edge',
|
|
131
|
+
'EXT_sRGB','KHR_parallel_shader_compile','OES_element_index_uint','OES_fbo_render_mipmap',
|
|
132
|
+
'OES_standard_derivatives','OES_texture_float','OES_texture_float_linear','OES_texture_half_float',
|
|
133
|
+
'OES_texture_half_float_linear','OES_vertex_array_object','WEBGL_blend_func_extended',
|
|
134
|
+
'WEBGL_color_buffer_float','WEBGL_compressed_texture_s3tc','WEBGL_compressed_texture_s3tc_srgb',
|
|
135
|
+
'WEBGL_debug_renderer_info','WEBGL_debug_shaders','WEBGL_depth_texture','WEBGL_draw_buffers',
|
|
136
|
+
'WEBGL_lose_context','WEBGL_multi_draw','WEBGL_polygon_mode'
|
|
137
|
+
];
|
|
138
|
+
const CANVAS_DATA_URL = process.env.AC_CANVAS_DATA_URL || 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAQCAYAAABQrvyxAAADbklEQVR4AcSWWahNYRSAjzljN2TMrJRIhkxJZAgZywOhW7yZC3kglBdESZIXD5cyZbhI8iZDmTM9GB+QeeiaMg/fd+7Zu/9sm/t07tH67lr/+v/977X+tf591Mz8/a8errUwCupACQwHfQ3QSkP+tIRiSl9eXh4mYHBzcR4E7eno47AcOucYh54Kq8GkaqELIa3Z9CH8TnCKcSOIJUygCd7ncBd+QAXcgBYwAj5D2xwd0Y5/ogshz9i0A9QImIhtUh/RsYQJGPxXZsbCAOgDY+AV3IJIamPoO4OuLvHUl/Cyk2AVrMxl7JIwAcYZx3UxvuSwEuewPenB6CngSVitb9ieECpjm3k6Exg8AvsTlfX7sjIHAc5/YuycGJRB4kqVeXjdfzd6GPjefugKA0bnyXlGO+AI3IZIDNjEbB0TW8SEF9yg12G3B09pJ3oT+KJBaO+KGDTDjP19CGMaGEhjtGKQ6iQejl3hvM+aiEmnVsAgj7LDYfAkvQ+XsE3qAtrEtF9jXwPXd0cbtJUx8HaMlcX8cf0HdCienMn6HitjT59ggUGGVYiCdX8Pw3Xh3XCfvAo0Z5MhMBPcfCnaVtmMHg1dwFNwQ09tFuOmYPC+YCu24ldqL4bV8ZQw8+QYI1/+GL0F0sTEPKiBTJbCPyVsITN8wMr7cBb8ChnoPeyLYCW8uC+w74D3Yhl6BvjFEMyM1VFbak9MO0kbHLbBU3SaGLT7+bytF94Xn5ORPDg5TKA+Dh/yC9MM+xe8AVunB9pWMCE/q86bqGW21ZjOE/v7QJ6ncmCLeGGtcKXn/3+9X96XrizzvkQYhy1XFibwnUW2SSv0S3gPXlgT0ie2jD5P32rZOn6lWBqL/d2JUVr7dMN/E7wvqCrFdpzPKiuBisVu8YPRK0wgns0ZXtC32P3B6qCyYvD+Zng6V/A8gaR4ysmXusbW64lhBbah09bgjsUqep9so9iJYSX9YFxPJmA7GLQ9ZgK2Sm8eMIGr6HdgP3qpPcVyxqF4QS2zPRz5TdKqqD05q+aa9dECtLJ5xnG4n5DGZ0GY4qwnU2gNEzAh1eycA1sgAWwCmbDHNgFC2Ej+Klcgd4OhRYT9z+PJh1ictlf3mQAYVLRnD9gto6JWIk9TJgIqriSFux4QvLi7kf7Cyv7sPVNQjtv+TCLL38AAAD//0WvmE8AAAAGSURBVAMACkfOk5B1KHEAAAAASUVORK5CYII=';
|
|
139
|
+
function makeWebGLContext() {
|
|
140
|
+
const debugInfo = {UNMASKED_VENDOR_WEBGL: 0x9245, UNMASKED_RENDERER_WEBGL: 0x9246};
|
|
141
|
+
const constants = {
|
|
142
|
+
VERSION: 0x1F02, SHADING_LANGUAGE_VERSION: 0x8B8C,
|
|
143
|
+
MAX_TEXTURE_SIZE: 0x0D33, MAX_VERTEX_ATTRIBS: 0x8869,
|
|
144
|
+
BLUE_BITS: 0x0D54, GREEN_BITS: 0x0D53, DEPTH_BITS: 0x0D56,
|
|
145
|
+
};
|
|
146
|
+
return {
|
|
147
|
+
getExtension(name){ return name === 'WEBGL_debug_renderer_info' ? debugInfo : (WEBGL_EXTENSIONS.includes(name) ? {} : null); },
|
|
148
|
+
getParameter(p){
|
|
149
|
+
if (p === debugInfo.UNMASKED_VENDOR_WEBGL) return WEBGL_VENDOR;
|
|
150
|
+
if (p === debugInfo.UNMASKED_RENDERER_WEBGL) return WEBGL_RENDERER;
|
|
151
|
+
if (p === constants.VERSION) return WEBGL_VERSION;
|
|
152
|
+
if (p === constants.SHADING_LANGUAGE_VERSION) return WEBGL_SHADING_LANGUAGE_VERSION;
|
|
153
|
+
if (p === constants.MAX_TEXTURE_SIZE) return 16384;
|
|
154
|
+
if (p === constants.MAX_VERTEX_ATTRIBS) return 16;
|
|
155
|
+
if (p === constants.BLUE_BITS || p === constants.GREEN_BITS) return 8;
|
|
156
|
+
if (p === constants.DEPTH_BITS) return 24;
|
|
157
|
+
return 0;
|
|
158
|
+
},
|
|
159
|
+
getSupportedExtensions(){ return WEBGL_EXTENSIONS.slice(); },
|
|
160
|
+
getContextAttributes(){ return {alpha:true,antialias:true,depth:true,desynchronized:false,failIfMajorPerformanceCaveat:false,powerPreference:'default',premultipliedAlpha:true,preserveDrawingBuffer:false,stencil:false,xrCompatible:false}; },
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
Object.defineProperty(document, 'cookie', {
|
|
164
|
+
get(){ return rawCookieOverride !== null ? rawCookieOverride : Object.entries(cookieStore).map(([k,v])=>`${k}=${v}`).join('; '); },
|
|
165
|
+
set(v){ const first=String(v).split(';',1)[0]; const i=first.indexOf('='); if(i<0)return; const k=first.slice(0,i).trim(); const val=first.slice(i+1); if(/expires=Mon, 20 Sep 2010|expires=Thu, 01-Jan-1970/i.test(v)) delete cookieStore[k]; else cookieStore[k]=val; },
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
function defineTag(obj, tag) {
|
|
169
|
+
Object.defineProperty(obj, Symbol.toStringTag, {value: tag, enumerable: false, configurable: true});
|
|
170
|
+
return obj;
|
|
171
|
+
}
|
|
172
|
+
function makeMimeType(type, suffixes, description) {
|
|
173
|
+
const proto = Object.create(Object.prototype);
|
|
174
|
+
defineTag(proto, 'MimeType');
|
|
175
|
+
Object.defineProperties(proto, {
|
|
176
|
+
type: {value:type, writable:true, enumerable:true, configurable:true},
|
|
177
|
+
suffixes: {value:suffixes, writable:true, enumerable:true, configurable:true},
|
|
178
|
+
description: {value:description, writable:true, enumerable:true, configurable:true},
|
|
179
|
+
enabledPlugin: {value:null, writable:true, enumerable:true, configurable:true},
|
|
180
|
+
constructor: {value:makeNativeFunction('MimeType', 0, () => {}), writable:true, enumerable:true, configurable:true},
|
|
181
|
+
});
|
|
182
|
+
return Object.create(proto);
|
|
183
|
+
}
|
|
184
|
+
function makeNativeItem(handler) {
|
|
185
|
+
const nativeBase = Array.prototype.find;
|
|
186
|
+
const fn = new Proxy(nativeBase, {apply(_target, _thisArg, args) { return handler(...args); }});
|
|
187
|
+
try { Object.defineProperty(fn, 'name', {value:'item', configurable:true}); } catch (_) {}
|
|
188
|
+
nativeSourceMap.set(fn, 'function item() { [native code] }');
|
|
189
|
+
return fn;
|
|
190
|
+
}
|
|
191
|
+
function makeNativeFunction(name, length, handler) {
|
|
192
|
+
const nativeBase = Array.prototype.find;
|
|
193
|
+
const fn = new Proxy(nativeBase, {apply(_target, _thisArg, args) { return handler(...args); }});
|
|
194
|
+
try {
|
|
195
|
+
Object.defineProperty(fn, 'name', {value:name, configurable:true});
|
|
196
|
+
Object.defineProperty(fn, 'length', {value:length, configurable:true});
|
|
197
|
+
} catch (_) {}
|
|
198
|
+
nativeSourceMap.set(fn, `function ${name}() { [native code] }`);
|
|
199
|
+
return fn;
|
|
200
|
+
}
|
|
201
|
+
if (String(process.env.AC_VARIANT || '').split(',').includes('native-doc-fns')) {
|
|
202
|
+
const oldGet = document.getElementsByTagName;
|
|
203
|
+
const oldCreate = document.createElement;
|
|
204
|
+
const oldEvent = document.createEvent;
|
|
205
|
+
document.getElementsByTagName = makeNativeFunction('getElementsByTagName', 1, tag => oldGet.call(document, tag));
|
|
206
|
+
document.createElement = makeNativeFunction('createElement', 1, tag => oldCreate.call(document, tag));
|
|
207
|
+
document.createEvent = makeNativeFunction('createEvent', 1, type => oldEvent.call(document, type));
|
|
208
|
+
}
|
|
209
|
+
function makeNativeConstructor(name, length) {
|
|
210
|
+
function C() {}
|
|
211
|
+
try {
|
|
212
|
+
Object.defineProperty(C, 'name', {value:name, configurable:true});
|
|
213
|
+
Object.defineProperty(C, 'length', {value:length, configurable:true});
|
|
214
|
+
} catch (_) {}
|
|
215
|
+
nativeSourceMap.set(C, `function ${name}() { [native code] }`);
|
|
216
|
+
return C;
|
|
217
|
+
}
|
|
218
|
+
function makePlugin(name) {
|
|
219
|
+
const m0 = makeMimeType('application/pdf', 'pdf', 'Portable Document Format');
|
|
220
|
+
const m1 = makeMimeType('text/pdf', 'pdf', 'Portable Document Format');
|
|
221
|
+
const itemFn = String(process.env.AC_VARIANT || '').split(',').includes('plain-item')
|
|
222
|
+
? function item(i) { return (i === 0 ? m0 : i === 1 ? m1 : null); }
|
|
223
|
+
: makeNativeItem(i => (i === 0 ? m0 : i === 1 ? m1 : null));
|
|
224
|
+
const proto = Object.create(Object.prototype);
|
|
225
|
+
defineTag(proto, 'Plugin');
|
|
226
|
+
Object.defineProperties(proto, {
|
|
227
|
+
name: {value:name, writable:true, enumerable:true, configurable:true},
|
|
228
|
+
filename: {value:'internal-pdf-viewer', writable:true, enumerable:true, configurable:true},
|
|
229
|
+
description: {value:'Portable Document Format', writable:true, enumerable:true, configurable:true},
|
|
230
|
+
length: {value:2, writable:true, enumerable:true, configurable:true},
|
|
231
|
+
item: {value:itemFn, writable:true, enumerable:true, configurable:true},
|
|
232
|
+
namedItem: {value:makeNativeFunction('namedItem', 1, type => type === 'application/pdf' ? m0 : type === 'text/pdf' ? m1 : null), writable:true, enumerable:true, configurable:true},
|
|
233
|
+
constructor: {value:makeNativeFunction('Plugin', 0, () => {}), writable:true, enumerable:true, configurable:true},
|
|
234
|
+
forEach: {value:makeNativeFunction('forEach', 1, () => {}), writable:true, enumerable:true, configurable:true},
|
|
235
|
+
});
|
|
236
|
+
const p = Object.create(proto);
|
|
237
|
+
Object.defineProperties(p, {
|
|
238
|
+
0: {value:m0, writable:true, enumerable:true, configurable:true},
|
|
239
|
+
1: {value:m1, writable:true, enumerable:true, configurable:true},
|
|
240
|
+
'application/pdf': {value:m0, writable:true, enumerable:true, configurable:true},
|
|
241
|
+
'text/pdf': {value:m1, writable:true, enumerable:true, configurable:true},
|
|
242
|
+
});
|
|
243
|
+
m0.__proto__.enabledPlugin = p;
|
|
244
|
+
m1.__proto__.enabledPlugin = p;
|
|
245
|
+
return p;
|
|
246
|
+
}
|
|
247
|
+
const pluginNames = ['PDF Viewer','Chrome PDF Viewer','Chromium PDF Viewer','Microsoft Edge PDF Viewer','WebKit built-in PDF'];
|
|
248
|
+
const pluginItems = pluginNames.map(makePlugin);
|
|
249
|
+
const pluginsProto = Object.create(Object.prototype);
|
|
250
|
+
defineTag(pluginsProto, 'PluginArray');
|
|
251
|
+
Object.defineProperties(pluginsProto, {
|
|
252
|
+
length: {value:pluginItems.length, writable:true, enumerable:true, configurable:true},
|
|
253
|
+
item: {value:makeNativeFunction('item', 1, i => (i >= 0 && i < pluginItems.length) ? pluginItems[i] : null), writable:true, enumerable:true, configurable:true},
|
|
254
|
+
namedItem: {value:makeNativeFunction('namedItem', 1, name => pluginItems.find(p => p.name === name) || null), writable:true, enumerable:true, configurable:true},
|
|
255
|
+
refresh: {value:makeNativeFunction('refresh', 0, () => {}), writable:true, enumerable:true, configurable:true},
|
|
256
|
+
constructor: {value:makeNativeFunction('PluginArray', 0, () => {}), writable:true, enumerable:true, configurable:true},
|
|
257
|
+
forEach: {value:makeNativeFunction('forEach', 1, () => {}), writable:true, enumerable:true, configurable:true},
|
|
258
|
+
});
|
|
259
|
+
const plugins = Object.create(pluginsProto);
|
|
260
|
+
for (let i = 0; i < pluginItems.length; i++) Object.defineProperty(plugins, String(i), {value:pluginItems[i], writable:true, enumerable:true, configurable:true});
|
|
261
|
+
for (const p of pluginItems) Object.defineProperty(plugins, p.name, {value:p, writable:true, enumerable:true, configurable:true});
|
|
262
|
+
const pluginVariantSet = new Set(String(process.env.AC_VARIANT || '').split(',').map(s => s.trim()));
|
|
263
|
+
if (pluginVariantSet.has('plugin-empty')) {
|
|
264
|
+
for (const p of pluginItems) {
|
|
265
|
+
const pp = Object.getPrototypeOf(p);
|
|
266
|
+
pp.name = ''; pp.filename = ''; pp.description = '';
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (pluginVariantSet.has('mime-empty')) {
|
|
270
|
+
for (const p of pluginItems) {
|
|
271
|
+
const mp = Object.getPrototypeOf(p[0]);
|
|
272
|
+
mp.type = ''; mp.suffixes = ''; mp.description = '';
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Optional exact Chromium shape used for one-cause experiments. The normal
|
|
277
|
+
// runner keeps the smaller hand-written objects; this branch mirrors the
|
|
278
|
+
// descriptors observed from a clean Chrome page (native getters, readonly
|
|
279
|
+
// indexed entries, non-enumerable named entries and MimeTypeArray).
|
|
280
|
+
const exactNativePlugins = pluginVariantSet.has('native-plugins');
|
|
281
|
+
const withMimeTypes = pluginVariantSet.has('native-plugins') || pluginVariantSet.has('with-mime') || pluginVariantSet.has('mime-empty');
|
|
282
|
+
if (exactNativePlugins) {
|
|
283
|
+
const nativeGetter = (name, value) => {
|
|
284
|
+
const fn = makeNativeFunction(`get ${name}`, 0, () => value);
|
|
285
|
+
return fn;
|
|
286
|
+
};
|
|
287
|
+
for (const p of pluginItems) {
|
|
288
|
+
const pp = Object.getPrototypeOf(p);
|
|
289
|
+
for (const [name, value] of [['name', pp.name], ['filename', pp.filename], ['description', pp.description], ['length', pp.length]]) {
|
|
290
|
+
Object.defineProperty(pp, name, {get: nativeGetter(name, value), enumerable:true, configurable:true});
|
|
291
|
+
}
|
|
292
|
+
Object.defineProperty(pp, 'constructor', {value:makeNativeFunction('Plugin', 0, () => {}), writable:true, enumerable:false, configurable:true});
|
|
293
|
+
Object.defineProperty(pp, 'forEach', {value:makeNativeFunction('forEach', 1, () => {}), writable:true, enumerable:false, configurable:true});
|
|
294
|
+
Object.defineProperty(pp, Symbol.toStringTag, {value:'Plugin', writable:true, enumerable:false, configurable:true});
|
|
295
|
+
Object.defineProperty(pp, Symbol.iterator, {value:makeNativeFunction('values', 0, function*(){yield* [this[0], this[1]]}), writable:true, enumerable:false, configurable:true});
|
|
296
|
+
for (const k of ['0','1']) Object.defineProperty(p, k, {value:p[k], writable:false, enumerable:true, configurable:true});
|
|
297
|
+
for (const k of ['application/pdf','text/pdf']) Object.defineProperty(p, k, {value:p[k], writable:false, enumerable:false, configurable:true});
|
|
298
|
+
}
|
|
299
|
+
Object.defineProperty(pluginsProto, 'length', {get:nativeGetter('length', pluginItems.length), enumerable:true, configurable:true});
|
|
300
|
+
Object.defineProperty(pluginsProto, 'constructor', {value:makeNativeFunction('PluginArray', 0, () => {}), writable:true, enumerable:false, configurable:true});
|
|
301
|
+
Object.defineProperty(pluginsProto, 'forEach', {value:makeNativeFunction('forEach', 1, () => {}), writable:true, enumerable:false, configurable:true});
|
|
302
|
+
Object.defineProperty(pluginsProto, Symbol.toStringTag, {value:'PluginArray', writable:true, enumerable:false, configurable:true});
|
|
303
|
+
Object.defineProperty(pluginsProto, Symbol.iterator, {value:makeNativeFunction('values', 0, function*(){yield* pluginItems}), writable:true, enumerable:false, configurable:true});
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const mimeItems = pluginItems.slice(0, 2).map((p, i) => {
|
|
307
|
+
const m = p[i];
|
|
308
|
+
if (exactNativePlugins) {
|
|
309
|
+
const mp = Object.getPrototypeOf(m);
|
|
310
|
+
for (const [name, value] of [['type', m.type], ['suffixes', m.suffixes], ['description', m.description], ['enabledPlugin', p]]) {
|
|
311
|
+
Object.defineProperty(mp, name, {get: makeNativeFunction(`get ${name}`, 0, () => value), enumerable:true, configurable:true});
|
|
312
|
+
}
|
|
313
|
+
Object.defineProperty(mp, 'constructor', {value:makeNativeFunction('MimeType', 0, () => {}), writable:true, enumerable:false, configurable:true});
|
|
314
|
+
Object.defineProperty(mp, Symbol.toStringTag, {value:'MimeType', writable:false, enumerable:false, configurable:true});
|
|
315
|
+
for (const k of ['type','suffixes','description','enabledPlugin']) { try { delete m[k]; } catch (_) {} }
|
|
316
|
+
}
|
|
317
|
+
return m;
|
|
318
|
+
});
|
|
319
|
+
const mimeTypesProto = Object.create(Object.prototype);
|
|
320
|
+
defineTag(mimeTypesProto, 'MimeTypeArray');
|
|
321
|
+
Object.defineProperties(mimeTypesProto, {
|
|
322
|
+
item: {value:makeNativeFunction('item', 1, i => (i >= 0 && i < mimeItems.length) ? mimeItems[i] : null), writable:true, enumerable:true, configurable:true},
|
|
323
|
+
namedItem: {value:makeNativeFunction('namedItem', 1, name => name === 'application/pdf' ? mimeItems[0] : name === 'text/pdf' ? mimeItems[1] : null), writable:true, enumerable:true, configurable:true},
|
|
324
|
+
constructor: {value:makeNativeFunction('MimeTypeArray', 0, () => {}), writable:true, enumerable:false, configurable:true},
|
|
325
|
+
forEach: {value:makeNativeFunction('forEach', 1, () => {}), writable:true, enumerable:false, configurable:true},
|
|
326
|
+
[Symbol.toStringTag]: {value:'MimeTypeArray', writable:true, enumerable:false, configurable:true},
|
|
327
|
+
[Symbol.iterator]: {value:makeNativeFunction('values', 0, function*(){yield* mimeItems}), writable:true, enumerable:false, configurable:true},
|
|
328
|
+
});
|
|
329
|
+
if (exactNativePlugins) Object.defineProperty(mimeTypesProto, 'length', {get:makeNativeFunction('get length', 0, () => mimeItems.length), enumerable:true, configurable:true});
|
|
330
|
+
else Object.defineProperty(mimeTypesProto, 'length', {value:mimeItems.length, writable:true, enumerable:true, configurable:true});
|
|
331
|
+
const mimeTypes = Object.create(mimeTypesProto);
|
|
332
|
+
for (let i=0; i<mimeItems.length;i++) Object.defineProperty(mimeTypes, String(i), {value:mimeItems[i], writable:false, enumerable:true, configurable:true});
|
|
333
|
+
for (const [k,m] of [['application/pdf',mimeItems[0]],['text/pdf',mimeItems[1]]]) Object.defineProperty(mimeTypes,k,{value:m,writable:false,enumerable:false,configurable:true});
|
|
334
|
+
|
|
335
|
+
const navigatorValues = {
|
|
336
|
+
userAgent: process.env.AC_UA || 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36',
|
|
337
|
+
appVersion: process.env.AC_APP_VERSION || ('5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36'),
|
|
338
|
+
productSub: '20030107', cookieEnabled: true, onLine: true,
|
|
339
|
+
platform: 'Win32', appCodeName:'Mozilla', appName:'Netscape', product:'Gecko',
|
|
340
|
+
vendor:'Google Inc.', vendorSub:'', doNotTrack:null, language:'zh-CN', languages:['zh-CN','zh'],
|
|
341
|
+
hardwareConcurrency:20, deviceMemory:32, maxTouchPoints:10, webdriver:false,
|
|
342
|
+
plugins,
|
|
343
|
+
connection:{rtt:0,downlink:10,effectiveType:'4g'},
|
|
344
|
+
getBattery: async()=>({charging:true,chargingTime:0,dischargingTime:Infinity,level:1}),
|
|
345
|
+
vibrate: function(){return false}, credentials:{}, storage:{},
|
|
346
|
+
requestMediaKeySystemAccess: function(){return Promise.reject(new Error('Not supported'))},
|
|
347
|
+
bluetooth:{},
|
|
348
|
+
vendorSubs:{ink:1787444753999},
|
|
349
|
+
};
|
|
350
|
+
if (withMimeTypes) navigatorValues.mimeTypes = mimeTypes;
|
|
351
|
+
if (String(process.env.AC_VARIANT || '').split(',').includes('ua-data')) navigatorValues.userAgentData = {brands:[{brand:'Chromium',version:'151'},{brand:'Google Chrome',version:'151'},{brand:'Not_A Brand',version:'99'}],mobile:false,platform:'Windows',getHighEntropyValues:async()=>({})};
|
|
352
|
+
if (String(process.env.AC_VARIANT || '').split(',').includes('ua-data-empty')) navigatorValues.userAgentData = {};
|
|
353
|
+
const navigatorProto = Object.create(Object.prototype);
|
|
354
|
+
for (const [key, value] of Object.entries(navigatorValues)) {
|
|
355
|
+
Object.defineProperty(navigatorProto, key, {value, writable:true, configurable:true, enumerable:false});
|
|
356
|
+
}
|
|
357
|
+
if (String(process.env.AC_VARIANT || '').split(',').includes('nav-constructor')) {
|
|
358
|
+
Object.defineProperty(navigatorProto, 'constructor', {value:function Navigator(){}, writable:true, configurable:true, enumerable:false});
|
|
359
|
+
}
|
|
360
|
+
let navigator = Object.create(navigatorProto);
|
|
361
|
+
// Chrome exposes this misspelled own property in the current profile.
|
|
362
|
+
navigator.pemrissions = {microphone:'granted'};
|
|
363
|
+
if (String(process.env.AC_VARIANT || '').split(',').includes('no-permissions')) delete navigator.pemrissions;
|
|
364
|
+
if (String(process.env.AC_VARIANT || '').split(',').includes('permissions-proto')) {
|
|
365
|
+
const p = Object.getPrototypeOf(navigator);
|
|
366
|
+
const d = Object.getOwnPropertyDescriptor(navigator, 'pemrissions');
|
|
367
|
+
if (d) { Object.defineProperty(p, 'pemrissions', d); delete navigator.pemrissions; }
|
|
368
|
+
}
|
|
369
|
+
if (String(process.env.AC_VARIANT || '').split(',').includes('permissions-empty')) navigator.pemrissions = {};
|
|
370
|
+
if (String(process.env.AC_VARIANT || '').split(',').includes('permissions-null')) navigator.pemrissions = null;
|
|
371
|
+
const navTagVariants = new Set(String(process.env.AC_VARIANT || '').split(',').map(s => s.trim()));
|
|
372
|
+
if (!navTagVariants.has('no-navtag')) {
|
|
373
|
+
if (navTagVariants.has('navtag-proto')) defineTag(navigatorProto, 'Navigator');
|
|
374
|
+
else defineTag(navigator, 'Navigator');
|
|
375
|
+
}
|
|
376
|
+
if (navTagVariants.has('nav-constructor-native')) {
|
|
377
|
+
Object.defineProperty(navigatorProto, 'constructor', {value:makeNativeConstructor('Navigator', 0), writable:true, configurable:true, enumerable:false});
|
|
378
|
+
}
|
|
379
|
+
if (navTagVariants.has('nav-proxy')) {
|
|
380
|
+
const navTarget = navigator;
|
|
381
|
+
navigator = new Proxy(navTarget, {
|
|
382
|
+
get(t, p) { return Reflect.get(t, p, t); },
|
|
383
|
+
has(t, p) { return Reflect.has(t, p); },
|
|
384
|
+
ownKeys(t) { return Reflect.ownKeys(t); },
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
if (navTagVariants.has('nav-tostring-object')) {
|
|
388
|
+
Object.defineProperty(navigatorProto, 'toString', {value: makeNativeFunction('toString', 0, () => '[object Object]'), writable:true, configurable:true, enumerable:false});
|
|
389
|
+
}
|
|
390
|
+
if (navTagVariants.has('nav-tostring-native')) {
|
|
391
|
+
Object.defineProperty(navigatorProto, 'toString', {value: makeNativeFunction('toString', 0, () => '[object Navigator]'), writable:true, configurable:true, enumerable:false});
|
|
392
|
+
}
|
|
393
|
+
if (navTagVariants.has('nav-getters')) {
|
|
394
|
+
for (const key of ['userAgent','platform','plugins','webdriver','language','languages','hardwareConcurrency','deviceMemory','maxTouchPoints','vendor','vendorSub','appCodeName','appName','product']) {
|
|
395
|
+
const value = navigatorValues[key];
|
|
396
|
+
Object.defineProperty(navigatorProto, key, {get: () => value, configurable:true, enumerable:true});
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
if (navTagVariants.has('nav-native-getters')) {
|
|
400
|
+
for (const key of ['userAgent','platform','plugins','webdriver','language','languages','hardwareConcurrency','deviceMemory','maxTouchPoints','vendor','vendorSub','appCodeName','appName','product','connection']) {
|
|
401
|
+
const value = navigatorValues[key];
|
|
402
|
+
Object.defineProperty(navigatorProto, key, {get:makeNativeFunction(`get ${key}`,0,()=>value), configurable:true, enumerable:true});
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
if (navTagVariants.has('chrome-nav')) {
|
|
406
|
+
// Clean Chromium navigator: the misspelled `pemrissions` is the only own
|
|
407
|
+
// string key; Navigator tag/constructor are inherited from its prototype.
|
|
408
|
+
try { delete navigator[Symbol.toStringTag]; } catch (_) {}
|
|
409
|
+
const p = Object.getPrototypeOf(navigator);
|
|
410
|
+
defineTag(p, 'Navigator');
|
|
411
|
+
Object.defineProperty(p, 'constructor', {
|
|
412
|
+
value: makeNativeConstructor('Navigator', 0),
|
|
413
|
+
writable: true, configurable: true, enumerable: false,
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
if (String(process.env.AC_VARIANT || '').split(',').includes('emptyplugins')) {
|
|
417
|
+
navigatorProto.plugins = defineTag({length:0, item(){return null}, namedItem(){return null}}, 'PluginArray');
|
|
418
|
+
}
|
|
419
|
+
const variantSet = new Set(String(process.env.AC_VARIANT || '').split(',').map(s => s.trim()));
|
|
420
|
+
if (variantSet.has('ua-empty')) navigatorProto.userAgent = '';
|
|
421
|
+
if (variantSet.has('platform-empty')) navigatorProto.platform = '';
|
|
422
|
+
if (variantSet.has('webdriver-true')) navigatorProto.webdriver = true;
|
|
423
|
+
if (variantSet.has('touch-zero')) navigatorProto.maxTouchPoints = 0;
|
|
424
|
+
if (variantSet.has('rtt-50')) navigatorProto.connection = {rtt:50, downlink:10, effectiveType:'4g'};
|
|
425
|
+
if (variantSet.has('images-zero')) document.images = [];
|
|
426
|
+
const screen = {width:2560,height:1440,availWidth:2560,availHeight:1392,colorDepth:24,pixelDepth:24};
|
|
427
|
+
const location = {
|
|
428
|
+
valueOf: makeNativeFunction('valueOf', 0, () => location),
|
|
429
|
+
ancestorOrigins: [],
|
|
430
|
+
href:process.env.AC_HREF || 'https://www.douyin.com/jingxuan', origin:'https://www.douyin.com',
|
|
431
|
+
protocol:'https:', host:'www.douyin.com', hostname:'www.douyin.com', port:'',
|
|
432
|
+
pathname:'/jingxuan', search:'', hash:'', username:'', password:'',
|
|
433
|
+
assign: makeNativeFunction('assign', 1, () => undefined),
|
|
434
|
+
reload: makeNativeFunction('reload', 0, () => undefined),
|
|
435
|
+
replace: makeNativeFunction('replace', 1, () => undefined),
|
|
436
|
+
toString: makeNativeFunction('toString', 0, () => location.href),
|
|
437
|
+
};
|
|
438
|
+
// Keep URL-derived location fields coherent when the production helper signs
|
|
439
|
+
// a request other than the historical /jingxuan fixture.
|
|
440
|
+
try {
|
|
441
|
+
const parsedLocation = new URL(location.href);
|
|
442
|
+
location.origin = parsedLocation.origin;
|
|
443
|
+
location.protocol = parsedLocation.protocol;
|
|
444
|
+
location.host = parsedLocation.host;
|
|
445
|
+
location.hostname = parsedLocation.hostname;
|
|
446
|
+
location.port = parsedLocation.port;
|
|
447
|
+
location.pathname = parsedLocation.pathname;
|
|
448
|
+
location.search = parsedLocation.search;
|
|
449
|
+
location.hash = parsedLocation.hash;
|
|
450
|
+
location.username = parsedLocation.username;
|
|
451
|
+
location.password = parsedLocation.password;
|
|
452
|
+
} catch (_) {}
|
|
453
|
+
const docVariants = new Set(String(process.env.AC_VARIANT || '').split(',').map(s => s.trim()));
|
|
454
|
+
if (docVariants.has('doc-methods-proto') || docVariants.has('doc-clean') || docVariants.has('doc-empty')) {
|
|
455
|
+
const proto = Object.create(Object.prototype);
|
|
456
|
+
for (const key of ['getElementsByTagName','createElement','createEvent']) {
|
|
457
|
+
const d = Object.getOwnPropertyDescriptor(document, key);
|
|
458
|
+
if (d) { Object.defineProperty(proto, key, d); delete document[key]; }
|
|
459
|
+
}
|
|
460
|
+
Object.setPrototypeOf(document, proto);
|
|
461
|
+
}
|
|
462
|
+
if (docVariants.has('doc-values-proto') || docVariants.has('doc-clean') || docVariants.has('doc-empty')) {
|
|
463
|
+
const proto = Object.getPrototypeOf(document);
|
|
464
|
+
for (const key of ['referrer','documentMode','characterSet','compatMode','body','head','images']) {
|
|
465
|
+
const d = Object.getOwnPropertyDescriptor(document, key);
|
|
466
|
+
if (d) { Object.defineProperty(proto, key, d); delete document[key]; }
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
if (docVariants.has('doc-location') || docVariants.has('doc-clean')) {
|
|
470
|
+
Object.defineProperty(document, 'location', {value:location, enumerable:true, configurable:false, writable:false});
|
|
471
|
+
}
|
|
472
|
+
if (docVariants.has('doc-empty')) {
|
|
473
|
+
try { delete document.cookie; } catch (_) {}
|
|
474
|
+
}
|
|
475
|
+
if (docVariants.has('real-shape')) {
|
|
476
|
+
// Chromium Document exposes most DOM values through its prototype. Keep only
|
|
477
|
+
// the own keys observed in the clean browser probe before acrawler runs.
|
|
478
|
+
const proto = Object.create(Object.prototype);
|
|
479
|
+
for (const key of ['referrer','documentMode','characterSet','compatMode','body','head','images']) {
|
|
480
|
+
const d = Object.getOwnPropertyDescriptor(document, key);
|
|
481
|
+
if (d) { Object.defineProperty(proto, key, d); delete document[key]; }
|
|
482
|
+
}
|
|
483
|
+
defineTag(proto, 'HTMLDocument');
|
|
484
|
+
Object.setPrototypeOf(document, proto);
|
|
485
|
+
Object.defineProperty(document, 'location', {value: location, enumerable:true, configurable:false, writable:false});
|
|
486
|
+
Object.defineProperty(document, 'execCommand', {value: makeNativeFunction('execCommand', 1, () => false), enumerable:true, configurable:true, writable:true});
|
|
487
|
+
if (docVariants.has('react-marker')) Object.defineProperty(document, '_reactListeningt7i2k1m2vkn', {value:true, enumerable:true, configurable:true, writable:true});
|
|
488
|
+
}
|
|
489
|
+
if (docVariants.has('chrome-doc')) {
|
|
490
|
+
// Exact clean-Chromium Document contract observed on the HTTPS parity page:
|
|
491
|
+
// only `location` is an own key; values and DOM methods live on the
|
|
492
|
+
// HTMLDocument prototype and the toStringTag is inherited.
|
|
493
|
+
const proto = Object.create(Object.prototype);
|
|
494
|
+
for (const key of ['referrer','documentMode','characterSet','compatMode',
|
|
495
|
+
'cookie','body','head','images','getElementsByTagName',
|
|
496
|
+
'createElement','createEvent']) {
|
|
497
|
+
const d = Object.getOwnPropertyDescriptor(document, key);
|
|
498
|
+
if (d) { Object.defineProperty(proto, key, d); delete document[key]; }
|
|
499
|
+
}
|
|
500
|
+
defineTag(proto, 'HTMLDocument');
|
|
501
|
+
Object.defineProperty(proto, 'constructor', {
|
|
502
|
+
value: makeNativeConstructor('HTMLDocument', 0),
|
|
503
|
+
writable: true, configurable: true, enumerable: false,
|
|
504
|
+
});
|
|
505
|
+
Object.setPrototypeOf(document, proto);
|
|
506
|
+
if (docVariants.has('doc-location-accessor')) {
|
|
507
|
+
Object.defineProperty(document, 'location', {
|
|
508
|
+
get: makeNativeFunction('get location', 0, () => location),
|
|
509
|
+
set: makeNativeFunction('set location', 1, () => undefined),
|
|
510
|
+
enumerable: true, configurable: false,
|
|
511
|
+
});
|
|
512
|
+
} else {
|
|
513
|
+
Object.defineProperty(document, 'location', {
|
|
514
|
+
value: location, enumerable: true, configurable: false, writable: false,
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
if (docVariants.has('chrome-doc-native-proto')) {
|
|
518
|
+
const p = Object.getPrototypeOf(document);
|
|
519
|
+
const vals = {referrer:'', characterSet:'UTF-8', compatMode:'CSS1Compat', body:document.body, head:document.head, images:document.images};
|
|
520
|
+
for (const [key, value] of Object.entries(vals)) Object.defineProperty(p, key, {get:makeNativeFunction(`get ${key}`,0,()=>value), enumerable:true, configurable:true});
|
|
521
|
+
Object.defineProperty(p, 'documentMode', {get:makeNativeFunction('get documentMode',0,()=>undefined), enumerable:true, configurable:true});
|
|
522
|
+
for (const key of ['getElementsByTagName','createElement','createEvent']) {
|
|
523
|
+
const fn = document[key];
|
|
524
|
+
Object.defineProperty(p, key, {value:makeNativeFunction(key,1, (...args)=>fn.apply(document,args)), writable:true, enumerable:true, configurable:true});
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
if (docVariants.has('doc-location-accessor')) {
|
|
529
|
+
// Chromium's own Document.location descriptor is a non-configurable native
|
|
530
|
+
// accessor (not a data property). This shape is probed by acrawler.
|
|
531
|
+
if (!Object.prototype.hasOwnProperty.call(document, 'location')) {
|
|
532
|
+
Object.defineProperty(document, 'location', {
|
|
533
|
+
get: makeNativeFunction('get location', 0, () => location),
|
|
534
|
+
set: makeNativeFunction('set location', 1, () => undefined),
|
|
535
|
+
enumerable: true, configurable: false,
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
if (docVariants.has('doc-constructor-native')) {
|
|
540
|
+
Object.defineProperty(Object.getPrototypeOf(document), 'constructor', {value:makeNativeConstructor('HTMLDocument', 0), writable:true, configurable:true, enumerable:false});
|
|
541
|
+
}
|
|
542
|
+
if (String(process.env.AC_VARIANT || '').split(',').includes('location-localhost')) {
|
|
543
|
+
location.href = 'http://localhost'; location.protocol = 'http:'; location.host = 'localhost'; location.hostname = 'localhost';
|
|
544
|
+
}
|
|
545
|
+
const performance = {now:()=>0, timing:{navigationStart:1787443280000}};
|
|
546
|
+
if (String(process.env.AC_VARIANT || '').split(',').includes('object-tags')) {
|
|
547
|
+
defineTag(location, 'Location');
|
|
548
|
+
Object.defineProperty(location, Symbol.toPrimitive, {value: makeNativeFunction('toPrimitive', 1, hint => hint === 'string' ? location.href : location.href), configurable:true});
|
|
549
|
+
defineTag(screen, 'Screen');
|
|
550
|
+
defineTag(performance, 'Performance');
|
|
551
|
+
defineTag(sessionStorage, 'Storage');
|
|
552
|
+
defineTag(localStorage, 'Storage');
|
|
553
|
+
}
|
|
554
|
+
const history = {};
|
|
555
|
+
if (!String(process.env.AC_VARIANT || '').split(',').includes('no-histtag')) defineTag(history, 'History');
|
|
556
|
+
const window = {
|
|
557
|
+
document, navigator, location, screen, performance, history, sessionStorage, localStorage,
|
|
558
|
+
innerWidth:2560, outerWidth:2560, innerHeight:1215, outerHeight:1392,
|
|
559
|
+
screenX:0, screenY:0, devicePixelRatio:1, isSecureContext:true,
|
|
560
|
+
addEventListener(){}, removeEventListener(){}, postMessage(){},
|
|
561
|
+
setTimeout, clearTimeout, setInterval, clearInterval,
|
|
562
|
+
};
|
|
563
|
+
if (String(process.env.AC_VARIANT || '').split(',').includes('browser-window-keys-undefined')) {
|
|
564
|
+
try {
|
|
565
|
+
const browserShape = JSON.parse(fs.readFileSync(__dirname + '/browser_window_shape.json', 'utf8'));
|
|
566
|
+
for (const k of browserShape.keys) if (!Object.prototype.hasOwnProperty.call(window, k)) Object.defineProperty(window, k, {value:undefined, writable:true, enumerable:true, configurable:true});
|
|
567
|
+
} catch (_) {}
|
|
568
|
+
}
|
|
569
|
+
if (String(process.env.AC_VARIANT || '').split(',').includes('window-constructor-native')) {
|
|
570
|
+
Object.defineProperty(window, 'constructor', {value:makeNativeConstructor('Window', 0), writable:true, configurable:true, enumerable:false});
|
|
571
|
+
}
|
|
572
|
+
if (String(process.env.AC_VARIANT || '').split(',').includes('window-proto-native')) {
|
|
573
|
+
const wp = Object.create(Object.prototype);
|
|
574
|
+
defineTag(wp, 'Window');
|
|
575
|
+
Object.defineProperty(wp, 'constructor', {value:makeNativeConstructor('Window', 0), writable:true, configurable:true, enumerable:false});
|
|
576
|
+
Object.setPrototypeOf(window, wp);
|
|
577
|
+
}
|
|
578
|
+
const accessTrace = [];
|
|
579
|
+
function traceValue(v) {
|
|
580
|
+
if (v === undefined) return {type:'undefined'};
|
|
581
|
+
if (v === null) return {type:'null'};
|
|
582
|
+
const t = typeof v;
|
|
583
|
+
if (t === 'function') return {type:'function', name:v.name, length:v.length, str:(()=>{try{return String(v).slice(0,120)}catch(_){return '<err>'}})()};
|
|
584
|
+
if (t !== 'object') return {type:t, value:v};
|
|
585
|
+
let tag; try { tag = rawObjectToString.call(v); } catch (_) { tag = '<err>'; }
|
|
586
|
+
let keys; try { keys = Reflect.ownKeys(v).map(String).slice(0,30); } catch (_) { keys = ['<err>']; }
|
|
587
|
+
return {type:'object', tag, keys};
|
|
588
|
+
}
|
|
589
|
+
function traceTop(target, label) {
|
|
590
|
+
if (!process.env.AC_ACCESS_TRACE || !target || (typeof target !== 'object' && typeof target !== 'function')) return target;
|
|
591
|
+
return new Proxy(target, {
|
|
592
|
+
get(t, p, r) {
|
|
593
|
+
if (accessTrace.length < 5000) accessTrace.push({op:'get', label, p:String(p)});
|
|
594
|
+
const value = Reflect.get(t, p, r);
|
|
595
|
+
if (process.env.AC_ACCESS_VALUE_TRACE && accessTrace.length <= 5000) accessTrace[accessTrace.length - 1].value = traceValue(value);
|
|
596
|
+
return value;
|
|
597
|
+
},
|
|
598
|
+
has(t, p) {
|
|
599
|
+
if (accessTrace.length < 5000) accessTrace.push({op:'has', label, p:String(p)});
|
|
600
|
+
const value = Reflect.has(t, p);
|
|
601
|
+
if (process.env.AC_ACCESS_VALUE_TRACE && accessTrace.length <= 5000) accessTrace[accessTrace.length - 1].value = value;
|
|
602
|
+
return value;
|
|
603
|
+
},
|
|
604
|
+
ownKeys(t) {
|
|
605
|
+
if (accessTrace.length < 5000) accessTrace.push({op:'ownKeys', label});
|
|
606
|
+
const value = Reflect.ownKeys(t);
|
|
607
|
+
if (process.env.AC_ACCESS_VALUE_TRACE && accessTrace.length <= 5000) accessTrace[accessTrace.length - 1].value = value.map(String);
|
|
608
|
+
return value;
|
|
609
|
+
},
|
|
610
|
+
getOwnPropertyDescriptor(t, p) {
|
|
611
|
+
if (accessTrace.length < 5000) accessTrace.push({op:'getOwnPropertyDescriptor', label, p:String(p)});
|
|
612
|
+
const value = Reflect.getOwnPropertyDescriptor(t, p);
|
|
613
|
+
if (process.env.AC_ACCESS_VALUE_TRACE && accessTrace.length <= 5000) {
|
|
614
|
+
accessTrace[accessTrace.length - 1].value = value && {configurable:value.configurable, enumerable:value.enumerable, writable:value.writable, hasGet:!!value.get, hasSet:!!value.set, value:traceValue(value.value), get:traceValue(value.get), set:traceValue(value.set)};
|
|
615
|
+
}
|
|
616
|
+
return value;
|
|
617
|
+
},
|
|
618
|
+
getPrototypeOf(t) {
|
|
619
|
+
if (accessTrace.length < 5000) accessTrace.push({op:'getPrototypeOf', label});
|
|
620
|
+
return Reflect.getPrototypeOf(t);
|
|
621
|
+
},
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
const tracedDocument = traceTop(document, 'document');
|
|
625
|
+
const tracedNavigator = traceTop(navigator, 'navigator');
|
|
626
|
+
const tracedLocation = traceTop(location, 'location');
|
|
627
|
+
const tracedHistory = traceTop(history, 'history');
|
|
628
|
+
const tracedScreen = traceTop(screen, 'screen');
|
|
629
|
+
const tracedPerformance = traceTop(performance, 'performance');
|
|
630
|
+
window.document = tracedDocument; window.navigator = tracedNavigator; window.location = tracedLocation;
|
|
631
|
+
window.history = tracedHistory; window.screen = tracedScreen; window.performance = tracedPerformance;
|
|
632
|
+
const tagVariants = new Set(String(process.env.AC_VARIANT || '').split(',').map(s => s.trim()));
|
|
633
|
+
if (!tagVariants.has('no-doctag') && !docVariants.has('chrome-doc')) defineTag(document, 'HTMLDocument');
|
|
634
|
+
if (!tagVariants.has('no-wintag')) defineTag(window, 'Window');
|
|
635
|
+
if (tagVariants.has('doc-tag-proto')) {
|
|
636
|
+
try {
|
|
637
|
+
delete document[Symbol.toStringTag];
|
|
638
|
+
const p = Object.create(Object.getPrototypeOf(document));
|
|
639
|
+
defineTag(p, 'HTMLDocument');
|
|
640
|
+
Object.setPrototypeOf(document, p);
|
|
641
|
+
} catch (_) {}
|
|
642
|
+
}
|
|
643
|
+
if (tagVariants.has('tags-proto')) {
|
|
644
|
+
for (const [obj, tag] of [[document,'HTMLDocument'], [window,'Window'], [history,'History']]) {
|
|
645
|
+
try {
|
|
646
|
+
delete obj[Symbol.toStringTag];
|
|
647
|
+
const proto = Object.create(Object.getPrototypeOf(obj));
|
|
648
|
+
defineTag(proto, tag);
|
|
649
|
+
Object.setPrototypeOf(obj, proto);
|
|
650
|
+
} catch (_) {}
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
if (tagVariants.has('doc-own-shape')) {
|
|
654
|
+
// Chrome's Document instance has only four own string properties in the
|
|
655
|
+
// captured target page. The rest of the small DOM surface is inherited
|
|
656
|
+
// from Document/Node prototypes. Rebuild that shape so Reflect.ownKeys /
|
|
657
|
+
// getOwnPropertyDescriptor observe the same contract.
|
|
658
|
+
try {
|
|
659
|
+
const proto = Object.create(Object.prototype);
|
|
660
|
+
const moved = ['referrer','documentMode','characterSet','compatMode','body','head','images','getElementsByTagName','createElement','createEvent'];
|
|
661
|
+
for (const key of moved) {
|
|
662
|
+
const d = Object.getOwnPropertyDescriptor(document, key);
|
|
663
|
+
if (d) {
|
|
664
|
+
try { delete document[key]; } catch (_) {}
|
|
665
|
+
Object.defineProperty(proto, key, {value:d.value, writable:true, enumerable:false, configurable:true});
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
try { delete document[Symbol.toStringTag]; } catch (_) {}
|
|
669
|
+
defineTag(proto, 'HTMLDocument');
|
|
670
|
+
Object.defineProperty(proto, 'constructor', {value:makeNativeConstructor('HTMLDocument', 0), writable:true, enumerable:false, configurable:true});
|
|
671
|
+
Object.setPrototypeOf(document, proto);
|
|
672
|
+
try { delete document.cookie; } catch (_) {}
|
|
673
|
+
Object.defineProperty(document, 'location', {
|
|
674
|
+
get: makeNativeFunction('get location', 0, () => location),
|
|
675
|
+
set: makeNativeFunction('set location', 1, () => undefined),
|
|
676
|
+
enumerable: true, configurable: false,
|
|
677
|
+
});
|
|
678
|
+
Object.defineProperty(document, 'cookie', {
|
|
679
|
+
get: makeNativeFunction('get cookie', 0, () => Object.entries(cookieStore).map(([k,v]) => `${k}=${v}`).join('; ')),
|
|
680
|
+
set: makeNativeFunction('set cookie', 1, (v) => {
|
|
681
|
+
const first = String(v).split(';', 1)[0]; const i = first.indexOf('='); if (i < 0) return;
|
|
682
|
+
const k = first.slice(0, i).trim(); const val = first.slice(i + 1);
|
|
683
|
+
if (/expires=Mon, 20 Sep 2010|expires=Thu, 01-Jan-1970/i.test(v)) delete cookieStore[k]; else cookieStore[k] = val;
|
|
684
|
+
}),
|
|
685
|
+
enumerable: false, configurable: false,
|
|
686
|
+
});
|
|
687
|
+
Object.defineProperty(document, 'execCommand', {value:makeNativeFunction('execCommand', 3, () => true), writable:true, enumerable:true, configurable:true});
|
|
688
|
+
Object.defineProperty(document, process.env.AC_REACT_KEY || '_reactListeningt7i2k1m2vkn', {value:true, writable:true, enumerable:true, configurable:true});
|
|
689
|
+
if (tagVariants.has('doc-createElement-own')) {
|
|
690
|
+
const fn = proto.createElement;
|
|
691
|
+
Object.defineProperty(document, 'createElement', {value:fn, writable:true, enumerable:true, configurable:true});
|
|
692
|
+
}
|
|
693
|
+
} catch (_) {}
|
|
694
|
+
}
|
|
695
|
+
window.byted_acrawler = {};
|
|
696
|
+
window.window=window; window.self=window; window.top=window; window.parent=window; window.globalThis=window;
|
|
697
|
+
const ctx = window;
|
|
698
|
+
const fixedNow = Number(process.env.AC_NOW || 0);
|
|
699
|
+
if (fixedNow) {
|
|
700
|
+
const RealDate = Date;
|
|
701
|
+
class FixedDate extends RealDate {
|
|
702
|
+
constructor(...args){ super(...(args.length ? args : [fixedNow])); }
|
|
703
|
+
static now(){ return fixedNow; }
|
|
704
|
+
}
|
|
705
|
+
window.Date = FixedDate;
|
|
706
|
+
}
|
|
707
|
+
let vmMath = Math;
|
|
708
|
+
let randomCalls = 0;
|
|
709
|
+
if (process.env.AC_RANDOMS) {
|
|
710
|
+
const randomSequence = JSON.parse(process.env.AC_RANDOMS);
|
|
711
|
+
let randomIndex = 0;
|
|
712
|
+
vmMath = Object.create(Math);
|
|
713
|
+
vmMath.random = () => { randomCalls++; return randomIndex < randomSequence.length ? randomSequence[randomIndex++] : 0.5; };
|
|
714
|
+
}
|
|
715
|
+
const jsonTrace = [];
|
|
716
|
+
const methodTrace = [];
|
|
717
|
+
const detectTrace = [];
|
|
718
|
+
if (process.env.AC_JSON_TRACE) {
|
|
719
|
+
const realStringify = JSON.stringify;
|
|
720
|
+
JSON.stringify = function(value, replacer, space) {
|
|
721
|
+
if (jsonTrace.length < 500) {
|
|
722
|
+
let safe;
|
|
723
|
+
try {
|
|
724
|
+
const raw = realStringify(value);
|
|
725
|
+
safe = raw.length > 20000 ? {type: typeof value, len: raw.length, head: raw.slice(0, 1000), tail: raw.slice(-1000)} : JSON.parse(raw);
|
|
726
|
+
} catch (_) {
|
|
727
|
+
safe = {type: typeof value};
|
|
728
|
+
}
|
|
729
|
+
jsonTrace.push(safe);
|
|
730
|
+
}
|
|
731
|
+
return realStringify.call(this, value, replacer, space);
|
|
732
|
+
};
|
|
733
|
+
}
|
|
734
|
+
Object.assign(ctx, {
|
|
735
|
+
window, document:tracedDocument, navigator:tracedNavigator, location:tracedLocation,
|
|
736
|
+
screen:tracedScreen, performance:tracedPerformance, history:tracedHistory,
|
|
737
|
+
sessionStorage, localStorage, console, setTimeout, clearTimeout, setInterval, clearInterval,
|
|
738
|
+
Object, Function, Reflect, Proxy, Date:window.Date, Math:vmMath, String, Array, Error, TypeError, JSON, Promise,
|
|
739
|
+
RegExp, parseInt, Image:function(){}, PluginArray:function(){}, TouchEvent:function(){}, DOMException:function(){},
|
|
740
|
+
HTMLElement: makeNativeConstructor('HTMLElement', 0),
|
|
741
|
+
indexedDB: {}, history, WebSocket:function(){}, Request:function(){}, Headers:function(){},
|
|
742
|
+
encodeURIComponent, encodeURI, decodeURIComponent, eval,
|
|
743
|
+
});
|
|
744
|
+
// Chromium's navigator.plugins is a genuine PluginArray instance. Keeping
|
|
745
|
+
// only the [object PluginArray] tag is insufficient: acrawler also evaluates
|
|
746
|
+
// `navigator.plugins instanceof PluginArray`; a false result sets its
|
|
747
|
+
// phantom-browser detector bit and changes byte 28 (plus the final checksum)
|
|
748
|
+
// of the signature.
|
|
749
|
+
{
|
|
750
|
+
const PluginArrayCtor = makeNativeConstructor('PluginArray', 0);
|
|
751
|
+
try { PluginArrayCtor.prototype = Object.getPrototypeOf(plugins); } catch (_) {}
|
|
752
|
+
try { Object.defineProperty(Object.getPrototypeOf(plugins), 'constructor', {value:PluginArrayCtor, writable:true, configurable:true, enumerable:false}); } catch (_) {}
|
|
753
|
+
ctx.PluginArray = PluginArrayCtor;
|
|
754
|
+
window.PluginArray = PluginArrayCtor;
|
|
755
|
+
}
|
|
756
|
+
if (process.env.AC_METHOD_TRACE) {
|
|
757
|
+
const realKeys = Object.keys;
|
|
758
|
+
const realOwnNames = Object.getOwnPropertyNames;
|
|
759
|
+
const realOwnDesc = Object.getOwnPropertyDescriptor;
|
|
760
|
+
const realToString = rawObjectToString;
|
|
761
|
+
const logMethod = (name, args, value) => {
|
|
762
|
+
if (methodTrace.length < 2000) methodTrace.push({name, args:args.map(traceValue), value: name === 'toString' ? value : (Array.isArray(value) ? value.map(String) : traceValue(value))});
|
|
763
|
+
};
|
|
764
|
+
Object.keys = function(o){ let v = realKeys(o); const vset=String(process.env.AC_VARIANT || '').split(','); if (vset.includes('keys-browser-window') || vset.includes('keys-runner-window')) { try { const tag = rawObjectToString.call(o); if (tag === '[object Window]') v = vset.includes('keys-runner-window') ? fs.readFileSync(__dirname + '/runner_window_keys_baseline.txt','utf8').split(/\r?\n/).filter(Boolean) : JSON.parse(fs.readFileSync(__dirname + '/browser_window_shape.json','utf8')).keys.slice(); } catch (_) {} } if (process.env.AC_DETECT_TRACE && v.join(',') === 'directSign,consistent,location,switch,dom,debugger,node,phantom,webdriver,incognito,hook,test') { const row={}; for (const k of v) { try { const x=o[k]; row[k]=(typeof x === 'boolean' || typeof x === 'number' || typeof x === 'string' || x == null) ? x : {type:typeof x, tag:rawObjectToString.call(x)}; } catch (e) { row[k]={error:String(e)}; } } detectTrace.push(row); } logMethod('keys',[o],v); return v; };
|
|
765
|
+
Object.getOwnPropertyNames = function(o){ const v = realOwnNames(o); logMethod('getOwnPropertyNames',[o],v); return v; };
|
|
766
|
+
Object.getOwnPropertyDescriptor = function(o,p){ const v = realOwnDesc(o,p); logMethod('getOwnPropertyDescriptor',[o,p],v); return v; };
|
|
767
|
+
Object.prototype.toString = function(){ const v = realToString.call(this); logMethod('toString',[this],v); return v; };
|
|
768
|
+
}
|
|
769
|
+
if (!process.env.AC_METHOD_TRACE && String(process.env.AC_VARIANT || '').split(',').some(v => v === 'keys-browser-window' || v === 'keys-runner-window')) {
|
|
770
|
+
const realKeysOnly = Object.keys;
|
|
771
|
+
Object.keys = function(o) {
|
|
772
|
+
let v = realKeysOnly(o);
|
|
773
|
+
try {
|
|
774
|
+
if (rawObjectToString.call(o) === '[object Window]' || v.length > 20) {
|
|
775
|
+
const vset = String(process.env.AC_VARIANT || '').split(',');
|
|
776
|
+
v = vset.includes('keys-runner-window') ? fs.readFileSync(__dirname + '/runner_window_keys_baseline.txt','utf8').split(/\r?\n/).filter(Boolean) : JSON.parse(fs.readFileSync(__dirname + '/browser_window_shape.json','utf8')).keys.slice();
|
|
777
|
+
}
|
|
778
|
+
} catch (_) {}
|
|
779
|
+
return v;
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
if (process.env.AC_KEYS_ONLY_TRACE) {
|
|
783
|
+
const realKeysOnlyTrace = Object.keys;
|
|
784
|
+
globalThis.__keysOnlyTrace = [];
|
|
785
|
+
Object.keys = function(o) {
|
|
786
|
+
const v = realKeysOnlyTrace(o);
|
|
787
|
+
try { globalThis.__keysOnlyTrace.push({len:v.length, tag:rawObjectToString.call(o), head:v.slice(0,5)}); } catch (_) {}
|
|
788
|
+
return v;
|
|
789
|
+
};
|
|
790
|
+
}
|
|
791
|
+
const globalTrace = [];
|
|
792
|
+
if (process.env.AC_GLOBAL_TRACE) {
|
|
793
|
+
const probeGlobals = [
|
|
794
|
+
'process','phantom','callPhantom','_phantom','__nightmare','InstallTrigger','safari',
|
|
795
|
+
'Audio','AudioContext','OfflineAudioContext','MediaRecorder','MediaSource','speechSynthesis',
|
|
796
|
+
'Notification','PointerEvent','MSPointerEvent','TouchEvent','CanvasRenderingContext2D',
|
|
797
|
+
'RTCPeerConnection','mozRTCPeerConnection','webkitRTCPeerConnection','BluetoothUUID',
|
|
798
|
+
'webkitRequestAnimationFrame','Request','Headers','WebSocket','fetch','XMLHttpRequest',
|
|
799
|
+
'CSS','CSSRuleList','CSSStyleSheet','FontFace','SVGElement','OffscreenCanvas','WebGL2RenderingContext',
|
|
800
|
+
'MutationObserver','ResizeObserver','IntersectionObserver','getComputedStyle','indexedDB',
|
|
801
|
+
'chrome','external','toolbar','locationbar','webkitStorageInfo','openDatabase','crypto',
|
|
802
|
+
'structuredClone','BigInt','Intl',
|
|
803
|
+
];
|
|
804
|
+
for (const name of probeGlobals) {
|
|
805
|
+
try {
|
|
806
|
+
const had = Object.prototype.hasOwnProperty.call(ctx, name);
|
|
807
|
+
const original = had ? ctx[name] : undefined;
|
|
808
|
+
Object.defineProperty(ctx, name, {configurable:true, enumerable:false, get(){ globalTrace.push({name, present:had, type:typeof original}); return original; }});
|
|
809
|
+
} catch (_) {}
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
if (String(process.env.AC_VARIANT || '').split(',').includes('dom-constructors')) {
|
|
813
|
+
ctx.Document = makeNativeConstructor('Document', 0);
|
|
814
|
+
ctx.HTMLDocument = makeNativeConstructor('HTMLDocument', 0);
|
|
815
|
+
ctx.Navigator = makeNativeConstructor('Navigator', 0);
|
|
816
|
+
}
|
|
817
|
+
if (String(process.env.AC_VARIANT || '').split(',').includes('native-constructor-globals')) {
|
|
818
|
+
for (const name of ['Image','PluginArray','TouchEvent','DOMException','WebSocket','Request','Headers','HTMLElement','Document','HTMLDocument','Navigator']) {
|
|
819
|
+
if (Object.prototype.hasOwnProperty.call(ctx, name)) ctx[name] = makeNativeConstructor(name, 0);
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
const variants = new Set(String(process.env.AC_VARIANT || '').split(',').map(s => s.trim()).filter(Boolean));
|
|
823
|
+
if (variants.has('no-bit-env')) delete cookieStore.bit_env;
|
|
824
|
+
if (variants.has('no-uifid')) delete cookieStore.UIFID_TEMP;
|
|
825
|
+
if (variants.has('no-ac-nonce')) delete cookieStore.__ac_nonce;
|
|
826
|
+
if (variants.has('no-touch-global')) delete ctx.TouchEvent;
|
|
827
|
+
if (variants.has('globals')) {
|
|
828
|
+
Object.assign(ctx, {
|
|
829
|
+
HTMLElement:function HTMLElement(){}, CanvasRenderingContext2D:function CanvasRenderingContext2D(){},
|
|
830
|
+
PointerEvent:function PointerEvent(){}, Audio:function Audio(){},
|
|
831
|
+
RTCPeerConnection:function RTCPeerConnection(){}, webkitRTCPeerConnection:function webkitRTCPeerConnection(){},
|
|
832
|
+
BluetoothUUID:function BluetoothUUID(){}, webkitRequestAnimationFrame:function webkitRequestAnimationFrame(){},
|
|
833
|
+
chrome: {runtime:{connect(){}}}, external: defineTag({}, 'External'),
|
|
834
|
+
toolbar: defineTag({}, 'BarProp'), locationbar: defineTag({}, 'BarProp'),
|
|
835
|
+
});
|
|
836
|
+
}
|
|
837
|
+
const globalVariants = {
|
|
838
|
+
'g-HTMLElement': ['HTMLElement', makeNativeConstructor('HTMLElement', 0)],
|
|
839
|
+
'g-CanvasRenderingContext2D': ['CanvasRenderingContext2D', makeNativeConstructor('CanvasRenderingContext2D', 0)],
|
|
840
|
+
'g-PointerEvent': ['PointerEvent', makeNativeConstructor('PointerEvent', 0)],
|
|
841
|
+
'g-Audio': ['Audio', makeNativeConstructor('Audio', 0)],
|
|
842
|
+
'g-RTCPeerConnection': ['RTCPeerConnection', makeNativeConstructor('RTCPeerConnection', 0)],
|
|
843
|
+
'g-webkitRTCPeerConnection': ['webkitRTCPeerConnection', makeNativeConstructor('webkitRTCPeerConnection', 0)],
|
|
844
|
+
'g-BluetoothUUID': ['BluetoothUUID', makeNativeConstructor('BluetoothUUID', 0)],
|
|
845
|
+
'g-webkitRequestAnimationFrame': ['webkitRequestAnimationFrame', makeNativeConstructor('webkitRequestAnimationFrame', 0)],
|
|
846
|
+
'g-chrome': ['chrome', {runtime:{connect(){}}}],
|
|
847
|
+
'g-external': ['external', defineTag({}, 'External')],
|
|
848
|
+
'g-toolbar': ['toolbar', defineTag({}, 'BarProp')],
|
|
849
|
+
'g-locationbar': ['locationbar', defineTag({}, 'BarProp')],
|
|
850
|
+
'g-InstallTrigger': ['InstallTrigger', {}],
|
|
851
|
+
'g-safari': ['safari', {}],
|
|
852
|
+
'g-phantom': ['phantom', {}],
|
|
853
|
+
'g-callPhantom': ['callPhantom', function(){}],
|
|
854
|
+
'g-domAutomation': ['domAutomation', {}],
|
|
855
|
+
'g-domAutomationController': ['domAutomationController', {}],
|
|
856
|
+
'g-webdriver': ['webdriver', true],
|
|
857
|
+
'g-process': ['process', {}],
|
|
858
|
+
'g-define': ['define', function(){}],
|
|
859
|
+
'g-module': ['module', {}],
|
|
860
|
+
'g-exports': ['exports', {}],
|
|
861
|
+
'g-require': ['require', function(){}],
|
|
862
|
+
};
|
|
863
|
+
for (const [flag, pair] of Object.entries(globalVariants)) if (variants.has(flag)) ctx[pair[0]] = pair[1];
|
|
864
|
+
if (variants.has('chrome-empty')) ctx.chrome = {};
|
|
865
|
+
if (variants.has('chrome-runtime-empty')) ctx.chrome = {runtime:{}};
|
|
866
|
+
if (variants.has('chrome-runtime-connect')) ctx.chrome = {runtime:{connect(){}}};
|
|
867
|
+
if (variants.has('chrome-rich')) ctx.chrome = {runtime:{connect(){},sendMessage(){}},loadTimes(){},csi(){},app:{isInstalled:false}};
|
|
868
|
+
if (variants.has('chrome-real')) ctx.chrome = {loadTimes:makeNativeFunction('loadTimes', 0, () => ({})), csi:makeNativeFunction('csi', 0, () => ({})), app:{}};
|
|
869
|
+
if (variants.has('browser-global-shape')) {
|
|
870
|
+
const ctorNames = ['Audio','AudioContext','OfflineAudioContext','MediaRecorder','MediaSource','Notification','PointerEvent','TouchEvent','CanvasRenderingContext2D','RTCPeerConnection','webkitRTCPeerConnection','BluetoothUUID','webkitRequestAnimationFrame','Request','Headers','WebSocket','fetch','XMLHttpRequest','CSSRuleList','CSSStyleSheet','FontFace','SVGElement','OffscreenCanvas','WebGL2RenderingContext','MutationObserver','ResizeObserver','IntersectionObserver','getComputedStyle','structuredClone','BigInt'];
|
|
871
|
+
for (const name of ctorNames) if (!(name in ctx)) ctx[name] = makeNativeConstructor(name, 0);
|
|
872
|
+
ctx.speechSynthesis = defineTag({}, 'SpeechSynthesis');
|
|
873
|
+
ctx.CSS = defineTag({highlights:{},Hz:1,Q:1,cap:1,ch:1,cm:1,cqb:1,cqh:1,cqi:1,cqmax:1,cqmin:1,cqw:1,deg:1}, 'CSS');
|
|
874
|
+
ctx.indexedDB = defineTag({}, 'IDBFactory');
|
|
875
|
+
ctx.chrome = {loadTimes:makeNativeFunction('loadTimes', 0, () => ({})), csi:makeNativeFunction('csi', 0, () => ({})), app:{}};
|
|
876
|
+
ctx.external = defineTag({}, 'External');
|
|
877
|
+
ctx.toolbar = defineTag({}, 'BarProp');
|
|
878
|
+
ctx.locationbar = defineTag({}, 'BarProp');
|
|
879
|
+
ctx.crypto = defineTag({}, 'Crypto');
|
|
880
|
+
ctx.Intl = defineTag({}, 'Intl');
|
|
881
|
+
}
|
|
882
|
+
ctx.global = ctx; ctx.globalThis = ctx;
|
|
883
|
+
vm.createContext(ctx);
|
|
884
|
+
if (String(process.env.AC_VARIANT || '').split(',').includes('hide-global')) {
|
|
885
|
+
// A page realm has no Node `global` binding. Remove the compatibility alias
|
|
886
|
+
// only after vm context creation (the ordinary runner installs it for
|
|
887
|
+
// diagnostics), immediately before evaluating the VMP.
|
|
888
|
+
try { delete ctx.global; vm.runInContext('try { delete globalThis.global; } catch (_) {}', ctx, {timeout:5000}); } catch (_) {}
|
|
889
|
+
}
|
|
890
|
+
let vmKeysTraceRef = null;
|
|
891
|
+
if (String(process.env.AC_VARIANT || '').split(',').some(v => v === 'vm-keys-browser-window' || v === 'vm-keys-one' || v === 'vm-keys-trace')) {
|
|
892
|
+
try {
|
|
893
|
+
const keyFile = String(process.env.AC_VARIANT || '').split(',').includes('vm-keys-runner-window') ? 'runner_window_keys_baseline.txt' : 'browser_window_shape.json';
|
|
894
|
+
const browserKeys = keyFile.endsWith('.json') ? JSON.parse(fs.readFileSync(__dirname + '/' + keyFile, 'utf8')).keys : fs.readFileSync(__dirname + '/' + keyFile, 'utf8').split(/\r?\n/).filter(Boolean);
|
|
895
|
+
ctx.__acBrowserKeys = browserKeys;
|
|
896
|
+
const vmKeysTraceOuter = []; vmKeysTraceRef = vmKeysTraceOuter;
|
|
897
|
+
ctx.__vmKeysTraceOuter = vmKeysTraceOuter;
|
|
898
|
+
vm.runInContext(`(() => { const real = Object.keys; const keys = __acBrowserKeys; const trace = __vmKeysTraceOuter; Object.keys = new Proxy(real, { apply(target, thisArg, args) { const v = Reflect.apply(target, thisArg, args); try { trace.push({len:v.length, head:v.slice(0,8), tag:Object.prototype.toString.call(args[0])}); } catch (_) {} return ${String(process.env.AC_VARIANT || '').split(',').includes('vm-keys-one') ? '["X"]' : (String(process.env.AC_VARIANT || '').split(',').includes('vm-keys-trace') ? 'v' : '(v.length > 20 ? keys.slice() : v)')}; } }); })()`, ctx, {timeout:5000});
|
|
899
|
+
ctx.__vmKeysTraceOuterRef = vmKeysTraceOuter;
|
|
900
|
+
} catch (_) {}
|
|
901
|
+
}
|
|
902
|
+
if (String(process.env.AC_VARIANT || '').split(',').includes('vm-global-window')) {
|
|
903
|
+
// In a real browser, window/globalThis/self/top/parent are the same global
|
|
904
|
+
// object. Node's vm context otherwise exposes a distinct context global.
|
|
905
|
+
vm.runInContext('globalThis.window=globalThis; globalThis.self=globalThis; globalThis.top=globalThis; globalThis.parent=globalThis; globalThis.globalThis=globalThis; globalThis.global=globalThis;', ctx);
|
|
906
|
+
}
|
|
907
|
+
if (String(process.env.AC_VARIANT || '').split(',').includes('no-global')) delete ctx.global;
|
|
908
|
+
if (String(process.env.AC_VARIANT || '').split(',').includes('realm-nav')) {
|
|
909
|
+
ctx.__hostNav = ctx.navigator;
|
|
910
|
+
const realmNav = vm.runInContext(`(() => {
|
|
911
|
+
const host = __hostNav;
|
|
912
|
+
const p = Object.create(Object.prototype);
|
|
913
|
+
for (const k of ['userAgent','platform','webdriver','plugins','hardwareConcurrency','deviceMemory','maxTouchPoints','language','languages','vendor','vendorSub','appCodeName','appName','product']) {
|
|
914
|
+
Object.defineProperty(p, k, {value: host[k], writable:true, configurable:true, enumerable:false});
|
|
915
|
+
}
|
|
916
|
+
Object.defineProperty(p, Symbol.toStringTag, {value:'Navigator', configurable:true});
|
|
917
|
+
const n = Object.create(p); n.pemrissions = {microphone:'granted'}; return n;
|
|
918
|
+
})()`, ctx);
|
|
919
|
+
ctx.navigator = realmNav;
|
|
920
|
+
ctx.window.navigator = realmNav;
|
|
921
|
+
delete ctx.__hostNav;
|
|
922
|
+
}
|
|
923
|
+
try {
|
|
924
|
+
const vmTrace = [];
|
|
925
|
+
ctx.__acVmTrace = vmTrace;
|
|
926
|
+
if (process.env.AC_CONSTRUCTOR_TRACE) {
|
|
927
|
+
ctx.__acCtorTrace = [];
|
|
928
|
+
ctx.__acTraceCtor = function(value, index) {
|
|
929
|
+
try {
|
|
930
|
+
ctx.__acCtorTrace.push({index, type:typeof value,
|
|
931
|
+
tag: rawObjectToString.call(value),
|
|
932
|
+
name: value && value.name,
|
|
933
|
+
str: String(value).slice(0,120)});
|
|
934
|
+
} catch (_) { ctx.__acCtorTrace.push({index, type:typeof value}); }
|
|
935
|
+
return value;
|
|
936
|
+
};
|
|
937
|
+
}
|
|
938
|
+
// Production bootstrap can pass the exact VMP chunk returned by the page.
|
|
939
|
+
// Keep the historical fixture as the fallback for offline parity tests.
|
|
940
|
+
const acVmFile = process.env.AC_VM_FILE || (__dirname + '/ac_vm.js');
|
|
941
|
+
let acSource = fs.readFileSync(acVmFile,'utf8');
|
|
942
|
+
if (process.env.AC_CONSTRUCTOR_TRACE) {
|
|
943
|
+
// The VMP's constructor opcode is emitted as ``new S[R]``. Wrap the
|
|
944
|
+
// selected stack value to identify the missing realm constructor without
|
|
945
|
+
// changing normal execution semantics.
|
|
946
|
+
acSource = acSource.replace(/new S\[R\]/g, 'new (__acTraceCtor(S[R], R))');
|
|
947
|
+
}
|
|
948
|
+
// The VMP file invokes _$jsvmprt in the same expression that defines it.
|
|
949
|
+
// Wrap that initial invocation before evaluation so its detector result is
|
|
950
|
+
// observable instead of inferring it from the final signature only.
|
|
951
|
+
if (process.env.AC_VM_TRACE) {
|
|
952
|
+
const marker = '}},(glb=';
|
|
953
|
+
const at = acSource.lastIndexOf(marker);
|
|
954
|
+
if (at >= 0) {
|
|
955
|
+
const injected = `}}; (function(){ const __acOrigVm = window._$jsvmprt; window._$jsvmprt = function(){ let __acOut; try { __acOut = __acOrigVm.apply(this, arguments); } catch (__acErr) { window.__acVmTrace.push({error:String(__acErr)}); throw __acErr; } try { window.__acVmTrace.push({out:JSON.parse(JSON.stringify(__acOut))}); } catch (_) { window.__acVmTrace.push({outType:typeof __acOut}); } return __acOut; }; })(); (glb=`;
|
|
956
|
+
acSource = acSource.slice(0, at) + injected + acSource.slice(at + marker.length);
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
vm.runInContext(acSource, ctx, {filename:'ac_vm.js', timeout:5000});
|
|
960
|
+
if (String(process.env.AC_VARIANT || '').split(',').includes('delete-glb-after-load')) {
|
|
961
|
+
// In Chrome the classic-site bundle's `var glb` is scoped away; this local
|
|
962
|
+
// standalone copy otherwise leaves an enumerable window.glb behind.
|
|
963
|
+
try { vm.runInContext('delete globalThis.glb; delete window.glb;', ctx, {timeout:5000}); } catch (_) {}
|
|
964
|
+
}
|
|
965
|
+
if (String(process.env.AC_VARIANT || '').split(',').includes('reorder-window-keys')) {
|
|
966
|
+
try {
|
|
967
|
+
const browserShape = JSON.parse(fs.readFileSync(__dirname + '/browser_window_shape.json', 'utf8'));
|
|
968
|
+
const code = `(function(){globalThis.window=globalThis; globalThis.self=globalThis; globalThis.top=globalThis; globalThis.parent=globalThis; globalThis.globalThis=globalThis; globalThis.global=globalThis; const order=${JSON.stringify(browserShape.keys)}; const keys=Reflect.ownKeys(globalThis).map(String); const desc={}; for(const k of keys){try{desc[k]=Object.getOwnPropertyDescriptor(globalThis,k)}catch(_){}} for(const k of order){if(!Object.prototype.hasOwnProperty.call(desc,k)) desc[k]={value:undefined,writable:true,enumerable:true,configurable:true}} const enumKeys=keys.filter(k=>desc[k]?.enumerable); const all=[...order,...enumKeys.filter(k=>!order.includes(k))]; const keep=new Set('Object Function Array Number parseFloat parseInt Infinity NaN undefined Boolean String Symbol Date Promise RegExp Error AggregateError EvalError RangeError ReferenceError SyntaxError TypeError URIError globalThis JSON Math Intl ArrayBuffer Atomics Uint8Array Int8Array Uint16Array Int16Array Uint32Array Int32Array Float32Array Float64Array Uint8ClampedArray BigUint64Array BigInt64Array DataView Map BigInt Set WeakMap WeakSet Proxy Reflect FinalizationRegistry WeakRef decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape eval isFinite isNaN console'.split(' ')); for(const k of all){try{if(desc[k]?.enumerable && desc[k]?.configurable && !keep.has(k) && !['window','self','top','parent','globalThis','global'].includes(k)) delete globalThis[k]}catch(_){}} for(const k of all){const d=desc[k]; if(!d || !d.enumerable || keep.has(k)) continue; try{Object.defineProperty(globalThis,k,d)}catch(_){}} })()`;
|
|
969
|
+
vm.runInContext(code, ctx, {timeout:5000});
|
|
970
|
+
} catch (_) {}
|
|
971
|
+
}
|
|
972
|
+
const out = vm.runInContext(`({same:this===window, vm:typeof window._$jsvmprt, keys:Object.keys(window.byted_acrawler||{}), globalKeys:Object.keys(globalThis).filter(k=>/ac|webrt|byte/i.test(k)), vmGlobalSame:(globalThis===window), vmGlobalTag:Object.prototype.toString.call(globalThis), vmWindowKeys:Object.keys(window).slice(0,200), vmGlobalKeys:Object.keys(globalThis).slice(0,200), cookie:document.cookie, sig:(window.byted_acrawler&&window.byted_acrawler.sign)?window.byted_acrawler.sign('', '${signNonce}') : null, sig2:(window.byted_acrawler&&window.byted_acrawler.sign)?window.byted_acrawler.sign('', '${signNonce}') : null})`, ctx, {timeout:5000});
|
|
973
|
+
if (process.env.AC_TRACE) out.functionTrace = functionTrace;
|
|
974
|
+
if (process.env.AC_ACCESS_TRACE) out.accessTrace = accessTrace;
|
|
975
|
+
if (process.env.AC_VM_TRACE) out.vmTrace = vmTrace;
|
|
976
|
+
if (process.env.AC_TRACE) out.randomCalls = randomCalls;
|
|
977
|
+
if (process.env.AC_JSON_TRACE) out.jsonTrace = jsonTrace;
|
|
978
|
+
if (process.env.AC_METHOD_TRACE) out.methodTrace = methodTrace;
|
|
979
|
+
if (process.env.AC_DETECT_TRACE) out.detectTrace = detectTrace;
|
|
980
|
+
if (process.env.AC_GLOBAL_TRACE) out.globalTrace = globalTrace;
|
|
981
|
+
if (process.env.AC_KEYS_ONLY_TRACE) out.keysOnlyTrace = vm.runInContext('globalThis.__keysOnlyTrace || []', ctx, {timeout:5000});
|
|
982
|
+
if (process.env.AC_CONSTRUCTOR_TRACE) out.constructorTrace = ctx.__acCtorTrace || [];
|
|
983
|
+
if (String(process.env.AC_VARIANT || '').split(',').includes('vm-keys-trace')) out.vmKeysTrace = vmKeysTraceRef || [];
|
|
984
|
+
if (process.env.AC_SHAPE_TRACE) out.shapes = {
|
|
985
|
+
windowOwn: Reflect.ownKeys(window).map(String),
|
|
986
|
+
globalThisSameWindow: globalThis === window,
|
|
987
|
+
globalSameWindow: typeof global !== 'undefined' && global === window,
|
|
988
|
+
globalThisTag: Object.prototype.toString.call(globalThis),
|
|
989
|
+
globalTag: typeof global !== 'undefined' ? Object.prototype.toString.call(global) : 'undefined',
|
|
990
|
+
globalThisOwn: Reflect.ownKeys(globalThis).map(String).slice(0,200),
|
|
991
|
+
docOwn: Reflect.ownKeys(document).map(String),
|
|
992
|
+
navOwn: Reflect.ownKeys(navigator).map(String),
|
|
993
|
+
docTag: Object.prototype.toString.call(document),
|
|
994
|
+
navTag: Object.prototype.toString.call(navigator),
|
|
995
|
+
docCtor: document.constructor && String(document.constructor).slice(0,120),
|
|
996
|
+
navCtor: navigator.constructor && String(navigator.constructor).slice(0,120),
|
|
997
|
+
};
|
|
998
|
+
console.log(JSON.stringify(out));
|
|
999
|
+
} catch (e) {
|
|
1000
|
+
if (process.env.AC_CONSTRUCTOR_TRACE) {
|
|
1001
|
+
try { console.error('CONSTRUCTOR_TRACE', JSON.stringify(ctx.__acCtorTrace || [])); } catch (_) {}
|
|
1002
|
+
}
|
|
1003
|
+
console.error(e && e.stack || e);
|
|
1004
|
+
process.exitCode=1;
|
|
1005
|
+
}
|