🐛 Fixes some bugs in OIDC
This commit is contained in:
@ -174,7 +174,14 @@ class AccountSettingsScreen extends HookConsumerWidget {
|
||||
)
|
||||
: Text(connection.providedIdentifier),
|
||||
leading: CircleAvatar(
|
||||
child: Icon(getProviderIcon(connection.provider)),
|
||||
child: getProviderIcon(
|
||||
connection.provider,
|
||||
size: 16,
|
||||
color:
|
||||
Theme.of(
|
||||
context,
|
||||
).colorScheme.onPrimaryContainer,
|
||||
),
|
||||
).padding(top: 4),
|
||||
trailing: const Icon(Symbols.chevron_right),
|
||||
isThreeLine: true,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/auth.dart';
|
||||
@ -17,20 +17,24 @@ import 'package:sign_in_with_apple/sign_in_with_apple.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
|
||||
// Helper function to get provider icon and localized name
|
||||
IconData getProviderIcon(String provider) {
|
||||
switch (provider.toLowerCase()) {
|
||||
Widget getProviderIcon(String provider, {double size = 24, Color? color}) {
|
||||
final providerLower = provider.toLowerCase();
|
||||
|
||||
// Check if we have an SVG for this provider
|
||||
switch (providerLower) {
|
||||
case 'apple':
|
||||
return Icons.apple;
|
||||
case 'microsoft':
|
||||
return Symbols.window; // Microsoft icon alternative
|
||||
case 'google':
|
||||
return Symbols.g_translate; // Google icon alternative
|
||||
case 'github':
|
||||
return Symbols.code; // GitHub icon
|
||||
case 'discord':
|
||||
return Symbols.forum; // Discord icon alternative
|
||||
return SvgPicture.asset(
|
||||
'assets/images/oidc/$providerLower.svg',
|
||||
width: size,
|
||||
height: size,
|
||||
color: color,
|
||||
);
|
||||
default:
|
||||
return Symbols.link;
|
||||
return Icon(Symbols.link, size: size);
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,7 +88,11 @@ class AccountConnectionSheet extends HookConsumerWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(getProviderIcon(connection.provider), size: 32),
|
||||
getProviderIcon(
|
||||
connection.provider,
|
||||
size: 32,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
const Gap(8),
|
||||
Text(getLocalizedProviderName(connection.provider)).tr(),
|
||||
const Gap(4),
|
||||
@ -161,15 +169,15 @@ class AccountConnectionNewSheet extends HookConsumerWidget {
|
||||
case 'google':
|
||||
case 'github':
|
||||
case 'discord':
|
||||
final token = await Navigator.of(context).push(
|
||||
await Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder:
|
||||
(context) => OidcScreen(
|
||||
provider: selectedProvider.value.toLowerCase(),
|
||||
title: 'Connect with ${selectedProvider.value}',
|
||||
),
|
||||
),
|
||||
);
|
||||
print(token);
|
||||
break;
|
||||
default:
|
||||
showSnackBar(context, 'accountConnectionAddError'.tr());
|
||||
@ -186,7 +194,11 @@ class AccountConnectionNewSheet extends HookConsumerWidget {
|
||||
DropdownButtonFormField<String>(
|
||||
value: selectedProvider.value,
|
||||
decoration: InputDecoration(
|
||||
prefixIcon: Icon(getProviderIcon(selectedProvider.value)),
|
||||
prefixIcon: getProviderIcon(
|
||||
selectedProvider.value,
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
).padding(all: 16),
|
||||
labelText: 'accountConnectionProvider'.tr(),
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
@ -304,8 +316,9 @@ class AccountConnectionsSheet extends HookConsumerWidget {
|
||||
return false;
|
||||
},
|
||||
child: ListTile(
|
||||
leading: Icon(
|
||||
getProviderIcon(connection.provider),
|
||||
leading: getProviderIcon(
|
||||
connection.provider,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
title:
|
||||
Text(
|
||||
|
@ -11,8 +11,6 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:flutter_otp_text_field/flutter_otp_text_field.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:google_sign_in/google_sign_in.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:island/models/auth.dart';
|
||||
@ -20,6 +18,7 @@ import 'package:island/pods/config.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/pods/userinfo.dart';
|
||||
import 'package:island/pods/websocket.dart';
|
||||
import 'package:island/screens/account/me/settings_connections.dart';
|
||||
import 'package:island/services/notify.dart';
|
||||
import 'package:island/services/udid.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
@ -271,7 +270,6 @@ class _LoginCheckScreen extends HookConsumerWidget {
|
||||
],
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: 'password'.tr(),
|
||||
),
|
||||
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||
@ -292,14 +290,12 @@ class _LoginCheckScreen extends HookConsumerWidget {
|
||||
textStyle: Theme.of(context).textTheme.titleLarge!,
|
||||
),
|
||||
const Gap(12),
|
||||
Card(
|
||||
child: ListTile(
|
||||
leading: Icon(
|
||||
kFactorTypes[factor!.type]?.$3 ?? Symbols.question_mark,
|
||||
),
|
||||
title: Text(kFactorTypes[factor!.type]?.$1 ?? 'unknown').tr(),
|
||||
subtitle: Text(kFactorTypes[factor!.type]?.$2 ?? 'unknown').tr(),
|
||||
ListTile(
|
||||
leading: Icon(
|
||||
kFactorTypes[factor!.type]?.$3 ?? Symbols.question_mark,
|
||||
),
|
||||
title: Text(kFactorTypes[factor!.type]?.$1 ?? 'unknown').tr(),
|
||||
subtitle: Text(kFactorTypes[factor!.type]?.$2 ?? 'unknown').tr(),
|
||||
),
|
||||
const Gap(12),
|
||||
Row(
|
||||
@ -604,25 +600,6 @@ class _LoginLookupScreen extends HookConsumerWidget {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> withGoogle() async {
|
||||
// TODO This crashes for no reason
|
||||
GoogleSignIn gsi = GoogleSignIn(
|
||||
clientId:
|
||||
kIsWeb
|
||||
? '961776991058-963m1qin2vtp8fv693b5fdrab5hmpl89.apps.googleusercontent.com'
|
||||
: (Platform.isIOS || Platform.isMacOS)
|
||||
? '961776991058-stt7et4qvn3cpscl4r61gl1hnlatqkig.apps.googleusercontent.com'
|
||||
: '961776991058-r4iv9qoio57ul7utbfpgfrda2etvtch8.apps.googleusercontent.com',
|
||||
scopes: ['openid', 'https://www.googleapis.com/auth/userinfo.email'],
|
||||
);
|
||||
|
||||
try {
|
||||
var ga = await gsi.signIn();
|
||||
} catch (err) {
|
||||
showErrorAlert(err);
|
||||
}
|
||||
}
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@ -658,28 +635,13 @@ class _LoginLookupScreen extends HookConsumerWidget {
|
||||
Text("loginOr").tr().fontSize(11).opacity(0.85),
|
||||
const Gap(8),
|
||||
Spacer(),
|
||||
// IconButton.filledTonal(
|
||||
// // onPressed: withGoogle,
|
||||
// padding: EdgeInsets.zero,
|
||||
// icon: SvgPicture.asset(
|
||||
// 'assets/images/oidc/google.svg',
|
||||
// width: 16,
|
||||
// height: 16,
|
||||
// ),
|
||||
// tooltip: 'Google',
|
||||
// ),
|
||||
IconButton.filledTonal(
|
||||
onPressed: withApple,
|
||||
padding: EdgeInsets.zero,
|
||||
icon: SvgPicture.asset(
|
||||
'assets/images/oidc/apple.svg',
|
||||
width: 16,
|
||||
height: 16,
|
||||
color:
|
||||
MediaQuery.of(context).platformBrightness ==
|
||||
Brightness.light
|
||||
? Colors.black54
|
||||
: Colors.white,
|
||||
icon: getProviderIcon(
|
||||
"apple",
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.onPrimaryContainer,
|
||||
),
|
||||
tooltip: 'Apple Account',
|
||||
),
|
||||
|
@ -1,36 +1,55 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:island/pods/config.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
|
||||
class OidcScreen extends ConsumerStatefulWidget {
|
||||
final String provider;
|
||||
final String? title;
|
||||
|
||||
const OidcScreen({super.key, required this.provider});
|
||||
const OidcScreen({super.key, required this.provider, this.title});
|
||||
|
||||
@override
|
||||
ConsumerState<OidcScreen> createState() => _OIDCScreenState();
|
||||
ConsumerState<OidcScreen> createState() => _OidcScreenState();
|
||||
}
|
||||
|
||||
class _OIDCScreenState extends ConsumerState<OidcScreen> {
|
||||
InAppWebViewController? _webViewController;
|
||||
class _OidcScreenState extends ConsumerState<OidcScreen> {
|
||||
String? authToken;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final serverUrl = ref.watch(serverUrlProvider);
|
||||
final token = ref.watch(tokenProvider);
|
||||
|
||||
return AppScaffold(
|
||||
appBar: AppBar(title: Text('login').tr()),
|
||||
appBar: AppBar(
|
||||
title: widget.title != null ? Text(widget.title!) : Text('login').tr(),
|
||||
),
|
||||
body: InAppWebView(
|
||||
initialSettings: InAppWebViewSettings(
|
||||
userAgent:
|
||||
kIsWeb
|
||||
? null
|
||||
: Platform.isIOS
|
||||
? 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1'
|
||||
: Platform.isAndroid
|
||||
? 'Mozilla/5.0 (Linux; Android 13) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/537.36'
|
||||
: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
|
||||
),
|
||||
initialUrlRequest: URLRequest(
|
||||
url: WebUri('$serverUrl/auth/login/${widget.provider}'),
|
||||
url: WebUri(
|
||||
(token?.token.isNotEmpty ?? false)
|
||||
? '$serverUrl/auth/login/${widget.provider}?tk=${token!.token}'
|
||||
: '$serverUrl/auth/login/${widget.provider}',
|
||||
),
|
||||
),
|
||||
onWebViewCreated: (controller) {
|
||||
_webViewController = controller;
|
||||
|
||||
// Register a handler to receive the token from JavaScript
|
||||
controller.addJavaScriptHandler(
|
||||
handlerName: 'tokenHandler',
|
||||
|
@ -4,20 +4,22 @@ import 'dart:ui_web' as ui;
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:island/pods/config.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:web/web.dart' as web;
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class OidcScreen extends ConsumerStatefulWidget {
|
||||
final String provider;
|
||||
final String? title;
|
||||
|
||||
const OidcScreen({super.key, required this.provider});
|
||||
const OidcScreen({super.key, required this.provider, this.title});
|
||||
|
||||
@override
|
||||
ConsumerState<OidcScreen> createState() => _OIDCScreenState();
|
||||
ConsumerState<OidcScreen> createState() => _OidcScreenState();
|
||||
}
|
||||
|
||||
class _OIDCScreenState extends ConsumerState<OidcScreen> {
|
||||
class _OidcScreenState extends ConsumerState<OidcScreen> {
|
||||
bool _isInitialized = false;
|
||||
final String _viewType = 'oidc-iframe';
|
||||
|
||||
@ -29,15 +31,19 @@ class _OIDCScreenState extends ConsumerState<OidcScreen> {
|
||||
if (message.startsWith("token=")) {
|
||||
String token = message.replaceFirst("token=", "");
|
||||
// Return the token and close the screen
|
||||
if (context.mounted) Navigator.pop(context, token);
|
||||
if (mounted) Navigator.pop(context, token);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Create the iframe for the OIDC login
|
||||
final token = ref.watch(tokenProvider);
|
||||
final iframe =
|
||||
web.HTMLIFrameElement()
|
||||
..src = '$serverUrl/auth/login/${widget.provider}'
|
||||
..src =
|
||||
(token?.token.isNotEmpty ?? false)
|
||||
? '$serverUrl/auth/login/${widget.provider}?tk=${token!.token}'
|
||||
: '$serverUrl/auth/login/${widget.provider}'
|
||||
..style.border = 'none'
|
||||
..width = '100%'
|
||||
..height = '100%';
|
||||
@ -68,7 +74,9 @@ class _OIDCScreenState extends ConsumerState<OidcScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AppScaffold(
|
||||
appBar: AppBar(title: Text('login').tr()),
|
||||
appBar: AppBar(
|
||||
title: widget.title != null ? Text(widget.title!) : Text('login').tr(),
|
||||
),
|
||||
body:
|
||||
_isInitialized
|
||||
? HtmlElementView(viewType: _viewType)
|
||||
|
Reference in New Issue
Block a user