@capgo/capacitor-native-biometric 7.1.13 → 7.1.15

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 (35) hide show
  1. package/Package.swift +28 -0
  2. package/README.md +4 -0
  3. package/android/src/main/java/ee/forgr/biometric/AuthActivity.java +141 -166
  4. package/android/src/main/java/ee/forgr/biometric/NativeBiometric.java +351 -443
  5. package/dist/esm/index.d.ts +2 -2
  6. package/dist/esm/index.js +4 -4
  7. package/dist/esm/index.js.map +1 -1
  8. package/dist/esm/web.d.ts +2 -2
  9. package/dist/esm/web.js +10 -10
  10. package/dist/esm/web.js.map +1 -1
  11. package/dist/plugin.cjs.js +10 -10
  12. package/dist/plugin.cjs.js.map +1 -1
  13. package/dist/plugin.js +10 -10
  14. package/dist/plugin.js.map +1 -1
  15. package/ios/{Plugin/Plugin.swift → Sources/CapgoNativeBiometricPlugin/CapgoNativeBiometricPlugin.swift} +3 -3
  16. package/ios/Tests/CapgoNativeBiometricPluginTests/CapgoNativeBiometricPluginTests.swift +13 -0
  17. package/package.json +20 -19
  18. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  19. package/android/gradle/wrapper/gradle-wrapper.properties +0 -7
  20. package/android/gradle.properties +0 -20
  21. package/android/gradlew +0 -252
  22. package/android/gradlew.bat +0 -94
  23. package/android/proguard-rules.pro +0 -21
  24. package/android/settings.gradle +0 -2
  25. package/android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java +0 -27
  26. package/android/src/test/java/com/getcapacitor/ExampleUnitTest.java +0 -18
  27. package/ios/Plugin/Info.plist +0 -24
  28. package/ios/Plugin.xcodeproj/project.pbxproj +0 -546
  29. package/ios/Plugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
  30. package/ios/Plugin.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
  31. package/ios/Plugin.xcworkspace/contents.xcworkspacedata +0 -10
  32. package/ios/Plugin.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
  33. package/ios/PluginTests/Info.plist +0 -22
  34. package/ios/PluginTests/PluginTests.swift +0 -25
  35. package/ios/Podfile +0 -16
package/Package.swift ADDED
@@ -0,0 +1,28 @@
1
+ // swift-tools-version: 5.9
2
+ import PackageDescription
3
+
4
+ let package = Package(
5
+ name: "CapgoCapacitorNativeBiometric",
6
+ platforms: [.iOS(.v14)],
7
+ products: [
8
+ .library(
9
+ name: "CapgoCapacitorNativeBiometric",
10
+ targets: ["CapgoNativeBiometricPlugin"])
11
+ ],
12
+ dependencies: [
13
+ .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "7.0.0")
14
+ ],
15
+ targets: [
16
+ .target(
17
+ name: "CapgoNativeBiometricPlugin",
18
+ dependencies: [
19
+ .product(name: "Capacitor", package: "capacitor-swift-pm"),
20
+ .product(name: "Cordova", package: "capacitor-swift-pm")
21
+ ],
22
+ path: "ios/Sources/CapgoNativeBiometricPlugin"),
23
+ .testTarget(
24
+ name: "CapgoNativeBiometricPluginTests",
25
+ dependencies: ["CapgoNativeBiometricPlugin"],
26
+ path: "ios/Tests/CapgoNativeBiometricPluginTests")
27
+ ]
28
+ )
package/README.md CHANGED
@@ -9,6 +9,10 @@
9
9
 
10
10
  Use biometrics confirm device owner presence or authenticate users. A couple of methods are provided to handle user credentials. These are securely stored using Keychain (iOS) and Keystore (Android).
11
11
 
12
+ ## Documentation
13
+
14
+ The most complete doc is available here: https://capgo.app/docs/plugins/native-biometric/
15
+
12
16
  ## Installation (Only supports Capacitor 7)
13
17
 
14
18
  - `npm i @capgo/capacitor-native-biometric`
@@ -14,185 +14,160 @@ import java.util.concurrent.Executor;
14
14
 
