UX fix from user feedback: previously the app only showed an "Entsperren" form, leaving first-time users without any passphrase confused. The page now loads with two distinct pre-screens decided by an initial API call: - empty DB -> "Willkommen" setup form: new passphrase, typed twice, minimum 8 characters, with no-reset warning - existing ciphertext records -> unlock form as before 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
crushdb – verschlüsselte Datensätze zwischen Personen
Sichere Datenbank für Transaktionen zwischen zwei Personen (Person A, Person B, Timestamp-Start, Timestamp-Ende, Aktion).
Alle Datensätze werden im Browser verschlüsselt (XChaCha20-Poly1305, Schlüsselableitung per Argon2id aus der Passphrase). Der Server sieht ausschließlich Chiffretext – auch bei vollständiger Serverkompromittierung bleiben die Inhalte ohne Passphrase vertraulich.
Starten (HTTP; TLS über Reverse Proxy)
python3 -m venv venv
./venv/bin/pip install -r requirements.txt
./venv/bin/python run.py
# → http://127.0.0.1:8085
Die App lauscht auf dem lokalen HTTP-Port (default 127.0.0.1:8085,
überschreibbar via HOST/PORT). Ein vertrauenswürdiger Reverse Proxy
(nginx, caddy, …) beendet HTTPS und reicht intern an die App weiter.
Die App selbst muss von außen nicht erreichbar sein.
Per systemd laufen lassen
Ein fertiges Unit-File liegt in deploy/crushdb.service (Reinheit:
nur instance/ schreibbar, keine Capabilities, Restart on failure).
Nach dem Kopieren nach /etc/systemd/system/ und daemon-reload
startet systemctl enable --now crushdb die App dauerhaft.
Tests
./venv/bin/python -m pytest backend/test_integrity.py -v # Integrität/Replay
node .e2e.mjs # optional: End-to-End (siehe unten)
Architektur
| Komponente | Datei | Aufgabe |
|---|---|---|
| Speicher | backend/storage.py |
SQLite, speichert nur Chiffretext (uuid, ciphertext, nonce, salt, version) |
| API | backend/app.py |
Flask REST API, Validierung nur von Form/Größe, Versions-Konfliktprüfung |
| Krypto (Client) | backend/static/crypto.js |
Argon2id-KDF + XChaCha20-Poly1305, uuid+salt als AEAD-AAD gebunden |
| UI | backend/static/ui.js + index.html/style.css |
Tabelle, Erstellen, Bearbeiten, Löschen; Passphrase bleibt im RAM |
| Server | run.py |
HTTP intern hinter Reverse Proxy, DB-Init |
Sicherheitsmodell
- Passphrase → Argon2id (t=2, m=16 MiB) → 256-Bit-Sitzungsschlüssel, ausschließlich im Browser/im Arbeitsspeicher; niemals am Server.
- Jeder Datensatz: eigene zufällige 16-Byte-Salt + 24-Byte-Nonce. uuid + salt sind als AEAD-Associated-Data gebunden – Vertauschen oder Um-Salten wird beim Entschlüsseln sicher erkannt.
- Monotoner Versionszähler pro Datensatz: veraltete Updates/Deletes
(Replay alter Stände) →
409, Duplikate →409. - Klartexte werden clientseitig nie persistiert; beim Sperren/Beenden
wird der Schlüssel verworfen (
wipeKey). - HTTPS wird außen vom vertrauenswürdigen Reverse Proxy beendet (nginx/caddy/…); die App lauscht nur intern auf HTTP.
Bekannte Grenzen
- Datenverlust (Löschen/Überschreiben) durch Angreifer bleibt möglich – Vertraulichkeit ist geschützt, Verfügbarkeit nicht.
- Backups der SQLite-Datei enthalten ausschließlich Chiffretext.
- Backups des Passphrasen-Verlusts = Datenverlust (by design).
Siehe spezification.txt für die Anforderungen.