Security, code quality and frontend improvements

- Move SECRET_KEY out of docker-compose into .env (env_file), add .env.example
- Add flask-limiter with 10 req/min on login route; introduce util/limiter.py
- Replace direct mysql.connector.connect() calls with MySQLConnectionPool via util/db_pool.py
- Fix deprecated datetime.utcnow() -> datetime.now(timezone.utc) in auth/login.py
- Remove dead /api/scripts 410 route from admin.py
- Add MD5 security warning in Md5Tool.jsx
- Add ErrorBoundary component and wrap App.jsx
- Expand README with setup guide, screenshot and project structure

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Nirodan
2026-04-24 13:52:53 +02:00
parent 8e2c2d740e
commit 80ec5eca7b
12 changed files with 232 additions and 75 deletions
+20 -17
View File
@@ -6,6 +6,7 @@ import Md5Tool from './components/Md5Tool';
import NavBar from './components/NavBar';
import ToolOverview from './components/ToolOverview';
import AdminDashboard from './components/AdminDashboard';
import ErrorBoundary from './components/ErrorBoundary';
import './css/base.css';
@@ -21,23 +22,25 @@ function App() {
const role = localStorage.getItem('role');
return (
<BrowserRouter>
<NavBar />
<Routes>
<Route path="/" element={isLoggedIn ? <ToolOverview /> : <Navigate to="/login" />} />
<Route path="/login" element={<LoginForm />} />
{/*<Route path="/register" element={<RegisterForm />} />*/}
<Route path="/tools/md5" element={isLoggedIn ? <Md5Tool /> : <Navigate to="/login" />} />
<Route
path="/admin"
element={
isLoggedIn && role === 'admin'
? <AdminDashboard />
: <Navigate to="/" />
}
/>
</Routes>
</BrowserRouter>
<ErrorBoundary>
<BrowserRouter>
<NavBar />
<Routes>
<Route path="/" element={isLoggedIn ? <ToolOverview /> : <Navigate to="/login" />} />
<Route path="/login" element={<LoginForm />} />
{/*<Route path="/register" element={<RegisterForm />} />*/}
<Route path="/tools/md5" element={isLoggedIn ? <Md5Tool /> : <Navigate to="/login" />} />
<Route
path="/admin"
element={
isLoggedIn && role === 'admin'
? <AdminDashboard />
: <Navigate to="/" />
}
/>
</Routes>
</BrowserRouter>
</ErrorBoundary>
);
}
+33
View File
@@ -0,0 +1,33 @@
import { Component } from 'react';
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null };
}
static getDerivedStateFromError(error) {
return { hasError: true, error };
}
componentDidCatch(error, info) {
console.error('ErrorBoundary caught:', error, info);
}
render() {
if (this.state.hasError) {
return (
<div style={{ padding: '2rem', textAlign: 'center' }}>
<h2>Ein unerwarteter Fehler ist aufgetreten.</h2>
<p style={{ opacity: 0.7 }}>{this.state.error?.message}</p>
<button onClick={() => this.setState({ hasError: false, error: null })}>
Erneut versuchen
</button>
</div>
);
}
return this.props.children;
}
}
export default ErrorBoundary;
+6 -1
View File
@@ -18,11 +18,16 @@ function Md5Tool() {
return (
<div className="main-content">
<h2>MD5 Hasher</h2>
<p style={{ color: '#e07b00', fontSize: '0.875rem', marginBottom: '0.75rem' }}>
<strong>Sicherheitshinweis:</strong> MD5 ist kryptografisch unsicher und darf
nicht zum Hashen von Passwörtern verwendet werden. Für Passwörter bitte
bcrypt, Argon2 oder scrypt einsetzen.
</p>
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Gib ein Passwort ein"
placeholder="Eingabe"
/>
<button onClick={hashPassword}>Hash berechnen</button>
{result && <p><strong>MD5:</strong> {result}</p>}