mirror of https://github.com/BTCPrivate/copay.git
WIP: better lock
This commit is contained in:
parent
d8e0d50dce
commit
bcb61810d5
|
@ -1,7 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('OpenController',
|
||||
function($scope, $rootScope, $location, walletFactory, controllerUtils, Passphrase, notification) {
|
||||
angular.module('copayApp.controllers').controller('OpenController', function($scope, $rootScope, $location, walletFactory, controllerUtils, Passphrase, notification) {
|
||||
controllerUtils.redirIfLogged();
|
||||
|
||||
var cmp = function(o1, o2) {
|
||||
|
@ -28,9 +27,7 @@ angular.module('copayApp.controllers').controller('OpenController',
|
|||
Passphrase.getBase64Async(password, function(passphrase) {
|
||||
var w, errMsg;
|
||||
try {
|
||||
w = walletFactory.open($scope.selectedWalletId, {
|
||||
passphrase: passphrase
|
||||
});
|
||||
w = walletFactory.open($scope.selectedWalletId, passphrase);
|
||||
} catch (e) {
|
||||
errMsg = e.message;
|
||||
};
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
var http = require('http');
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var nodeUtil = require('util');
|
||||
var async = require('async');
|
||||
var preconditions = require('preconditions').singleton();
|
||||
var parseBitcoinURI = require('./HDPath').parseBitcoinURI;
|
||||
var util = require('util');
|
||||
|
||||
var bitcore = require('bitcore');
|
||||
var bignum = bitcore.Bignum;
|
||||
|
@ -23,6 +23,7 @@ var PublicKeyRing = require('./PublicKeyRing');
|
|||
var TxProposal = require('./TxProposal');
|
||||
var TxProposals = require('./TxProposals');
|
||||
var PrivateKey = require('./PrivateKey');
|
||||
var WalletLock = require('./WalletLock');
|
||||
var copayConfig = require('../../../config');
|
||||
|
||||
function Wallet(opts) {
|
||||
|
@ -45,9 +46,11 @@ function Wallet(opts) {
|
|||
this.log('creating ' + opts.requiredCopayers + ' of ' + opts.totalCopayers + ' wallet');
|
||||
|
||||
this.id = opts.id || Wallet.getRandomId();
|
||||
this.lock = new WalletLock(this.storage, this.id, opts.lockTimeOutMin);
|
||||
|
||||
|
||||
this.name = opts.name;
|
||||
|
||||
this.ignoreLock = opts.ignoreLock;
|
||||
this.verbose = opts.verbose;
|
||||
this.publicKeyRing.walletId = this.id;
|
||||
this.txProposals.walletId = this.id;
|
||||
|
@ -64,7 +67,7 @@ function Wallet(opts) {
|
|||
this.network.setHexNonces(opts.networkNonces);
|
||||
}
|
||||
|
||||
nodeUtil.inherits(Wallet, EventEmitter);
|
||||
util.inherits(Wallet, EventEmitter);
|
||||
|
||||
Wallet.builderOpts = {
|
||||
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) {
|
||||
this.log('RECV INDEXES:', data);
|
||||
var inIndexes = HDParams.fromList(data.indexes);
|
||||
|
@ -438,11 +420,6 @@ Wallet.prototype.netStart = function(callback) {
|
|||
var self = this;
|
||||
var net = this.network;
|
||||
|
||||
if (this.checkAndLock() && !this.ignoreLock) {
|
||||
this.emit('locked');
|
||||
return;
|
||||
}
|
||||
|
||||
net.removeAllListeners();
|
||||
net.on('connect', self._handleConnect.bind(self));
|
||||
net.on('disconnect', self._handleDisconnect.bind(self));
|
||||
|
@ -519,7 +496,13 @@ Wallet.prototype.getRegisteredPeerIds = function() {
|
|||
return this.registeredPeerIds;
|
||||
};
|
||||
|
||||
Wallet.prototype.keepAlive = function() {
|
||||
this.lock.keepAlive();
|
||||
};
|
||||
|
||||
Wallet.prototype.store = function() {
|
||||
this.keepAlive();
|
||||
|
||||
var wallet = this.toObj();
|
||||
this.storage.setFromObj(this.id, wallet);
|
||||
this.log('Wallet stored');
|
||||
|
@ -556,8 +539,8 @@ Wallet.fromObj = function(o, storage, network, blockchain) {
|
|||
opts.storage = storage;
|
||||
opts.network = network;
|
||||
opts.blockchain = blockchain;
|
||||
var w = new Wallet(opts);
|
||||
return w;
|
||||
|
||||
return new Wallet(opts);
|
||||
};
|
||||
|
||||
Wallet.prototype.toEncryptedObj = function() {
|
||||
|
@ -782,7 +765,9 @@ Wallet.prototype.createPaymentTx = function(options, cb) {
|
|||
var self = this;
|
||||
|
||||
if (typeof options === 'string') {
|
||||
options = { uri: options };
|
||||
options = {
|
||||
uri: options
|
||||
};
|
||||
}
|
||||
options.uri = options.uri || options.url;
|
||||
|
||||
|
@ -824,7 +809,9 @@ Wallet.prototype.fetchPaymentTx = function(options, cb) {
|
|||
|
||||
options = options || {};
|
||||
if (typeof options === 'string') {
|
||||
options = { uri: options };
|
||||
options = {
|
||||
uri: options
|
||||
};
|
||||
}
|
||||
options.uri = options.uri || options.url;
|
||||
options.fetch = true;
|
||||
|
@ -980,8 +967,7 @@ Wallet.prototype.sendPaymentTx = function(ntxid, options, cb) {
|
|||
|
||||
var refund_outputs = [];
|
||||
|
||||
options.refund_to = options.refund_to
|
||||
|| this.publicKeyRing.getPubKeys(0, false, this.getMyCopayerId())[0];
|
||||
options.refund_to = options.refund_to || this.publicKeyRing.getPubKeys(0, false, this.getMyCopayerId())[0];
|
||||
|
||||
if (options.refund_to) {
|
||||
var total = txp.merchant.pr.pd.outputs.reduce(function(total, _, i) {
|
||||
|
@ -1031,8 +1017,7 @@ Wallet.prototype.sendPaymentTx = function(ntxid, options, cb) {
|
|||
pay.set('transactions', [tx.serialize()]);
|
||||
pay.set('refund_to', refund_outputs);
|
||||
|
||||
options.memo = options.memo || options.comment
|
||||
|| 'Hi server, I would like to give you some money.';
|
||||
options.memo = options.memo || options.comment || 'Hi server, I would like to give you some money.';
|
||||
|
||||
pay.set('memo', options.memo);
|
||||
|
||||
|
@ -1250,9 +1235,7 @@ Wallet.prototype.createPaymentTxSync = function(options, merchantData, unspent)
|
|||
Wallet.prototype.verifyPaymentRequest = function(ntxid) {
|
||||
if (!ntxid) return false;
|
||||
|
||||
var txp = typeof ntxid !== 'object'
|
||||
? this.txProposals.get(ntxid)
|
||||
: ntxid;
|
||||
var txp = typeof ntxid !== 'object' ? this.txProposals.get(ntxid) : ntxid;
|
||||
|
||||
// If we're not a payment protocol proposal, ignore.
|
||||
if (!txp.merchant) return true;
|
||||
|
@ -1358,8 +1341,7 @@ Wallet.prototype.verifyPaymentRequest = function(ntxid) {
|
|||
}
|
||||
|
||||
// Make sure the tx's output script and values match the payment request's.
|
||||
if (av.toString('hex') !== ev.toString('hex')
|
||||
|| as.toString('hex') !== es.toString('hex')) {
|
||||
if (av.toString('hex') !== ev.toString('hex') || as.toString('hex') !== es.toString('hex')) {
|
||||
// Verifiable outputs do not match outputs of merchant
|
||||
// data. We should not sign this transaction proposal!
|
||||
return false;
|
||||
|
@ -1386,8 +1368,7 @@ Wallet.prototype.verifyPaymentRequest = function(ntxid) {
|
|||
var as = new Buffer(ro.script.buffer, 'hex')
|
||||
.slice(ro.script.offset, ro.script.limit);
|
||||
|
||||
if (av.toString('hex') !== ev.toString('hex')
|
||||
|| as.toString('hex') !== es.toString('hex')) {
|
||||
if (av.toString('hex') !== ev.toString('hex') || as.toString('hex') !== es.toString('hex')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1506,14 +1487,19 @@ Wallet.prototype.createTx = function(toAddress, amountSatStr, comment, opts, cb)
|
|||
if (typeof amountSatStr === 'function') {
|
||||
var cb = amountSatStr;
|
||||
var merchant = toAddress;
|
||||
return this.createPaymentTx({ uri: merchant }, cb);
|
||||
return this.createPaymentTx({
|
||||
uri: merchant
|
||||
}, cb);
|
||||
}
|
||||
|
||||
if (typeof comment === 'function') {
|
||||
var cb = comment;
|
||||
var merchant = toAddress;
|
||||
var comment = amountSatStr;
|
||||
return this.createPaymentTx({ uri: merchant, memo: comment }, cb);
|
||||
return this.createPaymentTx({
|
||||
uri: merchant,
|
||||
memo: comment
|
||||
}, cb);
|
||||
}
|
||||
|
||||
if (typeof opts === 'function') {
|
||||
|
@ -1779,7 +1765,9 @@ Wallet.prototype.verifySignedJson = function(senderId, payload, signature) {
|
|||
|
||||
Wallet.request = function(options, callback) {
|
||||
if (typeof options === 'string') {
|
||||
options = { uri: options };
|
||||
options = {
|
||||
uri: options
|
||||
};
|
||||
}
|
||||
|
||||
options.method = options.method || 'GET';
|
||||
|
@ -1794,8 +1782,7 @@ Wallet.request = function(options, callback) {
|
|||
this._error = cb;
|
||||
return this;
|
||||
},
|
||||
_success: function() {
|
||||
;
|
||||
_success: function() {;
|
||||
},
|
||||
_error: function(_, err) {
|
||||
throw err;
|
||||
|
|
|
@ -108,6 +108,7 @@ WalletFactory.prototype.create = function(opts) {
|
|||
|
||||
var requiredCopayers = opts.requiredCopayers || this.walletDefaults.requiredCopayers;
|
||||
var totalCopayers = opts.totalCopayers || this.walletDefaults.totalCopayers;
|
||||
opts.lockTimeoutMin = this.walletDefaults.idleDurationMin;
|
||||
|
||||
opts.publicKeyRing = opts.publicKeyRing || new PublicKeyRing({
|
||||
networkName: this.networkName,
|
||||
|
@ -137,6 +138,7 @@ WalletFactory.prototype.create = function(opts) {
|
|||
opts.requiredCopayers = requiredCopayers;
|
||||
opts.totalCopayers = totalCopayers;
|
||||
opts.version = opts.version || this.version;
|
||||
|
||||
var w = new Wallet(opts);
|
||||
w.store();
|
||||
this.storage.setLastOpened(w.id);
|
||||
|
@ -166,16 +168,11 @@ 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);
|
||||
|
||||
var w = this.read(walletId);
|
||||
if (w) {
|
||||
WalletFactory.prototype.open = function(walletId, passphrase) {
|
||||
this.storage._setPassphrase(passphrase);
|
||||
var w = this.read(walletId, opts);
|
||||
if (w)
|
||||
w.store();
|
||||
}
|
||||
|
||||
this.storage.setLastOpened(walletId);
|
||||
return w;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
var CryptoJS = require('node-cryptojs-aes').CryptoJS;
|
||||
|
||||
var bitcore = require('bitcore');
|
||||
var id = 0;
|
||||
|
||||
function Storage(opts) {
|
||||
|
@ -93,6 +93,15 @@ Storage.prototype.removeGlobal = function(k) {
|
|||
this.localStorage.removeItem(k);
|
||||
};
|
||||
|
||||
Storage.prototype.getSessionId = function() {
|
||||
var sessionId = this.sessionStorage.getItem('sessionId');
|
||||
if (!sessionId) {
|
||||
sessionId = bitcore.getRandomBuffer(8).toString('hex');
|
||||
this.sessionStorage.setItem(sessionId, 'sessionId');
|
||||
}
|
||||
return sessionId;
|
||||
};
|
||||
|
||||
Storage.prototype._key = function(walletId, k) {
|
||||
return walletId + '::' + k;
|
||||
};
|
||||
|
@ -132,7 +141,8 @@ Storage.prototype.getWalletIds = function() {
|
|||
if (split.length == 2) {
|
||||
var walletId = split[0];
|
||||
|
||||
if (walletId === 'nameFor') continue;
|
||||
if (walletId === 'nameFor' || walletId === 'lock')
|
||||
continue;
|
||||
|
||||
if (typeof uniq[walletId] === 'undefined') {
|
||||
walletIds.push(walletId);
|
||||
|
@ -180,8 +190,9 @@ Storage.prototype.getLastOpened = function() {
|
|||
return this.getGlobal('lastOpened');
|
||||
}
|
||||
|
||||
// Lock related
|
||||
Storage.prototype.setLock = function(walletId) {
|
||||
this.setGlobal(this._key(walletId, 'Lock'), true);
|
||||
this.setGlobal(this._key(walletId, 'Lock'), this.sessionId());
|
||||
}
|
||||
|
||||
Storage.prototype.getLock = function(walletId) {
|
||||
|
|
|
@ -74,8 +74,8 @@ angular
|
|||
.html5Mode(false)
|
||||
.hashPrefix('!');
|
||||
// IDLE timeout
|
||||
$idleProvider.idleDuration(15 * 60); // in seconds
|
||||
$idleProvider.warningDuration(10); // in seconds
|
||||
$idleProvider.idleDuration(config.wallet.idleDurationMin * 60); // in seconds
|
||||
$idleProvider.warningDuration(20); // in seconds
|
||||
})
|
||||
.run(function($rootScope, $location, $idle) {
|
||||
$idle.watch();
|
||||
|
|
|
@ -35,6 +35,11 @@ FakeStorage.prototype.getLock = function(id) {
|
|||
return this.storage[id + '::lock'];
|
||||
}
|
||||
|
||||
FakeStorage.prototype.getSessionId = function() {
|
||||
return this.sessionId || 'aSessionId';
|
||||
};
|
||||
|
||||
|
||||
FakeStorage.prototype.removeLock = function(id) {
|
||||
delete this.storage[id + '::lock'];
|
||||
}
|
||||
|
|
|
@ -182,7 +182,6 @@ describe('Wallet model', function() {
|
|||
cachedW2obj.opts.reconnectDelay = 100;
|
||||
}
|
||||
var w = Wallet.fromObj(cachedW2obj, cachedW2.storage, cachedW2.network, cachedW2.blockchain);
|
||||
w.unlock();
|
||||
return w;
|
||||
};
|
||||
|
||||
|
@ -1025,20 +1024,6 @@ describe('Wallet model', function() {
|
|||
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();
|
||||
|
|
Loading…
Reference in New Issue