UNPKG

madeline-ton

Version:

Pure JS client-side implementation of the Telegram TON blockchain protocol

379 lines (283 loc) 11 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _stream = _interopRequireDefault(require("./stream")); var _objects = _interopRequireDefault(require("./objects")); var _random = require("../crypto-sync/random"); var _zlib = require("zlib"); var _tools = require("../tools"); var _long = _interopRequireDefault(require("../lib/bigint/long")); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } /** * Custom TL parser based on an unreleased project of mine (madeline.py). * Could've based it on my MadelineProto, but madeline.py's parser is way cleaner. */ var Parser = /*#__PURE__*/ function () { /** * Set TL Object store * @param {Objects} objects */ function Parser(objects, callbacks) { (0, _classCallCheck2["default"])(this, Parser); this.objects = objects; this.callbacks = callbacks; } /** * Set TL Object store * @param {Objects} objects */ (0, _createClass2["default"])(Parser, [{ key: "setObjectStore", value: function setObjectStore(objects) { this.objects = objects; } /** * Deserialize TL object * @param {Stream} data Data * @param {Object} type Type info */ }, { key: "deserialize", value: function deserialize(data, type) { type = type || { type: '' }; switch (type['type']) { case 'int': return data.readSignedInt(); case '#': return data.readUnsignedInt(); case 'long': return data.readSignedLong(); case 'int128': return data.readUnsignedInts(4); case 'int256': return data.readUnsignedInts(8); case 'int512': return data.readUnsignedInts(16); case 'double': return data.readDouble(); case 'Bool': return data.readSignedInt() === 0x997275b5; case 'string': return data.readString(); case 'bytes': return data.readBytes(); } if (!type['predicate']) { type = _objectSpread({}, type, {}, this.objects.findById(data.readSignedInt())); } switch (type['predicate']) { case 'gzip_packed': return this.deserialize((0, _zlib.gunzipSync)(data.readBytes()), { layer: type['layer'] }); case 'dataJSON': return JSON.parse(data.readString()); case 'vector': var length = data.readUnsignedInt(); var _result = Array(length); for (var x = 0; x < length; x++) { _result[x] = this.deserialize(data, type['subtype']); } return _result; } var result = { _: type['predicate'] }; for (var key in type['params']) { var param = type['params'][key]; if (param['pow']) { if (param['type'] === 'true') { result[key] = Boolean(result[param['flag']] & param['pow']); continue; } if (!(result[param['flag']] & param['pow'])) { continue; } } result[key] = this.deserialize(data, param); } // Later should delete unused flags return result; } /** * Serialize TL * @param {Stream} stream Stream * @param {mixed} data Data to serialize * @param {Object} type TL type definition */ }, { key: "serialize", value: function serialize(stream, data, type) { type = type || {}; switch (type['type']) { case 'int': return stream.writeSignedInt(data); case "#": return stream.writeUnsignedInt(data); case 'long': if (typeof data === 'string' || data instanceof String) { data = _long["default"].fromString(data, 10); data = [data.low_, data.high_]; } return stream.writeSignedLong(data); case 'int128': if (typeof data === 'string' || data instanceof String) { data = (0, _tools.atobInt32)(data); } return stream.writeUnsignedInts(data); case 'int256': if (typeof data === 'string' || data instanceof String) { data = (0, _tools.atobInt32)(data); } return stream.writeUnsignedInts(data); case 'int512': if (typeof data === 'string' || data instanceof String) { data = (0, _tools.atobInt32)(data); } return stream.writeUnsignedInts(data); case 'double': return stream.writeDouble(data); case 'Bool': return stream.writeSignedInt(data ? 0x997275b5 : 0xbc799737); case 'string': return stream.writeString(data); case 'bytes': return stream.writeBytes(data); case 'DataJSON': data = { _: 'dataJSON', data: JSON.stringify(data) }; } if (!type['predicate']) { if (type['type'] === 'Vector t') { type = _objectSpread({}, type, {}, this.objects.findByPredicateAndLayer('vector', type['layer'])); } else { type = _objectSpread({}, type, {}, this.objects.findByPredicateAndLayer(data['_'] || data['@type'], type['layer'])); } stream.prepareLength(1 + type['minSize']).writeSignedInt(type['id']); } else { stream.prepareLength(type['minSize']); } if (type['predicate'] === 'vector') { stream.writeUnsignedInt(data.length); if (this.objects.basicSizes[type['subtype']]) { stream.prepareLength(data.length * this.objects.basicSizes[type['subtype']]); } for (var element in data) { this.serialize(stream, data[element], type['subtype']); } return; } if (typeof data === 'string' || data instanceof String) { data = this.callbacks.typeConversion[type['type']](data); } var flagSize = 0; for (var key in type['params']) { var param = type['params'][key]; if (param['pow']) { var flags = data[param['flag']] || 0; if (!data[key]) { flags = flags & ~param['pow']; } else { flags = flags | param['pow']; flagSize += this.objects.basicSizes[param['type']] || 0; } data[param['flag']] = flags; } } stream.prepareLength(flagSize); for (var _key in type['params']) { var _param = type['params'][_key]; if (typeof data[_key] === 'undefined') { if (_param['pow']) { continue; } if (_param['type'] === '#') { stream.writeUnsignedInt(0); continue; } if (_key === 'random_bytes') { // This should run in a worker stream.writeBytes((0, _random.secureRandom)(new Uint8Array(15 + 4 * (0, _random.fastRandomInt)(3)))); continue; } if (_key === 'random_id') { switch (_param['type']) { case 'int': stream.writeUnsignedInts((0, _random.fastRandom)(new Uint32Array(1))); break; case 'long': stream.writeUnsignedInts((0, _random.fastRandom)(new Uint32Array(2))); break; case 'Vector t': if (data['id']) { var len = data['id'].length; // forwardMessages if (!_param['predicate']) { stream.prepareLength(1).writeSignedInt(this.objects.findByPredicateAndLayer('vector', type['layer'])['id']); } stream.prepareLength(1 + len * 2).writeUnsignedInt(len).writeUnsignedInts((0, _random.fastRandom)(new Uint32Array(len * 2))); break; } // Fall through default: throw new Error('Missing parameter ' + _key); } continue; } if (_param['type'] === 'string' || _param['type'] === 'bytes') { stream.writeBytes(new Uint8Array(0)); continue; } if (_param['type'] === 'Vector t') { if (!_param['predicate']) { stream.prepareLength(1).writeSignedInt(this.objects.findByPredicateAndLayer('vector', type['layer'])['id']); } stream.prepareLength(1).writeUnsignedInt(0); continue; } if (_key === 'hash' && _param['type'] === 'int') { stream.writeSignedInt(0); continue; } if (type['type'] === 'DocumentAttribute' && ['w', 'h', 'duration'].includes(_key)) { stream.writeSignedInt(0); continue; } try { var id = this.objects.findByPredicateAndLayer('input' + _param['type'] + "Empty", _param['layer']); if (id['type'] === _param['type']) { stream.writeSignedInt(id['id']); continue; } } catch (e) {} var paramType = _param['type']; paramType = paramType[0].toLowerCase().concat(paramType.slice(1)); try { var _id = this.objects.findByPredicateAndLayer(paramType + "Empty", _param['layer']); if (_id['type'] === _param['type']) { stream.writeSignedInt(_id['id']); continue; } } catch (e) {} throw new Error('Missing parameter ' + _key); } this.serialize(stream, data[_key], _param); } return stream; } }]); return Parser; }(); var _default = Parser; exports["default"] = _default;