mirror of
https://github.com/ProtonMail/ios-mail.git
synced 2026-05-15 09:50:39 +00:00
114 lines
3.8 KiB
Swift
114 lines
3.8 KiB
Swift
// Copyright (c) 2025 Proton Technologies AG
|
|
//
|
|
// This file is part of Proton Mail.
|
|
//
|
|
// Proton Mail is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Proton Mail is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Proton Mail. If not, see https://www.gnu.org/licenses/.
|
|
|
|
import Combine
|
|
import InboxCore
|
|
import proton_app_uniffi
|
|
|
|
class LockScreenStore: StateStore {
|
|
@Published var state: LockScreenState
|
|
private let pinVerifier: PINVerifier
|
|
private let biometricAuthorizationNotifier: BiometricAuthorizationNotifier
|
|
private let signOutService: SignOutService
|
|
private let dismissLock: () -> Void
|
|
|
|
init(
|
|
state: LockScreenState,
|
|
pinVerifier: PINVerifier,
|
|
biometricAuthorizationNotifier: BiometricAuthorizationNotifier,
|
|
signOutService: SignOutService,
|
|
dismissLock: @escaping () -> Void
|
|
) {
|
|
self.state = state
|
|
self.pinVerifier = pinVerifier
|
|
self.signOutService = signOutService
|
|
self.biometricAuthorizationNotifier = biometricAuthorizationNotifier
|
|
self.dismissLock = dismissLock
|
|
}
|
|
|
|
func handle(action: LockScreenAction) async {
|
|
switch action {
|
|
case .biometric(let output):
|
|
switch output {
|
|
case .authenticated:
|
|
biometricAuthorizationNotifier.biometricsCheckPassed()
|
|
dismissLock()
|
|
case .logOut:
|
|
await signOutAllAccounts()
|
|
}
|
|
case .pin(let output):
|
|
switch output {
|
|
case .logOut:
|
|
await signOutAllAccounts()
|
|
case .pin(let pin):
|
|
await verify(pin: pin)
|
|
}
|
|
case .pinScreenLoaded:
|
|
let pinAttemptsRemaining = await readNumberOfAttempts()
|
|
if pinAttemptsRemaining <= 3 {
|
|
handlePinAuthenticationError(attemptsLeft: pinAttemptsRemaining)
|
|
}
|
|
}
|
|
}
|
|
|
|
private func signOutAllAccounts() async {
|
|
do {
|
|
try await signOutService.signOutAllAccounts()
|
|
dismissLock()
|
|
} catch {
|
|
AppLogger.log(error: error, category: .appSettings)
|
|
}
|
|
}
|
|
|
|
private func handlePinAuthenticationError(attemptsLeft: Int) {
|
|
switch attemptsLeft {
|
|
case 0:
|
|
dismissLock()
|
|
case 1...3:
|
|
state =
|
|
state
|
|
.copy(\.pinAuthenticationError, to: .attemptsRemaining(attemptsLeft))
|
|
default:
|
|
state =
|
|
state
|
|
.copy(\.pinAuthenticationError, to: .custom(L10n.PINLock.invalidPIN.string))
|
|
}
|
|
}
|
|
|
|
private func verify(pin: PIN) async {
|
|
switch await pinVerifier.verifyPinCode(pin: pin.digits) {
|
|
case .ok:
|
|
dismissLock()
|
|
case .error(let error) where error == .reason(.tooFrequentAttempts):
|
|
state = state.copy(\.pinAuthenticationError, to: .tooFrequentAttempts)
|
|
case .error:
|
|
let pinAttemptsRemaining = await readNumberOfAttempts()
|
|
handlePinAuthenticationError(attemptsLeft: pinAttemptsRemaining)
|
|
}
|
|
}
|
|
|
|
private func readNumberOfAttempts() async -> Int {
|
|
do {
|
|
let attempts = try await pinVerifier.remainingPinAttempts().get() ?? 0
|
|
return Int(attempts)
|
|
} catch {
|
|
AppLogger.log(error: error, category: .appSettings)
|
|
return 0
|
|
}
|
|
}
|
|
}
|