@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.
Files changed (253) hide show
  1. package/cjs/network/auth-key.test.d.ts +1 -0
  2. package/cjs/network/auth-key.test.js +111 -0
  3. package/cjs/network/auth-key.test.js.map +1 -0
  4. package/cjs/network/config-manager.js +2 -1
  5. package/cjs/network/config-manager.js.map +1 -1
  6. package/cjs/network/config-manager.test.d.ts +1 -0
  7. package/cjs/network/config-manager.test.js +170 -0
  8. package/cjs/network/config-manager.test.js.map +1 -0
  9. package/cjs/network/network-manager.js +1 -1
  10. package/cjs/network/persistent-connection.test.d.ts +1 -0
  11. package/cjs/network/persistent-connection.test.js +157 -0
  12. package/cjs/network/persistent-connection.test.js.map +1 -0
  13. package/cjs/network/session-connection.js +3 -2
  14. package/cjs/network/session-connection.js.map +1 -1
  15. package/cjs/network/transports/intermediate.test.d.ts +1 -0
  16. package/cjs/network/transports/intermediate.test.js +86 -0
  17. package/cjs/network/transports/intermediate.test.js.map +1 -0
  18. package/cjs/network/transports/obfuscated.js +1 -1
  19. package/cjs/network/transports/obfuscated.js.map +1 -1
  20. package/cjs/network/transports/obfuscated.test.d.ts +1 -0
  21. package/cjs/network/transports/obfuscated.test.js +131 -0
  22. package/cjs/network/transports/obfuscated.test.js.map +1 -0
  23. package/cjs/network/transports/tcp.js +1 -1
  24. package/cjs/network/transports/tcp.js.map +1 -1
  25. package/cjs/network/transports/tcp.test.d.ts +1 -0
  26. package/cjs/network/transports/tcp.test.js +97 -0
  27. package/cjs/network/transports/tcp.test.js.map +1 -0
  28. package/cjs/network/transports/websocket.test.d.ts +1 -0
  29. package/cjs/network/transports/websocket.test.js +91 -0
  30. package/cjs/network/transports/websocket.test.js.map +1 -0
  31. package/cjs/storage/json.test.d.ts +1 -0
  32. package/cjs/storage/json.test.js +37 -0
  33. package/cjs/storage/json.test.js.map +1 -0
  34. package/cjs/storage/localstorage.test.d.ts +1 -0
  35. package/cjs/storage/localstorage.test.js +23 -0
  36. package/cjs/storage/localstorage.test.js.map +1 -0
  37. package/cjs/storage/memory.test.d.ts +1 -0
  38. package/cjs/storage/memory.test.js +47 -0
  39. package/cjs/storage/memory.test.js.map +1 -0
  40. package/cjs/utils/async-lock.test.d.ts +1 -0
  41. package/cjs/utils/async-lock.test.js +25 -0
  42. package/cjs/utils/async-lock.test.js.map +1 -0
  43. package/cjs/utils/bigint-utils.test.d.ts +1 -0
  44. package/cjs/utils/bigint-utils.test.js +150 -0
  45. package/cjs/utils/bigint-utils.test.js.map +1 -0
  46. package/cjs/utils/buffer-utils.test.d.ts +1 -0
  47. package/cjs/utils/buffer-utils.test.js +69 -0
  48. package/cjs/utils/buffer-utils.test.js.map +1 -0
  49. package/cjs/utils/condition-variable.test.d.ts +1 -0
  50. package/cjs/utils/condition-variable.test.js +27 -0
  51. package/cjs/utils/condition-variable.test.js.map +1 -0
  52. package/cjs/utils/controllable-promise.test.d.ts +1 -0
  53. package/cjs/utils/controllable-promise.test.js +17 -0
  54. package/cjs/utils/controllable-promise.test.js.map +1 -0
  55. package/cjs/utils/crypto/keys.test.d.ts +1 -0
  56. package/cjs/utils/crypto/keys.test.js +40 -0
  57. package/cjs/utils/crypto/keys.test.js.map +1 -0
  58. package/cjs/utils/crypto/miller-rabin.test.d.ts +1 -0
  59. package/cjs/utils/crypto/miller-rabin.test.js +60 -0
  60. package/cjs/utils/crypto/miller-rabin.test.js.map +1 -0
  61. package/cjs/utils/crypto/mtproto.test.d.ts +1 -0
  62. package/cjs/utils/crypto/mtproto.test.js +47 -0
  63. package/cjs/utils/crypto/mtproto.test.js.map +1 -0
  64. package/cjs/utils/crypto/node.test.d.ts +1 -0
  65. package/cjs/utils/crypto/node.test.js +13 -0
  66. package/cjs/utils/crypto/node.test.js.map +1 -0
  67. package/cjs/utils/crypto/password.test.d.ts +1 -0
  68. package/cjs/utils/crypto/password.test.js +95 -0
  69. package/cjs/utils/crypto/password.test.js.map +1 -0
  70. package/cjs/utils/crypto/utils.test.d.ts +1 -0
  71. package/cjs/utils/crypto/utils.test.js +49 -0
  72. package/cjs/utils/crypto/utils.test.js.map +1 -0
  73. package/cjs/utils/crypto/web.test.d.ts +1 -0
  74. package/cjs/utils/crypto/web.test.js +17 -0
  75. package/cjs/utils/crypto/web.test.js.map +1 -0
  76. package/cjs/utils/deque.test.d.ts +1 -0
  77. package/cjs/utils/deque.test.js +128 -0
  78. package/cjs/utils/deque.test.js.map +1 -0
  79. package/cjs/utils/function-utils.test.d.ts +1 -0
  80. package/cjs/utils/function-utils.test.js +23 -0
  81. package/cjs/utils/function-utils.test.js.map +1 -0
  82. package/cjs/utils/linked-list.test.d.ts +1 -0
  83. package/cjs/utils/linked-list.test.js +36 -0
  84. package/cjs/utils/linked-list.test.js.map +1 -0
  85. package/cjs/utils/links/bots.test.d.ts +1 -0
  86. package/cjs/utils/links/bots.test.js +152 -0
  87. package/cjs/utils/links/bots.test.js.map +1 -0
  88. package/cjs/utils/links/chat.test.d.ts +1 -0
  89. package/cjs/utils/links/chat.test.js +84 -0
  90. package/cjs/utils/links/chat.test.js.map +1 -0
  91. package/cjs/utils/links/misc.test.d.ts +1 -0
  92. package/cjs/utils/links/misc.test.js +153 -0
  93. package/cjs/utils/links/misc.test.js.map +1 -0
  94. package/cjs/utils/links/proxy.test.d.ts +1 -0
  95. package/cjs/utils/links/proxy.test.js +74 -0
  96. package/cjs/utils/links/proxy.test.js.map +1 -0
  97. package/cjs/utils/links/user.test.d.ts +1 -0
  98. package/cjs/utils/links/user.test.js +63 -0
  99. package/cjs/utils/links/user.test.js.map +1 -0
  100. package/cjs/utils/logger.test.d.ts +1 -0
  101. package/cjs/utils/logger.test.js +125 -0
  102. package/cjs/utils/logger.test.js.map +1 -0
  103. package/cjs/utils/long-utils.test.d.ts +1 -0
  104. package/cjs/utils/long-utils.test.js +158 -0
  105. package/cjs/utils/long-utils.test.js.map +1 -0
  106. package/cjs/utils/lru-map.test.d.ts +1 -0
  107. package/cjs/utils/lru-map.test.js +96 -0
  108. package/cjs/utils/lru-map.test.js.map +1 -0
  109. package/cjs/utils/lru-set.test.d.ts +1 -0
  110. package/cjs/utils/lru-set.test.js +77 -0
  111. package/cjs/utils/lru-set.test.js.map +1 -0
  112. package/cjs/utils/peer-utils.test.d.ts +1 -0
  113. package/cjs/utils/peer-utils.test.js +122 -0
  114. package/cjs/utils/peer-utils.test.js.map +1 -0
  115. package/cjs/utils/sorted-array.test.d.ts +1 -0
  116. package/cjs/utils/sorted-array.test.js +66 -0
  117. package/cjs/utils/sorted-array.test.js.map +1 -0
  118. package/cjs/utils/string-session.test.d.ts +1 -0
  119. package/cjs/utils/string-session.test.js +106 -0
  120. package/cjs/utils/string-session.test.js.map +1 -0
  121. package/cjs/utils/tl-json.test.d.ts +1 -0
  122. package/cjs/utils/tl-json.test.js +83 -0
  123. package/cjs/utils/tl-json.test.js.map +1 -0
  124. package/cjs/utils/type-assertions.test.d.ts +1 -0
  125. package/cjs/utils/type-assertions.test.js +67 -0
  126. package/cjs/utils/type-assertions.test.js.map +1 -0
  127. package/esm/network/auth-key.test.d.ts +1 -0
  128. package/esm/network/auth-key.test.js +106 -0
  129. package/esm/network/auth-key.test.js.map +1 -0
  130. package/esm/network/config-manager.js +2 -1
  131. package/esm/network/config-manager.js.map +1 -1
  132. package/esm/network/config-manager.test.d.ts +1 -0
  133. package/esm/network/config-manager.test.js +168 -0
  134. package/esm/network/config-manager.test.js.map +1 -0
  135. package/esm/network/network-manager.js +1 -1
  136. package/esm/network/persistent-connection.test.d.ts +1 -0
  137. package/esm/network/persistent-connection.test.js +155 -0
  138. package/esm/network/persistent-connection.test.js.map +1 -0
  139. package/esm/network/session-connection.js +3 -2
  140. package/esm/network/session-connection.js.map +1 -1
  141. package/esm/network/transports/intermediate.test.d.ts +1 -0
  142. package/esm/network/transports/intermediate.test.js +84 -0
  143. package/esm/network/transports/intermediate.test.js.map +1 -0
  144. package/esm/network/transports/obfuscated.js +1 -1
  145. package/esm/network/transports/obfuscated.js.map +1 -1
  146. package/esm/network/transports/obfuscated.test.d.ts +1 -0
  147. package/esm/network/transports/obfuscated.test.js +129 -0
  148. package/esm/network/transports/obfuscated.test.js.map +1 -0
  149. package/esm/network/transports/tcp.js +1 -1
  150. package/esm/network/transports/tcp.js.map +1 -1
  151. package/esm/network/transports/tcp.test.d.ts +1 -0
  152. package/esm/network/transports/tcp.test.js +95 -0
  153. package/esm/network/transports/tcp.test.js.map +1 -0
  154. package/esm/network/transports/websocket.test.d.ts +1 -0
  155. package/esm/network/transports/websocket.test.js +89 -0
  156. package/esm/network/transports/websocket.test.js.map +1 -0
  157. package/esm/storage/json.test.d.ts +1 -0
  158. package/esm/storage/json.test.js +35 -0
  159. package/esm/storage/json.test.js.map +1 -0
  160. package/esm/storage/localstorage.test.d.ts +1 -0
  161. package/esm/storage/localstorage.test.js +21 -0
  162. package/esm/storage/localstorage.test.js.map +1 -0
  163. package/esm/storage/memory.test.d.ts +1 -0
  164. package/esm/storage/memory.test.js +45 -0
  165. package/esm/storage/memory.test.js.map +1 -0
  166. package/esm/utils/async-lock.test.d.ts +1 -0
  167. package/esm/utils/async-lock.test.js +23 -0
  168. package/esm/utils/async-lock.test.js.map +1 -0
  169. package/esm/utils/bigint-utils.test.d.ts +1 -0
  170. package/esm/utils/bigint-utils.test.js +148 -0
  171. package/esm/utils/bigint-utils.test.js.map +1 -0
  172. package/esm/utils/buffer-utils.test.d.ts +1 -0
  173. package/esm/utils/buffer-utils.test.js +67 -0
  174. package/esm/utils/buffer-utils.test.js.map +1 -0
  175. package/esm/utils/condition-variable.test.d.ts +1 -0
  176. package/esm/utils/condition-variable.test.js +25 -0
  177. package/esm/utils/condition-variable.test.js.map +1 -0
  178. package/esm/utils/controllable-promise.test.d.ts +1 -0
  179. package/esm/utils/controllable-promise.test.js +15 -0
  180. package/esm/utils/controllable-promise.test.js.map +1 -0
  181. package/esm/utils/crypto/keys.test.d.ts +1 -0
  182. package/esm/utils/crypto/keys.test.js +38 -0
  183. package/esm/utils/crypto/keys.test.js.map +1 -0
  184. package/esm/utils/crypto/miller-rabin.test.d.ts +1 -0
  185. package/esm/utils/crypto/miller-rabin.test.js +58 -0
  186. package/esm/utils/crypto/miller-rabin.test.js.map +1 -0
  187. package/esm/utils/crypto/mtproto.test.d.ts +1 -0
  188. package/esm/utils/crypto/mtproto.test.js +45 -0
  189. package/esm/utils/crypto/mtproto.test.js.map +1 -0
  190. package/esm/utils/crypto/node.test.d.ts +1 -0
  191. package/esm/utils/crypto/node.test.js +11 -0
  192. package/esm/utils/crypto/node.test.js.map +1 -0
  193. package/esm/utils/crypto/password.test.d.ts +1 -0
  194. package/esm/utils/crypto/password.test.js +90 -0
  195. package/esm/utils/crypto/password.test.js.map +1 -0
  196. package/esm/utils/crypto/utils.test.d.ts +1 -0
  197. package/esm/utils/crypto/utils.test.js +47 -0
  198. package/esm/utils/crypto/utils.test.js.map +1 -0
  199. package/esm/utils/crypto/web.test.d.ts +1 -0
  200. package/esm/utils/crypto/web.test.js +15 -0
  201. package/esm/utils/crypto/web.test.js.map +1 -0
  202. package/esm/utils/deque.test.d.ts +1 -0
  203. package/esm/utils/deque.test.js +126 -0
  204. package/esm/utils/deque.test.js.map +1 -0
  205. package/esm/utils/function-utils.test.d.ts +1 -0
  206. package/esm/utils/function-utils.test.js +21 -0
  207. package/esm/utils/function-utils.test.js.map +1 -0
  208. package/esm/utils/linked-list.test.d.ts +1 -0
  209. package/esm/utils/linked-list.test.js +34 -0
  210. package/esm/utils/linked-list.test.js.map +1 -0
  211. package/esm/utils/links/bots.test.d.ts +1 -0
  212. package/esm/utils/links/bots.test.js +150 -0
  213. package/esm/utils/links/bots.test.js.map +1 -0
  214. package/esm/utils/links/chat.test.d.ts +1 -0
  215. package/esm/utils/links/chat.test.js +82 -0
  216. package/esm/utils/links/chat.test.js.map +1 -0
  217. package/esm/utils/links/misc.test.d.ts +1 -0
  218. package/esm/utils/links/misc.test.js +151 -0
  219. package/esm/utils/links/misc.test.js.map +1 -0
  220. package/esm/utils/links/proxy.test.d.ts +1 -0
  221. package/esm/utils/links/proxy.test.js +72 -0
  222. package/esm/utils/links/proxy.test.js.map +1 -0
  223. package/esm/utils/links/user.test.d.ts +1 -0
  224. package/esm/utils/links/user.test.js +61 -0
  225. package/esm/utils/links/user.test.js.map +1 -0
  226. package/esm/utils/logger.test.d.ts +1 -0
  227. package/esm/utils/logger.test.js +120 -0
  228. package/esm/utils/logger.test.js.map +1 -0
  229. package/esm/utils/long-utils.test.d.ts +1 -0
  230. package/esm/utils/long-utils.test.js +153 -0
  231. package/esm/utils/long-utils.test.js.map +1 -0
  232. package/esm/utils/lru-map.test.d.ts +1 -0
  233. package/esm/utils/lru-map.test.js +94 -0
  234. package/esm/utils/lru-map.test.js.map +1 -0
  235. package/esm/utils/lru-set.test.d.ts +1 -0
  236. package/esm/utils/lru-set.test.js +72 -0
  237. package/esm/utils/lru-set.test.js.map +1 -0
  238. package/esm/utils/peer-utils.test.d.ts +1 -0
  239. package/esm/utils/peer-utils.test.js +117 -0
  240. package/esm/utils/peer-utils.test.js.map +1 -0
  241. package/esm/utils/sorted-array.test.d.ts +1 -0
  242. package/esm/utils/sorted-array.test.js +64 -0
  243. package/esm/utils/sorted-array.test.js.map +1 -0
  244. package/esm/utils/string-session.test.d.ts +1 -0
  245. package/esm/utils/string-session.test.js +104 -0
  246. package/esm/utils/string-session.test.js.map +1 -0
  247. package/esm/utils/tl-json.test.d.ts +1 -0
  248. package/esm/utils/tl-json.test.js +81 -0
  249. package/esm/utils/tl-json.test.js.map +1 -0
  250. package/esm/utils/type-assertions.test.d.ts +1 -0
  251. package/esm/utils/type-assertions.test.js +65 -0
  252. package/esm/utils/type-assertions.test.js.map +1 -0
  253. package/package.json +2 -2
