deutsche Zeit statt UTC
Dieser Commit ist enthalten in:
@@ -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]
|
||||
})
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren