Merge pull request #1101 from matiu/feature/ts-session
Feature/ts session
This commit is contained in:
commit
acf2deb87a
17 changed files with 378 additions and 260 deletions
85
config.js
85
config.js
|
|
@ -19,11 +19,11 @@ var defaultConfig = {
|
||||||
// Use this to run your own local PeerJS server
|
// Use this to run your own local PeerJS server
|
||||||
// with params: ./peerjs -p 10009 -k '6d6d751ea61e26f2'
|
// with params: ./peerjs -p 10009 -k '6d6d751ea61e26f2'
|
||||||
/*
|
/*
|
||||||
key: '6d6d751ea61e26f2',
|
key: '6d6d751ea61e26f2',
|
||||||
host: 'localhost',
|
host: 'localhost',
|
||||||
port: 10009,
|
port: 10009,
|
||||||
path: '/',
|
path: '/',
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Use this to connect to bitpay's PeerJS server
|
// Use this to connect to bitpay's PeerJS server
|
||||||
key: 'satoshirocks',
|
key: 'satoshirocks',
|
||||||
|
|
@ -39,52 +39,44 @@ var defaultConfig = {
|
||||||
maxPeers: 15,
|
maxPeers: 15,
|
||||||
debug: 2,
|
debug: 2,
|
||||||
|
|
||||||
// Network encryption config
|
|
||||||
sjclParams: {
|
|
||||||
salt: 'mjuBtGybi/4=', // choose your own salt (base64)
|
|
||||||
iter: 1000,
|
|
||||||
mode: 'ccm',
|
|
||||||
ts: parseInt(64),
|
|
||||||
},
|
|
||||||
|
|
||||||
// PeerJS internal config object
|
// PeerJS internal config object
|
||||||
config: {
|
config: {
|
||||||
'iceServers': [
|
'iceServers': [
|
||||||
// Pass in STUN and TURN servers for maximum network compatibility
|
// Pass in STUN and TURN servers for maximum network compatibility
|
||||||
{
|
{
|
||||||
url: 'stun:162.242.219.26'
|
url: 'stun:162.242.219.26'
|
||||||
}, {
|
}, {
|
||||||
url: 'turn:162.242.219.26',
|
url: 'turn:162.242.219.26',
|
||||||
username: 'bitcore',
|
username: 'bitcore',
|
||||||
credential: 'bitcore',
|
credential: 'bitcore',
|
||||||
}
|
}
|
||||||
// {
|
// {
|
||||||
// url: 'stun:stun.l.google.com:19302'
|
// url: 'stun:stun.l.google.com:19302'
|
||||||
// }, {
|
// }, {
|
||||||
// url: 'stun:stun1.l.google.com:19302'
|
// url: 'stun:stun1.l.google.com:19302'
|
||||||
// }, {
|
// }, {
|
||||||
// url: 'stun:stun2.l.google.com:19302'
|
// url: 'stun:stun2.l.google.com:19302'
|
||||||
// }, {
|
// }, {
|
||||||
// url: 'stun:stun3.l.google.com:19302'
|
// url: 'stun:stun3.l.google.com:19302'
|
||||||
// }, {
|
// }, {
|
||||||
// url: 'stun:stun4.l.google.com:19302'
|
// url: 'stun:stun4.l.google.com:19302'
|
||||||
// }, {
|
// }, {
|
||||||
// url: 'stun:stunserver.org'
|
// url: 'stun:stunserver.org'
|
||||||
// }
|
// }
|
||||||
// // Options fot TURN servers with p2p communications are not possible.
|
// // Options fot TURN servers with p2p communications are not possible.
|
||||||
// {
|
// {
|
||||||
// url: 'turn:numb.viagenie.ca',
|
// url: 'turn:numb.viagenie.ca',
|
||||||
// credential: 'muazkh',
|
// credential: 'muazkh',
|
||||||
// username: 'webrtc@live.com'
|
// username: 'webrtc@live.com'
|
||||||
// }, {
|
// }, {
|
||||||
// url: 'turn:192.158.29.39:3478?transport=udp',
|
// url: 'turn:192.158.29.39:3478?transport=udp',
|
||||||
// credential: 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
|
// credential: 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
|
||||||
// username: '28224511:1379330808'
|
// username: '28224511:1379330808'
|
||||||
// }, {
|
// }, {
|
||||||
// url: 'turn:192.158.29.39:3478?transport=tcp',
|
// url: 'turn:192.158.29.39:3478?transport=tcp',
|
||||||
// credential: 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
|
// credential: 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
|
||||||
// username: '28224511:1379330808'
|
// username: '28224511:1379330808'
|
||||||
// }
|
// }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -97,6 +89,7 @@ var defaultConfig = {
|
||||||
verbose: 1,
|
verbose: 1,
|
||||||
// will duplicate itself after each try
|
// will duplicate itself after each try
|
||||||
reconnectDelay: 5000,
|
reconnectDelay: 5000,
|
||||||
|
idleDurationMin: 4
|
||||||
},
|
},
|
||||||
|
|
||||||
// blockchain service API config
|
// blockchain service API config
|
||||||
|
|
|
||||||
1
copay.js
1
copay.js
|
|
@ -15,6 +15,7 @@ var StorageLocalEncrypted = module.exports.StorageLocalEncrypted = require('./js
|
||||||
|
|
||||||
module.exports.WalletFactory = require('./js/models/core/WalletFactory');
|
module.exports.WalletFactory = require('./js/models/core/WalletFactory');
|
||||||
module.exports.Wallet = require('./js/models/core/Wallet');
|
module.exports.Wallet = require('./js/models/core/Wallet');
|
||||||
|
module.exports.WalletLock = require('./js/models/core/WalletLock');
|
||||||
module.exports.version = require('./version');
|
module.exports.version = require('./version');
|
||||||
|
|
||||||
// test hack :s, will fix
|
// test hack :s, will fix
|
||||||
|
|
|
||||||
|
|
@ -1,47 +1,48 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('copayApp.controllers').controller('OpenController',
|
angular.module('copayApp.controllers').controller('OpenController', function($scope, $rootScope, $location, walletFactory, controllerUtils, Passphrase, notification) {
|
||||||
function($scope, $rootScope, $location, walletFactory, controllerUtils, Passphrase, notification) {
|
controllerUtils.redirIfLogged();
|
||||||
controllerUtils.redirIfLogged();
|
|
||||||
|
|
||||||
var cmp = function(o1, o2) {
|
var cmp = function(o1, o2) {
|
||||||
var v1 = o1.show.toLowerCase(),
|
var v1 = o1.show.toLowerCase(),
|
||||||
v2 = o2.show.toLowerCase();
|
v2 = o2.show.toLowerCase();
|
||||||
return v1 > v2 ? 1 : (v1 < v2) ? -1 : 0;
|
return v1 > v2 ? 1 : (v1 < v2) ? -1 : 0;
|
||||||
};
|
};
|
||||||
$rootScope.fromSetup = false;
|
$rootScope.fromSetup = false;
|
||||||
$scope.loading = false;
|
$scope.loading = false;
|
||||||
$scope.wallets = walletFactory.getWallets().sort(cmp);
|
$scope.wallets = walletFactory.getWallets().sort(cmp);
|
||||||
$scope.selectedWalletId = walletFactory.storage.getLastOpened() || ($scope.wallets[0] && $scope.wallets[0].id);
|
$scope.selectedWalletId = walletFactory.storage.getLastOpened() || ($scope.wallets[0] && $scope.wallets[0].id);
|
||||||
$scope.openPassword = '';
|
$scope.openPassword = '';
|
||||||
$scope.isMobile = !!window.cordova;
|
$scope.isMobile = !!window.cordova;
|
||||||
|
|
||||||
$scope.open = function(form) {
|
if (!$scope.wallets.length){
|
||||||
if (form && form.$invalid) {
|
$location.path('/');
|
||||||
notification.error('Error', 'Please enter the required fields');
|
}
|
||||||
|
|
||||||
|
$scope.open = function(form) {
|
||||||
|
if (form && form.$invalid) {
|
||||||
|
notification.error('Error', 'Please enter the required fields');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.loading = true;
|
||||||
|
var password = form.openPassword.$modelValue;
|
||||||
|
|
||||||
|
Passphrase.getBase64Async(password, function(passphrase) {
|
||||||
|
var w, errMsg;
|
||||||
|
try {
|
||||||
|
w = walletFactory.open($scope.selectedWalletId, passphrase);
|
||||||
|
} catch (e) {
|
||||||
|
errMsg = e.message;
|
||||||
|
};
|
||||||
|
if (!w) {
|
||||||
|
$scope.loading = false;
|
||||||
|
notification.error('Error', errMsg || 'Wrong password');
|
||||||
|
$rootScope.$digest();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
controllerUtils.startNetwork(w, $scope);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
$scope.loading = true;
|
});
|
||||||
var password = form.openPassword.$modelValue;
|
|
||||||
|
|
||||||
Passphrase.getBase64Async(password, function(passphrase) {
|
|
||||||
var w, errMsg;
|
|
||||||
try {
|
|
||||||
w = walletFactory.open($scope.selectedWalletId, {
|
|
||||||
passphrase: passphrase
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
errMsg = e.message;
|
|
||||||
};
|
|
||||||
if (!w) {
|
|
||||||
$scope.loading = false;
|
|
||||||
notification.error('Error', errMsg || 'Wrong password');
|
|
||||||
$rootScope.$digest();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
controllerUtils.startNetwork(w, $scope);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ angular.module('copayApp.controllers').controller('SendController',
|
||||||
$scope.address = pp.address;
|
$scope.address = pp.address;
|
||||||
var amount = pp.amount / config.unitToSatoshi * 100000000;
|
var amount = pp.amount / config.unitToSatoshi * 100000000;
|
||||||
$scope.amount = amount;
|
$scope.amount = amount;
|
||||||
|
$scope.commentText = pp.message;
|
||||||
}
|
}
|
||||||
|
|
||||||
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
|
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
|
||||||
|
|
|
||||||
|
|
@ -65,13 +65,17 @@ angular.module('copayApp.controllers').controller('SidebarController', function(
|
||||||
controllerUtils.setSocketHandlers();
|
controllerUtils.setSocketHandlers();
|
||||||
|
|
||||||
if ($rootScope.wallet) {
|
if ($rootScope.wallet) {
|
||||||
$scope.$on('$idleStart', function(a) {
|
$scope.$on('$idleWarn', function(a,countdown) {
|
||||||
notification.warning('Session will be closed', 'Your session is about to expire due to inactivity');
|
if (!(countdown%5))
|
||||||
|
notification.warning('Session will be closed', 'Your session is about to expire due to inactivity in ' + countdown + ' seconds');
|
||||||
});
|
});
|
||||||
|
|
||||||
$scope.$on('$idleTimeout', function() {
|
$scope.$on('$idleTimeout', function() {
|
||||||
$scope.signout();
|
$scope.signout();
|
||||||
notification.warning('Session closed', 'Session closed because a long time of inactivity');
|
notification.warning('Session closed', 'Session closed because a long time of inactivity');
|
||||||
});
|
});
|
||||||
|
$scope.$on('$keepalive', function() {
|
||||||
|
$rootScope.wallet.keepAlive();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@
|
||||||
|
|
||||||
var http = require('http');
|
var http = require('http');
|
||||||
var EventEmitter = require('events').EventEmitter;
|
var EventEmitter = require('events').EventEmitter;
|
||||||
var nodeUtil = require('util');
|
|
||||||
var async = require('async');
|
var async = require('async');
|
||||||
var preconditions = require('preconditions').singleton();
|
var preconditions = require('preconditions').singleton();
|
||||||
var parseBitcoinURI = require('./HDPath').parseBitcoinURI;
|
var parseBitcoinURI = require('./HDPath').parseBitcoinURI;
|
||||||
|
var util = require('util');
|
||||||
|
|
||||||
var bitcore = require('bitcore');
|
var bitcore = require('bitcore');
|
||||||
var bignum = bitcore.Bignum;
|
var bignum = bitcore.Bignum;
|
||||||
|
|
@ -23,6 +23,7 @@ var PublicKeyRing = require('./PublicKeyRing');
|
||||||
var TxProposal = require('./TxProposal');
|
var TxProposal = require('./TxProposal');
|
||||||
var TxProposals = require('./TxProposals');
|
var TxProposals = require('./TxProposals');
|
||||||
var PrivateKey = require('./PrivateKey');
|
var PrivateKey = require('./PrivateKey');
|
||||||
|
var WalletLock = require('./WalletLock');
|
||||||
var copayConfig = require('../../../config');
|
var copayConfig = require('../../../config');
|
||||||
|
|
||||||
function Wallet(opts) {
|
function Wallet(opts) {
|
||||||
|
|
@ -45,9 +46,11 @@ function Wallet(opts) {
|
||||||
this.log('creating ' + opts.requiredCopayers + ' of ' + opts.totalCopayers + ' wallet');
|
this.log('creating ' + opts.requiredCopayers + ' of ' + opts.totalCopayers + ' wallet');
|
||||||
|
|
||||||
this.id = opts.id || Wallet.getRandomId();
|
this.id = opts.id || Wallet.getRandomId();
|
||||||
|
this.lock = new WalletLock(this.storage, this.id, opts.lockTimeOutMin);
|
||||||
|
|
||||||
|
|
||||||
this.name = opts.name;
|
this.name = opts.name;
|
||||||
|
|
||||||
this.ignoreLock = opts.ignoreLock;
|
|
||||||
this.verbose = opts.verbose;
|
this.verbose = opts.verbose;
|
||||||
this.publicKeyRing.walletId = this.id;
|
this.publicKeyRing.walletId = this.id;
|
||||||
this.txProposals.walletId = this.id;
|
this.txProposals.walletId = this.id;
|
||||||
|
|
@ -64,7 +67,7 @@ function Wallet(opts) {
|
||||||
this.network.setHexNonces(opts.networkNonces);
|
this.network.setHexNonces(opts.networkNonces);
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeUtil.inherits(Wallet, EventEmitter);
|
util.inherits(Wallet, EventEmitter);
|
||||||
|
|
||||||
Wallet.builderOpts = {
|
Wallet.builderOpts = {
|
||||||
lockTime: null,
|
lockTime: null,
|
||||||
|
|
@ -98,27 +101,6 @@ Wallet.prototype.connectToAll = function() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Wallet.prototype.getLock = function() {
|
|
||||||
return this.storage.getLock(this.id);
|
|
||||||
};
|
|
||||||
|
|
||||||
Wallet.prototype.setLock = function() {
|
|
||||||
return this.storage.setLock(this.id);
|
|
||||||
};
|
|
||||||
|
|
||||||
Wallet.prototype.unlock = function() {
|
|
||||||
this.storage.removeLock(this.id);
|
|
||||||
};
|
|
||||||
|
|
||||||
Wallet.prototype.checkAndLock = function() {
|
|
||||||
if (this.getLock()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setLock();
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
Wallet.prototype._handleIndexes = function(senderId, data, isInbound) {
|
Wallet.prototype._handleIndexes = function(senderId, data, isInbound) {
|
||||||
this.log('RECV INDEXES:', data);
|
this.log('RECV INDEXES:', data);
|
||||||
var inIndexes = HDParams.fromList(data.indexes);
|
var inIndexes = HDParams.fromList(data.indexes);
|
||||||
|
|
@ -438,11 +420,6 @@ Wallet.prototype.netStart = function(callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var net = this.network;
|
var net = this.network;
|
||||||
|
|
||||||
if (this.checkAndLock() && !this.ignoreLock) {
|
|
||||||
this.emit('locked');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
net.removeAllListeners();
|
net.removeAllListeners();
|
||||||
net.on('connect', self._handleConnect.bind(self));
|
net.on('connect', self._handleConnect.bind(self));
|
||||||
net.on('disconnect', self._handleDisconnect.bind(self));
|
net.on('disconnect', self._handleDisconnect.bind(self));
|
||||||
|
|
@ -519,7 +496,18 @@ Wallet.prototype.getRegisteredPeerIds = function() {
|
||||||
return this.registeredPeerIds;
|
return this.registeredPeerIds;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Wallet.prototype.keepAlive = function() {
|
||||||
|
try{
|
||||||
|
this.lock.keepAlive();
|
||||||
|
} catch(e){
|
||||||
|
this.log(e);
|
||||||
|
this.emit('locked',null,'Wallet appears to be openned on other browser instance. Closing this one.' );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Wallet.prototype.store = function() {
|
Wallet.prototype.store = function() {
|
||||||
|
this.keepAlive();
|
||||||
|
|
||||||
var wallet = this.toObj();
|
var wallet = this.toObj();
|
||||||
this.storage.setFromObj(this.id, wallet);
|
this.storage.setFromObj(this.id, wallet);
|
||||||
this.log('Wallet stored');
|
this.log('Wallet stored');
|
||||||
|
|
@ -556,8 +544,8 @@ Wallet.fromObj = function(o, storage, network, blockchain) {
|
||||||
opts.storage = storage;
|
opts.storage = storage;
|
||||||
opts.network = network;
|
opts.network = network;
|
||||||
opts.blockchain = blockchain;
|
opts.blockchain = blockchain;
|
||||||
var w = new Wallet(opts);
|
|
||||||
return w;
|
return new Wallet(opts);
|
||||||
};
|
};
|
||||||
|
|
||||||
Wallet.prototype.toEncryptedObj = function() {
|
Wallet.prototype.toEncryptedObj = function() {
|
||||||
|
|
@ -709,7 +697,7 @@ Wallet.prototype.sign = function(ntxid, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
var myId = self.getMyCopayerId();
|
var myId = self.getMyCopayerId();
|
||||||
var txp = self.txProposals.get(ntxid);
|
var txp = self.txProposals.get(ntxid);
|
||||||
// if (!txp || txp.rejectedBy[myId] || txp.signedBy[myId]) {
|
// if (!txp || txp.rejectedBy[myId] || txp.signedBy[myId]) {
|
||||||
// if (cb) cb(false);
|
// if (cb) cb(false);
|
||||||
// }
|
// }
|
||||||
|
|
@ -782,7 +770,9 @@ Wallet.prototype.createPaymentTx = function(options, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
if (typeof options === 'string') {
|
if (typeof options === 'string') {
|
||||||
options = { uri: options };
|
options = {
|
||||||
|
uri: options
|
||||||
|
};
|
||||||
}
|
}
|
||||||
options.uri = options.uri || options.url;
|
options.uri = options.uri || options.url;
|
||||||
|
|
||||||
|
|
@ -824,7 +814,9 @@ Wallet.prototype.fetchPaymentTx = function(options, cb) {
|
||||||
|
|
||||||
options = options || {};
|
options = options || {};
|
||||||
if (typeof options === 'string') {
|
if (typeof options === 'string') {
|
||||||
options = { uri: options };
|
options = {
|
||||||
|
uri: options
|
||||||
|
};
|
||||||
}
|
}
|
||||||
options.uri = options.uri || options.url;
|
options.uri = options.uri || options.url;
|
||||||
options.fetch = true;
|
options.fetch = true;
|
||||||
|
|
@ -980,8 +972,7 @@ Wallet.prototype.sendPaymentTx = function(ntxid, options, cb) {
|
||||||
|
|
||||||
var refund_outputs = [];
|
var refund_outputs = [];
|
||||||
|
|
||||||
options.refund_to = options.refund_to
|
options.refund_to = options.refund_to || this.publicKeyRing.getPubKeys(0, false, this.getMyCopayerId())[0];
|
||||||
|| this.publicKeyRing.getPubKeys(0, false, this.getMyCopayerId())[0];
|
|
||||||
|
|
||||||
if (options.refund_to) {
|
if (options.refund_to) {
|
||||||
var total = txp.merchant.pr.pd.outputs.reduce(function(total, _, i) {
|
var total = txp.merchant.pr.pd.outputs.reduce(function(total, _, i) {
|
||||||
|
|
@ -1003,23 +994,23 @@ Wallet.prototype.sendPaymentTx = function(ntxid, options, cb) {
|
||||||
rpo.set('amount', +total.toString(10));
|
rpo.set('amount', +total.toString(10));
|
||||||
|
|
||||||
rpo.set('script',
|
rpo.set('script',
|
||||||
Buffer.concat([
|
Buffer.concat([
|
||||||
new Buffer([
|
new Buffer([
|
||||||
118, // OP_DUP
|
118, // OP_DUP
|
||||||
169, // OP_HASH160
|
169, // OP_HASH160
|
||||||
76, // OP_PUSHDATA1
|
76, // OP_PUSHDATA1
|
||||||
20, // number of bytes
|
20, // number of bytes
|
||||||
]),
|
]),
|
||||||
// needs to be ripesha'd
|
// needs to be ripesha'd
|
||||||
bitcore.util.sha256ripe160(options.refund_to),
|
bitcore.util.sha256ripe160(options.refund_to),
|
||||||
new Buffer([
|
new Buffer([
|
||||||
136, // OP_EQUALVERIFY
|
136, // OP_EQUALVERIFY
|
||||||
172 // OP_CHECKSIG
|
172 // OP_CHECKSIG
|
||||||
])
|
])
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
|
|
||||||
refund_outputs.push(rpo.message);
|
refund_outputs.push(rpo.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We send this to the serve after receiving a PaymentRequest
|
// We send this to the serve after receiving a PaymentRequest
|
||||||
|
|
@ -1031,8 +1022,7 @@ Wallet.prototype.sendPaymentTx = function(ntxid, options, cb) {
|
||||||
pay.set('transactions', [tx.serialize()]);
|
pay.set('transactions', [tx.serialize()]);
|
||||||
pay.set('refund_to', refund_outputs);
|
pay.set('refund_to', refund_outputs);
|
||||||
|
|
||||||
options.memo = options.memo || options.comment
|
options.memo = options.memo || options.comment || 'Hi server, I would like to give you some money.';
|
||||||
|| 'Hi server, I would like to give you some money.';
|
|
||||||
|
|
||||||
pay.set('memo', options.memo);
|
pay.set('memo', options.memo);
|
||||||
|
|
||||||
|
|
@ -1188,8 +1178,8 @@ Wallet.prototype.createPaymentTxSync = function(options, merchantData, unspent)
|
||||||
merchantData.total = merchantData.total.toString(10);
|
merchantData.total = merchantData.total.toString(10);
|
||||||
|
|
||||||
var b = new Builder(opts)
|
var b = new Builder(opts)
|
||||||
.setUnspent(unspent)
|
.setUnspent(unspent)
|
||||||
.setOutputs(outs);
|
.setOutputs(outs);
|
||||||
|
|
||||||
merchantData.pr.pd.outputs.forEach(function(output, i) {
|
merchantData.pr.pd.outputs.forEach(function(output, i) {
|
||||||
var script = {
|
var script = {
|
||||||
|
|
@ -1250,9 +1240,7 @@ Wallet.prototype.createPaymentTxSync = function(options, merchantData, unspent)
|
||||||
Wallet.prototype.verifyPaymentRequest = function(ntxid) {
|
Wallet.prototype.verifyPaymentRequest = function(ntxid) {
|
||||||
if (!ntxid) return false;
|
if (!ntxid) return false;
|
||||||
|
|
||||||
var txp = typeof ntxid !== 'object'
|
var txp = typeof ntxid !== 'object' ? this.txProposals.get(ntxid) : ntxid;
|
||||||
? this.txProposals.get(ntxid)
|
|
||||||
: ntxid;
|
|
||||||
|
|
||||||
// If we're not a payment protocol proposal, ignore.
|
// If we're not a payment protocol proposal, ignore.
|
||||||
if (!txp.merchant) return true;
|
if (!txp.merchant) return true;
|
||||||
|
|
@ -1358,8 +1346,7 @@ Wallet.prototype.verifyPaymentRequest = function(ntxid) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure the tx's output script and values match the payment request's.
|
// Make sure the tx's output script and values match the payment request's.
|
||||||
if (av.toString('hex') !== ev.toString('hex')
|
if (av.toString('hex') !== ev.toString('hex') || as.toString('hex') !== es.toString('hex')) {
|
||||||
|| as.toString('hex') !== es.toString('hex')) {
|
|
||||||
// Verifiable outputs do not match outputs of merchant
|
// Verifiable outputs do not match outputs of merchant
|
||||||
// data. We should not sign this transaction proposal!
|
// data. We should not sign this transaction proposal!
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -1384,10 +1371,9 @@ Wallet.prototype.verifyPaymentRequest = function(ntxid) {
|
||||||
|
|
||||||
// Actual script
|
// Actual script
|
||||||
var as = new Buffer(ro.script.buffer, 'hex')
|
var as = new Buffer(ro.script.buffer, 'hex')
|
||||||
.slice(ro.script.offset, ro.script.limit);
|
.slice(ro.script.offset, ro.script.limit);
|
||||||
|
|
||||||
if (av.toString('hex') !== ev.toString('hex')
|
if (av.toString('hex') !== ev.toString('hex') || as.toString('hex') !== es.toString('hex')) {
|
||||||
|| as.toString('hex') !== es.toString('hex')) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1506,14 +1492,19 @@ Wallet.prototype.createTx = function(toAddress, amountSatStr, comment, opts, cb)
|
||||||
if (typeof amountSatStr === 'function') {
|
if (typeof amountSatStr === 'function') {
|
||||||
var cb = amountSatStr;
|
var cb = amountSatStr;
|
||||||
var merchant = toAddress;
|
var merchant = toAddress;
|
||||||
return this.createPaymentTx({ uri: merchant }, cb);
|
return this.createPaymentTx({
|
||||||
|
uri: merchant
|
||||||
|
}, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof comment === 'function') {
|
if (typeof comment === 'function') {
|
||||||
var cb = comment;
|
var cb = comment;
|
||||||
var merchant = toAddress;
|
var merchant = toAddress;
|
||||||
var comment = amountSatStr;
|
var comment = amountSatStr;
|
||||||
return this.createPaymentTx({ uri: merchant, memo: comment }, cb);
|
return this.createPaymentTx({
|
||||||
|
uri: merchant,
|
||||||
|
memo: comment
|
||||||
|
}, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof opts === 'function') {
|
if (typeof opts === 'function') {
|
||||||
|
|
@ -1684,7 +1675,7 @@ Wallet.prototype.indexDiscovery = function(start, change, cosigner, gap, cb) {
|
||||||
|
|
||||||
Wallet.prototype.disconnect = function() {
|
Wallet.prototype.disconnect = function() {
|
||||||
this.log('## DISCONNECTING');
|
this.log('## DISCONNECTING');
|
||||||
this.unlock();
|
this.lock.release();
|
||||||
this.network.disconnect();
|
this.network.disconnect();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1779,7 +1770,9 @@ Wallet.prototype.verifySignedJson = function(senderId, payload, signature) {
|
||||||
|
|
||||||
Wallet.request = function(options, callback) {
|
Wallet.request = function(options, callback) {
|
||||||
if (typeof options === 'string') {
|
if (typeof options === 'string') {
|
||||||
options = { uri: options };
|
options = {
|
||||||
|
uri: options
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
options.method = options.method || 'GET';
|
options.method = options.method || 'GET';
|
||||||
|
|
@ -1794,8 +1787,7 @@ Wallet.request = function(options, callback) {
|
||||||
this._error = cb;
|
this._error = cb;
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
_success: function() {
|
_success: function() {;
|
||||||
;
|
|
||||||
},
|
},
|
||||||
_error: function(_, err) {
|
_error: function(_, err) {
|
||||||
throw err;
|
throw err;
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,7 @@ WalletFactory.prototype.create = function(opts) {
|
||||||
|
|
||||||
var requiredCopayers = opts.requiredCopayers || this.walletDefaults.requiredCopayers;
|
var requiredCopayers = opts.requiredCopayers || this.walletDefaults.requiredCopayers;
|
||||||
var totalCopayers = opts.totalCopayers || this.walletDefaults.totalCopayers;
|
var totalCopayers = opts.totalCopayers || this.walletDefaults.totalCopayers;
|
||||||
|
opts.lockTimeoutMin = this.walletDefaults.idleDurationMin;
|
||||||
|
|
||||||
opts.publicKeyRing = opts.publicKeyRing || new PublicKeyRing({
|
opts.publicKeyRing = opts.publicKeyRing || new PublicKeyRing({
|
||||||
networkName: this.networkName,
|
networkName: this.networkName,
|
||||||
|
|
@ -137,6 +138,7 @@ WalletFactory.prototype.create = function(opts) {
|
||||||
opts.requiredCopayers = requiredCopayers;
|
opts.requiredCopayers = requiredCopayers;
|
||||||
opts.totalCopayers = totalCopayers;
|
opts.totalCopayers = totalCopayers;
|
||||||
opts.version = opts.version || this.version;
|
opts.version = opts.version || this.version;
|
||||||
|
|
||||||
var w = new Wallet(opts);
|
var w = new Wallet(opts);
|
||||||
w.store();
|
w.store();
|
||||||
this.storage.setLastOpened(w.id);
|
this.storage.setLastOpened(w.id);
|
||||||
|
|
@ -166,16 +168,12 @@ WalletFactory.prototype._checkNetwork = function(inNetworkName) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
WalletFactory.prototype.open = function(walletId, opts) {
|
|
||||||
opts = opts || {};
|
|
||||||
opts.id = walletId;
|
|
||||||
opts.verbose = this.verbose;
|
|
||||||
this.storage._setPassphrase(opts.passphrase);
|
|
||||||
|
|
||||||
|
WalletFactory.prototype.open = function(walletId, passphrase) {
|
||||||
|
this.storage._setPassphrase(passphrase);
|
||||||
var w = this.read(walletId);
|
var w = this.read(walletId);
|
||||||
if (w) {
|
if (w)
|
||||||
w.store();
|
w.store();
|
||||||
}
|
|
||||||
|
|
||||||
this.storage.setLastOpened(walletId);
|
this.storage.setLastOpened(walletId);
|
||||||
return w;
|
return w;
|
||||||
|
|
|
||||||
56
js/models/core/WalletLock.js
Normal file
56
js/models/core/WalletLock.js
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var preconditions = require('preconditions').singleton();
|
||||||
|
|
||||||
|
function WalletLock(storage, walletId, timeoutMin) {
|
||||||
|
preconditions.checkArgument(storage);
|
||||||
|
preconditions.checkArgument(walletId);
|
||||||
|
|
||||||
|
this.sessionId = storage.getSessionId();
|
||||||
|
this.storage = storage;
|
||||||
|
this.timeoutMin = timeoutMin || 5;
|
||||||
|
this.key = WalletLock._keyFor(walletId);
|
||||||
|
this._setLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
WalletLock._keyFor = function(walletId) {
|
||||||
|
return 'lock' + '::' + walletId;
|
||||||
|
};
|
||||||
|
|
||||||
|
WalletLock.prototype._isLockedByOther = function() {
|
||||||
|
var json = this.storage.getGlobal(this.key);
|
||||||
|
var wl = json ? JSON.parse(json) : null;
|
||||||
|
var t = wl ? (Date.now() - wl.expireTs) : false;
|
||||||
|
// is not locked?
|
||||||
|
if (!wl || t > 0 || wl.sessionId === this.sessionId)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Seconds remainding
|
||||||
|
return parseInt(-t/1000.);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
WalletLock.prototype._setLock = function() {
|
||||||
|
this.storage.setGlobal(this.key, {
|
||||||
|
sessionId: this.sessionId,
|
||||||
|
expireTs: Date.now() + this.timeoutMin * 60 * 1000,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
WalletLock.prototype.keepAlive = function() {
|
||||||
|
preconditions.checkState(this.sessionId);
|
||||||
|
|
||||||
|
var t = this._isLockedByOther();
|
||||||
|
if (t)
|
||||||
|
throw new Error('Wallet is already open. Close it to proceed or wait '+ t + ' seconds if you close it already' );
|
||||||
|
this._setLock();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
WalletLock.prototype.release = function() {
|
||||||
|
this.storage.removeGlobal(this.key);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = WalletLock;
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var CryptoJS = require('node-cryptojs-aes').CryptoJS;
|
var CryptoJS = require('node-cryptojs-aes').CryptoJS;
|
||||||
|
var bitcore = require('bitcore');
|
||||||
var id = 0;
|
var id = 0;
|
||||||
|
|
||||||
function Storage(opts) {
|
function Storage(opts) {
|
||||||
|
|
@ -11,11 +11,15 @@ function Storage(opts) {
|
||||||
if (opts.password)
|
if (opts.password)
|
||||||
this._setPassphrase(opts.password);
|
this._setPassphrase(opts.password);
|
||||||
|
|
||||||
if (opts.localStorage) {
|
try{
|
||||||
this.localStorage = opts.localStorage;
|
this.localStorage = opts.localStorage || localStorage;
|
||||||
} else if (localStorage) {
|
this.sessionStorage = opts.sessionStorage || sessionStorage;
|
||||||
this.localStorage = localStorage;
|
} catch (e) {};
|
||||||
}
|
|
||||||
|
if (!this.localStorage)
|
||||||
|
throw new Error('no localStorage');
|
||||||
|
if (!this.sessionStorage)
|
||||||
|
throw new Error('no sessionStorage');
|
||||||
}
|
}
|
||||||
|
|
||||||
var pps = {};
|
var pps = {};
|
||||||
|
|
@ -93,6 +97,15 @@ Storage.prototype.removeGlobal = function(k) {
|
||||||
this.localStorage.removeItem(k);
|
this.localStorage.removeItem(k);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Storage.prototype.getSessionId = function() {
|
||||||
|
var sessionId = this.sessionStorage.getItem('sessionId');
|
||||||
|
if (!sessionId) {
|
||||||
|
sessionId = bitcore.SecureRandom.getRandomBuffer(8).toString('hex');
|
||||||
|
this.sessionStorage.setItem('sessionId', sessionId);
|
||||||
|
}
|
||||||
|
return sessionId;
|
||||||
|
};
|
||||||
|
|
||||||
Storage.prototype._key = function(walletId, k) {
|
Storage.prototype._key = function(walletId, k) {
|
||||||
return walletId + '::' + k;
|
return walletId + '::' + k;
|
||||||
};
|
};
|
||||||
|
|
@ -132,7 +145,8 @@ Storage.prototype.getWalletIds = function() {
|
||||||
if (split.length == 2) {
|
if (split.length == 2) {
|
||||||
var walletId = split[0];
|
var walletId = split[0];
|
||||||
|
|
||||||
if (walletId === 'nameFor') continue;
|
if (!walletId || walletId === 'nameFor' || walletId ==='lock')
|
||||||
|
continue;
|
||||||
|
|
||||||
if (typeof uniq[walletId] === 'undefined') {
|
if (typeof uniq[walletId] === 'undefined') {
|
||||||
walletIds.push(walletId);
|
walletIds.push(walletId);
|
||||||
|
|
@ -180,18 +194,6 @@ Storage.prototype.getLastOpened = function() {
|
||||||
return this.getGlobal('lastOpened');
|
return this.getGlobal('lastOpened');
|
||||||
}
|
}
|
||||||
|
|
||||||
Storage.prototype.setLock = function(walletId) {
|
|
||||||
this.setGlobal(this._key(walletId, 'Lock'), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
Storage.prototype.getLock = function(walletId) {
|
|
||||||
return this.getGlobal(this._key(walletId, 'Lock'));
|
|
||||||
}
|
|
||||||
|
|
||||||
Storage.prototype.removeLock = function(walletId) {
|
|
||||||
this.removeGlobal(this._key(walletId, 'Lock'));
|
|
||||||
}
|
|
||||||
|
|
||||||
//obj contains keys to be set
|
//obj contains keys to be set
|
||||||
Storage.prototype.setFromObj = function(walletId, obj) {
|
Storage.prototype.setFromObj = function(walletId, obj) {
|
||||||
for (var k in obj) {
|
for (var k in obj) {
|
||||||
|
|
|
||||||
22
js/routes.js
22
js/routes.js
|
|
@ -69,13 +69,15 @@ angular
|
||||||
//Setting HTML5 Location Mode
|
//Setting HTML5 Location Mode
|
||||||
angular
|
angular
|
||||||
.module('copayApp')
|
.module('copayApp')
|
||||||
.config(function($locationProvider, $idleProvider) {
|
.config(function($locationProvider, $idleProvider, $keepaliveProvider) {
|
||||||
$locationProvider
|
$locationProvider
|
||||||
.html5Mode(false)
|
.html5Mode(false)
|
||||||
.hashPrefix('!');
|
.hashPrefix('!');
|
||||||
// IDLE timeout
|
// IDLE timeout
|
||||||
$idleProvider.idleDuration(15 * 60); // in seconds
|
var timeout = config.wallet.idleDurationMin * 60 || 300;
|
||||||
$idleProvider.warningDuration(10); // in seconds
|
$idleProvider.idleDuration(timeout); // in seconds
|
||||||
|
$idleProvider.warningDuration(20); // in seconds
|
||||||
|
$keepaliveProvider.interval(2); // in seconds
|
||||||
})
|
})
|
||||||
.run(function($rootScope, $location, $idle) {
|
.run(function($rootScope, $location, $idle) {
|
||||||
$idle.watch();
|
$idle.watch();
|
||||||
|
|
@ -83,20 +85,6 @@ angular
|
||||||
if (!util.supports.data) {
|
if (!util.supports.data) {
|
||||||
$location.path('unsupported');
|
$location.path('unsupported');
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Locked?
|
|
||||||
if ($rootScope.showLockWarning) {
|
|
||||||
if ($rootScope.tmp) {
|
|
||||||
if ($location.path() !== '/warning') {
|
|
||||||
$location.path('/warning');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
delete $rootScope['showLockWarning'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((!$rootScope.wallet || !$rootScope.wallet.id) && next.validate) {
|
if ((!$rootScope.wallet || !$rootScope.wallet.id) && next.validate) {
|
||||||
$idle.unwatch();
|
$idle.unwatch();
|
||||||
$location.path('/');
|
$location.path('/');
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ angular.module('copayApp.services')
|
||||||
|
|
||||||
Socket.removeAllListeners();
|
Socket.removeAllListeners();
|
||||||
|
|
||||||
$rootScope.wallet = $rootScope.tmp = null;
|
$rootScope.wallet = null;
|
||||||
delete $rootScope['wallet'];
|
delete $rootScope['wallet'];
|
||||||
|
|
||||||
video.close();
|
video.close();
|
||||||
|
|
@ -72,7 +72,6 @@ angular.module('copayApp.services')
|
||||||
root.setupRootVariables = function() {
|
root.setupRootVariables = function() {
|
||||||
uriHandler.register();
|
uriHandler.register();
|
||||||
$rootScope.unitName = config.unitName;
|
$rootScope.unitName = config.unitName;
|
||||||
$rootScope.showLockWarning = false;
|
|
||||||
$rootScope.txAlertCount = 0;
|
$rootScope.txAlertCount = 0;
|
||||||
$rootScope.insightError = 0;
|
$rootScope.insightError = 0;
|
||||||
$rootScope.isCollapsed = true;
|
$rootScope.isCollapsed = true;
|
||||||
|
|
@ -125,12 +124,6 @@ angular.module('copayApp.services')
|
||||||
};
|
};
|
||||||
|
|
||||||
notification.enableHtml5Mode(); // for chrome: if support, enable it
|
notification.enableHtml5Mode(); // for chrome: if support, enable it
|
||||||
w.on('locked', function() {
|
|
||||||
$rootScope.tmp = w;
|
|
||||||
$rootScope.showLockWarning=true;
|
|
||||||
$location.path('/warning');
|
|
||||||
$rootScope.$digest();
|
|
||||||
});
|
|
||||||
|
|
||||||
w.on('badMessage', function(peerId) {
|
w.on('badMessage', function(peerId) {
|
||||||
notification.error('Error', 'Received wrong message from peer ' + peerId);
|
notification.error('Error', 'Received wrong message from peer ' + peerId);
|
||||||
|
|
@ -195,6 +188,7 @@ angular.module('copayApp.services')
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
});
|
});
|
||||||
w.on('close', root.onErrorDigest);
|
w.on('close', root.onErrorDigest);
|
||||||
|
w.on('locked', root.onErrorDigest.bind(this));
|
||||||
w.netStart();
|
w.netStart();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ FakeStorage.prototype._setPassphrase = function(password) {
|
||||||
this.storage.passphrase = password;
|
this.storage.passphrase = password;
|
||||||
};
|
};
|
||||||
|
|
||||||
FakeStorage.prototype.setGlobal = function(id, payload) {
|
FakeStorage.prototype.setGlobal = function(id, v) {
|
||||||
this.storage[id] = payload;
|
this.storage[id] = typeof v === 'object' ? JSON.stringify(v) : v;
|
||||||
};
|
};
|
||||||
|
|
||||||
FakeStorage.prototype.getGlobal = function(id) {
|
FakeStorage.prototype.getGlobal = function(id) {
|
||||||
|
|
@ -35,6 +35,11 @@ FakeStorage.prototype.getLock = function(id) {
|
||||||
return this.storage[id + '::lock'];
|
return this.storage[id + '::lock'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FakeStorage.prototype.getSessionId = function() {
|
||||||
|
return this.sessionId || 'aSessionId';
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
FakeStorage.prototype.removeLock = function(id) {
|
FakeStorage.prototype.removeLock = function(id) {
|
||||||
delete this.storage[id + '::lock'];
|
delete this.storage[id + '::lock'];
|
||||||
}
|
}
|
||||||
|
|
@ -64,7 +69,11 @@ FakeStorage.prototype.getWalletIds = function() {
|
||||||
var split = ii.split('::');
|
var split = ii.split('::');
|
||||||
if (split.length == 2) {
|
if (split.length == 2) {
|
||||||
var walletId = split[0];
|
var walletId = split[0];
|
||||||
if (walletId !== 'nameFor' && typeof uniq[walletId] === 'undefined') {
|
|
||||||
|
if (!walletId || walletId === 'nameFor' || walletId ==='lock')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (typeof uniq[walletId] === 'undefined') {
|
||||||
walletIds.push(walletId);
|
walletIds.push(walletId);
|
||||||
uniq[walletId] = 1;
|
uniq[walletId] = 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,34 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
var copay = copay || require('../copay');
|
|
||||||
var chai = chai || require('chai');
|
var chai = chai || require('chai');
|
||||||
var should = chai.should();
|
var should = chai.should();
|
||||||
|
var is_browser = typeof process == 'undefined' || typeof process.versions === 'undefined';
|
||||||
|
var copay = copay || require('../copay');
|
||||||
var LocalEncrypted = copay.StorageLocalEncrypted;
|
var LocalEncrypted = copay.StorageLocalEncrypted;
|
||||||
|
|
||||||
|
|
||||||
var fakeWallet = 'fake-wallet-id';
|
var fakeWallet = 'fake-wallet-id';
|
||||||
var timeStamp = Date.now();
|
var timeStamp = Date.now();
|
||||||
var localMock = require('./mocks/FakeLocalStorage');
|
var localMock = require('./mocks/FakeLocalStorage');
|
||||||
|
var sessionMock = require('./mocks/FakeLocalStorage');
|
||||||
|
|
||||||
|
|
||||||
describe('Storage/LocalEncrypted model', function() {
|
describe('Storage/LocalEncrypted model', function() {
|
||||||
var s = new LocalEncrypted({
|
var s = new LocalEncrypted({
|
||||||
localStorage: localMock,
|
localStorage: localMock,
|
||||||
|
sessionStorage: sessionMock,
|
||||||
});
|
});
|
||||||
s._setPassphrase('mysupercoolpassword');
|
s._setPassphrase('mysupercoolpassword');
|
||||||
|
|
||||||
it('should create an instance', function() {
|
it('should create an instance', function() {
|
||||||
var s2 = new LocalEncrypted({
|
var s2 = new LocalEncrypted({
|
||||||
localStorage: localMock,
|
localStorage: localMock,
|
||||||
|
sessionStorage: sessionMock,
|
||||||
});
|
});
|
||||||
should.exist(s2);
|
should.exist(s2);
|
||||||
});
|
});
|
||||||
it('should fail when encrypting without a password', function() {
|
it('should fail when encrypting without a password', function() {
|
||||||
var s2 = new LocalEncrypted({
|
var s2 = new LocalEncrypted({
|
||||||
localStorage: localMock,
|
localStorage: localMock,
|
||||||
|
sessionStorage: sessionMock,
|
||||||
});
|
});
|
||||||
(function() {
|
(function() {
|
||||||
s2.set(fakeWallet, timeStamp, 1);
|
s2.set(fakeWallet, timeStamp, 1);
|
||||||
|
|
@ -69,6 +73,7 @@ describe('Storage/LocalEncrypted model', function() {
|
||||||
it('should export the encrypted wallet', function() {
|
it('should export the encrypted wallet', function() {
|
||||||
var storage = new LocalEncrypted({
|
var storage = new LocalEncrypted({
|
||||||
localStorage: localMock,
|
localStorage: localMock,
|
||||||
|
sessionStorage: sessionMock,
|
||||||
password: 'password',
|
password: 'password',
|
||||||
});
|
});
|
||||||
storage.set(fakeWallet, timeStamp, 'testval');
|
storage.set(fakeWallet, timeStamp, 'testval');
|
||||||
|
|
@ -86,6 +91,7 @@ describe('Storage/LocalEncrypted model', function() {
|
||||||
it('should remove an item', function() {
|
it('should remove an item', function() {
|
||||||
var s = new LocalEncrypted({
|
var s = new LocalEncrypted({
|
||||||
localStorage: localMock,
|
localStorage: localMock,
|
||||||
|
sessionStorage: sessionMock,
|
||||||
password: 'password'
|
password: 'password'
|
||||||
});
|
});
|
||||||
s.set('1', "hola", 'juan');
|
s.set('1', "hola", 'juan');
|
||||||
|
|
@ -101,6 +107,7 @@ describe('Storage/LocalEncrypted model', function() {
|
||||||
it('should get wallet ids', function() {
|
it('should get wallet ids', function() {
|
||||||
var s = new LocalEncrypted({
|
var s = new LocalEncrypted({
|
||||||
localStorage: localMock,
|
localStorage: localMock,
|
||||||
|
sessionStorage: sessionMock,
|
||||||
password: 'password'
|
password: 'password'
|
||||||
});
|
});
|
||||||
s.set('1', "hola", 'juan');
|
s.set('1', "hola", 'juan');
|
||||||
|
|
@ -113,6 +120,7 @@ describe('Storage/LocalEncrypted model', function() {
|
||||||
it('should get/set names', function() {
|
it('should get/set names', function() {
|
||||||
var s = new LocalEncrypted({
|
var s = new LocalEncrypted({
|
||||||
localStorage: localMock,
|
localStorage: localMock,
|
||||||
|
sessionStorage: sessionMock,
|
||||||
password: 'password'
|
password: 'password'
|
||||||
});
|
});
|
||||||
s.setName(1, 'hola');
|
s.setName(1, 'hola');
|
||||||
|
|
@ -124,6 +132,7 @@ describe('Storage/LocalEncrypted model', function() {
|
||||||
it('should get/set names', function() {
|
it('should get/set names', function() {
|
||||||
var s = new LocalEncrypted({
|
var s = new LocalEncrypted({
|
||||||
localStorage: localMock,
|
localStorage: localMock,
|
||||||
|
sessionStorage: sessionMock,
|
||||||
password: 'password'
|
password: 'password'
|
||||||
});
|
});
|
||||||
s.setLastOpened('hey');
|
s.setLastOpened('hey');
|
||||||
|
|
@ -131,23 +140,27 @@ describe('Storage/LocalEncrypted model', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#WalletLock', function() {
|
if (is_browser) {
|
||||||
it('should get/set/remove opened', function() {
|
describe('#getSessionId', function() {
|
||||||
var s = new LocalEncrypted({
|
it('should get SessionId', function() {
|
||||||
localStorage: localMock,
|
var s = new LocalEncrypted({
|
||||||
password: 'password'
|
localStorage: localMock,
|
||||||
|
sessionStorage: sessionMock,
|
||||||
|
password: 'password'
|
||||||
|
});
|
||||||
|
var sid = s.getSessionId();
|
||||||
|
should.exist(sid);
|
||||||
|
var sid2 = s.getSessionId();
|
||||||
|
sid2.should.equal(sid);
|
||||||
});
|
});
|
||||||
s.setLock('walletId');
|
|
||||||
s.getLock('walletId').should.equal(true);
|
|
||||||
s.removeLock('walletId');
|
|
||||||
should.not.exist(s.getLock('walletId'));
|
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
describe('#getWallets', function() {
|
describe('#getWallets', function() {
|
||||||
it('should retreive wallets from storage', function() {
|
it('should retreive wallets from storage', function() {
|
||||||
var s = new LocalEncrypted({
|
var s = new LocalEncrypted({
|
||||||
localStorage: localMock,
|
localStorage: localMock,
|
||||||
|
sessionStorage: sessionMock,
|
||||||
password: 'password'
|
password: 'password'
|
||||||
});
|
});
|
||||||
s.set('1', "hola", 'juan');
|
s.set('1', "hola", 'juan');
|
||||||
|
|
@ -167,6 +180,7 @@ describe('Storage/LocalEncrypted model', function() {
|
||||||
it('should delete a wallet', function() {
|
it('should delete a wallet', function() {
|
||||||
var s = new LocalEncrypted({
|
var s = new LocalEncrypted({
|
||||||
localStorage: localMock,
|
localStorage: localMock,
|
||||||
|
sessionStorage: sessionMock,
|
||||||
password: 'password'
|
password: 'password'
|
||||||
});
|
});
|
||||||
s.set('1', "hola", 'juan');
|
s.set('1', "hola", 'juan');
|
||||||
|
|
@ -186,6 +200,7 @@ describe('Storage/LocalEncrypted model', function() {
|
||||||
it('set localstorage from an object', function() {
|
it('set localstorage from an object', function() {
|
||||||
var s = new LocalEncrypted({
|
var s = new LocalEncrypted({
|
||||||
localStorage: localMock,
|
localStorage: localMock,
|
||||||
|
sessionStorage: sessionMock,
|
||||||
password: 'password'
|
password: 'password'
|
||||||
});
|
});
|
||||||
s.setFromObj('id1', {
|
s.setFromObj('id1', {
|
||||||
|
|
@ -205,6 +220,7 @@ describe('Storage/LocalEncrypted model', function() {
|
||||||
it('should set, get and remove keys', function() {
|
it('should set, get and remove keys', function() {
|
||||||
var s = new LocalEncrypted({
|
var s = new LocalEncrypted({
|
||||||
localStorage: localMock,
|
localStorage: localMock,
|
||||||
|
sessionStorage: sessionMock,
|
||||||
password: 'password'
|
password: 'password'
|
||||||
});
|
});
|
||||||
s.setGlobal('a', {
|
s.setGlobal('a', {
|
||||||
|
|
@ -217,4 +233,17 @@ describe('Storage/LocalEncrypted model', function() {
|
||||||
should.not.exist(s.getGlobal('a'));
|
should.not.exist(s.getGlobal('a'));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('session storage', function() {
|
||||||
|
it('should get a session ID', function() {
|
||||||
|
var s = new LocalEncrypted({
|
||||||
|
localStorage: localMock,
|
||||||
|
sessionStorage: sessionMock,
|
||||||
|
password: 'password'
|
||||||
|
});
|
||||||
|
s.getSessionId().length.should.equal(16);
|
||||||
|
(new Buffer(s.getSessionId(),'hex')).length.should.equal(8);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -182,7 +182,6 @@ describe('Wallet model', function() {
|
||||||
cachedW2obj.opts.reconnectDelay = 100;
|
cachedW2obj.opts.reconnectDelay = 100;
|
||||||
}
|
}
|
||||||
var w = Wallet.fromObj(cachedW2obj, cachedW2.storage, cachedW2.network, cachedW2.blockchain);
|
var w = Wallet.fromObj(cachedW2obj, cachedW2.storage, cachedW2.network, cachedW2.blockchain);
|
||||||
w.unlock();
|
|
||||||
return w;
|
return w;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1025,36 +1024,6 @@ describe('Wallet model', function() {
|
||||||
w.network.start.getCall(0).args[0].privkey.length.should.equal(64);
|
w.network.start.getCall(0).args[0].privkey.length.should.equal(64);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should check if wallet is already opened', function() {
|
|
||||||
var w = cachedCreateW2();
|
|
||||||
should.not.exist(w.getLock());
|
|
||||||
w.checkAndLock().should.equal(false);
|
|
||||||
w.getLock().should.equal(true);
|
|
||||||
});
|
|
||||||
it('should check if wallet is already opened', function() {
|
|
||||||
var w = cachedCreateW2();
|
|
||||||
should.not.exist(w.getLock());
|
|
||||||
w.checkAndLock().should.equal(false);
|
|
||||||
w.getLock().should.equal(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should not start if locked', function() {
|
|
||||||
var w = cachedCreateW2();
|
|
||||||
w.netStart();
|
|
||||||
w.emit = sinon.spy();
|
|
||||||
w.netStart();
|
|
||||||
w.emit.getCall(0).args[0].should.equal('locked');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should accept ignoreLocked', function() {
|
|
||||||
var w = cachedCreateW2();
|
|
||||||
w.netStart();
|
|
||||||
w.network.start = sinon.spy();
|
|
||||||
w.ignoreLock=1;
|
|
||||||
w.netStart();
|
|
||||||
w.network.start.getCall(0).args[0].privkey.length.should.equal(64);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#forceNetwork in config', function() {
|
describe('#forceNetwork in config', function() {
|
||||||
|
|
|
||||||
|
|
@ -298,6 +298,7 @@ describe('WalletFactory model', function() {
|
||||||
var w = wf.create({
|
var w = wf.create({
|
||||||
name: 'test wallet'
|
name: 'test wallet'
|
||||||
});
|
});
|
||||||
|
|
||||||
ws = wf.getWallets();
|
ws = wf.getWallets();
|
||||||
ws.length.should.equal(1);
|
ws.length.should.equal(1);
|
||||||
ws[0].name.should.equal('test wallet');
|
ws[0].name.should.equal('test wallet');
|
||||||
|
|
|
||||||
80
test/test.WalletLock.js
Normal file
80
test/test.WalletLock.js
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var chai = chai || require('chai');
|
||||||
|
var should = chai.should();
|
||||||
|
var sinon = require('sinon');
|
||||||
|
var is_browser = (typeof process == 'undefined' || typeof process.versions === 'undefined');
|
||||||
|
if (is_browser) {
|
||||||
|
var copay = require('copay'); //browser
|
||||||
|
} else {
|
||||||
|
var copay = require('../copay'); //node
|
||||||
|
}
|
||||||
|
var copayConfig = require('../config');
|
||||||
|
var WalletLock = copay.WalletLock;
|
||||||
|
|
||||||
|
var PrivateKey = copay.PrivateKey;
|
||||||
|
var Storage = require('./mocks/FakeStorage');
|
||||||
|
|
||||||
|
describe('WalletLock model', function() {
|
||||||
|
var storage = new Storage();
|
||||||
|
|
||||||
|
it('should fail with missing args', function() {
|
||||||
|
(function() {
|
||||||
|
new WalletLock()
|
||||||
|
}).should.throw('Argument');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should fail with missing args (case 2)', function() {
|
||||||
|
(function() {
|
||||||
|
new WalletLock(storage)
|
||||||
|
}).should.throw('Argument');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create an instance', function() {
|
||||||
|
var w = new WalletLock(storage, 'id');
|
||||||
|
should.exist(w);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should NOT fail if locked already', function() {
|
||||||
|
var w = new WalletLock(storage, 'walletId');
|
||||||
|
storage.sessionId = 'xxx';
|
||||||
|
var w2= new WalletLock(storage, 'walletId');
|
||||||
|
should.exist(w2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should change status of previously openned wallet', function() {
|
||||||
|
storage.sessionId = 'session1';
|
||||||
|
var w = new WalletLock(storage, 'walletId');
|
||||||
|
storage.sessionId = 'xxx';
|
||||||
|
var w2= new WalletLock(storage, 'walletId');
|
||||||
|
w2.keepAlive();
|
||||||
|
(function() {w.keepAlive();}).should.throw('already open');
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should not fail if locked by me', function() {
|
||||||
|
var s = new Storage();
|
||||||
|
var w = new WalletLock(s, 'walletId');
|
||||||
|
var w2 = new WalletLock(s, 'walletId')
|
||||||
|
w2.keepAlive();
|
||||||
|
should.exist(w2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not fail if expired', function() {
|
||||||
|
var s = new Storage();
|
||||||
|
var w = new WalletLock(s, 'walletId');
|
||||||
|
var k = Object.keys(s.storage)[0];
|
||||||
|
var v = JSON.parse(s.storage[k]);
|
||||||
|
v.expireTs = Date.now() - 60 * 6 * 1000;
|
||||||
|
s.storage[k] = JSON.stringify(v);
|
||||||
|
|
||||||
|
s.sessionId = 'xxx';
|
||||||
|
var w2 = new WalletLock(s, 'walletId')
|
||||||
|
should.exist(w2);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
@ -38,12 +38,12 @@ var createBundle = function(opts) {
|
||||||
expose: '../js/models/core/WalletFactory'
|
expose: '../js/models/core/WalletFactory'
|
||||||
});
|
});
|
||||||
b.require('./js/models/core/Wallet');
|
b.require('./js/models/core/Wallet');
|
||||||
b.require('./js/models/core/Wallet', {
|
|
||||||
expose: '../js/models/core/Wallet'
|
|
||||||
});
|
|
||||||
b.require('./js/models/core/Wallet', {
|
b.require('./js/models/core/Wallet', {
|
||||||
expose: '../../js/models/core/Wallet'
|
expose: '../../js/models/core/Wallet'
|
||||||
});
|
});
|
||||||
|
b.require('./js/models/core/WalletLock', {
|
||||||
|
expose: '../js/models/core/WalletLock'
|
||||||
|
});
|
||||||
b.require('./js/models/network/WebRTC', {
|
b.require('./js/models/network/WebRTC', {
|
||||||
expose: '../js/models/network/WebRTC'
|
expose: '../js/models/network/WebRTC'
|
||||||
});
|
});
|
||||||
|
|
@ -96,7 +96,7 @@ var createBundle = function(opts) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!opts.dontminify) {
|
if (!opts.debug) {
|
||||||
b.transform({
|
b.transform({
|
||||||
global: true
|
global: true
|
||||||
}, 'uglifyify');
|
}, 'uglifyify');
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue