refactor: Create a clean database API

This commit is contained in:
Christian Pauly 2021-05-20 09:21:07 +02:00 committed by Krille Fear
parent 6fae2e1426
commit c66e35c16c
15 changed files with 601 additions and 80 deletions

View File

@ -136,7 +136,6 @@ pages:
- public
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
# Adds license-scanning job. Because Gitlab does not support pub.dev
# we added https://github.com/oss-review-toolkit/ort

View File

@ -18,13 +18,13 @@
import 'dart:convert';
import 'package:famedlysdk/encryption/utils/stored_inbound_group_session.dart';
import 'package:olm/olm.dart' as olm;
import './encryption.dart';
import './utils/outbound_group_session.dart';
import './utils/session_key.dart';
import '../famedlysdk.dart';
import '../src/database/database.dart';
import '../src/utils/run_in_background.dart';
import '../src/utils/run_in_root.dart';
@ -231,15 +231,14 @@ class KeyManager {
}
return sess; // nothing to do
}
final session = await client.database
?.getDbInboundGroupSession(client.id, roomId, sessionId);
if (session == null) {
final sess = await client.database
?.getInboundGroupSession(client.id, roomId, sessionId, client.userID);
if (sess == null) {
return null;
}
if (!_inboundGroupSessions.containsKey(roomId)) {
_inboundGroupSessions[roomId] = <String, SessionKey>{};
}
final sess = SessionKey.fromDb(session, client.userID);
if (!sess.isValid ||
(sess.senderKey.isNotEmpty && sess.senderKey != senderKey)) {
return null;
@ -506,13 +505,12 @@ class KeyManager {
return; // nothing to do
}
_loadedOutboundGroupSessions.add(roomId);
final session =
await client.database.getDbOutboundGroupSession(client.id, roomId);
if (session == null) {
return;
}
final sess = OutboundGroupSession.fromDb(session, client.userID);
if (!sess.isValid) {
final sess = await client.database.getOutboundGroupSession(
client.id,
roomId,
client.userID,
);
if (sess == null || !sess.isValid) {
return;
}
_outboundGroupSessions[roomId] = sess;
@ -693,7 +691,7 @@ class KeyManager {
return; // we can't backup anyways
}
final dbSessions =
await client.database.getInboundGroupSessionsToUpload().get();
await client.database.getInboundGroupSessionsToUpload();
if (dbSessions.isEmpty) {
_haveKeysToUpload = false;
return; // nothing to do
@ -1060,7 +1058,7 @@ RoomKeys _generateUploadKeys(_GenerateUploadKeysArgs args) {
class _DbInboundGroupSessionBundle {
_DbInboundGroupSessionBundle({this.dbSession, this.verified});
DbInboundGroupSession dbSession;
StoredInboundGroupSession dbSession;
bool verified;
}

View File

@ -410,16 +410,9 @@ class OlmManager {
if (client.database == null) {
return [];
}
final rows =
await client.database.dbGetOlmSessions(client.id, senderKey).get();
final res = <OlmSession>[];
for (final row in rows) {
final sess = OlmSession.fromDb(row, client.userID);
if (sess.isValid) {
res.add(sess);
}
}
return res;
final olmSessions = await client.database
.getOlmSessions(client.id, senderKey, client.userID);
return olmSessions.where((sess) => sess.isValid).toList();
}
Future<void> getOlmSessionsForDevicesFromDatabase(
@ -427,15 +420,16 @@ class OlmManager {
if (client.database == null) {
return;
}
final rows = await client.database
.dbGetOlmSessionsForDevices(client.id, senderKeys)
.get();
final rows = await client.database.getOlmSessionsForDevices(
client.id,
senderKeys,
client.userID,
);
final res = <String, List<OlmSession>>{};
for (final row in rows) {
res[row.identityKey] ??= <OlmSession>[];
final sess = OlmSession.fromDb(row, client.userID);
for (final sess in rows) {
res[sess.identityKey] ??= <OlmSession>[];
if (sess.isValid) {
res[row.identityKey].add(sess);
res[sess.identityKey].add(sess);
}
}
for (final entry in res.entries) {
@ -653,8 +647,7 @@ class OlmManager {
'[OlmManager] Device ${device.userId}:${device.deviceId} generated a new olm session, replaying last sent message...');
final lastSentMessageRes = await client.database
.getLastSentMessageUserDeviceKey(
client.id, device.userId, device.deviceId)
.get();
client.id, device.userId, device.deviceId);
if (lastSentMessageRes.isEmpty ||
(lastSentMessageRes.first?.isEmpty ?? true)) {
return;

View File

@ -25,11 +25,11 @@ import 'package:base58check/base58.dart';
import 'package:crypto/crypto.dart';
import '../famedlysdk.dart';
import '../src/database/database.dart';
import '../src/utils/crypto/crypto.dart' as uc;
import '../src/utils/run_in_background.dart';
import '../src/utils/run_in_root.dart';
import 'encryption.dart';
import 'utils/ssss_cache.dart';
const cacheTypes = <String>{
EventTypes.CrossSigningSelfSigning,
@ -56,7 +56,7 @@ class SSSS {
final pendingShareRequests = <String, _ShareRequest>{};
final _validators = <String, FutureOr<bool> Function(String)>{};
final _cacheCallbacks = <String, FutureOr<void> Function(String)>{};
final Map<String, DbSSSSCache> _cache = <String, DbSSSSCache>{};
final Map<String, SSSSCache> _cache = <String, SSSSCache>{};
SSSS(this.encryption);
// for testing

View File

@ -16,10 +16,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import 'package:famedlysdk/encryption/utils/stored_inbound_group_session.dart';
import 'package:olm/olm.dart' as olm;
import '../../famedlysdk.dart';
import '../../src/database/database.dart' show DbInboundGroupSession;
class SessionKey {
/// The raw json content of the key
@ -76,7 +76,7 @@ class SessionKey {
allowedAtIndex ??= <String, Map<String, int>>{};
}
SessionKey.fromDb(DbInboundGroupSession dbEntry, String key) : key = key {
SessionKey.fromDb(StoredInboundGroupSession dbEntry, String key) : key = key {
final parsedContent = Event.getMapFromPayload(dbEntry.content);
final parsedIndexes = Event.getMapFromPayload(dbEntry.indexes);
final parsedAllowedAtIndex =

View File

@ -0,0 +1,44 @@
/*
* Famedly Matrix SDK
* Copyright (C) 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 <https://www.gnu.org/licenses/>.
*/
class SSSSCache {
final int clientId;
final String type;
final String keyId;
final String ciphertext;
final String content;
const SSSSCache(
{this.clientId, this.type, this.keyId, this.ciphertext, this.content});
factory SSSSCache.fromJson(Map<String, dynamic> json) => SSSSCache(
clientId: json['client_id'],
type: json['type'],
keyId: json['key_id'],
ciphertext: json['ciphertext'],
content: json['content'],
);
Map<String, dynamic> toJson() => {
'client_id': clientId,
'type': type,
'key_id': keyId,
'ciphertext': ciphertext,
'content': content,
};
}

View File

@ -0,0 +1,57 @@
/*
* Famedly Matrix SDK
* Copyright (C) 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 <https://www.gnu.org/licenses/>.
*/
class StoredInboundGroupSession {
final int clientId;
final String roomId;
final String sessionId;
final String pickle;
final String content;
final String indexes;
final String allowedAtIndex;
final bool uploaded;
final String senderKey;
final String senderClaimedKeys;
StoredInboundGroupSession({
this.clientId,
this.roomId,
this.sessionId,
this.pickle,
this.content,
this.indexes,
this.allowedAtIndex,
this.uploaded,
this.senderKey,
this.senderClaimedKeys,
});
factory StoredInboundGroupSession.fromJson(Map<String, dynamic> json) =>
StoredInboundGroupSession(
clientId: json['client_id'],
roomId: json['room_id'],
sessionId: json['session_id'],
pickle: json['pickle'],
content: json['content'],
indexes: json['indexes'],
allowedAtIndex: json['allowed_at_index'],
uploaded: json['uploaded'],
senderKey: json['sender_key'],
senderClaimedKeys: json['sender_claimed_keys'],
);
}

View File

@ -28,7 +28,7 @@ import 'package:pedantic/pedantic.dart';
import '../encryption.dart';
import '../famedlysdk.dart';
import 'database/database.dart' show Database;
import 'database/database_api.dart';
import 'event.dart';
import 'room.dart';
import 'user.dart';
@ -56,11 +56,11 @@ class Client extends MatrixApi {
int get id => _id;
final FutureOr<Database> Function(Client) databaseBuilder;
final FutureOr<DatabaseApi> Function(Client) databaseBuilder;
final FutureOr<void> Function(Client) databaseDestroyer;
Database _database;
DatabaseApi _database;
Database get database => _database;
DatabaseApi get database => _database;
bool enableE2eeRecovery;
@ -919,7 +919,7 @@ class Client extends MatrixApi {
);
}
_userDeviceKeys = await database.getUserDeviceKeys(this);
_rooms = await database.getRoomList(this, onlyLeft: false);
_rooms = await database.getRoomList(this);
_sortRooms();
accountData = await database.getAccountData(id);
presences.clear();
@ -1753,18 +1753,20 @@ sort order of ${prevState.sortOrder}. This should never happen...''');
if (database == null || !_toDeviceQueueNeedsProcessing) {
return;
}
final entries = await database.getToDeviceQueue(id).get();
final entries = await database.getToDeviceEventQueue(id);
if (entries.isEmpty) {
_toDeviceQueueNeedsProcessing = false;
return;
}
for (final entry in entries) {
// ohgod what is this...
final data = (json.decode(entry.content) as Map).map((k, v) =>
// Convert the Json Map to the correct format regarding
// https: //matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-sendtodevice-eventtype-txnid
final data = entry.content.map((k, v) =>
MapEntry<String, Map<String, Map<String, dynamic>>>(
k,
(v as Map).map((k, v) => MapEntry<String, Map<String, dynamic>>(
k, Map<String, dynamic>.from(v)))));
await super.sendToDevice(entry.type, entry.txnId, data);
await database.deleteFromToDeviceQueue(id, entry.id);
}

View File

@ -19,12 +19,19 @@
import 'dart:async';
import 'dart:convert';
import 'package:famedlysdk/encryption/utils/olm_session.dart';
import 'package:famedlysdk/encryption/utils/outbound_group_session.dart';
import 'package:famedlysdk/encryption/utils/session_key.dart';
import 'package:famedlysdk/encryption/utils/ssss_cache.dart';
import 'package:famedlysdk/encryption/utils/stored_inbound_group_session.dart';
import 'package:famedlysdk/src/utils/QueuedToDeviceEvent.dart';
import 'package:moor/moor.dart';
import '../../famedlysdk.dart' as sdk;
import 'package:matrix_api_lite/matrix_api_lite.dart' as api;
import '../client.dart';
import '../room.dart';
import 'database_api.dart';
part 'database.g.dart';
@ -64,7 +71,7 @@ extension MigratorExtension on Migrator {
@UseMoor(
include: {'database.moor'},
)
class Database extends _$Database {
class Database extends _$Database implements DatabaseApi {
Database(QueryExecutor e) : super(e);
Database.connect(DatabaseConnection connection) : super.connect(connection);
@ -72,6 +79,7 @@ class Database extends _$Database {
@override
int get schemaVersion => 12;
@override
int get maxFileSize => 1 * 1024 * 1024;
/// Update errors are coming here.
@ -202,6 +210,7 @@ class Database extends _$Database {
},
);
@override
Future<DbClient> getClient(String name) async {
final res = await dbGetClient(name).get();
if (res.isEmpty) return null;
@ -209,6 +218,7 @@ class Database extends _$Database {
return res.single;
}
@override
Future<Map<String, sdk.DeviceKeysList>> getUserDeviceKeys(
sdk.Client client) async {
final deviceKeys = await getAllUserDeviceKeys(client.id).get();
@ -228,45 +238,51 @@ class Database extends _$Database {
return res;
}
Future<DbOutboundGroupSession> getDbOutboundGroupSession(
int clientId, String roomId) async {
@override
Future<OutboundGroupSession> getOutboundGroupSession(
int clientId, String roomId, String userId) async {
final res = await dbGetOutboundGroupSession(clientId, roomId).get();
if (res.isEmpty) {
return null;
}
return res.single;
return OutboundGroupSession.fromDb(res.single, userId);
}
Future<List<DbInboundGroupSession>> getDbInboundGroupSessions(
int clientId, String roomId) async {
return await dbGetInboundGroupSessionKeys(clientId, roomId).get();
}
Future<DbInboundGroupSession> getDbInboundGroupSession(
int clientId, String roomId, String sessionId) async {
@override
Future<SessionKey> getInboundGroupSession(
int clientId,
String roomId,
String sessionId,
String userId,
) async {
final res =
await dbGetInboundGroupSessionKey(clientId, roomId, sessionId).get();
if (res.isEmpty) {
return null;
}
return res.single;
return SessionKey.fromDb(
StoredInboundGroupSession.fromJson(res.single.toJson()), userId);
}
Future<DbSSSSCache> getSSSSCache(int clientId, String type) async {
@override
Future<SSSSCache> getSSSSCache(int clientId, String type) async {
final res = await dbGetSSSSCache(clientId, type).get();
if (res.isEmpty) {
return null;
}
return res.single;
final dbCache = res.single;
return SSSSCache(
ciphertext: dbCache.ciphertext,
clientId: dbCache.clientId,
type: dbCache.type,
keyId: dbCache.keyId,
content: dbCache.content,
);
}
Future<List<sdk.Room>> getRoomList(sdk.Client client,
{bool onlyLeft = false}) async {
final res = await (select(rooms)
..where((t) => onlyLeft
? t.membership.equals('leave')
: t.membership.equals('leave').not()))
.get();
@override
Future<List<sdk.Room>> getRoomList(sdk.Client client) async {
final res = await select(rooms).get();
final resStates = await getImportantRoomStates(
client.id, client.importantStateEvents.toList())
.get();
@ -358,6 +374,7 @@ class Database extends _$Database {
return roomList;
}
@override
Future<Map<String, api.BasicEvent>> getAccountData(int clientId) async {
final newAccountData = <String, api.BasicEvent>{};
final rawAccountData = await getAllAccountData(clientId).get();
@ -381,6 +398,7 @@ class Database extends _$Database {
/// Stores a RoomUpdate object in the database. Must be called inside of
/// [transaction].
final Set<String> _ensuredRooms = {};
@override
Future<void> storeRoomUpdate(int clientId, sdk.RoomUpdate roomUpdate,
[sdk.Room oldRoom]) async {
final setKey = '$clientId;${roomUpdate.id}';
@ -446,6 +464,7 @@ class Database extends _$Database {
/// Stores an EventUpdate object in the database. Must be called inside of
/// [transaction].
@override
Future<void> storeEventUpdate(
int clientId, sdk.EventUpdate eventUpdate) async {
if (eventUpdate.type == sdk.EventUpdateType.ephemeral) return;
@ -579,6 +598,7 @@ class Database extends _$Database {
}
}
@override
Future<sdk.Event> getEventById(
int clientId, String eventId, sdk.Room room) async {
final event = await getEvent(clientId, eventId, room.id).get();
@ -617,6 +637,7 @@ class Database extends _$Database {
return success;
}
@override
Future<void> forgetRoom(int clientId, String roomId) async {
final setKey = '$clientId;$roomId';
_ensuredRooms.remove(setKey);
@ -634,6 +655,7 @@ class Database extends _$Database {
.go();
}
@override
Future<void> clearCache(int clientId) async {
await (delete(presences)..where((r) => r.clientId.equals(clientId))).go();
await (delete(roomAccountData)..where((r) => r.clientId.equals(clientId)))
@ -649,6 +671,7 @@ class Database extends _$Database {
await storePrevBatch(null, clientId);
}
@override
Future<void> clear(int clientId) async {
await clearCache(clientId);
await (delete(inboundGroupSessions)
@ -669,6 +692,7 @@ class Database extends _$Database {
.go();
}
@override
Future<sdk.User> getUser(int clientId, String userId, sdk.Room room) async {
final res = await dbGetUser(clientId, userId, room.id).get();
if (res.isEmpty) {
@ -677,19 +701,88 @@ class Database extends _$Database {
return sdk.Event.fromDb(res.single, room).asUser;
}
@override
Future<List<sdk.User>> getUsers(int clientId, sdk.Room room) async {
final res = await dbGetUsers(clientId, room.id).get();
return res.map((r) => sdk.Event.fromDb(r, room).asUser).toList();
}
@override
Future<List<sdk.Event>> getEventList(int clientId, sdk.Room room) async {
final res = await dbGetEventList(clientId, room.id).get();
return res.map((r) => sdk.Event.fromDb(r, room)).toList();
}
@override
Future<Uint8List> getFile(String mxcUri) async {
final res = await dbGetFile(mxcUri).get();
if (res.isEmpty) return null;
return res.single.bytes;
}
@override
Future<List<sdk.Event>> getUnimportantRoomEventStatesForRoom(
int client_id,
List<String> events,
Room room,
) async {
final entries = await getUnimportantRoomStatesForRoom(
client_id,
room.id,
events,
).get();
return entries.map((dbEvent) => sdk.Event.fromDb(dbEvent, room)).toList();
}
@override
Future<List<OlmSession>> getOlmSessions(
int client_id,
String identity_key,
String userId,
) async {
final rows = await dbGetOlmSessions(client_id, identity_key).get();
return rows.map((row) => OlmSession.fromDb(row, userId)).toList();
}
@override
Future<List<OlmSession>> getOlmSessionsForDevices(
int client_id,
List<String> identity_keys,
String userId,
) async {
final rows =
await dbGetOlmSessionsForDevices(client_id, identity_keys).get();
return rows.map((row) => OlmSession.fromDb(row, userId)).toList();
}
@override
Future<List<QueuedToDeviceEvent>> getToDeviceEventQueue(int client_id) async {
final rows = await getToDeviceQueue(client_id).get();
return rows
.map((row) => QueuedToDeviceEvent(
id: row.id,
type: row.type,
txnId: row.txnId,
content:
(json.decode(row.content) as Map<String, dynamic>).copy(),
))
.toList();
}
@override
Future<List<String>> getLastSentMessageUserDeviceKey(
int client_id,
String user_id,
String device_id,
) =>
dbGetLastSentMessageUserDeviceKey(client_id, user_id, device_id).get();
@override
Future<List<StoredInboundGroupSession>>
getInboundGroupSessionsToUpload() async {
final rows = await dbGetInboundGroupSessionsToUpload().get();
return rows
.map((row) => StoredInboundGroupSession.fromJson(row.toJson()))
.toList();
}
}

View File

@ -6881,7 +6881,7 @@ abstract class _$Database extends GeneratedDatabase {
);
}
Selectable<DbInboundGroupSession> getInboundGroupSessionsToUpload() {
Selectable<DbInboundGroupSession> dbGetInboundGroupSessionsToUpload() {
return customSelect(
'SELECT * FROM inbound_group_sessions WHERE uploaded = false LIMIT 500',
variables: [],
@ -7021,7 +7021,7 @@ abstract class _$Database extends GeneratedDatabase {
);
}
Selectable<String> getLastSentMessageUserDeviceKey(
Selectable<String> dbGetLastSentMessageUserDeviceKey(
int client_id, String user_id, String device_id) {
return customSelect(
'SELECT last_sent_message FROM user_device_keys_key WHERE client_id = :client_id AND user_id = :user_id AND device_id = :device_id',

View File

@ -208,7 +208,7 @@ getAllInboundGroupSessions: SELECT * FROM inbound_group_sessions WHERE client_id
storeInboundGroupSession: INSERT OR REPLACE INTO inbound_group_sessions (client_id, room_id, session_id, pickle, content, indexes, allowed_at_index, sender_key, sender_claimed_keys) VALUES (:client_id, :room_id, :session_id, :pickle, :content, :indexes, :allowed_at_index, :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;
updateInboundGroupSessionAllowedAtIndex: UPDATE inbound_group_sessions SET allowed_at_index = :allowed_at_index WHERE client_id = :client_id AND room_id = :room_id AND session_id = :session_id;
getInboundGroupSessionsToUpload: SELECT * FROM inbound_group_sessions WHERE uploaded = false LIMIT 500;
dbGetInboundGroupSessionsToUpload: SELECT * FROM inbound_group_sessions WHERE uploaded = false LIMIT 500;
markInboundGroupSessionAsUploaded: UPDATE inbound_group_sessions SET uploaded = true WHERE client_id = :client_id AND room_id = :room_id AND session_id = :session_id;
markInboundGroupSessionsAsNeedingUpload: UPDATE inbound_group_sessions SET uploaded = false WHERE client_id = :client_id;
storeUserDeviceKeysInfo: INSERT OR REPLACE INTO user_device_keys (client_id, user_id, outdated) VALUES (:client_id, :user_id, :outdated);
@ -218,7 +218,7 @@ storeUserDeviceKey: INSERT OR REPLACE INTO user_device_keys_key (client_id, user
removeUserDeviceKey: DELETE FROM user_device_keys_key WHERE client_id = :client_id AND user_id = :user_id AND device_id = :device_id;
setLastActiveUserDeviceKey: UPDATE user_device_keys_key SET last_active = :last_active WHERE client_id = :client_id AND user_id = :user_id AND device_id = :device_id;
setLastSentMessageUserDeviceKey: UPDATE user_device_keys_key SET last_sent_message = :last_sent_message WHERE client_id = :client_id AND user_id = :user_id AND device_id = :device_id;
getLastSentMessageUserDeviceKey: SELECT last_sent_message FROM user_device_keys_key WHERE client_id = :client_id AND user_id = :user_id AND device_id = :device_id;
dbGetLastSentMessageUserDeviceKey: SELECT last_sent_message FROM user_device_keys_key WHERE client_id = :client_id AND user_id = :user_id AND device_id = :device_id;
setVerifiedUserCrossSigningKey: UPDATE user_cross_signing_keys SET verified = :verified WHERE client_id = :client_id AND user_id = :user_id AND public_key = :public_key;
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);

View File

@ -0,0 +1,315 @@
/*
* Famedly Matrix SDK
* Copyright (C) 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 <https://www.gnu.org/licenses/>.
*/
import 'dart:typed_data';
import 'package:famedlysdk/encryption/utils/olm_session.dart';
import 'package:famedlysdk/encryption/utils/outbound_group_session.dart';
import 'package:famedlysdk/encryption/utils/session_key.dart';
import 'package:famedlysdk/encryption/utils/ssss_cache.dart';
import 'package:famedlysdk/encryption/utils/stored_inbound_group_session.dart';
import 'package:famedlysdk/src/utils/QueuedToDeviceEvent.dart';
import '../../famedlysdk.dart';
abstract class DatabaseApi {
int get maxFileSize => 1 * 1024 * 1024;
Future<dynamic> getClient(String name);
Future<Map<String, DeviceKeysList>> getUserDeviceKeys(Client client);
Future<OutboundGroupSession> getOutboundGroupSession(
int clientId,
String roomId,
String userId,
);
Future<SessionKey> getInboundGroupSession(
int clientId,
String roomId,
String sessionId,
String userId,
);
Future<SSSSCache> getSSSSCache(int clientId, String type);
Future<List<Room>> getRoomList(Client client);
Future<Map<String, BasicEvent>> getAccountData(int clientId);
/// Stores a RoomUpdate object in the database. Must be called inside of
/// [transaction].
Future<void> storeRoomUpdate(int clientId, RoomUpdate roomUpdate,
[Room oldRoom]);
/// Stores an EventUpdate object in the database. Must be called inside of
/// [transaction].
Future<void> storeEventUpdate(int clientId, EventUpdate eventUpdate);
Future<Event> getEventById(int clientId, String eventId, Room room);
Future<void> forgetRoom(int clientId, String roomId);
Future<void> clearCache(int clientId);
Future<void> clear(int clientId);
Future<User> getUser(int clientId, String userId, Room room);
Future<List<User>> getUsers(int clientId, Room room);
Future<List<Event>> getEventList(int clientId, Room room);
Future<Uint8List> getFile(String mxcUri);
Future<int> updateInboundGroupSessionIndexes(
String indexes,
int clientId,
String roomId,
String sessionId,
);
Future<int> storeInboundGroupSession(
int clientId,
String roomId,
String sessionId,
String pickle,
String content,
String indexes,
String allowedAtIndex,
String senderKey,
String senderClaimedKey,
);
Future<int> markInboundGroupSessionAsUploaded(
int clientId,
String roomId,
String sessionId,
);
Future<int> updateInboundGroupSessionAllowedAtIndex(
String allowedAtIndex,
int clientId,
String roomId,
String sessionId,
);
Future<int> removeOutboundGroupSession(int clientId, String roomId);
Future<int> storeFile(String mxcUri, Uint8List bytes, int time);
Future<int> updateClient(
String homeserverUrl,
String token,
String userId,
String deviceId,
String deviceName,
String prevBatch,
String olmAccount,
int clientId,
);
Future<int> insertClient(
String name,
String homeserverUrl,
String token,
String userId,
String deviceId,
String deviceName,
String prevBatch,
String olmAccount,
);
Future<int> storeSyncFilterId(String syncFilterId, int clientId);
Future<int> storeAccountData(int clientId, String type, String content);
Future<int> storeOutboundGroupSession(
int clientId,
String roomId,
String pickle,
String deviceIds,
int creationTime,
int sentMessages,
);
Future<int> updateClientKeys(String olmAccount, int clientId);
Future<int> storeOlmSession(
int clientId,
String identitiyKey,
String sessionId,
String pickle,
int lastReceived,
);
Future<int> setLastActiveUserDeviceKey(
int lastActive,
int clientId,
String userId,
String deviceId,
);
Future<int> setLastSentMessageUserDeviceKey(
String lastSentMessage,
int clientId,
String userId,
String deviceId,
);
Future<int> clearSSSSCache(int clientId);
Future<int> storeSSSSCache(
int clientId,
String type,
String keyId,
String ciphertext,
String content,
);
Future<int> markInboundGroupSessionsAsNeedingUpload(int clientId);
Future<int> storePrevBatch(String prevBatch, int clientId);
Future<int> deleteOldFiles(int savedAt);
Future<int> storeUserDeviceKeysInfo(
int clientId,
String userId,
bool outdated,
);
Future<int> storeUserDeviceKey(
int clientId,
String userId,
String deviceId,
String content,
bool verified,
bool blocked,
int lastActive,
);
Future<int> removeUserDeviceKey(
int clientId,
String userId,
String deviceId,
);
Future<int> removeUserCrossSigningKey(
int clientId,
String userId,
String publicKey,
);
Future<int> storeUserCrossSigningKey(
int clientId,
String userId,
String publicKey,
String content,
bool verified,
bool blocked,
);
Future<int> deleteFromToDeviceQueue(int clientId, int id);
Future<int> removeEvent(int clientId, String eventId, String roomId);
Future<int> updateRoomSortOrder(
double oldestSortOrder,
double newestSortOrder,
int clientId,
String roomId,
);
Future<int> setRoomPrevBatch(
String prevBatch,
int clientId,
String roomId,
);
Future<int> resetNotificationCount(int clientId, String roomId);
Future<int> setVerifiedUserCrossSigningKey(
bool verified,
int clientId,
String userId,
String publicKey,
);
Future<int> setBlockedUserCrossSigningKey(
bool blocked,
int clientId,
String userId,
String publicKey,
);
Future<int> setVerifiedUserDeviceKey(
bool verified,
int clientId,
String userId,
String deviceId,
);
Future<int> setBlockedUserDeviceKey(
bool blocked,
int clientId,
String userId,
String deviceId,
);
Future<List<Event>> getUnimportantRoomEventStatesForRoom(
int clientId,
List<String> events,
Room room,
);
Future<List<OlmSession>> getOlmSessions(
int clientId,
String identityKey,
String userId,
);
Future<List<OlmSession>> getOlmSessionsForDevices(
int clientId,
List<String> identityKeys,
String userId,
);
Future<List<QueuedToDeviceEvent>> getToDeviceEventQueue(int clientId);
/// Please do `jsonEncode(content)` in your code to stay compatible with
/// auto generated methods here.
Future<int> insertIntoToDeviceQueue(
int clientId,
String type,
String txnId,
String content,
);
Future<List<String>> getLastSentMessageUserDeviceKey(
int clientId,
String userId,
String deviceId,
);
Future<List<StoredInboundGroupSession>> getInboundGroupSessionsToUpload();
Future<dynamic> close();
Future<T> transaction<T>(Future<T> Function() action);
}

View File

@ -130,12 +130,11 @@ class Room {
return;
}
final allStates = await client.database
.getUnimportantRoomStatesForRoom(
client.id, id, client.importantStateEvents.toList())
.get();
.getUnimportantRoomEventStatesForRoom(
client.id, client.importantStateEvents.toList(), this);
for (final state in allStates) {
final newState = Event.fromDb(state, this);
setState(newState);
setState(state);
}
partial = false;
}

View File

@ -0,0 +1,23 @@
class QueuedToDeviceEvent {
final int id;
final String type;
final String txnId;
final Map<String, dynamic> content;
QueuedToDeviceEvent({this.id, this.type, this.txnId, this.content});
factory QueuedToDeviceEvent.fromJson(Map<String, dynamic> json) =>
QueuedToDeviceEvent(
id: json['id'],
type: json['type'],
txnId: json['txn_id'],
content: json['content'],
);
Map<String, dynamic> toJson() => {
'id': id,
'type': type,
'txn_id': txnId,
'content': content,
};
}

View File

@ -96,14 +96,12 @@ void main() {
client.encryption.keyManager.setInboundGroupSession(
roomId, sessionId, senderKey, sessionPayload,
forwarded: true);
var dbSessions =
await client.database.getInboundGroupSessionsToUpload().get();
var dbSessions = await client.database.getInboundGroupSessionsToUpload();
expect(dbSessions.isNotEmpty, true);
await client.encryption.keyManager.backgroundTasks();
final payload = FakeMatrixApi
.calledEndpoints['/client/unstable/room_keys/keys?version=5'].first;
dbSessions =
await client.database.getInboundGroupSessionsToUpload().get();
dbSessions = await client.database.getInboundGroupSessionsToUpload();
expect(dbSessions.isEmpty, true);
final onlineKeys = RoomKeys.fromJson(json.decode(payload));