15
15
  public class AuthActivity extends AppCompatActivity {
16
16
 
17
- private BiometricPrompt biometricPrompt;
18
- private int maxAttempts;
19
- private int counter = 0;
20
-
21
- @Override
22
- protected void onCreate(Bundle savedInstanceState) {
23
- super.onCreate(savedInstanceState);
24
- setContentView(R.layout.activity_auth_acitivy);
25
-
26
- maxAttempts = getIntent().getIntExtra("maxAttempts", 1);
27
-
28
- Executor executor;
29
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
30
- executor = this.getMainExecutor();
31
- } else {
32
- executor = new Executor() {
33
- @Override
34
- public void execute(Runnable command) {
35
- new Handler().post(command);
17
+ private BiometricPrompt biometricPrompt;
18
+ private int maxAttempts;
19
+ private int counter = 0;
20
+
21
+ @Override
22
+ protected void onCreate(Bundle savedInstanceState) {
23
+ super.onCreate(savedInstanceState);
24
+ setContentView(R.layout.activity_auth_acitivy);
25
+
26
+ maxAttempts = getIntent().getIntExtra("maxAttempts", 1);
27
+
28
+ Executor executor;
29
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
30
+ executor = this.getMainExecutor();
31
+ } else {
32
+ executor = new Executor() {
33
+ @Override
34
+ public void execute(Runnable command) {
35
+ new Handler().post(command);
36
+ }
37
+ };
36
38
  }
37
- };
38
- }
39
-
40
- BiometricPrompt.PromptInfo.Builder builder =
41
- new BiometricPrompt.PromptInfo.Builder()
42
- .setTitle(
43
- getIntent().hasExtra("title")
44
- ? Objects.requireNonNull(getIntent().getStringExtra("title"))
45
- : "Authenticate"
46
- )
47
- .setSubtitle(
48
- getIntent().hasExtra("subtitle")
49
- ? getIntent().getStringExtra("subtitle")
50
- : null
51
- )
52
- .setDescription(
53
- getIntent().hasExtra("description")
54
- ? getIntent().getStringExtra("description")
55
- : null
56
- );
57
39
 
58
- boolean useFallback = getIntent().getBooleanExtra("useFallback", false);
59
- int[] allowedTypes = getIntent().getIntArrayExtra("allowedBiometryTypes");
40
+ BiometricPrompt.PromptInfo.Builder builder = new BiometricPrompt.PromptInfo.Builder()
41
+ .setTitle(getIntent().hasExtra("title") ? Objects.requireNonNull(getIntent().getStringExtra("title")) : "Authenticate")
42
+ .setSubtitle(getIntent().hasExtra("subtitle") ? getIntent().getStringExtra("subtitle") : null)
43
+ .setDescription(getIntent().hasExtra("description") ? getIntent().getStringExtra("description") : null);
60
44
 
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);
45
+ boolean useFallback = getIntent().getBooleanExtra("useFallback", false);
46
+ int[] allowedTypes = getIntent().getIntArrayExtra("allowedBiometryTypes");
70
47
 
71
- if (!useFallback) {
72
- String negativeText = getIntent().getStringExtra("negativeButtonText");
73
- builder.setNegativeButtonText(
74
- negativeText != null ? negativeText : "Cancel"
75
- );
76
- }
77
-
78
- BiometricPrompt.PromptInfo promptInfo = builder.build();
79
-
80
- biometricPrompt = new BiometricPrompt(
81
- this,
82
- executor,
83
- new BiometricPrompt.AuthenticationCallback() {
84
- @Override
85
- public void onAuthenticationError(
86
- int errorCode,
87
- @NonNull CharSequence errString
88
- ) {
89
- super.onAuthenticationError(errorCode, errString);
90
- // Handle lockout cases explicitly
91
- if (
92
- errorCode == BiometricPrompt.ERROR_LOCKOUT ||
93
- errorCode == BiometricPrompt.ERROR_LOCKOUT_PERMANENT
94
- ) {
95
- int pluginErrorCode = convertToPluginErrorCode(errorCode);
96
- finishActivity("error", pluginErrorCode, errString.toString());
97
- return;
98
- }
99
- int pluginErrorCode = convertToPluginErrorCode(errorCode);
100
- finishActivity("error", pluginErrorCode, errString.toString());
48
+ int authenticators = BiometricManager.Authenticators.BIOMETRIC_STRONG;
49
+ if (useFallback) {
50
+ authenticators |= BiometricManager.Authenticators.DEVICE_CREDENTIAL;
101
51
  }
102
-
103
- @Override
104
- public void onAuthenticationSucceeded(
105
- @NonNull BiometricPrompt.AuthenticationResult result
106
- ) {
107
- super.onAuthenticationSucceeded(result);
108
- finishActivity();
52
+ if (allowedTypes != null) {
53
+ // Filter authenticators based on allowed types
54
+ authenticators = getAllowedAuthenticators(allowedTypes);
109
55
  }
56
+ builder.setAllowedAuthenticators(authenticators);
110
57
 
111
- @Override
112
- public void onAuthenticationFailed() {
113
- super.onAuthenticationFailed();
114
- counter++;
115
- if (counter >= maxAttempts) {
116
- biometricPrompt.cancelAuthentication();
117
- // Use error code 4 for too many attempts to match iOS behavior
118
- finishActivity("error", 4, "Too many failed attempts");
119
- }
58
+ if (!useFallback) {
59
+ String negativeText = getIntent().getStringExtra("negativeButtonText");
60
+ builder.setNegativeButtonText(negativeText != null ? negativeText : "Cancel");
120
61
  }
121
- }
122
- );
123
62
 
124
- biometricPrompt.authenticate(promptInfo);
125
- }
63
+ BiometricPrompt.PromptInfo promptInfo = builder.build();
64
+
65
+ biometricPrompt = new BiometricPrompt(
66
+ this,
67
+ executor,
68
+ new BiometricPrompt.AuthenticationCallback() {
69
+ @Override
70
+ public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
71
+ super.onAuthenticationError(errorCode, errString);
72
+ // Handle lockout cases explicitly
73
+ if (errorCode == BiometricPrompt.ERROR_LOCKOUT || errorCode == BiometricPrompt.ERROR_LOCKOUT_PERMANENT) {
74
+ int pluginErrorCode = convertToPluginErrorCode(errorCode);
75
+ finishActivity("error", pluginErrorCode, errString.toString());
76
+ return;
77
+ }
78
+ int pluginErrorCode = convertToPluginErrorCode(errorCode);
79
+ finishActivity("error", pluginErrorCode, errString.toString());
80
+ }
81
+
82
+ @Override
83
+ public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
84
+ super.onAuthenticationSucceeded(result);
85
+ finishActivity();
86
+ }
87
+
88
+ @Override
89
+ public void onAuthenticationFailed() {
90
+ super.onAuthenticationFailed();
91
+ counter++;
92
+ if (counter >= maxAttempts) {
93
+ biometricPrompt.cancelAuthentication();
94
+ // Use error code 4 for too many attempts to match iOS behavior
95
+ finishActivity("error", 4, "Too many failed attempts");
96
+ }
97
+ }
98
+ }
99
+ );
126
100
 
127
- void finishActivity() {
128
- finishActivity("success", null, null);
129
- }
101
+ biometricPrompt.authenticate(promptInfo);
102
+ }
130
103
 
