Test that device lists can get updated via PEP
Fix various bugs in the process. updates #497
This commit is contained in:
parent
41db49ffca
commit
ddd0ef8e20
@ -320,52 +320,54 @@
|
||||
[{'category': 'pubsub', 'type': 'pep'}],
|
||||
['http://jabber.org/protocol/pubsub#publish-options']
|
||||
).then(function () {
|
||||
test_utils.waitUntil(function () {
|
||||
return _converse.bookmarks;
|
||||
}, 300).then(function () {
|
||||
/* The stored data is automatically pushed to all of the user's
|
||||
* connected resources.
|
||||
*
|
||||
* Publisher receives event notification
|
||||
* -------------------------------------
|
||||
* <message from='juliet@capulet.lit'
|
||||
* to='juliet@capulet.lit/balcony'
|
||||
* type='headline'
|
||||
* id='rnfoo1'>
|
||||
* <event xmlns='http://jabber.org/protocol/pubsub#event'>
|
||||
* <items node='storage:bookmarks'>
|
||||
* <item id='current'>
|
||||
* <storage xmlns='storage:bookmarks'>
|
||||
* <conference name='The Play's the Thing'
|
||||
* autojoin='true'
|
||||
* jid='theplay@conference.shakespeare.lit'>
|
||||
* <nick>JC</nick>
|
||||
* </conference>
|
||||
* </storage>
|
||||
* </item>
|
||||
* </items>
|
||||
* </event>
|
||||
* </message>
|
||||
*/
|
||||
var stanza = $msg({
|
||||
'from': 'dummy@localhost',
|
||||
'to': 'dummy@localhost/resource',
|
||||
'type': 'headline',
|
||||
'id': 'rnfoo1'
|
||||
}).c('event', {'xmlns': 'http://jabber.org/protocol/pubsub#event'})
|
||||
.c('items', {'node': 'storage:bookmarks'})
|
||||
.c('item', {'id': 'current'})
|
||||
.c('storage', {'xmlns': 'storage:bookmarks'})
|
||||
.c('conference', {'name': 'The Play's the Thing',
|
||||
'autojoin': 'true',
|
||||
'jid':'theplay@conference.shakespeare.lit'})
|
||||
.c('nick').t('JC');
|
||||
return test_utils.waitUntil(() => _converse.bookmarks);
|
||||
}).then(function () {
|
||||
// Emit here instead of mocking fetching of bookmarks.
|
||||
_converse.emit('bookmarksInitialized');
|
||||
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
expect(_converse.bookmarks.length).toBe(1);
|
||||
expect(_converse.chatboxviews.get('theplay@conference.shakespeare.lit')).not.toBeUndefined();
|
||||
done();
|
||||
});
|
||||
/* The stored data is automatically pushed to all of the user's
|
||||
* connected resources.
|
||||
*
|
||||
* Publisher receives event notification
|
||||
* -------------------------------------
|
||||
* <message from='juliet@capulet.lit'
|
||||
* to='juliet@capulet.lit/balcony'
|
||||
* type='headline'
|
||||
* id='rnfoo1'>
|
||||
* <event xmlns='http://jabber.org/protocol/pubsub#event'>
|
||||
* <items node='storage:bookmarks'>
|
||||
* <item id='current'>
|
||||
* <storage xmlns='storage:bookmarks'>
|
||||
* <conference name='The Play's the Thing'
|
||||
* autojoin='true'
|
||||
* jid='theplay@conference.shakespeare.lit'>
|
||||
* <nick>JC</nick>
|
||||
* </conference>
|
||||
* </storage>
|
||||
* </item>
|
||||
* </items>
|
||||
* </event>
|
||||
* </message>
|
||||
*/
|
||||
var stanza = $msg({
|
||||
'from': 'dummy@localhost',
|
||||
'to': 'dummy@localhost/resource',
|
||||
'type': 'headline',
|
||||
'id': 'rnfoo1'
|
||||
}).c('event', {'xmlns': 'http://jabber.org/protocol/pubsub#event'})
|
||||
.c('items', {'node': 'storage:bookmarks'})
|
||||
.c('item', {'id': 'current'})
|
||||
.c('storage', {'xmlns': 'storage:bookmarks'})
|
||||
.c('conference', {'name': 'The Play's the Thing',
|
||||
'autojoin': 'true',
|
||||
'jid':'theplay@conference.shakespeare.lit'})
|
||||
.c('nick').t('JC');
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
return test_utils.waitUntil(() => _converse.bookmarks.length);
|
||||
}).then(function () {
|
||||
expect(_converse.bookmarks.length).toBe(1);
|
||||
expect(_converse.chatboxviews.get('theplay@conference.shakespeare.lit')).not.toBeUndefined();
|
||||
done();
|
||||
});
|
||||
}));
|
||||
|
||||
|
164
spec/omemo.js
164
spec/omemo.js
@ -4,6 +4,7 @@
|
||||
var Strophe = converse.env.Strophe;
|
||||
var b64_sha1 = converse.env.b64_sha1;
|
||||
var $iq = converse.env.$iq;
|
||||
var $msg = converse.env.$msg;
|
||||
var _ = converse.env._;
|
||||
var u = converse.env.utils;
|
||||
|
||||
@ -17,6 +18,165 @@
|
||||
done();
|
||||
}));
|
||||
|
||||
it("updates the user's device list based on PEP messages",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
let iq_stanza;
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
const contact_jid = mock.cur_names[3].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
|
||||
test_utils.waitUntil(function () {
|
||||
return _.filter(
|
||||
_converse.connection.IQ_stanzas,
|
||||
(iq) => {
|
||||
const node = iq.nodeTree.querySelector('iq[to="'+_converse.bare_jid+'"] query[node="eu.siacs.conversations.axolotl.devicelist"]');
|
||||
if (node) { iq_stanza = iq.nodeTree;}
|
||||
return node;
|
||||
}).length;
|
||||
}).then(function () {
|
||||
expect(iq_stanza.outerHTML).toBe(
|
||||
'<iq type="get" from="dummy@localhost" to="dummy@localhost" xmlns="jabber:client" id="'+iq_stanza.getAttribute("id")+'">'+
|
||||
'<query xmlns="http://jabber.org/protocol/disco#items" '+
|
||||
'node="eu.siacs.conversations.axolotl.devicelist"/>'+
|
||||
'</iq>');
|
||||
|
||||
const stanza = $iq({
|
||||
'from': contact_jid,
|
||||
'id': iq_stanza.getAttribute('id'),
|
||||
'to': _converse.bare_jid,
|
||||
'type': 'result',
|
||||
}).c('query', {
|
||||
'xmlns': 'http://jabber.org/protocol/disco#items',
|
||||
'node': 'eu.siacs.conversations.axolotl.devicelist'
|
||||
}).c('device', {'id': '555'}).up()
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
expect(_converse.devicelists.length).toBe(1);
|
||||
const devicelist = _converse.devicelists.get(_converse.bare_jid);
|
||||
expect(devicelist.devices.length).toBe(1);
|
||||
expect(devicelist.devices.at(0).get('id')).toBe('555');
|
||||
return test_utils.waitUntil(() => _converse.devicelists);
|
||||
}).then(function () {
|
||||
// We simply emit, to avoid doing all the setup work
|
||||
_converse.emit('OMEMOInitialized');
|
||||
|
||||
let stanza = $msg({
|
||||
'from': contact_jid,
|
||||
'to': _converse.bare_jid,
|
||||
'type': 'headline',
|
||||
'id': 'update_01',
|
||||
}).c('event', {'xmlns': 'http://jabber.org/protocol/pubsub#event'})
|
||||
.c('items', {'node': 'eu.siacs.conversations.axolotl.devicelist'})
|
||||
.c('item')
|
||||
.c('list', {'xmlns': 'eu.siacs.conversations.axolotl'})
|
||||
.c('device', {'id': '1234'})
|
||||
.c('device', {'id': '4223'})
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
expect(_converse.devicelists.length).toBe(2);
|
||||
let devices = _converse.devicelists.get(contact_jid).devices;
|
||||
expect(devices.length).toBe(2);
|
||||
expect(_.map(devices.models, 'attributes.id').sort().join()).toBe('1234,4223');
|
||||
expect(devices.get('1234').get('active')).toBe(true);
|
||||
expect(devices.get('4223').get('active')).toBe(true);
|
||||
|
||||
stanza = $msg({
|
||||
'from': contact_jid,
|
||||
'to': _converse.bare_jid,
|
||||
'type': 'headline',
|
||||
'id': 'update_02',
|
||||
}).c('event', {'xmlns': 'http://jabber.org/protocol/pubsub#event'})
|
||||
.c('items', {'node': 'eu.siacs.conversations.axolotl.devicelist'})
|
||||
.c('item')
|
||||
.c('list', {'xmlns': 'eu.siacs.conversations.axolotl'})
|
||||
.c('device', {'id': '4223'})
|
||||
.c('device', {'id': '4224'})
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
expect(_converse.devicelists.length).toBe(2);
|
||||
expect(devices.length).toBe(3);
|
||||
expect(_.map(devices.models, 'attributes.id').sort().join()).toBe('1234,4223,4224');
|
||||
expect(devices.get('1234').get('active')).toBe(false);
|
||||
expect(devices.get('4223').get('active')).toBe(true);
|
||||
expect(devices.get('4224').get('active')).toBe(true);
|
||||
|
||||
// Check that own devicelist gets updated
|
||||
stanza = $msg({
|
||||
'from': _converse.bare_jid,
|
||||
'to': _converse.bare_jid,
|
||||
'type': 'headline',
|
||||
'id': 'update_03',
|
||||
}).c('event', {'xmlns': 'http://jabber.org/protocol/pubsub#event'})
|
||||
.c('items', {'node': 'eu.siacs.conversations.axolotl.devicelist'})
|
||||
.c('item')
|
||||
.c('list', {'xmlns': 'eu.siacs.conversations.axolotl'})
|
||||
.c('device', {'id': '555'})
|
||||
.c('device', {'id': '777'})
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
expect(_converse.devicelists.length).toBe(2);
|
||||
devices = _converse.devicelists.get(_converse.bare_jid).devices;
|
||||
expect(devices.length).toBe(3);
|
||||
expect(_.map(devices.models, 'attributes.id').sort().join()).toBe('123456789,555,777');
|
||||
expect(devices.get('123456789').get('active')).toBe(true);
|
||||
expect(devices.get('555').get('active')).toBe(true);
|
||||
expect(devices.get('777').get('active')).toBe(true);
|
||||
|
||||
_converse.connection.IQ_stanzas = [];
|
||||
|
||||
// Check that own device gets re-added
|
||||
stanza = $msg({
|
||||
'from': _converse.bare_jid,
|
||||
'to': _converse.bare_jid,
|
||||
'type': 'headline',
|
||||
'id': 'update_03',
|
||||
}).c('event', {'xmlns': 'http://jabber.org/protocol/pubsub#event'})
|
||||
.c('items', {'node': 'eu.siacs.conversations.axolotl.devicelist'})
|
||||
.c('item')
|
||||
.c('list', {'xmlns': 'eu.siacs.conversations.axolotl'})
|
||||
.c('device', {'id': '444'})
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
return test_utils.waitUntil(function () {
|
||||
return _.filter(
|
||||
_converse.connection.IQ_stanzas,
|
||||
(iq) => {
|
||||
const node = iq.nodeTree.querySelector('iq[from="'+_converse.bare_jid+'"] publish[node="eu.siacs.conversations.axolotl.devicelist"]');
|
||||
if (node) { iq_stanza = iq.nodeTree;}
|
||||
return node;
|
||||
}).length;
|
||||
});
|
||||
}).then(function () {
|
||||
// Check that our own device is added again, but that removed
|
||||
// devices are not added.
|
||||
expect(iq_stanza.outerHTML).toBe(
|
||||
'<iq from="dummy@localhost" type="set" xmlns="jabber:client" id="'+iq_stanza.getAttribute('id')+'">'+
|
||||
'<pubsub xmlns="http://jabber.org/protocol/pubsub">'+
|
||||
'<publish node="eu.siacs.conversations.axolotl.devicelist">'+
|
||||
'<item>'+
|
||||
'<list xmlns="eu.siacs.conversations.axolotl"/>'+
|
||||
'<device id="123456789"/>'+
|
||||
'<device id="444"/>'+
|
||||
'</item>'+
|
||||
'</publish>'+
|
||||
'</pubsub>'+
|
||||
'</iq>');
|
||||
expect(_converse.devicelists.length).toBe(2);
|
||||
const devices = _converse.devicelists.get(_converse.bare_jid).devices;
|
||||
// The device id for this device (123456789) was also generated and added to the list,
|
||||
// which is why we have 4 devices now.
|
||||
expect(devices.length).toBe(4);
|
||||
expect(_.map(devices.models, 'attributes.id').sort().join()).toBe('123456789,444,555,777');
|
||||
expect(devices.get('123456789').get('active')).toBe(true);
|
||||
expect(devices.get('444').get('active')).toBe(true);
|
||||
expect(devices.get('555').get('active')).toBe(false);
|
||||
expect(devices.get('777').get('active')).toBe(false);
|
||||
done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("adds a toolbar button for starting an encrypted chat session",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
@ -60,7 +220,7 @@
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
return test_utils.waitUntil(() => {
|
||||
return _.filter(_converse.connection.IQ_stanzas, function (iq) {
|
||||
const node = iq.nodeTree.querySelector('publish[xmlns="eu.siacs.conversations.axolotl.devicelist"]');
|
||||
const node = iq.nodeTree.querySelector('publish[node="eu.siacs.conversations.axolotl.devicelist"]');
|
||||
if (node) { iq_stanza = iq.nodeTree; }
|
||||
return node;
|
||||
}).length;
|
||||
@ -69,7 +229,7 @@
|
||||
expect(iq_stanza.outerHTML).toBe(
|
||||
'<iq from="dummy@localhost" type="set" xmlns="jabber:client" id="'+iq_stanza.getAttribute('id')+'">'+
|
||||
'<pubsub xmlns="http://jabber.org/protocol/pubsub">'+
|
||||
'<publish xmlns="eu.siacs.conversations.axolotl.devicelist">'+
|
||||
'<publish node="eu.siacs.conversations.axolotl.devicelist">'+
|
||||
'<item>'+
|
||||
'<list xmlns="eu.siacs.conversations.axolotl"/>'+
|
||||
'<device id="482886413b977930064a5888b92134fe"/>'+
|
||||
|
@ -579,8 +579,10 @@
|
||||
// Add a handler for bookmarks pushed from other connected clients
|
||||
// (from the same user obviously)
|
||||
_converse.connection.addHandler((message) => {
|
||||
if (message.querySelector('event[xmlns="'+Strophe.NS.PUBSUB+'#event"]')) {
|
||||
_converse.bookmarks.createBookmarksFromStanza(message);
|
||||
if (sizzle('event[xmlns="'+Strophe.NS.PUBSUB+'#event"] items[node="storage:bookmarks"]', message).length) {
|
||||
_converse.api.waitUntil('bookmarksInitialized')
|
||||
.then(() => _converse.bookmarks.createBookmarksFromStanza(message))
|
||||
.catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
||||
}
|
||||
}, null, 'message', 'headline', null, _converse.bare_jid);
|
||||
});
|
||||
|
@ -519,11 +519,11 @@
|
||||
'from': _converse.bare_jid,
|
||||
'type': 'set'
|
||||
}).c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
|
||||
.c('publish', {'xmlns': Strophe.NS.OMEMO_DEVICELIST})
|
||||
.c('publish', {'node': Strophe.NS.OMEMO_DEVICELIST})
|
||||
.c('item')
|
||||
.c('list', {'xmlns': Strophe.NS.OMEMO}).up()
|
||||
|
||||
this.devices.each((device) => {
|
||||
_.each(this.devices.where({'active': true}), (device) => {
|
||||
stanza.c('device', {'id': device.get('id')}).up();
|
||||
});
|
||||
_converse.connection.sendIQ(stanza, resolve, reject, _converse.IQ_TIMEOUT);
|
||||
@ -584,48 +584,59 @@
|
||||
/* If our own device is not on the list, add it.
|
||||
* Also, deduplicate devices if necessary.
|
||||
*/
|
||||
return new Promise((resolve, reject) => {
|
||||
restoreOMEMOSession().then(() => {
|
||||
const devicelist = _converse.devicelists.get(_converse.bare_jid);
|
||||
const device_id = _converse.omemo_store.get('device_id');
|
||||
if (!devicelist.devices.findWhere({'id': device_id})) {
|
||||
return devicelist.addDeviceToList(device_id).then(resolve).catch(reject);
|
||||
}
|
||||
resolve();
|
||||
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
|
||||
});
|
||||
const devicelist = _converse.devicelists.get(_converse.bare_jid),
|
||||
device_id = _converse.omemo_store.get('device_id'),
|
||||
own_device = devicelist.devices.findWhere({'id': device_id});
|
||||
|
||||
if (!own_device) {
|
||||
return devicelist.addDeviceToList(device_id);
|
||||
} else if (!own_device.get('active')) {
|
||||
own_device.set('active', true, {'silent': true});
|
||||
return devicelist.addDeviceToList(device_id);
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function updateBundleFromStanza (stanza) {
|
||||
const items_el = sizzle(`items[node="${Strophe.NS.OMEMO_BUNDLES}"]`, stanza),
|
||||
device_id = items_el.getAttribute('node').split(':')[1],
|
||||
const items_el = sizzle(`items[node="${Strophe.NS.OMEMO_BUNDLES}"]`, stanza).pop();
|
||||
if (!items_el) {
|
||||
return;
|
||||
}
|
||||
const device_id = items_el.getAttribute('node').split(':')[1],
|
||||
from = stanza.getAttribute('from'),
|
||||
bundle_el = sizzle(`item list[xmlns="${Strophe.NS.OMEMO}"] bundle`, items_el).pop(),
|
||||
bundle = parseBundle(bundle_el);
|
||||
|
||||
const device = _converse.devicelists.get(from).devices.get(device_id);
|
||||
device.save({'bundle': bundle});
|
||||
device = _converse.devicelists.get(from).devices.get(device_id);
|
||||
device.save({'bundle': parseBundle(bundle_el)});
|
||||
}
|
||||
|
||||
function updateDevicesFromStanza (stanza) {
|
||||
// TODO: check whether our own device_id is still on the list,
|
||||
// otherwise we need to update it.
|
||||
const items_el = sizzle(`items[node="${Strophe.NS.OMEMO_DEVICELIST}"]`, stanza).pop();
|
||||
if (!items_el) {
|
||||
return;
|
||||
}
|
||||
const device_ids = _.map(
|
||||
sizzle(`items[node="${Strophe.NS.OMEMO_DEVICELIST}"] item list[xmlns="${Strophe.NS.OMEMO}"] device`, stanza),
|
||||
(device) => device.getAttribute('id'));
|
||||
|
||||
const removed_ids = _.difference(_converse.devices.pluck('id'), device_ids);
|
||||
_.forEach(removed_ids, (removed_id) => _converse.devices.get(removed_id).set('active', false));
|
||||
sizzle(`item list[xmlns="${Strophe.NS.OMEMO}"] device`, items_el),
|
||||
(device) => device.getAttribute('id')
|
||||
);
|
||||
const jid = stanza.getAttribute('from'),
|
||||
devicelist = _converse.devicelists.get(jid) || _converse.devicelists.create({'jid': jid}),
|
||||
devices = devicelist.devices,
|
||||
removed_ids = _.difference(devices.pluck('id'), device_ids);
|
||||
|
||||
_.forEach(removed_ids, (removed_id) => devices.get(removed_id).set('active', false));
|
||||
_.forEach(device_ids, (device_id) => {
|
||||
const dev = _converse.devices.get(device_id);
|
||||
const dev = devices.get(device_id);
|
||||
if (dev) {
|
||||
dev.save({'active': true});
|
||||
} else {
|
||||
_converse.devices.create({'id': device_id})
|
||||
devices.create({'id': device_id})
|
||||
}
|
||||
});
|
||||
// Make sure our own device is on the list (i.e. if it was
|
||||
// removed, add it again.
|
||||
updateOwnDeviceList();
|
||||
}
|
||||
|
||||
function registerPEPPushHandler () {
|
||||
@ -634,9 +645,9 @@
|
||||
if (message.querySelector('event[xmlns="'+Strophe.NS.PUBSUB+'#event"]')) {
|
||||
updateDevicesFromStanza(message);
|
||||
updateBundleFromStanza(message);
|
||||
updateOwnDeviceList();
|
||||
}
|
||||
}, null, 'message', 'headline', null, _converse.bare_jid);
|
||||
return true;
|
||||
}, null, 'message', 'headline');
|
||||
}
|
||||
|
||||
function restoreOMEMOSession () {
|
||||
@ -655,6 +666,7 @@
|
||||
b64_sha1(`converse.devicelists-${_converse.bare_jid}`)
|
||||
);
|
||||
fetchOwnDevices()
|
||||
.then(() => restoreOMEMOSession())
|
||||
.then(() => updateOwnDeviceList())
|
||||
.then(() => publishBundle())
|
||||
.then(() => _converse.emit('OMEMOInitialized'))
|
||||
|
Loading…
Reference in New Issue
Block a user