@navette-js/panels 1.0.0-beta.3 → 1.0.0-beta.5
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/THIRD-PARTY-NOTICES.md +2 -1
- package/dist/navette/navette/calendar.css +5 -5
- package/dist/navette/navette/motion.css +21 -21
- package/dist/navette/navette/motion.js +6 -6
- package/dist/navette/navette/security-keys.css +11 -0
- package/dist/navette/navette/security-keys.js +72 -0
- package/lib/auth.d.ts +17 -0
- package/lib/auth.js +70 -0
- package/lib/error-pages.d.ts +9 -0
- package/lib/error-pages.js +173 -0
- package/lib/import-export.d.ts +185 -0
- package/lib/import-export.js +543 -0
- package/lib/index.d.ts +629 -79
- package/lib/index.js +1945 -333
- package/lib/multi-factor.d.ts +348 -0
- package/lib/multi-factor.js +928 -0
- package/lib/notifications.d.ts +20 -2
- package/lib/notifications.js +34 -4
- package/lib/qr-code.d.ts +16 -0
- package/lib/qr-code.js +255 -0
- package/lib/session-store.d.ts +21 -0
- package/lib/session-store.js +35 -0
- package/lib/throttle.d.ts +10 -0
- package/lib/throttle.js +25 -0
- package/lib/topbar.d.ts +3 -1
- package/lib/topbar.js +18 -1
- package/lib/totp.d.ts +38 -0
- package/lib/totp.js +104 -0
- package/lib/webauthn.d.ts +155 -0
- package/lib/webauthn.js +287 -0
- package/lib/xlsx.d.ts +7 -0
- package/lib/xlsx.js +171 -0
- package/package.json +9 -9
- package/views/components/tenant-menu.ejs +3 -3
- package/views/components/user-menu.ejs +3 -2
- package/views/errors/page.ejs +87 -0
- package/views/layout/base.ejs +9 -1
- package/views/livewire/sidebar.ejs +35 -20
- package/views/livewire/topbar.ejs +1 -1
- package/views/pages/page.ejs +53 -35
- package/views/pages/simple.ejs +4 -0
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
import { Action } from '@navette-js/actions';
|
|
2
|
+
import { Field, OneTimeCodeInput } from '@navette-js/forms';
|
|
3
|
+
import { Component, type ComponentContext } from '@navette-js/schemas';
|
|
4
|
+
import { Throttle } from './throttle.ts';
|
|
5
|
+
import { type TotpAlgorithm } from './totp.ts';
|
|
6
|
+
import { type UserVerification } from './webauthn.ts';
|
|
7
|
+
import type { AuthProvider, Panel, User } from './index.ts';
|
|
8
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
9
|
+
/**
|
|
10
|
+
* A way to prove one's identity after the password. Register providers with `panel.multiFactorAuthentication([...])`.
|
|
11
|
+
* Each provider's state lives under its id: the challenge form fields under `data.multiFactor.<id>`.
|
|
12
|
+
*/
|
|
13
|
+
export interface MultiFactorAuthenticationProvider {
|
|
14
|
+
/** Unique id, used as the state path of its components (`app`, `security-keys`…). Letters, digits, `-` and `_`. */
|
|
15
|
+
getId(): string;
|
|
16
|
+
/** Label of the provider in the picker shown when a user has several. */
|
|
17
|
+
getLoginFormLabel(): string;
|
|
18
|
+
/** Whether the user has set this provider up. */
|
|
19
|
+
isEnabled(user: User, panel: Panel): MaybePromise<boolean>;
|
|
20
|
+
/** Components shown on the profile page (and the required setup page): status and actions to set up or disable. */
|
|
21
|
+
getManagementSchemaComponents(user: User, panel: Panel): Component[];
|
|
22
|
+
/** Fields of the login challenge. Their validation rules decide whether the challenge passes. */
|
|
23
|
+
getChallengeFormComponents(user: User, panel: Panel): Component[];
|
|
24
|
+
/** Runs when the challenge is shown, or when the user picks this provider (send a code by SMS…). */
|
|
25
|
+
beforeChallenge?(user: User, panel: Panel): MaybePromise<void>;
|
|
26
|
+
/** Called when the panel router is built: throw if something the provider needs is missing (its storage…). */
|
|
27
|
+
checkConfiguration?(panel: Panel): void;
|
|
28
|
+
}
|
|
29
|
+
/** Short-lived values: used codes (replay protection) and pending WebAuthn challenges. */
|
|
30
|
+
export interface MultiFactorCacheStore {
|
|
31
|
+
get(key: string): MaybePromise<unknown>;
|
|
32
|
+
put(key: string, value: unknown, ttlSeconds: number): MaybePromise<void>;
|
|
33
|
+
forget(key: string): MaybePromise<void>;
|
|
34
|
+
}
|
|
35
|
+
/** In-memory store: fine for a single process. When running several, use a shared store (Redis…) with `cacheStore()`. */
|
|
36
|
+
export declare class MemoryCacheStore implements MultiFactorCacheStore {
|
|
37
|
+
private entries;
|
|
38
|
+
private max;
|
|
39
|
+
constructor(max?: number);
|
|
40
|
+
get(key: string): unknown;
|
|
41
|
+
put(key: string, value: unknown, ttlSeconds: number): void;
|
|
42
|
+
forget(key: string): void;
|
|
43
|
+
}
|
|
44
|
+
/** Store used by the providers that do not set their own `cacheStore()`. */
|
|
45
|
+
export declare const useMultiFactorCacheStore: (store: MultiFactorCacheStore) => void;
|
|
46
|
+
/** The store of short-lived values shared by authentication features (multi-factor codes, email change blocks). */
|
|
47
|
+
export declare const getDefaultCacheStore: () => MultiFactorCacheStore;
|
|
48
|
+
/** The login challenge: enabled providers, the picker, rate limiting. */
|
|
49
|
+
export declare class MultiFactorChallenge {
|
|
50
|
+
/** Attempts per user and per minute. */
|
|
51
|
+
static maxAttempts: number;
|
|
52
|
+
private static throttle;
|
|
53
|
+
private panel;
|
|
54
|
+
constructor(panel: Panel);
|
|
55
|
+
static make(panel: Panel): MultiFactorChallenge;
|
|
56
|
+
getProviders(): MultiFactorAuthenticationProvider[];
|
|
57
|
+
getEnabledProviders(user: User): Promise<MultiFactorAuthenticationProvider[]>;
|
|
58
|
+
hasEnabledProviders(user: User): Promise<boolean>;
|
|
59
|
+
beforeChallenge(user: User, provider?: MultiFactorAuthenticationProvider): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* Challenge fields for these enabled providers: a picker when there are several, then each provider's fields under its id
|
|
62
|
+
* (only the picked provider's are shown and validated).
|
|
63
|
+
*/
|
|
64
|
+
getFormComponents(user: User, enabled: MultiFactorAuthenticationProvider[]): Component[];
|
|
65
|
+
private static limiter;
|
|
66
|
+
/** Records an attempt; returns 0 if allowed, otherwise the seconds to wait. */
|
|
67
|
+
hitRateLimiter(user: User): number;
|
|
68
|
+
clearRateLimiter(user: User): void;
|
|
69
|
+
}
|
|
70
|
+
/** Where app authentication data is kept; by default, the panel's auth provider (`knexAuthProvider` stores it in the users table). */
|
|
71
|
+
export type AppAuthenticationStore = Required<Pick<AuthProvider, 'getAppAuthenticationSecret' | 'saveAppAuthenticationSecret'>> & Partial<Pick<AuthProvider, 'getAppAuthenticationRecoveryCodes' | 'saveAppAuthenticationRecoveryCodes'>>;
|
|
72
|
+
/** Encrypts a TOTP secret at rest (AES-256-GCM, with a key derived from the panel key). */
|
|
73
|
+
export declare function encryptSecret(panel: Panel, secret: string): string;
|
|
74
|
+
/** Decrypts a stored secret; a value without the prefix is returned as is (secrets stored in clear by your own code). `null` when it cannot be read. */
|
|
75
|
+
export declare function decryptSecret(panel: Panel, stored: string): string | null;
|
|
76
|
+
/**
|
|
77
|
+
* Authentication with a code from an authenticator app (Google Authenticator, Microsoft Authenticator, 1Password…):
|
|
78
|
+
* time-based one-time passwords (RFC 6238). `recoverable()` adds single-use recovery codes.
|
|
79
|
+
*/
|
|
80
|
+
export declare class AppAuthentication implements MultiFactorAuthenticationProvider {
|
|
81
|
+
protected _id: string;
|
|
82
|
+
protected _recoverable: boolean;
|
|
83
|
+
protected _regenerableRecoveryCodes: boolean;
|
|
84
|
+
protected _recoveryCodeCount: number;
|
|
85
|
+
protected _brandName: string | null;
|
|
86
|
+
protected _codeWindow: number;
|
|
87
|
+
protected _digits: number;
|
|
88
|
+
protected _period: number;
|
|
89
|
+
protected _algorithm: TotpAlgorithm;
|
|
90
|
+
protected _store: AppAuthenticationStore | null;
|
|
91
|
+
protected _cacheStore: MultiFactorCacheStore | null;
|
|
92
|
+
protected _confirmsPassword: boolean;
|
|
93
|
+
protected _generateRecoveryCodes: (() => string[]) | null;
|
|
94
|
+
protected setupThrottle: Throttle;
|
|
95
|
+
protected managementThrottle: Throttle;
|
|
96
|
+
static make(): AppAuthentication;
|
|
97
|
+
getId(): string;
|
|
98
|
+
/** Changes the id (to register two app providers with different settings). */
|
|
99
|
+
id(id: string): this;
|
|
100
|
+
getLoginFormLabel(): string;
|
|
101
|
+
/** Single-use recovery codes, shown once at setup, to sign in without the app. Needs `get`/`saveAppAuthenticationRecoveryCodes` on the store. */
|
|
102
|
+
recoverable(condition?: boolean): this;
|
|
103
|
+
isRecoverable(): boolean;
|
|
104
|
+
/** `false`: users cannot regenerate their recovery codes. */
|
|
105
|
+
regenerableRecoveryCodes(condition?: boolean): this;
|
|
106
|
+
canRegenerateRecoveryCodes(): boolean;
|
|
107
|
+
recoveryCodeCount(count: number): this;
|
|
108
|
+
getRecoveryCodeCount(): number;
|
|
109
|
+
/** Generates the recovery codes (by default, `xxxxxxxxxx-xxxxxxxxxx` from 62 characters). */
|
|
110
|
+
generateRecoveryCodesUsing(callback: (() => string[]) | null): this;
|
|
111
|
+
/** Name shown in the app, next to the account (the panel's brand name by default). */
|
|
112
|
+
brandName(name: string | null): this;
|
|
113
|
+
getBrandName(panel: Panel): string;
|
|
114
|
+
/** Codes accepted before and after the current one, to allow for clock drift (1 by default: ±30 seconds). */
|
|
115
|
+
codeWindow(window: number): this;
|
|
116
|
+
getCodeWindow(): number;
|
|
117
|
+
/** Code settings. Most apps only support the defaults (6 digits, 30 seconds, SHA-1). */
|
|
118
|
+
codeOptions(options: {
|
|
119
|
+
digits?: number;
|
|
120
|
+
period?: number;
|
|
121
|
+
algorithm?: TotpAlgorithm;
|
|
122
|
+
}): this;
|
|
123
|
+
/** Where secrets and recovery codes are stored (the panel's auth provider by default). */
|
|
124
|
+
store(store: AppAuthenticationStore | null): this;
|
|
125
|
+
/** Where used codes are remembered (replay protection). */
|
|
126
|
+
cacheStore(store: MultiFactorCacheStore | null): this;
|
|
127
|
+
/** `false`: setting up and turning off do not ask for the current password (accounts without one). */
|
|
128
|
+
confirmsPassword(condition?: boolean): this;
|
|
129
|
+
protected getStore(panel: Panel): AppAuthenticationStore;
|
|
130
|
+
protected codeOptionsOf(): {
|
|
131
|
+
digits: number;
|
|
132
|
+
period: number;
|
|
133
|
+
algorithm: TotpAlgorithm;
|
|
134
|
+
};
|
|
135
|
+
checkConfiguration(panel: Panel): void;
|
|
136
|
+
isEnabled(user: User, panel: Panel): Promise<boolean>;
|
|
137
|
+
/** The user's secret, decrypted; `null` when none is set or it cannot be decrypted (the panel key changed). */
|
|
138
|
+
getSecret(user: User, panel: Panel): Promise<string | null>;
|
|
139
|
+
saveSecret(user: User, panel: Panel, secret: string | null): Promise<void>;
|
|
140
|
+
generateSecret(): string;
|
|
141
|
+
generateRecoveryCodes(): string[];
|
|
142
|
+
/** Saves recovery codes (hashed): `null` removes them. */
|
|
143
|
+
saveRecoveryCodes(user: User, panel: Panel, codes: string[] | null): Promise<void>;
|
|
144
|
+
/** `otpauth://` URI of a secret, for the QR code. */
|
|
145
|
+
getUri(user: User, panel: Panel, secret: string): string;
|
|
146
|
+
/** QR code of a secret, as a `data:` URI. */
|
|
147
|
+
generateQrCodeDataUri(user: User, panel: Panel, secret: string): string;
|
|
148
|
+
/**
|
|
149
|
+
* Checks a code. With `preventReuse` (sign-in and sensitive actions), a code is accepted once: the time step of the last
|
|
150
|
+
* accepted code is remembered, and that code and every earlier one are refused (RFC 6238 §5.2).
|
|
151
|
+
*/
|
|
152
|
+
verifyCode(code: unknown, secret: string, options?: {
|
|
153
|
+
preventReuse?: boolean;
|
|
154
|
+
}): Promise<boolean>;
|
|
155
|
+
/** Checks a recovery code and removes it: each one works once. */
|
|
156
|
+
verifyRecoveryCode(code: unknown, user: User, panel: Panel): Promise<boolean>;
|
|
157
|
+
getChallengeFormComponents(user: User, panel: Panel): Component[];
|
|
158
|
+
getManagementSchemaComponents(user: User, panel: Panel): Component[];
|
|
159
|
+
getActions(user: User, panel: Panel): Action[];
|
|
160
|
+
/** Setup modal: QR code and secret, a code from the app (and the password), then the recovery codes. */
|
|
161
|
+
setUpAction(panel: Panel): Action;
|
|
162
|
+
/** Recovery codes, with "copy" and "download" links. */
|
|
163
|
+
protected recoveryCodesContent(codes: (ctx: ComponentContext) => string[], instruction: string): Component[];
|
|
164
|
+
/** Fields confirming a sensitive action: a code from the app (or a recovery code) and, optionally, the password. */
|
|
165
|
+
protected confirmationFields(panel: Panel, group: string, options: {
|
|
166
|
+
recoveryCodes: boolean;
|
|
167
|
+
}): Component[];
|
|
168
|
+
/** Turns app authentication off, after a code (or a recovery code) and the password. */
|
|
169
|
+
disableAction(panel: Panel): Action;
|
|
170
|
+
/** Replaces the recovery codes, after a code from the app and the password; the new codes are shown once. */
|
|
171
|
+
regenerateRecoveryCodesAction(panel: Panel): Action;
|
|
172
|
+
/** Shows recovery codes just generated; only opened by `regenerateRecoveryCodesAction()`. */
|
|
173
|
+
showNewRecoveryCodesAction(panel: Panel): Action;
|
|
174
|
+
}
|
|
175
|
+
/** A registered security key or passkey. */
|
|
176
|
+
export type SecurityKey = {
|
|
177
|
+
id: string | number;
|
|
178
|
+
name: string;
|
|
179
|
+
credentialId: string;
|
|
180
|
+
publicKey: string;
|
|
181
|
+
algorithm: number;
|
|
182
|
+
signCount: number;
|
|
183
|
+
transports: string[];
|
|
184
|
+
createdAt: string | null;
|
|
185
|
+
lastUsedAt: string | null;
|
|
186
|
+
};
|
|
187
|
+
/** Where security keys are kept; by default, the panel's auth provider (`knexAuthProvider` uses a `security_keys` table). */
|
|
188
|
+
export type SecurityKeyStore = Required<Pick<AuthProvider, 'getSecurityKeys' | 'createSecurityKey' | 'updateSecurityKey' | 'deleteSecurityKey'>>;
|
|
189
|
+
/** Field running a WebAuthn ceremony in the browser; its state is the credential (JSON) the browser returns. */
|
|
190
|
+
export declare class SecurityKeyInput extends Field {
|
|
191
|
+
protected _mode: 'register' | 'authenticate';
|
|
192
|
+
protected _optionsUsing: ((field: SecurityKeyInput) => MaybePromise<Record<string, unknown> | null>) | null;
|
|
193
|
+
protected _submitOnSuccess: boolean;
|
|
194
|
+
protected _autoStart: boolean;
|
|
195
|
+
protected _buttonLabel: string | null;
|
|
196
|
+
static make(name: string): SecurityKeyInput;
|
|
197
|
+
/** `register`: adds a key (`navigator.credentials.create()`); `authenticate`: uses one (`navigator.credentials.get()`). */
|
|
198
|
+
mode(mode: 'register' | 'authenticate'): this;
|
|
199
|
+
/** Options of the ceremony, asked for by the browser when the user clicks the button. */
|
|
200
|
+
optionsUsing(callback: (field: SecurityKeyInput) => MaybePromise<Record<string, unknown> | null>): this;
|
|
201
|
+
/** Submits the form as soon as the key answered. */
|
|
202
|
+
submitOnSuccess(condition?: boolean): this;
|
|
203
|
+
/** Starts the ceremony when the field appears (browsers may still require a click). */
|
|
204
|
+
autoStart(condition?: boolean): this;
|
|
205
|
+
buttonLabel(label: string | null): this;
|
|
206
|
+
getExposedMethods(): string[];
|
|
207
|
+
getPublicKeyOptions(): Promise<Record<string, unknown> | null>;
|
|
208
|
+
hydrateState(value: unknown): unknown;
|
|
209
|
+
toHtml(): Promise<string>;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Authentication with a security key: a hardware key (YubiKey, Titan…) or a passkey stored by the device or a password
|
|
213
|
+
* manager (WebAuthn). Users can register several keys. Needs a secure context: HTTPS, or `localhost` in development.
|
|
214
|
+
*/
|
|
215
|
+
export declare class SecurityKeyAuthentication implements MultiFactorAuthenticationProvider {
|
|
216
|
+
protected _id: string;
|
|
217
|
+
protected _rpId: string | null;
|
|
218
|
+
protected _rpName: string | null;
|
|
219
|
+
protected _origins: string[] | null;
|
|
220
|
+
protected _userVerification: UserVerification;
|
|
221
|
+
protected _authenticatorAttachment: 'platform' | 'cross-platform' | null;
|
|
222
|
+
protected _residentKey: 'required' | 'preferred' | 'discouraged';
|
|
223
|
+
protected _timeout: number;
|
|
224
|
+
protected _maxKeys: number;
|
|
225
|
+
protected _store: SecurityKeyStore | null;
|
|
226
|
+
protected _cacheStore: MultiFactorCacheStore | null;
|
|
227
|
+
protected _confirmsPassword: boolean;
|
|
228
|
+
protected throttle: Throttle;
|
|
229
|
+
static make(): SecurityKeyAuthentication;
|
|
230
|
+
getId(): string;
|
|
231
|
+
id(id: string): this;
|
|
232
|
+
getLoginFormLabel(): string;
|
|
233
|
+
/** Relying party id: the domain the keys are bound to (by default, the host of `panel.appUrl()` or of the request). */
|
|
234
|
+
relyingPartyId(id: string | null): this;
|
|
235
|
+
/** Name shown by the browser while registering a key (the panel's brand name by default). */
|
|
236
|
+
relyingPartyName(name: string | null): this;
|
|
237
|
+
/** Origins allowed to use the keys (`https://admin.example.com`); by default, the origin of `panel.appUrl()` or of the request. */
|
|
238
|
+
origins(origins: string[] | null): this;
|
|
239
|
+
/** `required`: the key must check a PIN or biometrics; `preferred` (default): when it can. */
|
|
240
|
+
userVerification(requirement: UserVerification): this;
|
|
241
|
+
/** Restricts registration to keys built into the device (`platform`) or to removable ones (`cross-platform`). */
|
|
242
|
+
authenticatorAttachment(attachment: 'platform' | 'cross-platform' | null): this;
|
|
243
|
+
/** Asks for a discoverable credential (passkey) when registering. */
|
|
244
|
+
residentKey(requirement: 'required' | 'preferred' | 'discouraged'): this;
|
|
245
|
+
/** Milliseconds the browser waits for the key (2 minutes by default). */
|
|
246
|
+
timeout(milliseconds: number): this;
|
|
247
|
+
/** Keys a user may register (10 by default). */
|
|
248
|
+
maxKeys(count: number): this;
|
|
249
|
+
store(store: SecurityKeyStore | null): this;
|
|
250
|
+
/** Where pending challenges are kept between the two requests of a ceremony. */
|
|
251
|
+
cacheStore(store: MultiFactorCacheStore | null): this;
|
|
252
|
+
/** `false`: adding and removing keys do not ask for the current password. */
|
|
253
|
+
confirmsPassword(condition?: boolean): this;
|
|
254
|
+
protected getStore(panel: Panel): SecurityKeyStore;
|
|
255
|
+
checkConfiguration(panel: Panel): void;
|
|
256
|
+
getKeys(user: User, panel: Panel): Promise<SecurityKey[]>;
|
|
257
|
+
isEnabled(user: User, panel: Panel): Promise<boolean>;
|
|
258
|
+
/** Relying party of a request: its id (domain) and allowed origins. */
|
|
259
|
+
getRelyingParty(panel: Panel, req: {
|
|
260
|
+
protocol?: string;
|
|
261
|
+
hostname?: string;
|
|
262
|
+
get?: (name: string) => string | undefined;
|
|
263
|
+
} | undefined): {
|
|
264
|
+
id: string;
|
|
265
|
+
name: string;
|
|
266
|
+
origins: string[];
|
|
267
|
+
};
|
|
268
|
+
private cache;
|
|
269
|
+
/** A new challenge, remembered for this user and purpose until it is used or expires. */
|
|
270
|
+
protected issueChallenge(user: User, panel: Panel, purpose: 'register' | 'authenticate'): Promise<string>;
|
|
271
|
+
/** The challenge a response answers, if it was issued for this user and purpose; it is consumed (single use). */
|
|
272
|
+
protected consumeChallenge(response: any, user: User, panel: Panel, purpose: 'register' | 'authenticate'): Promise<string | null>;
|
|
273
|
+
protected requestOf(field: {
|
|
274
|
+
livewire: unknown;
|
|
275
|
+
}): any;
|
|
276
|
+
/** Checks an assertion from the browser against the user's keys; updates the key's counter. */
|
|
277
|
+
verifyAssertion(value: unknown, user: User, panel: Panel, req: any): Promise<boolean>;
|
|
278
|
+
getChallengeFormComponents(user: User, panel: Panel): Component[];
|
|
279
|
+
getManagementSchemaComponents(user: User, panel: Panel): Component[];
|
|
280
|
+
/** Adds a key: a name, the ceremony in the browser, and the password. */
|
|
281
|
+
registerAction(panel: Panel): Action;
|
|
282
|
+
/** Removes one of the user's keys, after the password. */
|
|
283
|
+
removeAction(panel: Panel): Action;
|
|
284
|
+
}
|
|
285
|
+
/** Where the email authentication flag is kept; by default, the panel's auth provider (`knexAuthProvider`: `has_email_authentication`). */
|
|
286
|
+
export type EmailAuthenticationStore = Required<Pick<AuthProvider, 'hasEmailAuthentication' | 'saveEmailAuthentication'>>;
|
|
287
|
+
/** One-time code field with a "Send a new code by email" link, which asks the server for another code. */
|
|
288
|
+
export declare class EmailCodeInput extends OneTimeCodeInput {
|
|
289
|
+
protected _resend: ((field: EmailCodeInput) => MaybePromise<void>) | null;
|
|
290
|
+
protected _resendLabel: string;
|
|
291
|
+
static make(name: string): EmailCodeInput;
|
|
292
|
+
/** What the link does (send a new code); without it, there is no link. */
|
|
293
|
+
resendUsing(callback: ((field: EmailCodeInput) => MaybePromise<void>) | null, label?: string): this;
|
|
294
|
+
getExposedMethods(): string[];
|
|
295
|
+
isRenderlessMethod(): boolean;
|
|
296
|
+
resendCode(): Promise<void>;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Authentication with a 6-digit code sent to the user's email address, through the panel's `mailer()`.
|
|
300
|
+
* A code is valid for a few minutes (4 by default) and once; at most two codes are sent per minute.
|
|
301
|
+
*/
|
|
302
|
+
export declare class EmailAuthentication implements MultiFactorAuthenticationProvider {
|
|
303
|
+
protected _id: string;
|
|
304
|
+
protected _codeExpiryMinutes: number;
|
|
305
|
+
protected _generateCode: (() => string) | null;
|
|
306
|
+
protected _store: EmailAuthenticationStore | null;
|
|
307
|
+
protected _cacheStore: MultiFactorCacheStore | null;
|
|
308
|
+
protected _sendCode: ((user: User, code: string, minutes: number, panel: Panel) => MaybePromise<void>) | null;
|
|
309
|
+
protected sendThrottle: Throttle;
|
|
310
|
+
protected managementThrottle: Throttle;
|
|
311
|
+
static make(): EmailAuthentication;
|
|
312
|
+
getId(): string;
|
|
313
|
+
id(id: string): this;
|
|
314
|
+
getLoginFormLabel(): string;
|
|
315
|
+
/** Minutes a code stays valid. */
|
|
316
|
+
codeExpiryMinutes(minutes: number): this;
|
|
317
|
+
getCodeExpiryMinutes(): number;
|
|
318
|
+
/** Generates the codes (6 random digits by default). */
|
|
319
|
+
generateCodeUsing(callback: (() => string) | null): this;
|
|
320
|
+
generateCode(): string;
|
|
321
|
+
/** Sends the code yourself (SMS gateway, your own email template…) instead of the panel's mailer. */
|
|
322
|
+
sendCodeUsing(callback: ((user: User, code: string, minutes: number, panel: Panel) => MaybePromise<void>) | null): this;
|
|
323
|
+
store(store: EmailAuthenticationStore | null): this;
|
|
324
|
+
/** Where pending codes are kept until they are used or expire. */
|
|
325
|
+
cacheStore(store: MultiFactorCacheStore | null): this;
|
|
326
|
+
protected getStore(panel: Panel): EmailAuthenticationStore;
|
|
327
|
+
checkConfiguration(panel: Panel): void;
|
|
328
|
+
isEnabled(user: User, panel: Panel): Promise<boolean>;
|
|
329
|
+
setEnabled(user: User, panel: Panel, enabled: boolean): Promise<void>;
|
|
330
|
+
private cache;
|
|
331
|
+
private codeKey;
|
|
332
|
+
/** Sends a new code (the previous one stops working). Returns `false` when two codes were already sent this minute. */
|
|
333
|
+
sendCode(user: User, panel: Panel): Promise<boolean>;
|
|
334
|
+
/** Checks a code against the last one sent; a valid code is consumed. */
|
|
335
|
+
verifyCode(code: unknown, user: User, panel: Panel): Promise<boolean>;
|
|
336
|
+
beforeChallenge(user: User, panel: Panel): Promise<void>;
|
|
337
|
+
/** Sends a new code and tells the user (or that they must wait). */
|
|
338
|
+
protected resend(user: User, panel: Panel, group: string): Promise<void>;
|
|
339
|
+
getChallengeFormComponents(user: User, panel: Panel): Component[];
|
|
340
|
+
/** Code field of the setup and disable modals: the signed-in user's code, rate limited. */
|
|
341
|
+
protected modalCodeInput(panel: Panel, group: string): EmailCodeInput;
|
|
342
|
+
getManagementSchemaComponents(user: User, panel: Panel): Component[];
|
|
343
|
+
/** Sends a code when the modal opens; entering it turns email codes on. */
|
|
344
|
+
setUpAction(panel: Panel): Action;
|
|
345
|
+
/** Sends a code when the modal opens; entering it turns email codes off. */
|
|
346
|
+
disableAction(panel: Panel): Action;
|
|
347
|
+
}
|
|
348
|
+
export {};
|