# Checkliste bis zum Livegang

Stand: 30. Juli 2026, 23:30. Alles unten ist gemessen, nicht geschätzt.

**`https://cloakdrop.com` ist erreichbar und steht hinter der PIN.** Zertifikat
von Google Trust Services, gueltig bis 28.10.2026, deckt Domain und alle
Unterdomains. `http` leitet mit 301 auf `https`. Die PIN steht in
`tasks/_gate-credentials.txt`.

---

## Erledigt (nichts mehr zu tun)

| | Beleg |
|---|---|
| Favicon in Blau, aus dem echten Logo statt aus der Maske | alle 8 Dateien `#0063fd`, live nachgemessen |
| PIN-Wand scharf, Production **und** Preview | `/`, `/about`, `/assets/*`, `/robots.txt`, `/sitemap.xml` → **401**; falsche PIN → 401; richtige PIN → 303 + Cookie |
| `/.well-known/` liegt frei | `security.txt` → 200, `/.well-knownx/…` → 401 (Gegenprobe im Test) |
| Zwei alte Deployments gelöscht | lieferten die Seite ohne PIN aus (200), jetzt **404** |
| `privacy.html` sagt das Cookie an | „No cookies" ersetzt, eigener Abschnitt *Cookies* |
| `deploy.md` berichtigt | `wrangler pages deploy .` entfernt — hätte `tasks/` samt PIN hochgeladen |
| `build_dist.py --offen` | Livegang ohne `functions/`, statt sich auf eine gelöschte Variable zu verlassen |
| `build_footer.py` wuchs bei jedem Lauf | zwei Leerzeilen je Durchgang, behoben |
| Ausgeliefertes = Arbeitsstand | vier Seiten byte-identisch gegengeprüft |
| Sicherheitskopfzeilen live | CSP, HSTS, X-Frame-Options DENY, nosniff, Referrer-Policy, Permissions-Policy, COOP/CORP |
| Quellstand gesichert | `Downloads\cloakdrop-sicherung-64a3f5d.zip`, 106 Dateien, **ohne** PIN-Datei |
| `abuse@` und `security@` zugestellt | fielen vorher auf den Boden |
| Impressum vorbereitet | `build_imprint.py` füllt 13 Felder + beide Vorreden, mit Platzhalterdaten durchgetestet |
| Notfallzettel | `tasks/notfall.md` |
| **Domain live** | `cloakdrop.com` und `www` → 401 PIN-Seite, Zertifikat steht, `http` → 301 |
| **Zonen-Schalter** | E-Mail-Verschleierung aus, Rocket Loader aus — an der echten Domain gemessen: 0 `/cdn-cgi`-Skripte, Adresse als Klartext |
| **DMARC** | `v=DMARC1; p=reject; rua=…` loest auf; SPF (`~all`), MX und DKIM unveraendert |
| **Abnahme aller 16 Seiten** | auf `cloakdrop.com`: 200, byte-identisch mit dem Bau, kein fremdes Skript |
| **Status-Board** | `status.cloakdrop.com` als eigener Worker mit eigenem Speicher: misst alle 5 Minuten, erste Messung 21:40 UTC, 104 ms |

---

## Was DU noch machen musst

Schritte 1 bis 3 (DNS, Zonen-Schalter, DMARC) sind erledigt und gemessen.

### 4 · Zwei-Faktor auf dem Cloudflare-Konto (5 Min.)

Profilsymbol oben rechts → **My Profile** → **Authentication** →
**Two-Factor Authentication** → per Authenticator-App, nicht SMS.
Recovery-Codes **ausdrucken**. Gemessen: heute ist 2FA aus. An diesem Konto
hängen Domain, Website, DNS und der Mailweg.

### 5 · Sicherung vom Laptop wegschaffen (2 Min.)

`Downloads\cloakdrop-sicherung-64a3f5d.zip` auf einen Stick oder in eine Cloud.
Es gibt keinen Git-Remote — ohne diese Kopie liegt alles nur auf einem Rechner.
Die PIN-Datei ist mit Absicht **nicht** darin.

### 6 · TLS-Schalter durchsehen (5 Min., wenn Zeit)

Domain → **SSL/TLS** → Overview: Modus `Full (strict)` oder `Automatic`,
**nie** `Flexible`. Edge Certificates: Always Use HTTPS **an**, Minimum TLS 1.2,
TLS 1.3 **an**, HSTS-Schalter **aus lassen** (der Header kommt aus `_headers`).

---

## Was dein Vater machen muss

### 7 · Impressumsdaten durchgeben

Vier Pflichtangaben: **Name**, **Rechtsform**, **ladungsfähige Anschrift**
(Postfach genügt nicht), **Telefonnummer**. Dazu die zuständige
Datenschutz-Aufsichtsbehörde seines Bundeslandes.

Vorlage: `tasks/_impressum-vorlage.txt`. Ausgefüllt nach `tasks/_impressum.txt`,
dann `python tasks/build_imprint.py`. Dauert danach zwei Minuten, nicht 45.

**Ohne diese vier Angaben darf die Seite nicht öffentlich stehen** (§ 5 DDG).

### 8 · Zielpostfach für die Post

Aktuell geht alles an `roman.grosz@icloud.com`. Empfangen ist unkritisch — die
Adresse ist nicht sichtbar. Sie wird sichtbar, sobald jemand **antwortet**.
Cloudflare → **Email** → **Email Routing** → **Destination addresses** →
neue Adresse anlegen und **Bestätigungsmail dort anklicken**, dann die drei
Regeln (`hello@`, `abuse@`, `security@`) umstellen.

### 9 · Registrar durchsehen

**Domain Registration** → **Manage Domains** → `cloakdrop.com`: Auto-Renew an,
Ablauf 30.07.2027. Und im Postfach die **ICANN-Bestätigungsmail** suchen und
anklicken — ohne sie sperrt die Registry die Domain nach 15 Tagen, und dann ist
auch `hello@cloakdrop.com` tot.

---

## Morgen, ab 15:45 — der Startablauf

| Zeit | Schritt | Wer |
|---|---|---|
| vorher | Impressumsdaten sind da, `build_imprint.py` gelaufen, `build_headers.py` + `verify_csp.py` grün | Claude |
| 15:45 | `python tasks/build_dist.py --offen` → muss **27 Dateien** melden (nicht 28) | Claude |
| 15:47 | `npx wrangler pages deploy dist --project-name=cloakdrop` | Claude |
| 15:48 | `npx wrangler secret delete GATE_PIN --config status-worker/wrangler.toml` — sonst bleibt das Status-Board hinter der PIN | Claude |
| 15:50 | `curl -s -o /dev/null -w "%{http_code}" https://cloakdrop.com/` → **200** | Claude |
| 15:52 | `https://cloakdrop.com/tasks/_gate-credentials.txt` → muss **404** sein | Claude |
| 15:55 | `https://cloakdrop.com/imprint` im Browser: Konsole leer, Mailadresse als Klartext | du |
| 16:00 | Ersten Link **an dich selbst** schicken, Vorschaukarte prüfen | du |
| 16:05 | Erst wenn die Karte stimmt: Link an andere | du |

Der Umweg über die eigene Chat-Notiz ist kein Zieren: Messenger holen die
Vorschaukarte **einmal** und behalten sie tagelang. Wird der erste Link
geteilt, während die Domain noch hakt, friert die leere Karte bei allen
Empfängern gleichzeitig ein.

---

## Erste Woche

- **CAA-Records** setzen — aber erst **nach** grünem Zertifikat, sonst sperrt
  man sich bei der nächsten Erneuerung selbst aus. `issue` **und** `issuewild`.
- ~~**HSTS** von `max-age=86400` auf ein Jahr~~ — am 31.07. erledigt, mit
  `includeSubDomains`. **Nicht** bei hstspreload.org einreichen — praktisch
  unumkehrbar, das bleibt so.
- Kalendereintrag **01.07.2027**: Domain läuft am 30.07.2027 ab.
- **Status-Board nach ein paar Tagen ansehen**: sobald 7 Tage gemessen sind,
  füllen sich die beiden leeren Kacheln von selbst. Bis dahin steht dort
  „noch nicht so lange gemessen" statt einer erfundenen Zahl.

---

## Nachtrag 31.07., nach der zweiten Testrunde

Umgesetzt und ausgeliefert, ohne dass du etwas tun musst:

- **Passwort auf einem Drop** — der meistgenannte Wunsch der Runde. Der
  Schlüssel wird mit 310.000 Runden PBKDF2 eingewickelt, bevor er in den Link
  geht. Wer nur den Link abfängt, hat nichts.
- **Hilfecenter entfernt.** Sechzehn Artikel, die dasselbe sagten wie die
  Fachseiten. Von siebzehn Seiten sind zwölf übrig.
- Fremde Domain im Einfügefeld wird benannt und abgewiesen; ein gekürzter
  Schlüssel wird als gekürzt gemeldet; die Übersicht nennt auf dem ersten
  Schirm keine Zahlen mehr.
- **`LICENSE`** (AGPL v3, vollständig) und **`README.md`** liegen im Baum,
  dazu `tasks/build_public.py`.

### Entschieden am 31.07.: kein Repository, keine Lizenz

Die Seite heißt jetzt „Read the code" statt „Open source" und verspricht keine
Veröffentlichung mehr. Der Grund ist kein Rückzieher, sondern eine Klarstellung:
die AGPL hätte Rechte weggegeben, die ohne Lizenz niemand hat. Ohne Lizenz gilt
das volle Urheberrecht — lesen und prüfen ja, weitergeben oder selbst betreiben
nein.

Was dabei erhalten bleibt, ist das einzige Argument, das das Produkt hat: der
Client ist eine einzige unminifizierte Datei und war immer vollständig lesbar.
`Strg+U` genügt. Das ist keine Konzession, das ist die Bauweise — und sie ist
der Grund, warum die Verschlüsselung überhaupt nachprüfbar ist.

`LICENSE` und `tasks/build_public.py` sind entfernt. Wenn du es dir anders
überlegst, stehen beide in Commit `61c5b31` und lassen sich zurückholen.

**Preis der Entscheidung, damit er benannt ist:** sechs von zehn Testern der
dritten Runde haben das fehlende Repository genannt, drei davon als Grund, das
Produkt nicht einzusetzen. Das bleibt so. Es ist eine Abwägung, keine Lösung.

### Weiterhin offen, weiterhin bei dir

1. **Die vier Impressumsangaben deines Vaters** — Name, Rechtsform,
   ladungsfähige Anschrift, Telefon. Ohne sie baut `--offen` nicht, und
   `build_public.py` baut auch nicht. Das ist Absicht.
2. 2FA auf dem Cloudflare-Konto (gemessen: aus).
3. Backup-ZIP vom Laptop herunter.
4. `hello@` / `abuse@` / `security@` weg von der privaten iCloud-Adresse.

---

## Nachtrag 31.07., abends — Testrunde 3 abgearbeitet

Zehn neue Personas, Schnitt 3,81, zehnmal „nein". 83 gemeldete Funde, davon
62 bestätigt, 12 teilweise, 9 Geschmacksfrage, **keiner widerlegt**. Bericht:
`tasks/kundentest3.md`.

Umgesetzt und ausgeliefert — Punkte 2 bis 13 und 16 der Rangfolge:

| Was | Nennungen | Beleg |
|---|---|---|
| Abbruch hinterlässt keine unsichtbaren Bruchstücke mehr | 10 | `verify_runde3.py` |
| „Download all" liefert ein ZIP statt zehn von vierzig Dateien | 8 | `verify_zip.py` |
| „Copy link again" trägt das Salz | 5 | `verify_runde3.py` |
| Hänger bei vollem Speicher abgefangen, Abbrechen-Knopf | 4 + 2 | `verify_runde3.py` |
| Browser-Bindung steht in der ersten Zeile von `/limits` | 10 | live geprüft |
| Vorspann widerspricht der Fehlermeldung nicht mehr | 2 | `verify_runde3.py` |
| Glossar auf dem Stand der App, Passwort und PBKDF2 drin | 3 | live geprüft |
| Passwort: mindestens 8 Zeichen, wachsende Wartezeit | 2 | `verify_runde3.py` |
| AAD über Frist, Drop-Id und Index | 1 | `verify_runde3.py` |
| Zeilenumbruch im eingefügten Link wird entfernt | 2 | `verify_runde3.py` |
| Bidi-Zeichen, Ortszeit statt UTC, Doppeldateien, 44-px-Tippziele | je 1 | — |
| Fremdes App-Store-Artwork raus (8 Marken-Logos, 53 KB) | 1 | Zusicherung im Bau |

Zwei neue Prüfer: `tasks/verify_zip.py` (öffnet das Archiv mit Pythons
`zipfile`, prüft Prüfsummen und vergleicht 14 Dateien Byte für Byte) und
`tasks/verify_runde3.py` (jede Prüfung darin war vorher rot).

### Offen — und warum

- **Relay** (10/10 als Blocker). Die eigentliche Aufgabe, nicht an einem Abend
  zu bauen.
- **Repository öffentlich** (6 Nennungen, 3 als Blocker). Vorbereitet, wartet
  auf deine Entscheidung und auf das Impressum.
- **Übergabenachweis / Downloadzähler** (2). Braucht das Relay.
- **Missbrauchsantwort vor dem Relay** (4 nennen Firefox Send). Eine
  Konzeptfrage, die dein Vater als Betreiber entscheiden muss, kein Code.
- **Deckel über 500 MB** (4). Der Browserspeicher begrenzt mit; ohne Relay
  wäre eine höhere Zahl eine Zusage, die das Gerät nicht hält.

### Neu für dich zum Nachlesen

`/limits` beantwortet jetzt die Frage nach Datenschutz, Haftung und
Auftragsverarbeitung. Dort stehen **Tatsachen über den Bau, ausdrücklich keine
Rechtsauskunft** — und der Satz, dass das Verbindliche ins Impressum und in die
Datenschutzerklärung gehört und dort noch fehlt. Lies den Absatz mit deinem
Vater durch, bevor die Seite aufmacht: er ist der Betreiber, und der Ton dieser
Antwort ist seine Entscheidung, nicht meine.

