You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit was created on GitHub.com and signed with GitHub’s verified signature.
Added
A second factor for the sign-in to the UI, a choice of each user. Its
first method is an authenticator app (TOTP): a code after the
password. A user holds it on up to ten named devices, each with codes
of its own, added, renamed and removed on the page Second factor
with a QR code. The first device brings ten recovery codes shown
once, also as a text file to download. A further device, new
recovery codes and the recovery key need a code. A password set by
someone else is changed only after the code. docs/AUTHENTICATION.md
has the details. Recovery codes made before schema 19 are void: make
new ones on the page Second factor after the update.
Gmail and Google Workspace accounts over the Gmail API, with the
kind of account gmail. They sign in with Google in the browser,
through a Google client of the deployment's own, set up as
docs/GOOGLE.md says and named in MAILBOX_SERVICE_OAUTH_GOOGLE_CLIENT_ID
with its secret. Without one, Gmail connects over IMAP with an app
password as before.
In a Gmail account labels are folders, and a message can be in
several. "All Mail" is the folder ALL_MAIL with the role all.
Setting keywords answers 501 not_supported. The change feed follows
Gmail's history, asked every MAILBOX_SERVICE_SYNC_INTERVAL seconds.
Looking up a Gmail address offers Sign in with Google first,
where the deployment has a Google client. The way over IMAP links to
Google's page for app passwords.
Each user in /v1/users says whether it has a second factor for the
UI sign-in, in second_factor. GET /v1/users/{user_id}/second-factor
(get_second_factor, in users.read) lists the devices of each
method, totp so far, never a secret. DELETE /v1/users/{user_id}/second-factor (remove_second_factor) removes the
whole second factor, DELETE /v1/users/{user_id}/second-factor/totp/{device_id}
(remove_totp_device) one TOTP device, both in users.manage, for a
user whose rights the caller holds, never for the caller itself. The
database moves to schema 19.
PATCH /v1/webhooks/{webhook_id} (update_webhook) changes a
webhook's url, events or accounts. A field left out stays, accounts set to null is every account the owner may read. Its
deliveries, where its posts stand and its secret stay. POST /v1/webhooks/{webhook_id}/secret (renew_webhook_secret) answers a
new signing secret, shown once. The one before stops at once. Both are
in webhooks.manage, for the webhook's owner alone, and audited as webhooks.changed and webhooks.secret_renewed. The UI's webhook
page has a Change card and New secret. mailbox-client has both
as update_webhook and renew_webhook_secret, with the records Webhook and WebhookSecret. The secret is a Secret, kept out of repr and str, read with get_secret_value().
users reset-second-factor <name> on the host removes a user's
second factor, for the last administrator who lost every device and
the recovery codes.
mailbox-client covers the whole REST API: every operation is a
method of both clients, named like its operationId. New are the
administration side (accounts, discovery and the sign-in with a
code, users and passwords, tokens, roles, second factors, webhooks,
the audit of administration and of sends, the state of the service,
the catalogue of rights, health), folders renamed, moved and
deleted, a message's source (get_message_raw), one message changed
(update_message), a batch (batch_messages) and the lists across
accounts (list_all_messages, list_all_changes, list_all_sends).
They answer records such as Account, User, Grant, Role, Token, Webhook and Activity, a list that pages as Paged. A
secret shown once, a new token, a one-time password or a signing
secret, comes as a Secret, kept out of repr and str.
Python 3.15. The packages support 3.11 to 3.15. The images stay on
3.14 until a Python 3.15 base image exists.
Changed
The MCP server reads its settings as the service does, through benethos-mailbox-common[settings], and no longer needs python-dotenv. A wrong value in the environment or the settings
file stops the start and names the setting. The settings file no
longer changes the environment of the process.
The service and the MCP server install a fourth package, benethos-mailbox-common, of the same version: what both of them
need. The MCP server's log is written as the service's: in colour on
a terminal unless NO_COLOR is set, and its tokens masked as ***.
A wrong password or code asked once more before a step, such as the
recovery key or new recovery codes, counts against the client address
as a failed sign-in does, not only against the name. Ten from one
address lock it out, whichever users they were for.
A session of the UI ends after 24 hours however it is used
(MAILBOX_SERVICE_SESSION_MAX_HOURS), and a user holds 10 at most: a
new sign-in ends the oldest (MAILBOX_SERVICE_SESSIONS_PER_USER). A
secret shown once, such as a new token, recovery codes or the
recovery key, waits 5 minutes for the page that shows it
(MAILBOX_SERVICE_SHOWN_ONCE_MINUTES).
Breaking:mailbox-client: list_messages and list_changes take one
account, account_id is required. list_all_messages and list_all_changes read every account. A change of the feed is the
record Change and a failed id of a batch the record Failed,
where both were a dict.
Breaking:mailbox-client: a message is the record Message,
a summary in a page, a changed message and a written draft the record MessageSummary, where each was a dict. The API's from is sender, a time a datetime, an address an Address, an attachment
of a message an AttachedFile. Change.at is a datetime too.
Breaking:mailbox-client: me() is now get_me(), named like
its operation, as every method of the client is.
The UI names the company a person signs in at: "Sign in with
Google" for Gmail. It offers a sign-in with a code only where the
provider has one.
The UI shows icons, a set of Bootstrap Icons kept in the service, and
asks before a form that changes much in a dialog of its own. Every
secret shown once has a copy button. Lists show recent times as
"3 minutes ago". / puts the cursor in the search field. Nothing is
loaded from elsewhere.
The UI's sidebar ends in an account menu with your page, Password,
Second factor and Sign out. It folds to icons, and a dot marks
Accounts or Webhooks when something there needs a look. Mail is now Mail search. The Status page is gone: the Accounts list shows
each account's last sync and error, the overview the sync worker.
Lists in the UI create at their head and act on their rows: a plus in
the card's header, a pencil and a bin on each device, token and the
folder shown. Several devices or tokens are ticked and removed or
revoked together, all of them or none, devices after one password
and one code. A folder is renamed and moved in one form, and a move
asks first.
A user's page in the UI has the tabs Rights, Access and Activity. The
grant editor shows each grant as a line to change or remove. The
Users list disables, enables, gives or takes a role of the ticked
users, all of them or none, and names those it could not change.
Each row of the UI's Accounts list links to the account's mail and
sends. A message has its actions in its header and its keywords as
chips, and Move asks for the folder in a dialog. The batch bar of a
mail list asks for a folder only to move, and its head ticks all.
Fixed
The MCP server writes a sender's name, a subject and a file name on
one line each. A line break in them could start a line inside the
mail's marker that looked like a header of its own.
The mail form of the UI shows a name with a double quote or a
backslash in it so that a reply or a forward reads it back as it was.
A Gmail or Microsoft account whose OAuth app is missing from the
settings no longer breaks every page of the UI. The Accounts list
says it cannot be used, it counts as needing attention, and it can be
removed. In GET /v1/status it is not synced and needs attention.
Changing your password checks the current one as any confirmation
does: a wrong one counts against your name and is audited as auth.confirm_failed.
A webhook's accounts cannot be an empty list, which would hear
nothing. Send null for every account.
Changing a webhook needs list_changes only on the accounts the
change adds. An owner who lost the right on one of its accounts can
still change the URL or the events.
The UI's Users list counts only the users a batch changed, not those
that were as asked already.
mailbox-client: Me has the caller's user_id and name.
The text of a mail written as HTML only, on the mail page and as the
text part of a send, leaves out what its inline style hides as the
MCP server does: too small, too faint, off the page, cut to nothing,
or in the colour of its background. An end tag without its start tag
no longer ends hidden text early.
The MCP server's text of an HTML mail keeps a link's address after
its text and puts a dash before each list item, as the mail page
does.
The text of an HTML mail keeps text whose colour and background are
alike only by a keyword such as inherit or currentcolor. Only
colours of their own count, such as #fff, rgb(...) or white. left and top far off the page hide text only with position absolute, fixed or relative.
Security
A secret shown once in the UI goes when its 5 minutes run out, at
the next request of its session or the next sign-in of anyone, not
only at the next page that could show it.
The audit keeps auth.session_evicted when a sign-in ends the
user's oldest session of the UI, and users.change_refused for each
user a batch of the Users list could not change.