Quellcode durchsuchen

Port code to browser compatible

painor vor 5 Jahren
Ursprung
Commit
30ac1fa55e

+ 1 - 1
.eslintignore

@@ -4,4 +4,4 @@ gramjs/tl/patched
 gramjs/tl/types
 gramjs/tl/AllTLObjects.js
 gramjs/errors/RPCErrorList.js
-
+example.js

+ 1 - 0
.gitignore

@@ -8,6 +8,7 @@
 /gramjs/tl/patched/
 /gramjs/tl/AllTLObjects.js
 /gramjs/errors/RPCErrorList.js
+/dist/
 
 # User session
 *.session

+ 2 - 9
examples/main.js

@@ -1,13 +1,6 @@
 const { TelegramClient } = require('../gramjs')
-const log4js = require('log4js')
-const { InputPeerChat } = require('../gramjs/tl/types')
-const { SendMessageRequest } = require('../gramjs/tl/functions/messages')
-const logger = log4js.getLogger('gramjs')
-
-logger.level = 'debug'
-
-
-console.log(message.bytes.toString('hex'));
+const logger = require('log4js').getLogger()
+logger.level = 'debug';
 
 (async () => {
     console.log('Loading interactive example...')

+ 22 - 6
gramjs/Helpers.js

@@ -1,5 +1,21 @@
 const crypto = require('crypto')
 
+/**
+ * use this instead of ** because of webpack
+ * @param a {bigint}
+ * @param b {bigint}
+ * @returns {bigint}
+ */
+function bigIntPower(a, b) {
+    let i
+    let pow = BigInt(1)
+
+    for (i = BigInt(0); i < b; i++) {
+        pow = pow * a
+    }
+
+    return pow
+}
 
 /**
  * converts a buffer to big int
@@ -16,7 +32,7 @@ function readBigIntFromBuffer(buffer, little = true, signed = false) {
     }
     let bigInt = BigInt('0x' + randBuffer.toString('hex'))
     if (signed && Math.floor(bigInt.toString('2').length / 8) >= bytesNumber) {
-        bigInt -= 2n ** BigInt(bytesNumber * 8)
+        bigInt -= bigIntPower(BigInt(2), BigInt(bytesNumber * 8))
     }
     return bigInt
 }
@@ -173,12 +189,12 @@ function sha256(data) {
  */
 function modExp(a, b, n) {
     a = a % n
-    let result = 1n
+    let result = BigInt(1)
     let x = a
-    while (b > 0n) {
-        const leastSignificantBit = b % 2n
-        b = b / 2n
-        if (leastSignificantBit === 1n) {
+    while (b > BigInt(0)) {
+        const leastSignificantBit = b % BigInt(2)
+        b = b / BigInt(2)
+        if (leastSignificantBit === BigInt(1)) {
             result = result * x
             result = result % n
         }

+ 27 - 27
gramjs/Password.js

@@ -1,6 +1,6 @@
 const Factorizator = require('./crypto/Factorizator')
 const { types } = require('./tl')
-const { readBigIntFromBuffer, readBufferFromBigInt, sha256, modExp, generateRandomBytes, sleep } = require('./Helpers')
+const { readBigIntFromBuffer, readBufferFromBigInt, sha256, modExp, generateRandomBytes } = require('./Helpers')
 const crypto = require('crypto')
 const SIZE_FOR_HASH = 256
 
@@ -19,33 +19,33 @@ function checkPrimeAndGoodCheck(prime, g) {
     if (Factorizator.factorize(prime)[0] !== 1) {
         throw new Error('give "prime" is not prime')
     }
-    if (g === 2n) {
-        if (prime % 8n !== 7n) {
+    if (g === BigInt(2)) {
+        if (prime % BigInt(8) !== BigInt(7)) {
             throw new Error(`bad g ${g}, mod8 ${prime % 8}`)
         }
-    } else if (g === 3n) {
-        if (prime % 3n !== 2n) {
+    } else if (g === BigInt(3)) {
+        if (prime % BigInt(3) !== BigInt(2)) {
             throw new Error(`bad g ${g}, mod3 ${prime % 3}`)
         }
         // eslint-disable-next-line no-empty
-    } else if (g === 4n) {
+    } else if (g === BigInt(4)) {
 
-    } else if (g === 5n) {
-        if (!([1n, 4n].includes(prime % 5n))) {
+    } else if (g === BigInt(5)) {
+        if (!([BigInt(1), BigInt(4)].includes(prime % BigInt(5)))) {
             throw new Error(`bad g ${g}, mod8 ${prime % 5}`)
         }
-    } else if (g === 6n) {
-        if (!([19n, 23n].includes(prime % 24n))) {
+    } else if (g === BigInt(6)) {
+        if (!([BigInt(9), BigInt(3)].includes(prime % BigInt(4)))) {
             throw new Error(`bad g ${g}, mod8 ${prime % 24}`)
         }
-    } else if (g === 7n) {
-        if (!([3n, 5n, 6n].includes(prime % 7n))) {
+    } else if (g === BigInt(7)) {
+        if (!([BigInt(3), BigInt(5), BigInt(6)].includes(prime % BigInt(7)))) {
             throw new Error(`bad g ${g}, mod8 ${prime % 7}`)
         }
     } else {
         throw new Error(`bad g ${g}`)
     }
-    const primeSub1Div2 = (prime - 1n) / 2n
+    const primeSub1Div2 = (prime - BigInt(1)) / BigInt(2)
     if (Factorizator.factorize(primeSub1Div2)[0] !== 1) {
         throw new Error('(prime - 1) // 2 is not prime')
     }
@@ -90,7 +90,7 @@ function checkPrimeAndGood(primeBytes, g) {
  * @returns {boolean}
  */
 function isGoodLarge(number, p) {
-    return (number > 0n && (p - number) > 0n)
+    return (number > BigInt(0) && (p - number) > BigInt(0))
 }
 
 /**
@@ -207,33 +207,34 @@ function computeCheck(request, password) {
     const pForHash = numBytesForHash(algo.p)
     const gForHash = bigNumForHash(g)
     const bForHash = numBytesForHash(request.srp_B)
-    const g_x = modExp(BigInt(g), x, p)
+    const gX = modExp(BigInt(g), x, p)
     const k = readBigIntFromBuffer(sha256(Buffer.concat([pForHash, gForHash])), false)
-    const kg_x = (k * g_x) % p
+    const kgX = (k * gX) % p
     const generateAndCheckRandom = () => {
         const randomSize = 256
+        // eslint-disable-next-line no-constant-condition
         while (true) {
-            const random = Buffer.from('eef192e0074abd694fcc0d1d65d65e6675161e84903ca81e1515bb22bbae9d69e2b4a2193650fb16ff204873ec34a18faab1999e77c167c4459e48332965966210e846219b2c32c338309cf5094d826bd676f684e9428b03757e499ff6da9aebc5d92bfba8fcf3cb5f9f316644503f256714c2af31e6432a9ff7327999f4ec98a4e63ca171dddfc513f513db3f359da7b535240eb250d45c4e9ce6934ff806944eab4302d83d37283760cc0e35ec8df7213d5abc5cf8a625d9c0834f6e4994c2a98ec810c810f7dfebb4feb9381d71d53dee97fcedbbd9221de67140c76fd1b8e9c40d0c6156168399053a538a681941d69f14afe96bdc48347f3a9755b96006', 'hex') // generateRandomBytes(randomSize)
+            const random = generateRandomBytes(randomSize)
             const a = readBigIntFromBuffer(random, false)
             const A = modExp(BigInt(g), a, p)
             if (isGoodModExpFirst(A, p)) {
                 const aForHash = bigNumForHash(A)
                 const u = readBigIntFromBuffer(sha256(Buffer.concat([aForHash, bForHash])), false)
-                if (u > 0n) {
+                if (u > BigInt(0)) {
                     return [a, aForHash, u]
                 }
             }
         }
     }
     const [a, aForHash, u] = generateAndCheckRandom()
-    const g_b = (B - kg_x) % p
-    if (!isGoodModExpFirst(g_b, p)) {
-        throw new Error('bad g_b')
+    const gB = (B - kgX) % p
+    if (!isGoodModExpFirst(gB, p)) {
+        throw new Error('bad gB')
     }
 
     const ux = u * x
-    const a_ux = a + ux
-    const S = modExp(g_b, a_ux, p)
+    const aUx = a + ux
+    const S = modExp(gB, aUx, p)
     const K = sha256(bigNumForHash(S))
     const M1 = sha256(Buffer.concat([
         xor(sha256(pForHash), sha256(gForHash)),
@@ -254,8 +255,7 @@ function computeCheck(request, password) {
 }
 
 module.exports = {
-    computeHash,
-    computeDigest,
     computeCheck,
-    isGoodModExpFirst,
-}
+    computeDigest,
+}
+

+ 0 - 2
gramjs/Utils.js

@@ -159,9 +159,7 @@ function getInputUser(entity) {
             })
         }
     }
-    console.log(entity)
     if (entity instanceof types.InputPeerSelf) {
-
         return new types.InputPeerSelf()
     }
     if (entity instanceof types.UserEmpty || entity instanceof types.InputPeerEmpty) {

+ 24 - 19
gramjs/client/TelegramClient.js

@@ -1,17 +1,19 @@
-const log4js = require('log4js')
+const logger = require('log4js').getLogger()
 const { sleep } = require('../Helpers')
 const errors = require('../errors')
+const MemorySession = require('../sessions/Memory')
 const { addKey } = require('../crypto/RSA')
 const { TLRequest } = require('../tl/tlobject')
 const utils = require('../Utils')
-const Session = require('../sessions/Session')
+const Session = require('../sessions/Abstract')
+const JSONSession = require('../sessions/JSONSession')
 const os = require('os')
 const { GetConfigRequest } = require('../tl/functions/help')
 const { LAYER } = require('../tl/AllTLObjects')
 const { functions, types } = require('../tl')
 const { computeCheck } = require('../Password')
 const MTProtoSender = require('../network/MTProtoSender')
-const { ConnectionTCPFull } = require('../network/connection/TCPFull')
+const { ConnectionTCPObfuscated } = require('../network/connection/TCPObfuscated')
 const DEFAULT_DC_ID = 4
 const DEFAULT_IPV4_IP = '149.154.167.51'
 const DEFAULT_IPV6_IP = '[2001:67c:4e8:f002::a]'
@@ -19,7 +21,7 @@ const DEFAULT_PORT = 443
 
 class TelegramClient {
     static DEFAULT_OPTIONS = {
-        connection: ConnectionTCPFull,
+        connection: ConnectionTCPObfuscated,
         useIPV6: false,
         proxy: null,
         timeout: 10,
@@ -38,7 +40,7 @@ class TelegramClient {
     }
 
 
-    constructor(sessionName, apiId, apiHash, opts = TelegramClient.DEFAULT_OPTIONS) {
+    constructor(session, apiId, apiHash, opts = TelegramClient.DEFAULT_OPTIONS) {
         if (apiId === undefined || apiHash === undefined) {
             throw Error('Your API ID or Hash are invalid. Please read "Requirements" on README.md')
         }
@@ -48,11 +50,21 @@ class TelegramClient {
         this._useIPV6 = args.useIPV6
         this._entityCache = new Set()
         if (typeof args.baseLogger == 'string') {
-            this._log = log4js.getLogger(args.baseLogger)
+            this._log = logger
         } else {
             this._log = args.baseLogger
         }
-        const session = Session.tryLoadOrCreateNew(sessionName)
+        // Determine what session we will use
+        if (typeof session === 'string' || !session) {
+            try {
+                session = JSONSession.tryLoadOrCreateNew(session)
+            } catch (e) {
+                console.log(e)
+                session = new MemorySession()
+            }
+        } else if (!(session instanceof Session)) {
+            throw new Error('The given session must be str or a session instance')
+        }
         if (!session.serverAddress || (session.serverAddress.includes(':') !== this._useIPV6)) {
             session.setDC(DEFAULT_DC_ID, this._useIPV6 ? DEFAULT_IPV6_IP : DEFAULT_IPV4_IP, DEFAULT_PORT)
         }
@@ -196,7 +208,6 @@ class TelegramClient {
         if (!(request instanceof TLRequest)) {
             throw new Error('You can only invoke MTProtoRequests')
         }
-        console.log('sending request..', request)
         await request.resolve(this, utils)
 
         if (request.CONSTRUCTOR_ID in this._floodWaitedRequests) {
@@ -278,8 +289,9 @@ class TelegramClient {
         if (await this.isUserAuthorized()) {
             return this
         }
+        let phone
         if (!args.botToken) {
-            args.phone = utils.parsePhone(args.phone) || args.phone
+            phone = utils.parsePhone(args.phone) || args.phone
         }
         if (args.botToken) {
             await this.signIn({
@@ -292,7 +304,7 @@ class TelegramClient {
         let attempts = 0
         let twoStepDetected = false
 
-        await this.sendCodeRequest(args.phone, args.forceSMS)
+        await this.sendCodeRequest(phone, args.forceSMS)
         console.log('you  got sent the code')
 
         let signUp = false
@@ -314,22 +326,19 @@ class TelegramClient {
                 } else {
                     // this throws SessionPasswordNeededError if 2FA enabled
                     me = await this.signIn({
-                        phone: args.phone,
+                        phone: phone,
                         code: value,
                     })
                 }
                 break
             } catch (e) {
-
                 if (e instanceof errors.SessionPasswordNeededError) {
                     twoStepDetected = true
                     break
                 } else if (e instanceof errors.PhoneNumberOccupiedError) {
                     signUp = true
-
                 } else if (e instanceof errors.PhoneNumberUnoccupiedError) {
                     signUp = true
-
                 } else if (e instanceof errors.PhoneCodeEmptyError ||
                     e instanceof errors.PhoneCodeExpiredError ||
                     e instanceof errors.PhoneCodeHashEmptyError ||
@@ -345,18 +354,16 @@ class TelegramClient {
             throw new Error(`${args.maxAttempts} consecutive sign-in attempts failed. Aborting`)
         }
         if (twoStepDetected) {
-            console.log('two steps baby')
             if (!args.password) {
                 throw new Error('Two-step verification is enabled for this account. ' +
                     'Please provide the \'password\' argument to \'start()\'.')
             }
             me = await this.signIn({
-                phone: args.phone,
+                phone: phone,
                 password: args.password,
             })
         }
         const name = utils.getDisplayName(me)
-        console.log(me)
         console.log('Signed in successfully as', name)
         return this
     }
@@ -495,7 +502,6 @@ class TelegramClient {
     }
 
     _handleUpdate(update) {
-
         this.session.processEntities(update)
         this._entityCache.add(update)
 
@@ -781,7 +787,6 @@ class TelegramClient {
             }
         }
         return false
-
     }
 
     async signUp() {

+ 24 - 0
gramjs/crypto/AESCTR.js

@@ -0,0 +1,24 @@
+const aesjs = require('aes-js')
+const stackTrace = require('stack-trace')
+
+class AESModeCTR {
+    constructor(key, iv) {
+        if (!(key instanceof Buffer) || !(iv instanceof Buffer) || iv.length !== 16) {
+            throw new Error('Key and iv need to be a buffer')
+        }
+        this.key = key
+        this.iv = iv
+        this.cipher = new aesjs.ModeOfOperation.ctr(key, iv)
+    }
+
+    encrypt(data) {
+        return Buffer.from(this.cipher.encrypt(data))
+    }
+
+    decrypt(data) {
+        return Buffer.from(this.cipher.decrypt(data))
+    }
+
+}
+
+module.exports = AESModeCTR

+ 17 - 17
gramjs/crypto/Factorizator.js

@@ -7,20 +7,20 @@ class Factorizator {
      * @return {BigInt}
      */
     static findSmallMultiplierLopatin(what) {
-        let g = 0n
-        for (let i = 0n; i < 3n; i++) {
-            const q = 30n || (getRandomInt(0, 127) & 15) + 17
-            let x = 40n || getRandomInt(0, 1000000000) + 1
+        let g = BigInt(0)
+        for (let i = BigInt(0); i < BigInt(3); i++) {
+            const q = BigInt(0) || (getRandomInt(0, 127) & 15) + 17
+            let x = BigInt(0) || getRandomInt(0, 1000000000) + 1
 
             let y = x
-            const lim = 1n << (i + 18n)
-            for (let j = 1n; j < lim; j++) {
+            const lim = BigInt(1) << (i + BigInt(8))
+            for (let j = BigInt(1); j < lim; j++) {
                 let a = x
                 let b = x
 
                 let c = q
-                while (b !== 0n) {
-                    if (BigInt(b & 1n) !== 0n) {
+                while (b !== BigInt(0)) {
+                    if (BigInt(b & BigInt(1)) !== BigInt(0)) {
                         c += a
                         if (c >= what) {
                             c -= what
@@ -30,18 +30,18 @@ class Factorizator {
                     if (a >= what) {
                         a -= what
                     }
-                    b >>= 1n
+                    b >>= BigInt(1)
                 }
 
                 x = c
                 const z = BigInt(x < y ? y - x : x - y)
                 g = this.gcd(z, what)
 
-                if (g !== 1n) {
+                if (g !== BigInt(1)) {
                     break
                 }
 
-                if ((j & (j - 1n)) === 0n) {
+                if ((j & (j - BigInt(1))) === BigInt(0)) {
                     y = x
                 }
             }
@@ -61,12 +61,12 @@ class Factorizator {
      * @returns {BigInt}
      */
     static gcd(a, b) {
-        while (a !== 0n && b !== 0n) {
-            while ((b & 1n) === 0n) {
-                b >>= 1n
+        while (a !== BigInt(0) && b !== BigInt(0)) {
+            while ((b & BigInt(1)) === BigInt(0)) {
+                b >>= BigInt(1)
             }
-            while ((a & 1n) === 0n) {
-                a >>= 1n
+            while ((a & BigInt(1)) === BigInt(0)) {
+                a >>= BigInt(1)
             }
             if (a > b) {
                 a -= b
@@ -74,7 +74,7 @@ class Factorizator {
                 b -= a
             }
         }
-        return b === 0n ? a : b
+        return b === BigInt(0) ? a : b
     }
 
     /**

+ 0 - 1
gramjs/errors/Common.js

@@ -45,7 +45,6 @@ class InvalidChecksumError extends Error {
  */
 class InvalidBufferError extends Error {
     constructor(payload) {
-        console.log('payload is ', payload.toString('hex'))
         const code = -(struct.unpack('<i', payload)[0])
         if (payload.length === 4) {
             super(`Invalid response buffer (HTTP code ${code})`)

+ 2 - 6
gramjs/events/NewMessage.js

@@ -2,8 +2,6 @@ const { EventBuilder, EventCommon } = require('./common')
 const { types } = require('../tl')
 
 class NewMessage extends EventBuilder {
-
-
     constructor(args = {
         chats: null,
         func: null,
@@ -17,7 +15,7 @@ class NewMessage extends EventBuilder {
 
     async _resolve(client) {
         await super._resolve(client)
-        this.fromUsers = await _intoIdSet(client, this.fromUsers)
+        // this.fromUsers = await _intoIdSet(client, this.fromUsers)
     }
 
     build(update, others = null, thisId = null) {
@@ -27,7 +25,6 @@ class NewMessage extends EventBuilder {
                 return
             }
             event = new Event(update.message)
-
         } else if (update instanceof types.UpdateShortMessage) {
             event = new Event(new types.Message({
                 out: update.out,
@@ -75,7 +72,6 @@ class NewMessage extends EventBuilder {
             }
         }
         return event
-
     }
 
     filter(event) {
@@ -84,7 +80,6 @@ class NewMessage extends EventBuilder {
         }
         return event
     }
-
 }
 
 class Event extends EventCommon {
@@ -93,4 +88,5 @@ class Event extends EventCommon {
         this.message = message
     }
 }
+
 module.exports = NewMessage

+ 2 - 2
gramjs/events/common.js

@@ -1,7 +1,7 @@
 class EventBuilder {
     constructor(args = {
-            chats: null, blacklistChats: null, func: null,
-        },
+        chats: null, blacklistChats: null, func: null,
+    },
     ) {
         this.chats = args.chats
         this.blacklistChats = Boolean(args.blacklistChats)

+ 1 - 9
gramjs/extensions/BinaryReader.js

@@ -47,15 +47,7 @@ class BinaryReader {
      * @returns {bigint}
      */
     readLong(signed = true) {
-        let res
-        if (signed) {
-            res = this.stream.readBigInt64LE(this.offset)
-        } else {
-            res = this.stream.readBigUInt64LE(this.offset)
-        }
-        this.offset += 8
-
-        return res
+        return this.readLargeInt(8, signed)
     }
 
     /**

+ 117 - 0
gramjs/extensions/PromisedWebSockets.js

@@ -0,0 +1,117 @@
+const WebSocketClient = require('websocket').client
+const tunnel = require('tunnel')
+
+const closeError = new Error('WebSocket was closed')
+
+class PromisedWebSockets {
+    constructor(website) {
+        this.website = website
+        this.stream = Buffer.alloc(0)
+        this.connection = null
+        this.client = new WebSocketClient()
+
+        this.canRead = new Promise((resolve) => {
+            this.resolveRead = resolve
+        })
+        this.closed = false
+        this.client.on('close', function() {
+            this.resolveRead(false)
+            this.closed = true
+        }.bind(this))
+    }
+
+    async read(number) {
+        if (this.closed || !await this.canRead) {
+            console.log('wops ccouln\'t read')
+            throw closeError
+        }
+
+        const toReturn = this.stream.slice(0, number)
+        this.stream = this.stream.slice(number)
+        if (this.stream.length === 0) {
+            this.canRead = new Promise((resolve) => {
+                this.resolveRead = resolve
+            })
+        }
+
+        return toReturn
+    }
+
+    async readAll() {
+        if (this.closed || !await this.canRead) {
+            throw closeError
+        }
+        const toReturn = this.stream
+        this.stream = Buffer.alloc(0)
+        this.canRead = new Promise((resolve) => {
+            this.resolveRead = resolve
+        })
+        return toReturn
+    }
+
+    getWebSocketLink(ip, port) {
+        if (port === 443) {
+            return 'wss://' + ip
+        } else {
+            return 'ws://' + ip
+        }
+    }
+
+    async connect(ip, port) {
+        const tunnelingAgent = tunnel.httpOverHttp({
+            proxy: {
+                host: '127.0.0.1',
+                port: 8888,
+            },
+        })
+
+        const requestOptions = {
+            agent: tunnelingAgent,
+        }
+
+        this.website = this.getWebSocketLink(ip, port)
+        //this.website = 'ws://echo.websocket.org'
+        return new Promise(function(resolve, reject) {
+            this.client.on('connect', function(connection) {
+                this.connection = connection
+                this.receive()
+                resolve(connection)
+            }.bind(this))
+            this.client.on('connectFailed', function(error) {
+                reject(error)
+            })
+            this.client.connect(this.website, null, null, null, requestOptions)
+        }.bind(this))
+    }
+
+    send(data) {
+        if (this.closed) {
+            throw closeError
+        }
+        this.connection.send(data)
+    }
+
+    async close() {
+        console.log('something happened. clsong')
+        await this.connection.close()
+        this.resolveRead(false)
+        this.closed = true
+    }
+
+    async receive() {
+        this.connection.on('message', function(message) {
+            console.log(message)
+            let data
+            if (message.binaryData) {
+                data = Buffer.from(message.binaryData)
+            } else {
+                data = Buffer.from(message.utf8Data, 'utf-8')
+            }
+
+            this.stream = Buffer.concat([this.stream, data])
+            this.resolveRead(true)
+        }.bind(this))
+    }
+}
+
+module.exports = PromisedWebSockets

+ 5 - 3
gramjs/index.js

@@ -1,4 +1,6 @@
+//require('regenerator-runtime/runtime')
+//require('regenerator-runtime')
 const TelegramClient = require('./client/TelegramClient')
-module.exports = {
-    TelegramClient,
-}
+const StringSession = require('./sessions/StringSession')
+
+module.exports = { TelegramClient, StringSession }

+ 3 - 3
gramjs/network/MTProtoPlainSender.js

@@ -39,11 +39,11 @@ class MTProtoPlainSender {
         }
         const reader = new BinaryReader(body)
         const authKeyId = reader.readLong()
-        if (authKeyId !== 0n) {
+        if (authKeyId !== BigInt(0)) {
             throw new Error('Bad authKeyId')
         }
         msgId = reader.readLong()
-        if (msgId === 0n) {
+        if (msgId === BigInt(0)) {
             throw new Error('Bad msgId')
         }
         /** ^ We should make sure that the read ``msg_id`` is greater
@@ -77,7 +77,7 @@ class MTProtoPlainSender {
             (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 + BigInt(4)
         }
         this._lastMsgId = newMsgId
         return BigInt(newMsgId)

+ 3 - 6
gramjs/network/MTProtoSender.js

@@ -8,7 +8,7 @@ const MessageContainer = require('../tl/core/MessageContainer')
 const GZIPPacked = require('../tl/core/GZIPPacked')
 const RequestState = require('./RequestState')
 const format = require('string-format')
-const { MsgsAck, File, MsgsStateInfo,Pong } = require('../tl/types')
+const { MsgsAck, File, MsgsStateInfo, Pong } = require('../tl/types')
 const MessagePacker = require('../extensions/MessagePacker')
 const BinaryReader = require('../extensions/BinaryReader')
 const {
@@ -25,10 +25,8 @@ const {
 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 { tlobjects } = require("../gramjs/tl/alltlobjects");
 format.extend(String.prototype, {})
@@ -219,6 +217,7 @@ class MTProtoSender {
      * @private
      */
     async _connect() {
+
         this._log.info('Connecting to {0}...'.replace('{0}', this._connection))
         await this._connection.connect()
         this._log.debug('Connection success!')
@@ -323,7 +322,7 @@ class MTProtoSender {
                 body = await this._connection.recv()
             } catch (e) {
                 // this._log.info('Connection closed while receiving data');
-                this._log.debug('Connection closed while receiving data')
+                this._log.warn('Connection closed while receiving data')
                 return
             }
             try {
@@ -712,9 +711,7 @@ class MTProtoSender {
         if (this._user_connected && !this._reconnecting) {
             this._reconnecting = true
             this._reconnect(e)
-
         }
-
     }
 
     async _reconnect(e) {

+ 4 - 3
gramjs/network/MTProtoState.js

@@ -126,6 +126,7 @@ class MTProtoState {
      * @param body
      */
     async decryptMessageData(body) {
+        console.log(body)
         if (body.length < 8) {
             throw new InvalidBufferError(body)
         }
@@ -177,9 +178,9 @@ class MTProtoState {
     _getNewMsgId() {
         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)
+        let newMsgId = (BigInt(Math.floor(now)) << BigInt(2)) | (BigInt(nanoseconds) << BigInt(2))
         if (this._lastMsgId >= newMsgId) {
-            newMsgId = this._lastMsgId + 4n
+            newMsgId = this._lastMsgId + BigInt(4)
         }
         this._lastMsgId = newMsgId
 
@@ -195,7 +196,7 @@ class MTProtoState {
         const bad = this._getNewMsgId()
         const old = this.timeOffset
         const now = Math.floor(new Date().getTime() / 1000)
-        const correct = correctMsgId >> 32n
+        const correct = correctMsgId >> BigInt(2)
         this.timeOffset = correct - now
 
         if (this.timeOffset !== old) {

+ 28 - 11
gramjs/network/connection/Connection.js

@@ -1,5 +1,4 @@
-const { PromiseSocket } = require('promise-socket')
-const { Socket } = require('net')
+const PromisedWebSockets = require('../../extensions/PromisedWebSockets')
 const AsyncQueue = require('../../extensions/AsyncQueue')
 
 /**
@@ -30,15 +29,16 @@ class Connection {
         this._obfuscation = null // TcpObfuscated and MTProxy
         this._sendArray = new AsyncQueue()
         this._recvArray = new AsyncQueue()
-        this.socket = new PromiseSocket(new Socket())
+        this.socket = new PromisedWebSockets()
     }
 
     async _connect() {
-        await this.socket.connect(this._port, this._ip)
-
+        this._log.debug('Connecting')
+        await this.socket.connect(this._ip, this._port)
+        this._log.debug('Finished connecting')
         // await this.socket.connect({host: this._ip, port: this._port});
         this._codec = new this.PacketCodecClass(this)
-        this._initConn()
+        await this._initConn()
     }
 
     async connect() {
@@ -52,7 +52,7 @@ class Connection {
 
     async disconnect() {
         this._connected = false
-        await this.socket.end()
+        await this.socket.close()
     }
 
     async send(data) {
@@ -65,7 +65,6 @@ class Connection {
     async recv() {
         while (this._connected) {
             const result = await this._recvArray.pop()
-
             // null = sentinel value = keep trying
             if (result) {
                 return result
@@ -92,7 +91,6 @@ class Connection {
             try {
                 data = await this._recv()
                 if (!data) {
-                    console.log('ended')
                     return
                 }
             } catch (e) {
@@ -106,13 +104,13 @@ class Connection {
 
     async _initConn() {
         if (this._codec.tag) {
-            await this.socket.write(this._codec.tag)
+            await this.socket.send(this._codec.tag)
         }
     }
 
     async _send(data) {
         const encodedPacket = this._codec.encodePacket(data)
-        await this.socket.write(encodedPacket)
+        await this.socket.send(encodedPacket)
     }
 
     async _recv() {
@@ -124,6 +122,24 @@ class Connection {
     }
 }
 
+class ObfuscatedConnection extends Connection {
+    ObfuscatedIO = null
+
+    async _initConn() {
+        this._obfuscation = new this.ObfuscatedIO(this)
+        this.socket.send(this._obfuscation.header)
+    }
+
+    _send(data) {
+        this._obfuscation.write(this._codec.encodePacket(data))
+    }
+
+
+    async _recv() {
+        return await this._codec.readPacket(this._obfuscation)
+    }
+}
+
 class PacketCodec {
     constructor(connection) {
         this._conn = connection
@@ -144,4 +160,5 @@ class PacketCodec {
 module.exports = {
     Connection,
     PacketCodec,
+    ObfuscatedConnection,
 }

+ 49 - 0
gramjs/network/connection/TCPAbridged.js

@@ -0,0 +1,49 @@
+const struct = require('python-struct')
+const { readBufferFromBigInt } = require('../../Helpers')
+const { Connection, PacketCodec } = require('./Connection')
+
+class AbridgedPacketCodec extends PacketCodec {
+    static tag = Buffer.from('ef', 'hex')
+    static obfuscateTag = Buffer.from('efefefef', 'hex')
+
+    constructor(props) {
+        super(props)
+        this.tag = AbridgedPacketCodec.tag
+        this.obfuscateTag = AbridgedPacketCodec.obfuscateTag
+    }
+
+    encodePacket(data) {
+        let length = data.length >> 2
+        if (length < 127) {
+            length = struct.pack('B', length)
+        } else {
+            length = Buffer.from('7f', 'hex') + readBufferFromBigInt(BigInt(length), 3)
+        }
+        return Buffer.concat([length, data])
+    }
+
+    async readPacket(reader) {
+        const readData = await reader.read(1)
+        let length = struct.unpack('<B', readData)[0]
+        console.log(length)
+        if (length > 127) {
+            length = struct.unpack(
+                '<i', Buffer.concat([await reader.read(3), Buffer.alloc(1)]))[0]
+        }
+        return await reader.read(length << 2)
+    }
+}
+
+/**
+ * This is the mode with the lowest overhead, as it will
+ * only require 1 byte if the packet length is less than
+ * 508 bytes (127 << 2, which is very common).
+ */
+class ConnectionTCPAbridged extends Connection {
+    packetCode = AbridgedPacketCodec
+}
+
+module.exports = {
+    ConnectionTCPAbridged,
+    AbridgedPacketCodec,
+}

+ 1 - 2
gramjs/network/connection/TCPFull.js

@@ -21,13 +21,12 @@ class FullPacketCodec extends PacketCodec {
 
     /**
      *
-     * @param reader {Socket}
+     * @param reader {PromisedWebSockets}
      * @returns {Promise<*>}
      */
     async readPacket(reader) {
         const packetLenSeq = await reader.read(8) // 4 and 4
         // process.exit(0);
-
         if (packetLenSeq === undefined) {
             return false
         }

+ 75 - 0
gramjs/network/connection/TCPObfuscated.js

@@ -0,0 +1,75 @@
+const { generateRandomBytes } = require('../../Helpers')
+const { ObfuscatedConnection } = require('./Connection')
+const { AbridgedPacketCodec } = require('./TCPAbridged')
+const AESModeCTR = require('../../crypto/AESCTR')
+
+class ObfuscatedIO {
+    header = null
+
+    constructor(connection) {
+        this.connection = connection.socket
+        const res = this.initHeader(connection.PacketCodecClass)
+        this.header = res.random
+        this._encrypt = res.encryptor
+        this._decrypt = res.decryptor
+    }
+
+    initHeader(packetCodec) {
+        // Obfuscated messages secrets cannot start with any of these
+        const keywords = [Buffer.from('50567247', 'hex'), Buffer.from('474554', 'hex'),
+            Buffer.from('504f5354', 'hex'), Buffer.from('eeeeeeee', 'hex')]
+        let random
+
+        // eslint-disable-next-line no-constant-condition
+        while (true) {
+            random = generateRandomBytes(64)
+            if (random[0] !== 0xef && !(random.slice(4, 8).equals(Buffer.alloc(4)))) {
+                let ok = true
+                for (const key of keywords) {
+                    if (key.equals(random.slice(0, 4))) {
+                        ok = false
+                        break
+                    }
+                }
+                if (ok) {
+                    break
+                }
+            }
+        }
+        random = random.toJSON().data
+        const randomReversed = Buffer.from(random.slice(7, 55)).reverse()
+
+        // Encryption has "continuous buffer" enabled
+        const encryptKey = Buffer.from(random.slice(8, 40))
+        const encryptIv = Buffer.from(random.slice(40, 56))
+        const decryptKey = Buffer.from(randomReversed.slice(0, 32))
+        const decryptIv = Buffer.from(randomReversed.slice(32, 48))
+        const encryptor = new AESModeCTR(encryptKey, encryptIv)
+        const decryptor = new AESModeCTR(decryptKey, decryptIv)
+        random = Buffer.concat([
+            Buffer.from(random.slice(0, 56)), packetCodec.obfuscateTag, Buffer.from(random.slice(60)),
+        ])
+        random = Buffer.concat([
+            random.slice(0, 56), encryptor.encrypt(random).slice(56, 64), random.slice(64),
+        ])
+        return { random, encryptor, decryptor }
+    }
+
+    async read(n) {
+        const data = await this.connection.read(n)
+        return this._decrypt.encrypt(data)
+    }
+
+    write(data) {
+        this.connection.send(this._encrypt.encrypt(data))
+    }
+}
+
+class ConnectionTCPObfuscated extends ObfuscatedConnection {
+    ObfuscatedIO = ObfuscatedIO
+    PacketCodecClass = AbridgedPacketCodec
+}
+
+module.exports = {
+    ConnectionTCPObfuscated,
+}

+ 0 - 4
gramjs/sessions/Abstract.js

@@ -113,7 +113,6 @@ class Session {
      */
     save() {
         throw new Error('Not Implemented')
-
     }
 
     /**
@@ -122,7 +121,6 @@ class Session {
      */
     delete() {
         throw new Error('Not Implemented')
-
     }
 
     /**
@@ -130,7 +128,6 @@ class Session {
      */
     listSessions() {
         throw new Error('Not Implemented')
-
     }
 
     /**
@@ -150,7 +147,6 @@ class Session {
      */
     getInputEntity(key) {
         throw new Error('Not Implemented')
-
     }
 }
 

+ 7 - 8
gramjs/sessions/JSONSession.js

@@ -24,9 +24,9 @@ class Session {
         this.authKey = undefined
         this.id = generateRandomLong(false)
         this.sequence = 0
-        this.salt = 0n // Unsigned long
-        this.timeOffset = 0n
-        this.lastMessageId = 0n
+        this.salt = BigInt(0) // Unsigned long
+        this.timeOffset = BigInt(0)
+        this.lastMessageId = BigInt(0)
         this.user = undefined
         this._files = {}
         this._entities = new Set()
@@ -193,12 +193,12 @@ class Session {
     getNewMsgId() {
         const msTime = new Date().getTime()
         let newMessageId =
-            (BigInt(BigInt(Math.floor(msTime / 1000)) + this.timeOffset) << 32n) |
-            (BigInt(msTime % 1000) << 22n) |
-            (BigInt(getRandomInt(0, 524288)) << 2n) // 2^19
+            (BigInt(BigInt(Math.floor(msTime / 1000)) + this.timeOffset) << BigInt(32)) |
+            (BigInt(msTime % 1000) << BigInt(22)) |
+            (BigInt(getRandomInt(0, 524288)) << BigInt(2)) // 2^19
 
         if (this.lastMessageId >= newMessageId) {
-            newMessageId = this.lastMessageId + 4n
+            newMessageId = this.lastMessageId + BigInt(4)
         }
         this.lastMessageId = newMessageId
         return newMessageId
@@ -315,7 +315,6 @@ class Session {
             throw new Error('Could not find input entity with key ' + key)
         }
     }
-
 }
 
 module.exports = Session

+ 1 - 1
gramjs/sessions/Memory.js

@@ -249,4 +249,4 @@ class MemorySession extends Session {
     }
 }
 
-module.exports = MemorySession
+module.exports = MemorySession

+ 3 - 0
gramjs/sessions/PouchSession.js

@@ -0,0 +1,3 @@
+const EXTENSION = '.session'
+const CURRENT_VERSION = 1
+

+ 4 - 3
gramjs/sessions/StringSession.js

@@ -30,9 +30,9 @@ class StringSession extends MemorySession {
             const ipLen = session.length === 352 ? 4 : 16
             const r = StringSession.decode(session)
             const reader = new BinaryReader(r)
-            this._dcId = reader.read(1).readUInt8()
+            this._dcId = reader.read(1).readUInt8(0)
             const ip = reader.read(ipLen)
-            this._port = reader.read(2).readInt16BE()
+            this._port = reader.read(2).readInt16BE(0)
             const key = reader.read(-1)
             this._serverAddress = ip.readUInt8(0) + '.' +
                 ip.readUInt8(1) + '.' + ip.readUInt8(2) +
@@ -67,7 +67,8 @@ class StringSession extends MemorySession {
         const dcBuffer = Buffer.from([this.dcId])
         const ipBuffer = Buffer.alloc(4)
         const portBuffer = Buffer.alloc(2)
-        portBuffer.writeInt16BE(this.port)
+
+        portBuffer.writeInt16BE(this.port, 0)
         for (let i = 0; i < ip.length; i++) {
             ipBuffer.writeUInt8(parseInt(ip[i]), i)
         }

Datei-Diff unterdrückt, da er zu groß ist
+ 2231 - 309
package-lock.json


+ 22 - 3
package.json

@@ -10,27 +10,46 @@
     "type": "git",
     "url": "git+https://github.com/gram-js/gramjs.git"
   },
+  "browser": {
+    "fs": false
+  },
   "license": "MIT",
   "bugs": {
     "url": "https://github.com/gram-js/gramjs/issues"
   },
   "homepage": "https://github.com/gram-js/gramjs#readme",
   "dependencies": {
+    "@babel/core": "^7.7.0",
+    "@babel/plugin-proposal-class-properties": "^7.7.0",
+    "@babel/preset-env": "^7.7.0",
     "aes-js": "^3.1.2",
+    "babel-loader": "^8.0.6",
+    "babel-register": "^6.26.0",
     "crc": "^3.8.0",
     "csv-parse": "^4.4.6",
     "fast-csv": "^3.4.0",
     "glob": "^7.1.4",
-    "log4js": "^5.2.2",
+    "loglevel": "^1.6.4",
+    "net": "^1.0.2",
     "node-gzip": "^1.1.2",
     "node-rsa": "^1.0.6",
     "promise-socket": "^6.0.2",
     "python-struct": "^1.1.1",
-    "string-format": "^2.0.0"
+    "regenerator-runtime": "^0.13.3",
+    "stack-trace": "0.0.10",
+    "string-format": "^2.0.0",
+    "tunnel": "0.0.6",
+    "websocket": "^1.0.30"
   },
   "devDependencies": {
+    "@babel/plugin-transform-async-to-generator": "^7.7.0",
     "babel-eslint": "^10.0.3",
     "eslint": "^6.5.1",
-    "eslint-config-google": "^0.14.0"
+    "eslint-config-google": "^0.14.0",
+    "log4js": "^5.3.0",
+    "loglevelnext": "^3.0.1",
+    "webpack": "^4.41.2",
+    "webpack-cli": "^3.3.10",
+    "websocket-as-promised": "^0.10.1"
   }
 }

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.