Skip to content

Commit 7ac6390

Browse files
committed
chore: reinitialized repository
1 parent 13bac08 commit 7ac6390

22 files changed

Lines changed: 2411 additions & 4798 deletions

File tree

.github/ISSUE_TEMPLATE/bug_report.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,5 @@ body:
6363
attributes:
6464
label: Reproducible example repository
6565
description: Please provide a link to a repository on GitHub with a reproducible example.
66-
render: js
6766
validations:
6867
required: true

.github/workflows/ci.yml

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -146,32 +146,14 @@ jobs:
146146
with:
147147
xcode-version: ${{ env.XCODE_VERSION }}
148148

149-
- name: Restore cocoapods
150-
if: env.turbo_cache_hit != 1
151-
id: cocoapods-cache
152-
uses: actions/cache/restore@v4
153-
with:
154-
path: |
155-
**/ios/Pods
156-
key: ${{ runner.os }}-cocoapods-${{ hashFiles('example/ios/Podfile.lock') }}
157-
restore-keys: |
158-
${{ runner.os }}-cocoapods-
159-
160149
- name: Install cocoapods
161150
if: env.turbo_cache_hit != 1 && steps.cocoapods-cache.outputs.cache-hit != 'true'
162151
run: |
163152
cd example
164153
bundle install
154+
bundle exec pod repo update --verbose
165155
bundle exec pod install --project-directory=ios
166156
167-
- name: Cache cocoapods
168-
if: env.turbo_cache_hit != 1 && steps.cocoapods-cache.outputs.cache-hit != 'true'
169-
uses: actions/cache/save@v4
170-
with:
171-
path: |
172-
**/ios/Pods
173-
key: ${{ steps.cocoapods-cache.outputs.cache-key }}
174-
175157
- name: Build example for iOS
176158
run: |
177159
yarn turbo run build:ios --cache-dir="${{ env.TURBO_CACHE_DIR }}"

README.md

Lines changed: 5 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# react-native-sensitive-info
22

3-
Descriptive
3+
..
44

55
## Installation
66

@@ -13,83 +13,17 @@ npm install react-native-sensitive-info react-native-nitro-modules
1313
## Usage
1414

1515

16+
```js
17+
import { multiply } from 'react-native-sensitive-info';
1618

17-
```ts
18-
import {
19-
setItem,
20-
getItem,
21-
deleteItem,
22-
isBiometricAvailable,
23-
authenticate,
24-
} from 'react-native-sensitive-info';
19+
// ...
2520

