Improve keychange notice reliability/perf
Bind a single listener to keychange events from the storage interface, which then looks up relevant conversations and adds notices to them, with tests. Previously we would need to instantiate a conversation model in order to start listening to its key change events. In practice this usually happens at startup but we shouldn't rely on it, and it incurs higher overhead since it creates a different listener for each conversation. // FREEBIE
This commit is contained in:
parent
787c393e1b
commit
aed5735620
8 changed files with 127 additions and 25 deletions
|
@ -659,6 +659,7 @@
|
|||
|
||||
<script type='text/javascript' src='js/wall_clock_listener.js'></script>
|
||||
<script type='text/javascript' src='js/rotate_signed_prekey_listener.js'></script>
|
||||
<script type='text/javascript' src='js/keychange_listener.js'></script>
|
||||
<script type='text/javascript' src='js/background.js'></script>
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
// start a background worker for ecc
|
||||
textsecure.startWorker('/js/libsignal-protocol-worker.js');
|
||||
Whisper.KeyChangeListener.init(textsecure.storage.protocol);
|
||||
|
||||
extension.onLaunched(function() {
|
||||
console.log('extension launched');
|
||||
|
|
|
@ -5,22 +5,6 @@
|
|||
'use strict';
|
||||
window.Whisper = window.Whisper || {};
|
||||
|
||||
var GroupCollection = Backbone.Collection.extend({
|
||||
database: Whisper.Database,
|
||||
storeName: 'conversations',
|
||||
model: Backbone.Model,
|
||||
fetchGroups: function(number) {
|
||||
return new Promise(function(resolve) {
|
||||
this.fetch({
|
||||
index: {
|
||||
name: 'group',
|
||||
only: number
|
||||
}
|
||||
}).always(resolve);
|
||||
}.bind(this));
|
||||
}
|
||||
});
|
||||
|
||||
Whisper.DeliveryReceipts = new (Backbone.Collection.extend({
|
||||
initialize: function() {
|
||||
this.on('add', this.onReceipt);
|
||||
|
@ -48,7 +32,7 @@
|
|||
});
|
||||
if (message) { return message; }
|
||||
|
||||
var groups = new GroupCollection();
|
||||
var groups = new Whisper.GroupCollection();
|
||||
return groups.fetchGroups(receipt.get('source')).then(function() {
|
||||
var ids = groups.pluck('id');
|
||||
ids.push(receipt.get('source'));
|
||||
|
|
30
js/keychange_listener.js
Normal file
30
js/keychange_listener.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* vim: ts=4:sw=4:expandtab
|
||||
*/
|
||||
|
||||
;(function () {
|
||||
'use strict';
|
||||
window.Whisper = window.Whisper || {};
|
||||
|
||||
Whisper.KeyChangeListener = {
|
||||
init: function(signalProtocolStore) {
|
||||
if (!(signalProtocolStore instanceof SignalProtocolStore)) {
|
||||
throw new Error('KeyChangeListener requires a SignalProtocolStore');
|
||||
}
|
||||
|
||||
signalProtocolStore.on('keychange', function(id) {
|
||||
var conversation = ConversationController.add({id: id});
|
||||
conversation.fetch().then(function() {
|
||||
conversation.addKeyChange(id);
|
||||
});
|
||||
var groups = new Whisper.GroupCollection();
|
||||
return groups.fetchGroups(id).then(function() {
|
||||
groups.each(function(conversation) {
|
||||
conversation = ConversationController.add(conversation);
|
||||
conversation.addKeyChange(id);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
}());
|
|
@ -46,13 +46,6 @@
|
|||
|
||||
this.on('change:avatar', this.updateAvatarUrl);
|
||||
this.on('destroy', this.revokeAvatarUrl);
|
||||
this.fetchContacts().then(function() {
|
||||
this.contactCollection.each(function(contact) {
|
||||
textsecure.storage.protocol.on('keychange:' + contact.id, function() {
|
||||
this.addKeyChange(contact.id);
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
addKeyChange: function(id) {
|
||||
|
@ -631,4 +624,21 @@
|
|||
});
|
||||
|
||||
Whisper.Conversation.COLORS = COLORS.concat(['grey', 'default']).join(' ');
|
||||
|
||||
// Special collection for fetching all the groups a certain number appears in
|
||||
Whisper.GroupCollection = Backbone.Collection.extend({
|
||||
database: Whisper.Database,
|
||||
storeName: 'conversations',
|
||||
model: Whisper.Conversation,
|
||||
fetchGroups: function(number) {
|
||||
return new Promise(function(resolve) {
|
||||
this.fetch({
|
||||
index: {
|
||||
name: 'group',
|
||||
only: number
|
||||
}
|
||||
}).always(resolve);
|
||||
}.bind(this));
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
|
|
@ -297,7 +297,7 @@
|
|||
this.removeIdentityKey(identifier).then(function() {
|
||||
this.saveIdentity(identifier, publicKey).then(function() {
|
||||
console.log('Key changed for', identifier);
|
||||
this.trigger('keychange:' + identifier);
|
||||
this.trigger('keychange', identifier);
|
||||
resolve(true);
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
|
|
|
@ -529,6 +529,7 @@
|
|||
<script type="text/javascript" src="../js/conversation_controller.js" data-cover></script>
|
||||
<script type="text/javascript" src="../js/panel_controller.js"></script>
|
||||
<script type='text/javascript' src='../js/emoji_util.js'></script>
|
||||
<script type="text/javascript" src="../js/keychange_listener.js"></script>
|
||||
|
||||
<script type="text/javascript" src="../js/chromium.js"></script>
|
||||
|
||||
|
@ -574,6 +575,7 @@
|
|||
<script type="text/javascript" src="models/conversations_test.js"></script>
|
||||
<script type="text/javascript" src="models/messages_test.js"></script>
|
||||
<script type="text/javascript" src="storage_test.js"></script>
|
||||
<script type="text/javascript" src="keychange_listener_test.js"></script>
|
||||
|
||||
<script type="text/javascript" src="fixtures.js"></script>
|
||||
<script type="text/javascript" src="fixtures_test.js"></script>
|
||||
|
|
74
test/keychange_listener_test.js
Normal file
74
test/keychange_listener_test.js
Normal file
|
@ -0,0 +1,74 @@
|
|||
describe('KeyChangeListener', function() {
|
||||
var phone_number_with_keychange = '+13016886524'; // nsa
|
||||
var oldkey = libsignal.crypto.getRandomBytes(33);
|
||||
var newkey = libsignal.crypto.getRandomBytes(33);
|
||||
var store;
|
||||
|
||||
before(function() {
|
||||
storage.put('safety-numbers-approval', false);
|
||||
});
|
||||
|
||||
after(function() {
|
||||
storage.remove('safety-numbers-approval');
|
||||
});
|
||||
|
||||
beforeEach(function() {
|
||||
store = new SignalProtocolStore();
|
||||
Whisper.KeyChangeListener.init(store);
|
||||
return store.saveIdentity(phone_number_with_keychange, oldkey);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
return store.removeIdentityKey(phone_number_with_keychange);
|
||||
});
|
||||
|
||||
describe('When we have a conversation with this contact', function() {
|
||||
var convo = new Whisper.Conversation({ id: phone_number_with_keychange, type: 'private'});
|
||||
before(function() {
|
||||
ConversationController.add(convo);
|
||||
return new Promise(function(resolve) { convo.save().then(resolve); });
|
||||
});
|
||||
|
||||
after(function() {
|
||||
convo.destroyMessages();
|
||||
return convo.destroy();
|
||||
});
|
||||
|
||||
it('generates a key change notice in the private conversation with this contact', function(done) {
|
||||
convo.on('newmessage', function() {
|
||||
return convo.fetchMessages().then(function() {
|
||||
var message = convo.messageCollection.at(0);
|
||||
assert.strictEqual(message.get('type'), 'keychange');
|
||||
done();
|
||||
});
|
||||
});
|
||||
return store.isTrustedIdentity(phone_number_with_keychange, newkey);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('When we have a group with this contact', function() {
|
||||
var convo = new Whisper.Conversation({ id: 'groupId', type: 'group', members: [phone_number_with_keychange] });
|
||||
before(function() {
|
||||
ConversationController.add(convo);
|
||||
return convo.save();
|
||||
});
|
||||
after(function() {
|
||||
convo.destroyMessages();
|
||||
return convo.destroy();
|
||||
});
|
||||
|
||||
it('generates a key change notice in the group conversation with this contact', function(done) {
|
||||
convo.on('newmessage', function() {
|
||||
return convo.fetchMessages().then(function() {
|
||||
var message = convo.messageCollection.at(0);
|
||||
assert.strictEqual(message.get('type'), 'keychange');
|
||||
done();
|
||||
});
|
||||
});
|
||||
return store.isTrustedIdentity(phone_number_with_keychange, newkey);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
Loading…
Add table
Reference in a new issue