"use client" import { FormEvent, useEffect, useState } from "react" import { useRouter } from "next/navigation" const API_BASE = "http://127.0.0.1:5000" type FirewallRule = { id: string name?: string ip?: string method?: string path_pattern?: string action?: string enabled?: boolean created_at?: string } type RuleForm = { name: string ip: string method: string path_pattern: string action: "block" | "allow" enabled: boolean } const initialRuleForm: RuleForm = { name: "", ip: "", method: "", path_pattern: "", action: "block", enabled: true, } export default function AdminFirewallPage() { const router = useRouter() const [ready, setReady] = useState(false) const [loading, setLoading] = useState(false) const [saving, setSaving] = useState(false) const [rules, setRules] = useState([]) const [message, setMessage] = useState("") const [form, setForm] = useState(initialRuleForm) const getToken = () => localStorage.getItem("admin_token") const headers = () => { const token = getToken() return token ? { "Content-Type": "application/json", Authorization: `Bearer ${token}` } : { "Content-Type": "application/json" } } const ensureAuth = async () => { const token = getToken() if (!token) { router.push("/admin/login") return false } const resp = await fetch(`${API_BASE}/api/admin/test`, { headers: headers() }) if (!resp.ok) { localStorage.removeItem("admin_token") router.push("/admin/login") return false } return true } const fetchRules = async () => { setLoading(true) setMessage("") try { const resp = await fetch(`${API_BASE}/api/admin/firewall/rules`, { headers: headers() }) const data = await resp.json().catch(() => ({})) if (!resp.ok) { setRules([]) setMessage(String(data.error || "Failed to load firewall rules.")) return } setRules(Array.isArray(data.rules) ? data.rules : []) } catch { setRules([]) setMessage("Network error while loading firewall rules.") } finally { setLoading(false) } } const createRule = async (e: FormEvent) => { e.preventDefault() setSaving(true) setMessage("") try { const payload = { name: form.name.trim(), ip: form.ip.trim(), method: form.method.trim().toUpperCase(), path_pattern: form.path_pattern.trim(), action: form.action, enabled: form.enabled, } const resp = await fetch(`${API_BASE}/api/admin/firewall/rules`, { method: "POST", headers: headers(), body: JSON.stringify(payload), }) const data = await resp.json().catch(() => ({})) if (!resp.ok) { setMessage(String(data.error || "Failed to create firewall rule.")) return } setForm(initialRuleForm) setMessage("Firewall rule created.") await fetchRules() } catch { setMessage("Network error while creating firewall rule.") } finally { setSaving(false) } } const deleteRule = async (ruleId: string) => { if (!ruleId) return setMessage("") try { const resp = await fetch(`${API_BASE}/api/admin/firewall/rules/${encodeURIComponent(ruleId)}`, { method: "DELETE", headers: headers(), }) const data = await resp.json().catch(() => ({})) if (!resp.ok) { setMessage(String(data.error || "Failed to delete firewall rule.")) return } setMessage("Firewall rule deleted.") await fetchRules() } catch { setMessage("Network error while deleting firewall rule.") } } useEffect(() => { const init = async () => { const ok = await ensureAuth() if (!ok) return setReady(true) await fetchRules() } init() }, []) if (!ready) { return (

Loading firewall manager...

) } return (

Manual Firewall

Add or remove manual allow/block rules by IP, method, and path pattern.

setForm((p) => ({ ...p, name: e.target.value }))} placeholder="Rule name" className="rounded-md border border-gray-300 px-3 py-2 text-sm dark:border-gray-700 dark:bg-gray-800" /> setForm((p) => ({ ...p, ip: e.target.value }))} placeholder="IP (optional)" className="rounded-md border border-gray-300 px-3 py-2 text-sm dark:border-gray-700 dark:bg-gray-800" /> setForm((p) => ({ ...p, method: e.target.value }))} placeholder="Method (GET/POST...)" className="rounded-md border border-gray-300 px-3 py-2 text-sm dark:border-gray-700 dark:bg-gray-800" /> setForm((p) => ({ ...p, path_pattern: e.target.value }))} placeholder="Path pattern (optional)" className="rounded-md border border-gray-300 px-3 py-2 text-sm dark:border-gray-700 dark:bg-gray-800" />

Active Rules

{message ?

{message}

: null}
{loading ? ( ) : rules.length === 0 ? ( ) : ( rules.map((rule) => ( )) )}
Name IP Method Path Pattern Action Enabled Created Actions
Loading rules...
No firewall rules configured.
{rule.name || "-"} {rule.ip || "-"} {rule.method || "-"} {rule.path_pattern || "-"} {rule.action || "block"} {rule.enabled ? "true" : "false"} {String(rule.created_at || "-")}
) }