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
93527862
authored
Jan 03, 2026
by
Calcium-Ion
Committed by
GitHub
Jan 03, 2026
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2571 from seefs001/feature/check-in-security-check
feat: check-in feature integrates Turnstile security check
parents
44f9d904
b32cecb4
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 @
93527862
...
@@ -96,7 +96,7 @@ func SetApiRouter(router *gin.Engine) {
...
@@ -96,7 +96,7 @@ func SetApiRouter(router *gin.Engine) {
// Check-in routes
// Check-in routes
selfRoute
.
GET
(
"/checkin"
,
controller
.
GetCheckinStatus
)
selfRoute
.
GET
(
"/checkin"
,
controller
.
GetCheckinStatus
)
selfRoute
.
POST
(
"/checkin"
,
controller
.
DoCheckin
)
selfRoute
.
POST
(
"/checkin"
,
middleware
.
TurnstileCheck
(),
controller
.
DoCheckin
)
}
}
adminRoute
:=
userRoute
.
Group
(
"/"
)
adminRoute
:=
userRoute
.
Group
(
"/"
)
...
...
web/src/components/settings/PersonalSetting.jsx
View file @
93527862
...
@@ -451,7 +451,12 @@ const PersonalSetting = () => {
...
@@ -451,7 +451,12 @@ const PersonalSetting = () => {
{
/* 签到日历 - 仅在启用时显示 */
}
{
/* 签到日历 - 仅在启用时显示 */
}
{
status
?.
checkin_enabled
&&
(
{
status
?.
checkin_enabled
&&
(
<
div
className=
'mt-4 md:mt-6'
>
<
div
className=
'mt-4 md:mt-6'
>
<
CheckinCalendar
t=
{
t
}
status=
{
status
}
/>
<
CheckinCalendar
t=
{
t
}
status=
{
status
}
turnstileEnabled=
{
turnstileEnabled
}
turnstileSiteKey=
{
turnstileSiteKey
}
/>
</
div
>
</
div
>
)
}
)
}
...
...
web/src/components/settings/personal/cards/CheckinCalendar.jsx
View file @
93527862
...
@@ -27,6 +27,7 @@ import {
...
@@ -27,6 +27,7 @@ import {
Spin
,
Spin
,
Tooltip
,
Tooltip
,
Collapsible
,
Collapsible
,
Modal
,
}
from
'@douyinfe/semi-ui'
;
}
from
'@douyinfe/semi-ui'
;
import
{
import
{
CalendarCheck
,
CalendarCheck
,
...
@@ -35,11 +36,14 @@ import {
...
@@ -35,11 +36,14 @@ import {
ChevronDown
,
ChevronDown
,
ChevronUp
,
ChevronUp
,
}
from
'lucide-react'
;
}
from
'lucide-react'
;
import
Turnstile
from
'react-turnstile'
;
import
{
API
,
showError
,
showSuccess
,
renderQuota
}
from
'../../../../helpers'
;
import
{
API
,
showError
,
showSuccess
,
renderQuota
}
from
'../../../../helpers'
;
const
CheckinCalendar
=
({
t
,
status
})
=>
{
const
CheckinCalendar
=
({
t
,
status
,
turnstileEnabled
,
turnstileSiteKey
})
=>
{
const
[
loading
,
setLoading
]
=
useState
(
false
);
const
[
loading
,
setLoading
]
=
useState
(
false
);
const
[
checkinLoading
,
setCheckinLoading
]
=
useState
(
false
);
const
[
checkinLoading
,
setCheckinLoading
]
=
useState
(
false
);
const
[
turnstileModalVisible
,
setTurnstileModalVisible
]
=
useState
(
false
);
const
[
turnstileWidgetKey
,
setTurnstileWidgetKey
]
=
useState
(
0
);
const
[
checkinData
,
setCheckinData
]
=
useState
({
const
[
checkinData
,
setCheckinData
]
=
useState
({
enabled
:
false
,
enabled
:
false
,
stats
:
{
stats
:
{
...
@@ -109,11 +113,23 @@ const CheckinCalendar = ({ t, status }) => {
...
@@ -109,11 +113,23 @@ const CheckinCalendar = ({ t, status }) => {
}
}
};
};
// 执行签到
const
postCheckin
=
async
(
token
)
=>
{
const
doCheckin
=
async
()
=>
{
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
);
setCheckinLoading
(
true
);
try
{
try
{
const
res
=
await
API
.
post
(
'/api/user/checkin'
);
const
res
=
await
postCheckin
(
token
);
const
{
success
,
data
,
message
}
=
res
.
data
;
const
{
success
,
data
,
message
}
=
res
.
data
;
if
(
success
)
{
if
(
success
)
{
showSuccess
(
showSuccess
(
...
@@ -121,7 +137,19 @@ const CheckinCalendar = ({ t, status }) => {
...
@@ -121,7 +137,19 @@ const CheckinCalendar = ({ t, status }) => {
);
);
// 刷新签到状态
// 刷新签到状态
fetchCheckinStatus
(
currentMonth
);
fetchCheckinStatus
(
currentMonth
);
setTurnstileModalVisible
(
false
);
}
else
{
}
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
(
'签到失败'
));
showError
(
message
||
t
(
'签到失败'
));
}
}
}
catch
(
error
)
{
}
catch
(
error
)
{
...
@@ -186,6 +214,30 @@ const CheckinCalendar = ({ t, status }) => {
...
@@ -186,6 +214,30 @@ const CheckinCalendar = ({ t, status }) => {
return
(
return
(
<
Card
className=
'!rounded-2xl'
>
<
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
className=
'flex items-center justify-between'
>
<
div
<
div
...
@@ -221,7 +273,7 @@ const CheckinCalendar = ({ t, status }) => {
...
@@ -221,7 +273,7 @@ const CheckinCalendar = ({ t, status }) => {
type=
'primary'
type=
'primary'
theme=
'solid'
theme=
'solid'
icon=
{
<
Gift
size=
{
16
}
/>
}
icon=
{
<
Gift
size=
{
16
}
/>
}
onClick=
{
doCheckin
}
onClick=
{
()
=>
doCheckin
()
}
loading=
{
checkinLoading
||
!
initialLoaded
}
loading=
{
checkinLoading
||
!
initialLoaded
}
disabled=
{
!
initialLoaded
||
checkinData
.
stats
?.
checked_in_today
}
disabled=
{
!
initialLoaded
||
checkinData
.
stats
?.
checked_in_today
}
className=
'!bg-green-600 hover:!bg-green-700'
className=
'!bg-green-600 hover:!bg-green-700'
...
...
web/src/services/secureVerification.js
View file @
93527862
...
@@ -42,12 +42,12 @@ export class SecureVerificationService {
...
@@ -42,12 +42,12 @@ export class SecureVerificationService {
isPasskeySupported
(),
isPasskeySupported
(),
]);
]);
console
.
log
(
'=== DEBUGGING VERIFICATION METHODS ==='
);
//
console.log('=== DEBUGGING VERIFICATION METHODS ===');
console
.
log
(
'2FA Response:'
,
JSON
.
stringify
(
twoFAResponse
,
null
,
2
));
//
console.log('2FA Response:', JSON.stringify(twoFAResponse, null, 2));
console
.
log
(
//
console.log(
'Passkey Response:'
,
//
'Passkey Response:',
JSON
.
stringify
(
passkeyResponse
,
null
,
2
),
//
JSON.stringify(passkeyResponse, null, 2),
);
//
);
const
has2FA
=
const
has2FA
=
twoFAResponse
.
data
?.
success
&&
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