-
+
- {{import.error|translate}}
+ {{error|translate}}
-
diff --git a/src/js/controllers/backup.js b/src/js/controllers/backup.js
index 320144800..7cbeaf093 100644
--- a/src/js/controllers/backup.js
+++ b/src/js/controllers/backup.js
@@ -23,8 +23,8 @@ angular.module('copayApp.controllers').controller('backupController',
handleEncryptedWallet(fc, function(err) {
if (err) {
- $scope.error = bwsError.msg(err, gettext('Could not decrypt'));
$log.warn('Error decrypting credentials:', $scope.error);
+ go.path(prevState);
return;
}
$scope.credentialsEncrypted = false;
@@ -69,10 +69,13 @@ angular.module('copayApp.controllers').controller('backupController',
};
$scope.goBack = function() {
- walletService.lock(fc);
go.path(prevState || 'walletHome');
};
+ $scope.$on('$destroy', function() {
+ walletService.lock(fc);
+ });
+
$scope.goToStep = function(n) {
if (n == 1)
$scope.initFlow();
diff --git a/src/js/controllers/export.js b/src/js/controllers/export.js
index cea7af04a..e34866f46 100644
--- a/src/js/controllers/export.js
+++ b/src/js/controllers/export.js
@@ -1,39 +1,111 @@
'use strict';
angular.module('copayApp.controllers').controller('exportController',
- function($scope, $timeout, $log, backupService, fingerprintService, configService, storageService, profileService, platformInfo, notification, go, gettext, gettextCatalog) {
+ function($rootScope, $scope, $timeout, $log, lodash, backupService, walletService, fingerprintService, configService, storageService, profileService, platformInfo, notification, go, gettext, gettextCatalog) {
+ var prevState;
var isWP = platformInfo.isWP;
var isAndroid = platformInfo.isAndroid;
- var isCordova = platformInfo.isCordova;
-
- $scope.error = null;
- $scope.success = null;
var fc = profileService.focusedClient;
$scope.isEncrypted = fc.isPrivKeyEncrypted();
- $scope.touchidSuccess = null;
- $scope.touchidEnabled = null;
+ $scope.isCordova = platformInfo.isCordova;
+ $scope.isSafari = platformInfo.isSafari;
$scope.error = null;
$scope.init = function(state) {
- if (!isCordova) return;
-
- var config = configService.getSync();
- var touchidAvailable = fingerprintService.isAvailable();
- var touchidEnabled = $scope.touchidEnabled = config.touchIdFor ? config.touchIdFor[fc.credentials.walletId] : null;
-
- if (!touchidAvailable || !touchidEnabled) return;
+ $scope.supported = true;
+ $scope.exportQR = false;
+ $scope.noSignEnabled = false;
+ $scope.showAdvanced = false;
+ prevState = state || 'walletHome';
fingerprintService.check(fc, function(err) {
- if (err)
- go.path(state || 'walletHome');
+ if (err) {
+ go.path(prevState);
+ return;
+ }
- $scope.touchidSuccess = true;
- $timeout(function() {
- $scope.$apply();
- }, 10);
+ handleEncryptedWallet(fc, function(err) {
+ if (err) {
+ go.path(prevState);
+ return;
+ }
+
+ $scope.exportWalletInfo = encodeWalletInfo();
+ $timeout(function() {
+ $scope.$apply();
+ }, 1);
+ });
});
};
+ /*
+ EXPORT WITHOUT PRIVATE KEY - PENDING
+
+ $scope.noSignEnabledChange = function() {
+ $scope.exportWalletInfo = encodeWalletInfo();
+ $timeout(function() {
+ $scope.$apply();
+ }, 1);
+ };
+ */
+
+ $scope.$on('$destroy', function() {
+ walletService.lock(fc);
+ });
+
+ function handleEncryptedWallet(client, cb) {
+ if (!walletService.isEncrypted(client)) {
+ $scope.credentialsEncrypted = false;
+ return cb();
+ }
+
+ $rootScope.$emit('Local/NeedsPassword', false, function(err, password) {
+ if (err) return cb(err);
+ return cb(walletService.unlock(client, password));
+ });
+ };
+
+ function encodeWalletInfo() {
+ var c = fc.credentials;
+ var derivationPath = fc.credentials.getBaseAddressDerivationPath();
+ var encodingType = {
+ mnemonic: 1,
+ xpriv: 2,
+ xpub: 3
+ };
+ var info;
+
+ $scope.supported = (c.derivationStrategy == 'BIP44' && c.canSign());
+
+ if ($scope.supported) {
+ if (c.mnemonic) {
+ info = {
+ type: encodingType.mnemonic,
+ data: c.mnemonic,
+ }
+ } else {
+ info = {
+ type: encodingType.xpriv,
+ data: c.xPrivKey
+ }
+ }
+ } else {
+ /*
+ EXPORT WITHOUT PRIVATE KEY - PENDING
+
+ info = {
+ type: encodingType.xpub,
+ data: c.xPubKey
+ }
+ */
+
+ return null;
+ }
+
+ var code = info.type + '|' + info.data + '|' + c.network.toLowerCase() + '|' + derivationPath + '|' + (c.mnemonicHasPassphrase);
+ return code;
+ };
+
$scope.downloadWalletBackup = function() {
$scope.getAddressbook(function(err, localAddressBook) {
if (err) {
diff --git a/src/js/controllers/import.js b/src/js/controllers/import.js
index af5a44cd9..a7d147c3e 100644
--- a/src/js/controllers/import.js
+++ b/src/js/controllers/import.js
@@ -1,58 +1,89 @@
'use strict';
angular.module('copayApp.controllers').controller('importController',
- function($scope, $rootScope, $timeout, $log, profileService, configService, notification, go, sjcl, gettext, lodash, ledger, trezor, derivationPathHelper, platformInfo, bwsError, bwcService, ongoingProcess) {
+ function($scope, $rootScope, $timeout, $log, profileService, configService, notification, go, sjcl, gettext, ledger, trezor, derivationPathHelper, platformInfo, bwcService, ongoingProcess) {
var isChromeApp = platformInfo.isChromeApp;
var isDevel = platformInfo.isDevel;
-
- var self = this;
var reader = new FileReader();
var defaults = configService.getDefaults();
var errors = bwcService.getErrors();
+ $scope.dataFromQR = null;
$scope.bwsurl = defaults.bws.url;
$scope.derivationPath = derivationPathHelper.default;
$scope.account = 1;
- self.importErr = false;
+ $scope.importErr = false;
var updateSeedSourceSelect = function() {
- self.seedOptions = [];
+ $scope.seedOptions = [];
if (isChromeApp) {
- self.seedOptions.push({
+ $scope.seedOptions.push({
id: 'ledger',
label: 'Ledger Hardware Wallet',
});
}
if (isChromeApp || isDevel) {
- self.seedOptions.push({
+ $scope.seedOptions.push({
id: 'trezor',
label: 'Trezor Hardware Wallet',
});
- $scope.seedSource = self.seedOptions[0];
+ $scope.seedSource = $scope.seedOptions[0];
}
};
- this.setType = function(type) {
+ $scope.processWalletInfo = function(code) {
+ $scope.dataFromQR = null;
+ $scope.importErr = false;
+ $scope.error = null;
+ var parsedCode = code.split('|');
+
+ if (parsedCode.length != 5) {
+ $scope.error = gettext('Cannot read the code properly. Missing parameters');
+ return;
+ }
+
+ var 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)
+ $scope.error = gettext('Password required. Make sure to enter your password in advanced options');
+
+ $scope.derivationPath = info.derivationPath;
+ $scope.testnetEnabled = info.network == 'testnet' ? true : false;
+
+ $timeout(function() {
+ $scope.words = null;
+ $scope.dataFromQR = info.data;
+ $rootScope.$apply();
+ }, 1);
+ };
+
+ $scope.setType = function(type) {
$scope.type = type;
- this.error = null;
+ $scope.error = null;
$timeout(function() {
$rootScope.$apply();
- });
+ }, 1);
};
var _importBlob = function(str, opts) {
var str2, err;
try {
- str2 = sjcl.decrypt(self.password, str);
+ str2 = sjcl.decrypt($scope.password, str);
} catch (e) {
err = gettext('Could not decrypt file, check your password');
$log.warn(e);
};
if (err) {
- self.error = err;
+ $scope.error = err;
$timeout(function() {
$rootScope.$apply();
});
@@ -67,7 +98,7 @@ angular.module('copayApp.controllers').controller('importController',
profileService.importWallet(str2, opts, function(err, walletId) {
ongoingProcess.set('importingWallet', false);
if (err) {
- self.error = err;
+ $scope.error = err;
} else {
$rootScope.$emit('Local/WalletImported', walletId);
notification.success(gettext('Success'), gettext('Your wallet has been imported correctly'));
@@ -84,9 +115,9 @@ angular.module('copayApp.controllers').controller('importController',
ongoingProcess.set('importingWallet', false);
if (err) {
if (err instanceof errors.NOT_AUTHORIZED) {
- self.importErr = true;
+ $scope.importErr = true;
} else {
- self.error = err;
+ $scope.error = err;
}
return $timeout(function() {
$scope.$apply();
@@ -100,6 +131,28 @@ angular.module('copayApp.controllers').controller('importController',
}, 100);
};
+ /*
+ IMPORT FROM PUBLIC KEY - PENDING
+
+ 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();
+ });
+ }
+ $rootScope.$emit('Local/WalletImported', walletId);
+ notification.success(gettext('Success'), gettext('Your wallet has been imported correctly'));
+ go.walletHome();
+ });
+ }, 100);
+ };
+ */
+
var _importMnemonic = function(words, opts) {
ongoingProcess.set('importingWallet', true);
@@ -109,9 +162,9 @@ angular.module('copayApp.controllers').controller('importController',
if (err) {
if (err instanceof errors.NOT_AUTHORIZED) {
- self.importErr = true;
+ $scope.importErr = true;
} else {
- self.error = err;
+ $scope.error = err;
}
return $timeout(function() {
$scope.$apply();
@@ -130,7 +183,7 @@ angular.module('copayApp.controllers').controller('importController',
$scope.derivationPath = derivationPathHelper.defaultTestnet;
else
$scope.derivationPath = derivationPathHelper.default;
- }
+ };
$scope.getFile = function() {
// If we use onloadend, we need to check the readyState.
@@ -143,9 +196,9 @@ angular.module('copayApp.controllers').controller('importController',
}
};
- this.importBlob = function(form) {
+ $scope.importBlob = function(form) {
if (form.$invalid) {
- this.error = gettext('There is an error in the form');
+ $scope.error = gettext('There is an error in the form');
$timeout(function() {
$scope.$apply();
});
@@ -157,7 +210,7 @@ angular.module('copayApp.controllers').controller('importController',
var password = form.password.$modelValue;
if (!backupFile && !backupText) {
- this.error = gettext('Please, select your backup file');
+ $scope.error = gettext('Please, select your backup file');
$timeout(function() {
$scope.$apply();
});
@@ -174,9 +227,9 @@ angular.module('copayApp.controllers').controller('importController',
}
};
- this.importMnemonic = function(form) {
+ $scope.importMnemonic = function(form) {
if (form.$invalid) {
- this.error = gettext('There is an error in the form');
+ $scope.error = gettext('There is an error in the form');
$timeout(function() {
$scope.$apply();
});
@@ -187,32 +240,33 @@ angular.module('copayApp.controllers').controller('importController',
if ($scope.bwsurl)
opts.bwsurl = $scope.bwsurl;
-
var pathData = derivationPathHelper.parse($scope.derivationPath);
if (!pathData) {
- this.error = gettext('Invalid derivation path');
+ $scope.error = gettext('Invalid derivation path');
return;
}
opts.account = pathData.account;
opts.networkName = pathData.networkName;
opts.derivationStrategy = pathData.derivationStrategy;
- var words = form.words.$modelValue;
- this.error = null;
+ var words = form.words.$modelValue || $scope.dataFromQR;
+ $scope.error = null;
if (!words) {
- this.error = gettext('Please enter the recovery phrase');
+ $scope.error = gettext('Please enter the recovery phrase');
} else if (words.indexOf('xprv') == 0 || words.indexOf('tprv') == 0) {
return _importExtendedPrivateKey(words, opts);
+ } else if (words.indexOf('xpub') == 0 || words.indexOf('tpuv') == 0) {
+ return _importExtendedPublicKey(words, opts);
} else {
var wordList = words.split(/[\u3000\s]+/);
if ((wordList.length % 3) != 0) {
- this.error = gettext('Wrong number of recovery words:') + wordList.length;
+ $scope.error = gettext('Wrong number of recovery words:') + wordList.length;
}
}
- if (this.error) {
+ if ($scope.error) {
$timeout(function() {
$scope.$apply();
});
@@ -225,12 +279,12 @@ angular.module('copayApp.controllers').controller('importController',
_importMnemonic(words, opts);
};
- this.importTrezor = function(account, isMultisig) {
- var self = this;
+ $scope.importTrezor = function(account, isMultisig) {
+ var $scope = $scope;
trezor.getInfoForNewWallet(isMultisig, account, function(err, lopts) {
ongoingProcess.clear();
if (err) {
- self.error = err;
+ $scope.error = err;
$scope.$apply();
return;
}
@@ -243,7 +297,7 @@ angular.module('copayApp.controllers').controller('importController',
profileService.importExtendedPublicKey(lopts, function(err, walletId) {
ongoingProcess.set('importingWallet', false);
if (err) {
- self.error = err;
+ $scope.error = err;
return $timeout(function() {
$scope.$apply();
});
@@ -255,56 +309,56 @@ angular.module('copayApp.controllers').controller('importController',
}, 100);
};
- this.importHW = function(form) {
+ $scope.importHW = function(form) {
if (form.$invalid || $scope.account < 0) {
- this.error = gettext('There is an error in the form');
+ $scope.error = gettext('There is an error in the form');
$timeout(function() {
$scope.$apply();
});
return;
}
- this.error = '';
- this.importErr = false;
+ $scope.error = '';
+ $scope.importErr = false;
var account = +$scope.account;
- if (self.seedSourceId == 'trezor') {
+ if ($scope.seedSourceId == 'trezor') {
if (account < 1) {
- this.error = gettext('Invalid account number');
+ $scope.error = gettext('Invalid account number');
return;
}
account = account - 1;
}
- switch (self.seedSourceId) {
+ switch ($scope.seedSourceId) {
case ('ledger'):
ongoingProcess.set('connectingledger', true);
- self.importLedger(account);
+ $scope.importLedger(account);
break;
case ('trezor'):
ongoingProcess.set('connectingtrezor', true);
- self.importTrezor(account, $scope.isMultisig);
+ $scope.importTrezor(account, $scope.isMultisig);
break;
default:
throw ('Error: bad source id');
};
};
- this.setSeedSource = function() {
+ $scope.setSeedSource = function() {
if (!$scope.seedSource) return;
- self.seedSourceId = $scope.seedSource.id;
+ $scope.seedSourceId = $scope.seedSource.id;
$timeout(function() {
$rootScope.$apply();
});
};
- this.importLedger = function(account) {
- var self = this;
+ $scope.importLedger = function(account) {
+ var $scope = $scope;
ledger.getInfoForNewWallet(true, account, function(err, lopts) {
ongoingProcess.clear();
if (err) {
- self.error = err;
+ $scope.error = err;
$scope.$apply();
return;
}
@@ -317,7 +371,7 @@ angular.module('copayApp.controllers').controller('importController',
profileService.importExtendedPublicKey(lopts, function(err, walletId) {
ongoingProcess.set('importingWallet', false);
if (err) {
- self.error = err;
+ $scope.error = err;
return $timeout(function() {
$scope.$apply();
});
@@ -330,5 +384,5 @@ angular.module('copayApp.controllers').controller('importController',
};
updateSeedSourceSelect();
- self.setSeedSource('new');
+ $scope.setSeedSource('new');
});
diff --git a/src/js/services/onGoingProcess.js b/src/js/services/onGoingProcess.js
index 9a9ed7547..836061f5f 100644
--- a/src/js/services/onGoingProcess.js
+++ b/src/js/services/onGoingProcess.js
@@ -28,6 +28,7 @@ angular.module('copayApp.services').factory('ongoingProcess', function($log, $ti
'importingWallet': gettext('Importing Wallet...'),
'sweepingWallet': gettext('Sweeping Wallet...'),
'deletingWallet': gettext('Deleting Wallet...'),
+ 'extractingWalletInfo': gettext('Extracting Wallet Information...'),
};
root.clear = function() {
diff --git a/src/sass/main.scss b/src/sass/main.scss
index ea0045783..daaeeb4b8 100644
--- a/src/sass/main.scss
+++ b/src/sass/main.scss
@@ -29,6 +29,16 @@ body {
right: 0;
}
+.qr-scanner-input-import {
+ position: absolute;
+ top: -5px;
+ right: 0;
+}
+
+.icon-close-import {
+ padding: 0px 40px 5px 10px;
+}
+
h1, h2, h3, h4, h5, h6 {
color: #2C3E50;
}
@@ -606,6 +616,14 @@ ul.manage li {
margin-right: 10px;
}
+.m40r {
+ margin-right: 40px;
+}
+
+.m25r {
+ margin-right: 25px;
+}
+
.m10l {
margin-left: 10px;
}
@@ -695,6 +713,10 @@ ul.manage li {
padding-left: 25px;
}
+.p15l {
+ padding-left: 15px;
+}
+
.p15 {
padding: 15px;
}
@@ -869,6 +891,12 @@ ul.manage li {
background-color: #1ABC9C;
}
+.lock-fromQR {
+ position: absolute;
+ width: 100%;
+ margin-top: 20px;
+}
+
.tx-proposal i {
padding: .1rem .3rem;
background-color: #A5B2BF;