Krille/make client extend matrixapi
This commit is contained in:
parent
574fe27101
commit
fb9b505988
|
@ -167,7 +167,7 @@ class CrossSigning {
|
||||||
}
|
}
|
||||||
if (signedKeys.isNotEmpty) {
|
if (signedKeys.isNotEmpty) {
|
||||||
// post our new keys!
|
// post our new keys!
|
||||||
await client.api.uploadKeySignatures(signedKeys);
|
await client.uploadKeySignatures(signedKeys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ class KeyManager {
|
||||||
encryption.ssss.setValidator(MEGOLM_KEY, (String secret) async {
|
encryption.ssss.setValidator(MEGOLM_KEY, (String secret) async {
|
||||||
final keyObj = olm.PkDecryption();
|
final keyObj = olm.PkDecryption();
|
||||||
try {
|
try {
|
||||||
final info = await client.api.getRoomKeysBackup();
|
final info = await client.getRoomKeysBackup();
|
||||||
if (info.algorithm != RoomKeysAlgorithmType.v1Curve25519AesSha2) {
|
if (info.algorithm != RoomKeysAlgorithmType.v1Curve25519AesSha2) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -288,7 +288,7 @@ class KeyManager {
|
||||||
key: client.userID,
|
key: client.userID,
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
await client.sendToDevice(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;
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
|
@ -339,7 +339,7 @@ class KeyManager {
|
||||||
final privateKey =
|
final privateKey =
|
||||||
base64.decode(await encryption.ssss.getCached(MEGOLM_KEY));
|
base64.decode(await encryption.ssss.getCached(MEGOLM_KEY));
|
||||||
final decryption = olm.PkDecryption();
|
final decryption = olm.PkDecryption();
|
||||||
final info = await client.api.getRoomKeysBackup();
|
final info = await client.getRoomKeysBackup();
|
||||||
String backupPubKey;
|
String backupPubKey;
|
||||||
try {
|
try {
|
||||||
backupPubKey = decryption.init_with_private_key(privateKey);
|
backupPubKey = decryption.init_with_private_key(privateKey);
|
||||||
|
@ -387,9 +387,9 @@ class KeyManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> loadSingleKey(String roomId, String sessionId) async {
|
Future<void> loadSingleKey(String roomId, String sessionId) async {
|
||||||
final info = await client.api.getRoomKeysBackup();
|
final info = await client.getRoomKeysBackup();
|
||||||
final ret =
|
final ret =
|
||||||
await client.api.getRoomKeysSingleKey(roomId, sessionId, info.version);
|
await client.getRoomKeysSingleKey(roomId, sessionId, info.version);
|
||||||
final keys = RoomKeys.fromJson({
|
final keys = RoomKeys.fromJson({
|
||||||
'rooms': {
|
'rooms': {
|
||||||
roomId: {
|
roomId: {
|
||||||
|
@ -434,22 +434,22 @@ class KeyManager {
|
||||||
sessionId: sessionId,
|
sessionId: sessionId,
|
||||||
senderKey: senderKey,
|
senderKey: senderKey,
|
||||||
);
|
);
|
||||||
await client.sendToDevice(
|
final userList = await room.requestParticipants();
|
||||||
[],
|
await client.sendToDevicesOfUserIds(
|
||||||
'm.room_key_request',
|
userList.map<String>((u) => u.id).toSet(),
|
||||||
{
|
'm.room_key_request',
|
||||||
'action': 'request',
|
{
|
||||||
'body': {
|
'action': 'request',
|
||||||
'algorithm': 'm.megolm.v1.aes-sha2',
|
'body': {
|
||||||
'room_id': room.id,
|
'algorithm': 'm.megolm.v1.aes-sha2',
|
||||||
'sender_key': senderKey,
|
'room_id': room.id,
|
||||||
'session_id': sessionId,
|
'sender_key': senderKey,
|
||||||
},
|
'session_id': sessionId,
|
||||||
'request_id': requestId,
|
|
||||||
'requesting_device_id': client.deviceID,
|
|
||||||
},
|
},
|
||||||
encrypted: false,
|
'request_id': requestId,
|
||||||
toUsers: await room.requestParticipants());
|
'requesting_device_id': client.deviceID,
|
||||||
|
},
|
||||||
|
);
|
||||||
outgoingShareRequests[request.requestId] = request;
|
outgoingShareRequests[request.requestId] = request;
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logs.error(
|
Logs.error(
|
||||||
|
@ -568,15 +568,24 @@ class KeyManager {
|
||||||
if (request.devices.isEmpty) {
|
if (request.devices.isEmpty) {
|
||||||
return; // no need to send any cancellation
|
return; // no need to send any cancellation
|
||||||
}
|
}
|
||||||
|
// Send with send-to-device messaging
|
||||||
|
final sendToDeviceMessage = {
|
||||||
|
'action': 'request_cancellation',
|
||||||
|
'request_id': request.requestId,
|
||||||
|
'requesting_device_id': client.deviceID,
|
||||||
|
};
|
||||||
|
var data = <String, Map<String, Map<String, dynamic>>>{};
|
||||||
|
for (final device in request.devices) {
|
||||||
|
if (!data.containsKey(device.userId)) {
|
||||||
|
data[device.userId] = {};
|
||||||
|
}
|
||||||
|
data[device.userId][device.deviceId] = sendToDeviceMessage;
|
||||||
|
}
|
||||||
await client.sendToDevice(
|
await client.sendToDevice(
|
||||||
request.devices,
|
'm.room_key_request',
|
||||||
'm.room_key_request',
|
client.generateUniqueTransactionId(),
|
||||||
{
|
data,
|
||||||
'action': 'request_cancellation',
|
);
|
||||||
'request_id': request.requestId,
|
|
||||||
'requesting_device_id': client.deviceID,
|
|
||||||
},
|
|
||||||
encrypted: false);
|
|
||||||
} else if (event.type == 'm.room_key') {
|
} else if (event.type == 'm.room_key') {
|
||||||
if (event.encryptedContent == null) {
|
if (event.encryptedContent == null) {
|
||||||
return; // the event wasn't encrypted, this is a security risk;
|
return; // the event wasn't encrypted, this is a security risk;
|
||||||
|
@ -675,7 +684,7 @@ class RoomKeyRequest extends ToDeviceEvent {
|
||||||
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
|
||||||
await keyManager.client.sendToDevice(
|
await keyManager.client.sendToDeviceEncrypted(
|
||||||
[requestingDevice],
|
[requestingDevice],
|
||||||
'm.forwarded_room_key',
|
'm.forwarded_room_key',
|
||||||
message,
|
message,
|
||||||
|
|
|
@ -183,7 +183,7 @@ class OlmManager {
|
||||||
signJson(keysContent['device_keys'] as Map<String, dynamic>);
|
signJson(keysContent['device_keys'] as Map<String, dynamic>);
|
||||||
}
|
}
|
||||||
|
|
||||||
final response = await client.api.uploadDeviceKeys(
|
final response = await client.uploadDeviceKeys(
|
||||||
deviceKeys: uploadDeviceKeys
|
deviceKeys: uploadDeviceKeys
|
||||||
? MatrixDeviceKeys.fromJson(keysContent['device_keys'])
|
? MatrixDeviceKeys.fromJson(keysContent['device_keys'])
|
||||||
: null,
|
: null,
|
||||||
|
@ -335,7 +335,7 @@ class OlmManager {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await startOutgoingOlmSessions([device]);
|
await startOutgoingOlmSessions([device]);
|
||||||
await client.sendToDevice([device], 'm.dummy', {});
|
await client.sendToDeviceEncrypted([device], 'm.dummy', {});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<ToDeviceEvent> decryptToDeviceEvent(ToDeviceEvent event) async {
|
Future<ToDeviceEvent> decryptToDeviceEvent(ToDeviceEvent event) async {
|
||||||
|
@ -383,7 +383,7 @@ class OlmManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
final response =
|
final response =
|
||||||
await client.api.requestOneTimeKeys(requestingKeysFrom, timeout: 10000);
|
await client.requestOneTimeKeys(requestingKeysFrom, timeout: 10000);
|
||||||
|
|
||||||
for (var userKeysEntry in response.oneTimeKeys.entries) {
|
for (var userKeysEntry in response.oneTimeKeys.entries) {
|
||||||
final userId = userKeysEntry.key;
|
final userId = userKeysEntry.key;
|
||||||
|
|
|
@ -222,7 +222,7 @@ class SSSS {
|
||||||
'mac': encrypted.mac,
|
'mac': encrypted.mac,
|
||||||
};
|
};
|
||||||
// store the thing in your account data
|
// store the thing in your account data
|
||||||
await client.api.setAccountData(client.userID, type, content);
|
await client.setAccountData(client.userID, type, content);
|
||||||
if (CACHE_TYPES.contains(type) && client.database != null) {
|
if (CACHE_TYPES.contains(type) && client.database != null) {
|
||||||
// cache the thing
|
// cache the thing
|
||||||
await client.database
|
await client.database
|
||||||
|
@ -271,7 +271,7 @@ class SSSS {
|
||||||
devices: devices,
|
devices: devices,
|
||||||
);
|
);
|
||||||
pendingShareRequests[requestId] = request;
|
pendingShareRequests[requestId] = request;
|
||||||
await client.sendToDevice(devices, 'm.secret.request', {
|
await client.sendToDeviceEncrypted(devices, 'm.secret.request', {
|
||||||
'action': 'request',
|
'action': 'request',
|
||||||
'requesting_device_id': client.deviceID,
|
'requesting_device_id': client.deviceID,
|
||||||
'request_id': requestId,
|
'request_id': requestId,
|
||||||
|
@ -308,7 +308,7 @@ class SSSS {
|
||||||
}
|
}
|
||||||
// okay, all checks out...time to share this secret!
|
// okay, all checks out...time to share this secret!
|
||||||
Logs.info('[SSSS] Replying with secret for ${type}');
|
Logs.info('[SSSS] Replying with secret for ${type}');
|
||||||
await client.sendToDevice(
|
await client.sendToDeviceEncrypted(
|
||||||
[device],
|
[device],
|
||||||
'm.secret.send',
|
'm.secret.send',
|
||||||
{
|
{
|
||||||
|
|
|
@ -571,7 +571,7 @@ class KeyVerification {
|
||||||
} else {
|
} else {
|
||||||
Logs.info(
|
Logs.info(
|
||||||
'[Key Verification] Sending to ${userId} device ${deviceId}...');
|
'[Key Verification] Sending to ${userId} device ${deviceId}...');
|
||||||
await client.sendToDevice(
|
await client.sendToDeviceEncrypted(
|
||||||
[client.userDeviceKeys[userId].deviceKeys[deviceId]], type, payload);
|
[client.userDeviceKeys[userId].deviceKeys[deviceId]], type, payload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1329,8 +1329,11 @@ class MatrixApi {
|
||||||
|
|
||||||
/// This endpoint is used to send send-to-device events to a set of client devices.
|
/// This endpoint is used to send send-to-device events to a set of client devices.
|
||||||
/// https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-sendtodevice-eventtype-txnid
|
/// https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-sendtodevice-eventtype-txnid
|
||||||
Future<void> sendToDevice(String eventType, String txnId,
|
Future<void> sendToDevice(
|
||||||
Map<String, Map<String, Map<String, dynamic>>> messages) async {
|
String eventType,
|
||||||
|
String txnId,
|
||||||
|
Map<String, Map<String, Map<String, dynamic>>> messages,
|
||||||
|
) async {
|
||||||
await request(
|
await request(
|
||||||
RequestType.PUT,
|
RequestType.PUT,
|
||||||
'/client/r0/sendToDevice/${Uri.encodeComponent(eventType)}/${Uri.encodeComponent(txnId)}',
|
'/client/r0/sendToDevice/${Uri.encodeComponent(eventType)}/${Uri.encodeComponent(txnId)}',
|
||||||
|
|
|
@ -22,7 +22,6 @@ import 'dart:core';
|
||||||
|
|
||||||
import 'package:famedlysdk/encryption.dart';
|
import 'package:famedlysdk/encryption.dart';
|
||||||
import 'package:famedlysdk/famedlysdk.dart';
|
import 'package:famedlysdk/famedlysdk.dart';
|
||||||
import 'package:famedlysdk/matrix_api.dart';
|
|
||||||
import 'package:famedlysdk/src/room.dart';
|
import 'package:famedlysdk/src/room.dart';
|
||||||
import 'package:famedlysdk/src/utils/device_keys_list.dart';
|
import 'package:famedlysdk/src/utils/device_keys_list.dart';
|
||||||
import 'package:famedlysdk/src/utils/logs.dart';
|
import 'package:famedlysdk/src/utils/logs.dart';
|
||||||
|
@ -45,7 +44,7 @@ enum LoginState { logged, loggedOut }
|
||||||
/// Represents a Matrix client to communicate with a
|
/// Represents a Matrix client to communicate with a
|
||||||
/// [Matrix](https://matrix.org) homeserver and is the entry point for this
|
/// [Matrix](https://matrix.org) homeserver and is the entry point for this
|
||||||
/// SDK.
|
/// SDK.
|
||||||
class Client {
|
class Client extends MatrixApi {
|
||||||
int _id;
|
int _id;
|
||||||
int get id => _id;
|
int get id => _id;
|
||||||
|
|
||||||
|
@ -53,7 +52,8 @@ class Client {
|
||||||
|
|
||||||
bool enableE2eeRecovery;
|
bool enableE2eeRecovery;
|
||||||
|
|
||||||
MatrixApi api;
|
@deprecated
|
||||||
|
MatrixApi get api => this;
|
||||||
|
|
||||||
Encryption encryption;
|
Encryption encryption;
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ class Client {
|
||||||
EventTypes.RoomCanonicalAlias,
|
EventTypes.RoomCanonicalAlias,
|
||||||
EventTypes.RoomTombstone,
|
EventTypes.RoomTombstone,
|
||||||
]);
|
]);
|
||||||
api = MatrixApi(httpClient: httpClient);
|
this.httpClient = httpClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The required name for this client.
|
/// The required name for this client.
|
||||||
|
@ -125,7 +125,7 @@ class Client {
|
||||||
String _deviceName;
|
String _deviceName;
|
||||||
|
|
||||||
/// Returns the current login state.
|
/// Returns the current login state.
|
||||||
bool isLogged() => api.accessToken != null;
|
bool isLogged() => accessToken != null;
|
||||||
|
|
||||||
/// A list of all rooms the user is participating or invited.
|
/// A list of all rooms the user is participating or invited.
|
||||||
List<Room> get rooms => _rooms;
|
List<Room> get rooms => _rooms;
|
||||||
|
@ -160,21 +160,6 @@ class Client {
|
||||||
|
|
||||||
int _transactionCounter = 0;
|
int _transactionCounter = 0;
|
||||||
|
|
||||||
@Deprecated('Use [api.request()] instead')
|
|
||||||
Future<Map<String, dynamic>> jsonRequest(
|
|
||||||
{RequestType type,
|
|
||||||
String action,
|
|
||||||
dynamic data = '',
|
|
||||||
int timeout,
|
|
||||||
String contentType = 'application/json'}) =>
|
|
||||||
api.request(
|
|
||||||
type,
|
|
||||||
action,
|
|
||||||
data: data,
|
|
||||||
timeout: timeout,
|
|
||||||
contentType: contentType,
|
|
||||||
);
|
|
||||||
|
|
||||||
String generateUniqueTransactionId() {
|
String generateUniqueTransactionId() {
|
||||||
_transactionCounter++;
|
_transactionCounter++;
|
||||||
return '${clientName}-${_transactionCounter}-${DateTime.now().millisecondsSinceEpoch}';
|
return '${clientName}-${_transactionCounter}-${DateTime.now().millisecondsSinceEpoch}';
|
||||||
|
@ -243,7 +228,7 @@ class Client {
|
||||||
Future<bool> checkServer(dynamic serverUrl) async {
|
Future<bool> checkServer(dynamic serverUrl) async {
|
||||||
try {
|
try {
|
||||||
if (serverUrl is Uri) {
|
if (serverUrl is Uri) {
|
||||||
api.homeserver = serverUrl;
|
homeserver = serverUrl;
|
||||||
} else {
|
} else {
|
||||||
// URLs allow to have whitespace surrounding them, see https://www.w3.org/TR/2011/WD-html5-20110525/urls.html
|
// URLs allow to have whitespace surrounding them, see https://www.w3.org/TR/2011/WD-html5-20110525/urls.html
|
||||||
// As we want to strip a trailing slash, though, we have to trim the url ourself
|
// As we want to strip a trailing slash, though, we have to trim the url ourself
|
||||||
|
@ -253,9 +238,9 @@ class Client {
|
||||||
if (serverUrl.endsWith('/')) {
|
if (serverUrl.endsWith('/')) {
|
||||||
serverUrl = serverUrl.substring(0, serverUrl.length - 1);
|
serverUrl = serverUrl.substring(0, serverUrl.length - 1);
|
||||||
}
|
}
|
||||||
api.homeserver = Uri.parse(serverUrl);
|
homeserver = Uri.parse(serverUrl);
|
||||||
}
|
}
|
||||||
final versions = await api.requestSupportedVersions();
|
final versions = await requestSupportedVersions();
|
||||||
|
|
||||||
for (var i = 0; i < versions.versions.length; i++) {
|
for (var i = 0; i < versions.versions.length; i++) {
|
||||||
if (versions.versions[i] == 'r0.5.0' ||
|
if (versions.versions[i] == 'r0.5.0' ||
|
||||||
|
@ -266,7 +251,7 @@ class Client {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final loginTypes = await api.requestLoginTypes();
|
final loginTypes = await requestLoginTypes();
|
||||||
if (loginTypes.flows.indexWhere((f) => f.type == 'm.login.password') ==
|
if (loginTypes.flows.indexWhere((f) => f.type == 'm.login.password') ==
|
||||||
-1) {
|
-1) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -274,7 +259,7 @@ class Client {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
api.homeserver = null;
|
homeserver = null;
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -282,16 +267,17 @@ class Client {
|
||||||
/// Checks to see if a username is available, and valid, for the server.
|
/// Checks to see if a username is available, and valid, for the server.
|
||||||
/// Returns the fully-qualified Matrix user ID (MXID) that has been registered.
|
/// Returns the fully-qualified Matrix user ID (MXID) that has been registered.
|
||||||
/// You have to call [checkServer] first to set a homeserver.
|
/// You have to call [checkServer] first to set a homeserver.
|
||||||
Future<void> register({
|
@override
|
||||||
String kind,
|
Future<LoginResponse> register({
|
||||||
String username,
|
String username,
|
||||||
String password,
|
String password,
|
||||||
Map<String, dynamic> auth,
|
|
||||||
String deviceId,
|
String deviceId,
|
||||||
String initialDeviceDisplayName,
|
String initialDeviceDisplayName,
|
||||||
bool inhibitLogin,
|
bool inhibitLogin,
|
||||||
|
Map<String, dynamic> auth,
|
||||||
|
String kind,
|
||||||
}) async {
|
}) async {
|
||||||
final response = await api.register(
|
final response = await super.register(
|
||||||
username: username,
|
username: username,
|
||||||
password: password,
|
password: password,
|
||||||
auth: auth,
|
auth: auth,
|
||||||
|
@ -309,66 +295,62 @@ class Client {
|
||||||
await connect(
|
await connect(
|
||||||
newToken: response.accessToken,
|
newToken: response.accessToken,
|
||||||
newUserID: response.userId,
|
newUserID: response.userId,
|
||||||
newHomeserver: api.homeserver,
|
newHomeserver: homeserver,
|
||||||
newDeviceName: initialDeviceDisplayName ?? '',
|
newDeviceName: initialDeviceDisplayName ?? '',
|
||||||
newDeviceID: response.deviceId);
|
newDeviceID: response.deviceId);
|
||||||
return;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles the login and allows the client to call all APIs which require
|
/// Handles the login and allows the client to call all APIs which require
|
||||||
/// authentication. Returns false if the login was not successful. Throws
|
/// authentication. Returns false if the login was not successful. Throws
|
||||||
/// MatrixException if login was not successful.
|
/// MatrixException if login was not successful.
|
||||||
/// You have to call [checkServer] first to set a homeserver.
|
/// You have to call [checkServer] first to set a homeserver.
|
||||||
Future<bool> login(
|
@override
|
||||||
String username,
|
Future<LoginResponse> login({
|
||||||
String password, {
|
String type = 'm.login.password',
|
||||||
String initialDeviceDisplayName,
|
String userIdentifierType = 'm.id.user',
|
||||||
|
String user,
|
||||||
|
String medium,
|
||||||
|
String address,
|
||||||
|
String password,
|
||||||
|
String token,
|
||||||
String deviceId,
|
String deviceId,
|
||||||
|
String initialDeviceDisplayName,
|
||||||
}) async {
|
}) async {
|
||||||
var data = <String, dynamic>{
|
final loginResp = await super.login(
|
||||||
'type': 'm.login.password',
|
type: type,
|
||||||
'user': username,
|
userIdentifierType: userIdentifierType,
|
||||||
'identifier': {
|
user: user,
|
||||||
'type': 'm.id.user',
|
|
||||||
'user': username,
|
|
||||||
},
|
|
||||||
'password': password,
|
|
||||||
};
|
|
||||||
if (deviceId != null) data['device_id'] = deviceId;
|
|
||||||
if (initialDeviceDisplayName != null) {
|
|
||||||
data['initial_device_display_name'] = initialDeviceDisplayName;
|
|
||||||
}
|
|
||||||
|
|
||||||
final loginResp = await api.login(
|
|
||||||
type: 'm.login.password',
|
|
||||||
userIdentifierType: 'm.id.user',
|
|
||||||
user: username,
|
|
||||||
password: password,
|
password: password,
|
||||||
deviceId: deviceId,
|
deviceId: deviceId,
|
||||||
initialDeviceDisplayName: initialDeviceDisplayName,
|
initialDeviceDisplayName: initialDeviceDisplayName,
|
||||||
|
medium: medium,
|
||||||
|
address: address,
|
||||||
|
token: token,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Connect if there is an access token in the response.
|
// Connect if there is an access token in the response.
|
||||||
if (loginResp.accessToken == null ||
|
if (loginResp.accessToken == null ||
|
||||||
loginResp.deviceId == null ||
|
loginResp.deviceId == null ||
|
||||||
loginResp.userId == null) {
|
loginResp.userId == null) {
|
||||||
throw 'Registered but token, device ID or user ID is null.';
|
throw Exception('Registered but token, device ID or user ID is null.');
|
||||||
}
|
}
|
||||||
await connect(
|
await connect(
|
||||||
newToken: loginResp.accessToken,
|
newToken: loginResp.accessToken,
|
||||||
newUserID: loginResp.userId,
|
newUserID: loginResp.userId,
|
||||||
newHomeserver: api.homeserver,
|
newHomeserver: homeserver,
|
||||||
newDeviceName: initialDeviceDisplayName ?? '',
|
newDeviceName: initialDeviceDisplayName ?? '',
|
||||||
newDeviceID: loginResp.deviceId,
|
newDeviceID: loginResp.deviceId,
|
||||||
);
|
);
|
||||||
return true;
|
return loginResp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sends a logout command to the homeserver and clears all local data,
|
/// Sends a logout command to the homeserver and clears all local data,
|
||||||
/// including all persistent data from the store.
|
/// including all persistent data from the store.
|
||||||
|
@override
|
||||||
Future<void> logout() async {
|
Future<void> logout() async {
|
||||||
try {
|
try {
|
||||||
await api.logout();
|
await super.logout();
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logs.error(e, s);
|
Logs.error(e, s);
|
||||||
rethrow;
|
rethrow;
|
||||||
|
@ -421,19 +403,19 @@ class Client {
|
||||||
if (cache && _profileCache.containsKey(userId)) {
|
if (cache && _profileCache.containsKey(userId)) {
|
||||||
return _profileCache[userId];
|
return _profileCache[userId];
|
||||||
}
|
}
|
||||||
final profile = await api.requestProfile(userId);
|
final profile = await requestProfile(userId);
|
||||||
_profileCache[userId] = profile;
|
_profileCache[userId] = profile;
|
||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<Room>> get archive async {
|
Future<List<Room>> get archive async {
|
||||||
var archiveList = <Room>[];
|
var archiveList = <Room>[];
|
||||||
final sync = await api.sync(
|
final syncResp = await sync(
|
||||||
filter: '{"room":{"include_leave":true,"timeline":{"limit":10}}}',
|
filter: '{"room":{"include_leave":true,"timeline":{"limit":10}}}',
|
||||||
timeout: 0,
|
timeout: 0,
|
||||||
);
|
);
|
||||||
if (sync.rooms.leave is Map<String, dynamic>) {
|
if (syncResp.rooms.leave is Map<String, dynamic>) {
|
||||||
for (var entry in sync.rooms.leave.entries) {
|
for (var entry in syncResp.rooms.leave.entries) {
|
||||||
final id = entry.key;
|
final id = entry.key;
|
||||||
final room = entry.value;
|
final room = entry.value;
|
||||||
var leftRoom = Room(
|
var leftRoom = Room(
|
||||||
|
@ -460,14 +442,10 @@ class Client {
|
||||||
return archiveList;
|
return archiveList;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Changes the user's displayname.
|
|
||||||
Future<void> setDisplayname(String displayname) =>
|
|
||||||
api.setDisplayname(userID, displayname);
|
|
||||||
|
|
||||||
/// Uploads a new user avatar for this user.
|
/// Uploads a new user avatar for this user.
|
||||||
Future<void> setAvatar(MatrixFile file) async {
|
Future<void> setAvatar(MatrixFile file) async {
|
||||||
final uploadResp = await api.upload(file.bytes, file.name);
|
final uploadResp = await upload(file.bytes, file.name);
|
||||||
await api.setAvatarUrl(userID, Uri.parse(uploadResp));
|
await setAvatarUrl(userID, Uri.parse(uploadResp));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -550,10 +528,6 @@ class Client {
|
||||||
final StreamController<KeyVerification> onKeyVerificationRequest =
|
final StreamController<KeyVerification> onKeyVerificationRequest =
|
||||||
StreamController.broadcast();
|
StreamController.broadcast();
|
||||||
|
|
||||||
/// Matrix synchronisation is done with https long polling. This needs a
|
|
||||||
/// timeout which is usually 30 seconds.
|
|
||||||
int syncTimeoutSec = 30;
|
|
||||||
|
|
||||||
/// How long should the app wait until it retrys the synchronisation after
|
/// How long should the app wait until it retrys the synchronisation after
|
||||||
/// an error?
|
/// an error?
|
||||||
int syncErrorTimeoutSec = 3;
|
int syncErrorTimeoutSec = 3;
|
||||||
|
@ -575,7 +549,7 @@ class Client {
|
||||||
/// "type": "m.login.password",
|
/// "type": "m.login.password",
|
||||||
/// "user": "test",
|
/// "user": "test",
|
||||||
/// "password": "1234",
|
/// "password": "1234",
|
||||||
/// "initial_device_display_name": "Fluffy Matrix Client"
|
/// "initial_device_display_name": "Matrix Client"
|
||||||
/// });
|
/// });
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
@ -604,8 +578,8 @@ class Client {
|
||||||
final account = await database.getClient(clientName);
|
final account = await database.getClient(clientName);
|
||||||
if (account != null) {
|
if (account != null) {
|
||||||
_id = account.clientId;
|
_id = account.clientId;
|
||||||
api.homeserver = Uri.parse(account.homeserverUrl);
|
homeserver = Uri.parse(account.homeserverUrl);
|
||||||
api.accessToken = account.token;
|
accessToken = account.token;
|
||||||
_userID = account.userId;
|
_userID = account.userId;
|
||||||
_deviceID = account.deviceId;
|
_deviceID = account.deviceId;
|
||||||
_deviceName = account.deviceName;
|
_deviceName = account.deviceName;
|
||||||
|
@ -613,15 +587,15 @@ class Client {
|
||||||
olmAccount = account.olmAccount;
|
olmAccount = account.olmAccount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
api.accessToken = newToken ?? api.accessToken;
|
accessToken = newToken ?? accessToken;
|
||||||
api.homeserver = newHomeserver ?? api.homeserver;
|
homeserver = newHomeserver ?? homeserver;
|
||||||
_userID = newUserID ?? _userID;
|
_userID = newUserID ?? _userID;
|
||||||
_deviceID = newDeviceID ?? _deviceID;
|
_deviceID = newDeviceID ?? _deviceID;
|
||||||
_deviceName = newDeviceName ?? _deviceName;
|
_deviceName = newDeviceName ?? _deviceName;
|
||||||
prevBatch = newPrevBatch ?? prevBatch;
|
prevBatch = newPrevBatch ?? prevBatch;
|
||||||
olmAccount = newOlmAccount ?? olmAccount;
|
olmAccount = newOlmAccount ?? olmAccount;
|
||||||
|
|
||||||
if (api.accessToken == null || api.homeserver == null || _userID == null) {
|
if (accessToken == null || homeserver == null || _userID == null) {
|
||||||
// we aren't logged in
|
// we aren't logged in
|
||||||
encryption?.dispose();
|
encryption?.dispose();
|
||||||
encryption = null;
|
encryption = null;
|
||||||
|
@ -636,8 +610,8 @@ class Client {
|
||||||
if (database != null) {
|
if (database != null) {
|
||||||
if (id != null) {
|
if (id != null) {
|
||||||
await database.updateClient(
|
await database.updateClient(
|
||||||
api.homeserver.toString(),
|
homeserver.toString(),
|
||||||
api.accessToken,
|
accessToken,
|
||||||
_userID,
|
_userID,
|
||||||
_deviceID,
|
_deviceID,
|
||||||
_deviceName,
|
_deviceName,
|
||||||
|
@ -648,8 +622,8 @@ class Client {
|
||||||
} else {
|
} else {
|
||||||
_id = await database.insertClient(
|
_id = await database.insertClient(
|
||||||
clientName,
|
clientName,
|
||||||
api.homeserver.toString(),
|
homeserver.toString(),
|
||||||
api.accessToken,
|
accessToken,
|
||||||
_userID,
|
_userID,
|
||||||
_deviceID,
|
_deviceID,
|
||||||
_deviceName,
|
_deviceName,
|
||||||
|
@ -666,7 +640,7 @@ class Client {
|
||||||
|
|
||||||
onLoginStateChanged.add(LoginState.logged);
|
onLoginStateChanged.add(LoginState.logged);
|
||||||
Logs.success(
|
Logs.success(
|
||||||
'Successfully connected as ${userID.localpart} with ${api.homeserver.toString()}',
|
'Successfully connected as ${userID.localpart} with ${homeserver.toString()}',
|
||||||
);
|
);
|
||||||
|
|
||||||
return _sync();
|
return _sync();
|
||||||
|
@ -680,8 +654,8 @@ class Client {
|
||||||
/// Resets all settings and stops the synchronisation.
|
/// Resets all settings and stops the synchronisation.
|
||||||
void clear() {
|
void clear() {
|
||||||
database?.clear(id);
|
database?.clear(id);
|
||||||
_id = api.accessToken =
|
_id = accessToken =
|
||||||
api.homeserver = _userID = _deviceID = _deviceName = prevBatch = null;
|
homeserver = _userID = _deviceID = _deviceName = prevBatch = null;
|
||||||
_rooms = [];
|
_rooms = [];
|
||||||
encryption?.dispose();
|
encryption?.dispose();
|
||||||
encryption = null;
|
encryption = null;
|
||||||
|
@ -694,13 +668,11 @@ class Client {
|
||||||
Future<void> _sync() async {
|
Future<void> _sync() async {
|
||||||
if (isLogged() == false || _disposed) return;
|
if (isLogged() == false || _disposed) return;
|
||||||
try {
|
try {
|
||||||
_syncRequest = api
|
_syncRequest = sync(
|
||||||
.sync(
|
|
||||||
filter: syncFilters,
|
filter: syncFilters,
|
||||||
since: prevBatch,
|
since: prevBatch,
|
||||||
timeout: prevBatch != null ? 30000 : null,
|
timeout: prevBatch != null ? 30000 : null,
|
||||||
)
|
).catchError((e) {
|
||||||
.catchError((e) {
|
|
||||||
_lastSyncError = e;
|
_lastSyncError = e;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
@ -1197,8 +1169,7 @@ class Client {
|
||||||
|
|
||||||
if (outdatedLists.isNotEmpty) {
|
if (outdatedLists.isNotEmpty) {
|
||||||
// Request the missing device key lists from the server.
|
// Request the missing device key lists from the server.
|
||||||
final response =
|
final response = await requestDeviceKeys(outdatedLists, timeout: 10000);
|
||||||
await api.requestDeviceKeys(outdatedLists, timeout: 10000);
|
|
||||||
|
|
||||||
for (final rawDeviceKeyListEntry in response.deviceKeys.entries) {
|
for (final rawDeviceKeyListEntry in response.deviceKeys.entries) {
|
||||||
final userId = rawDeviceKeyListEntry.key;
|
final userId = rawDeviceKeyListEntry.key;
|
||||||
|
@ -1347,17 +1318,35 @@ class Client {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Send an (unencrypted) to device [message] of a specific [eventType] to all
|
||||||
|
/// devices of a set of [users].
|
||||||
|
Future<void> sendToDevicesOfUserIds(
|
||||||
|
Set<String> users,
|
||||||
|
String eventType,
|
||||||
|
Map<String, dynamic> message, {
|
||||||
|
String messageId,
|
||||||
|
}) async {
|
||||||
|
// Send with send-to-device messaging
|
||||||
|
var data = <String, Map<String, Map<String, dynamic>>>{};
|
||||||
|
for (var user in users) {
|
||||||
|
data[user] = {};
|
||||||
|
data[user]['*'] = message;
|
||||||
|
}
|
||||||
|
await sendToDevice(
|
||||||
|
eventType, messageId ?? generateUniqueTransactionId(), data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/// Sends an encrypted [message] of this [type] to these [deviceKeys]. To send
|
/// Sends an encrypted [message] of this [type] to these [deviceKeys]. To send
|
||||||
/// the request to all devices of the current user, pass an empty list to [deviceKeys].
|
/// the request to all devices of the current user, pass an empty list to [deviceKeys].
|
||||||
Future<void> sendToDevice(
|
Future<void> sendToDeviceEncrypted(
|
||||||
List<DeviceKeys> deviceKeys,
|
List<DeviceKeys> deviceKeys,
|
||||||
String type,
|
String eventType,
|
||||||
Map<String, dynamic> message, {
|
Map<String, dynamic> message, {
|
||||||
bool encrypted = true,
|
String messageId,
|
||||||
List<User> toUsers,
|
|
||||||
bool onlyVerified = false,
|
bool onlyVerified = false,
|
||||||
}) async {
|
}) async {
|
||||||
if (encrypted && !encryptionEnabled) return;
|
if (!encryptionEnabled) return;
|
||||||
// Don't send this message to blocked devices, and if specified onlyVerified
|
// Don't send this message to blocked devices, and if specified onlyVerified
|
||||||
// then only send it to verified devices
|
// then only send it to verified devices
|
||||||
if (deviceKeys.isNotEmpty) {
|
if (deviceKeys.isNotEmpty) {
|
||||||
|
@ -1368,36 +1357,13 @@ class Client {
|
||||||
if (deviceKeys.isEmpty) return;
|
if (deviceKeys.isEmpty) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var sendToDeviceMessage = message;
|
|
||||||
|
|
||||||
// Send with send-to-device messaging
|
// Send with send-to-device messaging
|
||||||
var data = <String, Map<String, Map<String, dynamic>>>{};
|
var data = <String, Map<String, Map<String, dynamic>>>{};
|
||||||
if (deviceKeys.isEmpty) {
|
data =
|
||||||
if (toUsers == null) {
|
await encryption.encryptToDeviceMessage(deviceKeys, eventType, message);
|
||||||
data[userID] = {};
|
eventType = EventTypes.Encrypted;
|
||||||
data[userID]['*'] = sendToDeviceMessage;
|
await sendToDevice(
|
||||||
} else {
|
eventType, messageId ?? generateUniqueTransactionId(), data);
|
||||||
for (var user in toUsers) {
|
|
||||||
data[user.id] = {};
|
|
||||||
data[user.id]['*'] = sendToDeviceMessage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (encrypted) {
|
|
||||||
data =
|
|
||||||
await encryption.encryptToDeviceMessage(deviceKeys, type, message);
|
|
||||||
} else {
|
|
||||||
for (final device in deviceKeys) {
|
|
||||||
if (!data.containsKey(device.userId)) {
|
|
||||||
data[device.userId] = {};
|
|
||||||
}
|
|
||||||
data[device.userId][device.deviceId] = sendToDeviceMessage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (encrypted) type = EventTypes.Encrypted;
|
|
||||||
final messageID = generateUniqueTransactionId();
|
|
||||||
await api.sendToDevice(type, messageID, data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether all push notifications are muted using the [.m.rule.master]
|
/// Whether all push notifications are muted using the [.m.rule.master]
|
||||||
|
@ -1422,7 +1388,7 @@ class Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> setMuteAllPushNotifications(bool muted) async {
|
Future<void> setMuteAllPushNotifications(bool muted) async {
|
||||||
await api.enablePushRule(
|
await enablePushRule(
|
||||||
'global',
|
'global',
|
||||||
PushRuleKind.override,
|
PushRuleKind.override,
|
||||||
'.m.rule.master',
|
'.m.rule.master',
|
||||||
|
@ -1432,6 +1398,7 @@ class Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Changes the password. You should either set oldPasswort or another authentication flow.
|
/// Changes the password. You should either set oldPasswort or another authentication flow.
|
||||||
|
@override
|
||||||
Future<void> changePassword(String newPassword,
|
Future<void> changePassword(String newPassword,
|
||||||
{String oldPassword, Map<String, dynamic> auth}) async {
|
{String oldPassword, Map<String, dynamic> auth}) async {
|
||||||
try {
|
try {
|
||||||
|
@ -1442,7 +1409,7 @@ class Client {
|
||||||
'password': oldPassword,
|
'password': oldPassword,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
await api.changePassword(newPassword, auth: auth);
|
await super.changePassword(newPassword, auth: auth);
|
||||||
} on MatrixException catch (matrixException) {
|
} on MatrixException catch (matrixException) {
|
||||||
if (!matrixException.requireAdditionalAuthentication) {
|
if (!matrixException.requireAdditionalAuthentication) {
|
||||||
rethrow;
|
rethrow;
|
||||||
|
|
|
@ -374,21 +374,21 @@ class Room {
|
||||||
|
|
||||||
/// Call the Matrix API to change the name of this room. Returns the event ID of the
|
/// Call the Matrix API to change the name of this room. Returns the event ID of the
|
||||||
/// new m.room.name event.
|
/// new m.room.name event.
|
||||||
Future<String> setName(String newName) => client.api.sendState(
|
Future<String> setName(String newName) => client.sendState(
|
||||||
id,
|
id,
|
||||||
EventTypes.RoomName,
|
EventTypes.RoomName,
|
||||||
{'name': newName},
|
{'name': newName},
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Call the Matrix API to change the topic of this room.
|
/// Call the Matrix API to change the topic of this room.
|
||||||
Future<String> setDescription(String newName) => client.api.sendState(
|
Future<String> setDescription(String newName) => client.sendState(
|
||||||
id,
|
id,
|
||||||
EventTypes.RoomTopic,
|
EventTypes.RoomTopic,
|
||||||
{'topic': newName},
|
{'topic': newName},
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Add a tag to the room.
|
/// Add a tag to the room.
|
||||||
Future<void> addTag(String tag, {double order}) => client.api.addRoomTag(
|
Future<void> addTag(String tag, {double order}) => client.addRoomTag(
|
||||||
client.userID,
|
client.userID,
|
||||||
id,
|
id,
|
||||||
tag,
|
tag,
|
||||||
|
@ -396,7 +396,7 @@ class Room {
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Removes a tag from the room.
|
/// Removes a tag from the room.
|
||||||
Future<void> removeTag(String tag) => client.api.removeRoomTag(
|
Future<void> removeTag(String tag) => client.removeRoomTag(
|
||||||
client.userID,
|
client.userID,
|
||||||
id,
|
id,
|
||||||
tag,
|
tag,
|
||||||
|
@ -423,7 +423,7 @@ class Room {
|
||||||
|
|
||||||
/// Call the Matrix API to change the pinned events of this room.
|
/// Call the Matrix API to change the pinned events of this room.
|
||||||
Future<String> setPinnedEvents(List<String> pinnedEventIds) =>
|
Future<String> setPinnedEvents(List<String> pinnedEventIds) =>
|
||||||
client.api.sendState(
|
client.sendState(
|
||||||
id,
|
id,
|
||||||
EventTypes.RoomPinnedEvents,
|
EventTypes.RoomPinnedEvents,
|
||||||
{'pinned': pinnedEventIds},
|
{'pinned': pinnedEventIds},
|
||||||
|
@ -565,13 +565,13 @@ class Room {
|
||||||
uploadThumbnail = encryptedThumbnail.toMatrixFile();
|
uploadThumbnail = encryptedThumbnail.toMatrixFile();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final uploadResp = await client.api.upload(
|
final uploadResp = await client.upload(
|
||||||
uploadFile.bytes,
|
uploadFile.bytes,
|
||||||
uploadFile.name,
|
uploadFile.name,
|
||||||
contentType: uploadFile.mimeType,
|
contentType: uploadFile.mimeType,
|
||||||
);
|
);
|
||||||
final thumbnailUploadResp = uploadThumbnail != null
|
final thumbnailUploadResp = uploadThumbnail != null
|
||||||
? await client.api.upload(
|
? await client.upload(
|
||||||
uploadThumbnail.bytes,
|
uploadThumbnail.bytes,
|
||||||
uploadThumbnail.name,
|
uploadThumbnail.name,
|
||||||
contentType: uploadThumbnail.mimeType,
|
contentType: uploadThumbnail.mimeType,
|
||||||
|
@ -705,7 +705,7 @@ class Room {
|
||||||
? await client.encryption
|
? await client.encryption
|
||||||
.encryptGroupMessagePayload(id, content, type: type)
|
.encryptGroupMessagePayload(id, content, type: type)
|
||||||
: content;
|
: content;
|
||||||
final res = await client.api.sendMessage(
|
final res = await client.sendMessage(
|
||||||
id,
|
id,
|
||||||
sendType,
|
sendType,
|
||||||
messageID,
|
messageID,
|
||||||
|
@ -731,7 +731,7 @@ class Room {
|
||||||
/// automatically be set.
|
/// automatically be set.
|
||||||
Future<void> join() async {
|
Future<void> join() async {
|
||||||
try {
|
try {
|
||||||
await client.api.joinRoom(id);
|
await client.joinRoom(id);
|
||||||
final invitation = getState(EventTypes.RoomMember, client.userID);
|
final invitation = getState(EventTypes.RoomMember, client.userID);
|
||||||
if (invitation != null &&
|
if (invitation != null &&
|
||||||
invitation.content['is_direct'] is bool &&
|
invitation.content['is_direct'] is bool &&
|
||||||
|
@ -757,25 +757,25 @@ class Room {
|
||||||
/// chat, this will be removed too.
|
/// chat, this will be removed too.
|
||||||
Future<void> leave() async {
|
Future<void> leave() async {
|
||||||
if (directChatMatrixID != '') await removeFromDirectChat();
|
if (directChatMatrixID != '') await removeFromDirectChat();
|
||||||
await client.api.leaveRoom(id);
|
await client.leaveRoom(id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call the Matrix API to forget this room if you already left it.
|
/// Call the Matrix API to forget this room if you already left it.
|
||||||
Future<void> forget() async {
|
Future<void> forget() async {
|
||||||
await client.database?.forgetRoom(client.id, id);
|
await client.database?.forgetRoom(client.id, id);
|
||||||
await client.api.forgetRoom(id);
|
await client.forgetRoom(id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call the Matrix API to kick a user from this room.
|
/// Call the Matrix API to kick a user from this room.
|
||||||
Future<void> kick(String userID) => client.api.kickFromRoom(id, userID);
|
Future<void> kick(String userID) => client.kickFromRoom(id, userID);
|
||||||
|
|
||||||
/// Call the Matrix API to ban a user from this room.
|
/// Call the Matrix API to ban a user from this room.
|
||||||
Future<void> ban(String userID) => client.api.banFromRoom(id, userID);
|
Future<void> ban(String userID) => client.banFromRoom(id, userID);
|
||||||
|
|
||||||
/// Call the Matrix API to unban a banned user from this room.
|
/// Call the Matrix API to unban a banned user from this room.
|
||||||
Future<void> unban(String userID) => client.api.unbanInRoom(id, userID);
|
Future<void> unban(String userID) => client.unbanInRoom(id, userID);
|
||||||
|
|
||||||
/// Set the power level of the user with the [userID] to the value [power].
|
/// Set the power level of the user with the [userID] to the value [power].
|
||||||
/// Returns the event ID of the new state event. If there is no known
|
/// Returns the event ID of the new state event. If there is no known
|
||||||
|
@ -787,7 +787,7 @@ class Room {
|
||||||
if (powerMap['users'] == null) powerMap['users'] = {};
|
if (powerMap['users'] == null) powerMap['users'] = {};
|
||||||
powerMap['users'][userID] = power;
|
powerMap['users'][userID] = power;
|
||||||
|
|
||||||
return await client.api.sendState(
|
return await client.sendState(
|
||||||
id,
|
id,
|
||||||
EventTypes.RoomPowerLevels,
|
EventTypes.RoomPowerLevels,
|
||||||
powerMap,
|
powerMap,
|
||||||
|
@ -795,14 +795,14 @@ class Room {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call the Matrix API to invite a user to this room.
|
/// Call the Matrix API to invite a user to this room.
|
||||||
Future<void> invite(String userID) => client.api.inviteToRoom(id, userID);
|
Future<void> invite(String userID) => client.inviteToRoom(id, userID);
|
||||||
|
|
||||||
/// Request more previous events from the server. [historyCount] defines how much events should
|
/// Request more previous events from the server. [historyCount] defines how much events should
|
||||||
/// be received maximum. When the request is answered, [onHistoryReceived] will be triggered **before**
|
/// be received maximum. When the request is answered, [onHistoryReceived] will be triggered **before**
|
||||||
/// the historical events will be published in the onEvent stream.
|
/// the historical events will be published in the onEvent stream.
|
||||||
Future<void> requestHistory(
|
Future<void> requestHistory(
|
||||||
{int historyCount = DefaultHistoryCount, onHistoryReceived}) async {
|
{int historyCount = DefaultHistoryCount, onHistoryReceived}) async {
|
||||||
final resp = await client.api.requestMessages(
|
final resp = await client.requestMessages(
|
||||||
id,
|
id,
|
||||||
prev_batch,
|
prev_batch,
|
||||||
Direction.b,
|
Direction.b,
|
||||||
|
@ -853,7 +853,7 @@ class Room {
|
||||||
directChats[userID] = [id];
|
directChats[userID] = [id];
|
||||||
}
|
}
|
||||||
|
|
||||||
await client.api.setAccountData(
|
await client.setAccountData(
|
||||||
client.userID,
|
client.userID,
|
||||||
'm.direct',
|
'm.direct',
|
||||||
directChats,
|
directChats,
|
||||||
|
@ -871,7 +871,7 @@ class Room {
|
||||||
return;
|
return;
|
||||||
} // Nothing to do here
|
} // Nothing to do here
|
||||||
|
|
||||||
await client.api.setRoomAccountData(
|
await client.setRoomAccountData(
|
||||||
client.userID,
|
client.userID,
|
||||||
id,
|
id,
|
||||||
'm.direct',
|
'm.direct',
|
||||||
|
@ -884,7 +884,7 @@ class Room {
|
||||||
Future<void> sendReadReceipt(String eventID) async {
|
Future<void> sendReadReceipt(String eventID) async {
|
||||||
notificationCount = 0;
|
notificationCount = 0;
|
||||||
await client.database?.resetNotificationCount(client.id, id);
|
await client.database?.resetNotificationCount(client.id, id);
|
||||||
await client.api.sendReadMarker(
|
await client.sendReadMarker(
|
||||||
id,
|
id,
|
||||||
eventID,
|
eventID,
|
||||||
readReceiptLocationEventId: eventID,
|
readReceiptLocationEventId: eventID,
|
||||||
|
@ -1017,7 +1017,7 @@ class Room {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (participantListComplete) return getParticipants();
|
if (participantListComplete) return getParticipants();
|
||||||
final matrixEvents = await client.api.requestMembers(id);
|
final matrixEvents = await client.requestMembers(id);
|
||||||
final users =
|
final users =
|
||||||
matrixEvents.map((e) => Event.fromMatrixEvent(e, this).asUser).toList();
|
matrixEvents.map((e) => Event.fromMatrixEvent(e, this).asUser).toList();
|
||||||
for (final user in users) {
|
for (final user in users) {
|
||||||
|
@ -1080,7 +1080,7 @@ class Room {
|
||||||
if (mxID == null || !_requestingMatrixIds.add(mxID)) return null;
|
if (mxID == null || !_requestingMatrixIds.add(mxID)) return null;
|
||||||
Map<String, dynamic> resp;
|
Map<String, dynamic> resp;
|
||||||
try {
|
try {
|
||||||
resp = await client.api.requestStateContent(
|
resp = await client.requestStateContent(
|
||||||
id,
|
id,
|
||||||
EventTypes.RoomMember,
|
EventTypes.RoomMember,
|
||||||
mxID,
|
mxID,
|
||||||
|
@ -1093,7 +1093,7 @@ class Room {
|
||||||
}
|
}
|
||||||
if (resp == null && requestProfile) {
|
if (resp == null && requestProfile) {
|
||||||
try {
|
try {
|
||||||
final profile = await client.api.requestProfile(mxID);
|
final profile = await client.requestProfile(mxID);
|
||||||
resp = {
|
resp = {
|
||||||
'displayname': profile.displayname,
|
'displayname': profile.displayname,
|
||||||
'avatar_url': profile.avatarUrl,
|
'avatar_url': profile.avatarUrl,
|
||||||
|
@ -1135,7 +1135,7 @@ class Room {
|
||||||
|
|
||||||
/// Searches for the event on the server. Returns null if not found.
|
/// Searches for the event on the server. Returns null if not found.
|
||||||
Future<Event> getEventById(String eventID) async {
|
Future<Event> getEventById(String eventID) async {
|
||||||
final matrixEvent = await client.api.requestEvent(id, eventID);
|
final matrixEvent = await client.requestEvent(id, eventID);
|
||||||
return Event.fromMatrixEvent(matrixEvent, this);
|
return Event.fromMatrixEvent(matrixEvent, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1169,8 +1169,8 @@ class Room {
|
||||||
/// Uploads a new user avatar for this room. Returns the event ID of the new
|
/// Uploads a new user avatar for this room. Returns the event ID of the new
|
||||||
/// m.room.avatar event.
|
/// m.room.avatar event.
|
||||||
Future<String> setAvatar(MatrixFile file) async {
|
Future<String> setAvatar(MatrixFile file) async {
|
||||||
final uploadResp = await client.api.upload(file.bytes, file.name);
|
final uploadResp = await client.upload(file.bytes, file.name);
|
||||||
return await client.api.sendState(
|
return await client.sendState(
|
||||||
id,
|
id,
|
||||||
EventTypes.RoomAvatar,
|
EventTypes.RoomAvatar,
|
||||||
{'url': uploadResp},
|
{'url': uploadResp},
|
||||||
|
@ -1267,23 +1267,23 @@ class Room {
|
||||||
// All push notifications should be sent to the user
|
// All push notifications should be sent to the user
|
||||||
case PushRuleState.notify:
|
case PushRuleState.notify:
|
||||||
if (pushRuleState == PushRuleState.dont_notify) {
|
if (pushRuleState == PushRuleState.dont_notify) {
|
||||||
await client.api.deletePushRule('global', PushRuleKind.override, id);
|
await client.deletePushRule('global', PushRuleKind.override, id);
|
||||||
} else if (pushRuleState == PushRuleState.mentions_only) {
|
} else if (pushRuleState == PushRuleState.mentions_only) {
|
||||||
await client.api.deletePushRule('global', PushRuleKind.room, id);
|
await client.deletePushRule('global', PushRuleKind.room, id);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// Only when someone mentions the user, a push notification should be sent
|
// Only when someone mentions the user, a push notification should be sent
|
||||||
case PushRuleState.mentions_only:
|
case PushRuleState.mentions_only:
|
||||||
if (pushRuleState == PushRuleState.dont_notify) {
|
if (pushRuleState == PushRuleState.dont_notify) {
|
||||||
await client.api.deletePushRule('global', PushRuleKind.override, id);
|
await client.deletePushRule('global', PushRuleKind.override, id);
|
||||||
await client.api.setPushRule(
|
await client.setPushRule(
|
||||||
'global',
|
'global',
|
||||||
PushRuleKind.room,
|
PushRuleKind.room,
|
||||||
id,
|
id,
|
||||||
[PushRuleAction.dont_notify],
|
[PushRuleAction.dont_notify],
|
||||||
);
|
);
|
||||||
} else if (pushRuleState == PushRuleState.notify) {
|
} else if (pushRuleState == PushRuleState.notify) {
|
||||||
await client.api.setPushRule(
|
await client.setPushRule(
|
||||||
'global',
|
'global',
|
||||||
PushRuleKind.room,
|
PushRuleKind.room,
|
||||||
id,
|
id,
|
||||||
|
@ -1294,9 +1294,9 @@ class Room {
|
||||||
// No push notification should be ever sent for this room.
|
// No push notification should be ever sent for this room.
|
||||||
case PushRuleState.dont_notify:
|
case PushRuleState.dont_notify:
|
||||||
if (pushRuleState == PushRuleState.mentions_only) {
|
if (pushRuleState == PushRuleState.mentions_only) {
|
||||||
await client.api.deletePushRule('global', PushRuleKind.room, id);
|
await client.deletePushRule('global', PushRuleKind.room, id);
|
||||||
}
|
}
|
||||||
await client.api.setPushRule(
|
await client.setPushRule(
|
||||||
'global',
|
'global',
|
||||||
PushRuleKind.override,
|
PushRuleKind.override,
|
||||||
id,
|
id,
|
||||||
|
@ -1322,7 +1322,7 @@ class Room {
|
||||||
}
|
}
|
||||||
var data = <String, dynamic>{};
|
var data = <String, dynamic>{};
|
||||||
if (reason != null) data['reason'] = reason;
|
if (reason != null) data['reason'] = reason;
|
||||||
return await client.api.redact(
|
return await client.redact(
|
||||||
id,
|
id,
|
||||||
eventId,
|
eventId,
|
||||||
messageID,
|
messageID,
|
||||||
|
@ -1335,7 +1335,7 @@ class Room {
|
||||||
'typing': isTyping,
|
'typing': isTyping,
|
||||||
};
|
};
|
||||||
if (timeout != null) data['timeout'] = timeout;
|
if (timeout != null) data['timeout'] = timeout;
|
||||||
return client.api.sendTypingNotification(client.userID, id, isTyping);
|
return client.sendTypingNotification(client.userID, id, isTyping);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is sent by the caller when they wish to establish a call.
|
/// This is sent by the caller when they wish to establish a call.
|
||||||
|
@ -1349,7 +1349,7 @@ class Room {
|
||||||
{String type = 'offer', int version = 0, String txid}) async {
|
{String type = 'offer', int version = 0, String txid}) async {
|
||||||
txid ??= 'txid${DateTime.now().millisecondsSinceEpoch}';
|
txid ??= 'txid${DateTime.now().millisecondsSinceEpoch}';
|
||||||
|
|
||||||
return await client.api.sendMessage(
|
return await client.sendMessage(
|
||||||
id,
|
id,
|
||||||
EventTypes.CallInvite,
|
EventTypes.CallInvite,
|
||||||
txid,
|
txid,
|
||||||
|
@ -1387,7 +1387,7 @@ class Room {
|
||||||
String txid,
|
String txid,
|
||||||
}) async {
|
}) async {
|
||||||
txid ??= 'txid${DateTime.now().millisecondsSinceEpoch}';
|
txid ??= 'txid${DateTime.now().millisecondsSinceEpoch}';
|
||||||
return await client.api.sendMessage(
|
return await client.sendMessage(
|
||||||
id,
|
id,
|
||||||
EventTypes.CallCandidates,
|
EventTypes.CallCandidates,
|
||||||
txid,
|
txid,
|
||||||
|
@ -1407,7 +1407,7 @@ class Room {
|
||||||
Future<String> answerCall(String callId, String sdp,
|
Future<String> answerCall(String callId, String sdp,
|
||||||
{String type = 'answer', int version = 0, String txid}) async {
|
{String type = 'answer', int version = 0, String txid}) async {
|
||||||
txid ??= 'txid${DateTime.now().millisecondsSinceEpoch}';
|
txid ??= 'txid${DateTime.now().millisecondsSinceEpoch}';
|
||||||
return await client.api.sendMessage(
|
return await client.sendMessage(
|
||||||
id,
|
id,
|
||||||
EventTypes.CallAnswer,
|
EventTypes.CallAnswer,
|
||||||
txid,
|
txid,
|
||||||
|
@ -1425,7 +1425,7 @@ class Room {
|
||||||
Future<String> hangupCall(String callId,
|
Future<String> hangupCall(String callId,
|
||||||
{int version = 0, String txid}) async {
|
{int version = 0, String txid}) async {
|
||||||
txid ??= 'txid${DateTime.now().millisecondsSinceEpoch}';
|
txid ??= 'txid${DateTime.now().millisecondsSinceEpoch}';
|
||||||
return await client.api.sendMessage(
|
return await client.sendMessage(
|
||||||
id,
|
id,
|
||||||
EventTypes.CallHangup,
|
EventTypes.CallHangup,
|
||||||
txid,
|
txid,
|
||||||
|
@ -1461,7 +1461,7 @@ class Room {
|
||||||
|
|
||||||
/// Changes the join rules. You should check first if the user is able to change it.
|
/// Changes the join rules. You should check first if the user is able to change it.
|
||||||
Future<void> setJoinRules(JoinRules joinRules) async {
|
Future<void> setJoinRules(JoinRules joinRules) async {
|
||||||
await client.api.sendState(
|
await client.sendState(
|
||||||
id,
|
id,
|
||||||
EventTypes.RoomJoinRules,
|
EventTypes.RoomJoinRules,
|
||||||
{
|
{
|
||||||
|
@ -1486,7 +1486,7 @@ class Room {
|
||||||
|
|
||||||
/// Changes the guest access. You should check first if the user is able to change it.
|
/// Changes the guest access. You should check first if the user is able to change it.
|
||||||
Future<void> setGuestAccess(GuestAccess guestAccess) async {
|
Future<void> setGuestAccess(GuestAccess guestAccess) async {
|
||||||
await client.api.sendState(
|
await client.sendState(
|
||||||
id,
|
id,
|
||||||
EventTypes.GuestAccess,
|
EventTypes.GuestAccess,
|
||||||
{
|
{
|
||||||
|
@ -1512,7 +1512,7 @@ class Room {
|
||||||
|
|
||||||
/// Changes the history visibility. You should check first if the user is able to change it.
|
/// Changes the history visibility. You should check first if the user is able to change it.
|
||||||
Future<void> setHistoryVisibility(HistoryVisibility historyVisibility) async {
|
Future<void> setHistoryVisibility(HistoryVisibility historyVisibility) async {
|
||||||
await client.api.sendState(
|
await client.sendState(
|
||||||
id,
|
id,
|
||||||
EventTypes.HistoryVisibility,
|
EventTypes.HistoryVisibility,
|
||||||
{
|
{
|
||||||
|
@ -1539,7 +1539,7 @@ class Room {
|
||||||
Future<void> enableEncryption({int algorithmIndex = 0}) async {
|
Future<void> enableEncryption({int algorithmIndex = 0}) async {
|
||||||
if (encrypted) throw ('Encryption is already enabled!');
|
if (encrypted) throw ('Encryption is already enabled!');
|
||||||
final algorithm = Client.supportedGroupEncryptionAlgorithms[algorithmIndex];
|
final algorithm = Client.supportedGroupEncryptionAlgorithms[algorithmIndex];
|
||||||
await client.api.sendState(
|
await client.sendState(
|
||||||
id,
|
id,
|
||||||
EventTypes.Encryption,
|
EventTypes.Encryption,
|
||||||
{
|
{
|
||||||
|
|
|
@ -146,7 +146,7 @@ class User extends Event {
|
||||||
if (roomID != null) return roomID;
|
if (roomID != null) return roomID;
|
||||||
|
|
||||||
// Start a new direct chat
|
// Start a new direct chat
|
||||||
final newRoomID = await room.client.api.createRoom(
|
final newRoomID = await room.client.createRoom(
|
||||||
invite: [id],
|
invite: [id],
|
||||||
isDirect: true,
|
isDirect: true,
|
||||||
preset: CreateRoomPreset.trusted_private_chat,
|
preset: CreateRoomPreset.trusted_private_chat,
|
||||||
|
|
|
@ -22,8 +22,8 @@ import 'dart:core';
|
||||||
extension MxcUriExtension on Uri {
|
extension MxcUriExtension on Uri {
|
||||||
/// Returns a download Link to this content.
|
/// Returns a download Link to this content.
|
||||||
String getDownloadLink(Client matrix) => isScheme('mxc')
|
String getDownloadLink(Client matrix) => isScheme('mxc')
|
||||||
? matrix.api.homeserver != null
|
? matrix.homeserver != null
|
||||||
? '${matrix.api.homeserver.toString()}/_matrix/media/r0/download/$host$path'
|
? '${matrix.homeserver.toString()}/_matrix/media/r0/download/$host$path'
|
||||||
: ''
|
: ''
|
||||||
: toString();
|
: toString();
|
||||||
|
|
||||||
|
@ -36,8 +36,8 @@ extension MxcUriExtension on Uri {
|
||||||
final methodStr = method.toString().split('.').last;
|
final methodStr = method.toString().split('.').last;
|
||||||
width = width.round();
|
width = width.round();
|
||||||
height = height.round();
|
height = height.round();
|
||||||
return matrix.api.homeserver != null
|
return matrix.homeserver != null
|
||||||
? '${matrix.api.homeserver.toString()}/_matrix/media/r0/thumbnail/$host$path?width=$width&height=$height&method=$methodStr'
|
? '${matrix.homeserver.toString()}/_matrix/media/r0/thumbnail/$host$path?width=$width&height=$height&method=$methodStr'
|
||||||
: '';
|
: '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ void main() {
|
||||||
const fingerprintKey = 'gjL//fyaFHADt9KBADGag8g7F8Up78B/K1zXeiEPLJo';
|
const fingerprintKey = 'gjL//fyaFHADt9KBADGag8g7F8Up78B/K1zXeiEPLJo';
|
||||||
|
|
||||||
/// All Tests related to the Login
|
/// All Tests related to the Login
|
||||||
group('FluffyMatrix', () {
|
group('Client', () {
|
||||||
/// Check if all Elements get created
|
/// Check if all Elements get created
|
||||||
|
|
||||||
matrix = Client('testclient', httpClient: FakeMatrixApi());
|
matrix = Client('testclient', httpClient: FakeMatrixApi());
|
||||||
|
@ -74,7 +74,7 @@ void main() {
|
||||||
accountDataCounter++;
|
accountDataCounter++;
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(matrix.api.homeserver, null);
|
expect(matrix.homeserver, null);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await matrix.checkServer('https://fakeserver.wrongaddress');
|
await matrix.checkServer('https://fakeserver.wrongaddress');
|
||||||
|
@ -82,17 +82,9 @@ void main() {
|
||||||
expect(exception != null, true);
|
expect(exception != null, true);
|
||||||
}
|
}
|
||||||
await matrix.checkServer('https://fakeserver.notexisting');
|
await matrix.checkServer('https://fakeserver.notexisting');
|
||||||
expect(
|
expect(matrix.homeserver.toString(), 'https://fakeserver.notexisting');
|
||||||
matrix.api.homeserver.toString(), 'https://fakeserver.notexisting');
|
|
||||||
|
|
||||||
final resp = await matrix.api.login(
|
final available = await matrix.usernameAvailable('testuser');
|
||||||
type: 'm.login.password',
|
|
||||||
user: 'test',
|
|
||||||
password: '1234',
|
|
||||||
initialDeviceDisplayName: 'Fluffy Matrix Client',
|
|
||||||
);
|
|
||||||
|
|
||||||
final available = await matrix.api.usernameAvailable('testuser');
|
|
||||||
expect(available, true);
|
expect(available, true);
|
||||||
|
|
||||||
var loginStateFuture = matrix.onLoginStateChanged.stream.first;
|
var loginStateFuture = matrix.onLoginStateChanged.stream.first;
|
||||||
|
@ -100,21 +92,16 @@ void main() {
|
||||||
var syncFuture = matrix.onSync.stream.first;
|
var syncFuture = matrix.onSync.stream.first;
|
||||||
|
|
||||||
matrix.connect(
|
matrix.connect(
|
||||||
newToken: resp.accessToken,
|
newToken: 'abcd',
|
||||||
newUserID: resp.userId,
|
newUserID: '@test:fakeServer.notExisting',
|
||||||
newHomeserver: matrix.api.homeserver,
|
newHomeserver: matrix.homeserver,
|
||||||
newDeviceName: 'Text Matrix Client',
|
newDeviceName: 'Text Matrix Client',
|
||||||
newDeviceID: resp.deviceId,
|
newDeviceID: 'GHTYAJCE',
|
||||||
newOlmAccount: pickledOlmAccount,
|
newOlmAccount: pickledOlmAccount,
|
||||||
);
|
);
|
||||||
|
|
||||||
await Future.delayed(Duration(milliseconds: 50));
|
await Future.delayed(Duration(milliseconds: 50));
|
||||||
|
|
||||||
expect(matrix.api.accessToken == resp.accessToken, true);
|
|
||||||
expect(matrix.deviceName == 'Text Matrix Client', true);
|
|
||||||
expect(matrix.deviceID == resp.deviceId, true);
|
|
||||||
expect(matrix.userID == resp.userId, true);
|
|
||||||
|
|
||||||
var loginState = await loginStateFuture;
|
var loginState = await loginStateFuture;
|
||||||
var firstSync = await firstSyncFuture;
|
var firstSync = await firstSyncFuture;
|
||||||
var sync = await syncFuture;
|
var sync = await syncFuture;
|
||||||
|
@ -208,14 +195,11 @@ void main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Logout', () async {
|
test('Logout', () async {
|
||||||
await matrix.api.logout();
|
|
||||||
|
|
||||||
var loginStateFuture = matrix.onLoginStateChanged.stream.first;
|
var loginStateFuture = matrix.onLoginStateChanged.stream.first;
|
||||||
|
await matrix.logout();
|
||||||
|
|
||||||
matrix.clear();
|
expect(matrix.accessToken == null, true);
|
||||||
|
expect(matrix.homeserver == null, true);
|
||||||
expect(matrix.api.accessToken == null, true);
|
|
||||||
expect(matrix.api.homeserver == null, true);
|
|
||||||
expect(matrix.userID == null, true);
|
expect(matrix.userID == null, true);
|
||||||
expect(matrix.deviceID == null, true);
|
expect(matrix.deviceID == null, true);
|
||||||
expect(matrix.deviceName == null, true);
|
expect(matrix.deviceName == null, true);
|
||||||
|
@ -330,10 +314,10 @@ void main() {
|
||||||
final checkResp =
|
final checkResp =
|
||||||
await matrix.checkServer('https://fakeServer.notExisting');
|
await matrix.checkServer('https://fakeServer.notExisting');
|
||||||
|
|
||||||
final loginResp = await matrix.login('test', '1234');
|
final loginResp = await matrix.login(user: 'test', password: '1234');
|
||||||
|
|
||||||
expect(checkResp, true);
|
expect(checkResp, true);
|
||||||
expect(loginResp, true);
|
expect(loginResp != null, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('setAvatar', () async {
|
test('setAvatar', () async {
|
||||||
|
@ -386,8 +370,8 @@ void main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, matrix);
|
}, matrix);
|
||||||
test('sendToDevice', () async {
|
test('sendToDeviceEncrypted', () async {
|
||||||
await matrix.sendToDevice(
|
await matrix.sendToDeviceEncrypted(
|
||||||
[deviceKeys],
|
[deviceKeys],
|
||||||
'm.message',
|
'm.message',
|
||||||
{
|
{
|
||||||
|
@ -420,9 +404,9 @@ void main() {
|
||||||
await Future.delayed(Duration(milliseconds: 100));
|
await Future.delayed(Duration(milliseconds: 100));
|
||||||
|
|
||||||
expect(client2.isLogged(), true);
|
expect(client2.isLogged(), true);
|
||||||
expect(client2.api.accessToken, client1.api.accessToken);
|
expect(client2.accessToken, client1.accessToken);
|
||||||
expect(client2.userID, client1.userID);
|
expect(client2.userID, client1.userID);
|
||||||
expect(client2.api.homeserver, client1.api.homeserver);
|
expect(client2.homeserver, client1.homeserver);
|
||||||
expect(client2.deviceID, client1.deviceID);
|
expect(client2.deviceID, client1.deviceID);
|
||||||
expect(client2.deviceName, client1.deviceName);
|
expect(client2.deviceName, client1.deviceName);
|
||||||
if (client2.encryptionEnabled) {
|
if (client2.encryptionEnabled) {
|
||||||
|
|
|
@ -54,7 +54,7 @@ void main() {
|
||||||
otherClient.connect(
|
otherClient.connect(
|
||||||
newToken: 'abc',
|
newToken: 'abc',
|
||||||
newUserID: '@othertest:fakeServer.notExisting',
|
newUserID: '@othertest:fakeServer.notExisting',
|
||||||
newHomeserver: otherClient.api.homeserver,
|
newHomeserver: otherClient.homeserver,
|
||||||
newDeviceName: 'Text Matrix Client',
|
newDeviceName: 'Text Matrix Client',
|
||||||
newDeviceID: 'FOXDEVICE',
|
newDeviceID: 'FOXDEVICE',
|
||||||
newOlmAccount: otherPickledOlmAccount,
|
newOlmAccount: otherPickledOlmAccount,
|
||||||
|
|
|
@ -89,7 +89,7 @@ void main() {
|
||||||
client2.connect(
|
client2.connect(
|
||||||
newToken: 'abc',
|
newToken: 'abc',
|
||||||
newUserID: '@othertest:fakeServer.notExisting',
|
newUserID: '@othertest:fakeServer.notExisting',
|
||||||
newHomeserver: client2.api.homeserver,
|
newHomeserver: client2.homeserver,
|
||||||
newDeviceName: 'Text Matrix Client',
|
newDeviceName: 'Text Matrix Client',
|
||||||
newDeviceID: 'FOXDEVICE',
|
newDeviceID: 'FOXDEVICE',
|
||||||
newOlmAccount: otherPickledOlmAccount,
|
newOlmAccount: otherPickledOlmAccount,
|
||||||
|
|
|
@ -246,7 +246,7 @@ void main() {
|
||||||
test('sendAgain', () async {
|
test('sendAgain', () async {
|
||||||
var matrix = Client('testclient', httpClient: FakeMatrixApi());
|
var matrix = Client('testclient', httpClient: FakeMatrixApi());
|
||||||
await matrix.checkServer('https://fakeServer.notExisting');
|
await matrix.checkServer('https://fakeServer.notExisting');
|
||||||
await matrix.login('test', '1234');
|
await matrix.login(user: 'test', password: '1234');
|
||||||
|
|
||||||
var event = Event.fromJson(
|
var event = Event.fromJson(
|
||||||
jsonObj, Room(id: '!1234:example.com', client: matrix));
|
jsonObj, Room(id: '!1234:example.com', client: matrix));
|
||||||
|
@ -262,7 +262,7 @@ void main() {
|
||||||
test('requestKey', () async {
|
test('requestKey', () async {
|
||||||
var matrix = Client('testclient', httpClient: FakeMatrixApi());
|
var matrix = Client('testclient', httpClient: FakeMatrixApi());
|
||||||
await matrix.checkServer('https://fakeServer.notExisting');
|
await matrix.checkServer('https://fakeServer.notExisting');
|
||||||
await matrix.login('test', '1234');
|
await matrix.login(user: 'test', password: '1234');
|
||||||
|
|
||||||
var event = Event.fromJson(
|
var event = Event.fromJson(
|
||||||
jsonObj, Room(id: '!1234:example.com', client: matrix));
|
jsonObj, Room(id: '!1234:example.com', client: matrix));
|
||||||
|
|
|
@ -32,18 +32,12 @@ Future<Client> getClient() async {
|
||||||
final client = Client('testclient', httpClient: FakeMatrixApi());
|
final client = Client('testclient', httpClient: FakeMatrixApi());
|
||||||
client.database = getDatabase();
|
client.database = getDatabase();
|
||||||
await client.checkServer('https://fakeServer.notExisting');
|
await client.checkServer('https://fakeServer.notExisting');
|
||||||
final resp = await client.api.login(
|
|
||||||
type: 'm.login.password',
|
|
||||||
user: 'test',
|
|
||||||
password: '1234',
|
|
||||||
initialDeviceDisplayName: 'Fluffy Matrix Client',
|
|
||||||
);
|
|
||||||
client.connect(
|
client.connect(
|
||||||
newToken: resp.accessToken,
|
newToken: 'abcd',
|
||||||
newUserID: resp.userId,
|
newUserID: '@test:fakeServer.notExisting',
|
||||||
newHomeserver: client.api.homeserver,
|
newHomeserver: client.homeserver,
|
||||||
newDeviceName: 'Text Matrix Client',
|
newDeviceName: 'Text Matrix Client',
|
||||||
newDeviceID: resp.deviceId,
|
newDeviceID: 'GHTYAJCE',
|
||||||
newOlmAccount: pickledOlmAccount,
|
newOlmAccount: pickledOlmAccount,
|
||||||
);
|
);
|
||||||
await Future.delayed(Duration(milliseconds: 10));
|
await Future.delayed(Duration(milliseconds: 10));
|
||||||
|
|
|
@ -82,6 +82,10 @@ class FakeMatrixApi extends MockClient {
|
||||||
action.contains(
|
action.contains(
|
||||||
'/client/r0/rooms/!1234%3AfakeServer.notExisting/send/')) {
|
'/client/r0/rooms/!1234%3AfakeServer.notExisting/send/')) {
|
||||||
res = {'event_id': '\$event${FakeMatrixApi.eventCounter++}'};
|
res = {'event_id': '\$event${FakeMatrixApi.eventCounter++}'};
|
||||||
|
} else if (action.contains('/client/r0/sync')) {
|
||||||
|
res = {
|
||||||
|
'next_batch': DateTime.now().millisecondsSinceEpoch.toString
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
res = {
|
res = {
|
||||||
'errcode': 'M_UNRECOGNIZED',
|
'errcode': 'M_UNRECOGNIZED',
|
||||||
|
|
|
@ -33,13 +33,13 @@ void main() {
|
||||||
expect(content.isScheme('mxc'), true);
|
expect(content.isScheme('mxc'), true);
|
||||||
|
|
||||||
expect(content.getDownloadLink(client),
|
expect(content.getDownloadLink(client),
|
||||||
'${client.api.homeserver.toString()}/_matrix/media/r0/download/exampleserver.abc/abcdefghijklmn');
|
'${client.homeserver.toString()}/_matrix/media/r0/download/exampleserver.abc/abcdefghijklmn');
|
||||||
expect(content.getThumbnail(client, width: 50, height: 50),
|
expect(content.getThumbnail(client, width: 50, height: 50),
|
||||||
'${client.api.homeserver.toString()}/_matrix/media/r0/thumbnail/exampleserver.abc/abcdefghijklmn?width=50&height=50&method=crop');
|
'${client.homeserver.toString()}/_matrix/media/r0/thumbnail/exampleserver.abc/abcdefghijklmn?width=50&height=50&method=crop');
|
||||||
expect(
|
expect(
|
||||||
content.getThumbnail(client,
|
content.getThumbnail(client,
|
||||||
width: 50, height: 50, method: ThumbnailMethod.scale),
|
width: 50, height: 50, method: ThumbnailMethod.scale),
|
||||||
'${client.api.homeserver.toString()}/_matrix/media/r0/thumbnail/exampleserver.abc/abcdefghijklmn?width=50&height=50&method=scale');
|
'${client.homeserver.toString()}/_matrix/media/r0/thumbnail/exampleserver.abc/abcdefghijklmn?width=50&height=50&method=scale');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,7 +102,7 @@ void main() {
|
||||||
});
|
});
|
||||||
test('startDirectChat', () async {
|
test('startDirectChat', () async {
|
||||||
await client.checkServer('https://fakeserver.notexisting');
|
await client.checkServer('https://fakeserver.notexisting');
|
||||||
await client.login('test', '1234');
|
await client.login(user: 'test', password: '1234');
|
||||||
await user1.startDirectChat();
|
await user1.startDirectChat();
|
||||||
});
|
});
|
||||||
test('getPresence', () async {
|
test('getPresence', () async {
|
||||||
|
|
|
@ -22,14 +22,14 @@ void test() async {
|
||||||
var testClientA = Client('TestClientA');
|
var testClientA = Client('TestClientA');
|
||||||
testClientA.database = getDatabase();
|
testClientA.database = getDatabase();
|
||||||
await testClientA.checkServer(homeserver);
|
await testClientA.checkServer(homeserver);
|
||||||
await testClientA.login(testUserA, testPasswordA);
|
await testClientA.login(user: testUserA, password: testPasswordA);
|
||||||
assert(testClientA.encryptionEnabled);
|
assert(testClientA.encryptionEnabled);
|
||||||
|
|
||||||
Logs.success('++++ Login $testUserB ++++');
|
Logs.success('++++ Login $testUserB ++++');
|
||||||
var testClientB = Client('TestClientB');
|
var testClientB = Client('TestClientB');
|
||||||
testClientB.database = getDatabase();
|
testClientB.database = getDatabase();
|
||||||
await testClientB.checkServer(homeserver);
|
await testClientB.checkServer(homeserver);
|
||||||
await testClientB.login(testUserB, testPasswordA);
|
await testClientB.login(user: testUserB, password: testPasswordA);
|
||||||
assert(testClientB.encryptionEnabled);
|
assert(testClientB.encryptionEnabled);
|
||||||
|
|
||||||
Logs.success('++++ ($testUserA) Leave all rooms ++++');
|
Logs.success('++++ ($testUserA) Leave all rooms ++++');
|
||||||
|
@ -72,7 +72,7 @@ void test() async {
|
||||||
.userDeviceKeys[testUserB].deviceKeys[testClientB.deviceID].blocked);
|
.userDeviceKeys[testUserB].deviceKeys[testClientB.deviceID].blocked);
|
||||||
|
|
||||||
Logs.success('++++ ($testUserA) Create room and invite $testUserB ++++');
|
Logs.success('++++ ($testUserA) Create room and invite $testUserB ++++');
|
||||||
await testClientA.api.createRoom(invite: [testUserB]);
|
await testClientA.createRoom(invite: [testUserB]);
|
||||||
await Future.delayed(Duration(seconds: 1));
|
await Future.delayed(Duration(seconds: 1));
|
||||||
var room = testClientA.rooms.first;
|
var room = testClientA.rooms.first;
|
||||||
assert(room != null);
|
assert(room != null);
|
||||||
|
@ -217,7 +217,7 @@ void test() async {
|
||||||
Logs.success('++++ Login $testUserB in another client ++++');
|
Logs.success('++++ Login $testUserB in another client ++++');
|
||||||
var testClientC = Client('TestClientC', database: getDatabase());
|
var testClientC = Client('TestClientC', database: getDatabase());
|
||||||
await testClientC.checkServer(homeserver);
|
await testClientC.checkServer(homeserver);
|
||||||
await testClientC.login(testUserB, testPasswordA);
|
await testClientC.login(user: testUserB, password: testPasswordA);
|
||||||
await Future.delayed(Duration(seconds: 3));
|
await Future.delayed(Duration(seconds: 3));
|
||||||
|
|
||||||
Logs.success(
|
Logs.success(
|
||||||
|
@ -346,8 +346,8 @@ void test() async {
|
||||||
await Future.delayed(Duration(seconds: 1));
|
await Future.delayed(Duration(seconds: 1));
|
||||||
await testClientA.dispose();
|
await testClientA.dispose();
|
||||||
await testClientB.dispose();
|
await testClientB.dispose();
|
||||||
await testClientA.api.logoutAll();
|
await testClientA.logoutAll();
|
||||||
await testClientB.api.logoutAll();
|
await testClientB.logoutAll();
|
||||||
testClientA = null;
|
testClientA = null;
|
||||||
testClientB = null;
|
testClientB = null;
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Reference in a new issue