Browse Source

Fix first requests with new transport

Fix resend websocket messages after close
master
morethanwords 5 years ago
parent
commit
df74c2b7e7
  1. 116
      src/lib/mtproto/authorizer.ts
  2. 4
      src/lib/mtproto/mtproto_config.ts
  3. 2
      src/lib/mtproto/mtprotoworker.ts
  4. 73
      src/lib/mtproto/networker.ts
  5. 4
      src/lib/mtproto/rsaKeysManager.ts
  6. 77
      src/lib/mtproto/transports/websocket.ts

116
src/lib/mtproto/authorizer.ts

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
import { TLSerialization, TLDeserialization } from "./tl_utils";
import dcConfigurator from "./dcConfigurator";
import { dT, bytesToHex, bytesCmp, bytesFromHex, bytesXor } from "../bin_utils";
import { bytesToHex, bytesCmp, bytesFromHex, bytesXor } from "../bin_utils";
import rsaKeysManager from "./rsaKeysManager";
import timeManager from "./timeManager";
@ -9,6 +9,8 @@ import { BigInteger } from "jsbn"; @@ -9,6 +9,8 @@ import { BigInteger } from "jsbn";
import CryptoWorker from "../crypto/cryptoworker";
import { logger, LogLevels } from "../polyfill";
/* let fNewNonce: any = bytesFromHex('8761970c24cb2329b5b2459752c502f3057cb7e8dbab200e526e8767fdc73b3c').reverse();
let fNonce: any = bytesFromHex('b597720d11faa5914ef485c529cde414').reverse();
let fResult: any = new Uint8Array(bytesFromHex('000000000000000001b473a0661b285e480000006324160514e4cd29c585f44e91a5fa110d7297b5c0c4134c84893db5715ecd56af5ed618082182053cc5de91cd00000015c4b51c02000000a5b7f709355fc30b216be86c022bb4c3'));
@ -59,7 +61,10 @@ export class Authorizer { @@ -59,7 +61,10 @@ export class Authorizer {
[dcID: number]: Promise<AuthOptions>
} = {};
private log: ReturnType<typeof logger>;
constructor() {
this.log = logger(`AUTHORIZER`/* , LogLevels.error | LogLevels.log */);
}
public mtpSendPlainRequest(dcID: number, requestArray: Uint8Array) {
@ -94,10 +99,10 @@ export class Authorizer { @@ -94,10 +99,10 @@ export class Authorizer {
transport: transport
};
console.log(dT(), 'mtpSendPlainRequest: creating requestPromise');
this.log('mtpSendPlainRequest: creating requestPromise');
return transport.send(resultArray).then(result => {
console.log(dT(), 'mtpSendPlainRequest: in good sector', result);
this.log('mtpSendPlainRequest: in good sector', result);
if(!result || !result.byteLength) {
return Promise.reject(baseError);
@ -109,17 +114,17 @@ export class Authorizer { @@ -109,17 +114,17 @@ export class Authorizer {
let deserializer = new TLDeserialization(result, {mtproto: true});
let auth_key_id = deserializer.fetchLong('auth_key_id');
if(auth_key_id != 0) console.error('auth_key_id != 0', auth_key_id);
if(auth_key_id != 0) this.log.error('auth_key_id != 0', auth_key_id);
let msg_id = deserializer.fetchLong('msg_id');
if(msg_id == 0) console.error('msg_id == 0', msg_id);
if(msg_id == 0) this.log.error('msg_id == 0', msg_id);
let msg_len = deserializer.fetchInt('msg_len');
if(!msg_len) console.error('no msg_len', msg_len);
if(!msg_len) this.log.error('no msg_len', msg_len);
return deserializer;
} catch(e) {
console.error('mtpSendPlainRequest: deserialization went bad', e);
this.log.error('mtpSendPlainRequest: deserialization went bad', e);
let error = Object.assign(baseError, {originalError: e});
throw error;
}
@ -142,15 +147,14 @@ export class Authorizer { @@ -142,15 +147,14 @@ export class Authorizer {
// need
rsaKeysManager.prepare().then(() => {});
console.log(dT(), 'Send req_pq', auth.nonce.hex);
this.log('Send req_pq', auth.nonce.hex);
try {
var deserializer = await this.mtpSendPlainRequest(auth.dcID, request.getBytes(true));
} catch(error) {
console.error(dT(), 'req_pq error', error.message);
this.log.error('req_pq error', error.message);
throw error;
}
var response = deserializer.fetchObject('ResPQ');
if(response._ != 'resPQ') {
@ -158,7 +162,7 @@ export class Authorizer { @@ -158,7 +162,7 @@ export class Authorizer {
}
if(!bytesCmp(auth.nonce, response.nonce)) {
console.log(auth.nonce, response.nonce);
this.log.error(auth.nonce, response.nonce);
throw new Error('[MT] resPQ nonce mismatch');
}
@ -167,7 +171,7 @@ export class Authorizer { @@ -167,7 +171,7 @@ export class Authorizer {
auth.pq = response.pq;
auth.fingerprints = response.server_public_key_fingerprints;
console.log(dT(), 'Got ResPQ', bytesToHex(auth.serverNonce), bytesToHex(auth.pq), auth.fingerprints);
this.log('Got ResPQ', bytesToHex(auth.serverNonce), bytesToHex(auth.pq), auth.fingerprints);
let publicKey = await rsaKeysManager.select(auth.fingerprints);
if(!publicKey) {
@ -176,19 +180,19 @@ export class Authorizer { @@ -176,19 +180,19 @@ export class Authorizer {
auth.publicKey = publicKey;
console.log(dT(), 'PQ factorization start', auth.pq);
this.log('PQ factorization start', auth.pq);
try {
var pAndQ = await CryptoWorker.factorize(auth.pq);
} catch(error) {
console.error('worker error factorize', error);
this.log.error('worker error factorize', error);
throw error;
}
auth.p = pAndQ[0];
auth.q = pAndQ[1];
console.log(dT(), 'PQ factorization done', pAndQ);
this.log('PQ factorization done', pAndQ);
/* let p = new Uint32Array(new Uint8Array(auth.p).buffer)[0];
let q = new Uint32Array(new Uint8Array(auth.q).buffer)[0];
console.log(dT(), 'PQ factorization done', pAndQ, p.toString(16), q.toString(16)); */
@ -253,18 +257,18 @@ export class Authorizer { @@ -253,18 +257,18 @@ export class Authorizer {
let requestBytes = request.getBytes(true);
console.log(dT(), 'Send req_DH_params', req_DH_params/* , requestBytes.hex */);
this.log('Send req_DH_params', req_DH_params/* , requestBytes.hex */);
try {
var deserializer = await this.mtpSendPlainRequest(auth.dcID, requestBytes);
} catch(error) {
console.log(dT(), 'Send req_DH_params FAIL!', error);
this.log('Send req_DH_params FAIL!', error);
throw error;
}
var response = deserializer.fetchObject('Server_DH_Params', 'RESPONSE');
console.log(dT(), 'Sent req_DH_params, response:', response);
this.log('Sent req_DH_params, response:', response);
if(response._ != 'server_DH_params_fail' && response._ != 'server_DH_params_ok') {
throw new Error('[MT] Server_DH_Params response invalid: ' + response._);
@ -292,7 +296,7 @@ export class Authorizer { @@ -292,7 +296,7 @@ export class Authorizer {
try {
await this.mtpDecryptServerDhDataAnswer(auth, response.encrypted_answer);
} catch(e) {
console.error(dT(), 'mtpDecryptServerDhDataAnswer FAILED!', e);
this.log.error('mtpDecryptServerDhDataAnswer FAILED!', e);
throw e;
}
@ -342,7 +346,7 @@ export class Authorizer { @@ -342,7 +346,7 @@ export class Authorizer {
throw new Error('[MT] server_DH_inner_data serverNonce mismatch');
}
console.log(dT(), 'Done decrypting answer');
this.log('Done decrypting answer');
auth.g = response.g;
auth.dhPrime = response.dh_prime;
auth.gA = response.g_a;
@ -362,13 +366,13 @@ export class Authorizer { @@ -362,13 +366,13 @@ export class Authorizer {
}
public mtpVerifyDhParams(g: number, dhPrime: any, gA: any) {
console.log(dT(), 'Verifying DH params');
this.log('Verifying DH params');
var dhPrimeHex = bytesToHex(dhPrime);
if(g != 3 || dhPrimeHex !== 'c71caeb9c6b1c9048e6c522f70f13f73980d40238e3e21c14934d037563d930f48198a0aa7c14058229493d22530f4dbfa336f6e0ac925139543aed44cce7c3720fd51f69458705ac68cd4fe6b6b13abdc9746512969328454f18faf8c595f642477fe96bb2a941d5bcd1d4ac8cc49880708fa9b378e3c4f3a9060bee67cf9a4a4a695811051907e162753b56b0f6b410dba74d8a84b2a14b3144e0ef1284754fd17ed950d5965b4b9dd46582db1178d169c6bc465b0d6ff9ca3928fef5b9ae4e418fc15e83ebea0f87fa9ff5eed70050ded2849f47bf959d956850ce929851f0d8115f635b105ee2e4e15d04b2454bf6f4fadf034b10403119cd8e3b92fcc5b') {
// The verified value is from https://core.telegram.org/mtproto/security_guidelines
throw new Error('[MT] DH params are not verified: unknown dhPrime');
}
console.log(dT(), 'dhPrime cmp OK');
this.log('dhPrime cmp OK');
var gABigInt = new BigInteger(bytesToHex(gA), 16);
var dhPrimeBigInt = new BigInteger(dhPrimeHex, 16);
@ -380,7 +384,7 @@ export class Authorizer { @@ -380,7 +384,7 @@ export class Authorizer {
if(gABigInt.compareTo(dhPrimeBigInt.subtract(BigInteger.ONE)) >= 0) {
throw new Error('[MT] DH params are not verified: gA >= dhPrime - 1');
}
console.log(dT(), '1 < gA < dhPrime-1 OK');
this.log('1 < gA < dhPrime-1 OK');
var two = new BigInteger(/* null */'');
@ -393,7 +397,7 @@ export class Authorizer { @@ -393,7 +397,7 @@ export class Authorizer {
if(gABigInt.compareTo(dhPrimeBigInt.subtract(twoPow)) >= 0) {
throw new Error('[MT] DH params are not verified: gA > dhPrime - 2^{2048-64}');
}
console.log(dT(), '2^{2048-64} < gA < dhPrime-2^{2048-64} OK');
this.log('2^{2048-64} < gA < dhPrime-2^{2048-64} OK');
return true;
}
@ -433,7 +437,7 @@ export class Authorizer { @@ -433,7 +437,7 @@ export class Authorizer {
encrypted_data: encryptedData
});
console.log(dT(), 'Send set_client_DH_params');
this.log('Send set_client_DH_params');
try {
var deserializer = await this.mtpSendPlainRequest(auth.dcID, request.getBytes(true));
@ -466,43 +470,43 @@ export class Authorizer { @@ -466,43 +470,43 @@ export class Authorizer {
authKeyAux = authKeyHash.slice(0, 8),
authKeyID = authKeyHash.slice(-8);
console.log(dT(), 'Got Set_client_DH_params_answer', response._, authKey);
this.log('Got Set_client_DH_params_answer', response._, authKey);
switch(response._) {
case 'dh_gen_ok':
var newNonceHash1 = (await CryptoWorker.sha1Hash(auth.newNonce.concat([1], authKeyAux))).slice(-16);
//var newNonceHash1 = sha1BytesSync(auth.newNonce.concat([1], authKeyAux)).slice(-16);
if(!bytesCmp(newNonceHash1, response.new_nonce_hash1)) {
throw new Error('[MT] Set_client_DH_params_answer new_nonce_hash1 mismatch');
}
var serverSalt = bytesXor(auth.newNonce.slice(0, 8), auth.serverNonce.slice(0, 8));
console.log('Auth successfull!', authKeyID, authKey, serverSalt);
auth.authKeyID = authKeyID;
auth.authKey = authKey;
auth.serverSalt = serverSalt;
return auth;
break;
var newNonceHash1 = (await CryptoWorker.sha1Hash(auth.newNonce.concat([1], authKeyAux))).slice(-16);
//var newNonceHash1 = sha1BytesSync(auth.newNonce.concat([1], authKeyAux)).slice(-16);
if(!bytesCmp(newNonceHash1, response.new_nonce_hash1)) {
throw new Error('[MT] Set_client_DH_params_answer new_nonce_hash1 mismatch');
}
var serverSalt = bytesXor(auth.newNonce.slice(0, 8), auth.serverNonce.slice(0, 8));
this.log('Auth successfull!', authKeyID, authKey, serverSalt);
auth.authKeyID = authKeyID;
auth.authKey = authKey;
auth.serverSalt = serverSalt;
return auth;
break;
case 'dh_gen_retry':
//var newNonceHash2 = sha1BytesSync(auth.newNonce.concat([2], authKeyAux)).slice(-16);
var newNonceHash2 = (await CryptoWorker.sha1Hash(auth.newNonce.concat([2], authKeyAux))).slice(-16);
if(!bytesCmp(newNonceHash2, response.new_nonce_hash2)) {
throw new Error('[MT] Set_client_DH_params_answer new_nonce_hash2 mismatch');
}
return this.mtpSendSetClientDhParams(auth);
//var newNonceHash2 = sha1BytesSync(auth.newNonce.concat([2], authKeyAux)).slice(-16);
var newNonceHash2 = (await CryptoWorker.sha1Hash(auth.newNonce.concat([2], authKeyAux))).slice(-16);
if(!bytesCmp(newNonceHash2, response.new_nonce_hash2)) {
throw new Error('[MT] Set_client_DH_params_answer new_nonce_hash2 mismatch');
}
return this.mtpSendSetClientDhParams(auth);
case 'dh_gen_fail':
//var newNonceHash3 = sha1BytesSync(auth.newNonce.concat([3], authKeyAux)).slice(-16);
var newNonceHash3 = (await CryptoWorker.sha1Hash(auth.newNonce.concat([3], authKeyAux))).slice(-16);
if(!bytesCmp(newNonceHash3, response.new_nonce_hash3)) {
throw new Error('[MT] Set_client_DH_params_answer new_nonce_hash3 mismatch');
}
throw new Error('[MT] Set_client_DH_params_answer fail');
//var newNonceHash3 = sha1BytesSync(auth.newNonce.concat([3], authKeyAux)).slice(-16);
var newNonceHash3 = (await CryptoWorker.sha1Hash(auth.newNonce.concat([3], authKeyAux))).slice(-16);
if(!bytesCmp(newNonceHash3, response.new_nonce_hash3)) {
throw new Error('[MT] Set_client_DH_params_answer new_nonce_hash3 mismatch');
}
throw new Error('[MT] Set_client_DH_params_answer fail');
}
}

4
src/lib/mtproto/mtproto_config.ts

@ -9,7 +9,7 @@ export const App = { @@ -9,7 +9,7 @@ export const App = {
export const Modes = {
test: location.search.indexOf('test=1') > 0/* || true */,
debug: location.search.indexOf('debug=1') > 0,
http: location.search.indexOf('http=1') > 0,
ssl: location.search.indexOf('ssl=1') > 0 || location.protocol == 'https:' && location.search.indexOf('ssl=0') == -1,
http: false, //location.search.indexOf('http=1') > 0,
ssl: true, // location.search.indexOf('ssl=1') > 0 || location.protocol == 'https:' && location.search.indexOf('ssl=0') == -1,
multipleConnections: true
};

2
src/lib/mtproto/mtprotoworker.ts

@ -121,7 +121,7 @@ class ApiManagerProxy extends CryptoWorkerMethods { @@ -121,7 +121,7 @@ class ApiManagerProxy extends CryptoWorkerMethods {
stopTime?: number,
rawError?: any
} = {}): Promise<any> {
console.log('will invokeApi:', method, params, options);
//console.log('will invokeApi:', method, params, options);
return this.performTaskWorker('invokeApi', method, params, options);
}

73
src/lib/mtproto/networker.ts

@ -12,7 +12,7 @@ import NetworkerFactory from './networkerFactory'; @@ -12,7 +12,7 @@ import NetworkerFactory from './networkerFactory';
import dcConfigurator from './dcConfigurator';
import Socket from './transports/websocket';
import HTTP from './transports/http';
import { logger } from '../polyfill';
import { logger, LogLevels } from '../polyfill';
import { Modes, App } from './mtproto_config';
import { InvokeApiOptions } from '../../types';
@ -79,8 +79,6 @@ class MTPNetworker { @@ -79,8 +79,6 @@ class MTPNetworker {
private onOnlineCb = this.checkConnection.bind(this);
private debug = false;
private lastResendReq: {
req_msg_id: string,
resend_msg_ids: Array<string>
@ -99,6 +97,11 @@ class MTPNetworker { @@ -99,6 +97,11 @@ class MTPNetworker {
this.log = logger('NET-' + dcID + (this.upload ? '-U' : ''));
this.log('constructor'/* , this.authKey, this.authKeyID, this.serverSalt */);
/* // Test resend after bad_server_salt
if(this.dcID == 1 && this.upload) {
this.serverSalt[0] = 0;
} */
this.updateSession();
// if(!NetworkerFactory.offlineInited) {
@ -268,7 +271,7 @@ class MTPNetworker { @@ -268,7 +271,7 @@ class MTPNetworker {
if(Modes.debug/* || true */) {
this.log('Api call', method, message, params, options);
} else {
//////this.log('Api call', method);
this.log('Api call', method, params, options);
}
return this.pushMessage(message, options);
@ -344,28 +347,28 @@ class MTPNetworker { @@ -344,28 +347,28 @@ class MTPNetworker {
}
public pushResend(messageID: string, delay = 0) {
var value = delay ? Date.now() + delay : 0;
var sentMessage = this.sentMessages[messageID];
const value = delay ? Date.now() + delay : 0;
const sentMessage = this.sentMessages[messageID];
if(sentMessage.container) {
for(var i = 0; i < sentMessage.inner.length; i++) {
for(let i = 0, length = sentMessage.inner.length; i < length; i++) {
this.pendingMessages[sentMessage.inner[i]] = value;
}
} else {
this.pendingMessages[messageID] = value;
}
// this.log('Resend due', messageID, this.pendingMessages)
this.log('Resend due', messageID, this.pendingMessages);
this.scheduleRequest(delay);
}
public async getMsgKey(dataWithPadding: ArrayBuffer, isOut: boolean) {
var authKey = this.authKeyUint8;
var x = isOut ? 0 : 8
var msgKeyLargePlain = bufferConcat(authKey.subarray(88 + x, 88 + x + 32), dataWithPadding);
const authKey = this.authKeyUint8;
const x = isOut ? 0 : 8
const msgKeyLargePlain = bufferConcat(authKey.subarray(88 + x, 88 + x + 32), dataWithPadding);
let msgKeyLarge = await CryptoWorker.sha256Hash(msgKeyLargePlain);
var msgKey = new Uint8Array(msgKeyLarge).subarray(8, 24);
const msgKeyLarge = await CryptoWorker.sha256Hash(msgKeyLargePlain);
const msgKey = new Uint8Array(msgKeyLarge).subarray(8, 24);
return msgKey;
};
@ -513,7 +516,7 @@ class MTPNetworker { @@ -513,7 +516,7 @@ class MTPNetworker {
/* for(var i = 0; i < this.pendingResends.length; i++) {
resendMsgIDs.push(this.pendingResends[i]);
} */
// this.log('resendReq messages', resendMsgIDs)
this.log('resendReq messages', resendMsgIDs);
this.wrapMtpMessage({
_: 'msg_resend_req',
msg_ids: resendMsgIDs
@ -729,7 +732,7 @@ class MTPNetworker { @@ -729,7 +732,7 @@ class MTPNetworker {
public sendEncryptedRequest(message: any, options: any = {}) {
var self = this;
this.debug && this.log('Send encrypted', message, options, this.authKeyID);
this.log.debug('Send encrypted', message, options, this.authKeyID);
// console.trace()
var data = new TLSerialization({
startMaxLength: message.body.length + 2048
@ -740,7 +743,7 @@ class MTPNetworker { @@ -740,7 +743,7 @@ class MTPNetworker {
data.storeLong(message.msg_id, 'message_id');
data.storeInt(message.seq_no, 'seq_no');
data.storeInt(message.body.length, 'message_data_length');
data.storeRawBytes(message.body, 'message_data');
@ -756,7 +759,7 @@ class MTPNetworker { @@ -756,7 +759,7 @@ class MTPNetworker {
// this.log('auth_key_id', bytesToHex(self.authKeyID))
return this.getEncryptedMessage(dataWithPadding).then((encryptedResult) => {
this.debug && this.log('Got encrypted out message', encryptedResult);
this.log.debug('Got encrypted out message', encryptedResult);
let request = new TLSerialization({
startMaxLength: encryptedResult.bytes.byteLength + 256
@ -796,7 +799,7 @@ class MTPNetworker { @@ -796,7 +799,7 @@ class MTPNetworker {
}
public parseResponse(responseBuffer: Uint8Array) {
this.debug && this.log('Start parsing response'/* , responseBuffer */);
this.log.debug('Start parsing response'/* , responseBuffer */);
let self = this;
let deserializer = new TLDeserialization(responseBuffer);
@ -1016,6 +1019,18 @@ class MTPNetworker { @@ -1016,6 +1019,18 @@ class MTPNetworker {
};
}
/**
* только для сокета, возможно это будет неправильно работать, но в тесте сработало правильно
*/
public resend() {
for(let id in this.sentMessages) {
const msg = this.sentMessages[id];
if(msg.body) {
this.pushResend(id);
}
}
}
public processMessage(message: any, messageID: string, sessionID: Uint8Array | number[]) {
var msgidInt = parseInt(messageID/* .toString(10) */.substr(0, -10), 10);
if(msgidInt % 2) {
@ -1023,7 +1038,7 @@ class MTPNetworker { @@ -1023,7 +1038,7 @@ class MTPNetworker {
return;
}
this.debug && this.log('process message', message, messageID, sessionID);
this.log.debug('process message', message, messageID, sessionID);
switch(message._) {
case 'msg_container':
@ -1040,10 +1055,20 @@ class MTPNetworker { @@ -1040,10 +1055,20 @@ class MTPNetworker {
this.log(message.bad_msg_id, message.bad_msg_seqno);
throw new Error('[MT] Bad server salt for invalid message');
}
this.applyServerSalt(message.new_server_salt);
this.pushResend(message.bad_msg_id);
this.ackMessage(messageID);
/* // simulate disconnect
try {
this.log('networker state:', this);
// @ts-ignore
this.transport.ws.close(1000);
} catch(err) {
this.log.error('transport', this.transport, err);
} */
break;
case 'bad_msg_notification':
@ -1084,7 +1109,7 @@ class MTPNetworker { @@ -1084,7 +1109,7 @@ class MTPNetworker {
case 'new_session_created':
this.ackMessage(messageID);
this.log('new_session_created in my head');
this.log.debug('new_session_created', message);
//this.updateSession();
this.processMessageAck(message.first_msg_id);
@ -1150,7 +1175,7 @@ class MTPNetworker { @@ -1150,7 +1175,7 @@ class MTPNetworker {
} else {
if(deferred) {
if(Modes.debug) {
this.debug && this.log('Rpc response', message.result);
this.log.debug('Rpc response', message.result);
} else {
var dRes = message.result._;
if(!dRes) {
@ -1160,7 +1185,7 @@ class MTPNetworker { @@ -1160,7 +1185,7 @@ class MTPNetworker {
dRes = message.result;
}
}
this.debug && this.log('Rpc response', dRes, sentMessage);
this.log.debug('Rpc response', dRes, sentMessage);
}
sentMessage.deferred.resolve(message.result);
@ -1179,7 +1204,7 @@ class MTPNetworker { @@ -1179,7 +1204,7 @@ class MTPNetworker {
default:
this.ackMessage(messageID);
this.debug && this.log('Update', message);
this.log.debug('Update', message);
if(NetworkerFactory.updatesProcessor !== null) {
NetworkerFactory.updatesProcessor(message, true);

4
src/lib/mtproto/rsaKeysManager.ts

@ -113,7 +113,7 @@ export class RSAKeysManager { @@ -113,7 +113,7 @@ export class RSAKeysManager {
})).then(() => {
this.prepared = true;
console.log('[MT] Prepared keys');
//console.log('[MT] Prepared keys');
this.preparePromise = null;
});
}
@ -130,7 +130,7 @@ export class RSAKeysManager { @@ -130,7 +130,7 @@ export class RSAKeysManager {
fingerprintHex = new Array(16 - fingerprintHex.length).fill('0').join('') + fingerprintHex;
}
console.log(fingerprintHex, this.publicKeysParsed);
//console.log(fingerprintHex, this.publicKeysParsed);
if(foundKey = this.publicKeysParsed[fingerprintHex]) {
return Object.assign({
fingerprint: fingerprints[i]

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

@ -5,7 +5,7 @@ import {CTR} from '@cryptography/aes'; @@ -5,7 +5,7 @@ import {CTR} from '@cryptography/aes';
//import abridgetPacketCodec from './abridged';
import intermediatePacketCodec from './intermediate';
import {MTPNetworker} from '../networker';
import { logger } from '../../polyfill';
import { logger, LogLevels } from '../../polyfill';
import { bytesFromWordss } from '../../bin_utils';
import { Codec } from './codec';
@ -108,9 +108,14 @@ export class Obfuscation { @@ -108,9 +108,14 @@ export class Obfuscation {
}
export default class Socket extends MTTransport {
ws: WebSocket | undefined;
pending: Array<{resolve?: any, reject?: any, body?: Uint8Array}> = [];
ws: WebSocket;
pending: Array<Partial<{
resolve: any,
reject: any,
body: Uint8Array,
bodySent: boolean
}>> = [];
connected = false;
@ -122,14 +127,12 @@ export default class Socket extends MTTransport { @@ -122,14 +127,12 @@ export default class Socket extends MTTransport {
log: ReturnType<typeof logger>;
debug = false;
codec = intermediatePacketCodec;
constructor(dcID: number, url: string) {
super(dcID, url);
this.log = logger(`WS-${dcID}`);
this.log = logger(`WS-${dcID}`, LogLevels.log | LogLevels.error);
this.log('constructor');
@ -142,7 +145,7 @@ export default class Socket extends MTTransport { @@ -142,7 +145,7 @@ export default class Socket extends MTTransport {
this.ws.removeEventListener('close', this.handleClose);
this.ws.removeEventListener('message', this.handleMessage);
this.ws.close(1000);
}
}
this.ws = new WebSocket(this.url, 'binary');
this.ws.binaryType = 'arraybuffer';
@ -161,20 +164,34 @@ export default class Socket extends MTTransport { @@ -161,20 +164,34 @@ export default class Socket extends MTTransport {
};
handleClose = (event: CloseEvent) => {
this.log('closed', event);
this.log('closed', event, this.pending);
this.connected = false;
this.pending.length = 0;
if(this.networker) {
//this.pending.length = 0;
/* if(this.networker) {
this.networker.resend();
this.networker.cleanupSent();
}
} */
this.log('trying to reconnect...');
this.connect();
for(let pending of this.pending) {
if(pending.bodySent) {
pending.bodySent = false;
}
}
if(this.networker) {
this.ws.addEventListener('open', () => {
this.networker.resend();
this.networker.cleanupSent();
}, {once: true});
}
};
handleMessage = (event: MessageEvent) => {
this.debug && this.log('<-', 'handleMessage', event);
this.log.debug('<-', 'handleMessage', event);
let data = this.obfuscation.decode(new Uint8Array(event.data));
data = this.codec.readPacket(data);
@ -182,9 +199,9 @@ export default class Socket extends MTTransport { @@ -182,9 +199,9 @@ export default class Socket extends MTTransport {
if(this.networker) { // authenticated!
//this.pending = this.pending.filter(p => p.body); // clear pending
this.debug && this.log('redirecting to networker');
this.log.debug('redirecting to networker');
return this.networker.parseResponse(data).then(response => {
this.debug && this.log('redirecting to networker response:', response);
this.log.debug('redirecting to networker response:', response);
this.networker.processMessage(response.response, response.messageID, response.sessionID);
});
}
@ -192,14 +209,14 @@ export default class Socket extends MTTransport { @@ -192,14 +209,14 @@ export default class Socket extends MTTransport {
//console.log('got hex:', data.hex);
let pending = this.pending.shift();
if(!pending) {
return this.log('no pending for res:', data.hex);
return this.log.debug('no pending for res:', data.hex);
}
pending.resolve(data);
};
send = (body: Uint8Array) => {
this.debug && this.log('-> body length to pending:', body.length);
this.log.debug('-> body length to pending:', body.length);
if(this.networker) {
this.pending.push({body});
@ -221,26 +238,28 @@ export default class Socket extends MTTransport { @@ -221,26 +238,28 @@ export default class Socket extends MTTransport {
return;
}
let length = this.pending.length;
//this.log.error('Pending length:', this.pending.length);
const length = this.pending.length;
for(let i = length - 1; i >= 0; --i) {
let pending = this.pending[i];
let {body} = pending;
if(body) {
let toEncode = this.codec.encodePacket(body);
//console.log('send before obf:', /* body.hex, nonce.hex, */ toEncode.hex);
let enc = this.obfuscation.encode(toEncode);
//console.log('send after obf:', enc.hex);
const pending = this.pending[i];
const {body, bodySent} = pending;
if(body && !bodySent) {
const toEncode = this.codec.encodePacket(body);
this.debug && this.log('-> body length to send:', enc.length);
//this.log('send before obf:', /* body.hex, nonce.hex, */ toEncode.hex);
const enc = this.obfuscation.encode(toEncode);
//this.log('send after obf:', enc.hex);
this.log.debug('-> body length to send:', enc.length);
this.ws.send(enc);
if(!pending.resolve) { // remove if no response needed
this.pending.splice(i, 1);
} else {
pending.bodySent = true;
}
delete pending.body;
//delete pending.body;
}
}
}

Loading…
Cancel
Save