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
This commit is contained in:
Peter
2026-05-16 13:29:25 +00:00
parent f26d02573e
commit ea90a3c9e3
6 changed files with 137 additions and 36 deletions
+64 -14
View File
@@ -2,35 +2,85 @@ 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():
a = random.randint(1, 15)
b = random.randint(1, 15)
op = random.choice(['+', '-'])
if op == '+':
answer = a + b
else:
answer = a - b
token = hashlib.sha256(f"{a}{op}{b}{int(time.time()/600)}captcha".encode()).hexdigest()[:16]
# FIX: Speichere Antwort in Session
session['captcha_answer'] = answer
"""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 {
"question": f"{a} {op} {b} = ?",
"token": token,
"answer": answer
"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')
if stored and str(stored) == str(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