diff --git a/README.md b/README.md index b65b8999..401892d3 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ The core loop is simple: *answer honestly → choose what to reveal → keep a r | What | Why it matters | | --- | --- | -| 🔐 **Real E2EE** | Answer content is encrypted on-device. Server only sees ciphertext. Couple-owned keys via Tink (Android). | +| 🔐 **Real E2EE** | Answers **and chat messages** are encrypted on-device. Server only sees ciphertext. Couple-owned keys via Tink (Android). | | 💑 **One subscription per couple** | No double-billing partners. Premium unlocks for both — server-verified. | | 🚫 **No engagement traps** | No infinite scroll. No likes. No follower counts. One daily question is the loop. | | 🌗 **Decoupled theme + art** | In-app light/dark controls art; system theme isn't required to match. | @@ -63,7 +63,7 @@ Closer treats both the same way: **clear, straightforward, and built on honesty. - 🪞 **Private first, reveal second.** Each partner answers independently. Both decide what to share. - 🧠 **Curated, not generated.** 6,000+ hand-written prompts across 22 categories — no AI confabulation in the core loop. - 💸 **One sub, not two.** Subscription unlocks for both partners. Server-verified. No silent trial conversions. -- 🔒 **Encryption that earns the word.** Tink AEAD with couple-owned keys. Recovery phrase. Server never sees plaintext. +- 🔒 **Encryption that earns the word.** Tink AEAD with couple-owned keys. Answers, messages, and history — server never sees plaintext. Recover with your phrase *or* your partner. - 🌙 **Quiet hours, server-side.** Partner pushes respect the *recipient's* in-app window — not just foreground detection. --- @@ -316,9 +316,11 @@ npm run dev ## Security & privacy -- 🔐 **E2EE answer content.** Tink AEAD with couple-owned keys. Server never sees plaintext answers or capsule content. +- 🔐 **E2EE content.** Tink AEAD with couple-owned keys. Answers, **chat messages** (text *and* images), locked capsules, and conversation history are encrypted on-device — the server only ever sees ciphertext. Messages live under `couples/{coupleId}/conversations/…`; images upload to Storage as opaque encrypted bytes, and even the inbox preview line is encrypted. +- 💾 **Encrypted conversation backup.** Chat and thread history is backed up as couple-key ciphertext — cheap incremental appends plus periodic full snapshots — so history can return to a new device. The backup is never readable server-side. - 🧂 **Key wrapping.** Argon2id KDF over the recovery phrase; keys wrapped client-side. -- 🪪 **Recovery phrase.** Server-blind; wiped from the inviter on acceptance. +- 🪪 **Recovery phrase.** Server-blind; wiped from the inviter on acceptance. One of **two** recovery paths. +- 🤝 **Partner-assisted restore.** Lost or wiped your device? Your partner can restore your full history with **no recovery phrase**: your new device publishes a fresh public key, you read a 6-digit code aloud on a separate channel, and they wrap the couple key to that key (ECIES `keybox:v1:`). The server only relays the sealed blob — never the key itself. Your own devices get a *"was this you?"* security alert whenever a restore is requested or completes. - 🚧 **Firestore rules.** Couple-scoped; deny-by-default; field allowlists on `users/{uid}` updates; shape-restricted couple create. - 🛡️ **App Check.** Play Integrity (Android), DeviceCheck (iOS, planned) — blocks abusive backend access. - 🌙 **Quiet hours, server-side.** Suppression is enforced where the push is **sent**, not where it might be foregrounded. Client cannot bypass by being backgrounded.