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,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* x-rap-param 纯算 —— 加密侧(crypto + 信封),零补环境。
|
|
3
|
+
* 管线:payload → gzip(pure XHS) → alphabet36-random-pad → XOR(xorKey) → AES-128-ECB(自研S-box, 固定密钥) → body
|
|
4
|
+
* encR = AES-128-ECB(xorKey)
|
|
5
|
+
* 信封 = header + nonce + encR + len + body + trailing(bodyLen)
|
|
6
|
+
* 分组密码 = 标准 AES-128-ECB,仅 S-box 换成小红书自研表。
|
|
7
|
+
* DEFLATE = deflate.js(简单贪婪LZ77 + 动态Huffman,字节对齐浏览器版本)。
|
|
8
|
+
*/
|
|
9
|
+
'use strict';
|
|
10
|
+
const crypto = require('crypto');
|
|
11
|
+
const zlib = require('zlib');
|
|
12
|
+
const { aesEncBlock } = require('./aes_encrypt.js');
|
|
13
|
+
const { aesDecBlock } = require('./aes_decrypt.js');
|
|
14
|
+
const { encodeGzip } = require('./deflate.js');
|
|
15
|
+
|
|
16
|
+
const SBOX = [122,1,88,224,80,78,2,121,29,75,83,218,107,72,212,82,237,119,18,33,20,21,236,16,24,229,185,241,12,8,252,125,249,205,181,200,230,55,38,135,86,186,184,43,173,240,104,247,139,141,211,94,54,77,46,146,49,130,242,41,112,61,45,215,182,64,178,67,68,128,120,210,13,73,74,9,99,108,7,58,158,213,6,198,225,98,244,52,36,89,169,87,42,0,62,23,44,10,26,66,250,147,190,220,245,179,106,19,232,3,199,151,187,115,118,134,227,70,114,71,208,5,76,56,124,31,129,171,117,81,235,243,50,116,17,143,132,137,156,113,34,126,157,207,63,145,105,101,60,109,150,162,152,153,51,57,154,202,195,159,160,188,228,163,164,84,127,167,168,4,111,93,172,183,39,175,176,40,65,174,180,110,11,27,223,142,48,177,254,144,97,96,192,203,92,14,239,22,131,234,32,233,201,85,196,69,133,204,30,170,103,138,123,53,214,25,216,217,194,219,148,221,28,222,166,255,248,191,91,90,15,231,193,189,209,102,197,37,238,140,226,95,136,161,59,165,246,206,149,47,100,35,251,253,79,155];
|
|
17
|
+
const AES_KEY = [...Buffer.from('kqI1DTcwKX90ZtAy')];
|
|
18
|
+
const ALPHABET36 = '0123456789abcdefghijklmnopqrstuvwxyz';
|
|
19
|
+
|
|
20
|
+
function aesEcbEnc(data) { const o = []; for (let i = 0; i < data.length; i += 16) o.push(...aesEncBlock([...data.slice(i, i + 16)], AES_KEY.slice(), SBOX)); return Buffer.from(o); }
|
|
21
|
+
function aesEcbDec(data) { const o = []; for (let i = 0; i + 16 <= data.length; i += 16) o.push(...aesDecBlock([...data.slice(i, i + 16)], AES_KEY.slice(), SBOX)); return Buffer.from(o); }
|
|
22
|
+
|
|
23
|
+
// XHS 使用 alphabet36 随机 ASCII 填充到 16 字节边界 (NOT PKCS7)
|
|
24
|
+
function alpha36Pad(buf) {
|
|
25
|
+
const n = 16 - (buf.length % 16);
|
|
26
|
+
const padActual = n === 0 ? 16 : n;
|
|
27
|
+
const rand = crypto.randomBytes(padActual);
|
|
28
|
+
const padBytes = Buffer.from([...rand].map(b => ALPHABET36.charCodeAt(b % 36)));
|
|
29
|
+
return Buffer.concat([buf, padBytes]);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function pkcs7(buf) { const n = 16 - (buf.length % 16); return Buffer.concat([buf, Buffer.alloc(n, n)]); }
|
|
33
|
+
|
|
34
|
+
// 加密:payload(Buffer) + xorKey(16B) → {encR, body, gzipLen}
|
|
35
|
+
// mtime 可选:想字节对齐浏览器需要提供 mtime 与 xorKey,padBytes(可选)覆盖随机填充
|
|
36
|
+
function encryptPayload(payload, xorKey, opts = {}) {
|
|
37
|
+
let gz;
|
|
38
|
+
try {
|
|
39
|
+
gz = encodeGzip(payload, opts.mtime || 0);
|
|
40
|
+
} catch (err) {
|
|
41
|
+
// 大 payload(如 Creator 发布的 452B 指纹)会让自研 Huffman 树深超过 15
|
|
42
|
+
// 触发 overflow;回退 Node zlib 裸 deflate(与浏览器同族的合法编码,
|
|
43
|
+
// 服务端只做 AES-ECB + XOR + gunzip 校验,不逐字节比对 deflate)。
|
|
44
|
+
const deflated = zlib.deflateRawSync(payload, { level: 9 });
|
|
45
|
+
const mtime = opts.mtime || 0;
|
|
46
|
+
gz = Buffer.alloc(10 + deflated.length + 8);
|
|
47
|
+
gz[0] = 0x1f; gz[1] = 0x8b; gz[2] = 0x08; gz[3] = 0x00;
|
|
48
|
+
gz.writeUInt32LE(mtime, 4);
|
|
49
|
+
gz[8] = 0x00; gz[9] = 0x03;
|
|
50
|
+
deflated.copy(gz, 10);
|
|
51
|
+
gz.writeUInt32LE(zlib.crc32(payload), 10 + deflated.length);
|
|
52
|
+
gz.writeUInt32LE(payload.length & 0xffffffff, 14 + deflated.length);
|
|
53
|
+
}
|
|
54
|
+
const gzipLen = gz.length;
|
|
55
|
+
const padded = opts.padBytes
|
|
56
|
+
? Buffer.concat([gz, Buffer.from(opts.padBytes)])
|
|
57
|
+
: alpha36Pad(gz);
|
|
58
|
+
const xored = Buffer.from(padded.map((b, i) => b ^ xorKey[i % 16]));
|
|
59
|
+
const body = aesEcbEnc(xored);
|
|
60
|
+
const encR = aesEcbEnc(Buffer.from(xorKey));
|
|
61
|
+
return { encR, body, gzipLen };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// 解密(验证用)— 通过尝试不同尾部长度找出 gzip 结束位置
|
|
65
|
+
function decryptBody(encR, body) {
|
|
66
|
+
const xorKey = aesEcbDec(encR);
|
|
67
|
+
const xored = aesEcbDec(body);
|
|
68
|
+
const gz = Buffer.from(xored.map((b, i) => b ^ xorKey[i % 16]));
|
|
69
|
+
for (let trim = 0; trim <= 16; trim++) { try { return zlib.gunzipSync(gz.slice(0, gz.length - trim)); } catch (e) {} }
|
|
70
|
+
throw new Error('gunzip failed');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
module.exports = { encryptPayload, decryptBody, aesEcbEnc, aesEcbDec, SBOX, AES_KEY, pkcs7, alpha36Pad };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{
|
|
2
|
+
"captured": "2026-07-14",
|
|
3
|
+
"source": "capture_20260714.json sample[1] (homefeed 235B)",
|
|
4
|
+
"mask": "0x38",
|
|
5
|
+
"plLen": 235,
|
|
6
|
+
"bodyLen": 219,
|
|
7
|
+
"bodyUnmaskedHex": "03ea00000010346c326b326a6a673668696d6472366203ebb0037bbb041b00041c00041d00041e00041f00042000042100042200042300042400042500042600042700042800042900042e00042a00042b00042c00042d00044c00000000042f00043000043100043600000000043a00000000043c00000000044000000000044200000000044900000012000000019f615912f2010000019f617b376d044400000a000446000004f704470000019f615908a50445000000000448000443000000040012ffff048400048500000000048000048100048200048300"
|
|
8
|
+
}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"source": "xhs-pc-browser-fixtures-20260718",
|
|
4
|
+
"release": {
|
|
5
|
+
"appId": "xhs-pc-web",
|
|
6
|
+
"platform": "Windows",
|
|
7
|
+
"signVersion": "4.4.3",
|
|
8
|
+
"b1SdkVersion": "3.5.4",
|
|
9
|
+
"webProfileSdkVersion": "4.4.3",
|
|
10
|
+
"webBuild": "6.47.2",
|
|
11
|
+
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/152.0.0.0 Safari/537.36",
|
|
12
|
+
"secChUa": "\"Not;A=Brand\";v=\"8\", \"Chromium\";v=\"152\", \"Google Chrome\";v=\"152\""
|
|
13
|
+
},
|
|
14
|
+
"b1Reference": {
|
|
15
|
+
"frameCount": 2,
|
|
16
|
+
"x39": 22,
|
|
17
|
+
"x50": "131,88,103",
|
|
18
|
+
"secCanvas": "__SEC_CAV__1-1-1-1-1|",
|
|
19
|
+
"timeOriginOffsetMs": -2027.8,
|
|
20
|
+
"telemetryProfile": "active",
|
|
21
|
+
"selectedGlobalNames": [
|
|
22
|
+
"_BHjFmfUMEtxhI",
|
|
23
|
+
"_AUuXfEG27Xa3x",
|
|
24
|
+
"__xhsPendingNotePoint25300ReportMap",
|
|
25
|
+
"__xhsReportedNotePoint25300RecordMap",
|
|
26
|
+
"setImDebugMode",
|
|
27
|
+
"anti_hp_sign_config",
|
|
28
|
+
"__rap_app_id__",
|
|
29
|
+
"__rap_report__",
|
|
30
|
+
"__rap_last_sign_cost__",
|
|
31
|
+
"__rap_last_transform_cost__",
|
|
32
|
+
"__rap_hijack_installed__",
|
|
33
|
+
"__ed1a7dddf7c818e4bd",
|
|
34
|
+
"__hp_xhs_search_input_state__",
|
|
35
|
+
"__hp_xhs_search_submit_state__"
|
|
36
|
+
],
|
|
37
|
+
"mouse": {
|
|
38
|
+
"me": 50,
|
|
39
|
+
"mm": 50,
|
|
40
|
+
"md": 3,
|
|
41
|
+
"mu": 3,
|
|
42
|
+
"c": 3,
|
|
43
|
+
"dc": 1
|
|
44
|
+
},
|
|
45
|
+
"keyboard": {},
|
|
46
|
+
"page": {
|
|
47
|
+
"ulr": 5,
|
|
48
|
+
"ps": 1,
|
|
49
|
+
"f": 20,
|
|
50
|
+
"b": 19,
|
|
51
|
+
"vc": 2,
|
|
52
|
+
"rs": 1,
|
|
53
|
+
"sc": 1
|
|
54
|
+
},
|
|
55
|
+
"state": {
|
|
56
|
+
"h": 0,
|
|
57
|
+
"f": 1,
|
|
58
|
+
"kr": 0
|
|
59
|
+
},
|
|
60
|
+
"features": {
|
|
61
|
+
"ae": 2.8905690597867015,
|
|
62
|
+
"ak": 5.664426623996462,
|
|
63
|
+
"cdr": 0.15566784512304102,
|
|
64
|
+
"bf": {
|
|
65
|
+
"ar": 0.9785478547854786,
|
|
66
|
+
"fr": 6.242728437964205
|
|
67
|
+
},
|
|
68
|
+
"fi": 3363
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
"b1Profiles": {
|
|
72
|
+
"login": {
|
|
73
|
+
"frameCount": 2,
|
|
74
|
+
"x39": 0,
|
|
75
|
+
"x50": "",
|
|
76
|
+
"generatedAtOffsetMs": 1839,
|
|
77
|
+
"secCanvas": "__SEC_CAV__1-1-1-1-1|__SEC_UD__|",
|
|
78
|
+
"timeOriginOffsetMs": -791.9,
|
|
79
|
+
"telemetryProfile": "login",
|
|
80
|
+
"telemetryTemplate": "{mt:{to:__TIME_ORIGIN__},m:{},k:{},p:{ulr:0,rs:1,ps:1,f:1},st:{h:0,f:1,kr:0},ft:{ae:null,ak:null,cdr:null,bf:null,fi:null}}",
|
|
81
|
+
"x37": "0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|1|0|0|0|0|0",
|
|
82
|
+
"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",
|
|
83
|
+
"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",
|
|
84
|
+
"evidence": "Fresh isolated PC login page6 webprofile collector on 2026-07-19"
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"webProfile": {
|
|
88
|
+
"algorithm": "base64-des-ecb-zero-padding-hex",
|
|
89
|
+
"i12Seed": 70,
|
|
90
|
+
"i12DynamicIndexes": [],
|
|
91
|
+
"telemetryFi": 326,
|
|
92
|
+
"timeOriginOffsetMs": -791.9,
|
|
93
|
+
"telemetryTemplate": "{mt:{to:__TIME_ORIGIN__},m:{},k:{},p:{ulr:0,rs:1,ps:1,f:1},st:{h:0,f:1,kr:0},ft:{ae:null,ak:null,cdr:null,bf:null,fi:null}}",
|
|
94
|
+
"fields": {
|
|
95
|
+
"x1": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/152.0.0.0 Safari/537.36",
|
|
96
|
+
"x2": "false",
|
|
97
|
+
"x3": "zh-CN",
|
|
98
|
+
"x4": "24",
|
|
99
|
+
"x5": "32",
|
|
100
|
+
"x6": "24",
|
|
101
|
+
"x7": "Google Inc. (NVIDIA),ANGLE (NVIDIA, NVIDIA GeForce RTX 5060 Ti (0x00002D04) Direct3D11 vs_5_0 ps_5_0, D3D11)",
|
|
102
|
+
"x8": "20",
|
|
103
|
+
"x9": "2560;1440",
|
|
104
|
+
"x10": "2560;1392",
|
|
105
|
+
"x11": "-480",
|
|
106
|
+
"x12": "Asia/Shanghai",
|
|
107
|
+
"x13": "true",
|
|
108
|
+
"x14": "true",
|
|
109
|
+
"x15": "true",
|
|
110
|
+
"x16": "false",
|
|
111
|
+
"x17": "false",
|
|
112
|
+
"x18": "un",
|
|
113
|
+
"x19": "Win32",
|
|
114
|
+
"x20": "un",
|
|
115
|
+
"x21": "PDF Viewer,Chrome PDF Viewer,Chromium PDF Viewer,Microsoft Edge PDF Viewer,WebKit built-in PDF",
|
|
116
|
+
"x22": "c8e2f6ff2a07957f70a18cde6b905ebb",
|
|
117
|
+
"x23": "false",
|
|
118
|
+
"x24": "false",
|
|
119
|
+
"x25": "false",
|
|
120
|
+
"x26": "false",
|
|
121
|
+
"x27": "false",
|
|
122
|
+
"x28": "10,false,false",
|
|
123
|
+
"x29": "4,7,8",
|
|
124
|
+
"x30": "swf object not loaded",
|
|
125
|
+
"x31": "124.04347527516074",
|
|
126
|
+
"x33": "0",
|
|
127
|
+
"x34": "0",
|
|
128
|
+
"x35": "0",
|
|
129
|
+
"x36": "2",
|
|
130
|
+
"x37": "0|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|1|0|0|0|0|0",
|
|
131
|
+
"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",
|
|
132
|
+
"x39": "0",
|
|
133
|
+
"x40": "0",
|
|
134
|
+
"x41": "0",
|
|
135
|
+
"x42": "3.5.4",
|
|
136
|
+
"x43": "Canvas not supported",
|
|
137
|
+
"x44": "1784388700729",
|
|
138
|
+
"x45": "__SEC_CAV__1-1-1-1-1|__SEC_UD__|",
|
|
139
|
+
"x46": "false",
|
|
140
|
+
"x47": "1|0|0|0|0|0",
|
|
141
|
+
"x48": "",
|
|
142
|
+
"x49": "{list:[],type:}",
|
|
143
|
+
"x50": "",
|
|
144
|
+
"x51": "",
|
|
145
|
+
"x52": "",
|
|
146
|
+
"x54": "11311144241322244122",
|
|
147
|
+
"x55": "280,300,280,260,280,280,260,280,240,280,280,340,260,320",
|
|
148
|
+
"x56": "Google Inc. (NVIDIA)|ANGLE (NVIDIA, NVIDIA GeForce RTX 5060 Ti (0x00002D04) Direct3D11 vs_5_0 ps_5_0, D3D11)|0ebc53d03ea89d69525d81de558e2544|35",
|
|
149
|
+
"x53": "993da9a681fd3994c9f53de11f2903b3",
|
|
150
|
+
"x57": "ets=1784388696387; domain=.xiaohongshu.com; path=/; max-age=2592000",
|
|
151
|
+
"x58": "251",
|
|
152
|
+
"x59": "47",
|
|
153
|
+
"x60": "63",
|
|
154
|
+
"x61": "1352",
|
|
155
|
+
"x62": "2047",
|
|
156
|
+
"x63": "0",
|
|
157
|
+
"x64": "0",
|
|
158
|
+
"x65": "0",
|
|
159
|
+
"x66": {
|
|
160
|
+
"referer": "",
|
|
161
|
+
"location": "https://www.xiaohongshu.com/explore",
|
|
162
|
+
"frame": 0
|
|
163
|
+
},
|
|
164
|
+
"x67": "1|0",
|
|
165
|
+
"x68": "0",
|
|
166
|
+
"x69": "un",
|
|
167
|
+
"x70": [
|
|
168
|
+
"location",
|
|
169
|
+
"getElementById",
|
|
170
|
+
"getElementsByTagName",
|
|
171
|
+
"querySelector",
|
|
172
|
+
"querySelectorAll",
|
|
173
|
+
"evaluate"
|
|
174
|
+
],
|
|
175
|
+
"x71": "true",
|
|
176
|
+
"x72": "complete",
|
|
177
|
+
"x73": "1800",
|
|
178
|
+
"x74": "0|0|0",
|
|
179
|
+
"x75": "Google Inc.",
|
|
180
|
+
"x76": "true",
|
|
181
|
+
"x77": "1|1|1|1|1|1|1|1|1|1",
|
|
182
|
+
"x78": {
|
|
183
|
+
"x": 0,
|
|
184
|
+
"y": 2598.9375,
|
|
185
|
+
"left": 0,
|
|
186
|
+
"right": 290.828125,
|
|
187
|
+
"bottom": 2616.9375,
|
|
188
|
+
"height": 18,
|
|
189
|
+
"top": 2598.9375,
|
|
190
|
+
"width": 290.828125,
|
|
191
|
+
"font": "system-ui, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\", -apple-system, \"Segoe UI\", Roboto, Ubuntu, Cantarell, \"Noto Sans\", sans-serif, BlinkMacSystemFont, \"Helvetica Neue\", Arial, \"PingFang SC\", \"PingFang TC\", \"PingFang HK\", \"Microsoft Yahei\", \"Microsoft JhengHei\""
|
|
192
|
+
},
|
|
193
|
+
"x79": "14442|6442465386",
|
|
194
|
+
"x80": "1|[object FileSystemDirectoryHandle]",
|
|
195
|
+
"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",
|
|
196
|
+
"x83": "eyJkIjp7IjAiOjEzMiwiMSI6MTYyLCIyIjoxMDksIjMiOjExNiwiNCI6MTI5LCI1IjoxNjIsIjYiOjExNiwiNyI6MTExLCI4IjoyMDMsIjkiOjY2LCIxMCI6MTIxLCIxMSI6MjQ3LCIxMiI6MTU4LCIxMyI6MTQ0LCIxNCI6MTQ1LCIxNSI6ODEsIjE2IjoxNTQsIjE3IjoxNjEsIjE4IjoxMDksIjE5IjoxMjgsIjIwIjoxNjEsIjIxIjoxMDcsIjIyIjoxMjgsIjIzIjoxNjEsIjI0IjoxMTIsIjI1IjoxMzIsIjI2IjoxNjMsIjI3IjoxMTcsIjI4IjoxMDgsIjI5IjoxMTQsIjMwIjoxNDQsIjMxIjoxNjIsIjMyIjoxMTQsIjMzIjoxMTUsIjM0IjoxNDUsIjM1IjoxMzEsIjM2IjoxNjIsIjM3IjoxMTYsIjM4IjoxMTUsIjM5IjoyMDUsIjQwIjoyLCI0MSI6MTUwLCI0MiI6MTYxLCI0MyI6MTA0LCI0NCI6MTk0LCI0NSI6MTYxLCI0NiI6MTAyLCI0NyI6MTk1LCI0OCI6MTYyLCI0OSI6MTEyLCI1MCI6MTE1LCI1MSI6MTQ1LCI1MiI6MTMxLCI1MyI6MTYyLCI1NCI6MTE2LCI1NSI6MTE1LCI1NiI6MjA1LCI1NyI6NSwiNTgiOjU1LCI1OSI6MTYxLCI2MCI6MTA0LCI2MSI6MTk0LCI2MiI6MTYxLCI2MyI6MTAyLCI2NCI6MTk1LCI2NSI6MTYxLCI2NiI6MTAyLCI2NyI6MTQ1LCI2OCI6MTMxLCI2OSI6MTYyLCI3MCI6MTE2LCI3MSI6MTE1LCI3MiI6MjA1LCI3MyI6NywiNzQiOjU3LCI3NSI6MTYxLCI3NiI6MTA0LCI3NyI6MTk0LCI3OCI6MTYxLCI3OSI6MTAyLCI4MCI6MTk1fSwidiI6MSwiZSI6Im0ifQ==",
|
|
197
|
+
"x84": "{mt:{to:1784456743189.1},m:{},k:{},p:{ulr:0,rs:1,ps:1,f:1},st:{h:0,f:1,kr:0},ft:{ae:null,ak:null,cdr:null,bf:null,fi:null}}"
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
"mnsStages": {
|
|
201
|
+
"security": {
|
|
202
|
+
"tier": "0201",
|
|
203
|
+
"envConst": 1315,
|
|
204
|
+
"envFpTailHex": "f8536767c9b581635e0744fa8415",
|
|
205
|
+
"evidence": "cold-start seq 1-4, four browser fixtures byte-exact"
|
|
206
|
+
},
|
|
207
|
+
"coldContent": {
|
|
208
|
+
"tier": "0101",
|
|
209
|
+
"envConst": 1327,
|
|
210
|
+
"envFpTailHex": "f9536767c9b581635e0744fa8415",
|
|
211
|
+
"evidence": "cold-start seq 5-10, six browser fixtures byte-exact"
|
|
212
|
+
},
|
|
213
|
+
"steadyContent": {
|
|
214
|
+
"tier": "0301",
|
|
215
|
+
"envConst": 1352,
|
|
216
|
+
"envFpTailHex": "f9416767c9b581635e0744fa8415",
|
|
217
|
+
"evidence": "Fresh isolated PC login page6 webprofile x61; runtime-state dependent"
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
"loginMnsProfiles": {
|
|
221
|
+
"security_initial": {
|
|
222
|
+
"tier": "0201",
|
|
223
|
+
"envConst": 1322,
|
|
224
|
+
"envFpTailHex": "f8536767c9b581635e0744fa8415",
|
|
225
|
+
"evidence": "Fresh isolated Chrome 152 PC login security chain, 2026-09-06"
|
|
226
|
+
},
|
|
227
|
+
"security_callback": {
|
|
228
|
+
"tier": "0101",
|
|
229
|
+
"envConst": 1332,
|
|
230
|
+
"envFpTailHex": "f9526767c9b581635e0744fa8415",
|
|
231
|
+
"evidence": "Fresh isolated Chrome 152 PC seccallback, 2026-09-06"
|
|
232
|
+
},
|
|
233
|
+
"activate": {
|
|
234
|
+
"tier": "0101",
|
|
235
|
+
"envConst": 1335,
|
|
236
|
+
"envFpTailHex": "f9526767c9b581635e0744fa8415",
|
|
237
|
+
"evidence": "Fresh isolated Chrome 152 PC login activation, 2026-09-06"
|
|
238
|
+
},
|
|
239
|
+
"qrcode_create": {
|
|
240
|
+
"tier": "0301",
|
|
241
|
+
"envConst": 1350,
|
|
242
|
+
"envFpTailHex": "f9416767c9b581635e0744fa8415",
|
|
243
|
+
"evidence": "Fresh isolated Chrome 152 PC QR creation, 2026-09-06"
|
|
244
|
+
},
|
|
245
|
+
"qrcode_poll": {
|
|
246
|
+
"tier": "0301",
|
|
247
|
+
"envConst": 1351,
|
|
248
|
+
"envFpTailHex": "f9416767c9b581635e0744fa8415",
|
|
249
|
+
"evidence": "Fresh isolated Chrome 152 PC QR polling, 2026-09-06"
|
|
250
|
+
},
|
|
251
|
+
"webprofile": {
|
|
252
|
+
"tier": "0301",
|
|
253
|
+
"envConst": 1358,
|
|
254
|
+
"envFpTailHex": "f9416767c9b581635e0744fa8415",
|
|
255
|
+
"evidence": "Fresh isolated Chrome 152 PC webprofile, 2026-09-06"
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
"rap": {
|
|
259
|
+
"fingerprintVersion": 10301,
|
|
260
|
+
"fingerprintTemplate": "rap_fingerprint_template.json"
|
|
261
|
+
}
|
|
262
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const crypto = require('crypto');
|
|
4
|
+
|
|
5
|
+
const X25519_PKCS8_PREFIX = Buffer.from('302e020100300506032b656e04220420', 'hex');
|
|
6
|
+
const X25519_SPKI_PREFIX = Buffer.from('302a300506032b656e032100', 'hex');
|
|
7
|
+
const SERVER_PUBLIC_KEY = Buffer.from(
|
|
8
|
+
'Kr0iygsCu3inYJNXCL4k4JuzaYQ2afI1xbwc7BH6sm8=',
|
|
9
|
+
'base64',
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
function privateKeyFromRaw(raw) {
|
|
13
|
+
const value = Buffer.from(raw);
|
|
14
|
+
if (value.length !== 32) throw new Error('X25519 private key must be 32 bytes');
|
|
15
|
+
return crypto.createPrivateKey({
|
|
16
|
+
key: Buffer.concat([X25519_PKCS8_PREFIX, value]),
|
|
17
|
+
format: 'der',
|
|
18
|
+
type: 'pkcs8',
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function publicKeyFromRaw(raw) {
|
|
23
|
+
const value = Buffer.from(raw);
|
|
24
|
+
if (value.length !== 32) throw new Error('X25519 public key must be 32 bytes');
|
|
25
|
+
return crypto.createPublicKey({
|
|
26
|
+
key: Buffer.concat([X25519_SPKI_PREFIX, value]),
|
|
27
|
+
format: 'der',
|
|
28
|
+
type: 'spki',
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function createHandshake() {
|
|
33
|
+
const { privateKey, publicKey } = crypto.generateKeyPairSync('x25519');
|
|
34
|
+
const privateDer = privateKey.export({ format: 'der', type: 'pkcs8' });
|
|
35
|
+
const publicDer = publicKey.export({ format: 'der', type: 'spki' });
|
|
36
|
+
return {
|
|
37
|
+
private_key_base64: privateDer.subarray(-32).toString('base64'),
|
|
38
|
+
client_public_key_base64: publicDer.subarray(-32).toString('base64'),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function acceptSsk(privateKeyBase64, encryptedSskBase64, serverPublicKey = SERVER_PUBLIC_KEY) {
|
|
43
|
+
const privateKey = privateKeyFromRaw(Buffer.from(String(privateKeyBase64), 'base64'));
|
|
44
|
+
const publicKey = publicKeyFromRaw(Buffer.from(serverPublicKey));
|
|
45
|
+
const sharedSecret = crypto.diffieHellman({ privateKey, publicKey });
|
|
46
|
+
const encrypted = Buffer.from(String(encryptedSskBase64), 'base64');
|
|
47
|
+
if (encrypted.length < 12 + 16) throw new Error('encrypted SSK is truncated');
|
|
48
|
+
const nonce = encrypted.subarray(0, 12);
|
|
49
|
+
const payload = encrypted.subarray(12);
|
|
50
|
+
const ciphertext = payload.subarray(0, -16);
|
|
51
|
+
const tag = payload.subarray(-16);
|
|
52
|
+
const decipher = crypto.createDecipheriv('aes-256-gcm', sharedSecret, nonce);
|
|
53
|
+
decipher.setAuthTag(tag);
|
|
54
|
+
const plain = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
55
|
+
if (plain.length < 32) throw new Error('decrypted SSK is too short');
|
|
56
|
+
return plain.toString('base64');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function main() {
|
|
60
|
+
const input = JSON.parse(process.argv[2] || '{}');
|
|
61
|
+
if (input.action === 'create') {
|
|
62
|
+
process.stdout.write(JSON.stringify(createHandshake()) + '\n');
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (input.action === 'accept') {
|
|
66
|
+
process.stdout.write(JSON.stringify({
|
|
67
|
+
ssk_base64: acceptSsk(input.private_key_base64, input.encrypted_ssk_base64),
|
|
68
|
+
}) + '\n');
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
throw new Error('action must be create or accept');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (require.main === module) main();
|
|
75
|
+
|
|
76
|
+
module.exports = {
|
|
77
|
+
SERVER_PUBLIC_KEY,
|
|
78
|
+
createHandshake,
|
|
79
|
+
acceptSsk,
|
|
80
|
+
privateKeyFromRaw,
|
|
81
|
+
publicKeyFromRaw,
|
|
82
|
+
};
|