fixes; locked down api (allegedly, idk, i let claude vibe it) and vandilised pedophiles profiles
This commit is contained in:
+47
-4
@@ -63,6 +63,9 @@ const siteGateEnabled = String(import.meta.env.VITE_SITE_GATE || 'false').toLowe
|
||||
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 BLOCKED_PLAYER_UIDS = new Set(['165569402', '86157459', '33536334', '41808996', '3651161'])
|
||||
const BLOCKED_TEAM_NAMES = new Set(['TPC'])
|
||||
const blogPostFiles = import.meta.glob('./blog/posts/*.md', {
|
||||
eager: true,
|
||||
import: 'default',
|
||||
@@ -1393,11 +1396,11 @@ function AppContent() {
|
||||
games: { status: 'idle', data: null, error: null },
|
||||
})
|
||||
const teams = useMemo(
|
||||
() => leaderboard.data?.teams || leaderboard.data?.squadrons || [],
|
||||
() => (leaderboard.data?.teams || leaderboard.data?.squadrons || []).filter((t) => !BLOCKED_TEAM_NAMES.has(bestTeamName(t))),
|
||||
[leaderboard.data],
|
||||
)
|
||||
const players = useMemo(
|
||||
() => playerLeaderboard.data?.players || [],
|
||||
() => (playerLeaderboard.data?.players || []).filter((p) => !BLOCKED_PLAYER_UIDS.has(String(p?.uid || ''))),
|
||||
[playerLeaderboard.data],
|
||||
)
|
||||
const teamsToWatch = useMemo(
|
||||
@@ -1645,10 +1648,14 @@ function AppContent() {
|
||||
if (controller.signal.aborted) return
|
||||
|
||||
const teamResults = teamResult.status === 'fulfilled'
|
||||
? (teamResult.value.teams || teamResult.value.results || []).map(teamSearchResult)
|
||||
? (teamResult.value.teams || teamResult.value.results || [])
|
||||
.filter((team) => !BLOCKED_TEAM_NAMES.has(bestTeamName(team)))
|
||||
.map(teamSearchResult)
|
||||
: []
|
||||
const playerResults = playerResult.status === 'fulfilled'
|
||||
? (playerResult.value.players || []).map(playerSearchResult)
|
||||
? (playerResult.value.players || [])
|
||||
.filter((player) => !BLOCKED_PLAYER_UIDS.has(String(player?.uid || '')))
|
||||
.map(playerSearchResult)
|
||||
: []
|
||||
const results = dedupeSearchResults([...teamResults, ...playerResults]).slice(0, 10)
|
||||
|
||||
@@ -2663,6 +2670,26 @@ function PlayerStatCard({ label, value }) {
|
||||
)
|
||||
}
|
||||
|
||||
function BlockedPage({ onBack }) {
|
||||
return (
|
||||
<section className="mx-auto max-w-4xl pb-12 pt-24 sm:pt-28">
|
||||
<div className="mt-8 rounded-xl border border-border bg-fury-white p-10 text-center">
|
||||
<p className="text-7xl">🤡🤡🤡🤡</p>
|
||||
<p className="mt-4 text-text-soft">user affiliated with pedophiles, blocked~</p>
|
||||
{onBack ? (
|
||||
<button
|
||||
className="mt-6 text-sm font-semibold text-fury-cyan transition hover:text-text"
|
||||
onClick={onBack}
|
||||
type="button"
|
||||
>
|
||||
Go back
|
||||
</button>
|
||||
) : null}
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
function PlayerPage({ uid, navigate }) {
|
||||
const [state, setState] = useState({ status: 'loading', data: null, error: '' })
|
||||
|
||||
@@ -2671,6 +2698,10 @@ function PlayerPage({ uid, navigate }) {
|
||||
setState({ status: 'error', data: null, error: 'No player specified.' })
|
||||
return
|
||||
}
|
||||
if (BLOCKED_PLAYER_UIDS.has(String(uid))) {
|
||||
setState({ status: 'blocked', data: null, error: '' })
|
||||
return
|
||||
}
|
||||
let cancelled = false
|
||||
setState({ status: 'loading', data: null, error: '' })
|
||||
fetchPublicJson(publicDataSources.player(uid))
|
||||
@@ -2687,6 +2718,12 @@ function PlayerPage({ uid, navigate }) {
|
||||
|
||||
const { status, data, error } = state
|
||||
|
||||
if (status === 'blocked') {
|
||||
return (
|
||||
<BlockedPage onBack={() => navigate('/players')} />
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<section className="mx-auto max-w-4xl pb-12 pt-24 sm:pt-28">
|
||||
<div className="border-b border-border pb-6">
|
||||
@@ -4241,6 +4278,12 @@ function TeamProfilePage({ navigate, profile, requestedTeam, teams }) {
|
||||
const leaderboardTeam = teams.find((team) => bestTeamName(team) === requestedTeam)
|
||||
const displayName = detail?.name || bestTeamName(leaderboardTeam) || requestedTeam
|
||||
|
||||
if (BLOCKED_TEAM_NAMES.has(requestedTeam)) {
|
||||
return (
|
||||
<BlockedPage onBack={() => navigate('/teams')} />
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<section className="space-y-6 pt-24 sm:pt-28">
|
||||
<button
|
||||
|
||||
+21
-3
@@ -1944,6 +1944,8 @@ function isRateLimited(req) {
|
||||
const current = rateLimits.get(ip)
|
||||
|
||||
if (!current || current.resetAt <= now) {
|
||||
// When the map is at capacity, deny new IPs rather than clearing existing limits.
|
||||
if (!current && rateLimits.size >= MAX_RATE_LIMIT_KEYS) return true
|
||||
rateLimits.set(ip, { count: 1, resetAt: now + API_RATE_LIMIT_WINDOW_MS })
|
||||
return false
|
||||
}
|
||||
@@ -1956,11 +1958,17 @@ function pruneMaps() {
|
||||
const now = Date.now()
|
||||
|
||||
for (const [key, value] of apiCache) {
|
||||
if (value.expiresAt <= now || apiCache.size > MAX_CACHE_ENTRIES) apiCache.delete(key)
|
||||
if (value.expiresAt <= now) apiCache.delete(key)
|
||||
}
|
||||
if (apiCache.size > MAX_CACHE_ENTRIES) {
|
||||
const sorted = [...apiCache.entries()].sort((a, b) => a[1].expiresAt - b[1].expiresAt)
|
||||
for (const [key] of sorted.slice(0, apiCache.size - MAX_CACHE_ENTRIES)) {
|
||||
apiCache.delete(key)
|
||||
}
|
||||
}
|
||||
|
||||
for (const [key, value] of rateLimits) {
|
||||
if (value.resetAt <= now || rateLimits.size > MAX_RATE_LIMIT_KEYS) rateLimits.delete(key)
|
||||
if (value.resetAt <= now) rateLimits.delete(key)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2156,6 +2164,8 @@ function proxyRequest(req, res) {
|
||||
delete headers['access-control-allow-methods']
|
||||
delete headers['access-control-allow-headers']
|
||||
delete headers['access-control-expose-headers']
|
||||
delete headers['server']
|
||||
delete headers['x-powered-by']
|
||||
|
||||
res.writeHead(statusCode, headers)
|
||||
|
||||
@@ -2759,7 +2769,11 @@ const server = http.createServer((req, res) => {
|
||||
}
|
||||
|
||||
if (req.url === '/health') {
|
||||
sendJson(res, 200, { ok: true, public_data: publicDataStartupStatus })
|
||||
if (isRateLimited(req)) {
|
||||
sendJson(res, 429, { error: 'Too many requests' }, { 'retry-after': String(Math.ceil(API_RATE_LIMIT_WINDOW_MS / 1000)) })
|
||||
return
|
||||
}
|
||||
sendJson(res, 200, { ok: true })
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2790,6 +2804,10 @@ const server = http.createServer((req, res) => {
|
||||
}
|
||||
|
||||
if (req.method === 'GET' && req.url === '/api/viewers') {
|
||||
if (!isSameOriginRequest(req)) {
|
||||
sendJson(res, 403, { error: 'Viewer analytics are restricted to this site' })
|
||||
return
|
||||
}
|
||||
if (isRateLimited(req)) {
|
||||
sendJson(res, 429, { error: 'Too many requests' }, { 'retry-after': String(Math.ceil(API_RATE_LIMIT_WINDOW_MS / 1000)) })
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user