Commit Graph
1533 Commits
Author SHA1 Message Date
Linus Rath 5d90a850bd Merge branch 'feat/org-recovery' into feat/org-features
# Conflicts:
#	components/email/email-list.tsx
2026-10-28 09:17:56 +01:00
Linus Rath 272083399c Merge branch 'feat/org-tags' into feat/org-features
# Conflicts:
#	lib/admin/restriction-keys.ts
#	lib/jmap/client.ts
2026-10-28 09:15:17 +01:00
Linus Rath f1a666777b Merge branch 'feat/org-features' into feat/org-recovery 2026-10-28 09:08:49 +01:00
Linus Rath 4d846cfc91 fix: read the whole deleted items archive newest first and only for the account shown #1319
Stalwart's x:ArchivedItem/query without calculateTotal scans ids
ascending, stops at 5000 and only then reverses them, so the newest
items of a large archive never showed, and admin accounts got every
account's items. The review of the branch also found gaps around
account switches, restores and focus.

- Read the archive in pages of 500 with calculateTotal, newest first,
  stop at a whole page older than the days limit, and offer
  "Show older" after 2000 items; detection asks for one item.
- Send the accountId filter and fall back without it on
  unsupportedFilter; keep only items of the account, never one without
  an account id.
- Ask nothing until config and policy are loaded and the policy is the
  current account's; the later check after a refusal is forced.
- Show the Trash link only when the archive holds a message inside the
  days limit; the Settings page shows whenever the server has the
  feature and says that archiving must be on in Stalwart.
- Restore: notFound leaves the list with a note, forbidden hides the
  page, results for another account are dropped, the button keeps focus.
- Forget what servers said at a full sign-out.
2026-10-28 09:08:44 +01:00
Linus Rath 3a03bc363b Merge branch 'feat/org-templates' into feat/org-features 2026-10-28 09:01:42 +01:00
Linus Rath 33ca8efb0f fix: keep shared tags safe when members edit at once or the server fails
The first version wrote the whole tag list on every change, guessed a
group when the server wouldn't say, and treated a failed read like a
server without metadata. Now:

- Definitions are a map by tag id under `tags`, and each change patches
  one tag (`metadata/org.bulwarkmail.tags/tags/<id>`), so two members
  adding tags at once both keep theirs. Fields and colors this version
  doesn't know survive. The `{ list }` and bare-array shapes are still
  read and converted by the first save.
- Shared tags appear only for confirmed group principals. A failed
  principal lookup keeps the user's own tags and asks again later.
- "No metadata advertised" (0.16) and "the read failed" are separate.
  A failed read keeps the last good tags; a failed save keeps the change,
  says so, and sends it with the next good read after the client's
  pause.
- Push reloads wait for 5 s of quiet and skip the echo of our own save;
  a returning tab reloads definitions only, and the scan for unnamed tags
  runs once per sign-in and then at most every 30 minutes.
- The editor names its buttons after the tag, shows the delete warning
  and 44 px buttons on phones, returns focus to the edit button, and
  asks for Inbox rights only for confirmed groups.
2026-10-28 08:58:11 +01:00
Linus Rath e82679c3dc fix: name the admin section for deleted mail Recover deleted items, as users see it 2026-10-28 08:30:11 +01:00
Linus Rath 08f25506d4 Merge branch 'feat/org-teaminbox' into feat/org-features 2026-10-28 08:26:48 +01:00
Linus Rath c00c7080a1 fix: give plugins the directory only with their own permission, and only confirmed team mailboxes
- `directory:read` for api.user.findPeople, with at least 3 characters,
  at most 20 ids, 20 results and 10 lookups a minute, in the directory
  of the account the call names; one load in flight per client.
- Plugins hear `group` only for accounts the server confirmed are group
  principals; the policy's fallback stays for the admin's scopes.
- The email.* keyword methods refuse $draft, $junk, $notjunk and
  $phishing.
- A plugin keeps at most 4 KB in a mailbox and reads it 30 times a
  minute; the email:write consent text says others in a team mailbox
  can read it.
