Temp 2FA commit
This commit is contained in:
parent
67e76a3f03
commit
3e514c1caa
144
src/components/monkeys/tracking.ts
Normal file
144
src/components/monkeys/tracking.ts
Normal file
@ -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
Normal file
100
src/components/sidebarLeft/tabs/2fa/email.ts
Normal file
@ -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();
|
||||
}
|
||||
}
|
@ -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
|
||||
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
|
||||
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
|
||||
|
||||
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
Normal file
91
src/components/sidebarLeft/tabs/2fa/hint.ts
Normal file
@ -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();
|
||||
}
|
||||
}
|
@ -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 {
|
||||
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();
|
||||
|
@ -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
|
||||
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
|
||||
});
|
||||
|
||||
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
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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) {
|
||||
|
||||
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));
|
||||
|
@ -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 {
|
||||
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());
|
||||
}
|
||||
|
@ -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';
|
||||
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> => {
|
||||
const codeInputLabel = codeInput.nextElementSibling as HTMLLabelElement;
|
||||
const editButton = page.pageEl.querySelector('.phone-edit') as HTMLElement;
|
||||
|
||||
/* if(EDITONSAMEPAGE) {
|
||||
let editable = false;
|
||||
let changePhonePromise: Promise<unknown>;
|
||||
editButton.addEventListener('click', function() {
|
||||
return pageSignIn.mount();
|
||||
});
|
||||
|
||||
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();
|
||||
});
|
||||
//}
|
||||
|
||||
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> => {
|
||||
});
|
||||
};
|
||||
|
||||
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> => {
|
||||
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> => {
|
||||
}
|
||||
|
||||
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
|
||||
codeInput.dispatchEvent(evt);
|
||||
}
|
||||
|
||||
//let LottieLoader = (await import('../lib/lottieLoader')).default;
|
||||
|
||||
headerElement.innerText = authCode.phone_number;
|
||||
switch(authCode.type._) {
|
||||
case 'auth.sentCodeTypeSms':
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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…
x
Reference in New Issue
Block a user