From 65dc6b6ea4d6f3260825e8e4f8113cec03c3bedf Mon Sep 17 00:00:00 2001 From: morethanwords Date: Tue, 18 Aug 2020 21:31:30 +0300 Subject: [PATCH] Password hint Moved password manager from worker --- src/lib/crypto/crypto.worker.js | 2 +- src/lib/crypto/crypto_methods.ts | 6 +++++- src/lib/crypto/cryptoworker.ts | 6 +++++- src/lib/crypto/srp.ts | 23 ++--------------------- src/lib/mtproto/apiManager.ts | 8 -------- src/lib/mtproto/mtproto.worker.js | 5 +++-- src/lib/mtproto/mtprotoworker.ts | 4 ---- src/lib/mtproto/passwordManager.ts | 11 ++++++----- src/pages/pagePassword.ts | 22 +++++++++++++++++++--- src/tests/srp.test.ts | 4 ++-- src/types.d.ts | 27 ++++++++++++++++++++++++++- 11 files changed, 69 insertions(+), 49 deletions(-) diff --git a/src/lib/crypto/crypto.worker.js b/src/lib/crypto/crypto.worker.js index f63211cd..cb23fa12 100644 --- a/src/lib/crypto/crypto.worker.js +++ b/src/lib/crypto/crypto.worker.js @@ -15,7 +15,7 @@ ctx.onmessage = function(e) { result = null; switch(e.data.task) { - case 'unzip': + case 'gzipUncompress': result = gzipUncompress.apply(null, e.data.args); break; diff --git a/src/lib/crypto/crypto_methods.ts b/src/lib/crypto/crypto_methods.ts index 91d8b668..c81b984a 100644 --- a/src/lib/crypto/crypto_methods.ts +++ b/src/lib/crypto/crypto_methods.ts @@ -41,6 +41,10 @@ export default abstract class CryptoWorkerMethods { } public gzipUncompress(bytes: ArrayBuffer, toString?: boolean) { - return this.performTaskWorker('unzip', bytes, toString); + return this.performTaskWorker('gzipUncompress', bytes, toString); + } + + public computeSRP(password: string, state: any) { + return this.performTaskWorker('computeSRP', password, state); } } \ No newline at end of file diff --git a/src/lib/crypto/cryptoworker.ts b/src/lib/crypto/cryptoworker.ts index 46506fbb..0c4852e0 100644 --- a/src/lib/crypto/cryptoworker.ts +++ b/src/lib/crypto/cryptoworker.ts @@ -38,8 +38,12 @@ class CryptoWorker extends CryptoWorkerMethods { 'rsa-encrypt': utils.rsaEncrypt, 'factorize': utils.pqPrimeFactorization, 'mod-pow': utils.bytesModPow, - 'unzip': utils.gzipUncompress + 'gzipUncompress': utils.gzipUncompress, }); + }), + + import('./srp').then(srp => { + this.utils.computeSRP = srp.computeSRP; })/* , import('../bin_utils').then(utils => { diff --git a/src/lib/crypto/srp.ts b/src/lib/crypto/srp.ts index 22222f4a..1c993950 100644 --- a/src/lib/crypto/srp.ts +++ b/src/lib/crypto/srp.ts @@ -5,6 +5,7 @@ import {str2bigInt, isZero, bigInt2str, powMod, int2bigInt, mult, mod, sub, bitSize, negative, add, greater} from 'leemon'; import {logger, LogLevels} from '../logger'; +import { AccountPassword } from "../../types"; const log = logger('SRP', LogLevels.error); @@ -31,27 +32,7 @@ export async function makePasswordHash(password: string, client_salt: Uint8Array return buffer; } -type Algo = { - salt1: Uint8Array, - salt2: Uint8Array, - p: Uint8Array, - g: number -}; - -export async function computeCheck(password: string, state: { - _?: 'accont.password', - flags?: number, - pFlags?: Partial<{ - has_recovery: true, - has_password: true - }>, - current_algo: Algo, - new_algo?: Algo, - new_secure_algo?: Algo, - srp_B: Uint8Array, - srp_id: string, - secure_random: Uint8Array -}) { +export async function computeSRP(password: string, state: AccountPassword) { //console.log('computeCheck:', password, state); let algo = state.current_algo; diff --git a/src/lib/mtproto/apiManager.ts b/src/lib/mtproto/apiManager.ts index bb97740c..439388ac 100644 --- a/src/lib/mtproto/apiManager.ts +++ b/src/lib/mtproto/apiManager.ts @@ -9,7 +9,6 @@ import {App, Modes} from './mtproto_config'; import dcConfigurator from './dcConfigurator'; import HTTP from './transports/http'; import { logger } from '../logger'; -import passwordManager from './passwordManager'; /// #if !MTPROTO_WORKER import { $rootScope } from '../utils'; @@ -329,13 +328,6 @@ export class ApiManager { return auth.id || 0; }); } - - public checkPassword(value: string): Promise { - return passwordManager.getState() - .then(state => { - return passwordManager.check(state, value); - }); - } } export default new ApiManager(); diff --git a/src/lib/mtproto/mtproto.worker.js b/src/lib/mtproto/mtproto.worker.js index abc134b2..25e72093 100644 --- a/src/lib/mtproto/mtproto.worker.js +++ b/src/lib/mtproto/mtproto.worker.js @@ -85,8 +85,9 @@ ctx.onmessage = function(e) { } switch(e.data.task) { - case 'unzip': - return cryptoWorker.gzipUncompress.apply(cryptoWorker, e.data.args).then(result => { + case 'computeSRP': + case 'gzipUncompress': + return cryptoWorker[e.data.task].apply(cryptoWorker, e.data.args).then(result => { //ctx.postMessage({taskID: taskID, result: result}); reply({taskID: taskID, result: result}); }); diff --git a/src/lib/mtproto/mtprotoworker.ts b/src/lib/mtproto/mtprotoworker.ts index 1108d1bd..95fbd88c 100644 --- a/src/lib/mtproto/mtprotoworker.ts +++ b/src/lib/mtproto/mtprotoworker.ts @@ -145,10 +145,6 @@ class ApiManagerProxy extends CryptoWorkerMethods { public logOut(): Promise { return this.performTaskWorker('logOut'); } - - public checkPassword(value: string): Promise { - return this.performTaskWorker('checkPassword', value); - } } const apiManagerProxy = new ApiManagerProxy(); diff --git a/src/lib/mtproto/passwordManager.ts b/src/lib/mtproto/passwordManager.ts index 9fd66734..d39e14b3 100644 --- a/src/lib/mtproto/passwordManager.ts +++ b/src/lib/mtproto/passwordManager.ts @@ -1,8 +1,9 @@ -import apiManager from "./apiManager"; -import { computeCheck } from "../crypto/srp"; +import apiManager from './mtprotoworker'; +import { AccountPassword } from '../../types'; +//import { computeCheck } from "../crypto/srp"; export class PasswordManager { - public getState(options: any = {}) { + public getState(options: any = {}): Promise { return apiManager.invokeApi('account.getPassword', {}, options).then((result) => { return result; }); @@ -55,8 +56,8 @@ export class PasswordManager { }); } */ - public check(state: any, password: string, options: any = {}) { - return computeCheck(password, state).then((inputCheckPassword) => { + public check(password: string, state: AccountPassword, options: any = {}) { + return apiManager.computeSRP(password, state).then((inputCheckPassword) => { return apiManager.invokeApi('auth.checkPassword', { password: inputCheckPassword }, options); diff --git a/src/pages/pagePassword.ts b/src/pages/pagePassword.ts index 7ae6400f..a24daba6 100644 --- a/src/pages/pagePassword.ts +++ b/src/pages/pagePassword.ts @@ -8,6 +8,8 @@ import LottieLoader, { RLottiePlayer } from '../lib/lottieLoader'; import apiManager from '../lib/mtproto/mtprotoworker'; import Page from './page'; import { mediaSizes } from '../lib/config'; +import passwordManager from '../lib/mtproto/passwordManager'; +import { AccountPassword } from '../types'; let onFirstMount = (): Promise => { let needFrame = 0; @@ -17,9 +19,17 @@ let onFirstMount = (): Promise => { const btnNext = page.pageEl.querySelector('button') as HTMLButtonElement; const passwordInput = document.getElementById('password') as HTMLInputElement; - //const passwordInputLabel = passwordInput.nextElementSibling as HTMLLabelElement; + const passwordInputLabel = passwordInput.nextElementSibling as HTMLLabelElement; const toggleVisible = page.pageEl.querySelector('.toggle-visible') as HTMLSpanElement; + let getState = () => { + return passwordManager.getState().then(_state => { + state = _state; + + passwordInputLabel.innerText = state.hint ?? 'Password'; + }); + }; + let handleError = (err: any) => { btnNext.removeAttribute('disabled'); @@ -28,6 +38,8 @@ let onFirstMount = (): Promise => { btnNext.innerText = err.type; break; } + + getState(); }; toggleVisible.addEventListener('click', function(this, e) { @@ -50,6 +62,8 @@ let onFirstMount = (): Promise => { } }); + let state: AccountPassword; + btnNext.addEventListener('click', function(this, e) { if(!passwordInput.value.length) { passwordInput.classList.add('error'); @@ -62,7 +76,7 @@ let onFirstMount = (): Promise => { this.textContent = 'PLEASE WAIT...'; putPreloader(this); - apiManager.checkPassword(value).then((response: any) => { + passwordManager.check(value, state).then((response: any) => { //console.log('passwordManager response:', response); switch(response._) { @@ -118,7 +132,9 @@ let onFirstMount = (): Promise => { needFrame = 49; //animation.play(); - }) + }), + + getState() ]); }; diff --git a/src/tests/srp.test.ts b/src/tests/srp.test.ts index 4b4ef2af..762b3c9e 100644 --- a/src/tests/srp.test.ts +++ b/src/tests/srp.test.ts @@ -1,5 +1,5 @@ import { salt1, salt2, g, p, srp_id, secure_random, srp_B, password, A, M1, passwordHashed } from '../mock/srp'; -import { computeCheck, makePasswordHash } from '../lib/crypto/srp'; +import { computeSRP, makePasswordHash } from '../lib/crypto/srp'; test('2FA hash', async() => { const bytes = await makePasswordHash(password, salt1, salt2); @@ -7,7 +7,7 @@ test('2FA hash', async() => { }); test('2FA whole (with negative)', async() => { - return await computeCheck(password, { + return await computeSRP(password, { current_algo: { salt1, salt2, diff --git a/src/types.d.ts b/src/types.d.ts index 9850c8ac..6c00c499 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -62,4 +62,29 @@ export type InvokeApiOptions = Partial<{ waitTime: number, stopTime: number, rawError: any -}>; \ No newline at end of file +}>; + +type Algo = { + salt1: Uint8Array, + salt2: Uint8Array, + p: Uint8Array, + g: number +}; + +export type AccountPassword = { + _?: 'accont.password', + flags?: number, + pFlags?: Partial<{ + has_recovery: true, + has_secure_values: true, + has_password: true + }>, + current_algo: Algo, + new_algo?: Algo, + new_secure_algo?: Algo, + hint?: string, + email_unconfirmed_pattern?: string, + srp_B?: Uint8Array, + srp_id?: string, + secure_random: Uint8Array, +}; \ No newline at end of file