Skip to content

Commit

Permalink
remove sign-in page
Browse files Browse the repository at this point in the history
  • Loading branch information
stormcloud266 authored and youngkidwarrior committed Aug 30, 2024
1 parent 4e1ef47 commit 4c333ed
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 107 deletions.
74 changes: 0 additions & 74 deletions packages/app/features/auth/components/SignInButton.tsx

This file was deleted.

84 changes: 67 additions & 17 deletions packages/app/features/auth/sign-up/sign-up-form.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
import { useState } from 'react'
import { Turnstile } from '@marsidev/react-turnstile'
import { BigHeading, ButtonText, H3, Paragraph, SubmitButton, XStack, YStack } from '@my/ui'
import {
BigHeading,
ButtonText,
H3,
Paragraph,
SubmitButton,
XStack,
YStack,
useToastController,
} from '@my/ui'
import { TRPCClientError } from '@trpc/client'
import { bytesToHex, hexToBytes } from 'viem'
import { useRouter } from 'solito/router'
import { z } from 'zod'
import { FormProvider, useForm } from 'react-hook-form'
import { RecoveryOptions } from '@my/api/src/routers/account-recovery/types'
import { VerifyCode } from 'app/features/auth/components/VerifyCode'
import { SchemaForm, formFields } from 'app/utils/SchemaForm'
import { api } from 'app/utils/api'
import { useState } from 'react'
import { FormProvider, useForm } from 'react-hook-form'
import { useRouter } from 'solito/router'
import { z } from 'zod'
import { SignInButton } from '../components/SignInButton'
import { formatErrorMessage } from 'app/features/splash/screen'
import { formatErrorMessage } from 'app/utils/formatErrorMessage'
import { signChallenge } from 'app/utils/signChallenge'
import { useAuthScreenParams } from 'app/routers/params'

