@symbiote-native/local-auth 0.0.1 → 0.3.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/LICENSE +21 -0
- package/README.md +252 -24
- package/build/angular/index.d.ts +1 -0
- package/build/angular/index.js +4 -0
- package/build/core/index.d.ts +2 -0
- package/build/core/index.js +2 -0
- package/build/core/local-authentication.d.ts +33 -0
- package/build/core/local-authentication.js +75 -0
- package/build/core/native-module.d.ts +13 -0
- package/build/core/native-module.js +3 -0
- package/build/core/types.d.ts +83 -0
- package/build/core/types.js +55 -0
- package/build/react/index.d.ts +1 -0
- package/build/react/index.js +6 -0
- package/build/svelte/index.d.ts +1 -0
- package/build/svelte/index.js +6 -0
- package/build/vue/index.d.ts +1 -0
- package/build/vue/index.js +4 -0
- package/build-ngc/angular/index.d.ts +1 -0
- package/build-ngc/angular/index.js +5 -0
- package/build-ngc/angular/index.js.map +1 -0
- package/build-ngc/core/index.d.ts +2 -0
- package/build-ngc/core/index.js +3 -0
- package/build-ngc/core/index.js.map +1 -0
- package/build-ngc/core/local-authentication.d.ts +33 -0
- package/build-ngc/core/local-authentication.js +76 -0
- package/build-ngc/core/local-authentication.js.map +1 -0
- package/build-ngc/core/native-module.d.ts +13 -0
- package/build-ngc/core/native-module.js +4 -0
- package/build-ngc/core/native-module.js.map +1 -0
- package/build-ngc/core/types.d.ts +83 -0
- package/build-ngc/core/types.js +56 -0
- package/build-ngc/core/types.js.map +1 -0
- package/native-link.json +17 -0
- package/package.json +110 -3
- package/src/angular/index.ts +4 -0
- package/src/core/index.ts +16 -0
- package/src/core/local-authentication.ts +96 -0
- package/src/core/native-module.ts +27 -0
- package/src/core/types.ts +130 -0
- package/src/react/index.ts +6 -0
- package/src/svelte/index.ts +6 -0
- package/src/vue/index.ts +4 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,iCAAiC,EACjC,eAAe,EACf,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,kBAAkB,EAClB,aAAa,GAKd,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { AuthenticationType, ILocalAuthenticationOptions, ILocalAuthenticationResult, SecurityLevel } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Determine whether a face or fingerprint scanner is available on the device.
|
|
4
|
+
*/
|
|
5
|
+
export declare function hasHardwareAsync(): Promise<boolean>;
|
|
6
|
+
/**
|
|
7
|
+
* Determine what kinds of authentications are available on the device. Devices can support
|
|
8
|
+
* multiple authentication methods — e.g. `[FINGERPRINT, FACIAL_RECOGNITION]` means the device
|
|
9
|
+
* supports both. Returns an empty array if none are supported.
|
|
10
|
+
*/
|
|
11
|
+
export declare function supportedAuthenticationTypesAsync(): Promise<AuthenticationType[]>;
|
|
12
|
+
/**
|
|
13
|
+
* Determine whether the device has saved fingerprints or facial data to use for authentication.
|
|
14
|
+
*/
|
|
15
|
+
export declare function isEnrolledAsync(): Promise<boolean>;
|
|
16
|
+
/**
|
|
17
|
+
* Determine what kind of authentication is enrolled on the device.
|
|
18
|
+
* > On Android devices prior to M, `SECRET` can be returned if only the SIM lock has been
|
|
19
|
+
* enrolled, which is not the method `authenticateAsync` prompts.
|
|
20
|
+
*/
|
|
21
|
+
export declare function getEnrolledLevelAsync(): Promise<SecurityLevel>;
|
|
22
|
+
/**
|
|
23
|
+
* Attempts to authenticate via Fingerprint/TouchID (or FaceID if available on the device).
|
|
24
|
+
* > Apple requires apps which use FaceID to provide a description of why they use this API
|
|
25
|
+
* (`NSFaceIDUsageDescription` in `Info.plist`). Without it, the module authenticates using the
|
|
26
|
+
* device passcode instead.
|
|
27
|
+
*/
|
|
28
|
+
export declare function authenticateAsync(options?: ILocalAuthenticationOptions): Promise<ILocalAuthenticationResult>;
|
|
29
|
+
/**
|
|
30
|
+
* Cancels the authentication flow.
|
|
31
|
+
* @platform android
|
|
32
|
+
*/
|
|
33
|
+
export declare function cancelAuthenticate(): Promise<void>;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { UnavailabilityError } from 'expo-modules-core';
|
|
2
|
+
import invariant from 'invariant';
|
|
3
|
+
import { expoLocalAuthentication } from './native-module';
|
|
4
|
+
const NATIVE_MODULE_NAME = 'expo-local-authentication';
|
|
5
|
+
const DEFAULT_PROMPT_MESSAGE = 'Authenticate';
|
|
6
|
+
const DEFAULT_CANCEL_LABEL = 'Cancel';
|
|
7
|
+
/**
|
|
8
|
+
* Determine whether a face or fingerprint scanner is available on the device.
|
|
9
|
+
*/
|
|
10
|
+
export async function hasHardwareAsync() {
|
|
11
|
+
if (!expoLocalAuthentication.hasHardwareAsync) {
|
|
12
|
+
throw new UnavailabilityError(NATIVE_MODULE_NAME, 'hasHardwareAsync');
|
|
13
|
+
}
|
|
14
|
+
return expoLocalAuthentication.hasHardwareAsync();
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Determine what kinds of authentications are available on the device. Devices can support
|
|
18
|
+
* multiple authentication methods — e.g. `[FINGERPRINT, FACIAL_RECOGNITION]` means the device
|
|
19
|
+
* supports both. Returns an empty array if none are supported.
|
|
20
|
+
*/
|
|
21
|
+
export async function supportedAuthenticationTypesAsync() {
|
|
22
|
+
if (!expoLocalAuthentication.supportedAuthenticationTypesAsync) {
|
|
23
|
+
throw new UnavailabilityError(NATIVE_MODULE_NAME, 'supportedAuthenticationTypesAsync');
|
|
24
|
+
}
|
|
25
|
+
return expoLocalAuthentication.supportedAuthenticationTypesAsync();
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Determine whether the device has saved fingerprints or facial data to use for authentication.
|
|
29
|
+
*/
|
|
30
|
+
export async function isEnrolledAsync() {
|
|
31
|
+
if (!expoLocalAuthentication.isEnrolledAsync) {
|
|
32
|
+
throw new UnavailabilityError(NATIVE_MODULE_NAME, 'isEnrolledAsync');
|
|
33
|
+
}
|
|
34
|
+
return expoLocalAuthentication.isEnrolledAsync();
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Determine what kind of authentication is enrolled on the device.
|
|
38
|
+
* > On Android devices prior to M, `SECRET` can be returned if only the SIM lock has been
|
|
39
|
+
* enrolled, which is not the method `authenticateAsync` prompts.
|
|
40
|
+
*/
|
|
41
|
+
export async function getEnrolledLevelAsync() {
|
|
42
|
+
if (!expoLocalAuthentication.getEnrolledLevelAsync) {
|
|
43
|
+
throw new UnavailabilityError(NATIVE_MODULE_NAME, 'getEnrolledLevelAsync');
|
|
44
|
+
}
|
|
45
|
+
return expoLocalAuthentication.getEnrolledLevelAsync();
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Attempts to authenticate via Fingerprint/TouchID (or FaceID if available on the device).
|
|
49
|
+
* > Apple requires apps which use FaceID to provide a description of why they use this API
|
|
50
|
+
* (`NSFaceIDUsageDescription` in `Info.plist`). Without it, the module authenticates using the
|
|
51
|
+
* device passcode instead.
|
|
52
|
+
*/
|
|
53
|
+
export async function authenticateAsync(options = {}) {
|
|
54
|
+
if (!expoLocalAuthentication.authenticateAsync) {
|
|
55
|
+
throw new UnavailabilityError(NATIVE_MODULE_NAME, 'authenticateAsync');
|
|
56
|
+
}
|
|
57
|
+
if (options.promptMessage !== undefined) {
|
|
58
|
+
invariant(typeof options.promptMessage === 'string' && options.promptMessage.length > 0, 'LocalAuthentication.authenticateAsync: `options.promptMessage` must be a non-empty string.');
|
|
59
|
+
}
|
|
60
|
+
return expoLocalAuthentication.authenticateAsync({
|
|
61
|
+
...options,
|
|
62
|
+
promptMessage: options.promptMessage || DEFAULT_PROMPT_MESSAGE,
|
|
63
|
+
cancelLabel: options.cancelLabel || DEFAULT_CANCEL_LABEL,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Cancels the authentication flow.
|
|
68
|
+
* @platform android
|
|
69
|
+
*/
|
|
70
|
+
export async function cancelAuthenticate() {
|
|
71
|
+
if (!expoLocalAuthentication.cancelAuthenticate) {
|
|
72
|
+
throw new UnavailabilityError(NATIVE_MODULE_NAME, 'cancelAuthenticate');
|
|
73
|
+
}
|
|
74
|
+
await expoLocalAuthentication.cancelAuthenticate();
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=local-authentication.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-authentication.js","sourceRoot":"","sources":["../../src/core/local-authentication.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,SAAS,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAQ1D,MAAM,kBAAkB,GAAG,2BAA2B,CAAC;AACvD,MAAM,sBAAsB,GAAG,cAAc,CAAC;AAC9C,MAAM,oBAAoB,GAAG,QAAQ,CAAC;AAEtC;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,IAAI,CAAC,uBAAuB,CAAC,gBAAgB,EAAE,CAAC;QAC9C,MAAM,IAAI,mBAAmB,CAAC,kBAAkB,EAAE,kBAAkB,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,uBAAuB,CAAC,gBAAgB,EAAE,CAAC;AACpD,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,iCAAiC;IACrD,IAAI,CAAC,uBAAuB,CAAC,iCAAiC,EAAE,CAAC;QAC/D,MAAM,IAAI,mBAAmB,CAAC,kBAAkB,EAAE,mCAAmC,CAAC,CAAC;IACzF,CAAC;IACD,OAAO,uBAAuB,CAAC,iCAAiC,EAAE,CAAC;AACrE,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,IAAI,CAAC,uBAAuB,CAAC,eAAe,EAAE,CAAC;QAC7C,MAAM,IAAI,mBAAmB,CAAC,kBAAkB,EAAE,iBAAiB,CAAC,CAAC;IACvE,CAAC;IACD,OAAO,uBAAuB,CAAC,eAAe,EAAE,CAAC;AACnD,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,IAAI,CAAC,uBAAuB,CAAC,qBAAqB,EAAE,CAAC;QACnD,MAAM,IAAI,mBAAmB,CAAC,kBAAkB,EAAE,uBAAuB,CAAC,CAAC;IAC7E,CAAC;IACD,OAAO,uBAAuB,CAAC,qBAAqB,EAAE,CAAC;AACzD,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,UAAuC,EAAE;IAEzC,IAAI,CAAC,uBAAuB,CAAC,iBAAiB,EAAE,CAAC;QAC/C,MAAM,IAAI,mBAAmB,CAAC,kBAAkB,EAAE,mBAAmB,CAAC,CAAC;IACzE,CAAC;IAED,IAAI,OAAO,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;QACxC,SAAS,CACP,OAAO,OAAO,CAAC,aAAa,KAAK,QAAQ,IAAI,OAAO,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,EAC7E,4FAA4F,CAC7F,CAAC;IACJ,CAAC;IAED,OAAO,uBAAuB,CAAC,iBAAiB,CAAC;QAC/C,GAAG,OAAO;QACV,aAAa,EAAE,OAAO,CAAC,aAAa,IAAI,sBAAsB;QAC9D,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,oBAAoB;KACzD,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,IAAI,CAAC,uBAAuB,CAAC,kBAAkB,EAAE,CAAC;QAChD,MAAM,IAAI,mBAAmB,CAAC,kBAAkB,EAAE,oBAAoB,CAAC,CAAC;IAC1E,CAAC;IACD,MAAM,uBAAuB,CAAC,kBAAkB,EAAE,CAAC;AACrD,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AuthenticationType, ILocalAuthenticationOptions, ILocalAuthenticationResult, SecurityLevel } from './types';
|
|
2
|
+
export type INativeLocalAuthenticationModule = {
|
|
3
|
+
hasHardwareAsync?(): Promise<boolean>;
|
|
4
|
+
supportedAuthenticationTypesAsync?(): Promise<AuthenticationType[]>;
|
|
5
|
+
isEnrolledAsync?(): Promise<boolean>;
|
|
6
|
+
getEnrolledLevelAsync?(): Promise<SecurityLevel>;
|
|
7
|
+
authenticateAsync?(options: ILocalAuthenticationOptions & {
|
|
8
|
+
promptMessage: string;
|
|
9
|
+
cancelLabel: string;
|
|
10
|
+
}): Promise<ILocalAuthenticationResult>;
|
|
11
|
+
cancelAuthenticate?(): Promise<void>;
|
|
12
|
+
};
|
|
13
|
+
export declare const expoLocalAuthentication: INativeLocalAuthenticationModule;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { requireNativeModule } from 'expo-modules-core';
|
|
2
|
+
const EXPO_LOCAL_AUTHENTICATION_MODULE_NAME = 'ExpoLocalAuthentication';
|
|
3
|
+
export const expoLocalAuthentication = requireNativeModule(EXPO_LOCAL_AUTHENTICATION_MODULE_NAME);
|
|
4
|
+
//# sourceMappingURL=native-module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-module.js","sourceRoot":"","sources":["../../src/core/native-module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAQxD,MAAM,qCAAqC,GAAG,yBAAyB,CAAC;AAgBxE,MAAM,CAAC,MAAM,uBAAuB,GAAG,mBAAmB,CACxD,qCAAqC,CACtC,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
export type ILocalAuthenticationResult = {
|
|
2
|
+
success: true;
|
|
3
|
+
} | {
|
|
4
|
+
success: false;
|
|
5
|
+
error: ILocalAuthenticationError;
|
|
6
|
+
warning?: string;
|
|
7
|
+
};
|
|
8
|
+
export declare enum AuthenticationType {
|
|
9
|
+
/** Indicates fingerprint support. */
|
|
10
|
+
FINGERPRINT = 1,
|
|
11
|
+
/** Indicates facial recognition support. */
|
|
12
|
+
FACIAL_RECOGNITION = 2,
|
|
13
|
+
/**
|
|
14
|
+
* Indicates iris recognition support.
|
|
15
|
+
* @platform android
|
|
16
|
+
*/
|
|
17
|
+
IRIS = 3
|
|
18
|
+
}
|
|
19
|
+
export declare enum SecurityLevel {
|
|
20
|
+
/** Indicates no enrolled authentication. */
|
|
21
|
+
NONE = 0,
|
|
22
|
+
/** Indicates non-biometric authentication (e.g. PIN, Pattern). */
|
|
23
|
+
SECRET = 1,
|
|
24
|
+
/**
|
|
25
|
+
* Indicates biometric authentication.
|
|
26
|
+
* @deprecated please use `BIOMETRIC_STRONG` or `BIOMETRIC_WEAK` instead.
|
|
27
|
+
* @hidden
|
|
28
|
+
*/
|
|
29
|
+
BIOMETRIC,
|
|
30
|
+
/**
|
|
31
|
+
* Indicates weak biometric authentication. For example, a 2D image-based face unlock. There
|
|
32
|
+
* are currently no weak biometric authentication options on iOS.
|
|
33
|
+
*/
|
|
34
|
+
BIOMETRIC_WEAK = 2,
|
|
35
|
+
/** Indicates strong biometric authentication. For example, a fingerprint scan or 3D face unlock. */
|
|
36
|
+
BIOMETRIC_STRONG = 3
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Security level of the biometric authentication to allow.
|
|
40
|
+
* @platform android
|
|
41
|
+
*/
|
|
42
|
+
export type IBiometricsSecurityLevel = 'weak' | 'strong';
|
|
43
|
+
export type ILocalAuthenticationOptions = {
|
|
44
|
+
/** A message that is shown alongside the TouchID or FaceID prompt. */
|
|
45
|
+
promptMessage?: string;
|
|
46
|
+
/**
|
|
47
|
+
* A subtitle displayed below the prompt message in the authentication prompt.
|
|
48
|
+
* @platform android
|
|
49
|
+
*/
|
|
50
|
+
promptSubtitle?: string;
|
|
51
|
+
/**
|
|
52
|
+
* A description displayed in the middle of the authentication prompt.
|
|
53
|
+
* @platform android
|
|
54
|
+
*/
|
|
55
|
+
promptDescription?: string;
|
|
56
|
+
/** Allows customizing the default `Cancel` label shown. */
|
|
57
|
+
cancelLabel?: string;
|
|
58
|
+
/**
|
|
59
|
+
* After several failed attempts, the system falls back to the device passcode. This setting
|
|
60
|
+
* allows you to disable this option and instead handle the fallback yourself. Defaults to `false`.
|
|
61
|
+
*/
|
|
62
|
+
disableDeviceFallback?: boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Sets a hint to the system for whether to require user confirmation after authentication.
|
|
65
|
+
* Defaults to `true`.
|
|
66
|
+
* @platform android
|
|
67
|
+
*/
|
|
68
|
+
requireConfirmation?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Sets the security class of biometric authentication to allow. `strong` allows only Android
|
|
71
|
+
* Class 3 biometrics; `weak` allows both Class 3 and Class 2.
|
|
72
|
+
* @platform android
|
|
73
|
+
* @default 'weak'
|
|
74
|
+
*/
|
|
75
|
+
biometricsSecurityLevel?: IBiometricsSecurityLevel;
|
|
76
|
+
/**
|
|
77
|
+
* Allows customizing the default `Use Passcode` label shown after several failed attempts. An
|
|
78
|
+
* empty string disables the button.
|
|
79
|
+
* @platform ios
|
|
80
|
+
*/
|
|
81
|
+
fallbackLabel?: string;
|
|
82
|
+
};
|
|
83
|
+
export type ILocalAuthenticationError = 'not_enrolled' | 'user_cancel' | 'app_cancel' | 'not_available' | 'lockout' | 'no_space' | 'timeout' | 'unable_to_process' | 'unknown' | 'system_cancel' | 'user_fallback' | 'invalid_context' | 'passcode_not_set' | 'authentication_failed';
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// expo-local-authentication's own types file imports Platform from the `expo` meta-package. We
|
|
2
|
+
// never depend on `expo` itself (it drags in a second Metro/babel pipeline — see the
|
|
3
|
+
// symbiote-expo-native-module skill) so this pulls Platform straight from expo-modules-core,
|
|
4
|
+
// which is where `expo` re-exports it from — same source device-sensor.ts (packages/sensors)
|
|
5
|
+
// uses for the same reason.
|
|
6
|
+
import { Platform } from 'expo-modules-core';
|
|
7
|
+
export var AuthenticationType;
|
|
8
|
+
(function (AuthenticationType) {
|
|
9
|
+
/** Indicates fingerprint support. */
|
|
10
|
+
AuthenticationType[AuthenticationType["FINGERPRINT"] = 1] = "FINGERPRINT";
|
|
11
|
+
/** Indicates facial recognition support. */
|
|
12
|
+
AuthenticationType[AuthenticationType["FACIAL_RECOGNITION"] = 2] = "FACIAL_RECOGNITION";
|
|
13
|
+
/**
|
|
14
|
+
* Indicates iris recognition support.
|
|
15
|
+
* @platform android
|
|
16
|
+
*/
|
|
17
|
+
AuthenticationType[AuthenticationType["IRIS"] = 3] = "IRIS";
|
|
18
|
+
})(AuthenticationType || (AuthenticationType = {}));
|
|
19
|
+
export var SecurityLevel;
|
|
20
|
+
(function (SecurityLevel) {
|
|
21
|
+
/** Indicates no enrolled authentication. */
|
|
22
|
+
SecurityLevel[SecurityLevel["NONE"] = 0] = "NONE";
|
|
23
|
+
/** Indicates non-biometric authentication (e.g. PIN, Pattern). */
|
|
24
|
+
SecurityLevel[SecurityLevel["SECRET"] = 1] = "SECRET";
|
|
25
|
+
/**
|
|
26
|
+
* Indicates biometric authentication.
|
|
27
|
+
* @deprecated please use `BIOMETRIC_STRONG` or `BIOMETRIC_WEAK` instead.
|
|
28
|
+
* @hidden
|
|
29
|
+
*/
|
|
30
|
+
SecurityLevel[SecurityLevel["BIOMETRIC"] = Platform.OS === 'android'
|
|
31
|
+
? SecurityLevel.BIOMETRIC_WEAK
|
|
32
|
+
: SecurityLevel.BIOMETRIC_STRONG] = "BIOMETRIC";
|
|
33
|
+
/**
|
|
34
|
+
* Indicates weak biometric authentication. For example, a 2D image-based face unlock. There
|
|
35
|
+
* are currently no weak biometric authentication options on iOS.
|
|
36
|
+
*/
|
|
37
|
+
SecurityLevel[SecurityLevel["BIOMETRIC_WEAK"] = 2] = "BIOMETRIC_WEAK";
|
|
38
|
+
/** Indicates strong biometric authentication. For example, a fingerprint scan or 3D face unlock. */
|
|
39
|
+
SecurityLevel[SecurityLevel["BIOMETRIC_STRONG"] = 3] = "BIOMETRIC_STRONG";
|
|
40
|
+
})(SecurityLevel || (SecurityLevel = {}));
|
|
41
|
+
// Upstream deprecation shim: SecurityLevel.BIOMETRIC used to be a real enum member; it's now a
|
|
42
|
+
// getter aliasing to the platform-correct strong/weak member, so old call sites still resolve
|
|
43
|
+
// but see a console warning steering them to the non-deprecated name.
|
|
44
|
+
Object.defineProperty(SecurityLevel, 'BIOMETRIC', {
|
|
45
|
+
get() {
|
|
46
|
+
const additionalMessage = Platform.OS === 'android'
|
|
47
|
+
? '. `SecurityLevel.BIOMETRIC` is currently an alias for `SecurityLevel.BIOMETRIC_WEAK` on Android, which might lead to unexpected behaviour.'
|
|
48
|
+
: '';
|
|
49
|
+
console.warn('`SecurityLevel.BIOMETRIC` has been deprecated. Use `SecurityLevel.BIOMETRIC_WEAK` or `SecurityLevel.BIOMETRIC_STRONG` instead' +
|
|
50
|
+
additionalMessage);
|
|
51
|
+
return Platform.OS === 'android'
|
|
52
|
+
? SecurityLevel.BIOMETRIC_WEAK
|
|
53
|
+
: SecurityLevel.BIOMETRIC_STRONG;
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,qFAAqF;AACrF,6FAA6F;AAC7F,6FAA6F;AAC7F,4BAA4B;AAC5B,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAU7C,MAAM,CAAN,IAAY,kBAUX;AAVD,WAAY,kBAAkB;IAC5B,qCAAqC;IACrC,yEAAe,CAAA;IACf,4CAA4C;IAC5C,uFAAsB,CAAA;IACtB;;;OAGG;IACH,2DAAQ,CAAA;AACV,CAAC,EAVW,kBAAkB,KAAlB,kBAAkB,QAU7B;AAED,MAAM,CAAN,IAAY,aAoBX;AApBD,WAAY,aAAa;IACvB,4CAA4C;IAC5C,iDAAQ,CAAA;IACR,kEAAkE;IAClE,qDAAU,CAAA;IACV;;;;OAIG;IACH,2CAAY,QAAQ,CAAC,EAAE,KAAK,SAAS;QACnC,CAAC,CAAC,aAAa,CAAC,cAAc;QAC9B,CAAC,CAAC,aAAa,CAAC,gBAAgB,eAAA,CAAA;IAClC;;;OAGG;IACH,qEAAkB,CAAA;IAClB,oGAAoG;IACpG,yEAAoB,CAAA;AACtB,CAAC,EApBW,aAAa,KAAb,aAAa,QAoBxB;AAED,+FAA+F;AAC/F,8FAA8F;AAC9F,sEAAsE;AACtE,MAAM,CAAC,cAAc,CAAC,aAAa,EAAE,WAAW,EAAE;IAChD,GAAG;QACD,MAAM,iBAAiB,GACrB,QAAQ,CAAC,EAAE,KAAK,SAAS;YACvB,CAAC,CAAC,4IAA4I;YAC9I,CAAC,CAAC,EAAE,CAAC;QACT,OAAO,CAAC,IAAI,CACV,+HAA+H;YAC7H,iBAAiB,CACpB,CAAC;QACF,OAAO,QAAQ,CAAC,EAAE,KAAK,SAAS;YAC9B,CAAC,CAAC,aAAa,CAAC,cAAc;YAC9B,CAAC,CAAC,aAAa,CAAC,gBAAgB,CAAC;IACrC,CAAC;CACF,CAAC,CAAC"}
|
package/native-link.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"android": {
|
|
3
|
+
"gradleProjectName": "expo-local-authentication",
|
|
4
|
+
"modules": [
|
|
5
|
+
{
|
|
6
|
+
"importPath": "expo.modules.localauthentication.LocalAuthenticationModule",
|
|
7
|
+
"className": "LocalAuthenticationModule",
|
|
8
|
+
"nativeName": "ExpoLocalAuthentication"
|
|
9
|
+
}
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
"ios": {
|
|
13
|
+
"infoPlistKeys": {
|
|
14
|
+
"NSFaceIDUsageDescription": "This app uses Face ID to authenticate you."
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbiote-native/local-auth",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"description": "expo-local-authentication wrapped for SymbioteNative —
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "expo-local-authentication wrapped for SymbioteNative — one framework-agnostic core, built once and reachable from the React, Vue, and Angular adapters. FaceID/TouchID on iOS, the Fingerprint/Biometric API on Android.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -13,7 +13,114 @@
|
|
|
13
13
|
"url": "https://github.com/OneEyed1366/symbiote-native/issues"
|
|
14
14
|
},
|
|
15
15
|
"author": "Andrey Prokopenko <psevdoproger@gmail.com>",
|
|
16
|
+
"type": "module",
|
|
17
|
+
"main": "./build/core/index.js",
|
|
18
|
+
"module": "./build/core/index.js",
|
|
19
|
+
"types": "./build/core/index.d.ts",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./build/core/index.d.ts",
|
|
23
|
+
"default": "./build/core/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./vue": {
|
|
26
|
+
"types": "./build/vue/index.d.ts",
|
|
27
|
+
"default": "./build/vue/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./react": {
|
|
30
|
+
"types": "./build/react/index.d.ts",
|
|
31
|
+
"default": "./build/react/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./svelte": {
|
|
34
|
+
"types": "./build/svelte/index.d.ts",
|
|
35
|
+
"default": "./build/svelte/index.js"
|
|
36
|
+
},
|
|
37
|
+
"./angular": {
|
|
38
|
+
"types": "./build-ngc/angular/index.d.ts",
|
|
39
|
+
"react-native": "./build-ngc/angular/index.js",
|
|
40
|
+
"default": "./src/angular/index.ts"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"files": [
|
|
44
|
+
"src",
|
|
45
|
+
"build",
|
|
46
|
+
"build-ngc",
|
|
47
|
+
"native-link.json",
|
|
48
|
+
"!src/**/*.test.*",
|
|
49
|
+
"!src/**/*.spec.*",
|
|
50
|
+
"!src/**/*.detox.*"
|
|
51
|
+
],
|
|
16
52
|
"publishConfig": {
|
|
17
53
|
"access": "public"
|
|
54
|
+
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"expo-local-authentication": "57.0.2",
|
|
57
|
+
"expo-modules-core": "57.0.5",
|
|
58
|
+
"invariant": "^2.2.4"
|
|
59
|
+
},
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"@symbiote-native/angular": ">=0.6.2",
|
|
62
|
+
"@symbiote-native/engine": ">=0.1.7",
|
|
63
|
+
"@symbiote-native/react": ">=0.2.8",
|
|
64
|
+
"@symbiote-native/svelte": ">=0.1.0",
|
|
65
|
+
"@symbiote-native/vue": ">=0.3.8",
|
|
66
|
+
"@angular/core": ">=20",
|
|
67
|
+
"@vue/runtime-core": "^3.5.13",
|
|
68
|
+
"react": ">=19.0.0",
|
|
69
|
+
"react-native": ">=0.86",
|
|
70
|
+
"svelte": ">=5.56.0",
|
|
71
|
+
"vue": ">=3.5.0"
|
|
72
|
+
},
|
|
73
|
+
"peerDependenciesMeta": {
|
|
74
|
+
"@symbiote-native/angular": {
|
|
75
|
+
"optional": true
|
|
76
|
+
},
|
|
77
|
+
"@symbiote-native/react": {
|
|
78
|
+
"optional": true
|
|
79
|
+
},
|
|
80
|
+
"@symbiote-native/svelte": {
|
|
81
|
+
"optional": true
|
|
82
|
+
},
|
|
83
|
+
"@symbiote-native/vue": {
|
|
84
|
+
"optional": true
|
|
85
|
+
},
|
|
86
|
+
"@angular/core": {
|
|
87
|
+
"optional": true
|
|
88
|
+
},
|
|
89
|
+
"@vue/runtime-core": {
|
|
90
|
+
"optional": true
|
|
91
|
+
},
|
|
92
|
+
"react": {
|
|
93
|
+
"optional": true
|
|
94
|
+
},
|
|
95
|
+
"svelte": {
|
|
96
|
+
"optional": true
|
|
97
|
+
},
|
|
98
|
+
"vue": {
|
|
99
|
+
"optional": true
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
"devDependencies": {
|
|
103
|
+
"@angular/compiler": "~22.0.8",
|
|
104
|
+
"@angular/compiler-cli": "~22.0.8",
|
|
105
|
+
"@angular/core": "~22.0.8",
|
|
106
|
+
"@types/invariant": "^2.2.37",
|
|
107
|
+
"@types/node": "^26.0.0",
|
|
108
|
+
"@types/react": "^19.2.0",
|
|
109
|
+
"@vue/runtime-core": "^3.5.13",
|
|
110
|
+
"react": "19.2.3",
|
|
111
|
+
"svelte": "^5.56.0",
|
|
112
|
+
"typescript": "~6.0.0",
|
|
113
|
+
"@symbiote-native/angular": "0.7.0",
|
|
114
|
+
"@symbiote-native/engine": "0.2.0",
|
|
115
|
+
"@symbiote-native/react": "0.3.0",
|
|
116
|
+
"@symbiote-native/svelte": "0.2.0",
|
|
117
|
+
"@symbiote-native/test-utils": "0.1.6",
|
|
118
|
+
"@symbiote-native/vue": "0.4.0"
|
|
119
|
+
},
|
|
120
|
+
"scripts": {
|
|
121
|
+
"typecheck": "tsc --build",
|
|
122
|
+
"clean": "rm -rf build-ngc",
|
|
123
|
+
"ng:build": "pnpm run clean && ngc -p tsconfig.angular.json",
|
|
124
|
+
"format": "prettier --write \"src/**/*.{ts,tsx}\""
|
|
18
125
|
}
|
|
19
|
-
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export {
|
|
2
|
+
hasHardwareAsync,
|
|
3
|
+
supportedAuthenticationTypesAsync,
|
|
4
|
+
isEnrolledAsync,
|
|
5
|
+
getEnrolledLevelAsync,
|
|
6
|
+
authenticateAsync,
|
|
7
|
+
cancelAuthenticate,
|
|
8
|
+
} from './local-authentication';
|
|
9
|
+
export {
|
|
10
|
+
AuthenticationType,
|
|
11
|
+
SecurityLevel,
|
|
12
|
+
type IBiometricsSecurityLevel,
|
|
13
|
+
type ILocalAuthenticationOptions,
|
|
14
|
+
type ILocalAuthenticationResult,
|
|
15
|
+
type ILocalAuthenticationError,
|
|
16
|
+
} from './types';
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { UnavailabilityError } from 'expo-modules-core';
|
|
2
|
+
import invariant from 'invariant';
|
|
3
|
+
|
|
4
|
+
import { expoLocalAuthentication } from './native-module';
|
|
5
|
+
import type {
|
|
6
|
+
AuthenticationType,
|
|
7
|
+
ILocalAuthenticationOptions,
|
|
8
|
+
ILocalAuthenticationResult,
|
|
9
|
+
SecurityLevel,
|
|
10
|
+
} from './types';
|
|
11
|
+
|
|
12
|
+
const NATIVE_MODULE_NAME = 'expo-local-authentication';
|
|
13
|
+
const DEFAULT_PROMPT_MESSAGE = 'Authenticate';
|
|
14
|
+
const DEFAULT_CANCEL_LABEL = 'Cancel';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Determine whether a face or fingerprint scanner is available on the device.
|
|
18
|
+
*/
|
|
19
|
+
export async function hasHardwareAsync(): Promise<boolean> {
|
|
20
|
+
if (!expoLocalAuthentication.hasHardwareAsync) {
|
|
21
|
+
throw new UnavailabilityError(NATIVE_MODULE_NAME, 'hasHardwareAsync');
|
|
22
|
+
}
|
|
23
|
+
return expoLocalAuthentication.hasHardwareAsync();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Determine what kinds of authentications are available on the device. Devices can support
|
|
28
|
+
* multiple authentication methods — e.g. `[FINGERPRINT, FACIAL_RECOGNITION]` means the device
|
|
29
|
+
* supports both. Returns an empty array if none are supported.
|
|
30
|
+
*/
|
|
31
|
+
export async function supportedAuthenticationTypesAsync(): Promise<AuthenticationType[]> {
|
|
32
|
+
if (!expoLocalAuthentication.supportedAuthenticationTypesAsync) {
|
|
33
|
+
throw new UnavailabilityError(NATIVE_MODULE_NAME, 'supportedAuthenticationTypesAsync');
|
|
34
|
+
}
|
|
35
|
+
return expoLocalAuthentication.supportedAuthenticationTypesAsync();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Determine whether the device has saved fingerprints or facial data to use for authentication.
|
|
40
|
+
*/
|
|
41
|
+
export async function isEnrolledAsync(): Promise<boolean> {
|
|
42
|
+
if (!expoLocalAuthentication.isEnrolledAsync) {
|
|
43
|
+
throw new UnavailabilityError(NATIVE_MODULE_NAME, 'isEnrolledAsync');
|
|
44
|
+
}
|
|
45
|
+
return expoLocalAuthentication.isEnrolledAsync();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Determine what kind of authentication is enrolled on the device.
|
|
50
|
+
* > On Android devices prior to M, `SECRET` can be returned if only the SIM lock has been
|
|
51
|
+
* enrolled, which is not the method `authenticateAsync` prompts.
|
|
52
|
+
*/
|
|
53
|
+
export async function getEnrolledLevelAsync(): Promise<SecurityLevel> {
|
|
54
|
+
if (!expoLocalAuthentication.getEnrolledLevelAsync) {
|
|
55
|
+
throw new UnavailabilityError(NATIVE_MODULE_NAME, 'getEnrolledLevelAsync');
|
|
56
|
+
}
|
|
57
|
+
return expoLocalAuthentication.getEnrolledLevelAsync();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Attempts to authenticate via Fingerprint/TouchID (or FaceID if available on the device).
|
|
62
|
+
* > Apple requires apps which use FaceID to provide a description of why they use this API
|
|
63
|
+
* (`NSFaceIDUsageDescription` in `Info.plist`). Without it, the module authenticates using the
|
|
64
|
+
* device passcode instead.
|
|
65
|
+
*/
|
|
66
|
+
export async function authenticateAsync(
|
|
67
|
+
options: ILocalAuthenticationOptions = {},
|
|
68
|
+
): Promise<ILocalAuthenticationResult> {
|
|
69
|
+
if (!expoLocalAuthentication.authenticateAsync) {
|
|
70
|
+
throw new UnavailabilityError(NATIVE_MODULE_NAME, 'authenticateAsync');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (options.promptMessage !== undefined) {
|
|
74
|
+
invariant(
|
|
75
|
+
typeof options.promptMessage === 'string' && options.promptMessage.length > 0,
|
|
76
|
+
'LocalAuthentication.authenticateAsync: `options.promptMessage` must be a non-empty string.',
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return expoLocalAuthentication.authenticateAsync({
|
|
81
|
+
...options,
|
|
82
|
+
promptMessage: options.promptMessage || DEFAULT_PROMPT_MESSAGE,
|
|
83
|
+
cancelLabel: options.cancelLabel || DEFAULT_CANCEL_LABEL,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Cancels the authentication flow.
|
|
89
|
+
* @platform android
|
|
90
|
+
*/
|
|
91
|
+
export async function cancelAuthenticate(): Promise<void> {
|
|
92
|
+
if (!expoLocalAuthentication.cancelAuthenticate) {
|
|
93
|
+
throw new UnavailabilityError(NATIVE_MODULE_NAME, 'cancelAuthenticate');
|
|
94
|
+
}
|
|
95
|
+
await expoLocalAuthentication.cancelAuthenticate();
|
|
96
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { requireNativeModule } from 'expo-modules-core';
|
|
2
|
+
import type {
|
|
3
|
+
AuthenticationType,
|
|
4
|
+
ILocalAuthenticationOptions,
|
|
5
|
+
ILocalAuthenticationResult,
|
|
6
|
+
SecurityLevel,
|
|
7
|
+
} from './types';
|
|
8
|
+
|
|
9
|
+
const EXPO_LOCAL_AUTHENTICATION_MODULE_NAME = 'ExpoLocalAuthentication';
|
|
10
|
+
|
|
11
|
+
// Every method is optional — each call site checks for its presence before calling through and
|
|
12
|
+
// throws an UnavailabilityError itself, matching upstream's own per-platform capability checks
|
|
13
|
+
// rather than assuming the native module implements the whole surface.
|
|
14
|
+
export type INativeLocalAuthenticationModule = {
|
|
15
|
+
hasHardwareAsync?(): Promise<boolean>;
|
|
16
|
+
supportedAuthenticationTypesAsync?(): Promise<AuthenticationType[]>;
|
|
17
|
+
isEnrolledAsync?(): Promise<boolean>;
|
|
18
|
+
getEnrolledLevelAsync?(): Promise<SecurityLevel>;
|
|
19
|
+
authenticateAsync?(
|
|
20
|
+
options: ILocalAuthenticationOptions & { promptMessage: string; cancelLabel: string },
|
|
21
|
+
): Promise<ILocalAuthenticationResult>;
|
|
22
|
+
cancelAuthenticate?(): Promise<void>;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const expoLocalAuthentication = requireNativeModule<INativeLocalAuthenticationModule>(
|
|
26
|
+
EXPO_LOCAL_AUTHENTICATION_MODULE_NAME,
|
|
27
|
+
);
|