From 1b8616aac4774d02cf84a684079226291ceb9217 Mon Sep 17 00:00:00 2001 From: fulleni Date: 2025年7月13日 16:56:59 +0100 Subject: [PATCH 1/5] refactor(auth): improve exception handling in initiateEmailSignIn Refactors the try-catch block in the `initiateEmailSignIn` method to improve robustness and clarity. - The generic `catch` block now includes the stack trace in the log for better error diagnostics. - Adds a comment to the `on HtHttpException` block to clarify that it correctly propagates specific exceptions like `ForbiddenException`, preventing them from being masked as generic 50 --- lib/src/services/auth_service.dart | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/src/services/auth_service.dart b/lib/src/services/auth_service.dart index d1a0cfc..427c17a 100644 --- a/lib/src/services/auth_service.dart +++ b/lib/src/services/auth_service.dart @@ -105,11 +105,13 @@ class AuthService { await _emailRepository.sendOtpEmail(recipientEmail: email, otpCode: code); _log.info('Initiated email sign-in for $email, code sent.'); } on HtHttpException { - // Propagate known exceptions from dependencies + // Propagate known exceptions from dependencies or from this method's logic. + // This ensures that specific errors like ForbiddenException are not + // masked as a generic server error. rethrow; - } catch (e) { - // Catch unexpected errors during orchestration - _log.severe('Error during initiateEmailSignIn for $email: $e'); + } catch (e, s) { + // Catch unexpected errors during orchestration. + _log.severe('Error during initiateEmailSignIn for $email: $e', e, s); throw const OperationFailedException( 'Failed to initiate email sign-in process.', ); From ca36a5c2de121434943de8a079faea7754099fbb Mon Sep 17 00:00:00 2001 From: fulleni Date: 2025年7月13日 16:57:38 +0100 Subject: [PATCH 2/5] fix(auth): correctly propagate exceptions in completeEmailSignIn Refactors the try-catch block in the `completeEmailSignIn` method to correctly handle exceptions during user lookup and creation. Previously, any `HtHttpException` (including `ForbiddenException` thrown for users without dashboard permissions) was caught and re-thrown as a generic `OperationFailedException`. This masked the original error and prevented the `errorHandler` middleware from returning the correct 403 status code. This change ensures that `HtHttpException` subtypes are re-thrown directly, allowing for proper error handling and correct HTTP responses, thus fixing the authentication vulnerability. --- lib/src/services/auth_service.dart | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/src/services/auth_service.dart b/lib/src/services/auth_service.dart index 427c17a..abddb40 100644 --- a/lib/src/services/auth_service.dart +++ b/lib/src/services/auth_service.dart @@ -256,14 +256,14 @@ class AuthService { 'Created default UserContentPreferences for user: ${user.id}', ); } - } on HtHttpException catch (e) { - _log.severe('Error finding/creating user for $email: $e'); - throw const OperationFailedException( - 'Failed to find or create user account.', - ); - } catch (e) { + } on HtHttpException { + // Propagate known exceptions from dependencies or from this method's logic. + // This ensures that specific errors like ForbiddenException are not + // masked as a generic server error. + rethrow; + } catch (e, s) { _log.severe( - 'Unexpected error during user lookup/creation for $email: $e', + 'Unexpected error during user lookup/creation for $email: $e', e, s, ); throw const OperationFailedException('Failed to process user account.'); } From 9a2b1e98045ad599e29b80bc1b5637b5f422e7b5 Mon Sep 17 00:00:00 2001 From: fulleni Date: 2025年7月13日 17:08:01 +0100 Subject: [PATCH 3/5] fix(auth): make request-code handler resilient to body param types Refactors the parsing of the `isDashboardLogin` parameter in the `/api/v1/auth/request-code` route handler. Previously, the handler would crash with a type cast error if the `isDashboardLogin` value was sent as a string (e.g., `"true"`) instead of a boolean. This change introduces robust parsing that correctly handles values that are boolean `true`, the string `"true"`, or missing, preventing the 500 Internal Server Error and making the endpoint more resilient to varied client implementations. --- routes/api/v1/auth/request-code.dart | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/routes/api/v1/auth/request-code.dart b/routes/api/v1/auth/request-code.dart index be61aa5..11b6706 100644 --- a/routes/api/v1/auth/request-code.dart +++ b/routes/api/v1/auth/request-code.dart @@ -43,8 +43,17 @@ Future onRequest(RequestContext context) async { ); } - // Check for the optional dashboard login flag. Default to false if not present. - final isDashboardLogin = (body['isDashboardLogin'] as bool?) ?? false; + // Check for the optional dashboard login flag. This handles both boolean + // `true` and string `"true"` values to prevent type cast errors. + // It defaults to `false` if the key is missing or the value is not + // recognized as true. + final isDashboardLoginRaw = body['isDashboardLogin']; + var isDashboardLogin = false; + if (isDashboardLoginRaw is bool) { + isDashboardLogin = isDashboardLoginRaw; + } else if (isDashboardLoginRaw is String) { + isDashboardLogin = isDashboardLoginRaw.toLowerCase() == 'true'; + } // Basic email format check (more robust validation can be added) // Using a slightly more common regex pattern From bbbff119db50d2a9b3e5db01788033287470a559 Mon Sep 17 00:00:00 2001 From: fulleni Date: 2025年7月13日 17:13:39 +0100 Subject: [PATCH 4/5] fix(auth): prevent code requests for invalid dashboard users Refactors the validation logic in `AuthService.initiateEmailSignIn` to correct a critical security flaw. Previously, the logic allowed verification codes to be sent to any email address during a dashboard login attempt, even if the user did not exist or lacked permissions. This change restructures the validation into a more explicit `if-else if` block. It now correctly throws an `UnauthorizedException` if the user is not found or a `ForbiddenException` if they lack permissions, ensuring that execution is halted immediately and a code is never sent for an invalid dashboard login attempt. --- lib/src/services/auth_service.dart | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/src/services/auth_service.dart b/lib/src/services/auth_service.dart index abddb40..0ac4c6e 100644 --- a/lib/src/services/auth_service.dart +++ b/lib/src/services/auth_service.dart @@ -75,18 +75,15 @@ class AuthService { // For dashboard login, first validate the user exists and has permissions. if (isDashboardLogin) { final user = await _findUserByEmail(email); + + // For dashboard login, the user must exist AND have permission. + // If either condition fails, throw the appropriate exception. if (user == null) { _log.warning('Dashboard login failed: User $email not found.'); throw const UnauthorizedException( 'This email address is not registered for dashboard access.', ); - } - - // Use the PermissionService to check for the specific dashboard login permission. - if (!_permissionService.hasPermission( - user, - Permissions.dashboardLogin, - )) { + } else if (!_permissionService.hasPermission(user, Permissions.dashboardLogin)) { _log.warning( 'Dashboard login failed: User ${user.id} lacks required permission (${Permissions.dashboardLogin}).', ); @@ -94,6 +91,7 @@ class AuthService { 'Your account does not have the required permissions to sign in.', ); } + _log.info('Dashboard user ${user.id} verified successfully.'); } From ad65ef29218a70dadebb562cf7bea82092dce518 Mon Sep 17 00:00:00 2001 From: fulleni Date: 2025年7月13日 18:02:30 +0100 Subject: [PATCH 5/5] fix(auth): improve dashboard login security - Added email verification for dashboard login - Improved error handling for email mismatch - Enhanced logging for security issues - Added more informative error messages - Fixed potential security vulnerability --- lib/src/services/auth_service.dart | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/src/services/auth_service.dart b/lib/src/services/auth_service.dart index 0ac4c6e..30a1777 100644 --- a/lib/src/services/auth_service.dart +++ b/lib/src/services/auth_service.dart @@ -166,13 +166,25 @@ class AuthService { // This closes the loophole where a non-admin user could request a code // via the app flow and then use it to log into the dashboard. if (isDashboardLogin) { + if (user.email != email) { + // This is a critical security check. If the user found by email + // somehow has a different email than the one provided, it's a + // sign of a serious issue (like the data layer bug we fixed). + // We throw a generic error to avoid revealing information. + _log.severe( + 'CRITICAL: Mismatch between requested email ($email) and found ' + 'user email (${user.email}) during dashboard login for user ' + 'ID ${user.id}.', + ); + throw const UnauthorizedException('User account does not exist.'); + } if (!_permissionService.hasPermission( user, Permissions.dashboardLogin, )) { _log.warning( - 'Dashboard login failed: User ${user.id} lacks required permission ' - 'during code verification.', + 'Dashboard login failed: User ${user.id} lacks required ' + 'permission during code verification.', ); throw const ForbiddenException( 'Your account does not have the required permissions to sign in.',

AltStyle によって変換されたページ (->オリジナル) /