From c33ac97c7195af2e41d8377cefa91702da4db591 Mon Sep 17 00:00:00 2001 From: Seefs Date: Sat, 3 Jan 2026 11:08:26 +0800 Subject: [PATCH] feat: check-in feature integrates Turnstile security check --- router/api-router.go | 2 +- .../components/settings/PersonalSetting.jsx | 7 ++- .../personal/cards/CheckinCalendar.jsx | 62 +++++++++++++++++-- web/src/services/secureVerification.js | 12 ++-- 4 files changed, 70 insertions(+), 13 deletions(-) diff --git a/router/api-router.go b/router/api-router.go index e02e1c3f3..800c5c657 100644 --- a/router/api-router.go +++ b/router/api-router.go @@ -96,7 +96,7 @@ func SetApiRouter(router *gin.Engine) { // Check-in routes selfRoute.GET("/checkin", controller.GetCheckinStatus) - selfRoute.POST("/checkin", controller.DoCheckin) + selfRoute.POST("/checkin", middleware.TurnstileCheck(), controller.DoCheckin) } adminRoute := userRoute.Group("/") diff --git a/web/src/components/settings/PersonalSetting.jsx b/web/src/components/settings/PersonalSetting.jsx index e70b997cd..657d9b4ff 100644 --- a/web/src/components/settings/PersonalSetting.jsx +++ b/web/src/components/settings/PersonalSetting.jsx @@ -451,7 +451,12 @@ const PersonalSetting = () => { {/* 签到日历 - 仅在启用时显示 */} {status?.checkin_enabled && (
- +
)} diff --git a/web/src/components/settings/personal/cards/CheckinCalendar.jsx b/web/src/components/settings/personal/cards/CheckinCalendar.jsx index d6f57cf69..2298ae94d 100644 --- a/web/src/components/settings/personal/cards/CheckinCalendar.jsx +++ b/web/src/components/settings/personal/cards/CheckinCalendar.jsx @@ -27,6 +27,7 @@ import { Spin, Tooltip, Collapsible, + Modal, } from '@douyinfe/semi-ui'; import { CalendarCheck, @@ -35,11 +36,14 @@ import { ChevronDown, ChevronUp, } from 'lucide-react'; +import Turnstile from 'react-turnstile'; import { API, showError, showSuccess, renderQuota } from '../../../../helpers'; -const CheckinCalendar = ({ t, status }) => { +const CheckinCalendar = ({ t, status, turnstileEnabled, turnstileSiteKey }) => { const [loading, setLoading] = useState(false); const [checkinLoading, setCheckinLoading] = useState(false); + const [turnstileModalVisible, setTurnstileModalVisible] = useState(false); + const [turnstileWidgetKey, setTurnstileWidgetKey] = useState(0); const [checkinData, setCheckinData] = useState({ enabled: false, stats: { @@ -109,11 +113,23 @@ const CheckinCalendar = ({ t, status }) => { } }; - // 执行签到 - const doCheckin = async () => { + const postCheckin = async (token) => { + const url = token + ? `/api/user/checkin?turnstile=${encodeURIComponent(token)}` + : '/api/user/checkin'; + return API.post(url); + }; + + const shouldTriggerTurnstile = (message) => { + if (!turnstileEnabled) return false; + if (typeof message !== 'string') return true; + return message.includes('Turnstile'); + }; + + const doCheckin = async (token) => { setCheckinLoading(true); try { - const res = await API.post('/api/user/checkin'); + const res = await postCheckin(token); const { success, data, message } = res.data; if (success) { showSuccess( @@ -121,7 +137,19 @@ const CheckinCalendar = ({ t, status }) => { ); // 刷新签到状态 fetchCheckinStatus(currentMonth); + setTurnstileModalVisible(false); } else { + if (!token && shouldTriggerTurnstile(message)) { + if (!turnstileSiteKey) { + showError('Turnstile is enabled but site key is empty.'); + return; + } + setTurnstileModalVisible(true); + return; + } + if (token && shouldTriggerTurnstile(message)) { + setTurnstileWidgetKey((v) => v + 1); + } showError(message || t('签到失败')); } } catch (error) { @@ -186,6 +214,30 @@ const CheckinCalendar = ({ t, status }) => { return ( + { + setTurnstileModalVisible(false); + setTurnstileWidgetKey((v) => v + 1); + }} + > +
+ { + doCheckin(token); + }} + onExpire={() => { + setTurnstileWidgetKey((v) => v + 1); + }} + /> +
+
+ {/* 卡片头部 */}
{ type='primary' theme='solid' icon={} - onClick={doCheckin} + onClick={() => doCheckin()} loading={checkinLoading || !initialLoaded} disabled={!initialLoaded || checkinData.stats?.checked_in_today} className='!bg-green-600 hover:!bg-green-700' diff --git a/web/src/services/secureVerification.js b/web/src/services/secureVerification.js index 51f871a96..97b9c0229 100644 --- a/web/src/services/secureVerification.js +++ b/web/src/services/secureVerification.js @@ -42,12 +42,12 @@ export class SecureVerificationService { isPasskeySupported(), ]); - console.log('=== DEBUGGING VERIFICATION METHODS ==='); - console.log('2FA Response:', JSON.stringify(twoFAResponse, null, 2)); - console.log( - 'Passkey Response:', - JSON.stringify(passkeyResponse, null, 2), - ); + // console.log('=== DEBUGGING VERIFICATION METHODS ==='); + // console.log('2FA Response:', JSON.stringify(twoFAResponse, null, 2)); + // console.log( + // 'Passkey Response:', + // JSON.stringify(passkeyResponse, null, 2), + // ); const has2FA = twoFAResponse.data?.success &&