@mtkruto/browser 0.132.0 → 0.133.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) 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/connection/0_get_tls_header.d.ts +2 -0
  11. package/esm/connection/0_get_tls_header.d.ts.map +1 -0
  12. package/esm/connection/0_get_tls_header.js +151 -0
  13. package/esm/connection/1_connection_tcp.d.ts.map +1 -1
  14. package/esm/connection/1_connection_tcp.js +21 -52
  15. package/esm/connection/1_connection_tls.d.ts +33 -0
  16. package/esm/connection/1_connection_tls.d.ts.map +1 -0
  17. package/esm/connection/1_connection_tls.js +203 -0
  18. package/esm/deps/jsr.io/@std/io/0.225.3/write_all.d.ts +52 -0
  19. package/esm/deps/jsr.io/@std/io/0.225.3/write_all.d.ts.map +1 -0
  20. package/esm/deps/jsr.io/@std/io/0.225.3/write_all.js +61 -0
  21. package/esm/session/2_session_encrypted.d.ts.map +1 -1
  22. package/esm/session/2_session_encrypted.js +4 -1
  23. package/esm/transport/0_obfuscation.d.ts +5 -1
  24. package/esm/transport/0_obfuscation.d.ts.map +1 -1
  25. package/esm/transport/0_obfuscation.js +17 -4
  26. package/esm/transport/1_transport_intermediate.d.ts +7 -1
  27. package/esm/transport/1_transport_intermediate.d.ts.map +1 -1
  28. package/esm/transport/1_transport_intermediate.js +17 -7
  29. package/esm/transport/2_transport_provider_mtproxy.d.ts +23 -0
  30. package/esm/transport/2_transport_provider_mtproxy.d.ts.map +1 -0
  31. package/esm/transport/2_transport_provider_mtproxy.js +51 -0
  32. package/esm/transport/2_transport_provider_web_socket.js +1 -1
  33. package/esm/utilities/1_crypto.d.ts +1 -0
  34. package/esm/utilities/1_crypto.d.ts.map +1 -1
  35. package/esm/utilities/1_crypto.js +4 -0
  36. package/package.json +1 -1
  37. package/script/0_deps.d.ts +2 -2
  38. package/script/0_deps.d.ts.map +1 -1
  39. package/script/0_deps.js +4 -3
  40. package/script/2_connection.d.ts +2 -0
  41. package/script/2_connection.d.ts.map +1 -1
  42. package/script/2_connection.js +2 -0
  43. package/script/3_transport.d.ts +1 -0
  44. package/script/3_transport.d.ts.map +1 -1
  45. package/script/3_transport.js +1 -0
  46. package/script/connection/0_get_tls_header.d.ts +2 -0
  47. package/script/connection/0_get_tls_header.d.ts.map +1 -0
  48. package/script/connection/0_get_tls_header.js +154 -0
  49. package/script/connection/1_connection_tcp.d.ts.map +1 -1
  50. package/script/connection/1_connection_tcp.js +21 -52
  51. package/script/connection/1_connection_tls.d.ts +33 -0
  52. package/script/connection/1_connection_tls.d.ts.map +1 -0
  53. package/script/connection/1_connection_tls.js +207 -0
  54. package/script/deps/jsr.io/@std/io/0.225.3/write_all.d.ts +52 -0
  55. package/script/deps/jsr.io/@std/io/0.225.3/write_all.d.ts.map +1 -0
  56. package/script/deps/jsr.io/@std/io/0.225.3/write_all.js +65 -0
  57. package/script/session/2_session_encrypted.d.ts.map +1 -1
  58. package/script/session/2_session_encrypted.js +4 -1
  59. package/script/transport/0_obfuscation.d.ts +5 -1
  60. package/script/transport/0_obfuscation.d.ts.map +1 -1
  61. package/script/transport/0_obfuscation.js +16 -3
  62. package/script/transport/1_transport_intermediate.d.ts +7 -1
  63. package/script/transport/1_transport_intermediate.d.ts.map +1 -1
  64. package/script/transport/1_transport_intermediate.js +16 -6
  65. package/script/transport/2_transport_provider_mtproxy.d.ts +23 -0
  66. package/script/transport/2_transport_provider_mtproxy.d.ts.map +1 -0
  67. package/script/transport/2_transport_provider_mtproxy.js +54 -0
  68. package/script/transport/2_transport_provider_web_socket.js +1 -1
  69. package/script/utilities/1_crypto.d.ts +1 -0
  70. package/script/utilities/1_crypto.d.ts.map +1 -1
  71. package/script/utilities/1_crypto.js +5 -0
  72. package/esm/deps/jsr.io/@std/io/0.225.3/_constants.d.ts +0 -3
  73. package/esm/deps/jsr.io/@std/io/0.225.3/_constants.d.ts.map +0 -1
  74. package/esm/deps/jsr.io/@std/io/0.225.3/_constants.js +0 -4
  75. package/esm/deps/jsr.io/@std/io/0.225.3/iterate_reader.d.ts +0 -80
  76. package/esm/deps/jsr.io/@std/io/0.225.3/iterate_reader.d.ts.map +0 -1
  77. package/esm/deps/jsr.io/@std/io/0.225.3/iterate_reader.js +0 -96
  78. package/script/deps/jsr.io/@std/io/0.225.3/_constants.d.ts +0 -3
  79. package/script/deps/jsr.io/@std/io/0.225.3/_constants.d.ts.map +0 -1
  80. package/script/deps/jsr.io/@std/io/0.225.3/_constants.js +0 -7
  81. package/script/deps/jsr.io/@std/io/0.225.3/iterate_reader.d.ts +0 -80
  82. package/script/deps/jsr.io/@std/io/0.225.3/iterate_reader.d.ts.map +0 -1
  83. package/script/deps/jsr.io/@std/io/0.225.3/iterate_reader.js +0 -100
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getTlsHeader = getTlsHeader;
4
+ const _0_deps_js_1 = require("../0_deps.js");
5
+ const _1_utilities_js_1 = require("../1_utilities.js");
6
+ async function getTlsHeader(secret) {
7
+ const array = serializeOps(ops, secret.slice(16));
8
+ secret = secret.slice(0, 16);
9
+ secret = await (0, _1_utilities_js_1.hmacSha256)(array, secret);
10
+ array.set(secret.slice(0), 11);
11
+ const dataView = new DataView(array.buffer);
12
+ const old = dataView.getInt32(39, true);
13
+ dataView.setInt32(39, old ^ Math.floor(Date.now() / 1000), true);
14
+ return array;
15
+ }
16
+ const ops = [
17
+ { type: "string", data: new Uint8Array([0x16, 0x03, 0x01, 0x02, 0x00, 0x01, 0x00, 0x01, 0xfc, 0x03, 0x03]) },
18
+ { type: "zero", length: 32 },
19
+ { type: "string", data: new Uint8Array([0x20]) },
20
+ { type: "random", length: 32 },
21
+ { type: "string", data: new Uint8Array([0x00, 0x2a]) },
22
+ { type: "grease", seed: 0 },
23
+ { 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]) },
24
+ { type: "grease", seed: 2 },
25
+ { type: "string", data: new Uint8Array([0x00, 0x00, 0x00, 0x00]) },
26
+ { type: "beginScope" },
27
+ { type: "beginScope" },
28
+ { type: "string", data: new Uint8Array([0x00]) },
29
+ { type: "beginScope" },
30
+ { type: "domain" },
31
+ { type: "endScope" },
32
+ { type: "endScope" },
33
+ { type: "endScope" },
34
+ { type: "string", data: new Uint8Array([0x00, 0x17, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x0a]) },
35
+ { type: "grease", seed: 4 },
36
+ { 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]) },
37
+ { type: "grease", seed: 4 },
38
+ { type: "string", data: new Uint8Array([0x00, 0x01, 0x00, 0x00, 0x1d, 0x00, 0x20]) },
39
+ { type: "key" },
40
+ { type: "string", data: new Uint8Array([0x00, 0x2d, 0x00, 0x02, 0x01, 0x01, 0x00, 0x2b, 0x00, 0x0b, 0x0a]) },
41
+ { type: "grease", seed: 6 },
42
+ { type: "string", data: new Uint8Array([0x03, 0x04, 0x03, 0x03, 0x03, 0x02, 0x03, 0x01, 0x00, 0x1b, 0x00, 0x03, 0x02, 0x00, 0x01]) },
43
+ { type: "grease", seed: 3 },
44
+ { type: "string", data: new Uint8Array([0x00, 0x01, 0x00]) },
45
+ { type: "padding" },
46
+ ];
47
+ function getGrease() {
48
+ const res = crypto.getRandomValues(new Uint8Array(7));
49
+ for (let i = 0; i < res.length; ++i) {
50
+ res[i] = (res[i] & 0xF0) + 0x0A;
51
+ }
52
+ for (let i = 1; i < res.length; i += 2) {
53
+ if (res[i] === res[i - 1]) {
54
+ res[i] ^= 0x10;
55
+ }
56
+ }
57
+ return res;
58
+ }
59
+ function getY2(x, mod) {
60
+ let y = (x + 486662n) % mod;
61
+ y = y * x % mod;
62
+ y = (y + 1n) % mod;
63
+ return y * x % mod;
64
+ }
65
+ function getDoubleX(x, mod) {
66
+ const y2 = getY2(x, mod);
67
+ const denominator = (4n * y2) % mod;
68
+ let numerator = (x * x % mod - 1n + mod) % mod;
69
+ numerator = (numerator * numerator) % mod;
70
+ const denominatorInv = (0, _1_utilities_js_1.modExp)(denominator, mod - 2n, mod);
71
+ numerator = (numerator * denominatorInv) % mod;
72
+ return numerator;
73
+ }
74
+ function isQuadraticResidue(a) {
75
+ const mod = 2n ** 255n - 19n;
76
+ const pow = 2n ** 254n - 10n;
77
+ const r = (0, _1_utilities_js_1.modExp)(a, pow, mod);
78
+ return r === 1n;
79
+ }
80
+ function serializeOps(ops, domain) {
81
+ const GREASE = getGrease();
82
+ let buffer = new Uint8Array();
83
+ const scopes = new Array();
84
+ function serializeOp(op) {
85
+ switch (op.type) {
86
+ case "string":
87
+ buffer = (0, _0_deps_js_1.concat)([buffer, op.data]);
88
+ break;
89
+ case "random":
90
+ buffer = (0, _0_deps_js_1.concat)([
91
+ buffer,
92
+ crypto.getRandomValues(new Uint8Array(op.length)),
93
+ ]);
94
+ break;
95
+ case "zero":
96
+ buffer = (0, _0_deps_js_1.concat)([buffer, new Uint8Array(op.length)]);
97
+ break;
98
+ case "domain":
99
+ buffer = (0, _0_deps_js_1.concat)([buffer, domain]);
100
+ break;
101
+ case "grease": {
102
+ const grease = GREASE[op.seed];
103
+ buffer = (0, _0_deps_js_1.concat)([buffer, new Uint8Array([grease, grease])]);
104
+ break;
105
+ }
106
+ case "key": {
107
+ const mod = (0, _1_utilities_js_1.intFromBytes)((0, _0_deps_js_1.decodeHex)("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"), { byteOrder: "big", isSigned: false });
108
+ let key = new Uint8Array(32);
109
+ while (true) {
110
+ crypto.getRandomValues(key);
111
+ key[31] &= 127;
112
+ let x = (0, _1_utilities_js_1.intFromBytes)(key, { byteOrder: "big", isSigned: false });
113
+ const y = getY2(x, mod);
114
+ if (isQuadraticResidue(y)) {
115
+ for (let i = 0; i < 3; ++i) {
116
+ x = getDoubleX(x, mod);
117
+ }
118
+ key = (0, _1_utilities_js_1.intToBytes)(x, 32, { byteOrder: "little", isSigned: false });
119
+ break;
120
+ }
121
+ }
122
+ buffer = (0, _0_deps_js_1.concat)([buffer, key]);
123
+ break;
124
+ }
125
+ case "beginScope":
126
+ scopes.push(buffer.length);
127
+ buffer = (0, _0_deps_js_1.concat)([buffer, new Uint8Array([0, 0])]);
128
+ break;
129
+ case "endScope": {
130
+ const beginOffset = scopes.pop();
131
+ if (beginOffset === undefined) {
132
+ throw new TypeError("Invalid endScope");
133
+ }
134
+ const endOffset = buffer.length;
135
+ const size = endOffset - beginOffset - 2;
136
+ new DataView(buffer.buffer).setUint16(beginOffset, size);
137
+ break;
138
+ }
139
+ case "padding": {
140
+ const size = 513 - buffer.length;
141
+ if (size > 0) {
142
+ serializeOp({ type: "string", data: new Uint8Array([0x00, 0x15]) });
143
+ serializeOp({ type: "beginScope" });
144
+ serializeOp({ type: "zero", length: size });
145
+ serializeOp({ type: "endScope" });
146
+ }
147
+ }
148
+ }
149
+ }
150
+ for (const op of ops) {
151
+ serializeOp(op);
152
+ }
153
+ return buffer;
154
+ }
@@ -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"}
@@ -20,7 +20,6 @@
20
20
  */
21
21
  Object.defineProperty(exports, "__esModule", { value: true });
22
22
  exports.ConnectionTCP = void 0;
23
- const _0_deps_js_1 = require("../0_deps.js");
24
23
  const _0_errors_js_1 = require("../0_errors.js");
25
24
  const _1_utilities_js_1 = require("../1_utilities.js");
26
25
  const L = (0, _1_utilities_js_1.getLogger)("ConnectionTCP");
@@ -30,8 +29,6 @@ class ConnectionTCP {
30
29
  #connection;
31
30
  #rMutex = new _1_utilities_js_1.Mutex();
32
31
  #wMutex = new _1_utilities_js_1.Mutex();
33
- #buffer = new Uint8Array();
34
- #nextResolve = null;
35
32
  #canRead = false;
36
33
  #canWrite = false;
37
34
  connect = Deno.connect;
@@ -42,6 +39,7 @@ class ConnectionTCP {
42
39
  this.#port = port;
43
40
  }
44
41
  get isConnected() {
42
+ Deno.errors.BrokenPipe;
45
43
  return !!this.#connection && this.#canRead && this.#canWrite;
46
44
  }
47
45
  #assertConnected() {
@@ -62,48 +60,27 @@ class ConnectionTCP {
62
60
  this.#canRead = this.#canWrite = true;
63
61
  this.stateChangeHandler?.(true);
64
62
  L.debug("connected to", this.#hostname, "port", this.#port);
65
- Promise.resolve().then(async () => {
66
- do {
67
- try {
68
- for await (const chunk of (0, _0_deps_js_1.iterateReader)(connection)) {
69
- this.callback?.read(chunk.length);
70
- this.#buffer = (0, _0_deps_js_1.concat)([this.#buffer, chunk]);
71
- if (this.#nextResolve !== null && this.#buffer.length >= this.#nextResolve[0]) {
72
- this.#nextResolve[1].resolve();
73
- this.#nextResolve = null;
74
- }
75
- }
76
- this.#canRead = false;
77
- break;
78
- }
79
- catch (err) {
80
- this.#canRead = false;
81
- this.stateChangeHandler?.(false);
82
- this.#rejectRead();
83
- L.error(err);
84
- }
85
- } while (this.isConnected);
86
- this.stateChangeHandler?.(false);
87
- });
88
63
  this.#connection = connection;
89
64
  }
90
- #rejectRead() {
91
- if (this.#nextResolve !== null) {
92
- this.#nextResolve[1].reject(new _0_errors_js_1.ConnectionError("The connection was closed."));
93
- this.#nextResolve = null;
94
- }
95
- }
96
65
  async read(p) {
97
66
  this.#assertConnected();
98
67
  const unlock = await this.#rMutex.lock();
68
+ let offset = 0;
99
69
  try {
100
- this.#assertConnected();
101
- if (this.#buffer.length < p.length) {
102
- await new Promise((resolve, reject) => this.#nextResolve = [p.length, { resolve, reject }]);
103
- }
104
- const slice = this.#buffer.slice(0, p.length);
105
- p.set(slice);
106
- this.#buffer = this.#buffer.slice(slice.length);
70
+ do {
71
+ const read = await this.#connection.read(p.subarray(offset));
72
+ if (read === null) {
73
+ this.#canRead = false;
74
+ this.stateChangeHandler?.(false);
75
+ throw new _0_errors_js_1.ConnectionError("The connection was closed.");
76
+ }
77
+ offset += read;
78
+ } while (offset < p.byteLength);
79
+ }
80
+ catch {
81
+ this.#canRead = false;
82
+ this.stateChangeHandler?.(false);
83
+ throw new _0_errors_js_1.ConnectionError("The connection was closed.");
107
84
  }
108
85
  finally {
109
86
  unlock();
@@ -115,23 +92,16 @@ class ConnectionTCP {
115
92
  try {
116
93
  this.#assertConnected();
117
94
  let written = 0;
118
- while (written < p.length) {
95
+ while (written < p.byteLength) {
119
96
  try {
120
97
  const wrote = await this.#connection.write(p.subarray(written));
121
98
  this.callback?.write(wrote);
122
99
  written += wrote;
123
100
  }
124
- catch (err) {
125
- if (err instanceof Deno.errors.BrokenPipe || err instanceof Deno.errors.ConnectionReset) {
126
- this.#canWrite = false;
127
- }
128
- if (!this.isConnected) {
129
- this.stateChangeHandler?.(false);
130
- throw new _0_errors_js_1.ConnectionError("The connection was closed.");
131
- }
132
- else {
133
- throw err;
134
- }
101
+ catch {
102
+ this.#canWrite = false;
103
+ this.stateChangeHandler?.(false);
104
+ throw new _0_errors_js_1.ConnectionError("The connection was closed.");
135
105
  }
136
106
  }
137
107
  }
@@ -144,7 +114,6 @@ class ConnectionTCP {
144
114
  this.#connection.close();
145
115
  this.#canRead = this.#canWrite = false;
146
116
  this.#connection = undefined;
147
- this.#rejectRead();
148
117
  }
149
118
  }
150
119
  exports.ConnectionTCP = ConnectionTCP;
@@ -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,207 @@
1
+ "use strict";
2
+ /**
3
+ * MTKruto - Cross-runtime JavaScript library for building Telegram clients
4
+ * Copyright (C) 2023-2026 Roj <https://roj.im/>
5
+ *
6
+ * This file is part of MTKruto.
7
+ *
8
+ * This program is free software: you can redistribute it and/or modify
9
+ * it under the terms of the GNU Lesser General Public License as published by
10
+ * the Free Software Foundation, either version 3 of the License, or
11
+ * (at your option) any later version.
12
+ *
13
+ * This program is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ * GNU Lesser General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU Lesser General Public License
19
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
20
+ */
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.ConnectionTLS = void 0;
23
+ const _0_deps_js_1 = require("../0_deps.js");
24
+ const _0_errors_js_1 = require("../0_errors.js");
25
+ const _1_utilities_js_1 = require("../1_utilities.js");
26
+ const _0_get_tls_header_js_1 = require("./0_get_tls_header.js");
27
+ const HEADER_LENGTH = 5;
28
+ const MAX_PACKET_LENGTH = 2878;
29
+ const L = (0, _1_utilities_js_1.getLogger)("ConnectionTLS");
30
+ class ConnectionTLS {
31
+ #hostname;
32
+ #port;
33
+ #secret;
34
+ #connection;
35
+ #rMutex = new _1_utilities_js_1.Mutex();
36
+ #wMutex = new _1_utilities_js_1.Mutex();
37
+ #buffer = new Uint8Array();
38
+ #canRead = false;
39
+ #canWrite = false;
40
+ #isFirstWrite = true;
41
+ connect = Deno.connect;
42
+ stateChangeHandler;
43
+ callback;
44
+ constructor(hostname, port, secret) {
45
+ this.#hostname = hostname;
46
+ this.#port = port;
47
+ this.#secret = secret.byteLength > 16 ? secret.slice(1) : secret;
48
+ }
49
+ get isConnected() {
50
+ return !!this.#connection && this.#canRead && this.#canWrite;
51
+ }
52
+ #assertConnected() {
53
+ if (!this.isConnected) {
54
+ throw new _0_errors_js_1.ConnectionError("The connection is not open.");
55
+ }
56
+ }
57
+ async #read(array) {
58
+ let offset = 0;
59
+ try {
60
+ while (offset < array.length) {
61
+ const n = await this.#connection.read(array.subarray(offset));
62
+ if (n === null) {
63
+ this.#canRead = false;
64
+ this.stateChangeHandler?.(false);
65
+ throw new _0_errors_js_1.ConnectionError("The connection is not open.");
66
+ }
67
+ if (n <= 0) {
68
+ continue;
69
+ }
70
+ this.callback?.read(n);
71
+ offset += n;
72
+ }
73
+ }
74
+ catch (err) {
75
+ this.stateChangeHandler?.(false);
76
+ this.#canRead = false;
77
+ throw err;
78
+ }
79
+ }
80
+ async open() {
81
+ if (this.isConnected) {
82
+ return;
83
+ }
84
+ const connection = await this.connect({
85
+ hostname: this.#hostname,
86
+ port: this.#port,
87
+ });
88
+ connection.setNoDelay(true);
89
+ connection.setKeepAlive(true);
90
+ this.#canRead = this.#canWrite = this.#isFirstWrite = true;
91
+ this.stateChangeHandler?.(true);
92
+ L.debug("connected to", this.#hostname, "port", this.#port);
93
+ this.#connection = connection;
94
+ const header = await (0, _0_get_tls_header_js_1.getTlsHeader)(this.#secret);
95
+ const helloRand = header.subarray(11, 43);
96
+ await (0, _0_deps_js_1.writeAll)(this.#connection, header);
97
+ let offset = 0;
98
+ let read = new Uint8Array();
99
+ for (const prefix of [
100
+ new Uint8Array([0x16, 0x03, 0x03]),
101
+ new Uint8Array([0x14, 0x03, 0x03, 0x00, 0x01, 0x01, 0x17, 0x03, 0x03]),
102
+ ]) {
103
+ while (true) {
104
+ if ((read.byteLength - offset) >= (prefix.byteLength + 2)) {
105
+ if (!(0, _0_deps_js_1.startsWith)(read.subarray(offset), prefix)) {
106
+ throw new TypeError("Received an invalid prefix.");
107
+ }
108
+ const dataView = new DataView(read.buffer, read.byteOffset, read.byteLength);
109
+ const size = dataView.getUint16(offset + prefix.byteLength, false);
110
+ const total = prefix.byteLength + 2 + size;
111
+ if ((read.byteLength - offset) >= total) {
112
+ offset += total;
113
+ break;
114
+ }
115
+ }
116
+ const buffer = new Uint8Array(4096);
117
+ const n = await connection.read(buffer);
118
+ if (n === null) {
119
+ throw new TypeError("Failed to initialize TLS connection.");
120
+ }
121
+ if (n <= 0) {
122
+ continue;
123
+ }
124
+ this.callback?.read(n);
125
+ read = (0, _0_deps_js_1.concat)([read, buffer.subarray(0, n)]);
126
+ }
127
+ }
128
+ const response = read.subarray(0, offset);
129
+ const actual = response.slice(11, 43);
130
+ const zeroed = response.slice();
131
+ zeroed.fill(0, 11, 43);
132
+ const expected = await (0, _1_utilities_js_1.hmacSha256)((0, _0_deps_js_1.concat)([helloRand, zeroed]), this.#secret.slice(0, 16));
133
+ if (!(0, _0_deps_js_1.equals)(actual, expected)) {
134
+ throw new TypeError("Failed to initialize TLS connection.");
135
+ }
136
+ L.debug(`initialized TLS connection with ${this.#hostname}`);
137
+ }
138
+ async #readPacket() {
139
+ const header = new Uint8Array(HEADER_LENGTH);
140
+ await this.#read(header);
141
+ if (!(0, _0_deps_js_1.startsWith)(header, new Uint8Array([0x17, 0x03, 0x03]))) {
142
+ throw new TypeError("Failed to read TLS packet.");
143
+ }
144
+ const length = new DataView(header.buffer).getUint16(3);
145
+ const packet = new Uint8Array(length);
146
+ await this.#read(packet);
147
+ this.#buffer = (0, _0_deps_js_1.concat)([this.#buffer, packet]);
148
+ }
149
+ async #writePacket(packet) {
150
+ const header = new Uint8Array([0x17, 0x03, 0x03, 0x00, 0x00]);
151
+ new DataView(header.buffer).setUint16(3, packet.byteLength);
152
+ let data = (0, _0_deps_js_1.concat)([header, packet]);
153
+ if (this.#isFirstWrite) {
154
+ this.#isFirstWrite = false;
155
+ data = (0, _0_deps_js_1.concat)([new Uint8Array([0x14, 0x03, 0x03, 0x00, 0x01, 0x01]), data]);
156
+ }
157
+ try {
158
+ await (0, _0_deps_js_1.writeAll)(this.#connection, data);
159
+ this.callback?.write(data.byteLength);
160
+ }
161
+ catch (err) {
162
+ this.#canWrite = false;
163
+ this.stateChangeHandler?.(false);
164
+ throw err;
165
+ }
166
+ }
167
+ async read(p) {
168
+ this.#assertConnected();
169
+ const unlock = await this.#rMutex.lock();
170
+ try {
171
+ while (this.#buffer.byteLength < p.byteLength) {
172
+ await this.#readPacket();
173
+ }
174
+ p.set(this.#buffer.subarray(0, p.byteLength));
175
+ this.#buffer = this.#buffer.slice(p.byteLength);
176
+ }
177
+ finally {
178
+ unlock();
179
+ }
180
+ }
181
+ async write(p) {
182
+ this.#assertConnected();
183
+ const unlock = await this.#wMutex.lock();
184
+ try {
185
+ let offset = 0;
186
+ while (true) {
187
+ const packet = p.subarray(offset, offset + MAX_PACKET_LENGTH - HEADER_LENGTH);
188
+ if (packet.byteLength === 0) {
189
+ break;
190
+ }
191
+ await this.#writePacket(packet);
192
+ offset += packet.byteLength;
193
+ }
194
+ }
195
+ finally {
196
+ unlock();
197
+ }
198
+ }
199
+ close() {
200
+ this.#assertConnected();
201
+ this.#connection.close();
202
+ this.#canRead = this.#canWrite = false;
203
+ this.#isFirstWrite = true;
204
+ this.#connection = undefined;
205
+ }
206
+ }
207
+ exports.ConnectionTLS = ConnectionTLS;
@@ -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,65 @@
1
+ "use strict";
2
+ // Copyright 2018-2026 the Deno authors. MIT license.
3
+ // This module is browser compatible.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.writeAll = writeAll;
6
+ exports.writeAllSync = writeAllSync;
7
+ /**
8
+ * Write all the content of the array buffer (`arr`) to the writer (`w`).
9
+ *
10
+ * @example Writing to stdout
11
+ * ```ts no-assert
12
+ * import { writeAll } from "@std/io/write-all";
13
+ *
14
+ * const contentBytes = new TextEncoder().encode("Hello World");
15
+ * await writeAll(Deno.stdout, contentBytes);
16
+ * ```
17
+ *
18
+ * @example Writing to file
19
+ * ```ts ignore no-assert
20
+ * import { writeAll } from "@std/io/write-all";
21
+ *
22
+ * const contentBytes = new TextEncoder().encode("Hello World");
23
+ * using file = await Deno.open('test.file', { write: true });
24
+ * await writeAll(file, contentBytes);
25
+ * ```
26
+ *
27
+ * @param writer The writer to write to
28
+ * @param data The data to write
29
+ */
30
+ async function writeAll(writer, data) {
31
+ let nwritten = 0;
32
+ while (nwritten < data.length) {
33
+ nwritten += await writer.write(data.subarray(nwritten));
34
+ }
35
+ }
36
+ /**
37
+ * Synchronously write all the content of the array buffer (`arr`) to the
38
+ * writer (`w`).
39
+ *
40
+ * @example "riting to stdout
41
+ * ```ts no-assert
42
+ * import { writeAllSync } from "@std/io/write-all";
43
+ *
44
+ * const contentBytes = new TextEncoder().encode("Hello World");
45
+ * writeAllSync(Deno.stdout, contentBytes);
46
+ * ```
47
+ *
48
+ * @example Writing to file
49
+ * ```ts ignore no-assert
50
+ * import { writeAllSync } from "@std/io/write-all";
51
+ *
52
+ * const contentBytes = new TextEncoder().encode("Hello World");
53
+ * using file = Deno.openSync("test.file", { write: true });
54
+ * writeAllSync(file, contentBytes);
55
+ * ```
56
+ *
57
+ * @param writer The writer to write to
58
+ * @param data The data to write
59
+ */
60
+ function writeAllSync(writer, data) {
61
+ let nwritten = 0;
62
+ while (nwritten < data.length) {
63
+ nwritten += writer.writeSync(data.subarray(nwritten));
64
+ }
65
+ }
@@ -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"}
@@ -193,10 +193,13 @@ class SessionEncrypted extends _1_session_js_1.Session {
193
193
  return messageWriter.buffer;
194
194
  }
195
195
  async #decryptMessage(buffer) {
196
- const reader = new _2_tl_js_1.TLReader(buffer);
196
+ let reader = new _2_tl_js_1.TLReader(buffer);
197
197
  (0, _0_deps_js_1.assertEquals)(reader.readInt64(), this.#authKeyId);
198
198
  const messageKey_ = reader.readInt128();
199
199
  const messageKey = (0, _1_utilities_js_1.intToBytes)(messageKey_, 16);
200
+ if (reader.buffer.length % 16 !== 0) {
201
+ reader = new _2_tl_js_1.TLReader(reader.buffer.subarray(0, -(reader.buffer.length % 16)));
202
+ }
200
203
  const a = await (0, _1_utilities_js_1.sha256)((0, _0_deps_js_1.concat)([messageKey, this.#authKey.subarray(8, 44)]));
201
204
  const b = await (0, _1_utilities_js_1.sha256)((0, _0_deps_js_1.concat)([this.#authKey.subarray(48, 84), messageKey]));
202
205
  const aesKey = (0, _0_deps_js_1.concat)([a.subarray(0, 8), b.subarray(8, 24), a.subarray(24, 32)]);