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
@@ -0,0 +1,69 @@
import { useState } from 'react';
import axios from '../services/api';
const sectionBox = {
marginTop: '12px',
padding: '14px',
background: 'var(--surface-2)',
border: '1px solid var(--border)',
borderRadius: '12px',
};
function JwtDecoderTool() {
const [input, setInput] = useState('');
const [decoded, setDecoded] = useState(null);
const [error, setError] = useState('');
const handleDecode = async () => {
setError('');
setDecoded(null);
try {
const res = await axios.post('/api/jwt/decode', { token: input });
setDecoded(res.data);
} catch (err) {
setError(err.response?.data?.message || 'Ungültiger JWT');
}
};
return (
<div className="main-content">
<h2>JWT Decoder</h2>
<p style={{ color: 'var(--accent)', fontSize: '0.875rem', marginBottom: '0.75rem' }}>
<strong>Hinweis:</strong> Dieser Decoder verifiziert keine Signatur nur zur Analyse.
</p>
<textarea
rows={3}
value={input}
onChange={(e) => { setInput(e.target.value); setDecoded(null); setError(''); }}
placeholder="JWT Token einfügen"
style={{ resize: 'vertical', fontFamily: 'monospace', fontSize: '0.85rem' }}
/>
<button onClick={handleDecode}>Dekodieren</button>
{error && <p className="error">{error}</p>}
{decoded && (
<>
<div style={sectionBox}>
<p className="eyebrow" style={{ marginBottom: '6px' }}>Header</p>
<pre style={{ margin: 0, color: 'var(--text)', fontSize: '0.875rem', whiteSpace: 'pre-wrap', wordBreak: 'break-all' }}>
{JSON.stringify(decoded.header, null, 2)}
</pre>
</div>
<div style={sectionBox}>
<p className="eyebrow" style={{ marginBottom: '6px' }}>Payload</p>
<pre style={{ margin: 0, color: 'var(--text)', fontSize: '0.875rem', whiteSpace: 'pre-wrap', wordBreak: 'break-all' }}>
{JSON.stringify(decoded.payload, null, 2)}
</pre>
</div>
<div style={{ ...sectionBox, borderColor: decoded.expired ? '#ef4444' : '#22c55e' }}>
<p className="eyebrow" style={{ marginBottom: '4px' }}>Status</p>
<span style={{ fontWeight: 700, color: decoded.expired ? '#ef4444' : '#22c55e' }}>
{decoded.expired ? 'Abgelaufen' : 'Gültig'}
</span>
</div>
</>
)}
</div>
);
}
export default JwtDecoderTool;