Agent api keys and theme - #1
Merged
Merged
Conversation
New page under My Account with a three way segmented control. The choice lives in localStorage (per device, not on the customer record) and applies immediately; "system" is resolved against prefers-color-scheme and stamped on <html> as data-theme, so app.css needs one dark palette block rather than duplicated media queries. An inline script in index.html stamps it before first paint to avoid a flash of the light theme. Four hardcoded colours had to become tokens to survive the dark palette: main's background (the filler behind .container's rounded corner, which showed a bright blue wedge), and the white labels on filled buttons, .segmented-option-active and .button-pill, which are unreadable against dark's lighter --link. The select arrow SVG was a leftover dark-theme colour that had been near-invisible on the light theme all along. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Changelog now sits in the header nav before "Signed in as", next to Sign Out. It needs no new CSS: header nav already styles plain anchors as muted white underlined text, matching the Sign Out control. Service Status is gone from the sidebar entirely. The /status route and StatusPage still exist and are reachable by URL, but nothing links to them now, so that page either needs a home somewhere or should go. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign-in goes through Ordnary's SSO, which enforces its own second factor, so the banner apologised for a gap that isn't ours and pointed people at a setting Amelu is never going to own. The "Second Factor Auth - Disabled" row in the card below is wrong for the same reason and is still there; it needs dropping or relabelling to name the identity provider. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
/account/api-keys replaces the greyed-out sidebar item: create a named key, see its prefix, created and last-used, revoke it. The raw key is returned once and never stored - api_keys holds a SHA-256 hash, the same shape as sessions and organization_invitations. auth.Require now accepts either the session cookie or an API key in Authorization: Bearer, so every /api route took keys the moment the middleware changed. A key acts as its owning customer with that customer's organization role. The account surface and key management moved to a new cookie-only auth.RequireSession, so a leaked key can manage domains and mailboxes but cannot mint further keys, move the sign-in email, or terminate the account. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three endpoints on /api/mailboxes/{id}/messages so an automated caller can
work a mailbox without speaking IMAP or SMTP: list a page of inbox or sent,
fetch one message with decoded bodies and attachment metadata, and send.
They extend the JMAP path ListRecentEmails already used.
Sending has no from field. Both the header From and the SMTP envelope are
the submitting mailbox, so a key cannot send as a colleague - that is not a
check that can be bypassed but an input that doesn't exist. Recipients
containing a newline, comma or space are rejected, which is the header
injection case.
New authz.CanAccessMailboxContents, owner and admin only, deliberately
narrower than CanManageMailboxes: helpdesk resetting a password is a
support action the owner can see happened, silently reading their mail is
not.
Not yet exercised against a live Stalwart, so the submission envelope and
the onSuccessUpdateEmail move out of Drafts are the parts most likely to
need correcting. Covered meanwhile by a fake JMAP server that pins the
request shapes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this change?
Why?
How was this tested?
Checklist
go build ./... && go vet ./... && go test ./...passes (if backend changed)npm testpasses incloudflare/edge(if the edge Worker changed)CONTRIBUTING.mdandLICENSE.mdAGENTS.md(no new abstractions/config knobs without a real need, mirrored existing patterns)