LEGAL / SECURITY
Security
Last updated: [DATE]
This page says how the hosted part of fair.ninja protects your data, in plain terms, including what is not done yet. The Privacy Policy says what we store; this page says how we keep it safe.
The design: your device first
Tomato keeps your data on your device and works without a server. Sync is an optional service on top. That design is itself a security property: if our server is unreachable, compromised, or gone, your timer still runs, your plan is still there, and your export still works. The hosted part holds only what you chose to sync.
In transit
- Every connection to fair.ninja uses TLS, with certificates issued automatically by Let's Encrypt and renewed before they expire. Plain HTTP is redirected.
- Browsers are told to remember that (HTTP Strict Transport Security), not to sniff content types, not to frame our pages, and — on the app pages — to run only scripts we ship (Content Security Policy, enforced, with violation reports sent back to us).
- Camera, microphone and location are switched off for our pages by policy; the apps never ask for them.
At rest
- The application data lives in PostgreSQL on a server we operate in
[the EU — datacenter to confirm]. - Every table holding user data has row-level security enforced by the database itself: each request runs as a database role that can only see the rows of the account it serves. A bug in the application cannot turn into a read of someone else's data, because the database refuses it.
- Passwords: we never hold one. Sign-in is delegated to Google's Firebase Authentication.
- Session tokens, personal access tokens and webhook signing secrets are stored only as hashes or encrypted with a key that is not in the database.
- What is not there (yet): the synced content is not encrypted end-to-end. The server can read it, because sync, export and assistant access need to. Disk-level encryption of the server is
[owner to confirm with the hosting provider]. We say this plainly rather than imply a zero-knowledge design we don't have.
Your account
- Sign in with Google or with e-mail and password, through Firebase Authentication. Our server verifies a short-lived proof from Firebase and issues its own session.
- The session cookie is HttpOnly, Secure and same-site, so scripts cannot read it and other sites cannot ride on it; a second cookie protects every change you make against cross-site request forgery.
- Sessions end after 14 days of no use, or after 30 days regardless.
- The account portal shows every device and session on your account. You can end any of them, or all of them at once with Sign out everywhere, which also cuts off every assistant connection.
- Assistant connections (MCP) get only the scopes you tick on the consent screen, act under a daily chips cap, and stop working the moment you revoke the device they are bound to.
Backups and recovery
- A full, encrypted backup of the database is taken every day. It is encrypted before it is written, with keys that are not stored on the server, and kept for 14 days.
- Work in progress: copies are not yet stored off the server, and we do not yet keep a continuous transaction log, so in the worst case up to a day of synced changes could be lost. Both are on the beta checklist; this page will change when they ship. Until then, keep using the export.
- Data export gives you an independent copy at any time — a ZIP in an open, documented format.
Operations
- The service is run by a very small team. Access to the server is by SSH key only; secrets are stored encrypted in the code repository and decrypted only on the server.
- We collect server logs and metrics to keep the service healthy. They contain request identifiers and account identifiers, not IP addresses, e-mail addresses or the content you sync.
- Every request is rate-limited per IP and per account; abusive traffic is throttled before it reaches the database.
- Dependencies are checked for known vulnerabilities in the build pipeline.
Reporting a vulnerability
If you find a security problem, please tell us first: [security@fair.ninja]. Give us reasonable time to fix it before publishing. In return: we will not take legal action against research done in good faith that avoids other people's data and does not disrupt the service, we will answer you, and we will credit you here if you like. There is no bounty programme yet.
If something goes wrong
If we learn of a breach affecting your data, we investigate, contain it, notify the supervisory authority within 72 hours where the law requires it, and tell affected users directly, without undue delay, what happened and what to do. Incidents that affect the service are also published on our status/changelog page.
Generated from the repository's docs/legal/security.md. Questions: see section 1.