-
Notifications
You must be signed in to change notification settings - Fork 16
/
error.ts
259 lines (235 loc) · 7.31 KB
/
error.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
import { AuthgearError, CancelError } from "@authgear/core";
// On iOS, the arguments passed to RCTPromiseRejectBlock
// will be processed by RCTJSErrorFromCodeMessageAndNSError.
//
// The error shape is
// {
// "code": "The first argument of RCTPromiseRejectBlock"
// "domain": "The domain of the third argument",
// "userInfo": "The userInfo of the third argument"
// }
// iOS LocalAuthentication
const kLAErrorDomain = "com.apple.LocalAuthentication";
// const kLAErrorAuthenticationFailed = "-1";
const kLAErrorUserCancel = "-2";
// const kLAErrorUserFallback = "-3";
// const kLAErrorSystemCancel = "-4";
const kLAErrorPasscodeNotSet = "-5";
// const kLAErrorAppCancel = "-9";
// const kLAErrorInvalidContext = "-10";
// const kLAErrorWatchNotAvailable = "-11";
// const kLAErrorNotInteractive = "-1004";
const kLAErrorBiometryNotAvailable = "-6";
const kLAErrorBiometryNotEnrolled = "-7";
const kLAErrorBiometryLockout = "-8";
// iOS Keychain
const NSOSStatusErrorDomain = "NSOSStatusErrorDomain";
const errSecUserCanceled = "-128";
// const errSecAuthFailed = "-25293";
const errSecItemNotFound = "-25300";
// Android BiometricManager.canAuthenticate
const BIOMETRIC_ERROR_HW_UNAVAILABLE = "BIOMETRIC_ERROR_HW_UNAVAILABLE";
const BIOMETRIC_ERROR_NONE_ENROLLED = "BIOMETRIC_ERROR_NONE_ENROLLED";
const BIOMETRIC_ERROR_NO_HARDWARE = "BIOMETRIC_ERROR_NO_HARDWARE";
const BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED =
"BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED";
const BIOMETRIC_ERROR_UNSUPPORTED = "BIOMETRIC_ERROR_UNSUPPORTED";
// const BIOMETRIC_STATUS_UNKNOWN = "BIOMETRIC_STATUS_UNKNOWN";
// Android BiometricPrompt
const ERROR_CANCELED = "ERROR_CANCELED";
const ERROR_HW_NOT_PRESENT = "ERROR_HW_NOT_PRESENT";
const ERROR_HW_UNAVAILABLE = "ERROR_HW_UNAVAILABLE";
const ERROR_LOCKOUT = "ERROR_LOCKOUT";
const ERROR_LOCKOUT_PERMANENT = "ERROR_LOCKOUT_PERMANENT";
const ERROR_NEGATIVE_BUTTON = "ERROR_NEGATIVE_BUTTON";
const ERROR_NO_BIOMETRICS = "ERROR_NO_BIOMETRICS";
const ERROR_NO_DEVICE_CREDENTIAL = "ERROR_NO_DEVICE_CREDENTIAL";
// const ERROR_NO_SPACE = "ERROR_NO_SPACE";
const ERROR_SECURITY_UPDATE_REQUIRED = "ERROR_SECURITY_UPDATE_REQUIRED";
// const ERROR_TIMEOUT = "ERROR_TIMEOUT";
// const ERROR_UNABLE_TO_PROCESS = "ERROR_UNABLE_TO_PROCESS";
const ERROR_USER_CANCELED = "ERROR_USER_CANCELED";
// const ERROR_VENDOR = "ERROR_VENDOR";
export interface PlatformErrorIOS {
code: string;
domain: string;
userInfo?: unknown;
}
export interface PlatformErrorAndroid {
code: string;
userInfo?: unknown;
}
export function isPlatformErrorIOS(e: unknown): e is PlatformErrorIOS {
return typeof e === "object" && e != null && "domain" in e && "code" in e;
}
export function isPlatformErrorAndroid(e: unknown): e is PlatformErrorAndroid {
return typeof e === "object" && e != null && "code" in e;
}
/**
* BiometricPrivateKeyNotFoundError means the biometric has changed so that
* the private key has been invalidated.
*
* @public
*/
export class BiometricPrivateKeyNotFoundError extends AuthgearError {}
/**
* BiometricNotSupportedOrPermissionDeniedError means this device does not support biometric,
* or the user has denied the usage of biometric.
*
* @public
*/
export class BiometricNotSupportedOrPermissionDeniedError extends AuthgearError {}
/**
* BiometricNoPasscodeError means the device does not have a passcode.
* You should prompt the user to setup a password for their device.
*
* @public
*/
export class BiometricNoPasscodeError extends AuthgearError {}
/**
* BiometricNoEnrollmentError means the user has not setup biometric.
* You should prompt the user to do so.
*
* @public
*/
export class BiometricNoEnrollmentError extends AuthgearError {}
/**
* BiometricLockoutError means the biometric is locked due to too many failed attempts.
*
* @public
*/
export class BiometricLockoutError extends AuthgearError {}
type _ErrorIdentificationFunction = (e: unknown) => boolean;
const _errorMappings: [_ErrorIdentificationFunction, typeof AuthgearError][] = [
[_isBiometricPrivateKeyNotFoundError, BiometricPrivateKeyNotFoundError],
[_isBiometricCancel, CancelError],
[
_isBiometricNotSupportedOrPermissionDeniedError,
BiometricNotSupportedOrPermissionDeniedError,
],
[_isBiometricNoEnrollmentError, BiometricNoEnrollmentError],
[_isBiometricNoPasscodeError, BiometricNoPasscodeError],
[_isBiometricLockoutError, BiometricLockoutError],
[_isCancel, CancelError],
];
/**
* @internal
*/
export function _wrapError(e: unknown): unknown {
for (const [f, cls] of _errorMappings) {
if (f(e)) {
const err = new cls();
err.underlyingError = e;
return err;
}
}
const err = new AuthgearError();
err.underlyingError = e;
return err;
}
export function _isCancel(e: unknown): boolean {
if (isPlatformErrorIOS(e)) {
return e.code === "CANCEL";
}
if (isPlatformErrorAndroid(e)) {
return e.code === "CANCEL";
}
return false;
}
/**
* @internal
*/
export function _isBiometricPrivateKeyNotFoundError(e: unknown): boolean {
if (isPlatformErrorIOS(e)) {
return e.domain === NSOSStatusErrorDomain && e.code === errSecItemNotFound;
}
if (isPlatformErrorAndroid(e)) {
return (
e.code === "android.security.keystore.KeyPermanentlyInvalidatedException"
);
}
return false;
}
/**
* @internal
*/
export function _isBiometricCancel(e: unknown): boolean {
if (isPlatformErrorIOS(e)) {
return (
(e.domain === kLAErrorDomain && e.code === kLAErrorUserCancel) ||
(e.domain === NSOSStatusErrorDomain && e.code === errSecUserCanceled)
);
}
if (isPlatformErrorAndroid(e)) {
return (
e.code === ERROR_CANCELED ||
e.code === ERROR_NEGATIVE_BUTTON ||
e.code === ERROR_USER_CANCELED
);
}
return false;
}
/**
* @internal
*/
export function _isBiometricNotSupportedOrPermissionDeniedError(
e: unknown
): boolean {
if (isPlatformErrorIOS(e)) {
return (
e.domain === kLAErrorDomain && e.code === kLAErrorBiometryNotAvailable
);
}
if (isPlatformErrorAndroid(e)) {
return (
e.code === BIOMETRIC_ERROR_HW_UNAVAILABLE ||
e.code === BIOMETRIC_ERROR_NO_HARDWARE ||
e.code === BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED ||
e.code === BIOMETRIC_ERROR_UNSUPPORTED ||
e.code === ERROR_HW_NOT_PRESENT ||
e.code === ERROR_HW_UNAVAILABLE ||
e.code === ERROR_SECURITY_UPDATE_REQUIRED
);
}
return false;
}
/**
* @internal
*/
export function _isBiometricNoEnrollmentError(e: unknown): boolean {
if (isPlatformErrorIOS(e)) {
return (
e.domain === kLAErrorDomain && e.code === kLAErrorBiometryNotEnrolled
);
}
if (isPlatformErrorAndroid(e)) {
return (
e.code === BIOMETRIC_ERROR_NONE_ENROLLED || e.code === ERROR_NO_BIOMETRICS
);
}
return false;
}
/**
* @internal
*/
export function _isBiometricNoPasscodeError(e: unknown): boolean {
if (isPlatformErrorIOS(e)) {
return e.domain === kLAErrorDomain && e.code === kLAErrorPasscodeNotSet;
}
if (isPlatformErrorAndroid(e)) {
return e.code === ERROR_NO_DEVICE_CREDENTIAL;
}
return false;
}
/**
* @internal
*/
export function _isBiometricLockoutError(e: unknown): boolean {
if (isPlatformErrorIOS(e)) {
return e.domain === kLAErrorDomain && e.code === kLAErrorBiometryLockout;
}
if (isPlatformErrorAndroid(e)) {
return e.code === ERROR_LOCKOUT || e.code === ERROR_LOCKOUT_PERMANENT;
}
return false;
}