Big Sweep: Security + Race-Conditions + Tests + DSGVO + A11y, SW by-v1095
SECURITY (auth.py, routes/auth.py, database.py, main.py) - JWT bekommt jti; Logout trägt in neue jwt_blacklist-Tabelle ein, decode_token() prüft → server-side Invalidierung - JWT-Expiry default 30 → 7 Tage (ENV JWT_EXPIRY_DAYS überschreibt) - Sliding-Refresh-Middleware: erneuert Cookie wenn >50% verbraucht (Schwelle via JWT_REFRESH_FRACTION, Default 2) - Login-Lockout in DB-Tabelle login_attempts (5 Versuche / 15 Min, überlebt Container-Restart) — alte In-Memory-Lockouts ersetzt - SMTP-Versand: alle 'except: pass' durch logger.exception ersetzt; Fehlversuche landen in failed_emails-Tabelle für späteres Retry - Referral-Counter Race gefixt: UPDATE partner_codes SET uses=uses+1 ... WHERE uses<max_uses RETURNING — atomar statt SELECT+UPDATE RACE CONDITIONS (routes/invoices.py, database.py) - Neue invoice_counters-Tabelle für atomare Nummernvergabe - _next_invoice_number nutzt BEGIN IMMEDIATE + atomares UPDATE - Funktioniert für RG- und ST-Prefixe (Stornorechnungen) - Race-Test verifiziert (5 Threads × 20 Calls = 100 eindeutige Nummern) VERSION + TESTS + ERROR-DIGEST (VERSION, Makefile, tests/, scheduler.py) - Neue VERSION-Datei (Single Source of Truth) — main.py liest beim Startup - Makefile-Target 'make bump' propagiert in sw.js, app.js, index.html - Makefile-Target 'make test' setzt venv auf, läuft pytest - 19 Smoke-Tests in tests/ (health, auth, diary, invoice) — alle grün - Scheduler: täglicher _job_error_digest um 06:30 → schickt Error- Zusammenfassung an ADMIN_EMAIL (still wenn keine Errors) DSGVO + A11Y + ERSTE-HILFE - landing.html: 'HTML und ODS' → 'JSON' (tatsächlich implementiert) - datenschutz.js: Sektion Account-Löschung erweitert (sofort gelöscht / anonymisiert / 10 Jahre für Rechnungen) - erste-hilfe.js: prominentes Warning-Banner oben (ersetzt keine Tierarzt-Beratung); Notfallnummern gruppiert nach Land, TODO-Platz- halter für AT-Uni-Klinik, CH Tox Info Suisse, CH Tierspital Zürich - ui.js Modal: ESC schließt, Focus-Trap, Auto-Focus erstes Element, Restore Focus auf vorigen Caller - impressum.js Kontaktformular: Labels mit for=cf-name etc. NEUE DB-TABELLEN (idempotent via CREATE TABLE IF NOT EXISTS) - jwt_blacklist, login_attempts, failed_emails, invoice_counters NEUE ENV-VARS - JWT_REFRESH_FRACTION (Default 2) - JWT_EXPIRY_DAYS Default geändert (30 → 7)
This commit is contained in:
parent
6224044654
commit
9394bab1fb
23 changed files with 1208 additions and 78 deletions
|
|
@ -15,10 +15,35 @@ window.Page_erste_hilfe = (() => {
|
|||
// ----------------------------------------------------------------
|
||||
// DATA
|
||||
// ----------------------------------------------------------------
|
||||
const NOTFALLNUMMERN = [
|
||||
{ label: 'Tiergiftzentrale München', tel: '+4989 19240', display: '+49 89 19240' },
|
||||
{ label: 'Tiergiftzentrale Berlin', tel: '+4930 19240', display: '+49 30 19240' },
|
||||
{ label: 'Tiergiftzentrale Wien', tel: '+431 4064343', display: '+43 1 4064343' },
|
||||
// Liste von Notrufen, nach Land gruppiert.
|
||||
// Struktur ist erweiterbar: weitere Länder/Städte einfach an die jeweilige
|
||||
// Gruppe anhängen. Einträge mit tel:null werden als "TODO: Nummer einfügen"
|
||||
// dargestellt — Rendering kümmert sich um Optik und tel: -Link.
|
||||
const NOTFALLNUMMERN_GRUPPEN = [
|
||||
{
|
||||
land: 'Deutschland',
|
||||
flag: 'DE',
|
||||
eintraege: [
|
||||
{ label: 'Tiergiftzentrale München', tel: '+4989 19240', display: '+49 89 19240' },
|
||||
{ label: 'Tiergiftzentrale Berlin', tel: '+4930 19240', display: '+49 30 19240' },
|
||||
],
|
||||
},
|
||||
{
|
||||
land: 'Österreich',
|
||||
flag: 'AT',
|
||||
eintraege: [
|
||||
{ label: 'Vergiftungsinformationszentrale Wien', tel: '+431 4064343', display: '+43 1 4064343' },
|
||||
{ label: 'Veterinärmedizinische Universität Wien (Notfallklinik)', tel: null, display: 'TODO: Nummer einfügen' },
|
||||
],
|
||||
},
|
||||
{
|
||||
land: 'Schweiz',
|
||||
flag: 'CH',
|
||||
eintraege: [
|
||||
{ label: 'Tox Info Suisse (Tiergiftnotruf)', tel: null, display: 'TODO: Nummer einfügen (ggf. 145)' },
|
||||
{ label: 'Tierspital Zürich', tel: null, display: 'TODO: Nummer einfügen' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const SCHNELL = [
|
||||
|
|
@ -213,6 +238,7 @@ window.Page_erste_hilfe = (() => {
|
|||
_container.innerHTML = `
|
||||
<div id="eh-wrap" style="padding-bottom:var(--space-8)">
|
||||
|
||||
${_renderDisclaimer()}
|
||||
${_renderNotfallbanner()}
|
||||
${_renderSchnell()}
|
||||
|
||||
|
|
@ -244,13 +270,51 @@ window.Page_erste_hilfe = (() => {
|
|||
_activateTab('lebensgefahr');
|
||||
}
|
||||
|
||||
function _renderDisclaimer() {
|
||||
return `
|
||||
<div role="alert" style="display:flex;align-items:flex-start;gap:var(--space-3);
|
||||
background:#fef3c7;color:#78350f;border-left:4px solid #d97706;
|
||||
border-radius:var(--radius-md);padding:var(--space-3) var(--space-4);
|
||||
margin-bottom:var(--space-4);font-size:var(--text-sm);line-height:1.5">
|
||||
<svg class="ph-icon" aria-hidden="true" style="flex-shrink:0;color:#d97706;width:22px;height:22px;margin-top:2px"><use href="/icons/phosphor.svg#warning"></use></svg>
|
||||
<div>
|
||||
<strong style="display:block;margin-bottom:2px">Diese Hinweise ersetzen keine tierärztliche Beratung.</strong>
|
||||
Im Notfall sofort einen Tierarzt aufsuchen!
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function _renderNotfallbanner() {
|
||||
const nums = NOTFALLNUMMERN.map(n => `
|
||||
<a href="tel:${n.tel}"
|
||||
style="display:flex;align-items:center;gap:var(--space-2);color:#fff;text-decoration:none;font-size:var(--text-sm);padding:var(--space-2) var(--space-3);background:rgba(255,255,255,0.15);border-radius:var(--radius-md)">
|
||||
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#phone"></use></svg>
|
||||
<span><strong>${n.label}</strong><br>${n.display}</span>
|
||||
</a>
|
||||
const renderEintrag = (n) => {
|
||||
// Eintrag mit verfügbarer Nummer → tel:-Link
|
||||
if (n.tel) {
|
||||
return `
|
||||
<a href="tel:${n.tel}"
|
||||
style="display:flex;align-items:center;gap:var(--space-2);color:#fff;text-decoration:none;font-size:var(--text-sm);padding:var(--space-2) var(--space-3);background:rgba(255,255,255,0.15);border-radius:var(--radius-md)">
|
||||
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#phone"></use></svg>
|
||||
<span><strong>${n.label}</strong><br>${n.display}</span>
|
||||
</a>
|
||||
`;
|
||||
}
|
||||
// Eintrag ohne Nummer → ausgegrauter Platzhalter
|
||||
return `
|
||||
<div style="display:flex;align-items:center;gap:var(--space-2);color:rgba(255,255,255,0.85);font-size:var(--text-sm);padding:var(--space-2) var(--space-3);background:rgba(255,255,255,0.08);border-radius:var(--radius-md);border:1px dashed rgba(255,255,255,0.35)">
|
||||
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#phone"></use></svg>
|
||||
<span><strong>${n.label}</strong><br><em style="font-style:normal;opacity:.85">${n.display}</em></span>
|
||||
</div>
|
||||
`;
|
||||
};
|
||||
|
||||
const gruppen = NOTFALLNUMMERN_GRUPPEN.map(g => `
|
||||
<div>
|
||||
<div style="font-size:var(--text-xs);font-weight:var(--weight-semibold);color:rgba(255,255,255,0.85);text-transform:uppercase;letter-spacing:0.04em;margin-bottom:var(--space-1)">
|
||||
${g.flag} · ${g.land}
|
||||
</div>
|
||||
<div style="display:flex;flex-direction:column;gap:var(--space-2)">
|
||||
${g.eintraege.map(renderEintrag).join('')}
|
||||
</div>
|
||||
</div>
|
||||
`).join('');
|
||||
|
||||
return `
|
||||
|
|
@ -259,8 +323,8 @@ window.Page_erste_hilfe = (() => {
|
|||
<svg class="ph-icon" style="width:20px;height:20px" aria-hidden="true"><use href="/icons/phosphor.svg#siren"></use></svg>
|
||||
Tiergiftzentralen — jetzt anrufen
|
||||
</div>
|
||||
<div style="display:flex;flex-direction:column;gap:var(--space-2)">
|
||||
${nums}
|
||||
<div style="display:flex;flex-direction:column;gap:var(--space-3)">
|
||||
${gruppen}
|
||||
</div>
|
||||
<p style="margin-top:var(--space-3);font-size:var(--text-xs);color:rgba(255,255,255,0.8)">
|
||||
Tierärztlicher Notdienst: Über die Tierarztsuche in der Banyaro-Karte
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue