feat: API Key Auth + erweiterte MCP Tools + Dokumentation
continuous-integration/drone/push Build is passing

- API Key Middleware für alle /api/ Endpoints (X-API-Key, Bearer, Query)
- API Key Management Routes (generate, revoke, status)
- MCP Tools erweitert: 12 Tools (war 3) inkl. bulk ops, dashboard, search
- Audit Logging für alle API/MCP Aktionen
- docs/API-REFERENCE.md - vollständige API Dokumentation
- docs/ARCHITECTURE.md - Architektur-Übersicht
- Vorbereitung für NotiBot-Integration
This commit is contained in:
NotiBot
2026-02-03 10:23:18 +01:00
parent c1f7a13c0e
commit 4f6aff32ab
8 changed files with 1569 additions and 98 deletions
+61
View File
@@ -16,6 +16,7 @@ const recurrenceService = new RecurrenceService(storage);
const gamificationService = new GamificationService(storage);
import { setupAuth, hashPassword, comparePassword } from "./auth.js";
import { apiKeyAuth } from "./api-key-auth.js";
function isAdmin(req: any, res: any, next: any) {
if (req.isAuthenticated() && req.user.role === 'admin') {
@@ -27,6 +28,10 @@ function isAdmin(req: any, res: any, next: any) {
export async function registerRoutes(app: Express): Promise<Server> {
setupAuth(app);
// API Key auth middleware - must be after session setup
// Allows external tools to authenticate via X-API-Key header
app.use("/api", apiKeyAuth());
// Update user schedule
app.patch("/api/user/schedule", async (req, res) => {
if (!req.isAuthenticated()) return res.sendStatus(401);
@@ -838,6 +843,62 @@ ${activeTasksWithLabels.slice(0, 5).map(t => `- [${t.priority}] [${t.label}] ${t
}
});
// --- API Key Management Routes ---
// Get current API key (masked)
app.get("/api/user/api-key", async (req, res) => {
if (!req.isAuthenticated()) return res.sendStatus(401);
const user = req.user as User;
if (user.apiKey) {
// Show first 8 and last 4 chars
const masked = user.apiKey.substring(0, 8) + "..." + user.apiKey.substring(user.apiKey.length - 4);
res.json({ hasKey: true, maskedKey: masked });
} else {
res.json({ hasKey: false, maskedKey: null });
}
});
// Generate new API key
app.post("/api/user/api-key", async (req, res) => {
if (!req.isAuthenticated()) return res.sendStatus(401);
const user = req.user as User;
const crypto = await import("crypto");
const newKey = "tf_" + crypto.randomBytes(32).toString("hex");
await storage.updateUserApiKey(user.id, newKey);
await storage.createAuditLog({
userId: user.id,
action: "CREATE",
entityType: "API_KEY",
entityId: user.id,
details: { message: "API key generated" },
source: "USER"
});
// Return full key ONCE (user must save it)
res.json({ apiKey: newKey, message: "Save this key - it won't be shown again in full." });
});
// Revoke API key
app.delete("/api/user/api-key", async (req, res) => {
if (!req.isAuthenticated()) return res.sendStatus(401);
const user = req.user as User;
await storage.updateUserApiKey(user.id, null);
await storage.createAuditLog({
userId: user.id,
action: "DELETE",
entityType: "API_KEY",
entityId: user.id,
details: { message: "API key revoked" },
source: "USER"
});
res.json({ message: "API key revoked" });
});
// Health check endpoint
app.get("/api/health", (req, res) => {
res.status(200).json({ status: "ok", timestamp: new Date().toISOString() });