moon cricket

This commit is contained in:
Heidi
2026-06-28 22:50:47 +01:00
parent 0c764a773d
commit 88d6bbe68b
+31 -8
View File
@@ -66,6 +66,7 @@ const siteGateEnabled = siteGateSetting == null
const staticDataBase = (import.meta.env.VITE_STATIC_DATA_BASE || '/data').replace(/\/+$/, '')
const staticDataEnabled = String(import.meta.env.VITE_STATIC_DATA || 'false').toLowerCase() === 'true'
const missingStaticDataPaths = new Set()
const turnstileRequiredEvent = 'tssbot:turnstile-required'
const BLOCKED_PLAYER_UIDS = new Set(['165569402', '86157459', '33536334', '41808996', '3651161'])
const BLOCKED_TEAM_NAMES = new Set(['TPC'])
@@ -135,6 +136,15 @@ function dataSource(apiPath, staticPath = null) {
return { apiPath, staticPath }
}
function turnstileSessionRequiredMessage(error) {
return error === 'Turnstile session required' || error === 'Site session required'
}
function promptTurnstileSession(detail) {
if (typeof window === 'undefined' || !turnstileSiteKey) return
window.dispatchEvent(new CustomEvent(turnstileRequiredEvent, { detail }))
}
const publicDataSources = {
teams: dataSource(apiEndpoints.teams, staticDataPath('leaderboard-teams.json')),
players: dataSource(apiEndpoints.players, staticDataPath('leaderboard-players.json')),
@@ -161,6 +171,10 @@ async function fetchJson(path, signal) {
const error = new Error(body?.error || `Request failed with ${response.status}`)
error.status = response.status
error.path = path
error.detail = body?.detail
if (response.status === 403 && turnstileSessionRequiredMessage(body?.error)) {
promptTurnstileSession({ path, error: body?.error, detail: body?.detail })
}
throw error
}
@@ -1307,10 +1321,10 @@ function SiteGate({ onVerified }) {
>
<div className="flex w-full max-w-sm flex-col items-center gap-4 rounded-md border border-border bg-fury-white p-6 text-center text-text shadow-[0_24px_70px_rgba(0,0,0,0.24)]">
<h1 id="site-gate-title" className="text-lg font-semibold">
Verifying you are human
Start a protected session
</h1>
<p className="text-sm text-text-soft">
This quick check protects the site from automated abuse. It usually clears itself.
Complete this Turnstile check to continue using protected site data.
</p>
<TurnstileWidget
siteKey={turnstileSiteKey}
@@ -1330,15 +1344,15 @@ function SiteGate({ onVerified }) {
}
function App() {
if (!siteGateEnabled) return <AppContent />
return <GatedAppContent />
if (!turnstileSiteKey) return <AppContent />
return <GatedAppContent enforceInitialGate={siteGateEnabled} />
}
function GatedAppContent() {
function GatedAppContent({ enforceInitialGate }) {
const embeddedGateState = document
.querySelector('meta[name="tss-turnstile-session"]')
?.getAttribute('content')
const initialGateState = turnstileSiteKey
const initialGateState = enforceInitialGate
? ['verified', 'required'].includes(embeddedGateState)
? embeddedGateState
: 'checking'
@@ -1346,7 +1360,7 @@ function GatedAppContent() {
const [gateState, setGateState] = useState(initialGateState)
useEffect(() => {
if (!turnstileSiteKey || gateState !== 'checking') return undefined
if (!enforceInitialGate || gateState !== 'checking') return undefined
let cancelled = false
fetch('/api/turnstile/session', { headers: { Accept: 'application/json' } })
.then((response) => (response.ok ? response.json() : { verified: false }))
@@ -1360,7 +1374,16 @@ function GatedAppContent() {
return () => {
cancelled = true
}
}, [gateState])
}, [enforceInitialGate, gateState])
useEffect(() => {
function handleTurnstileRequired() {
setGateState('required')
}
window.addEventListener(turnstileRequiredEvent, handleTurnstileRequired)
return () => window.removeEventListener(turnstileRequiredEvent, handleTurnstileRequired)
}, [])
if (gateState === 'checking') {
return <div className="fixed inset-0 bg-bg" aria-hidden="true" />