/
StringSession.ts
124 lines (112 loc) · 3.91 KB
/
StringSession.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
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,
])
)
);
}
}