Initial commit — DRB server stack

Includes c2-core (FastAPI/MQTT/Firestore), discord-bot (slash commands),
frontend (Next.js admin UI), and mosquitto config.
This commit is contained in:
Logan
2026-04-05 19:01:39 -04:00
commit 2f0597c81b
77 changed files with 4126 additions and 0 deletions
+58
View File
@@ -0,0 +1,58 @@
import { auth } from "@/lib/firebase";
const BASE = process.env.NEXT_PUBLIC_C2_URL ?? "http://localhost:8000";
async function request<T>(path: string, options?: RequestInit): Promise<T> {
const user = auth.currentUser;
const token = user ? await user.getIdToken() : null;
const res = await fetch(`${BASE}${path}`, {
...options,
headers: {
"Content-Type": "application/json",
...(token ? { Authorization: `Bearer ${token}` } : {}),
...(options?.headers as Record<string, string> | undefined),
},
});
if (!res.ok) throw new Error(`C2 API error ${res.status}: ${await res.text()}`);
if (res.status === 204) return undefined as T;
return res.json();
}
export const c2api = {
// Nodes
getNodes: () => request<unknown[]>("/nodes"),
getNode: (id: string) => request<unknown>(`/nodes/${id}`),
sendCommand: (nodeId: string, payload: object) =>
request(`/nodes/${nodeId}/command`, { method: "POST", body: JSON.stringify(payload) }),
assignSystem: (nodeId: string, systemId: string) =>
request(`/nodes/${nodeId}/config/${systemId}`, { method: "POST" }),
// Systems
getSystems: () => request<unknown[]>("/systems"),
createSystem: (body: object) =>
request("/systems", { method: "POST", body: JSON.stringify(body) }),
updateSystem: (id: string, body: object) =>
request(`/systems/${id}`, { method: "PUT", body: JSON.stringify(body) }),
deleteSystem: (id: string) =>
request(`/systems/${id}`, { method: "DELETE" }),
// Tokens
getTokens: () => request<unknown[]>("/tokens"),
addToken: (body: { name: string; token: string }) =>
request("/tokens", { method: "POST", body: JSON.stringify(body) }),
deleteToken: (id: string) =>
request(`/tokens/${id}`, { method: "DELETE" }),
// Node approval
approveNode: (id: string) =>
request(`/nodes/${id}/approve`, { method: "POST" }),
rejectNode: (id: string) =>
request(`/nodes/${id}/reject`, { method: "POST" }),
// Calls
getCalls: (params?: Record<string, string>) => {
const qs = params ? "?" + new URLSearchParams(params).toString() : "";
return request<unknown[]>(`/calls${qs}`);
},
};