mirror of
https://github.com/zitadel/zitadel.git
synced 2025-12-12 14:54:33 +00:00
initial param for password set page, fix cookie overflow
This commit is contained in:
@@ -19,7 +19,7 @@ export default async function Page({
|
|||||||
const t = await getTranslations({ locale, namespace: "password" });
|
const t = await getTranslations({ locale, namespace: "password" });
|
||||||
const tError = await getTranslations({ locale, namespace: "error" });
|
const tError = await getTranslations({ locale, namespace: "error" });
|
||||||
|
|
||||||
const { loginName, organization, authRequestId, code } = searchParams;
|
const { loginName, organization, authRequestId } = searchParams;
|
||||||
|
|
||||||
// also allow no session to be found (ignoreUnkownUsername)
|
// also allow no session to be found (ignoreUnkownUsername)
|
||||||
const sessionFactors = await loadMostRecentSession({
|
const sessionFactors = await loadMostRecentSession({
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ export default async function Page({
|
|||||||
const t = await getTranslations({ locale, namespace: "password" });
|
const t = await getTranslations({ locale, namespace: "password" });
|
||||||
const tError = await getTranslations({ locale, namespace: "error" });
|
const tError = await getTranslations({ locale, namespace: "error" });
|
||||||
|
|
||||||
const { userId, loginName, organization, authRequestId, code } = searchParams;
|
const { userId, loginName, organization, authRequestId, code, initial } =
|
||||||
|
searchParams;
|
||||||
|
|
||||||
// also allow no session to be found (ignoreUnkownUsername)
|
// also allow no session to be found (ignoreUnkownUsername)
|
||||||
let session: Session | undefined;
|
let session: Session | undefined;
|
||||||
@@ -81,7 +82,7 @@ export default async function Page({
|
|||||||
></UserAvatar>
|
></UserAvatar>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<Alert type={AlertType.INFO}>{t("set.codeSent")}</Alert>
|
{!initial && <Alert type={AlertType.INFO}>{t("set.codeSent")}</Alert>}
|
||||||
|
|
||||||
{passwordComplexity &&
|
{passwordComplexity &&
|
||||||
(loginName ?? user?.preferredLoginName) &&
|
(loginName ?? user?.preferredLoginName) &&
|
||||||
@@ -93,6 +94,7 @@ export default async function Page({
|
|||||||
authRequestId={authRequestId}
|
authRequestId={authRequestId}
|
||||||
organization={organization}
|
organization={organization}
|
||||||
passwordComplexitySettings={passwordComplexity}
|
passwordComplexitySettings={passwordComplexity}
|
||||||
|
codeRequired={!(initial === "true")}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="py-4">
|
<div className="py-4">
|
||||||
|
|||||||
@@ -104,13 +104,13 @@ export const U2F = (alreadyAdded: boolean, link: string) => {
|
|||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
fill="none"
|
fill="none"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
stroke-width="1.5"
|
strokeWidth="1.5"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
className="w-8 h-8 mr-4"
|
className="w-8 h-8 mr-4"
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
stroke-linecap="round"
|
strokeLinecap="round"
|
||||||
stroke-linejoin="round"
|
strokeLinejoin="round"
|
||||||
d="M7.864 4.243A7.5 7.5 0 0119.5 10.5c0 2.92-.556 5.709-1.568 8.268M5.742 6.364A7.465 7.465 0 004.5 10.5a7.464 7.464 0 01-1.15 3.993m1.989 3.559A11.209 11.209 0 008.25 10.5a3.75 3.75 0 117.5 0c0 .527-.021 1.049-.064 1.565M12 10.5a14.94 14.94 0 01-3.6 9.75m6.633-4.596a18.666 18.666 0 01-2.485 5.33"
|
d="M7.864 4.243A7.5 7.5 0 0119.5 10.5c0 2.92-.556 5.709-1.568 8.268M5.742 6.364A7.465 7.465 0 004.5 10.5a7.464 7.464 0 01-1.15 3.993m1.989 3.559A11.209 11.209 0 008.25 10.5a3.75 3.75 0 117.5 0c0 .527-.021 1.049-.064 1.565M12 10.5a14.94 14.94 0 01-3.6 9.75m6.633-4.596a18.666 18.666 0 01-2.485 5.33"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
@@ -143,8 +143,8 @@ export const EMAIL = (alreadyAdded: boolean, link: string) => {
|
|||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
stroke-linecap="round"
|
strokeLinecap="round"
|
||||||
stroke-linejoin="round"
|
strokeLinejoin="round"
|
||||||
d="M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-1.07 1.916l-7.5 4.615a2.25 2.25 0 01-2.36 0L3.32 8.91a2.25 2.25 0 01-1.07-1.916V6.75"
|
d="M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-1.07 1.916l-7.5 4.615a2.25 2.25 0 01-2.36 0L3.32 8.91a2.25 2.25 0 01-1.07-1.916V6.75"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import { create } from "@zitadel/client";
|
|||||||
import { ChecksSchema } from "@zitadel/proto/zitadel/session/v2/session_service_pb";
|
import { ChecksSchema } from "@zitadel/proto/zitadel/session/v2/session_service_pb";
|
||||||
import { PasswordComplexitySettings } from "@zitadel/proto/zitadel/settings/v2/password_settings_pb";
|
import { PasswordComplexitySettings } from "@zitadel/proto/zitadel/settings/v2/password_settings_pb";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import { useRouter } from "next/navigation";
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { FieldValues, useForm } from "react-hook-form";
|
import { FieldValues, useForm } from "react-hook-form";
|
||||||
import { Alert } from "./alert";
|
import { Alert } from "./alert";
|
||||||
@@ -57,8 +56,6 @@ export function ChangePasswordForm({
|
|||||||
const [loading, setLoading] = useState<boolean>(false);
|
const [loading, setLoading] = useState<boolean>(false);
|
||||||
const [error, setError] = useState<string>("");
|
const [error, setError] = useState<string>("");
|
||||||
|
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
async function submitChange(values: Inputs) {
|
async function submitChange(values: Inputs) {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const changeResponse = await setMyPassword({
|
const changeResponse = await setMyPassword({
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ type Props = {
|
|||||||
userId: string;
|
userId: string;
|
||||||
organization?: string;
|
organization?: string;
|
||||||
authRequestId?: string;
|
authRequestId?: string;
|
||||||
|
codeRequired: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function SetPasswordForm({
|
export function SetPasswordForm({
|
||||||
@@ -44,6 +45,7 @@ export function SetPasswordForm({
|
|||||||
loginName,
|
loginName,
|
||||||
userId,
|
userId,
|
||||||
code,
|
code,
|
||||||
|
codeRequired,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const t = useTranslations("password");
|
const t = useTranslations("password");
|
||||||
|
|
||||||
@@ -59,11 +61,17 @@ export function SetPasswordForm({
|
|||||||
|
|
||||||
async function submitRegister(values: Inputs) {
|
async function submitRegister(values: Inputs) {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const changeResponse = await changePassword({
|
let payload: { userId: string; password: string; code?: string } = {
|
||||||
userId: userId,
|
userId: userId,
|
||||||
password: values.password,
|
password: values.password,
|
||||||
code: values.code,
|
};
|
||||||
}).catch(() => {
|
|
||||||
|
// this is not required for initial password setup
|
||||||
|
if (codeRequired) {
|
||||||
|
payload = { ...payload, code: values.code };
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeResponse = await changePassword(payload).catch(() => {
|
||||||
setError("Could not register user");
|
setError("Could not register user");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -94,7 +102,8 @@ export function SetPasswordForm({
|
|||||||
password: { password: values.password },
|
password: { password: values.password },
|
||||||
}),
|
}),
|
||||||
authRequestId,
|
authRequestId,
|
||||||
}).catch(() => {
|
}).catch((error) => {
|
||||||
|
console.error("verifyerror", error);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
setError("Could not verify password");
|
setError("Could not verify password");
|
||||||
return;
|
return;
|
||||||
@@ -109,23 +118,6 @@ export function SetPasswordForm({
|
|||||||
) {
|
) {
|
||||||
setError(passwordResponse.error);
|
setError(passwordResponse.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// // skip verification for now as it is an app based flow
|
|
||||||
// // return router.push(`/verify?` + params);
|
|
||||||
|
|
||||||
// // check for mfa force to continue with mfa setup
|
|
||||||
|
|
||||||
// if (authRequestId && changeResponse.sessionId) {
|
|
||||||
// if (authRequestId) {
|
|
||||||
// params.append("authRequest", authRequestId);
|
|
||||||
// }
|
|
||||||
// return router.push(`/login?` + params);
|
|
||||||
// } else {
|
|
||||||
// if (authRequestId) {
|
|
||||||
// params.append("authRequestId", authRequestId);
|
|
||||||
// }
|
|
||||||
// return router.push(`/signedin?` + params);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const { errors } = formState;
|
const { errors } = formState;
|
||||||
@@ -152,25 +144,28 @@ export function SetPasswordForm({
|
|||||||
return (
|
return (
|
||||||
<form className="w-full">
|
<form className="w-full">
|
||||||
<div className="pt-4 grid grid-cols-1 gap-4 mb-4">
|
<div className="pt-4 grid grid-cols-1 gap-4 mb-4">
|
||||||
<div className="flex flex-row items-end">
|
{codeRequired && (
|
||||||
<div className="flex-1">
|
<div className="flex flex-row items-end">
|
||||||
<TextInput
|
<div className="flex-1">
|
||||||
type="text"
|
<TextInput
|
||||||
required
|
type="text"
|
||||||
{...register("code", {
|
required
|
||||||
required: "This field is required",
|
{...register("code", {
|
||||||
})}
|
required: "This field is required",
|
||||||
label="Code"
|
})}
|
||||||
autoComplete="one-time-code"
|
label="Code"
|
||||||
error={errors.code?.message as string}
|
autoComplete="one-time-code"
|
||||||
/>
|
error={errors.code?.message as string}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="ml-4 mb-1">
|
||||||
|
<Button variant={ButtonVariants.Secondary}>
|
||||||
|
{t("set.resend")}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-4 mb-1">
|
)}
|
||||||
<Button variant={ButtonVariants.Secondary}>
|
|
||||||
{t("set.resend")}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="">
|
<div className="">
|
||||||
<TextInput
|
<TextInput
|
||||||
type="password"
|
type="password"
|
||||||
|
|||||||
@@ -65,7 +65,13 @@ export function VerifyEmailForm({
|
|||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const params = new URLSearchParams({});
|
const params = new URLSearchParams({
|
||||||
|
userId: userId,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isInvite) {
|
||||||
|
params.append("initial", "true");
|
||||||
|
}
|
||||||
|
|
||||||
if (loginName) {
|
if (loginName) {
|
||||||
params.append("loginName", loginName);
|
params.append("loginName", loginName);
|
||||||
@@ -121,7 +127,10 @@ export function VerifyEmailForm({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if auth methods fall trough, we complete to login
|
// if auth methods fall trough, we complete to login
|
||||||
const params = new URLSearchParams({});
|
const params = new URLSearchParams({
|
||||||
|
userId: userId,
|
||||||
|
initial: "true", // defines that a code is not required and is therefore not shown in the UI
|
||||||
|
});
|
||||||
|
|
||||||
if (organization) {
|
if (organization) {
|
||||||
params.set("organization", organization);
|
params.set("organization", organization);
|
||||||
|
|||||||
@@ -3,6 +3,9 @@
|
|||||||
import { cookies } from "next/headers";
|
import { cookies } from "next/headers";
|
||||||
import { LANGUAGE_COOKIE_NAME } from "./i18n";
|
import { LANGUAGE_COOKIE_NAME } from "./i18n";
|
||||||
|
|
||||||
|
// TODO: improve this to handle overflow
|
||||||
|
export const MAX_COOKIE_SIZE = 4096;
|
||||||
|
|
||||||
export type Cookie = {
|
export type Cookie = {
|
||||||
id: string;
|
id: string;
|
||||||
token: string;
|
token: string;
|
||||||
@@ -56,7 +59,13 @@ export async function addSessionToCookie<T>(
|
|||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
currentSessions[index] = session;
|
currentSessions[index] = session;
|
||||||
} else {
|
} else {
|
||||||
currentSessions = [...currentSessions, session];
|
const temp = [...currentSessions, session];
|
||||||
|
|
||||||
|
if (temp.length > MAX_COOKIE_SIZE) {
|
||||||
|
// TODO: improve cookie handling
|
||||||
|
// this replaces the first session (oldest) with the new one
|
||||||
|
currentSessions = [session].concat(currentSessions.slice(1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cleanup) {
|
if (cleanup) {
|
||||||
|
|||||||
@@ -169,7 +169,6 @@ export const PROVIDER_MAPPING: {
|
|||||||
} = {
|
} = {
|
||||||
[IdentityProviderType.GOOGLE]: (idp: IDPInformation) => {
|
[IdentityProviderType.GOOGLE]: (idp: IDPInformation) => {
|
||||||
const rawInfo = idp.rawInformation as OIDC_USER;
|
const rawInfo = idp.rawInformation as OIDC_USER;
|
||||||
console.log(rawInfo);
|
|
||||||
|
|
||||||
return create(AddHumanUserRequestSchema, {
|
return create(AddHumanUserRequestSchema, {
|
||||||
username: idp.userName,
|
username: idp.userName,
|
||||||
|
|||||||
@@ -71,8 +71,6 @@ export async function sendPassword(command: UpdateSessionCommand) {
|
|||||||
organizationId: command.organization,
|
organizationId: command.organization,
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(users);
|
|
||||||
|
|
||||||
if (users.details?.totalResult == BigInt(1) && users.result[0].userId) {
|
if (users.details?.totalResult == BigInt(1) && users.result[0].userId) {
|
||||||
user = users.result[0];
|
user = users.result[0];
|
||||||
|
|
||||||
@@ -89,7 +87,7 @@ export async function sendPassword(command: UpdateSessionCommand) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// this is a fake error message to hide that the user does not even exist
|
// this is a fake error message to hide that the user does not even exist
|
||||||
return { error: "Could not verify password!" };
|
return { error: "Could not verify password" };
|
||||||
} else {
|
} else {
|
||||||
session = await setSessionAndUpdateCookie(
|
session = await setSessionAndUpdateCookie(
|
||||||
sessionCookie,
|
sessionCookie,
|
||||||
@@ -274,7 +272,7 @@ export async function sendPassword(command: UpdateSessionCommand) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function changePassword(command: {
|
export async function changePassword(command: {
|
||||||
code: string;
|
code?: string;
|
||||||
userId: string;
|
userId: string;
|
||||||
password: string;
|
password: string;
|
||||||
}) {
|
}) {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { Checks } from "@zitadel/proto/zitadel/session/v2/session_service_pb";
|
|||||||
import { IDPInformation } from "@zitadel/proto/zitadel/user/v2/idp_pb";
|
import { IDPInformation } from "@zitadel/proto/zitadel/user/v2/idp_pb";
|
||||||
import {
|
import {
|
||||||
RetrieveIdentityProviderIntentRequest,
|
RetrieveIdentityProviderIntentRequest,
|
||||||
|
SetPasswordRequestSchema,
|
||||||
VerifyPasskeyRegistrationRequest,
|
VerifyPasskeyRegistrationRequest,
|
||||||
VerifyU2FRegistrationRequest,
|
VerifyU2FRegistrationRequest,
|
||||||
} from "@zitadel/proto/zitadel/user/v2/user_service_pb";
|
} from "@zitadel/proto/zitadel/user/v2/user_service_pb";
|
||||||
@@ -315,7 +316,6 @@ export async function verifyInviteCode(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function resendInviteCode(userId: string) {
|
export async function resendInviteCode(userId: string) {
|
||||||
console.log("resetInit");
|
|
||||||
return userService.resendInviteCode({ userId }, {});
|
return userService.resendInviteCode({ userId }, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -580,24 +580,50 @@ export async function passwordReset(userId: string, host: string | null) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param userId userId of the user to set the password for
|
||||||
|
* @param password the new password
|
||||||
|
* @param code optional if the password should be set with a code (reset), no code for initial setup of password
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
export async function setPassword(
|
export async function setPassword(
|
||||||
userId: string,
|
userId: string,
|
||||||
password: string,
|
password: string,
|
||||||
code: string,
|
code?: string,
|
||||||
) {
|
) {
|
||||||
return userService.setPassword(
|
let payload = create(SetPasswordRequestSchema, {
|
||||||
{
|
userId,
|
||||||
userId,
|
newPassword: {
|
||||||
newPassword: {
|
password,
|
||||||
password,
|
},
|
||||||
},
|
});
|
||||||
|
|
||||||
|
// check if the user has no password set in order to set a password
|
||||||
|
if (!code) {
|
||||||
|
const authmethods = await listAuthenticationMethodTypes(userId);
|
||||||
|
|
||||||
|
// if the user has no authmethods set, we can set a password otherwise we need a code
|
||||||
|
if (
|
||||||
|
!authmethods ||
|
||||||
|
!authmethods.authMethodTypes ||
|
||||||
|
authmethods.authMethodTypes.length === 0
|
||||||
|
) {
|
||||||
|
return { error: "Provide a code to set a password" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (code) {
|
||||||
|
payload = {
|
||||||
|
...payload,
|
||||||
verification: {
|
verification: {
|
||||||
case: "verificationCode",
|
case: "verificationCode",
|
||||||
value: code,
|
value: code,
|
||||||
},
|
},
|
||||||
},
|
};
|
||||||
{},
|
}
|
||||||
);
|
|
||||||
|
return userService.setPassword(payload, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user