feat: Implement new sign in flow
This commit is contained in:
parent
f7932639e2
commit
4d7f0295ca
19 changed files with 944 additions and 559 deletions
72
lib/pages/sign_in/view_model/flows/check_homeserver.dart
Normal file
72
lib/pages/sign_in/view_model/flows/check_homeserver.dart
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
|
||||
import 'package:fluffychat/l10n/l10n.dart';
|
||||
import 'package:fluffychat/pages/sign_in/view_model/flows/sso_login.dart';
|
||||
import 'package:fluffychat/pages/sign_in/view_model/model/public_homeserver_data.dart';
|
||||
import 'package:fluffychat/utils/localized_exception_extension.dart';
|
||||
import 'package:fluffychat/utils/platform_infos.dart';
|
||||
import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
void connectToHomeserverFlow(
|
||||
PublicHomeserverData homeserverData,
|
||||
BuildContext context,
|
||||
void Function(AsyncSnapshot<bool>) setState,
|
||||
bool signUp,
|
||||
) async {
|
||||
setState(AsyncSnapshot.waiting());
|
||||
try {
|
||||
final homeserverInput = homeserverData.name!;
|
||||
var homeserver = Uri.parse(homeserverInput);
|
||||
if (homeserver.scheme.isEmpty) {
|
||||
homeserver = Uri.https(homeserverInput, '');
|
||||
}
|
||||
final l10n = L10n.of(context);
|
||||
final client = await Matrix.of(context).getLoginClient();
|
||||
final (_, _, loginFlows, _) = await client.checkHomeserver(homeserver);
|
||||
|
||||
final supportsSso = loginFlows.any((flow) => flow.type == 'm.login.sso');
|
||||
|
||||
if (!supportsSso) {
|
||||
final regLink = homeserverData.regLink;
|
||||
if (signUp && regLink != null) {
|
||||
await launchUrlString(regLink);
|
||||
}
|
||||
|
||||
final pathSegments = List.of(
|
||||
GoRouter.of(context).routeInformationProvider.value.uri.pathSegments,
|
||||
);
|
||||
pathSegments.removeLast();
|
||||
pathSegments.add('login');
|
||||
context.go('/${pathSegments.join('/')}', extra: client);
|
||||
setState(AsyncSnapshot.withData(ConnectionState.done, true));
|
||||
return;
|
||||
}
|
||||
if (kIsWeb || PlatformInfos.isLinux) {
|
||||
final consent = await showOkCancelAlertDialog(
|
||||
context: context,
|
||||
title: l10n.appWantsToUseForLogin(homeserverInput),
|
||||
message: l10n.appWantsToUseForLoginDescription,
|
||||
okLabel: l10n.continueText,
|
||||
);
|
||||
if (consent != OkCancelResult.ok) return;
|
||||
}
|
||||
await ssoLoginFlow(client, context, signUp);
|
||||
|
||||
setState(AsyncSnapshot.withData(ConnectionState.done, true));
|
||||
} catch (e, s) {
|
||||
setState(AsyncSnapshot.withError(ConnectionState.done, e, s));
|
||||
if (!context.mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
e.toLocalizedString(context, ExceptionContext.checkHomeserver),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
24
lib/pages/sign_in/view_model/flows/sort_homeservers.dart
Normal file
24
lib/pages/sign_in/view_model/flows/sort_homeservers.dart
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import 'package:fluffychat/pages/sign_in/view_model/model/public_homeserver_data.dart';
|
||||
|
||||
int sortHomeservers(PublicHomeserverData a, PublicHomeserverData b) {
|
||||
return _calcHomeserverScore(b).compareTo(_calcHomeserverScore(a));
|
||||
}
|
||||
|
||||
int _calcHomeserverScore(PublicHomeserverData homeserver) {
|
||||
var score = 0;
|
||||
if (homeserver.description?.isNotEmpty == true) score++;
|
||||
if (homeserver.homepage?.isNotEmpty == true) score++;
|
||||
score += (homeserver.languages?.length ?? 0);
|
||||
score += (homeserver.features?.length ?? 0);
|
||||
score += (homeserver.onlineStatus ?? 0);
|
||||
if (homeserver.ipv6 == true) score++;
|
||||
if (homeserver.isp?.isNotEmpty == true) score++;
|
||||
if (homeserver.privacy?.isNotEmpty == true) score++;
|
||||
if (homeserver.rules?.isNotEmpty == true) score++;
|
||||
if (homeserver.version?.isNotEmpty == true) score++;
|
||||
if (homeserver.usingVanillaReg == true) score--;
|
||||
if (homeserver.regLink != null) score--;
|
||||
if (homeserver.regMethod != 'SSO') score--;
|
||||
if (homeserver.regMethod == 'In-house Element') score--;
|
||||
return score;
|
||||
}
|
||||
49
lib/pages/sign_in/view_model/flows/sso_login.dart
Normal file
49
lib/pages/sign_in/view_model/flows/sso_login.dart
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:flutter_web_auth_2/flutter_web_auth_2.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
import 'package:universal_html/html.dart' as html;
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/utils/platform_infos.dart';
|
||||
|
||||
Future<void> ssoLoginFlow(
|
||||
Client client,
|
||||
BuildContext context,
|
||||
bool signUp,
|
||||
) async {
|
||||
final redirectUrl = kIsWeb
|
||||
? Uri.parse(
|
||||
html.window.location.href,
|
||||
).resolveUri(Uri(pathSegments: ['auth.html'])).toString()
|
||||
: (PlatformInfos.isMobile || PlatformInfos.isWeb || PlatformInfos.isMacOS)
|
||||
? '${AppConfig.appOpenUrlScheme.toLowerCase()}://login'
|
||||
: 'http://localhost:3001//login';
|
||||
|
||||
final url = client.homeserver!.replace(
|
||||
path: '/_matrix/client/v3/login/sso/redirect',
|
||||
queryParameters: {
|
||||
'redirectUrl': redirectUrl,
|
||||
'action': signUp ? 'register' : 'login',
|
||||
},
|
||||
);
|
||||
|
||||
final urlScheme =
|
||||
(PlatformInfos.isMobile || PlatformInfos.isWeb || PlatformInfos.isMacOS)
|
||||
? Uri.parse(redirectUrl).scheme
|
||||
: "http://localhost:3001";
|
||||
final result = await FlutterWebAuth2.authenticate(
|
||||
url: url.toString(),
|
||||
callbackUrlScheme: urlScheme,
|
||||
options: FlutterWebAuth2Options(useWebview: PlatformInfos.isMobile),
|
||||
);
|
||||
final token = Uri.parse(result).queryParameters['loginToken'];
|
||||
if (token?.isEmpty ?? false) return;
|
||||
|
||||
await client.login(
|
||||
LoginType.mLoginToken,
|
||||
token: token,
|
||||
initialDeviceDisplayName: PlatformInfos.clientName,
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue