SHA256
feat: browser UI – unlock, table view, create/edit/delete with client-side crypto
Vanilla HTML/CSS/JS frontend served by Flask: - Unlock screen: passphrase -> Argon2id session key, held in memory only (never sent to the server); "Sperren" wipes key and DOM rows. - Records table (Person A/B, start/end, action) rendered via textContent only (no HTML injection); undecryptable rows are flagged. - Create/edit modal encrypts payloads with XChaCha20-Poly1305 before any network call; updates carry the server version (optimistic lock, conflict toast on 409); delete fetches current version first. 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>crushdb</title>
|
||||
<link rel="stylesheet" href="/static/style.css" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>crushdb</h1>
|
||||
<p class="tagline">Verschlüsselte Datensätze zwischen zwei Personen</p>
|
||||
|
||||
<section id="flash" class="flash" aria-live="polite"></section>
|
||||
|
||||
<!-- unlock screen: passphrase stays in memory only -->
|
||||
<section id="unlock">
|
||||
<form id="unlock-form" autocomplete="off">
|
||||
<label for="passphrase">Passphrase</label>
|
||||
<input
|
||||
type="password"
|
||||
id="passphrase"
|
||||
autocomplete="off"
|
||||
required
|
||||
placeholder="Passphrase eingeben …"
|
||||
/>
|
||||
<button type="submit">Entsperren</button>
|
||||
<p class="hint">
|
||||
Die Passphrase verlässt niemals deinen Browser. Sie wird per
|
||||
Argon2id lokal abgeleitet und nur im Arbeitsspeicher gehalten.
|
||||
</p>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<!-- main app, hidden until unlocked -->
|
||||
<section id="app" hidden>
|
||||
<div class="toolbar">
|
||||
<button id="new-btn" type="button">+ Neuer Datensatz</button>
|
||||
<button id="lock-btn" type="button">Sperren</button>
|
||||
</div>
|
||||
|
||||
<table id="records">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Person A</th>
|
||||
<th>Person B</th>
|
||||
<th>Start</th>
|
||||
<th>Ende</th>
|
||||
<th>Aktion</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<!-- create/edit modal -->
|
||||
<div id="editor-backdrop" hidden>
|
||||
<form id="editor" autocomplete="off">
|
||||
<h2 id="editor-title">Neuer Datensatz</h2>
|
||||
<label>Person A
|
||||
<input id="f-persona" type="text" required maxlength="120" />
|
||||
</label>
|
||||
<label>Person B
|
||||
<input id="f-personb" type="text" required maxlength="120" />
|
||||
</label>
|
||||
<label>Start (optional)
|
||||
<input id="f-tsstart" type="datetime-local" />
|
||||
</label>
|
||||
<label>Ende (optional)
|
||||
<input id="f-tsend" type="datetime-local" />
|
||||
</label>
|
||||
<label>Aktion
|
||||
<input id="f-action" type="text" required maxlength="500" />
|
||||
</label>
|
||||
<div class="actions">
|
||||
<button type="submit">Speichern</button>
|
||||
<button type="button" id="editor-cancel">Abbrechen</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script type="module" src="/static/ui.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user