Skip to content

Commit

Permalink
Biometrics check updates (#1326)
Browse files Browse the repository at this point in the history
  • Loading branch information
danvleju-rdx committed Sep 9, 2024
1 parent 9efb25e commit 86d335d
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public enum UserDefaultsKey: String, Sendable, Hashable, CaseIterable {
case showRelinkConnectorsAfterUpdate
case showRelinkConnectorsAfterProfileRestore
case homeCards
case appLockMessageShown

/// DO NOT CHANGE THIS KEY
case activeProfileID
Expand Down Expand Up @@ -233,6 +234,14 @@ extension UserDefaults.Dependency {
public func setHomeCards(_ value: Data) {
set(data: value, key: .homeCards)
}

public var appLockMessageShown: Bool {
bool(key: .appLockMessageShown)
}

public func setAppLockMessageShown(_ value: Bool) {
set(value, forKey: Key.appLockMessageShown.rawValue)
}
}

// MARK: - BackupResult
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ extension UserDefaults.Dependency.Key {
return [userDefaults.showRelinkConnectorsAfterProfileRestore].map(String.init(describing:))
case .homeCards:
return [userDefaults.getHomeCards() == nil ? "No Data available" : "Data available"]
case .appLockMessageShown:
return [userDefaults.appLockMessageShown].map(String.init(describing:))
}
}
}
25 changes: 9 additions & 16 deletions RadixWallet/Features/SettingsFeature/Preferences/Preferences.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public struct Preferences: Sendable, FeatureReducer {

public enum InternalAction: Sendable, Equatable {
case loadedAppPreferences(AppPreferences)
case advancedLockDisableResult(TaskResult<Bool>)
case advancedLockToggleResult(authResult: TaskResult<Bool>, isEnabled: Bool)
}

public struct Destination: DestinationReducer {
Expand Down Expand Up @@ -111,10 +111,11 @@ public struct Preferences: Sendable, FeatureReducer {
}

case let .advancedLockToogled(isEnabled):
if !isEnabled {
return confirmAdvancedLockDisableWithBiometrics()
} else {
return updateAdvancedLock(state: &state, isEnabled: isEnabled)
return .run { send in
let authResult = await TaskResult<Bool> {
try await localAuthenticationClient.authenticateWithBiometrics()
}
await send(.internal(.advancedLockToggleResult(authResult: authResult, isEnabled: isEnabled)))
}

case .exportLogsButtonTapped:
Expand All @@ -133,13 +134,13 @@ public struct Preferences: Sendable, FeatureReducer {
state.appPreferences = appPreferences
return .none

case let .advancedLockDisableResult(.failure(error)):
case let .advancedLockToggleResult(.failure(error), _):
errorQueue.schedule(error)
return .none

case let .advancedLockDisableResult(.success(success)):
case let .advancedLockToggleResult(.success(success), isEnabled):
guard success else { return .none }
return updateAdvancedLock(state: &state, isEnabled: false)
return updateAdvancedLock(state: &state, isEnabled: isEnabled)
}
}

Expand All @@ -158,14 +159,6 @@ public struct Preferences: Sendable, FeatureReducer {
}
}

private func confirmAdvancedLockDisableWithBiometrics() -> Effect<Action> {
.run { send in
await send(.internal(.advancedLockDisableResult(.init {
try await localAuthenticationClient.authenticateWithBiometrics()
})))
}
}

private func updateAdvancedLock(state: inout State, isEnabled: Bool) -> Effect<Action> {
state.appPreferences?.security.isAdvancedLockEnabled = isEnabled
guard let preferences = state.appPreferences else { return .none }
Expand Down
57 changes: 43 additions & 14 deletions RadixWallet/Features/SplashFeature/Splash.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public struct Splash: Sendable, FeatureReducer {
case passcodeConfigResult(TaskResult<LocalAuthenticationConfig>)
case biometricsCheckResult(TaskResult<Bool>)
case advancedLockStateLoaded(isEnabled: Bool)
case showAppLockMessage
}

public enum DelegateAction: Sendable, Equatable {
Expand All @@ -53,6 +54,7 @@ public struct Splash: Sendable, FeatureReducer {
public enum ErrorAlert: Sendable, Equatable {
case retryVerifyPasscodeButtonTapped
case openSettingsButtonTapped
case appLockOkButtonTapped
}
}

Expand All @@ -64,6 +66,7 @@ public struct Splash: Sendable, FeatureReducer {
@Dependency(\.localAuthenticationClient) var localAuthenticationClient
@Dependency(\.onboardingClient) var onboardingClient
@Dependency(\.openURL) var openURL
@Dependency(\.userDefaults) var userDefaults

public init() {}

Expand All @@ -82,14 +85,24 @@ public struct Splash: Sendable, FeatureReducer {
return .run { send in
let isAdvancedLockEnabled = await onboardingClient.loadProfile().appPreferences.security.isAdvancedLockEnabled

guard #available(iOS 18, *) else {
// For versions below iOS 18, perform the advanced lock state check
if isAdvancedLockEnabled {
#if targetEnvironment(simulator)
let isEnabled = _XCTIsTesting
#else
let isEnabled = true
#endif
await send(.internal(.advancedLockStateLoaded(isEnabled: isEnabled)))
} else {
await send(.internal(.advancedLockStateLoaded(isEnabled: false)))
}
return
}

// Starting with iOS 18, the system-provided biometric check will be used
if #unavailable(iOS 18), isAdvancedLockEnabled {
#if targetEnvironment(simulator)
let isEnabled = _XCTIsTesting
#else
let isEnabled = true
#endif
await send(.internal(.advancedLockStateLoaded(isEnabled: isEnabled)))
if isAdvancedLockEnabled, !userDefaults.appLockMessageShown {
await send(.internal(.showAppLockMessage))
} else {
await send(.internal(.advancedLockStateLoaded(isEnabled: false)))
}
Expand Down Expand Up @@ -137,11 +150,9 @@ public struct Splash: Sendable, FeatureReducer {
case let .biometricsCheckResult(.failure(error)):
state.biometricsCheckFailed = true
state.destination = .errorAlert(.init(
title: .init(L10n.Common.errorAlertTitle),
message: .init(error.localizedDescription),
buttons: [
.default(.init(L10n.Common.ok)),
]
title: { .init(L10n.Common.errorAlertTitle) },
actions: { .default(.init(L10n.Common.ok)) },
message: { .init(error.localizedDescription) }
))
return .none

Expand All @@ -152,17 +163,35 @@ public struct Splash: Sendable, FeatureReducer {
}

return delegateCompleted(context: state.context)

case .showAppLockMessage:
state.destination = .errorAlert(.init(
title: { .init(L10n.Biometrics.AppLockAvailableAlert.title) },
actions: {
.default(
.init(L10n.Common.dismiss),
action: .send(.appLockOkButtonTapped)
)
},
message: { .init(L10n.Biometrics.AppLockAvailableAlert.message) }
))
return .none
}
}

public func reduce(into state: inout State, presentedAction: Destination.Action) -> Effect<Action> {
switch presentedAction {
case .errorAlert(.retryVerifyPasscodeButtonTapped):
verifyPasscode()
return verifyPasscode()

case .errorAlert(.openSettingsButtonTapped):
.run { _ in
return .run { _ in
await openURL(URL(string: UIApplication.openSettingsURLString)!)
}

case .errorAlert(.appLockOkButtonTapped):
userDefaults.setAppLockMessageShown(true)
return .send(.internal(.advancedLockStateLoaded(isEnabled: false)))
}
}

Expand Down

0 comments on commit 86d335d

Please sign in to comment.