major refactoring adding and finishing xstate signin flow
This commit is contained in:
		| @@ -35,6 +35,7 @@ | |||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "@graphql-tools/graphql-file-loader": "^8.0.0", |     "@graphql-tools/graphql-file-loader": "^8.0.0", | ||||||
|     "@graphql-tools/load": "^8.0.0", |     "@graphql-tools/load": "^8.0.0", | ||||||
|  |     "@iconify/icons-ion": "^1.2.10", | ||||||
|     "@iconify/svelte": "^3.1.4", |     "@iconify/svelte": "^3.1.4", | ||||||
|     "@lit-protocol/auth-helpers": "^2.2.50", |     "@lit-protocol/auth-helpers": "^2.2.50", | ||||||
|     "@lit-protocol/constants": "^2.2.50", |     "@lit-protocol/constants": "^2.2.50", | ||||||
|   | |||||||
							
								
								
									
										9
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										9
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							| @@ -7,6 +7,9 @@ dependencies: | |||||||
|   '@graphql-tools/load': |   '@graphql-tools/load': | ||||||
|     specifier: ^8.0.0 |     specifier: ^8.0.0 | ||||||
|     version: 8.0.0(graphql@16.8.0) |     version: 8.0.0(graphql@16.8.0) | ||||||
|  |   '@iconify/icons-ion': | ||||||
|  |     specifier: ^1.2.10 | ||||||
|  |     version: 1.2.10 | ||||||
|   '@iconify/svelte': |   '@iconify/svelte': | ||||||
|     specifier: ^3.1.4 |     specifier: ^3.1.4 | ||||||
|     version: 3.1.4(svelte@3.54.0) |     version: 3.1.4(svelte@3.54.0) | ||||||
| @@ -2611,6 +2614,12 @@ packages: | |||||||
|     dependencies: |     dependencies: | ||||||
|       '@hapi/hoek': 9.3.0 |       '@hapi/hoek': 9.3.0 | ||||||
|  |  | ||||||
|  |   /@iconify/icons-ion@1.2.10: | ||||||
|  |     resolution: {integrity: sha512-8vd2gihc8fkugNH+bqnNpgAbXJl2AyTiGRgpDG/ELDUyscvUefEE/kW7uz6NnPUYH293vR+tdiruLIgvVsQfNA==} | ||||||
|  |     dependencies: | ||||||
|  |       '@iconify/types': 2.0.0 | ||||||
|  |     dev: false | ||||||
|  |  | ||||||
|   /@iconify/svelte@3.1.4(svelte@3.54.0): |   /@iconify/svelte@3.1.4(svelte@3.54.0): | ||||||
|     resolution: {integrity: sha512-YDwQlN46ka8KPRayDb7TivmkAPizfTXi6BSRNqa1IV0+byA907n8JcgQafA7FD//pW5XCuuAhVx6uRbKTo+CfA==} |     resolution: {integrity: sha512-YDwQlN46ka8KPRayDb7TivmkAPizfTXi6BSRNqa1IV0+byA907n8JcgQafA7FD//pW5XCuuAhVx6uRbKTo+CfA==} | ||||||
|     peerDependencies: |     peerDependencies: | ||||||
|   | |||||||
| @@ -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 { useMachine } from "@xstate/svelte"; | ||||||
|   import walletMachine from "./machines/walletMachine"; |   import walletMachine from "./machines/walletMachine"; | ||||||
|   import { onMount } from "svelte"; |   import { onMount } from "svelte"; | ||||||
|  |   import Icon from "@iconify/svelte"; | ||||||
|  |  | ||||||
|  |   import { | ||||||
|  |     signInWithGoogle, | ||||||
|  |     startSignIn as startSignInService, | ||||||
|  |   } from "./services/signInWithGoogle"; | ||||||
|  |  | ||||||
|   const { state, send } = useMachine(walletMachine); |   const { state, send } = useMachine(walletMachine); | ||||||
|  |  | ||||||
|   $: { |   $: { | ||||||
|     if ($state.context.pkps && $state.context.sessionSigs) { |     if ($state.context.pkps && $state.context.sessionSigs) { | ||||||
|       localStorage.setItem( |       localStorage.setItem( | ||||||
| @@ -21,38 +28,62 @@ | |||||||
|       send({ type: "RELOAD", ...me }); |       send({ type: "RELOAD", ...me }); | ||||||
|     } |     } | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|  |   async function startSignIn() { | ||||||
|  |     startSignInService.set(true); | ||||||
|  |     await signInWithGoogle(); | ||||||
|  |   } | ||||||
|  |   function clearSession() { | ||||||
|  |     send("LOGOUT"); | ||||||
|  |   } | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| {#if $state.matches("creatingSession")} | {#if $state.matches("sessionAvailable") || $state.matches("creatingSession") || $state.matches("signIn")} | ||||||
|   <div class="bg-white p-10"> |   {#if $state.matches("signIn")} | ||||||
|     <p>Authenticated successfully. Selecting or minting PKP...</p> |     <div class="w-1/3"> | ||||||
|   </div> |       <button | ||||||
| {:else if $state.matches("sessionAvailable")} |         on:click={startSignIn} | ||||||
|   <div class="bg-white p-10"> |         class="w-full py-2 text-white bg-blue-500 rounded hover:bg-blue-700 flex items-center justify-center" | ||||||
|     <p>Signed in successfully. Here is your PKP:</p> |       > | ||||||
|     <pre>{JSON.stringify($state.context.pkps[0].ethAddress, null, 2)}</pre> |         <span class="mr-2"><Icon icon="flat-color-icons:google" /></span> | ||||||
|     <p>Session available. Here are your session signatures:</p> |         <span>Sign in with Google</span> | ||||||
|     <div class="flex flex-col"> |       </button> | ||||||
|       {#each Object.keys($state.context.sessionSigs) as key} |     </div> | ||||||
|         <div class="flex items-center p-2 bg-white rounded shadow mb-2"> |   {:else if $state.context.pkps} | ||||||
|           <div |     <div | ||||||
|             class="w-4 h-4 mr-2 rounded-full" |       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" | ||||||
|             class:bg-green-500={!$state.context.sessionSigs[key].expired} |     > | ||||||
|             class:bg-red-500={$state.context.sessionSigs[key].expired} |       <div class="w-full flex items-center justify-between space-x-4"> | ||||||
|           /> |         <div class="flex items-center space-x-2"> | ||||||
|           <div class="flex-grow"> |           <div> | ||||||
|             <p class="font-bold">{key}</p> |             <p class="text-sm"> | ||||||
|             <p class="text-sm text-gray-500"> |               <span class="font-semibold">Address:</span> | ||||||
|               {$state.context.sessionSigs[key].sig} |               {$state.context.pkps[0].ethAddress} | ||||||
|  |             </p> | ||||||
|  |             <p class="text-xs"> | ||||||
|  |               <span class="font-semibold">Provider:</span> | ||||||
|  |               {$state.context.providerName} | ||||||
|             </p> |             </p> | ||||||
|           </div> |           </div> | ||||||
|         </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> | ||||||
|   </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} | {/if} | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ | |||||||
| import { createMachine, assign } from 'xstate'; | import { createMachine, assign } from 'xstate'; | ||||||
| import { signInWithGoogle } from '../services/signInWithGoogle'; | import { signInWithGoogle } from '../services/signInWithGoogle'; | ||||||
| import { createSession } from '../services/createSession'; | import { createSession } from '../services/createSession'; | ||||||
|  | import { goto } from '$app/navigation'; | ||||||
|  |  | ||||||
| const walletMachine = createMachine({ | const walletMachine = createMachine({ | ||||||
|     id: 'wallet', |     id: 'wallet', | ||||||
| @@ -11,7 +12,8 @@ const walletMachine = createMachine({ | |||||||
|         providerName: null, |         providerName: null, | ||||||
|         authMethod: null, |         authMethod: null, | ||||||
|         pkps: [], |         pkps: [], | ||||||
|         sessionSigs: null |         sessionSigs: null, | ||||||
|  |         redirect: false | ||||||
|     }, |     }, | ||||||
|     states: { |     states: { | ||||||
|         signIn: { |         signIn: { | ||||||
| @@ -83,11 +85,26 @@ const walletMachine = createMachine({ | |||||||
|             on: { |             on: { | ||||||
|                 EXPIRED: { |                 EXPIRED: { | ||||||
|                     target: 'sessionExpired', |                     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: { |     services: { | ||||||
|   | |||||||
| @@ -1,23 +1,36 @@ | |||||||
| // src/lib/services/signInWithGoogle.ts | // src/lib/services/signInWithGoogle.ts | ||||||
| import { connectProvider } from "$lib/setupLit"; | import { connectProvider } from "$lib/setupLit"; | ||||||
| import { isSignInRedirect, getProviderFromUrl } from "@lit-protocol/lit-auth-client"; | 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 () => { | export const signInWithGoogle = async () => { | ||||||
|     if (typeof window !== 'undefined') { |     if (typeof window !== 'undefined') { | ||||||
|         try { |         try { | ||||||
|             let provider = await connectProvider(); |             let provider = await connectProvider(); | ||||||
|             if (isSignInRedirect("http://localhost:3000/")) { |             if (isSignInRedirect("http://localhost:3000/")) { | ||||||
|                 const providerName = getProviderFromUrl(); |                 providerName = getProviderFromUrl(); | ||||||
|                 if (providerName) { |                 if (providerName) { | ||||||
|                     const authMethod = await provider.authenticate(); |                     const authMethod = await provider.authenticate(); | ||||||
|                     return { authMethod, provider, providerName }; // Return the data |                     return { authMethod, provider, providerName }; | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 await provider.signIn(); |                 let shouldStartSignIn = false; | ||||||
|  |                 startSignIn.subscribe(value => { | ||||||
|  |                     shouldStartSignIn = value; | ||||||
|  |                 }); | ||||||
|  |                 if (!providerName && shouldStartSignIn) { | ||||||
|  |                     await provider.signIn(); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|         } catch (err) { |         } catch (err) { | ||||||
|             console.error(err); |             console.error('Error during sign-in:', err); | ||||||
|             throw err; |             throw err; | ||||||
|  |         } finally { | ||||||
|  |             startSignIn.set(false); | ||||||
|         } |         } | ||||||
|     } else { |     } else { | ||||||
|         throw new Error("Cannot sign in with Google in a non-browser environment."); |         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 signedMessages = writable([]) | ||||||
|  |  | ||||||
|  | export const redirectStore = writable(false); | ||||||
|  |  | ||||||
| export const googleSession = writable({ | export const googleSession = writable({ | ||||||
|     activeSession: false |     activeSession: false | ||||||
|   }); |   }); | ||||||
| @@ -7,8 +7,6 @@ | |||||||
|   import { onMount } from "svelte"; |   import { onMount } from "svelte"; | ||||||
|   import { initChainProvider } from "$lib/setupChainProvider"; |   import { initChainProvider } from "$lib/setupChainProvider"; | ||||||
|   import { googleSession } from "$lib/stores.js"; |   import { googleSession } from "$lib/stores.js"; | ||||||
|   import GooglePKP from "$lib/GooglePKP.svelte"; |  | ||||||
|   import GoogleSession from "$lib/GoogleSession.svelte"; |  | ||||||
|   import Wallet from "$lib/Wallet.svelte"; |   import Wallet from "$lib/Wallet.svelte"; | ||||||
|  |  | ||||||
|   let activeSession = false; |   let activeSession = false; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user