GDPR compliance: self-host all assets, add Impressum + Datenschutz

- Self-host Tailwind, Plotly, D3.js (no more CDN requests)
- Self-host Inter font (no more Google Fonts requests)
- Replace JetBrains Mono with system monospace font stack
- Zero external requests when visiting the site (GDPR-safe)
- Add /impressum page (§5 TMG, §18 MStV)
- Add /datenschutz page (DSGVO Art. 13/14)
- Hosting: Hetzner, no cookies, no tracking, no analytics
- Add Impressum/Datenschutz links to sidebar footer
- Configure Flask static_folder for local asset serving

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-07 08:20:52 +01:00
parent 75c4da72e0
commit da2a989744
13 changed files with 345 additions and 8 deletions

View File

@@ -44,6 +44,8 @@ from webui.data import (
app = Flask(
__name__,
template_folder=str(Path(__file__).parent / "templates"),
static_folder=str(Path(__file__).parent / "static"),
static_url_path="/static",
)
app.config["SECRET_KEY"] = "ietf-dashboard-dev"
@@ -282,6 +284,16 @@ def about():
return render_template("about.html", stats=stats)
@app.route("/impressum")
def impressum():
return render_template("impressum.html")
@app.route("/datenschutz")
def datenschutz():
return render_template("datenschutz.html")
# --- API endpoints for AJAX (used by client-side charts) ---

View File

@@ -0,0 +1,29 @@
/* Self-hosted Inter font (GDPR-compliant, no external requests) */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('/static/fonts/inter-400.woff2') format('woff2');
}
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url('/static/fonts/inter-500.woff2') format('woff2');
}
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url('/static/fonts/inter-600.woff2') format('woff2');
}
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('/static/fonts/inter-700.woff2') format('woff2');
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

2
src/webui/static/js/d3.v7.min.js vendored Normal file

File diff suppressed because one or more lines are too long

8
src/webui/static/js/plotly.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -4,7 +4,7 @@
{% block title %}Author Network — IETF Draft Analyzer{% endblock %}
{% block extra_head %}
<script src="https://d3js.org/d3.v7.min.js"></script>
<script src="/static/js/d3.v7.min.js"></script>
<style>
#networkSvg {
width: 100%;

View File

@@ -4,10 +4,9 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}IETF Draft Analyzer{% endblock %}</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.plot.ly/plotly-2.35.0.min.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
<script src="/static/js/tailwind.js"></script>
<script src="/static/js/plotly.min.js"></script>
<link rel="stylesheet" href="/static/css/fonts.css">
<script>
tailwind.config = {
darkMode: 'class',
@@ -15,7 +14,7 @@
extend: {
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
mono: ['JetBrains Mono', 'monospace'],
mono: ['ui-monospace', 'SFMono-Regular', 'Menlo', 'Consolas', 'monospace'],
},
}
}
@@ -135,8 +134,12 @@
</a>
</div>
</nav>
<div class="p-4 border-t border-slate-800 text-xs text-slate-600">
IETF Draft Analyzer v0.3
<div class="p-4 border-t border-slate-800 text-xs text-slate-600 space-y-1">
<div>IETF Draft Analyzer v0.3</div>
<div class="flex gap-3">
<a href="/impressum" class="hover:text-slate-400 transition">Impressum</a>
<a href="/datenschutz" class="hover:text-slate-400 transition">Datenschutz</a>
</div>
</div>
</aside>

View File

