diff --git a/config/config.go b/config/config.go index 750c52a..9ed9bfe 100644 --- a/config/config.go +++ b/config/config.go @@ -23,4 +23,9 @@ type Config struct { HomepageUrl string RegisterUrl string ServerName string + + Captcha struct { + Type string + SiteKey string + } } diff --git a/frontend/package.json b/frontend/package.json index 3682cf8..e3923d7 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -12,13 +12,15 @@ "dependencies": { "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", + "@marsidev/react-turnstile": "^0.3.1", "@mui/icons-material": "^5.14.9", "@mui/material": "^5.14.10", "immer": "^10.0.2", "jotai": "^2.4.2", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-router-dom": "^6.16.0" + "react-router-dom": "^6.16.0", + "swr": "^2.2.2" }, "devDependencies": { "@types/node": "^20.6.2", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index bd3b30b..192d465 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -11,6 +11,9 @@ dependencies: '@emotion/styled': specifier: ^11.11.0 version: 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.21)(react@18.2.0) + '@marsidev/react-turnstile': + specifier: ^0.3.1 + version: 0.3.1(react-dom@18.2.0)(react@18.2.0) '@mui/icons-material': specifier: ^5.14.9 version: 5.14.9(@mui/material@5.14.10)(@types/react@18.2.21)(react@18.2.0) @@ -32,6 +35,9 @@ dependencies: react-router-dom: specifier: ^6.16.0 version: 6.16.0(react-dom@18.2.0)(react@18.2.0) + swr: + specifier: ^2.2.2 + version: 2.2.2(react@18.2.0) devDependencies: '@types/node': @@ -527,6 +533,16 @@ packages: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} dev: true + /@marsidev/react-turnstile@0.3.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-XnpIUqufuZp2VoC14fmYztB2/8lSABh8eFG6TWAR7Loipdy0p2lZXzuvUOTcQl69j1XKvWu3WChFCBWx/Cbd1A==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + dependencies: + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@mui/base@5.0.0-beta.16(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-OYxhC81c9bO0wobGcM8rrY5bRwpCXAI21BL0P2wz/2vTv4ek7ALz9+U5M8wgdmtRNUhmCmAB4L2WRwFRf5Cd8Q==} engines: {node: '>=12.0.0'} @@ -1139,6 +1155,10 @@ packages: supports-color: 7.2.0 dev: true + /client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + dev: false + /clsx@2.0.0: resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==} engines: {node: '>=6'} @@ -2035,6 +2055,16 @@ packages: engines: {node: '>= 0.4'} dev: false + /swr@2.2.2(react@18.2.0): + resolution: {integrity: sha512-CbR41AoMD4TQBQw9ic3GTXspgfM9Y8Mdhb5Ob4uIKXhWqnRLItwA5fpGvB7SmSw3+zEjb0PdhiEumtUvYoQ+bQ==} + peerDependencies: + react: ^16.11.0 || ^17.0.0 || ^18.0.0 + dependencies: + client-only: 0.0.1 + react: 18.2.0 + use-sync-external-store: 1.2.0(react@18.2.0) + dev: false + /text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true @@ -2084,6 +2114,14 @@ packages: punycode: 2.3.0 dev: true + /use-sync-external-store@1.2.0(react@18.2.0): + resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + react: 18.2.0 + dev: false + /vite@4.4.9(@types/node@20.6.2): resolution: {integrity: sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==} engines: {node: ^14.18.0 || >=16.0.0} diff --git a/frontend/src/apis/model.ts b/frontend/src/apis/model.ts index 03e01c8..1792e57 100644 --- a/frontend/src/apis/model.ts +++ b/frontend/src/apis/model.ts @@ -11,4 +11,11 @@ export interface Api { data: T } -export type ApiErr = Api \ No newline at end of file +export type ApiErr = Api + +interface captcha { + type: string + siteKey: string +} + +export type ApiCaptcha = Api \ No newline at end of file diff --git a/frontend/src/components/TurnstileWidget.tsx b/frontend/src/components/TurnstileWidget.tsx new file mode 100644 index 0000000..e221207 --- /dev/null +++ b/frontend/src/components/TurnstileWidget.tsx @@ -0,0 +1,38 @@ +import { Turnstile } from '@marsidev/react-turnstile' +import Button from '@mui/material/Button' +import { useRef, useState, memo } from 'react' +import type { TurnstileInstance } from '@marsidev/react-turnstile' +import useSWR from "swr"; +import { ApiCaptcha } from '@/apis/model'; +import Alert from '@mui/material/Alert'; +import Skeleton from '@mui/material/Skeleton'; + +interface prop { + onSuccess: ((token: string) => void) +} + +const TurnstileWidget = memo(({ onSuccess }: prop) => { + const ref = useRef(null) + const [key, setKey] = useState(1) + const { data, error, isLoading } = useSWR(import.meta.env.VITE_APIADDR + '/api/v1/captcha') + + if (error) { + console.warn(error) + return {String(error)} + } + if (isLoading) { + return + } + if (data?.code != 0) { + console.warn(error) + return {String(data?.msg)} + } + return ( + <> + + + + ) +}) + +export default TurnstileWidget \ No newline at end of file diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index c65c6fd..8c1d783 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -2,11 +2,16 @@ import React from 'react' import ReactDOM from 'react-dom/client' import App from './App.tsx' import CssBaseline from '@mui/material/CssBaseline'; +import { SWRConfig } from 'swr' ReactDOM.createRoot(document.getElementById('root')!).render( - + + fetch(resource, init).then(res => res.json()) + }}> - + + ) diff --git a/frontend/src/views/Register.tsx b/frontend/src/views/Register.tsx index 1405793..34aa619 100644 --- a/frontend/src/views/Register.tsx +++ b/frontend/src/views/Register.tsx @@ -16,6 +16,7 @@ import Alert from '@mui/material/Alert'; import Snackbar from '@mui/material/Snackbar'; import Loading from '@/components/Loading' import { useNavigate } from "react-router-dom"; +import TurnstileWidget from '@/components/TurnstileWidget'; export default function SignUp() { const [regErr, setRegErr] = useState(""); @@ -119,6 +120,9 @@ export default function SignUp() { autoComplete="new-password" /> + + console.log(v)} /> +