Commit 61dcebbb authored by JC Brand's avatar JC Brand

When generating a device id, check whether it already exists

and if so, generate a new one.

To do so we have to change the order of events.

1. first we fetch our device list
2. then we generate our bundle info (if necessary)
3. then we update our device list (if necessary)
4. then we publish our bundle

updates #497
parent fd3bb570
...@@ -26,38 +26,13 @@ ...@@ -26,38 +26,13 @@
const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost'; const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.waitUntil(function () { test_utils.waitUntil(function () {
return _.filter(_converse.connection.IQ_stanzas, function (iq) { return _.filter(
const node = iq.nodeTree.querySelector('publish[node="eu.siacs.conversations.axolotl.bundles:31415"]'); _converse.connection.IQ_stanzas,
if (node) { iq_stanza = iq.nodeTree; } (iq) => {
return node; const node = iq.nodeTree.querySelector('iq[to="'+_converse.bare_jid+'"] query[node="eu.siacs.conversations.axolotl.devicelist"]');
}).length; if (node) { iq_stanza = iq.nodeTree;}
}).then(function () { return node;
expect(iq_stanza.getAttributeNames().sort().join()).toBe(["from", "type", "xmlns", "id"].sort().join()); }).length;
expect(iq_stanza.querySelector('prekeys').childNodes.length).toBe(100);
const signed_prekeys = iq_stanza.querySelectorAll('signedPreKeyPublic');
expect(signed_prekeys.length).toBe(1);
const signed_prekey = signed_prekeys[0];
expect(signed_prekey.getAttribute('signedPreKeyId')).toBe('0')
expect(iq_stanza.querySelectorAll('signedPreKeySignature').length).toBe(1);
expect(iq_stanza.querySelectorAll('identityKey').length).toBe(1);
const stanza = $iq({
'from': _converse.bare_jid,
'id': iq_stanza.getAttribute('id'),
'to': _converse.bare_jid,
'type': 'result'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
return test_utils.waitUntil(() => {
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 () { }).then(function () {
expect(iq_stanza.outerHTML).toBe( expect(iq_stanza.outerHTML).toBe(
'<iq type="get" from="dummy@localhost" to="dummy@localhost" xmlns="jabber:client" id="'+iq_stanza.getAttribute("id")+'">'+ '<iq type="get" from="dummy@localhost" to="dummy@localhost" xmlns="jabber:client" id="'+iq_stanza.getAttribute("id")+'">'+
...@@ -97,16 +72,45 @@ ...@@ -97,16 +72,45 @@
'<item>'+ '<item>'+
'<list xmlns="eu.siacs.conversations.axolotl"/>'+ '<list xmlns="eu.siacs.conversations.axolotl"/>'+
'<device id="482886413b977930064a5888b92134fe"/>'+ '<device id="482886413b977930064a5888b92134fe"/>'+
'<device id="123456789"/>'+
'</item>'+ '</item>'+
'</publish>'+ '</publish>'+
'</pubsub>'+ '</pubsub>'+
'</iq>'); '</iq>');
const stanza = $iq({ const stanza = $iq({
'from': _converse.bare_jid, 'from': _converse.bare_jid,
'id': iq_stanza.getAttribute('id'), 'id': iq_stanza.getAttribute('id'),
'to': _converse.bare_jid, 'to': _converse.bare_jid,
'type': 'result'}); 'type': 'result'});
_converse.connection._dataRecv(test_utils.createRequest(stanza)); _converse.connection._dataRecv(test_utils.createRequest(stanza));
return test_utils.waitUntil(() => {
return _.filter(_converse.connection.IQ_stanzas, function (iq) {
const node = iq.nodeTree.querySelector('publish[node="eu.siacs.conversations.axolotl.bundles:123456789"]');
if (node) { iq_stanza = iq.nodeTree; }
return node;
}).length;
});
}).then(function () {
expect(iq_stanza.getAttributeNames().sort().join()).toBe(["from", "type", "xmlns", "id"].sort().join());
expect(iq_stanza.querySelector('prekeys').childNodes.length).toBe(100);
const signed_prekeys = iq_stanza.querySelectorAll('signedPreKeyPublic');
expect(signed_prekeys.length).toBe(1);
const signed_prekey = signed_prekeys[0];
expect(signed_prekey.getAttribute('signedPreKeyId')).toBe('0')
expect(iq_stanza.querySelectorAll('signedPreKeySignature').length).toBe(1);
expect(iq_stanza.querySelectorAll('identityKey').length).toBe(1);
const stanza = $iq({
'from': _converse.bare_jid,
'id': iq_stanza.getAttribute('id'),
'to': _converse.bare_jid,
'type': 'result'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
return test_utils.waitUntil(() => { return test_utils.waitUntil(() => {
return _.filter( return _.filter(
_converse.connection.IQ_stanzas, _converse.connection.IQ_stanzas,
......
...@@ -82,8 +82,18 @@ ...@@ -82,8 +82,18 @@
function generateBundle () { function generateBundle () {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
libsignal.KeyHelper.generateIdentityKeyPair().then((identity_keypair) => { libsignal.KeyHelper.generateIdentityKeyPair().then((identity_keypair) => {
const existing_ids = _converse.devicelists.get(_converse.bare_jid).devices.pluck('id');
let device_id = libsignal.KeyHelper.generateRegistrationId();
let i = 0;
while (_.includes(existing_ids, device_id)) {
device_id = libsignal.KeyHelper.generateRegistrationId();
i++;
if (i == 10) {
throw new Error("Unable to generate a unique device ID");
}
}
const data = { const data = {
'device_id': libsignal.KeyHelper.generateRegistrationId(), 'device_id': device_id,
'pubkey': identity_keypair.pubKey, 'pubkey': identity_keypair.pubKey,
'privkey': identity_keypair.privKey, 'privkey': identity_keypair.privKey,
'prekeys': {} 'prekeys': {}
...@@ -190,11 +200,12 @@ ...@@ -190,11 +200,12 @@
}); });
}, },
addDeviceToList () { addDeviceToList (device_id) {
/* Add this device to our list of devices stored on the /* Add this device to our list of devices stored on the
* server. * server.
* https://xmpp.org/extensions/xep-0384.html#usecases-announcing * https://xmpp.org/extensions/xep-0384.html#usecases-announcing
*/ */
this.devices.create({'id': device_id});
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const stanza = $iq({ const stanza = $iq({
'from': _converse.bare_jid, 'from': _converse.bare_jid,
...@@ -264,11 +275,14 @@ ...@@ -264,11 +275,14 @@
* Also, deduplicate devices if necessary. * Also, deduplicate devices if necessary.
*/ */
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const devicelist = _converse.devicelists.get(_converse.bare_jid); restoreOMEMOSession().then(() => {
if (!devicelist.devices.findWhere({'id': _converse.omemo_store.get('device_id')})) { const devicelist = _converse.devicelists.get(_converse.bare_jid);
return devicelist.addDeviceToList().then(resolve).catch(reject); const device_id = _converse.omemo_store.get('device_id');
} if (!devicelist.devices.findWhere({'id': device_id})) {
resolve(); return devicelist.addDeviceToList(device_id).then(resolve).catch(reject);
}
resolve();
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
}); });
} }
...@@ -303,11 +317,13 @@ ...@@ -303,11 +317,13 @@
} }
function restoreOMEMOSession () { function restoreOMEMOSession () {
_converse.omemo_store = new _converse.OMEMOStore(); if (_.isUndefined(_converse.omemo_store)) {
_converse.omemo_store.browserStorage = new Backbone.BrowserStorage.session( _converse.omemo_store = new _converse.OMEMOStore();
b64_sha1(`converse.omemosession-${_converse.bare_jid}`) _converse.omemo_store.browserStorage = new Backbone.BrowserStorage.session(
); b64_sha1(`converse.omemosession-${_converse.bare_jid}`)
return _converse.omemo_store.fetchSession() );
}
return _converse.omemo_store.fetchSession();
} }
function addOMEMOToolbarButton (view) { function addOMEMOToolbarButton (view) {
...@@ -326,10 +342,9 @@ ...@@ -326,10 +342,9 @@
_converse.devicelists.browserStorage = new Backbone.BrowserStorage.session( _converse.devicelists.browserStorage = new Backbone.BrowserStorage.session(
b64_sha1(`converse.devicelists-${_converse.bare_jid}`) b64_sha1(`converse.devicelists-${_converse.bare_jid}`)
); );
restoreOMEMOSession() fetchOwnDevices()
.then(() => publishBundle())
.then(() => fetchOwnDevices())
.then(() => updateOwnDeviceList()) .then(() => updateOwnDeviceList())
.then(() => publishBundle())
.then(() => _converse.emit('OMEMOInitialized')) .then(() => _converse.emit('OMEMOInitialized'))
.catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR)); .catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
} }
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
}); });
}, },
'generateRegistrationId': function () { 'generateRegistrationId': function () {
return '31415'; return '123456789';
}, },
'generatePreKey': function (keyid) { 'generatePreKey': function (keyid) {
return Promise.resolve({ return Promise.resolve({
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment