diff --git a/lib/features/login/data/network/authentication_client/authentication_client_base.dart b/lib/features/login/data/network/authentication_client/authentication_client_base.dart index 4fbd79eeba..75ef41ac29 100644 --- a/lib/features/login/data/network/authentication_client/authentication_client_base.dart +++ b/lib/features/login/data/network/authentication_client/authentication_client_base.dart @@ -1,4 +1,3 @@ - import 'package:model/oidc/oidc_configuration.dart'; import 'package:model/oidc/response/oidc_discovery_response.dart'; import 'package:model/oidc/token_id.dart'; diff --git a/lib/features/login/data/network/authentication_client/authentication_client_interaction_mixin.dart b/lib/features/login/data/network/authentication_client/authentication_client_interaction_mixin.dart new file mode 100644 index 0000000000..a70eb3aa9d --- /dev/null +++ b/lib/features/login/data/network/authentication_client/authentication_client_interaction_mixin.dart @@ -0,0 +1,88 @@ +import 'package:core/utils/app_logger.dart'; +import 'package:core/utils/platform_info.dart'; +import 'package:flutter_appauth_platform_interface/flutter_appauth_platform_interface.dart'; +import 'package:model/oidc/oidc_configuration.dart'; +import 'package:model/oidc/response/oidc_discovery_response.dart'; +import 'package:model/oidc/token_id.dart'; +import 'package:tmail_ui_user/features/login/domain/exceptions/oauth_authorization_error.dart'; +import 'package:tmail_ui_user/features/login/domain/extensions/oidc_configuration_extensions.dart'; + +mixin AuthenticationClientInteractionMixin { + EndSessionRequest getEndSessionRequest( + TokenId tokenId, + OIDCConfiguration config, + OIDCDiscoveryResponse discoveryResponse, + ) { + final authorizationEndpoint = discoveryResponse.authorizationEndpoint; + final tokenEndpoint = discoveryResponse.tokenEndpoint; + AuthorizationServiceConfiguration? serviceConfiguration; + + if (authorizationEndpoint != null && tokenEndpoint != null) { + serviceConfiguration = AuthorizationServiceConfiguration( + authorizationEndpoint: authorizationEndpoint, + tokenEndpoint: tokenEndpoint, + endSessionEndpoint: discoveryResponse.endSessionEndpoint, + ); + } + + return EndSessionRequest( + idTokenHint: tokenId.uuid, + postLogoutRedirectUrl: config.logoutRedirectUrl, + discoveryUrl: config.discoveryUrl, + serviceConfiguration: serviceConfiguration, + externalUserAgent: getExternalUserAgent(), + ); + } + + ExternalUserAgent getExternalUserAgent() => PlatformInfo.isIOS + ? ExternalUserAgent.ephemeralAsWebAuthenticationSession + : ExternalUserAgent.asWebAuthenticationSession; + + TokenRequest getRefreshTokenRequest( + String clientId, + String redirectUrl, + String discoveryUrl, + String refreshToken, + List scopes, + ) { + return TokenRequest( + clientId, + redirectUrl, + discoveryUrl: discoveryUrl, + refreshToken: refreshToken, + grantType: GrantType.refreshToken, + scopes: scopes, + ); + } + + AuthorizationTokenRequest getAuthorizationTokenRequest( + String clientId, + String redirectUrl, + String discoveryUrl, + List scopes, + ) { + return AuthorizationTokenRequest( + clientId, + redirectUrl, + discoveryUrl: discoveryUrl, + scopes: scopes, + externalUserAgent: getExternalUserAgent(), + ); + } + + dynamic handleException(dynamic exception) { + if (exception is FlutterAppAuthPlatformException) { + logError('$runtimeType::handleException: ErrorDetails = ${exception.platformErrorDetails.toString()}'); + final errorCode = exception.platformErrorDetails.error; + if (errorCode != null) { + final oauthErrorCode = OAuthAuthorizationError.fromErrorCode( + errorCode, + errorDescription: exception.platformErrorDetails.errorDescription, + ); + return oauthErrorCode; + } + } + + return exception; + } +} diff --git a/lib/features/login/data/network/authentication_client/authentication_client_mobile.dart b/lib/features/login/data/network/authentication_client/authentication_client_mobile.dart index 4eecf70cfb..4671d7af9f 100644 --- a/lib/features/login/data/network/authentication_client/authentication_client_mobile.dart +++ b/lib/features/login/data/network/authentication_client/authentication_client_mobile.dart @@ -10,82 +10,88 @@ import 'package:model/oidc/token_oidc.dart'; import 'package:tmail_ui_user/features/login/data/extensions/authentication_token_extension.dart'; import 'package:tmail_ui_user/features/login/data/extensions/token_response_extension.dart'; import 'package:tmail_ui_user/features/login/data/network/authentication_client/authentication_client_base.dart'; +import 'package:tmail_ui_user/features/login/data/network/authentication_client/authentication_client_interaction_mixin.dart'; import 'package:tmail_ui_user/features/login/data/network/config/oidc_constant.dart'; import 'package:tmail_ui_user/features/login/domain/exceptions/authentication_exception.dart'; import 'package:tmail_ui_user/features/login/domain/extensions/oidc_configuration_extensions.dart'; -class AuthenticationClientMobile implements AuthenticationClientBase { +class AuthenticationClientMobile with AuthenticationClientInteractionMixin + implements AuthenticationClientBase { final FlutterAppAuth _appAuth; AuthenticationClientMobile(this._appAuth); @override - Future getTokenOIDC(String clientId, String redirectUrl, - String discoveryUrl, List scopes) async { + Future getTokenOIDC( + String clientId, + String redirectUrl, + String discoveryUrl, + List scopes, + ) async { + final authorizationTokenRequest = getAuthorizationTokenRequest( + clientId, + redirectUrl, + discoveryUrl, + scopes, + ); final authorizationTokenResponse = await _appAuth.authorizeAndExchangeCode( - AuthorizationTokenRequest( - clientId, - redirectUrl, - discoveryUrl: discoveryUrl, - scopes: scopes, - preferEphemeralSession: true)); - - log('AuthenticationClientMobile::getTokenOIDC(): token: ${authorizationTokenResponse?.accessToken}'); - - if (authorizationTokenResponse != null) { - final tokenOIDC = authorizationTokenResponse.toTokenOIDC(); - if (tokenOIDC.isTokenValid()) { - return tokenOIDC; - } else { - throw AccessTokenInvalidException(); - } + authorizationTokenRequest, + ); + log('$runtimeType::getTokenOIDC(): token: ${authorizationTokenResponse.accessToken}'); + final tokenOIDC = authorizationTokenResponse.toTokenOIDC(); + if (tokenOIDC.isTokenValid()) { + return tokenOIDC; } else { - throw NotFoundAccessTokenException(); + throw AccessTokenInvalidException(); } } @override - Future logoutOidc(TokenId tokenId, OIDCConfiguration config, OIDCDiscoveryResponse oidcRescovery) async { - final authorizationServiceConfiguration = oidcRescovery.authorizationEndpoint == null || oidcRescovery.tokenEndpoint == null - ? null - : AuthorizationServiceConfiguration( - authorizationEndpoint: oidcRescovery.authorizationEndpoint!, - tokenEndpoint: oidcRescovery.tokenEndpoint!, - endSessionEndpoint: oidcRescovery.endSessionEndpoint); - - final endSession = await _appAuth.endSession(EndSessionRequest( - idTokenHint: tokenId.uuid, - postLogoutRedirectUrl: config.logoutRedirectUrl, - discoveryUrl: config.discoveryUrl, - serviceConfiguration: authorizationServiceConfiguration, - preferEphemeralSession: true, - )); - log('AuthenticationClientMobile::logoutOidc(): ${endSession?.state}'); - return endSession?.state?.isNotEmpty == true; + Future logoutOidc( + TokenId tokenId, + OIDCConfiguration config, + OIDCDiscoveryResponse discoveryResponse, + ) async { + final endSessionRequest = getEndSessionRequest( + tokenId, + config, + discoveryResponse, + ); + final endSession = await _appAuth.endSession(endSessionRequest); + log('$runtimeType::logoutOidc(): ${endSession.state}'); + return endSession.state?.isNotEmpty == true; } @override - Future refreshingTokensOIDC(String clientId, String redirectUrl, - String discoveryUrl, List scopes, String refreshToken) async { - final tokenResponse = await _appAuth.token(TokenRequest( + Future refreshingTokensOIDC( + String clientId, + String redirectUrl, + String discoveryUrl, + List scopes, + String refreshToken, + ) async { + try { + final tokenRequest = getRefreshTokenRequest( clientId, redirectUrl, - discoveryUrl: discoveryUrl, - refreshToken: refreshToken, - scopes: scopes)); - - log('AuthenticationClientMobile::refreshingTokensOIDC(): refreshToken: ${tokenResponse?.accessToken}'); - - if (tokenResponse != null) { - final tokenOIDC = tokenResponse.toTokenOIDC(maybeAvailableRefreshToken: refreshToken); + discoveryUrl, + refreshToken, + scopes, + ); + final tokenResponse = await _appAuth.token(tokenRequest); + log('$runtimeType::refreshingTokensOIDC():Token: ${tokenResponse.accessToken}'); + final tokenOIDC = tokenResponse.toTokenOIDC( + maybeAvailableRefreshToken: refreshToken, + ); if (tokenOIDC.isTokenValid()) { return tokenOIDC; } else { throw AccessTokenInvalidException(); } - } else { - throw NotFoundAccessTokenException(); + } catch (e) { + logError('$runtimeType::refreshingTokensOIDC(): $e'); + throw handleException(e); } } @@ -104,7 +110,7 @@ class AuthenticationClientMobile implements AuthenticationClientBase { intentFlags: ephemeralIntentFlags, ), ); - log('AuthenticationClientMobile::signInTwakeWorkplace():Uri = $uri'); + log('$runtimeType::signInTwakeWorkplace():Uri = $uri'); return TokenOIDC.fromUri(uri); } @@ -117,7 +123,7 @@ class AuthenticationClientMobile implements AuthenticationClientBase { intentFlags: ephemeralIntentFlags, ), ); - log('AuthenticationClientMobile::signUpTwakeWorkplace():Uri = $uri'); + log('$runtimeType::signUpTwakeWorkplace():Uri = $uri'); return TokenOIDC.fromUri(uri); } } diff --git a/lib/features/login/data/network/authentication_client/authentication_client_web.dart b/lib/features/login/data/network/authentication_client/authentication_client_web.dart index 0f58a9e939..e0a66d5e4e 100644 --- a/lib/features/login/data/network/authentication_client/authentication_client_web.dart +++ b/lib/features/login/data/network/authentication_client/authentication_client_web.dart @@ -9,89 +9,104 @@ import 'package:model/oidc/token_oidc.dart'; import 'package:tmail_ui_user/features/login/data/extensions/authentication_token_extension.dart'; import 'package:tmail_ui_user/features/login/data/extensions/token_response_extension.dart'; import 'package:tmail_ui_user/features/login/data/network/authentication_client/authentication_client_base.dart'; +import 'package:tmail_ui_user/features/login/data/network/authentication_client/authentication_client_interaction_mixin.dart'; import 'package:tmail_ui_user/features/login/data/utils/library_platform/app_auth_plugin/app_auth_plugin.dart'; import 'package:tmail_ui_user/features/login/domain/exceptions/authentication_exception.dart'; -import 'package:tmail_ui_user/features/login/domain/extensions/oidc_configuration_extensions.dart'; -class AuthenticationClientWeb implements AuthenticationClientBase { +class AuthenticationClientWeb with AuthenticationClientInteractionMixin + implements AuthenticationClientBase { final AppAuthWebPlugin _appAuthWeb; AuthenticationClientWeb(this._appAuthWeb); @override - Future getTokenOIDC(String clientId, String redirectUrl, - String discoveryUrl, List scopes) async { - final authorizationTokenResponse = await _appAuthWeb.authorizeAndExchangeCode(AuthorizationTokenRequest( - clientId, - redirectUrl, - discoveryUrl: discoveryUrl, - scopes: scopes, - preferEphemeralSession: true)); - - log('AuthClientMobile::getTokenOIDC(): token: ${authorizationTokenResponse?.accessToken}'); - - if (authorizationTokenResponse != null) { - final tokenOIDC = authorizationTokenResponse.toTokenOIDC(); - if (tokenOIDC.isTokenValid()) { - return tokenOIDC; - } else { - throw AccessTokenInvalidException(); - } + Future getTokenOIDC( + String clientId, + String redirectUrl, + String discoveryUrl, + List scopes, + ) async { + final authorizationTokenRequest = getAuthorizationTokenRequest( + clientId, + redirectUrl, + discoveryUrl, + scopes, + ); + final authorizationTokenResponse = await _appAuthWeb.authorizeAndExchangeCode( + authorizationTokenRequest, + ); + log('$runtimeType::getTokenOIDC():Token: ${authorizationTokenResponse.accessToken}'); + final tokenOIDC = authorizationTokenResponse.toTokenOIDC(); + if (tokenOIDC.isTokenValid()) { + return tokenOIDC; } else { - throw NotFoundAccessTokenException(); + throw AccessTokenInvalidException(); } } @override - Future logoutOidc(TokenId tokenId, OIDCConfiguration config, OIDCDiscoveryResponse oidcRescovery) async { - final authorizationServiceConfiguration = oidcRescovery.authorizationEndpoint == null || oidcRescovery.tokenEndpoint == null - ? null - : AuthorizationServiceConfiguration( - authorizationEndpoint: oidcRescovery.authorizationEndpoint!, - tokenEndpoint: oidcRescovery.tokenEndpoint!, - endSessionEndpoint: oidcRescovery.endSessionEndpoint); - final endSession = await _appAuthWeb.endSession(EndSessionRequest( - idTokenHint: tokenId.uuid, - postLogoutRedirectUrl: config.logoutRedirectUrl, - discoveryUrl: config.discoveryUrl, - serviceConfiguration: authorizationServiceConfiguration - )); - return endSession != null; + Future logoutOidc( + TokenId tokenId, + OIDCConfiguration config, + OIDCDiscoveryResponse discoveryResponse, + ) async { + final endSessionRequest = getEndSessionRequest( + tokenId, + config, + discoveryResponse, + ); + final endSession = await _appAuthWeb.endSession(endSessionRequest); + log('$runtimeType::logoutOidc(): ${endSession.state}'); + return endSession.state?.isNotEmpty == true; } @override - Future refreshingTokensOIDC(String clientId, String redirectUrl, - String discoveryUrl, List scopes, String refreshToken) async { - final tokenResponse = await _appAuthWeb.token(TokenRequest( + Future refreshingTokensOIDC( + String clientId, + String redirectUrl, + String discoveryUrl, + List scopes, + String refreshToken, + ) async { + try { + final tokenRequest = getRefreshTokenRequest( clientId, redirectUrl, - discoveryUrl: discoveryUrl, - refreshToken: refreshToken, - grantType: 'refresh_token', - scopes: scopes)); - - if (tokenResponse != null) { - final tokenOIDC = tokenResponse.toTokenOIDC(maybeAvailableRefreshToken: refreshToken); + discoveryUrl, + refreshToken, + scopes, + ); + final tokenResponse = await _appAuthWeb.token(tokenRequest); + final tokenOIDC = tokenResponse.toTokenOIDC( + maybeAvailableRefreshToken: refreshToken, + ); if (tokenOIDC.isTokenValid()) { return tokenOIDC; } else { throw AccessTokenInvalidException(); } - } else { - throw NotFoundAccessTokenException(); + } catch (e) { + logError('$runtimeType::refreshingTokensOIDC(): $e'); + throw handleException(e); } } @override - Future authenticateOidcOnBrowser(String clientId, String redirectUrl, - String discoveryUrl, List scopes) async { + Future authenticateOidcOnBrowser( + String clientId, + String redirectUrl, + String discoveryUrl, + List scopes, + ) async { await _appAuthWeb.authorizeAndExchangeCode( - AuthorizationTokenRequest( - clientId, - redirectUrl, - discoveryUrl: discoveryUrl, - scopes: scopes)); + AuthorizationTokenRequest( + clientId, + redirectUrl, + discoveryUrl: discoveryUrl, + scopes: scopes, + ), + ); } @override diff --git a/lib/features/login/data/network/interceptors/authorization_interceptors.dart b/lib/features/login/data/network/interceptors/authorization_interceptors.dart index 8699df8b2c..ef75632781 100644 --- a/lib/features/login/data/network/interceptors/authorization_interceptors.dart +++ b/lib/features/login/data/network/interceptors/authorization_interceptors.dart @@ -14,6 +14,7 @@ import 'package:model/oidc/token_oidc.dart'; import 'package:tmail_ui_user/features/login/data/local/account_cache_manager.dart'; import 'package:tmail_ui_user/features/login/data/local/token_oidc_cache_manager.dart'; import 'package:tmail_ui_user/features/login/data/network/authentication_client/authentication_client_base.dart'; +import 'package:tmail_ui_user/features/login/domain/exceptions/oauth_authorization_error.dart'; import 'package:tmail_ui_user/features/login/domain/extensions/oidc_configuration_extensions.dart'; import 'package:tmail_ui_user/features/upload/data/network/file_uploader.dart'; import 'package:tmail_ui_user/main/utils/ios_sharing_manager.dart'; @@ -152,7 +153,14 @@ class AuthorizationInterceptors extends QueuedInterceptorsWrapper { } } catch (e) { logError('AuthorizationInterceptors::onError:Exception: $e'); - return super.onError(err.copyWith(error: e), handler); + if (e is ServerError || e is TemporarilyUnavailable) { + return super.onError( + DioError(requestOptions: err.requestOptions, error: e), + handler, + ); + } else { + return super.onError(err.copyWith(error: e), handler); + } } } diff --git a/lib/features/login/domain/exceptions/authentication_exception.dart b/lib/features/login/domain/exceptions/authentication_exception.dart index 825fbb6cbe..4fa2284541 100644 --- a/lib/features/login/domain/exceptions/authentication_exception.dart +++ b/lib/features/login/domain/exceptions/authentication_exception.dart @@ -25,8 +25,6 @@ class InvalidBaseUrl extends AuthenticationException { InvalidBaseUrl() : super(AuthenticationException.invalidBaseUrl); } -class NotFoundAccessTokenException implements Exception {} - class AccessTokenInvalidException implements Exception {} class DownloadAttachmentHasTokenExpiredException implements Exception { diff --git a/lib/features/login/domain/exceptions/oauth_authorization_error.dart b/lib/features/login/domain/exceptions/oauth_authorization_error.dart new file mode 100644 index 0000000000..65a8d5efaa --- /dev/null +++ b/lib/features/login/domain/exceptions/oauth_authorization_error.dart @@ -0,0 +1,40 @@ +class OAuthAuthorizationError { + static const String serverError = 'server_error'; // HTTP 500 error code + static const String temporarilyUnavailable = + 'temporarily_unavailable'; // HTTP 503 error code + + final String error; + final String? errorDescription; + + const OAuthAuthorizationError({ + required this.error, + this.errorDescription, + }); + + static OAuthAuthorizationError fromErrorCode( + String error, { + String? errorDescription, + }) { + switch (error) { + case serverError: + return ServerError(errorDescription: errorDescription); + case temporarilyUnavailable: + return TemporarilyUnavailable(errorDescription: errorDescription); + default: + return OAuthAuthorizationError( + error: error, + errorDescription: errorDescription, + ); + } + } +} + +class ServerError extends OAuthAuthorizationError { + const ServerError({super.errorDescription}) + : super(error: OAuthAuthorizationError.serverError); +} + +class TemporarilyUnavailable extends OAuthAuthorizationError { + const TemporarilyUnavailable({super.errorDescription}) + : super(error: OAuthAuthorizationError.temporarilyUnavailable); +} diff --git a/lib/features/login/domain/state/refresh_token_oidc_state.dart b/lib/features/login/domain/state/refresh_token_oidc_state.dart deleted file mode 100644 index 7680d7c456..0000000000 --- a/lib/features/login/domain/state/refresh_token_oidc_state.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:core/presentation/state/failure.dart'; -import 'package:core/presentation/state/success.dart'; -import 'package:model/oidc/token_oidc.dart'; - -class RefreshTokenOIDCSuccess extends UIState { - - final TokenOIDC tokenOIDC; - - RefreshTokenOIDCSuccess(this.tokenOIDC); - - @override - List get props => [tokenOIDC]; -} - -class RefreshTokenOIDCFailure extends FeatureFailure { - - RefreshTokenOIDCFailure(dynamic exception) : super(exception: exception); -} \ No newline at end of file diff --git a/lib/main/exceptions/remote_exception_thrower.dart b/lib/main/exceptions/remote_exception_thrower.dart index 885133b92b..7c6ed981d3 100644 --- a/lib/main/exceptions/remote_exception_thrower.dart +++ b/lib/main/exceptions/remote_exception_thrower.dart @@ -6,6 +6,7 @@ import 'package:get/get_connect/http/src/status/http_status.dart'; import 'package:jmap_dart_client/jmap/core/error/method/error_method_response.dart'; import 'package:jmap_dart_client/jmap/core/error/method/exception/error_method_response_exception.dart'; import 'package:tmail_ui_user/features/login/domain/exceptions/authentication_exception.dart'; +import 'package:tmail_ui_user/features/login/domain/exceptions/oauth_authorization_error.dart'; import 'package:tmail_ui_user/features/network_connection/presentation/network_connection_controller.dart' if (dart.library.html) 'package:tmail_ui_user/features/network_connection/presentation/web_network_connection_controller.dart'; import 'package:tmail_ui_user/main/exceptions/exception_thrower.dart'; @@ -28,48 +29,66 @@ class RemoteExceptionThrower extends ExceptionThrower { void handleDioError(dynamic error) { if (error is DioError) { - logError('RemoteExceptionThrower::throwException():type: ${error.type} | response: ${error.response} | error: ${error.error}'); - if (error.response != null) { - if (error.response!.statusCode == HttpStatus.internalServerError) { - throw const InternalServerError(); - } else if (error.response!.statusCode == HttpStatus.badGateway) { - throw BadGateway(); - } else if (error.response!.statusCode == HttpStatus.unauthorized) { - throw const BadCredentialsException(); - } else { - throw UnknownError( - code: error.response!.statusCode, - message: error.response!.statusMessage); - } - } else { - switch (error.type) { - case DioErrorType.connectionTimeout: - throw ConnectionTimeout(message: error.message); - case DioErrorType.connectionError: - throw ConnectionError(message: error.message); - case DioErrorType.badResponse: + logError( + 'RemoteExceptionThrower::throwException():type: ${error.type} | response: ${error.response} | error: ${error.error}', + ); + + final response = error.response; + final statusCode = response?.statusCode; + + if (response != null) { + switch (statusCode) { + case HttpStatus.internalServerError: + throw const InternalServerError(); + case HttpStatus.badGateway: + throw BadGateway(); + case HttpStatus.unauthorized: throw const BadCredentialsException(); default: - if (error.error is SocketException) { - throw const SocketError(); - } else if (error.error != null) { - throw UnknownError(message: error.error); - } else { - throw const UnknownError(); - } + throw UnknownError( + code: statusCode, + message: response.statusMessage, + ); } } - } else if (error is ErrorMethodResponseException) { + + return _handleDioErrorWithoutResponse(error); + } + + if (error is ErrorMethodResponseException) { final errorResponse = error.errorResponse as ErrorMethodResponse; if (errorResponse is CannotCalculateChangesMethodResponse) { throw CannotCalculateChangesMethodResponseException(); } else { throw MethodLevelErrors( - errorResponse.type, - message: errorResponse.description); + errorResponse.type, + message: errorResponse.description, + ); } - } else { - throw error; + } + + throw error; + } + + void _handleDioErrorWithoutResponse(DioError error) { + switch (error.type) { + case DioErrorType.connectionTimeout: + throw ConnectionTimeout(message: error.message); + case DioErrorType.connectionError: + throw ConnectionError(message: error.message); + case DioErrorType.badResponse: + throw const BadCredentialsException(); + default: + final underlyingError = error.error; + if (underlyingError is SocketException) { + throw const SocketError(); + } else if (underlyingError is OAuthAuthorizationError) { + throw underlyingError; + } else if (underlyingError != null) { + throw UnknownError(message: underlyingError); + } else { + throw const UnknownError(); + } } } } \ No newline at end of file diff --git a/lib/main/utils/toast_manager.dart b/lib/main/utils/toast_manager.dart index e7465abdf0..3bd0c66ac7 100644 --- a/lib/main/utils/toast_manager.dart +++ b/lib/main/utils/toast_manager.dart @@ -8,6 +8,7 @@ import 'package:core/presentation/utils/app_toast.dart'; import 'package:core/utils/app_logger.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_appauth_web/authorization_exception.dart'; import 'package:jmap_dart_client/jmap/core/error/method/error_method_response.dart'; import 'package:jmap_dart_client/jmap/core/error/method/exception/error_method_response_exception.dart'; import 'package:jmap_dart_client/jmap/core/error/set_error.dart'; @@ -23,6 +24,7 @@ import 'package:tmail_ui_user/features/home/data/exceptions/session_exceptions.d import 'package:tmail_ui_user/features/home/domain/state/get_session_state.dart'; import 'package:tmail_ui_user/features/login/data/network/oidc_error.dart'; import 'package:tmail_ui_user/features/login/domain/exceptions/authentication_exception.dart'; +import 'package:tmail_ui_user/features/login/domain/exceptions/oauth_authorization_error.dart'; import 'package:tmail_ui_user/features/mailbox/domain/state/clear_mailbox_state.dart'; import 'package:tmail_ui_user/features/manage_account/domain/state/add_recipient_in_forwarding_state.dart'; import 'package:tmail_ui_user/features/manage_account/domain/state/delete_recipient_in_forwarding_state.dart'; @@ -98,7 +100,7 @@ class ToastManager { return '[${exception.type.value}] ${exception.message}'; } else if (exception is SetError) { return '[${exception.type.value}] ${exception.description}'; - }else if (exception is PlatformException && + } else if (exception is PlatformException && exception.message?.isNotEmpty == true) { return exception.message!; } else if (exception is NotGrantedPermissionStorageException) { @@ -114,6 +116,12 @@ class ToastManager { final firstError = mapErrors.values.first; return '[${firstError.type.value}] ${firstError.description}'; } + } else if (exception is ServerError) { + return '[${exception.error}] ${exception.errorDescription}'; + } else if (exception is TemporarilyUnavailable) { + return '[${exception.error}] ${exception.errorDescription}'; + } else if (exception is AutoRedirectToAppAfterStoreAuthorizeDestinationUrlException) { + return ''; } if (useDefaultMessage) { diff --git a/pubspec.lock b/pubspec.lock index ed9122d116..da96d9868a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -698,27 +698,27 @@ packages: dependency: "direct main" description: name: flutter_appauth - sha256: f2696d4cf437f627fa09bc4864afdd8c80273f2e293fde544b18202a627754b1 + sha256: b09fa8e3eaba12ec341c69ec45063e06eb565304e24cc35caaf105bbae2e955c url: "https://pub.dev" source: hosted - version: "6.0.6" + version: "9.0.1" flutter_appauth_platform_interface: dependency: "direct main" description: name: flutter_appauth_platform_interface - sha256: "44feaa7058191b5d3cd7c9ff195262725773643121bcada172d49c2ddcff71cb" + sha256: fd2920b853d09741aff2e1178e044ea2ade0c87799cd8e63f094ab35b00fdf70 url: "https://pub.dev" source: hosted - version: "6.0.0" + version: "9.0.0" flutter_appauth_web: dependency: "direct main" description: path: "." - ref: main - resolved-ref: "39f9806f27f45da34bb86b2b9b22847be9153516" - url: "https://github.com/CarlosPacheco/flutter_appauth_web.git" + ref: upgrade-flutter-appauth + resolved-ref: "0952346bf781bd87b93b8c61619f81a264be52db" + url: "https://github.com/linagora/flutter_appauth_web.git" source: git - version: "0.0.3" + version: "1.0.0" flutter_charset_detector: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index e5766ab993..1b888761da 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -82,8 +82,8 @@ dependencies: flutter_appauth_web: git: - url: https://github.com/CarlosPacheco/flutter_appauth_web.git - ref: main + url: https://github.com/linagora/flutter_appauth_web.git + ref: upgrade-flutter-appauth flutter_date_range_picker: git: @@ -172,7 +172,7 @@ dependencies: better_open_file: 3.6.4 - flutter_appauth: 6.0.6 + flutter_appauth: 9.0.1 percent_indicator: 4.2.2 @@ -206,7 +206,7 @@ dependencies: debounce_throttle: 2.0.0 - flutter_appauth_platform_interface: 6.0.0 + flutter_appauth_platform_interface: 9.0.0 intl: 0.19.0