u2f, otp api

This commit is contained in:
peintnermax
2024-09-04 09:44:19 +02:00
parent 07f360a749
commit 53c495c3b9
7 changed files with 117 additions and 146 deletions

View File

@@ -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 });
}
}

View File

@@ -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 });
}
}

View File

@@ -1,3 +1,5 @@
"use server";
import {
getMostRecentSessionCookie,
getSessionCookieById,

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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 ?? "",
};