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 {
|
export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperTab {
|
||||||
public state: AccountPassword;
|
public state: AccountPassword;
|
||||||
|
public passwordInputField: PasswordInputField;
|
||||||
|
public plainPassword: string;
|
||||||
|
|
||||||
constructor(slider: SidebarSlider) {
|
constructor(slider: SidebarSlider) {
|
||||||
super(slider, true);
|
super(slider, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected init() {
|
protected init() {
|
||||||
|
const isNew = !this.state.pFlags.has_password || this.plainPassword;
|
||||||
this.container.classList.add('two-step-verification-enter-password');
|
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({
|
const section = new SettingSection({
|
||||||
noDelimiter: true
|
noDelimiter: true
|
||||||
@ -29,9 +32,9 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT
|
|||||||
const inputWrapper = document.createElement('div');
|
const inputWrapper = document.createElement('div');
|
||||||
inputWrapper.classList.add('input-wrapper');
|
inputWrapper.classList.add('input-wrapper');
|
||||||
|
|
||||||
const passwordInputField = new PasswordInputField({
|
const passwordInputField = this.passwordInputField = new PasswordInputField({
|
||||||
name: 'first-password',
|
name: 'enter-password',
|
||||||
label: this.state.pFlags.has_password ? this.state.hint ?? 'Password' : 'Enter a Password'
|
label: isNew ? 'Enter a Password' : (this.state.hint ?? 'Password')
|
||||||
});
|
});
|
||||||
|
|
||||||
const monkey = new PasswordMonkey(passwordInputField, 157);
|
const monkey = new PasswordMonkey(passwordInputField, 157);
|
||||||
@ -65,7 +68,7 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
if(this.state.pFlags.has_password) {
|
if(!isNew) {
|
||||||
let getStateInterval: number;
|
let getStateInterval: number;
|
||||||
|
|
||||||
let getState = () => {
|
let getState = () => {
|
||||||
@ -128,8 +131,14 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT
|
|||||||
|
|
||||||
const tab = new AppTwoStepVerificationReEnterPasswordTab(this.slider);
|
const tab = new AppTwoStepVerificationReEnterPasswordTab(this.slider);
|
||||||
tab.state = this.state;
|
tab.state = this.state;
|
||||||
|
tab.newPassword = passwordInputField.value;
|
||||||
|
tab.plainPassword = this.plainPassword;
|
||||||
tab.open();
|
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 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'});
|
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, () => {
|
attachClickEvent(btnDisablePassword, () => {
|
||||||
const popup = new PopupConfirmAction('popup-disable-password', [{
|
const popup = new PopupConfirmAction('popup-disable-password', [{
|
||||||
text: 'DISABLE',
|
text: 'DISABLE',
|
||||||
@ -61,7 +68,7 @@ export default class AppTwoStepVerificationTab extends SliderSuperTab {
|
|||||||
isDanger: true,
|
isDanger: true,
|
||||||
}], {
|
}], {
|
||||||
title: 'Warning',
|
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();
|
popup.show();
|
||||||
|
@ -1,24 +1,25 @@
|
|||||||
import AppTwoStepVerificationTab from ".";
|
|
||||||
import { SettingSection } from "../..";
|
import { SettingSection } from "../..";
|
||||||
import { attachClickEvent, cancelEvent } from "../../../../helpers/dom";
|
import { attachClickEvent, cancelEvent } from "../../../../helpers/dom";
|
||||||
import { AccountPassword } from "../../../../layer";
|
import { AccountPassword } from "../../../../layer";
|
||||||
import passwordManager from "../../../../lib/mtproto/passwordManager";
|
|
||||||
import Button from "../../../button";
|
import Button from "../../../button";
|
||||||
import { putPreloader } from "../../../misc";
|
|
||||||
import PasswordMonkey from "../../../monkeys/password";
|
|
||||||
import PasswordInputField from "../../../passwordInputField";
|
import PasswordInputField from "../../../passwordInputField";
|
||||||
import { ripple } from "../../../ripple";
|
import { ripple } from "../../../ripple";
|
||||||
import SidebarSlider, { SliderSuperTab } from "../../../slider";
|
import SidebarSlider, { SliderSuperTab } from "../../../slider";
|
||||||
|
import TrackingMonkey from "../../../monkeys/tracking";
|
||||||
|
import AppTwoStepVerificationHintTab from "./hint";
|
||||||
|
|
||||||
export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSuperTab {
|
export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSuperTab {
|
||||||
public state: AccountPassword;
|
public state: AccountPassword;
|
||||||
|
public passwordInputField: PasswordInputField;
|
||||||
|
public plainPassword: string;
|
||||||
|
public newPassword: string;
|
||||||
|
|
||||||
constructor(slider: SidebarSlider) {
|
constructor(slider: SidebarSlider) {
|
||||||
super(slider, true);
|
super(slider, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected init() {
|
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';
|
this.title.innerHTML = 'Re-Enter your Password';
|
||||||
|
|
||||||
const section = new SettingSection({
|
const section = new SettingSection({
|
||||||
@ -28,12 +29,12 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe
|
|||||||
const inputWrapper = document.createElement('div');
|
const inputWrapper = document.createElement('div');
|
||||||
inputWrapper.classList.add('input-wrapper');
|
inputWrapper.classList.add('input-wrapper');
|
||||||
|
|
||||||
const passwordInputField = new PasswordInputField({
|
const passwordInputField = this.passwordInputField = new PasswordInputField({
|
||||||
name: 're-enter-password',
|
name: 're-enter-password',
|
||||||
label: 'Re-Enter your Password'
|
label: 'Re-Enter your Password'
|
||||||
});
|
});
|
||||||
|
|
||||||
const monkey = new PasswordMonkey(passwordInputField, 157);
|
const monkey = new TrackingMonkey(passwordInputField, 157);
|
||||||
monkey.load();
|
monkey.load();
|
||||||
|
|
||||||
const btnContinue = Button('btn-primary', {text: 'CONTINUE'});
|
const btnContinue = Button('btn-primary', {text: 'CONTINUE'});
|
||||||
@ -56,7 +57,7 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe
|
|||||||
});
|
});
|
||||||
|
|
||||||
const verifyInput = () => {
|
const verifyInput = () => {
|
||||||
if(!passwordInputField.value.length) {
|
if(this.newPassword !== passwordInputField.value) {
|
||||||
passwordInputField.input.classList.add('error');
|
passwordInputField.input.classList.add('error');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -68,7 +69,15 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe
|
|||||||
cancelEvent(e);
|
cancelEvent(e);
|
||||||
if(!verifyInput()) return;
|
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);
|
return this.performTaskWorker<T>('gzipUncompress', bytes, toString);
|
||||||
}
|
}
|
||||||
|
|
||||||
public computeSRP(password: string, state: any): Promise<InputCheckPasswordSRP> {
|
public computeSRP(password: string, state: any, isNew = false): Promise<InputCheckPasswordSRP> {
|
||||||
return this.performTaskWorker('computeSRP', password, state);
|
return this.performTaskWorker('computeSRP', password, state, isNew);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -31,10 +31,10 @@ export async function makePasswordHash(password: string, client_salt: Uint8Array
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function computeSRP(password: string, state: AccountPassword) {
|
export async function computeSRP(password: string, state: AccountPassword, isNew: boolean) {
|
||||||
//console.log('computeCheck:', password, state);
|
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 p = str2bigInt(bytesToHex(algo.p), 16);
|
||||||
let B = str2bigInt(bytesToHex(state.srp_B), 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);
|
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));
|
//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));
|
||||||
|
@ -21,7 +21,7 @@ export class PasswordManager {
|
|||||||
//state = Object.assign({}, state);
|
//state = Object.assign({}, state);
|
||||||
//state.new_algo = Object.assign({}, state.new_algo);
|
//state.new_algo = Object.assign({}, state.new_algo);
|
||||||
|
|
||||||
this.getState().then(state => {
|
return this.getState().then(state => {
|
||||||
let currentHashPromise: ReturnType<CryptoWorkerMethods['computeSRP']>;
|
let currentHashPromise: ReturnType<CryptoWorkerMethods['computeSRP']>;
|
||||||
let newHashPromise: Promise<Uint8Array>;
|
let newHashPromise: Promise<Uint8Array>;
|
||||||
const params: AccountUpdatePasswordSettings = {
|
const params: AccountUpdatePasswordSettings = {
|
||||||
@ -49,7 +49,7 @@ export class PasswordManager {
|
|||||||
newAlgo.salt1 = salt1;
|
newAlgo.salt1 = salt1;
|
||||||
|
|
||||||
if(settings.newPassword) {
|
if(settings.newPassword) {
|
||||||
newHashPromise = Promise.resolve(new Uint8Array());
|
newHashPromise = apiManager.computeSRP(settings.newPassword, state, true) as any;
|
||||||
} else {
|
} else {
|
||||||
newHashPromise = Promise.resolve(new Uint8Array());
|
newHashPromise = Promise.resolve(new Uint8Array());
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
import mediaSizes from '../helpers/mediaSizes';
|
import mediaSizes from '../helpers/mediaSizes';
|
||||||
import { AuthSentCode, AuthSentCodeType } from '../layer';
|
import { AuthSentCode, AuthSentCodeType } from '../layer';
|
||||||
import appStateManager from '../lib/appManagers/appStateManager';
|
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 apiManager from '../lib/mtproto/mtprotoworker';
|
||||||
import Page from './page';
|
import Page from './page';
|
||||||
import pageIm from './pageIm';
|
import pageIm from './pageIm';
|
||||||
@ -11,20 +8,16 @@ import pagePassword from './pagePassword';
|
|||||||
import pageSignIn from './pageSignIn';
|
import pageSignIn from './pageSignIn';
|
||||||
import pageSignUp from './pageSignUp';
|
import pageSignUp from './pageSignUp';
|
||||||
import InputField from '../components/inputField';
|
import InputField from '../components/inputField';
|
||||||
|
import TrackingMonkey from '../components/monkeys/tracking';
|
||||||
|
|
||||||
let authCode: AuthSentCode.authSentCode = null;
|
let authCode: AuthSentCode.authSentCode = null;
|
||||||
|
|
||||||
//const EDITONSAMEPAGE = false;
|
|
||||||
|
|
||||||
let headerElement: HTMLHeadElement = null;
|
let headerElement: HTMLHeadElement = null;
|
||||||
let sentTypeElement: HTMLParagraphElement = null;
|
let sentTypeElement: HTMLParagraphElement = null;
|
||||||
let codeInput: HTMLInputElement;
|
let codeInput: HTMLInputElement;
|
||||||
|
|
||||||
let onFirstMount = (): Promise<any> => {
|
let onFirstMount = (): Promise<any> => {
|
||||||
let needFrame = 0, lastLength = 0;
|
let lastLength = 0;
|
||||||
|
|
||||||
let animation: RLottiePlayer;
|
|
||||||
let idleAnimation: RLottiePlayer;
|
|
||||||
|
|
||||||
const CODELENGTH = (authCode.type as AuthSentCodeType.authSentCodeTypeApp).length;
|
const CODELENGTH = (authCode.type as AuthSentCodeType.authSentCodeTypeApp).length;
|
||||||
|
|
||||||
@ -44,92 +37,20 @@ let onFirstMount = (): Promise<any> => {
|
|||||||
const codeInputLabel = codeInput.nextElementSibling as HTMLLabelElement;
|
const codeInputLabel = codeInput.nextElementSibling as HTMLLabelElement;
|
||||||
const editButton = page.pageEl.querySelector('.phone-edit') as HTMLElement;
|
const editButton = page.pageEl.querySelector('.phone-edit') as HTMLElement;
|
||||||
|
|
||||||
/* if(EDITONSAMEPAGE) {
|
editButton.addEventListener('click', function() {
|
||||||
let editable = false;
|
return pageSignIn.mount();
|
||||||
let changePhonePromise: Promise<unknown>;
|
});
|
||||||
|
|
||||||
let changePhone = () => {
|
const cleanup = () => {
|
||||||
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 = () => {
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if(animation) animation.remove();
|
monkey.remove();
|
||||||
if(idleAnimation) idleAnimation.remove();
|
|
||||||
}, 300);
|
}, 300);
|
||||||
};
|
};
|
||||||
|
|
||||||
let submitCode = (code: string) => {
|
const submitCode = (code: string) => {
|
||||||
codeInput.setAttribute('disabled', 'true');
|
codeInput.setAttribute('disabled', 'true');
|
||||||
|
|
||||||
let params = {
|
const params = {
|
||||||
phone_number: authCode.phone_number,
|
phone_number: authCode.phone_number,
|
||||||
phone_code_hash: authCode.phone_code_hash,
|
phone_code_hash: authCode.phone_code_hash,
|
||||||
phone_code: code
|
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) {
|
codeInput.addEventListener('input', function(this: typeof codeInput, e) {
|
||||||
this.classList.remove('error');
|
this.classList.remove('error');
|
||||||
codeInputLabel.innerText = 'Code';
|
codeInputLabel.innerText = 'Code';
|
||||||
@ -199,7 +117,7 @@ let onFirstMount = (): Promise<any> => {
|
|||||||
this.value = this.value.slice(0, CODELENGTH);
|
this.value = this.value.slice(0, CODELENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
let length = this.value.length;
|
const length = this.value.length;
|
||||||
if(length === CODELENGTH) { // submit code
|
if(length === CODELENGTH) { // submit code
|
||||||
submitCode(this.value);
|
submitCode(this.value);
|
||||||
} else if(length === lastLength) {
|
} else if(length === lastLength) {
|
||||||
@ -207,117 +125,13 @@ let onFirstMount = (): Promise<any> => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
lastLength = length;
|
lastLength = length;
|
||||||
|
|
||||||
playAnimation(length);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const playAnimation = (length: number) => {
|
const imageDiv = page.pageEl.querySelector('.auth-image') as HTMLDivElement;
|
||||||
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 size = mediaSizes.isMobile ? 100 : 166;
|
const size = mediaSizes.isMobile ? 100 : 166;
|
||||||
return Promise.all([
|
const monkey = new TrackingMonkey(codeInputField, size);
|
||||||
LottieLoader.loadAnimationFromURL({
|
imageDiv.append(monkey.container);
|
||||||
container: imageDiv,
|
return monkey.load();
|
||||||
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 page = new Page('page-authCode', true, onFirstMount, (_authCode: typeof authCode) => {
|
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);
|
codeInput.dispatchEvent(evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
//let LottieLoader = (await import('../lib/lottieLoader')).default;
|
|
||||||
|
|
||||||
headerElement.innerText = authCode.phone_number;
|
headerElement.innerText = authCode.phone_number;
|
||||||
switch(authCode.type._) {
|
switch(authCode.type._) {
|
||||||
case 'auth.sentCodeTypeSms':
|
case 'auth.sentCodeTypeSms':
|
||||||
|
@ -225,6 +225,17 @@
|
|||||||
background: darken($color-blue, 8%);
|
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 & {
|
body.animation-level-0 & {
|
||||||
transition: none;
|
transition: none;
|
||||||
}
|
}
|
||||||
|
@ -907,12 +907,26 @@
|
|||||||
width: 168px;
|
width: 168px;
|
||||||
height: 168px;
|
height: 168px;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.two-step-verification-enter-password {
|
&-enter-password {
|
||||||
.media-sticker-wrapper {
|
.media-sticker-wrapper {
|
||||||
width: 157px;
|
width: 157px;
|
||||||
height: 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