temporary refactor of sign in stateflow

This commit is contained in:
Samuel Andert 2023-09-01 14:11:27 +02:00
parent 879f7aad3f
commit 24b83ec99e
11 changed files with 270 additions and 111 deletions

View File

@ -46,6 +46,7 @@
"@wagmi/core": "^1.3.9", "@wagmi/core": "^1.3.9",
"@wundergraph/sdk": "^0.174.5", "@wundergraph/sdk": "^0.174.5",
"@wundergraph/svelte-query": "^0.3.10", "@wundergraph/svelte-query": "^0.3.10",
"@xstate/svelte": "^2.1.0",
"axios": "^1.4.0", "axios": "^1.4.0",
"cookie": "^0.5.0", "cookie": "^0.5.0",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
@ -57,7 +58,8 @@
"node-jose": "^2.2.0", "node-jose": "^2.2.0",
"path": "^0.12.7", "path": "^0.12.7",
"svelte-kit-cookie-session": "^4.0.0", "svelte-kit-cookie-session": "^4.0.0",
"url": "^0.11.1" "url": "^0.11.1",
"xstate": "^4.38.2"
}, },
"type": "module" "type": "module"
} }

View File

@ -40,6 +40,9 @@ dependencies:
'@wundergraph/svelte-query': '@wundergraph/svelte-query':
specifier: ^0.3.10 specifier: ^0.3.10
version: 0.3.10(@tanstack/svelte-query@4.29.1)(@wundergraph/sdk@0.174.5)(svelte@3.54.0) version: 0.3.10(@tanstack/svelte-query@4.29.1)(@wundergraph/sdk@0.174.5)(svelte@3.54.0)
'@xstate/svelte':
specifier: ^2.1.0
version: 2.1.0(svelte@3.54.0)(xstate@4.38.2)
axios: axios:
specifier: ^1.4.0 specifier: ^1.4.0
version: 1.4.0 version: 1.4.0
@ -76,6 +79,9 @@ dependencies:
url: url:
specifier: ^0.11.1 specifier: ^0.11.1
version: 0.11.1 version: 0.11.1
xstate:
specifier: ^4.38.2
version: 4.38.2
devDependencies: devDependencies:
'@fontsource/fira-mono': '@fontsource/fira-mono':
@ -5390,6 +5396,22 @@ packages:
- supports-color - supports-color
dev: false dev: false
/@xstate/svelte@2.1.0(svelte@3.54.0)(xstate@4.38.2):
resolution: {integrity: sha512-cot553w2v4MdmDLkRBLhEjGO5LlnlPcpZ9RT7jFqpn+h0rpmjtkva6zjIZddPrxEOM6DVHDwzYbpDe+BErElQg==}
peerDependencies:
'@xstate/fsm': ^2.1.0
svelte: ^3.24.1 || ^4
xstate: ^4.38.1
peerDependenciesMeta:
'@xstate/fsm':
optional: true
xstate:
optional: true
dependencies:
svelte: 3.54.0
xstate: 4.38.2
dev: false
/JSONStream@1.3.5: /JSONStream@1.3.5:
resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==}
hasBin: true hasBin: true
@ -12048,6 +12070,10 @@ packages:
optional: true optional: true
dev: false dev: false
/xstate@4.38.2:
resolution: {integrity: sha512-Fba/DwEPDLneHT3tbJ9F3zafbQXszOlyCJyQqqdzmtlY/cwE2th462KK48yaANf98jHlP6lJvxfNtN0LFKXPQg==}
dev: false
/xstream@11.14.0: /xstream@11.14.0:
resolution: {integrity: sha512-1bLb+kKKtKPbgTK6i/BaoAn03g47PpFstlbe1BA+y3pNS/LfvcaghS5BFf9+EE1J+KwSQsEpfJvFN5GqFtiNmw==} resolution: {integrity: sha512-1bLb+kKKtKPbgTK6i/BaoAn03g47PpFstlbe1BA+y3pNS/LfvcaghS5BFf9+EE1J+KwSQsEpfJvFN5GqFtiNmw==}
dependencies: dependencies:

View File

@ -6,6 +6,7 @@
} from "@lit-protocol/lit-auth-client"; } from "@lit-protocol/lit-auth-client";
import type { IRelayPKP } from "@lit-protocol/types"; import type { IRelayPKP } from "@lit-protocol/types";
import Icon from "@iconify/svelte"; import Icon from "@iconify/svelte";
import { mintPkp } from "./mintPkp";
import { createLitSession } from "./createLitSession"; import { createLitSession } from "./createLitSession";
import { connectProvider } from "./setupLit"; import { connectProvider } from "./setupLit";

View File

@ -53,7 +53,7 @@
} }
</script> </script>
{#if myPKP} <!-- {#if myPKP}
<div <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" 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"
> >
@ -82,4 +82,4 @@
</button> </button>
</div> </div>
</div> </div>
{/if} {/if} -->

View File

@ -1,103 +0,0 @@
<script>
let litNodeClient;
litNodeClient.connect();
var authSig = JSON.parse(
'{"sig":"0x18a173d68d2f78cc5c13da0dfe36eec2a293285bee6d42547b9577bf26cdc985660ed3dddc4e75d422366cac07e8a9fc77669b10373bef9c7b8e4280252dfddf1b","derivedVia":"web3.eth.personal.sign","signedMessage":"I am creating an account to use LITs at 2021-08-04T20:14:04.918Z","address":"0xdbd360f30097fb6d938dcc8b7b62854b36160b45"}'
);
var randomPath = () =>
"/" +
Math.random().toString(36).substring(2, 15) +
Math.random().toString(36).substring(2, 15);
var testProvisoningAndSigning = async ({
unifiedAccessControlConditions,
testName,
}) => {
document.getElementById("status").innerText = `Testing ${testName}...`;
document.getElementById(
"humanized"
).innerText = `Humanized: ${await litNodeClient.humanizeAccessControlConditions(
{
unifiedAccessControlConditions,
}
)}`;
var solAuthSig = await litNodeClient.checkAndSignAuthMessage({
chain: "solana",
});
var ethAuthSig = await litNodeClient.checkAndSignAuthMessage({
chain: "ethereum",
});
let resourceId = {
baseUrl: "my-dynamic-content-server.com",
path: randomPath(),
orgId: "",
role: "",
extraData: "",
};
await litNodeClient.saveSigningCondition({
unifiedAccessControlConditions,
authSig: {
solana: solAuthSig,
ethereum: ethAuthSig,
},
resourceId,
});
let jwt = await litNodeClient.getSignedToken({
unifiedAccessControlConditions,
authSig: {
solana: solAuthSig,
ethereum: ethAuthSig,
},
resourceId,
});
console.log("jwt", jwt);
// uncomment this to break the jwt, to test an invalid jwt
// jwt = jwt.replace(/.$/, "3");
const { verified, header, payload } = litNodeClient.verifyJwt({ jwt });
console.log("verified", verified);
console.log("header", header);
console.log("payload", payload);
if (jwt && verified) {
document.getElementById("status").innerText = `${testName}: Success`;
} else {
document.getElementById("status").innerText = `${testName}: Failure`;
}
};
var IsPermittedAction = async () => {
/*
{ contract_address: "0x9e1DDB2499C6834204347F047Ace1ae18E830449", chain: "mumbai", standard_contract_type: "PubkeyRouterAndPermissions", method: "isPermittedAction", parameters: ["0xab9704fbd33d96c0475f6d2f1e6e7ff3497d4eceb10df78d0fcf012ab3b09300", "0x12203577a857f9d58507be2f4a87d969cc582dd00a1d0486281113e68208163cb5e8"], return_value_test: JsonReturnValueTest { comparator: "=", value: "true" } }
*/
var unifiedAccessControlConditions = [
{
conditionType: "evmBasic",
contractAddress: "0x9e1DDB2499C6834204347F047Ace1ae18E830449",
chain: "mumbai",
standardContractType: "PubkeyRouterAndPermissions",
method: "isPermittedAction",
parameters: [
"0xab9704fbd33d96c0475f6d2f1e6e7ff3497d4eceb10df78d0fcf012ab3b09300",
"0x12203577a857f9d58507be2f4a87d969cc582dd00a1d0486281113e68208163cb5e8",
],
returnValueTest: { comparator: "=", value: "true" },
},
];
await testProvisoningEncryptingAndDecrypting({
unifiedAccessControlConditions,
testName: "IsPermittedAction",
});
};
</script>
<br />
<button on:click={IsPermittedAction}>IsPermittedAction</button>
<br />

58
src/lib/Wallet.svelte Normal file
View File

@ -0,0 +1,58 @@
<script>
import { useMachine } from "@xstate/svelte";
import walletMachine from "./machines/walletMachine";
import { onMount } from "svelte";
const { state, send } = useMachine(walletMachine);
$: {
if ($state.context.pkps && $state.context.sessionSigs) {
localStorage.setItem(
"me",
JSON.stringify({
pkps: $state.context.pkps,
sessionSigs: $state.context.sessionSigs,
})
);
}
}
onMount(() => {
const me = JSON.parse(localStorage.getItem("me"));
if (me && me.pkps && me.sessionSigs) {
send({ type: "RELOAD", ...me });
}
});
</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}
</p>
</div>
</div>
{/each}
</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}

View File

@ -0,0 +1,99 @@
// src/lib/machines/walletMachine.ts
import { createMachine, assign } from 'xstate';
import { signInWithGoogle } from '../services/signInWithGoogle';
import { createSession } from '../services/createSession';
const walletMachine = createMachine({
id: 'wallet',
initial: 'signIn',
context: {
provider: null,
providerName: null,
authMethod: null,
pkps: [],
sessionSigs: null
},
states: {
signIn: {
on: {
RELOAD: {
target: 'sessionAvailable',
actions: assign({
pkps: (_, event) => event.pkps,
sessionSigs: (_, event) => event.sessionSigs,
}),
},
},
invoke: {
src: 'signInWithGoogle',
onDone: {
target: 'authenticated',
actions: assign({
providerName: (_, event) => event.data.providerName,
provider: (_, event) => event.data.provider,
authMethod: (_, event) => event.data.authMethod,
}),
},
},
},
authenticated: {
invoke: {
src: async (context) => {
const pkps = await context.provider.fetchPKPsThroughRelayer(context.authMethod);
if (pkps.length === 0) {
const newPKP = await context.provider.mintPKP(context.authMethod);
pkps.push(newPKP);
}
return pkps;
},
onDone: {
target: 'creatingSession',
actions: assign({
pkps: (_, event) => event.data,
}),
},
onError: 'authenticated',
},
},
creatingSession: {
invoke: {
src: async (context) => {
const { pkps, sessionSigs } = await createSession(context.provider, context.authMethod, context.pkps);
return { pkps, sessionSigs };
},
onDone: {
target: 'sessionAvailable',
actions: [
assign({
pkps: (_, event) => event.data.pkps,
sessionSigs: (_, event) => event.data.sessionSigs,
}),
(context) => console.log('Context after creating session:', context), // Debug log
],
},
onError: {
target: 'sessionExpired',
actions: assign({
error: (_, event) => event.data,
}),
},
},
},
sessionAvailable: {
on: {
EXPIRED: {
target: 'sessionExpired',
cond: (context) => context.sessionSigs === null
}
}
},
sessionExpired: {}
},
}, {
services: {
signInWithGoogle,
createSession
},
});
export default walletMachine;

18
src/lib/mintPkp.ts Normal file
View File

@ -0,0 +1,18 @@
import type { IRelayPKP } from '@lit-protocol/types';
import type { IProvider } from '$lib/IProvider';
export async function mintPkp(provider: IProvider, authMethod: any): Promise<IRelayPKP> {
const txHash: string = await provider.mintPKPThroughRelayer(authMethod);
const response = await provider.relay.pollRequestUntilTerminalState(txHash);
if (response.status !== 'Succeeded') {
throw new Error('Minting failed');
}
const newPKP: IRelayPKP = {
tokenId: response.pkpTokenId,
publicKey: response.pkpPublicKey,
ethAddress: response.pkpEthAddress
};
return newPKP;
}

View File

@ -0,0 +1,30 @@
// src/lib/services/createSession.ts
import { createLitSession } from '$lib/createLitSession';
import type { IRelayPKP } from "@lit-protocol/types";
export const createSession = async (provider, authMethod, pkps: IRelayPKP[]) => {
try {
let currentPKP;
if (pkps.length === 0) {
currentPKP = await provider.mintPKP(authMethod);
pkps = [...pkps, currentPKP];
} else {
currentPKP = pkps[0];
}
console.log('Current PKP:', currentPKP); // Debug log
const sessionSigs = await createLitSession(
provider,
currentPKP.publicKey,
authMethod
);
console.log('Session Signatures:', sessionSigs); // Debug log
return { pkps, sessionSigs };
} catch (error) {
console.error('Error in createSession:', error); // Debug log
throw new Error(`Failed to create session: ${error.message}`);
}
};

View File

@ -0,0 +1,25 @@
// src/lib/services/signInWithGoogle.ts
import { connectProvider } from "$lib/setupLit";
import { isSignInRedirect, getProviderFromUrl } from "@lit-protocol/lit-auth-client";
export const signInWithGoogle = async () => {
if (typeof window !== 'undefined') {
try {
let provider = await connectProvider();
if (isSignInRedirect("http://localhost:3000/")) {
const providerName = getProviderFromUrl();
if (providerName) {
const authMethod = await provider.authenticate();
return { authMethod, provider, providerName }; // Return the data
}
} else {
await provider.signIn();
}
} catch (err) {
console.error(err);
throw err;
}
} else {
throw new Error("Cannot sign in with Google in a non-browser environment.");
}
};

View File

@ -7,10 +7,11 @@
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 GoogleSigner from "$lib/GoogleSigner.svelte";
import GooglePKP from "$lib/GooglePKP.svelte"; import GooglePKP from "$lib/GooglePKP.svelte";
import GoogleSession from "$lib/GoogleSession.svelte";
import Wallet from "$lib/Wallet.svelte";
let activeSession = true; let activeSession = false;
export let data: LayoutData; export let data: LayoutData;
@ -34,9 +35,11 @@
style="background-image: url('lake.jpeg');" style="background-image: url('lake.jpeg');"
> >
<QueryClientProvider client={data.queryClient}> <QueryClientProvider client={data.queryClient}>
<div class="text-lg bg-white">{activeSession}</div> <Wallet />
<!-- <GoogleSession />
<div class="text-lg bg-white">{activeSession}</div> -->
<slot /> <slot />
{#if activeSession}active {:else} <GooglePKP /> {/if} <!-- {#if activeSession}active {:else} expired {/if}
<GoogleSigner /> <GooglePKP /> -->
</QueryClientProvider> </QueryClientProvider>
</div> </div>