refactor(keybackup): Update database for stored megolm keys to prepare for proper online key backup

This commit is contained in:
Sorunome 2020-08-11 13:38:50 +02:00
parent 20d72eb8d7
commit ea59c4bd94
No known key found for this signature in database
GPG key ID: B19471D07FC9BE9C
7 changed files with 291 additions and 49 deletions

View file

@ -71,7 +71,20 @@ class KeyManager {
void setInboundGroupSession(String roomId, String sessionId, String senderKey, void setInboundGroupSession(String roomId, String sessionId, String senderKey,
Map<String, dynamic> content, Map<String, dynamic> content,
{bool forwarded = false}) { {bool forwarded = false, Map<String, String> senderClaimedKeys}) {
senderClaimedKeys ??= <String, String>{};
if (!senderClaimedKeys.containsKey('ed25519')) {
DeviceKeys device;
for (final user in client.userDeviceKeys.values) {
device = user.deviceKeys.values.firstWhere(
(e) => e.curve25519Key == senderKey,
orElse: () => null);
if (device != null) {
senderClaimedKeys['ed25519'] = device.ed25519Key;
break;
}
}
}
final oldSession = final oldSession =
getInboundGroupSession(roomId, sessionId, senderKey, otherRooms: false); getInboundGroupSession(roomId, sessionId, senderKey, otherRooms: false);
if (content['algorithm'] != 'm.megolm.v1.aes-sha2') { if (content['algorithm'] != 'm.megolm.v1.aes-sha2') {
@ -97,6 +110,8 @@ class KeyManager {
inboundGroupSession: inboundGroupSession, inboundGroupSession: inboundGroupSession,
indexes: {}, indexes: {},
key: client.userID, key: client.userID,
senderKey: senderKey,
senderClaimedKeys: senderClaimedKeys,
); );
final oldFirstIndex = final oldFirstIndex =
oldSession?.inboundGroupSession?.first_known_index() ?? 0; oldSession?.inboundGroupSession?.first_known_index() ?? 0;
@ -124,6 +139,8 @@ class KeyManager {
inboundGroupSession.pickle(client.userID), inboundGroupSession.pickle(client.userID),
json.encode(content), json.encode(content),
json.encode({}), json.encode({}),
senderKey,
json.encode(senderClaimedKeys),
); );
// Note to self: When adding key-backup that needs to be unawaited(), else // Note to self: When adding key-backup that needs to be unawaited(), else
// we might accidentally end up with http requests inside of the sync loop // we might accidentally end up with http requests inside of the sync loop
@ -139,7 +156,11 @@ class KeyManager {
{bool otherRooms = true}) { {bool otherRooms = true}) {
if (_inboundGroupSessions.containsKey(roomId) && if (_inboundGroupSessions.containsKey(roomId) &&
_inboundGroupSessions[roomId].containsKey(sessionId)) { _inboundGroupSessions[roomId].containsKey(sessionId)) {
return _inboundGroupSessions[roomId][sessionId]; final sess = _inboundGroupSessions[roomId][sessionId];
if (sess.senderKey != senderKey && sess.senderKey.isNotEmpty) {
return null;
}
return sess;
} }
if (!otherRooms) { if (!otherRooms) {
return null; return null;
@ -147,7 +168,11 @@ class KeyManager {
// search if this session id is *somehow* found in another room // search if this session id is *somehow* found in another room
for (final val in _inboundGroupSessions.values) { for (final val in _inboundGroupSessions.values) {
if (val.containsKey(sessionId)) { if (val.containsKey(sessionId)) {
return val[sessionId]; final sess = val[sessionId];
if (sess.senderKey != senderKey && sess.senderKey.isNotEmpty) {
return null;
}
return sess;
} }
} }
return null; return null;
@ -161,7 +186,11 @@ class KeyManager {
} }
if (_inboundGroupSessions.containsKey(roomId) && if (_inboundGroupSessions.containsKey(roomId) &&
_inboundGroupSessions[roomId].containsKey(sessionId)) { _inboundGroupSessions[roomId].containsKey(sessionId)) {
return _inboundGroupSessions[roomId][sessionId]; // nothing to do final sess = _inboundGroupSessions[roomId][sessionId];
if (sess.senderKey != senderKey && sess.senderKey.isNotEmpty) {
return null; // sender keys do not match....better not do anything
}
return sess; // nothing to do
} }
final session = await client.database final session = await client.database
?.getDbInboundGroupSession(client.id, roomId, sessionId); ?.getDbInboundGroupSession(client.id, roomId, sessionId);
@ -181,7 +210,8 @@ class KeyManager {
_inboundGroupSessions[roomId] = <String, SessionKey>{}; _inboundGroupSessions[roomId] = <String, SessionKey>{};
} }
final sess = SessionKey.fromDb(session, client.userID); final sess = SessionKey.fromDb(session, client.userID);
if (!sess.isValid) { if (!sess.isValid ||
(sess.senderKey.isNotEmpty && sess.senderKey != senderKey)) {
return null; return null;
} }
_inboundGroupSessions[roomId][sessionId] = sess; _inboundGroupSessions[roomId][sessionId] = sess;
@ -377,7 +407,10 @@ class KeyManager {
decrypted['room_id'] = roomId; decrypted['room_id'] = roomId;
setInboundGroupSession( setInboundGroupSession(
roomId, sessionId, decrypted['sender_key'], decrypted, roomId, sessionId, decrypted['sender_key'], decrypted,
forwarded: true); forwarded: true,
senderClaimedKeys: decrypted['sender_claimed_keys'] != null
? Map<String, String>.from(decrypted['sender_claimed_keys'])
: null);
} }
} }
} }
@ -556,11 +589,20 @@ class KeyManager {
if (device == null) { if (device == null) {
return; // someone we didn't send our request to replied....better ignore this return; // someone we didn't send our request to replied....better ignore this
} }
// we add the sender key to the forwarded key chain
if (!(event.content['forwarding_curve25519_key_chain'] is List)) {
event.content['forwarding_curve25519_key_chain'] = <String>[];
}
event.content['forwarding_curve25519_key_chain']
.add(event.encryptedContent['sender_key']);
// TODO: verify that the keys work to decrypt a message // TODO: verify that the keys work to decrypt a message
// alright, all checks out, let's go ahead and store this session // alright, all checks out, let's go ahead and store this session
setInboundGroupSession( setInboundGroupSession(
request.room.id, request.sessionId, request.senderKey, event.content, request.room.id, request.sessionId, request.senderKey, event.content,
forwarded: true); forwarded: true,
senderClaimedKeys: {
'ed25519': event.content['sender_claimed_ed25519_key'],
});
request.devices.removeWhere( request.devices.removeWhere(
(k) => k.userId == device.userId && k.deviceId == device.deviceId); (k) => k.userId == device.userId && k.deviceId == device.deviceId);
outgoingShareRequests.remove(request.requestId); outgoingShareRequests.remove(request.requestId);
@ -659,28 +701,19 @@ class RoomKeyRequest extends ToDeviceEvent {
var room = this.room; var room = this.room;
final session = await keyManager.loadInboundGroupSession( final session = await keyManager.loadInboundGroupSession(
room.id, request.sessionId, request.senderKey); room.id, request.sessionId, request.senderKey);
var forwardedKeys = <dynamic>[keyManager.encryption.identityKey];
for (final key in session.forwardingCurve25519KeyChain) {
forwardedKeys.add(key);
}
var message = session.content; var message = session.content;
message['forwarding_curve25519_key_chain'] = forwardedKeys; message['forwarding_curve25519_key_chain'] =
List<String>.from(session.forwardingCurve25519KeyChain);
message['sender_key'] = request.senderKey; message['sender_key'] =
(session.senderKey != null && session.senderKey.isNotEmpty)
? session.senderKey
: request.senderKey;
message['sender_claimed_ed25519_key'] = message['sender_claimed_ed25519_key'] =
forwardedKeys.isEmpty ? keyManager.encryption.fingerprintKey : null; session.senderClaimedKeys['ed25519'] ??
if (message['sender_claimed_ed25519_key'] == null) { (session.forwardingCurve25519KeyChain.isEmpty
for (final value in keyManager.client.userDeviceKeys.values) { ? keyManager.encryption.fingerprintKey
for (final key in value.deviceKeys.values) { : null);
if (key.curve25519Key == forwardedKeys.first) {
message['sender_claimed_ed25519_key'] = key.ed25519Key;
}
}
if (message['sender_claimed_ed25519_key'] != null) {
break;
}
}
}
message['session_key'] = session.inboundGroupSession message['session_key'] = session.inboundGroupSession
.export_session(session.inboundGroupSession.first_known_index()); .export_session(session.inboundGroupSession.first_known_index());
// send the actual reply of the key back to the requester // send the actual reply of the key back to the requester

View file

@ -29,23 +29,39 @@ class SessionKey {
Map<String, int> indexes; Map<String, int> indexes;
olm.InboundGroupSession inboundGroupSession; olm.InboundGroupSession inboundGroupSession;
final String key; final String key;
List<dynamic> get forwardingCurve25519KeyChain => List<String> get forwardingCurve25519KeyChain =>
content['forwarding_curve25519_key_chain'] ?? []; (content['forwarding_curve25519_key_chain'] != null
String get senderClaimedEd25519Key => ? List<String>.from(content['forwarding_curve25519_key_chain'])
content['sender_claimed_ed25519_key'] ?? ''; : null) ??
String get senderKey => content['sender_key'] ?? ''; <String>[];
Map<String, String> senderClaimedKeys;
String senderKey;
bool get isValid => inboundGroupSession != null; bool get isValid => inboundGroupSession != null;
SessionKey({this.content, this.inboundGroupSession, this.key, this.indexes}); SessionKey(
{this.content,
this.inboundGroupSession,
this.key,
this.indexes,
String senderKey,
Map<String, String> senderClaimedKeys}) {
_setSenderKey(senderKey);
_setSenderClaimedKeys(senderClaimedKeys);
}
SessionKey.fromDb(DbInboundGroupSession dbEntry, String key) : key = key { SessionKey.fromDb(DbInboundGroupSession dbEntry, String key) : key = key {
final parsedContent = Event.getMapFromPayload(dbEntry.content); final parsedContent = Event.getMapFromPayload(dbEntry.content);
final parsedIndexes = Event.getMapFromPayload(dbEntry.indexes); final parsedIndexes = Event.getMapFromPayload(dbEntry.indexes);
final parsedSenderClaimedKeys =
Event.getMapFromPayload(dbEntry.senderClaimedKeys);
content = content =
parsedContent != null ? Map<String, dynamic>.from(parsedContent) : null; parsedContent != null ? Map<String, dynamic>.from(parsedContent) : null;
indexes = parsedIndexes != null indexes = parsedIndexes != null
? Map<String, int>.from(parsedIndexes) ? Map<String, int>.from(parsedIndexes)
: <String, int>{}; : <String, int>{};
_setSenderKey(dbEntry.senderKey);
_setSenderClaimedKeys(Map<String, String>.from(parsedSenderClaimedKeys));
inboundGroupSession = olm.InboundGroupSession(); inboundGroupSession = olm.InboundGroupSession();
try { try {
inboundGroupSession.unpickle(key, dbEntry.pickle); inboundGroupSession.unpickle(key, dbEntry.pickle);
@ -57,6 +73,22 @@ class SessionKey {
} }
} }
void _setSenderKey(String key) {
senderKey = key ?? content['sender_key'] ?? '';
}
void _setSenderClaimedKeys(Map<String, String> keys) {
senderClaimedKeys = (keys != null && keys.isNotEmpty)
? keys
: (content['sender_claimed_keys'] is Map
? Map<String, String>.from(content['sender_claimed_keys'])
: (content['sender_claimed_ed25519_key'] is String
? <String, String>{
'ed25519': content['sender_claimed_ed25519_key']
}
: <String, String>{}));
}
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final data = <String, dynamic>{}; final data = <String, dynamic>{};
if (content != null) { if (content != null) {

View file

@ -20,7 +20,7 @@ class Database extends _$Database {
Database.connect(DatabaseConnection connection) : super.connect(connection); Database.connect(DatabaseConnection connection) : super.connect(connection);
@override @override
int get schemaVersion => 5; int get schemaVersion => 6;
int get maxFileSize => 1 * 1024 * 1024; int get maxFileSize => 1 * 1024 * 1024;
@ -62,6 +62,15 @@ class Database extends _$Database {
await m.addColumn(olmSessions, olmSessions.lastReceived); await m.addColumn(olmSessions, olmSessions.lastReceived);
from++; from++;
} }
if (from == 5) {
await m.addColumn(
inboundGroupSessions, inboundGroupSessions.uploaded);
await m.addColumn(
inboundGroupSessions, inboundGroupSessions.senderKey);
await m.addColumn(
inboundGroupSessions, inboundGroupSessions.senderClaimedKeys);
from++;
}
}, },
beforeOpen: (_) async { beforeOpen: (_) async {
if (executor.dialect == SqlDialect.sqlite) { if (executor.dialect == SqlDialect.sqlite) {

View file

@ -2062,19 +2062,26 @@ class DbInboundGroupSession extends DataClass
final String pickle; final String pickle;
final String content; final String content;
final String indexes; final String indexes;
final bool uploaded;
final String senderKey;
final String senderClaimedKeys;
DbInboundGroupSession( DbInboundGroupSession(
{@required this.clientId, {@required this.clientId,
@required this.roomId, @required this.roomId,
@required this.sessionId, @required this.sessionId,
@required this.pickle, @required this.pickle,
this.content, this.content,
this.indexes}); this.indexes,
this.uploaded,
this.senderKey,
this.senderClaimedKeys});
factory DbInboundGroupSession.fromData( factory DbInboundGroupSession.fromData(
Map<String, dynamic> data, GeneratedDatabase db, Map<String, dynamic> data, GeneratedDatabase db,
{String prefix}) { {String prefix}) {
final effectivePrefix = prefix ?? ''; final effectivePrefix = prefix ?? '';
final intType = db.typeSystem.forDartType<int>(); final intType = db.typeSystem.forDartType<int>();
final stringType = db.typeSystem.forDartType<String>(); final stringType = db.typeSystem.forDartType<String>();
final boolType = db.typeSystem.forDartType<bool>();
return DbInboundGroupSession( return DbInboundGroupSession(
clientId: clientId:
intType.mapFromDatabaseResponse(data['${effectivePrefix}client_id']), intType.mapFromDatabaseResponse(data['${effectivePrefix}client_id']),
@ -2088,6 +2095,12 @@ class DbInboundGroupSession extends DataClass
stringType.mapFromDatabaseResponse(data['${effectivePrefix}content']), stringType.mapFromDatabaseResponse(data['${effectivePrefix}content']),
indexes: indexes:
stringType.mapFromDatabaseResponse(data['${effectivePrefix}indexes']), stringType.mapFromDatabaseResponse(data['${effectivePrefix}indexes']),
uploaded:
boolType.mapFromDatabaseResponse(data['${effectivePrefix}uploaded']),
senderKey: stringType
.mapFromDatabaseResponse(data['${effectivePrefix}sender_key']),
senderClaimedKeys: stringType.mapFromDatabaseResponse(
data['${effectivePrefix}sender_claimed_keys']),
); );
} }
@override @override
@ -2111,6 +2124,15 @@ class DbInboundGroupSession extends DataClass
if (!nullToAbsent || indexes != null) { if (!nullToAbsent || indexes != null) {
map['indexes'] = Variable<String>(indexes); map['indexes'] = Variable<String>(indexes);
} }
if (!nullToAbsent || uploaded != null) {
map['uploaded'] = Variable<bool>(uploaded);
}
if (!nullToAbsent || senderKey != null) {
map['sender_key'] = Variable<String>(senderKey);
}
if (!nullToAbsent || senderClaimedKeys != null) {
map['sender_claimed_keys'] = Variable<String>(senderClaimedKeys);
}
return map; return map;
} }
@ -2124,6 +2146,10 @@ class DbInboundGroupSession extends DataClass
pickle: serializer.fromJson<String>(json['pickle']), pickle: serializer.fromJson<String>(json['pickle']),
content: serializer.fromJson<String>(json['content']), content: serializer.fromJson<String>(json['content']),
indexes: serializer.fromJson<String>(json['indexes']), indexes: serializer.fromJson<String>(json['indexes']),
uploaded: serializer.fromJson<bool>(json['uploaded']),
senderKey: serializer.fromJson<String>(json['sender_key']),
senderClaimedKeys:
serializer.fromJson<String>(json['sender_claimed_keys']),
); );
} }
@override @override
@ -2136,6 +2162,9 @@ class DbInboundGroupSession extends DataClass
'pickle': serializer.toJson<String>(pickle), 'pickle': serializer.toJson<String>(pickle),
'content': serializer.toJson<String>(content), 'content': serializer.toJson<String>(content),
'indexes': serializer.toJson<String>(indexes), 'indexes': serializer.toJson<String>(indexes),
'uploaded': serializer.toJson<bool>(uploaded),
'sender_key': serializer.toJson<String>(senderKey),
'sender_claimed_keys': serializer.toJson<String>(senderClaimedKeys),
}; };
} }
@ -2145,7 +2174,10 @@ class DbInboundGroupSession extends DataClass
String sessionId, String sessionId,
String pickle, String pickle,
String content, String content,
String indexes}) => String indexes,
bool uploaded,
String senderKey,
String senderClaimedKeys}) =>
DbInboundGroupSession( DbInboundGroupSession(
clientId: clientId ?? this.clientId, clientId: clientId ?? this.clientId,
roomId: roomId ?? this.roomId, roomId: roomId ?? this.roomId,
@ -2153,6 +2185,9 @@ class DbInboundGroupSession extends DataClass
pickle: pickle ?? this.pickle, pickle: pickle ?? this.pickle,
content: content ?? this.content, content: content ?? this.content,
indexes: indexes ?? this.indexes, indexes: indexes ?? this.indexes,
uploaded: uploaded ?? this.uploaded,
senderKey: senderKey ?? this.senderKey,
senderClaimedKeys: senderClaimedKeys ?? this.senderClaimedKeys,
); );
@override @override
String toString() { String toString() {
@ -2162,7 +2197,10 @@ class DbInboundGroupSession extends DataClass
..write('sessionId: $sessionId, ') ..write('sessionId: $sessionId, ')
..write('pickle: $pickle, ') ..write('pickle: $pickle, ')
..write('content: $content, ') ..write('content: $content, ')
..write('indexes: $indexes') ..write('indexes: $indexes, ')
..write('uploaded: $uploaded, ')
..write('senderKey: $senderKey, ')
..write('senderClaimedKeys: $senderClaimedKeys')
..write(')')) ..write(')'))
.toString(); .toString();
} }
@ -2174,8 +2212,16 @@ class DbInboundGroupSession extends DataClass
roomId.hashCode, roomId.hashCode,
$mrjc( $mrjc(
sessionId.hashCode, sessionId.hashCode,
$mrjc(pickle.hashCode, $mrjc(
$mrjc(content.hashCode, indexes.hashCode)))))); pickle.hashCode,
$mrjc(
content.hashCode,
$mrjc(
indexes.hashCode,
$mrjc(
uploaded.hashCode,
$mrjc(senderKey.hashCode,
senderClaimedKeys.hashCode)))))))));
@override @override
bool operator ==(dynamic other) => bool operator ==(dynamic other) =>
identical(this, other) || identical(this, other) ||
@ -2185,7 +2231,10 @@ class DbInboundGroupSession extends DataClass
other.sessionId == this.sessionId && other.sessionId == this.sessionId &&
other.pickle == this.pickle && other.pickle == this.pickle &&
other.content == this.content && other.content == this.content &&
other.indexes == this.indexes); other.indexes == this.indexes &&
other.uploaded == this.uploaded &&
other.senderKey == this.senderKey &&
other.senderClaimedKeys == this.senderClaimedKeys);
} }
class InboundGroupSessionsCompanion class InboundGroupSessionsCompanion
@ -2196,6 +2245,9 @@ class InboundGroupSessionsCompanion
final Value<String> pickle; final Value<String> pickle;
final Value<String> content; final Value<String> content;
final Value<String> indexes; final Value<String> indexes;
final Value<bool> uploaded;
final Value<String> senderKey;
final Value<String> senderClaimedKeys;
const InboundGroupSessionsCompanion({ const InboundGroupSessionsCompanion({
this.clientId = const Value.absent(), this.clientId = const Value.absent(),
this.roomId = const Value.absent(), this.roomId = const Value.absent(),
@ -2203,6 +2255,9 @@ class InboundGroupSessionsCompanion
this.pickle = const Value.absent(), this.pickle = const Value.absent(),
this.content = const Value.absent(), this.content = const Value.absent(),
this.indexes = const Value.absent(), this.indexes = const Value.absent(),
this.uploaded = const Value.absent(),
this.senderKey = const Value.absent(),
this.senderClaimedKeys = const Value.absent(),
}); });
InboundGroupSessionsCompanion.insert({ InboundGroupSessionsCompanion.insert({
@required int clientId, @required int clientId,
@ -2211,6 +2266,9 @@ class InboundGroupSessionsCompanion
@required String pickle, @required String pickle,
this.content = const Value.absent(), this.content = const Value.absent(),
this.indexes = const Value.absent(), this.indexes = const Value.absent(),
this.uploaded = const Value.absent(),
this.senderKey = const Value.absent(),
this.senderClaimedKeys = const Value.absent(),
}) : clientId = Value(clientId), }) : clientId = Value(clientId),
roomId = Value(roomId), roomId = Value(roomId),
sessionId = Value(sessionId), sessionId = Value(sessionId),
@ -2222,6 +2280,9 @@ class InboundGroupSessionsCompanion
Expression<String> pickle, Expression<String> pickle,
Expression<String> content, Expression<String> content,
Expression<String> indexes, Expression<String> indexes,
Expression<bool> uploaded,
Expression<String> senderKey,
Expression<String> senderClaimedKeys,
}) { }) {
return RawValuesInsertable({ return RawValuesInsertable({
if (clientId != null) 'client_id': clientId, if (clientId != null) 'client_id': clientId,
@ -2230,6 +2291,9 @@ class InboundGroupSessionsCompanion
if (pickle != null) 'pickle': pickle, if (pickle != null) 'pickle': pickle,
if (content != null) 'content': content, if (content != null) 'content': content,
if (indexes != null) 'indexes': indexes, if (indexes != null) 'indexes': indexes,
if (uploaded != null) 'uploaded': uploaded,
if (senderKey != null) 'sender_key': senderKey,
if (senderClaimedKeys != null) 'sender_claimed_keys': senderClaimedKeys,
}); });
} }
@ -2239,7 +2303,10 @@ class InboundGroupSessionsCompanion
Value<String> sessionId, Value<String> sessionId,
Value<String> pickle, Value<String> pickle,
Value<String> content, Value<String> content,
Value<String> indexes}) { Value<String> indexes,
Value<bool> uploaded,
Value<String> senderKey,
Value<String> senderClaimedKeys}) {
return InboundGroupSessionsCompanion( return InboundGroupSessionsCompanion(
clientId: clientId ?? this.clientId, clientId: clientId ?? this.clientId,
roomId: roomId ?? this.roomId, roomId: roomId ?? this.roomId,
@ -2247,6 +2314,9 @@ class InboundGroupSessionsCompanion
pickle: pickle ?? this.pickle, pickle: pickle ?? this.pickle,
content: content ?? this.content, content: content ?? this.content,
indexes: indexes ?? this.indexes, indexes: indexes ?? this.indexes,
uploaded: uploaded ?? this.uploaded,
senderKey: senderKey ?? this.senderKey,
senderClaimedKeys: senderClaimedKeys ?? this.senderClaimedKeys,
); );
} }
@ -2271,6 +2341,15 @@ class InboundGroupSessionsCompanion
if (indexes.present) { if (indexes.present) {
map['indexes'] = Variable<String>(indexes.value); map['indexes'] = Variable<String>(indexes.value);
} }
if (uploaded.present) {
map['uploaded'] = Variable<bool>(uploaded.value);
}
if (senderKey.present) {
map['sender_key'] = Variable<String>(senderKey.value);
}
if (senderClaimedKeys.present) {
map['sender_claimed_keys'] = Variable<String>(senderClaimedKeys.value);
}
return map; return map;
} }
} }
@ -2328,9 +2407,45 @@ class InboundGroupSessions extends Table
$customConstraints: ''); $customConstraints: '');
} }
final VerificationMeta _uploadedMeta = const VerificationMeta('uploaded');
GeneratedBoolColumn _uploaded;
GeneratedBoolColumn get uploaded => _uploaded ??= _constructUploaded();
GeneratedBoolColumn _constructUploaded() {
return GeneratedBoolColumn('uploaded', $tableName, true,
$customConstraints: 'DEFAULT false',
defaultValue: const CustomExpression<bool>('false'));
}
final VerificationMeta _senderKeyMeta = const VerificationMeta('senderKey');
GeneratedTextColumn _senderKey;
GeneratedTextColumn get senderKey => _senderKey ??= _constructSenderKey();
GeneratedTextColumn _constructSenderKey() {
return GeneratedTextColumn('sender_key', $tableName, true,
$customConstraints: '');
}
final VerificationMeta _senderClaimedKeysMeta =
const VerificationMeta('senderClaimedKeys');
GeneratedTextColumn _senderClaimedKeys;
GeneratedTextColumn get senderClaimedKeys =>
_senderClaimedKeys ??= _constructSenderClaimedKeys();
GeneratedTextColumn _constructSenderClaimedKeys() {
return GeneratedTextColumn('sender_claimed_keys', $tableName, true,
$customConstraints: '');
}
@override @override
List<GeneratedColumn> get $columns => List<GeneratedColumn> get $columns => [
[clientId, roomId, sessionId, pickle, content, indexes]; clientId,
roomId,
sessionId,
pickle,
content,
indexes,
uploaded,
senderKey,
senderClaimedKeys
];
@override @override
InboundGroupSessions get asDslTable => this; InboundGroupSessions get asDslTable => this;
@override @override
@ -2375,6 +2490,20 @@ class InboundGroupSessions extends Table
context.handle(_indexesMeta, context.handle(_indexesMeta,
indexes.isAcceptableOrUnknown(data['indexes'], _indexesMeta)); indexes.isAcceptableOrUnknown(data['indexes'], _indexesMeta));
} }
if (data.containsKey('uploaded')) {
context.handle(_uploadedMeta,
uploaded.isAcceptableOrUnknown(data['uploaded'], _uploadedMeta));
}
if (data.containsKey('sender_key')) {
context.handle(_senderKeyMeta,
senderKey.isAcceptableOrUnknown(data['sender_key'], _senderKeyMeta));
}
if (data.containsKey('sender_claimed_keys')) {
context.handle(
_senderClaimedKeysMeta,
senderClaimedKeys.isAcceptableOrUnknown(
data['sender_claimed_keys'], _senderClaimedKeysMeta));
}
return context; return context;
} }
@ -5669,6 +5798,9 @@ abstract class _$Database extends GeneratedDatabase {
pickle: row.readString('pickle'), pickle: row.readString('pickle'),
content: row.readString('content'), content: row.readString('content'),
indexes: row.readString('indexes'), indexes: row.readString('indexes'),
uploaded: row.readBool('uploaded'),
senderKey: row.readString('sender_key'),
senderClaimedKeys: row.readString('sender_claimed_keys'),
); );
} }
@ -5701,17 +5833,26 @@ abstract class _$Database extends GeneratedDatabase {
readsFrom: {inboundGroupSessions}).map(_rowToDbInboundGroupSession); readsFrom: {inboundGroupSessions}).map(_rowToDbInboundGroupSession);
} }
Future<int> storeInboundGroupSession(int client_id, String room_id, Future<int> storeInboundGroupSession(
String session_id, String pickle, String content, String indexes) { int client_id,
String room_id,
String session_id,
String pickle,
String content,
String indexes,
String sender_key,
String sender_claimed_keys) {
return customInsert( return customInsert(
'INSERT OR REPLACE INTO inbound_group_sessions (client_id, room_id, session_id, pickle, content, indexes) VALUES (:client_id, :room_id, :session_id, :pickle, :content, :indexes)', 'INSERT OR REPLACE INTO inbound_group_sessions (client_id, room_id, session_id, pickle, content, indexes, sender_key, sender_claimed_keys) VALUES (:client_id, :room_id, :session_id, :pickle, :content, :indexes, :sender_key, :sender_claimed_keys)',
variables: [ variables: [
Variable.withInt(client_id), Variable.withInt(client_id),
Variable.withString(room_id), Variable.withString(room_id),
Variable.withString(session_id), Variable.withString(session_id),
Variable.withString(pickle), Variable.withString(pickle),
Variable.withString(content), Variable.withString(content),
Variable.withString(indexes) Variable.withString(indexes),
Variable.withString(sender_key),
Variable.withString(sender_claimed_keys)
], ],
updates: {inboundGroupSessions}, updates: {inboundGroupSessions},
); );

View file

@ -71,6 +71,9 @@ CREATE TABLE inbound_group_sessions (
pickle TEXT NOT NULL, pickle TEXT NOT NULL,
content TEXT, content TEXT,
indexes TEXT, indexes TEXT,
uploaded BOOLEAN DEFAULT false,
sender_key TEXT,
sender_claimed_keys TEXT,
UNIQUE(client_id, room_id, session_id) UNIQUE(client_id, room_id, session_id)
) AS DbInboundGroupSession; ) AS DbInboundGroupSession;
CREATE INDEX inbound_group_sessions_index ON inbound_group_sessions(client_id); CREATE INDEX inbound_group_sessions_index ON inbound_group_sessions(client_id);
@ -186,7 +189,7 @@ removeOutboundGroupSession: DELETE FROM outbound_group_sessions WHERE client_id
dbGetInboundGroupSessionKey: SELECT * FROM inbound_group_sessions WHERE client_id = :client_id AND room_id = :room_id AND session_id = :session_id; dbGetInboundGroupSessionKey: SELECT * FROM inbound_group_sessions WHERE client_id = :client_id AND room_id = :room_id AND session_id = :session_id;
dbGetInboundGroupSessionKeys: SELECT * FROM inbound_group_sessions WHERE client_id = :client_id AND room_id = :room_id; dbGetInboundGroupSessionKeys: SELECT * FROM inbound_group_sessions WHERE client_id = :client_id AND room_id = :room_id;
getAllInboundGroupSessions: SELECT * FROM inbound_group_sessions WHERE client_id = :client_id; getAllInboundGroupSessions: SELECT * FROM inbound_group_sessions WHERE client_id = :client_id;
storeInboundGroupSession: INSERT OR REPLACE INTO inbound_group_sessions (client_id, room_id, session_id, pickle, content, indexes) VALUES (:client_id, :room_id, :session_id, :pickle, :content, :indexes); storeInboundGroupSession: INSERT OR REPLACE INTO inbound_group_sessions (client_id, room_id, session_id, pickle, content, indexes, sender_key, sender_claimed_keys) VALUES (:client_id, :room_id, :session_id, :pickle, :content, :indexes, :sender_key, :sender_claimed_keys);
updateInboundGroupSessionIndexes: UPDATE inbound_group_sessions SET indexes = :indexes WHERE client_id = :client_id AND room_id = :room_id AND session_id = :session_id; updateInboundGroupSessionIndexes: UPDATE inbound_group_sessions SET indexes = :indexes WHERE client_id = :client_id AND room_id = :room_id AND session_id = :session_id;
storeUserDeviceKeysInfo: INSERT OR REPLACE INTO user_device_keys (client_id, user_id, outdated) VALUES (:client_id, :user_id, :outdated); storeUserDeviceKeysInfo: INSERT OR REPLACE INTO user_device_keys (client_id, user_id, outdated) VALUES (:client_id, :user_id, :outdated);
setVerifiedUserDeviceKey: UPDATE user_device_keys_key SET verified = :verified WHERE client_id = :client_id AND user_id = :user_id AND device_id = :device_id; setVerifiedUserDeviceKey: UPDATE user_device_keys_key SET verified = :verified WHERE client_id = :client_id AND user_id = :user_id AND device_id = :device_id;

View file

@ -60,7 +60,7 @@ void main() {
'session_key': sessionKey, 'session_key': sessionKey,
}, },
encryptedContent: { encryptedContent: {
'sender_key': validSessionId, 'sender_key': validSenderKey,
}); });
await client.encryption.keyManager.handleToDeviceEvent(event); await client.encryption.keyManager.handleToDeviceEvent(event);
expect( expect(
@ -185,6 +185,11 @@ void main() {
.getInboundGroupSession(roomId, sessionId, senderKey) != .getInboundGroupSession(roomId, sessionId, senderKey) !=
null, null,
true); true);
expect(
client.encryption.keyManager
.getInboundGroupSession(roomId, sessionId, 'invalid') !=
null,
false);
expect( expect(
client.encryption.keyManager client.encryption.keyManager
@ -196,6 +201,11 @@ void main() {
.getInboundGroupSession('otherroom', sessionId, senderKey) != .getInboundGroupSession('otherroom', sessionId, senderKey) !=
null, null,
true); true);
expect(
client.encryption.keyManager
.getInboundGroupSession('otherroom', sessionId, 'invalid') !=
null,
false);
expect( expect(
client.encryption.keyManager client.encryption.keyManager
.getInboundGroupSession('otherroom', 'invalid', senderKey) != .getInboundGroupSession('otherroom', 'invalid', senderKey) !=
@ -215,6 +225,20 @@ void main() {
.getInboundGroupSession(roomId, sessionId, senderKey) != .getInboundGroupSession(roomId, sessionId, senderKey) !=
null, null,
true); true);
client.encryption.keyManager.clearInboundGroupSessions();
expect(
client.encryption.keyManager
.getInboundGroupSession(roomId, sessionId, senderKey) !=
null,
false);
await client.encryption.keyManager
.loadInboundGroupSession(roomId, sessionId, 'invalid');
expect(
client.encryption.keyManager
.getInboundGroupSession(roomId, sessionId, 'invalid') !=
null,
false);
}); });
test('setInboundGroupSession', () async { test('setInboundGroupSession', () async {

View file

@ -53,7 +53,7 @@ void main() {
if (!olmEnabled) return; if (!olmEnabled) return;
final validSessionId = 'ciM/JWTPrmiWPPZNkRLDPQYf9AW/I46bxyLSr+Bx5oU'; final validSessionId = 'ciM/JWTPrmiWPPZNkRLDPQYf9AW/I46bxyLSr+Bx5oU';
final validSenderKey = '3C5BFWi2Y8MaVvjM8M22DBmh24PmgR0nPvJOIArzgyI'; final validSenderKey = 'JBG7ZaPn54OBC7TuIEiylW3BZ+7WcGQhFBPB9pogbAg';
test('Create Request', () async { test('Create Request', () async {
var matrix = await getClient(); var matrix = await getClient();
final requestRoom = matrix.getRoomById('!726s6s6q:example.com'); final requestRoom = matrix.getRoomById('!726s6s6q:example.com');