refactor: Olm Exceptions
This commit is contained in:
parent
33500012b2
commit
39b776716c
|
|
@ -155,7 +155,7 @@ class Encryption {
|
||||||
var canRequestSession = false;
|
var canRequestSession = false;
|
||||||
try {
|
try {
|
||||||
if (event.content['algorithm'] != AlgorithmTypes.megolmV1AesSha2) {
|
if (event.content['algorithm'] != AlgorithmTypes.megolmV1AesSha2) {
|
||||||
throw (DecryptError.UNKNOWN_ALGORITHM);
|
throw DecryptException(DecryptException.unknownAlgorithm);
|
||||||
}
|
}
|
||||||
final String sessionId = event.content['session_id'];
|
final String sessionId = event.content['session_id'];
|
||||||
final String senderKey = event.content['sender_key'];
|
final String senderKey = event.content['sender_key'];
|
||||||
|
|
@ -163,10 +163,11 @@ class Encryption {
|
||||||
keyManager.getInboundGroupSession(roomId, sessionId, senderKey);
|
keyManager.getInboundGroupSession(roomId, sessionId, senderKey);
|
||||||
if (inboundGroupSession == null) {
|
if (inboundGroupSession == null) {
|
||||||
canRequestSession = true;
|
canRequestSession = true;
|
||||||
throw (DecryptError.UNKNOWN_SESSION);
|
throw DecryptException(DecryptException.unknownSession);
|
||||||
}
|
}
|
||||||
// decrypt errors here may mean we have a bad session key - others might have a better one
|
// decrypt errors here may mean we have a bad session key - others might have a better one
|
||||||
canRequestSession = true;
|
canRequestSession = true;
|
||||||
|
|
||||||
final decryptResult = inboundGroupSession.inboundGroupSession
|
final decryptResult = inboundGroupSession.inboundGroupSession
|
||||||
.decrypt(event.content['ciphertext']);
|
.decrypt(event.content['ciphertext']);
|
||||||
canRequestSession = false;
|
canRequestSession = false;
|
||||||
|
|
@ -179,7 +180,7 @@ class Encryption {
|
||||||
if (haveIndex &&
|
if (haveIndex &&
|
||||||
inboundGroupSession.indexes[messageIndexKey] != messageIndexValue) {
|
inboundGroupSession.indexes[messageIndexKey] != messageIndexValue) {
|
||||||
Logs().e('[Decrypt] Could not decrypt due to a corrupted session.');
|
Logs().e('[Decrypt] Could not decrypt due to a corrupted session.');
|
||||||
throw (DecryptError.CHANNEL_CORRUPTED);
|
throw DecryptException(DecryptException.channelCorrupted);
|
||||||
}
|
}
|
||||||
inboundGroupSession.indexes[messageIndexKey] = messageIndexValue;
|
inboundGroupSession.indexes[messageIndexKey] = messageIndexValue;
|
||||||
if (!haveIndex) {
|
if (!haveIndex) {
|
||||||
|
|
@ -197,7 +198,7 @@ class Encryption {
|
||||||
} catch (exception) {
|
} catch (exception) {
|
||||||
// alright, if this was actually by our own outbound group session, we might as well clear it
|
// alright, if this was actually by our own outbound group session, we might as well clear it
|
||||||
if (client.enableE2eeRecovery &&
|
if (client.enableE2eeRecovery &&
|
||||||
exception != DecryptError.UNKNOWN_SESSION &&
|
exception.toString() != DecryptException.unknownSession &&
|
||||||
(keyManager
|
(keyManager
|
||||||
.getOutboundGroupSession(roomId)
|
.getOutboundGroupSession(roomId)
|
||||||
?.outboundGroupSession
|
?.outboundGroupSession
|
||||||
|
|
@ -383,11 +384,30 @@ class Encryption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class DecryptError {
|
class DecryptException implements Exception {
|
||||||
static const String NOT_ENABLED = 'Encryption is not enabled in your client.';
|
String cause;
|
||||||
static const String UNKNOWN_ALGORITHM = 'Unknown encryption algorithm.';
|
String libolmMessage;
|
||||||
static const String UNKNOWN_SESSION =
|
DecryptException(this.cause, [this.libolmMessage]);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => cause;
|
||||||
|
|
||||||
|
static const String notEnabled = 'Encryption is not enabled in your client.';
|
||||||
|
static const String unknownAlgorithm = 'Unknown encryption algorithm.';
|
||||||
|
static const String unknownSession =
|
||||||
'The sender has not sent us the session key.';
|
'The sender has not sent us the session key.';
|
||||||
static const String CHANNEL_CORRUPTED =
|
static const String channelCorrupted =
|
||||||
'The secure channel with the sender was corrupted.';
|
'The secure channel with the sender was corrupted.';
|
||||||
|
static const String unableToDecryptWithAnyOlmSession =
|
||||||
|
'Unable to decrypt with any existing OLM session';
|
||||||
|
static const String senderDoesntMatch =
|
||||||
|
"Message was decrypted but sender doesn't match";
|
||||||
|
static const String recipientDoesntMatch =
|
||||||
|
"Message was decrypted but recipient doesn't match";
|
||||||
|
static const String ownFingerprintDoesntMatch =
|
||||||
|
"Message was decrypted but own fingerprint Key doesn't match";
|
||||||
|
static const String isntSentForThisDevice =
|
||||||
|
"The message isn't sent for this device";
|
||||||
|
static const String unknownMessageType = 'Unknown message type';
|
||||||
|
static const String decryptionFailed = 'Decryption failed';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -248,17 +248,17 @@ class OlmManager {
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
if (event.content['algorithm'] != AlgorithmTypes.olmV1Curve25519AesSha2) {
|
if (event.content['algorithm'] != AlgorithmTypes.olmV1Curve25519AesSha2) {
|
||||||
throw ('Unknown algorithm: ${event.content['algorithm']}');
|
throw DecryptException(DecryptException.unknownAlgorithm);
|
||||||
}
|
}
|
||||||
if (!event.content['ciphertext'].containsKey(identityKey)) {
|
if (!event.content['ciphertext'].containsKey(identityKey)) {
|
||||||
throw ("The message isn't sent for this device");
|
throw DecryptException(DecryptException.isntSentForThisDevice);
|
||||||
}
|
}
|
||||||
String plaintext;
|
String plaintext;
|
||||||
final String senderKey = event.content['sender_key'];
|
final String senderKey = event.content['sender_key'];
|
||||||
final String body = event.content['ciphertext'][identityKey]['body'];
|
final String body = event.content['ciphertext'][identityKey]['body'];
|
||||||
final int type = event.content['ciphertext'][identityKey]['type'];
|
final int type = event.content['ciphertext'][identityKey]['type'];
|
||||||
if (type != 0 && type != 1) {
|
if (type != 0 && type != 1) {
|
||||||
throw ('Unknown message type');
|
throw DecryptException(DecryptException.unknownMessageType);
|
||||||
}
|
}
|
||||||
final device = client.userDeviceKeys[event.sender]?.deviceKeys?.values
|
final device = client.userDeviceKeys[event.sender]?.deviceKeys?.values
|
||||||
?.firstWhere((d) => d.curve25519Key == senderKey, orElse: () => null);
|
?.firstWhere((d) => d.curve25519Key == senderKey, orElse: () => null);
|
||||||
|
|
@ -280,7 +280,12 @@ class OlmManager {
|
||||||
if (existingSessions != null) {
|
if (existingSessions != null) {
|
||||||
for (var session in existingSessions) {
|
for (var session in existingSessions) {
|
||||||
if (type == 0 && session.session.matches_inbound(body) == true) {
|
if (type == 0 && session.session.matches_inbound(body) == true) {
|
||||||
plaintext = session.session.decrypt(type, body);
|
try {
|
||||||
|
plaintext = session.session.decrypt(type, body);
|
||||||
|
} catch (e) {
|
||||||
|
throw DecryptException(
|
||||||
|
DecryptException.decryptionFailed, e.toString());
|
||||||
|
}
|
||||||
updateSessionUsage(session);
|
updateSessionUsage(session);
|
||||||
break;
|
break;
|
||||||
} else if (type == 1) {
|
} else if (type == 1) {
|
||||||
|
|
@ -295,7 +300,7 @@ class OlmManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (plaintext == null && type != 0) {
|
if (plaintext == null && type != 0) {
|
||||||
throw ('Unable to decrypt with any existing OLM session');
|
throw DecryptException(DecryptException.unableToDecryptWithAnyOlmSession);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (plaintext == null) {
|
if (plaintext == null) {
|
||||||
|
|
@ -313,24 +318,24 @@ class OlmManager {
|
||||||
lastReceived: DateTime.now(),
|
lastReceived: DateTime.now(),
|
||||||
)));
|
)));
|
||||||
updateSessionUsage();
|
updateSessionUsage();
|
||||||
} catch (_) {
|
} catch (e) {
|
||||||
newSession?.free();
|
newSession?.free();
|
||||||
rethrow;
|
throw DecryptException(DecryptException.decryptionFailed, e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final Map<String, dynamic> plainContent = json.decode(plaintext);
|
final Map<String, dynamic> plainContent = json.decode(plaintext);
|
||||||
if (plainContent.containsKey('sender') &&
|
if (plainContent.containsKey('sender') &&
|
||||||
plainContent['sender'] != event.sender) {
|
plainContent['sender'] != event.sender) {
|
||||||
throw ("Message was decrypted but sender doesn't match");
|
throw DecryptException(DecryptException.senderDoesntMatch);
|
||||||
}
|
}
|
||||||
if (plainContent.containsKey('recipient') &&
|
if (plainContent.containsKey('recipient') &&
|
||||||
plainContent['recipient'] != client.userID) {
|
plainContent['recipient'] != client.userID) {
|
||||||
throw ("Message was decrypted but recipient doesn't match");
|
throw DecryptException(DecryptException.recipientDoesntMatch);
|
||||||
}
|
}
|
||||||
if (plainContent['recipient_keys'] is Map &&
|
if (plainContent['recipient_keys'] is Map &&
|
||||||
plainContent['recipient_keys']['ed25519'] is String &&
|
plainContent['recipient_keys']['ed25519'] is String &&
|
||||||
plainContent['recipient_keys']['ed25519'] != fingerprintKey) {
|
plainContent['recipient_keys']['ed25519'] != fingerprintKey) {
|
||||||
throw ("Message was decrypted but own fingerprint Key doesn't match");
|
throw DecryptException(DecryptException.ownFingerprintDoesntMatch);
|
||||||
}
|
}
|
||||||
return ToDeviceEvent(
|
return ToDeviceEvent(
|
||||||
content: plainContent['content'],
|
content: plainContent['content'],
|
||||||
|
|
|
||||||
|
|
@ -43,16 +43,16 @@ abstract class EventLocalizations {
|
||||||
case MessageTypes.BadEncrypted:
|
case MessageTypes.BadEncrypted:
|
||||||
String errorText;
|
String errorText;
|
||||||
switch (event.body) {
|
switch (event.body) {
|
||||||
case DecryptError.CHANNEL_CORRUPTED:
|
case DecryptException.channelCorrupted:
|
||||||
errorText = i18n.channelCorruptedDecryptError + '.';
|
errorText = i18n.channelCorruptedDecryptError + '.';
|
||||||
break;
|
break;
|
||||||
case DecryptError.NOT_ENABLED:
|
case DecryptException.notEnabled:
|
||||||
errorText = i18n.encryptionNotEnabled + '.';
|
errorText = i18n.encryptionNotEnabled + '.';
|
||||||
break;
|
break;
|
||||||
case DecryptError.UNKNOWN_ALGORITHM:
|
case DecryptException.unknownAlgorithm:
|
||||||
errorText = i18n.unknownEncryptionAlgorithm + '.';
|
errorText = i18n.unknownEncryptionAlgorithm + '.';
|
||||||
break;
|
break;
|
||||||
case DecryptError.UNKNOWN_SESSION:
|
case DecryptException.unknownSession:
|
||||||
errorText = i18n.noPermission + '.';
|
errorText = i18n.noPermission + '.';
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -302,7 +302,7 @@ void main() {
|
||||||
'status': 2,
|
'status': 2,
|
||||||
'content': json.encode({
|
'content': json.encode({
|
||||||
'msgtype': 'm.bad.encrypted',
|
'msgtype': 'm.bad.encrypted',
|
||||||
'body': DecryptError.UNKNOWN_SESSION,
|
'body': DecryptException.unknownSession,
|
||||||
'can_request_session': true,
|
'can_request_session': true,
|
||||||
'algorithm': AlgorithmTypes.megolmV1AesSha2,
|
'algorithm': AlgorithmTypes.megolmV1AesSha2,
|
||||||
'ciphertext': 'AwgAEnACgAkLmt6qF84IK++J7UDH2Za1YVchHyprqTqsg...',
|
'ciphertext': 'AwgAEnACgAkLmt6qF84IK++J7UDH2Za1YVchHyprqTqsg...',
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue