Test that own devices (from other clients) get included
when sending out encrypted messages. updates #497
This commit is contained in:
parent
a3593dbc7d
commit
e774e9d1af
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
describe("The OMEMO module", function() {
|
describe("The OMEMO module", function() {
|
||||||
|
|
||||||
it("enables encrypted messages to be sent",
|
it("enables encrypted messages to be sent and received",
|
||||||
mock.initConverseWithPromises(
|
mock.initConverseWithPromises(
|
||||||
null, ['rosterGroupsFetched'], {},
|
null, ['rosterGroupsFetched'], {},
|
||||||
function (done, _converse) {
|
function (done, _converse) {
|
||||||
|
@ -83,7 +83,9 @@
|
||||||
return _.filter(
|
return _.filter(
|
||||||
_converse.connection.IQ_stanzas,
|
_converse.connection.IQ_stanzas,
|
||||||
(iq) => {
|
(iq) => {
|
||||||
const node = iq.nodeTree.querySelector('iq[to="'+contact_jid+'"] items[node="eu.siacs.conversations.axolotl.bundles:555"]');
|
const node = iq.nodeTree.querySelector(
|
||||||
|
'iq[to="'+contact_jid+'"] items[node="eu.siacs.conversations.axolotl.bundles:555"]'
|
||||||
|
);
|
||||||
if (node) { iq_stanza = iq.nodeTree; }
|
if (node) { iq_stanza = iq.nodeTree; }
|
||||||
return node;
|
return node;
|
||||||
}).length;
|
}).length;
|
||||||
|
@ -106,6 +108,36 @@
|
||||||
.c('preKeyPublic', {'preKeyId': '1'}).t(btoa('1001')).up()
|
.c('preKeyPublic', {'preKeyId': '1'}).t(btoa('1001')).up()
|
||||||
.c('preKeyPublic', {'preKeyId': '2'}).t(btoa('1002')).up()
|
.c('preKeyPublic', {'preKeyId': '2'}).t(btoa('1002')).up()
|
||||||
.c('preKeyPublic', {'preKeyId': '3'}).t(btoa('1003'));
|
.c('preKeyPublic', {'preKeyId': '3'}).t(btoa('1003'));
|
||||||
|
_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+'"] items[node="eu.siacs.conversations.axolotl.bundles:482886413b977930064a5888b92134fe"]'
|
||||||
|
);
|
||||||
|
if (node) { iq_stanza = iq.nodeTree; }
|
||||||
|
return node;
|
||||||
|
}).length;
|
||||||
|
});
|
||||||
|
}).then(() => {
|
||||||
|
const stanza = $iq({
|
||||||
|
'from': _converse.bare_jid,
|
||||||
|
'id': iq_stanza.getAttribute('id'),
|
||||||
|
'to': _converse.bare_jid,
|
||||||
|
'type': 'result',
|
||||||
|
}).c('pubsub', {
|
||||||
|
'xmlns': 'http://jabber.org/protocol/pubsub'
|
||||||
|
}).c('items', {'node': "eu.siacs.conversations.axolotl.bundles:482886413b977930064a5888b92134fe"})
|
||||||
|
.c('item')
|
||||||
|
.c('bundle', {'xmlns': 'eu.siacs.conversations.axolotl'})
|
||||||
|
.c('signedPreKeyPublic', {'signedPreKeyId': '4223'}).t(btoa('100000')).up()
|
||||||
|
.c('signedPreKeySignature').t(btoa('200000')).up()
|
||||||
|
.c('identityKey').t(btoa('300000')).up()
|
||||||
|
.c('prekeys')
|
||||||
|
.c('preKeyPublic', {'preKeyId': '1'}).t(btoa('1991')).up()
|
||||||
|
.c('preKeyPublic', {'preKeyId': '2'}).t(btoa('1992')).up()
|
||||||
|
.c('preKeyPublic', {'preKeyId': '3'}).t(btoa('1993'));
|
||||||
|
|
||||||
spyOn(_converse.connection, 'send').and.callFake(stanza => { sent_stanza = stanza });
|
spyOn(_converse.connection, 'send').and.callFake(stanza => { sent_stanza = stanza });
|
||||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||||
|
@ -117,11 +149,25 @@
|
||||||
`<body>This is an OMEMO encrypted message which your client doesn’t seem to support. Find more information on https://conversations.im/omemo</body>`+
|
`<body>This is an OMEMO encrypted message which your client doesn’t seem to support. Find more information on https://conversations.im/omemo</body>`+
|
||||||
`<encrypted xmlns='eu.siacs.conversations.axolotl'>`+
|
`<encrypted xmlns='eu.siacs.conversations.axolotl'>`+
|
||||||
`<header sid='123456789'>`+
|
`<header sid='123456789'>`+
|
||||||
`<key>eyJpdiI6IjEyMzQ1In0=</key>`+
|
`<key rid='482886413b977930064a5888b92134fe'>eyJ0eXBlIjoxLCJib2R5IjoiYzFwaDNSNzNYNyIsInJlZ2lzdHJhdGlvbklkIjoiMTMzNyJ9</key>`+
|
||||||
`<iv>12345</iv>`+
|
`<key rid='555'>eyJ0eXBlIjoxLCJib2R5IjoiYzFwaDNSNzNYNyIsInJlZ2lzdHJhdGlvbklkIjoiMTMzNyJ9</key>`+
|
||||||
|
`<iv>${sent_stanza.nodeTree.querySelector('iv').textContent}</iv>`+
|
||||||
`</header>`+
|
`</header>`+
|
||||||
`</encrypted>`+
|
`</encrypted>`+
|
||||||
`</message>`);
|
`</message>`);
|
||||||
|
|
||||||
|
// Test reception of an encrypted message
|
||||||
|
const stanza = $msg({
|
||||||
|
'from': contact_jid,
|
||||||
|
'to': _converse.connection.jid,
|
||||||
|
'type': 'chat',
|
||||||
|
'id': 'qwerty'
|
||||||
|
}).c('body').t('This is a fallback message').up()
|
||||||
|
.c('encrypted', {'xmlns': Strophe.NS.OMEMO})
|
||||||
|
.c('header', {'sid': '555'})
|
||||||
|
.c('key', {'rid': _converse.omemo_store.get('device_id')}).t('c1ph3R73X7').up()
|
||||||
|
.c('iv').t('1234');
|
||||||
|
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -92,8 +92,13 @@
|
||||||
const { _converse } = this.__super__;
|
const { _converse } = this.__super__;
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
_converse.getDevicesForContact(this.get('jid'))
|
_converse.getDevicesForContact(this.get('jid'))
|
||||||
.then((devices) => {
|
.then((their_devices) => {
|
||||||
Promise.all(devices.map((device) => device.getBundle()))
|
const device_id = _converse.omemo_store.get('device_id'),
|
||||||
|
devicelist = _converse.devicelists.get(_converse.bare_jid),
|
||||||
|
own_devices = devicelist.devices.filter(device => device.get('id') !== device_id),
|
||||||
|
devices = _.concat(own_devices, their_devices.models);
|
||||||
|
|
||||||
|
Promise.all(devices.map(device => device.getBundle()))
|
||||||
.then(() => this.buildSessions(devices))
|
.then(() => this.buildSessions(devices))
|
||||||
.then(() => resolve(devices))
|
.then(() => resolve(devices))
|
||||||
.catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
|
.catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
|
||||||
|
@ -165,22 +170,27 @@
|
||||||
address = new libsignal.SignalProtocolAddress(this.get('jid'), device.get('id')),
|
address = new libsignal.SignalProtocolAddress(this.get('jid'), device.get('id')),
|
||||||
sessionCipher = new window.libsignal.SessionCipher(_converse.omemo_store, address);
|
sessionCipher = new window.libsignal.SessionCipher(_converse.omemo_store, address);
|
||||||
|
|
||||||
return sessionCipher.encrypt(plaintext);
|
return new Promise((resolve, reject) => {
|
||||||
|
sessionCipher.encrypt(plaintext)
|
||||||
|
.then(payload => resolve({'payload': payload, 'device': device}))
|
||||||
|
.catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
addKeysToMessageStanza (stanza, devices, payloads) {
|
addKeysToMessageStanza (stanza, dicts, iv) {
|
||||||
for (var i in payloads) {
|
for (var i in dicts) {
|
||||||
if (Object.prototype.hasOwnProperty.call(payloads, i)) {
|
if (Object.prototype.hasOwnProperty.call(dicts, i)) {
|
||||||
const payload = btoa(JSON.stringify(payloads[i]))
|
const payload = dicts[i].payload,
|
||||||
const prekey = 3 == parseInt(payloads[i].type, 10)
|
device = dicts[i].device,
|
||||||
if (i == payloads.length-1) {
|
prekey = 3 == parseInt(payload.type, 10);
|
||||||
stanza.c('key', {'rid': devices.get('id') }).t(payload)
|
|
||||||
if (prekey) {
|
stanza.c('key', {'rid': device.get('id') }).t(btoa(JSON.stringify(dicts[i].payload)));
|
||||||
stanza.attrs({'prekey': prekey});
|
if (prekey) {
|
||||||
}
|
stanza.attrs({'prekey': prekey});
|
||||||
stanza.up().c('iv').t(payloads[0].iv).up().up()
|
}
|
||||||
} else {
|
stanza.up();
|
||||||
stanza.c('key', {prekey: prekey, rid: devices.get('id') }).t(payload).up()
|
if (i == dicts.length-1) {
|
||||||
|
stanza.c('iv').t(iv).up().up()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -213,8 +223,13 @@
|
||||||
// long-standing SignalProtocol session.
|
// long-standing SignalProtocol session.
|
||||||
|
|
||||||
// TODO: need to include own devices here as well (and filter out distrusted devices)
|
// TODO: need to include own devices here as well (and filter out distrusted devices)
|
||||||
const promises = devices.map(device => this.encryptKey(payload.key_str+payload.tag, device));
|
const promises = devices
|
||||||
return Promise.all(promises).then((payloads) => this.addKeysToMessageStanza(stanza, devices, payloads));
|
.filter(device => device.get('trusted') != UNTRUSTED)
|
||||||
|
.map(device => this.encryptKey(payload.key_str+payload.tag, device));
|
||||||
|
|
||||||
|
return Promise.all(promises)
|
||||||
|
.then((dicts) => this.addKeysToMessageStanza(stanza, dicts, payload.iv))
|
||||||
|
.catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,9 @@
|
||||||
this.remoteAddress = remote_address;
|
this.remoteAddress = remote_address;
|
||||||
this.storage = storage;
|
this.storage = storage;
|
||||||
this.encrypt = () => Promise.resolve({
|
this.encrypt = () => Promise.resolve({
|
||||||
'iv': '12345'
|
'type': 1,
|
||||||
|
'body': 'c1ph3R73X7',
|
||||||
|
'registrationId': '1337'
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
'SessionBuilder': function (storage, remote_address) {
|
'SessionBuilder': function (storage, remote_address) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user