YouTwitFace %!s(int64=5) %!d(string=hai) anos
pai
achega
3d76faa372
Modificáronse 43 ficheiros con 1174 adicións e 1354 borrados
  1. 1 0
      .eslintignore
  2. 31 0
      .eslintrc.json
  3. 12 16
      gramjs/crypto/AES.js
  4. 13 21
      gramjs/crypto/AuthKey.js
  5. 10 15
      gramjs/crypto/Factorizator.js
  6. 28 34
      gramjs/crypto/RSA.js
  7. 28 28
      gramjs/errors/Common.js
  8. 19 22
      gramjs/errors/RPCBaseErrors.js
  9. 6 5
      gramjs/errors/index.js
  10. 41 36
      gramjs/extensions/BinaryReader.js
  11. 1 2
      gramjs/extensions/BinaryWriter.js
  12. 25 23
      gramjs/extensions/MessagePacker.js
  13. 96 124
      gramjs/network/Authenticator.js
  14. 19 26
      gramjs/network/MTProtoPlainSender.js
  15. 147 156
      gramjs/network/MTProtoSender.js
  16. 46 88
      gramjs/network/MTProtoState.js
  17. 2 7
      gramjs/network/RequestState.js
  18. 23 30
      gramjs/network/connection/Connection.js
  19. 18 22
      gramjs/network/connection/TCPFull.js
  20. 4 9
      gramjs/tl/MTProtoRequest.js
  21. 26 29
      gramjs/tl/Session.js
  22. 34 39
      gramjs/tl/TelegramClient.js
  23. 11 12
      gramjs/tl/core/GZIPPacked.js
  24. 12 14
      gramjs/tl/core/MessageContainer.js
  25. 8 13
      gramjs/tl/core/RPCResult.js
  26. 2 2
      gramjs/tl/core/TLMessage.js
  27. 6 7
      gramjs/tl/core/index.js
  28. 3 2
      gramjs/tl/index.js
  29. 10 20
      gramjs/tl/tlobject.js
  30. 61 100
      gramjs/utils/Helpers.js
  31. 5 5
      gramjs_generator/docswriter.js
  32. 38 41
      gramjs_generator/generators/docs.js
  33. 11 24
      gramjs_generator/generators/errors.js
  34. 145 220
      gramjs_generator/generators/tlobject.js
  35. 15 25
      gramjs_generator/parsers/errors.js
  36. 6 14
      gramjs_generator/parsers/methods.js
  37. 8 17
      gramjs_generator/parsers/tlobject/parser.js
  38. 21 27
      gramjs_generator/parsers/tlobject/tlarg.js
  39. 9 24
      gramjs_generator/parsers/tlobject/tlobject.js
  40. 1 1
      index.js
  41. 33 42
      main.js
  42. 136 12
      package-lock.json
  43. 3 0
      package.json

+ 1 - 0
.eslintignore

@@ -0,0 +1 @@
+gramjs_generator/data/html/js/search.js

+ 31 - 0
.eslintrc.json

@@ -0,0 +1,31 @@
+{
+    "env": {
+        "commonjs": true,
+        "es6": true,
+        "node": true
+    },
+    "extends": ["google"],
+    "globals": {
+        "Atomics": "readonly",
+        "SharedArrayBuffer": "readonly"
+    },
+    "parser": "babel-eslint",
+    "parserOptions": {
+        "ecmaVersion": 2018
+    },
+    "rules": {
+        "indent": ["error", 4],
+        "max-len": [
+            "error",
+            {
+                "code": 120,
+                "ignoreUrls": true,
+                "ignoreStrings": true,
+                "ignoreTemplateLiterals": true
+            }
+        ],
+        "object-curly-spacing": ["error", "always"],
+        "require-jsdoc": "off",
+        "valid-jsdoc": "off"
+    }
+}

+ 12 - 16
gramjs/crypto/AES.js

@@ -1,5 +1,5 @@
 const aesjs = require('aes-js');
-const Helpers = require("../utils/Helpers");
+const Helpers = require('../utils/Helpers');
 
 class AES {
     /**
@@ -13,15 +13,15 @@ class AES {
         let iv1 = iv.slice(0, Math.floor(iv.length / 2));
         let iv2 = iv.slice(Math.floor(iv.length / 2));
         let plainText = new Array(cipherText.length).fill(0);
-        let aes = new aesjs.AES(key);
-        let blocksCount = Math.floor(plainText.length / 16);
-        let cipherTextBlock = new Array(16).fill(0);
+        const aes = new aesjs.AES(key);
+        const blocksCount = Math.floor(plainText.length / 16);
+        const cipherTextBlock = new Array(16).fill(0);
 
         for (let blockIndex = 0; blockIndex < blocksCount; blockIndex++) {
             for (let i = 0; i < 16; i++) {
                 cipherTextBlock[i] = cipherText[blockIndex * 16 + i] ^ iv2[i];
             }
-            let plainTextBlock = aes.decrypt(cipherTextBlock);
+            const plainTextBlock = aes.decrypt(cipherTextBlock);
             for (let i = 0; i < 16; i++) {
                 plainTextBlock[i] ^= iv1[i];
             }
@@ -31,9 +31,8 @@ class AES {
             plainText = new Uint8Array([
                 ...plainText.slice(0, blockIndex * 16),
                 ...plainTextBlock.slice(0, 16),
-                ...plainText.slice(blockIndex * 16 + 16)
+                ...plainText.slice(blockIndex * 16 + 16),
             ]);
-
         }
         return Buffer.from(plainText);
     }
@@ -46,7 +45,7 @@ class AES {
      * @returns {Buffer}
      */
     static encryptIge(plainText, key, iv) {
-        let padding = plainText.length % 16;
+        const padding = plainText.length % 16;
         if (padding) {
             plainText = Buffer.concat([plainText, Helpers.generateRandomBytes(16 - padding)]);
         }
@@ -54,17 +53,17 @@ class AES {
         let iv1 = iv.slice(0, Math.floor(iv.length / 2));
         let iv2 = iv.slice(Math.floor(iv.length / 2));
 
-        let aes = new aesjs.AES(key);
+        const aes = new aesjs.AES(key);
         let cipherText = Buffer.alloc(0);
-        let blockCount = Math.floor(plainText.length / 16);
+        const blockCount = Math.floor(plainText.length / 16);
 
         for (let blockIndex = 0; blockIndex < blockCount; blockIndex++) {
-            let plainTextBlock = Buffer.from(plainText.slice(blockIndex * 16, blockIndex * 16 + 16));
+            const plainTextBlock = Buffer.from(plainText.slice(blockIndex * 16, blockIndex * 16 + 16));
 
             for (let i = 0; i < 16; i++) {
                 plainTextBlock[i] ^= iv1[i];
             }
-            let cipherTextBlock = Buffer.from(aes.encrypt(plainTextBlock));
+            const cipherTextBlock = Buffer.from(aes.encrypt(plainTextBlock));
 
             for (let i = 0; i < 16; i++) {
                 cipherTextBlock[i] ^= iv2[i];
@@ -72,10 +71,7 @@ class AES {
 
             iv1 = cipherTextBlock;
             iv2 = plainText.slice(blockIndex * 16, blockIndex * 16 + 16);
-            cipherText = Buffer.concat([
-                cipherText,
-                cipherTextBlock,
-            ]);
+            cipherText = Buffer.concat([cipherText, cipherTextBlock]);
         }
         return cipherText;
     }

+ 13 - 21
gramjs/crypto/AuthKey.js

@@ -1,27 +1,25 @@
-const Helpers = require("../utils/Helpers");
-const BinaryReader = require("../extensions/BinaryReader");
-const struct = require("python-struct");
-const bigUintLE = require("biguintle");
+const Helpers = require('../utils/Helpers');
+const BinaryReader = require('../extensions/BinaryReader');
+const struct = require('python-struct');
 
 class AuthKey {
     constructor(data) {
         this.key = data;
-
     }
 
     set key(value) {
         if (!value) {
             this._key = this.auxHash = this.keyId = null;
-            return
+            return;
         }
         if (value instanceof AuthKey) {
             this._key = value._key;
             this.auxHash = value.auxHash;
             this.keyId = value.keyId;
-            return
+            return;
         }
         this._key = value;
-        let reader = new BinaryReader(Helpers.sha1(this._key));
+        const reader = new BinaryReader(Helpers.sha1(this._key));
         this.auxHash = reader.readLong(false);
         reader.read(4);
         this.keyId = reader.readLong(false);
@@ -31,32 +29,26 @@ class AuthKey {
         return this._key;
     }
 
-
     // TODO : This doesn't really fit here, it's only used in authentication
 
     /**
      * Calculates the new nonce hash based on the current class fields' values
-     * @param new_nonce
+     * @param newNonce
      * @param number
      * @returns {bigint}
      */
-    calcNewNonceHash(new_nonce, number) {
+    calcNewNonceHash(newNonce, number) {
+        newNonce = Helpers.readBufferFromBigInt(newNonce, 32, true, true);
+        const data = Buffer.concat([newNonce, struct.pack('<BQ', number.toString(), this.auxHash.toString())]);
 
-        new_nonce = Helpers.readBufferFromBigInt(new_nonce, 32, true, true);
-        let data = Buffer.concat([
-            new_nonce,
-            struct.pack("<BQ", number.toString(), this.auxHash.toString())
-        ]);
-
-        //Calculates the message key from the given data
-        let shaData = Helpers.sha1(data).slice(4, 20);
+        // Calculates the message key from the given data
+        const shaData = Helpers.sha1(data).slice(4, 20);
         return Helpers.readBigIntFromBuffer(shaData, true, true);
     }
 
     equals(other) {
-        return (other instanceof this.constructor && other.key === this._key)
+        return other instanceof this.constructor && other.key === this._key;
     }
-
 }
 
 module.exports = AuthKey;

+ 10 - 15
gramjs/crypto/Factorizator.js

@@ -1,7 +1,6 @@
-const Helpers = require("../utils/Helpers");
+const Helpers = require('../utils/Helpers');
 
 class Factorizator {
-
     /**
      * Finds the small multiplier by using Lopatin's method
      * @param what {BigInt}
@@ -10,12 +9,11 @@ class Factorizator {
     static findSmallMultiplierLopatin(what) {
         let g = 0n;
         for (let i = 0n; i < 3n; i++) {
-            let q = 30n || (Helpers.getRandomInt(0, 127) & 15) + 17;
+            const q = 30n || (Helpers.getRandomInt(0, 127) & 15) + 17;
             let x = 40n || Helpers.getRandomInt(0, 1000000000) + 1;
 
-
             let y = x;
-            let lim = 1n << (i + 18n);
+            const lim = 1n << (i + 18n);
             for (let j = 1n; j < lim; j++) {
                 let a = x;
                 let b = x;
@@ -36,24 +34,22 @@ class Factorizator {
                 }
 
                 x = c;
-                let z = BigInt((x < y) ? (y - x) : (x - y));
+                const z = BigInt(x < y ? y - x : x - y);
                 g = this.gcd(z, what);
 
-
                 if (g !== 1n) {
-                    break
+                    break;
                 }
 
                 if ((j & (j - 1n)) === 0n) {
                     y = x;
                 }
-
             }
             if (g > 1) {
                 break;
             }
         }
-        let p = what / g;
+        const p = what / g;
 
         return p < g ? p : g;
     }
@@ -65,8 +61,7 @@ class Factorizator {
      * @returns {BigInt}
      */
     static gcd(a, b) {
-
-        while (((a !== 0n) && (b !== 0n))) {
+        while (a !== 0n && b !== 0n) {
             while ((b & 1n) === 0n) {
                 b >>= 1n;
             }
@@ -79,7 +74,7 @@ class Factorizator {
                 b -= a;
             }
         }
-        return ((b === 0n) ? a : b);
+        return b === 0n ? a : b;
     }
 
     /**
@@ -88,8 +83,8 @@ class Factorizator {
      * @returns {{p: BigInt, q: BigInt}}
      */
     static factorize(pq) {
-        let divisor = this.findSmallMultiplierLopatin(pq);
-        return {p: divisor, q: pq / divisor}
+        const divisor = this.findSmallMultiplierLopatin(pq);
+        return { p: divisor, q: pq / divisor };
     }
 }
 

+ 28 - 34
gramjs/crypto/RSA.js

@@ -1,8 +1,7 @@
 const NodeRSA = require('node-rsa');
-const {TLObject} = require("../tl/tlobject");
-const struct = require("python-struct");
-const Helpers = require("../utils/Helpers");
-let _serverKeys = {};
+const { TLObject } = require('../tl/tlobject');
+const Helpers = require('../utils/Helpers');
+const _serverKeys = {};
 
 /**
  * Gets the arbitrary-length byte array corresponding to the given integer
@@ -11,53 +10,49 @@ let _serverKeys = {};
  * @returns {Buffer}
  */
 function getByteArray(integer, signed = false) {
-
-    let bits = integer.toString(2).length;
-    let byteLength = Math.floor((bits + 8 - 1) / 8);
-    let f;
-    f = Helpers.readBufferFromBigInt(BigInt(integer), byteLength, false, signed);
-    return f;
+    const { length: bits } = integer.toString(2);
+    const byteLength = Math.floor((bits + 8 - 1) / 8);
+    return Helpers.readBufferFromBigInt(BigInt(integer), byteLength, false, signed);
 }
 
 function _computeFingerprint(key) {
-    let buf = Helpers.readBigIntFromBuffer(key.keyPair.n.toBuffer(), false);
-    let nArray = getByteArray(buf);
+    const buf = Helpers.readBigIntFromBuffer(key.keyPair.n.toBuffer(), false);
+    const nArray = getByteArray(buf);
 
-    let n = TLObject.serializeBytes(nArray);
-    let e = TLObject.serializeBytes(getByteArray(key.keyPair.e));
-//Telegram uses the last 8 bytes as the fingerprint
-    let sh = Helpers.sha1(Buffer.concat([n, e]));
+    const n = TLObject.serializeBytes(nArray);
+    const e = TLObject.serializeBytes(getByteArray(key.keyPair.e));
+    // Telegram uses the last 8 bytes as the fingerprint
+    const sh = Helpers.sha1(Buffer.concat([n, e]));
     return Helpers.readBigIntFromBuffer(sh.slice(-8), true, true);
 }
 
 function addKey(pub) {
-    let key = new NodeRSA(pub);
+    const key = new NodeRSA(pub);
     _serverKeys[_computeFingerprint(key)] = key;
-
 }
 
-
 function encrypt(fingerprint, data) {
-    let key = _serverKeys[fingerprint];
+    const key = _serverKeys[fingerprint];
     if (!key) {
         return undefined;
     }
-    let buf = Helpers.readBigIntFromBuffer(key.keyPair.n.toBuffer(), false);
+    const buf = Helpers.readBigIntFromBuffer(key.keyPair.n.toBuffer(), false);
     let rand = Helpers.generateRandomBytes(235 - data.length);
     rand = Buffer.from(
-        "66a6f809e0dfd71d9dbbc2d6b5fe5fc0be9f5b2b0f2f85688843eea6b2c6d51329750f020c8de27a0a911b07d2a46600493d1abb7caf24" +
-        "01ccd815d7de7c5ea830cdf6cce8bff12f77db589f233bce436b644c3415f16d073335fdadfe313c603485b3274e8fcd148fd1a5e18bd2" +
-        "4b3e983df94d58b61c150333ab8d614101e7a904dc38af3a3b29e73d62", "hex");
+        '66a6f809e0dfd71d9dbbc2d6b5fe5fc0be9f5b2b0f2f85688843eea6b2c6d51329750f020c8de27a0a911b07d2a46600493d1abb7caf24' +
+            '01ccd815d7de7c5ea830cdf6cce8bff12f77db589f233bce436b644c3415f16d073335fdadfe313c603485b3274e8fcd148fd1a5e18bd2' +
+            '4b3e983df94d58b61c150333ab8d614101e7a904dc38af3a3b29e73d62',
+        'hex'
+    );
 
-    let toEncrypt = Buffer.concat([Helpers.sha1(data), data, rand]);
-    let payload = Helpers.readBigIntFromBuffer(toEncrypt, false);
-    let encrypted = Helpers.modExp(payload, BigInt(key.keyPair.e),
-        buf);
-    let block = Helpers.readBufferFromBigInt(encrypted, 256, false);
+    const toEncrypt = Buffer.concat([Helpers.sha1(data), data, rand]);
+    const payload = Helpers.readBigIntFromBuffer(toEncrypt, false);
+    const encrypted = Helpers.modExp(payload, BigInt(key.keyPair.e), buf);
+    const block = Helpers.readBufferFromBigInt(encrypted, 256, false);
     return block;
 }
 
-let publicKeys = [
+const publicKeys = [
     `-----BEGIN RSA PUBLIC KEY-----
 MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6
 lyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daS
@@ -92,11 +87,10 @@ qAqBdmI1iBGdQv/OQCBcbXIWCGDY2AsiqLhlGQfPOI7/vvKc188rTriocgUtoTUc
 /n/sIUzkgwTqRyvWYynWARWzQg0I9olLBBC2q5RQJJlnYXZwyTL3y9tdb7zOHkks
 WV9IMQmZmyZh/N7sMbGWQpt4NMchGpPGeJ2e5gHBjDnlIf2p1yZOYeUYrdbwcS0t
 UiggS4UeE8TzIuXFQxw7fzEIlmhIaq3FnwIDAQAB
------END RSA PUBLIC KEY-----`
+-----END RSA PUBLIC KEY-----`,
 ];
-for (let pub of publicKeys) {
+for (const pub of publicKeys) {
     addKey(pub);
 }
 
-
-module.exports = {encrypt};
+module.exports = { encrypt };

+ 28 - 28
gramjs/errors/Common.js

@@ -2,15 +2,14 @@
  * Errors not related to the Telegram API itself
  */
 
-const {TLRequest} = require("../tl");
-const struct = require("python-struct");
+const struct = require('python-struct');
 
 /**
  * Occurs when a read operation was cancelled.
  */
 class ReadCancelledError extends Error {
     constructor() {
-        super("The read operation was cancelled.");
+        super('The read operation was cancelled.');
     }
 }
 
@@ -19,9 +18,8 @@ class ReadCancelledError extends Error {
  * when trying to read a TLObject with an invalid constructor code.
  */
 class TypeNotFoundError extends Error {
-
     constructor(invalidConstructorId, remaining) {
-        super(`Could not find a matching Constructor ID for the TLObject that was supposed to be 
+        super(`Could not find a matching Constructor ID for the TLObject that was supposed to be
         read with ID ${invalidConstructorId}. Most likely, a TLObject was trying to be read when
          it should not be read. Remaining bytes: ${remaining}`);
         this.invalidConstructorId = invalidConstructorId;
@@ -47,27 +45,25 @@ class InvalidChecksumError extends Error {
  */
 class InvalidBufferError extends Error {
     constructor(payload) {
-        let code = (-struct.unpack("<i", payload)[0]);
-        if ((payload.length === 4)) {
+        const [code] = -struct.unpack('<i', payload);
+        if (payload.length === 4) {
             super(`Invalid response buffer (HTTP code ${code})`);
         } else {
-            this.code = null;
             super(`Invalid response buffer (too short ${payload})`);
+            this.code = null;
         }
         this.code = code;
         this.payload = payload;
-
     }
 }
 
-
 /**
  * Generic security error, mostly used when generating a new AuthKey.
  */
 class SecurityError extends Error {
     constructor(...args) {
-        if (!args) {
-            args = ["A security check failed."];
+        if (!args.length) {
+            args = ['A security check failed.'];
         }
         super(...args);
     }
@@ -79,7 +75,7 @@ class SecurityError extends Error {
  */
 class CdnFileTamperedError extends SecurityError {
     constructor() {
-        super("The CDN file has been altered and its download cancelled.");
+        super('The CDN file has been altered and its download cancelled.');
     }
 }
 
@@ -88,7 +84,7 @@ class CdnFileTamperedError extends SecurityError {
  */
 class AlreadyInConversationError extends Error {
     constructor() {
-        super("Cannot open exclusive conversation in a chat that already has one open conversation");
+        super('Cannot open exclusive conversation in a chat that already has one open conversation');
     }
 }
 
@@ -97,45 +93,49 @@ class AlreadyInConversationError extends Error {
  */
 class BadMessageError extends Error {
     static ErrorMessages = {
-        16: 'msg_id too low (most likely, client time is wrong it would be worthwhile to ' +
+        16:
+            'msg_id too low (most likely, client time is wrong it would be worthwhile to ' +
             'synchronize it using msg_id notifications and re-send the original message ' +
             'with the “correct” msg_id or wrap it in a container with a new msg_id if the ' +
             'original message had waited too long on the client to be transmitted).',
 
-        17: 'msg_id too high (similar to the previous case, the client time has to be ' +
+        17:
+            'msg_id too high (similar to the previous case, the client time has to be ' +
             'synchronized, and the message re-sent with the correct msg_id).',
 
-        18: 'Incorrect two lower order msg_id bits (the server expects client message msg_id ' +
+        18:
+            'Incorrect two lower order msg_id bits (the server expects client message msg_id ' +
             'to be divisible by 4).',
 
-        19: 'Container msg_id is the same as msg_id of a previously received message ' +
-            '(this must never happen).',
+        19: 'Container msg_id is the same as msg_id of a previously received message ' + '(this must never happen).',
 
-        20: 'Message too old, and it cannot be verified whether the server has received a ' +
+        20:
+            'Message too old, and it cannot be verified whether the server has received a ' +
             'message with this msg_id or not.',
 
-        32: 'msg_seqno too low (the server has already received a message with a lower ' +
+        32:
+            'msg_seqno too low (the server has already received a message with a lower ' +
             'msg_id but with either a higher or an equal and odd seqno).',
 
-        33: 'msg_seqno too high (similarly, there is a message with a higher msg_id but with ' +
+        33:
+            'msg_seqno too high (similarly, there is a message with a higher msg_id but with ' +
             'either a lower or an equal and odd seqno).',
 
         34: 'An even msg_seqno expected (irrelevant message), but odd received.',
 
         35: 'Odd msg_seqno expected (relevant message), but even received.',
 
-        48: 'Incorrect server salt (in this case, the bad_server_salt response is received with ' +
+        48:
+            'Incorrect server salt (in this case, the bad_server_salt response is received with ' +
             'the correct salt, and the message is to be re-sent with it).',
 
-        64: 'Invalid container.'
+        64: 'Invalid container.',
     };
 
     constructor(code) {
         super(BadMessageError.ErrorMessages[code] || `Unknown error code (this should not happen): ${code}.`);
         this.code = code;
-
     }
-
 }
 
 // TODO : Support multi errors.
@@ -148,5 +148,5 @@ module.exports = {
     SecurityError,
     CdnFileTamperedError,
     AlreadyInConversationError,
-    BadMessageError
-};
+    BadMessageError,
+};

+ 19 - 22
gramjs/errors/RPCBaseErrors.js

@@ -2,20 +2,20 @@
  * Base class for all Remote Procedure Call errors.
  */
 class RPCError extends Error {
-
-
     constructor(request, message, code = null) {
-        super("RPCError {0}: {1}{2}"
-            .replace("{0}", code)
-            .replace("{1}", message)
-            .replace("{2}", RPCError._fmtRequest(request)));
+        super(
+            'RPCError {0}: {1}{2}'
+                .replace('{0}', code)
+                .replace('{1}', message)
+                .replace('{2}', RPCError._fmtRequest(request))
+        );
         this.code = code;
         this.message = message;
     }
 
     static _fmtRequest(request) {
         // TODO fix this
-        return ` (caused by ${request})`
+        return ` (caused by ${request})`;
     }
 }
 
@@ -24,10 +24,9 @@ class RPCError extends Error {
  */
 class InvalidDCError extends RPCError {
     code = 303;
-    message = 'ERROR_SEE_OTHER'
+    message = 'ERROR_SEE_OTHER';
 }
 
-
 /**
  * The query contains errors. In the event that a request was created
  * using a form and contains user generated data, the user should be
@@ -35,7 +34,7 @@ class InvalidDCError extends RPCError {
  */
 class BadRequestError extends RPCError {
     code = 400;
-    message = 'BAD_REQUEST'
+    message = 'BAD_REQUEST';
 }
 
 /**
@@ -44,7 +43,7 @@ class BadRequestError extends RPCError {
  */
 class UnauthorizedError extends RPCError {
     code = 401;
-    message = 'UNAUTHORIZED'
+    message = 'UNAUTHORIZED';
 }
 
 /**
@@ -53,7 +52,7 @@ class UnauthorizedError extends RPCError {
  */
 class ForbiddenError extends RPCError {
     code = 403;
-    message = 'FORBIDDEN'
+    message = 'FORBIDDEN';
 }
 
 /**
@@ -61,7 +60,7 @@ class ForbiddenError extends RPCError {
  */
 class NotFoundError extends RPCError {
     code = 404;
-    message = 'NOT_FOUND'
+    message = 'NOT_FOUND';
 }
 
 /**
@@ -70,7 +69,7 @@ class NotFoundError extends RPCError {
  */
 class AuthKeyError extends RPCError {
     code = 406;
-    message = 'AUTH_KEY'
+    message = 'AUTH_KEY';
 }
 
 /**
@@ -81,9 +80,7 @@ class AuthKeyError extends RPCError {
  */
 class FloodError extends RPCError {
     code = 420;
-    message = 'FLOOD'
-
-
+    message = 'FLOOD';
 }
 
 /**
@@ -92,8 +89,8 @@ class FloodError extends RPCError {
  * storage
  */
 class ServerError extends RPCError {
-    code = 500;  // Also witnessed as -500
-    message = 'INTERNAL'
+    code = 500; // Also witnessed as -500
+    message = 'INTERNAL';
 }
 
 /**
@@ -101,7 +98,7 @@ class ServerError extends RPCError {
  * call ``answerCallbackQuery`` will result in this "special" RPCError.
  */
 class TimedOutError extends RPCError {
-    code = 503;  // Only witnessed as -503
+    code = 503; // Only witnessed as -503
     message = 'Timeout';
 }
 
@@ -115,5 +112,5 @@ module.exports = {
     AuthKeyError,
     FloodError,
     ServerError,
-    TimedOutError
-}
+    TimedOutError,
+};

+ 6 - 5
gramjs/errors/index.js

@@ -4,12 +4,13 @@
  * @param request the request that caused this error
  * @constructor the RPCError as a Python exception that represents this error
  */
-const {rpcErrorsObject} = require("./rpcerrorlist");
+const { rpcErrorsObject } = require('./rpcerrorlist');
 
 function RPCMessageToError(rpcError, request) {
-    //Try to get the error by direct look-up, otherwise regex
-    let cls = rpcErrorsObject[rpcError.errorMessage];
+    // Try to get the error by direct look-up, otherwise regex
+    const cls = rpcErrorsObject[rpcError.errorMessage];
     if (cls) {
+        // eslint-disable-next-line new-cap
         return new cls(request);
     } else {
         return rpcError.errorMessage;
@@ -17,5 +18,5 @@ function RPCMessageToError(rpcError, request) {
 }
 
 module.exports = {
-    RPCMessageToError
-}
+    RPCMessageToError,
+};

+ 41 - 36
gramjs/extensions/BinaryReader.js

@@ -1,10 +1,10 @@
-const unpack = require("python-struct").unpack;
-const {TypeNotFoundError} = require("../errors/Common");
-const {coreObjects} = require("../tl/core");
-const {tlobjects} = require("../tl/alltlobjects");
-const Helpers = require("../utils/Helpers");
-class BinaryReader {
+const { unpack } = require('python-struct');
+const { TypeNotFoundError } = require('../errors/Common');
+const { coreObjects } = require('../tl/core');
+const { tlobjects } = require('../tl/alltlobjects');
+const Helpers = require('../utils/Helpers');
 
+class BinaryReader {
     /**
      * Small utility class to read binary data.
      * @param data {Buffer}
@@ -80,7 +80,7 @@ class BinaryReader {
      * @param signed {Boolean}
      */
     readLargeInt(bits, signed = true) {
-        let buffer = this.read(Math.floor(bits / 8));
+        const buffer = this.read(Math.floor(bits / 8));
         return Helpers.readBigIntFromBuffer(buffer, true, signed);
     }
 
@@ -92,10 +92,12 @@ class BinaryReader {
         if (length === -1) {
             length = this.stream.length - this.offset;
         }
-        let result = this.stream.slice(this.offset, this.offset + length);
+        const result = this.stream.slice(this.offset, this.offset + length);
         this.offset += length;
         if (result.length !== length) {
-            throw Error(`No more data left to read (need ${length}, got ${result.length}: ${result}); last read ${this._last}`)
+            throw Error(
+                `No more data left to read (need ${length}, got ${result.length}: ${result}); last read ${this._last}`
+            );
         }
         this._last = result;
         return result;
@@ -118,16 +120,17 @@ class BinaryReader {
      * @returns {Buffer}
      */
     tgReadBytes() {
-        let firstByte = this.readByte();
-        let padding, length;
+        const firstByte = this.readByte();
+        let padding;
+        let length;
         if (firstByte === 254) {
-            length = this.readByte() | this.readByte() << 8 | this.readByte() << 16;
+            length = this.readByte() | (this.readByte() << 8) | (this.readByte() << 16);
             padding = length % 4;
         } else {
             length = firstByte;
             padding = (length + 1) % 4;
         }
-        let data = this.read(length);
+        const data = this.read(length);
 
         if (padding > 0) {
             padding = 4 - padding;
@@ -142,7 +145,7 @@ class BinaryReader {
      * @returns {string}
      */
     tgReadString() {
-        return this.tgReadBytes().toString("utf-8");
+        return this.tgReadBytes().toString('utf-8');
     }
 
     /**
@@ -150,13 +153,15 @@ class BinaryReader {
      * @returns {boolean}
      */
     tgReadBool() {
-        let value = this.readInt(false);
-        if (value === 0x997275b5) { // boolTrue
+        const value = this.readInt(false);
+        if (value === 0x997275b5) {
+            // boolTrue
             return true;
-        } else if (value === 0xbc799737) { //boolFalse
+        } else if (value === 0xbc799737) {
+            // boolFalse
             return false;
         } else {
-            throw new Error(`Invalid boolean code ${value.toString("16")}`);
+            throw new Error(`Invalid boolean code ${value.toString('16')}`);
         }
     }
 
@@ -166,7 +171,7 @@ class BinaryReader {
      * @returns {Date}
      */
     tgReadDate() {
-        let value = this.readInt();
+        const value = this.readInt();
         return new Date(value * 1000);
     }
 
@@ -174,21 +179,24 @@ class BinaryReader {
      * Reads a Telegram object.
      */
     tgReadObject() {
-        let constructorId = this.readInt(false);
+        const constructorId = this.readInt(false);
         let clazz = tlobjects[constructorId];
         if (clazz === undefined) {
             /**
              * The class was None, but there's still a
              * chance of it being a manually parsed value like bool!
              */
-            let value = constructorId;
-            if (value === 0x997275b5) { // boolTrue
-                return true
-            } else if (value === 0xbc799737) {  // boolFalse
+            const value = constructorId;
+            if (value === 0x997275b5) {
+                // boolTrue
+                return true;
+            } else if (value === 0xbc799737) {
+                // boolFalse
                 return false;
-            } else if (value === 0x1cb5c415) {  // Vector
-                let temp = [];
-                let length = this.readInt();
+            } else if (value === 0x1cb5c415) {
+                // Vector
+                const temp = [];
+                const length = this.readInt();
                 for (let i = 0; i < length; i++) {
                     temp.push(this.tgReadObject());
                 }
@@ -200,15 +208,13 @@ class BinaryReader {
             if (clazz === undefined) {
                 // If there was still no luck, give up
                 this.seek(-4); // Go back
-                let pos = this.tellPosition();
-                let error = new TypeNotFoundError(constructorId, this.read());
+                const pos = this.tellPosition();
+                const error = new TypeNotFoundError(constructorId, this.read());
                 this.setPosition(pos);
                 throw error;
             }
-
         }
         return clazz.fromReader(this);
-
     }
 
     /**
@@ -219,8 +225,8 @@ class BinaryReader {
         if (this.readInt(false) !== 0x1cb5c415) {
             throw new Error('Invalid constructor code, vector was expected');
         }
-        let count = this.readInt();
-        let temp = [];
+        const count = this.readInt();
+        const temp = [];
         for (let i = 0; i < count; i++) {
             temp.push(this.tgReadObject());
         }
@@ -263,8 +269,7 @@ class BinaryReader {
         this.offset += offset;
     }
 
-    //endregion
-
+    // endregion
 }
 
-module.exports = BinaryReader;
+module.exports = BinaryReader;

+ 1 - 2
gramjs/extensions/BinaryWriter.js

@@ -10,7 +10,6 @@ class BinaryWriter {
     getValue() {
         return this._stream;
     }
-
 }
 
-module.exports = BinaryWriter;
+module.exports = BinaryWriter;

+ 25 - 23
gramjs/extensions/MessagePacker.js

@@ -1,9 +1,8 @@
-const Helpers = require("../utils/Helpers");
-const MessageContainer = require("../tl/core/MessageContainer");
-const TLMessage = require("../tl/core/TLMessage");
-const {TLRequest} = require("../tl/tlobject");
-const BinaryWriter = require("../extensions/BinaryWriter");
-
+const Helpers = require('../utils/Helpers');
+const MessageContainer = require('../tl/core/MessageContainer');
+const TLMessage = require('../tl/core/TLMessage');
+const { TLRequest } = require('../tl/tlobject');
+const BinaryWriter = require('../extensions/BinaryWriter');
 
 class MessagePacker {
     constructor(state, logger) {
@@ -19,7 +18,7 @@ class MessagePacker {
     }
 
     extend(states) {
-        for (let state of states) {
+        for (const state of states) {
             this._queue.push(state);
         }
         this._ready = true;
@@ -33,13 +32,13 @@ class MessagePacker {
             }
         }
         let data;
-        let buffer = new BinaryWriter(Buffer.alloc(0));
+        const buffer = new BinaryWriter(Buffer.alloc(0));
 
-        let batch = [];
+        const batch = [];
         let size = 0;
 
         while (this._queue.length && batch.length <= MessageContainer.MAXIMUM_LENGTH) {
-            let state = this._queue.shift();
+            const state = this._queue.shift();
             size += state.data.length + TLMessage.SIZE_OVERHEAD;
             if (size <= MessageContainer.MAXIMUM_SIZE) {
                 let afterId;
@@ -47,7 +46,9 @@ class MessagePacker {
                     afterId = state.after.msgId;
                 }
                 state.msgId = await this._state.writeDataAsMessage(
-                    buffer, state.data, state.request instanceof TLRequest,
+                    buffer,
+                    state.data,
+                    state.request instanceof TLRequest,
                     afterId
                 );
 
@@ -59,30 +60,31 @@ class MessagePacker {
                 this._queue.unshift(state);
                 break;
             }
-            this._log.warn(`Message payload for ${state.request.constructor.name} is too long ${state.data.length} and cannot be sent`);
-            state.promise.reject("Request Payload is too big");
+            this._log.warn(
+                `Message payload for ${state.request.constructor.name} is too long ${state.data.length} and cannot be sent`
+            );
+            state.promise.reject('Request Payload is too big');
             size = 0;
-            continue
+            continue;
         }
         if (!batch.length) {
             return null;
         }
         if (batch.length > 1) {
-            data = Buffer.concat([struct.pack(
-                '<Ii', MessageContainer.CONSTRUCTOR_ID, batch.length
-            ), buffer.getValue()]);
+            data = Buffer.concat([
+                struct.pack('<Ii', MessageContainer.CONSTRUCTOR_ID, batch.length),
+                buffer.getValue(),
+            ]);
 
-            let containerId = await this._state.writeDataAsMessage(
-                buffer, data, false
-            );
-            for (let s of batch) {
+            const containerId = await this._state.writeDataAsMessage(buffer, data, false);
+            for (const s of batch) {
                 s.containerId = containerId;
             }
         }
 
         data = buffer.getValue();
-        return {batch, data}
+        return { batch, data };
     }
 }
 
-module.exports = MessagePacker;
+module.exports = MessagePacker;

+ 96 - 124
gramjs/network/Authenticator.js

@@ -1,23 +1,22 @@
-const AES = require("../crypto/AES");
-const AuthKey = require("../crypto/AuthKey");
-const Factorizator = require("../crypto/Factorizator");
-const RSA = require("../crypto/RSA");
-const Helpers = require("../utils/Helpers");
-const {ServerDHParamsFail} = require("../tl/types");
-const {ServerDHParamsOk} = require("../tl/types");
-const {ReqDHParamsRequest} = require("../tl/functions");
-const {SecurityError} = require("../errors/Common");
-const {PQInnerData} = require("../tl/types");
-const BinaryReader = require("../extensions/BinaryReader");
-const {ClientDHInnerData} = require("../tl/types");
-const {DhGenFail} = require("../tl/types");
-const {DhGenRetry} = require("../tl/types");
-const {DhGenOk} = require("../tl/types");
-const {SetClientDHParamsRequest} = require("../tl/functions");
-const {ServerDHInnerData} = require("../tl/types");
-const {ResPQ} = require("../tl/types");
-const {ReqPqMultiRequest} = require("../tl/functions");
-
+const AES = require('../crypto/AES');
+const AuthKey = require('../crypto/AuthKey');
+const Factorizator = require('../crypto/Factorizator');
+const RSA = require('../crypto/RSA');
+const Helpers = require('../utils/Helpers');
+const { ServerDHParamsFail } = require('../tl/types');
+const { ServerDHParamsOk } = require('../tl/types');
+const { ReqDHParamsRequest } = require('../tl/functions');
+const { SecurityError } = require('../errors/Common');
+const { PQInnerData } = require('../tl/types');
+const BinaryReader = require('../extensions/BinaryReader');
+const { ClientDHInnerData } = require('../tl/types');
+const { DhGenFail } = require('../tl/types');
+const { DhGenRetry } = require('../tl/types');
+const { DhGenOk } = require('../tl/types');
+const { SetClientDHParamsRequest } = require('../tl/functions');
+const { ServerDHInnerData } = require('../tl/types');
+const { ResPQ } = require('../tl/types');
+const { ReqPqMultiRequest } = require('../tl/functions');
 
 /**
  * Executes the authentication process with the Telegram servers.
@@ -26,188 +25,164 @@ const {ReqPqMultiRequest} = require("../tl/functions");
  * @returns {Promise<{authKey: *, timeOffset: *}>}
  */
 async function doAuthentication(sender, log) {
-
     // Step 1 sending: PQ Request, endianness doesn't matter since it's random
     let bytes = Helpers.generateRandomBytes(16);
 
-    let nonce = Helpers.readBigIntFromBuffer(bytes, false, true);
+    const nonce = Helpers.readBigIntFromBuffer(bytes, false, true);
 
-    let resPQ = await sender.send(new ReqPqMultiRequest({nonce: nonce}));
-    log.debug("Starting authKey generation step 1");
+    const resPQ = await sender.send(new ReqPqMultiRequest({ nonce: nonce }));
+    log.debug('Starting authKey generation step 1');
 
     if (!(resPQ instanceof ResPQ)) {
-        throw new Error(`Step 1 answer was ${resPQ}`)
+        throw new Error(`Step 1 answer was ${resPQ}`);
     }
     if (resPQ.nonce !== nonce) {
-        throw new SecurityError("Step 1 invalid nonce from server")
+        throw new SecurityError('Step 1 invalid nonce from server');
     }
-    let pq = Helpers.readBigIntFromBuffer(resPQ.pq, false, true);
-    log.debug("Finished authKey generation step 1");
-    log.debug("Starting authKey generation step 2");
+    const pq = Helpers.readBigIntFromBuffer(resPQ.pq, false, true);
+    log.debug('Finished authKey generation step 1');
+    log.debug('Starting authKey generation step 2');
     // Step 2 sending: DH Exchange
-    let {p, q} = Factorizator.factorize(pq);
+    let { p, q } = Factorizator.factorize(pq);
     p = getByteArray(p);
 
     q = getByteArray(q);
 
     bytes = Helpers.generateRandomBytes(32);
-    let newNonce = Helpers.readBigIntFromBuffer(bytes, true, true);
+    const newNonce = Helpers.readBigIntFromBuffer(bytes, true, true);
 
-
-    let pqInnerData = new PQInnerData({
-            pq: getByteArray(pq), //unsigned
-            p: p,
-            q: q,
-            nonce: resPQ.nonce,
-            serverNonce: resPQ.serverNonce,
-            newNonce: newNonce
-
-        }
-    );
+    const pqInnerData = new PQInnerData({
+        pq: getByteArray(pq), // unsigned
+        p: p,
+        q: q,
+        nonce: resPQ.nonce,
+        serverNonce: resPQ.serverNonce,
+        newNonce: newNonce,
+    });
 
     // sha_digest + data + random_bytes
     let cipherText = null;
     let targetFingerprint = null;
-    for (let fingerprint of resPQ.serverPublicKeyFingerprints) {
+    for (const fingerprint of resPQ.serverPublicKeyFingerprints) {
         cipherText = RSA.encrypt(fingerprint.toString(), pqInnerData.bytes);
         if (cipherText !== null && cipherText !== undefined) {
             targetFingerprint = fingerprint;
-            break
+            break;
         }
     }
     if (cipherText === null || cipherText === undefined) {
-        throw new SecurityError(
-            'Step 2 could not find a valid key for fingerprints');
+        throw new SecurityError('Step 2 could not find a valid key for fingerprints');
     }
 
-    let serverDhParams = await sender.send(new ReqDHParamsRequest({
+    const serverDhParams = await sender.send(
+        new ReqDHParamsRequest({
             nonce: resPQ.nonce,
             serverNonce: resPQ.serverNonce,
-            p: p, q: q,
+            p: p,
+            q: q,
             publicKeyFingerprint: targetFingerprint,
-            encryptedData: cipherText
-        }
-    ));
+            encryptedData: cipherText,
+        })
+    );
     if (!(serverDhParams instanceof ServerDHParamsOk || serverDhParams instanceof ServerDHParamsFail)) {
-        throw new Error(`Step 2.1 answer was ${serverDhParams}`)
+        throw new Error(`Step 2.1 answer was ${serverDhParams}`);
     }
     if (serverDhParams.nonce !== resPQ.nonce) {
         throw new SecurityError('Step 2 invalid nonce from server');
-
     }
 
     if (serverDhParams.serverNonce !== resPQ.serverNonce) {
-        throw new SecurityError('Step 2 invalid server nonce from server')
+        throw new SecurityError('Step 2 invalid server nonce from server');
     }
 
     if (serverDhParams instanceof ServerDHParamsFail) {
-        let sh = Helpers.sha1(Helpers.readBufferFromBigInt(newNonce, 32, true, true).slice(4, 20));
-        let nnh = Helpers.readBigIntFromBuffer(sh, true, true);
+        const sh = Helpers.sha1(Helpers.readBufferFromBigInt(newNonce, 32, true, true).slice(4, 20));
+        const nnh = Helpers.readBigIntFromBuffer(sh, true, true);
         if (serverDhParams.newNonceHash !== nnh) {
-            throw new SecurityError('Step 2 invalid DH fail nonce from server')
-
+            throw new SecurityError('Step 2 invalid DH fail nonce from server');
         }
     }
     if (!(serverDhParams instanceof ServerDHParamsOk)) {
         throw new Error(`Step 2.2 answer was ${serverDhParams}`);
     }
-    log.debug("Finished authKey generation step 2");
-    log.debug("Starting authKey generation step 3");
+    log.debug('Finished authKey generation step 2');
+    log.debug('Starting authKey generation step 3');
 
     // Step 3 sending: Complete DH Exchange
-    let {key, iv} = Helpers.generateKeyDataFromNonce(resPQ.serverNonce, newNonce);
+    const { key, iv } = Helpers.generateKeyDataFromNonce(resPQ.serverNonce, newNonce);
     if (serverDhParams.encryptedAnswer.length % 16 !== 0) {
         // See PR#453
-        throw new SecurityError('Step 3 AES block size mismatch')
+        throw new SecurityError('Step 3 AES block size mismatch');
     }
-    let plainTextAnswer = AES.decryptIge(
-        serverDhParams.encryptedAnswer, key, iv
-    );
-    let reader = new BinaryReader(plainTextAnswer);
+    const plainTextAnswer = AES.decryptIge(serverDhParams.encryptedAnswer, key, iv);
+    const reader = new BinaryReader(plainTextAnswer);
     reader.read(20); // hash sum
-    let serverDhInner = reader.tgReadObject();
+    const serverDhInner = reader.tgReadObject();
     if (!(serverDhInner instanceof ServerDHInnerData)) {
-        throw new Error(`Step 3 answer was ${serverDhInner}`)
+        throw new Error(`Step 3 answer was ${serverDhInner}`);
     }
 
     if (serverDhInner.nonce !== resPQ.nonce) {
-        throw new SecurityError('Step 3 Invalid nonce in encrypted answer')
+        throw new SecurityError('Step 3 Invalid nonce in encrypted answer');
     }
     if (serverDhInner.serverNonce !== resPQ.serverNonce) {
-        throw new SecurityError('Step 3 Invalid server nonce in encrypted answer')
+        throw new SecurityError('Step 3 Invalid server nonce in encrypted answer');
     }
-    let dhPrime = Helpers.readBigIntFromBuffer(serverDhInner.dhPrime, false, false);
-    let ga = Helpers.readBigIntFromBuffer(serverDhInner.gA, false, false);
-    let timeOffset = serverDhInner.serverTime - Math.floor(new Date().getTime() / 1000);
+    const dhPrime = Helpers.readBigIntFromBuffer(serverDhInner.dhPrime, false, false);
+    const ga = Helpers.readBigIntFromBuffer(serverDhInner.gA, false, false);
+    const timeOffset = serverDhInner.serverTime - Math.floor(new Date().getTime() / 1000);
 
-    let b = Helpers.readBigIntFromBuffer(Helpers.generateRandomBytes(256), false, false);
-    let gb = Helpers.modExp(BigInt(serverDhInner.g), b, dhPrime);
-    let gab = Helpers.modExp(ga, b, dhPrime);
+    const b = Helpers.readBigIntFromBuffer(Helpers.generateRandomBytes(256), false, false);
+    const gb = Helpers.modExp(BigInt(serverDhInner.g), b, dhPrime);
+    const gab = Helpers.modExp(ga, b, dhPrime);
 
     // Prepare client DH Inner Data
-    let clientDhInner = new ClientDHInnerData({
-            nonce: resPQ.nonce,
-            serverNonce: resPQ.serverNonce,
-            retryId: 0,  // TODO Actual retry ID
-            gB: getByteArray(gb, false)
-        }
-    ).bytes;
-
-    let clientDdhInnerHashed = Buffer.concat([
-        Helpers.sha1(clientDhInner),
-        clientDhInner
-    ]);
+    const { bytes: clientDhInner } = new ClientDHInnerData({
+        nonce: resPQ.nonce,
+        serverNonce: resPQ.serverNonce,
+        retryId: 0, // TODO Actual retry ID
+        gB: getByteArray(gb, false),
+    });
+
+    const clientDdhInnerHashed = Buffer.concat([Helpers.sha1(clientDhInner), clientDhInner]);
     // Encryption
-    let clientDhEncrypted = AES.encryptIge(clientDdhInnerHashed, key, iv);
-    let dhGen = await sender.send(new SetClientDHParamsRequest({
+    const clientDhEncrypted = AES.encryptIge(clientDdhInnerHashed, key, iv);
+    const dhGen = await sender.send(
+        new SetClientDHParamsRequest({
             nonce: resPQ.nonce,
             serverNonce: resPQ.serverNonce,
             encryptedData: clientDhEncrypted,
-        }
-    ));
-    let nonceTypes = [DhGenOk, DhGenRetry, DhGenFail];
+        })
+    );
+    const nonceTypes = [DhGenOk, DhGenRetry, DhGenFail];
     if (!(dhGen instanceof nonceTypes[0] || dhGen instanceof nonceTypes[1] || dhGen instanceof nonceTypes[2])) {
-        throw new Error(`Step 3.1 answer was ${dhGen}`)
+        throw new Error(`Step 3.1 answer was ${dhGen}`);
     }
-    let name = dhGen.constructor.name;
+    const { name } = dhGen.constructor;
     if (dhGen.nonce !== resPQ.nonce) {
-        throw new SecurityError(`Step 3 invalid ${name} nonce from server`)
+        throw new SecurityError(`Step 3 invalid ${name} nonce from server`);
     }
     if (dhGen.serverNonce !== resPQ.serverNonce) {
-        throw new SecurityError(`Step 3 invalid ${name} server nonce from server`)
-
+        throw new SecurityError(`Step 3 invalid ${name} server nonce from server`);
     }
-    let authKey = new AuthKey(getByteArray(gab));
-    let nonceNumber = 1 + nonceTypes.indexOf(dhGen.constructor);
+    const authKey = new AuthKey(getByteArray(gab));
+    const nonceNumber = 1 + nonceTypes.indexOf(dhGen.constructor);
 
-    let newNonceHash = authKey.calcNewNonceHash(newNonce, nonceNumber);
-    let dhHash = dhGen[`newNonceHash${nonceNumber}`];
+    const newNonceHash = authKey.calcNewNonceHash(newNonce, nonceNumber);
+    const dhHash = dhGen[`newNonceHash${nonceNumber}`];
 
     if (dhHash !== newNonceHash) {
         throw new SecurityError('Step 3 invalid new nonce hash');
     }
 
     if (!(dhGen instanceof DhGenOk)) {
-        throw new Error(`Step 3.2 answer was ${dhGen}`)
+        throw new Error(`Step 3.2 answer was ${dhGen}`);
     }
-    log.debug("Finished authKey generation step 3");
-
-    return {authKey, timeOffset};
+    log.debug('Finished authKey generation step 3');
 
-
-}
-
-
-/**
- * Gets a fingerprint text in 01-23-45-67-89-AB-CD-EF format (no hyphens)
- * @param fingerprint {Array}
- * @returns {string}
- */
-function getFingerprintText(fingerprint) {
-    return fingerprint.toString();
+    return { authKey, timeOffset };
 }
 
-
 /**
  * Gets the arbitrary-length byte array corresponding to the given integer
  * @param integer {number,BigInt}
@@ -215,12 +190,9 @@ function getFingerprintText(fingerprint) {
  * @returns {Buffer}
  */
 function getByteArray(integer, signed = false) {
-    let bits = integer.toString(2).length;
-    let byteLength = Math.floor((bits + 8 - 1) / 8);
-    let f;
-    f = Helpers.readBufferFromBigInt(BigInt(integer), byteLength, false, signed);
-
-    return f;
+    const bits = integer.toString(2).length;
+    const byteLength = Math.floor((bits + 8 - 1) / 8);
+    return Helpers.readBufferFromBigInt(BigInt(integer), byteLength, false, signed);
 }
 
 module.exports = doAuthentication;

+ 19 - 26
gramjs/network/MTProtoPlainSender.js

@@ -2,11 +2,11 @@
  *  This module contains the class used to communicate with Telegram's servers
  *  in plain text, when no authorization key has been created yet.
  */
-const Helpers = require("../utils/Helpers");
-const MTProtoState = require("./MTProtoState");
-const struct = require("python-struct");
-const BinaryReader = require("../extensions/BinaryReader");
-const {InvalidBufferError} = require("../errors/Common");
+const Helpers = require('../utils/Helpers');
+const MTProtoState = require('./MTProtoState');
+const struct = require('python-struct');
+const BinaryReader = require('../extensions/BinaryReader');
+const { InvalidBufferError } = require('../errors/Common');
 
 /**
  * MTProto Mobile Protocol plain sender (https://core.telegram.org/mtproto/description#unencrypted-messages)
@@ -21,7 +21,6 @@ class MTProtoPlainSender {
     constructor(connection, loggers) {
         this._state = new MTProtoState(connection, loggers);
         this._connection = connection;
-
     }
 
     /**
@@ -31,24 +30,21 @@ class MTProtoPlainSender {
     async send(request) {
         let body = request.bytes;
         let msgId = this._state._getNewMsgId();
-        let res = Buffer.concat([
-            struct.pack('<qqi', [0, msgId.toString(), body.length]),
-            body
-        ]);
+        const res = Buffer.concat([struct.pack('<qqi', [0, msgId.toString(), body.length]), body]);
 
         await this._connection.send(res);
         body = await this._connection.recv();
         if (body.length < 9) {
             throw new InvalidBufferError(body);
         }
-        let reader = new BinaryReader(body);
-        let authKeyId = reader.readLong();
+        const reader = new BinaryReader(body);
+        const authKeyId = reader.readLong();
         if (authKeyId !== 0n) {
-            throw new Error("Bad authKeyId");
+            throw new Error('Bad authKeyId');
         }
         msgId = reader.readLong();
         if (msgId === 0n) {
-            throw new Error("Bad msgId");
+            throw new Error('Bad msgId');
         }
         /** ^ We should make sure that the read ``msg_id`` is greater
          * than our own ``msg_id``. However, under some circumstances
@@ -56,9 +52,9 @@ class MTProtoPlainSender {
          * be the case, which would cause endless assertion errors.
          */
 
-        let length = reader.readInt();
+        const length = reader.readInt();
         if (length <= 0) {
-            throw new Error("Bad length");
+            throw new Error('Bad length');
         }
         /**
          * We could read length bytes and use those in a new reader to read
@@ -66,29 +62,26 @@ class MTProtoPlainSender {
          * reader isn't used for anything else after this, it's unnecessary.
          */
         return reader.tgReadObject();
-
     }
 
-
     /**
      * Generates a new message ID based on the current time (in ms) since epoch
      * @returns {BigInt}
      */
     getNewMsgId() {
-        //See https://core.telegram.org/mtproto/description#message-identifier-msg-id
-        let msTime = Date.now();
-        let newMsgId = ((BigInt(Math.floor(msTime / 1000)) << BigInt(32)) | // "must approximately equal unixtime*2^32"
+        // See https://core.telegram.org/mtproto/description#message-identifier-msg-id
+        const msTime = Date.now();
+        let newMsgId =
+            (BigInt(Math.floor(msTime / 1000)) << BigInt(32)) | // "must approximately equal unixtime*2^32"
             (BigInt(msTime % 1000) << BigInt(32)) | // "approximate moment in time the message was created"
-            BigInt(Helpers.getRandomInt(0, 524288)) << BigInt(2));// "message identifiers are divisible by 4"
-        //Ensure that we always return a message ID which is higher than the previous one
+            (BigInt(Helpers.getRandomInt(0, 524288)) << BigInt(2)); // "message identifiers are divisible by 4"
+        // Ensure that we always return a message ID which is higher than the previous one
         if (this._lastMsgId >= newMsgId) {
-            newMsgId = this._lastMsgId + 4n
+            newMsgId = this._lastMsgId + 4n;
         }
         this._lastMsgId = newMsgId;
         return BigInt(newMsgId);
-
     }
-
 }
 
 module.exports = MTProtoPlainSender;

+ 147 - 156
gramjs/network/MTProtoSender.js

@@ -1,31 +1,38 @@
-const MtProtoPlainSender = require("./MTProtoPlainSender");
-const MTProtoState = require("./MTProtoState");
-const Helpers = require("../utils/Helpers");
-const {MsgsAck} = require("../tl/types");
-const AuthKey = require("../crypto/AuthKey");
-const doAuthentication = require("./Authenticator");
-const RPCResult = require("../tl/core/RPCResult");
-const MessageContainer = require("../tl/core/MessageContainer");
-const GZIPPacked = require("../tl/core/GZIPPacked");
-const RequestState = require("./RequestState");
+const MtProtoPlainSender = require('./MTProtoPlainSender');
+const MTProtoState = require('./MTProtoState');
+const Helpers = require('../utils/Helpers');
+const { MsgsAck } = require('../tl/types');
+const AuthKey = require('../crypto/AuthKey');
+const doAuthentication = require('./Authenticator');
+const RPCResult = require('../tl/core/RPCResult');
+const MessageContainer = require('../tl/core/MessageContainer');
+const GZIPPacked = require('../tl/core/GZIPPacked');
+const RequestState = require('./RequestState');
 const format = require('string-format');
 
-const MessagePacker = require("../extensions/MessagePacker");
-const Pong = require("../tl/core/GZIPPacked");
-const BinaryReader = require("../extensions/BinaryReader");
+const MessagePacker = require('../extensions/MessagePacker');
+const Pong = require('../tl/core/GZIPPacked');
+const BinaryReader = require('../extensions/BinaryReader');
 const {
-    BadServerSalt, BadMsgNotification, MsgDetailedInfo, MsgNewDetailedInfo,
-    NewSessionCreated, FutureSalts, MsgsStateReq, MsgResendReq, MsgsAllInfo
-} = require("../tl/types");
-const {SecurityError} = require("../errors/Common");
-const {InvalidBufferError} = require("../errors/Common");
-const {LogOutRequest} = require("../tl/functions/auth");
+    BadServerSalt,
+    BadMsgNotification,
+    MsgDetailedInfo,
+    MsgNewDetailedInfo,
+    NewSessionCreated,
+    FutureSalts,
+    MsgsStateReq,
+    MsgResendReq,
+    MsgsAllInfo,
+} = require('../tl/types');
+const { SecurityError } = require('../errors/Common');
+const { InvalidBufferError } = require('../errors/Common');
+const { LogOutRequest } = require('../tl/functions/auth');
 const log4js = require('log4js');
-const {RPCMessageToError} = require("../errors");
-const {TypeNotFoundError} = require("../errors/Common");
-const logger = log4js.getLogger("gramjs");
+const { RPCMessageToError } = require('../errors');
+const { TypeNotFoundError } = require('../errors/Common');
+const logger = log4js.getLogger('gramjs');
 
-//const {tlobjects} = require("../gramjs/tl/alltlobjects");
+// const { tlobjects } = require("../gramjs/tl/alltlobjects");
 format.extend(String.prototype, {});
 
 /**
@@ -42,21 +49,23 @@ format.extend(String.prototype, {});
  * key exists yet.
  */
 class MTProtoSender {
-
     /**
      * @param authKey
      * @param opt
      */
-    constructor(authKey, opt = {
-        logger: null,
-        retries: 5,
-        delay: 1,
-        autoReconnect: true,
-        connectTimeout: null,
-        authKeyCallback: null,
-        updateCallback: null,
-        autoReconnectCallback: null
-    }) {
+    constructor(
+        authKey,
+        opt = {
+            logger: null,
+            retries: 5,
+            delay: 1,
+            autoReconnect: true,
+            connectTimeout: null,
+            authKeyCallback: null,
+            updateCallback: null,
+            autoReconnectCallback: null,
+        }
+    ) {
         this._connection = null;
         this._log = opt.logger;
         this._retries = opt.retries;
@@ -95,8 +104,7 @@ class MTProtoSender {
          * Outgoing messages are put in a queue and sent in a batch.
          * Note that here we're also storing their ``_RequestState``.
          */
-        this._send_queue = new MessagePacker(this._state,
-            this._log);
+        this._send_queue = new MessagePacker(this._state, this._log);
 
         /**
          * Sent states are remembered until a response is received.
@@ -134,9 +142,7 @@ class MTProtoSender {
             [MsgsStateReq.CONSTRUCTOR_ID]: this._handleStateForgotten.bind(this),
             [MsgResendReq.CONSTRUCTOR_ID]: this._handleStateForgotten.bind(this),
             [MsgsAllInfo.CONSTRUCTOR_ID]: this._handleMsgAll.bind(this),
-        }
-
-
+        };
     }
 
     // Public API
@@ -156,8 +162,8 @@ class MTProtoSender {
         return true;
     }
 
-    is_connected() {
-        return this._user_connected
+    isConnected() {
+        return this._user_connected;
     }
 
     /**
@@ -195,15 +201,15 @@ class MTProtoSender {
      */
     send(request) {
         if (!this._user_connected) {
-            throw new Error('Cannot send requests while disconnected')
+            throw new Error('Cannot send requests while disconnected');
         }
 
         if (!Helpers.isArrayLike(request)) {
-            let state = new RequestState(request);
+            const state = new RequestState(request);
             this._send_queue.append(state);
             return state.promise;
         } else {
-            throw new Error("not supported");
+            throw new Error('not supported');
         }
     }
 
@@ -215,14 +221,14 @@ class MTProtoSender {
      * @private
      */
     async _connect() {
-        this._log.info('Connecting to {0}...'.replace("{0}", this._connection));
+        this._log.info('Connecting to {0}...'.replace('{0}', this._connection));
         await this._connection.connect();
-        this._log.debug("Connection success!");
+        this._log.debug('Connection success!');
         if (!this.authKey._key) {
-            let plain = new MtProtoPlainSender(this._connection, this._loggers);
+            const plain = new MtProtoPlainSender(this._connection, this._loggers);
             this._log.debug('New auth_key attempt ...');
-            let res = await doAuthentication(plain, this._log);
-            this._log.debug("Generated new auth_key successfully");
+            const res = await doAuthentication(plain, this._log);
+            this._log.debug('Generated new auth_key successfully');
             this.authKey.key = res.authKey;
             this._state.time_offset = res.timeOffset;
 
@@ -233,40 +239,35 @@ class MTProtoSender {
              * switch to different data centers.
              */
             if (this._authKeyCallback) {
-                this._authKeyCallback(this.authKey)
-
+                this._authKeyCallback(this.authKey);
             }
-
         } else {
             this._log.debug('Already have an auth key ...');
         }
         this._user_connected = true;
 
         this._log.debug('Starting send loop');
-        this._send_loop_handle = this._send_loop();
+        this._send_loop_handle = this._sendLoop();
 
         this._log.debug('Starting receive loop');
-        this._recv_loop_handle = this._recv_loop();
+        this._recv_loop_handle = this._recvLoop();
 
         // _disconnected only completes after manual disconnection
         // or errors after which the sender cannot continue such
         // as failing to reconnect or any unexpected error.
 
-        this._log.info('Connection to %s complete!', this._connection.toString())
-
+        this._log.info('Connection to %s complete!', this._connection.toString());
     }
 
-
     async _disconnect(error = null) {
         if (this._connection === null) {
             this._log.info('Not disconnecting (already have no connection)');
-            return
+            return;
         }
         this._log.info('Disconnecting from %s...', this._connection);
         this._user_connected = false;
         this._log.debug('Closing current connection...');
-        await this._connection.disconnect()
-
+        await this._connection.disconnect();
     }
 
     /**
@@ -276,25 +277,25 @@ class MTProtoSender {
      * @returns {Promise<void>}
      * @private
      */
-    async _send_loop() {
+    async _sendLoop() {
         while (this._user_connected && !this._reconnecting) {
             if (this._pending_ack.size) {
-                let ack = new RequestState(new MsgsAck({msgIds: Array(...this._pending_ack)}));
+                const ack = new RequestState(new MsgsAck({ msgIds: Array(...this._pending_ack) }));
                 this._send_queue.append(ack);
                 this._last_acks.push(ack);
-                this._pending_ack.clear()
+                this._pending_ack.clear();
             }
-            //this._log.debug('Waiting for messages to send...');
-            this._log.debug("Waiting for messages to send...");
+            // this._log.debug('Waiting for messages to send...');
+            this._log.debug('Waiting for messages to send...');
             // TODO Wait for the connection send queue to be empty?
             // This means that while it's not empty we can wait for
             // more messages to be added to the send queue.
-            let res = await this._send_queue.get();
+            const res = await this._send_queue.get();
             if (!res) {
-                continue
+                continue;
             }
             let data = res.data;
-            let batch = res.batch;
+            const batch = res.batch;
             this._log.debug(`Encrypting ${batch.length} message(s) in ${data.length} bytes for sending`);
 
             data = this._state.encryptMessageData(data);
@@ -304,29 +305,28 @@ class MTProtoSender {
             } catch (e) {
                 console.log(e);
                 this._log.info('Connection closed while sending data');
-                return
+                return;
             }
-            for (let state of batch) {
+            for (const state of batch) {
                 this._pending_state[state.msgId] = state;
             }
             this._log.debug('Encrypted messages put in a queue to be sent');
-
         }
     }
 
-
-    async _recv_loop() {
-        let body, message;
+    async _recvLoop() {
+        let body;
+        let message;
 
         while (this._user_connected && !this._reconnecting) {
-            //this._log.debug('Receiving items from the network...');
+            // this._log.debug('Receiving items from the network...');
             this._log.debug('Receiving items from the network...');
             try {
                 body = await this._connection.recv();
             } catch (e) {
-                //this._log.info('Connection closed while receiving data');
+                // this._log.info('Connection closed while receiving data');
                 this._log.debug('Connection closed while receiving data');
-                return
+                return;
             }
             try {
                 message = await this._state.decryptMessageData(body);
@@ -336,33 +336,31 @@ class MTProtoSender {
                 if (e instanceof TypeNotFoundError) {
                     // Received object which we don't know how to deserialize
                     this._log.info(`Type ${e.invalidConstructorId} not found, remaining data ${e.remaining}`);
-                    continue
+                    continue;
                 } else if (e instanceof SecurityError) {
                     // A step while decoding had the incorrect data. This message
                     // should not be considered safe and it should be ignored.
                     this._log.warn(`Security error while unpacking a received message: ${e}`);
-                    continue
+                    continue;
                 } else if (e instanceof InvalidBufferError) {
                     this._log.info('Broken authorization key; resetting');
                     this.authKey.key = null;
                     if (this._authKeyCallback) {
-                        this._authKeyCallback(null)
+                        this._authKeyCallback(null);
                     }
-                    return
+                    return;
                 } else {
                     this._log.error('Unhandled error while receiving data');
-                    return
+                    return;
                 }
             }
             try {
-                await this._processMessage(message)
+                await this._processMessage(message);
             } catch (e) {
                 console.log(e);
                 this._log.error('Unhandled error while receiving data');
-
             }
         }
-
     }
 
     // Response Handlers
@@ -380,7 +378,7 @@ class MTProtoSender {
         message.obj = await message.obj;
         let handler = this._handlers[message.obj.CONSTRUCTOR_ID];
         if (!handler) {
-            handler = this._handleUpdate
+            handler = this._handleUpdate;
         }
 
         await handler(message);
@@ -400,33 +398,32 @@ class MTProtoSender {
             return [state];
         }
 
-        let to_pop = [];
+        const toPop = [];
 
         for (state in this._pending_state) {
             if (state.containerId === msgId) {
-                to_pop.push(state.msgId);
+                toPop.push(state.msgId);
             }
         }
 
-        if (to_pop) {
-            let temp = [];
-            for (let x of to_pop) {
+        if (toPop.length) {
+            const temp = [];
+            for (const x of toPop) {
                 temp.push(this._pending_state[x]);
                 delete this._pending_state[x];
-
             }
-            return temp
+            return temp;
         }
 
-        for (let ack of this._last_acks) {
-            if (ack.msgId === msgId)
-                return [ack]
+        for (const ack of this._last_acks) {
+            if (ack.msgId === msgId) {
+                return [ack];
+            }
         }
 
-        return []
+        return [];
     }
 
-
     /**
      * Handles the result for Remote Procedure Calls:
      * rpc_result#f35c6d01 req_msg_id:long result:bytes = RpcResult;
@@ -436,8 +433,8 @@ class MTProtoSender {
      * @private
      */
     async _handleRPCResult(message) {
-        let RPCResult = message.obj;
-        let state = this._pending_state[RPCResult.reqMsgId];
+        const RPCResult = message.obj;
+        const state = this._pending_state[RPCResult.reqMsgId];
         if (state) {
             delete this._pending_state[RPCResult.reqMsgId];
         }
@@ -449,35 +446,32 @@ class MTProtoSender {
             // See #658, #759 and #958. They seem to happen in a container
             // which contain the real response right after.
             try {
-                let reader = new BinaryReader(RPCResult.body);
+                const reader = new BinaryReader(RPCResult.body);
                 if (!(reader.tgReadObject() instanceof File)) {
-                    throw new TypeNotFoundError("Not an upload.File");
+                    throw new TypeNotFoundError('Not an upload.File');
                 }
             } catch (e) {
                 console.log(e);
                 if (e instanceof TypeNotFoundError) {
                     this._log.info(`Received response without parent request: ${RPCResult.body}`);
-                    return
+                    return;
                 } else {
                     throw e;
                 }
             }
         }
         if (RPCResult.error) {
-            let error = RPCMessageToError(RPCResult.error, state.request);
-            console.log("error happen", error);
+            // eslint-disable-next-line new-cap
+            const error = RPCMessageToError(RPCResult.error, state.request);
+            console.log('error happen', error);
 
-            this._send_queue.append(
-                new RequestState(new MsgsAck({msgIds: [state.msgId]}))
-            );
-            state.reject(error)
+            this._send_queue.append(new RequestState(new MsgsAck({ msgIds: [state.msgId] })));
+            state.reject(error);
         } else {
-            let reader = new BinaryReader(RPCResult.body);
-            let read = await state.request.readResult(reader);
+            const reader = new BinaryReader(RPCResult.body);
+            const read = await state.request.readResult(reader);
             state.resolve(read);
         }
-
-
     }
 
     /**
@@ -489,8 +483,8 @@ class MTProtoSender {
      */
     async _handleContainer(message) {
         this._log.debug('Handling container');
-        for (let inner_message of message.obj.messages) {
-            await this._processMessage(inner_message)
+        for (const innerMessage of message.obj.messages) {
+            await this._processMessage(innerMessage);
         }
     }
 
@@ -503,20 +497,21 @@ class MTProtoSender {
      */
     async _handleGzipPacked(message) {
         this._log.debug('Handling gzipped data');
-        let reader = new BinaryReader(message.obj.data);
+        const reader = new BinaryReader(message.obj.data);
         message.obj = reader.tgReadObject();
-        await this._processMessage(message)
+        await this._processMessage(message);
     }
 
     async _handleUpdate(message) {
-        if (message.obj.SUBCLASS_OF_ID !== 0x8af52aac) {  // crc32(b'Updates')
-            //TODO fix this. currently getting an error about this not being defined.
+        if (message.obj.SUBCLASS_OF_ID !== 0x8af52aac) {
+            // crc32(b'Updates')
+            // TODO fix this. currently getting an error about this not being defined.
             logger.warn(`Note: ${message.obj.constructor.name} is not an update, not dispatching it`);
-            return
+            return;
         }
         this._log.debug('Handling update %s', message.obj.constructor.name);
         if (this._updateCallback) {
-            this._updateCallback(message.obj)
+            this._updateCallback(message.obj);
         }
     }
 
@@ -529,14 +524,14 @@ class MTProtoSender {
      * @private
      */
     async _handlePong(message) {
-        let pong = message.obj;
+        const pong = message.obj;
         this._log.debug(`Handling pong for message ${pong.msgId}`);
-        let state = this._pending_state[pong.msgId];
+        const state = this._pending_state[pong.msgId];
         delete this._pending_state[pong.msgId];
 
         // Todo Check result
         if (state) {
-            state.resolve(pong)
+            state.resolve(pong);
         }
     }
 
@@ -550,10 +545,10 @@ class MTProtoSender {
      * @private
      */
     async _handleBadServerSalt(message) {
-        let badSalt = message.obj;
+        const badSalt = message.obj;
         this._log.debug(`Handling bad salt for message ${badSalt.badMsgId}`);
         this._state.salt = badSalt.newServerSalt;
-        let states = this._popStates(badSalt.badMsgId);
+        const states = this._popStates(badSalt.badMsgId);
         this._send_queue.extend(states);
         this._log.debug(`${states.length} message(s) will be resent`);
     }
@@ -568,33 +563,33 @@ class MTProtoSender {
      * @private
      */
     async _handleBadNotification(message) {
-        let badMsg = message.obj;
-        let states = this._popStates(badMsg.badMsgId);
+        const badMsg = message.obj;
+        const states = this._popStates(badMsg.badMsgId);
         this._log.debug(`Handling bad msg ${badMsg}`);
         if ([16, 17].contains(badMsg.errorCode)) {
             // Sent msg_id too low or too high (respectively).
             // Use the current msg_id to determine the right time offset.
-            let to = this._state.updateTimeOffset(message.msgId);
+            const to = this._state.updateTimeOffset(message.msgId);
             this._log.info(`System clock is wrong, set time offset to ${to}s`);
         } else if (badMsg.errorCode === 32) {
             // msg_seqno too low, so just pump it up by some "large" amount
             // TODO A better fix would be to start with a new fresh session ID
-            this._state._sequence += 64
+            this._state._sequence += 64;
         } else if (badMsg.errorCode === 33) {
             // msg_seqno too high never seems to happen but just in case
-            this._state._sequence -= 16
+            this._state._sequence -= 16;
         } else {
-            for (let state of states) {
-                // TODO set errors;
-                /* state.future.set_exception(
-                BadMessageError(state.request, bad_msg.error_code))*/
-            }
+            // for (const state of states) {
+            // TODO set errors;
+            /* state.future.set_exception(
+            BadMessageError(state.request, bad_msg.error_code))*/
+            // }
 
-            return
+            return;
         }
         // Messages are to be re-sent once we've corrected the issue
         this._send_queue.extend(states);
-        this._log.debug(`${states.length} messages will be resent due to bad msg`)
+        this._log.debug(`${states.length} messages will be resent due to bad msg`);
     }
 
     /**
@@ -607,9 +602,9 @@ class MTProtoSender {
      */
     async _handleDetailedInfo(message) {
         // TODO https://goo.gl/VvpCC6
-        let msgId = message.obj.answerMsgId;
+        const msgId = message.obj.answerMsgId;
         this._log.debug(`Handling detailed info for message ${msgId}`);
-        this._pending_ack.add(msgId)
+        this._pending_ack.add(msgId);
     }
 
     /**
@@ -622,9 +617,9 @@ class MTProtoSender {
      */
     async _handleNewDetailedInfo(message) {
         // TODO https://goo.gl/VvpCC6
-        let msgId = message.obj.answerMsgId;
+        const msgId = message.obj.answerMsgId;
         this._log.debug(`Handling new detailed info for message ${msgId}`);
-        this._pending_ack.add(msgId)
+        this._pending_ack.add(msgId);
     }
 
     /**
@@ -660,16 +655,15 @@ class MTProtoSender {
      * @private
      */
     async _handleAck(message) {
-        let ack = message.obj;
+        const ack = message.obj;
         this._log.debug(`Handling acknowledge for ${ack.msgIds}`);
-        for (let msgId of ack.msgIds) {
-            let state = this._pending_state[msgId];
+        for (const msgId of ack.msgIds) {
+            const state = this._pending_state[msgId];
             if (state && state.request instanceof LogOutRequest) {
                 delete this._pending_state[msgId];
-                state.resolve(true)
+                state.resolve(true);
             }
         }
-
     }
 
     /**
@@ -685,11 +679,11 @@ class MTProtoSender {
         // TODO save these salts and automatically adjust to the
         // correct one whenever the salt in use expires.
         this._log.debug(`Handling future salts for message ${message.msgId}`);
-        let state = this._pending_state[message.msgId];
+        const state = this._pending_state[message.msgId];
 
         if (state) {
             delete this._pending_state[message];
-            state.resolve(message.obj)
+            state.resolve(message.obj);
         }
     }
 
@@ -701,8 +695,9 @@ class MTProtoSender {
      * @private
      */
     async _handleStateForgotten(message) {
-        this._send_queue.append(new RequestState(new MsgsStateInfo(
-            message.msgId, String.fromCharCode(1).repeat(message.obj.msgIds))))
+        this._send_queue.append(
+            new RequestState(new MsgsStateInfo(message.msgId, String.fromCharCode(1).repeat(message.obj.msgIds)))
+        );
     }
 
     /**
@@ -711,11 +706,7 @@ class MTProtoSender {
      * @returns {Promise<void>}
      * @private
      */
-    async _handleMsgAll(message) {
-
-    }
-
-
+    async _handleMsgAll(message) {}
 }
 
 module.exports = MTProtoSender;

+ 46 - 88
gramjs/network/MTProtoState.js

@@ -1,11 +1,11 @@
-const struct = require("python-struct");
-const Helpers = require("../utils/Helpers");
-const AES = require("../crypto/AES");
-const BinaryReader = require("../extensions/BinaryReader");
-const GZIPPacked = require("../tl/core/GZIPPacked");
-const {TLMessage} = require("../tl/core");
-const {SecurityError} = require("../errors/Common");
-const {InvalidBufferError} = require("../errors/Common");
+const struct = require('python-struct');
+const Helpers = require('../utils/Helpers');
+const AES = require('../crypto/AES');
+const BinaryReader = require('../extensions/BinaryReader');
+const GZIPPacked = require('../tl/core/GZIPPacked');
+const { TLMessage } = require('../tl/core');
+const { SecurityError } = require('../errors/Common');
+const { InvalidBufferError } = require('../errors/Common');
 
 class MTProtoState {
     /**
@@ -70,26 +70,13 @@ class MTProtoState {
      * @returns {{iv: Buffer, key: Buffer}}
      */
     _calcKey(authKey, msgKey, client) {
-        let x = client === true ? 0 : 8;
-        let sha256a = Helpers.sha256(Buffer.concat([
-            msgKey,
-            authKey.slice(x, (x + 36))
-        ]));
-        let sha256b = Helpers.sha256(Buffer.concat([
-            authKey.slice(x + 40, x + 76),
-            msgKey,
-        ]));
-
-        let key = Buffer.concat([
-            sha256a.slice(0, 8),
-            sha256b.slice(8, 24),
-            sha256a.slice(24, 32)]);
-        let iv = Buffer.concat([
-            sha256b.slice(0, 8),
-            sha256a.slice(8, 24),
-            sha256b.slice(24, 32)]);
-        return {key, iv}
+        const x = client === true ? 0 : 8;
+        const sha256a = Helpers.sha256(Buffer.concat([msgKey, authKey.slice(x, x + 36)]));
+        const sha256b = Helpers.sha256(Buffer.concat([authKey.slice(x + 40, x + 76), msgKey]));
 
+        const key = Buffer.concat([sha256a.slice(0, 8), sha256b.slice(8, 24), sha256a.slice(24, 32)]);
+        const iv = Buffer.concat([sha256b.slice(0, 8), sha256a.slice(8, 24), sha256b.slice(24, 32)]);
+        return { key, iv };
     }
 
     /**
@@ -101,15 +88,13 @@ class MTProtoState {
      * @param afterId
      */
     async writeDataAsMessage(buffer, data, contentRelated, afterId) {
-        let msgId = this._getNewMsgId();
-        let seqNo = this._getSeqNo(contentRelated);
+        const msgId = this._getNewMsgId();
+        const seqNo = this._getSeqNo(contentRelated);
         let body;
         if (!afterId) {
-            body = await GZIPPacked.GZIPIfSmaller(contentRelated, data);
+            body = await GZIPPacked.gzipIfSmaller(contentRelated, data);
         } else {
-            body = await GZIPPacked.GZIPIfSmaller(contentRelated,
-                new InvokeAfterMsgRequest(afterId, data).toBuffer()
-            );
+            body = await GZIPPacked.gzipIfSmaller(contentRelated, new InvokeAfterMsgRequest(afterId, data).toBuffer());
         }
         buffer.write(struct.pack('<qii', msgId.toString(), seqNo, body.length));
         buffer.write(body);
@@ -122,37 +107,18 @@ class MTProtoState {
      * @param data
      */
     encryptMessageData(data) {
-        data = Buffer.concat([
-            struct.pack('<qq', this.salt.toString(), this.id.toString()),
-            data,
-        ]);
-        let padding = Helpers.generateRandomBytes(Helpers.mod(-(data.length + 12), 16) + 12);
+        data = Buffer.concat([struct.pack('<qq', this.salt.toString(), this.id.toString()), data]);
+        const padding = Helpers.generateRandomBytes(Helpers.mod(-(data.length + 12), 16) + 12);
         // Being substr(what, offset, length); x = 0 for client
         // "msg_key_large = SHA256(substr(auth_key, 88+x, 32) + pt + padding)"
-        let msgKeyLarge = Helpers.sha256(
-            Buffer.concat([
-                this.authKey.key.slice(88, 88 + 32),
-                data,
-                padding
-            ])
-        );
+        const msgKeyLarge = Helpers.sha256(Buffer.concat([this.authKey.key.slice(88, 88 + 32), data, padding]));
         // "msg_key = substr (msg_key_large, 8, 16)"
-        let msgKey = msgKeyLarge.slice(8, 24);
+        const msgKey = msgKeyLarge.slice(8, 24);
 
-        let {iv, key} = this._calcKey(this.authKey.key, msgKey, true);
-
-        let keyId = Helpers.readBufferFromBigInt(this.authKey.keyId, 8);
-        return Buffer.concat([
-            keyId,
-            msgKey,
-            AES.encryptIge(Buffer.concat([
-                    data,
-                    padding
-                ]),
-                key,
-                iv)
-        ]);
+        const { iv, key } = this._calcKey(this.authKey.key, msgKey, true);
 
+        const keyId = Helpers.readBufferFromBigInt(this.authKey.keyId, 8);
+        return Buffer.concat([keyId, msgKey, AES.encryptIge(Buffer.concat([data, padding]), key, iv)]);
     }
 
     /**
@@ -165,47 +131,42 @@ class MTProtoState {
         }
 
         // TODO Check salt,sessionId, and sequenceNumber
-        let keyId = Helpers.readBigIntFromBuffer(body.slice(0, 8));
+        const keyId = Helpers.readBigIntFromBuffer(body.slice(0, 8));
 
         if (keyId !== this.authKey.keyId) {
             throw new SecurityError('Server replied with an invalid auth key');
         }
 
-        let msgKey = body.slice(8, 24);
-        let {iv, key} = this._calcKey(this.authKey.key, msgKey, false);
+        const msgKey = body.slice(8, 24);
+        const { iv, key } = this._calcKey(this.authKey.key, msgKey, false);
         body = AES.decryptIge(body.slice(24), key, iv);
 
         // https://core.telegram.org/mtproto/security_guidelines
         // Sections "checking sha256 hash" and "message length"
 
-        let ourKey = Helpers.sha256(Buffer.concat([
-            this.authKey.key.slice(96, 96 + 32),
-            body
-        ]));
+        const ourKey = Helpers.sha256(Buffer.concat([this.authKey.key.slice(96, 96 + 32), body]));
 
         if (!msgKey.equals(ourKey.slice(8, 24))) {
-            throw new SecurityError(
-                "Received msg_key doesn't match with expected one")
+            throw new SecurityError('Received msg_key doesn\'t match with expected one');
         }
 
-        let reader = new BinaryReader(body);
+        const reader = new BinaryReader(body);
         reader.readLong(); // removeSalt
-        let serverId = reader.readLong();
+        const serverId = reader.readLong();
         if (serverId !== this.id) {
-            //throw new SecurityError('Server replied with a wrong session ID');
+            // throw new SecurityError('Server replied with a wrong session ID');
         }
 
-        let remoteMsgId = reader.readLong();
-        let remoteSequence = reader.readInt();
+        const remoteMsgId = reader.readLong();
+        const remoteSequence = reader.readInt();
         reader.readInt(); // msgLen for the inner object, padding ignored
 
         // We could read msg_len bytes and use those in a new reader to read
         // the next TLObject without including the padding, but since the
         // reader isn't used for anything else after this, it's unnecessary.
-        let obj = await reader.tgReadObject();
+        const obj = await reader.tgReadObject();
 
         return new TLMessage(remoteMsgId, remoteSequence, obj);
-
     }
 
     /**
@@ -214,9 +175,8 @@ class MTProtoState {
      * @private
      */
     _getNewMsgId() {
-
-        let now = new Date().getTime() / 1000 + this.timeOffset;
-        let nanoseconds = Math.floor((now - Math.floor(now)) * 1e+9);
+        const now = new Date().getTime() / 1000 + this.timeOffset;
+        const nanoseconds = Math.floor((now - Math.floor(now)) * 1e9);
         let newMsgId = (BigInt(Math.floor(now)) << 32n) | (BigInt(nanoseconds) << 2n);
         if (this._lastMsgId >= newMsgId) {
             newMsgId = this._lastMsgId + 4n;
@@ -232,17 +192,17 @@ class MTProtoState {
      * @param correctMsgId
      */
     updateTimeOffset(correctMsgId) {
-        let bad = this._getNewMsgId();
-        let old = this.timeOffset;
-        let now = Math.floor(new Date().getTime() / 1000);
-        let correct = correctMsgId >> 32n;
+        const bad = this._getNewMsgId();
+        const old = this.timeOffset;
+        const now = Math.floor(new Date().getTime() / 1000);
+        const correct = correctMsgId >> 32n;
         this.timeOffset = correct - now;
 
         if (this.timeOffset !== old) {
             this._lastMsgId = 0;
             this._log.debug(
-                `Updated time offset (old offset ${old}, bad ${bad}, good ${correctMsgId}, new ${this.timeOffset})`,
-            )
+                `Updated time offset (old offset ${old}, bad ${bad}, good ${correctMsgId}, new ${this.timeOffset})`
+            );
         }
 
         return this.timeOffset;
@@ -256,15 +216,13 @@ class MTProtoState {
      */
     _getSeqNo(contentRelated) {
         if (contentRelated) {
-            let result = this._sequence * 2 + 1;
+            const result = this._sequence * 2 + 1;
             this._sequence += 1;
             return result;
         } else {
             return this._sequence * 2;
         }
     }
-
 }
 
-
-module.exports = MTProtoState;
+module.exports = MTProtoState;

+ 2 - 7
gramjs/network/RequestState.js

@@ -1,8 +1,4 @@
-const Helpers = require("../utils/Helpers");
-
 class RequestState {
-
-
     constructor(request, after = null) {
         this.containerId = null;
         this.msgId = null;
@@ -12,10 +8,9 @@ class RequestState {
         this.result = null;
         this.promise = new Promise((resolve, reject) => {
             this.resolve = resolve;
-            this.reject = reject
+            this.reject = reject;
         });
     }
-
 }
 
-module.exports = RequestState;
+module.exports = RequestState;

+ 23 - 30
gramjs/network/connection/Connection.js

@@ -1,6 +1,6 @@
-const {PromiseSocket, TimeoutError} = require("promise-socket");
-const {Socket} = require("net");
-const Helpers = require("../../utils/Helpers");
+const { PromiseSocket } = require('promise-socket');
+const { Socket } = require('net');
+const Helpers = require('../../utils/Helpers');
 
 /**
  * The `Connection` class is a wrapper around ``asyncio.open_connection``.
@@ -14,7 +14,7 @@ const Helpers = require("../../utils/Helpers");
  * the client is disconnected (includes remote disconnections).
  */
 class Connection {
-    packetCodec = null;
+    PacketCodecClass = null;
 
     constructor(ip, port, dcId, loggers) {
         this._ip = ip;
@@ -27,18 +27,17 @@ class Connection {
         this._sendTask = null;
         this._recvTask = null;
         this._codec = null;
-        this._obfuscation = null;  // TcpObfuscated and MTProxy
+        this._obfuscation = null; // TcpObfuscated and MTProxy
         this._sendArray = [];
         this._recvArray = [];
         this.socket = new PromiseSocket(new Socket());
-
     }
 
     async _connect() {
         await this.socket.connect(this._port, this._ip);
 
-        //await this.socket.connect({host: this._ip, port: this._port});
-        this._codec = new this.packetCodec(this);
+        // await this.socket.connect({host: this._ip, port: this._port});
+        this._codec = new this.PacketCodecClass(this);
         this._initConn();
     }
 
@@ -56,7 +55,7 @@ class Connection {
 
     async send(data) {
         if (!this._connected) {
-            throw new Error("Not connected");
+            throw new Error('Not connected');
         }
         while (this._sendArray.length !== 0) {
             await Helpers.sleep(1000);
@@ -66,35 +65,31 @@ class Connection {
 
     async recv() {
         while (this._connected) {
-
             while (this._recvArray.length === 0) {
                 await Helpers.sleep(1000);
             }
-            let result = this._recvArray.pop();
+            const result = this._recvArray.pop();
 
-            if (result) { // null = sentinel value = keep trying
-                return result
+            // null = sentinel value = keep trying
+            if (result) {
+                return result;
             }
         }
-        throw new Error("Not connected");
+        throw new Error('Not connected');
     }
 
     async _sendLoop() {
         // TODO handle errors
         try {
-
-
             while (this._connected) {
                 while (this._sendArray.length === 0) {
                     await Helpers.sleep(1000);
                 }
                 await this._send(this._sendArray.pop());
-
             }
         } catch (e) {
             console.log(e);
-            this._log.info('The server closed the connection while sending')
-
+            this._log.info('The server closed the connection while sending');
         }
     }
 
@@ -105,7 +100,7 @@ class Connection {
                 data = await this._recv();
             } catch (e) {
                 console.log(e);
-                this._log.info("The server closed the connection")
+                this._log.info('The server closed the connection');
             }
             while (this._recvArray.length !== 0) {
                 await Helpers.sleep(1000);
@@ -122,9 +117,8 @@ class Connection {
     }
 
     async _send(data) {
-        let encodedPacket = this._codec.encodePacket(data);
+        const encodedPacket = this._codec.encodePacket(data);
         await this.socket.write(encodedPacket);
-
     }
 
     async _recv() {
@@ -132,9 +126,8 @@ class Connection {
     }
 
     toString() {
-        return `${this._ip}:${this._port}/${this.constructor.name.replace("Connection", "")}`
+        return `${this._ip}:${this._port}/${this.constructor.name.replace('Connection', '')}`;
     }
-
 }
 
 class PacketCodec {
@@ -143,18 +136,18 @@ class PacketCodec {
     }
 
     encodePacket(data) {
-        throw new Error("Not Implemented")
+        throw new Error('Not Implemented');
 
-        //Override
+        // Override
     }
 
     async readPacket(reader) {
-        //override
-        throw new Error("Not Implemented")
+        // override
+        throw new Error('Not Implemented');
     }
 }
 
 module.exports = {
     Connection,
-    PacketCodec
-};
+    PacketCodec,
+};

+ 18 - 22
gramjs/network/connection/TCPFull.js

@@ -1,9 +1,7 @@
-const {Connection, PacketCodec} = require("./Connection");
-const struct = require("python-struct");
-const {crc32} = require("crc");
-const {InvalidChecksumError} = require("../../errors/Common");
-const Socket = require("net").Socket;
-const Helpers = require("../../utils/Helpers");
+const { Connection, PacketCodec } = require('./Connection');
+const struct = require('python-struct');
+const { crc32 } = require('crc');
+const { InvalidChecksumError } = require('../../errors/Common');
 
 class FullPacketCodec extends PacketCodec {
     constructor(connection) {
@@ -14,9 +12,9 @@ class FullPacketCodec extends PacketCodec {
     encodePacket(data) {
         // https://core.telegram.org/mtproto#tcp-transport
         // total length, sequence number, packet and checksum (CRC32)
-        let length = data.length + 12;
+        const length = data.length + 12;
         data = Buffer.concat([struct.pack('<ii', length, this._sendCounter), data]);
-        let crc = struct.pack('<I', crc32(data));
+        const crc = struct.pack('<I', crc32(data));
         this._sendCounter += 1;
         return Buffer.concat([data, crc]);
     }
@@ -27,24 +25,22 @@ class FullPacketCodec extends PacketCodec {
      * @returns {Promise<*>}
      */
     async readPacket(reader) {
-        let packetLenSeq = await reader.read(8); // 4 and 4
-        //process.exit(0);
+        const packetLenSeq = await reader.read(8); // 4 and 4
+        // process.exit(0);
 
         if (packetLenSeq === undefined) {
-            console.log("connection closed. exiting");
-            process.exit(0)
-            throw new Error("closed connection");
-
+            console.log('connection closed. exiting');
+            process.exit(0);
+            throw new Error('closed connection');
         }
 
-        let res = struct.unpack("<ii", packetLenSeq);
-        let packetLen = res[0];
-        let seq = res[1];
+        const res = struct.unpack('<ii', packetLenSeq);
+        const [packetLen] = res;
         let body = await reader.read(packetLen - 8);
-        let checksum = struct.unpack("<I", body.slice(-4))[0];
+        const [checksum] = struct.unpack('<I', body.slice(-4));
         body = body.slice(0, -4);
 
-        let validChecksum = crc32(Buffer.concat([packetLenSeq, body]));
+        const validChecksum = crc32(Buffer.concat([packetLenSeq, body]));
         if (!(validChecksum === checksum)) {
             throw new InvalidChecksumError(checksum, validChecksum);
         }
@@ -53,10 +49,10 @@ class FullPacketCodec extends PacketCodec {
 }
 
 class ConnectionTCPFull extends Connection {
-    packetCodec = FullPacketCodec;
+    PacketCodecClass = FullPacketCodec;
 }
 
 module.exports = {
     FullPacketCodec,
-    ConnectionTCPFull
-};
+    ConnectionTCPFull,
+};

+ 4 - 9
gramjs/tl/MTProtoRequest.js

@@ -1,8 +1,7 @@
 class MTProtoRequest {
-
     constructor() {
         this.sent = false;
-        this.msgId = 0; //long
+        this.msgId = 0; // long
         this.sequence = 0;
 
         this.dirty = false;
@@ -32,16 +31,12 @@ class MTProtoRequest {
 
     // These should be overrode
     onSend() {
-        throw Error("Not overload " + this.constructor.name);
+        throw Error('Not overload ' + this.constructor.name);
     }
 
-    onResponse(buffer) {
-
-    }
+    onResponse(buffer) {}
 
-    onException(exception) {
-
-    }
+    onException(exception) {}
 }
 
 module.exports = MTProtoRequest;

+ 26 - 29
gramjs/tl/Session.js

@@ -1,25 +1,27 @@
-const Helpers = require("../utils/Helpers");
-const fs = require("fs").promises;
-const {existsSync, readFileSync} = require("fs");
-const AuthKey = require("../crypto/AuthKey");
-BigInt.toJSON = function () {
-    return {fool: this.fool.toString("hex")}
-};
-BigInt.parseJson = function () {
-    return {fool: BigInt("0x" + this.fool)}
-};
+const Helpers = require('../utils/Helpers');
+const fs = require('fs').promises;
+const { existsSync, readFileSync } = require('fs');
+const AuthKey = require('../crypto/AuthKey');
+
 const DEFAULT_DC_ID = 4;
 const DEFAULT_IPV4_IP = '149.154.167.92';
 const DEFAULT_IPV6_IP = '[2001:67c:4e8:f002::a]';
 const DEFAULT_PORT = 443;
 
+BigInt.toJSON = function() {
+    return { fool: this.fool.toString('hex') };
+};
+BigInt.parseJson = function() {
+    return { fool: BigInt('0x' + this.fool) };
+};
+
 class Session {
     constructor(sessionUserId) {
         this.sessionUserId = sessionUserId;
         this.serverAddress = DEFAULT_IPV4_IP;
         this.port = DEFAULT_PORT;
-        //this.serverAddress = "localhost";
-        //this.port = 21;
+        // this.serverAddress = "localhost";
+        // this.port = 21;
         this.authKey = undefined;
         this.id = Helpers.generateRandomLong(false);
         this.sequence = 0;
@@ -27,8 +29,6 @@ class Session {
         this.timeOffset = 0n;
         this.lastMessageId = 0n;
         this.user = undefined;
-
-
     }
 
     /**
@@ -36,15 +36,14 @@ class Session {
      */
     async save() {
         if (this.sessionUserId) {
-            let str = JSON.stringify(this, function (key, value) {
+            const str = JSON.stringify(this, function(key, value) {
                 if (typeof value === 'bigint') {
-                    return value.toString() + "n";
+                    return value.toString() + 'n';
                 } else {
                     return value;
                 }
             });
 
-
             await fs.writeFile(`${this.sessionUserId}.session`, str);
         }
     }
@@ -53,24 +52,22 @@ class Session {
         if (sessionUserId === undefined) {
             return new Session();
         }
-        let filepath = `${sessionUserId}.session`;
+        const filepath = `${sessionUserId}.session`;
         if (existsSync(filepath)) {
-
-            let ob = JSON.parse(readFileSync(filepath, "utf-8"), function (key, value) {
-                if ((typeof value) == "string" && value.match(/(\d+)n/)) {
+            const ob = JSON.parse(readFileSync(filepath, 'utf-8'), function(key, value) {
+                if (typeof value == 'string' && value.match(/(\d+)n/)) {
                     return BigInt(value.slice(0, -1));
                 } else {
                     return value;
                 }
             });
 
-
-            let authKey = new AuthKey(Buffer.from(ob.authKey._key.data));
-            let session = new Session(ob.sessionUserId);
+            const authKey = new AuthKey(Buffer.from(ob.authKey._key.data));
+            const session = new Session(ob.sessionUserId);
             session.serverAddress = ob.serverAddress;
             session.port = ob.port;
-            //this.serverAddress = "localhost";
-            //this.port = 21;
+            // this.serverAddress = "localhost";
+            // this.port = 21;
             session.authKey = authKey;
             session.id = ob.id;
             session.sequence = ob.sequence;
@@ -85,8 +82,9 @@ class Session {
     }
 
     getNewMsgId() {
-        let msTime = new Date().getTime();
-        let newMessageId = (BigInt(BigInt(Math.floor(msTime / 1000)) + this.timeOffset) << 32n) |
+        const msTime = new Date().getTime();
+        let newMessageId =
+            (BigInt(BigInt(Math.floor(msTime / 1000)) + this.timeOffset) << 32n) |
             (BigInt(msTime % 1000) << 22n) |
             (BigInt(Helpers.getRandomInt(0, 524288)) << 2n); // 2^19
 
@@ -99,4 +97,3 @@ class Session {
 }
 
 module.exports = Session;
-

+ 34 - 39
gramjs/tl/TelegramClient.js

@@ -1,53 +1,48 @@
-const Session = require("./Session");
-const doAuthentication = require("../network/Authenticator");
-const MtProtoSender = require("../network/mtprotoSender");
-const MTProtoRequest = require("../tl/MTProtoRequest");
-const {ImportBotAuthorizationRequest} = require("./functions/auth");
-const {ConnectionTCPFull} = require("../network/connection/TCPFull");
-const {TLRequest} = require("./tlobject");
-const {InvokeWithLayerRequest, InitConnectionRequest} = require("./functions/index");
-const {GetConfigRequest} = require("./functions/help");
-const {LAYER} = require("../tl/alltlobjects");
+const Session = require('./Session');
+const MtProtoSender = require('../network/mtprotoSender');
+const { ImportBotAuthorizationRequest } = require('./functions/auth');
+const { ConnectionTCPFull } = require('../network/connection/TCPFull');
+const { TLRequest } = require('./tlobject');
+const { InvokeWithLayerRequest, InitConnectionRequest } = require('./functions/index');
+const { GetConfigRequest } = require('./functions/help');
+const { LAYER } = require('../tl/alltlobjects');
 const log4js = require('log4js');
 
 class TelegramClient {
-
     constructor(sessionUserId, apiId, apiHash, connection = ConnectionTCPFull) {
         if (apiId === undefined || apiHash === undefined) {
-            throw Error("Your API ID or Hash are invalid. Please read \"Requirements\" on README.md");
+            throw Error('Your API ID or Hash are invalid. Please read "Requirements" on README.md');
         }
 
         this.apiId = apiId;
         this.apiHash = apiHash;
         this._connection = ConnectionTCPFull;
-        this._log = log4js.getLogger("gramjs");
+        this._log = log4js.getLogger('gramjs');
         this._initWith = (x) => {
             return new InvokeWithLayerRequest({
                 layer: LAYER,
                 query: new InitConnectionRequest({
                     apiId: this.apiId,
-                    deviceModel: "Windows",
-                    systemVersion: "1.8.3",
-                    appVersion: "1.8",
-                    langCode: "en",
-                    langPack: "",
-                    systemLangCode: "en",
+                    deviceModel: 'Windows',
+                    systemVersion: '1.8.3',
+                    appVersion: '1.8',
+                    langCode: 'en',
+                    langPack: '',
+                    systemLangCode: 'en',
                     query: x,
                     proxy: null,
-                })
-            })
+                }),
+            });
         };
         this.session = Session.tryLoadOrCreateNew(sessionUserId);
-        //These will be set later
+        // These will be set later
         this.dcOptions = null;
         this._sender = new MtProtoSender(this.session.authKey, {
             logger: this._log,
         });
-        this.phoneCodeHashes = Array();
-
+        this.phoneCodeHashes = [];
     }
 
-
     /**
      * Connects to the Telegram servers, executing authentication if required.
      * Note that authenticating to the Telegram servers is not the same as authenticating
@@ -55,19 +50,20 @@ class TelegramClient {
      * @returns {Promise<void>}
      */
     async connect() {
-        let connection = new this._connection(this.session.serverAddress, this.session.port, this.session.dcId, this._log);
-        if (!await this._sender.connect(connection)) {
+        const connection = new this._connection(
+            this.session.serverAddress,
+            this.session.port,
+            this.session.dcId,
+            this._log
+        );
+        if (!(await this._sender.connect(connection))) {
             return;
         }
         this.session.authKey = this._sender.authKey;
         await this.session.save();
-        await this._sender.send(this._initWith(
-            new GetConfigRequest()
-        ));
-
+        await this._sender.send(this._initWith(new GetConfigRequest()));
     }
 
-
     /**
      * Disconnects from the Telegram server
      * @returns {Promise<void>}
@@ -85,13 +81,12 @@ class TelegramClient {
      */
     async invoke(request) {
         if (!(request instanceof TLRequest)) {
-            throw new Error("You can only invoke MTProtoRequests");
+            throw new Error('You can only invoke MTProtoRequests');
         }
-        let res = await this._sender.send(request);
+        const res = await this._sender.send(request);
         return res;
     }
 
-
     /**
      * Logs in to Telegram to an existing user or bot account.
 
@@ -106,15 +101,15 @@ class TelegramClient {
      * @param args {{botToken: string}}
      * @returns {Promise<void>}
      */
-    async signIn(args = {phone: null, code: null, password: null, botToken: null, phoneCodeHash: null}) {
-        let botToken = args.botToken;
-        let request = new ImportBotAuthorizationRequest({
+    async signIn(args = { phone: null, code: null, password: null, botToken: null, phoneCodeHash: null }) {
+        const botToken = args.botToken;
+        const request = new ImportBotAuthorizationRequest({
             flags: 0,
             botAuthToken: botToken,
             apiId: this.apiId,
             apiHash: this.apiHash,
         });
-        let result = await this.invoke(request);
+        const result = await this.invoke(request);
         return result;
     }
 }

+ 11 - 12
gramjs/tl/core/GZIPPacked.js

@@ -1,7 +1,7 @@
-const {TLObject} = require("../tlobject");
-const struct = require("python-struct");
-const {ungzip} = require("node-gzip");
-const {gzip} = require("node-gzip");
+const { TLObject } = require('../tlobject');
+const struct = require('python-struct');
+const { ungzip } = require('node-gzip');
+const { gzip } = require('node-gzip');
 
 class GZIPPacked extends TLObject {
     static CONSTRUCTOR_ID = 0x3072cfa1;
@@ -12,9 +12,9 @@ class GZIPPacked extends TLObject {
         this.CONSTRUCTOR_ID = 0x3072cfa1;
     }
 
-    static async GZIPIfSmaller(contentRelated, data) {
+    static async gzipIfSmaller(contentRelated, data) {
         if (contentRelated && data.length > 512) {
-            let gzipped = await (new GZIPPacked(data)).toBytes();
+            const gzipped = await new GZIPPacked(data).toBytes();
             if (gzipped.length < data.length) {
                 return gzipped;
             }
@@ -24,15 +24,15 @@ class GZIPPacked extends TLObject {
 
     async toBytes() {
         return Buffer.concat([
-            struct.pack("<I", GZIPPacked.CONSTRUCTOR_ID),
-            TLObject.serializeBytes(await gzip(this.data))
-        ])
+            struct.pack('<I', GZIPPacked.CONSTRUCTOR_ID),
+            TLObject.serializeBytes(await gzip(this.data)),
+        ]);
     }
 
     static async read(reader) {
-        let constructor = reader.readInt(false);
+        const constructor = reader.readInt(false);
         if (constructor !== GZIPPacked.CONSTRUCTOR_ID) {
-            throw new Error("not equal");
+            throw new Error('not equal');
         }
         return await gzip(reader.tgReadBytes());
     }
@@ -40,7 +40,6 @@ class GZIPPacked extends TLObject {
     static async fromReader(reader) {
         return new GZIPPacked(await ungzip(reader.tgReadBytes()));
     }
-
 }
 
 module.exports = GZIPPacked;

+ 12 - 14
gramjs/tl/core/MessageContainer.js

@@ -1,6 +1,5 @@
-const {TLObject} = require("../tlobject");
-const struct = require("python-struct");
-const TLMessage = require("./TLMessage");
+const { TLObject } = require('../tlobject');
+const TLMessage = require('./TLMessage');
 
 class MessageContainer extends TLObject {
     static CONSTRUCTOR_ID = 0x73f1f8dc;
@@ -27,21 +26,20 @@ class MessageContainer extends TLObject {
     }
 
     static async fromReader(reader) {
-        let messages = [];
-        let length = reader.readInt();
+        const messages = [];
+        const length = reader.readInt();
         for (let x = 0; x < length; x++) {
-            let msgId = reader.readLong();
-            let seqNo = reader.readInt();
-            let length = reader.readInt();
-            let before = reader.tellPosition();
-            let obj = reader.tgReadObject();
+            const msgId = reader.readLong();
+            const seqNo = reader.readInt();
+            const length = reader.readInt();
+            const before = reader.tellPosition();
+            const obj = reader.tgReadObject();
             reader.setPosition(before + length);
-            let tlMessage = new TLMessage(msgId, seqNo, obj);
-            messages.push(tlMessage)
+            const tlMessage = new TLMessage(msgId, seqNo, obj);
+            messages.push(tlMessage);
         }
         return new MessageContainer(messages);
     }
-
 }
 
-module.exports = MessageContainer;
+module.exports = MessageContainer;

+ 8 - 13
gramjs/tl/core/RPCResult.js

@@ -1,9 +1,6 @@
-const {TLObject} = require("../tlobject");
-const {RpcError} = require("../types");
-const GZIPPacked = require("./GZIPPacked");
-console.log(TLObject);
-console.log(RpcError);
-console.log(GZIPPacked);
+const { TLObject } = require('../tlobject');
+const { RpcError } = require('../types');
+const GZIPPacked = require('./GZIPPacked');
 
 class RPCResult extends TLObject {
     static CONSTRUCTOR_ID = 0xf35c6d01;
@@ -17,22 +14,20 @@ class RPCResult extends TLObject {
     }
 
     static async fromReader(reader) {
-        let msgId = reader.readLong();
-        let innerCode = reader.readInt(false);
+        const msgId = reader.readLong();
+        const innerCode = reader.readInt(false);
         if (innerCode === RpcError.CONSTRUCTOR_ID) {
             return new RPCResult(msgId, null, RpcError.fromReader(reader));
         }
         if (innerCode === GZIPPacked.CONSTRUCTOR_ID) {
-            return new RPCResult(msgId, (await GZIPPacked.fromReader(reader)).data)
+            return new RPCResult(msgId, (await GZIPPacked.fromReader(reader)).data);
         }
         reader.seek(-4);
         // This reader.read() will read more than necessary, but it's okay.
         // We could make use of MessageContainer's length here, but since
         // it's not necessary we don't need to care about it.
-        return new RPCResult(msgId, reader.read(), null)
-
+        return new RPCResult(msgId, reader.read(), null);
     }
-
 }
 
-module.exports = RPCResult;
+module.exports = RPCResult;

+ 2 - 2
gramjs/tl/core/TLMessage.js

@@ -1,4 +1,4 @@
-const {TLObject} = require("../tlobject");
+const { TLObject } = require('../tlobject');
 
 class TLMessage extends TLObject {
     static SIZE_OVERHEAD = 12;
@@ -11,4 +11,4 @@ class TLMessage extends TLObject {
     }
 }
 
-module.exports = TLMessage;
+module.exports = TLMessage;

+ 6 - 7
gramjs/tl/core/index.js

@@ -1,11 +1,11 @@
-const TLMessage = require("./TLMessage");
-const RPCResult = require("./RPCResult");
-const MessageContainer = require("./MessageContainer");
-const GZIPPacked = require("./GZIPPacked");
+const TLMessage = require('./TLMessage');
+const RPCResult = require('./RPCResult');
+const MessageContainer = require('./MessageContainer');
+const GZIPPacked = require('./GZIPPacked');
 coreObjects = {
     [RPCResult.CONSTRUCTOR_ID]: RPCResult,
     [GZIPPacked.CONSTRUCTOR_ID]: GZIPPacked,
-    [MessageContainer.CONSTRUCTOR_ID]: MessageContainer
+    [MessageContainer.CONSTRUCTOR_ID]: MessageContainer,
 };
 
 module.exports = {
@@ -14,5 +14,4 @@ module.exports = {
     MessageContainer,
     GZIPPacked,
     coreObjects,
-}
-
+};

+ 3 - 2
gramjs/tl/index.js

@@ -1,6 +1,7 @@
-const types = require("./types");
-const functions = require("./functions");
+const types = require('./types');
+const functions = require('./functions');
 const patched = null;
+
 module.exports = {
     types,
     functions,

+ 10 - 20
gramjs/tl/tlobject.js

@@ -1,4 +1,4 @@
-const struct = require("python-struct");
+const struct = require('python-struct');
 
 class TLObject {
     CONSTRUCTOR_ID = null;
@@ -14,13 +14,13 @@ class TLObject {
      */
     static serializeBytes(data) {
         if (!(data instanceof Buffer)) {
-            if (typeof data == "string") {
+            if (typeof data == 'string') {
                 data = Buffer.from(data);
             } else {
                 throw Error(`Bytes or str expected, not ${data.constructor.name}`);
             }
         }
-        let r = [];
+        const r = [];
         let padding;
         if (data.length < 254) {
             padding = (data.length + 1) % 4;
@@ -34,13 +34,7 @@ class TLObject {
             if (padding !== 0) {
                 padding = 4 - padding;
             }
-            r.push(Buffer.from([
-                254,
-                data.length % 256,
-                (data.length >> 8) % 256,
-                (data.length >> 16) % 256,
-
-            ]));
+            r.push(Buffer.from([254, data.length % 256, (data.length >> 8) % 256, (data.length >> 16) % 256]));
             r.push(data);
         }
         r.push(Buffer.alloc(padding).fill(0));
@@ -54,17 +48,15 @@ class TLObject {
         if (dt instanceof Date) {
             dt = Math.floor((Date.now() - dt.getTime()) / 1000);
         }
-        if (typeof dt == "number") {
-            return struct.pack('<i', dt)
+        if (typeof dt == 'number') {
+            return struct.pack('<i', dt);
         }
         throw Error(`Cannot interpret "${dt}" as a date`);
-
     }
 
     fromReader(reader) {
-        throw Error("not implemented");
+        throw Error('not implemented');
     }
-
 }
 
 /**
@@ -80,12 +72,10 @@ class TLRequest extends TLObject {
         return reader.tgReadObject();
     }
 
-    async resolve(self, client, utils) {
-
-    }
+    async resolve(self, client, utils) {}
 }
 
 module.exports = {
     TLObject,
-    TLRequest
-};
+    TLRequest,
+};

+ 61 - 100
gramjs/utils/Helpers.js

@@ -1,33 +1,30 @@
 const crypto = require('crypto');
-const fs = require("fs").promises;
+const fs = require('fs').promises;
 
 class Helpers {
-
     static readBigIntFromBuffer(buffer, little = true, signed = false) {
         let randBuffer = Buffer.from(buffer);
-        let bytesNumber = randBuffer.length;
+        const bytesNumber = randBuffer.length;
         if (little) {
             randBuffer = randBuffer.reverse();
         }
-        let bigInt = BigInt("0x" + randBuffer.toString("hex"));
-        if (signed && Math.floor(bigInt.toString("2").length / 8) >= bytesNumber) {
+        let bigInt = BigInt('0x' + randBuffer.toString('hex'));
+        if (signed && Math.floor(bigInt.toString('2').length / 8) >= bytesNumber) {
             bigInt -= 2n ** BigInt(bytesNumber * 8);
         }
         return bigInt;
     }
 
-
     static readBufferFromBigInt(bigInt, bytesNumber, little = true, signed = false) {
-        let bitLength = bigInt.toString("2").length;
+        const bitLength = bigInt.toString('2').length;
 
-        let bytes = Math.ceil(bitLength / 8);
+        const bytes = Math.ceil(bitLength / 8);
         if (bytesNumber < bytes) {
-            throw new Error("OverflowError: int too big to convert")
+            throw new Error('OverflowError: int too big to convert');
         } else if (bytesNumber > bytes) {
-
         }
         if (!signed && bigInt < 0) {
-            throw new Error("Cannot convert to unsigned");
+            throw new Error('Cannot convert to unsigned');
         }
         let below = false;
         if (bigInt < 0) {
@@ -35,8 +32,8 @@ class Helpers {
             bigInt = -bigInt;
         }
 
-        let hex = bigInt.toString("16").padStart(bytesNumber * 2, "0");
-        let l = Buffer.from(hex, "hex");
+        const hex = bigInt.toString('16').padStart(bytesNumber * 2, '0');
+        let l = Buffer.from(hex, 'hex');
         if (little) {
             l = l.reverse();
         }
@@ -52,9 +49,7 @@ class Helpers {
                 for (let i = 0; i < l.length - 1; i++) {
                     l[i] = 255 - l[i];
                 }
-
             }
-
         }
         return l;
     }
@@ -67,7 +62,6 @@ class Helpers {
         return this.readBigIntFromBuffer(Helpers.generateRandomBytes(8), true, signed);
     }
 
-
     /**
      * .... really javascript
      * @param n {number}
@@ -78,7 +72,6 @@ class Helpers {
         return ((n % m) + m) % m;
     }
 
-
     /**
      * Generates a random bytes array
      * @param count
@@ -93,19 +86,21 @@ class Helpers {
      * @param path
      * @returns {Promise<void>}
      */
-    static async loadSettings(path = "api/settings") {
-        let settings = {};
-        let left, right, value_pair;
+    static async loadSettings(path = 'api/settings') {
+        const settings = {};
+        let left;
+        let right;
+        let valuePair;
 
-        let data = await fs.readFile(path, 'utf-8');
+        const data = await fs.readFile(path, 'utf-8');
 
-        for (let line of data.toString().split('\n')) {
-            value_pair = line.split("=");
-            if (value_pair.length !== 2) {
+        for (const line of data.toString().split('\n')) {
+            valuePair = line.split('=');
+            if (valuePair.length !== 2) {
                 break;
             }
-            left = value_pair[0].replace(/ \r?\n|\r/g, '');
-            right = value_pair[1].replace(/ \r?\n|\r/g, '');
+            left = valuePair[0].replace(/ \r?\n|\r/g, '');
+            right = valuePair[1].replace(/ \r?\n|\r/g, '');
             if (!isNaN(right)) {
                 settings[left] = Number.parseInt(right);
             } else {
@@ -113,51 +108,28 @@ class Helpers {
             }
         }
 
-
         return settings;
-
-
     }
 
     /**
      * Calculate the key based on Telegram guidelines, specifying whether it's the client or not
-     * @param shared_key
-     * @param msg_key
+     * @param sharedKey
+     * @param msgKey
      * @param client
      * @returns {{iv: Buffer, key: Buffer}}
      */
 
-    static calcKey(shared_key, msg_key, client) {
-        let x = client === true ? 0 : 8;
-        let iv, key, sha1a, sha1b, sha1c, sha1d;
-        sha1a = Helpers.sha1(Buffer.concat([
-            msg_key,
-            shared_key.slice(x, (x + 32))
-        ]));
-        sha1b = Helpers.sha1(Buffer.concat([
-            shared_key.slice(x + 32, x + 48),
-            msg_key,
-            shared_key.slice(x + 48, x + 64)
-        ]));
-        sha1c = Helpers.sha1(Buffer.concat([
-            shared_key.slice(x + 64, x + 96),
-            msg_key
-        ]));
-        sha1d = Helpers.sha1(Buffer.concat([
-            msg_key,
-            shared_key.slice((x + 96), (x + 128))
-        ]));
-        key = Buffer.concat([
-            sha1a.slice(0, 8),
-            sha1b.slice(8, 20),
-            sha1c.slice(4, 16)]);
-        iv = Buffer.concat([
-            sha1a.slice(8, 20),
-            sha1b.slice(0, 8),
-            sha1c.slice(16, 20),
-            sha1d.slice(0, 8)]);
-        return {key, iv}
-
+    static calcKey(sharedKey, msgKey, client) {
+        const x = client === true ? 0 : 8;
+        const sha1a = Helpers.sha1(Buffer.concat([msgKey, sharedKey.slice(x, x + 32)]));
+        const sha1b = Helpers.sha1(
+            Buffer.concat([sharedKey.slice(x + 32, x + 48), msgKey, sharedKey.slice(x + 48, x + 64)])
+        );
+        const sha1c = Helpers.sha1(Buffer.concat([sharedKey.slice(x + 64, x + 96), msgKey]));
+        const sha1d = Helpers.sha1(Buffer.concat([msgKey, sharedKey.slice(x + 96, x + 128)]));
+        const key = Buffer.concat([sha1a.slice(0, 8), sha1b.slice(8, 20), sha1c.slice(4, 16)]);
+        const iv = Buffer.concat([sha1a.slice(8, 20), sha1b.slice(0, 8), sha1c.slice(16, 20), sha1d.slice(0, 8)]);
+        return { key, iv };
     }
 
     /**
@@ -167,8 +139,6 @@ class Helpers {
      */
     static calcMsgKey(data) {
         return Helpers.sha1(data).slice(4, 20);
-
-
     }
 
     /**
@@ -180,12 +150,12 @@ class Helpers {
     static generateKeyDataFromNonce(serverNonce, newNonce) {
         serverNonce = Helpers.readBufferFromBigInt(serverNonce, 16, true, true);
         newNonce = Helpers.readBufferFromBigInt(newNonce, 32, true, true);
-        let hash1 = Helpers.sha1(Buffer.concat([newNonce, serverNonce]));
-        let hash2 = Helpers.sha1(Buffer.concat([serverNonce, newNonce]));
-        let hash3 = Helpers.sha1(Buffer.concat([newNonce, newNonce]));
-        let keyBuffer = Buffer.concat([hash1, hash2.slice(0, 12)]);
-        let ivBuffer = Buffer.concat([hash2.slice(12, 20), hash3, newNonce.slice(0, 4)]);
-        return {key: keyBuffer, iv: ivBuffer}
+        const hash1 = Helpers.sha1(Buffer.concat([newNonce, serverNonce]));
+        const hash2 = Helpers.sha1(Buffer.concat([serverNonce, newNonce]));
+        const hash3 = Helpers.sha1(Buffer.concat([newNonce, newNonce]));
+        const keyBuffer = Buffer.concat([hash1, hash2.slice(0, 12)]);
+        const ivBuffer = Buffer.concat([hash2.slice(12, 20), hash3, newNonce.slice(0, 4)]);
+        return { key: keyBuffer, iv: ivBuffer };
     }
 
     /**
@@ -194,10 +164,9 @@ class Helpers {
      * @returns {Buffer}
      */
     static sha1(data) {
-        let shaSum = crypto.createHash('sha1');
+        const shaSum = crypto.createHash('sha1');
         shaSum.update(data);
         return shaSum.digest();
-
     }
 
     /**
@@ -206,13 +175,11 @@ class Helpers {
      * @returns {Buffer}
      */
     static sha256(data) {
-        let shaSum = crypto.createHash('sha256');
+        const shaSum = crypto.createHash('sha256');
         shaSum.update(data);
         return shaSum.digest();
-
     }
 
-
     /**
      * Reads a Telegram-encoded string
      * @param buffer {Buffer}
@@ -220,10 +187,10 @@ class Helpers {
      * @returns {{string: string, offset: number}}
      */
     static tgReadString(buffer, offset) {
-        let res = Helpers.tgReadByte(buffer, offset);
+        const res = Helpers.tgReadByte(buffer, offset);
         offset = res.offset;
-        let string = res.data.toString("utf8");
-        return {string, offset}
+        const string = res.data.toString('utf8');
+        return { string, offset };
     }
 
     /**
@@ -232,25 +199,24 @@ class Helpers {
      * @param offset {number}
      */
     static tgReadObject(reader, offset) {
-        let constructorId = reader.readUInt32LE(offset);
+        const constructorId = reader.readUInt32LE(offset);
         offset += 4;
-        let clazz = tlobjects[constructorId];
+        const clazz = tlobjects[constructorId];
         if (clazz === undefined) {
             /**
              * The class was None, but there's still a
              *  chance of it being a manually parsed value like bool!
              */
             if (constructorId === 0x997275b5) {
-                return true
+                return true;
             } else if (constructorId === 0xbc799737) {
-                return false
+                return false;
             }
-            throw Error("type not found " + constructorId);
+            throw Error('type not found ' + constructorId);
         }
         return undefined;
     }
 
-
     /**
      *
      * @param buffer {Buffer}
@@ -258,9 +224,10 @@ class Helpers {
      * @returns {{data: Buffer, offset: Number}}
      */
     static tgReadByte(buffer, offset) {
-        let firstByte = buffer[offset];
+        const firstByte = buffer[offset];
         offset += 1;
-        let padding, length;
+        let padding;
+        let length;
         if (firstByte === 254) {
             length = buffer.readInt8(offset) | (buffer.readInt8(offset + 1) << 8) | (buffer.readInt8(offset + 2) << 16);
             offset += 3;
@@ -270,7 +237,7 @@ class Helpers {
             padding = (length + 1) % 4;
         }
 
-        let data = buffer.slice(offset, offset + length);
+        const data = buffer.slice(offset, offset + length);
 
         offset += length;
 
@@ -279,12 +246,11 @@ class Helpers {
             offset += padding;
         }
 
-        return {data: data, offset: offset}
+        return { data: data, offset: offset };
     }
 
-
     static tgWriteString(string) {
-        return Helpers.tgWriteBytes(Buffer.from(string, "utf8"));
+        return Helpers.tgWriteBytes(Buffer.from(string, 'utf8'));
     }
 
     static tgWriteBytes(data) {
@@ -309,12 +275,9 @@ class Helpers {
                 Buffer.from([(data.length >> 16) % 256]),
                 data,
             ]);
-
         }
 
         return Buffer.concat([buffer, Buffer.alloc(padding).fill(0)]);
-
-
     }
 
     /**
@@ -329,7 +292,7 @@ class Helpers {
         let result = 1n;
         let x = a;
         while (b > 0n) {
-            let leastSignificantBit = b % 2n;
+            const leastSignificantBit = b % 2n;
             b = b / 2n;
             if (leastSignificantBit === 1n) {
                 result = result * x;
@@ -339,7 +302,7 @@ class Helpers {
             x = x % n;
         }
         return result;
-    };
+    }
 
     /**
      * returns a random int from min (inclusive) and max (inclusive)
@@ -358,7 +321,7 @@ class Helpers {
      * @param ms time in milliseconds
      * @returns {Promise}
      */
-    static sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
+    static sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
 
     /**
      * Checks if the obj is an array
@@ -367,19 +330,17 @@ class Helpers {
      */
     static isArrayLike(obj) {
         if (!obj) return false;
-        let l = obj.length;
+        const l = obj.length;
         if (typeof l != 'number' || l < 0) return false;
         if (Math.floor(l) !== l) return false;
         // fast check
-        if (l > 0 && !((l - 1) in obj)) return false;
+        if (l > 0 && !(l - 1 in obj)) return false;
         // more complete check (optional)
         for (let i = 0; i < l; ++i) {
             if (!(i in obj)) return false;
         }
         return true;
     }
-
 }
 
 module.exports = Helpers;
-

+ 5 - 5
gramjs_generator/docswriter.js

@@ -19,7 +19,7 @@ class DocsWriter {
         this.menuSeparatorTag = null;
 
         // Utility functions
-        this.typeToPath = t => this._rel(typeToPath(t));
+        this.typeToPath = (t) => this._rel(typeToPath(t));
 
         // Control signals
         this.menuBegan = false;
@@ -212,8 +212,8 @@ class DocsWriter {
         // Now write the resulting type (result from a function/type)
         this.write(' = ');
         const [genericName] = tlobject.args
-            .filter(arg => arg.genericDefinition)
-            .map(arg => arg.name);
+            .filter((arg) => arg.genericDefinition)
+            .map((arg) => arg.name);
 
         if (tlobject.result === genericName) {
             // Generic results cannot have any link
@@ -324,7 +324,7 @@ class DocsWriter {
         this.write(
             `<button onclick="cp('${textToCopy.replace(
                 /'/g,
-                "\\'"
+                '\\\''
             )}');">${text}</button>`
         );
     }
@@ -337,7 +337,7 @@ class DocsWriter {
         }
     }
 
-    /***
+    /**
      * Ends the whole document. This should be called the last
      */
     endBody() {

+ 38 - 41
gramjs_generator/generators/docs.js

@@ -19,19 +19,19 @@ const CORE_TYPES = new Set([
     'date',
 ]);
 
-const mkdir = path => fs.mkdirSync(path, { recursive: true });
+const mkdir = (path) => fs.mkdirSync(path, { recursive: true });
 
-const titleCase = text =>
+const titleCase = (text) =>
     text
         .toLowerCase()
         .split(/(\W)/)
-        .map(word => `${word.slice(0, 1).toUpperCase()}${word.slice(1)}`)
+        .map((word) => `${word.slice(0, 1).toUpperCase()}${word.slice(1)}`)
         .join('');
 
 /**
  * ``ClassName -> class_name.html``.
  */
-const getFileName = tlobject => {
+const getFileName = (tlobject) => {
     const name = tlobject instanceof TLObject ? tlobject.name : tlobject;
     // Courtesy of http://stackoverflow.com/a/1176023/4759433
     const s1 = name.replace(/(.)([A-Z][a-z]+)/, '$1_$2');
@@ -42,7 +42,7 @@ const getFileName = tlobject => {
 /**
  * ``TLObject -> const { ... } = require(...);``.
  */
-const getImportCode = tlobject => {
+const getImportCode = (tlobject) => {
     const kind = tlobject.isFunction ? 'functions' : 'types';
     const ns = tlobject.namespace ? `/${tlobject.namespace}` : '';
     return `const { ${tlobject.className} } = require('gramjs/tl/${kind}${ns}');`;
@@ -51,7 +51,7 @@ const getImportCode = tlobject => {
 /**
  * Returns the path for the given TLObject.
  */
-const getPathFor = tlobject => {
+const getPathFor = (tlobject) => {
     let outDir = tlobject.isFunction ? 'methods' : 'constructors';
 
     if (tlobject.namespace) {
@@ -64,7 +64,7 @@ const getPathFor = tlobject => {
 /**
  * Similar to `getPathFor` but for only type names.
  */
-const getPathForType = type => {
+const getPathForType = (type) => {
     if (CORE_TYPES.has(type.toLowerCase())) {
         return `index.html#${type.toLowerCase()}`;
     } else if (type.includes('.')) {
@@ -78,7 +78,7 @@ const getPathForType = type => {
 /**
  * Finds the <title> for the given HTML file, or (Unknown).
  */
-const findTitle = htmlFile => {
+const findTitle = (htmlFile) => {
     const f = fs.readFileSync(htmlFile, { encoding: 'utf-8' });
 
     for (const line of f.split('\n')) {
@@ -97,7 +97,7 @@ const findTitle = htmlFile => {
 /**
  * Builds the menu used for the current ``DocumentWriter``.
  */
-const buildMenu = docs => {
+const buildMenu = (docs) => {
     const paths = [];
     let current = docs.filename;
 
@@ -135,9 +135,7 @@ const generateIndex = (folder, paths, botsIndex, botsIndexPaths) => {
     const INDEX = 'index.html';
     const BOT_INDEX = 'botindex.html';
 
-    for (const item of botsIndexPaths.length
-        ? botsIndexPaths
-        : fs.readdirSync(folder)) {
+    for (const item of botsIndexPaths.length ? botsIndexPaths : fs.readdirSync(folder)) {
         const fullPath = botsIndexPaths.length ? item : `${folder}/${item}`;
 
         if (fs.statSync(fullPath).isDirectory()) {
@@ -211,7 +209,7 @@ const generateIndex = (folder, paths, botsIndex, botsIndexPaths) => {
 
     files
         .sort((x, y) => x.localeCompare(y))
-        .forEach(file => {
+        .forEach((file) => {
             docs.addRow(findTitle(file), file);
         });
 
@@ -223,7 +221,7 @@ const generateIndex = (folder, paths, botsIndex, botsIndexPaths) => {
 /**
  * Generates a proper description for the given argument.
  */
-const getDescription = arg => {
+const getDescription = (arg) => {
     const desc = [];
     let otherwise = false;
 
@@ -308,15 +306,15 @@ const writeHtmlPages = (tlobjects, methods, layer, inputRes) => {
     // * Generating the types documentation, showing available constructors.
     const paths = {
         '404': '404.html',
-        css: 'css',
-        arrow: 'img/arrow.svg',
+        'css': 'css',
+        'arrow': 'img/arrow.svg',
         'search.js': 'js/search.js',
-        indexAll: 'index.html',
-        botIndex: 'botindex.html',
-        indexTypes: 'types/index.html',
-        indexMethods: 'methods/index.html',
-        indexConstructors: 'constructors/index.html',
-        defaultCss: 'light',
+        'indexAll': 'index.html',
+        'botIndex': 'botindex.html',
+        'indexTypes': 'types/index.html',
+        'indexMethods': 'methods/index.html',
+        'indexConstructors': 'constructors/index.html',
+        'defaultCss': 'light',
     };
 
     const typeToConstructors = {};
@@ -383,14 +381,14 @@ const writeHtmlPages = (tlobjects, methods, layer, inputRes) => {
         docs.writeTitle(tlobject.isFunction ? 'Returns' : 'Belongs to', 3);
 
         let [genericArg] = tlobject.args
-            .filter(arg => arg.genericDefinition)
-            .map(arg => arg.name);
+            .filter((arg) => arg.genericDefinition)
+            .map((arg) => arg.name);
 
         if (tlobject.result === genericArg) {
             //  We assume it's a function returning a generic type
             [genericArg] = tlobject.args
-                .filter(arg => arg.isGeneric)
-                .map(arg => arg.name);
+                .filter((arg) => arg.isGeneric)
+                .map((arg) => arg.name);
 
             docs.writeText(
                 `This function returns the result of whatever the result from invoking the request passed through <i>${genericArg}</i> is.`
@@ -433,7 +431,7 @@ const writeHtmlPages = (tlobjects, methods, layer, inputRes) => {
         // on the generated code (flags go last)
         const args = tlobject
             .sortedArgs()
-            .filter(a => !a.flagIndicator && !a.genericDefinition);
+            .filter((a) => !a.flagIndicator && !a.genericDefinition);
 
         if (args.length) {
             // Writing parameters
@@ -476,7 +474,7 @@ const writeHtmlPages = (tlobjects, methods, layer, inputRes) => {
 
             if (!errors || !errors.length) {
                 docs.writeText(
-                    "This request can't cause any RPC error as far as we know."
+                    'This request can\'t cause any RPC error as far as we know.'
                 );
             } else {
                 docs.writeText(
@@ -561,11 +559,10 @@ const writeHtmlPages = (tlobjects, methods, layer, inputRes) => {
         }
 
         // Since we don't have access to the full TLObject, split the type
-        let namespace = null;
         let name = t;
 
         if (t.includes('.')) {
-            [namespace, name] = t.split('.');
+            [, name] = t.split('.');
         }
 
         const docs = new DocsWriter(filename, getPathForType).open();
@@ -625,7 +622,7 @@ const writeHtmlPages = (tlobjects, methods, layer, inputRes) => {
         // List all the methods which take this type as input
         docs.writeTitle('Methods accepting this type as input', 3);
         const otherMethods = tlobjects
-            .filter(u => u.isFunction && u.args.some(a => a.type === t))
+            .filter((u) => u.isFunction && u.args.some((a) => a.type === t))
             .sort((x, y) => x.name.localeCompare(y.name));
 
         if (!otherMethods.length) {
@@ -652,7 +649,7 @@ const writeHtmlPages = (tlobjects, methods, layer, inputRes) => {
         // List every other type which has this type as a member
         docs.writeTitle('Other types containing this type', 3);
         const otherTypes = tlobjects
-            .filter(u => !u.isFunction && u.args.some(a => a.type === t))
+            .filter((u) => !u.isFunction && u.args.some((a) => a.type === t))
             .sort((x, y) => x.name.localeCompare(y.name));
 
         if (!otherTypes.length) {
@@ -718,7 +715,7 @@ const writeHtmlPages = (tlobjects, methods, layer, inputRes) => {
         layer,
     });
 
-    let fmt = xs => {
+    let fmt = (xs) => {
         const zs = []; // create an object to hold those which have duplicated keys
 
         for (const x of xs) {
@@ -726,10 +723,10 @@ const writeHtmlPages = (tlobjects, methods, layer, inputRes) => {
         }
 
         return xs
-            .map(x =>
-                zs[x.className] && x.namespace
-                    ? `"${x.namespace}.${x.className}"`
-                    : `"${x.className}"`
+            .map((x) =>
+                zs[x.className] && x.namespace ?
+                    `"${x.namespace}.${x.className}"` :
+                    `"${x.className}"`
             )
             .join(', ');
     };
@@ -740,7 +737,7 @@ const writeHtmlPages = (tlobjects, methods, layer, inputRes) => {
     fmt = (xs, formatter) => {
         return xs
             .map(
-                x =>
+                (x) =>
                     `"${formatter(x).replace(
                         new RegExp(`\\${path.sep}`, 'g'),
                         '/'
@@ -749,7 +746,7 @@ const writeHtmlPages = (tlobjects, methods, layer, inputRes) => {
             .join(', ');
     };
 
-    const typeNames = fmt([...types], x => x);
+    const typeNames = fmt([...types], (x) => x);
 
     const requestUrls = fmt(methods_, getPathFor);
     const typeUrls = fmt([...types], getPathForType);
@@ -766,7 +763,7 @@ const writeHtmlPages = (tlobjects, methods, layer, inputRes) => {
     });
 };
 
-const copyResources = resDir => {
+const copyResources = (resDir) => {
     for (const [dirname, files] of [
         ['css', ['docs.light.css', 'docs.dark.css']],
         ['img', ['arrow.svg']],
@@ -785,7 +782,7 @@ const copyResources = resDir => {
 /**
  * Pre-create the required directory structure.
  */
-const createStructure = tlobjects => {
+const createStructure = (tlobjects) => {
     const typeNs = new Set();
     const methodsNs = new Set();
 

+ 11 - 24
gramjs_generator/generators/errors.js

@@ -22,33 +22,23 @@ const generateErrors = (errors, f) => {
     }
 
     // Imports and new subclass creation
-    f.write(
-        `const { RPCError, ${[...importBase.values()].join(
-            ', '
-        )} } = require('./rpcbaseerrors');`
-    );
+    f.write(`const { RPCError, ${[...importBase.values()].join(', ')} } = require('./rpcbaseerrors');`);
 
-    f.write("\nconst format = require('string-format');");
+    f.write('\nconst format = require(\'string-format\');');
 
     for (const [cls, intCode] of Object.entries(createBase)) {
-        f.write(
-            `\n\nclass ${cls} extends RPCError {\n    constructor() {\n        this.code = ${intCode};\n    }\n}`
-        );
+        f.write(`\n\nclass ${cls} extends RPCError {\n    constructor() {\n        this.code = ${intCode};\n    }\n}`);
     }
 
     // Error classes generation
     for (const error of errors) {
-        f.write(
-            `\n\nclass ${error.name} extends ${error.subclass} {\n    constructor(args) {\n        `
-        );
+        f.write(`\n\nclass ${error.name} extends ${error.subclass} {\n    constructor(args) {\n        `);
 
         if (error.hasCaptures) {
-            f.write(
-                `const ${error.captureName} = Number(args.capture || 0);\n        `
-            );
+            f.write(`const ${error.captureName} = Number(args.capture || 0);\n        `);
         }
 
-        const capture = error.description.replace(/'/g, "\\'");
+        const capture = error.description.replace(/'/g, '\\\'');
 
         if (error.hasCaptures) {
             f.write(`super(format('${capture}', {${error.captureName}})`);
@@ -59,9 +49,7 @@ const generateErrors = (errors, f) => {
         f.write(' + RPCError._fmtRequest(args.request));\n');
 
         if (error.hasCaptures) {
-            f.write(
-                `        this.${error.captureName} = ${error.captureName};\n`
-            );
+            f.write(`        this.${error.captureName} = ${error.captureName};\n`);
         }
 
         f.write('    }\n}\n');
@@ -80,18 +68,17 @@ const generateErrors = (errors, f) => {
     }
 
     f.write('];');
-    f.write("module.exports = {");
+    f.write('module.exports = {');
     for (const error of regexMatch) {
         f.write(`     ${error.name},\n`);
     }
     for (const error of exactMatch) {
         f.write(`     ${error.name},\n`);
     }
-    f.write("     rpcErrorsObject,\n");
-    f.write("     rpcErrorRe,\n");
-
-    f.write("}");
+    f.write('     rpcErrorsObject,\n');
+    f.write('     rpcErrorRe,\n');
 
+    f.write('}');
 };
 
 module.exports = {

+ 145 - 220
gramjs_generator/generators/tlobject.js

@@ -1,11 +1,10 @@
 const fs = require('fs');
 const util = require('util');
-const {crc32} = require('crc');
+const { crc32 } = require('crc');
 const SourceBuilder = require('../sourcebuilder');
-const {snakeToCamelCase, variableSnakeToCamelCase} = require("../utils");
+const { snakeToCamelCase, variableSnakeToCamelCase } = require('../utils');
 
-const AUTO_GEN_NOTICE =
-    "/*! File generated by TLObjects' generator. All changes will be ERASED !*/";
+const AUTO_GEN_NOTICE = '/*! File generated by TLObjects\' generator. All changes will be ERASED !*/';
 
 const AUTO_CASTS = {
     InputPeer: 'utils.get_input_peer(await client.get_input_entity(%s))',
@@ -34,21 +33,11 @@ const NAMED_AUTO_CASTS = {
 //       did recurse into them to resolve them.
 const NAMED_BLACKLIST = new Set(['messages.discardEncryption']);
 
-const BASE_TYPES = [
-    'string',
-    'bytes',
-    'int',
-    'long',
-    'int128',
-    'int256',
-    'double',
-    'Bool',
-    'true',
-];
+const BASE_TYPES = ['string', 'bytes', 'int', 'long', 'int128', 'int256', 'double', 'Bool', 'true'];
 
 // Patched types {fullname: custom.ns.Name}
 
-//No patches currently
+// No patches currently
 /**
  const PATCHED_TYPES = {
     messageEmpty: 'message.Message',
@@ -57,15 +46,9 @@ const BASE_TYPES = [
 };*/
 const PATCHED_TYPES = {};
 
-const writeModules = (
-    outDir,
-    depth,
-    kind,
-    namespaceTlobjects,
-    typeConstructors
-) => {
+const writeModules = (outDir, depth, kind, namespaceTlobjects, typeConstructors) => {
     // namespace_tlobjects: {'namespace', [TLObject]}
-    fs.mkdirSync(outDir, {recursive: true});
+    fs.mkdirSync(outDir, { recursive: true });
 
     for (const [ns, tlobjects] of Object.entries(namespaceTlobjects)) {
         const file = `${outDir}/${ns === 'null' ? 'index' : ns}.js`;
@@ -74,14 +57,10 @@ const writeModules = (
         const dotDepth = '.'.repeat(depth || 1);
 
         builder.writeln(AUTO_GEN_NOTICE);
-        builder.writeln(
-            `const { TLObject } = require('${dotDepth}/tlobject');`
-        );
+        builder.writeln(`const { TLObject } = require('${dotDepth}/tlobject');`);
 
         if (kind !== 'TLObject') {
-            builder.writeln(
-                `const { ${kind} } = require('${dotDepth}/tlobject');`
-            );
+            builder.writeln(`const { ${kind} } = require('${dotDepth}/tlobject');`);
         }
 
         // Add the relative imports to the namespaces,
@@ -95,7 +74,7 @@ const writeModules = (
         }
 
         // Import struct for the .__bytes__(self) serialization
-        builder.writeln("const struct = require('python-struct');");
+        builder.writeln('const struct = require(\'python-struct\');');
         builder.writeln(`const Helpers = require('../../utils/Helpers');`);
 
         const typeNames = new Set();
@@ -136,17 +115,7 @@ const writeModules = (
         }*/
 
         const imports = {};
-        const primitives = new Set([
-            'int',
-            'long',
-            'int128',
-            'int256',
-            'double',
-            'string',
-            'bytes',
-            'Bool',
-            'true',
-        ]);
+        const primitives = new Set(['int', 'long', 'int128', 'int256', 'double', 'string', 'bytes', 'Bool', 'true']);
 
         // Find all the types in other files that are used in this file
         // and generate the information required to import those types.
@@ -214,20 +183,18 @@ const writeModules = (
             builder.writeln(line);
         }
         writeModuleExports(tlobjects, builder);
-        if (file.indexOf("index.js") > 0) {
-            for (const [ns, tlobjects] of Object.entries(namespaceTlobjects)) {
+        if (file.indexOf('index.js') > 0) {
+            for (const [ns] of Object.entries(namespaceTlobjects)) {
                 if (ns !== 'null') {
-                    builder.writeln("let %s = require('./%s');", ns, ns);
+                    builder.writeln('let %s = require(\'./%s\');', ns, ns);
                 }
             }
-            for (const [ns, tlobjects] of Object.entries(namespaceTlobjects)) {
+            for (const [ns] of Object.entries(namespaceTlobjects)) {
                 if (ns !== 'null') {
-                    builder.writeln("module.exports.%s = %s;", ns, ns);
+                    builder.writeln('module.exports.%s = %s;', ns, ns);
                 }
             }
-
         }
-
     }
 };
 
@@ -237,8 +204,9 @@ const writeReadResult = (tlobject, builder) => {
     //
     // The default behaviour is reading a TLObject too, so no need
     // to override it unless necessary.
-    if (!tlobject.isFunction)
+    if (!tlobject.isFunction) {
         return;
+    }
 
     // https://core.telegram.org/mtproto/serialize#boxed-and-bare-types
     // TL;DR; boxed types start with uppercase always, so we can use
@@ -247,17 +215,18 @@ const writeReadResult = (tlobject, builder) => {
     // Currently only un-boxed responses are Vector<int>/Vector<long>.
     // If this weren't the case, we should check upper case after
     // max(index('<'), index('.')) (and if it is, it's boxed, so return).
-    let m = tlobject.result.match(/Vector<(int|long)>/);
+    const m = tlobject.result.match(/Vector<(int|long)>/);
     if (!m) {
-        return
+        return;
     }
-    //builder.endBlock();
+
+    // builder.endBlock();
     builder.writeln('readResult(reader){');
     builder.writeln('reader.readInt();  // Vector ID');
     builder.writeln('let temp = [];');
-    builder.writeln("let len = reader.readInt(); //fix this");
+    builder.writeln('let len = reader.readInt(); //fix this');
     builder.writeln('for (let i=0;i<len;i++){');
-    let read = m[1][0].toUpperCase() + m[1].slice(1);
+    const read = m[1][0].toUpperCase() + m[1].slice(1);
     builder.writeln('temp.push(reader.read%s())', read);
     builder.endBlock();
     builder.writeln('return temp');
@@ -275,30 +244,20 @@ const writeReadResult = (tlobject, builder) => {
 const writeSourceCode = (tlobject, kind, builder, typeConstructors) => {
     writeClassConstructor(tlobject, kind, typeConstructors, builder);
     writeResolve(tlobject, builder);
-    //writeToJson(tlobject, builder);
+    // writeToJson(tlobject, builder);
     writeToBytes(tlobject, builder);
     builder.currentIndent--;
     writeFromReader(tlobject, builder);
     writeReadResult(tlobject, builder);
     builder.currentIndent--;
     builder.writeln('}');
-
 };
 
-
 const writeClassConstructor = (tlobject, kind, typeConstructors, builder) => {
     builder.writeln();
     builder.writeln();
     builder.writeln(`class ${tlobject.className} extends ${kind} {`);
 
-    // Convert the args to string parameters, flags having =None
-    const args = tlobject.realArgs.map(
-        a =>
-            `${a.name}: ${a.typeHint()}${
-                a.isFlag || a.canBeInferred ? `=None` : ''
-            }`
-    );
-
     // Write the __init__ function if it has any argument
     if (!tlobject.realArgs.length) {
         return;
@@ -306,10 +265,8 @@ const writeClassConstructor = (tlobject, kind, typeConstructors, builder) => {
 
     // Note : this is needed to be able to access them
     // with or without an instance
-    builder.writeln(
-        `static CONSTRUCTOR_ID = 0x${tlobject.id.toString(16).padStart(8, '0')};`
-    );
-    builder.writeln(`static SUBCLASS_OF_ID = 0x${crc32(tlobject.result).toString("16")};`);
+    builder.writeln(`static CONSTRUCTOR_ID = 0x${tlobject.id.toString(16).padStart(8, '0')};`);
+    builder.writeln(`static SUBCLASS_OF_ID = 0x${crc32(tlobject.result).toString(16)};`);
     builder.writeln();
 
     builder.writeln('/**');
@@ -327,11 +284,7 @@ const writeClassConstructor = (tlobject, kind, typeConstructors, builder) => {
     } else if (constructors.length === 1) {
         builder.writeln(`Instance of ${constructors[0].className}`);
     } else {
-        builder.writeln(
-            `Instance of either ${constructors
-                .map(c => c.className)
-                .join(', ')}`
-        );
+        builder.writeln(`Instance of either ${constructors.map((c) => c.className).join(', ')}`);
     }
 
     builder.writeln('*/');
@@ -339,21 +292,23 @@ const writeClassConstructor = (tlobject, kind, typeConstructors, builder) => {
     builder.writeln(`super();`);
 
     // Class-level variable to store its Telegram's constructor ID
-    builder.writeln(
-        `this.CONSTRUCTOR_ID = 0x${tlobject.id.toString(16).padStart(8, '0')};`
-    );
-    builder.writeln(`this.SUBCLASS_OF_ID = 0x${crc32(tlobject.result).toString("16")};`);
+    builder.writeln(`this.CONSTRUCTOR_ID = 0x${tlobject.id.toString(16).padStart(8, '0')};`);
+    builder.writeln(`this.SUBCLASS_OF_ID = 0x${crc32(tlobject.result).toString(16)};`);
+
     builder.writeln();
 
     // Set the arguments
     for (const arg of tlobject.realArgs) {
         if (!arg.canBeInferred) {
-            builder.writeln(`this.${variableSnakeToCamelCase(arg.name)} = args.${variableSnakeToCamelCase(arg.name)};`);
-        }
+            builder.writeln(
+                `this.${variableSnakeToCamelCase(arg.name)}: ${a.typeHint()} = args.${variableSnakeToCamelCase(
+                    arg.name
+                )}${a.isFlag || a.canBeInferred ? ' || null' : ''};`
+            );
 
             // Currently the only argument that can be
-        // inferred are those called 'random_id'
-        else if (arg.name === 'random_id') {
+            // inferred are those called 'random_id'
+        } else if (arg.name === 'random_id') {
             // Endianness doesn't really matter, and 'big' is shorter
             let code = `Helpers.readBigIntFromBuffer(Helpers.generateRandomBytes(${
                 arg.type === 'long' ? 8 : 4
@@ -362,18 +317,14 @@ const writeClassConstructor = (tlobject, kind, typeConstructors, builder) => {
             if (arg.isVector) {
                 // Currently for the case of "messages.forwardMessages"
                 // Ensure we can infer the length from id:Vector<>
-                if (!tlobject.realArgs.find(a => a.name === 'id').isVector) {
-                    throw new Error(
-                        `Cannot infer list of random ids for ${tlobject}`
-                    );
+                if (!tlobject.realArgs.find((a) => a.name === 'id').isVector) {
+                    throw new Error(`Cannot infer list of random ids for ${tlobject}`);
                 }
 
                 code = `new Array(id.length).fill().map(_ => ${code})`;
             }
 
-            builder.writeln(
-                `this.randomId = args.randomId !== undefined ? args.randomId : ${code};`
-            );
+            builder.writeln(`this.randomId = args.randomId !== undefined ? args.randomId : ${code};`);
         } else {
             throw new Error(`Cannot infer a value for ${arg}`);
         }
@@ -386,10 +337,9 @@ const writeResolve = (tlobject, builder) => {
     if (
         tlobject.isFunction &&
         tlobject.realArgs.some(
-            arg =>
+            (arg) =>
                 arg.type in AUTO_CASTS ||
-                (`${arg.name},${arg.type}` in NAMED_AUTO_CASTS &&
-                    !NAMED_BLACKLIST.has(tlobject.fullname))
+                (`${arg.name},${arg.type}` in NAMED_AUTO_CASTS && !NAMED_BLACKLIST.has(tlobject.fullname))
         )
     ) {
         builder.writeln('async resolve(client, utils) {');
@@ -416,10 +366,7 @@ const writeResolve = (tlobject, builder) => {
                 builder.endBlock();
                 builder.writeln(`this.${arg.name} = _tmp;`);
             } else {
-                builder.writeln(
-                    `this.${arg.name} = %s`,
-                    util.format(ac, `this.${arg.name}`)
-                );
+                builder.writeln(`this.${arg.name} = %s`, util.format(ac, `this.${arg.name}`));
             }
 
             if (arg.isFlag) {
@@ -482,7 +429,7 @@ const writeToBytes = (tlobject, builder) => {
     // Some objects require more than one flag parameter to be set
     // at the same time. In this case, add an assertion.
     const repeatedArgs = {};
-    for (let arg of tlobject.args) {
+    for (const arg of tlobject.args) {
         if (arg.isFlag) {
             if (!repeatedArgs[arg.flagIndex]) {
                 repeatedArgs[arg.flagIndex] = [];
@@ -490,66 +437,64 @@ const writeToBytes = (tlobject, builder) => {
             repeatedArgs[arg.flagIndex].push(arg);
         }
     }
-    for (let ra of Object.values(repeatedArgs)) {
+
+    for (const ra of Object.values(repeatedArgs)) {
         if (ra.length > 1) {
-            let cnd1 = [];
-            let cnd2 = [];
-            let names = [];
+            const cnd1 = [];
+            const cnd2 = [];
+            const names = [];
 
-            for (let a of ra) {
+            for (const a of ra) {
                 cnd1.push(`this.${a.name} || this.${a.name}!==null`);
                 cnd2.push(`this.${a.name}===null || this.${a.name}===false`);
                 names.push(a.name);
             }
-            builder.writeln("if (!((%s) && (%s)))\n\t throw new Error('%s paramaters must all"
-                + " be false-y or all true')", cnd1.join(" && "), cnd2.join(" && "), names.join(", "));
+            builder.writeln(
+                'if (!((%s) && (%s)))\n\t throw new Error(\'%s paramaters must all be false-y or all true\')',
+                cnd1.join(' && '),
+                cnd2.join(' && '),
+                names.join(', ')
+            );
         }
     }
-    builder.writeln("return Buffer.concat([");
+    builder.writeln('return Buffer.concat([');
     builder.currentIndent++;
-    let b = Buffer.alloc(4);
+    const b = Buffer.alloc(4);
     b.writeUInt32LE(tlobject.id, 0);
     // First constructor code, we already know its bytes
-    builder.writeln('Buffer.from("%s","hex"),', b.toString("hex"));
-    for (let arg of tlobject.args) {
+    builder.writeln('Buffer.from("%s","hex"),', b.toString('hex'));
+    for (const arg of tlobject.args) {
         if (writeArgToBytes(builder, arg, tlobject.args)) {
             builder.writeln(',');
         }
     }
-    builder.writeln("])");
+    builder.writeln('])');
     builder.endBlock();
-
 };
 
 // writeFromReader
 const writeFromReader = (tlobject, builder) => {
-
-    builder.writeln("static fromReader(reader) {");
+    builder.writeln('static fromReader(reader) {');
     for (const arg of tlobject.args) {
-
-        if (arg.name !== "flag") {
-
-
-            if (arg.name !== "x") {
-
-
-                builder.writeln("let %s", "_" + arg.name + ";");
+        if (arg.name !== 'flag') {
+            if (arg.name !== 'x') {
+                builder.writeln('let %s', '_' + arg.name + ';');
             }
         }
     }
-    // TODO fix this really
-    builder.writeln("let _x;");
-    builder.writeln("let len;");
 
+    // TODO fix this really
+    builder.writeln('let _x;');
+    builder.writeln('let len;');
 
     for (const arg of tlobject.args) {
-        writeArgReadCode(builder, arg, tlobject.args, "_" + arg.name);
+        writeArgReadCode(builder, arg, tlobject.args, '_' + arg.name);
     }
-    let temp = [];
-    for (let a of tlobject.realArgs) {
-        temp.push(`${variableSnakeToCamelCase(a.name)}:_${a.name}`)
+    const temp = [];
+    for (const a of tlobject.realArgs) {
+        temp.push(`${variableSnakeToCamelCase(a.name)}:_${a.name}`);
     }
-    builder.writeln("return new this({%s})", temp.join(",\n\t"));
+    builder.writeln('return new this({%s})', temp.join(',\n\t'));
     builder.endBlock();
 };
 // writeReadResult
@@ -568,12 +513,11 @@ const writeArgToBytes = (builder, arg, args, name = null) => {
     if (arg.genericDefinition) {
         return; // Do nothing, this only specifies a later type
     }
+
     if (name === null) {
         name = `this.${arg.name}`;
     }
-    if (name =="this.msg_ids"){
-        console.log(name)
-    }
+
     name = variableSnakeToCamelCase(name);
     // The argument may be a flag, only write if it's not None AND
     // if it's not a True type.
@@ -587,22 +531,22 @@ const writeArgToBytes = (builder, arg, args, name = null) => {
             // so we need an extra join here. Note that empty vector flags
             // should NOT be sent either!
             builder.write(
-                "(%s === undefined || %s === false || %s ===null) ? Buffer.alloc(0) :Buffer.concat([",
+                '(%s === undefined || %s === false || %s ===null) ? Buffer.alloc(0) :Buffer.concat([',
                 name,
                 name,
                 name
             );
         } else {
-            builder.write("(%s === undefined || %s === false || %s ===null) ? Buffer.alloc(0) : [", name, name,name);
+            builder.write('(%s === undefined || %s === false || %s ===null) ? Buffer.alloc(0) : [', name, name, name);
         }
     }
 
     if (arg.isVector) {
         if (arg.useVectorId) {
-            builder.write("Buffer.from('15c4b51c','hex'),");
+            builder.write('Buffer.from(\'15c4b51c\', \'hex\'),');
         }
 
-        builder.write("struct.pack('<i', %s.length),", name);
+        builder.write('struct.pack(\'<i\', %s.length),', name);
 
         // Cannot unpack the values for the outer tuple through *[(
         // since that's a Python >3.5 feature, so add another join.
@@ -618,34 +562,37 @@ const writeArgToBytes = (builder, arg, args, name = null) => {
         builder.write('))');
     } else if (arg.flagIndicator) {
         // Calculate the flags with those items which are not None
-        if (!args.some(f => f.isFlag)) {
+        if (!args.some((f) => f.isFlag)) {
             // There's a flag indicator, but no flag arguments so it's 0
             builder.write('Buffer.alloc(4)');
         } else {
-            builder.write("struct.pack('<I', ");
+            builder.write('struct.pack(\'<I\', ');
             builder.write(
                 args
-                    .filter(flag => flag.isFlag)
+                    .filter((flag) => flag.isFlag)
                     .map(
-                        flag =>
-                            `(this.${variableSnakeToCamelCase(flag.name)} === undefined || this.${
-                                variableSnakeToCamelCase(flag.name)
-                            } === false || this.${variableSnakeToCamelCase(flag.name)} === null) ? 0 : ${1 << flag.flagIndex}`
+                        (flag) =>
+                            `(this.${variableSnakeToCamelCase(
+                                flag.name
+                            )} === undefined || this.${variableSnakeToCamelCase(
+                                flag.name
+                            )} === false || this.${variableSnakeToCamelCase(flag.name)} === null) ? 0 : ${1 <<
+                                flag.flagIndex}`
                     )
                     .join(' | ')
             );
             builder.write(')');
         }
     } else if (arg.type === 'int') {
-        builder.write("struct.pack('<i', %s)", name);
+        builder.write('struct.pack(\'<i\', %s)', name);
     } else if (arg.type === 'long') {
-        builder.write("Helpers.readBufferFromBigInt(%s,8,true,true)", name);
+        builder.write('Helpers.readBufferFromBigInt(%s,8,true,true)', name);
     } else if (arg.type === 'int128') {
-        builder.write("Helpers.readBufferFromBigInt(%s,16,true,true)", name);
+        builder.write('Helpers.readBufferFromBigInt(%s,16,true,true)', name);
     } else if (arg.type === 'int256') {
-        builder.write("Helpers.readBufferFromBigInt(%s,32,true,true)", name);
+        builder.write('Helpers.readBufferFromBigInt(%s,32,true,true)', name);
     } else if (arg.type === 'double') {
-        builder.write("struct.pack('<d', %s.toString())", name);
+        builder.write('struct.pack(\'<d\', %s.toString())', name);
     } else if (arg.type === 'string') {
         builder.write('TLObject.serializeBytes(%s)', name);
     } else if (arg.type === 'Bool') {
@@ -681,7 +628,6 @@ const writeArgToBytes = (builder, arg, args, name = null) => {
     return true;
 };
 
-
 /**
  * Writes the read code for the given argument, setting the
  * arg.name variable to its read value.
@@ -695,20 +641,20 @@ const writeArgToBytes = (builder, arg, args, name = null) => {
  */
 const writeArgReadCode = (builder, arg, args, name) => {
     if (arg.genericDefinition) {
-        return // Do nothing, this only specifies a later type
+        return; // Do nothing, this only specifies a later type
     }
-    //The argument may be a flag, only write that flag was given!
+    // The argument may be a flag, only write that flag was given!
     let wasFlag = false;
     if (arg.isFlag) {
         // Treat 'true' flags as a special case, since they're true if
         // they're set, and nothing else needs to actually be read.
-        if (arg.type === "true") {
-            builder.writeln("%s = Boolean(flags & %s);", name, 1 << arg.flagIndex);
+        if (arg.type === 'true') {
+            builder.writeln('%s = Boolean(flags & %s);', name, 1 << arg.flagIndex);
             return;
         }
 
         wasFlag = true;
-        builder.writeln("if (flags & %s) {", 1 << arg.flagIndex);
+        builder.writeln('if (flags & %s) {', 1 << arg.flagIndex);
         // Temporary disable .is_flag not to enter this if
         // again when calling the method recursively
         arg.isFlag = false;
@@ -717,41 +663,41 @@ const writeArgReadCode = (builder, arg, args, name) => {
     if (arg.isVector) {
         if (arg.useVectorId) {
             // We have to read the vector's constructor ID
-            builder.writeln("reader.readInt();");
+            builder.writeln('reader.readInt();');
         }
-        builder.writeln("%s = [];", name);
-        builder.writeln("len = reader.readInt();");
+
+        builder.writeln('%s = [];', name);
+        builder.writeln('len = reader.readInt();');
         builder.writeln('for (let i=0;i<len;i++){');
 
         // Temporary disable .is_vector, not to enter this if again
         arg.isVector = false;
-        writeArgReadCode(builder, arg, args, "_x");
-        builder.writeln("%s.push(_x);", name);
+        writeArgReadCode(builder, arg, args, '_x');
+        builder.writeln('%s.push(_x);', name);
         arg.isVector = true;
-
     } else if (arg.flagIndicator) {
-        //Read the flags, which will indicate what items we should read next
-        builder.writeln("let flags = reader.readInt();");
+        // Read the flags, which will indicate what items we should read next
+        builder.writeln('let flags = reader.readInt();');
         builder.writeln();
-    } else if (arg.type === "int") {
-        builder.writeln("%s = reader.readInt();", name)
-    } else if (arg.type === "long") {
-        builder.writeln("%s = reader.readLong();", name);
-    } else if (arg.type === "int128") {
+    } else if (arg.type === 'int') {
+        builder.writeln('%s = reader.readInt();', name);
+    } else if (arg.type === 'long') {
+        builder.writeln('%s = reader.readLong();', name);
+    } else if (arg.type === 'int128') {
         builder.writeln('%s = reader.readLargeInt(128);', name);
-    } else if (arg.type === "int256") {
+    } else if (arg.type === 'int256') {
         builder.writeln('%s = reader.readLargeInt(256);', name);
-    } else if (arg.type === "double") {
+    } else if (arg.type === 'double') {
         builder.writeln('%s = reader.readDouble();', name);
-    } else if (arg.type === "string") {
+    } else if (arg.type === 'string') {
         builder.writeln('%s = reader.tgReadString();', name);
-    } else if (arg.type === "Bool") {
+    } else if (arg.type === 'Bool') {
         builder.writeln('%s = reader.tgReadBool();', name);
-    } else if (arg.type === "true") {
+    } else if (arg.type === 'true') {
         builder.writeln('%s = true;', name);
-    } else if (arg.type === "bytes") {
+    } else if (arg.type === 'bytes') {
         builder.writeln('%s = reader.tgReadBytes();', name);
-    } else if (arg.type === "date") {
+    } else if (arg.type === 'date') {
         builder.writeln('%s = reader.tgReadDate();', name);
     } else {
         // Else it may be a custom type
@@ -762,45 +708,46 @@ const writeArgReadCode = (builder, arg, args, name) => {
             // There may be better solutions so that we can just access
             // all the types before the files have been parsed, but I
             // don't know of any.
-            let sepIndex = arg.type.indexOf(".");
-            let ns, t;
+            const sepIndex = arg.type.indexOf('.');
+            let ns;
+            let t;
+
             if (sepIndex === -1) {
-                ns = ".";
+                ns = '.';
                 t = arg.type;
             } else {
-                ns = "." + arg.type.slice(0, sepIndex);
+                ns = '.' + arg.type.slice(0, sepIndex);
                 t = arg.type.slice(sepIndex + 1);
             }
-            let className = snakeToCamelCase(t);
+
+            const className = snakeToCamelCase(t);
 
             // There would be no need to import the type if we're in the
             // file with the same namespace, but since it does no harm
             // and we don't have information about such thing in the
             // method we just ignore that case.
             builder.writeln('let %s = require("%s");', className, ns);
-            builder.writeln("%s = %s.fromReader(reader);", name, className);
+            builder.writeln('%s = %s.fromReader(reader);', name, className);
         }
     }
 
     // End vector and flag blocks if required (if we opened them before)
     if (arg.isVector) {
-        builder.writeln("}");
-
+        builder.writeln('}');
     }
+
     if (wasFlag) {
         builder.endBlock();
-        builder.writeln("else {");
-        builder.writeln("%s = null", name);
+        builder.writeln('else {');
+        builder.writeln('%s = null', name);
         builder.endBlock();
         // Restore .isFlag;
         arg.isFlag = true;
     }
 };
 
-
 const writePatched = (outDir, namespaceTlobjects) => {
-
-    fs.mkdirSync(outDir, {recursive: true});
+    fs.mkdirSync(outDir, { recursive: true });
 
     for (const [ns, tlobjects] of Object.entries(namespaceTlobjects)) {
         const file = `${outDir}/${ns === 'null' ? 'index' : ns}.js`;
@@ -808,41 +755,32 @@ const writePatched = (outDir, namespaceTlobjects) => {
         const builder = new SourceBuilder(stream);
 
         builder.writeln(AUTO_GEN_NOTICE);
-        builder.writeln("const struct = require('python-struct');");
+        builder.writeln('const struct = require(\'python-struct\');');
         builder.writeln(`const { TLObject, types, custom } = require('..');`);
         builder.writeln(`const Helpers = require('../../utils/Helpers');`);
 
         builder.writeln();
 
         for (const t of tlobjects) {
-            builder.writeln(
-                'class %s extends custom.%s {',
-                t.className,
-                PATCHED_TYPES[t.fullname]
-            );
+            builder.writeln('class %s extends custom.%s {', t.className, PATCHED_TYPES[t.fullname]);
             builder.writeln(`static CONSTRUCTOR_ID = 0x${t.id.toString(16)}`);
-            builder.writeln(`static SUBCLASS_OF_ID = 0x${crc32(t.result).toString("16")}`);
+            builder.writeln(`static SUBCLASS_OF_ID = 0x${crc32(t.result).toString('16')}`);
             builder.writeln();
             builder.writeln('constructor() {');
             builder.writeln('super();');
             builder.writeln(`this.CONSTRUCTOR_ID = 0x${t.id.toString(16)}`);
-            builder.writeln(`this.SUBCLASS_OF_ID = 0x${crc32(t.result).toString("16")}`);
+            builder.writeln(`this.SUBCLASS_OF_ID = 0x${crc32(t.result).toString('16')}`);
 
             builder.endBlock();
 
-            //writeToJson(t, builder);
+            // writeToJson(t, builder);
             writeToBytes(t, builder);
             writeFromReader(t, builder);
 
             builder.writeln();
             builder.endBlock();
             builder.currentIndent = 0;
-            builder.writeln(
-                'types.%s%s = %s',
-                t.namespace ? `${t.namespace}.` : '',
-                t.className,
-                t.className
-            );
+            builder.writeln('types.%s%s = %s', t.namespace ? `${t.namespace}.` : '', t.className, t.className);
             builder.writeln();
         }
     }
@@ -852,7 +790,7 @@ const writeAllTLObjects = (tlobjects, layer, builder) => {
     builder.writeln(AUTO_GEN_NOTICE);
     builder.writeln();
 
-    builder.writeln("const { types, functions, patched } = require('.');");
+    builder.writeln('const { types, functions, patched } = require(\'.\');');
     builder.writeln();
 
     // Create a constant variable to indicate which layer this is
@@ -925,20 +863,8 @@ const generateTLObjects = (tlobjects, layer, importDepth, outputDir) => {
         }
     }
 
-    writeModules(
-        `${outputDir}/functions`,
-        importDepth,
-        'TLRequest',
-        namespaceFunctions,
-        typeConstructors
-    );
-    writeModules(
-        `${outputDir}/types`,
-        importDepth,
-        'TLObject',
-        namespaceTypes,
-        typeConstructors
-    );
+    writeModules(`${outputDir}/functions`, importDepth, 'TLRequest', namespaceFunctions, typeConstructors);
+    writeModules(`${outputDir}/types`, importDepth, 'TLObject', namespaceTypes, typeConstructors);
     writePatched(`${outputDir}/patched`, namespacePatched);
 
     const filename = `${outputDir}/alltlobjects.js`;
@@ -948,8 +874,8 @@ const generateTLObjects = (tlobjects, layer, importDepth, outputDir) => {
     writeAllTLObjects(tlobjects, layer, builder);
 };
 
-const cleanTLObjects = outputDir => {
-    for (let d in ['functions', 'types', 'patched']) {
+const cleanTLObjects = (outputDir) => {
+    for (let d of ['functions', 'types', 'patched']) {
         d = `${outputDir}/d`;
 
         if (fs.statSync(d).isDirectory()) {
@@ -965,7 +891,6 @@ const cleanTLObjects = outputDir => {
 };
 
 const writeModuleExports = (tlobjects, builder) => {
-
     builder.writeln('module.exports = {');
 
     for (const t of tlobjects) {

+ 15 - 25
gramjs_generator/parsers/errors.js

@@ -18,12 +18,9 @@ const KNOWN_BASE_CLASSES = {
  * Gets the corresponding class name for the given error code,
  * this either being an integer (thus base error name) or str.
  */
-const getClassName = errorCode => {
+const getClassName = (errorCode) => {
     if (typeof errorCode === 'number') {
-        return (
-            KNOWN_BASE_CLASSES[Math.abs(errorCode)] ||
-            'RPCError' + errorCode.toString().replace('-', 'Neg')
-        );
+        return KNOWN_BASE_CLASSES[Math.abs(errorCode)] || 'RPCError' + errorCode.toString().replace('-', 'Neg');
     }
 
     return snakeToCamelCase(
@@ -40,7 +37,7 @@ class TelegramError {
         // TODO Some errors have the same name but different integer codes
         // Should these be split into different files or doesn't really matter?
         // Telegram isn't exactly consistent with returned errors anyway.
-        this.intCode = codes[0];
+        [this.intCode] = codes;
         this.stringCode = name;
         this.subclass = getClassName(codes[0]);
         this.subclassExists = Math.abs(codes[0]) in KNOWN_BASE_CLASSES;
@@ -51,7 +48,7 @@ class TelegramError {
         if (this.hasCaptures) {
             this.name = getClassName(name.replace('_X', ''));
             this.pattern = name.replace('_X', '_(\\d+)');
-            this.captureName = description.match(/{(\w+)}/)[1];
+            [this.captureName] = description.match(/{(\w+)}/);
         } else {
             this.name = getClassName(name);
             this.pattern = name;
@@ -64,33 +61,26 @@ class TelegramError {
  * Parses the input CSV file with columns (name, error codes, description)
  * and yields `Error` instances as a result.
  */
-const parseErrors = function*(csvFile) {
-    const f = csvParse(fs.readFileSync(csvFile, { encoding: 'utf-8' })).slice(
-        1
-    );
+const parseErrors = function* (csvFile) {
+    const f = csvParse(fs.readFileSync(csvFile, { encoding: 'utf-8' })).slice(1);
 
     for (let line = 0; line < f.length; line++) {
         if (f[line].length !== 3) {
-            throw new Error(
-                `Columns count mismatch, unquoted comma in desc? (line ${line +
-                    2})`
-            );
+            throw new Error(`Columns count mismatch, unquoted comma in desc? (line ${line + 2})`);
         }
 
         let [name, codes, description] = f[line];
 
         codes =
-            codes === ''
-                ? [400]
-                : codes.split(' ').map(x => {
-                      if (isNaN(x)) {
-                          throw new Error(
-                              `Not all codes are integers (line ${line + 2})`
-                          );
-                      }
+            codes === '' ?
+                [400] :
+                codes.split(' ').map((x) => {
+                    if (isNaN(x)) {
+                        throw new Error(`Not all codes are integers (line ${line + 2})`);
+                    }
 
-                      return Number(x);
-                  });
+                    return Number(x);
+                });
 
         yield new TelegramError(codes, name, description);
     }

+ 6 - 14
gramjs_generator/parsers/methods.js

@@ -17,9 +17,7 @@ class MethodInfo {
         if (usability.toUpperCase() in Usability) {
             this.usability = Usability[usability.toUpperCase()];
         } else {
-            throw new Error(
-                `Usability must be either user, bot, both or unknown, not ${usability}`
-            );
+            throw new Error(`Usability must be either user, bot, both or unknown, not ${usability}`);
         }
     }
 }
@@ -28,11 +26,9 @@ class MethodInfo {
  * Parses the input CSV file with columns (method, usability, errors)
  * and yields `MethodInfo` instances as a result.
  */
-const parseMethods = function*(csvFile, friendlyCsvFile, errorsDict) {
+const parseMethods = function* (csvFile, friendlyCsvFile, errorsDict) {
     const rawToFriendly = {};
-    const f1 = csvParse(
-        fs.readFileSync(friendlyCsvFile, { encoding: 'utf-8' })
-    );
+    const f1 = csvParse(fs.readFileSync(friendlyCsvFile, { encoding: 'utf-8' }));
 
     for (const [ns, friendly, rawList] of f1.slice(1)) {
         for (const raw of rawList.split(' ')) {
@@ -40,9 +36,7 @@ const parseMethods = function*(csvFile, friendlyCsvFile, errorsDict) {
         }
     }
 
-    const f2 = csvParse(fs.readFileSync(csvFile, { encoding: 'utf-8' })).slice(
-        1
-    );
+    const f2 = csvParse(fs.readFileSync(csvFile, { encoding: 'utf-8' })).slice(1);
 
     for (let line = 0; line < f2.length; line++) {
         let [method, usability, errors] = f2[line];
@@ -50,11 +44,9 @@ const parseMethods = function*(csvFile, friendlyCsvFile, errorsDict) {
         errors = errors
             .split(' ')
             .filter(Boolean)
-            .map(x => {
+            .map((x) => {
                 if (x && !(x in errorsDict)) {
-                    throw new Error(
-                        `Method ${method} references unknown errors ${errors}`
-                    );
+                    throw new Error(`Method ${method} references unknown errors ${errors}`);
                 }
 
                 return errorsDict[x];

+ 8 - 17
gramjs_generator/parsers/tlobject/parser.js

@@ -51,9 +51,7 @@ const findall = (regex, str, matches) => {
 };
 
 const fromLine = (line, isFunction, methodInfo, layer) => {
-    const match = line.match(
-        /([\w.]+)(?:#([0-9a-fA-F]+))?(?:\s{?\w+:[\w\d<>#.?!]+}?)*\s=\s([\w\d<>#.?]+);$/
-    );
+    const match = line.match(/([\w.]+)(?:#([0-9a-fA-F]+))?(?:\s{?\w+:[\w\d<>#.?!]+}?)*\s=\s([\w\d<>#.?]+);$/);
 
     if (!match) {
         // Probably "vector#1cb5c415 {t:Type} # [ t ] = Vector t;"
@@ -64,7 +62,8 @@ const fromLine = (line, isFunction, methodInfo, layer) => {
     const [, name] = match;
     methodInfo = methodInfo[name];
 
-    let usability, friendly;
+    let usability;
+    let friendly;
 
     if (methodInfo) {
         usability = methodInfo.usability;
@@ -77,10 +76,7 @@ const fromLine = (line, isFunction, methodInfo, layer) => {
     return new TLObject(
         name,
         match[2],
-        argsMatch.map(
-            ([brace, name, argType]) =>
-                new TLArg(name, argType, brace !== undefined)
-        ),
+        argsMatch.map(([brace, name, argType]) => new TLArg(name, argType, brace !== undefined)),
         match[3],
         isFunction,
         usability,
@@ -95,11 +91,8 @@ const fromLine = (line, isFunction, methodInfo, layer) => {
  * Note that the file is parsed completely before the function yields
  * because references to other objects may appear later in the file.
  */
-const parseTl = function*(filePath, layer, methods, ignoreIds = CORE_TYPES) {
-    const methodInfo = (methods || []).reduce(
-        (o, m) => ({ ...o, [m.name]: m }),
-        {}
-    );
+const parseTl = function* (filePath, layer, methods, ignoreIds = CORE_TYPES) {
+    const methodInfo = (methods || []).reduce((o, m) => ({ ...o, [m.name]: m }), {});
     const objAll = [];
     const objByName = {};
     const objByType = {};
@@ -165,9 +158,7 @@ const parseTl = function*(filePath, layer, methods, ignoreIds = CORE_TYPES) {
         }
 
         for (const arg of obj.args) {
-            arg.cls =
-                objByType[arg.type] ||
-                (arg.type in objByName ? [objByName[arg.type]] : []);
+            arg.cls = objByType[arg.type] || (arg.type in objByName ? [objByName[arg.type]] : []);
         }
     }
 
@@ -179,7 +170,7 @@ const parseTl = function*(filePath, layer, methods, ignoreIds = CORE_TYPES) {
 /**
  * Finds the layer used on the specified scheme.tl file.
  */
-const findLayer = filePath => {
+const findLayer = (filePath) => {
     const layerRegex = /^\/\/\s*LAYER\s*(\d+)$/;
 
     const file = fs.readFileSync(filePath, { encoding: 'utf-8' });

+ 21 - 27
gramjs_generator/parsers/tlobject/tlarg.js

@@ -4,53 +4,50 @@ const fmtStrings = (...objects) => {
             if (['null', 'true', 'false'].includes(v)) {
                 object[k] = `<strong>${v}</strong>`;
             } else {
-                object[k] = v.replace(
-                    /((['"]).*\2)/,
-                    (_, g) => `<em>${g}</em>`
-                );
+                object[k] = v.replace(/((['"]).*\2)/, (_, g) => `<em>${g}</em>`);
             }
         }
     }
 };
 
 const KNOWN_NAMED_EXAMPLES = {
-    'message,string': "'Hello there!'",
+    'message,string': '\'Hello there!\'',
     'expires_at,date': 'datetime.timedelta(minutes=5)',
     'until_date,date': 'datetime.timedelta(days=14)',
     'view_messages,true': 'None',
     'send_messages,true': 'None',
     'limit,int': '100',
     'hash,int': '0',
-    'hash,string': "'A4LmkR23G0IGxBE71zZfo1'",
+    'hash,string': '\'A4LmkR23G0IGxBE71zZfo1\'',
     'min_id,int': '0',
     'max_id,int': '0',
     'min_id,long': '0',
     'max_id,long': '0',
     'add_offset,int': '0',
-    'title,string': "'My awesome title'",
-    'device_model,string': "'ASUS Laptop'",
-    'system_version,string': "'Arch Linux'",
-    'app_version,string': "'1.0'",
-    'system_lang_code,string': "'en'",
-    'lang_pack,string': "''",
-    'lang_code,string': "'en'",
+    'title,string': '\'My awesome title\'',
+    'device_model,string': '\'ASUS Laptop\'',
+    'system_version,string': '\'Arch Linux\'',
+    'app_version,string': '\'1.0\'',
+    'system_lang_code,string': '\'en\'',
+    'lang_pack,string': '\'\'',
+    'lang_code,string': '\'en\'',
     'chat_id,int': '478614198',
     'client_id,long': 'random.randrange(-2**63, 2**63)',
 };
 
 const KNOWN_TYPED_EXAMPLES = {
-    int128: "int.from_bytes(crypto.randomBytes(16), 'big')",
-    bytes: "b'arbitrary\\x7f data \\xfa here'",
+    int128: 'int.from_bytes(crypto.randomBytes(16), \'big\')',
+    bytes: 'b\'arbitrary\\x7f data \\xfa here\'',
     long: '-12398745604826',
-    string: "'some string here'",
+    string: '\'some string here\'',
     int: '42',
     date: 'datetime.datetime(2018, 6, 25)',
     double: '7.13',
     Bool: 'False',
     true: 'True',
-    InputChatPhoto: "client.upload_file('/path/to/photo.jpg')",
-    InputFile: "client.upload_file('/path/to/file.jpg')",
-    InputPeer: "'username'",
+    InputChatPhoto: 'client.upload_file(\'/path/to/photo.jpg\')',
+    InputFile: 'client.upload_file(\'/path/to/file.jpg\')',
+    InputPeer: '\'username\'',
 };
 
 fmtStrings(KNOWN_NAMED_EXAMPLES, KNOWN_TYPED_EXAMPLES);
@@ -129,7 +126,7 @@ class TLArg {
                 this.isFlag = true;
                 this.flagIndex = Number(flagMatch[1]);
                 // Update the type to match the exact type, not the "flagged" one
-                this.type = flagMatch[2];
+                [, , this.type] = flagMatch;
             }
 
             // Then check if the type is a Vector<REAL_TYPE>
@@ -143,7 +140,7 @@ class TLArg {
                 this.useVectorId = this.type.charAt(0) === 'V';
 
                 // Update the type to match the one inside the vector
-                this.type = vectorMatch[1];
+                [, this.type] = vectorMatch;
             }
 
             // See use_vector_id. An example of such case is ipPort in
@@ -179,7 +176,7 @@ class TLArg {
         let cls = this.type;
 
         if (cls.includes('.')) {
-            cls = cls.split('.')[1];
+            [, cls] = cls.split('.');
         }
 
         let result = {
@@ -252,7 +249,7 @@ class TLArg {
             return;
         }
 
-        let known =
+        const known =
             KNOWN_NAMED_EXAMPLES[`${this.name},${this.type}`] ||
             KNOWN_TYPED_EXAMPLES[this.type] ||
             KNOWN_TYPED_EXAMPLES[SYNONYMS[this.type]];
@@ -277,10 +274,7 @@ class TLArg {
     }
 
     omitExample() {
-        return (
-            this.isFlag ||
-            (this.canBeInferred && OMITTED_EXAMPLES.includes(this.name))
-        );
+        return this.isFlag || (this.canBeInferred && OMITTED_EXAMPLES.includes(this.name));
     }
 }
 

+ 9 - 24
gramjs_generator/parsers/tlobject/tlobject.js

@@ -27,16 +27,7 @@ const WHITELISTED_MISMATCHING_IDS = {
  * :param layer: The layer this TLObject belongs to.
  */
 class TLObject {
-    constructor(
-        fullname,
-        objectId,
-        args,
-        result,
-        isFunction,
-        usability,
-        friendly,
-        layer
-    ) {
+    constructor(fullname, objectId, args, result, isFunction, usability, friendly, layer) {
         // The name can or not have a namespace
         this.fullname = fullname;
 
@@ -75,14 +66,9 @@ class TLObject {
             }
         }
 
-        this.className = snakeToCamelCase(
-            this.name,
-            this.isFunction ? 'Request' : ''
-        );
+        this.className = snakeToCamelCase(this.name, this.isFunction ? 'Request' : '');
 
-        this.realArgs = this.sortedArgs().filter(
-            a => !(a.flagIndicator || a.genericDefinition)
-        );
+        this.realArgs = this.sortedArgs().filter((a) => !(a.flagIndicator || a.genericDefinition));
     }
 
     get innermostResult() {
@@ -96,11 +82,12 @@ class TLObject {
      * can be inferred will go last so they can default =None)
      */
     sortedArgs() {
-        return this.args.sort(x => x.isFlag || x.canBeInferred);
+        return this.args.sort((x) => x.isFlag || x.canBeInferred);
     }
 
     repr(ignoreId) {
-        let hexId, args;
+        let hexId;
+        let args;
 
         if (this.id === null || ignoreId) {
             hexId = '';
@@ -109,7 +96,7 @@ class TLObject {
         }
 
         if (this.args.length) {
-            args = ` ${this.args.map(arg => arg.toString()).join(' ')}`;
+            args = ` ${this.args.map((arg) => arg.toString()).join(' ')}`;
         } else {
             args = '';
         }
@@ -136,9 +123,7 @@ class TLObject {
         return {
             id: struct.unpack('i', struct.pack('I', this.id))[0].toString(),
             [this.isFunction ? 'method' : 'predicate']: this.fullname,
-            param: this.args
-                .filter(x => !x.genericDefinition)
-                .map(x => x.toJson()),
+            param: this.args.filter((x) => !x.genericDefinition).map((x) => x.toJson()),
             type: this.result,
         };
     }
@@ -160,7 +145,7 @@ class TLObject {
         f.write(this.className);
         f.write('(');
 
-        const args = this.realArgs.filter(arg => !arg.omitExample());
+        const args = this.realArgs.filter((arg) => !arg.omitExample());
 
         if (!args.length) {
             f.write(')');

+ 1 - 1
index.js

@@ -136,7 +136,7 @@ const generate = (which, action = 'gen') => {
         console.log(action, 'JSON schema...');
 
         const jsonFiles = TLOBJECT_IN_TLS.map(
-            x => x.slice(0, x.lastIndexOf('.')) + '.json'
+            (x) => x.slice(0, x.lastIndexOf('.')) + '.json'
         );
 
         if (clean) {

+ 33 - 42
main.js

@@ -1,58 +1,49 @@
-const Helpers = require("./gramjs/utils/Helpers");
-const TelegramClient = require("./gramjs/tl/TelegramClient");
-const {GetConfigRequest} = require("./gramjs/tl/functions/help");
-const struct = require("python-struct");
+const TelegramClient = require('./gramjs/tl/TelegramClient');
 const log4js = require('log4js');
-const {InputPeerChannel} = require("./gramjs/tl/types");
-const {SendMessageRequest} = require("./gramjs/tl/functions/messages");
-const {InputPeerUser} = require("./gramjs/tl/types");
-const {ResolveUsernameRequest} = require("./gramjs/tl/functions/contacts");
-const logger = log4js.getLogger("gramjs");
+const { InputPeerChannel } = require('./gramjs/tl/types');
+const { SendMessageRequest } = require('./gramjs/tl/functions/messages');
+const { ResolveUsernameRequest } = require('./gramjs/tl/functions/contacts');
+const logger = log4js.getLogger('gramjs');
 
 logger.level = 'debug';
 
-let painorId = 400319287;
-let painorHash = 4770003194588524965n;
-
-let input_peer = new InputPeerChannel({
+const inputPeer = new InputPeerChannel({
     channelId: 1180212174,
-    accessHash: 548480552819456668n,
+    accessHash: BigInt('548480552819456668'),
 });
-let message = new SendMessageRequest({
-    peer: input_peer,
-    message: "hi",
+const message = new SendMessageRequest({
+    peer: inputPeer,
+    message: 'hi',
     randomId: 5,
 });
-console.log(message.bytes.toString("hex"));
-
-(async function () {
-
-
-    console.log("Loading interactive example...");
-    let sessionName = "anon";
-    let apiId = ;
-    let apiHash = "";
-    let client = new TelegramClient(sessionName, apiId, apiHash);
+console.log(message.bytes.toString('hex'));
+
+(async () => {
+    console.log('Loading interactive example...');
+    const sessionName = 'anon';
+    const apiId = 0;
+    const apiHash = '';
+    const client = new TelegramClient(sessionName, apiId, apiHash);
     await client.connect();
-    //let request = new GetConfigRequest();
-    //let res =         await client._sender.send(new GetConfigRequest());
-    //console.log(res)
-    let res = await client.signIn({botToken: ""});
-    let user = res.user;
+    // let request = new GetConfigRequest();
+    // let res =         await client._sender.send(new GetConfigRequest());
+    // console.log(res)
+    const res = await client.signIn({ botToken: '' });
+    const user = res.user;
     client._authorized = true;
-    let result = await client.invoke(new ResolveUsernameRequest({
-            username: 'gramjschat'
-        }
-    ));
+    const result = await client.invoke(
+        new ResolveUsernameRequest({
+            username: 'gramjschat',
+        })
+    );
     console.log(result);
 
-    let message = new SendMessageRequest({
-        peer: input_peer,
-        message: "hi from GramJS",
+    const message = new SendMessageRequest({
+        peer: inputPeer,
+        message: 'hi from GramJS',
     });
     console.log(message);
-    let r = await client.invoke(message);
+    const r = await client.invoke(message);
     console.log(r);
-    console.log("You should now be connected.", user);
+    console.log('You should now be connected.', user);
 })();
-

+ 136 - 12
package-lock.json

@@ -12,6 +12,47 @@
         "@babel/highlight": "^7.0.0"
       }
     },
+    "@babel/generator": {
+      "version": "7.6.4",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.6.4.tgz",
+      "integrity": "sha512-jsBuXkFoZxk0yWLyGI9llT9oiQ2FeTASmRFE32U+aaDTfoE92t78eroO7PTpU/OrYq38hlcDM6vbfLDaOLy+7w==",
+      "dev": true,
+      "requires": {
+        "@babel/types": "^7.6.3",
+        "jsesc": "^2.5.1",
+        "lodash": "^4.17.13",
+        "source-map": "^0.5.0"
+      }
+    },
+    "@babel/helper-function-name": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz",
+      "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-get-function-arity": "^7.0.0",
+        "@babel/template": "^7.1.0",
+        "@babel/types": "^7.0.0"
+      }
+    },
+    "@babel/helper-get-function-arity": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz",
+      "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==",
+      "dev": true,
+      "requires": {
+        "@babel/types": "^7.0.0"
+      }
+    },
+    "@babel/helper-split-export-declaration": {
+      "version": "7.4.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz",
+      "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==",
+      "dev": true,
+      "requires": {
+        "@babel/types": "^7.4.4"
+      }
+    },
     "@babel/highlight": {
       "version": "7.5.0",
       "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz",
@@ -22,6 +63,51 @@
         "js-tokens": "^4.0.0"
       }
     },
+    "@babel/parser": {
+      "version": "7.6.4",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.4.tgz",
+      "integrity": "sha512-D8RHPW5qd0Vbyo3qb+YjO5nvUVRTXFLQ/FsDxJU2Nqz4uB5EnUN0ZQSEYpvTIbRuttig1XbHWU5oMeQwQSAA+A==",
+      "dev": true
+    },
+    "@babel/template": {
+      "version": "7.6.0",
+      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.6.0.tgz",
+      "integrity": "sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ==",
+      "dev": true,
+      "requires": {
+        "@babel/code-frame": "^7.0.0",
+        "@babel/parser": "^7.6.0",
+        "@babel/types": "^7.6.0"
+      }
+    },
+    "@babel/traverse": {
+      "version": "7.6.3",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.6.3.tgz",
+      "integrity": "sha512-unn7P4LGsijIxaAJo/wpoU11zN+2IaClkQAxcJWBNCMS6cmVh802IyLHNkAjQ0iYnRS3nnxk5O3fuXW28IMxTw==",
+      "dev": true,
+      "requires": {
+        "@babel/code-frame": "^7.5.5",
+        "@babel/generator": "^7.6.3",
+        "@babel/helper-function-name": "^7.1.0",
+        "@babel/helper-split-export-declaration": "^7.4.4",
+        "@babel/parser": "^7.6.3",
+        "@babel/types": "^7.6.3",
+        "debug": "^4.1.0",
+        "globals": "^11.1.0",
+        "lodash": "^4.17.13"
+      }
+    },
+    "@babel/types": {
+      "version": "7.6.3",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.6.3.tgz",
+      "integrity": "sha512-CqbcpTxMcpuQTMhjI37ZHVgjBkysg5icREQIEZ0eG1yCNwg3oy+5AaLiOKmjsCj6nqOsa6Hf0ObjRVwokb7srA==",
+      "dev": true,
+      "requires": {
+        "esutils": "^2.0.2",
+        "lodash": "^4.17.13",
+        "to-fast-properties": "^2.0.0"
+      }
+    },
     "@types/lodash": {
       "version": "4.14.138",
       "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.138.tgz",
@@ -38,14 +124,14 @@
       "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA=="
     },
     "acorn": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.0.0.tgz",
-      "integrity": "sha512-PaF/MduxijYYt7unVGRuds1vBC9bFxbNf+VWqhOClfdgy7RlVkQqt610ig1/yxTgsDIfW1cWDel5EBbOy3jdtQ=="
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz",
+      "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ=="
     },
     "acorn-jsx": {
-      "version": "5.0.2",
-      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.2.tgz",
-      "integrity": "sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw=="
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.1.0.tgz",
+      "integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw=="
     },
     "aes-js": {
       "version": "3.1.2",
@@ -102,6 +188,20 @@
       "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
       "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg=="
     },
+    "babel-eslint": {
+      "version": "10.0.3",
+      "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.0.3.tgz",
+      "integrity": "sha512-z3U7eMY6r/3f3/JB9mTsLjyxrv0Yb1zb8PCWCLpguxfCzBIZUwy23R1t/XKewP+8mEN2Ck8Dtr4q20z6ce6SoA==",
+      "dev": true,
+      "requires": {
+        "@babel/code-frame": "^7.0.0",
+        "@babel/parser": "^7.0.0",
+        "@babel/traverse": "^7.0.0",
+        "@babel/types": "^7.0.0",
+        "eslint-visitor-keys": "^1.0.0",
+        "resolve": "^1.12.0"
+      }
+    },
     "balanced-match": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
@@ -353,9 +453,9 @@
       "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
     },
     "eslint": {
-      "version": "6.4.0",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.4.0.tgz",
-      "integrity": "sha512-WTVEzK3lSFoXUovDHEbkJqCVPEPwbhCq4trDktNI6ygs7aO41d4cDT0JFAT5MivzZeVLWlg7vHL+bgrQv/t3vA==",
+      "version": "6.5.1",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.5.1.tgz",
+      "integrity": "sha512-32h99BoLYStT1iq1v2P9uwpyznQ4M2jRiFB6acitKz52Gqn+vPaMDUTB1bYi1WN4Nquj2w+t+bimYUG83DC55A==",
       "requires": {
         "@babel/code-frame": "^7.0.0",
         "ajv": "^6.10.0",
@@ -396,6 +496,12 @@
         "v8-compile-cache": "^2.0.3"
       }
     },
+    "eslint-config-google": {
+      "version": "0.14.0",
+      "resolved": "https://registry.npmjs.org/eslint-config-google/-/eslint-config-google-0.14.0.tgz",
+      "integrity": "sha512-WsbX4WbjuMvTdeVL6+J3rK1RGhCTqjsFjX7UMSMgZiyxxaNLkoJENbrGExzERFeoTpGw3F3FypTiWAP9ZXzkEw==",
+      "dev": true
+    },
     "eslint-scope": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz",
@@ -601,9 +707,9 @@
       }
     },
     "glob-parent": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.0.0.tgz",
-      "integrity": "sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==",
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz",
+      "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==",
       "requires": {
         "is-glob": "^4.0.1"
       }
@@ -782,6 +888,12 @@
         "esprima": "^4.0.0"
       }
     },
+    "jsesc": {
+      "version": "2.5.2",
+      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
+      "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
+      "dev": true
+    },
     "json-parse-better-errors": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
@@ -1282,6 +1394,12 @@
         "smart-buffer": "4.0.2"
       }
     },
+    "source-map": {
+      "version": "0.5.7",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+      "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+      "dev": true
+    },
     "spdx-correct": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
@@ -1423,6 +1541,12 @@
         "os-tmpdir": "~1.0.2"
       }
     },
+    "to-fast-properties": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+      "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
+      "dev": true
+    },
     "tslib": {
       "version": "1.10.0",
       "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",

+ 3 - 0
package.json

@@ -28,8 +28,11 @@
     "string-format": "^2.0.0"
   },
   "devDependencies": {
+    "babel-eslint": "^10.0.3",
     "bigint-buffer": "^1.1.2",
     "biguintle": "^1.0.3",
+    "eslint": "^6.5.1",
+    "eslint-config-google": "^0.14.0",
     "leemon": "^6.2.0"
   }
 }