- email.updateKeywords also changes the rows of expanded conversations.
2026-10-28 08:16:52 +01:00
Linus Rath 7f06ed7637 Merge branch 'feat/org-features' into feat/org-tags
# Conflicts:
#	lib/admin/restriction-keys.ts
2026-10-28 08:14:39 +01:00
Linus Rath 9304557819 fix: look up another signed-in account for the external mail checks only when an admin turned them on 2026-10-28 08:07:55 +01:00
Linus Rath f1bcba6222 fix: start merging the browser's template list from the sync driver, not at import 2026-10-28 07:53:54 +01:00
Linus Rath 2a5f6fc6f0 test: cover expired tombstones and a lone queued deletion at sign-out 2026-10-28 07:48:49 +01:00
Linus Rath 62bed18fe8 Merge branch 'feat/org-features' into feat/org-teaminbox 2026-10-28 07:38:25 +01:00
Linus Rath 88f20e1ab0 fix: never lose personal templates to a deletion, a clock or a settings load elsewhere
The first version took a template missing from the account's Inbox
metadata as deleted, skipped the browser's own list once the account
held anything, wrote the marker before the settings blob had loaded,
and let a round overwrite edits made while it ran. Each of these could
drop templates, or bring deleted ones back.

Now the marker entry `org.bulwarkmail.templates` holds tombstones
(90 days, at most 8 KB, oldest dropped first) and only a tombstone
deletes; a missing entry is uploaded again. Every round merges the
browser's list in when it is this account's, each version once, minus
what a newer tombstone deleted. While settings sync hasn't loaded the
account's settings, the list isn't used and no marker is written; a
blob that loads later is merged into the account's copy. The settings
blob drops its templates only once the marker is on the server. Without
settings sync the list goes into the first account that answers only.
A round that saw changes while it ran plans again against the server as
it left it. An answer without the metadata property counts as
unsupported. Changes move `updatedAt` past the previous value, dateless
synced templates get a fixed early date, and ids that don't fit a
metadata key get a new id derived from the old one. Queued changes go
out before an account signs out; a full sign-out keeps unsent templates
and deletions.

Team templates are written only if the entry is still the version the
edit started from ("Changed by someone else"), never carry Bcc, and a
refusal is told apart by Stalwart's error type. The template manager's
lists are a real tab list with arrow keys and 44 px row buttons on
phones.
2026-10-28 07:34:25 +01:00
Linus Rath 4aa4606b84 fix: give plugins no personal templates when the admin hid them 2026-10-28 07:34:23 +01:00
Linus Rath a6af7bc8f1 feat: let admins limit or hide recovering deleted items per domain or group #1319 2026-10-28 07:27:55 +01:00
Linus Rath ba6e6af014 feat: recover deleted items from Stalwart's archive #1319 2026-10-28 07:27:47 +01:00
Linus Rath b5e92ba176 Merge branch 'feat/org-features' into feat/org-templates
# Conflicts:
#	lib/admin/restriction-keys.ts
2026-10-28 07:10:25 +01:00
Linus Rath 3d8a0cfd0b feat: let admins lock shared tags per domain or group 2026-10-28 06:46:04 +01:00
Linus Rath b049b6f470 feat: share tag names and colours in group mailboxes #1310 2026-10-28 06:43:46 +01:00
Linus Rath a69d7eee33 feat: let plugins work with team mailboxes: list filters, row badge icons, account info and message conditions
What the team inbox plugin needs, kept general for other plugins:

- `api.ui.setListFilters`: keyword filters drawn as chips in the list
  header of the folders they apply to (by account kind and folder
  role). A chip the user turns on is ANDed into the folder's query and
  comes off with one click; a keyword change a filter tests loads the
  list again (ui:message-list).
- Actions get `accounts`, `hasKeyword` and `notKeyword`, so a button
  shows only on messages of group accounts, or of a keyword state; the
  click of message-row-actions and reader-actions carries the message's
  `accountId`.
- `api.email.updateKeywords`: several keywords in one change, through
  the list for a listed message (email:write).
