Browse Source

no comments

master
Eduard Kuzmenko 3 years ago
parent
commit
e0999ad4d0
  1. 44
      package.json
  2. 50
      src/components/chat/bubbleGroups.ts
  3. 29
      src/components/chat/bubbles.ts
  4. 2
      src/components/chat/contextMenu.ts
  5. 2
      src/lib/appManagers/appMessagesManager.ts
  6. 2
      src/lib/appManagers/appStateManager.ts
  7. 6
      src/lib/appManagers/appUsersManager.ts
  8. 2
      src/lib/crypto/crypto_utils.ts
  9. 8
      src/lib/mtproto/apiManager.ts
  10. 30
      src/lib/mtproto/mtproto_config.ts
  11. 2
      src/lib/mtproto/mtprotoworker.ts
  12. 53
      src/lib/mtproto/networker.ts
  13. 4
      src/lib/mtproto/tl_utils.ts
  14. 4
      src/lib/mtproto/transports/intermediate.ts
  15. 4
      src/lib/mtproto/transports/obfuscation.ts
  16. 4
      src/lib/mtproto/transports/websocket.ts
  17. 92
      t.py
  18. 83
      t2.py
  19. 6
      webpack.common.js

44
package.json

@ -19,64 +19,64 @@ @@ -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"
}

50
src/components/chat/bubbleGroups.ts

@ -1,22 +1,23 @@ @@ -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<BubbleGroup> = []; // map to group
private detailsMap: Map<HTMLElement, BubbleGroup> = new Map();
private groups: Array<Group> = [];
//updateRAFs: Map<HTMLDivElement[], number> = new Map();
//updateRAFs: Map<HTMLElement[], number> = 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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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);
}

29
src/components/chat/bubbles.ts

@ -152,12 +152,9 @@ export default class ChatBubbles { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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) {

2
src/components/chat/contextMenu.ts

@ -215,7 +215,7 @@ export default class ChatContextMenu { @@ -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',

2
src/lib/appManagers/appMessagesManager.ts

@ -3313,7 +3313,7 @@ export class AppMessagesManager { @@ -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',

2
src/lib/appManagers/appStateManager.ts

@ -156,7 +156,7 @@ export class AppStateManager extends EventListenerBase<{ @@ -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);
}

6
src/lib/appManagers/appUsersManager.ts

@ -118,7 +118,9 @@ export class AppUsersManager { @@ -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 { @@ -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[] = [];

2
src/lib/crypto/crypto_utils.ts

@ -16,7 +16,7 @@ import { addPadding, bytesFromBigInt } from '../mtproto/bin_utils'; @@ -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<number> {
/* let perf = performance.now();
for(let i = 0; i < 1000000; ++i) {
bytesFromWords({words: longToInts(sLong), sigBytes: 8}).reverse();

8
src/lib/mtproto/apiManager.ts

@ -157,12 +157,12 @@ export class ApiManager { @@ -157,12 +157,12 @@ export class ApiManager {
// mtpGetNetworker
public getNetworker(dcId: number, options: InvokeApiOptions = {}): Promise<MTPNetworker> {
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 { @@ -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) {

30
src/lib/mtproto/mtproto_config.ts

@ -34,3 +34,33 @@ export const Database = { @@ -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);

2
src/lib/mtproto/mtprotoworker.ts

@ -124,7 +124,7 @@ export class ApiManagerProxy extends CryptoWorkerMethods { @@ -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) {

53
src/lib/mtproto/networker.ts

@ -100,8 +100,9 @@ export default class MTPNetworker { @@ -100,8 +100,9 @@ export default class MTPNetworker {
/// #endif
private seqNo: number = 0;
private prevSessionId: Array<number> = [];
private sessionId: Array<number> = [];
private prevSessionId: Uint8Array;
private sessionId: Uint8Array;
private serverSalt: Uint8Array;
private lastResendReq: {
req_msg_id: string,
@ -119,9 +120,12 @@ export default class MTPNetworker { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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<Promise<number[]>> = [];
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 { @@ -900,7 +904,7 @@ export default class MTPNetworker {
return {
bytes: encryptedBytes,
msgKey: msgKey
msgKey
};
}
@ -934,6 +938,14 @@ export default class MTPNetworker { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -1137,7 +1154,7 @@ export default class MTPNetworker {
return {
response,
messageId,
sessionId: sessionId,
sessionId,
seqNo
};
});
@ -1151,7 +1168,7 @@ export default class MTPNetworker { @@ -1151,7 +1168,7 @@ export default class MTPNetworker {
['dc' + this.dcId + '_server_salt']: bytesToHex(serverSalt)
});
this.serverSalt = serverSalt;
this.serverSalt = new Uint8Array(serverSalt);
}
// ! таймаут очень сильно тормозит скорость работы сокета (даже нулевой)

4
src/lib/mtproto/tl_utils.ts

@ -1,5 +1,6 @@ @@ -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 { @@ -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 };

4
src/lib/mtproto/transports/intermediate.ts

@ -4,13 +4,15 @@ export class IntermediatePacketCodec implements Codec { @@ -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);

4
src/lib/mtproto/transports/obfuscation.ts

@ -95,8 +95,8 @@ export default class Obfuscation { @@ -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);

4
src/lib/mtproto/transports/websocket.ts

@ -34,6 +34,8 @@ export default class Socket extends MTTransport { @@ -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 { @@ -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);

92
t.py

@ -1,8 +1,16 @@ @@ -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' @@ -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()

83
t2.py

@ -0,0 +1,83 @@ @@ -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()

6
webpack.common.js

@ -8,8 +8,8 @@ const fs = require('fs'); @@ -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 = { @@ -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'

Loading…
Cancel
Save