major refactoring adding and finishing xstate signin flow
This commit is contained in:
		@@ -1,125 +0,0 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
  import { onMount } from "svelte";
 | 
			
		||||
  import {
 | 
			
		||||
    isSignInRedirect,
 | 
			
		||||
    getProviderFromUrl,
 | 
			
		||||
  } from "@lit-protocol/lit-auth-client";
 | 
			
		||||
  import type { IRelayPKP } from "@lit-protocol/types";
 | 
			
		||||
  import Icon from "@iconify/svelte";
 | 
			
		||||
  import { mintPkp } from "./mintPkp";
 | 
			
		||||
  import { createLitSession } from "./createLitSession";
 | 
			
		||||
  import { connectProvider } from "./setupLit";
 | 
			
		||||
 | 
			
		||||
  const redirectUri = "http://localhost:3000/";
 | 
			
		||||
 | 
			
		||||
  let sessionSigs = null;
 | 
			
		||||
  let currentPKP, authMethod, provider;
 | 
			
		||||
  let status = "Initializing...";
 | 
			
		||||
  let pkps: IRelayPKP[] = [];
 | 
			
		||||
  let view = "SIGN_IN";
 | 
			
		||||
 | 
			
		||||
  onMount(async () => {
 | 
			
		||||
    initialize();
 | 
			
		||||
 | 
			
		||||
    const storedSession = localStorage.getItem("google-session");
 | 
			
		||||
    const storedPKP = localStorage.getItem("current-pkp");
 | 
			
		||||
    if (storedSession != null) {
 | 
			
		||||
      sessionSigs = JSON.parse(storedSession);
 | 
			
		||||
      currentPKP = JSON.parse(storedPKP);
 | 
			
		||||
      view = "READY";
 | 
			
		||||
    } else {
 | 
			
		||||
      view = "SIGN_IN";
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  async function initialize() {
 | 
			
		||||
    status = "Connecting to Google provider...";
 | 
			
		||||
    try {
 | 
			
		||||
      provider = await connectProvider();
 | 
			
		||||
      status = "Connected to Google provider.";
 | 
			
		||||
      if (isSignInRedirect(redirectUri)) {
 | 
			
		||||
        const providerName = getProviderFromUrl();
 | 
			
		||||
        if (providerName) {
 | 
			
		||||
          await handleRedirect(providerName);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      console.log(err);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async function authWithGoogle() {
 | 
			
		||||
    try {
 | 
			
		||||
      if (!provider) {
 | 
			
		||||
        provider = await connectProvider();
 | 
			
		||||
        status = "Reconnected to Google provider.";
 | 
			
		||||
      }
 | 
			
		||||
      await provider.signIn();
 | 
			
		||||
      status = "Signing in with Google...";
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      console.log(err);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async function handleRedirect(providerName: string) {
 | 
			
		||||
    try {
 | 
			
		||||
      if (!provider) throw new Error("Invalid provider.");
 | 
			
		||||
      authMethod = await provider.authenticate();
 | 
			
		||||
      status = "Authenticated successfully.";
 | 
			
		||||
      pkps = await provider.fetchPKPsThroughRelayer(authMethod);
 | 
			
		||||
      status = "Fetching your Google PKP...";
 | 
			
		||||
      if (pkps.length === 0) {
 | 
			
		||||
        status = "No PKPs found. Minting new PKP...";
 | 
			
		||||
        await mint();
 | 
			
		||||
      } else {
 | 
			
		||||
        // Use the first PKP directly
 | 
			
		||||
        await createSession(pkps[0]);
 | 
			
		||||
      }
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      console.log(err);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async function mint() {
 | 
			
		||||
    const newPKP: IRelayPKP = await mintPkp(provider, authMethod);
 | 
			
		||||
    pkps = [...pkps, newPKP];
 | 
			
		||||
    status = "New PKP minted.";
 | 
			
		||||
    await createSession(newPKP);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async function createSession(pkp: IRelayPKP) {
 | 
			
		||||
    try {
 | 
			
		||||
      currentPKP = pkp; // Assign the selected PKP to currentPKP
 | 
			
		||||
      createLitSession(provider, pkp.publicKey, authMethod).then((sigs) => {
 | 
			
		||||
        sessionSigs = sigs;
 | 
			
		||||
        // Store sessionSigs and currentPKP in localStorage
 | 
			
		||||
        localStorage.setItem("google-session", JSON.stringify(sessionSigs));
 | 
			
		||||
        localStorage.setItem("current-pkp", JSON.stringify(currentPKP));
 | 
			
		||||
      });
 | 
			
		||||
      status = "Session created successfully.";
 | 
			
		||||
      view = "SIGN_IN";
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      console.log(err);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<div class="flex items-center justify-center h-screen">
 | 
			
		||||
  <div>
 | 
			
		||||
    {#if view === "SIGN_IN"}
 | 
			
		||||
      <button on:click={authWithGoogle} class="btn variant-filled">
 | 
			
		||||
        <span><Icon icon="flat-color-icons:google" /></span>
 | 
			
		||||
        <span>Sign in with Google</span>
 | 
			
		||||
      </button>
 | 
			
		||||
    {/if}
 | 
			
		||||
    {#if view === "READY"}
 | 
			
		||||
      <div>
 | 
			
		||||
        <h3>Your PKP Address:</h3>
 | 
			
		||||
        <p>{currentPKP.ethAddress}</p>
 | 
			
		||||
      </div>
 | 
			
		||||
    {/if}
 | 
			
		||||
    <div class="mt-4 text-center">
 | 
			
		||||
      <p>{status}</p>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
@@ -1,118 +0,0 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
  import { onMount } from "svelte";
 | 
			
		||||
  import {
 | 
			
		||||
    isSignInRedirect,
 | 
			
		||||
    getProviderFromUrl,
 | 
			
		||||
  } from "@lit-protocol/lit-auth-client";
 | 
			
		||||
  import type { IRelayPKP } from "@lit-protocol/types";
 | 
			
		||||
  import Icon from "@iconify/svelte";
 | 
			
		||||
  import { createLitSession } from "./createLitSession";
 | 
			
		||||
  import { connectProvider } from "./setupLit";
 | 
			
		||||
  import { googleSession } from "./stores";
 | 
			
		||||
 | 
			
		||||
  const redirectUri = "http://localhost:3000/";
 | 
			
		||||
 | 
			
		||||
  let authMethod, provider;
 | 
			
		||||
  let status = "Initializing...";
 | 
			
		||||
  let pkps: IRelayPKP[] = [];
 | 
			
		||||
 | 
			
		||||
  onMount(async () => {
 | 
			
		||||
    initialize();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  async function initialize() {
 | 
			
		||||
    status = "Connecting to Google provider...";
 | 
			
		||||
    try {
 | 
			
		||||
      provider = await connectProvider();
 | 
			
		||||
      status = "Connected to Google provider.";
 | 
			
		||||
      if (isSignInRedirect(redirectUri)) {
 | 
			
		||||
        const providerName = getProviderFromUrl();
 | 
			
		||||
        if (providerName) {
 | 
			
		||||
          await handleRedirect(providerName);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      console.log(err);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async function authWithGoogle() {
 | 
			
		||||
    try {
 | 
			
		||||
      if (!provider) {
 | 
			
		||||
        provider = await connectProvider();
 | 
			
		||||
        status = "Reconnected to Google provider.";
 | 
			
		||||
      }
 | 
			
		||||
      await provider.signIn();
 | 
			
		||||
      status = "Signing in with Google...";
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      console.log(err);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async function handleRedirect(providerName: string) {
 | 
			
		||||
    try {
 | 
			
		||||
      if (!provider) throw new Error("Invalid provider.");
 | 
			
		||||
      authMethod = await provider.authenticate();
 | 
			
		||||
      status = "Authenticated successfully.";
 | 
			
		||||
      pkps = await provider.fetchPKPsThroughRelayer(authMethod);
 | 
			
		||||
      status = "Fetching your Google PKP...";
 | 
			
		||||
      if (pkps.length === 0) {
 | 
			
		||||
        status = "No PKPs found. Minting new PKP...";
 | 
			
		||||
        await mint();
 | 
			
		||||
      } else {
 | 
			
		||||
        // Use the first PKP directly
 | 
			
		||||
        await createSession(pkps[0]);
 | 
			
		||||
      }
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      console.log(err);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async function mint() {
 | 
			
		||||
    const newPKP: IRelayPKP = await mintPkp(provider, authMethod);
 | 
			
		||||
    pkps = [...pkps, newPKP];
 | 
			
		||||
    status = "New PKP minted.";
 | 
			
		||||
    await createSession(newPKP);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async function createSession(pkp: IRelayPKP) {
 | 
			
		||||
    try {
 | 
			
		||||
      const currentPKP = pkp; // Assign the selected PKP to currentPKP
 | 
			
		||||
      const sessionSigs = await createLitSession(
 | 
			
		||||
        provider,
 | 
			
		||||
        pkp.publicKey,
 | 
			
		||||
        authMethod
 | 
			
		||||
      );
 | 
			
		||||
      // Add the sessionSigs and PKP to localstorage
 | 
			
		||||
      localStorage.setItem(
 | 
			
		||||
        "myPKP",
 | 
			
		||||
        JSON.stringify({
 | 
			
		||||
          provider: "google",
 | 
			
		||||
          pkp: currentPKP,
 | 
			
		||||
          sessionSigs: sessionSigs,
 | 
			
		||||
        })
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      status = "Session created successfully.";
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      console.log(err);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<div>
 | 
			
		||||
  <div class="p-8 bg-white bg-opacity-75 rounded shadow-md">
 | 
			
		||||
    <button
 | 
			
		||||
      on:click={authWithGoogle}
 | 
			
		||||
      class="w-full py-2 text-white bg-blue-500 rounded hover:bg-blue-700 flex items-center justify-center"
 | 
			
		||||
    >
 | 
			
		||||
      <span class="mr-2"><Icon icon="flat-color-icons:google" /></span>
 | 
			
		||||
      <span>Sign in with Google</span>
 | 
			
		||||
    </button>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="px-4 bg-white bg-opacity-75 rounded shadow-md">
 | 
			
		||||
    <div class="mt-4 text-center">
 | 
			
		||||
      <p class="text-gray-600">{status}</p>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
@@ -1,85 +0,0 @@
 | 
			
		||||
<script>
 | 
			
		||||
  import { onMount } from "svelte";
 | 
			
		||||
  import Icon from "@iconify/svelte";
 | 
			
		||||
  import { googleSession } from "$lib/stores.js";
 | 
			
		||||
 | 
			
		||||
  let myPKP;
 | 
			
		||||
 | 
			
		||||
  onMount(() => {
 | 
			
		||||
    myPKP = JSON.parse(localStorage.getItem("myPKP"));
 | 
			
		||||
    if (myPKP) {
 | 
			
		||||
      let parsedSigs = parseSessionSigs(myPKP.sessionSigs);
 | 
			
		||||
      let active = parsedSigs.some((sig) => !sig.isExpired);
 | 
			
		||||
      if (!active) {
 | 
			
		||||
        clearSession();
 | 
			
		||||
        googleSession.set({ activeSession: false });
 | 
			
		||||
      } else {
 | 
			
		||||
        googleSession.set({ activeSession: true });
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  $: {
 | 
			
		||||
    if (myPKP) {
 | 
			
		||||
      let parsedSigs = parseSessionSigs(myPKP.sessionSigs);
 | 
			
		||||
      let active = parsedSigs.some((sig) => !sig.isExpired);
 | 
			
		||||
      googleSession.set({ activeSession: true });
 | 
			
		||||
      if (!active) {
 | 
			
		||||
        clearSession();
 | 
			
		||||
        googleSession.set({ activeSession: false });
 | 
			
		||||
      } else {
 | 
			
		||||
        googleSession.set({ activeSession: true });
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function parseSessionSigs(jsonData) {
 | 
			
		||||
    let sessionList = Object.values(jsonData).map((session) => {
 | 
			
		||||
      let sessionData = JSON.parse(session.signedMessage);
 | 
			
		||||
      let expirationDate = new Date(sessionData.expiration);
 | 
			
		||||
      let isExpired = expirationDate < new Date();
 | 
			
		||||
      return {
 | 
			
		||||
        sig: session.sig,
 | 
			
		||||
        expiration: expirationDate,
 | 
			
		||||
        isExpired: isExpired,
 | 
			
		||||
      };
 | 
			
		||||
    });
 | 
			
		||||
    return sessionList;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function clearSession() {
 | 
			
		||||
    localStorage.removeItem("myPKP");
 | 
			
		||||
    myPKP = null;
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<!-- {#if myPKP}
 | 
			
		||||
  <div
 | 
			
		||||
    class="fixed bottom-0 left-0 right-0 p-3 bg-white bg-opacity-75 rounded-t-lg shadow-md flex flex-col items-center space-y-4"
 | 
			
		||||
  >
 | 
			
		||||
    <div class="w-full flex items-center justify-between space-x-4">
 | 
			
		||||
      <div class="flex items-center space-x-2">
 | 
			
		||||
        <Icon
 | 
			
		||||
          icon="ic:baseline-account-circle"
 | 
			
		||||
          class="text-gray-500 w-12 h-12"
 | 
			
		||||
        />
 | 
			
		||||
        <div>
 | 
			
		||||
          <p class="text-sm">
 | 
			
		||||
            <span class="font-semibold">Address:</span>
 | 
			
		||||
            {myPKP.pkp.ethAddress}
 | 
			
		||||
          </p>
 | 
			
		||||
          <p class="text-xs">
 | 
			
		||||
            <span class="font-semibold">Provider:</span>
 | 
			
		||||
            {myPKP.provider}
 | 
			
		||||
          </p>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <button
 | 
			
		||||
        on:click={clearSession}
 | 
			
		||||
        class="py-1 px-2 text-white bg-red-500 rounded hover:bg-red-700"
 | 
			
		||||
      >
 | 
			
		||||
        Clear Session
 | 
			
		||||
      </button>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
{/if} -->
 | 
			
		||||
@@ -1,120 +0,0 @@
 | 
			
		||||
<!-- SignVerifyMessage.svelte -->
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
  import { ethers } from "ethers";
 | 
			
		||||
  import { onMount } from "svelte";
 | 
			
		||||
  import { signRequest, signedMessages } from "./stores.js";
 | 
			
		||||
 | 
			
		||||
  let messageToSign = {};
 | 
			
		||||
  let currentPKP;
 | 
			
		||||
  let sessionSigs;
 | 
			
		||||
  let status = "";
 | 
			
		||||
  let litNodeClient;
 | 
			
		||||
  let messageSignature;
 | 
			
		||||
 | 
			
		||||
  onMount(async () => {
 | 
			
		||||
    litNodeClient = new LitNodeClient({ litNetwork: "serrano" });
 | 
			
		||||
    await litNodeClient.connect();
 | 
			
		||||
 | 
			
		||||
    const sessionSigsLocalStorage = localStorage.getItem("google-session");
 | 
			
		||||
    const currentPKPLocalStorage = localStorage.getItem("current-pkp");
 | 
			
		||||
    if (sessionSigsLocalStorage && currentPKPLocalStorage) {
 | 
			
		||||
      sessionSigs = JSON.parse(sessionSigsLocalStorage);
 | 
			
		||||
      currentPKP = JSON.parse(currentPKPLocalStorage);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  async function signMessageWithPKP() {
 | 
			
		||||
    const userConfirmed = window.confirm(
 | 
			
		||||
      "Do you want to sign the following message?\n\n" +
 | 
			
		||||
        JSON.stringify(messageToSign, null, 2)
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if (!userConfirmed) {
 | 
			
		||||
      status = "User did not allow to sign the message.";
 | 
			
		||||
      dispatch("status", status);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    try {
 | 
			
		||||
      // Create a specific JSON object
 | 
			
		||||
      const jsonString = JSON.stringify(messageToSign);
 | 
			
		||||
 | 
			
		||||
      // Convert the JSON string to an array of character codes
 | 
			
		||||
      const toSign = ethers.getBytes(ethers.hashMessage(jsonString));
 | 
			
		||||
 | 
			
		||||
      const litActionCode = `
 | 
			
		||||
        const go = async () => {
 | 
			
		||||
          const sigShare = await LitActions.signEcdsa({ toSign, publicKey, sigName });
 | 
			
		||||
        };
 | 
			
		||||
        go();
 | 
			
		||||
      `;
 | 
			
		||||
 | 
			
		||||
      // Sign message
 | 
			
		||||
      const results = await litNodeClient.executeJs({
 | 
			
		||||
        code: litActionCode,
 | 
			
		||||
        sessionSigs: sessionSigs,
 | 
			
		||||
        jsParams: {
 | 
			
		||||
          toSign: toSign,
 | 
			
		||||
          publicKey: currentPKP.publicKey,
 | 
			
		||||
          sigName: "sig1",
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      // Get signature
 | 
			
		||||
      const result = results.signatures["sig1"];
 | 
			
		||||
      messageSignature = ethers.Signature.from({
 | 
			
		||||
        r: "0x" + result.r,
 | 
			
		||||
        s: "0x" + result.s,
 | 
			
		||||
        v: result.recid,
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      signedMessages.update((messages) => [
 | 
			
		||||
        ...messages,
 | 
			
		||||
        { json: messageToSign, signature: messageSignature },
 | 
			
		||||
      ]);
 | 
			
		||||
 | 
			
		||||
      // verify();
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      console.error(err);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  async function verify() {
 | 
			
		||||
    const response = await fetch("/api/verify", {
 | 
			
		||||
      method: "POST",
 | 
			
		||||
      headers: {
 | 
			
		||||
        "Content-Type": "application/json",
 | 
			
		||||
      },
 | 
			
		||||
      body: JSON.stringify({
 | 
			
		||||
        messageToSign,
 | 
			
		||||
        messageSignature,
 | 
			
		||||
        currentPKP,
 | 
			
		||||
      }),
 | 
			
		||||
    });
 | 
			
		||||
    if (!response.ok) {
 | 
			
		||||
      alert("verify failed");
 | 
			
		||||
    } else {
 | 
			
		||||
      let json = await response.json();
 | 
			
		||||
      alert(json.verified ? "Signature valid" : "! Signature NOT valid !");
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  signRequest.subscribe(({ json }) => {
 | 
			
		||||
    if (messageToSign && Object.keys(json).length > 0) {
 | 
			
		||||
      signRequest.set({ json: {} });
 | 
			
		||||
      messageToSign = json;
 | 
			
		||||
      signMessageWithPKP(json);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
{#if status}
 | 
			
		||||
  <div class="mt-4 text-center">
 | 
			
		||||
    <p>Status: {status}</p>
 | 
			
		||||
  </div>
 | 
			
		||||
{/if}
 | 
			
		||||
{#if messageSignature}
 | 
			
		||||
  <div class="mt-4 text-center">
 | 
			
		||||
    <p>Signature</p>
 | 
			
		||||
    <pre>{JSON.stringify(messageSignature)}</pre>
 | 
			
		||||
  </div>
 | 
			
		||||
  <button on:click={verify}>Verify</button><br />
 | 
			
		||||
{/if}
 | 
			
		||||
@@ -2,8 +2,15 @@
 | 
			
		||||
  import { useMachine } from "@xstate/svelte";
 | 
			
		||||
  import walletMachine from "./machines/walletMachine";
 | 
			
		||||
  import { onMount } from "svelte";
 | 
			
		||||
  import Icon from "@iconify/svelte";
 | 
			
		||||
 | 
			
		||||
  import {
 | 
			
		||||
    signInWithGoogle,
 | 
			
		||||
    startSignIn as startSignInService,
 | 
			
		||||
  } from "./services/signInWithGoogle";
 | 
			
		||||
 | 
			
		||||
  const { state, send } = useMachine(walletMachine);
 | 
			
		||||
 | 
			
		||||
  $: {
 | 
			
		||||
    if ($state.context.pkps && $state.context.sessionSigs) {
 | 
			
		||||
      localStorage.setItem(
 | 
			
		||||
@@ -21,38 +28,62 @@
 | 
			
		||||
      send({ type: "RELOAD", ...me });
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  async function startSignIn() {
 | 
			
		||||
    startSignInService.set(true);
 | 
			
		||||
    await signInWithGoogle();
 | 
			
		||||
  }
 | 
			
		||||
  function clearSession() {
 | 
			
		||||
    send("LOGOUT");
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
{#if $state.matches("creatingSession")}
 | 
			
		||||
  <div class="bg-white p-10">
 | 
			
		||||
    <p>Authenticated successfully. Selecting or minting PKP...</p>
 | 
			
		||||
  </div>
 | 
			
		||||
{:else if $state.matches("sessionAvailable")}
 | 
			
		||||
  <div class="bg-white p-10">
 | 
			
		||||
    <p>Signed in successfully. Here is your PKP:</p>
 | 
			
		||||
    <pre>{JSON.stringify($state.context.pkps[0].ethAddress, null, 2)}</pre>
 | 
			
		||||
    <p>Session available. Here are your session signatures:</p>
 | 
			
		||||
    <div class="flex flex-col">
 | 
			
		||||
      {#each Object.keys($state.context.sessionSigs) as key}
 | 
			
		||||
        <div class="flex items-center p-2 bg-white rounded shadow mb-2">
 | 
			
		||||
          <div
 | 
			
		||||
            class="w-4 h-4 mr-2 rounded-full"
 | 
			
		||||
            class:bg-green-500={!$state.context.sessionSigs[key].expired}
 | 
			
		||||
            class:bg-red-500={$state.context.sessionSigs[key].expired}
 | 
			
		||||
          />
 | 
			
		||||
          <div class="flex-grow">
 | 
			
		||||
            <p class="font-bold">{key}</p>
 | 
			
		||||
            <p class="text-sm text-gray-500">
 | 
			
		||||
              {$state.context.sessionSigs[key].sig}
 | 
			
		||||
{#if $state.matches("sessionAvailable") || $state.matches("creatingSession") || $state.matches("signIn")}
 | 
			
		||||
  {#if $state.matches("signIn")}
 | 
			
		||||
    <div class="w-1/3">
 | 
			
		||||
      <button
 | 
			
		||||
        on:click={startSignIn}
 | 
			
		||||
        class="w-full py-2 text-white bg-blue-500 rounded hover:bg-blue-700 flex items-center justify-center"
 | 
			
		||||
      >
 | 
			
		||||
        <span class="mr-2"><Icon icon="flat-color-icons:google" /></span>
 | 
			
		||||
        <span>Sign in with Google</span>
 | 
			
		||||
      </button>
 | 
			
		||||
    </div>
 | 
			
		||||
  {:else if $state.context.pkps}
 | 
			
		||||
    <div
 | 
			
		||||
      class="fixed bottom-0 left-0 right-0 p-3 bg-white bg-opacity-75 rounded-t-lg shadow-md flex flex-col items-center space-y-4"
 | 
			
		||||
    >
 | 
			
		||||
      <div class="w-full flex items-center justify-between space-x-4">
 | 
			
		||||
        <div class="flex items-center space-x-2">
 | 
			
		||||
          <div>
 | 
			
		||||
            <p class="text-sm">
 | 
			
		||||
              <span class="font-semibold">Address:</span>
 | 
			
		||||
              {$state.context.pkps[0].ethAddress}
 | 
			
		||||
            </p>
 | 
			
		||||
            <p class="text-xs">
 | 
			
		||||
              <span class="font-semibold">Provider:</span>
 | 
			
		||||
              {$state.context.providerName}
 | 
			
		||||
            </p>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      {/each}
 | 
			
		||||
        <button
 | 
			
		||||
          on:click={clearSession}
 | 
			
		||||
          class="py-1 px-2 text-white bg-red-500 rounded hover:bg-red-700"
 | 
			
		||||
        >
 | 
			
		||||
          Logout
 | 
			
		||||
        </button>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  {:else if $state.matches("sessionExpired")}
 | 
			
		||||
    <div class="bg-white p-10">
 | 
			
		||||
      <p>Error creating session. Please try again.</p>
 | 
			
		||||
      <pre>{JSON.stringify($state.context.error, null, 2)}</pre>
 | 
			
		||||
    </div>
 | 
			
		||||
  {/if}
 | 
			
		||||
{:else}
 | 
			
		||||
  <div class="bg-white p-10 rounded-full">
 | 
			
		||||
    <div class="bg-white rounded-full p-5 animate-spin">
 | 
			
		||||
      <Icon icon="la:spinner" width="100" height="100" />
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
{:else if $state.matches("sessionExpired")}
 | 
			
		||||
  <div class="bg-white p-10">
 | 
			
		||||
    <p>Error creating session. Please try again.</p>
 | 
			
		||||
    <pre>{JSON.stringify($state.context.error, null, 2)}</pre>
 | 
			
		||||
  </div>
 | 
			
		||||
{/if}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
import { createMachine, assign } from 'xstate';
 | 
			
		||||
import { signInWithGoogle } from '../services/signInWithGoogle';
 | 
			
		||||
import { createSession } from '../services/createSession';
 | 
			
		||||
import { goto } from '$app/navigation';
 | 
			
		||||
 | 
			
		||||
const walletMachine = createMachine({
 | 
			
		||||
    id: 'wallet',
 | 
			
		||||
@@ -11,7 +12,8 @@ const walletMachine = createMachine({
 | 
			
		||||
        providerName: null,
 | 
			
		||||
        authMethod: null,
 | 
			
		||||
        pkps: [],
 | 
			
		||||
        sessionSigs: null
 | 
			
		||||
        sessionSigs: null,
 | 
			
		||||
        redirect: false
 | 
			
		||||
    },
 | 
			
		||||
    states: {
 | 
			
		||||
        signIn: {
 | 
			
		||||
@@ -83,11 +85,26 @@ const walletMachine = createMachine({
 | 
			
		||||
            on: {
 | 
			
		||||
                EXPIRED: {
 | 
			
		||||
                    target: 'sessionExpired',
 | 
			
		||||
                    cond: (context) => context.sessionSigs === null
 | 
			
		||||
                    cond: (context) => context.sessionSigs && Object.values(context.sessionSigs).every(sig => sig.expired)
 | 
			
		||||
                },
 | 
			
		||||
                LOGOUT: 'sessionExpired'
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        sessionExpired: {
 | 
			
		||||
            entry: assign({
 | 
			
		||||
                sessionSigs: null,
 | 
			
		||||
                redirect: true
 | 
			
		||||
            }),
 | 
			
		||||
            after: {
 | 
			
		||||
                0: {
 | 
			
		||||
                    target: 'signIn',
 | 
			
		||||
                    actions: () => {
 | 
			
		||||
                        localStorage.removeItem('me');
 | 
			
		||||
                        window.location.href = '/';
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        sessionExpired: {}
 | 
			
		||||
    },
 | 
			
		||||
}, {
 | 
			
		||||
    services: {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,23 +1,36 @@
 | 
			
		||||
// src/lib/services/signInWithGoogle.ts
 | 
			
		||||
import { connectProvider } from "$lib/setupLit";
 | 
			
		||||
import { isSignInRedirect, getProviderFromUrl } from "@lit-protocol/lit-auth-client";
 | 
			
		||||
import { writable } from 'svelte/store';
 | 
			
		||||
 | 
			
		||||
export let startSignIn = writable(false);
 | 
			
		||||
 | 
			
		||||
let providerName;
 | 
			
		||||
 | 
			
		||||
export const signInWithGoogle = async () => {
 | 
			
		||||
    if (typeof window !== 'undefined') {
 | 
			
		||||
        try {
 | 
			
		||||
            let provider = await connectProvider();
 | 
			
		||||
            if (isSignInRedirect("http://localhost:3000/")) {
 | 
			
		||||
                const providerName = getProviderFromUrl();
 | 
			
		||||
                providerName = getProviderFromUrl();
 | 
			
		||||
                if (providerName) {
 | 
			
		||||
                    const authMethod = await provider.authenticate();
 | 
			
		||||
                    return { authMethod, provider, providerName }; // Return the data
 | 
			
		||||
                    return { authMethod, provider, providerName };
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                await provider.signIn();
 | 
			
		||||
                let shouldStartSignIn = false;
 | 
			
		||||
                startSignIn.subscribe(value => {
 | 
			
		||||
                    shouldStartSignIn = value;
 | 
			
		||||
                });
 | 
			
		||||
                if (!providerName && shouldStartSignIn) {
 | 
			
		||||
                    await provider.signIn();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } catch (err) {
 | 
			
		||||
            console.error(err);
 | 
			
		||||
            console.error('Error during sign-in:', err);
 | 
			
		||||
            throw err;
 | 
			
		||||
        } finally {
 | 
			
		||||
            startSignIn.set(false);
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        throw new Error("Cannot sign in with Google in a non-browser environment.");
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,8 @@ export const signRequest = writable({json: {}});
 | 
			
		||||
 | 
			
		||||
export const signedMessages = writable([])
 | 
			
		||||
 | 
			
		||||
export const redirectStore = writable(false);
 | 
			
		||||
 | 
			
		||||
export const googleSession = writable({
 | 
			
		||||
    activeSession: false
 | 
			
		||||
  });
 | 
			
		||||
@@ -7,8 +7,6 @@
 | 
			
		||||
  import { onMount } from "svelte";
 | 
			
		||||
  import { initChainProvider } from "$lib/setupChainProvider";
 | 
			
		||||
  import { googleSession } from "$lib/stores.js";
 | 
			
		||||
  import GooglePKP from "$lib/GooglePKP.svelte";
 | 
			
		||||
  import GoogleSession from "$lib/GoogleSession.svelte";
 | 
			
		||||
  import Wallet from "$lib/Wallet.svelte";
 | 
			
		||||
 | 
			
		||||
  let activeSession = false;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user