@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
package/esm/0_deps.d.ts CHANGED
@@ -33,11 +33,11 @@ export { concat } from "./deps/jsr.io/@std/bytes/1.0.6/concat.js";
33
33
  export { equals } from "./deps/jsr.io/@std/bytes/1.0.6/equals.js";
34
34
  export { startsWith } from "./deps/jsr.io/@std/bytes/1.0.6/starts_with.js";
35
35
  export { LruCache } from "./deps/jsr.io/@std/cache/0.2.2/lru_cache.js";
36
- export { iterateReader } from "./deps/jsr.io/@std/io/0.225.3/iterate_reader.js";
36
+ export { writeAll } from "./deps/jsr.io/@std/io/0.225.3/write_all.js";
37
37
  export { format } from "./deps/jsr.io/@std/datetime/0.225.7/format.js";
38
38
  export { MINUTE, SECOND } from "./deps/jsr.io/@std/datetime/0.225.7/constants.js";
39
39
  export { toArrayBuffer } from "./deps/jsr.io/@std/streams/1.0.17/to_array_buffer.js";
40
- export { encodeHex } from "./deps/jsr.io/@std/encoding/1.0.10/hex.js";
40
+ export { decodeHex, encodeHex } from "./deps/jsr.io/@std/encoding/1.0.10/hex.js";
41
41
  export { decodeBase64, encodeBase64 } from "./deps/jsr.io/@std/encoding/1.0.10/base64.js";
42
42
  import { contentType as contentType_ } from "./deps/jsr.io/@std/media-types/1.1.0/content_type.js";
43
43
  export declare const contentType: typeof contentType_;
@@ -1 +1 @@
1
- {"version":3,"file":"0_deps.d.ts","sourceRoot":"","sources":["../src/0_deps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,4CAA4C,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,2CAA2C,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,4CAA4C,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,iDAAiD,CAAC;AAC9E,OAAO,EAAE,cAAc,EAAE,MAAM,qDAAqD,CAAC;AAErF,OAAO,EAAE,IAAI,EAAE,MAAM,uCAAuC,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,MAAM,0CAA0C,CAAC;AACnE,OAAO,EAAE,QAAQ,EAAE,MAAM,2CAA2C,CAAC;AACrE,OAAO,EAAE,SAAS,EAAE,MAAM,8CAA8C,CAAC;AACzE,OAAO,EAAE,UAAU,EAAE,MAAM,8CAA8C,CAAC;AAE1E,OAAO,EAAE,KAAK,EAAE,MAAM,yCAAyC,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,wCAAwC,CAAC;AAEnE,OAAO,EAAE,MAAM,EAAE,MAAM,0CAA0C,CAAC;AAClE,OAAO,EAAE,MAAM,EAAE,MAAM,0CAA0C,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,+CAA+C,CAAC;AAE3E,OAAO,EAAE,QAAQ,EAAE,MAAM,6CAA6C,CAAC;AAEvE,OAAO,EAAE,aAAa,EAAE,MAAM,iDAAiD,CAAC;AAEhF,OAAO,EAAE,MAAM,EAAE,MAAM,+CAA+C,CAAC;AACvE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,kDAAkD,CAAC;AAElF,OAAO,EAAE,aAAa,EAAE,MAAM,sDAAsD,CAAC;AAErF,OAAO,EAAE,SAAS,EAAE,MAAM,2CAA2C,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,8CAA8C,CAAC;AAE1F,OAAO,EAAE,WAAW,IAAI,YAAY,EAAE,MAAM,sDAAsD,CAAC;AACnG,eAAO,MAAM,WAAW,EAAE,OAAO,YAMhC,CAAC;AAEF,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,UAMzC;AAED,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,IAAI,IAAI,YAAY,EAAE,MAAM,+CAA+C,CAAC"}
1
+ {"version":3,"file":"0_deps.d.ts","sourceRoot":"","sources":["../src/0_deps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,4CAA4C,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,2CAA2C,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,4CAA4C,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,iDAAiD,CAAC;AAC9E,OAAO,EAAE,cAAc,EAAE,MAAM,qDAAqD,CAAC;AAErF,OAAO,EAAE,IAAI,EAAE,MAAM,uCAAuC,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,MAAM,0CAA0C,CAAC;AACnE,OAAO,EAAE,QAAQ,EAAE,MAAM,2CAA2C,CAAC;AACrE,OAAO,EAAE,SAAS,EAAE,MAAM,8CAA8C,CAAC;AACzE,OAAO,EAAE,UAAU,EAAE,MAAM,8CAA8C,CAAC;AAE1E,OAAO,EAAE,KAAK,EAAE,MAAM,yCAAyC,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,wCAAwC,CAAC;AAEnE,OAAO,EAAE,MAAM,EAAE,MAAM,0CAA0C,CAAC;AAClE,OAAO,EAAE,MAAM,EAAE,MAAM,0CAA0C,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,+CAA+C,CAAC;AAE3E,OAAO,EAAE,QAAQ,EAAE,MAAM,6CAA6C,CAAC;AAEvE,OAAO,EAAE,QAAQ,EAAE,MAAM,4CAA4C,CAAC;AAEtE,OAAO,EAAE,MAAM,EAAE,MAAM,+CAA+C,CAAC;AACvE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,kDAAkD,CAAC;AAElF,OAAO,EAAE,aAAa,EAAE,MAAM,sDAAsD,CAAC;AAErF,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,8CAA8C,CAAC;AAE1F,OAAO,EAAE,WAAW,IAAI,YAAY,EAAE,MAAM,sDAAsD,CAAC;AACnG,eAAO,MAAM,WAAW,EAAE,OAAO,YAMhC,CAAC;AAEF,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,UAMzC;AAED,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,IAAI,IAAI,YAAY,EAAE,MAAM,+CAA+C,CAAC"}
package/esm/0_deps.js CHANGED
@@ -33,11 +33,11 @@ export { concat } from "./deps/jsr.io/@std/bytes/1.0.6/concat.js";
33
33
  export { equals } from "./deps/jsr.io/@std/bytes/1.0.6/equals.js";
34
34
  export { startsWith } from "./deps/jsr.io/@std/bytes/1.0.6/starts_with.js";
35
35
  export { LruCache } from "./deps/jsr.io/@std/cache/0.2.2/lru_cache.js";
36
- export { iterateReader } from "./deps/jsr.io/@std/io/0.225.3/iterate_reader.js";
36
+ export { writeAll } from "./deps/jsr.io/@std/io/0.225.3/write_all.js";
37
37
  export { format } from "./deps/jsr.io/@std/datetime/0.225.7/format.js";
38
38
  export { MINUTE, SECOND } from "./deps/jsr.io/@std/datetime/0.225.7/constants.js";
39
39
  export { toArrayBuffer } from "./deps/jsr.io/@std/streams/1.0.17/to_array_buffer.js";
40
- export { encodeHex } from "./deps/jsr.io/@std/encoding/1.0.10/hex.js";
40
+ export { decodeHex, encodeHex } from "./deps/jsr.io/@std/encoding/1.0.10/hex.js";
41
41
  export { decodeBase64, encodeBase64 } from "./deps/jsr.io/@std/encoding/1.0.10/base64.js";
42
42
  import { contentType as contentType_ } from "./deps/jsr.io/@std/media-types/1.1.0/content_type.js";
43
43
  export const contentType = (extentionOrType) => {
@@ -18,5 +18,7 @@
18
18
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
19
19
  */
20
20
  export * from "./connection/0_connection.js";
21
+ export * from "./connection/1_connection_tcp.js";
22
+ export * from "./connection/1_connection_tls.js";
21
23
  export * from "./connection/1_connection_web_socket.js";
22
24
  //# sourceMappingURL=2_connection.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"2_connection.d.ts","sourceRoot":"","sources":["../src/2_connection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,cAAc,8BAA8B,CAAC;AAC7C,cAAc,yCAAyC,CAAC"}
1
+ {"version":3,"file":"2_connection.d.ts","sourceRoot":"","sources":["../src/2_connection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,cAAc,8BAA8B,CAAC;AAC7C,cAAc,kCAAkC,CAAC;AACjD,cAAc,kCAAkC,CAAC;AACjD,cAAc,yCAAyC,CAAC"}
@@ -18,4 +18,6 @@
18
18
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
19
19
  */
20
20
  export * from "./connection/0_connection.js";
21
+ export * from "./connection/1_connection_tcp.js";
22
+ export * from "./connection/1_connection_tls.js";
21
23
  export * from "./connection/1_connection_web_socket.js";
@@ -21,6 +21,7 @@ export * from "./transport/0_transport.js";
21
21
  export * from "./transport/1_transport_abridged.js";
22
22
  export * from "./transport/1_transport_intermediate.js";
23
23
  export * from "./transport/1_transport_provider.js";
24
+ export * from "./transport/2_transport_provider_mtproxy.js";
24
25
  export * from "./transport/2_transport_provider_tcp.js";
25
26
  export * from "./transport/2_transport_provider_web_socket.js";
26
27
  //# sourceMappingURL=3_transport.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"3_transport.d.ts","sourceRoot":"","sources":["../src/3_transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,cAAc,4BAA4B,CAAC;AAC3C,cAAc,qCAAqC,CAAC;AACpD,cAAc,yCAAyC,CAAC;AACxD,cAAc,qCAAqC,CAAC;AACpD,cAAc,yCAAyC,CAAC;AACxD,cAAc,gDAAgD,CAAC"}
1
+ {"version":3,"file":"3_transport.d.ts","sourceRoot":"","sources":["../src/3_transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,cAAc,4BAA4B,CAAC;AAC3C,cAAc,qCAAqC,CAAC;AACpD,cAAc,yCAAyC,CAAC;AACxD,cAAc,qCAAqC,CAAC;AACpD,cAAc,6CAA6C,CAAC;AAC5D,cAAc,yCAAyC,CAAC;AACxD,cAAc,gDAAgD,CAAC"}
@@ -21,5 +21,6 @@ export * from "./transport/0_transport.js";
21
21
  export * from "./transport/1_transport_abridged.js";
22
22
  export * from "./transport/1_transport_intermediate.js";
23
23
  export * from "./transport/1_transport_provider.js";
24
+ export * from "./transport/2_transport_provider_mtproxy.js";
24
25
  export * from "./transport/2_transport_provider_tcp.js";
25
26
  export * from "./transport/2_transport_provider_web_socket.js";
@@ -0,0 +1,2 @@
1
+ export declare function getTlsHeader(secret: Uint8Array<ArrayBuffer>): Promise<Uint8Array<ArrayBuffer>>;
2
+ //# sourceMappingURL=0_get_tls_header.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"0_get_tls_header.d.ts","sourceRoot":"","sources":["../../src/connection/0_get_tls_header.ts"],"names":[],"mappings":"AAGA,wBAAsB,YAAY,CAAC,MAAM,EAAE,UAAU,CAAC,WAAW,CAAC,oCASjE"}
@@ -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.byteLength > 16 ? 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
+ }