- `api.user.getSelf`, `getMailAccounts` and `findPeople`: the user's own
  account id (Stalwart's principal id), which accounts are group
  accounts, and people from the directory (account:read).
- `api.accountData`: a plugin's own entry in a mail account's shared
  Inbox metadata on Stalwart 1.0 (email:read / email:write).
- Row badges take an `icon`.
2026-10-28 06:39:57 +01:00
Linus Rath 82918fc7d7 Merge branch 'feat/org-features' into feat/org-delegates
# Conflicts:
#	lib/admin/restriction-keys.ts
2026-10-28 06:30:09 +01:00
Linus Rath 49c9ec6a45 fix: start a delegate's Change from what they have and keep what fits no choice as it is
Change used to pre-fill the closest choice and then replace everything
of that type, so a folder added after "all", a single non-Inbox folder,
a non-default calendar, free/busy only or manager rights were narrowed
or widened on Save. Now a type gets a choice only when the grants match
it exactly; anything else starts at "Keep as it is", which leaves that
type out of the patch. Mixed levels keep each type's rights.

Also in the Delegates page:
- Change and Remove wait, with Try again, while a type couldn't be read
- an answer from the account before an account switch is dropped
- calendars, contacts and files follow their feature gates
- Remove says it covers what was shared from the user's own account
- typing your own address says "That's you"
- groups named only by the session get the group badge
- on Stalwart 1.0 the read hint says read delegates can flag mail
- the person list is plain buttons, not a listbox without arrow keys
- the rights follow sharingRights
2026-10-28 06:28:02 +01:00
Linus Rath f0539a33f6 feat: let admins limit every share dialog to read access with sharingRights 2026-10-28 06:27:49 +01:00
Linus Rath f0a89fdb65 fix: forget delegate names on sign-out and when their account is removed 2026-10-28 06:27:28 +01:00
Linus Rath 5ce0f96f26 fix: read delegate sharing only for the apps that are on, with the file tree alongside 2026-10-28 06:27:07 +01:00
Linus Rath 87e41f0403 feat: share team templates in a group mailbox 2026-10-28 06:24:46 +01:00
Linus Rath 47c47b4f08 feat: keep personal templates in the account on Stalwart 1.0 2026-10-28 06:13:47 +01:00
Linus Rath 57065d7ef2 feat: show an organisation template library from the admin 2026-10-28 05:53:50 +01:00
Linus Rath 795faceee7 Merge branch 'feat/org-thirdparty' into feat/org-features 2026-10-28 05:51:22 +01:00
Linus Rath 00ea203f4f refactor: describe the sending identity and account once for every send check 2026-10-28 05:50:17 +01:00
Linus Rath 687cd89346 Merge branch 'feat/org-external' into feat/org-features
# Conflicts:
#	lib/outgoing/quick-reply.ts
#	lib/outgoing/send-pipeline.ts
2026-10-28 05:46:11 +01:00
Linus Rath 9e809a31db Merge branch 'feat/org-features' into feat/org-thirdparty 2026-10-28 05:27:58 +01:00
Linus Rath 823da8c810 Merge branch 'feat/org-features' into feat/org-external
# Conflicts:
#	components/email/email-viewer.tsx
#	components/mail/mail-app.tsx
2026-10-28 05:19:21 +01:00
Linus Rath 9dab8955dd feat: confirm before inviting people outside the organisation to a meeting 2026-10-28 05:12:24 +01:00
Linus Rath 0232ae322b feat: let admins hide delegates or limit them to read access per domain or group 2026-10-28 05:11:26 +01:00
Linus Rath 1202a13720 fix: judge external mail by the message's own account and the sending account in several-account setups 2026-10-28 05:11:24 +01:00
Linus Rath bcf4f3a7a6 feat: give a delegate access to mail, calendars and contacts in one step 2026-10-28 05:11:23 +01:00
Linus Rath 60167f752f fix: label mail as External when any sender is outside or has no domain, and show the domain on a tap 2026-10-28 05:09:35 +01:00
Linus Rath 836dcba66e fix: don't count senders whose images the user allowed as contacts for the external recipient confirm 2026-10-28 05:09:03 +01:00
Linus Rath c51245081a test: sign quick replies addressed through the envelope and keep the disclaimer out of sign-out drafts 2026-10-28 04:57:09 +01:00
Linus Rath 2ace501871 Merge branch 'feat/org-features' into feat/org-signatures 2026-10-28 04:51:22 +01:00
Linus Rath 2e34759f54 fix: show a folder shared read only on Stalwart 1.0 as read only, not custom 2026-10-28 04:50:08 +01:00
Linus Rath 9aa810f20d refactor: keep the share rights presets in one module for every share dialog 2026-10-28 04:46:45 +01:00
Linus Rath d128503db5 fix: use the organisation policy of the account a message is sent from 2026-10-28 04:32:39 +01:00
Linus Rath 4bb596a9a0 test: cover the plugin API's own no-third-party locks #903 2026-10-28 04:30:43 +01:00
Linus Rath 010e9fb6d9 feat: fence a Lite build made with no third-party traffic to its own hosts #903 2026-10-28 04:30:42 +01:00
Linus Rath 1a747ac9dd feat: limit the page's CSP to the configured hosts with no third-party traffic #903 2026-10-28 04:30:41 +01:00
Linus Rath 381494fe34 fix: move push registrations to the organisation's relay when the relay changes #903 2026-10-28 04:30:33 +01:00