- Fixed Challenge Modal overlap issue by adjusting the main stacking context in App.tsx

- Implemented "click-outside-to-close" functionality for both the Challenge Modal and User Dropdown
- Added protocol-specific action buttons for challenges: "Open in new tab" for HTTP and "Copy to clipboard" for NC
- Enhanced Scoreboard rankings with significantly larger, consistent font sizes (text-2xl) for better readability
- Rebranded "TEAM_IDENTIFIER" to "PLAYER" and "TOTAL_POINTS" to "POINTS" across the platform (Scoreboard, Matrix, User Menu)
- Updated navigation: Renamed "SCOREBOARD" to "SCORES" in the nav bar and dynamic page titles
- Modernized User Dropdown menu with a dedicated "PLAYER" header and "LOGOUT" action
- Improved Score Matrix and Score Graph titles for consistency with the new "Player" terminology
- Added CAPTCHA human verification (svg-captcha) to Login and Registration flows for enhanced security
- Optimized frontend assets by migrating Tailwind and JetBrains Mono to local hosting
- Refactored Admin panel: Renamed "Operators" to "Users" and improved layout alignment
This commit is contained in:
m0rph3us1987
2026-03-11 17:47:46 +01:00
parent 27566a7813
commit 0d07264788
20 changed files with 753 additions and 489 deletions

View File

@@ -5,8 +5,9 @@ import { api } from './services/api';
interface CTFContextType {
state: CTFState;
currentUser: Team | null;
login: (name: string, pass: string) => Promise<boolean>;
register: (name: string, pass: string) => Promise<void>;
login: (name: string, pass: string, captchaId: string, captchaAnswer: string) => Promise<boolean>;
register: (name: string, pass: string, captchaId: string, captchaAnswer: string) => Promise<void>;
getCaptcha: () => Promise<{ id: string, data: string }>;
logout: () => void;
submitFlag: (challengeId: string, flag: string) => Promise<boolean>;
toggleCtf: () => Promise<void>;
@@ -94,8 +95,19 @@ export const CTFProvider: React.FC<{ children: React.ReactNode }> = ({ children
return () => clearInterval(interval);
}, [refreshState]);
const login = async (n: string, p: string) => { try { const { team, token } = await api.login(n, p); localStorage.setItem('hip6_session', JSON.stringify({ team, token })); setCurrentUser(team); await refreshState(); return true; } catch (e) { return false; } };
const register = async (n: string, p: string) => { const { team, token } = await api.register(n, p); localStorage.setItem('hip6_session', JSON.stringify({ team, token })); setCurrentUser(team); await refreshState(); };
const login = async (n: string, p: string, cid: string, cans: string) => {
try {
const { team, token } = await api.login(n, p, cid, cans);
localStorage.setItem('hip6_session', JSON.stringify({ team, token }));
setCurrentUser(team);
await refreshState();
return true;
} catch (e) {
return false;
}
};
const register = async (n: string, p: string, cid: string, cans: string) => { const { team, token } = await api.register(n, p, cid, cans); localStorage.setItem('hip6_session', JSON.stringify({ team, token })); setCurrentUser(team); await refreshState(); };
const getCaptcha = async () => await api.getCaptcha();
const logout = () => { localStorage.removeItem('hip6_session'); setCurrentUser(null); };
const submitFlag = async (cid: string, f: string) => { const res = await api.submitFlag(cid, f); await refreshState(); return res.success; };
const toggleCtf = async () => { await api.toggleCtf(); await refreshState(); };
@@ -109,7 +121,7 @@ export const CTFProvider: React.FC<{ children: React.ReactNode }> = ({ children
const restoreDatabase = async (f: File) => await api.restoreDatabase(f);
const updateTeam = async (id: string, d: any) => { await api.updateTeam(id, d); await refreshState(); };
const updateProfile = async (p?: string) => { await api.updateProfile({ password: p }); await refreshState(); };
const deleteTeam = async (id: string) => { if (window.confirm("EXPEL_OPERATOR?")) { await api.deleteTeam(id); await refreshState(); } };
const deleteTeam = async (id: string) => { if (window.confirm("EXPEL_USER?")) { await api.deleteTeam(id); await refreshState(); } };
const deleteSolve = async (teamId: string, challengeId: string) => { if (window.confirm("DELETE_SOLVE?")) { await api.deleteSolve(teamId, challengeId); await refreshState(); } };
const createBlogPost = async (d: any) => { await api.createBlogPost(d); await refreshState(); };
const updateBlogPost = async (id: string, d: any) => { await api.updateBlogPost(id, d); await refreshState(); };
@@ -118,7 +130,7 @@ export const CTFProvider: React.FC<{ children: React.ReactNode }> = ({ children
return (
<CTFContext.Provider value={{
state, currentUser, login, register, logout, submitFlag, toggleCtf, resetScores,
state, currentUser, login, register, getCaptcha, logout, submitFlag, toggleCtf, resetScores,
upsertChallenge, deleteChallenge, deleteAllChallenges, exportChallenges,
importChallenges, backupDatabase, restoreDatabase, updateTeam, updateProfile,
deleteTeam, deleteSolve, createBlogPost, updateBlogPost, deleteBlogPost, updateConfig,