Files
reservierungssystem/app/auth.py
T
Peter ea90a3c9e3 Reservierungssystem: E-Mail-Feld & Bild-Captcha hinzugefuegt
Aenderungen:
- E-Mail-Feld im Reservierungs-Formular hinzugefuegt (Pflichtfeld)
- Math-Captcha durch Bild-Captcha (4 Zeichen) ersetzt
- E-Mail-Validierung im Backend
- Captcha-Validierung fuer Reservierungen
- Pillow zu Dockerfile hinzugefuegt
2026-05-16 13:29:25 +00:00

101 lines
3.2 KiB
Python

import os
import hashlib
import random
import time
import io
import base64
from functools import wraps
from flask import session, request, jsonify
from PIL import Image, ImageDraw, ImageFont
ADMIN_PASSWORD_PLAIN = 'changeme'
SECRET_KEY = os.environ.get('SESSION_SECRET', 'dev-secret-change-in-production')
def generate_captcha():
"""Generiert ein Bild-Captcha mit 4 Zeichen (Zahlen und Buchstaben)"""
# 4 zufaellige Zeichen (ohne aehnlich aussehende wie O/0, I/l)
chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'
code = ''.join(random.choice(chars) for _ in range(4))
# Token fuer Validierung
token = hashlib.sha256(f"{code}{int(time.time()/600)}captcha".encode()).hexdigest()[:16]
# Antwort in Session speichern
session['captcha_answer'] = code
session['captcha_token'] = token
# Bild generieren
img = Image.new('RGB', (180, 60), color='#f8fafc')
draw = ImageDraw.Draw(img)
# Hintergrund-Noise (Punkte)
for _ in range(100):
x = random.randint(0, 180)
y = random.randint(0, 60)
draw.point((x, y), fill='#cbd5e1')
# Linien hinzufuegen
for _ in range(5):
x1 = random.randint(0, 180)
y1 = random.randint(0, 60)
x2 = random.randint(0, 180)
y2 = random.randint(0, 60)
draw.line([(x1, y1), (x2, y2)], fill='#94a3b8', width=1)
# Text zeichnen (mit leichter Rotation pro Buchstabe)
try:
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 36)
except:
font = ImageFont.load_default()
positions = [20, 55, 90, 125]
for i, char in enumerate(code):
x = positions[i]
y = random.randint(12, 18)
# Zufaellige Farbe pro Buchstabe
color = random.choice(['#1e40af', '#166534', '#9a3412', '#701a75'])
draw.text((x, y), char, font=font, fill=color)
# Mehr Noise ueber den Text
for _ in range(50):
x = random.randint(0, 180)
y = random.randint(0, 60)
draw.point((x, y), fill='#64748b')
# In Base64 konvertieren
buffer = io.BytesIO()
img.save(buffer, format='PNG')
img_base64 = base64.b64encode(buffer.getvalue()).decode('utf-8')
return {
"image": f"data:image/png;base64,{img_base64}",
"token": token
}
def verify_captcha(token, answer):
"""Ueberprueft die Captcha-Antwort"""
if not token or not answer:
return False
stored = session.get('captcha_answer')
stored_token = session.get('captcha_token')
if stored and stored_token == token and str(stored).upper() == str(answer).upper():
session.pop('captcha_answer', None)
session.pop('captcha_token', None)
return True
return False
def require_auth(role='admin'):
def decorator(f):
@wraps(f)
def decorated(*args, **kwargs):
if 'user_role' not in session:
return jsonify({"error": "Unauthorized"}), 401
if role == 'admin' and session['user_role'] != 'admin':
return jsonify({"error": "Admin required"}), 403
return f(*args, **kwargs)
return decorated
return decorator
def check_admin_password(password):
return password == ADMIN_PASSWORD_PLAIN