modified: web/app.py

modified:   web/templates/privacy_policy.html
This commit is contained in:
simon
2026-04-15 11:55:22 +02:00
parent a45dd74083
commit 2f13b0a5c6
2 changed files with 37 additions and 3 deletions

View File

@@ -118,7 +118,7 @@ def create_app() -> Flask:
resp.headers.setdefault("X-Content-Type-Options", "nosniff") resp.headers.setdefault("X-Content-Type-Options", "nosniff")
resp.headers.setdefault("X-Frame-Options", "DENY") resp.headers.setdefault("X-Frame-Options", "DENY")
resp.headers.setdefault("Referrer-Policy", "strict-origin-when-cross-origin") resp.headers.setdefault("Referrer-Policy", "strict-origin-when-cross-origin")
resp.headers.setdefault("Content-Security-Policy", "default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; img-src 'self' data:; font-src 'self' https://cdn.jsdelivr.net; connect-src 'self'; frame-ancestors 'none';") resp.headers.setdefault("Content-Security-Policy", "default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; img-src 'self' data: https://minotar.net; font-src 'self' https://cdn.jsdelivr.net; connect-src 'self'; frame-ancestors 'none';")
return resp return resp
@app.route("/privacy-policy") @app.route("/privacy-policy")
@@ -126,8 +126,9 @@ def create_app() -> Flask:
from config import Config from config import Config
return render_template( return render_template(
"privacy_policy.html", "privacy_policy.html",
last_updated="April 14, 2026", last_updated="April 15, 2026",
invite_expiry_hours=Config.INVITE_EXPIRY_HOURS, invite_expiry_hours=Config.INVITE_EXPIRY_HOURS,
audit_retention_days=Config.AUDIT_LOG_RETENTION_DAYS,
) )
@app.errorhandler(400) @app.errorhandler(400)

View File

@@ -91,7 +91,28 @@
session ends. session ends.
</p> </p>
<h3 class="fw-semibold">3.5 Server Log Files</h3> <h3 class="fw-semibold">3.5 Panel Audit Log</h3>
<p>
MCLogger maintains an <strong>internal audit log</strong> in the panel database that records
security-relevant and data-access events. Each entry contains:
</p>
<ul>
<li>The panel user who performed the action (username and internal ID)</li>
<li>The action taken (e.g. login, logout, member role change, viewing player data)</li>
<li>The affected entity (e.g. a Minecraft player's UUID when player profile pages are accessed)</li>
<li>The IP address of the panel user at the time of the action</li>
<li>A UTC timestamp</li>
</ul>
<p>
This includes access to pages that display Minecraft player data (player list, player detail,
chat history, commands, deaths, block events, sessions, proxy events). The log therefore
records <em>who</em> in the panel team accessed <em>which</em> player's data and <em>when</em>,
providing an accountable audit trail as required by Art. 32 GDPR.
Audit log entries are automatically deleted after {{ audit_retention_days }} days
(configurable by the operator).
</p>
<h3 class="fw-semibold">3.6 Server Log Files</h3>
<p> <p>
The web server (gunicorn) may write standard HTTP access logs containing IP The web server (gunicorn) may write standard HTTP access logs containing IP
addresses, request paths, and timestamps. These logs are used for operational addresses, request paths, and timestamps. These logs are used for operational
@@ -128,6 +149,11 @@
<td>Security monitoring and error diagnosis</td> <td>Security monitoring and error diagnosis</td>
<td>Art. 6(1)(f) — legitimate interest</td> <td>Art. 6(1)(f) — legitimate interest</td>
</tr> </tr>
<tr>
<td>Panel audit log (incl. IP addresses of panel users)</td>
<td>Accountability for access to personal data; security incident traceability</td>
<td>Art. 6(1)(c) — legal obligation / Art. 32 GDPR (security of processing)</td>
</tr>
</tbody> </tbody>
</table> </table>
@@ -136,6 +162,7 @@
<li><strong>Minecraft logs</strong> are retained as long as the server operator deems necessary for moderation purposes.</li> <li><strong>Minecraft logs</strong> are retained as long as the server operator deems necessary for moderation purposes.</li>
<li><strong>Panel accounts</strong> are retained until manually deleted by a site administrator.</li> <li><strong>Panel accounts</strong> are retained until manually deleted by a site administrator.</li>
<li><strong>Invite tokens</strong> expire after {{ invite_expiry_hours }} hours and are never sent to third parties beyond the intended recipient.</li> <li><strong>Invite tokens</strong> expire after {{ invite_expiry_hours }} hours and are never sent to third parties beyond the intended recipient.</li>
<li><strong>Panel audit log entries</strong> are automatically deleted after {{ audit_retention_days }} days. This includes IP address data logged on data-access events.</li>
<li><strong>Server access logs</strong> are typically rotated within 30 days.</li> <li><strong>Server access logs</strong> are typically rotated within 30 days.</li>
</ul> </ul>
@@ -145,6 +172,12 @@
parties. All data remains within the infrastructure controlled by the server operator. parties. All data remains within the infrastructure controlled by the server operator.
No third-party analytics services, advertising networks, or tracking pixels are used. No third-party analytics services, advertising networks, or tracking pixels are used.
</p> </p>
<p>
Player head images are loaded from <strong>minotar.net</strong>, a public Minecraft avatar service.
Minotar may process the Minecraft username and your IP address as part of serving the image.
Please consult <a href="https://minotar.net" target="_blank" rel="noopener noreferrer">minotar.net</a>
for their privacy practices. If the image cannot be loaded, a local fallback placeholder is displayed.
</p>
<p> <p>
External resources loaded by the web interface (Bootstrap CSS/JS and Bootstrap Icons) External resources loaded by the web interface (Bootstrap CSS/JS and Bootstrap Icons)
are served from the jsDelivr CDN (<code>cdn.jsdelivr.net</code>). jsDelivr may process are served from the jsDelivr CDN (<code>cdn.jsdelivr.net</code>). jsDelivr may process