dograma
Version:
NodeJS/Browser MTProto API Telegram client library,
125 lines (112 loc) • 4 kB
text/typescript
import { MemorySession } from "./Memory";
import { BinaryReader } from "../extensions";
import { AuthKey } from "../crypto/AuthKey";
const CURRENT_VERSION = "1";
export class StringSession extends MemorySession {
_key?: Buffer;
/**
* This session file can be easily saved and loaded as a string. According
* to the initial design, it contains only the data that is necessary for
* successful connection and authentication, so takeout ID is not stored.
* It is thought to be used where you don't want to create any on-disk
* files but would still like to be able to save and load existing sessions
* by other means.
* You can use custom `encode` and `decode` functions, if present:
* `encode` definition must be ``function encode(value: Buffer) -> string:``.
* `decode` definition must be ``function decode(value: string) -> Buffer:``.
* @param session {string|null}
*/
constructor(session?: string) {
super();
if (session) {
if (session[0] !== CURRENT_VERSION) {
throw new Error("Not a valid string");
}
session = session.slice(1);
const r = StringSession.decode(session);
const reader = new BinaryReader(r);
this._dcId = reader.read(1).readUInt8(0);
if (session.length == 352) {
// Telethon session
const ip_v4 = reader.read(4);
// TODO looks ugly smh
this._serverAddress =
ip_v4[0].toString() +
"." +
ip_v4[1].toString() +
"." +
ip_v4[2].toString() +
"." +
ip_v4[3].toString();
} else {
// TODO find a better of doing this
const serverAddressLen = reader.read(2).readInt16BE(0);
if (serverAddressLen > 100) {
reader.offset -= 2;
this._serverAddress = reader
.read(16)
.toString("hex")
.match(/.{1,4}/g)!
.map((val) => val.replace(/^0+/, ""))
.join(":")
.replace(/0000\:/g, ":")
.replace(/:{2,}/g, "::");
} else {
this._serverAddress = reader
.read(serverAddressLen)
.toString();
}
}
this._port = reader.read(2).readInt16BE(0);
this._key = reader.read(-1);
}
}
/**
* @param x {Buffer}
* @returns {string}
*/
static encode(x: Buffer) {
return x.toString("base64");
}
/**
* @param x {string}
* @returns {Buffer}
*/
static decode(x: string) {
return Buffer.from(x, "base64");
}
async load() {
if (this._key) {
this._authKey = new AuthKey();
await this._authKey.setKey(this._key);
}
}
save() {
if (!this.authKey || !this.serverAddress || !this.port) {
return "";
}
// TS is weird
const key = this.authKey.getKey();
if (!key) {
return "";
}
const dcBuffer = Buffer.from([this.dcId]);
const addressBuffer = Buffer.from(this.serverAddress);
const addressLengthBuffer = Buffer.alloc(2);
addressLengthBuffer.writeInt16BE(addressBuffer.length, 0);
const portBuffer = Buffer.alloc(2);
portBuffer.writeInt16BE(this.port, 0);
return (
CURRENT_VERSION +
StringSession.encode(
Buffer.concat([
dcBuffer,
addressLengthBuffer,
addressBuffer,
portBuffer,
key,
])
)
);
}
}