deutsche Zeit statt UTC

Dieser Commit ist enthalten in:
2025-06-08 20:21:58 +02:00
Ursprung f9e5823eeb
Commit f269082115
19 geänderte Dateien mit 1411 neuen und 31 gelöschten Zeilen

Datei anzeigen

@@ -7,6 +7,7 @@ from functools import wraps
from dotenv import load_dotenv
import pandas as pd
from datetime import datetime, timedelta
from zoneinfo import ZoneInfo
import io
import subprocess
import gzip
@@ -72,7 +73,7 @@ def login_required(f):
# Prüfe ob Session abgelaufen ist
if 'last_activity' in session:
last_activity = datetime.fromisoformat(session['last_activity'])
time_since_activity = datetime.now() - last_activity
time_since_activity = datetime.now(ZoneInfo("Europe/Berlin")).replace(tzinfo=None) - last_activity
# Debug-Logging
app.logger.info(f"Session check for {session.get('username', 'unknown')}: "
@@ -170,7 +171,7 @@ def get_or_create_encryption_key():
def create_backup(backup_type="manual", created_by=None):
"""Erstellt ein verschlüsseltes Backup der Datenbank"""
start_time = time.time()
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
timestamp = datetime.now(ZoneInfo("Europe/Berlin")).strftime("%Y%m%d_%H%M%S")
filename = f"backup_v2docker_{timestamp}_encrypted.sql.gz.enc"
filepath = BACKUP_DIR / filename
@@ -398,7 +399,7 @@ def check_ip_blocked(ip_address):
conn.close()
if result and result[0]:
if result[0] > datetime.now():
if result[0] > datetime.now(ZoneInfo("Europe/Berlin")).replace(tzinfo=None):
return True, result[0]
return False, None
@@ -425,7 +426,7 @@ def record_failed_attempt(ip_address, username):
blocked_until = None
if new_count >= MAX_LOGIN_ATTEMPTS:
blocked_until = datetime.now() + timedelta(hours=BLOCK_DURATION_HOURS)
blocked_until = datetime.now(ZoneInfo("Europe/Berlin")).replace(tzinfo=None) + timedelta(hours=BLOCK_DURATION_HOURS)
# E-Mail-Benachrichtigung (wenn aktiviert)
if os.getenv("EMAIL_ENABLED", "false").lower() == "true":
send_security_alert_email(ip_address, username, new_count)
@@ -505,7 +506,7 @@ def send_security_alert_email(ip_address, username, attempt_count):
IP-Adresse: {ip_address}
Versuchter Benutzername: {username}
Anzahl Versuche: {attempt_count}
Zeit: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
Zeit: {datetime.now(ZoneInfo("Europe/Berlin")).strftime('%Y-%m-%d %H:%M:%S')}
Die IP-Adresse wurde für 24 Stunden gesperrt.
@@ -565,7 +566,7 @@ def generate_license_key(license_type='full'):
chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'
# Datum-Teil
now = datetime.now()
now = datetime.now(ZoneInfo("Europe/Berlin"))
date_part = now.strftime('%Y%m')
type_char = 'F' if license_type == 'full' else 'T'
@@ -606,7 +607,7 @@ def login():
# Prüfen ob IP gesperrt ist
is_blocked, blocked_until = check_ip_blocked(ip_address)
if is_blocked:
time_remaining = (blocked_until - datetime.now()).total_seconds() / 3600
time_remaining = (blocked_until - datetime.now(ZoneInfo("Europe/Berlin")).replace(tzinfo=None)).total_seconds() / 3600
error_msg = f"IP GESPERRT! Noch {time_remaining:.1f} Stunden warten."
return render_template("login.html", error=error_msg, error_type="blocked")
@@ -668,7 +669,7 @@ def login():
session.permanent = True # Aktiviert das Timeout
session['logged_in'] = True
session['username'] = username
session['last_activity'] = datetime.now().isoformat()
session['last_activity'] = datetime.now(ZoneInfo("Europe/Berlin")).replace(tzinfo=None).isoformat()
reset_login_attempts(ip_address)
log_audit('LOGIN_SUCCESS', 'user',
additional_info=f"Erfolgreiche Anmeldung von IP: {ip_address}")
@@ -710,7 +711,7 @@ def logout():
def heartbeat():
"""Endpoint für Session Keep-Alive - aktualisiert last_activity"""
# Aktualisiere last_activity nur wenn explizit angefordert
session['last_activity'] = datetime.now().isoformat()
session['last_activity'] = datetime.now(ZoneInfo("Europe/Berlin")).replace(tzinfo=None).isoformat()
# Force session save
session.modified = True
@@ -975,7 +976,7 @@ def dashboard():
'ip_address': event[0],
'attempt_count': event[1],
'last_attempt': event[2].strftime('%d.%m %H:%M'),
'blocked_until': event[3].strftime('%d.%m %H:%M') if event[3] and event[3] > datetime.now() else None,
'blocked_until': event[3].strftime('%d.%m %H:%M') if event[3] and event[3] > datetime.now(ZoneInfo("Europe/Berlin")).replace(tzinfo=None) else None,
'username_tried': event[4],
'error_message': event[5]
})
@@ -1249,7 +1250,7 @@ def batch_licenses():
'licenses': generated_licenses,
'valid_from': valid_from,
'valid_until': valid_until,
'timestamp': datetime.now().isoformat()
'timestamp': datetime.now(ZoneInfo("Europe/Berlin")).replace(tzinfo=None).isoformat()
}
flash(f'{quantity} Lizenzen erfolgreich generiert!', 'success')
@@ -1308,7 +1309,7 @@ def export_batch():
io.BytesIO(output.getvalue().encode('utf-8-sig')),
mimetype='text/csv',
as_attachment=True,
download_name=f"batch_licenses_{batch_data['customer'].replace(' ', '_')}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"
download_name=f"batch_licenses_{batch_data['customer'].replace(' ', '_')}_{datetime.now(ZoneInfo('Europe/Berlin')).strftime('%Y%m%d_%H%M%S')}.csv"
)
@app.route("/licenses")
@@ -1778,7 +1779,7 @@ def export_licenses():
# Audit-Log
log_audit('EXPORT', 'license',
additional_info=f"Export aller Lizenzen als {export_format.upper()}")
filename = f'lizenzen_export_{datetime.now().strftime("%Y%m%d_%H%M%S")}'
filename = f'lizenzen_export_{datetime.now(ZoneInfo("Europe/Berlin")).strftime("%Y%m%d_%H%M%S")}'
if export_format == 'csv':
# CSV Export
@@ -1859,7 +1860,7 @@ def export_customers():
# Audit-Log
log_audit('EXPORT', 'customer',
additional_info=f"Export aller Kunden als {export_format.upper()}")
filename = f'kunden_export_{datetime.now().strftime("%Y%m%d_%H%M%S")}'
filename = f'kunden_export_{datetime.now(ZoneInfo("Europe/Berlin")).strftime("%Y%m%d_%H%M%S")}'
if export_format == 'csv':
# CSV Export
@@ -2108,7 +2109,7 @@ def blocked_ips():
'first_attempt': ip[2].strftime('%d.%m.%Y %H:%M'),
'last_attempt': ip[3].strftime('%d.%m.%Y %H:%M'),
'blocked_until': ip[4].strftime('%d.%m.%Y %H:%M'),
'is_active': ip[4] > datetime.now(),
'is_active': ip[4] > datetime.now(ZoneInfo("Europe/Berlin")).replace(tzinfo=None),
'last_username': ip[5],
'last_error': ip[6]
})