Browse Source

Password hint

Moved password manager from worker
master
morethanwords 4 years ago
parent
commit
65dc6b6ea4
  1. 2
      src/lib/crypto/crypto.worker.js
  2. 6
      src/lib/crypto/crypto_methods.ts
  3. 6
      src/lib/crypto/cryptoworker.ts
  4. 23
      src/lib/crypto/srp.ts
  5. 8
      src/lib/mtproto/apiManager.ts
  6. 5
      src/lib/mtproto/mtproto.worker.js
  7. 4
      src/lib/mtproto/mtprotoworker.ts
  8. 11
      src/lib/mtproto/passwordManager.ts
  9. 22
      src/pages/pagePassword.ts
  10. 4
      src/tests/srp.test.ts
  11. 27
      src/types.d.ts

2
src/lib/crypto/crypto.worker.js

@ -15,7 +15,7 @@ ctx.onmessage = function(e) {
result = null; result = null;
switch(e.data.task) { switch(e.data.task) {
case 'unzip': case 'gzipUncompress':
result = gzipUncompress.apply(null, e.data.args); result = gzipUncompress.apply(null, e.data.args);
break; break;

6
src/lib/crypto/crypto_methods.ts

@ -41,6 +41,10 @@ export default abstract class CryptoWorkerMethods {
} }
public gzipUncompress<T>(bytes: ArrayBuffer, toString?: boolean) { public gzipUncompress<T>(bytes: ArrayBuffer, toString?: boolean) {
return this.performTaskWorker<T>('unzip', bytes, toString); return this.performTaskWorker<T>('gzipUncompress', bytes, toString);
}
public computeSRP(password: string, state: any) {
return this.performTaskWorker('computeSRP', password, state);
} }
} }

6
src/lib/crypto/cryptoworker.ts

