@mtcute/core 0.1.1 → 0.1.2
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/cjs/network/auth-key.test.d.ts +1 -0
- package/cjs/network/auth-key.test.js +111 -0
- package/cjs/network/auth-key.test.js.map +1 -0
- package/cjs/network/config-manager.js +2 -1
- package/cjs/network/config-manager.js.map +1 -1
- package/cjs/network/config-manager.test.d.ts +1 -0
- package/cjs/network/config-manager.test.js +170 -0
- package/cjs/network/config-manager.test.js.map +1 -0
- package/cjs/network/network-manager.js +1 -1
- package/cjs/network/persistent-connection.test.d.ts +1 -0
- package/cjs/network/persistent-connection.test.js +157 -0
- package/cjs/network/persistent-connection.test.js.map +1 -0
- package/cjs/network/session-connection.js +3 -2
- package/cjs/network/session-connection.js.map +1 -1
- package/cjs/network/transports/intermediate.test.d.ts +1 -0
- package/cjs/network/transports/intermediate.test.js +86 -0
- package/cjs/network/transports/intermediate.test.js.map +1 -0
- package/cjs/network/transports/obfuscated.js +1 -1
- package/cjs/network/transports/obfuscated.js.map +1 -1
- package/cjs/network/transports/obfuscated.test.d.ts +1 -0
- package/cjs/network/transports/obfuscated.test.js +131 -0
- package/cjs/network/transports/obfuscated.test.js.map +1 -0
- package/cjs/network/transports/tcp.js +1 -1
- package/cjs/network/transports/tcp.js.map +1 -1
- package/cjs/network/transports/tcp.test.d.ts +1 -0
- package/cjs/network/transports/tcp.test.js +97 -0
- package/cjs/network/transports/tcp.test.js.map +1 -0
- package/cjs/network/transports/websocket.test.d.ts +1 -0
- package/cjs/network/transports/websocket.test.js +91 -0
- package/cjs/network/transports/websocket.test.js.map +1 -0
- package/cjs/storage/json.test.d.ts +1 -0
- package/cjs/storage/json.test.js +37 -0
- package/cjs/storage/json.test.js.map +1 -0
- package/cjs/storage/localstorage.test.d.ts +1 -0
- package/cjs/storage/localstorage.test.js +23 -0
- package/cjs/storage/localstorage.test.js.map +1 -0
- package/cjs/storage/memory.test.d.ts +1 -0
- package/cjs/storage/memory.test.js +47 -0
- package/cjs/storage/memory.test.js.map +1 -0
- package/cjs/utils/async-lock.test.d.ts +1 -0
- package/cjs/utils/async-lock.test.js +25 -0
- package/cjs/utils/async-lock.test.js.map +1 -0
- package/cjs/utils/bigint-utils.test.d.ts +1 -0
- package/cjs/utils/bigint-utils.test.js +150 -0
- package/cjs/utils/bigint-utils.test.js.map +1 -0
- package/cjs/utils/buffer-utils.test.d.ts +1 -0
- package/cjs/utils/buffer-utils.test.js +69 -0
- package/cjs/utils/buffer-utils.test.js.map +1 -0
- package/cjs/utils/condition-variable.test.d.ts +1 -0
- package/cjs/utils/condition-variable.test.js +27 -0
- package/cjs/utils/condition-variable.test.js.map +1 -0
- package/cjs/utils/controllable-promise.test.d.ts +1 -0
- package/cjs/utils/controllable-promise.test.js +17 -0
- package/cjs/utils/controllable-promise.test.js.map +1 -0
- package/cjs/utils/crypto/keys.test.d.ts +1 -0
- package/cjs/utils/crypto/keys.test.js +40 -0
- package/cjs/utils/crypto/keys.test.js.map +1 -0
- package/cjs/utils/crypto/miller-rabin.test.d.ts +1 -0
- package/cjs/utils/crypto/miller-rabin.test.js +60 -0
- package/cjs/utils/crypto/miller-rabin.test.js.map +1 -0
- package/cjs/utils/crypto/mtproto.test.d.ts +1 -0
- package/cjs/utils/crypto/mtproto.test.js +47 -0
- package/cjs/utils/crypto/mtproto.test.js.map +1 -0
- package/cjs/utils/crypto/node.test.d.ts +1 -0
- package/cjs/utils/crypto/node.test.js +13 -0
- package/cjs/utils/crypto/node.test.js.map +1 -0
- package/cjs/utils/crypto/password.test.d.ts +1 -0
- package/cjs/utils/crypto/password.test.js +95 -0
- package/cjs/utils/crypto/password.test.js.map +1 -0
- package/cjs/utils/crypto/utils.test.d.ts +1 -0
- package/cjs/utils/crypto/utils.test.js +49 -0
- package/cjs/utils/crypto/utils.test.js.map +1 -0
- package/cjs/utils/crypto/web.test.d.ts +1 -0
- package/cjs/utils/crypto/web.test.js +17 -0
- package/cjs/utils/crypto/web.test.js.map +1 -0
- package/cjs/utils/deque.test.d.ts +1 -0
- package/cjs/utils/deque.test.js +128 -0
- package/cjs/utils/deque.test.js.map +1 -0
- package/cjs/utils/function-utils.test.d.ts +1 -0
- package/cjs/utils/function-utils.test.js +23 -0
- package/cjs/utils/function-utils.test.js.map +1 -0
- package/cjs/utils/linked-list.test.d.ts +1 -0
- package/cjs/utils/linked-list.test.js +36 -0
- package/cjs/utils/linked-list.test.js.map +1 -0
- package/cjs/utils/links/bots.test.d.ts +1 -0
- package/cjs/utils/links/bots.test.js +152 -0
- package/cjs/utils/links/bots.test.js.map +1 -0
- package/cjs/utils/links/chat.test.d.ts +1 -0
- package/cjs/utils/links/chat.test.js +84 -0
- package/cjs/utils/links/chat.test.js.map +1 -0
- package/cjs/utils/links/misc.test.d.ts +1 -0
- package/cjs/utils/links/misc.test.js +153 -0
- package/cjs/utils/links/misc.test.js.map +1 -0
- package/cjs/utils/links/proxy.test.d.ts +1 -0
- package/cjs/utils/links/proxy.test.js +74 -0
- package/cjs/utils/links/proxy.test.js.map +1 -0
- package/cjs/utils/links/user.test.d.ts +1 -0
- package/cjs/utils/links/user.test.js +63 -0
- package/cjs/utils/links/user.test.js.map +1 -0
- package/cjs/utils/logger.test.d.ts +1 -0
- package/cjs/utils/logger.test.js +125 -0
- package/cjs/utils/logger.test.js.map +1 -0
- package/cjs/utils/long-utils.test.d.ts +1 -0
- package/cjs/utils/long-utils.test.js +158 -0
- package/cjs/utils/long-utils.test.js.map +1 -0
- package/cjs/utils/lru-map.test.d.ts +1 -0
- package/cjs/utils/lru-map.test.js +96 -0
- package/cjs/utils/lru-map.test.js.map +1 -0
- package/cjs/utils/lru-set.test.d.ts +1 -0
- package/cjs/utils/lru-set.test.js +77 -0
- package/cjs/utils/lru-set.test.js.map +1 -0
- package/cjs/utils/peer-utils.test.d.ts +1 -0
- package/cjs/utils/peer-utils.test.js +122 -0
- package/cjs/utils/peer-utils.test.js.map +1 -0
- package/cjs/utils/sorted-array.test.d.ts +1 -0
- package/cjs/utils/sorted-array.test.js +66 -0
- package/cjs/utils/sorted-array.test.js.map +1 -0
- package/cjs/utils/string-session.test.d.ts +1 -0
- package/cjs/utils/string-session.test.js +106 -0
- package/cjs/utils/string-session.test.js.map +1 -0
- package/cjs/utils/tl-json.test.d.ts +1 -0
- package/cjs/utils/tl-json.test.js +83 -0
- package/cjs/utils/tl-json.test.js.map +1 -0
- package/cjs/utils/type-assertions.test.d.ts +1 -0
- package/cjs/utils/type-assertions.test.js +67 -0
- package/cjs/utils/type-assertions.test.js.map +1 -0
- package/esm/network/auth-key.test.d.ts +1 -0
- package/esm/network/auth-key.test.js +106 -0
- package/esm/network/auth-key.test.js.map +1 -0
- package/esm/network/config-manager.js +2 -1
- package/esm/network/config-manager.js.map +1 -1
- package/esm/network/config-manager.test.d.ts +1 -0
- package/esm/network/config-manager.test.js +168 -0
- package/esm/network/config-manager.test.js.map +1 -0
- package/esm/network/network-manager.js +1 -1
- package/esm/network/persistent-connection.test.d.ts +1 -0
- package/esm/network/persistent-connection.test.js +155 -0
- package/esm/network/persistent-connection.test.js.map +1 -0
- package/esm/network/session-connection.js +3 -2
- package/esm/network/session-connection.js.map +1 -1
- package/esm/network/transports/intermediate.test.d.ts +1 -0
- package/esm/network/transports/intermediate.test.js +84 -0
- package/esm/network/transports/intermediate.test.js.map +1 -0
- package/esm/network/transports/obfuscated.js +1 -1
- package/esm/network/transports/obfuscated.js.map +1 -1
- package/esm/network/transports/obfuscated.test.d.ts +1 -0
- package/esm/network/transports/obfuscated.test.js +129 -0
- package/esm/network/transports/obfuscated.test.js.map +1 -0
- package/esm/network/transports/tcp.js +1 -1
- package/esm/network/transports/tcp.js.map +1 -1
- package/esm/network/transports/tcp.test.d.ts +1 -0
- package/esm/network/transports/tcp.test.js +95 -0
- package/esm/network/transports/tcp.test.js.map +1 -0
- package/esm/network/transports/websocket.test.d.ts +1 -0
- package/esm/network/transports/websocket.test.js +89 -0
- package/esm/network/transports/websocket.test.js.map +1 -0
- package/esm/storage/json.test.d.ts +1 -0
- package/esm/storage/json.test.js +35 -0
- package/esm/storage/json.test.js.map +1 -0
- package/esm/storage/localstorage.test.d.ts +1 -0
- package/esm/storage/localstorage.test.js +21 -0
- package/esm/storage/localstorage.test.js.map +1 -0
- package/esm/storage/memory.test.d.ts +1 -0
- package/esm/storage/memory.test.js +45 -0
- package/esm/storage/memory.test.js.map +1 -0
- package/esm/utils/async-lock.test.d.ts +1 -0
- package/esm/utils/async-lock.test.js +23 -0
- package/esm/utils/async-lock.test.js.map +1 -0
- package/esm/utils/bigint-utils.test.d.ts +1 -0
- package/esm/utils/bigint-utils.test.js +148 -0
- package/esm/utils/bigint-utils.test.js.map +1 -0
- package/esm/utils/buffer-utils.test.d.ts +1 -0
- package/esm/utils/buffer-utils.test.js +67 -0
- package/esm/utils/buffer-utils.test.js.map +1 -0
- package/esm/utils/condition-variable.test.d.ts +1 -0
- package/esm/utils/condition-variable.test.js +25 -0
- package/esm/utils/condition-variable.test.js.map +1 -0
- package/esm/utils/controllable-promise.test.d.ts +1 -0
- package/esm/utils/controllable-promise.test.js +15 -0
- package/esm/utils/controllable-promise.test.js.map +1 -0
- package/esm/utils/crypto/keys.test.d.ts +1 -0
- package/esm/utils/crypto/keys.test.js +38 -0
- package/esm/utils/crypto/keys.test.js.map +1 -0
- package/esm/utils/crypto/miller-rabin.test.d.ts +1 -0
- package/esm/utils/crypto/miller-rabin.test.js +58 -0
- package/esm/utils/crypto/miller-rabin.test.js.map +1 -0
- package/esm/utils/crypto/mtproto.test.d.ts +1 -0
- package/esm/utils/crypto/mtproto.test.js +45 -0
- package/esm/utils/crypto/mtproto.test.js.map +1 -0
- package/esm/utils/crypto/node.test.d.ts +1 -0
- package/esm/utils/crypto/node.test.js +11 -0
- package/esm/utils/crypto/node.test.js.map +1 -0
- package/esm/utils/crypto/password.test.d.ts +1 -0
- package/esm/utils/crypto/password.test.js +90 -0
- package/esm/utils/crypto/password.test.js.map +1 -0
- package/esm/utils/crypto/utils.test.d.ts +1 -0
- package/esm/utils/crypto/utils.test.js +47 -0
- package/esm/utils/crypto/utils.test.js.map +1 -0
- package/esm/utils/crypto/web.test.d.ts +1 -0
- package/esm/utils/crypto/web.test.js +15 -0
- package/esm/utils/crypto/web.test.js.map +1 -0
- package/esm/utils/deque.test.d.ts +1 -0
- package/esm/utils/deque.test.js +126 -0
- package/esm/utils/deque.test.js.map +1 -0
- package/esm/utils/function-utils.test.d.ts +1 -0
- package/esm/utils/function-utils.test.js +21 -0
- package/esm/utils/function-utils.test.js.map +1 -0
- package/esm/utils/linked-list.test.d.ts +1 -0
- package/esm/utils/linked-list.test.js +34 -0
- package/esm/utils/linked-list.test.js.map +1 -0
- package/esm/utils/links/bots.test.d.ts +1 -0
- package/esm/utils/links/bots.test.js +150 -0
- package/esm/utils/links/bots.test.js.map +1 -0
- package/esm/utils/links/chat.test.d.ts +1 -0
- package/esm/utils/links/chat.test.js +82 -0
- package/esm/utils/links/chat.test.js.map +1 -0
- package/esm/utils/links/misc.test.d.ts +1 -0
- package/esm/utils/links/misc.test.js +151 -0
- package/esm/utils/links/misc.test.js.map +1 -0
- package/esm/utils/links/proxy.test.d.ts +1 -0
- package/esm/utils/links/proxy.test.js +72 -0
- package/esm/utils/links/proxy.test.js.map +1 -0
- package/esm/utils/links/user.test.d.ts +1 -0
- package/esm/utils/links/user.test.js +61 -0
- package/esm/utils/links/user.test.js.map +1 -0
- package/esm/utils/logger.test.d.ts +1 -0
- package/esm/utils/logger.test.js +120 -0
- package/esm/utils/logger.test.js.map +1 -0
- package/esm/utils/long-utils.test.d.ts +1 -0
- package/esm/utils/long-utils.test.js +153 -0
- package/esm/utils/long-utils.test.js.map +1 -0
- package/esm/utils/lru-map.test.d.ts +1 -0
- package/esm/utils/lru-map.test.js +94 -0
- package/esm/utils/lru-map.test.js.map +1 -0
- package/esm/utils/lru-set.test.d.ts +1 -0
- package/esm/utils/lru-set.test.js +72 -0
- package/esm/utils/lru-set.test.js.map +1 -0
- package/esm/utils/peer-utils.test.d.ts +1 -0
- package/esm/utils/peer-utils.test.js +117 -0
- package/esm/utils/peer-utils.test.js.map +1 -0
- package/esm/utils/sorted-array.test.d.ts +1 -0
- package/esm/utils/sorted-array.test.js +64 -0
- package/esm/utils/sorted-array.test.js.map +1 -0
- package/esm/utils/string-session.test.d.ts +1 -0
- package/esm/utils/string-session.test.js +104 -0
- package/esm/utils/string-session.test.js.map +1 -0
- package/esm/utils/tl-json.test.d.ts +1 -0
- package/esm/utils/tl-json.test.js +81 -0
- package/esm/utils/tl-json.test.js.map +1 -0
- package/esm/utils/type-assertions.test.d.ts +1 -0
- package/esm/utils/type-assertions.test.js +65 -0
- package/esm/utils/type-assertions.test.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const type_assertions_js_1 = require("./type-assertions.js");
|
|
5
|
+
(0, vitest_1.describe)('isPresent', () => {
|
|
6
|
+
(0, vitest_1.it)('should return true for non-null values', () => {
|
|
7
|
+
(0, vitest_1.expect)((0, type_assertions_js_1.isPresent)(1)).toBe(true);
|
|
8
|
+
(0, vitest_1.expect)((0, type_assertions_js_1.isPresent)('')).toBe(true);
|
|
9
|
+
(0, vitest_1.expect)((0, type_assertions_js_1.isPresent)({})).toBe(true);
|
|
10
|
+
(0, vitest_1.expect)((0, type_assertions_js_1.isPresent)([])).toBe(true);
|
|
11
|
+
});
|
|
12
|
+
(0, vitest_1.it)('should return false for null/undefined', () => {
|
|
13
|
+
(0, vitest_1.expect)((0, type_assertions_js_1.isPresent)(null)).toBe(false);
|
|
14
|
+
(0, vitest_1.expect)((0, type_assertions_js_1.isPresent)(undefined)).toBe(false);
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
(0, vitest_1.describe)('hasPresentKey', () => {
|
|
18
|
+
(0, vitest_1.it)('should return true for objects with present keys', () => {
|
|
19
|
+
(0, vitest_1.expect)((0, type_assertions_js_1.hasPresentKey)('a')({ a: 1 })).toBe(true);
|
|
20
|
+
(0, vitest_1.expect)((0, type_assertions_js_1.hasPresentKey)('a')({ a: 1, b: 2 })).toBe(true);
|
|
21
|
+
});
|
|
22
|
+
(0, vitest_1.it)('should return false for objects with undefined/null keys', () => {
|
|
23
|
+
(0, vitest_1.expect)((0, type_assertions_js_1.hasPresentKey)('a')({ a: undefined })).toBe(false);
|
|
24
|
+
(0, vitest_1.expect)((0, type_assertions_js_1.hasPresentKey)('a')({ a: null })).toBe(false);
|
|
25
|
+
(0, vitest_1.expect)((0, type_assertions_js_1.hasPresentKey)('a')({ a: undefined, b: 2 })).toBe(false);
|
|
26
|
+
(0, vitest_1.expect)((0, type_assertions_js_1.hasPresentKey)('a')({ a: null, b: 2 })).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
(0, vitest_1.it)('should return false for objects without the key', () => {
|
|
29
|
+
(0, vitest_1.expect)((0, type_assertions_js_1.hasPresentKey)('a')({ b: 2 })).toBe(false);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
(0, vitest_1.describe)('hasValueAtKey', () => {
|
|
33
|
+
(0, vitest_1.it)('should return true for objects with the correct value', () => {
|
|
34
|
+
(0, vitest_1.expect)((0, type_assertions_js_1.hasValueAtKey)('a', 1)({ a: 1 })).toBe(true);
|
|
35
|
+
(0, vitest_1.expect)((0, type_assertions_js_1.hasValueAtKey)('a', 1)({ a: 1, b: 2 })).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
(0, vitest_1.it)('should return false for objects with the wrong value', () => {
|
|
38
|
+
(0, vitest_1.expect)((0, type_assertions_js_1.hasValueAtKey)('a', 1)({ a: 2 })).toBe(false);
|
|
39
|
+
(0, vitest_1.expect)((0, type_assertions_js_1.hasValueAtKey)('a', 1)({ a: 2, b: 2 })).toBe(false);
|
|
40
|
+
});
|
|
41
|
+
(0, vitest_1.it)('should return false for objects without the key', () => {
|
|
42
|
+
// @ts-expect-error - we want to make sure the key is not present at runtime
|
|
43
|
+
(0, vitest_1.expect)((0, type_assertions_js_1.hasValueAtKey)('a', 1)({ b: 2 })).toBe(false);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
(0, vitest_1.describe)('assertTypeIs', () => {
|
|
47
|
+
(0, vitest_1.it)('should not throw for correct types', () => {
|
|
48
|
+
(0, type_assertions_js_1.assertTypeIs)('peerUser', { _: 'peerUser', userId: 1 }, 'peerUser');
|
|
49
|
+
(0, type_assertions_js_1.mtpAssertTypeIs)('peerUser', { _: 'mt_rpc_answer_unknown' }, 'mt_rpc_answer_unknown');
|
|
50
|
+
});
|
|
51
|
+
(0, vitest_1.it)('should throw for incorrect types', () => {
|
|
52
|
+
// eslint-disable-next-line
|
|
53
|
+
(0, vitest_1.expect)(() => (0, type_assertions_js_1.assertTypeIs)('peerUser', { _: 'peerChannel', channelId: 1 }, 'peerUser')).toThrow();
|
|
54
|
+
// eslint-disable-next-line
|
|
55
|
+
(0, vitest_1.expect)(() => (0, type_assertions_js_1.mtpAssertTypeIs)('peerUser', { _: 'mt_rpc_answer_unknown' }, 'peerUser')).toThrow();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
(0, vitest_1.describe)('assertTypeIsNot', () => {
|
|
59
|
+
(0, vitest_1.it)('should not throw for correct types', () => {
|
|
60
|
+
// eslint-disable-next-line
|
|
61
|
+
(0, type_assertions_js_1.assertTypeIsNot)('peerUser', { _: 'peerChannel', channelId: 1 }, 'peerUser');
|
|
62
|
+
});
|
|
63
|
+
(0, vitest_1.it)('should throw for incorrect types', () => {
|
|
64
|
+
(0, vitest_1.expect)(() => (0, type_assertions_js_1.assertTypeIsNot)('peerUser', { _: 'peerUser', userId: 1 }, 'peerUser')).toThrow();
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
//# sourceMappingURL=type-assertions.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type-assertions.test.js","sourceRoot":"","sources":["../../../src/utils/type-assertions.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, it } from 'vitest'\n\nimport {\n assertTypeIs,\n assertTypeIsNot,\n hasPresentKey,\n hasValueAtKey,\n isPresent,\n mtpAssertTypeIs,\n} from './type-assertions.js'\n\ndescribe('isPresent', () => {\n it('should return true for non-null values', () => {\n expect(isPresent(1)).toBe(true)\n expect(isPresent('')).toBe(true)\n expect(isPresent({})).toBe(true)\n expect(isPresent([])).toBe(true)\n })\n\n it('should return false for null/undefined', () => {\n expect(isPresent(null)).toBe(false)\n expect(isPresent(undefined)).toBe(false)\n })\n})\n\ndescribe('hasPresentKey', () => {\n it('should return true for objects with present keys', () => {\n expect(hasPresentKey('a')({ a: 1 })).toBe(true)\n expect(hasPresentKey('a')({ a: 1, b: 2 })).toBe(true)\n })\n\n it('should return false for objects with undefined/null keys', () => {\n expect(hasPresentKey('a')({ a: undefined })).toBe(false)\n expect(hasPresentKey('a')({ a: null })).toBe(false)\n expect(hasPresentKey('a')({ a: undefined, b: 2 })).toBe(false)\n expect(hasPresentKey('a')({ a: null, b: 2 })).toBe(false)\n })\n\n it('should return false for objects without the key', () => {\n expect(hasPresentKey('a')({ b: 2 })).toBe(false)\n })\n})\n\ndescribe('hasValueAtKey', () => {\n it('should return true for objects with the correct value', () => {\n expect(hasValueAtKey('a', 1)({ a: 1 })).toBe(true)\n expect(hasValueAtKey('a', 1)({ a: 1, b: 2 })).toBe(true)\n })\n\n it('should return false for objects with the wrong value', () => {\n expect(hasValueAtKey('a', 1)({ a: 2 })).toBe(false)\n expect(hasValueAtKey('a', 1)({ a: 2, b: 2 })).toBe(false)\n })\n\n it('should return false for objects without the key', () => {\n // @ts-expect-error - we want to make sure the key is not present at runtime\n expect(hasValueAtKey('a', 1)({ b: 2 })).toBe(false)\n })\n})\n\ndescribe('assertTypeIs', () => {\n it('should not throw for correct types', () => {\n assertTypeIs('peerUser', { _: 'peerUser', userId: 1 }, 'peerUser')\n mtpAssertTypeIs('peerUser', { _: 'mt_rpc_answer_unknown' }, 'mt_rpc_answer_unknown')\n })\n\n it('should throw for incorrect types', () => {\n // eslint-disable-next-line\n expect(() => assertTypeIs('peerUser', { _: 'peerChannel', channelId: 1 } as any, 'peerUser')).toThrow()\n // eslint-disable-next-line\n expect(() => mtpAssertTypeIs('peerUser', { _: 'mt_rpc_answer_unknown' } as any, 'peerUser')).toThrow()\n })\n})\n\ndescribe('assertTypeIsNot', () => {\n it('should not throw for correct types', () => {\n // eslint-disable-next-line\n assertTypeIsNot('peerUser', { _: 'peerChannel', channelId: 1 } as any, 'peerUser')\n })\n\n it('should throw for incorrect types', () => {\n expect(() => assertTypeIsNot('peerUser', { _: 'peerUser', userId: 1 }, 'peerUser')).toThrow()\n })\n})\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import Long from 'long';
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { defaultTestCryptoProvider } from '@mtcute/test';
|
|
4
|
+
import { hexDecode, hexDecodeToBuffer, hexEncode, utf8Decode, utf8EncodeToBuffer, } from '@mtcute/tl-runtime';
|
|
5
|
+
import { LogManager } from '../utils/index.js';
|
|
6
|
+
import { AuthKey } from './auth-key.js';
|
|
7
|
+
const authKey = new Uint8Array(256);
|
|
8
|
+
for (let i = 0; i < 256; i += 32) {
|
|
9
|
+
hexDecode(authKey.subarray(i, i + 32), '98cb29c6ffa89e79da695a54f572e6cb101e81c688b63a4bf73c3622dec230e0');
|
|
10
|
+
}
|
|
11
|
+
describe('AuthKey', () => {
|
|
12
|
+
async function create() {
|
|
13
|
+
const logger = new LogManager();
|
|
14
|
+
const readerMap = {};
|
|
15
|
+
const crypto = await defaultTestCryptoProvider();
|
|
16
|
+
const key = new AuthKey(crypto, logger, readerMap);
|
|
17
|
+
key.setup(authKey);
|
|
18
|
+
return key;
|
|
19
|
+
}
|
|
20
|
+
const msgId = Long.fromBits(0xbeef1234, 0x1234beef, true);
|
|
21
|
+
const seqNo = 777;
|
|
22
|
+
const serverSalt = Long.fromBits(0xdeadbeef, 0xbeefdead);
|
|
23
|
+
const sessionId = Long.fromBits(0xfeedbeef, 0xbeeffeed);
|
|
24
|
+
function writeMessage(body) {
|
|
25
|
+
const buf = new Uint8Array(16 + body.length);
|
|
26
|
+
const dv = new DataView(buf.buffer);
|
|
27
|
+
dv.setInt32(0, msgId.low, true);
|
|
28
|
+
dv.setInt32(4, msgId.high, true);
|
|
29
|
+
dv.setInt32(8, seqNo, true);
|
|
30
|
+
dv.setInt32(12, body.length, true);
|
|
31
|
+
buf.set(body, 16);
|
|
32
|
+
return buf;
|
|
33
|
+
}
|
|
34
|
+
it('should calculate derivatives', async () => {
|
|
35
|
+
const key = await create();
|
|
36
|
+
expect(hexEncode(key.key)).toEqual(hexEncode(authKey));
|
|
37
|
+
expect(hexEncode(key.clientSalt)).toEqual('f73c3622dec230e098cb29c6ffa89e79da695a54f572e6cb101e81c688b63a4b');
|
|
38
|
+
expect(hexEncode(key.serverSalt)).toEqual('98cb29c6ffa89e79da695a54f572e6cb101e81c688b63a4bf73c3622dec230e0');
|
|
39
|
+
expect(hexEncode(key.id)).toEqual('40fa5bb7cb56a895');
|
|
40
|
+
});
|
|
41
|
+
it('should encrypt a message', async () => {
|
|
42
|
+
const message = writeMessage(utf8EncodeToBuffer('hello, world!!!!'));
|
|
43
|
+
const key = await create();
|
|
44
|
+
const msg = key.encryptMessage(message, serverSalt, sessionId);
|
|
45
|
+
expect(hexEncode(msg)).toEqual('40fa5bb7cb56a895f6f5a88914892aadf87c68031cc953ba29d68e118021f329' +
|
|
46
|
+
'be386a620d49f3ad3a50c60dcef3733f214e8cefa3e403c11d193637d4971dc1' +
|
|
47
|
+
'5db7f74b26fd16cb0e8fee30bf7e3f68858fe82927e2cd06');
|
|
48
|
+
});
|
|
49
|
+
describe('decrypt', () => {
|
|
50
|
+
async function decrypt(message) {
|
|
51
|
+
const key = await create();
|
|
52
|
+
return new Promise((resolve, reject) => {
|
|
53
|
+
// in this method, errors are not thrown but rather logged
|
|
54
|
+
vi.spyOn(key.log, 'warn').mockImplementation((msg, ...fmt) => reject(`${msg} : ${fmt.map((it) => JSON.stringify(it)).join(' ')}`));
|
|
55
|
+
key.decryptMessage(message, sessionId, (...args) => resolve(args));
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
it('should decrypt a message', async () => {
|
|
59
|
+
const message = hexDecodeToBuffer('40fa5bb7cb56a8950c394b884f1529efc42fea22d972fea650a714ce6d2d1bdb' +
|
|
60
|
+
'3d98ff5929b8768c401771a69795f36a7e720dcafac2efbccd0ba368e8a7f48b' +
|
|
61
|
+
'07362cac1a32ffcabe188b51a36cc4d54e1d0633cf9eaf35');
|
|
62
|
+
const [decMsgId, decSeqNo, data] = await decrypt(message);
|
|
63
|
+
expect(decMsgId).toEqual(msgId);
|
|
64
|
+
expect(decSeqNo).toEqual(seqNo);
|
|
65
|
+
expect(utf8Decode(data.raw(16))).toEqual('hello, world!!!!');
|
|
66
|
+
});
|
|
67
|
+
it('should decrypt a message with padding', async () => {
|
|
68
|
+
const message = hexDecodeToBuffer('40fa5bb7cb56a8950c394b884f1529efc42fea22d972fea650a714ce6d2d1bdb' +
|
|
69
|
+
'3d98ff5929b8768c401771a69795f36a7e720dcafac2efbccd0ba368e8a7f48b' +
|
|
70
|
+
'07362cac1a32ffcabe188b51a36cc4d54e1d0633cf9eaf35' +
|
|
71
|
+
'deadbeef');
|
|
72
|
+
const [decMsgId, decSeqNo, data] = await decrypt(message);
|
|
73
|
+
expect(decMsgId).toEqual(msgId);
|
|
74
|
+
expect(decSeqNo).toEqual(seqNo);
|
|
75
|
+
expect(utf8Decode(data.raw(16))).toEqual('hello, world!!!!');
|
|
76
|
+
});
|
|
77
|
+
it('should ignore messages with invalid message key', async () => {
|
|
78
|
+
const message = hexDecodeToBuffer('40fa5bb7cb56a8950000000000000000000000000000000050a714ce6d2d1bdb' +
|
|
79
|
+
'3d98ff5929b8768c401771a69795f36a7e720dcafac2efbccd0ba368e8a7f48b' +
|
|
80
|
+
'07362cac1a32ffcabe188b51a36cc4d54e1d0633cf9eaf35');
|
|
81
|
+
await expect(() => decrypt(message)).rejects.toThrow('message with invalid messageKey');
|
|
82
|
+
});
|
|
83
|
+
it('should ignore messages with invalid session_id', async () => {
|
|
84
|
+
const message = hexDecodeToBuffer('40fa5bb7cb56a895a986a7e97f4e90aa2769b5e702c6e86f5e1e82c6ff0c6829' +
|
|
85
|
+
'2521a2ba9704fa37fb341d895cf32662c6cf47ba31cbf27c30d5c03f6c2930f4' +
|
|
86
|
+
'30fd8858b836b73fe32d4a95b8ebcdbc9ca8908f7964c40a');
|
|
87
|
+
await expect(() => decrypt(message)).rejects.toThrow('message with invalid sessionId');
|
|
88
|
+
});
|
|
89
|
+
it('should ignore messages with invalid length', async () => {
|
|
90
|
+
const messageTooLong = hexDecodeToBuffer('40fa5bb7cb56a8950d19412233dd5d24be697c73274e08fbe515cf65e0c5f70c' +
|
|
91
|
+
'ad75fd2badc18c9f999f287351144eeb1cfcaa9bea33ef5058999ad96a498306' +
|
|
92
|
+
'08d2859425685a55b21fab413bfabc42ec5da283853b28c0');
|
|
93
|
+
const messageUnaligned = hexDecodeToBuffer('40fa5bb7cb56a8957b4e4bec561eee4a5a1025bc8a35d3d0c79a3685d2b90ff0' +
|
|
94
|
+
'5f638e9c42c9fd9448b0ce8e7d49e7ea1ce458e47b825b5c7fd8ddf5b4fded46' +
|
|
95
|
+
'2a4bcc02f3ff2e89de6764d6d219f575e457fdcf8c163cdf');
|
|
96
|
+
await expect(() => decrypt(messageTooLong)).rejects.toThrow('message with invalid length: %d > %d');
|
|
97
|
+
await expect(() => decrypt(messageUnaligned)).rejects.toThrow('message with invalid length: %d is not a multiple of 4');
|
|
98
|
+
});
|
|
99
|
+
it('should ignore messages with invalid padding', async () => {
|
|
100
|
+
const message = hexDecodeToBuffer('40fa5bb7cb56a895133671d1c637a9836e2c64b4d1a0521d8a25a6416fd4dc9e' +
|
|
101
|
+
'79f9478fb837703cc9efa0a19d12143c2a26e57cb4bc64d7bc972dd8f19c53c590cc258162f44afc');
|
|
102
|
+
await expect(() => decrypt(message)).rejects.toThrow('message with invalid padding size');
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
//# sourceMappingURL=auth-key.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-key.test.js","sourceRoot":"","sources":["../../../src/network/auth-key.test.ts"],"names":[],"mappings":"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","sourcesContent":["import Long from 'long'\nimport { describe, expect, it, vi } from 'vitest'\n\nimport { defaultTestCryptoProvider } from '@mtcute/test'\nimport {\n hexDecode,\n hexDecodeToBuffer,\n hexEncode,\n TlBinaryReader,\n TlReaderMap,\n utf8Decode,\n utf8EncodeToBuffer,\n} from '@mtcute/tl-runtime'\n\nimport { LogManager } from '../utils/index.js'\nimport { AuthKey } from './auth-key.js'\n\nconst authKey = new Uint8Array(256)\n\nfor (let i = 0; i < 256; i += 32) {\n hexDecode(authKey.subarray(i, i + 32), '98cb29c6ffa89e79da695a54f572e6cb101e81c688b63a4bf73c3622dec230e0')\n}\n\ndescribe('AuthKey', () => {\n async function create() {\n const logger = new LogManager()\n const readerMap: TlReaderMap = {}\n const crypto = await defaultTestCryptoProvider()\n\n const key = new AuthKey(crypto, logger, readerMap)\n key.setup(authKey)\n\n return key\n }\n\n const msgId = Long.fromBits(0xbeef1234, 0x1234beef, true)\n const seqNo = 777\n const serverSalt = Long.fromBits(0xdeadbeef, 0xbeefdead)\n const sessionId = Long.fromBits(0xfeedbeef, 0xbeeffeed)\n\n function writeMessage(body: Uint8Array) {\n const buf = new Uint8Array(16 + body.length)\n const dv = new DataView(buf.buffer)\n\n dv.setInt32(0, msgId.low, true)\n dv.setInt32(4, msgId.high, true)\n dv.setInt32(8, seqNo, true)\n dv.setInt32(12, body.length, true)\n buf.set(body, 16)\n\n return buf\n }\n\n it('should calculate derivatives', async () => {\n const key = await create()\n\n expect(hexEncode(key.key)).toEqual(hexEncode(authKey))\n expect(hexEncode(key.clientSalt)).toEqual('f73c3622dec230e098cb29c6ffa89e79da695a54f572e6cb101e81c688b63a4b')\n expect(hexEncode(key.serverSalt)).toEqual('98cb29c6ffa89e79da695a54f572e6cb101e81c688b63a4bf73c3622dec230e0')\n expect(hexEncode(key.id)).toEqual('40fa5bb7cb56a895')\n })\n\n it('should encrypt a message', async () => {\n const message = writeMessage(utf8EncodeToBuffer('hello, world!!!!'))\n\n const key = await create()\n const msg = key.encryptMessage(message, serverSalt, sessionId)\n\n expect(hexEncode(msg)).toEqual(\n '40fa5bb7cb56a895f6f5a88914892aadf87c68031cc953ba29d68e118021f329' +\n 'be386a620d49f3ad3a50c60dcef3733f214e8cefa3e403c11d193637d4971dc1' +\n '5db7f74b26fd16cb0e8fee30bf7e3f68858fe82927e2cd06',\n )\n })\n\n describe('decrypt', () => {\n async function decrypt(message: Uint8Array) {\n const key = await create()\n\n return new Promise<[Long, number, TlBinaryReader]>((resolve, reject) => {\n // in this method, errors are not thrown but rather logged\n vi.spyOn(key.log, 'warn').mockImplementation((msg, ...fmt) =>\n reject(`${msg} : ${fmt.map((it) => JSON.stringify(it)).join(' ')}`),\n )\n\n key.decryptMessage(message, sessionId, (...args) => resolve(args))\n })\n }\n\n it('should decrypt a message', async () => {\n const message = hexDecodeToBuffer(\n '40fa5bb7cb56a8950c394b884f1529efc42fea22d972fea650a714ce6d2d1bdb' +\n '3d98ff5929b8768c401771a69795f36a7e720dcafac2efbccd0ba368e8a7f48b' +\n '07362cac1a32ffcabe188b51a36cc4d54e1d0633cf9eaf35',\n )\n\n const [decMsgId, decSeqNo, data] = await decrypt(message)\n\n expect(decMsgId).toEqual(msgId)\n expect(decSeqNo).toEqual(seqNo)\n expect(utf8Decode(data.raw(16))).toEqual('hello, world!!!!')\n })\n\n it('should decrypt a message with padding', async () => {\n const message = hexDecodeToBuffer(\n '40fa5bb7cb56a8950c394b884f1529efc42fea22d972fea650a714ce6d2d1bdb' +\n '3d98ff5929b8768c401771a69795f36a7e720dcafac2efbccd0ba368e8a7f48b' +\n '07362cac1a32ffcabe188b51a36cc4d54e1d0633cf9eaf35' +\n 'deadbeef', // some padding (e.g. from padded transport),\n )\n\n const [decMsgId, decSeqNo, data] = await decrypt(message)\n\n expect(decMsgId).toEqual(msgId)\n expect(decSeqNo).toEqual(seqNo)\n expect(utf8Decode(data.raw(16))).toEqual('hello, world!!!!')\n })\n\n it('should ignore messages with invalid message key', async () => {\n const message = hexDecodeToBuffer(\n '40fa5bb7cb56a8950000000000000000000000000000000050a714ce6d2d1bdb' +\n '3d98ff5929b8768c401771a69795f36a7e720dcafac2efbccd0ba368e8a7f48b' +\n '07362cac1a32ffcabe188b51a36cc4d54e1d0633cf9eaf35',\n )\n\n await expect(() => decrypt(message)).rejects.toThrow('message with invalid messageKey')\n })\n\n it('should ignore messages with invalid session_id', async () => {\n const message = hexDecodeToBuffer(\n '40fa5bb7cb56a895a986a7e97f4e90aa2769b5e702c6e86f5e1e82c6ff0c6829' +\n '2521a2ba9704fa37fb341d895cf32662c6cf47ba31cbf27c30d5c03f6c2930f4' +\n '30fd8858b836b73fe32d4a95b8ebcdbc9ca8908f7964c40a',\n )\n\n await expect(() => decrypt(message)).rejects.toThrow('message with invalid sessionId')\n })\n\n it('should ignore messages with invalid length', async () => {\n const messageTooLong = hexDecodeToBuffer(\n '40fa5bb7cb56a8950d19412233dd5d24be697c73274e08fbe515cf65e0c5f70c' +\n 'ad75fd2badc18c9f999f287351144eeb1cfcaa9bea33ef5058999ad96a498306' +\n '08d2859425685a55b21fab413bfabc42ec5da283853b28c0',\n )\n const messageUnaligned = hexDecodeToBuffer(\n '40fa5bb7cb56a8957b4e4bec561eee4a5a1025bc8a35d3d0c79a3685d2b90ff0' +\n '5f638e9c42c9fd9448b0ce8e7d49e7ea1ce458e47b825b5c7fd8ddf5b4fded46' +\n '2a4bcc02f3ff2e89de6764d6d219f575e457fdcf8c163cdf',\n )\n\n await expect(() => decrypt(messageTooLong)).rejects.toThrow('message with invalid length: %d > %d')\n await expect(() => decrypt(messageUnaligned)).rejects.toThrow(\n 'message with invalid length: %d is not a multiple of 4',\n )\n })\n\n it('should ignore messages with invalid padding', async () => {\n const message = hexDecodeToBuffer(\n '40fa5bb7cb56a895133671d1c637a9836e2c64b4d1a0521d8a25a6416fd4dc9e' +\n '79f9478fb837703cc9efa0a19d12143c2a26e57cb4bc64d7bc972dd8f19c53c590cc258162f44afc',\n )\n\n await expect(() => decrypt(message)).rejects.toThrow('message with invalid padding size')\n })\n })\n})\n"]}
|
|
@@ -11,7 +11,7 @@ export class ConfigManager {
|
|
|
11
11
|
this._listeners = [];
|
|
12
12
|
}
|
|
13
13
|
get isStale() {
|
|
14
|
-
return !this._config || this._config.expires
|
|
14
|
+
return !this._config || this._config.expires <= Date.now() / 1000;
|
|
15
15
|
}
|
|
16
16
|
update(force = false) {
|
|
17
17
|
if (!force && !this.isStale)
|
|
@@ -21,6 +21,7 @@ export class ConfigManager {
|
|
|
21
21
|
return (this._updatingPromise = this._update().then((config) => {
|
|
22
22
|
if (this._destroyed)
|
|
23
23
|
return;
|
|
24
|
+
this._updatingPromise = undefined;
|
|
24
25
|
this.setConfig(config);
|
|
25
26
|
}));
|
|
26
27
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-manager.js","sourceRoot":"","sources":["../../../src/network/config-manager.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,OAAO,aAAa;IACtB,YAAoB,OAAoC;QAApC,YAAO,GAAP,OAAO,CAA6B;QAEhD,eAAU,GAAG,KAAK,CAAA;QAOlB,eAAU,GAAuC,EAAE,CAAA;IATA,CAAC;IAW5D,IAAI,OAAO;QACP,OAAO,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,
|
|
1
|
+
{"version":3,"file":"config-manager.js","sourceRoot":"","sources":["../../../src/network/config-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { tl } from '@mtcute/tl'\n\n/**\n * Config manager is responsible for keeping\n * the current server configuration up-to-date\n * and providing methods to find the best DC\n * option for the current session.\n */\nexport class ConfigManager {\n constructor(private _update: () => Promise<tl.RawConfig>) {}\n\n private _destroyed = false\n private _config?: tl.RawConfig\n private _cdnConfig?: tl.RawCdnConfig\n\n private _updateTimeout?: NodeJS.Timeout\n private _updatingPromise?: Promise<void>\n\n private _listeners: ((config: tl.RawConfig) => void)[] = []\n\n get isStale(): boolean {\n return !this._config || this._config.expires <= Date.now() / 1000\n }\n\n update(force = false): Promise<void> {\n if (!force && !this.isStale) return Promise.resolve()\n if (this._updatingPromise) return this._updatingPromise\n\n return (this._updatingPromise = this._update().then((config) => {\n if (this._destroyed) return\n this._updatingPromise = undefined\n\n this.setConfig(config)\n }))\n }\n\n setConfig(config: tl.RawConfig): void {\n this._config = config\n\n if (this._updateTimeout) clearTimeout(this._updateTimeout)\n this._updateTimeout = setTimeout(\n () => void this.update().catch(() => {}),\n (config.expires - Date.now() / 1000) * 1000,\n )\n\n for (const cb of this._listeners) cb(config)\n }\n\n onConfigUpdate(cb: (config: tl.RawConfig) => void): void {\n this._listeners.push(cb)\n }\n\n offConfigUpdate(cb: (config: tl.RawConfig) => void): void {\n const idx = this._listeners.indexOf(cb)\n if (idx >= 0) this._listeners.splice(idx, 1)\n }\n\n getNow(): tl.RawConfig | undefined {\n return this._config\n }\n\n async get(): Promise<tl.RawConfig> {\n if (this.isStale) await this.update()\n\n return this._config!\n }\n\n destroy(): void {\n if (this._updateTimeout) clearTimeout(this._updateTimeout)\n this._listeners.length = 0\n this._destroyed = true\n }\n\n async findOption(params: {\n dcId: number\n allowIpv6?: boolean\n preferIpv6?: boolean\n allowMedia?: boolean\n preferMedia?: boolean\n cdn?: boolean\n }): Promise<tl.RawDcOption | undefined> {\n if (this.isStale) await this.update()\n\n const options = this._config!.dcOptions.filter((opt) => {\n if (opt.tcpoOnly) return false // unsupported\n if (opt.ipv6 && !params.allowIpv6) return false\n if (opt.mediaOnly && !params.allowMedia) return false\n if (opt.cdn && !params.cdn) return false\n\n return opt.id === params.dcId\n })\n\n if (params.preferMedia && params.preferIpv6) {\n const r = options.find((opt) => opt.mediaOnly && opt.ipv6)\n if (r) return r\n }\n\n if (params.preferMedia) {\n const r = options.find((opt) => opt.mediaOnly)\n if (r) return r\n }\n\n if (params.preferIpv6) {\n const r = options.find((opt) => opt.ipv6)\n if (r) return r\n }\n\n return options[0]\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { createStub } from '@mtcute/test';
|
|
3
|
+
import { ConfigManager } from './config-manager.js';
|
|
4
|
+
describe('ConfigManager', () => {
|
|
5
|
+
const config = createStub('config', {
|
|
6
|
+
expires: 300,
|
|
7
|
+
});
|
|
8
|
+
const getConfig = vi.fn();
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
vi.useFakeTimers();
|
|
11
|
+
vi.setSystemTime(0);
|
|
12
|
+
getConfig.mockClear().mockImplementation(() => Promise.resolve(config));
|
|
13
|
+
});
|
|
14
|
+
afterEach(() => void vi.useRealTimers());
|
|
15
|
+
it('should fetch initial config', async () => {
|
|
16
|
+
const cm = new ConfigManager(getConfig);
|
|
17
|
+
const fetchedConfig = await cm.get();
|
|
18
|
+
expect(getConfig).toHaveBeenCalledTimes(1);
|
|
19
|
+
expect(fetchedConfig).toEqual(config);
|
|
20
|
+
expect(cm.getNow()).toEqual(config);
|
|
21
|
+
});
|
|
22
|
+
it('should automatically update config', async () => {
|
|
23
|
+
const cm = new ConfigManager(getConfig);
|
|
24
|
+
await cm.update();
|
|
25
|
+
getConfig.mockImplementation(() => Promise.resolve({
|
|
26
|
+
...config,
|
|
27
|
+
expires: 600,
|
|
28
|
+
}));
|
|
29
|
+
await vi.advanceTimersByTimeAsync(301000);
|
|
30
|
+
expect(getConfig).toHaveBeenCalledTimes(2);
|
|
31
|
+
});
|
|
32
|
+
it('should correctly determine stale config', () => {
|
|
33
|
+
const cm = new ConfigManager(getConfig);
|
|
34
|
+
expect(cm.isStale).toBe(true);
|
|
35
|
+
cm.setConfig(config);
|
|
36
|
+
expect(cm.isStale).toBe(false);
|
|
37
|
+
vi.setSystemTime(300000);
|
|
38
|
+
expect(cm.isStale).toBe(true);
|
|
39
|
+
});
|
|
40
|
+
it('should not update config if not stale', async () => {
|
|
41
|
+
const cm = new ConfigManager(getConfig);
|
|
42
|
+
await cm.update();
|
|
43
|
+
getConfig.mockClear();
|
|
44
|
+
await cm.update();
|
|
45
|
+
expect(getConfig).not.toHaveBeenCalled();
|
|
46
|
+
});
|
|
47
|
+
it('should not update config twice', async () => {
|
|
48
|
+
const cm = new ConfigManager(getConfig);
|
|
49
|
+
await cm.update();
|
|
50
|
+
vi.setSystemTime(300000);
|
|
51
|
+
getConfig.mockClear();
|
|
52
|
+
await Promise.all([cm.update(), cm.update()]);
|
|
53
|
+
expect(getConfig).toHaveBeenCalledOnce();
|
|
54
|
+
});
|
|
55
|
+
it('should call listeners on config update', async () => {
|
|
56
|
+
const cm = new ConfigManager(getConfig);
|
|
57
|
+
const listener = vi.fn();
|
|
58
|
+
cm.onConfigUpdate(listener);
|
|
59
|
+
await cm.update();
|
|
60
|
+
vi.setSystemTime(300000);
|
|
61
|
+
cm.offConfigUpdate(listener);
|
|
62
|
+
await cm.update();
|
|
63
|
+
expect(listener).toHaveBeenCalledOnce();
|
|
64
|
+
expect(listener).toHaveBeenCalledWith(config);
|
|
65
|
+
});
|
|
66
|
+
it('should correctly destroy', async () => {
|
|
67
|
+
const cm = new ConfigManager(getConfig);
|
|
68
|
+
await cm.update();
|
|
69
|
+
cm.destroy();
|
|
70
|
+
getConfig.mockClear();
|
|
71
|
+
await vi.advanceTimersByTimeAsync(301000);
|
|
72
|
+
expect(getConfig).not.toHaveBeenCalled();
|
|
73
|
+
});
|
|
74
|
+
describe('findOption', () => {
|
|
75
|
+
const useDcOptions = (options) => {
|
|
76
|
+
getConfig.mockImplementation(() => Promise.resolve({
|
|
77
|
+
...config,
|
|
78
|
+
dcOptions: options,
|
|
79
|
+
}));
|
|
80
|
+
};
|
|
81
|
+
const findOption = async (params) => {
|
|
82
|
+
const cm = new ConfigManager(getConfig);
|
|
83
|
+
await cm.update();
|
|
84
|
+
return cm.findOption(params);
|
|
85
|
+
};
|
|
86
|
+
it('should find option by dc id', async () => {
|
|
87
|
+
useDcOptions([
|
|
88
|
+
createStub('dcOption', { id: 1, ipAddress: '1.1.1.1' }),
|
|
89
|
+
createStub('dcOption', { id: 2, ipAddress: '2.2.2.2' }),
|
|
90
|
+
]);
|
|
91
|
+
expect(await findOption({ dcId: 1 })).toMatchObject({
|
|
92
|
+
id: 1,
|
|
93
|
+
ipAddress: '1.1.1.1',
|
|
94
|
+
});
|
|
95
|
+
expect(await findOption({ dcId: 2 })).toMatchObject({
|
|
96
|
+
id: 2,
|
|
97
|
+
ipAddress: '2.2.2.2',
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
it('should ignore tcpoOnly options', async () => {
|
|
101
|
+
useDcOptions([
|
|
102
|
+
createStub('dcOption', { id: 1, ipAddress: '1.1.1.1', tcpoOnly: true }),
|
|
103
|
+
createStub('dcOption', { id: 1, ipAddress: '1.1.1.2' }),
|
|
104
|
+
]);
|
|
105
|
+
expect(await findOption({ dcId: 1 })).toMatchObject({
|
|
106
|
+
id: 1,
|
|
107
|
+
ipAddress: '1.1.1.2',
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
it('should respect allowMedia flag', async () => {
|
|
111
|
+
useDcOptions([
|
|
112
|
+
createStub('dcOption', { id: 2, ipAddress: '2.2.2.2', mediaOnly: true }),
|
|
113
|
+
createStub('dcOption', { id: 2, ipAddress: '2.2.2.3' }),
|
|
114
|
+
]);
|
|
115
|
+
expect(await findOption({ dcId: 2 })).toMatchObject({
|
|
116
|
+
id: 2,
|
|
117
|
+
ipAddress: '2.2.2.3',
|
|
118
|
+
});
|
|
119
|
+
expect(await findOption({ dcId: 2, allowMedia: true })).toMatchObject({
|
|
120
|
+
id: 2,
|
|
121
|
+
ipAddress: '2.2.2.2',
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
it('should respect preferMedia flag', async () => {
|
|
125
|
+
useDcOptions([
|
|
126
|
+
createStub('dcOption', { id: 2, ipAddress: '2.2.2.3' }),
|
|
127
|
+
createStub('dcOption', { id: 2, ipAddress: '2.2.2.2', mediaOnly: true }),
|
|
128
|
+
]);
|
|
129
|
+
expect(await findOption({ dcId: 2 })).toMatchObject({
|
|
130
|
+
id: 2,
|
|
131
|
+
ipAddress: '2.2.2.3',
|
|
132
|
+
});
|
|
133
|
+
expect(await findOption({ dcId: 2, allowMedia: true, preferMedia: true })).toMatchObject({
|
|
134
|
+
id: 2,
|
|
135
|
+
ipAddress: '2.2.2.2',
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
it('should respect allowIpv6 flag', async () => {
|
|
139
|
+
useDcOptions([
|
|
140
|
+
createStub('dcOption', { id: 2, ipAddress: '::1', ipv6: true }),
|
|
141
|
+
createStub('dcOption', { id: 2, ipAddress: '2.2.2.3' }),
|
|
142
|
+
]);
|
|
143
|
+
expect(await findOption({ dcId: 2 })).toMatchObject({
|
|
144
|
+
id: 2,
|
|
145
|
+
ipAddress: '2.2.2.3',
|
|
146
|
+
});
|
|
147
|
+
expect(await findOption({ dcId: 2, allowIpv6: true })).toMatchObject({
|
|
148
|
+
id: 2,
|
|
149
|
+
ipAddress: '::1',
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
it('should respect preferIpv6 flag', async () => {
|
|
153
|
+
useDcOptions([
|
|
154
|
+
createStub('dcOption', { id: 2, ipAddress: '2.2.2.3' }),
|
|
155
|
+
createStub('dcOption', { id: 2, ipAddress: '::1', ipv6: true }),
|
|
156
|
+
]);
|
|
157
|
+
expect(await findOption({ dcId: 2 })).toMatchObject({
|
|
158
|
+
id: 2,
|
|
159
|
+
ipAddress: '2.2.2.3',
|
|
160
|
+
});
|
|
161
|
+
expect(await findOption({ dcId: 2, allowIpv6: true, preferIpv6: true })).toMatchObject({
|
|
162
|
+
id: 2,
|
|
163
|
+
ipAddress: '::1',
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
//# sourceMappingURL=config-manager.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-manager.test.js","sourceRoot":"","sources":["../../../src/network/config-manager.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'\n\nimport { createStub } from '@mtcute/test'\nimport { tl } from '@mtcute/tl'\n\nimport { ConfigManager } from './config-manager.js'\n\ndescribe('ConfigManager', () => {\n const config = createStub('config', {\n expires: 300,\n })\n const getConfig = vi.fn()\n\n beforeEach(() => {\n vi.useFakeTimers()\n vi.setSystemTime(0)\n getConfig.mockClear().mockImplementation(() => Promise.resolve(config))\n })\n afterEach(() => void vi.useRealTimers())\n\n it('should fetch initial config', async () => {\n const cm = new ConfigManager(getConfig)\n\n const fetchedConfig = await cm.get()\n\n expect(getConfig).toHaveBeenCalledTimes(1)\n expect(fetchedConfig).toEqual(config)\n expect(cm.getNow()).toEqual(config)\n })\n\n it('should automatically update config', async () => {\n const cm = new ConfigManager(getConfig)\n await cm.update()\n\n getConfig.mockImplementation(() =>\n Promise.resolve({\n ...config,\n expires: 600,\n }),\n )\n\n await vi.advanceTimersByTimeAsync(301_000)\n\n expect(getConfig).toHaveBeenCalledTimes(2)\n })\n\n it('should correctly determine stale config', () => {\n const cm = new ConfigManager(getConfig)\n expect(cm.isStale).toBe(true)\n\n cm.setConfig(config)\n expect(cm.isStale).toBe(false)\n\n vi.setSystemTime(300_000)\n expect(cm.isStale).toBe(true)\n })\n\n it('should not update config if not stale', async () => {\n const cm = new ConfigManager(getConfig)\n await cm.update()\n\n getConfig.mockClear()\n await cm.update()\n\n expect(getConfig).not.toHaveBeenCalled()\n })\n\n it('should not update config twice', async () => {\n const cm = new ConfigManager(getConfig)\n await cm.update()\n\n vi.setSystemTime(300_000)\n getConfig.mockClear()\n await Promise.all([cm.update(), cm.update()])\n\n expect(getConfig).toHaveBeenCalledOnce()\n })\n\n it('should call listeners on config update', async () => {\n const cm = new ConfigManager(getConfig)\n const listener = vi.fn()\n cm.onConfigUpdate(listener)\n await cm.update()\n\n vi.setSystemTime(300_000)\n cm.offConfigUpdate(listener)\n await cm.update()\n\n expect(listener).toHaveBeenCalledOnce()\n expect(listener).toHaveBeenCalledWith(config)\n })\n\n it('should correctly destroy', async () => {\n const cm = new ConfigManager(getConfig)\n await cm.update()\n\n cm.destroy()\n\n getConfig.mockClear()\n await vi.advanceTimersByTimeAsync(301_000)\n\n expect(getConfig).not.toHaveBeenCalled()\n })\n\n describe('findOption', () => {\n const useDcOptions = (options: tl.RawDcOption[]) => {\n getConfig.mockImplementation(() =>\n Promise.resolve({\n ...config,\n dcOptions: options,\n }),\n )\n }\n\n const findOption = async (params: Parameters<ConfigManager['findOption']>[0]) => {\n const cm = new ConfigManager(getConfig)\n await cm.update()\n\n return cm.findOption(params)\n }\n\n it('should find option by dc id', async () => {\n useDcOptions([\n createStub('dcOption', { id: 1, ipAddress: '1.1.1.1' }),\n createStub('dcOption', { id: 2, ipAddress: '2.2.2.2' }),\n ])\n\n expect(await findOption({ dcId: 1 })).toMatchObject({\n id: 1,\n ipAddress: '1.1.1.1',\n })\n expect(await findOption({ dcId: 2 })).toMatchObject({\n id: 2,\n ipAddress: '2.2.2.2',\n })\n })\n\n it('should ignore tcpoOnly options', async () => {\n useDcOptions([\n createStub('dcOption', { id: 1, ipAddress: '1.1.1.1', tcpoOnly: true }),\n createStub('dcOption', { id: 1, ipAddress: '1.1.1.2' }),\n ])\n\n expect(await findOption({ dcId: 1 })).toMatchObject({\n id: 1,\n ipAddress: '1.1.1.2',\n })\n })\n\n it('should respect allowMedia flag', async () => {\n useDcOptions([\n createStub('dcOption', { id: 2, ipAddress: '2.2.2.2', mediaOnly: true }),\n createStub('dcOption', { id: 2, ipAddress: '2.2.2.3' }),\n ])\n\n expect(await findOption({ dcId: 2 })).toMatchObject({\n id: 2,\n ipAddress: '2.2.2.3',\n })\n\n expect(await findOption({ dcId: 2, allowMedia: true })).toMatchObject({\n id: 2,\n ipAddress: '2.2.2.2',\n })\n })\n\n it('should respect preferMedia flag', async () => {\n useDcOptions([\n createStub('dcOption', { id: 2, ipAddress: '2.2.2.3' }),\n createStub('dcOption', { id: 2, ipAddress: '2.2.2.2', mediaOnly: true }),\n ])\n\n expect(await findOption({ dcId: 2 })).toMatchObject({\n id: 2,\n ipAddress: '2.2.2.3',\n })\n\n expect(await findOption({ dcId: 2, allowMedia: true, preferMedia: true })).toMatchObject({\n id: 2,\n ipAddress: '2.2.2.2',\n })\n })\n\n it('should respect allowIpv6 flag', async () => {\n useDcOptions([\n createStub('dcOption', { id: 2, ipAddress: '::1', ipv6: true }),\n createStub('dcOption', { id: 2, ipAddress: '2.2.2.3' }),\n ])\n\n expect(await findOption({ dcId: 2 })).toMatchObject({\n id: 2,\n ipAddress: '2.2.2.3',\n })\n\n expect(await findOption({ dcId: 2, allowIpv6: true })).toMatchObject({\n id: 2,\n ipAddress: '::1',\n })\n })\n\n it('should respect preferIpv6 flag', async () => {\n useDcOptions([\n createStub('dcOption', { id: 2, ipAddress: '2.2.2.3' }),\n createStub('dcOption', { id: 2, ipAddress: '::1', ipv6: true }),\n ])\n\n expect(await findOption({ dcId: 2 })).toMatchObject({\n id: 2,\n ipAddress: '2.2.2.3',\n })\n\n expect(await findOption({ dcId: 2, allowIpv6: true, preferIpv6: true })).toMatchObject({\n id: 2,\n ipAddress: '::1',\n })\n })\n })\n})\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|