Skip to content

Commit

Permalink
feat: display verification phrase during space registration
Browse files Browse the repository at this point in the history
storacha/w3up#432 introduces a
mechanism for providing "definitive verification of the validity of a [space registration] email request".

A full justification for this flow is provided in that PR, and this PR
updates w3ui and w3console to show the phrase generated by the access API.
  • Loading branch information
travis committed Feb 22, 2023
1 parent 0f166e0 commit 9734cb2
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 10 deletions.
12 changes: 10 additions & 2 deletions examples/react/w3console/src/components/Authenticator.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react'
import {
Authenticator as AuthCore,
SpaceRegistrationPhrase,
useAuthenticator
} from '@w3ui/react-keyring'

Expand Down Expand Up @@ -33,8 +34,15 @@ export function AuthenticationSubmitted (): JSX.Element {
<div className='authenticator'>
<div className='bg-gray-400 px-24 py-16 rounded-md'>
<h1 className='text-xl'>Verify your email address!</h1>
<p className='pt-2 pb-4'>
Click the link in the email we sent to {email} to sign in.
<p className='py-2'>
We've just sent an email to {email}.
</p>
<p className='py-2'>
Please verify that the phrase in the email matches the following words:
</p>
<SpaceRegistrationPhrase className='block font-mono font-lg bg-white/75 my-4 p-2'/>
<p className='pb-4'>
If it does, please click "Verify email address" to sign in.
</p>
<AuthCore.CancelButton className='w3ui-button w-full'>
Cancel
Expand Down
6 changes: 5 additions & 1 deletion packages/keyring-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ export interface KeyringContextState {
agent?: Signer
}

export interface RegisterSpaceOptions {
handlePhrase: (phrase: string) => void
}

export interface KeyringContextActions {
/**
* Load the user agent and all stored data from secure storage.
Expand Down Expand Up @@ -117,7 +121,7 @@ export interface KeyringContextActions {
* storage. Use cancelRegisterSpace to abort. Automatically sets the
* newly registered space as the current space.
*/
registerSpace: (email: string) => Promise<void>
registerSpace: (email: string, options: RegisterSpaceOptions) => Promise<void>
/**
* Abort an ongoing account registration.
*/
Expand Down
25 changes: 21 additions & 4 deletions packages/react-keyring/src/Authenticator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,13 @@ export type AuthenticatorContextState = KeyringContextState & {
* A callback that can be passed to an `onSubmit` handler to
* register a new space or log in using `email`
*/
handleRegisterSubmit?: (e: React.FormEvent<HTMLFormElement>) => Promise<void>
handleRegisterSubmit?: (e: React.FormEvent<HTMLFormElement>) => Promise<void>,
/**
* A short phrase generated by the access API that should be presented to
* the user on the email verification wait screen. Users should be instructed
* to verify that the phrase in their email matches this phrase.
*/
spaceRegistrationPhrase?: string
}

export type AuthenticatorContextActions = KeyringContextActions & {
Expand Down Expand Up @@ -103,14 +109,15 @@ export const AuthenticatorRoot: Component<AuthenticatorRootProps> =
const { createSpace, registerSpace } = actions
const [email, setEmail] = useState('')
const [submitted, setSubmitted] = useState(false)
const [spaceRegistrationPhrase, setSpaceRegistrationPhrase] = useState('')

const handleRegisterSubmit = useCallback(
async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault()
setSubmitted(true)
try {
await createSpace()
await registerSpace(email)
await registerSpace(email, { handlePhrase: (phrase) => { setSpaceRegistrationPhrase(phrase) } })
} catch (error: any) {
throw new Error('failed to register', { cause: error })
} finally {
Expand All @@ -122,10 +129,10 @@ export const AuthenticatorRoot: Component<AuthenticatorRootProps> =

const value = useMemo<AuthenticatorContextValue>(
() => [
{ ...state, email, submitted, handleRegisterSubmit },
{ ...state, email, submitted, handleRegisterSubmit, spaceRegistrationPhrase },
{ ...actions, setEmail }
],
[state, actions, email, submitted, handleRegisterSubmit]
[state, actions, email, submitted, handleRegisterSubmit, spaceRegistrationPhrase]
)
return (
<AgentLoader>
Expand Down Expand Up @@ -194,6 +201,16 @@ export const CancelButton: Component<CancelButtonProps> = createComponent(
}
)

export type SpaceRegistrationPhraseOptions<T extends As = 'button'> = Options<T>
export type SpaceRegistrationPhraseProps<T extends As = 'button'> = Props<CancelButtonOptions<T>>

export const SpaceRegistrationPhrase: Component<SpaceRegistrationPhraseProps> = createComponent(
(props) => {
const [{spaceRegistrationPhrase}] = useAuthenticator()
return createElement('span', {...props, children: <>{spaceRegistrationPhrase}</>})
}
)

/**
* Use the scoped authenticator context state from a parent `Authenticator`.
*/
Expand Down
7 changes: 4 additions & 3 deletions packages/react-keyring/src/providers/Keyring.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import {
import type {
KeyringContextState,
KeyringContextActions,
ServiceConfig
ServiceConfig,
RegisterSpaceOptions
} from '@w3ui/keyring-core'
import type { Agent } from '@web3-storage/access'
import type { Abilities } from '@web3-storage/access/types'
Expand Down Expand Up @@ -102,13 +103,13 @@ export function KeyringProvider ({
return did
}

const registerSpace = async (email: string): Promise<void> => {
const registerSpace = async (email: string, opts: RegisterSpaceOptions): Promise<void> => {
const agent = await getAgent()
const controller = new AbortController()
setRegisterAbortController(controller)

try {
await agent.registerSpace(email, { signal: controller.signal })
await agent.registerSpace(email, {...opts, signal: controller.signal })
setSpace(getCurrentSpace(agent))
setSpaces(getSpaces(agent))
} catch (error) {
Expand Down

0 comments on commit 9734cb2

Please sign in to comment.