From 27566a7813c254f4c3d683bd3a6ca8d776425cd4 Mon Sep 17 00:00:00 2001 From: m0rph3us1987 Date: Tue, 10 Mar 2026 13:29:50 +0100 Subject: [PATCH] - Added "HW" (Hardware) category to the platform with a dedicated icon and color - Updated challenge grid to 6 columns on desktop to accommodate the new category - Alphabetized challenge categories in the main view and Admin panel selection - Alphabetized operators list in the Admin panel with case-insensitive sorting - Restricted visibility of Challenges, Scoreboard, and Score Matrix to authenticated users only - Secured the /state API endpoint to prevent leaking challenges, solves, teams, or internal IP (dockerIp) to guests - Implemented server-side verification of user profile in the state response to prevent client-side admin spoofing - Refactored the /state backend endpoint using async/await for better reliability and error handling - Rebranded the project from "cypherstrike-ctf" to "hipctf" across package.json, index.html, and server defaults - Synchronized browser page title with the competition name configured in the Admin panel - Fixed a "black page" issue by resolving a missing React import and adding frontend sanity checks --- Admin.tsx | 4 +- App.tsx | 16 ++++-- CTFContext.tsx | 11 +++++ Challenges.tsx | 6 +-- UIComponents.tsx | 3 +- changelog.txt | 15 +++++- constants.ts | 2 +- index.html | 2 +- package-lock.json | 15 ++++-- package.json | 2 +- server.js | 123 +++++++++++++++++++++++----------------------- types.ts | 1 + 12 files changed, 121 insertions(+), 79 deletions(-) diff --git a/Admin.tsx b/Admin.tsx index 4290183..a465c36 100644 --- a/Admin.tsx +++ b/Admin.tsx @@ -24,9 +24,9 @@ export const Admin: React.FC = () => { }, [state.challenges]); const sortedOperators = useMemo(() => { - return state.teams + return [...state.teams] .filter(t => t.id !== 'admin-0') - .sort((a, b) => a.name.localeCompare(b.name)); + .sort((a, b) => (a.name || '').localeCompare(b.name || '', undefined, { sensitivity: 'base' })); }, [state.teams]); useEffect(() => { diff --git a/App.tsx b/App.tsx index fd3b9d4..c57bcb3 100644 --- a/App.tsx +++ b/App.tsx @@ -1,5 +1,5 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { HashRouter, Routes, Route, Link, Navigate } from 'react-router-dom'; import { Terminal, Flag, Trophy, Newspaper, Shield, Settings, LogOut, X, History } from 'lucide-react'; import { CTFProvider, useCTF } from './CTFContext'; @@ -44,6 +44,12 @@ const LayoutShell: React.FC = () => { const { state, currentUser, logout, loading, loadError } = useCTF(); const [showProfileModal, setShowProfileModal] = useState(false); + useEffect(() => { + if (state.config && state.config.conferenceName) { + document.title = state.config.conferenceName; + } + }, [state.config]); + if (loading) return
INITIALIZING_SESSION...
; const now = Date.now(); @@ -71,9 +77,9 @@ const LayoutShell: React.FC = () => {
- Challenges + {currentUser ? Challenges : null} Blog - Scoreboard + {currentUser ? Scoreboard : null} {currentUser ? Log : null} {currentUser?.isAdmin ? Admin : null}
@@ -99,9 +105,9 @@ const LayoutShell: React.FC = () => { } /> } /> } /> - } /> + } /> } /> - } /> + } /> {currentUser?.isAdmin ? : }} /> } /> diff --git a/CTFContext.tsx b/CTFContext.tsx index ea1cc5d..284da5a 100644 --- a/CTFContext.tsx +++ b/CTFContext.tsx @@ -49,7 +49,18 @@ export const CTFProvider: React.FC<{ children: React.ReactNode }> = ({ children const refreshState = useCallback(async () => { try { const newState = await api.getState(); + if (!newState || !newState.config) return; setState(newState); + if (newState.user !== undefined) { + setCurrentUser(newState.user); + const session = localStorage.getItem('hip6_session'); + if (session && newState.user) { + const { token } = JSON.parse(session); + localStorage.setItem('hip6_session', JSON.stringify({ team: newState.user, token })); + } else if (session && !newState.user) { + localStorage.removeItem('hip6_session'); + } + } } catch (err: any) { console.error("State refresh failed:", err); throw err; diff --git a/Challenges.tsx b/Challenges.tsx index ee3ae14..ea43733 100644 --- a/Challenges.tsx +++ b/Challenges.tsx @@ -3,6 +3,7 @@ import React, { useState, useMemo } from 'react'; import { X, CheckCircle2, Download, Globe, Sparkles, Heart, Clock, Bell } from 'lucide-react'; import { useCTF } from './CTFContext'; import { Challenge, Difficulty } from './types'; +import { CATEGORIES } from './constants'; import { Button, CategoryIcon, Countdown } from './UIComponents'; import { calculateChallengeValue, getFirstBloodBonusFactor } from './services/scoring'; @@ -122,7 +123,6 @@ export const ChallengeList: React.FC = () => { const [selectedChallenge, setSelectedChallenge] = useState(null); const [showRefreshPopup, setShowRefreshPopup] = useState(false); const difficultyWeight: Record = { 'Low': 1, 'Medium': 2, 'High': 3 }; - const CATEGORIES = ['WEB', 'PWN', 'REV', 'CRY', 'MSC']; const now = Date.now(); const startTime = parseInt(state.config.eventStartTime || "0"); @@ -178,7 +178,7 @@ export const ChallengeList: React.FC = () => { return (
-
+
{CATEGORIES.map(category => { const categoryChallenges = (state.challenges || []) .filter(c => c.category === category) @@ -188,7 +188,7 @@ export const ChallengeList: React.FC = () => {
- +

{category}

diff --git a/UIComponents.tsx b/UIComponents.tsx index 080c8a6..2c28a0e 100644 --- a/UIComponents.tsx +++ b/UIComponents.tsx @@ -1,7 +1,7 @@ import React, { useState, useEffect } from 'react'; import { Navigate, useLocation } from 'react-router-dom'; -import { Terminal, Radar, Zap, RefreshCw, Box } from 'lucide-react'; +import { Terminal, Radar, Zap, RefreshCw, Box, Cpu } from 'lucide-react'; import { useCTF } from './CTFContext'; export const formatDuration = (ms: number) => { @@ -51,6 +51,7 @@ export const CategoryIcon: React.FC<{ category: string; size?: number; color?: s case 'PWN': return ; case 'REV': return ; case 'CRY': return ; + case 'HW': return ; default: return ; } }; diff --git a/changelog.txt b/changelog.txt index aeb3076..adb02c0 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,16 @@ +2026-03-10 +- Added "HW" (Hardware) category to the platform with a dedicated icon and color +- Updated challenge grid to 6 columns on desktop to accommodate the new category +- Alphabetized challenge categories in the main view and Admin panel selection +- Alphabetized operators list in the Admin panel with case-insensitive sorting +- Restricted visibility of Challenges, Scoreboard, and Score Matrix to authenticated users only +- Secured the /state API endpoint to prevent leaking challenges, solves, teams, or internal IP (dockerIp) to guests +- Implemented server-side verification of user profile in the state response to prevent client-side admin spoofing +- Refactored the /state backend endpoint using async/await for better reliability and error handling +- Rebranded the project from "cypherstrike-ctf" to "hipctf" across package.json, index.html, and server defaults +- Synchronized browser page title with the competition name configured in the Admin panel +- Fixed a "black page" issue by resolving a missing React import and adding frontend sanity checks + 2026-03-08 - Added an interactive graph view to the event log to track the score progression of the top 10 teams @@ -37,4 +50,4 @@ 2026-01-07 - Removed the README.md file -- Initial project setup including React frontend, Express backend, Docker configuration, and baseline scoring services \ No newline at end of file +- Initial project setup including React frontend, Express backend, Docker configuration, and baseline scoring services diff --git a/constants.ts b/constants.ts index cbf4d2a..7441932 100644 --- a/constants.ts +++ b/constants.ts @@ -1,7 +1,7 @@ import { Challenge, Team } from './types'; -export const CATEGORIES = ['WEB', 'PWN', 'REV', 'CRY', 'MSC']; +export const CATEGORIES = ['CRY', 'HW', 'MSC', 'PWN', 'REV', 'WEB']; export const DIFFICULTIES: ('Low' | 'Medium' | 'High')[] = ['Low', 'Medium', 'High']; export const INITIAL_CHALLENGES: Challenge[] = [ diff --git a/index.html b/index.html index ced807f..9c19251 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ - HIP7CTF + HIPCTF