|
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; |
|
9 | 12 | import android.security.keystore.KeyInfo; |
10 | 13 | import android.security.KeyPairGeneratorSpec; |
11 | 14 | import android.security.keystore.KeyProperties; |
12 | | -import android.support.annotation.NonNull; |
13 | 15 | import android.util.Base64; |
14 | 16 | import android.util.Log; |
| 17 | +import androidx.annotation.NonNull; |
15 | 18 |
|
16 | 19 | import com.facebook.react.bridge.Promise; |
17 | 20 | import com.facebook.react.bridge.ReactApplicationContext; |
@@ -68,6 +71,9 @@ public class RNSensitiveInfoModule extends ReactContextBaseJavaModule { |
68 | 71 | private KeyStore mKeyStore; |
69 | 72 | private CancellationSignal mCancellationSignal; |
70 | 73 |
|
| 74 | + // Keep it true by default to maintain backwards compatibility with existing users. |
| 75 | + private boolean invalidateEnrollment = true; |
| 76 | + |
71 | 77 | public RNSensitiveInfoModule(ReactApplicationContext reactContext) { |
72 | 78 | super(reactContext); |
73 | 79 |
|
@@ -126,6 +132,16 @@ private boolean hasSetupFingerprint() { |
126 | 132 | } |
127 | 133 | } |
128 | 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 | + |
129 | 145 | @ReactMethod |
130 | 146 | public void isHardwareDetected(final Promise pm) { |
131 | 147 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { |
@@ -291,6 +307,34 @@ private void initKeyStore() { |
291 | 307 | } |
292 | 308 | } |
293 | 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 | + |
294 | 338 | /** |
295 | 339 | * Generates a new AES key and stores it under the { @code KEY_ALIAS_AES } in the |
296 | 340 | * Android Keystore. |
@@ -322,6 +366,14 @@ private void prepareKey() throws Exception { |
322 | 366 | // forces user authentication with fingerprint |
323 | 367 | .setUserAuthenticationRequired(true); |
324 | 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 | + |
325 | 377 | keyGenerator.init(builder.build()); |
326 | 378 | keyGenerator.generateKey(); |
327 | 379 | } |
@@ -362,12 +414,7 @@ public void onError(String errorCode, CharSequence errString) { |
362 | 414 | } |
363 | 415 |
|
364 | 416 | // Show the fingerprint dialog |
365 | | - FingerprintAuthenticationDialogFragment fragment |
366 | | - = FingerprintAuthenticationDialogFragment.newInstance(strings); |
367 | | - fragment.setCryptoObject(new FingerprintManager.CryptoObject(cipher)); |
368 | | - fragment.setCallback(new PutExtraWithAESCallback()); |
369 | | - |
370 | | - fragment.show(getCurrentActivity().getFragmentManager(), AppConstants.DIALOG_FRAGMENT_TAG); |
| 417 | + showDialog(strings, new FingerprintManager.CryptoObject(cipher), new PutExtraWithAESCallback()); |
371 | 418 |
|
372 | 419 | } else { |
373 | 420 | mCancellationSignal = new CancellationSignal(); |
@@ -478,12 +525,7 @@ public void onError(String errorCode, CharSequence errString) { |
478 | 525 | } |
479 | 526 |
|
480 | 527 | // Show the fingerprint dialog |
481 | | - FingerprintAuthenticationDialogFragment fragment |
482 | | - = FingerprintAuthenticationDialogFragment.newInstance(strings); |
483 | | - fragment.setCryptoObject(new FingerprintManager.CryptoObject(cipher)); |
484 | | - fragment.setCallback(new DecryptWithAesCallback()); |
485 | | - |
486 | | - fragment.show(getCurrentActivity().getFragmentManager(), AppConstants.DIALOG_FRAGMENT_TAG); |
| 528 | + showDialog(strings, new FingerprintManager.CryptoObject(cipher), new DecryptWithAesCallback()); |
487 | 529 |
|
488 | 530 | } else { |
489 | 531 | mCancellationSignal = new CancellationSignal(); |
|
0 commit comments