Properly handle the same OMEMO message being recieved twice, with the
2nd one failing to decrypt.
This commit is contained in:
JC Brand 2022-02-10 22:35:40 +01:00
parent f6c524f760
commit 38519a6261
3 changed files with 85 additions and 3 deletions

View File

@ -2,7 +2,7 @@
## 9.0.1 (Unreleased) ## 9.0.1 (Unreleased)
- Updated translations: lt - Updated translations: af, ar, es, eu, fr, gl, he, lt
- Increased stanza timeout from 10 to 20 seconds - Increased stanza timeout from 10 to 20 seconds
- Replace various font icons with SVG icons - Replace various font icons with SVG icons
- #1761: Add a new dark theme based on the [Dracula](https://draculatheme.com/) theme - #1761: Add a new dark theme based on the [Dracula](https://draculatheme.com/) theme

View File

@ -449,8 +449,21 @@ const ChatBox = ModelWithContact.extend({
}, },
getUpdatedMessageAttributes (message, attrs) { getUpdatedMessageAttributes (message, attrs) {
// Filter the attrs object, restricting it to only the `is_archived` key. if (!attrs.error_type && message.get('error_type') === 'Decryption') {
return (({ is_archived }) => ({ is_archived }))(attrs) // Looks like we have a failed decrypted message stored, and now
// we have a properly decrypted version of the same message.
// See issue: https://github.com/conversejs/converse.js/issues/2733#issuecomment-1035493594
return Object.assign({}, attrs, {
error_condition: undefined,
error_message: undefined,
error_text: undefined,
error_type: undefined,
is_archived: attrs.is_archived,
is_ephemeral: false,
});
} else {
return { is_archived: attrs.is_archived };
}
}, },
updateMessage (message, attrs) { updateMessage (message, attrs) {

View File

@ -152,6 +152,75 @@ describe("The OMEMO module", function() {
.toBe('Another received encrypted message without fallback'); .toBe('Another received encrypted message without fallback');
})); }));
it("properly handles an already decrypted message being received again",
mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
await mock.waitForRoster(_converse, 'current', 1);
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await mock.initializedOMEMO(_converse);
await mock.openChatBoxFor(_converse, contact_jid);
const iq_stanza = await u.waitUntil(() => mock.deviceListFetched(_converse, contact_jid));
let stanza = $iq({
'from': contact_jid,
'id': iq_stanza.getAttribute('id'),
'to': _converse.connection.jid,
'type': 'result',
}).c('pubsub', {'xmlns': "http://jabber.org/protocol/pubsub"})
.c('items', {'node': "eu.siacs.conversations.axolotl.devicelist"})
.c('item', {'xmlns': "http://jabber.org/protocol/pubsub"}) // TODO: must have an id attribute
.c('list', {'xmlns': "eu.siacs.conversations.axolotl"})
.c('device', {'id': '555'});
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => _converse.omemo_store);
const view = _converse.chatboxviews.get(contact_jid);
view.model.set('omemo_active', true);
// Test reception of an encrypted message
const msg_txt = 'This is an encrypted message from the contact';
const obj = await omemo.encryptMessage(msg_txt)
const id = _converse.connection.getUniqueId();
stanza = $msg({
'from': contact_jid,
'to': _converse.connection.jid,
'type': 'chat',
id
}).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(u.arrayBufferToBase64(obj.key_and_tag)).up()
.c('iv').t(obj.iv)
.up().up()
.c('payload').t(obj.payload);
_converse.connection._dataRecv(mock.createRequest(stanza));
// Test reception of the same message, but the decryption fails.
// The properly decrypted message should still show to the user.
// See issue: https://github.com/conversejs/converse.js/issues/2733#issuecomment-1035493594
stanza = $msg({
'from': contact_jid,
'to': _converse.connection.jid,
'type': 'chat',
id
}).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(u.arrayBufferToBase64(obj.key_and_tag)).up()
.c('iv').t(obj.iv)
.up().up()
.c('payload').t(obj.payload+'x'); // Hack to break decryption.
_converse.connection._dataRecv(mock.createRequest(stanza));
await u.waitUntil(() => view.querySelector('.chat-msg__text')?.textContent.trim() === msg_txt);
expect(view.model.messages.length).toBe(1);
const msg = view.model.messages.at(0);
expect(msg.get('is_ephemeral')).toBe(false)
}));
it("will create a new device based on a received carbon message", it("will create a new device based on a received carbon message",
mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) { mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {