diff --git a/app-template/package.json b/app-template/package.json index 369729f80..1b9235f8c 100644 --- a/app-template/package.json +++ b/app-template/package.json @@ -42,7 +42,7 @@ "url": "https://github.com/bitpay/copay/issues" }, "dependencies": { - "bitcore-wallet-client": "2.11.0", + "bitcore-wallet-client": "4.0.0", "coveralls": "^2.11.9", "express": "^4.11.2", "fs": "0.0.2", diff --git a/chrome-app/manifest.json b/chrome-app/manifest.json index fc689fd60..7f7f2324b 100644 --- a/chrome-app/manifest.json +++ b/chrome-app/manifest.json @@ -5,7 +5,7 @@ "manifest_version": 2, "name": "BitPay", "description": "The BitPay Bitcoin Wallet", - "version": "0.3.0", + "version": "0.6.0", "permissions": [ "storage", "unlimitedStorage", diff --git a/package.json b/package.json index 0785ac8e7..dbd5438d2 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ - { + { "//":"PLEASE! Do not edit this file directly", - "//":" Modify it at app-template/", + "//":" Modify it at app-template/", "name": "bitpay", "description": "The BitPay Bitcoin Wallet", "author": "BitPay", - "version": "0.3.0", + "version": "0.6.0", "keywords": [ "wallet", "copay", @@ -23,10 +23,8 @@ "visible": true, "resizable": true, "frame": true, - "width": 400, + "width": 800, "height": 600, - "min_width": 400, - "min_height": 600, "position": "center", "fullscreen": false }, @@ -47,7 +45,7 @@ "url": "https://github.com/bitpay/copay/issues" }, "dependencies": { - "bitcore-wallet-client": "2.11.0", + "bitcore-wallet-client": "4.0.0", "coveralls": "^2.11.9", "express": "^4.11.2", "fs": "0.0.2", diff --git a/public/views/backup.html b/public/views/backup.html index 1606bff0f..46cb5ce27 100644 --- a/public/views/backup.html +++ b/public/views/backup.html @@ -7,6 +7,10 @@   + +
+delete mnemonics. You can still export it. +
diff --git a/public/views/preferences.html b/public/views/preferences.html index 0a3f1260a..6e761c24a 100644 --- a/public/views/preferences.html +++ b/public/views/preferences.html @@ -20,18 +20,12 @@
- Devices + Wallet Type - 1 + {{wallet.m}}-of-{{wallet.n}}
-
- Required number of signatures - - 1 - -
-
+
Hardware wallet {{wallet.externalSource}} @@ -56,15 +50,20 @@
Security
-
+
Backup
-
+
Request Spending Password
+
+ + Request Fingerprint + +
Delete recovery phrase diff --git a/public/views/tab-home.html b/public/views/tab-home.html index 1fae3a978..dad46a8b3 100644 --- a/public/views/tab-home.html +++ b/public/views/tab-home.html @@ -22,7 +22,7 @@ More ({{notificationsMore}}) -(ToDo: 1-1 no here yet) +(ToDo: Cache, refresh & seft not. 1-1 no here yet)
diff --git a/src/js/controllers/backup.js b/src/js/controllers/backup.js index 65ab2a89f..ad8c3cd3e 100644 --- a/src/js/controllers/backup.js +++ b/src/js/controllers/backup.js @@ -6,45 +6,32 @@ angular.module('copayApp.controllers').controller('backupController', var wallet = profileService.getWallet($stateParams.walletId); $scope.walletName = wallet.credentials.walletName; $scope.n = wallet.n; + var keys; - $scope.credentialsEncrypted = wallet.isPrivKeyEncrypted; + $scope.credentialsEncrypted = wallet.isPrivKeyEncrypted(); var isDeletedSeed = function() { - if (lodash.isEmpty(wallet.credentials.mnemonic) && lodash.isEmpty(wallet.credentials.mnemonicEncrypted)) + if (!wallet.credentials.mnemonic && !wallet.credentials.mnemonicEncrypted) return true; + return false; }; - var handleEncryptedWallet = function(client, cb) { - if (!walletService.isEncrypted(client)) { - return cb(); - } - - $rootScope.$emit('Local/NeedsPassword', false, function(err, password) { - if (err) return cb(err); - return cb(walletService.unlock(client, password)); - }); - }; - $scope.init = function() { $scope.deleted = isDeletedSeed(); - if ($scope.deleted) return; + if ($scope.deleted) { + $log.debug('no mnemonics'); + return; + } - fingerprintService.check(wallet, function(err) { - if (err) { - $state.go('preferences'); + walletService.getKeys(wallet, function(err, k) { + if (err || !k) { + $state.go('wallet.preferences'); return; } - - handleEncryptedWallet(wallet, function(err) { - if (err) { - $log.warn('Error decrypting credentials:', $scope.error); - $state.go('preferences'); - return; - } - $scope.credentialsEncrypted = false; - $scope.initFlow(); - }); + $scope.credentialsEncrypted = false; + keys = k; + $scope.initFlow(); }); }; @@ -60,8 +47,10 @@ angular.module('copayApp.controllers').controller('backupController', }; $scope.initFlow = function() { - var words = wallet.getMnemonic(); - $scope.xPrivKey = wallet.credentials.xPrivKey; + if (!keys) return; + + var words = keys.mnemonic; + $scope.mnemonicWords = words.split(/[\u3000\s]+/); $scope.shuffledMnemonicWords = shuffledWords($scope.mnemonicWords); $scope.mnemonicHasPassphrase = wallet.mnemonicHasPassphrase(); @@ -72,6 +61,7 @@ angular.module('copayApp.controllers').controller('backupController', $scope.selectComplete = false; $scope.backupError = false; + words = lodash.repeat('x', 300); $timeout(function() { $scope.$apply(); }, 10); @@ -139,10 +129,12 @@ angular.module('copayApp.controllers').controller('backupController', account: wallet.credentials.account }); } catch (err) { + walletClient.credentials.xPrivKey = lodash.repeat('x', 64); return cb(err); } - if (walletClient.credentials.xPrivKey != $scope.xPrivKey) { + if (walletClient.credentials.xPrivKey.substr(walletClient.credentials.xPrivKey) != keys.xPrivKey) { + delete walletClient.credentials; return cb('Private key mismatch'); } } @@ -205,9 +197,4 @@ angular.module('copayApp.controllers').controller('backupController', $scope.selectComplete = false; }; - - $scope.$on('$destroy', function() { - walletService.lock(wallet); - }); - }); diff --git a/src/js/controllers/bitpayCard.js b/src/js/controllers/bitpayCard.js index b861275e7..9451b38fa 100644 --- a/src/js/controllers/bitpayCard.js +++ b/src/js/controllers/bitpayCard.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('copayApp.controllers').controller('bitpayCardController', function($scope, $rootScope, $timeout, $log, $ionicModal, lodash, bitpayCardService, configService, profileService, walletService, fingerprintService, ongoingProcess, bwcError, bitcore, pbkdf2Service, moment, platformInfo) { +angular.module('copayApp.controllers').controller('bitpayCardController', function($scope, $rootScope, $timeout, $log, $ionicModal, lodash, bitpayCardService, configService, profileService, walletService, ongoingProcess, pbkdf2Service, moment, platformInfo) { var self = this; var wallet; @@ -205,7 +205,6 @@ angular.module('copayApp.controllers').controller('bitpayCardController', functi }; walletService.createTx(wallet, txp, function(err, createdTxp) { - ongoingProcess.set('Processing Transaction...', false); if (err) { self.error = bwcError.msg(err); $timeout(function() { @@ -213,10 +212,9 @@ angular.module('copayApp.controllers').controller('bitpayCardController', functi }); return; } - self.confirmTx(createdTxp, function(err, tx) { - ongoingProcess.set('Processing Transaction...', false); + walletService.publishAndSign(createdTxp, function(err, tx) { if (err) { - self.error = bwcError.msg(err); + self.error = err; $timeout(function() { $scope.$digest(); }); @@ -234,55 +232,6 @@ angular.module('copayApp.controllers').controller('bitpayCardController', functi }, 100); }; - this.confirmTx = function(txp, cb) { - - fingerprintService.check(wallet, function(err) { - if (err) { - $log.debug(err); - return cb(err); - } - - walletService.handleEncryptedWallet(wallet, function(err) { - if (err) { - $log.debug(err); - return bwcError.cb(err, null, cb); - } - - ongoingProcess.set('Processing Transaction...', true); - walletService.publishTx(wallet, txp, function(err, publishedTxp) { - if (err) { - $log.debug(err); - return bwcError.cb(err, null, cb); - } - - walletService.signTx(wallet, publishedTxp, function(err, signedTxp) { - walletService.lock(wallet); - if (err) { - $log.debug(err); - walletService.removeTx(wallet, signedTxp, function(err) { - if (err) $log.debug(err); - }); - return bwcError.cb(err, null, cb); - } - - walletService.broadcastTx(wallet, signedTxp, function(err, broadcastedTxp) { - if (err) { - $log.debug(err); - walletService.removeTx(wallet, broadcastedTxp, function(err) { - if (err) $log.debug(err); - }); - return bwcError.cb(err, null, cb); - } - $timeout(function() { - return cb(null, broadcastedTxp); - }, 5000); - }); - }); - }); - }); - }); - }; - this.authenticate = function() { self.error = null; diff --git a/src/js/controllers/buyAmazon.js b/src/js/controllers/buyAmazon.js index afb87955e..335ab0cbc 100644 --- a/src/js/controllers/buyAmazon.js +++ b/src/js/controllers/buyAmazon.js @@ -244,7 +244,6 @@ angular.module('copayApp.controllers').controller('buyAmazonController', } walletService.signTx(wallet, publishedTxp, function(err, signedTxp) { - walletService.lock(wallet); if (err) { $log.debug(err); walletService.removeTx(wallet, signedTxp, function(err) { diff --git a/src/js/controllers/confirm.js b/src/js/controllers/confirm.js index 4ec35031e..e9af90994 100644 --- a/src/js/controllers/confirm.js +++ b/src/js/controllers/confirm.js @@ -189,7 +189,7 @@ angular.module('copayApp.controllers').controller('confirmController', function( }; var setSendError = function(msg) { - showAlert(gettext('Error creating transaction'), msg); + showAlert(gettext('Error at confirm:'), msg); }; function apply(txp) { diff --git a/src/js/controllers/export.js b/src/js/controllers/export.js index 7c3870993..1ea44845f 100644 --- a/src/js/controllers/export.js +++ b/src/js/controllers/export.js @@ -1,7 +1,7 @@ 'use strict'; angular.module('copayApp.controllers').controller('exportController', - function($rootScope, $scope, $timeout, $log, lodash, backupService, walletService, storageService, profileService, platformInfo, notification, gettext, gettextCatalog, $state, $stateParams) { + function($rootScope, $scope, $timeout, $log, lodash, backupService, walletService, storageService, profileService, platformInfo, gettext, gettextCatalog, $state, $stateParams) { var prevState; var isWP = platformInfo.isWP; var isAndroid = platformInfo.isAndroid; @@ -21,7 +21,7 @@ angular.module('copayApp.controllers').controller('exportController', $scope.canSign = wallet.canSign(); walletService.getEncodedWalletInfo(wallet, function(err, code) { - if (err) { + if (err || !code) { $log.warn(err); return $state.go('wallet.preferencesAdvanced') } @@ -48,10 +48,6 @@ angular.module('copayApp.controllers').controller('exportController', }; */ - $scope.$on('$destroy', function() { - walletService.lock(wallet); - }); - $scope.downloadWalletBackup = function() { $scope.getAddressbook(function(err, localAddressBook) { if (err) { @@ -68,7 +64,6 @@ angular.module('copayApp.controllers').controller('exportController', $scope.error = true; return; } - notification.success(gettext('Success'), gettext('Encrypted export file saved')); $state.go('tabs.home'); }); }); diff --git a/src/js/controllers/modals/txpDetails.js b/src/js/controllers/modals/txpDetails.js index 497a33e95..b426602e6 100644 --- a/src/js/controllers/modals/txpDetails.js +++ b/src/js/controllers/modals/txpDetails.js @@ -48,10 +48,6 @@ angular.module('copayApp.controllers').controller('txpDetailsController', functi }, 10); }; - $scope.$on('$destroy', function() { - walletService.lock($scope.wallet); - }); - $scope.reject = function(txp) { $scope.loading = true; $scope.error = null; diff --git a/src/js/controllers/preferences.js b/src/js/controllers/preferences.js index 4a72ae416..92fb04344 100644 --- a/src/js/controllers/preferences.js +++ b/src/js/controllers/preferences.js @@ -1,7 +1,7 @@ 'use strict'; angular.module('copayApp.controllers').controller('preferencesController', - function($scope, $rootScope, $timeout, $log, $stateParams, configService, profileService, fingerprintService, walletService) { + function($scope, $rootScope, $timeout, $log, $stateParams, configService, profileService, fingerprintService, walletService, $state) { var wallet = profileService.getWallet($stateParams.walletId); var walletId = wallet.credentials.walletId; @@ -10,22 +10,20 @@ angular.module('copayApp.controllers').controller('preferencesController', $scope.init = function() { $scope.externalSource = null; - if (wallet) { - var config = configService.getSync(); - config.aliasFor = config.aliasFor || {}; - $scope.alias = config.aliasFor[walletId] || wallet.credentials.walletName; - $scope.color = config.colorFor[walletId] || '#4A90E2'; + if (!wallet) + return $state.go('tabs.home'); - $scope.encryptEnabled = walletService.isEncrypted(wallet); - if (wallet.isPrivKeyExternal) - $scope.externalSource = wallet.getPrivKeyExternalSourceName() == 'ledger' ? 'Ledger' : 'Trezor'; + var config = configService.getSync(); + config.aliasFor = config.aliasFor || {}; + $scope.alias = config.aliasFor[walletId] || wallet.credentials.walletName; + $scope.color = config.colorFor[walletId] || '#4A90E2'; - // TODO externalAccount - //this.externalIndex = wallet.getExternalIndex(); - } + $scope.encryptEnabled = walletService.isEncrypted(wallet); + if (wallet.isPrivKeyExternal) + $scope.externalSource = wallet.getPrivKeyExternalSourceName() == 'ledger' ? 'Ledger' : 'Trezor'; - $scope.touchidAvailable = fingerprintService.isAvailable(); - $scope.touchidEnabled = config.touchIdFor ? config.touchIdFor[walletId] : null; + $scope.touchIdAvailable = fingerprintService.isAvailable(); + $scope.touchIdEnabled = config.touchIdFor ? config.touchIdFor[walletId] : null; $scope.deleted = false; if (wallet.credentials && !wallet.credentials.mnemonicEncrypted && !wallet.credentials.mnemonic) { @@ -33,97 +31,51 @@ angular.module('copayApp.controllers').controller('preferencesController', } }; - var handleEncryptedWallet = function(cb) { - $rootScope.$emit('Local/NeedsPassword', false, function(err, password) { - if (err) return cb(err); - return cb(walletService.unlock(wallet, password)); - }); - }; - $scope.encryptChange = function() { if (!wallet) return; var val = $scope.encryptEnabled; - var setPrivateKeyEncryption = function(password, cb) { - $log.debug('Encrypting private key for', wallet.credentials.walletName); - - wallet.setPrivateKeyEncryption(password); - wallet.lock(); - profileService.updateCredentials(JSON.parse(wallet.export()), function() { - $log.debug('Wallet encrypted'); - return cb(); - }); - }; - - var disablePrivateKeyEncryption = function(cb) { - $log.debug('Disabling private key encryption for', wallet.credentials.walletName); - - try { - wallet.disablePrivateKeyEncryption(); - } catch (e) { - return cb(e); - } - profileService.updateCredentials(JSON.parse(wallet.export()), function() { - $log.debug('Wallet encryption disabled'); - return cb(); - }); - }; - if (val && !walletService.isEncrypted(wallet)) { - $rootScope.$emit('Local/NeedsPassword', true, function(err, password) { - if (err || !password) { + $log.debug('Encrypting private key for', wallet.name); + walletService.encrypt(wallet, function(err) { + if (err) { + $log.warn(err); + + // ToDo show error? $scope.encryptEnabled = false; return; } - setPrivateKeyEncryption(password, function() { - $rootScope.$emit('Local/NewEncryptionSetting'); + profileService.updateCredentials(JSON.parse(wallet.export()), function() { + $log.debug('Wallet encrypted'); + return; + }); + }) + } else if (!val && walletService.isEncrypted(wallet)) { + walletService.decrypt(wallet, function(err) { + if (err) { + $log.warn(err); + + // ToDo show error? $scope.encryptEnabled = true; + return; + } + profileService.updateCredentials(JSON.parse(wallet.export()), function() { + $log.debug('Wallet decrypted'); + return; }); - }); - } else { - if (!val && walletService.isEncrypted(wallet)) { - handleEncryptedWallet(function(err) { - if (err) { - $scope.encryptEnabled = true; - return; - } - disablePrivateKeyEncryption(function(err) { - $rootScope.$emit('Local/NewEncryptionSetting'); - if (err) { - $scope.encryptEnabled = true; - $log.error(err); - return; - } - $scope.encryptEnabled = false; - }); - }); - } + }) } }; - $scope.touchidChange = function() { - - var opts = { - touchIdFor: {} - }; - opts.touchIdFor[walletId] = $scope.touchidEnabled; - - fingerprintService.check(wallet, function(err) { + $scope.touchIdChange = function() { + var newStatus = $scope.touchIdEnabled; + walletService.setTouchId(wallet, newStatus, function(err) { if (err) { - $log.debug(err); - $timeout(function() { - $scope.touchidError = true; - $scope.touchidEnabled = true; - }, 100); + $log.warn(err); + $scope.touchIdEnabled = !newStatus; return; } - configService.set(opts, function(err) { - if (err) { - $log.debug(err); - $scope.touchidError = true; - $scope.touchidEnabled = false; - } - }); + $log.debug('Touch Id status changed: ' + newStatus); }); }; }); diff --git a/src/js/controllers/sellCoinbase.js b/src/js/controllers/sellCoinbase.js index 9d9f876eb..6ce9b28b3 100644 --- a/src/js/controllers/sellCoinbase.js +++ b/src/js/controllers/sellCoinbase.js @@ -30,14 +30,6 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController', ]; $scope.selectedPriceSensitivity = $scope.priceSensitivity[1]; - var handleEncryptedWallet = function(client, cb) { - if (!walletService.isEncrypted(client)) return cb(); - $rootScope.$emit('Local/NeedsPassword', false, function(err, password) { - if (err) return cb(err); - return cb(walletService.unlock(client, password)); - }); - }; - this.init = function(testnet) { self.allWallets = profileService.getWallets(testnet ? 'testnet' : 'livenet', 1); @@ -263,66 +255,7 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController', this.confirmTx = function(txp, cb) { - fingerprintService.check(client, function(err) { - if (err) { - $log.debug(err); - return cb(err); - } - - handleEncryptedWallet(client, function(err) { - if (err) { - $log.debug(err); - return cb(err); - } - - ongoingProcess.set('Sending Bitcoin to Coinbase...', true); - walletService.publishTx(client, txp, function(err, publishedTxp) { - if (err) { - ongoingProcess.set('Sending Bitcoin to Coinbase...', false); - $log.debug(err); - return cb({ - errors: [{ - message: 'Transaction could not be published: ' + err.message - }] - }); - } - - walletService.signTx(client, publishedTxp, function(err, signedTxp) { - walletService.lock(client); - if (err) { - ongoingProcess.set('Sending Bitcoin to Coinbase...', false); - $log.debug(err); - walletService.removeTx(client, signedTxp, function(err) { - if (err) $log.debug(err); - }); - return cb({ - errors: [{ - message: 'The payment was created but could not be completed: ' + err.message - }] - }); - } - - walletService.broadcastTx(client, signedTxp, function(err, broadcastedTxp) { - if (err) { - ongoingProcess.set('Sending Bitcoin to Coinbase...', false); - $log.debug(err); - walletService.removeTx(client, broadcastedTxp, function(err) { - if (err) $log.debug(err); - }); - return cb({ - errors: [{ - message: 'The payment was created but could not be broadcasted: ' + err.message - }] - }); - } - $timeout(function() { - return cb(null, broadcastedTxp); - }, 5000); - }); - }); - }); - }); - }); + // TODO see walletService createAndPublish }; }); diff --git a/src/js/controllers/sellGlidera.js b/src/js/controllers/sellGlidera.js index 66c0f0de0..e50757128 100644 --- a/src/js/controllers/sellGlidera.js +++ b/src/js/controllers/sellGlidera.js @@ -208,53 +208,44 @@ angular.module('copayApp.controllers').controller('sellGlideraController', self.error = err.message ||  bwcError.msg(err); return; } - fingerprintService.check(wallet, function(err) { + walletService.prepare(wallet, txp, function(err, password) { if (err) { self.error = err.message ||  bwcError.msg(err); return; } - - walletService.handleEncryptedWallet(wallet, function(err) { + ongoingProcess.set('signingTx', true); + walletService.publishTx(wallet, createdTxp, function(err, publishedTxp) { if (err) { + ongoingProcess.clear(); self.error = err.message ||  bwcError.msg(err); - return; } - ongoingProcess.set('signingTx', true); - walletService.publishTx(wallet, createdTxp, function(err, publishedTxp) { + walletService.signTx(wallet, publishedTxp, function(err, password, signedTxp) { + walletService.removeTx(wallet, signedTxp, function(err) { + if (err) $log.debug(err); + }); + ongoingProcess.clear(); if (err) { - ongoingProcess.clear(); self.error = err.message ||  bwcError.msg(err); + return; } - - walletService.signTx(wallet, publishedTxp, function(err, signedTxp) { - walletService.lock(wallet); - walletService.removeTx(wallet, signedTxp, function(err) { - if (err) $log.debug(err); - }); + var rawTx = signedTxp.raw; + var data = { + refundAddress: refundAddress, + signedTransaction: rawTx, + priceUuid: self.sellPrice.priceUuid, + useCurrentPrice: self.sellPrice.priceUuid ? false : true, + ip: null + }; + ongoingProcess.set('Seling Bitcoin', true); + glideraService.sell(token, twoFaCode, data, function(err, data) { ongoingProcess.clear(); if (err) { self.error = err.message ||  bwcError.msg(err); return; } - var rawTx = signedTxp.raw; - var data = { - refundAddress: refundAddress, - signedTransaction: rawTx, - priceUuid: self.sellPrice.priceUuid, - useCurrentPrice: self.sellPrice.priceUuid ? false : true, - ip: null - }; - ongoingProcess.set('Seling Bitcoin', true); - glideraService.sell(token, twoFaCode, data, function(err, data) { - ongoingProcess.clear(); - if (err) { - self.error = err.message ||  bwcError.msg(err); - return; - } - self.success = data; - $scope.update(); - }); + self.success = data; + $scope.update(); }); }); }); diff --git a/src/js/controllers/tab-home.js b/src/js/controllers/tab-home.js index da9538144..b6886b5c2 100644 --- a/src/js/controllers/tab-home.js +++ b/src/js/controllers/tab-home.js @@ -37,7 +37,6 @@ angular.module('copayApp.controllers').controller('tabHomeController', walletService.getNotifications(wallet, { timeSpan: timeSpan }, function(err, n) { -console.log('[tab-home.js.39]', wallet.name, n); //TODO if (err) { console.log('[tab-home.js.35:err:]', $log.error(err)); //TODO return; diff --git a/src/js/services/profileService.js b/src/js/services/profileService.js index 12d55b3e5..d54881695 100644 --- a/src/js/services/profileService.js +++ b/src/js/services/profileService.js @@ -87,11 +87,6 @@ angular.module('copayApp.services') }); }); - if (wallet.hasPrivKeyEncrypted() && !wallet.isPrivKeyEncrypted()) { - $log.warn('Auto locking unlocked wallet:' + walletId); - wallet.lock(); - } - wallet.initialize({}, function(err) { if (err) { $log.error('Could not init notifications err:', err); @@ -548,14 +543,6 @@ angular.module('copayApp.services') return cb(gettext('Could not import. Check input file and spending password')); } - if (walletClient.hasPrivKeyEncrypted()) { - try { - walletClient.disablePrivateKeyEncryption(); - } catch (e) { - $log.warn(e); - } - } - str = JSON.parse(str); var addressBook = str.addressBook || {}; diff --git a/src/js/services/walletService.js b/src/js/services/walletService.js index b8b006e7e..f4230fc33 100644 --- a/src/js/services/walletService.js +++ b/src/js/services/walletService.js @@ -547,27 +547,6 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim return isEncrypted; }; - root.lock = function(wallet) { - try { - wallet.lock(); - } catch (e) { - $log.warn('Encrypting wallet:', e); - }; - }; - - root.unlock = function(wallet, password) { - if (lodash.isEmpty(wallet)) - return 'MISSING_PARAMETER'; - if (lodash.isEmpty(password)) - return 'NO_PASSWORD_GIVEN'; - try { - wallet.unlock(password); - } catch (e) { - $log.warn('Decrypting wallet:', e); - return 'PASSWORD_INCORRECT'; - } - }; - root.createTx = function(wallet, txp, cb) { if (lodash.isEmpty(txp) || lodash.isEmpty(wallet)) return cb('MISSING_PARAMETER'); @@ -578,28 +557,12 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim else return cb(null, createdTxp); }); } else { - wallet.getFeeLevels(wallet.credentials.network, function(err, levels) { + wallet.createTxProposal(txp, function(err, createdTxp) { if (err) return cb(err); - - var feeLevelValue = lodash.find(levels, { - level: txp.feeLevel - }); - - if (!feeLevelValue || !feeLevelValue.feePerKB) - return cb({ - message: 'Could not get dynamic fee for level: ' + feeLevel - }); - - $log.debug('Dynamic fee: ' + txp.feeLevel + ' ' + feeLevelValue.feePerKB + ' SAT'); - - txp.feePerKb = feeLevelValue.feePerKB; - wallet.createTxProposal(txp, function(err, createdTxp) { - if (err) return cb(err); - else { - $log.debug('Transaction created'); - return cb(null, createdTxp); - } - }); + else { + $log.debug('Transaction created'); + return cb(null, createdTxp); + } }); } }; @@ -619,8 +582,8 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim }); }; - root.signTx = function(wallet, txp, cb) { - if (lodash.isEmpty(txp) || lodash.isEmpty(wallet)) + root.signTx = function(wallet, txp, password, cb) { + if (!wallet || !txp || !cb) return cb('MISSING_PARAMETER'); if (wallet.isPrivKeyExternal()) { @@ -637,8 +600,8 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim } else { try { - wallet.signTxProposal(txp, function(err, signedTxp) { - $log.debug('Transaction signed'); + wallet.signTxProposal(txp, password, function(err, signedTxp) { + $log.debug('Transaction signed err:' + err); return cb(err, signedTxp); }); } catch (e) { @@ -861,12 +824,12 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim // An alert dialog - var askPassword = function(name, cb) { + var askPassword = function(name, title, cb) { var scope = $rootScope.$new(true); scope.data = []; var pass = $ionicPopup.show({ template: '', - title: 'Enter Spending Password', + title: title, subTitle: name, scope: scope, buttons: [{ @@ -891,12 +854,42 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim }); }; + + root.encrypt = function(wallet, cb) { + askPassword(wallet.name, gettext('Enter new spending password'), function(password) { + if (!password) return cb('no password'); + askPassword(wallet.name, gettext('Confirm you new spending password'), function(password2) { + if (!password2 || password != password2) + return cb('password mismatch'); + + wallet.encryptPrivateKey(password); + return cb(); + }); + }); + }; + + + root.decrypt = function(wallet, cb) { + $log.debug('Disabling private key encryption for' + wallet.name); + askPassword(wallet.name, gettext('Enter Spending Password'), function(password) { + if (!password) return cb('no password'); + + try { + wallet.decryptPrivateKey(password); + } catch (e) { + return cb(e); + } + return cb(); + }); + }; + root.handleEncryptedWallet = function(wallet, cb) { if (!root.isEncrypted(wallet)) return cb(); - askPassword(wallet.name, function(password) { + askPassword(wallet.name, gettext('Enter Spending Password'), function(password) { if (!password) return cb('no password'); - return cb(root.unlock(wallet, password)); + + return cb(null, password); }); }; @@ -932,6 +925,19 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim }); }; + + root.prepare = function(wallet, cb) { + fingerprintService.check(wallet, function(err) { + if (err) return cb(err); + + root.handleEncryptedWallet(wallet, function(err, password) { + if (err) return cb(err); + + return cb(null, password); + }); + }); + }; + root.publishAndSign = function(wallet, txp, cb) { var publishFn = root.publishTx; @@ -943,56 +949,51 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim }; } - fingerprintService.check(wallet, function(err) { - if (err) return cb(err); + root.prepare(wallet, function(err, password) { + if (err) return cb('Prepare error: ' + err); - root.handleEncryptedWallet(wallet, function(err) { - if (err) return cb(err); + ongoingProcess.set('sendingTx', true); + publishFn(wallet, txp, function(err, publishedTxp) { + ongoingProcess.set('sendingTx', false); + if (err) return cb('Send Error: ' + err); - ongoingProcess.set('sendingTx', true); - publishFn(wallet, txp, function(err, publishedTxp) { - ongoingProcess.set('sendingTx', false); - if (err) return cb(err); - - ongoingProcess.set('signingTx', true); - root.signTx(wallet, publishedTxp, function(err, signedTxp) { - root.lock(wallet); - - ongoingProcess.set('signingTx', false); - root.invalidateCache(wallet); + ongoingProcess.set('signingTx', true); + root.signTx(wallet, publishedTxp, password, function(err, signedTxp) { + ongoingProcess.set('signingTx', false); + root.invalidateCache(wallet); - if (err) { - // TODO? - var msg = err.message ? - err.message : - gettext('The payment was created but could not be completed. Please try again from home screen'); - $rootScope.$emit('Local/TxAction', wallet.id); - return cb(err); - } + if (err) { + $log.warn('sign error:' + err); + // TODO? + var msg = err.message ? + err.message : + gettext('The payment was created but could not be completed. Please try again from home screen'); + $rootScope.$emit('Local/TxAction', wallet.id); + return cb(msg); + } - if (signedTxp.status == 'accepted') { - ongoingProcess.set('broadcastingTx', true); - root.broadcastTx(wallet, signedTxp, function(err, broadcastedTxp) { - ongoingProcess.set('broadcastingTx', false); - if (err) return cb(err); + if (signedTxp.status == 'accepted') { + ongoingProcess.set('broadcastingTx', true); + root.broadcastTx(wallet, signedTxp, function(err, broadcastedTxp) { + ongoingProcess.set('broadcastingTx', false); + if (err) return cb('sign error' + err); - var type = txStatus.notify(broadcastedTxp); - root.openStatusModal(type, broadcastedTxp, function() { - $rootScope.$emit('Local/TxAction', wallet.id); - }); - - return cb(null, broadcastedTxp) - }); - } else { - var type = txStatus.notify(signedTxp); - root.openStatusModal(type, signedTxp, function() { - root.invalidateCache(wallet); + var type = txStatus.notify(broadcastedTxp); + root.openStatusModal(type, broadcastedTxp, function() { $rootScope.$emit('Local/TxAction', wallet.id); }); - return cb(null, signedTxp); - } - }); + + return cb(null, broadcastedTxp) + }); + } else { + var type = txStatus.notify(signedTxp); + root.openStatusModal(type, signedTxp, function() { + root.invalidateCache(wallet); + $rootScope.$emit('Local/TxAction', wallet.id); + }); + return cb(null, signedTxp); + } }); }); }); @@ -1004,7 +1005,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim if (err) return cb(err); notifications = lodash.filter(notifications, function(x) { - return x.type != 'NewBlock' && x.type != 'BalanceUpdated' && x.type !='NewOutgoingTxByThirdParty'; + return x.type != 'NewBlock' && x.type != 'BalanceUpdated' && x.type != 'NewOutgoingTxByThirdParty'; }); var idToName = {}; @@ -1027,42 +1028,34 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim root.getEncodedWalletInfo = function(wallet, cb) { - var getCode = function() { - var derivationPath = wallet.credentials.getBaseAddressDerivationPath(); - var encodingType = { - mnemonic: 1, - xpriv: 2, - xpub: 3 - }; - var info; + var derivationPath = wallet.credentials.getBaseAddressDerivationPath(); + var encodingType = { + mnemonic: 1, + xpriv: 2, + xpub: 3 + }; + var info; - // not supported yet - if (wallet.credentials.derivationStrategy != 'BIP44' || !wallet.canSign()) - return null; + // not supported yet + if (wallet.credentials.derivationStrategy != 'BIP44' || !wallet.canSign()) + return null; - if (wallet.credentials.mnemonic) { + root.getKeys(wallet, function(err, keys){ + if (err || !keys) return cb(err); + + if (keys.mnemonic) { info = { type: encodingType.mnemonic, - data: wallet.credentials.mnemonic, + data: keys.mnemonic, } } else { info = { type: encodingType.xpriv, - data: wallet.credentials.xPrivKey + data: keys.xPrivKey } } - return info.type + '|' + info.data + '|' + wallet.credentials.network.toLowerCase() + '|' + derivationPath + '|' + (wallet.credentials.mnemonicHasPassphrase); - }; + return cb(null, info.type + '|' + info.data + '|' + wallet.credentials.network.toLowerCase() + '|' + derivationPath + '|' + (wallet.credentials.mnemonicHasPassphrase)); - fingerprintService.check(wallet, function(err) { - if (err) return cb(err); - - root.handleEncryptedWallet(wallet, function(err) { - if (err) return cb(err); - - var code = getCode(); - return cb(null, code); - }); }); }; @@ -1110,7 +1103,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim } }); - // messsages... + // messages... var u = bwcService.getUtils(); lodash.each(finale, function(x) { @@ -1124,6 +1117,31 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim }; + root.setTouchId = function(wallet, enabled, cb) { + fingerprintService.check(wallet, function(err) { + if (err) return cb(err); { + $log.debug(err); + return; + } + configService.set(opts, cb); + }); + }; + + root.getKeys = function(wallet, cb) { + root.prepare(wallet, function(err, password) { + if (err) return cb(err); + var keys; + + try { + keys = wallet.getKeys(password); + } catch (e) { + return cb(err); + } + + return cb(null, keys); + }); + }; + return root; }); diff --git a/webkitbuilds/.desktop b/webkitbuilds/.desktop index 67bbc6f08..e83b575d2 100644 --- a/webkitbuilds/.desktop +++ b/webkitbuilds/.desktop @@ -1,6 +1,6 @@ [Desktop Entry] Type=Application -Version=0.3.0 +Version=0.6.0 Name=BitPay Comment=The BitPay Bitcoin Wallet Exec=bitpay diff --git a/webkitbuilds/setup-win.iss b/webkitbuilds/setup-win.iss index 7973ff779..356408e01 100755 --- a/webkitbuilds/setup-win.iss +++ b/webkitbuilds/setup-win.iss @@ -2,7 +2,7 @@ ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! #define MyAppName "bitpay" -#define MyAppVersion "0.3.0" +#define MyAppVersion "0.6.0" #define MyAppPublisher "BitPay" #define MyAppURL "https://bitpay.com" #define MyAppExeName "*NAMECASENOSPACE.exe"