Initial commit: Werkzeuge-Sammlung

Enthält:
- rdp_client.py: RDP Client mit GUI und Monitor-Auswahl
- rdp.sh: Bash-basierter RDP Client
- teamleader_test/: Network Scanner Fullstack-App
- teamleader_test2/: Network Mapper CLI

Subdirectories mit eigenem Repo wurden ausgeschlossen.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
root
2026-01-28 09:39:24 +01:00
commit cb073786b3
112 changed files with 23543 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>LAN Graph Explorer</title>
<link rel="stylesheet" href="/static/style.css" />
</head>
<body>
<header>
<h1>LAN Graph Explorer</h1>
<p>Discover your local hosts and their relationships in a Visio-style topology.</p>
<button id="refresh">Refresh scan</button>
</header>
<main>
<div id="status">Idle</div>
<svg id="topology" viewBox="0 0 1000 600"></svg>
</main>
<script src="https://d3js.org/d3.v7.min.js"></script>
<script src="/static/script.js"></script>
</body>
</html>

View File

@@ -0,0 +1,103 @@
const statusEl = document.querySelector('#status');
const svg = d3.select('#topology');
const width = 1000;
const height = 600;
const linkGroup = svg.append('g').attr('class', 'links');
const nodeGroup = svg.append('g').attr('class', 'nodes');
const simulation = d3.forceSimulation()
.force('link', d3.forceLink().id(d => d.ip).distance(140))
.force('charge', d3.forceManyBody().strength(-200))
.force('center', d3.forceCenter(width / 2, height / 2));
function colorForNode(node) {
if (node.comment && node.comment.includes('gateway')) return '#ffb347';
if (node.comment && node.comment.includes('scanner')) return '#4db8ff';
return node.via_ssh ? '#7fbea6' : '#d4d4d4';
}
function render(data) {
const edges = data.edges.map(edge => ({
...edge,
source: edge.source,
target: edge.target,
}));
const link = linkGroup.selectAll('line').data(edges, d => `${d.source}|${d.target}|${d.relation}`);
link.join(
enter => enter.append('line').attr('stroke-width', 2),
update => update,
exit => exit.remove()
).attr('stroke', '#999');
const node = nodeGroup.selectAll('g').data(data.nodes, d => d.ip);
const nodeEnter = node.enter().append('g').call(d3.drag()
.on('start', dragstarted)
.on('drag', dragged)
.on('end', dragended));
nodeEnter.append('circle').attr('r', 26);
nodeEnter.append('text')
.attr('text-anchor', 'middle')
.attr('dy', '0.35em')
.text(d => d.ip);
nodeEnter.append('title');
const nodeMerged = nodeEnter.merge(node);
nodeMerged.select('circle').attr('fill', colorForNode);
nodeMerged.select('title').text(d => `${d.ip}\n${d.dns_name || 'no reverse host'}\nvia SSH: ${d.via_ssh}`);
node.exit().remove();
simulation.nodes(data.nodes).on('tick', ticked);
simulation.force('link').links(edges);
simulation.alpha(1).restart();
}
function ticked() {
linkGroup.selectAll('line')
.attr('x1', d => d.source.x)
.attr('y1', d => d.source.y)
.attr('x2', d => d.target.x)
.attr('y2', d => d.target.y);
nodeGroup.selectAll('g')
.attr('transform', d => `translate(${d.x},${d.y})`);
}
function dragstarted(event, d) {
if (!event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(event, d) {
d.fx = event.x;
d.fy = event.y;
}
function dragended(event, d) {
if (!event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
async function refresh() {
try {
statusEl.textContent = 'Scanning local LAN…';
const response = await fetch('/api/scan');
if (!response.ok) {
throw new Error(`scan failed: ${response.status}`);
}
const payload = await response.json();
render(payload);
statusEl.textContent = `Last scanned ${new Date().toLocaleTimeString()}`;
} catch (error) {
statusEl.textContent = `Error: ${error.message}`;
}
}
document.querySelector('#refresh').addEventListener('click', refresh);
refresh();

View File

@@ -0,0 +1,71 @@
* {
box-sizing: border-box;
font-family: Inter, system-ui, sans-serif;
}
body {
margin: 0;
background: #0f141a;
color: #f4f5f7;
}
header {
padding: 1rem 2rem;
background: linear-gradient(90deg, #1d2734, #0d121b);
display: flex;
justify-content: space-between;
gap: 1rem;
align-items: center;
}
h1 {
margin: 0;
font-size: 1.5rem;
}
header p {
margin: 0;
color: #9da8b7;
}
main {
display: flex;
flex-direction: column;
align-items: center;
padding: 1rem;
}
#status {
margin-bottom: 0.5rem;
font-size: 0.95rem;
color: #a5c9ff;
}
#topology {
width: min(100%, 1100px);
background: #111827;
border-radius: 1rem;
border: 1px solid rgba(255, 255, 255, 0.08);
box-shadow: 0 25px 45px rgba(5, 5, 5, 0.4);
}
circle {
stroke: #fff;
stroke-width: 1;
}
button {
border: none;
border-radius: 999px;
padding: 0.5rem 1rem;
background: #2563eb;
color: white;
font-weight: 600;
cursor: pointer;
transition: transform 0.15s ease, box-shadow 0.15s ease;
}
button:hover {
transform: translateY(-1px);
box-shadow: 0 10px 20px rgba(37, 99, 235, 0.35);
}