/* * Famedly Matrix SDK * Copyright (C) 2019, 2020, 2021 Famedly GmbH * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ import 'dart:convert'; import 'package:vodozemac/vodozemac.dart' as vod; import 'package:matrix/encryption/utils/pickle_key.dart'; import 'package:matrix/encryption/utils/stored_inbound_group_session.dart'; import 'package:matrix/matrix.dart'; class SessionKey { /// The raw json content of the key Map content = {}; /// Map of stringified-index to event id, so that we can detect replay attacks Map indexes; /// Map of userId to map of deviceId to index, that we know that device receivied, e.g. sending it ourself. /// Used for automatically answering key requests Map> allowedAtIndex; /// Underlying olm [InboundGroupSession] object vod.InboundGroupSession? inboundGroupSession; /// Key for libolm pickle / unpickle final String key; /// Forwarding keychain List get forwardingCurve25519KeyChain => (content['forwarding_curve25519_key_chain'] != null ? List.from(content['forwarding_curve25519_key_chain']) : null) ?? []; /// Claimed keys of the original sender late Map senderClaimedKeys; /// Sender curve25519 key String senderKey; /// Is this session valid? bool get isValid => inboundGroupSession != null; /// roomId for this session String roomId; /// Id of this session String sessionId; SessionKey({ required this.content, required this.inboundGroupSession, required this.key, Map? indexes, Map>? allowedAtIndex, required this.roomId, required this.sessionId, required this.senderKey, required this.senderClaimedKeys, }) : indexes = indexes ?? {}, allowedAtIndex = allowedAtIndex ?? >{}; SessionKey.fromDb(StoredInboundGroupSession dbEntry, this.key) : content = Event.getMapFromPayload(dbEntry.content), indexes = Event.getMapFromPayload(dbEntry.indexes) .catchMap((k, v) => MapEntry(k, v)), allowedAtIndex = Event.getMapFromPayload(dbEntry.allowedAtIndex) .catchMap((k, v) => MapEntry(k, Map.from(v))), roomId = dbEntry.roomId, sessionId = dbEntry.sessionId, senderKey = dbEntry.senderKey { final parsedSenderClaimedKeys = Event.getMapFromPayload(dbEntry.senderClaimedKeys) .catchMap((k, v) => MapEntry(k, v)); // we need to try...catch as the map used to be and that will throw an error. senderClaimedKeys = (parsedSenderClaimedKeys.isNotEmpty) ? parsedSenderClaimedKeys : (content .tryGetMap('sender_claimed_keys') ?.catchMap((k, v) => MapEntry(k, v)) ?? (content['sender_claimed_ed25519_key'] is String ? { 'ed25519': content['sender_claimed_ed25519_key'], } : {})); try { inboundGroupSession = vod.InboundGroupSession.fromPickleEncrypted( pickle: dbEntry.pickle, pickleKey: key.toPickleKey(), ); } catch (e, s) { try { Logs().d('Unable to unpickle inboundGroupSession. Try LibOlm format.'); inboundGroupSession = vod.InboundGroupSession.fromOlmPickleEncrypted( pickle: dbEntry.pickle, pickleKey: utf8.encode(key), ); } catch (_) { Logs().e('[Vodozemac] Unable to unpickle inboundGroupSession', e, s); rethrow; } } } }