mdpush runs on a zero-knowledge architecture. Your content, titles, categories, and project names are encrypted on your device. By the time anything reaches our servers, it's already gibberish to us.
Same document. Two very different views.
Here's the revised auth flow after yesterday's review. The big change: we're moving session-token hashing into the database trigger so we never have raw tokens in transit…
No vague language. Field by field, what hits our database and whether we can read it.
| Data | What we store | Can we read it? |
|---|---|---|
| Hashed for lookup + encrypted for sending codes | × No | |
| Passphrase | Never stored, never transmitted | × No |
| Document content | AES-256-GCM ciphertext | × No |
| Titles & metadata | Encrypted alongside content | × No |
| Encryption keys | Wrapped with your passphrase-derived key | × No |
| View count | Plain number (operational) | Yes |
| Expiration date | Plain timestamp (operational) | Yes |
| Lock type | light or strong (operational) | Yes |
// operational data is the bare minimum needed to enforce expiration, view limits, and lock gates
If we were ever subpoenaed, this is literally all we'd have to hand over for one document.
{
"id": "k7f2x9",
"user_id": "u_3a91...",
"encrypted_payload": "<ciphertext above>",
"wrapped_doc_key": "<wrapped with passphrase-derived key>",
"lock_type": "strong",
"lock_credential_hashes": ["<sha256>"],
"created_at": "2026-04-06T14:22:01Z",
"expires_at": "2026-04-13T14:22:01Z",
"max_views": 10,
"view_count": 3,
"status": "active"
}No title. No content. No project name. No category. No reader IPs. The wrapped key is mathematically useless without your passphrase, which we've never seen.