modified krawl template for single page visualization

This commit is contained in:
Patrick Di Fazio
2026-01-05 17:27:27 +01:00
parent 4478c60956
commit 190d74e1a7
3 changed files with 128 additions and 21 deletions

View File

@@ -156,11 +156,35 @@ def generate_dashboard(stats: dict) -> str:
background: #1c1917;
border-left: 4px solid #f85149;
}}
th.sortable {{
cursor: pointer;
user-select: none;
position: relative;
padding-right: 24px;
}}
th.sortable:hover {{
background: #1c2128;
}}
th.sortable::after {{
content: '';
position: absolute;
right: 8px;
opacity: 0.5;
font-size: 12px;
}}
th.sortable.asc::after {{
content: '';
opacity: 1;
}}
th.sortable.desc::after {{
content: '';
opacity: 1;
}}
</style>
</head>
<body>
<div class="container">
<h1>&#128375;&#65039; Krawl Dashboard</h1>
<h1>Krawl Dashboard</h1>
<div class="stats-grid">
<div class="stat-card">
@@ -190,13 +214,13 @@ def generate_dashboard(stats: dict) -> str:
</div>
<div class="table-container alert-section">
<h2>🍯 Honeypot Triggers by IP</h2>
<table>
<h2>Honeypot Triggers by IP</h2>
<table id="honeypot-table">
<thead>
<tr>
<th>IP Address</th>
<th class="sortable" data-sort="ip">IP Address</th>
<th>Accessed Paths</th>
<th>Count</th>
<th class="sortable" data-sort="count">Count</th>
</tr>
</thead>
<tbody>
@@ -206,7 +230,7 @@ def generate_dashboard(stats: dict) -> str:
</div>
<div class="table-container alert-section">
<h2>&#9888;&#65039; Recent Suspicious Activity</h2>
<h2>Recent Suspicious Activity</h2>
<table>
<thead>
<tr>
@@ -223,7 +247,7 @@ def generate_dashboard(stats: dict) -> str:
</div>
<div class="table-container alert-section">
<h2>🔑 Captured Credentials</h2>
<h2>Captured Credentials</h2>
<table>
<thead>
<tr>
@@ -241,7 +265,7 @@ def generate_dashboard(stats: dict) -> str:
</div>
<div class="table-container alert-section">
<h2>&#128520; Detected Attack Types</h2>
<h2>Detected Attack Types</h2>
<table>
<thead>
<tr>
@@ -306,6 +330,64 @@ def generate_dashboard(stats: dict) -> str:
</table>
</div>
</div>
<script>
// Add sorting functionality to tables
document.querySelectorAll('th.sortable').forEach(header => {{
header.addEventListener('click', function() {{
const table = this.closest('table');
const tbody = table.querySelector('tbody');
const rows = Array.from(tbody.querySelectorAll('tr'));
const sortType = this.getAttribute('data-sort');
const columnIndex = Array.from(this.parentElement.children).indexOf(this);
// Determine sort direction
const isAscending = this.classList.contains('asc');
// Remove sort classes from all headers in this table
table.querySelectorAll('th.sortable').forEach(th => {{
th.classList.remove('asc', 'desc');
}});
// Add appropriate class to clicked header
this.classList.add(isAscending ? 'desc' : 'asc');
// Sort rows
rows.sort((a, b) => {{
let aValue = a.cells[columnIndex].textContent.trim();
let bValue = b.cells[columnIndex].textContent.trim();
// Handle numeric sorting
if (sortType === 'count') {{
aValue = parseInt(aValue) || 0;
bValue = parseInt(bValue) || 0;
return isAscending ? bValue - aValue : aValue - bValue;
}}
// Handle IP address sorting
if (sortType === 'ip') {{
const ipToNum = ip => {{
const parts = ip.split('.');
if (parts.length !== 4) return 0;
return parts.reduce((acc, part, i) => acc + (parseInt(part) || 0) * Math.pow(256, 3 - i), 0);
}};
const aNum = ipToNum(aValue);
const bNum = ipToNum(bValue);
return isAscending ? bNum - aNum : aNum - bNum;
}}
// Default string sorting
if (isAscending) {{
return bValue.localeCompare(aValue);
}} else {{
return aValue.localeCompare(bValue);
}}
}});
// Re-append sorted rows
rows.forEach(row => tbody.appendChild(row));
}});
}});
</script>
</body>
</html>
"""

View File

@@ -9,40 +9,64 @@
background-color: #0d1117;
color: #c9d1d9;
margin: 0;
padding: 40px 20px;
min-height: 100vh;
padding: 0;
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
overflow: hidden;
}}
.container {{
max-width: 1200px;
width: 100%;
height: 100vh;
display: flex;
flex-direction: column;
padding: 20px;
box-sizing: border-box;
}}
h1 {{
color: #f85149;
text-align: center;
font-size: 48px;
margin: 60px 0 30px;
font-size: 36px;
margin: 40px 0 20px 0;
flex-shrink: 0;
}}
.counter {{
color: #f85149;
text-align: center;
font-size: 56px;
font-size: 32px;
font-weight: bold;
margin-bottom: 60px;
margin: 0 0 30px 0;
flex-shrink: 0;
}}
.links-container {{
display: flex;
flex-direction: column;
gap: 20px;
gap: 10px;
align-items: center;
overflow-y: auto;
flex: 1;
padding-top: 10px;
}}
.links-container::-webkit-scrollbar {{
width: 8px;
}}
.links-container::-webkit-scrollbar-track {{
background: #0d1117;
}}
.links-container::-webkit-scrollbar-thumb {{
background: #30363d;
border-radius: 4px;
}}
.links-container::-webkit-scrollbar-thumb:hover {{
background: #484f58;
}}
.link-box {{
background: #161b22;
border: 1px solid #30363d;
border-radius: 6px;
padding: 15px 30px;
padding: 10px 20px;
min-width: 300px;
text-align: center;
transition: all 0.3s ease;
@@ -56,7 +80,7 @@
a {{
color: #58a6ff;
text-decoration: none;
font-size: 20px;
font-size: 16px;
font-weight: 700;
}}
a:hover {{
@@ -66,21 +90,21 @@
background: #1c1917;
border: 2px solid #f85149;
border-radius: 8px;
padding: 30px 50px;
margin: 40px auto;
padding: 20px 30px;
margin: 20px auto;
max-width: 800px;
overflow-x: auto;
}}
.canary-token a {{
color: #f85149;
font-size: 18px;
font-size: 14px;
white-space: nowrap;
}}
</style>
</head>
<body>
<div class="container">
<h1>Krawl me! &#128376;</h1>
<h1>Krawl me!</h1>
<div class="counter">{counter}</div>
<div class="links-container">

View File

@@ -125,6 +125,7 @@ class Wordlists:
def server_errors(self):
return self._data.get("server_errors", {})
@property
def server_headers(self):
return self._data.get("server_headers", [])