Jelajahi Sumber

Fix get bytes
Update authenticator
Fix BinaryReader

painor 5 tahun lalu
induk
melakukan
74feec1c3d

+ 12 - 1
gramjs/errors/Common.js

@@ -138,4 +138,15 @@ class BadMessageError extends Error {
 
 }
 
-// TODO : Support multi errors.
+// TODO : Support multi errors.
+
+module.exports = {
+    ReadCancelledError,
+    TypeNotFoundError,
+    InvalidChecksumError,
+    InvalidBufferError,
+    SecurityError,
+    CdnFileTamperedError,
+    AlreadyInConversationError,
+    BadMessageError
+};

+ 1 - 1
gramjs/extensions/BinaryReader.js

@@ -114,7 +114,7 @@ class BinaryReader {
      * specifying its length.
      * @returns {Buffer}
      */
-    tgReadByte() {
+    tgReadBytes() {
         let firstByte = this.readByte();
         let padding, length;
         if (firstByte === 254) {

+ 21 - 7
gramjs/network/Authenticator.js

@@ -5,6 +5,20 @@ const RSA = require("../crypto/RSA");
 const MtProtoPlainSender = require("./MTProtoPlainSender");
 const Helpers = require("../utils/Helpers");
 const BigIntBuffer = require("bigint-buffer");
+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 {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.
@@ -23,7 +37,7 @@ async function doAuthentication(sender) {
     if (!resPQ.nonce.equals(nonce)) {
         throw new SecurityError("Step 1 invalid nonce from server'")
     }
-    pq = BigIntBuffer.toBigIntBE(resPQ.pq);
+    let pq = BigIntBuffer.toBigIntBE(resPQ.pq);
 
     // Step 2 sending: DH Exchange
     let {p, q} = Factorizator.factorize(pq);
@@ -31,7 +45,7 @@ async function doAuthentication(sender) {
     q = getByteArray(q);
     let newNonce = Helpers.generateRandomBytes(32);
     let pqInnerData = PQInnerData({
-            pq: rsa.get_byte_array(pq),
+            pq: getByteArray(pq),
             p: p,
             q: q,
             nonce: resPQ.nonce,
@@ -44,7 +58,7 @@ async function doAuthentication(sender) {
     // sha_digest + data + random_bytes
     let cipherText = null;
     let targetFingerprint = null;
-    for (let fingerprint of resPQ.serverPublicKeyFingerprints) {
+    for (let fingerprint of resPQ.server_public_key_fingerprints) {
         cipherText = RSA.encrypt(getFingerprintText(fingerprint), pqInnerData);
         if (cipherText !== null) {
             targetFingerprint = fingerprint;
@@ -78,7 +92,7 @@ async function doAuthentication(sender) {
     if (serverDhParams instanceof ServerDHParamsFail) {
         let sh = Helpers.sha1(BigIntBuffer.toBufferLE(newNonce, 32).slice(4, 20));
         let nnh = BigIntBuffer.toBigIntLE(sh);
-        if (serverDhParams.newNonceHash !== nnh) {
+        if (serverDhParams.new_nonce_hash !== nnh) {
             throw new SecurityError('Step 2 invalid DH fail nonce from server')
 
         }
@@ -90,12 +104,12 @@ async function doAuthentication(sender) {
     // Step 3 sending: Complete DH Exchange
     let {key, iv} = Helpers.generateKeyDataFromNonces(resPQ.server_nonce, newNonce);
 
-    if (serverDhParams.encryptedAnswer.length % 16 !== 0) {
+    if (serverDhParams.encrypted_answer.length % 16 !== 0) {
         // See PR#453
         throw new SecurityError('Step 3 AES block size mismatch')
     }
     let plainTextAnswer = AES.decryptIge(
-        serverDhParams.encryptedAnswer, key, iv
+        serverDhParams.encrypted_answer, key, iv
     );
 
     let reader = new BinaryReader(plainTextAnswer);
@@ -112,7 +126,7 @@ async function doAuthentication(sender) {
         throw new SecurityError('Step 3 Invalid server nonce in encrypted answer')
     }
     let dhPrime = BigIntBuffer.toBigIntLE(serverDhInner.dhPrime);
-    let ga = BigIntBuffer.toBigIntLE(serverDhInner.ga);
+    let ga = BigIntBuffer.toBigIntLE(serverDhInner.gA);
     let timeOffset = serverDhInner.serverTime - Math.floor(new Date().getTime() / 1000);
 
     let b = BigIntBuffer.toBigIntLE(Helpers.generateRandomBytes(256));

+ 60 - 64
gramjs_generator/generators/tlobject.js

@@ -2,7 +2,7 @@ const fs = require('fs');
 const util = require('util');
 const {crc32} = require('crc');
 const SourceBuilder = require('../sourcebuilder');
-const {snakeToCamelCase} = require("../utils");
+const {snakeToCamelCase, variableSnakeToCamelCase} = require("../utils");
 
 const AUTO_GEN_NOTICE =
     "/*! File generated by TLObjects' generator. All changes will be ERASED !*/";
@@ -92,10 +92,12 @@ const writeModules = (
 
         // Import struct for the .__bytes__(self) serialization
         builder.writeln("const struct = require('python-struct');");
+        builder.writeln(`const Helpers = require('../../utils/Helpers');`);
+        builder.writeln(`const BigIntBuffer = require("bigint-buffer");`);
 
         const typeNames = new Set();
         const typeDefs = [];
-
+        /*
         // Find all the types in this file and generate type definitions
         // based on the types. The type definitions are written to the
         // file at the end.
@@ -128,7 +130,7 @@ const writeModules = (
                     );
                 }
             }
-        }
+        }*/
 
         const imports = {};
         const primitives = new Set([
@@ -318,7 +320,7 @@ const writeClassConstructor = (tlobject, kind, typeConstructors, builder) => {
     // Set the arguments
     for (const arg of tlobject.realArgs) {
         if (!arg.canBeInferred) {
-            builder.writeln(`this.${arg.name} = args.${arg.name};`);
+            builder.writeln(`this.${variableSnakeToCamelCase(arg.name)} = args.${variableSnakeToCamelCase(arg.name)};`);
         }
 
         // Currently the only argument that can be
@@ -452,8 +454,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 (const arg of tlobject.args) {
+    for (let arg of tlobject.args) {
         if (arg.isFlag) {
             if (!repeatedArgs[arg.flagIndex]) {
                 repeatedArgs[arg.flagIndex] = [];
@@ -461,59 +462,50 @@ const writeToBytes = (tlobject, builder) => {
             repeatedArgs[arg.flagIndex].push(arg);
         }
     }
-
-    for (const ra of Object.values(repeatedArgs)) {
+    for (let ra of Object.values(repeatedArgs)) {
         if (ra.length > 1) {
-            const cnd1 = ra.map(
-                a => `(this.${a.name} || this.${a.name} !== null)`
-            );
-            const cnd2 = ra.map(
-                a => `(this.${a.name} === null || this.${a.name} === false)`
-            );
-
-            builder.writeln(
-                'if (!(%s || %s)) {',
-                cnd1.join(' && '),
-                cnd2.join(' && ')
-            );
-
-            builder.writeln(
-                "throw new Error('%s parameters must all be false-y (like null) or all me true-y');",
-                ra.map(a => a.name).join(', ')
-            );
-            builder.endBlock();
+            let cnd1 = [];
+            let cnd2 = [];
+            let names = [];
+
+            for (let 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(", "));
         }
     }
-
-    const bytes = Buffer.from(
-        parseInt(tlobject.id)
-            .toString(16)
-            .padStart(8, `0`),
-        `hex`
-    )
-        .readUInt32LE(0)
-        .toString(16)
-        .padStart(8, `0`);
-
-    builder.writeln('return Buffer.concat([');
+    builder.writeln("return Buffer.concat([");
     builder.currentIndent++;
-
-    builder.writeln("'%s',", bytes);
-
-    for (const arg of tlobject.args) {
+    let 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) {
+        console.log("ok");
         if (writeArgToBytes(builder, arg, tlobject.args)) {
             builder.writeln(',');
         }
     }
-
     builder.currentIndent--;
-    builder.writeln(']);');
+    builder.writeln("])");
     builder.endBlock();
+
 };
 
 // writeFromReader
 const writeFromReader = (tlobject, builder) => {
+
     builder.writeln("static fromReader(reader) {");
+    for (const arg of tlobject.args) {
+        if (arg.name !== "flag")
+            builder.writeln("let %s", "_" + arg.name + ";");
+    }
+    builder.writeln("let _x;");
+
+
     for (const arg of tlobject.args) {
         writeArgReadCode(builder, arg, tlobject.args, "_" + arg.name);
     }
@@ -544,7 +536,7 @@ const writeArgToBytes = (builder, arg, args, name = null) => {
     if (name === null) {
         name = `this.${arg.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.
     // True types are not actually sent, but instead only used to
@@ -643,7 +635,7 @@ const writeArgToBytes = (builder, arg, args, name = null) => {
         builder.write(']');
 
         if (arg.isVector) {
-            builder.write(']');
+            builder.write(')');
         }
     }
 
@@ -672,7 +664,7 @@ const writeArgReadCode = (builder, arg, args, name) => {
         // 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("let %s = Boolean(flags & %s)", name, 1 << arg.flagIndex);
+            builder.writeln("%s = Boolean(flags & %s)", name, 1 << arg.flagIndex);
             return;
         }
 
@@ -686,9 +678,9 @@ 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("let %s = []", name);
+        builder.writeln("%s = []", name);
         builder.writeln("for (let i=0;i<reader.readInt();i++){");
         // Temporary disable .is_vector, not to enter this if again
         arg.isVector = false;
@@ -701,29 +693,29 @@ const writeArgReadCode = (builder, arg, args, name) => {
         builder.writeln("let flags = reader.readInt()");
         builder.writeln();
     } else if (arg.type === "int") {
-        builder.writeln("let %s = reader.readInt()", name)
+        builder.writeln("%s = reader.readInt();", name)
     } else if (arg.type === "long") {
-        builder.writeln("let %s = reader.readInt()", name);
+        builder.writeln("%s = reader.readInt();", name);
     } else if (arg.type === "int128") {
-        builder.writeln('let %s = reader.readLargeInt(bits=128)', name);
+        builder.writeln('%s = reader.readLargeInt(128);', name);
     } else if (arg.type === "int256") {
-        builder.writeln('let %s = reader.readLargeInt(bits=256)', name);
+        builder.writeln('%s = reader.readLargeInt(256);', name);
     } else if (arg.type === "double") {
-        builder.writeln('let %s = reader.readDouble()', name);
+        builder.writeln('%s = reader.readDouble();', name);
     } else if (arg.type === "string") {
-        builder.writeln('let %s = reader.tgReadString()', name);
+        builder.writeln('%s = reader.tgReadString();', name);
     } else if (arg.type === "Bool") {
-        builder.writeln('let %s = reader.tgReadBool()', name);
+        builder.writeln('%s = reader.tgReadBool();', name);
     } else if (arg.type === "true") {
-        builder.writeln('let %s = true', name);
+        builder.writeln('%s = true;', name);
     } else if (arg.type === "bytes") {
-        builder.writeln('let %s = reader.tgReadBytes()', name);
+        builder.writeln('%s = reader.tgReadBytes();', name);
     } else if (arg.type === "date") {
-        builder.writeln('let %s = reader.tgReadDate()', name);
+        builder.writeln('%s = reader.tgReadDate();', name);
     } else {
         // Else it may be a custom type
         if (!arg.skipConstructorId) {
-            builder.writeln('let %s = reader.tgReadObject()', name);
+            builder.writeln('%s = reader.tgReadObject();', name);
         } else {
             // Import the correct type inline to avoid cyclic imports.
             // There may be better solutions so that we can just access
@@ -744,8 +736,8 @@ const writeArgReadCode = (builder, arg, args, name) => {
             // 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('const %s = require("%S")', className, ns);
-            builder.writeln("let %s = %s.fromReader(reader)", name, className);
+            builder.writeln('const %s = require("%S");', className, ns);
+            builder.writeln("%s = %s.fromReader(reader);", name, className);
         }
     }
 
@@ -753,11 +745,12 @@ const writeArgReadCode = (builder, arg, args, name) => {
     if (arg.isVector) {
         builder.endBlock();
     }
-
+    builder.currentIndent -= 1;
     if (wasFlag) {
         builder.currentIndent -= 1;
         builder.writeln("else");
-        builder.writeln("let %s = null", name);
+        builder.currentIndent -= 1;
+        builder.writeln("%s = null", name);
         builder.currentIndent -= 1;
         // Restore .isFlag;
         arg.isFlag = true;
@@ -776,6 +769,9 @@ const writePatched = (outDir, namespaceTlobjects) => {
         builder.writeln(AUTO_GEN_NOTICE);
         builder.writeln("const struct = require('python-struct');");
         builder.writeln(`const { TLObject, types, custom } = require('..');`);
+        builder.writeln(`const Helpers = require('../../utils/Helpers');`);
+        builder.writeln(`const BigIntBuffer = require("bigint-buffer");`);
+
         builder.writeln();
 
         for (const t of tlobjects) {

+ 7 - 0
gramjs_generator/utils.js

@@ -2,7 +2,14 @@ const snakeToCamelCase = (name, suffix) => {
     const result = name.replace(/(?:^|_)([a-z])/g, (_, g) => g.toUpperCase());
     return result.replace(/_/g, '') + (suffix || '');
 };
+const variableSnakeToCamelCase = (str) => str.replace(
+    /([-_][a-z])/g,
+    (group) => group.toUpperCase()
+        .replace('-', '')
+        .replace('_', '')
+);
 
 module.exports = {
     snakeToCamelCase,
+    variableSnakeToCamelCase,
 };