cleanup utils

This commit is contained in:
Max Peintner
2024-11-21 10:48:00 +01:00
parent f187ddc6ba
commit ea95a20f36
10 changed files with 199 additions and 97 deletions

View File

@@ -3,7 +3,7 @@ import { DynamicTheme } from "@/components/dynamic-theme";
import { LoginOTP } from "@/components/login-otp";
import { UserAvatar } from "@/components/user-avatar";
import { loadMostRecentSession } from "@/lib/session";
import { getBrandingSettings } from "@/lib/zitadel";
import { getBrandingSettings, getLoginSettings } from "@/lib/zitadel";
import { getLocale, getTranslations } from "next-intl/server";
export default async function Page({
@@ -29,6 +29,8 @@ export default async function Page({
const branding = await getBrandingSettings(organization);
const loginSettings = await getLoginSettings(organization);
return (
<DynamicTheme branding={branding}>
<div className="flex flex-col items-center space-y-4">
@@ -65,6 +67,7 @@ export default async function Page({
authRequestId={authRequestId}
organization={organization}
method={method}
loginSettings={loginSettings}
></LoginOTP>
)}
</div>

View File

@@ -9,6 +9,7 @@ import {
addOTPEmail,
addOTPSMS,
getBrandingSettings,
getLoginSettings,
registerTOTP,
} from "@/lib/zitadel";
import { RegisterTOTPResponse } from "@zitadel/proto/zitadel/user/v2/user_service_pb";
@@ -32,6 +33,8 @@ export default async function Page({
const { method } = params;
const branding = await getBrandingSettings(organization);
const loginSettings = await getLoginSettings(organization);
const session = await loadMostRecentSession({
loginName,
organization,
@@ -137,6 +140,7 @@ export default async function Page({
authRequestId={authRequestId}
organization={organization}
checkAfter={checkAfter === "true"}
loginSettings={loginSettings}
></TotpRegister>
</div>{" "}
</>

View File

@@ -4,7 +4,11 @@ import { LoginPasskey } from "@/components/login-passkey";
import { UserAvatar } from "@/components/user-avatar";
import { getSessionCookieById } from "@/lib/cookies";
import { loadMostRecentSession } from "@/lib/session";
import { getBrandingSettings, getSession } from "@/lib/zitadel";
import {
getBrandingSettings,
getLoginSettings,
getSession,
} from "@/lib/zitadel";
import { getLocale, getTranslations } from "next-intl/server";
export default async function Page({
@@ -37,6 +41,8 @@ export default async function Page({
const branding = await getBrandingSettings(organization);
const loginSettings = await getLoginSettings(organization);
return (
<DynamicTheme branding={branding}>
<div className="flex flex-col items-center space-y-4">
@@ -61,6 +67,7 @@ export default async function Page({
authRequestId={authRequestId}
altPassword={altPassword === "true"}
organization={organization}
loginSettings={loginSettings}
/>
)}
</div>

View File

@@ -1,10 +1,11 @@
"use client";
import { finishFlow } from "@/lib/login";
import { getNextUrl } from "@/lib/client";
import { updateSession } from "@/lib/server/session";
import { create } from "@zitadel/client";
import { RequestChallengesSchema } from "@zitadel/proto/zitadel/session/v2/challenge_pb";
import { ChecksSchema } from "@zitadel/proto/zitadel/session/v2/session_service_pb";
import { LoginSettings } from "@zitadel/proto/zitadel/settings/v2/login_settings_pb";
import { useTranslations } from "next-intl";
import { useRouter } from "next/navigation";
import { useEffect, useRef, useState } from "react";
@@ -23,6 +24,7 @@ type Props = {
organization?: string;
method: string;
code?: string;
loginSettings?: LoginSettings;
};
type Inputs = {
@@ -36,6 +38,7 @@ export function LoginOTP({
organization,
method,
code,
loginSettings,
}: Props) {
const t = useTranslations("otp");
@@ -153,20 +156,31 @@ export function LoginOTP({
}
function setCodeAndContinue(values: Inputs, organization?: string) {
return submitCode(values, organization).then((response) => {
return submitCode(values, organization).then(async (response) => {
if (response) {
return authRequestId && response.sessionId
? finishFlow({
sessionId: response.sessionId,
authRequestId: authRequestId,
organization: response.factors?.user?.organizationId,
})
: response.factors?.user
? finishFlow({
loginName: response.factors.user.loginName,
organization: response.factors?.user?.organizationId,
})
: null;
const url =
authRequestId && response.sessionId
? await getNextUrl(
{
sessionId: response.sessionId,
authRequestId: authRequestId,
organization: response.factors?.user?.organizationId,
},
loginSettings?.defaultRedirectUri,
)
: response.factors?.user
? await getNextUrl(
{
loginName: response.factors.user.loginName,
organization: response.factors?.user?.organizationId,
},
loginSettings?.defaultRedirectUri,
)
: null;
if (url) {
router.push(url);
}
}
});
}

View File

@@ -1,7 +1,7 @@
"use client";
import { coerceToArrayBuffer, coerceToBase64Url } from "@/helpers/base64";
import { finishFlow } from "@/lib/login";
import { getNextUrl } from "@/lib/client";
import { updateSession } from "@/lib/server/session";
import { create } from "@zitadel/client";
import {
@@ -9,6 +9,7 @@ import {
UserVerificationRequirement,
} from "@zitadel/proto/zitadel/session/v2/challenge_pb";
import { Checks } from "@zitadel/proto/zitadel/session/v2/session_service_pb";
import { LoginSettings } from "@zitadel/proto/zitadel/settings/v2/login_settings_pb";
import { useTranslations } from "next-intl";
import { useRouter } from "next/navigation";
import { useEffect, useRef, useState } from "react";
@@ -25,6 +26,7 @@ type Props = {
altPassword: boolean;
login?: boolean;
organization?: string;
loginSettings?: LoginSettings;
};
export function LoginPasskey({
@@ -34,6 +36,7 @@ export function LoginPasskey({
altPassword,
organization,
login = true,
loginSettings,
}: Props) {
const t = useTranslations("passkey");
@@ -177,18 +180,29 @@ export function LoginPasskey({
};
return submitLogin(data).then(async (resp) => {
return authRequestId && resp?.sessionId
? await finishFlow({
sessionId: resp.sessionId,
authRequestId: authRequestId,
organization: organization,
})
: resp?.factors?.user?.loginName
? await finishFlow({
loginName: resp.factors.user.loginName,
organization: organization,
})
: null;
const url =
authRequestId && resp?.sessionId
? await getNextUrl(
{
sessionId: resp.sessionId,
authRequestId: authRequestId,
organization: organization,
},
loginSettings?.defaultRedirectUri,
)
: resp?.factors?.user?.loginName
? await getNextUrl(
{
loginName: resp.factors.user.loginName,
organization: organization,
},
loginSettings?.defaultRedirectUri,
)
: null;
if (url) {
router.push(url);
}
});
});
}

View File

@@ -1,8 +1,9 @@
"use client";
import { coerceToArrayBuffer, coerceToBase64Url } from "@/helpers/base64";
import { finishFlow } from "@/lib/login";
import { getNextUrl } from "@/lib/client";
import { addU2F, verifyU2F } from "@/lib/server/u2f";
import { LoginSettings } from "@zitadel/proto/zitadel/settings/v2/login_settings_pb";
import { RegisterU2FResponse } from "@zitadel/proto/zitadel/user/v2/user_service_pb";
import { useTranslations } from "next-intl";
import { useRouter } from "next/navigation";
@@ -18,6 +19,7 @@ type Props = {
authRequestId?: string;
organization?: string;
checkAfter: boolean;
loginSettings?: LoginSettings;
};
export function RegisterU2f({
@@ -26,6 +28,7 @@ export function RegisterU2f({
organization,
authRequestId,
checkAfter,
loginSettings,
}: Props) {
const t = useTranslations("u2f");
@@ -165,18 +168,28 @@ export function RegisterU2f({
return router.push(`/u2f?` + paramsToContinue);
} else {
return authRequestId && sessionId
? finishFlow({
sessionId: sessionId,
authRequestId: authRequestId,
organization: organization,
})
: loginName
? finishFlow({
loginName: loginName,
organization: organization,
})
: null;
const url =
authRequestId && sessionId
? await getNextUrl(
{
sessionId: sessionId,
authRequestId: authRequestId,
organization: organization,
},
loginSettings?.defaultRedirectUri,
)
: loginName
? await getNextUrl(
{
loginName: loginName,
organization: organization,
},
loginSettings?.defaultRedirectUri,
)
: null;
if (url) {
return router.push(url);
}
}
}
}

View File

@@ -1,6 +1,7 @@
"use client";
import { finishFlow } from "@/lib/login";
import { getNextUrl } from "@/lib/client";
import { verifyTOTP } from "@/lib/server-actions";
import { LoginSettings } from "@zitadel/proto/zitadel/settings/v2/login_settings_pb";
import { useTranslations } from "next-intl";
import Link from "next/link";
import { useRouter } from "next/navigation";
@@ -25,6 +26,7 @@ type Props = {
authRequestId?: string;
organization?: string;
checkAfter?: boolean;
loginSettings?: LoginSettings;
};
export function TotpRegister({
uri,
@@ -34,6 +36,7 @@ export function TotpRegister({
authRequestId,
organization,
checkAfter,
loginSettings,
}: Props) {
const t = useTranslations("otp");
@@ -51,7 +54,7 @@ export function TotpRegister({
async function continueWithCode(values: Inputs) {
setLoading(true);
return verifyTOTP(values.code, loginName, organization)
.then((response) => {
.then(async () => {
// if attribute is set, validate MFA after it is setup, otherwise proceed as usual (when mfa is enforced to login)
if (checkAfter) {
const params = new URLSearchParams({});
@@ -68,18 +71,29 @@ export function TotpRegister({
return router.push(`/otp/time-based?` + params);
} else {
return authRequestId && sessionId
? finishFlow({
sessionId: sessionId,
authRequestId: authRequestId,
organization: organization,
})
: loginName
? finishFlow({
loginName: loginName,
organization: organization,
})
: null;
const url =
authRequestId && sessionId
? await getNextUrl(
{
sessionId: sessionId,
authRequestId: authRequestId,
organization: organization,
},
loginSettings?.defaultRedirectUri,
)
: loginName
? await getNextUrl(
{
loginName: loginName,
organization: organization,
},
loginSettings?.defaultRedirectUri,
)
: null;
if (url) {
return router.push(url);
}
}
})
.catch((e) => {

View File

@@ -1,6 +1,3 @@
import { redirect } from "next/navigation";
import { getLoginSettings } from "./zitadel";
type FinishFlowCommand =
| {
sessionId: string;
@@ -13,28 +10,29 @@ type FinishFlowCommand =
* @param command
* @returns
*/
export async function finishFlow(
export async function getNextUrl(
command: FinishFlowCommand & { organization?: string },
) {
defaultRedirectUri?: string,
): Promise<string> {
if ("sessionId" in command && "authRequestId" in command) {
return redirect(
const url =
`/login?` +
new URLSearchParams({
sessionId: command.sessionId,
authRequest: command.authRequestId,
}),
);
}
const loginSettings = await getLoginSettings(command.organization);
if (loginSettings?.defaultRedirectUri) {
return redirect(loginSettings.defaultRedirectUri);
}
return redirect(
`/signedin?` +
new URLSearchParams({
loginName: command.loginName,
}),
);
sessionId: command.sessionId,
authRequest: command.authRequestId,
});
return url;
}
if (defaultRedirectUri) {
return defaultRedirectUri;
}
const signedInUrl =
`/signedin?` +
new URLSearchParams({
loginName: command.loginName,
});
return signedInUrl;
}

View File

@@ -1,7 +1,7 @@
"use server";
import { createSessionAndUpdateCookie } from "@/lib/server/cookie";
import { addHumanUser } from "@/lib/zitadel";
import { addHumanUser, getLoginSettings } from "@/lib/zitadel";
import { create } from "@zitadel/client";
import { Factors } from "@zitadel/proto/zitadel/session/v2/session_pb";
import {
@@ -9,7 +9,7 @@ import {
ChecksSchema,
} from "@zitadel/proto/zitadel/session/v2/session_service_pb";
import { redirect } from "next/navigation";
import { finishFlow } from "../login";
import { getNextUrl } from "../client";
type RegisterUserCommand = {
email: string;
@@ -73,7 +73,11 @@ export async function registerUser(command: RegisterUserCommand) {
return redirect("/passkey/set?" + params);
} else {
return finishFlow(
const loginSettings = await getLoginSettings(
session.factors.user.organizationId,
);
const url = await getNextUrl(
command.authRequestId && session.id
? {
sessionId: session.id,
@@ -84,6 +88,9 @@ export async function registerUser(command: RegisterUserCommand) {
loginName: session.factors.user.loginName,
organization: session.factors.user.organizationId,
},
loginSettings?.defaultRedirectUri,
);
return redirect(url);
}
}

View File

@@ -4,17 +4,22 @@ import {
createSessionForIdpAndUpdateCookie,
setSessionAndUpdateCookie,
} from "@/lib/server/cookie";
import { deleteSession, listAuthenticationMethodTypes } from "@/lib/zitadel";
import {
deleteSession,
getLoginSettings,
listAuthenticationMethodTypes,
} from "@/lib/zitadel";
import { RequestChallenges } from "@zitadel/proto/zitadel/session/v2/challenge_pb";
import { Session } from "@zitadel/proto/zitadel/session/v2/session_pb";
import { Checks } from "@zitadel/proto/zitadel/session/v2/session_service_pb";
import { redirect } from "next/navigation";
import { getNextUrl } from "../client";
import {
getMostRecentSessionCookie,
getSessionCookieById,
getSessionCookieByLoginName,
removeSessionFromCookie,
} from "../cookies";
import { finishFlow } from "../login";
type CreateNewSessionCommand = {
userId: string;
@@ -43,7 +48,11 @@ export async function createNewSessionForIdp(options: CreateNewSessionCommand) {
return { error: "Could not create session" };
}
return finishFlow(
const loginSettings = await getLoginSettings(
session.factors.user.organizationId,
);
const url = await getNextUrl(
authRequestId && session.id
? {
sessionId: session.id,
@@ -54,25 +63,44 @@ export async function createNewSessionForIdp(options: CreateNewSessionCommand) {
loginName: session.factors.user.loginName,
organization: session.factors.user.organizationId,
},
loginSettings?.defaultRedirectUri,
);
if (url) {
return redirect(url);
}
}
export async function continueWithSession({
authRequestId,
...session
}: Session & { authRequestId?: string }) {
return authRequestId && session.id && session.factors?.user
? finishFlow({
sessionId: session.id,
authRequestId: authRequestId,
organization: session.factors.user.organizationId,
})
: session.factors?.user
? finishFlow({
loginName: session.factors.user.loginName,
organization: session.factors.user.organizationId,
})
: null;
const loginSettings = await getLoginSettings(
session.factors?.user?.organizationId,
);
const url =
authRequestId && session.id && session.factors?.user
? await getNextUrl(
{
sessionId: session.id,
authRequestId: authRequestId,
organization: session.factors.user.organizationId,
},
loginSettings?.defaultRedirectUri,
)
: session.factors?.user
? await getNextUrl(
{
loginName: session.factors.user.loginName,
organization: session.factors.user.organizationId,
},
loginSettings?.defaultRedirectUri,
)
: null;
if (url) {
return redirect(url);
}
}
export type UpdateSessionCommand = {