diff --git a/apps/connect/src/components/create-space.tsx b/apps/connect/src/components/create-space.tsx index 7b2c7e1d..11d4c540 100644 --- a/apps/connect/src/components/create-space.tsx +++ b/apps/connect/src/components/create-space.tsx @@ -92,11 +92,14 @@ export function CreateSpace() { }; return ( - <> - setSpaceName(e.target.value)} /> - - +
+ Create a new space +
+ setSpaceName(e.target.value)} /> + +
+
); } diff --git a/apps/connect/src/components/spaces.tsx b/apps/connect/src/components/spaces.tsx index 6a6efc6f..e289b54c 100644 --- a/apps/connect/src/components/spaces.tsx +++ b/apps/connect/src/components/spaces.tsx @@ -1,53 +1,30 @@ -import { useIdentityToken } from '@privy-io/react-auth'; -import { useQuery } from '@tanstack/react-query'; +import { useSpaces } from '@/hooks/use-spaces'; export function Spaces() { - const { identityToken } = useIdentityToken(); - - const { isPending, error, data } = useQuery<{ - spaces: { - id: string; - name: string; - appIdentities: { address: string; appId: string }[]; - keyBoxes: { - id: string; - ciphertext: string; - nonce: string; - authorPublicKey: string; - }[]; - }[]; - }>({ - queryKey: ['spaces'], - queryFn: async () => { - if (!identityToken) return; - const response = await fetch(`${import.meta.env.VITE_HYPERGRAPH_SYNC_SERVER_ORIGIN}/connect/spaces`, { - headers: { 'privy-id-token': identityToken }, - }); - return await response.json(); - }, - }); + const { isPending, error, data } = useSpaces(); if (isPending) return 'Loading spaces …'; if (error) return `An error has occurred: ${error.message}`; return ( - <> - {data.spaces.map((space) => ( -
-

- {space.name} ({space.id}) -
- --------- -
- {space.appIdentities.map((appIdentity) => ( -
- {appIdentity.appId} ({appIdentity.address}) -
- ))} -

-
- ))} - +
+

Spaces

+ +
); } diff --git a/apps/connect/src/hooks/use-spaces.ts b/apps/connect/src/hooks/use-spaces.ts new file mode 100644 index 00000000..cd851cde --- /dev/null +++ b/apps/connect/src/hooks/use-spaces.ts @@ -0,0 +1,55 @@ +import { getAppInfoByIds } from '@/lib/get-app-info-by-ids'; +import { useIdentityToken } from '@privy-io/react-auth'; +import { useQuery } from '@tanstack/react-query'; + +type SpaceData = { + id: string; + name: string; + appIdentities: { address: string; appId: string }[]; + apps: { name: string; id: string }[]; + keyBoxes: { + id: string; + ciphertext: string; + nonce: string; + authorPublicKey: string; + }[]; +}; + +export const useSpaces = () => { + const { identityToken } = useIdentityToken(); + + return useQuery({ + queryKey: ['spaces'], + queryFn: async () => { + if (!identityToken) return []; + const response = await fetch(`${import.meta.env.VITE_HYPERGRAPH_SYNC_SERVER_ORIGIN}/connect/spaces`, { + headers: { 'privy-id-token': identityToken }, + }); + const data = await response.json(); + const appIds = new Set(); + for (const space of data.spaces) { + for (const appIdentity of space.appIdentities) { + appIds.add(appIdentity.appId); + } + } + const appInfo = await getAppInfoByIds(Array.from(appIds)); + const spaces = data.spaces.map((space: SpaceData) => { + const spaceAppIds = new Set(); + for (const appIdentity of space.appIdentities) { + spaceAppIds.add(appIdentity.appId); + } + return { + ...space, + apps: Array.from(spaceAppIds).map((appId) => { + return { + // @ts-expect-error - need to improve appInfo typing + name: appInfo[appId]?.name ?? 'Unknown', + id: appId, + }; + }), + }; + }); + return spaces; + }, + }); +}; diff --git a/apps/connect/src/lib/get-app-info-by-ids.ts b/apps/connect/src/lib/get-app-info-by-ids.ts new file mode 100644 index 00000000..f2f8d75a --- /dev/null +++ b/apps/connect/src/lib/get-app-info-by-ids.ts @@ -0,0 +1,11 @@ +const apps = { + '93bb8907-085a-4a0e-83dd-62b0dc98e793': { + name: 'Todos', + }, +}; + +export const getAppInfoByIds = async (appIds: string[]) => { + // sleep for 1 second + await new Promise((resolve) => setTimeout(resolve, 1000)); + return apps; +}; diff --git a/apps/connect/src/routes/authenticate.tsx b/apps/connect/src/routes/authenticate.tsx index dd53aca7..2b559ed2 100644 --- a/apps/connect/src/routes/authenticate.tsx +++ b/apps/connect/src/routes/authenticate.tsx @@ -1,12 +1,12 @@ import { CreateSpace } from '@/components/create-space'; import { Button } from '@/components/ui/button'; +import { useSpaces } from '@/hooks/use-spaces'; import { Connect, type Identity, Key, type Messages, StoreConnect, Utils } from '@graphprotocol/hypergraph'; import { useIdentityToken, usePrivy, useWallets } from '@privy-io/react-auth'; -import { useQuery, useQueryClient } from '@tanstack/react-query'; import { createFileRoute } from '@tanstack/react-router'; import { createStore } from '@xstate/store'; import { useSelector } from '@xstate/store/react'; -import { Effect } from 'effect'; +import { Effect, Schema } from 'effect'; import { useEffect } from 'react'; import { createWalletClient, custom } from 'viem'; import { mainnet } from 'viem/chains'; @@ -39,60 +39,74 @@ type AppInfo = { type ComponentContext = | { step: 'fetching-app-identity'; + appIdentityResponse: undefined; appIdentity: undefined; error: undefined; appInfo: undefined; } - | { - step: 'app-identity-does-not-exist'; - appIdentity: undefined; - error: undefined; - appInfo: AppInfo; - } | { step: 'error'; appIdentity: undefined; + appIdentityResponse: undefined; error: string; appInfo: AppInfo | undefined; } | { - step: 'selecting-spaces'; - appIdentity: Connect.PrivateAppIdentity; + step: 'selecting-spaces-new-app-identity'; + appIdentityResponse: undefined; + appIdentity: undefined; + error: undefined; + appInfo: AppInfo; + } + | { + step: 'selecting-spaces-existing-app-identity'; + appIdentityResponse: Connect.AppIdentityResponse; + appIdentity: undefined; error: undefined; appInfo: AppInfo; }; const initialContext: ComponentContext = { step: 'fetching-app-identity' as const, + appIdentityResponse: undefined, appIdentity: undefined, error: undefined, appInfo: undefined, }; type ComponentEvents = { - setAppIdentity: { appIdentity: Connect.PrivateAppIdentity; appInfo: AppInfo }; - setStepToAppIdentityDoesNotExist: { appInfo: AppInfo }; + setStepToSelectingSpacesExistingAppIdentity: { + appInfo: AppInfo; + // biome-ignore lint/suspicious/noExplicitAny: TODO add types later + appIdentityResponse: any; + }; + setStepToSelectingSpacesNewAppIdentity: { appInfo: AppInfo }; setStepToError: { error: string; appInfo: AppInfo | undefined }; }; +const decodeAppIdentityResponse = Schema.decodeSync(Connect.AppIdentityResponse); + const componentStore = createStore({ context: initialContext, on: { - setAppIdentity: (_context, event) => ({ - step: 'selecting-spaces', - appIdentity: event.appIdentity, + setStepToSelectingSpacesExistingAppIdentity: (_context, event) => ({ + step: 'selecting-spaces-existing-app-identity', + appIdentity: undefined, + appIdentityResponse: event.appIdentityResponse, error: undefined, appInfo: event.appInfo, }), - setStepToAppIdentityDoesNotExist: (_context, event) => ({ - step: 'app-identity-does-not-exist', + setStepToSelectingSpacesNewAppIdentity: (_context, event) => ({ + step: 'selecting-spaces-new-app-identity', appIdentity: undefined, + appIdentityResponse: undefined, error: undefined, appInfo: event.appInfo, }), setStepToError: (context, event) => ({ step: 'error', appIdentity: undefined, + appIdentityResponse: undefined, error: event.error, appInfo: event.appInfo ?? context.appInfo, }), @@ -120,36 +134,13 @@ function AuthenticateComponent() { const embeddedWallet = wallets.find((wallet) => wallet.walletClientType === 'privy') || wallets[0]; const state = useSelector(componentStore, (state) => state.context); - const queryClient = useQueryClient(); const { // isPending, // error, data: spacesData, - } = useQuery<{ - spaces: { - id: string; - name: string; - appIdentities: { address: string; appId: string }[]; - keyBoxes: { - id: string; - ciphertext: string; - nonce: string; - authorPublicKey: string; - }[]; - }[]; - }>({ - queryKey: ['spaces'], - queryFn: async () => { - if (!identityToken) return { spaces: [] }; - const response = await fetch(`${import.meta.env.VITE_HYPERGRAPH_SYNC_SERVER_ORIGIN}/connect/spaces`, { - headers: { 'privy-id-token': identityToken }, - }); - return await response.json(); - }, - }); + } = useSpaces(); - // biome-ignore lint/correctness/useExhaustiveDependencies: signMessage would cause an infinite loop useEffect(() => { const run = async () => { if (!identityToken || !accountAddress || !keys || !embeddedWallet) { @@ -158,28 +149,6 @@ function AuthenticateComponent() { try { const parsedAuthParams = await Effect.runPromise(Connect.parseAuthParams({ data, redirect, nonce })); - - const privyProvider = await embeddedWallet.getEthereumProvider(); - const walletClient = createWalletClient({ - chain: mainnet, - transport: custom(privyProvider), - }); - - const signer: Identity.Signer = { - getAddress: async () => { - const [address] = await walletClient.getAddresses(); - return address; - }, - signMessage: async (message: string) => { - if (embeddedWallet.walletClientType === 'privy') { - const { signature } = await signMessage({ message }); - return signature; - } - const [address] = await walletClient.getAddresses(); - return await walletClient.signMessage({ account: address, message }); - }, - }; - const response = await fetch( `${import.meta.env.VITE_HYPERGRAPH_SYNC_SERVER_ORIGIN}/connect/app-identity/${parsedAuthParams.payload.appId}`, { @@ -190,31 +159,10 @@ function AuthenticateComponent() { }, ); if (response.status === 200) { - const appIdentity = await response.json(); - console.log('appIdentity', appIdentity); - const decryptedIdentity = await Connect.decryptAppIdentity( - signer, - accountAddress, - appIdentity.appIdentity.ciphertext, - appIdentity.appIdentity.nonce, - ); - console.log( - 'decryptedIdentity', - decryptedIdentity.encryptionPrivateKey, - decryptedIdentity.signaturePrivateKey, - ); + const appIdentityResponseRaw = await response.json(); + const appIdentityResponse = decodeAppIdentityResponse(appIdentityResponseRaw?.appIdentity); componentStore.send({ - type: 'setAppIdentity', - appIdentity: { - address: appIdentity.appIdentity.address, - signaturePublicKey: decryptedIdentity.signaturePublicKey, - encryptionPublicKey: decryptedIdentity.encryptionPublicKey, - addressPrivateKey: decryptedIdentity.addressPrivateKey, - encryptionPrivateKey: decryptedIdentity.encryptionPrivateKey, - signaturePrivateKey: decryptedIdentity.signaturePrivateKey, - sessionToken: appIdentity.appIdentity.sessionToken, - sessionTokenExpires: new Date(appIdentity.appIdentity.sessionTokenExpires), - }, + type: 'setStepToSelectingSpacesExistingAppIdentity', appInfo: { appId: parsedAuthParams.payload.appId, redirect: parsedAuthParams.redirect, @@ -222,13 +170,13 @@ function AuthenticateComponent() { expiry: parsedAuthParams.payload.expiry, ephemeralEncryptionPublicKey: parsedAuthParams.payload.encryptionPublicKey, }, + appIdentityResponse, }); - queryClient.invalidateQueries({ queryKey: ['spaces'] }); return; } if (response.status === 404) { componentStore.send({ - type: 'setStepToAppIdentityDoesNotExist', + type: 'setStepToSelectingSpacesNewAppIdentity', appInfo: { appId: parsedAuthParams.payload.appId, redirect: parsedAuthParams.redirect, @@ -239,17 +187,126 @@ function AuthenticateComponent() { }); return; } - alert('Failed to fetch app identity'); + componentStore.send({ + type: 'setStepToError', + error: 'Failed to fetch app identity', + appInfo: undefined, + }); } catch (error) { console.error(error); - alert('Failed to parse authentication data'); + componentStore.send({ + type: 'setStepToError', + error: 'Failed to parse authentication data', + appInfo: undefined, + }); } }; run(); - // }, [data, redirect, nonce, identityToken, accountAddress, keys, embeddedWallet, queryClient.invalidateQueries, signMessage]); - }, [data, redirect, nonce, identityToken, accountAddress, keys, embeddedWallet, queryClient.invalidateQueries]); + }, [data, redirect, nonce, identityToken, accountAddress, keys, embeddedWallet]); + + const encryptSpacesAndRedirect = async ({ + accountAddress, + appIdentity, + appInfo, + }: { + accountAddress: string; + appIdentity: Connect.PrivateAppIdentity; + appInfo: AppInfo; + }) => { + // TODO: compare the existing selected spaces for this app identity with the selected spaces and only encrypt the new spaces and attach them to the app identity in the sync server + if (!identityToken || !accountAddress || !keys || !embeddedWallet) { + return; + } + + const spacesInput = spacesData + ? spacesData.map((space) => { + // TODO: currently without checking we assume all keyboxes exists and we don't create any - we should check if the keyboxes exist and create them if they don't + if (space.appIdentities.some((spaceAppIdentity) => spaceAppIdentity.address === appIdentity.address)) + return { + id: space.id, + keyBoxes: [], + }; + + const spaceKeys = space.keyBoxes.map((keyboxData) => { + const key = Key.decryptKey({ + privateKey: Utils.hexToBytes(keys.encryptionPrivateKey), + publicKey: Utils.hexToBytes(keyboxData.authorPublicKey), + keyBoxCiphertext: Utils.hexToBytes(keyboxData.ciphertext), + keyBoxNonce: Utils.hexToBytes(keyboxData.nonce), + }); + return { + id: keyboxData.id, + key: key, + }; + }); + + const keyBoxes = spaceKeys.map((keyData) => { + const keyBox = Key.encryptKey({ + privateKey: Utils.hexToBytes(keys.encryptionPrivateKey), + publicKey: Utils.hexToBytes(appIdentity.encryptionPublicKey), + key: keyData.key, + }); + return { + id: keyData.id, + ciphertext: Utils.bytesToHex(keyBox.keyBoxCiphertext), + nonce: Utils.bytesToHex(keyBox.keyBoxNonce), + authorPublicKey: appIdentity.encryptionPublicKey, + accountAddress: accountAddress, + }; + }); + + return { + id: space.id, + keyBoxes, + }; + }) + : []; + + const message: Messages.RequestConnectAddAppIdentityToSpaces = { + type: 'connect-add-app-identity-to-spaces', + appIdentityAddress: appIdentity.address, + spacesInput, + }; + + // TODO add loading indicator by updating the state + const response = await fetch( + `${import.meta.env.VITE_HYPERGRAPH_SYNC_SERVER_ORIGIN}/connect/add-app-identity-to-spaces`, + { + headers: { + 'privy-id-token': identityToken, + 'Content-Type': 'application/json', + }, + method: 'POST', + body: JSON.stringify(message), + }, + ); + if (response.status === 200) { + const params = Connect.createCallbackParams({ + appId: appInfo.appId, + nonce: appInfo.appNonce, + ephemeralPublicKey: appInfo.ephemeralEncryptionPublicKey, + appIdentityAddress: appIdentity.address, + encryptionPrivateKey: appIdentity.encryptionPrivateKey, + signaturePrivateKey: appIdentity.signaturePrivateKey, + signaturePublicKey: appIdentity.signaturePublicKey, + appIdentityAddressPrivateKey: appIdentity.addressPrivateKey, + encryptionPublicKey: appIdentity.encryptionPublicKey, + spaces: spacesData?.map((space) => ({ id: space.id })) ?? [], + expiry: appInfo.expiry, + sessionToken: appIdentity.sessionToken, + sessionTokenExpires: appIdentity.sessionTokenExpires.getTime(), + }); + window.location.href = `${appInfo.redirect}?ciphertext=${params.ciphertext}&nonce=${params.nonce}`; + } else { + componentStore.send({ + type: 'setStepToError', + error: 'Failed to authenticate and give access to all spaces', + appInfo: appInfo, + }); + } + }; - const createNewAppIdentity = async () => { + const createNewAppIdentityAndRedirect = async () => { if (!identityToken || !accountAddress || !keys || !embeddedWallet || !state.appInfo) { return; } @@ -306,180 +363,118 @@ function AuthenticateComponent() { body: JSON.stringify(message), }); const appIdentityResponse = await response.json(); - console.log('appIdentity', appIdentityResponse); - componentStore.send({ - type: 'setAppIdentity', + await encryptSpacesAndRedirect({ + accountAddress, appIdentity: { address: newAppIdentity.address, - signaturePublicKey: newAppIdentity.signaturePublicKey, - encryptionPublicKey: newAppIdentity.encryptionPublicKey, addressPrivateKey: newAppIdentity.addressPrivateKey, encryptionPrivateKey: keys.encryptionPrivateKey, signaturePrivateKey: keys.signaturePrivateKey, + encryptionPublicKey: newAppIdentity.encryptionPublicKey, + signaturePublicKey: newAppIdentity.signaturePublicKey, sessionToken: appIdentityResponse.appIdentity.sessionToken, - sessionTokenExpires: appIdentityResponse.appIdentity.sessionTokenExpires, - }, - appInfo: { - appId: state.appInfo.appId, - redirect: state.appInfo.redirect, - appNonce: state.appInfo.appNonce, - expiry: state.appInfo.expiry, - ephemeralEncryptionPublicKey: state.appInfo.ephemeralEncryptionPublicKey, + sessionTokenExpires: new Date(appIdentityResponse.appIdentity.sessionTokenExpires), }, + appInfo: state.appInfo, }); - queryClient.invalidateQueries({ queryKey: ['spaces'] }); } catch (error) { console.error(error); - alert('Failed to create new app identity'); + componentStore.send({ + type: 'setStepToError', + error: 'Failed to create new app identity', + appInfo: state.appInfo, + }); } }; - const encryptSpacesAndRedirect = async () => { - // TODO: compare the existing selected spaces for this app identity with the selected spaces and only encrypt the new spaces and attach them to the app identity in the sync server - if ( - !identityToken || - !accountAddress || - !keys || - !embeddedWallet || - !state.appInfo || - state.step !== 'selecting-spaces' - ) { + const decryptAppIdentityAndRedirect = async () => { + if (!state.appIdentityResponse) { return; } - const spacesInput = spacesData - ? spacesData.spaces.map((space) => { - // TODO: currently without checking we assume all keyboxes exists and we don't create any - we should check if the keyboxes exist and create them if they don't - if (space.appIdentities.some((appIdentity) => appIdentity.address === state.appIdentity.address)) - return { - id: space.id, - keyBoxes: [], - }; - - const spaceKeys = space.keyBoxes.map((keyboxData) => { - const key = Key.decryptKey({ - privateKey: Utils.hexToBytes(keys.encryptionPrivateKey), - publicKey: Utils.hexToBytes(keyboxData.authorPublicKey), - keyBoxCiphertext: Utils.hexToBytes(keyboxData.ciphertext), - keyBoxNonce: Utils.hexToBytes(keyboxData.nonce), - }); - return { - id: keyboxData.id, - key: key, - }; - }); - - const keyBoxes = spaceKeys.map((keyData) => { - const keyBox = Key.encryptKey({ - privateKey: Utils.hexToBytes(keys.encryptionPrivateKey), - publicKey: Utils.hexToBytes(state.appIdentity.encryptionPublicKey), - key: keyData.key, - }); - return { - id: keyData.id, - ciphertext: Utils.bytesToHex(keyBox.keyBoxCiphertext), - nonce: Utils.bytesToHex(keyBox.keyBoxNonce), - authorPublicKey: state.appIdentity.encryptionPublicKey, - accountAddress: accountAddress, - }; - }); - - return { - id: space.id, - keyBoxes, - }; - }) - : []; + const privyProvider = await embeddedWallet.getEthereumProvider(); + const walletClient = createWalletClient({ + chain: mainnet, + transport: custom(privyProvider), + }); - const message: Messages.RequestConnectAddAppIdentityToSpaces = { - type: 'connect-add-app-identity-to-spaces', - appIdentityAddress: state.appIdentity.address, - spacesInput, + const signer: Identity.Signer = { + getAddress: async () => { + const [address] = await walletClient.getAddresses(); + return address; + }, + signMessage: async (message: string) => { + if (embeddedWallet.walletClientType === 'privy') { + const { signature } = await signMessage({ message }); + return signature; + } + const [address] = await walletClient.getAddresses(); + return await walletClient.signMessage({ account: address, message }); + }, }; - // TODO add loading indicator by updating the state - const response = await fetch( - `${import.meta.env.VITE_HYPERGRAPH_SYNC_SERVER_ORIGIN}/connect/add-app-identity-to-spaces`, - { - headers: { - 'privy-id-token': identityToken, - 'Content-Type': 'application/json', - }, - method: 'POST', - body: JSON.stringify(message), - }, + const decryptedIdentity = await Connect.decryptAppIdentity( + signer, + state.appIdentityResponse.accountAddress, + state.appIdentityResponse.ciphertext, + state.appIdentityResponse.nonce, ); - if (response.status === 200) { - console.log('state.appIdentity', state.appIdentity); - const params = Connect.createCallbackParams({ - appId: state.appInfo.appId, - nonce: state.appInfo.appNonce, - ephemeralPublicKey: state.appInfo.ephemeralEncryptionPublicKey, - appIdentityAddress: state.appIdentity.address, - encryptionPrivateKey: state.appIdentity.encryptionPrivateKey, - signaturePrivateKey: state.appIdentity.signaturePrivateKey, - signaturePublicKey: state.appIdentity.signaturePublicKey, - appIdentityAddressPrivateKey: state.appIdentity.addressPrivateKey, - encryptionPublicKey: state.appIdentity.encryptionPublicKey, - spaces: spacesData?.spaces.map((space) => ({ id: space.id })) ?? [], - expiry: state.appInfo.expiry, - sessionToken: state.appIdentity.sessionToken, - sessionTokenExpires: state.appIdentity.sessionTokenExpires.getTime(), - }); - window.location.href = `${state.appInfo.redirect}?ciphertext=${params.ciphertext}&nonce=${params.nonce}`; - } else { - alert('Failed to authenticate and give access to all spaces'); - } + await encryptSpacesAndRedirect({ + accountAddress: state.appIdentityResponse.accountAddress, + appIdentity: { + address: decryptedIdentity.address, + addressPrivateKey: decryptedIdentity.addressPrivateKey, + encryptionPrivateKey: decryptedIdentity.encryptionPrivateKey, + signaturePrivateKey: decryptedIdentity.signaturePrivateKey, + encryptionPublicKey: decryptedIdentity.encryptionPublicKey, + signaturePublicKey: decryptedIdentity.signaturePublicKey, + sessionToken: state.appIdentityResponse.sessionToken, + sessionTokenExpires: new Date(state.appIdentityResponse.sessionTokenExpires), + }, + appInfo: state.appInfo, + }); }; return ( -
+
-

Authenticating

+

Authenticating with Geo Connect

{state.step === 'fetching-app-identity' &&

Loading…

} - {state.step === 'app-identity-does-not-exist' && ( - <> -

Do you want accociate this app with your account and give access to all spaces?

-

- App Id: {state.appInfo.appId ?? 'unknown'} -
- Redirect: {state.appInfo.redirect ?? 'unknown'} -

-

Select spaces (not working yet)

- {spacesData?.spaces.map((space: { id: string; name: string }) => ( -
- {space.name} ({space.id}) -
- ))} - - - - )} - {state.step === 'selecting-spaces' && ( - <> -

Do you want login with this app?

-

- App Id: {state.appInfo.appId ?? 'unknown'} -
- Redirect: {state.appInfo.redirect ?? 'unknown'} -

-

Select spaces (not working yet)

- {spacesData?.spaces.map((space) => ( -
- {space.name} ({space.id}) -
- --------- -
- {space.appIdentities.map((appIdentity) => ( -
- {appIdentity.appId} ({appIdentity.address}) -
- ))} -
- ))} + {state.step === 'error' &&

Error: {state.error}

} + {(state.step === 'selecting-spaces-existing-app-identity' || + state.step === 'selecting-spaces-new-app-identity') && ( +
+
+ App Id +
{state.appInfo.appId ?? 'unknown'}
+ Redirect: +
{state.appInfo.redirect ?? 'unknown'}
+
+

Spaces

+
    + {spacesData?.map((space) => ( +
  • +

    {space.name}

    +

    Apps with access to this space

    +
      + {space.apps.map((app) => ( +
    • + {app.name} +
    • + ))} +
    +
  • + ))} +
- - +
+ {state.step === 'selecting-spaces-new-app-identity' ? ( + + ) : ( + + )} +
+
)}
diff --git a/apps/connect/src/routes/index.tsx b/apps/connect/src/routes/index.tsx index ddaf4d73..cfaf0399 100644 --- a/apps/connect/src/routes/index.tsx +++ b/apps/connect/src/routes/index.tsx @@ -15,7 +15,7 @@ function Index() { return (
-

Welcome to Connect

+

Welcome to Geo Connect

diff --git a/packages/hypergraph/src/connect/create-auth-url.ts b/packages/hypergraph/src/connect/create-auth-url.ts index f8745465..10909a30 100644 --- a/packages/hypergraph/src/connect/create-auth-url.ts +++ b/packages/hypergraph/src/connect/create-auth-url.ts @@ -18,8 +18,6 @@ export const createAuthUrl = (params: CreateAuthUrlParams) => { } = params; const { publicKey, secretKey } = generateKeypair(); - console.log('PUBLIC KEY (new)', publicKey); - const expiry = Date.now() + expiryMilliseconds; const payload: ConnectAuthPayload = { expiry, @@ -34,8 +32,6 @@ export const createAuthUrl = (params: CreateAuthUrlParams) => { url.searchParams.set('redirect', encodeURIComponent(redirectUrl)); url.searchParams.set('nonce', nonce); - console.log('secretKey', secretKey); - return { url, nonce, diff --git a/packages/hypergraph/src/connect/create-callback-params.ts b/packages/hypergraph/src/connect/create-callback-params.ts index 3a619a93..02f17607 100644 --- a/packages/hypergraph/src/connect/create-callback-params.ts +++ b/packages/hypergraph/src/connect/create-callback-params.ts @@ -22,7 +22,6 @@ export const createCallbackParams = ({ nonce, ephemeralPublicKey, ...rest }: Cre message: utf8ToBytes(JSON.stringify(rest)), publicKey: hexToBytes(ephemeralPublicKey.replace(/^0x/, '')), }); - console.log('encrypt publicKey', hexToBytes(ephemeralPublicKey.replace(/^0x/, ''))); return { ciphertext: bytesToHex(ciphertext), diff --git a/packages/hypergraph/src/connect/parse-callback-params.ts b/packages/hypergraph/src/connect/parse-callback-params.ts index 47b1a5eb..2bad9c08 100644 --- a/packages/hypergraph/src/connect/parse-callback-params.ts +++ b/packages/hypergraph/src/connect/parse-callback-params.ts @@ -37,7 +37,9 @@ export const parseCallbackParams = ({ }); const decoded = decodeDecryptedResult(JSON.parse(bytesToUtf8(decryptionResult))); if (Either.isLeft(decoded)) { - return Effect.fail(new FailedToParseAuthCallbackUrl({ message: 'Failed to parse connect auth payload' })); + return Effect.fail( + new FailedToParseAuthCallbackUrl({ message: 'Failed to parse connect auth callback payload' }), + ); } const data = decoded.right; if (data.expiry !== storedExpiry) { @@ -59,6 +61,7 @@ export const parseCallbackParams = ({ spaces: data.spaces, }); } catch (error) { - return Effect.fail(new FailedToParseAuthCallbackUrl({ message: 'Failed to parse connect auth payload' })); + console.error(error); + return Effect.fail(new FailedToParseAuthCallbackUrl({ message: 'Failed to parse connect auth callback payload' })); } }; diff --git a/packages/hypergraph/src/connect/types.ts b/packages/hypergraph/src/connect/types.ts index 0c5c1b8c..abe3b174 100644 --- a/packages/hypergraph/src/connect/types.ts +++ b/packages/hypergraph/src/connect/types.ts @@ -29,6 +29,22 @@ export const KeysSchema = Schema.Struct({ export type KeysSchema = Schema.Schema.Type; +export const AppIdentityResponse = Schema.Struct({ + accountAddress: Schema.String, + signaturePublicKey: Schema.String, + encryptionPublicKey: Schema.String, + accountProof: Schema.String, + keyProof: Schema.String, + ciphertext: Schema.String, + nonce: Schema.String, + sessionToken: Schema.String, + address: Schema.String, + appId: Schema.String, + sessionTokenExpires: Schema.String, +}); + +export type AppIdentityResponse = Schema.Schema.Type; + export type Identity = IdentityKeys & { accountAddress: string; };