@ -38,8 +38,12 @@ class CryptoWorker extends CryptoWorkerMethods {
'rsa-encrypt': utils.rsaEncrypt, 'rsa-encrypt': utils.rsaEncrypt,
'factorize': utils.pqPrimeFactorization, 'factorize': utils.pqPrimeFactorization,
'mod-pow': utils.bytesModPow, 'mod-pow': utils.bytesModPow,
'unzip': utils.gzipUncompress 'gzipUncompress': utils.gzipUncompress,
}); });
}),
import('./srp').then(srp => {
this.utils.computeSRP = srp.computeSRP;
})/* , })/* ,
import('../bin_utils').then(utils => { import('../bin_utils').then(utils => {

23
src/lib/crypto/srp.ts

@ -5,6 +5,7 @@ import {str2bigInt, isZero,
bigInt2str, powMod, int2bigInt, mult, mod, sub, bitSize, negative, add, greater} from 'leemon'; bigInt2str, powMod, int2bigInt, mult, mod, sub, bitSize, negative, add, greater} from 'leemon';
import {logger, LogLevels} from '../logger'; import {logger, LogLevels} from '../logger';
import { AccountPassword } from "../../types";
const log = logger('SRP', LogLevels.error); const log = logger('SRP', LogLevels.error);
@ -31,27 +32,7 @@ export async function makePasswordHash(password: string, client_salt: Uint8Array
return buffer; return buffer;
} }
type Algo = { export async function computeSRP(password: string, state: AccountPassword) {
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
}) {
//console.log('computeCheck:', password, state); //console.log('computeCheck:', password, state);
let algo = state.current_algo; let algo = state.current_algo;

8
src/lib/mtproto/apiManager.ts

@ -9,7 +9,6 @@ import {App, Modes} from './mtproto_config';
import dcConfigurator from './dcConfigurator'; import dcConfigurator from './dcConfigurator';
import HTTP from './transports/http'; import HTTP from './transports/http';
import { logger } from '../logger'; import { logger } from '../logger';
import passwordManager from './passwordManager';
/// #if !MTPROTO_WORKER /// #if !MTPROTO_WORKER
import { $rootScope } from '../utils'; import { $rootScope } from '../utils';
@ -329,13 +328,6 @@ export class ApiManager {
return auth.id || 0; return auth.id || 0;
}); });
} }
public checkPassword(value: string): Promise<any> {
return passwordManager.getState()
.then(state => {
return passwordManager.check(state, value);
});
}
} }
export default new ApiManager(); export default new ApiManager();

5
src/lib/mtproto/mtproto.worker.js

@ -85,8 +85,9 @@ ctx.onmessage = function(e) {
} }
switch(e.data.task) { switch(e.data.task) {
case 'unzip': case 'computeSRP':
return cryptoWorker.gzipUncompress.apply(cryptoWorker, e.data.args).then(result => { case 'gzipUncompress':
return cryptoWorker[e.data.task].apply(cryptoWorker, e.data.args).then(result => {
//ctx.postMessage({taskID: taskID, result: result}); //ctx.postMessage({taskID: taskID, result: result});
reply({taskID: taskID, result: result}); reply({taskID: taskID, result: result});
}); });

4
src/lib/mtproto/mtprotoworker.ts

@ -145,10 +145,6 @@ class ApiManagerProxy extends CryptoWorkerMethods {
public logOut(): Promise<void> { public logOut(): Promise<void> {
return this.performTaskWorker('logOut'); return this.performTaskWorker('logOut');
} }
public checkPassword(value: string): Promise<any> {
return this.performTaskWorker('checkPassword', value);
}
} }
const apiManagerProxy = new ApiManagerProxy(); const apiManagerProxy = new ApiManagerProxy();

11
src/lib/mtproto/passwordManager.ts

@ -1,8 +1,9 @@
import apiManager from "./apiManager"; import apiManager from './mtprotoworker';
import { computeCheck } from "../crypto/srp"; import { AccountPassword } from '../../types';
//import { computeCheck } from "../crypto/srp";
export class PasswordManager { export class PasswordManager {
public getState(options: any = {}) { public getState(options: any = {}): Promise<AccountPassword> {
return apiManager.invokeApi('account.getPassword', {}, options).then((result) => { return apiManager.invokeApi('account.getPassword', {}, options).then((result) => {
return result; return result;
}); });
@ -55,8 +56,8 @@ export class PasswordManager {
}); });
} */ } */
public check(state: any, password: string, options: any = {}) { public check(password: string, state: AccountPassword, options: any = {}) {
return computeCheck(password, state).then((inputCheckPassword) => { return apiManager.computeSRP(password, state).then((inputCheckPassword) => {
return apiManager.invokeApi('auth.checkPassword', { return apiManager.invokeApi('auth.checkPassword', {
password: inputCheckPassword password: inputCheckPassword
}, options); }, options);

22
src/pages/pagePassword.ts

@ -8,6 +8,8 @@ import LottieLoader, { RLottiePlayer } from '../lib/lottieLoader';
import apiManager from '../lib/mtproto/mtprotoworker'; import apiManager from '../lib/mtproto/mtprotoworker';
import Page from './page'; import Page from './page';
import { mediaSizes } from '../lib/config'; import { mediaSizes } from '../lib/config';
import passwordManager from '../lib/mtproto/passwordManager';
import { AccountPassword } from '../types';
let onFirstMount = (): Promise<any> => { let onFirstMount = (): Promise<any> => {
let needFrame = 0; let needFrame = 0;
@ -17,9 +19,17 @@ let onFirstMount = (): Promise<any> => {
const btnNext = page.pageEl.querySelector('button') as HTMLButtonElement; const btnNext = page.pageEl.querySelector('button') as HTMLButtonElement;
const passwordInput = document.getElementById('password') as HTMLInputElement; 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; 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) => { let handleError = (err: any) => {
btnNext.removeAttribute('disabled'); btnNext.removeAttribute('disabled');
@ -28,6 +38,8 @@ let onFirstMount = (): Promise<any> => {
btnNext.innerText = err.type; btnNext.innerText = err.type;
break; break;
} }
getState();
}; };
toggleVisible.addEventListener('click', function(this, e) { toggleVisible.addEventListener('click', function(this, e) {
@ -50,6 +62,8 @@ let onFirstMount = (): Promise<any> => {
} }
}); });
let state: AccountPassword;
btnNext.addEventListener('click', function(this, e) { btnNext.addEventListener('click', function(this, e) {
if(!passwordInput.value.length) { if(!passwordInput.value.length) {
passwordInput.classList.add('error'); passwordInput.classList.add('error');
@ -62,7 +76,7 @@ let onFirstMount = (): Promise<any> => {
this.textContent = 'PLEASE WAIT...'; this.textContent = 'PLEASE WAIT...';
putPreloader(this); putPreloader(this);
apiManager.checkPassword(value).then((response: any) => { passwordManager.check(value, state).then((response: any) => {
//console.log('passwordManager response:', response); //console.log('passwordManager response:', response);
switch(response._) { switch(response._) {
@ -118,7 +132,9 @@ let onFirstMount = (): Promise<any> => {
needFrame = 49; needFrame = 49;
//animation.play(); //animation.play();
}) }),
getState()
]); ]);
}; };

4
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 { 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() => { test('2FA hash', async() => {
const bytes = await makePasswordHash(password, salt1, salt2); const bytes = await makePasswordHash(password, salt1, salt2);
@ -7,7 +7,7 @@ test('2FA hash', async() => {
}); });
test('2FA whole (with negative)', async() => { test('2FA whole (with negative)', async() => {
return await computeCheck(password, { return await computeSRP(password, {
current_algo: { current_algo: {
salt1, salt1,
salt2, salt2,

27
src/types.d.ts vendored

@ -62,4 +62,29 @@ export type InvokeApiOptions = Partial<{
waitTime: number, waitTime: number,
stopTime: number, stopTime: number,
rawError: any rawError: any
}>; }>;
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,
};
Loading…
Cancel
Save