@melandlabs/integrations-telegram 0.1.0

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,671 @@
1
+ import { Buffer } from 'buffer';
2
+ import * as crypto from 'crypto';
3
+ import * as fs from 'fs';
4
+ import * as path from 'path';
5
+
6
+ var __defProp = Object.defineProperty;
7
+ var __getOwnPropNames = Object.getOwnPropertyNames;
8
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
9
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
10
+ }) : x)(function(x) {
11
+ if (typeof require !== "undefined") return require.apply(this, arguments);
12
+ throw Error('Dynamic require of "' + x + '" is not supported');
13
+ });
14
+ var __esm = (fn, res) => function __init() {
15
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
16
+ };
17
+ var __export = (target, all) => {
18
+ for (var name in all)
19
+ __defProp(target, name, { get: all[name], enumerable: true });
20
+ };
21
+ function xorBuffer(a, b) {
22
+ for (let i = 0; i < a.length; i++) {
23
+ a.writeUInt8(a.readUInt8(i) ^ b.readUInt8(i), i);
24
+ }
25
+ }
26
+ function igeCrypt(buffer, aesKey, aesIv, isEncrypt) {
27
+ const cipher = crypto.createDecipheriv("aes-256-ecb", aesKey, null);
28
+ cipher.setAutoPadding(false);
29
+ const result = Buffer.allocUnsafe(buffer.length);
30
+ let prevCipherblock;
31
+ let prevPlainblock;
32
+ {
33
+ prevCipherblock = aesIv.subarray(16, 32);
34
+ prevPlainblock = aesIv.subarray(0, 16);
35
+ }
36
+ const current = Buffer.allocUnsafe(16);
37
+ for (let offset = 0; offset < buffer.length; offset += 16) {
38
+ const chunk = buffer.subarray(offset, offset + 16);
39
+ chunk.copy(current);
40
+ xorBuffer(current, prevCipherblock);
41
+ const crypted = Buffer.from(cipher.update(current));
42
+ xorBuffer(crypted, prevPlainblock);
43
+ crypted.copy(result, offset);
44
+ prevCipherblock = crypted;
45
+ prevPlainblock = chunk;
46
+ }
47
+ cipher.final();
48
+ return result;
49
+ }
50
+ function createLocalKey(passcode, salt) {
51
+ const iterations = passcode.length > 0 ? kStrongIterationsCount : 1;
52
+ const password = crypto.createHash("sha512");
53
+ password.update(salt);
54
+ password.update(passcode);
55
+ password.update(salt);
56
+ return crypto.pbkdf2Sync(password.digest(), salt, iterations, 256, "sha512");
57
+ }
58
+ function createLegacyLocalKey(passcode, salt) {
59
+ const iterations = passcode.length > 0 ? LocalEncryptIterCount : LocalEncryptNoPwdIterCount;
60
+ return crypto.pbkdf2Sync(passcode, salt, iterations, 256, "sha1");
61
+ }
62
+ function decryptLocal(encryptedMsg, localKey) {
63
+ const msgKey = encryptedMsg.subarray(0, 16);
64
+ const encryptedData = encryptedMsg.subarray(16);
65
+ const decrypted = aesDecryptLocal(encryptedData, msgKey, localKey);
66
+ const sha1 = crypto.createHash("sha1");
67
+ sha1.update(decrypted);
68
+ const calculatedMsgKey = sha1.digest().subarray(0, 16);
69
+ if (calculatedMsgKey.compare(msgKey) !== 0) {
70
+ throw new CryptoException("bad decrypt key, data not decrypted - incorrect password");
71
+ }
72
+ const length = decrypted.readUInt32LE(0);
73
+ if (length > decrypted.length) {
74
+ throw new CryptoException(`corrupted data. wrong length: ${length}`);
75
+ }
76
+ return decrypted.subarray(4, 4 + length);
77
+ }
78
+ function aesDecryptLocal(encryptedData, msgKey, localKey) {
79
+ const { aesKey, aesIv } = prepareAesOldMtp(localKey, msgKey, false);
80
+ return igeCrypt(encryptedData, aesKey, aesIv);
81
+ }
82
+ function prepareAesOldMtp(localKey, msgKey, send = false) {
83
+ const x = send ? 0 : 8;
84
+ const keyPos = (pos, size) => {
85
+ return localKey.subarray(pos, pos + size);
86
+ };
87
+ const dataA = Buffer.concat([msgKey, keyPos(x, 32)]);
88
+ const dataB = Buffer.concat([keyPos(x + 32, 16), msgKey, keyPos(x + 48, 16)]);
89
+ const dataC = Buffer.concat([keyPos(x + 64, 32), msgKey]);
90
+ const dataD = Buffer.concat([msgKey, keyPos(x + 96, 32)]);
91
+ const sha1A = crypto.createHash("sha1").update(dataA).digest();
92
+ const sha1B = crypto.createHash("sha1").update(dataB).digest();
93
+ const sha1C = crypto.createHash("sha1").update(dataC).digest();
94
+ const sha1D = crypto.createHash("sha1").update(dataD).digest();
95
+ const aesKey = Buffer.concat([sha1A.subarray(0, 8), sha1B.subarray(8, 20), sha1C.subarray(4, 16)]);
96
+ const aesIv = Buffer.concat([
97
+ sha1A.subarray(8, 20),
98
+ sha1B.subarray(0, 8),
99
+ sha1C.subarray(16, 20),
100
+ sha1D.subarray(0, 8)
101
+ ]);
102
+ return { aesKey, aesIv };
103
+ }
104
+ var LocalEncryptNoPwdIterCount, LocalEncryptIterCount, kStrongIterationsCount, CryptoException;
105
+ var init_crypto = __esm({
106
+ "src/tdata-decrypter/crypto.ts"() {
107
+ LocalEncryptNoPwdIterCount = 4;
108
+ LocalEncryptIterCount = 400;
109
+ kStrongIterationsCount = 1e5;
110
+ CryptoException = class extends Error {
111
+ constructor(message) {
112
+ super(message);
113
+ this.name = "CryptoException";
114
+ }
115
+ };
116
+ }
117
+ });
118
+ function readBytes(buffer, offset, size) {
119
+ if (offset + size > buffer.length) {
120
+ throw new Error(`Cannot read ${size} bytes at offset ${offset}, buffer length is ${buffer.length}`);
121
+ }
122
+ return buffer.subarray(offset, offset + size);
123
+ }
124
+ function readQtInteger(buffer, offset, size, signed) {
125
+ const value = readBytes(buffer, offset, size);
126
+ const hex = value.toString("hex");
127
+ let num = BigInt(`0x${hex}`);
128
+ if (signed && num >= BigInt(2) ** BigInt(size * 8 - 1)) {
129
+ num -= BigInt(2) ** BigInt(size * 8);
130
+ }
131
+ return Number(num);
132
+ }
133
+ function readQtInt32(buffer, offset) {
134
+ return readQtInteger(buffer, offset, 4, true);
135
+ }
136
+ function readQtUint32(buffer, offset) {
137
+ return readQtInteger(buffer, offset, 4, false);
138
+ }
139
+ function readQtInt64(buffer, offset) {
140
+ return readQtInteger(buffer, offset, 8, true);
141
+ }
142
+ function readQtUint64(buffer, offset) {
143
+ return readQtInteger(buffer, offset, 8, false);
144
+ }
145
+ function readQtByteArray(buffer, offset) {
146
+ const length = readQtInt32(buffer, offset);
147
+ let newOffset = offset + 4;
148
+ if (length <= 0) {
149
+ return { value: Buffer.alloc(0), newOffset };
150
+ }
151
+ const value = readBytes(buffer, newOffset, length);
152
+ newOffset += length;
153
+ return { value, newOffset };
154
+ }
155
+ function readQtUtf8(buffer, offset) {
156
+ const { value, newOffset } = readQtByteArray(buffer, offset);
157
+ const str = value.toString("utf16le");
158
+ return { value: str, newOffset };
159
+ }
160
+ var init_qt = __esm({
161
+ "src/tdata-decrypter/qt.ts"() {
162
+ }
163
+ });
164
+
165
+ // src/tdata-decrypter/settings.ts
166
+ function readSettingsBlock(version, buffer, offset, blockId) {
167
+ switch (blockId) {
168
+ case 6 /* dbiAutoStart */:
169
+ case 7 /* dbiStartMinimized */:
170
+ case 29 /* dbiSendToMenu */:
171
+ case 10 /* dbiSeenTrayTooltip */:
172
+ case 12 /* dbiAutoUpdate */: {
173
+ const value = readQtInt32(buffer, offset) === 1;
174
+ return { value, newOffset: offset + 4 };
175
+ }
176
+ case 41 /* dbiSongVolumeOld */: {
177
+ const value = readQtInt32(buffer, offset) / 1e6;
178
+ return { value, newOffset: offset + 4 };
179
+ }
180
+ case 13 /* dbiLastUpdateCheck */:
181
+ case 88 /* dbiScalePercent */:
182
+ case 87 /* dbiPowerSaving */: {
183
+ const value = readQtInt32(buffer, offset);
184
+ return { value, newOffset: offset + 4 };
185
+ }
186
+ case 96 /* dbiFallbackProductionConfig */:
187
+ case 94 /* dbiApplicationSettings */: {
188
+ const { value, newOffset } = readQtByteArray(buffer, offset);
189
+ return { value, newOffset };
190
+ }
191
+ case 35 /* dbiDialogLastPath */: {
192
+ const { value, newOffset } = readQtUtf8(buffer, offset);
193
+ return { value, newOffset };
194
+ }
195
+ case 84 /* dbiThemeKey */: {
196
+ const day = readQtUint64(buffer, offset);
197
+ const night = readQtUint64(buffer, offset + 8);
198
+ const nightMode = readQtInt32(buffer, offset + 16) === 1;
199
+ return {
200
+ value: { day, night, nightMode },
201
+ newOffset: offset + 20
202
+ };
203
+ }
204
+ case 97 /* dbiBackgroundKey */: {
205
+ const day = readQtUint64(buffer, offset);
206
+ const night = readQtUint64(buffer, offset + 8);
207
+ return {
208
+ value: { day, night },
209
+ newOffset: offset + 16
210
+ };
211
+ }
212
+ case 85 /* dbiTileBackground */: {
213
+ const day = readQtInt32(buffer, offset);
214
+ const night = readQtInt32(buffer, offset + 4);
215
+ return {
216
+ value: { day, night },
217
+ newOffset: offset + 8
218
+ };
219
+ }
220
+ case 78 /* dbiLangPackKey */: {
221
+ const value = readQtUint64(buffer, offset);
222
+ return { value, newOffset: offset + 8 };
223
+ }
224
+ case 75 /* dbiMtpAuthorization */: {
225
+ const { value, newOffset } = readQtByteArray(buffer, offset);
226
+ return { value, newOffset };
227
+ }
228
+ default:
229
+ throw new Error(`Unknown block ID while reading settings: ${blockId}`);
230
+ }
231
+ }
232
+ function readSettingsBlocks(version, buffer) {
233
+ const blocks = /* @__PURE__ */ new Map();
234
+ let offset = 0;
235
+ try {
236
+ while (offset < buffer.length) {
237
+ const blockId = readQtInt32(buffer, offset);
238
+ offset += 4;
239
+ const { value, newOffset } = readSettingsBlock(version, buffer, offset, blockId);
240
+ offset = newOffset;
241
+ blocks.set(blockId, value);
242
+ }
243
+ } catch {
244
+ }
245
+ return blocks;
246
+ }
247
+ var SettingsBlocks;
248
+ var init_settings = __esm({
249
+ "src/tdata-decrypter/settings.ts"() {
250
+ init_qt();
251
+ SettingsBlocks = /* @__PURE__ */ ((SettingsBlocks2) => {
252
+ SettingsBlocks2[SettingsBlocks2["dbiKey"] = 0] = "dbiKey";
253
+ SettingsBlocks2[SettingsBlocks2["dbiUser"] = 1] = "dbiUser";
254
+ SettingsBlocks2[SettingsBlocks2["dbiDcOptionOldOld"] = 2] = "dbiDcOptionOldOld";
255
+ SettingsBlocks2[SettingsBlocks2["dbiChatSizeMaxOld"] = 3] = "dbiChatSizeMaxOld";
256
+ SettingsBlocks2[SettingsBlocks2["dbiMutePeerOld"] = 4] = "dbiMutePeerOld";
257
+ SettingsBlocks2[SettingsBlocks2["dbiSendKeyOld"] = 5] = "dbiSendKeyOld";
258
+ SettingsBlocks2[SettingsBlocks2["dbiAutoStart"] = 6] = "dbiAutoStart";
259
+ SettingsBlocks2[SettingsBlocks2["dbiStartMinimized"] = 7] = "dbiStartMinimized";
260
+ SettingsBlocks2[SettingsBlocks2["dbiSoundFlashBounceNotifyOld"] = 8] = "dbiSoundFlashBounceNotifyOld";
261
+ SettingsBlocks2[SettingsBlocks2["dbiWorkModeOld"] = 9] = "dbiWorkModeOld";
262
+ SettingsBlocks2[SettingsBlocks2["dbiSeenTrayTooltip"] = 10] = "dbiSeenTrayTooltip";
263
+ SettingsBlocks2[SettingsBlocks2["dbiDesktopNotifyOld"] = 11] = "dbiDesktopNotifyOld";
264
+ SettingsBlocks2[SettingsBlocks2["dbiAutoUpdate"] = 12] = "dbiAutoUpdate";
265
+ SettingsBlocks2[SettingsBlocks2["dbiLastUpdateCheck"] = 13] = "dbiLastUpdateCheck";
266
+ SettingsBlocks2[SettingsBlocks2["dbiWindowPositionOld"] = 14] = "dbiWindowPositionOld";
267
+ SettingsBlocks2[SettingsBlocks2["dbiConnectionTypeOldOld"] = 15] = "dbiConnectionTypeOldOld";
268
+ SettingsBlocks2[SettingsBlocks2["dbiDefaultAttach"] = 17] = "dbiDefaultAttach";
269
+ SettingsBlocks2[SettingsBlocks2["dbiCatsAndDogsOld"] = 18] = "dbiCatsAndDogsOld";
270
+ SettingsBlocks2[SettingsBlocks2["dbiReplaceEmojiOld"] = 19] = "dbiReplaceEmojiOld";
271
+ SettingsBlocks2[SettingsBlocks2["dbiAskDownloadPathOld"] = 20] = "dbiAskDownloadPathOld";
272
+ SettingsBlocks2[SettingsBlocks2["dbiDownloadPathOldOld"] = 21] = "dbiDownloadPathOldOld";
273
+ SettingsBlocks2[SettingsBlocks2["dbiScaleOld"] = 22] = "dbiScaleOld";
274
+ SettingsBlocks2[SettingsBlocks2["dbiEmojiTabOld"] = 23] = "dbiEmojiTabOld";
275
+ SettingsBlocks2[SettingsBlocks2["dbiRecentEmojiOldOldOld"] = 24] = "dbiRecentEmojiOldOldOld";
276
+ SettingsBlocks2[SettingsBlocks2["dbiLoggedPhoneNumberOld"] = 25] = "dbiLoggedPhoneNumberOld";
277
+ SettingsBlocks2[SettingsBlocks2["dbiMutedPeersOld"] = 26] = "dbiMutedPeersOld";
278
+ SettingsBlocks2[SettingsBlocks2["dbiNotifyViewOld"] = 28] = "dbiNotifyViewOld";
279
+ SettingsBlocks2[SettingsBlocks2["dbiSendToMenu"] = 29] = "dbiSendToMenu";
280
+ SettingsBlocks2[SettingsBlocks2["dbiCompressPastedImageOld"] = 30] = "dbiCompressPastedImageOld";
281
+ SettingsBlocks2[SettingsBlocks2["dbiLangOld"] = 31] = "dbiLangOld";
282
+ SettingsBlocks2[SettingsBlocks2["dbiLangFileOld"] = 32] = "dbiLangFileOld";
283
+ SettingsBlocks2[SettingsBlocks2["dbiTileBackgroundOld"] = 33] = "dbiTileBackgroundOld";
284
+ SettingsBlocks2[SettingsBlocks2["dbiAutoLockOld"] = 34] = "dbiAutoLockOld";
285
+ SettingsBlocks2[SettingsBlocks2["dbiDialogLastPath"] = 35] = "dbiDialogLastPath";
286
+ SettingsBlocks2[SettingsBlocks2["dbiRecentEmojiOldOld"] = 36] = "dbiRecentEmojiOldOld";
287
+ SettingsBlocks2[SettingsBlocks2["dbiEmojiVariantsOldOld"] = 37] = "dbiEmojiVariantsOldOld";
288
+ SettingsBlocks2[SettingsBlocks2["dbiRecentStickers"] = 38] = "dbiRecentStickers";
289
+ SettingsBlocks2[SettingsBlocks2["dbiDcOptionOld"] = 39] = "dbiDcOptionOld";
290
+ SettingsBlocks2[SettingsBlocks2["dbiTryIPv6Old"] = 40] = "dbiTryIPv6Old";
291
+ SettingsBlocks2[SettingsBlocks2["dbiSongVolumeOld"] = 41] = "dbiSongVolumeOld";
292
+ SettingsBlocks2[SettingsBlocks2["dbiWindowsNotificationsOld"] = 48] = "dbiWindowsNotificationsOld";
293
+ SettingsBlocks2[SettingsBlocks2["dbiIncludeMutedOld"] = 49] = "dbiIncludeMutedOld";
294
+ SettingsBlocks2[SettingsBlocks2["dbiMegagroupSizeMaxOld"] = 50] = "dbiMegagroupSizeMaxOld";
295
+ SettingsBlocks2[SettingsBlocks2["dbiDownloadPathOld"] = 51] = "dbiDownloadPathOld";
296
+ SettingsBlocks2[SettingsBlocks2["dbiAutoDownloadOld"] = 52] = "dbiAutoDownloadOld";
297
+ SettingsBlocks2[SettingsBlocks2["dbiSavedGifsLimitOld"] = 53] = "dbiSavedGifsLimitOld";
298
+ SettingsBlocks2[SettingsBlocks2["dbiShowingSavedGifsOld"] = 54] = "dbiShowingSavedGifsOld";
299
+ SettingsBlocks2[SettingsBlocks2["dbiAutoPlayOld"] = 55] = "dbiAutoPlayOld";
300
+ SettingsBlocks2[SettingsBlocks2["dbiAdaptiveForWideOld"] = 56] = "dbiAdaptiveForWideOld";
301
+ SettingsBlocks2[SettingsBlocks2["dbiHiddenPinnedMessagesOld"] = 57] = "dbiHiddenPinnedMessagesOld";
302
+ SettingsBlocks2[SettingsBlocks2["dbiRecentEmojiOld"] = 58] = "dbiRecentEmojiOld";
303
+ SettingsBlocks2[SettingsBlocks2["dbiEmojiVariantsOld"] = 59] = "dbiEmojiVariantsOld";
304
+ SettingsBlocks2[SettingsBlocks2["dbiDialogsModeOld"] = 64] = "dbiDialogsModeOld";
305
+ SettingsBlocks2[SettingsBlocks2["dbiModerateModeOld"] = 65] = "dbiModerateModeOld";
306
+ SettingsBlocks2[SettingsBlocks2["dbiVideoVolumeOld"] = 66] = "dbiVideoVolumeOld";
307
+ SettingsBlocks2[SettingsBlocks2["dbiStickersRecentLimitOld"] = 67] = "dbiStickersRecentLimitOld";
308
+ SettingsBlocks2[SettingsBlocks2["dbiNativeNotificationsOld"] = 68] = "dbiNativeNotificationsOld";
309
+ SettingsBlocks2[SettingsBlocks2["dbiNotificationsCountOld"] = 69] = "dbiNotificationsCountOld";
310
+ SettingsBlocks2[SettingsBlocks2["dbiNotificationsCornerOld"] = 70] = "dbiNotificationsCornerOld";
311
+ SettingsBlocks2[SettingsBlocks2["dbiThemeKeyOld"] = 71] = "dbiThemeKeyOld";
312
+ SettingsBlocks2[SettingsBlocks2["dbiDialogsWidthRatioOld"] = 72] = "dbiDialogsWidthRatioOld";
313
+ SettingsBlocks2[SettingsBlocks2["dbiUseExternalVideoPlayerOld"] = 73] = "dbiUseExternalVideoPlayerOld";
314
+ SettingsBlocks2[SettingsBlocks2["dbiDcOptionsOld"] = 74] = "dbiDcOptionsOld";
315
+ SettingsBlocks2[SettingsBlocks2["dbiMtpAuthorization"] = 75] = "dbiMtpAuthorization";
316
+ SettingsBlocks2[SettingsBlocks2["dbiLastSeenWarningSeenOld"] = 76] = "dbiLastSeenWarningSeenOld";
317
+ SettingsBlocks2[SettingsBlocks2["dbiSessionSettings"] = 77] = "dbiSessionSettings";
318
+ SettingsBlocks2[SettingsBlocks2["dbiLangPackKey"] = 78] = "dbiLangPackKey";
319
+ SettingsBlocks2[SettingsBlocks2["dbiConnectionTypeOld"] = 79] = "dbiConnectionTypeOld";
320
+ SettingsBlocks2[SettingsBlocks2["dbiStickersFavedLimitOld"] = 80] = "dbiStickersFavedLimitOld";
321
+ SettingsBlocks2[SettingsBlocks2["dbiSuggestStickersByEmojiOld"] = 81] = "dbiSuggestStickersByEmojiOld";
322
+ SettingsBlocks2[SettingsBlocks2["dbiSuggestEmojiOld"] = 82] = "dbiSuggestEmojiOld";
323
+ SettingsBlocks2[SettingsBlocks2["dbiTxtDomainStringOldOld"] = 83] = "dbiTxtDomainStringOldOld";
324
+ SettingsBlocks2[SettingsBlocks2["dbiThemeKey"] = 84] = "dbiThemeKey";
325
+ SettingsBlocks2[SettingsBlocks2["dbiTileBackground"] = 85] = "dbiTileBackground";
326
+ SettingsBlocks2[SettingsBlocks2["dbiCacheSettingsOld"] = 86] = "dbiCacheSettingsOld";
327
+ SettingsBlocks2[SettingsBlocks2["dbiPowerSaving"] = 87] = "dbiPowerSaving";
328
+ SettingsBlocks2[SettingsBlocks2["dbiScalePercent"] = 88] = "dbiScalePercent";
329
+ SettingsBlocks2[SettingsBlocks2["dbiPlaybackSpeedOld"] = 89] = "dbiPlaybackSpeedOld";
330
+ SettingsBlocks2[SettingsBlocks2["dbiLanguagesKey"] = 90] = "dbiLanguagesKey";
331
+ SettingsBlocks2[SettingsBlocks2["dbiCallSettingsOld"] = 91] = "dbiCallSettingsOld";
332
+ SettingsBlocks2[SettingsBlocks2["dbiCacheSettings"] = 92] = "dbiCacheSettings";
333
+ SettingsBlocks2[SettingsBlocks2["dbiTxtDomainStringOld"] = 93] = "dbiTxtDomainStringOld";
334
+ SettingsBlocks2[SettingsBlocks2["dbiApplicationSettings"] = 94] = "dbiApplicationSettings";
335
+ SettingsBlocks2[SettingsBlocks2["dbiDialogsFiltersOld"] = 95] = "dbiDialogsFiltersOld";
336
+ SettingsBlocks2[SettingsBlocks2["dbiFallbackProductionConfig"] = 96] = "dbiFallbackProductionConfig";
337
+ SettingsBlocks2[SettingsBlocks2["dbiBackgroundKey"] = 97] = "dbiBackgroundKey";
338
+ SettingsBlocks2[SettingsBlocks2["dbiEncryptedWithSalt"] = 333] = "dbiEncryptedWithSalt";
339
+ SettingsBlocks2[SettingsBlocks2["dbiEncrypted"] = 444] = "dbiEncrypted";
340
+ SettingsBlocks2[SettingsBlocks2["dbiVersion"] = 666] = "dbiVersion";
341
+ return SettingsBlocks2;
342
+ })(SettingsBlocks || {});
343
+ }
344
+ });
345
+ function decryptSettingsTdf(settingsTdf) {
346
+ const encryptedData = settingsTdf.encryptedData;
347
+ let offset = 0;
348
+ const { value: salt, newOffset: offset1 } = readQtByteArray(encryptedData, offset);
349
+ offset = offset1;
350
+ const { value: encryptedSettings, newOffset: _ } = readQtByteArray(encryptedData, offset);
351
+ const settingsKey = createLegacyLocalKey(Buffer.alloc(0), salt);
352
+ return decryptLocal(encryptedSettings, settingsKey);
353
+ }
354
+ function decryptKeyDataTdf(passcode, keyDataTdf) {
355
+ const stream = keyDataTdf.encryptedData;
356
+ let offset = 0;
357
+ const { value: salt, newOffset: offset1 } = readQtByteArray(stream, offset);
358
+ offset = offset1;
359
+ const { value: keyEncrypted, newOffset: offset2 } = readQtByteArray(stream, offset);
360
+ offset = offset2;
361
+ const { value: infoEncrypted, newOffset: _ } = readQtByteArray(stream, offset);
362
+ const passcodeKey = createLocalKey(passcode, salt);
363
+ const localKey = decryptLocal(keyEncrypted, passcodeKey);
364
+ const infoDecrypted = decryptLocal(infoEncrypted, localKey);
365
+ return [localKey, infoDecrypted];
366
+ }
367
+ function readKeyDataAccounts(data) {
368
+ let offset = 0;
369
+ const count = data.readInt32BE(offset);
370
+ offset += 4;
371
+ const indexes = [];
372
+ for (let i = 0; i < count; i++) {
373
+ const index = data.readInt32BE(offset);
374
+ offset += 4;
375
+ indexes.push(index);
376
+ }
377
+ const mainAccount = data.readInt32BE(offset);
378
+ return [indexes, mainAccount];
379
+ }
380
+ var init_storage = __esm({
381
+ "src/tdata-decrypter/storage.ts"() {
382
+ init_crypto();
383
+ init_qt();
384
+ }
385
+ });
386
+ function parseRawTdf(data) {
387
+ if (data.subarray(0, 4).compare(TDF_MAGIC) !== 0) {
388
+ throw new WrongMagicTdfParserError();
389
+ }
390
+ const version = data.readUInt32LE(4);
391
+ const encryptedData = data.subarray(8, data.length - 16);
392
+ const hashsum = data.subarray(data.length - 16);
393
+ const actualMd5 = crypto.createHash("md5");
394
+ actualMd5.update(encryptedData);
395
+ const lengthBuffer = Buffer.allocUnsafe(4);
396
+ lengthBuffer.writeUInt32LE(encryptedData.length, 0);
397
+ actualMd5.update(lengthBuffer);
398
+ const versionBuffer = Buffer.allocUnsafe(4);
399
+ versionBuffer.writeUInt32LE(version, 0);
400
+ actualMd5.update(versionBuffer);
401
+ actualMd5.update(TDF_MAGIC);
402
+ const actualMd5Digest = actualMd5.digest();
403
+ if (actualMd5Digest.compare(hashsum) !== 0) {
404
+ throw new WrongHashsumTdfParserError();
405
+ }
406
+ return {
407
+ version,
408
+ encryptedData,
409
+ hashsum
410
+ };
411
+ }
412
+ function readTdfFile(filepath) {
413
+ const candidates = [`${filepath}s`, filepath];
414
+ for (const candidate of candidates) {
415
+ try {
416
+ const data = fs.readFileSync(candidate);
417
+ return parseRawTdf(data);
418
+ } catch (error) {
419
+ if (error.code !== "ENOENT") {
420
+ throw error;
421
+ }
422
+ }
423
+ }
424
+ throw new Error(`TDF file not found: ${filepath}`);
425
+ }
426
+ var TDF_MAGIC, TdfParserError, WrongMagicTdfParserError, WrongHashsumTdfParserError;
427
+ var init_tdf = __esm({
428
+ "src/tdata-decrypter/tdf.ts"() {
429
+ TDF_MAGIC = Buffer.from("TDF$", "ascii");
430
+ TdfParserError = class extends Error {
431
+ constructor(message) {
432
+ super(message);
433
+ this.name = "TdfParserError";
434
+ }
435
+ };
436
+ WrongMagicTdfParserError = class extends TdfParserError {
437
+ constructor(message = "Wrong magic. Not a TDF file?") {
438
+ super(message);
439
+ this.name = "WrongMagicTdfParserError";
440
+ }
441
+ };
442
+ WrongHashsumTdfParserError = class extends TdfParserError {
443
+ constructor(message = "Wrong hashsum. Corrupted file?") {
444
+ super(message);
445
+ this.name = "WrongHashsumTdfParserError";
446
+ }
447
+ };
448
+ }
449
+ });
450
+
451
+ // src/tdata-decrypter/decrypter.ts
452
+ var decrypter_exports = {};
453
+ __export(decrypter_exports, {
454
+ TdataReader: () => TdataReader
455
+ });
456
+ function fileKeyToStr(fileKey) {
457
+ let result = "";
458
+ for (const b of fileKey) {
459
+ const hex = b.toString(16).toUpperCase();
460
+ const padded = hex.length === 1 ? `0${hex}` : hex;
461
+ result += padded[1] + padded[0];
462
+ }
463
+ return result;
464
+ }
465
+ function computeDataNameKey(dataName) {
466
+ const fileKey = crypto.createHash("md5").update(dataName, "utf8").digest().subarray(0, 8);
467
+ return fileKeyToStr(fileKey);
468
+ }
469
+ function composeAccountName(dataName, index) {
470
+ if (index > 0) {
471
+ return `${dataName}#${index + 1}`;
472
+ }
473
+ return dataName;
474
+ }
475
+ function readMtpAuthorization(buffer) {
476
+ let offset = 0;
477
+ const legacyUserId = readQtInt32(buffer, offset);
478
+ const legacyMainDcId = readQtInt32(buffer, offset + 4);
479
+ offset += 8;
480
+ let userId;
481
+ let mainDcId;
482
+ if (legacyUserId === -1 && legacyMainDcId === -1) {
483
+ userId = Number(readQtUint64(buffer, offset));
484
+ offset += 8;
485
+ mainDcId = readQtInt32(buffer, offset);
486
+ offset += 4;
487
+ } else {
488
+ userId = legacyUserId;
489
+ mainDcId = legacyMainDcId;
490
+ }
491
+ const count = readQtInt32(buffer, offset);
492
+ offset += 4;
493
+ const keys = /* @__PURE__ */ new Map();
494
+ for (let i = 0; i < count; i++) {
495
+ const dcId = readQtInt32(buffer, offset);
496
+ offset += 4;
497
+ const key = Buffer.from(buffer.subarray(offset, offset + 256));
498
+ offset += 256;
499
+ keys.set(dcId, key);
500
+ }
501
+ const destroyCount = readQtInt32(buffer, offset);
502
+ offset += 4;
503
+ const keysToDestroy = /* @__PURE__ */ new Map();
504
+ for (let i = 0; i < destroyCount; i++) {
505
+ const dcId = readQtInt32(buffer, offset);
506
+ offset += 4;
507
+ const key = Buffer.from(buffer.subarray(offset, offset + 256));
508
+ offset += 256;
509
+ keysToDestroy.set(dcId, key);
510
+ }
511
+ return {
512
+ userId,
513
+ currentDcId: mainDcId,
514
+ keys,
515
+ keysToDestroy
516
+ };
517
+ }
518
+ var AccountReader, TdataReader;
519
+ var init_decrypter = __esm({
520
+ "src/tdata-decrypter/decrypter.ts"() {
521
+ init_crypto();
522
+ init_qt();
523
+ init_settings();
524
+ init_storage();
525
+ init_tdf();
526
+ AccountReader = class {
527
+ basePath;
528
+ index;
529
+ accountName;
530
+ dataNameKey;
531
+ constructor(basePath, index, dataName) {
532
+ this.basePath = basePath;
533
+ this.index = index;
534
+ this.accountName = composeAccountName(dataName, index);
535
+ this.dataNameKey = computeDataNameKey(this.accountName);
536
+ }
537
+ /**
538
+ * Read account data using local key
539
+ */
540
+ read(localKey) {
541
+ const mtpData = this.readMtpData(localKey);
542
+ return {
543
+ index: this.index,
544
+ mtpData
545
+ };
546
+ }
547
+ /**
548
+ * Read MTP data
549
+ */
550
+ readMtpData(localKey) {
551
+ const mtpDataFilePath = path.join(this.basePath, this.dataNameKey);
552
+ const tdfFile = readTdfFile(mtpDataFilePath);
553
+ const offset = 0;
554
+ const { value: encryptedData, newOffset: _ } = readQtByteArray(
555
+ Buffer.from(tdfFile.encryptedData),
556
+ offset
557
+ );
558
+ const decrypted = decryptLocal(encryptedData, localKey);
559
+ const blocks = readSettingsBlocks(tdfFile.version, decrypted);
560
+ const mtpAuth = blocks.get(75);
561
+ if (!mtpAuth || !(mtpAuth instanceof Buffer)) {
562
+ throw new Error("MTP authorization not found");
563
+ }
564
+ return readMtpAuthorization(mtpAuth);
565
+ }
566
+ };
567
+ TdataReader = class _TdataReader {
568
+ basePath;
569
+ dataName;
570
+ static DEFAULT_DATANAME = "data";
571
+ constructor(basePath, dataName) {
572
+ this.basePath = basePath;
573
+ this.dataName = dataName ?? _TdataReader.DEFAULT_DATANAME;
574
+ }
575
+ /**
576
+ * Read tdata directory
577
+ */
578
+ read(passcode) {
579
+ const settings = this.readSettings();
580
+ const [localKey, accountIndexes] = this.readKeyData(passcode ?? "");
581
+ const accounts = /* @__PURE__ */ new Map();
582
+ for (const accountIndex of accountIndexes) {
583
+ const reader = new AccountReader(this.basePath, accountIndex, this.dataName);
584
+ const account = reader.read(localKey);
585
+ accounts.set(accountIndex, account);
586
+ }
587
+ return { settings, accounts };
588
+ }
589
+ /**
590
+ * Read key data
591
+ */
592
+ readKeyData(passcode) {
593
+ const keyDataName = `key_${this.dataName}`;
594
+ const keyDataPath = path.join(this.basePath, keyDataName);
595
+ const keyDataTdf = readTdfFile(keyDataPath);
596
+ const [localKey, infoDecrypted] = decryptKeyDataTdf(Buffer.from(passcode), keyDataTdf);
597
+ const [accountIndexes, _] = readKeyDataAccounts(infoDecrypted);
598
+ return [localKey, accountIndexes];
599
+ }
600
+ /**
601
+ * Read settings
602
+ */
603
+ readSettings() {
604
+ const settingsPath = path.join(this.basePath, "settings");
605
+ const settingsTdf = readTdfFile(settingsPath);
606
+ const decrypted = settingsTdf.encryptedData;
607
+ return readSettingsBlocks(settingsTdf.version, decrypted);
608
+ }
609
+ };
610
+ }
611
+ });
612
+
613
+ // src/tdata-decrypter/index.ts
614
+ init_decrypter();
615
+ init_tdf();
616
+ init_crypto();
617
+ init_qt();
618
+ init_storage();
619
+ init_settings();
620
+ init_tdf();
621
+ init_crypto();
622
+ async function extractAuthKey(tdataPath) {
623
+ try {
624
+ const { TdataReader: TdataReader2 } = await Promise.resolve().then(() => (init_decrypter(), decrypter_exports));
625
+ let path2 = tdataPath;
626
+ if (!path2.endsWith("tdata")) {
627
+ const tdataDir = __require("path").join(tdataPath, "tdata");
628
+ if (__require("fs").existsSync(tdataDir)) {
629
+ path2 = tdataDir;
630
+ }
631
+ }
632
+ const reader = new TdataReader2(path2);
633
+ const result = reader.read();
634
+ if (!result.accounts || result.accounts.size === 0) {
635
+ return {
636
+ success: false,
637
+ error: "No accounts found in tdata. Please make sure you're logged into Telegram Desktop."
638
+ };
639
+ }
640
+ const firstAccount = result.accounts.values().next().value;
641
+ if (!firstAccount) {
642
+ return {
643
+ success: false,
644
+ error: "No accounts found in tdata."
645
+ };
646
+ }
647
+ const { mtpData } = firstAccount;
648
+ const authKeyBytes = mtpData.keys.get(mtpData.currentDcId);
649
+ if (!authKeyBytes) {
650
+ return {
651
+ success: false,
652
+ error: `No auth key found for DC ${mtpData.currentDcId}`
653
+ };
654
+ }
655
+ return {
656
+ success: true,
657
+ userId: mtpData.userId,
658
+ dcId: mtpData.currentDcId,
659
+ authKey: authKeyBytes.toString("hex")
660
+ };
661
+ } catch (error) {
662
+ return {
663
+ success: false,
664
+ error: error instanceof Error ? error.message : String(error)
665
+ };
666
+ }
667
+ }
668
+
669
+ export { CryptoException, SettingsBlocks, TDF_MAGIC, TdataReader, TdfParserError, WrongHashsumTdfParserError, WrongMagicTdfParserError, aesDecryptLocal, createLegacyLocalKey, createLocalKey, decryptKeyDataTdf, decryptLocal, decryptSettingsTdf, extractAuthKey, parseRawTdf, prepareAesOldMtp, readBytes, readKeyDataAccounts, readQtByteArray, readQtInt32, readQtInt64, readQtInteger, readQtUint32, readQtUint64, readQtUtf8, readSettingsBlock, readSettingsBlocks, readTdfFile };
670
+ //# sourceMappingURL=tdata-decrypter-index.js.map
671
+ //# sourceMappingURL=tdata-decrypter-index.js.map