hide mfa method from selection if phone or email is not verified

This commit is contained in:
peintnermax
2024-05-07 14:27:56 +02:00
parent 92e9150405
commit 09194d18f9
3 changed files with 72 additions and 43 deletions

View File

@@ -14,6 +14,7 @@ import {
getMostRecentCookieWithLoginname,
getSessionCookieById,
} from "#/utils/cookies";
import { user } from "@zitadel/server";
export default async function Page({
searchParams,
@@ -23,7 +24,7 @@ export default async function Page({
const { loginName, checkAfter, authRequestId, organization, sessionId } =
searchParams;
const sessionFactors = sessionId
const sessionWithData = sessionId
? await loadSessionById(sessionId, organization)
: await loadSessionByLoginname(loginName, organization);
@@ -37,13 +38,16 @@ export default async function Page({
);
return getSession(server, recent.id, recent.token).then((response) => {
if (response?.session && response.session.factors?.user?.id) {
return listAuthenticationMethodTypes(
response.session.factors.user.id
).then((methods) => {
return {
factors: response.session?.factors,
authMethods: methods.authMethodTypes ?? [],
};
const userId = response.session.factors.user.id;
return listAuthenticationMethodTypes(userId).then((methods) => {
return getUserByID(userId).then((user) => {
return {
factors: response.session?.factors,
authMethods: methods.authMethodTypes ?? [],
phoneVerified: user.user?.human?.phone?.isVerified ?? false,
emailVerified: user.user?.human?.email?.isVerified ?? false,
};
});
});
}
});
@@ -53,13 +57,16 @@ export default async function Page({
const recent = await getSessionCookieById(sessionId, organization);
return getSession(server, recent.id, recent.token).then((response) => {
if (response?.session && response.session.factors?.user?.id) {
return listAuthenticationMethodTypes(
response.session.factors.user.id
).then((methods) => {
return {
factors: response.session?.factors,
authMethods: methods.authMethodTypes ?? [],
};
const userId = response.session.factors.user.id;
return listAuthenticationMethodTypes(userId).then((methods) => {
return getUserByID(userId).then((user) => {
return {
factors: response.session?.factors,
authMethods: methods.authMethodTypes ?? [],
phoneVerified: user.user?.human?.phone?.isVerified ?? false,
emailVerified: user.user?.human?.email?.isVerified ?? false,
};
});
});
}
});
@@ -75,10 +82,10 @@ export default async function Page({
<p className="ztdl-p">Choose one of the following second factors.</p>
{sessionFactors && (
{sessionWithData && (
<UserAvatar
loginName={loginName ?? sessionFactors.factors?.user?.loginName}
displayName={sessionFactors.factors?.user?.displayName}
loginName={loginName ?? sessionWithData.factors?.user?.loginName}
displayName={sessionWithData.factors?.user?.displayName}
showDropdown
searchParams={searchParams}
></UserAvatar>
@@ -88,14 +95,16 @@ export default async function Page({
<Alert>Provide your active session as loginName param</Alert>
)}
{loginSettings && sessionFactors ? (
{loginSettings && sessionWithData ? (
<ChooseSecondFactorToSetup
loginName={loginName}
sessionId={sessionId}
authRequestId={authRequestId}
organization={organization}
loginSettings={loginSettings}
userMethods={sessionFactors.authMethods ?? []}
userMethods={sessionWithData.authMethods ?? []}
phoneVerified={sessionWithData.phoneVerified ?? false}
emailVerified={sessionWithData.emailVerified ?? false}
checkAfter={checkAfter === "true"}
></ChooseSecondFactorToSetup>
) : (

View File

@@ -2,16 +2,37 @@ import clsx from "clsx";
import Link from "next/link";
import { BadgeState, StateBadge } from "./StateBadge";
import { CheckIcon } from "@heroicons/react/24/solid";
import { ReactNode } from "react";
const cardClasses = (alreadyAdded: boolean) =>
clsx(
"relative bg-background-light-400 dark:bg-background-dark-400 group block space-y-1.5 rounded-md px-5 py-3 border border-divider-light dark:border-divider-dark transition-all ",
alreadyAdded ? "" : "hover:shadow-lg hover:dark:bg-white/10"
alreadyAdded
? "opacity-50 cursor-default"
: "hover:shadow-lg hover:dark:bg-white/10"
);
const LinkWrapper = ({
alreadyAdded,
children,
link,
}: {
alreadyAdded: boolean;
children: ReactNode;
link: string;
}) => {
return !alreadyAdded ? (
<Link href={link} className={cardClasses(alreadyAdded)}>
{children}
</Link>
) : (
<div className={cardClasses(alreadyAdded)}>{children}</div>
);
};
export const TOTP = (alreadyAdded: boolean, link: string) => {
return (
<Link href={link} className={cardClasses(alreadyAdded)}>
<LinkWrapper alreadyAdded={alreadyAdded} link={link}>
<div
className={clsx(
"font-medium flex items-center",
@@ -66,13 +87,13 @@ C72,238.87917,85.87916,225,102.99997,225H248z"
<Setup />
</>
)}
</Link>
</LinkWrapper>
);
};
export const U2F = (alreadyAdded: boolean, link: string) => {
return (
<Link href={link} className={cardClasses(alreadyAdded)}>
<LinkWrapper alreadyAdded={alreadyAdded} link={link}>
<div
className={clsx(
"font-medium flex items-center",
@@ -100,13 +121,13 @@ export const U2F = (alreadyAdded: boolean, link: string) => {
<Setup />
</>
)}
</Link>
</LinkWrapper>
);
};
export const EMAIL = (alreadyAdded: boolean, link: string) => {
return (
<Link href={link} className={cardClasses(alreadyAdded)}>
<LinkWrapper alreadyAdded={alreadyAdded} link={link}>
<div
className={clsx(
"font-medium flex items-center",
@@ -135,13 +156,13 @@ export const EMAIL = (alreadyAdded: boolean, link: string) => {
<Setup />
</>
)}
</Link>
</LinkWrapper>
);
};
export const SMS = (alreadyAdded: boolean, link: string) => {
return (
<Link href={link} className={cardClasses(alreadyAdded)}>
<LinkWrapper alreadyAdded={alreadyAdded} link={link}>
<div
className={clsx(
"font-medium flex items-center",
@@ -169,7 +190,7 @@ export const SMS = (alreadyAdded: boolean, link: string) => {
<Setup />
</>
)}
</Link>
</LinkWrapper>
);
};

View File

@@ -11,6 +11,8 @@ type Props = {
loginSettings: LoginSettings;
userMethods: AuthenticationMethodType[];
checkAfter: boolean;
phoneVerified: boolean;
emailVerified: boolean;
};
export default function ChooseSecondFactorToSetup({
@@ -21,6 +23,8 @@ export default function ChooseSecondFactorToSetup({
loginSettings,
userMethods,
checkAfter,
phoneVerified,
emailVerified,
}: Props) {
const params = new URLSearchParams({});
@@ -43,20 +47,15 @@ export default function ChooseSecondFactorToSetup({
return (
<div className="grid grid-cols-1 gap-5 w-full pt-4">
{loginSettings.secondFactors.map((factor, i) => {
return (
<div key={"method-" + i}>
{factor === 1 &&
TOTP(
userMethods.includes(4),
userMethods.includes(4) ? "" : "/otp/time-based/set?" + params
)}
{factor === 2 && U2F(userMethods.includes(5), "/u2f/set?" + params)}
{factor === 3 &&
EMAIL(userMethods.includes(7), "/otp/email/set?" + params)}
{factor === 4 &&
SMS(userMethods.includes(6), "/otp/sms/set?" + params)}
</div>
);
return factor === 1
? TOTP(userMethods.includes(4), "/otp/time-based/set?" + params)
: factor === 2
? U2F(userMethods.includes(5), "/u2f/set?" + params)
: factor === 3 && emailVerified
? EMAIL(userMethods.includes(7), "/otp/email/set?" + params)
: factor === 4 && phoneVerified
? SMS(userMethods.includes(6), "/otp/sms/set?" + params)
: null;
})}
</div>
);