@capgo/capacitor-native-biometric 5.0.1 → 5.1.1

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.
Files changed (66) hide show
  1. package/LICENSE +2 -2
  2. package/{readme.md → README.md} +49 -22
  3. package/android/build.gradle +9 -9
  4. package/android/gradlew +8 -4
  5. package/android/src/main/java/ee/forgr/biometric/AuthActivity.java +69 -37
  6. package/android/src/main/java/ee/forgr/biometric/NativeBiometric.java +121 -74
  7. package/dist/docs.json +27 -13
  8. package/dist/esm/definitions.d.ts +31 -3
  9. package/dist/esm/definitions.js +27 -0
  10. package/dist/esm/definitions.js.map +1 -1
  11. package/dist/esm/index.js.map +1 -1
  12. package/dist/esm/web.d.ts +3 -3
  13. package/dist/esm/web.js.map +1 -1
  14. package/dist/plugin.cjs.js +24 -1
  15. package/dist/plugin.cjs.js.map +1 -1
  16. package/dist/plugin.js +26 -3
  17. package/dist/plugin.js.map +1 -1
  18. package/ios/Plugin/Plugin.swift +60 -58
  19. package/ios/Podfile.lock +4 -4
  20. package/ios/Pods/Local Podspecs/Capacitor.podspec.json +2 -2
  21. package/ios/Pods/Local Podspecs/CapacitorCordova.podspec.json +2 -2
  22. package/ios/Pods/Manifest.lock +4 -4
  23. package/ios/Pods/Pods.xcodeproj/project.pbxproj +572 -572
  24. package/ios/Pods/Target Support Files/Capacitor/Capacitor-Info.plist +1 -1
  25. package/ios/Pods/Target Support Files/CapacitorCordova/CapacitorCordova-Info.plist +1 -1
  26. package/ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests-frameworks.sh +0 -0
  27. package/package.json +17 -22
  28. package/android/.gradle/8.0.2/checksums/checksums.lock +0 -0
  29. package/android/.gradle/8.0.2/dependencies-accessors/dependencies-accessors.lock +0 -0
  30. package/android/.gradle/8.0.2/dependencies-accessors/gc.properties +0 -0
  31. package/android/.gradle/8.0.2/executionHistory/executionHistory.bin +0 -0
  32. package/android/.gradle/8.0.2/executionHistory/executionHistory.lock +0 -0
  33. package/android/.gradle/8.0.2/fileChanges/last-build.bin +0 -0
  34. package/android/.gradle/8.0.2/fileHashes/fileHashes.bin +0 -0
  35. package/android/.gradle/8.0.2/fileHashes/fileHashes.lock +0 -0
  36. package/android/.gradle/8.0.2/fileHashes/resourceHashesCache.bin +0 -0
  37. package/android/.gradle/8.0.2/gc.properties +0 -0
  38. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  39. package/android/.gradle/buildOutputCleanup/cache.properties +0 -2
  40. package/android/.gradle/buildOutputCleanup/outputFiles.bin +0 -0
  41. package/android/.gradle/vcs-1/gc.properties +0 -0
  42. package/android/android.iml +0 -40
  43. package/android/local.properties +0 -8
  44. package/ios/Plugin.xcodeproj/project.xcworkspace/xcuserdata/pilito.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  45. package/ios/Plugin.xcodeproj/xcuserdata/jmartinez.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
  46. package/ios/Plugin.xcodeproj/xcuserdata/josemartinez.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
  47. package/ios/Plugin.xcodeproj/xcuserdata/pilito.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
  48. package/ios/Plugin.xcworkspace/xcuserdata/jmartinez.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  49. package/ios/Plugin.xcworkspace/xcuserdata/josemartinez.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  50. package/ios/Plugin.xcworkspace/xcuserdata/pilito.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  51. package/ios/Pods/Pods.xcodeproj/xcuserdata/jmartinez.xcuserdatad/xcschemes/Capacitor.xcscheme +0 -60
  52. package/ios/Pods/Pods.xcodeproj/xcuserdata/jmartinez.xcuserdatad/xcschemes/CapacitorCordova.xcscheme +0 -58
  53. package/ios/Pods/Pods.xcodeproj/xcuserdata/jmartinez.xcuserdatad/xcschemes/Pods-Plugin.xcscheme +0 -58
  54. package/ios/Pods/Pods.xcodeproj/xcuserdata/jmartinez.xcuserdatad/xcschemes/Pods-PluginTests.xcscheme +0 -58
  55. package/ios/Pods/Pods.xcodeproj/xcuserdata/jmartinez.xcuserdatad/xcschemes/xcschememanagement.plist +0 -39
  56. package/ios/Pods/Pods.xcodeproj/xcuserdata/josemartinez.xcuserdatad/xcschemes/Capacitor.xcscheme +0 -60
  57. package/ios/Pods/Pods.xcodeproj/xcuserdata/josemartinez.xcuserdatad/xcschemes/CapacitorCordova.xcscheme +0 -58
  58. package/ios/Pods/Pods.xcodeproj/xcuserdata/josemartinez.xcuserdatad/xcschemes/Pods-Plugin.xcscheme +0 -58
  59. package/ios/Pods/Pods.xcodeproj/xcuserdata/josemartinez.xcuserdatad/xcschemes/Pods-PluginTests.xcscheme +0 -58
  60. package/ios/Pods/Pods.xcodeproj/xcuserdata/josemartinez.xcuserdatad/xcschemes/xcschememanagement.plist +0 -39
  61. package/ios/Pods/Pods.xcodeproj/xcuserdata/martindonadieu.xcuserdatad/xcschemes/Capacitor.xcscheme +0 -58
  62. package/ios/Pods/Pods.xcodeproj/xcuserdata/martindonadieu.xcuserdatad/xcschemes/CapacitorCordova.xcscheme +0 -58
  63. package/ios/Pods/Pods.xcodeproj/xcuserdata/martindonadieu.xcuserdatad/xcschemes/Pods-Plugin.xcscheme +0 -58
  64. package/ios/Pods/Pods.xcodeproj/xcuserdata/martindonadieu.xcuserdatad/xcschemes/Pods-PluginTests.xcscheme +0 -58
  65. package/ios/Pods/Pods.xcodeproj/xcuserdata/martindonadieu.xcuserdatad/xcschemes/xcschememanagement.plist +0 -31
  66. package/ios/Pods/Pods.xcodeproj/xcuserdata/pilito.xcuserdatad/xcschemes/xcschememanagement.plist +0 -29
@@ -1,5 +1,6 @@
1
1
  package ee.forgr.biometric;
2
2
 
3
+ import android.annotation.SuppressLint;
3
4
  import android.app.Activity;
4
5
  import android.app.KeyguardManager;
5
6
  import android.content.Context;
@@ -10,6 +11,7 @@ import android.os.Build;
10
11
  import android.security.KeyPairGeneratorSpec;
11
12
  import android.security.keystore.KeyGenParameterSpec;
12
13
  import android.security.keystore.KeyProperties;
14
+ import android.security.keystore.StrongBoxUnavailableException;
13
15
  import android.util.Base64;
14
16
  import androidx.activity.result.ActivityResult;
15
17
  import androidx.biometric.BiometricManager;
@@ -46,7 +48,6 @@ import javax.crypto.spec.SecretKeySpec;
46
48
  @CapacitorPlugin(name = "NativeBiometric")
47
49
  public class NativeBiometric extends Plugin {
48
50
 
49
- private BiometricManager biometricManager;
50
51
  //protected final static int AUTH_CODE = 0102;
51
52
 
52
53
  private static final int NONE = 0;
@@ -111,17 +112,33 @@ public class NativeBiometric extends Plugin {
111
112
  public void isAvailable(PluginCall call) {
112
113
  JSObject ret = new JSObject();
113
114
 
114
- biometricManager = BiometricManager.from(getContext());
115
+ boolean useFallback = Boolean.TRUE.equals(
116
+ call.getBoolean("useFallback", false)
117
+ );
118
+
119
+ BiometricManager biometricManager = BiometricManager.from(getContext());
115
120
  int canAuthenticateResult = biometricManager.canAuthenticate();
121
+ // Using deviceHasCredentials instead of canAuthenticate(DEVICE_CREDENTIAL)
122
+ // > "Developers that wish to check for the presence of a PIN, pattern, or password on these versions should instead use isDeviceSecure."
123
+ // @see https://developer.android.com/reference/androidx/biometric/BiometricManager#canAuthenticate(int)
124
+ boolean fallbackAvailable = useFallback && this.deviceHasCredentials();
125
+ if (useFallback && !fallbackAvailable) {
126
+ canAuthenticateResult = BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE;
127
+ }
128
+
129
+ boolean isAvailable =
130
+ (
131
+ canAuthenticateResult == BiometricManager.BIOMETRIC_SUCCESS ||
132
+ fallbackAvailable
133
+ );
134
+ ret.put("isAvailable", isAvailable);
116
135
 
117
- switch (canAuthenticateResult) {
118
- case BiometricManager.BIOMETRIC_SUCCESS:
119
- ret.put("isAvailable", true);
120
- break;
121
- default:
122
- ret.put("isAvailable", false);
123
- ret.put("errorCode", canAuthenticateResult);
124
- break;
136
+ if (!isAvailable) {
137
+ // BiometricManager Error Constants use the same values as BiometricPrompt's Constants. So we can reuse our
138
+ int pluginErrorCode = AuthActivity.convertToPluginErrorCode(
139
+ canAuthenticateResult
140
+ );
141
+ ret.put("errorCode", pluginErrorCode);
125
142
  }
126
143
 
127
144
  ret.put("biometryType", getAvailableFeature());
@@ -134,32 +151,30 @@ public class NativeBiometric extends Plugin {
134
151
 
135
152
  intent.putExtra("title", call.getString("title", "Authenticate"));
136
153
 
137
- if (call.hasOption("subtitle")) intent.putExtra(
138
- "subtitle",
139
- call.getString("subtitle")
140
- );
141
-
142
- if (call.hasOption("description")) intent.putExtra(
143
- "description",
144
- call.getString("description")
145
- );
154
+ if (call.hasOption("subtitle")) {
155
+ intent.putExtra("subtitle", call.getString("subtitle"));
156
+ }
146
157
 
147
- if (call.hasOption("negativeButtonText")) intent.putExtra(
148
- "negativeButtonText",
149
- call.getString("negativeButtonText")
150
- );
158
+ if (call.hasOption("description")) {
159
+ intent.putExtra("description", call.getString("description"));
160
+ }
151
161
 
152
- if (call.hasOption("maxAttempts")) intent.putExtra(
153
- "maxAttempts",
154
- call.getInt("maxAttempts")
155
- );
162
+ if (call.hasOption("negativeButtonText")) {
163
+ intent.putExtra(
164
+ "negativeButtonText",
165
+ call.getString("negativeButtonText")
166
+ );
167
+ }
156
168
 
157
- boolean useFallback = call.getBoolean("useFallback", false);
169
+ if (call.hasOption("maxAttempts")) {
170
+ intent.putExtra("maxAttempts", call.getInt("maxAttempts"));
171
+ }
158
172
 
159
- if (useFallback && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
160
- KeyguardManager keyguardManager = (KeyguardManager) getActivity()
161
- .getSystemService(Context.KEYGUARD_SERVICE);
162
- useFallback = keyguardManager.isDeviceSecure();
173
+ boolean useFallback = Boolean.TRUE.equals(
174
+ call.getBoolean("useFallback", false)
175
+ );
176
+ if (useFallback) {
177
+ useFallback = this.deviceHasCredentials();
163
178
  }
164
179
 
165
180
  intent.putExtra("useFallback", useFallback);
@@ -181,14 +196,17 @@ public class NativeBiometric extends Plugin {
181
196
  Context.MODE_PRIVATE
182
197
  )
183
198
  .edit();
184
- editor.putString("username", encryptString(username, KEY_ALIAS));
185
- editor.putString("password", encryptString(password, KEY_ALIAS));
199
+ editor.putString(
200
+ KEY_ALIAS + "-username",
201
+ encryptString(username, KEY_ALIAS)
202
+ );
203
+ editor.putString(
204
+ KEY_ALIAS + "-password",
205
+ encryptString(password, KEY_ALIAS)
206
+ );
186
207
  editor.apply();
187
208
  call.resolve();
188
- } catch (GeneralSecurityException e) {
189
- call.reject("Failed to save credentials", e);
190
- e.printStackTrace();
191
- } catch (IOException e) {
209
+ } catch (GeneralSecurityException | IOException e) {
192
210
  call.reject("Failed to save credentials", e);
193
211
  e.printStackTrace();
194
212
  }
@@ -206,8 +224,14 @@ public class NativeBiometric extends Plugin {
206
224
  NATIVE_BIOMETRIC_SHARED_PREFERENCES,
207
225
  Context.MODE_PRIVATE
208
226
  );
209
- String username = sharedPreferences.getString("username", null);
210
- String password = sharedPreferences.getString("password", null);
227
+ String username = sharedPreferences.getString(
228
+ KEY_ALIAS + "-username",
229
+ null
230
+ );
231
+ String password = sharedPreferences.getString(
232
+ KEY_ALIAS + "-password",
233
+ null
234
+ );
211
235
  if (KEY_ALIAS != null) {
212
236
  if (username != null && password != null) {
213
237
  try {
@@ -215,10 +239,10 @@ public class NativeBiometric extends Plugin {
215
239
  jsObject.put("username", decryptString(username, KEY_ALIAS));
216
240
  jsObject.put("password", decryptString(password, KEY_ALIAS));
217
241
  call.resolve(jsObject);
218
- } catch (GeneralSecurityException e) {
219
- call.reject("Failed to get credentials", e);
220
- } catch (IOException e) {
221
- call.reject("Failed to get credentials", e);
242
+ } catch (GeneralSecurityException | IOException e) {
243
+ // Can get here if not authenticated.
244
+ String errorMessage = "Failed to get credentials";
245
+ call.reject(errorMessage);
222
246
  }
223
247
  } else {
224
248
  call.reject("No credentials found");
@@ -232,22 +256,21 @@ public class NativeBiometric extends Plugin {
232
256
  private void verifyResult(PluginCall call, ActivityResult result) {
233
257
  if (result.getResultCode() == Activity.RESULT_OK) {
234
258
  Intent data = result.getData();
235
- if (data.hasExtra("result")) {
259
+ if (data != null && data.hasExtra("result")) {
236
260
  switch (data.getStringExtra("result")) {
237
261
  case "success":
238
262
  call.resolve();
239
263
  break;
240
264
  case "failed":
265
+ case "error":
241
266
  call.reject(
242
267
  data.getStringExtra("errorDetails"),
243
268
  data.getStringExtra("errorCode")
244
269
  );
245
270
  break;
246
271
  default:
247
- call.reject(
248
- "Verification error: " + data.getStringExtra("result"),
249
- data.getStringExtra("errorCode")
250
- );
272
+ // Should not get to here unless AuthActivity starts returning different Activity Results.
273
+ call.reject("Something went wrong.");
251
274
  break;
252
275
  }
253
276
  }
@@ -272,13 +295,12 @@ public class NativeBiometric extends Plugin {
272
295
  editor.clear();
273
296
  editor.apply();
274
297
  call.resolve();
275
- } catch (KeyStoreException e) {
276
- call.reject("Failed to delete", e);
277
- } catch (CertificateException e) {
278
- call.reject("Failed to delete", e);
279
- } catch (NoSuchAlgorithmException e) {
280
- call.reject("Failed to delete", e);
281
- } catch (IOException e) {
298
+ } catch (
299
+ KeyStoreException
300
+ | CertificateException
301
+ | NoSuchAlgorithmException
302
+ | IOException e
303
+ ) {
282
304
  call.reject("Failed to delete", e);
283
305
  }
284
306
  } else {
@@ -324,23 +346,39 @@ public class NativeBiometric extends Plugin {
324
346
  return new String(decryptedData, "UTF-8");
325
347
  }
326
348
 
349
+ @SuppressLint("NewAPI") // API level is already checked
327
350
  private Key generateKey(String KEY_ALIAS)
328
351
  throws GeneralSecurityException, IOException {
352
+ Key key;
353
+ try {
354
+ key = generateKey(KEY_ALIAS, true);
355
+ } catch (StrongBoxUnavailableException e) {
356
+ key = generateKey(KEY_ALIAS, false);
357
+ }
358
+ return key;
359
+ }
360
+
361
+ private Key generateKey(String KEY_ALIAS, boolean isStrongBoxBacked)
362
+ throws GeneralSecurityException, IOException, StrongBoxUnavailableException {
329
363
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
330
364
  KeyGenerator generator = KeyGenerator.getInstance(
331
365
  KeyProperties.KEY_ALGORITHM_AES,
332
366
  ANDROID_KEY_STORE
333
367
  );
334
- generator.init(
335
- new KeyGenParameterSpec.Builder(
336
- KEY_ALIAS,
337
- KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT
338
- )
339
- .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
340
- .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
341
- .setRandomizedEncryptionRequired(false)
342
- .build()
343
- );
368
+ KeyGenParameterSpec.Builder paramBuilder = new KeyGenParameterSpec.Builder(
369
+ KEY_ALIAS,
370
+ KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT
371
+ )
372
+ .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
373
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
374
+ .setRandomizedEncryptionRequired(false);
375
+
376
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
377
+ paramBuilder.setUnlockedDeviceRequired(true);
378
+ paramBuilder.setIsStrongBoxBacked(isStrongBoxBacked);
379
+ }
380
+
381
+ generator.init(paramBuilder.build());
344
382
  return generator.generateKey();
345
383
  } else {
346
384
  return getAESKey(KEY_ALIAS);
@@ -349,8 +387,8 @@ public class NativeBiometric extends Plugin {
349
387
 
350
388
  private Key getKey(String KEY_ALIAS)
351
389
  throws GeneralSecurityException, IOException {
352
- KeyStore.SecretKeyEntry secretKeyEntry =
353
- (KeyStore.SecretKeyEntry) getKeyStore().getEntry(KEY_ALIAS, null);
390
+ KeyStore.SecretKeyEntry secretKeyEntry = (KeyStore.SecretKeyEntry) getKeyStore()
391
+ .getEntry(KEY_ALIAS, null);
354
392
  if (secretKeyEntry != null) {
355
393
  return secretKeyEntry.getSecretKey();
356
394
  }
@@ -359,13 +397,11 @@ public class NativeBiometric extends Plugin {
359
397
 
360
398
  private KeyStore getKeyStore()
361
399
  throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
362
- if (keyStore != null) {
363
- return keyStore;
364
- } else {
400
+ if (keyStore == null) {
365
401
  keyStore = KeyStore.getInstance(ANDROID_KEY_STORE);
366
402
  keyStore.load(null);
367
- return keyStore;
368
403
  }
404
+ return keyStore;
369
405
  }
370
406
 
371
407
  private Key getAESKey(String KEY_ALIAS)
@@ -392,8 +428,8 @@ public class NativeBiometric extends Plugin {
392
428
 
393
429
  private KeyStore.PrivateKeyEntry getPrivateKeyEntry(String KEY_ALIAS)
394
430
  throws NoSuchProviderException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, CertificateException, KeyStoreException, IOException, UnrecoverableEntryException {
395
- KeyStore.PrivateKeyEntry privateKeyEntry =
396
- (KeyStore.PrivateKeyEntry) getKeyStore().getEntry(KEY_ALIAS, null);
431
+ KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) getKeyStore()
432
+ .getEntry(KEY_ALIAS, null);
397
433
 
398
434
  if (privateKeyEntry == null) {
399
435
  KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
@@ -454,4 +490,15 @@ public class NativeBiometric extends Plugin {
454
490
  }
455
491
  return bytes;
456
492
  }
493
+
494
+ private boolean deviceHasCredentials() {
495
+ KeyguardManager keyguardManager = (KeyguardManager) getActivity()
496
+ .getSystemService(Context.KEYGUARD_SERVICE);
497
+ // Can only use fallback if the device has a pin/pattern/password lockscreen.
498
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
499
+ return keyguardManager.isDeviceSecure();
500
+ } else {
501
+ return keyguardManager.isKeyguardSecure();
502
+ }
503
+ }
457
504
  }
package/dist/docs.json CHANGED
@@ -7,12 +7,12 @@
7
7
  "methods": [
8
8
  {
9
9
  "name": "isAvailable",
10
- "signature": "(options?: IsAvailableOptions) => any",
10
+ "signature": "(options?: IsAvailableOptions | undefined) => any",
11
11
  "parameters": [
12
12
  {
13
13
  "name": "options",
14
14
  "docs": "",
15
- "type": "IsAvailableOptions"
15
+ "type": "IsAvailableOptions | undefined"
16
16
  }
17
17
  ],
18
18
  "returns": "any",
@@ -42,12 +42,12 @@
42
42
  },
43
43
  {
44
44
  "name": "verifyIdentity",
45
- "signature": "(options?: BiometricOptions) => any",
45
+ "signature": "(options?: BiometricOptions | undefined) => any",
46
46
  "parameters": [
47
47
  {
48
48
  "name": "options",
49
49
  "docs": "",
50
- "type": "BiometricOptions"
50
+ "type": "BiometricOptions | undefined"
51
51
  }
52
52
  ],
53
53
  "returns": "any",
@@ -225,7 +225,7 @@
225
225
  "tags": [],
226
226
  "docs": "",
227
227
  "complexTypes": [],
228
- "type": "number"
228
+ "type": "number | undefined"
229
229
  }
230
230
  ]
231
231
  },
@@ -241,42 +241,49 @@
241
241
  "tags": [],
242
242
  "docs": "",
243
243
  "complexTypes": [],
244
- "type": "string"
244
+ "type": "string | undefined"
245
245
  },
246
246
  {
247
247
  "name": "title",
248
248
  "tags": [],
249
249
  "docs": "",
250
250
  "complexTypes": [],
251
- "type": "string"
251
+ "type": "string | undefined"
252
252
  },
253
253
  {
254
254
  "name": "subtitle",
255
255
  "tags": [],
256
256
  "docs": "",
257
257
  "complexTypes": [],
258
- "type": "string"
258
+ "type": "string | undefined"
259
259
  },
260
260
  {
261
261
  "name": "description",
262
262
  "tags": [],
263
263
  "docs": "",
264
264
  "complexTypes": [],
265
- "type": "string"
265
+ "type": "string | undefined"
266
266
  },
267
267
  {
268
268
  "name": "negativeButtonText",
269
269
  "tags": [],
270
270
  "docs": "",
271
271
  "complexTypes": [],
272
- "type": "string"
272
+ "type": "string | undefined"
273
273
  },
274
274
  {
275
275
  "name": "useFallback",
276
276
  "tags": [],
277
- "docs": "",
277
+ "docs": "Specifies if should fallback to passcode authentication if biometric authentication fails.",
278
278
  "complexTypes": [],
279
- "type": "boolean"
279
+ "type": "boolean | undefined"
280
+ },
281
+ {
282
+ "name": "fallbackTitle",
283
+ "tags": [],
284
+ "docs": "Only for iOS.\nSet the text for the fallback button in the authentication dialog.\nIf this property is not specified, the default text is set by the system.",
285
+ "complexTypes": [],
286
+ "type": "string | undefined"
280
287
  },
281
288
  {
282
289
  "name": "maxAttempts",
@@ -288,7 +295,7 @@
288
295
  ],
289
296
  "docs": "Only for Android.\nSet a maximum number of attempts for biometric authentication. The maximum allowed by android is 5.",
290
297
  "complexTypes": [],
291
- "type": "number"
298
+ "type": "number | undefined"
292
299
  }
293
300
  ]
294
301
  },
@@ -385,36 +392,43 @@
385
392
  "members": [
386
393
  {
387
394
  "name": "NONE",
395
+ "value": "0",
388
396
  "tags": [],
389
397
  "docs": ""
390
398
  },
391
399
  {
392
400
  "name": "TOUCH_ID",
401
+ "value": "1",
393
402
  "tags": [],
394
403
  "docs": ""
395
404
  },
396
405
  {
397
406
  "name": "FACE_ID",
407
+ "value": "2",
398
408
  "tags": [],
399
409
  "docs": ""
400
410
  },
401
411
  {
402
412
  "name": "FINGERPRINT",
413
+ "value": "3",
403
414
  "tags": [],
404
415
  "docs": ""
405
416
  },
406
417
  {
407
418
  "name": "FACE_AUTHENTICATION",
419
+ "value": "4",
408
420
  "tags": [],
409
421
  "docs": ""
410
422
  },
411
423
  {
412
424
  "name": "IRIS_AUTHENTICATION",
425
+ "value": "5",
413
426
  "tags": [],
414
427
  "docs": ""
415
428
  },
416
429
  {
417
430
  "name": "MULTIPLE",
431
+ "value": "6",
418
432
  "tags": [],
419
433
  "docs": ""
420
434
  }
@@ -28,7 +28,16 @@ export interface BiometricOptions {
28
28
  subtitle?: string;
29
29
  description?: string;
30
30
  negativeButtonText?: string;
31
+ /**
32
+ * Specifies if should fallback to passcode authentication if biometric authentication fails.
33
+ */
31
34
  useFallback?: boolean;
35
+ /**
36
+ * Only for iOS.
37
+ * Set the text for the fallback button in the authentication dialog.
38
+ * If this property is not specified, the default text is set by the system.
39
+ */
40
+ fallbackTitle?: string;
32
41
  /**
33
42
  * Only for Android.
34
43
  * Set a maximum number of attempts for biometric authentication. The maximum allowed by android is 5.
@@ -47,6 +56,25 @@ export interface SetCredentialOptions {
47
56
  export interface DeleteCredentialOptions {
48
57
  server: string;
49
58
  }
59
+ /**
60
+ * Keep this in sync with BiometricAuthError in README.md
61
+ * Update whenever `convertToPluginErrorCode` functions are modified
62
+ */
63
+ export declare enum BiometricAuthError {
64
+ UNKNOWN_ERROR = 0,
65
+ BIOMETRICS_UNAVAILABLE = 1,
66
+ USER_LOCKOUT = 2,
67
+ BIOMETRICS_NOT_ENROLLED = 3,
68
+ USER_TEMPORARY_LOCKOUT = 4,
69
+ AUTHENTICATION_FAILED = 10,
70
+ APP_CANCEL = 11,
71
+ INVALID_CONTEXT = 12,
72
+ NOT_INTERACTIVE = 13,
73
+ PASSCODE_NOT_SET = 14,
74
+ SYSTEM_CANCEL = 15,
75
+ USER_CANCEL = 16,
76
+ USER_FALLBACK = 17
77
+ }
50
78
  export interface NativeBiometricPlugin {
51
79
  /**
52
80
  * Checks if biometric authentication hardware is available.
@@ -63,7 +91,7 @@ export interface NativeBiometricPlugin {
63
91
  * @memberof NativeBiometricPlugin
64
92
  * @since 1.0.0
65
93
  */
66
- verifyIdentity(options?: BiometricOptions): Promise<any>;
94
+ verifyIdentity(options?: BiometricOptions): Promise<void>;
67
95
  /**
68
96
  * Gets the stored credentials for a given server.
69
97
  * @param {GetCredentialOptions} options
@@ -79,7 +107,7 @@ export interface NativeBiometricPlugin {
79
107
  * @memberof NativeBiometricPlugin
80
108
  * @since 1.0.0
81
109
  */
82
- setCredentials(options: SetCredentialOptions): Promise<any>;
110
+ setCredentials(options: SetCredentialOptions): Promise<void>;
83
111
  /**
84
112
  * Deletes the stored credentials for a given server.
85
113
  * @param {DeleteCredentialOptions} options
@@ -87,5 +115,5 @@ export interface NativeBiometricPlugin {
87
115
  * @memberof NativeBiometricPlugin
88
116
  * @since 1.0.0
89
117
  */
90
- deleteCredentials(options: DeleteCredentialOptions): Promise<any>;
118
+ deleteCredentials(options: DeleteCredentialOptions): Promise<void>;
91
119
  }
@@ -1,11 +1,38 @@
1
1
  export var BiometryType;
2
2
  (function (BiometryType) {
3
+ // Android, iOS
3
4
  BiometryType[BiometryType["NONE"] = 0] = "NONE";
5
+ // iOS
4
6
  BiometryType[BiometryType["TOUCH_ID"] = 1] = "TOUCH_ID";
7
+ // iOS
5
8
  BiometryType[BiometryType["FACE_ID"] = 2] = "FACE_ID";
9
+ // Android
6
10
  BiometryType[BiometryType["FINGERPRINT"] = 3] = "FINGERPRINT";
11
+ // Android
7
12
  BiometryType[BiometryType["FACE_AUTHENTICATION"] = 4] = "FACE_AUTHENTICATION";
13
+ // Android
8
14
  BiometryType[BiometryType["IRIS_AUTHENTICATION"] = 5] = "IRIS_AUTHENTICATION";
15
+ // Android
9
16
  BiometryType[BiometryType["MULTIPLE"] = 6] = "MULTIPLE";
10
17
  })(BiometryType || (BiometryType = {}));
18
+ /**
19
+ * Keep this in sync with BiometricAuthError in README.md
20
+ * Update whenever `convertToPluginErrorCode` functions are modified
21
+ */
22
+ export var BiometricAuthError;
23
+ (function (BiometricAuthError) {
24
+ BiometricAuthError[BiometricAuthError["UNKNOWN_ERROR"] = 0] = "UNKNOWN_ERROR";
25
+ BiometricAuthError[BiometricAuthError["BIOMETRICS_UNAVAILABLE"] = 1] = "BIOMETRICS_UNAVAILABLE";
26
+ BiometricAuthError[BiometricAuthError["USER_LOCKOUT"] = 2] = "USER_LOCKOUT";
27
+ BiometricAuthError[BiometricAuthError["BIOMETRICS_NOT_ENROLLED"] = 3] = "BIOMETRICS_NOT_ENROLLED";
28
+ BiometricAuthError[BiometricAuthError["USER_TEMPORARY_LOCKOUT"] = 4] = "USER_TEMPORARY_LOCKOUT";
29
+ BiometricAuthError[BiometricAuthError["AUTHENTICATION_FAILED"] = 10] = "AUTHENTICATION_FAILED";
30
+ BiometricAuthError[BiometricAuthError["APP_CANCEL"] = 11] = "APP_CANCEL";
31
+ BiometricAuthError[BiometricAuthError["INVALID_CONTEXT"] = 12] = "INVALID_CONTEXT";
32
+ BiometricAuthError[BiometricAuthError["NOT_INTERACTIVE"] = 13] = "NOT_INTERACTIVE";
33
+ BiometricAuthError[BiometricAuthError["PASSCODE_NOT_SET"] = 14] = "PASSCODE_NOT_SET";
34
+ BiometricAuthError[BiometricAuthError["SYSTEM_CANCEL"] = 15] = "SYSTEM_CANCEL";
35
+ BiometricAuthError[BiometricAuthError["USER_CANCEL"] = 16] = "USER_CANCEL";
36
+ BiometricAuthError[BiometricAuthError["USER_FALLBACK"] = 17] = "USER_FALLBACK";
37
+ })(BiometricAuthError || (BiometricAuthError = {}));
11
38
  //# sourceMappingURL=definitions.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,YAQX;AARD,WAAY,YAAY;IACtB,+CAAI,CAAA;IACJ,uDAAQ,CAAA;IACR,qDAAO,CAAA;IACP,6DAAW,CAAA;IACX,6EAAmB,CAAA;IACnB,6EAAmB,CAAA;IACnB,uDAAQ,CAAA;AACV,CAAC,EARW,YAAY,KAAZ,YAAY,QAQvB"}
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,YAeX;AAfD,WAAY,YAAY;IACtB,eAAe;IACf,+CAAQ,CAAA;IACR,MAAM;IACN,uDAAY,CAAA;IACZ,MAAM;IACN,qDAAW,CAAA;IACX,UAAU;IACV,6DAAe,CAAA;IACf,UAAU;IACV,6EAAuB,CAAA;IACvB,UAAU;IACV,6EAAuB,CAAA;IACvB,UAAU;IACV,uDAAY,CAAA;AACd,CAAC,EAfW,YAAY,KAAZ,YAAY,QAevB;AA0DD;;;GAGG;AACH,MAAM,CAAN,IAAY,kBAcX;AAdD,WAAY,kBAAkB;IAC5B,6EAAiB,CAAA;IACjB,+FAA0B,CAAA;IAC1B,2EAAgB,CAAA;IAChB,iGAA2B,CAAA;IAC3B,+FAA0B,CAAA;IAC1B,8FAA0B,CAAA;IAC1B,wEAAe,CAAA;IACf,kFAAoB,CAAA;IACpB,kFAAoB,CAAA;IACpB,oFAAqB,CAAA;IACrB,8EAAkB,CAAA;IAClB,0EAAgB,CAAA;IAChB,8EAAkB,CAAA;AACpB,CAAC,EAdW,kBAAkB,KAAlB,kBAAkB,QAc7B","sourcesContent":["export enum BiometryType {\n // Android, iOS\n NONE = 0,\n // iOS\n TOUCH_ID = 1,\n // iOS\n FACE_ID = 2,\n // Android\n FINGERPRINT = 3,\n // Android\n FACE_AUTHENTICATION = 4,\n // Android\n IRIS_AUTHENTICATION = 5,\n // Android\n MULTIPLE = 6,\n}\n\nexport interface Credentials {\n username: string;\n password: string;\n}\n\nexport interface IsAvailableOptions {\n /**\n * Specifies if should fallback to passcode authentication if biometric authentication is not available.\n */\n useFallback: boolean;\n}\n\nexport interface AvailableResult {\n isAvailable: boolean;\n biometryType: BiometryType;\n errorCode?: number;\n}\n\nexport interface BiometricOptions {\n reason?: string;\n title?: string;\n subtitle?: string;\n description?: string;\n negativeButtonText?: string;\n /**\n * Specifies if should fallback to passcode authentication if biometric authentication fails.\n */\n useFallback?: boolean;\n /**\n * Only for iOS.\n * Set the text for the fallback button in the authentication dialog.\n * If this property is not specified, the default text is set by the system.\n */\n fallbackTitle?: string;\n /**\n * Only for Android.\n * Set a maximum number of attempts for biometric authentication. The maximum allowed by android is 5.\n * @default 1\n */\n maxAttempts?: number;\n}\n\nexport interface GetCredentialOptions {\n server: string;\n}\n\nexport interface SetCredentialOptions {\n username: string;\n password: string;\n server: string;\n}\n\nexport interface DeleteCredentialOptions {\n server: string;\n}\n\n/**\n * Keep this in sync with BiometricAuthError in README.md\n * Update whenever `convertToPluginErrorCode` functions are modified\n */\nexport enum BiometricAuthError {\n UNKNOWN_ERROR = 0,\n BIOMETRICS_UNAVAILABLE = 1,\n USER_LOCKOUT = 2,\n BIOMETRICS_NOT_ENROLLED = 3,\n USER_TEMPORARY_LOCKOUT = 4,\n AUTHENTICATION_FAILED = 10,\n APP_CANCEL = 11,\n INVALID_CONTEXT = 12,\n NOT_INTERACTIVE = 13,\n PASSCODE_NOT_SET = 14,\n SYSTEM_CANCEL = 15,\n USER_CANCEL = 16,\n USER_FALLBACK = 17,\n}\n\nexport interface NativeBiometricPlugin {\n /**\n * Checks if biometric authentication hardware is available.\n * @param {IsAvailableOptions} [options]\n * @returns {Promise<AvailableResult>}\n * @memberof NativeBiometricPlugin\n * @since 1.0.0\n */\n isAvailable(options?: IsAvailableOptions): Promise<AvailableResult>;\n /**\n * Prompts the user to authenticate with biometrics.\n * @param {BiometricOptions} [options]\n * @returns {Promise<any>}\n * @memberof NativeBiometricPlugin\n * @since 1.0.0\n */\n verifyIdentity(options?: BiometricOptions): Promise<void>;\n /**\n * Gets the stored credentials for a given server.\n * @param {GetCredentialOptions} options\n * @returns {Promise<Credentials>}\n * @memberof NativeBiometricPlugin\n * @since 1.0.0\n */\n getCredentials(options: GetCredentialOptions): Promise<Credentials>;\n /**\n * Stores the given credentials for a given server.\n * @param {SetCredentialOptions} options\n * @returns {Promise<any>}\n * @memberof NativeBiometricPlugin\n * @since 1.0.0\n */\n setCredentials(options: SetCredentialOptions): Promise<void>;\n /**\n * Deletes the stored credentials for a given server.\n * @param {DeleteCredentialOptions} options\n * @returns {Promise<any>}\n * @memberof NativeBiometricPlugin\n * @since 1.0.0\n */\n deleteCredentials(options: DeleteCredentialOptions): Promise<void>;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,eAAe,GAAG,cAAc,CACpC,iBAAiB,EACjB;IACE,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,kBAAkB,EAAE,CAAC;CACnE,CACF,CAAC;AAEF,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,eAAe,EAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,eAAe,GAAG,cAAc,CACpC,iBAAiB,EACjB;IACE,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,kBAAkB,EAAE,CAAC;CACnE,CACF,CAAC;AAEF,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,eAAe,EAAE,CAAC","sourcesContent":["import { registerPlugin } from \"@capacitor/core\";\n\nimport type { NativeBiometricPlugin } from \"./definitions\";\n\nconst NativeBiometric = registerPlugin<NativeBiometricPlugin>(\n \"NativeBiometric\",\n {\n web: () => import(\"./web\").then((m) => new m.NativeBiometricWeb()),\n }\n);\n\nexport * from \"./definitions\";\nexport { NativeBiometric };\n"]}
package/dist/esm/web.d.ts CHANGED
@@ -3,8 +3,8 @@ import type { NativeBiometricPlugin, AvailableResult, BiometricOptions, GetCrede
3
3
  export declare class NativeBiometricWeb extends WebPlugin implements NativeBiometricPlugin {
4
4
  constructor();
5
5
  isAvailable(): Promise<AvailableResult>;
6
- verifyIdentity(_options?: BiometricOptions): Promise<any>;
6
+ verifyIdentity(_options?: BiometricOptions): Promise<void>;
7
7
  getCredentials(_options: GetCredentialOptions): Promise<Credentials>;
8
- setCredentials(_options: SetCredentialOptions): Promise<any>;
9
- deleteCredentials(_options: DeleteCredentialOptions): Promise<any>;
8
+ setCredentials(_options: SetCredentialOptions): Promise<void>;
9
+ deleteCredentials(_options: DeleteCredentialOptions): Promise<void>;
10
10
  }
@@ -1 +1 @@
1
- {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAY5C,MAAM,OAAO,kBACX,SAAQ,SAAS;IAGjB;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IACD,WAAW;QACT,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IAED,cAAc,CAAC,QAA2B;QACxC,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IACD,cAAc,CAAC,QAA8B;QAC3C,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IACD,cAAc,CAAC,QAA8B;QAC3C,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IACD,iBAAiB,CAAC,QAAiC;QACjD,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;CACF"}
1
+ {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAY5C,MAAM,OAAO,kBACX,SAAQ,SAAS;IAGjB;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IACD,WAAW;QACT,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IAED,cAAc,CAAC,QAA2B;QACxC,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IACD,cAAc,CAAC,QAA8B;QAC3C,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IACD,cAAc,CAAC,QAA8B;QAC3C,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IACD,iBAAiB,CAAC,QAAiC;QACjD,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;CACF","sourcesContent":["import { WebPlugin } from \"@capacitor/core\";\n\nimport type {\n NativeBiometricPlugin,\n AvailableResult,\n BiometricOptions,\n GetCredentialOptions,\n SetCredentialOptions,\n DeleteCredentialOptions,\n Credentials,\n} from \"./definitions\";\n\nexport class NativeBiometricWeb\n extends WebPlugin\n implements NativeBiometricPlugin\n{\n constructor() {\n super();\n }\n isAvailable(): Promise<AvailableResult> {\n throw new Error(\"Method not implemented.\");\n }\n\n verifyIdentity(_options?: BiometricOptions): Promise<void> {\n throw new Error(\"Method not implemented.\");\n }\n getCredentials(_options: GetCredentialOptions): Promise<Credentials> {\n throw new Error(\"Method not implemented.\");\n }\n setCredentials(_options: SetCredentialOptions): Promise<void> {\n throw new Error(\"Method not implemented.\");\n }\n deleteCredentials(_options: DeleteCredentialOptions): Promise<void> {\n throw new Error(\"Method not implemented.\");\n }\n}\n"]}
@@ -1,17 +1,40 @@
1
1
  'use strict';
2
2
 
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
3
5
  var core = require('@capacitor/core');
4
6
 
5
- exports.BiometryType = void 0;
6
7
  (function (BiometryType) {
8
+ // Android, iOS
7
9
  BiometryType[BiometryType["NONE"] = 0] = "NONE";
10
+ // iOS
8
11
  BiometryType[BiometryType["TOUCH_ID"] = 1] = "TOUCH_ID";
12
+ // iOS
9
13
  BiometryType[BiometryType["FACE_ID"] = 2] = "FACE_ID";
14
+ // Android
10
15
  BiometryType[BiometryType["FINGERPRINT"] = 3] = "FINGERPRINT";
16
+ // Android
11
17
  BiometryType[BiometryType["FACE_AUTHENTICATION"] = 4] = "FACE_AUTHENTICATION";
18
+ // Android
12
19
  BiometryType[BiometryType["IRIS_AUTHENTICATION"] = 5] = "IRIS_AUTHENTICATION";
20
+ // Android
13
21
  BiometryType[BiometryType["MULTIPLE"] = 6] = "MULTIPLE";
14
22
  })(exports.BiometryType || (exports.BiometryType = {}));
23
+ (function (BiometricAuthError) {
24
+ BiometricAuthError[BiometricAuthError["UNKNOWN_ERROR"] = 0] = "UNKNOWN_ERROR";
25
+ BiometricAuthError[BiometricAuthError["BIOMETRICS_UNAVAILABLE"] = 1] = "BIOMETRICS_UNAVAILABLE";
26
+ BiometricAuthError[BiometricAuthError["USER_LOCKOUT"] = 2] = "USER_LOCKOUT";
27
+ BiometricAuthError[BiometricAuthError["BIOMETRICS_NOT_ENROLLED"] = 3] = "BIOMETRICS_NOT_ENROLLED";
28
+ BiometricAuthError[BiometricAuthError["USER_TEMPORARY_LOCKOUT"] = 4] = "USER_TEMPORARY_LOCKOUT";
29
+ BiometricAuthError[BiometricAuthError["AUTHENTICATION_FAILED"] = 10] = "AUTHENTICATION_FAILED";
30
+ BiometricAuthError[BiometricAuthError["APP_CANCEL"] = 11] = "APP_CANCEL";
31
+ BiometricAuthError[BiometricAuthError["INVALID_CONTEXT"] = 12] = "INVALID_CONTEXT";
32
+ BiometricAuthError[BiometricAuthError["NOT_INTERACTIVE"] = 13] = "NOT_INTERACTIVE";
33
+ BiometricAuthError[BiometricAuthError["PASSCODE_NOT_SET"] = 14] = "PASSCODE_NOT_SET";
34
+ BiometricAuthError[BiometricAuthError["SYSTEM_CANCEL"] = 15] = "SYSTEM_CANCEL";
35
+ BiometricAuthError[BiometricAuthError["USER_CANCEL"] = 16] = "USER_CANCEL";
36
+ BiometricAuthError[BiometricAuthError["USER_FALLBACK"] = 17] = "USER_FALLBACK";
37
+ })(exports.BiometricAuthError || (exports.BiometricAuthError = {}));
15
38
 
16
39
  const NativeBiometric = core.registerPlugin("NativeBiometric", {
17
40
  web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.NativeBiometricWeb()),