Merge branch 'soru/autoreply-more-key-requests' into 'main'
feat: Auto-Share megolm sessions with other users we know for a fact are... Closes #127 See merge request famedly/famedlysdk!570
This commit is contained in:
commit
dfd88277b9
|
|
@ -29,6 +29,7 @@ import '../src/database/database.dart';
|
||||||
import '../matrix_api/utils/logs.dart';
|
import '../matrix_api/utils/logs.dart';
|
||||||
import '../src/utils/run_in_background.dart';
|
import '../src/utils/run_in_background.dart';
|
||||||
import '../src/utils/run_in_root.dart';
|
import '../src/utils/run_in_root.dart';
|
||||||
|
import '../matrix_api/utils/try_get_map_extension.dart';
|
||||||
|
|
||||||
const MEGOLM_KEY = EventTypes.MegolmBackup;
|
const MEGOLM_KEY = EventTypes.MegolmBackup;
|
||||||
|
|
||||||
|
|
@ -88,7 +89,8 @@ class KeyManager {
|
||||||
Map<String, dynamic> content,
|
Map<String, dynamic> content,
|
||||||
{bool forwarded = false,
|
{bool forwarded = false,
|
||||||
Map<String, String> senderClaimedKeys,
|
Map<String, String> senderClaimedKeys,
|
||||||
bool uploaded = false}) {
|
bool uploaded = false,
|
||||||
|
Map<String, Map<String, int>> allowedAtIndex}) {
|
||||||
senderClaimedKeys ??= <String, String>{};
|
senderClaimedKeys ??= <String, String>{};
|
||||||
if (!senderClaimedKeys.containsKey('ed25519')) {
|
if (!senderClaimedKeys.containsKey('ed25519')) {
|
||||||
final device = client.getUserDeviceKeysByCurve25519Key(senderKey);
|
final device = client.getUserDeviceKeysByCurve25519Key(senderKey);
|
||||||
|
|
@ -123,6 +125,7 @@ class KeyManager {
|
||||||
key: client.userID,
|
key: client.userID,
|
||||||
senderKey: senderKey,
|
senderKey: senderKey,
|
||||||
senderClaimedKeys: senderClaimedKeys,
|
senderClaimedKeys: senderClaimedKeys,
|
||||||
|
allowedAtIndex: allowedAtIndex,
|
||||||
);
|
);
|
||||||
final oldFirstIndex =
|
final oldFirstIndex =
|
||||||
oldSession?.inboundGroupSession?.first_known_index() ?? 0;
|
oldSession?.inboundGroupSession?.first_known_index() ?? 0;
|
||||||
|
|
@ -151,6 +154,7 @@ class KeyManager {
|
||||||
inboundGroupSession.pickle(client.userID),
|
inboundGroupSession.pickle(client.userID),
|
||||||
json.encode(content),
|
json.encode(content),
|
||||||
json.encode({}),
|
json.encode({}),
|
||||||
|
json.encode(allowedAtIndex ?? {}),
|
||||||
senderKey,
|
senderKey,
|
||||||
json.encode(senderClaimedKeys),
|
json.encode(senderClaimedKeys),
|
||||||
)
|
)
|
||||||
|
|
@ -290,6 +294,8 @@ class KeyManager {
|
||||||
wipe = true;
|
wipe = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
final inboundSess = await loadInboundGroupSession(room.id,
|
||||||
|
sess.outboundGroupSession.session_id(), encryption.identityKey);
|
||||||
if (!wipe) {
|
if (!wipe) {
|
||||||
// next check if the devices in the room changed
|
// next check if the devices in the room changed
|
||||||
final devicesToReceive = <DeviceKeys>[];
|
final devicesToReceive = <DeviceKeys>[];
|
||||||
|
|
@ -350,6 +356,25 @@ class KeyManager {
|
||||||
try {
|
try {
|
||||||
devicesToReceive.removeWhere((k) => k.blocked);
|
devicesToReceive.removeWhere((k) => k.blocked);
|
||||||
if (devicesToReceive.isNotEmpty) {
|
if (devicesToReceive.isNotEmpty) {
|
||||||
|
// update allowedAtIndex
|
||||||
|
for (final device in devicesToReceive) {
|
||||||
|
inboundSess.allowedAtIndex[device.userId] ??= <String, int>{};
|
||||||
|
if (!inboundSess.allowedAtIndex[device.userId]
|
||||||
|
.containsKey(device.deviceId) ||
|
||||||
|
inboundSess.allowedAtIndex[device.userId][device.deviceId] >
|
||||||
|
sess.outboundGroupSession.message_index()) {
|
||||||
|
inboundSess.allowedAtIndex[device.userId][device.deviceId] =
|
||||||
|
sess.outboundGroupSession.message_index();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (client.database != null) {
|
||||||
|
await client.database.updateInboundGroupSessionAllowedAtIndex(
|
||||||
|
json.encode(inboundSess.allowedAtIndex),
|
||||||
|
client.id,
|
||||||
|
room.id,
|
||||||
|
sess.outboundGroupSession.session_id());
|
||||||
|
}
|
||||||
|
// send out the key
|
||||||
await client.sendToDeviceEncrypted(
|
await client.sendToDeviceEncrypted(
|
||||||
devicesToReceive, 'm.room_key', rawSession);
|
devicesToReceive, 'm.room_key', rawSession);
|
||||||
}
|
}
|
||||||
|
|
@ -404,6 +429,7 @@ class KeyManager {
|
||||||
}
|
}
|
||||||
final deviceKeys = await room.getUserDeviceKeys();
|
final deviceKeys = await room.getUserDeviceKeys();
|
||||||
final deviceKeyIds = _getDeviceKeyIdMap(deviceKeys);
|
final deviceKeyIds = _getDeviceKeyIdMap(deviceKeys);
|
||||||
|
deviceKeys.removeWhere((k) => k.blocked);
|
||||||
final outboundGroupSession = olm.OutboundGroupSession();
|
final outboundGroupSession = olm.OutboundGroupSession();
|
||||||
try {
|
try {
|
||||||
outboundGroupSession.create();
|
outboundGroupSession.create();
|
||||||
|
|
@ -418,8 +444,15 @@ class KeyManager {
|
||||||
'session_id': outboundGroupSession.session_id(),
|
'session_id': outboundGroupSession.session_id(),
|
||||||
'session_key': outboundGroupSession.session_key(),
|
'session_key': outboundGroupSession.session_key(),
|
||||||
};
|
};
|
||||||
|
final allowedAtIndex = <String, Map<String, int>>{};
|
||||||
|
for (final device in deviceKeys) {
|
||||||
|
allowedAtIndex[device.userId] ??= <String, int>{};
|
||||||
|
allowedAtIndex[device.userId][device.deviceId] =
|
||||||
|
outboundGroupSession.message_index();
|
||||||
|
}
|
||||||
setInboundGroupSession(
|
setInboundGroupSession(
|
||||||
roomId, rawSession['session_id'], encryption.identityKey, rawSession);
|
roomId, rawSession['session_id'], encryption.identityKey, rawSession,
|
||||||
|
allowedAtIndex: allowedAtIndex);
|
||||||
final sess = OutboundGroupSession(
|
final sess = OutboundGroupSession(
|
||||||
devices: deviceKeyIds,
|
devices: deviceKeyIds,
|
||||||
creationTime: DateTime.now(),
|
creationTime: DateTime.now(),
|
||||||
|
|
@ -428,7 +461,6 @@ class KeyManager {
|
||||||
key: client.userID,
|
key: client.userID,
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
deviceKeys.removeWhere((k) => k.blocked);
|
|
||||||
await client.sendToDeviceEncrypted(deviceKeys, 'm.room_key', rawSession);
|
await client.sendToDeviceEncrypted(deviceKeys, 'm.room_key', rawSession);
|
||||||
await storeOutboundGroupSession(roomId, sess);
|
await storeOutboundGroupSession(roomId, sess);
|
||||||
_outboundGroupSessions[roomId] = sess;
|
_outboundGroupSessions[roomId] = sess;
|
||||||
|
|
@ -736,8 +768,9 @@ class KeyManager {
|
||||||
final sessionId = event.content['body']['session_id'];
|
final sessionId = event.content['body']['session_id'];
|
||||||
final senderKey = event.content['body']['sender_key'];
|
final senderKey = event.content['body']['sender_key'];
|
||||||
// okay, let's see if we have this session at all
|
// okay, let's see if we have this session at all
|
||||||
if ((await loadInboundGroupSession(room.id, sessionId, senderKey)) ==
|
final session =
|
||||||
null) {
|
await loadInboundGroupSession(room.id, sessionId, senderKey);
|
||||||
|
if (session == null) {
|
||||||
Logs().i('[KeyManager] Unknown session, ignoring');
|
Logs().i('[KeyManager] Unknown session, ignoring');
|
||||||
return; // we don't have this session anyways
|
return; // we don't have this session anyways
|
||||||
}
|
}
|
||||||
|
|
@ -761,6 +794,18 @@ class KeyManager {
|
||||||
Logs().i('[KeyManager] All checks out, forwarding key...');
|
Logs().i('[KeyManager] All checks out, forwarding key...');
|
||||||
// alright, we can forward the key
|
// alright, we can forward the key
|
||||||
await roomKeyRequest.forwardKey();
|
await roomKeyRequest.forwardKey();
|
||||||
|
} else if (!device.blocked &&
|
||||||
|
session.allowedAtIndex
|
||||||
|
.tryGet<Map<String, dynamic>>(device.userId)
|
||||||
|
?.tryGet(device.deviceId) !=
|
||||||
|
null) {
|
||||||
|
// if we know the user may see the message, then we can just forward the key.
|
||||||
|
// we do not need to check if the device is verified, just if it is not blocked,
|
||||||
|
// as that is the logic we already initially try to send out the room keys.
|
||||||
|
final index = session.allowedAtIndex[device.userId][device.deviceId];
|
||||||
|
Logs().i(
|
||||||
|
'[KeyManager] Valid foreign request, forwarding key at index $index...');
|
||||||
|
await roomKeyRequest.forwardKey(index);
|
||||||
} else {
|
} else {
|
||||||
Logs()
|
Logs()
|
||||||
.i('[KeyManager] Asking client, if the key should be forwarded');
|
.i('[KeyManager] Asking client, if the key should be forwarded');
|
||||||
|
|
@ -903,7 +948,7 @@ class RoomKeyRequest extends ToDeviceEvent {
|
||||||
|
|
||||||
DeviceKeys get requestingDevice => request.devices.first;
|
DeviceKeys get requestingDevice => request.devices.first;
|
||||||
|
|
||||||
Future<void> forwardKey() async {
|
Future<void> forwardKey([int index]) async {
|
||||||
if (request.canceled) {
|
if (request.canceled) {
|
||||||
keyManager.incomingShareRequests.remove(request.requestId);
|
keyManager.incomingShareRequests.remove(request.requestId);
|
||||||
return; // request is canceled, don't send anything
|
return; // request is canceled, don't send anything
|
||||||
|
|
@ -924,8 +969,8 @@ class RoomKeyRequest extends ToDeviceEvent {
|
||||||
(session.forwardingCurve25519KeyChain.isEmpty
|
(session.forwardingCurve25519KeyChain.isEmpty
|
||||||
? keyManager.encryption.fingerprintKey
|
? keyManager.encryption.fingerprintKey
|
||||||
: null);
|
: null);
|
||||||
message['session_key'] = session.inboundGroupSession
|
message['session_key'] = session.inboundGroupSession.export_session(
|
||||||
.export_session(session.inboundGroupSession.first_known_index());
|
index ?? 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
|
||||||
await keyManager.client.sendToDeviceEncrypted(
|
await keyManager.client.sendToDeviceEncrypted(
|
||||||
[requestingDevice],
|
[requestingDevice],
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,6 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
import 'package:olm/olm.dart' as olm;
|
import 'package:olm/olm.dart' as olm;
|
||||||
|
|
||||||
import '../../famedlysdk.dart';
|
import '../../famedlysdk.dart';
|
||||||
|
|
@ -25,19 +23,42 @@ import '../../src/database/database.dart' show DbInboundGroupSession;
|
||||||
import '../../matrix_api/utils/logs.dart';
|
import '../../matrix_api/utils/logs.dart';
|
||||||
|
|
||||||
class SessionKey {
|
class SessionKey {
|
||||||
|
/// The raw json content of the key
|
||||||
Map<String, dynamic> content;
|
Map<String, dynamic> content;
|
||||||
|
|
||||||
|
/// Map of stringified-index to event id, so that we can detect replay attacks
|
||||||
Map<String, String> indexes;
|
Map<String, String> 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<String, Map<String, int>> allowedAtIndex;
|
||||||
|
|
||||||
|
/// Underlying olm [InboundGroupSession] object
|
||||||
olm.InboundGroupSession inboundGroupSession;
|
olm.InboundGroupSession inboundGroupSession;
|
||||||
|
|
||||||
|
/// Key for libolm pickle / unpickle
|
||||||
final String key;
|
final String key;
|
||||||
|
|
||||||
|
/// Forwarding keychain
|
||||||
List<String> get forwardingCurve25519KeyChain =>
|
List<String> get forwardingCurve25519KeyChain =>
|
||||||
(content['forwarding_curve25519_key_chain'] != null
|
(content['forwarding_curve25519_key_chain'] != null
|
||||||
? List<String>.from(content['forwarding_curve25519_key_chain'])
|
? List<String>.from(content['forwarding_curve25519_key_chain'])
|
||||||
: null) ??
|
: null) ??
|
||||||
<String>[];
|
<String>[];
|
||||||
|
|
||||||
|
/// Claimed keys of the original sender
|
||||||
Map<String, String> senderClaimedKeys;
|
Map<String, String> senderClaimedKeys;
|
||||||
|
|
||||||
|
/// Sender curve25519 key
|
||||||
String senderKey;
|
String senderKey;
|
||||||
|
|
||||||
|
/// Is this session valid?
|
||||||
bool get isValid => inboundGroupSession != null;
|
bool get isValid => inboundGroupSession != null;
|
||||||
|
|
||||||
|
/// roomId for this session
|
||||||
String roomId;
|
String roomId;
|
||||||
|
|
||||||
|
/// Id of this session
|
||||||
String sessionId;
|
String sessionId;
|
||||||
|
|
||||||
SessionKey(
|
SessionKey(
|
||||||
|
|
@ -45,17 +66,22 @@ class SessionKey {
|
||||||
this.inboundGroupSession,
|
this.inboundGroupSession,
|
||||||
this.key,
|
this.key,
|
||||||
this.indexes,
|
this.indexes,
|
||||||
|
this.allowedAtIndex,
|
||||||
this.roomId,
|
this.roomId,
|
||||||
this.sessionId,
|
this.sessionId,
|
||||||
String senderKey,
|
String senderKey,
|
||||||
Map<String, String> senderClaimedKeys}) {
|
Map<String, String> senderClaimedKeys}) {
|
||||||
_setSenderKey(senderKey);
|
_setSenderKey(senderKey);
|
||||||
_setSenderClaimedKeys(senderClaimedKeys);
|
_setSenderClaimedKeys(senderClaimedKeys);
|
||||||
|
indexes ??= <String, String>{};
|
||||||
|
allowedAtIndex ??= <String, Map<String, int>>{};
|
||||||
}
|
}
|
||||||
|
|
||||||
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 parsedAllowedAtIndex =
|
||||||
|
Event.getMapFromPayload(dbEntry.allowedAtIndex);
|
||||||
final parsedSenderClaimedKeys =
|
final parsedSenderClaimedKeys =
|
||||||
Event.getMapFromPayload(dbEntry.senderClaimedKeys);
|
Event.getMapFromPayload(dbEntry.senderClaimedKeys);
|
||||||
content =
|
content =
|
||||||
|
|
@ -68,6 +94,14 @@ class SessionKey {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
indexes = <String, String>{};
|
indexes = <String, String>{};
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
allowedAtIndex = parsedAllowedAtIndex != null
|
||||||
|
? Map<String, Map<String, int>>.from(parsedAllowedAtIndex
|
||||||
|
.map((k, v) => MapEntry(k, Map<String, int>.from(v))))
|
||||||
|
: <String, Map<String, int>>{};
|
||||||
|
} catch (e) {
|
||||||
|
allowedAtIndex = <String, Map<String, int>>{};
|
||||||
|
}
|
||||||
roomId = dbEntry.roomId;
|
roomId = dbEntry.roomId;
|
||||||
sessionId = dbEntry.sessionId;
|
sessionId = dbEntry.sessionId;
|
||||||
_setSenderKey(dbEntry.senderKey);
|
_setSenderKey(dbEntry.senderKey);
|
||||||
|
|
@ -98,23 +132,8 @@ class SessionKey {
|
||||||
: <String, String>{}));
|
: <String, String>{}));
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
|
||||||
final data = <String, dynamic>{};
|
|
||||||
if (content != null) {
|
|
||||||
data['content'] = content;
|
|
||||||
}
|
|
||||||
if (indexes != null) {
|
|
||||||
data['indexes'] = indexes;
|
|
||||||
}
|
|
||||||
data['inboundGroupSession'] = inboundGroupSession.pickle(key);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dispose() {
|
void dispose() {
|
||||||
inboundGroupSession?.free();
|
inboundGroupSession?.free();
|
||||||
inboundGroupSession = null;
|
inboundGroupSession = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() => json.encode(toJson());
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ class Database extends _$Database {
|
||||||
Database.connect(DatabaseConnection connection) : super.connect(connection);
|
Database.connect(DatabaseConnection connection) : super.connect(connection);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get schemaVersion => 7;
|
int get schemaVersion => 8;
|
||||||
|
|
||||||
int get maxFileSize => 1 * 1024 * 1024;
|
int get maxFileSize => 1 * 1024 * 1024;
|
||||||
|
|
||||||
|
|
@ -136,6 +136,12 @@ class Database extends _$Database {
|
||||||
await delete(rooms).go();
|
await delete(rooms).go();
|
||||||
await delete(outboundGroupSessions).go();
|
await delete(outboundGroupSessions).go();
|
||||||
await customStatement('UPDATE clients SET prev_batch = null');
|
await customStatement('UPDATE clients SET prev_batch = null');
|
||||||
|
from++;
|
||||||
|
}
|
||||||
|
if (from == 7) {
|
||||||
|
await m.addColumnIfNotExists(
|
||||||
|
inboundGroupSessions, inboundGroupSessions.allowedAtIndex);
|
||||||
|
from++;
|
||||||
}
|
}
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logs().e('Database migration failed', e, s);
|
Logs().e('Database migration failed', e, s);
|
||||||
|
|
|
||||||
|
|
@ -2262,6 +2262,7 @@ class DbInboundGroupSession extends DataClass
|
||||||
final String pickle;
|
final String pickle;
|
||||||
final String content;
|
final String content;
|
||||||
final String indexes;
|
final String indexes;
|
||||||
|
final String allowedAtIndex;
|
||||||
final bool uploaded;
|
final bool uploaded;
|
||||||
final String senderKey;
|
final String senderKey;
|
||||||
final String senderClaimedKeys;
|
final String senderClaimedKeys;
|
||||||
|
|
@ -2272,6 +2273,7 @@ class DbInboundGroupSession extends DataClass
|
||||||
@required this.pickle,
|
@required this.pickle,
|
||||||
this.content,
|
this.content,
|
||||||
this.indexes,
|
this.indexes,
|
||||||
|
this.allowedAtIndex,
|
||||||
this.uploaded,
|
this.uploaded,
|
||||||
this.senderKey,
|
this.senderKey,
|
||||||
this.senderClaimedKeys});
|
this.senderClaimedKeys});
|
||||||
|
|
@ -2295,6 +2297,8 @@ 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']),
|
||||||
|
allowedAtIndex: stringType
|
||||||
|
.mapFromDatabaseResponse(data['${effectivePrefix}allowed_at_index']),
|
||||||
uploaded:
|
uploaded:
|
||||||
boolType.mapFromDatabaseResponse(data['${effectivePrefix}uploaded']),
|
boolType.mapFromDatabaseResponse(data['${effectivePrefix}uploaded']),
|
||||||
senderKey: stringType
|
senderKey: stringType
|
||||||
|
|
@ -2324,6 +2328,9 @@ class DbInboundGroupSession extends DataClass
|
||||||
if (!nullToAbsent || indexes != null) {
|
if (!nullToAbsent || indexes != null) {
|
||||||
map['indexes'] = Variable<String>(indexes);
|
map['indexes'] = Variable<String>(indexes);
|
||||||
}
|
}
|
||||||
|
if (!nullToAbsent || allowedAtIndex != null) {
|
||||||
|
map['allowed_at_index'] = Variable<String>(allowedAtIndex);
|
||||||
|
}
|
||||||
if (!nullToAbsent || uploaded != null) {
|
if (!nullToAbsent || uploaded != null) {
|
||||||
map['uploaded'] = Variable<bool>(uploaded);
|
map['uploaded'] = Variable<bool>(uploaded);
|
||||||
}
|
}
|
||||||
|
|
@ -2354,6 +2361,9 @@ class DbInboundGroupSession extends DataClass
|
||||||
indexes: indexes == null && nullToAbsent
|
indexes: indexes == null && nullToAbsent
|
||||||
? const Value.absent()
|
? const Value.absent()
|
||||||
: Value(indexes),
|
: Value(indexes),
|
||||||
|
allowedAtIndex: allowedAtIndex == null && nullToAbsent
|
||||||
|
? const Value.absent()
|
||||||
|
: Value(allowedAtIndex),
|
||||||
uploaded: uploaded == null && nullToAbsent
|
uploaded: uploaded == null && nullToAbsent
|
||||||
? const Value.absent()
|
? const Value.absent()
|
||||||
: Value(uploaded),
|
: Value(uploaded),
|
||||||
|
|
@ -2376,6 +2386,7 @@ 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']),
|
||||||
|
allowedAtIndex: serializer.fromJson<String>(json['allowed_at_index']),
|
||||||
uploaded: serializer.fromJson<bool>(json['uploaded']),
|
uploaded: serializer.fromJson<bool>(json['uploaded']),
|
||||||
senderKey: serializer.fromJson<String>(json['sender_key']),
|
senderKey: serializer.fromJson<String>(json['sender_key']),
|
||||||
senderClaimedKeys:
|
senderClaimedKeys:
|
||||||
|
|
@ -2392,6 +2403,7 @@ 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),
|
||||||
|
'allowed_at_index': serializer.toJson<String>(allowedAtIndex),
|
||||||
'uploaded': serializer.toJson<bool>(uploaded),
|
'uploaded': serializer.toJson<bool>(uploaded),
|
||||||
'sender_key': serializer.toJson<String>(senderKey),
|
'sender_key': serializer.toJson<String>(senderKey),
|
||||||
'sender_claimed_keys': serializer.toJson<String>(senderClaimedKeys),
|
'sender_claimed_keys': serializer.toJson<String>(senderClaimedKeys),
|
||||||
|
|
@ -2405,6 +2417,7 @@ class DbInboundGroupSession extends DataClass
|
||||||
String pickle,
|
String pickle,
|
||||||
String content,
|
String content,
|
||||||
String indexes,
|
String indexes,
|
||||||
|
String allowedAtIndex,
|
||||||
bool uploaded,
|
bool uploaded,
|
||||||
String senderKey,
|
String senderKey,
|
||||||
String senderClaimedKeys}) =>
|
String senderClaimedKeys}) =>
|
||||||
|
|
@ -2415,6 +2428,7 @@ 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,
|
||||||
|
allowedAtIndex: allowedAtIndex ?? this.allowedAtIndex,
|
||||||
uploaded: uploaded ?? this.uploaded,
|
uploaded: uploaded ?? this.uploaded,
|
||||||
senderKey: senderKey ?? this.senderKey,
|
senderKey: senderKey ?? this.senderKey,
|
||||||
senderClaimedKeys: senderClaimedKeys ?? this.senderClaimedKeys,
|
senderClaimedKeys: senderClaimedKeys ?? this.senderClaimedKeys,
|
||||||
|
|
@ -2428,6 +2442,7 @@ class DbInboundGroupSession extends DataClass
|
||||||
..write('pickle: $pickle, ')
|
..write('pickle: $pickle, ')
|
||||||
..write('content: $content, ')
|
..write('content: $content, ')
|
||||||
..write('indexes: $indexes, ')
|
..write('indexes: $indexes, ')
|
||||||
|
..write('allowedAtIndex: $allowedAtIndex, ')
|
||||||
..write('uploaded: $uploaded, ')
|
..write('uploaded: $uploaded, ')
|
||||||
..write('senderKey: $senderKey, ')
|
..write('senderKey: $senderKey, ')
|
||||||
..write('senderClaimedKeys: $senderClaimedKeys')
|
..write('senderClaimedKeys: $senderClaimedKeys')
|
||||||
|
|
@ -2448,10 +2463,12 @@ class DbInboundGroupSession extends DataClass
|
||||||
content.hashCode,
|
content.hashCode,
|
||||||
$mrjc(
|
$mrjc(
|
||||||
indexes.hashCode,
|
indexes.hashCode,
|
||||||
|
$mrjc(
|
||||||
|
allowedAtIndex.hashCode,
|
||||||
$mrjc(
|
$mrjc(
|
||||||
uploaded.hashCode,
|
uploaded.hashCode,
|
||||||
$mrjc(senderKey.hashCode,
|
$mrjc(senderKey.hashCode,
|
||||||
senderClaimedKeys.hashCode)))))))));
|
senderClaimedKeys.hashCode))))))))));
|
||||||
@override
|
@override
|
||||||
bool operator ==(dynamic other) =>
|
bool operator ==(dynamic other) =>
|
||||||
identical(this, other) ||
|
identical(this, other) ||
|
||||||
|
|
@ -2462,6 +2479,7 @@ class DbInboundGroupSession extends DataClass
|
||||||
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.allowedAtIndex == this.allowedAtIndex &&
|
||||||
other.uploaded == this.uploaded &&
|
other.uploaded == this.uploaded &&
|
||||||
other.senderKey == this.senderKey &&
|
other.senderKey == this.senderKey &&
|
||||||
other.senderClaimedKeys == this.senderClaimedKeys);
|
other.senderClaimedKeys == this.senderClaimedKeys);
|
||||||
|
|
@ -2475,6 +2493,7 @@ 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<String> allowedAtIndex;
|
||||||
final Value<bool> uploaded;
|
final Value<bool> uploaded;
|
||||||
final Value<String> senderKey;
|
final Value<String> senderKey;
|
||||||
final Value<String> senderClaimedKeys;
|
final Value<String> senderClaimedKeys;
|
||||||
|
|
@ -2485,6 +2504,7 @@ 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.allowedAtIndex = const Value.absent(),
|
||||||
this.uploaded = const Value.absent(),
|
this.uploaded = const Value.absent(),
|
||||||
this.senderKey = const Value.absent(),
|
this.senderKey = const Value.absent(),
|
||||||
this.senderClaimedKeys = const Value.absent(),
|
this.senderClaimedKeys = const Value.absent(),
|
||||||
|
|
@ -2496,6 +2516,7 @@ 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.allowedAtIndex = const Value.absent(),
|
||||||
this.uploaded = const Value.absent(),
|
this.uploaded = const Value.absent(),
|
||||||
this.senderKey = const Value.absent(),
|
this.senderKey = const Value.absent(),
|
||||||
this.senderClaimedKeys = const Value.absent(),
|
this.senderClaimedKeys = const Value.absent(),
|
||||||
|
|
@ -2510,6 +2531,7 @@ class InboundGroupSessionsCompanion
|
||||||
Expression<String> pickle,
|
Expression<String> pickle,
|
||||||
Expression<String> content,
|
Expression<String> content,
|
||||||
Expression<String> indexes,
|
Expression<String> indexes,
|
||||||
|
Expression<String> allowedAtIndex,
|
||||||
Expression<bool> uploaded,
|
Expression<bool> uploaded,
|
||||||
Expression<String> senderKey,
|
Expression<String> senderKey,
|
||||||
Expression<String> senderClaimedKeys,
|
Expression<String> senderClaimedKeys,
|
||||||
|
|
@ -2521,6 +2543,7 @@ 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 (allowedAtIndex != null) 'allowed_at_index': allowedAtIndex,
|
||||||
if (uploaded != null) 'uploaded': uploaded,
|
if (uploaded != null) 'uploaded': uploaded,
|
||||||
if (senderKey != null) 'sender_key': senderKey,
|
if (senderKey != null) 'sender_key': senderKey,
|
||||||
if (senderClaimedKeys != null) 'sender_claimed_keys': senderClaimedKeys,
|
if (senderClaimedKeys != null) 'sender_claimed_keys': senderClaimedKeys,
|
||||||
|
|
@ -2534,6 +2557,7 @@ class InboundGroupSessionsCompanion
|
||||||
Value<String> pickle,
|
Value<String> pickle,
|
||||||
Value<String> content,
|
Value<String> content,
|
||||||
Value<String> indexes,
|
Value<String> indexes,
|
||||||
|
Value<String> allowedAtIndex,
|
||||||
Value<bool> uploaded,
|
Value<bool> uploaded,
|
||||||
Value<String> senderKey,
|
Value<String> senderKey,
|
||||||
Value<String> senderClaimedKeys}) {
|
Value<String> senderClaimedKeys}) {
|
||||||
|
|
@ -2544,6 +2568,7 @@ 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,
|
||||||
|
allowedAtIndex: allowedAtIndex ?? this.allowedAtIndex,
|
||||||
uploaded: uploaded ?? this.uploaded,
|
uploaded: uploaded ?? this.uploaded,
|
||||||
senderKey: senderKey ?? this.senderKey,
|
senderKey: senderKey ?? this.senderKey,
|
||||||
senderClaimedKeys: senderClaimedKeys ?? this.senderClaimedKeys,
|
senderClaimedKeys: senderClaimedKeys ?? this.senderClaimedKeys,
|
||||||
|
|
@ -2571,6 +2596,9 @@ class InboundGroupSessionsCompanion
|
||||||
if (indexes.present) {
|
if (indexes.present) {
|
||||||
map['indexes'] = Variable<String>(indexes.value);
|
map['indexes'] = Variable<String>(indexes.value);
|
||||||
}
|
}
|
||||||
|
if (allowedAtIndex.present) {
|
||||||
|
map['allowed_at_index'] = Variable<String>(allowedAtIndex.value);
|
||||||
|
}
|
||||||
if (uploaded.present) {
|
if (uploaded.present) {
|
||||||
map['uploaded'] = Variable<bool>(uploaded.value);
|
map['uploaded'] = Variable<bool>(uploaded.value);
|
||||||
}
|
}
|
||||||
|
|
@ -2592,6 +2620,7 @@ class InboundGroupSessionsCompanion
|
||||||
..write('pickle: $pickle, ')
|
..write('pickle: $pickle, ')
|
||||||
..write('content: $content, ')
|
..write('content: $content, ')
|
||||||
..write('indexes: $indexes, ')
|
..write('indexes: $indexes, ')
|
||||||
|
..write('allowedAtIndex: $allowedAtIndex, ')
|
||||||
..write('uploaded: $uploaded, ')
|
..write('uploaded: $uploaded, ')
|
||||||
..write('senderKey: $senderKey, ')
|
..write('senderKey: $senderKey, ')
|
||||||
..write('senderClaimedKeys: $senderClaimedKeys')
|
..write('senderClaimedKeys: $senderClaimedKeys')
|
||||||
|
|
@ -2653,6 +2682,16 @@ class InboundGroupSessions extends Table
|
||||||
$customConstraints: '');
|
$customConstraints: '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final VerificationMeta _allowedAtIndexMeta =
|
||||||
|
const VerificationMeta('allowedAtIndex');
|
||||||
|
GeneratedTextColumn _allowedAtIndex;
|
||||||
|
GeneratedTextColumn get allowedAtIndex =>
|
||||||
|
_allowedAtIndex ??= _constructAllowedAtIndex();
|
||||||
|
GeneratedTextColumn _constructAllowedAtIndex() {
|
||||||
|
return GeneratedTextColumn('allowed_at_index', $tableName, true,
|
||||||
|
$customConstraints: '');
|
||||||
|
}
|
||||||
|
|
||||||
final VerificationMeta _uploadedMeta = const VerificationMeta('uploaded');
|
final VerificationMeta _uploadedMeta = const VerificationMeta('uploaded');
|
||||||
GeneratedBoolColumn _uploaded;
|
GeneratedBoolColumn _uploaded;
|
||||||
GeneratedBoolColumn get uploaded => _uploaded ??= _constructUploaded();
|
GeneratedBoolColumn get uploaded => _uploaded ??= _constructUploaded();
|
||||||
|
|
@ -2688,6 +2727,7 @@ class InboundGroupSessions extends Table
|
||||||
pickle,
|
pickle,
|
||||||
content,
|
content,
|
||||||
indexes,
|
indexes,
|
||||||
|
allowedAtIndex,
|
||||||
uploaded,
|
uploaded,
|
||||||
senderKey,
|
senderKey,
|
||||||
senderClaimedKeys
|
senderClaimedKeys
|
||||||
|
|
@ -2736,6 +2776,12 @@ class InboundGroupSessions extends Table
|
||||||
context.handle(_indexesMeta,
|
context.handle(_indexesMeta,
|
||||||
indexes.isAcceptableOrUnknown(data['indexes'], _indexesMeta));
|
indexes.isAcceptableOrUnknown(data['indexes'], _indexesMeta));
|
||||||
}
|
}
|
||||||
|
if (data.containsKey('allowed_at_index')) {
|
||||||
|
context.handle(
|
||||||
|
_allowedAtIndexMeta,
|
||||||
|
allowedAtIndex.isAcceptableOrUnknown(
|
||||||
|
data['allowed_at_index'], _allowedAtIndexMeta));
|
||||||
|
}
|
||||||
if (data.containsKey('uploaded')) {
|
if (data.containsKey('uploaded')) {
|
||||||
context.handle(_uploadedMeta,
|
context.handle(_uploadedMeta,
|
||||||
uploaded.isAcceptableOrUnknown(data['uploaded'], _uploadedMeta));
|
uploaded.isAcceptableOrUnknown(data['uploaded'], _uploadedMeta));
|
||||||
|
|
@ -6293,10 +6339,11 @@ abstract class _$Database extends GeneratedDatabase {
|
||||||
String pickle,
|
String pickle,
|
||||||
String content,
|
String content,
|
||||||
String indexes,
|
String indexes,
|
||||||
|
String allowed_at_index,
|
||||||
String sender_key,
|
String sender_key,
|
||||||
String sender_claimed_keys) {
|
String sender_claimed_keys) {
|
||||||
return customInsert(
|
return customInsert(
|
||||||
'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)',
|
'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)',
|
||||||
variables: [
|
variables: [
|
||||||
Variable.withInt(client_id),
|
Variable.withInt(client_id),
|
||||||
Variable.withString(room_id),
|
Variable.withString(room_id),
|
||||||
|
|
@ -6304,6 +6351,7 @@ abstract class _$Database extends GeneratedDatabase {
|
||||||
Variable.withString(pickle),
|
Variable.withString(pickle),
|
||||||
Variable.withString(content),
|
Variable.withString(content),
|
||||||
Variable.withString(indexes),
|
Variable.withString(indexes),
|
||||||
|
Variable.withString(allowed_at_index),
|
||||||
Variable.withString(sender_key),
|
Variable.withString(sender_key),
|
||||||
Variable.withString(sender_claimed_keys)
|
Variable.withString(sender_claimed_keys)
|
||||||
],
|
],
|
||||||
|
|
@ -6326,6 +6374,21 @@ abstract class _$Database extends GeneratedDatabase {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<int> updateInboundGroupSessionAllowedAtIndex(String allowed_at_index,
|
||||||
|
int client_id, String room_id, String session_id) {
|
||||||
|
return customUpdate(
|
||||||
|
'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',
|
||||||
|
variables: [
|
||||||
|
Variable.withString(allowed_at_index),
|
||||||
|
Variable.withInt(client_id),
|
||||||
|
Variable.withString(room_id),
|
||||||
|
Variable.withString(session_id)
|
||||||
|
],
|
||||||
|
updates: {inboundGroupSessions},
|
||||||
|
updateKind: UpdateKind.update,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Selectable<DbInboundGroupSession> getInboundGroupSessionsToUpload() {
|
Selectable<DbInboundGroupSession> getInboundGroupSessionsToUpload() {
|
||||||
return customSelect(
|
return customSelect(
|
||||||
'SELECT * FROM inbound_group_sessions WHERE uploaded = false LIMIT 500',
|
'SELECT * FROM inbound_group_sessions WHERE uploaded = false LIMIT 500',
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,7 @@ CREATE TABLE inbound_group_sessions (
|
||||||
pickle TEXT NOT NULL,
|
pickle TEXT NOT NULL,
|
||||||
content TEXT,
|
content TEXT,
|
||||||
indexes TEXT,
|
indexes TEXT,
|
||||||
|
allowed_at_index TEXT,
|
||||||
uploaded BOOLEAN DEFAULT false,
|
uploaded BOOLEAN DEFAULT false,
|
||||||
sender_key TEXT,
|
sender_key TEXT,
|
||||||
sender_claimed_keys TEXT,
|
sender_claimed_keys TEXT,
|
||||||
|
|
@ -189,8 +190,9 @@ 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, sender_key, sender_claimed_keys) VALUES (:client_id, :room_id, :session_id, :pickle, :content, :indexes, :sender_key, :sender_claimed_keys);
|
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;
|
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;
|
getInboundGroupSessionsToUpload: 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;
|
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;
|
markInboundGroupSessionsAsNeedingUpload: UPDATE inbound_group_sessions SET uploaded = false WHERE client_id = :client_id;
|
||||||
|
|
|
||||||
|
|
@ -108,11 +108,11 @@ void main() {
|
||||||
expect(
|
expect(
|
||||||
client.encryption.keyManager.getOutboundGroupSession(roomId) != null,
|
client.encryption.keyManager.getOutboundGroupSession(roomId) != null,
|
||||||
true);
|
true);
|
||||||
expect(
|
var inbound = client.encryption.keyManager.getInboundGroupSession(
|
||||||
client.encryption.keyManager.getInboundGroupSession(roomId,
|
roomId, sess.outboundGroupSession.session_id(), client.identityKey);
|
||||||
sess.outboundGroupSession.session_id(), client.identityKey) !=
|
expect(inbound != null, true);
|
||||||
null,
|
expect(inbound.allowedAtIndex['@alice:example.com']['JLAFKJWSCS'], 0);
|
||||||
true);
|
expect(inbound.allowedAtIndex['@alice:example.com']['OTHERDEVICE'], 0);
|
||||||
|
|
||||||
// rotate after too many messages
|
// rotate after too many messages
|
||||||
sess.sentMessages = 300;
|
sess.sentMessages = 300;
|
||||||
|
|
@ -159,6 +159,8 @@ void main() {
|
||||||
// do not rotate if new device is added
|
// do not rotate if new device is added
|
||||||
sess =
|
sess =
|
||||||
await client.encryption.keyManager.createOutboundGroupSession(roomId);
|
await client.encryption.keyManager.createOutboundGroupSession(roomId);
|
||||||
|
sess.outboundGroupSession.encrypt(
|
||||||
|
'foxies'); // so that the new device will have a different index
|
||||||
client.userDeviceKeys['@alice:example.com'].deviceKeys['NEWDEVICE'] =
|
client.userDeviceKeys['@alice:example.com'].deviceKeys['NEWDEVICE'] =
|
||||||
DeviceKeys.fromJson({
|
DeviceKeys.fromJson({
|
||||||
'user_id': '@alice:example.com',
|
'user_id': '@alice:example.com',
|
||||||
|
|
@ -177,6 +179,11 @@ void main() {
|
||||||
expect(
|
expect(
|
||||||
client.encryption.keyManager.getOutboundGroupSession(roomId) != null,
|
client.encryption.keyManager.getOutboundGroupSession(roomId) != null,
|
||||||
true);
|
true);
|
||||||
|
inbound = client.encryption.keyManager.getInboundGroupSession(
|
||||||
|
roomId, sess.outboundGroupSession.session_id(), client.identityKey);
|
||||||
|
expect(inbound.allowedAtIndex['@alice:example.com']['JLAFKJWSCS'], 0);
|
||||||
|
expect(inbound.allowedAtIndex['@alice:example.com']['OTHERDEVICE'], 0);
|
||||||
|
expect(inbound.allowedAtIndex['@alice:example.com']['NEWDEVICE'], 1);
|
||||||
|
|
||||||
// do not rotate if new user is added
|
// do not rotate if new user is added
|
||||||
member.content['membership'] = 'leave';
|
member.content['membership'] = 'leave';
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,9 @@ void main() {
|
||||||
await matrix
|
await matrix
|
||||||
.userDeviceKeys['@alice:example.com'].deviceKeys['OTHERDEVICE']
|
.userDeviceKeys['@alice:example.com'].deviceKeys['OTHERDEVICE']
|
||||||
.setVerified(true);
|
.setVerified(true);
|
||||||
|
final session = await matrix.encryption.keyManager
|
||||||
|
.loadInboundGroupSession(
|
||||||
|
'!726s6s6q:example.com', validSessionId, validSenderKey);
|
||||||
// test a successful share
|
// test a successful share
|
||||||
var event = ToDeviceEvent(
|
var event = ToDeviceEvent(
|
||||||
sender: '@alice:example.com',
|
sender: '@alice:example.com',
|
||||||
|
|
@ -115,8 +118,58 @@ void main() {
|
||||||
(k) => k.startsWith('/client/r0/sendToDevice/m.room.encrypted')),
|
(k) => k.startsWith('/client/r0/sendToDevice/m.room.encrypted')),
|
||||||
true);
|
true);
|
||||||
|
|
||||||
|
// test a successful foreign share
|
||||||
|
FakeMatrixApi.calledEndpoints.clear();
|
||||||
|
session.allowedAtIndex['@test:fakeServer.notExisting'] = <String, int>{
|
||||||
|
'OTHERDEVICE': 0,
|
||||||
|
};
|
||||||
|
event = ToDeviceEvent(
|
||||||
|
sender: '@test:fakeServer.notExisting',
|
||||||
|
type: 'm.room_key_request',
|
||||||
|
content: {
|
||||||
|
'action': 'request',
|
||||||
|
'body': {
|
||||||
|
'algorithm': AlgorithmTypes.megolmV1AesSha2,
|
||||||
|
'room_id': '!726s6s6q:example.com',
|
||||||
|
'sender_key': validSenderKey,
|
||||||
|
'session_id': validSessionId,
|
||||||
|
},
|
||||||
|
'request_id': 'request_a1',
|
||||||
|
'requesting_device_id': 'OTHERDEVICE',
|
||||||
|
});
|
||||||
|
await matrix.encryption.keyManager.handleToDeviceEvent(event);
|
||||||
|
Logs().i(FakeMatrixApi.calledEndpoints.keys.toString());
|
||||||
|
expect(
|
||||||
|
FakeMatrixApi.calledEndpoints.keys.any(
|
||||||
|
(k) => k.startsWith('/client/r0/sendToDevice/m.room.encrypted')),
|
||||||
|
true);
|
||||||
|
session.allowedAtIndex.remove('@test:fakeServer.notExisting');
|
||||||
|
|
||||||
// test various fail scenarios
|
// test various fail scenarios
|
||||||
|
|
||||||
|
// unknown person
|
||||||
|
FakeMatrixApi.calledEndpoints.clear();
|
||||||
|
event = ToDeviceEvent(
|
||||||
|
sender: '@test:fakeServer.notExisting',
|
||||||
|
type: 'm.room_key_request',
|
||||||
|
content: {
|
||||||
|
'action': 'request',
|
||||||
|
'body': {
|
||||||
|
'algorithm': AlgorithmTypes.megolmV1AesSha2,
|
||||||
|
'room_id': '!726s6s6q:example.com',
|
||||||
|
'sender_key': validSenderKey,
|
||||||
|
'session_id': validSessionId,
|
||||||
|
},
|
||||||
|
'request_id': 'request_a2',
|
||||||
|
'requesting_device_id': 'OTHERDEVICE',
|
||||||
|
});
|
||||||
|
await matrix.encryption.keyManager.handleToDeviceEvent(event);
|
||||||
|
Logs().i(FakeMatrixApi.calledEndpoints.keys.toString());
|
||||||
|
expect(
|
||||||
|
FakeMatrixApi.calledEndpoints.keys.any(
|
||||||
|
(k) => k.startsWith('/client/r0/sendToDevice/m.room.encrypted')),
|
||||||
|
false);
|
||||||
|
|
||||||
// no body
|
// no body
|
||||||
FakeMatrixApi.calledEndpoints.clear();
|
FakeMatrixApi.calledEndpoints.clear();
|
||||||
event = ToDeviceEvent(
|
event = ToDeviceEvent(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue