Skip to content

Commit

Permalink
error handling while sync container
Browse files Browse the repository at this point in the history
  • Loading branch information
frankmer committed Sep 16, 2024
1 parent 1ddc4d1 commit 4b2c929
Show file tree
Hide file tree
Showing 11 changed files with 84 additions and 23 deletions.
39 changes: 36 additions & 3 deletions lib/api/token_container_api_endpoint.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,15 @@ import 'package:privacyidea_authenticator/processors/scheme_processors/token_imp
import 'package:privacyidea_authenticator/utils/ecc_utils.dart';
import 'package:privacyidea_authenticator/utils/privacyidea_io_client.dart';

import '../l10n/app_localizations.dart';
import '../model/riverpod_states/token_state.dart';
import '../model/token_template.dart';
import '../model/tokens/container_credentials.dart';
import '../model/tokens/token.dart';
import '../utils/globals.dart';
import '../utils/identifiers.dart';
import '../utils/logger.dart';
import '../utils/view_utils.dart';
import '../widgets/dialog_widgets/enter_passphrase_dialog.dart';

part 'token_container_api_endpoint.freezed.dart';
Expand Down Expand Up @@ -131,16 +133,21 @@ class PrivacyideaContainerApi {

Future<ContainerChallenge?> _getChallenge(ContainerCredentialFinalized container) async {
final initResponse = await _ioClient.doGet(url: container.syncUrl, parameters: {CONTAINER_SERIAL: container.serial});
if (initResponse.statusCode != 200) {
_showSyncStatusMessage(initResponse);
return null;
}

try {
Logger.debug('Received container sync challenge: ${initResponse.body}', name: 'TokenContainerApiEndpoint#sync');
final piResponse = PiServerResponse<ContainerChallenge>.fromResponse(initResponse);
if (piResponse.isError) {
Logger.error('Error while syncing container: ${piResponse.asError.resultError}', name: 'TokenContainerApiEndpoint#sync');
Logger.error('Error while getting sync challenge: ${piResponse.asError.resultError}', name: 'TokenContainerApiEndpoint#sync');
return null;
}
return piResponse.asSuccess.resultValue;
} catch (e, s) {
Logger.error('Error while syncing container: $e', name: 'TokenContainerApiEndpoint#sync', stackTrace: s);
Logger.error('Error while getting sync challenge: $e', name: 'TokenContainerApiEndpoint#sync', stackTrace: s);
return null;
}
}
Expand Down Expand Up @@ -174,9 +181,13 @@ class PrivacyideaContainerApi {
};

final response = await _ioClient.doPost(url: Uri.parse(challenge.finalizeSyncUrl), body: body);
if (response.statusCode != 200) {
_showSyncStatusMessage(response);
return null;
}
final containerSyncResponse = PiServerResponse<ContainerSyncResult>.fromResponse(response);
if (containerSyncResponse.isError) {
Logger.error('Error while syncing container: ${containerSyncResponse.asError.resultError}', name: 'TokenContainerApiEndpoint#sync');
Logger.error('Error while reciving sync response: ${containerSyncResponse.asError.resultError}', name: 'TokenContainerApiEndpoint#sync');
return null;
}

Expand Down Expand Up @@ -264,6 +275,28 @@ class PrivacyideaContainerApi {
}
return (mergedTemplatesWithSerial, deleteSerials);
}

void _showSyncStatusMessage(Response response) {
assert(response.statusCode != 200, 'Status code should not be 200');

final AppLocalizations appLocalizations = AppLocalizations.of(globalNavigatorKey.currentContext!)!;
if (response.statusCode == 525) return;
if (response.statusCode == 500) {
return showStatusMessage(message: appLocalizations.syncContainerFailed, subMessage: appLocalizations.internalServerError(500));
}
if (response.statusCode == 408) {
return showStatusMessage(message: appLocalizations.timeOut, subMessage: appLocalizations.checkYourNetwork);
}
if (response.statusCode == 404) {
return showStatusMessage(message: appLocalizations.syncContainerFailed, subMessage: appLocalizations.checkYourNetwork);
}
Logger.error(
'Received unexpected response',
error: 'StatusCode: ${response.statusCode}',
name: 'TokenContainerApiEndpoint#_showStatusMessage',
stackTrace: StackTrace.current,
);
}
}

abstract class PiServerResult {
Expand Down
4 changes: 2 additions & 2 deletions lib/l10n/app_cs.arb
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,8 @@
"@allTokensSynchronized": {
"description": "Content of the push synchronization dialog. Signaling the user that everything worked."
},
"synchronizationFailed": "Synchronizace následujících tokenů selhala, zkuste to znovu:",
"@synchronizationFailed": {
"syncFbTokenFailed": "Synchronizace následujících tokenů selhala, zkuste to znovu:",
"@syncFbTokenFailed": {
"description": "Headline for the list of tokens where the synchronization failed."
},
"tokensDoNotSupportSynchronization": "Následující tokeny nepodporují synchronizaci a musí být znovu zaregistrovány:",
Expand Down
4 changes: 2 additions & 2 deletions lib/l10n/app_de.arb
Original file line number Diff line number Diff line change
Expand Up @@ -199,8 +199,8 @@
"@allTokensSynchronized": {
"description": "Content of the push synchronization dialog. Signaling the user that everything worked."
},
"synchronizationFailed": "Synchronisation ist für die folgenden Token fehlgeschlagen:",
"@synchronizationFailed": {
"syncFbTokenFailed": "Synchronisation ist für die folgenden Token fehlgeschlagen:",
"@syncFbTokenFailed": {
"description": "Headline for the list of tokens where the synchronization failed."
},
"tokensDoNotSupportSynchronization": "Die folgenden Token unterstützen keine Synchronisation und müssen erneut ausgerollt werden:",
Expand Down
18 changes: 15 additions & 3 deletions lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -203,8 +203,8 @@
"@allTokensSynchronized": {
"description": "Content of the push synchronization dialog. Signaling the user that everything worked."
},
"synchronizationFailed": "Synchronization failed for the following tokens, please try again:",
"@synchronizationFailed": {
"syncFbTokenFailed": "Synchronization failed for the following tokens, please try again:",
"@syncFbTokenFailed": {
"description": "Headline for the list of tokens where the synchronization failed."
},
"tokensDoNotSupportSynchronization": "The following tokens do not support synchronization and must be rolled out again:",
Expand Down Expand Up @@ -748,5 +748,17 @@
"example": "token data"
}
}
}
},
"internalServerError": "Internal server error ({code})",
"@internalServerError": {
"placeholders": {
"code": {
"example": "500"
}
}
},
"timeOut": "Time out",
"syncContainerFailed": "Failed to synchronize container",
"handshakeFailed" : "Handshake failed",
"checkServerCertificate": "Please check the server certificate"
}
4 changes: 2 additions & 2 deletions lib/l10n/app_es.arb
Original file line number Diff line number Diff line change
Expand Up @@ -199,8 +199,8 @@
"@allTokensSynchronized": {
"description": "Content of the push synchronization dialog. Signaling the user that everything worked."
},
"synchronizationFailed": "La sincronización ha fallado para los siguientes tokens, por favor inténtelo de nuevo:",
"@synchronizationFailed": {
"syncFbTokenFailed": "La sincronización ha fallado para los siguientes tokens, por favor inténtelo de nuevo:",
"@syncFbTokenFailed": {
"description": "Headline for the list of tokens where the synchronization failed."
},
"tokensDoNotSupportSynchronization": "Las siguientes tokens no admiten la sincronización y deben volver a desplegarse:",
Expand Down
4 changes: 2 additions & 2 deletions lib/l10n/app_fr.arb
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,8 @@
"@allTokensSynchronized": {
"description": "Content of the push synchronization dialog. Signaling the user that everything worked."
},
"synchronizationFailed": "La synchronisation a échoué pour ces jetons, veuillez reéssayer:",
"@synchronizationFailed": {
"syncFbTokenFailed": "La synchronisation a échoué pour ces jetons, veuillez reéssayer:",
"@syncFbTokenFailed": {
"description": "Headline for the list of tokens where the synchronization failed."
},
"tokensDoNotSupportSynchronization": "Ces jetons ne supportent pas la synchronisation et doivent être de nouveau générés:",
Expand Down
4 changes: 2 additions & 2 deletions lib/l10n/app_nl.arb
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,8 @@
"@allTokensSynchronized": {
"description": "Content of the push synchronization dialog. Signaling the user that everything worked."
},
"synchronizationFailed": "Synchroniseren mislukt voor de volgende tokens, probeer het opnieuw:",
"@synchronizationFailed": {
"syncFbTokenFailed": "Synchroniseren mislukt voor de volgende tokens, probeer het opnieuw:",
"@syncFbTokenFailed": {
"description": "Headline for the list of tokens where the synchronization failed."
},
"tokensDoNotSupportSynchronization": "Voor de volgende tokens wordt synchroniseren niet ondersteunt, ze moeten opnieuw worden aangeleverd:",
Expand Down
4 changes: 2 additions & 2 deletions lib/l10n/app_pl.arb
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,8 @@
"@allTokensSynchronized": {
"description": "Content of the push synchronization dialog. Signaling the user that everything worked."
},
"synchronizationFailed": "Synchronizacja dla poniższych tokenów się nie udała, spróbuj ponownie:",
"@synchronizationFailed": {
"syncFbTokenFailed": "Synchronizacja dla poniższych tokenów się nie udała, spróbuj ponownie:",
"@syncFbTokenFailed": {
"description": "Headline for the list of tokens where the synchronization failed."
},
"tokensDoNotSupportSynchronization": "Następujące tokeny nie wspierają synchronizacji i muszą zostać wdrożone od nowa:",
Expand Down
14 changes: 10 additions & 4 deletions lib/utils/privacyidea_io_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -176,17 +176,23 @@ class PrivacyideaIOClient {
response = await ioClient.get(uri).timeout(const Duration(seconds: 15));
} on HandshakeException catch (e, _) {
Logger.warning('Handshake failed. sslVerify: $sslVerify', name: 'utils.dart#doGet');
showMessage(message: 'Handshake failed, please check the server certificate and try again.');
showStatusMessage(
message: AppLocalizations.of(await globalContext)!.handshakeFailed,
subMessage: AppLocalizations.of(await globalContext)!.checkServerCertificate,
);
response = Response('${e.runtimeType}', 525);
} on TimeoutException catch (e, _) {
Logger.info('Get request timed out', name: 'utils.dart#doGet');
response = Response('${e.runtimeType}', 408);
response = Response('${AppLocalizations.of(await globalContext)!.timeOut}', 408);
} on SocketException catch (e, _) {
Logger.info('Get request failed', name: 'utils.dart#doGet');
response = Response('${e.runtimeType}', 404);
response = Response('${AppLocalizations.of(await globalContext)!.connectionFailed}', 404);
} on ClientException catch (e, _) {
Logger.info('Get request failed', name: 'utils.dart#doGet');
response = Response('${AppLocalizations.of(await globalContext)!.connectionFailed}', 404);
} catch (e, _) {
Logger.warning('Something unexpected happened', name: 'utils.dart#doGet');
response = Response('${e.runtimeType}', 404);
response = Response('${AppLocalizations.of(await globalContext)!.unexpectedError}', 520);
}

if (response.statusCode != 200) {
Expand Down
10 changes: 10 additions & 0 deletions lib/utils/view_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import 'package:flutter/material.dart';

import 'globals.dart';
import 'logger.dart';
import 'riverpod/riverpod_providers/state_providers/status_message_provider.dart';

/// Shows a snackbar message to the user for a given `Duration`.
void showMessage({
Expand All @@ -36,6 +37,15 @@ void showMessage({
);
}

void showStatusMessage({required String message, String? subMessage}) {
final ref = globalRef;
if (ref == null) {
Logger.warning('Could not show status message: globalRef is null');
return;
}
ref.read(statusMessageProvider.notifier).state = (message, subMessage);
}

Future<T?> showAsyncDialog<T>({
required WidgetBuilder builder,
bool barrierDismissible = true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class _UpdateFirebaseTokenDialogState extends ConsumerState<UpdateFirebaseTokenD

if (tokenWithFailedUpdate.isNotEmpty) {
children.add(
Text('${AppLocalizations.of(globalNavigatorKey.currentContext!)!.synchronizationFailed}\n'),
Text('${AppLocalizations.of(globalNavigatorKey.currentContext!)!.syncFbTokenFailed}\n'),
);
for (PushToken p in tokenWithFailedUpdate) {
children.add(Text('• ${p.label}'));
Expand Down

0 comments on commit 4b2c929

Please sign in to comment.