switch between wallets in profile working

This commit is contained in:
Matias Alejo Garcia 2014-10-05 15:59:41 -03:00
commit ac491d10b0
19 changed files with 293 additions and 179 deletions

54
js/controllers/create.js Normal file
View file

@ -0,0 +1,54 @@
'use strict';
angular.module('copayApp.controllers').controller('CreateController',
function($scope, $rootScope, $location, $timeout, controllerUtils, backupService, notification) {
$rootScope.fromSetup = true;
$scope.loading = false;
$scope.walletPassword = $rootScope.walletPassword;
$scope.isMobile = !!window.cordova;
$scope.hideAdv = true;
$scope.networkName = config.networkName;
// ng-repeat defined number of times instead of repeating over array?
$scope.getNumber = function(num) {
return new Array(num);
}
$scope.totalCopayers = config.wallet.totalCopayers;
$scope.TCValues = _.range(1, config.limits.totalCopayers + 1);
var updateRCSelect = function(n) {
var maxReq = copay.Wallet.getMaxRequiredCopayers(n);
$scope.RCValues = _.range(1, maxReq + 1);
$scope.requiredCopayers = Math.min(parseInt(n / 2 + 1), maxReq);
};
updateRCSelect($scope.totalCopayers);
$scope.$watch('totalCopayers', function(tc) {
updateRCSelect(tc);
});
$scope.create = function(form) {
if (form && form.$invalid) {
notification.error('Error', 'Please enter the required fields');
return;
}
$scope.loading = true;
var opts = {
requiredCopayers: $scope.requiredCopayers,
totalCopayers: $scope.totalCopayers,
name: $scope.walletName,
privateKeyHex: $scope.private,
networkName: $scope.networkName,
};
$rootScope.iden.createWallet(opts, function(err, w) {
$rootScope.iden.closeWallet($rootScope.wallet.id, function() {
$scope.loading = false;
$rootScope.wallet = w;
controllerUtils.bindWallet(w, $scope);
});
});
};
});

View file

@ -13,10 +13,8 @@ angular.module('copayApp.controllers').controller('CreateProfileController', fun
walletDefaults: config.wallet,
passphrase: config.passphrase,
}, function(err, iden ,w) {
$scope.loading = false;
$rootScope.iden = iden;
$rootScope.wallet = w;
controllerUtils.bindWallet(w, $scope);
});
}

View file

@ -18,7 +18,6 @@ angular.module('copayApp.controllers').controller('HomeController', function($sc
controllerUtils.onErrorDigest(
$scope, (err.toString()||'').match('PNOTFOUND') ? 'Profile not found' : 'Unknown error');
} else {
$scope.loading = false;
$rootScope.iden = iden;
$rootScope.wallet = w;
controllerUtils.bindWallet(w, $scope);

View file

@ -1,8 +1,7 @@
'use strict';
angular.module('copayApp.controllers').controller('JoinController',
function($scope, $rootScope, $timeout, identity, controllerUtils, Passphrase, notification) {
controllerUtils.redirIfLogged();
function($scope, $rootScope, $timeout, controllerUtils, notification) {
$rootScope.fromSetup = false;
$scope.loading = false;
$scope.isMobile = !!window.cordova;
@ -120,31 +119,32 @@ angular.module('copayApp.controllers').controller('JoinController',
$scope.loading = true;
Passphrase.getBase64Async($scope.joinPassword, function(passphrase) {
identity.joinCreateSession({
secret: $scope.connectionId,
nickname: $scope.nickname,
passphrase: passphrase,
privateHex: $scope.private,
}, function(err, w) {
$rootScope.iden.joinWallet({
secret: $scope.connectionId,
nickname: $scope.nickname,
privateHex: $scope.private,
}, function(err, w) {
$scope.loading = false;
if (err || !w) {
if (err === 'joinError')
notification.error('Fatal error connecting to Insight server');
else if (err === 'walletFull')
notification.error('The wallet is full');
else if (err === 'badNetwork')
notification.error('Network Error', 'Wallet network configuration missmatch');
else if (err === 'badSecret')
notification.error('Bad secret', 'The secret string you entered is invalid');
else
notification.error('Unknown error');
controllerUtils.onErrorDigest();
} else {
controllerUtils.startNetwork(w, $scope);
}
});
$scope.loading = false;
if (err || !w) {
if (err === 'joinError')
notification.error('Fatal error connecting to Insight server');
else if (err === 'walletFull')
notification.error('The wallet is full');
else if (err === 'badNetwork')
notification.error('Network Error', 'Wallet network configuration missmatch');
else if (err === 'badSecret')
notification.error('Bad secret', 'The secret string you entered is invalid');
else
notification.error('Unknown error');
controllerUtils.onErrorDigest();
} else {
$rootScope.iden.closeWallet($rootScope.wallet.id, function() {
$scope.loading = false;
$rootScope.wallet = w;
controllerUtils.bindWallet(w, $scope);
});
}
});
}
});

View file

@ -1,7 +1,7 @@
'use strict';
angular.module('copayApp.controllers').controller('MoreController',
function($scope, $rootScope, $location, $filter, backupService, identity, controllerUtils, notification, rateService) {
function($scope, $rootScope, $location, $filter, backupService, controllerUtils, notification, rateService) {
var w = $rootScope.wallet;
$scope.isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0;
@ -81,7 +81,7 @@ angular.module('copayApp.controllers').controller('MoreController',
};
$scope.deleteWallet = function() {
identity.delete(w.id, function() {
$rootScope.iden.deleteWallet(w.id, function() {
controllerUtils.logout();
});
};

View file

@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.controllers').controller('OpenController', function($scope, $rootScope, $location, identity, controllerUtils, Passphrase, notification) {
angular.module('copayApp.controllers').controller('OpenController', function($scope, $rootScope, $location, controllerUtils, Passphrase, notification) {
controllerUtils.redirIfLogged();
if ($rootScope.pendingPayment) {

View file

@ -58,9 +58,9 @@ angular.module('copayApp.controllers').controller('SidebarController', function(
}
if ($rootScope.wallet) {
$scope.$on('$idleWarn', function(a,countdown) {
if (!(countdown%5))
notification.warning('Session will be closed', $filter('translate')('Your session is about to expire due to inactivity in') + ' ' + countdown + ' ' + $filter('translate')('seconds'));
$scope.$on('$idleWarn', function(a, countdown) {
if (!(countdown % 5))
notification.warning('Session will be closed', $filter('translate')('Your session is about to expire due to inactivity in') + ' ' + countdown + ' ' + $filter('translate')('seconds'));
});
$scope.$on('$idleTimeout', function() {
@ -71,4 +71,21 @@ angular.module('copayApp.controllers').controller('SidebarController', function(
$rootScope.wallet.keepAlive();
});
}
$scope.switchWallet = function(id) {
var iden = $rootScope.iden;
controllerUtils.unbindWallet($scope);
iden.openWallet(id, null, function(err, w) {
if (err) {
notification.warning('Could not open wallet');
} else {
iden.closeWallet($rootScope.wallet.id, function() {
$scope.loading = false;
$rootScope.wallet = w;
controllerUtils.bindWallet(w, $scope);
});
}
});
};
});

View file

@ -111,14 +111,13 @@ angular.module('copayApp.directives')
};
}
])
.directive('walletSecret', ['walletFactory',
function(walletFactory) {
.directive('walletSecret', function() {
return {
require: 'ngModel',
link: function(scope, elem, attrs, ctrl) {
var validator = function(value) {
var a = new Address(value);
ctrl.$setValidity('walletSecret', !a.isValid() && Boolean(walletFactory.decodeSecret(value)));
ctrl.$setValidity('walletSecret', !a.isValid() && Boolean(copay.Wallet.decodeSecret(value)));
return value;
};
@ -126,7 +125,7 @@ angular.module('copayApp.directives')
}
};
}
])
)
.directive('loading', function() {
return {
restrict: 'A',

View file

@ -94,8 +94,8 @@ Identity._walletRead = function(id, s, n, b, skip, cb) {
return Wallet.read(id, s, n, b, skip, cb);
};
Identity._walletDelete = function(id, cb) {
return Wallet.delete(id, cb);
Identity._walletDelete = function(id, s, cb) {
return Wallet.delete(id, s, cb);
};
/* for stubbing */
@ -133,6 +133,7 @@ Identity.create = function(email, password, opts, cb) {
requiredCopayers: 1,
totalCopayers: 1,
password: password,
name: 'general',
});
iden.createWallet(wopts, function(err, w) {
return cb(null, iden, w);
@ -170,10 +171,22 @@ Identity.open = function(email, password, opts, cb) {
Identity._openProfile(email, password, iden.storage, function(err, profile) {
if (err) return cb(err);
iden.profile = profile;
var wid = iden.listWallets()[0].id;
iden.openWallet(wid, password, function(err, w) {
return cb(err, iden, w);
})
var wids = _.pluck(iden.listWallets(), 'id');
while (1) {
var wid = wids.shift();
if (!wid)
return new Error('Could not open any wallet from profile');
iden.openWallet(wid, password, function(err, w) {
if (err)
log.info('Cound not open wallet id:' + wid + '. Skipping')
else
return cb(err, iden, w);
})
}
});
};
@ -222,6 +235,16 @@ Identity.prototype.store = function(opts, cb) {
};
Identity.prototype._cleanUp = function() {
log.info('Cleaning Network connections')
var self = this;
_.each(['livenet', 'testnet'], function(n) {
self.networks[n].cleanUp();
self.blockchains[n].destroy();
});
};
/**
* @desc Closes the wallet and disconnects all services
*/
@ -234,12 +257,17 @@ Identity.prototype.close = function(cb) {
return cb ? cb() : null;
}
var self = this;
_.each(this.openWallets, function(w) {
w.close(function(err) {
console.log('[Identity.js.239:err:]', err); //TODO
if (err) return cb(err);
if (++i == l && cb)
return cb();
console.log('[Identity.js.241]', i, l); //TODO
if (++i == l) {
self._cleanUp();
if (cb) return cb();
}
})
});
};
@ -268,6 +296,22 @@ Identity.prototype.importWallet = function(base64, password, skipFields, cb) {
w.store(cb);
});
};
Identity.prototype.closeWallet = function(wid, cb) {
var w = _.findWhere(this.openWallets, function(w) {
w.id === wid;
});
preconditions.checkState(w);
var self = this;
w.close(function(err) {
self.openWallets = _.without(self.openWallets, function(id) {
id === wid
});
return cb(err);
});
};
/**
* @desc This method prepares options for a new Wallet
*
@ -345,13 +389,15 @@ Identity.prototype.createWallet = function(opts, cb) {
var w = Identity._newWallet(opts);
this.addWallet(w, function(err) {
if (err) return cb(err);
self.openWallets.push(w);
self.profile.setLastOpenedTs(w.id, function(err) {
return cb(err, w);
});
});
};
// add open wallet?
// add wallet (import)
Identity.prototype.addWallet = function(wallet, cb) {
preconditions.checkArgument(wallet);
preconditions.checkArgument(wallet.getId);
@ -359,10 +405,11 @@ Identity.prototype.addWallet = function(wallet, cb) {
preconditions.checkState(this.profile);
var self = this;
self.profile.addWallet(wallet.id, {}, function(err) {
self.profile.addWallet(wallet.getId(), {
name: wallet.name
}, function(err) {
if (err) return cb(err);
self.openWallets.push(wallet);
wallet.store(function(err) {
return cb(err);
});
@ -400,15 +447,19 @@ Identity.prototype._checkVersion = function(inVersion) {
* @return
*/
Identity.prototype.openWallet = function(walletId, password, cb) {
console.log('[Identity.js.434:openWallet:]', walletId); //TODO
preconditions.checkArgument(cb);
var self = this;
self.storage.setPassword(password);
if (password)
self.storage.setPassword(password);
// TODO
// self.migrateWallet(walletId, password, function() {
Identity._walletRead(walletId, self.storage, self.networks, self.blockchains, [], function(err, w) {
if (err) return cb(err);
self.openWallets.push(w);
w.store(function(err) {
self.profile.setLastOpenedTs(walletId, function() {
@ -421,7 +472,8 @@ Identity.prototype.openWallet = function(walletId, password, cb) {
Identity.prototype.listWallets = function(a) {
return this.profile.listWallets();
var ret = this.profile.listWallets();
return ret;
};
/**
@ -468,7 +520,6 @@ Identity.prototype.decodeSecret = function(secret) {
*
* @param {object} opts
* @param {string} opts.secret - the wallet secret
* @param {string} opts.password - a password to use to encrypt the wallet for persistance
* @param {string} opts.nickname - a nickname for the current user
* @param {string} opts.privateHex - the private extended master key
* @param {walletCreationCallback} cb - a callback
@ -476,8 +527,6 @@ Identity.prototype.decodeSecret = function(secret) {
Identity.prototype.joinWallet = function(opts, cb) {
preconditions.checkArgument(opts);
preconditions.checkArgument(opts.secret);
preconditions.checkArgument(opts.password);
preconditions.checkArgument(opts.nickname);
preconditions.checkArgument(cb);
var self = this;
var decodedSecret = this.decodeSecret(opts.secret);
@ -534,8 +583,10 @@ Identity.prototype.joinWallet = function(opts, cb) {
walletOpts.id = data.walletId;
walletOpts.privateKey = privateKey;
walletOpts.nickname = opts.nickname;
walletOpts.password = opts.password;
walletOpts.nickname = opts.nickname || self.profile.name;
if (opts.password)
walletOpts.password = opts.password;
self.createWallet(walletOpts, function(err, w) {

View file

@ -12,7 +12,7 @@ function Profile(info, storage) {
this.hash = info.hash;
this.email = info.email;
this.extra = info.extra;
this.extra = info.extra || {};
this.walletInfos = info.walletInfos || {};
this.key = Profile.key(this.hash);
@ -69,7 +69,7 @@ Profile.prototype.getWallet = function(walletId, cb) {
Profile.prototype.listWallets = function(opts, cb) {
return _.sortBy(this.walletInfos, function(winfo) {
return winfo.lastOpenedTs || winfo.createdTs;
return -winfo.lastOpenedTs || -winfo.createdTs;
});
};
@ -141,4 +141,9 @@ Profile.prototype.store = function(opts, cb) {
});
};
Profile.prototype.getName = function() {
return this.extra.nickname || this.email;
};
module.exports = Profile;

View file

@ -183,12 +183,13 @@ Storage.prototype.delete = function(key, cb) {
};
Storage.prototype.deletePrefix = function(prefix, cb) {
storage.getFirst(prefix, function(err, v, k) {
if (err && !v) return cb(err);
var self = this;
this.getFirst(prefix, function(err, v, k) {
if (err || !v) return cb(err);
storage.delete(k, function(err) {
self.delete(k, function(err) {
if (err) return cb(err);
storage.deletePrefix(prefix, cb);
self.deletePrefix(prefix, cb);
})
});
};

View file

@ -241,6 +241,7 @@ Wallet.read = function(walletId, storage, network, blockchain, skipFields, cb) {
var w, err;
obj.id = walletId;
try {
log.debug('## OPENING Wallet: ' + walletId);
w = self.fromObj(obj, storage, network, blockchain, skipFields);
} catch (e) {
log.debug("ERROR: ", e.message);
@ -892,6 +893,7 @@ Wallet.prototype.netStart = function() {
self.emit('connectionError');
});
log.debug('Starting wallet networking');
net.start(startOpts, function() {
self._setBlockchainListeners();
self.emit('ready', net.getPeer());
@ -2536,10 +2538,8 @@ Wallet.prototype.indexDiscovery = function(start, change, copayerIndex, gap, cb)
*/
Wallet.prototype.close = function(cb) {
var self = this;
log.debug('## CLOSING Wallet');
log.debug('## CLOSING Wallet: ' + this.id);
this.lock.release(function() {
self.network.cleanUp();
self.blockchain.destroy();
if (cb) return cb();
});
};

View file

@ -20,7 +20,7 @@ angular
})
.when('/join', {
templateUrl: 'views/join.html',
validate: false
validate: true
})
.when('/import', {
templateUrl: 'views/import.html',

View file

@ -154,13 +154,18 @@ angular.module('copayApp.services')
});
};
root.unbindWallet = function($scope) {
var w =$rootScope.wallet;
w.removeAllListeners();
};
root.bindWallet = function(w, $scope) {
root.setupRootVariables();
root.installWalletHandlers(w, $scope);
root.updateAddressList();
notification.enableHtml5Mode(); // for chrome: if support, enable it
w.netStart();
};
// TODO movie this to wallet