introduce concepts phase 1-2
This commit is contained in:
parent
0648647c8a
commit
202ee5f801
@ -21,8 +21,10 @@ export interface Props {
|
||||
|
||||
const { tool } = Astro.props;
|
||||
|
||||
// Check if this is a method vs software
|
||||
|
||||
// Check types
|
||||
const isMethod = tool.type === 'method';
|
||||
const isConcept = tool.type === 'concept';
|
||||
|
||||
// Check if tool has a valid project URL (means we're hosting it)
|
||||
const hasValidProjectUrl = tool.projectUrl !== undefined &&
|
||||
@ -34,7 +36,8 @@ const hasValidProjectUrl = tool.projectUrl !== undefined &&
|
||||
const hasKnowledgebase = tool.knowledgebase === true;
|
||||
|
||||
// Determine card styling based on type and hosting status
|
||||
const cardClass = isMethod ? 'card card-method tool-card' :
|
||||
const cardClass = isConcept ? 'card card-concept tool-card' :
|
||||
isMethod ? 'card card-method tool-card' :
|
||||
hasValidProjectUrl ? 'card card-hosted tool-card' :
|
||||
(tool.license !== 'Proprietary' ? 'card card-oss tool-card' : 'card tool-card');
|
||||
---
|
||||
@ -101,7 +104,12 @@ const cardClass = isMethod ? 'card card-method tool-card' :
|
||||
|
||||
<!-- Buttons - Fixed at Bottom -->
|
||||
<div class="tool-card-buttons" onclick="event.stopPropagation();">
|
||||
{isMethod ? (
|
||||
{isConcept ? (
|
||||
<!-- Concept button -->
|
||||
<a href={tool.url} target="_blank" rel="noopener noreferrer" class="btn btn-primary single-button" style="background-color: var(--color-concept); border-color: var(--color-concept);">
|
||||
Mehr erfahren
|
||||
</a>
|
||||
) : isMethod ? (
|
||||
<!-- Method button -->
|
||||
<a href={tool.projectUrl || tool.url} target="_blank" rel="noopener noreferrer" class="btn btn-primary single-button" style="background-color: var(--color-method); border-color: var(--color-method);">
|
||||
Zur Methode
|
||||
|
@ -342,35 +342,6 @@ const sortedTags = Object.entries(tagFrequency)
|
||||
return true;
|
||||
});
|
||||
|
||||
// Sort filtered results: methods first, then self-hosted, then OSS, proprietary last
|
||||
filtered.sort((a, b) => {
|
||||
const aMethod = isMethod(a);
|
||||
const bMethod = isMethod(b);
|
||||
const aHosted = isToolHosted(a);
|
||||
const bHosted = isToolHosted(b);
|
||||
const aProprietary = !aMethod && a.license === 'Proprietary';
|
||||
const bProprietary = !bMethod && b.license === 'Proprietary';
|
||||
|
||||
// Methods first
|
||||
//if (aMethod && !bMethod) return -1;
|
||||
//if (!aMethod && bMethod) return 1;
|
||||
|
||||
// If both are methods or both are tools
|
||||
if (aMethod === bMethod) {
|
||||
// Self-hosted tools first (regardless of license)
|
||||
if (aHosted && !bHosted) return -1;
|
||||
if (!aHosted && bHosted) return 1;
|
||||
|
||||
// If both have same hosting status, proprietary tools go last
|
||||
if (aHosted === bHosted) {
|
||||
if (!aProprietary && bProprietary) return -1;
|
||||
if (aProprietary && !bProprietary) return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
// Update matrix highlighting
|
||||
updateMatrixHighlighting();
|
||||
// Emit custom event with filtered results
|
||||
@ -418,16 +389,6 @@ const sortedTags = Object.entries(tagFrequency)
|
||||
|
||||
if (view === 'hosted') {
|
||||
const hosted = window.toolsData.filter(tool => isToolHosted(tool));
|
||||
hosted.sort((a, b) => {
|
||||
const aProprietary = a.license === 'Proprietary';
|
||||
const bProprietary = b.license === 'Proprietary';
|
||||
|
||||
if (!aProprietary && bProprietary) return -1;
|
||||
if (aProprietary && !bProprietary) return 1;
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
window.dispatchEvent(new CustomEvent('toolsFiltered', { detail: hosted }));
|
||||
} else {
|
||||
filterTools();
|
||||
|
@ -24,6 +24,7 @@ domains.forEach((domain: any) => {
|
||||
matrix[domain.id] = {};
|
||||
phases.forEach((phase: any) => {
|
||||
matrix[domain.id][phase.id] = tools.filter((tool: any) =>
|
||||
tool.type !== 'concept' && // Exclude concepts from matrix
|
||||
tool.domains && tool.domains.includes(domain.id) &&
|
||||
tool.phases && tool.phases.includes(phase.id)
|
||||
);
|
||||
@ -407,6 +408,11 @@ domains.forEach((domain: any) => {
|
||||
|
||||
// Re-populate with filtered tools based on domains × phases
|
||||
filtered.forEach(tool => {
|
||||
// Skip concepts - they don't belong in matrix
|
||||
if (tool.type === 'concept') {
|
||||
return;
|
||||
}
|
||||
|
||||
const isMethod = tool.type === 'method';
|
||||
const hasValidProjectUrl = tool.projectUrl !== undefined &&
|
||||
tool.projectUrl !== null &&
|
||||
|
@ -1904,6 +1904,95 @@ tools:
|
||||
- jamf
|
||||
- enterprise
|
||||
- commandline
|
||||
- name: Regular Expressions (Regex)
|
||||
icon: 🔤
|
||||
type: concept
|
||||
description: >-
|
||||
Pattern matching language for searching, extracting, and manipulating text.
|
||||
Essential for log analysis, malware signature creation, and data extraction from
|
||||
unstructured sources. Forms the backbone of many forensic tools and custom scripts.
|
||||
domains:
|
||||
- incident-response
|
||||
- malware-analysis
|
||||
- network-forensics
|
||||
- fraud-investigation
|
||||
phases:
|
||||
- examination
|
||||
- analysis
|
||||
platforms: []
|
||||
domain-agnostic-software: null
|
||||
skillLevel: intermediate
|
||||
accessType: null
|
||||
url: https://regexr.com/
|
||||
projectUrl: null
|
||||
license: null
|
||||
knowledgebase: false
|
||||
tags:
|
||||
- pattern-matching
|
||||
- text-processing
|
||||
- log-analysis
|
||||
- string-manipulation
|
||||
- search-algorithms
|
||||
|
||||
- name: SQL Query Fundamentals
|
||||
icon: 🗃️
|
||||
type: concept
|
||||
description: >-
|
||||
Structured Query Language for database interrogation and analysis. Critical for
|
||||
examining application databases, SQLite artifacts from mobile devices, and
|
||||
browser history databases. Enables complex correlation and filtering of large datasets.
|
||||
domains:
|
||||
- incident-response
|
||||
- mobile-forensics
|
||||
- fraud-investigation
|
||||
- cloud-forensics
|
||||
phases:
|
||||
- examination
|
||||
- analysis
|
||||
platforms: []
|
||||
domain-agnostic-software: null
|
||||
skillLevel: intermediate
|
||||
accessType: null
|
||||
url: https://www.w3schools.com/sql/
|
||||
projectUrl: null
|
||||
license: null
|
||||
knowledgebase: false
|
||||
tags:
|
||||
- database-analysis
|
||||
- query-language
|
||||
- data-correlation
|
||||
- mobile-artifacts
|
||||
- browser-forensics
|
||||
|
||||
- name: Hash Functions & Digital Signatures
|
||||
icon: 🔐
|
||||
type: concept
|
||||
description: >-
|
||||
Cryptographic principles for data integrity verification and authentication.
|
||||
Fundamental for evidence preservation, malware identification, and establishing
|
||||
chain of custody. Understanding of MD5, SHA, and digital signature validation.
|
||||
domains:
|
||||
- incident-response
|
||||
- law-enforcement
|
||||
- malware-analysis
|
||||
- cloud-forensics
|
||||
phases:
|
||||
- data-collection
|
||||
- examination
|
||||
platforms: []
|
||||
domain-agnostic-software: null
|
||||
skillLevel: advanced
|
||||
accessType: null
|
||||
url: https://en.wikipedia.org/wiki/Cryptographic_hash_function
|
||||
projectUrl: null
|
||||
license: null
|
||||
knowledgebase: false
|
||||
tags:
|
||||
- cryptography
|
||||
- data-integrity
|
||||
- evidence-preservation
|
||||
- malware-identification
|
||||
- chain-of-custody
|
||||
domains:
|
||||
- id: incident-response
|
||||
name: Incident Response & Breach-Untersuchung
|
||||
|
@ -112,6 +112,29 @@ const tools = data.tools;
|
||||
// Initial tools HTML
|
||||
const initialToolsHTML = toolsContainer.innerHTML;
|
||||
|
||||
// Simple sorting function - no external imports needed
|
||||
function sortTools(tools, sortBy = 'default') {
|
||||
const sorted = [...tools]; // Don't mutate original array
|
||||
|
||||
switch (sortBy) {
|
||||
case 'alphabetical':
|
||||
return sorted.sort((a, b) => a.name.localeCompare(b.name));
|
||||
case 'difficulty':
|
||||
const difficultyOrder = { 'novice': 0, 'beginner': 1, 'intermediate': 2, 'advanced': 3, 'expert': 4 };
|
||||
return sorted.sort((a, b) =>
|
||||
(difficultyOrder[a.skillLevel] || 999) - (difficultyOrder[b.skillLevel] || 999)
|
||||
);
|
||||
case 'type':
|
||||
const typeOrder = { 'concept': 0, 'method': 1, 'software': 2 };
|
||||
return sorted.sort((a, b) =>
|
||||
(typeOrder[a.type] || 999) - (typeOrder[b.type] || 999)
|
||||
);
|
||||
case 'default':
|
||||
default:
|
||||
return sorted; // No sorting - embrace the entropy
|
||||
}
|
||||
}
|
||||
|
||||
// Authentication check function
|
||||
async function checkAuthentication() {
|
||||
try {
|
||||
@ -177,7 +200,7 @@ const tools = data.tools;
|
||||
|
||||
// Hide filter controls in AI mode - AGGRESSIVE APPROACH
|
||||
const domainPhaseContainer = document.querySelector('.domain-phase-container') as HTMLElement;
|
||||
const searchInput = document.getElementById('search-tools') as HTMLElement;
|
||||
const searchInput = document.getElementById('search-input') as HTMLElement;
|
||||
const tagCloud = document.querySelector('.tag-cloud') as HTMLElement;
|
||||
// Hide all checkbox wrappers
|
||||
const checkboxWrappers = document.querySelectorAll('.checkbox-wrapper');
|
||||
@ -227,7 +250,7 @@ const tools = data.tools;
|
||||
|
||||
// Show filter controls in matrix mode
|
||||
const domainPhaseContainerMatrix = document.querySelector('.domain-phase-container') as HTMLElement;
|
||||
const searchInputMatrix = document.getElementById('search-tools') as HTMLElement;
|
||||
const searchInputMatrix = document.getElementById('search-input') as HTMLElement;
|
||||
const tagCloudMatrix = document.querySelector('.tag-cloud') as HTMLElement;
|
||||
const checkboxWrappersMatrix = document.querySelectorAll('.checkbox-wrapper');
|
||||
const tagHeaderMatrix = document.querySelector('.tag-header') as HTMLElement;
|
||||
@ -262,7 +285,7 @@ const tools = data.tools;
|
||||
|
||||
// Show filter controls in grid mode
|
||||
const domainPhaseContainerGrid = document.querySelector('.domain-phase-container') as HTMLElement;
|
||||
const searchInputGrid = document.getElementById('search-tools') as HTMLElement;
|
||||
const searchInputGrid = document.getElementById('search-input') as HTMLElement;
|
||||
const tagCloudGrid = document.querySelector('.tag-cloud') as HTMLElement;
|
||||
const checkboxWrappersGrid = document.querySelectorAll('.checkbox-wrapper');
|
||||
const tagHeaderGrid = document.querySelector('.tag-header') as HTMLElement;
|
||||
@ -318,8 +341,12 @@ const tools = data.tools;
|
||||
} else {
|
||||
noResults.style.display = 'none';
|
||||
|
||||
// Render filtered tools
|
||||
filtered.forEach((tool: any) => {
|
||||
// Apply sorting here - single place for all sorting logic
|
||||
const currentSortOption = 'default'; // Will be dynamic later
|
||||
const sortedTools = sortTools(filtered, currentSortOption);
|
||||
|
||||
// Render sorted tools
|
||||
sortedTools.forEach((tool: any) => {
|
||||
const toolCard = createToolCard(tool);
|
||||
toolsContainer.appendChild(toolCard);
|
||||
});
|
||||
@ -338,6 +365,7 @@ const tools = data.tools;
|
||||
|
||||
function createToolCard(tool) {
|
||||
const isMethod = tool.type === 'method';
|
||||
const isConcept = tool.type === 'concept';
|
||||
const hasValidProjectUrl = tool.projectUrl !== undefined &&
|
||||
tool.projectUrl !== null &&
|
||||
tool.projectUrl !== "" &&
|
||||
@ -346,7 +374,8 @@ function createToolCard(tool) {
|
||||
const hasKnowledgebase = tool.knowledgebase === true;
|
||||
|
||||
const cardDiv = document.createElement('div');
|
||||
const cardClass = isMethod ? 'card card-method tool-card' :
|
||||
const cardClass = isConcept ? 'card card-concept tool-card' :
|
||||
isMethod ? 'card card-method tool-card' :
|
||||
hasValidProjectUrl ? 'card card-hosted tool-card' :
|
||||
(tool.license !== 'Proprietary' ? 'card card-oss tool-card' : 'card tool-card');
|
||||
cardDiv.className = cardClass;
|
||||
@ -358,7 +387,7 @@ function createToolCard(tool) {
|
||||
<div class="tool-card-header">
|
||||
<h3>${tool.icon ? `<span style="margin-right: 0.5rem; font-size: 1.125rem;">${tool.icon}</span>` : ''}${tool.name}</h3>
|
||||
<div class="tool-card-badges">
|
||||
${!isMethod && hasValidProjectUrl ? '<span class="badge badge-primary">CC24-Server</span>' : ''}
|
||||
${!isMethod && !isConcept && hasValidProjectUrl ? '<span class="badge badge-primary">CC24-Server</span>' : ''}
|
||||
${hasKnowledgebase ? '<span class="badge badge-error">📖</span>' : ''}
|
||||
</div>
|
||||
</div>
|
||||
@ -395,7 +424,7 @@ function createToolCard(tool) {
|
||||
<polyline points="14 2 14 8 20 8"></polyline>
|
||||
</svg>
|
||||
<span style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;">
|
||||
${isMethod ? 'Methode' : tool.license === 'Proprietary' ? 'Prop.' : tool.license?.split(' ')[0] || 'N/A'}
|
||||
${isConcept ? 'Konzept' : isMethod ? 'Methode' : tool.license === 'Proprietary' ? 'Prop.' : tool.license?.split(' ')[0] || 'N/A'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -405,7 +434,11 @@ function createToolCard(tool) {
|
||||
</div>
|
||||
|
||||
<div class="tool-card-buttons" onclick="event.stopPropagation();">
|
||||
${isMethod ? `
|
||||
${isConcept ? `
|
||||
<a href="${tool.url}" target="_blank" rel="noopener noreferrer" class="btn btn-primary single-button" style="background-color: var(--color-concept); border-color: var(--color-concept);">
|
||||
Mehr erfahren
|
||||
</a>
|
||||
` : isMethod ? `
|
||||
<a href="${tool.projectUrl || tool.url}" target="_blank" rel="noopener noreferrer" class="btn btn-primary single-button" style="background-color: var(--color-method); border-color: var(--color-method);">
|
||||
Zur Methode
|
||||
</a>
|
||||
|
@ -11,23 +11,28 @@
|
||||
:root {
|
||||
/* Light Theme Colors */
|
||||
--color-bg: #fff;
|
||||
--color-bg-secondary: #f5f5f5;
|
||||
--color-bg-tertiary: #e0e0e0;
|
||||
--color-text: #1a1a1a;
|
||||
--color-text-secondary: #666;
|
||||
--color-border: #d0d0d0;
|
||||
--color-bg-secondary: #f8fafc;
|
||||
--color-bg-tertiary: #e2e8f0;
|
||||
--color-text: #1e293b;
|
||||
--color-text-secondary: #64748b;
|
||||
--color-border: #cbd5e1;
|
||||
--color-primary: #2563eb;
|
||||
--color-primary-hover: #1d4ed8;
|
||||
--color-accent: #10b981;
|
||||
--color-accent-hover: #059669;
|
||||
--color-warning: #f59e0b;
|
||||
--color-error: #ef4444;
|
||||
--color-hosted: #8b5cf6;
|
||||
--color-accent: #059669;
|
||||
--color-accent-hover: #047857;
|
||||
--color-warning: #d97706;
|
||||
--color-error: #dc2626;
|
||||
|
||||
/* Enhanced card type colors */
|
||||
--color-hosted: #7c3aed; /* More vibrant purple */
|
||||
--color-hosted-bg: #f3f0ff;
|
||||
--color-oss: #10b981;
|
||||
--color-oss: #059669; /* Deeper green for better contrast */
|
||||
--color-oss-bg: #ecfdf5;
|
||||
--color-method: #3a90ed;
|
||||
--color-method-bg: #f3f4f6;
|
||||
--color-method: #0891b2; /* Distinct teal-cyan for methods */
|
||||
--color-method-bg: #f0f9ff; /* Fixed: proper light background */
|
||||
--color-concept: #ea580c; /* Warmer orange-red for concepts */
|
||||
--color-concept-bg: #fff7ed;
|
||||
|
||||
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 5%);
|
||||
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 10%);
|
||||
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 10%);
|
||||
@ -39,24 +44,29 @@
|
||||
|
||||
[data-theme="dark"] {
|
||||
/* Dark Theme Colors */
|
||||
--color-bg: #0f0f0f;
|
||||
--color-bg-secondary: #1a1a1a;
|
||||
--color-bg-tertiary: #262626;
|
||||
--color-text: #e5e5e5;
|
||||
--color-text-secondary: #a3a3a3;
|
||||
--color-border: #404040;
|
||||
--color-bg: #0f172a;
|
||||
--color-bg-secondary: #1e293b;
|
||||
--color-bg-tertiary: #334155;
|
||||
--color-text: #f1f5f9;
|
||||
--color-text-secondary: #94a3b8;
|
||||
--color-border: #475569;
|
||||
--color-primary: #3b82f6;
|
||||
--color-primary-hover: #60a5fa;
|
||||
--color-accent: #34d399;
|
||||
--color-accent-hover: #6ee7b7;
|
||||
--color-warning: #fbbf24;
|
||||
--color-accent: #10b981;
|
||||
--color-accent-hover: #34d399;
|
||||
--color-warning: #f59e0b;
|
||||
--color-error: #f87171;
|
||||
--color-hosted: #a78bfa;
|
||||
|
||||
/* Enhanced dark card type colors */
|
||||
--color-hosted: #a855f7; /* Brighter purple for dark mode */
|
||||
--color-hosted-bg: #2e1065;
|
||||
--color-oss: #34d399;
|
||||
--color-oss: #10b981; /* Vibrant green */
|
||||
--color-oss-bg: #064e3b;
|
||||
--color-method: #8bbdfa;
|
||||
--color-method-bg: #2e4e81;
|
||||
--color-method: #0891b2; /* Distinct teal-cyan */
|
||||
--color-method-bg: #164e63; /* Proper dark background */
|
||||
--color-concept: #f97316; /* Bright orange for dark mode */
|
||||
--color-concept-bg: #7c2d12;
|
||||
|
||||
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 30%);
|
||||
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 40%);
|
||||
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 50%);
|
||||
@ -313,6 +323,11 @@ input[type="checkbox"] {
|
||||
border-color: var(--color-method);
|
||||
}
|
||||
|
||||
.card-concept {
|
||||
background-color: var(--color-concept-bg);
|
||||
border-color: var(--color-concept);
|
||||
}
|
||||
|
||||
.grid-auto-fit {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 350px));
|
||||
|
@ -6,7 +6,7 @@ import { z } from 'zod';
|
||||
const ToolSchema = z.object({
|
||||
name: z.string(),
|
||||
icon: z.string().optional().nullable(),
|
||||
type: z.string(),
|
||||
type: z.enum(['software', 'method', 'concept']), // Make this more explicit
|
||||
description: z.string(),
|
||||
domains: z.array(z.string()).optional().nullable().default([]),
|
||||
phases: z.array(z.string()).optional().nullable().default([]),
|
||||
@ -127,12 +127,15 @@ export async function getToolsData(): Promise<ToolsData> {
|
||||
return cachedRandomizedData;
|
||||
}
|
||||
|
||||
// Get compressed data for AI (removes projectUrl and statusUrl)
|
||||
// Get compressed data for AI (removes projectUrl and statusUrl, excludes concepts)
|
||||
export async function getCompressedToolsDataForAI(): Promise<CompressedToolsData> {
|
||||
if (!cachedCompressedData) {
|
||||
const data = await getToolsData();
|
||||
|
||||
const compressedTools = data.tools.map(tool => {
|
||||
// Filter out concepts and compress remaining tools
|
||||
const compressedTools = data.tools
|
||||
.filter(tool => tool.type !== 'concept') // Exclude concepts from AI
|
||||
.map(tool => {
|
||||
const { projectUrl, statusUrl, ...compressedTool } = tool;
|
||||
return compressedTool;
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user