Encrypt pages at rest with a key per person
CI / test (push) Successful in 2m2s
Release / release (push) Successful in 2m15s

Pages are sealed with AES-256-GCM. Each person's key is derived (HKDF) from a master key in the settings file plus their Authentik issuer and subject. Plain files from earlier versions are read and re-saved encrypted. Mako refuses to open a notebook it cannot decrypt rather than overwrite it.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
VeillaxandClaude Sonnet 5.5 committed 2026-11-01 00:25:37 -06:00
1 parent e3147597e8
commit 9f2fe4a416
11 files changed
+396 -33

No files matched your search

+28 -8
View File
@@ -2,7 +2,7 @@
A private notebook in the spirit of Obsidian and Notion, for people who would rather run their own.
Pages that nest inside each other, `[[links]]` between them with backlinks, a journal page for each
day, tags, and quick search, all kept as plain markdown files. One small binary, no database, no
day, tags, and quick search, all kept as encrypted markdown files. One small binary, no database, no
dependencies. You sign in with **Authentik** and nothing else: there are no passwords in Mako.
Named for the mako shark, the fastest in the sea, because a notebook should keep up with you.
@@ -116,23 +116,42 @@ written to it:
| `oidc.client_id` | `MAKO_OIDC_CLIENT_ID` | |
| `oidc.client_secret` | `MAKO_OIDC_CLIENT_SECRET` | |
| `allowed` | `MAKO_ALLOWED` | optional; emails, usernames or Authentik ids, comma separated |
| `key` | `MAKO_KEY` | encrypts your pages; made for you, see Encryption below |
| `listen` | `MAKO_LISTEN` | default `127.0.0.1:8490` |
| `data_dir` | `MAKO_DATA` | default `data` |
`mako.json` also holds a `secret` that signs session cookies. It is made on first run and written
with mode `0600`. Changing it signs everyone out.
## Encryption
Every page is encrypted on disk with AES-256-GCM. Each person has a key of their own, made from the
`key` in `mako.json` together with who they are in Authentik (the issuer and their subject id). So one
person's files cannot be opened with another's key, and a file copied over another page's name stops
opening. Pages are decrypted in the server's memory while it runs, and your downloads are plain
markdown.
- **The key is made on first run** and written to `mako.json` (mode `0600`), or set `MAKO_KEY` (at least
32 characters, for example `openssl rand -base64 32`) to keep it out of the file.
- **Back the key up, apart from the notes.** Without it the pages cannot be read, and Mako refuses to
start a notebook it cannot decrypt rather than overwrite it. Do not change it. Unlike `secret`,
changing `key` does not just sign people out.
- **What it protects:** a stolen disk or backup of `data/`, and anyone who can read the notes folder but
not the settings. **What it does not:** someone who controls the running server, or who can read both
`mako.json` and `data/`. Who you are in Authentik is not secret, so it cannot be the key by itself.
- **Upgrading from 0.1.0:** existing plain files are read and saved again encrypted the first time
that person signs in, and a `key` is added to your settings file.
## Where your notes are
```
data/users/<hash of who you are>/
owner.txt your name and email, so the folder can be matched to a person
notes/20261031-143205-a1b2c3.md one file per page
notes/daily-2026-10-31.md the journal page for a day
notes/20261031-143205-a1b2c3 one encrypted file per page (named .md)
notes/daily-2026-10-31 the journal page for a day
trash/ deleted pages, until the trash is emptied
```
A page file looks like this, so you can edit it with anything:
Inside, a page is markdown with a small header (shown here decrypted, and what the zip export holds):
```
---
@@ -146,8 +165,8 @@ pinned: true
Flights and hotels, see [[Packing list]] #travel
```
A plain `.md` file dropped into `notes/` is picked up too, with its file time as its date (name it with
lower-case letters, numbers and dashes). Restart Mako to see files added by hand.
A plain `.md` file dropped into `notes/` is picked up when that person's notebook next opens, with its
file time as its date, and is then encrypted (name it with lower-case letters, numbers and dashes).
## Security notes
@@ -161,7 +180,8 @@ lower-case letters, numbers and dashes). Restart Mako to see files added by hand
person's requests can only ever reach their own folder.
- Every change from the browser needs a header a page on another site can't send. The page has a strict
Content-Security-Policy, and pages are never rendered as HTML.
- Pages are **not encrypted** on disk. Anyone who can read the server's disk can read them.
- Pages are encrypted on disk (see Encryption), with a key per person. The server itself, while it
runs, can read them: this is not end-to-end encryption.
## Honest limits