decryptRoomEventSync method
Implementation
Event decryptRoomEventSync(String roomId, Event event) {
if (event.type != EventTypes.Encrypted || event.redacted) {
return event;
}
final content = event.parsedRoomEncryptedContent;
if (event.type != EventTypes.Encrypted ||
content.ciphertextMegolm == null) {
return event;
}
Map<String, dynamic> decryptedPayload;
var canRequestSession = false;
try {
if (content.algorithm != AlgorithmTypes.megolmV1AesSha2) {
throw DecryptException(DecryptException.unknownAlgorithm);
}
final sessionId = content.sessionId;
if (sessionId == null) {
throw DecryptException(DecryptException.unknownSession);
}
final inboundGroupSession =
keyManager.getInboundGroupSession(roomId, sessionId);
if (!(inboundGroupSession?.isValid ?? false)) {
canRequestSession = true;
throw DecryptException(DecryptException.unknownSession);
}
// decrypt errors here may mean we have a bad session key - others might have a better one
canRequestSession = true;
final decryptResult = inboundGroupSession!.inboundGroupSession!
.decrypt(content.ciphertextMegolm!);
canRequestSession = false;
// we can't have the key be an int, else json-serializing will fail, thus we need it to be a string
final messageIndexKey = 'key-${decryptResult.message_index}';
final messageIndexValue =
'${event.eventId}|${event.originServerTs.millisecondsSinceEpoch}';
final haveIndex =
inboundGroupSession.indexes.containsKey(messageIndexKey);
if (haveIndex &&
inboundGroupSession.indexes[messageIndexKey] != messageIndexValue) {
Logs().e('[Decrypt] Could not decrypt due to a corrupted session.');
throw DecryptException(DecryptException.channelCorrupted);
}
inboundGroupSession.indexes[messageIndexKey] = messageIndexValue;
if (!haveIndex) {
// now we persist the udpated indexes into the database.
// the entry should always exist. In the case it doesn't, the following
// line *could* throw an error. As that is a future, though, and we call
// it un-awaited here, nothing happens, which is exactly the result we want
client.database
// ignore: discarded_futures
?.updateInboundGroupSessionIndexes(
json.encode(inboundGroupSession.indexes),
roomId,
sessionId,
)
// ignore: discarded_futures
.onError((e, _) => Logs().e('Ignoring error for updating indexes'));
}
decryptedPayload = json.decode(decryptResult.plaintext);
} catch (exception) {
// alright, if this was actually by our own outbound group session, we might as well clear it
if (exception.toString() != DecryptException.unknownSession &&
(keyManager
.getOutboundGroupSession(roomId)
?.outboundGroupSession
?.session_id() ??
'') ==
content.sessionId) {
runInRoot(
() async =>
keyManager.clearOrUseOutboundGroupSession(roomId, wipe: true),
);
}
if (canRequestSession) {
decryptedPayload = {
'content': event.content,
'type': EventTypes.Encrypted,
};
decryptedPayload['content']['body'] = exception.toString();
decryptedPayload['content']['msgtype'] = MessageTypes.BadEncrypted;
decryptedPayload['content']['can_request_session'] = true;
} else {
decryptedPayload = {
'content': <String, dynamic>{
'msgtype': MessageTypes.BadEncrypted,
'body': exception.toString(),
},
'type': EventTypes.Encrypted,
};
}
}
if (event.content['m.relates_to'] != null) {
decryptedPayload['content']['m.relates_to'] =
event.content['m.relates_to'];
}
return Event(
content: decryptedPayload['content'],
type: decryptedPayload['type'],
senderId: event.senderId,
eventId: event.eventId,
room: event.room,
originServerTs: event.originServerTs,
unsigned: event.unsigned,
stateKey: event.stateKey,
prevContent: event.prevContent,
status: event.status,
originalSource: event,
);
}