Address Book
Empty. Create an alias for your addresses
@@ -775,16 +775,19 @@
Address
| Creator
| Date
- |
+ |
|
-
+
| {{info.label}} |
{{addr}} |
{{$root.wallet.publicKeyRing.nicknameForCopayer(info.copayerId)}} |
|
- |
+ {{info.hidden ?
+ 'Enable' : 'Disable'}} |
diff --git a/js/controllers/send.js b/js/controllers/send.js
index 0ab3d3858..e9f3d92ec 100644
--- a/js/controllers/send.js
+++ b/js/controllers/send.js
@@ -14,7 +14,7 @@ angular.module('copayApp.controllers').controller('SendController',
var flag;
if (w) {
for (var k in w.addressBook) {
- if (w.addressBook[k].copayerId != -1) {
+ if (w.addressBook[k]) {
flag = true;
break;
}
@@ -194,23 +194,9 @@ angular.module('copayApp.controllers').controller('SendController',
}, 500);
};
- $scope.deleteAddressBook = function(addressBook) {
+ $scope.toggleAddressBookEntry = function(key) {
var w = $rootScope.wallet;
- $timeout(function() {
- var errorMsg;
- try {
- w.deleteAddressBook(addressBook);
- } catch (e) {
- errorMsg = e.message;
- }
-
- if (errorMsg) {
- notification.error('Error', errorMsg);
- } else {
- notification.success('Success', 'Entry removed successfully');
- }
- $rootScope.$digest();
- }, 500);
+ w.toggleAddressBookEntry(key);
};
$scope.copyAddress = function(address) {
@@ -262,7 +248,6 @@ angular.module('copayApp.controllers').controller('SendController',
}
$rootScope.$digest();
}, 500);
- $anchorScroll();
// reset fields
$scope.newaddress = $scope.newlabel = null;
});
diff --git a/js/directives.js b/js/directives.js
index cac0adb93..e5c0502b2 100644
--- a/js/directives.js
+++ b/js/directives.js
@@ -128,7 +128,7 @@ angular.module('copayApp.directives')
var address = attrs.address;
var contact = scope.wallet.addressBook[address];
- if (contact) {
+ if (contact && !contact.hidden) {
element.append(contact.label);
attrs['tooltip'] = attrs.address;
} else {
diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js
index 5ee65c49b..7e892dd42 100644
--- a/js/models/core/Wallet.js
+++ b/js/models/core/Wallet.js
@@ -140,10 +140,8 @@ Wallet.prototype._handleAddressBook = function(senderId, data, isInbound) {
var hasChange;
for (var key in rcv) {
if (!this.addressBook[key]) {
- this.addressBook[key] = rcv[key];
- hasChange = true;
- } else {
- if (rcv[key].createdTs > this.addressBook[key].createdTs) {
+ var isVerified = this.verifyAddressbookEntry(rcv[key], senderId, key);
+ if (isVerified) {
this.addressBook[key] = rcv[key];
hasChange = true;
}
@@ -235,7 +233,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);
@@ -839,23 +836,42 @@ Wallet.prototype._checkAddressBook = function(key) {
Wallet.prototype.setAddressBook = function(key, label) {
this._checkAddressBook(key);
- var addressbook = {
- createdTs: Date.now(),
- copayerId: this.getMyCopayerId(),
- label: label
+ var copayerId = this.getMyCopayerId();
+ var ts = Date.now();
+ var payload = {
+ address: key,
+ label: label,
+ copayerId: copayerId,
+ createdTs: ts
};
- this.addressBook[key] = addressbook;
+ var newEntry = {
+ hidden: false,
+ createdTs: ts,
+ copayerId: copayerId,
+ label: label,
+ signature: this.signJson(payload)
+ };
+ this.addressBook[key] = newEntry;
this.sendAddressBook();
this.store();
};
-Wallet.prototype.deleteAddressBook = function(key) {
- if (key) {
- this.addressBook[key].copayerId = -1;
- this.addressBook[key].createdTs = Date.now();
- this.sendAddressBook();
- this.store();
- }
+Wallet.prototype.verifyAddressbookEntry = function(rcvEntry, senderId, key) {
+ if (!key) throw new Error('Keys are required');
+ var signature = rcvEntry.signature;
+ var payload = {
+ address: key,
+ label: rcvEntry.label,
+ copayerId: rcvEntry.copayerId,
+ createdTs: rcvEntry.createdTs
+ };
+ return this.verifySignedJson(senderId, payload, signature);
+}
+
+Wallet.prototype.toggleAddressBookEntry = function(key) {
+ if (!key) throw new Error('Key is required');
+ this.addressBook[key].hidden = !this.addressBook[key].hidden;
+ this.store();
};
Wallet.prototype.isReady = function() {
@@ -868,4 +884,19 @@ Wallet.prototype.offerBackup = function() {
this.store();
};
+Wallet.prototype.signJson = 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.verifySignedJson = function(senderId, payload, signature) {
+ var pubkey = new Buffer(senderId, '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 3ba333d43..42991ed57 100644
--- a/test/test.Wallet.js
+++ b/test/test.Wallet.js
@@ -79,11 +79,13 @@ describe('Wallet model', function() {
label: 'John',
copayerId: '026a55261b7c898fff760ebe14fd22a71892295f3b49e0ca66727bc0a0d7f94d03',
createdTs: 1403102115,
+ hidden: false
},
'2MtP8WyiwG7ZdVWM96CVsk2M1N8zyfiVQsY': {
label: 'Jennifer',
copayerId: '032991f836543a492bd6d0bb112552bfc7c5f3b7d5388fcbcbf2fbb893b44770d7',
createdTs: 1403103115,
+ hidden: false
}
};
@@ -784,61 +786,119 @@ 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);
+ (function() {
+ w.toggleAddressBookEntry();
+ }).should.throw();
+ });
+
+ it('handle network addressBook correctly', function() {
+ var w = createW();
+
+ var data = {
+ type: "addressbook",
+ addressBook: {
+ "3Ae1ieAYNXznm7NkowoFTu5MkzgrTfDz8Z" : {
+ copayerId: "03baa45498fee1045fa8f91a2913f638dc3979b455498924d3cf1a11303c679cdb",
+ createdTs: 1404769393509,
+ hidden: false,
+ label: "adsf",
+ signature: "3046022100d4cdefef66ab8cea26031d5df03a38fc9ec9b09b0fb31d3a26b6e204918e9e78022100ecdbbd889ec99ea1bfd471253487af07a7fa7c0ac6012ca56e10e66f335e4586"
+ }
+ },
+ walletId: "11d23e638ed84c06",
+ isBroadcast: 1
+ };
+
+ var senderId = "03baa45498fee1045fa8f91a2913f638dc3979b455498924d3cf1a11303c679cdb";
+
+ Object.keys(w.addressBook).length.should.equal(2);
+ 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.signJson(payload));
+ });
+
+ it('should verify signed object', function() {
+ var w = createW();
+
+ var payload = {
+ address: "3Ae1ieAYNXznm7NkowoFTu5MkzgrTfDz8Z",
+ label: "adsf",
+ copayerId: "03baa45498fee1045fa8f91a2913f638dc3979b455498924d3cf1a11303c679cdb",
+ createdTs: 1404769393509
+ }
+
+ var signature = "3046022100d4cdefef66ab8cea26031d5df03a38fc9ec9b09b0fb31d3a26b6e204918e9e78022100ecdbbd889ec99ea1bfd471253487af07a7fa7c0ac6012ca56e10e66f335e4586";
+
+ var pubKey = "03baa45498fee1045fa8f91a2913f638dc3979b455498924d3cf1a11303c679cdb";
+
+ w.verifySignedJson(pubKey, payload, signature).should.equal(true);
+ payload.label = 'Another';
+ w.verifySignedJson(pubKey, payload, signature).should.equal(false);
+ });
+
+ it('should verify signed addressbook entry', function() {
+ var w = createW();
+ var key = "3Ae1ieAYNXznm7NkowoFTu5MkzgrTfDz8Z";
+ var pubKey = "03baa45498fee1045fa8f91a2913f638dc3979b455498924d3cf1a11303c679cdb";
+ w.addressBook[key] = {
+ copayerId: pubKey,
+ createdTs: 1404769393509,
+ hidden: false,
+ label: "adsf",
+ signature: "3046022100d4cdefef66ab8cea26031d5df03a38fc9ec9b09b0fb31d3a26b6e204918e9e78022100ecdbbd889ec99ea1bfd471253487af07a7fa7c0ac6012ca56e10e66f335e4586"
+ };
+
+ w.verifyAddressbookEntry(w.addressBook[key], pubKey, key).should.equal(true);
+ w.addressBook[key].label = 'Another';
+ w.verifyAddressbookEntry(w.addressBook[key], pubKey, key).should.equal(false);
+ (function() {
+ w.verifyAddressbookEntry();
+ }).should.throw();
});
- 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() {