Commit d4a49e4f authored by dev0tion's avatar dev0tion

Add mnemonic verification

parent cf736886
<section id="breeze">
<div class="login d-flex align-items-center text-center">
<div class="container">
<p class="textback text-left mb-5 col-11 mx-auto">
<a (click)="onBackClicked()">
<span class="ico-arrow-left2"></span>
</a>
</p>
<h3 class="display-5">Confirm secret words</h3>
<p class="lead">Please enter the corresponding secret words below.</p>
<!-- /row-->
<div class="row d-flex justify-content-center">
<form class="col-md-8 col-xs-12 text-left" [formGroup]="mnemonicForm">
<div class="form-group">
<label class="col-12 row" for="word1">Word n°4</label>
<input type="text" class="form-control" formControlName="word1" id="word1">
<div *ngIf="formErrors.word1" class="text-danger mt-2">{{ formErrors.word1 }}</div>
</div>
<div class="form-group">
<label class="col-12 row" for="word2">Word n°8</label>
<input type="text" class="form-control" formControlName="word2" id="word2">
<div *ngIf="formErrors.word2" class="text-danger mt-2">{{ formErrors.word2 }}</div>
</div>
<div class="form-group">
<label class="col-12 row" for="word3">Word n°12</label>
<input type="text" class="form-control" formControlName="word3" id="word3">
<div *ngIf="formErrors.word3" class="text-danger mt-2">{{ formErrors.word3 }}</div>
</div>
<div *ngIf="matchError" class="text-danger mt-2">{{ matchError }}</div>
</form>
</div>
<div class="row d-flex justify-content-center" *ngIf="!isCreating">
<button type="button" class="btn btn-darkgray btn-lg" [disabled]="!mnemonicForm.valid || isCreating" (click)="onConfirmClicked()">Confirm</button>
</div>
<div class="row d-flex justify-content-center" *ngIf="isCreating">
<div class="spinner">
<div class="double-bounce1"></div>
<div class="double-bounce2"></div>
</div>
</div>
<!-- /row-->
</div>
<!-- /container-->
</div>
<!-- /login-->
</section>
<!-- /breeze-->
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ConfirmMnemonicComponent } from './confirm-mnemonic.component';
describe('ConfirmMnemonicComponent', () => {
let component: ConfirmMnemonicComponent;
let fixture: ComponentFixture<ConfirmMnemonicComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ConfirmMnemonicComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ConfirmMnemonicComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators, FormBuilder } from '@angular/forms';
import { Router, ActivatedRoute } from '@angular/router';
import { GlobalService } from '../../../shared/services/global.service';
import { ApiService } from '../../../shared/services/api.service';
import { ModalService } from '../../../shared/services/modal.service';
import { WalletCreation } from '../../../shared/classes/wallet-creation';
import { Subscription } from 'rxjs/Subscription';
import { Subscribable } from 'rxjs/Observable';
@Component({
selector: 'app-confirm-mnemonic',
templateUrl: './confirm-mnemonic.component.html',
styleUrls: ['./confirm-mnemonic.component.css']
})
export class ConfirmMnemonicComponent implements OnInit {
constructor(private globalService: GlobalService, private apiService: ApiService, private genericModalService: ModalService, private route: ActivatedRoute, private router: Router, private fb: FormBuilder) {
this.buildMnemonicForm();
}
private subscription: Subscription;
private newWallet: WalletCreation;
public mnemonicForm: FormGroup;
public matchError: string = "";
public isCreating: boolean;
ngOnInit() {
this.subscription = this.route.queryParams.subscribe(params => {
this.newWallet = new WalletCreation(
params["name"],
params["mnemonic"],
params["password"]
)
});
}
private buildMnemonicForm(): void {
this.mnemonicForm = this.fb.group({
"word1": ["",
Validators.compose([
Validators.required,
Validators.minLength(1),
Validators.maxLength(24),
Validators.pattern(/^[a-zA-Z]*$/)
])
],
"word2": ["",
Validators.compose([
Validators.required,
Validators.minLength(1),
Validators.maxLength(24),
Validators.pattern(/^[a-zA-Z]*$/)
])
],
"word3": ["",
Validators.compose([
Validators.required,
Validators.minLength(1),
Validators.maxLength(24),
Validators.pattern(/^[a-zA-Z]*$/)
])
]
});
this.mnemonicForm.valueChanges
.subscribe(data => this.onValueChanged(data));
this.onValueChanged();
}
onValueChanged(data?: any) {
if (!this.mnemonicForm) { return; }
const form = this.mnemonicForm;
for (const field in this.formErrors) {
this.formErrors[field] = '';
const control = form.get(field);
if (control && control.dirty && !control.valid) {
const messages = this.validationMessages[field];
for (const key in control.errors) {
this.formErrors[field] += messages[key] + ' ';
}
}
}
this.matchError = "";
}
formErrors = {
'word1': '',
'word2': '',
'word3': ''
};
validationMessages = {
'word1': {
'required': 'This secret word is required.',
'minlength': 'A secret word must be at least one character long',
'maxlength': 'A secret word can not be longer than 24 characters',
'pattern': 'Please enter a valid scret word. [a-Z] are the only characters allowed.'
},
'word2': {
'required': 'This secret word is required.',
'minlength': 'A secret word must be at least one character long',
'maxlength': 'A secret word can not be longer than 24 characters',
'pattern': 'Please enter a valid scret word. [a-Z] are the only characters allowed.'
},
'word3': {
'required': 'This secret word is required.',
'minlength': 'A secret word must be at least one character long',
'maxlength': 'A secret word can not be longer than 24 characters',
'pattern': 'Please enter a valid scret word. [a-Z] are the only characters allowed.'
}
};
public onConfirmClicked() {
this.checkMnemonic();
if (this.checkMnemonic()) {
this.isCreating = true;
this.createWallets(this.newWallet);
}
}
public onBackClicked() {
this.router.navigate(['/setup/create/show-mnemonic'], { queryParams : { name: this.newWallet.name, mnemonic: this.newWallet.mnemonic, password: this.newWallet.password }});
}
private checkMnemonic(): boolean {
let mnemonic = this.newWallet.mnemonic;
let mnemonicArray = mnemonic.split(" ");
if (this.mnemonicForm.get("word1").value.trim() === mnemonicArray[3] && this.mnemonicForm.get("word2").value.trim() === mnemonicArray[7] && this.mnemonicForm.get("word3").value.trim() === mnemonicArray[11]) {
return true;
} else {
this.matchError = "The secret words do not match."
return false;
}
}
private createWallets(wallet: WalletCreation) {
this.apiService
.createBitcoinWallet(wallet)
.subscribe(
response => {
if (response.status >= 200 && response.status < 400){
// Bitcoin wallet created
}
},
error => {
console.log(error);
this.isCreating = false;
if (error.status === 0) {
this.genericModalService.openModal(null, null);
} else if (error.status >= 400) {
if (!error.json().errors[0]) {
console.log(error);
}
else {
this.genericModalService.openModal(null, error.json().errors[0].message);
this.router.navigate(['/setup/create']);
}
}
},
() => this.createStratisWallet(wallet)
)
;
}
private createStratisWallet(wallet: WalletCreation) {
this.apiService
.createStratisWallet(wallet)
.subscribe(
response => {
if (response.status >= 200 && response.status < 400){
this.genericModalService.openModal("Wallet Created", "Your wallet has been created.<br>Keep your secret words and password safe!");
this.router.navigate(['']);
}
},
error => {
this.isCreating = false;
console.log(error);
if (error.status === 0) {
this.genericModalService.openModal(null, null);
} else if (error.status >= 400) {
if (!error.json().errors[0]) {
console.log(error);
}
else {
this.genericModalService.openModal(null, error.json().errors[0].message);
this.router.navigate(['/setup/create']);
}
}
}
)
;
}
}
......@@ -31,14 +31,8 @@
</form>
</div>
<!-- /row-->
<div class="row d-flex justify-content-center" *ngIf="!isCreating">
<button type="button" class="btn btn-darkgray btn-lg" [disabled]="!createWalletForm.valid || isCreating" (click)="onCreateClicked()">Create</button>
</div>
<div class="row d-flex justify-content-center" *ngIf="isCreating">
<div class="spinner">
<div class="double-bounce1"></div>
<div class="double-bounce2"></div>
</div>
<div class="row d-flex justify-content-center">
<button type="button" class="btn btn-darkgray btn-lg" [disabled]="!createWalletForm.valid" (click)="onContinueClicked()">Continue</button>
</div>
<!-- /row-->
</div>
......
......@@ -25,7 +25,6 @@ export class CreateComponent implements OnInit {
public createWalletForm: FormGroup;
private newWallet: WalletCreation;
private mnemonic: string;
public isCreating: boolean = false;
ngOnInit() {
this.getNewMnemonic();
......@@ -101,15 +100,15 @@ export class CreateComponent implements OnInit {
this.router.navigate(["/setup"]);
}
public onCreateClicked() {
this.isCreating = true;
public onContinueClicked() {
if (this.mnemonic) {
this.newWallet = new WalletCreation(
this.createWalletForm.get("walletName").value,
this.mnemonic,
this.createWalletForm.get("walletPassword").value,
);
this.createWallets(this.newWallet);
this.router.navigate(['/setup/create/show-mnemonic'], { queryParams : { name: this.newWallet.name, mnemonic: this.newWallet.mnemonic, password: this.newWallet.password }});
//this.createWallets(this.newWallet);
}
}
......@@ -138,61 +137,4 @@ export class CreateComponent implements OnInit {
)
;
}
private createWallets(wallet: WalletCreation) {
this.apiService
.createBitcoinWallet(wallet)
.subscribe(
response => {
if (response.status >= 200 && response.status < 400){
// Bitcoin wallet created
}
},
error => {
console.log(error);
this.isCreating = false;
if (error.status === 0) {
this.genericModalService.openModal(null, null);
} else if (error.status >= 400) {
if (!error.json().errors[0]) {
console.log(error);
}
else {
this.genericModalService.openModal(null, error.json().errors[0].message);
}
}
},
() => this.createStratisWallet(wallet)
)
;
}
private createStratisWallet(wallet: WalletCreation) {
this.apiService
.createStratisWallet(wallet)
.subscribe(
response => {
if (response.status >= 200 && response.status < 400){
let walletBody = "Your wallet has been created.<br><br>Please write down your 12 word passphrase: <br>" + this.mnemonic + "<br><br>You can recover your wallet on any computer with:<br>- your passphrase<br>- your password<br>- In addition, knowing the approximate date at which you created your wallet will speed up recovery.<br><br>Unlike most other wallets if an attacker acquires your passphrase, he will not be able to hack your wallet without knowing your password. On the contrary, unlike other wallets, you will not be able to recover your wallet only with your passphrase if you lose your password.";
this.genericModalService.openModal("Wallet Info", walletBody);
this.router.navigate(['']);
}
},
error => {
this.isCreating = false;
console.log(error);
if (error.status === 0) {
this.genericModalService.openModal(null, null);
} else if (error.status >= 400) {
if (!error.json().errors[0]) {
console.log(error);
}
else {
this.genericModalService.openModal(null, error.json().errors[0].message);
}
}
}
)
;
}
}
<section id="breeze">
<div class="login d-flex align-items-center text-center">
<div class="container">
<p class="textback text-left mb-5 col-11 mx-auto">
<a (click)="onBackClicked()">
<span class="ico-arrow-left2"></span>
</a>
</p>
<h3 class="display-5">Secret words</h3>
<p class="lead">Please write down your secret words and password. <br>You will need <strong>both</strong> to recover your wallet in the future.</p>
<div class="row d-flex justify-content-center my-5">
<ul *ngFor="let word of mnemonicArray; let i=index" class="list-inline list-unstyled col-xs-12 col-md-6">
<li class="list-inline-item"><span class="badge badge-default">{{ i + 1 }}. {{ word }}</span></li>
</ul>
</div>
<!-- /row-->
<div class="row d-flex justify-content-center">
<!-- <button type="button" class="btn btn-linkgray btn-lg col-12">Save the list somewhere</button> -->
<button type="button" class="btn btn-darkgray btn-lg" (click)="onContinueClicked()">Continue</button>
</div>
<!-- /row-->
</div>
<!-- /container-->
</div>
<!-- /login-->
</section>
<!-- /breeze-->
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ShowMnemonicComponent } from './show-mnemonic.component';
describe('ShowMnemonicComponent', () => {
let component: ShowMnemonicComponent;
let fixture: ComponentFixture<ShowMnemonicComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ShowMnemonicComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ShowMnemonicComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { WalletCreation } from '../../../shared/classes/wallet-creation';
import { Subscription } from 'rxjs/Subscription';
@Component({
selector: 'app-show-mnemonic',
templateUrl: './show-mnemonic.component.html',
styleUrls: ['./show-mnemonic.component.css']
})
export class ShowMnemonicComponent implements OnInit, OnDestroy {
constructor(private route: ActivatedRoute, private router: Router) { }
private parameters: any;
private mnemonic: string;
private subscription: Subscription;
private newWallet: WalletCreation;
public mnemonicArray: string[];
ngOnInit() {
this.subscription = this.route.queryParams.subscribe(params => {
this.newWallet = new WalletCreation(
params["name"],
params["mnemonic"],
params["password"]
)
});
this.showMnemonic();
}
private showMnemonic() {
this.mnemonic = this.newWallet.mnemonic;
this.mnemonicArray = this.mnemonic.split(" ");
}
public onContinueClicked() {
this.router.navigate(['/setup/create/confirm-mnemonic'], { queryParams : { name: this.newWallet.name, mnemonic: this.newWallet.mnemonic, password: this.newWallet.password }});
}
public onBackClicked() {
this.router.navigate(['/setup/create']);
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
......@@ -3,12 +3,16 @@ import { RouterModule, Routes } from '@angular/router';
import { SetupComponent } from './setup.component';
import { CreateComponent } from './create/create.component';
import { ShowMnemonicComponent } from './create/show-mnemonic/show-mnemonic.component';
import { ConfirmMnemonicComponent } from './create/confirm-mnemonic/confirm-mnemonic.component';
import { RecoverComponent } from './recover/recover.component';
const routes: Routes = [
{ path: '', redirectTo: 'setup', pathMatch: 'full'},
{ path: 'setup', component: SetupComponent },
{ path: 'create', component: CreateComponent },
{ path: 'create/show-mnemonic', component: ShowMnemonicComponent },
{ path: 'create/confirm-mnemonic', component: ConfirmMnemonicComponent },
{ path: 'recover', component: RecoverComponent }
];
......
......@@ -10,6 +10,8 @@ import { SharedModule } from '../shared/shared.module';
import { SetupRoutingModule } from './setup-routing.module';
import { RecoverComponent } from './recover/recover.component';
import { ShowMnemonicComponent } from './create/show-mnemonic/show-mnemonic.component';
import { ConfirmMnemonicComponent } from './create/confirm-mnemonic/confirm-mnemonic.component';
@NgModule({
imports: [
......@@ -22,7 +24,9 @@ import { RecoverComponent } from './recover/recover.component';
declarations: [
CreateComponent,
SetupComponent,
RecoverComponent
RecoverComponent,
ShowMnemonicComponent,
ConfirmMnemonicComponent
],
exports: [],
providers: []
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment