From 8da84e61dfe7382a6a862a4984561642ab780a00 Mon Sep 17 00:00:00 2001 From: Aleksander <170264518+t-aleksander@users.noreply.github.com> Date: Tue, 20 Oct 2026 13:21:52 +0200 Subject: [PATCH 1/3] move fido code --- .../ConfigureSelectMethodsStep.tsx | 5 +++++ .../components/MethodRow.tsx | 9 +++++++- new-ui/src/shared/utils/mfa.test.ts | 22 +++++++++++++++++++ new-ui/src/shared/utils/mfa.ts | 13 +++++++++++ src-tauri/Cargo.toml | 4 ++-- src-tauri/deny.toml | 6 ++--- src-tauri/{ => enterprise}/fido2/Cargo.toml | 2 +- src-tauri/{ => enterprise}/fido2/src/hid.rs | 0 src-tauri/{ => enterprise}/fido2/src/lib.rs | 0 .../{ => enterprise}/fido2/src/protocol.rs | 0 .../fido2/src/protocol/tests.rs | 0 .../{ => enterprise}/fido2/src/windows/api.rs | 0 .../fido2/src/windows/convert.rs | 0 .../{ => enterprise}/fido2/src/windows/mod.rs | 0 .../fido2/src/windows/options.rs | 0 15 files changed, 54 insertions(+), 7 deletions(-) rename src-tauri/{ => enterprise}/fido2/Cargo.toml (97%) rename src-tauri/{ => enterprise}/fido2/src/hid.rs (100%) rename src-tauri/{ => enterprise}/fido2/src/lib.rs (100%) rename src-tauri/{ => enterprise}/fido2/src/protocol.rs (100%) rename src-tauri/{ => enterprise}/fido2/src/protocol/tests.rs (100%) rename src-tauri/{ => enterprise}/fido2/src/windows/api.rs (100%) rename src-tauri/{ => enterprise}/fido2/src/windows/convert.rs (100%) rename src-tauri/{ => enterprise}/fido2/src/windows/mod.rs (100%) rename src-tauri/{ => enterprise}/fido2/src/windows/options.rs (100%) diff --git a/new-ui/src/pages/full/ConfigureMfaPage/verify/ConfigureSelectMethodsStep/ConfigureSelectMethodsStep.tsx b/new-ui/src/pages/full/ConfigureMfaPage/verify/ConfigureSelectMethodsStep/ConfigureSelectMethodsStep.tsx index 9a9ed86cf..8dd77e023 100644 --- a/new-ui/src/pages/full/ConfigureMfaPage/verify/ConfigureSelectMethodsStep/ConfigureSelectMethodsStep.tsx +++ b/new-ui/src/pages/full/ConfigureMfaPage/verify/ConfigureSelectMethodsStep/ConfigureSelectMethodsStep.tsx @@ -19,6 +19,7 @@ import { isClientConfigurableMethod, isDesktopDrivableMethod, isMfaMethodAvailable, + isMfaMethodLicenseLocked, mfaStepsOf as locationMfaSteps, mfaToText, setupMethodsOf, @@ -103,10 +104,13 @@ export const ConfigureSelectMethodsStep = ({ onCancel }: Props) => { const configured = accountConfigured.includes(method); const available = isMfaMethodAvailable(method, instance); const satisfied = configuredMethods.includes(method) && available; + const locked = isMfaMethodLicenseLocked(method, instance); let hint: string | null = null; if (!available) { hint = `${mfaToText(method, instance ?? undefined)} is not available on this Defguard instance.`; + } else if (locked) { + hint = `${mfaToText(method)} requires an Enterprise license on this Defguard instance.`; } else if (disabled && !configured) { if (satisfied) { // Reached only via the email fallback, which registers the factor as it verifies. @@ -128,6 +132,7 @@ export const ConfigureSelectMethodsStep = ({ onCancel }: Props) => { disabled, configured, hint, + locked, }; }, [accountConfigured, configuredMethods, setupMethods, selected, instance], diff --git a/new-ui/src/pages/full/ConfigureMfaPage/verify/ConfigureSelectMethodsStep/components/MethodRow.tsx b/new-ui/src/pages/full/ConfigureMfaPage/verify/ConfigureSelectMethodsStep/components/MethodRow.tsx index 80a099be7..21c52becc 100644 --- a/new-ui/src/pages/full/ConfigureMfaPage/verify/ConfigureSelectMethodsStep/components/MethodRow.tsx +++ b/new-ui/src/pages/full/ConfigureMfaPage/verify/ConfigureSelectMethodsStep/components/MethodRow.tsx @@ -19,6 +19,8 @@ export type MethodRowState = { configured: boolean; /** Why the row is disabled, when a badge does not already say it. */ hint: string | null; + /** The instance license does not allow the factor, so the hint shows a lock. */ + locked: boolean; }; interface Props extends MethodRowState { @@ -31,6 +33,7 @@ export const MethodRow = ({ disabled, configured, hint, + locked, onToggle, }: Props) => (
@@ -52,7 +55,11 @@ export const MethodRow = ({ {isPresent(hint) && ( - +

{hint}

diff --git a/new-ui/src/shared/utils/mfa.test.ts b/new-ui/src/shared/utils/mfa.test.ts index 89d453ed2..99898f4a3 100644 --- a/new-ui/src/shared/utils/mfa.test.ts +++ b/new-ui/src/shared/utils/mfa.test.ts @@ -15,6 +15,7 @@ import { connectionAbilityOf, hasMfaMethodChoice, isMfaMethodAvailable, + isMfaMethodLicenseLocked, mfaConfigurableInstances, resolveMfaStepPlan, setupMethodsOf, @@ -122,6 +123,27 @@ describe('setupMethodsOf', () => { }); }); +describe('isMfaMethodLicenseLocked', () => { + it('locks FIDO2 when Core leaves it out of the setup methods', () => { + const instance = { + mfa_capabilities: capabilitiesOf([MfaMethod.Totp, MfaMethod.Email]), + }; + expect(isMfaMethodLicenseLocked(MfaMethod.Fido2, instance)).toBe(true); + expect(isMfaMethodLicenseLocked(MfaMethod.Totp, instance)).toBe(false); + }); + + it('does not lock FIDO2 when Core offers it or cannot configure from the client', () => { + const offered = { + mfa_capabilities: capabilitiesOf([MfaMethod.Totp, MfaMethod.Fido2]), + }; + expect(isMfaMethodLicenseLocked(MfaMethod.Fido2, offered)).toBe(false); + expect(isMfaMethodLicenseLocked(MfaMethod.Fido2, { mfa_capabilities: null })).toBe( + false, + ); + expect(isMfaMethodLicenseLocked(MfaMethod.Fido2, undefined)).toBe(false); + }); +}); + describe('canSetUpMfaMethod', () => { it('needs both the client and the instance', () => { const instance = { diff --git a/new-ui/src/shared/utils/mfa.ts b/new-ui/src/shared/utils/mfa.ts index ca5e51cd9..a61cab5d4 100644 --- a/new-ui/src/shared/utils/mfa.ts +++ b/new-ui/src/shared/utils/mfa.ts @@ -208,6 +208,19 @@ export const canSetUpMfaMethod = ( ): method is ClientConfigurableMethod => setupMethodsOf(instance).some((candidate) => candidate === method); +/** Core leaves FIDO2 out of the setup methods when its license lacks the Enterprise tier. */ +export const isMfaMethodLicenseLocked = ( + method: MfaMethodValue, + instance?: Pick | null, +): boolean => { + const coreSetupMethods = instance?.mfa_capabilities?.setup_methods; + return ( + method === MfaMethod.Fido2 && + isPresent(coreSetupMethods) && + !coreSetupMethods.includes(method) + ); +}; + /** What this client can authorize an MFA configuration session with. Mirrors * AUTHORIZING_METHODS in core mfa_config.rs. */ const clientAuthorizingMethods: MfaMethodValue[] = [ diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 1ca4b7b85..8c91a7894 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["cli", "client-cli", "common", "client-proto", "core", "daemon", "fido2", "enterprise/posture", "enterprise/provisioning", "enterprise/config-sync", "enterprise/service-locations"] +members = ["cli", "client-cli", "common", "client-proto", "core", "daemon", "enterprise/fido2", "enterprise/posture", "enterprise/provisioning", "enterprise/config-sync", "enterprise/service-locations"] default-members = ["cli", "client-cli", "daemon", "."] [workspace.dependencies] @@ -131,7 +131,7 @@ redundant_closure = "warn" base64.workspace = true chrono.workspace = true defguard-cli.path = "client-cli" -defguard-client-fido2.path = "fido2" +defguard-client-fido2.path = "enterprise/fido2" defguard-client-proto.path = "client-proto" defguard-client-core.path = "core" defguard-client-posture.path = "enterprise/posture" diff --git a/src-tauri/deny.toml b/src-tauri/deny.toml index aa2b73fbc..65b8f7003 100644 --- a/src-tauri/deny.toml +++ b/src-tauri/deny.toml @@ -144,9 +144,6 @@ exceptions = [ { allow = [ "AGPL-3.0-or-later", ], crate = "defguard-client-core" }, - { allow = [ - "AGPL-3.0-or-later", - ], crate = "defguard-client-fido2" }, { allow = [ "AGPL-3.0-or-later", ], crate = "defguard-client-service" }, @@ -168,6 +165,9 @@ exceptions = [ { allow = [ "LicenseRef-Proprietary", ], crate = "defguard-client-service-locations" }, + { allow = [ + "LicenseRef-Proprietary", + ], crate = "defguard-client-fido2" }, ] # Some crates don't have (easily) machine readable licensing information, diff --git a/src-tauri/fido2/Cargo.toml b/src-tauri/enterprise/fido2/Cargo.toml similarity index 97% rename from src-tauri/fido2/Cargo.toml rename to src-tauri/enterprise/fido2/Cargo.toml index d37be7abc..1ff3cf7ef 100644 --- a/src-tauri/fido2/Cargo.toml +++ b/src-tauri/enterprise/fido2/Cargo.toml @@ -4,7 +4,7 @@ description = "FIDO2 security key ceremonies for the Defguard desktop client (Ta authors.workspace = true edition.workspace = true homepage.workspace = true -license-file.workspace = true +license = "LicenseRef-Proprietary" rust-version.workspace = true version.workspace = true diff --git a/src-tauri/fido2/src/hid.rs b/src-tauri/enterprise/fido2/src/hid.rs similarity index 100% rename from src-tauri/fido2/src/hid.rs rename to src-tauri/enterprise/fido2/src/hid.rs diff --git a/src-tauri/fido2/src/lib.rs b/src-tauri/enterprise/fido2/src/lib.rs similarity index 100% rename from src-tauri/fido2/src/lib.rs rename to src-tauri/enterprise/fido2/src/lib.rs diff --git a/src-tauri/fido2/src/protocol.rs b/src-tauri/enterprise/fido2/src/protocol.rs similarity index 100% rename from src-tauri/fido2/src/protocol.rs rename to src-tauri/enterprise/fido2/src/protocol.rs diff --git a/src-tauri/fido2/src/protocol/tests.rs b/src-tauri/enterprise/fido2/src/protocol/tests.rs similarity index 100% rename from src-tauri/fido2/src/protocol/tests.rs rename to src-tauri/enterprise/fido2/src/protocol/tests.rs diff --git a/src-tauri/fido2/src/windows/api.rs b/src-tauri/enterprise/fido2/src/windows/api.rs similarity index 100% rename from src-tauri/fido2/src/windows/api.rs rename to src-tauri/enterprise/fido2/src/windows/api.rs diff --git a/src-tauri/fido2/src/windows/convert.rs b/src-tauri/enterprise/fido2/src/windows/convert.rs similarity index 100% rename from src-tauri/fido2/src/windows/convert.rs rename to src-tauri/enterprise/fido2/src/windows/convert.rs diff --git a/src-tauri/fido2/src/windows/mod.rs b/src-tauri/enterprise/fido2/src/windows/mod.rs similarity index 100% rename from src-tauri/fido2/src/windows/mod.rs rename to src-tauri/enterprise/fido2/src/windows/mod.rs diff --git a/src-tauri/fido2/src/windows/options.rs b/src-tauri/enterprise/fido2/src/windows/options.rs similarity index 100% rename from src-tauri/fido2/src/windows/options.rs rename to src-tauri/enterprise/fido2/src/windows/options.rs From 1864aa49669e596ff9c9d7a7dd76a910076a3957 Mon Sep 17 00:00:00 2001 From: Aleksander <170264518+t-aleksander@users.noreply.github.com> Date: Thu, 22 Oct 2026 12:51:47 +0200 Subject: [PATCH 2/3] make labels more generic --- .../ConfigureSelectMethodsStep.tsx | 8 +++---- .../components/MethodRow.tsx | 2 +- new-ui/src/shared/utils/mfa.test.ts | 22 ++++++++++++------- new-ui/src/shared/utils/mfa.ts | 9 +++++--- 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/new-ui/src/pages/full/ConfigureMfaPage/verify/ConfigureSelectMethodsStep/ConfigureSelectMethodsStep.tsx b/new-ui/src/pages/full/ConfigureMfaPage/verify/ConfigureSelectMethodsStep/ConfigureSelectMethodsStep.tsx index 8dd77e023..d447ec097 100644 --- a/new-ui/src/pages/full/ConfigureMfaPage/verify/ConfigureSelectMethodsStep/ConfigureSelectMethodsStep.tsx +++ b/new-ui/src/pages/full/ConfigureMfaPage/verify/ConfigureSelectMethodsStep/ConfigureSelectMethodsStep.tsx @@ -19,7 +19,7 @@ import { isClientConfigurableMethod, isDesktopDrivableMethod, isMfaMethodAvailable, - isMfaMethodLicenseLocked, + isMfaMethodLocked, mfaStepsOf as locationMfaSteps, mfaToText, setupMethodsOf, @@ -104,13 +104,11 @@ export const ConfigureSelectMethodsStep = ({ onCancel }: Props) => { const configured = accountConfigured.includes(method); const available = isMfaMethodAvailable(method, instance); const satisfied = configuredMethods.includes(method) && available; - const locked = isMfaMethodLicenseLocked(method, instance); + const locked = isMfaMethodLocked(method, instance); let hint: string | null = null; - if (!available) { + if (!available || locked) { hint = `${mfaToText(method, instance ?? undefined)} is not available on this Defguard instance.`; - } else if (locked) { - hint = `${mfaToText(method)} requires an Enterprise license on this Defguard instance.`; } else if (disabled && !configured) { if (satisfied) { // Reached only via the email fallback, which registers the factor as it verifies. diff --git a/new-ui/src/pages/full/ConfigureMfaPage/verify/ConfigureSelectMethodsStep/components/MethodRow.tsx b/new-ui/src/pages/full/ConfigureMfaPage/verify/ConfigureSelectMethodsStep/components/MethodRow.tsx index 21c52becc..def4bc336 100644 --- a/new-ui/src/pages/full/ConfigureMfaPage/verify/ConfigureSelectMethodsStep/components/MethodRow.tsx +++ b/new-ui/src/pages/full/ConfigureMfaPage/verify/ConfigureSelectMethodsStep/components/MethodRow.tsx @@ -19,7 +19,7 @@ export type MethodRowState = { configured: boolean; /** Why the row is disabled, when a badge does not already say it. */ hint: string | null; - /** The instance license does not allow the factor, so the hint shows a lock. */ + /** The instance withholds the factor, so the hint shows a lock. */ locked: boolean; }; diff --git a/new-ui/src/shared/utils/mfa.test.ts b/new-ui/src/shared/utils/mfa.test.ts index 99898f4a3..641efb25c 100644 --- a/new-ui/src/shared/utils/mfa.test.ts +++ b/new-ui/src/shared/utils/mfa.test.ts @@ -15,7 +15,7 @@ import { connectionAbilityOf, hasMfaMethodChoice, isMfaMethodAvailable, - isMfaMethodLicenseLocked, + isMfaMethodLocked, mfaConfigurableInstances, resolveMfaStepPlan, setupMethodsOf, @@ -123,24 +123,30 @@ describe('setupMethodsOf', () => { }); }); -describe('isMfaMethodLicenseLocked', () => { - it('locks FIDO2 when Core leaves it out of the setup methods', () => { +describe('isMfaMethodLocked', () => { + it('locks a client-configurable method Core leaves out of the setup methods', () => { const instance = { mfa_capabilities: capabilitiesOf([MfaMethod.Totp, MfaMethod.Email]), }; - expect(isMfaMethodLicenseLocked(MfaMethod.Fido2, instance)).toBe(true); - expect(isMfaMethodLicenseLocked(MfaMethod.Totp, instance)).toBe(false); + expect(isMfaMethodLocked(MfaMethod.Fido2, instance)).toBe(true); + expect(isMfaMethodLocked(MfaMethod.Totp, instance)).toBe(false); + expect(isMfaMethodLocked(MfaMethod.Oidc, instance)).toBe(false); + + const withoutTotp = { + mfa_capabilities: capabilitiesOf([MfaMethod.Email, MfaMethod.Fido2]), + }; + expect(isMfaMethodLocked(MfaMethod.Totp, withoutTotp)).toBe(true); }); it('does not lock FIDO2 when Core offers it or cannot configure from the client', () => { const offered = { mfa_capabilities: capabilitiesOf([MfaMethod.Totp, MfaMethod.Fido2]), }; - expect(isMfaMethodLicenseLocked(MfaMethod.Fido2, offered)).toBe(false); - expect(isMfaMethodLicenseLocked(MfaMethod.Fido2, { mfa_capabilities: null })).toBe( + expect(isMfaMethodLocked(MfaMethod.Fido2, offered)).toBe(false); + expect(isMfaMethodLocked(MfaMethod.Fido2, { mfa_capabilities: null })).toBe( false, ); - expect(isMfaMethodLicenseLocked(MfaMethod.Fido2, undefined)).toBe(false); + expect(isMfaMethodLocked(MfaMethod.Fido2, undefined)).toBe(false); }); }); diff --git a/new-ui/src/shared/utils/mfa.ts b/new-ui/src/shared/utils/mfa.ts index a61cab5d4..79584a6b0 100644 --- a/new-ui/src/shared/utils/mfa.ts +++ b/new-ui/src/shared/utils/mfa.ts @@ -208,14 +208,17 @@ export const canSetUpMfaMethod = ( ): method is ClientConfigurableMethod => setupMethodsOf(instance).some((candidate) => candidate === method); -/** Core leaves FIDO2 out of the setup methods when its license lacks the Enterprise tier. */ -export const isMfaMethodLicenseLocked = ( +/** + * Every Core that reports capabilities knows all client-configurable methods, so one it leaves out + * of the setup methods is withheld from this instance. + */ +export const isMfaMethodLocked = ( method: MfaMethodValue, instance?: Pick | null, ): boolean => { const coreSetupMethods = instance?.mfa_capabilities?.setup_methods; return ( - method === MfaMethod.Fido2 && + isClientConfigurableMethod(method) && isPresent(coreSetupMethods) && !coreSetupMethods.includes(method) ); From edf06f524f3c1d9e95606b22200b64dd6768895c Mon Sep 17 00:00:00 2001 From: Aleksander <170264518+t-aleksander@users.noreply.github.com> Date: Thu, 22 Oct 2026 12:56:08 +0200 Subject: [PATCH 3/3] merge two lists --- .../hooks/useConfigureMfaStore.tsx | 18 ++++++++---------- .../src/pages/full/ConfigureMfaPage/types.ts | 12 +----------- .../src/pages/full/ConfigureMfaPage/utils.ts | 10 +++++----- .../verify/ConfigureMfaVerify.tsx | 4 ++-- .../ConfigureSelectVerificationStep.tsx | 6 ++++-- new-ui/src/shared/utils/mfa.ts | 12 +++++++----- 6 files changed, 27 insertions(+), 35 deletions(-) diff --git a/new-ui/src/pages/full/ConfigureMfaPage/hooks/useConfigureMfaStore.tsx b/new-ui/src/pages/full/ConfigureMfaPage/hooks/useConfigureMfaStore.tsx index fdf06de92..092ba1920 100644 --- a/new-ui/src/pages/full/ConfigureMfaPage/hooks/useConfigureMfaStore.tsx +++ b/new-ui/src/pages/full/ConfigureMfaPage/hooks/useConfigureMfaStore.tsx @@ -13,14 +13,12 @@ import { type MfaMethodValue, } from '../../../../shared/rust-api/types'; import { isPresent } from '../../../../shared/utils/isPresent'; -import { setupMethodsOf } from '../../../../shared/utils/mfa'; -import { dismissEdgeComsError } from '../components/EdgeComsError/useEdgeComsErrorStore'; import { - ConfigureMfaStep, - type ConfigureMfaStepValue, - MFA_WIZARD_STEPS, - type MfaVerificationMethod, -} from '../types'; + type ClientAuthorizingMethod, + setupMethodsOf, +} from '../../../../shared/utils/mfa'; +import { dismissEdgeComsError } from '../components/EdgeComsError/useEdgeComsErrorStore'; +import { ConfigureMfaStep, type ConfigureMfaStepValue, MFA_WIZARD_STEPS } from '../types'; import { isCodeMfaMethod, isMfaFactorOfferable, @@ -45,9 +43,9 @@ type StoreValues = { /** Pre-ticked in the selection step, from the entry point or an earlier pass. */ initialSelection: MfaMethodValue[]; /** most preferred first, from the session since an older Core rejects some factors */ - verificationMethods: MfaVerificationMethod[]; + verificationMethods: ClientAuthorizingMethod[]; /** null until picked, asked only when the session offers more than one method */ - verificationMethod: MfaVerificationMethod | null; + verificationMethod: ClientAuthorizingMethod | null; /** No factor was configured, so an emailed code was the only way in. */ emailFallback: boolean; /** ISO timestamp the session dies at, null once nothing in the flow needs it. */ @@ -136,7 +134,7 @@ interface Store extends StoreValues { origin: ConfigureMfaOrigin, ) => void; selectMethods: (methods: MfaMethodValue[]) => void; - selectVerificationMethod: (method: MfaVerificationMethod) => void; + selectVerificationMethod: (method: ClientAuthorizingMethod) => void; /** Keeps the current picks ticked and the session alive. */ backToSelection: () => void; backFromVerification: () => void; diff --git a/new-ui/src/pages/full/ConfigureMfaPage/types.ts b/new-ui/src/pages/full/ConfigureMfaPage/types.ts index 3be9ef2ba..7f6ac7614 100644 --- a/new-ui/src/pages/full/ConfigureMfaPage/types.ts +++ b/new-ui/src/pages/full/ConfigureMfaPage/types.ts @@ -1,4 +1,4 @@ -import { MfaMethod, type MfaMethodValue } from '../../../shared/rust-api/types'; +import type { MfaMethodValue } from '../../../shared/rust-api/types'; /** Wizard steps, in the order they run. Setup steps are the ones a factor can claim. */ export const ConfigureMfaStep = { @@ -25,13 +25,3 @@ export type MfaFactor = { /** Whether the account can hold several of these, so it stays offerable once configured. */ repeatable: boolean; }; - -/** most preferred first */ -export const mfaVerificationMethods = [ - MfaMethod.Totp, - MfaMethod.Email, - MfaMethod.Fido2, - MfaMethod.Oidc, -] as const; - -export type MfaVerificationMethod = (typeof mfaVerificationMethods)[number]; diff --git a/new-ui/src/pages/full/ConfigureMfaPage/utils.ts b/new-ui/src/pages/full/ConfigureMfaPage/utils.ts index e0fe944d5..254332a76 100644 --- a/new-ui/src/pages/full/ConfigureMfaPage/utils.ts +++ b/new-ui/src/pages/full/ConfigureMfaPage/utils.ts @@ -4,7 +4,9 @@ import { type MfaMethodValue, } from '../../../shared/rust-api/types'; import { + CLIENT_AUTHORIZING_METHODS, CLIENT_CONFIGURABLE_METHODS, + type ClientAuthorizingMethod, type ClientConfigurableMethod, } from '../../../shared/utils/mfa'; import { @@ -12,8 +14,6 @@ import { type ConfigureMfaStepValue, MFA_WIZARD_STEPS, type MfaFactor, - type MfaVerificationMethod, - mfaVerificationMethods, } from './types'; /** Keyed on the shared list, so a new factor fails to compile until mapped here. */ @@ -64,13 +64,13 @@ export const isCodeMfaMethod = (method: MfaMethodValue): boolean => /** ordered by preference, not by the input */ export const verificationMethodsOf = ( availableMethods: MfaMethodValue[], -): MfaVerificationMethod[] => - mfaVerificationMethods.filter((method) => availableMethods.includes(method)); +): ClientAuthorizingMethod[] => + CLIENT_AUTHORIZING_METHODS.filter((method) => availableMethods.includes(method)); /** The fallback mails a code to the address on file, so email is the only way in. */ export const sessionVerificationMethodsOf = ( response: Pick, -): MfaVerificationMethod[] => +): ClientAuthorizingMethod[] => verificationMethodsOf( response.email_fallback ? [MfaMethod.Email] : response.available_methods, ); diff --git a/new-ui/src/pages/full/ConfigureMfaPage/verify/ConfigureMfaVerify.tsx b/new-ui/src/pages/full/ConfigureMfaPage/verify/ConfigureMfaVerify.tsx index 6b54141e4..0b1b70cce 100644 --- a/new-ui/src/pages/full/ConfigureMfaPage/verify/ConfigureMfaVerify.tsx +++ b/new-ui/src/pages/full/ConfigureMfaPage/verify/ConfigureMfaVerify.tsx @@ -1,7 +1,7 @@ import { MfaMethod } from '../../../../shared/rust-api/types'; import { isPresent } from '../../../../shared/utils/isPresent'; +import type { ClientAuthorizingMethod } from '../../../../shared/utils/mfa'; import { useConfigureMfaStore } from '../hooks/useConfigureMfaStore'; -import type { MfaVerificationMethod } from '../types'; import { ConfigureSelectMethodsStep } from './ConfigureSelectMethodsStep/ConfigureSelectMethodsStep'; import { ConfigureSelectVerificationStep } from './ConfigureSelectVerificationStep/ConfigureSelectVerificationStep'; import { ConfigureVerifyEmailStep } from './ConfigureVerifyEmailStep/ConfigureVerifyEmailStep'; @@ -29,7 +29,7 @@ export const ConfigureMfaVerify = ({ onCancel, onSessionExpired }: Props) => { } // for the type only, a session with nothing to verify with is refused at start - const method: MfaVerificationMethod = + const method: ClientAuthorizingMethod = verificationMethod ?? candidates[0] ?? MfaMethod.Email; switch (method) { diff --git a/new-ui/src/pages/full/ConfigureMfaPage/verify/ConfigureSelectVerificationStep/ConfigureSelectVerificationStep.tsx b/new-ui/src/pages/full/ConfigureMfaPage/verify/ConfigureSelectVerificationStep/ConfigureSelectVerificationStep.tsx index 891111769..3d4fbe723 100644 --- a/new-ui/src/pages/full/ConfigureMfaPage/verify/ConfigureSelectVerificationStep/ConfigureSelectVerificationStep.tsx +++ b/new-ui/src/pages/full/ConfigureMfaPage/verify/ConfigureSelectVerificationStep/ConfigureSelectVerificationStep.tsx @@ -4,9 +4,9 @@ import { ButtonVariant } from '../../../../../shared/components/Button/types'; import { Controls } from '../../../../../shared/components/Controls/Controls'; import { FullPageTitle } from '../../../../../shared/components/FullPageTitle/FullPageTitle'; import { FullPage } from '../../../../../shared/layouts/FullPage/FullPage'; +import type { ClientAuthorizingMethod } from '../../../../../shared/utils/mfa'; import { ConfigureMfaVerificatorFactorSelector } from '../../components/ConfigureMfaVerificatorFactorSelector/ConfigureMfaVerificatorFactorSelector'; import { useConfigureMfaStore } from '../../hooks/useConfigureMfaStore'; -import type { MfaVerificationMethod } from '../../types'; import '../style.scss'; import './style.scss'; @@ -14,7 +14,9 @@ import './style.scss'; export const ConfigureSelectVerificationStep = () => { const methods = useConfigureMfaStore((s) => s.verificationMethods); - const [selected, setSelected] = useState(methods[0]); + const [selected, setSelected] = useState( + methods[0], + ); return ( & MfaCapabilitiesInstance; @@ -243,7 +245,7 @@ export type MfaConfigInstance = Pick & export const canAuthorizeMfaConfig = (instance?: MfaConfigInstance | null): boolean => { const authorizeMethods = instance?.mfa_capabilities?.authorize_methods ?? []; const configuredMethods = instance?.mfa_configured_methods ?? []; - const holdsAuthorizer = clientAuthorizingMethods.some( + const holdsAuthorizer = CLIENT_AUTHORIZING_METHODS.some( (method) => authorizeMethods.includes(method) && configuredMethods.includes(method) &&