mirror of
https://github.com/Dr-Blank/Vaani.git
synced 2025-12-06 02:59:28 +00:00
* feat: add fadeSlideTransitionBuilder for smoother transitions in user login * fix: reuse onboarding components on server manager page * fix: gaining focus rebuilt the widget using memoized fixes this issue
121 lines
3.9 KiB
Dart
121 lines
3.9 KiB
Dart
import 'dart:io';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
import 'package:shelfsdk/audiobookshelf_api.dart';
|
|
import 'package:vaani/api/api_provider.dart';
|
|
import 'package:vaani/features/onboarding/providers/oauth_provider.dart';
|
|
import 'package:vaani/features/onboarding/view/user_login_with_password.dart';
|
|
import 'package:vaani/main.dart';
|
|
import 'package:vaani/models/error_response.dart';
|
|
import 'package:vaani/router/router.dart';
|
|
import 'package:vaani/settings/constants.dart';
|
|
import 'package:vaani/settings/models/models.dart' as model;
|
|
import 'package:vaani/shared/extensions/obfuscation.dart';
|
|
import 'package:vaani/shared/utils.dart';
|
|
|
|
class UserLoginWithOpenID extends HookConsumerWidget {
|
|
UserLoginWithOpenID({
|
|
super.key,
|
|
required this.server,
|
|
required this.addServer,
|
|
this.openIDButtonText,
|
|
this.onSuccess,
|
|
});
|
|
|
|
final Uri server;
|
|
final model.AudiobookShelfServer Function() addServer;
|
|
final String? openIDButtonText;
|
|
final responseErrorHandler = ErrorResponseHandler(name: 'OpenID');
|
|
final Function(model.AuthenticatedUser)? onSuccess;
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
final serverStatus = ref.watch(serverStatusProvider(server));
|
|
void openIDLoginFlow() async {
|
|
appLogger.fine('Clicked Login with OpenID');
|
|
|
|
final api = ref.read(audiobookshelfApiProvider(server));
|
|
final (verifier, challenge) = generateVerifierAndChallenge();
|
|
|
|
appLogger.fine('Generated verifier: $verifier\nchallenge: $challenge');
|
|
final appRedirectUri =
|
|
'${AppMetadata.appScheme}://${Routes.openIDCallback.fullPath.substring(1)}';
|
|
final (openIDLoginEndpoint, authCookie) = await api.server.oauth2Request(
|
|
clientId: AppMetadata.appName,
|
|
codeChallenge: challenge,
|
|
// redirectUri: Uri(
|
|
// scheme: AppMetadata.appScheme,
|
|
// host: Routes.openIDCallback.path.substring(1),
|
|
// ).toString(),
|
|
redirectUri: appRedirectUri,
|
|
responseErrorHandler: responseErrorHandler.storeError,
|
|
);
|
|
|
|
if (openIDLoginEndpoint == null) {
|
|
if (responseErrorHandler.response.statusCode == 400 &&
|
|
responseErrorHandler.response.body
|
|
.toLowerCase()
|
|
.contains(RegExp(r'invalid.*redirect.*uri'))) {
|
|
// show error
|
|
handleServerError(
|
|
context,
|
|
responseErrorHandler,
|
|
title: 'Failed to get OpenID login endpoint\n',
|
|
body:
|
|
'Please check that the redirect URI: "$appRedirectUri" is registered with the server.',
|
|
outLink: server.replace(path: '${Routes.settings.fullPath}/auth'),
|
|
outLinkText: 'Server settings',
|
|
);
|
|
return;
|
|
}
|
|
|
|
// show error
|
|
handleServerError(
|
|
context,
|
|
responseErrorHandler,
|
|
title: 'Failed to get OpenID login endpoint',
|
|
);
|
|
return;
|
|
}
|
|
|
|
// extract the state parameter
|
|
final oauthState = openIDLoginEndpoint.queryParameters['state'];
|
|
|
|
if (oauthState == null) {
|
|
handleServerError(
|
|
context,
|
|
responseErrorHandler,
|
|
title: 'Failed to get OpenID login endpoint',
|
|
body: 'No state parameter found in the response',
|
|
);
|
|
return;
|
|
}
|
|
|
|
appLogger.fine(
|
|
'Got OpenID login endpoint: ${openIDLoginEndpoint.obfuscate()}',
|
|
);
|
|
|
|
// add the flow to the provider
|
|
ref.read(oauthFlowsProvider.notifier).addFlow(
|
|
oauthState,
|
|
verifier: verifier,
|
|
serverUri: server,
|
|
cookie: Cookie.fromSetCookieValue(authCookie!),
|
|
);
|
|
|
|
await handleLaunchUrl(
|
|
openIDLoginEndpoint,
|
|
);
|
|
}
|
|
|
|
return Column(
|
|
children: [
|
|
ElevatedButton(
|
|
onPressed: openIDLoginFlow,
|
|
child: Text(openIDButtonText ?? 'Login with OpenID'),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|