180 lines
5.4 KiB
TypeScript
180 lines
5.4 KiB
TypeScript
|
|
import { Challenge, Team, Solve, CTFState, BlogPost } from '../types';
|
|
|
|
const API_BASE = '/api';
|
|
|
|
class ApiService {
|
|
private getHeaders() {
|
|
const session = localStorage.getItem('hip6_session');
|
|
const headers: HeadersInit = {
|
|
'Content-Type': 'application/json',
|
|
};
|
|
if (session) {
|
|
const { token } = JSON.parse(session);
|
|
if (token) headers['Authorization'] = `Bearer ${token}`;
|
|
}
|
|
return headers;
|
|
}
|
|
|
|
async getState(): Promise<CTFState> {
|
|
try {
|
|
const res = await fetch(`${API_BASE}/state`);
|
|
if (!res.ok) throw new Error(`HTTP Error ${res.status}`);
|
|
return res.json();
|
|
} catch (err) {
|
|
console.error('API Error (getState):', err);
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
async login(name: string, pass: string): Promise<{ team: Team, token: string }> {
|
|
const res = await fetch(`${API_BASE}/auth/login`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ name, password: pass }),
|
|
});
|
|
if (!res.ok) {
|
|
const err = await res.json();
|
|
throw new Error(err.message || 'Invalid credentials');
|
|
}
|
|
return res.json();
|
|
}
|
|
|
|
async register(name: string, pass: string): Promise<{ team: Team, token: string }> {
|
|
const res = await fetch(`${API_BASE}/auth/register`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ name, password: pass }),
|
|
});
|
|
if (!res.ok) {
|
|
const err = await res.json();
|
|
throw new Error(err.message || 'Registration failed');
|
|
}
|
|
return res.json();
|
|
}
|
|
|
|
async toggleCtf(): Promise<void> {
|
|
const res = await fetch(`${API_BASE}/admin/toggle-ctf`, {
|
|
method: 'POST',
|
|
headers: this.getHeaders(),
|
|
});
|
|
if (!res.ok) throw new Error('Unauthorized or failed to toggle CTF');
|
|
}
|
|
|
|
async updateConfig(formData: FormData): Promise<void> {
|
|
const session = localStorage.getItem('hip6_session');
|
|
const headers: HeadersInit = {};
|
|
if (session) {
|
|
const { token } = JSON.parse(session);
|
|
headers['Authorization'] = `Bearer ${token}`;
|
|
}
|
|
const res = await fetch(`${API_BASE}/admin/config`, {
|
|
method: 'PUT',
|
|
headers,
|
|
body: formData,
|
|
});
|
|
if (!res.ok) throw new Error('Failed to update configuration');
|
|
}
|
|
|
|
async updateTeam(id: string, data: { name: string, isDisabled: boolean, isAdmin: boolean, password?: string }): Promise<void> {
|
|
const res = await fetch(`${API_BASE}/admin/teams/${id}`, {
|
|
method: 'PUT',
|
|
headers: this.getHeaders(),
|
|
body: JSON.stringify(data),
|
|
});
|
|
if (!res.ok) {
|
|
const err = await res.json();
|
|
throw new Error(err.message || 'Failed to update team');
|
|
}
|
|
}
|
|
|
|
async updateProfile(data: { password?: string }): Promise<void> {
|
|
const res = await fetch(`${API_BASE}/profile`, {
|
|
method: 'PUT',
|
|
headers: this.getHeaders(),
|
|
body: JSON.stringify(data),
|
|
});
|
|
if (!res.ok) {
|
|
const err = await res.json();
|
|
throw new Error(err.message || 'Failed to update profile');
|
|
}
|
|
}
|
|
|
|
async deleteTeam(id: string): Promise<void> {
|
|
const res = await fetch(`${API_BASE}/admin/teams/${id}`, {
|
|
method: 'DELETE',
|
|
headers: this.getHeaders(),
|
|
});
|
|
if (!res.ok) throw new Error('Failed to delete team');
|
|
}
|
|
|
|
async submitFlag(challengeId: string, flag: string): Promise<{ success: boolean }> {
|
|
const res = await fetch(`${API_BASE}/challenges/submit`, {
|
|
method: 'POST',
|
|
headers: this.getHeaders(),
|
|
body: JSON.stringify({ challengeId, flag }),
|
|
});
|
|
if (!res.ok) throw new Error('Submission failed');
|
|
return res.json();
|
|
}
|
|
|
|
async upsertChallenge(formData: FormData, id?: string): Promise<any> {
|
|
const method = id ? 'PUT' : 'POST';
|
|
const url = id ? `${API_BASE}/admin/challenges/${id}` : `${API_BASE}/admin/challenges`;
|
|
|
|
const session = localStorage.getItem('hip6_session');
|
|
const headers: HeadersInit = {};
|
|
if (session) {
|
|
const { token } = JSON.parse(session);
|
|
headers['Authorization'] = `Bearer ${token}`;
|
|
}
|
|
|
|
const res = await fetch(url, {
|
|
method,
|
|
headers,
|
|
body: formData,
|
|
});
|
|
if (!res.ok) {
|
|
const err = await res.json().catch(() => ({ message: 'Save failed' }));
|
|
throw new Error(err.message || 'Failed to save challenge');
|
|
}
|
|
return res.json();
|
|
}
|
|
|
|
async deleteChallenge(id: string): Promise<void> {
|
|
const res = await fetch(`${API_BASE}/admin/challenges/${id}`, {
|
|
method: 'DELETE',
|
|
headers: this.getHeaders(),
|
|
});
|
|
if (!res.ok) throw new Error('Failed to delete challenge');
|
|
}
|
|
|
|
async createBlogPost(data: { title: string, content: string }): Promise<void> {
|
|
const res = await fetch(`${API_BASE}/admin/blogs`, {
|
|
method: 'POST',
|
|
headers: this.getHeaders(),
|
|
body: JSON.stringify(data),
|
|
});
|
|
if (!res.ok) throw new Error('Failed to create blog post');
|
|
}
|
|
|
|
async updateBlogPost(id: string, data: { title: string, content: string }): Promise<void> {
|
|
const res = await fetch(`${API_BASE}/admin/blogs/${id}`, {
|
|
method: 'PUT',
|
|
headers: this.getHeaders(),
|
|
body: JSON.stringify(data),
|
|
});
|
|
if (!res.ok) throw new Error('Failed to update blog post');
|
|
}
|
|
|
|
async deleteBlogPost(id: string): Promise<void> {
|
|
const res = await fetch(`${API_BASE}/admin/blogs/${id}`, {
|
|
method: 'DELETE',
|
|
headers: this.getHeaders(),
|
|
});
|
|
if (!res.ok) throw new Error('Failed to delete blog post');
|
|
}
|
|
}
|
|
|
|
export const api = new ApiService();
|