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
This commit is contained in:
JC Brand 2018-05-13 16:04:52 +02:00
parent fd3bb570cd
commit 61dcebbbf6
3 changed files with 67 additions and 48 deletions

View File

@ -26,38 +26,13 @@
const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.waitUntil(function () {
return _.filter(_converse.connection.IQ_stanzas, function (iq) {
const node = iq.nodeTree.querySelector('publish[node="eu.siacs.conversations.axolotl.bundles:31415"]');
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 _.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;
});
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")+'">'+
@ -97,16 +72,45 @@
'<item>'+
'<list xmlns="eu.siacs.conversations.axolotl"/>'+
'<device id="482886413b977930064a5888b92134fe"/>'+
'<device id="123456789"/>'+
'</item>'+
'</publish>'+
'</pubsub>'+
'</iq>');
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, 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 _.filter(
_converse.connection.IQ_stanzas,

View File

@ -82,8 +82,18 @@
function generateBundle () {
return new Promise((resolve, reject) => {
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 = {
'device_id': libsignal.KeyHelper.generateRegistrationId(),
'device_id': device_id,
'pubkey': identity_keypair.pubKey,
'privkey': identity_keypair.privKey,
'prekeys': {}
@ -190,11 +200,12 @@
});
},
addDeviceToList () {
addDeviceToList (device_id) {
/* Add this device to our list of devices stored on the
* server.
* https://xmpp.org/extensions/xep-0384.html#usecases-announcing
*/
this.devices.create({'id': device_id});
return new Promise((resolve, reject) => {
const stanza = $iq({
'from': _converse.bare_jid,
@ -264,11 +275,14 @@
* Also, deduplicate devices if necessary.
*/
return new Promise((resolve, reject) => {
const devicelist = _converse.devicelists.get(_converse.bare_jid);
if (!devicelist.devices.findWhere({'id': _converse.omemo_store.get('device_id')})) {
return devicelist.addDeviceToList().then(resolve).catch(reject);
}
resolve();
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));
});
}
@ -303,11 +317,13 @@
}
function restoreOMEMOSession () {
_converse.omemo_store = new _converse.OMEMOStore();
_converse.omemo_store.browserStorage = new Backbone.BrowserStorage.session(
b64_sha1(`converse.omemosession-${_converse.bare_jid}`)
);
return _converse.omemo_store.fetchSession()
if (_.isUndefined(_converse.omemo_store)) {
_converse.omemo_store = new _converse.OMEMOStore();
_converse.omemo_store.browserStorage = new Backbone.BrowserStorage.session(
b64_sha1(`converse.omemosession-${_converse.bare_jid}`)
);
}
return _converse.omemo_store.fetchSession();
}
function addOMEMOToolbarButton (view) {
@ -326,10 +342,9 @@
_converse.devicelists.browserStorage = new Backbone.BrowserStorage.session(
b64_sha1(`converse.devicelists-${_converse.bare_jid}`)
);
restoreOMEMOSession()
.then(() => publishBundle())
.then(() => fetchOwnDevices())
fetchOwnDevices()
.then(() => updateOwnDeviceList())
.then(() => publishBundle())
.then(() => _converse.emit('OMEMOInitialized'))
.catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
}

View File

@ -15,7 +15,7 @@
});
},
'generateRegistrationId': function () {
return '31415';
return '123456789';
},
'generatePreKey': function (keyid) {
return Promise.resolve({