diff --git a/web/.env.devnet-neo.public b/web/.env.devnet-neo.public index 805e1dea6..c1a2d7d2d 100644 --- a/web/.env.devnet-neo.public +++ b/web/.env.devnet-neo.public @@ -6,6 +6,7 @@ export REACT_APP_STATUS_URL=https://kleros-v2-devnet.betteruptime.com/badge export REACT_APP_GENESIS_BLOCK_ARBSEPOLIA=3084598 export REACT_APP_DEVTOOLS_URL=https://dev--kleros-v2-neo-devtools.netlify.app export REACT_APP_ARBITRATOR_TYPE=neo +export REACT_APP_ATLAS_URI=http://localhost:3000 export WALLETCONNECT_PROJECT_ID= export ALCHEMY_API_KEY= export NODE_OPTIONS='--max-old-space-size=7680' diff --git a/web/.env.devnet-university.public b/web/.env.devnet-university.public index fb26be0b6..1e167ec4b 100644 --- a/web/.env.devnet-university.public +++ b/web/.env.devnet-university.public @@ -5,6 +5,7 @@ export REACT_APP_DRT_ARBSEPOLIA_SUBGRAPH=https://api.studio.thegraph.com/query/6 export REACT_APP_STATUS_URL=https://kleros-v2-devnet.betteruptime.com/badge export REACT_APP_GENESIS_BLOCK_ARBSEPOLIA=3084598 export REACT_APP_ARBITRATOR_TYPE=university +export REACT_APP_ATLAS_URI=http://localhost:3000 export WALLETCONNECT_PROJECT_ID= export ALCHEMY_API_KEY= export NODE_OPTIONS='--max-old-space-size=7680' diff --git a/web/.env.devnet.public b/web/.env.devnet.public index cbcd5b218..6422335a8 100644 --- a/web/.env.devnet.public +++ b/web/.env.devnet.public @@ -4,6 +4,7 @@ export REACT_APP_CORE_SUBGRAPH=https://api.studio.thegraph.com/query/61738/klero export REACT_APP_DRT_ARBSEPOLIA_SUBGRAPH=https://api.studio.thegraph.com/query/61738/kleros-v2-drt-arbisep-devnet/version/latest export REACT_APP_STATUS_URL=https://kleros-v2-devnet.betteruptime.com/badge export REACT_APP_GENESIS_BLOCK_ARBSEPOLIA=3084598 +export REACT_APP_ATLAS_URI=http://localhost:3000 export REACT_APP_DEVTOOLS_URL=https://dev--kleros-v2-testnet-devtools.netlify.app export WALLETCONNECT_PROJECT_ID= export ALCHEMY_API_KEY= diff --git a/web/.env.local.public b/web/.env.local.public index 3128b605e..b5a5cdd43 100644 --- a/web/.env.local.public +++ b/web/.env.local.public @@ -2,6 +2,7 @@ export REACT_APP_DEPLOYMENT=devnet export REACT_APP_CORE_SUBGRAPH=http://localhost:8000/subgraphs/name/kleros/kleros-v2-core-local export REACT_APP_DRT_ARBSEPOLIA_SUBGRAPH=https://api.thegraph.com/subgraphs/name/alcercu/templateregistrydevnet +export REACT_APP_ATLAS_URI=http://localhost:3000 export WALLETCONNECT_PROJECT_ID= export ALCHEMY_API_KEY= export NODE_OPTIONS='--max-old-space-size=7680' diff --git a/web/.env.mainnet-neo.public b/web/.env.mainnet-neo.public index d5baa5c86..de5c58216 100644 --- a/web/.env.mainnet-neo.public +++ b/web/.env.mainnet-neo.public @@ -6,6 +6,7 @@ export REACT_APP_STATUS_URL=https://kleros-v2-devnet.betteruptime.com/badge export REACT_APP_GENESIS_BLOCK_ARBMAINNET=190274403 export REACT_APP_DEVTOOLS_URL=https://devtools.v2.kleros.builders export REACT_APP_ARBITRATOR_TYPE=neo +export REACT_APP_ATLAS_URI=http://localhost:3000 export WALLETCONNECT_PROJECT_ID= export ALCHEMY_API_KEY= export NODE_OPTIONS='--max-old-space-size=7680' \ No newline at end of file diff --git a/web/.env.testnet.public b/web/.env.testnet.public index e7fdd7f6f..b6bd4e057 100644 --- a/web/.env.testnet.public +++ b/web/.env.testnet.public @@ -3,6 +3,7 @@ export REACT_APP_DEPLOYMENT=testnet export REACT_APP_CORE_SUBGRAPH=https://api.studio.thegraph.com/query/61738/kleros-v2-core-testnet/version/latest export REACT_APP_DRT_ARBSEPOLIA_SUBGRAPH=https://api.studio.thegraph.com/query/61738/kleros-v2-drt-arbisep-devnet/version/latest export REACT_APP_STATUS_URL=https://kleros-v2.betteruptime.com/badge +export REACT_APP_ATLAS_URI=http://localhost:3000 export REACT_APP_GENESIS_BLOCK_ARBSEPOLIA=3842783 export REACT_APP_DEVTOOLS_URL=https://devtools.v2-testnet.kleros.builders export WALLETCONNECT_PROJECT_ID= diff --git a/web/netlify/functions/authUser.ts b/web/netlify/functions/authUser.ts deleted file mode 100644 index 8c4b18cd3..000000000 --- a/web/netlify/functions/authUser.ts +++ /dev/null @@ -1,117 +0,0 @@ -import middy from "@middy/core"; -import jsonBodyParser from "@middy/http-json-body-parser"; -import { createClient } from "@supabase/supabase-js"; -import { ethers } from "ethers"; -import * as jwt from "jose"; -import { SiweMessage } from "siwe"; - -import { ETH_SIGNATURE_REGEX, DEFAULT_CHAIN, isProductionDeployment } from "consts/processEnvConsts"; - -import { netlifyUri, netlifyDeployUri, netlifyDeployPrimeUri } from "src/generatedNetlifyInfo.json"; -import { Database } from "src/types/supabase-notification"; - -const authUser = async (event) => { - try { - if (!event.body) { - throw new Error("No body provided"); - } - - const signature = event?.body?.signature; - if (!signature) { - throw new Error("Missing key : signature"); - } - - if (!ETH_SIGNATURE_REGEX.test(signature)) { - throw new Error("Invalid signature"); - } - - const message = event?.body?.message; - if (!message) { - throw new Error("Missing key : message"); - } - - const address = event?.body?.address; - if (!address) { - throw new Error("Missing key : address"); - } - - const siweMessage = new SiweMessage(message); - - if ( - !( - (netlifyUri && netlifyUri === siweMessage.uri) || - (netlifyDeployUri && netlifyDeployUri === siweMessage.uri) || - (netlifyDeployPrimeUri && netlifyDeployPrimeUri === siweMessage.uri) - ) - ) { - console.debug( - `Invalid URI: expected one of [${netlifyUri} ${netlifyDeployUri} ${netlifyDeployPrimeUri}] but got ${siweMessage.uri}` - ); - throw new Error(`Invalid URI`); - } - - if (siweMessage.chainId !== DEFAULT_CHAIN) { - console.debug(`Invalid chain ID: expected ${DEFAULT_CHAIN} but got ${siweMessage.chainId}`); - throw new Error(`Invalid chain ID`); - } - - const lowerCaseAddress = siweMessage.address.toLowerCase(); - if (lowerCaseAddress !== address.toLowerCase()) { - throw new Error("Address mismatch in provided address and message"); - } - - const supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_CLIENT_API_KEY!); - - // get nonce from db, if its null that means it was already used - const { error: nonceError, data: nonceData } = await supabase - .from("user-nonce") - .select("nonce") - .eq("address", lowerCaseAddress) - .single(); - - if (nonceError || !nonceData?.nonce) { - throw new Error("Unable to fetch nonce from DB"); - } - - try { - // If the main Alchemy API key is permissioned, it won't work in a Netlify Function so we use a dedicated API key - const alchemyApiKey = process.env.ALCHEMY_FUNCTIONS_API_KEY ?? process.env.ALCHEMY_API_KEY; - const alchemyChain = isProductionDeployment() ? "arb-mainnet" : "arb-sepolia"; - const alchemyRpcURL = `https://${alchemyChain}.g.alchemy.com/v2/${alchemyApiKey}`; - const provider = new ethers.providers.JsonRpcProvider(alchemyRpcURL); - await siweMessage.verify({ signature, nonce: nonceData.nonce, time: new Date().toISOString() }, { provider }); - } catch (err) { - throw new Error("Invalid signer: " + JSON.stringify(err)); - } - - const { error } = await supabase.from("user-nonce").delete().match({ address: lowerCaseAddress }); - - if (error) { - throw new Error("Error updating nonce in DB"); - } - - const issuer = process.env.JWT_ISSUER ?? "Kleros"; // ex :- Kleros - const audience = process.env.JWT_AUDIENCE ?? "Court"; // ex :- Court, Curate, Escrow - const authExp = process.env.JWT_EXP_TIME ?? "2h"; - const secret = process.env.JWT_SECRET; - - if (!secret) { - throw new Error("Secret not set in environment"); - } - // user verified, generate auth token - const encodedSecret = new TextEncoder().encode(secret); - - const token = await new jwt.SignJWT({ id: address.toLowerCase() }) - .setProtectedHeader({ alg: "HS256" }) - .setIssuer(issuer) - .setAudience(audience) - .setExpirationTime(authExp) - .sign(encodedSecret); - - return { statusCode: 200, body: JSON.stringify({ message: "User authorised", token }) }; - } catch (err) { - return { statusCode: 500, body: JSON.stringify({ message: `${err}` }) }; - } -}; - -export const handler = middy(authUser).use(jsonBodyParser()); diff --git a/web/netlify/functions/fetch-settings.ts b/web/netlify/functions/fetch-settings.ts deleted file mode 100644 index 73a4d04ad..000000000 --- a/web/netlify/functions/fetch-settings.ts +++ /dev/null @@ -1,33 +0,0 @@ -import middy from "@middy/core"; -import { createClient } from "@supabase/supabase-js"; - -import { Database } from "../../src/types/supabase-notification"; -import { authMiddleware } from "../middleware/authMiddleware"; - -const fetchSettings = async (event) => { - try { - const address = event.auth.id; - const lowerCaseAddress = address.toLowerCase() as `0x${string}`; - - const supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_CLIENT_API_KEY!); - - const { error, data } = await supabase - .from("user-settings") - .select("address, email, telegram") - .eq("address", lowerCaseAddress) - .single(); - - if (!data) { - return { statusCode: 404, message: `Error : User not found` }; - } - - if (error) { - throw error; - } - return { statusCode: 200, body: JSON.stringify({ data }) }; - } catch (err) { - return { statusCode: 500, message: `Error ${err?.message ?? err}` }; - } -}; - -export const handler = middy(fetchSettings).use(authMiddleware()); diff --git a/web/netlify/functions/getNonce.ts b/web/netlify/functions/getNonce.ts deleted file mode 100644 index 9219c5eab..000000000 --- a/web/netlify/functions/getNonce.ts +++ /dev/null @@ -1,50 +0,0 @@ -import middy from "@middy/core"; -import { createClient } from "@supabase/supabase-js"; -import { generateNonce } from "siwe"; - -import { ETH_ADDRESS_REGEX } from "consts/processEnvConsts"; - -import { Database } from "src/types/supabase-notification"; - -const getNonce = async (event) => { - try { - const { queryStringParameters } = event; - - if (!queryStringParameters?.address) { - return { - statusCode: 400, - body: JSON.stringify({ message: "Invalid query parameters" }), - }; - } - - const { address } = queryStringParameters; - - if (!ETH_ADDRESS_REGEX.test(address)) { - throw new Error("Invalid Ethereum address format"); - } - - const lowerCaseAddress = address.toLowerCase() as `0x${string}`; - - const supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_CLIENT_API_KEY!); - - // generate nonce and save in db - const nonce = generateNonce(); - - const { error } = await supabase - .from("user-nonce") - .upsert({ address: lowerCaseAddress, nonce: nonce }) - .eq("address", lowerCaseAddress); - - if (error) { - throw error; - } - - return { statusCode: 200, body: JSON.stringify({ nonce }) }; - } catch (err) { - console.log(err); - - return { statusCode: 500, message: `Error ${err?.message ?? err}` }; - } -}; - -export const handler = middy(getNonce); diff --git a/web/netlify/functions/update-settings.ts b/web/netlify/functions/update-settings.ts deleted file mode 100644 index 4a30dddd3..000000000 --- a/web/netlify/functions/update-settings.ts +++ /dev/null @@ -1,92 +0,0 @@ -import middy from "@middy/core"; -import jsonBodyParser from "@middy/http-json-body-parser"; -import { createClient } from "@supabase/supabase-js"; - -import { EMAIL_REGEX, TELEGRAM_REGEX, ETH_ADDRESS_REGEX } from "consts/processEnvConsts"; - -import { Database } from "src/types/supabase-notification"; - -import { authMiddleware } from "../middleware/authMiddleware"; - -type NotificationSettings = { - email?: string; - telegram?: string; - address: `0x${string}`; -}; - -const validate = (input: any): NotificationSettings => { - const requiredKeys: (keyof NotificationSettings)[] = ["address"]; - const optionalKeys: (keyof NotificationSettings)[] = ["email", "telegram"]; - const receivedKeys = Object.keys(input); - - for (const key of requiredKeys) { - if (!receivedKeys.includes(key)) { - throw new Error(`Missing key: ${key}`); - } - } - - const allExpectedKeys = [...requiredKeys, ...optionalKeys]; - for (const key of receivedKeys) { - if (!allExpectedKeys.includes(key as keyof NotificationSettings)) { - throw new Error(`Unexpected key: ${key}`); - } - } - - const email = input.email ? input.email.trim() : ""; - if (email && !EMAIL_REGEX.test(email)) { - throw new Error("Invalid email format"); - } - - const telegram = input.telegram ? input.telegram.trim() : ""; - if (telegram && !TELEGRAM_REGEX.test(telegram)) { - throw new Error("Invalid Telegram username format"); - } - - if (!ETH_ADDRESS_REGEX.test(input.address)) { - throw new Error("Invalid Ethereum address format"); - } - - return { - email: input.email?.trim(), - telegram: input.telegram?.trim(), - address: input.address.trim().toLowerCase(), - }; -}; - -const updateSettings = async (event) => { - try { - if (!event.body) { - throw new Error("No body provided"); - } - - const { email, telegram, address } = validate(event.body); - const lowerCaseAddress = address.toLowerCase() as `0x${string}`; - - // Prevent using someone else's token - if (event?.auth?.id.toLowerCase() !== lowerCaseAddress) { - throw new Error("Unauthorised user"); - } - const supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_CLIENT_API_KEY!); - - // If the message is empty, delete the user record - if (email === "" && telegram === "") { - const { error } = await supabase.from("user-settings").delete().match({ address: lowerCaseAddress }); - if (error) throw error; - return { statusCode: 200, body: JSON.stringify({ message: "Record deleted successfully." }) }; - } - - // For a user matching this address, upsert the user record - const { error } = await supabase - .from("user-settings") - .upsert({ address: lowerCaseAddress, email: email, telegram: telegram }) - .match({ address: lowerCaseAddress }); - if (error) { - throw error; - } - return { statusCode: 200, body: JSON.stringify({ message: "Record updated successfully." }) }; - } catch (err) { - return { statusCode: 500, body: JSON.stringify({ message: `${err}` }) }; - } -}; - -export const handler = middy(updateSettings).use(jsonBodyParser()).use(authMiddleware()); diff --git a/web/netlify/functions/uploadToIPFS.ts b/web/netlify/functions/uploadToIPFS.ts deleted file mode 100644 index e59ccfcb7..000000000 --- a/web/netlify/functions/uploadToIPFS.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { File, FilebaseClient } from "@filebase/client"; -import middy from "@middy/core"; -import amqp, { Connection } from "amqplib"; -import busboy from "busboy"; - -import { authMiddleware } from "../middleware/authMiddleware"; - -const { FILEBASE_TOKEN, RABBITMQ_URL } = process.env; -const filebase = new FilebaseClient({ token: FILEBASE_TOKEN ?? "" }); - -type FormElement = - | { isFile: true; filename: string; mimeType: string; content: Buffer } - | { isFile: false; content: string }; -type FormData = { [key: string]: FormElement }; - -const emitRabbitMQLog = async (cid: string, operation: string) => { - let connection: Connection | undefined; - try { - connection = await amqp.connect(RABBITMQ_URL ?? ""); - const channel = await connection.createChannel(); - - await channel.assertExchange("ipfs", "topic"); - channel.publish("ipfs", operation, Buffer.from(cid)); - - //eslint-disable-next-line no-console - console.log(`Sent IPFS CID '${cid}' to exchange 'ipfs'`); - } catch (err) { - console.warn(err); - } finally { - if (typeof connection !== "undefined") await connection.close(); - } -}; - -const parseMultipart = ({ headers, body, isBase64Encoded }) => - new Promise((resolve, reject) => { - const fields: FormData = {}; - - const bb = busboy({ headers }); - - bb.on("file", (name, file, { filename, mimeType }) => - file.on("data", (content) => { - fields[name] = { isFile: true, filename, mimeType, content }; - }) - ) - .on("field", (name, value) => { - if (value) fields[name] = { isFile: false, content: value }; - }) - .on("close", () => resolve(fields)) - .on("error", (err) => reject(err)); - - bb.write(body, isBase64Encoded ? "base64" : "binary"); - bb.end(); - }); - -const pinToFilebase = async (data: FormData, operation: string): Promise> => { - const cids = new Array(); - for (const [_, dataElement] of Object.entries(data)) { - if (dataElement.isFile) { - const { filename, mimeType, content } = dataElement; - const path = `${filename}`; - const cid = await filebase.storeDirectory([new File([content], path, { type: mimeType })]); - await emitRabbitMQLog(cid, operation); - cids.push(`ipfs://${cid}/${path}`); - } - } - - return cids; -}; - -export const uploadToIPFS = async (event) => { - const { queryStringParameters } = event; - - if (!queryStringParameters?.operation) { - return { - statusCode: 400, - body: JSON.stringify({ message: "Invalid query parameters" }), - }; - } - - const { operation } = queryStringParameters; - - try { - const parsed = await parseMultipart(event); - const cids = await pinToFilebase(parsed, operation); - - return { - statusCode: 200, - body: JSON.stringify({ - message: "File has been stored successfully", - cids, - }), - }; - } catch (err: any) { - return { - statusCode: 500, - body: JSON.stringify({ message: err.message }), - }; - } -}; - -export const handler = middy(uploadToIPFS).use(authMiddleware()); diff --git a/web/netlify/middleware/authMiddleware.ts b/web/netlify/middleware/authMiddleware.ts deleted file mode 100644 index 8835e5f01..000000000 --- a/web/netlify/middleware/authMiddleware.ts +++ /dev/null @@ -1,39 +0,0 @@ -import * as jwt from "jose"; - -export const authMiddleware = () => { - return { - before: async (request) => { - const { event } = request; - - const authToken = event?.headers?.["x-auth-token"]; - if (!authToken) { - return { - statusCode: 400, - body: JSON.stringify({ message: `Error : Missing x-auth-token in Header}` }), - }; - } - - try { - const issuer = process.env.JWT_ISSUER ?? "Kleros"; // ex :- Kleros - const audience = process.env.JWT_AUDIENCE ?? "Court"; // ex :- Court, Curate, Escrow - const secret = process.env.JWT_SECRET; - - if (!secret) { - throw new Error("Secret not set in environment"); - } - - const encodedSecret = new TextEncoder().encode(secret); - - const { payload } = await jwt.jwtVerify(authToken, encodedSecret, { issuer, audience }); - - // add auth details to event - request.event.auth = payload; - } catch (err) { - return { - statusCode: 401, - body: JSON.stringify({ message: `Error : ${err?.message ?? "Not Authorised"}` }), - }; - } - }, - }; -}; diff --git a/web/package.json b/web/package.json index f89a6fcf9..c0cb9142d 100644 --- a/web/package.json +++ b/web/package.json @@ -42,8 +42,7 @@ "check-types": "tsc --noEmit", "generate": "yarn generate:gql && yarn generate:hooks", "generate:gql": "graphql-codegen --require tsconfig-paths/register", - "generate:hooks": "NODE_NO_WARNINGS=1 wagmi generate", - "generate:supabase": "scripts/generateSupabaseTypes.sh" + "generate:hooks": "NODE_NO_WARNINGS=1 wagmi generate" }, "prettier": "@kleros/kleros-v2-prettier-config", "devDependencies": { @@ -68,7 +67,6 @@ "eslint-plugin-react": "^7.37.1", "eslint-plugin-react-hooks": "^4.6.2", "lru-cache": "^7.18.3", - "supabase": "^1.133.3", "typescript": "^5.3.3", "vite": "^5.4.2", "vite-plugin-node-polyfills": "^0.21.0", @@ -86,7 +84,6 @@ "@middy/http-json-body-parser": "^5.3.2", "@sentry/react": "^7.93.0", "@sentry/tracing": "^7.93.0", - "@supabase/supabase-js": "^2.39.3", "@tanstack/react-query": "^5.40.1", "@types/react-modal": "^3.16.3", "@web3modal/wagmi": "^4.1.10", @@ -118,7 +115,7 @@ "react-use": "^17.4.3", "siwe": "^2.3.1", "styled-components": "^5.3.11", - "viem": "^2.1.0", + "viem": "^2.17.3", "wagmi": "^2.12.8" } } diff --git a/web/scripts/generateSupabaseTypes.sh b/web/scripts/generateSupabaseTypes.sh deleted file mode 100755 index 1b63c8dea..000000000 --- a/web/scripts/generateSupabaseTypes.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash - -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" - -mkdir -p $SCRIPT_DIR/../src/types - -# Docs: https://supabase.com/docs/guides/api/rest/generating-types#generating-types-using-supabase-cli -supabase=$SCRIPT_DIR/../../node_modules/supabase/bin/supabase -$supabase gen types typescript --project-id elokscrfhzodpgvaixfd --schema public > $SCRIPT_DIR/../src/types/supabase-notification.ts -$supabase gen types typescript --project-id pyyfdntuqbsfquzzatkz --schema public > $SCRIPT_DIR/../src/types/supabase-datalake.ts diff --git a/web/src/app.tsx b/web/src/app.tsx index a2212f39c..a961e70ca 100644 --- a/web/src/app.tsx +++ b/web/src/app.tsx @@ -4,6 +4,7 @@ import { Route } from "react-router-dom"; import "react-loading-skeleton/dist/skeleton.css"; import "react-toastify/dist/ReactToastify.css"; +import AtlasProvider from "context/AtlasProvider"; import GraphqlBatcherProvider from "context/GraphqlBatcher"; import IsListProvider from "context/IsListProvider"; import { NewDisputeProvider } from "context/NewDisputeContext"; @@ -15,6 +16,7 @@ const Dashboard = lazy(() => import("./pages/Dashboard")); const Courts = lazy(() => import("./pages/Courts")); const DisputeResolver = lazy(() => import("./pages/Resolver")); const GetPnk = lazy(() => import("./pages/GetPnk")); +const Settings = lazy(() => import("./pages/Settings")); import Web3Provider from "context/Web3Provider"; import Loader from "components/Loader"; @@ -28,63 +30,73 @@ const App: React.FC = () => { - - - - }> - }> - - - } - /> - }> - - - } - /> - }> - - - } - /> - }> - - - } - /> - }> - - - } - /> - }> - - - } - /> - Justice not found here ¯\_( ͡° ͜ʖ ͡°)_/¯} /> - - - - + + + + + }> + }> + + + } + /> + }> + + + } + /> + }> + + + } + /> + }> + + + } + /> + }> + + + } + /> + }> + + + } + /> + }> + + + } + /> + Justice not found here ¯\_( ͡° ͜ʖ ͡°)_/¯} /> + + + + + diff --git a/web/src/assets/svgs/icons/warning-outline.svg b/web/src/assets/svgs/icons/warning-outline.svg new file mode 100644 index 000000000..fc09d8ca3 --- /dev/null +++ b/web/src/assets/svgs/icons/warning-outline.svg @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/web/src/components/EnsureAuth.tsx b/web/src/components/EnsureAuth.tsx index 5da207605..3414bdf72 100644 --- a/web/src/components/EnsureAuth.tsx +++ b/web/src/components/EnsureAuth.tsx @@ -1,100 +1,30 @@ -import React, { useMemo, useState } from "react"; +import React from "react"; -import * as jwt from "jose"; -import { SiweMessage } from "siwe"; -import { useAccount, useChainId, useSignMessage } from "wagmi"; +import { useAccount } from "wagmi"; import { Button } from "@kleros/ui-components-library"; -import { DEFAULT_CHAIN } from "consts/chains"; -import { useSessionStorage } from "hooks/useSessionStorage"; -import { authoriseUser, getNonce } from "utils/authoriseUser"; +import { useAtlasProvider } from "context/AtlasProvider"; interface IEnsureAuth { children: React.ReactElement; className?: string; } -export const EnsureAuth: React.FC = ({ children, className }) => { - const localToken = window.sessionStorage.getItem("auth-token"); - const [isLoading, setIsLoading] = useState(false); - - const [authToken, setAuthToken] = useSessionStorage("auth-token", localToken); +const EnsureAuth: React.FC = ({ children, className }) => { const { address } = useAccount(); - const chainId = useChainId(); - - const { signMessageAsync } = useSignMessage(); - - const isVerified = useMemo(() => { - if (!authToken || !address) return false; - - const payload = jwt.decodeJwt(authToken); - - if ((payload?.id as string).toLowerCase() !== address.toLowerCase()) return false; - if (payload.exp && payload.exp < Date.now() / 1000) return false; - - return true; - }, [authToken, address]); - - const handleSignIn = async () => { - try { - setIsLoading(true); - if (!address) return; - - const message = await createSiweMessage(address, "Sign In to Kleros with Ethereum.", chainId); - - const signature = await signMessageAsync({ message }); - - if (!signature) return; - - authoriseUser({ - address, - signature, - message, - }) - .then(async (res) => { - const response = await res.json(); - setAuthToken(response["token"]); - }) - .catch((err) => console.log({ err })) - .finally(() => setIsLoading(false)); - } catch (err) { - setIsLoading(false); - console.log({ err }); - } - }; - + const { isVerified, isSigningIn, authoriseUser } = useAtlasProvider(); return isVerified ? ( children ) : (