Skip to content

Harden authentication flow with login throttling and safer credential handling#2679

Open
Divyateja2709 wants to merge 1 commit into
openMF:devfrom
Divyateja2709:login-fix
Open

Harden authentication flow with login throttling and safer credential handling#2679
Divyateja2709 wants to merge 1 commit into
openMF:devfrom
Divyateja2709:login-fix

Conversation

@Divyateja2709

Copy link
Copy Markdown

hi @therajanmaurya

This PR introduces a focused security remediation in the authentication flow, aligned with Cipher 2026 hardening goals.
It adds temporary login throttling after repeated failed attempts, avoids persisting plaintext passwords in local user state, and preserves password fidelity by removing accidental trimming before auth requests.

Changes included
Add failed-attempt lockout logic in login flow (5 failures -> 1 minute lockout).
Add localized error message for temporary lockout.
Stop storing raw password in persisted User object.
Keep username normalization (trim) but do not trim password in repository login call.
Why this matters
Reduces risk of brute-force behavior on client login attempts.
Minimizes sensitive data exposure in local persisted state.
Prevents authentication edge cases caused by password mutation.
Validation
Static lints on touched files: no issues.
Build verification was blocked locally because JAVA_HOME is not set in the environment.

@Divyateja2709 Divyateja2709 requested a review from a team May 10, 2026 14:16
@coderabbitai

coderabbitai Bot commented May 10, 2026

Copy link
Copy Markdown

Review Change Stack

Summary by CodeRabbit

  • New Features

    • Added temporary account lockout that activates after multiple failed login attempts
    • Displays "too many attempts" error message when locked out
  • Security

    • Enhanced password handling during authentication flow

Walkthrough

This PR implements temporary account lockout after repeated failed login attempts, improves password security by not persisting credentials, and refactors login result handling to use consistent failure/success callbacks throughout the authentication flow.

Changes

Login Attempt Lockout & Password Security
Layer / File(s) Summary
String Resources & Lockout Configuration
feature/auth/src/commonMain/composeResources/values/strings.xml, feature/auth/src/commonMain/kotlin/com/mifos/feature/auth/login/LoginViewModel.kt
Adds feature_auth_error_too_many_attempts string resource and introduces MAX_LOGIN_ATTEMPTS (default 5) and LOCKOUT_DURATION_MS constants along with failure tracking state.
Lockout State & Helper Methods
feature/auth/src/commonMain/kotlin/com/mifos/feature/auth/login/LoginViewModel.kt
Adds isLoginTemporarilyLocked() to check current lockout status, onLoginFailure() to increment attempt counters with expiration timestamp, and resetLoginFailureState() to clear counters after success using kotlinx.datetime.Clock.
Validation & Lockout Check
feature/auth/src/commonMain/kotlin/com/mifos/feature/auth/login/LoginViewModel.kt
Updates validateUserInputs to trim username, check lockout status before validation, and emit "too many attempts" error when locked.
Login Result Handling
feature/auth/src/commonMain/kotlin/com/mifos/feature/auth/login/LoginViewModel.kt
Refactors login() to call onLoginFailure() for both DataState.Error and unauthenticated outcomes instead of directly setting UI error; authenticated success now resets failure counters and calls onLoginSuccessful().
Password Security & Persistence
feature/auth/src/commonMain/kotlin/com/mifos/feature/auth/login/LoginViewModel.kt, core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/LoginRepositoryImp.kt
Persists authenticated User with password = null instead of storing entered credentials; repository now trims only username, not password.

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
Jira Link And Before/After Sections ❌ Error PR description missing required Jira link (e.g., https://mifosforge.jira.com/browse/MIFOSAC-####) and Before/After sections with media as specified in .github/PULL_REQUEST_TEMPLATE.md. Add Jira link in format "Fixes - Jira-#" and populate Before/After table with screenshots showing UI changes from login throttling and error messaging.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main changes: authentication hardening with login throttling and safer credential handling, which aligns with the security-focused modifications in the changeset.
Description check ✅ Passed The description is directly related to the changeset, explaining the security improvements, lockout logic, credential handling, and validation steps undertaken in the PR.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sonarqubecloud

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
feature/auth/src/commonMain/kotlin/com/mifos/feature/auth/login/LoginViewModel.kt (2)

79-105: 🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

Async collection and reducer/state transitions are still mixed.

In LoginViewModel.kt, collect directly mutates _loginUiState across branches instead of dispatching internal actions and reducing in one place. This is explicitly against the project’s ViewModel MVI rule.

As per coding guidelines: "Repository/network/database results MUST be converted into internal actions using sendAction(...)" and "handleAction(...) must act as the primary reducer responsible for state mutation."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@feature/auth/src/commonMain/kotlin/com/mifos/feature/auth/login/LoginViewModel.kt`
around lines 79 - 105, The collector in LoginViewModel is directly mutating
_loginUiState inside loginUseCase(...).collect and must instead translate
DataState branches into internal actions and let handleAction(...) perform all
state updates; replace direct assignments and Logger calls in the collect block
with sendAction(...) calls (e.g., LoginAction.LoginLoading,
LoginAction.LoginSuccess(authData, username),
LoginAction.LoginError(errorPayload)) and include any error/result payloads
needed, then implement handling in handleAction(...) to set _loginUiState
(ShowProgress, ShowError, resetLoginFailureState,
onLoginSuccessful/onLoginFailure) so LoginViewModel only dispatches actions from
the collect block and handleAction is the single reducer that mutates
_loginUiState.

114-123: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard nullable auth response fields before persisting user data.

PostAuthenticationResponse defines userId, officeId, and permissions as nullable. The force-unwraps at lines 116–121 will crash the login success path if the backend returns incomplete payloads.

Add explicit null checks before persisting user data, failing gracefully with a ShowError state:

Proposed patch
viewModelScope.launch {
+    val userId = user.userId
+    val officeId = user.officeId
+    val permissions = user.permissions
+    if (userId == null || officeId == null || permissions == null) {
+        _loginUiState.value = LoginUiState.ShowError(Res.string.feature_auth_error_login_failed)
+        Logger.d("@@@", Throwable("login: missing required auth fields in response"))
+        return@launch
+    }
+
     prefManager.updateUser(
         User(
             username = username,
             password = null,
-            userId = user.userId!!,
+            userId = userId,
             base64EncodedAuthenticationKey = user.base64EncodedAuthenticationKey,
             isAuthenticated = user.authenticated ?: false,
-            officeId = user.officeId!!,
+            officeId = officeId,
             officeName = user.officeName,
-            permissions = user.permissions!!,
+            permissions = permissions,
         ),
     )
 }

Per coding guidelines: avoid !! operator and handle null cases explicitly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@feature/auth/src/commonMain/kotlin/com/mifos/feature/auth/login/LoginViewModel.kt`
around lines 114 - 123, The code is force-unwrapping nullable fields from
PostAuthenticationResponse (user.userId, user.officeId, user.permissions) before
calling prefManager.updateUser, which can crash; update LoginViewModel's success
handling to explicitly guard those fields on the received `user` (from
PostAuthenticationResponse) - check that user.userId, user.officeId and
user.permissions are non-null (and any other nullable fields used) and if any
are null emit the ShowError state (or appropriate failure state) and abort
persisting; only call prefManager.updateUser(User(...)) with the unwrapped
values after these null checks, removing all `!!` uses. Ensure you reference the
existing prefManager.updateUser call and the User construction in LoginViewModel
to apply the checks.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/LoginRepositoryImp.kt`:
- Around line 24-25: The login method in LoginRepositoryImp returns the network
DTO PostAuthenticationResponse directly; change it to call
dataManagerAuth.login(...) and map the returned PostAuthenticationResponse into
a domain model (or appropriate entity) using the existing mapper, then wrap the
result in a DataState before returning; update the signature/return flow of
LoginRepositoryImp.login to return DataState<YourDomainAuthModel> (or
DataState<Unit/SuccessType> as appropriate), use the mapper to translate
PostAuthenticationResponse -> Domain type, and propagate errors into DataState
as per repository conventions.

In
`@feature/auth/src/commonMain/kotlin/com/mifos/feature/auth/login/LoginViewModel.kt`:
- Around line 81-85: The failure handling currently calls onLoginFailure() but
doesn't know if lockout was triggered, so update onLoginFailure to return a
Boolean (true when lockout threshold reached) and change all callers (the
DataState.Error branches in LoginViewModel where Logger.d and _loginUiState are
set, e.g., the blocks around the existing handlers at the mentioned locations)
to capture the returned value and choose
LoginUiState.ShowLockout(Res.string.feature_auth_error_login_locked_out) when
true, otherwise
LoginUiState.ShowError(Res.string.feature_auth_error_login_failed); also update
the onLoginFailure implementation to compute and return the lockout flag and
propagate any necessary state changes.

---

Outside diff comments:
In
`@feature/auth/src/commonMain/kotlin/com/mifos/feature/auth/login/LoginViewModel.kt`:
- Around line 79-105: The collector in LoginViewModel is directly mutating
_loginUiState inside loginUseCase(...).collect and must instead translate
DataState branches into internal actions and let handleAction(...) perform all
state updates; replace direct assignments and Logger calls in the collect block
with sendAction(...) calls (e.g., LoginAction.LoginLoading,
LoginAction.LoginSuccess(authData, username),
LoginAction.LoginError(errorPayload)) and include any error/result payloads
needed, then implement handling in handleAction(...) to set _loginUiState
(ShowProgress, ShowError, resetLoginFailureState,
onLoginSuccessful/onLoginFailure) so LoginViewModel only dispatches actions from
the collect block and handleAction is the single reducer that mutates
_loginUiState.
- Around line 114-123: The code is force-unwrapping nullable fields from
PostAuthenticationResponse (user.userId, user.officeId, user.permissions) before
calling prefManager.updateUser, which can crash; update LoginViewModel's success
handling to explicitly guard those fields on the received `user` (from
PostAuthenticationResponse) - check that user.userId, user.officeId and
user.permissions are non-null (and any other nullable fields used) and if any
are null emit the ShowError state (or appropriate failure state) and abort
persisting; only call prefManager.updateUser(User(...)) with the unwrapped
values after these null checks, removing all `!!` uses. Ensure you reference the
existing prefManager.updateUser call and the User construction in LoginViewModel
to apply the checks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 86dbf3af-e1ef-4604-a40c-8db819fd003b

📥 Commits

Reviewing files that changed from the base of the PR and between f59ebc6 and 70b48d3.

📒 Files selected for processing (3)
  • core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/LoginRepositoryImp.kt
  • feature/auth/src/commonMain/composeResources/values/strings.xml
  • feature/auth/src/commonMain/kotlin/com/mifos/feature/auth/login/LoginViewModel.kt
📜 Review details
🧰 Additional context used
📓 Path-based instructions (5)
**/data/repositoryImp/**/*.kt

⚙️ CodeRabbit configuration file

**/data/repositoryImp/**/*.kt: Repository Implementation Guidelines:

  • MUST convert T -> DataState<T> for one-shot APIs, and Flow<T> -> Flow<DataState<T>> using .asDataStateFlow().
  • MUST perform network availability checks, handle exceptions, and apply appropriate dispatchers.
  • Repositories act as the boundary translator. They MUST use mappers to convert DTOs (from network) and Entities (from database) into Domain Models (from :core:model) before returning data.
  • Flag: If a repository implementation returns a raw DTO or Entity directly to the caller instead of a Domain model.

Files:

  • core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/LoginRepositoryImp.kt
**/{core-base,core}/**/*.kt

⚙️ CodeRabbit configuration file

**/{core-base,core}/**/*.kt: Critical Module Change Detection:

  • Changes in core-base module must be treated as high-impact.
  • Flag any PR that modifies files inside core-base for careful review.
  • Verify that modifications in core-base are necessary and minimal.
    Output:
  • Clearly highlight that core-base is a shared foundational module and requires extra review attention.

Files:

  • core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/LoginRepositoryImp.kt
**/*.kt

⚙️ CodeRabbit configuration file

**/*.kt: Additional Code Review Guidelines:

  1. Null Safety & Stability
  • Avoid using !! operator
  • Handle null cases explicitly using safe calls or proper state handling
  • Do not assume values are always non-null without guarantees
  1. Architecture Boundaries
  • ViewModel must not depend on specific network/library implementations
  • Ensure proper separation between data, domain, and presentation layers
  • Do not format data (currency, dates, calculations) inside the UI layer
  • All formatting must be handled in the ViewModel and exposed via state (e.g., StateFlow)
  1. Performance Considerations
  • Avoid unnecessary recompositions in Compose
  • Do not attach heavy logic to frequently changing states (e.g., scrollState)
  • Prefer lifting state up instead of recomputing in child composables
  1. Compose & Navigation Best Practices
  • NEVER trigger navigation functions or side-effects directly during composition
  • Always wrap navigation calls inside LaunchedEffect or EventsEffect to avoid repeated execution on recomposition
  • Avoid triggering intensive side-effects during recomposition
  • Navigation routes must be type-safe.
  • Ensure all route classes or objects used for navigation are annotated with @Serializable.
  1. UI Structure
  • Dialogs must be separated into their own composables
  • Do not embed dialogs inline within complex main screens
  1. Localization Consistency
  • Ensure all supported languages are updated consistently across modules
  • Verify translations exist for newly added UI strings
  1. Code Cleanliness
  • Avoid unnecessary inline comments unless critical
  • Remove leftover debug or commented code
  1. Focus on correctness, readability, and maintainability over cosmetic nitpicks.
  • Avoid reviewing README, config, or asset files.
  • Prioritize identifying bugs, performance issues, and architectural concerns.
  1. Naming & Intent Rules:

Files:

  • core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/LoginRepositoryImp.kt
  • feature/auth/src/commonMain/kotlin/com/mifos/feature/auth/login/LoginViewModel.kt
**/composeResources/values*/strings.xml

⚙️ CodeRabbit configuration file

**/composeResources/values*/strings.xml: String resource conventions:

Naming:

  • All keys must follow:
    feature_{feature_name}_{ui_text_in_snake_case}

Examples:
"In Advance" → feature_loan_in_advance
"Outstanding" → feature_loan_outstanding

  • Avoid generic names like: title, text1, label
  • The suffix should be a short, readable representation of the UI text
  • Avoid multiple keys representing the same UI text
  • Keys must be lowercase and use snake_case

Flag:

  • Incorrect naming pattern
  • Generic or unclear key names
  • Duplicate keys for same UI text

Files:

  • feature/auth/src/commonMain/composeResources/values/strings.xml
**/*ViewModel.kt

⚙️ CodeRabbit configuration file

**/*ViewModel.kt: MVI architecture rules:

  • All new features must follow MVI
  • ViewModel must extend BaseViewModel
  • The ViewModel MUST maintain a single UI state (e.g., a single StateFlow)
    instead of multiple separate state variables.

Required:

  • Use *State, *Event, *Action
  • Naming must be consistent (FeatureViewModel, FeatureState, FeatureEvent, FeatureAction)
  • Follow unidirectional flow:
    Action → ViewModel → State → UI

Internal reducer/action architecture rules:

  • Async operations MUST NOT directly mutate UI state repeatedly inside
    Flow collectors, suspend callbacks, or repository result handlers.

  • Repository/network/database results MUST be converted into internal
    actions using sendAction(...).

  • handleAction(...) must act as the primary reducer responsible for:

    • state mutation
    • reducer-style state transitions
    • triggering follow-up actions
  • Large async methods must be split into:

    1. async collection layer
    2. internal action dispatching
    3. reducer/state handling
  • Avoid directly calling another business/data-loading method from
    repository collectors or async callbacks.
    Prefer dispatching follow-up internal actions instead.

Preferred pattern:
repository result
-> sendAction(...)
-> handleAction(...)
-> mutableStateFlow.update { ... }

Anti-pattern examples:
mutableStateFlow.update { ... } inside collect { }
fetchX() -> directly calls fetchY() inside async collector
large methods mixing:
- collection
- state mutation
- navigation
- business chaining

Flag:

  • Multiple mutableStateFlow.update {} calls inside collect { }
  • Direct state mutation inside async repository callbacks
  • Async methods performing both collection and reducer logic
  • Direct business-flow chaining from async collectors
  • Missing internal reducer actions for async results
  • Missing *State / *Event / *Action
  • ViewModel not...

Files:

  • feature/auth/src/commonMain/kotlin/com/mifos/feature/auth/login/LoginViewModel.kt
🧠 Learnings (2)
📚 Learning: 2026-02-06T13:15:16.968Z
Learnt from: sahilshivekar
Repo: openMF/android-client PR: 2603
File: feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanTransaction/LoanTransactionsViewModel.kt:43-106
Timestamp: 2026-02-06T13:15:16.968Z
Learning: Guideline: When a Kotlin function parameter is nullable (e.g., balance: Double?, currencyCode: String?, maximumFractionDigits: Int?) and downstream calls require a non-null value, add null-safety handling in all implementations. Specifically, avoid calling Currency.getInstance(currencyCode) with a possibly null currencyCode; provide a safe default (e.g., currencyCode ?: "$") or validate before use. Ensure all platform targets (Android/Desktop/Native) follow consistent null handling, and consider centralizing currencyCode normalization in the common layer if feasible. Add tests covering null currencyCode to prevent NPEs.

Applied to files:

  • core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/LoginRepositoryImp.kt
  • feature/auth/src/commonMain/kotlin/com/mifos/feature/auth/login/LoginViewModel.kt
📚 Learning: 2026-04-01T05:03:14.323Z
Learnt from: kartikey004
Repo: openMF/mifos-x-field-officer-app PR: 2659
File: feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanDisbursement/LoanAccountDisbursementScreen.kt:190-195
Timestamp: 2026-04-01T05:03:14.323Z
Learning: In this repo, existing `SelectableDates` / `SelectableDates.isSelectableDate(utcTimeMillis: Long)` implementations use `Clock.System.now().toEpochMilliseconds()` (UTC epoch millis) for date-boundary checks. During PR reviews, do not flag these checks for not using a timezone-aware `LocalDate` start-of-day approach; treat it as an established project-wide pattern. If a change is desired, handle it as a coordinated project-wide improvement rather than as a per-PR review issue.

Applied to files:

  • core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/LoginRepositoryImp.kt
  • feature/auth/src/commonMain/kotlin/com/mifos/feature/auth/login/LoginViewModel.kt
🔇 Additional comments (1)
feature/auth/src/commonMain/composeResources/values/strings.xml (1)

21-21: String key and copy look good.

In strings.xml, feature_auth_error_too_many_attempts is well-named and the message is user-friendly.

Comment on lines 24 to +25
override suspend fun login(username: String, password: String): PostAuthenticationResponse {
return dataManagerAuth.login(username.trim(), password.trim())
return dataManagerAuth.login(username.trim(), password)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

Repository boundary still leaks a network DTO.

In LoginRepositoryImp.kt, login (Line 24) returns PostAuthenticationResponse directly. This bypasses the repository translation boundary and couples callers to transport models.

As per coding guidelines: "MUST convert T -> DataState<T> ... Repositories ... MUST use mappers ... Flag ... returns a raw DTO or Entity directly."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@core/data/src/commonMain/kotlin/com/mifos/core/data/repositoryImp/LoginRepositoryImp.kt`
around lines 24 - 25, The login method in LoginRepositoryImp returns the network
DTO PostAuthenticationResponse directly; change it to call
dataManagerAuth.login(...) and map the returned PostAuthenticationResponse into
a domain model (or appropriate entity) using the existing mapper, then wrap the
result in a DataState before returning; update the signature/return flow of
LoginRepositoryImp.login to return DataState<YourDomainAuthModel> (or
DataState<Unit/SuccessType> as appropriate), use the mapper to translate
PostAuthenticationResponse -> Domain type, and propagate errors into DataState
as per repository conventions.

Comment on lines 81 to 85
is DataState.Error -> {
onLoginFailure()
_loginUiState.value =
LoginUiState.ShowError(Res.string.feature_auth_error_login_failed)
Logger.d("@@@", Throwable("login: ${result.data}"))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Show lockout error immediately on the threshold failure.

In LoginViewModel.kt, when the 5th failure occurs, lockout is activated but UI still shows generic login failure; lockout text appears only on the next attempt.

Short fix: make onLoginFailure() return whether lockout was triggered and map the error string accordingly.

Proposed patch
-    private fun onLoginFailure() {
+    private fun onLoginFailure(): Boolean {
         failedLoginAttempts += 1
         if (failedLoginAttempts >= MAX_FAILED_ATTEMPTS) {
             lockoutExpiresAtMillis = Clock.System.now().toEpochMilliseconds() + LOCKOUT_DURATION_MILLIS
             failedLoginAttempts = 0
+            return true
         }
+        return false
     }
-                    is DataState.Error -> {
-                        onLoginFailure()
-                        _loginUiState.value =
-                            LoginUiState.ShowError(Res.string.feature_auth_error_login_failed)
+                    is DataState.Error -> {
+                        val isLocked = onLoginFailure()
+                        _loginUiState.value = LoginUiState.ShowError(
+                            if (isLocked) Res.string.feature_auth_error_too_many_attempts
+                            else Res.string.feature_auth_error_login_failed,
+                        )
                         Logger.d("@@@", Throwable("login: ${result.data}"))
                     }
-                        } else {
-                            onLoginFailure()
-                            _loginUiState.value =
-                                LoginUiState.ShowError(Res.string.feature_auth_error_login_failed)
+                        } else {
+                            val isLocked = onLoginFailure()
+                            _loginUiState.value = LoginUiState.ShowError(
+                                if (isLocked) Res.string.feature_auth_error_too_many_attempts
+                                else Res.string.feature_auth_error_login_failed,
+                            )

Also applies to: 97-100, 135-140

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@feature/auth/src/commonMain/kotlin/com/mifos/feature/auth/login/LoginViewModel.kt`
around lines 81 - 85, The failure handling currently calls onLoginFailure() but
doesn't know if lockout was triggered, so update onLoginFailure to return a
Boolean (true when lockout threshold reached) and change all callers (the
DataState.Error branches in LoginViewModel where Logger.d and _loginUiState are
set, e.g., the blocks around the existing handlers at the mentioned locations)
to capture the returned value and choose
LoginUiState.ShowLockout(Res.string.feature_auth_error_login_locked_out) when
true, otherwise
LoginUiState.ShowError(Res.string.feature_auth_error_login_failed); also update
the onLoginFailure implementation to compute and return the lockout flag and
propagate any necessary state changes.

@IOhacker IOhacker left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Max failed Attempts is managed by the back end not by the front end. It should be removed.

_loginUiState.value = LoginUiState.PassCodeActivityIntent
}

private fun isLoginTemporarilyLocked(): Boolean {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Max failed Attempts is managed by the back end not by the front end. It should be removed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants