dograma
Version:
NodeJS/Browser MTProto API Telegram client library,
122 lines (121 loc) • 4.67 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConnectionTCPMTProxyAbridged = exports.TCPMTProxy = void 0;
const Connection_1 = require("./Connection");
const TCPAbridged_1 = require("./TCPAbridged");
const Helpers_1 = require("../../Helpers");
const CTR_1 = require("../../crypto/CTR");
class MTProxyIO {
constructor(connection) {
this.header = undefined;
this.connection = connection.socket;
this._packetClass =
connection.PacketCodecClass;
this._secret = connection._secret;
this._dcId = connection._dcId;
}
async initHeader() {
let secret = this._secret;
const isDD = secret.length == 17 && secret[0] == 0xdd;
secret = isDD ? secret.slice(1) : secret;
if (secret.length != 16) {
throw new Error("MTProxy secret must be a hex-string representing 16 bytes");
}
const keywords = [
Buffer.from("50567247", "hex"),
Buffer.from("474554", "hex"),
Buffer.from("504f5354", "hex"),
Buffer.from("eeeeeeee", "hex"),
];
let random;
// eslint-disable-next-line no-constant-condition
while (true) {
random = (0, Helpers_1.generateRandomBytes)(64);
if (random[0] !== 0xef &&
!random.slice(4, 8).equals(Buffer.alloc(4))) {
let ok = true;
for (const key of keywords) {
if (key.equals(random.slice(0, 4))) {
ok = false;
break;
}
}
if (ok) {
break;
}
}
}
random = random.toJSON().data;
const randomReversed = Buffer.from(random.slice(8, 56)).reverse();
// Encryption has "continuous buffer" enabled
const encryptKey = await (0, Helpers_1.sha256)(Buffer.concat([Buffer.from(random.slice(8, 40)), secret]));
const encryptIv = Buffer.from(random.slice(40, 56));
const decryptKey = await (0, Helpers_1.sha256)(Buffer.concat([Buffer.from(randomReversed.slice(0, 32)), secret]));
const decryptIv = Buffer.from(randomReversed.slice(32, 48));
const encryptor = new CTR_1.CTR(encryptKey, encryptIv);
const decryptor = new CTR_1.CTR(decryptKey, decryptIv);
random = Buffer.concat([
Buffer.from(random.slice(0, 56)),
this._packetClass.obfuscateTag,
Buffer.from(random.slice(60)),
]);
const dcIdBytes = Buffer.alloc(2);
dcIdBytes.writeInt8(this._dcId, 0);
random = Buffer.concat([
Buffer.from(random.slice(0, 60)),
dcIdBytes,
Buffer.from(random.slice(62)),
]);
random = Buffer.concat([
Buffer.from(random.slice(0, 56)),
Buffer.from(encryptor.encrypt(random).slice(56, 64)),
Buffer.from(random.slice(64)),
]);
this.header = random;
this._encrypt = encryptor;
this._decrypt = decryptor;
}
async read(n) {
const data = await this.connection.readExactly(n);
return this._decrypt.encrypt(data);
}
write(data) {
this.connection.write(this._encrypt.encrypt(data));
}
}
class TCPMTProxy extends Connection_1.ObfuscatedConnection {
constructor({ ip, port, dcId, loggers, proxy, socket, testServers, }) {
super({
ip: proxy.ip,
port: proxy.port,
dcId: dcId,
loggers: loggers,
socket: socket,
proxy: proxy,
testServers: testServers,
});
this.ObfuscatedIO = MTProxyIO;
if (!proxy.MTProxy) {
throw new Error("This connection only supports MPTProxies");
}
if (!proxy.secret) {
throw new Error("You need to provide the secret for the MTProxy");
}
if (proxy.secret && proxy.secret.match(/^[0-9a-f]+$/i)) {
// probably hex
this._secret = Buffer.from(proxy.secret, "hex");
}
else {
// probably b64
this._secret = Buffer.from(proxy.secret, "base64");
}
}
}
exports.TCPMTProxy = TCPMTProxy;
class ConnectionTCPMTProxyAbridged extends TCPMTProxy {
constructor() {
super(...arguments);
this.PacketCodecClass = TCPAbridged_1.AbridgedPacketCodec;
}
}
exports.ConnectionTCPMTProxyAbridged = ConnectionTCPMTProxyAbridged;