@aparajita/capacitor-biometric-auth 3.1.3 → 4.0.0
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.
- package/README.md +27 -6
- package/android/src/main/AndroidManifest.xml +1 -1
- package/android/src/main/java/com/aparajita/capacitor/biometricauth/BiometricAuthNative.java +9 -2
- package/android/src/main/res/values/strings.xml +1 -10
- package/android/src/main/res/values/styles.xml +0 -6
- package/dist/esm/definitions.d.ts +32 -17
- package/dist/esm/definitions.js +14 -13
- package/dist/esm/info.json +1 -1
- package/dist/esm/native.js +3 -2
- package/dist/esm/web.js +2 -1
- package/dist/plugin.cjs.js +19 -18
- package/dist/plugin.js +19 -18
- package/ios/Plugin/Plugin.swift +21 -16
- package/package.json +25 -25
- package/android/src/main/res/layout/bridge_layout_main.xml +0 -15
- package/android/src/main/res/navigation/nav_graph.xml +0 -28
- package/android/src/main/res/values/colors.xml +0 -3
- package/android/src/main/res/values/dimens.xml +0 -3
package/README.md
CHANGED
|
@@ -28,6 +28,8 @@ Not using [pnpm](https://pnpm.js.org/)? You owe it to yourself to give it a try.
|
|
|
28
28
|
|
|
29
29
|
The API is extensively documented in the [TypeScript definitions file](src/definitions.ts). There is also (somewhat incomplete auto-generated) documentation [below](#api). For a complete example of how to use this plugin in practice, see the [demo app](https://github.com/aparajita/capacitor-biometric-auth-demo).
|
|
30
30
|
|
|
31
|
+
> **NOTE:** Your Android app must use a base theme named "AppTheme".
|
|
32
|
+
|
|
31
33
|
### Checking availability
|
|
32
34
|
|
|
33
35
|
Before giving the user the option to use biometry (such as displaying a biometry icon), call [`checkBiometry`](#checkbiometry) and inspect the [`CheckBiometryResult`](#checkbiometryresult) to see what (if any) biometry is available on the device. Note that `isAvailable` may be `false` but `biometryType` may indicate the presence of biometry on the device. This occurs if the current user is not enrolled in biometry, or if biometry has been disabled for the current app. In such cases the `reason` will tell you why.
|
|
@@ -107,7 +109,7 @@ web only<br><br>On the web, this method allows you to dynamically simulate diffe
|
|
|
107
109
|
authenticate(options?: AuthenticateOptions) => Promise<void>
|
|
108
110
|
```
|
|
109
111
|
|
|
110
|
-
Prompt the user for authentication. If authorization fails for any reason, the promise is rejected with a `BiometryError`.<br><br>For detailed information about the behavior on iOS, see:<br><br>https://developer.apple.com/documentation/localauthentication/lapolicy/deviceownerauthenticationwithbiometrics<br><br>Android
|
|
112
|
+
Prompt the user for authentication. If authorization fails for any reason, the promise is rejected with a `BiometryError`.<br><br>For detailed information about the behavior on iOS, see:<br><br>https://developer.apple.com/documentation/localauthentication/lapolicy/deviceownerauthenticationwithbiometrics<br><br>Some versions of Android impose a limit on the number of failed attempts. If `allowDeviceCredential` is `true`, when the limit is reached the user will then be presented with a device credential prompt. If `allowDeviceCredential` is `false`, when the limit is reached `authenticate()` will reject with a <a href="#biometryerrortype">`BiometryErrorType`</a> of `biometryLockout`, after which the user will have to wait the system-defined length of time before being allowed to authenticate again.
|
|
111
113
|
|
|
112
114
|
| Param | Type |
|
|
113
115
|
| :------ | :----------------------------------------------------- |
|
|
@@ -135,11 +137,12 @@ Register a function that will be called when the app resumes. The function will
|
|
|
135
137
|
|
|
136
138
|
#### CheckBiometryResult
|
|
137
139
|
|
|
138
|
-
| Prop | Type
|
|
139
|
-
| :----------- |
|
|
140
|
-
| isAvailable | boolean
|
|
141
|
-
| biometryType | <a href="#biometrytype">BiometryType</a>
|
|
142
|
-
| reason | string
|
|
140
|
+
| Prop | Type | Description |
|
|
141
|
+
| :----------- | :------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
142
|
+
| isAvailable | boolean | True if the device has biometric authentication capability and the current user has enrolled in biometry. |
|
|
143
|
+
| biometryType | <a href="#biometrytype">BiometryType</a> | The type of biometry available on the device. |
|
|
144
|
+
| reason | string | If biometry is not available and the system gives a reason why, it will be returned here. Otherwise it's an empty string. |
|
|
145
|
+
| code | <a href="#biometryerrortype">BiometryErrorType</a> | If biometry is not available, the error code will be returned here. Otherwise it's an empty string. The error code will be one of the <a href="#biometryerrortype">`BiometryErrorType`</a> enum values, and is consistent across platforms. This allows you to check for specific errors in a platform- independent way, for example:<br><br>if (result.code === <a href="#biometryerrortype">BiometryErrorType.biometryNotEnrolled</a>) { ... } |
|
|
143
146
|
|
|
144
147
|
#### AuthenticateOptions
|
|
145
148
|
|
|
@@ -179,5 +182,23 @@ The signature of the callback passed to `addResumeListener()`.
|
|
|
179
182
|
| faceAuthentication | Android face authentication is available |
|
|
180
183
|
| irisAuthentication | Android iris authentication is available |
|
|
181
184
|
|
|
185
|
+
#### BiometryErrorType
|
|
186
|
+
|
|
187
|
+
| Members | Value |
|
|
188
|
+
| :------------------- | :--------------------- |
|
|
189
|
+
| none | '' |
|
|
190
|
+
| appCancel | 'appCancel' |
|
|
191
|
+
| authenticationFailed | 'authenticationFailed' |
|
|
192
|
+
| invalidContext | 'invalidContext' |
|
|
193
|
+
| notInteractive | 'notInteractive' |
|
|
194
|
+
| passcodeNotSet | 'passcodeNotSet' |
|
|
195
|
+
| systemCancel | 'systemCancel' |
|
|
196
|
+
| userCancel | 'userCancel' |
|
|
197
|
+
| userFallback | 'userFallback' |
|
|
198
|
+
| biometryLockout | 'biometryLockout' |
|
|
199
|
+
| biometryNotAvailable | 'biometryNotAvailable' |
|
|
200
|
+
| biometryNotEnrolled | 'biometryNotEnrolled' |
|
|
201
|
+
| noDeviceCredential | 'noDeviceCredential' |
|
|
202
|
+
|
|
182
203
|
</docgen-api>
|
|
183
204
|
</div>
|
package/android/src/main/java/com/aparajita/capacitor/biometricauth/BiometricAuthNative.java
CHANGED
|
@@ -120,17 +120,24 @@ public class BiometricAuthNative extends Plugin {
|
|
|
120
120
|
reason = "There is no biometric hardware on this device.";
|
|
121
121
|
break;
|
|
122
122
|
case BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED:
|
|
123
|
-
reason = "The user can
|
|
123
|
+
reason = "The user can’t authenticate because a security vulnerability has been discovered with one or more hardware sensors.";
|
|
124
124
|
break;
|
|
125
125
|
case BiometricManager.BIOMETRIC_ERROR_UNSUPPORTED:
|
|
126
|
-
reason = "The user can
|
|
126
|
+
reason = "The user can’t authenticate because the specified options are incompatible with the current Android version.";
|
|
127
127
|
break;
|
|
128
128
|
case BiometricManager.BIOMETRIC_STATUS_UNKNOWN:
|
|
129
129
|
reason = "Unable to determine whether the user can authenticate.";
|
|
130
130
|
break;
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
+
String errorCode = biometryErrorCodeMap.get(biometryResult);
|
|
134
|
+
|
|
135
|
+
if (errorCode == null) {
|
|
136
|
+
errorCode = "biometryNotAvailable";
|
|
137
|
+
}
|
|
138
|
+
|
|
133
139
|
ret.put("reason", reason);
|
|
140
|
+
ret.put("code", errorCode);
|
|
134
141
|
call.resolve(ret);
|
|
135
142
|
}
|
|
136
143
|
|
|
@@ -1,12 +1,3 @@
|
|
|
1
1
|
<resources>
|
|
2
|
-
<string name="
|
|
3
|
-
<string name="title_activity_auth_acitivy">AuthAcitivy</string>
|
|
4
|
-
<!-- Strings used for fragments for navigation -->
|
|
5
|
-
<string name="first_fragment_label">First Fragment</string>
|
|
6
|
-
<string name="second_fragment_label">Second Fragment</string>
|
|
7
|
-
<string name="next">Next</string>
|
|
8
|
-
<string name="previous">Previous</string>
|
|
9
|
-
|
|
10
|
-
<string name="hello_first_fragment">Hello first fragment</string>
|
|
11
|
-
<string name="hello_second_fragment">Hello second fragment. Arg: %1$s</string>
|
|
2
|
+
<string name="title_activity_auth_activity">AuthActivity</string>
|
|
12
3
|
</resources>
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
<resources>
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
<style name="AppTheme.NoActionBar">
|
|
5
|
-
<item name="windowActionBar">false</item>
|
|
6
|
-
<item name="windowNoTitle">true</item>
|
|
7
|
-
</style>
|
|
8
|
-
|
|
9
3
|
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
|
|
10
4
|
|
|
11
5
|
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
|
|
@@ -110,18 +110,19 @@ export interface AuthenticateOptions {
|
|
|
110
110
|
* for a description of each error code.
|
|
111
111
|
*/
|
|
112
112
|
export declare enum BiometryErrorType {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
113
|
+
none = "",
|
|
114
|
+
appCancel = "appCancel",
|
|
115
|
+
authenticationFailed = "authenticationFailed",
|
|
116
|
+
invalidContext = "invalidContext",
|
|
117
|
+
notInteractive = "notInteractive",
|
|
118
|
+
passcodeNotSet = "passcodeNotSet",
|
|
119
|
+
systemCancel = "systemCancel",
|
|
120
|
+
userCancel = "userCancel",
|
|
121
|
+
userFallback = "userFallback",
|
|
122
|
+
biometryLockout = "biometryLockout",
|
|
123
|
+
biometryNotAvailable = "biometryNotAvailable",
|
|
124
|
+
biometryNotEnrolled = "biometryNotEnrolled",
|
|
125
|
+
noDeviceCredential = "noDeviceCredential"
|
|
125
126
|
}
|
|
126
127
|
export interface ResultError extends PluginResultError {
|
|
127
128
|
code: string;
|
|
@@ -146,6 +147,18 @@ export interface CheckBiometryResult {
|
|
|
146
147
|
* it will be returned here. Otherwise it's an empty string.
|
|
147
148
|
*/
|
|
148
149
|
reason: string;
|
|
150
|
+
/**
|
|
151
|
+
* If biometry is not available, the error code will be returned here.
|
|
152
|
+
* Otherwise it's an empty string. The error code will be one of the
|
|
153
|
+
* `BiometryErrorType` enum values, and is consistent across
|
|
154
|
+
* platforms. This allows you to check for specific errors in a platform-
|
|
155
|
+
* independent way, for example:
|
|
156
|
+
*
|
|
157
|
+
* if (result.code === BiometryErrorType.biometryNotEnrolled) {
|
|
158
|
+
* ...
|
|
159
|
+
* }
|
|
160
|
+
*/
|
|
161
|
+
code: BiometryErrorType;
|
|
149
162
|
}
|
|
150
163
|
/**
|
|
151
164
|
* The signature of the callback passed to `addResumeListener()`.
|
|
@@ -173,11 +186,13 @@ export interface BiometricAuthPlugin extends WebPlugin {
|
|
|
173
186
|
*
|
|
174
187
|
* https://developer.apple.com/documentation/localauthentication/lapolicy/deviceownerauthenticationwithbiometrics
|
|
175
188
|
*
|
|
176
|
-
* Android
|
|
177
|
-
* `true`, the
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
189
|
+
* Some versions of Android impose a limit on the number of failed attempts.
|
|
190
|
+
* If `allowDeviceCredential` is `true`, when the limit is reached
|
|
191
|
+
* the user will then be presented with a device credential prompt.
|
|
192
|
+
* If `allowDeviceCredential` is `false`, when the limit is reached
|
|
193
|
+
* `authenticate()` will reject with a `BiometryErrorType` of `biometryLockout`,
|
|
194
|
+
* after which the user will have to wait the system-defined length of time
|
|
195
|
+
* before being allowed to authenticate again.
|
|
181
196
|
*
|
|
182
197
|
* @rejects {BiometryError}
|
|
183
198
|
*/
|
package/dist/esm/definitions.js
CHANGED
|
@@ -35,22 +35,23 @@ export var BiometryType;
|
|
|
35
35
|
*/
|
|
36
36
|
export var BiometryErrorType;
|
|
37
37
|
(function (BiometryErrorType) {
|
|
38
|
-
BiometryErrorType[
|
|
39
|
-
BiometryErrorType[
|
|
40
|
-
BiometryErrorType[
|
|
41
|
-
BiometryErrorType[
|
|
42
|
-
BiometryErrorType[
|
|
43
|
-
BiometryErrorType[
|
|
44
|
-
BiometryErrorType[
|
|
45
|
-
BiometryErrorType[
|
|
46
|
-
BiometryErrorType[
|
|
47
|
-
BiometryErrorType[
|
|
48
|
-
BiometryErrorType[
|
|
49
|
-
BiometryErrorType[
|
|
38
|
+
BiometryErrorType["none"] = "";
|
|
39
|
+
BiometryErrorType["appCancel"] = "appCancel";
|
|
40
|
+
BiometryErrorType["authenticationFailed"] = "authenticationFailed";
|
|
41
|
+
BiometryErrorType["invalidContext"] = "invalidContext";
|
|
42
|
+
BiometryErrorType["notInteractive"] = "notInteractive";
|
|
43
|
+
BiometryErrorType["passcodeNotSet"] = "passcodeNotSet";
|
|
44
|
+
BiometryErrorType["systemCancel"] = "systemCancel";
|
|
45
|
+
BiometryErrorType["userCancel"] = "userCancel";
|
|
46
|
+
BiometryErrorType["userFallback"] = "userFallback";
|
|
47
|
+
BiometryErrorType["biometryLockout"] = "biometryLockout";
|
|
48
|
+
BiometryErrorType["biometryNotAvailable"] = "biometryNotAvailable";
|
|
49
|
+
BiometryErrorType["biometryNotEnrolled"] = "biometryNotEnrolled";
|
|
50
|
+
BiometryErrorType["noDeviceCredential"] = "noDeviceCredential";
|
|
50
51
|
})(BiometryErrorType || (BiometryErrorType = {}));
|
|
51
52
|
export class BiometryError {
|
|
52
53
|
constructor(message, code) {
|
|
53
54
|
this.message = message;
|
|
54
|
-
this.code =
|
|
55
|
+
this.code = code;
|
|
55
56
|
}
|
|
56
57
|
}
|
package/dist/esm/info.json
CHANGED
package/dist/esm/native.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BiometricAuthBase } from './base';
|
|
2
|
-
import { BiometryType } from './definitions';
|
|
2
|
+
import { BiometryErrorType, BiometryType } from './definitions';
|
|
3
3
|
// eslint-disable-next-line import/prefer-default-export
|
|
4
4
|
export class BiometricAuthNative extends BiometricAuthBase {
|
|
5
5
|
constructor(capProxy) {
|
|
@@ -12,7 +12,8 @@ export class BiometricAuthNative extends BiometricAuthBase {
|
|
|
12
12
|
return Promise.resolve({
|
|
13
13
|
isAvailable: true,
|
|
14
14
|
biometryType: BiometryType.none,
|
|
15
|
-
reason: ''
|
|
15
|
+
reason: '',
|
|
16
|
+
code: BiometryErrorType.none
|
|
16
17
|
});
|
|
17
18
|
}
|
|
18
19
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars,@typescript-eslint/no-empty-function
|
package/dist/esm/web.js
CHANGED
|
@@ -11,7 +11,8 @@ export class BiometricAuthWeb extends BiometricAuthBase {
|
|
|
11
11
|
return Promise.resolve({
|
|
12
12
|
isAvailable: this.biometryType !== BiometryType.none,
|
|
13
13
|
biometryType: this.biometryType,
|
|
14
|
-
reason: ''
|
|
14
|
+
reason: '',
|
|
15
|
+
code: BiometryErrorType.none
|
|
15
16
|
});
|
|
16
17
|
}
|
|
17
18
|
async authenticate(options) {
|
package/dist/plugin.cjs.js
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
-
|
|
5
3
|
var core = require('@capacitor/core');
|
|
6
4
|
var app = require('@capacitor/app');
|
|
7
5
|
|
|
8
6
|
var info = {
|
|
9
7
|
name: "@aparajita/capacitor-biometric-auth",
|
|
10
|
-
version: "
|
|
8
|
+
version: "4.0.0"
|
|
11
9
|
};
|
|
12
10
|
|
|
13
11
|
exports.BiometryType = void 0;
|
|
@@ -47,23 +45,24 @@ exports.BiometryType = void 0;
|
|
|
47
45
|
*/
|
|
48
46
|
exports.BiometryErrorType = void 0;
|
|
49
47
|
(function (BiometryErrorType) {
|
|
50
|
-
BiometryErrorType[
|
|
51
|
-
BiometryErrorType[
|
|
52
|
-
BiometryErrorType[
|
|
53
|
-
BiometryErrorType[
|
|
54
|
-
BiometryErrorType[
|
|
55
|
-
BiometryErrorType[
|
|
56
|
-
BiometryErrorType[
|
|
57
|
-
BiometryErrorType[
|
|
58
|
-
BiometryErrorType[
|
|
59
|
-
BiometryErrorType[
|
|
60
|
-
BiometryErrorType[
|
|
61
|
-
BiometryErrorType[
|
|
48
|
+
BiometryErrorType["none"] = "";
|
|
49
|
+
BiometryErrorType["appCancel"] = "appCancel";
|
|
50
|
+
BiometryErrorType["authenticationFailed"] = "authenticationFailed";
|
|
51
|
+
BiometryErrorType["invalidContext"] = "invalidContext";
|
|
52
|
+
BiometryErrorType["notInteractive"] = "notInteractive";
|
|
53
|
+
BiometryErrorType["passcodeNotSet"] = "passcodeNotSet";
|
|
54
|
+
BiometryErrorType["systemCancel"] = "systemCancel";
|
|
55
|
+
BiometryErrorType["userCancel"] = "userCancel";
|
|
56
|
+
BiometryErrorType["userFallback"] = "userFallback";
|
|
57
|
+
BiometryErrorType["biometryLockout"] = "biometryLockout";
|
|
58
|
+
BiometryErrorType["biometryNotAvailable"] = "biometryNotAvailable";
|
|
59
|
+
BiometryErrorType["biometryNotEnrolled"] = "biometryNotEnrolled";
|
|
60
|
+
BiometryErrorType["noDeviceCredential"] = "noDeviceCredential";
|
|
62
61
|
})(exports.BiometryErrorType || (exports.BiometryErrorType = {}));
|
|
63
62
|
class BiometryError {
|
|
64
63
|
constructor(message, code) {
|
|
65
64
|
this.message = message;
|
|
66
|
-
this.code =
|
|
65
|
+
this.code = code;
|
|
67
66
|
}
|
|
68
67
|
}
|
|
69
68
|
|
|
@@ -115,7 +114,8 @@ class BiometricAuthWeb extends BiometricAuthBase {
|
|
|
115
114
|
return Promise.resolve({
|
|
116
115
|
isAvailable: this.biometryType !== exports.BiometryType.none,
|
|
117
116
|
biometryType: this.biometryType,
|
|
118
|
-
reason: ''
|
|
117
|
+
reason: '',
|
|
118
|
+
code: exports.BiometryErrorType.none
|
|
119
119
|
});
|
|
120
120
|
}
|
|
121
121
|
async authenticate(options) {
|
|
@@ -167,7 +167,8 @@ class BiometricAuthNative extends BiometricAuthBase {
|
|
|
167
167
|
return Promise.resolve({
|
|
168
168
|
isAvailable: true,
|
|
169
169
|
biometryType: exports.BiometryType.none,
|
|
170
|
-
reason: ''
|
|
170
|
+
reason: '',
|
|
171
|
+
code: exports.BiometryErrorType.none
|
|
171
172
|
});
|
|
172
173
|
}
|
|
173
174
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars,@typescript-eslint/no-empty-function
|
package/dist/plugin.js
CHANGED
|
@@ -3,7 +3,7 @@ var capacitorBiometricAuth = (function (exports, core, app) {
|
|
|
3
3
|
|
|
4
4
|
var info = {
|
|
5
5
|
name: "@aparajita/capacitor-biometric-auth",
|
|
6
|
-
version: "
|
|
6
|
+
version: "4.0.0"
|
|
7
7
|
};
|
|
8
8
|
|
|
9
9
|
exports.BiometryType = void 0;
|
|
@@ -43,23 +43,24 @@ var capacitorBiometricAuth = (function (exports, core, app) {
|
|
|
43
43
|
*/
|
|
44
44
|
exports.BiometryErrorType = void 0;
|
|
45
45
|
(function (BiometryErrorType) {
|
|
46
|
-
BiometryErrorType[
|
|
47
|
-
BiometryErrorType[
|
|
48
|
-
BiometryErrorType[
|
|
49
|
-
BiometryErrorType[
|
|
50
|
-
BiometryErrorType[
|
|
51
|
-
BiometryErrorType[
|
|
52
|
-
BiometryErrorType[
|
|
53
|
-
BiometryErrorType[
|
|
54
|
-
BiometryErrorType[
|
|
55
|
-
BiometryErrorType[
|
|
56
|
-
BiometryErrorType[
|
|
57
|
-
BiometryErrorType[
|
|
46
|
+
BiometryErrorType["none"] = "";
|
|
47
|
+
BiometryErrorType["appCancel"] = "appCancel";
|
|
48
|
+
BiometryErrorType["authenticationFailed"] = "authenticationFailed";
|
|
49
|
+
BiometryErrorType["invalidContext"] = "invalidContext";
|
|
50
|
+
BiometryErrorType["notInteractive"] = "notInteractive";
|
|
51
|
+
BiometryErrorType["passcodeNotSet"] = "passcodeNotSet";
|
|
52
|
+
BiometryErrorType["systemCancel"] = "systemCancel";
|
|
53
|
+
BiometryErrorType["userCancel"] = "userCancel";
|
|
54
|
+
BiometryErrorType["userFallback"] = "userFallback";
|
|
55
|
+
BiometryErrorType["biometryLockout"] = "biometryLockout";
|
|
56
|
+
BiometryErrorType["biometryNotAvailable"] = "biometryNotAvailable";
|
|
57
|
+
BiometryErrorType["biometryNotEnrolled"] = "biometryNotEnrolled";
|
|
58
|
+
BiometryErrorType["noDeviceCredential"] = "noDeviceCredential";
|
|
58
59
|
})(exports.BiometryErrorType || (exports.BiometryErrorType = {}));
|
|
59
60
|
class BiometryError {
|
|
60
61
|
constructor(message, code) {
|
|
61
62
|
this.message = message;
|
|
62
|
-
this.code =
|
|
63
|
+
this.code = code;
|
|
63
64
|
}
|
|
64
65
|
}
|
|
65
66
|
|
|
@@ -111,7 +112,8 @@ var capacitorBiometricAuth = (function (exports, core, app) {
|
|
|
111
112
|
return Promise.resolve({
|
|
112
113
|
isAvailable: this.biometryType !== exports.BiometryType.none,
|
|
113
114
|
biometryType: this.biometryType,
|
|
114
|
-
reason: ''
|
|
115
|
+
reason: '',
|
|
116
|
+
code: exports.BiometryErrorType.none
|
|
115
117
|
});
|
|
116
118
|
}
|
|
117
119
|
async authenticate(options) {
|
|
@@ -163,7 +165,8 @@ var capacitorBiometricAuth = (function (exports, core, app) {
|
|
|
163
165
|
return Promise.resolve({
|
|
164
166
|
isAvailable: true,
|
|
165
167
|
biometryType: exports.BiometryType.none,
|
|
166
|
-
reason: ''
|
|
168
|
+
reason: '',
|
|
169
|
+
code: exports.BiometryErrorType.none
|
|
167
170
|
});
|
|
168
171
|
}
|
|
169
172
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars,@typescript-eslint/no-empty-function
|
|
@@ -185,8 +188,6 @@ var capacitorBiometricAuth = (function (exports, core, app) {
|
|
|
185
188
|
exports.BiometryError = BiometryError;
|
|
186
189
|
exports.getBiometryName = getBiometryName;
|
|
187
190
|
|
|
188
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
189
|
-
|
|
190
191
|
return exports;
|
|
191
192
|
|
|
192
193
|
})({}, capacitorExports, app);
|
package/ios/Plugin/Plugin.swift
CHANGED
|
@@ -7,18 +7,18 @@ private let kMissingFaceIDUsageEntry = "The device supports Face ID, but NSFaceI
|
|
|
7
7
|
|
|
8
8
|
@objc(BiometricAuthNative)
|
|
9
9
|
public class BiometricAuthNative: CAPPlugin {
|
|
10
|
-
let biometryErrorCodeMap: [
|
|
11
|
-
.appCancel: "appCancel",
|
|
12
|
-
.authenticationFailed: "authenticationFailed",
|
|
13
|
-
.invalidContext: "invalidContext",
|
|
14
|
-
.notInteractive: "notInteractive",
|
|
15
|
-
.passcodeNotSet: "passcodeNotSet",
|
|
16
|
-
.systemCancel: "systemCancel",
|
|
17
|
-
.userCancel: "userCancel",
|
|
18
|
-
.userFallback: "userFallback",
|
|
19
|
-
.biometryLockout: "biometryLockout",
|
|
20
|
-
.biometryNotAvailable: "biometryNotAvailable",
|
|
21
|
-
.biometryNotEnrolled: "biometryNotEnrolled"
|
|
10
|
+
let biometryErrorCodeMap: [Int: String] = [
|
|
11
|
+
LAError.appCancel.rawValue: "appCancel",
|
|
12
|
+
LAError.authenticationFailed.rawValue: "authenticationFailed",
|
|
13
|
+
LAError.invalidContext.rawValue: "invalidContext",
|
|
14
|
+
LAError.notInteractive.rawValue: "notInteractive",
|
|
15
|
+
LAError.passcodeNotSet.rawValue: "passcodeNotSet",
|
|
16
|
+
LAError.systemCancel.rawValue: "systemCancel",
|
|
17
|
+
LAError.userCancel.rawValue: "userCancel",
|
|
18
|
+
LAError.userFallback.rawValue: "userFallback",
|
|
19
|
+
LAError.biometryLockout.rawValue: "biometryLockout",
|
|
20
|
+
LAError.biometryNotAvailable.rawValue: "biometryNotAvailable",
|
|
21
|
+
LAError.biometryNotEnrolled.rawValue: "biometryNotEnrolled",
|
|
22
22
|
]
|
|
23
23
|
|
|
24
24
|
var canEvaluatePolicy = true
|
|
@@ -31,6 +31,7 @@ public class BiometricAuthNative: CAPPlugin {
|
|
|
31
31
|
var error: NSError?
|
|
32
32
|
var available = context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error)
|
|
33
33
|
var reason = ""
|
|
34
|
+
var errorCode = ""
|
|
34
35
|
|
|
35
36
|
if available, context.biometryType == .faceID {
|
|
36
37
|
// The system may report that biometry is available, but if the type is Face ID
|
|
@@ -42,6 +43,7 @@ public class BiometricAuthNative: CAPPlugin {
|
|
|
42
43
|
available = false
|
|
43
44
|
canEvaluatePolicy = false
|
|
44
45
|
reason = kMissingFaceIDUsageEntry
|
|
46
|
+
errorCode = biometryErrorCodeMap[LAError.biometryNotAvailable.rawValue] ?? ""
|
|
45
47
|
}
|
|
46
48
|
} else if !available,
|
|
47
49
|
let error = error {
|
|
@@ -51,12 +53,15 @@ public class BiometricAuthNative: CAPPlugin {
|
|
|
51
53
|
if let failureReason = error.localizedFailureReason {
|
|
52
54
|
reason = "\(reason): \(failureReason)"
|
|
53
55
|
}
|
|
56
|
+
|
|
57
|
+
errorCode = biometryErrorCodeMap[error.code] ?? biometryErrorCodeMap[LAError.biometryNotAvailable.rawValue] ?? ""
|
|
54
58
|
}
|
|
55
59
|
|
|
56
60
|
call.resolve([
|
|
57
61
|
"isAvailable": available,
|
|
58
62
|
"biometryType": context.biometryType.rawValue,
|
|
59
|
-
"reason": reason
|
|
63
|
+
"reason": reason,
|
|
64
|
+
"code": errorCode
|
|
60
65
|
])
|
|
61
66
|
}
|
|
62
67
|
|
|
@@ -72,7 +77,7 @@ public class BiometricAuthNative: CAPPlugin {
|
|
|
72
77
|
guard canEvaluatePolicy else {
|
|
73
78
|
call.reject(
|
|
74
79
|
kMissingFaceIDUsageEntry,
|
|
75
|
-
biometryErrorCodeMap[.biometryNotAvailable]
|
|
80
|
+
biometryErrorCodeMap[LAError.biometryNotAvailable.rawValue]
|
|
76
81
|
)
|
|
77
82
|
|
|
78
83
|
return
|
|
@@ -111,10 +116,10 @@ public class BiometricAuthNative: CAPPlugin {
|
|
|
111
116
|
call.resolve()
|
|
112
117
|
} else {
|
|
113
118
|
if let policyError = error as? LAError {
|
|
114
|
-
let code = self.biometryErrorCodeMap[policyError.code]
|
|
119
|
+
let code = self.biometryErrorCodeMap[policyError.code.rawValue]
|
|
115
120
|
call.reject(policyError.localizedDescription, code)
|
|
116
121
|
} else {
|
|
117
|
-
call.reject("An unknown error occurred.", self.biometryErrorCodeMap[.authenticationFailed])
|
|
122
|
+
call.reject("An unknown error occurred.", self.biometryErrorCodeMap[LAError.authenticationFailed.rawValue])
|
|
118
123
|
}
|
|
119
124
|
}
|
|
120
125
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aparajita/capacitor-biometric-auth",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "Provides access to the native biometric auth APIs for Capacitor apps",
|
|
5
5
|
"author": "Aparajita Fishman",
|
|
6
6
|
"license": "MIT",
|
|
@@ -56,37 +56,37 @@
|
|
|
56
56
|
"@aparajita/eslint-config-base": "^1.1.5",
|
|
57
57
|
"@aparajita/prettier-config": "^1.0.0",
|
|
58
58
|
"@aparajita/swiftly": "^1.0.4",
|
|
59
|
-
"@capacitor/cli": "^4.
|
|
60
|
-
"@commitlint/cli": "^17.
|
|
61
|
-
"@commitlint/config-conventional": "^17.
|
|
59
|
+
"@capacitor/cli": "^4.7.2",
|
|
60
|
+
"@commitlint/cli": "^17.5.1",
|
|
61
|
+
"@commitlint/config-conventional": "^17.4.4",
|
|
62
62
|
"@ionic/swiftlint-config": "^1.1.2",
|
|
63
|
-
"@rollup/plugin-json": "^
|
|
64
|
-
"@types/node": "^18.
|
|
65
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
66
|
-
"@typescript-eslint/parser": "^5.
|
|
67
|
-
"commit-and-tag-version": "^
|
|
68
|
-
"eslint": "^8.
|
|
69
|
-
"eslint-config-prettier": "^8.
|
|
63
|
+
"@rollup/plugin-json": "^6.0.0",
|
|
64
|
+
"@types/node": "^18.15.11",
|
|
65
|
+
"@typescript-eslint/eslint-plugin": "^5.57.0",
|
|
66
|
+
"@typescript-eslint/parser": "^5.57.0",
|
|
67
|
+
"commit-and-tag-version": "^11.2.0",
|
|
68
|
+
"eslint": "^8.37.0",
|
|
69
|
+
"eslint-config-prettier": "^8.8.0",
|
|
70
70
|
"eslint-config-standard": "^17.0.0",
|
|
71
|
-
"eslint-import-resolver-typescript": "^3.4
|
|
72
|
-
"eslint-plugin-import": "^2.
|
|
73
|
-
"eslint-plugin-n": "^15.
|
|
71
|
+
"eslint-import-resolver-typescript": "^3.5.4",
|
|
72
|
+
"eslint-plugin-import": "^2.27.5",
|
|
73
|
+
"eslint-plugin-n": "^15.7.0",
|
|
74
74
|
"eslint-plugin-prettier": "^4.2.1",
|
|
75
|
-
"eslint-plugin-promise": "^6.
|
|
76
|
-
"husky": "^8.0.
|
|
77
|
-
"nodemon": "^2.0.
|
|
78
|
-
"prettier": "^2.7
|
|
79
|
-
"prettier-plugin-java": "^1.
|
|
80
|
-
"rimraf": "^
|
|
81
|
-
"rollup": "^
|
|
75
|
+
"eslint-plugin-promise": "^6.1.1",
|
|
76
|
+
"husky": "^8.0.3",
|
|
77
|
+
"nodemon": "^2.0.22",
|
|
78
|
+
"prettier": "^2.8.7",
|
|
79
|
+
"prettier-plugin-java": "^2.1.0",
|
|
80
|
+
"rimraf": "^4.4.1",
|
|
81
|
+
"rollup": "^3.20.2",
|
|
82
82
|
"swiftlint": "^1.0.1",
|
|
83
83
|
"typescript": "~4.7.4"
|
|
84
84
|
},
|
|
85
85
|
"dependencies": {
|
|
86
|
-
"@capacitor/android": "^4.
|
|
87
|
-
"@capacitor/app": "^4.
|
|
88
|
-
"@capacitor/core": "^4.
|
|
89
|
-
"@capacitor/ios": "^4.
|
|
86
|
+
"@capacitor/android": "^4.7.2",
|
|
87
|
+
"@capacitor/app": "^4.1.1",
|
|
88
|
+
"@capacitor/core": "^4.7.2",
|
|
89
|
+
"@capacitor/ios": "^4.7.2"
|
|
90
90
|
},
|
|
91
91
|
"scripts": {
|
|
92
92
|
"clean": "rimraf dist",
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
-
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
3
|
-
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
4
|
-
xmlns:tools="http://schemas.android.com/tools"
|
|
5
|
-
android:layout_width="match_parent"
|
|
6
|
-
android:layout_height="match_parent"
|
|
7
|
-
tools:context="com.getcapacitor.BridgeActivity"
|
|
8
|
-
>
|
|
9
|
-
|
|
10
|
-
<WebView
|
|
11
|
-
android:id="@+id/webview"
|
|
12
|
-
android:layout_width="fill_parent"
|
|
13
|
-
android:layout_height="fill_parent" />
|
|
14
|
-
|
|
15
|
-
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
-
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
|
|
3
|
-
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
4
|
-
xmlns:tools="http://schemas.android.com/tools"
|
|
5
|
-
android:id="@+id/nav_graph"
|
|
6
|
-
app:startDestination="@id/FirstFragment">
|
|
7
|
-
|
|
8
|
-
<fragment
|
|
9
|
-
android:id="@+id/FirstFragment"
|
|
10
|
-
android:name="com.epicshaggy.biometric.FirstFragment"
|
|
11
|
-
android:label="@string/first_fragment_label"
|
|
12
|
-
tools:layout="@layout/fragment_first">
|
|
13
|
-
|
|
14
|
-
<action
|
|
15
|
-
android:id="@+id/action_FirstFragment_to_SecondFragment"
|
|
16
|
-
app:destination="@id/SecondFragment" />
|
|
17
|
-
</fragment>
|
|
18
|
-
<fragment
|
|
19
|
-
android:id="@+id/SecondFragment"
|
|
20
|
-
android:name="com.epicshaggy.biometric.SecondFragment"
|
|
21
|
-
android:label="@string/second_fragment_label"
|
|
22
|
-
tools:layout="@layout/fragment_second">
|
|
23
|
-
|
|
24
|
-
<action
|
|
25
|
-
android:id="@+id/action_SecondFragment_to_FirstFragment"
|
|
26
|
-
app:destination="@id/FirstFragment" />
|
|
27
|
-
</fragment>
|
|
28
|
-
</navigation>
|