Send a 'm.new_device' when we get a message for an unknown group session

This should reduce the risk of a device getting permenantly stuck unable
to receive encrypted group messages.
This commit is contained in:
Mark Haines
2016-09-14 19:16:24 +01:00
parent 6ca917f4db
commit 72a4b92022
4 changed files with 52 additions and 9 deletions
+6 -4
View File
@@ -539,7 +539,9 @@ OlmDevice.prototype._saveInboundGroupSession = function(
* @param {string} senderKey
* @param {string} sessionId
* @param {function} func
* @return {object} result of func
* @return {object} Object with two keys "result": result of func, "exists"
* whether the session exists. if the session doesn't exist then the function
* isn't called and the "result" is undefined.
* @private
*/
OlmDevice.prototype._getInboundGroupSession = function(
@@ -550,7 +552,7 @@ OlmDevice.prototype._getInboundGroupSession = function(
);
if (r === null) {
throw new Error("Unknown inbound group session id");
return {sessionExists: false}
}
r = JSON.parse(r);
@@ -567,7 +569,7 @@ OlmDevice.prototype._getInboundGroupSession = function(
var session = new Olm.InboundGroupSession();
try {
session.unpickle(this._pickleKey, r.session);
return func(session);
return {sessionExists: true, result: func(session)};
} finally {
session.free();
}
@@ -603,7 +605,7 @@ OlmDevice.prototype.addInboundGroupSession = function(
* @param {string} sessionId session identifier
* @param {string} body base64-encoded body of the encrypted message
*
* @return {string} plaintext
* @return {object} {result: "plaintext"|undefined, sessionExists: Boolean}
*/
OlmDevice.prototype.decryptGroupMessage = function(
roomId, senderKey, sessionId, body
+7 -2
View File
@@ -356,7 +356,8 @@ utils.inherits(MegolmDecryption, base.DecryptionAlgorithm);
*
* @param {object} event raw event
*
* @return {object} decrypted payload (with properties 'type', 'content')
* @return {object} object with 'result' key with decrypted payload (with
* properties 'type', 'content') and a 'sessionKey' key.
*
* @throws {module:crypto/algorithms/base.DecryptionError} if there is a
* problem decrypting the event
@@ -377,7 +378,11 @@ MegolmDecryption.prototype.decryptEvent = function(event) {
var res = this._olmDevice.decryptGroupMessage(
event.room_id, content.sender_key, content.session_id, content.ciphertext
);
return JSON.parse(res);
if (res.sessionExists) {
return {result: JSON.parse(res.result), sessionExists: true};
} else {
return {sessionExists: false};
}
} catch (e) {
throw new base.DecryptionError(e);
}
+4 -2
View File
@@ -142,7 +142,9 @@ utils.inherits(OlmDecryption, base.DecryptionAlgorithm);
*
* @param {object} event raw event
*
* @return {object} decrypted payload (with properties 'type', 'content')
* @return {object} result object with result property with the decrypted
* payload (with properties 'type', 'content'), and a "sessionExists" key
* always set to true.
*
* @throws {module:crypto/algorithms/base.DecryptionError} if there is a
* problem decrypting the event
@@ -198,7 +200,7 @@ OlmDecryption.prototype.decryptEvent = function(event) {
// TODO: Check the sender user id matches the sender key.
// TODO: check the room_id and fingerprint
if (payloadString !== null) {
return JSON.parse(payloadString);
return {result: JSON.parse(payloadString), sessionExists: true};
} else {
throw new base.DecryptionError("Bad Encrypted Message");
}
+35 -1
View File
@@ -820,7 +820,41 @@ Crypto.prototype.decryptEvent = function(event) {
var alg = new AlgClass({
olmDevice: this._olmDevice,
});
return alg.decryptEvent(event);
var r = alg.decryptEvent(event);
if (r.sessionExists) {
return r.result;
} else {
// We've got a message for a session we don't have.
// Maybe the sender forgot to tell us about the session.
// Remind the sender that we exists so that they might
// tell us about the sender.
if (event.getRoomId !== undefined && event.getSender !== undefined) {
var senderUserId = event.getSender();
var roomId = event.getRoomId();
var content = {};
var senderDeviceId = event.content.device_id;
if (senderDeviceId !== undefined) {
content[senderUserId][senderDeviceId] = {
device_id: this._deviceId,
rooms: [roomId],
};
} else {
content[senderUserId]["*"] = {
device_id: this._deviceId,
rooms: [roomId],
};
}
// TODO: Ratelimit the "m.new_device" messages to make sure we don't
// flood the target device with messages if we get lots of encrypted
// messages from them at once.
this._baseApis.sendToDevice(
"m.new_device", // OH HAI!
content
).done(function() {});
}
throw new algorithms.DecryptionError("Unknown inbound session id");
}
};
/**