Compare commits

..

9 Commits

Author SHA1 Message Date
Samuel Andert
293180c2b5 major refactoring adding and finishing xstate signin flow 2023-09-01 17:38:22 +02:00
Samuel Andert
24b83ec99e temporary refactor of sign in stateflow 2023-09-01 14:11:27 +02:00
Samuel Andert
879f7aad3f Work in progress refactor 2023-08-31 19:08:35 +02:00
Samuel Andert
efc2b41f9e updated UI of login flow 2023-08-31 12:54:49 +02:00
Samuel Andert
7652938c74 Added basic Tailwind styling and fixed a active session bug 2023-08-31 11:13:53 +02:00
Samuel Andert
b8012cf9fd Refactored GoogleAuth Signup Flow and added Clear Session 2023-08-31 10:47:08 +02:00
Samuel Andert
978e438854 external triggering of SignRequest 2023-08-30 19:54:57 +02:00
Samuel Andert
9aa3bfc0d2 Added verify signature api service 2023-08-30 12:22:33 +02:00
Samuel Andert
042f9209ed non working LIT jwt 2023-08-30 09:04:58 +02:00
28 changed files with 1522 additions and 318 deletions

View File

@ -21,9 +21,12 @@
"@types/cookie": "^0.5.1", "@types/cookie": "^0.5.1",
"@types/js-cookie": "^3.0.3", "@types/js-cookie": "^3.0.3",
"@types/jsonwebtoken": "^9.0.2", "@types/jsonwebtoken": "^9.0.2",
"autoprefixer": "^10.4.15",
"concurrently": "^7.6.0", "concurrently": "^7.6.0",
"postcss": "^8.4.29",
"svelte": "^3.54.0", "svelte": "^3.54.0",
"svelte-check": "^3.0.1", "svelte-check": "^3.0.1",
"tailwindcss": "^3.3.3",
"tslib": "^2.4.1", "tslib": "^2.4.1",
"typescript": "^5.0.0", "typescript": "^5.0.0",
"vite": "^4.2.0", "vite": "^4.2.0",
@ -32,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",
@ -40,8 +44,10 @@
"@lit-protocol/pkp-client": "^2.2.50", "@lit-protocol/pkp-client": "^2.2.50",
"@lit-protocol/types": "^2.2.50", "@lit-protocol/types": "^2.2.50",
"@tanstack/svelte-query": "^4.29.1", "@tanstack/svelte-query": "^4.29.1",
"@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",
@ -52,7 +58,9 @@
"jwks-rsa": "^3.0.1", "jwks-rsa": "^3.0.1",
"node-jose": "^2.2.0", "node-jose": "^2.2.0",
"path": "^0.12.7", "path": "^0.12.7",
"url": "^0.11.1" "svelte-kit-cookie-session": "^4.0.0",
"url": "^0.11.1",
"xstate": "^4.38.2"
}, },
"type": "module" "type": "module"
} }

File diff suppressed because it is too large Load Diff

6
postcss.config.js Normal file
View File

@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

3
src/app.css Normal file
View File

@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

17
src/app.d.ts vendored
View File

@ -1,12 +1,23 @@
import type { Session } from 'svelte-kit-cookie-session';
type SessionData = {
views: number;
};
// See https://kit.svelte.dev/docs/types#app // See https://kit.svelte.dev/docs/types#app
// for information about these interfaces // for information about these interfaces
declare global { declare global {
namespace App { namespace App {
// interface Error {} // interface Error {}
// interface Locals {} interface Locals {
// interface PageData {} session: Session<SessionData>;
}
interface PageData {
// can add any properties here, return it from your root layout
session: SessionData;
}
// interface Platform {} // interface Platform {}
} }
} }
export {}; export { };

5
src/hooks.server.ts Normal file
View File

@ -0,0 +1,5 @@
import { handleSession } from 'svelte-kit-cookie-session';
export const handle = handleSession({
secret: 'SOME_COMPLEX_SECRET_32_CHARSLONG'
});

View File

@ -1,179 +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 Signer from "./Signer.svelte";
const redirectUri = "http://localhost:3000/";
let sessionSigs = null;
let error, currentPKP, authMethod, provider;
let status = "Initializing...";
let pkps: IRelayPKP[] = [];
let view = "SIGN_IN";
let sessionStatuses;
let activeSession = null;
let messageToSign = { user: "Sam", loggedIn: true };
onMount(async () => {
// Load activeSession from local storage
const storedSession = localStorage.getItem("google-session");
const storedPKP = localStorage.getItem("current-pkp");
if (storedSession && storedPKP) {
activeSession = JSON.parse(storedSession);
currentPKP = JSON.parse(storedPKP);
view = "READY";
}
initialize();
});
$: if (sessionSigs) {
// Store sessionSigs in local storage in its original format
localStorage.setItem("google-session", JSON.stringify(sessionSigs));
// Update sessionStatuses
sessionStatuses = Object.entries(sessionSigs).map(([node, data]) => {
const sessionKey = JSON.parse(data.signedMessage).sessionKey;
const expiration = new Date(JSON.parse(data.signedMessage).expiration);
const isExpired = expiration < new Date();
return {
node,
sessionKey,
expiration: expiration.toISOString(),
isExpired,
};
});
// Find an active session
activeSession = sessionStatuses.find(({ isExpired }) => !isExpired);
view = "READY";
}
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) {
setError(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) {
setError(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) {
setError(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-signature", JSON.stringify(sessionSigs));
localStorage.setItem("current-pkp", JSON.stringify(currentPKP));
});
status = "Session created successfully.";
} catch (err) {
setError(err);
}
}
function setError(err) {
error = err;
view = "ERROR";
status = `Error: ${err.message}`;
}
</script>
<div class="flex items-center justify-center h-screen">
<div>
{#if error}
<div class="mt-4 text-center">
<h1>Error</h1>
<p>{error.message}</p>
</div>
{:else 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>
Signer
<Signer {messageToSign} />
Sessions
{/if}
<div class="mt-4 text-center">
<p>{status}</p>
</div>
{#if activeSession}
<div>
<h3>Active Session:</h3>
<p>Node: {activeSession.node}</p>
<p>Session Key: {activeSession.sessionKey}</p>
<p>Expiration: {activeSession.expiration}</p>
</div>
{#if sessionStatuses}
{#each sessionStatuses as { node, sessionKey, expiration, isExpired }}
<p>
{isExpired ? "🔴" : "🟢"} Node: {node}, Session Key: {sessionKey},
Expiration: {expiration}
</p>
{/each}
{/if}
{/if}
</div>
</div>

View File

@ -2,7 +2,17 @@
import Cookies from "js-cookie"; import Cookies from "js-cookie";
async function login() { async function login() {
const response = await fetch("/api/auth", { method: "POST" }); const response = await fetch("/api/auth", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Sam",
loggedIn: true,
roles: ["admin"],
}),
});
if (!response.ok) { if (!response.ok) {
alert("Login failed"); alert("Login failed");
} else { } else {

View File

@ -1,106 +0,0 @@
<!-- SignVerifyMessage.svelte -->
<script lang="ts">
import { ethers } from "ethers";
import { onMount } from "svelte";
export 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);
}
});
export 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,
});
// Display the signed JSON
status = JSON.stringify(messageToSign, null, 2);
// Verify the signature
const recoveredAddr = ethers.verifyMessage(jsonString, messageSignature);
// Check if the address associated with the signature is the same as the current PKP
const verified =
currentPKP.ethAddress.toLowerCase() === recoveredAddr.toLowerCase();
if (verified) {
status = "The signature is valid.";
} else {
status = "The signature is invalid.";
}
} catch (err) {
console.error(err);
}
}
</script>
<button on:click={signMessageWithPKP}>Sign Message</button>
{#if messageToSign}
<pre>{JSON.stringify(messageToSign)}</pre>
{/if}
{#if status}
<div class="mt-4 text-center">
<p>Status: {status}</p>
</div>
{/if}
{#if messageSignature}
<div class="mt-4 text-center">
<h3>Signature</h3>
<pre>{JSON.stringify(messageSignature)}</pre>
</div>
{/if}

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

@ -0,0 +1,89 @@
<script>
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(
"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 });
}
});
async function startSignIn() {
startSignInService.set(true);
await signInWithGoogle();
}
function clearSession() {
send("LOGOUT");
}
</script>
{#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>
<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>
{/if}

View File

@ -0,0 +1,116 @@
// src/lib/machines/walletMachine.ts
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',
initial: 'signIn',
context: {
provider: null,
providerName: null,
authMethod: null,
pkps: [],
sessionSigs: null,
redirect: false
},
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 && 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 = '/';
}
}
}
},
},
}, {
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,38 @@
// 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/")) {
providerName = getProviderFromUrl();
if (providerName) {
const authMethod = await provider.authenticate();
return { authMethod, provider, providerName };
}
} else {
let shouldStartSignIn = false;
startSignIn.subscribe(value => {
shouldStartSignIn = value;
});
if (!providerName && shouldStartSignIn) {
await provider.signIn();
}
}
} catch (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.");
}
};

