Codes are covered until revealed. A reveal is a server-side, per-session
window (60 s, two periods): POST /api/accounts/{id}/reveal opens it and
returns the code, GET /api/codes only ever returns codes for accounts in
that window, and /hide closes it early. The browser therefore never holds
a code it has not asked for by name, which is what makes the log honest.
Settings -> Log is an audit trail in the style of Daito: one line per
event with who, how long ago and from which address. It records what the
server observed - sign-ins and failed attempts (under the name tried),
reveals, accounts added / renamed / removed, delivery and credential
changes, test messages. Entries are JSON lines in audit.jsonl (owner-only,
newest 5,000 kept, compacted at twice that). The address comes from
X-Forwarded-For / X-Real-IP when parseable, else the TCP peer via
ConnectInfo; in Docker bridge networking that peer is the gateway, which
the README and template now say.
The account list shows each service's mark instead of an initial. The
pack (crates/webui/src/icons.js, generated by scripts/fetch-icons.py) is
~175 marks from Simple Icons (CC0) plus Font Awesome Free brands (CC BY
4.0) for Amazon, AWS, Microsoft, LinkedIn, Slack, Xbox, Salesforce and
Yahoo, which Simple Icons no longer carries. Matching is by issuer name,
then shorter word prefixes, then the label's mail domain; unmatched
accounts keep the initial tile. Marks that would vanish against a theme's
tile fall back to ink for that theme only.
The setup and Delivery platform pickers are plain text; the coloured dots
are gone.
Router tests cover the reveal window, session scoping, 401s, and the
forwarded address landing in the log.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
3.8 KiB
Publishing to Gitea
Releases are cut by hand. Each one needs a Gitea personal access token
with the write:repository and write:package scopes, which is why none of
this is automated: the token should only ever exist in your own shell or
keychain.
On a Mac that has pushed before, git already holds the token in the login keychain and nothing needs exporting. Elsewhere, create one at Gitea → Settings → Applications → Generate New Token and export it once per shell session:
export GITEA_TOKEN='<paste-your-token>'
1. Cut the version
Bump version in the workspace Cargo.toml, update the IMAGE_TAG and
GIT_REF defaults in scripts/build-and-publish-unraid.sh, add a line to the
README changelog, and commit. Then tag:
git tag -a v0.2 -m "OpenMFA v0.2"
Tags are vMAJOR.MINOR[.PATCH] — v0.1, v0.2, … — and the image carries
the same number without the v (0.1, 0.1.1, 0.2) plus a moving latest.
2. Push the code and the tag
git push origin main --follow-tags
With a token in the environment rather than the keychain, prefix the command
with git -c "http.extraHeader=Authorization: token $GITEA_TOKEN".
3. Build the image
The Dockerfile cross-compiles to x86_64-unknown-linux-musl from whatever
architecture the builder runs on, so this is fast on Apple Silicon — no QEMU.
--provenance=false --sbom=false matters: Unraid's Docker cannot load the
attestation manifests BuildKit attaches by default.
docker build --pull --platform linux/amd64 --provenance=false --sbom=false -f deploy/docker/Dockerfile -t gitea.milesward.dev/mward4/openmfa:0.2 -t gitea.milesward.dev/mward4/openmfa:latest .
4. Push the image
Never run docker login or docker logout for gitea.milesward.dev on a
Mac where git keeps the token in the keychain. Docker's osxkeychain
credential helper maps to the same keychain item as git's: login fails with
"The specified item already exists in the keychain (-25299)", and logout
silently deletes the credential git was using, so the next git push fails
with a bare 401. Write the auth into a throwaway config instead — a config
that already contains an auths entry makes the CLI skip the helper:
export DOCKER_CONFIG="$(mktemp -d)" && printf '{"auths":{"gitea.milesward.dev":{"auth":"%s"}}}' "$(printf 'mward4:%s' "$GITEA_TOKEN" | base64 | tr -d '\n')" > "$DOCKER_CONFIG/config.json" && docker push gitea.milesward.dev/mward4/openmfa:0.2 && docker push gitea.milesward.dev/mward4/openmfa:latest; rm -rf "$DOCKER_CONFIG"; unset DOCKER_CONFIG
On a Colima host, export DOCKER_HOST="unix://$HOME/.colima/default/docker.sock"
first: an isolated DOCKER_CONFIG has no currentContext, and the CLI would
otherwise look for /var/run/docker.sock.
On a fresh machine, scripts/build-and-publish-unraid.sh does the clone,
build and push in one pass using that same private-config approach:
GITEA_TOKEN="$GITEA_TOKEN" ./scripts/build-and-publish-unraid.sh
5. Verify the pull
The repo is public, so this needs no credentials — which is exactly how Unraid will fetch it:
docker pull gitea.milesward.dev/mward4/openmfa:0.2
6. Deploy on Unraid
Add a container with Repository set to:
gitea.milesward.dev/mward4/openmfa:0.2
(or :latest). Map /var/lib/openmfa to /mnt/user/appdata/openmfa,
publish port 8720, and leave networking on bridge. Or import
deploy/unraid/openmfa.xml into
/boot/config/plugins/dockerMan/templates-user/ to get all of that prefilled.
To upgrade an existing container, change the tag and apply. The vault, key, settings and admin account all live in the appdata mount and carry over.
Afterwards
If a token was exported, make sure it is not left in the shell:
unset GITEA_TOKEN