@aparajita/capacitor-biometric-auth 5.2.0 โ 6.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 +92 -16
- package/android/src/main/java/com/aparajita/capacitor/biometricauth/BiometricAuthNative.java +35 -21
- package/dist/esm/base.d.ts +2 -1
- package/dist/esm/base.js +19 -1
- package/dist/esm/definitions.d.ts +17 -18
- package/dist/esm/definitions.js +6 -2
- package/dist/esm/native.d.ts +1 -1
- package/dist/esm/native.js +23 -6
- package/dist/esm/web.d.ts +1 -1
- package/dist/esm/web.js +16 -12
- package/dist/plugin.cjs.js +62 -20
- package/dist/plugin.js +62 -20
- package/ios/Plugin/Plugin.m +1 -1
- package/ios/Plugin/Plugin.swift +34 -13
- package/package.json +19 -19
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ This plugin for [Capacitor 5](https://capacitorjs.com) provides access to native
|
|
|
6
6
|
|
|
7
7
|
๐ **NOTE:** This plugin only works with Capacitor 5. If you are upgrading from the Capacitor 2 version, note that the plugin name has changed to `BiometricAuth`.
|
|
8
8
|
|
|
9
|
-
๐ **BREAKING CHANGE:** If you are upgrading from a version prior to
|
|
9
|
+
๐ **BREAKING CHANGE:** If you are upgrading from a version prior to 6.0.0, please note that [`authenticate()`](#authenticate) now throws an instance of `BiometryError`, and `BiometryError.code` is now typed as [`BiometryErrorType`](#biometryerrortype).
|
|
10
10
|
|
|
11
11
|
## Demos
|
|
12
12
|
|
|
@@ -24,29 +24,103 @@ pnpm add @aparajita/capacitor-biometric-auth
|
|
|
24
24
|
|
|
25
25
|
Not using [pnpm](https://pnpm.js.org/)? You owe it to yourself to give it a try. Itโs faster, better with monorepos, and uses _way, way_ less disk space than the alternatives.
|
|
26
26
|
|
|
27
|
+
### iOS
|
|
28
|
+
|
|
29
|
+
๐ **IMPORTANT!!** In order to use Face ID, you must add the `NSFaceIDUsageDescription` key to your `Info.plist` file. This is a string that describes why your app needs access to Face ID. If you donโt add this key, the system wonโt allow your app to use Face ID.
|
|
30
|
+
|
|
31
|
+
1. In Xcode, open your appโs `Info.plist` file.
|
|
32
|
+
2. Hover your mouse over one of the existing keys, and click the `+` button that appears.
|
|
33
|
+
3. In the popup that appears, type `Privacy - Face ID Usage Description` and press Enter.
|
|
34
|
+
4. In the Value column, enter a string that describes why your app needs access to Face ID.
|
|
35
|
+
5. Save your changes.
|
|
36
|
+
|
|
27
37
|
## Usage
|
|
28
38
|
|
|
29
39
|
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
40
|
|
|
31
|
-
|
|
41
|
+
๐ **NOTE:** Your Android app must use a base theme named "AppTheme".
|
|
32
42
|
|
|
33
43
|
### Checking availability
|
|
34
44
|
|
|
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
|
|
45
|
+
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 the following:
|
|
36
46
|
|
|
37
|
-
|
|
47
|
+
- `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` and `code` will tell you why.
|
|
48
|
+
|
|
49
|
+
- `biometryTypes` may contain more than one type of biometry. This occurs on Android devices that support multiple types of biometry. In such cases the `biometryType` will indicate the primary (most secure) type of biometry, and the `biometryTypes` array will contain all of the biometry types supported by the device. Note that Android only guarantees that one of the types is actually available.
|
|
50
|
+
|
|
51
|
+
Because the availability of biometry can change while your app is in the background, itโs important to check availability when your app resumes. By calling [`addResumeListener()`](#addresumelistener) you can register a callback that is passed a [`CheckBiometryResult`](#checkbiometryresult) when your app resumes.
|
|
52
|
+
|
|
53
|
+
#### Example
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { CheckBiometryResult } from './definitions'
|
|
57
|
+
|
|
58
|
+
let appListener: PluginListenerHandle
|
|
59
|
+
|
|
60
|
+
function updateBiometryInfo(info: CheckBiometryResult): void {
|
|
61
|
+
if (info.isAvailable) {
|
|
62
|
+
// Biometry is available, info.biometryType will tell you the primary type.
|
|
63
|
+
} else {
|
|
64
|
+
// Biometry is not available, info.reason and info.code will tell you why.
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function onComponentMounted(): Promise<void> {
|
|
69
|
+
updateBiometryInfo(await BiometricAuth.checkBiometry())
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
appListener = await BiometricAuth.addResumeListener(updateBiometryInfo)
|
|
73
|
+
} catch (error) {
|
|
74
|
+
if (error instanceof Error) {
|
|
75
|
+
console.error(error.message)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function onComponentUnmounted(): Promise<void> {
|
|
81
|
+
await appListener?.remove()
|
|
82
|
+
}
|
|
83
|
+
```
|
|
38
84
|
|
|
39
85
|
### Authenticating
|
|
40
86
|
|
|
41
|
-
|
|
87
|
+
To initiate biometric authentication call [`authenticate()`](#authenticate). `authenticate` takes an [`AuthenticateOptions`](#authenticateoptions) object which you will want to use in order to control the behavior and appearance of the biometric prompt.
|
|
42
88
|
|
|
43
|
-
If authentication succeeds, the Promise resolves. If authentication fails, the Promise is rejected with
|
|
89
|
+
If authentication succeeds, the Promise resolves. If authentication fails, the Promise is rejected with an instance of [`BiometryError`](#biometryerror), which has two properties:
|
|
44
90
|
|
|
45
91
|
| Property | Type | Description |
|
|
46
92
|
| :------- | :------------------------------------------------------------------------------------------------------ | :------------------------------------------------ |
|
|
47
93
|
| message | string | A description of the error suitable for debugging |
|
|
48
94
|
| code | [BiometryErrorType](https://github.com/aparajita/capacitor-biometric-auth/blob/main/src/definitions.ts) | What caused the error |
|
|
49
95
|
|
|
96
|
+
#### Example
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
import { BiometryError, BiometryErrorType } from './definitions'
|
|
100
|
+
|
|
101
|
+
async function authenticate(): Promise<void> {
|
|
102
|
+
try {
|
|
103
|
+
await BiometricAuth.authenticate({
|
|
104
|
+
reason: 'Please authenticate',
|
|
105
|
+
cancelTitle: 'Cancel',
|
|
106
|
+
allowDeviceCredential: true,
|
|
107
|
+
iosFallbackTitle: 'Use passcode',
|
|
108
|
+
androidTitle: 'Biometric login',
|
|
109
|
+
androidSubtitle: 'Log in using biometric authentication',
|
|
110
|
+
androidConfirmationRequired: false,
|
|
111
|
+
})
|
|
112
|
+
} catch (error) {
|
|
113
|
+
// error is always an instance of BiometryError.
|
|
114
|
+
if (error instanceof BiometryError) {
|
|
115
|
+
if (error.code !== BiometryErrorType.userCancel) {
|
|
116
|
+
// Display the error.
|
|
117
|
+
await showAlert(error.message)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
50
124
|
## Biometry support
|
|
51
125
|
|
|
52
126
|
### web
|
|
@@ -59,7 +133,7 @@ On iOS, Touch ID and Face ID are supported.
|
|
|
59
133
|
|
|
60
134
|
### Android
|
|
61
135
|
|
|
62
|
-
On Android, fingerprint, face, and iris authentication are supported. Note that if a device supports more than one type of biometry, the plugin will only present the primary type, which is determined by the system.
|
|
136
|
+
On Android, fingerprint, face, and iris authentication are supported. Note that if a device supports more than one type of biometry, the plugin will only present the primary (most secure) type, which is determined by the system.
|
|
63
137
|
|
|
64
138
|
## API
|
|
65
139
|
|
|
@@ -77,6 +151,8 @@ On Android, fingerprint, face, and iris authentication are supported. Note that
|
|
|
77
151
|
<docgen-api>
|
|
78
152
|
<!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
|
|
79
153
|
|
|
154
|
+
This is the public interface of the plugin.
|
|
155
|
+
|
|
80
156
|
### checkBiometry()
|
|
81
157
|
|
|
82
158
|
```typescript
|
|
@@ -123,7 +199,7 @@ Prompt the user for authentication. If authorization fails for any reason, the p
|
|
|
123
199
|
addResumeListener(listener: ResumeListener) => Promise<PluginListenerHandle>
|
|
124
200
|
```
|
|
125
201
|
|
|
126
|
-
Register a function that will be called when the app resumes. The function will be passed the result of `checkBiometry()
|
|
202
|
+
Register a function that will be called when the app resumes. The function will be passed the result of `checkBiometry()`.<br><br>๐ **NOTE:** checkBiometry() must be called at least once before calling this method.
|
|
127
203
|
|
|
128
204
|
| Param | Type |
|
|
129
205
|
| :------- | :------------------------------------------- |
|
|
@@ -137,13 +213,13 @@ Register a function that will be called when the app resumes. The function will
|
|
|
137
213
|
|
|
138
214
|
#### CheckBiometryResult
|
|
139
215
|
|
|
140
|
-
| Prop | Type | Description
|
|
141
|
-
| :------------ | :------------------------------------------------- |
|
|
142
|
-
| isAvailable | boolean | True if the device has biometric authentication capability and the current user has enrolled in some form of biometry.
|
|
143
|
-
| biometryType | <a href="#biometrytype">BiometryType</a> | The primary type of biometry available on the device. If the device supports both fingerprint and face authentication, this will be <a href="#biometrytype">`BiometryType.touchId`</a>.
|
|
144
|
-
| biometryTypes | BiometryType[] | All of the biometry types supported by the device (currently only Android devices support multiple biometry types). If no biometry is available, this will be an empty array. If multiple types are supported, Android only guarantees that one of them is actually available.
|
|
145
|
-
| 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.
|
|
146
|
-
| 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.
|
|
216
|
+
| Prop | Type | Description |
|
|
217
|
+
| :------------ | :------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
218
|
+
| isAvailable | boolean | True if the device has biometric authentication capability and the current user has enrolled in some form of biometry. |
|
|
219
|
+
| biometryType | <a href="#biometrytype">BiometryType</a> | The primary type of biometry available on the device. If the device supports both fingerprint and face authentication, this will be <a href="#biometrytype">`BiometryType.touchId`</a>. |
|
|
220
|
+
| biometryTypes | BiometryType[] | All of the biometry types supported by the device (currently only Android devices support multiple biometry types). If no biometry is available, this will be an empty array. If multiple types are supported, Android only guarantees that one of them is actually available. |
|
|
221
|
+
| 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. |
|
|
222
|
+
| 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. |
|
|
147
223
|
|
|
148
224
|
#### AuthenticateOptions
|
|
149
225
|
|
|
@@ -155,7 +231,7 @@ Register a function that will be called when the app resumes. The function will
|
|
|
155
231
|
| iosFallbackTitle | string | The system presents a fallback button when biometric authentication fails โ for example, because the system doesnโt recognize the presented finger, or after several failed attempts to recognize the userโs face.<br><br>If `allowDeviceCredential` is false, tapping this button dismisses the authentication dialog and returns the error code userFallback. If undefined, the localized system default title is used. Passing an empty string hides the fallback button completely.<br><br>If `allowDeviceCredential` is true and this is undefined, the localized system default title is used. |
|
|
156
232
|
| androidTitle | string | Title for the Android dialog. If not supplied, the system default is used. |
|
|
157
233
|
| androidSubtitle | string | Subtitle for the Android dialog. If not supplied, the system default is used. |
|
|
158
|
-
| androidConfirmationRequired | boolean | For information on this setting, see
|
|
234
|
+
| androidConfirmationRequired | boolean | If not set, defaults to true.<br><br>For information on this setting, see https://developer.android.com/reference/android/hardware/biometrics/BiometricPrompt.Builder#setConfirmationRequired(boolean). |
|
|
159
235
|
|
|
160
236
|
#### PluginListenerHandle
|
|
161
237
|
|
package/android/src/main/java/com/aparajita/capacitor/biometricauth/BiometricAuthNative.java
CHANGED
|
@@ -96,6 +96,13 @@ public class BiometricAuthNative extends Plugin {
|
|
|
96
96
|
*/
|
|
97
97
|
@PluginMethod
|
|
98
98
|
public void checkBiometry(PluginCall call) {
|
|
99
|
+
call.resolve(checkDeviceBiometry());
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Check the device's availability and type of biometric authentication.
|
|
104
|
+
*/
|
|
105
|
+
private JSObject checkDeviceBiometry() {
|
|
99
106
|
BiometricManager manager = BiometricManager.from(getContext());
|
|
100
107
|
int biometryResult;
|
|
101
108
|
|
|
@@ -106,14 +113,14 @@ public class BiometricAuthNative extends Plugin {
|
|
|
106
113
|
biometryResult = manager.canAuthenticate();
|
|
107
114
|
}
|
|
108
115
|
|
|
109
|
-
JSObject
|
|
110
|
-
|
|
116
|
+
JSObject result = new JSObject();
|
|
117
|
+
result.put(
|
|
111
118
|
"isAvailable",
|
|
112
119
|
biometryResult == BiometricManager.BIOMETRIC_SUCCESS
|
|
113
120
|
);
|
|
114
121
|
|
|
115
122
|
biometryTypes = getDeviceBiometryTypes();
|
|
116
|
-
|
|
123
|
+
result.put("biometryType", biometryTypes.get(0).getType());
|
|
117
124
|
|
|
118
125
|
JSArray returnTypes = new JSArray();
|
|
119
126
|
|
|
@@ -121,7 +128,7 @@ public class BiometricAuthNative extends Plugin {
|
|
|
121
128
|
returnTypes.put(type.getType());
|
|
122
129
|
}
|
|
123
130
|
|
|
124
|
-
|
|
131
|
+
result.put("biometryTypes", returnTypes);
|
|
125
132
|
|
|
126
133
|
String reason = "";
|
|
127
134
|
|
|
@@ -156,13 +163,13 @@ public class BiometricAuthNative extends Plugin {
|
|
|
156
163
|
errorCode = "biometryNotAvailable";
|
|
157
164
|
}
|
|
158
165
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
166
|
+
result.put("reason", reason);
|
|
167
|
+
result.put("code", errorCode);
|
|
168
|
+
return result;
|
|
162
169
|
}
|
|
163
170
|
|
|
164
171
|
private ArrayList<BiometryType> getDeviceBiometryTypes() {
|
|
165
|
-
ArrayList<BiometryType> types = new ArrayList
|
|
172
|
+
ArrayList<BiometryType> types = new ArrayList<>();
|
|
166
173
|
PackageManager manager = getContext().getPackageManager();
|
|
167
174
|
|
|
168
175
|
if (manager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
|
|
@@ -188,7 +195,18 @@ public class BiometricAuthNative extends Plugin {
|
|
|
188
195
|
* Prompt the user for biometric authentication.
|
|
189
196
|
*/
|
|
190
197
|
@PluginMethod
|
|
191
|
-
public void
|
|
198
|
+
public void internalAuthenticate(final PluginCall call) {
|
|
199
|
+
// Make sure biometry is available
|
|
200
|
+
JSObject checkResult = checkDeviceBiometry();
|
|
201
|
+
|
|
202
|
+
if (Boolean.FALSE.equals(checkResult.getBoolean("isAvailable", false))) {
|
|
203
|
+
call.reject(
|
|
204
|
+
checkResult.getString("reason", ""),
|
|
205
|
+
checkResult.getString("code", "")
|
|
206
|
+
);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
192
210
|
// The result of an intent is supposed to have the package name as a prefix
|
|
193
211
|
RESULT_EXTRA_PREFIX = getContext().getPackageName() + ".";
|
|
194
212
|
|
|
@@ -279,23 +297,19 @@ public class BiometricAuthNative extends Plugin {
|
|
|
279
297
|
);
|
|
280
298
|
|
|
281
299
|
switch (resultType) {
|
|
282
|
-
case SUCCESS
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
case ERROR:
|
|
290
|
-
// The user cancelled, the system cancelled, or some error occurred.
|
|
291
|
-
// If the user cancelled, errorMessage is the text of the "negative" button,
|
|
292
|
-
// which is not especially descriptive.
|
|
300
|
+
case SUCCESS -> call.resolve();
|
|
301
|
+
// Biometry was successfully presented but was not recognized
|
|
302
|
+
case FAILURE -> call.reject(errorMessage, BIOMETRIC_FAILURE);
|
|
303
|
+
// The user cancelled, the system cancelled, or some error occurred.
|
|
304
|
+
// If the user cancelled, errorMessage is the text of the "negative" button,
|
|
305
|
+
// which is not especially descriptive.
|
|
306
|
+
case ERROR -> {
|
|
293
307
|
if (errorCode == BiometricPrompt.ERROR_NEGATIVE_BUTTON) {
|
|
294
308
|
errorMessage = "Cancel button was pressed";
|
|
295
309
|
}
|
|
296
310
|
|
|
297
311
|
call.reject(errorMessage, biometryErrorCodeMap.get(errorCode));
|
|
298
|
-
|
|
312
|
+
}
|
|
299
313
|
}
|
|
300
314
|
}
|
|
301
315
|
|
package/dist/esm/base.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { AuthenticateOptions, BiometricAuthPlugin, CheckBiometryResult, Res
|
|
|
4
4
|
export declare abstract class BiometricAuthBase extends WebPlugin implements BiometricAuthPlugin {
|
|
5
5
|
abstract setBiometryType(type: BiometryType | string | undefined): Promise<void>;
|
|
6
6
|
abstract checkBiometry(): Promise<CheckBiometryResult>;
|
|
7
|
-
|
|
7
|
+
authenticate(options?: AuthenticateOptions): Promise<void>;
|
|
8
|
+
protected abstract internalAuthenticate(options?: AuthenticateOptions): Promise<void>;
|
|
8
9
|
addResumeListener(listener: ResumeListener): Promise<PluginListenerHandle> & PluginListenerHandle;
|
|
9
10
|
}
|
package/dist/esm/base.js
CHANGED
|
@@ -1,7 +1,25 @@
|
|
|
1
1
|
import { App } from '@capacitor/app';
|
|
2
|
-
import { WebPlugin } from '@capacitor/core';
|
|
2
|
+
import { CapacitorException, WebPlugin } from '@capacitor/core';
|
|
3
|
+
import { BiometryError } from './definitions';
|
|
3
4
|
// eslint-disable-next-line import/prefer-default-export
|
|
4
5
|
export class BiometricAuthBase extends WebPlugin {
|
|
6
|
+
async authenticate(options) {
|
|
7
|
+
try {
|
|
8
|
+
await this.internalAuthenticate(options);
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
// error will be an instance of CapacitorException on native platforms,
|
|
12
|
+
// an instance of BiometryError on the web.
|
|
13
|
+
if (error instanceof CapacitorException) {
|
|
14
|
+
throw new BiometryError(error.message,
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- error.data values are typed as any
|
|
16
|
+
error.data.code);
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
throw error;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
5
23
|
addResumeListener(listener) {
|
|
6
24
|
return App.addListener('appStateChange', ({ isActive }) => {
|
|
7
25
|
if (isActive) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PluginListenerHandle,
|
|
1
|
+
import type { PluginListenerHandle, WebPlugin } from '@capacitor/core';
|
|
2
2
|
export declare enum BiometryType {
|
|
3
3
|
/**
|
|
4
4
|
* No biometry is available
|
|
@@ -101,17 +101,15 @@ export interface AuthenticateOptions {
|
|
|
101
101
|
*/
|
|
102
102
|
androidSubtitle?: string;
|
|
103
103
|
/**
|
|
104
|
-
* For information on this setting, see:
|
|
105
|
-
*
|
|
106
|
-
* https://developer.android.com/reference/android/hardware/biometrics/BiometricPrompt.Builder#setConfirmationRequired(boolean)
|
|
107
|
-
*
|
|
108
104
|
* If not set, defaults to true.
|
|
105
|
+
*
|
|
106
|
+
* For information on this setting, see https://developer.android.com/reference/android/hardware/biometrics/BiometricPrompt.Builder#setConfirmationRequired(boolean).
|
|
109
107
|
*/
|
|
110
108
|
androidConfirmationRequired?: boolean;
|
|
111
109
|
}
|
|
112
110
|
/**
|
|
113
|
-
* If the `authenticate()` method throws an exception, the
|
|
114
|
-
* contains a .code property which will contain one of these strings,
|
|
111
|
+
* If the `authenticate()` method throws an exception, the `BiometryError`
|
|
112
|
+
* instance contains a .code property which will contain one of these strings,
|
|
115
113
|
* indicating what the error was.
|
|
116
114
|
*
|
|
117
115
|
* See https://developer.apple.com/documentation/localauthentication/laerror
|
|
@@ -132,12 +130,12 @@ export declare enum BiometryErrorType {
|
|
|
132
130
|
biometryNotEnrolled = "biometryNotEnrolled",
|
|
133
131
|
noDeviceCredential = "noDeviceCredential"
|
|
134
132
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
export declare class BiometryError
|
|
133
|
+
/**
|
|
134
|
+
* `authenticate()` throws instances of this class.
|
|
135
|
+
*/
|
|
136
|
+
export declare class BiometryError {
|
|
139
137
|
message: string;
|
|
140
|
-
code:
|
|
138
|
+
code: BiometryErrorType;
|
|
141
139
|
constructor(message: string, code: BiometryErrorType);
|
|
142
140
|
}
|
|
143
141
|
export interface CheckBiometryResult {
|
|
@@ -169,12 +167,7 @@ export interface CheckBiometryResult {
|
|
|
169
167
|
* If biometry is not available, the error code will be returned here.
|
|
170
168
|
* Otherwise it's an empty string. The error code will be one of the
|
|
171
169
|
* `BiometryErrorType` enum values, and is consistent across
|
|
172
|
-
* platforms.
|
|
173
|
-
* independent way, for example:
|
|
174
|
-
*
|
|
175
|
-
* if (result.code === BiometryErrorType.biometryNotEnrolled) {
|
|
176
|
-
* ...
|
|
177
|
-
* }
|
|
170
|
+
* platforms.
|
|
178
171
|
*/
|
|
179
172
|
code: BiometryErrorType;
|
|
180
173
|
}
|
|
@@ -182,6 +175,9 @@ export interface CheckBiometryResult {
|
|
|
182
175
|
* The signature of the callback passed to `addResumeListener()`.
|
|
183
176
|
*/
|
|
184
177
|
export type ResumeListener = (info: CheckBiometryResult) => void;
|
|
178
|
+
/**
|
|
179
|
+
* This is the public interface of the plugin.
|
|
180
|
+
*/
|
|
185
181
|
export interface BiometricAuthPlugin extends WebPlugin {
|
|
186
182
|
/**
|
|
187
183
|
* Check to see what biometry type (if any) is available.
|
|
@@ -218,6 +214,9 @@ export interface BiometricAuthPlugin extends WebPlugin {
|
|
|
218
214
|
/**
|
|
219
215
|
* Register a function that will be called when the app resumes.
|
|
220
216
|
* The function will be passed the result of `checkBiometry()`.
|
|
217
|
+
*
|
|
218
|
+
* ๐ **NOTE:** checkBiometry() must be called at least once
|
|
219
|
+
* before calling this method.
|
|
221
220
|
*/
|
|
222
221
|
addResumeListener: (listener: ResumeListener) => Promise<PluginListenerHandle>;
|
|
223
222
|
}
|
package/dist/esm/definitions.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// noinspection JSUnusedGlobalSymbols
|
|
1
2
|
export var BiometryType;
|
|
2
3
|
(function (BiometryType) {
|
|
3
4
|
/**
|
|
@@ -26,8 +27,8 @@ export var BiometryType;
|
|
|
26
27
|
BiometryType[BiometryType["irisAuthentication"] = 5] = "irisAuthentication";
|
|
27
28
|
})(BiometryType || (BiometryType = {}));
|
|
28
29
|
/**
|
|
29
|
-
* If the `authenticate()` method throws an exception, the
|
|
30
|
-
* contains a .code property which will contain one of these strings,
|
|
30
|
+
* If the `authenticate()` method throws an exception, the `BiometryError`
|
|
31
|
+
* instance contains a .code property which will contain one of these strings,
|
|
31
32
|
* indicating what the error was.
|
|
32
33
|
*
|
|
33
34
|
* See https://developer.apple.com/documentation/localauthentication/laerror
|
|
@@ -49,6 +50,9 @@ export var BiometryErrorType;
|
|
|
49
50
|
BiometryErrorType["biometryNotEnrolled"] = "biometryNotEnrolled";
|
|
50
51
|
BiometryErrorType["noDeviceCredential"] = "noDeviceCredential";
|
|
51
52
|
})(BiometryErrorType || (BiometryErrorType = {}));
|
|
53
|
+
/**
|
|
54
|
+
* `authenticate()` throws instances of this class.
|
|
55
|
+
*/
|
|
52
56
|
export class BiometryError {
|
|
53
57
|
constructor(message, code) {
|
|
54
58
|
this.message = message;
|
package/dist/esm/native.d.ts
CHANGED
|
@@ -4,6 +4,6 @@ import { BiometryType } from './definitions';
|
|
|
4
4
|
export declare class BiometricAuthNative extends BiometricAuthBase {
|
|
5
5
|
constructor(capProxy: BiometricAuthPlugin);
|
|
6
6
|
checkBiometry(): Promise<CheckBiometryResult>;
|
|
7
|
-
|
|
7
|
+
internalAuthenticate(options?: AuthenticateOptions): Promise<void>;
|
|
8
8
|
setBiometryType(type: BiometryType | string | undefined): Promise<void>;
|
|
9
9
|
}
|
package/dist/esm/native.js
CHANGED
|
@@ -4,11 +4,24 @@ import { BiometryErrorType, BiometryType } from './definitions';
|
|
|
4
4
|
export class BiometricAuthNative extends BiometricAuthBase {
|
|
5
5
|
constructor(capProxy) {
|
|
6
6
|
super();
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
/*
|
|
8
|
+
In order to call native methods and maintain the ability to
|
|
9
|
+
call pure Javascript methods as well, we have to bind the native methods
|
|
10
|
+
to the proxy.
|
|
11
|
+
|
|
12
|
+
capProxy is a proxy of an instance of this class, so it is safe
|
|
13
|
+
to cast it to this class.
|
|
14
|
+
*/
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
16
|
+
const proxy = capProxy;
|
|
17
|
+
/* eslint-disable @typescript-eslint/unbound-method */
|
|
18
|
+
this.checkBiometry = proxy.checkBiometry;
|
|
19
|
+
this.internalAuthenticate = proxy.internalAuthenticate;
|
|
20
|
+
/* eslint-enable */
|
|
9
21
|
}
|
|
22
|
+
// @native
|
|
10
23
|
async checkBiometry() {
|
|
11
|
-
// Never used, satisfy the compiler
|
|
24
|
+
// Never used, but we have to satisfy the compiler.
|
|
12
25
|
return Promise.resolve({
|
|
13
26
|
isAvailable: true,
|
|
14
27
|
biometryType: BiometryType.none,
|
|
@@ -17,12 +30,16 @@ export class BiometricAuthNative extends BiometricAuthBase {
|
|
|
17
30
|
code: BiometryErrorType.none,
|
|
18
31
|
});
|
|
19
32
|
}
|
|
20
|
-
//
|
|
21
|
-
|
|
33
|
+
// @native
|
|
34
|
+
// On native platforms, this will present the native authentication UI.
|
|
35
|
+
async internalAuthenticate(
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
37
|
+
options) { }
|
|
38
|
+
// Web only, used for simulating biometric authentication.
|
|
22
39
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
23
40
|
async setBiometryType(
|
|
24
41
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
25
42
|
type) {
|
|
26
|
-
throw this.unimplemented('setBiometryType is web only');
|
|
43
|
+
throw this.unimplemented('setBiometryType() is web only');
|
|
27
44
|
}
|
|
28
45
|
}
|
package/dist/esm/web.d.ts
CHANGED
|
@@ -4,6 +4,6 @@ import { BiometryType } from './definitions';
|
|
|
4
4
|
export declare class BiometricAuthWeb extends BiometricAuthBase {
|
|
5
5
|
private biometryType;
|
|
6
6
|
checkBiometry(): Promise<CheckBiometryResult>;
|
|
7
|
-
|
|
7
|
+
internalAuthenticate(options?: AuthenticateOptions): Promise<void>;
|
|
8
8
|
setBiometryType(type: BiometryType | string | undefined): Promise<void>;
|
|
9
9
|
}
|
package/dist/esm/web.js
CHANGED
|
@@ -7,6 +7,7 @@ export class BiometricAuthWeb extends BiometricAuthBase {
|
|
|
7
7
|
super(...arguments);
|
|
8
8
|
this.biometryType = BiometryType.none;
|
|
9
9
|
}
|
|
10
|
+
// On the web, return the fake biometry set by setBiometryType().
|
|
10
11
|
async checkBiometry() {
|
|
11
12
|
return Promise.resolve({
|
|
12
13
|
isAvailable: this.biometryType !== BiometryType.none,
|
|
@@ -16,20 +17,23 @@ export class BiometricAuthWeb extends BiometricAuthBase {
|
|
|
16
17
|
code: BiometryErrorType.none,
|
|
17
18
|
});
|
|
18
19
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
20
|
+
// On the web, fake authentication with a confirm dialog.
|
|
21
|
+
async internalAuthenticate(options) {
|
|
22
|
+
const { isAvailable, biometryType } = await this.checkBiometry();
|
|
23
|
+
if (isAvailable) {
|
|
24
|
+
if (
|
|
25
|
+
// eslint-disable-next-line no-alert
|
|
26
|
+
confirm(
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- we want to use the default value if options?.reason is an empty string
|
|
28
|
+
(options === null || options === void 0 ? void 0 : options.reason) ||
|
|
29
|
+
`Authenticate with ${getBiometryName(biometryType)}?`)) {
|
|
30
|
+
return;
|
|
29
31
|
}
|
|
30
|
-
throw new BiometryError('
|
|
31
|
-
}
|
|
32
|
+
throw new BiometryError('User cancelled', BiometryErrorType.userCancel);
|
|
33
|
+
}
|
|
34
|
+
throw new BiometryError('Biometry not available', BiometryErrorType.biometryNotAvailable);
|
|
32
35
|
}
|
|
36
|
+
// Web only, used for simulating biometric authentication.
|
|
33
37
|
async setBiometryType(type) {
|
|
34
38
|
if (typeof type === 'undefined') {
|
|
35
39
|
return Promise.resolve();
|
package/dist/plugin.cjs.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var core = require('@capacitor/core');
|
|
4
4
|
var app = require('@capacitor/app');
|
|
5
5
|
|
|
6
|
+
// noinspection JSUnusedGlobalSymbols
|
|
6
7
|
exports.BiometryType = void 0;
|
|
7
8
|
(function (BiometryType) {
|
|
8
9
|
/**
|
|
@@ -31,8 +32,8 @@ exports.BiometryType = void 0;
|
|
|
31
32
|
BiometryType[BiometryType["irisAuthentication"] = 5] = "irisAuthentication";
|
|
32
33
|
})(exports.BiometryType || (exports.BiometryType = {}));
|
|
33
34
|
/**
|
|
34
|
-
* If the `authenticate()` method throws an exception, the
|
|
35
|
-
* contains a .code property which will contain one of these strings,
|
|
35
|
+
* If the `authenticate()` method throws an exception, the `BiometryError`
|
|
36
|
+
* instance contains a .code property which will contain one of these strings,
|
|
36
37
|
* indicating what the error was.
|
|
37
38
|
*
|
|
38
39
|
* See https://developer.apple.com/documentation/localauthentication/laerror
|
|
@@ -54,6 +55,9 @@ exports.BiometryErrorType = void 0;
|
|
|
54
55
|
BiometryErrorType["biometryNotEnrolled"] = "biometryNotEnrolled";
|
|
55
56
|
BiometryErrorType["noDeviceCredential"] = "noDeviceCredential";
|
|
56
57
|
})(exports.BiometryErrorType || (exports.BiometryErrorType = {}));
|
|
58
|
+
/**
|
|
59
|
+
* `authenticate()` throws instances of this class.
|
|
60
|
+
*/
|
|
57
61
|
class BiometryError {
|
|
58
62
|
constructor(message, code) {
|
|
59
63
|
this.message = message;
|
|
@@ -85,6 +89,23 @@ const proxy = core.registerPlugin('BiometricAuthNative', {
|
|
|
85
89
|
|
|
86
90
|
// eslint-disable-next-line import/prefer-default-export
|
|
87
91
|
class BiometricAuthBase extends core.WebPlugin {
|
|
92
|
+
async authenticate(options) {
|
|
93
|
+
try {
|
|
94
|
+
await this.internalAuthenticate(options);
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
// error will be an instance of CapacitorException on native platforms,
|
|
98
|
+
// an instance of BiometryError on the web.
|
|
99
|
+
if (error instanceof core.CapacitorException) {
|
|
100
|
+
throw new BiometryError(error.message,
|
|
101
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- error.data values are typed as any
|
|
102
|
+
error.data.code);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
88
109
|
addResumeListener(listener) {
|
|
89
110
|
return app.App.addListener('appStateChange', ({ isActive }) => {
|
|
90
111
|
if (isActive) {
|
|
@@ -104,6 +125,7 @@ class BiometricAuthWeb extends BiometricAuthBase {
|
|
|
104
125
|
super(...arguments);
|
|
105
126
|
this.biometryType = exports.BiometryType.none;
|
|
106
127
|
}
|
|
128
|
+
// On the web, return the fake biometry set by setBiometryType().
|
|
107
129
|
async checkBiometry() {
|
|
108
130
|
return Promise.resolve({
|
|
109
131
|
isAvailable: this.biometryType !== exports.BiometryType.none,
|
|
@@ -113,20 +135,23 @@ class BiometricAuthWeb extends BiometricAuthBase {
|
|
|
113
135
|
code: exports.BiometryErrorType.none,
|
|
114
136
|
});
|
|
115
137
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
138
|
+
// On the web, fake authentication with a confirm dialog.
|
|
139
|
+
async internalAuthenticate(options) {
|
|
140
|
+
const { isAvailable, biometryType } = await this.checkBiometry();
|
|
141
|
+
if (isAvailable) {
|
|
142
|
+
if (
|
|
143
|
+
// eslint-disable-next-line no-alert
|
|
144
|
+
confirm(
|
|
145
|
+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- we want to use the default value if options?.reason is an empty string
|
|
146
|
+
(options === null || options === void 0 ? void 0 : options.reason) ||
|
|
147
|
+
`Authenticate with ${getBiometryName(biometryType)}?`)) {
|
|
148
|
+
return;
|
|
126
149
|
}
|
|
127
|
-
throw new BiometryError('
|
|
128
|
-
}
|
|
150
|
+
throw new BiometryError('User cancelled', exports.BiometryErrorType.userCancel);
|
|
151
|
+
}
|
|
152
|
+
throw new BiometryError('Biometry not available', exports.BiometryErrorType.biometryNotAvailable);
|
|
129
153
|
}
|
|
154
|
+
// Web only, used for simulating biometric authentication.
|
|
130
155
|
async setBiometryType(type) {
|
|
131
156
|
if (typeof type === 'undefined') {
|
|
132
157
|
return Promise.resolve();
|
|
@@ -154,11 +179,24 @@ var web = /*#__PURE__*/Object.freeze({
|
|
|
154
179
|
class BiometricAuthNative extends BiometricAuthBase {
|
|
155
180
|
constructor(capProxy) {
|
|
156
181
|
super();
|
|
157
|
-
|
|
158
|
-
|
|
182
|
+
/*
|
|
183
|
+
In order to call native methods and maintain the ability to
|
|
184
|
+
call pure Javascript methods as well, we have to bind the native methods
|
|
185
|
+
to the proxy.
|
|
186
|
+
|
|
187
|
+
capProxy is a proxy of an instance of this class, so it is safe
|
|
188
|
+
to cast it to this class.
|
|
189
|
+
*/
|
|
190
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
191
|
+
const proxy = capProxy;
|
|
192
|
+
/* eslint-disable @typescript-eslint/unbound-method */
|
|
193
|
+
this.checkBiometry = proxy.checkBiometry;
|
|
194
|
+
this.internalAuthenticate = proxy.internalAuthenticate;
|
|
195
|
+
/* eslint-enable */
|
|
159
196
|
}
|
|
197
|
+
// @native
|
|
160
198
|
async checkBiometry() {
|
|
161
|
-
// Never used, satisfy the compiler
|
|
199
|
+
// Never used, but we have to satisfy the compiler.
|
|
162
200
|
return Promise.resolve({
|
|
163
201
|
isAvailable: true,
|
|
164
202
|
biometryType: exports.BiometryType.none,
|
|
@@ -167,13 +205,17 @@ class BiometricAuthNative extends BiometricAuthBase {
|
|
|
167
205
|
code: exports.BiometryErrorType.none,
|
|
168
206
|
});
|
|
169
207
|
}
|
|
170
|
-
//
|
|
171
|
-
|
|
208
|
+
// @native
|
|
209
|
+
// On native platforms, this will present the native authentication UI.
|
|
210
|
+
async internalAuthenticate(
|
|
211
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
212
|
+
options) { }
|
|
213
|
+
// Web only, used for simulating biometric authentication.
|
|
172
214
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
173
215
|
async setBiometryType(
|
|
174
216
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
175
217
|
type) {
|
|
176
|
-
throw this.unimplemented('setBiometryType is web only');
|
|
218
|
+
throw this.unimplemented('setBiometryType() is web only');
|
|
177
219
|
}
|
|
178
220
|
}
|
|
179
221
|
|
package/dist/plugin.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
var capacitorBiometricAuth = (function (exports, core, app) {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
+
// noinspection JSUnusedGlobalSymbols
|
|
4
5
|
exports.BiometryType = void 0;
|
|
5
6
|
(function (BiometryType) {
|
|
6
7
|
/**
|
|
@@ -29,8 +30,8 @@ var capacitorBiometricAuth = (function (exports, core, app) {
|
|
|
29
30
|
BiometryType[BiometryType["irisAuthentication"] = 5] = "irisAuthentication";
|
|
30
31
|
})(exports.BiometryType || (exports.BiometryType = {}));
|
|
31
32
|
/**
|
|
32
|
-
* If the `authenticate()` method throws an exception, the
|
|
33
|
-
* contains a .code property which will contain one of these strings,
|
|
33
|
+
* If the `authenticate()` method throws an exception, the `BiometryError`
|
|
34
|
+
* instance contains a .code property which will contain one of these strings,
|
|
34
35
|
* indicating what the error was.
|
|
35
36
|
*
|
|
36
37
|
* See https://developer.apple.com/documentation/localauthentication/laerror
|
|
@@ -52,6 +53,9 @@ var capacitorBiometricAuth = (function (exports, core, app) {
|
|
|
52
53
|
BiometryErrorType["biometryNotEnrolled"] = "biometryNotEnrolled";
|
|
53
54
|
BiometryErrorType["noDeviceCredential"] = "noDeviceCredential";
|
|
54
55
|
})(exports.BiometryErrorType || (exports.BiometryErrorType = {}));
|
|
56
|
+
/**
|
|
57
|
+
* `authenticate()` throws instances of this class.
|
|
58
|
+
*/
|
|
55
59
|
class BiometryError {
|
|
56
60
|
constructor(message, code) {
|
|
57
61
|
this.message = message;
|
|
@@ -83,6 +87,23 @@ var capacitorBiometricAuth = (function (exports, core, app) {
|
|
|
83
87
|
|
|
84
88
|
// eslint-disable-next-line import/prefer-default-export
|
|
85
89
|
class BiometricAuthBase extends core.WebPlugin {
|
|
90
|
+
async authenticate(options) {
|
|
91
|
+
try {
|
|
92
|
+
await this.internalAuthenticate(options);
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
// error will be an instance of CapacitorException on native platforms,
|
|
96
|
+
// an instance of BiometryError on the web.
|
|
97
|
+
if (error instanceof core.CapacitorException) {
|
|
98
|
+
throw new BiometryError(error.message,
|
|
99
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- error.data values are typed as any
|
|
100
|
+
error.data.code);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
86
107
|
addResumeListener(listener) {
|
|
87
108
|
return app.App.addListener('appStateChange', ({ isActive }) => {
|
|
88
109
|
if (isActive) {
|
|
@@ -102,6 +123,7 @@ var capacitorBiometricAuth = (function (exports, core, app) {
|
|
|
102
123
|
super(...arguments);
|
|
103
124
|
this.biometryType = exports.BiometryType.none;
|
|
104
125
|
}
|
|
126
|
+
// On the web, return the fake biometry set by setBiometryType().
|
|
105
127
|
async checkBiometry() {
|
|
106
128
|
return Promise.resolve({
|
|
107
129
|
isAvailable: this.biometryType !== exports.BiometryType.none,
|
|
@@ -111,20 +133,23 @@ var capacitorBiometricAuth = (function (exports, core, app) {
|
|
|
111
133
|
code: exports.BiometryErrorType.none,
|
|
112
134
|
});
|
|
113
135
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
136
|
+
// On the web, fake authentication with a confirm dialog.
|
|
137
|
+
async internalAuthenticate(options) {
|
|
138
|
+
const { isAvailable, biometryType } = await this.checkBiometry();
|
|
139
|
+
if (isAvailable) {
|
|
140
|
+
if (
|
|
141
|
+
// eslint-disable-next-line no-alert
|
|
142
|
+
confirm(
|
|
143
|
+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- we want to use the default value if options?.reason is an empty string
|
|
144
|
+
(options === null || options === void 0 ? void 0 : options.reason) ||
|
|
145
|
+
`Authenticate with ${getBiometryName(biometryType)}?`)) {
|
|
146
|
+
return;
|
|
124
147
|
}
|
|
125
|
-
throw new BiometryError('
|
|
126
|
-
}
|
|
148
|
+
throw new BiometryError('User cancelled', exports.BiometryErrorType.userCancel);
|
|
149
|
+
}
|
|
150
|
+
throw new BiometryError('Biometry not available', exports.BiometryErrorType.biometryNotAvailable);
|
|
127
151
|
}
|
|
152
|
+
// Web only, used for simulating biometric authentication.
|
|
128
153
|
async setBiometryType(type) {
|
|
129
154
|
if (typeof type === 'undefined') {
|
|
130
155
|
return Promise.resolve();
|
|
@@ -152,11 +177,24 @@ var capacitorBiometricAuth = (function (exports, core, app) {
|
|
|
152
177
|
class BiometricAuthNative extends BiometricAuthBase {
|
|
153
178
|
constructor(capProxy) {
|
|
154
179
|
super();
|
|
155
|
-
|
|
156
|
-
|
|
180
|
+
/*
|
|
181
|
+
In order to call native methods and maintain the ability to
|
|
182
|
+
call pure Javascript methods as well, we have to bind the native methods
|
|
183
|
+
to the proxy.
|
|
184
|
+
|
|
185
|
+
capProxy is a proxy of an instance of this class, so it is safe
|
|
186
|
+
to cast it to this class.
|
|
187
|
+
*/
|
|
188
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
189
|
+
const proxy = capProxy;
|
|
190
|
+
/* eslint-disable @typescript-eslint/unbound-method */
|
|
191
|
+
this.checkBiometry = proxy.checkBiometry;
|
|
192
|
+
this.internalAuthenticate = proxy.internalAuthenticate;
|
|
193
|
+
/* eslint-enable */
|
|
157
194
|
}
|
|
195
|
+
// @native
|
|
158
196
|
async checkBiometry() {
|
|
159
|
-
// Never used, satisfy the compiler
|
|
197
|
+
// Never used, but we have to satisfy the compiler.
|
|
160
198
|
return Promise.resolve({
|
|
161
199
|
isAvailable: true,
|
|
162
200
|
biometryType: exports.BiometryType.none,
|
|
@@ -165,13 +203,17 @@ var capacitorBiometricAuth = (function (exports, core, app) {
|
|
|
165
203
|
code: exports.BiometryErrorType.none,
|
|
166
204
|
});
|
|
167
205
|
}
|
|
168
|
-
//
|
|
169
|
-
|
|
206
|
+
// @native
|
|
207
|
+
// On native platforms, this will present the native authentication UI.
|
|
208
|
+
async internalAuthenticate(
|
|
209
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
210
|
+
options) { }
|
|
211
|
+
// Web only, used for simulating biometric authentication.
|
|
170
212
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
171
213
|
async setBiometryType(
|
|
172
214
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
173
215
|
type) {
|
|
174
|
-
throw this.unimplemented('setBiometryType is web only');
|
|
216
|
+
throw this.unimplemented('setBiometryType() is web only');
|
|
175
217
|
}
|
|
176
218
|
}
|
|
177
219
|
|
package/ios/Plugin/Plugin.m
CHANGED
package/ios/Plugin/Plugin.swift
CHANGED
|
@@ -22,12 +22,32 @@ public class BiometricAuthNative: CAPPlugin {
|
|
|
22
22
|
LAError.biometryNotEnrolled.rawValue: "biometryNotEnrolled"
|
|
23
23
|
]
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
struct CheckDeviceBiometryResult {
|
|
26
|
+
let isAvailable: Bool
|
|
27
|
+
let biometryType: LABiometryType.RawValue
|
|
28
|
+
let biometryTypes: JSArray
|
|
29
|
+
let reason: String
|
|
30
|
+
let code: String
|
|
31
|
+
}
|
|
26
32
|
|
|
27
33
|
/**
|
|
28
|
-
*
|
|
34
|
+
* Plugin call checkBiometry()
|
|
29
35
|
*/
|
|
30
36
|
@objc func checkBiometry(_ call: CAPPluginCall) {
|
|
37
|
+
let checkResult = checkDeviceBiometry()
|
|
38
|
+
call.resolve([
|
|
39
|
+
"isAvailable": checkResult.isAvailable,
|
|
40
|
+
"biometryType": checkResult.biometryType,
|
|
41
|
+
"biometryTypes": checkResult.biometryTypes,
|
|
42
|
+
"reason": checkResult.reason,
|
|
43
|
+
"code": checkResult.code
|
|
44
|
+
])
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Check the device's availability and type of biometric authentication.
|
|
49
|
+
*/
|
|
50
|
+
func checkDeviceBiometry() -> CheckDeviceBiometryResult {
|
|
31
51
|
let context = LAContext()
|
|
32
52
|
var error: NSError?
|
|
33
53
|
var available = context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error)
|
|
@@ -42,7 +62,6 @@ public class BiometricAuthNative: CAPPlugin {
|
|
|
42
62
|
|
|
43
63
|
if entry == nil {
|
|
44
64
|
available = false
|
|
45
|
-
canEvaluatePolicy = false
|
|
46
65
|
reason = kMissingFaceIDUsageEntry
|
|
47
66
|
errorCode = biometryErrorCodeMap[LAError.biometryNotAvailable.rawValue] ?? ""
|
|
48
67
|
}
|
|
@@ -61,13 +80,13 @@ public class BiometricAuthNative: CAPPlugin {
|
|
|
61
80
|
var types = JSArray()
|
|
62
81
|
types.append(context.biometryType.rawValue)
|
|
63
82
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
83
|
+
return CheckDeviceBiometryResult(
|
|
84
|
+
isAvailable: available,
|
|
85
|
+
biometryType: context.biometryType.rawValue,
|
|
86
|
+
biometryTypes: types,
|
|
87
|
+
reason: reason,
|
|
88
|
+
code: errorCode
|
|
89
|
+
)
|
|
71
90
|
}
|
|
72
91
|
|
|
73
92
|
/**
|
|
@@ -77,11 +96,13 @@ public class BiometricAuthNative: CAPPlugin {
|
|
|
77
96
|
* @returns {Promise<void>}
|
|
78
97
|
* @rejects {BiometricResultError}
|
|
79
98
|
*/
|
|
80
|
-
@objc func
|
|
99
|
+
@objc func internalAuthenticate(_ call: CAPPluginCall) {
|
|
81
100
|
// Make sure the app can evaluate policy, otherwise evaluatePolicy() will crash
|
|
82
|
-
|
|
101
|
+
let checkResult = checkDeviceBiometry()
|
|
102
|
+
|
|
103
|
+
guard checkResult.isAvailable else {
|
|
83
104
|
call.reject(
|
|
84
|
-
|
|
105
|
+
checkResult.reason,
|
|
85
106
|
biometryErrorCodeMap[LAError.biometryNotAvailable.rawValue]
|
|
86
107
|
)
|
|
87
108
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aparajita/capacitor-biometric-auth",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.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",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"types": "dist/esm/index.d.ts",
|
|
10
10
|
"unpkg": "dist/plugin.js",
|
|
11
11
|
"engines": {
|
|
12
|
-
"node": ">=
|
|
12
|
+
"node": ">=18"
|
|
13
13
|
},
|
|
14
14
|
"files": [
|
|
15
15
|
"android/src/main/",
|
|
@@ -56,35 +56,35 @@
|
|
|
56
56
|
"@aparajita/eslint-config-base": "^1.1.6",
|
|
57
57
|
"@aparajita/prettier-config": "^2.0.0",
|
|
58
58
|
"@aparajita/swiftly": "^1.0.4",
|
|
59
|
-
"@capacitor/cli": "^5.
|
|
60
|
-
"@commitlint/cli": "^
|
|
61
|
-
"@commitlint/config-conventional": "^
|
|
59
|
+
"@capacitor/cli": "^5.5.1",
|
|
60
|
+
"@commitlint/cli": "^18.4.1",
|
|
61
|
+
"@commitlint/config-conventional": "^18.4.0",
|
|
62
62
|
"@ionic/swiftlint-config": "^1.1.2",
|
|
63
|
-
"@rollup/plugin-json": "^6.0.
|
|
64
|
-
"@types/node": "^20.
|
|
65
|
-
"@typescript-eslint/eslint-plugin": "^6.
|
|
66
|
-
"@typescript-eslint/parser": "^6.
|
|
67
|
-
"commit-and-tag-version": "^
|
|
68
|
-
"eslint": "^8.
|
|
63
|
+
"@rollup/plugin-json": "^6.0.1",
|
|
64
|
+
"@types/node": "^20.9.0",
|
|
65
|
+
"@typescript-eslint/eslint-plugin": "^6.11.0",
|
|
66
|
+
"@typescript-eslint/parser": "^6.11.0",
|
|
67
|
+
"commit-and-tag-version": "^12.0.0",
|
|
68
|
+
"eslint": "^8.53.0",
|
|
69
69
|
"eslint-config-prettier": "^9.0.0",
|
|
70
70
|
"eslint-config-standard": "^17.1.0",
|
|
71
71
|
"eslint-import-resolver-typescript": "^3.6.1",
|
|
72
|
-
"eslint-plugin-import": "^2.
|
|
73
|
-
"eslint-plugin-n": "^16.1
|
|
72
|
+
"eslint-plugin-import": "^2.29.0",
|
|
73
|
+
"eslint-plugin-n": "^16.3.1",
|
|
74
74
|
"eslint-plugin-promise": "^6.1.1",
|
|
75
75
|
"nodemon": "^3.0.1",
|
|
76
|
-
"prettier": "^3.0
|
|
77
|
-
"prettier-plugin-java": "^2.
|
|
76
|
+
"prettier": "^3.1.0",
|
|
77
|
+
"prettier-plugin-java": "^2.4.0",
|
|
78
78
|
"rimraf": "^5.0.5",
|
|
79
|
-
"rollup": "^
|
|
79
|
+
"rollup": "^4.4.0",
|
|
80
80
|
"swiftlint": "^1.0.2",
|
|
81
81
|
"typescript": "~5.2.2"
|
|
82
82
|
},
|
|
83
83
|
"dependencies": {
|
|
84
|
-
"@capacitor/android": "^5.
|
|
84
|
+
"@capacitor/android": "^5.5.1",
|
|
85
85
|
"@capacitor/app": "^5.0.6",
|
|
86
|
-
"@capacitor/core": "^5.
|
|
87
|
-
"@capacitor/ios": "^5.
|
|
86
|
+
"@capacitor/core": "^5.5.1",
|
|
87
|
+
"@capacitor/ios": "^5.5.1"
|
|
88
88
|
},
|
|
89
89
|
"scripts": {
|
|
90
90
|
"clean": "rimraf dist",
|