Skip to content

Commit

Permalink
Merge pull request #17 from nevissecurity/feature/NEVISACCESSAPP-5283-…
Browse files Browse the repository at this point in the history
…Delete-local-data

NEVISACCESSAPP-5283: Delete local data
  • Loading branch information
tamas-toth authored Nov 13, 2023
2 parents 1b01724 + d41ab21 commit dbe1878
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 14 deletions.
5 changes: 5 additions & 0 deletions NevisExampleApp/Model/Operation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ public enum Operation {
/// Device information change operation.
case deviceInformationChange

/// Local data operation.
case localData

/// Unknown operation.
case unknown

Expand All @@ -54,6 +57,8 @@ public enum Operation {
return L10n.Operation.Pinchange.title
case .deviceInformationChange:
return L10n.Operation.DeviceInformationChange.title
case .localData:
return L10n.Operation.LocalData.title
case .unknown:
return String()
}
Expand Down
4 changes: 3 additions & 1 deletion NevisExampleApp/Resources/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"home_pin_change_button" = "PIN change";
"home_change_device_information_button" = "Change Device Information";
"home_auth_cloud_api_registration_button" = "Auth Cloud Api Registration";
"home_delete_authenticators_button" = "Delete Authenticators";
"home_separator" = "Identity Suite only";
"home_in_band_registration_button" = "In-Band Register";

Expand Down Expand Up @@ -76,7 +77,7 @@
"logging_title" = "Pull to see log";

// Operation
"operation_success_title" = "%@ successful!";
"operation_success_title" = "%@ succeeded!";
"operation_failed_title" = "%@ failed!";
"operation_init_client_title" = "Client initialization";
"operation_payload_decode_title" = "Payload decode";
Expand All @@ -86,6 +87,7 @@
"operation_deregistration_title" = "Deregistration";
"operation_pin_change_title" = "PIN change";
"operation_device_information_change_title" = "Device information change";
"operation_local_data_title" = "Local data operation";

// Error
"error_generic_title" = "Failure";
Expand Down
104 changes: 93 additions & 11 deletions NevisExampleApp/Screens/Home/HomePresenter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,13 @@ extension HomePresenter {

/// Starts an In-Band Authentication operation.
func authenticate() {
let accounts = mobileAuthenticationClient?.localData.accounts ?? [any Account]()
guard let accounts = mobileAuthenticationClient?.localData.accounts, !accounts.isEmpty else {
logger.log("Accounts not found.", color: .red)
let operationError = OperationError(operation: .authentication,
underlyingError: AppError.accountsNotFound)
return errorHandlerChain.handle(error: operationError)
}

let parameter: SelectAccountParameter = .select(accounts: accounts,
operation: .authentication,
handler: nil,
Expand Down Expand Up @@ -157,22 +163,30 @@ extension HomePresenter {

/// Starts PIN changing.
func changePin() {
// find enrolled accounts
guard let accounts = mobileAuthenticationClient?.localData.accounts, !accounts.isEmpty else {
let operationError = OperationError(operation: .pinChange,
underlyingError: AppError.accountsNotFound)
return errorHandlerChain.handle(error: operationError)
}

// find PIN authenticator
guard let authenticators = mobileAuthenticationClient?.localData.authenticators else {
return errorHandlerChain.handle(error: AppError.pinAuthenticatorNotFound)
let operationError = OperationError(operation: .pinChange,
underlyingError: AppError.pinAuthenticatorNotFound)
return errorHandlerChain.handle(error: operationError)
}

guard let pinAuthenticator = authenticators.filter({ $0.aaid == AuthenticatorAaid.Pin.rawValue }).first else {
return errorHandlerChain.handle(error: AppError.pinAuthenticatorNotFound)
let operationError = OperationError(operation: .pinChange,
underlyingError: AppError.pinAuthenticatorNotFound)
return errorHandlerChain.handle(error: operationError)
}

guard let enrollment = pinAuthenticator.userEnrollment as? SdkUserEnrollment else {
return errorHandlerChain.handle(error: AppError.pinAuthenticatorNotFound)
}

// find enrolled accounts
guard let accounts = mobileAuthenticationClient?.localData.accounts else {
return errorHandlerChain.handle(error: AppError.accountsNotFound)
let operationError = OperationError(operation: .pinChange,
underlyingError: AppError.pinAuthenticatorNotFound)
return errorHandlerChain.handle(error: operationError)
}

let eligibleAccounts = accounts.filter { account in
Expand All @@ -183,7 +197,9 @@ extension HomePresenter {

switch eligibleAccounts.count {
case 0:
errorHandlerChain.handle(error: AppError.accountsNotFound)
let operationError = OperationError(operation: .pinChange,
underlyingError: AppError.accountsNotFound)
return errorHandlerChain.handle(error: operationError)
case 1:
// do PIN change automatically
doPinChange(for: eligibleAccounts.first!.username)
Expand All @@ -202,7 +218,9 @@ extension HomePresenter {
let deviceInformation = mobileAuthenticationClient?.localData.deviceInformation
guard let deviceInformation else {
logger.log("Device information not found.", color: .red)
return errorHandlerChain.handle(error: AppError.deviceInformationNotFound)
let operationError = OperationError(operation: .deviceInformationChange,
underlyingError: AppError.deviceInformationNotFound)
return errorHandlerChain.handle(error: operationError)
}

let parameter: ChangeDeviceInformationParameter = .change(deviceInformation: deviceInformation)
Expand All @@ -214,6 +232,29 @@ extension HomePresenter {
appCoordinator.navigateToAuthCloudApiRegistration()
}

/// Deletes local authenticators.
func deleteLocalAuthenticators() {
// find enrolled accounts
guard let accounts = mobileAuthenticationClient?.localData.accounts, !accounts.isEmpty else {
logger.log("Accounts not found.", color: .red)
let operationError = OperationError(operation: .localData,
underlyingError: AppError.accountsNotFound)
return errorHandlerChain.handle(error: operationError)
}

doDeleteAuthenticators(of: accounts.map(\.username)) { result in
switch result {
case .success:
self.logger.log("Delete authenticators succeeded.", color: .green)
self.appCoordinator.navigateToResult(with: .success(operation: .localData))
case let .failure(error):
self.logger.log("Delete authenticators failed.", color: .red)
let operationError = OperationError(operation: .localData, underlyingError: error)
self.errorHandlerChain.handle(error: operationError)
}
}
}

/// Starts In-Band registration operation.
func register() {
appCoordinator.navigateToUsernamePasswordLogin()
Expand Down Expand Up @@ -268,4 +309,45 @@ private extension HomePresenter {
}
.execute()
}

/// Deletes all local authenticators of all accounts.
///
/// - Parameters:
/// - usernames: The usernames of the enrolled accounts.
/// - handler: The code need to be executed after deletion.
func doDeleteAuthenticators(of usernames: [Username], completion handler: @escaping (Result<(), Error>) -> ()) {
var remainingUsernames = usernames
guard let username = remainingUsernames.popLast() else {
return handler(.success)
}

doDeleteAuthenticators(of: username) { result in
if case let .failure(error) = result {
return handler(.failure(error))
}
self.logger.log("Delete authenticators succeeded for user \(username).", color: .green)
self.doDeleteAuthenticators(of: remainingUsernames, completion: handler)
}
}

/// Deletes all local authenticators of an account.
///
/// - Parameters:
/// - usernames: The username of the enrolled account.
/// - handler: The code need to be executed after deletion.
func doDeleteAuthenticators(of username: Username, completion handler: @escaping (Result<(), Error>) -> ()) {
DispatchQueue.global().async {
do {
try self.mobileAuthenticationClient?.localData.deleteAuthenticator(username: username, aaid: nil)
DispatchQueue.main.async {
handler(.success)
}
}
catch {
DispatchQueue.main.async {
handler(.failure(error))
}
}
}
}
}
17 changes: 17 additions & 0 deletions NevisExampleApp/Screens/Home/HomeScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ final class HomeScreen: BaseScreen, Screen {
/// The Auth Cloud Api Register button.
private let authCloudApiRegisterButton = OutlinedButton(title: L10n.Home.authCloudApiRegistration)

/// The Delete Authenticators button.
private let deleteAuthenticatorsButton = OutlinedButton(title: L10n.Home.deleteAuthenticators)

/// The separator label.
private let separatorLabel = NSLabel(text: L10n.Home.separator, style: .normal)

Expand Down Expand Up @@ -102,6 +105,7 @@ private extension HomeScreen {
setupPinChangeButton()
setupChangeDeviceInformationButton()
setupAuthCloudApiRegisterButton()
setupDeleteAuthenticatorsButton()
setupSeparatorLabel()
setupInBandRegisterButton()
}
Expand Down Expand Up @@ -166,6 +170,14 @@ private extension HomeScreen {
}
}

func setupDeleteAuthenticatorsButton() {
deleteAuthenticatorsButton.do {
addItemToBottom($0, spacing: 16)
$0.setHeight(with: 40)
$0.addTarget(self, action: #selector(deleteAuthenticators), for: .touchUpInside)
}
}

func setupSeparatorLabel() {
separatorLabel.do {
addItemToBottom($0, spacing: 8)
Expand Down Expand Up @@ -216,6 +228,11 @@ private extension HomeScreen {
presenter.authCloudApiRegister()
}

@objc
func deleteAuthenticators() {
presenter.deleteLocalAuthenticators()
}

@objc
func register() {
presenter.register()
Expand Down
11 changes: 9 additions & 2 deletions NevisExampleApp/Utility/Localization/Strings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,10 @@ enum L10n {
static let changePin = L10n.tr("home_pin_change_button")
/// Change device information button: "Change Device Information"
static let changeDeviceInformation = L10n.tr("home_change_device_information_button")
/// Auth cloud api registration button: "Auth Cloud Api Registration"
/// Auth Cloud Api registration button: "Auth Cloud Api Registration"
static let authCloudApiRegistration = L10n.tr("home_auth_cloud_api_registration_button")
/// Delete authenticators button: "Delete Authenticators"
static let deleteAuthenticators = L10n.tr("home_delete_authenticators_button")
/// Screen description: "Identity Suite only"
static let separator = L10n.tr("home_separator")
/// In-band registration button: "In-Band Register"
Expand Down Expand Up @@ -289,9 +291,14 @@ enum L10n {
static let title = L10n.tr("operation_device_information_change_title")
}

enum LocalData {
/// Operation title: "Local data operation"
static let title = L10n.tr("operation_local_data_title")
}

/// Successful operation related localized strings.
enum Success {
/// Title: "%@ successful!"
/// Title: "%@ succeeded!"
///
/// - parameter operation: The current operation.
/// - returns: The localized string.
Expand Down

0 comments on commit dbe1878

Please sign in to comment.