Test that bundles can be updated via PEP
Fix bugs in the process udpates #497
This commit is contained in:
parent
ddd0ef8e20
commit
d484320c09
148
spec/omemo.js
148
spec/omemo.js
|
@ -18,7 +18,7 @@
|
|||
done();
|
||||
}));
|
||||
|
||||
it("updates the user's device list based on PEP messages",
|
||||
it("updates device lists based on PEP messages",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
@ -131,7 +131,7 @@
|
|||
'from': _converse.bare_jid,
|
||||
'to': _converse.bare_jid,
|
||||
'type': 'headline',
|
||||
'id': 'update_03',
|
||||
'id': 'update_04',
|
||||
}).c('event', {'xmlns': 'http://jabber.org/protocol/pubsub#event'})
|
||||
.c('items', {'node': 'eu.siacs.conversations.axolotl.devicelist'})
|
||||
.c('item')
|
||||
|
@ -177,6 +177,150 @@
|
|||
});
|
||||
}));
|
||||
|
||||
it("updates device bundles 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);
|
||||
return test_utils.waitUntil(() => _converse.devicelists);
|
||||
}).then(function () {
|
||||
// We simply emit, to avoid doing all the setup work
|
||||
expect(_converse.devicelists.length).toBe(1);
|
||||
let devicelist = _converse.devicelists.get(_converse.bare_jid);
|
||||
expect(devicelist.devices.length).toBe(2);
|
||||
expect(devicelist.devices.at(0).get('id')).toBe('555');
|
||||
expect(devicelist.devices.at(1).get('id')).toBe('123456789');
|
||||
_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.bundles:555'})
|
||||
.c('item')
|
||||
.c('bundle', {'xmlns': 'eu.siacs.conversations.axolotl'})
|
||||
.c('signedPreKeyPublic', {'signedPreKeyId': '4223'}).t('1111').up()
|
||||
.c('signedPreKeySignature').t('2222').up()
|
||||
.c('identityKey').t('3333').up()
|
||||
.c('prekeys')
|
||||
.c('preKeyPublic', {'preKeyId': '1001'}).up()
|
||||
.c('preKeyPublic', {'preKeyId': '1002'}).up()
|
||||
.c('preKeyPublic', {'preKeyId': '1003'});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
expect(_converse.devicelists.length).toBe(2);
|
||||
devicelist = _converse.devicelists.get(contact_jid);
|
||||
expect(devicelist.devices.length).toBe(1);
|
||||
let device = devicelist.devices.at(0);
|
||||
expect(device.get('bundle').identity_key).toBe(3333);
|
||||
expect(device.get('bundle').signed_prekey.public_key).toBe('1111');
|
||||
expect(device.get('bundle').signed_prekey.id).toBe(4223);
|
||||
expect(device.get('bundle').signed_prekey.signature).toBe('2222');
|
||||
expect(device.get('bundle').prekeys.length).toBe(3);
|
||||
expect(device.get('bundle').prekeys[0].id).toBe(1001);
|
||||
expect(device.get('bundle').prekeys[1].id).toBe(1002);
|
||||
expect(device.get('bundle').prekeys[2].id).toBe(1003);
|
||||
|
||||
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.bundles:555'})
|
||||
.c('item')
|
||||
.c('bundle', {'xmlns': 'eu.siacs.conversations.axolotl'})
|
||||
.c('signedPreKeyPublic', {'signedPreKeyId': '4223'}).t('5555').up()
|
||||
.c('signedPreKeySignature').t('6666').up()
|
||||
.c('identityKey').t('7777').up()
|
||||
.c('prekeys')
|
||||
.c('preKeyPublic', {'preKeyId': '2001'}).up()
|
||||
.c('preKeyPublic', {'preKeyId': '2002'}).up()
|
||||
.c('preKeyPublic', {'preKeyId': '2003'});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
expect(_converse.devicelists.length).toBe(2);
|
||||
devicelist = _converse.devicelists.get(contact_jid);
|
||||
expect(devicelist.devices.length).toBe(1);
|
||||
device = devicelist.devices.at(0);
|
||||
expect(device.get('bundle').identity_key).toBe(7777);
|
||||
expect(device.get('bundle').signed_prekey.public_key).toBe('5555');
|
||||
expect(device.get('bundle').signed_prekey.id).toBe(4223);
|
||||
expect(device.get('bundle').signed_prekey.signature).toBe('6666');
|
||||
expect(device.get('bundle').prekeys.length).toBe(3);
|
||||
expect(device.get('bundle').prekeys[0].id).toBe(2001);
|
||||
expect(device.get('bundle').prekeys[1].id).toBe(2002);
|
||||
expect(device.get('bundle').prekeys[2].id).toBe(2003);
|
||||
|
||||
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.bundles:123456789'})
|
||||
.c('item')
|
||||
.c('bundle', {'xmlns': 'eu.siacs.conversations.axolotl'})
|
||||
.c('signedPreKeyPublic', {'signedPreKeyId': '9999'}).t('8888').up()
|
||||
.c('signedPreKeySignature').t('3333').up()
|
||||
.c('identityKey').t('1111').up()
|
||||
.c('prekeys')
|
||||
.c('preKeyPublic', {'preKeyId': '3001'}).up()
|
||||
.c('preKeyPublic', {'preKeyId': '3002'}).up()
|
||||
.c('preKeyPublic', {'preKeyId': '3003'});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
expect(_converse.devicelists.length).toBe(2);
|
||||
devicelist = _converse.devicelists.get(_converse.bare_jid);
|
||||
expect(devicelist.devices.length).toBe(2);
|
||||
expect(devicelist.devices.at(0).get('id')).toBe('555');
|
||||
expect(devicelist.devices.at(1).get('id')).toBe('123456789');
|
||||
device = devicelist.devices.at(1);
|
||||
expect(device.get('bundle').identity_key).toBe(1111);
|
||||
expect(device.get('bundle').signed_prekey.public_key).toBe('8888');
|
||||
expect(device.get('bundle').signed_prekey.id).toBe(9999);
|
||||
expect(device.get('bundle').signed_prekey.signature).toBe('3333');
|
||||
expect(device.get('bundle').prekeys.length).toBe(3);
|
||||
expect(device.get('bundle').prekeys[0].id).toBe(3001);
|
||||
expect(device.get('bundle').prekeys[1].id).toBe(3002);
|
||||
expect(device.get('bundle').prekeys[2].id).toBe(3003);
|
||||
done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("adds a toolbar button for starting an encrypted chat session",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
|
|
|
@ -54,23 +54,23 @@
|
|||
* and return a map.
|
||||
*/
|
||||
const signed_prekey_public_el = bundle_el.querySelector('signedPreKeyPublic'),
|
||||
signed_prekey_signature_el = bundle_el.querySelector('signedPreKeySignature'),
|
||||
identity_key_el = bundle_el.querySelector('identityKey');
|
||||
signed_prekey_signature_el = bundle_el.querySelector('signedPreKeySignature'),
|
||||
identity_key_el = bundle_el.querySelector('identityKey');
|
||||
|
||||
const prekeys = _.map(
|
||||
sizzle(`> prekeys > preKeyPublic`, bundle_el),
|
||||
sizzle(`prekeys > preKeyPublic`, bundle_el),
|
||||
(el) => {
|
||||
return {
|
||||
'id': parseInt(el.getAttribute('keyId'), 10),
|
||||
'key': u.base64ToArrayBuffer(el.textContent)
|
||||
'id': parseInt(el.getAttribute('preKeyId'), 10),
|
||||
'key': el.textContent
|
||||
}
|
||||
});
|
||||
return {
|
||||
'identity_key': bundle_el.querySelector('> identityKey').textContent,
|
||||
'identity_key': parseInt(bundle_el.querySelector('identityKey').textContent, 10),
|
||||
'signed_prekey': {
|
||||
'id': parseInt(signed_prekey_public_el.getAttribute('signedPreKeyId'), 10),
|
||||
'public_key': u.base64ToArrayBuffer(signed_prekey_public_el.textContent),
|
||||
'signature': u.base64ToArrayBuffer(signed_prekey_signature_el.textContent)
|
||||
'public_key': signed_prekey_public_el.textContent,
|
||||
'signature': signed_prekey_signature_el.textContent
|
||||
},
|
||||
'prekeys': prekeys
|
||||
}
|
||||
|
@ -89,49 +89,15 @@
|
|||
|
||||
ChatBox: {
|
||||
|
||||
parseBundleFromIQ (device_id, stanza) {
|
||||
const publish_el = sizzle(`items[node="${Strophe.NS.OMEMO_BUNDLES}:${device_id}"]`, stanza).pop();
|
||||
const bundle_el = sizzle(`bundle[xmlns="${Strophe.NS.OMEMO}"]`, publish_el).pop();
|
||||
return parseBundle(bundle_el);
|
||||
},
|
||||
|
||||
fetchBundle (device_id) {
|
||||
const { _converse } = this.__super__,
|
||||
device = _converse.devicelists.get(this.get('jid')).devices.get(device_id);
|
||||
|
||||
if (device.get('bundle')) {
|
||||
return Promise.resolve(device.get('bundle').toJSON());
|
||||
} else {
|
||||
return new Promise((resolve, reject) => {
|
||||
const stanza = $iq({
|
||||
'type': 'get',
|
||||
'from': _converse.bare_jid,
|
||||
'to': this.get('jid')
|
||||
}).c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
|
||||
.c('items', {'xmlns': `${Strophe.NS.OMEMO_BUNDLES}:${device_id}`});
|
||||
_converse.connection.sendIQ(
|
||||
stanza,
|
||||
(iq) => {
|
||||
const bundle = this.parseBundleFromIQ(iq);
|
||||
bundle.device_id = device_id;
|
||||
resolve(bundle);
|
||||
},
|
||||
reject,
|
||||
_converse.IQ_TIMEOUT
|
||||
);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
fetchBundlesAndBuildSessions () {
|
||||
getBundlesAndBuildSessions () {
|
||||
const { _converse } = this.__super__;
|
||||
return new Promise((resolve, reject) => {
|
||||
getDevicesForContact(this.get('jid'))
|
||||
.then((devices) => {
|
||||
const bundle_promises = _.map(devices, (device_id) => this.fetchBundle(device_id));
|
||||
Promise.all(bundle_promises).then(() => {
|
||||
const promises = _.map(devices, (device) => device.getBundle());
|
||||
Promise.all(promises).then(() => {
|
||||
this.buildSessions(devices)
|
||||
.then(() => resolve(bundles))
|
||||
.then(() => resolve(devices))
|
||||
.catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
|
||||
|
||||
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
|
||||
|
@ -145,7 +111,7 @@
|
|||
|
||||
return Promise.all(_.map(devices, (device) => {
|
||||
const recipient_id = device['id'];
|
||||
const address = new libsignal.SignalProtocolAddress(recipient_id, device_id);
|
||||
const address = new libsignal.SignalProtocolAddress(parseInt(recipient_id, 10), device_id);
|
||||
const sessionBuilder = new libsignal.SessionBuilder(_converse.omemo_store, address);
|
||||
return sessionBuilder.processPreKey({
|
||||
'registrationId': _converse.omemo_store.get('registration_id'),
|
||||
|
@ -201,7 +167,7 @@
|
|||
|
||||
createMessageStanza (message) {
|
||||
if (this.get('omemo_active')) {
|
||||
return this.fetchBundlesAndBuildSessions()
|
||||
return this.getBundlesAndBuildSessions()
|
||||
.then((bundles) => this.createOMEMOMessageStanza(message, bundles));
|
||||
} else {
|
||||
return Promise.resolve(this.__super__.createMessageStanza.apply(this, arguments));
|
||||
|
@ -449,6 +415,39 @@
|
|||
defaults: {
|
||||
'active': true,
|
||||
'trusted': UNDECIDED
|
||||
},
|
||||
|
||||
fetchBundleFromServer () {
|
||||
return new Promise((resolve, reject) => {
|
||||
const stanza = $iq({
|
||||
'type': 'get',
|
||||
'from': _converse.bare_jid,
|
||||
'to': this.get('jid')
|
||||
}).c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
|
||||
.c('items', {'xmlns': `${Strophe.NS.OMEMO_BUNDLES}:${this.get('id')}`});
|
||||
_converse.connection.sendIQ(
|
||||
stanza,
|
||||
(iq) => {
|
||||
const publish_el = sizzle(`items[node="${Strophe.NS.OMEMO_BUNDLES}:${this.get('id')}"]`, stanza).pop();
|
||||
const bundle_el = sizzle(`bundle[xmlns="${Strophe.NS.OMEMO}"]`, publish_el).pop();
|
||||
this.save(parseBundle(bundle_el));
|
||||
resolve();
|
||||
},
|
||||
reject,
|
||||
_converse.IQ_TIMEOUT
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
getBundle () {
|
||||
/* Fetch and save the bundle information associated with
|
||||
* this device, if the information is not at hand already.
|
||||
*/
|
||||
if (this.get('bundle')) {
|
||||
return Promise.resolve(this.get('bundle').toJSON());
|
||||
} else {
|
||||
return this.fetchBundleFromServer();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -600,14 +599,15 @@
|
|||
|
||||
|
||||
function updateBundleFromStanza (stanza) {
|
||||
const items_el = sizzle(`items[node="${Strophe.NS.OMEMO_BUNDLES}"]`, stanza).pop();
|
||||
if (!items_el) {
|
||||
const items_el = sizzle(`items`, stanza).pop();
|
||||
if (!items_el || !items_el.getAttribute('node').startsWith(Strophe.NS.OMEMO_BUNDLES)) {
|
||||
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(),
|
||||
device = _converse.devicelists.get(from).devices.get(device_id);
|
||||
jid = stanza.getAttribute('from'),
|
||||
bundle_el = sizzle(`item > bundle`, items_el).pop(),
|
||||
devicelist = _converse.devicelists.get(jid) || _converse.devicelists.create({'jid': jid}),
|
||||
device = devicelist.devices.get(device_id) || devicelist.devices.create({'id': device_id});
|
||||
device.save({'bundle': parseBundle(bundle_el)});
|
||||
}
|
||||
|
||||
|
|
|
@ -849,8 +849,11 @@
|
|||
const binary_string = window.atob(b64),
|
||||
len = binary_string.length,
|
||||
bytes = new Uint8Array(len);
|
||||
_.forEach(_.range(0, len), (i) => bytes.push(binary_string.charCodeAt(i))); // eslint-disable-line lodash/prefer-map
|
||||
return bytes.buffer;
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
bytes[i] = binary_string.charCodeAt(i)
|
||||
}
|
||||
return bytes.buffer
|
||||
};
|
||||
|
||||
return u;
|
||||
|
|
Loading…
Reference in New Issue
Block a user