diff --git a/src/pages/add/import-wallet/import-wallet.html b/src/pages/add/import-wallet/import-wallet.html
index 435984fa4..171d3684b 100644
--- a/src/pages/add/import-wallet/import-wallet.html
+++ b/src/pages/add/import-wallet/import-wallet.html
@@ -23,7 +23,7 @@
Choose a backup file from your computer
-
+
@@ -34,7 +34,7 @@
-
+
Show advanced options
Hide advanced options
@@ -64,4 +64,4 @@
-
+
\ No newline at end of file
diff --git a/src/pages/add/import-wallet/import-wallet.ts b/src/pages/add/import-wallet/import-wallet.ts
index ec045908a..80e22ea2e 100644
--- a/src/pages/add/import-wallet/import-wallet.ts
+++ b/src/pages/add/import-wallet/import-wallet.ts
@@ -1,40 +1,69 @@
import { Component, OnInit } from '@angular/core';
import { NavController, NavParams } from 'ionic-angular';
import { Validators, FormBuilder, FormGroup } from '@angular/forms';
+import { Logger } from '@nsalaun/ng-logger';
+// Pages
+import { HomePage } from '../../../pages/home/home';
+
+// Providers
import { BwcProvider } from '../../../providers/bwc/bwc';
-import { WalletProvider } from '../../../providers/wallet/wallet';
-import { DerivationPathHelperProvider } from '../../../providers/derivation-path-helper/derivation-path-helper';
import { ConfigProvider } from '../../../providers/config/config';
+import { DerivationPathHelperProvider } from '../../../providers/derivation-path-helper/derivation-path-helper';
+import { OnGoingProcessProvider } from '../../../providers/on-going-process/on-going-process';
+import { PlatformProvider } from '../../../providers/platform/platform';
+import { ProfileProvider } from '../../../providers/profile/profile';
+import { PopupProvider } from '../../../providers/popup/popup';
+import { WalletProvider } from '../../../providers/wallet/wallet';
@Component({
selector: 'page-import-wallet',
templateUrl: 'import-wallet.html'
})
export class ImportWalletPage implements OnInit {
- public fromOnboarding: boolean;
- public formData: any;
- public showAdvOpts: boolean;
- public selectedTab: string;
- public seedOptions: any;
private derivationPathByDefault: string;
private derivationPathForTestnet: string;
private importForm: FormGroup;
+ private reader: FileReader;
+ private defaults: any;
+ private config: any;
+ private errors: any;
+ private importErr: boolean;
+
+ public fromOnboarding: boolean;
+ public formData: any;
+ public showAdvOpts: boolean;
+ public selectedTab: string;
+ public enableCash: boolean = false;
+ public isCordova: boolean;
+ public file: File;
constructor(
- public navCtrl: NavController,
+ private navCtrl: NavController,
private navParams: NavParams,
private form: FormBuilder,
- private bwc: BwcProvider,
- private pathHelper: DerivationPathHelperProvider,
+ private bwcProvider: BwcProvider,
+ private derivationPathHelperProvider: DerivationPathHelperProvider,
private walletProvider: WalletProvider,
private configProvider: ConfigProvider,
+ private popupProvider: PopupProvider,
+ private platformProvider: PlatformProvider,
+ private logger: Logger,
+ private onGoingProcessProvider: OnGoingProcessProvider,
+ private profileProvider: ProfileProvider
) {
+ this.reader = new FileReader();
+ this.defaults = configProvider.getDefaults();
+ this.config = configProvider.get();
+ this.errors = bwcProvider.getErrors();
+
+ this.isCordova = this.platformProvider.isCordova;
+ this.importErr = false;
this.fromOnboarding = this.navParams.data.fromOnboarding;
this.selectedTab = 'words';
- this.derivationPathByDefault = this.pathHelper.default;
- this.derivationPathForTestnet = this.pathHelper.defaultTestnet;
+ this.derivationPathByDefault = this.derivationPathHelperProvider.default;
+ this.derivationPathForTestnet = this.derivationPathHelperProvider.defaultTestnet;
this.showAdvOpts = false;
this.formData = {
words: null,
@@ -43,8 +72,14 @@ export class ImportWalletPage implements OnInit {
filePassword: null,
derivationPath: this.derivationPathByDefault,
testnet: false,
- bwsURL: this.configProvider.get()['bws']['url'],
+ bwsURL: this.defaults.bws.url,
+ coin: this.navParams.data.coin ? this.navParams.data.coin : null
};
+
+ if (this.config.cashSupport) this.enableCash = true;
+
+ if (this.navParams.data.code)
+ this.processWalletInfo(this.navParams.data.code);
}
ngOnInit() {
@@ -85,19 +120,259 @@ export class ImportWalletPage implements OnInit {
this.importForm.get('filePassword').updateValueAndValidity();
}
- setDerivationPath() {
- this.formData.derivationPath = this.formData.testnet ? this.derivationPathForTestnet : this.derivationPathByDefault;
- }
-
normalizeMnemonic(words: string) {
if (!words || !words.indexOf) return words;
var isJA = words.indexOf('\u3000') > -1;
var wordList = words.split(/[\u3000\s]+/);
return wordList.join(isJA ? '\u3000' : ' ');
- };
+ }
+
+ private processWalletInfo(code: string): void {
+ if (!code) return;
+
+ this.importErr = false;
+ let parsedCode = code.split('|');
+
+ if (parsedCode.length != 5) {
+ /// Trying to import a malformed wallet export QR code
+ this.popupProvider.ionicAlert('Error', 'Incorrect code format'); //TODO gettextcatalog
+ return;
+ }
+
+ let info = {
+ type: parsedCode[0],
+ data: parsedCode[1],
+ network: parsedCode[2],
+ derivationPath: parsedCode[3],
+ hasPassphrase: parsedCode[4] == 'true' ? true : false
+ };
+
+ if (info.type == '1' && info.hasPassphrase)
+ this.popupProvider.ionicAlert('Error', 'Password required. Make sure to enter your password in advanced options'); //TODO gettextcatalog
+
+ this.formData.derivationPath = info.derivationPath;
+ this.formData.testnetEnabled = info.network == 'testnet' ? true : false;
+ this.formData.words = info.data;
+ }
+
+ public switchTestnetOff(): void {
+ this.formData.testnetEnabled = false;
+ this.setDerivationPath();
+ }
+
+ private setDerivationPath(): void {
+ this.formData.derivationPath = this.formData.testnet ? this.derivationPathForTestnet : this.derivationPathByDefault;
+ }
+
+ private importBlob(str: string, opts: any): void {
+ let str2: string;
+ let err: any = null;
+ try {
+ str2 = this.bwcProvider.getSJCL().decrypt(this.formData.filePassword, str);
+ } catch (e) {
+ err = 'Could not decrypt file, check your password'; //TODO gettextcatalog
+ this.logger.warn(e);
+ };
+
+ if (err) {
+ this.popupProvider.ionicAlert('Error', err); //TODO gettextcatalog
+ return;
+ }
+
+ this.onGoingProcessProvider.set('importingWallet', true);
+ opts.compressed = null;
+ opts.password = null;
+
+ setTimeout(() => {
+ this.profileProvider.importWallet(str2, opts).then((wallet: any) => {
+ this.onGoingProcessProvider.set('importingWallet', false);
+ this.finish(wallet);
+ }).catch((err: any) => {
+ this.onGoingProcessProvider.set('importingWallet', false);
+ this.popupProvider.ionicAlert('Error', err); //TODO gettextcatalog
+ return;
+ });
+ }, 100);
+ }
+
+ private finish(wallet: any): void {
+ this.walletProvider.updateRemotePreferences(wallet).then(() => {
+ this.profileProvider.setBackupFlag(wallet.credentials.walletId);
+ if (this.fromOnboarding) {
+ this.profileProvider.setDisclaimerAccepted().catch((err: any) => {
+ this.logger.error(err);
+ });
+ }
+ this.navCtrl.setRoot(HomePage);
+ this.navCtrl.popToRoot();
+ }).catch((err: any) => {
+ this.logger.warn(err);
+ });
+ }
+
+ private importExtendedPrivateKey(xPrivKey, opts) {
+ this.onGoingProcessProvider.set('importingWallet', true);
+ setTimeout(() => {
+ this.profileProvider.importExtendedPrivateKey(xPrivKey, opts).then((wallet: any) => {
+ this.onGoingProcessProvider.set('importingWallet', false);
+ this.finish(wallet);
+ }).catch((err: any) => {
+ this.onGoingProcessProvider.set('importingWallet', false);
+ if (err instanceof this.errors.NOT_AUTHORIZED) {
+ this.importErr = true;
+ } else {
+ this.popupProvider.ionicAlert('Error', err); // TODO: gettextcatalog
+ }
+ return;
+ });
+ }, 100);
+ }
+
+ /*
+ IMPORT FROM PUBLIC KEY - PENDING TODO from v1
+
+ var _importExtendedPublicKey = function(xPubKey, opts) {
+ ongoingProcess.set('importingWallet', true);
+ $timeout(function() {
+ profileService.importExtendedPublicKey(opts, function(err, walletId) {
+ ongoingProcess.set('importingWallet', false);
+ if (err) {
+ $scope.error = err;
+ return $timeout(function() {
+ $scope.$apply();
+ });
+ }
+
+ profileService.setBackupFlag(walletId);
+ if ($stateParams.fromOnboarding) {
+ profileService.setDisclaimerAccepted(function(err) {
+ if (err) $log.error(err);
+ });
+ }
+
+ $state.go('tabs.home');
+ });
+ }, 100);
+ };
+ */
+
+ private importMnemonic(words: string, opts: any): void {
+ this.onGoingProcessProvider.set('importingWallet', true);
+ setTimeout(() => {
+ this.profileProvider.importMnemonic(words, opts).then((wallet: any) => {
+ this.onGoingProcessProvider.set('importingWallet', false);
+ this.finish(wallet);
+ }).catch((err: any) => {
+ if (err instanceof this.errors.NOT_AUTHORIZED) {
+ this.importErr = true;
+ } else {
+ this.popupProvider.ionicAlert('Error', err); // TODO: gettextcatalog
+ }
+ });
+ }, 100);
+ }
+
import() {
- console.log(this.formData);
+ if (this.selectedTab === 'file') {
+ this.importFromFile();
+ } else {
+ this.importFromMnemonic();
+ }
}
+
+ public importFromFile(): void {
+ if (!this.importForm.valid) {
+ this.popupProvider.ionicAlert('Error', 'There is an error in the form'); // TODO: gettextcatalog
+ return;
+ }
+
+ let backupFile = this.file;
+ let backupText = this.formData.backupText;
+ let password = this.formData.filePassword;
+
+ if (!backupFile && !backupText) {
+ this.popupProvider.ionicAlert('Error', 'Please, select your backup file'); // TODO: gettextcatalog
+ return;
+ }
+
+ if (backupFile) {
+ this.reader.readAsBinaryString(backupFile);
+ } else {
+ let opts: any = {};
+ opts.bwsurl = this.formData.bwsurl;
+ opts.coin = this.formData.coin;
+ this.importBlob(backupText, opts);
+ }
+ }
+
+ public importFromMnemonic(): void {
+ if (!this.importForm.valid) {
+ this.popupProvider.ionicAlert('Error', 'There is an error in the form'); // TODO: gettextcatalog
+ return;
+ }
+
+ let opts: any = {};
+
+ if (this.formData.bwsurl)
+ opts.bwsurl = this.formData.bwsurl;
+
+ let pathData: any = this.derivationPathHelperProvider.parse(this.formData.derivationPath);
+
+ if (!pathData) {
+ this.popupProvider.ionicAlert('Error', 'Invalid derivation path'); // TODO: gettextcatalog
+ return;
+ }
+
+ opts.account = pathData.account;
+ opts.networkName = pathData.networkName;
+ opts.derivationStrategy = pathData.derivationStrategy;
+ opts.coin = this.formData.coin;
+
+ let words: string = this.formData.words || null;
+
+ if (!words) {
+ this.popupProvider.ionicAlert('Error', 'Please enter the recovery phrase');
+ return;
+ } else if (words.indexOf('xprv') == 0 || words.indexOf('tprv') == 0) {
+ return this.importExtendedPrivateKey(words, opts);
+ } else if (words.indexOf('xpub') == 0 || words.indexOf('tpuv') == 0) {
+ //return this.importExtendedPublicKey(words, opts); TODO
+ return this.logger.warn("TODO: this.importExtendedPublicKey(words, opts)");
+ } else {
+ let wordList: Array = words.split(/[\u3000\s]+/);
+
+ if ((wordList.length % 3) != 0) {
+ this.popupProvider.ionicAlert('Error', 'Wrong number of recovery words: ' + wordList.length);
+ return;
+ }
+ }
+
+ opts.passphrase = this.formData.passphrase || null;
+ this.importMnemonic(words, opts);
+ }
+
+ public toggleShowAdvOpts(): void {
+ this.showAdvOpts = !this.showAdvOpts;
+ }
+
+ public fileChangeEvent($event: any) {
+ this.file = $event.target ? $event.target.files[0] : $event.srcElement.files[0];
+ this.formData.file = $event.target.value;
+ this.getFile();
+ }
+
+ private getFile() {
+ // If we use onloadend, we need to check the readyState.
+ this.reader.onloadend = (evt: any) => {
+ if (evt.target.readyState == 2) { // DONE == 2
+ let opts: any = {};
+ opts.bwsurl = this.formData.bwsurl;
+ opts.coin = this.formData.coin;
+ this.importBlob(evt.target.result, opts);
+ }
+ }
+ }
+
}
diff --git a/src/providers/on-going-process/on-going-process.ts b/src/providers/on-going-process/on-going-process.ts
index 839fba31b..d5d4facc7 100644
--- a/src/providers/on-going-process/on-going-process.ts
+++ b/src/providers/on-going-process/on-going-process.ts
@@ -17,7 +17,6 @@ export class OnGoingProcessProvider {
content: processName
});
this.loading.present();
-
}
else {
this.loading.dismiss();
diff --git a/src/providers/wallet/wallet.ts b/src/providers/wallet/wallet.ts
index 57494b7b0..f8d2b1691 100644
--- a/src/providers/wallet/wallet.ts
+++ b/src/providers/wallet/wallet.ts
@@ -416,7 +416,7 @@ export class WalletProvider {
if (lodash.isEmpty(txs)) {
return resolve(localTxs);
};
-
+
try {
localTxs = JSON.parse(txs);
} catch (ex) {
@@ -709,9 +709,9 @@ export class WalletProvider {
});
}
- public updateRemotePreferences(clients: any, prefs: any): Promise {
+ public updateRemotePreferences(clients: any, prefs?: any): Promise {
return new Promise((resolve, reject) => {
- prefs = prefs || {};
+ prefs = prefs ? prefs : {};
if (!lodash.isArray(clients))
clients = [clients];
@@ -723,13 +723,16 @@ export class WalletProvider {
this.logger.debug('Saving remote preferences', wallet.credentials.walletName, prefs);
wallet.savePreferences(prefs, (err: any) => {
-
if (err) {
this.popupProvider.ionicAlert(this.bwcErrorProvider.msg(err, 'Could not save preferences on the server')); //TODO Gettextcatalog
return reject(err);
}
- updateRemotePreferencesFor(clients, prefs);
+ updateRemotePreferencesFor(clients, prefs).then(() => {
+ return resolve();
+ }).catch((err: any) => {
+ return reject(err);
+ });
});
});
};
@@ -740,7 +743,7 @@ export class WalletProvider {
//prefs.email (may come from arguments)
prefs.email = config.emailNotifications.email;
- prefs.language = "English" // This line was hardcoded - TODO: prefs.language = uxLanguage.getCurrentLanguage();
+ prefs.language = "en" // This line was hardcoded - TODO: prefs.language = uxLanguage.getCurrentLanguage();
// prefs.unit = walletSettings.unitCode; // TODO: remove, not used
updateRemotePreferencesFor(lodash.clone(clients), prefs).then(() => {