From 5ea8479c622976cbe84e65a2e5960d98fef4e330 Mon Sep 17 00:00:00 2001 From: Neeraj Date: Fri, 18 Oct 2024 15:52:42 +0530 Subject: [PATCH] Add comments for SIWE implementations --- packages/backend/package.json | 6 +-- packages/backend/src/routes/auth.ts | 3 +- packages/backend/src/server.ts | 5 ++- packages/frontend/package.json | 2 +- packages/frontend/src/App.tsx | 4 +- .../src/components/shared/Sidebar/Sidebar.tsx | 4 +- .../frontend/src/context/Web3Provider.tsx | 9 ++-- packages/frontend/src/index.tsx | 6 +-- packages/frontend/src/utils/accessCode.ts | 4 +- packages/frontend/src/utils/constants.ts | 2 +- packages/frontend/src/utils/siwe.ts | 4 +- .../frontend/src/utils/turnkey-frontend.ts | 8 ++-- yarn.lock | 43 +++++++++++-------- 13 files changed, 55 insertions(+), 45 deletions(-) diff --git a/packages/backend/package.json b/packages/backend/package.json index bd5190ed..a7a5d34b 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -16,11 +16,11 @@ "apollo-server-core": "^3.13.0", "apollo-server-express": "^3.13.0", "cookie-session": "^2.1.0", - "cors": "2.8.5", + "cors": "^2.8.5", "debug": "^4.3.1", "express": "^4.18.2", "express-async-errors": "^3.1.1", - "express-session": "1.18.0", + "express-session": "^1.18.0", "fs-extra": "^11.2.0", "graphql": "^16.8.1", "luxon": "^3.4.4", @@ -51,7 +51,7 @@ }, "devDependencies": { "@types/cookie-session": "^2.0.49", - "@types/express-session": "1.17.10", + "@types/express-session": "^1.17.10", "@types/fs-extra": "^11.0.4", "better-sqlite3": "^9.2.2", "copyfiles": "^2.4.1", diff --git a/packages/backend/src/routes/auth.ts b/packages/backend/src/routes/auth.ts index 2ef917e7..e528f0dc 100644 --- a/packages/backend/src/routes/auth.ts +++ b/packages/backend/src/routes/auth.ts @@ -53,7 +53,7 @@ router.post('/validate', async (req, res) => { }); if (!success) { - return res.send({ success, error: 'SIWE verifcation failed' } ); + return res.send({ success }); } const service: Service = req.app.get('service'); const user = await service.getUserByEthAddress(data.address); @@ -66,6 +66,7 @@ router.post('/validate', async (req, res) => { subOrgId: '', turnkeyWalletId: '', }); + // SIWESession from the web3modal library requires both address and chain ID req.session.address = newUser.id; req.session.chainId = data.chainId; } else { diff --git a/packages/backend/src/server.ts b/packages/backend/src/server.ts index 16b35886..734893e7 100644 --- a/packages/backend/src/server.ts +++ b/packages/backend/src/server.ts @@ -22,6 +22,9 @@ import { Service } from './service'; const log = debug('snowball:server'); +// Set cookie expiration to 1 month in milliseconds +const COOKIE_MAX_AGE = 30 * 24 * 60 * 60 * 1000; + declare module 'express-session' { interface SessionData { address: string; @@ -86,7 +89,7 @@ export const createAndStartServer = async ( saveUninitialized: true, cookie: { secure: new URL(appOriginUrl).protocol === 'https:', - maxAge: 30 * 24 * 60 * 60 * 1000, + maxAge: COOKIE_MAX_AGE, domain: domain || undefined, sameSite: new URL(appOriginUrl).protocol === 'https:' ? 'none' : 'lax', } diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 6505174f..3a8b9a21 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -38,7 +38,7 @@ "@snowballtools/smartwallet-alchemy-light": "^0.2.0", "@snowballtools/types": "^0.2.0", "@snowballtools/utils": "^0.1.1", - "@tanstack/react-query": "5.22.2", + "@tanstack/react-query": "^5.22.2", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", diff --git a/packages/frontend/src/App.tsx b/packages/frontend/src/App.tsx index e1518029..05c254f8 100644 --- a/packages/frontend/src/App.tsx +++ b/packages/frontend/src/App.tsx @@ -12,7 +12,7 @@ import Index from './pages'; import AuthPage from './pages/AuthPage'; import { DashboardLayout } from './pages/org-slug/layout'; import Web3Provider from 'context/Web3Provider'; -import { baseUrl } from 'utils/constants'; +import { BASE_URL } from 'utils/constants'; const router = createBrowserRouter([ { @@ -56,7 +56,7 @@ function App() { // Hacky way of checking session // TODO: Handle redirect backs useEffect(() => { - fetch(`${baseUrl}/auth/session`, { + fetch(`${BASE_URL}/auth/session`, { credentials: 'include', }).then((res) => { const path = window.location.pathname; diff --git a/packages/frontend/src/components/shared/Sidebar/Sidebar.tsx b/packages/frontend/src/components/shared/Sidebar/Sidebar.tsx index 816c9bb1..9c0ca570 100644 --- a/packages/frontend/src/components/shared/Sidebar/Sidebar.tsx +++ b/packages/frontend/src/components/shared/Sidebar/Sidebar.tsx @@ -21,7 +21,7 @@ import { cn } from 'utils/classnames'; import { useMediaQuery } from 'usehooks-ts'; import { SIDEBAR_MENU } from './constants'; import { UserSelect } from 'components/shared/UserSelect'; -import { baseUrl } from 'utils/constants'; +import { BASE_URL } from 'utils/constants'; interface SidebarProps { mobileOpen?: boolean; @@ -86,7 +86,7 @@ export const Sidebar = ({ mobileOpen }: SidebarProps) => { }, [orgSlug]); const handleLogOut = useCallback(async () => { - await fetch(`${baseUrl}/auth/logout`, { + await fetch(`${BASE_URL}/auth/logout`, { method: 'POST', credentials: 'include', }); diff --git a/packages/frontend/src/context/Web3Provider.tsx b/packages/frontend/src/context/Web3Provider.tsx index cd456c3d..3c71785c 100644 --- a/packages/frontend/src/context/Web3Provider.tsx +++ b/packages/frontend/src/context/Web3Provider.tsx @@ -4,6 +4,7 @@ import { SiweMessage, generateNonce } from 'siwe'; import { WagmiProvider } from 'wagmi'; import { arbitrum, mainnet } from 'wagmi/chains'; import axios from 'axios'; + import { createWeb3Modal } from '@web3modal/wagmi/react'; import { defaultWagmiConfig } from '@web3modal/wagmi/react/config'; import { createSIWEConfig } from '@web3modal/siwe'; @@ -13,16 +14,16 @@ import type { } from '@web3modal/core'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { VITE_WALLET_CONNECT_ID, baseUrl } from 'utils/constants'; +import { VITE_WALLET_CONNECT_ID, BASE_URL } from 'utils/constants'; if (!VITE_WALLET_CONNECT_ID) { throw new Error('Error: REACT_APP_WALLET_CONNECT_ID env config is not set'); } -assert(baseUrl, 'VITE_SERVER_URL is not set in env'); +assert(BASE_URL, 'VITE_SERVER_URL is not set in env'); const queryClient = new QueryClient(); const axiosInstance = axios.create({ - baseURL: baseUrl, + baseURL: BASE_URL, headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', @@ -112,4 +113,4 @@ export default function Web3ModalProvider({ {children} ); -} \ No newline at end of file +} diff --git a/packages/frontend/src/index.tsx b/packages/frontend/src/index.tsx index 47bdb778..f0cded53 100644 --- a/packages/frontend/src/index.tsx +++ b/packages/frontend/src/index.tsx @@ -14,7 +14,7 @@ import { GQLClientProvider } from './context/GQLClientContext'; import { SERVER_GQL_PATH } from './constants'; import { Toaster } from 'components/shared/Toast'; import { LogErrorBoundary } from 'utils/log-error'; -import { baseUrl } from 'utils/constants'; +import { BASE_URL } from 'utils/constants'; import Web3ModalProvider from './context/Web3Provider'; @@ -24,8 +24,8 @@ const root = ReactDOM.createRoot( document.getElementById('root') as HTMLElement, ); -assert(baseUrl, 'VITE_SERVER_URL is not set in env'); -const gqlEndpoint = `${baseUrl}/${SERVER_GQL_PATH}`; +assert(BASE_URL, 'VITE_SERVER_URL is not set in env'); +const gqlEndpoint = `${BASE_URL}/${SERVER_GQL_PATH}`; const gqlClient = new GQLClient({ gqlEndpoint }); diff --git a/packages/frontend/src/utils/accessCode.ts b/packages/frontend/src/utils/accessCode.ts index d5e1b68f..00f49920 100644 --- a/packages/frontend/src/utils/accessCode.ts +++ b/packages/frontend/src/utils/accessCode.ts @@ -1,9 +1,9 @@ -import { baseUrl } from './constants'; +import { BASE_URL } from './constants'; export async function verifyAccessCode( accesscode: string, ): Promise { - const res = await fetch(`${baseUrl}/auth/accesscode`, { + const res = await fetch(`${BASE_URL}/auth/accesscode`, { method: 'POST', body: JSON.stringify({ accesscode, diff --git a/packages/frontend/src/utils/constants.ts b/packages/frontend/src/utils/constants.ts index 3e4b03a6..57bd5391 100644 --- a/packages/frontend/src/utils/constants.ts +++ b/packages/frontend/src/utils/constants.ts @@ -1,4 +1,4 @@ -export const baseUrl = import.meta.env.VITE_SERVER_URL; +export const BASE_URL = import.meta.env.VITE_SERVER_URL; export const PASSKEY_WALLET_RPID = import.meta.env.VITE_PASSKEY_WALLET_RPID!; export const TURNKEY_BASE_URL = import.meta.env.VITE_TURNKEY_API_BASE_URL!; export const VITE_GITHUB_PWA_TEMPLATE_REPO = import.meta.env diff --git a/packages/frontend/src/utils/siwe.ts b/packages/frontend/src/utils/siwe.ts index d45e1739..8007be0f 100644 --- a/packages/frontend/src/utils/siwe.ts +++ b/packages/frontend/src/utils/siwe.ts @@ -2,7 +2,7 @@ import { SiweMessage } from 'siwe'; import { PKPEthersWallet } from '@lit-protocol/pkp-ethers'; import { v4 as uuid } from 'uuid'; -import { baseUrl } from './constants'; +import { BASE_URL } from './constants'; const domain = window.location.host; const origin = window.location.origin; @@ -19,7 +19,7 @@ export async function signInWithEthereum( ); const signature = await wallet.signMessage(message); - const res = await fetch(`${baseUrl}/auth/validate`, { + const res = await fetch(`${BASE_URL}/auth/validate`, { method: 'POST', headers: { 'Content-Type': 'application/json', diff --git a/packages/frontend/src/utils/turnkey-frontend.ts b/packages/frontend/src/utils/turnkey-frontend.ts index f670b754..2124ee47 100644 --- a/packages/frontend/src/utils/turnkey-frontend.ts +++ b/packages/frontend/src/utils/turnkey-frontend.ts @@ -1,7 +1,7 @@ import { TurnkeyClient, getWebAuthnAttestation } from '@turnkey/http'; import { WebauthnStamper } from '@turnkey/webauthn-stamper'; -import { baseUrl, PASSKEY_WALLET_RPID, TURNKEY_BASE_URL } from './constants'; +import { BASE_URL, PASSKEY_WALLET_RPID, TURNKEY_BASE_URL } from './constants'; // All algorithms can be found here: https://www.iana.org/assignments/cose/cose.xhtml#algorithms // We only support ES256, which is listed here @@ -10,7 +10,7 @@ const es256 = -7; export async function subOrganizationIdForEmail( email: string, ): Promise { - const res = await fetch(`${baseUrl}/auth/registration/${email}`); + const res = await fetch(`${BASE_URL}/auth/registration/${email}`); // If API returns a non-empty 200, this email maps to an existing user. if (res.status == 200) { @@ -64,7 +64,7 @@ export async function turnkeySignup(email: string) { }, }); - const res = await fetch(`${baseUrl}/auth/register`, { + const res = await fetch(`${BASE_URL}/auth/register`, { method: 'POST', body: JSON.stringify({ email, @@ -108,7 +108,7 @@ export async function turnkeySignin(subOrganizationId: string) { throw new Error(`Error during webauthn prompt: ${e}`); } - const res = await fetch(`${baseUrl}/auth/authenticate`, { + const res = await fetch(`${BASE_URL}/auth/authenticate`, { method: 'POST', body: JSON.stringify({ signedWhoamiRequest: signedRequest, diff --git a/yarn.lock b/yarn.lock index 5cd17981..1d5205b6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7035,17 +7035,17 @@ "@types/express" "^4.7.0" file-system-cache "2.3.0" -"@tanstack/query-core@5.22.2": - version "5.22.2" - resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.22.2.tgz#af67d41b0b4a3e846c2325f32540f39ca0d4788d" - integrity sha512-z3PwKFUFACMUqe1eyesCIKg3Jv1mysSrYfrEW5ww5DCDUD4zlpTKBvUDaEjsfZzL3ULrFLDM9yVUxI/fega1Qg== +"@tanstack/query-core@5.59.13": + version "5.59.13" + resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.59.13.tgz#8c962980af174bbd446b7e9b9999f7432897df80" + integrity sha512-Oou0bBu/P8+oYjXsJQ11j+gcpLAMpqW42UlokQYEz4dE7+hOtVO9rVuolJKgEccqzvyFzqX4/zZWY+R/v1wVsQ== -"@tanstack/react-query@5.22.2": - version "5.22.2" - resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.22.2.tgz#e5fce278fbdd026fc1d561a4505142b9f93549d7" - integrity sha512-TaxJDRzJ8/NWRT4lY2jguKCrNI6MRN+67dELzPjNUlvqzTxGANlMp68l7aC7hG8Bd1uHNxHl7ihv7MT50i/43A== +"@tanstack/react-query@^5.22.2": + version "5.59.15" + resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.59.15.tgz#fa1c5b4d96e6a148ec761f214304bbf5ac1906be" + integrity sha512-QbVlAkTI78wB4Mqgf2RDmgC0AOiJqer2c5k9STOOSXGv1S6ZkY37r/6UpE8DbQ2Du0ohsdoXgFNEyv+4eDoPEw== dependencies: - "@tanstack/query-core" "5.22.2" + "@tanstack/query-core" "5.59.13" "@testing-library/dom@^8.5.0": version "8.20.1" @@ -7495,10 +7495,10 @@ "@types/range-parser" "*" "@types/send" "*" -"@types/express-session@1.17.10": - version "1.17.10" - resolved "https://registry.yarnpkg.com/@types/express-session/-/express-session-1.17.10.tgz#3a9394f1f314a4c657af3fb1cdb52f00fc207fd2" - integrity sha512-U32bC/s0ejXijw5MAzyaV4tuZopCh/K7fPoUDyNbsRXHvPSeymygYD1RFL99YOLhF5PNOkzswvOTRaVHdL1zMw== +"@types/express-session@^1.17.10": + version "1.18.0" + resolved "https://registry.yarnpkg.com/@types/express-session/-/express-session-1.18.0.tgz#7c6f25c3604b28d6bc08a2e3929997bbc7672fa2" + integrity sha512-27JdDRgor6PoYlURY+Y5kCakqp5ulC0kmf7y+QwaY+hv9jEFuQOThgkjyA53RP3jmKuBsH5GR6qEfFmvb8mwOA== dependencies: "@types/express" "*" @@ -10383,6 +10383,11 @@ cookie@0.6.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== +cookie@0.7.2: + version "0.7.2" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.2.tgz#556369c472a2ba910f2979891b526b3436237ed7" + integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w== + cookies@0.9.1: version "0.9.1" resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.9.1.tgz#3ffed6f60bb4fb5f146feeedba50acc418af67e3" @@ -10416,7 +10421,7 @@ core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== -cors@2.8.5, cors@^2.8.5: +cors@^2.8.5: version "2.8.5" resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== @@ -11760,12 +11765,12 @@ express-async-errors@^3.1.1: resolved "https://registry.yarnpkg.com/express-async-errors/-/express-async-errors-3.1.1.tgz#6053236d61d21ddef4892d6bd1d736889fc9da41" integrity sha512-h6aK1da4tpqWSbyCa3FxB/V6Ehd4EEB15zyQq9qe75OZBp0krinNKuH4rAY+S/U/2I36vdLAUFSjQJ+TFmODng== -express-session@1.18.0: - version "1.18.0" - resolved "https://registry.yarnpkg.com/express-session/-/express-session-1.18.0.tgz#a6ae39d9091f2efba5f20fc5c65a3ce7c9ce16a3" - integrity sha512-m93QLWr0ju+rOwApSsyso838LQwgfs44QtOP/WBiwtAgPIo/SAh1a5c6nn2BR6mFNZehTpqKDESzP+fRHVbxwQ== +express-session@^1.18.0: + version "1.18.1" + resolved "https://registry.yarnpkg.com/express-session/-/express-session-1.18.1.tgz#88d0bbd41878882840f24ec6227493fcb167e8d5" + integrity sha512-a5mtTqEaZvBCL9A9aqkrtfz+3SMDhOVUnjafjo+s7A9Txkq+SVX2DLvSp1Zrv4uCXa3lMSK3viWnh9Gg07PBUA== dependencies: - cookie "0.6.0" + cookie "0.7.2" cookie-signature "1.0.7" debug "2.6.9" depd "~2.0.0"