@mtcute/test 0.16.7 → 0.16.13
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/client.d.ts +3 -5
- package/client.test.d.ts +1 -0
- package/crypto.d.ts +1 -1
- package/index.d.cts +8 -0
- package/index.js +862 -9
- package/package.json +44 -35
- package/platform.test.d.ts +1 -0
- package/schema.d.ts +1 -1
- package/storage/auth-keys.d.ts +1 -1
- package/storage/key-value.d.ts +1 -1
- package/storage/peers.d.ts +1 -1
- package/storage/ref-messages.d.ts +1 -1
- package/storage.d.ts +1 -1
- package/stub.d.ts +1 -1
- package/stub.test.d.ts +1 -0
- package/transport.d.ts +4 -5
- package/transport.test.d.ts +1 -0
- package/types.d.ts +2 -2
- package/utils.d.ts +1 -1
- package/utils.test.d.ts +1 -0
- package/client.js +0 -230
- package/client.js.map +0 -1
- package/crypto.js +0 -179
- package/crypto.js.map +0 -1
- package/index.js.map +0 -1
- package/platform.js +0 -5
- package/platform.js.map +0 -1
- package/platform.web.js +0 -4
- package/platform.web.js.map +0 -1
- package/schema.js +0 -28
- package/schema.js.map +0 -1
- package/storage/auth-keys.js +0 -90
- package/storage/auth-keys.js.map +0 -1
- package/storage/index.js +0 -5
- package/storage/index.js.map +0 -1
- package/storage/key-value.js +0 -36
- package/storage/key-value.js.map +0 -1
- package/storage/peers.js +0 -70
- package/storage/peers.js.map +0 -1
- package/storage/ref-messages.js +0 -64
- package/storage/ref-messages.js.map +0 -1
- package/storage.js +0 -45
- package/storage.js.map +0 -1
- package/stub.js +0 -63
- package/stub.js.map +0 -1
- package/transport.js +0 -47
- package/transport.js.map +0 -1
- package/types.js +0 -2
- package/types.js.map +0 -1
- package/utils.js +0 -13
- package/utils.js.map +0 -1
package/index.js
CHANGED
|
@@ -1,9 +1,862 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
import { MemoryStorage, MtArgumentError, TransportState, parseMarkedPeerId, tl } from "@mtcute/core";
|
|
2
|
+
import { BaseTelegramClient } from "@mtcute/core/client.js";
|
|
3
|
+
import { WebPlatform, WebCryptoProvider } from "@mtcute/web";
|
|
4
|
+
import { createAesIgeForMessage, dataViewFromBuffer, TlBinaryWriter } from "@mtcute/core/utils.js";
|
|
5
|
+
import EventEmitter from "node:events";
|
|
6
|
+
import { gzipSync, inflateSync } from "node:zlib";
|
|
7
|
+
import { beforeEach, vi, afterEach, beforeAll, it, expect, describe } from "vitest";
|
|
8
|
+
import { getPlatform } from "@mtcute/core/platform.js";
|
|
9
|
+
import Long from "long";
|
|
10
|
+
import * as schema_ from "@mtcute/tl/api-schema.json";
|
|
11
|
+
import { __tlWriterMap } from "@mtcute/tl/binary/writer.js";
|
|
12
|
+
const defaultPlatform = new WebPlatform();
|
|
13
|
+
const defaultCryptoProvider = new WebCryptoProvider();
|
|
14
|
+
class StubMemoryTelegramStorage extends MemoryStorage {
|
|
15
|
+
constructor(params = {
|
|
16
|
+
hasKeys: true,
|
|
17
|
+
hasTempKeys: true
|
|
18
|
+
}) {
|
|
19
|
+
super();
|
|
20
|
+
this.params = params;
|
|
21
|
+
const _origGet = this.authKeys.get;
|
|
22
|
+
this.authKeys.get = (dcId) => {
|
|
23
|
+
if (this.params.hasKeys) {
|
|
24
|
+
if (this.params.hasKeys === true || this.params.hasKeys.includes(dcId)) {
|
|
25
|
+
return new Uint8Array(256);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return _origGet.call(this.authKeys, dcId);
|
|
29
|
+
};
|
|
30
|
+
const _origGetTemp = this.authKeys.getTemp;
|
|
31
|
+
this.authKeys.getTemp = (dcId, idx, now) => {
|
|
32
|
+
if (this.params.hasTempKeys) {
|
|
33
|
+
if (this.params.hasTempKeys === true || this.params.hasTempKeys.includes(dcId)) {
|
|
34
|
+
return new Uint8Array(256);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return _origGetTemp.call(this.authKeys, dcId, idx, now);
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
decryptOutgoingMessage(crypto, data, dcId, tempIndex) {
|
|
41
|
+
const key = tempIndex ? this.authKeys.getTemp(dcId, tempIndex, Date.now()) : this.authKeys.get(dcId);
|
|
42
|
+
if (!key) {
|
|
43
|
+
throw new MtArgumentError(`No auth key for DC ${dcId}`);
|
|
44
|
+
}
|
|
45
|
+
const messageKey = data.subarray(8, 24);
|
|
46
|
+
const encryptedData = data.subarray(24);
|
|
47
|
+
const ige = createAesIgeForMessage(crypto, key, messageKey, true);
|
|
48
|
+
const innerData = ige.decrypt(encryptedData);
|
|
49
|
+
const dv = new DataView(innerData.buffer, innerData.byteOffset, innerData.byteLength);
|
|
50
|
+
const length = dv.getUint32(28, true);
|
|
51
|
+
return innerData.subarray(32, 32 + length);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
class StubTelegramTransport extends EventEmitter {
|
|
55
|
+
constructor(params) {
|
|
56
|
+
super();
|
|
57
|
+
this.params = params;
|
|
58
|
+
if (params.getMtproxyInfo) {
|
|
59
|
+
this.getMtproxyInfo = params.getMtproxyInfo;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
_state = TransportState.Idle;
|
|
63
|
+
_currentDc = null;
|
|
64
|
+
_crypto;
|
|
65
|
+
_log;
|
|
66
|
+
write(data) {
|
|
67
|
+
this.emit("message", data);
|
|
68
|
+
}
|
|
69
|
+
setup(crypto, log) {
|
|
70
|
+
this._crypto = crypto;
|
|
71
|
+
this._log = log;
|
|
72
|
+
}
|
|
73
|
+
state() {
|
|
74
|
+
return this._state;
|
|
75
|
+
}
|
|
76
|
+
currentDc() {
|
|
77
|
+
return this._currentDc;
|
|
78
|
+
}
|
|
79
|
+
connect(dc, testMode) {
|
|
80
|
+
this._currentDc = dc;
|
|
81
|
+
this._state = TransportState.Ready;
|
|
82
|
+
this.emit("ready");
|
|
83
|
+
this._log.debug("stubbing connection to %s:%d", dc.ipAddress, dc.port);
|
|
84
|
+
this.params.onConnect?.(dc, testMode);
|
|
85
|
+
}
|
|
86
|
+
close() {
|
|
87
|
+
this._currentDc = null;
|
|
88
|
+
this._state = TransportState.Idle;
|
|
89
|
+
this.emit("close");
|
|
90
|
+
this._log.debug("stub connection closed");
|
|
91
|
+
this.params.onClose?.();
|
|
92
|
+
}
|
|
93
|
+
async send(data) {
|
|
94
|
+
this.params.onMessage?.(data);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function markedIdToPeer(id) {
|
|
98
|
+
const [type, bareId] = parseMarkedPeerId(id);
|
|
99
|
+
switch (type) {
|
|
100
|
+
case "user":
|
|
101
|
+
return { _: "peerUser", userId: bareId };
|
|
102
|
+
case "chat":
|
|
103
|
+
return { _: "peerChat", chatId: bareId };
|
|
104
|
+
case "channel":
|
|
105
|
+
return { _: "peerChannel", channelId: bareId };
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
class StubTelegramClient extends BaseTelegramClient {
|
|
109
|
+
constructor(params) {
|
|
110
|
+
const storage = new StubMemoryTelegramStorage({
|
|
111
|
+
hasKeys: true,
|
|
112
|
+
hasTempKeys: true
|
|
113
|
+
});
|
|
114
|
+
super({
|
|
115
|
+
apiId: 0,
|
|
116
|
+
apiHash: "",
|
|
117
|
+
logLevel: 5,
|
|
118
|
+
storage,
|
|
119
|
+
disableUpdates: true,
|
|
120
|
+
transport: () => {
|
|
121
|
+
const transport = new StubTelegramTransport({
|
|
122
|
+
onMessage: (data) => {
|
|
123
|
+
if (!this._onRawMessage) {
|
|
124
|
+
if (this._responders.size) {
|
|
125
|
+
this.emitError(new Error("Unexpected outgoing message"));
|
|
126
|
+
}
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const dcId = transport._currentDc.id;
|
|
130
|
+
const key = storage.authKeys.get(dcId);
|
|
131
|
+
if (key) {
|
|
132
|
+
this._onRawMessage(storage.decryptOutgoingMessage(transport._crypto, data, dcId));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
return transport;
|
|
137
|
+
},
|
|
138
|
+
crypto: defaultCryptoProvider,
|
|
139
|
+
...params
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Create a fake client that may not actually be used for API calls
|
|
144
|
+
*
|
|
145
|
+
* Useful for testing "offline" methods
|
|
146
|
+
*/
|
|
147
|
+
static offline() {
|
|
148
|
+
const client = new StubTelegramClient();
|
|
149
|
+
client.call = (obj) => {
|
|
150
|
+
throw new Error(`Expected offline client to not make any API calls (method called: ${obj._})`);
|
|
151
|
+
};
|
|
152
|
+
return client;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Create a fake "full" client (i.e. TelegramClient)
|
|
156
|
+
*
|
|
157
|
+
* Basically a proxy that returns an empty function for every unknown method
|
|
158
|
+
*/
|
|
159
|
+
static full() {
|
|
160
|
+
const client = new StubTelegramClient();
|
|
161
|
+
return new Proxy(client, {
|
|
162
|
+
get(target, prop) {
|
|
163
|
+
if (typeof prop === "string" && !(prop in target)) {
|
|
164
|
+
return () => {
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
return target[prop];
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
// some fake peers handling //
|
|
172
|
+
_knownChats = /* @__PURE__ */ new Map();
|
|
173
|
+
_knownUsers = /* @__PURE__ */ new Map();
|
|
174
|
+
_selfId = 0;
|
|
175
|
+
async registerPeers(...peers) {
|
|
176
|
+
for (const peer of peers) {
|
|
177
|
+
if (tl.isAnyUser(peer)) {
|
|
178
|
+
this._knownUsers.set(peer.id, peer);
|
|
179
|
+
} else {
|
|
180
|
+
this._knownChats.set(peer.id, peer);
|
|
181
|
+
}
|
|
182
|
+
await this.storage.peers.updatePeersFrom(peer);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
getPeers(ids) {
|
|
186
|
+
const users = [];
|
|
187
|
+
const chats = [];
|
|
188
|
+
for (let id of ids) {
|
|
189
|
+
if (!id) continue;
|
|
190
|
+
if (typeof id === "number") {
|
|
191
|
+
id = markedIdToPeer(id);
|
|
192
|
+
}
|
|
193
|
+
switch (id._) {
|
|
194
|
+
case "peerUser": {
|
|
195
|
+
const user = this._knownUsers.get(id.userId);
|
|
196
|
+
if (!user) throw new Error(`Unknown user with ID ${id.userId}`);
|
|
197
|
+
users.push(user);
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
case "peerChat": {
|
|
201
|
+
const chat = this._knownChats.get(id.chatId);
|
|
202
|
+
if (!chat) throw new Error(`Unknown chat with ID ${id.chatId}`);
|
|
203
|
+
chats.push(chat);
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
case "peerChannel": {
|
|
207
|
+
const chat = this._knownChats.get(id.channelId);
|
|
208
|
+
if (!chat) throw new Error(`Unknown channel with ID ${id.channelId}`);
|
|
209
|
+
chats.push(chat);
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return { users, chats };
|
|
215
|
+
}
|
|
216
|
+
// method calls intercepting //
|
|
217
|
+
_onRawMessage;
|
|
218
|
+
onRawMessage(fn) {
|
|
219
|
+
this._onRawMessage = fn;
|
|
220
|
+
}
|
|
221
|
+
_responders = /* @__PURE__ */ new Map();
|
|
222
|
+
addResponder(responders) {
|
|
223
|
+
if (Array.isArray(responders)) {
|
|
224
|
+
for (const responder2 of responders) {
|
|
225
|
+
this.addResponder(responder2);
|
|
226
|
+
}
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
if (typeof responders === "function") {
|
|
230
|
+
responders = responders(this);
|
|
231
|
+
}
|
|
232
|
+
const [method, responder] = responders;
|
|
233
|
+
this.respondWith(method, responder);
|
|
234
|
+
}
|
|
235
|
+
respondWith(method, response) {
|
|
236
|
+
this._responders.set(method, response);
|
|
237
|
+
return response;
|
|
238
|
+
}
|
|
239
|
+
async call(message, params) {
|
|
240
|
+
if (this._responders.has(message._)) {
|
|
241
|
+
return Promise.resolve(this._responders.get(message._)(message));
|
|
242
|
+
}
|
|
243
|
+
return super.call(message, params);
|
|
244
|
+
}
|
|
245
|
+
// some fake updates mechanism //
|
|
246
|
+
_fakeMessageBoxes = /* @__PURE__ */ new Map();
|
|
247
|
+
_lastQts = 0;
|
|
248
|
+
_lastDate = Math.floor(Date.now() / 1e3);
|
|
249
|
+
_lastSeq = 0;
|
|
250
|
+
getMessageBox(chatId = 0) {
|
|
251
|
+
const state = this._fakeMessageBoxes.get(chatId);
|
|
252
|
+
if (!state) {
|
|
253
|
+
const newState = { pts: 0, lastMessageId: 0 };
|
|
254
|
+
this._fakeMessageBoxes.set(chatId, newState);
|
|
255
|
+
return newState;
|
|
256
|
+
}
|
|
257
|
+
return state;
|
|
258
|
+
}
|
|
259
|
+
getNextMessageId(chatId = 0) {
|
|
260
|
+
const state = this.getMessageBox(chatId);
|
|
261
|
+
const nextId = state.lastMessageId + 1;
|
|
262
|
+
state.lastMessageId = nextId;
|
|
263
|
+
return nextId;
|
|
264
|
+
}
|
|
265
|
+
getNextPts(chatId = 0, count = 1) {
|
|
266
|
+
const state = this.getMessageBox(chatId);
|
|
267
|
+
const nextPts = state.pts + count;
|
|
268
|
+
state.pts = nextPts;
|
|
269
|
+
return nextPts;
|
|
270
|
+
}
|
|
271
|
+
getNextQts() {
|
|
272
|
+
return this._lastQts++;
|
|
273
|
+
}
|
|
274
|
+
getNextDate() {
|
|
275
|
+
return this._lastDate = Math.floor(Date.now() / 1e3);
|
|
276
|
+
}
|
|
277
|
+
createStubUpdates(params) {
|
|
278
|
+
const { peers, updates, seq = 0, seqCount = 1 } = params;
|
|
279
|
+
const { users, chats } = this.getPeers(peers ?? []);
|
|
280
|
+
const seqStart = seq - seqCount + 1;
|
|
281
|
+
if (seq !== 0) {
|
|
282
|
+
this._lastSeq = seq + seqCount;
|
|
283
|
+
}
|
|
284
|
+
if (seqStart !== seq) {
|
|
285
|
+
return {
|
|
286
|
+
_: "updatesCombined",
|
|
287
|
+
updates,
|
|
288
|
+
users,
|
|
289
|
+
chats,
|
|
290
|
+
date: this.getNextDate(),
|
|
291
|
+
seq,
|
|
292
|
+
seqStart
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
return {
|
|
296
|
+
_: "updates",
|
|
297
|
+
updates,
|
|
298
|
+
users,
|
|
299
|
+
chats,
|
|
300
|
+
date: this.getNextDate(),
|
|
301
|
+
seq
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
// helpers //
|
|
305
|
+
async with(fn) {
|
|
306
|
+
await this.connect();
|
|
307
|
+
let error;
|
|
308
|
+
this.onError((err) => {
|
|
309
|
+
error = err;
|
|
310
|
+
});
|
|
311
|
+
try {
|
|
312
|
+
await fn();
|
|
313
|
+
} catch (e) {
|
|
314
|
+
error = e;
|
|
315
|
+
}
|
|
316
|
+
await this.close();
|
|
317
|
+
if (error) {
|
|
318
|
+
throw error;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
const DEFAULT_ENTROPY = `
|
|
323
|
+
29afd26df40fb8ed10b6b4ad6d56ef5df9453f88e6ee6adb6e0544ba635dc6a8a990c9b8b980c343936b33fa7f97bae025102532233abb269c489920ef99021b
|
|
324
|
+
259ce3a2c964c5c8972b4a84ff96f3375a94b535a9468f2896e2080ac7a32ed58e910474a4b02415e07671cbb5bdd58a5dd26fd137c4c98b8c346571fae6ead3
|
|
325
|
+
9dfd612bd6b480b6723433f5218e9d6e271591153fb3ffefc089f7e848d3f4633459fff66b33cf939e5655813149fa34be8625f9bc4814d1ee6cf40e4d0de229
|
|
326
|
+
1aa22e68c8ad8cc698103734f9aaf79f2bdc052a787a7a9b3629d1ed38750f88cb0481c0ba30a9c611672f9a4d1dc02637abb4e98913ee810a3b152d3d75f25d
|
|
327
|
+
7efdc263c08833569968b1771ebbe843d187e2c917d9ad8e8865e44b69f7b74d72ab86a4ef1891dce196ee11a7c9d7d8074fc0450e745bd3a827d77bb0820b90
|
|
328
|
+
3055dc15f0abd897ea740a99606b64d28968d770b5e43492ddbf07a7c75104d3e522be9b72050c0fdae8412cdf49014be21105b87a06cb7202dd580387adc007
|
|
329
|
+
6280d98b015a1a413819d817f007939d1490467a1ef85a345584c7e594bb729c12a1233f806e515e7088360219dfa109264310ba84777b93eb1ad3c40727a25a
|
|
330
|
+
a5d9cdd6748c6ab2ca0bd4daa2ba8225bce2b066a163bcacf05609fc84055bb86a4742c28addd7d7ab8d87b64cfde0b3f4b3bc8e05f3d0a1a2fadb294860e099
|
|
331
|
+
a10b3721b0d5b28918b8fb49a18a82a0fde6680a64ed915637805e35ffe8b2c1d4177ec10d10eaaf24425e0351b6a89e794944e1aa82eb5c0210a37da66cccac
|
|
332
|
+
895398cf915a8aa141f611521fc258514a99c02721113942c66f2c9a8f9601ff0044a953d17a47b07ad1b5f8725cc020a1a5239be65db0a43d42c206903740f0
|
|
333
|
+
27c3f749ecfff2e646570118cd54db2fec392b44d8eb8377309f3e4d164dbc0530914b117b9d278b06db8359d97442d4dcbcaff93cd9a08a6b06a5ba8725d0d7
|
|
334
|
+
06b313a5d792be254d33e087b7a4fafcdf819941b9bec4c6057d4c050bd01eb243efd4e6b707281b127820a2b734c6d8f6b2131bf0b5b215c7a798ff3fe90ceb
|
|
335
|
+
da91539fcc7b03d2b8b1381bd6023fff20278344ad944d364ba684842db3901c346335f0d455eda414f99c1e794a86aa3a90bcc6e085eecb0b4bf61198d16ed3
|
|
336
|
+
89cfa495f977a37a51502b2f60649f2efd7d89c757b6366776ba4c0612017bf1fbfc682dd62e9960d39cbea854d2dcc708b1db5d268192954d13ee72c0bb1bd8
|
|
337
|
+
558a3cf3b02b1cd795b40f7a57780391bb8724883d3f7764846c3823e165b3f8c025f59d896905f9a955478586ce57f820d958a01aa59a4cace7ecdf125df334
|
|
338
|
+
fa3de8e50aac96c1275591a1221c32a60a1513370a33a228e00894341b10cf44a6ae6ac250d17a364e956ab1a17b068df3fb2d5b5a672d8a409eeb8b6ca1ade6
|
|
339
|
+
`.replace(/\s/g, "");
|
|
340
|
+
function withFakeRandom(provider, source = DEFAULT_ENTROPY) {
|
|
341
|
+
const sourceBytes = getPlatform().hexDecode(source);
|
|
342
|
+
let offset = 0;
|
|
343
|
+
function getRandomValues(buf) {
|
|
344
|
+
if (offset + buf.length > sourceBytes.length) {
|
|
345
|
+
throw new Error("not enough entropy");
|
|
346
|
+
}
|
|
347
|
+
buf.set(sourceBytes.subarray(offset, offset + buf.length));
|
|
348
|
+
offset += buf.length;
|
|
349
|
+
}
|
|
350
|
+
return new Proxy(provider, {
|
|
351
|
+
get(target, prop, receiver) {
|
|
352
|
+
if (prop === "randomFill") return getRandomValues;
|
|
353
|
+
return Reflect.get(target, prop, receiver);
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
function useFakeMathRandom(source = DEFAULT_ENTROPY) {
|
|
358
|
+
const sourceBytes = getPlatform().hexDecode(source);
|
|
359
|
+
const dv = dataViewFromBuffer(sourceBytes);
|
|
360
|
+
let spy;
|
|
361
|
+
beforeEach(() => {
|
|
362
|
+
let offset = 0;
|
|
363
|
+
spy = vi.spyOn(globalThis.Math, "random").mockImplementation(() => {
|
|
364
|
+
const ret = dv.getUint32(offset, true) / 4294967295;
|
|
365
|
+
offset += 4;
|
|
366
|
+
return ret;
|
|
367
|
+
});
|
|
368
|
+
});
|
|
369
|
+
afterEach(() => {
|
|
370
|
+
spy.mockRestore();
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
async function defaultTestCryptoProvider(source = DEFAULT_ENTROPY) {
|
|
374
|
+
const prov = withFakeRandom(defaultCryptoProvider, source);
|
|
375
|
+
await prov.initialize?.();
|
|
376
|
+
return prov;
|
|
377
|
+
}
|
|
378
|
+
function testCryptoProvider(c) {
|
|
379
|
+
beforeAll(() => c.initialize?.());
|
|
380
|
+
const p = getPlatform();
|
|
381
|
+
function gzipSyncWrap(data) {
|
|
382
|
+
return gzipSync(data);
|
|
383
|
+
}
|
|
384
|
+
function inflateSyncWrap(data) {
|
|
385
|
+
return inflateSync(data);
|
|
386
|
+
}
|
|
387
|
+
it("should calculate sha1", () => {
|
|
388
|
+
expect(p.hexEncode(c.sha1(p.utf8Encode("")))).to.eq("da39a3ee5e6b4b0d3255bfef95601890afd80709");
|
|
389
|
+
expect(p.hexEncode(c.sha1(p.utf8Encode("hello")))).to.eq("aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d");
|
|
390
|
+
expect(p.hexEncode(c.sha1(p.hexDecode("aebb1f")))).to.eq("62849d15c5dea495916c5eea8dba5f9551288850");
|
|
391
|
+
});
|
|
392
|
+
it("should calculate sha256", () => {
|
|
393
|
+
expect(p.hexEncode(c.sha256(p.utf8Encode("")))).to.eq(
|
|
394
|
+
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
|
395
|
+
);
|
|
396
|
+
expect(p.hexEncode(c.sha256(p.utf8Encode("hello")))).to.eq(
|
|
397
|
+
"2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
|
|
398
|
+
);
|
|
399
|
+
expect(p.hexEncode(c.sha256(p.hexDecode("aebb1f")))).to.eq(
|
|
400
|
+
"2d29658aba48f2b286fe8bbddb931b7ad297e5adb5b9a6fc3aab67ef7fbf4e80"
|
|
401
|
+
);
|
|
402
|
+
});
|
|
403
|
+
it("should calculate hmac-sha256", async () => {
|
|
404
|
+
const key = p.hexDecode("aaeeff");
|
|
405
|
+
expect(p.hexEncode(await c.hmacSha256(p.utf8Encode(""), key))).to.eq(
|
|
406
|
+
"642711307c9e4437df09d6ebaa6bdc1b3a810c7f15c50fd1d0f8d7d5490f44dd"
|
|
407
|
+
);
|
|
408
|
+
expect(p.hexEncode(await c.hmacSha256(p.utf8Encode("hello"), key))).to.eq(
|
|
409
|
+
"39b00bab151f9868e6501655c580b5542954711181243474d46b894703b1c1c2"
|
|
410
|
+
);
|
|
411
|
+
expect(p.hexEncode(await c.hmacSha256(p.hexDecode("aebb1f"), key))).to.eq(
|
|
412
|
+
"a3a7273871808711cab17aba14f58e96f63f3ccfc5097d206f0f00ead2c3dd35"
|
|
413
|
+
);
|
|
414
|
+
});
|
|
415
|
+
it("should derive pbkdf2 key", async () => {
|
|
416
|
+
expect(p.hexEncode(await c.pbkdf2(p.utf8Encode("pbkdf2 test"), p.utf8Encode("some salt"), 10))).to.eq(
|
|
417
|
+
"e43276cfa27f135f261cec8ddcf593fd74ec251038e459c165461f2308f3a7235e0744ee1aed9710b00db28d1a2112e20fea3601c60e770ac57ffe6b33ca8be1"
|
|
418
|
+
);
|
|
419
|
+
});
|
|
420
|
+
it("should encrypt and decrypt aes-ctr", () => {
|
|
421
|
+
let aes = c.createAesCtr(
|
|
422
|
+
p.hexDecode("d450aae0bf0060a4af1044886b42a13f7c506b35255d134a7e87ab3f23a9493b"),
|
|
423
|
+
p.hexDecode("0182de2bd789c295c3c6c875c5e9e190"),
|
|
424
|
+
true
|
|
425
|
+
);
|
|
426
|
+
const data = p.hexDecode("7baae571e4c2f4cfadb1931d5923aca7");
|
|
427
|
+
expect(p.hexEncode(aes.process(data))).eq("df5647dbb70bc393f2fb05b72f42286f");
|
|
428
|
+
expect(p.hexEncode(aes.process(data))).eq("3917147082672516b3177150129bc579");
|
|
429
|
+
expect(p.hexEncode(aes.process(data))).eq("2a7a9089270a5de45d5e3dd399cac725");
|
|
430
|
+
expect(p.hexEncode(aes.process(data))).eq("56d085217771398ac13583de4d677dd8");
|
|
431
|
+
expect(p.hexEncode(aes.process(data))).eq("cc639b488126cf36e79c4515e8012b92");
|
|
432
|
+
expect(p.hexEncode(aes.process(data))).eq("01384d100646cd562cc5586ec3f8f8c4");
|
|
433
|
+
aes.close?.();
|
|
434
|
+
aes = c.createAesCtr(
|
|
435
|
+
p.hexDecode("d450aae0bf0060a4af1044886b42a13f7c506b35255d134a7e87ab3f23a9493b"),
|
|
436
|
+
p.hexDecode("0182de2bd789c295c3c6c875c5e9e190"),
|
|
437
|
+
false
|
|
438
|
+
);
|
|
439
|
+
expect(p.hexEncode(aes.process(p.hexDecode("df5647dbb70bc393f2fb05b72f42286f")))).eq(p.hexEncode(data));
|
|
440
|
+
expect(p.hexEncode(aes.process(p.hexDecode("3917147082672516b3177150129bc579")))).eq(p.hexEncode(data));
|
|
441
|
+
expect(p.hexEncode(aes.process(p.hexDecode("2a7a9089270a5de45d5e3dd399cac725")))).eq(p.hexEncode(data));
|
|
442
|
+
expect(p.hexEncode(aes.process(p.hexDecode("56d085217771398ac13583de4d677dd8")))).eq(p.hexEncode(data));
|
|
443
|
+
expect(p.hexEncode(aes.process(p.hexDecode("cc639b488126cf36e79c4515e8012b92")))).eq(p.hexEncode(data));
|
|
444
|
+
expect(p.hexEncode(aes.process(p.hexDecode("01384d100646cd562cc5586ec3f8f8c4")))).eq(p.hexEncode(data));
|
|
445
|
+
aes.close?.();
|
|
446
|
+
});
|
|
447
|
+
it("should encrypt and decrypt aes-ige", () => {
|
|
448
|
+
const aes = c.createAesIge(
|
|
449
|
+
p.hexDecode("5468697320697320616E20696D706C655468697320697320616E20696D706C65"),
|
|
450
|
+
p.hexDecode("6D656E746174696F6E206F6620494745206D6F646520666F72204F70656E5353")
|
|
451
|
+
);
|
|
452
|
+
expect(
|
|
453
|
+
p.hexEncode(aes.encrypt(p.hexDecode("99706487a1cde613bc6de0b6f24b1c7aa448c8b9c3403e3467a8cad89340f53b")))
|
|
454
|
+
).to.eq("792ea8ae577b1a66cb3bd92679b8030ca54ee631976bd3a04547fdcb4639fa69");
|
|
455
|
+
expect(
|
|
456
|
+
p.hexEncode(aes.decrypt(p.hexDecode("792ea8ae577b1a66cb3bd92679b8030ca54ee631976bd3a04547fdcb4639fa69")))
|
|
457
|
+
).to.eq("99706487a1cde613bc6de0b6f24b1c7aa448c8b9c3403e3467a8cad89340f53b");
|
|
458
|
+
});
|
|
459
|
+
it(
|
|
460
|
+
"should decompose PQ to prime factors P and Q",
|
|
461
|
+
async () => {
|
|
462
|
+
const testFactorization = async (pq, p_, q) => {
|
|
463
|
+
const [p1, q1] = await c.factorizePQ(p.hexDecode(pq));
|
|
464
|
+
expect(p.hexEncode(p1)).eq(p_.toLowerCase());
|
|
465
|
+
expect(p.hexEncode(q1)).eq(q.toLowerCase());
|
|
466
|
+
};
|
|
467
|
+
await testFactorization("17ED48941A08F981", "494C553B", "53911073");
|
|
468
|
+
await testFactorization("14fcab4dfc861f45", "494c5c99", "494c778d");
|
|
469
|
+
},
|
|
470
|
+
// since PQ factorization relies on RNG, it may take a while (or may not!)
|
|
471
|
+
{ timeout: 1e4 }
|
|
472
|
+
);
|
|
473
|
+
it("should correctly gzip", () => {
|
|
474
|
+
const data = new Uint8Array(1e3).fill(66);
|
|
475
|
+
const compressed = c.gzip(data, 100);
|
|
476
|
+
expect(compressed).not.toBeNull();
|
|
477
|
+
const decompressed = inflateSyncWrap(compressed);
|
|
478
|
+
expect(compressed.length).toBeLessThan(data.length);
|
|
479
|
+
expect(p.hexEncode(decompressed)).toEqual(p.hexEncode(data));
|
|
480
|
+
});
|
|
481
|
+
it("should correctly gunzip", () => {
|
|
482
|
+
const data = new Uint8Array(1e3).fill(66);
|
|
483
|
+
const compressed = gzipSyncWrap(data);
|
|
484
|
+
const decompressed = c.gunzip(compressed);
|
|
485
|
+
expect(p.hexEncode(decompressed)).toEqual(p.hexEncode(data));
|
|
486
|
+
});
|
|
487
|
+
describe("randomBytes", () => {
|
|
488
|
+
it("should return exactly N bytes", () => {
|
|
489
|
+
expect(c.randomBytes(0).length).eq(0);
|
|
490
|
+
expect(c.randomBytes(5).length).eq(5);
|
|
491
|
+
expect(c.randomBytes(10).length).eq(10);
|
|
492
|
+
expect(c.randomBytes(256).length).eq(256);
|
|
493
|
+
});
|
|
494
|
+
it("should not be deterministic", () => {
|
|
495
|
+
expect([...c.randomBytes(8)]).not.eql([...c.randomBytes(8)]);
|
|
496
|
+
});
|
|
497
|
+
it("should use randomFill", () => {
|
|
498
|
+
const spy = vi.spyOn(c, "randomFill");
|
|
499
|
+
c.randomBytes(8);
|
|
500
|
+
expect(spy).toHaveBeenCalled();
|
|
501
|
+
});
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
function u8HexDecode(hex) {
|
|
505
|
+
const buf = getPlatform().hexDecode(hex);
|
|
506
|
+
return buf;
|
|
507
|
+
}
|
|
508
|
+
function fakeAuthKeysRepository() {
|
|
509
|
+
return {
|
|
510
|
+
get: vi.fn(),
|
|
511
|
+
set: vi.fn(),
|
|
512
|
+
getTemp: vi.fn(),
|
|
513
|
+
setTemp: vi.fn(),
|
|
514
|
+
deleteByDc: vi.fn(),
|
|
515
|
+
deleteAll: vi.fn()
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
function fixBuffer$1(buf) {
|
|
519
|
+
if (!buf) return buf;
|
|
520
|
+
return typeof Buffer !== "undefined" && buf instanceof Buffer ? new Uint8Array(buf) : buf;
|
|
521
|
+
}
|
|
522
|
+
function testAuthKeysRepository(repo) {
|
|
523
|
+
const key2 = new Uint8Array(256).fill(66);
|
|
524
|
+
const key3 = new Uint8Array(256).fill(67);
|
|
525
|
+
const key2i0 = new Uint8Array(256).fill(68);
|
|
526
|
+
const key2i1 = new Uint8Array(256).fill(69);
|
|
527
|
+
const key3i0 = new Uint8Array(256).fill(70);
|
|
528
|
+
const key3i1 = new Uint8Array(256).fill(71);
|
|
529
|
+
describe("auth keys", () => {
|
|
530
|
+
afterEach(() => repo.deleteAll());
|
|
531
|
+
it("should be empty by default", async () => {
|
|
532
|
+
expect(fixBuffer$1(await repo.get(2))).toEqual(null);
|
|
533
|
+
expect(fixBuffer$1(await repo.get(3))).toEqual(null);
|
|
534
|
+
});
|
|
535
|
+
it("should store and retrieve auth keys", async () => {
|
|
536
|
+
await repo.set(2, key2);
|
|
537
|
+
await repo.set(3, key3);
|
|
538
|
+
expect(fixBuffer$1(await repo.get(2))).toEqual(key2);
|
|
539
|
+
expect(fixBuffer$1(await repo.get(3))).toEqual(key3);
|
|
540
|
+
});
|
|
541
|
+
it("should delete auth keys", async () => {
|
|
542
|
+
await repo.set(2, key2);
|
|
543
|
+
await repo.set(3, key3);
|
|
544
|
+
await repo.set(2, null);
|
|
545
|
+
await repo.set(3, null);
|
|
546
|
+
expect(fixBuffer$1(await repo.get(2))).toEqual(null);
|
|
547
|
+
expect(fixBuffer$1(await repo.get(3))).toEqual(null);
|
|
548
|
+
});
|
|
549
|
+
it("should store and retrieve temp auth keys", async () => {
|
|
550
|
+
await repo.setTemp(2, 0, key2i0, 1);
|
|
551
|
+
await repo.setTemp(2, 1, key2i1, 1);
|
|
552
|
+
await repo.setTemp(3, 0, key3i0, 1);
|
|
553
|
+
await repo.setTemp(3, 1, key3i1, 1);
|
|
554
|
+
expect(fixBuffer$1(await repo.getTemp(2, 0, 0))).toEqual(key2i0);
|
|
555
|
+
expect(fixBuffer$1(await repo.getTemp(2, 1, 0))).toEqual(key2i1);
|
|
556
|
+
expect(fixBuffer$1(await repo.getTemp(3, 0, 0))).toEqual(key3i0);
|
|
557
|
+
expect(fixBuffer$1(await repo.getTemp(3, 1, 0))).toEqual(key3i1);
|
|
558
|
+
expect(fixBuffer$1(await repo.getTemp(2, 0, 100))).toEqual(null);
|
|
559
|
+
expect(fixBuffer$1(await repo.getTemp(2, 1, 100))).toEqual(null);
|
|
560
|
+
expect(fixBuffer$1(await repo.getTemp(3, 0, 100))).toEqual(null);
|
|
561
|
+
expect(fixBuffer$1(await repo.getTemp(3, 1, 100))).toEqual(null);
|
|
562
|
+
});
|
|
563
|
+
it("should delete temp auth keys", async () => {
|
|
564
|
+
await repo.setTemp(2, 0, key2i0, 1);
|
|
565
|
+
await repo.setTemp(2, 1, key2i1, 1);
|
|
566
|
+
await repo.setTemp(3, 0, key3i0, 1);
|
|
567
|
+
await repo.setTemp(3, 1, key3i1, 1);
|
|
568
|
+
await repo.setTemp(2, 0, null, 1);
|
|
569
|
+
await repo.setTemp(2, 1, null, 1);
|
|
570
|
+
await repo.setTemp(3, 0, null, 1);
|
|
571
|
+
await repo.setTemp(3, 1, null, 1);
|
|
572
|
+
expect(fixBuffer$1(await repo.getTemp(2, 0, 0))).toEqual(null);
|
|
573
|
+
expect(fixBuffer$1(await repo.getTemp(2, 1, 0))).toEqual(null);
|
|
574
|
+
expect(fixBuffer$1(await repo.getTemp(3, 0, 0))).toEqual(null);
|
|
575
|
+
expect(fixBuffer$1(await repo.getTemp(3, 1, 0))).toEqual(null);
|
|
576
|
+
});
|
|
577
|
+
it("should delete all auth keys by DC", async () => {
|
|
578
|
+
await repo.set(2, key2);
|
|
579
|
+
await repo.set(3, key3);
|
|
580
|
+
await repo.setTemp(2, 0, key2i0, 1);
|
|
581
|
+
await repo.setTemp(2, 1, key2i1, 1);
|
|
582
|
+
await repo.setTemp(3, 0, key3i0, 1);
|
|
583
|
+
await repo.setTemp(3, 1, key3i1, 1);
|
|
584
|
+
await repo.deleteByDc(2);
|
|
585
|
+
expect(fixBuffer$1(await repo.get(2))).toEqual(null);
|
|
586
|
+
expect(fixBuffer$1(await repo.get(3))).toEqual(key3);
|
|
587
|
+
expect(fixBuffer$1(await repo.getTemp(2, 0, 0))).toEqual(null);
|
|
588
|
+
expect(fixBuffer$1(await repo.getTemp(2, 1, 0))).toEqual(null);
|
|
589
|
+
expect(fixBuffer$1(await repo.getTemp(3, 0, 0))).toEqual(key3i0);
|
|
590
|
+
expect(fixBuffer$1(await repo.getTemp(3, 1, 0))).toEqual(key3i1);
|
|
591
|
+
});
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
function fakeKeyValueRepository() {
|
|
595
|
+
return {
|
|
596
|
+
get: vi.fn(),
|
|
597
|
+
set: vi.fn(),
|
|
598
|
+
delete: vi.fn(),
|
|
599
|
+
deleteAll: vi.fn()
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
function fixBuffer(buf) {
|
|
603
|
+
if (!buf) return buf;
|
|
604
|
+
return typeof Buffer !== "undefined" && buf instanceof Buffer ? new Uint8Array(buf) : buf;
|
|
605
|
+
}
|
|
606
|
+
function testKeyValueRepository(repo, driver) {
|
|
607
|
+
describe("key-value", () => {
|
|
608
|
+
afterEach(() => repo.deleteAll());
|
|
609
|
+
it("should be empty by default", async () => {
|
|
610
|
+
expect(fixBuffer(await repo.get("key"))).toEqual(null);
|
|
611
|
+
});
|
|
612
|
+
it("should store and retrieve values", async () => {
|
|
613
|
+
await repo.set("key", new Uint8Array([1, 2, 3]));
|
|
614
|
+
await driver.save?.();
|
|
615
|
+
expect(fixBuffer(await repo.get("key"))).toEqual(new Uint8Array([1, 2, 3]));
|
|
616
|
+
});
|
|
617
|
+
it("should delete values", async () => {
|
|
618
|
+
await repo.set("key", new Uint8Array([1, 2, 3]));
|
|
619
|
+
await driver.save?.();
|
|
620
|
+
await repo.delete("key");
|
|
621
|
+
await driver.save?.();
|
|
622
|
+
expect(fixBuffer(await repo.get("key"))).toEqual(null);
|
|
623
|
+
});
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
const schema = "default" in schema_ ? schema_.default : schema_;
|
|
627
|
+
let _cachedEntriesMap = null;
|
|
628
|
+
let _cachedUnionsMap = null;
|
|
629
|
+
function getEntriesMap() {
|
|
630
|
+
if (_cachedEntriesMap) {
|
|
631
|
+
return {
|
|
632
|
+
entries: _cachedEntriesMap,
|
|
633
|
+
unions: _cachedUnionsMap
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
_cachedEntriesMap = /* @__PURE__ */ new Map();
|
|
637
|
+
_cachedUnionsMap = /* @__PURE__ */ new Map();
|
|
638
|
+
let entry;
|
|
639
|
+
for (entry of schema.e) {
|
|
640
|
+
_cachedEntriesMap.set(entry.name, entry);
|
|
641
|
+
if (!_cachedUnionsMap.has(entry.type)) {
|
|
642
|
+
_cachedUnionsMap.set(entry.type, []);
|
|
643
|
+
}
|
|
644
|
+
_cachedUnionsMap.get(entry.type).push(entry);
|
|
645
|
+
}
|
|
646
|
+
return {
|
|
647
|
+
entries: _cachedEntriesMap,
|
|
648
|
+
unions: _cachedUnionsMap
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
function getDefaultFor(arg) {
|
|
652
|
+
if (arg.typeModifiers?.isVector || arg.typeModifiers?.isBareVector) {
|
|
653
|
+
return [];
|
|
654
|
+
}
|
|
655
|
+
if (arg.typeModifiers?.predicate) {
|
|
656
|
+
return arg.type === "true" ? false : void 0;
|
|
657
|
+
}
|
|
658
|
+
switch (arg.type) {
|
|
659
|
+
case "int":
|
|
660
|
+
case "int53":
|
|
661
|
+
case "double":
|
|
662
|
+
return 0;
|
|
663
|
+
case "long":
|
|
664
|
+
return Long.ZERO;
|
|
665
|
+
case "int128":
|
|
666
|
+
return new Uint8Array(16);
|
|
667
|
+
case "int256":
|
|
668
|
+
return new Uint8Array(32);
|
|
669
|
+
case "string":
|
|
670
|
+
return "";
|
|
671
|
+
case "bytes":
|
|
672
|
+
return new Uint8Array(0);
|
|
673
|
+
case "Bool":
|
|
674
|
+
case "bool":
|
|
675
|
+
return false;
|
|
676
|
+
default: {
|
|
677
|
+
const union = getEntriesMap().unions.get(arg.type);
|
|
678
|
+
if (!union) throw new Error(`Unknown type ${arg.type}`);
|
|
679
|
+
return createStub(union[0].name);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
function snakeToCamel(s) {
|
|
684
|
+
return s.replace(/(?<!^|_)_[a-z0-9]/gi, ($1) => {
|
|
685
|
+
return $1.substring(1).toUpperCase();
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
function createStub(name, partial = {}) {
|
|
689
|
+
const { entries } = getEntriesMap();
|
|
690
|
+
const entry = entries.get(name);
|
|
691
|
+
if (!entry) throw new Error(`Entry ${name} is unknown`);
|
|
692
|
+
const ret = {
|
|
693
|
+
_: name
|
|
694
|
+
};
|
|
695
|
+
for (const arg of entry.arguments) {
|
|
696
|
+
if (arg.type === "#") continue;
|
|
697
|
+
if (arg.name in partial) continue;
|
|
698
|
+
ret[snakeToCamel(arg.name)] = getDefaultFor(arg);
|
|
699
|
+
}
|
|
700
|
+
for (const key in partial) {
|
|
701
|
+
ret[key] = partial[key];
|
|
702
|
+
}
|
|
703
|
+
return ret;
|
|
704
|
+
}
|
|
705
|
+
function fakePeersRepository() {
|
|
706
|
+
return {
|
|
707
|
+
getById: vi.fn(),
|
|
708
|
+
getByUsername: vi.fn(),
|
|
709
|
+
getByPhone: vi.fn(),
|
|
710
|
+
store: vi.fn(),
|
|
711
|
+
deleteAll: vi.fn()
|
|
712
|
+
};
|
|
713
|
+
}
|
|
714
|
+
function fixPeerInfo(peer) {
|
|
715
|
+
if (!peer) return peer;
|
|
716
|
+
return {
|
|
717
|
+
...peer,
|
|
718
|
+
complete: (
|
|
719
|
+
// eslint-disable-next-line no-restricted-globals
|
|
720
|
+
typeof Buffer !== "undefined" && peer.complete instanceof Buffer ? new Uint8Array(peer.complete) : peer.complete
|
|
721
|
+
)
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
function testPeersRepository(repo, driver) {
|
|
725
|
+
const stubPeerUser = {
|
|
726
|
+
id: 123123,
|
|
727
|
+
accessHash: "123|456",
|
|
728
|
+
isMin: false,
|
|
729
|
+
usernames: ["some_user"],
|
|
730
|
+
phone: "78005553535",
|
|
731
|
+
updated: 666,
|
|
732
|
+
complete: TlBinaryWriter.serializeObject(__tlWriterMap, createStub("user", { id: 123123 }))
|
|
733
|
+
};
|
|
734
|
+
const stubPeerChannel = {
|
|
735
|
+
id: -1001183945448,
|
|
736
|
+
accessHash: "666|555",
|
|
737
|
+
isMin: false,
|
|
738
|
+
usernames: ["some_channel"],
|
|
739
|
+
updated: 777,
|
|
740
|
+
complete: TlBinaryWriter.serializeObject(__tlWriterMap, createStub("channel", { id: 123123 }))
|
|
741
|
+
};
|
|
742
|
+
const stupPeerMinUser = { ...stubPeerUser, isMin: true };
|
|
743
|
+
describe("peers", () => {
|
|
744
|
+
it("should be empty by default", async () => {
|
|
745
|
+
expect(await repo.getById(123123, false)).toEqual(null);
|
|
746
|
+
expect(await repo.getByUsername("some_user")).toEqual(null);
|
|
747
|
+
expect(await repo.getByPhone("phone")).toEqual(null);
|
|
748
|
+
});
|
|
749
|
+
it("should store and retrieve peers", async () => {
|
|
750
|
+
await repo.store(stubPeerUser);
|
|
751
|
+
await repo.store(stubPeerChannel);
|
|
752
|
+
await driver.save?.();
|
|
753
|
+
expect(fixPeerInfo(await repo.getById(123123, false))).toEqual(stubPeerUser);
|
|
754
|
+
expect(fixPeerInfo(await repo.getByUsername("some_user"))).toEqual(stubPeerUser);
|
|
755
|
+
expect(fixPeerInfo(await repo.getByPhone("78005553535"))).toEqual(stubPeerUser);
|
|
756
|
+
expect(fixPeerInfo(await repo.getById(-1001183945448, false))).toEqual(stubPeerChannel);
|
|
757
|
+
expect(fixPeerInfo(await repo.getByUsername("some_channel"))).toEqual(stubPeerChannel);
|
|
758
|
+
});
|
|
759
|
+
it("should update peers usernames", async () => {
|
|
760
|
+
await repo.store(stubPeerUser);
|
|
761
|
+
await driver.save?.();
|
|
762
|
+
const modUser = { ...stubPeerUser, usernames: ["some_user2"] };
|
|
763
|
+
await repo.store(modUser);
|
|
764
|
+
await driver.save?.();
|
|
765
|
+
expect(fixPeerInfo(await repo.getById(123123, false))).toEqual(modUser);
|
|
766
|
+
expect(await repo.getByUsername("some_user")).toEqual(null);
|
|
767
|
+
expect(fixPeerInfo(await repo.getByUsername("some_user2"))).toEqual(modUser);
|
|
768
|
+
});
|
|
769
|
+
it("should not return min peers by default", async () => {
|
|
770
|
+
await repo.deleteAll();
|
|
771
|
+
await repo.store(stupPeerMinUser);
|
|
772
|
+
await driver.save?.();
|
|
773
|
+
expect(await repo.getById(123123, false)).toEqual(null);
|
|
774
|
+
expect(await repo.getByUsername("some_user")).toEqual(null);
|
|
775
|
+
expect(await repo.getByPhone("78005553535")).toEqual(null);
|
|
776
|
+
expect(fixPeerInfo(await repo.getById(123123, true))).toEqual(stupPeerMinUser);
|
|
777
|
+
});
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
function fakeRefMessagesRepository() {
|
|
781
|
+
return {
|
|
782
|
+
store: vi.fn(),
|
|
783
|
+
getByPeer: vi.fn(),
|
|
784
|
+
delete: vi.fn(),
|
|
785
|
+
deleteByPeer: vi.fn(),
|
|
786
|
+
deleteAll: vi.fn()
|
|
787
|
+
};
|
|
788
|
+
}
|
|
789
|
+
function testRefMessagesRepository(repo, driver) {
|
|
790
|
+
describe("IReferenceMessagesRepository", () => {
|
|
791
|
+
afterEach(() => repo.deleteAll());
|
|
792
|
+
it("should be empty by default", async () => {
|
|
793
|
+
expect(await repo.getByPeer(1)).toEqual(null);
|
|
794
|
+
});
|
|
795
|
+
it("should store and retrieve reference messages", async () => {
|
|
796
|
+
await repo.store(1, 2, 3);
|
|
797
|
+
await repo.store(1, 4, 5);
|
|
798
|
+
await repo.store(2, 6, 7);
|
|
799
|
+
await driver.save?.();
|
|
800
|
+
expect(await repo.getByPeer(1)).deep.oneOf([
|
|
801
|
+
[2, 3],
|
|
802
|
+
[4, 5]
|
|
803
|
+
]);
|
|
804
|
+
expect(await repo.getByPeer(2)).toEqual([6, 7]);
|
|
805
|
+
expect(await repo.getByPeer(3)).toEqual(null);
|
|
806
|
+
expect(await repo.getByPeer(4)).toEqual(null);
|
|
807
|
+
expect(await repo.getByPeer(5)).toEqual(null);
|
|
808
|
+
expect(await repo.getByPeer(6)).toEqual(null);
|
|
809
|
+
expect(await repo.getByPeer(7)).toEqual(null);
|
|
810
|
+
});
|
|
811
|
+
it("should delete reference messages", async () => {
|
|
812
|
+
await repo.store(1, 2, 3);
|
|
813
|
+
await repo.store(1, 4, 5);
|
|
814
|
+
await repo.store(2, 6, 7);
|
|
815
|
+
await driver.save?.();
|
|
816
|
+
await repo.delete(4, [5]);
|
|
817
|
+
await driver.save?.();
|
|
818
|
+
expect(await repo.getByPeer(1)).toEqual([2, 3]);
|
|
819
|
+
await repo.delete(2, [2, 3, 4]);
|
|
820
|
+
await driver.save?.();
|
|
821
|
+
expect(await repo.getByPeer(1)).toEqual(null);
|
|
822
|
+
});
|
|
823
|
+
it("should delete all reference messages for a peer", async () => {
|
|
824
|
+
await repo.store(1, 2, 3);
|
|
825
|
+
await repo.store(1, 4, 5);
|
|
826
|
+
await repo.store(1, 6, 7);
|
|
827
|
+
await repo.store(2, 20, 30);
|
|
828
|
+
await repo.store(2, 40, 50);
|
|
829
|
+
await repo.store(2, 60, 70);
|
|
830
|
+
await driver.save?.();
|
|
831
|
+
await repo.deleteByPeer(1);
|
|
832
|
+
await driver.save?.();
|
|
833
|
+
expect(await repo.getByPeer(1)).toEqual(null);
|
|
834
|
+
expect(await repo.getByPeer(2)).deep.oneOf([
|
|
835
|
+
[20, 30],
|
|
836
|
+
[40, 50],
|
|
837
|
+
[60, 70]
|
|
838
|
+
]);
|
|
839
|
+
});
|
|
840
|
+
});
|
|
841
|
+
}
|
|
842
|
+
export {
|
|
843
|
+
StubMemoryTelegramStorage,
|
|
844
|
+
StubTelegramClient,
|
|
845
|
+
StubTelegramTransport,
|
|
846
|
+
createStub,
|
|
847
|
+
defaultCryptoProvider,
|
|
848
|
+
defaultPlatform,
|
|
849
|
+
defaultTestCryptoProvider,
|
|
850
|
+
fakeAuthKeysRepository,
|
|
851
|
+
fakeKeyValueRepository,
|
|
852
|
+
fakePeersRepository,
|
|
853
|
+
fakeRefMessagesRepository,
|
|
854
|
+
testAuthKeysRepository,
|
|
855
|
+
testCryptoProvider,
|
|
856
|
+
testKeyValueRepository,
|
|
857
|
+
testPeersRepository,
|
|
858
|
+
testRefMessagesRepository,
|
|
859
|
+
u8HexDecode,
|
|
860
|
+
useFakeMathRandom,
|
|
861
|
+
withFakeRandom
|
|
862
|
+
};
|