diff --git a/src/components/AIQueryInterface.astro b/src/components/AIQueryInterface.astro
index 1d782ae..417d094 100644
--- a/src/components/AIQueryInterface.astro
+++ b/src/components/AIQueryInterface.astro
@@ -46,13 +46,29 @@ const domainAgnosticSoftware = data['domain-agnostic-software'] || [];
-
+
+
+ `;
+ }
+
+ return html;
+ }
+
+ function displayWorkflowResults(recommendation, originalQuery) {
+ const toolsByPhase = {};
+
+ const phaseOrder = phases.map(phase => phase.id);
+ const phaseNames = phases.reduce((acc, phase) => {
+ acc[phase.id] = phase.name;
+ return acc;
+ }, {});
+
+ phaseOrder.forEach(phase => {
+ toolsByPhase[phase] = [];
+ });
+
+ recommendation.recommended_tools?.forEach(recTool => {
+ if (toolsByPhase[recTool.phase]) {
+ const fullTool = tools.find(t => t.name === recTool.name);
+ if (fullTool) {
+ toolsByPhase[recTool.phase].push({
+ ...fullTool,
+ recommendation: recTool
+ });
+ }
+ }
+ });
+
+ const resultsHTML = `
+
+
+
Empfohlener DFIR-Workflow
+
+ Basierend auf Ihrer Anfrage: "${originalQuery.slice(0, 100)}${originalQuery.length > 100 ? '...' : ''}"
+
+
+
+ ${renderContextualAnalysis(recommendation, 'workflow')}
+
+ ${renderBackgroundKnowledge(recommendation.background_knowledge)}
+
+ ${phaseOrder.map((phase, index) => {
+ const phaseTools = toolsByPhase[phase];
+ if (phaseTools.length === 0) return '';
+
+ return `
+
+
+ ${index < phaseOrder.length - 1 ? `
+
+ ` : ''}
+
+ `;
+ }).join('')}
+
+ ${recommendation.workflow_suggestion ? `
+
+
+
+
+
+
+ Workflow-Empfehlung
+
+ ${formatWorkflowSuggestion(recommendation.workflow_suggestion)}
+
+ ` : ''}
+
+ ${recommendation.additional_notes ? `
+
+
+
+
+
+
+
+ Wichtige Hinweise
+
+
+ ${formatWorkflowSuggestion(recommendation.additional_notes).replace(/color: var\(--color-text\)/g, 'color: white')}
+
+
+ ` : ''}
+
+ `;
+
+ aiResults.innerHTML = '';
+ const tempDiv = document.createElement('div');
+ tempDiv.innerHTML = resultsHTML;
+ aiResults.appendChild(tempDiv);
+ }
+
+ function displayToolResults(recommendation, originalQuery) {
+ function getSuitabilityText(score) {
+ const suitabilityTexts = {
+ high: 'GUT GEEIGNET',
+ medium: 'GEEIGNET',
+ low: 'VIELLEICHT GEEIGNET'
+ };
+ return suitabilityTexts[score] || 'GEEIGNET';
+ }
+
+ function getToolPhases(tool) {
+ if (!tool.phases || tool.phases.length === 0) return '';
+
+ const phaseNames = phases.reduce((acc, phase) => {
+ acc[phase.id] = phase.name;
+ return acc;
+ }, {});
+
+ const domainAgnosticNames = domainAgnosticSoftware.reduce((acc, section) => {
+ acc[section.id] = section.name;
+ return acc;
+ }, {});
+
+ const allPhaseNames = { ...phaseNames, ...domainAgnosticNames };
+
+ return tool.phases.map(phaseId => allPhaseNames[phaseId]).filter(Boolean).join(', ');
+ }
+
+ const resultsHTML = `
+
+ `;
+
+ aiResults.innerHTML = '';
+ const tempDiv = document.createElement('div');
+ tempDiv.innerHTML = resultsHTML;
+ aiResults.appendChild(tempDiv);
+ }
+
const handleSubmit = async () => {
const query = aiInput.value.trim();
@@ -402,456 +909,6 @@ document.addEventListener('DOMContentLoaded', () => {
}
};
- function formatWorkflowSuggestion(text) {
- const numberedListPattern = /(\d+\.\s)/g;
-
- if (numberedListPattern.test(text)) {
- const items = text.split(/\d+\.\s/).filter(item => item.trim().length > 0);
-
- if (items.length > 1) {
- const listItems = items.map(item =>
- `${item.trim()}`
- ).join('');
-
- return `${listItems}
`;
- }
- }
-
- const bulletPattern = /^[\s]*[-\*•]\s/gm;
- if (bulletPattern.test(text)) {
- const items = text.split(/^[\s]*[-\*•]\s/gm).filter(item => item.trim().length > 0);
-
- if (items.length > 1) {
- const listItems = items.map(item =>
- `${item.trim()}`
- ).join('');
-
- return ``;
- }
- }
-
- if (text.includes('\n')) {
- const lines = text.split('\n').filter(line => line.trim().length > 0);
- if (lines.length > 1) {
- const listItems = lines.map(line =>
- `${line.trim()}`
- ).join('');
-
- return ``;
- }
- }
-
- return `${text}
`;
- }
-
- function renderBackgroundKnowledge(backgroundKnowledge) {
- if (!backgroundKnowledge || backgroundKnowledge.length === 0) {
- return '';
- }
-
- const conceptLinks = backgroundKnowledge.map(concept => `
-
-
-
- Hintergrundwissen
-
-
- ${concept.relevance}
-
-
- `).join('');
-
- return `
-
-
-
-
-
-
- Empfohlenes Hintergrundwissen
-
- ${conceptLinks}
-
- `;
- }
-
- function displayWorkflowResults(recommendation, originalQuery) {
- const toolsByPhase = {};
-
- const phaseOrder = phases.map(phase => phase.id);
- const phaseNames = phases.reduce((acc, phase) => {
- acc[phase.id] = phase.name;
- return acc;
- }, {});
-
- phaseOrder.forEach(phase => {
- toolsByPhase[phase] = [];
- });
-
- recommendation.recommended_tools?.forEach(recTool => {
- if (toolsByPhase[recTool.phase]) {
- const fullTool = tools.find(t => t.name === recTool.name);
- if (fullTool) {
- toolsByPhase[recTool.phase].push({
- ...fullTool,
- recommendation: recTool
- });
- }
- }
- });
-
- const resultsHTML = `
-
-
-
Empfohlener DFIR-Workflow
-
- Basierend auf Ihrer Anfrage: "${originalQuery.slice(0, 100)}${originalQuery.length > 100 ? '...' : ''}"
-
-
-
- ${recommendation.scenario_analysis ? `
-
-
-
-
-
-
- Szenario-Analyse
-
- ${formatWorkflowSuggestion(recommendation.scenario_analysis)}
-
- ` : ''}
-
- ${renderBackgroundKnowledge(recommendation.background_knowledge)}
-
- ${phaseOrder.map((phase, index) => {
- const phaseTools = toolsByPhase[phase];
- if (phaseTools.length === 0) return '';
-
- return `
-
-
- ${index < phaseOrder.length - 1 ? `
-
- ` : ''}
-
- `;
- }).join('')}
-
- ${recommendation.workflow_suggestion ? `
-
-
-
-
-
-
- Workflow-Empfehlung
-
- ${formatWorkflowSuggestion(recommendation.workflow_suggestion)}
-
- ` : ''}
-
- ${recommendation.additional_notes ? `
-
-
-
-
-
-
-
- Wichtige Hinweise
-
-
- ${formatWorkflowSuggestion(recommendation.additional_notes).replace(/color: var\(--color-text\)/g, 'color: white')}
-
-
- ` : ''}
-
- `;
-
- aiResults.innerHTML = '';
- const tempDiv = document.createElement('div');
- tempDiv.innerHTML = resultsHTML;
- aiResults.appendChild(tempDiv);
- }
-
- function displayToolResults(recommendation, originalQuery) {
- function getSuitabilityText(score) {
- const suitabilityTexts = {
- high: 'GUT GEEIGNET',
- medium: 'GEEIGNET',
- low: 'VIELLEICHT GEEIGNET'
- };
- return suitabilityTexts[score] || 'GEEIGNET';
- }
-
- function getToolPhases(tool) {
- if (!tool.phases || tool.phases.length === 0) return '';
-
- const phaseNames = phases.reduce((acc, phase) => {
- acc[phase.id] = phase.name;
- return acc;
- }, {});
-
- const domainAgnosticNames = domainAgnosticSoftware.reduce((acc, section) => {
- acc[section.id] = section.name;
- return acc;
- }, {});
-
- const allPhaseNames = { ...phaseNames, ...domainAgnosticNames };
-
- return tool.phases.map(phaseId => allPhaseNames[phaseId]).filter(Boolean).join(', ');
- }
- const resultsHTML = `
-
- `;
-
- aiResults.innerHTML = '';
- const tempDiv = document.createElement('div');
- tempDiv.innerHTML = resultsHTML;
- aiResults.appendChild(tempDiv);
- }
-
updateModeUI();
});
\ No newline at end of file
diff --git a/src/pages/api/ai/enhance-input.ts b/src/pages/api/ai/enhance-input.ts
new file mode 100644
index 0000000..ccfb2fe
--- /dev/null
+++ b/src/pages/api/ai/enhance-input.ts
@@ -0,0 +1,182 @@
+// src/pages/api/ai/enhance-input.ts
+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_MODEL = getEnv('AI_MODEL');
+const rateLimitStore = new Map();
+const RATE_LIMIT_WINDOW = 60 * 1000; // 1 minute
+const RATE_LIMIT_MAX = 5; // 5 enhancement requests per minute per user
+
+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); // Shorter limit for enhancement
+}
+
+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);
+ }
+ }
+}
+
+// Clean up expired limits every 5 minutes
+setInterval(cleanupExpiredRateLimits, 5 * 60 * 1000);
+
+function createEnhancementPrompt(input: string): string {
+ return `Analysiere diese forensische Szenario-Beschreibung und schlage 2-3 kurze, präzise Fragen vor, die dem Nutzer helfen würden, vollständigere Informationen zu liefern.
+
+Nutzer-Eingabe: "${input}"
+
+Konzentriere dich auf wichtige Details die für eine forensische Untersuchung relevant sind:
+- Betroffene Systeme/Plattformen
+- Zeitrahmen/Timeline
+- Verfügbare Evidenz
+- Verdächtige Aktivitäten
+- Technische Details
+
+Antworte NUR mit einem JSON-Array von 2-3 kurzen Fragen (max. 60 Zeichen pro Frage):
+["Frage 1?", "Frage 2?", "Frage 3?"]
+
+Keine zusätzlichen Erklärungen.`;
+}
+
+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 < 20) {
+ return apiError.badRequest('Input too short for enhancement');
+ }
+
+ const sanitizedInput = sanitizeInput(input);
+ if (sanitizedInput.length < 20) {
+ 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(process.env.AI_API_ENDPOINT + '/v1/chat/completions', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Authorization': `Bearer ${process.env.AI_API_KEY}`
+ },
+ body: JSON.stringify({
+ model: AI_MODEL,
+ messages: [
+ {
+ role: 'user',
+ content: systemPrompt
+ }
+ ],
+ max_tokens: 200,
+ temperature: 0.7
+ })
+ }), 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 {
+ // Clean up the response and parse JSON
+ const cleanedContent = aiContent
+ .replace(/^```json\s*/i, '')
+ .replace(/\s*```\s*$/, '')
+ .trim();
+
+ questions = JSON.parse(cleanedContent);
+
+ if (!Array.isArray(questions) || questions.length === 0) {
+ throw new Error('Invalid questions format');
+ }
+
+ // Validate and clean questions
+ questions = questions
+ .filter(q => typeof q === 'string' && q.length > 5 && q.length < 100)
+ .slice(0, 3);
+
+ if (questions.length === 0) {
+ throw new Error('No valid questions found');
+ }
+
+ } catch (error) {
+ console.error('Failed to parse enhancement response:', aiContent);
+ return apiServerError.unavailable('Invalid enhancement response format');
+ }
+
+ console.log(`[AI Enhancement] User: ${userId}, Questions: ${questions.length}, Input length: ${sanitizedInput.length}`);
+
+ return new Response(JSON.stringify({
+ success: true,
+ questions,
+ taskId
+ }), {
+ status: 200,
+ headers: { 'Content-Type': 'application/json' }
+ });
+
+ } catch (error) {
+ console.error('Enhancement error:', error);
+ return apiServerError.internal('Enhancement processing failed');
+ }
+};
\ No newline at end of file
diff --git a/src/pages/api/ai/query.ts b/src/pages/api/ai/query.ts
index c011d84..55cae17 100644
--- a/src/pages/api/ai/query.ts
+++ b/src/pages/api/ai/query.ts
@@ -155,6 +155,11 @@ WICHTIGE REGELN:
8. WICHTIG: Erwähne relevante Hintergrundwissen-Konzepte wenn Tools verwendet werden, die related_concepts haben
9. Konzepte sind NICHT Tools - empfehle sie nicht als actionable Schritte, sondern als Wissensbasis
+ENHANCED CONTEXTUAL ANALYSIS:
+10. Analysiere das Szenario detailliert und identifiziere Schlüsselelemente, Bedrohungen und forensische Herausforderungen
+11. Entwickle einen strategischen Untersuchungsansatz basierend auf dem spezifischen Szenario
+12. Identifiziere zeitkritische oder besonders wichtige Faktoren für diesen Fall
+
SOFTWARE/METHODEN-AUSWAHL NACH PHASE:
${phaseDescriptions}
@@ -163,16 +168,18 @@ ${domainAgnosticDescriptions}
ANTWORT-FORMAT (strict JSON):
{
- "scenario_analysis": "Detaillierte Analyse des Szenarios auf Deutsch/English",
+ "scenario_analysis": "Detaillierte Analyse des Szenarios: Erkannte Schlüsselelemente, Art des Vorfalls, betroffene Systeme, potentielle Bedrohungen und forensische Herausforderungen",
+ "investigation_approach": "Strategischer Untersuchungsansatz für dieses spezifische Szenario: Prioritäten, Reihenfolge der Phasen, besondere Überlegungen",
+ "critical_considerations": "Zeitkritische Faktoren, wichtige Sicherheitsaspekte oder besondere Vorsichtsmaßnahmen für diesen Fall",
"recommended_tools": [
{
"name": "EXAKTER Name aus der Tools-Database",
"priority": "high|medium|low",
"phase": "${validPhases}",
- "justification": "Warum diese Methode für diese Phase und Szenario geeignet ist"
+ "justification": "Warum diese Methode für diese Phase und dieses spezifische Szenario geeignet ist - mit Bezug zu den erkannten Schlüsselelementen"
}
],
- "workflow_suggestion": "Vorgeschlagener Untersuchungsablauf",
+ "workflow_suggestion": "Vorgeschlagener Untersuchungsablauf mit konkreten Schritten für dieses Szenario",
"background_knowledge": [
{
"concept_name": "EXAKTER Name aus der Konzepte-Database",
@@ -230,15 +237,22 @@ WICHTIGE REGELN:
10. WICHTIG: Erwähne relevante Hintergrundwissen-Konzepte wenn Tools verwendet werden, die related_concepts haben
11. Konzepte sind NICHT Tools - empfehle sie nicht als actionable Schritte, sondern als Wissensbasis
+ENHANCED CONTEXTUAL ANALYSIS:
+12. Analysiere das Problem detailliert und identifiziere technische Anforderungen, Herausforderungen und Erfolgsfaktoren
+13. Entwickle einen strategischen Lösungsansatz basierend auf dem spezifischen Problem
+14. Identifiziere wichtige Voraussetzungen oder Warnungen für die Anwendung
+
ANTWORT-FORMAT (strict JSON):
{
- "problem_analysis": "Detaillierte Analyse des Problems/der Anforderung",
+ "problem_analysis": "Detaillierte Analyse des Problems: Erkannte technische Anforderungen, Herausforderungen, benötigte Fähigkeiten und Erfolgsfaktoren",
+ "investigation_approach": "Strategischer Lösungsansatz für dieses spezifische Problem: Herangehensweise, Prioritäten, optimale Anwendungsreihenfolge",
+ "critical_considerations": "Wichtige Voraussetzungen, potentielle Fallstricke oder Warnungen für die Anwendung der empfohlenen Lösungen",
"recommended_tools": [
{
"name": "EXAKTER Name aus der Tools-Database",
"rank": 1,
"suitability_score": "high|medium|low",
- "detailed_explanation": "Detaillierte Erklärung, warum dieses Tool/diese Methode das Problem löst",
+ "detailed_explanation": "Detaillierte Erklärung, warum dieses Tool/diese Methode das spezifische Problem löst - mit Bezug zu den erkannten Anforderungen",
"implementation_approach": "Konkrete Schritte/Ansatz zur Anwendung für dieses spezifische Problem",
"pros": ["Spezifische Vorteile für diesen Anwendungsfall", "Weitere Vorteile"],
"cons": ["Potentielle Nachteile oder Limitationen", "Weitere Einschränkungen"],
@@ -348,6 +362,10 @@ export const POST: APIRoute = async ({ request }) => {
if (mode === 'workflow') {
validatedRecommendation = {
...recommendation,
+ // Ensure all new fields are included with fallbacks
+ scenario_analysis: recommendation.scenario_analysis || recommendation.problem_analysis || '',
+ investigation_approach: recommendation.investigation_approach || '',
+ critical_considerations: recommendation.critical_considerations || '',
recommended_tools: recommendation.recommended_tools?.filter((tool: any) => {
if (!validToolNames.has(tool.name)) {
console.warn(`AI recommended unknown tool: ${tool.name}`);
@@ -366,6 +384,10 @@ export const POST: APIRoute = async ({ request }) => {
} else {
validatedRecommendation = {
...recommendation,
+ // Ensure all new fields are included with fallbacks
+ problem_analysis: recommendation.problem_analysis || recommendation.scenario_analysis || '',
+ investigation_approach: recommendation.investigation_approach || '',
+ critical_considerations: recommendation.critical_considerations || '',
recommended_tools: recommendation.recommended_tools?.filter((tool: any) => {
if (!validToolNames.has(tool.name)) {
console.warn(`AI recommended unknown tool: ${tool.name}`);