mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import React from 'react'
2import {StyleSheet} from 'react-native'
3import {WebView, WebViewNavigation} from 'react-native-webview'
4import {ShouldStartLoadRequest} from 'react-native-webview/lib/WebViewTypes'
5
6import {SignupState} from '#/screens/Signup/state'
7
8const ALLOWED_HOSTS = [
9 'bsky.social',
10 'bsky.app',
11 'staging.bsky.app',
12 'staging.bsky.dev',
13 'js.hcaptcha.com',
14 'newassets.hcaptcha.com',
15 'api2.hcaptcha.com',
16]
17
18export function CaptchaWebView({
19 url,
20 stateParam,
21 state,
22 onSuccess,
23 onError,
24}: {
25 url: string
26 stateParam: string
27 state?: SignupState
28 onSuccess: (code: string) => void
29 onError: (error: unknown) => void
30}) {
31 const redirectHost = React.useMemo(() => {
32 if (!state?.serviceUrl) return 'bsky.app'
33
34 return state?.serviceUrl &&
35 new URL(state?.serviceUrl).host === 'staging.bsky.dev'
36 ? 'staging.bsky.app'
37 : 'bsky.app'
38 }, [state?.serviceUrl])
39
40 const wasSuccessful = React.useRef(false)
41
42 const onShouldStartLoadWithRequest = React.useCallback(
43 (event: ShouldStartLoadRequest) => {
44 const urlp = new URL(event.url)
45 return ALLOWED_HOSTS.includes(urlp.host)
46 },
47 [],
48 )
49
50 const onNavigationStateChange = React.useCallback(
51 (e: WebViewNavigation) => {
52 if (wasSuccessful.current) return
53
54 const urlp = new URL(e.url)
55 if (urlp.host !== redirectHost) return
56
57 const code = urlp.searchParams.get('code')
58 if (urlp.searchParams.get('state') !== stateParam || !code) {
59 onError({error: 'Invalid state or code'})
60 return
61 }
62
63 wasSuccessful.current = true
64 onSuccess(code)
65 },
66 [redirectHost, stateParam, onSuccess, onError],
67 )
68
69 return (
70 <WebView
71 source={{uri: url}}
72 javaScriptEnabled
73 style={styles.webview}
74 onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
75 onNavigationStateChange={onNavigationStateChange}
76 scrollEnabled={false}
77 onError={e => {
78 onError(e.nativeEvent)
79 }}
80 onHttpError={e => {
81 onError(e.nativeEvent)
82 }}
83 />
84 )
85}
86
87const styles = StyleSheet.create({
88 webview: {
89 flex: 1,
90 backgroundColor: 'transparent',
91 borderRadius: 10,
92 },
93})