Merge pull request #686 from maraoz/automatic/backup

Automatic backup after create/join
This commit is contained in:
Gustavo Maximiliano Cortez 2014-06-17 10:56:27 -03:00
commit 03993b5172
9 changed files with 150 additions and 79 deletions

View File

@ -849,6 +849,7 @@ on supported browsers please check <a href="http://www.webrtc.org/">http://www.w
<script src="js/services/controllerUtils.js"></script>
<script src="js/services/passphrase.js"></script>
<script src="js/services/notifications.js"></script>
<script src="js/services/backupService.js"></script>
<script src="js/controllers/header.js"></script>
<script src="js/controllers/footer.js"></script>

View File

@ -26,13 +26,13 @@ var copayApp = window.copayApp = angular.module('copayApp',[
'monospaced.qrcode',
'notifications',
'copayApp.filters',
'copayApp.services',
'copayApp.controllers',
'copayApp.directives',
'copayApp.services',
]);
angular.module('copayApp.filters', []);
angular.module('copayApp.services', []);
angular.module('copayApp.controllers', []);
angular.module('copayApp.directives', []);
angular.module('copayApp.services', []);

View File

@ -1,69 +1,33 @@
'use strict';
angular.module('copayApp.controllers').controller('BackupController',
function($scope, $rootScope, $location, $window, $timeout, $modal) {
function($scope, $rootScope, $location, $window, $timeout, $modal, backupService) {
$scope.title = 'Backup';
var _getEncryptedWallet = function() {
var wallet = $rootScope.wallet.toEncryptedObj();
return wallet;
};
$scope.download = function() {
var timestamp = +(new Date);
var walletName = ($rootScope.wallet.name ? $rootScope.wallet.name : '') + '-' + $rootScope.wallet.id ;
var filename = walletName + '-' + timestamp + '.json.aes';
var wallet = _getEncryptedWallet();
var blob = new Blob([wallet], {type: 'text/plain;charset=utf-8'});
// show a native save dialog if we are in the shell
// and pass the wallet to the shell to convert to node Buffer
if (window.cshell) {
return window.cshell.send('backup:download', {
name: walletName,
wallet: wallet
});
}
// otherwise lean on the browser implementation
saveAs(blob, filename);
backupService.download($rootScope.wallet);
};
$scope.openModal = function () {
var modalInstance = $modal.open({
templateUrl: 'backupModal.html',
controller: ModalInstanceCtrl,
});
$scope.openModal = function() {
var modalInstance = $modal.open({
templateUrl: 'backupModal.html',
controller: ModalInstanceCtrl,
});
modalInstance.result.then(sendEmail);
};
modalInstance.result.then(function(email) {
backupService.sendEmail(email, $rootScope.wallet);
});
};
var sendEmail = function(email) {
var body = _getEncryptedWallet();
var subject = ($rootScope.wallet.name ? $rootScope.wallet.name + ' - ' : '') + $rootScope.wallet.id;
var href = 'mailto:' + email + '?'
+ 'subject=[Copay Backup] ' + subject + '&'
+ 'body=' + body;
});
if (window.cshell) {
return window.cshell.send('backup:email', href);
}
var ModalInstanceCtrl = function($scope, $modalInstance) {
var newWin = $window.open(href, '_blank', 'scrollbars=yes,resizable=yes,width=10,height=10');
if (newWin) {
$timeout(function() {
newWin.close();
}, 1000);
}
};
});
var ModalInstanceCtrl = function ($scope, $modalInstance) {
$scope.submit = function (form) {
$scope.submit = function(form) {
$modalInstance.close($scope.email);
};
$scope.cancel = function () {
$scope.cancel = function() {
$modalInstance.dismiss('cancel');
};
};

View File

@ -33,7 +33,7 @@ var valid_pairs = {
};
angular.module('copayApp.controllers').controller('SetupController',
function($scope, $rootScope, $location, $timeout, walletFactory, controllerUtils, Passphrase) {
function($scope, $rootScope, $location, $timeout, walletFactory, controllerUtils, Passphrase, backupService) {
$rootScope.videoInfo = {};
$scope.loading = false;
@ -84,6 +84,7 @@ angular.module('copayApp.controllers').controller('SetupController',
passphrase: passphrase,
};
var w = walletFactory.create(opts);
backupService.download(w);
controllerUtils.startNetwork(w, $scope);
});
};

View File

@ -1,10 +1,11 @@
'use strict';
angular.module('copayApp.controllers').controller('SigninController',
function($scope, $rootScope, $location, walletFactory, controllerUtils, Passphrase) {
var cmp = function(o1, o2){
var v1 = o1.show.toLowerCase(), v2 = o2.show.toLowerCase();
return v1 > v2 ? 1 : ( v1 < v2 ) ? -1 : 0;
function($scope, $rootScope, $location, walletFactory, controllerUtils, Passphrase, backupService) {
var cmp = function(o1, o2) {
var v1 = o1.show.toLowerCase(),
v2 = o2.show.toLowerCase();
return v1 > v2 ? 1 : (v1 < v2) ? -1 : 0;
};
$rootScope.videoInfo = {};
$scope.loading = false;
@ -14,23 +15,31 @@ angular.module('copayApp.controllers').controller('SigninController',
$scope.open = function(form) {
if (form && form.$invalid) {
$rootScope.$flashMessage = { message: 'Please, enter required fields', type: 'error'};
$rootScope.$flashMessage = {
message: 'Please, enter required fields',
type: 'error'
};
return;
}
$scope.loading = true;
var password = form.openPassword.$modelValue;
Passphrase.getBase64Async(password, function(passphrase){
Passphrase.getBase64Async(password, function(passphrase) {
var w, errMsg;
try{
var w = walletFactory.open($scope.selectedWalletId, { passphrase: passphrase});
} catch (e){
try {
var w = walletFactory.open($scope.selectedWalletId, {
passphrase: passphrase
});
} catch (e) {
errMsg = e.message;
};
if (!w) {
$scope.loading = false;
$rootScope.$flashMessage = { message: errMsg || 'Wrong password', type: 'error'};
$rootScope.$flashMessage = {
message: errMsg || 'Wrong password',
type: 'error'
};
$rootScope.$digest();
return;
}
@ -40,31 +49,48 @@ angular.module('copayApp.controllers').controller('SigninController',
$scope.join = function(form) {
if (form && form.$invalid) {
$rootScope.$flashMessage = { message: 'Please, enter required fields', type: 'error'};
$rootScope.$flashMessage = {
message: 'Please, enter required fields',
type: 'error'
};
return;
}
$scope.loading = true;
walletFactory.network.on('badSecret', function() {
});
walletFactory.network.on('badSecret', function() {});
Passphrase.getBase64Async($scope.joinPassword, function(passphrase){
walletFactory.joinCreateSession($scope.connectionId, $scope.nickname, passphrase, function(err,w) {
Passphrase.getBase64Async($scope.joinPassword, function(passphrase) {
walletFactory.joinCreateSession($scope.connectionId, $scope.nickname, passphrase, function(err, w) {
$scope.loading = false;
if (err || !w) {
if (err === 'joinError')
$rootScope.$flashMessage = { message: 'Can not find peer'};
$rootScope.$flashMessage = {
message: 'Can\'t find peer'
};
else if (err === 'walletFull')
$rootScope.$flashMessage = { message: 'The wallet is full', type: 'error'};
$rootScope.$flashMessage = {
message: 'The wallet is full',
type: 'error'
};
else if (err === 'badNetwork')
$rootScope.$flashMessage = { message: 'The wallet your are trying to join uses a different Bitcoin Network. Check your settings.', type: 'error'};
$rootScope.$flashMessage = {
message: 'The wallet your are trying to join uses a different Bitcoin Network. Check your settings.',
type: 'error'
};
else if (err === 'badSecret')
$rootScope.$flashMessage = { message: 'Bad secret secret string', type: 'error'};
$rootScope.$flashMessage = {
message: 'Bad secret secret string',
type: 'error'
};
else
$rootScope.$flashMessage = { message: 'Unknown error', type: 'error'};
$rootScope.$flashMessage = {
message: 'Unknown error',
type: 'error'
};
controllerUtils.onErrorDigest();
} else {
controllerUtils.startNetwork(w, $scope);
backupService.download(w);
controllerUtils.startNetwork(w, $scope);
}
});
});

View File

@ -0,0 +1,47 @@
'use strict';
var BackupService = function() {};
BackupService.prototype.getName = function(wallet) {
return (wallet.name ? (wallet.name+'-') : '') + wallet.id;
};
BackupService.prototype.download = function(wallet) {
var ew = wallet.toEncryptedObj();
var timestamp = +(new Date());
var walletName = this.getName(wallet);
var filename = walletName + '-' + timestamp + '-keybackup.json.aes';
var blob = new Blob([ew], {
type: 'text/plain;charset=utf-8'
});
// show a native save dialog if we are in the shell
// and pass the wallet to the shell to convert to node Buffer
if (window.cshell) {
return window.cshell.send('backup:download', {
name: walletName,
wallet: ew
});
}
// otherwise lean on the browser implementation
saveAs(blob, filename);
};
BackupService.prototype.sendEmail = function(email, wallet) {
var ew = wallet.toEncryptedObj();
var body = ew;
var subject = this.getName(wallet);
var href = 'mailto:' + email + '?' + 'subject=[Copay Backup] ' + subject + '&' + 'body=' + body;
if (window.cshell) {
return window.cshell.send('backup:email', href);
}
var newWin = window.open(href, '_blank', 'scrollbars=yes,resizable=yes,width=10,height=10');
if (newWin) {
setTimeout(function() {
newWin.close();
}, 1000);
}
};
angular.module('copayApp.services').value('backupService', new BackupService());

View File

@ -3,6 +3,7 @@ var FakeWallet = function(){
this.balance=10000;
this.safeBalance=1000;
this.balanceByAddr={'1CjPR7Z5ZSyWk6WtXvSFgkptmpoi4UM9BC': 1000};
this.name = 'myTESTwullet';
};
FakeWallet.prototype.set = function(balance, safeBalance, balanceByAddr){
@ -28,6 +29,11 @@ FakeWallet.prototype.getBalance=function(cb){
return cb(null, this.balance, this.balanceByAddr, this.safeBalance);
};
FakeWallet.prototype.toEncryptedObj = function() {
return 'SUPERENCRYPTEDSICRITSTUFF';
};
// This mock is meant for karma, module.exports is not necesary.
try {
module.exports = require('soop')(FakeWallet);

View File

@ -87,3 +87,24 @@ describe("Unit: controllerUtils", function() {
});
describe("Unit: Backup Service", function() {
var sinon = require('../sinon');
beforeEach(angular.mock.module('copayApp.services'));
it('should contain a backup service', inject(function(backupService) {
expect(backupService).not.to.equal(null);
}));
it('should backup in file', inject(function(backupService) {
var mock = sinon.mock(window);
var expectation = mock.expects('saveAs');
backupService.download(new FakeWallet());
expectation.once();
}));
it('should backup by email', inject(function(backupService) {
var mock = sinon.mock(window);
var expectation = mock.expects('open');
backupService.sendEmail('fake@test.com', new FakeWallet());
expectation.once();
}));
});

View File

@ -80,6 +80,11 @@ var createBundle = function(opts) {
expose: '../js/models/core/Passphrase'
});
if (opts.dontminify) {
b.require('sinon', {
expose: '../sinon'
});
}
if (!opts.dontminify) {
b.transform({
global: true