fix: remove CDN swagger UI, revert CSP, translate apiToken i18n keys to German

- Delete public/doc-assets/swagger.html and swagger-init.js (CDN dependency violates project constraints)
- Remove /docs route from server/index.js
- Revert styleSrc and fontSrc in CSP to not include cdn.jsdelivr.net
- Translate all 22 settings.apiToken* keys in de.json from English to German

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Ulas Kalayci
2026-04-26 08:57:21 +02:00
parent a1b1a71227
commit cd68bbfae7
5 changed files with 24 additions and 75 deletions
View File
-11
View File
@@ -1,11 +0,0 @@
window.addEventListener('DOMContentLoaded', () => {
window.ui = window.SwaggerUIBundle({
url: '/openapi.json',
dom_id: '#swagger-ui',
deepLinking: true,
docExpansion: 'list',
persistAuthorization: true,
displayRequestDuration: true,
filter: true,
});
});
-37
View File
@@ -1,37 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Oikos API Docs</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css">
<style>
body { margin: 0; background: #f6f8fb; }
.docs-topbar {
display: flex;
gap: 12px;
align-items: center;
justify-content: space-between;
padding: 14px 20px;
background: #0f172a;
color: #fff;
font: 14px/1.4 system-ui, sans-serif;
}
.docs-links { display: flex; gap: 12px; flex-wrap: wrap; }
.docs-links a { color: #93c5fd; text-decoration: none; }
.docs-links a:hover { text-decoration: underline; }
</style>
<script src="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js" defer></script>
<script src="/doc-assets/swagger-init.js" defer></script>
</head>
<body>
<header class="docs-topbar">
<strong>Oikos API Documentation</strong>
<nav class="docs-links">
<a href="/openapi.json" target="_blank" rel="noreferrer">openapi.json</a>
<a href="/openapi.json?download=1">Download JSON</a>
</nav>
</header>
<div id="swagger-ui"></div>
</body>
</html>
+22 -22
View File
@@ -630,28 +630,28 @@
"currencyLabel": "Währung", "currencyLabel": "Währung",
"currencyHint": "Legt die Währung für den gesamten Budget-Bereich fest.", "currencyHint": "Legt die Währung für den gesamten Budget-Bereich fest.",
"currencySaved": "Währung gespeichert.", "currencySaved": "Währung gespeichert.",
"apiTokensTitle": "API Tokens", "apiTokensTitle": "API-Tokens",
"apiTokensCardTitle": "Access Tokens", "apiTokensCardTitle": "Zugriffstoken",
"apiTokensHint": "Create API tokens for external integrations. The full token is shown only once after creation.", "apiTokensHint": "Erstelle API-Tokens für externe Integrationen. Der vollständige Token wird nach der Erstellung nur einmal angezeigt.",
"apiTokenNameLabel": "Token name", "apiTokenNameLabel": "Tokenname",
"apiTokenExpiresLabel": "Expiration date", "apiTokenExpiresLabel": "Ablaufdatum",
"apiTokenExpiresHint": "Leave empty to create a token without expiration.", "apiTokenExpiresHint": "Leer lassen, um einen Token ohne Ablaufdatum zu erstellen.",
"apiTokenCreatedLabel": "New API token", "apiTokenCreatedLabel": "Neuer API-Token",
"apiTokenCreatedHint": "Store this token securely. It cannot be shown again.", "apiTokenCreatedHint": "Speichere diesen Token sicher. Er kann nicht erneut angezeigt werden.",
"apiTokenCreate": "Create token", "apiTokenCreate": "Token erstellen",
"apiTokenInvalidExpiration": "Please enter a valid expiration date.", "apiTokenInvalidExpiration": "Bitte gib ein gültiges Ablaufdatum ein.",
"apiTokenCreatedToast": "API token created.", "apiTokenCreatedToast": "API-Token erstellt.",
"apiTokenRevokedToast": "API token revoked.", "apiTokenRevokedToast": "API-Token widerrufen.",
"apiTokenRevokeConfirm": "Revoke API token \"{{name}}\"?", "apiTokenRevokeConfirm": "API-Token \"{{name}}\" widerrufen?",
"apiTokenRevoke": "Revoke token", "apiTokenRevoke": "Token widerrufen",
"apiTokenRevoked": "Revoked", "apiTokenRevoked": "Widerrufen",
"apiTokenExpired": "Expired", "apiTokenExpired": "Abgelaufen",
"apiTokenActive": "Active", "apiTokenActive": "Aktiv",
"apiTokenPrefix": "Prefix", "apiTokenPrefix": "Präfix",
"apiTokenExpires": "Expires", "apiTokenExpires": "Läuft ab",
"apiTokenNeverExpires": "No expiration", "apiTokenNeverExpires": "Kein Ablaufdatum",
"apiTokenLastUsed": "Last used", "apiTokenLastUsed": "Zuletzt verwendet",
"apiTokenNeverUsed": "Never used", "apiTokenNeverUsed": "Nie verwendet",
"ics": { "ics": {
"title": "ICS-Abonnements", "title": "ICS-Abonnements",
"add": "Abonnement hinzufügen", "add": "Abonnement hinzufügen",
+2 -5
View File
@@ -57,10 +57,10 @@ app.use(helmet({
// Alpine.js CDN (optional, falls verwendet) // Alpine.js CDN (optional, falls verwendet)
'https://cdn.jsdelivr.net', 'https://cdn.jsdelivr.net',
], ],
styleSrc: ["'self'", "'unsafe-inline'", 'https://cdn.jsdelivr.net'], styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", 'data:'], imgSrc: ["'self'", 'data:'],
connectSrc: ["'self'"], connectSrc: ["'self'"],
fontSrc: ["'self'", 'data:', 'https://cdn.jsdelivr.net'], fontSrc: ["'self'"],
objectSrc: ["'none'"], objectSrc: ["'none'"],
frameSrc: ["'none'"], frameSrc: ["'none'"],
// upgrade-insecure-requests nur mit HTTPS aktivieren // upgrade-insecure-requests nur mit HTTPS aktivieren
@@ -176,9 +176,6 @@ function sendOpenApi(req, res) {
app.get('/api/v1/openapi.json', sendOpenApi); app.get('/api/v1/openapi.json', sendOpenApi);
app.get('/openapi.json', sendOpenApi); app.get('/openapi.json', sendOpenApi);
app.get('/docs', (_req, res) => {
res.sendFile(path.join(import.meta.dirname, '..', 'public', 'doc-assets', 'swagger.html'));
});
// Alle weiteren API-Routen erfordern Authentifizierung + CSRF-Schutz // Alle weiteren API-Routen erfordern Authentifizierung + CSRF-Schutz
app.use('/api/v1', requireAuth); app.use('/api/v1', requireAuth);