tgsnake
Version:
Telegram MTProto framework for nodejs.
305 lines (304 loc) • 14.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SnakeSession = void 0;
exports.buildBytesFromPeer = buildBytesFromPeer;
exports.buildPeerFromBytes = buildPeerFromBytes;
exports.buildBytesFromSecretChat = buildBytesFromSecretChat;
exports.buildSecretChatFromBytes = buildSecretChatFromBytes;
exports.generateName = generateName;
const platform_node_js_1 = require("../platform.node.js");
const Logger_js_1 = require("../Context/Logger.js");
class SnakeSession extends platform_node_js_1.Storages.BaseSession {
_name;
_sessionDir;
_sessionExt;
_cacheDir;
_cacheExt;
constructor(name, sessionDir, sessionExt, cacheDir, cacheExt) {
super();
this._name = name;
this._sessionDir = sessionDir;
this._sessionExt = sessionExt;
this._cacheDir = cacheDir;
this._cacheExt = cacheExt;
}
async load() {
const sessionName = `${this._name}.${this._sessionExt.replace(/^\./, '')}`;
if (platform_node_js_1.fs.existsSync(platform_node_js_1.path.join(this._sessionDir, sessionName))) {
const start = Math.floor(Date.now() / 1000);
const bytes = platform_node_js_1.fs.readFileSync(platform_node_js_1.path.join(this._sessionDir, sessionName));
Logger_js_1.Logger.debug(`Session have a ${platform_node_js_1.Buffer.byteLength(bytes)} bytes`);
this._dcId = bytes.readUInt8(0);
Logger_js_1.Logger.debug(`Found dcId: ${this._dcId}.`);
this._apiId = bytes.readUInt32LE(1);
Logger_js_1.Logger.debug(`Found apiId: ${this._apiId}.`);
this._testMode = bytes.readUInt8(5) ? true : false;
Logger_js_1.Logger.debug(`Found testMode: ${this._testMode}.`);
this._authKey = bytes.subarray(6, 262);
Logger_js_1.Logger.debug(`Found authKey: ${this._authKey.length} bytes.`);
this._userId = BigInt(`0x${bytes.subarray(262, 270).toString('hex')}`);
Logger_js_1.Logger.debug(`Found userId: ${this._userId}.`);
this._isBot = bytes.readUInt8(270) ? true : false;
Logger_js_1.Logger.debug(`Found isBot: ${this._isBot}.`);
Logger_js_1.Logger.debug(`Done parsing string session (${Math.floor(Date.now() / 1000) - start}s)`);
}
const [peers, secretChats] = await this._loadCache();
for (const peer of peers) {
this._peers.set(peer[0], peer);
}
for (const secretChat of secretChats) {
this._secretChats.set(secretChat.id, secretChat);
}
}
async save() {
const sessionName = `${this._name}.${this._sessionExt.replace(/^\./, '')}`;
const cacheName = `${this._name}.${this._cacheExt.replace(/^\./, '')}`;
if (!platform_node_js_1.fs.existsSync(platform_node_js_1.path.join(this._sessionDir, sessionName))) {
platform_node_js_1.fs.writeFileSync(platform_node_js_1.path.join(this._sessionDir, sessionName), platform_node_js_1.Buffer.from(platform_node_js_1.Helpers.base64urlTobase64(await this.exportString()), 'base64'));
Logger_js_1.Logger.info(`Session saved to: "${platform_node_js_1.path.join(this._sessionDir, sessionName)}".`);
}
platform_node_js_1.fs.writeFileSync(platform_node_js_1.path.join(this._cacheDir, cacheName), await this._makeCache());
Logger_js_1.Logger.info(`Cache saved to: "${platform_node_js_1.path.join(this._cacheDir, cacheName)}".`);
}
async _loadCache() {
const peer = [];
const cacheName = `${this._name}.${this._cacheExt.replace(/^\./, '')}`;
let e2e = [];
if (platform_node_js_1.fs.existsSync(platform_node_js_1.path.join(this._cacheDir, cacheName))) {
const buffer = platform_node_js_1.fs.readFileSync(platform_node_js_1.path.join(this._cacheDir, cacheName));
if (buffer[0] === 2) {
Logger_js_1.Logger.info(`Load cache version: 2`);
const bytes = new platform_node_js_1.Raws.BytesIO(buffer.subarray(1));
const cacheLength = await platform_node_js_1.Raws.Primitive.Int.read(bytes);
const cacheBytes = new platform_node_js_1.Raws.BytesIO(await bytes.read(cacheLength));
const peerLength = await platform_node_js_1.Raws.Primitive.Int.read(cacheBytes);
const E2ELength = await platform_node_js_1.Raws.Primitive.Int.read(bytes);
if (E2ELength) {
e2e = await this._loadE2E(await bytes.read(E2ELength));
}
for (let i = 0; i < peerLength; i++) {
const count = await platform_node_js_1.Raws.Primitive.Int.read(cacheBytes);
peer.push(await buildPeerFromBytes(cacheBytes.read(count)));
}
}
else {
Logger_js_1.Logger.info(`Load cache version: 1`);
const bytes = new platform_node_js_1.Raws.BytesIO(buffer);
const length = await platform_node_js_1.Raws.Primitive.Int.read(bytes);
for (let i = 0; i < length; i++) {
const count = await platform_node_js_1.Raws.Primitive.Int.read(bytes);
peer.push(await buildPeerFromBytes(bytes.read(count)));
}
}
}
return [
peer,
e2e,
];
}
async _loadE2E(bytes) {
const secretChat = [];
if (bytes[0] === 1) {
const b = new platform_node_js_1.Raws.BytesIO(bytes.subarray(1));
const length = await platform_node_js_1.Raws.Primitive.Int.read(b);
for (let i = 0; i < length; i++) {
const count = await platform_node_js_1.Raws.Primitive.Int.read(b);
secretChat.push(await buildSecretChatFromBytes(b.read(count)));
}
}
return secretChat;
}
async _makeCache() {
let count = 0;
const bytes = new platform_node_js_1.Raws.BytesIO();
for (const [, value] of this._peers) {
count += 1;
const content = await buildBytesFromPeer(value);
bytes.write(platform_node_js_1.Buffer.concat([platform_node_js_1.Raws.Primitive.Int.write(content.length), content]));
}
let e2e = platform_node_js_1.Buffer.alloc(0);
if (this._secretChats.size) {
e2e = await this._makeE2E();
}
const cache = platform_node_js_1.Buffer.concat([platform_node_js_1.Raws.Primitive.Int.write(count), bytes.buffer]);
return platform_node_js_1.Buffer.concat([
platform_node_js_1.Buffer.from([2]),
platform_node_js_1.Raws.Primitive.Int.write(cache.length),
cache,
platform_node_js_1.Raws.Primitive.Int.write(e2e.length),
e2e,
]);
}
async _makeE2E() {
let count = 0;
const bytes = new platform_node_js_1.Raws.BytesIO();
for (const [, value] of this._secretChats) {
count += 1;
const content = await buildBytesFromSecretChat(value);
bytes.write(platform_node_js_1.Buffer.concat([platform_node_js_1.Raws.Primitive.Int.write(content.length), content]));
}
return platform_node_js_1.Buffer.concat([platform_node_js_1.Buffer.from([1]), platform_node_js_1.Raws.Primitive.Int.write(count), bytes.buffer]);
}
[Symbol.for('nodejs.util.inspect.custom')]() {
const toPrint = {
_: this.constructor.name,
};
for (const key in this) {
if (this.hasOwnProperty(key)) {
const value = this[key];
if (!key.startsWith('_')) {
toPrint[key] = value;
}
}
}
return toPrint;
}
toJSON() {
const toPrint = {
_: this.constructor.name,
};
for (const key in this) {
if (this.hasOwnProperty(key)) {
const value = this[key];
if (!key.startsWith('_')) {
toPrint[key] = typeof value === 'bigint' ? String(value) : value;
}
}
}
return toPrint;
}
toString() {
return `[constructor of ${this.constructor.name}] ${JSON.stringify(this, null, 2)}`;
}
}
exports.SnakeSession = SnakeSession;
function buildBytesFromPeer(peer) {
const bytes = new platform_node_js_1.Raws.BytesIO();
let flags = 0;
if (peer[3]) {
flags |= 1 << 6;
}
if (peer[4]) {
flags |= 1 << 5;
}
bytes.write(platform_node_js_1.Raws.Primitive.Int.write(flags));
bytes.write(platform_node_js_1.Raws.Primitive.Long.write(peer[0]));
bytes.write(platform_node_js_1.Raws.Primitive.Long.write(peer[1]));
bytes.write(platform_node_js_1.Raws.Primitive.String.write(peer[2]));
if (peer[3]) {
bytes.write(platform_node_js_1.Raws.Primitive.Vector.write(peer[3] || [], platform_node_js_1.Raws.Primitive.String));
}
if (peer[4]) {
bytes.write(platform_node_js_1.Raws.Primitive.String.write(peer[4]));
}
return bytes.buffer;
}
async function buildPeerFromBytes(bytes) {
const b = new platform_node_js_1.Raws.BytesIO(bytes);
const results = [];
const flags = await platform_node_js_1.Raws.Primitive.Int.read(b);
results.push(await platform_node_js_1.Raws.Primitive.Long.read(b));
results.push(await platform_node_js_1.Raws.Primitive.Long.read(b));
results.push(await platform_node_js_1.Raws.Primitive.String.read(b));
if (flags & (1 << 4)) {
results.push([await platform_node_js_1.Raws.Primitive.String.read(b)]);
}
else if (flags & (1 << 6)) {
await platform_node_js_1.Raws.Primitive.Int.read(b, false);
results.push(await platform_node_js_1.Raws.Primitive.Vector.read(b, platform_node_js_1.Raws.Primitive.String));
}
if (flags & (1 << 5)) {
results.push(await platform_node_js_1.Raws.Primitive.String.read(b));
}
return results;
}
function buildBytesFromSecretChat(secretChat) {
const bytes = new platform_node_js_1.Raws.BytesIO();
let flags = 0;
if (secretChat.rekeyStep) {
flags |= 1 << 3;
}
if (secretChat.rekeyExchange) {
flags |= 1 << 4;
}
if (secretChat.adminId) {
flags |= 1 << 5;
}
if (secretChat.ttl) {
flags |= 1 << 6;
}
bytes.write(platform_node_js_1.Raws.Primitive.Int.write(flags));
bytes.write(platform_node_js_1.Raws.Primitive.Int.write(secretChat.id));
bytes.write(platform_node_js_1.Raws.Primitive.Long.write(secretChat.accessHash));
bytes.write(platform_node_js_1.Raws.Primitive.Bool.write(secretChat.isAdmin));
bytes.write(platform_node_js_1.Raws.Primitive.Bytes.write(secretChat.authKey));
bytes.write(platform_node_js_1.Raws.Primitive.Int.write(secretChat.mtproto));
bytes.write(platform_node_js_1.Raws.Primitive.Int.write(secretChat.layer));
bytes.write(platform_node_js_1.Raws.Primitive.Int.write(secretChat.inSeqNo));
bytes.write(platform_node_js_1.Raws.Primitive.Int.write(secretChat.outSeqNo));
bytes.write(platform_node_js_1.Raws.Primitive.Int.write(secretChat.inSeqNoX));
bytes.write(platform_node_js_1.Raws.Primitive.Int.write(secretChat.outSeqNoX));
bytes.write(platform_node_js_1.Raws.Primitive.Int.write(secretChat.timeRekey));
bytes.write(platform_node_js_1.Raws.Primitive.Float.write(secretChat.created));
bytes.write(platform_node_js_1.Raws.Primitive.Float.write(secretChat.changed));
if (secretChat.rekeyStep) {
bytes.write(platform_node_js_1.Raws.Primitive.Int.write(secretChat.rekeyStep));
}
if (secretChat.rekeyExchange) {
bytes.write(platform_node_js_1.Raws.Primitive.Long.write(secretChat.rekeyExchange));
}
if (secretChat.adminId) {
bytes.write(platform_node_js_1.Raws.Primitive.Long.write(secretChat.adminId));
}
if (secretChat.ttl) {
bytes.write(platform_node_js_1.Raws.Primitive.Int.write(secretChat.ttl));
}
return bytes.buffer;
}
async function buildSecretChatFromBytes(bytes) {
const b = new platform_node_js_1.Raws.BytesIO(bytes);
const flags = await platform_node_js_1.Raws.Primitive.Int.read(b);
const id = await platform_node_js_1.Raws.Primitive.Int.read(b);
const accessHash = await platform_node_js_1.Raws.Primitive.Long.read(b);
const isAdmin = await platform_node_js_1.Raws.Primitive.Bool.read(b);
const authKey = await platform_node_js_1.Raws.Primitive.Bytes.read(b);
const secretChat = new platform_node_js_1.Storages.SecretChat({
id,
accessHash,
isAdmin,
authKey,
});
secretChat.mtproto = await platform_node_js_1.Raws.Primitive.Int.read(b);
secretChat.layer = await platform_node_js_1.Raws.Primitive.Int.read(b);
secretChat.inSeqNo = await platform_node_js_1.Raws.Primitive.Int.read(b);
secretChat.outSeqNo = await platform_node_js_1.Raws.Primitive.Int.read(b);
secretChat.inSeqNoX = await platform_node_js_1.Raws.Primitive.Int.read(b);
secretChat.outSeqNoX = await platform_node_js_1.Raws.Primitive.Int.read(b);
secretChat.timeRekey = await platform_node_js_1.Raws.Primitive.Int.read(b);
secretChat.created = await platform_node_js_1.Raws.Primitive.Float.read(b);
secretChat.changed = await platform_node_js_1.Raws.Primitive.Float.read(b);
if (flags & (1 << 3)) {
secretChat.rekeyStep = await platform_node_js_1.Raws.Primitive.Int.read(b);
}
if (flags & (1 << 4)) {
secretChat.rekeyExchange = await platform_node_js_1.Raws.Primitive.Long.read(b);
}
if (flags & (1 << 5)) {
secretChat.adminId = await platform_node_js_1.Raws.Primitive.Long.read(b);
}
if (flags & (1 << 6)) {
secretChat.ttl = await platform_node_js_1.Raws.Primitive.Int.read(b);
}
return secretChat;
}
function generateName(base, loginPath, loginExt, cachePath, cacheExt) {
let i = 0;
while (true) {
const name = i === 0 ? base : `${base}${i}`;
if (!platform_node_js_1.fs.existsSync(platform_node_js_1.path.join(loginPath, `${name}.${loginExt.replace(/^\./, '')}`)) &&
!platform_node_js_1.fs.existsSync(platform_node_js_1.path.join(cachePath, `${name}.${cacheExt.replace(/^\./, '')}`))) {
return name;
}
i++;
}
}