@capgo/capacitor-native-biometric 7.1.1 → 7.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -57,28 +57,21 @@ public class AuthActivity extends AppCompatActivity {
57
57
  boolean useFallback = getIntent().getBooleanExtra("useFallback", false);
58
58
  int[] allowedTypes = getIntent().getIntArrayExtra("allowedBiometryTypes");
59
59
 
60
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
61
- int authenticators = BiometricManager.Authenticators.BIOMETRIC_STRONG;
62
- if (useFallback) {
63
- authenticators |= BiometricManager.Authenticators.DEVICE_CREDENTIAL;
64
- }
65
- if (allowedTypes != null) {
66
- // Filter authenticators based on allowed types
67
- authenticators = getAllowedAuthenticators(allowedTypes);
68
- }
69
- builder.setAllowedAuthenticators(authenticators);
70
- } else {
71
- if (useFallback) {
72
- builder.setDeviceCredentialAllowed(true);
73
- } else {
74
- builder.setNegativeButtonText(
75
- getIntent().hasExtra("negativeButtonText")
76
- ? Objects.requireNonNull(
77
- getIntent().getStringExtra("negativeButtonText")
78
- )
79
- : "Cancel"
80
- );
81
- }
60
+ int authenticators = BiometricManager.Authenticators.BIOMETRIC_STRONG;
61
+ if (useFallback) {
62
+ authenticators |= BiometricManager.Authenticators.DEVICE_CREDENTIAL;
63
+ }
64
+ if (allowedTypes != null) {
65
+ // Filter authenticators based on allowed types
66
+ authenticators = getAllowedAuthenticators(allowedTypes);
67
+ }
68
+ builder.setAllowedAuthenticators(authenticators);
69
+
70
+ if (!useFallback) {
71
+ String negativeText = getIntent().getStringExtra("negativeButtonText");
72
+ builder.setNegativeButtonText(
73
+ negativeText != null ? negativeText : "Cancel"
74
+ );
82
75
  }
83
76
 
84
77
  BiometricPrompt.PromptInfo promptInfo = builder.build();
@@ -8,7 +8,6 @@ import android.content.Intent;
8
8
  import android.content.SharedPreferences;
9
9
  import android.content.pm.PackageManager;
10
10
  import android.os.Build;
11
- import android.security.KeyPairGeneratorSpec;
12
11
  import android.security.keystore.KeyGenParameterSpec;
13
12
  import android.security.keystore.KeyProperties;
14
13
  import android.security.keystore.StrongBoxUnavailableException;
@@ -74,42 +73,55 @@ public class NativeBiometric extends Plugin {
74
73
 
75
74
  private int getAvailableFeature() {
76
75
  // default to none
77
- int type = NONE;
78
-
79
- // if has fingerprint
80
- if (
81
- getContext()
82
- .getPackageManager()
83
- .hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
84
- ) {
85
- type = FINGERPRINT;
86
- }
76
+ BiometricManager biometricManager = BiometricManager.from(getContext());
87
77
 
88
- // if has face auth
89
- if (
90
- getContext()
91
- .getPackageManager()
92
- .hasSystemFeature(PackageManager.FEATURE_FACE)
93
- ) {
94
- // if also has fingerprint
95
- if (type != NONE) return MULTIPLE;
78
+ // Check for biometric capabilities
79
+ int authenticators = BiometricManager.Authenticators.BIOMETRIC_STRONG;
80
+ int canAuthenticate = biometricManager.canAuthenticate(authenticators);
96
81
 
97
- type = FACE_AUTHENTICATION;
98
- }
82
+ if (canAuthenticate == BiometricManager.BIOMETRIC_SUCCESS) {
83
+ // Check specific features
84
+ PackageManager pm = getContext().getPackageManager();
85
+ boolean hasFinger = pm.hasSystemFeature(
86
+ PackageManager.FEATURE_FINGERPRINT
87
+ );
88
+ boolean hasIris = false;
89
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
90
+ hasIris = pm.hasSystemFeature(PackageManager.FEATURE_IRIS);
91
+ }
99
92
 
100
- // if has iris auth
101
- if (
102
- getContext()
103
- .getPackageManager()
104
- .hasSystemFeature(PackageManager.FEATURE_IRIS)
105
- ) {
106
- // if also has fingerprint or face auth
107
- if (type != NONE) return MULTIPLE;
93
+ // For face, we rely on BiometricManager since it's more reliable
94
+ boolean hasFace = false;
95
+ try {
96
+ // Try to create a face authentication prompt - if it succeeds, face auth is available
97
+ androidx.biometric.BiometricPrompt.PromptInfo promptInfo =
98
+ new androidx.biometric.BiometricPrompt.PromptInfo.Builder()
99
+ .setTitle("Test")
100
+ .setNegativeButtonText("Cancel")
101
+ .setAllowedAuthenticators(
102
+ BiometricManager.Authenticators.BIOMETRIC_STRONG
103
+ )
104
+ .build();
105
+ hasFace = true;
106
+ } catch (Exception e) {
107
+ System.out.println(
108
+ "Error creating face authentication prompt: " + e.getMessage()
109
+ );
110
+ }
108
111
 
109
- type = IRIS_AUTHENTICATION;
112
+ // Determine the type based on available features
113
+ if (hasFinger && (hasFace || hasIris)) {
114
+ return MULTIPLE;
115
+ } else if (hasFinger) {
116
+ return FINGERPRINT;
117
+ } else if (hasFace) {
118
+ return FACE_AUTHENTICATION;
119
+ } else if (hasIris) {
120
+ return IRIS_AUTHENTICATION;
121
+ }
110
122
  }
111
123
 
112
- return type;
124
+ return NONE;
113
125
  }
114
126
 
115
127
  @PluginMethod
@@ -121,7 +133,13 @@ public class NativeBiometric extends Plugin {
121
133
  );
122
134
 
123
135
  BiometricManager biometricManager = BiometricManager.from(getContext());
124
- int canAuthenticateResult = biometricManager.canAuthenticate();
136
+ int authenticators = BiometricManager.Authenticators.BIOMETRIC_STRONG;
137
+ if (useFallback) {
138
+ authenticators |= BiometricManager.Authenticators.DEVICE_CREDENTIAL;
139
+ }
140
+ int canAuthenticateResult = biometricManager.canAuthenticate(
141
+ authenticators
142
+ );
125
143
  // Using deviceHasCredentials instead of canAuthenticate(DEVICE_CREDENTIAL)
126
144
  // > "Developers that wish to check for the presence of a PIN, pattern, or password on these versions should instead use isDeviceSecure."
127
145
  // @see https://developer.android.com/reference/androidx/biometric/BiometricManager#canAuthenticate(int)
@@ -153,23 +171,24 @@ public class NativeBiometric extends Plugin {
153
171
 
154
172
  intent.putExtra("title", call.getString("title", "Authenticate"));
155
173
 
156
- if (call.hasOption("subtitle")) {
157
- intent.putExtra("subtitle", call.getString("subtitle"));
174
+ String subtitle = call.getString("subtitle");
175
+ if (subtitle != null) {
176
+ intent.putExtra("subtitle", subtitle);
158
177
  }
159
178
 
160
- if (call.hasOption("description")) {
161
- intent.putExtra("description", call.getString("description"));
179
+ String description = call.getString("description");
180
+ if (description != null) {
181
+ intent.putExtra("description", description);
162
182
  }
163
183
 
164
- if (call.hasOption("negativeButtonText")) {
165
- intent.putExtra(
166
- "negativeButtonText",
167
- call.getString("negativeButtonText")
168
- );
184
+ String negativeButtonText = call.getString("negativeButtonText");
185
+ if (negativeButtonText != null) {
186
+ intent.putExtra("negativeButtonText", negativeButtonText);
169
187
  }
170
188
 
171
- if (call.hasOption("maxAttempts")) {
172
- intent.putExtra("maxAttempts", call.getInt("maxAttempts"));
189
+ Integer maxAttempts = call.getInt("maxAttempts");
190
+ if (maxAttempts != null) {
191
+ intent.putExtra("maxAttempts", maxAttempts);
173
192
  }
174
193
 
175
194
  // Pass allowed biometry types
@@ -220,7 +239,7 @@ public class NativeBiometric extends Plugin {
220
239
  call.resolve();
221
240
  } catch (GeneralSecurityException | IOException e) {
222
241
  call.reject("Failed to save credentials", e);
223
- e.printStackTrace();
242
+ System.out.println("Error saving credentials: " + e.getMessage());
224
243
  }
225
244
  } else {
226
245
  call.reject("Missing properties");
@@ -443,8 +462,12 @@ public class NativeBiometric extends Plugin {
443
462
  ANDROID_KEY_STORE
444
463
  );
445
464
  keyPairGenerator.initialize(
446
- new KeyPairGeneratorSpec.Builder(getContext())
447
- .setAlias(KEY_ALIAS)
465
+ new KeyGenParameterSpec.Builder(
466
+ KEY_ALIAS,
467
+ KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT
468
+ )
469
+ .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
470
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
448
471
  .build()
449
472
  );
450
473
  keyPairGenerator.generateKeyPair();
@@ -471,8 +494,7 @@ public class NativeBiometric extends Plugin {
471
494
  cipherOutputStream.write(secret);
472
495
  cipherOutputStream.close();
473
496
 
474
- byte[] vals = outputStream.toByteArray();
475
- return vals;
497
+ return outputStream.toByteArray();
476
498
  }
477
499
 
478
500
  private byte[] rsaDecrypt(byte[] encrypted, String KEY_ALIAS)
@@ -8,7 +8,7 @@ import LocalAuthentication
8
8
  */
9
9
 
10
10
  @objc(NativeBiometric)
11
- public class NativeBiometric: CAPPlugin {
11
+ public class NativeBiometric: CAPPlugin, CAPBridgedPlugin {
12
12
  public let identifier = "NativeBiometric"
13
13
  public let jsName = "NativeBiometric"
14
14
  public let pluginMethods: [CAPPluginMethod] = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-native-biometric",
3
- "version": "7.1.1",
3
+ "version": "7.1.6",
4
4
  "description": "This plugin gives access to the native biometric apis for android and iOS",
5
5
  "main": "dist/esm/index.js",
6
6
  "types": "dist/esm/index.d.ts",