|
1 | 1 | package br.com.classapp.RNSensitiveInfo; |
2 | 2 |
|
| 3 | +import android.app.Activity; |
| 4 | +import android.app.Fragment; |
| 5 | +import android.app.FragmentTransaction; |
3 | 6 | import android.content.Context; |
4 | 7 | import android.content.SharedPreferences; |
5 | 8 | import android.hardware.fingerprint.FingerprintManager; |
|
12 | 15 | import android.util.Base64; |
13 | 16 | import android.util.Log; |
14 | 17 | import androidx.annotation.NonNull; |
| 18 | + |
15 | 19 | import com.facebook.react.bridge.Promise; |
16 | 20 | import com.facebook.react.bridge.ReactApplicationContext; |
17 | 21 | import com.facebook.react.bridge.ReactContextBaseJavaModule; |
@@ -67,6 +71,9 @@ public class RNSensitiveInfoModule extends ReactContextBaseJavaModule { |
67 | 71 | private KeyStore mKeyStore; |
68 | 72 | private CancellationSignal mCancellationSignal; |
69 | 73 |
|
| 74 | + // Keep it true by default to maintain backwards compatibility with existing users. |
| 75 | + private boolean invalidateEnrollment = true; |
| 76 | + |
70 | 77 | public RNSensitiveInfoModule(ReactApplicationContext reactContext) { |
71 | 78 | super(reactContext); |
72 | 79 |
|
@@ -125,6 +132,16 @@ private boolean hasSetupFingerprint() { |
125 | 132 | } |
126 | 133 | } |
127 | 134 |
|
| 135 | + @ReactMethod |
| 136 | + public void setInvalidatedByBiometricEnrollment(final boolean invalidatedByBiometricEnrollment, final Promise pm) { |
| 137 | + this.invalidateEnrollment = invalidatedByBiometricEnrollment; |
| 138 | + try { |
| 139 | + prepareKey(); |
| 140 | + } catch (Exception e) { |
| 141 | + pm.reject(e); |
| 142 | + } |
| 143 | + } |
| 144 | + |
128 | 145 | @ReactMethod |
129 | 146 | public void isHardwareDetected(final Promise pm) { |
130 | 147 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { |
@@ -290,6 +307,34 @@ private void initKeyStore() { |
290 | 307 | } |
291 | 308 | } |
292 | 309 |
|
| 310 | + private void showDialog(final HashMap strings, Object cryptoObject, FingerprintUiHelper.Callback callback) { |
| 311 | + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { |
| 312 | + // DialogFragment.show() will take care of adding the fragment |
| 313 | + // in a transaction. We also want to remove any currently showing |
| 314 | + // dialog, so make our own transaction and take care of that here. |
| 315 | + |
| 316 | + Activity activity = getCurrentActivity(); |
| 317 | + if (activity == null) { |
| 318 | + callback.onError(AppConstants.E_INIT_FAILURE, |
| 319 | + strings.containsKey("cancelled") ? strings.get("cancelled").toString() : "Authentication was cancelled"); |
| 320 | + return; |
| 321 | + } |
| 322 | + |
| 323 | + FragmentTransaction ft = activity.getFragmentManager().beginTransaction(); |
| 324 | + Fragment prev = getCurrentActivity().getFragmentManager().findFragmentByTag(AppConstants.DIALOG_FRAGMENT_TAG); |
| 325 | + if (prev != null) { |
| 326 | + ft.remove(prev); |
| 327 | + } |
| 328 | + ft.addToBackStack(null); |
| 329 | + |
| 330 | + // Create and show the dialog. |
| 331 | + FingerprintAuthenticationDialogFragment newFragment = FingerprintAuthenticationDialogFragment.newInstance(strings); |
| 332 | + newFragment.setCryptoObject((FingerprintManager.CryptoObject) cryptoObject); |
| 333 | + newFragment.setCallback(callback); |
| 334 | + newFragment.show(ft, AppConstants.DIALOG_FRAGMENT_TAG); |
| 335 | + } |
| 336 | + } |
| 337 | + |
293 | 338 | /** |
294 | 339 | * Generates a new AES key and stores it under the { @code KEY_ALIAS_AES } in the |
295 | 340 | * Android Keystore. |
@@ -321,6 +366,14 @@ private void prepareKey() throws Exception { |
321 | 366 | // forces user authentication with fingerprint |
322 | 367 | .setUserAuthenticationRequired(true); |
323 | 368 |
|
| 369 | + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { |
| 370 | + try { |
| 371 | + builder.setInvalidatedByBiometricEnrollment(invalidateEnrollment); |
| 372 | + } catch (Exception e) { |
| 373 | + Log.d("RNSensitiveInfo", "Error setting setInvalidatedByBiometricEnrollment: " + e.getMessage()); |
| 374 | + } |
| 375 | + } |
| 376 | + |
324 | 377 | keyGenerator.init(builder.build()); |
325 | 378 | keyGenerator.generateKey(); |
326 | 379 | } |
@@ -361,12 +414,7 @@ public void onError(String errorCode, CharSequence errString) { |
361 | 414 | } |
362 | 415 |
|
363 | 416 | // Show the fingerprint dialog |
364 | | - FingerprintAuthenticationDialogFragment fragment |
365 | | - = FingerprintAuthenticationDialogFragment.newInstance(strings); |
366 | | - fragment.setCryptoObject(new FingerprintManager.CryptoObject(cipher)); |
367 | | - fragment.setCallback(new PutExtraWithAESCallback()); |
368 | | - |
369 | | - fragment.show(getCurrentActivity().getFragmentManager(), AppConstants.DIALOG_FRAGMENT_TAG); |
| 417 | + showDialog(strings, new FingerprintManager.CryptoObject(cipher), new PutExtraWithAESCallback()); |
370 | 418 |
|
371 | 419 | } else { |
372 | 420 | mCancellationSignal = new CancellationSignal(); |
@@ -477,12 +525,7 @@ public void onError(String errorCode, CharSequence errString) { |
477 | 525 | } |
478 | 526 |
|
479 | 527 | // Show the fingerprint dialog |
480 | | - FingerprintAuthenticationDialogFragment fragment |
481 | | - = FingerprintAuthenticationDialogFragment.newInstance(strings); |
482 | | - fragment.setCryptoObject(new FingerprintManager.CryptoObject(cipher)); |
483 | | - fragment.setCallback(new DecryptWithAesCallback()); |
484 | | - |
485 | | - fragment.show(getCurrentActivity().getFragmentManager(), AppConstants.DIALOG_FRAGMENT_TAG); |
| 528 | + showDialog(strings, new FingerprintManager.CryptoObject(cipher), new DecryptWithAesCallback()); |
486 | 529 |
|
487 | 530 | } else { |
488 | 531 | mCancellationSignal = new CancellationSignal(); |
|
0 commit comments