Dashboard erfordert Login, Magic-Links nutzen konfigurierten Endpunkt statt IP (v1.2.3)
## Dashboard nur noch intern '/' (das Kachel-Dashboard) verlangt jetzt @login_required -- ein anonymer Besuch landet zuerst auf der Login-Seite (ueber Flask-Logins bereits konfigurierten login_manager.login_view), statt innerhalb der Dashboard- Huelle einen 'bitte anmelden'-Platzhalter zu zeigen. Anders als bei TESM selbst (dessen Geraete-Dashboard bewusst auch ohne Login als Status-Board sichtbar bleibt) ist der Lizenzserver ein reines internes Verwaltungs- werkzeug. ## Magic-Links zeigen den konfigurierten Lizenzserver-Endpunkt, nicht die IP Self-Service-Link, Kundenportal-Anfrage/-Zugang und der in 'Lizenz per E-Mail senden' eingebettete Link wurden bisher per url_for(..., _external=True) gebaut -- das nutzt den Host-Header der GERADE laufenden Anfrage, zeigt also z.B. die interne IP, ueber die zufaellig der Admin gerade eingeloggt ist, statt der unter Einstellungen -> Lizenz -> Anbieter & Lizenzserver gepflegten oeffentlichen Domain. Neue Hilfs- funktion _customer_facing_url() baut diese Links jetzt stattdessen aus dem admin-gepflegten Lizenzserver-Endpunkt (_get_master_endpoint(), derselbe Wert, der auch in jede Lizenzdatei eingebettet wird) -- faellt auf die alte, request-basierte externe URL zurueck, wenn der Endpunkt noch nicht konfiguriert ist (frische Installation). Verifiziert gegen eine echte Kopie der Live-Datenbank: mit konfiguriertem Endpunkt zeigt der Self-Service-Link jetzt https://tesml.int.eertmoed.net/... statt der IP, unabhaengig davon, ueber welchen Host der Admin gerade zugreift; ohne konfigurierten Endpunkt bleibt der bisherige Fallback erhalten. ## Ausserdem live behoben (kein Code-Fix, reine Konfiguration) /etc/nginx/sites-available/tesm-license auf dem Master zeigte fuer /static/ faelschlich auf /srv/tesm/static/ (ein laengst nicht mehr existierendes Verzeichnis -- Ueberbleibsel aus der Zeit vor der Repo-Trennung) statt auf /srv/tesm-license/static/, wodurch CSS/JS/ Bilder ueberall 404eten (nackte, ungestylte Seiten). install.sh schreibt die nginx-Konfiguration bewusst nur bei einer FRISCHEN Installation (um manuelle Anpassungen wie TLS-Zertifikate bei Updates nicht zu ueberschreiben) -- das im Repo hinterlegte Template selbst war bereits korrekt, nur die schon laenger bestehende Datei auf dem Master war es nicht. Direkt auf dem Master korrigiert und nginx neu geladen. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1 +1 @@
|
||||
1.2.2
|
||||
1.2.3
|
||||
|
||||
+32
-7
@@ -1977,6 +1977,23 @@ def _get_master_endpoint():
|
||||
return get_setting("master_endpoint", "")
|
||||
|
||||
|
||||
def _customer_facing_url(endpoint, **values):
|
||||
"""Baut eine externe URL fuer an KUNDEN gerichtete Magic-Links (Self-
|
||||
Service, Kundenportal-Anfrage/-Zugang, Lizenz-per-E-Mail) auf Basis
|
||||
des admin-gepflegten Lizenzserver-Endpunkts (siehe _get_master_endpoint(),
|
||||
Einstellungen -> Lizenz -> Anbieter & Lizenzserver) -- NICHT per
|
||||
url_for(..., _external=True), das stattdessen den Host-Header der
|
||||
GERADE laufenden Anfrage verwendet und damit z.B. die interne IP
|
||||
zeigt, ueber die zufaellig der Admin gerade eingeloggt ist, statt der
|
||||
fuer Kunden eigentlich gedachten oeffentlichen Domain. Faellt auf die
|
||||
normale request-basierte externe URL zurueck, wenn der Endpunkt noch
|
||||
nicht konfiguriert ist (z.B. auf einer frischen Installation)."""
|
||||
base = _get_master_endpoint().rstrip("/")
|
||||
if not base:
|
||||
return url_for(endpoint, _external=True, **values)
|
||||
return base + url_for(endpoint, **values)
|
||||
|
||||
|
||||
def _customer_row(conn, customer_id):
|
||||
return conn.execute("SELECT * FROM license_customers WHERE id=?", (customer_id,)).fetchone()
|
||||
|
||||
@@ -2635,8 +2652,8 @@ def ticket_detail(ticket_id):
|
||||
license_types=licensing.LICENSE_TYPES, all_modules=licensing.ALL_MODULES,
|
||||
type_labels=LICENSE_TYPE_LABELS, module_labels=MODULE_LABELS,
|
||||
master_licensed=license_active(),
|
||||
self_service_url=url_for("self_service", ticket_id=ticket_id, _external=True),
|
||||
portal_request_url=url_for("portal_request", _external=True),
|
||||
self_service_url=_customer_facing_url("self_service", ticket_id=ticket_id),
|
||||
portal_request_url=_customer_facing_url("portal_request"),
|
||||
can_edit=current_user.has_permission("licenses.edit"),
|
||||
)
|
||||
|
||||
@@ -2876,12 +2893,12 @@ def license_send_email(license_id):
|
||||
return redirect(url_for("license_detail", license_id=license_id))
|
||||
self_service_note = ""
|
||||
if row["ticket_id"]:
|
||||
self_service_url = url_for("self_service", ticket_id=row["ticket_id"], _external=True)
|
||||
self_service_url = _customer_facing_url("self_service", ticket_id=row["ticket_id"])
|
||||
self_service_note = (
|
||||
f"\nÜber diesen Link können Sie Ihre Lizenz jederzeit selbst herunterladen, "
|
||||
f"widerrufen oder (z.B. nach einem Systemwechsel) neu erstellen:\n{self_service_url}\n"
|
||||
)
|
||||
portal_request_url = url_for("portal_request", _external=True)
|
||||
portal_request_url = _customer_facing_url("portal_request")
|
||||
self_service_note += (
|
||||
f"\nEine Übersicht all Ihrer Tickets/Lizenzen können Sie sich jederzeit unter folgendem Link per "
|
||||
f"E-Mail zuschicken lassen:\n{portal_request_url}\n"
|
||||
@@ -3086,7 +3103,7 @@ def portal_request():
|
||||
(now + timedelta(minutes=PORTAL_ACCESS_LINK_MINUTES)).strftime("%Y-%m-%d %H:%M:%S")),
|
||||
)
|
||||
conn.commit()
|
||||
access_url = url_for("portal_access", token=grant_token, _external=True)
|
||||
access_url = _customer_facing_url("portal_access", token=grant_token)
|
||||
try:
|
||||
_graph_send_mail(
|
||||
customer["contact_email"],
|
||||
@@ -3604,6 +3621,7 @@ def inject_license_topbar():
|
||||
|
||||
|
||||
@app.route("/")
|
||||
@login_required
|
||||
def index():
|
||||
"""Dashboard des Master-Lizenzservers -- eine rein informative Kachel-
|
||||
uebersicht der gerade AKTIVEN Lizenzen (analog zur Geraete-Kachel-
|
||||
@@ -3613,8 +3631,15 @@ def index():
|
||||
mit status='active' -- alles andere (Tickets anlegen/bearbeiten/
|
||||
loeschen, Lizenzen ausstellen/widerrufen/loeschen) ist Verwaltung und
|
||||
lebt seit der Kachel-Umstellung auf der eigenen Tickets-Seite
|
||||
(tickets_list())."""
|
||||
if not current_user.is_authenticated or not current_user.has_permission("licenses.view"):
|
||||
(tickets_list()).
|
||||
|
||||
@login_required (anders als bei TESM selbst, wo das Geraete-Dashboard
|
||||
bewusst auch ohne Login als reines Status-Board sichtbar bleibt): der
|
||||
Lizenzserver ist reines internes Verwaltungswerkzeug -- ein anonymer
|
||||
Besuch auf '/' soll immer zuerst auf die Login-Seite treffen (via
|
||||
login_manager.login_view), nicht auf einen 'bitte anmelden'-Platzhalter
|
||||
innerhalb der Dashboard-Huelle."""
|
||||
if not current_user.has_permission("licenses.view"):
|
||||
return render_template("index.html", buckets=None)
|
||||
conn = get_db_connection()
|
||||
active_rows = conn.execute("""
|
||||
|
||||
Reference in New Issue
Block a user