lizenzserver API gedöns
Dieser Commit ist enthalten in:
@@ -931,6 +931,31 @@ def license_config():
|
||||
conn = get_connection()
|
||||
cur = conn.cursor()
|
||||
|
||||
# Get client configuration
|
||||
cur.execute("""
|
||||
SELECT id, client_name, api_key, heartbeat_interval, session_timeout,
|
||||
current_version, minimum_version, download_url, whats_new,
|
||||
created_at, updated_at
|
||||
FROM client_configs
|
||||
WHERE client_name = 'Account Forger'
|
||||
""")
|
||||
client_config = cur.fetchone()
|
||||
|
||||
# Get active sessions
|
||||
cur.execute("""
|
||||
SELECT ls.id, ls.session_token, l.license_key, c.name as customer_name,
|
||||
ls.hardware_id, ls.ip_address, ls.client_version,
|
||||
ls.started_at AT TIME ZONE 'Europe/Berlin' as started_at,
|
||||
ls.last_heartbeat AT TIME ZONE 'Europe/Berlin' as last_heartbeat,
|
||||
EXTRACT(EPOCH FROM (CURRENT_TIMESTAMP - ls.last_heartbeat)) as seconds_since_heartbeat
|
||||
FROM license_sessions ls
|
||||
JOIN licenses l ON ls.license_id = l.id
|
||||
LEFT JOIN customers c ON l.customer_id = c.id
|
||||
ORDER BY ls.last_heartbeat DESC
|
||||
LIMIT 5
|
||||
""")
|
||||
active_sessions = cur.fetchall()
|
||||
|
||||
# Get feature flags
|
||||
cur.execute("""
|
||||
SELECT * FROM feature_flags
|
||||
@@ -938,14 +963,6 @@ def license_config():
|
||||
""")
|
||||
feature_flags = cur.fetchall()
|
||||
|
||||
# Get API clients
|
||||
cur.execute("""
|
||||
SELECT id, client_name, api_key, is_active, created_at
|
||||
FROM api_clients
|
||||
ORDER BY created_at DESC
|
||||
""")
|
||||
api_clients = cur.fetchall()
|
||||
|
||||
# Get rate limits
|
||||
cur.execute("""
|
||||
SELECT * FROM api_rate_limits
|
||||
@@ -954,8 +971,9 @@ def license_config():
|
||||
rate_limits = cur.fetchall()
|
||||
|
||||
return render_template('license_config.html',
|
||||
client_config=client_config,
|
||||
active_sessions=active_sessions,
|
||||
feature_flags=feature_flags,
|
||||
api_clients=api_clients,
|
||||
rate_limits=rate_limits
|
||||
)
|
||||
|
||||
@@ -1006,6 +1024,174 @@ def update_feature_flag(flag_id):
|
||||
return redirect(url_for('admin.license_config'))
|
||||
|
||||
|
||||
|
||||
@admin_bp.route("/lizenzserver/config/update", methods=["POST"])
|
||||
@login_required
|
||||
def update_client_config():
|
||||
"""Update client configuration"""
|
||||
if session.get('username') not in ['rac00n', 'w@rh@mm3r']:
|
||||
flash('Zugriff verweigert', 'error')
|
||||
return redirect(url_for('admin.dashboard'))
|
||||
|
||||
try:
|
||||
conn = get_connection()
|
||||
cur = conn.cursor()
|
||||
|
||||
# Update configuration
|
||||
cur.execute("""
|
||||
UPDATE client_configs
|
||||
SET current_version = %s,
|
||||
minimum_version = %s,
|
||||
download_url = %s,
|
||||
whats_new = %s,
|
||||
heartbeat_interval = %s,
|
||||
session_timeout = %s,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE client_name = 'Account Forger'
|
||||
""", (
|
||||
request.form.get('current_version'),
|
||||
request.form.get('minimum_version'),
|
||||
'', # download_url - no longer used
|
||||
'', # whats_new - no longer used
|
||||
30, # heartbeat_interval - fixed
|
||||
60 # session_timeout - fixed
|
||||
))
|
||||
|
||||
conn.commit()
|
||||
flash('Client-Konfiguration wurde aktualisiert', 'success')
|
||||
|
||||
# Log action
|
||||
log_action(
|
||||
username=session.get('username'),
|
||||
action='UPDATE',
|
||||
entity_type='client_config',
|
||||
entity_id=1,
|
||||
new_values={
|
||||
'current_version': request.form.get('current_version'),
|
||||
'minimum_version': request.form.get('minimum_version')
|
||||
}
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
flash(f'Fehler beim Aktualisieren: {str(e)}', 'error')
|
||||
finally:
|
||||
if 'cur' in locals():
|
||||
cur.close()
|
||||
if 'conn' in locals():
|
||||
conn.close()
|
||||
|
||||
return redirect(url_for('admin.license_config'))
|
||||
|
||||
|
||||
@admin_bp.route("/lizenzserver/sessions")
|
||||
@login_required
|
||||
def license_sessions():
|
||||
"""Show active license sessions"""
|
||||
try:
|
||||
conn = get_connection()
|
||||
cur = conn.cursor()
|
||||
|
||||
# Get active sessions
|
||||
cur.execute("""
|
||||
SELECT ls.id, ls.session_token, l.license_key, c.name as customer_name,
|
||||
ls.hardware_id, ls.ip_address, ls.client_version,
|
||||
ls.started_at AT TIME ZONE 'Europe/Berlin' as started_at,
|
||||
ls.last_heartbeat AT TIME ZONE 'Europe/Berlin' as last_heartbeat,
|
||||
EXTRACT(EPOCH FROM (CURRENT_TIMESTAMP - ls.last_heartbeat)) as seconds_since_heartbeat
|
||||
FROM license_sessions ls
|
||||
JOIN licenses l ON ls.license_id = l.id
|
||||
LEFT JOIN customers c ON l.customer_id = c.id
|
||||
ORDER BY ls.last_heartbeat DESC
|
||||
""")
|
||||
sessions = cur.fetchall()
|
||||
|
||||
# Get session history (last 24h)
|
||||
cur.execute("""
|
||||
SELECT sh.id, l.license_key, c.name as customer_name,
|
||||
sh.hardware_id, sh.ip_address, sh.client_version,
|
||||
sh.started_at AT TIME ZONE 'Europe/Berlin' as started_at,
|
||||
sh.ended_at AT TIME ZONE 'Europe/Berlin' as ended_at,
|
||||
sh.end_reason,
|
||||
EXTRACT(EPOCH FROM (sh.ended_at - sh.started_at)) as duration_seconds
|
||||
FROM session_history sh
|
||||
JOIN licenses l ON sh.license_id = l.id
|
||||
LEFT JOIN customers c ON l.customer_id = c.id
|
||||
WHERE sh.ended_at > CURRENT_TIMESTAMP - INTERVAL '24 hours'
|
||||
ORDER BY sh.ended_at DESC
|
||||
LIMIT 100
|
||||
""")
|
||||
history = cur.fetchall()
|
||||
|
||||
return render_template('license_sessions.html',
|
||||
active_sessions=sessions,
|
||||
session_history=history)
|
||||
|
||||
except Exception as e:
|
||||
flash(f'Fehler beim Laden der Sessions: {str(e)}', 'error')
|
||||
return render_template('license_sessions.html')
|
||||
finally:
|
||||
if 'cur' in locals():
|
||||
cur.close()
|
||||
if 'conn' in locals():
|
||||
conn.close()
|
||||
|
||||
|
||||
@admin_bp.route("/lizenzserver/sessions/<int:session_id>/terminate", methods=["POST"])
|
||||
@login_required
|
||||
def terminate_session(session_id):
|
||||
"""Force terminate a session"""
|
||||
if session.get('username') not in ['rac00n', 'w@rh@mm3r']:
|
||||
flash('Zugriff verweigert', 'error')
|
||||
return redirect(url_for('admin.license_sessions'))
|
||||
|
||||
try:
|
||||
conn = get_connection()
|
||||
cur = conn.cursor()
|
||||
|
||||
# Get session info
|
||||
cur.execute("""
|
||||
SELECT license_id, hardware_id, ip_address, client_version, started_at
|
||||
FROM license_sessions
|
||||
WHERE id = %s
|
||||
""", (session_id,))
|
||||
session_info = cur.fetchone()
|
||||
|
||||
if session_info:
|
||||
# Log to history
|
||||
cur.execute("""
|
||||
INSERT INTO session_history
|
||||
(license_id, hardware_id, ip_address, client_version, started_at, ended_at, end_reason)
|
||||
VALUES (%s, %s, %s, %s, %s, CURRENT_TIMESTAMP, 'forced')
|
||||
""", session_info)
|
||||
|
||||
# Delete session
|
||||
cur.execute("DELETE FROM license_sessions WHERE id = %s", (session_id,))
|
||||
|
||||
conn.commit()
|
||||
flash('Session wurde beendet', 'success')
|
||||
|
||||
# Log action
|
||||
log_action(
|
||||
username=session.get('username'),
|
||||
action='TERMINATE_SESSION',
|
||||
entity_type='license_session',
|
||||
entity_id=session_id,
|
||||
additional_info={'hardware_id': session_info[1]}
|
||||
)
|
||||
else:
|
||||
flash('Session nicht gefunden', 'error')
|
||||
|
||||
except Exception as e:
|
||||
flash(f'Fehler beim Beenden der Session: {str(e)}', 'error')
|
||||
finally:
|
||||
if 'cur' in locals():
|
||||
cur.close()
|
||||
if 'conn' in locals():
|
||||
conn.close()
|
||||
|
||||
return redirect(url_for('admin.license_sessions'))
|
||||
|
||||
|
||||
@admin_bp.route("/api/admin/lizenzserver/live-stats")
|
||||
@login_required
|
||||
def license_live_stats():
|
||||
@@ -1024,27 +1210,36 @@ def license_live_stats():
|
||||
""")
|
||||
stats = cur.fetchone()
|
||||
|
||||
# Get latest validations
|
||||
# Get active sessions count
|
||||
cur.execute("""
|
||||
SELECT l.license_key, lh.hardware_id, lh.ip_address, lh.timestamp
|
||||
FROM license_heartbeats lh
|
||||
JOIN licenses l ON lh.license_id = l.id
|
||||
ORDER BY lh.timestamp DESC
|
||||
SELECT COUNT(*) FROM license_sessions
|
||||
""")
|
||||
active_count = cur.fetchone()[0]
|
||||
|
||||
# Get latest sessions
|
||||
cur.execute("""
|
||||
SELECT ls.id, l.license_key, c.name as customer_name,
|
||||
ls.client_version, ls.last_heartbeat AT TIME ZONE 'Europe/Berlin' as last_heartbeat,
|
||||
EXTRACT(EPOCH FROM (CURRENT_TIMESTAMP - ls.last_heartbeat)) as seconds_since
|
||||
FROM license_sessions ls
|
||||
JOIN licenses l ON ls.license_id = l.id
|
||||
LEFT JOIN customers c ON l.customer_id = c.id
|
||||
ORDER BY ls.last_heartbeat DESC
|
||||
LIMIT 5
|
||||
""")
|
||||
latest_validations = cur.fetchall()
|
||||
latest_sessions = cur.fetchall()
|
||||
|
||||
return jsonify({
|
||||
'active_licenses': stats[0] or 0,
|
||||
'active_licenses': active_count,
|
||||
'validations_per_minute': stats[1] or 0,
|
||||
'active_devices': stats[2] or 0,
|
||||
'latest_validations': [
|
||||
'latest_sessions': [
|
||||
{
|
||||
'license_key': v[0][:8] + '...',
|
||||
'hardware_id': v[1][:8] + '...',
|
||||
'ip_address': v[2] or 'Unknown',
|
||||
'timestamp': v[3].strftime('%H:%M:%S')
|
||||
} for v in latest_validations
|
||||
'customer_name': s[2],
|
||||
'version': s[3],
|
||||
'last_heartbeat': s[4].strftime('%H:%M:%S'),
|
||||
'seconds_since': int(s[5])
|
||||
} for s in latest_sessions
|
||||
]
|
||||
})
|
||||
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren