diff --git a/data-browser/src/components/RegisterSignIn.tsx b/data-browser/src/components/RegisterSignIn.tsx index 6c0d13f0..fb939fc7 100644 --- a/data-browser/src/components/RegisterSignIn.tsx +++ b/data-browser/src/components/RegisterSignIn.tsx @@ -8,7 +8,13 @@ import { import React, { FormEvent, useCallback, useEffect, useState } from 'react'; import { useSettings } from '../helpers/AppSettings'; import { Button } from './Button'; -import { Agent, nameRegex, useRegister, useServerURL } from '@tomic/react'; +import { + Agent, + nameRegex, + register, + useServerURL, + useStore, +} from '@tomic/react'; import Field from './forms/Field'; import { InputWrapper, InputStyled } from './forms/InputStyles'; import { Row } from './Row'; @@ -30,7 +36,7 @@ export function RegisterSignIn({ }: React.PropsWithChildren): JSX.Element { const { dialogProps, show } = useDialog(); const { agent } = useSettings(); - const [register, setRegister] = useState(true); + const [isRegister, setRegister] = useState(true); if (agent) { return <>{children}; @@ -56,7 +62,9 @@ export function RegisterSignIn({ Sign In - {register ? : } + + {isRegister ? : } + ); } @@ -69,8 +77,9 @@ function Register() { const [newAgent, setNewAgent] = useState(undefined); const [serverUrlStr] = useServerURL(); const [nameErr, setErr] = useState(undefined); - const register = useRegister(); + const doRegister = useCallback(register, []); const { setAgent } = useSettings(); + const store = useStore(); const serverUrl = new URL(serverUrlStr); serverUrl.host = `${name}.${serverUrl.host}`; @@ -95,7 +104,11 @@ function Register() { } try { - const { driveURL: newDriveURL, agent } = await register(name, email); + const { driveURL: newDriveURL, agent } = await doRegister( + store, + name, + email, + ); setDriveURL(newDriveURL); setSecret(agent.buildSecret()); setNewAgent(agent); diff --git a/lib/src/authentication.ts b/lib/src/authentication.ts index 16418dd4..b52de4f6 100644 --- a/lib/src/authentication.ts +++ b/lib/src/authentication.ts @@ -1,7 +1,9 @@ import { Agent, + generateKeyPair, getTimestampNow, HeadersObject, + properties, signToBase64, Store, } from './index.js'; @@ -111,3 +113,49 @@ export const checkAuthenticationCookie = (): boolean => { return matches.length > 0; }; + +export interface RegisterResult { + agent: Agent; + driveURL: string; +} + +/** Only lowercase chars, numbers and a hyphen */ +export const nameRegex = '^[a-z0-9_-]+'; + +/** Creates a new Agent + Drive using a shortname and email. Uses the serverURL from the Store. */ +export const register = async ( + store: Store, + name: string, + email: string, +): Promise => { + const keypair = await generateKeyPair(); + const agent = new Agent(keypair.privateKey); + const publicKey = await agent.getPublicKey(); + const url = new URL('/register', store.getServerUrl()); + url.searchParams.set('name', name); + url.searchParams.set('public-key', publicKey); + url.searchParams.set('email', email); + const resource = await store.getResourceAsync(url.toString()); + const driveURL = resource.get(properties.redirect.destination) as string; + const agentSubject = resource.get( + properties.redirect.redirectAgent, + ) as string; + + if (resource.error) { + throw resource.error; + } + + if (!driveURL) { + throw new Error('No redirect destination'); + } + + if (!agentSubject) { + throw new Error('No agent returned'); + } + + agent.subject = agentSubject; + + store.setAgent(agent); + + return { driveURL, agent }; +}; diff --git a/react/src/index.ts b/react/src/index.ts index 78becf7f..5ee70cf0 100644 --- a/react/src/index.ts +++ b/react/src/index.ts @@ -30,5 +30,4 @@ export * from './useImporter.js'; export * from './useLocalStorage.js'; export * from './useMarkdown.js'; export * from './useServerSearch.js'; -export * from './useRegister.js'; export * from '@tomic/lib'; diff --git a/react/src/useRegister.ts b/react/src/useRegister.ts deleted file mode 100644 index 662867dd..00000000 --- a/react/src/useRegister.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { useCallback } from 'react'; -import { Agent, generateKeyPair, properties, useStore } from '.'; - -/** Only allows lowercase chars and numbers */ -export const nameRegex = '^[a-z0-9_-]+'; - -interface RegisterResult { - agent: Agent; - driveURL: string; -} - -// Allow users to register and create a drive on the `/register` route. -export function useRegister(): ( - userName: string, - email: string, -) => Promise { - const store = useStore(); - - const register = useCallback( - /** Returns redirect URL of new drie on success */ - async (name: string, email: string): Promise => { - const keypair = await generateKeyPair(); - const newAgent = new Agent(keypair.privateKey); - const publicKey = await newAgent.getPublicKey(); - const url = new URL('/register', store.getServerUrl()); - url.searchParams.set('name', name); - url.searchParams.set('public-key', publicKey); - url.searchParams.set('email', email); - const resource = await store.getResourceAsync(url.toString()); - const destination = resource.get( - properties.redirect.destination, - ) as string; - const agentSubject = resource.get( - properties.redirect.redirectAgent, - ) as string; - - if (resource.error) { - throw resource.error; - } - - if (!destination) { - throw new Error('No redirect destination'); - } - - if (!agentSubject) { - throw new Error('No agent returned'); - } - - newAgent.subject = agentSubject; - - store.setAgent(newAgent); - - return { driveURL: destination, agent: newAgent }; - }, - [], - ); - - return register; -}