From 697ed671f394cbd07ea9751fe17f262744d99a49 Mon Sep 17 00:00:00 2001 From: polwex Date: Wed, 16 Jul 2025 08:51:35 +0700 Subject: m --- lib/passkey.ts | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- lib/types.ts | 2 ++ 2 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 lib/types.ts (limited to 'lib') diff --git a/lib/passkey.ts b/lib/passkey.ts index 573c62b..81a21a5 100644 --- a/lib/passkey.ts +++ b/lib/passkey.ts @@ -1,8 +1,14 @@ +"use client"; + +import { Platform } from "react-native"; +import * as SecureStore from "expo-secure-store"; +import type { AsyncRes } from "./types"; + const PASSKEY_CREDENTIAL_ID_KEY = "urbit_wallet_passkey_id"; const RELYING_PARTY_ID = "wallet.urbit.org"; // Change this to your domain const RELYING_PARTY_NAME = "Urbit Wallet"; -async function createPasskey() { +export async function createPasskey(): AsyncRes { const pkok = await window.PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable(); console.log({ pkok }); @@ -117,15 +123,70 @@ async function createPasskey() { if (credential) { // Store the credential ID for later use - // await SecureStore.setItemAsync(PASSKEY_CREDENTIAL_ID_KEY, credential.id); + await SecureStore.setItemAsync(PASSKEY_CREDENTIAL_ID_KEY, credential.id); console.log("Passkey created successfully", credential.id); - return true; + return { ok: credential }; } - return false; + return { error: "Failed to create passkey" }; } catch (error) { console.error("Error creating passkey:", error); - return false; + return { error: `${error}` }; + } +} + +export async function authenticateWithPasskey(): AsyncRes { + // if (Platform.OS !== "web") { + // return false; + // } + + try { + const credentialId = await SecureStore.getItemAsync( + PASSKEY_CREDENTIAL_ID_KEY, + ); + + if (!credentialId) { + console.log("No passkey found"); + return { error: "No passkey found" }; + } + + // Generate a random challenge + const challenge = new Uint8Array(32); + crypto.getRandomValues(challenge); + + const getCredentialOptions: CredentialRequestOptions = { + publicKey: { + challenge, + rpId: + window.location.hostname === "localhost" + ? "localhost" + : RELYING_PARTY_ID, + allowCredentials: [ + { + id: Uint8Array.from(atob(credentialId), (c) => c.charCodeAt(0)), + type: "public-key", + transports: ["internal", "hybrid"] as AuthenticatorTransport[], + }, + ], + userVerification: "preferred", + timeout: 60000, + }, + }; + + const credential = (await navigator.credentials.get( + getCredentialOptions, + )) as PublicKeyCredential; + + if (credential) { + // In a production app, you would send the assertion to your server + // to verify it. For this demo, we're just checking if we got a credential. + console.log("Passkey authentication successful"); + return { ok: credential }; + } + + return { error: "failed to generate creds" }; + } catch (error) { + return { error: `${error}` }; } } diff --git a/lib/types.ts b/lib/types.ts new file mode 100644 index 0000000..a22e8be --- /dev/null +++ b/lib/types.ts @@ -0,0 +1,2 @@ +export type Result = { ok: T } | { error: string }; +export type AsyncRes = Promise>; -- cgit v1.2.3