From 81a49586fb251e206b71e4ac31b485a0e0d88af5 Mon Sep 17 00:00:00 2001 From: Javier Date: Wed, 12 Oct 2016 14:57:02 -0300 Subject: [PATCH 1/6] export decrypted wallet --- src/js/controllers/preferencesDelete.js | 3 ++- src/js/services/walletService.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/js/controllers/preferencesDelete.js b/src/js/controllers/preferencesDelete.js index 60c1a4c2d..9c30fda2e 100644 --- a/src/js/controllers/preferencesDelete.js +++ b/src/js/controllers/preferencesDelete.js @@ -21,7 +21,8 @@ angular.module('copayApp.controllers').controller('preferencesDeleteWalletContro if (err) { popupService.showAlert(gettextCatalog.getString('Error'), err.message || err); } else { - $ionicHistory.removeBackView(); + $ionicHistory.clearHistory(); + $ionicHistory.clearCache(); $state.go('tabs.home'); } }); diff --git a/src/js/services/walletService.js b/src/js/services/walletService.js index 216df83d8..748846d72 100644 --- a/src/js/services/walletService.js +++ b/src/js/services/walletService.js @@ -872,7 +872,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim if (!password) return cb('no password'); if (!wallet.checkPassword(password)) return cb('wrong password'); - + wallet.credentials.decryptPrivateKey(password); return cb(null, password); }); }; From 60f371fe6d2c955bc327a7d5e9d19675d363fdaf Mon Sep 17 00:00:00 2001 From: Javier Date: Wed, 12 Oct 2016 14:58:02 -0300 Subject: [PATCH 2/6] update bwc version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c690d4989..3a2339ec0 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "angular-mocks": "1.4.10", "bezier-easing": "^2.0.3", "bhttp": "^1.2.1", - "bitcore-wallet-client": "4.3.1", + "bitcore-wallet-client": "4.3.2", "bower": "^1.7.9", "chai": "^3.5.0", "cordova-android": "5.1.1", From 696c5bbd1845cbc8457619dfa264a01850e4f636 Mon Sep 17 00:00:00 2001 From: Javier Date: Wed, 12 Oct 2016 18:11:02 -0300 Subject: [PATCH 3/6] fix export wallet --- src/js/controllers/export.js | 99 ++++++++++++++++++++++---------- src/js/services/walletService.js | 40 +++++++------ www/views/export.html | 12 ++-- 3 files changed, 97 insertions(+), 54 deletions(-) diff --git a/src/js/controllers/export.js b/src/js/controllers/export.js index a5a90766b..64fa8ba9d 100644 --- a/src/js/controllers/export.js +++ b/src/js/controllers/export.js @@ -15,6 +15,54 @@ angular.module('copayApp.controllers').controller('exportController', }); }; + function prepareWallet(cb) { + if ($scope.password) return cb($scope.password); + + walletService.prepare(wallet, function(err, password) { + if (err) { + popupService.showAlert(gettextCatalog.getString('Error'), err); + return cb(); + } + $scope.password = password; + + walletService.getEncodedWalletInfo(wallet, $scope.password, function(err, code) { + if (err) { + popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Could not decrypt private key')); + return cb(password); + } + + $scope.file.value = false; + + if (!code) + $scope.formData.supported = false; + else { + $scope.formData.supported = true; + $scope.formData.exportWalletInfo = code; + } + + $timeout(function() { + $scope.$apply(); + }); + return cb(password); + }); + }); + }; + + $scope.generateQrCode = function() { + if ($scope.formData.exportWalletInfo) { + $scope.file.value = false; + $timeout(function() { + $scope.$apply(); + }); + return; + } + + prepareWallet(function(password) { + if (!password) return; + $scope.password = password; + }); + }; + var init = function() { $scope.formData = {}; $scope.isEncrypted = wallet.isPrivKeyEncrypted(); @@ -25,23 +73,6 @@ angular.module('copayApp.controllers').controller('exportController', $scope.wallet = wallet; $scope.canSign = wallet.canSign(); - walletService.getEncodedWalletInfo(wallet, function(err, code) { - if (err || !code) { - $log.warn(err); - return $ionicHistory.goBack(); - } - - if (!code) - $scope.formData.supported = false; - else { - $scope.formData.supported = true; - $scope.formData.exportWalletInfo = code; - } - - $timeout(function() { - $scope.$apply(); - }, 1); - }); }; /* @@ -67,23 +98,28 @@ angular.module('copayApp.controllers').controller('exportController', }; $scope.downloadWalletBackup = function() { - $scope.getAddressbook(function(err, localAddressBook) { - if (err) { - popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Failed to export')); - return; - } - var opts = { - noSign: $scope.formData.noSignEnabled, - addressBook: localAddressBook - }; + prepareWallet(function(password) { + if (!password) return; - backupService.walletDownload($scope.formData.password, opts, function(err) { + $scope.getAddressbook(function(err, localAddressBook) { if (err) { popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Failed to export')); return; } - $ionicHistory.removeBackView(); - $state.go('tabs.home'); + var opts = { + noSign: $scope.formData.noSignEnabled, + addressBook: localAddressBook, + password: password + }; + + backupService.walletDownload($scope.formData.password, opts, function(err) { + if (err) { + popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Failed to export')); + return; + } + $ionicHistory.removeBackView(); + $state.go('tabs.home'); + }); }); }); }; @@ -171,6 +207,11 @@ angular.module('copayApp.controllers').controller('exportController', $scope.$on("$ionicView.beforeEnter", function(event, data) { init(); + $scope.file = { + value: true + }; + $scope.formData.exportWalletInfo = null; + $scope.password = null; }); }); diff --git a/src/js/services/walletService.js b/src/js/services/walletService.js index 748846d72..593698907 100644 --- a/src/js/services/walletService.js +++ b/src/js/services/walletService.js @@ -869,10 +869,9 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim if (!root.isEncrypted(wallet)) return cb(); askPassword(wallet.name, gettext('Enter Spending Password'), function(password) { - if (!password) return cb('no password'); - if (!wallet.checkPassword(password)) return cb('wrong password'); + if (!password) return cb('No password'); + if (!wallet.checkPassword(password)) return cb('Wrong password'); - wallet.credentials.decryptPrivateKey(password); return cb(null, password); }); }; @@ -990,8 +989,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim }); }; - root.getEncodedWalletInfo = function(wallet, cb) { - + root.getEncodedWalletInfo = function(wallet, password, cb) { var derivationPath = wallet.credentials.getBaseAddressDerivationPath(); var encodingType = { mnemonic: 1, @@ -1004,23 +1002,21 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim if (wallet.credentials.derivationStrategy != 'BIP44' || !wallet.canSign()) return null; - root.getKeys(wallet, function(err, keys) { - if (err || !keys) return cb(err); + var keys = root.getKeysWithPassword(wallet, password); - if (keys.mnemonic) { - info = { - type: encodingType.mnemonic, - data: keys.mnemonic, - } - } else { - info = { - type: encodingType.xpriv, - data: keys.xPrivKey - } + if (keys.mnemonic) { + info = { + type: encodingType.mnemonic, + data: keys.mnemonic, } - return cb(null, info.type + '|' + info.data + '|' + wallet.credentials.network.toLowerCase() + '|' + derivationPath + '|' + (wallet.credentials.mnemonicHasPassphrase)); + } else { + info = { + type: encodingType.xpriv, + data: keys.xPrivKey + } + } - }); + return cb(null, info.type + '|' + info.data + '|' + wallet.credentials.network.toLowerCase() + '|' + derivationPath + '|' + (wallet.credentials.mnemonicHasPassphrase)); }; root.setTouchId = function(wallet, enabled, cb) { @@ -1055,6 +1051,12 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim }); }; + root.getKeysWithPassword = function(wallet, password) { + try { + return wallet.getKeys(password); + } catch (e) {} + } + root.getViewStatus = function(wallet, txp) { var status = txp.status; var type; diff --git a/www/views/export.html b/www/views/export.html index b6117ced1..805a84e1c 100644 --- a/www/views/export.html +++ b/www/views/export.html @@ -5,17 +5,17 @@ - -
-
+ +
+
File/Text
-
+
QR Code
-
-
+
+
From 18a25775233e3dd403e4ac86acad800c95774d70 Mon Sep 17 00:00:00 2001 From: Javier Date: Wed, 12 Oct 2016 18:42:30 -0300 Subject: [PATCH 4/6] check extended private key at import --- src/js/services/profileService.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/js/services/profileService.js b/src/js/services/profileService.js index 659f9dd8f..459b3a6e5 100644 --- a/src/js/services/profileService.js +++ b/src/js/services/profileService.js @@ -134,8 +134,7 @@ angular.module('copayApp.services') if (n.type == "NewBlock" && n.data.network == "testnet") { throttledBwsEvent(n, wallet); - } - else newBwsEvent(n, wallet); + } else newBwsEvent(n, wallet); }); wallet.on('walletCompleted', function() { @@ -600,6 +599,7 @@ angular.module('copayApp.services') var walletClient = bwcService.getClient(null, opts); $log.debug('Importing Wallet:', opts); + try { walletClient.import(str, { compressed: opts.compressed, @@ -611,6 +611,11 @@ angular.module('copayApp.services') str = JSON.parse(str); + if (str.xPrivKey) { + delete str.xPrivKeyEncrypted; + delete str.mnemonicEncrypted; + } + var addressBook = str.addressBook || {}; addAndBindWalletClient(walletClient, { From 1c40185b0530a9a79fdb9df937d7369d5f113c93 Mon Sep 17 00:00:00 2001 From: Javier Date: Thu, 13 Oct 2016 10:16:10 -0300 Subject: [PATCH 5/6] complete decrypt pk process --- package.json | 2 +- src/js/controllers/export.js | 71 ++++++++++++++++++-------------- src/js/services/walletService.js | 2 +- 3 files changed, 43 insertions(+), 32 deletions(-) diff --git a/package.json b/package.json index 3a2339ec0..c690d4989 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "angular-mocks": "1.4.10", "bezier-easing": "^2.0.3", "bhttp": "^1.2.1", - "bitcore-wallet-client": "4.3.2", + "bitcore-wallet-client": "4.3.1", "bower": "^1.7.9", "chai": "^3.5.0", "cordova-android": "5.1.1", diff --git a/src/js/controllers/export.js b/src/js/controllers/export.js index 64fa8ba9d..27ebf6705 100644 --- a/src/js/controllers/export.js +++ b/src/js/controllers/export.js @@ -16,22 +16,14 @@ angular.module('copayApp.controllers').controller('exportController', }; function prepareWallet(cb) { - if ($scope.password) return cb($scope.password); + if ($scope.password) return cb(null, $scope.password); walletService.prepare(wallet, function(err, password) { - if (err) { - popupService.showAlert(gettextCatalog.getString('Error'), err); - return cb(); - } + if (err) return cb(err); $scope.password = password; walletService.getEncodedWalletInfo(wallet, $scope.password, function(err, code) { - if (err) { - popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Could not decrypt private key')); - return cb(password); - } - - $scope.file.value = false; + if (err) return cb(err); if (!code) $scope.formData.supported = false; @@ -40,10 +32,7 @@ angular.module('copayApp.controllers').controller('exportController', $scope.formData.exportWalletInfo = code; } - $timeout(function() { - $scope.$apply(); - }); - return cb(password); + return cb(null, password); }); }); }; @@ -57,9 +46,19 @@ angular.module('copayApp.controllers').controller('exportController', return; } - prepareWallet(function(password) { + prepareWallet(function(err, password) { + if (err) { + popupService.showAlert(gettextCatalog.getString('Error'), err); + return; + } if (!password) return; + + $scope.file.value = false; $scope.password = password; + + $timeout(function() { + $scope.$apply(); + }); }); }; @@ -72,7 +71,6 @@ angular.module('copayApp.controllers').controller('exportController', $scope.showAdvanced = false; $scope.wallet = wallet; $scope.canSign = wallet.canSign(); - }; /* @@ -98,7 +96,11 @@ angular.module('copayApp.controllers').controller('exportController', }; $scope.downloadWalletBackup = function() { - prepareWallet(function(password) { + prepareWallet(function(err, password) { + if (err) { + popupService.showAlert(gettextCatalog.getString('Error'), err); + return; + } if (!password) return; $scope.getAddressbook(function(err, localAddressBook) { @@ -140,21 +142,30 @@ angular.module('copayApp.controllers').controller('exportController', }; $scope.getBackup = function(cb) { - $scope.getAddressbook(function(err, localAddressBook) { + prepareWallet(function(err, password) { if (err) { - popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Failed to export')); - return cb(null); + popupService.showAlert(gettextCatalog.getString('Error'), err); + return; } - var opts = { - noSign: $scope.formData.noSignEnabled, - addressBook: localAddressBook - }; + if (!password) return; - var ew = backupService.walletExport($scope.formData.password, opts); - if (!ew) { - popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Failed to export')); - } - return cb(ew); + $scope.getAddressbook(function(err, localAddressBook) { + if (err) { + popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Failed to export')); + return cb(null); + } + var opts = { + noSign: $scope.formData.noSignEnabled, + addressBook: localAddressBook, + password: password + }; + + var ew = backupService.walletExport($scope.formData.password, opts); + if (!ew) { + popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Failed to export')); + } + return cb(ew); + }); }); }; diff --git a/src/js/services/walletService.js b/src/js/services/walletService.js index 593698907..4ea415b0f 100644 --- a/src/js/services/walletService.js +++ b/src/js/services/walletService.js @@ -1000,7 +1000,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim // not supported yet if (wallet.credentials.derivationStrategy != 'BIP44' || !wallet.canSign()) - return null; + return cb(gettextCatalog.getString('Exporting via QR not supported for this wallet')); var keys = root.getKeysWithPassword(wallet, password); From d245123079a45c6963d40dfbf2cc6445f91c1571 Mon Sep 17 00:00:00 2001 From: Javier Date: Thu, 13 Oct 2016 12:13:57 -0300 Subject: [PATCH 6/6] add check and warning before delete the encrypted version --- src/js/services/profileService.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/js/services/profileService.js b/src/js/services/profileService.js index 459b3a6e5..de2c29e98 100644 --- a/src/js/services/profileService.js +++ b/src/js/services/profileService.js @@ -611,7 +611,8 @@ angular.module('copayApp.services') str = JSON.parse(str); - if (str.xPrivKey) { + if (str.xPrivKey && str.xPrivKeyEncrypted) { + $log.warn('Found both encrypted and decrypted key. Deleting the encrypted version'); delete str.xPrivKeyEncrypted; delete str.mnemonicEncrypted; }