1
0
Fork 0
forked from lthn/blockchain

Merge branch 'frontend'

This commit is contained in:
wildkif 2019-04-22 20:48:06 +03:00
commit f79e9937a6
27 changed files with 818 additions and 296 deletions

View file

@ -4,6 +4,7 @@
"SETUP_CONFIRM_PASS": "Confirm the password",
"MASTER_PASS": "Master password",
"BUTTON_NEXT": "Next",
"BUTTON_SKIP": "Skip",
"INCORRECT_PASSWORD": "Invalid password",
"FORM_ERRORS": {
"PASS_REQUIRED": "Password is required.",
@ -83,6 +84,13 @@
"NAME_REQUIRED": "Name is required.",
"NAME_DUPLICATE": "Name is duplicate.",
"MAX_LENGTH": "Maximum name length reached."
},
"MODAL": {
"TITLE": "Type wallet password",
"LABEL": "Password to this wallet",
"OPEN": "Open wallet",
"SKIP": "Skip",
"NOT_FOUND": "Not found"
}
},
"RESTORE_WALLET": {

View file

@ -780,3 +780,14 @@ app-progress-container {
}
}
}
app-open-wallet-modal {
.modal {
@include themify($themes) {
background: themed(modalBackground);
color: themed(mainTextColor);
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -13,9 +13,27 @@ export class BackendService {
backendObject: any;
backendLoaded = false;
constructor(private translate: TranslateService, private variablesService: VariablesService, private modalService: ModalService, private moneyToIntPipe: MoneyToIntPipe) {}
constructor(
private translate: TranslateService,
private variablesService: VariablesService,
private modalService: ModalService,
private moneyToIntPipe: MoneyToIntPipe
) {
}
private Debug(type, message) {
static bigNumberParser(key, val) {
if (val.constructor.name === 'BigNumber' && ['balance', 'unlocked_balance', 'amount', 'fee', 'b_fee', 'to_pay', 'a_pledge', 'b_pledge', 'coast', 'a'].indexOf(key) === -1) {
return val.toNumber();
}
if (key === 'rcv' || key === 'spn') {
for (let i = 0; i < val.length; i++) {
val[i] = new BigNumber(val[i]);
}
}
return val;
}
static Debug(type, message) {
switch (type) {
case 0:
console.error(message);
@ -112,13 +130,14 @@ export class BackendService {
}
}
break;
case 'NOT_FOUND': if (command !== 'open_wallet' && command !== 'get_alias_info_by_name' && command !== 'get_alias_info_by_address') {
error_translate = this.translate.instant('ERRORS.FILE_NOT_FOUND');
params = JSON.parse(params);
if (params.path) {
error_translate += ': ' + params.path;
case 'NOT_FOUND':
if (command !== 'open_wallet' && command !== 'get_alias_info_by_name' && command !== 'get_alias_info_by_address') {
error_translate = this.translate.instant('ERRORS.FILE_NOT_FOUND');
params = JSON.parse(params);
if (params.path) {
error_translate += ': ' + params.path;
}
}
}
break;
case 'CANCELED':
case '':
@ -142,36 +161,21 @@ export class BackendService {
}
}
private bigNumberParser(key, val) {
if (val.constructor.name === 'BigNumber' && ['balance', 'unlocked_balance', 'amount', 'fee', 'b_fee', 'to_pay', 'a_pledge', 'b_pledge', 'coast', 'a'].indexOf(key) === -1) {
return val.toNumber();
}
if (key === 'rcv' || key === 'spn') {
for (let i = 0; i < val.length; i++) {
val[i] = new BigNumber(val[i]);
}
}
return val;
}
private commandDebug(command, params, result) {
this.Debug(2, '----------------- ' + command + ' -----------------');
BackendService.Debug(2, '----------------- ' + command + ' -----------------');
const debug = {
_send_params: params,
_result: result
};
this.Debug(2, debug);
BackendService.Debug(2, debug);
try {
this.Debug(2, JSONBigNumber.parse(result, this.bigNumberParser));
BackendService.Debug(2, JSONBigNumber.parse(result, BackendService.bigNumberParser));
} catch (e) {
this.Debug(2, {response_data: result, error_code: 'OK'});
BackendService.Debug(2, {response_data: result, error_code: 'OK'});
}
}
private asVal(data) {
return {v: data};
}
private backendCallback(resultStr, params, callback, command) {
let Result = resultStr;
if (command !== 'get_clipboard') {
@ -179,7 +183,7 @@ export class BackendService {
Result = {};
} else {
try {
Result = JSONBigNumber.parse(resultStr, this.bigNumberParser);
Result = JSONBigNumber.parse(resultStr, BackendService.bigNumberParser);
} catch (e) {
Result = {response_data: resultStr, error_code: 'OK'};
}
@ -194,7 +198,7 @@ export class BackendService {
const Status = (Result.error_code === 'OK' || Result.error_code === 'TRUE');
if (!Status && Status !== undefined && Result.error_code !== undefined) {
this.Debug(1, 'API error for command: "' + command + '". Error code: ' + Result.error_code);
BackendService.Debug(1, 'API error for command: "' + command + '". Error code: ' + Result.error_code);
}
const data = ((typeof Result === 'object') && 'response_data' in Result) ? Result.response_data : Result;
@ -220,7 +224,7 @@ export class BackendService {
if (this.backendObject) {
const Action = this.backendObject[command];
if (!Action) {
this.Debug(0, 'Run Command Error! Command "' + command + '" don\'t found in backendObject');
BackendService.Debug(0, 'Run Command Error! Command "' + command + '" don\'t found in backendObject');
} else {
const that = this;
params = (typeof params === 'string') ? params : JSONBigNumber.stringify(params);
@ -245,7 +249,7 @@ export class BackendService {
this.backendObject[command].connect(callback);
} else {
this.backendObject[command].connect((str) => {
callback(JSONBigNumber.parse(str, this.bigNumberParser));
callback(JSONBigNumber.parse(str, BackendService.bigNumberParser));
});
}
}
@ -285,6 +289,12 @@ export class BackendService {
}
storeAppData(callback?) {
if (this.variablesService.wallets.length) {
this.variablesService.settings.wallets = [];
this.variablesService.wallets.forEach((wallet) => {
this.variablesService.settings.wallets.push({name: wallet.name, path: wallet.path});
});
}
this.runCommand('store_app_data', this.variablesService.settings, callback);
}
@ -292,10 +302,7 @@ export class BackendService {
this.runCommand('get_secure_app_data', pass, callback);
}
storeSecureAppData(callback) {
if (this.variablesService.appPass === '') {
return callback(false);
}
storeSecureAppData(callback?) {
const wallets = [];
this.variablesService.wallets.forEach((wallet) => {
wallets.push({name: wallet.name, pass: wallet.pass, path: wallet.path});
@ -305,6 +312,12 @@ export class BackendService {
});
}
dropSecureAppData(callback?) {
this.backendObject['drop_secure_app_data']((dataStore) => {
this.backendCallback(dataStore, {}, callback, 'drop_secure_app_data');
});
}
haveSecureAppData(callback) {
this.runCommand('have_secure_app_data', {}, callback);
}
@ -346,7 +359,7 @@ export class BackendService {
this.runCommand('open_wallet', params, callback);
}
closeWallet(wallet_id, callback) {
closeWallet(wallet_id, callback?) {
this.runCommand('close_wallet', {wallet_id: +wallet_id}, callback);
}
@ -354,7 +367,7 @@ export class BackendService {
this.runCommand('get_smart_wallet_info', {wallet_id: +wallet_id}, callback);
}
runWallet(wallet_id, callback) {
runWallet(wallet_id, callback?) {
this.runCommand('run_wallet', {wallet_id: +wallet_id}, callback);
}
@ -418,7 +431,7 @@ export class BackendService {
fee: this.variablesService.default_fee_big,
b_fee: this.variablesService.default_fee_big
};
this.Debug(1, params);
BackendService.Debug(1, params);
this.runCommand('create_proposal', params, callback);
}
@ -426,7 +439,7 @@ export class BackendService {
const params = {
wallet_id: parseInt(wallet_id, 10)
};
this.Debug(1, params);
BackendService.Debug(1, params);
this.runCommand('get_contracts', params, callback);
}
@ -435,7 +448,7 @@ export class BackendService {
wallet_id: parseInt(wallet_id, 10),
contract_id: contract_id
};
this.Debug(1, params);
BackendService.Debug(1, params);
this.runCommand('accept_proposal', params, callback);
}
@ -445,7 +458,7 @@ export class BackendService {
contract_id: contract_id,
release_type: release_type // "normal" or "burn"
};
this.Debug(1, params);
BackendService.Debug(1, params);
this.runCommand('release_contract', params, callback);
}
@ -456,7 +469,7 @@ export class BackendService {
fee: this.variablesService.default_fee_big,
expiration_period: parseInt(time, 10) * 60 * 60
};
this.Debug(1, params);
BackendService.Debug(1, params);
this.runCommand('request_cancel_contract', params, callback);
}
@ -465,7 +478,7 @@ export class BackendService {
wallet_id: parseInt(wallet_id, 10),
contract_id: contract_id
};
this.Debug(1, params);
BackendService.Debug(1, params);
this.runCommand('accept_cancel_contract', params, callback);
}
@ -506,7 +519,7 @@ export class BackendService {
this.runCommand('set_localization_strings', params, callback);
}
registerAlias (wallet_id, alias, address, fee, comment, reward, callback) {
registerAlias(wallet_id, alias, address, fee, comment, reward, callback) {
const params = {
wallet_id: wallet_id,
alias: {
@ -521,7 +534,7 @@ export class BackendService {
this.runCommand('request_alias_registration', params, callback);
}
updateAlias (wallet_id, alias, fee, callback) {
updateAlias(wallet_id, alias, fee, callback) {
const params = {
wallet_id: wallet_id,
alias: {
@ -535,24 +548,24 @@ export class BackendService {
this.runCommand('request_alias_update', params, callback);
}
getAllAliases (callback) {
getAllAliases(callback) {
this.runCommand('get_all_aliases', {}, callback);
}
getAliasByName (value, callback) {
getAliasByName(value, callback) {
return this.runCommand('get_alias_info_by_name', value, callback);
}
getAliasByAddress (value, callback) {
getAliasByAddress(value, callback) {
return this.runCommand('get_alias_info_by_address', value, callback);
}
getAliasCoast (alias, callback) {
getAliasCoast(alias, callback) {
this.runCommand('get_alias_coast', {v: alias}, callback);
}
getWalletAlias(address) {
if (address != null && this.variablesService.daemon_state === 2) {
if (address !== null && this.variablesService.daemon_state === 2) {
if (this.variablesService.aliasesChecked[address] == null) {
this.variablesService.aliasesChecked[address] = {};
if (this.variablesService.aliases.length) {

View file

@ -13,6 +13,7 @@ export class VariablesService {
public digits = 12;
public appPass = '';
public appLogin = false;
public moneyEquivalent = 0;
public defaultTheme = 'dark';
public defaultCurrency = 'ZAN';
@ -35,7 +36,8 @@ export class VariablesService {
language: 'en',
default_path: '/',
viewedContracts: [],
notViewedContracts: []
notViewedContracts: [],
wallets: []
};
public wallets: Array<Wallet> = [];
@ -56,6 +58,7 @@ export class VariablesService {
this.ngZone.run(() => {
this.idle.stop();
this.appPass = '';
this.appLogin = false;
this.router.navigate(['/login'], {queryParams: {type: 'auth'}});
});
});

View file

@ -1,4 +1,4 @@
<app-sidebar *ngIf="variablesService.appPass"></app-sidebar>
<app-sidebar *ngIf="variablesService.appLogin"></app-sidebar>
<div class="app-content scrolled-content">
<router-outlet *ngIf="[0, 1, 2].indexOf(variablesService.daemon_state) !== -1"></router-outlet>
@ -24,3 +24,6 @@
<ng-template contextMenuItem (execute)="contextMenuPaste($event.item)">{{ 'CONTEXT_MENU.PASTE' | translate }}</ng-template>
<ng-template contextMenuItem (execute)="contextMenuSelect($event.item)">{{ 'CONTEXT_MENU.SELECT' | translate }}</ng-template>
</context-menu>
<app-open-wallet-modal *ngIf="needOpenWallets.length" [wallets]="needOpenWallets"></app-open-wallet-modal>

View file

@ -20,6 +20,8 @@ export class AppComponent implements OnInit, OnDestroy {
onQuitRequest = false;
firstOnlineState = false;
needOpenWallets = [];
@ViewChild('allContextMenu') public allContextMenu: ContextMenuComponent;
@ViewChild('onlyCopyContextMenu') public onlyCopyContextMenu: ContextMenuComponent;
@ -75,8 +77,9 @@ export class AppComponent implements OnInit, OnDestroy {
this.ngZone.run(() => {
this.router.navigate(['/']);
});
this.needOpenWallets = [];
this.variablesService.daemon_state = 5;
this.backend.storeSecureAppData(() => {
const saveFunction = () => {
this.backend.storeAppData(() => {
const recursionCloseWallets = () => {
if (this.variablesService.wallets.length) {
@ -91,7 +94,14 @@ export class AppComponent implements OnInit, OnDestroy {
};
recursionCloseWallets();
});
});
};
if (this.variablesService.appPass) {
this.backend.storeSecureAppData(() => {
saveFunction();
});
} else {
saveFunction();
}
}
this.onQuitRequest = true;
});
@ -386,7 +396,8 @@ export class AppComponent implements OnInit, OnDestroy {
for (let i = 0, length = data.events.length; i < length; i++) {
switch (data.events[i].method) {
case 'CORE_EVENT_BLOCK_ADDED': break;
case 'CORE_EVENT_BLOCK_ADDED':
break;
case 'CORE_EVENT_ADD_ALIAS':
if (this.variablesService.aliasesChecked[data.events[i].details.address] != null) {
this.variablesService.aliasesChecked[data.events[i].details.address]['name'] = '@' + data.events[i].details.alias;
@ -439,7 +450,8 @@ export class AppComponent implements OnInit, OnDestroy {
}
this.variablesService.changeAliases();
break;
default: break;
default:
break;
}
}
}
@ -490,9 +502,17 @@ export class AppComponent implements OnInit, OnDestroy {
this.router.navigate(['/login'], {queryParams: {type: 'auth'}});
});
} else {
this.ngZone.run(() => {
this.router.navigate(['/login'], {queryParams: {type: 'reg'}});
});
if (Object.keys(data).length !== 0) {
this.needOpenWallets = JSON.parse(JSON.stringify(this.variablesService.settings.wallets));
this.ngZone.run(() => {
this.variablesService.appLogin = true;
this.router.navigate(['/']);
});
} else {
this.ngZone.run(() => {
this.router.navigate(['/login'], {queryParams: {type: 'reg'}});
});
}
}
});
}
@ -531,6 +551,9 @@ export class AppComponent implements OnInit, OnDestroy {
} else if (error === 'OVERFLOW') {
this.variablesService.aliases = [];
this.variablesService.enableAliasSearch = false;
this.variablesService.wallets.forEach(wallet => {
wallet.alias = this.backend.getWalletAlias(wallet.address);
});
} else {
this.variablesService.enableAliasSearch = true;
if (data.aliases && data.aliases.length) {
@ -547,10 +570,18 @@ export class AppComponent implements OnInit, OnDestroy {
wallet.alias = this.backend.getWalletAlias(wallet.address);
});
this.variablesService.aliases = this.variablesService.aliases.sort((a, b) => {
if (a.name.length > b.name.length) return 1;
if (a.name.length < b.name.length) return -1;
if (a.name > b.name) return 1;
if (a.name < b.name) return -1;
if (a.name.length > b.name.length) {
return 1;
}
if (a.name.length < b.name.length) {
return -1;
}
if (a.name > b.name) {
return 1;
}
if (a.name < b.name) {
return -1;
}
return 0;
});
this.variablesService.changeAliases();

View file

@ -10,6 +10,7 @@ import { SidebarComponent } from './sidebar/sidebar.component';
import { MainComponent } from './main/main.component';
import { CreateWalletComponent } from './create-wallet/create-wallet.component';
import { OpenWalletComponent } from './open-wallet/open-wallet.component';
import { OpenWalletModalComponent } from './open-wallet-modal/open-wallet-modal.component';
import { RestoreWalletComponent } from './restore-wallet/restore-wallet.component';
import { SeedPhraseComponent } from './seed-phrase/seed-phrase.component';
import { WalletDetailsComponent } from './wallet-details/wallet-details.component';
@ -73,6 +74,7 @@ Highcharts.setOptions({
MainComponent,
CreateWalletComponent,
OpenWalletComponent,
OpenWalletModalComponent,
RestoreWalletComponent,
SeedPhraseComponent,
WalletDetailsComponent,

View file

@ -77,6 +77,7 @@ export class CreateWalletComponent implements OnInit {
generate_data['wi'].mined_total,
generate_data['wi'].tracking_hey
);
this.variablesService.opening_wallet.alias = this.backend.getWalletAlias(generate_data['wi'].address);
this.ngZone.run(() => {
this.walletSaved = true;
this.progressWidth = '50%';

View file

@ -9,21 +9,11 @@
<div class="input-block">
<label for="master-pass">{{ 'LOGIN.SETUP_MASTER_PASS' | translate }}</label>
<input type="password" id="master-pass" formControlName="password" (contextmenu)="variablesService.onContextMenuPasteSelect($event)">
<div class="error-block" *ngIf="regForm.controls['password'].invalid && (regForm.controls['password'].dirty || regForm.controls['password'].touched)">
<div *ngIf="regForm.controls['password'].errors['required']">
{{ 'LOGIN.FORM_ERRORS.PASS_REQUIRED' | translate }}
</div>
</div>
</div>
<div class="input-block">
<label for="confirm-pass">{{ 'LOGIN.SETUP_CONFIRM_PASS' | translate }}</label>
<input type="password" id="confirm-pass" formControlName="confirmation" (contextmenu)="variablesService.onContextMenuPasteSelect($event)">
<div class="error-block" *ngIf="regForm.controls['confirmation'].invalid && (regForm.controls['confirmation'].dirty || regForm.controls['confirmation'].touched)">
<div *ngIf="regForm.controls['confirmation'].errors['required']">
{{ 'LOGIN.FORM_ERRORS.CONFIRM_REQUIRED' | translate }}
</div>
</div>
<div class="error-block" *ngIf="regForm.controls['password'].dirty && regForm.controls['confirmation'].dirty && regForm.errors">
<div *ngIf="regForm.errors['mismatch']">
{{ 'LOGIN.FORM_ERRORS.MISMATCH' | translate }}
@ -31,7 +21,10 @@
</div>
</div>
<button type="submit" class="blue-button">{{ 'LOGIN.BUTTON_NEXT' | translate }}</button>
<div class="wrap-button">
<button type="submit" class="blue-button" [disabled]="!regForm.controls['password'].value.length || !regForm.controls['confirmation'].value.length || (regForm.errors && regForm.errors['mismatch'])">{{ 'LOGIN.BUTTON_NEXT' | translate }}</button>
<button type="button" class="blue-button" (click)="onSkipCreatePass()" [disabled]="regForm.controls['password'].value.length || regForm.controls['confirmation'].value.length">{{ 'LOGIN.BUTTON_SKIP' | translate }}</button>
</div>
</form>
@ -40,11 +33,6 @@
<div class="input-block">
<label for="master-pass-login">{{ 'LOGIN.MASTER_PASS' | translate }}</label>
<input type="password" id="master-pass-login" formControlName="password" autofocus (contextmenu)="variablesService.onContextMenuPasteSelect($event)">
<div class="error-block" *ngIf="authForm.controls['password'].invalid && (authForm.controls['password'].dirty || authForm.controls['password'].touched)">
<div *ngIf="authForm.controls['password'].errors['required']">
{{ 'LOGIN.FORM_ERRORS.PASS_REQUIRED' | translate }}
</div>
</div>
</div>
<button type="submit" class="blue-button">{{ 'LOGIN.BUTTON_NEXT' | translate }}</button>

View file

@ -16,13 +16,23 @@
.logo {
background: url(../../assets/icons/logo.svg) no-repeat center;
width: 100%;
height: 20rem;
height: 15rem;
}
.form-login {
display: flex;
flex-direction: column;
.wrap-button {
display: flex;
align-items: center;
justify-content: space-between;
button {
margin: 2.5rem 0;
}
}
button {
margin: 2.5rem auto;
width: 100%;

View file

@ -16,14 +16,14 @@ export class LoginComponent implements OnInit, OnDestroy {
queryRouting;
regForm = new FormGroup({
password: new FormControl('', Validators.required),
confirmation: new FormControl('', Validators.required)
password: new FormControl(''),
confirmation: new FormControl('')
}, function (g: FormGroup) {
return g.get('password').value === g.get('confirmation').value ? null : {'mismatch': true};
});
authForm = new FormGroup({
password: new FormControl('', Validators.required)
password: new FormControl('')
});
type = 'reg';
@ -32,7 +32,7 @@ export class LoginComponent implements OnInit, OnDestroy {
private route: ActivatedRoute,
private router: Router,
private backend: BackendService,
private variablesService: VariablesService,
public variablesService: VariablesService,
private modalService: ModalService,
private ngZone: NgZone
) {
@ -51,6 +51,8 @@ export class LoginComponent implements OnInit, OnDestroy {
this.variablesService.appPass = this.regForm.get('password').value;
this.backend.storeSecureAppData((status, data) => {
if (status) {
this.variablesService.appLogin = true;
this.variablesService.startCountdown();
this.ngZone.run(() => {
this.router.navigate(['/']);
});
@ -61,11 +63,20 @@ export class LoginComponent implements OnInit, OnDestroy {
}
}
onSkipCreatePass(): void {
this.variablesService.appPass = '';
this.ngZone.run(() => {
this.variablesService.appLogin = true;
this.router.navigate(['/']);
});
}
onSubmitAuthPass(): void {
if (this.authForm.valid) {
const appPass = this.authForm.get('password').value;
this.backend.getSecureAppData({pass: appPass}, (status, data) => {
if (!data.error_code) {
this.variablesService.appLogin = true;
this.variablesService.startCountdown();
this.variablesService.appPass = appPass;
if (this.variablesService.wallets.length) {

View file

@ -0,0 +1,18 @@
<div class="modal">
<h3 class="title">{{ 'OPEN_WALLET.MODAL.TITLE' | translate }}</h3>
<form class="open-form" (ngSubmit)="openWallet()">
<div class="wallet-path">{{ wallet.name }}</div>
<div class="wallet-path">{{ wallet.path }}</div>
<div class="input-block" *ngIf="!wallet.notFound && !wallet.emptyPass">
<label for="password">{{ 'OPEN_WALLET.MODAL.LABEL' | translate }}</label>
<input type="password" id="password" name="password" [(ngModel)]="wallet.pass" (contextmenu)="variablesService.onContextMenuPasteSelect($event)"/>
</div>
<div class="error-block" *ngIf="wallet.notFound">
{{ 'OPEN_WALLET.MODAL.NOT_FOUND' | translate }}
</div>
<div class="wrap-button">
<button type="submit" class="blue-button" [disabled]="wallet.notFound">{{ 'OPEN_WALLET.MODAL.OPEN' | translate }}</button>
<button type="button" class="blue-button" (click)="skipWallet()">{{ 'OPEN_WALLET.MODAL.SKIP' | translate }}</button>
</div>
</form>
</div>

View file

@ -0,0 +1,45 @@
:host {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
display: flex;
align-items: center;
justify-content: center;
background: rgba(255, 255, 255, 0.25);
}
.modal {
display: flex;
flex-direction: column;
background-position: center;
background-size: 200%;
padding: 2rem;
width: 34rem;
.title {
font-size: 1.8rem;
text-align: center;
}
.open-form {
.wallet-path {
font-size: 1.3rem;
margin: 5rem 0 2rem;
}
.wrap-button {
display: flex;
align-items: center;
justify-content: space-between;
margin: 2rem -2rem 0;
button {
flex: 1 0 0;
margin: 0 2rem ;
}
}
}
}

View file

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { OpenWalletModalComponent } from './open-wallet-modal.component';
describe('OpenWalletModalComponent', () => {
let component: OpenWalletModalComponent;
let fixture: ComponentFixture<OpenWalletModalComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ OpenWalletModalComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(OpenWalletModalComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -0,0 +1,121 @@
import {Component, OnInit, Input, NgZone} from '@angular/core';
import {VariablesService} from '../_helpers/services/variables.service';
import {Wallet} from '../_helpers/models/wallet.model';
import {BackendService} from '../_helpers/services/backend.service';
import {TranslateService} from '@ngx-translate/core';
import {ModalService} from '../_helpers/services/modal.service';
@Component({
selector: 'app-open-wallet-modal',
templateUrl: './open-wallet-modal.component.html',
styleUrls: ['./open-wallet-modal.component.scss']
})
export class OpenWalletModalComponent implements OnInit {
@Input() wallets;
wallet = {
name: '',
path: '',
pass: '',
notFound: false,
emptyPass: false
};
constructor(
public variablesService: VariablesService,
private backend: BackendService,
private translate: TranslateService,
private modalService: ModalService,
private ngZone: NgZone,
) {
}
ngOnInit() {
if (this.wallets.length) {
this.wallet = this.wallets[0];
this.wallet.pass = '';
this.backend.openWallet(this.wallet.path, '', true, (status, data, error) => {
if (error === 'FILE_NOT_FOUND') {
this.wallet.notFound = true;
}
if (status) {
this.wallet.pass = '';
this.wallet.emptyPass = true;
this.backend.closeWallet(data.wallet_id);
this.openWallet();
}
});
}
}
openWallet() {
if (this.wallets.length === 0) {
return;
}
this.backend.openWallet(this.wallet.path, this.wallet.pass, false, (open_status, open_data, open_error) => {
if (open_error && open_error === 'FILE_NOT_FOUND') {
let error_translate = this.translate.instant('OPEN_WALLET.FILE_NOT_FOUND1');
error_translate += ':<br>' + this.wallet.path;
error_translate += this.translate.instant('OPEN_WALLET.FILE_NOT_FOUND2');
this.modalService.prepareModal('error', error_translate);
} else {
if (open_status || open_error === 'FILE_RESTORED') {
let exists = false;
this.variablesService.wallets.forEach((wallet) => {
if (wallet.address === open_data['wi'].address) {
exists = true;
}
});
if (exists) {
this.modalService.prepareModal('error', 'OPEN_WALLET.WITH_ADDRESS_ALREADY_OPEN');
this.backend.closeWallet(open_data.wallet_id);
} else {
const new_wallet = new Wallet(
open_data.wallet_id,
this.wallet.name,
this.wallet.pass,
open_data['wi'].path,
open_data['wi'].address,
open_data['wi'].balance,
open_data['wi'].unlocked_balance,
open_data['wi'].mined_total,
open_data['wi'].tracking_hey
);
new_wallet.alias = this.backend.getWalletAlias(new_wallet.address);
if (open_data.recent_history && open_data.recent_history.history) {
new_wallet.prepareHistory(open_data.recent_history.history);
}
this.backend.getContracts(open_data.wallet_id, (contracts_status, contracts_data) => {
if (contracts_status && contracts_data.hasOwnProperty('contracts')) {
this.ngZone.run(() => {
new_wallet.prepareContractsAfterOpen(
contracts_data.contracts,
this.variablesService.exp_med_ts,
this.variablesService.height_app,
this.variablesService.settings.viewedContracts,
this.variablesService.settings.notViewedContracts
);
});
}
});
this.variablesService.wallets.push(new_wallet);
this.backend.runWallet(open_data.wallet_id);
this.skipWallet();
}
}
}
});
}
skipWallet() {
if (this.wallets.length) {
this.wallets.splice(0, 1);
this.ngOnInit();
}
}
}

View file

@ -110,9 +110,9 @@ export class OpenWalletComponent implements OnInit, OnDestroy {
this.variablesService.wallets.push(new_wallet);
this.backend.runWallet(open_data.wallet_id, (run_status, run_data) => {
if (run_status) {
this.backend.storeSecureAppData((status, data) => {
console.log('Store App Data', status, data);
});
if (this.variablesService.appPass) {
this.backend.storeSecureAppData();
}
this.ngZone.run(() => {
this.router.navigate(['/wallet/' + open_data.wallet_id]);
});

View file

@ -1,5 +1,5 @@
import {Component, NgZone, OnDestroy, OnInit} from '@angular/core';
import {Location} from "@angular/common";
import {Location} from '@angular/common';
import {BackendService} from '../_helpers/services/backend.service';
import {ActivatedRoute, Router} from '@angular/router';
import {VariablesService} from '../_helpers/services/variables.service';
@ -52,9 +52,9 @@ export class SeedPhraseComponent implements OnInit, OnDestroy {
this.backend.runWallet(this.wallet_id, (run_status, run_data) => {
if (run_status) {
this.variablesService.wallets.push(this.variablesService.opening_wallet);
this.backend.storeSecureAppData((status, data) => {
console.log('Store App Data', status, data);
});
if (this.variablesService.appPass) {
this.backend.storeSecureAppData();
}
this.ngZone.run(() => {
this.router.navigate(['/wallet/' + this.wallet_id]);
});

View file

@ -54,14 +54,9 @@
<span class="master-password-title">{{ 'SETTINGS.MASTER_PASSWORD.TITLE' | translate }}</span>
<div class="input-block">
<div class="input-block" *ngIf="variablesService.appPass">
<label for="old-password">{{ 'SETTINGS.MASTER_PASSWORD.OLD' | translate }}</label>
<input type="password" id="old-password" formControlName="password" (contextmenu)="variablesService.onContextMenuPasteSelect($event)"/>
<div class="error-block" *ngIf="changeForm.controls['password'].invalid && (changeForm.controls['password'].dirty || changeForm.controls['password'].touched)">
<div *ngIf="changeForm.controls['password'].errors['required']">
{{ 'SETTINGS.FORM_ERRORS.PASS_REQUIRED' | translate }}
</div>
</div>
<div class="error-block" *ngIf="changeForm.invalid && changeForm.controls['password'].valid && (changeForm.controls['password'].dirty || changeForm.controls['password'].touched) && changeForm.errors && changeForm.errors.pass_mismatch">
{{ 'SETTINGS.FORM_ERRORS.PASS_NOT_MATCH' | translate }}
</div>
@ -70,21 +65,11 @@
<div class="input-block">
<label for="new-password">{{ 'SETTINGS.MASTER_PASSWORD.NEW' | translate }}</label>
<input type="password" id="new-password" formControlName="new_password" (contextmenu)="variablesService.onContextMenuPasteSelect($event)"/>
<div class="error-block" *ngIf="changeForm.controls['new_password'].invalid && (changeForm.controls['new_password'].dirty || changeForm.controls['new_password'].touched)">
<div *ngIf="changeForm.controls['new_password'].errors['required']">
{{ 'SETTINGS.FORM_ERRORS.PASS_REQUIRED' | translate }}
</div>
</div>
</div>
<div class="input-block">
<label for="confirm-password">{{ 'SETTINGS.MASTER_PASSWORD.CONFIRM' | translate }}</label>
<input type="password" id="confirm-password" formControlName="new_confirmation" (contextmenu)="variablesService.onContextMenuPasteSelect($event)"/>
<div class="error-block" *ngIf="changeForm.controls['new_confirmation'].invalid && (changeForm.controls['new_confirmation'].dirty || changeForm.controls['new_confirmation'].touched)">
<div *ngIf="changeForm.controls['new_confirmation'].errors['required']">
{{ 'SETTINGS.FORM_ERRORS.PASS_REQUIRED' | translate }}
</div>
</div>
<div class="error-block" *ngIf="changeForm.invalid && (changeForm.controls['new_confirmation'].dirty || changeForm.controls['new_confirmation'].touched) && changeForm.errors && changeForm.errors.confirm_mismatch">
{{ 'SETTINGS.FORM_ERRORS.CONFIRM_NOT_MATCH' | translate }}
</div>

View file

@ -1,7 +1,7 @@
import {Component, NgZone, OnInit, Renderer2} from '@angular/core';
import {VariablesService} from '../_helpers/services/variables.service';
import {BackendService} from '../_helpers/services/backend.service';
import {FormControl, FormGroup, Validators} from '@angular/forms';
import {FormControl, FormGroup} from '@angular/forms';
import {Location} from '@angular/common';
@Component({
@ -63,13 +63,16 @@ export class SettingsComponent implements OnInit {
this.theme = this.variablesService.settings.theme;
this.scale = this.variablesService.settings.scale;
this.changeForm = new FormGroup({
password: new FormControl('', Validators.required),
new_password: new FormControl('', Validators.required),
new_confirmation: new FormControl('', Validators.required)
password: new FormControl(''),
new_password: new FormControl(''),
new_confirmation: new FormControl('')
}, [(g: FormGroup) => {
return g.get('new_password').value === g.get('new_confirmation').value ? null : {'confirm_mismatch': true};
}, (g: FormGroup) => {
return g.get('password').value === this.variablesService.appPass ? null : {'pass_mismatch': true};
if (this.variablesService.appPass) {
return g.get('password').value === this.variablesService.appPass ? null : {'pass_mismatch': true};
}
return null;
}]);
}
@ -99,18 +102,19 @@ export class SettingsComponent implements OnInit {
onSubmitChangePass() {
if (this.changeForm.valid) {
this.variablesService.appPass = this.changeForm.get('new_password').value;
this.backend.storeSecureAppData((status, data) => {
if (status) {
this.changeForm.reset();
} else {
console.log(data);
}
});
if (this.variablesService.appPass) {
this.backend.storeSecureAppData();
} else {
this.backend.dropSecureAppData();
}
this.changeForm.reset();
}
}
onLockChange() {
this.variablesService.restartCountdown();
if (this.variablesService.appLogin) {
this.variablesService.restartCountdown();
}
this.backend.storeAppData();
}

View file

@ -49,6 +49,7 @@ export class SidebarComponent implements OnInit, OnDestroy {
logOut() {
this.variablesService.stopCountdown();
this.variablesService.appLogin = false;
this.variablesService.appPass = '';
this.ngZone.run(() => {
this.router.navigate(['/login'], {queryParams: {type: 'auth'}});

View file

@ -72,16 +72,17 @@ export class WalletDetailsComponent implements OnInit, OnDestroy {
this.variablesService.wallets.splice(i, 1);
}
}
this.backend.storeSecureAppData(() => {
this.ngZone.run(() => {
if (this.variablesService.wallets.length) {
this.variablesService.currentWallet = this.variablesService.wallets[0];
this.router.navigate(['/wallet/' + this.variablesService.currentWallet.wallet_id]);
} else {
this.router.navigate(['/']);
}
});
this.ngZone.run(() => {
if (this.variablesService.wallets.length) {
this.variablesService.currentWallet = this.variablesService.wallets[0];
this.router.navigate(['/wallet/' + this.variablesService.currentWallet.wallet_id]);
} else {
this.router.navigate(['/']);
}
});
if (this.variablesService.appPass) {
this.backend.storeSecureAppData();
}
});
}

View file

@ -4,6 +4,7 @@
"SETUP_CONFIRM_PASS": "Confirm the password",
"MASTER_PASS": "Master password",
"BUTTON_NEXT": "Next",
"BUTTON_SKIP": "Skip",
"INCORRECT_PASSWORD": "Invalid password",
"FORM_ERRORS": {
"PASS_REQUIRED": "Password is required.",
@ -83,6 +84,13 @@
"NAME_REQUIRED": "Name is required.",
"NAME_DUPLICATE": "Name is duplicate.",
"MAX_LENGTH": "Maximum name length reached."
},
"MODAL": {
"TITLE": "Type wallet password",
"LABEL": "Password to this wallet",
"OPEN": "Open wallet",
"SKIP": "Skip",
"NOT_FOUND": "Not found"
}
},
"RESTORE_WALLET": {

View file

@ -780,3 +780,14 @@ app-progress-container {
}
}
}
app-open-wallet-modal {
.modal {
@include themify($themes) {
background: themed(modalBackground);
color: themed(mainTextColor);
}
}
}