refactor: Follow up clean up bootstrap
This commit is contained in:
parent
b563aec7bb
commit
6657e073a0
|
|
@ -29,19 +29,44 @@ import '../../famedlysdk.dart';
|
||||||
import '../../matrix_api/utils/logs.dart';
|
import '../../matrix_api/utils/logs.dart';
|
||||||
|
|
||||||
enum BootstrapState {
|
enum BootstrapState {
|
||||||
loading, // loading
|
/// Is loading.
|
||||||
askWipeSsss, // existing SSSS found, should we wipe it?
|
loading,
|
||||||
askUseExistingSsss, // ask if an existing SSSS should be userDeviceKeys
|
|
||||||
askBadSsss, // SSSS is in a bad state, continue with potential dataloss?
|
/// Existing SSSS found, should we wipe it?
|
||||||
askUnlockSsss, // Ask to unlock all the SSSS keys
|
askWipeSsss,
|
||||||
askNewSsss, // Ask for new SSSS key / passphrase
|
|
||||||
openExistingSsss, // Open an existing SSSS key
|
/// Ask if an existing SSSS should be userDeviceKeys
|
||||||
askWipeCrossSigning, // Ask if cross signing should be wiped
|
askUseExistingSsss,
|
||||||
askSetupCrossSigning, // Ask if cross signing should be set up
|
|
||||||
askWipeOnlineKeyBackup, // Ask if online key backup should be wiped
|
/// Ask to unlock all the SSSS keys
|
||||||
askSetupOnlineKeyBackup, // Ask if the online key backup should be set up
|
askUnlockSsss,
|
||||||
error, // error
|
|
||||||
done, // done
|
/// SSSS is in a bad state, continue with potential dataloss?
|
||||||
|
askBadSsss,
|
||||||
|
|
||||||
|
/// Ask for new SSSS key / passphrase
|
||||||
|
askNewSsss,
|
||||||
|
|
||||||
|
/// Open an existing SSSS key
|
||||||
|
openExistingSsss,
|
||||||
|
|
||||||
|
/// Ask if cross signing should be wiped
|
||||||
|
askWipeCrossSigning,
|
||||||
|
|
||||||
|
/// Ask if cross signing should be set up
|
||||||
|
askSetupCrossSigning,
|
||||||
|
|
||||||
|
/// Ask if online key backup should be wiped
|
||||||
|
askWipeOnlineKeyBackup,
|
||||||
|
|
||||||
|
/// Ask if the online key backup should be set up
|
||||||
|
askSetupOnlineKeyBackup,
|
||||||
|
|
||||||
|
/// An error has been occured.
|
||||||
|
error,
|
||||||
|
|
||||||
|
/// done
|
||||||
|
done,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bootstrapping SSSS and cross-signing
|
/// Bootstrapping SSSS and cross-signing
|
||||||
|
|
@ -425,8 +450,9 @@ class Bootstrap {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// upload the keys!
|
// upload the keys!
|
||||||
|
state = BootstrapState.loading;
|
||||||
await client.uiaRequestBackground(
|
await client.uiaRequestBackground(
|
||||||
(Map<String, dynamic> auth) => client.uploadDeviceSigningKeys(
|
(AuthenticationData auth) => client.uploadDeviceSigningKeys(
|
||||||
masterKey: masterKey,
|
masterKey: masterKey,
|
||||||
selfSigningKey: selfSigningKey,
|
selfSigningKey: selfSigningKey,
|
||||||
userSigningKey: userSigningKey,
|
userSigningKey: userSigningKey,
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,16 @@ export 'matrix_api/model/upload_key_signatures_response.dart';
|
||||||
export 'matrix_api/model/user_search_result.dart';
|
export 'matrix_api/model/user_search_result.dart';
|
||||||
export 'matrix_api/model/well_known_informations.dart';
|
export 'matrix_api/model/well_known_informations.dart';
|
||||||
export 'matrix_api/model/who_is_info.dart';
|
export 'matrix_api/model/who_is_info.dart';
|
||||||
|
export 'matrix_api/model/auth/authentication_data.dart';
|
||||||
|
export 'matrix_api/model/auth/authentication_identifier.dart';
|
||||||
|
export 'matrix_api/model/auth/authentication_password.dart';
|
||||||
|
export 'matrix_api/model/auth/authentication_phone_identifier.dart';
|
||||||
|
export 'matrix_api/model/auth/authentication_recaptcha.dart';
|
||||||
|
export 'matrix_api/model/auth/authentication_third_party_identifier.dart';
|
||||||
|
export 'matrix_api/model/auth/authentication_three_pid_creds.dart';
|
||||||
|
export 'matrix_api/model/auth/authentication_token.dart';
|
||||||
|
export 'matrix_api/model/auth/authentication_types.dart';
|
||||||
|
export 'matrix_api/model/auth/authentication_user_identifier.dart';
|
||||||
export 'matrix_api/model/events/secret_storage_default_key_content.dart';
|
export 'matrix_api/model/events/secret_storage_default_key_content.dart';
|
||||||
export 'matrix_api/model/events/secret_storage_key_content.dart';
|
export 'matrix_api/model/events/secret_storage_key_content.dart';
|
||||||
export 'matrix_api/model/events/tombstone_content.dart';
|
export 'matrix_api/model/events/tombstone_content.dart';
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,12 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:famedlysdk/famedlysdk.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:mime/mime.dart';
|
import 'package:mime/mime.dart';
|
||||||
import 'package:moor/moor.dart';
|
import 'package:moor/moor.dart';
|
||||||
|
|
||||||
|
import 'model/auth/authentication_types.dart';
|
||||||
import 'model/device.dart';
|
import 'model/device.dart';
|
||||||
import 'model/event_context.dart';
|
import 'model/event_context.dart';
|
||||||
import 'model/events_sync_update.dart';
|
import 'model/events_sync_update.dart';
|
||||||
|
|
@ -247,7 +249,7 @@ class MatrixApi {
|
||||||
/// Authenticates the user, and issues an access token they can use to authorize themself in subsequent requests.
|
/// Authenticates the user, and issues an access token they can use to authorize themself in subsequent requests.
|
||||||
/// https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-login
|
/// https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-login
|
||||||
Future<LoginResponse> login({
|
Future<LoginResponse> login({
|
||||||
String type = 'm.login.password',
|
String type = AuthenticationTypes.password,
|
||||||
String userIdentifierType,
|
String userIdentifierType,
|
||||||
String user,
|
String user,
|
||||||
String medium,
|
String medium,
|
||||||
|
|
@ -256,7 +258,7 @@ class MatrixApi {
|
||||||
String token,
|
String token,
|
||||||
String deviceId,
|
String deviceId,
|
||||||
String initialDeviceDisplayName,
|
String initialDeviceDisplayName,
|
||||||
Map<String, dynamic> auth,
|
AuthenticationData auth,
|
||||||
}) async {
|
}) async {
|
||||||
final response = await request(RequestType.POST, '/client/r0/login', data: {
|
final response = await request(RequestType.POST, '/client/r0/login', data: {
|
||||||
'type': type,
|
'type': type,
|
||||||
|
|
@ -272,7 +274,7 @@ class MatrixApi {
|
||||||
if (deviceId != null) 'device_id': deviceId,
|
if (deviceId != null) 'device_id': deviceId,
|
||||||
if (initialDeviceDisplayName != null)
|
if (initialDeviceDisplayName != null)
|
||||||
'initial_device_display_name': initialDeviceDisplayName,
|
'initial_device_display_name': initialDeviceDisplayName,
|
||||||
if (auth != null) 'auth': auth,
|
if (auth != null) 'auth': auth.toJson(),
|
||||||
});
|
});
|
||||||
return LoginResponse.fromJson(response);
|
return LoginResponse.fromJson(response);
|
||||||
}
|
}
|
||||||
|
|
@ -302,13 +304,25 @@ class MatrixApi {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Register for an account on this homeserver.
|
||||||
|
///
|
||||||
|
/// There are two kinds of user account:
|
||||||
|
///
|
||||||
|
/// user accounts. These accounts may use the full API described in this
|
||||||
|
/// specification.
|
||||||
|
/// guest accounts. These accounts may have limited permissions and may not
|
||||||
|
/// be supported by all servers.
|
||||||
|
///
|
||||||
|
/// If registration is successful, this endpoint will issue an access token
|
||||||
|
/// the client can use to authorize itself in subsequent requests.
|
||||||
|
/// https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-register
|
||||||
Future<LoginResponse> register({
|
Future<LoginResponse> register({
|
||||||
String username,
|
String username,
|
||||||
String password,
|
String password,
|
||||||
String deviceId,
|
String deviceId,
|
||||||
String initialDeviceDisplayName,
|
String initialDeviceDisplayName,
|
||||||
bool inhibitLogin,
|
bool inhibitLogin,
|
||||||
Map<String, dynamic> auth,
|
AuthenticationData auth,
|
||||||
String kind,
|
String kind,
|
||||||
}) async {
|
}) async {
|
||||||
var action = '/client/r0/register';
|
var action = '/client/r0/register';
|
||||||
|
|
@ -320,7 +334,7 @@ class MatrixApi {
|
||||||
if (initialDeviceDisplayName != null)
|
if (initialDeviceDisplayName != null)
|
||||||
'initial_device_display_name': initialDeviceDisplayName,
|
'initial_device_display_name': initialDeviceDisplayName,
|
||||||
if (inhibitLogin != null) 'inhibit_login': inhibitLogin,
|
if (inhibitLogin != null) 'inhibit_login': inhibitLogin,
|
||||||
if (auth != null) 'auth': auth,
|
if (auth != null) 'auth': auth.toJson(),
|
||||||
});
|
});
|
||||||
return LoginResponse.fromJson(response);
|
return LoginResponse.fromJson(response);
|
||||||
}
|
}
|
||||||
|
|
@ -382,11 +396,11 @@ class MatrixApi {
|
||||||
/// https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-account-password
|
/// https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-account-password
|
||||||
Future<void> changePassword(
|
Future<void> changePassword(
|
||||||
String newPassword, {
|
String newPassword, {
|
||||||
Map<String, dynamic> auth,
|
AuthenticationData auth,
|
||||||
}) async {
|
}) async {
|
||||||
await request(RequestType.POST, '/client/r0/account/password', data: {
|
await request(RequestType.POST, '/client/r0/account/password', data: {
|
||||||
'new_password': newPassword,
|
'new_password': newPassword,
|
||||||
if (auth != null) 'auth': auth,
|
if (auth != null) 'auth': auth.toJson(),
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -443,14 +457,15 @@ class MatrixApi {
|
||||||
return RequestTokenResponse.fromJson(response);
|
return RequestTokenResponse.fromJson(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-account-deactivate
|
||||||
Future<IdServerUnbindResult> deactivateAccount({
|
Future<IdServerUnbindResult> deactivateAccount({
|
||||||
String idServer,
|
String idServer,
|
||||||
Map<String, dynamic> auth,
|
AuthenticationData auth,
|
||||||
}) async {
|
}) async {
|
||||||
final response =
|
final response =
|
||||||
await request(RequestType.POST, '/client/r0/account/deactivate', data: {
|
await request(RequestType.POST, '/client/r0/account/deactivate', data: {
|
||||||
if (idServer != null) 'id_server': idServer,
|
if (idServer != null) 'id_server': idServer,
|
||||||
if (auth != null) 'auth': auth,
|
if (auth != null) 'auth': auth.toJson(),
|
||||||
});
|
});
|
||||||
|
|
||||||
return IdServerUnbindResult.values.firstWhere(
|
return IdServerUnbindResult.values.firstWhere(
|
||||||
|
|
@ -486,12 +501,12 @@ class MatrixApi {
|
||||||
Future<void> addThirdPartyIdentifier(
|
Future<void> addThirdPartyIdentifier(
|
||||||
String clientSecret,
|
String clientSecret,
|
||||||
String sid, {
|
String sid, {
|
||||||
Map<String, dynamic> auth,
|
AuthenticationData auth,
|
||||||
}) async {
|
}) async {
|
||||||
await request(RequestType.POST, '/client/r0/account/3pid/add', data: {
|
await request(RequestType.POST, '/client/r0/account/3pid/add', data: {
|
||||||
'sid': sid,
|
'sid': sid,
|
||||||
'client_secret': clientSecret,
|
'client_secret': clientSecret,
|
||||||
if (auth != null && auth.isNotEmpty) 'auth': auth,
|
if (auth != null) 'auth': auth.toJson(),
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1381,12 +1396,11 @@ class MatrixApi {
|
||||||
|
|
||||||
/// Deletes the given device, and invalidates any access token associated with it.
|
/// Deletes the given device, and invalidates any access token associated with it.
|
||||||
/// https://matrix.org/docs/spec/client_server/r0.6.1#delete-matrix-client-r0-devices-deviceid
|
/// https://matrix.org/docs/spec/client_server/r0.6.1#delete-matrix-client-r0-devices-deviceid
|
||||||
Future<void> deleteDevice(String deviceId,
|
Future<void> deleteDevice(String deviceId, {AuthenticationData auth}) async {
|
||||||
{Map<String, dynamic> auth}) async {
|
|
||||||
await request(RequestType.DELETE,
|
await request(RequestType.DELETE,
|
||||||
'/client/r0/devices/${Uri.encodeComponent(deviceId)}',
|
'/client/r0/devices/${Uri.encodeComponent(deviceId)}',
|
||||||
data: {
|
data: {
|
||||||
if (auth != null) 'auth': auth,
|
if (auth != null) 'auth': auth.toJson(),
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1394,10 +1408,10 @@ class MatrixApi {
|
||||||
/// Deletes the given devices, and invalidates any access token associated with them.
|
/// Deletes the given devices, and invalidates any access token associated with them.
|
||||||
/// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-delete-devices
|
/// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-delete-devices
|
||||||
Future<void> deleteDevices(List<String> deviceIds,
|
Future<void> deleteDevices(List<String> deviceIds,
|
||||||
{Map<String, dynamic> auth}) async {
|
{AuthenticationData auth}) async {
|
||||||
await request(RequestType.POST, '/client/r0/delete_devices', data: {
|
await request(RequestType.POST, '/client/r0/delete_devices', data: {
|
||||||
'devices': deviceIds,
|
'devices': deviceIds,
|
||||||
if (auth != null) 'auth': auth,
|
if (auth != null) 'auth': auth.toJson(),
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1470,7 +1484,7 @@ class MatrixApi {
|
||||||
MatrixCrossSigningKey masterKey,
|
MatrixCrossSigningKey masterKey,
|
||||||
MatrixCrossSigningKey selfSigningKey,
|
MatrixCrossSigningKey selfSigningKey,
|
||||||
MatrixCrossSigningKey userSigningKey,
|
MatrixCrossSigningKey userSigningKey,
|
||||||
Map<String, dynamic> auth,
|
AuthenticationData auth,
|
||||||
}) async {
|
}) async {
|
||||||
await request(
|
await request(
|
||||||
RequestType.POST,
|
RequestType.POST,
|
||||||
|
|
@ -1479,7 +1493,7 @@ class MatrixApi {
|
||||||
if (masterKey != null) 'master_key': masterKey.toJson(),
|
if (masterKey != null) 'master_key': masterKey.toJson(),
|
||||||
if (selfSigningKey != null) 'self_signing_key': selfSigningKey.toJson(),
|
if (selfSigningKey != null) 'self_signing_key': selfSigningKey.toJson(),
|
||||||
if (userSigningKey != null) 'user_signing_key': userSigningKey.toJson(),
|
if (userSigningKey != null) 'user_signing_key': userSigningKey.toJson(),
|
||||||
if (auth != null) 'auth': auth,
|
if (auth != null) 'auth': auth.toJson(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Famedly Matrix SDK
|
||||||
|
* Copyright (C) 2019, 2020 Famedly GmbH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class AuthenticationData {
|
||||||
|
String type;
|
||||||
|
String session;
|
||||||
|
|
||||||
|
AuthenticationData({this.type, this.session});
|
||||||
|
|
||||||
|
AuthenticationData.fromJson(Map<String, dynamic> json) {
|
||||||
|
type = json['type'];
|
||||||
|
session = json['session'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final data = <String, dynamic>{};
|
||||||
|
data['type'] = type;
|
||||||
|
data['session'] = session;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Famedly Matrix SDK
|
||||||
|
* Copyright (C) 2019, 2020 Famedly GmbH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class AuthenticationIdentifier {
|
||||||
|
String type;
|
||||||
|
|
||||||
|
AuthenticationIdentifier({this.type});
|
||||||
|
|
||||||
|
AuthenticationIdentifier.fromJson(Map<String, dynamic> json) {
|
||||||
|
type = json['type'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final data = <String, dynamic>{};
|
||||||
|
data['type'] = type;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* Famedly Matrix SDK
|
||||||
|
* Copyright (C) 2019, 2020 Famedly GmbH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import 'package:famedlysdk/matrix_api/model/auth/authentication_user_identifier.dart';
|
||||||
|
|
||||||
|
import 'authentication_data.dart';
|
||||||
|
import 'authentication_identifier.dart';
|
||||||
|
import 'authentication_phone_identifier.dart';
|
||||||
|
import 'authentication_third_party_identifier.dart';
|
||||||
|
import 'authentication_types.dart';
|
||||||
|
|
||||||
|
class AuthenticationPassword extends AuthenticationData {
|
||||||
|
String user;
|
||||||
|
String password;
|
||||||
|
|
||||||
|
/// You may want to cast this as [AuthenticationUserIdentifier] or other
|
||||||
|
/// Identifier classes extending AuthenticationIdentifier.
|
||||||
|
AuthenticationIdentifier identifier;
|
||||||
|
|
||||||
|
AuthenticationPassword(
|
||||||
|
{String session, this.password, this.user, this.identifier})
|
||||||
|
: super(
|
||||||
|
type: AuthenticationTypes.password,
|
||||||
|
session: session,
|
||||||
|
);
|
||||||
|
|
||||||
|
AuthenticationPassword.fromJson(Map<String, dynamic> json)
|
||||||
|
: super.fromJson(json) {
|
||||||
|
user = json['user'];
|
||||||
|
password = json['password'];
|
||||||
|
identifier = AuthenticationIdentifier.fromJson(json['identifier']);
|
||||||
|
switch (identifier.type) {
|
||||||
|
case AuthenticationIdentifierTypes.userId:
|
||||||
|
identifier = AuthenticationUserIdentifier.fromJson(json['identifier']);
|
||||||
|
break;
|
||||||
|
case AuthenticationIdentifierTypes.phone:
|
||||||
|
identifier = AuthenticationPhoneIdentifier.fromJson(json['identifier']);
|
||||||
|
break;
|
||||||
|
case AuthenticationIdentifierTypes.thirdParty:
|
||||||
|
identifier =
|
||||||
|
AuthenticationThirdPartyIdentifier.fromJson(json['identifier']);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final data = super.toJson();
|
||||||
|
if (user != null) data['user'] = user;
|
||||||
|
data['password'] = password;
|
||||||
|
switch (identifier.type) {
|
||||||
|
case AuthenticationIdentifierTypes.userId:
|
||||||
|
data['identifier'] =
|
||||||
|
(identifier as AuthenticationUserIdentifier).toJson();
|
||||||
|
break;
|
||||||
|
case AuthenticationIdentifierTypes.phone:
|
||||||
|
data['identifier'] =
|
||||||
|
(identifier as AuthenticationPhoneIdentifier).toJson();
|
||||||
|
break;
|
||||||
|
case AuthenticationIdentifierTypes.thirdParty:
|
||||||
|
data['identifier'] =
|
||||||
|
(identifier as AuthenticationThirdPartyIdentifier).toJson();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
data['identifier'] = identifier.toJson();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Famedly Matrix SDK
|
||||||
|
* Copyright (C) 2019, 2020 Famedly GmbH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import 'authentication_identifier.dart';
|
||||||
|
import 'authentication_types.dart';
|
||||||
|
|
||||||
|
class AuthenticationPhoneIdentifier extends AuthenticationIdentifier {
|
||||||
|
String country;
|
||||||
|
String phone;
|
||||||
|
|
||||||
|
AuthenticationPhoneIdentifier({this.country, this.phone})
|
||||||
|
: super(type: AuthenticationIdentifierTypes.phone);
|
||||||
|
|
||||||
|
AuthenticationPhoneIdentifier.fromJson(Map<String, dynamic> json)
|
||||||
|
: super.fromJson(json) {
|
||||||
|
country = json['country'];
|
||||||
|
phone = json['phone'];
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final data = super.toJson();
|
||||||
|
data['country'] = country;
|
||||||
|
data['phone'] = phone;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Famedly Matrix SDK
|
||||||
|
* Copyright (C) 2019, 2020 Famedly GmbH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import 'authentication_data.dart';
|
||||||
|
import 'authentication_types.dart';
|
||||||
|
|
||||||
|
class AuthenticationRecaptcha extends AuthenticationData {
|
||||||
|
String response;
|
||||||
|
|
||||||
|
AuthenticationRecaptcha({String session, this.response})
|
||||||
|
: super(
|
||||||
|
type: AuthenticationTypes.recaptcha,
|
||||||
|
session: session,
|
||||||
|
);
|
||||||
|
|
||||||
|
AuthenticationRecaptcha.fromJson(Map<String, dynamic> json)
|
||||||
|
: super.fromJson(json) {
|
||||||
|
response = json['response'];
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final data = super.toJson();
|
||||||
|
data['response'] = response;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Famedly Matrix SDK
|
||||||
|
* Copyright (C) 2019, 2020 Famedly GmbH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import 'authentication_identifier.dart';
|
||||||
|
import 'authentication_types.dart';
|
||||||
|
|
||||||
|
class AuthenticationThirdPartyIdentifier extends AuthenticationIdentifier {
|
||||||
|
String medium;
|
||||||
|
String address;
|
||||||
|
|
||||||
|
AuthenticationThirdPartyIdentifier({this.medium, this.address})
|
||||||
|
: super(type: AuthenticationIdentifierTypes.thirdParty);
|
||||||
|
|
||||||
|
AuthenticationThirdPartyIdentifier.fromJson(Map<String, dynamic> json)
|
||||||
|
: super.fromJson(json) {
|
||||||
|
medium = json['medium'];
|
||||||
|
address = json['address'];
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final data = super.toJson();
|
||||||
|
data['medium'] = medium;
|
||||||
|
data['address'] = address;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* Famedly Matrix SDK
|
||||||
|
* Copyright (C) 2019, 2020 Famedly GmbH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import 'authentication_data.dart';
|
||||||
|
|
||||||
|
/// For email based identity:
|
||||||
|
/// https://matrix.org/docs/spec/client_server/r0.6.1#email-based-identity-homeserver
|
||||||
|
/// Or phone number based identity:
|
||||||
|
/// https://matrix.org/docs/spec/client_server/r0.6.1#phone-number-msisdn-based-identity-homeserver
|
||||||
|
class AuthenticationThreePidCreds extends AuthenticationData {
|
||||||
|
List<ThreepidCreds> threepidCreds;
|
||||||
|
|
||||||
|
AuthenticationThreePidCreds({String session, String type, this.threepidCreds})
|
||||||
|
: super(
|
||||||
|
type: type,
|
||||||
|
session: session,
|
||||||
|
);
|
||||||
|
|
||||||
|
AuthenticationThreePidCreds.fromJson(Map<String, dynamic> json)
|
||||||
|
: super.fromJson(json) {
|
||||||
|
if (json['threepidCreds'] != null) {
|
||||||
|
threepidCreds = (json['threepidCreds'] as List)
|
||||||
|
.map((item) => ThreepidCreds.fromJson(item))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is so extremly stupid... kill it with fire!
|
||||||
|
if (json['threepid_creds'] != null) {
|
||||||
|
threepidCreds = (json['threepid_creds'] as List)
|
||||||
|
.map((item) => ThreepidCreds.fromJson(item))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final data = super.toJson();
|
||||||
|
data['threepidCreds'] = threepidCreds.map((t) => t.toJson()).toList();
|
||||||
|
// Help me! I'm prisoned in a developer factory against my will,
|
||||||
|
// where we are forced to work with json like this!!
|
||||||
|
data['threepid_creds'] = threepidCreds.map((t) => t.toJson()).toList();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ThreepidCreds {
|
||||||
|
String sid;
|
||||||
|
String clientSecret;
|
||||||
|
String idServer;
|
||||||
|
String idAccessToken;
|
||||||
|
|
||||||
|
ThreepidCreds(
|
||||||
|
{this.sid, this.clientSecret, this.idServer, this.idAccessToken});
|
||||||
|
|
||||||
|
ThreepidCreds.fromJson(Map<String, dynamic> json) {
|
||||||
|
sid = json['sid'];
|
||||||
|
clientSecret = json['client_secret'];
|
||||||
|
idServer = json['id_server'];
|
||||||
|
idAccessToken = json['id_access_token'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final data = <String, dynamic>{};
|
||||||
|
data['sid'] = sid;
|
||||||
|
data['client_secret'] = clientSecret;
|
||||||
|
data['id_server'] = idServer;
|
||||||
|
data['id_access_token'] = idAccessToken;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* Famedly Matrix SDK
|
||||||
|
* Copyright (C) 2019, 2020 Famedly GmbH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import 'authentication_data.dart';
|
||||||
|
import 'authentication_types.dart';
|
||||||
|
|
||||||
|
class AuthenticationToken extends AuthenticationData {
|
||||||
|
String token;
|
||||||
|
String txnId;
|
||||||
|
|
||||||
|
AuthenticationToken({String session, this.token, this.txnId})
|
||||||
|
: super(
|
||||||
|
type: AuthenticationTypes.token,
|
||||||
|
session: session,
|
||||||
|
);
|
||||||
|
|
||||||
|
AuthenticationToken.fromJson(Map<String, dynamic> json)
|
||||||
|
: super.fromJson(json) {
|
||||||
|
token = json['token'];
|
||||||
|
txnId = json['txn_id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final data = super.toJson();
|
||||||
|
data['token'] = token;
|
||||||
|
data['txn_id'] = txnId;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Famedly Matrix SDK
|
||||||
|
* Copyright (C) 2019, 2020 Famedly GmbH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
abstract class AuthenticationTypes {
|
||||||
|
static const String password = 'm.login.password';
|
||||||
|
static const String recaptcha = 'm.login.recaptcha';
|
||||||
|
static const String token = 'm.login.token';
|
||||||
|
static const String oauth2 = 'm.login.oauth2';
|
||||||
|
static const String sso = 'm.login.sso';
|
||||||
|
static const String emailIdentity = 'm.login.email.identity';
|
||||||
|
static const String msisdn = 'm.login.msisdn';
|
||||||
|
static const String dummy = 'm.login.dummy';
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class AuthenticationIdentifierTypes {
|
||||||
|
static const String userId = 'm.id.user';
|
||||||
|
static const String thirdParty = 'm.id.thirdparty';
|
||||||
|
static const String phone = 'm.id.phone';
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Famedly Matrix SDK
|
||||||
|
* Copyright (C) 2019, 2020 Famedly GmbH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import 'authentication_identifier.dart';
|
||||||
|
import 'authentication_types.dart';
|
||||||
|
|
||||||
|
class AuthenticationUserIdentifier extends AuthenticationIdentifier {
|
||||||
|
String user;
|
||||||
|
|
||||||
|
AuthenticationUserIdentifier({this.user})
|
||||||
|
: super(type: AuthenticationIdentifierTypes.userId);
|
||||||
|
|
||||||
|
AuthenticationUserIdentifier.fromJson(Map<String, dynamic> json)
|
||||||
|
: super.fromJson(json) {
|
||||||
|
user = json['user'];
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final data = super.toJson();
|
||||||
|
data['user'] = user;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -309,7 +309,7 @@ class Client extends MatrixApi {
|
||||||
String deviceId,
|
String deviceId,
|
||||||
String initialDeviceDisplayName,
|
String initialDeviceDisplayName,
|
||||||
bool inhibitLogin,
|
bool inhibitLogin,
|
||||||
Map<String, dynamic> auth,
|
AuthenticationData auth,
|
||||||
String kind,
|
String kind,
|
||||||
}) async {
|
}) async {
|
||||||
final response = await super.register(
|
final response = await super.register(
|
||||||
|
|
@ -342,8 +342,8 @@ class Client extends MatrixApi {
|
||||||
/// You have to call [checkHomeserver] first to set a homeserver.
|
/// You have to call [checkHomeserver] first to set a homeserver.
|
||||||
@override
|
@override
|
||||||
Future<LoginResponse> login({
|
Future<LoginResponse> login({
|
||||||
String type = 'm.login.password',
|
String type = AuthenticationTypes.password,
|
||||||
String userIdentifierType = 'm.id.user',
|
String userIdentifierType = AuthenticationIdentifierTypes.userId,
|
||||||
String user,
|
String user,
|
||||||
String medium,
|
String medium,
|
||||||
String address,
|
String address,
|
||||||
|
|
@ -351,7 +351,7 @@ class Client extends MatrixApi {
|
||||||
String token,
|
String token,
|
||||||
String deviceId,
|
String deviceId,
|
||||||
String initialDeviceDisplayName,
|
String initialDeviceDisplayName,
|
||||||
Map<String, dynamic> auth,
|
AuthenticationData auth,
|
||||||
}) async {
|
}) async {
|
||||||
final loginResp = await super.login(
|
final loginResp = await super.login(
|
||||||
type: type,
|
type: type,
|
||||||
|
|
@ -412,15 +412,15 @@ class Client extends MatrixApi {
|
||||||
|
|
||||||
/// Run any request and react on user interactive authentication flows here.
|
/// Run any request and react on user interactive authentication flows here.
|
||||||
Future<T> uiaRequestBackground<T>(
|
Future<T> uiaRequestBackground<T>(
|
||||||
Future<T> Function(Map<String, dynamic> auth) request) {
|
Future<T> Function(AuthenticationData auth) request) {
|
||||||
final completer = Completer<T>();
|
final completer = Completer<T>();
|
||||||
UiaRequest uia;
|
UiaRequest uia;
|
||||||
uia = UiaRequest(
|
uia = UiaRequest(
|
||||||
request: request,
|
request: request,
|
||||||
onDone: () {
|
onUpdate: (state) {
|
||||||
if (uia.done) {
|
if (state == UiaRequestState.done) {
|
||||||
completer.complete(uia.result);
|
completer.complete(uia.result);
|
||||||
} else if (uia.fail) {
|
} else if (state == UiaRequestState.fail) {
|
||||||
completer.completeError(uia.error);
|
completer.completeError(uia.error);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -538,7 +538,7 @@ class Client extends MatrixApi {
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
static const Set<String> supportedVersions = {'r0.5.0', 'r0.6.0'};
|
static const Set<String> supportedVersions = {'r0.5.0', 'r0.6.0'};
|
||||||
static const Set<String> supportedLoginTypes = {'m.login.password'};
|
static const Set<String> supportedLoginTypes = {AuthenticationTypes.password};
|
||||||
static const String syncFilters =
|
static const String syncFilters =
|
||||||
'{"room":{"state":{"lazy_load_members":true}}}';
|
'{"room":{"state":{"lazy_load_members":true}}}';
|
||||||
static const String messagesFilters = '{"lazy_load_members":true}';
|
static const String messagesFilters = '{"lazy_load_members":true}';
|
||||||
|
|
@ -1603,14 +1603,14 @@ sort order of ${prevState.sortOrder}. This should never happen...''');
|
||||||
/// 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
|
@override
|
||||||
Future<void> changePassword(String newPassword,
|
Future<void> changePassword(String newPassword,
|
||||||
{String oldPassword, Map<String, dynamic> auth}) async {
|
{String oldPassword, AuthenticationData auth}) async {
|
||||||
try {
|
try {
|
||||||
if (oldPassword != null) {
|
if (oldPassword != null) {
|
||||||
auth = {
|
auth = AuthenticationPassword(
|
||||||
'type': 'm.login.password',
|
user: userID,
|
||||||
'user': userID,
|
identifier: AuthenticationUserIdentifier(user: userID),
|
||||||
'password': oldPassword,
|
password: oldPassword,
|
||||||
};
|
);
|
||||||
}
|
}
|
||||||
await super.changePassword(newPassword, auth: auth);
|
await super.changePassword(newPassword, auth: auth);
|
||||||
} on MatrixException catch (matrixException) {
|
} on MatrixException catch (matrixException) {
|
||||||
|
|
@ -1619,7 +1619,7 @@ sort order of ${prevState.sortOrder}. This should never happen...''');
|
||||||
}
|
}
|
||||||
if (matrixException.authenticationFlows.length != 1 ||
|
if (matrixException.authenticationFlows.length != 1 ||
|
||||||
!matrixException.authenticationFlows.first.stages
|
!matrixException.authenticationFlows.first.stages
|
||||||
.contains('m.login.password')) {
|
.contains(AuthenticationTypes.password)) {
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
if (oldPassword == null) {
|
if (oldPassword == null) {
|
||||||
|
|
@ -1627,13 +1627,12 @@ sort order of ${prevState.sortOrder}. This should never happen...''');
|
||||||
}
|
}
|
||||||
return changePassword(
|
return changePassword(
|
||||||
newPassword,
|
newPassword,
|
||||||
auth: {
|
auth: AuthenticationPassword(
|
||||||
'type': 'm.login.password',
|
user: userID,
|
||||||
'user': userID,
|
identifier: AuthenticationUserIdentifier(user: userID),
|
||||||
'identifier': {'type': 'm.id.user', 'user': userID},
|
password: oldPassword,
|
||||||
'password': oldPassword,
|
session: matrixException.session,
|
||||||
'session': matrixException.session,
|
),
|
||||||
},
|
|
||||||
);
|
);
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
rethrow;
|
rethrow;
|
||||||
|
|
|
||||||
|
|
@ -18,30 +18,48 @@
|
||||||
|
|
||||||
import '../../famedlysdk.dart';
|
import '../../famedlysdk.dart';
|
||||||
|
|
||||||
|
enum UiaRequestState {
|
||||||
|
/// The request is done
|
||||||
|
done,
|
||||||
|
|
||||||
|
/// The request has failed
|
||||||
|
fail,
|
||||||
|
|
||||||
|
/// The request is currently loading
|
||||||
|
loading,
|
||||||
|
|
||||||
|
/// The request is waiting for user interaction
|
||||||
|
waitForUser,
|
||||||
|
}
|
||||||
|
|
||||||
/// Wrapper to handle User interactive authentication requests
|
/// Wrapper to handle User interactive authentication requests
|
||||||
class UiaRequest<T> {
|
class UiaRequest<T> {
|
||||||
void Function() onUpdate;
|
void Function(UiaRequestState state) onUpdate;
|
||||||
void Function() onDone;
|
final Future<T> Function(AuthenticationData auth) request;
|
||||||
final Future<T> Function(Map<String, dynamic> auth) request;
|
|
||||||
String session;
|
String session;
|
||||||
bool done = false;
|
UiaRequestState _state = UiaRequestState.loading;
|
||||||
bool fail = false;
|
|
||||||
T result;
|
T result;
|
||||||
Exception error;
|
Exception error;
|
||||||
Set<String> nextStages = <String>{};
|
Set<String> nextStages = <String>{};
|
||||||
Map<String, dynamic> params = <String, dynamic>{};
|
Map<String, dynamic> params = <String, dynamic>{};
|
||||||
UiaRequest({this.onUpdate, this.request, this.onDone}) {
|
|
||||||
run();
|
UiaRequestState get state => _state;
|
||||||
|
set state(UiaRequestState newState) {
|
||||||
|
if (_state == newState) return;
|
||||||
|
_state = newState;
|
||||||
|
onUpdate?.call(newState);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<T> run([Map<String, dynamic> auth]) async {
|
UiaRequest({this.onUpdate, this.request}) {
|
||||||
|
_run();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<T> _run([AuthenticationData auth]) async {
|
||||||
|
state = UiaRequestState.loading;
|
||||||
try {
|
try {
|
||||||
auth ??= <String, dynamic>{};
|
auth ??= AuthenticationData(session: session);
|
||||||
if (session != null) {
|
|
||||||
auth['session'] = session;
|
|
||||||
}
|
|
||||||
final res = await request(auth);
|
final res = await request(auth);
|
||||||
done = true;
|
state = UiaRequestState.done;
|
||||||
result = res;
|
result = res;
|
||||||
return res;
|
return res;
|
||||||
} on MatrixException catch (err) {
|
} on MatrixException catch (err) {
|
||||||
|
|
@ -59,23 +77,16 @@ class UiaRequest<T> {
|
||||||
return null;
|
return null;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
error = err is Exception ? err : Exception(err);
|
error = err is Exception ? err : Exception(err);
|
||||||
fail = true;
|
state = UiaRequestState.fail;
|
||||||
return null;
|
return null;
|
||||||
} finally {
|
} finally {
|
||||||
if (onUpdate != null) {
|
if (state == UiaRequestState.loading) {
|
||||||
onUpdate();
|
state = UiaRequestState.waitForUser;
|
||||||
}
|
|
||||||
if ((fail || done) && onDone != null) {
|
|
||||||
onDone();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<T> completeStage(String type, [Map<String, dynamic> auth]) async {
|
Future<T> completeStage(AuthenticationData auth) => _run(auth);
|
||||||
auth ??= <String, dynamic>{};
|
|
||||||
auth['type'] = type;
|
|
||||||
return await run(auth);
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<String> getNextStages(
|
Set<String> getNextStages(
|
||||||
List<AuthenticationFlow> flows, List<String> completed) {
|
List<AuthenticationFlow> flows, List<String> completed) {
|
||||||
|
|
|
||||||
|
|
@ -204,11 +204,14 @@ void main() {
|
||||||
test('changePassword', () async {
|
test('changePassword', () async {
|
||||||
matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting');
|
matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting');
|
||||||
matrixApi.accessToken = '1234';
|
matrixApi.accessToken = '1234';
|
||||||
await matrixApi.changePassword('1234', auth: {
|
await matrixApi.changePassword(
|
||||||
'type': 'example.type.foo',
|
'1234',
|
||||||
'session': 'xxxxx',
|
auth: AuthenticationData.fromJson({
|
||||||
'example_credential': 'verypoorsharedsecret'
|
'type': 'example.type.foo',
|
||||||
});
|
'session': 'xxxxx',
|
||||||
|
'example_credential': 'verypoorsharedsecret'
|
||||||
|
}),
|
||||||
|
);
|
||||||
matrixApi.homeserver = matrixApi.accessToken = null;
|
matrixApi.homeserver = matrixApi.accessToken = null;
|
||||||
});
|
});
|
||||||
test('resetPasswordUsingEmail', () async {
|
test('resetPasswordUsingEmail', () async {
|
||||||
|
|
@ -241,12 +244,14 @@ void main() {
|
||||||
test('deactivateAccount', () async {
|
test('deactivateAccount', () async {
|
||||||
matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting');
|
matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting');
|
||||||
matrixApi.accessToken = '1234';
|
matrixApi.accessToken = '1234';
|
||||||
final response = await matrixApi
|
final response = await matrixApi.deactivateAccount(
|
||||||
.deactivateAccount(idServer: 'https://example.com', auth: {
|
idServer: 'https://example.com',
|
||||||
'type': 'example.type.foo',
|
auth: AuthenticationData.fromJson({
|
||||||
'session': 'xxxxx',
|
'type': 'example.type.foo',
|
||||||
'example_credential': 'verypoorsharedsecret'
|
'session': 'xxxxx',
|
||||||
});
|
'example_credential': 'verypoorsharedsecret'
|
||||||
|
}),
|
||||||
|
);
|
||||||
expect(response, IdServerUnbindResult.success);
|
expect(response, IdServerUnbindResult.success);
|
||||||
matrixApi.homeserver = matrixApi.accessToken = null;
|
matrixApi.homeserver = matrixApi.accessToken = null;
|
||||||
});
|
});
|
||||||
|
|
@ -267,7 +272,8 @@ void main() {
|
||||||
test('addThirdPartyIdentifier', () async {
|
test('addThirdPartyIdentifier', () async {
|
||||||
matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting');
|
matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting');
|
||||||
matrixApi.accessToken = '1234';
|
matrixApi.accessToken = '1234';
|
||||||
await matrixApi.addThirdPartyIdentifier('1234', '1234', auth: {});
|
await matrixApi.addThirdPartyIdentifier('1234', '1234',
|
||||||
|
auth: AuthenticationData.fromJson({'type': 'm.login.dummy'}));
|
||||||
matrixApi.homeserver = matrixApi.accessToken = null;
|
matrixApi.homeserver = matrixApi.accessToken = null;
|
||||||
});
|
});
|
||||||
test('bindThirdPartyIdentifier', () async {
|
test('bindThirdPartyIdentifier', () async {
|
||||||
|
|
@ -1041,7 +1047,8 @@ void main() {
|
||||||
matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting');
|
matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting');
|
||||||
matrixApi.accessToken = '1234';
|
matrixApi.accessToken = '1234';
|
||||||
|
|
||||||
await matrixApi.deleteDevice('QBUAZIFURK', auth: {});
|
await matrixApi.deleteDevice('QBUAZIFURK',
|
||||||
|
auth: AuthenticationData.fromJson({}));
|
||||||
|
|
||||||
matrixApi.homeserver = matrixApi.accessToken = null;
|
matrixApi.homeserver = matrixApi.accessToken = null;
|
||||||
});
|
});
|
||||||
|
|
@ -1049,7 +1056,8 @@ void main() {
|
||||||
matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting');
|
matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting');
|
||||||
matrixApi.accessToken = '1234';
|
matrixApi.accessToken = '1234';
|
||||||
|
|
||||||
await matrixApi.deleteDevices(['QBUAZIFURK'], auth: {});
|
await matrixApi
|
||||||
|
.deleteDevices(['QBUAZIFURK'], auth: AuthenticationData.fromJson({}));
|
||||||
|
|
||||||
matrixApi.homeserver = matrixApi.accessToken = null;
|
matrixApi.homeserver = matrixApi.accessToken = null;
|
||||||
});
|
});
|
||||||
|
|
@ -1785,5 +1793,122 @@ void main() {
|
||||||
['/client/unstable/room_keys/keys?version=5']({}),
|
['/client/unstable/room_keys/keys?version=5']({}),
|
||||||
ret.toJson());
|
ret.toJson());
|
||||||
});
|
});
|
||||||
|
test('AuthenticationData', () {
|
||||||
|
final json = {'session': '1234', 'type': 'm.login.dummy'};
|
||||||
|
expect(AuthenticationData.fromJson(json).toJson(), json);
|
||||||
|
expect(
|
||||||
|
AuthenticationData(session: '1234', type: 'm.login.dummy').toJson(),
|
||||||
|
json);
|
||||||
|
});
|
||||||
|
test('AuthenticationRecaptcha', () {
|
||||||
|
final json = {
|
||||||
|
'session': '1234',
|
||||||
|
'type': 'm.login.recaptcha',
|
||||||
|
'response': 'a',
|
||||||
|
};
|
||||||
|
expect(AuthenticationRecaptcha.fromJson(json).toJson(), json);
|
||||||
|
expect(AuthenticationRecaptcha(session: '1234', response: 'a').toJson(),
|
||||||
|
json);
|
||||||
|
});
|
||||||
|
test('AuthenticationToken', () {
|
||||||
|
final json = {
|
||||||
|
'session': '1234',
|
||||||
|
'type': 'm.login.token',
|
||||||
|
'token': 'a',
|
||||||
|
'txn_id': '1'
|
||||||
|
};
|
||||||
|
expect(AuthenticationToken.fromJson(json).toJson(), json);
|
||||||
|
expect(
|
||||||
|
AuthenticationToken(session: '1234', token: 'a', txnId: '1').toJson(),
|
||||||
|
json);
|
||||||
|
});
|
||||||
|
test('AuthenticationThreePidCreds', () {
|
||||||
|
final json = {
|
||||||
|
'type': 'm.login.email.identity',
|
||||||
|
'threepidCreds': [
|
||||||
|
{
|
||||||
|
'sid': '1',
|
||||||
|
'client_secret': 'a',
|
||||||
|
'id_server': 'matrix.org',
|
||||||
|
'id_access_token': 'a',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'threepid_creds': [
|
||||||
|
{
|
||||||
|
'sid': '1',
|
||||||
|
'client_secret': 'a',
|
||||||
|
'id_server': 'matrix.org',
|
||||||
|
'id_access_token': 'a',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'session': '1',
|
||||||
|
};
|
||||||
|
expect(AuthenticationThreePidCreds.fromJson(json).toJson(), json);
|
||||||
|
expect(
|
||||||
|
AuthenticationThreePidCreds(
|
||||||
|
session: '1',
|
||||||
|
type: AuthenticationTypes.emailIdentity,
|
||||||
|
threepidCreds: [
|
||||||
|
ThreepidCreds(
|
||||||
|
sid: '1',
|
||||||
|
clientSecret: 'a',
|
||||||
|
idServer: 'matrix.org',
|
||||||
|
idAccessToken: 'a',
|
||||||
|
),
|
||||||
|
]).toJson(),
|
||||||
|
json);
|
||||||
|
});
|
||||||
|
test('AuthenticationIdentifier', () {
|
||||||
|
final json = {'type': 'm.id.user'};
|
||||||
|
expect(AuthenticationIdentifier.fromJson(json).toJson(), json);
|
||||||
|
expect(AuthenticationIdentifier(type: 'm.id.user').toJson(), json);
|
||||||
|
});
|
||||||
|
test('AuthenticationPassword', () {
|
||||||
|
final json = {
|
||||||
|
'type': 'm.login.password',
|
||||||
|
'identifier': {'type': 'm.id.user', 'user': 'a'},
|
||||||
|
'password': 'a',
|
||||||
|
'session': '1',
|
||||||
|
'user': 'a',
|
||||||
|
};
|
||||||
|
expect(AuthenticationPassword.fromJson(json).toJson(), json);
|
||||||
|
expect(
|
||||||
|
AuthenticationPassword(
|
||||||
|
session: '1',
|
||||||
|
password: 'a',
|
||||||
|
user: 'a',
|
||||||
|
identifier: AuthenticationUserIdentifier(user: 'a'),
|
||||||
|
).toJson(),
|
||||||
|
json);
|
||||||
|
json['identifier'] = {
|
||||||
|
'type': 'm.id.thirdparty',
|
||||||
|
'medium': 'a',
|
||||||
|
'address': 'a',
|
||||||
|
};
|
||||||
|
expect(AuthenticationPassword.fromJson(json).toJson(), json);
|
||||||
|
expect(
|
||||||
|
AuthenticationPassword(
|
||||||
|
session: '1',
|
||||||
|
password: 'a',
|
||||||
|
user: 'a',
|
||||||
|
identifier:
|
||||||
|
AuthenticationThirdPartyIdentifier(medium: 'a', address: 'a'),
|
||||||
|
).toJson(),
|
||||||
|
json);
|
||||||
|
json['identifier'] = {
|
||||||
|
'type': 'm.id.phone',
|
||||||
|
'country': 'a',
|
||||||
|
'phone': 'a',
|
||||||
|
};
|
||||||
|
expect(AuthenticationPassword.fromJson(json).toJson(), json);
|
||||||
|
expect(
|
||||||
|
AuthenticationPassword(
|
||||||
|
session: '1',
|
||||||
|
password: 'a',
|
||||||
|
user: 'a',
|
||||||
|
identifier: AuthenticationPhoneIdentifier(country: 'a', phone: 'a'),
|
||||||
|
).toJson(),
|
||||||
|
json);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,14 +29,14 @@ void main() {
|
||||||
var finished = false;
|
var finished = false;
|
||||||
final request = UiaRequest(
|
final request = UiaRequest(
|
||||||
request: (auth) async {
|
request: (auth) async {
|
||||||
if (auth['session'] != null && auth['session'] != 'foxies') {
|
if (auth.session != null && auth.session != 'foxies') {
|
||||||
throw MatrixException.fromJson(<String, dynamic>{});
|
throw MatrixException.fromJson(<String, dynamic>{});
|
||||||
}
|
}
|
||||||
if (auth['type'] == 'stage1') {
|
if (auth.type == 'stage1') {
|
||||||
if (completed.isEmpty) {
|
if (completed.isEmpty) {
|
||||||
completed.add('stage1');
|
completed.add('stage1');
|
||||||
}
|
}
|
||||||
} else if (auth['type'] == 'stage2') {
|
} else if (auth.type == 'stage2') {
|
||||||
if (completed.length == 1 && completed[0] == 'stage1') {
|
if (completed.length == 1 && completed[0] == 'stage1') {
|
||||||
// okay, we are done!
|
// okay, we are done!
|
||||||
return 'FOXIES ARE FLOOOOOFY!!!!!';
|
return 'FOXIES ARE FLOOOOOFY!!!!!';
|
||||||
|
|
@ -54,24 +54,29 @@ void main() {
|
||||||
};
|
};
|
||||||
throw MatrixException.fromJson(res);
|
throw MatrixException.fromJson(res);
|
||||||
},
|
},
|
||||||
onUpdate: () => updated++,
|
onUpdate: (state) {
|
||||||
onDone: () => finished = true,
|
if (state == UiaRequestState.done) {
|
||||||
|
finished = true;
|
||||||
|
}
|
||||||
|
updated++;
|
||||||
|
},
|
||||||
);
|
);
|
||||||
await Future.delayed(Duration(milliseconds: 50));
|
await Future.delayed(Duration(milliseconds: 50));
|
||||||
expect(request.nextStages.contains('stage1'), true);
|
expect(request.nextStages.contains('stage1'), true);
|
||||||
expect(request.nextStages.length, 1);
|
expect(request.nextStages.length, 1);
|
||||||
expect(updated, 1);
|
expect(updated, 1);
|
||||||
expect(finished, false);
|
expect(finished, false);
|
||||||
await request.completeStage('stage1');
|
await request.completeStage(AuthenticationData(type: 'stage1'));
|
||||||
expect(request.nextStages.contains('stage2'), true);
|
expect(request.nextStages.contains('stage2'), true);
|
||||||
expect(request.nextStages.length, 1);
|
expect(request.nextStages.length, 1);
|
||||||
expect(updated, 2);
|
expect(updated, 3);
|
||||||
expect(finished, false);
|
expect(finished, false);
|
||||||
final res = await request.completeStage('stage2');
|
final res =
|
||||||
|
await request.completeStage(AuthenticationData(type: 'stage2'));
|
||||||
expect(res, 'FOXIES ARE FLOOOOOFY!!!!!');
|
expect(res, 'FOXIES ARE FLOOOOOFY!!!!!');
|
||||||
expect(request.result, 'FOXIES ARE FLOOOOOFY!!!!!');
|
expect(request.result, 'FOXIES ARE FLOOOOOFY!!!!!');
|
||||||
expect(request.done, true);
|
expect(request.state, UiaRequestState.done);
|
||||||
expect(updated, 3);
|
expect(updated, 5);
|
||||||
expect(finished, true);
|
expect(finished, true);
|
||||||
});
|
});
|
||||||
test('it should throw errors', () async {
|
test('it should throw errors', () async {
|
||||||
|
|
@ -81,11 +86,15 @@ void main() {
|
||||||
request: (auth) async {
|
request: (auth) async {
|
||||||
throw Exception('nope');
|
throw Exception('nope');
|
||||||
},
|
},
|
||||||
onUpdate: () => updated = true,
|
onUpdate: (state) {
|
||||||
onDone: () => finished = true,
|
if (state == UiaRequestState.fail) {
|
||||||
|
finished = true;
|
||||||
|
}
|
||||||
|
updated = true;
|
||||||
|
},
|
||||||
);
|
);
|
||||||
await Future.delayed(Duration(milliseconds: 50));
|
await Future.delayed(Duration(milliseconds: 50));
|
||||||
expect(request.fail, true);
|
expect(request.state, UiaRequestState.fail);
|
||||||
expect(updated, true);
|
expect(updated, true);
|
||||||
expect(finished, true);
|
expect(finished, true);
|
||||||
expect(request.error.toString(), Exception('nope').toString());
|
expect(request.error.toString(), Exception('nope').toString());
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue