add debug admin API for logs and database management
This commit is contained in:
parent
b41fd980ce
commit
95960ab7a9
|
|
@ -128,6 +128,15 @@ SMTP_USE_TLS=true
|
|||
# WICHTIG: Muss die URL sein, unter der das Frontend erreichbar ist
|
||||
FRONTEND_URL=https://coder.example.com
|
||||
|
||||
# ============================================================
|
||||
# DEBUG & ADMINISTRATION
|
||||
# ============================================================
|
||||
|
||||
# Debug-Token fuer Admin-API (view-logs, delete-email, etc.)
|
||||
# Generiere mit: python3 -c "import secrets; print(secrets.token_hex(32))"
|
||||
# Nutze via: curl -H "X-Debug-Token: xxx" http://localhost:5000/api/admin/debug?action=view-logs
|
||||
DEBUG_TOKEN=
|
||||
|
||||
# ============================================================
|
||||
# PRODUKTION - Erweiterte Einstellungen
|
||||
# ============================================================
|
||||
|
|
|
|||
161
admin_api.py
161
admin_api.py
|
|
@ -322,3 +322,164 @@ def get_active_takeovers():
|
|||
'sessions': sessions_list,
|
||||
'total': len(sessions_list)
|
||||
}), 200
|
||||
|
||||
|
||||
@admin_bp.route('/debug', methods=['GET', 'POST'])
|
||||
def debug_management():
|
||||
"""
|
||||
Debug-Management Endpoint für Logs und Datenbank-Bereinigung
|
||||
|
||||
Authentifizierung via:
|
||||
1. DEBUG_TOKEN Header: X-Debug-Token: <token>
|
||||
2. Oder Admin JWT Token
|
||||
|
||||
Actions:
|
||||
- view-logs: Zeigt letzte 100 Zeilen der Logs
|
||||
- clear-logs: Löscht alle Logs
|
||||
- delete-email: Entfernt User und alle zugehörigen Daten
|
||||
Parameter: ?email=test@example.com
|
||||
- delete-token: Entfernt Magic Link Tokens für Email
|
||||
Parameter: ?email=test@example.com
|
||||
"""
|
||||
# Authentifizierung prüfen
|
||||
debug_token = current_app.config.get('DEBUG_TOKEN')
|
||||
provided_token = request.headers.get('X-Debug-Token')
|
||||
|
||||
# Versuch JWT-Auth
|
||||
is_admin = False
|
||||
try:
|
||||
from flask_jwt_extended import verify_jwt_in_request, get_jwt_identity
|
||||
verify_jwt_in_request(optional=True)
|
||||
user_id = get_jwt_identity()
|
||||
if user_id:
|
||||
user = User.query.get(int(user_id))
|
||||
is_admin = user and user.is_admin
|
||||
except:
|
||||
pass
|
||||
|
||||
# Authentifizierung validieren
|
||||
if not (is_admin or (debug_token and provided_token == debug_token)):
|
||||
return jsonify({'error': 'Authentifizierung erforderlich (JWT oder X-Debug-Token Header)'}), 403
|
||||
|
||||
action = request.args.get('action', '').lower()
|
||||
|
||||
# ===== view-logs =====
|
||||
if action == 'view-logs':
|
||||
log_file = current_app.config.get('LOG_FILE', '/app/logs/spawner.log')
|
||||
try:
|
||||
with open(log_file, 'r', encoding='utf-8') as f:
|
||||
lines = f.readlines()
|
||||
last_100 = lines[-100:] if len(lines) > 100 else lines
|
||||
return jsonify({
|
||||
'action': 'view-logs',
|
||||
'lines': len(lines),
|
||||
'last_100': ''.join(last_100)
|
||||
}), 200
|
||||
except FileNotFoundError:
|
||||
return jsonify({'error': 'Log-Datei nicht gefunden'}), 404
|
||||
except Exception as e:
|
||||
return jsonify({'error': f'Fehler beim Lesen der Logs: {str(e)}'}), 500
|
||||
|
||||
# ===== clear-logs =====
|
||||
elif action == 'clear-logs':
|
||||
log_file = current_app.config.get('LOG_FILE', '/app/logs/spawner.log')
|
||||
try:
|
||||
with open(log_file, 'w') as f:
|
||||
f.write('')
|
||||
current_app.logger.info('[DEBUG] Logs wurden gelöscht')
|
||||
return jsonify({
|
||||
'action': 'clear-logs',
|
||||
'message': 'Logs wurden gelöscht'
|
||||
}), 200
|
||||
except Exception as e:
|
||||
return jsonify({'error': f'Fehler beim Löschen der Logs: {str(e)}'}), 500
|
||||
|
||||
# ===== delete-email =====
|
||||
elif action == 'delete-email':
|
||||
email = request.args.get('email', '').strip()
|
||||
if not email:
|
||||
return jsonify({'error': 'Parameter erforderlich: email'}), 400
|
||||
|
||||
try:
|
||||
user = User.query.filter_by(email=email).first()
|
||||
if not user:
|
||||
return jsonify({'error': f'User {email} nicht gefunden'}), 404
|
||||
|
||||
user_id = user.id
|
||||
email_deleted = user.email
|
||||
|
||||
# Container löschen falls vorhanden
|
||||
if user.container_id:
|
||||
try:
|
||||
container_mgr = ContainerManager()
|
||||
container_mgr.stop_container(user.container_id)
|
||||
container_mgr.remove_container(user.container_id)
|
||||
except:
|
||||
pass
|
||||
|
||||
# User und alle zugehörigen Daten löschen
|
||||
db.session.delete(user)
|
||||
db.session.commit()
|
||||
|
||||
current_app.logger.info(f'[DEBUG] User {email_deleted} wurde gelöscht')
|
||||
|
||||
return jsonify({
|
||||
'action': 'delete-email',
|
||||
'message': f'User {email_deleted} wurde gelöscht',
|
||||
'user_id': user_id
|
||||
}), 200
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
return jsonify({'error': f'Fehler beim Löschen: {str(e)}'}), 500
|
||||
|
||||
# ===== delete-token =====
|
||||
elif action == 'delete-token':
|
||||
email = request.args.get('email', '').strip()
|
||||
if not email:
|
||||
return jsonify({'error': 'Parameter erforderlich: email'}), 400
|
||||
|
||||
try:
|
||||
from models import MagicLinkToken
|
||||
user = User.query.filter_by(email=email).first()
|
||||
if not user:
|
||||
return jsonify({'error': f'User {email} nicht gefunden'}), 404
|
||||
|
||||
tokens = MagicLinkToken.query.filter_by(user_id=user.id).all()
|
||||
count = len(tokens)
|
||||
|
||||
for token in tokens:
|
||||
db.session.delete(token)
|
||||
db.session.commit()
|
||||
|
||||
current_app.logger.info(f'[DEBUG] {count} Magic Link Tokens für {email} wurden gelöscht')
|
||||
|
||||
return jsonify({
|
||||
'action': 'delete-token',
|
||||
'message': f'{count} Tokens für {email} gelöscht',
|
||||
'tokens_deleted': count
|
||||
}), 200
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
return jsonify({'error': f'Fehler: {str(e)}'}), 500
|
||||
|
||||
# ===== info =====
|
||||
elif action == 'info' or not action:
|
||||
return jsonify({
|
||||
'endpoint': '/api/admin/debug',
|
||||
'auth': 'X-Debug-Token Header oder Admin JWT',
|
||||
'actions': {
|
||||
'view-logs': 'Zeigt letzte 100 Zeilen der Logs',
|
||||
'clear-logs': 'Löscht alle Logs',
|
||||
'delete-email': 'Löscht User (Parameter: email=...)',
|
||||
'delete-token': 'Löscht Magic Link Tokens (Parameter: email=...)',
|
||||
'info': 'Diese Hilfe'
|
||||
},
|
||||
'examples': [
|
||||
'GET /api/admin/debug?action=view-logs -H "X-Debug-Token: xxx"',
|
||||
'GET /api/admin/debug?action=delete-email&email=test@example.com',
|
||||
'GET /api/admin/debug?action=delete-token&email=test@example.com'
|
||||
]
|
||||
}), 200
|
||||
|
||||
else:
|
||||
return jsonify({'error': f'Unbekannte Action: {action}'}), 400
|
||||
|
|
|
|||
55
config.py
55
config.py
|
|
@ -99,35 +99,10 @@ class Config:
|
|||
print(f"[CONFIG] Warnung: Fehler beim Laden von templates.json: {e}", file=sys.stderr)
|
||||
return {}
|
||||
|
||||
@staticmethod
|
||||
def _build_container_templates() -> dict:
|
||||
"""
|
||||
Baut CONTAINER_TEMPLATES Dictionary aus:
|
||||
1. TEMPLATE_IMAGES (Liste der verfügbaren Images)
|
||||
2. TEMPLATES_CONFIG (Metadaten aus templates.json)
|
||||
"""
|
||||
templates = {}
|
||||
|
||||
for image in Config.TEMPLATE_IMAGES:
|
||||
# Extrahiere Typ aus Image-Namen
|
||||
container_type = Config._extract_type_from_image(image)
|
||||
|
||||
# Hole Metadaten aus JSON (falls vorhanden)
|
||||
config = Config.TEMPLATES_CONFIG.get(container_type, {})
|
||||
|
||||
# Verwende JSON-Metadaten oder Fallback
|
||||
templates[container_type] = {
|
||||
'image': image,
|
||||
'display_name': config.get('display_name', container_type.replace('-', ' ').title()),
|
||||
'description': config.get('description', f'Container basierend auf {image}')
|
||||
}
|
||||
|
||||
return templates
|
||||
|
||||
# Dynamisches Template-Loading initialisieren
|
||||
TEMPLATE_IMAGES = _load_template_images.__func__()
|
||||
TEMPLATES_CONFIG = _load_templates_config.__func__()
|
||||
CONTAINER_TEMPLATES = _build_container_templates.__func__()
|
||||
# Temp-Variablen für Template-Loading (werden nach Klasse verarbeitet)
|
||||
TEMPLATE_IMAGES = None
|
||||
TEMPLATES_CONFIG = None
|
||||
CONTAINER_TEMPLATES = None
|
||||
|
||||
# ========================================
|
||||
# Traefik/Domain-Konfiguration
|
||||
|
|
@ -186,6 +161,11 @@ class Config:
|
|||
MAGIC_LINK_TOKEN_EXPIRY = int(os.getenv('MAGIC_LINK_TOKEN_EXPIRY', 900)) # 15 Minuten
|
||||
MAGIC_LINK_RATE_LIMIT = int(os.getenv('MAGIC_LINK_RATE_LIMIT', 3)) # Max 3 pro Stunde
|
||||
|
||||
# ========================================
|
||||
# Debug & Administration
|
||||
# ========================================
|
||||
DEBUG_TOKEN = os.getenv('DEBUG_TOKEN', '') # Für Admin-Debug-API
|
||||
|
||||
|
||||
class DevelopmentConfig(Config):
|
||||
"""Konfiguration für Entwicklung"""
|
||||
|
|
@ -215,6 +195,23 @@ class TestingConfig(Config):
|
|||
WTF_CSRF_ENABLED = False
|
||||
|
||||
|
||||
# Initialisiere Templates NACH Klassendefini tion
|
||||
Config.TEMPLATE_IMAGES = Config._load_template_images()
|
||||
Config.TEMPLATES_CONFIG = Config._load_templates_config()
|
||||
|
||||
# Baue CONTAINER_TEMPLATES aus Templates
|
||||
templates = {}
|
||||
for image in Config.TEMPLATE_IMAGES:
|
||||
container_type = Config._extract_type_from_image(image)
|
||||
config_meta = Config.TEMPLATES_CONFIG.get(container_type, {})
|
||||
templates[container_type] = {
|
||||
'image': image,
|
||||
'display_name': config_meta.get('display_name', container_type.replace('-', ' ').title()),
|
||||
'description': config_meta.get('description', f'Container basierend auf {image}')
|
||||
}
|
||||
Config.CONTAINER_TEMPLATES = templates
|
||||
|
||||
|
||||
# Config-Dict für einfaches Laden
|
||||
config = {
|
||||
'development': DevelopmentConfig,
|
||||
|
|
|
|||
|
|
@ -7,13 +7,12 @@ services:
|
|||
container_name: spawner
|
||||
restart: unless-stopped
|
||||
|
||||
env_file:
|
||||
- .env
|
||||
|
||||
ports:
|
||||
- "5000:5000" # Optional: Direktzugriff für Debugging
|
||||
|
||||
volumes:
|
||||
# .env zur Laufzeit laden (wird bei restart neu gelesen!)
|
||||
- .env:/app/.env:ro
|
||||
# Docker-Socket für Container-Management
|
||||
- /var/run/docker.sock:/var/run/docker.sock:rw
|
||||
# Persistente Daten
|
||||
|
|
@ -21,39 +20,7 @@ services:
|
|||
# Logs
|
||||
- ./logs:/app/logs
|
||||
|
||||
environment:
|
||||
# Aus .env-Datei - Sicherheit
|
||||
- SECRET_KEY=${SECRET_KEY}
|
||||
- JWT_SECRET_KEY=${JWT_SECRET_KEY:-${SECRET_KEY}}
|
||||
# Domain & Routing
|
||||
- BASE_DOMAIN=${BASE_DOMAIN}
|
||||
- SPAWNER_SUBDOMAIN=${SPAWNER_SUBDOMAIN:-coder}
|
||||
- CORS_ORIGINS=https://${SPAWNER_SUBDOMAIN:-coder}.${BASE_DOMAIN},http://localhost:3000
|
||||
# Docker & Traefik
|
||||
- TRAEFIK_NETWORK=${TRAEFIK_NETWORK}
|
||||
- DOCKER_HOST=${DOCKER_HOST:-unix:///var/run/docker.sock}
|
||||
# Templates (Dynamisches System)
|
||||
- USER_TEMPLATE_IMAGE=${USER_TEMPLATE_IMAGE:-user-template-01:latest}
|
||||
- USER_TEMPLATE_IMAGES=${USER_TEMPLATE_IMAGES:-"user-template-01:latest;user-template-02:latest;user-template-next:latest"}
|
||||
# Traefik-Zertifikate
|
||||
- TRAEFIK_CERTRESOLVER=${TRAEFIK_CERTRESOLVER:-lets-encrypt}
|
||||
- TRAEFIK_ENTRYPOINT=${TRAEFIK_ENTRYPOINT:-websecure}
|
||||
# SMTP & Email
|
||||
- SMTP_HOST=${SMTP_HOST}
|
||||
- SMTP_PORT=${SMTP_PORT}
|
||||
- SMTP_USER=${SMTP_USER}
|
||||
- SMTP_PASSWORD=${SMTP_PASSWORD}
|
||||
- SMTP_FROM=${SMTP_FROM}
|
||||
- SMTP_USE_TLS=${SMTP_USE_TLS:-true}
|
||||
- FRONTEND_URL=${FRONTEND_URL}
|
||||
# Magic Links
|
||||
- MAGIC_LINK_TOKEN_EXPIRY=${MAGIC_LINK_TOKEN_EXPIRY:-900}
|
||||
- MAGIC_LINK_RATE_LIMIT=${MAGIC_LINK_RATE_LIMIT:-3}
|
||||
# JWT
|
||||
- JWT_ACCESS_TOKEN_EXPIRES=${JWT_ACCESS_TOKEN_EXPIRES:-3600}
|
||||
# Ressourcen-Limits
|
||||
- DEFAULT_MEMORY_LIMIT=${DEFAULT_MEMORY_LIMIT:-512m}
|
||||
- DEFAULT_CPU_QUOTA=${DEFAULT_CPU_QUOTA:-50000}
|
||||
# .env wird als Volume gemountet - keine Duplication nötig!
|
||||
|
||||
networks:
|
||||
- web
|
||||
|
|
|
|||
|
|
@ -402,6 +402,305 @@ docker exec spawner sqlite3 /app/data/users.db \
|
|||
|
||||
---
|
||||
|
||||
## ⚙️ Häufige Konfigurationsänderungen nach Deployment
|
||||
|
||||
**WICHTIG:** Die `.env` Datei wird als **Volume in den Container gemountet**. Das bedeutet:
|
||||
- Änderungen in `.env` werden **zur Laufzeit** gelesen
|
||||
- Du brauchst **kein Docker-Rebuild** für Konfigurationsänderungen
|
||||
- Nur `docker-compose down` + `docker-compose up -d` reicht
|
||||
|
||||
### SMTP/Email-Anmeldedaten ändern
|
||||
|
||||
Falls du die Email-Anmeldedaten später ändern musst (z.B. Passwort aktualisiert):
|
||||
|
||||
```bash
|
||||
# 1. Bearbeite .env
|
||||
nano .env
|
||||
|
||||
# Ändere diese Zeilen:
|
||||
# SMTP_HOST=smtp.gmail.com
|
||||
# SMTP_PORT=587
|
||||
# SMTP_USER=deine-email@gmail.com
|
||||
# SMTP_PASSWORD=neues-passwort
|
||||
# SMTP_FROM=noreply@domain.com
|
||||
|
||||
# 2. Stoppe Container komplett und starte neu
|
||||
docker-compose down
|
||||
docker-compose up -d spawner
|
||||
|
||||
# 3. Überprüfe ob neue Credentials geladen wurden
|
||||
docker exec spawner cat /app/.env | grep SMTP_HOST
|
||||
```
|
||||
|
||||
**Hinweis:** `docker-compose restart spawner` reicht auch aus (schneller), aber `down`/`up` ist sicherer.
|
||||
|
||||
### Domain oder Base URL ändern
|
||||
|
||||
Falls du die Domain oder Subdomain ändern möchtest:
|
||||
|
||||
```bash
|
||||
# 1. Bearbeite .env
|
||||
nano .env
|
||||
|
||||
# Ändere diese Zeilen:
|
||||
# BASE_DOMAIN=neudomain.com
|
||||
# SPAWNER_SUBDOMAIN=coder (oder etwas anderes)
|
||||
# FRONTEND_URL=https://coder.neudomain.com
|
||||
|
||||
# 2. Starte Services neu
|
||||
docker-compose down
|
||||
docker-compose up -d spawner frontend
|
||||
|
||||
# 3. Überprüfe Config (sollte neue Domain zeigen)
|
||||
docker exec spawner cat /app/.env | grep BASE_DOMAIN
|
||||
```
|
||||
|
||||
### Magic Link Token Expiration ändern
|
||||
|
||||
Standardmäßig haben Magic Links 15 Minuten Gültigkeitsdauer. Wenn du das ändern möchtest:
|
||||
|
||||
```bash
|
||||
# 1. Bearbeite .env
|
||||
nano .env
|
||||
|
||||
# Ändere diese Zeilen:
|
||||
# MAGIC_LINK_TOKEN_EXPIRY=900 (in Sekunden, default: 15 Min)
|
||||
# MAGIC_LINK_RATE_LIMIT=3 (max. 3 Links pro Stunde)
|
||||
|
||||
# 2. Starte Backend neu
|
||||
docker-compose restart spawner
|
||||
# oder sicherer:
|
||||
# docker-compose down
|
||||
# docker-compose up -d spawner
|
||||
```
|
||||
|
||||
### JWT Token Expiration ändern
|
||||
|
||||
Standardmäßig verfallen JWT Tokens nach 1 Stunde:
|
||||
|
||||
```bash
|
||||
# 1. Bearbeite .env
|
||||
nano .env
|
||||
|
||||
# Ändere diese Zeile:
|
||||
# JWT_ACCESS_TOKEN_EXPIRES=3600 (in Sekunden)
|
||||
|
||||
# 2. Starte Backend neu
|
||||
docker-compose restart spawner
|
||||
```
|
||||
|
||||
### Container-Resource-Limits ändern
|
||||
|
||||
Wenn deine Server-Hardware unterschiedlich ist, passe die Limits an:
|
||||
|
||||
```bash
|
||||
# 1. Bearbeite .env
|
||||
nano .env
|
||||
|
||||
# Ändere diese Zeilen:
|
||||
# DEFAULT_MEMORY_LIMIT=512m (RAM pro Container)
|
||||
# DEFAULT_CPU_QUOTA=50000 (CPU: 50000 = 0.5 CPU, 100000 = 1 CPU)
|
||||
|
||||
# 2. Starte Backend neu
|
||||
docker-compose restart spawner
|
||||
|
||||
# Info: Neue Container verwenden sofort die neuen Limits
|
||||
# Laufende Container behalten alte Limits (bis Neustart)
|
||||
```
|
||||
|
||||
### Logging Level ändern
|
||||
|
||||
```bash
|
||||
# 1. Bearbeite .env
|
||||
nano .env
|
||||
|
||||
# Ändere diese Zeile:
|
||||
# LOG_LEVEL=INFO (Options: DEBUG, INFO, WARNING, ERROR)
|
||||
|
||||
# 2. Starte Backend neu
|
||||
docker-compose restart spawner
|
||||
```
|
||||
|
||||
### Überprüfe welche Werte der Container tatsächlich nutzt
|
||||
|
||||
Falls du unsicher bist, ob die neuen Konfigurationswerte geladen wurden:
|
||||
|
||||
```bash
|
||||
# Zeige die .env Werte, die der Container sieht
|
||||
docker exec spawner cat /app/.env | grep SMTP
|
||||
|
||||
# Alle SMTP-Einstellungen anzeigen:
|
||||
docker exec spawner cat /app/.env | grep SMTP
|
||||
|
||||
# Überprüfe mit Python, ob die Werte korrekt geladen sind:
|
||||
docker exec spawner python3 << 'EOF'
|
||||
from config import Config
|
||||
print(f"SMTP_HOST: {Config.SMTP_HOST}")
|
||||
print(f"SMTP_USER: {Config.SMTP_USER}")
|
||||
print(f"SMTP_PORT: {Config.SMTP_PORT}")
|
||||
EOF
|
||||
```
|
||||
|
||||
**Wichtig:**
|
||||
- `cat /app/.env | grep SMTP` zeigt die **aktuellen** Werte aus der `.env` Datei
|
||||
- `docker exec spawner env` zeigt Shell-Variablen, nicht Python-Variablen!
|
||||
- Python lädt die Werte mit `load_dotenv()` - überprüfe mit Python-Code ob sie korrekt geladen sind
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Debug-API für Administratoren
|
||||
|
||||
**Neue Feature:** Admin-API zum Debuggen und Bereinigen von Logs und Datenbanken
|
||||
|
||||
### Vorbereitung: DEBUG_TOKEN generieren
|
||||
|
||||
```bash
|
||||
# 1. Token generieren
|
||||
python3 -c "import secrets; print(secrets.token_hex(32))"
|
||||
|
||||
# Beispiel-Output:
|
||||
# a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6
|
||||
|
||||
# 2. In .env eintragen
|
||||
nano .env
|
||||
# DEBUG_TOKEN=a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6
|
||||
|
||||
# 3. Backend neustarten
|
||||
docker-compose restart spawner
|
||||
```
|
||||
|
||||
### Debug-API Endpoints
|
||||
|
||||
**Base:** `/api/admin/debug`
|
||||
|
||||
**Authentifizierung via Header:**
|
||||
```bash
|
||||
curl -H "X-Debug-Token: your-token-here" "http://localhost:5000/api/admin/debug?action=..."
|
||||
```
|
||||
|
||||
Oder mit **Admin JWT Token:**
|
||||
```bash
|
||||
curl -H "Authorization: Bearer your-jwt-token" "http://localhost:5000/api/admin/debug?action=..."
|
||||
```
|
||||
|
||||
### Verfügbare Actions
|
||||
|
||||
#### 1. Logs anzeigen (view-logs)
|
||||
|
||||
```bash
|
||||
curl -H "X-Debug-Token: xxx" \
|
||||
"http://localhost:5000/api/admin/debug?action=view-logs"
|
||||
```
|
||||
|
||||
Zeigt die **letzten 100 Zeilen** der Logs mit Zeilenanzahl.
|
||||
|
||||
#### 2. Logs löschen (clear-logs)
|
||||
|
||||
```bash
|
||||
curl -H "X-Debug-Token: xxx" \
|
||||
"http://localhost:5000/api/admin/debug?action=clear-logs"
|
||||
```
|
||||
|
||||
Löscht **alle Logs** komplett. Danach ist die Log-Datei leer.
|
||||
|
||||
#### 3. User entfernen (delete-email)
|
||||
|
||||
```bash
|
||||
curl -H "X-Debug-Token: xxx" \
|
||||
"http://localhost:5000/api/admin/debug?action=delete-email&email=test@example.com"
|
||||
```
|
||||
|
||||
Entfernt einen **User komplett** aus der Datenbank:
|
||||
- User-Profil gelöscht
|
||||
- Container gelöscht (falls existiert)
|
||||
- Alle Token gelöscht
|
||||
- Alle Datenbank-Einträge entfernt
|
||||
|
||||
**WARNUNG:** Das ist **nicht rückgängig zu machen**!
|
||||
|
||||
#### 4. Magic Link Tokens entfernen (delete-token)
|
||||
|
||||
```bash
|
||||
curl -H "X-Debug-Token: xxx" \
|
||||
"http://localhost:5000/api/admin/debug?action=delete-token&email=test@example.com"
|
||||
```
|
||||
|
||||
Löscht **nur die Magic Link Tokens** für eine Email. Der User bleibt bestehen!
|
||||
|
||||
Nützlich wenn:
|
||||
- Rate-Limiting blockiert den User
|
||||
- Tokens sind fehlerhaft
|
||||
- User neue Tokens anfordern soll
|
||||
|
||||
#### 5. Hilfe anzeigen (info)
|
||||
|
||||
```bash
|
||||
curl -H "X-Debug-Token: xxx" \
|
||||
"http://localhost:5000/api/admin/debug?action=info"
|
||||
```
|
||||
|
||||
Zeigt alle verfügbaren Actions und Beispiele.
|
||||
|
||||
### Praktische Beispiele
|
||||
|
||||
**Problem: User kann sich nicht anmelden (Rate Limit)**
|
||||
|
||||
```bash
|
||||
# 1. Lösche alle Tokens für diese Email
|
||||
curl -H "X-Debug-Token: xxx" \
|
||||
"http://localhost:5000/api/admin/debug?action=delete-token&email=user@example.com"
|
||||
|
||||
# 2. User kann jetzt neu anfragen
|
||||
```
|
||||
|
||||
**Problem: Alte Test-User in der Datenbank**
|
||||
|
||||
```bash
|
||||
# Lösche kompletten User
|
||||
curl -H "X-Debug-Token: xxx" \
|
||||
"http://localhost:5000/api/admin/debug?action=delete-email&email=test@example.com"
|
||||
```
|
||||
|
||||
**Problem: Logs sind zu groß**
|
||||
|
||||
```bash
|
||||
# Lösche alle Logs
|
||||
curl -H "X-Debug-Token: xxx" \
|
||||
"http://localhost:5000/api/admin/debug?action=clear-logs"
|
||||
```
|
||||
|
||||
**Problem: Brauche die letzten Fehler zum Debuggen**
|
||||
|
||||
```bash
|
||||
# Hole letzten 100 Zeilen
|
||||
curl -H "X-Debug-Token: xxx" \
|
||||
"http://localhost:5000/api/admin/debug?action=view-logs"
|
||||
```
|
||||
|
||||
### Bash-Alias für schnellen Zugriff
|
||||
|
||||
Füge dies in `~/.bashrc` ein für schnellere Befehle:
|
||||
|
||||
```bash
|
||||
export SPAWNER_DEBUG_TOKEN="dein-token-hier"
|
||||
export SPAWNER_URL="http://localhost:5000"
|
||||
|
||||
alias spawner-logs="curl -H 'X-Debug-Token: $SPAWNER_DEBUG_TOKEN' '$SPAWNER_URL/api/admin/debug?action=view-logs'"
|
||||
alias spawner-clear-logs="curl -H 'X-Debug-Token: $SPAWNER_DEBUG_TOKEN' '$SPAWNER_URL/api/admin/debug?action=clear-logs'"
|
||||
alias spawner-delete-email="curl -H 'X-Debug-Token: $SPAWNER_DEBUG_TOKEN' '$SPAWNER_URL/api/admin/debug?action=delete-email&email="
|
||||
```
|
||||
|
||||
Dann:
|
||||
```bash
|
||||
# Logs anzeigen
|
||||
spawner-logs
|
||||
|
||||
# User löschen
|
||||
spawner-delete-email=test@example.com"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Security Checklist
|
||||
|
||||
- [ ] SECRET_KEY ist generiert und komplex
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user