Merge pull request #4445 from JDonadio/bug/display-fingerprint-02

Fingerprint request in export and backup
This commit is contained in:
Matias Alejo Garcia 2016-06-17 11:32:15 -03:00 committed by GitHub
commit b948996af8
6 changed files with 100 additions and 108 deletions

View file

@ -1,4 +1,4 @@
<div class="backup" ng-controller="backupController" ng-init="init()"> <div class="backup" ng-controller="backupController" ng-init="init(index.prevState)">
<nav class="tab-bar"> <nav class="tab-bar">
<section class="left-small" ng-show="(step != 1 && step != 4)"> <section class="left-small" ng-show="(step != 1 && step != 4)">
<a ng-click="goToStep(1);"> <a ng-click="goToStep(1);">
@ -11,7 +11,7 @@
</section> </section>
<section class="right-small"> <section class="right-small">
<a class="p10" ng-click="backTo(index.prevState)"> <a class="p10" ng-click="goBack()">
<span class="text-close"> <span class="text-close">
<i class="fi-x size-24"></i> <i class="fi-x size-24"></i>
</span> </span>
@ -31,7 +31,7 @@
<div class="content preferences text-center"> <div class="content preferences text-center">
<div ng-show="step == 1"> <div ng-show="step == 1">
<div ng-show="mnemonicWords || (credentialsEncrypted && !deleted)" class="row"> <div ng-show="mnemonicWords || (!credentialsEncrypted && !deleted)" class="row">
<h5 class="text-center" translate>Write your wallet recovery phrase</h5> <h5 class="text-center" translate>Write your wallet recovery phrase</h5>
<div class="size-14 text-gray columns" ng-show="(index.n>1 && index.m != index.n )"> <div class="size-14 text-gray columns" ng-show="(index.n>1 && index.m != index.n )">
<span translate> <span translate>
@ -62,20 +62,12 @@
</div> </div>
</div> </div>
<div ng-show="mnemonicWords || (credentialsEncrypted && !deleted)"> <div ng-show="mnemonicWords || (!credentialsEncrypted && !deleted)">
<p class="text-center columns text-gray" ng-show="index.n==1 && step == 1"> <p class="text-center columns text-gray" ng-show="index.n==1 && step == 1">
<span translate> <span translate>
You need the wallet recovery phrase to restore this personal wallet. Write it down and keep them somewhere safe. You need the wallet recovery phrase to restore this personal wallet. Write it down and keep them somewhere safe.
</span> </span>
</p> </p>
<div class="row" ng-show="credentialsEncrypted">
<div class="m10t columns">
<a class="button outline light-gray expand tiny" ng-click="toggle()">
<i class="fi-widget m3r"></i>
<span translate ng-hide="show">Show Wallet Recovery Phrase</span>
</a>
</div>
</div>
<div class="row" ng-show="!credentialsEncrypted"> <div class="row" ng-show="!credentialsEncrypted">
<div class="columns"> <div class="columns">
<div class="panel" ng-class="{'enable_text_select': index.network == 'testnet'}"> <div class="panel" ng-class="{'enable_text_select': index.network == 'testnet'}">

View file

@ -4,12 +4,12 @@
ng-init="titleSection='Export Wallet'; goBackToState = 'preferencesAdvanced'"> ng-init="titleSection='Export Wallet'; goBackToState = 'preferencesAdvanced'">
</div> </div>
<div class="content preferences" ng-controller="exportController"> <div class="content preferences" ng-controller="exportController" ng-init="init(index.prevState)">
<h4></h4> <h4></h4>
<div ng-show="!backupWalletPlainText"> <div ng-show="!backupWalletPlainText">
<div class="text-warning size-14 m20b" ng-show="error"> <div class="text-warning size-14 m20b" ng-show="error">
<i class="fi-alert size-12"></i> <i class="fi-alert size-12"></i>
<span translate> Failed to export </span> <span translate>Failed to export</span>
</div> </div>
<div class="row"> <div class="row">
@ -21,7 +21,7 @@
</div> </div>
</div> </div>
<form> <form ng-hide="touchidEnabled && !touchidSuccess">
<div class="row"> <div class="row">
<div class="columns"> <div class="columns">
<label for="password" translate>Set up a password </label> <label for="password" translate>Set up a password </label>

View file

@ -1,37 +1,65 @@
'use strict'; 'use strict';
angular.module('copayApp.controllers').controller('backupController', angular.module('copayApp.controllers').controller('backupController',
function($rootScope, $scope, $timeout, $log, go, lodash, profileService, gettext, bwcService, bwsError, walletService, ongoingProcess) { function($rootScope, $scope, $timeout, $log, go, lodash, fingerprintService, platformInfo, configService, profileService, gettext, bwcService, bwsError, walletService, ongoingProcess) {
var fc = profileService.focusedClient; var fc = profileService.focusedClient;
var prevState;
$scope.customWords = []; $scope.customWords = [];
$scope.walletName = fc.credentials.walletName; $scope.walletName = fc.credentials.walletName;
$scope.credentialsEncrypted = fc.isPrivKeyEncrypted;
var handleEncryptedWallet = function(client, cb) { $scope.init = function(state) {
if (!walletService.isEncrypted(client)) return cb(); prevState = state || 'walletHome';
$rootScope.$emit('Local/NeedsPassword', false, function(err, password) { $scope.step = 1;
if (err) return cb(err); $scope.deleted = isDeletedSeed();
return cb(walletService.unlock(client, password)); if ($scope.deleted) return;
fingerprintService.check(fc, function(err) {
if (err) {
go.path(prevState);
return;
}
handleEncryptedWallet(fc, function(err) {
if (err) {
$scope.error = bwsError.msg(err, gettext('Could not decrypt'));
$log.warn('Error decrypting credentials:', $scope.error);
return;
}
$scope.credentialsEncrypted = false;
$scope.initFlow();
});
}); });
}; };
if (fc.isPrivKeyEncrypted() && !isDeletedSeed()) { function shuffledWords(words) {
$scope.credentialsEncrypted = true; var sort = lodash.sortBy(words);
passwordRequest();
} else {
if (!isDeletedSeed())
initWords();
}
$scope.init = function() { return lodash.map(sort, function(w) {
$scope.passphrase = ''; return {
word: w,
selected: false
};
});
};
$scope.initFlow = function() {
var words = fc.getMnemonic();
$scope.xPrivKey = fc.credentials.xPrivKey;
$scope.mnemonicWords = words.split(/[\u3000\s]+/);
$scope.shuffledMnemonicWords = shuffledWords($scope.mnemonicWords); $scope.shuffledMnemonicWords = shuffledWords($scope.mnemonicWords);
$scope.mnemonicHasPassphrase = fc.mnemonicHasPassphrase();
$scope.useIdeograms = words.indexOf("\u3000") >= 0;
$scope.passphrase = '';
$scope.customWords = []; $scope.customWords = [];
$scope.step = 1; $scope.step = 1;
$scope.deleted = isDeletedSeed();
$scope.credentialsEncrypted = false;
$scope.selectComplete = false; $scope.selectComplete = false;
$scope.backupError = false; $scope.backupError = false;
$timeout(function() {
$scope.$apply();
}, 10);
}; };
function isDeletedSeed() { function isDeletedSeed() {
@ -40,16 +68,14 @@ angular.module('copayApp.controllers').controller('backupController',
return false; return false;
}; };
$scope.backTo = function(state) { $scope.goBack = function() {
if (state == 'walletHome') walletService.lock(fc);
go.walletHome(); go.path(prevState || 'walletHome');
else
go.preferences();
}; };
$scope.goToStep = function(n) { $scope.goToStep = function(n) {
if (n == 1) if (n == 1)
$scope.init(); $scope.initFlow();
if (n == 2) if (n == 2)
$scope.step = 2; $scope.step = 2;
if (n == 3) { if (n == 3) {
@ -76,66 +102,6 @@ angular.module('copayApp.controllers').controller('backupController',
}; };
}; };
function initWords() {
var words = fc.getMnemonic();
$scope.xPrivKey = fc.credentials.xPrivKey;
walletService.lock(fc);
$scope.mnemonicWords = words.split(/[\u3000\s]+/);
$scope.shuffledMnemonicWords = shuffledWords($scope.mnemonicWords);
$scope.mnemonicHasPassphrase = fc.mnemonicHasPassphrase();
$scope.useIdeograms = words.indexOf("\u3000") >= 0;
};
function shuffledWords(words) {
var sort = lodash.sortBy(words);
return lodash.map(sort, function(w) {
return {
word: w,
selected: false
};
});
};
$scope.toggle = function() {
$scope.error = "";
if ($scope.credentialsEncrypted)
passwordRequest();
$timeout(function() {
$scope.$apply();
}, 1);
};
function passwordRequest() {
try {
initWords();
} catch (e) {
if (e.message && e.message.match(/encrypted/) && fc.isPrivKeyEncrypted()) {
$timeout(function() {
$scope.$apply();
}, 1);
handleEncryptedWallet(fc, function(err) {
if (err) {
$scope.error = bwsError.msg(err, gettext('Could not decrypt'));
$log.warn('Error decrypting credentials:', $scope.error); //TODO
return;
}
$scope.credentialsEncrypted = false;
initWords();
$timeout(function() {
$scope.$apply();
}, 1);
});
}
}
};
$scope.addButton = function(index, item) { $scope.addButton = function(index, item) {
var newWord = { var newWord = {
word: item.word, word: item.word,
@ -196,6 +162,18 @@ angular.module('copayApp.controllers').controller('backupController',
}, 1); }, 1);
}; };
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 backupError(err) { function backupError(err) {
ongoingProcess.set('validatingWords', false); ongoingProcess.set('validatingWords', false);
$log.debug('Failed to verify backup: ', err); $log.debug('Failed to verify backup: ', err);

View file

@ -1,15 +1,35 @@
'use strict'; 'use strict';
angular.module('copayApp.controllers').controller('exportController', angular.module('copayApp.controllers').controller('exportController',
function($rootScope, $scope, $timeout, $log, backupService, storageService, profileService, platformInfo, notification, go, gettext, gettextCatalog) { function($rootScope, $scope, $timeout, $log, backupService, fingerprintService, configService, storageService, profileService, platformInfo, notification, go, gettext, gettextCatalog) {
var isWP = platformInfo.isWP; var isWP = platformInfo.isWP;
var isAndroid = platformInfo.isAndroid; var isAndroid = platformInfo.isAndroid;
var isCordova = platformInfo.isCordova;
$scope.error = null;
$scope.success = null;
$scope.metaDataEnabled = true;
var fc = profileService.focusedClient; var fc = profileService.focusedClient;
$scope.isEncrypted = fc.isPrivKeyEncrypted(); $scope.isEncrypted = fc.isPrivKeyEncrypted();
$scope.touchidSuccess = null;
$scope.touchidEnabled = null;
$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;
fingerprintService.check(fc, function(err) {
if (err)
go.path(state || 'walletHome');
$scope.touchidSuccess = true;
$timeout(function() {
$scope.$apply();
}, 10);
});
};
$scope.downloadWalletBackup = function() { $scope.downloadWalletBackup = function() {
$scope.getMetaData($scope.metaDataEnabled, function(err, txsFromLocal, localAddressBook) { $scope.getMetaData($scope.metaDataEnabled, function(err, txsFromLocal, localAddressBook) {
@ -46,7 +66,7 @@ angular.module('copayApp.controllers').controller('exportController',
return cb(null, txsFromLocal, localAddressBook) return cb(null, txsFromLocal, localAddressBook)
}); });
}); });
} };
$scope.getHistoryCache = function(cb) { $scope.getHistoryCache = function(cb) {
storageService.getTxHistory(fc.credentials.walletId, function(err, txs) { storageService.getTxHistory(fc.credentials.walletId, function(err, txs) {
@ -63,7 +83,7 @@ angular.module('copayApp.controllers').controller('exportController',
return cb(null, localTxs); return cb(null, localTxs);
}); });
} };
$scope.getAddressbook = function(cb) { $scope.getAddressbook = function(cb) {
storageService.getAddressbook(fc.credentials.network, function(err, addressBook) { storageService.getAddressbook(fc.credentials.network, function(err, addressBook) {
@ -78,7 +98,7 @@ angular.module('copayApp.controllers').controller('exportController',
return cb(null, localAddressBook); return cb(null, localAddressBook);
}); });
} };
$scope.getBackup = function(cb) { $scope.getBackup = function(cb) {
$scope.getMetaData($scope.metaDataEnabled, function(err, txsFromLocal, localAddressBook) { $scope.getMetaData($scope.metaDataEnabled, function(err, txsFromLocal, localAddressBook) {
@ -101,7 +121,7 @@ angular.module('copayApp.controllers').controller('exportController',
} }
return cb(ew); return cb(ew);
}); });
} };
$scope.viewWalletBackup = function() { $scope.viewWalletBackup = function() {
$timeout(function() { $timeout(function() {

View file

@ -12,7 +12,7 @@ angular.module('copayApp.controllers').controller('preferencesDeleteWordsControl
confirmDialog.show(msg, function(ok) { confirmDialog.show(msg, function(ok) {
if (ok) { if (ok) {
fc.clearMnemonic(); fc.clearMnemonic();
profileService.updateCredentials(fc.export(), function() { profileService.updateCredentials(JSON.parse(fc.export()), function() {
notification.success(successMsg); notification.success(successMsg);
go.walletHome(); go.walletHome();
}); });

View file

@ -18,6 +18,7 @@ describe('Backup Controller', function() {
}); });
it('should set the mnemonic incomplete wallets', function(done) { it('should set the mnemonic incomplete wallets', function(done) {
scope.initFlow();
should.exist(scope.mnemonicWords); should.exist(scope.mnemonicWords);
scope.mnemonicWords.should.deep.equal('dizzy cycle skirt decrease exotic fork sure mixture hair vapor copper hero'.split(' ')); scope.mnemonicWords.should.deep.equal('dizzy cycle skirt decrease exotic fork sure mixture hair vapor copper hero'.split(' '));
done(); done();
@ -36,6 +37,7 @@ describe('Backup Controller', function() {
}); });
it('should not set the mnemonic for complete wallets', function() { it('should not set the mnemonic for complete wallets', function() {
scope.initFlow();
scope.mnemonicWords.should.deep.equal('cheese where alarm job conduct donkey license pave congress pepper fence current'.split(' ')); scope.mnemonicWords.should.deep.equal('cheese where alarm job conduct donkey license pave congress pepper fence current'.split(' '));
}); });