fix: SSO on web hopefully

This commit is contained in:
Christian Pauly 2021-06-06 17:07:19 +02:00
parent f6082c5bac
commit cefa4be534
2 changed files with 68 additions and 55 deletions

View File

@ -1,12 +1,21 @@
import 'dart:async';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/pages/views/homeserver_picker_view.dart'; import 'package:fluffychat/pages/views/homeserver_picker_view.dart';
import 'package:fluffychat/widgets/matrix.dart'; import 'package:fluffychat/widgets/matrix.dart';
import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart'; import 'package:fluffychat/config/setting_keys.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../utils/localized_exception_extension.dart'; import '../utils/localized_exception_extension.dart';
import 'package:vrouter/vrouter.dart'; import 'package:vrouter/vrouter.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:uni_links/uni_links.dart';
import 'package:universal_html/html.dart' as html;
import '../main.dart';
class HomeserverPicker extends StatefulWidget { class HomeserverPicker extends StatefulWidget {
@override @override
@ -18,6 +27,55 @@ class HomeserverPickerController extends State<HomeserverPicker> {
String domain = AppConfig.defaultHomeserver; String domain = AppConfig.defaultHomeserver;
final TextEditingController homeserverController = final TextEditingController homeserverController =
TextEditingController(text: AppConfig.defaultHomeserver); TextEditingController(text: AppConfig.defaultHomeserver);
StreamSubscription _intentDataStreamSubscription;
void _loginWithToken(String token) {
if (token?.isEmpty ?? true) return;
showFutureLoadingDialog(
context: context,
future: () => Matrix.of(context).client.login(
type: AuthenticationTypes.token,
token: token,
initialDeviceDisplayName: PlatformInfos.clientName,
),
);
}
void _processIncomingUris(String text) async {
if (text == null || !text.startsWith(AppConfig.appOpenUrlScheme)) return;
VRouter.of(context).push('/home');
final token = Uri.parse(text).queryParameters['loginToken'];
if (token != null) _loginWithToken(token);
}
void _initReceiveUri() {
if (!PlatformInfos.isMobile) return;
// For receiving shared Uris
_intentDataStreamSubscription = linkStream.listen(_processIncomingUris);
if (FluffyChatApp.gotInitialLink == false) {
FluffyChatApp.gotInitialLink = true;
getInitialLink().then(_processIncomingUris);
}
}
@override
void initState() {
super.initState();
_initReceiveUri();
if (kIsWeb) {
WidgetsBinding.instance.addPostFrameCallback((_) {
final token =
Uri.parse(html.window.location.href).queryParameters['loginToken'];
_loginWithToken(token);
});
}
}
@override
void dispose() {
super.dispose();
_intentDataStreamSubscription?.cancel();
}
/// Starts an analysis of the given homeserver. It uses the current domain and /// Starts an analysis of the given homeserver. It uses the current domain and
/// makes sure that it is prefixed with https. Then it searches for the /// makes sure that it is prefixed with https. Then it searches for the

View File

@ -3,19 +3,14 @@ import 'dart:async';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pages/views/sign_up_view.dart'; import 'package:fluffychat/pages/views/sign_up_view.dart';
import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/utils/famedlysdk_store.dart';
import 'package:fluffychat/widgets/matrix.dart'; import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:uni_links/uni_links.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'package:universal_html/html.dart' as html; import 'package:universal_html/html.dart' as html;
import 'package:vrouter/vrouter.dart';
import '../main.dart';
class SignUp extends StatefulWidget { class SignUp extends StatefulWidget {
@override @override
@ -25,7 +20,7 @@ class SignUp extends StatefulWidget {
class SignUpController extends State<SignUp> { class SignUpController extends State<SignUp> {
Map<String, dynamic> _rawLoginTypes; Map<String, dynamic> _rawLoginTypes;
bool registrationSupported; bool registrationSupported;
StreamSubscription _intentDataStreamSubscription;
List<IdentityProvider> get identityProviders { List<IdentityProvider> get identityProviders {
if (!ssoLoginSupported) return []; if (!ssoLoginSupported) return [];
final rawProviders = _rawLoginTypes.tryGetList('flows').singleWhere( final rawProviders = _rawLoginTypes.tryGetList('flows').singleWhere(
@ -36,54 +31,6 @@ class SignUpController extends State<SignUp> {
.toList(); .toList();
} }
void _loginWithToken(String token) {
if (token?.isEmpty ?? true) return;
showFutureLoadingDialog(
context: context,
future: () => Matrix.of(context).client.login(
type: AuthenticationTypes.token,
token: token,
initialDeviceDisplayName: PlatformInfos.clientName,
),
);
}
void _processIncomingUris(String text) async {
if (text == null || !text.startsWith(AppConfig.appOpenUrlScheme)) return;
VRouter.of(context).push('/home');
final token = Uri.parse(text).queryParameters['loginToken'];
if (token != null) _loginWithToken(token);
}
void _initReceiveUri() {
if (!PlatformInfos.isMobile) return;
// For receiving shared Uris
_intentDataStreamSubscription = linkStream.listen(_processIncomingUris);
if (FluffyChatApp.gotInitialLink == false) {
FluffyChatApp.gotInitialLink = true;
getInitialLink().then(_processIncomingUris);
}
}
@override
void initState() {
super.initState();
_initReceiveUri();
if (kIsWeb) {
WidgetsBinding.instance.addPostFrameCallback((_) {
final token =
Uri.parse(html.window.location.href).queryParameters['loginToken'];
_loginWithToken(token);
});
}
}
@override
void dispose() {
super.dispose();
_intentDataStreamSubscription?.cancel();
}
bool get passwordLoginSupported => bool get passwordLoginSupported =>
Matrix.of(context) Matrix.of(context)
.client .client
@ -118,7 +65,15 @@ class SignUpController extends State<SignUp> {
return _rawLoginTypes; return _rawLoginTypes;
} }
static const String _ssoHomeserverKey = 'sso-homeserver';
void ssoLoginAction(String id) { void ssoLoginAction(String id) {
if (kIsWeb) {
// We store the homserver in the local storage instead of a redirect
// parameter because of possible CSRF attacks.
Store().setItem(
_ssoHomeserverKey, Matrix.of(context).client.homeserver.toString());
}
final redirectUrl = kIsWeb final redirectUrl = kIsWeb
? html.window.location.href ? html.window.location.href
: AppConfig.appOpenUrlScheme.toLowerCase() + '://sso'; : AppConfig.appOpenUrlScheme.toLowerCase() + '://sso';