Merge pull request #7859 from gabrielbazan7/fix/backupflow

[V4] FIX: Backup flow for wallets with password on their mnemonics
This commit is contained in:
Gustavo Maximiliano Cortez 2018-01-16 14:57:29 -03:00 committed by GitHub
commit 1a537d2b47
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 47 additions and 50 deletions

View File

@ -9,36 +9,41 @@
<ion-content>
<div *ngIf="deleted">
<h1 translate>Wallet recovery phrase not available.</h1>
<p translate>You can still export it from Advanced &gt; Export.</p>
<h1 class="deleted-title">{{'Wallet recovery phrase not available' |translate}}</h1>
<ion-item-divider text-wrap>
{{'You can still export it from Advanced &gt; Export.' |translate}}
<span *ngIf="wallet.coin == 'bch'" translate>
Note: if this BCH wallet was duplicated from a BTC wallet, they share the same recovery phrase.
</span>
</ion-item-divider>
</div>
<ion-slides pager="true" *ngIf="!deleted">
<ion-slide>
<div *ngIf="mnemonicWords && mnemonicWords[0] || !credentialsEncrypted">
<h4 translate>Please carefully write down this phrase.</h4>
<h4 class="slide-title" translate>Please carefully write down this phrase.</h4>
<div copy-to-clipboard="{{ copyRecoveryPhrase() }}" class="phrase">
<span *ngFor="let word of mnemonicWords">
<span>{{word}}</span>
<span *ngIf="useIdeograms">&#x3000;</span>
<span *ngIf="useIdeograms">&#x3000;</span>
</span>
</div>
<div class="bottom-absolute">
<div class="tldr" translate>We'll confirm on the next screen.</div>
<ion-item-divider>{{"We'll confirm on the next screen." | translate}}</ion-item-divider>
<button ion-button block [disabled]="credentialsEncrypted || error" (click)="slideNext()" translate>I've written it down</button>
</div>
</div>
</ion-slide>
<ion-slide>
<h1 translate>Let's verify your backup phrase.</h1>
<h4 class="slide-title" translate>Let's verify your backup phrase.</h4>
<div class="phrase">
<button ion-button outline *ngFor="let customWord of customWords; let i = index" (click)="removeButton(i, customWord)">{{customWord.word}}</button>
</div>
<div class="bottom-absolute">
<div *ngIf="!selectComplete">
<div class="tldr" translate>Please tap each word in the correct order.</div>
<ion-item-divider>{{'Please tap each word in the correct order.' | translate}}</ion-item-divider>
<div>
<button ion-button *ngFor="let shuffledWord of shuffledMnemonicWords; let i = index" (click)="addButton(i, shuffledWord)"
[disabled]="shuffledWord.selected">{{shuffledWord.word}}
@ -47,7 +52,7 @@
</div>
<div *ngIf="selectComplete">
<div class="tldr" translate>Is this correct?</div>
<ion-item-divider>{{'Is this correct?' | translate}}</ion-item-divider>
<div>
<button ion-button block (click)="slideNext();" translate>Confirm</button>
<button ion-button block outline (click)="setFlow();" translate>Clear</button>
@ -57,18 +62,19 @@
</ion-slide>
<ion-slide *ngIf="wallet.mnemonicHasPassphrase">
<h1 translate>Enter your password</h1>
<p translate>In order to verify your wallet backup, please type your password.</p>
<div class="input">
<input type="password" id="passphrase" [(ngModel)]="passphrase" autocapitalize="off" spellcheck="false" />
</div>
<div class="password-required" translate>
This recovery phrase was created with a password. To recover this wallet both the recovery phrase and password are needed.
</div>
<h4 translate>Enter your password</h4>
<ion-item-divider text-wrap>{{'In order to verify your wallet backup, please type your password.' | translate}}</ion-item-divider>
<ion-item>
<ion-label stacked translate>Password</ion-label>
<ion-input type="password" id="password" [(ngModel)]="password" autocapitalize="off" spellcheck="false"></ion-input>
</ion-item>
<ion-item-divider text-wrap class="assertive">
{{'This recovery phrase was created with a password. To recover this wallet both the recovery phrase and password are needed.'
| translate}}
</ion-item-divider>
<div class="bottom-absolute">
<button ion-button block [disabled]="!passphrase" (click)="finalStep();" translate>Confirm</button>
<button ion-button block [disabled]="!password" (click)="finalStep()" translate>Confirm</button>
</div>
</ion-slide>
</ion-slides>

View File

@ -1,9 +1,9 @@
page-backup-game {
p {
line-height: 1.6;
font-size: 18px;
margin-right: 10px;
margin-left: 10px;
.deleted-title {
text-align: center;
}
.slide-title {
padding: 20px;
}
.swiper-pagination {
display: none;
@ -11,11 +11,6 @@ page-backup-game {
.slide-zoom {
height: 100%;
}
.password-required {
padding: 2rem;
font-size: 14px;
color: color($colors, danger);
}
.password {
background-color: color($colors, light);
padding: 2rem;
@ -23,19 +18,10 @@ page-backup-game {
.phrase {
display: -webkit-box;
background: color($colors, light);
border: 2px dashed #d9d9d9;
border-radius: 3px;
color: color($colors, secondary);
text-align: center;
max-width: 500px;
min-height: 12rem;
align-items: center;
margin: 20px auto;
padding: 15px 0;
line-height: 170%;
word-spacing: 10px;
}
.tldr {
padding: 1rem;
}
}

View File

@ -1,11 +1,16 @@
import { Component, ViewChild } from '@angular/core';
import { NavController, Slides, Navbar, AlertController, NavParams } from 'ionic-angular';
import { Logger } from '@nsalaun/ng-logger';
import * as _ from 'lodash';
//pahes
import { DisclaimerPage } from '../../onboarding/disclaimer/disclaimer';
//providers
import { ProfileProvider } from '../../../providers/profile/profile';
import { WalletProvider } from '../../../providers/wallet/wallet';
import { BwcProvider } from '../../../providers/bwc/bwc';
import { Logger } from '@nsalaun/ng-logger';
import * as _ from 'lodash';
import { OnGoingProcessProvider } from '../../../providers/on-going-process/on-going-process';
@Component({
selector: 'page-backup-game',
@ -21,14 +26,13 @@ export class BackupGamePage {
public deleted: boolean;
public mnemonicWords: Array<String>;
public shuffledMnemonicWords: Array<any>;
public passphrase: String;
public password: String;
public customWords: Array<any>;
public selectComplete: boolean;
public error: boolean;
public credentialsEncrypted: boolean;
private mnemonicHasPassphrase: any;
private data: any;
private walletId: string;
private wallet: any;
private keys: any;
@ -41,7 +45,8 @@ export class BackupGamePage {
private logger: Logger,
private profileProvider: ProfileProvider,
private walletProvider: WalletProvider,
private bwcProvider: BwcProvider
private bwcProvider: BwcProvider,
private onGoingProcessProvider: OnGoingProcessProvider
) {
this.walletId = this.navParams.get('walletId');
this.fromOnboarding = this.navParams.get('fromOnboarding');
@ -70,12 +75,13 @@ export class BackupGamePage {
ngOnInit() {
this.currentIndex = 0;
this.navBar.backButtonClick = (e: UIEvent) => {
this.slidePrev();
if (this.slides) this.slidePrev();
else this.navCtrl.pop();
}
}
ionViewDidLoad() {
this.slides.lockSwipes(true);
if (this.slides) this.slides.lockSwipes(true);
}
private shuffledWords(words: Array<String>) {
@ -197,13 +203,12 @@ export class BackupGamePage {
if (!this.keys) return;
let words = this.keys.mnemonic;
this.data = {};
this.mnemonicWords = words.split(/[\u3000\s]+/);
this.shuffledMnemonicWords = this.shuffledWords(this.mnemonicWords);
this.mnemonicHasPassphrase = this.wallet.mnemonicHasPassphrase();
this.useIdeograms = words.indexOf("\u3000") >= 0;
this.data['passphrase'] = null;
this.password = '';
this.customWords = [];
this.selectComplete = false;
this.error = false;
@ -234,12 +239,12 @@ export class BackupGamePage {
let walletClient = this.bwcProvider.getClient();
let separator = this.useIdeograms ? '\u3000' : ' ';
let customSentence = customWordList.join(separator);
let passphrase = this.data.passphrase || '';
let password = this.password || '';
try {
walletClient.seedFromMnemonic(customSentence, {
network: this.wallet.credentials.network,
passphrase: passphrase,
password: password,
account: this.wallet.credentials.account
});
} catch (err) {
@ -259,9 +264,9 @@ export class BackupGamePage {
};
private finalStep(): void {
//ongoingProcess.set('validatingWords', true);
this.onGoingProcessProvider.set('validatingWords', true);
this.confirm().then(() => {
//ongoingProcess.set('validatingWords', false);
this.onGoingProcessProvider.set('validatingWords', false);
this.showBackupResult();
}).catch((err) => {
this.backupError(err);