@@ -0,0 +1,127 @@
{% extends "base.html" %}
{% set active_page = "datenschutz" %}
{% block title %}Datenschutzerklaerung — IETF Draft Analyzer{% endblock %}
{% block content %}
<div class="max-w-3xl">
<h1 class="text-2xl font-bold text-white mb-6">Datenschutzerklaerung</h1>
<div class="prose prose-invert prose-sm max-w-none space-y-6 text-slate-300">
<!-- 1. Verantwortlicher -->
<div class="bg-slate-900/60 rounded-xl border border-slate-800 p-6 space-y-4">
<h2 class="text-lg font-semibold text-white">1. Verantwortlicher</h2>
<p>
Verantwortlich fuer die Datenverarbeitung auf dieser Website ist:<br><br>
Christian Nennemann<br>
Maillingerstrasse 30<br>
80636 Muenchen<br>
E-Mail: kontakt@nennemann.de
</p>
</div>
<!-- 2. Hosting -->
<div class="bg-slate-900/60 rounded-xl border border-slate-800 p-6 space-y-4">
<h2 class="text-lg font-semibold text-white">2. Hosting</h2>
<p>
Diese Website wird gehostet bei Hetzner Online GmbH, Industriestr. 25, 91710 Gunzenhausen, Deutschland. Beim Besuch dieser Website erfasst der Hosting-Anbieter
automatisch Informationen in sogenannten Server-Logfiles. Diese umfassen:
</p>
<ul class="list-disc list-inside space-y-1 text-slate-400">
<li>Besuchte Seite (URL)</li>
<li>Uhrzeit und Datum des Zugriffs</li>
<li>Menge der gesendeten Daten in Byte</li>
<li>Referrer-URL (zuvor besuchte Seite)</li>
<li>Verwendeter Browser und Betriebssystem</li>
<li>IP-Adresse (ggf. anonymisiert)</li>
</ul>
<p>
Die Verarbeitung erfolgt gemaess Art. 6 Abs. 1 lit. f DSGVO auf Basis des berechtigten Interesses
an der Sicherstellung eines stoerungsfreien Betriebs der Website. Server-Logfiles werden nach
14 Tagen automatisch geloescht.
</p>
</div>
<!-- 3. Keine Cookies -->
<div class="bg-slate-900/60 rounded-xl border border-slate-800 p-6 space-y-4">
<h2 class="text-lg font-semibold text-white">3. Cookies</h2>
<p>
Diese Website verwendet <strong class="text-white">keine Cookies</strong>. Es werden weder
eigene Cookies noch Cookies von Drittanbietern gesetzt. Ein Cookie-Consent-Banner ist daher
nicht erforderlich.
</p>
</div>
<!-- 4. Keine externen Ressourcen -->
<div class="bg-slate-900/60 rounded-xl border border-slate-800 p-6 space-y-4">
<h2 class="text-lg font-semibold text-white">4. Externe Ressourcen</h2>
<p>
Diese Website laedt <strong class="text-white">keine Ressourcen von externen Servern</strong>.
Alle Schriftarten (Fonts), JavaScript-Bibliotheken und Stylesheets werden lokal von diesem
Server ausgeliefert. Beim Besuch dieser Website werden keine Verbindungen zu Google, CDN-Diensten
oder sonstigen Drittanbietern hergestellt.
</p>
<p>
Diese Website verlinkt auf externe Seiten (insbesondere den IETF Datatracker und den RFC Editor).
Beim Klick auf diese Links verlassen Sie diese Website und es gelten die
Datenschutzbestimmungen der jeweiligen Zielseiten.
</p>
</div>
<!-- 5. Keine Analyse-Tools -->
<div class="bg-slate-900/60 rounded-xl border border-slate-800 p-6 space-y-4">
<h2 class="text-lg font-semibold text-white">5. Analyse-Tools und Tracking</h2>
<p>
Diese Website verwendet <strong class="text-white">keine Analyse-Tools</strong> (wie Google Analytics,
Matomo o.ae.) und kein Tracking. Es findet keine Auswertung des Nutzerverhaltens statt.
</p>
</div>
<!-- 6. Datenquellen -->
<div class="bg-slate-900/60 rounded-xl border border-slate-800 p-6 space-y-4">
<h2 class="text-lg font-semibold text-white">6. Dargestellte Daten</h2>
<p>
Die auf dieser Website dargestellten Informationen zu IETF Internet-Drafts stammen aus
oeffentlich zugaenglichen Quellen, insbesondere dem
<a href="https://datatracker.ietf.org" target="_blank" rel="noopener" class="text-blue-400 hover:text-blue-300">IETF Datatracker</a>.
Die Autorennamen und Organisationszugehoerigkeiten sind oeffentliche Informationen aus den
IETF-Dokumenten selbst.
</p>
<p>
Die auf dieser Website gezeigten Bewertungen und Analysen wurden automatisiert mit Hilfe von
KI-Modellen erstellt und stellen keine redaktionelle Meinungsaeusserung dar.
</p>
</div>
<!-- 7. Betroffenenrechte -->
<div class="bg-slate-900/60 rounded-xl border border-slate-800 p-6 space-y-4">
<h2 class="text-lg font-semibold text-white">7. Ihre Rechte (DSGVO)</h2>
<p>Sie haben gegenueber dem Verantwortlichen folgende Rechte hinsichtlich Ihrer personenbezogenen Daten:</p>
<ul class="list-disc list-inside space-y-1 text-slate-400">
<li>Recht auf Auskunft (Art. 15 DSGVO)</li>
<li>Recht auf Berichtigung (Art. 16 DSGVO)</li>
<li>Recht auf Loeschung (Art. 17 DSGVO)</li>
<li>Recht auf Einschraenkung der Verarbeitung (Art. 18 DSGVO)</li>
<li>Recht auf Widerspruch gegen die Verarbeitung (Art. 21 DSGVO)</li>
<li>Recht auf Datenuebertragbarkeit (Art. 20 DSGVO)</li>
</ul>
<p>
Sie haben zudem das Recht, sich bei einer Datenschutz-Aufsichtsbehoerde ueber die
Verarbeitung Ihrer personenbezogenen Daten zu beschweren.
</p>
</div>
<!-- 8. SSL -->
<div class="bg-slate-900/60 rounded-xl border border-slate-800 p-6 space-y-4">
<h2 class="text-lg font-semibold text-white">8. SSL-/TLS-Verschluesselung</h2>
<p>
Diese Website nutzt aus Sicherheitsgruenden eine SSL- bzw. TLS-Verschluesselung.
Eine verschluesselte Verbindung erkennen Sie daran, dass die Adresszeile des Browsers von
"http://" auf "https://" wechselt und an dem Schloss-Symbol in Ihrer Browserzeile.
</p>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,73 @@
{% extends "base.html" %}
{% set active_page = "impressum" %}
{% block title %}Impressum — IETF Draft Analyzer{% endblock %}
{% block content %}
<div class="max-w-3xl">
<h1 class="text-2xl font-bold text-white mb-6">Impressum</h1>
<div class="prose prose-invert prose-sm max-w-none space-y-6 text-slate-300">
<div class="bg-slate-900/60 rounded-xl border border-slate-800 p-6 space-y-4">
<h2 class="text-lg font-semibold text-white">Angaben gemaess &sect;5 TMG</h2>
<p>
Christian Nennemann<br>
Maillingerstrasse 30<br>
80636 Muenchen<br>
Deutschland
</p>
<h3 class="text-base font-semibold text-white">Kontakt</h3>
<p>
E-Mail: kontakt@nennemann.de
</p>
<h3 class="text-base font-semibold text-white">Verantwortlich fuer den Inhalt nach &sect;18 Abs. 2 MStV</h3>
<p>
Christian Nennemann<br>
Maillingerstrasse 30<br>
80636 Muenchen
</p>
</div>
<div class="bg-slate-900/60 rounded-xl border border-slate-800 p-6 space-y-4">
<h2 class="text-lg font-semibold text-white">Haftungsausschluss</h2>
<h3 class="text-base font-semibold text-white">Haftung fuer Inhalte</h3>
<p>
Die Inhalte dieser Seite wurden mit groesster Sorgfalt erstellt. Fuer die Richtigkeit, Vollstaendigkeit
und Aktualitaet der Inhalte kann jedoch keine Gewaehr uebernommen werden. Als Diensteanbieter bin ich
gemaess &sect;7 Abs.1 TMG fuer eigene Inhalte auf diesen Seiten nach den allgemeinen Gesetzen verantwortlich.
Nach &sect;&sect;8 bis 10 TMG bin ich als Diensteanbieter jedoch nicht verpflichtet, uebermittelte oder
gespeicherte fremde Informationen zu ueberwachen oder nach Umstaenden zu forschen, die auf eine
rechtswidrige Taetigkeit hinweisen.
</p>
<h3 class="text-base font-semibold text-white">Haftung fuer Links</h3>
<p>
Diese Seite enthaelt Links zu externen Webseiten Dritter, auf deren Inhalte ich keinen Einfluss habe.
Deshalb kann ich fuer diese fremden Inhalte auch keine Gewaehr uebernehmen. Fuer die Inhalte der
verlinkten Seiten ist stets der jeweilige Anbieter oder Betreiber der Seiten verantwortlich. Die
verlinkten Seiten wurden zum Zeitpunkt der Verlinkung auf moegliche Rechtsverstoesse ueberprueft.
Rechtswidrige Inhalte waren zum Zeitpunkt der Verlinkung nicht erkennbar. Eine permanente inhaltliche
Kontrolle der verlinkten Seiten ist jedoch ohne konkrete Anhaltspunkte einer Rechtsverletzung nicht
zumutbar. Bei Bekanntwerden von Rechtsverletzungen werde ich derartige Links umgehend entfernen.
</p>
<h3 class="text-base font-semibold text-white">Urheberrecht</h3>
<p>
Die durch den Seitenbetreiber erstellten Inhalte und Werke auf diesen Seiten unterliegen dem deutschen
Urheberrecht. Die Vervielfaeltigung, Bearbeitung, Verbreitung und jede Art der Verwertung ausserhalb der
Grenzen des Urheberrechtes beduerfen der schriftlichen Zustimmung des jeweiligen Autors bzw. Erstellers.
Downloads und Kopien dieser Seite sind nur fuer den privaten, nicht kommerziellen Gebrauch gestattet.
</p>
<p>
Die auf dieser Seite dargestellten IETF Internet-Drafts sind oeffentliche Dokumente der IETF
(Internet Engineering Task Force) und unterliegen den jeweiligen IETF-Lizenzbedingungen.
Die hier gezeigten Analysen, Bewertungen und Zusammenfassungen sind eigenstaendige redaktionelle
Leistungen.
</p>
</div>
</div>
</div>
{% endblock %}