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,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"capturedAt": "2026-09-26",
|
|
3
|
+
"source": "Chrome login shell /i/flow/login + current ondemand.s.fb6d53755aa5bd29a.js",
|
|
4
|
+
"key": "nHnf0az57nJeg3cryUhHijcrB07vzlQdJOY8jH0haiX1tcMeA4lEFbpO5I/mtsvn",
|
|
5
|
+
"indices": [13, 47, 26, 28],
|
|
6
|
+
"frames": [
|
|
7
|
+
"M 10,30 C 111,41 250,128 186,124 h 71 s 131,3 208,224 C 26,116 105,178 43,4 h 29 s 94,194 28,138 C 2,244 164,17 184,125 h 87 s 193,55 183,201 C 47,41 12,11 136,5 h 165 s 140,76 39,208 C 225,225 159,195 162,98 h 164 s 120,248 14,32 C 143,127 170,89 48,57 h 106 s 86,61 168,105 C 136,37 57,58 166,96 h 136 s 46,53 168,15 C 144,49 66,198 155,213 h 130 s 204,146 41,30 C 61,171 34,167 183,101 h 58 s 60,34 159,117 C 188,193 80,201 123,29 h 153 s 50,255 13,204 C 242,115 68,210 240,114 h 165 s 36,203 161,198 C 207,23 226,44 173,191 h 152 s 208,79 44,138 C 76,202 39,234 164,247 h 241 s 203,27 91,102 C 40,74 44,152 29,101 h 169 s 40,212 120,109 C 231,126 122,182 16,194 h 98 s 158,65 98,58 C 26,184 135,19 9,5 h 30 s 23,22 7,212",
|
|
8
|
+
"M 10,30 C 25,198 215,229 77,67 h 14 s 220,12 50,245 C 100,209 222,20 116,6 h 122 s 152,242 242,72 C 154,110 132,84 14,0 h 189 s 206,99 34,63 C 112,172 57,224 25,38 h 141 s 154,25 233,35 C 160,238 122,74 210,37 h 171 s 102,249 42,230 C 17,194 120,49 27,35 h 190 s 223,53 216,192 C 78,48 131,237 172,188 h 34 s 103,193 219,55 C 163,181 51,182 214,188 h 58 s 228,131 188,168 C 131,30 131,109 224,230 h 148 s 228,13 127,46 C 129,120 92,36 200,55 h 109 s 24,181 177,92 C 121,21 73,96 90,48 h 91 s 185,0 30,54 C 181,128 69,219 247,64 h 232 s 252,42 87,189 C 41,93 188,253 119,51 h 44 s 104,172 92,173 C 255,68 28,75 49,101 h 74 s 35,65 255,225 C 40,168 107,97 218,13 h 119 s 251,203 199,117 C 4,129 208,151 128,190 h 25 s 173,17 85,11",
|
|
9
|
+
"M 10,30 C 220,241 180,60 83,47 h 253 s 166,46 1,207 C 50,38 132,79 177,212 h 27 s 126,43 218,198 C 153,149 34,184 25,148 h 62 s 205,101 92,45 C 179,195 136,245 200,186 h 6 s 87,220 64,128 C 207,88 214,52 218,206 h 252 s 39,169 25,205 C 118,189 53,225 151,186 h 23 s 75,162 160,249 C 68,23 24,35 157,23 h 195 s 148,19 220,71 C 199,84 14,66 41,2 h 17 s 114,73 108,199 C 29,221 207,20 31,165 h 209 s 9,29 111,47 C 139,54 167,11 137,227 h 16 s 84,136 249,85 C 191,178 209,193 116,1 h 91 s 168,212 134,117 C 140,231 73,124 248,76 h 196 s 202,231 65,208 C 120,110 156,158 116,181 h 62 s 159,106 129,18 C 37,176 101,149 104,17 h 123 s 194,236 193,55 C 29,149 205,24 32,223 h 15 s 60,208 152,137 C 69,205 138,149 68,242 h 73 s 5,113 113,7",
|
|
10
|
+
"M 10,30 C 75,47 93,40 123,41 h 137 s 28,7 72,187 C 38,121 180,136 224,213 h 238 s 239,214 187,85 C 52,135 198,49 159,238 h 190 s 231,110 157,59 C 250,181 64,159 8,69 h 121 s 136,176 135,231 C 115,113 171,96 221,146 h 112 s 84,39 195,97 C 211,150 165,139 224,12 h 37 s 44,25 76,131 C 30,45 134,159 220,159 h 95 s 248,168 24,26 C 140,174 97,127 78,16 h 48 s 38,142 10,203 C 128,30 174,78 107,219 h 198 s 166,61 217,189 C 226,253 231,27 24,250 h 24 s 142,133 82,99 C 119,233 139,85 112,162 h 101 s 154,142 122,58 C 10,161 148,255 114,127 h 12 s 244,99 223,52 C 83,79 235,130 59,0 h 80 s 4,222 111,95 C 101,200 9,117 102,149 h 243 s 103,10 64,56 C 209,121 240,178 241,203 h 189 s 200,175 16,19 C 155,29 186,83 49,86 h 21 s 214,57 122,44"
|
|
11
|
+
]
|
|
12
|
+
}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
|
|
5
|
+
const B1_RC4_KEY = 'xhswebmplfbt';
|
|
6
|
+
const B1_BASE64_ALPHABET = 'ZmserbBoHQtNP+wOcza/LpngG8yJq42KWYj0DSfdikx3VT16IlUAFM97hECvuRX5';
|
|
7
|
+
const MINI_FIELD_KEYS = Object.freeze([
|
|
8
|
+
'x33', 'x34', 'x35', 'x36', 'x37', 'x38', 'x39',
|
|
9
|
+
'x42', 'x43', 'x44', 'x45', 'x46',
|
|
10
|
+
'x48', 'x49', 'x50', 'x51', 'x52', 'x82', 'x84',
|
|
11
|
+
]);
|
|
12
|
+
const DEFAULT_X37 = '0|0|0|0|0|0|0|0|0|1|0|0|1|0|0|0|0|1|1|0|0|0|0|0';
|
|
13
|
+
const DEFAULT_X38 = '0|0|1|0|1|0|0|0|0|0|1|0|1|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0';
|
|
14
|
+
const DEFAULT_X82 = '1|_BHjFmfUMEtxhI|_AUuXfEG27Xa3x|__xhsPendingNotePoint25300ReportMap|__xhsReportedNotePoint25300RecordMap|setImDebugMode|anti_hp_sign_config|__rap_app_id__|__rap_report__|__rap_last_sign_cost__|__rap_last_transform_cost__|__rap_hijack_installed__|__ed1a7dddf7c818e4bd|__hp_xhs_search_input_state__|__h';
|
|
15
|
+
const DEFAULT_X39 = '22';
|
|
16
|
+
const DEFAULT_X45 = '__SEC_CAV__1-1-1-1-1|';
|
|
17
|
+
const DEFAULT_X50 = '131,88,103';
|
|
18
|
+
|
|
19
|
+
function orderedMiniFields(input) {
|
|
20
|
+
const out = {};
|
|
21
|
+
for (const key of MINI_FIELD_KEYS) {
|
|
22
|
+
if (Object.prototype.hasOwnProperty.call(input || {}, key)) out[key] = input[key];
|
|
23
|
+
}
|
|
24
|
+
return out;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function rc4BinaryString(plainText, key = B1_RC4_KEY) {
|
|
28
|
+
const state = Array.from({ length: 256 }, (_, i) => i);
|
|
29
|
+
let j = 0;
|
|
30
|
+
for (let i = 0; i < 256; i++) {
|
|
31
|
+
j = (j + state[i] + key.charCodeAt(i % key.length)) & 0xff;
|
|
32
|
+
[state[i], state[j]] = [state[j], state[i]];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
let i = 0;
|
|
36
|
+
j = 0;
|
|
37
|
+
let encrypted = '';
|
|
38
|
+
for (let offset = 0; offset < plainText.length; offset++) {
|
|
39
|
+
i = (i + 1) & 0xff;
|
|
40
|
+
j = (j + state[i]) & 0xff;
|
|
41
|
+
[state[i], state[j]] = [state[j], state[i]];
|
|
42
|
+
const keyByte = state[(state[i] + state[j]) & 0xff];
|
|
43
|
+
encrypted += String.fromCharCode(plainText.charCodeAt(offset) ^ keyByte);
|
|
44
|
+
}
|
|
45
|
+
return encrypted;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function customBase64(bytes, alphabet = B1_BASE64_ALPHABET) {
|
|
49
|
+
let out = '';
|
|
50
|
+
for (let offset = 0; offset < bytes.length; offset += 3) {
|
|
51
|
+
const a = bytes[offset];
|
|
52
|
+
const hasB = offset + 1 < bytes.length;
|
|
53
|
+
const hasC = offset + 2 < bytes.length;
|
|
54
|
+
const b = hasB ? bytes[offset + 1] : 0;
|
|
55
|
+
const c = hasC ? bytes[offset + 2] : 0;
|
|
56
|
+
out += alphabet[a >>> 2];
|
|
57
|
+
out += alphabet[((a & 0x03) << 4) | (b >>> 4)];
|
|
58
|
+
out += hasB ? alphabet[((b & 0x0f) << 2) | (c >>> 6)] : '=';
|
|
59
|
+
out += hasC ? alphabet[c & 0x3f] : '=';
|
|
60
|
+
}
|
|
61
|
+
return out;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function customBase64Decode(text, alphabet = B1_BASE64_ALPHABET) {
|
|
65
|
+
const reverse = new Map(Array.from(alphabet, (char, index) => [char, index]));
|
|
66
|
+
const bytes = [];
|
|
67
|
+
for (let offset = 0; offset < text.length; offset += 4) {
|
|
68
|
+
const a = reverse.get(text[offset]);
|
|
69
|
+
const b = reverse.get(text[offset + 1]);
|
|
70
|
+
const c = text[offset + 2] === '=' ? 0 : reverse.get(text[offset + 2]);
|
|
71
|
+
const d = text[offset + 3] === '=' ? 0 : reverse.get(text[offset + 3]);
|
|
72
|
+
if ([a, b, c, d].some(x => x === undefined)) throw new Error('invalid b1 base64 character');
|
|
73
|
+
bytes.push((a << 2) | (b >>> 4));
|
|
74
|
+
if (text[offset + 2] !== '=') bytes.push(((b & 0x0f) << 4) | (c >>> 2));
|
|
75
|
+
if (text[offset + 3] !== '=') bytes.push(((c & 0x03) << 6) | d);
|
|
76
|
+
}
|
|
77
|
+
return Uint8Array.from(bytes);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function encodeB1FromMini(miniFields) {
|
|
81
|
+
const plainText = JSON.stringify(orderedMiniFields(miniFields));
|
|
82
|
+
const encrypted = rc4BinaryString(plainText);
|
|
83
|
+
return customBase64(Buffer.from(encrypted, 'utf8'));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function decodeB1(b1) {
|
|
87
|
+
const encrypted = Buffer.from(customBase64Decode(b1)).toString('utf8');
|
|
88
|
+
const plainText = rc4BinaryString(encrypted);
|
|
89
|
+
return JSON.parse(plainText);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function formatTelemetry(options = {}) {
|
|
93
|
+
const now = Number(options.now ?? Date.now());
|
|
94
|
+
const timeOrigin = Number(options.timeOrigin ?? (now - Number(options.sessionAgeMs ?? 2151.1)));
|
|
95
|
+
const activeProfile = options.profile === 'active' || options.profile === 'legacy-active';
|
|
96
|
+
const mouse = activeProfile
|
|
97
|
+
? { me: 50, mm: 50, md: 1, mu: 1, c: 1, ...(options.mouse || {}) }
|
|
98
|
+
: { ...(options.mouse || {}) };
|
|
99
|
+
const page = activeProfile
|
|
100
|
+
? { ulr: 1, ps: 1, f: 3, b: 3, vc: 0, rs: 1, sc: 0, ...(options.page || {}) }
|
|
101
|
+
: { ulr: 2, ps: 1, ...(options.page || {}) };
|
|
102
|
+
const state = { h: 0, f: 1, kr: 0, ...(options.state || {}) };
|
|
103
|
+
const featureInput = options.features || {};
|
|
104
|
+
const features = activeProfile ? {
|
|
105
|
+
ae: 3.3656015629507223,
|
|
106
|
+
ak: 6.231183732330187,
|
|
107
|
+
cdr: 0.4096814442007536,
|
|
108
|
+
bf: { ar: 0.6210873146622735, fr: 7.158084478545331 },
|
|
109
|
+
fi: Number(options.firstInteraction ?? 2151.1),
|
|
110
|
+
...featureInput,
|
|
111
|
+
} : {
|
|
112
|
+
ae: null,
|
|
113
|
+
ak: null,
|
|
114
|
+
cdr: null,
|
|
115
|
+
bf: null,
|
|
116
|
+
fi: null,
|
|
117
|
+
...featureInput,
|
|
118
|
+
};
|
|
119
|
+
const keyboard = options.keyboard || {};
|
|
120
|
+
const mapText = value => Object.entries(value)
|
|
121
|
+
.map(([key, item]) => `${key}:${item}`)
|
|
122
|
+
.join(',');
|
|
123
|
+
const bfText = features.bf == null
|
|
124
|
+
? 'null'
|
|
125
|
+
: `{ar:${features.bf.ar},fr:${features.bf.fr}}`;
|
|
126
|
+
return `{mt:{to:${timeOrigin}},m:{${mapText(mouse)}},k:{${mapText(keyboard)}},p:{${mapText(page)}},st:{${mapText(state)}},ft:{ae:${features.ae},ak:${features.ak},cdr:${features.cdr},bf:${bfText},fi:${features.fi}}}`;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// 默认构造“冷启动/低交互”profile。b1 是环境快照,不是稳定设备 ID:
|
|
130
|
+
// x36/x39/x44/x50/x82/x84 会随页面、浏览器能力和交互状态变化。
|
|
131
|
+
// 如需和某一条浏览器样本逐字节相等,必须把该样本解出的字段通过 overrides 传入。
|
|
132
|
+
function buildMiniFields(options = {}) {
|
|
133
|
+
const now = Number(options.now ?? Date.now());
|
|
134
|
+
const windowKeysRaw = Array.isArray(options.windowKeys)
|
|
135
|
+
? `1|${options.windowKeys.join('|')}`
|
|
136
|
+
: (options.x82 ?? DEFAULT_X82);
|
|
137
|
+
// 浏览器 collector 对页面全局名快照最多保留 300 个字符。
|
|
138
|
+
const windowKeys = String(windowKeysRaw).slice(0, 300);
|
|
139
|
+
const fields = {
|
|
140
|
+
x33: '0',
|
|
141
|
+
x34: '0',
|
|
142
|
+
x35: '0',
|
|
143
|
+
x36: String(options.frameCount ?? 2),
|
|
144
|
+
x37: DEFAULT_X37,
|
|
145
|
+
x38: DEFAULT_X38,
|
|
146
|
+
// x39 不是 window/global 数量。Creator 4.3.6 的发布页采集器通常
|
|
147
|
+
// 落在 16-22;纯算层把它作为显式环境输入,历史 fixture 可覆盖。
|
|
148
|
+
x39: String(options.x39 ?? DEFAULT_X39),
|
|
149
|
+
// Creator's current 4.3.6 collector reports 3.5.6. Captured fixture
|
|
150
|
+
// callers can still override x42 explicitly for historical replays.
|
|
151
|
+
x42: String(options.sdkVersion ?? '3.5.6'),
|
|
152
|
+
x43: String(options.canvasFingerprint ?? 'Canvas not supported'),
|
|
153
|
+
x44: String(now),
|
|
154
|
+
x45: String(options.secCanvas ?? DEFAULT_X45),
|
|
155
|
+
x46: String(options.webdriver ?? false),
|
|
156
|
+
x48: String(options.x48 ?? ''),
|
|
157
|
+
x49: String(options.x49 ?? '{list:[],type:}'),
|
|
158
|
+
// x50 是初始化期缓存的三元素浏览器能力向量,不是 global 数量。
|
|
159
|
+
x50: String(options.x50 ?? options.globalCount ?? DEFAULT_X50),
|
|
160
|
+
x51: String(options.x51 ?? ''),
|
|
161
|
+
x52: String(options.x52 ?? ''),
|
|
162
|
+
x82: String(windowKeys),
|
|
163
|
+
x84: String(options.x84 ?? formatTelemetry({ ...options.telemetry, now })),
|
|
164
|
+
};
|
|
165
|
+
return Object.assign(fields, options.overrides || {});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function generateB1(options = {}) {
|
|
169
|
+
const mini = buildMiniFields(options);
|
|
170
|
+
return { b1: encodeB1FromMini(mini), mini };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function main(argv = process.argv) {
|
|
174
|
+
const arg = argv[2];
|
|
175
|
+
if (arg === '--generate') {
|
|
176
|
+
const options = argv[3] ? JSON.parse(argv[3]) : {};
|
|
177
|
+
process.stdout.write(JSON.stringify(generateB1(options)) + '\n');
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (arg === '--decode') {
|
|
181
|
+
process.stdout.write(JSON.stringify(decodeB1(argv[3] || ''), null, 2) + '\n');
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (!arg) {
|
|
185
|
+
process.stdout.write(JSON.stringify(generateB1()) + '\n');
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const input = arg.startsWith('@')
|
|
189
|
+
? JSON.parse(fs.readFileSync(arg.slice(1), 'utf8'))
|
|
190
|
+
: JSON.parse(arg);
|
|
191
|
+
process.stdout.write(encodeB1FromMini(input) + '\n');
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (require.main === module) main();
|
|
195
|
+
|
|
196
|
+
module.exports = {
|
|
197
|
+
B1_RC4_KEY,
|
|
198
|
+
B1_BASE64_ALPHABET,
|
|
199
|
+
MINI_FIELD_KEYS,
|
|
200
|
+
orderedMiniFields,
|
|
201
|
+
rc4BinaryString,
|
|
202
|
+
customBase64,
|
|
203
|
+
customBase64Decode,
|
|
204
|
+
encodeB1FromMini,
|
|
205
|
+
decodeB1,
|
|
206
|
+
formatTelemetry,
|
|
207
|
+
buildMiniFields,
|
|
208
|
+
generateB1,
|
|
209
|
+
main,
|
|
210
|
+
};
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mnsv2 → mns0101_/0201_/0301_ 100% 纯算法
|
|
3
|
+
* ============================================================
|
|
4
|
+
*
|
|
5
|
+
* sign = "mns0301_" + base64_custom( XOR( pack(fields), KEYSTREAM ) )
|
|
6
|
+
*
|
|
7
|
+
* 全部子过程均已还原为可读算法(无 VM / 无 __$c / 无补环境):
|
|
8
|
+
* - pack : 见 packPlaintext(TLV 字段布局)
|
|
9
|
+
* - ds 环境指纹 : envFp() = [1, ver0^115, <14 固定环境常量>]
|
|
10
|
+
* - ds 设备签名 : dsSig() = dsf(le64(ts)++md5(api+data)) 逐字节 XOR ver0
|
|
11
|
+
* - _dsf : 自定义 4-lane ARX 哈希(见 dsf())
|
|
12
|
+
* - encrypt : XOR 固定密钥流(stream cipher)
|
|
13
|
+
* - base64 : 自定义字母表
|
|
14
|
+
*/
|
|
15
|
+
'use strict';
|
|
16
|
+
|
|
17
|
+
const crypto = require('crypto');
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const path = require('path');
|
|
20
|
+
|
|
21
|
+
const ALPHABET = 'MfgqrsbcyzPQRStuvC7mn501HIJBo2DEFTKdeNOwxWXYZap89+/A4UVLhijkl63G';
|
|
22
|
+
const MNS0101_ALPHABET = 'NOPQRStuvwxWXYZabcyz012DEFTKLMdefghijkl4563GHIJBC7mnop89+/';
|
|
23
|
+
|
|
24
|
+
const KEYSTREAM = (() => {
|
|
25
|
+
const j = JSON.parse(fs.readFileSync(path.join(__dirname, 'mns_keystreams.json'), 'utf8'));
|
|
26
|
+
return [...Buffer.from(j.b64, 'base64')];
|
|
27
|
+
})();
|
|
28
|
+
|
|
29
|
+
const MNS0101_KEYSTREAM = (() => {
|
|
30
|
+
const j = JSON.parse(fs.readFileSync(path.join(__dirname, 'mns_0101_keystream.json'), 'utf8'));
|
|
31
|
+
return [...Buffer.from(j.b64, 'base64')];
|
|
32
|
+
})();
|
|
33
|
+
|
|
34
|
+
// envConst/envFpTail/loadts/seq/appId/deviceTag 属于页面、平台与会话状态,
|
|
35
|
+
// 不是算法常量。PC 与 Creator 共用本文件,平台层必须显式传入这些材料。
|
|
36
|
+
|
|
37
|
+
function md5Bytes(s) {
|
|
38
|
+
return [...crypto.createHash('md5').update(String(s), 'utf8').digest()];
|
|
39
|
+
}
|
|
40
|
+
function le32(n) {
|
|
41
|
+
n >>>= 0;
|
|
42
|
+
return [n & 255, (n >>> 8) & 255, (n >>> 16) & 255, (n >>> 24) & 255];
|
|
43
|
+
}
|
|
44
|
+
function le64(n) {
|
|
45
|
+
const out = [];
|
|
46
|
+
let b = BigInt(n);
|
|
47
|
+
for (let i = 0; i < 8; i++) { out.push(Number(b & 255n)); b >>= 8n; }
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
function strBytes(s) {
|
|
51
|
+
return [...Buffer.from(String(s), 'utf8')];
|
|
52
|
+
}
|
|
53
|
+
function base64Custom(bytes) {
|
|
54
|
+
let out = '';
|
|
55
|
+
for (let i = 0; i < bytes.length; i += 3) {
|
|
56
|
+
const b0 = bytes[i], b1 = bytes[i + 1], b2 = bytes[i + 2];
|
|
57
|
+
out += ALPHABET[b0 >> 2];
|
|
58
|
+
out += ALPHABET[((b0 & 3) << 4) | ((b1 || 0) >> 4)];
|
|
59
|
+
if (b1 === undefined) { out += '=='; break; }
|
|
60
|
+
out += ALPHABET[((b1 & 15) << 2) | ((b2 || 0) >> 6)];
|
|
61
|
+
if (b2 === undefined) { out += '='; break; }
|
|
62
|
+
out += ALPHABET[b2 & 63];
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// mns0101 使用自定义 Base58,而不是 0201/0301 的自定义 Base64。
|
|
68
|
+
// 前导零使用该字母表中的 `1` 表示。
|
|
69
|
+
function base58Custom(bytes) {
|
|
70
|
+
let value = 0n;
|
|
71
|
+
for (const byte of bytes) value = (value << 8n) | BigInt(byte);
|
|
72
|
+
let body = '';
|
|
73
|
+
while (value > 0n) {
|
|
74
|
+
body = MNS0101_ALPHABET[Number(value % 58n)] + body;
|
|
75
|
+
value /= 58n;
|
|
76
|
+
}
|
|
77
|
+
let zeros = 0;
|
|
78
|
+
for (const byte of bytes) {
|
|
79
|
+
if (byte !== 0) break;
|
|
80
|
+
zeros++;
|
|
81
|
+
}
|
|
82
|
+
return '1'.repeat(zeros) + body;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function base58CustomDecode(text) {
|
|
86
|
+
const reverse = new Map(Array.from(MNS0101_ALPHABET, (char, index) => [char, BigInt(index)]));
|
|
87
|
+
let value = 0n;
|
|
88
|
+
let offset = 0;
|
|
89
|
+
while (offset < text.length && text[offset] === '1') offset++;
|
|
90
|
+
for (let i = offset; i < text.length; i++) {
|
|
91
|
+
const digit = reverse.get(text[i]);
|
|
92
|
+
if (digit === undefined) throw new Error(`invalid mns0101 base58 character at ${i}`);
|
|
93
|
+
value = value * 58n + digit;
|
|
94
|
+
}
|
|
95
|
+
const bytes = [];
|
|
96
|
+
while (value > 0n) {
|
|
97
|
+
bytes.unshift(Number(value & 255n));
|
|
98
|
+
value >>= 8n;
|
|
99
|
+
}
|
|
100
|
+
return new Array(offset).fill(0).concat(bytes);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// --- ds 设备签名 _dsf:自定义 4-lane ARX 哈希 ---
|
|
104
|
+
function rotl(x, r) {
|
|
105
|
+
return (((x << r) | 0) + (x >>> (32 - r))) | 0;
|
|
106
|
+
}
|
|
107
|
+
function dsf(data) {
|
|
108
|
+
const len = data.length;
|
|
109
|
+
const rd = (o) => (data[o] | (data[o + 1] << 8) | (data[o + 2] << 16) | (data[o + 3] << 24)) | 0;
|
|
110
|
+
let h1 = (0x6d2b79f5 ^ len) | 0;
|
|
111
|
+
let h2 = (0x1b873593 ^ (len << 8)) | 0;
|
|
112
|
+
let h3 = (0x85ebca6b ^ (len << 16)) | 0;
|
|
113
|
+
let h4 = (0xc2b2ae35 ^ (len << 24)) | 0;
|
|
114
|
+
for (let i = 0; i + 8 <= len; i += 8) {
|
|
115
|
+
const w0 = rd(i), w1 = rd(i + 4);
|
|
116
|
+
h1 = rotl((((h1 + w0) | 0) ^ h3) | 0, 7);
|
|
117
|
+
h2 = rotl((((h2 ^ w0) | 0) + h4) | 0, 11);
|
|
118
|
+
h3 = rotl((((h3 + w1) | 0) ^ h1) | 0, 13);
|
|
119
|
+
h4 = rotl((((h4 ^ w1) | 0) + h2) | 0, 17);
|
|
120
|
+
}
|
|
121
|
+
h1 = (h1 ^ len) | 0;
|
|
122
|
+
h2 = (h2 ^ h1) | 0;
|
|
123
|
+
h3 = (h3 + h2) | 0;
|
|
124
|
+
h4 = (h4 ^ h3) | 0;
|
|
125
|
+
h1 = rotl(h1, 9); h2 = rotl(h2, 13); h3 = rotl(h3, 17); h4 = rotl(h4, 19);
|
|
126
|
+
h1 = (h1 + h3) | 0;
|
|
127
|
+
h2 = (h2 ^ h4) | 0;
|
|
128
|
+
h3 = (h3 + h1) | 0;
|
|
129
|
+
h4 = (h4 ^ h2) | 0;
|
|
130
|
+
const out = [];
|
|
131
|
+
for (const h of [h1 >>> 0, h2 >>> 0, h3 >>> 0, h4 >>> 0]) {
|
|
132
|
+
out.push(h & 255, (h >>> 8) & 255, (h >>> 16) & 255, (h >>> 24) & 255);
|
|
133
|
+
}
|
|
134
|
+
return out;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function envFp(versionKey, tail) {
|
|
138
|
+
if (!Array.isArray(tail) || tail.length !== 14) {
|
|
139
|
+
throw new Error('envFpTail required (14 bytes)');
|
|
140
|
+
}
|
|
141
|
+
return [1, versionKey ^ 115].concat(tail);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function packPlaintext(p) {
|
|
145
|
+
if (p.loadts == null) throw new Error('mns loadts required');
|
|
146
|
+
if (p.seq == null) throw new Error('mns seq required');
|
|
147
|
+
if (p.envConst == null) throw new Error('mns envConst required');
|
|
148
|
+
if (!Array.isArray(p.envFpTail) || p.envFpTail.length !== 14) {
|
|
149
|
+
throw new Error('mns envFpTail required (14 bytes)');
|
|
150
|
+
}
|
|
151
|
+
const version = p.version >>> 0;
|
|
152
|
+
const vKey = version & 255;
|
|
153
|
+
const ts = p.ts;
|
|
154
|
+
const loadts = p.loadts;
|
|
155
|
+
const appId = String(p.appId || 'xhs-pc-web');
|
|
156
|
+
const deviceTag = String(p.deviceTag || p.dsn || 'a3');
|
|
157
|
+
const full = String(p.api) + (p.data || '');
|
|
158
|
+
// md5FullBytes / md5UrlBytes are the u and p params from seccore_signv2 (already-computed md5s).
|
|
159
|
+
// If not supplied, compute from api+data / api locally.
|
|
160
|
+
const md5full = p.md5FullBytes ? [...p.md5FullBytes] : md5Bytes(full);
|
|
161
|
+
const md5api = p.md5UrlBytes ? [...p.md5UrlBytes] : md5Bytes(p.api);
|
|
162
|
+
// DS 脚本尚未就绪时浏览器的 window._dsn = "nop",此阶段尾部直接放
|
|
163
|
+
// MD5(url) XOR versionLowByte;DS 就绪后 PC/Creator 分别使用 a3/a1,
|
|
164
|
+
// 尾部改为 _dsf(null, timestamp || MD5(url)) XOR versionLowByte。
|
|
165
|
+
// Creator 的 _dsf 来自当前服务端 DS 程序,通过 dsSigBytes 显式传入;
|
|
166
|
+
// 本地 dsf() 仅保留给已经完成静态提纯的平台路径。
|
|
167
|
+
let rawDsSig;
|
|
168
|
+
if (deviceTag === 'nop') {
|
|
169
|
+
rawDsSig = md5api;
|
|
170
|
+
} else if (Array.isArray(p.dsSigBytes) || ArrayBuffer.isView(p.dsSigBytes)) {
|
|
171
|
+
rawDsSig = Array.from(p.dsSigBytes);
|
|
172
|
+
if (rawDsSig.length !== 16) throw new Error('mns dsSigBytes must be 16 bytes');
|
|
173
|
+
} else {
|
|
174
|
+
rawDsSig = dsf(le64(ts).concat(md5api));
|
|
175
|
+
}
|
|
176
|
+
const dsSig = rawDsSig.map((b) => b ^ vKey);
|
|
177
|
+
|
|
178
|
+
const out = [];
|
|
179
|
+
const push = (a) => { for (const b of a) out.push(b); };
|
|
180
|
+
push([121, 104, 96, 41]);
|
|
181
|
+
push(le32(version));
|
|
182
|
+
push(le64(ts));
|
|
183
|
+
push(le64(loadts));
|
|
184
|
+
push(le32(p.seq >>> 0)); // 请求序列号(会话自增计数器)
|
|
185
|
+
push(le32(p.envConst >>> 0));
|
|
186
|
+
push(le32(p.fullLen != null ? p.fullLen >>> 0 : Buffer.byteLength(full, 'utf8')));
|
|
187
|
+
push(md5full.slice(0, 8).map((b) => b ^ vKey));
|
|
188
|
+
push([p.a1.length]);
|
|
189
|
+
push(strBytes(p.a1));
|
|
190
|
+
const appBytes = strBytes(appId);
|
|
191
|
+
if (appBytes.length > 255) throw new Error('mns appId too long');
|
|
192
|
+
push([appBytes.length]);
|
|
193
|
+
push(appBytes);
|
|
194
|
+
push(envFp(vKey, p.envFpTail));
|
|
195
|
+
const tagBytes = strBytes(deviceTag);
|
|
196
|
+
if (tagBytes.length > 255) throw new Error('mns deviceTag too long');
|
|
197
|
+
push([tagBytes.length]);
|
|
198
|
+
push(tagBytes);
|
|
199
|
+
push([16]);
|
|
200
|
+
push(dsSig);
|
|
201
|
+
return out;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Helper: hex string → bytes array
|
|
205
|
+
function hexToBytes(hex) {
|
|
206
|
+
const out = [];
|
|
207
|
+
for (let i = 0; i < hex.length; i += 2) out.push(parseInt(hex.slice(i, i + 2), 16));
|
|
208
|
+
return out;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// seccore_signv2 wrapper: matches browser's exact call convention.
|
|
212
|
+
// c = url + JSON.stringify(data) or url + data(string), u = md5(c) hex, p = md5(url) hex.
|
|
213
|
+
function seccoreSignV2({
|
|
214
|
+
url, data, a1, ts, loadts, seq, version, envConst, envFpTail,
|
|
215
|
+
appId = 'xhs-pc-web', deviceTag = 'a3',
|
|
216
|
+
}) {
|
|
217
|
+
const c = String(url) + (data == null ? '' : (typeof data === 'object' ? JSON.stringify(data) : String(data)));
|
|
218
|
+
const uHex = crypto.createHash('md5').update(c).digest('hex');
|
|
219
|
+
const pHex = crypto.createHash('md5').update(String(url)).digest('hex');
|
|
220
|
+
const md5FullBytes = hexToBytes(uHex);
|
|
221
|
+
const md5UrlBytes = hexToBytes(pHex);
|
|
222
|
+
return sign({
|
|
223
|
+
api: url, data, a1, ts, loadts, seq, version, envConst, envFpTail,
|
|
224
|
+
appId, deviceTag,
|
|
225
|
+
md5FullBytes, md5UrlBytes,
|
|
226
|
+
fullLen: Buffer.byteLength(c, 'utf8'),
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function sign(p) {
|
|
231
|
+
const plain = packPlaintext(p);
|
|
232
|
+
const cipher = plain.map((b, i) => b ^ KEYSTREAM[i]);
|
|
233
|
+
return 'mns0301_' + base64Custom(cipher);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// mns0101:同一 144B pack → 固定密钥流 XOR → 自定义 Base58。
|
|
237
|
+
// 浏览器冷启动内容请求夹具已从显式 pack 输入 6/6 byte-exact。
|
|
238
|
+
function sign0101(p) {
|
|
239
|
+
const plain = packPlaintext(p);
|
|
240
|
+
if (plain.length > MNS0101_KEYSTREAM.length) {
|
|
241
|
+
throw new Error(`mns0101 keystream too short: ${MNS0101_KEYSTREAM.length} < ${plain.length}`);
|
|
242
|
+
}
|
|
243
|
+
const cipher = plain.map((byte, index) => byte ^ MNS0101_KEYSTREAM[index]);
|
|
244
|
+
return 'mns0101_' + base58Custom(cipher);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// ============================================================
|
|
248
|
+
// mns0201 档位:XXTEA(自定义 DELTA) + 同一自定义 base64 字母表
|
|
249
|
+
// ------------------------------------------------------------
|
|
250
|
+
// 从 vendor-dynamic VM 字节码静态还原(f_13448_141 管线):
|
|
251
|
+
// pack(144B) --toWordsLE(includeLength=true)--> 37 words
|
|
252
|
+
// --XXTEA_encrypt(key, DELTA=1013904243)--> 37 words
|
|
253
|
+
// --fromWordsLE(includeLength=false)--> 148 bytes
|
|
254
|
+
// --base64_custom--> payload ;结果 = "mns0201_" + payload
|
|
255
|
+
// 真实密钥 = utf8("e6483ca2a1eed5e3")(VM 内 "e6"+"483c"+"a2a1eed5e3" 拼接)。
|
|
256
|
+
// 注意:"99754106633f94d350db34d548d6091a" 是字节码里的诱饵(其派生值随即被覆盖)。
|
|
257
|
+
const MNS0201_DELTA = 1013904243; // 0x3C6EF373(非标准 golden-ratio)
|
|
258
|
+
const MNS0201_KEY_STR = 'e6483ca2a1eed5e3';
|
|
259
|
+
|
|
260
|
+
function mnsKeyWords() {
|
|
261
|
+
let kb = [...Buffer.from(MNS0201_KEY_STR, 'utf8')];
|
|
262
|
+
if (kb.length < 16) kb = kb.concat(new Array(16 - kb.length).fill(0));
|
|
263
|
+
return toWordsLE(kb, false);
|
|
264
|
+
}
|
|
265
|
+
function toWordsLE(bytes, includeLength) {
|
|
266
|
+
const e = bytes.length;
|
|
267
|
+
let a = e >> 2;
|
|
268
|
+
if (e & 3) a++;
|
|
269
|
+
const t = includeLength ? new Array(a + 1).fill(0) : new Array(a).fill(0);
|
|
270
|
+
if (includeLength) t[a] = e;
|
|
271
|
+
for (let o = 0; o < e; o++) t[o >> 2] |= bytes[o] << ((o & 3) << 3);
|
|
272
|
+
return t;
|
|
273
|
+
}
|
|
274
|
+
function fromWordsLE(r, includeLength) {
|
|
275
|
+
let t = r.length, a = t << 2;
|
|
276
|
+
if (includeLength) { const e = r[t - 1]; a -= 4; if (e < a - 3 || e > a) return null; a = e; }
|
|
277
|
+
const f = new Array(a);
|
|
278
|
+
for (let i = 0; i < a; i++) f[i] = (r[i >> 2] >>> ((i & 3) << 3)) & 0xff;
|
|
279
|
+
return f;
|
|
280
|
+
}
|
|
281
|
+
function xxteaMx(sum, y, z, p, e, k) {
|
|
282
|
+
return ((((z >>> 5) ^ (y << 2)) + ((y >>> 3) ^ (z << 4))) ^ (((sum ^ y) + (k[(p & 3) ^ e] ^ z)))) | 0;
|
|
283
|
+
}
|
|
284
|
+
function xxteaEncrypt(v, k) {
|
|
285
|
+
const n = v.length;
|
|
286
|
+
if (n < 2) return v;
|
|
287
|
+
const nn = n - 1;
|
|
288
|
+
let rounds = Math.floor(6 + 52 / n);
|
|
289
|
+
let sum = 0, y, z = v[nn], e, p;
|
|
290
|
+
while (rounds-- > 0) {
|
|
291
|
+
sum = (sum + MNS0201_DELTA) | 0;
|
|
292
|
+
e = (sum >>> 2) & 3;
|
|
293
|
+
for (p = 0; p < nn; p++) { y = v[p + 1]; z = v[p] = (v[p] + xxteaMx(sum, y, z, p, e, k)) | 0; }
|
|
294
|
+
y = v[0]; z = v[nn] = (v[nn] + xxteaMx(sum, y, z, nn, e, k)) | 0;
|
|
295
|
+
}
|
|
296
|
+
return v;
|
|
297
|
+
}
|
|
298
|
+
function xxteaDecrypt(v, k) {
|
|
299
|
+
const n = v.length;
|
|
300
|
+
if (n < 2) return v;
|
|
301
|
+
const nn = n - 1;
|
|
302
|
+
let rounds = Math.floor(6 + 52 / n);
|
|
303
|
+
let sum = (rounds * MNS0201_DELTA) | 0, y = v[0], z, e, p;
|
|
304
|
+
while (sum !== 0) {
|
|
305
|
+
e = (sum >>> 2) & 3;
|
|
306
|
+
for (p = nn; p > 0; p--) { z = v[p - 1]; y = v[p] = (v[p] - xxteaMx(sum, y, z, p, e, k)) | 0; }
|
|
307
|
+
z = v[nn]; y = v[0] = (v[0] - xxteaMx(sum, y, z, 0, e, k)) | 0;
|
|
308
|
+
sum = (sum - MNS0201_DELTA) | 0;
|
|
309
|
+
}
|
|
310
|
+
return v;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function encrypt0201(pack) {
|
|
314
|
+
const kw = mnsKeyWords();
|
|
315
|
+
const dataWords = toWordsLE(pack, true);
|
|
316
|
+
const cipherWords = xxteaEncrypt(dataWords.slice(), kw);
|
|
317
|
+
return fromWordsLE(cipherWords, false);
|
|
318
|
+
}
|
|
319
|
+
function sign0201(p) {
|
|
320
|
+
const plain = packPlaintext(p);
|
|
321
|
+
return 'mns0201_' + base64Custom(encrypt0201(plain));
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// 统一入口:按档位分发(0301 默认;0201 = XXTEA)
|
|
325
|
+
function signTier(p, tier) {
|
|
326
|
+
switch (tier || '0301') {
|
|
327
|
+
case '0101': return sign0101(p);
|
|
328
|
+
case '0201': return sign0201(p);
|
|
329
|
+
case '0301': return sign(p);
|
|
330
|
+
default: throw new Error(`unsupported mns tier: ${tier}`);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
module.exports = {
|
|
335
|
+
sign, sign0101, sign0201, signTier, packPlaintext, dsf, envFp,
|
|
336
|
+
base58Custom, base58CustomDecode, base64Custom,
|
|
337
|
+
KEYSTREAM, MNS0101_KEYSTREAM, ALPHABET, MNS0101_ALPHABET,
|
|
338
|
+
encrypt0201, xxteaEncrypt, xxteaDecrypt, toWordsLE, fromWordsLE, mnsKeyWords,
|
|
339
|
+
MNS0201_DELTA, MNS0201_KEY_STR, seccoreSignV2, hexToBytes, le64
|
|
340
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
{
|
|
2
|
+
"source": "browser-cold-start-fixtures-20260716",
|
|
3
|
+
"length": 160,
|
|
4
|
+
"b64": "r1crlcplstnsdrtdLpfLZTKZzGYzmcxmM5nM5nM5nM5nMxkMBgMBAAAAAACAQCCQSCQSicTicTgcDgcDAYBAoFAoFIrFYjEYDAaDwWAwmEwmk8lkslmsVqvV6vX6/X4/n08nk0mk0ul0Op1OJ5NJpNLp9Ho9Ho9HI5FIpNJpNBqNRiMRCIRCIZDIZDKZTKbT6XS63e53Ox2OR6NRKBSKxQ=="
|
|
5
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"len":2048,"b64":"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"}
|