26-
// Store a value securely
27-
await setItem('myKey', 'mySecret');
28-
29-
// Retrieve a value
30-
const { value, error } = await getItem('myKey');
31-
32-
// Store a value requiring biometric authentication
33-
await setItem('biometricKey', 'superSecret', {
34-
biometric: true,
35-
promptReason: 'Authenticate to access your secret',
36-
});
37-
38-
// Retrieve a value with automatic biometric prompt
39-
const { value: secret } = await getItem('biometricKey');
40-
41-
// Delete a value
42-
await deleteItem('myKey');
43-
44-
// Check if biometric is available
45-
const isAvailable = await isBiometricAvailable();
46-
47-
// Prompt for biometric authentication only
48-
const { value: authResult } = await authenticate({ promptReason: 'Please authenticate' });
21+
const result = multiply(3, 7);
4922
```
50-
## React Hooks
51-
52-
This library provides hooks for easy integration in React components:
53-
54-
```ts
55-
import { useSensitiveInfo, useBiometricAuth } from 'react-native-sensitive-info/hooks';
56-
57-
const { value, error, loading, get, set, del } = useSensitiveInfo('myKey');
58-
const { success, error: bioError, loading: bioLoading, authenticate } = useBiometricAuth();
59-
```
60-
6123

6224

6325
## Contributing
6426

65-
66-
## API
67-
68-
69-
### setItem(key, value, options?)
70-
Store a value securely. Pass `{ biometric: true, promptReason }` to require biometric authentication. Automatically stores metadata for biometric detection.
71-
72-
### getItem(key, options?)
73-
Retrieve a value. If the value was stored with biometric protection, biometric prompt is automatic.
74-
75-
### deleteItem(key)
76-
Delete a value securely (and its metadata).
77-
78-
### isBiometricAvailable()
79-
Check if biometric authentication is available on the device.
80-
81-
### authenticate(options?)
82-
Prompt the user for biometric authentication only (no storage).
83-
84-
### useSensitiveInfo(key, options?)
85-
React hook for secure value management. Returns `{ value, error, loading, get, set, del }`.
86-
87-
### useBiometricAuth(options?)
88-
React hook for biometric authentication. Returns `{ success, error, loading, authenticate }`.
89-
90-
#### SensitiveInfoOptions
91-
Customize the biometric prompt (use `promptReason`, `promptTitle`, `promptDescription`, `promptNegativeButton`).
92-
9327
See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
9428

9529
## License

SensitiveInfo.podspec

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,23 @@ Pod::Spec.new do |s|
1313
s.platforms = { :ios => min_ios_version_supported }
1414
s.source = { :git => "https://github.com/mCodex/react-native-sensitive-info.git", :tag => "#{s.version}" }
1515

16-
s.source_files = "ios/**/*.{h,m,mm,swift}"
16+
17+
s.source_files = [
18+
"ios/**/*.{swift}",
19+
"ios/**/*.{m,mm}",
20+
"cpp/**/*.{hpp,cpp}",
21+
]
22+
23+
s.pod_target_xcconfig = {
24+
# C++ compiler flags, mainly for folly.
25+
"GCC_PREPROCESSOR_DEFINITIONS" => "$(inherited) FOLLY_NO_CONFIG FOLLY_CFG_NO_COROUTINES"
26+
}
27+
28+
s.dependency 'React-jsi'
29+
s.dependency 'React-callinvoker'
1730

1831
load 'nitrogen/generated/ios/SensitiveInfo+autolinking.rb'
1932
add_nitrogen_files(s)
2033

21-
install_modules_dependencies(s)
34+
install_modules_dependencies(s)
2235
end

android/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ android {
4242
externalNativeBuild {
4343
cmake {
4444
cppFlags "-frtti -fexceptions -Wall -fstack-protector-all"
45-
arguments "-DANDROID_STL=c++_shared"
45+
arguments "-DANDROID_STL=c++_shared", "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
4646
abiFilters (*reactNativeArchitectures())
4747

4848
buildTypes {
Lines changed: 5 additions & 184 deletions
Original file line numberDiff line numberDiff line change
@@ -1,189 +1,10 @@
11
package com.margelo.nitro.sensitiveinfo
2-
3-
import android.content.Context
4-
import androidx.biometric.BiometricManager
5-
import androidx.biometric.BiometricPrompt
6-
import androidx.core.content.ContextCompat
2+
73
import com.facebook.proguard.annotations.DoNotStrip
8-
import kotlinx.coroutines.suspendCancellableCoroutine
9-
import java.util.concurrent.Executor
10-
import kotlin.coroutines.resume
114

125
@DoNotStrip
136
class SensitiveInfo : HybridSensitiveInfoSpec() {
14-
15-
private fun getMasterKey(context: Context): androidx.security.crypto.MasterKey {
16-
val builder = androidx.security.crypto.MasterKey.Builder(context)
17-
.setKeyScheme(androidx.security.crypto.MasterKey.KeyScheme.AES256_GCM)
18-
// Use StrongBox if available
19-
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
20-
try {
21-
builder.setUserAuthenticationRequired(false, 0)
22-
builder.setRequestStrongBoxBacked(true)
23-
} catch (_: Exception) {}
24-
}
25-
return builder.build()
26-
}
27-
28-
suspend fun setItem(
29-
key: String,
30-
value: String,
31-
requireBiometric: Boolean,
32-
promptTitle: String?,
33-
promptSubtitle: String?,
34-
promptDescription: String?,
35-
promptNegativeButton: String?,
36-
promptReason: String?
37-
) {
38-
val context = getReactApplicationContext()
39-
val masterKey = getMasterKey(context)
40-
val prefs = androidx.security.crypto.EncryptedSharedPreferences.create(
41-
"sensitive_info_prefs",
42-
"master_key_alias",
43-
masterKey,
44-
context,
45-
androidx.security.crypto.EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
46-
androidx.security.crypto.EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
47-
)
48-
try {
49-
if (requireBiometric) {
50-
prefs.edit().putString("${key}_biometric", "true").apply()
51-
}
52-
prefs.edit().putString(key, value).apply()
53-
} catch (e: Exception) {
54-
throw Exception("Keystore error", e)
55-
} finally {
56-
value.toByteArray().fill(0)
57-
}
58-
}
59-
60-
suspend fun getItem(
61-
key: String,
62-
requireBiometric: Boolean,
63-
promptTitle: String?,
64-
promptSubtitle: String?,
65-
promptDescription: String?,
66-
promptNegativeButton: String?,
67-
promptReason: String?
68-
): String? {
69-
val context = getReactApplicationContext()
70-
val masterKey = getMasterKey(context)
71-
val prefs = androidx.security.crypto.EncryptedSharedPreferences.create(
72-
"sensitive_info_prefs",
73-
"master_key_alias",
74-
masterKey,
75-
context,
76-
androidx.security.crypto.EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
77-
androidx.security.crypto.EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
78-
)
79-
try {
80-
if (requireBiometric) {
81-
val title = promptTitle ?: "Authenticate"
82-
val subtitle = promptSubtitle
83-
val description = promptDescription
84-
val negativeButtonText = promptNegativeButton ?: "Cancel"
85-
86-
val executor: Executor = ContextCompat.getMainExecutor(context)
87-
val activity = getCurrentActivity() ?: throw Exception("No current activity")
88-
return suspendCancellableCoroutine { continuation ->
89-
val biometricPrompt = BiometricPrompt(
90-
activity,
91-
executor,
92-
object : BiometricPrompt.AuthenticationCallback() {
93-
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
94-
val value = prefs.getString(key, null)
95-
value?.toByteArray()?.fill(0)
96-
continuation.resume(value)
97-
}
98-
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
99-
continuation.resume(null)
100-
}
101-
override fun onAuthenticationFailed() {
102-
// Do nothing, user can retry
103-
}
104-
}
105-
)
106-
val promptInfo = BiometricPrompt.PromptInfo.Builder()
107-
.setTitle(title)
108-
.setNegativeButtonText(negativeButtonText)
109-
.apply {
110-
subtitle?.let { setSubtitle(it) }
111-
description?.let { setDescription(it) }
112-
}
113-
.build()
114-
biometricPrompt.authenticate(promptInfo)
115-
}
116-
} else {
117-
val value = prefs.getString(key, null)
118-
value?.toByteArray()?.fill(0)
119-
return value
120-
}
121-
} catch (e: Exception) {
122-
throw Exception("Keystore error", e)
123-
}
124-
}
125-
126-
suspend fun deleteItem(key: String) {
127-
val context = getReactApplicationContext()
128-
val masterKey = getMasterKey(context)
129-
val prefs = androidx.security.crypto.EncryptedSharedPreferences.create(
130-
"sensitive_info_prefs",
131-
"master_key_alias",
132-
masterKey,
133-
context,
134-
androidx.security.crypto.EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
135-
androidx.security.crypto.EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
136-
)
137-
prefs.edit().remove(key).apply()
138-
prefs.edit().remove("${key}_biometric").apply()
139-
}
140-
141-
suspend fun isBiometricAvailable(): Boolean {
142-
val context = getReactApplicationContext()
143-
val biometricManager = BiometricManager.from(context)
144-
return biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG) == BiometricManager.BIOMETRIC_SUCCESS
145-
}
146-
147-
suspend fun authenticate(
148-
promptTitle: String?,
149-
promptSubtitle: String?,
150-
promptDescription: String?,
151-
promptNegativeButton: String?,
152-
promptReason: String?
153-
): Boolean {
154-
val context = getReactApplicationContext()
155-
val title = promptTitle ?: "Authenticate"
156-
val subtitle = promptSubtitle
157-
val description = promptDescription
158-
val negativeButtonText = promptNegativeButton ?: "Cancel"
159-
160-
val executor: Executor = ContextCompat.getMainExecutor(context)
161-
val activity = getCurrentActivity() ?: throw Exception("No current activity")
162-
return suspendCancellableCoroutine { continuation ->
163-
val biometricPrompt = BiometricPrompt(
164-
activity,
165-
executor,
166-
object : BiometricPrompt.AuthenticationCallback() {
167-
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
168-
continuation.resume(true)
169-
}
170-
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
171-
continuation.resume(false)
172-
}
173-
override fun onAuthenticationFailed() {
174-
// Do nothing, user can retry
175-
}
176-
}
177-
)
178-
val promptInfo = BiometricPrompt.PromptInfo.Builder()
179-
.setTitle(title)
180-
.setNegativeButtonText(negativeButtonText)
181-
.apply {
182-
subtitle?.let { setSubtitle(it) }
183-
description?.let { setDescription(it) }
184-
}
185-
.build()
186-
biometricPrompt.authenticate(promptInfo)
187-
}
188-
}
189-
}
7+
override fun multiply(a: Double, b: Double): Double {
8+
return a * b
9+
}
10+
}

0 commit comments

Comments
 (0)