Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
new-api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
b32cecb4
authored
Jan 03, 2026
by
Seefs
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: check-in feature integrates Turnstile security check
parent
ea60d305
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
70 additions
and
13 deletions
+70
-13
router/api-router.go
+1
-1
web/src/components/settings/PersonalSetting.jsx
+6
-1
web/src/components/settings/personal/cards/CheckinCalendar.jsx
+57
-5
web/src/services/secureVerification.js
+6
-6
No files found.
router/api-router.go
View file @
b32cecb4
...
...
@@ -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
(
"/"
)
...
...
web/src/components/settings/PersonalSetting.jsx
View file @
b32cecb4
...
...
@@ -451,7 +451,12 @@ const PersonalSetting = () => {
{
/* 签到日历 - 仅在启用时显示 */
}
{
status
?.
checkin_enabled
&&
(
<
div
className=
'mt-4 md:mt-6'
>
<
CheckinCalendar
t=
{
t
}
status=
{
status
}
/>
<
CheckinCalendar
t=
{
t
}
status=
{
status
}
turnstileEnabled=
{
turnstileEnabled
}
turnstileSiteKey=
{
turnstileSiteKey
}
/>
</
div
>
)
}
...
...
web/src/components/settings/personal/cards/CheckinCalendar.jsx
View file @
b32cecb4
...
...
@@ -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
(
<
Card
className=
'!rounded-2xl'
>
<
Modal
title=
'Security Check'
visible=
{
turnstileModalVisible
}
footer=
{
null
}
centered
onCancel=
{
()
=>
{
setTurnstileModalVisible
(
false
);
setTurnstileWidgetKey
((
v
)
=>
v
+
1
);
}
}
>
<
div
className=
'flex justify-center py-2'
>
<
Turnstile
key=
{
turnstileWidgetKey
}
sitekey=
{
turnstileSiteKey
}
onVerify=
{
(
token
)
=>
{
doCheckin
(
token
);
}
}
onExpire=
{
()
=>
{
setTurnstileWidgetKey
((
v
)
=>
v
+
1
);
}
}
/>
</
div
>
</
Modal
>
{
/* 卡片头部 */
}
<
div
className=
'flex items-center justify-between'
>
<
div
...
...
@@ -221,7 +273,7 @@ const CheckinCalendar = ({ t, status }) => {
type=
'primary'
theme=
'solid'
icon=
{
<
Gift
size=
{
16
}
/>
}
onClick=
{
doCheckin
}
onClick=
{
()
=>
doCheckin
()
}
loading=
{
checkinLoading
||
!
initialLoaded
}
disabled=
{
!
initialLoaded
||
checkinData
.
stats
?.
checked_in_today
}
className=
'!bg-green-600 hover:!bg-green-700'
...
...
web/src/services/secureVerification.js
View file @
b32cecb4
...
...
@@ -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
&&
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment