/*
* 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;
}
}
}
}