Browse Source

Fix file download speed for 1 thread

master
morethanwords 5 years ago
parent
commit
c7b7427f19
  1. 2
      src/lib/appManagers/appMessagesManager.ts
  2. 27
      src/lib/mtproto/apiFileManager.ts
  3. 85
      src/lib/mtproto/apiManager.ts
  4. 71
      src/lib/mtproto/dcConfigurator.ts
  5. 58
      src/lib/mtproto/networker.ts
  6. 5
      src/lib/mtproto/networkerFactory.ts
  7. 44
      src/lib/mtproto/passwordManager.ts
  8. 19
      src/types.d.ts

2
src/lib/appManagers/appMessagesManager.ts

@ -183,7 +183,7 @@ export class AppMessagesManager {
public loadSavedState() { public loadSavedState() {
if(this.loaded) return this.loaded; if(this.loaded) return this.loaded;
this.loaded = new Promise((resolve, reject) => { return this.loaded = new Promise((resolve, reject) => {
AppStorage.get<{ AppStorage.get<{
dialogs: Dialog[], dialogs: Dialog[],
allDialogsLoaded: AppMessagesManager['allDialogsLoaded'], allDialogsLoaded: AppMessagesManager['allDialogsLoaded'],

27
src/lib/mtproto/apiFileManager.ts

@ -29,22 +29,22 @@ export class ApiFileManager {
resolve: (...args: any[]) => void, resolve: (...args: any[]) => void,
reject: (...args: any[]) => void reject: (...args: any[]) => void
}, },
activeDelta?: number activeDelta: number
}> }>
} = {}; } = {};
public downloadActives: {[dcID: string]: number} = {}; public downloadActives: {[dcID: string]: number} = {};
private log: ReturnType<typeof logger> = logger('AFM'); private log: ReturnType<typeof logger> = logger('AFM');
public downloadRequest(dcID: string | number, cb: () => Promise<unknown>, activeDelta?: number) { public downloadRequest(dcID: string | number, cb: () => Promise<unknown>, activeDelta: number) {
if(this.downloadPulls[dcID] === undefined) { if(this.downloadPulls[dcID] === undefined) {
this.downloadPulls[dcID] = []; this.downloadPulls[dcID] = [];
this.downloadActives[dcID] = 0; this.downloadActives[dcID] = 0;
} }
var downloadPull = this.downloadPulls[dcID]; const downloadPull = this.downloadPulls[dcID];
let promise = new Promise((resolve, reject) => { const promise = new Promise((resolve, reject) => {
downloadPull.push({cb: cb, deferred: {resolve, reject}, activeDelta: activeDelta}); downloadPull.push({cb: cb, deferred: {resolve, reject}, activeDelta: activeDelta});
})/* .catch(() => {}) */; })/* .catch(() => {}) */;
@ -56,15 +56,16 @@ export class ApiFileManager {
} }
public downloadCheck(dcID: string | number) { public downloadCheck(dcID: string | number) {
var downloadPull = this.downloadPulls[dcID]; const downloadPull = this.downloadPulls[dcID];
var downloadLimit = dcID == 'upload' ? 11 : 5; //const downloadLimit = dcID == 'upload' ? 11 : 5;
const downloadLimit = 24;
if(this.downloadActives[dcID] >= downloadLimit || !downloadPull || !downloadPull.length) { if(this.downloadActives[dcID] >= downloadLimit || !downloadPull || !downloadPull.length) {
return false; return false;
} }
var data = downloadPull.shift(); const data = downloadPull.shift();
var activeDelta = data.activeDelta || 1; const activeDelta = data.activeDelta || 1;
this.downloadActives[dcID] += activeDelta; this.downloadActives[dcID] += activeDelta;
@ -122,8 +123,8 @@ export class ApiFileManager {
} }
public getTempFileName(file: any) { public getTempFileName(file: any) {
var size = file.size || -1; const size = file.size || -1;
var random = nextRandomInt(0xFFFFFFFF); const random = nextRandomInt(0xFFFFFFFF);
return '_temp' + random + '_' + size; return '_temp' + random + '_' + size;
} }
@ -131,12 +132,12 @@ export class ApiFileManager {
if(!location) { if(!location) {
return false; return false;
} }
var fileName = this.getFileName(location); const fileName = this.getFileName(location);
return this.cachedDownloads[fileName] || false; return this.cachedDownloads[fileName] || false;
} }
public getFileStorage(): typeof cacheStorage { public getFileStorage() {
return cacheStorage; return cacheStorage;
} }
@ -419,7 +420,7 @@ export class ApiFileManager {
fileDownload: true/* , fileDownload: true/* ,
singleInRequest: 'safari' in window */ singleInRequest: 'safari' in window */
}); });
}, dcID).then((result: any) => { }, 2).then((result: any) => {
writeFilePromise.then(() => { writeFilePromise.then(() => {
if(canceled) { if(canceled) {
return Promise.resolve(); return Promise.resolve();

85
src/lib/mtproto/apiManager.ts

@ -13,6 +13,7 @@ import passwordManager from './passwordManager';
/// #if !MTPROTO_WORKER /// #if !MTPROTO_WORKER
import { $rootScope } from '../utils'; import { $rootScope } from '../utils';
import { InvokeApiOptions } from '../../types';
/// #endif /// #endif
//console.error('apiManager included!'); //console.error('apiManager included!');
@ -133,10 +134,10 @@ export class ApiManager {
} }
// mtpGetNetworker // mtpGetNetworker
public async getNetworker(dcID: number, options: any = {}): Promise<MTPNetworker> { public async getNetworker(dcID: number, options: InvokeApiOptions): Promise<MTPNetworker> {
let upload = (options.fileUpload || options.fileDownload) const upload = (options.fileUpload || options.fileDownload)
&& (dcConfigurator.chooseServer(dcID, true) instanceof HTTP || Modes.multipleConnections); && (dcConfigurator.chooseServer(dcID, true) instanceof HTTP || Modes.multipleConnections);
let cache = upload ? this.cachedUploadNetworkers : this.cachedNetworkers; const cache = upload ? this.cachedUploadNetworkers : this.cachedNetworkers;
if(!dcID) { if(!dcID) {
throw new Error('get Networker without dcID'); throw new Error('get Networker without dcID');
@ -146,72 +147,61 @@ export class ApiManager {
return cache[dcID]; return cache[dcID];
} }
let getKey = dcID + '-' + +upload; const getKey = dcID + '-' + +upload;
if(this.gettingNetworkers[getKey]) { if(this.gettingNetworkers[getKey]) {
return this.gettingNetworkers[getKey]; return this.gettingNetworkers[getKey];
} }
return this.gettingNetworkers[getKey] = new Promise(async(resolve, reject) => { const ak = 'dc' + dcID + '_auth_key';
var ak = 'dc' + dcID + '_auth_key'; const akID = 'dc' + dcID + '_auth_keyID';
var akID = 'dc' + dcID + '_auth_keyID'; const ss = 'dc' + dcID + '_server_salt';
var ss = 'dc' + dcID + '_server_salt';
let result = await AppStorage.get<string[]/* |boolean[] */>([ak, akID, ss]); return this.gettingNetworkers[getKey] = AppStorage.get<string[]/* |boolean[] */>([ak, akID, ss])
.then(async([authKeyHex, authKeyIDHex, serverSaltHex]) => {
let [authKeyHex, authKeyIDHex, serverSaltHex] = result; /* if(authKeyHex && !authKeyIDHex && serverSaltHex) {
if(authKeyHex && !authKeyIDHex && serverSaltHex) {
this.log.warn('Updating to new version (+akID)'); this.log.warn('Updating to new version (+akID)');
await AppStorage.remove(ak, akID, ss); await AppStorage.remove(ak, akID, ss);
authKeyHex = serverSaltHex = ''; authKeyHex = serverSaltHex = '';
} } */
let networker: MTPNetworker;
if(authKeyHex && authKeyHex.length == 512) { if(authKeyHex && authKeyHex.length == 512) {
if(!serverSaltHex || serverSaltHex.length != 16) { if(!serverSaltHex || serverSaltHex.length != 16) {
serverSaltHex = 'AAAAAAAAAAAAAAAA'; serverSaltHex = 'AAAAAAAAAAAAAAAA';
} }
var authKey = bytesFromHex(authKeyHex); const authKey = bytesFromHex(authKeyHex);
var authKeyID = new Uint8Array(bytesFromHex(authKeyIDHex)); const authKeyID = new Uint8Array(bytesFromHex(authKeyIDHex));
var serverSalt = bytesFromHex(serverSaltHex); const serverSalt = bytesFromHex(serverSaltHex);
resolve(cache[dcID] = networkerFactory.getNetworker(dcID, authKey, authKeyID, serverSalt, options));
} else try {
let auth = await authorizer.auth(dcID);
let storeObj = {
[ak]: bytesToHex(auth.authKey),
[akID]: auth.authKeyID.hex,
[ss]: bytesToHex(auth.serverSalt)
};
AppStorage.set(storeObj); networker = networkerFactory.getNetworker(dcID, authKey, authKeyID, serverSalt, options);
} else {
resolve(cache[dcID] = networkerFactory.getNetworker(dcID, auth.authKey, auth.authKeyID, auth.serverSalt, options)); try { // if no saved state
} catch(error) { const auth = await authorizer.auth(dcID);
this.log('Get networker error', error, error.stack);
reject(error); const storeObj = {
[ak]: bytesToHex(auth.authKey),
[akID]: auth.authKeyID.hex,
[ss]: bytesToHex(auth.serverSalt)
};
AppStorage.set(storeObj);
networker = networkerFactory.getNetworker(dcID, auth.authKey, auth.authKeyID, auth.serverSalt, options);
} catch(error) {
this.log('Get networker error', error, error.stack);
delete this.gettingNetworkers[getKey];
throw error;
}
} }
delete this.gettingNetworkers[getKey]; delete this.gettingNetworkers[getKey];
return cache[dcID] = networker;
}); });
} }
// mtpInvokeApi // mtpInvokeApi
public invokeApi(method: string, params: any = {}, options: Partial<{ public invokeApi(method: string, params: any = {}, options: InvokeApiOptions = {}) {
dcID: number,
timeout: number,
noErrorBox: boolean,
fileUpload: boolean,
ignoreErrors: boolean,
fileDownload: boolean,
createNetworker: boolean,
singleInRequest: boolean,
startMaxLength: number,
waitTime: number,
stopTime: number,
rawError: any
}> = {}) {
///////this.log('Invoke api', method, params, options); ///////this.log('Invoke api', method, params, options);
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -343,7 +333,6 @@ export class ApiManager {
public checkPassword(value: string): Promise<any> { public checkPassword(value: string): Promise<any> {
return passwordManager.getState() return passwordManager.getState()
.then(state => { .then(state => {
console.log(state);
return passwordManager.check(state, value); return passwordManager.check(state, value);
}); });
} }

71
src/lib/mtproto/dcConfigurator.ts

@ -3,19 +3,11 @@ import MTTransport from './transports/transport';
import HTTP from './transports/http'; import HTTP from './transports/http';
import { Modes } from './mtproto_config'; import { Modes } from './mtproto_config';
type TransportTypes = 'websocket' | 'https' | 'http';
type Servers = { type Servers = {
[transport: string]: { [transportType in TransportTypes]: {
[dcID: number]: MTTransport [dcID: number]: MTTransport[]
} }
/* websocket: {
[dcID: number]: Socket
},
https: {
[dcID: number]: HTTPTransport
},
http: {
[dcID: number]: HTTPTransport
} */
}; };
export class DcConfigurator { export class DcConfigurator {
@ -47,41 +39,50 @@ export class DcConfigurator {
http: {} http: {}
}; };
public chooseServer(dcID: number, upload?: boolean, transport = 'websocket') { public chooseServer(dcID: number, upload?: boolean, transportType: TransportTypes = 'websocket') {
let servers = upload && (transport != 'websocket' || Modes.multipleConnections) const servers = upload && (transportType != 'websocket' || Modes.multipleConnections)
? this.chosenUploadServers[transport] ? this.chosenUploadServers[transportType]
: this.chosenServers[transport]; : this.chosenServers[transportType];
if(!(dcID in servers)) { if(!(dcID in servers)) {
let chosenServer = ''; servers[dcID] = [];
}
if(transport == 'websocket') { const transports = servers[dcID];
let subdomain = this.sslSubdomains[dcID - 1];
let path = Modes.test ? 'apiws_test' : 'apiws';
chosenServer = 'wss://' + subdomain + '.web.telegram.org/' + path;
return servers[dcID] = new Socket(dcID, chosenServer);
}
if(Modes.ssl || !Modes.http || transport == 'https') { if(!transports.length || (upload && transports.length < 1)) {
let subdomain = this.sslSubdomains[dcID - 1] + (upload ? '-1' : ''); let transport: MTTransport;
let path = Modes.test ? 'apiw_test1' : 'apiw1';
chosenServer = 'https://' + subdomain + '.web.telegram.org/' + path;
return servers[dcID] = new HTTP(dcID, chosenServer);
}
for(let dcOption of this.dcOptions) { if(transportType == 'websocket') {
if(dcOption.id == dcID) { const subdomain = this.sslSubdomains[dcID - 1];
chosenServer = 'http://' + dcOption.host + (dcOption.port != 80 ? ':' + dcOption.port : '') + '/apiw1'; const path = Modes.test ? 'apiws_test' : 'apiws';
return servers[dcID] = new HTTP(dcID, chosenServer); const chosenServer = 'wss://' + subdomain + '.web.telegram.org/' + path;
transport = new Socket(dcID, chosenServer);
} else if(Modes.ssl || !Modes.http || transportType == 'https') {
const subdomain = this.sslSubdomains[dcID - 1] + (upload ? '-1' : '');
const path = Modes.test ? 'apiw_test1' : 'apiw1';
const chosenServer = 'https://' + subdomain + '.web.telegram.org/' + path;
transport = new HTTP(dcID, chosenServer);
} else {
for(let dcOption of this.dcOptions) {
if(dcOption.id == dcID) {
const chosenServer = 'http://' + dcOption.host + (dcOption.port != 80 ? ':' + dcOption.port : '') + '/apiw1';
transport = new HTTP(dcID, chosenServer);
break;
}
} }
} }
console.error('No chosenServer!', dcID); if(!transport) {
console.error('No chosenServer!', dcID);
return null;
}
return null; transports.push(transport);
return transport;
} }
return servers[dcID]; return transports[0];
} }
} }

58
src/lib/mtproto/networker.ts

@ -14,6 +14,7 @@ import Socket from './transports/websocket';
import HTTP from './transports/http'; import HTTP from './transports/http';
import { logger } from '../polyfill'; import { logger } from '../polyfill';
import { Modes, App } from './mtproto_config'; import { Modes, App } from './mtproto_config';
import { InvokeApiOptions } from '../../types';
//console.error('networker included!', new Error().stack); //console.error('networker included!', new Error().stack);
@ -90,14 +91,12 @@ class MTPNetworker {
private log: ReturnType<typeof logger>; private log: ReturnType<typeof logger>;
constructor(private dcID: number, private authKey: number[], private authKeyID: Uint8Array, constructor(private dcID: number, private authKey: number[], private authKeyID: Uint8Array,
private serverSalt: number[], private options: any = {}) { private serverSalt: number[], private options: InvokeApiOptions = {}) {
this.authKeyUint8 = convertToUint8Array(this.authKey); this.authKeyUint8 = convertToUint8Array(this.authKey);
//this.authKeyID = sha1BytesSync(this.authKey).slice(-8); //this.authKeyID = sha1BytesSync(this.authKey).slice(-8);
this.upload = this.options.fileUpload || this.options.fileDownload || false; this.upload = this.options.fileUpload || this.options.fileDownload || false;
this.log = logger('NET-' + dcID + (this.upload ? '-U' : '')); this.log = logger('NET-' + dcID + (this.upload ? '-U' : ''));
this.log('constructor'/* , this.authKey, this.authKeyID, this.serverSalt */); this.log('constructor'/* , this.authKey, this.authKeyID, this.serverSalt */);
this.updateSession(); this.updateSession();
@ -111,7 +110,7 @@ class MTPNetworker {
this.transport = dcConfigurator.chooseServer(this.dcID, this.upload); this.transport = dcConfigurator.chooseServer(this.dcID, this.upload);
if(this.transport instanceof HTTP) { if(this.transport instanceof HTTP) {
/* this.longPollInt = */window.setInterval(this.checkLongPoll.bind(this), 10000); /* this.longPollInt = */setInterval(this.checkLongPoll.bind(this), 10000);
this.checkLongPoll(); this.checkLongPoll();
} else { } else {
(this.transport as Socket).networker = this; (this.transport as Socket).networker = this;
@ -204,24 +203,7 @@ class MTPNetworker {
return this.pushMessage(message, options); return this.pushMessage(message, options);
} }
public wrapApiCall(method: string, params: any = {}, options: { public wrapApiCall(method: string, params: any = {}, options: InvokeApiOptions = {}) {
dcID?: number,
timeout?: number,
noErrorBox?: boolean,
fileUpload?: boolean,
ignoreErrors?: boolean,
fileDownload?: boolean,
createNetworker?: boolean,
singleInRequest?: boolean,
startMaxLength?: number,
afterMessageID?: string,
resultType?: boolean,
waitTime?: number,
stopTime?: number,
rawError?: any
} = {}) {
let serializer = new TLSerialization(options); let serializer = new TLSerialization(options);
if(!this.connectionInited) { // this will call once for each new session if(!this.connectionInited) { // this will call once for each new session
@ -293,7 +275,7 @@ class MTPNetworker {
} }
public checkLongPoll() { public checkLongPoll() {
var isClean = this.cleanupSent(); const isClean = this.cleanupSent();
//this.log('Check lp', this.longPollPending, tsNow(), this.dcID, isClean, this); //this.log('Check lp', this.longPollPending, tsNow(), this.dcID, isClean, this);
if((this.longPollPending && Date.now() < this.longPollPending) || if((this.longPollPending && Date.now() < this.longPollPending) ||
this.offline) { this.offline) {
@ -301,18 +283,17 @@ class MTPNetworker {
return false; return false;
} }
var self = this;
AppStorage.get<number>('dc').then((baseDcID: number) => { AppStorage.get<number>('dc').then((baseDcID: number) => {
if(isClean && ( if(isClean && (
baseDcID != self.dcID || baseDcID != this.dcID ||
self.upload || this.upload ||
(self.sleepAfter && Date.now() > self.sleepAfter) (this.sleepAfter && Date.now() > this.sleepAfter)
)) { )) {
//console.warn(dT(), 'Send long-poll for DC is delayed', self.dcID, self.sleepAfter); //console.warn(dT(), 'Send long-poll for DC is delayed', this.dcID, this.sleepAfter);
return; return;
} }
self.sendLongPoll(); this.sendLongPoll();
}); });
} }
@ -963,7 +944,7 @@ class MTPNetworker {
clearTimeout(this.nextReqTimeout); clearTimeout(this.nextReqTimeout);
this.nextReqTimeout = 0; this.nextReqTimeout = 0;
if(delay > 0) { if(delay > 0) {
this.nextReqTimeout = window.setTimeout(this.performScheduledRequest.bind(this), delay || 0); this.nextReqTimeout = setTimeout(this.performScheduledRequest.bind(this), delay || 0);
} else { } else {
setTimeout(this.performScheduledRequest.bind(this), 0); setTimeout(this.performScheduledRequest.bind(this), 0);
} }
@ -984,26 +965,25 @@ class MTPNetworker {
} }
public cleanupSent() { public cleanupSent() {
var self = this; let notEmpty = false;
var notEmpty = false;
// this.log('clean start', this.dcID/*, this.sentMessages*/) // this.log('clean start', this.dcID/*, this.sentMessages*/)
Object.keys(this.sentMessages).forEach((msgID) => { Object.keys(this.sentMessages).forEach((msgID) => {
let message = this.sentMessages[msgID]; const message = this.sentMessages[msgID];
// this.log('clean iter', msgID, message) // this.log('clean iter', msgID, message)
if(message.notContentRelated && self.pendingMessages[msgID] === undefined) { if(message.notContentRelated && this.pendingMessages[msgID] === undefined) {
// this.log('clean notContentRelated', msgID) // this.log('clean notContentRelated', msgID)
delete self.sentMessages[msgID]; delete this.sentMessages[msgID];
} else if(message.container) { } else if(message.container) {
for(var i = 0; i < message.inner.length; i++) { for(let i = 0; i < message.inner.length; i++) {
if(self.sentMessages[message.inner[i]] !== undefined) { if(this.sentMessages[message.inner[i]] !== undefined) {
// this.log('clean failed, found', msgID, message.inner[i], self.sentMessages[message.inner[i]].seq_no) // this.log('clean failed, found', msgID, message.inner[i], this.sentMessages[message.inner[i]].seq_no)
notEmpty = true; notEmpty = true;
return; return;
} }
} }
// this.log('clean container', msgID) // this.log('clean container', msgID)
delete self.sentMessages[msgID]; delete this.sentMessages[msgID];
} else { } else {
notEmpty = true; notEmpty = true;
} }

5
src/lib/mtproto/networkerFactory.ts

@ -1,4 +1,5 @@
import { MTPNetworker } from "./networker"; import { MTPNetworker } from "./networker";
import { InvokeApiOptions } from "../../types";
export class NetworkerFactory { export class NetworkerFactory {
public updatesProcessor: (obj: any, bool: boolean) => void = null; public updatesProcessor: (obj: any, bool: boolean) => void = null;
@ -7,8 +8,8 @@ export class NetworkerFactory {
this.updatesProcessor = callback; this.updatesProcessor = callback;
} }
public getNetworker(dcID: number, authKey: number[], authKeyID: Uint8Array, serverSalt: number[], options: any) { public getNetworker(dcID: number, authKey: number[], authKeyID: Uint8Array, serverSalt: number[], options: InvokeApiOptions) {
//console.log(dT(), 'NetworkerFactory: creating new instance of MTPNetworker:', dcID, options); //console.log('NetworkerFactory: creating new instance of MTPNetworker:', dcID, options);
return new MTPNetworker(dcID, authKey, authKeyID, serverSalt, options); return new MTPNetworker(dcID, authKey, authKeyID, serverSalt, options);
} }
} }

44
src/lib/mtproto/passwordManager.ts

@ -6,6 +6,8 @@ import {str2bigInt, greater, isZero,
bigInt2str, powMod, int2bigInt, mult, mod, sub, bitSize, negative, mult, add} from 'leemon/es/index/'; bigInt2str, powMod, int2bigInt, mult, mod, sub, bitSize, negative, mult, add} from 'leemon/es/index/';
export class PasswordManager { export class PasswordManager {
private log = (...args: any[]) => {};
public getState(options: any = {}) { public getState(options: any = {}) {
return apiManager.invokeApi('account.getPassword', {}, options).then((result) => { return apiManager.invokeApi('account.getPassword', {}, options).then((result) => {
return result return result
@ -89,19 +91,19 @@ export class PasswordManager {
let buffer = bufferConcats(client_salt, passwordBuffer, client_salt); let buffer = bufferConcats(client_salt, passwordBuffer, client_salt);
return CryptoWorker.sha256Hash(buffer).then((buffer: any) => { return CryptoWorker.sha256Hash(buffer).then((buffer: any) => {
console.log('encoded 1', bytesToHex(new Uint8Array(buffer))); this.log('encoded 1', bytesToHex(new Uint8Array(buffer)));
buffer = bufferConcats(server_salt, buffer, server_salt); buffer = bufferConcats(server_salt, buffer, server_salt);
return CryptoWorker.sha256Hash(buffer).then((buffer: any) => { return CryptoWorker.sha256Hash(buffer).then((buffer: any) => {
console.log('encoded 2', buffer, bytesToHex(new Uint8Array(buffer))); this.log('encoded 2', buffer, bytesToHex(new Uint8Array(buffer)));
return CryptoWorker.pbkdf2(new Uint8Array(buffer), client_salt, 100000).then((hash: any) => { return CryptoWorker.pbkdf2(new Uint8Array(buffer), client_salt, 100000).then((hash: any) => {
console.log('encoded 3', hash, bytesToHex(new Uint8Array(hash))); this.log('encoded 3', hash, bytesToHex(new Uint8Array(hash)));
hash = bufferConcats(server_salt, hash, server_salt); hash = bufferConcats(server_salt, hash, server_salt);
return CryptoWorker.sha256Hash(hash).then((buffer: any) => { return CryptoWorker.sha256Hash(hash).then((buffer: any) => {
console.log('got password hash:', buffer, bytesToHex(new Uint8Array(buffer))); this.log('got password hash:', buffer, bytesToHex(new Uint8Array(buffer)));
return buffer; return buffer;
}); });
@ -117,8 +119,8 @@ export class PasswordManager {
let B = str2bigInt(bytesToHex(state.srp_B), 16); let B = str2bigInt(bytesToHex(state.srp_B), 16);
let g = int2bigInt(algo.g, 32, 256); let g = int2bigInt(algo.g, 32, 256);
console.log('p', bigInt2str(p, 16)); this.log('p', bigInt2str(p, 16));
console.log('B', bigInt2str(B, 16)); this.log('B', bigInt2str(B, 16));
/* if(B.compareTo(BigInteger.ZERO) < 0) { /* if(B.compareTo(BigInteger.ZERO) < 0) {
console.error('srp_B < 0') console.error('srp_B < 0')
@ -144,7 +146,7 @@ export class PasswordManager {
new Uint8Array(algo.salt2)) as ArrayBuffer; new Uint8Array(algo.salt2)) as ArrayBuffer;
let x = str2bigInt(bytesToHex(new Uint8Array(pw_hash)), 16); let x = str2bigInt(bytesToHex(new Uint8Array(pw_hash)), 16);
console.warn('computed pw_hash:', pw_hash, x, bytesToHex(new Uint8Array(pw_hash))); this.log('computed pw_hash:', pw_hash, x, bytesToHex(new Uint8Array(pw_hash)));
var padArray = function(arr: any[], len: number, fill = 0) { var padArray = function(arr: any[], len: number, fill = 0) {
@ -155,25 +157,25 @@ export class PasswordManager {
let gForHash = padArray(bytesFromHex(bigInt2str(g, 16)), 256); // like uint8array let gForHash = padArray(bytesFromHex(bigInt2str(g, 16)), 256); // like uint8array
let b_for_hash = padArray(bytesFromHex(bigInt2str(B, 16)), 256); let b_for_hash = padArray(bytesFromHex(bigInt2str(B, 16)), 256);
console.log(bytesToHex(pForHash)); this.log(bytesToHex(pForHash));
console.log(bytesToHex(gForHash)); this.log(bytesToHex(gForHash));
console.log(bytesToHex(b_for_hash)); this.log(bytesToHex(b_for_hash));
let g_x = powMod(g, x, p); let g_x = powMod(g, x, p);
console.log('g_x', bigInt2str(g_x, 16)); this.log('g_x', bigInt2str(g_x, 16));
let k: any = await CryptoWorker.sha256Hash(bufferConcat(pForHash, gForHash)); let k: any = await CryptoWorker.sha256Hash(bufferConcat(pForHash, gForHash));
k = str2bigInt(bytesToHex(new Uint8Array(k)), 16); k = str2bigInt(bytesToHex(new Uint8Array(k)), 16);
console.log('k', bigInt2str(k, 16)); this.log('k', bigInt2str(k, 16));
// kg_x = (k * g_x) % p // kg_x = (k * g_x) % p
let kg_x = mod(mult(k, g_x), p); let kg_x = mod(mult(k, g_x), p);
// good // good
console.log('kg_x', bigInt2str(kg_x, 16)); this.log('kg_x', bigInt2str(kg_x, 16));
let is_good_mod_exp_first = (modexp: any, prime: any) => { let is_good_mod_exp_first = (modexp: any, prime: any) => {
let diff = sub(prime, modexp); let diff = sub(prime, modexp);
@ -217,12 +219,12 @@ export class PasswordManager {
let {a, a_for_hash, u} = await generate_and_check_random(); let {a, a_for_hash, u} = await generate_and_check_random();
console.log('a', bigInt2str(a, 16)); this.log('a', bigInt2str(a, 16));
console.log('a_for_hash', bytesToHex(a_for_hash)); this.log('a_for_hash', bytesToHex(a_for_hash));
console.log('u', bigInt2str(u, 16)); this.log('u', bigInt2str(u, 16));
// g_b = (B - kg_x) % p // g_b = (B - kg_x) % p
console.log('B - kg_x', bigInt2str(sub(B, kg_x), 16)); this.log('B - kg_x', bigInt2str(sub(B, kg_x), 16));
//let g_b = mod(sub(B, kg_x), p); //let g_b = mod(sub(B, kg_x), p);
/* let g_b = sub(B, kg_x); /* let g_b = sub(B, kg_x);
if(negative(g_b)) g_b = add(g_b, p); if(negative(g_b)) g_b = add(g_b, p);
@ -231,15 +233,15 @@ export class PasswordManager {
if(!negative(sub(B, kg_x))) g_b = sub(mod(B, p), kg_x); if(!negative(sub(B, kg_x))) g_b = sub(mod(B, p), kg_x);
else g_b = mod(sub(B, kg_x), p); */ else g_b = mod(sub(B, kg_x), p); */
/* let lol = trim(sub(B, kg_x), 10); /* let lol = trim(sub(B, kg_x), 10);
console.log('llalala', bigInt2str(lol, 16)); */ this.log('llalala', bigInt2str(lol, 16)); */
let g_b; let g_b;
if(!greater(B, kg_x)) { if(!greater(B, kg_x)) {
console.log('negative'); this.log('negative');
g_b = add(B, p); g_b = add(B, p);
} else g_b = B; } else g_b = B;
g_b = mod(sub(g_b, kg_x), p); g_b = mod(sub(g_b, kg_x), p);
//g_b = mod(g_b, p); //g_b = mod(g_b, p);
//console.log('g_b', bigInt2str(g_b, 16)); //this.log('g_b', bigInt2str(g_b, 16));
/* if(!is_good_mod_exp_first(g_b, p)) /* if(!is_good_mod_exp_first(g_b, p))
throw new Error('bad g_b'); */ throw new Error('bad g_b'); */
@ -277,7 +279,7 @@ export class PasswordManager {
}; };
console.log('out', bytesToHex(out.A), bytesToHex(out.M1)); this.log('out', bytesToHex(out.A), bytesToHex(out.M1));
return out; return out;
/* console.log(gForHash, pForHash, bForHash); */ /* console.log(gForHash, pForHash, bForHash); */

19
src/types.d.ts vendored

@ -43,3 +43,22 @@ export type MTPhotoSize = {
location?: any, location?: any,
bytes?: Uint8Array // if type == 'i' bytes?: Uint8Array // if type == 'i'
}; };
export type InvokeApiOptions = Partial<{
dcID: number,
timeout: number,
noErrorBox: boolean,
fileUpload: boolean,
ignoreErrors: boolean,
fileDownload: boolean,
createNetworker: boolean,
singleInRequest: boolean,
startMaxLength: number,
afterMessageID: string,
resultType: boolean,
waitTime: number,
stopTime: number,
rawError: any
}>;
Loading…
Cancel
Save