131
- void finishActivity(String result, Integer errorCode, String errorDetails) {
132
- Intent intent = new Intent();
133
- intent.putExtra("result", result);
134
- if (errorCode != null) {
135
- intent.putExtra("errorCode", String.valueOf(errorCode));
104
+ void finishActivity() {
105
+ finishActivity("success", null, null);
136
106
  }
137
- if (errorDetails != null) {
138
- intent.putExtra("errorDetails", errorDetails);
107
+
108
+ void finishActivity(String result, Integer errorCode, String errorDetails) {
109
+ Intent intent = new Intent();
110
+ intent.putExtra("result", result);
111
+ if (errorCode != null) {
112
+ intent.putExtra("errorCode", String.valueOf(errorCode));
113
+ }
114
+ if (errorDetails != null) {
115
+ intent.putExtra("errorDetails", errorDetails);
116
+ }
117
+ setResult(RESULT_OK, intent);
118
+ finish();
139
119
  }
140
- setResult(RESULT_OK, intent);
141
- finish();
142
- }
143
-
144
- /**
145
- * Convert Auth Error Codes to plugin expected Biometric Auth Errors (in README.md)
146
- * This way both iOS and Android return the same error codes for the same authentication failure reasons.
147
- * !!IMPORTANT!!: Whenever this is modified, check if similar function in iOS Plugin.swift needs to be modified as well
148
- * @see <a href="https://developer.android.com/reference/androidx/biometric/BiometricPrompt#constants">...</a>
149
- * @return BiometricAuthError
150
- */
151
- public static int convertToPluginErrorCode(int errorCode) {
152
- switch (errorCode) {
153
- case BiometricPrompt.ERROR_HW_UNAVAILABLE:
154
- case BiometricPrompt.ERROR_HW_NOT_PRESENT:
155
- return 1;
156
- case BiometricPrompt.ERROR_LOCKOUT_PERMANENT:
157
- return 2; // Permanent lockout
158
- case BiometricPrompt.ERROR_NO_BIOMETRICS:
159
- return 3;
160
- case BiometricPrompt.ERROR_LOCKOUT:
161
- return 4; // Temporary lockout (too many attempts)
162
- // Authentication Failure (10) Handled by `onAuthenticationFailed`.
163
- // App Cancel (11), Invalid Context (12), and Not Interactive (13) are not valid error codes for Android.
164
- case BiometricPrompt.ERROR_NO_DEVICE_CREDENTIAL:
165
- return 14;
166
- case BiometricPrompt.ERROR_TIMEOUT:
167
- case BiometricPrompt.ERROR_CANCELED:
168
- return 15;
169
- case BiometricPrompt.ERROR_USER_CANCELED:
170
- case BiometricPrompt.ERROR_NEGATIVE_BUTTON:
171
- return 16;
172
- case BiometricPrompt.AUTHENTICATION_RESULT_TYPE_BIOMETRIC:
173
- return 0; // Success case, should not be handled here
174
- default:
175
- return 0;
120
+
121
+ /**
122
+ * Convert Auth Error Codes to plugin expected Biometric Auth Errors (in README.md)
123
+ * This way both iOS and Android return the same error codes for the same authentication failure reasons.
124
+ * !!IMPORTANT!!: Whenever this is modified, check if similar function in iOS Plugin.swift needs to be modified as well
125
+ * @see <a href="https://developer.android.com/reference/androidx/biometric/BiometricPrompt#constants">...</a>
126
+ * @return BiometricAuthError
127
+ */
128
+ public static int convertToPluginErrorCode(int errorCode) {
129
+ switch (errorCode) {
130
+ case BiometricPrompt.ERROR_HW_UNAVAILABLE:
131
+ case BiometricPrompt.ERROR_HW_NOT_PRESENT:
132
+ return 1;
133
+ case BiometricPrompt.ERROR_LOCKOUT_PERMANENT:
134
+ return 2; // Permanent lockout
135
+ case BiometricPrompt.ERROR_NO_BIOMETRICS:
136
+ return 3;
137
+ case BiometricPrompt.ERROR_LOCKOUT:
138
+ return 4; // Temporary lockout (too many attempts)
139
+ // Authentication Failure (10) Handled by `onAuthenticationFailed`.
140
+ // App Cancel (11), Invalid Context (12), and Not Interactive (13) are not valid error codes for Android.
141
+ case BiometricPrompt.ERROR_NO_DEVICE_CREDENTIAL:
142
+ return 14;
143
+ case BiometricPrompt.ERROR_TIMEOUT:
144
+ case BiometricPrompt.ERROR_CANCELED:
145
+ return 15;
146
+ case BiometricPrompt.ERROR_USER_CANCELED:
147
+ case BiometricPrompt.ERROR_NEGATIVE_BUTTON:
148
+ return 16;
149
+ case BiometricPrompt.AUTHENTICATION_RESULT_TYPE_BIOMETRIC:
150
+ return 0; // Success case, should not be handled here
151
+ default:
152
+ return 0;
153
+ }
176
154
  }
177
- }
178
-
179
- private int getAllowedAuthenticators(int[] allowedTypes) {
180
- int authenticators = 0;
181
- for (int type : allowedTypes) {
182
- switch (type) {
183
- case 3: // FINGERPRINT
184
- authenticators |= BiometricManager.Authenticators.BIOMETRIC_STRONG;
185
- break;
186
- case 4: // FACE_AUTHENTICATION
187
- authenticators |= BiometricManager.Authenticators.BIOMETRIC_STRONG;
188
- break;
189
- case 5: // IRIS_AUTHENTICATION
190
- authenticators |= BiometricManager.Authenticators.BIOMETRIC_STRONG;
191
- break;
192
- }
155
+
156
+ private int getAllowedAuthenticators(int[] allowedTypes) {
157
+ int authenticators = 0;
158
+ for (int type : allowedTypes) {
159
+ switch (type) {
160
+ case 3: // FINGERPRINT
161
+ authenticators |= BiometricManager.Authenticators.BIOMETRIC_STRONG;
162
+ break;
163
+ case 4: // FACE_AUTHENTICATION
164
+ authenticators |= BiometricManager.Authenticators.BIOMETRIC_STRONG;
165
+ break;
166
+ case 5: // IRIS_AUTHENTICATION
167
+ authenticators |= BiometricManager.Authenticators.BIOMETRIC_STRONG;
168
+ break;
169
+ }
170
+ }
171
+ return authenticators > 0 ? authenticators : BiometricManager.Authenticators.BIOMETRIC_STRONG;
193
172
  }
194
- return authenticators > 0
195
- ? authenticators
196
- : BiometricManager.Authenticators.BIOMETRIC_STRONG;
197
- }
198
173
  }