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';
|
||||
|
||||
enum BootstrapState {
|
||||
loading, // loading
|
||||
askWipeSsss, // existing SSSS found, should we wipe it?
|
||||
askUseExistingSsss, // ask if an existing SSSS should be userDeviceKeys
|
||||
askBadSsss, // SSSS is in a bad state, continue with potential dataloss?
|
||||
askUnlockSsss, // Ask to unlock all the SSSS keys
|
||||
askNewSsss, // Ask for new SSSS key / passphrase
|
||||
openExistingSsss, // Open an existing SSSS key
|
||||
askWipeCrossSigning, // Ask if cross signing should be wiped
|
||||
askSetupCrossSigning, // Ask if cross signing should be set up
|
||||
askWipeOnlineKeyBackup, // Ask if online key backup should be wiped
|
||||
askSetupOnlineKeyBackup, // Ask if the online key backup should be set up
|
||||
error, // error
|
||||
done, // done
|
||||
/// Is loading.
|
||||
loading,
|
||||
|
||||
/// Existing SSSS found, should we wipe it?
|
||||
askWipeSsss,
|
||||
|
||||
/// Ask if an existing SSSS should be userDeviceKeys
|
||||
askUseExistingSsss,
|
||||
|
||||
/// Ask to unlock all the SSSS keys
|
||||
askUnlockSsss,
|
||||
|
||||
/// 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
|
||||
|
|
@ -425,8 +450,9 @@ class Bootstrap {
|
|||
}
|
||||
try {
|
||||
// upload the keys!
|
||||
state = BootstrapState.loading;
|
||||
await client.uiaRequestBackground(
|
||||
(Map<String, dynamic> auth) => client.uploadDeviceSigningKeys(
|
||||
(AuthenticationData auth) => client.uploadDeviceSigningKeys(
|
||||
masterKey: masterKey,
|
||||
selfSigningKey: selfSigningKey,
|
||||
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/well_known_informations.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_key_content.dart';
|
||||
export 'matrix_api/model/events/tombstone_content.dart';
|
||||
|
|
|
|||
|
|
@ -19,10 +19,12 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:famedlysdk/famedlysdk.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:mime/mime.dart';
|
||||
import 'package:moor/moor.dart';
|
||||
|
||||
import 'model/auth/authentication_types.dart';
|
||||
import 'model/device.dart';
|
||||
import 'model/event_context.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.
|
||||
/// https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-login
|
||||
Future<LoginResponse> login({
|
||||
String type = 'm.login.password',
|
||||
String type = AuthenticationTypes.password,
|
||||
String userIdentifierType,
|
||||
String user,
|
||||
String medium,
|
||||
|
|
@ -256,7 +258,7 @@ class MatrixApi {
|
|||
String token,
|
||||
String deviceId,
|
||||
String initialDeviceDisplayName,
|
||||
Map<String, dynamic> auth,
|
||||
AuthenticationData auth,
|
||||
}) async {
|
||||
final response = await request(RequestType.POST, '/client/r0/login', data: {
|
||||
'type': type,
|
||||
|
|
@ -272,7 +274,7 @@ class MatrixApi {
|
|||
if (deviceId != null) 'device_id': deviceId,
|
||||
if (initialDeviceDisplayName != null)
|
||||
'initial_device_display_name': initialDeviceDisplayName,
|
||||
if (auth != null) 'auth': auth,
|
||||
if (auth != null) 'auth': auth.toJson(),
|
||||
});
|
||||
return LoginResponse.fromJson(response);
|
||||
}
|
||||
|
|
@ -302,13 +304,25 @@ class MatrixApi {
|
|||
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({
|
||||
String username,
|
||||
String password,
|
||||
String deviceId,
|
||||
String initialDeviceDisplayName,
|
||||
bool inhibitLogin,
|
||||
Map<String, dynamic> auth,
|
||||
AuthenticationData auth,
|
||||
String kind,
|
||||
}) async {
|
||||
var action = '/client/r0/register';
|
||||
|
|
@ -320,7 +334,7 @@ class MatrixApi {
|
|||
if (initialDeviceDisplayName != null)
|
||||
'initial_device_display_name': initialDeviceDisplayName,
|
||||
if (inhibitLogin != null) 'inhibit_login': inhibitLogin,
|
||||
if (auth != null) 'auth': auth,
|
||||
if (auth != null) 'auth': auth.toJson(),
|
||||
});
|
||||
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
|
||||
Future<void> changePassword(
|
||||
String newPassword, {
|
||||
Map<String, dynamic> auth,
|
||||
AuthenticationData auth,
|
||||
}) async {
|
||||
await request(RequestType.POST, '/client/r0/account/password', data: {
|
||||
'new_password': newPassword,
|
||||
if (auth != null) 'auth': auth,
|
||||
if (auth != null) 'auth': auth.toJson(),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
|
@ -443,14 +457,15 @@ class MatrixApi {
|
|||
return RequestTokenResponse.fromJson(response);
|
||||
}
|
||||
|
||||
/// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-account-deactivate
|
||||
Future<IdServerUnbindResult> deactivateAccount({
|
||||
String idServer,
|
||||
Map<String, dynamic> auth,
|
||||
AuthenticationData auth,
|
||||
}) async {
|
||||
final response =
|
||||
await request(RequestType.POST, '/client/r0/account/deactivate', data: {
|
||||
if (idServer != null) 'id_server': idServer,
|
||||
if (auth != null) 'auth': auth,
|
||||
if (auth != null) 'auth': auth.toJson(),
|
||||
});
|
||||
|
||||
return IdServerUnbindResult.values.firstWhere(
|
||||
|
|
@ -486,12 +501,12 @@ class MatrixApi {
|
|||
Future<void> addThirdPartyIdentifier(
|
||||
String clientSecret,
|
||||
String sid, {
|
||||
Map<String, dynamic> auth,
|
||||
AuthenticationData auth,
|
||||
}) async {
|
||||
await request(RequestType.POST, '/client/r0/account/3pid/add', data: {
|
||||
'sid': sid,
|
||||
'client_secret': clientSecret,
|
||||
if (auth != null && auth.isNotEmpty) 'auth': auth,
|
||||
if (auth != null) 'auth': auth.toJson(),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
|
@ -1381,12 +1396,11 @@ class MatrixApi {
|
|||
|
||||
/// 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
|
||||
Future<void> deleteDevice(String deviceId,
|
||||
{Map<String, dynamic> auth}) async {
|
||||
Future<void> deleteDevice(String deviceId, {AuthenticationData auth}) async {
|
||||
await request(RequestType.DELETE,
|
||||
'/client/r0/devices/${Uri.encodeComponent(deviceId)}',
|
||||
data: {
|
||||
if (auth != null) 'auth': auth,
|
||||
if (auth != null) 'auth': auth.toJson(),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
|
@ -1394,10 +1408,10 @@ class MatrixApi {
|
|||
/// 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
|
||||
Future<void> deleteDevices(List<String> deviceIds,
|
||||
{Map<String, dynamic> auth}) async {
|
||||
{AuthenticationData auth}) async {
|
||||
await request(RequestType.POST, '/client/r0/delete_devices', data: {
|
||||
'devices': deviceIds,
|
||||
if (auth != null) 'auth': auth,
|
||||
if (auth != null) 'auth': auth.toJson(),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
|
@ -1470,7 +1484,7 @@ class MatrixApi {
|
|||
MatrixCrossSigningKey masterKey,
|
||||
MatrixCrossSigningKey selfSigningKey,
|
||||
MatrixCrossSigningKey userSigningKey,
|
||||
Map<String, dynamic> auth,
|
||||
AuthenticationData auth,
|
||||
}) async {
|
||||
await request(
|
||||
RequestType.POST,
|
||||
|
|
@ -1479,7 +1493,7 @@ class MatrixApi {
|
|||
if (masterKey != null) 'master_key': masterKey.toJson(),
|
||||
if (selfSigningKey != null) 'self_signing_key': selfSigningKey.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 initialDeviceDisplayName,
|
||||
bool inhibitLogin,
|
||||
Map<String, dynamic> auth,
|
||||
AuthenticationData auth,
|
||||
String kind,
|
||||
}) async {
|
||||
final response = await super.register(
|
||||
|
|
@ -342,8 +342,8 @@ class Client extends MatrixApi {
|
|||
/// You have to call [checkHomeserver] first to set a homeserver.
|
||||
@override
|
||||
Future<LoginResponse> login({
|
||||
String type = 'm.login.password',
|
||||
String userIdentifierType = 'm.id.user',
|
||||
String type = AuthenticationTypes.password,
|
||||
String userIdentifierType = AuthenticationIdentifierTypes.userId,
|
||||
String user,
|
||||
String medium,
|
||||
String address,
|
||||
|
|
@ -351,7 +351,7 @@ class Client extends MatrixApi {
|
|||
String token,
|
||||
String deviceId,
|
||||
String initialDeviceDisplayName,
|
||||
Map<String, dynamic> auth,
|
||||
AuthenticationData auth,
|
||||
}) async {
|
||||
final loginResp = await super.login(
|
||||
type: type,
|
||||
|
|
@ -412,15 +412,15 @@ class Client extends MatrixApi {
|
|||
|
||||
/// Run any request and react on user interactive authentication flows here.
|
||||
Future<T> uiaRequestBackground<T>(
|
||||
Future<T> Function(Map<String, dynamic> auth) request) {
|
||||
Future<T> Function(AuthenticationData auth) request) {
|
||||
final completer = Completer<T>();
|
||||
UiaRequest uia;
|
||||
uia = UiaRequest(
|
||||
request: request,
|
||||
onDone: () {
|
||||
if (uia.done) {
|
||||
onUpdate: (state) {
|
||||
if (state == UiaRequestState.done) {
|
||||
completer.complete(uia.result);
|
||||
} else if (uia.fail) {
|
||||
} else if (state == UiaRequestState.fail) {
|
||||
completer.completeError(uia.error);
|
||||
}
|
||||
},
|
||||
|
|
@ -538,7 +538,7 @@ class Client extends MatrixApi {
|
|||
: null;
|
||||
|
||||
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 =
|
||||
'{"room":{"state":{"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.
|
||||
@override
|
||||
Future<void> changePassword(String newPassword,
|
||||
{String oldPassword, Map<String, dynamic> auth}) async {
|
||||
{String oldPassword, AuthenticationData auth}) async {
|
||||
try {
|
||||
if (oldPassword != null) {
|
||||
auth = {
|
||||
'type': 'm.login.password',
|
||||
'user': userID,
|
||||
'password': oldPassword,
|
||||
};
|
||||
auth = AuthenticationPassword(
|
||||
user: userID,
|
||||
identifier: AuthenticationUserIdentifier(user: userID),
|
||||
password: oldPassword,
|
||||
);
|
||||
}
|
||||
await super.changePassword(newPassword, auth: auth);
|
||||
} on MatrixException catch (matrixException) {
|
||||
|
|
@ -1619,7 +1619,7 @@ sort order of ${prevState.sortOrder}. This should never happen...''');
|
|||
}
|
||||
if (matrixException.authenticationFlows.length != 1 ||
|
||||
!matrixException.authenticationFlows.first.stages
|
||||
.contains('m.login.password')) {
|
||||
.contains(AuthenticationTypes.password)) {
|
||||
rethrow;
|
||||
}
|
||||
if (oldPassword == null) {
|
||||
|
|
@ -1627,13 +1627,12 @@ sort order of ${prevState.sortOrder}. This should never happen...''');
|
|||
}
|
||||
return changePassword(
|
||||
newPassword,
|
||||
auth: {
|
||||
'type': 'm.login.password',
|
||||
'user': userID,
|
||||
'identifier': {'type': 'm.id.user', 'user': userID},
|
||||
'password': oldPassword,
|
||||
'session': matrixException.session,
|
||||
},
|
||||
auth: AuthenticationPassword(
|
||||
user: userID,
|
||||
identifier: AuthenticationUserIdentifier(user: userID),
|
||||
password: oldPassword,
|
||||
session: matrixException.session,
|
||||
),
|
||||
);
|
||||
} catch (_) {
|
||||
rethrow;
|
||||
|
|
|
|||
|
|
@ -18,30 +18,48 @@
|
|||
|
||||
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
|
||||
class UiaRequest<T> {
|
||||
void Function() onUpdate;
|
||||
void Function() onDone;
|
||||
final Future<T> Function(Map<String, dynamic> auth) request;
|
||||
void Function(UiaRequestState state) onUpdate;
|
||||
final Future<T> Function(AuthenticationData auth) request;
|
||||
String session;
|
||||
bool done = false;
|
||||
bool fail = false;
|
||||
UiaRequestState _state = UiaRequestState.loading;
|
||||
T result;
|
||||
Exception error;
|
||||
Set<String> nextStages = <String>{};
|
||||
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 {
|
||||
try {
|
||||
auth ??= <String, dynamic>{};
|
||||
if (session != null) {
|
||||
auth['session'] = session;
|
||||
UiaRequest({this.onUpdate, this.request}) {
|
||||
_run();
|
||||
}
|
||||
|
||||
Future<T> _run([AuthenticationData auth]) async {
|
||||
state = UiaRequestState.loading;
|
||||
try {
|
||||
auth ??= AuthenticationData(session: session);
|
||||
final res = await request(auth);
|
||||
done = true;
|
||||
state = UiaRequestState.done;
|
||||
result = res;
|
||||
return res;
|
||||
} on MatrixException catch (err) {
|
||||
|
|
@ -59,23 +77,16 @@ class UiaRequest<T> {
|
|||
return null;
|
||||
} catch (err) {
|
||||
error = err is Exception ? err : Exception(err);
|
||||
fail = true;
|
||||
state = UiaRequestState.fail;
|
||||
return null;
|
||||
} finally {
|
||||
if (onUpdate != null) {
|
||||
onUpdate();
|
||||
}
|
||||
if ((fail || done) && onDone != null) {
|
||||
onDone();
|
||||
if (state == UiaRequestState.loading) {
|
||||
state = UiaRequestState.waitForUser;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<T> completeStage(String type, [Map<String, dynamic> auth]) async {
|
||||
auth ??= <String, dynamic>{};
|
||||
auth['type'] = type;
|
||||
return await run(auth);
|
||||
}
|
||||
Future<T> completeStage(AuthenticationData auth) => _run(auth);
|
||||
|
||||
Set<String> getNextStages(
|
||||
List<AuthenticationFlow> flows, List<String> completed) {
|
||||
|
|
|
|||
|
|
@ -204,11 +204,14 @@ void main() {
|
|||
test('changePassword', () async {
|
||||
matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting');
|
||||
matrixApi.accessToken = '1234';
|
||||
await matrixApi.changePassword('1234', auth: {
|
||||
await matrixApi.changePassword(
|
||||
'1234',
|
||||
auth: AuthenticationData.fromJson({
|
||||
'type': 'example.type.foo',
|
||||
'session': 'xxxxx',
|
||||
'example_credential': 'verypoorsharedsecret'
|
||||
});
|
||||
}),
|
||||
);
|
||||
matrixApi.homeserver = matrixApi.accessToken = null;
|
||||
});
|
||||
test('resetPasswordUsingEmail', () async {
|
||||
|
|
@ -241,12 +244,14 @@ void main() {
|
|||
test('deactivateAccount', () async {
|
||||
matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting');
|
||||
matrixApi.accessToken = '1234';
|
||||
final response = await matrixApi
|
||||
.deactivateAccount(idServer: 'https://example.com', auth: {
|
||||
final response = await matrixApi.deactivateAccount(
|
||||
idServer: 'https://example.com',
|
||||
auth: AuthenticationData.fromJson({
|
||||
'type': 'example.type.foo',
|
||||
'session': 'xxxxx',
|
||||
'example_credential': 'verypoorsharedsecret'
|
||||
});
|
||||
}),
|
||||
);
|
||||
expect(response, IdServerUnbindResult.success);
|
||||
matrixApi.homeserver = matrixApi.accessToken = null;
|
||||
});
|
||||
|
|
@ -267,7 +272,8 @@ void main() {
|
|||
test('addThirdPartyIdentifier', () async {
|
||||
matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting');
|
||||
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;
|
||||
});
|
||||
test('bindThirdPartyIdentifier', () async {
|
||||
|
|
@ -1041,7 +1047,8 @@ void main() {
|
|||
matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting');
|
||||
matrixApi.accessToken = '1234';
|
||||
|
||||
await matrixApi.deleteDevice('QBUAZIFURK', auth: {});
|
||||
await matrixApi.deleteDevice('QBUAZIFURK',
|
||||
auth: AuthenticationData.fromJson({}));
|
||||
|
||||
matrixApi.homeserver = matrixApi.accessToken = null;
|
||||
});
|
||||
|
|
@ -1049,7 +1056,8 @@ void main() {
|
|||
matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting');
|
||||
matrixApi.accessToken = '1234';
|
||||
|
||||
await matrixApi.deleteDevices(['QBUAZIFURK'], auth: {});
|
||||
await matrixApi
|
||||
.deleteDevices(['QBUAZIFURK'], auth: AuthenticationData.fromJson({}));
|
||||
|
||||
matrixApi.homeserver = matrixApi.accessToken = null;
|
||||
});
|
||||
|
|
@ -1785,5 +1793,122 @@ void main() {
|
|||
['/client/unstable/room_keys/keys?version=5']({}),
|
||||
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;
|
||||
final request = UiaRequest(
|
||||
request: (auth) async {
|
||||
if (auth['session'] != null && auth['session'] != 'foxies') {
|
||||
if (auth.session != null && auth.session != 'foxies') {
|
||||
throw MatrixException.fromJson(<String, dynamic>{});
|
||||
}
|
||||
if (auth['type'] == 'stage1') {
|
||||
if (auth.type == 'stage1') {
|
||||
if (completed.isEmpty) {
|
||||
completed.add('stage1');
|
||||
}
|
||||
} else if (auth['type'] == 'stage2') {
|
||||
} else if (auth.type == 'stage2') {
|
||||
if (completed.length == 1 && completed[0] == 'stage1') {
|
||||
// okay, we are done!
|
||||
return 'FOXIES ARE FLOOOOOFY!!!!!';
|
||||
|
|
@ -54,24 +54,29 @@ void main() {
|
|||
};
|
||||
throw MatrixException.fromJson(res);
|
||||
},
|
||||
onUpdate: () => updated++,
|
||||
onDone: () => finished = true,
|
||||
onUpdate: (state) {
|
||||
if (state == UiaRequestState.done) {
|
||||
finished = true;
|
||||
}
|
||||
updated++;
|
||||
},
|
||||
);
|
||||
await Future.delayed(Duration(milliseconds: 50));
|
||||
expect(request.nextStages.contains('stage1'), true);
|
||||
expect(request.nextStages.length, 1);
|
||||
expect(updated, 1);
|
||||
expect(finished, false);
|
||||
await request.completeStage('stage1');
|
||||
await request.completeStage(AuthenticationData(type: 'stage1'));
|
||||
expect(request.nextStages.contains('stage2'), true);
|
||||
expect(request.nextStages.length, 1);
|
||||
expect(updated, 2);
|
||||
expect(updated, 3);
|
||||
expect(finished, false);
|
||||
final res = await request.completeStage('stage2');
|
||||
final res =
|
||||
await request.completeStage(AuthenticationData(type: 'stage2'));
|
||||
expect(res, 'FOXIES ARE FLOOOOOFY!!!!!');
|
||||
expect(request.result, 'FOXIES ARE FLOOOOOFY!!!!!');
|
||||
expect(request.done, true);
|
||||
expect(updated, 3);
|
||||
expect(request.state, UiaRequestState.done);
|
||||
expect(updated, 5);
|
||||
expect(finished, true);
|
||||
});
|
||||
test('it should throw errors', () async {
|
||||
|
|
@ -81,11 +86,15 @@ void main() {
|
|||
request: (auth) async {
|
||||
throw Exception('nope');
|
||||
},
|
||||
onUpdate: () => updated = true,
|
||||
onDone: () => finished = true,
|
||||
onUpdate: (state) {
|
||||
if (state == UiaRequestState.fail) {
|
||||
finished = true;
|
||||
}
|
||||
updated = true;
|
||||
},
|
||||
);
|
||||
await Future.delayed(Duration(milliseconds: 50));
|
||||
expect(request.fail, true);
|
||||
expect(request.state, UiaRequestState.fail);
|
||||
expect(updated, true);
|
||||
expect(finished, true);
|
||||
expect(request.error.toString(), Exception('nope').toString());
|
||||
|
|
|
|||
Loading…
Reference in New Issue