From 53fc22e048be489b10d641ab340b6514b2edeff0 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Tue, 24 Dec 2024 09:15:12 +0100 Subject: [PATCH] skipsend, checkinvite --- apps/login/src/app/(login)/verify/page.tsx | 26 ++++++++++++++-- apps/login/src/components/verify-form.tsx | 4 +-- apps/login/src/lib/server/loginname.ts | 35 +++++++++------------- apps/login/src/lib/verify-helper.ts | 33 ++++++++++++++++---- 4 files changed, 68 insertions(+), 30 deletions(-) diff --git a/apps/login/src/app/(login)/verify/page.tsx b/apps/login/src/app/(login)/verify/page.tsx index 0a45ce5a3e..b4a46f7541 100644 --- a/apps/login/src/app/(login)/verify/page.tsx +++ b/apps/login/src/app/(login)/verify/page.tsx @@ -3,6 +3,7 @@ import { DynamicTheme } from "@/components/dynamic-theme"; import { UserAvatar } from "@/components/user-avatar"; import { VerifyForm } from "@/components/verify-form"; import { VerifyRedirectButton } from "@/components/verify-redirect-button"; +import { resendVerification } from "@/lib/server/verify"; import { loadMostRecentSession } from "@/lib/session"; import { getBrandingSettings, @@ -19,8 +20,15 @@ export default async function Page(props: { searchParams: Promise }) { const t = await getTranslations({ locale, namespace: "verify" }); const tError = await getTranslations({ locale, namespace: "error" }); - const { userId, loginName, code, organization, authRequestId, invite } = - searchParams; + const { + userId, + loginName, + code, + organization, + authRequestId, + invite, + skipsend, + } = searchParams; const branding = await getBrandingSettings(organization); @@ -34,7 +42,21 @@ export default async function Page(props: { searchParams: Promise }) { loginName, organization, }); + + if (!skipsend && sessionFactors?.factors?.user?.id) { + await resendVerification({ + userId: sessionFactors?.factors?.user?.id, + isInvite: invite === "true", + }); + } } else if ("userId" in searchParams && userId) { + if (!skipsend) { + await resendVerification({ + userId, + isInvite: invite === "true", + }); + } + const userResponse = await getUserByID(userId); if (userResponse) { user = userResponse.user; diff --git a/apps/login/src/components/verify-form.tsx b/apps/login/src/components/verify-form.tsx index 2eea113398..6b6189297e 100644 --- a/apps/login/src/components/verify-form.tsx +++ b/apps/login/src/components/verify-form.tsx @@ -88,12 +88,12 @@ export function VerifyForm({ setLoading(false); }); - if (response?.error) { + if (response && "error" in response && response?.error) { setError(response.error); return; } - if (response?.redirect) { + if (response && "redirect" in response && response?.redirect) { return router.push(response?.redirect); } }, diff --git a/apps/login/src/lib/server/loginname.ts b/apps/login/src/lib/server/loginname.ts index 74d1bacdaa..54a989f986 100644 --- a/apps/login/src/lib/server/loginname.ts +++ b/apps/login/src/lib/server/loginname.ts @@ -8,6 +8,7 @@ import { idpTypeToIdentityProviderType, idpTypeToSlug } from "../idp"; import { PasskeysType } from "@zitadel/proto/zitadel/settings/v2/login_settings_pb"; import { UserState } from "@zitadel/proto/zitadel/user/v2/user_pb"; +import { checkInvite } from "../verify-helper"; import { getActiveIdentityProviders, getIDPByID, @@ -171,29 +172,21 @@ export async function sendLoginname(command: SendLoginnameCommand) { ); if (!methods.authMethodTypes || !methods.authMethodTypes.length) { - if ( - potentialUsers[0].type.case === "human" && - potentialUsers[0].type.value.email && - !potentialUsers[0].type.value.email.isVerified - ) { - const paramsVerify = new URLSearchParams({ - loginName: session.factors?.user?.loginName, - userId: session.factors?.user?.id, // verify needs user id - invite: "true", // TODO: check - set this to true as we dont expect old email verification method here - }); + const humanUser = + potentialUsers[0].type.case === "human" + ? potentialUsers[0].type.value + : undefined; - if (command.organization || session.factors?.user?.organizationId) { - paramsVerify.append( - "organization", - command.organization ?? session.factors?.user?.organizationId, - ); - } + // redirect to /verify invite if no auth method is set and email is not verified + const inviteCheck = checkInvite( + session, + humanUser, + session.factors.user.organizationId, + command.authRequestId, + ); - if (command.authRequestId) { - paramsVerify.append("authRequestId", command.authRequestId); - } - - return { redirect: "/verify?" + paramsVerify }; + if (inviteCheck?.redirect) { + return inviteCheck; } const paramsAuthenticatorSetup = new URLSearchParams({ diff --git a/apps/login/src/lib/verify-helper.ts b/apps/login/src/lib/verify-helper.ts index 2161e08168..cc58f8c5dc 100644 --- a/apps/login/src/lib/verify-helper.ts +++ b/apps/login/src/lib/verify-helper.ts @@ -29,17 +29,40 @@ export function checkPasswordChangeRequired( } } +export function checkInvite( + session: Session, + humanUser?: HumanUser, + organization?: string, + authRequestId?: string, +) { + if (humanUser?.email && humanUser.email.isVerified) { + const paramsVerify = new URLSearchParams({ + loginName: session.factors?.user?.loginName as string, + userId: session.factors?.user?.id as string, // verify needs user id + invite: "true", // TODO: check - set this to true as we dont expect old email verification method here + }); + + if (organization || session.factors?.user?.organizationId) { + paramsVerify.append( + "organization", + organization ?? (session.factors?.user?.organizationId as string), + ); + } + + if (authRequestId) { + paramsVerify.append("authRequestId", authRequestId); + } + + return { redirect: "/verify?" + paramsVerify }; + } +} + export function checkEmailVerification( session: Session, humanUser?: HumanUser, organization?: string, authRequestId?: string, ) { - console.log( - humanUser?.email, - process.env.EMAIL_VERIFICATION, - process.env.EMAIL_VERIFICATION === "true", - ); if ( !humanUser?.email?.isVerified && process.env.EMAIL_VERIFICATION === "true"