Skip to content

Commit

Permalink
Fixed authenticators
Browse files Browse the repository at this point in the history
  • Loading branch information
smikhalevski committed Oct 26, 2023
1 parent 60e2859 commit 9587ffe
Show file tree
Hide file tree
Showing 9 changed files with 147 additions and 46 deletions.
1 change: 1 addition & 0 deletions android/example/src/main/java/com/example/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ class MainActivity : AppCompatActivity() {
eventBus.register(FacebookLoginPlugin(this))
eventBus.register(FacebookSharePlugin(this))
eventBus.register(BiometricPlugin(this))
eventBus.register(BiometricEncryptedStoragePlugin(this, File(filesDir, "biometric_storage")))
eventBus.register(ToastPlugin(this))

@Suppress("DEPRECATION")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import androidx.core.content.ContextCompat
import androidx.fragment.app.FragmentActivity
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import org.racehorse.utils.ifNullOrBlank
import java.io.File
import java.io.Serializable
import java.security.KeyStore
Expand Down Expand Up @@ -87,7 +88,7 @@ open class BiometricEncryptedStoragePlugin(private val activity: FragmentActivit

private val encryptedStorage = EncryptedStorage(storageDir)

@Subscribe(threadMode = ThreadMode.ASYNC)
@Subscribe(threadMode = ThreadMode.MAIN)
open fun onSetBiometricEncryptedValue(event: SetBiometricEncryptedValueEvent) {
val baseCipher = getCipher()
baseCipher.init(Cipher.ENCRYPT_MODE, getSecretKey(event.key))
Expand All @@ -102,7 +103,7 @@ open class BiometricEncryptedStoragePlugin(private val activity: FragmentActivit
}
}

@Subscribe(threadMode = ThreadMode.ASYNC)
@Subscribe(threadMode = ThreadMode.MAIN)
open fun onGetBiometricEncryptedValue(event: GetBiometricEncryptedValueEvent) {
val (iv, encryptedBytes) = encryptedStorage.getRecord(event.key)
?: return event.respond(GetEncryptedValueEvent.ResultEvent(null))
Expand Down Expand Up @@ -153,13 +154,13 @@ open class BiometricEncryptedStoragePlugin(private val activity: FragmentActivit
}

val promptInfoBuilder = BiometricPrompt.PromptInfo.Builder()
.setTitle(config?.title ?: "Authentication required")
.setTitle(config?.title.ifNullOrBlank { "Authentication required" })
.setSubtitle(config?.subtitle)
.setDescription(config?.description)
.setAllowedAuthenticators(authenticators)

if (config?.negativeButtonText != null && authenticators and BiometricManager.Authenticators.BIOMETRIC_WEAK == 0) {
promptInfoBuilder.setNegativeButtonText(config.negativeButtonText)
if (authenticators and BiometricManager.Authenticators.DEVICE_CREDENTIAL == 0) {
promptInfoBuilder.setNegativeButtonText(config?.negativeButtonText.ifNullOrBlank { "Discard" })
}

try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ enum class BiometricAuthenticator(val value: Int) {
fun from(authenticators: Array<BiometricAuthenticator>?): Int {
val result = authenticators?.map(BiometricAuthenticator::value)?.fold(0, Int::or) ?: 0

return if (result == 0) BiometricManager.Authenticators.BIOMETRIC_WEAK else result
return if (result == 0) BiometricManager.Authenticators.BIOMETRIC_STRONG else result
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package org.racehorse.utils

inline fun String?.ifNullOrBlank(defaultValue: () -> String): String =
if (isNullOrBlank()) defaultValue() else this
2 changes: 2 additions & 0 deletions web/example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ import { FacebookLoginExample } from './examples/FacebookLoginExample';
import { FacebookShareExample } from './examples/FacebookShareExample';
import { DownloadExample } from './examples/DownloadExample';
import { BiometricExample } from './examples/BiometricExample';
import { BiometricEncryptedStorageExample } from './examples/BiometricEncryptedStorageExample';

export function App() {
return (
<>
<ToastExample />
<BiometricExample />
<BiometricEncryptedStorageExample />
<DownloadExample />
<KeyboardExample />
<FacebookShareExample />
Expand Down
78 changes: 78 additions & 0 deletions web/example/src/examples/BiometricEncryptedStorageExample.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import React, { useEffect, useState } from 'react';
import { FormattedJSON } from '../components/FormattedJSON';
import { BiometricAuthenticator, BiometricConfig, biometricEncryptedStorageManager } from 'racehorse';

const biometricConfig: BiometricConfig = {
title: 'Authentication required',
authenticators: [BiometricAuthenticator.BIOMETRIC_STRONG],
};

export function BiometricEncryptedStorageExample() {
const [key, setKey] = useState('my_key');
const [value, setValue] = useState('my_value');
const [persistedValue, setPersistedValue] = useState<string | null>(null);

useEffect(() => {
biometricEncryptedStorageManager.get(key).then(setPersistedValue);
}, [key, value]);

return (
<>
<h2>{'Biometric encrypted storage'}</h2>

<div style={{ display: 'flex', gap: '10px' }}>
<div>
{'Key:'}
<br />
<input
type="text"
value={key}
size={10}
onChange={event => {
setKey(event.target.value);
}}
/>
</div>

<div>
{'Value:'}
<br />
<input
type="text"
value={value}
size={10}
onChange={event => {
setValue(event.target.value);
}}
/>
</div>
</div>

<p>
<button
onClick={() => {
biometricEncryptedStorageManager.set(key, value, biometricConfig).then(ok => {
if (ok) {
biometricEncryptedStorageManager.get(key, biometricConfig).then(setPersistedValue);
}
});
}}
>
{'Set value'}
</button>{' '}
<button
onClick={() => {
if (biometricEncryptedStorageManager.delete(key)) {
biometricEncryptedStorageManager.get(key, biometricConfig).then(setPersistedValue);
}
}}
>
{'Delete value'}
</button>
</p>

{'Persisted value: '}
<FormattedJSON value={persistedValue} />
</>
);
}
83 changes: 45 additions & 38 deletions web/example/src/examples/EncryptedStorageExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,58 +15,65 @@ export function EncryptedStorageExample() {
return (
<>
<h2>{'Encrypted storage'}</h2>
<p>
{'Key:'}
<br />
<input
type="text"
value={key}
onChange={event => {
setKey(event.target.value);
}}
/>
</p>

<p>
{'Value:'}
<br />
<input
type="text"
value={value}
onChange={event => {
setValue(event.target.value);
}}
/>
</p>
<div style={{ display: 'flex', gap: '10px' }}>
<div>
{'Key:'}
<br />
<input
type="text"
value={key}
size={10}
onChange={event => {
setKey(event.target.value);
}}
/>
</div>

<p>
{'Password:'}
<br />
<input
type="text"
value={password}
onChange={event => {
setPassword(event.target.value);
}}
/>
</p>
<div>
{'Value:'}
<br />
<input
type="text"
value={value}
size={10}
onChange={event => {
setValue(event.target.value);
}}
/>
</div>

<div>
{'Password:'}
<br />
<input
type="text"
value={password}
size={10}
onChange={event => {
setPassword(event.target.value);
}}
/>
</div>
</div>

<p>
<button
onClick={() => {
encryptedStorageManager.set(key, value, password).then(() => {
encryptedStorageManager.get(key, password).then(setPersistedValue);
encryptedStorageManager.set(key, value, password).then(ok => {
if (ok) {
encryptedStorageManager.get(key, password).then(setPersistedValue);
}
});
}}
>
{'Set value'}
</button>{' '}
<button
onClick={() => {
encryptedStorageManager.delete(key);
encryptedStorageManager.get(key, password).then(() => {
if (encryptedStorageManager.delete(key)) {
encryptedStorageManager.get(key, password).then(setPersistedValue);
});
}
}}
>
{'Delete value'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,15 @@ export interface BiometricConfig {
title?: string;
subtitle?: string;
description?: string;

/**
* The label on the button that aborts the authentication.
*/
negativeButtonText?: string;

/**
* The list of allowed authenticators.
*/
authenticators?: BiometricAuthenticator[];
}

Expand Down
4 changes: 2 additions & 2 deletions web/racehorse/src/main/createBiometricManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export interface BiometricManager {
* Returns the status of the biometric authentication support for a given set of authenticators.
*
* @param authenticators The array of authenticators that must be supported for successful result. If omitted, or if
* an empty array is provided then {@link BiometricAuthenticator.BIOMETRIC_WEAK} is used.
* an empty array is provided then {@link BiometricAuthenticator.BIOMETRIC_STRONG} is used.
*/
getBiometricStatus(authenticators?: BiometricAuthenticator[]): BiometricStatus;

Expand All @@ -66,7 +66,7 @@ export interface BiometricManager {
* without any user interaction.
*
* @param authenticators The array of authenticators that must be supported for successful enrollment. If omitted, or
* if an empty array is provided then {@link BiometricAuthenticator.BIOMETRIC_WEAK} is used.
* if an empty array is provided then {@link BiometricAuthenticator.BIOMETRIC_STRONG} is used.
* @return `true` if biometric enrollment succeeded, or `false` otherwise.
*/
enrollBiometric(authenticators?: BiometricAuthenticator[]): Promise<boolean>;
Expand Down

0 comments on commit 9587ffe

Please sign in to comment.