diff --git a/apps/login/src/app/api/u2f/route.ts b/apps/login/src/app/api/u2f/route.ts deleted file mode 100644 index f8a646a981e..00000000000 --- a/apps/login/src/app/api/u2f/route.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { - createPasskeyRegistrationLink, - getSession, - registerPasskey, - registerU2F, -} from "@/lib/zitadel"; -import { getSessionCookieById } from "@zitadel/next"; -import { NextRequest, NextResponse } from "next/server"; - -export async function POST(request: NextRequest) { - const body = await request.json(); - if (body) { - const { sessionId } = body; - - const sessionCookie = await getSessionCookieById({ sessionId }); - - const session = await getSession(sessionCookie.id, sessionCookie.token); - - const domain: string = request.nextUrl.hostname; - - const userId = session?.session?.factors?.user?.id; - - if (userId) { - return registerU2F(userId, domain) - .then((resp) => { - return NextResponse.json(resp); - }) - .catch((error) => { - console.error("error on creating passkey registration link"); - return NextResponse.json(error, { status: 500 }); - }); - } else { - return NextResponse.json( - { details: "could not get session" }, - { status: 500 }, - ); - } - } else { - return NextResponse.json({}, { status: 400 }); - } -} diff --git a/apps/login/src/app/api/u2f/verify/route.ts b/apps/login/src/app/api/u2f/verify/route.ts deleted file mode 100644 index 3b61c87cce4..00000000000 --- a/apps/login/src/app/api/u2f/verify/route.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { getSession, verifyU2FRegistration } from "@/lib/zitadel"; -import { getSessionCookieById } from "@zitadel/next"; -import { NextRequest, NextResponse, userAgent } from "next/server"; -import { - VerifyU2FRegistrationRequestSchema, - VerifyU2FRegistrationResponseSchema, -} from "@zitadel/proto/zitadel/user/v2/user_service_pb"; -import { create, toJson } from "@zitadel/client"; - -export async function POST(request: NextRequest) { - const body = await request.json(); - if (body) { - let { u2fId, passkeyName, publicKeyCredential, sessionId } = body; - - if (!!!passkeyName) { - const { browser, device, os } = userAgent(request); - passkeyName = `${device.vendor ?? ""} ${device.model ?? ""}${ - device.vendor || device.model ? ", " : "" - }${os.name}${os.name ? ", " : ""}${browser.name}`; - } - const sessionCookie = await getSessionCookieById({ sessionId }); - - const session = await getSession(sessionCookie.id, sessionCookie.token); - - const userId = session?.session?.factors?.user?.id; - - if (userId) { - // TODO: this does not make sens to me - // We create the object, and later on we assign another object to it. - // let req: VerifyU2FRegistrationRequest = { - // publicKeyCredential, - // u2fId, - // userId, - // tokenName: passkeyName, - // }; - - const req = create( - VerifyU2FRegistrationRequestSchema, - // TODO: why did we passed the request instead of body here? - body, - ); - - return verifyU2FRegistration(req) - .then((resp) => { - return NextResponse.json( - toJson(VerifyU2FRegistrationResponseSchema, resp), - ); - }) - .catch((error) => { - return NextResponse.json(error, { status: 500 }); - }); - } else { - return NextResponse.json( - { details: "could not get session" }, - { status: 500 }, - ); - } - } else { - return NextResponse.json({}, { status: 400 }); - } -} diff --git a/apps/login/src/lib/server/otp.ts b/apps/login/src/lib/server/otp.ts index b64da9996dd..12410c1f6a0 100644 --- a/apps/login/src/lib/server/otp.ts +++ b/apps/login/src/lib/server/otp.ts @@ -1,3 +1,5 @@ +"use server"; + import { getMostRecentSessionCookie, getSessionCookieById, diff --git a/apps/login/src/lib/server/register.ts b/apps/login/src/lib/server/register.ts index fca55c1fddb..c01e9491bf3 100644 --- a/apps/login/src/lib/server/register.ts +++ b/apps/login/src/lib/server/register.ts @@ -1,10 +1,7 @@ "use server"; import { addHumanUser } from "@/lib/zitadel"; -import { - createSessionAndUpdateCookie, - createSessionForUserIdAndUpdateCookie, -} from "@/utils/session"; +import { createSessionForUserIdAndUpdateCookie } from "@/utils/session"; type RegisterUserCommand = { email: string; diff --git a/apps/login/src/lib/server/u2f.ts b/apps/login/src/lib/server/u2f.ts new file mode 100644 index 00000000000..8aa4d8f04e1 --- /dev/null +++ b/apps/login/src/lib/server/u2f.ts @@ -0,0 +1,71 @@ +"use server"; + +import { getSession, registerU2F, verifyU2FRegistration } from "@/lib/zitadel"; +import { getSessionCookieById } from "@zitadel/next"; +import { userAgent } from "next/server"; +import { VerifyU2FRegistrationRequestSchema } from "@zitadel/proto/zitadel/user/v2/user_service_pb"; +import { create } from "@zitadel/client"; +import { headers } from "next/headers"; + +type RegisterU2FCommand = { + sessionId: string; +}; + +type VerifyU2FCommand = { + u2fId: string; + passkeyName?: string; + publicKeyCredential: any; + sessionId: string; +}; + +export async function addU2F(command: RegisterU2FCommand) { + const { sessionId } = command; + + const sessionCookie = await getSessionCookieById({ sessionId }); + + const session = await getSession(sessionCookie.id, sessionCookie.token); + + const domain = headers().get("host"); + + if (!domain) { + throw Error("Could not get domain"); + } + + const userId = session?.session?.factors?.user?.id; + + if (!userId) { + throw Error("Could not get session"); + } + return registerU2F(userId, domain); +} + +export async function verifyU2F(command: VerifyU2FCommand) { + let { passkeyName, sessionId } = command; + + if (!!!passkeyName) { + const headersList = headers(); + const userAgentStructure = { headers: headersList }; + const { browser, device, os } = userAgent(userAgentStructure); + + passkeyName = `${device.vendor ?? ""} ${device.model ?? ""}${ + device.vendor || device.model ? ", " : "" + }${os.name}${os.name ? ", " : ""}${browser.name}`; + } + const sessionCookie = await getSessionCookieById({ sessionId }); + + const session = await getSession(sessionCookie.id, sessionCookie.token); + + const userId = session?.session?.factors?.user?.id; + + if (!userId) { + throw new Error("Could not get session"); + } + + const req = create( + VerifyU2FRegistrationRequestSchema, + // TODO: why did we passed the request instead of body here? + command, + ); + + return verifyU2FRegistration(req); +} diff --git a/apps/login/src/ui/RegisterU2F.tsx b/apps/login/src/ui/RegisterU2F.tsx index 01081cd5eed..a69d7d641d4 100644 --- a/apps/login/src/ui/RegisterU2F.tsx +++ b/apps/login/src/ui/RegisterU2F.tsx @@ -9,6 +9,7 @@ import Alert from "./Alert"; import { coerceToArrayBuffer, coerceToBase64Url } from "@/utils/base64"; import BackButton from "./BackButton"; import { RegisterU2FResponse } from "@zitadel/proto/zitadel/user/v2/user_service_pb"; +import { addU2F, verifyU2F } from "@/lib/server/u2f"; type Inputs = {}; @@ -36,23 +37,15 @@ export default function RegisterU2F({ async function submitRegister() { setError(""); setLoading(true); - const res = await fetch("/api/u2f", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - sessionId, - }), + const response = await addU2F({ + sessionId, + }).catch((error) => { + setLoading(false); + setError(error.message); }); - const response = await res.json(); - setLoading(false); - if (!res.ok) { - setError(response.details); - return Promise.reject(response.details); - } + return response; } @@ -63,26 +56,18 @@ export default function RegisterU2F({ sessionId: string, ) { setLoading(true); - const res = await fetch("/api/u2f/verify", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - u2fId, - passkeyName, - publicKeyCredential, - sessionId, - }), + const response = await verifyU2F({ + u2fId, + passkeyName, + publicKeyCredential, + sessionId, + }).catch((error: Error) => { + setLoading(false); + setError(error.message); }); - const response = await res.json(); - setLoading(false); - if (!res.ok) { - setError(response.details); - return Promise.reject(response.details); - } + return response; } diff --git a/apps/login/src/utils/session.ts b/apps/login/src/utils/session.ts index 2aeea44c3fd..a192b758392 100644 --- a/apps/login/src/utils/session.ts +++ b/apps/login/src/utils/session.ts @@ -16,7 +16,7 @@ import { Checks, ChecksSchema, } from "@zitadel/proto/zitadel/session/v2/session_service_pb"; -import { toDate } from "@zitadel/client"; +import { timestampDate, toDate } from "@zitadel/client"; import { create } from "@zitadel/client"; type CustomCookieData = { @@ -112,9 +112,15 @@ export async function createSessionForUserIdAndUpdateCookie( const sessionCookie: CustomCookieData = { id: createdSession.sessionId, token: createdSession.sessionToken, - creationDate: `${toDate(response.session.creationDate)?.getTime() ?? ""}`, - expirationDate: `${toDate(response.session.expirationDate)?.getTime() ?? ""}`, - changeDate: `${toDate(response.session.changeDate)?.getTime() ?? ""}`, + creationDate: response.session.creationDate + ? `${timestampDate(response.session.creationDate).toDateString()}` + : "", + expirationDate: response.session.expirationDate + ? `${timestampDate(response.session.expirationDate).toDateString()}` + : "", + changeDate: response.session.changeDate + ? `${timestampDate(response.session.changeDate).toDateString()}` + : "", loginName: response.session.factors.user.loginName ?? "", }; @@ -162,9 +168,15 @@ export async function createSessionForIdpAndUpdateCookie( const sessionCookie: CustomCookieData = { id: createdSession.sessionId, token: createdSession.sessionToken, - creationDate: `${toDate(response.session.creationDate)?.getTime() ?? ""}`, - expirationDate: `${toDate(response.session.expirationDate)?.getTime() ?? ""}`, - changeDate: `${toDate(response.session.changeDate)?.getTime() ?? ""}`, + creationDate: response.session.creationDate + ? `${timestampDate(response.session.creationDate).toDateString()}` + : "", + expirationDate: response.session.expirationDate + ? `${timestampDate(response.session.expirationDate).toDateString()}` + : "", + changeDate: response.session.changeDate + ? `${timestampDate(response.session.changeDate).toDateString()}` + : "", loginName: response.session.factors.user.loginName ?? "", organization: response.session.factors.user.organizationId ?? "", }; @@ -211,7 +223,10 @@ export async function setSessionAndUpdateCookie( token: updatedSession.sessionToken, creationDate: recentCookie.creationDate, expirationDate: recentCookie.expirationDate, - changeDate: `${toDate(updatedSession.details?.changeDate)?.getTime() ?? ""}`, + // just overwrite the changeDate with the new one + changeDate: updatedSession.details?.changeDate + ? `${timestampDate(updatedSession.details.changeDate).toDateString()}` + : "", loginName: recentCookie.loginName, organization: recentCookie.organization, }; @@ -229,7 +244,10 @@ export async function setSessionAndUpdateCookie( token: updatedSession.sessionToken, creationDate: sessionCookie.creationDate, expirationDate: sessionCookie.expirationDate, - changeDate: `${toDate(session.changeDate)?.getTime() ?? ""}`, + // just overwrite the changeDate with the new one + changeDate: updatedSession.details?.changeDate + ? `${timestampDate(updatedSession.details.changeDate).toDateString()}` + : "", loginName: session.factors?.user?.loginName ?? "", organization: session.factors?.user?.organizationId ?? "", };