@@ -0,0 +1,84 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { defaultTestCryptoProvider, useFakeMathRandom } from '@mtcute/test';
3
+ import { hexDecodeToBuffer, hexEncode } from '@mtcute/tl-runtime';
4
+ import { IntermediatePacketCodec, PaddedIntermediatePacketCodec, TransportError } from '../../index.js';
5
+ import { concatBuffers } from '../../utils/index.js';
6
+ describe('IntermediatePacketCodec', () => {
7
+ it('should return correct tag', () => {
8
+ expect(hexEncode(new IntermediatePacketCodec().tag())).eq('eeeeeeee');
9
+ });
10
+ it('should correctly parse immediate framing', () => new Promise((done) => {
11
+ const codec = new IntermediatePacketCodec();
12
+ codec.on('packet', (data) => {
13
+ expect([...data]).eql([5, 1, 2, 3, 4]);
14
+ done();
15
+ });
16
+ codec.feed(hexDecodeToBuffer('050000000501020304'));
17
+ }));
18
+ it('should correctly parse incomplete framing', () => new Promise((done) => {
19
+ const codec = new IntermediatePacketCodec();
20
+ codec.on('packet', (data) => {
21
+ expect([...data]).eql([5, 1, 2, 3, 4]);
22
+ done();
23
+ });
24
+ codec.feed(hexDecodeToBuffer('050000000501'));
25
+ codec.feed(hexDecodeToBuffer('020304'));
26
+ }));
27
+ it('should correctly parse multiple streamed packets', () => new Promise((done) => {
28
+ const codec = new IntermediatePacketCodec();
29
+ let number = 0;
30
+ codec.on('packet', (data) => {
31
+ if (number === 0) {
32
+ expect([...data]).eql([5, 1, 2, 3, 4]);
33
+ number = 1;
34
+ }
35
+ else {
36
+ expect([...data]).eql([3, 1, 2, 3, 1]);
37
+ done();
38
+ }
39
+ });
40
+ codec.feed(hexDecodeToBuffer('050000000501'));
41
+ codec.feed(hexDecodeToBuffer('020304050000'));
42
+ codec.feed(hexDecodeToBuffer('000301020301'));
43
+ }));
44
+ it('should correctly parse transport errors', () => new Promise((done) => {
45
+ const codec = new IntermediatePacketCodec();
46
+ codec.on('error', (err) => {
47
+ expect(err).to.have.instanceOf(TransportError);
48
+ expect(err.code).eq(404);
49
+ done();
50
+ });
51
+ codec.feed(hexDecodeToBuffer('040000006cfeffff'));
52
+ }));
53
+ it('should reset when called reset()', () => new Promise((done) => {
54
+ const codec = new IntermediatePacketCodec();
55
+ codec.on('packet', (data) => {
56
+ expect([...data]).eql([1, 2, 3, 4, 5]);
57
+ done();
58
+ });
59
+ codec.feed(hexDecodeToBuffer('ff0000001234567812345678'));
60
+ codec.reset();
61
+ codec.feed(hexDecodeToBuffer('050000000102030405'));
62
+ }));
63
+ it('should correctly frame packets', () => {
64
+ const data = hexDecodeToBuffer('6cfeffff');
65
+ // eslint-disable-next-line no-restricted-globals
66
+ expect(Buffer.from(new IntermediatePacketCodec().encode(data))).toEqual(concatBuffers([new Uint8Array([0x04, 0x00, 0x00, 0x00]), data]));
67
+ });
68
+ });
69
+ describe('PaddedIntermediatePacketCodec', () => {
70
+ useFakeMathRandom();
71
+ const create = async () => {
72
+ const codec = new PaddedIntermediatePacketCodec();
73
+ codec.setup(await defaultTestCryptoProvider());
74
+ return codec;
75
+ };
76
+ it('should return correct tag', async () => {
77
+ expect(hexEncode((await create()).tag())).eq('dddddddd');
78
+ });
79
+ it('should correctly frame packets', async () => {
80
+ const data = hexDecodeToBuffer('6cfeffff');
81
+ expect(hexEncode((await create()).encode(data))).toEqual('0a0000006cfeffff29afd26df40f');
82
+ });
83
+ });
84
+ //# sourceMappingURL=intermediate.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"intermediate.test.js","sourceRoot":"","sources":["../../../../src/network/transports/intermediate.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, it } from 'vitest'\n\nimport { defaultTestCryptoProvider, useFakeMathRandom } from '@mtcute/test'\nimport { hexDecodeToBuffer, hexEncode } from '@mtcute/tl-runtime'\n\nimport { IntermediatePacketCodec, PaddedIntermediatePacketCodec, TransportError } from '../../index.js'\nimport { concatBuffers } from '../../utils/index.js'\n\ndescribe('IntermediatePacketCodec', () => {\n it('should return correct tag', () => {\n expect(hexEncode(new IntermediatePacketCodec().tag())).eq('eeeeeeee')\n })\n\n it('should correctly parse immediate framing', () =>\n new Promise<void>((done) => {\n const codec = new IntermediatePacketCodec()\n codec.on('packet', (data: Uint8Array) => {\n expect([...data]).eql([5, 1, 2, 3, 4])\n done()\n })\n codec.feed(hexDecodeToBuffer('050000000501020304'))\n }))\n\n it('should correctly parse incomplete framing', () =>\n new Promise<void>((done) => {\n const codec = new IntermediatePacketCodec()\n codec.on('packet', (data: Uint8Array) => {\n expect([...data]).eql([5, 1, 2, 3, 4])\n done()\n })\n codec.feed(hexDecodeToBuffer('050000000501'))\n codec.feed(hexDecodeToBuffer('020304'))\n }))\n\n it('should correctly parse multiple streamed packets', () =>\n new Promise<void>((done) => {\n const codec = new IntermediatePacketCodec()\n\n let number = 0\n\n codec.on('packet', (data: Uint8Array) => {\n if (number === 0) {\n expect([...data]).eql([5, 1, 2, 3, 4])\n number = 1\n } else {\n expect([...data]).eql([3, 1, 2, 3, 1])\n done()\n }\n })\n codec.feed(hexDecodeToBuffer('050000000501'))\n codec.feed(hexDecodeToBuffer('020304050000'))\n codec.feed(hexDecodeToBuffer('000301020301'))\n }))\n\n it('should correctly parse transport errors', () =>\n new Promise<void>((done) => {\n const codec = new IntermediatePacketCodec()\n\n codec.on('error', (err: TransportError) => {\n expect(err).to.have.instanceOf(TransportError)\n expect(err.code).eq(404)\n done()\n })\n\n codec.feed(hexDecodeToBuffer('040000006cfeffff'))\n }))\n\n it('should reset when called reset()', () =>\n new Promise<void>((done) => {\n const codec = new IntermediatePacketCodec()\n\n codec.on('packet', (data: Uint8Array) => {\n expect([...data]).eql([1, 2, 3, 4, 5])\n done()\n })\n\n codec.feed(hexDecodeToBuffer('ff0000001234567812345678'))\n codec.reset()\n codec.feed(hexDecodeToBuffer('050000000102030405'))\n }))\n\n it('should correctly frame packets', () => {\n const data = hexDecodeToBuffer('6cfeffff')\n\n // eslint-disable-next-line no-restricted-globals\n expect(Buffer.from(new IntermediatePacketCodec().encode(data))).toEqual(\n concatBuffers([new Uint8Array([0x04, 0x00, 0x00, 0x00]), data]),\n )\n })\n})\n\ndescribe('PaddedIntermediatePacketCodec', () => {\n useFakeMathRandom()\n\n const create = async () => {\n const codec = new PaddedIntermediatePacketCodec()\n codec.setup!(await defaultTestCryptoProvider())\n\n return codec\n }\n\n it('should return correct tag', async () => {\n expect(hexEncode((await create()).tag())).eq('dddddddd')\n })\n\n it('should correctly frame packets', async () => {\n const data = hexDecodeToBuffer('6cfeffff')\n\n expect(hexEncode((await create()).encode(data))).toEqual('0a0000006cfeffff29afd26df40f')\n })\n})\n"]}
@@ -13,7 +13,7 @@ export class ObfuscatedPacketCodec extends WrappedCodec {
13
13
  if (random[0] === 0xef)
14
14
  continue;
15
15
  dv = dataViewFromBuffer(random);
16
- const firstInt = dv.getInt32(0, true);
16
+ const firstInt = dv.getUint32(0, true);
17
17
  if (firstInt === 0x44414548 || // HEAD
18
18
  firstInt === 0x54534f50 || // POST
19
19
  firstInt === 0x20544547 || // GET(space)
@@ -1 +1 @@
1
- {"version":3,"file":"obfuscated.js","sourceRoot":"","sources":["../../../../src/network/transports/obfuscated.ts"],"names":[],"mappings":"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","sourcesContent":["import { bufferToReversed, concatBuffers, dataViewFromBuffer } from '../../utils/buffer-utils.js'\nimport { IAesCtr } from '../../utils/index.js'\nimport { IPacketCodec } from './abstract.js'\nimport { WrappedCodec } from './wrapped.js'\n\nexport interface MtProxyInfo {\n dcId: number\n secret: Uint8Array\n test: boolean\n media: boolean\n}\n\nexport class ObfuscatedPacketCodec extends WrappedCodec implements IPacketCodec {\n private _encryptor?: IAesCtr\n private _decryptor?: IAesCtr\n\n private _proxy?: MtProxyInfo\n\n constructor(inner: IPacketCodec, proxy?: MtProxyInfo) {\n super(inner)\n this._proxy = proxy\n }\n\n async tag(): Promise<Uint8Array> {\n let random: Uint8Array\n let dv: DataView\n\n for (;;) {\n random = this._crypto.randomBytes(64)\n if (random[0] === 0xef) continue\n\n dv = dataViewFromBuffer(random)\n const firstInt = dv.getInt32(0, true)\n\n if (\n firstInt === 0x44414548 || // HEAD\n firstInt === 0x54534f50 || // POST\n firstInt === 0x20544547 || // GET(space)\n firstInt === 0x4954504f || // OPTI\n firstInt === 0xdddddddd || // padded intermediate\n firstInt === 0xeeeeeeee || // intermediate\n firstInt === 0x02010316 // no idea, taken from tdlib\n ) {\n continue\n }\n if (dv.getInt32(4, true) === 0) continue\n\n break\n }\n\n let innerTag = await this._inner.tag()\n\n if (innerTag.length !== 4) {\n const b = innerTag[0]\n innerTag = new Uint8Array([b, b, b, b])\n }\n random.set(innerTag, 56)\n\n if (this._proxy) {\n let dcId = this._proxy.dcId\n if (this._proxy.test) dcId += 10000\n if (this._proxy.media) dcId = -dcId\n\n dv.setInt16(60, dcId, true)\n }\n\n const randomRev = bufferToReversed(random, 8, 56)\n\n let encryptKey = random.subarray(8, 40)\n const encryptIv = random.subarray(40, 56)\n\n let decryptKey = randomRev.subarray(0, 32)\n const decryptIv = randomRev.subarray(32, 48)\n\n if (this._proxy) {\n encryptKey = this._crypto.sha256(concatBuffers([encryptKey, this._proxy.secret]))\n decryptKey = this._crypto.sha256(concatBuffers([decryptKey, this._proxy.secret]))\n }\n\n this._encryptor = this._crypto.createAesCtr(encryptKey, encryptIv, true)\n this._decryptor = this._crypto.createAesCtr(decryptKey, decryptIv, false)\n\n const encrypted = this._encryptor.process(random)\n random.set(encrypted.subarray(56, 64), 56)\n\n return random\n }\n\n async encode(packet: Uint8Array): Promise<Uint8Array> {\n return this._encryptor!.process(await this._inner.encode(packet))\n }\n\n feed(data: Uint8Array): void {\n const dec = this._decryptor!.process(data)\n\n this._inner.feed(dec)\n }\n\n reset(): void {\n this._inner.reset()\n this._encryptor?.close?.()\n this._decryptor?.close?.()\n\n this._encryptor = undefined\n this._decryptor = undefined\n }\n}\n"]}
1
+ {"version":3,"file":"obfuscated.js","sourceRoot":"","sources":["../../../../src/network/transports/obfuscated.ts"],"names":[],"mappings":"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","sourcesContent":["import { bufferToReversed, concatBuffers, dataViewFromBuffer } from '../../utils/buffer-utils.js'\nimport { IAesCtr } from '../../utils/index.js'\nimport { IPacketCodec } from './abstract.js'\nimport { WrappedCodec } from './wrapped.js'\n\nexport interface MtProxyInfo {\n dcId: number\n secret: Uint8Array\n test: boolean\n media: boolean\n}\n\nexport class ObfuscatedPacketCodec extends WrappedCodec implements IPacketCodec {\n private _encryptor?: IAesCtr\n private _decryptor?: IAesCtr\n\n private _proxy?: MtProxyInfo\n\n constructor(inner: IPacketCodec, proxy?: MtProxyInfo) {\n super(inner)\n this._proxy = proxy\n }\n\n async tag(): Promise<Uint8Array> {\n let random: Uint8Array\n let dv: DataView\n\n for (;;) {\n random = this._crypto.randomBytes(64)\n if (random[0] === 0xef) continue\n\n dv = dataViewFromBuffer(random)\n const firstInt = dv.getUint32(0, true)\n\n if (\n firstInt === 0x44414548 || // HEAD\n firstInt === 0x54534f50 || // POST\n firstInt === 0x20544547 || // GET(space)\n firstInt === 0x4954504f || // OPTI\n firstInt === 0xdddddddd || // padded intermediate\n firstInt === 0xeeeeeeee || // intermediate\n firstInt === 0x02010316 // no idea, taken from tdlib\n ) {\n continue\n }\n if (dv.getInt32(4, true) === 0) continue\n\n break\n }\n\n let innerTag = await this._inner.tag()\n\n if (innerTag.length !== 4) {\n const b = innerTag[0]\n innerTag = new Uint8Array([b, b, b, b])\n }\n random.set(innerTag, 56)\n\n if (this._proxy) {\n let dcId = this._proxy.dcId\n if (this._proxy.test) dcId += 10000\n if (this._proxy.media) dcId = -dcId\n\n dv.setInt16(60, dcId, true)\n }\n\n const randomRev = bufferToReversed(random, 8, 56)\n\n let encryptKey = random.subarray(8, 40)\n const encryptIv = random.subarray(40, 56)\n\n let decryptKey = randomRev.subarray(0, 32)\n const decryptIv = randomRev.subarray(32, 48)\n\n if (this._proxy) {\n encryptKey = this._crypto.sha256(concatBuffers([encryptKey, this._proxy.secret]))\n decryptKey = this._crypto.sha256(concatBuffers([decryptKey, this._proxy.secret]))\n }\n\n this._encryptor = this._crypto.createAesCtr(encryptKey, encryptIv, true)\n this._decryptor = this._crypto.createAesCtr(decryptKey, decryptIv, false)\n\n const encrypted = this._encryptor.process(random)\n random.set(encrypted.subarray(56, 64), 56)\n\n return random\n }\n\n async encode(packet: Uint8Array): Promise<Uint8Array> {\n return this._encryptor!.process(await this._inner.encode(packet))\n }\n\n feed(data: Uint8Array): void {\n const dec = this._decryptor!.process(data)\n\n this._inner.feed(dec)\n }\n\n reset(): void {\n this._inner.reset()\n this._encryptor?.close?.()\n this._decryptor?.close?.()\n\n this._encryptor = undefined\n this._decryptor = undefined\n }\n}\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,129 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { defaultTestCryptoProvider, u8HexDecode } from '@mtcute/test';
3
+ import { hexDecodeToBuffer, hexEncode, LogManager } from '../../utils/index.js';
4
+ import { IntermediatePacketCodec } from './intermediate.js';
5
+ import { ObfuscatedPacketCodec } from './obfuscated.js';
6
+ describe('ObfuscatedPacketCodec', () => {
7
+ const create = async (randomSource, proxy) => {
8
+ const codec = new ObfuscatedPacketCodec(new IntermediatePacketCodec(), proxy);
9
+ const crypto = await defaultTestCryptoProvider(randomSource);
10
+ codec.setup(crypto, new LogManager());
11
+ return [codec, crypto];
12
+ };
13
+ describe('tag', () => {
14
+ it('should correctly generate random initial payload', async () => {
15
+ const random = 'ff'.repeat(64);
16
+ const [codec] = await create(random);
17
+ const tag = await codec.tag();
18
+ expect(hexEncode(tag)).toEqual('ff'.repeat(56) + 'fce8ab2203db2bff');
19
+ });
20
+ describe('mtproxy', () => {
21
+ it('should correctly generate random initial payload for prod dc', async () => {
22
+ const random = 'ff'.repeat(64);
23
+ const proxy = {
24
+ dcId: 1,
25
+ secret: new Uint8Array(16),
26
+ test: false,
27
+ media: false,
28
+ };
29
+ const [codec] = await create(random, proxy);
30
+ const tag = await codec.tag();
31
+ expect(hexEncode(tag)).toEqual('ff'.repeat(56) + 'ecec4cbda8bb188b');
32
+ });
33
+ it('should correctly generate random initial payload for test dc', async () => {
34
+ const random = 'ff'.repeat(64);
35
+ const proxy = {
36
+ dcId: 1,
37
+ secret: new Uint8Array(16),
38
+ test: true,
39
+ media: false,
40
+ };
41
+ const [codec] = await create(random, proxy);
42
+ const tag = await codec.tag();
43
+ expect(hexEncode(tag)).toEqual('ff'.repeat(56) + 'ecec4cbdb89c188b');
44
+ });
45
+ it('should correctly generate random initial payload for media dc', async () => {
46
+ const random = 'ff'.repeat(64);
47
+ const proxy = {
48
+ dcId: 1,
49
+ secret: new Uint8Array(16),
50
+ test: false,
51
+ media: true,
52
+ };
53
+ const [codec] = await create(random, proxy);
54
+ const tag = await codec.tag();
55
+ expect(hexEncode(tag)).toEqual('ff'.repeat(56) + 'ecec4cbd5644188b');
56
+ });
57
+ });
58
+ it.each([
59
+ ['ef'],
60
+ ['48454144'],
61
+ ['504f5354'],
62
+ ['47455420'],
63
+ ['4f505449'],
64
+ ['dddddddd'],
65
+ ['eeeeeeee'],
66
+ ['16030102'],
67
+ ])('should correctly retry for %s prefix', async (prefix) => {
68
+ const random = prefix + 'ff'.repeat(64 - prefix.length / 2);
69
+ const [codec] = await create(random);
70
+ // generating random payload requires 64 bytes of entropy, so
71
+ // if it asks for more, it means it tried to generate it again
72
+ await expect(() => codec.tag()).rejects.toThrow('not enough entropy');
73
+ });
74
+ });
75
+ it('should correctly create aes ctr', async () => {
76
+ const [codec, crypto] = await create();
77
+ const spyCreateAesCtr = vi.spyOn(crypto, 'createAesCtr');
78
+ await codec.tag();
79
+ expect(spyCreateAesCtr).toHaveBeenCalledTimes(2);
80
+ expect(spyCreateAesCtr).toHaveBeenNthCalledWith(1, u8HexDecode('10b6b4ad6d56ef5df9453f88e6ee6adb6e0544ba635dc6a8a990c9b8b980c343'), u8HexDecode('936b33fa7f97bae025102532233abb26'), true);
81
+ expect(spyCreateAesCtr).toHaveBeenNthCalledWith(2, u8HexDecode('26bb3a2332251025e0ba977ffa336b9343c380b9b8c990a9a8c65d63ba44056e'), u8HexDecode('db6aeee6883f45f95def566dadb4b610'), false);
82
+ });
83
+ it('should correctly create aes ctr for mtproxy', async () => {
84
+ const proxy = {
85
+ dcId: 1,
86
+ secret: hexDecodeToBuffer('00112233445566778899aabbccddeeff'),
87
+ test: true,
88
+ media: false,
89
+ };
90
+ const [codec, crypto] = await create(undefined, proxy);
91
+ const spyCreateAesCtr = vi.spyOn(crypto, 'createAesCtr');
92
+ await codec.tag();
93
+ expect(spyCreateAesCtr).toHaveBeenCalledTimes(2);
94
+ expect(spyCreateAesCtr).toHaveBeenNthCalledWith(1, hexDecodeToBuffer('dd03188944590983e28dad14d97d0952389d118af4ffcbdb28d56a6a612ef7a6'), u8HexDecode('936b33fa7f97bae025102532233abb26'), true);
95
+ expect(spyCreateAesCtr).toHaveBeenNthCalledWith(2, hexDecodeToBuffer('413b8e08021fbb08a2962b6d7187194fe46565c6b329d3bbdfcffd4870c16119'), u8HexDecode('db6aeee6883f45f95def566dadb4b610'), false);
96
+ });
97
+ it('should correctly encrypt the underlying codec', async () => {
98
+ const data = hexDecodeToBuffer('6cfeffff');
99
+ const msg1 = 'a1020630a410e940';
100
+ const msg2 = 'f53ff53f371db495';
101
+ const [codec] = await create();
102
+ await codec.tag();
103
+ expect(hexEncode(await codec.encode(data))).toEqual(msg1);
104
+ expect(hexEncode(await codec.encode(data))).toEqual(msg2);
105
+ });
106
+ it('should correctly decrypt the underlying codec', async () => {
107
+ const msg1 = 'e8027df708ab3b5c';
108
+ const msg2 = '1854be76d2df4949';
109
+ const [codec] = await create();
110
+ await codec.tag();
111
+ const log = [];
112
+ codec.on('error', (e) => {
113
+ log.push(e.toString());
114
+ });
115
+ codec.feed(hexDecodeToBuffer(msg1));
116
+ codec.feed(hexDecodeToBuffer(msg2));
117
+ await vi.waitFor(() => expect(log).toEqual(['Error: Transport error: 404', 'Error: Transport error: 404']));
118
+ });
119
+ it('should correctly reset', async () => {
120
+ const inner = new IntermediatePacketCodec();
121
+ const spyInnerReset = vi.spyOn(inner, 'reset');
122
+ const codec = new ObfuscatedPacketCodec(inner);
123
+ codec.setup(await defaultTestCryptoProvider(), new LogManager());
124
+ await codec.tag();
125
+ codec.reset();
126
+ expect(spyInnerReset).toHaveBeenCalledTimes(1);
127
+ });
128
+ });
129
+ //# sourceMappingURL=obfuscated.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"obfuscated.test.js","sourceRoot":"","sources":["../../../../src/network/transports/obfuscated.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, it, vi } from 'vitest'\n\nimport { defaultTestCryptoProvider, u8HexDecode } from '@mtcute/test'\n\nimport { hexDecodeToBuffer, hexEncode, LogManager } from '../../utils/index.js'\nimport { IntermediatePacketCodec } from './intermediate.js'\nimport { MtProxyInfo, ObfuscatedPacketCodec } from './obfuscated.js'\n\ndescribe('ObfuscatedPacketCodec', () => {\n const create = async (randomSource?: string, proxy?: MtProxyInfo) => {\n const codec = new ObfuscatedPacketCodec(new IntermediatePacketCodec(), proxy)\n const crypto = await defaultTestCryptoProvider(randomSource)\n codec.setup(crypto, new LogManager())\n\n return [codec, crypto] as const\n }\n\n describe('tag', () => {\n it('should correctly generate random initial payload', async () => {\n const random = 'ff'.repeat(64)\n const [codec] = await create(random)\n\n const tag = await codec.tag()\n\n expect(hexEncode(tag)).toEqual(\n 'ff'.repeat(56) + 'fce8ab2203db2bff', // encrypted part\n )\n })\n\n describe('mtproxy', () => {\n it('should correctly generate random initial payload for prod dc', async () => {\n const random = 'ff'.repeat(64)\n const proxy: MtProxyInfo = {\n dcId: 1,\n secret: new Uint8Array(16),\n test: false,\n media: false,\n }\n const [codec] = await create(random, proxy)\n\n const tag = await codec.tag()\n\n expect(hexEncode(tag)).toEqual(\n 'ff'.repeat(56) + 'ecec4cbda8bb188b', // encrypted part with dcId = 1\n )\n })\n\n it('should correctly generate random initial payload for test dc', async () => {\n const random = 'ff'.repeat(64)\n const proxy: MtProxyInfo = {\n dcId: 1,\n secret: new Uint8Array(16),\n test: true,\n media: false,\n }\n const [codec] = await create(random, proxy)\n\n const tag = await codec.tag()\n\n expect(hexEncode(tag)).toEqual(\n 'ff'.repeat(56) + 'ecec4cbdb89c188b', // encrypted part with dcId = 10001\n )\n })\n\n it('should correctly generate random initial payload for media dc', async () => {\n const random = 'ff'.repeat(64)\n const proxy: MtProxyInfo = {\n dcId: 1,\n secret: new Uint8Array(16),\n test: false,\n media: true,\n }\n const [codec] = await create(random, proxy)\n\n const tag = await codec.tag()\n\n expect(hexEncode(tag)).toEqual(\n 'ff'.repeat(56) + 'ecec4cbd5644188b', // encrypted part with dcId = -1\n )\n })\n })\n\n it.each([\n ['ef'],\n ['48454144'],\n ['504f5354'],\n ['47455420'],\n ['4f505449'],\n ['dddddddd'],\n ['eeeeeeee'],\n ['16030102'],\n ])('should correctly retry for %s prefix', async (prefix) => {\n const random = prefix + 'ff'.repeat(64 - prefix.length / 2)\n const [codec] = await create(random)\n\n // generating random payload requires 64 bytes of entropy, so\n // if it asks for more, it means it tried to generate it again\n await expect(() => codec.tag()).rejects.toThrow('not enough entropy')\n })\n })\n\n it('should correctly create aes ctr', async () => {\n const [codec, crypto] = await create()\n\n const spyCreateAesCtr = vi.spyOn(crypto, 'createAesCtr')\n\n await codec.tag()\n\n expect(spyCreateAesCtr).toHaveBeenCalledTimes(2)\n expect(spyCreateAesCtr).toHaveBeenNthCalledWith(\n 1,\n u8HexDecode('10b6b4ad6d56ef5df9453f88e6ee6adb6e0544ba635dc6a8a990c9b8b980c343'),\n u8HexDecode('936b33fa7f97bae025102532233abb26'),\n true,\n )\n expect(spyCreateAesCtr).toHaveBeenNthCalledWith(\n 2,\n u8HexDecode('26bb3a2332251025e0ba977ffa336b9343c380b9b8c990a9a8c65d63ba44056e'),\n u8HexDecode('db6aeee6883f45f95def566dadb4b610'),\n false,\n )\n })\n\n it('should correctly create aes ctr for mtproxy', async () => {\n const proxy: MtProxyInfo = {\n dcId: 1,\n secret: hexDecodeToBuffer('00112233445566778899aabbccddeeff'),\n test: true,\n media: false,\n }\n const [codec, crypto] = await create(undefined, proxy)\n\n const spyCreateAesCtr = vi.spyOn(crypto, 'createAesCtr')\n\n await codec.tag()\n\n expect(spyCreateAesCtr).toHaveBeenCalledTimes(2)\n expect(spyCreateAesCtr).toHaveBeenNthCalledWith(\n 1,\n hexDecodeToBuffer('dd03188944590983e28dad14d97d0952389d118af4ffcbdb28d56a6a612ef7a6'),\n u8HexDecode('936b33fa7f97bae025102532233abb26'),\n true,\n )\n expect(spyCreateAesCtr).toHaveBeenNthCalledWith(\n 2,\n hexDecodeToBuffer('413b8e08021fbb08a2962b6d7187194fe46565c6b329d3bbdfcffd4870c16119'),\n u8HexDecode('db6aeee6883f45f95def566dadb4b610'),\n false,\n )\n })\n\n it('should correctly encrypt the underlying codec', async () => {\n const data = hexDecodeToBuffer('6cfeffff')\n const msg1 = 'a1020630a410e940'\n const msg2 = 'f53ff53f371db495'\n\n const [codec] = await create()\n\n await codec.tag()\n\n expect(hexEncode(await codec.encode(data))).toEqual(msg1)\n expect(hexEncode(await codec.encode(data))).toEqual(msg2)\n })\n\n it('should correctly decrypt the underlying codec', async () => {\n const msg1 = 'e8027df708ab3b5c'\n const msg2 = '1854be76d2df4949'\n\n const [codec] = await create()\n\n await codec.tag()\n\n const log: string[] = []\n\n codec.on('error', (e: Error) => {\n log.push(e.toString())\n })\n\n codec.feed(hexDecodeToBuffer(msg1))\n codec.feed(hexDecodeToBuffer(msg2))\n\n await vi.waitFor(() => expect(log).toEqual(['Error: Transport error: 404', 'Error: Transport error: 404']))\n })\n\n it('should correctly reset', async () => {\n const inner = new IntermediatePacketCodec()\n const spyInnerReset = vi.spyOn(inner, 'reset')\n\n const codec = new ObfuscatedPacketCodec(inner)\n codec.setup(await defaultTestCryptoProvider(), new LogManager())\n\n await codec.tag()\n\n codec.reset()\n\n expect(spyInnerReset).toHaveBeenCalledTimes(1)\n })\n})\n"]}
@@ -97,10 +97,10 @@ export class BaseTcpTransport extends EventEmitter {
97
97
  .catch((err) => this.emit('error', err));
98
98
  }
99
99
  async send(bytes) {
100
+ const framed = await this._packetCodec.encode(bytes);
100
101
  if (this._state !== TransportState.Ready) {
101
102
  throw new MtcuteError('Transport is not READY');
102
103
  }
103
- const framed = await this._packetCodec.encode(bytes);
104
104
  return new Promise((resolve, reject) => {
105
105
  this._socket.write(framed, (error) => {
106
106
  if (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"tcp.js","sourceRoot":"","sources":["../../../../src/network/transports/tcp.ts"],"names":[],"mappings":"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","sourcesContent":["import EventEmitter from 'events'\nimport { connect, Socket } from 'net'\n\nimport { tl } from '@mtcute/tl'\n\nimport { MtcuteError } from '../../types/errors.js'\nimport { ICryptoProvider, Logger } from '../../utils/index.js'\nimport { IPacketCodec, ITelegramTransport, TransportState } from './abstract.js'\nimport { IntermediatePacketCodec } from './intermediate.js'\n\n/**\n * Base for TCP transports.\n * Subclasses must provide packet codec in `_packetCodec` property\n */\nexport abstract class BaseTcpTransport extends EventEmitter implements ITelegramTransport {\n protected _currentDc: tl.RawDcOption | null = null\n protected _state: TransportState = TransportState.Idle\n protected _socket: Socket | null = null\n\n abstract _packetCodec: IPacketCodec\n protected _crypto!: ICryptoProvider\n protected log!: Logger\n\n packetCodecInitialized = false\n\n private _updateLogPrefix() {\n if (this._currentDc) {\n this.log.prefix = `[TCP:${this._currentDc.ipAddress}:${this._currentDc.port}] `\n } else {\n this.log.prefix = '[TCP:disconnected] '\n }\n }\n\n setup(crypto: ICryptoProvider, log: Logger): void {\n this._crypto = crypto\n this.log = log.create('tcp')\n this._updateLogPrefix()\n }\n\n state(): TransportState {\n return this._state\n }\n\n currentDc(): tl.RawDcOption | null {\n return this._currentDc\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n connect(dc: tl.RawDcOption, testMode: boolean): void {\n if (this._state !== TransportState.Idle) {\n throw new MtcuteError('Transport is not IDLE')\n }\n\n if (!this.packetCodecInitialized) {\n this._packetCodec.setup?.(this._crypto, this.log)\n this._packetCodec.on('error', (err) => this.emit('error', err))\n this._packetCodec.on('packet', (buf) => this.emit('message', buf))\n this.packetCodecInitialized = true\n }\n\n this._state = TransportState.Connecting\n this._currentDc = dc\n this._updateLogPrefix()\n\n this.log.debug('connecting to %j', dc)\n\n this._socket = connect(dc.port, dc.ipAddress, this.handleConnect.bind(this))\n\n this._socket.on('data', (data) => {\n this._packetCodec.feed(data)\n })\n this._socket.on('error', this.handleError.bind(this))\n this._socket.on('close', this.close.bind(this))\n }\n\n close(): void {\n if (this._state === TransportState.Idle) return\n this.log.info('connection closed')\n\n this.emit('close')\n this._state = TransportState.Idle\n this._socket!.removeAllListeners()\n this._socket!.destroy()\n this._socket = null\n this._currentDc = null\n this._packetCodec.reset()\n }\n\n handleError(error: Error): void {\n this.log.error('error: %s', error.stack)\n this.emit('error', error)\n }\n\n handleConnect(): void {\n this.log.info('connected')\n\n Promise.resolve(this._packetCodec.tag())\n .then((initialMessage) => {\n if (initialMessage.length) {\n this._socket!.write(initialMessage, (err) => {\n if (err) {\n this.log.error('failed to write initial message: %s', err.stack)\n this.emit('error')\n this.close()\n } else {\n this._state = TransportState.Ready\n this.emit('ready')\n }\n })\n } else {\n this._state = TransportState.Ready\n this.emit('ready')\n }\n })\n .catch((err) => this.emit('error', err))\n }\n\n async send(bytes: Uint8Array): Promise<void> {\n if (this._state !== TransportState.Ready) {\n throw new MtcuteError('Transport is not READY')\n }\n\n const framed = await this._packetCodec.encode(bytes)\n\n return new Promise((resolve, reject) => {\n this._socket!.write(framed, (error) => {\n if (error) {\n reject(error)\n } else {\n resolve()\n }\n })\n })\n }\n}\n\nexport class TcpTransport extends BaseTcpTransport {\n _packetCodec = new IntermediatePacketCodec()\n}\n"]}
1
+ {"version":3,"file":"tcp.js","sourceRoot":"","sources":["../../../../src/network/transports/tcp.ts"],"names":[],"mappings":"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","sourcesContent":["import EventEmitter from 'events'\nimport { connect, Socket } from 'net'\n\nimport { tl } from '@mtcute/tl'\n\nimport { MtcuteError } from '../../types/errors.js'\nimport { ICryptoProvider, Logger } from '../../utils/index.js'\nimport { IPacketCodec, ITelegramTransport, TransportState } from './abstract.js'\nimport { IntermediatePacketCodec } from './intermediate.js'\n\n/**\n * Base for TCP transports.\n * Subclasses must provide packet codec in `_packetCodec` property\n */\nexport abstract class BaseTcpTransport extends EventEmitter implements ITelegramTransport {\n protected _currentDc: tl.RawDcOption | null = null\n protected _state: TransportState = TransportState.Idle\n protected _socket: Socket | null = null\n\n abstract _packetCodec: IPacketCodec\n protected _crypto!: ICryptoProvider\n protected log!: Logger\n\n packetCodecInitialized = false\n\n private _updateLogPrefix() {\n if (this._currentDc) {\n this.log.prefix = `[TCP:${this._currentDc.ipAddress}:${this._currentDc.port}] `\n } else {\n this.log.prefix = '[TCP:disconnected] '\n }\n }\n\n setup(crypto: ICryptoProvider, log: Logger): void {\n this._crypto = crypto\n this.log = log.create('tcp')\n this._updateLogPrefix()\n }\n\n state(): TransportState {\n return this._state\n }\n\n currentDc(): tl.RawDcOption | null {\n return this._currentDc\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n connect(dc: tl.RawDcOption, testMode: boolean): void {\n if (this._state !== TransportState.Idle) {\n throw new MtcuteError('Transport is not IDLE')\n }\n\n if (!this.packetCodecInitialized) {\n this._packetCodec.setup?.(this._crypto, this.log)\n this._packetCodec.on('error', (err) => this.emit('error', err))\n this._packetCodec.on('packet', (buf) => this.emit('message', buf))\n this.packetCodecInitialized = true\n }\n\n this._state = TransportState.Connecting\n this._currentDc = dc\n this._updateLogPrefix()\n\n this.log.debug('connecting to %j', dc)\n\n this._socket = connect(dc.port, dc.ipAddress, this.handleConnect.bind(this))\n\n this._socket.on('data', (data) => {\n this._packetCodec.feed(data)\n })\n this._socket.on('error', this.handleError.bind(this))\n this._socket.on('close', this.close.bind(this))\n }\n\n close(): void {\n if (this._state === TransportState.Idle) return\n this.log.info('connection closed')\n\n this.emit('close')\n this._state = TransportState.Idle\n this._socket!.removeAllListeners()\n this._socket!.destroy()\n this._socket = null\n this._currentDc = null\n this._packetCodec.reset()\n }\n\n handleError(error: Error): void {\n this.log.error('error: %s', error.stack)\n this.emit('error', error)\n }\n\n handleConnect(): void {\n this.log.info('connected')\n\n Promise.resolve(this._packetCodec.tag())\n .then((initialMessage) => {\n if (initialMessage.length) {\n this._socket!.write(initialMessage, (err) => {\n if (err) {\n this.log.error('failed to write initial message: %s', err.stack)\n this.emit('error')\n this.close()\n } else {\n this._state = TransportState.Ready\n this.emit('ready')\n }\n })\n } else {\n this._state = TransportState.Ready\n this.emit('ready')\n }\n })\n .catch((err) => this.emit('error', err))\n }\n\n async send(bytes: Uint8Array): Promise<void> {\n const framed = await this._packetCodec.encode(bytes)\n\n if (this._state !== TransportState.Ready) {\n throw new MtcuteError('Transport is not READY')\n }\n\n return new Promise((resolve, reject) => {\n this._socket!.write(framed, (error) => {\n if (error) {\n reject(error)\n } else {\n resolve()\n }\n })\n })\n }\n}\n\nexport class TcpTransport extends BaseTcpTransport {\n _packetCodec = new IntermediatePacketCodec()\n}\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,95 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { defaultTestCryptoProvider, u8HexDecode } from '@mtcute/test';
3
+ import { defaultProductionDc, hexDecodeToBuffer, LogManager } from '../../utils/index.js';
4
+ import { TransportState } from './abstract.js';
5
+ import { TcpTransport } from './tcp.js';
6
+ vi.mock('net', () => ({
7
+ connect: vi.fn().mockImplementation((port, ip, cb) => {
8
+ cb();
9
+ return {
10
+ on: vi.fn(),
11
+ write: vi.fn().mockImplementation((data, cb) => {
12
+ cb();
13
+ }),
14
+ end: vi.fn(),
15
+ removeAllListeners: vi.fn(),
16
+ destroy: vi.fn(),
17
+ };
18
+ }),
19
+ }));
20
+ describe('TcpTransport', async () => {
21
+ const net = await import('net');
22
+ const connect = vi.mocked(net.connect);
23
+ const getLastSocket = () => {
24
+ return connect.mock.results[connect.mock.results.length - 1].value;
25
+ };
26
+ const create = async () => {
27
+ const transport = new TcpTransport();
28
+ const logger = new LogManager();
29
+ logger.level = 0;
30
+ transport.setup(await defaultTestCryptoProvider(), logger);
31
+ return transport;
32
+ };
33
+ it('should initiate a tcp connection to the given dc', async () => {
34
+ const t = await create();
35
+ t.connect(defaultProductionDc.main, false);
36
+ expect(connect).toHaveBeenCalledOnce();
37
+ expect(connect).toHaveBeenCalledWith(defaultProductionDc.main.port, defaultProductionDc.main.ipAddress, expect.any(Function));
38
+ await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready));
39
+ });
40
+ it('should set up event handlers', async () => {
41
+ const t = await create();
42
+ t.connect(defaultProductionDc.main, false);
43
+ const socket = getLastSocket();
44
+ expect(socket.on).toHaveBeenCalledTimes(3);
45
+ expect(socket.on).toHaveBeenCalledWith('data', expect.any(Function));
46
+ expect(socket.on).toHaveBeenCalledWith('error', expect.any(Function));
47
+ expect(socket.on).toHaveBeenCalledWith('close', expect.any(Function));
48
+ });
49
+ it('should write packet codec tag once connected', async () => {
50
+ const t = await create();
51
+ t.connect(defaultProductionDc.main, false);
52
+ const socket = getLastSocket();
53
+ await vi.waitFor(() => expect(socket.write).toHaveBeenCalledWith(u8HexDecode('eeeeeeee'), // intermediate
54
+ expect.any(Function)));
55
+ });
56
+ it('should write to the underlying socket', async () => {
57
+ const t = await create();
58
+ t.connect(defaultProductionDc.main, false);
59
+ await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready));
60
+ await t.send(hexDecodeToBuffer('00010203040506070809'));
61
+ const socket = getLastSocket();
62
+ expect(socket.write).toHaveBeenCalledWith(u8HexDecode('0a00000000010203040506070809'), expect.any(Function));
63
+ });
64
+ it('should correctly close', async () => {
65
+ const t = await create();
66
+ t.connect(defaultProductionDc.main, false);
67
+ await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready));
68
+ t.close();
69
+ const socket = getLastSocket();
70
+ expect(socket.removeAllListeners).toHaveBeenCalledOnce();
71
+ expect(socket.destroy).toHaveBeenCalledOnce();
72
+ });
73
+ it('should feed data to the packet codec', async () => {
74
+ const t = await create();
75
+ const codec = t._packetCodec;
76
+ const spyFeed = vi.spyOn(codec, 'feed');
77
+ t.connect(defaultProductionDc.main, false);
78
+ await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready));
79
+ const socket = getLastSocket();
80
+ const onDataCall = socket.on.mock.calls.find((c) => c[0] === 'data');
81
+ onDataCall[1](u8HexDecode('00010203040506070809'));
82
+ expect(spyFeed).toHaveBeenCalledWith(u8HexDecode('00010203040506070809'));
83
+ });
84
+ it('should propagate errors', async () => {
85
+ const t = await create();
86
+ const spyEmit = vi.spyOn(t, 'emit').mockImplementation(() => true);
87
+ t.connect(defaultProductionDc.main, false);
88
+ await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready));
89
+ const socket = getLastSocket();
90
+ const onErrorCall = socket.on.mock.calls.find((c) => c[0] === 'error');
91
+ onErrorCall[1](new Error('test error'));
92
+ expect(spyEmit).toHaveBeenCalledWith('error', new Error('test error'));
93
+ });
94
+ });
95
+ //# sourceMappingURL=tcp.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tcp.test.js","sourceRoot":"","sources":["../../../../src/network/transports/tcp.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { Socket } from 'net'\nimport { describe, expect, it, MockedObject, vi } from 'vitest'\n\nimport { defaultTestCryptoProvider, u8HexDecode } from '@mtcute/test'\n\nimport { defaultProductionDc, hexDecodeToBuffer, LogManager } from '../../utils/index.js'\nimport { TransportState } from './abstract.js'\nimport { TcpTransport } from './tcp.js'\n\nvi.mock('net', () => ({\n connect: vi.fn().mockImplementation((port: number, ip: string, cb: () => void) => {\n cb()\n\n return {\n on: vi.fn(),\n write: vi.fn().mockImplementation((data: Uint8Array, cb: () => void) => {\n cb()\n }),\n end: vi.fn(),\n removeAllListeners: vi.fn(),\n destroy: vi.fn(),\n }\n }),\n}))\n\ndescribe('TcpTransport', async () => {\n const net = await import('net')\n const connect = vi.mocked(net.connect)\n\n const getLastSocket = () => {\n return connect.mock.results[connect.mock.results.length - 1].value as MockedObject<Socket>\n }\n\n const create = async () => {\n const transport = new TcpTransport()\n const logger = new LogManager()\n logger.level = 0\n transport.setup(await defaultTestCryptoProvider(), logger)\n\n return transport\n }\n\n it('should initiate a tcp connection to the given dc', async () => {\n const t = await create()\n\n t.connect(defaultProductionDc.main, false)\n\n expect(connect).toHaveBeenCalledOnce()\n expect(connect).toHaveBeenCalledWith(\n defaultProductionDc.main.port,\n defaultProductionDc.main.ipAddress,\n expect.any(Function),\n )\n await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready))\n })\n\n it('should set up event handlers', async () => {\n const t = await create()\n\n t.connect(defaultProductionDc.main, false)\n\n const socket = getLastSocket()\n\n expect(socket.on).toHaveBeenCalledTimes(3)\n expect(socket.on).toHaveBeenCalledWith('data', expect.any(Function))\n expect(socket.on).toHaveBeenCalledWith('error', expect.any(Function))\n expect(socket.on).toHaveBeenCalledWith('close', expect.any(Function))\n })\n\n it('should write packet codec tag once connected', async () => {\n const t = await create()\n\n t.connect(defaultProductionDc.main, false)\n\n const socket = getLastSocket()\n\n await vi.waitFor(() =>\n expect(socket.write).toHaveBeenCalledWith(\n u8HexDecode('eeeeeeee'), // intermediate\n expect.any(Function),\n ),\n )\n })\n\n it('should write to the underlying socket', async () => {\n const t = await create()\n\n t.connect(defaultProductionDc.main, false)\n await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready))\n\n await t.send(hexDecodeToBuffer('00010203040506070809'))\n\n const socket = getLastSocket()\n\n expect(socket.write).toHaveBeenCalledWith(u8HexDecode('0a00000000010203040506070809'), expect.any(Function))\n })\n\n it('should correctly close', async () => {\n const t = await create()\n\n t.connect(defaultProductionDc.main, false)\n await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready))\n\n t.close()\n\n const socket = getLastSocket()\n\n expect(socket.removeAllListeners).toHaveBeenCalledOnce()\n expect(socket.destroy).toHaveBeenCalledOnce()\n })\n\n it('should feed data to the packet codec', async () => {\n const t = await create()\n const codec = t._packetCodec\n\n const spyFeed = vi.spyOn(codec, 'feed')\n\n t.connect(defaultProductionDc.main, false)\n await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready))\n\n const socket = getLastSocket()\n\n const onDataCall = socket.on.mock.calls.find((c) => (c as string[])[0] === 'data') as unknown as [\n string,\n (data: Uint8Array) => void,\n ]\n onDataCall[1](u8HexDecode('00010203040506070809'))\n\n expect(spyFeed).toHaveBeenCalledWith(u8HexDecode('00010203040506070809'))\n })\n\n it('should propagate errors', async () => {\n const t = await create()\n\n const spyEmit = vi.spyOn(t, 'emit').mockImplementation(() => true)\n\n t.connect(defaultProductionDc.main, false)\n await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready))\n\n const socket = getLastSocket()\n\n const onErrorCall = socket.on.mock.calls.find((c) => (c as string[])[0] === 'error') as unknown as [\n string,\n (error: Error) => void,\n ]\n onErrorCall[1](new Error('test error'))\n\n expect(spyEmit).toHaveBeenCalledWith('error', new Error('test error'))\n })\n})\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,89 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { defaultTestCryptoProvider, u8HexDecode } from '@mtcute/test';
3
+ import { defaultProductionDc, hexDecodeToBuffer, LogManager } from '../../utils/index.js';
4
+ import { TransportState } from './abstract.js';
5
+ import { WebSocketTransport } from './websocket.js';
6
+ describe('WebSocketTransport', () => {
7
+ const create = async () => {
8
+ const fakeWs = vi.fn().mockImplementation(() => ({
9
+ addEventListener: vi.fn().mockImplementation((event, cb) => {
10
+ if (event === 'open') {
11
+ cb();
12
+ }
13
+ }),
14
+ removeEventListener: vi.fn(),
15
+ close: vi.fn(),
16
+ send: vi.fn(),
17
+ }));
18
+ const transport = new WebSocketTransport({ ws: fakeWs });
19
+ const logger = new LogManager();
20
+ logger.level = 0;
21
+ transport.setup(await defaultTestCryptoProvider(), logger);
22
+ return [transport, fakeWs];
23
+ };
24
+ const getLastSocket = (ws) => {
25
+ return ws.mock.results[ws.mock.results.length - 1].value;
26
+ };
27
+ it('should initiate a websocket connection to the given dc', async () => {
28
+ const [t, ws] = await create();
29
+ t.connect(defaultProductionDc.main, false);
30
+ expect(ws).toHaveBeenCalledOnce();
31
+ expect(ws).toHaveBeenCalledWith('wss://venus.web.telegram.org/apiws', 'binary');
32
+ await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready));
33
+ });
34
+ it('should set up event handlers', async () => {
35
+ const [t, ws] = await create();
36
+ t.connect(defaultProductionDc.main, false);
37
+ const socket = getLastSocket(ws);
38
+ expect(socket.addEventListener).toHaveBeenCalledWith('message', expect.any(Function));
39
+ expect(socket.addEventListener).toHaveBeenCalledWith('error', expect.any(Function));
40
+ expect(socket.addEventListener).toHaveBeenCalledWith('close', expect.any(Function));
41
+ });
42
+ it('should write packet codec tag to the socket', async () => {
43
+ const [t, ws] = await create();
44
+ t.connect(defaultProductionDc.main, false);
45
+ const socket = getLastSocket(ws);
46
+ await vi.waitFor(() => expect(socket.send).toHaveBeenCalledWith(u8HexDecode('29afd26df40fb8ed10b6b4ad6d56ef5df9453f88e6ee6adb6e0544ba635dc6a8a990c9b8b980c343936b33fa7f97bae025102532233abb26d4a1fe6d34f1ba08')));
47
+ });
48
+ it('should write to the underlying socket', async () => {
49
+ const [t, ws] = await create();
50
+ t.connect(defaultProductionDc.main, false);
51
+ const socket = getLastSocket(ws);
52
+ await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready));
53
+ await t.send(hexDecodeToBuffer('00010203040506070809'));
54
+ expect(socket.send).toHaveBeenCalledWith(hexDecodeToBuffer('af020630c8ef14bcf53af33853ea'));
55
+ });
56
+ it('should correctly close', async () => {
57
+ const [t, ws] = await create();
58
+ t.connect(defaultProductionDc.main, false);
59
+ const socket = getLastSocket(ws);
60
+ await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready));
61
+ t.close();
62
+ expect(socket.removeEventListener).toHaveBeenCalled();
63
+ expect(socket.close).toHaveBeenCalled();
64
+ });
65
+ it('should correctly handle incoming messages', async () => {
66
+ const [t, ws] = await create();
67
+ const feedSpy = vi.spyOn(t._packetCodec, 'feed');
68
+ t.connect(defaultProductionDc.main, false);
69
+ const socket = getLastSocket(ws);
70
+ await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready));
71
+ const data = hexDecodeToBuffer('00010203040506070809');
72
+ const message = new MessageEvent('message', { data });
73
+ const onMessageCall = socket.addEventListener.mock.calls.find(([event]) => event === 'message');
74
+ onMessageCall[1](message);
75
+ expect(feedSpy).toHaveBeenCalledWith(u8HexDecode('00010203040506070809'));
76
+ });
77
+ it('should propagate errors', async () => {
78
+ const [t, ws] = await create();
79
+ const spyEmit = vi.spyOn(t, 'emit').mockImplementation(() => true);
80
+ t.connect(defaultProductionDc.main, false);
81
+ const socket = getLastSocket(ws);
82
+ await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready));
83
+ const error = new Error('test');
84
+ const onErrorCall = socket.addEventListener.mock.calls.find(([event]) => event === 'error');
85
+ onErrorCall[1]({ error });
86
+ expect(spyEmit).toHaveBeenCalledWith('error', error);
87
+ });
88
+ });
89
+ //# sourceMappingURL=websocket.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket.test.js","sourceRoot":"","sources":["../../../../src/network/transports/websocket.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAsB,EAAE,EAAE,MAAM,QAAQ,CAAA;AAErE,OAAO,EAAE,yBAAyB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAErE,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACzF,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AAEnD,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAChC,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE;QACtB,MAAM,MAAM,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,GAAG,EAAE,CAAC,CAAC;YAC7C,gBAAgB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,CAAC,KAAa,EAAE,EAAc,EAAE,EAAE;gBAC3E,IAAI,KAAK,KAAK,MAAM,EAAE;oBAClB,EAAE,EAAE,CAAA;iBACP;YACL,CAAC,CAAC;YACF,mBAAmB,EAAE,EAAE,CAAC,EAAE,EAAE;YAC5B,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE;YACd,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE;SAChB,CAAC,CAAC,CAAA;QAEH,MAAM,SAAS,GAAG,IAAI,kBAAkB,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAA;QACxD,MAAM,MAAM,GAAG,IAAI,UAAU,EAAE,CAAA;QAC/B,MAAM,CAAC,KAAK,GAAG,CAAC,CAAA;QAChB,SAAS,CAAC,KAAK,CAAC,MAAM,yBAAyB,EAAE,EAAE,MAAM,CAAC,CAAA;QAE1D,OAAO,CAAC,SAAS,EAAE,MAAM,CAAU,CAAA;IACvC,CAAC,CAAA;IAED,MAAM,aAAa,GAAG,CAAC,EAAQ,EAAE,EAAE;QAC/B,OAAO,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,KAAgC,CAAA;IACvF,CAAC,CAAA;IAED,EAAE,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;QACpE,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,MAAM,MAAM,EAAE,CAAA;QAE9B,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QAE1C,MAAM,CAAC,EAAE,CAAC,CAAC,oBAAoB,EAAE,CAAA;QACjC,MAAM,CAAC,EAAE,CAAC,CAAC,oBAAoB,CAAC,oCAAoC,EAAE,QAAQ,CAAC,CAAA;QAC/E,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAA;IAC3E,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8BAA8B,EAAE,KAAK,IAAI,EAAE;QAC1C,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,MAAM,MAAM,EAAE,CAAA;QAE9B,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QAC1C,MAAM,MAAM,GAAG,aAAa,CAAC,EAAE,CAAC,CAAA;QAEhC,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,oBAAoB,CAAC,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAA;QACrF,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAA;QACnF,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAA;IACvF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QACzD,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,MAAM,MAAM,EAAE,CAAA;QAE9B,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QAC1C,MAAM,MAAM,GAAG,aAAa,CAAC,EAAE,CAAC,CAAA;QAEhC,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAClB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,oBAAoB,CACpC,WAAW,CACP,kIAAkI,CACrI,CACJ,CACJ,CAAA;IACL,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;QACnD,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,MAAM,MAAM,EAAE,CAAA;QAE9B,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QAC1C,MAAM,MAAM,GAAG,aAAa,CAAC,EAAE,CAAC,CAAA;QAChC,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAA;QAEvE,MAAM,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,sBAAsB,CAAC,CAAC,CAAA;QAEvD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,8BAA8B,CAAC,CAAC,CAAA;IAC/F,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wBAAwB,EAAE,KAAK,IAAI,EAAE;QACpC,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,MAAM,MAAM,EAAE,CAAA;QAE9B,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QAC1C,MAAM,MAAM,GAAG,aAAa,CAAC,EAAE,CAAC,CAAA;QAChC,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAA;QAEvE,CAAC,CAAC,KAAK,EAAE,CAAA;QAET,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,gBAAgB,EAAE,CAAA;QACrD,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,gBAAgB,EAAE,CAAA;IAC3C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACvD,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,MAAM,MAAM,EAAE,CAAA;QAE9B,MAAM,OAAO,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,EAAE,MAAM,CAAC,CAAA;QAEhD,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QAC1C,MAAM,MAAM,GAAG,aAAa,CAAC,EAAE,CAAC,CAAA;QAChC,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAA;QAEvE,MAAM,IAAI,GAAG,iBAAiB,CAAC,sBAAsB,CAAC,CAAA;QACtD,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;QAErD,MAAM,aAAa,GAAG,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,KAAK,SAAS,CAG7F,CAAA;QACD,aAAa,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAA;QAEzB,MAAM,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,WAAW,CAAC,sBAAsB,CAAC,CAAC,CAAA;IAC7E,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,yBAAyB,EAAE,KAAK,IAAI,EAAE;QACrC,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,MAAM,MAAM,EAAE,CAAA;QAE9B,MAAM,OAAO,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;QAElE,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QAC1C,MAAM,MAAM,GAAG,aAAa,CAAC,EAAE,CAAC,CAAA;QAChC,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAA;QAEvE,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,CAAA;QAC/B,MAAM,WAAW,GAAG,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,KAAK,OAAO,CAGzF,CAAA;QACD,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;QAEzB,MAAM,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;IACxD,CAAC,CAAC,CAAA;AACN,CAAC,CAAC,CAAA","sourcesContent":["import { describe, expect, it, Mock, MockedObject, vi } from 'vitest'\n\nimport { defaultTestCryptoProvider, u8HexDecode } from '@mtcute/test'\n\nimport { defaultProductionDc, hexDecodeToBuffer, LogManager } from '../../utils/index.js'\nimport { TransportState } from './abstract.js'\nimport { WebSocketTransport } from './websocket.js'\n\ndescribe('WebSocketTransport', () => {\n const create = async () => {\n const fakeWs = vi.fn().mockImplementation(() => ({\n addEventListener: vi.fn().mockImplementation((event: string, cb: () => void) => {\n if (event === 'open') {\n cb()\n }\n }),\n removeEventListener: vi.fn(),\n close: vi.fn(),\n send: vi.fn(),\n }))\n\n const transport = new WebSocketTransport({ ws: fakeWs })\n const logger = new LogManager()\n logger.level = 0\n transport.setup(await defaultTestCryptoProvider(), logger)\n\n return [transport, fakeWs] as const\n }\n\n const getLastSocket = (ws: Mock) => {\n return ws.mock.results[ws.mock.results.length - 1].value as MockedObject<WebSocket>\n }\n\n it('should initiate a websocket connection to the given dc', async () => {\n const [t, ws] = await create()\n\n t.connect(defaultProductionDc.main, false)\n\n expect(ws).toHaveBeenCalledOnce()\n expect(ws).toHaveBeenCalledWith('wss://venus.web.telegram.org/apiws', 'binary')\n await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready))\n })\n\n it('should set up event handlers', async () => {\n const [t, ws] = await create()\n\n t.connect(defaultProductionDc.main, false)\n const socket = getLastSocket(ws)\n\n expect(socket.addEventListener).toHaveBeenCalledWith('message', expect.any(Function))\n expect(socket.addEventListener).toHaveBeenCalledWith('error', expect.any(Function))\n expect(socket.addEventListener).toHaveBeenCalledWith('close', expect.any(Function))\n })\n\n it('should write packet codec tag to the socket', async () => {\n const [t, ws] = await create()\n\n t.connect(defaultProductionDc.main, false)\n const socket = getLastSocket(ws)\n\n await vi.waitFor(() =>\n expect(socket.send).toHaveBeenCalledWith(\n u8HexDecode(\n '29afd26df40fb8ed10b6b4ad6d56ef5df9453f88e6ee6adb6e0544ba635dc6a8a990c9b8b980c343936b33fa7f97bae025102532233abb26d4a1fe6d34f1ba08',\n ),\n ),\n )\n })\n\n it('should write to the underlying socket', async () => {\n const [t, ws] = await create()\n\n t.connect(defaultProductionDc.main, false)\n const socket = getLastSocket(ws)\n await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready))\n\n await t.send(hexDecodeToBuffer('00010203040506070809'))\n\n expect(socket.send).toHaveBeenCalledWith(hexDecodeToBuffer('af020630c8ef14bcf53af33853ea'))\n })\n\n it('should correctly close', async () => {\n const [t, ws] = await create()\n\n t.connect(defaultProductionDc.main, false)\n const socket = getLastSocket(ws)\n await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready))\n\n t.close()\n\n expect(socket.removeEventListener).toHaveBeenCalled()\n expect(socket.close).toHaveBeenCalled()\n })\n\n it('should correctly handle incoming messages', async () => {\n const [t, ws] = await create()\n\n const feedSpy = vi.spyOn(t._packetCodec, 'feed')\n\n t.connect(defaultProductionDc.main, false)\n const socket = getLastSocket(ws)\n await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready))\n\n const data = hexDecodeToBuffer('00010203040506070809')\n const message = new MessageEvent('message', { data })\n\n const onMessageCall = socket.addEventListener.mock.calls.find(([event]) => event === 'message') as unknown as [\n string,\n (evt: MessageEvent) => void,\n ]\n onMessageCall[1](message)\n\n expect(feedSpy).toHaveBeenCalledWith(u8HexDecode('00010203040506070809'))\n })\n\n it('should propagate errors', async () => {\n const [t, ws] = await create()\n\n const spyEmit = vi.spyOn(t, 'emit').mockImplementation(() => true)\n\n t.connect(defaultProductionDc.main, false)\n const socket = getLastSocket(ws)\n await vi.waitFor(() => expect(t.state()).toEqual(TransportState.Ready))\n\n const error = new Error('test')\n const onErrorCall = socket.addEventListener.mock.calls.find(([event]) => event === 'error') as unknown as [\n string,\n (evt: { error: Error }) => void,\n ]\n onErrorCall[1]({ error })\n\n expect(spyEmit).toHaveBeenCalledWith('error', error)\n })\n})\n"]}
@@ -0,0 +1 @@
1
+ export {};