implement the attestation client, update captcha loop
This commit is contained in:
+1
-1
@@ -186,7 +186,7 @@
|
|||||||
"react-native": "^0.79.3",
|
"react-native": "^0.79.3",
|
||||||
"react-native-compressor": "^1.11.0",
|
"react-native-compressor": "^1.11.0",
|
||||||
"react-native-date-picker": "^5.0.12",
|
"react-native-date-picker": "^5.0.12",
|
||||||
"react-native-device-attest": "^0.1.1",
|
"react-native-device-attest": "^0.1.4",
|
||||||
"react-native-drawer-layout": "^4.1.8",
|
"react-native-drawer-layout": "^4.1.8",
|
||||||
"react-native-edge-to-edge": "^1.6.0",
|
"react-native-edge-to-edge": "^1.6.0",
|
||||||
"react-native-gesture-handler": "2.25.0",
|
"react-native-gesture-handler": "2.25.0",
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import React from 'react'
|
import React, {useEffect, useState} from 'react'
|
||||||
import {ActivityIndicator, View} from 'react-native'
|
import {ActivityIndicator, Platform, View} from 'react-native'
|
||||||
|
import ReactNativeDeviceAttest from 'react-native-device-attest'
|
||||||
import {msg} from '@lingui/macro'
|
import {msg} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {nanoid} from 'nanoid/non-secure'
|
import {nanoid} from 'nanoid/non-secure'
|
||||||
|
|
||||||
import {createFullHandle} from '#/lib/strings/handles'
|
import {createFullHandle} from '#/lib/strings/handles'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {isWeb} from '#/platform/detection'
|
import {isAndroid, isIOS, isNative, isWeb} from '#/platform/detection'
|
||||||
import {ScreenTransition} from '#/screens/Login/ScreenTransition'
|
import {ScreenTransition} from '#/screens/Login/ScreenTransition'
|
||||||
import {useSignupContext} from '#/screens/Signup/state'
|
import {useSignupContext} from '#/screens/Signup/state'
|
||||||
import {CaptchaWebView} from '#/screens/Signup/StepCaptcha/CaptchaWebView'
|
import {CaptchaWebView} from '#/screens/Signup/StepCaptcha/CaptchaWebView'
|
||||||
@@ -16,9 +17,56 @@ import {BackNextButtons} from '../BackNextButtons'
|
|||||||
|
|
||||||
const CAPTCHA_PATH = isWeb ? '/gate/signup' : '/gate/signup/attempt-attest'
|
const CAPTCHA_PATH = isWeb ? '/gate/signup' : '/gate/signup/attempt-attest'
|
||||||
|
|
||||||
type
|
|
||||||
|
|
||||||
export function StepCaptcha() {
|
export function StepCaptcha() {
|
||||||
|
if (isWeb) {
|
||||||
|
return <StepCaptchaInner />
|
||||||
|
} else {
|
||||||
|
return <StepCaptchaNative />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function StepCaptchaNative() {
|
||||||
|
const [token, setToken] = useState<string>()
|
||||||
|
const [payload, setPayload] = useState<string>()
|
||||||
|
const [ready, setReady] = useState(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
;(async () => {
|
||||||
|
logger.debug('trying to generate attestation token...')
|
||||||
|
try {
|
||||||
|
if (isIOS) {
|
||||||
|
logger.debug('starting to generate devicecheck token...')
|
||||||
|
const token = await ReactNativeDeviceAttest.getDeviceCheckToken()
|
||||||
|
setToken(encodeURIComponent(token))
|
||||||
|
logger.debug(`generated devicecheck token: ${token}`)
|
||||||
|
} else {
|
||||||
|
const {token, payload} =
|
||||||
|
await ReactNativeDeviceAttest.getIntegrityToken('signup')
|
||||||
|
setToken(encodeURIComponent(token))
|
||||||
|
setPayload(encodeURIComponent(base64UrlEncode(payload)))
|
||||||
|
}
|
||||||
|
} catch (e: any) {
|
||||||
|
logger.error(e)
|
||||||
|
} finally {
|
||||||
|
setReady(true)
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
if (!ready) {
|
||||||
|
return <View />
|
||||||
|
}
|
||||||
|
|
||||||
|
return <StepCaptchaInner token={token} payload={payload} />
|
||||||
|
}
|
||||||
|
|
||||||
|
function StepCaptchaInner({
|
||||||
|
token,
|
||||||
|
payload,
|
||||||
|
}: {
|
||||||
|
token?: string
|
||||||
|
payload?: string
|
||||||
|
}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
const {state, dispatch} = useSignupContext()
|
const {state, dispatch} = useSignupContext()
|
||||||
@@ -27,6 +75,7 @@ export function StepCaptcha() {
|
|||||||
|
|
||||||
const stateParam = React.useMemo(() => nanoid(15), [])
|
const stateParam = React.useMemo(() => nanoid(15), [])
|
||||||
const url = React.useMemo(() => {
|
const url = React.useMemo(() => {
|
||||||
|
console.log(`service url: ${state.serviceUrl}`)
|
||||||
const newUrl = new URL(state.serviceUrl)
|
const newUrl = new URL(state.serviceUrl)
|
||||||
newUrl.pathname = CAPTCHA_PATH
|
newUrl.pathname = CAPTCHA_PATH
|
||||||
newUrl.searchParams.set(
|
newUrl.searchParams.set(
|
||||||
@@ -36,8 +85,26 @@ export function StepCaptcha() {
|
|||||||
newUrl.searchParams.set('state', stateParam)
|
newUrl.searchParams.set('state', stateParam)
|
||||||
newUrl.searchParams.set('colorScheme', theme.name)
|
newUrl.searchParams.set('colorScheme', theme.name)
|
||||||
|
|
||||||
|
if (isNative && token) {
|
||||||
|
newUrl.searchParams.set('platform', Platform.OS)
|
||||||
|
newUrl.searchParams.set('token', token)
|
||||||
|
if (isAndroid && payload) {
|
||||||
|
newUrl.searchParams.set('payload', payload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(newUrl.href)
|
||||||
|
|
||||||
return newUrl.href
|
return newUrl.href
|
||||||
}, [state.serviceUrl, state.handle, state.userDomain, stateParam, theme.name])
|
}, [
|
||||||
|
state.serviceUrl,
|
||||||
|
state.handle,
|
||||||
|
state.userDomain,
|
||||||
|
stateParam,
|
||||||
|
theme.name,
|
||||||
|
token,
|
||||||
|
payload,
|
||||||
|
])
|
||||||
|
|
||||||
const onSuccess = React.useCallback(
|
const onSuccess = React.useCallback(
|
||||||
(code: string) => {
|
(code: string) => {
|
||||||
@@ -108,3 +175,13 @@ export function StepCaptcha() {
|
|||||||
</ScreenTransition>
|
</ScreenTransition>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function base64UrlEncode(data: string): string {
|
||||||
|
const encoder = new TextEncoder()
|
||||||
|
const bytes = encoder.encode(data)
|
||||||
|
|
||||||
|
const binaryString = String.fromCharCode(...bytes)
|
||||||
|
const base64 = btoa(binaryString)
|
||||||
|
|
||||||
|
return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/[=]/g, '')
|
||||||
|
}
|
||||||
|
|||||||
@@ -16787,10 +16787,10 @@ react-native-date-picker@^5.0.12:
|
|||||||
resolved "https://registry.yarnpkg.com/react-native-date-picker/-/react-native-date-picker-5.0.12.tgz#12540b6a58500811ee7e4fc0244e3accc7cca9c1"
|
resolved "https://registry.yarnpkg.com/react-native-date-picker/-/react-native-date-picker-5.0.12.tgz#12540b6a58500811ee7e4fc0244e3accc7cca9c1"
|
||||||
integrity sha512-R/mUnCKhcuxbhKPFwYdBQCxQt9HHLqpM4ruRUqlcBjiUZ3N2wdnwOMyc888Ps8qp8e7v29PrDHtUlG8LPuFn9w==
|
integrity sha512-R/mUnCKhcuxbhKPFwYdBQCxQt9HHLqpM4ruRUqlcBjiUZ3N2wdnwOMyc888Ps8qp8e7v29PrDHtUlG8LPuFn9w==
|
||||||
|
|
||||||
react-native-device-attest@^0.1.1:
|
react-native-device-attest@^0.1.4:
|
||||||
version "0.1.1"
|
version "0.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/react-native-device-attest/-/react-native-device-attest-0.1.1.tgz#5aa55bad2fcc964228656d1b764fb87625afe888"
|
resolved "https://registry.yarnpkg.com/react-native-device-attest/-/react-native-device-attest-0.1.4.tgz#221860443765422f6dfebf4d868f367cda2a61b1"
|
||||||
integrity sha512-dOOaCWPzEISdMubtCbwExhjOe7izZmAUbdk790FCBVqq09Vqepxt/vn2zRKyy4EoUBG8LKLMg22kCko6TJNoPA==
|
integrity sha512-jFogWXXl3NBEAA3U+f1NQwdeIysCu6bGEmMGzz6gw4uipe6ELxZmovx64cJJHessZs1gjYDaUcbXGncirwykYg==
|
||||||
|
|
||||||
react-native-dotenv@^3.4.11:
|
react-native-dotenv@^3.4.11:
|
||||||
version "3.4.11"
|
version "3.4.11"
|
||||||
|
|||||||
Reference in New Issue
Block a user