madeline-ton
Version:
Pure JS client-side implementation of the Telegram TON blockchain protocol
245 lines (206 loc) • 7.75 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _adnl = _interopRequireDefault(require("./network/adnl"));
var _crypto = _interopRequireDefault(require("./crypto"));
var _tools = require("./tools");
var _random = require("./crypto-sync/random");
var _parser = _interopRequireDefault(require("./TL/parser"));
var _stream = _interopRequireDefault(require("./TL/stream"));
var ADNLConnection =
/*#__PURE__*/
function () {
/**
*
* @param {Parser} TLParser
* @param {Object} endpoint
* @param {string} URI
*/
function ADNLConnection(TLParser, key, uri) {
(0, _classCallCheck2["default"])(this, ADNLConnection);
(0, _defineProperty2["default"])(this, "requests", {});
(0, _defineProperty2["default"])(this, "pings", {});
this.TLParser = TLParser;
this.key = key;
this.uri = uri;
this.crypto = new _crypto["default"](this.TLParser);
}
(0, _createClass2["default"])(ADNLConnection, [{
key: "connect",
value: function () {
var _connect = (0, _asyncToGenerator2["default"])(
/*#__PURE__*/
_regenerator["default"].mark(function _callee() {
var _this = this;
var _ref, pub, secret, init, ctx, digest, key, iv, processor, encryptedInit, id, socket;
return _regenerator["default"].wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return this.crypto.initEC(this.key['key']);
case 2:
_ref = _context.sent;
pub = _ref.pub;
secret = _ref.secret;
_context.next = 7;
return this.crypto.secureRandom(new Uint32Array(40));
case 7:
init = _context.sent;
//init = new Uint32Array(hexToBytes('e9c77267d521ec3644410f78d555ecc5857e9a5dc84dc575ac5b611d42b1874696e1b5a0cfe4bc45fb2feccf02061f4df5b5d5be679afe46177d8561aaea8cc37ded93ee999b9e086b0c4d65a519d6000968316e63755d3519818fa941df37ba8bce3dca622c78eedbf04af4253b510fd16df084e6ffc4b5d417aef6443385ff41e12749bbbbd5c770f961db642ca82105e7918427e217129bc4b3c58723da7e').buffer)
ctx = {
crypto: this.crypto,
decrypt: [init.slice(0, 8), init.slice(16, 20)],
encrypt: [init.slice(8, 16), init.slice(20, 24)],
uri: this.uri
};
_context.next = 11;
return this.crypto.sha256(init);
case 11:
digest = _context.sent;
init = new Uint8Array(init.buffer);
digest = new Uint8Array(digest);
key = (0, _tools.bufferConcat)(secret.slice(0, 16), digest.slice(16, 32));
iv = (0, _tools.bufferConcat)(digest.slice(0, 4), secret.slice(20, 32));
_context.next = 18;
return this.crypto.getCtr(key, iv);
case 18:
processor = _context.sent;
_context.t0 = Uint8Array;
_context.next = 22;
return processor.process(init);
case 22:
_context.t1 = _context.sent;
encryptedInit = new _context.t0(_context.t1);
processor.close();
_context.t2 = Uint8Array;
_context.next = 28;
return this.crypto.sha256(this.TLParser.serialize(new _stream["default"](), this.key).uBuf);
case 28:
_context.t3 = _context.sent;
id = new _context.t2(_context.t3);
ctx['init'] = (0, _tools.bufferConcat)((0, _tools.bufferConcat)(id, pub), digest, encryptedInit);
socket = new _adnl["default"]();
socket.onClose = function () {
return console.log("Closed connection!");
};
socket.onMessage = function (message) {
return _this.onMessage(message);
};
_context.next = 36;
return socket.connect(ctx);
case 36:
this.socket = socket;
this.pingId = setInterval(function () {
_this.ping();
}, 5000);
case 38:
case "end":
return _context.stop();
}
}
}, _callee, this);
}));
function connect() {
return _connect.apply(this, arguments);
}
return connect;
}()
/**
* Incoming message
* @param {Stream} message Incoming message
*/
}, {
key: "onMessage",
value: function onMessage(message) {
message = this.TLParser.deserialize(message);
if (message['_'] === 'tcp.pong') {
this.pings[message['random_id']].res(message);
delete this.pings[message['random_id']];
return;
}
if (message['_'] !== 'adnl.message.answer') {
console.log("Weird message: ", message);
return;
}
clearTimeout(this.requests[message['query_id']]['timeoutId']);
this.requests[message['query_id']].res(this.TLParser.deserialize(new _stream["default"](message['answer'].buffer)));
delete this.requests[message['query_id']];
}
/**
* Send ADNL query
* @param {Uint8Array} query Query
*/
}, {
key: "query",
value: function query(_query) {
var _this2 = this;
var query_id = (0, _random.fastRandom)(new Uint32Array(8));
_query = this.TLParser.serialize(this.socket.getBuffer(), {
_: 'adnl.message.query',
query_id: query_id,
query: _query
});
var promise = new Promise(function (res, rej) {
var timeoutId = setTimeout(_this2.timeout.bind(_this2), 10000, query_id);
_this2.requests[query_id] = {
res: res,
rej: rej,
timeoutId: timeoutId
};
});
return this.socket.write(_query).then(function () {
return promise;
});
}
}, {
key: "timeout",
value: function timeout(query_id) {
this.requests[query_id].rej(new Error("Timeout!"));
delete this.requests[query_id];
}
/**
* Send ping
*/
}, {
key: "ping",
value: function ping() {
var _this3 = this;
if (!this.socket) return;
var random_id = (0, _random.fastRandom)(new Int32Array(2));
var ping = this.TLParser.serialize(this.socket.getBuffer(), {
_: 'tcp.ping',
random_id: random_id
});
var promise = new Promise(function (res, rej) {
_this3.pings[random_id] = {
res: res,
rej: rej
};
});
return this.socket.write(ping).then(function () {
return promise;
});
}
}, {
key: "close",
value: function close() {
if (this.socket) {
this.socket.close();
this.socket = undefined;
clearInterval(this.pingId);
}
}
}]);
return ADNLConnection;
}();
var _default = ADNLConnection;
exports["default"] = _default;