Add 6 new tools: Hasher, Base64, JWT Decoder, Password Gen, Timestamp, Text Diff

- backend/tools/hasher.py: POST /api/hash/sha256 and /api/hash/bcrypt (bcrypt added to requirements)
- backend/tools/base64tool.py: POST /api/base64/encode and /api/base64/decode
- backend/tools/jwtdecoder.py: POST /api/jwt/decode (signature verification disabled)
- backend/tools/passwordgen.py: POST /api/password/generate with charset and length options
- backend/tools/timestamp.py: POST /api/timestamp/convert (unix<->date, ISO 8601 + German format)
- backend/tools/textdiff.py: POST /api/text/diff returning structured added/removed/unchanged lines
- All blueprints registered in app.py and tools/__init__.py
- React components with copy button, dark/light mode support via CSS variables
- ToolOverview rebuilt as card grid; App.jsx routes added for all tools

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Nirodan
2026-04-24 14:28:18 +02:00
parent 80ec5eca7b
commit 7f9c5c874a
17 changed files with 788 additions and 6 deletions
+28 -4
View File
@@ -2,9 +2,18 @@ import { useNavigate } from 'react-router-dom';
import { useEffect, useState } from 'react';
import axios from '../services/api';
const TOOLS = [
{ icon: '🔒', path: '/tools/md5', title: 'MD5 Hasher', desc: 'MD5-Hash berechnen (nur zur Analyse)' },
{ icon: '#️⃣', path: '/tools/hasher', title: 'SHA256 / bcrypt', desc: 'Sichere Hash-Algorithmen für Strings' },
{ icon: '📦', path: '/tools/base64', title: 'Base64', desc: 'Text kodieren und dekodieren' },
{ icon: '🔑', path: '/tools/jwt', title: 'JWT Decoder', desc: 'JWT Token analysieren (ohne Signaturprüfung)' },
{ icon: '🔐', path: '/tools/password', title: 'Passwort-Generator', desc: 'Sichere Passwörter generieren' },
{ icon: '🕐', path: '/tools/timestamp', title: 'Timestamp Converter', desc: 'Unix Timestamp in Datum umrechnen' },
{ icon: '📝', path: '/tools/textdiff', title: 'Text Diff', desc: 'Zwei Texte vergleichen' },
];
function ToolOverview() {
const navigate = useNavigate();
const role = localStorage.getItem('role');
const [websites, setWebsites] = useState([]);
const [loadingWebsites, setLoadingWebsites] = useState(true);
@@ -13,7 +22,7 @@ function ToolOverview() {
try {
const res = await axios.get('/api/websites');
setWebsites(res.data);
} catch (e) {
} catch {
setWebsites([]);
} finally {
setLoadingWebsites(false);
@@ -27,9 +36,24 @@ function ToolOverview() {
<h2>Tool-Übersicht</h2>
<p>Wähle ein Tool aus:</p>
<button onClick={() => navigate('/tools/md5')}>🔒 MD5 Tool</button><br /><br />
<div className="card-grid">
{TOOLS.map((tool) => (
<div
key={tool.path}
className="link-card"
onClick={() => navigate(tool.path)}
style={{ cursor: 'pointer' }}
>
<div className="link-card__icon">{tool.icon}</div>
<div>
<div className="link-card__title">{tool.title}</div>
<div className="link-card__desc">{tool.desc}</div>
</div>
</div>
))}
</div>
<h3 style={{ marginTop: '24px' }}>🌐 Externe Webseiten</h3>
<h3 style={{ marginTop: '24px' }}>Externe Webseiten</h3>
{loadingWebsites ? (
<p className="muted">Lade Links...</p>
) : websites.length === 0 ? (