mirror of
https://github.com/zitadel/zitadel.git
synced 2025-12-12 06:52:24 +00:00
navigator, utils
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
createPasskeyRegistrationLink,
|
createPasskeyRegistrationLink,
|
||||||
getSession,
|
getSession,
|
||||||
|
registerPasskey,
|
||||||
server,
|
server,
|
||||||
} from "#/lib/zitadel";
|
} from "#/lib/zitadel";
|
||||||
import { getSessionCookieById } from "#/utils/cookies";
|
import { getSessionCookieById } from "#/utils/cookies";
|
||||||
@@ -12,7 +13,6 @@ export async function POST(request: NextRequest) {
|
|||||||
const { sessionId } = body;
|
const { sessionId } = body;
|
||||||
|
|
||||||
const sessionCookie = await getSessionCookieById(sessionId);
|
const sessionCookie = await getSessionCookieById(sessionId);
|
||||||
console.log(sessionCookie);
|
|
||||||
|
|
||||||
const session = await getSession(
|
const session = await getSession(
|
||||||
server,
|
server,
|
||||||
@@ -20,14 +20,15 @@ export async function POST(request: NextRequest) {
|
|||||||
sessionCookie.token
|
sessionCookie.token
|
||||||
);
|
);
|
||||||
|
|
||||||
if (session?.session && session.session?.factors?.user?.id) {
|
const userId = session?.session?.factors?.user?.id;
|
||||||
console.log(session.session.factors.user.id, sessionCookie.token);
|
|
||||||
return createPasskeyRegistrationLink(
|
if (userId) {
|
||||||
session.session.factors.user.id,
|
return createPasskeyRegistrationLink(userId, sessionCookie.token)
|
||||||
sessionCookie.token
|
|
||||||
)
|
|
||||||
.then((resp) => {
|
.then((resp) => {
|
||||||
return NextResponse.json(resp);
|
const code = resp.code;
|
||||||
|
return registerPasskey(userId, code).then((resp) => {
|
||||||
|
return NextResponse.json(resp);
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
return NextResponse.json(error, { status: 500 });
|
return NextResponse.json(error, { status: 500 });
|
||||||
|
|||||||
@@ -251,7 +251,7 @@ export async function verifyPasskeyRegistration(
|
|||||||
*/
|
*/
|
||||||
export async function registerPasskey(
|
export async function registerPasskey(
|
||||||
userId: string,
|
userId: string,
|
||||||
sessionToken: string
|
code: { id: string; code: string }
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
// this actions will be made from the currently seleected user
|
// this actions will be made from the currently seleected user
|
||||||
const zitadelConfig: ZitadelServerOptions = {
|
const zitadelConfig: ZitadelServerOptions = {
|
||||||
@@ -263,13 +263,11 @@ export async function registerPasskey(
|
|||||||
const authserver: ZitadelServer = initializeServer(zitadelConfig);
|
const authserver: ZitadelServer = initializeServer(zitadelConfig);
|
||||||
console.log("server", authserver);
|
console.log("server", authserver);
|
||||||
const userservice = user.getUser(server);
|
const userservice = user.getUser(server);
|
||||||
return userservice.registerPasskey(
|
return userservice.registerPasskey({
|
||||||
{
|
userId,
|
||||||
userId,
|
code,
|
||||||
// returnCode: new ReturnPasskeyRegistrationCode(),
|
// returnCode: new ReturnPasskeyRegistrationCode(),
|
||||||
},
|
});
|
||||||
{ metadata: bearerTokenMetadata(sessionToken) }
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export { server };
|
export { server };
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ import { useForm } from "react-hook-form";
|
|||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { Spinner } from "./Spinner";
|
import { Spinner } from "./Spinner";
|
||||||
import Alert from "./Alert";
|
import Alert from "./Alert";
|
||||||
|
import { RegisterPasskeyResponse } from "@zitadel/server";
|
||||||
|
import { coerceToArrayBuffer, coerceToBase64Url } from "#/utils/base64";
|
||||||
type Inputs = {};
|
type Inputs = {};
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -50,8 +51,120 @@ export default function RegisterPasskey({ sessionId }: Props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function submitRegisterAndContinue(value: Inputs): Promise<boolean | void> {
|
function submitRegisterAndContinue(value: Inputs): Promise<boolean | void> {
|
||||||
return submitRegister().then((resp: any) => {
|
return submitRegister().then((resp: RegisterPasskeyResponse) => {
|
||||||
return router.push(`/accounts`);
|
console.log(resp.publicKeyCredentialCreationOptions?.publicKey);
|
||||||
|
if (
|
||||||
|
resp.publicKeyCredentialCreationOptions &&
|
||||||
|
resp.publicKeyCredentialCreationOptions.publicKey
|
||||||
|
) {
|
||||||
|
resp.publicKeyCredentialCreationOptions.publicKey.challenge =
|
||||||
|
coerceToArrayBuffer(
|
||||||
|
resp.publicKeyCredentialCreationOptions.publicKey.challenge,
|
||||||
|
"challenge"
|
||||||
|
);
|
||||||
|
resp.publicKeyCredentialCreationOptions.publicKey.user.id =
|
||||||
|
coerceToArrayBuffer(
|
||||||
|
resp.publicKeyCredentialCreationOptions.publicKey.user.id,
|
||||||
|
"challenge"
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
resp.publicKeyCredentialCreationOptions.publicKey.excludeCredentials
|
||||||
|
) {
|
||||||
|
resp.publicKeyCredentialCreationOptions.publicKey.excludeCredentials.map(
|
||||||
|
(cred: any) => {
|
||||||
|
cred.id = coerceToArrayBuffer(
|
||||||
|
cred.id as string,
|
||||||
|
"excludeCredentials.id"
|
||||||
|
);
|
||||||
|
return cred;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
navigator.credentials
|
||||||
|
.create(resp.publicKeyCredentialCreationOptions)
|
||||||
|
.then((resp) => {
|
||||||
|
console.log(resp);
|
||||||
|
if (
|
||||||
|
resp &&
|
||||||
|
(resp as any).response.attestationObject &&
|
||||||
|
(resp as any).response.clientDataJSON &&
|
||||||
|
(resp as any).rawId
|
||||||
|
) {
|
||||||
|
const attestationObject = (resp as any).response
|
||||||
|
.attestationObject;
|
||||||
|
const clientDataJSON = (resp as any).response.clientDataJSON;
|
||||||
|
const rawId = (resp as any).rawId;
|
||||||
|
|
||||||
|
const data = JSON.stringify({
|
||||||
|
id: resp.id,
|
||||||
|
rawId: coerceToBase64Url(rawId, "rawId"),
|
||||||
|
type: resp.type,
|
||||||
|
response: {
|
||||||
|
attestationObject: coerceToBase64Url(
|
||||||
|
attestationObject,
|
||||||
|
"attestationObject"
|
||||||
|
),
|
||||||
|
clientDataJSON: coerceToBase64Url(
|
||||||
|
clientDataJSON,
|
||||||
|
"clientDataJSON"
|
||||||
|
),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const base64 = btoa(data);
|
||||||
|
|
||||||
|
return base64;
|
||||||
|
// if (this.type === U2FComponentDestination.MFA) {
|
||||||
|
// this.service
|
||||||
|
// .verifyMyMultiFactorU2F(base64, this.name)
|
||||||
|
// .then(() => {
|
||||||
|
// this.translate
|
||||||
|
// .get("USER.MFA.U2F_SUCCESS")
|
||||||
|
// .pipe(take(1))
|
||||||
|
// .subscribe((msg) => {
|
||||||
|
// this.toast.showInfo(msg);
|
||||||
|
// });
|
||||||
|
// this.dialogRef.close(true);
|
||||||
|
// this.loading = false;
|
||||||
|
// })
|
||||||
|
// .catch((error) => {
|
||||||
|
// this.loading = false;
|
||||||
|
// this.toast.showError(error);
|
||||||
|
// });
|
||||||
|
// } else if (this.type === U2FComponentDestination.PASSWORDLESS) {
|
||||||
|
// this.service
|
||||||
|
// .verifyMyPasswordless(base64, this.name)
|
||||||
|
// .then(() => {
|
||||||
|
// this.translate
|
||||||
|
// .get("USER.PASSWORDLESS.U2F_SUCCESS")
|
||||||
|
// .pipe(take(1))
|
||||||
|
// .subscribe((msg) => {
|
||||||
|
// this.toast.showInfo(msg);
|
||||||
|
// });
|
||||||
|
// this.dialogRef.close(true);
|
||||||
|
// this.loading = false;
|
||||||
|
// })
|
||||||
|
// .catch((error) => {
|
||||||
|
// this.loading = false;
|
||||||
|
// this.toast.showError(error);
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
} else {
|
||||||
|
setLoading(false);
|
||||||
|
setError("An error on registering passkey");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
setLoading(false);
|
||||||
|
// setError(error);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// return router.push(`/accounts`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
63
apps/login/utils/base64.ts
Normal file
63
apps/login/utils/base64.ts
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
export function coerceToBase64Url(thing: any, name: string) {
|
||||||
|
// Array or ArrayBuffer to Uint8Array
|
||||||
|
if (Array.isArray(thing)) {
|
||||||
|
thing = Uint8Array.from(thing);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thing instanceof ArrayBuffer) {
|
||||||
|
thing = new Uint8Array(thing);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint8Array to base64
|
||||||
|
if (thing instanceof Uint8Array) {
|
||||||
|
var str = "";
|
||||||
|
var len = thing.byteLength;
|
||||||
|
|
||||||
|
for (var i = 0; i < len; i++) {
|
||||||
|
str += String.fromCharCode(thing[i]);
|
||||||
|
}
|
||||||
|
thing = window.btoa(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof thing !== "string") {
|
||||||
|
throw new Error("could not coerce '" + name + "' to string");
|
||||||
|
}
|
||||||
|
|
||||||
|
// base64 to base64url
|
||||||
|
// NOTE: "=" at the end of challenge is optional, strip it off here
|
||||||
|
thing = thing.replace(/\+/g, "-").replace(/\//g, "_").replace(/=*$/g, "");
|
||||||
|
|
||||||
|
return thing;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function coerceToArrayBuffer(thing: any, name: string) {
|
||||||
|
if (typeof thing === "string") {
|
||||||
|
// base64url to base64
|
||||||
|
thing = thing.replace(/-/g, "+").replace(/_/g, "/");
|
||||||
|
|
||||||
|
// base64 to Uint8Array
|
||||||
|
var str = window.atob(thing);
|
||||||
|
var bytes = new Uint8Array(str.length);
|
||||||
|
for (var i = 0; i < str.length; i++) {
|
||||||
|
bytes[i] = str.charCodeAt(i);
|
||||||
|
}
|
||||||
|
thing = bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array to Uint8Array
|
||||||
|
if (Array.isArray(thing)) {
|
||||||
|
thing = new Uint8Array(thing);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint8Array to ArrayBuffer
|
||||||
|
if (thing instanceof Uint8Array) {
|
||||||
|
thing = thing.buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error if none of the above worked
|
||||||
|
if (!(thing instanceof ArrayBuffer)) {
|
||||||
|
throw new TypeError("could not coerce '" + name + "' to ArrayBuffer");
|
||||||
|
}
|
||||||
|
|
||||||
|
return thing;
|
||||||
|
}
|
||||||
@@ -29,6 +29,7 @@ export {
|
|||||||
AddHumanUserResponse,
|
AddHumanUserResponse,
|
||||||
VerifyEmailResponse,
|
VerifyEmailResponse,
|
||||||
VerifyPasskeyRegistrationResponse,
|
VerifyPasskeyRegistrationResponse,
|
||||||
|
RegisterPasskeyResponse,
|
||||||
} from "./proto/server/zitadel/user/v2alpha/user_service";
|
} from "./proto/server/zitadel/user/v2alpha/user_service";
|
||||||
|
|
||||||
export { type LegalAndSupportSettings } from "./proto/server/zitadel/settings/v2alpha/legal_settings";
|
export { type LegalAndSupportSettings } from "./proto/server/zitadel/settings/v2alpha/legal_settings";
|
||||||
|
|||||||
Reference in New Issue
Block a user