From 0a0b93f9c88a48184a505383c3cf4ad7d8453e23 Mon Sep 17 00:00:00 2001 From: dankito Date: Tue, 24 Sep 2024 05:55:47 +0200 Subject: [PATCH] Implemented biometric authentication on iOS (at least i hope it works, cannot test it) --- .../ui/service/AuthenticationService.kt | 4 ++-- .../banking/ui/service/BankingService.kt | 2 +- .../ui/service/AuthenticationService.ios.kt | 19 ++++++++++++++++--- iosApp/iosApp/Info.plist | 4 ++++ 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/AuthenticationService.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/AuthenticationService.kt index 10ebbc8..3a2e46a 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/AuthenticationService.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/AuthenticationService.kt @@ -23,7 +23,7 @@ fun AuthenticationService.safelyAuthenticateWithBiometrics(authenticationResult: try { this.authenticateWithBiometrics(authenticationResult) } catch (e: Throwable) { - Log.error(e) { "Could not authenticate with Biometrics" } - DI.uiState.applicationErrorOccurred(ErroneousAction.BiometricAuthentication, "Beim Login mit Fingerabdruck / Gesichtsscan ist etwas fehlgeschlagen, was nicht fehlschlagen sollte. Die folgende Fehlermeldung wird Ihnen vermutlich nichts sagen. Am besten informieren Sie die Entwickler (die faulen Säcke), z. B. mit einem Screenshot dieser Fehlermeldung, damit diese sich darum kümmern.", e) + DI.bankingService.showAndLogError(ErroneousAction.BiometricAuthentication, "Could not authenticate with Biometrics", "Beim Login mit Fingerabdruck / Gesichtsscan ist etwas fehlgeschlagen, was nicht fehlschlagen sollte. Die folgende Fehlermeldung wird Ihnen vermutlich nichts sagen. Am besten informieren Sie die Entwickler (die faulen Säcke), z. B. mit einem Screenshot dieser Fehlermeldung, damit diese sich darum kümmern.", e) + authenticationResult(AuthenticationResult(false)) } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/BankingService.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/BankingService.kt index 7c3461a..bc68a80 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/BankingService.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/BankingService.kt @@ -427,7 +427,7 @@ class BankingService( } } - private fun showAndLogError(action: ErroneousAction, logMessage: String, messageToShowToUser: String? = null, exception: Throwable? = null) { + fun showAndLogError(action: ErroneousAction, logMessage: String, messageToShowToUser: String? = null, exception: Throwable? = null) { log.error(exception) { logMessage } uiState.applicationErrorOccurred(action, messageToShowToUser, exception) diff --git a/composeApp/src/iosMain/kotlin/net/codinux/banking/ui/service/AuthenticationService.ios.kt b/composeApp/src/iosMain/kotlin/net/codinux/banking/ui/service/AuthenticationService.ios.kt index b09cdc9..50c62b4 100644 --- a/composeApp/src/iosMain/kotlin/net/codinux/banking/ui/service/AuthenticationService.ios.kt +++ b/composeApp/src/iosMain/kotlin/net/codinux/banking/ui/service/AuthenticationService.ios.kt @@ -4,12 +4,12 @@ import kotlinx.cinterop.ExperimentalForeignApi import kotlinx.cinterop.memScoped import kotlinx.cinterop.refTo import net.codinux.banking.ui.model.AuthenticationResult -import platform.CoreCrypto.CCCalibratePBKDF import platform.CoreCrypto.CCKeyDerivationPBKDF import platform.CoreCrypto.CC_SHA512 import platform.CoreCrypto.CC_SHA512_DIGEST_LENGTH import platform.CoreCrypto.kCCPBKDF2 import platform.CoreCrypto.kCCPRFHmacAlgSHA256 +import platform.LocalAuthentication.LAContext import platform.Security.SecRandomCopyBytes import platform.Security.kSecRandomDefault @@ -35,10 +35,23 @@ actual object AuthenticationService { } - actual val supportsBiometricAuthentication = false // TODO + actual val supportsBiometricAuthentication: Boolean by lazy { + try { + val localAuthenticationContext = LAContext() + + localAuthenticationContext.canEvaluatePolicy(platform.LocalAuthentication.LAPolicyDeviceOwnerAuthenticationWithBiometrics, null) + } catch (e: Throwable) { + false + } + } actual fun authenticateWithBiometrics(authenticationResult: (AuthenticationResult) -> Unit) { - authenticationResult(AuthenticationResult(false, "Biometrics is not implemented yet")) + val context = LAContext() + val reason = "Authentifizieren Sie sich bitte um die App zu entsperren" + + context.evaluatePolicy(platform.LocalAuthentication.LAPolicyDeviceOwnerAuthenticationWithBiometrics, reason) { success, error -> + authenticationResult(AuthenticationResult(success, error?.localizedDescription)) + } } diff --git a/iosApp/iosApp/Info.plist b/iosApp/iosApp/Info.plist index e4d356d..919da14 100644 --- a/iosApp/iosApp/Info.plist +++ b/iosApp/iosApp/Info.plist @@ -22,6 +22,10 @@ $(CURRENT_PROJECT_VERSION) LSRequiresIPhoneOS + NSCameraUsageDescription + Used to scan QR codes to initiate money transfer + NSFaceIDUsageDescription + On user demand we use FaceID to unlock the app UIApplicationSceneManifest UIApplicationSupportsMultipleScenes