diff --git a/lib/encryption/ssss.dart b/lib/encryption/ssss.dart index 0d9bc0d..43da3ca 100644 --- a/lib/encryption/ssss.dart +++ b/lib/encryption/ssss.dart @@ -177,7 +177,7 @@ class SSSS { } // check if it is still valid final keys = keyIdsFromType(type); - if (keys.contains(ret.keyId)) { + if (keys.contains(ret.keyId) && client.accountData[type].content['encrypted'][ret.keyId]['ciphertext'] == ret.ciphertext) { return ret.content; } return null; @@ -200,7 +200,7 @@ class SSSS { final decrypted = decryptAes(encryptInfo, key, type); if (CACHE_TYPES.contains(type) && client.database != null) { // cache the thing - await client.database.storeSSSSCache(client.id, type, keyId, decrypted); + await client.database.storeSSSSCache(client.id, type, keyId, enc['ciphertext'], decrypted); } return decrypted; } @@ -224,7 +224,7 @@ class SSSS { ); if (CACHE_TYPES.contains(type) && client.database != null) { // cache the thing - await client.database.storeSSSSCache(client.id, type, keyId, secret); + await client.database.storeSSSSCache(client.id, type, keyId, encrypted.ciphertext, secret); } } @@ -352,8 +352,9 @@ class SSSS { if (client.database != null) { final keyId = keyIdFromType(request.type); if (keyId != null) { + final ciphertext = client.accountData[request.type].content['encrypted'][keyId]['ciphertext']; await client.database - .storeSSSSCache(client.id, request.type, keyId, secret); + .storeSSSSCache(client.id, request.type, keyId, ciphertext, secret); } } } diff --git a/lib/src/database/database.g.dart b/lib/src/database/database.g.dart index 6cfaac8..0c50118 100644 --- a/lib/src/database/database.g.dart +++ b/lib/src/database/database.g.dart @@ -4805,11 +4805,13 @@ class DbSSSSCache extends DataClass implements Insertable { final int clientId; final String type; final String keyId; + final String ciphertext; final String content; DbSSSSCache( {@required this.clientId, @required this.type, @required this.keyId, + @required this.ciphertext, @required this.content}); factory DbSSSSCache.fromData(Map data, GeneratedDatabase db, {String prefix}) { @@ -4822,6 +4824,8 @@ class DbSSSSCache extends DataClass implements Insertable { type: stringType.mapFromDatabaseResponse(data['${effectivePrefix}type']), keyId: stringType.mapFromDatabaseResponse(data['${effectivePrefix}key_id']), + ciphertext: stringType + .mapFromDatabaseResponse(data['${effectivePrefix}ciphertext']), content: stringType.mapFromDatabaseResponse(data['${effectivePrefix}content']), ); @@ -4838,6 +4842,9 @@ class DbSSSSCache extends DataClass implements Insertable { if (!nullToAbsent || keyId != null) { map['key_id'] = Variable(keyId); } + if (!nullToAbsent || ciphertext != null) { + map['ciphertext'] = Variable(ciphertext); + } if (!nullToAbsent || content != null) { map['content'] = Variable(content); } @@ -4851,6 +4858,7 @@ class DbSSSSCache extends DataClass implements Insertable { clientId: serializer.fromJson(json['client_id']), type: serializer.fromJson(json['type']), keyId: serializer.fromJson(json['key_id']), + ciphertext: serializer.fromJson(json['ciphertext']), content: serializer.fromJson(json['content']), ); } @@ -4861,16 +4869,22 @@ class DbSSSSCache extends DataClass implements Insertable { 'client_id': serializer.toJson(clientId), 'type': serializer.toJson(type), 'key_id': serializer.toJson(keyId), + 'ciphertext': serializer.toJson(ciphertext), 'content': serializer.toJson(content), }; } DbSSSSCache copyWith( - {int clientId, String type, String keyId, String content}) => + {int clientId, + String type, + String keyId, + String ciphertext, + String content}) => DbSSSSCache( clientId: clientId ?? this.clientId, type: type ?? this.type, keyId: keyId ?? this.keyId, + ciphertext: ciphertext ?? this.ciphertext, content: content ?? this.content, ); @override @@ -4879,14 +4893,19 @@ class DbSSSSCache extends DataClass implements Insertable { ..write('clientId: $clientId, ') ..write('type: $type, ') ..write('keyId: $keyId, ') + ..write('ciphertext: $ciphertext, ') ..write('content: $content') ..write(')')) .toString(); } @override - int get hashCode => $mrjf($mrjc(clientId.hashCode, - $mrjc(type.hashCode, $mrjc(keyId.hashCode, content.hashCode)))); + int get hashCode => $mrjf($mrjc( + clientId.hashCode, + $mrjc( + type.hashCode, + $mrjc( + keyId.hashCode, $mrjc(ciphertext.hashCode, content.hashCode))))); @override bool operator ==(dynamic other) => identical(this, other) || @@ -4894,6 +4913,7 @@ class DbSSSSCache extends DataClass implements Insertable { other.clientId == this.clientId && other.type == this.type && other.keyId == this.keyId && + other.ciphertext == this.ciphertext && other.content == this.content); } @@ -4901,32 +4921,38 @@ class SsssCacheCompanion extends UpdateCompanion { final Value clientId; final Value type; final Value keyId; + final Value ciphertext; final Value content; const SsssCacheCompanion({ this.clientId = const Value.absent(), this.type = const Value.absent(), this.keyId = const Value.absent(), + this.ciphertext = const Value.absent(), this.content = const Value.absent(), }); SsssCacheCompanion.insert({ @required int clientId, @required String type, @required String keyId, + @required String ciphertext, @required String content, }) : clientId = Value(clientId), type = Value(type), keyId = Value(keyId), + ciphertext = Value(ciphertext), content = Value(content); static Insertable custom({ Expression clientId, Expression type, Expression keyId, + Expression ciphertext, Expression content, }) { return RawValuesInsertable({ if (clientId != null) 'client_id': clientId, if (type != null) 'type': type, if (keyId != null) 'key_id': keyId, + if (ciphertext != null) 'ciphertext': ciphertext, if (content != null) 'content': content, }); } @@ -4935,11 +4961,13 @@ class SsssCacheCompanion extends UpdateCompanion { {Value clientId, Value type, Value keyId, + Value ciphertext, Value content}) { return SsssCacheCompanion( clientId: clientId ?? this.clientId, type: type ?? this.type, keyId: keyId ?? this.keyId, + ciphertext: ciphertext ?? this.ciphertext, content: content ?? this.content, ); } @@ -4956,6 +4984,9 @@ class SsssCacheCompanion extends UpdateCompanion { if (keyId.present) { map['key_id'] = Variable(keyId.value); } + if (ciphertext.present) { + map['ciphertext'] = Variable(ciphertext.value); + } if (content.present) { map['content'] = Variable(content.value); } @@ -4991,6 +5022,14 @@ class SsssCache extends Table with TableInfo { $customConstraints: 'NOT NULL'); } + final VerificationMeta _ciphertextMeta = const VerificationMeta('ciphertext'); + GeneratedTextColumn _ciphertext; + GeneratedTextColumn get ciphertext => _ciphertext ??= _constructCiphertext(); + GeneratedTextColumn _constructCiphertext() { + return GeneratedTextColumn('ciphertext', $tableName, false, + $customConstraints: 'NOT NULL'); + } + final VerificationMeta _contentMeta = const VerificationMeta('content'); GeneratedTextColumn _content; GeneratedTextColumn get content => _content ??= _constructContent(); @@ -5000,7 +5039,8 @@ class SsssCache extends Table with TableInfo { } @override - List get $columns => [clientId, type, keyId, content]; + List get $columns => + [clientId, type, keyId, ciphertext, content]; @override SsssCache get asDslTable => this; @override @@ -5030,6 +5070,14 @@ class SsssCache extends Table with TableInfo { } else if (isInserting) { context.missing(_keyIdMeta); } + if (data.containsKey('ciphertext')) { + context.handle( + _ciphertextMeta, + ciphertext.isAcceptableOrUnknown( + data['ciphertext'], _ciphertextMeta)); + } else if (isInserting) { + context.missing(_ciphertextMeta); + } if (data.containsKey('content')) { context.handle(_contentMeta, content.isAcceptableOrUnknown(data['content'], _contentMeta)); @@ -5770,14 +5818,15 @@ abstract class _$Database extends GeneratedDatabase { ); } - Future storeSSSSCache( - int client_id, String type, String key_id, String content) { + Future storeSSSSCache(int client_id, String type, String key_id, + String ciphertext, String content) { return customInsert( - 'INSERT OR REPLACE INTO ssss_cache (client_id, type, key_id, content) VALUES (:client_id, :type, :key_id, :content)', + 'INSERT OR REPLACE INTO ssss_cache (client_id, type, key_id, ciphertext, content) VALUES (:client_id, :type, :key_id, :ciphertext, :content)', variables: [ Variable.withInt(client_id), Variable.withString(type), Variable.withString(key_id), + Variable.withString(ciphertext), Variable.withString(content) ], updates: {ssssCache}, @@ -5789,6 +5838,7 @@ abstract class _$Database extends GeneratedDatabase { clientId: row.readInt('client_id'), type: row.readString('type'), keyId: row.readString('key_id'), + ciphertext: row.readString('ciphertext'), content: row.readString('content'), ); } diff --git a/lib/src/database/database.moor b/lib/src/database/database.moor index 2601b6c..68a0ee5 100644 --- a/lib/src/database/database.moor +++ b/lib/src/database/database.moor @@ -78,6 +78,7 @@ CREATE TABLE ssss_cache ( client_id INTEGER NOT NULL REFERENCES clients(client_id), type TEXT NOT NULL, key_id TEXT NOT NULL, + ciphertext TEXT NOT NULL, content TEXT NOT NULL, UNIQUE(client_id, type) ) AS DbSSSSCache; @@ -195,7 +196,7 @@ setVerifiedUserCrossSigningKey: UPDATE user_cross_signing_keys SET verified = :v setBlockedUserCrossSigningKey: UPDATE user_cross_signing_keys SET blocked = :blocked WHERE client_id = :client_id AND user_id = :user_id AND public_key = :public_key; storeUserCrossSigningKey: INSERT OR REPLACE INTO user_cross_signing_keys (client_id, user_id, public_key, content, verified, blocked) VALUES (:client_id, :user_id, :public_key, :content, :verified, :blocked); removeUserCrossSigningKey: DELETE FROM user_cross_signing_keys WHERE client_id = :client_id AND user_id = :user_id AND public_key = :public_key; -storeSSSSCache: INSERT OR REPLACE INTO ssss_cache (client_id, type, key_id, content) VALUES (:client_id, :type, :key_id, :content); +storeSSSSCache: INSERT OR REPLACE INTO ssss_cache (client_id, type, key_id, ciphertext, content) VALUES (:client_id, :type, :key_id, :ciphertext, :content); dbGetSSSSCache: SELECT * FROM ssss_cache WHERE client_id = :client_id AND type = :type; insertClient: INSERT INTO clients (name, homeserver_url, token, user_id, device_id, device_name, prev_batch, olm_account) VALUES (:name, :homeserver_url, :token, :user_id, :device_id, :device_name, :prev_batch, :olm_account); ensureRoomExists: INSERT OR IGNORE INTO rooms (client_id, room_id, membership) VALUES (:client_id, :room_id, :membership);