@mtkruto/node 0.0.63 → 0.0.72

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.
@@ -2,28 +2,29 @@ import { gunzip } from "../deps.js";
2
2
  import { ackThreshold } from "../constants.js";
3
3
  import { getRandomBigInt } from "../utilities/0_bigint.js";
4
4
  import { decryptMessage, encryptMessage, getMessageId } from "../utilities/1_message.js";
5
- import { BadMsgNotification, BadServerSalt, GZIPPacked, MsgsAck, Pong, RPCError, Updates } from "../tl/2_types.js";
6
- import { Ping } from "../tl/3_functions.js";
5
+ import * as types from "../tl/2_types.js";
6
+ import * as functions from "../tl/3_functions.js";
7
7
  import { TLReader } from "../tl/3_tl_reader.js";
8
8
  import { RPCResult } from "../tl/4_rpc_result.js";
9
9
  import { Message } from "../tl/5_message.js";
10
10
  import { MessageContainer } from "../tl/6_message_container.js";
11
11
  import { ClientAbstract } from "./client_abstract.js";
12
12
  import { ClientPlain } from "./client_plain.js";
13
+ import { SessionMemory } from "../session/session_memory.js";
13
14
  export class Client extends ClientAbstract {
14
- constructor() {
15
- super(...arguments);
16
- Object.defineProperty(this, "sessionId", {
15
+ constructor(session = new SessionMemory(), params) {
16
+ super(params?.transportProvider);
17
+ Object.defineProperty(this, "session", {
17
18
  enumerable: true,
18
19
  configurable: true,
19
20
  writable: true,
20
- value: getRandomBigInt(8, true, false)
21
+ value: session
21
22
  });
22
- Object.defineProperty(this, "auth", {
23
+ Object.defineProperty(this, "sessionId", {
23
24
  enumerable: true,
24
25
  configurable: true,
25
26
  writable: true,
26
- value: void 0
27
+ value: getRandomBigInt(8, true, false)
27
28
  });
28
29
  Object.defineProperty(this, "state", {
29
30
  enumerable: true,
@@ -51,30 +52,39 @@ export class Client extends ClientAbstract {
51
52
  });
52
53
  }
53
54
  async connect() {
54
- const plain = new ClientPlain(this.transportProvider);
55
- await plain.connect();
56
- const { authKey: key, authKeyId: id, salt } = await plain.createAuthKey();
57
- await plain.disconnect();
58
- this.auth = { key, id };
59
- this.state.salt = salt;
55
+ await this.session.load();
56
+ if (this.session.authKey == null) {
57
+ const plain = new ClientPlain(this.transportProvider);
58
+ await plain.connect();
59
+ const { authKey, salt } = await plain.createAuthKey();
60
+ await plain.disconnect();
61
+ this.state.salt = salt;
62
+ this.session.authKey = authKey;
63
+ }
64
+ if (this.session.dc != null) {
65
+ const { connection, transport, dcId } = this.transportProvider({ dc: this.session.dc, cdn: false });
66
+ this.connection = connection;
67
+ this.transport = transport;
68
+ this.dcId = dcId;
69
+ }
60
70
  await super.connect();
61
71
  // logger().debug("Client connected");
62
72
  this.receiveLoop();
63
73
  this.pingLoop();
64
74
  }
65
75
  async receiveLoop() {
66
- if (!this.auth) {
76
+ if (!this.session.authKey) {
67
77
  throw new Error("Not connected");
68
78
  }
69
79
  while (this.connected) {
70
80
  if (this.toAcknowledge.size >= ackThreshold) {
71
- await this.send(new MsgsAck({ msgIds: [...this.toAcknowledge] }));
81
+ await this.send(new types.MsgsAck({ msgIds: [...this.toAcknowledge] }));
72
82
  this.toAcknowledge.clear();
73
83
  }
74
84
  const buffer = await this.transport.receive();
75
85
  let decrypted;
76
86
  try {
77
- decrypted = await decryptMessage(buffer, this.auth.key, this.auth.id, this.sessionId);
87
+ decrypted = await decryptMessage(buffer, this.session.authKey, this.sessionId);
78
88
  }
79
89
  catch (_err) {
80
90
  // logger().error(`Failed to decrypt message: ${err}`);
@@ -83,21 +93,21 @@ export class Client extends ClientAbstract {
83
93
  const messages = decrypted instanceof MessageContainer ? decrypted.messages : [decrypted];
84
94
  for (const message of messages) {
85
95
  let body = message.body;
86
- if (body instanceof GZIPPacked) {
96
+ if (body instanceof types.GZIPPacked) {
87
97
  body = new TLReader(gunzip(body.packedData)).readObject();
88
98
  }
89
99
  // logger().debug(`Received ${body.constructor.name}`);
90
- if (body instanceof Updates) {
100
+ if (body instanceof types.Updates) {
91
101
  this.updatesHandler?.(this, body);
92
102
  }
93
103
  else if (message.body instanceof RPCResult) {
94
104
  let result = message.body.result;
95
- if (result instanceof GZIPPacked) {
105
+ if (result instanceof types.GZIPPacked) {
96
106
  result = new TLReader(gunzip(result.packedData)).readObject();
97
107
  }
98
108
  const promise = this.promises.get(message.body.messageId);
99
109
  if (promise) {
100
- if (result instanceof RPCError) {
110
+ if (result instanceof types.RPCError) {
101
111
  promise.reject(result);
102
112
  }
103
113
  else {
@@ -106,15 +116,15 @@ export class Client extends ClientAbstract {
106
116
  this.promises.delete(message.body.messageId);
107
117
  }
108
118
  }
109
- else if (message.body instanceof Pong) {
119
+ else if (message.body instanceof types.Pong) {
110
120
  const promise = this.promises.get(message.body.msgId);
111
121
  if (promise) {
112
122
  promise.resolve(message.body);
113
123
  this.promises.delete(message.body.msgId);
114
124
  }
115
125
  }
116
- else if (message.body instanceof BadMsgNotification || message.body instanceof BadServerSalt) {
117
- if (message.body instanceof BadServerSalt) {
126
+ else if (message.body instanceof types.BadMsgNotification || message.body instanceof types.BadServerSalt) {
127
+ if (message.body instanceof types.BadServerSalt) {
118
128
  this.state.salt = message.body.newServerSalt;
119
129
  }
120
130
  const promise = this.promises.get(message.body.badMsgId);
@@ -130,7 +140,7 @@ export class Client extends ClientAbstract {
130
140
  async pingLoop() {
131
141
  while (this.connected) {
132
142
  try {
133
- await this.invoke(new Ping({ pingId: getRandomBigInt(8, true, false) }));
143
+ await this.invoke(new functions.Ping({ pingId: getRandomBigInt(8, true, false) }));
134
144
  }
135
145
  catch (_err) {
136
146
  // logger().error(`Failed to invoke ping: ${err}`);
@@ -139,16 +149,16 @@ export class Client extends ClientAbstract {
139
149
  }
140
150
  }
141
151
  async invoke(function_, noWait) {
142
- if (!this.auth) {
152
+ if (!this.session.authKey) {
143
153
  throw new Error("Not connected");
144
154
  }
145
155
  let seqNo = this.state.seqNo * 2;
146
- if (!(function_ instanceof Ping) && !(function_ instanceof MsgsAck)) {
156
+ if (!(function_ instanceof functions.Ping) && !(function_ instanceof types.MsgsAck)) {
147
157
  seqNo++;
148
158
  this.state.seqNo++;
149
159
  }
150
160
  const message = new Message(getMessageId(), seqNo, function_);
151
- await this.transport.send(await encryptMessage(message, this.auth.key, this.auth.id, this.state.salt, this.sessionId));
161
+ await this.transport.send(await encryptMessage(message, this.session.authKey, this.state.salt, this.sessionId));
152
162
  // logger().debug(`Invoked ${function_.constructor.name}`);
153
163
  if (noWait) {
154
164
  return;
@@ -156,7 +166,7 @@ export class Client extends ClientAbstract {
156
166
  const result = await new Promise((resolve, reject) => {
157
167
  this.promises.set(message.id, { resolve, reject });
158
168
  });
159
- if (result instanceof BadServerSalt) {
169
+ if (result instanceof types.BadServerSalt) {
160
170
  return await this.invoke(function_);
161
171
  }
162
172
  else {
@@ -1,5 +1,5 @@
1
- import { defaultTransportProvider } from "../transport/transport_provider.js";
2
1
  import { initTgCrypto } from "../deps.js";
2
+ import { defaultDc, defaultTransportProvider } from "../transport/transport_provider.js";
3
3
  export class ClientAbstract {
4
4
  constructor(transportProvider = defaultTransportProvider()) {
5
5
  Object.defineProperty(this, "transportProvider", {
@@ -32,7 +32,7 @@ export class ClientAbstract {
32
32
  writable: true,
33
33
  value: false
34
34
  });
35
- const { connection, transport, dcId } = transportProvider(false);
35
+ const { connection, transport, dcId } = transportProvider({ dc: defaultDc, cdn: false });
36
36
  this.connection = connection;
37
37
  this.transport = transport;
38
38
  this.dcId = dcId;
@@ -101,11 +101,9 @@ export class ClientPlain extends ClientAbstract {
101
101
  const salt = newNonce_.slice(0, 0 + 8).map((v, i) => v ^ serverNonceSlice[i]);
102
102
  const authKey_ = modExp(gA, b, dhPrime);
103
103
  const authKey = bufferFromBigInt(authKey_, 256, false, false);
104
- const authKeyId = (await sha1(authKey)).slice(-8);
105
104
  // logger().debug("Auth key created");
106
105
  return {
107
106
  authKey,
108
- authKeyId: bigIntFromBuffer(authKeyId, true, false),
109
107
  salt: bigIntFromBuffer(salt, true, false),
110
108
  };
111
109
  }
package/esm/mod.js CHANGED
@@ -3,10 +3,17 @@ import { getRandomId } from "./utilities/0_bigint.js";
3
3
  export const utils = { checkPassword, getRandomId };
4
4
  export * as types from "./tl/2_types.js";
5
5
  export * as functions from "./tl/3_functions.js";
6
+ export * from "./tl/4_rpc_result.js";
7
+ export * from "./tl/5_message.js";
8
+ export * from "./tl/6_message_container.js";
6
9
  export * from "./client/client_plain.js";
7
10
  export * from "./client/client.js";
11
+ export * from "./session/session.js";
12
+ export * from "./session/session_memory.js";
13
+ export * from "./session/session_local_storage.js";
8
14
  export * from "./transport/transport_abridged.js";
9
15
  export * from "./transport/transport_intermediate.js";
10
16
  export * from "./transport/transport.js";
11
17
  export * from "./transport/transport_provider.js";
12
18
  export * from "./connection/connection.js";
19
+ export * from "./connection/connection_web_socket.js";
@@ -0,0 +1,16 @@
1
+ export class Session {
2
+ constructor() {
3
+ Object.defineProperty(this, "dc", {
4
+ enumerable: true,
5
+ configurable: true,
6
+ writable: true,
7
+ value: null
8
+ });
9
+ Object.defineProperty(this, "authKey", {
10
+ enumerable: true,
11
+ configurable: true,
12
+ writable: true,
13
+ value: null
14
+ });
15
+ }
16
+ }
@@ -0,0 +1,26 @@
1
+ import { Session } from "./session.js";
2
+ export class SessionLocalStorage extends Session {
3
+ constructor(key) {
4
+ if (typeof localStorage == "undefined") {
5
+ throw new Error("Unavailable in current environment");
6
+ }
7
+ super();
8
+ Object.defineProperty(this, "key", {
9
+ enumerable: true,
10
+ configurable: true,
11
+ writable: true,
12
+ value: key
13
+ });
14
+ }
15
+ load() {
16
+ const { dc = null, authKey = null } = JSON.parse(localStorage.getItem(this.key) ?? "{}");
17
+ this.dc = dc;
18
+ if (authKey != null) {
19
+ this.authKey = new Uint8Array(authKey.split(/([0-9a-f]{2})/).filter((v) => v).map((v) => parseInt(v, 16)));
20
+ }
21
+ }
22
+ save() {
23
+ const authKey = this.authKey == null ? undefined : Array.from(this.authKey).map((v) => v.toString(16)).map((v) => v.padStart(2, "0"));
24
+ localStorage.setItem(this.key, JSON.stringify({ dc: this.dc, authKey }));
25
+ }
26
+ }
@@ -0,0 +1,5 @@
1
+ import { Session } from "./session.js";
2
+ export class SessionMemory extends Session {
3
+ load() { }
4
+ save() { }
5
+ }
@@ -11,13 +11,13 @@ const dcToNameMap = {
11
11
  "4": "vesta",
12
12
  "5": "flora",
13
13
  };
14
- export const defaultTransportProvider = (params) => {
15
- return (cdn) => {
16
- const { dc, wss = typeof location !== "undefined" && location.protocol == "http:" ? false : true } = params ?? { dc: defaultDc };
14
+ export function defaultTransportProvider(wss) {
15
+ return ({ dc, cdn }) => {
16
+ wss ??= typeof location !== "undefined" && location.protocol == "http:" ? false : true;
17
17
  const url = `${wss ? "wss" : "ws"}://${dcToNameMap[dc]}${cdn ? "-1" : ""}.web.telegram.org/${dc.endsWith("-test") ? "apiws_test" : "apiws"}`;
18
18
  const connection = new ConnectionWebSocket(url);
19
19
  const transport = new TransportIntermediate(connection, true);
20
20
  const dcId = Number(dc[0]) + (dc.endsWith("-test") ? 10000 : 0) * (cdn ? -1 : 1);
21
21
  return { connection, transport, dcId };
22
22
  };
23
- };
23
+ }
@@ -6,8 +6,12 @@ import { TLReader } from "../tl/3_tl_reader.js";
6
6
  import { RPCResult } from "../tl/4_rpc_result.js";
7
7
  import { Message } from "../tl/5_message.js";
8
8
  import { MessageContainer } from "../tl/6_message_container.js";
9
+ import { bigIntFromBuffer } from "./0_bigint.js";
9
10
  import { bufferFromBigInt, concat } from "./0_buffer.js";
10
- import { sha256 } from "./0_hash.js";
11
+ import { sha1, sha256 } from "./0_hash.js";
12
+ async function getAuthKeyId(authKey) {
13
+ return bigIntFromBuffer((await sha1(authKey)).slice(-8), true, false);
14
+ }
11
15
  let lastMsgId = 0n;
12
16
  export function getMessageId() {
13
17
  const now = new Date().getTime() / 1000 + 0;
@@ -33,8 +37,9 @@ export function unpackUnencryptedMessage(buffer) {
33
37
  const message = reader.read(messageLength);
34
38
  return { messageId, message };
35
39
  }
36
- export async function encryptMessage(message, authKey, authKeyId, salt, sessionId) {
40
+ export async function encryptMessage(message, authKey, salt, sessionId) {
37
41
  const encoded = message.body.serialize();
42
+ const authKeyId = await getAuthKeyId(authKey);
38
43
  const payloadWriter = new TLRawWriter();
39
44
  payloadWriter.writeInt64(salt);
40
45
  payloadWriter.writeInt64(sessionId);
@@ -61,7 +66,8 @@ export async function encryptMessage(message, authKey, authKeyId, salt, sessionI
61
66
  messageWriter.write(ige256Encrypt(payload, aesKey, aesIV));
62
67
  return messageWriter.buffer;
63
68
  }
64
- export async function decryptMessage(buffer, authKey, authKeyId, _sessionId) {
69
+ export async function decryptMessage(buffer, authKey, _sessionId) {
70
+ const authKeyId = await getAuthKeyId(authKey);
65
71
  const reader = new TLReader(buffer);
66
72
  assertEquals(reader.readInt64(false), authKeyId);
67
73
  const messageKey_ = reader.readInt128();
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "main": "./script/mod.js",
4
4
  "types": "./types/mod.d.ts",
5
5
  "name": "@mtkruto/node",
6
- "version": "0.0.63",
6
+ "version": "0.0.72",
7
7
  "description": "MTKruto for Node.js",
8
8
  "author": "Roj <rojvv@icloud.com>",
9
9
  "license": "LGPL-3.0-or-later",
@@ -1,32 +1,56 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  Object.defineProperty(exports, "__esModule", { value: true });
3
26
  exports.Client = void 0;
4
27
  const deps_js_1 = require("../deps.js");
5
28
  const constants_js_1 = require("../constants.js");
6
29
  const _0_bigint_js_1 = require("../utilities/0_bigint.js");
7
30
  const _1_message_js_1 = require("../utilities/1_message.js");
8
- const _2_types_js_1 = require("../tl/2_types.js");
9
- const _3_functions_js_1 = require("../tl/3_functions.js");
31
+ const types = __importStar(require("../tl/2_types.js"));
32
+ const functions = __importStar(require("../tl/3_functions.js"));
10
33
  const _3_tl_reader_js_1 = require("../tl/3_tl_reader.js");
11
34
  const _4_rpc_result_js_1 = require("../tl/4_rpc_result.js");
12
35
  const _5_message_js_1 = require("../tl/5_message.js");
13
36
  const _6_message_container_js_1 = require("../tl/6_message_container.js");
14
37
  const client_abstract_js_1 = require("./client_abstract.js");
15
38
  const client_plain_js_1 = require("./client_plain.js");
39
+ const session_memory_js_1 = require("../session/session_memory.js");
16
40
  class Client extends client_abstract_js_1.ClientAbstract {
17
- constructor() {
18
- super(...arguments);
19
- Object.defineProperty(this, "sessionId", {
41
+ constructor(session = new session_memory_js_1.SessionMemory(), params) {
42
+ super(params?.transportProvider);
43
+ Object.defineProperty(this, "session", {
20
44
  enumerable: true,
21
45
  configurable: true,
22
46
  writable: true,
23
- value: (0, _0_bigint_js_1.getRandomBigInt)(8, true, false)
47
+ value: session
24
48
  });
25
- Object.defineProperty(this, "auth", {
49
+ Object.defineProperty(this, "sessionId", {
26
50
  enumerable: true,
27
51
  configurable: true,
28
52
  writable: true,
29
- value: void 0
53
+ value: (0, _0_bigint_js_1.getRandomBigInt)(8, true, false)
30
54
  });
31
55
  Object.defineProperty(this, "state", {
32
56
  enumerable: true,
@@ -54,30 +78,39 @@ class Client extends client_abstract_js_1.ClientAbstract {
54
78
  });
55
79
  }
56
80
  async connect() {
57
- const plain = new client_plain_js_1.ClientPlain(this.transportProvider);
58
- await plain.connect();
59
- const { authKey: key, authKeyId: id, salt } = await plain.createAuthKey();
60
- await plain.disconnect();
61
- this.auth = { key, id };
62
- this.state.salt = salt;
81
+ await this.session.load();
82
+ if (this.session.authKey == null) {
83
+ const plain = new client_plain_js_1.ClientPlain(this.transportProvider);
84
+ await plain.connect();
85
+ const { authKey, salt } = await plain.createAuthKey();
86
+ await plain.disconnect();
87
+ this.state.salt = salt;
88
+ this.session.authKey = authKey;
89
+ }
90
+ if (this.session.dc != null) {
91
+ const { connection, transport, dcId } = this.transportProvider({ dc: this.session.dc, cdn: false });
92
+ this.connection = connection;
93
+ this.transport = transport;
94
+ this.dcId = dcId;
95
+ }
63
96
  await super.connect();
64
97
  // logger().debug("Client connected");
65
98
  this.receiveLoop();
66
99
  this.pingLoop();
67
100
  }
68
101
  async receiveLoop() {
69
- if (!this.auth) {
102
+ if (!this.session.authKey) {
70
103
  throw new Error("Not connected");
71
104
  }
72
105
  while (this.connected) {
73
106
  if (this.toAcknowledge.size >= constants_js_1.ackThreshold) {
74
- await this.send(new _2_types_js_1.MsgsAck({ msgIds: [...this.toAcknowledge] }));
107
+ await this.send(new types.MsgsAck({ msgIds: [...this.toAcknowledge] }));
75
108
  this.toAcknowledge.clear();
76
109
  }
77
110
  const buffer = await this.transport.receive();
78
111
  let decrypted;
79
112
  try {
80
- decrypted = await (0, _1_message_js_1.decryptMessage)(buffer, this.auth.key, this.auth.id, this.sessionId);
113
+ decrypted = await (0, _1_message_js_1.decryptMessage)(buffer, this.session.authKey, this.sessionId);
81
114
  }
82
115
  catch (_err) {
83
116
  // logger().error(`Failed to decrypt message: ${err}`);
@@ -86,21 +119,21 @@ class Client extends client_abstract_js_1.ClientAbstract {
86
119
  const messages = decrypted instanceof _6_message_container_js_1.MessageContainer ? decrypted.messages : [decrypted];
87
120
  for (const message of messages) {
88
121
  let body = message.body;
89
- if (body instanceof _2_types_js_1.GZIPPacked) {
122
+ if (body instanceof types.GZIPPacked) {
90
123
  body = new _3_tl_reader_js_1.TLReader((0, deps_js_1.gunzip)(body.packedData)).readObject();
91
124
  }
92
125
  // logger().debug(`Received ${body.constructor.name}`);
93
- if (body instanceof _2_types_js_1.Updates) {
126
+ if (body instanceof types.Updates) {
94
127
  this.updatesHandler?.(this, body);
95
128
  }
96
129
  else if (message.body instanceof _4_rpc_result_js_1.RPCResult) {
97
130
  let result = message.body.result;
98
- if (result instanceof _2_types_js_1.GZIPPacked) {
131
+ if (result instanceof types.GZIPPacked) {
99
132
  result = new _3_tl_reader_js_1.TLReader((0, deps_js_1.gunzip)(result.packedData)).readObject();
100
133
  }
101
134
  const promise = this.promises.get(message.body.messageId);
102
135
  if (promise) {
103
- if (result instanceof _2_types_js_1.RPCError) {
136
+ if (result instanceof types.RPCError) {
104
137
  promise.reject(result);
105
138
  }
106
139
  else {
@@ -109,15 +142,15 @@ class Client extends client_abstract_js_1.ClientAbstract {
109
142
  this.promises.delete(message.body.messageId);
110
143
  }
111
144
  }
112
- else if (message.body instanceof _2_types_js_1.Pong) {
145
+ else if (message.body instanceof types.Pong) {
113
146
  const promise = this.promises.get(message.body.msgId);
114
147
  if (promise) {
115
148
  promise.resolve(message.body);
116
149
  this.promises.delete(message.body.msgId);
117
150
  }
118
151
  }
119
- else if (message.body instanceof _2_types_js_1.BadMsgNotification || message.body instanceof _2_types_js_1.BadServerSalt) {
120
- if (message.body instanceof _2_types_js_1.BadServerSalt) {
152
+ else if (message.body instanceof types.BadMsgNotification || message.body instanceof types.BadServerSalt) {
153
+ if (message.body instanceof types.BadServerSalt) {
121
154
  this.state.salt = message.body.newServerSalt;
122
155
  }
123
156
  const promise = this.promises.get(message.body.badMsgId);
@@ -133,7 +166,7 @@ class Client extends client_abstract_js_1.ClientAbstract {
133
166
  async pingLoop() {
134
167
  while (this.connected) {
135
168
  try {
136
- await this.invoke(new _3_functions_js_1.Ping({ pingId: (0, _0_bigint_js_1.getRandomBigInt)(8, true, false) }));
169
+ await this.invoke(new functions.Ping({ pingId: (0, _0_bigint_js_1.getRandomBigInt)(8, true, false) }));
137
170
  }
138
171
  catch (_err) {
139
172
  // logger().error(`Failed to invoke ping: ${err}`);
@@ -142,16 +175,16 @@ class Client extends client_abstract_js_1.ClientAbstract {
142
175
  }
143
176
  }
144
177
  async invoke(function_, noWait) {
145
- if (!this.auth) {
178
+ if (!this.session.authKey) {
146
179
  throw new Error("Not connected");
147
180
  }
148
181
  let seqNo = this.state.seqNo * 2;
149
- if (!(function_ instanceof _3_functions_js_1.Ping) && !(function_ instanceof _2_types_js_1.MsgsAck)) {
182
+ if (!(function_ instanceof functions.Ping) && !(function_ instanceof types.MsgsAck)) {
150
183
  seqNo++;
151
184
  this.state.seqNo++;
152
185
  }
153
186
  const message = new _5_message_js_1.Message((0, _1_message_js_1.getMessageId)(), seqNo, function_);
154
- await this.transport.send(await (0, _1_message_js_1.encryptMessage)(message, this.auth.key, this.auth.id, this.state.salt, this.sessionId));
187
+ await this.transport.send(await (0, _1_message_js_1.encryptMessage)(message, this.session.authKey, this.state.salt, this.sessionId));
155
188
  // logger().debug(`Invoked ${function_.constructor.name}`);
156
189
  if (noWait) {
157
190
  return;
@@ -159,7 +192,7 @@ class Client extends client_abstract_js_1.ClientAbstract {
159
192
  const result = await new Promise((resolve, reject) => {
160
193
  this.promises.set(message.id, { resolve, reject });
161
194
  });
162
- if (result instanceof _2_types_js_1.BadServerSalt) {
195
+ if (result instanceof types.BadServerSalt) {
163
196
  return await this.invoke(function_);
164
197
  }
165
198
  else {
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ClientAbstract = void 0;
4
- const transport_provider_js_1 = require("../transport/transport_provider.js");
5
4
  const deps_js_1 = require("../deps.js");
5
+ const transport_provider_js_1 = require("../transport/transport_provider.js");
6
6
  class ClientAbstract {
7
7
  constructor(transportProvider = (0, transport_provider_js_1.defaultTransportProvider)()) {
8
8
  Object.defineProperty(this, "transportProvider", {
@@ -35,7 +35,7 @@ class ClientAbstract {
35
35
  writable: true,
36
36
  value: false
37
37
  });
38
- const { connection, transport, dcId } = transportProvider(false);
38
+ const { connection, transport, dcId } = transportProvider({ dc: transport_provider_js_1.defaultDc, cdn: false });
39
39
  this.connection = connection;
40
40
  this.transport = transport;
41
41
  this.dcId = dcId;
@@ -104,11 +104,9 @@ class ClientPlain extends client_abstract_js_1.ClientAbstract {
104
104
  const salt = newNonce_.slice(0, 0 + 8).map((v, i) => v ^ serverNonceSlice[i]);
105
105
  const authKey_ = (0, _0_bigint_js_1.modExp)(gA, b, dhPrime);
106
106
  const authKey = (0, _0_buffer_js_1.bufferFromBigInt)(authKey_, 256, false, false);
107
- const authKeyId = (await (0, _0_hash_js_1.sha1)(authKey)).slice(-8);
108
107
  // logger().debug("Auth key created");
109
108
  return {
110
109
  authKey,
111
- authKeyId: (0, _0_bigint_js_1.bigIntFromBuffer)(authKeyId, true, false),
112
110
  salt: (0, _0_bigint_js_1.bigIntFromBuffer)(salt, true, false),
113
111
  };
114
112
  }
package/script/mod.js CHANGED
@@ -32,10 +32,17 @@ const _0_bigint_js_1 = require("./utilities/0_bigint.js");
32
32
  exports.utils = { checkPassword: _1_password_js_1.checkPassword, getRandomId: _0_bigint_js_1.getRandomId };
33
33
  exports.types = __importStar(require("./tl/2_types.js"));
34
34
  exports.functions = __importStar(require("./tl/3_functions.js"));
35
+ __exportStar(require("./tl/4_rpc_result.js"), exports);
36
+ __exportStar(require("./tl/5_message.js"), exports);
37
+ __exportStar(require("./tl/6_message_container.js"), exports);
35
38
  __exportStar(require("./client/client_plain.js"), exports);
36
39
  __exportStar(require("./client/client.js"), exports);
40
+ __exportStar(require("./session/session.js"), exports);
41
+ __exportStar(require("./session/session_memory.js"), exports);
42
+ __exportStar(require("./session/session_local_storage.js"), exports);
37
43
  __exportStar(require("./transport/transport_abridged.js"), exports);
38
44
  __exportStar(require("./transport/transport_intermediate.js"), exports);
39
45
  __exportStar(require("./transport/transport.js"), exports);
40
46
  __exportStar(require("./transport/transport_provider.js"), exports);
41
47
  __exportStar(require("./connection/connection.js"), exports);
48
+ __exportStar(require("./connection/connection_web_socket.js"), exports);
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Session = void 0;
4
+ class Session {
5
+ constructor() {
6
+ Object.defineProperty(this, "dc", {
7
+ enumerable: true,
8
+ configurable: true,
9
+ writable: true,
10
+ value: null
11
+ });
12
+ Object.defineProperty(this, "authKey", {
13
+ enumerable: true,
14
+ configurable: true,
15
+ writable: true,
16
+ value: null
17
+ });
18
+ }
19
+ }
20
+ exports.Session = Session;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SessionLocalStorage = void 0;
4
+ const session_js_1 = require("./session.js");
5
+ class SessionLocalStorage extends session_js_1.Session {
6
+ constructor(key) {
7
+ if (typeof localStorage == "undefined") {
8
+ throw new Error("Unavailable in current environment");
9
+ }
10
+ super();
11
+ Object.defineProperty(this, "key", {
12
+ enumerable: true,
13
+ configurable: true,
14
+ writable: true,
15
+ value: key
16
+ });
17
+ }
18
+ load() {
19
+ const { dc = null, authKey = null } = JSON.parse(localStorage.getItem(this.key) ?? "{}");
20
+ this.dc = dc;
21
+ if (authKey != null) {
22
+ this.authKey = new Uint8Array(authKey.split(/([0-9a-f]{2})/).filter((v) => v).map((v) => parseInt(v, 16)));
23
+ }
24
+ }
25
+ save() {
26
+ const authKey = this.authKey == null ? undefined : Array.from(this.authKey).map((v) => v.toString(16)).map((v) => v.padStart(2, "0"));
27
+ localStorage.setItem(this.key, JSON.stringify({ dc: this.dc, authKey }));
28
+ }
29
+ }
30
+ exports.SessionLocalStorage = SessionLocalStorage;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SessionMemory = void 0;
4
+ const session_js_1 = require("./session.js");
5
+ class SessionMemory extends session_js_1.Session {
6
+ load() { }
7
+ save() { }
8
+ }
9
+ exports.SessionMemory = SessionMemory;
@@ -14,14 +14,14 @@ const dcToNameMap = {
14
14
  "4": "vesta",
15
15
  "5": "flora",
16
16
  };
17
- const defaultTransportProvider = (params) => {
18
- return (cdn) => {
19
- const { dc, wss = typeof location !== "undefined" && location.protocol == "http:" ? false : true } = params ?? { dc: exports.defaultDc };
17
+ function defaultTransportProvider(wss) {
18
+ return ({ dc, cdn }) => {
19
+ wss ??= typeof location !== "undefined" && location.protocol == "http:" ? false : true;
20
20
  const url = `${wss ? "wss" : "ws"}://${dcToNameMap[dc]}${cdn ? "-1" : ""}.web.telegram.org/${dc.endsWith("-test") ? "apiws_test" : "apiws"}`;
21
21
  const connection = new connection_web_socket_js_1.ConnectionWebSocket(url);
22
22
  const transport = new transport_intermediate_js_1.TransportIntermediate(connection, true);
23
23
  const dcId = Number(dc[0]) + (dc.endsWith("-test") ? 10000 : 0) * (cdn ? -1 : 1);
24
24
  return { connection, transport, dcId };
25
25
  };
26
- };
26
+ }
27
27
  exports.defaultTransportProvider = defaultTransportProvider;
@@ -9,8 +9,12 @@ const _3_tl_reader_js_1 = require("../tl/3_tl_reader.js");
9
9
  const _4_rpc_result_js_1 = require("../tl/4_rpc_result.js");
10
10
  const _5_message_js_1 = require("../tl/5_message.js");
11
11
  const _6_message_container_js_1 = require("../tl/6_message_container.js");
12
+ const _0_bigint_js_1 = require("./0_bigint.js");
12
13
  const _0_buffer_js_1 = require("./0_buffer.js");
13
14
  const _0_hash_js_1 = require("./0_hash.js");
15
+ async function getAuthKeyId(authKey) {
16
+ return (0, _0_bigint_js_1.bigIntFromBuffer)((await (0, _0_hash_js_1.sha1)(authKey)).slice(-8), true, false);
17
+ }
14
18
  let lastMsgId = 0n;
15
19
  function getMessageId() {
16
20
  const now = new Date().getTime() / 1000 + 0;
@@ -39,8 +43,9 @@ function unpackUnencryptedMessage(buffer) {
39
43
  return { messageId, message };
40
44
  }
41
45
  exports.unpackUnencryptedMessage = unpackUnencryptedMessage;
42
- async function encryptMessage(message, authKey, authKeyId, salt, sessionId) {
46
+ async function encryptMessage(message, authKey, salt, sessionId) {
43
47
  const encoded = message.body.serialize();
48
+ const authKeyId = await getAuthKeyId(authKey);
44
49
  const payloadWriter = new _0_tl_raw_writer_js_1.TLRawWriter();
45
50
  payloadWriter.writeInt64(salt);
46
51
  payloadWriter.writeInt64(sessionId);
@@ -68,7 +73,8 @@ async function encryptMessage(message, authKey, authKeyId, salt, sessionId) {
68
73
  return messageWriter.buffer;
69
74
  }
70
75
  exports.encryptMessage = encryptMessage;
71
- async function decryptMessage(buffer, authKey, authKeyId, _sessionId) {
76
+ async function decryptMessage(buffer, authKey, _sessionId) {
77
+ const authKeyId = await getAuthKeyId(authKey);
72
78
  const reader = new _3_tl_reader_js_1.TLReader(buffer);
73
79
  (0, deps_js_1.assertEquals)(reader.readInt64(false), authKeyId);
74
80
  const messageKey_ = reader.readInt128();
@@ -1,19 +1,24 @@
1
1
  import { MaybePromise } from "../types.js";
2
- import { Type, Updates } from "../tl/2_types.js";
3
- import { Function } from "../tl/3_functions.js";
2
+ import * as types from "../tl/2_types.js";
3
+ import * as functions from "../tl/3_functions.js";
4
4
  import { ClientAbstract } from "./client_abstract.js";
5
- export type UpdatesHandler = null | ((client: Client, update: Updates) => MaybePromise<void>);
5
+ import { Session } from "../session/session.js";
6
+ import { TransportProvider } from "../transport/transport_provider.js";
7
+ export type UpdatesHandler = null | ((client: Client, update: types.Updates) => MaybePromise<void>);
6
8
  export declare class Client extends ClientAbstract {
9
+ readonly session: Session;
7
10
  private sessionId;
8
- private auth?;
9
11
  private state;
10
12
  private promises;
11
13
  private toAcknowledge;
12
14
  updatesHandler: UpdatesHandler;
15
+ constructor(session?: Session, params?: {
16
+ transportProvider?: TransportProvider;
17
+ });
13
18
  connect(): Promise<void>;
14
19
  private receiveLoop;
15
20
  private pingLoop;
16
- invoke<T extends (Function<unknown> | Type) = Function<unknown>>(function_: T): Promise<T extends Function<unknown> ? T["__R"] : void>;
17
- invoke<T extends (Function<unknown> | Type) = Function<unknown>>(function_: T, noWait: true): Promise<void>;
18
- send<T extends (Function<unknown> | Type) = Function<unknown>>(function_: T): Promise<void>;
21
+ invoke<T extends (functions.Function<unknown> | types.Type) = functions.Function<unknown>>(function_: T): Promise<T extends functions.Function<unknown> ? T["__R"] : void>;
22
+ invoke<T extends (functions.Function<unknown> | types.Type) = functions.Function<unknown>>(function_: T, noWait: true): Promise<void>;
23
+ send<T extends (functions.Function<unknown> | types.Type) = functions.Function<unknown>>(function_: T): Promise<void>;
19
24
  }
@@ -1,20 +1,12 @@
1
1
  import { Connection } from "../connection/connection.js";
2
2
  import { Transport } from "../transport/transport.js";
3
3
  export declare abstract class ClientAbstract {
4
- protected transportProvider: (cdn: boolean) => {
5
- connection: Connection;
6
- transport: Transport;
7
- dcId: number;
8
- };
9
- connection: Connection;
10
- transport: Transport;
4
+ protected transportProvider: import("../transport/transport_provider.js").TransportProvider;
5
+ protected connection: Connection;
6
+ protected transport: Transport;
11
7
  dcId: number;
12
8
  protected connected: boolean;
13
- constructor(transportProvider?: (cdn: boolean) => {
14
- connection: Connection;
15
- transport: Transport;
16
- dcId: number;
17
- });
9
+ constructor(transportProvider?: import("../transport/transport_provider.js").TransportProvider);
18
10
  connect(): Promise<void>;
19
11
  disconnect(): Promise<void>;
20
12
  }
@@ -4,7 +4,6 @@ export declare class ClientPlain extends ClientAbstract {
4
4
  invoke<T extends Function<unknown>>(function_: T): Promise<T["__R"]>;
5
5
  createAuthKey(): Promise<{
6
6
  authKey: Uint8Array;
7
- authKeyId: bigint;
8
7
  salt: bigint;
9
8
  }>;
10
9
  }
package/types/mod.d.ts CHANGED
@@ -6,10 +6,17 @@ export declare const utils: {
6
6
  };
7
7
  export * as types from "./tl/2_types.js";
8
8
  export * as functions from "./tl/3_functions.js";
9
+ export * from "./tl/4_rpc_result.js";
10
+ export * from "./tl/5_message.js";
11
+ export * from "./tl/6_message_container.js";
9
12
  export * from "./client/client_plain.js";
10
13
  export * from "./client/client.js";
14
+ export * from "./session/session.js";
15
+ export * from "./session/session_memory.js";
16
+ export * from "./session/session_local_storage.js";
11
17
  export * from "./transport/transport_abridged.js";
12
18
  export * from "./transport/transport_intermediate.js";
13
19
  export * from "./transport/transport.js";
14
20
  export * from "./transport/transport_provider.js";
15
21
  export * from "./connection/connection.js";
22
+ export * from "./connection/connection_web_socket.js";
@@ -0,0 +1,8 @@
1
+ import { MaybePromise } from "../types.js";
2
+ import { TransportProviderParams } from "../transport/transport_provider.js";
3
+ export declare abstract class Session {
4
+ dc: TransportProviderParams["dc"] | null;
5
+ authKey: Uint8Array | null;
6
+ abstract load(): MaybePromise<void>;
7
+ abstract save(): MaybePromise<void>;
8
+ }
@@ -0,0 +1,7 @@
1
+ import { Session } from "./session.js";
2
+ export declare class SessionLocalStorage extends Session implements Session {
3
+ private readonly key;
4
+ constructor(key: string);
5
+ load(): void;
6
+ save(): void;
7
+ }
@@ -0,0 +1,5 @@
1
+ import { Session } from "./session.js";
2
+ export declare class SessionMemory extends Session implements Session {
3
+ load(): void;
4
+ save(): void;
5
+ }
@@ -2,11 +2,12 @@ import { Connection } from "../connection/connection.js";
2
2
  import { Transport } from "./transport.js";
3
3
  export interface TransportProviderParams {
4
4
  dc: "1" | "2" | "3" | "4" | "5" | "1-test" | "2-test" | "3-test";
5
+ cdn: boolean;
5
6
  }
6
- export type TransportProvider = (params?: TransportProviderParams) => (cdn: boolean) => {
7
+ export type TransportProvider = (params: TransportProviderParams) => {
7
8
  connection: Connection;
8
9
  transport: Transport;
9
10
  dcId: number;
10
11
  };
11
12
  export declare const defaultDc: TransportProviderParams["dc"];
12
- export declare const defaultTransportProvider: TransportProvider;
13
+ export declare function defaultTransportProvider(wss?: boolean): TransportProvider;
@@ -6,5 +6,5 @@ export declare function unpackUnencryptedMessage(buffer: Uint8Array): {
6
6
  messageId: bigint;
7
7
  message: Uint8Array;
8
8
  };
9
- export declare function encryptMessage(message: Message, authKey: Uint8Array, authKeyId: bigint, salt: bigint, sessionId: bigint): Promise<Uint8Array>;
10
- export declare function decryptMessage(buffer: Uint8Array, authKey: Uint8Array, authKeyId: bigint, _sessionId: bigint): Promise<Message | MessageContainer>;
9
+ export declare function encryptMessage(message: Message, authKey: Uint8Array, salt: bigint, sessionId: bigint): Promise<Uint8Array>;
10
+ export declare function decryptMessage(buffer: Uint8Array, authKey: Uint8Array, _sessionId: bigint): Promise<Message | MessageContainer>;