From e0999ad4d0c98a98af628e58da36288a0a5b5dde Mon Sep 17 00:00:00 2001 From: Eduard Kuzmenko Date: Fri, 12 Feb 2021 19:24:20 +0400 Subject: [PATCH] no comments --- package.json | 44 +++++------ src/components/chat/bubbleGroups.ts | 50 ++++++------ src/components/chat/bubbles.ts | 29 ++----- src/components/chat/contextMenu.ts | 2 +- src/lib/appManagers/appMessagesManager.ts | 2 +- src/lib/appManagers/appStateManager.ts | 2 +- src/lib/appManagers/appUsersManager.ts | 6 +- src/lib/crypto/crypto_utils.ts | 2 +- src/lib/mtproto/apiManager.ts | 8 +- src/lib/mtproto/mtproto_config.ts | 30 +++++++ src/lib/mtproto/mtprotoworker.ts | 2 +- src/lib/mtproto/networker.ts | 53 ++++++++----- src/lib/mtproto/tl_utils.ts | 4 +- src/lib/mtproto/transports/intermediate.ts | 4 +- src/lib/mtproto/transports/obfuscation.ts | 4 +- src/lib/mtproto/transports/websocket.ts | 4 + t.py | 92 +++++++++++++++++++++- t2.py | 83 +++++++++++++++++++ webpack.common.js | 6 +- 19 files changed, 316 insertions(+), 111 deletions(-) create mode 100644 t2.py diff --git a/package.json b/package.json index ee093be5..3ea32d75 100644 --- a/package.json +++ b/package.json @@ -19,64 +19,64 @@ "license": "ISC", "dependencies": { "jsbn": "^1.1.0", - "webpack-dev-server": "^3.11.0" + "webpack-dev-server": "^3.11.2" }, "devDependencies": { - "@babel/cli": "^7.12.1", - "@babel/core": "^7.12.3", - "@babel/plugin-proposal-class-properties": "^7.12.1", - "@babel/plugin-transform-typescript": "^7.12.1", + "@babel/cli": "^7.12.13", + "@babel/core": "^7.12.13", + "@babel/plugin-proposal-class-properties": "^7.12.13", + "@babel/plugin-transform-typescript": "^7.12.13", "@babel/polyfill": "^7.12.1", - "@babel/preset-env": "^7.12.1", + "@babel/preset-env": "^7.12.13", "@babel/preset-es2015": "^7.0.0-beta.53", - "@babel/preset-typescript": "^7.12.1", + "@babel/preset-typescript": "^7.12.13", "@cryptography/aes": "^0.1.1", "@cryptography/sha1": "^0.1.0", "@cryptography/sha256": "^0.2.0", - "@peculiar/webcrypto": "^1.1.3", + "@peculiar/webcrypto": "^1.1.6", "@types/aes-js": "^3.1.1", "@types/chrome": "0.0.91", "@types/jest": "^24.9.1", "@types/serviceworker-webpack-plugin": "^1.0.1", "aes-js": "^3.1.2", - "autoprefixer": "^9.8.0", + "autoprefixer": "^9.8.6", "babel-jest": "^24.9.0", - "babel-loader": "^8.1.0", + "babel-loader": "^8.2.2", "babel-preset-es2015": "^6.24.1", "compression": "^1.7.4", "compression-webpack-plugin": "^3.1.0", - "core-js": "^3.6.5", - "css-loader": "^3.5.3", + "core-js": "^3.8.3", + "css-loader": "^3.6.0", "express": "^4.17.1", - "fast-png": "^5.0.2", + "fast-png": "^5.0.3", "handlebars": "^4.7.6", "handlebars-loader": "^1.7.1", "html-webpack-plugin": "^3.2.0", "ifdef-loader": "^2.1.5", "install": "^0.13.0", "jest": "^24.9.0", - "media-query-plugin": "^1.3.1", + "media-query-plugin": "^1.4.0", "mini-css-extract-plugin": "^0.9.0", "node-sass": "^4.14.1", - "npm": "^6.14.10", + "npm": "^6.14.11", "on-build-webpack": "^0.1.0", - "optimize-css-assets-webpack-plugin": "^5.0.3", + "optimize-css-assets-webpack-plugin": "^5.0.4", "pako": "^1.0.11", - "postcss": "^7.0.32", + "postcss": "^7.0.35", "postcss-loader": "^3.0.0", "postcss-preset-env": "^6.7.0", - "qr-code-styling": "^1.0.1", + "qr-code-styling": "^1.3.4", "resolve-url-loader": "^3.1.2", "sass-loader": "^8.0.2", "serviceworker-webpack-plugin": "^1.0.1", - "style-loader": "^1.2.1", - "terser-webpack-plugin": "^3.0.2", + "style-loader": "^1.3.0", + "terser-webpack-plugin": "^3.1.0", "ts-jest": "^24.3.0", "ts-loader": "^6.2.2", "typescript": "^3.9.7", "url-loader": "^2.3.0", - "webpack": "^4.43.0", - "webpack-cli": "^3.3.11", + "webpack": "^4.46.0", + "webpack-cli": "^3.3.12", "webpack-merge": "^4.2.2", "worker-loader": "^2.0.0" } diff --git a/src/components/chat/bubbleGroups.ts b/src/components/chat/bubbleGroups.ts index 20542ba4..8ec1fe7a 100644 --- a/src/components/chat/bubbleGroups.ts +++ b/src/components/chat/bubbleGroups.ts @@ -1,22 +1,23 @@ import rootScope from "../../lib/rootScope"; -import { generatePathData } from "../../helpers/dom"; +//import { generatePathData } from "../../helpers/dom"; import { MyMessage } from "../../lib/appManagers/appMessagesManager"; import Chat from "./chat"; -type Group = {bubble: HTMLDivElement, mid: number, timestamp: number}[]; +type Group = {bubble: HTMLElement, mid: number, timestamp: number}[]; type BubbleGroup = {timestamp: number, fromId: number, mid: number, group: Group}; export default class BubbleGroups { private bubbles: Array = []; // map to group + private detailsMap: Map = new Map(); private groups: Array = []; - //updateRAFs: Map = new Map(); + //updateRAFs: Map = new Map(); private newGroupDiff = 121; // * 121 in scheduled messages constructor(private chat: Chat) { } - removeBubble(bubble: HTMLDivElement, mid: number) { - const details = this.bubbles.findAndSplice(g => g.mid === mid); + removeBubble(bubble: HTMLElement) { + const details = this.detailsMap.get(bubble); if(details && details.group.length) { details.group.findAndSplice(d => d.bubble === bubble); if(!details.group.length) { @@ -27,7 +28,7 @@ export default class BubbleGroups { } } - addBubble(bubble: HTMLDivElement, message: MyMessage, reverse: boolean) { + addBubble(bubble: HTMLElement, message: MyMessage, reverse: boolean) { //return; const timestamp = message.date; @@ -41,7 +42,7 @@ export default class BubbleGroups { } // try to find added - //this.removeBubble(message.mid); + this.removeBubble(bubble); const insertObject = {bubble, mid, timestamp}; if(this.bubbles.length) { @@ -105,28 +106,24 @@ export default class BubbleGroups { //console.log('[BUBBLE]: addBubble', bubble, message.mid, fromId, reverse, group); - if(mid > 0) { - let insertIndex = 0; - for(; insertIndex < this.bubbles.length; ++insertIndex) { - if(this.bubbles[insertIndex].mid < mid) { - break; - } + const bubbleGroup = {timestamp, fromId, mid: message.mid, group}; + let insertIndex = 0; + for(; insertIndex < this.bubbles.length; ++insertIndex) { + if(this.bubbles[insertIndex].mid < mid) { + break; } - - this.bubbles.splice(insertIndex, 0, {timestamp, fromId, mid: message.mid, group}); - } else { - this.bubbles.unshift({timestamp, fromId, mid: message.mid, group}); } - //this.bubbles.push({timestamp, fromId, mid: message.mid, group}); + this.bubbles.splice(insertIndex, 0, {timestamp, fromId, mid: message.mid, group}); this.updateGroup(group); + + this.detailsMap.set(bubble, bubbleGroup); } - setClipIfNeeded(bubble: HTMLDivElement, remove = false) { + /* setClipIfNeeded(bubble: HTMLDivElement, remove = false) { //console.log('setClipIfNeeded', bubble, remove); const className = bubble.className; - if(className.includes('is-message-empty')/* && !className.includes('is-reply') */ - && (className.includes('photo') || className.includes('video'))) { + if(className.includes('is-message-empty') && (className.includes('photo') || className.includes('video'))) { let container = bubble.querySelector('.bubble__media-container') as SVGSVGElement; //console.log('setClipIfNeeded', bubble, remove, container); if(!container) return; @@ -171,7 +168,7 @@ export default class BubbleGroups { }); } catch(err) {} } - } + } */ updateGroup(group: Group) { /* if(this.updateRAFs.has(group)) { @@ -192,25 +189,25 @@ export default class BubbleGroups { if(group.length === 1) { first.classList.add('is-group-first', 'is-group-last'); - this.setClipIfNeeded(first); + //this.setClipIfNeeded(first); return; } else { first.classList.remove('is-group-last'); first.classList.add('is-group-first'); - this.setClipIfNeeded(first, true); + //this.setClipIfNeeded(first, true); } const length = group.length - 1; for(let i = 1; i < length; ++i) { const bubble = group[i].bubble; bubble.classList.remove('is-group-last', 'is-group-first'); - this.setClipIfNeeded(bubble, true); + //this.setClipIfNeeded(bubble, true); } const last = group[group.length - 1].bubble; last.classList.remove('is-group-first'); last.classList.add('is-group-last'); - this.setClipIfNeeded(last); + //this.setClipIfNeeded(last); //})); } @@ -224,6 +221,7 @@ export default class BubbleGroups { cleanup() { this.bubbles = []; this.groups = []; + this.detailsMap.clear(); /* for(let value of this.updateRAFs.values()) { window.cancelAnimationFrame(value); } diff --git a/src/components/chat/bubbles.ts b/src/components/chat/bubbles.ts index 73c00a53..29fd50f9 100644 --- a/src/components/chat/bubbles.ts +++ b/src/components/chat/bubbles.ts @@ -152,12 +152,9 @@ export default class ChatBubbles { const message = this.chat.getMessage(mid); //bubble.remove(); - this.bubbleGroups.removeBubble(bubble, message.mid); this.setBubblePosition(bubble, message, false); //this.log('history_update', this.bubbles[mid], mid, message); - this.bubbleGroups.addBubble(bubble, message, false); - if(this.scrollingToNewBubble) { this.scrollToNewLastBubble(); } @@ -268,8 +265,6 @@ export default class ChatBubbles { //}); bubble.dataset.mid = '' + mid; - - this.bubbleGroups.removeBubble(bubble, tempId); } if(this.unreadOut.has(tempId)) { @@ -423,7 +418,7 @@ export default class ChatBubbles { const msgIdsByPeer = e; if(!(this.peerId in msgIdsByPeer)) return; - const msgIds = msgIdsByPeer[this.peerId]; + const msgIds = (msgIdsByPeer[this.peerId] as number[]).slice().sort((a, b) => b - a); this.renderNewMessagesByIds(msgIds); }); @@ -1147,7 +1142,7 @@ export default class ChatBubbles { this.firstUnreadBubble = null; } - this.bubbleGroups.removeBubble(bubble, mid); + this.bubbleGroups.removeBubble(bubble); if(this.unreadedObserver) { this.unreadedObserver.unobserve(bubble); } @@ -1691,6 +1686,8 @@ export default class ChatBubbles { dateMessage.container.append(bubble); } } + + this.bubbleGroups.addBubble(bubble, message, reverse); } // * will change .cleaned in cleanup() and new instance will be created @@ -1779,16 +1776,8 @@ export default class ChatBubbles { bubble.remove(); // * for positionElementByIndex } */ - if(!sameMid || updatePosition) { - this.bubbleGroups.removeBubble(bubble, originalMid); - } - if(!sameMid) { delete this.bubbles[originalMid]; - - if(!updatePosition) { - this.bubbleGroups.addBubble(bubble, message, reverse); - } } //bubble.innerHTML = ''; @@ -1815,9 +1804,7 @@ export default class ChatBubbles { if(updatePosition) { this.renderMessagesQueue(message, bubble, reverse, loadPromises); - if(!message.pFlags.is_single) { // * Ignore 'Discussion started' - this.bubbleGroups.addBubble(bubble, message, reverse); - } else { + if(message.pFlags.is_single) { // * Ignore 'Discussion started' bubble.classList.add('is-group-last'); } } @@ -2452,13 +2439,7 @@ export default class ChatBubbles { bubble.classList.add(isOut ? 'is-out' : 'is-in'); if(updatePosition) { - if(!isThreadStarter) { - this.bubbleGroups.addBubble(bubble, message, reverse); - } - this.renderMessagesQueue(message, bubble, reverse, loadPromises); - } else { - this.bubbleGroups.updateGroupByMessageId(message.mid); } if(withReplies) { diff --git a/src/components/chat/contextMenu.ts b/src/components/chat/contextMenu.ts index 2db68aa6..90b5423c 100644 --- a/src/components/chat/contextMenu.ts +++ b/src/components/chat/contextMenu.ts @@ -215,7 +215,7 @@ export default class ChatContextMenu { icon: 'link', text: 'Copy Link', onClick: this.onCopyLinkClick, - verify: () => this.appPeersManager.isChannel(this.peerId) + verify: () => this.appPeersManager.isChannel(this.peerId) && !this.message.pFlags.is_outgoing }, { icon: 'pin', text: 'Pin', diff --git a/src/lib/appManagers/appMessagesManager.ts b/src/lib/appManagers/appMessagesManager.ts index b6fe9d0a..c5347a72 100644 --- a/src/lib/appManagers/appMessagesManager.ts +++ b/src/lib/appManagers/appMessagesManager.ts @@ -3313,7 +3313,7 @@ export class AppMessagesManager { } as any, id: this.generateMessageId(message.id, true), date: message.date, - from_id: message.from_id, + from_id: {_: 'peerUser', user_id: 0}/* message.from_id */, peer_id: message.peer_id, action: { _: 'messageActionCustomAction', diff --git a/src/lib/appManagers/appStateManager.ts b/src/lib/appManagers/appStateManager.ts index b59eb4a5..705180a4 100644 --- a/src/lib/appManagers/appStateManager.ts +++ b/src/lib/appManagers/appStateManager.ts @@ -156,7 +156,7 @@ export class AppStateManager extends EventListenerBase<{ if(state) { if(state.version !== STATE_VERSION) { state = copy(STATE_INIT); - } else if((state.stateCreatedTime + REFRESH_EVERY) < time/* && false */) { + } else if((state.stateCreatedTime + REFRESH_EVERY) < time/* || true *//* && false */) { if(DEBUG) { this.log('will refresh state', state.stateCreatedTime, time); } diff --git a/src/lib/appManagers/appUsersManager.ts b/src/lib/appManagers/appUsersManager.ts index 6a16820a..db75ad05 100644 --- a/src/lib/appManagers/appUsersManager.ts +++ b/src/lib/appManagers/appUsersManager.ts @@ -118,7 +118,9 @@ export class AppUsersManager { this.pushContact(userId); }); - this.contactsFillPromise = Promise.resolve(this.contactsList); + if(this.contactsList.size) { + this.contactsFillPromise = Promise.resolve(this.contactsList); + } } }); } @@ -605,7 +607,7 @@ export class AppUsersManager { return apiManager.invokeApi('contacts.getTopPeers', { correspondents: true, offset: 0, - limit: 30, + limit: 15, hash: 0, }).then((result) => { let peerIds: number[] = []; diff --git a/src/lib/crypto/crypto_utils.ts b/src/lib/crypto/crypto_utils.ts index 17b556e2..0195cf3f 100644 --- a/src/lib/crypto/crypto_utils.ts +++ b/src/lib/crypto/crypto_utils.ts @@ -16,7 +16,7 @@ import { addPadding, bytesFromBigInt } from '../mtproto/bin_utils'; import { bytesToWordss, bytesFromWordss, bytesToHex, bytesFromHex } from '../../helpers/bytes'; import { nextRandomInt } from '../../helpers/random'; -export function longToBytes(sLong: string) { +export function longToBytes(sLong: string): Array { /* let perf = performance.now(); for(let i = 0; i < 1000000; ++i) { bytesFromWords({words: longToInts(sLong), sigBytes: 8}).reverse(); diff --git a/src/lib/mtproto/apiManager.ts b/src/lib/mtproto/apiManager.ts index b0c8a17f..0c0742f1 100644 --- a/src/lib/mtproto/apiManager.ts +++ b/src/lib/mtproto/apiManager.ts @@ -157,12 +157,12 @@ export class ApiManager { // mtpGetNetworker public getNetworker(dcId: number, options: InvokeApiOptions = {}): Promise { - const connectionType: ConnectionType = options.fileDownload ? 'download' : (options.fileUpload ? 'upload' : 'client'); - //const connectionType: ConnectionType = 'client'; + //const connectionType: ConnectionType = options.fileDownload ? 'download' : (options.fileUpload ? 'upload' : 'client'); + const connectionType: ConnectionType = 'client'; /// #if MTPROTO_HTTP_UPLOAD // @ts-ignore - const transportType: TransportType = connectionType === 'upload' && isSafari ? 'https' : 'websocket'; + const transportType: TransportType = connectionType === 'upload' && isSafari && false ? 'https' : 'websocket'; //const transportType: TransportType = connectionType !== 'client' ? 'https' : 'websocket'; /// #else // @ts-ignore @@ -183,7 +183,7 @@ export class ApiManager { } const networkers = cache[dcId]; - if(networkers.length >= /* 1 */(connectionType === 'client' || transportType === 'https' ? 1 : (connectionType === 'download' ? 3 : 3))) { + if(networkers.length >= /* 1 */(connectionType === 'client' || transportType === 'https' ? 1 : (connectionType === 'download' ? 3 : 1))) { let i = networkers.length - 1, found = false; for(; i >= 0; --i) { if(networkers[i].isOnline) { diff --git a/src/lib/mtproto/mtproto_config.ts b/src/lib/mtproto/mtproto_config.ts index 3b20211b..54476c91 100644 --- a/src/lib/mtproto/mtproto_config.ts +++ b/src/lib/mtproto/mtproto_config.ts @@ -34,3 +34,33 @@ export const Database = { export const DEBUG = process.env.NODE_ENV !== 'production' || Modes.debug; export const MOUNT_CLASS_TO: any = DEBUG ? (typeof(window) !== 'undefined' ? window : self) : null; + +export const superDebug = (object: any, key: string) => { + var d = object[key]; + var beforeStr = '', afterStr = ''; + for(var r of d) { + beforeStr += r.before.hex + '\n'; + afterStr += r.after.hex + '\n'; + } + + beforeStr = beforeStr.trim(); + afterStr = afterStr.trim(); + //var beforeStr = d.map(r => r.before.hex).join('\n'); + //var afterStr = d.map(r => r.after.hex).join('\n'); + + var dada = (name: string, str: string) => { + var a = document.createElement('a'); + a.target = '_blank'; + a.download = name + '.txt'; + a.href = URL.createObjectURL(new Blob([str], { + type: 'text/plain' + })); + document.body.append(a); + a.click(); + }; + + dada(key + '_' + 'before', beforeStr); + dada(key + '_' + 'after', afterStr); +} + +MOUNT_CLASS_TO && (MOUNT_CLASS_TO.superDebug = superDebug); diff --git a/src/lib/mtproto/mtprotoworker.ts b/src/lib/mtproto/mtprotoworker.ts index a23bb281..e4e53c28 100644 --- a/src/lib/mtproto/mtprotoworker.ts +++ b/src/lib/mtproto/mtprotoworker.ts @@ -124,7 +124,7 @@ export class ApiManagerProxy extends CryptoWorkerMethods { //const worker = window; worker.addEventListener('message', (e) => { if(!this.worker) { - this.worker = worker; + this.worker = worker as any; this.log('set webWorker'); if(USE_WORKER_AS_WORKER) { diff --git a/src/lib/mtproto/networker.ts b/src/lib/mtproto/networker.ts index 35710a77..e6518a0c 100644 --- a/src/lib/mtproto/networker.ts +++ b/src/lib/mtproto/networker.ts @@ -100,8 +100,9 @@ export default class MTPNetworker { /// #endif private seqNo: number = 0; - private prevSessionId: Array = []; - private sessionId: Array = []; + private prevSessionId: Uint8Array; + private sessionId: Uint8Array; + private serverSalt: Uint8Array; private lastResendReq: { req_msg_id: string, @@ -119,9 +120,12 @@ export default class MTPNetworker { private tt = 0; //public onConnectionStatusChange: (online: boolean) => void; + private debugRequests: Array<{before: Uint8Array, after: Uint8Array}> = []; + constructor(public dcId: number, private authKey: number[], private authKeyId: Uint8Array, - private serverSalt: number[], private transport: MTTransport, options: InvokeApiOptions = {}) { + serverSalt: number[], private transport: MTTransport, options: InvokeApiOptions = {}) { this.authKeyUint8 = convertToUint8Array(this.authKey); + this.serverSalt = convertToUint8Array(serverSalt); this.isFileUpload = !!options.fileUpload; this.isFileDownload = !!options.fileDownload; @@ -179,7 +183,7 @@ export default class MTPNetworker { public updateSession() { this.seqNo = 0; this.prevSessionId = this.sessionId; - this.sessionId = [...new Uint8Array(8).randomize()]; + this.sessionId = new Uint8Array(8).randomize(); } public updateSentMessage(sentMessageId: string) { @@ -231,7 +235,7 @@ export default class MTPNetworker { const message = { msg_id: messageId, seq_no: seqNo, - body: serializer.getBytes() + body: serializer.getBytes(true) }; if(Modes.debug) { @@ -250,7 +254,7 @@ export default class MTPNetworker { const message = { msg_id: messageId, seq_no: seqNo, - body: serializer.getBytes() + body: serializer.getBytes(true) }; if(Modes.debug) { @@ -335,7 +339,7 @@ export default class MTPNetworker { } private sendPingDelayDisconnect = () => { - if(this.pingPromise) return; + if(this.pingPromise || true) return; if(!this.isOnline) { if((this.transport as Socket).connected) { @@ -667,28 +671,28 @@ export default class MTPNetworker { this.scheduleRequest(delay); } + // * correct, fully checked public async getMsgKey(dataWithPadding: ArrayBuffer, isOut: boolean) { - const authKey = this.authKeyUint8; const x = isOut ? 0 : 8 - const msgKeyLargePlain = bufferConcat(authKey.subarray(88 + x, 88 + x + 32), dataWithPadding); + const msgKeyLargePlain = bufferConcat(this.authKeyUint8.subarray(88 + x, 88 + x + 32), dataWithPadding); const msgKeyLarge = await CryptoWorker.sha256Hash(msgKeyLargePlain); const msgKey = new Uint8Array(msgKeyLarge).subarray(8, 24); return msgKey; }; + // * correct, fully checked public getAesKeyIv(msgKey: Uint8Array | number[], isOut: boolean): Promise<[Uint8Array, Uint8Array]> { - const authKey = this.authKeyUint8; const x = isOut ? 0 : 8; const sha2aText = new Uint8Array(52); const sha2bText = new Uint8Array(52); const promises: Array> = []; sha2aText.set(msgKey, 0); - sha2aText.set(authKey.subarray(x, x + 36), 16); + sha2aText.set(this.authKeyUint8.subarray(x, x + 36), 16); promises.push(CryptoWorker.sha256Hash(sha2aText)); - sha2bText.set(authKey.subarray(40 + x, 40 + x + 36), 0); + sha2bText.set(this.authKeyUint8.subarray(40 + x, 40 + x + 36), 0); sha2bText.set(msgKey, 36); promises.push(CryptoWorker.sha256Hash(sha2bText)); @@ -900,7 +904,7 @@ export default class MTPNetworker { return { bytes: encryptedBytes, - msgKey: msgKey + msgKey }; } @@ -934,6 +938,14 @@ export default class MTPNetworker { data.storeInt(message.body.length, 'message_data_length'); data.storeRawBytes(message.body, 'message_data'); + const des = new TLDeserialization(data.getBuffer().slice(16)); + const desSalt = des.fetchLong(); + const desSessionId = des.fetchLong(); + + if(!this.isOnline) { + this.log.error('trying to send message when offline', message, new Uint8Array(des.buffer), desSalt, desSessionId); + } + /* const messageDataLength = message.body.length; let canBeLength = 0; // bytes canBeLength += 8; @@ -950,13 +962,15 @@ export default class MTPNetworker { } */ const paddingLength = (16 - (data.offset % 16)) + 16 * (1 + nextRandomInt(5)); - const padding = [...new Uint8Array(paddingLength).randomize()]; + const padding = (message as any).padding || new Uint8Array(paddingLength).randomize().fill(0); /* const padding = [167, 148, 207, 226, 86, 192, 193, 57, 124, 153, 174, 145, 159, 1, 5, 70, 127, 157, 51, 241, 46, 85, 141, 212, 139, 234, 213, 164, 197, 116, 245, 70, 184, 40, 40, 201, 233, 211, 150, 94, 57, 84, 1, 135, 108, 253, 34, 139, 222, 208, 71, 214, 90, 67, 36, 28, 167, 148, 207, 226, 86, 192, 193, 57, 124, 153, 174, 145, 159, 1, 5, 70, 127, 157, 51, 241, 46, 85, 141, 212, 139, 234, 213, 164, 197, 116, 245, 70, 184, 40, 40, 201, 233, 211, 150, 94, 57, 84, 1, 135, 108, 253, 34, 139, 222, 208, 71, 214, 90, 67, 36, 28].slice(0, paddingLength); */ + (message as any).padding = padding; + const dataWithPadding = bufferConcat(dataBuffer, padding); // this.log('Adding padding', dataBuffer, padding, dataWithPadding) // this.log('auth_key_id', bytesToHex(self.authKeyID)) @@ -969,6 +983,7 @@ export default class MTPNetworker { this.log('Send encrypted: body length:', (message.body as ArrayBuffer).byteLength, paddingLength, dataWithPadding); } */ + // * full next block is correct return this.getEncryptedMessage(dataWithPadding).then((encryptedResult) => { /* if(DEBUG) { this.log('Got encrypted out message', encryptedResult); @@ -983,10 +998,12 @@ export default class MTPNetworker { const requestData = request.getBytes(true); - //if(message.fileUpload) { + if(this.isFileNetworker) { //this.log('Send encrypted: requestData length:', requestData.length, requestData.length % 16, paddingLength % 16, paddingLength, data.offset, encryptedResult.msgKey.length % 16, encryptedResult.bytes.length % 16); //this.log('Send encrypted: messageId:', message.msg_id, requestData.length); - //} + //this.log('Send encrypted:', message, new Uint8Array(bufferConcat(des.buffer, padding)), requestData, this.serverSalt.hex, this.sessionId.hex/* new Uint8Array(des.buffer) */); + this.debugRequests.push({before: new Uint8Array(bufferConcat(des.buffer, padding)), after: requestData}); + } return requestData; }); @@ -1137,7 +1154,7 @@ export default class MTPNetworker { return { response, messageId, - sessionId: sessionId, + sessionId, seqNo }; }); @@ -1151,7 +1168,7 @@ export default class MTPNetworker { ['dc' + this.dcId + '_server_salt']: bytesToHex(serverSalt) }); - this.serverSalt = serverSalt; + this.serverSalt = new Uint8Array(serverSalt); } // ! таймаут очень сильно тормозит скорость работы сокета (даже нулевой) diff --git a/src/lib/mtproto/tl_utils.ts b/src/lib/mtproto/tl_utils.ts index 87a2f558..f67f7854 100644 --- a/src/lib/mtproto/tl_utils.ts +++ b/src/lib/mtproto/tl_utils.ts @@ -1,5 +1,6 @@ import { bytesToHex } from '../../helpers/bytes'; import { bigint, bigStringInt, isObject } from './bin_utils'; +import { MOUNT_CLASS_TO } from './mtproto_config'; /// #if MTPROTO_WORKER // @ts-ignore import { gzipUncompress } from '../crypto/crypto_utils'; @@ -789,5 +790,6 @@ class TLDeserialization { } } +MOUNT_CLASS_TO && (MOUNT_CLASS_TO.TLDeserialization = TLDeserialization); +MOUNT_CLASS_TO && (MOUNT_CLASS_TO.TLSerialization = TLSerialization); export { TLDeserialization, TLSerialization }; - diff --git a/src/lib/mtproto/transports/intermediate.ts b/src/lib/mtproto/transports/intermediate.ts index 0b82333f..70278b40 100644 --- a/src/lib/mtproto/transports/intermediate.ts +++ b/src/lib/mtproto/transports/intermediate.ts @@ -4,13 +4,15 @@ export class IntermediatePacketCodec implements Codec { public tag = 0xee; public obfuscateTag = new Uint8Array([this.tag, this.tag, this.tag, this.tag]); + //private lol = 0; + public encodePacket(data: Uint8Array) { if((data.length % 4) !== 0) { console.error('Encode error!', data.length, data); } const len = data.length; - const header = new Uint8Array(new Uint32Array([len]).buffer); + const header = new Uint8Array(new Int32Array([/* ++this.lol >= 25 ? 0x80000001 : */len]).buffer); //console.log('got nobody cause im braindead', header, len, /* data, */data.buffer.byteLength === data.length); return header.concat(data); diff --git a/src/lib/mtproto/transports/obfuscation.ts b/src/lib/mtproto/transports/obfuscation.ts index ed623d70..608100e8 100644 --- a/src/lib/mtproto/transports/obfuscation.ts +++ b/src/lib/mtproto/transports/obfuscation.ts @@ -95,8 +95,8 @@ export default class Obfuscation { /* this.enc = new aesjs.ModeOfOperation.ctr(encKey, new aesjs.Counter(encIv as any)); this.dec = new aesjs.ModeOfOperation.ctr(decKey, new aesjs.Counter(decIv as any)); */ - /* console.log('encKey', encKey, encIv); - console.log('decKey', decKey, decIv); */ + console.log('encKey', encKey.hex, encIv.hex); + console.log('decKey', decKey.hex, decIv.hex); this.encNew = new CTR(encKey, encIv); this.decNew = new CTR(decKey, decIv); diff --git a/src/lib/mtproto/transports/websocket.ts b/src/lib/mtproto/transports/websocket.ts index 97863429..0cb7b31a 100644 --- a/src/lib/mtproto/transports/websocket.ts +++ b/src/lib/mtproto/transports/websocket.ts @@ -34,6 +34,8 @@ export default class Socket extends MTTransport { //private lol: Uint8Array[] = []; //private dd: () => void; + //private debugPayloads: MTPNetworker['debugRequests'] = []; + constructor(dcId: number, url: string, logSuffix: string, public retryTimeout: number) { super(dcId, url); @@ -220,6 +222,8 @@ export default class Socket extends MTTransport { const enc = this.obfuscation.encode(toEncode); //this.log('send after obf:', enc.hex); + //this.debugPayloads.push({before: body.slice(), after: enc}); + this.debug && this.log.debug('-> body length to send:', enc.length, this.ws.bufferedAmount); /* if(this.ws.bufferedAmount) { this.log.error('bufferedAmount:', this.ws.bufferedAmount); diff --git a/t.py b/t.py index df39cecb..bd613ba4 100644 --- a/t.py +++ b/t.py @@ -1,8 +1,16 @@ from telethon import TelegramClient, events, sync from telethon.network import ConnectionTcpAbridged +from telethon.network.mtprotostate import MTProtoState +from telethon.crypto.authkey import AuthKey +from telethon.network.connection.tcpobfuscated import ConnectionTcpObfuscated +from telethon.network.connection.tcpintermediate import IntermediatePacketCodec -import sys -print(sys.path) +import struct +import logging +logging.basicConfig(level=logging.DEBUG) + +# import sys +# print(sys.path) # These example values won't work. You must get your own api_id and # api_hash from https://my.telegram.org, under API Development. @@ -11,4 +19,82 @@ api_hash = '452b0359b988148995f22ff0f4229750' client = TelegramClient('session_name', api_id, api_hash, connection=ConnectionTcpAbridged) #client.start() -client.connect() +#client.connect() + +authKey = AuthKey(bytes.fromhex("2c45ed62da34d41bc82b6ef660760d3b01cb80028b0c363633f1c40ec80d5f4ad9d4ddee646736b6a9465fd7258b8936dedde6a86c69b4a03277ed6c543ccfd31fa8fa9f9449d686b4822b54542c91255231ecfa6aed4a9896cdcc3d5491e7f1b7529cbff75597f262813ced7eb3b5ac1e7e6794ca7aa00c5ea4d1d714e7c276fb63e5f8a1742cf4707eace8a6ec2ed4dcceceabdc7fc92bd099c811931e0da337f1b0271d8ba33e7a4a22fa1e4a913d8220edb0dd3a810ed408f03fe5d7f2d5dd43db4272d314b20a22376c03b0a05423600f4d012e7196ce9b3c45b28a75dbfa053222f5c86d1c6a706a2fd68ca270fd9a6449df1fa15a21837d34f4cf4e95")) +state = MTProtoState(authKey, loggers=client._log) + +state.salt = struct.unpack('q', bytes.fromhex("d1b37eebb4997ca9"))[0] +state.id = struct.unpack('q', bytes.fromhex("502368ee46d39313"))[0] + +#print(state.id) + +""" with open('file_part.txt', 'r') as file: + data = file.read() + messageData = bytes.fromhex(data) + #messageData = bytes.fromhex("146f8265b5342560290000000c000000ec77be7aaa40f90300000000") + #print(data) + + encrypted = state.encrypt_message_data(messageData) + + file.close() + with open('file_part_encrypted.txt', 'w') as file: + file.write(encrypted.hex()) + file.close() + #print(encrypted) """ + +ConnectionTcpObfuscated.packet_codec = IntermediatePacketCodec +connection = ConnectionTcpObfuscated("", "", 2, loggers=client._log) +obfuscatedIo = connection.obfuscated_io(connection) +#print(encrypted) +#exit() +#encoded = connection.packet_codec.encode_packet(connection.packet_codec, bytes.fromhex("deadbeef")) +#print(encoded) +#exit() + +name = "debugPayloads" +#name = "debugRequests" + +with open(name + '_before.txt', 'r') as fileBefore: + data = fileBefore.read() + lines = data.splitlines() + + with open(name + '_after.txt', 'r') as fileAfter: + data = fileAfter.read() + linesAfter = data.splitlines() + + length = len(lines) + for i in range(length): + print("processing line %i, of %i", i, length) + + lineBefore = lines[i] + lineAfter = linesAfter[i] + + messageData = bytes.fromhex(lineBefore) + messageData = connection.packet_codec.encode_packet(connection.packet_codec, messageData) + encrypted = obfuscatedIo._encrypt.encrypt(messageData) + #encrypted = state.encrypt_message_data(messageData) # need to comment padding inside + + #print(encrypted.hex()) + + #print(len(encrypted.hex())) + #print(len(lineAfter)) + #print(encrypted.hex() == lineAfter) + + #break + + if encrypted.hex() != lineAfter: + print("lol") + + with open('difference_before.txt', 'w') as file: + file.write(lineAfter) + file.close() + + with open('difference_after.txt', 'w') as file: + file.write(encrypted.hex()) + file.close() + + + #print(encrypted.hex()) + #print(lineAfter) + exit() diff --git a/t2.py b/t2.py new file mode 100644 index 00000000..3770bdf0 --- /dev/null +++ b/t2.py @@ -0,0 +1,83 @@ +from telethon import TelegramClient, events, sync +from telethon.network import ConnectionTcpAbridged +from telethon.network.mtprotostate import MTProtoState +from telethon.crypto.authkey import AuthKey + +import struct +import logging +logging.basicConfig(level=logging.DEBUG) + +# import sys +# print(sys.path) + +# These example values won't work. You must get your own api_id and +# api_hash from https://my.telegram.org, under API Development. +api_id = 1025907 +api_hash = '452b0359b988148995f22ff0f4229750' + +client = TelegramClient('session_name', api_id, api_hash, connection=ConnectionTcpAbridged) +#client.start() +#client.connect() + +authKey = AuthKey(bytes.fromhex("2c45ed62da34d41bc82b6ef660760d3b01cb80028b0c363633f1c40ec80d5f4ad9d4ddee646736b6a9465fd7258b8936dedde6a86c69b4a03277ed6c543ccfd31fa8fa9f9449d686b4822b54542c91255231ecfa6aed4a9896cdcc3d5491e7f1b7529cbff75597f262813ced7eb3b5ac1e7e6794ca7aa00c5ea4d1d714e7c276fb63e5f8a1742cf4707eace8a6ec2ed4dcceceabdc7fc92bd099c811931e0da337f1b0271d8ba33e7a4a22fa1e4a913d8220edb0dd3a810ed408f03fe5d7f2d5dd43db4272d314b20a22376c03b0a05423600f4d012e7196ce9b3c45b28a75dbfa053222f5c86d1c6a706a2fd68ca270fd9a6449df1fa15a21837d34f4cf4e95")) +state = MTProtoState(authKey, loggers=client._log) + +state.salt = struct.unpack('q', bytes.fromhex("d1b37eebb4997ca9"))[0] +state.id = struct.unpack('q', bytes.fromhex("502368ee46d39313"))[0] + +print(state.id) + +""" with open('file_part.txt', 'r') as file: + data = file.read() + messageData = bytes.fromhex(data) + #messageData = bytes.fromhex("146f8265b5342560290000000c000000ec77be7aaa40f90300000000") + #print(data) + + encrypted = state.encrypt_message_data(messageData) + + file.close() + with open('file_part_encrypted.txt', 'w') as file: + file.write(encrypted.hex()) + file.close() + #print(encrypted) """ + +with open('debugRequests_before.txt', 'r') as fileBefore: + data = fileBefore.read() + lines = data.splitlines() + + with open('debugRequests_after.txt', 'r') as fileAfter: + data = fileAfter.read() + linesAfter = data.splitlines() + + length = len(lines) + for i in range(length): + print("processing line %i, of %i", i, length) + + lineBefore = lines[i] + + messageData = bytes.fromhex(lineBefore) + encrypted = state.encrypt_message_data(messageData) # need to comment padding inside + + lineAfter = linesAfter[i] + + #print(len(encrypted.hex())) + #print(len(lineAfter)) + #print(encrypted.hex() == lineAfter) + + #break + + if encrypted.hex() != lineAfter: + print("lol") + + with open('difference_before.txt', 'w') as file: + file.write(lineAfter) + file.close() + + with open('difference_after.txt', 'w') as file: + file.write(encrypted.hex()) + file.close() + + + #print(encrypted.hex()) + #print(lineAfter) + exit() diff --git a/webpack.common.js b/webpack.common.js index d7dac3d3..7a5a6153 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -8,8 +8,8 @@ const fs = require('fs'); const allowedIPs = ['194.58.97.147', '195.66.140.39', '127.0.0.1', '176.100.8.254']; const devMode = process.env.NODE_ENV !== 'production'; -const useLocal = false; -const useLocalNotLocal = false; +const useLocal = true; +const useLocalNotLocal = true; if(devMode) { console.log('DEVMODE IS ON!'); @@ -103,7 +103,7 @@ module.exports = { allowedHosts: useLocal ? undefined : [ 'tweb.enko.club' ], - host: useLocalNotLocal ? '192.168.93.183' : (useLocal ? undefined : '0.0.0.0'), + host: useLocalNotLocal ? '192.168.93.209' : (useLocal ? undefined : '0.0.0.0'), public: useLocal ? undefined : 'tweb.enko.club', //host: '192.168.0.105', // '0.0.0.0' //host: 'tweb.enko.club', // '0.0.0.0'