const SignUpSchema = z.object({
countrycode: formFields.countrycode,
Expand All @@ -20,8 +32,51 @@ export const SignUpForm = () => {
const form = useForm<z.infer<typeof SignUpSchema>>()
const signInWithOtp = api.auth.signInWithOtp.useMutation()
const router = useRouter()
const [queryParams] = useAuthScreenParams()
const { redirectUri } = queryParams
const toast = useToastController()
const [captchaToken, setCaptchaToken] = useState<string | undefined>()
const [signInError, setSignInError] = useState<Error | null>(null)
const [isSigningIn, setIsSigningIn] = useState(false)

const { mutateAsync: getChallengeMutateAsync } = api.challenge.getChallenge.useMutation({
retry: false,
})
const { mutateAsync: validateSignatureMutateAsync } = api.challenge.validateSignature.useMutation(
{ retry: false }
)

const handleSignIn = async () => {
setIsSigningIn(true)
try {
const challengeData = await getChallengeMutateAsync()

const rawIdsB64: { id: string; userHandle: string }[] = []
const { encodedWebAuthnSig, accountName, keySlot } = await signChallenge(
challengeData.challenge as `0x${string}`,
rawIdsB64
)

const encodedWebAuthnSigBytes = hexToBytes(encodedWebAuthnSig)
const newEncodedWebAuthnSigBytes = new Uint8Array(encodedWebAuthnSigBytes.length + 1)
newEncodedWebAuthnSigBytes[0] = keySlot
newEncodedWebAuthnSigBytes.set(encodedWebAuthnSigBytes, 1)

await validateSignatureMutateAsync({
recoveryType: RecoveryOptions.WEBAUTHN,
signature: bytesToHex(newEncodedWebAuthnSigBytes),
challengeId: challengeData.id,
identifier: `${accountName}.${keySlot}`,
})

router.push(redirectUri ?? '/')
} catch (error) {
toast.show('Failed to sign in', { preset: 'error', isUrgent: true })
setSignInError(error as Error)
} finally {
setIsSigningIn(false)
}
}

async function signUpWithPhone({ phone, countrycode }: z.infer<typeof SignUpSchema>) {
const { error } = await signInWithOtp
Expand Down Expand Up @@ -134,16 +189,11 @@ export const SignUpForm = () => {
<Paragraph size="$2" color="$color11">
Already have an account?
</Paragraph>
<SignInButton
setError={setSignInError}
unstyled
color="$color11"
renderButtonText={(isSigningIn) => (
<ButtonText textDecorationLine="underline">
{isSigningIn ? 'Signing in...' : 'Sign in'}
</ButtonText>
)}
/>
<SubmitButton onPress={handleSignIn} disabled={isSigningIn} unstyled>
<ButtonText color="$color11" size="$2" textDecorationLine="underline">
{isSigningIn ? 'Signing in...' : 'Sign in'}
</ButtonText>
</SubmitButton>
</XStack>

{signInError && (
Expand Down
70 changes: 59 additions & 11 deletions packages/app/features/splash/screen.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
Button,
ButtonText,
H1,
LinearGradient,
Paragraph,
Expand All @@ -18,14 +19,14 @@ import { SolitoImage } from 'solito/image'
import { useLink } from 'solito/link'
import { AnimationLayout } from '../../components/layout/animation-layout'
import { useState } from 'react'
import { SignInButton } from '../auth/components/SignInButton'

export const formatErrorMessage = (error: Error) => {
if (error.message.startsWith('The operation either timed out or was not allowed')) {
return 'Passkey Authentication Failed'
}
return error.message
}
import { formatErrorMessage } from 'app/utils/formatErrorMessage'
import { RecoveryOptions } from '@my/api/src/routers/account-recovery/types'
import { SubmitButton, useToastController } from '@my/ui'
import { api } from 'app/utils/api'
import { signChallenge } from 'app/utils/signChallenge'
import { useRouter } from 'solito/router'
import { bytesToHex, hexToBytes } from 'viem'
import { useAuthScreenParams } from 'app/routers/params'

export function SplashScreen() {
return (
Expand Down Expand Up @@ -149,7 +150,7 @@ function Hero() {
height={isWeb ? '100dvh' : '100%'}
>
<Stack
bc="$black"
bc="$color1"
pos="absolute"
top={0}
left={0}
Expand Down Expand Up @@ -243,8 +244,52 @@ function Hero() {
}

function AuthButtons() {
const [signInError, setSignInError] = useState<Error | null>(null)
const [queryParams] = useAuthScreenParams()
const { redirectUri } = queryParams
const toast = useToastController()
const router = useRouter()
const signUpLink = useLink({ href: '/auth/sign-up' })
const [signInError, setSignInError] = useState<Error | null>(null)
const [isSigningIn, setIsSigningIn] = useState(false)

const { mutateAsync: getChallengeMutateAsync } = api.challenge.getChallenge.useMutation({
retry: false,
})
const { mutateAsync: validateSignatureMutateAsync } = api.challenge.validateSignature.useMutation(
{ retry: false }
)

const handleSignIn = async () => {
setIsSigningIn(true)
try {
const challengeData = await getChallengeMutateAsync()

const rawIdsB64: { id: string; userHandle: string }[] = []
const { encodedWebAuthnSig, accountName, keySlot } = await signChallenge(
challengeData.challenge as `0x${string}`,
rawIdsB64
)

const encodedWebAuthnSigBytes = hexToBytes(encodedWebAuthnSig)
const newEncodedWebAuthnSigBytes = new Uint8Array(encodedWebAuthnSigBytes.length + 1)
newEncodedWebAuthnSigBytes[0] = keySlot
newEncodedWebAuthnSigBytes.set(encodedWebAuthnSigBytes, 1)

await validateSignatureMutateAsync({
recoveryType: RecoveryOptions.WEBAUTHN,
signature: bytesToHex(newEncodedWebAuthnSigBytes),
challengeId: challengeData.id,
identifier: `${accountName}.${keySlot}`,
})

router.push(redirectUri ?? '/')
} catch (error) {
toast.show('Failed to sign in', { preset: 'error', isUrgent: true })
setSignInError(error as Error)
} finally {
setIsSigningIn(false)
}
}

return (
<XStack
Expand All @@ -256,7 +301,10 @@ function AuthButtons() {
w="100%"
alignSelf="center"
>
<SignInButton setError={setSignInError} size="$4" w="$12" />
<SubmitButton size="$4" w="$12" onPress={handleSignIn} disabled={isSigningIn}>
<ButtonText>{isSigningIn ? 'SIGNING IN...' : 'SIGN-IN'}</ButtonText>
</SubmitButton>

<Button {...signUpLink} borderColor="$primary" variant="outlined" size="$4" w="$12">
<Button.Text color="$white" $gtMd={{ color: '$color12' }}>
SIGN-UP
Expand Down
7 changes: 2 additions & 5 deletions packages/app/features/unknown/screen.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import { Button, Container, H1, H2, YStack } from '@my/ui'
import { Link } from 'solito/link'
import { Container, H1, H2, YStack, LinkableButton } from '@my/ui'

export function UnknownScreen() {
return (
<Container>
<YStack jc={'center'} alignItems="center" f={1} gap="$6">
<H1>Not found.</H1>
<H2>Send, Instant Payments.</H2>
<Link href="/">
<Button>Need to sign in?</Button>
</Link>
<LinkableButton href="/">Need to sign in?</LinkableButton>
</YStack>
</Container>
)
Expand Down
17 changes: 17 additions & 0 deletions packages/app/utils/formatErrorMessage.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { formatErrorMessage } from './formatErrorMessage'

describe('formatErrorMessage', () => {
it('should return "Passkey Authentication Failed"', () => {
const error = new Error(
'The operation either timed out or was not allowed due to security reasons'
)
const result = formatErrorMessage(error)
expect(result).toBe('Passkey Authentication Failed')
})

it('should return the original error message', () => {
const error = new Error('Some other error message')
const result = formatErrorMessage(error)
expect(result).toBe('Some other error message')
})
})
6 changes: 6 additions & 0 deletions packages/app/utils/formatErrorMessage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const formatErrorMessage = (error: Error) => {
if (error.message.startsWith('The operation either timed out or was not allowed')) {
return 'Passkey Authentication Failed'
}
return error.message
}

0 comments on commit 4c333ed

Please sign in to comment.