Correct three creator-facing docs to match code
Fixes surfaced by the creator-trust audit -- all cases of docs describing
the code less accurately than reality:
- tech/security.md: the breach-scenario paragraph claimed TOTP seeds are
stored unencrypted with encryption only "planned". They are already
encrypted at the application layer (ChaCha20-Poly1305, per-secret nonce,
key derived from a server-only signing secret held outside the DB).
Rewrote it to say so; the old text made 2FA look weaker than it is.
- exports/content.rs: the export ZIP manifest advertised the git clone URL
as /source/<user>/<repo>.git, a dead path. Live routes and guide/git.md
use /git/. Fixed the string.
- support/faq.md: "Public API documentation is planned" -- but the
developer/ docs (OAuth, license keys, OTA, SyncKit, feeds) are already
published. Point at them instead.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
3 files changed,
+3 insertions,
-3 deletions
| 99 |
99 |
|
## Technical
|
| 100 |
100 |
|
|
| 101 |
101 |
|
### Is there an API?
|
| 102 |
|
- |
Yes. The platform has a JSON API for managing projects, items, tags, blog posts, license keys, promo codes, memberships, follows, and data exports. It's used by the platform itself and is available to authenticated creators. Public API documentation is planned.
|
|
102 |
+ |
Yes. The platform has a JSON API for managing projects, items, tags, blog posts, license keys, promo codes, memberships, follows, and data exports. It's used by the platform itself and is available to authenticated creators. See the [developer docs](../developer/api-overview.md) for the API overview, OAuth, license keys, OTA updates, SyncKit, and feeds.
|
| 103 |
103 |
|
|
| 104 |
104 |
|
### Can I self-host?
|
| 105 |
105 |
|
Source code is available for review, but the license (PolyForm Noncommercial 1.0.0) does not permit commercial self-hosting.
|
| 49 |
49 |
|
|
| 50 |
50 |
|
Encryption at rest is infrastructure-level (Hetzner), protecting against physical theft and infrastructure compromise. No application-level encryption layer; the platform has server-side access to stored data (necessary for indexing, search, and content delivery).
|
| 51 |
51 |
|
|
| 52 |
|
- |
**What this means in a breach scenario.** If a database dump were obtained without the disk-encryption key, an attacker would get only ciphertext. If an attacker reached the running process or a decrypted backup, the following would be readable as-is: email addresses, account metadata, content metadata, and second-factor seeds (TOTP secrets are stored unencrypted at the application layer). Passwords are not affected: they are stored only as Argon2id hashes and cannot be recovered from a dump. Backup codes are stored as hashes. Passkey credentials are public-key material and are not secrets. We plan to move TOTP seeds behind an application-level key so that a database-only compromise does not yield working second factors; until then, treat TOTP as protecting against credential reuse and phishing, not against a server-side breach.
|
|
52 |
+ |
**What this means in a breach scenario.** If a database dump were obtained without the disk-encryption key, an attacker would get only ciphertext. If an attacker reached the running process or a decrypted backup, the following would be readable as-is: email addresses, account metadata, and content metadata. Passwords are not affected: they are stored only as Argon2id hashes and cannot be recovered from a dump. Backup codes are stored as hashes. Passkey credentials are public-key material and are not secrets. TOTP second-factor seeds are encrypted at the application layer (ChaCha20-Poly1305 with a per-secret nonce, under a key derived from a server-only signing secret that lives in the server's environment, not the database), so a database-only compromise yields only ciphertext and no working second factors; decrypting them would additionally require the signing secret.
|
| 53 |
53 |
|
|
| 54 |
54 |
|
---
|
| 55 |
55 |
|
|
| 396 |
396 |
|
}
|
| 397 |
397 |
|
}
|
| 398 |
398 |
|
readme.push_str("\nNote: Git repositories are not included in this export.\n");
|
| 399 |
|
- |
readme.push_str("Clone them separately: git clone https://makenot.work/source/<username>/<repo>.git\n");
|
|
399 |
+ |
readme.push_str("Clone them separately: git clone https://makenot.work/git/<username>/<repo>.git\n");
|
| 400 |
400 |
|
|
| 401 |
401 |
|
// Append README, finalize the central directory, and flush the buffer to
|
| 402 |
402 |
|
// disk — all blocking — off the runtime before the upload reads the file.
|