@aooth/auth-moost 0.1.22 → 0.1.23
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/dist/atscript/index.d.mts +38 -20
- package/dist/atscript/index.mjs +2 -2
- package/dist/{forms-uqegc32h.mjs → forms-xaBNc5Ng.mjs} +19 -3
- package/dist/index.d.mts +199 -21
- package/dist/index.mjs +297 -57
- package/package.json +9 -9
- package/src/atscript/models/forms.as +45 -2
- package/src/atscript/models/forms.as.d.ts +38 -19
|
@@ -138,7 +138,7 @@ declare class Select2faForm {
|
|
|
138
138
|
}
|
|
139
139
|
/**
|
|
140
140
|
* Atscript interface **PincodeForm**
|
|
141
|
-
* @see {@link ./forms.as:
|
|
141
|
+
* @see {@link ./forms.as:421:18}
|
|
142
142
|
*/
|
|
143
143
|
declare class PincodeForm {
|
|
144
144
|
// transportHint: ui.paragraph
|
|
@@ -157,7 +157,7 @@ declare class PincodeForm {
|
|
|
157
157
|
}
|
|
158
158
|
/**
|
|
159
159
|
* Atscript interface **AskEmailForm**
|
|
160
|
-
* @see {@link ./forms.as:
|
|
160
|
+
* @see {@link ./forms.as:460:18}
|
|
161
161
|
*/
|
|
162
162
|
declare class AskEmailForm extends WithInlineConsentForm {
|
|
163
163
|
// disclosure: ui.paragraph
|
|
@@ -174,7 +174,7 @@ declare class AskEmailForm extends WithInlineConsentForm {
|
|
|
174
174
|
}
|
|
175
175
|
/**
|
|
176
176
|
* Atscript interface **AskPhoneForm**
|
|
177
|
-
* @see {@link ./forms.as:
|
|
177
|
+
* @see {@link ./forms.as:490:18}
|
|
178
178
|
*/
|
|
179
179
|
declare class AskPhoneForm extends WithInlineConsentForm {
|
|
180
180
|
// disclosure: ui.paragraph
|
|
@@ -190,7 +190,7 @@ declare class AskPhoneForm extends WithInlineConsentForm {
|
|
|
190
190
|
}
|
|
191
191
|
/**
|
|
192
192
|
* Atscript interface **EnrollPickMethodForm**
|
|
193
|
-
* @see {@link ./forms.as:
|
|
193
|
+
* @see {@link ./forms.as:514:18}
|
|
194
194
|
*/
|
|
195
195
|
declare class EnrollPickMethodForm {
|
|
196
196
|
method: string; // skip: ui.action
|
|
@@ -206,7 +206,7 @@ declare class EnrollPickMethodForm {
|
|
|
206
206
|
}
|
|
207
207
|
/**
|
|
208
208
|
* Atscript interface **EnrollAddressForm**
|
|
209
|
-
* @see {@link ./forms.as:
|
|
209
|
+
* @see {@link ./forms.as:548:18}
|
|
210
210
|
*/
|
|
211
211
|
declare class EnrollAddressForm {
|
|
212
212
|
address: string; // skip: ui.action
|
|
@@ -223,7 +223,7 @@ declare class EnrollAddressForm {
|
|
|
223
223
|
}
|
|
224
224
|
/**
|
|
225
225
|
* Atscript interface **EnrollConfirmForm**
|
|
226
|
-
* @see {@link ./forms.as:
|
|
226
|
+
* @see {@link ./forms.as:594:18}
|
|
227
227
|
*/
|
|
228
228
|
declare class EnrollConfirmForm {
|
|
229
229
|
// transportHint: ui.paragraph
|
|
@@ -242,7 +242,7 @@ declare class EnrollConfirmForm {
|
|
|
242
242
|
}
|
|
243
243
|
/**
|
|
244
244
|
* Atscript interface **EnrollTotpQrForm**
|
|
245
|
-
* @see {@link ./forms.as:
|
|
245
|
+
* @see {@link ./forms.as:644:18}
|
|
246
246
|
*/
|
|
247
247
|
declare class EnrollTotpQrForm {
|
|
248
248
|
// qrCode: ui.paragraph
|
|
@@ -260,10 +260,11 @@ declare class EnrollTotpQrForm {
|
|
|
260
260
|
}
|
|
261
261
|
/**
|
|
262
262
|
* Atscript interface **ManageMfaForm**
|
|
263
|
-
* @see {@link ./forms.as:
|
|
263
|
+
* @see {@link ./forms.as:687:18}
|
|
264
264
|
*/
|
|
265
265
|
declare class ManageMfaForm {
|
|
266
266
|
// lockedNote: ui.paragraph
|
|
267
|
+
// requiredNote: ui.paragraph
|
|
267
268
|
operation: string; // cancel: ui.action
|
|
268
269
|
static __is_atscript_annotated_type: true;
|
|
269
270
|
static type: TAtscriptTypeObject<keyof ManageMfaForm, ManageMfaForm>;
|
|
@@ -276,7 +277,7 @@ declare class ManageMfaForm {
|
|
|
276
277
|
}
|
|
277
278
|
/**
|
|
278
279
|
* Atscript interface **RemoveMfaConfirmForm**
|
|
279
|
-
* @see {@link ./forms.as:
|
|
280
|
+
* @see {@link ./forms.as:721:18}
|
|
280
281
|
*/
|
|
281
282
|
declare class RemoveMfaConfirmForm {
|
|
282
283
|
// notice: ui.paragraph
|
|
@@ -292,7 +293,7 @@ declare class RemoveMfaConfirmForm {
|
|
|
292
293
|
}
|
|
293
294
|
/**
|
|
294
295
|
* Atscript interface **PasswordReauthForm**
|
|
295
|
-
* @see {@link ./forms.as:
|
|
296
|
+
* @see {@link ./forms.as:744:18}
|
|
296
297
|
*/
|
|
297
298
|
declare class PasswordReauthForm {
|
|
298
299
|
password: string; // cancel: ui.action
|
|
@@ -305,9 +306,26 @@ declare class PasswordReauthForm {
|
|
|
305
306
|
/** @deprecated Example Data support is disabled. To enable, set `exampleData: true` in tsPlugin options. */
|
|
306
307
|
static toExampleData?: () => any;
|
|
307
308
|
}
|
|
309
|
+
/**
|
|
310
|
+
* Atscript interface **StepUpConfirmForm**
|
|
311
|
+
* @see {@link ./forms.as:775:18}
|
|
312
|
+
*/
|
|
313
|
+
declare class StepUpConfirmForm {
|
|
314
|
+
// notice: ui.paragraph
|
|
315
|
+
// useDifferentMethod: ui.action
|
|
316
|
+
// cancel: ui.action
|
|
317
|
+
static __is_atscript_annotated_type: true;
|
|
318
|
+
static type: TAtscriptTypeObject<keyof StepUpConfirmForm, StepUpConfirmForm>;
|
|
319
|
+
static metadata: TMetadataMap<AtscriptMetadata>;
|
|
320
|
+
static validator: (opts?: Partial<TValidatorOptions>) => Validator<typeof StepUpConfirmForm>;
|
|
321
|
+
/** @deprecated JSON Schema support is disabled. Calling this method will throw a runtime error. To enable, set `jsonSchema: 'lazy'` or `jsonSchema: 'bundle'` in tsPlugin options, or add `@emit.jsonSchema` annotation to individual interfaces. */
|
|
322
|
+
static toJsonSchema: () => any;
|
|
323
|
+
/** @deprecated Example Data support is disabled. To enable, set `exampleData: true` in tsPlugin options. */
|
|
324
|
+
static toExampleData?: () => any;
|
|
325
|
+
}
|
|
308
326
|
/**
|
|
309
327
|
* Atscript interface **TermsBumpForm**
|
|
310
|
-
* @see {@link ./forms.as:
|
|
328
|
+
* @see {@link ./forms.as:803:18}
|
|
311
329
|
*/
|
|
312
330
|
declare class TermsBumpForm extends WithInlineConsentForm {
|
|
313
331
|
static __is_atscript_annotated_type: true;
|
|
@@ -321,7 +339,7 @@ declare class TermsBumpForm extends WithInlineConsentForm {
|
|
|
321
339
|
}
|
|
322
340
|
/**
|
|
323
341
|
* Atscript interface **ConcurrencyLimitForm**
|
|
324
|
-
* @see {@link ./forms.as:
|
|
342
|
+
* @see {@link ./forms.as:816:18}
|
|
325
343
|
*/
|
|
326
344
|
declare class ConcurrencyLimitForm {
|
|
327
345
|
static __is_atscript_annotated_type: true;
|
|
@@ -335,7 +353,7 @@ declare class ConcurrencyLimitForm {
|
|
|
335
353
|
}
|
|
336
354
|
/**
|
|
337
355
|
* Atscript interface **MagicLinkRequestForm**
|
|
338
|
-
* @see {@link ./forms.as:
|
|
356
|
+
* @see {@link ./forms.as:826:18}
|
|
339
357
|
*/
|
|
340
358
|
declare class MagicLinkRequestForm {
|
|
341
359
|
identifier: string;
|
|
@@ -350,7 +368,7 @@ declare class MagicLinkRequestForm {
|
|
|
350
368
|
}
|
|
351
369
|
/**
|
|
352
370
|
* Atscript interface **RecoveryModeSelectForm**
|
|
353
|
-
* @see {@link ./forms.as:
|
|
371
|
+
* @see {@link ./forms.as:841:18}
|
|
354
372
|
*/
|
|
355
373
|
declare class RecoveryModeSelectForm {
|
|
356
374
|
mode: string;
|
|
@@ -365,7 +383,7 @@ declare class RecoveryModeSelectForm {
|
|
|
365
383
|
}
|
|
366
384
|
/**
|
|
367
385
|
* Atscript interface **RecoveryFactorForm**
|
|
368
|
-
* @see {@link ./forms.as:
|
|
386
|
+
* @see {@link ./forms.as:864:18}
|
|
369
387
|
*/
|
|
370
388
|
declare class RecoveryFactorForm {
|
|
371
389
|
factor: string;
|
|
@@ -381,7 +399,7 @@ declare class RecoveryFactorForm {
|
|
|
381
399
|
}
|
|
382
400
|
/**
|
|
383
401
|
* Atscript interface **ChangePasswordForm**
|
|
384
|
-
* @see {@link ./forms.as:
|
|
402
|
+
* @see {@link ./forms.as:898:18}
|
|
385
403
|
*/
|
|
386
404
|
declare class ChangePasswordForm {
|
|
387
405
|
// intro: ui.paragraph
|
|
@@ -399,7 +417,7 @@ declare class ChangePasswordForm {
|
|
|
399
417
|
}
|
|
400
418
|
/**
|
|
401
419
|
* Atscript interface **ProveControlForm**
|
|
402
|
-
* @see {@link ./forms.as:
|
|
420
|
+
* @see {@link ./forms.as:963:18}
|
|
403
421
|
*/
|
|
404
422
|
declare class ProveControlForm {
|
|
405
423
|
// intro: ui.paragraph
|
|
@@ -415,7 +433,7 @@ declare class ProveControlForm {
|
|
|
415
433
|
}
|
|
416
434
|
/**
|
|
417
435
|
* Atscript interface **ProveControlOtpForm**
|
|
418
|
-
* @see {@link ./forms.as:
|
|
436
|
+
* @see {@link ./forms.as:998:18}
|
|
419
437
|
*/
|
|
420
438
|
declare class ProveControlOtpForm {
|
|
421
439
|
// intro: ui.paragraph
|
|
@@ -432,7 +450,7 @@ declare class ProveControlOtpForm {
|
|
|
432
450
|
}
|
|
433
451
|
/**
|
|
434
452
|
* Atscript interface **AuthorizeConsentForm**
|
|
435
|
-
* @see {@link ./forms.as:
|
|
453
|
+
* @see {@link ./forms.as:1048:18}
|
|
436
454
|
*/
|
|
437
455
|
declare class AuthorizeConsentForm {
|
|
438
456
|
// notice: ui.paragraph
|
|
@@ -447,4 +465,4 @@ declare class AuthorizeConsentForm {
|
|
|
447
465
|
static toExampleData?: () => any;
|
|
448
466
|
}
|
|
449
467
|
//#endregion
|
|
450
|
-
export { AskEmailForm, AskPhoneForm, AuthorizeConsentForm, ChangePasswordForm, ConcurrencyLimitForm, EmailIdentifierForm, EnrollAddressForm, EnrollConfirmForm, EnrollPickMethodForm, EnrollTotpQrForm, InviteForm, LoginCredentialsForm, MagicLinkRequestForm, ManageMfaForm, MfaCodeForm, PasswordReauthForm, PincodeForm, ProveControlForm, ProveControlOtpForm, RecoveryFactorForm, RecoveryModeSelectForm, RemoveMfaConfirmForm, Select2faForm, SetPasswordForm, SignupForm, TermsBumpForm, WithInlineConsentForm };
|
|
468
|
+
export { AskEmailForm, AskPhoneForm, AuthorizeConsentForm, ChangePasswordForm, ConcurrencyLimitForm, EmailIdentifierForm, EnrollAddressForm, EnrollConfirmForm, EnrollPickMethodForm, EnrollTotpQrForm, InviteForm, LoginCredentialsForm, MagicLinkRequestForm, ManageMfaForm, MfaCodeForm, PasswordReauthForm, PincodeForm, ProveControlForm, ProveControlOtpForm, RecoveryFactorForm, RecoveryModeSelectForm, RemoveMfaConfirmForm, Select2faForm, SetPasswordForm, SignupForm, StepUpConfirmForm, TermsBumpForm, WithInlineConsentForm };
|
package/dist/atscript/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { C as Select2faForm, D as
|
|
2
|
-
export { AskEmailForm, AskPhoneForm, AuthorizeConsentForm, ChangePasswordForm, ConcurrencyLimitForm, EmailIdentifierForm, EnrollAddressForm, EnrollConfirmForm, EnrollPickMethodForm, EnrollTotpQrForm, InviteForm, LoginCredentialsForm, MagicLinkRequestForm, ManageMfaForm, MfaCodeForm, PasswordReauthForm, PincodeForm, ProveControlForm, ProveControlOtpForm, RecoveryFactorForm, RecoveryModeSelectForm, RemoveMfaConfirmForm, Select2faForm, SetPasswordForm, SignupForm, TermsBumpForm, WithInlineConsentForm };
|
|
1
|
+
import { C as Select2faForm, D as TermsBumpForm, E as StepUpConfirmForm, O as WithInlineConsentForm, S as RemoveMfaConfirmForm, T as SignupForm, _ as PincodeForm, a as ConcurrencyLimitForm, b as RecoveryFactorForm, c as EnrollConfirmForm, d as InviteForm, f as LoginCredentialsForm, g as PasswordReauthForm, h as MfaCodeForm, i as ChangePasswordForm, l as EnrollPickMethodForm, m as ManageMfaForm, n as AskPhoneForm, o as EmailIdentifierForm, p as MagicLinkRequestForm, r as AuthorizeConsentForm, s as EnrollAddressForm, t as AskEmailForm, u as EnrollTotpQrForm, v as ProveControlForm, w as SetPasswordForm, x as RecoveryModeSelectForm, y as ProveControlOtpForm } from "../forms-xaBNc5Ng.mjs";
|
|
2
|
+
export { AskEmailForm, AskPhoneForm, AuthorizeConsentForm, ChangePasswordForm, ConcurrencyLimitForm, EmailIdentifierForm, EnrollAddressForm, EnrollConfirmForm, EnrollPickMethodForm, EnrollTotpQrForm, InviteForm, LoginCredentialsForm, MagicLinkRequestForm, ManageMfaForm, MfaCodeForm, PasswordReauthForm, PincodeForm, ProveControlForm, ProveControlOtpForm, RecoveryFactorForm, RecoveryModeSelectForm, RemoveMfaConfirmForm, Select2faForm, SetPasswordForm, SignupForm, StepUpConfirmForm, TermsBumpForm, WithInlineConsentForm };
|
|
@@ -162,6 +162,15 @@ var PasswordReauthForm = class {
|
|
|
162
162
|
throwFeatureDisabled("JSON Schema", "jsonSchema", "emit.jsonSchema");
|
|
163
163
|
}
|
|
164
164
|
};
|
|
165
|
+
var StepUpConfirmForm = class {
|
|
166
|
+
static __is_atscript_annotated_type = true;
|
|
167
|
+
static type = {};
|
|
168
|
+
static metadata = /* @__PURE__ */ new Map();
|
|
169
|
+
static id = "StepUpConfirmForm";
|
|
170
|
+
static toJsonSchema() {
|
|
171
|
+
throwFeatureDisabled("JSON Schema", "jsonSchema", "emit.jsonSchema");
|
|
172
|
+
}
|
|
173
|
+
};
|
|
165
174
|
var TermsBumpForm = class {
|
|
166
175
|
static __is_atscript_annotated_type = true;
|
|
167
176
|
static type = {};
|
|
@@ -319,7 +328,7 @@ defineAnnotatedType("object", InviteForm).prop("email", defineAnnotatedType().de
|
|
|
319
328
|
flags: "",
|
|
320
329
|
message: "Invalid email format."
|
|
321
330
|
}, true).$type).prop("roles", defineAnnotatedType("array").of(defineAnnotatedType().designType("string").tags("string").$type).annotate("ui.form.order", 20).annotate("ui.form.type", "select").annotate("ui.form.fn.options", "(_, _data, context) => Array.isArray(context.public?.admin?.availableRoles) ? context.public.admin.availableRoles.map(r => ({ key: r, label: r })) : []").annotate("meta.label", "Roles").$type).annotate("meta.label", "Send an invitation").annotate("meta.description", "Enter the recipient email address and pick the roles to grant on acceptance. They will receive a magic link to set their password.").annotate("wf.context.pass", "public", true);
|
|
322
|
-
defineAnnotatedType("object", Select2faForm).prop("methodName", defineAnnotatedType().designType("string").tags("string").annotate("ui.form.order", 10).annotate("ui.form.type", "radio").annotate("ui.form.fn.options", "(_, _d, ctx) => Array.isArray(ctx.public?.mfa?.enrolledMethods) ? ctx.public.mfa.enrolledMethods.map(m => ({ key: m.methodName, label: m.kind === \"totp\" ? \"TOTP (Authenticator app)\" : m.kind === \"email\" ? \"Email\" : m.kind === \"sms\" ? \"SMS\" : m.kind })) : []").annotate("meta.label", "MFA method").annotate("meta.required", {}).$type).prop("saveAsDefault", defineAnnotatedType().designType("boolean").tags("boolean").annotate("ui.form.type", "checkbox").annotate("meta.label", "Save as default").annotate("meta.default", "false").$type).prop("rememberDevice", defineAnnotatedType().designType("boolean").tags("boolean").annotate("ui.form.type", "checkbox").annotate("meta.label", "Remember this device").annotate("meta.default", "false").annotate("ui.form.fn.hidden", "(_, _d, ctx) => !ctx.public?.trust?.optIn || !!ctx.public?.newPasswordRequired").$type).annotate("meta.label", "Choose a verification method").annotate("meta.description", "Pick how you would like to verify your identity.").annotate("wf.context.pass", "public", true);
|
|
331
|
+
defineAnnotatedType("object", Select2faForm).prop("methodName", defineAnnotatedType().designType("string").tags("string").annotate("ui.form.order", 10).annotate("ui.form.type", "radio").annotate("ui.form.fn.options", "(_, _d, ctx) => Array.isArray(ctx.public?.mfa?.enrolledMethods) ? ctx.public.mfa.enrolledMethods.map(m => ({ key: m.methodName, label: (m.kind === \"totp\" ? \"TOTP (Authenticator app)\" : m.kind === \"email\" ? \"Email\" : m.kind === \"sms\" ? \"SMS\" : m.kind) + (m.masked && (m.kind === \"email\" || m.kind === \"sms\") ? \" (\" + m.masked + \")\" : \"\") })) : []").annotate("meta.label", "MFA method").annotate("meta.required", {}).$type).prop("saveAsDefault", defineAnnotatedType().designType("boolean").tags("boolean").annotate("ui.form.type", "checkbox").annotate("meta.label", "Save as default").annotate("meta.default", "false").$type).prop("rememberDevice", defineAnnotatedType().designType("boolean").tags("boolean").annotate("ui.form.type", "checkbox").annotate("meta.label", "Remember this device").annotate("meta.default", "false").annotate("ui.form.fn.hidden", "(_, _d, ctx) => !ctx.public?.trust?.optIn || !!ctx.public?.newPasswordRequired").$type).annotate("meta.label", "Choose a verification method").annotate("meta.description", "Pick how you would like to verify your identity.").annotate("wf.context.pass", "public", true);
|
|
323
332
|
defineAnnotatedType("object", PincodeForm).prop("transportHint", defineAnnotatedType().designType("phantom").tags("paragraph", "ui").annotate("ui.form.fn.value", "(_, _d, ctx) => ctx.public?.mfa?.method === \"totp\" ? \"Enter the current 6-digit code from your authenticator app.\" : ctx.public?.pincode?.sentTo ? \"Code sent to \" + ctx.public.pincode.sentTo + \".\" : \"Enter your verification code.\"").optional().$type).prop("code", defineAnnotatedType().designType("string").tags("string").annotate("ui.form.type", "text").annotate("meta.label", "Verification code").annotate("ui.form.autocomplete", "one-time-code").annotate("ui.form.fn.attr", {
|
|
324
333
|
name: "maxlength",
|
|
325
334
|
fn: "(_, _d, ctx) => ctx.public?.pincode?.codeLength"
|
|
@@ -394,7 +403,7 @@ defineAnnotatedType("object", EnrollTotpQrForm).prop("qrCode", defineAnnotatedTy
|
|
|
394
403
|
id: "skip",
|
|
395
404
|
label: "Skip for now"
|
|
396
405
|
}).annotate("ui.form.fn.hidden", "(_, _d, ctx) => ctx.public?.mfaEnroll?.mode !== \"optional\"").optional().$type).annotate("meta.label", "Scan this QR code").annotate("meta.description", "Open your authenticator app and scan the code (or enter the key manually), then continue to enter the code it shows.").annotate("wf.context.pass", "public", true).annotate("ui.form.submit.text", "Continue");
|
|
397
|
-
defineAnnotatedType("object", ManageMfaForm).prop("lockedNote", defineAnnotatedType().designType("phantom").tags("paragraph", "ui").annotate("ui.form.order", 5).annotate("ui.form.fn.value", "(_, _d, ctx) => (ctx.public?.manage?.locked?.length ?? 0) > 0 ? \"Some methods are also used to sign in and can’t be changed here.\" : \"\"").annotate("ui.form.fn.hidden", "(_, _d, ctx) => (ctx.public?.manage?.locked?.length ?? 0) === 0").$type).prop("operation", defineAnnotatedType().designType("string").tags("string").annotate("ui.form.order", 10).annotate("ui.form.type", "radio").annotate("ui.form.fn.options", "(_, _d, ctx) => { const lbl = (t) => t === \"totp\" ? \"authenticator app\" : t === \"sms\" ? \"SMS\" : t === \"email\" ? \"email\" : t; const locked = ctx.public?.manage?.locked ?? []; const out = []; for (const t of (ctx.public?.manage?.candidates ?? [])) out.push({ key: \"add:\" + t, label: \"Add \" + lbl(t) }); for (const m of (ctx.public?.mfa?.enrolledMethods ?? [])) { if (locked.includes(m.kind)) continue; out.push({ key: \"replace:\" + m.kind, label: \"Change \" + lbl(m.kind) + (m.masked ? \" (\" + m.masked + \")\" : \"\") }); out.push({ key: \"remove:\" + m.kind, label: \"Remove \" + lbl(m.kind) }); } return out; }").annotate("meta.label", "What would you like to do?").annotate("meta.required", {}).$type).prop("cancel", defineAnnotatedType().designType("phantom").tags("action", "ui").annotate("ui.form.action", {
|
|
406
|
+
defineAnnotatedType("object", ManageMfaForm).prop("lockedNote", defineAnnotatedType().designType("phantom").tags("paragraph", "ui").annotate("ui.form.order", 5).annotate("ui.form.fn.value", "(_, _d, ctx) => (ctx.public?.manage?.locked?.length ?? 0) > 0 ? \"Some methods are also used to sign in and can’t be changed here.\" : \"\"").annotate("ui.form.fn.hidden", "(_, _d, ctx) => (ctx.public?.manage?.locked?.length ?? 0) === 0").$type).prop("requiredNote", defineAnnotatedType().designType("phantom").tags("paragraph", "ui").annotate("ui.form.order", 6).annotate("ui.form.fn.value", "(_, _d, ctx) => ctx.public?.manage?.removeBlocked ? \"Two-factor authentication is required for your account, so your last method can be changed but not removed.\" : \"\"").annotate("ui.form.fn.hidden", "(_, _d, ctx) => !ctx.public?.manage?.removeBlocked").$type).prop("operation", defineAnnotatedType().designType("string").tags("string").annotate("ui.form.order", 10).annotate("ui.form.type", "radio").annotate("ui.form.fn.options", "(_, _d, ctx) => { const lbl = (t) => t === \"totp\" ? \"authenticator app\" : t === \"sms\" ? \"SMS\" : t === \"email\" ? \"email\" : t; const locked = ctx.public?.manage?.locked ?? []; const out = []; for (const t of (ctx.public?.manage?.candidates ?? [])) out.push({ key: \"add:\" + t, label: \"Add \" + lbl(t) }); for (const m of (ctx.public?.mfa?.enrolledMethods ?? [])) { if (locked.includes(m.kind)) continue; out.push({ key: \"replace:\" + m.kind, label: \"Change \" + lbl(m.kind) + (m.masked ? \" (\" + m.masked + \")\" : \"\") }); if (!ctx.public?.manage?.removeBlocked) out.push({ key: \"remove:\" + m.kind, label: \"Remove \" + lbl(m.kind) }); } return out; }").annotate("meta.label", "What would you like to do?").annotate("meta.required", {}).$type).prop("cancel", defineAnnotatedType().designType("phantom").tags("action", "ui").annotate("ui.form.action", {
|
|
398
407
|
id: "cancel",
|
|
399
408
|
label: "Cancel"
|
|
400
409
|
}).annotate("ui.form.fn.hidden", "() => true").optional().$type).annotate("meta.label", "Manage two-factor authentication").annotate("meta.description", "Add, change, or remove a verification method.").annotate("wf.context.pass", "public", true).annotate("ui.form.submit.text", "Continue");
|
|
@@ -406,6 +415,13 @@ defineAnnotatedType("object", PasswordReauthForm).prop("password", defineAnnotat
|
|
|
406
415
|
id: "cancel",
|
|
407
416
|
label: "Cancel"
|
|
408
417
|
}).annotate("ui.form.fn.hidden", "() => true").optional().$type).annotate("meta.label", "Confirm your password").annotate("meta.description", "Re-enter your account password to manage your two-factor methods.").annotate("wf.context.pass", "public", true).annotate("ui.form.submit.text", "Verify");
|
|
418
|
+
defineAnnotatedType("object", StepUpConfirmForm).prop("notice", defineAnnotatedType().designType("phantom").tags("paragraph", "ui").annotate("ui.form.order", 1).annotate("ui.form.fn.value", "(_, _d, ctx) => { const kind = ctx.public?.mfa?.method; const m = (ctx.public?.mfa?.enrolledMethods ?? []).find(e => e.kind === kind); const to = m && m.masked ? \" to \" + m.masked : kind === \"sms\" ? \" to your phone\" : \" to your email\"; return \"To continue, we will send a verification code\" + to + \".\"; }").$type).prop("useDifferentMethod", defineAnnotatedType().designType("phantom").tags("action", "ui").annotate("ui.form.action", {
|
|
419
|
+
id: "useDifferentMethod",
|
|
420
|
+
label: "Use a different method"
|
|
421
|
+
}).annotate("ui.form.fn.hidden", "(_, _d, ctx) => (ctx.public?.mfa?.methodCount ?? 0) < 2").optional().$type).prop("cancel", defineAnnotatedType().designType("phantom").tags("action", "ui").annotate("ui.form.action", {
|
|
422
|
+
id: "cancel",
|
|
423
|
+
label: "Cancel"
|
|
424
|
+
}).annotate("ui.form.fn.hidden", "() => true").optional().$type).annotate("meta.label", "Verify your identity").annotate("wf.context.pass", "public", true).annotate("ui.form.submit.text", "Continue");
|
|
409
425
|
defineAnnotatedType("object", TermsBumpForm).prop("consents", defineAnnotatedType("array").of(defineAnnotatedType().designType("string").tags("string").$type).annotate("meta.label", "Pending consents").annotate("ui.form.component", "AsConsentArray").annotate("ui.form.fn.attr", {
|
|
410
426
|
name: "pendingConsents",
|
|
411
427
|
fn: "(_, _d, ctx) => ctx.public?.consents?.pending"
|
|
@@ -455,4 +471,4 @@ defineAnnotatedType("object", AuthorizeConsentForm).prop("notice", defineAnnotat
|
|
|
455
471
|
value: "center"
|
|
456
472
|
}, true).annotate("ui.form.pushDown", true).optional().$type).annotate("meta.label", "Authorize access").annotate("wf.context.pass", "public", true).annotate("ui.form.submit.text", "Authorize");
|
|
457
473
|
//#endregion
|
|
458
|
-
export { Select2faForm as C,
|
|
474
|
+
export { Select2faForm as C, TermsBumpForm as D, StepUpConfirmForm as E, WithInlineConsentForm as O, RemoveMfaConfirmForm as S, SignupForm as T, PincodeForm as _, ConcurrencyLimitForm as a, RecoveryFactorForm as b, EnrollConfirmForm as c, InviteForm as d, LoginCredentialsForm as f, PasswordReauthForm as g, MfaCodeForm as h, ChangePasswordForm as i, EnrollPickMethodForm as l, ManageMfaForm as m, AskPhoneForm as n, EmailIdentifierForm as o, MagicLinkRequestForm as p, AuthorizeConsentForm as r, EnrollAddressForm as s, AskEmailForm as t, EnrollTotpQrForm as u, ProveControlForm as v, SetPasswordForm as w, RecoveryModeSelectForm as x, ProveControlOtpForm as y };
|
package/dist/index.d.mts
CHANGED
|
@@ -1590,12 +1590,40 @@ interface AuthWfAddMfaState {
|
|
|
1590
1590
|
* replay-resistant). Gates the one-time swap + the management menu.
|
|
1591
1591
|
*/
|
|
1592
1592
|
stepUpDone?: boolean;
|
|
1593
|
+
/**
|
|
1594
|
+
* The user has explicitly consented to the step-up pincode dispatch —
|
|
1595
|
+
* either by submitting `manage-stepup-confirm`'s "we'll send a code to
|
|
1596
|
+
* ma•••@x" notice, or by picking a factor on `select-2fa` (choosing
|
|
1597
|
+
* "Email (ma•••@x)" and submitting IS the consent). Gates the
|
|
1598
|
+
* `manage-stepup-confirm` pause so opening the manage dialog never
|
|
1599
|
+
* dispatches a code as a side effect. Also set when
|
|
1600
|
+
* `resolveStepUpConfirmBeforeSend` opts the deployment out of the pause.
|
|
1601
|
+
* Server-only; sms/email step-up only (TOTP dispatches nothing).
|
|
1602
|
+
*/
|
|
1603
|
+
stepUpConfirmed?: boolean;
|
|
1593
1604
|
/** The management action the user picked on the menu. */
|
|
1594
1605
|
action?: "add" | "replace" | "remove";
|
|
1595
1606
|
/** The transport the chosen `action` applies to. */
|
|
1596
1607
|
target?: MfaTransport;
|
|
1597
1608
|
/** Set by `confirm-remove-mfa` so `finish-add-mfa` can report which factor was removed. */
|
|
1598
1609
|
removed?: MfaTransport;
|
|
1610
|
+
/**
|
|
1611
|
+
* Removing a factor is currently impossible: the user has exactly one
|
|
1612
|
+
* confirmed (policy-allowed) factor and `mfaPolicy.mode === 'required'`.
|
|
1613
|
+
* Computed by `manage-menu` before its pause and mirrored to
|
|
1614
|
+
* `public.manage.removeBlocked` so `ManageMfaForm` omits the Remove option
|
|
1615
|
+
* (and explains why) instead of offering an operation that can never
|
|
1616
|
+
* succeed. Re-checked server-side in `manage-menu` + `confirm-remove-mfa`.
|
|
1617
|
+
*/
|
|
1618
|
+
removeBlocked?: boolean;
|
|
1619
|
+
/**
|
|
1620
|
+
* Set by `confirm-remove-mfa` when it arrives in an un-removable state
|
|
1621
|
+
* (stale/crafted route — the menu filters these): the step aborts to the
|
|
1622
|
+
* `finish-add-mfa` terminal with a reason-specific message instead of
|
|
1623
|
+
* pausing on a form whose only submit re-throws the same guard error
|
|
1624
|
+
* (a dead-end loop, since the manage forms hide their built-in cancel).
|
|
1625
|
+
*/
|
|
1626
|
+
blocked?: "last-required-factor" | "method-locked";
|
|
1599
1627
|
}
|
|
1600
1628
|
/**
|
|
1601
1629
|
* Self-signup flow state. Populated by `init-signup` (policy from
|
|
@@ -1694,12 +1722,15 @@ interface AuthWfPublicState {
|
|
|
1694
1722
|
mfaEnroll?: Pick<AuthWfMfaEnrollState, "method" | "mode" | "availableTransports" | "secret" | "uri">;
|
|
1695
1723
|
/**
|
|
1696
1724
|
* Mirrors the manage-MFA menu inputs — the un-enrolled transports the user
|
|
1697
|
-
* can Add
|
|
1698
|
-
*
|
|
1725
|
+
* can Add, the locked transports to omit from Change/Remove, and the
|
|
1726
|
+
* `removeBlocked` flag that omits the Remove option for the last confirmed
|
|
1727
|
+
* factor under a `required` policy. The enrolled method list the menu
|
|
1728
|
+
* cross-references is `public.mfa.enrolledMethods`.
|
|
1699
1729
|
*/
|
|
1700
1730
|
manage?: {
|
|
1701
1731
|
candidates?: MfaTransport[];
|
|
1702
1732
|
locked?: MfaTransport[];
|
|
1733
|
+
removeBlocked?: boolean;
|
|
1703
1734
|
};
|
|
1704
1735
|
/** Mirrors `ctx.defaults` — prefill source for the recovery email field. */
|
|
1705
1736
|
defaults?: {
|
|
@@ -1888,7 +1919,8 @@ interface AuthWorkflowOpts {
|
|
|
1888
1919
|
enrollConfirm?: TAtscriptAnnotatedType; /** Manage-MFA menu (Add / Change / Remove) shown after step-up. */
|
|
1889
1920
|
manageMfa?: TAtscriptAnnotatedType; /** Confirm-removal pause for the manage-MFA "Remove" action. */
|
|
1890
1921
|
removeMfaConfirm?: TAtscriptAnnotatedType; /** Password re-auth — step-up fallback when no factor is MFA-challengeable. */
|
|
1891
|
-
passwordReauth?: TAtscriptAnnotatedType;
|
|
1922
|
+
passwordReauth?: TAtscriptAnnotatedType; /** Step-up dispatch consent — "we'll send a code to ma•••@x" notice before the step-up pincode send. */
|
|
1923
|
+
stepUpConfirm?: TAtscriptAnnotatedType;
|
|
1892
1924
|
select2fa?: TAtscriptAnnotatedType;
|
|
1893
1925
|
mfaCode?: TAtscriptAnnotatedType;
|
|
1894
1926
|
pincode?: TAtscriptAnnotatedType;
|
|
@@ -1944,6 +1976,7 @@ interface ResolvedAuthWorkflowOpts {
|
|
|
1944
1976
|
manageMfa: TAtscriptAnnotatedType;
|
|
1945
1977
|
removeMfaConfirm: TAtscriptAnnotatedType;
|
|
1946
1978
|
passwordReauth: TAtscriptAnnotatedType;
|
|
1979
|
+
stepUpConfirm: TAtscriptAnnotatedType;
|
|
1947
1980
|
select2fa: TAtscriptAnnotatedType;
|
|
1948
1981
|
mfaCode: TAtscriptAnnotatedType;
|
|
1949
1982
|
pincode: TAtscriptAnnotatedType;
|
|
@@ -2236,6 +2269,39 @@ declare class AuthWorkflow {
|
|
|
2236
2269
|
* typed would confirm an unproven inbox. Never asked for TOTP.
|
|
2237
2270
|
*/
|
|
2238
2271
|
protected resolveEnrollPreConfirmed(_ctx: AuthWfCtx, _method: MfaTransport, _address: string): boolean | Promise<boolean>;
|
|
2272
|
+
/**
|
|
2273
|
+
* Pin the enrolment address for an sms/email transport — the policy seam
|
|
2274
|
+
* for deployments whose factor must be BOUND to an account record (e.g.
|
|
2275
|
+
* staff MFA locked to the work mailbox so portal access dies with it at
|
|
2276
|
+
* offboarding; a free-text form would let a self-service swap to a personal
|
|
2277
|
+
* inbox defeat that control entirely). Asked by `enroll-address` BEFORE its
|
|
2278
|
+
* form renders, with the staged transport (ctx-first, extra positional arg —
|
|
2279
|
+
* same convention as `resolveEnrollPreConfirmed`).
|
|
2280
|
+
*
|
|
2281
|
+
* Returning a string stages it as the enrolment address (normalized via
|
|
2282
|
+
* `normalizeMfaAddress`; the free-text form is SKIPPED — the same staging
|
|
2283
|
+
* seam consumer pre-seeding uses, so the user is never shown a form whose
|
|
2284
|
+
* only valid input is one known string). `'collect'` (the default) keeps
|
|
2285
|
+
* the free-text form. A pinned address composes with the rest of the trio
|
|
2286
|
+
* machinery untouched: `enroll-send` dispatches the pincode to it, and
|
|
2287
|
+
* `resolveEnrollPreConfirmed` may vouch it (a deployment pinning to a
|
|
2288
|
+
* verified-by-construction address gets the no-code path for free).
|
|
2289
|
+
*
|
|
2290
|
+
* ```ts
|
|
2291
|
+
* protected async resolveEnrollAddress(ctx: AuthWfCtx, method: MfaTransport) {
|
|
2292
|
+
* if (method !== "email") return "collect";
|
|
2293
|
+
* const user = await this.users.getUser(ctx.subject!);
|
|
2294
|
+
* return (user as { email?: string }).email ?? "collect";
|
|
2295
|
+
* }
|
|
2296
|
+
* ```
|
|
2297
|
+
*
|
|
2298
|
+
* The returned address is trusted as-is (no `validateMfaAddress` pass) —
|
|
2299
|
+
* the deployment is authoritative for its own records. An empty/blank
|
|
2300
|
+
* return falls back to `'collect'`. For nuanced RULES on a user-typed
|
|
2301
|
+
* address (domain allowlists, record comparisons) override the ctx-first
|
|
2302
|
+
* {@link validateMfaAddress} instead.
|
|
2303
|
+
*/
|
|
2304
|
+
protected resolveEnrollAddress(_ctx: AuthWfCtx, _method: MfaTransport): string | "collect" | Promise<string | "collect">;
|
|
2239
2305
|
/**
|
|
2240
2306
|
* Resolve the finalize policy. Reached from login.flow. `auditLogin` is
|
|
2241
2307
|
* dropped from the shape per §2 — audit moved out of the workflow layer.
|
|
@@ -2315,6 +2381,33 @@ declare class AuthWorkflow {
|
|
|
2315
2381
|
* ```
|
|
2316
2382
|
*/
|
|
2317
2383
|
protected resolveLockedMfaTransports(_ctx: AuthWfCtx): MfaTransport[] | Promise<MfaTransport[]>;
|
|
2384
|
+
/**
|
|
2385
|
+
* Whether the manage-MFA step-up must collect explicit consent BEFORE
|
|
2386
|
+
* dispatching its sms/email pincode (the `manage-stepup-confirm` pause:
|
|
2387
|
+
* "To continue, we will send a verification code to ma•••@x"). Default
|
|
2388
|
+
* `true` — nothing should email/text the user as a side effect of opening
|
|
2389
|
+
* a manage dialog: a user who opened it by mistake (or just to look)
|
|
2390
|
+
* closes it with zero codes consumed, no resend cooldown burnt. Override
|
|
2391
|
+
* to `false` to restore the zero-click dispatch (the code is already in
|
|
2392
|
+
* flight when the first form renders). Never asked for TOTP step-up
|
|
2393
|
+
* (nothing is dispatched) and not consulted by the login flow (its
|
|
2394
|
+
* challenge is mid-authentication, where zero-click is the norm).
|
|
2395
|
+
*/
|
|
2396
|
+
protected resolveStepUpConfirmBeforeSend(_ctx: AuthWfCtx): boolean | Promise<boolean>;
|
|
2397
|
+
/**
|
|
2398
|
+
* What the user's authenticator app shows as the ACCOUNT half of
|
|
2399
|
+
* "issuer: account" for a TOTP enrolment (the issuer half is
|
|
2400
|
+
* `resolveMfaPolicy().issuer` / `opts.totpIssuer`). Cosmetic only — never
|
|
2401
|
+
* used for lookup — but it is how a user with several entries tells
|
|
2402
|
+
* accounts apart, and it is encoded into the `otpauth://` URI at
|
|
2403
|
+
* secret-provisioning time, so it lives in the authenticator FOREVER
|
|
2404
|
+
* (re-labeling requires re-enrolment). Default prefers a human-readable
|
|
2405
|
+
* identifier the flow already carries (`ctx.email` — invite/recovery/
|
|
2406
|
+
* signup) and otherwise loads the user's `username`; the stable-uuid
|
|
2407
|
+
* `ctx.subject` is the last resort. Override for a richer label (display
|
|
2408
|
+
* name, tenant-qualified email, …).
|
|
2409
|
+
*/
|
|
2410
|
+
protected resolveTotpAccountLabel(ctx: AuthWfCtx): string | Promise<string>;
|
|
2318
2411
|
/**
|
|
2319
2412
|
* Resolve the channel-OTP disclosure copy rendered beneath the email/phone
|
|
2320
2413
|
* input on `AskEmailForm` / `AskPhoneForm`. Reached from login.flow Phase 3.
|
|
@@ -2583,6 +2676,18 @@ declare class AuthWorkflow {
|
|
|
2583
2676
|
* and resend.
|
|
2584
2677
|
*/
|
|
2585
2678
|
private mintAndSendEnrollPincode;
|
|
2679
|
+
/**
|
|
2680
|
+
* Idempotent TOTP secret provisioning into wf-state ONLY (the QR renders
|
|
2681
|
+
* from `public.mfaEnroll.secret/uri`; the user record is written on confirm
|
|
2682
|
+
* — write-on-confirm). The single implementation behind BOTH provisioning
|
|
2683
|
+
* sites — `enroll-pick-method`'s auto-pick/picker tail and `enroll-totp-qr`
|
|
2684
|
+
* (covers the manage add/change path where the picker is skipped) — so the
|
|
2685
|
+
* account label baked into the `otpauth://` URI cannot drift between them.
|
|
2686
|
+
* The label comes from {@link resolveTotpAccountLabel} (human-readable
|
|
2687
|
+
* default); blank falls back to the subject uuid so the URI always carries
|
|
2688
|
+
* SOME account discriminator.
|
|
2689
|
+
*/
|
|
2690
|
+
private provisionTotpSecret;
|
|
2586
2691
|
/**
|
|
2587
2692
|
* Drop the per-enrolment scratch fields (the `mfaEnroll` provisioning fields +
|
|
2588
2693
|
* the pincode timers/`sentTo`) off ctx — the shared teardown used by the
|
|
@@ -2600,8 +2705,24 @@ declare class AuthWorkflow {
|
|
|
2600
2705
|
* or `undefined` when valid. Email must look like an email; SMS is permissive
|
|
2601
2706
|
* E.164-ish (normalized by {@link normalizeMfaAddress}). Override for stricter
|
|
2602
2707
|
* (e.g. libphonenumber) validation.
|
|
2708
|
+
*
|
|
2709
|
+
* Ctx-first and async-capable, so record-based rules need no ctx-stash
|
|
2710
|
+
* workaround — an override can load the account and compare directly
|
|
2711
|
+
* (e.g. domain-allowlist the typed inbox, or require it to match a
|
|
2712
|
+
* record field). To PIN the address outright — never show the free-text
|
|
2713
|
+
* form at all — use {@link resolveEnrollAddress} instead; this hook is for
|
|
2714
|
+
* nuanced rules on what the user typed.
|
|
2715
|
+
*
|
|
2716
|
+
* ```ts
|
|
2717
|
+
* protected async validateMfaAddress(ctx: AuthWfCtx, method: MfaTransport, value: string) {
|
|
2718
|
+
* if (method === "email" && !value.trim().toLowerCase().endsWith("@corp.example")) {
|
|
2719
|
+
* return "Use your corporate email address";
|
|
2720
|
+
* }
|
|
2721
|
+
* return super.validateMfaAddress(ctx, method, value);
|
|
2722
|
+
* }
|
|
2723
|
+
* ```
|
|
2603
2724
|
*/
|
|
2604
|
-
protected validateMfaAddress(method: MfaTransport, value: string): string | undefined
|
|
2725
|
+
protected validateMfaAddress(_ctx: AuthWfCtx, method: MfaTransport, value: string): string | undefined | Promise<string | undefined>;
|
|
2605
2726
|
/**
|
|
2606
2727
|
* Light normalization of a validated MFA address before it is stored. Default:
|
|
2607
2728
|
* trims, and strips spacing/punctuation from SMS numbers while KEEPING the
|
|
@@ -2869,10 +2990,17 @@ declare class AuthWorkflow {
|
|
|
2869
2990
|
/**
|
|
2870
2991
|
* Terminal for the manage-MFA flow. The user KEEPS their current session (no
|
|
2871
2992
|
* re-issue, no cookies) — a plain data finish. Outcomes, in priority order:
|
|
2872
|
-
* removed → changed (`replace` + done) → added (done) →
|
|
2873
|
-
* (
|
|
2993
|
+
* removed → changed (`replace` + done) → added (done) → blocked
|
|
2994
|
+
* (un-removable operation aborted by `confirm-remove-mfa`) →
|
|
2995
|
+
* nothing-available (zero candidates, never had to step-up) → cancelled.
|
|
2874
2996
|
*/
|
|
2875
2997
|
finishAddMfa(ctx: AuthWfCtx): undefined;
|
|
2998
|
+
/**
|
|
2999
|
+
* `finish-add-mfa`'s envelope construction, extracted pure so the outcome
|
|
3000
|
+
* priority (removed → changed → added → blocked → nothing-available →
|
|
3001
|
+
* cancelled) is unit-testable without a wf event context.
|
|
3002
|
+
*/
|
|
3003
|
+
protected buildAddMfaFinishEnvelope(ctx: AuthWfCtx): WfFinished;
|
|
2876
3004
|
/**
|
|
2877
3005
|
* Resolve which transports the user may NOT change/remove via the manage flow
|
|
2878
3006
|
* (calls {@link resolveLockedMfaTransports}) and write them to
|
|
@@ -2887,6 +3015,22 @@ declare class AuthWorkflow {
|
|
|
2887
3015
|
* encapsulated when no durable store is wired (the registry default).
|
|
2888
3016
|
*/
|
|
2889
3017
|
manageStepUpDone(ctx: AuthWfCtx): undefined;
|
|
3018
|
+
/**
|
|
3019
|
+
* Manage-MFA step-up consent — pauses on `StepUpConfirmForm` ("To continue,
|
|
3020
|
+
* we will send a verification code to ma•••@x") BEFORE `pincode-send`
|
|
3021
|
+
* dispatches the step-up code, so opening the manage dialog never consumes
|
|
3022
|
+
* a code send as a side effect. Fires only on the auto-picked paths (single
|
|
3023
|
+
* factor, or default factor) — an explicit `select-2fa` pick already
|
|
3024
|
+
* counts as consent (`select2fa` sets `stepUpConfirmed`). `Continue`
|
|
3025
|
+
* consents and the SAME engine pass mints + sends; `useDifferentMethod`
|
|
3026
|
+
* re-opens the picker; `cancel` aborts with nothing dispatched (the
|
|
3027
|
+
* schema's `{ break: aborted }` right after this step keeps the pair from
|
|
3028
|
+
* sending the declined code). Gated by {@link resolveStepUpConfirmBeforeSend}
|
|
3029
|
+
* (default on) — an opt-out marks consent and falls straight through.
|
|
3030
|
+
*/
|
|
3031
|
+
manageStepUpConfirm(ctx: AuthWfCtx): undefined | Promise<undefined>;
|
|
3032
|
+
/** `manage-stepup-confirm` tail — opt-out fall-through or the consent pause. */
|
|
3033
|
+
private applyStepUpConfirm;
|
|
2890
3034
|
/**
|
|
2891
3035
|
* Manage-MFA password re-auth — the step-up FALLBACK when the user's only
|
|
2892
3036
|
* confirmed factor(s) are of kinds the policy no longer allows, so nothing is
|
|
@@ -2900,6 +3044,15 @@ declare class AuthWorkflow {
|
|
|
2900
3044
|
* subject), and `verifyPassword` is the same check `changePassword` enforces.
|
|
2901
3045
|
*/
|
|
2902
3046
|
managePasswordReauth(ctx: AuthWfCtx): Promise<undefined>;
|
|
3047
|
+
/**
|
|
3048
|
+
* The keep-at-least-one rule: removing the user's LAST confirmed factor under
|
|
3049
|
+
* a `required` policy can never succeed. The single source for the predicate
|
|
3050
|
+
* `manage-menu` mirrors into `addMfa.removeBlocked` (to drop the Remove option)
|
|
3051
|
+
* AND `confirm-remove-mfa` re-checks before its pause (defence in depth) — so
|
|
3052
|
+
* a policy change (e.g. "keep at least two", or a backup-codes exception)
|
|
3053
|
+
* lands in one place, not two copies that can drift.
|
|
3054
|
+
*/
|
|
3055
|
+
private isLastRequiredFactor;
|
|
2903
3056
|
/**
|
|
2904
3057
|
* Manage-MFA menu — pauses on `ManageMfaForm` and routes the chosen
|
|
2905
3058
|
* `operation` (`add:<t>` / `replace:<t>` / `remove:<t>`). Only reached when
|
|
@@ -2912,8 +3065,13 @@ declare class AuthWorkflow {
|
|
|
2912
3065
|
/**
|
|
2913
3066
|
* Manage-MFA remove confirmation. Pauses on `RemoveMfaConfirmForm`; the
|
|
2914
3067
|
* 'Remove' submit performs the removal, 'Cancel' aborts. Re-checks the locked
|
|
2915
|
-
* set
|
|
2916
|
-
*
|
|
3068
|
+
* set and the keep-at-least-one rule (LAST confirmed factor under a
|
|
3069
|
+
* `required` policy) BEFORE the pause — and an un-removable state aborts to
|
|
3070
|
+
* the `finish-add-mfa` terminal (reason on `addMfa.blocked`) instead of
|
|
3071
|
+
* pausing: `manage-menu` filters these operations out, so arriving here
|
|
3072
|
+
* blocked means a stale/crafted route, and a retryable form whose only
|
|
3073
|
+
* submit re-throws the same guard would be a dead-end loop (the manage
|
|
3074
|
+
* forms hide their built-in cancel — the host owns it).
|
|
2917
3075
|
*/
|
|
2918
3076
|
confirmRemoveMfa(ctx: AuthWfCtx): Promise<undefined>;
|
|
2919
3077
|
askChannel(ctx: AuthWfCtx, channel: "email" | "phone"): Promise<unknown>;
|
|
@@ -2996,17 +3154,30 @@ declare class AuthWorkflow {
|
|
|
2996
3154
|
enrollPickMethod(ctx: AuthWfCtx): undefined | Promise<undefined>;
|
|
2997
3155
|
/**
|
|
2998
3156
|
* Unified MFA-enrol phase 2 (collect sms/email address). Not invoked for
|
|
2999
|
-
* totp.
|
|
3000
|
-
*
|
|
3001
|
-
*
|
|
3002
|
-
*
|
|
3003
|
-
*
|
|
3004
|
-
*
|
|
3005
|
-
*
|
|
3006
|
-
*
|
|
3007
|
-
*
|
|
3008
|
-
|
|
3009
|
-
|
|
3157
|
+
* totp. Asks {@link resolveEnrollAddress} FIRST — a deployment that pins
|
|
3158
|
+
* the address (factor bound to an account record) stages it here and the
|
|
3159
|
+
* free-text form never renders; this single call site covers every trio
|
|
3160
|
+
* path (picker, auto-pick, manage add/replace pre-seed), and `enroll-send`
|
|
3161
|
+
* dispatches to the pinned address in the same engine pass. Otherwise
|
|
3162
|
+
* (`'collect'`) handles `skip` (opt-in) / `cancel` (manage) /
|
|
3163
|
+
* `useDifferentMethod`, validates the typed address server-side via the
|
|
3164
|
+
* ctx-first {@link validateMfaAddress} (the client `@ui.form.validate`
|
|
3165
|
+
* hint is advisory), then STAGES the candidate value in wf-state
|
|
3166
|
+
* (`m.address`) — the user record is written only on confirm
|
|
3167
|
+
* (write-on-confirm), so an ADD leaves no partial row and a REPLACE keeps
|
|
3168
|
+
* the old confirmed value live until the new code verifies in
|
|
3169
|
+
* `enroll-confirm`. Collection ONLY: the pincode dispatch lives in
|
|
3170
|
+
* `enroll-send` (same engine pass, no extra round-trip), so a consumer
|
|
3171
|
+
* pre-seeding `mfaEnroll.address` — which skips this whole step via its
|
|
3172
|
+
* schema condition — still gets exactly one code.
|
|
3173
|
+
*/
|
|
3174
|
+
enrollAddress(ctx: AuthWfCtx): undefined | Promise<undefined>;
|
|
3175
|
+
/**
|
|
3176
|
+
* `enroll-address` tail — stage a pinned address, or run the free-text
|
|
3177
|
+
* collect pause (skip/cancel/useDifferentMethod triage + ctx-first
|
|
3178
|
+
* validation + write-on-confirm staging).
|
|
3179
|
+
*/
|
|
3180
|
+
private collectEnrollAddress;
|
|
3010
3181
|
/**
|
|
3011
3182
|
* Unified MFA-enrol dispatch (sms/email only) — the trio's ONLY pincode
|
|
3012
3183
|
* send. A separate step (the canonical "send if no pin" gate, mirroring
|
|
@@ -3476,12 +3647,19 @@ declare class AuthWorkflow {
|
|
|
3476
3647
|
* 3. STEP-UP (only when `stepUpRequired`): re-verify identity before any
|
|
3477
3648
|
* change — `mfaStepUpLoop` challenges an EXISTING factor when one is still
|
|
3478
3649
|
* challengeable (`stepUpMode==='mfa'`), else `manage-password-reauth` falls
|
|
3479
|
-
* back to the account password (`stepUpMode==='password'`).
|
|
3650
|
+
* back to the account password (`stepUpMode==='password'`). The sms/email
|
|
3651
|
+
* challenge collects explicit consent (`manage-stepup-confirm`) BEFORE
|
|
3652
|
+
* dispatching its pincode — opening the dialog never sends a code as a
|
|
3653
|
+
* side effect (see `resolveStepUpConfirmBeforeSend`). On success
|
|
3480
3654
|
* `manage-stepup-done` swaps off the encapsulated start onto the durable
|
|
3481
3655
|
* `store` strategy (server-anchored, replay-resistant; mirrors login's
|
|
3482
3656
|
* swap-after-credentials).
|
|
3483
3657
|
* 4. `manage-menu` (only when `stepUpRequired`) — pick add / change / remove +
|
|
3484
|
-
* target; pre-seeds `mfaEnroll.method` for add/change.
|
|
3658
|
+
* target; pre-seeds `mfaEnroll.method` for add/change. Un-offerable
|
|
3659
|
+
* operations never render: locked transports drop their Change/Remove
|
|
3660
|
+
* options, and the LAST factor under a `required` policy drops Remove
|
|
3661
|
+
* (`removeBlocked`) — `confirm-remove-mfa` aborts to the finish terminal
|
|
3662
|
+
* if a blocked remove arrives anyway (no retryable dead-end form).
|
|
3485
3663
|
* 5. Route: `confirm-remove-mfa` for remove; otherwise the REUSED enrol trio
|
|
3486
3664
|
* (`enroll-pick-method` → `enroll-address` / `enroll-totp-qr` →
|
|
3487
3665
|
* `enroll-confirm`). A zero-MFA user skips step-up + menu and lands on the
|