From fbdf4517c29d87a2bd0d837fb732f93d255d6f64 Mon Sep 17 00:00:00 2001
From: Hailey <me@haileyok.com>
Date: Sat, 17 Feb 2024 16:03:47 -0800
Subject: Implement captcha (#2882)

* web height adjustment

border radius incase of dark/dim mismatch

rm country codes

adjust height

general form refactor

more form refactor

refactor form submission

activity indicator after finished

remove remaining phone stuff

adjust captcha height

adjust state to reflect switch

move handle to the second step

pass color scheme param

ts

ts

update state when captcha is complete

web views and callbacks

remove old state

allow specified hosts

replace phone verification with a webview

* remove log

* height adjustment

* few changes

* use the correct url

* remove some debug

* validate handle before continuing

* explicitly check if there is a did, dont rely on error

* rm throw

* update allowed hosts

* update redirect host for webview

* fix handle

* fix handle check

* adjust height for full challenge
---
 src/view/com/auth/create/CaptchaWebView.tsx | 86 +++++++++++++++++++++++++++++
 1 file changed, 86 insertions(+)
 create mode 100644 src/view/com/auth/create/CaptchaWebView.tsx

(limited to 'src/view/com/auth/create/CaptchaWebView.tsx')

diff --git a/src/view/com/auth/create/CaptchaWebView.tsx b/src/view/com/auth/create/CaptchaWebView.tsx
new file mode 100644
index 000000000..b0de8b4a4
--- /dev/null
+++ b/src/view/com/auth/create/CaptchaWebView.tsx
@@ -0,0 +1,86 @@
+import React from 'react'
+import {WebView, WebViewNavigation} from 'react-native-webview'
+import {ShouldStartLoadRequest} from 'react-native-webview/lib/WebViewTypes'
+import {StyleSheet} from 'react-native'
+import {CreateAccountState} from 'view/com/auth/create/state'
+
+const ALLOWED_HOSTS = [
+  'bsky.social',
+  'bsky.app',
+  'staging.bsky.app',
+  'staging.bsky.dev',
+  'js.hcaptcha.com',
+  'newassets.hcaptcha.com',
+  'api2.hcaptcha.com',
+]
+
+export function CaptchaWebView({
+  url,
+  stateParam,
+  uiState,
+  onSuccess,
+  onError,
+}: {
+  url: string
+  stateParam: string
+  uiState?: CreateAccountState
+  onSuccess: (code: string) => void
+  onError: () => void
+}) {
+  const redirectHost = React.useMemo(() => {
+    if (!uiState?.serviceUrl) return 'bsky.app'
+
+    return uiState?.serviceUrl &&
+      new URL(uiState?.serviceUrl).host === 'staging.bsky.dev'
+      ? 'staging.bsky.app'
+      : 'bsky.app'
+  }, [uiState?.serviceUrl])
+
+  const wasSuccessful = React.useRef(false)
+
+  const onShouldStartLoadWithRequest = React.useCallback(
+    (event: ShouldStartLoadRequest) => {
+      const urlp = new URL(event.url)
+      return ALLOWED_HOSTS.includes(urlp.host)
+    },
+    [],
+  )
+
+  const onNavigationStateChange = React.useCallback(
+    (e: WebViewNavigation) => {
+      if (wasSuccessful.current) return
+
+      const urlp = new URL(e.url)
+      if (urlp.host !== redirectHost) return
+
+      const code = urlp.searchParams.get('code')
+      if (urlp.searchParams.get('state') !== stateParam || !code) {
+        onError()
+        return
+      }
+
+      wasSuccessful.current = true
+      onSuccess(code)
+    },
+    [redirectHost, stateParam, onSuccess, onError],
+  )
+
+  return (
+    <WebView
+      source={{uri: url}}
+      javaScriptEnabled
+      style={styles.webview}
+      onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
+      onNavigationStateChange={onNavigationStateChange}
+      scrollEnabled={false}
+    />
+  )
+}
+
+const styles = StyleSheet.create({
+  webview: {
+    flex: 1,
+    backgroundColor: 'transparent',
+    borderRadius: 10,
+  },
+})
-- 
cgit 1.4.1

