// src/pages/api/ai/enhance-input.ts - ENHANCED with forensics methodology import type { APIRoute } from 'astro'; import { withAPIAuth } from '../../../utils/auth.js'; import { apiError, apiServerError, createAuthErrorResponse } from '../../../utils/api.js'; import { enqueueApiCall } from '../../../utils/rateLimitedQueue.js'; export const prerender = false; function getEnv(key: string): string { const value = process.env[key]; if (!value) { throw new Error(`Missing environment variable: ${key}`); } return value; } const AI_ENDPOINT = getEnv('AI_ANALYZER_ENDPOINT'); const AI_ANALYZER_API_KEY = getEnv('AI_ANALYZER_API_KEY'); const AI_ANALYZER_MODEL = getEnv('AI_ANALYZER_MODEL'); const rateLimitStore = new Map(); const RATE_LIMIT_WINDOW = 60 * 1000; // 1 minute const RATE_LIMIT_MAX = 5; function sanitizeInput(input: string): string { return input .replace(/```[\s\S]*?```/g, '[CODE_BLOCK_REMOVED]') .replace(/\<\/?[^>]+(>|$)/g, '') .replace(/\b(system|assistant|user)\s*[:]/gi, '[ROLE_REMOVED]') .replace(/\b(ignore|forget|disregard)\s+(previous|all|your)\s+(instructions?|context|rules?)/gi, '[INSTRUCTION_REMOVED]') .trim() .slice(0, 1000); } function checkRateLimit(userId: string): boolean { const now = Date.now(); const userLimit = rateLimitStore.get(userId); if (!userLimit || now > userLimit.resetTime) { rateLimitStore.set(userId, { count: 1, resetTime: now + RATE_LIMIT_WINDOW }); return true; } if (userLimit.count >= RATE_LIMIT_MAX) { return false; } userLimit.count++; return true; } function cleanupExpiredRateLimits() { const now = Date.now(); for (const [userId, limit] of rateLimitStore.entries()) { if (now > limit.resetTime) { rateLimitStore.delete(userId); } } } setInterval(cleanupExpiredRateLimits, 5 * 60 * 1000); function createEnhancementPrompt(input: string): string { return `Sie sind ein DFIR-Experte mit Spezialisierung auf forensische Methodik. Ein Nutzer beschreibt ein forensisches Szenario oder Problem. Analysieren Sie die Eingabe auf Vollständigkeit für eine wissenschaftlich fundierte forensische Untersuchung. ANALYSIEREN SIE DIESE FORENSISCHEN KATEGORIEN: 1. **Incident Context**: Was ist passiert? Welche Angriffsvektoren oder technischen Probleme liegen vor? 2. **Affected Systems**: Welche spezifischen Technologien/Plattformen sind betroffen? (Windows/Linux/ICS/SCADA/Mobile/Cloud/Network Infrastructure) 3. **Available Evidence**: Welche forensischen Datenquellen stehen zur Verfügung? (RAM-Dumps, Disk-Images, Log-Files, Network-Captures, Registry-Hives) 4. **Investigation Objectives**: Was soll erreicht werden? (IOC-Extraktion, Timeline-Rekonstruktion, Attribution, Impact-Assessment) 5. **Timeline Constraints**: Wie zeitkritisch ist die Untersuchung? 6. **Legal & Compliance**: Rechtliche Anforderungen, Chain of Custody, Compliance-Rahmen (DSGVO, sector-specific regulations) 7. **Technical Constraints**: Verfügbare Ressourcen, Skills, Infrastrukturbeschränkungen WENN die Beschreibung alle kritischen forensischen Aspekte abdeckt: Geben Sie eine leere Liste [] zurück. WENN wichtige forensische Details fehlen: Formulieren Sie 2-3 präzise Fragen, die die kritischsten Lücken für eine wissenschaftlich fundierte forensische Analyse schließen. QUALITÄTSKRITERIEN FÜR FRAGEN: - Forensisch spezifisch, nicht allgemein (❌ "Mehr Details?" ✅ "Welche forensischen Artefakte (RAM-Dumps, Disk-Images, Logs) stehen zur Verfügung?") - Methodisch relevant (❌ "Wann passierte das?" ✅ "Liegen Log-Dateien aus dem Incident-Zeitraum vor, und welche Retention-Policy gilt?") - Priorisiert nach Auswirkung auf die forensische Untersuchungsqualität ANTWORTFORMAT (NUR JSON, KEIN ZUSÄTZLICHER TEXT): [ "Forensisch spezifische Frage 1?", "Forensisch spezifische Frage 2?", "Forensisch spezifische Frage 3?" ] NUTZER-EINGABE: ${input} `.trim(); } export const POST: APIRoute = async ({ request }) => { try { const authResult = await withAPIAuth(request, 'ai'); if (!authResult.authenticated) { return createAuthErrorResponse(); } const userId = authResult.userId; if (!checkRateLimit(userId)) { return apiError.rateLimit('Enhancement rate limit exceeded'); } const body = await request.json(); const { input } = body; if (!input || typeof input !== 'string' || input.length < 40) { return apiError.badRequest('Input too short for enhancement (minimum 40 characters)'); } const sanitizedInput = sanitizeInput(input); if (sanitizedInput.length < 40) { return apiError.badRequest('Input too short after sanitization'); } const systemPrompt = createEnhancementPrompt(sanitizedInput); const taskId = `enhance_${userId}_${Date.now()}_${Math.random().toString(36).substr(2, 4)}`; const aiResponse = await enqueueApiCall(() => fetch(`${AI_ENDPOINT}/v1/chat/completions`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${AI_ANALYZER_API_KEY}` }, body: JSON.stringify({ model: AI_ANALYZER_MODEL, messages: [ { role: 'user', content: systemPrompt } ], max_tokens: 300, temperature: 0.7, top_p: 0.9, frequency_penalty: 0.2, presence_penalty: 0.1 }) }), taskId); if (!aiResponse.ok) { console.error('AI enhancement error:', await aiResponse.text()); return apiServerError.unavailable('Enhancement service unavailable'); } const aiData = await aiResponse.json(); const aiContent = aiData.choices?.[0]?.message?.content; if (!aiContent) { return apiServerError.unavailable('No enhancement response'); } let questions; try { const cleanedContent = aiContent .replace(/^```json\s*/i, '') .replace(/\s*```\s*$/, '') .trim(); questions = JSON.parse(cleanedContent); if (!Array.isArray(questions)) { throw new Error('Response is not an array'); } questions = questions .filter(q => typeof q === 'string' && q.length > 20 && q.length < 200) .filter(q => q.includes('?')) .filter(q => { const forensicsTerms = ['forensisch', 'log', 'dump', 'image', 'artefakt', 'evidence', 'incident', 'system', 'netzwerk', 'zeitraum', 'verfügbar']; const lowerQ = q.toLowerCase(); return forensicsTerms.some(term => lowerQ.includes(term)); }) .map(q => q.trim()) .slice(0, 3); if (questions.length === 0) { questions = []; } } catch (error) { console.error('Failed to parse enhancement response:', aiContent); questions = []; } console.log(`[AI Enhancement] User: ${userId}, Forensics Questions: ${questions.length}, Input length: ${sanitizedInput.length}`); return new Response(JSON.stringify({ success: true, questions, taskId, inputComplete: questions.length === 0 // Flag to indicate if input seems complete }), { status: 200, headers: { 'Content-Type': 'application/json' } }); } catch (error) { console.error('Enhancement error:', error); return apiServerError.internal('Enhancement processing failed'); } };