Browse Source

Temp 2FA commit

master
morethanwords 4 years ago
parent
commit
3e514c1caa
  1. 144
      src/components/monkeys/tracking.ts
  2. 100
      src/components/sidebarLeft/tabs/2fa/email.ts
  3. 19
      src/components/sidebarLeft/tabs/2fa/enterPassword.ts
  4. 91
      src/components/sidebarLeft/tabs/2fa/hint.ts
  5. 9
      src/components/sidebarLeft/tabs/2fa/index.ts
  6. 27
      src/components/sidebarLeft/tabs/2fa/reEnterPassword.ts
  7. 4
      src/lib/crypto/crypto_methods.ts
  8. 11
      src/lib/crypto/srp.ts
  9. 4
      src/lib/mtproto/passwordManager.ts
  10. 216
      src/pages/pageAuthCode.ts
  11. 11
      src/scss/partials/_button.scss
  12. 24
      src/scss/partials/_leftSidebar.scss

144
src/components/monkeys/tracking.ts

@ -0,0 +1,144 @@ @@ -0,0 +1,144 @@
import InputField from "../inputField";
import lottieLoader, { RLottiePlayer } from "../../lib/lottieLoader";
export default class TrackingMonkey {
public container: HTMLElement;
protected max = 45;
protected needFrame = 0;
protected animation: RLottiePlayer;
protected idleAnimation: RLottiePlayer;
protected loadPromise: Promise<any>;
constructor(protected inputField: InputField, protected size: number) {
this.container = document.createElement('div');
this.container.classList.add('media-sticker-wrapper');
const input = inputField.input;
input.addEventListener('blur', () => {
this.playAnimation(0);
});
input.addEventListener('input', (e) => {
this.playAnimation(inputField.value.length);
});
/* codeInput.addEventListener('focus', () => {
playAnimation(Math.max(codeInput.value.length, 1));
}); */
}
// 1st symbol = frame 15
// end symbol = frame 165
public playAnimation(length: number) {
if(!this.animation) return;
length = Math.min(length, 30);
let frame: number;
if(length) {
frame = Math.round(Math.min(this.max, length) * (165 / this.max) + 11.33);
if(this.idleAnimation) {
this.idleAnimation.stop(true);
this.idleAnimation.canvas.style.display = 'none';
}
this.animation.canvas.style.display = '';
} else {
/* const cb = (frameNo: number) => {
if(frameNo <= 1) { */
/* idleAnimation.play();
idleAnimation.canvas.style.display = '';
animation.canvas.style.display = 'none'; */
/* animation.removeListener('enterFrame', cb);
}
};
animation.addListener('enterFrame', cb); */
frame = 0;
}
//animation.playSegments([1, 2]);
const direction = this.needFrame > frame ? -1 : 1;
//console.log('keydown', length, frame, direction);
this.animation.setDirection(direction);
if(this.needFrame !== 0 && frame === 0) {
this.animation.setSpeed(7);
}
/* let diff = Math.abs(needFrame - frame * direction);
if((diff / 20) > 1) animation.setSpeed(diff / 20 | 0); */
this.needFrame = frame;
this.animation.play();
/* animation.goToAndStop(15, true); */
//animation.goToAndStop(length / max * );
}
public load() {
if(this.loadPromise) return this.loadPromise;
this.loadPromise = Promise.all([
lottieLoader.loadAnimationFromURL({
container: this.container,
loop: true,
autoplay: true,
width: this.size,
height: this.size
}, 'assets/img/TwoFactorSetupMonkeyIdle.tgs').then(animation => {
this.idleAnimation = animation;
// ! animationIntersector will stop animation instantly
if(!this.inputField.value.length) {
animation.play();
}
}),
lottieLoader.loadAnimationFromURL({
container: this.container,
loop: false,
autoplay: false,
width: this.size,
height: this.size
}, 'assets/img/TwoFactorSetupMonkeyTracking.tgs').then(_animation => {
this.animation = _animation;
if(!this.inputField.value.length) {
this.animation.canvas.style.display = 'none';
}
this.animation.addListener('enterFrame', currentFrame => {
//console.log('enterFrame', currentFrame, needFrame);
//let currentFrame = Math.round(e.currentTime);
if((this.animation.direction === 1 && currentFrame >= this.needFrame) ||
(this.animation.direction === -1 && currentFrame <= this.needFrame)) {
this.animation.setSpeed(1);
this.animation.pause();
}
if(currentFrame === 0 && this.needFrame === 0) {
//animation.curFrame = 0;
if(this.idleAnimation) {
this.idleAnimation.canvas.style.display = '';
this.idleAnimation.play();
this.animation.canvas.style.display = 'none';
}
}
});
//console.log(animation.getDuration(), animation.getDuration(true));
})
]);
}
public remove() {
if(this.animation) this.animation.remove();
if(this.idleAnimation) this.idleAnimation.remove();
}
}

100
src/components/sidebarLeft/tabs/2fa/email.ts

@ -0,0 +1,100 @@ @@ -0,0 +1,100 @@
import { SettingSection } from "../..";
import { AccountPassword } from "../../../../layer";
import appStickersManager from "../../../../lib/appManagers/appStickersManager";
import Button from "../../../button";
import SidebarSlider, { SliderSuperTab } from "../../../slider";
import { wrapSticker } from "../../../wrappers";
import InputField from "../../../inputField";
import { attachClickEvent } from "../../../../helpers/dom";
import PopupConfirmAction from "../../../popups/confirmAction";
import { putPreloader } from "../../../misc";
import passwordManager from "../../../../lib/mtproto/passwordManager";
export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
public inputField: InputField;
public state: AccountPassword;
public plainPassword: string;
public newPassword: string;
public hint: string;
constructor(slider: SidebarSlider) {
super(slider, true);
}
protected init() {
this.container.classList.add('two-step-verification-email');
this.title.innerHTML = 'Recovery Email';
const section = new SettingSection({
caption: ' ',
noDelimiter: true
});
const emoji = '💌';
const doc = appStickersManager.getAnimatedEmojiSticker(emoji);
const stickerContainer = document.createElement('div');
wrapSticker({
doc,
div: stickerContainer,
loop: false,
play: true,
width: 168,
height: 168,
emoji
}).then(() => {
// this.animation = player;
});
section.content.append(stickerContainer);
const inputContent = section.generateContentElement();
const inputWrapper = document.createElement('div');
inputWrapper.classList.add('input-wrapper');
const inputField = this.inputField = new InputField({
name: 'recovery-email',
label: 'Recovery Email'
});
const btnContinue = Button('btn-primary', {text: 'CONTINUE'});
const btnSkip = Button('btn-primary btn-primary-transparent primary', {text: 'SKIP'});
attachClickEvent(btnSkip, (e) => {
const popup = new PopupConfirmAction('popup-skip-email', [{
text: 'CANCEL',
isCancel: true
}, {
text: 'SKIP',
callback: () => {
inputContent.classList.add('sidebar-left-section-disabled');
putPreloader(btnSkip);
passwordManager.updateSettings({
hint: this.hint,
currentPassword: this.plainPassword,
newPassword: this.newPassword
}).then(() => {
});
},
isDanger: true,
}], {
title: 'Warning',
text: 'No, seriously.<br/><br/>If you forget your password, you will<br/>lose access to your Telegram account.<br/>There will be no way to restore it.'
});
popup.show();
});
inputWrapper.append(inputField.container, btnContinue, btnSkip);
inputContent.append(inputWrapper);
this.scrollable.container.append(section.container);
}
onOpenAfterTimeout() {
this.inputField.input.focus();
}
}

19
src/components/sidebarLeft/tabs/2fa/enterPassword.ts

@ -13,14 +13,17 @@ import AppTwoStepVerificationReEnterPasswordTab from "./reEnterPassword"; @@ -13,14 +13,17 @@ import AppTwoStepVerificationReEnterPasswordTab from "./reEnterPassword";
export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperTab {
public state: AccountPassword;
public passwordInputField: PasswordInputField;
public plainPassword: string;
constructor(slider: SidebarSlider) {
super(slider, true);
}
protected init() {
const isNew = !this.state.pFlags.has_password || this.plainPassword;
this.container.classList.add('two-step-verification-enter-password');
this.title.innerHTML = this.state.pFlags.has_password ? 'Enter Your Password' : 'Enter a Password';
this.title.innerHTML = isNew ? 'Enter a Password' : 'Enter your Password';
const section = new SettingSection({
noDelimiter: true
@ -29,9 +32,9 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT @@ -29,9 +32,9 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT
const inputWrapper = document.createElement('div');
inputWrapper.classList.add('input-wrapper');
const passwordInputField = new PasswordInputField({
name: 'first-password',
label: this.state.pFlags.has_password ? this.state.hint ?? 'Password' : 'Enter a Password'
const passwordInputField = this.passwordInputField = new PasswordInputField({
name: 'enter-password',
label: isNew ? 'Enter a Password' : (this.state.hint ?? 'Password')
});
const monkey = new PasswordMonkey(passwordInputField, 157);
@ -65,7 +68,7 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT @@ -65,7 +68,7 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT
return true;
};
if(this.state.pFlags.has_password) {
if(!isNew) {
let getStateInterval: number;
let getState = () => {
@ -128,8 +131,14 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT @@ -128,8 +131,14 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT
const tab = new AppTwoStepVerificationReEnterPasswordTab(this.slider);
tab.state = this.state;
tab.newPassword = passwordInputField.value;
tab.plainPassword = this.plainPassword;
tab.open();
});
}
}
onOpenAfterTimeout() {
this.passwordInputField.input.focus();
}
}

91
src/components/sidebarLeft/tabs/2fa/hint.ts

@ -0,0 +1,91 @@ @@ -0,0 +1,91 @@
import { SettingSection } from "../..";
import { AccountPassword } from "../../../../layer";
import appStickersManager from "../../../../lib/appManagers/appStickersManager";
import Button from "../../../button";
import SidebarSlider, { SliderSuperTab } from "../../../slider";
import { wrapSticker } from "../../../wrappers";
import InputField from "../../../inputField";
import AppTwoStepVerificationEmailTab from "./email";
import { attachClickEvent, cancelEvent } from "../../../../helpers/dom";
export default class AppTwoStepVerificationHintTab extends SliderSuperTab {
public inputField: InputField;
public state: AccountPassword;
public plainPassword: string;
public newPassword: string;
constructor(slider: SidebarSlider) {
super(slider, true);
}
protected init() {
this.container.classList.add('two-step-verification-hint');
this.title.innerHTML = 'Password Hint';
const section = new SettingSection({
caption: ' ',
noDelimiter: true
});
const emoji = '💡';
const doc = appStickersManager.getAnimatedEmojiSticker(emoji);
const stickerContainer = document.createElement('div');
wrapSticker({
doc,
div: stickerContainer,
loop: false,
play: true,
width: 168,
height: 168,
emoji
}).then(() => {
// this.animation = player;
});
section.content.append(stickerContainer);
const inputWrapper = document.createElement('div');
inputWrapper.classList.add('input-wrapper');
const inputField = this.inputField = new InputField({
name: 'hint',
label: 'Hint'
});
inputField.input.addEventListener('keypress', (e) => {
if(e.key === 'Enter') {
return (inputField.value ? btnContinue : btnSkip).click();
}
});
const goNext = (e: Event, saveHint: boolean) => {
cancelEvent(e);
const tab = new AppTwoStepVerificationEmailTab(this.slider);
tab.state = this.state;
tab.plainPassword = this.plainPassword;
tab.newPassword = this.newPassword;
if(saveHint) {
tab.hint = inputField.value;
}
tab.open();
};
const btnContinue = Button('btn-primary', {text: 'CONTINUE'});
const btnSkip = Button('btn-primary btn-primary-transparent primary', {text: 'SKIP'});
attachClickEvent(btnContinue, (e) => goNext(e, true));
attachClickEvent(btnSkip, (e) => goNext(e, false));
inputWrapper.append(inputField.container, btnContinue, btnSkip);
section.content.append(inputWrapper);
this.scrollable.container.append(section.container);
}
onOpenAfterTimeout() {
this.inputField.input.focus();
}
}

9
src/components/sidebarLeft/tabs/2fa/index.ts

@ -52,6 +52,13 @@ export default class AppTwoStepVerificationTab extends SliderSuperTab { @@ -52,6 +52,13 @@ export default class AppTwoStepVerificationTab extends SliderSuperTab {
const btnDisablePassword = Button('btn-primary btn-transparent', {icon: 'passwordoff', text: 'Turn Password Off'});
const btnSetRecoveryEmail = Button('btn-primary btn-transparent', {icon: 'email', text: 'Set Recovery Email'});
attachClickEvent(btnChangePassword, () => {
const tab = new AppTwoStepVerificationEnterPasswordTab(this.slider);
tab.state = this.state;
tab.plainPassword = this.plainPassword;
tab.open();
});
attachClickEvent(btnDisablePassword, () => {
const popup = new PopupConfirmAction('popup-disable-password', [{
text: 'DISABLE',
@ -61,7 +68,7 @@ export default class AppTwoStepVerificationTab extends SliderSuperTab { @@ -61,7 +68,7 @@ export default class AppTwoStepVerificationTab extends SliderSuperTab {
isDanger: true,
}], {
title: 'Warning',
text: 'Are you sure you want to disable your password?'
text: 'Are you sure you want to disable<br/>your password?'
});
popup.show();

27
src/components/sidebarLeft/tabs/2fa/reEnterPassword.ts

@ -1,24 +1,25 @@ @@ -1,24 +1,25 @@
import AppTwoStepVerificationTab from ".";
import { SettingSection } from "../..";
import { attachClickEvent, cancelEvent } from "../../../../helpers/dom";
import { AccountPassword } from "../../../../layer";
import passwordManager from "../../../../lib/mtproto/passwordManager";
import Button from "../../../button";
import { putPreloader } from "../../../misc";
import PasswordMonkey from "../../../monkeys/password";
import PasswordInputField from "../../../passwordInputField";
import { ripple } from "../../../ripple";
import SidebarSlider, { SliderSuperTab } from "../../../slider";
import TrackingMonkey from "../../../monkeys/tracking";
import AppTwoStepVerificationHintTab from "./hint";
export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSuperTab {
public state: AccountPassword;
public passwordInputField: PasswordInputField;
public plainPassword: string;
public newPassword: string;
constructor(slider: SidebarSlider) {
super(slider, true);
}
protected init() {
this.container.classList.add('two-step-verification-enter-password');
this.container.classList.add('two-step-verification-enter-password', 'two-step-verification-re-enter-password');
this.title.innerHTML = 'Re-Enter your Password';
const section = new SettingSection({
@ -28,12 +29,12 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe @@ -28,12 +29,12 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe
const inputWrapper = document.createElement('div');
inputWrapper.classList.add('input-wrapper');
const passwordInputField = new PasswordInputField({
const passwordInputField = this.passwordInputField = new PasswordInputField({
name: 're-enter-password',
label: 'Re-Enter your Password'
});
const monkey = new PasswordMonkey(passwordInputField, 157);
const monkey = new TrackingMonkey(passwordInputField, 157);
monkey.load();
const btnContinue = Button('btn-primary', {text: 'CONTINUE'});
@ -56,7 +57,7 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe @@ -56,7 +57,7 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe
});
const verifyInput = () => {
if(!passwordInputField.value.length) {
if(this.newPassword !== passwordInputField.value) {
passwordInputField.input.classList.add('error');
return false;
}
@ -68,7 +69,15 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe @@ -68,7 +69,15 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe
cancelEvent(e);
if(!verifyInput()) return;
const tab = new AppTwoStepVerificationHintTab(this.slider);
tab.state = this.state;
tab.plainPassword = this.plainPassword;
tab.newPassword = this.newPassword;
tab.open();
});
}
onOpenAfterTimeout() {
this.passwordInputField.input.focus();
}
}

4
src/lib/crypto/crypto_methods.ts

@ -44,7 +44,7 @@ export default abstract class CryptoWorkerMethods { @@ -44,7 +44,7 @@ export default abstract class CryptoWorkerMethods {
return this.performTaskWorker<T>('gzipUncompress', bytes, toString);
}
public computeSRP(password: string, state: any): Promise<InputCheckPasswordSRP> {
return this.performTaskWorker('computeSRP', password, state);
public computeSRP(password: string, state: any, isNew = false): Promise<InputCheckPasswordSRP> {
return this.performTaskWorker('computeSRP', password, state, isNew);
}
}

11
src/lib/crypto/srp.ts

@ -31,10 +31,10 @@ export async function makePasswordHash(password: string, client_salt: Uint8Array @@ -31,10 +31,10 @@ export async function makePasswordHash(password: string, client_salt: Uint8Array
return buffer;
}
export async function computeSRP(password: string, state: AccountPassword) {
//console.log('computeCheck:', password, state);
export async function computeSRP(password: string, state: AccountPassword, isNew: boolean) {
console.log('computeSRP:', password, state, isNew);
let algo = state.current_algo as PasswordKdfAlgo.passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow;
let algo = (state.current_algo || state.new_algo) as PasswordKdfAlgo.passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow;
let p = str2bigInt(bytesToHex(algo.p), 16);
let B = str2bigInt(bytesToHex(state.srp_B), 16);
@ -82,6 +82,11 @@ export async function computeSRP(password: string, state: AccountPassword) { @@ -82,6 +82,11 @@ export async function computeSRP(password: string, state: AccountPassword) {
let g_x = powMod(g, x, p);
// * https://core.telegram.org/api/srp#setting-a-new-2fa-password
if(isNew) {
return padArray(bytesFromHex(bigInt2str(g_x, 16)), 256);
}
//log('g_x', bigInt2str(g_x, 16));
let k: any = await CryptoWorker.sha256Hash(bufferConcat(pForHash, gForHash));

4
src/lib/mtproto/passwordManager.ts

@ -21,7 +21,7 @@ export class PasswordManager { @@ -21,7 +21,7 @@ export class PasswordManager {
//state = Object.assign({}, state);
//state.new_algo = Object.assign({}, state.new_algo);
this.getState().then(state => {
return this.getState().then(state => {
let currentHashPromise: ReturnType<CryptoWorkerMethods['computeSRP']>;
let newHashPromise: Promise<Uint8Array>;
const params: AccountUpdatePasswordSettings = {
@ -49,7 +49,7 @@ export class PasswordManager { @@ -49,7 +49,7 @@ export class PasswordManager {
newAlgo.salt1 = salt1;
if(settings.newPassword) {
newHashPromise = Promise.resolve(new Uint8Array());
newHashPromise = apiManager.computeSRP(settings.newPassword, state, true) as any;
} else {
newHashPromise = Promise.resolve(new Uint8Array());
}

216
src/pages/pageAuthCode.ts

@ -1,9 +1,6 @@ @@ -1,9 +1,6 @@
import mediaSizes from '../helpers/mediaSizes';
import { AuthSentCode, AuthSentCodeType } from '../layer';
import appStateManager from '../lib/appManagers/appStateManager';
import LottieLoader, { RLottiePlayer } from '../lib/lottieLoader';
//import CryptoWorker from '../lib/crypto/cryptoworker';
//import apiManager from '../lib/mtproto/apiManager';
import apiManager from '../lib/mtproto/mtprotoworker';
import Page from './page';
import pageIm from './pageIm';
@ -11,20 +8,16 @@ import pagePassword from './pagePassword'; @@ -11,20 +8,16 @@ import pagePassword from './pagePassword';
import pageSignIn from './pageSignIn';
import pageSignUp from './pageSignUp';
import InputField from '../components/inputField';
import TrackingMonkey from '../components/monkeys/tracking';
let authCode: AuthSentCode.authSentCode = null;
//const EDITONSAMEPAGE = false;
let headerElement: HTMLHeadElement = null;
let sentTypeElement: HTMLParagraphElement = null;
let codeInput: HTMLInputElement;
let onFirstMount = (): Promise<any> => {
let needFrame = 0, lastLength = 0;
let animation: RLottiePlayer;
let idleAnimation: RLottiePlayer;
let lastLength = 0;
const CODELENGTH = (authCode.type as AuthSentCodeType.authSentCodeTypeApp).length;
@ -44,92 +37,20 @@ let onFirstMount = (): Promise<any> => { @@ -44,92 +37,20 @@ let onFirstMount = (): Promise<any> => {
const codeInputLabel = codeInput.nextElementSibling as HTMLLabelElement;
const editButton = page.pageEl.querySelector('.phone-edit') as HTMLElement;
/* if(EDITONSAMEPAGE) {
let editable = false;
let changePhonePromise: Promise<unknown>;
let changePhone = () => {
if(changePhonePromise) return;
let phone_number = '+' + headerElement.innerText.replace(/\D/g, '');
if(authCode.phone_number === phone_number) return;
codeInput.setAttribute('disabled', 'true');
changePhonePromise = apiManager.invokeApi('auth.sendCode', {
phone_number: phone_number,
api_id: App.id,
api_hash: App.hash,
settings: {
_: 'codeSettings' // that's how we sending Type
}
//lang_code: navigator.language || 'en'
}).then((code: any) => {
console.log('got code 2', code);
authCode = Object.assign(code, {phone_number});
changePhonePromise = undefined;
codeInput.removeAttribute('disabled');
codeInput.focus();
}).catch(err => {
switch(err.type) {
case 'PHONE_NUMBER_INVALID':
headerElement.classList.add('error');
editable = true;
headerElement.setAttribute('contenteditable', '' + editable);
headerElement.focus();
break;
default:
codeInputLabel.innerText = err.type;
break;
}
changePhonePromise = undefined;
codeInput.removeAttribute('disabled');
});
};
headerElement.addEventListener('keypress', function(this, e) {
if(e.key === 'Enter') {
editable = false;
headerElement.setAttribute('contenteditable', '' + editable);
changePhone();
}
if(/\D/.test(e.key)) {
e.preventDefault();
return false;
}
this.classList.remove('error');
});
editButton.addEventListener('click', function() {
if(changePhonePromise) return;
editable = !editable;
headerElement.setAttribute('contenteditable', '' + editable);
if(!editable) changePhone();
});
} else { */
editButton.addEventListener('click', function() {
return pageSignIn.mount();
});
//}
editButton.addEventListener('click', function() {
return pageSignIn.mount();
});
let cleanup = () => {
const cleanup = () => {
setTimeout(() => {
if(animation) animation.remove();
if(idleAnimation) idleAnimation.remove();
monkey.remove();
}, 300);
};
let submitCode = (code: string) => {
const submitCode = (code: string) => {
codeInput.setAttribute('disabled', 'true');
let params = {
const params = {
phone_number: authCode.phone_number,
phone_code_hash: authCode.phone_code_hash,
phone_code: code
@ -187,9 +108,6 @@ let onFirstMount = (): Promise<any> => { @@ -187,9 +108,6 @@ let onFirstMount = (): Promise<any> => {
});
};
const max = 45;
// 1st symbol = frame 15
// end symbol = frame 165
codeInput.addEventListener('input', function(this: typeof codeInput, e) {
this.classList.remove('error');
codeInputLabel.innerText = 'Code';
@ -199,7 +117,7 @@ let onFirstMount = (): Promise<any> => { @@ -199,7 +117,7 @@ let onFirstMount = (): Promise<any> => {
this.value = this.value.slice(0, CODELENGTH);
}
let length = this.value.length;
const length = this.value.length;
if(length === CODELENGTH) { // submit code
submitCode(this.value);
} else if(length === lastLength) {
@ -207,117 +125,13 @@ let onFirstMount = (): Promise<any> => { @@ -207,117 +125,13 @@ let onFirstMount = (): Promise<any> => {
}
lastLength = length;
playAnimation(length);
});
const playAnimation = (length: number) => {
if(!animation) return;
let frame: number;
if(length) {
frame = Math.round(Math.min(max, length) * (165 / max) + 11.33);
if(idleAnimation) {
idleAnimation.stop(true);
idleAnimation.canvas.style.display = 'none';
}
animation.canvas.style.display = '';
} else {
/* const cb = (frameNo: number) => {
if(frameNo <= 1) { */
/* idleAnimation.play();
idleAnimation.canvas.style.display = '';
animation.canvas.style.display = 'none'; */
/* animation.removeListener('enterFrame', cb);
}
};
animation.addListener('enterFrame', cb); */
frame = 0;
}
//animation.playSegments([1, 2]);
const direction = needFrame > frame ? -1 : 1;
//console.log('keydown', length, frame, direction);
animation.setDirection(direction);
if(needFrame !== 0 && frame === 0) {
animation.setSpeed(7);
}
/* let diff = Math.abs(needFrame - frame * direction);
if((diff / 20) > 1) animation.setSpeed(diff / 20 | 0); */
needFrame = frame;
animation.play();
/* animation.goToAndStop(15, true); */
//animation.goToAndStop(length / max * );
};
/* codeInput.addEventListener('focus', () => {
playAnimation(Math.max(codeInput.value.length, 1));
}); */
codeInput.addEventListener('blur', () => {
playAnimation(0);
});
let imageDiv = page.pageEl.querySelector('.auth-image') as HTMLDivElement;
const imageDiv = page.pageEl.querySelector('.auth-image') as HTMLDivElement;
const size = mediaSizes.isMobile ? 100 : 166;
return Promise.all([
LottieLoader.loadAnimationFromURL({
container: imageDiv,
loop: true,
autoplay: true,
width: size,
height: size
}, 'assets/img/TwoFactorSetupMonkeyIdle.tgs').then(animation => {
idleAnimation = animation;
// ! animationIntersector will stop animation instantly
if(!codeInput.value.length) {
animation.play();
}
}),
LottieLoader.loadAnimationFromURL({
container: imageDiv,
loop: false,
autoplay: false,
width: size,
height: size
}, 'assets/img/TwoFactorSetupMonkeyTracking.tgs').then(_animation => {
animation = _animation;
if(!codeInput.value.length) {
animation.canvas.style.display = 'none';
}
animation.addListener('enterFrame', currentFrame => {
//console.log('enterFrame', currentFrame, needFrame);
//let currentFrame = Math.round(e.currentTime);
if((animation.direction === 1 && currentFrame >= needFrame) ||
(animation.direction === -1 && currentFrame <= needFrame)) {
animation.setSpeed(1);
animation.pause();
}
if(currentFrame === 0 && needFrame === 0) {
//animation.curFrame = 0;
if(idleAnimation) {
idleAnimation.canvas.style.display = '';
idleAnimation.play();
animation.canvas.style.display = 'none';
}
}
});
//console.log(animation.getDuration(), animation.getDuration(true));
})
]);
const monkey = new TrackingMonkey(codeInputField, size);
imageDiv.append(monkey.container);
return monkey.load();
};
const page = new Page('page-authCode', true, onFirstMount, (_authCode: typeof authCode) => {
@ -334,8 +148,6 @@ const page = new Page('page-authCode', true, onFirstMount, (_authCode: typeof au @@ -334,8 +148,6 @@ const page = new Page('page-authCode', true, onFirstMount, (_authCode: typeof au
codeInput.dispatchEvent(evt);
}
//let LottieLoader = (await import('../lib/lottieLoader')).default;
headerElement.innerText = authCode.phone_number;
switch(authCode.type._) {
case 'auth.sentCodeTypeSms':

11
src/scss/partials/_button.scss

@ -225,6 +225,17 @@ @@ -225,6 +225,17 @@
background: darken($color-blue, 8%);
}
&-transparent {
background-color: transparent;
@include hover() {
background: hover-color($color-blue);
}
.preloader-circular .preloader-path {
stroke: $color-blue;
}
}
body.animation-level-0 & {
transition: none;
}

24
src/scss/partials/_leftSidebar.scss

@ -907,12 +907,26 @@ @@ -907,12 +907,26 @@
width: 168px;
height: 168px;
}
}
.two-step-verification-enter-password {
.media-sticker-wrapper {
width: 157px;
height: 157px;
&-enter-password {
.media-sticker-wrapper {
width: 157px;
height: 157px;
}
}
&-hint {
.media-sticker-wrapper {
width: 120px;
height: 120px;
}
}
&-email {
.media-sticker-wrapper {
width: 120px;
height: 120px;
}
}
}

Loading…
Cancel
Save