Browse Source

Two-factor:

Recovery email
Fix enter shortcut on handhelds
master
Eduard Kuzmenko 3 years ago
parent
commit
a6753d7325
  1. 38
      src/components/codeInputField.ts
  2. 5
      src/components/misc.ts
  3. 24
      src/components/sidebarLeft/tabs/2fa/email.ts
  4. 106
      src/components/sidebarLeft/tabs/2fa/emailConfirmation.ts
  5. 23
      src/components/sidebarLeft/tabs/2fa/enterPassword.ts
  6. 29
      src/components/sidebarLeft/tabs/2fa/hint.ts
  7. 15
      src/components/sidebarLeft/tabs/2fa/index.ts
  8. 3
      src/components/sidebarLeft/tabs/2fa/passwordSet.ts
  9. 12
      src/components/sidebarLeft/tabs/2fa/reEnterPassword.ts
  10. 9
      src/components/sidebarLeft/tabs/privacyAndSecurity.ts
  11. 14
      src/helpers/dom.ts
  12. 2
      src/lib/appManagers/appDialogsManager.ts
  13. 12
      src/lib/mtproto/passwordManager.ts
  14. 44
      src/pages/pageAuthCode.ts
  15. 4
      src/scss/partials/_button.scss
  16. 16
      src/scss/partials/_leftSidebar.scss

38
src/components/codeInputField.ts

@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
import InputField from "./inputField";
export default class CodeInputField extends InputField {
constructor(options: {
label?: string,
name?: string,
length: number,
onFill: (code: number) => void
}) {
super({
plainText: true,
...options
});
const input = this.input as HTMLInputElement;
input.type = 'tel';
input.setAttribute('required', '');
input.autocomplete = 'off';
let lastLength = 0;
this.input.addEventListener('input', (e) => {
this.input.classList.remove('error');
this.label.innerText = options.label;
const value = this.value.replace(/\D/g, '').slice(0, options.length);
this.setValueSilently(value);
const length = this.value.length;
if(length === options.length) { // submit code
options.onFill(+this.value);
} else if(length === lastLength) {
return;
}
lastLength = length;
});
}
}

5
src/components/misc.ts

@ -55,14 +55,14 @@ export function renderImageFromUrl(elem: HTMLElement | HTMLImageElement | SVGIma @@ -55,14 +55,14 @@ export function renderImageFromUrl(elem: HTMLElement | HTMLImageElement | SVGIma
}
}
export function putPreloader(elem: Element, returnDiv = false) {
export function putPreloader(elem: Element, returnDiv = false): HTMLElement {
const html = `
<svg xmlns="http://www.w3.org/2000/svg" class="preloader-circular" viewBox="25 25 50 50">
<circle class="preloader-path" cx="50" cy="50" r="20" fill="none" stroke-miterlimit="10"/>
</svg>`;
if(returnDiv) {
let div = document.createElement('div');
const div = document.createElement('div');
div.classList.add('preloader');
div.innerHTML = html;
@ -74,6 +74,7 @@ export function putPreloader(elem: Element, returnDiv = false) { @@ -74,6 +74,7 @@ export function putPreloader(elem: Element, returnDiv = false) {
}
elem.innerHTML += html;
return elem.lastElementChild as HTMLElement;
}
MOUNT_CLASS_TO && (MOUNT_CLASS_TO.putPreloader = putPreloader);

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

@ -5,7 +5,7 @@ import Button from "../../../button"; @@ -5,7 +5,7 @@ import Button from "../../../button";
import SidebarSlider, { SliderSuperTab } from "../../../slider";
import { wrapSticker } from "../../../wrappers";
import InputField from "../../../inputField";
import { attachClickEvent, cancelEvent } from "../../../../helpers/dom";
import { attachClickEvent, cancelEvent, canFocus } from "../../../../helpers/dom";
import PopupConfirmAction from "../../../popups/confirmAction";
import { putPreloader } from "../../../misc";
import passwordManager from "../../../../lib/mtproto/passwordManager";
@ -19,6 +19,7 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab { @@ -19,6 +19,7 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
public plainPassword: string;
public newPassword: string;
public hint: string;
public isFirst = false;
constructor(slider: SidebarSlider) {
super(slider, true);
@ -29,7 +30,7 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab { @@ -29,7 +30,7 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
this.title.innerHTML = 'Recovery Email';
const section = new SettingSection({
caption: ' ',
caption: '',
noDelimiter: true
});
@ -69,7 +70,7 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab { @@ -69,7 +70,7 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
inputField.input.addEventListener('keypress', (e) => {
if(e.key === 'Enter') {
cancelEvent(e);
return btnContinue.click();
return onContinueClick();
}
});
@ -78,13 +79,13 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab { @@ -78,13 +79,13 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
});
const btnContinue = Button('btn-primary btn-color-primary', {text: 'CONTINUE'});
const btnSkip = Button('btn-primary btn-primary-transparent primary', {text: 'SKIP'});
const btnSkip = Button('btn-primary btn-secondary btn-primary-transparent primary', {text: 'SKIP'});
const goNext = () => {
new AppTwoStepVerificationSetTab(this.slider).open();
};
attachClickEvent(btnContinue, (e) => {
const onContinueClick = () => {
const email = inputField.value.trim();
const match = RichTextProcessor.matchEmail(email);
if(!match || match[0].length !== email.length) {
@ -93,7 +94,7 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab { @@ -93,7 +94,7 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
}
toggleButtons(true);
putPreloader(btnContinue);
const d = putPreloader(btnContinue);
passwordManager.updateSettings({
hint: this.hint,
@ -108,9 +109,6 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab { @@ -108,9 +109,6 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
const tab = new AppTwoStepVerificationEmailConfirmationTab(this.slider);
tab.state = this.state;
tab.newPassword = this.newPassword;
tab.plainPassword = this.plainPassword;
tab.hint = this.hint;
tab.email = email;
tab.length = symbols;
tab.open();
@ -119,8 +117,10 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab { @@ -119,8 +117,10 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
}
toggleButtons(false);
d.remove();
});
});
};
attachClickEvent(btnContinue, onContinueClick);
const toggleButtons = (freeze: boolean) => {
if(freeze) {
@ -145,7 +145,8 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab { @@ -145,7 +145,8 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
passwordManager.updateSettings({
hint: this.hint,
currentPassword: this.plainPassword,
newPassword: this.newPassword
newPassword: this.newPassword,
email: ''
}).then(() => {
goNext();
}, (err) => {
@ -169,6 +170,7 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab { @@ -169,6 +170,7 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
}
onOpenAfterTimeout() {
if(!canFocus(this.isFirst)) return;
this.inputField.input.focus();
}
}

106
src/components/sidebarLeft/tabs/2fa/emailConfirmation.ts

@ -4,21 +4,19 @@ import appStickersManager from "../../../../lib/appManagers/appStickersManager"; @@ -4,21 +4,19 @@ 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 { attachClickEvent, canFocus, toggleDisability } from "../../../../helpers/dom";
import passwordManager from "../../../../lib/mtproto/passwordManager";
import AppTwoStepVerificationSetTab from "./passwordSet";
import CodeInputField from "../../../codeInputField";
import AppTwoStepVerificationEmailTab from "./email";
import { putPreloader } from "../../../misc";
export default class AppTwoStepVerificationEmailConfirmationTab extends SliderSuperTab {
public inputField: InputField;
public codeInputField: CodeInputField;
public state: AccountPassword;
public plainPassword: string;
public newPassword: string;
public hint: string;
public email: string;
public length: number;
public isFirst = false;
constructor(slider: SidebarSlider) {
super(slider, true);
@ -29,10 +27,12 @@ export default class AppTwoStepVerificationEmailConfirmationTab extends SliderSu @@ -29,10 +27,12 @@ export default class AppTwoStepVerificationEmailConfirmationTab extends SliderSu
this.title.innerHTML = 'Recovery Email';
const section = new SettingSection({
caption: ' ',
caption: 'Please enter code we\'ve just emailed at <b></b>',
noDelimiter: true
});
(section.caption.lastElementChild as HTMLElement).innerText = this.email;
const emoji = '📬';
const doc = appStickersManager.getAnimatedEmojiSticker(emoji);
const stickerContainer = document.createElement('div');
@ -60,54 +60,69 @@ export default class AppTwoStepVerificationEmailConfirmationTab extends SliderSu @@ -60,54 +60,69 @@ export default class AppTwoStepVerificationEmailConfirmationTab extends SliderSu
const inputWrapper = document.createElement('div');
inputWrapper.classList.add('input-wrapper');
const inputField = this.inputField = new InputField({
const inputField = this.codeInputField = new CodeInputField({
name: 'recovery-email-code',
label: 'Code'
label: 'Code',
length: this.length,
onFill: (code) => {
freeze(true);
passwordManager.confirmPasswordEmail('' + code)
.then(value => {
if(!value) {
}
goNext();
})
.catch(err => {
switch(err.type) {
case 'CODE_INVALID':
inputField.input.classList.add('error');
inputField.label.innerText = 'Invalid Code';
break;
default:
console.error('confirm error', err);
break;
}
freeze(false);
});
}
});
const btnContinue = Button('btn-primary btn-color-primary', {text: 'CONTINUE'});
const btnSkip = Button('btn-primary btn-primary-transparent primary', {text: 'SKIP'});
const btnChange = Button('btn-primary btn-primary-transparent primary', {text: 'CHANGE EMAIL'});
const btnResend = Button('btn-primary btn-secondary btn-primary-transparent primary', {text: 'RE-SEND CODE'});
const goNext = () => {
new AppTwoStepVerificationSetTab(this.slider).open();
};
attachClickEvent(btnContinue, (e) => {
});
const freeze = (disable: boolean) => {
toggleDisability([inputField.input, btnChange, btnResend], disable);
};
attachClickEvent(btnSkip, (e) => {
const popup = new PopupConfirmAction('popup-skip-email', [{
text: 'CANCEL',
isCancel: true
}, {
text: 'SKIP',
callback: () => {
//inputContent.classList.add('sidebar-left-section-disabled');
btnContinue.setAttribute('disabled', 'true');
btnSkip.setAttribute('disabled', 'true');
putPreloader(btnSkip);
passwordManager.updateSettings({
hint: this.hint,
currentPassword: this.plainPassword,
newPassword: this.newPassword
}).then(() => {
goNext();
}, (err) => {
btnContinue.removeAttribute('disabled');
btnSkip.removeAttribute('disabled');
});
},
isDanger: true,
}], {
title: 'Warning',
text: 'No, seriously.<br/><br/>If you forget your password, you will lose access to your Telegram account. There will be no way to restore it.'
attachClickEvent(btnChange, (e) => {
freeze(true);
passwordManager.cancelPasswordEmail().then(value => {
this.slider.sliceTabsUntilTab(AppTwoStepVerificationEmailTab, this);
this.close();
}, () => {
freeze(false);
});
});
popup.show();
attachClickEvent(btnResend, (e) => {
freeze(true);
const d = putPreloader(btnResend);
passwordManager.resendPasswordEmail().then(value => {
d.remove();
freeze(false);
});
});
inputWrapper.append(inputField.container, btnContinue, btnSkip);
inputWrapper.append(inputField.container, btnChange, btnResend);
inputContent.append(inputWrapper);
@ -115,6 +130,7 @@ export default class AppTwoStepVerificationEmailConfirmationTab extends SliderSu @@ -115,6 +130,7 @@ export default class AppTwoStepVerificationEmailConfirmationTab extends SliderSu
}
onOpenAfterTimeout() {
this.inputField.input.focus();
if(!canFocus(this.isFirst)) return;
this.codeInputField.input.focus();
}
}

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

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
import AppTwoStepVerificationTab from ".";
import { SettingSection } from "../..";
import { attachClickEvent, cancelEvent } from "../../../../helpers/dom";
import { attachClickEvent, cancelEvent, canFocus } from "../../../../helpers/dom";
import { isMobileSafari } from "../../../../helpers/userAgent";
import { AccountPassword } from "../../../../layer";
import passwordManager from "../../../../lib/mtproto/passwordManager";
import RichTextProcessor from "../../../../lib/richtextprocessor";
@ -16,6 +17,7 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT @@ -16,6 +17,7 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT
public state: AccountPassword;
public passwordInputField: PasswordInputField;
public plainPassword: string;
public isFirst = true;
constructor(slider: SidebarSlider) {
super(slider, true);
@ -56,7 +58,7 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT @@ -56,7 +58,7 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT
}
if(e.key === 'Enter') {
return btnContinue.click();
return onContinueClick();
}
});
@ -69,6 +71,7 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT @@ -69,6 +71,7 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT
return true;
};
let onContinueClick: (e?: Event) => void;
if(!isNew) {
let getStateInterval: number;
@ -123,12 +126,15 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT @@ -123,12 +126,15 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT
});
};
attachClickEvent(btnContinue, submit);
onContinueClick = submit;
getState();
} else {
attachClickEvent(btnContinue, (e) => {
cancelEvent(e);
onContinueClick = (e) => {
if(e) {
cancelEvent(e);
}
if(!verifyInput()) return;
const tab = new AppTwoStepVerificationReEnterPasswordTab(this.slider);
@ -136,11 +142,14 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT @@ -136,11 +142,14 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT
tab.newPassword = passwordInputField.value;
tab.plainPassword = this.plainPassword;
tab.open();
});
};
}
attachClickEvent(btnContinue, onContinueClick);
}
onOpenAfterTimeout() {
if(!canFocus(this.isFirst)) return;
this.passwordInputField.input.focus();
}
}

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

@ -7,6 +7,7 @@ import { wrapSticker } from "../../../wrappers"; @@ -7,6 +7,7 @@ import { wrapSticker } from "../../../wrappers";
import InputField from "../../../inputField";
import AppTwoStepVerificationEmailTab from "./email";
import { attachClickEvent, cancelEvent } from "../../../../helpers/dom";
import { toast } from "../../../toast";
export default class AppTwoStepVerificationHintTab extends SliderSuperTab {
public inputField: InputField;
@ -23,7 +24,6 @@ export default class AppTwoStepVerificationHintTab extends SliderSuperTab { @@ -23,7 +24,6 @@ export default class AppTwoStepVerificationHintTab extends SliderSuperTab {
this.title.innerHTML = 'Password Hint';
const section = new SettingSection({
caption: ' ',
noDelimiter: true
});
@ -60,28 +60,37 @@ export default class AppTwoStepVerificationHintTab extends SliderSuperTab { @@ -60,28 +60,37 @@ export default class AppTwoStepVerificationHintTab extends SliderSuperTab {
inputField.input.addEventListener('keypress', (e) => {
if(e.key === 'Enter') {
cancelEvent(e);
return (inputField.value ? btnContinue : btnSkip).click();
return inputField.value ? onContinueClick() : onSkipClick();
}
});
const goNext = (e: Event, saveHint: boolean) => {
cancelEvent(e);
const goNext = (e?: Event, saveHint?: boolean) => {
if(e) {
cancelEvent(e);
}
const hint = saveHint ? inputField.value : undefined;
if(hint && this.newPassword === hint) {
toast('Hint must be different from your password');
return;
}
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.hint = hint;
tab.open();
};
const btnContinue = Button('btn-primary btn-color-primary', {text: 'CONTINUE'});
const btnSkip = Button('btn-primary btn-primary-transparent primary', {text: 'SKIP'});
const btnSkip = Button('btn-primary btn-secondary btn-primary-transparent primary', {text: 'SKIP'});
attachClickEvent(btnContinue, (e) => goNext(e, true));
attachClickEvent(btnSkip, (e) => goNext(e, false));
const onContinueClick = (e?: Event) => goNext(e, true);
const onSkipClick = (e?: Event) => goNext(e, false);
attachClickEvent(btnContinue, onContinueClick);
attachClickEvent(btnSkip, onSkipClick);
inputWrapper.append(inputField.container, btnContinue, btnSkip);

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

@ -8,6 +8,7 @@ import PopupConfirmAction from "../../../popups/confirmAction"; @@ -8,6 +8,7 @@ import PopupConfirmAction from "../../../popups/confirmAction";
import SidebarSlider, { SliderSuperTab } from "../../../slider";
import { wrapSticker } from "../../../wrappers";
import AppSettingsTab from "../settings";
import AppTwoStepVerificationEmailTab from "./email";
import AppTwoStepVerificationEnterPasswordTab from "./enterPassword";
export default class AppTwoStepVerificationTab extends SliderSuperTab {
@ -19,7 +20,7 @@ export default class AppTwoStepVerificationTab extends SliderSuperTab { @@ -19,7 +20,7 @@ export default class AppTwoStepVerificationTab extends SliderSuperTab {
}
protected init() {
this.container.classList.add('two-step-verification');
this.container.classList.add('two-step-verification', 'two-step-verification-main');
this.title.innerHTML = 'Two-Step Verification';
const section = new SettingSection({
@ -55,7 +56,7 @@ export default class AppTwoStepVerificationTab extends SliderSuperTab { @@ -55,7 +56,7 @@ export default class AppTwoStepVerificationTab extends SliderSuperTab {
const btnChangePassword = Button('btn-primary btn-transparent', {icon: 'edit', text: 'Change Password'});
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: this.state.pFlags.has_recovery ? 'Change Recovery Email' : 'Set Recovery Email'});
attachClickEvent(btnChangePassword, () => {
const tab = new AppTwoStepVerificationEnterPasswordTab(this.slider);
@ -82,6 +83,16 @@ export default class AppTwoStepVerificationTab extends SliderSuperTab { @@ -82,6 +83,16 @@ export default class AppTwoStepVerificationTab extends SliderSuperTab {
popup.show();
});
attachClickEvent(btnSetRecoveryEmail, () => {
const tab = new AppTwoStepVerificationEmailTab(this.slider);
tab.state = this.state;
tab.hint = this.state.hint;
tab.plainPassword = this.plainPassword;
tab.newPassword = this.plainPassword;
tab.isFirst = true;
tab.open();
});
c.append(btnChangePassword, btnDisablePassword, btnSetRecoveryEmail);
} else {
section.caption.innerHTML = 'You can set a password that will be required when you log in on a new device in addition to the code you get in the SMS.';

3
src/components/sidebarLeft/tabs/2fa/passwordSet.ts

@ -31,8 +31,7 @@ export default class AppTwoStepVerificationSetTab extends SliderSuperTab { @@ -31,8 +31,7 @@ export default class AppTwoStepVerificationSetTab extends SliderSuperTab {
loop: true,
play: true,
width: 160,
height: 160,
emoji
height: 160
}).then(() => {
// this.animation = player;
});

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

@ -52,7 +52,7 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe @@ -52,7 +52,7 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe
}
if(e.key === 'Enter') {
return btnContinue.click();
return onContinueClick();
}
});
@ -65,8 +65,11 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe @@ -65,8 +65,11 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe
return true;
};
attachClickEvent(btnContinue, (e) => {
cancelEvent(e);
const onContinueClick = (e?: Event) => {
if(e) {
cancelEvent(e);
}
if(!verifyInput()) return;
const tab = new AppTwoStepVerificationHintTab(this.slider);
@ -74,7 +77,8 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe @@ -74,7 +77,8 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe
tab.plainPassword = this.plainPassword;
tab.newPassword = this.newPassword;
tab.open();
});
};
attachClickEvent(btnContinue, onContinueClick);
}
onOpenAfterTimeout() {

9
src/components/sidebarLeft/tabs/privacyAndSecurity.ts

@ -7,6 +7,7 @@ import AppPrivacyPhoneNumberTab from "./privacy/phoneNumber"; @@ -7,6 +7,7 @@ import AppPrivacyPhoneNumberTab from "./privacy/phoneNumber";
import AppTwoStepVerificationTab from "./2fa";
import passwordManager from "../../../lib/mtproto/passwordManager";
import AppTwoStepVerificationEnterPasswordTab from "./2fa/enterPassword";
import AppTwoStepVerificationEmailConfirmationTab from "./2fa/emailConfirmation";
export default class AppPrivacyAndSecurityTab extends SliderSuperTab {
constructor(slider: SidebarSlider) {
@ -35,9 +36,15 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTab { @@ -35,9 +36,15 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTab {
title: 'Two-Step Verification',
subtitle: 'Loading...',
clickable: (e: Event) => {
let tab: AppTwoStepVerificationTab | AppTwoStepVerificationEnterPasswordTab;
let tab: AppTwoStepVerificationTab | AppTwoStepVerificationEnterPasswordTab | AppTwoStepVerificationEmailConfirmationTab;
if(passwordState.pFlags.has_password) {
tab = new AppTwoStepVerificationEnterPasswordTab(this.slider);
} else if(passwordState.email_unconfirmed_pattern) {
tab = new AppTwoStepVerificationEmailConfirmationTab(this.slider);
tab.email = passwordState.email_unconfirmed_pattern;
tab.length = 6;
tab.isFirst = true;
passwordManager.resendPasswordEmail();
} else {
tab = new AppTwoStepVerificationTab(this.slider);
}

14
src/helpers/dom.ts

@ -2,7 +2,7 @@ import { MessageEntity } from "../layer"; @@ -2,7 +2,7 @@ import { MessageEntity } from "../layer";
import RichTextProcessor from "../lib/richtextprocessor";
import ListenerSetter from "./listenerSetter";
import { isTouchSupported } from "./touchSupport";
import { isApple } from "./userAgent";
import { isApple, isMobileSafari } from "./userAgent";
import rootScope from "../lib/rootScope";
import { MOUNT_CLASS_TO } from "../config/debug";
import { doubleRaf } from "./schedulers";
@ -784,3 +784,15 @@ export function disableTransition(elements: HTMLElement[]) { @@ -784,3 +784,15 @@ export function disableTransition(elements: HTMLElement[]) {
elements.forEach(el => el.classList.remove('no-transition'));
});
}
export function toggleDisability(elements: HTMLElement[], disable: boolean) {
if(disable) {
elements.forEach(el => el.setAttribute('disabled', 'true'));
} else {
elements.forEach(el => el.removeAttribute('disabled'));
}
}
export function canFocus(isFirstInput: boolean) {
return !isMobileSafari || !isFirstInput;
}

2
src/lib/appManagers/appDialogsManager.ts

@ -181,7 +181,7 @@ export class AppDialogsManager { @@ -181,7 +181,7 @@ export class AppDialogsManager {
public doms: {[peerId: number]: DialogDom} = {};
public chatsContainer = document.getElementById('chatlist-container') as HTMLDivElement;
private chatsPreloader: HTMLDivElement;
private chatsPreloader: HTMLElement;
public loadDialogsPromise: Promise<any>;

12
src/lib/mtproto/passwordManager.ts

@ -80,6 +80,18 @@ export class PasswordManager { @@ -80,6 +80,18 @@ export class PasswordManager {
});
}
public confirmPasswordEmail(code: string) {
return apiManager.invokeApi('account.confirmPasswordEmail', {code});
}
public resendPasswordEmail() {
return apiManager.invokeApi('account.resendPasswordEmail');
}
public cancelPasswordEmail() {
return apiManager.invokeApi('account.cancelPasswordEmail');
}
/* public requestRecovery(options: any = {}) {
return apiManager.invokeApi('auth.requestPasswordRecovery', {}, options);
}

44
src/pages/pageAuthCode.ts

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
import mediaSizes from '../helpers/mediaSizes';
import { AuthSentCode, AuthSentCodeType } from '../layer';
import { AuthSentCode, AuthSentCodeType, AuthSignIn } from '../layer';
import appStateManager from '../lib/appManagers/appStateManager';
import apiManager from '../lib/mtproto/mtprotoworker';
import Page from './page';
@ -7,8 +7,8 @@ import pageIm from './pageIm'; @@ -7,8 +7,8 @@ import pageIm from './pageIm';
import pagePassword from './pagePassword';
import pageSignIn from './pageSignIn';
import pageSignUp from './pageSignUp';
import InputField from '../components/inputField';
import TrackingMonkey from '../components/monkeys/tracking';
import CodeInputField from '../components/codeInputField';
let authCode: AuthSentCode.authSentCode = null;
@ -17,24 +17,21 @@ let sentTypeElement: HTMLParagraphElement = null; @@ -17,24 +17,21 @@ let sentTypeElement: HTMLParagraphElement = null;
let codeInput: HTMLInputElement;
let onFirstMount = (): Promise<any> => {
let lastLength = 0;
const CODELENGTH = (authCode.type as AuthSentCodeType.authSentCodeTypeApp).length;
const codeInputField = new InputField({
const codeInputField = new CodeInputField({
label: 'Code',
name: 'code',
plainText: true
length: CODELENGTH,
onFill: (code) => {
submitCode('' + code);
}
});
codeInput = codeInputField.input as HTMLInputElement;
codeInput.type = 'tel';
codeInput.setAttribute('required', '');
codeInput.autocomplete = 'off';
page.pageEl.querySelector('.input-wrapper').append(codeInputField.container);
const codeInputLabel = codeInput.nextElementSibling as HTMLLabelElement;
const editButton = page.pageEl.querySelector('.phone-edit') as HTMLElement;
editButton.addEventListener('click', function() {
@ -50,7 +47,7 @@ let onFirstMount = (): Promise<any> => { @@ -50,7 +47,7 @@ let onFirstMount = (): Promise<any> => {
const submitCode = (code: string) => {
codeInput.setAttribute('disabled', 'true');
const params = {
const params: AuthSignIn = {
phone_number: authCode.phone_number,
phone_code_hash: authCode.phone_code_hash,
phone_code: code
@ -92,15 +89,15 @@ let onFirstMount = (): Promise<any> => { @@ -92,15 +89,15 @@ let onFirstMount = (): Promise<any> => {
break;
case 'PHONE_CODE_EXPIRED':
codeInput.classList.add('error');
codeInputLabel.innerText = 'Code expired';
codeInputField.label.innerText = 'Code expired';
break;
case 'PHONE_CODE_EMPTY':
case 'PHONE_CODE_INVALID':
codeInput.classList.add('error');
codeInputLabel.innerText = 'Invalid Code';
codeInputField.label.innerText = 'Invalid Code';
break;
default:
codeInputLabel.innerText = err.type;
codeInputField.label.innerText = err.type;
break;
}
@ -108,25 +105,6 @@ let onFirstMount = (): Promise<any> => { @@ -108,25 +105,6 @@ let onFirstMount = (): Promise<any> => {
});
};
codeInput.addEventListener('input', function(this: typeof codeInput, e) {
this.classList.remove('error');
codeInputLabel.innerText = 'Code';
this.value = this.value.replace(/\D/g, '');
if(this.value.length > CODELENGTH) {
this.value = this.value.slice(0, CODELENGTH);
}
const length = this.value.length;
if(length === CODELENGTH) { // submit code
submitCode(this.value);
} else if(length === lastLength) {
return;
}
lastLength = length;
});
const imageDiv = page.pageEl.querySelector('.auth-image') as HTMLDivElement;
const size = mediaSizes.isMobile ? 100 : 166;
const monkey = new TrackingMonkey(codeInputField, size);

4
src/scss/partials/_button.scss

@ -264,6 +264,10 @@ @@ -264,6 +264,10 @@
@include hover-background-effect();
&.danger {
@include hover-background-effect(red);
}
// * tgico
&:before {
color: #707579;

16
src/scss/partials/_leftSidebar.scss

@ -913,8 +913,14 @@ @@ -913,8 +913,14 @@
margin-bottom: 1.125rem;
}
.btn-primary + .btn-primary {
margin-top: .125rem !important;
&-main {
.btn-primary + .btn-primary {
margin-top: .125rem !important;
}
}
.btn-secondary {
margin-top: .5rem !important;
}
.media-sticker-wrapper {
@ -935,12 +941,6 @@ @@ -935,12 +941,6 @@
}
}
&-hint, &-email {
.btn-primary + .btn-primary {
margin-top: .5rem !important;
}
}
&-hint {
.media-sticker-wrapper {
width: 160px;

Loading…
Cancel
Save