All checks were successful
Dev Deployment (Zero Downtime) / deploy-dev (push) Successful in 13m33s
Build Optimizations: - Enable Docker BuildKit cache for faster builds (7min → 3-4min) - Add .dockerignore to reduce build context - Optimize Dockerfile with better layer caching - Run linting and tests in parallel - Skip blocking checks for dev deployments Rollback Functionality: - Add rollback.sh script to restore previous versions - Supports both production and dev environments - Automatic health checks after rollback Security Improvements: - Add authentication to n8n/generate-image endpoint - Add rate limiting to all n8n endpoints (10-30 req/min) - Create email obfuscation utilities - Add ObfuscatedEmail React component - Document security best practices Files: - .dockerignore - Faster builds - scripts/rollback.sh - Rollback functionality - lib/email-obfuscate.ts - Email obfuscation utilities - components/ObfuscatedEmail.tsx - React component - SECURITY_IMPROVEMENTS.md - Security documentation
79 lines
2.4 KiB
TypeScript
79 lines
2.4 KiB
TypeScript
// app/api/n8n/status/route.ts
|
|
import { NextRequest, NextResponse } from "next/server";
|
|
|
|
// Cache für 30 Sekunden, damit wir n8n nicht zuspammen
|
|
export const revalidate = 30;
|
|
|
|
export async function GET(request: NextRequest) {
|
|
// Rate limiting for n8n status endpoint
|
|
const ip = request.headers.get('x-forwarded-for') || request.headers.get('x-real-ip') || 'unknown';
|
|
const { checkRateLimit } = await import('@/lib/auth');
|
|
|
|
if (!checkRateLimit(ip, 30, 60000)) { // 30 requests per minute for status
|
|
return NextResponse.json(
|
|
{ error: 'Rate limit exceeded. Please try again later.' },
|
|
{ status: 429 }
|
|
);
|
|
}
|
|
try {
|
|
// Check if n8n webhook URL is configured
|
|
const n8nWebhookUrl = process.env.N8N_WEBHOOK_URL;
|
|
|
|
if (!n8nWebhookUrl) {
|
|
// Return fallback if n8n is not configured
|
|
return NextResponse.json({
|
|
status: { text: "offline", color: "gray" },
|
|
music: null,
|
|
gaming: null,
|
|
coding: null,
|
|
});
|
|
}
|
|
|
|
// Rufe den n8n Webhook auf
|
|
// Add timestamp to query to bypass Cloudflare cache
|
|
const res = await fetch(
|
|
`${n8nWebhookUrl}/webhook/denshooter-71242/status?t=${Date.now()}`,
|
|
{
|
|
method: "GET",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
next: { revalidate: 30 },
|
|
},
|
|
);
|
|
|
|
if (!res.ok) {
|
|
throw new Error(`n8n error: ${res.status}`);
|
|
}
|
|
|
|
const data = await res.json();
|
|
|
|
// n8n gibt oft ein Array zurück: [{...}]. Wir wollen nur das Objekt.
|
|
const statusData = Array.isArray(data) ? data[0] : data;
|
|
|
|
// Safety check: if statusData is still undefined/null (e.g. empty array), use fallback
|
|
if (!statusData) {
|
|
throw new Error("Empty data received from n8n");
|
|
}
|
|
|
|
// Ensure coding object has proper structure
|
|
if (statusData.coding && typeof statusData.coding === "object") {
|
|
// Already properly formatted from n8n
|
|
} else if (statusData.coding === null || statusData.coding === undefined) {
|
|
// No coding data - keep as null
|
|
statusData.coding = null;
|
|
}
|
|
|
|
return NextResponse.json(statusData);
|
|
} catch (error) {
|
|
console.error("Error fetching n8n status:", error);
|
|
// Leeres Fallback-Objekt, damit die Seite nicht abstürzt
|
|
return NextResponse.json({
|
|
status: { text: "offline", color: "gray" },
|
|
music: null,
|
|
gaming: null,
|
|
coding: null,
|
|
});
|
|
}
|
|
}
|