View File

@ -0,0 +1,58 @@
import { configureChains, createConfig } from '@wagmi/core';
import { gnosis } from '@wagmi/core/chains';
import { publicProvider } from '@wagmi/core/providers/public';
import { InjectedConnector } from '@wagmi/core/connectors/injected';
import { jsonRpcProvider } from '@wagmi/core/providers/jsonRpc';
// const chronicleChain = {
// id: 175177,
// name: 'Chronicle',
// network: 'chronicle',
// nativeCurrency: {
// decimals: 18,
// name: 'Chronicle - Lit Protocol Testnet',
// symbol: 'LIT'
// },
// rpcUrls: {
// default: {
// http: ['https://chain-rpc.litprotocol.com/http']
// },
// public: {
// http: ['https://chain-rpc.litprotocol.com/http']
// }
// },
// blockExplorers: {
// default: {
// name: 'Chronicle - Lit Protocol Testnet',
// url: 'https://chain.litprotocol.com'
// }
// },
// testnet: true
// };
export function initChainProvider() {
const { chains, publicClient } = configureChains(
[gnosis],
[
jsonRpcProvider({
rpc: (chain) => ({ http: chain.rpcUrls.default.http[0] })
}),
jsonRpcProvider({
rpc: () => ({
http: `https://rpc.ankr.com/gnosis`,
wss: `wss://rpc.gnosischain.com/wss`
})
}),
publicProvider()
]
);
createConfig({
autoConnect: true,
connectors: [
new InjectedConnector({ chains }),
],
publicClient
});
}

11
src/lib/stores.js Normal file
View File

@ -0,0 +1,11 @@
import { writable } from 'svelte/store';
export const signRequest = writable({json: {}});
export const signedMessages = writable([])
export const redirectStore = writable(false);
export const googleSession = writable({
activeSession: false
});

View File

@ -1,18 +1,43 @@
<script lang="ts"> <script lang="ts">
import "../app.css";
import { QueryClientProvider } from "@tanstack/svelte-query"; import { QueryClientProvider } from "@tanstack/svelte-query";
import type { LayoutData } from "./$types"; import type { LayoutData } from "./$types";
import { client } from "$lib/wundergraph"; import { client } from "$lib/wundergraph";
import Cookies from "js-cookie"; import Cookies from "js-cookie";
import { onMount } from "svelte";
import { initChainProvider } from "$lib/setupChainProvider";
import { googleSession } from "$lib/stores.js";
import Wallet from "$lib/Wallet.svelte";
let activeSession = false;
export let data: LayoutData; export let data: LayoutData;
const token = Cookies.get("token"); const token = Cookies.get("token");
googleSession.subscribe((value) => {
activeSession = value.activeSession;
});
onMount(() => {
initChainProvider();
});
if (token) { if (token) {
client.setAuthorizationToken(token); client.setAuthorizationToken(token);
} }
</script> </script>
<QueryClientProvider client={data.queryClient}> <div
<slot /> class="flex items-center justify-center h-screen bg-cover bg-center"
</QueryClientProvider> style="background-image: url('lake.jpeg');"
>
<QueryClientProvider client={data.queryClient}>
<Wallet />
<!-- <GoogleSession />
<div class="text-lg bg-white">{activeSession}</div> -->
<slot />
<!-- {#if activeSession}active {:else} expired {/if}
<GooglePKP /> -->
</QueryClientProvider>
</div>

View File

@ -10,6 +10,5 @@ export const load: LayoutLoad = async () => {
}, },
}, },
}); });
return { queryClient }; return { queryClient };
}; };

View File

@ -0,0 +1,10 @@
import type { ServerLoad } from '@sveltejs/kit';
export const load: ServerLoad = async ({ locals }) => {
await locals.session.set({ myPKP: "hello1" });
return {
myPKP: locals.session.data.myPKP
};
};

View File

@ -1,5 +1,14 @@
<script> <script lang="ts">
import GoogleAuth from "$lib/GoogleAuth.svelte"; // import { signRequest } from "$lib/stores.js";
// function trigger() {
// signRequest.set({ json: { hello: "test" } });
// }
// import type { PageData } from "./$types";
// export let data: PageData;
</script> </script>
<GoogleAuth /> <!-- <div class="bg-white">myPKP {data.myPKP}</div> -->
<!-- <button on:click={trigger}>Sign Request</button> -->

View File

@ -1,10 +1,11 @@
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
import { error } from '@sveltejs/kit'; import { error } from '@sveltejs/kit';
const secretKey = 'mysecrettestkey'; const secretKey = process.env.JWT_KEY;
export async function POST() { export async function POST({ request }) {
const token = jwt.sign({ name: 'Samuel', loggedIn: true, roles: ['admin'] }, secretKey); const user = await request.json();
const token = jwt.sign(user, secretKey);
if (!token) { if (!token) {
throw error(400, 'No token created.'); throw error(400, 'No token created.');
} }

View File

@ -2,7 +2,7 @@
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
import { error } from '@sveltejs/kit'; import { error } from '@sveltejs/kit';
const secretKey = 'mysecrettestkey'; const secretKey = process.env.JWT_KEY;
export async function GET({ request }) { export async function GET({ request }) {
const authHeader = request.headers.get('Authorization'); const authHeader = request.headers.get('Authorization');

View File

@ -0,0 +1,13 @@
import jwt from 'jsonwebtoken';
import { error } from '@sveltejs/kit';
const secretKey = process.env.JWT_KEY;
export async function POST({ request }) {
const user = await request.json();
const token = jwt.sign(user, secretKey);
if (!token) {
throw error(400, 'No token created.');
}
return new Response(JSON.stringify({ token }), { status: 200 });
}

View File

@ -0,0 +1,15 @@
import { json } from '@sveltejs/kit';
import { ethers } from 'ethers';
export async function POST({ request }) {
const { messageToSign, messageSignature, currentPKP } = await request.json();
// Verify the signature
const jsonString = JSON.stringify(messageToSign);
const recoveredAddr = ethers.verifyMessage(jsonString, messageSignature);
// Check if the address associated with the signature is the same as the current PKP
const verified = currentPKP.ethAddress.toLowerCase() === recoveredAddr.toLowerCase();
return json({ verified }, { status: 200 });
}

BIN
static/lake.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

View File

@ -13,6 +13,7 @@ const config = {
// See https://kit.svelte.dev/docs/adapters for more information about adapters. // See https://kit.svelte.dev/docs/adapters for more information about adapters.
adapter: adapter(), adapter: adapter(),
}, },
}; };
export default config; export default config;

9
tailwind.config.js Normal file
View File

@ -0,0 +1,9 @@
/** @type {import('tailwindcss').Config} */
export default {
content: ['./src/**/*.{html,js,svelte,ts}'],
theme: {
extend: {},
},
plugins: [],
}

View File

@ -1,6 +1,7 @@
import { sveltekit } from '@sveltejs/kit/vite'; import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite'; import { defineConfig } from 'vite';
import { fetchSchema } from './.wundergraph/schemas/fetch-schemas'; import { fetchSchemas } from './.wundergraph/schemas/fetch-schemas';
import { vitePreprocess } from '@sveltejs/kit/vite';
export default defineConfig({ export default defineConfig({
plugins: [ plugins: [