forked from shihaam/thijooree
87 lines
3.2 KiB
Markdown
87 lines
3.2 KiB
Markdown
# Lock Screen
|
||
|
||
`LockActivity` is shown whenever the app is locked — on cold start (when credentials exist), after the autolock timer fires, or when the user taps the lock icon in the toolbar.
|
||
|
||
---
|
||
|
||
## Authentication Methods
|
||
|
||
The app attempts authentication in priority order:
|
||
|
||
1. **Biometrics** — if enrolled and enabled, `BiometricPrompt` is presented automatically on open
|
||
2. **PIN** — numeric keypad
|
||
3. **Pattern** — `PatternView` grid
|
||
|
||
The user can switch between biometric and PIN/pattern manually.
|
||
|
||
---
|
||
|
||
## Biometric Authentication
|
||
|
||
Uses Android `BiometricPrompt` with `BIOMETRIC_WEAK` (fingerprint or face depending on device). A successful biometric result sets `app.isUnlocked = true` and calls `MainActivity` to route to `HomeActivity`.
|
||
|
||
On biometric failure or cancellation the screen falls back to PIN/pattern entry.
|
||
|
||
---
|
||
|
||
## PIN Entry
|
||
|
||
- A custom on-screen numeric keypad (0–9 + backspace + confirm)
|
||
- The entered digits are shown as filled/unfilled circles (no digit echo)
|
||
- Confirm fires verification immediately when the correct number of digits is entered
|
||
|
||
---
|
||
|
||
## Pattern Entry
|
||
|
||
- The same `PatternView` widget used in onboarding, in verify-only mode
|
||
- The drawn pattern is hashed and compared against the stored derived key
|
||
|
||
---
|
||
|
||
## Verification
|
||
|
||
The entered PIN or pattern is run through **PBKDF2-HMAC-SHA256** with the stored salt and compared to the stored hash. On match:
|
||
|
||
1. `app.isUnlocked = true`
|
||
2. `LockActivity` finishes
|
||
3. `MainActivity` routes to `HomeActivity`
|
||
|
||
On mismatch the attempt counter increments and an error shake animation plays.
|
||
|
||
---
|
||
|
||
## Brute-Force Protection
|
||
|
||
Constants live in `LockActivity.kt:44-45`: `MAX_ATTEMPTS = 5`, `LOCKOUT_MS = 30_000L`.
|
||
|
||
| Threshold | Behaviour |
|
||
|---|---|
|
||
| 1–4 wrong attempts | Error label shows remaining attempts |
|
||
| 5 wrong attempts | 30-second lockout; further entries are rejected by `checkAndShowLockout()` until `LOCKOUT_MS` has elapsed since the last fail |
|
||
| After 30 s | Lockout expires (purely time-based, via `last_fail_time`) — the counter itself does **not** reset until a successful unlock |
|
||
|
||
The fail counter resets to zero only inside `resetFailures()` (`LockActivity.kt:313-315`), which is called from the success paths of biometric, PIN, and pattern entry. A user who repeatedly fails will hit the 30-second wait again on the very first failure after each lockout window expires.
|
||
|
||
The attempt counter and last-fail timestamp live in a dedicated `lock_attempts` `SharedPreferences` file (`LockActivity.kt:41`) — plain (not encrypted), which is a known limitation documented in the security audit. The app does not wipe credentials after repeated failures.
|
||
|
||
---
|
||
|
||
## `app.isUnlocked` Guard
|
||
|
||
`app.isUnlocked` is an in-memory flag that is `false` on every process start. Even if an attacker bypasses `LockActivity` via `adb`, `HomeActivity` checks this flag and re-fires `LockActivity` on resume if it is `false`. This prevents cold-start bypass.
|
||
|
||
---
|
||
|
||
## Screenshot Protection
|
||
|
||
`FLAG_SECURE` is set on `LockActivity`'s window, preventing screenshots and screen recording. This is always on for the lock screen regardless of the user's global screenshots setting.
|
||
|
||
---
|
||
|
||
|
||
|
||
---
|
||
|
||
[← Onboarding](01-onboarding.md) **Next →** [Login](03-login.md)
|