@mtkruto/browser 0.131.0 → 0.132.1

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 (139) hide show
  1. package/esm/0_deps.d.ts +2 -2
  2. package/esm/0_deps.d.ts.map +1 -1
  3. package/esm/0_deps.js +2 -2
  4. package/esm/2_connection.d.ts +2 -0
  5. package/esm/2_connection.d.ts.map +1 -1
  6. package/esm/2_connection.js +2 -0
  7. package/esm/3_transport.d.ts +1 -0
  8. package/esm/3_transport.d.ts.map +1 -1
  9. package/esm/3_transport.js +1 -0
  10. package/esm/3_types.d.ts +4 -0
  11. package/esm/3_types.d.ts.map +1 -1
  12. package/esm/3_types.js +4 -0
  13. package/esm/client/0_params.d.ts +16 -0
  14. package/esm/client/0_params.d.ts.map +1 -1
  15. package/esm/client/1_client_generic.d.ts +26 -5
  16. package/esm/client/1_client_generic.d.ts.map +1 -1
  17. package/esm/client/2_payment_manager.d.ts +4 -1
  18. package/esm/client/2_payment_manager.d.ts.map +1 -1
  19. package/esm/client/2_payment_manager.js +33 -1
  20. package/esm/client/6_client.d.ts +26 -5
  21. package/esm/client/6_client.d.ts.map +1 -1
  22. package/esm/client/6_client.js +30 -3
  23. package/esm/client/6_client_dispatcher.d.ts +26 -5
  24. package/esm/client/6_client_dispatcher.d.ts.map +1 -1
  25. package/esm/client/6_client_dispatcher.js +30 -3
  26. package/esm/connection/0_get_tls_header.d.ts +2 -0
  27. package/esm/connection/0_get_tls_header.d.ts.map +1 -0
  28. package/esm/connection/0_get_tls_header.js +151 -0
  29. package/esm/connection/1_connection_tcp.d.ts.map +1 -1
  30. package/esm/connection/1_connection_tcp.js +21 -52
  31. package/esm/connection/1_connection_tls.d.ts +33 -0
  32. package/esm/connection/1_connection_tls.d.ts.map +1 -0
  33. package/esm/connection/1_connection_tls.js +203 -0
  34. package/esm/deps/jsr.io/@std/io/0.225.3/write_all.d.ts +52 -0
  35. package/esm/deps/jsr.io/@std/io/0.225.3/write_all.d.ts.map +1 -0
  36. package/esm/deps/jsr.io/@std/io/0.225.3/write_all.js +61 -0
  37. package/esm/session/2_session_encrypted.d.ts.map +1 -1
  38. package/esm/session/2_session_encrypted.js +4 -1
  39. package/esm/transport/0_obfuscation.d.ts +5 -1
  40. package/esm/transport/0_obfuscation.d.ts.map +1 -1
  41. package/esm/transport/0_obfuscation.js +17 -4
  42. package/esm/transport/1_transport_intermediate.d.ts +7 -1
  43. package/esm/transport/1_transport_intermediate.d.ts.map +1 -1
  44. package/esm/transport/1_transport_intermediate.js +17 -7
  45. package/esm/transport/2_transport_provider_mtproxy.d.ts +23 -0
  46. package/esm/transport/2_transport_provider_mtproxy.d.ts.map +1 -0
  47. package/esm/transport/2_transport_provider_mtproxy.js +51 -0
  48. package/esm/transport/2_transport_provider_web_socket.js +1 -1
  49. package/esm/types/0_star_amount.d.ts +29 -0
  50. package/esm/types/0_star_amount.d.ts.map +1 -0
  51. package/esm/types/0_star_amount.js +25 -0
  52. package/esm/types/2_star_transaction_peer.d.ts +66 -0
  53. package/esm/types/2_star_transaction_peer.d.ts.map +1 -0
  54. package/esm/types/2_star_transaction_peer.js +45 -0
  55. package/esm/types/5_star_transaction.d.ts +64 -0
  56. package/esm/types/5_star_transaction.d.ts.map +1 -0
  57. package/esm/types/5_star_transaction.js +71 -0
  58. package/esm/types/6_star_transaction_list.d.ts +31 -0
  59. package/esm/types/6_star_transaction_list.d.ts.map +1 -0
  60. package/esm/types/6_star_transaction_list.js +28 -0
  61. package/esm/utilities/1_crypto.d.ts +1 -0
  62. package/esm/utilities/1_crypto.d.ts.map +1 -1
  63. package/esm/utilities/1_crypto.js +4 -0
  64. package/package.json +1 -1
  65. package/script/0_deps.d.ts +2 -2
  66. package/script/0_deps.d.ts.map +1 -1
  67. package/script/0_deps.js +4 -3
  68. package/script/2_connection.d.ts +2 -0
  69. package/script/2_connection.d.ts.map +1 -1
  70. package/script/2_connection.js +2 -0
  71. package/script/3_transport.d.ts +1 -0
  72. package/script/3_transport.d.ts.map +1 -1
  73. package/script/3_transport.js +1 -0
  74. package/script/3_types.d.ts +4 -0
  75. package/script/3_types.d.ts.map +1 -1
  76. package/script/3_types.js +4 -0
  77. package/script/client/0_params.d.ts +16 -0
  78. package/script/client/0_params.d.ts.map +1 -1
  79. package/script/client/1_client_generic.d.ts +26 -5
  80. package/script/client/1_client_generic.d.ts.map +1 -1
  81. package/script/client/2_payment_manager.d.ts +4 -1
  82. package/script/client/2_payment_manager.d.ts.map +1 -1
  83. package/script/client/2_payment_manager.js +32 -0
  84. package/script/client/6_client.d.ts +26 -5
  85. package/script/client/6_client.d.ts.map +1 -1
  86. package/script/client/6_client.js +30 -3
  87. package/script/client/6_client_dispatcher.d.ts +26 -5
  88. package/script/client/6_client_dispatcher.d.ts.map +1 -1
  89. package/script/client/6_client_dispatcher.js +30 -3
  90. package/script/connection/0_get_tls_header.d.ts +2 -0
  91. package/script/connection/0_get_tls_header.d.ts.map +1 -0
  92. package/script/connection/0_get_tls_header.js +154 -0
  93. package/script/connection/1_connection_tcp.d.ts.map +1 -1
  94. package/script/connection/1_connection_tcp.js +21 -52
  95. package/script/connection/1_connection_tls.d.ts +33 -0
  96. package/script/connection/1_connection_tls.d.ts.map +1 -0
  97. package/script/connection/1_connection_tls.js +207 -0
  98. package/script/deps/jsr.io/@std/io/0.225.3/write_all.d.ts +52 -0
  99. package/script/deps/jsr.io/@std/io/0.225.3/write_all.d.ts.map +1 -0
  100. package/script/deps/jsr.io/@std/io/0.225.3/write_all.js +65 -0
  101. package/script/session/2_session_encrypted.d.ts.map +1 -1
  102. package/script/session/2_session_encrypted.js +4 -1
  103. package/script/transport/0_obfuscation.d.ts +5 -1
  104. package/script/transport/0_obfuscation.d.ts.map +1 -1
  105. package/script/transport/0_obfuscation.js +16 -3
  106. package/script/transport/1_transport_intermediate.d.ts +7 -1
  107. package/script/transport/1_transport_intermediate.d.ts.map +1 -1
  108. package/script/transport/1_transport_intermediate.js +16 -6
  109. package/script/transport/2_transport_provider_mtproxy.d.ts +23 -0
  110. package/script/transport/2_transport_provider_mtproxy.d.ts.map +1 -0
  111. package/script/transport/2_transport_provider_mtproxy.js +54 -0
  112. package/script/transport/2_transport_provider_web_socket.js +1 -1
  113. package/script/types/0_star_amount.d.ts +29 -0
  114. package/script/types/0_star_amount.d.ts.map +1 -0
  115. package/script/types/0_star_amount.js +28 -0
  116. package/script/types/2_star_transaction_peer.d.ts +66 -0
  117. package/script/types/2_star_transaction_peer.d.ts.map +1 -0
  118. package/script/types/2_star_transaction_peer.js +48 -0
  119. package/script/types/5_star_transaction.d.ts +64 -0
  120. package/script/types/5_star_transaction.d.ts.map +1 -0
  121. package/script/types/5_star_transaction.js +74 -0
  122. package/script/types/6_star_transaction_list.d.ts +31 -0
  123. package/script/types/6_star_transaction_list.d.ts.map +1 -0
  124. package/script/types/6_star_transaction_list.js +31 -0
  125. package/script/utilities/1_crypto.d.ts +1 -0
  126. package/script/utilities/1_crypto.d.ts.map +1 -1
  127. package/script/utilities/1_crypto.js +5 -0
  128. package/esm/deps/jsr.io/@std/io/0.225.3/_constants.d.ts +0 -3
  129. package/esm/deps/jsr.io/@std/io/0.225.3/_constants.d.ts.map +0 -1
  130. package/esm/deps/jsr.io/@std/io/0.225.3/_constants.js +0 -4
  131. package/esm/deps/jsr.io/@std/io/0.225.3/iterate_reader.d.ts +0 -80
  132. package/esm/deps/jsr.io/@std/io/0.225.3/iterate_reader.d.ts.map +0 -1
  133. package/esm/deps/jsr.io/@std/io/0.225.3/iterate_reader.js +0 -96
  134. package/script/deps/jsr.io/@std/io/0.225.3/_constants.d.ts +0 -3
  135. package/script/deps/jsr.io/@std/io/0.225.3/_constants.d.ts.map +0 -1
  136. package/script/deps/jsr.io/@std/io/0.225.3/_constants.js +0 -7
  137. package/script/deps/jsr.io/@std/io/0.225.3/iterate_reader.d.ts +0 -80
  138. package/script/deps/jsr.io/@std/io/0.225.3/iterate_reader.d.ts.map +0 -1
  139. package/script/deps/jsr.io/@std/io/0.225.3/iterate_reader.js +0 -100
@@ -0,0 +1,151 @@
1
+ import { concat, decodeHex } from "../0_deps.js";
2
+ import { hmacSha256, intFromBytes, intToBytes, modExp } from "../1_utilities.js";
3
+ export async function getTlsHeader(secret) {
4
+ const array = serializeOps(ops, secret.slice(16));
5
+ secret = secret.slice(0, 16);
6
+ secret = await hmacSha256(array, secret);
7
+ array.set(secret.slice(0), 11);
8
+ const dataView = new DataView(array.buffer);
9
+ const old = dataView.getInt32(39, true);
10
+ dataView.setInt32(39, old ^ Math.floor(Date.now() / 1000), true);
11
+ return array;
12
+ }
13
+ const ops = [
14
+ { type: "string", data: new Uint8Array([0x16, 0x03, 0x01, 0x02, 0x00, 0x01, 0x00, 0x01, 0xfc, 0x03, 0x03]) },
15
+ { type: "zero", length: 32 },
16
+ { type: "string", data: new Uint8Array([0x20]) },
17
+ { type: "random", length: 32 },
18
+ { type: "string", data: new Uint8Array([0x00, 0x2a]) },
19
+ { type: "grease", seed: 0 },
20
+ { type: "string", data: new Uint8Array([0x13, 0x01, 0x13, 0x02, 0x13, 0x03, 0xc0, 0x2c, 0xc0, 0x2b, 0xcc, 0xa9, 0xc0, 0x30, 0xc0, 0x2f, 0xcc, 0xa8, 0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x14, 0xc0, 0x13, 0x00, 0x9d, 0x00, 0x9c, 0x00, 0x35, 0x00, 0x2f, 0xc0, 0x08, 0xc0, 0x12, 0x00, 0x0a, 0x01, 0x00, 0x01, 0x89]) },
21
+ { type: "grease", seed: 2 },
22
+ { type: "string", data: new Uint8Array([0x00, 0x00, 0x00, 0x00]) },
23
+ { type: "beginScope" },
24
+ { type: "beginScope" },
25
+ { type: "string", data: new Uint8Array([0x00]) },
26
+ { type: "beginScope" },
27
+ { type: "domain" },
28
+ { type: "endScope" },
29
+ { type: "endScope" },
30
+ { type: "endScope" },
31
+ { type: "string", data: new Uint8Array([0x00, 0x17, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x0a]) },
32
+ { type: "grease", seed: 4 },
33
+ { type: "string", data: new Uint8Array([0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x10, 0x00, 0x0e, 0x00, 0x0c, 0x02, 0x68, 0x32, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x16, 0x00, 0x14, 0x04, 0x03, 0x08, 0x04, 0x04, 0x01, 0x05, 0x03, 0x08, 0x05, 0x08, 0x05, 0x05, 0x01, 0x08, 0x06, 0x06, 0x01, 0x02, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00, 0x33, 0x00, 0x2b, 0x00, 0x29]) },
34
+ { type: "grease", seed: 4 },
35
+ { type: "string", data: new Uint8Array([0x00, 0x01, 0x00, 0x00, 0x1d, 0x00, 0x20]) },
36
+ { type: "key" },
37
+ { type: "string", data: new Uint8Array([0x00, 0x2d, 0x00, 0x02, 0x01, 0x01, 0x00, 0x2b, 0x00, 0x0b, 0x0a]) },
38
+ { type: "grease", seed: 6 },
39
+ { type: "string", data: new Uint8Array([0x03, 0x04, 0x03, 0x03, 0x03, 0x02, 0x03, 0x01, 0x00, 0x1b, 0x00, 0x03, 0x02, 0x00, 0x01]) },
40
+ { type: "grease", seed: 3 },
41
+ { type: "string", data: new Uint8Array([0x00, 0x01, 0x00]) },
42
+ { type: "padding" },
43
+ ];
44
+ function getGrease() {
45
+ const res = crypto.getRandomValues(new Uint8Array(7));
46
+ for (let i = 0; i < res.length; ++i) {
47
+ res[i] = (res[i] & 0xF0) + 0x0A;
48
+ }
49
+ for (let i = 1; i < res.length; i += 2) {
50
+ if (res[i] === res[i - 1]) {
51
+ res[i] ^= 0x10;
52
+ }
53
+ }
54
+ return res;
55
+ }
56
+ function getY2(x, mod) {
57
+ let y = (x + 486662n) % mod;
58
+ y = y * x % mod;
59
+ y = (y + 1n) % mod;
60
+ return y * x % mod;
61
+ }
62
+ function getDoubleX(x, mod) {
63
+ const y2 = getY2(x, mod);
64
+ const denominator = (4n * y2) % mod;
65
+ let numerator = (x * x % mod - 1n + mod) % mod;
66
+ numerator = (numerator * numerator) % mod;
67
+ const denominatorInv = modExp(denominator, mod - 2n, mod);
68
+ numerator = (numerator * denominatorInv) % mod;
69
+ return numerator;
70
+ }
71
+ function isQuadraticResidue(a) {
72
+ const mod = 2n ** 255n - 19n;
73
+ const pow = 2n ** 254n - 10n;
74
+ const r = modExp(a, pow, mod);
75
+ return r === 1n;
76
+ }
77
+ function serializeOps(ops, domain) {
78
+ const GREASE = getGrease();
79
+ let buffer = new Uint8Array();
80
+ const scopes = new Array();
81
+ function serializeOp(op) {
82
+ switch (op.type) {
83
+ case "string":
84
+ buffer = concat([buffer, op.data]);
85
+ break;
86
+ case "random":
87
+ buffer = concat([
88
+ buffer,
89
+ crypto.getRandomValues(new Uint8Array(op.length)),
90
+ ]);
91
+ break;
92
+ case "zero":
93
+ buffer = concat([buffer, new Uint8Array(op.length)]);
94
+ break;
95
+ case "domain":
96
+ buffer = concat([buffer, domain]);
97
+ break;
98
+ case "grease": {
99
+ const grease = GREASE[op.seed];
100
+ buffer = concat([buffer, new Uint8Array([grease, grease])]);
101
+ break;
102
+ }
103
+ case "key": {
104
+ const mod = intFromBytes(decodeHex("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"), { byteOrder: "big", isSigned: false });
105
+ let key = new Uint8Array(32);
106
+ while (true) {
107
+ crypto.getRandomValues(key);
108
+ key[31] &= 127;
109
+ let x = intFromBytes(key, { byteOrder: "big", isSigned: false });
110
+ const y = getY2(x, mod);
111
+ if (isQuadraticResidue(y)) {
112
+ for (let i = 0; i < 3; ++i) {
113
+ x = getDoubleX(x, mod);
114
+ }
115
+ key = intToBytes(x, 32, { byteOrder: "little", isSigned: false });
116
+ break;
117
+ }
118
+ }
119
+ buffer = concat([buffer, key]);
120
+ break;
121
+ }
122
+ case "beginScope":
123
+ scopes.push(buffer.length);
124
+ buffer = concat([buffer, new Uint8Array([0, 0])]);
125
+ break;
126
+ case "endScope": {
127
+ const beginOffset = scopes.pop();
128
+ if (beginOffset === undefined) {
129
+ throw new TypeError("Invalid endScope");
130
+ }
131
+ const endOffset = buffer.length;
132
+ const size = endOffset - beginOffset - 2;
133
+ new DataView(buffer.buffer).setUint16(beginOffset, size);
134
+ break;
135
+ }
136
+ case "padding": {
137
+ const size = 513 - buffer.length;
138
+ if (size > 0) {
139
+ serializeOp({ type: "string", data: new Uint8Array([0x00, 0x15]) });
140
+ serializeOp({ type: "beginScope" });
141
+ serializeOp({ type: "zero", length: size });
142
+ serializeOp({ type: "endScope" });
143
+ }
144
+ }
145
+ }
146
+ }
147
+ for (const op of ops) {
148
+ serializeOp(op);
149
+ }
150
+ return buffer;
151
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"1_connection_tcp.d.ts","sourceRoot":"","sources":["../../src/connection/1_connection_tcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAIpD,qBAAa,aAAc,YAAW,UAAU;;IAU9C,OAAO,EAAE,OAAO,IAAI,CAAC,OAAO,CAAgB;IAC5C,kBAAkB,CAAC,EAAE,UAAU,CAAC,oBAAoB,CAAC,CAAC;IACtD,QAAQ,CAAC,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC;gBAEtB,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAK1C,IAAI,WAAW,IAAI,OAAO,CAEzB;IAQK,IAAI;IAiDJ,IAAI,CAAC,CAAC,EAAE,UAAU;IAgBlB,KAAK,CAAC,CAAC,EAAE,UAAU;IA4BzB,KAAK;CAON"}
1
+ {"version":3,"file":"1_connection_tcp.d.ts","sourceRoot":"","sources":["../../src/connection/1_connection_tcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAIpD,qBAAa,aAAc,YAAW,UAAU;;IAQ9C,OAAO,EAAE,OAAO,IAAI,CAAC,OAAO,CAAgB;IAC5C,kBAAkB,CAAC,EAAE,UAAU,CAAC,oBAAoB,CAAC,CAAC;IACtD,QAAQ,CAAC,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC;gBAEtB,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAK1C,IAAI,WAAW,IAAI,OAAO,CAGzB;IAQK,IAAI;IAiBJ,IAAI,CAAC,CAAC,EAAE,UAAU;IAyBlB,KAAK,CAAC,CAAC,EAAE,UAAU;IAsBzB,KAAK;CAMN"}
@@ -17,7 +17,6 @@
17
17
  * You should have received a copy of the GNU Lesser General Public License
18
18
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
19
19
  */
20
- import { concat, iterateReader } from "../0_deps.js";
21
20
  import { ConnectionError } from "../0_errors.js";
22
21
  import { getLogger, Mutex } from "../1_utilities.js";
23
22
  const L = getLogger("ConnectionTCP");
@@ -27,8 +26,6 @@ export class ConnectionTCP {
27
26
  #connection;
28
27
  #rMutex = new Mutex();
29
28
  #wMutex = new Mutex();
30
- #buffer = new Uint8Array();
31
- #nextResolve = null;
32
29
  #canRead = false;
33
30
  #canWrite = false;
34
31
  connect = Deno.connect;
@@ -39,6 +36,7 @@ export class ConnectionTCP {
39
36
  this.#port = port;
40
37
  }
41
38
  get isConnected() {
39
+ Deno.errors.BrokenPipe;
42
40
  return !!this.#connection && this.#canRead && this.#canWrite;
43
41
  }
44
42
  #assertConnected() {
@@ -59,48 +57,27 @@ export class ConnectionTCP {
59
57
  this.#canRead = this.#canWrite = true;
60
58
  this.stateChangeHandler?.(true);
61
59
  L.debug("connected to", this.#hostname, "port", this.#port);
62
- Promise.resolve().then(async () => {
63
- do {
64
- try {
65
- for await (const chunk of iterateReader(connection)) {
66
- this.callback?.read(chunk.length);
67
- this.#buffer = concat([this.#buffer, chunk]);
68
- if (this.#nextResolve !== null && this.#buffer.length >= this.#nextResolve[0]) {
69
- this.#nextResolve[1].resolve();
70
- this.#nextResolve = null;
71
- }
72
- }
73
- this.#canRead = false;
74
- break;
75
- }
76
- catch (err) {
77
- this.#canRead = false;
78
- this.stateChangeHandler?.(false);
79
- this.#rejectRead();
80
- L.error(err);
81
- }
82
- } while (this.isConnected);
83
- this.stateChangeHandler?.(false);
84
- });
85
60
  this.#connection = connection;
86
61
  }
87
- #rejectRead() {
88
- if (this.#nextResolve !== null) {
89
- this.#nextResolve[1].reject(new ConnectionError("The connection was closed."));
90
- this.#nextResolve = null;
91
- }
92
- }
93
62
  async read(p) {
94
63
  this.#assertConnected();
95
64
  const unlock = await this.#rMutex.lock();
65
+ let offset = 0;
96
66
  try {
97
- this.#assertConnected();
98
- if (this.#buffer.length < p.length) {
99
- await new Promise((resolve, reject) => this.#nextResolve = [p.length, { resolve, reject }]);
100
- }
101
- const slice = this.#buffer.slice(0, p.length);
102
- p.set(slice);
103
- this.#buffer = this.#buffer.slice(slice.length);
67
+ do {
68
+ const read = await this.#connection.read(p.subarray(offset));
69
+ if (read === null) {
70
+ this.#canRead = false;
71
+ this.stateChangeHandler?.(false);
72
+ throw new ConnectionError("The connection was closed.");
73
+ }
74
+ offset += read;
75
+ } while (offset < p.byteLength);
76
+ }
77
+ catch {
78
+ this.#canRead = false;
79
+ this.stateChangeHandler?.(false);
80
+ throw new ConnectionError("The connection was closed.");
104
81
  }
105
82
  finally {
106
83
  unlock();
@@ -112,23 +89,16 @@ export class ConnectionTCP {
112
89
  try {
113
90
  this.#assertConnected();
114
91
  let written = 0;
115
- while (written < p.length) {
92
+ while (written < p.byteLength) {
116
93
  try {
117
94
  const wrote = await this.#connection.write(p.subarray(written));
118
95
  this.callback?.write(wrote);
119
96
  written += wrote;
120
97
  }
121
- catch (err) {
122
- if (err instanceof Deno.errors.BrokenPipe || err instanceof Deno.errors.ConnectionReset) {
123
- this.#canWrite = false;
124
- }
125
- if (!this.isConnected) {
126
- this.stateChangeHandler?.(false);
127
- throw new ConnectionError("The connection was closed.");
128
- }
129
- else {
130
- throw err;
131
- }
98
+ catch {
99
+ this.#canWrite = false;
100
+ this.stateChangeHandler?.(false);
101
+ throw new ConnectionError("The connection was closed.");
132
102
  }
133
103
  }
134
104
  }
@@ -141,6 +111,5 @@ export class ConnectionTCP {
141
111
  this.#connection.close();
142
112
  this.#canRead = this.#canWrite = false;
143
113
  this.#connection = undefined;
144
- this.#rejectRead();
145
114
  }
146
115
  }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * MTKruto - Cross-runtime JavaScript library for building Telegram clients
3
+ * Copyright (C) 2023-2026 Roj <https://roj.im/>
4
+ *
5
+ * This file is part of MTKruto.
6
+ *
7
+ * This program is free software: you can redistribute it and/or modify
8
+ * it under the terms of the GNU Lesser General Public License as published by
9
+ * the Free Software Foundation, either version 3 of the License, or
10
+ * (at your option) any later version.
11
+ *
12
+ * This program is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ * GNU Lesser General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public License
18
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
19
+ */
20
+ import type { Connection } from "./0_connection.js";
21
+ export declare class ConnectionTLS implements Connection {
22
+ #private;
23
+ connect: typeof Deno.connect;
24
+ stateChangeHandler?: Connection["stateChangeHandler"];
25
+ callback?: Connection["callback"];
26
+ constructor(hostname: string, port: number, secret: Uint8Array<ArrayBuffer>);
27
+ get isConnected(): boolean;
28
+ open(): Promise<void>;
29
+ read(p: Uint8Array): Promise<void>;
30
+ write(p: Uint8Array): Promise<void>;
31
+ close(): void;
32
+ }
33
+ //# sourceMappingURL=1_connection_tls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"1_connection_tls.d.ts","sourceRoot":"","sources":["../../src/connection/1_connection_tls.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAQpD,qBAAa,aAAc,YAAW,UAAU;;IAW9C,OAAO,EAAE,OAAO,IAAI,CAAC,OAAO,CAAgB;IAC5C,kBAAkB,CAAC,EAAE,UAAU,CAAC,oBAAoB,CAAC,CAAC;IACtD,QAAQ,CAAC,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC;gBAEtB,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,WAAW,CAAC;IAM3E,IAAI,WAAW,IAAI,OAAO,CAEzB;IA+BK,IAAI;IAuGJ,IAAI,CAAC,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAclC,KAAK,CAAC,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBzC,KAAK;CAON"}
@@ -0,0 +1,203 @@
1
+ /**
2
+ * MTKruto - Cross-runtime JavaScript library for building Telegram clients
3
+ * Copyright (C) 2023-2026 Roj <https://roj.im/>
4
+ *
5
+ * This file is part of MTKruto.
6
+ *
7
+ * This program is free software: you can redistribute it and/or modify
8
+ * it under the terms of the GNU Lesser General Public License as published by
9
+ * the Free Software Foundation, either version 3 of the License, or
10
+ * (at your option) any later version.
11
+ *
12
+ * This program is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ * GNU Lesser General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public License
18
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
19
+ */
20
+ import { concat, equals, startsWith, writeAll } from "../0_deps.js";
21
+ import { ConnectionError } from "../0_errors.js";
22
+ import { getLogger, hmacSha256, Mutex } from "../1_utilities.js";
23
+ import { getTlsHeader } from "./0_get_tls_header.js";
24
+ const HEADER_LENGTH = 5;
25
+ const MAX_PACKET_LENGTH = 2878;
26
+ const L = getLogger("ConnectionTLS");
27
+ export class ConnectionTLS {
28
+ #hostname;
29
+ #port;
30
+ #secret;
31
+ #connection;
32
+ #rMutex = new Mutex();
33
+ #wMutex = new Mutex();
34
+ #buffer = new Uint8Array();
35
+ #canRead = false;
36
+ #canWrite = false;
37
+ #isFirstWrite = true;
38
+ connect = Deno.connect;
39
+ stateChangeHandler;
40
+ callback;
41
+ constructor(hostname, port, secret) {
42
+ this.#hostname = hostname;
43
+ this.#port = port;
44
+ this.#secret = (secret[0] === 0xDD || secret[0] === 0xEE) ? secret.slice(1) : secret;
45
+ }
46
+ get isConnected() {
47
+ return !!this.#connection && this.#canRead && this.#canWrite;
48
+ }
49
+ #assertConnected() {
50
+ if (!this.isConnected) {
51
+ throw new ConnectionError("The connection is not open.");
52
+ }
53
+ }
54
+ async #read(array) {
55
+ let offset = 0;
56
+ try {
57
+ while (offset < array.length) {
58
+ const n = await this.#connection.read(array.subarray(offset));
59
+ if (n === null) {
60
+ this.#canRead = false;
61
+ this.stateChangeHandler?.(false);
62
+ throw new ConnectionError("The connection is not open.");
63
+ }
64
+ if (n <= 0) {
65
+ continue;
66
+ }
67
+ this.callback?.read(n);
68
+ offset += n;
69
+ }
70
+ }
71
+ catch (err) {
72
+ this.stateChangeHandler?.(false);
73
+ this.#canRead = false;
74
+ throw err;
75
+ }
76
+ }
77
+ async open() {
78
+ if (this.isConnected) {
79
+ return;
80
+ }
81
+ const connection = await this.connect({
82
+ hostname: this.#hostname,
83
+ port: this.#port,
84
+ });
85
+ connection.setNoDelay(true);
86
+ connection.setKeepAlive(true);
87
+ this.#canRead = this.#canWrite = this.#isFirstWrite = true;
88
+ this.stateChangeHandler?.(true);
89
+ L.debug("connected to", this.#hostname, "port", this.#port);
90
+ this.#connection = connection;
91
+ const header = await getTlsHeader(this.#secret);
92
+ const helloRand = header.subarray(11, 43);
93
+ await writeAll(this.#connection, header);
94
+ let offset = 0;
95
+ let read = new Uint8Array();
96
+ for (const prefix of [
97
+ new Uint8Array([0x16, 0x03, 0x03]),
98
+ new Uint8Array([0x14, 0x03, 0x03, 0x00, 0x01, 0x01, 0x17, 0x03, 0x03]),
99
+ ]) {
100
+ while (true) {
101
+ if ((read.byteLength - offset) >= (prefix.byteLength + 2)) {
102
+ if (!startsWith(read.subarray(offset), prefix)) {
103
+ throw new TypeError("Received an invalid prefix.");
104
+ }
105
+ const dataView = new DataView(read.buffer, read.byteOffset, read.byteLength);
106
+ const size = dataView.getUint16(offset + prefix.byteLength, false);
107
+ const total = prefix.byteLength + 2 + size;
108
+ if ((read.byteLength - offset) >= total) {
109
+ offset += total;
110
+ break;
111
+ }
112
+ }
113
+ const buffer = new Uint8Array(4096);
114
+ const n = await connection.read(buffer);
115
+ if (n === null) {
116
+ throw new TypeError("Failed to initialize TLS connection.");
117
+ }
118
+ if (n <= 0) {
119
+ continue;
120
+ }
121
+ this.callback?.read(n);
122
+ read = concat([read, buffer.subarray(0, n)]);
123
+ }
124
+ }
125
+ const response = read.subarray(0, offset);
126
+ const actual = response.slice(11, 43);
127
+ const zeroed = response.slice();
128
+ zeroed.fill(0, 11, 43);
129
+ const expected = await hmacSha256(concat([helloRand, zeroed]), this.#secret.slice(0, 16));
130
+ if (!equals(actual, expected)) {
131
+ throw new TypeError("Failed to initialize TLS connection.");
132
+ }
133
+ L.debug(`initialized TLS connection with ${this.#hostname}`);
134
+ }
135
+ async #readPacket() {
136
+ const header = new Uint8Array(HEADER_LENGTH);
137
+ await this.#read(header);
138
+ if (!startsWith(header, new Uint8Array([0x17, 0x03, 0x03]))) {
139
+ throw new TypeError("Failed to read TLS packet.");
140
+ }
141
+ const length = new DataView(header.buffer).getUint16(3);
142
+ const packet = new Uint8Array(length);
143
+ await this.#read(packet);
144
+ this.#buffer = concat([this.#buffer, packet]);
145
+ }
146
+ async #writePacket(packet) {
147
+ const header = new Uint8Array([0x17, 0x03, 0x03, 0x00, 0x00]);
148
+ new DataView(header.buffer).setUint16(3, packet.byteLength);
149
+ let data = concat([header, packet]);
150
+ if (this.#isFirstWrite) {
151
+ this.#isFirstWrite = false;
152
+ data = concat([new Uint8Array([0x14, 0x03, 0x03, 0x00, 0x01, 0x01]), data]);
153
+ }
154
+ try {
155
+ await writeAll(this.#connection, data);
156
+ this.callback?.write(data.byteLength);
157
+ }
158
+ catch (err) {
159
+ this.#canWrite = false;
160
+ this.stateChangeHandler?.(false);
161
+ throw err;
162
+ }
163
+ }
164
+ async read(p) {
165
+ this.#assertConnected();
166
+ const unlock = await this.#rMutex.lock();
167
+ try {
168
+ while (this.#buffer.byteLength < p.byteLength) {
169
+ await this.#readPacket();
170
+ }
171
+ p.set(this.#buffer.subarray(0, p.byteLength));
172
+ this.#buffer = this.#buffer.slice(p.byteLength);
173
+ }
174
+ finally {
175
+ unlock();
176
+ }
177
+ }
178
+ async write(p) {
179
+ this.#assertConnected();
180
+ const unlock = await this.#wMutex.lock();
181
+ try {
182
+ let offset = 0;
183
+ while (true) {
184
+ const packet = p.subarray(offset, offset + MAX_PACKET_LENGTH - HEADER_LENGTH);
185
+ if (packet.byteLength === 0) {
186
+ break;
187
+ }
188
+ await this.#writePacket(packet);
189
+ offset += packet.byteLength;
190
+ }
191
+ }
192
+ finally {
193
+ unlock();
194
+ }
195
+ }
196
+ close() {
197
+ this.#assertConnected();
198
+ this.#connection.close();
199
+ this.#canRead = this.#canWrite = false;
200
+ this.#isFirstWrite = true;
201
+ this.#connection = undefined;
202
+ }
203
+ }
@@ -0,0 +1,52 @@
1
+ import type { Writer, WriterSync } from "./types.js";
2
+ export type { Writer, WriterSync } from "./types.js";
3
+ /**
4
+ * Write all the content of the array buffer (`arr`) to the writer (`w`).
5
+ *
6
+ * @example Writing to stdout
7
+ * ```ts no-assert
8
+ * import { writeAll } from "@std/io/write-all";
9
+ *
10
+ * const contentBytes = new TextEncoder().encode("Hello World");
11
+ * await writeAll(Deno.stdout, contentBytes);
12
+ * ```
13
+ *
14
+ * @example Writing to file
15
+ * ```ts ignore no-assert
16
+ * import { writeAll } from "@std/io/write-all";
17
+ *
18
+ * const contentBytes = new TextEncoder().encode("Hello World");
19
+ * using file = await Deno.open('test.file', { write: true });
20
+ * await writeAll(file, contentBytes);
21
+ * ```
22
+ *
23
+ * @param writer The writer to write to
24
+ * @param data The data to write
25
+ */
26
+ export declare function writeAll(writer: Writer, data: Uint8Array): Promise<void>;
27
+ /**
28
+ * Synchronously write all the content of the array buffer (`arr`) to the
29
+ * writer (`w`).
30
+ *
31
+ * @example "riting to stdout
32
+ * ```ts no-assert
33
+ * import { writeAllSync } from "@std/io/write-all";
34
+ *
35
+ * const contentBytes = new TextEncoder().encode("Hello World");
36
+ * writeAllSync(Deno.stdout, contentBytes);
37
+ * ```
38
+ *
39
+ * @example Writing to file
40
+ * ```ts ignore no-assert
41
+ * import { writeAllSync } from "@std/io/write-all";
42
+ *
43
+ * const contentBytes = new TextEncoder().encode("Hello World");
44
+ * using file = Deno.openSync("test.file", { write: true });
45
+ * writeAllSync(file, contentBytes);
46
+ * ```
47
+ *
48
+ * @param writer The writer to write to
49
+ * @param data The data to write
50
+ */
51
+ export declare function writeAllSync(writer: WriterSync, data: Uint8Array): void;
52
+ //# sourceMappingURL=write_all.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write_all.d.ts","sourceRoot":"","sources":["../../../../../../src/deps/jsr.io/@std/io/0.225.3/write_all.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAErD,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAErD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,iBAK9D;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,QAKhE"}
@@ -0,0 +1,61 @@
1
+ // Copyright 2018-2026 the Deno authors. MIT license.
2
+ // This module is browser compatible.
3
+ /**
4
+ * Write all the content of the array buffer (`arr`) to the writer (`w`).
5
+ *
6
+ * @example Writing to stdout
7
+ * ```ts no-assert
8
+ * import { writeAll } from "@std/io/write-all";
9
+ *
10
+ * const contentBytes = new TextEncoder().encode("Hello World");
11
+ * await writeAll(Deno.stdout, contentBytes);
12
+ * ```
13
+ *
14
+ * @example Writing to file
15
+ * ```ts ignore no-assert
16
+ * import { writeAll } from "@std/io/write-all";
17
+ *
18
+ * const contentBytes = new TextEncoder().encode("Hello World");
19
+ * using file = await Deno.open('test.file', { write: true });
20
+ * await writeAll(file, contentBytes);
21
+ * ```
22
+ *
23
+ * @param writer The writer to write to
24
+ * @param data The data to write
25
+ */
26
+ export async function writeAll(writer, data) {
27
+ let nwritten = 0;
28
+ while (nwritten < data.length) {
29
+ nwritten += await writer.write(data.subarray(nwritten));
30
+ }
31
+ }
32
+ /**
33
+ * Synchronously write all the content of the array buffer (`arr`) to the
34
+ * writer (`w`).
35
+ *
36
+ * @example "riting to stdout
37
+ * ```ts no-assert
38
+ * import { writeAllSync } from "@std/io/write-all";
39
+ *
40
+ * const contentBytes = new TextEncoder().encode("Hello World");
41
+ * writeAllSync(Deno.stdout, contentBytes);
42
+ * ```
43
+ *
44
+ * @example Writing to file
45
+ * ```ts ignore no-assert
46
+ * import { writeAllSync } from "@std/io/write-all";
47
+ *
48
+ * const contentBytes = new TextEncoder().encode("Hello World");
49
+ * using file = Deno.openSync("test.file", { write: true });
50
+ * writeAllSync(file, contentBytes);
51
+ * ```
52
+ *
53
+ * @param writer The writer to write to
54
+ * @param data The data to write
55
+ */
56
+ export function writeAllSync(writer, data) {
57
+ let nwritten = 0;
58
+ while (nwritten < data.length) {
59
+ nwritten += writer.writeSync(data.subarray(nwritten));
60
+ }
61
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"2_session_encrypted.d.ts","sourceRoot":"","sources":["../../src/session/2_session_encrypted.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH,OAAO,EAAwD,OAAO,EAAuC,MAAM,YAAY,CAAC;AAChI,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,mBAAmB,CAAC;AAI5C,OAAO,EAAE,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAa7D,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,eAAe,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,eAAe,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACxD,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,KAAK,IAAI,CAAC;IACtC,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,SAAS,KAAK,IAAI,CAAC;IAC5D,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;CACxD;AAED,qBAAa,gBAAiB,SAAQ,OAAQ,YAAW,OAAO;;IAI9D,QAAQ,EAAE,QAAQ,CAAM;gBAiBZ,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,aAAa;IAQpC,UAAU,CAAC,GAAG,EAAE,UAAU,CAAC,WAAW,CAAC;IAM7C,IAAI,OAAO,IAAI,UAAU,CAAC,WAAW,CAAC,CAErC;IAEc,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAe9B,UAAU,IAAI,IAAI;IA6ErB,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;CAwX3D"}
1
+ {"version":3,"file":"2_session_encrypted.d.ts","sourceRoot":"","sources":["../../src/session/2_session_encrypted.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH,OAAO,EAAwD,OAAO,EAAuC,MAAM,YAAY,CAAC;AAChI,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,mBAAmB,CAAC;AAI5C,OAAO,EAAE,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAa7D,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,eAAe,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,eAAe,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACxD,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,KAAK,IAAI,CAAC;IACtC,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,SAAS,KAAK,IAAI,CAAC;IAC5D,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;CACxD;AAED,qBAAa,gBAAiB,SAAQ,OAAQ,YAAW,OAAO;;IAI9D,QAAQ,EAAE,QAAQ,CAAM;gBAiBZ,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,aAAa;IAQpC,UAAU,CAAC,GAAG,EAAE,UAAU,CAAC,WAAW,CAAC;IAM7C,IAAI,OAAO,IAAI,UAAU,CAAC,WAAW,CAAC,CAErC;IAEc,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAe9B,UAAU,IAAI,IAAI;IA6ErB,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;CA4X3D"}
@@ -190,10 +190,13 @@ export class SessionEncrypted extends Session {
190
190
  return messageWriter.buffer;
191
191
  }
192
192
  async #decryptMessage(buffer) {
193
- const reader = new TLReader(buffer);
193
+ let reader = new TLReader(buffer);
194
194
  assertEquals(reader.readInt64(), this.#authKeyId);
195
195
  const messageKey_ = reader.readInt128();
196
196
  const messageKey = intToBytes(messageKey_, 16);
197
+ if (reader.buffer.length % 16 !== 0) {
198
+ reader = new TLReader(reader.buffer.subarray(0, -(reader.buffer.length % 16)));
199
+ }
197
200
  const a = await sha256(concat([messageKey, this.#authKey.subarray(8, 44)]));
198
201
  const b = await sha256(concat([this.#authKey.subarray(48, 84), messageKey]));
199
202
  const aesKey = concat([a.subarray(0, 8), b.subarray(8, 24), a.subarray(24, 32)]);
@@ -19,7 +19,11 @@
19
19
  */
20
20
  import { CTR } from "../1_utilities.js";
21
21
  import type { Connection } from "../2_connection.js";
22
- export declare function getObfuscationParameters(protocol: number, connection: Connection): Promise<{
22
+ export interface GetObfuscationParametersParams {
23
+ dcId?: number;
24
+ secret?: Uint8Array;
25
+ }
26
+ export declare function getObfuscationParameters(protocol: number, connection: Connection, params?: GetObfuscationParametersParams): Promise<{
23
27
  encryptionCTR: CTR;
24
28
  decryptionCTR: CTR;
25
29
  }>;