From 313fcd4808a599e931aabd998200115c3cb1c576 Mon Sep 17 00:00:00 2001 From: Gustavo Cortez Date: Mon, 7 Jul 2014 01:33:39 -0300 Subject: [PATCH] Added creator's signature to address book entry. Re-factory somethings and improve the merge of them --- index.html | 9 ++- js/controllers/send.js | 34 ++++----- js/models/core/Wallet.js | 56 +++++++++++---- test/test.Wallet.js | 152 ++++++++++++++++++++++++++------------- 4 files changed, 169 insertions(+), 82 deletions(-) diff --git a/index.html b/index.html index 339e7e7ce..6455f73b7 100644 --- a/index.html +++ b/index.html @@ -753,16 +753,19 @@ Address Creator Date -   + Signature + Hidden - + {{info.label}} {{addr}} {{$root.wallet.publicKeyRing.nicknameForCopayer(info.copayerId)}} - + {{signAddressBook[addr]}} + {{info.hidden}} diff --git a/js/controllers/send.js b/js/controllers/send.js index 5d94e90fd..a09e76010 100644 --- a/js/controllers/send.js +++ b/js/controllers/send.js @@ -186,23 +186,23 @@ angular.module('copayApp.controllers').controller('SendController', }, 500); }; - $scope.deleteAddressBook = function(addressBook) { - var w = $rootScope.wallet; - $timeout(function() { - var errorMsg; - try { - w.deleteAddressBook(addressBook); - } catch (e) { - errorMsg = e.message; - } + $scope.signAddressBook = {}; - if (errorMsg) { - notification.error('Error', errorMsg); - } else { - notification.success('Success', 'Entry removed successfully'); - } - $rootScope.$digest(); - }, 500); + $scope.checkSignAddressBook = function(key) { + if (key) { + $timeout(function() { + var w = $rootScope.wallet; + var sign = w.verifySignAddressBook(key); + $scope.signAddressBook[key] = sign; + }, 10); + } + }; + + $scope.toggleAddressBookEntry = function(key) { + if (key) { + var w = $rootScope.wallet; + w.toggleAddressBookEntry(key); + } }; $scope.copyAddress = function(address) { @@ -250,11 +250,11 @@ angular.module('copayApp.controllers').controller('SendController', if (errorMsg) { notification.error('Error', errorMsg); } else { + $scope.checkSignAddressBook(entry.address); notification.success('Success', 'New entry has been created'); } $rootScope.$digest(); }, 500); - $anchorScroll(); // reset fields $scope.newaddress = $scope.newlabel = null; }); diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index fec67735b..ece26ad2a 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -146,11 +146,6 @@ Wallet.prototype._handleAddressBook = function(senderId, data, isInbound) { if (!this.addressBook[key]) { this.addressBook[key] = rcv[key]; hasChange = true; - } else { - if (rcv[key].createdTs > this.addressBook[key].createdTs) { - this.addressBook[key] = rcv[key]; - hasChange = true; - } } } if (hasChange) { @@ -244,7 +239,6 @@ Wallet.prototype.getMyCopayerIdPriv = function() { return this.privateKey.getIdPriv(); //copayer idpriv is hex of a private key }; - Wallet.prototype.getSecret = function() { var pubkeybuf = new Buffer(this.getMyCopayerId(), 'hex'); var str = Base58Check.encode(pubkeybuf); @@ -838,21 +832,42 @@ Wallet.prototype._checkAddressBook = function(key) { Wallet.prototype.setAddressBook = function(key, label) { this._checkAddressBook(key); + var copayerId = this.getMyCopayerId(); + var ts = Date.now(); + var payload = { + address: key, + label: label, + copayerId: copayerId, + createdTs: ts + }; var addressbook = { - createdTs: Date.now(), - copayerId: this.getMyCopayerId(), - label: label + hidden: false, + createdTs: ts, + copayerId: copayerId, + label: label, + signature: this.signObject(payload) }; this.addressBook[key] = addressbook; this.sendAddressBook(); this.store(); }; -Wallet.prototype.deleteAddressBook = function(key) { +Wallet.prototype.verifySignAddressBook = function(key) { if (key) { - this.addressBook[key].copayerId = -1; - this.addressBook[key].createdTs = Date.now(); - this.sendAddressBook(); + var signature = this.addressBook[key].signature; + var payload = { + address: key, + label: this.addressBook[key].label, + copayerId: this.addressBook[key].copayerId, + createdTs: this.addressBook[key].createdTs + }; + return this.verifySignedObject(payload, signature); + } +} + +Wallet.prototype.toggleAddressBookEntry = function(key) { + if (key) { + this.addressBook[key].hidden = !this.addressBook[key].hidden; this.store(); } }; @@ -867,4 +882,19 @@ Wallet.prototype.offerBackup = function() { this.store(); }; +Wallet.prototype.signObject = function(payload) { + var key = new bitcore.Key(); + key.private = new Buffer(this.getMyCopayerIdPriv(), 'hex'); + key.regenerateSync(); + var sign = bitcore.Message.sign(JSON.stringify(payload), key); + return sign.toString('hex'); +} + +Wallet.prototype.verifySignedObject = function(payload, signature) { + var pubkey = new Buffer(this.getMyCopayerId(), 'hex'); + var sign = new Buffer(signature, 'hex'); + var v = bitcore.Message.verifyWithPubKey(pubkey, JSON.stringify(payload), sign); + return v; +} + module.exports = require('soop')(Wallet); diff --git a/test/test.Wallet.js b/test/test.Wallet.js index 20dd4b6ba..c172a1e93 100644 --- a/test/test.Wallet.js +++ b/test/test.Wallet.js @@ -78,11 +78,13 @@ describe('Wallet model', function() { label: 'John', copayerId: '026a55261b7c898fff760ebe14fd22a71892295f3b49e0ca66727bc0a0d7f94d03', createdTs: 1403102115, + hidden: false }, '2MtP8WyiwG7ZdVWM96CVsk2M1N8zyfiVQsY': { label: 'Jennifer', copayerId: '032991f836543a492bd6d0bb112552bfc7c5f3b7d5388fcbcbf2fbb893b44770d7', createdTs: 1403103115, + hidden: false } }; @@ -760,61 +762,113 @@ describe('Wallet model', function() { done(); }); - var contacts = [{ - label: 'Charles', - address: '2N8pJWpXCAxmNLHKVEhz3TtTcYCtHd43xWU ', - }, { - label: 'Linda', - address: '2N4Zq92goYGrf5J4F4SZZq7jnPYbCiyRYT2 ', - }]; + describe('#AddressBook', function() { + var contacts = [{ + label: 'Charles', + address: '2N8pJWpXCAxmNLHKVEhz3TtTcYCtHd43xWU ', + }, { + label: 'Linda', + address: '2N4Zq92goYGrf5J4F4SZZq7jnPYbCiyRYT2 ', + }]; - it('should create new entry for address book', function() { - var w = createW(); - contacts.forEach(function(c) { - w.setAddressBook(c.address, c.label); + it('should create new entry for address book', function() { + var w = createW(); + contacts.forEach(function(c) { + w.setAddressBook(c.address, c.label); + }); + Object.keys(w.addressBook).length.should.equal(4); }); - Object.keys(w.addressBook).length.should.equal(4); - }); - it('should fail if create a duplicate address', function() { - var w = createW(); - w.setAddressBook(contacts[0].address, contacts[0].label); - (function() { + it('should fail if create a duplicate address', function() { + var w = createW(); w.setAddressBook(contacts[0].address, contacts[0].label); - }).should. - throw(); - }); - - it('should delete an entry for address book', function() { - var w = createW(); - contacts.forEach(function(c) { - w.setAddressBook(c.address, c.label); + (function() { + w.setAddressBook(contacts[0].address, contacts[0].label); + }).should. + throw(); + }); + + it('should show/hide everywhere', function() { + var w = createW(); + var key = '2NFR2kzH9NUdp8vsXTB4wWQtTtzhpKxsyoJ'; + w.toggleAddressBookEntry(key); + w.addressBook[key].hidden.should.equal(true); + w.toggleAddressBookEntry(key); + w.addressBook[key].hidden.should.equal(false); + }); + + it('handle network addressBook correctly', function() { + var w = createW(); + var data = { + walletId: w.id, + addressBook: { + 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx': { + label: 'Faucet', + copayerId: '026a55261b7c898fff760ebe14fd22a71892295f3b49e0ca66727bc0a0d7f94d03', + createdTs: 1403102115, + } + }, + type: 'addressbook' + }; + Object.keys(w.addressBook).length.should.equal(2); + // New address + w._handleAddressBook('senderID', data, true); + Object.keys(w.addressBook).length.should.equal(3); + // Existent address + w._handleAddressBook('senderID', data, true); + Object.keys(w.addressBook).length.should.equal(3); + }); + + it('should return signed object', function() { + var w = createW(); + var payload = { + address: 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx', + label: 'Faucet', + copayerId: '026a55261b7c898fff760ebe14fd22a71892295f3b49e0ca66727bc0a0d7f94d03', + createdTs: 1403102115 + }; + should.exist(w.signObject(payload)); + }); + + it('should verify signed object', function() { + var w = createW(); + var data = { + address: 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx', + label: 'Faucet', + copayerId: '026a55261b7c898fff760ebe14fd22a71892295f3b49e0ca66727bc0a0d7f94d03', + createdTs: 1403102115, + }; + var signature = w.signObject(data); + + w.verifySignedObject(data, signature).should.equal(true); + data.label = 'Another'; + w.verifySignedObject(data, signature).should.equal(false); + }); + + it('should verify signed addressbook entry', function() { + var w = createW(); + var key = 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx'; + var payload = { + address: key, + label: 'Faucet', + copayerId: '026a55261b7c898fff760ebe14fd22a71892295f3b49e0ca66727bc0a0d7f94d03', + createdTs: 1403102115, + }; + + var addressbook = { + hidden: false, + createdTs: payload.createdTs, + copayerId: payload.copayerId, + label: payload.label, + signature: w.signObject(payload) + }; + w.addressBook[key] = addressbook; + + w.verifySignAddressBook(key).should.equal(true); + w.addressBook[key].label = 'Another'; + w.verifySignAddressBook(key).should.equal(false); }); - Object.keys(w.addressBook).length.should.equal(4); - var key = contacts[0].address; - w.deleteAddressBook(key); - w.addressBook[key].copayerId.should.equal(-1); - }); - it('handle network addressBook correctly', function() { - var w = createW(); - var data = { - walletId: w.id, - addressBook: { - 'msj42CCGruhRsFrGATiUuh25dtxYtnpbTx': { - label: 'Faucet', - copayerId: '026a55261b7c898fff760ebe14fd22a71892295f3b49e0ca66727bc0a0d7f94d03', - createdTs: 1403102115, - } - }, - type: 'addressbook' - }; - Object.keys(w.addressBook).length.should.equal(2); - w._handleAddressBook('senderID', data, true); - Object.keys(w.addressBook).length.should.equal(3); - data.addressBook['msj42CCGruhRsFrGATiUuh25dtxYtnpbTx'].createdTs = 1403102215; - w._handleAddressBook('senderID', data, true); - Object.keys(w.addressBook).length.should.equal(3); }); it('#getNetworkName', function() {