forensic-pathways/dfir_yaml_editor.html
overcuriousity b1834aace1 prepare prod
2025-07-27 23:45:30 +02:00

1976 lines
87 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DFIR Tools YAML Editor</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-yaml/4.1.0/js-yaml.min.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--primary: #3498db;
--secondary: #95a5a6;
--success: #27ae60;
--warning: #f39c12;
--danger: #e74c3c;
--dark: #2c3e50;
--light: #ecf0f1;
--border: #dee2e6;
--accent: #9b59b6;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1400px;
margin: 0 auto;
background: white;
border-radius: 15px;
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
overflow: hidden;
}
.header {
background: linear-gradient(135deg, var(--dark) 0%, var(--primary) 100%);
color: white;
padding: 25px;
text-align: center;
}
.tabs {
background: var(--light);
display: flex;
border-bottom: 2px solid var(--border);
overflow-x: auto;
}
.tab {
padding: 15px 25px;
cursor: pointer;
border-bottom: 3px solid transparent;
transition: all 0.3s ease;
font-weight: 500;
white-space: nowrap;
min-width: 120px;
}
.tab:hover {
background: var(--border);
}
.tab.active {
background: white;
border-bottom-color: var(--primary);
color: var(--primary);
}
.tab-content {
display: none;
padding: 30px;
min-height: 600px;
}
.tab-content.active {
display: block;
}
.btn {
background: var(--primary);
color: white;
border: none;
padding: 12px 24px;
border-radius: 8px;
cursor: pointer;
font-weight: 500;
margin: 5px;
transition: all 0.3s ease;
text-decoration: none;
display: inline-block;
}
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(52, 152, 219, 0.3);
}
.btn:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none;
box-shadow: none;
}
.btn-secondary { background: var(--secondary); }
.btn-danger { background: var(--danger); }
.btn-success { background: var(--success); }
.btn-warning { background: var(--warning); }
.btn-accent { background: var(--accent); }
.search-container {
background: var(--light);
padding: 15px;
border-radius: 8px;
margin-bottom: 20px;
}
.search-input {
width: 100%;
padding: 12px;
border: 2px solid var(--border);
border-radius: 8px;
font-size: 16px;
transition: border-color 0.3s ease;
}
.search-input:focus {
outline: none;
border-color: var(--primary);
}
.search-results-info {
margin-top: 10px;
font-size: 14px;
color: var(--secondary);
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.stat-card {
background: var(--primary);
color: white;
padding: 20px;
border-radius: 10px;
text-align: center;
}
.tools-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
margin-top: 20px;
}
.tool-card {
background: white;
border: 1px solid var(--border);
border-radius: 10px;
padding: 20px;
transition: all 0.3s ease;
}
.tool-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}
.tool-card.software { border-left: 4px solid var(--primary); }
.tool-card.method { border-left: 4px solid var(--accent); }
.tool-card.concept { border-left: 4px solid #e67e22; }
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 600;
color: var(--dark);
}
.form-group input,
.form-group select,
.form-group textarea {
width: 100%;
padding: 12px;
border: 2px solid var(--border);
border-radius: 8px;
font-size: 14px;
transition: border-color 0.3s ease;
}
.form-group input:focus,
.form-group select:focus,
.form-group textarea:focus {
outline: none;
border-color: var(--primary);
}
.checkbox-group {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 12px;
margin-top: 10px;
padding: 15px;
background: #f8f9fa;
border-radius: 8px;
}
.checkbox-item {
display: flex;
align-items: center;
gap: 8px;
padding: 8px;
border-radius: 6px;
transition: background-color 0.2s ease;
}
.checkbox-item:hover {
background: rgba(52, 152, 219, 0.1);
}
.checkbox-item input[type="checkbox"] {
width: auto;
margin: 0;
}
.tags-input {
display: flex;
flex-wrap: wrap;
gap: 8px;
min-height: 50px;
padding: 12px;
border: 2px solid var(--border);
border-radius: 8px;
background: white;
transition: border-color 0.3s ease;
}
.tags-input:focus-within {
border-color: var(--primary);
}
.tag {
background: var(--light);
padding: 6px 12px;
border-radius: 20px;
font-size: 0.9em;
display: flex;
align-items: center;
gap: 8px;
border: 1px solid var(--border);
}
.tag-remove {
cursor: pointer;
font-weight: bold;
color: #666;
background: rgba(231, 76, 60, 0.1);
border-radius: 50%;
width: 18px;
height: 18px;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
}
.tag-remove:hover {
background: var(--danger);
color: white;
}
.bulk-section {
background: var(--light);
padding: 20px;
border-radius: 10px;
margin-bottom: 20px;
border: 2px solid var(--border);
}
.bulk-controls {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 10px;
margin-top: 15px;
}
.message {
padding: 15px;
border-radius: 8px;
margin: 10px 0;
position: fixed;
top: 20px;
right: 20px;
z-index: 1000;
min-width: 300px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}
.message.success {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.message.error {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.hidden { display: none !important; }
.filter-section {
display: flex;
gap: 15px;
align-items: center;
flex-wrap: wrap;
margin-top: 15px;
}
.filter-section select {
min-width: 150px;
}
.form-section {
background: #f8f9fa;
padding: 20px;
border-radius: 10px;
margin-bottom: 20px;
border-left: 4px solid var(--primary);
}
.form-section h4 {
margin: 0 0 15px 0;
color: var(--dark);
display: flex;
align-items: center;
gap: 8px;
}
.loading {
opacity: 0.7;
pointer-events: none;
}
@media (max-width: 768px) {
.tabs {
flex-direction: column;
}
.tab {
min-width: auto;
text-align: center;
}
.stats-grid {
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}
.tools-grid {
grid-template-columns: 1fr;
}
.checkbox-group {
grid-template-columns: 1fr;
}
.bulk-controls {
grid-template-columns: 1fr;
}
.filter-section {
flex-direction: column;
align-items: stretch;
}
.message {
position: relative;
top: auto;
right: auto;
min-width: auto;
}
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🔧 DFIR Tools YAML Editor</h1>
<p>Enhanced editor for Digital Forensics and Incident Response tools, methods, and concepts</p>
</div>
<div class="tabs">
<div class="tab active" onclick="showTab('overview')">📊 Overview</div>
<div class="tab" onclick="showTab('tools')">🛠️ Tools & Concepts</div>
<div class="tab" onclick="showTab('editor')">✏️ Editor</div>
<div class="tab" onclick="showTab('bulk')">📋 Bulk Edit</div>
<div class="tab" onclick="showTab('knowledge')">📚 Knowledge Generator</div>
<div class="tab" onclick="showTab('export')">💾 Export</div>
</div>
<!-- Overview Tab -->
<div id="overview" class="tab-content active">
<div style="background: var(--light); padding: 20px; border-radius: 10px; margin-bottom: 20px; border: 2px dashed var(--border); text-align: center;">
<h3>📁 Load YAML File</h3>
<input type="file" id="fileInput" accept=".yaml,.yml" onchange="loadFile()">
<p>Select a YAML file to load existing tools data</p>
</div>
<div id="stats" class="stats-grid"></div>
<div id="validationResults" class="hidden">
<h3>🔍 Validation Results</h3>
<div id="validationContent"></div>
</div>
<div style="text-align: center; margin-top: 20px;">
<button class="btn" onclick="validateYAML()">🔍 Validate YAML</button>
<button class="btn btn-secondary" onclick="previewYAML()">👁️ Preview YAML</button>
</div>
</div>
<!-- Tools Tab with Enhanced Search -->
<div id="tools" class="tab-content">
<div class="search-container">
<h3>🔍 Search & Filter Tools</h3>
<input type="text"
id="searchInput"
class="search-input"
placeholder="Search by name, description, tags, related concepts, related software, or scenarios..."
oninput="applySearch()">
<div class="search-results-info" id="searchResults"></div>
<div class="filter-section">
<label>Type:</label>
<select id="typeFilter" onchange="applyFilters()">
<option value="">All Types</option>
<option value="software">Software</option>
<option value="method">Method</option>
<option value="concept">Concept</option>
</select>
<label>Skill Level:</label>
<select id="skillFilter" onchange="applyFilters()">
<option value="">All Levels</option>
<option value="novice">Novice</option>
<option value="beginner">Beginner</option>
<option value="intermediate">Intermediate</option>
<option value="advanced">Advanced</option>
<option value="expert">Expert</option>
</select>
<button class="btn btn-secondary" onclick="clearFilters()">Clear All</button>
</div>
</div>
<div id="toolsGrid" class="tools-grid"></div>
</div>
<!-- Enhanced Editor Tab -->
<div id="editor" class="tab-content">
<h3>✏️ Add/Edit Tool, Method, or Concept</h3>
<form id="toolForm">
<div class="form-section">
<h4>📝 Basic Information</h4>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px;">
<div class="form-group">
<label for="toolType">Type *</label>
<select id="toolType" onchange="toggleConditionalFields()" required>
<option value="software">Software</option>
<option value="method">Method</option>
<option value="concept">Concept</option>
</select>
</div>
<div class="form-group">
<label for="skillLevel">Skill Level *</label>
<select id="skillLevel" required>
<option value="novice">Novice</option>
<option value="beginner">Beginner</option>
<option value="intermediate">Intermediate</option>
<option value="advanced">Advanced</option>
<option value="expert">Expert</option>
</select>
</div>
</div>
<div style="display: grid; grid-template-columns: 1fr auto; gap: 15px; align-items: end;">
<div class="form-group">
<label for="toolName">Name *</label>
<input type="text" id="toolName" required>
</div>
<div class="form-group">
<label for="toolIcon">Icon</label>
<input type="text" id="toolIcon" placeholder="🔧" maxlength="4" style="width: 80px; text-align: center; font-size: 1.5em;">
</div>
</div>
<div class="form-group">
<label for="description">Description *</label>
<textarea id="description" required rows="4" placeholder="Detailed description of the tool, method, or concept..."></textarea>
</div>
<div class="form-group">
<label for="url">URL *</label>
<input type="url" id="url" required placeholder="https://example.com">
</div>
</div>
<div class="form-section">
<h4>🎯 Classification</h4>
<div class="form-group">
<label>Domains</label>
<div id="domainsCheckbox" class="checkbox-group"></div>
</div>
<div class="form-group">
<label>Phases</label>
<div id="phasesCheckbox" class="checkbox-group"></div>
</div>
<div class="form-group">
<label>Scenarios</label>
<div id="scenariosCheckbox" class="checkbox-group"></div>
</div>
</div>
<!-- Software/Method specific fields -->
<div id="softwareMethodFields" class="form-section">
<h4>⚙️ Technical Details</h4>
<div class="form-group">
<label>Platforms</label>
<div id="platformsCheckbox" class="checkbox-group">
<div class="checkbox-item">
<input type="checkbox" value="Windows" id="platform-windows">
<label for="platform-windows">Windows</label>
</div>
<div class="checkbox-item">
<input type="checkbox" value="Linux" id="platform-linux">
<label for="platform-linux">Linux</label>
</div>
<div class="checkbox-item">
<input type="checkbox" value="macOS" id="platform-macos">
<label for="platform-macos">macOS</label>
</div>
<div class="checkbox-item">
<input type="checkbox" value="Web" id="platform-web">
<label for="platform-web">Web</label>
</div>
<div class="checkbox-item">
<input type="checkbox" value="Cloud" id="platform-cloud">
<label for="platform-cloud">Cloud</label>
</div>
</div>
</div>
<div class="form-group">
<label>Domain-Agnostic Categories</label>
<div id="domainAgnosticCheckbox" class="checkbox-group"></div>
</div>
</div>
<!-- Software specific fields -->
<div id="softwareFields" class="form-section">
<h4>💻 Software Specific</h4>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px;">
<div class="form-group">
<label for="accessType">Access Type</label>
<select id="accessType">
<option value="">Select Access Type</option>
<option value="download">Download</option>
<option value="web">Web Application</option>
<option value="api">API</option>
<option value="cli">Command Line</option>
<option value="service">Service</option>
</select>
</div>
<div class="form-group">
<label for="license">License</label>
<input type="text" id="license" placeholder="e.g., Apache 2.0, MIT, Proprietary">
</div>
</div>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px;">
<div class="form-group">
<label for="projectUrl">Project URL (CC24 Server)</label>
<input type="url" id="projectUrl" placeholder="https://cc24-server.example.com">
</div>
<div class="form-group">
<label for="statusUrl">Status URL</label>
<input type="url" id="statusUrl" placeholder="https://status.example.com">
</div>
</div>
</div>
<div class="form-section">
<h4>🔗 Relationships</h4>
<div class="form-group">
<div class="checkbox-item" style="background: #e8f5e8; padding: 12px; border-radius: 8px;">
<input type="checkbox" id="knowledgebase">
<label for="knowledgebase">📚 Has Extended Knowledgebase</label>
</div>
</div>
<div class="form-group">
<label for="tagsInput">🏷️ Tags</label>
<div class="tags-input" id="tagsInput" onclick="focusTagInput()">
<input type="text" id="tagInputField" placeholder="Add tags..." onkeydown="handleTagInput(event)" style="border: none; outline: none; flex: 1; min-width: 100px;">
</div>
</div>
<div class="form-group">
<label for="relatedConceptsInput">💡 Related Concepts</label>
<div class="tags-input" id="relatedConceptsInput" onclick="focusRelatedConceptInput()">
<input type="text" id="relatedConceptInputField" placeholder="Add concept names..." onkeydown="handleRelatedConceptInput(event)" style="border: none; outline: none; flex: 1; min-width: 100px;">
</div>
</div>
<div class="form-group">
<label for="relatedSoftwareInput">🛠️ Related Software</label>
<div class="tags-input" id="relatedSoftwareInput" onclick="focusRelatedSoftwareInput()">
<input type="text" id="relatedSoftwareInputField" placeholder="Add software names..." onkeydown="handleRelatedSoftwareInput(event)" style="border: none; outline: none; flex: 1; min-width: 100px;">
</div>
</div>
</div>
<div style="text-align: center; margin-top: 30px; padding: 20px; background: var(--light); border-radius: 10px;">
<button type="button" class="btn btn-success" onclick="saveTool()">💾 Save Tool</button>
<button type="button" class="btn btn-secondary" onclick="clearForm()">🔄 Clear Form</button>
<button type="button" class="btn btn-warning" onclick="cancelEdit()">❌ Cancel Edit</button>
</div>
</form>
</div>
<!-- Enhanced Bulk Edit Tab -->
<div id="bulk" class="tab-content">
<div class="bulk-section">
<h3>📋 Bulk Operations</h3>
<div id="selectionInfo" style="margin-bottom: 15px; padding: 15px; background: white; border-radius: 8px; font-weight: 600; text-align: center; border: 2px solid var(--primary);">
No tools selected
</div>
<div class="bulk-controls">
<button class="btn" onclick="selectAllTools()">✅ Select All</button>
<button class="btn btn-secondary" onclick="clearSelection()">❌ Clear Selection</button>
<button class="btn btn-warning" onclick="bulkSetType()">🔄 Set Type</button>
<button class="btn btn-warning" onclick="bulkSetSkillLevel()">📊 Set Skill Level</button>
</div>
<h4 style="margin: 25px 0 10px 0; color: var(--dark); border-bottom: 2px solid var(--border); padding-bottom: 5px;">🏷️ Tags Operations</h4>
<div class="bulk-controls">
<button class="btn btn-accent" onclick="bulkAddTags()"> Add Tags</button>
<button class="btn btn-danger" onclick="bulkRemoveTags()"> Remove Tags</button>
<button class="btn btn-secondary" onclick="bulkReplaceTags()">🔄 Replace Tags</button>
<button class="btn btn-danger" onclick="bulkClearTags()">🗑️ Clear All Tags</button>
</div>
<h4 style="margin: 25px 0 10px 0; color: var(--dark); border-bottom: 2px solid var(--border); padding-bottom: 5px;">🎯 Classification Operations</h4>
<div class="bulk-controls">
<button class="btn btn-accent" onclick="bulkAddDomains()"> Add Domains</button>
<button class="btn btn-danger" onclick="bulkRemoveDomains()"> Remove Domains</button>
<button class="btn btn-danger" onclick="bulkClearDomains()">🗑️ Clear Domains</button>
<button class="btn btn-accent" onclick="bulkAddPhases()"> Add Phases</button>
<button class="btn btn-danger" onclick="bulkRemovePhases()"> Remove Phases</button>
<button class="btn btn-danger" onclick="bulkClearPhases()">🗑️ Clear Phases</button>
</div>
<h4 style="margin: 25px 0 10px 0; color: var(--dark); border-bottom: 2px solid var(--border); padding-bottom: 5px;">🎮 Scenarios Operations</h4>
<div class="bulk-controls">
<button class="btn btn-accent" onclick="bulkAddScenarios()"> Add Scenarios</button>
<button class="btn btn-danger" onclick="bulkRemoveScenarios()"> Remove Scenarios</button>
<button class="btn btn-danger" onclick="bulkClearScenarios()">🗑️ Clear Scenarios</button>
</div>
<h4 style="margin: 25px 0 10px 0; color: var(--dark); border-bottom: 2px solid var(--border); padding-bottom: 5px;">💻 Platform Operations</h4>
<div class="bulk-controls">
<button class="btn btn-accent" onclick="bulkAddPlatforms()"> Add Platforms</button>
<button class="btn btn-danger" onclick="bulkRemovePlatforms()"> Remove Platforms</button>
<button class="btn btn-danger" onclick="bulkClearPlatforms()">🗑️ Clear Platforms</button>
</div>
<h4 style="margin: 25px 0 10px 0; color: var(--dark); border-bottom: 2px solid var(--border); padding-bottom: 5px;">🔗 Relationships Operations</h4>
<div class="bulk-controls">
<button class="btn btn-accent" onclick="bulkAddRelatedConcepts()"> Add Related Concepts</button>
<button class="btn btn-danger" onclick="bulkRemoveRelatedConcepts()"> Remove Related Concepts</button>
<button class="btn btn-danger" onclick="bulkClearRelatedConcepts()">🗑️ Clear Related Concepts</button>
<button class="btn btn-accent" onclick="bulkAddRelatedSoftware()"> Add Related Software</button>
<button class="btn btn-danger" onclick="bulkRemoveRelatedSoftware()"> Remove Related Software</button>
<button class="btn btn-danger" onclick="bulkClearRelatedSoftware()">🗑️ Clear Related Software</button>
</div>
<h4 style="margin: 25px 0 10px 0; color: var(--danger); border-bottom: 2px solid var(--danger); padding-bottom: 5px;">⚠️ Dangerous Operations</h4>
<div class="bulk-controls">
<button class="btn btn-danger" onclick="bulkDelete()">💀 Delete Selected Tools</button>
</div>
</div>
<div id="bulkToolsGrid" class="tools-grid"></div>
</div>
<!-- Knowledge Generator Tab -->
<div id="knowledge" class="tab-content">
<div style="background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 8px; padding: 20px; margin-top: 20px;">
<h3>📚 Knowledgebase Entry Generator</h3>
<p>Generate properly formatted markdown files for ForensicPathways knowledgebase.</p>
<div class="form-group">
<label for="knowledgeToolSelect">Select Tool/Concept:</label>
<select id="knowledgeToolSelect" onchange="generateKnowledgeTemplate()">
<option value="">Choose a tool or concept...</option>
</select>
</div>
<div id="knowledgePreview" class="hidden">
<h4>Generated Markdown Template:</h4>
<textarea id="markdownContent" readonly style="width: 100%; height: 400px; font-family: monospace; background: var(--light); border: 1px solid var(--border); border-radius: 4px; padding: 15px;"></textarea>
<div style="margin-top: 10px;">
<button class="btn" onclick="downloadMarkdown()">💾 Download Markdown</button>
<button class="btn btn-secondary" onclick="copyMarkdown()">📋 Copy to Clipboard</button>
</div>
</div>
</div>
</div>
<!-- Export Tab -->
<div id="export" class="tab-content">
<h3>💾 Export & Preview</h3>
<div id="yamlPreview" class="hidden">
<h4>YAML Preview:</h4>
<textarea id="yamlPreviewText" readonly style="width: 100%; height: 400px; font-family: monospace; border: 2px solid var(--border); border-radius: 8px; padding: 15px;"></textarea>
</div>
<div style="text-align: center; margin-top: 20px;">
<button class="btn" onclick="previewYAML()">👁️ Preview YAML</button>
<button class="btn btn-success" onclick="exportYAML()">📥 Export YAML</button>
<button class="btn btn-secondary" onclick="exportJSON()">📄 Export JSON</button>
</div>
</div>
</div>
<script>
let yamlData = null;
let currentEditingIndex = -1;
let selectedTools = new Set();
let filteredToolsCache = [];
// Initialize with correct YAML structure including scenarios
function init() {
yamlData = {
tools: [],
domains: [
{ id: 'incident-response', name: 'Incident Response & Breach-Untersuchung' },
{ id: 'static-investigations', name: 'Datenträgerforensik & Ermittlungen' },
{ id: 'malware-analysis', name: 'Malware-Analyse & Reverse Engineering' },
{ id: 'fraud-investigation', name: 'Betrugs- & Finanzkriminalität' },
{ id: 'network-forensics', name: 'Netzwerk-Forensik & Traffic-Analyse' },
{ id: 'mobile-forensics', name: 'Mobile Geräte & App-Forensik' },
{ id: 'cloud-forensics', name: 'Cloud & Virtuelle Umgebungen' },
{ id: 'ics-forensics', name: 'Industrielle Kontrollsysteme (ICS/SCADA)' }
],
phases: [
{ id: 'data-collection', name: 'Datensammlung', description: 'Imaging, Acquisition, Remote Collection Tools' },
{ id: 'examination', name: 'Auswertung', description: 'Parsing, Extraction, Initial Analysis Tools' },
{ id: 'analysis', name: 'Analyse', description: 'Deep Analysis, Correlation, Visualization Tools' },
{ id: 'reporting', name: 'Bericht & Präsentation', description: 'Documentation, Visualization, Presentation Tools' }
],
'domain-agnostic-software': [
{ id: 'collaboration-general', name: 'Übergreifend & Kollaboration', description: 'Cross-cutting tools and collaboration platforms' },
{ id: 'specific-os', name: 'Betriebssysteme', description: 'Operating Systems which focus on forensics' }
],
scenarios: [
{ id: 'registry', icon: '🗃️', friendly_name: 'Registry-Analyse' },
{ id: 'memory-forensics', icon: '🧠', friendly_name: 'Memory-Forensik' },
{ id: 'network-analysis', icon: '🌐', friendly_name: 'Netzwerk-Analyse' },
{ id: 'malware-analysis', icon: '🦠', friendly_name: 'Malware-Analyse' },
{ id: 'mobile-forensics', icon: '📱', friendly_name: 'Mobile-Forensik' }
]
};
populateFormOptions();
updateStats();
renderToolsGrid();
updateKnowledgeToolSelect();
}
function showTab(tabName) {
document.querySelectorAll('.tab-content').forEach(content => content.classList.remove('active'));
document.querySelectorAll('.tab').forEach(tab => tab.classList.remove('active'));
document.getElementById(tabName).classList.add('active');
event.target.classList.add('active');
if (tabName === 'tools') renderToolsGrid();
else if (tabName === 'bulk') renderBulkGrid();
else if (tabName === 'knowledge') updateKnowledgeToolSelect();
}
// Enhanced Search Functionality including scenarios and related_software
function applySearch() {
applyFilters();
}
function searchTools(tools, searchTerm) {
if (!searchTerm) return tools;
const term = searchTerm.toLowerCase();
return tools.filter(tool => {
// Search in name
if (tool.name && tool.name.toLowerCase().includes(term)) return true;
// Search in description
if (tool.description && tool.description.toLowerCase().includes(term)) return true;
// Search in tags
if (tool.tags && tool.tags.some(tag => tag.toLowerCase().includes(term))) return true;
// Search in related concepts
if (tool.related_concepts && tool.related_concepts.some(concept => concept.toLowerCase().includes(term))) return true;
// Search in related software
if (tool.related_software && tool.related_software.some(software => software.toLowerCase().includes(term))) return true;
// Search in scenarios
if (tool.scenarios && tool.scenarios.some(scenario => {
const scenarioData = yamlData.scenarios.find(s => s.id === scenario);
return scenarioData && scenarioData.friendly_name.toLowerCase().includes(term);
})) return true;
// Search in type
if (tool.type && tool.type.toLowerCase().includes(term)) return true;
// Search in platforms
if (tool.platforms && tool.platforms.some(platform => platform.toLowerCase().includes(term))) return true;
return false;
});
}
function populateFormOptions() {
// Populate domains
const domainsContainer = document.getElementById('domainsCheckbox');
domainsContainer.innerHTML = '';
yamlData.domains.forEach(domain => {
const div = document.createElement('div');
div.className = 'checkbox-item';
div.innerHTML = `<input type="checkbox" value="${domain.id}" id="domain-${domain.id}"><label for="domain-${domain.id}">${domain.name}</label>`;
domainsContainer.appendChild(div);
});
// Populate phases
const phasesContainer = document.getElementById('phasesCheckbox');
phasesContainer.innerHTML = '';
yamlData.phases.forEach(phase => {
const div = document.createElement('div');
div.className = 'checkbox-item';
div.innerHTML = `<input type="checkbox" value="${phase.id}" id="phase-${phase.id}"><label for="phase-${phase.id}">${phase.name}</label>`;
phasesContainer.appendChild(div);
});
// Populate scenarios
const scenariosContainer = document.getElementById('scenariosCheckbox');
scenariosContainer.innerHTML = '';
yamlData.scenarios.forEach(scenario => {
const div = document.createElement('div');
div.className = 'checkbox-item';
div.innerHTML = `<input type="checkbox" value="${scenario.id}" id="scenario-${scenario.id}"><label for="scenario-${scenario.id}">${scenario.icon} ${scenario.friendly_name}</label>`;
scenariosContainer.appendChild(div);
});
// Populate domain-agnostic software
const domainAgnosticContainer = document.getElementById('domainAgnosticCheckbox');
domainAgnosticContainer.innerHTML = '';
yamlData['domain-agnostic-software'].forEach(category => {
const div = document.createElement('div');
div.className = 'checkbox-item';
div.innerHTML = `<input type="checkbox" value="${category.id}" id="domain-agnostic-${category.id}"><label for="domain-agnostic-${category.id}">${category.name}</label>`;
domainAgnosticContainer.appendChild(div);
});
}
function toggleConditionalFields() {
const toolType = document.getElementById('toolType').value;
const softwareMethodFields = document.getElementById('softwareMethodFields');
const softwareFields = document.getElementById('softwareFields');
if (toolType === 'concept') {
softwareMethodFields.style.display = 'none';
softwareFields.style.display = 'none';
} else if (toolType === 'method') {
softwareMethodFields.style.display = 'block';
softwareFields.style.display = 'none';
} else {
softwareMethodFields.style.display = 'block';
softwareFields.style.display = 'block';
}
}
function loadFile() {
const file = document.getElementById('fileInput').files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function(e) {
try {
yamlData = jsyaml.load(e.target.result);
showMessage('YAML file loaded successfully!', 'success');
populateFormOptions();
updateStats();
renderToolsGrid();
updateKnowledgeToolSelect();
} catch (error) {
showMessage('Error loading YAML file: ' + error.message, 'error');
}
};
reader.readAsText(file);
}
function showMessage(message, type = 'success') {
// Remove existing messages
document.querySelectorAll('.message').forEach(msg => msg.remove());
const messageDiv = document.createElement('div');
messageDiv.className = `message ${type}`;
messageDiv.textContent = message;
document.body.appendChild(messageDiv);
setTimeout(() => {
if (messageDiv.parentNode) {
messageDiv.remove();
}
}, 4000);
}
function updateStats() {
if (!yamlData?.tools) return;
const stats = {
total: yamlData.tools.length,
software: yamlData.tools.filter(t => t.type === 'software' || !t.type).length,
methods: yamlData.tools.filter(t => t.type === 'method').length,
concepts: yamlData.tools.filter(t => t.type === 'concept').length,
withKnowledgebase: yamlData.tools.filter(t => t.knowledgebase).length,
withRelatedSoftware: yamlData.tools.filter(t => t.related_software && t.related_software.length > 0).length
};
document.getElementById('stats').innerHTML = `
<div class="stat-card"><h3>${stats.total}</h3><p>Total Items</p></div>
<div class="stat-card"><h3>${stats.software}</h3><p>Software Tools</p></div>
<div class="stat-card"><h3>${stats.methods}</h3><p>Methods</p></div>
<div class="stat-card"><h3>${stats.concepts}</h3><p>Concepts</p></div>
<div class="stat-card"><h3>${stats.withKnowledgebase}</h3><p>With Knowledgebase</p></div>
<div class="stat-card"><h3>${stats.withRelatedSoftware}</h3><p>With Related Software</p></div>
`;
}
// Enhanced tag input handlers for related software
function focusTagInput() { document.getElementById('tagInputField').focus(); }
function focusRelatedConceptInput() { document.getElementById('relatedConceptInputField').focus(); }
function focusRelatedSoftwareInput() { document.getElementById('relatedSoftwareInputField').focus(); }
function handleTagInput(event) {
if (event.key === 'Enter' || event.key === ',') {
event.preventDefault();
const input = event.target;
const value = input.value.trim();
if (value) {
addTag('tagsInput', value);
input.value = '';
}
}
}
function handleRelatedConceptInput(event) {
if (event.key === 'Enter' || event.key === ',') {
event.preventDefault();
const input = event.target;
const value = input.value.trim();
if (value) {
addTag('relatedConceptsInput', value);
input.value = '';
}
}
}
function handleRelatedSoftwareInput(event) {
if (event.key === 'Enter' || event.key === ',') {
event.preventDefault();
const input = event.target;
const value = input.value.trim();
if (value) {
addTag('relatedSoftwareInput', value);
input.value = '';
}
}
}
function addTag(containerId, value) {
const container = document.getElementById(containerId);
const input = container.querySelector('input');
const tag = document.createElement('span');
tag.className = 'tag';
tag.innerHTML = `${value} <span class="tag-remove" onclick="this.parentElement.remove()">×</span>`;
container.insertBefore(tag, input);
}
function getCheckedValues(selector) {
return Array.from(document.querySelectorAll(selector + ':checked')).map(cb => cb.value);
}
function getTags() {
return Array.from(document.querySelectorAll('#tagsInput .tag')).map(tag =>
tag.textContent.replace('×', '').trim()
).filter(tag => tag);
}
function getRelatedConcepts() {
return Array.from(document.querySelectorAll('#relatedConceptsInput .tag')).map(tag =>
tag.textContent.replace('×', '').trim()
).filter(concept => concept);
}
function getRelatedSoftware() {
return Array.from(document.querySelectorAll('#relatedSoftwareInput .tag')).map(tag =>
tag.textContent.replace('×', '').trim()
).filter(software => software);
}
function saveTool() {
try {
if (!yamlData) yamlData = { tools: [] };
if (!yamlData.tools) yamlData.tools = [];
const toolType = document.getElementById('toolType').value;
const tool = {
name: document.getElementById('toolName').value,
type: toolType,
description: document.getElementById('description').value,
skillLevel: document.getElementById('skillLevel').value,
url: document.getElementById('url').value
};
// Add icon if provided
const icon = document.getElementById('toolIcon').value.trim();
if (icon) tool.icon = icon;
// Add domains, phases, and scenarios
tool.domains = getCheckedValues('#domainsCheckbox input:checked');
tool.phases = getCheckedValues('#phasesCheckbox input:checked');
const scenarios = getCheckedValues('#scenariosCheckbox input:checked');
if (scenarios.length > 0) tool.scenarios = scenarios;
// Add tags, related concepts, and related software
const tags = getTags();
if (tags.length > 0) tool.tags = tags;
const relatedConcepts = getRelatedConcepts();
if (relatedConcepts.length > 0) tool.related_concepts = relatedConcepts;
const relatedSoftware = getRelatedSoftware();
if (relatedSoftware.length > 0) tool.related_software = relatedSoftware;
// Type-specific fields
if (toolType === 'software') {
tool.platforms = getCheckedValues('#platformsCheckbox input:checked');
const accessType = document.getElementById('accessType').value;
if (accessType) tool.accessType = accessType;
const license = document.getElementById('license').value.trim();
if (license) tool.license = license;
const projectUrl = document.getElementById('projectUrl').value.trim();
if (projectUrl) tool.projectUrl = projectUrl;
const statusUrl = document.getElementById('statusUrl').value.trim();
if (statusUrl) tool.statusUrl = statusUrl;
tool.knowledgebase = document.getElementById('knowledgebase').checked;
const domainAgnostic = getCheckedValues('#domainAgnosticCheckbox input:checked');
if (domainAgnostic.length > 0) tool['domain-agnostic-software'] = domainAgnostic;
} else if (toolType === 'method') {
tool.platforms = getCheckedValues('#platformsCheckbox input:checked');
const domainAgnostic = getCheckedValues('#domainAgnosticCheckbox input:checked');
if (domainAgnostic.length > 0) tool['domain-agnostic-software'] = domainAgnostic;
tool.knowledgebase = document.getElementById('knowledgebase').checked;
} else if (toolType === 'concept') {
tool.knowledgebase = document.getElementById('knowledgebase').checked;
}
if (currentEditingIndex >= 0) {
yamlData.tools[currentEditingIndex] = tool;
showMessage('Tool updated successfully!');
currentEditingIndex = -1;
} else {
yamlData.tools.push(tool);
showMessage('Tool added successfully!');
}
clearForm();
updateStats();
renderToolsGrid();
updateKnowledgeToolSelect();
} catch (error) {
showMessage('Error saving tool: ' + error.message, 'error');
}
}
function clearForm() {
document.getElementById('toolForm').reset();
document.getElementById('tagsInput').innerHTML = '<input type="text" id="tagInputField" placeholder="Add tags..." onkeydown="handleTagInput(event)" style="border: none; outline: none; flex: 1; min-width: 100px;">';
document.getElementById('relatedConceptsInput').innerHTML = '<input type="text" id="relatedConceptInputField" placeholder="Add concept names..." onkeydown="handleRelatedConceptInput(event)" style="border: none; outline: none; flex: 1; min-width: 100px;">';
document.getElementById('relatedSoftwareInput').innerHTML = '<input type="text" id="relatedSoftwareInputField" placeholder="Add software names..." onkeydown="handleRelatedSoftwareInput(event)" style="border: none; outline: none; flex: 1; min-width: 100px;">';
currentEditingIndex = -1;
toggleConditionalFields();
}
function cancelEdit() {
clearForm();
showMessage('Edit cancelled');
}
function editTool(index) {
const tool = yamlData.tools[index];
currentEditingIndex = index;
// Populate form fields
document.getElementById('toolType').value = tool.type || 'software';
document.getElementById('toolName').value = tool.name || '';
document.getElementById('toolIcon').value = tool.icon || '';
document.getElementById('description').value = tool.description || '';
document.getElementById('skillLevel').value = tool.skillLevel || 'intermediate';
document.getElementById('url').value = tool.url || '';
// Software-specific fields
if (tool.type === 'software' || !tool.type) {
document.getElementById('accessType').value = tool.accessType || '';
document.getElementById('projectUrl').value = tool.projectUrl || '';
document.getElementById('license').value = tool.license || '';
document.getElementById('statusUrl').value = tool.statusUrl || '';
}
document.getElementById('knowledgebase').checked = tool.knowledgebase || false;
// Set checkboxes
setCheckboxValues('#domainsCheckbox input', tool.domains || []);
setCheckboxValues('#phasesCheckbox input', tool.phases || []);
setCheckboxValues('#scenariosCheckbox input', tool.scenarios || []);
setCheckboxValues('#platformsCheckbox input', tool.platforms || []);
setCheckboxValues('#domainAgnosticCheckbox input', tool['domain-agnostic-software'] || []);
// Set tags
const tagsContainer = document.getElementById('tagsInput');
tagsContainer.innerHTML = '<input type="text" id="tagInputField" placeholder="Add tags..." onkeydown="handleTagInput(event)" style="border: none; outline: none; flex: 1; min-width: 100px;">';
(tool.tags || []).forEach(tag => addTag('tagsInput', tag));
// Set related concepts
const conceptsContainer = document.getElementById('relatedConceptsInput');
conceptsContainer.innerHTML = '<input type="text" id="relatedConceptInputField" placeholder="Add concept names..." onkeydown="handleRelatedConceptInput(event)" style="border: none; outline: none; flex: 1; min-width: 100px;">';
(tool.related_concepts || []).forEach(concept => addTag('relatedConceptsInput', concept));
// Set related software
const softwareContainer = document.getElementById('relatedSoftwareInput');
softwareContainer.innerHTML = '<input type="text" id="relatedSoftwareInputField" placeholder="Add software names..." onkeydown="handleRelatedSoftwareInput(event)" style="border: none; outline: none; flex: 1; min-width: 100px;">';
(tool.related_software || []).forEach(software => addTag('relatedSoftwareInput', software));
toggleConditionalFields();
showTab('editor');
}
function setCheckboxValues(selector, values) {
document.querySelectorAll(selector).forEach(cb => {
cb.checked = values.includes(cb.value);
});
}
function deleteTool(index) {
if (confirm('Are you sure you want to delete this tool?')) {
yamlData.tools.splice(index, 1);
showMessage('Tool deleted successfully!');
updateStats();
renderToolsGrid();
updateKnowledgeToolSelect();
}
}
function renderToolsGrid() {
const container = document.getElementById('toolsGrid');
container.innerHTML = '';
if (!yamlData?.tools) return;
let filteredTools = yamlData.tools;
// Apply search filter
const searchTerm = document.getElementById('searchInput')?.value;
if (searchTerm) {
filteredTools = searchTools(filteredTools, searchTerm);
}
// Apply type and skill filters
const typeFilter = document.getElementById('typeFilter')?.value;
const skillFilter = document.getElementById('skillFilter')?.value;
if (typeFilter) filteredTools = filteredTools.filter(tool => (tool.type || 'software') === typeFilter);
if (skillFilter) filteredTools = filteredTools.filter(tool => tool.skillLevel === skillFilter);
// Cache filtered results
filteredToolsCache = filteredTools;
// Update search results info
const searchResults = document.getElementById('searchResults');
if (searchResults) {
const totalTools = yamlData.tools.length;
const filteredCount = filteredTools.length;
if (searchTerm || typeFilter || skillFilter) {
searchResults.textContent = `Showing ${filteredCount} of ${totalTools} tools`;
} else {
searchResults.textContent = `Showing all ${totalTools} tools`;
}
}
filteredTools.forEach((tool, index) => {
const originalIndex = yamlData.tools.indexOf(tool);
const card = createToolCard(tool, originalIndex);
container.appendChild(card);
});
}
function createToolCard(tool, index) {
const card = document.createElement('div');
card.className = `tool-card ${tool.type || 'software'}`;
const tags = (tool.tags || []).map(tag => `<span class="tag">${tag}</span>`).join('');
const knowledgebaseIndicator = tool.knowledgebase ? '<span class="tag" style="background: #e8f5e8; color: #27ae60;">📚 KB</span>' : '';
const relatedSoftwareIndicator = (tool.related_software && tool.related_software.length > 0) ? '<span class="tag" style="background: #e3f2fd; color: #1976d2;">🔗 SW</span>' : '';
const scenariosIndicator = (tool.scenarios && tool.scenarios.length > 0) ? '<span class="tag" style="background: #f3e5f5; color: #7b1fa2;">🎮 SC</span>' : '';
card.innerHTML = `
<h3>${tool.icon ? tool.icon + ' ' : ''}${tool.name} <span style="font-size: 0.7em; color: #666;">[${tool.type || 'software'}]</span></h3>
<p style="margin-bottom: 15px;">${tool.description}</p>
<div style="margin: 10px 0; min-height: 30px;">${tags} ${knowledgebaseIndicator} ${relatedSoftwareIndicator} ${scenariosIndicator}</div>
<div style="display: flex; gap: 5px; margin-top: auto;">
<button class="btn btn-secondary" onclick="editTool(${index})" style="flex: 1; padding: 8px;">✏️ Edit</button>
<button class="btn btn-danger" onclick="deleteTool(${index})" style="flex: 1; padding: 8px;">🗑️ Delete</button>
</div>
`;
return card;
}
function applyFilters() { renderToolsGrid(); }
function clearFilters() {
document.getElementById('typeFilter').value = '';
document.getElementById('skillFilter').value = '';
document.getElementById('searchInput').value = '';
renderToolsGrid();
}
// Enhanced Bulk Operations including scenarios and related software
function renderBulkGrid() {
const container = document.getElementById('bulkToolsGrid');
container.innerHTML = '';
if (!yamlData?.tools) return;
yamlData.tools.forEach((tool, index) => {
const card = createBulkToolCard(tool, index);
container.appendChild(card);
});
updateSelectionCount();
}
function createBulkToolCard(tool, index) {
const card = document.createElement('div');
card.className = `tool-card ${tool.type || 'software'}`;
const isSelected = selectedTools.has(index);
card.style.opacity = isSelected ? '1' : '0.7';
card.style.border = isSelected ? '2px solid var(--primary)' : '1px solid var(--border)';
const indicators = [];
if (tool.knowledgebase) indicators.push('📚');
if (tool.related_software?.length > 0) indicators.push('🔗');
if (tool.scenarios?.length > 0) indicators.push('🎮');
card.innerHTML = `
<div style="display: flex; align-items: center; gap: 10px; margin-bottom: 10px;">
<input type="checkbox" ${isSelected ? 'checked' : ''} onchange="toggleToolSelection(${index})" style="transform: scale(1.2);">
<h3 style="margin: 0; flex: 1;">${tool.icon ? tool.icon + ' ' : ''}${tool.name}</h3>
<div style="font-size: 1.2em;">${indicators.join(' ')}</div>
</div>
<p style="margin-bottom: 10px;">${tool.description}</p>
<div style="display: flex; gap: 8px; flex-wrap: wrap;">
<span style="background: var(--light); padding: 2px 6px; border-radius: 10px; font-size: 0.8em;">${tool.type || 'software'}</span>
<span style="background: var(--light); padding: 2px 6px; border-radius: 10px; font-size: 0.8em;">${tool.skillLevel}</span>
</div>
`;
return card;
}
function toggleToolSelection(index) {
if (selectedTools.has(index)) {
selectedTools.delete(index);
} else {
selectedTools.add(index);
}
updateSelectionCount();
renderBulkGrid();
}
function selectAllTools() {
selectedTools.clear();
yamlData.tools.forEach((_, index) => selectedTools.add(index));
updateSelectionCount();
renderBulkGrid();
}
function clearSelection() {
selectedTools.clear();
updateSelectionCount();
renderBulkGrid();
}
function updateSelectionCount() {
const count = selectedTools.size;
const info = document.getElementById('selectionInfo');
if (count === 0) {
info.textContent = 'No tools selected';
info.style.background = 'white';
info.style.borderColor = 'var(--border)';
} else {
info.textContent = `${count} tool(s) selected`;
info.style.background = '#e3f2fd';
info.style.borderColor = 'var(--primary)';
}
}
// Enhanced bulk operations with scenarios and related software
function bulkSetType() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
const newType = prompt('Enter new type (software/method/concept):');
if (newType && ['software', 'method', 'concept'].includes(newType)) {
selectedTools.forEach(index => yamlData.tools[index].type = newType);
showMessage(`Updated type for ${selectedTools.size} tools`);
updateStats();
renderBulkGrid();
}
}
function bulkSetSkillLevel() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
const newLevel = prompt('Enter skill level (novice/beginner/intermediate/advanced/expert):');
if (newLevel && ['novice', 'beginner', 'intermediate', 'advanced', 'expert'].includes(newLevel)) {
selectedTools.forEach(index => yamlData.tools[index].skillLevel = newLevel);
showMessage(`Updated skill level for ${selectedTools.size} tools`);
renderBulkGrid();
}
}
function bulkAddTags() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
const tags = prompt('Enter tags to add (comma-separated):');
if (tags) {
const tagList = tags.split(',').map(t => t.trim()).filter(t => t);
selectedTools.forEach(index => {
const tool = yamlData.tools[index];
tool.tags = [...new Set([...(tool.tags || []), ...tagList])];
});
showMessage(`Added tags to ${selectedTools.size} tools`);
renderBulkGrid();
}
}
function bulkRemoveTags() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
const tags = prompt('Enter tags to remove (comma-separated):');
if (tags) {
const tagList = tags.split(',').map(t => t.trim()).filter(t => t);
selectedTools.forEach(index => {
const tool = yamlData.tools[index];
if (tool.tags) {
tool.tags = tool.tags.filter(tag => !tagList.includes(tag));
if (tool.tags.length === 0) delete tool.tags;
}
});
showMessage(`Removed tags from ${selectedTools.size} tools`);
renderBulkGrid();
}
}
function bulkReplaceTags() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
const tags = prompt('Enter new tags (comma-separated, will replace all existing tags):');
if (tags !== null) {
const tagList = tags.split(',').map(t => t.trim()).filter(t => t);
selectedTools.forEach(index => {
const tool = yamlData.tools[index];
if (tagList.length > 0) {
tool.tags = tagList;
} else {
delete tool.tags;
}
});
showMessage(`Replaced tags for ${selectedTools.size} tools`);
renderBulkGrid();
}
}
function bulkClearTags() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
if (confirm(`Are you sure you want to clear ALL tags from ${selectedTools.size} selected tools?`)) {
selectedTools.forEach(index => {
delete yamlData.tools[index].tags;
});
showMessage(`Cleared tags from ${selectedTools.size} tools`);
renderBulkGrid();
}
}
// Domain operations
function bulkAddDomains() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
const domains = prompt('Enter domain IDs to add (comma-separated):');
if (domains) {
const domainList = domains.split(',').map(d => d.trim()).filter(d => d);
selectedTools.forEach(index => {
const tool = yamlData.tools[index];
tool.domains = [...new Set([...(tool.domains || []), ...domainList])];
});
showMessage(`Added domains to ${selectedTools.size} tools`);
renderBulkGrid();
}
}
function bulkRemoveDomains() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
const domains = prompt('Enter domain IDs to remove (comma-separated):');
if (domains) {
const domainList = domains.split(',').map(d => d.trim()).filter(d => d);
selectedTools.forEach(index => {
const tool = yamlData.tools[index];
if (tool.domains) {
tool.domains = tool.domains.filter(domain => !domainList.includes(domain));
if (tool.domains.length === 0) delete tool.domains;
}
});
showMessage(`Removed domains from ${selectedTools.size} tools`);
renderBulkGrid();
}
}
function bulkClearDomains() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
if (confirm(`Are you sure you want to clear ALL domains from ${selectedTools.size} selected tools?`)) {
selectedTools.forEach(index => {
delete yamlData.tools[index].domains;
});
showMessage(`Cleared domains from ${selectedTools.size} tools`);
renderBulkGrid();
}
}
// Phase operations
function bulkAddPhases() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
const phases = prompt('Enter phase IDs to add (comma-separated):');
if (phases) {
const phaseList = phases.split(',').map(p => p.trim()).filter(p => p);
selectedTools.forEach(index => {
const tool = yamlData.tools[index];
tool.phases = [...new Set([...(tool.phases || []), ...phaseList])];
});
showMessage(`Added phases to ${selectedTools.size} tools`);
renderBulkGrid();
}
}
function bulkRemovePhases() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
const phases = prompt('Enter phase IDs to remove (comma-separated):');
if (phases) {
const phaseList = phases.split(',').map(p => p.trim()).filter(p => p);
selectedTools.forEach(index => {
const tool = yamlData.tools[index];
if (tool.phases) {
tool.phases = tool.phases.filter(phase => !phaseList.includes(phase));
if (tool.phases.length === 0) delete tool.phases;
}
});
showMessage(`Removed phases from ${selectedTools.size} tools`);
renderBulkGrid();
}
}
function bulkClearPhases() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
if (confirm(`Are you sure you want to clear ALL phases from ${selectedTools.size} selected tools?`)) {
selectedTools.forEach(index => {
delete yamlData.tools[index].phases;
});
showMessage(`Cleared phases from ${selectedTools.size} tools`);
renderBulkGrid();
}
}
// NEW: Scenario operations
function bulkAddScenarios() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
const scenarios = prompt('Enter scenario IDs to add (comma-separated):');
if (scenarios) {
const scenarioList = scenarios.split(',').map(s => s.trim()).filter(s => s);
selectedTools.forEach(index => {
const tool = yamlData.tools[index];
tool.scenarios = [...new Set([...(tool.scenarios || []), ...scenarioList])];
});
showMessage(`Added scenarios to ${selectedTools.size} tools`);
renderBulkGrid();
}
}
function bulkRemoveScenarios() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
const scenarios = prompt('Enter scenario IDs to remove (comma-separated):');
if (scenarios) {
const scenarioList = scenarios.split(',').map(s => s.trim()).filter(s => s);
selectedTools.forEach(index => {
const tool = yamlData.tools[index];
if (tool.scenarios) {
tool.scenarios = tool.scenarios.filter(scenario => !scenarioList.includes(scenario));
if (tool.scenarios.length === 0) delete tool.scenarios;
}
});
showMessage(`Removed scenarios from ${selectedTools.size} tools`);
renderBulkGrid();
}
}
function bulkClearScenarios() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
if (confirm(`Are you sure you want to clear ALL scenarios from ${selectedTools.size} selected tools?`)) {
selectedTools.forEach(index => {
delete yamlData.tools[index].scenarios;
});
showMessage(`Cleared scenarios from ${selectedTools.size} tools`);
renderBulkGrid();
}
}
// Platform operations
function bulkAddPlatforms() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
const platforms = prompt('Enter platforms to add (comma-separated, e.g., Windows,Linux,macOS):');
if (platforms) {
const platformList = platforms.split(',').map(p => p.trim()).filter(p => p);
selectedTools.forEach(index => {
const tool = yamlData.tools[index];
tool.platforms = [...new Set([...(tool.platforms || []), ...platformList])];
});
showMessage(`Added platforms to ${selectedTools.size} tools`);
renderBulkGrid();
}
}
function bulkRemovePlatforms() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
const platforms = prompt('Enter platforms to remove (comma-separated):');
if (platforms) {
const platformList = platforms.split(',').map(p => p.trim()).filter(p => p);
selectedTools.forEach(index => {
const tool = yamlData.tools[index];
if (tool.platforms) {
tool.platforms = tool.platforms.filter(platform => !platformList.includes(platform));
if (tool.platforms.length === 0) delete tool.platforms;
}
});
showMessage(`Removed platforms from ${selectedTools.size} tools`);
renderBulkGrid();
}
}
function bulkClearPlatforms() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
if (confirm(`Are you sure you want to clear ALL platforms from ${selectedTools.size} selected tools?`)) {
selectedTools.forEach(index => {
delete yamlData.tools[index].platforms;
});
showMessage(`Cleared platforms from ${selectedTools.size} tools`);
renderBulkGrid();
}
}
// Related concepts operations
function bulkAddRelatedConcepts() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
const concepts = prompt('Enter related concept names to add (comma-separated):');
if (concepts) {
const conceptList = concepts.split(',').map(c => c.trim()).filter(c => c);
selectedTools.forEach(index => {
const tool = yamlData.tools[index];
tool.related_concepts = [...new Set([...(tool.related_concepts || []), ...conceptList])];
});
showMessage(`Added related concepts to ${selectedTools.size} tools`);
renderBulkGrid();
}
}
function bulkRemoveRelatedConcepts() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
const concepts = prompt('Enter related concept names to remove (comma-separated):');
if (concepts) {
const conceptList = concepts.split(',').map(c => c.trim()).filter(c => c);
selectedTools.forEach(index => {
const tool = yamlData.tools[index];
if (tool.related_concepts) {
tool.related_concepts = tool.related_concepts.filter(concept => !conceptList.includes(concept));
if (tool.related_concepts.length === 0) delete tool.related_concepts;
}
});
showMessage(`Removed related concepts from ${selectedTools.size} tools`);
renderBulkGrid();
}
}
function bulkClearRelatedConcepts() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
if (confirm(`Are you sure you want to clear ALL related concepts from ${selectedTools.size} selected tools?`)) {
selectedTools.forEach(index => {
delete yamlData.tools[index].related_concepts;
});
showMessage(`Cleared related concepts from ${selectedTools.size} tools`);
renderBulkGrid();
}
}
// NEW: Related software operations
function bulkAddRelatedSoftware() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
const software = prompt('Enter related software names to add (comma-separated):');
if (software) {
const softwareList = software.split(',').map(s => s.trim()).filter(s => s);
selectedTools.forEach(index => {
const tool = yamlData.tools[index];
tool.related_software = [...new Set([...(tool.related_software || []), ...softwareList])];
});
showMessage(`Added related software to ${selectedTools.size} tools`);
renderBulkGrid();
}
}
function bulkRemoveRelatedSoftware() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
const software = prompt('Enter related software names to remove (comma-separated):');
if (software) {
const softwareList = software.split(',').map(s => s.trim()).filter(s => s);
selectedTools.forEach(index => {
const tool = yamlData.tools[index];
if (tool.related_software) {
tool.related_software = tool.related_software.filter(sw => !softwareList.includes(sw));
if (tool.related_software.length === 0) delete tool.related_software;
}
});
showMessage(`Removed related software from ${selectedTools.size} tools`);
renderBulkGrid();
}
}
function bulkClearRelatedSoftware() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
if (confirm(`Are you sure you want to clear ALL related software from ${selectedTools.size} selected tools?`)) {
selectedTools.forEach(index => {
delete yamlData.tools[index].related_software;
});
showMessage(`Cleared related software from ${selectedTools.size} tools`);
renderBulkGrid();
}
}
function bulkDelete() {
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
if (confirm(`Are you sure you want to delete ${selectedTools.size} selected tools? This action cannot be undone!`)) {
const indicesToDelete = Array.from(selectedTools).sort((a, b) => b - a);
indicesToDelete.forEach(index => yamlData.tools.splice(index, 1));
selectedTools.clear();
showMessage(`Deleted ${indicesToDelete.length} tools successfully!`);
updateStats();
renderBulkGrid();
updateKnowledgeToolSelect();
}
}
// Knowledge Generator - Enhanced for ForensicPathways format with scenarios and related_software
function updateKnowledgeToolSelect() {
const select = document.getElementById('knowledgeToolSelect');
select.innerHTML = '<option value="">Choose a tool or concept...</option>';
if (!yamlData?.tools) return;
yamlData.tools.forEach((tool, index) => {
const option = document.createElement('option');
option.value = index;
option.textContent = `${tool.icon ? tool.icon + ' ' : ''}${tool.name} (${tool.type || 'software'})`;
select.appendChild(option);
});
}
function generateKnowledgeTemplate() {
const select = document.getElementById('knowledgeToolSelect');
const index = parseInt(select.value);
if (isNaN(index)) {
document.getElementById('knowledgePreview').classList.add('hidden');
return;
}
const tool = yamlData.tools[index];
const template = createCC24MarkdownTemplate(tool);
document.getElementById('markdownContent').value = template;
document.getElementById('knowledgePreview').classList.remove('hidden');
}
function createCC24MarkdownTemplate(tool) {
const toolSlug = tool.name.toLowerCase()
.replace(/[^a-z0-9\s-]/g, '')
.replace(/\s+/g, '-')
.replace(/-+/g, '-')
.replace(/^-|-$/g, '');
return `---
title: "${tool.name}"
description: "${tool.description.split('\n')[0].trim()}"
last_updated: ${new Date().toISOString().split('T')[0]}
tool_name: "${tool.name}"
related_tools: ${JSON.stringify([...(tool.related_concepts || []), ...(tool.related_software || [])])}
author: "CC24-Team"
difficulty: "${tool.skillLevel || 'intermediate'}"
categories: ${tool.type === 'concept' ? '["concepts"]' : tool.type === 'method' ? '["methods"]' : '["tools"]'}
tags: ${tool.tags ? JSON.stringify(tool.tags) : '[]'}
published: true
---
# ${tool.icon ? tool.icon + ' ' : ''}${tool.name}
## Übersicht
${tool.description}
**Typ**: ${tool.type || 'software'}
**Skill Level**: ${tool.skillLevel || 'intermediate'}
**Offizielle URL**: [${tool.name}](${tool.url})
${tool.license ? `**Lizenz**: ${tool.license}\n` : ''}${tool.platforms && tool.platforms.length > 0 ? `**Plattformen**: ${tool.platforms.join(', ')}\n` : ''}${tool.accessType ? `**Zugriff**: ${tool.accessType}\n` : ''}
${tool.domains && tool.domains.length > 0 ? `## Anwendungsbereiche
${tool.domains.map(domain => `- ${domain}`).join('\n')}\n\n` : ''}${tool.phases && tool.phases.length > 0 ? `## Ermittlungsphasen
${tool.phases.map(phase => `- ${phase}`).join('\n')}\n\n` : ''}${tool.scenarios && tool.scenarios.length > 0 ? `## Anwendungsszenarien
${tool.scenarios.map(scenario => {
const scenarioData = yamlData.scenarios.find(s => s.id === scenario);
return scenarioData ? `- ${scenarioData.icon} ${scenarioData.friendly_name}` : `- ${scenario}`;
}).join('\n')}\n\n` : ''}## ${tool.type === 'concept' ? 'Grundlagen' : tool.type === 'method' ? 'Vorgehensweise' : 'Installation & Nutzung'}
${tool.type === 'concept' ?
`### Kernkonzepte
TODO: Beschreibe die wichtigsten Konzepte und Prinzipien.
### Anwendungsbereiche
TODO: Erkläre, wo und wie dieses Konzept angewendet wird.` :
tool.type === 'method' ?
`### Schritt-für-Schritt Anleitung
1. TODO: Erster Schritt
2. TODO: Zweiter Schritt
3. TODO: Dritter Schritt
### Voraussetzungen
TODO: Liste die erforderlichen Voraussetzungen auf.` :
`### Installation
TODO: Beschreibe die Installation für die relevanten Plattformen.
### Grundlegende Nutzung
TODO: Erkläre die wichtigsten Funktionen und Befehle.
### Workflow-Beispiele
TODO: Zeige typische Anwendungsfälle und Workflows.`}
## Best Practices
TODO: Teile bewährte Praktiken und Tipps für die optimale Nutzung.
## Häufige Probleme
TODO: Beschreibe häufige Stolpersteine und deren Lösungen.
${(tool.related_concepts && tool.related_concepts.length > 0) || (tool.related_software && tool.related_software.length > 0) ? `## Verwandte Tools und Konzepte
${(tool.related_concepts || []).map(concept => `- 💡 ${concept} (Konzept)`).join('\n')}${(tool.related_concepts || []).length > 0 && (tool.related_software || []).length > 0 ? '\n' : ''}${(tool.related_software || []).map(software => `- 🛠️ ${software} (Software)`).join('\n')}\n\n` : ''}## Weitere Ressourcen
- [Offizielle Dokumentation](${tool.url})${tool.projectUrl ? `\n- [CC24 Server Zugang](${tool.projectUrl})` : ''}
TODO: Füge weitere nützliche Links und Ressourcen hinzu.
---
*Zuletzt aktualisiert: ${new Date().toLocaleDateString('de-DE')}*
`;
}
function downloadMarkdown() {
const content = document.getElementById('markdownContent').value;
const select = document.getElementById('knowledgeToolSelect');
const index = parseInt(select.value);
const tool = yamlData.tools[index];
const toolSlug = tool.name.toLowerCase()
.replace(/[^a-z0-9\s-]/g, '')
.replace(/\s+/g, '-')
.replace(/-+/g, '-')
.replace(/^-|-$/g, '');
const blob = new Blob([content], { type: 'text/markdown' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `${toolSlug}.md`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
showMessage('Markdown template downloaded successfully!');
}
function copyMarkdown() {
const content = document.getElementById('markdownContent').value;
navigator.clipboard.writeText(content).then(() => {
showMessage('Markdown copied to clipboard!');
}).catch(() => {
showMessage('Failed to copy to clipboard', 'error');
});
}
// Enhanced Validation including scenarios and related_software
function validateYAML() {
if (!yamlData) return showMessage('No data to validate', 'error');
const validationResults = [];
// Check required sections
if (!yamlData.tools) validationResults.push('❌ Missing tools section');
if (!yamlData.domains) validationResults.push('❌ Missing domains section');
if (!yamlData.phases) validationResults.push('❌ Missing phases section');
if (!yamlData.scenarios) validationResults.push('⚠️ Missing scenarios section');
// Validate tools
yamlData.tools?.forEach((tool, index) => {
if (!tool.name) validationResults.push(`❌ Tool ${index + 1}: Missing name`);
if (!tool.description) validationResults.push(`❌ Tool ${index + 1}: Missing description`);
if (!tool.skillLevel) validationResults.push(`❌ Tool ${index + 1}: Missing skillLevel`);
if (!tool.url) validationResults.push(`❌ Tool ${index + 1}: Missing url`);
if (tool.type && !['software', 'method', 'concept'].includes(tool.type)) {
validationResults.push(`❌ Tool ${index + 1}: Invalid type`);
}
// Type-specific validation
if (tool.type === 'software' && (!tool.platforms || tool.platforms.length === 0)) {
validationResults.push(`⚠️ Tool ${index + 1}: Software should have platforms`);
}
if (tool.type === 'concept' && tool.platforms?.length > 0) {
validationResults.push(`⚠️ Tool ${index + 1}: Concepts should not have platforms`);
}
// Validate related_software references
if (tool.related_software && tool.related_software.length > 0) {
tool.related_software.forEach(relatedName => {
const exists = yamlData.tools.some(t => t.name === relatedName);
if (!exists) {
validationResults.push(`⚠️ Tool ${index + 1}: Related software "${relatedName}" not found in tools`);
}
});
}
// Validate scenarios references
if (tool.scenarios && tool.scenarios.length > 0) {
tool.scenarios.forEach(scenarioId => {
const exists = yamlData.scenarios?.some(s => s.id === scenarioId);
if (!exists) {
validationResults.push(`⚠️ Tool ${index + 1}: Scenario "${scenarioId}" not found in scenarios`);
}
});
}
});
const container = document.getElementById('validationContent');
if (validationResults.length === 0) {
container.innerHTML = '<div class="message success">✅ YAML structure is valid!</div>';
} else {
container.innerHTML = '<div class="message error">' + validationResults.join('<br>') + '</div>';
}
document.getElementById('validationResults').classList.remove('hidden');
}
function previewYAML() {
if (!yamlData) return showMessage('No data to preview', 'error');
const yamlString = jsyaml.dump(yamlData, { indent: 2 });
document.getElementById('yamlPreviewText').value = yamlString;
document.getElementById('yamlPreview').classList.remove('hidden');
}
function exportYAML() {
if (!yamlData) return showMessage('No data to export', 'error');
const yamlString = jsyaml.dump(yamlData, { indent: 2 });
const blob = new Blob([yamlString], { type: 'text/yaml' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'tools.yaml';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
showMessage('YAML file exported successfully!');
}
function exportJSON() {
if (!yamlData) return showMessage('No data to export', 'error');
const jsonString = JSON.stringify(yamlData, null, 2);
const blob = new Blob([jsonString], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'tools.json';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
showMessage('JSON file exported successfully!');
}
// Initialize
init();
</script>
</body>
</html>