teleproto 203.0.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.
- package/CryptoFile.d.ts +2 -0
- package/CryptoFile.js +23 -0
- package/Helpers.d.ts +151 -0
- package/Helpers.js +477 -0
- package/LICENSE +23 -0
- package/Password.d.ts +15 -0
- package/Password.js +271 -0
- package/README.md +111 -0
- package/Utils.d.ts +228 -0
- package/Utils.js +1248 -0
- package/Version.d.ts +1 -0
- package/Version.js +4 -0
- package/client/2fa.d.ts +48 -0
- package/client/2fa.js +109 -0
- package/client/TelegramClient.d.ts +1042 -0
- package/client/TelegramClient.js +1167 -0
- package/client/account.d.ts +0 -0
- package/client/account.js +1 -0
- package/client/auth.d.ts +93 -0
- package/client/auth.js +375 -0
- package/client/bots.d.ts +6 -0
- package/client/bots.js +24 -0
- package/client/buttons.d.ts +4 -0
- package/client/buttons.js +87 -0
- package/client/chats.d.ts +46 -0
- package/client/chats.js +350 -0
- package/client/dialogs.d.ts +52 -0
- package/client/dialogs.js +174 -0
- package/client/downloads.d.ts +157 -0
- package/client/downloads.js +598 -0
- package/client/fs.d.ts +1 -0
- package/client/fs.js +13 -0
- package/client/index.d.ts +15 -0
- package/client/index.js +50 -0
- package/client/messageParse.d.ts +17 -0
- package/client/messageParse.js +191 -0
- package/client/messages.d.ts +259 -0
- package/client/messages.js +804 -0
- package/client/os.d.ts +2 -0
- package/client/os.js +23 -0
- package/client/path.d.ts +2 -0
- package/client/path.js +7 -0
- package/client/telegramBaseClient.d.ts +238 -0
- package/client/telegramBaseClient.js +368 -0
- package/client/updates.d.ts +31 -0
- package/client/updates.js +254 -0
- package/client/uploads.d.ts +137 -0
- package/client/uploads.js +514 -0
- package/client/users.d.ts +29 -0
- package/client/users.js +491 -0
- package/crypto/AuthKey.d.ts +20 -0
- package/crypto/AuthKey.js +76 -0
- package/crypto/CTR.d.ts +6 -0
- package/crypto/CTR.js +35 -0
- package/crypto/Factorizator.d.ts +19 -0
- package/crypto/Factorizator.js +74 -0
- package/crypto/IGE.d.ts +18 -0
- package/crypto/IGE.js +34 -0
- package/crypto/RSA.d.ts +15 -0
- package/crypto/RSA.js +70 -0
- package/crypto/converters.d.ts +19 -0
- package/crypto/converters.js +52 -0
- package/crypto/crypto.d.ts +27 -0
- package/crypto/crypto.js +117 -0
- package/crypto/words.d.ts +6 -0
- package/crypto/words.js +48 -0
- package/define.d.ts +77 -0
- package/entityCache.d.ts +7 -0
- package/entityCache.js +79 -0
- package/errors/Common.d.ts +72 -0
- package/errors/Common.js +122 -0
- package/errors/RPCBaseErrors.d.ts +84 -0
- package/errors/RPCBaseErrors.js +134 -0
- package/errors/RPCErrorList.d.ts +37 -0
- package/errors/RPCErrorList.js +117 -0
- package/errors/index.d.ts +11 -0
- package/errors/index.js +29 -0
- package/events/Album.d.ts +36 -0
- package/events/Album.js +104 -0
- package/events/CallbackQuery.d.ts +74 -0
- package/events/CallbackQuery.js +193 -0
- package/events/DeletedMessage.d.ts +45 -0
- package/events/DeletedMessage.js +63 -0
- package/events/EditedMessage.d.ts +30 -0
- package/events/EditedMessage.js +41 -0
- package/events/NewMessage.d.ts +89 -0
- package/events/NewMessage.js +182 -0
- package/events/Raw.d.ts +29 -0
- package/events/Raw.js +43 -0
- package/events/common.d.ts +66 -0
- package/events/common.js +141 -0
- package/events/index.d.ts +2 -0
- package/events/index.js +8 -0
- package/extensions/AsyncQueue.d.ts +10 -0
- package/extensions/AsyncQueue.js +32 -0
- package/extensions/BinaryReader.d.ts +100 -0
- package/extensions/BinaryReader.js +242 -0
- package/extensions/BinaryWriter.d.ts +7 -0
- package/extensions/BinaryWriter.js +15 -0
- package/extensions/Deferred.d.ts +8 -0
- package/extensions/Deferred.js +16 -0
- package/extensions/Logger.d.ts +56 -0
- package/extensions/Logger.js +107 -0
- package/extensions/MessagePacker.d.ts +22 -0
- package/extensions/MessagePacker.js +154 -0
- package/extensions/PendingState.d.ts +12 -0
- package/extensions/PendingState.js +29 -0
- package/extensions/PromisedNetSockets.d.ts +25 -0
- package/extensions/PromisedNetSockets.js +178 -0
- package/extensions/PromisedWebSockets.d.ts +19 -0
- package/extensions/PromisedWebSockets.js +124 -0
- package/extensions/html.d.ts +5 -0
- package/extensions/html.js +213 -0
- package/extensions/index.d.ts +7 -0
- package/extensions/index.js +17 -0
- package/extensions/markdown.d.ts +5 -0
- package/extensions/markdown.js +76 -0
- package/extensions/markdownv2.d.ts +5 -0
- package/extensions/markdownv2.js +51 -0
- package/extensions/net.d.ts +1 -0
- package/extensions/net.js +13 -0
- package/extensions/socks.d.ts +1 -0
- package/extensions/socks.js +13 -0
- package/index.d.ts +14 -0
- package/index.js +48 -0
- package/inspect.d.ts +1 -0
- package/inspect.js +5 -0
- package/network/Authenticator.d.ts +12 -0
- package/network/Authenticator.js +193 -0
- package/network/MTProtoPlainSender.d.ts +19 -0
- package/network/MTProtoPlainSender.js +74 -0
- package/network/MTProtoSender.d.ts +291 -0
- package/network/MTProtoSender.js +854 -0
- package/network/MTProtoState.d.ts +103 -0
- package/network/MTProtoState.js +267 -0
- package/network/RequestState.d.ts +19 -0
- package/network/RequestState.js +35 -0
- package/network/connection/Connection.d.ts +71 -0
- package/network/connection/Connection.js +157 -0
- package/network/connection/TCPAbridged.d.ts +20 -0
- package/network/connection/TCPAbridged.js +58 -0
- package/network/connection/TCPFull.d.ts +17 -0
- package/network/connection/TCPFull.js +61 -0
- package/network/connection/TCPMTProxy.d.ts +50 -0
- package/network/connection/TCPMTProxy.js +121 -0
- package/network/connection/TCPObfuscated.d.ts +19 -0
- package/network/connection/TCPObfuscated.js +78 -0
- package/network/connection/index.d.ts +4 -0
- package/network/connection/index.js +11 -0
- package/network/index.d.ts +11 -0
- package/network/index.js +23 -0
- package/package.json +69 -0
- package/requestIter.d.ts +24 -0
- package/requestIter.js +107 -0
- package/sessions/Abstract.d.ts +103 -0
- package/sessions/Abstract.js +6 -0
- package/sessions/CacheApiSession.d.ts +18 -0
- package/sessions/CacheApiSession.js +99 -0
- package/sessions/Memory.d.ts +38 -0
- package/sessions/Memory.js +272 -0
- package/sessions/StoreSession.d.ts +14 -0
- package/sessions/StoreSession.js +77 -0
- package/sessions/StringSession.d.ts +33 -0
- package/sessions/StringSession.js +116 -0
- package/sessions/index.d.ts +4 -0
- package/sessions/index.js +13 -0
- package/sessions/localStorage.d.ts +1 -0
- package/sessions/localStorage.js +4 -0
- package/tl/AllTLObjects.d.ts +3 -0
- package/tl/AllTLObjects.js +17 -0
- package/tl/MTProtoRequest.d.ts +19 -0
- package/tl/MTProtoRequest.js +38 -0
- package/tl/api.d.ts +31425 -0
- package/tl/api.js +507 -0
- package/tl/apiTl.d.ts +2 -0
- package/tl/apiTl.js +2142 -0
- package/tl/core/GZIPPacked.d.ts +16 -0
- package/tl/core/GZIPPacked.js +51 -0
- package/tl/core/MessageContainer.d.ts +12 -0
- package/tl/core/MessageContainer.js +42 -0
- package/tl/core/RPCResult.d.ts +15 -0
- package/tl/core/RPCResult.js +32 -0
- package/tl/core/TLMessage.d.ts +10 -0
- package/tl/core/TLMessage.js +14 -0
- package/tl/core/index.d.ts +6 -0
- package/tl/core/index.js +16 -0
- package/tl/custom/button.d.ts +25 -0
- package/tl/custom/button.js +78 -0
- package/tl/custom/chatGetter.d.ts +30 -0
- package/tl/custom/chatGetter.js +114 -0
- package/tl/custom/dialog.d.ts +31 -0
- package/tl/custom/dialog.js +40 -0
- package/tl/custom/draft.d.ts +22 -0
- package/tl/custom/draft.js +48 -0
- package/tl/custom/file.d.ts +22 -0
- package/tl/custom/file.js +68 -0
- package/tl/custom/forward.d.ts +16 -0
- package/tl/custom/forward.js +47 -0
- package/tl/custom/index.d.ts +1 -0
- package/tl/custom/index.js +5 -0
- package/tl/custom/inlineResult.d.ts +33 -0
- package/tl/custom/inlineResult.js +87 -0
- package/tl/custom/inlineResults.d.ts +21 -0
- package/tl/custom/inlineResults.js +26 -0
- package/tl/custom/message.d.ts +428 -0
- package/tl/custom/message.js +702 -0
- package/tl/custom/messageButton.d.ts +55 -0
- package/tl/custom/messageButton.js +152 -0
- package/tl/custom/senderGetter.d.ts +29 -0
- package/tl/custom/senderGetter.js +55 -0
- package/tl/generateModule.d.ts +1 -0
- package/tl/generateModule.js +17 -0
- package/tl/generationHelpers.d.ts +12 -0
- package/tl/generationHelpers.js +289 -0
- package/tl/index.d.ts +3 -0
- package/tl/index.js +10 -0
- package/tl/patched/index.d.ts +2 -0
- package/tl/patched/index.js +77 -0
- package/tl/schemaTl.d.ts +2 -0
- package/tl/schemaTl.js +64 -0
- package/tl/types-generator/generate.d.ts +1 -0
- package/tl/types-generator/generate.js +84 -0
- package/tl/types-generator/template.d.ts +6 -0
- package/tl/types-generator/template.js +257 -0
package/Password.js
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.computeDigest = exports.computeCheck = void 0;
|
|
7
|
+
const tl_1 = require("./tl");
|
|
8
|
+
const Helpers_1 = require("./Helpers");
|
|
9
|
+
const big_integer_1 = __importDefault(require("big-integer"));
|
|
10
|
+
const CryptoFile_1 = __importDefault(require("./CryptoFile"));
|
|
11
|
+
const SIZE_FOR_HASH = 256;
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
*
|
|
15
|
+
* @param prime{BigInteger}
|
|
16
|
+
* @param g{BigInteger}
|
|
17
|
+
*/
|
|
18
|
+
/*
|
|
19
|
+
We don't support changing passwords yet
|
|
20
|
+
function checkPrimeAndGoodCheck(prime, g) {
|
|
21
|
+
console.error('Unsupported function `checkPrimeAndGoodCheck` call. Arguments:', prime, g)
|
|
22
|
+
|
|
23
|
+
const goodPrimeBitsCount = 2048
|
|
24
|
+
if (prime < 0 || prime.bitLength() !== goodPrimeBitsCount) {
|
|
25
|
+
throw new Error(`bad prime count ${prime.bitLength()},expected ${goodPrimeBitsCount}`)
|
|
26
|
+
}
|
|
27
|
+
// TODO this is kinda slow
|
|
28
|
+
if (Factorizator.factorize(prime)[0] !== 1) {
|
|
29
|
+
throw new Error('give "prime" is not prime')
|
|
30
|
+
}
|
|
31
|
+
if (g.eq(bigInt(2))) {
|
|
32
|
+
if ((prime.remainder(bigInt(8))).neq(bigInt(7))) {
|
|
33
|
+
throw new Error(`bad g ${g}, mod8 ${prime % 8}`)
|
|
34
|
+
}
|
|
35
|
+
} else if (g.eq(bigInt(3))) {
|
|
36
|
+
if ((prime.remainder(bigInt(3))).neq(bigInt(2))) {
|
|
37
|
+
throw new Error(`bad g ${g}, mod3 ${prime % 3}`)
|
|
38
|
+
}
|
|
39
|
+
// eslint-disable-next-line no-empty
|
|
40
|
+
} else if (g.eq(bigInt(4))) {
|
|
41
|
+
|
|
42
|
+
} else if (g.eq(bigInt(5))) {
|
|
43
|
+
if (!([ bigInt(1), bigInt(4) ].includes(prime.remainder(bigInt(5))))) {
|
|
44
|
+
throw new Error(`bad g ${g}, mod8 ${prime % 5}`)
|
|
45
|
+
}
|
|
46
|
+
} else if (g.eq(bigInt(6))) {
|
|
47
|
+
if (!([ bigInt(19), bigInt(23) ].includes(prime.remainder(bigInt(24))))) {
|
|
48
|
+
throw new Error(`bad g ${g}, mod8 ${prime % 24}`)
|
|
49
|
+
}
|
|
50
|
+
} else if (g.eq(bigInt(7))) {
|
|
51
|
+
if (!([ bigInt(3), bigInt(5), bigInt(6) ].includes(prime.remainder(bigInt(7))))) {
|
|
52
|
+
throw new Error(`bad g ${g}, mod8 ${prime % 7}`)
|
|
53
|
+
}
|
|
54
|
+
} else {
|
|
55
|
+
throw new Error(`bad g ${g}`)
|
|
56
|
+
}
|
|
57
|
+
const primeSub1Div2 = (prime.subtract(bigInt(1))).divide(bigInt(2))
|
|
58
|
+
if (Factorizator.factorize(primeSub1Div2)[0] !== 1) {
|
|
59
|
+
throw new Error('(prime - 1) // 2 is not prime')
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
*/
|
|
63
|
+
/**
|
|
64
|
+
*
|
|
65
|
+
* @param primeBytes{Buffer}
|
|
66
|
+
* @param g{number}
|
|
67
|
+
*/
|
|
68
|
+
function checkPrimeAndGood(primeBytes, g) {
|
|
69
|
+
const goodPrime = Buffer.from([
|
|
70
|
+
0xc7, 0x1c, 0xae, 0xb9, 0xc6, 0xb1, 0xc9, 0x04, 0x8e, 0x6c, 0x52, 0x2f,
|
|
71
|
+
0x70, 0xf1, 0x3f, 0x73, 0x98, 0x0d, 0x40, 0x23, 0x8e, 0x3e, 0x21, 0xc1,
|
|
72
|
+
0x49, 0x34, 0xd0, 0x37, 0x56, 0x3d, 0x93, 0x0f, 0x48, 0x19, 0x8a, 0x0a,
|
|
73
|
+
0xa7, 0xc1, 0x40, 0x58, 0x22, 0x94, 0x93, 0xd2, 0x25, 0x30, 0xf4, 0xdb,
|
|
74
|
+
0xfa, 0x33, 0x6f, 0x6e, 0x0a, 0xc9, 0x25, 0x13, 0x95, 0x43, 0xae, 0xd4,
|
|
75
|
+
0x4c, 0xce, 0x7c, 0x37, 0x20, 0xfd, 0x51, 0xf6, 0x94, 0x58, 0x70, 0x5a,
|
|
76
|
+
0xc6, 0x8c, 0xd4, 0xfe, 0x6b, 0x6b, 0x13, 0xab, 0xdc, 0x97, 0x46, 0x51,
|
|
77
|
+
0x29, 0x69, 0x32, 0x84, 0x54, 0xf1, 0x8f, 0xaf, 0x8c, 0x59, 0x5f, 0x64,
|
|
78
|
+
0x24, 0x77, 0xfe, 0x96, 0xbb, 0x2a, 0x94, 0x1d, 0x5b, 0xcd, 0x1d, 0x4a,
|
|
79
|
+
0xc8, 0xcc, 0x49, 0x88, 0x07, 0x08, 0xfa, 0x9b, 0x37, 0x8e, 0x3c, 0x4f,
|
|
80
|
+
0x3a, 0x90, 0x60, 0xbe, 0xe6, 0x7c, 0xf9, 0xa4, 0xa4, 0xa6, 0x95, 0x81,
|
|
81
|
+
0x10, 0x51, 0x90, 0x7e, 0x16, 0x27, 0x53, 0xb5, 0x6b, 0x0f, 0x6b, 0x41,
|
|
82
|
+
0x0d, 0xba, 0x74, 0xd8, 0xa8, 0x4b, 0x2a, 0x14, 0xb3, 0x14, 0x4e, 0x0e,
|
|
83
|
+
0xf1, 0x28, 0x47, 0x54, 0xfd, 0x17, 0xed, 0x95, 0x0d, 0x59, 0x65, 0xb4,
|
|
84
|
+
0xb9, 0xdd, 0x46, 0x58, 0x2d, 0xb1, 0x17, 0x8d, 0x16, 0x9c, 0x6b, 0xc4,
|
|
85
|
+
0x65, 0xb0, 0xd6, 0xff, 0x9c, 0xa3, 0x92, 0x8f, 0xef, 0x5b, 0x9a, 0xe4,
|
|
86
|
+
0xe4, 0x18, 0xfc, 0x15, 0xe8, 0x3e, 0xbe, 0xa0, 0xf8, 0x7f, 0xa9, 0xff,
|
|
87
|
+
0x5e, 0xed, 0x70, 0x05, 0x0d, 0xed, 0x28, 0x49, 0xf4, 0x7b, 0xf9, 0x59,
|
|
88
|
+
0xd9, 0x56, 0x85, 0x0c, 0xe9, 0x29, 0x85, 0x1f, 0x0d, 0x81, 0x15, 0xf6,
|
|
89
|
+
0x35, 0xb1, 0x05, 0xee, 0x2e, 0x4e, 0x15, 0xd0, 0x4b, 0x24, 0x54, 0xbf,
|
|
90
|
+
0x6f, 0x4f, 0xad, 0xf0, 0x34, 0xb1, 0x04, 0x03, 0x11, 0x9c, 0xd8, 0xe3,
|
|
91
|
+
0xb9, 0x2f, 0xcc, 0x5b,
|
|
92
|
+
]);
|
|
93
|
+
if (goodPrime.equals(primeBytes)) {
|
|
94
|
+
if ([3, 4, 5, 7].includes(g)) {
|
|
95
|
+
return; // It's good
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
throw new Error("Changing passwords unsupported");
|
|
99
|
+
//checkPrimeAndGoodCheck(readBigIntFromBuffer(primeBytes, false), g)
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
*
|
|
103
|
+
* @param number{BigInteger}
|
|
104
|
+
* @param p{BigInteger}
|
|
105
|
+
* @returns {boolean}
|
|
106
|
+
*/
|
|
107
|
+
function isGoodLarge(number, p) {
|
|
108
|
+
return number.greater((0, big_integer_1.default)(0)) && p.subtract(number).greater((0, big_integer_1.default)(0));
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
*
|
|
112
|
+
* @param number {Buffer}
|
|
113
|
+
* @returns {Buffer}
|
|
114
|
+
*/
|
|
115
|
+
function numBytesForHash(number) {
|
|
116
|
+
return Buffer.concat([Buffer.alloc(SIZE_FOR_HASH - number.length), number]);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
*
|
|
120
|
+
* @param g {bigInt}
|
|
121
|
+
* @returns {Buffer}
|
|
122
|
+
*/
|
|
123
|
+
function bigNumForHash(g) {
|
|
124
|
+
return (0, Helpers_1.readBufferFromBigInt)(g, SIZE_FOR_HASH, false);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
*
|
|
128
|
+
* @param modexp {BigInteger}
|
|
129
|
+
* @param prime {BigInteger}
|
|
130
|
+
* @returns {Boolean}
|
|
131
|
+
*/
|
|
132
|
+
function isGoodModExpFirst(modexp, prime) {
|
|
133
|
+
const diff = prime.subtract(modexp);
|
|
134
|
+
const minDiffBitsCount = 2048 - 64;
|
|
135
|
+
const maxModExpSize = 256;
|
|
136
|
+
return !(diff.lesser((0, big_integer_1.default)(0)) ||
|
|
137
|
+
diff.bitLength().toJSNumber() < minDiffBitsCount ||
|
|
138
|
+
modexp.bitLength().toJSNumber() < minDiffBitsCount ||
|
|
139
|
+
Math.floor((modexp.bitLength().toJSNumber() + 7) / 8) > maxModExpSize);
|
|
140
|
+
}
|
|
141
|
+
function xor(a, b) {
|
|
142
|
+
const length = Math.min(a.length, b.length);
|
|
143
|
+
for (let i = 0; i < length; i++) {
|
|
144
|
+
a[i] = a[i] ^ b[i];
|
|
145
|
+
}
|
|
146
|
+
return a;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
*
|
|
150
|
+
* @param password{Buffer}
|
|
151
|
+
* @param salt{Buffer}
|
|
152
|
+
* @param iterations{number}
|
|
153
|
+
* @returns {*}
|
|
154
|
+
*/
|
|
155
|
+
function pbkdf2sha512(password, salt, iterations) {
|
|
156
|
+
return CryptoFile_1.default.pbkdf2Sync(password, salt, iterations, 64, "sha512");
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
*
|
|
160
|
+
* @param algo {constructors.PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow}
|
|
161
|
+
* @param password
|
|
162
|
+
* @returns {Buffer|*}
|
|
163
|
+
*/
|
|
164
|
+
async function computeHash(algo, password) {
|
|
165
|
+
const hash1 = await (0, Helpers_1.sha256)(Buffer.concat([algo.salt1, Buffer.from(password, "utf-8"), algo.salt1]));
|
|
166
|
+
const hash2 = await (0, Helpers_1.sha256)(Buffer.concat([algo.salt2, hash1, algo.salt2]));
|
|
167
|
+
const hash3 = await pbkdf2sha512(hash2, algo.salt1, 100000);
|
|
168
|
+
return (0, Helpers_1.sha256)(Buffer.concat([algo.salt2, hash3, algo.salt2]));
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
*
|
|
172
|
+
* @param algo {constructors.PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow}
|
|
173
|
+
* @param password
|
|
174
|
+
*/
|
|
175
|
+
async function computeDigest(algo, password) {
|
|
176
|
+
try {
|
|
177
|
+
checkPrimeAndGood(algo.p, algo.g);
|
|
178
|
+
}
|
|
179
|
+
catch (e) {
|
|
180
|
+
throw new Error("bad p/g in password");
|
|
181
|
+
}
|
|
182
|
+
const value = (0, Helpers_1.modExp)((0, big_integer_1.default)(algo.g), (0, Helpers_1.readBigIntFromBuffer)(await computeHash(algo, password), false), (0, Helpers_1.readBigIntFromBuffer)(algo.p, false));
|
|
183
|
+
return bigNumForHash(value);
|
|
184
|
+
}
|
|
185
|
+
exports.computeDigest = computeDigest;
|
|
186
|
+
/**
|
|
187
|
+
*
|
|
188
|
+
* @param request {constructors.account.Password}
|
|
189
|
+
* @param password {string}
|
|
190
|
+
*/
|
|
191
|
+
async function computeCheck(request, password) {
|
|
192
|
+
const algo = request.currentAlgo;
|
|
193
|
+
if (!(algo instanceof
|
|
194
|
+
tl_1.Api.PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow)) {
|
|
195
|
+
throw new Error(`Unsupported password algorithm ${algo === null || algo === void 0 ? void 0 : algo.className}`);
|
|
196
|
+
}
|
|
197
|
+
const srp_B = request.srp_B;
|
|
198
|
+
const srpId = request.srpId;
|
|
199
|
+
if (!srp_B || !srpId) {
|
|
200
|
+
throw new Error(`Undefined srp_b ${request}`);
|
|
201
|
+
}
|
|
202
|
+
const pwHash = await computeHash(algo, password);
|
|
203
|
+
const p = (0, Helpers_1.readBigIntFromBuffer)(algo.p, false);
|
|
204
|
+
const g = algo.g;
|
|
205
|
+
const B = (0, Helpers_1.readBigIntFromBuffer)(srp_B, false);
|
|
206
|
+
try {
|
|
207
|
+
checkPrimeAndGood(algo.p, g);
|
|
208
|
+
}
|
|
209
|
+
catch (e) {
|
|
210
|
+
throw new Error("bad /g in password");
|
|
211
|
+
}
|
|
212
|
+
if (!isGoodLarge(B, p)) {
|
|
213
|
+
throw new Error("bad b in check");
|
|
214
|
+
}
|
|
215
|
+
const x = (0, Helpers_1.readBigIntFromBuffer)(pwHash, false);
|
|
216
|
+
const pForHash = numBytesForHash(algo.p);
|
|
217
|
+
const gForHash = bigNumForHash((0, big_integer_1.default)(g));
|
|
218
|
+
const bForHash = numBytesForHash(srp_B);
|
|
219
|
+
const gX = (0, Helpers_1.modExp)((0, big_integer_1.default)(g), x, p);
|
|
220
|
+
const k = (0, Helpers_1.readBigIntFromBuffer)(await (0, Helpers_1.sha256)(Buffer.concat([pForHash, gForHash])), false);
|
|
221
|
+
const kgX = (0, Helpers_1.bigIntMod)(k.multiply(gX), p);
|
|
222
|
+
const generateAndCheckRandom = async () => {
|
|
223
|
+
const randomSize = 256;
|
|
224
|
+
// eslint-disable-next-line no-constant-condition
|
|
225
|
+
while (true) {
|
|
226
|
+
const random = (0, Helpers_1.generateRandomBytes)(randomSize);
|
|
227
|
+
const a = (0, Helpers_1.readBigIntFromBuffer)(random, false);
|
|
228
|
+
const A = (0, Helpers_1.modExp)((0, big_integer_1.default)(g), a, p);
|
|
229
|
+
if (isGoodModExpFirst(A, p)) {
|
|
230
|
+
const aForHash = bigNumForHash(A);
|
|
231
|
+
const u = (0, Helpers_1.readBigIntFromBuffer)(await (0, Helpers_1.sha256)(Buffer.concat([aForHash, bForHash])), false);
|
|
232
|
+
if (u.greater((0, big_integer_1.default)(0))) {
|
|
233
|
+
return {
|
|
234
|
+
a: a,
|
|
235
|
+
aForHash: aForHash,
|
|
236
|
+
u: u,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
const { a, aForHash, u } = await generateAndCheckRandom();
|
|
243
|
+
const gB = (0, Helpers_1.bigIntMod)(B.subtract(kgX), p);
|
|
244
|
+
if (!isGoodModExpFirst(gB, p)) {
|
|
245
|
+
throw new Error("bad gB");
|
|
246
|
+
}
|
|
247
|
+
const ux = u.multiply(x);
|
|
248
|
+
const aUx = a.add(ux);
|
|
249
|
+
const S = (0, Helpers_1.modExp)(gB, aUx, p);
|
|
250
|
+
const [K, pSha, gSha, salt1Sha, salt2Sha] = await Promise.all([
|
|
251
|
+
(0, Helpers_1.sha256)(bigNumForHash(S)),
|
|
252
|
+
(0, Helpers_1.sha256)(pForHash),
|
|
253
|
+
(0, Helpers_1.sha256)(gForHash),
|
|
254
|
+
(0, Helpers_1.sha256)(algo.salt1),
|
|
255
|
+
(0, Helpers_1.sha256)(algo.salt2),
|
|
256
|
+
]);
|
|
257
|
+
const M1 = await (0, Helpers_1.sha256)(Buffer.concat([
|
|
258
|
+
xor(pSha, gSha),
|
|
259
|
+
salt1Sha,
|
|
260
|
+
salt2Sha,
|
|
261
|
+
aForHash,
|
|
262
|
+
bForHash,
|
|
263
|
+
K,
|
|
264
|
+
]));
|
|
265
|
+
return new tl_1.Api.InputCheckPasswordSRP({
|
|
266
|
+
srpId: srpId,
|
|
267
|
+
A: Buffer.from(aForHash),
|
|
268
|
+
M1: M1,
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
exports.computeCheck = computeCheck;
|
package/README.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# teleproto
|
|
2
|
+
|
|
3
|
+
A modern Telegram client library written in TypeScript for Node.js and browsers, forked from [GramJS](https://github.com/gram-js/gramjs) with performance and size improvements.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
Here's how to get started with teleproto:
|
|
8
|
+
|
|
9
|
+
### Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
$ npm i teleproto
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Authentication Setup
|
|
16
|
+
|
|
17
|
+
1. Login to your [Telegram account](https://my.telegram.org/)
|
|
18
|
+
2. Click "API development tools" and create an application
|
|
19
|
+
3. Save your API ID and hash (never share these with anyone)
|
|
20
|
+
|
|
21
|
+
### Basic Usage
|
|
22
|
+
|
|
23
|
+
```javascript
|
|
24
|
+
import { TelegramClient } from "teleproto";
|
|
25
|
+
import { StringSession } from "teleproto/sessions";
|
|
26
|
+
import readline from "readline";
|
|
27
|
+
|
|
28
|
+
const apiId = 123456; // Replace with your API ID
|
|
29
|
+
const apiHash = "123456abcdefg"; // Replace with your API Hash
|
|
30
|
+
const stringSession = new StringSession(""); // Save the string session for later use
|
|
31
|
+
|
|
32
|
+
const rl = readline.createInterface({
|
|
33
|
+
input: process.stdin,
|
|
34
|
+
output: process.stdout,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
async function main() {
|
|
38
|
+
console.log("Starting teleproto client...");
|
|
39
|
+
const client = new TelegramClient(stringSession, apiId, apiHash, {
|
|
40
|
+
connectionRetries: 5,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
await client.start({
|
|
44
|
+
phoneNumber: async () =>
|
|
45
|
+
await new Promise(resolve => rl.question("Phone number: ", resolve)),
|
|
46
|
+
password: async () =>
|
|
47
|
+
await new Promise(resolve => rl.question("Password: ", resolve)),
|
|
48
|
+
phoneCode: async () =>
|
|
49
|
+
await new Promise(resolve => rl.question("Verification code: ", resolve)),
|
|
50
|
+
onError: (err) => console.error(err),
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
console.log("Connected successfully!");
|
|
54
|
+
console.log("Session string:", client.session.save()); // Save this to avoid login next time
|
|
55
|
+
|
|
56
|
+
// Send a message to yourself
|
|
57
|
+
await client.sendMessage("me", { message: "Hello from teleproto!" });
|
|
58
|
+
|
|
59
|
+
// Disconnect when done
|
|
60
|
+
await client.disconnect();
|
|
61
|
+
rl.close();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
main();
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
You can also use `StoreSession` to save auth data to a folder instead of a string:
|
|
68
|
+
|
|
69
|
+
```javascript
|
|
70
|
+
import { StoreSession } from "teleproto/sessions";
|
|
71
|
+
const storeSession = new StoreSession("session_folder");
|
|
72
|
+
const client = new TelegramClient(storeSession, apiId, apiHash, {});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Browser Support
|
|
76
|
+
|
|
77
|
+
teleproto works in browsers with frontend frameworks like React and Vue. To generate a browser bundle:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
node generate_webpack.js
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## API Usage
|
|
84
|
+
|
|
85
|
+
### Calling Raw API Methods
|
|
86
|
+
|
|
87
|
+
```javascript
|
|
88
|
+
await client.invoke(new Api.RequestClass({ param1: "value1" }));
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Event Handling
|
|
92
|
+
|
|
93
|
+
```javascript
|
|
94
|
+
import { NewMessage } from "teleproto/events";
|
|
95
|
+
|
|
96
|
+
client.addEventHandler(async (event) => {
|
|
97
|
+
console.log("New message received:", event.message.text);
|
|
98
|
+
|
|
99
|
+
if (event.message.text === "Hello") {
|
|
100
|
+
await event.message.reply("Hi there!");
|
|
101
|
+
}
|
|
102
|
+
}, new NewMessage({}));
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Documentation
|
|
106
|
+
|
|
107
|
+
For detailed documentation, visit our [documentation site](https://teleproto.dev).
|
|
108
|
+
|
|
109
|
+
## Need Help?
|
|
110
|
+
|
|
111
|
+
If you have questions about teleproto, feel free to open an issue or join our community.
|
package/Utils.d.ts
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import bigInt from "big-integer";
|
|
3
|
+
import type { ParseInterface } from "./client/messageParse";
|
|
4
|
+
import { CustomFile } from "./client/uploads";
|
|
5
|
+
import type { Entity, EntityLike, MessageIDLike } from "./define";
|
|
6
|
+
import { EntityCache } from "./entityCache";
|
|
7
|
+
import { Api } from "./tl";
|
|
8
|
+
export declare function getFileInfo(fileLocation: Api.Message | Api.MessageMediaDocument | Api.MessageMediaPhoto | Api.TypeInputFileLocation): {
|
|
9
|
+
dcId?: number;
|
|
10
|
+
location: Api.TypeInputFileLocation;
|
|
11
|
+
size?: bigInt.BigInteger;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Turns the given iterable into chunks of the specified size,
|
|
15
|
+
* which is 100 by default since that's what Telegram uses the most.
|
|
16
|
+
*/
|
|
17
|
+
export declare function chunks<T>(arr: T[], size?: number): Generator<T[]>;
|
|
18
|
+
import TypeInputFile = Api.TypeInputFile;
|
|
19
|
+
/**
|
|
20
|
+
Gets the input peer for the given "entity" (user, chat or channel).
|
|
21
|
+
|
|
22
|
+
A ``TypeError`` is raised if the given entity isn't a supported type
|
|
23
|
+
or if ``check_hash is True`` but the entity's ``accessHash is None``
|
|
24
|
+
*or* the entity contains ``min`` information. In this case, the hash
|
|
25
|
+
cannot be used for general purposes, and thus is not returned to avoid
|
|
26
|
+
any issues which can derive from invalid access hashes.
|
|
27
|
+
|
|
28
|
+
Note that ``checkHash`` **is ignored** if an input peer is already
|
|
29
|
+
passed since in that case we assume the user knows what they're doing.
|
|
30
|
+
This is key to getting entities by explicitly passing ``hash = 0``.
|
|
31
|
+
|
|
32
|
+
* @param entity
|
|
33
|
+
* @param allowSelf
|
|
34
|
+
* @param checkHash
|
|
35
|
+
*/
|
|
36
|
+
export declare function getInputPeer(entity: any, allowSelf?: boolean, checkHash?: boolean): Api.TypeInputPeer;
|
|
37
|
+
export declare function _photoSizeByteCount(size: Api.TypePhotoSize): number | undefined;
|
|
38
|
+
export declare function _getEntityPair(entityId: string, entities: Map<string, Entity>, cache: EntityCache, getInputPeerFunction?: any): [Entity?, Api.TypeInputPeer?];
|
|
39
|
+
export declare function getInnerText(text: string, entities: Api.TypeMessageEntity[]): string[];
|
|
40
|
+
/**
|
|
41
|
+
Similar to :meth:`get_input_peer`, but for :tl:`InputChannel`'s alone.
|
|
42
|
+
|
|
43
|
+
.. important::
|
|
44
|
+
|
|
45
|
+
This method does not validate for invalid general-purpose access
|
|
46
|
+
hashes, unlike `get_input_peer`. Consider using instead:
|
|
47
|
+
``get_input_channel(get_input_peer(channel))``.
|
|
48
|
+
|
|
49
|
+
* @param entity
|
|
50
|
+
* @returns {InputChannel|*}
|
|
51
|
+
*/
|
|
52
|
+
export declare function getInputChannel(entity: EntityLike): Api.InputChannelEmpty | Api.InputChannel | Api.InputChannelFromMessage;
|
|
53
|
+
/**
|
|
54
|
+
Similar to :meth:`getInputPeer`, but for :tl:`InputUser`'s alone.
|
|
55
|
+
|
|
56
|
+
.. important::
|
|
57
|
+
|
|
58
|
+
This method does not validate for invalid general-purpose access
|
|
59
|
+
hashes, unlike `get_input_peer`. Consider using instead:
|
|
60
|
+
``get_input_channel(get_input_peer(channel))``.
|
|
61
|
+
|
|
62
|
+
* @param entity
|
|
63
|
+
*/
|
|
64
|
+
export declare function getInputUser(entity: EntityLike): Api.TypeInputUser;
|
|
65
|
+
/**
|
|
66
|
+
Similar to :meth:`get_input_peer`, but for dialogs
|
|
67
|
+
* @param dialog
|
|
68
|
+
*/
|
|
69
|
+
/**
|
|
70
|
+
* Similar to :meth:`get_input_peer`, but for input messages.
|
|
71
|
+
*/
|
|
72
|
+
export declare function getInputMessage(message: any): Api.InputMessageID;
|
|
73
|
+
/**
|
|
74
|
+
* Similar to :meth:`get_input_peer`, but for input messages.
|
|
75
|
+
*/
|
|
76
|
+
export declare function getInputChatPhoto(photo: any): Api.TypeInputChatPhoto;
|
|
77
|
+
/**
|
|
78
|
+
* Adds the JPG header and footer to a stripped image.
|
|
79
|
+
* Ported from https://github.com/telegramdesktop/tdesktop/blob/bec39d89e19670eb436dc794a8f20b657cb87c71/Telegram/SourceFiles/ui/image/image.cpp#L225
|
|
80
|
+
|
|
81
|
+
* @param stripped{Buffer}
|
|
82
|
+
* @returns {Buffer}
|
|
83
|
+
*/
|
|
84
|
+
export declare function strippedPhotoToJpg(stripped: Buffer): Buffer;
|
|
85
|
+
/**
|
|
86
|
+
* Similar to :meth:`get_input_peer`, but for photos
|
|
87
|
+
*/
|
|
88
|
+
export declare function getInputPhoto(photo: any): Api.TypeInputPhoto;
|
|
89
|
+
/**
|
|
90
|
+
* Similar to :meth:`get_input_peer`, but for documents
|
|
91
|
+
*/
|
|
92
|
+
export declare function getInputDocument(document: any): Api.InputDocument | Api.InputDocumentEmpty;
|
|
93
|
+
interface GetAttributesParams {
|
|
94
|
+
attributes?: any;
|
|
95
|
+
mimeType?: string;
|
|
96
|
+
forceDocument?: boolean;
|
|
97
|
+
voiceNote?: boolean;
|
|
98
|
+
videoNote?: boolean;
|
|
99
|
+
supportsStreaming?: boolean;
|
|
100
|
+
thumb?: any;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Returns `True` if the file has an audio mime type.
|
|
104
|
+
*/
|
|
105
|
+
export declare function isAudio(file: any): boolean;
|
|
106
|
+
/**
|
|
107
|
+
* Returns `True` if the file has an image mime type.
|
|
108
|
+
*/
|
|
109
|
+
export declare function isImage(file: any): boolean;
|
|
110
|
+
export declare function getExtension(media: any): string;
|
|
111
|
+
/**
|
|
112
|
+
Get a list of attributes for the given file and
|
|
113
|
+
the mime type as a tuple ([attribute], mime_type).
|
|
114
|
+
*/
|
|
115
|
+
export declare function getAttributes(file: File | CustomFile | TypeInputFile | string, { attributes, mimeType, forceDocument, voiceNote, videoNote, supportsStreaming, thumb, }: GetAttributesParams): {
|
|
116
|
+
attrs: Api.TypeDocumentAttribute[];
|
|
117
|
+
mimeType: string;
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* Similar to :meth:`get_input_peer`, but for geo points
|
|
121
|
+
*/
|
|
122
|
+
export declare function getInputGeo(geo: any): Api.TypeInputGeoPoint;
|
|
123
|
+
export interface GetInputMediaInterface {
|
|
124
|
+
isPhoto?: boolean;
|
|
125
|
+
attributes?: Api.TypeDocumentAttribute[];
|
|
126
|
+
forceDocument?: boolean;
|
|
127
|
+
voiceNote?: boolean;
|
|
128
|
+
videoNote?: boolean;
|
|
129
|
+
supportsStreaming?: boolean;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
*
|
|
133
|
+
Similar to :meth:`get_input_peer`, but for media.
|
|
134
|
+
|
|
135
|
+
If the media is :tl:`InputFile` and ``is_photo`` is known to be `True`,
|
|
136
|
+
it will be treated as an :tl:`InputMediaUploadedPhoto`. Else, the rest
|
|
137
|
+
of parameters will indicate how to treat it.
|
|
138
|
+
* @param media
|
|
139
|
+
* @param isPhoto - whether it's a photo or not
|
|
140
|
+
* @param attributes
|
|
141
|
+
* @param forceDocument
|
|
142
|
+
* @param voiceNote
|
|
143
|
+
* @param videoNote
|
|
144
|
+
* @param supportsStreaming
|
|
145
|
+
*/
|
|
146
|
+
export declare function getInputMedia(media: any, { isPhoto, attributes, forceDocument, voiceNote, videoNote, supportsStreaming, }?: GetInputMediaInterface): Api.TypeInputMedia;
|
|
147
|
+
/**
|
|
148
|
+
* Gets the appropriated part size when uploading or downloading files,
|
|
149
|
+
* given an initial file size.
|
|
150
|
+
* @param fileSize
|
|
151
|
+
* @returns {Number}
|
|
152
|
+
*/
|
|
153
|
+
export declare function getAppropriatedPartSize(fileSize: bigInt.BigInteger): 256 | 512 | 128;
|
|
154
|
+
export declare function getPeer(peer: EntityLike | any): any;
|
|
155
|
+
export declare function sanitizeParseMode(mode: string | ParseInterface): ParseInterface;
|
|
156
|
+
/**
|
|
157
|
+
Convert the given peer into its marked ID by default.
|
|
158
|
+
|
|
159
|
+
This "mark" comes from the "bot api" format, and with it the peer type
|
|
160
|
+
can be identified back. User ID is left unmodified, chat ID is negated,
|
|
161
|
+
and channel ID is prefixed with -100:
|
|
162
|
+
|
|
163
|
+
* ``userId``
|
|
164
|
+
* ``-chatId``
|
|
165
|
+
* ``-100channel_id``
|
|
166
|
+
|
|
167
|
+
The original ID and the peer type class can be returned with
|
|
168
|
+
a call to :meth:`resolve_id(marked_id)`.
|
|
169
|
+
* @param peer
|
|
170
|
+
* @param addMark
|
|
171
|
+
*/
|
|
172
|
+
export declare function getPeerId(peer: EntityLike, addMark?: boolean): string;
|
|
173
|
+
/**
|
|
174
|
+
* Given a marked ID, returns the original ID and its :tl:`Peer` type.
|
|
175
|
+
* @param markedId
|
|
176
|
+
*/
|
|
177
|
+
export declare function resolveId(markedId: bigInt.BigInteger): [
|
|
178
|
+
bigInt.BigInteger,
|
|
179
|
+
typeof Api.PeerUser | typeof Api.PeerChannel | typeof Api.PeerChat
|
|
180
|
+
];
|
|
181
|
+
/**
|
|
182
|
+
* returns an entity pair
|
|
183
|
+
* @param entityId
|
|
184
|
+
* @param entities
|
|
185
|
+
* @param cache
|
|
186
|
+
* @param getInputPeer
|
|
187
|
+
* @returns {{inputEntity: *, entity: *}}
|
|
188
|
+
* @private
|
|
189
|
+
*/
|
|
190
|
+
export declare function getMessageId(message: number | Api.TypeMessage | MessageIDLike | undefined): number | undefined;
|
|
191
|
+
/**
|
|
192
|
+
* Parses the given phone, or returns `undefined` if it's invalid.
|
|
193
|
+
* @param phone
|
|
194
|
+
*/
|
|
195
|
+
export declare function parsePhone(phone: string): string | undefined;
|
|
196
|
+
/**
|
|
197
|
+
* Parses a string ID into a big int
|
|
198
|
+
* @param id
|
|
199
|
+
*/
|
|
200
|
+
export declare function parseID(id: string): bigInt.BigInteger | undefined;
|
|
201
|
+
export declare function resolveInviteLink(link: string): [number, number, number];
|
|
202
|
+
/**
|
|
203
|
+
Parses the given username or channel access hash, given
|
|
204
|
+
a string, username or URL. Returns a tuple consisting of
|
|
205
|
+
both the stripped, lowercase username and whether it is
|
|
206
|
+
a joinchat/ hash (in which case is not lowercase'd).
|
|
207
|
+
|
|
208
|
+
Returns ``(undefined, false)`` if the ``username`` or link is not valid.
|
|
209
|
+
|
|
210
|
+
* @param username {string}
|
|
211
|
+
*/
|
|
212
|
+
export declare function parseUsername(username: string): {
|
|
213
|
+
username?: string;
|
|
214
|
+
isInvite: boolean;
|
|
215
|
+
};
|
|
216
|
+
export declare function rtrim(s: string, mask: string): string;
|
|
217
|
+
/**
|
|
218
|
+
* Gets the display name for the given :tl:`User`,
|
|
219
|
+
:tl:`Chat` or :tl:`Channel`. Returns an empty string otherwise
|
|
220
|
+
* @param entity
|
|
221
|
+
*/
|
|
222
|
+
export declare function getDisplayName(entity: EntityLike): string;
|
|
223
|
+
export {};
|
|
224
|
+
/**
|
|
225
|
+
* check if a given item is an array like or not
|
|
226
|
+
* @param item
|
|
227
|
+
* @returns {boolean}
|
|
228
|
+
*/
|