Commit Graph
2262 Commits
Author SHA1 Message Date
Linus Rath c48b4428fa Merge pull request #1489 from VasilisNtovolos/fix/discard-pending-uploads
fix: cancel pending attachment uploads when discarding a draft
2026-11-01 18:10:50 +01:00
Linus Rath e4338ac47d feat: add the Search in setting to Message list settings #1485 2026-11-01 17:44:15 +01:00
Linus Rath aaafe428fe test: expect the full send options in the Pro compose draft account test #523 2026-11-01 17:40:53 +01:00
Linus Rath 300d49a917 test: give the push prompt test's settings store mock the calendar sync bridge 2026-11-01 17:38:58 +01:00
Linus Rath 1b2281a4fc fix: stop the sidebar re-rendering on every message open #1486 2026-11-01 17:36:29 +01:00
VasilisNtovolos 2a9a02b782 fix: cancel pending attachment uploads when discarding a draft 2026-11-01 18:00:10 +02:00
Linus Rath 4b60fcc1e6 fix: make the offline outbox never send twice, never lose mail silently and never skip a plugin #523
The review of offline mode found ways to send a message twice, to lose
unsent mail without a word, and to send mail without its signing,
encryption or check plugin. This fixes them and the smaller findings:

- each outbox message is taken for sending in one database transaction
  under a Web Lock per account; only a failure before the submission
  request (SendNotStartedError from the client) puts it back, any other
  one marks it "may have gone out"; read-backs after the submission no
  longer fail a send; a send of a closed tab turns uncertain after a minute
- every sign-out the user didn't confirm names the deleted messages on
  the sign-in page, or in a toast when another account stays signed in
- nothing is queued while an enabled plugin isn't running (after a start
  without the network none can); the composer says why
- the outbox waits for a fresh policy and holds messages the rules have
  since made stricter (a required label, a required send check)
- another tab switching offline mode off sticks: only switching it on
  may create the database
- only attachments of kept messages are kept, filed with their message,
  deleted with it and under the cap between syncs; file names and types
  are sealed; folders that went away leave the scope, and a folder that
  couldn't be asked keeps its mail without holding the others back
- a group scope that forbids offline mode waits until the account's
  groups are known; one server down no longer holds another's mail
- an offline start only when the server is really unreachable, and the
  real sign-in follows by itself once it answers
- the service worker files pages and chunks under the build that served
  them, and the shell list of another build isn't kept under this one
- a raw send counts as the composer's only from the plugin running its
  takeover, for that identity
- errors and refusals are in all languages; the banner tells "offline"
  from "server can't be reached"; outbox buttons name their message;
  changes and messages go in the order they were made
2026-11-01 14:19:54 +01:00
Linus Rath 52188f54d6 Merge branch 'feat/enterprise-pack' into feat/enterprise-pack-f 2026-11-01 13:50:22 +01:00
Linus Rath e9b235bab2 Merge branch 'main' into feat/enterprise-pack
# Conflicts:
#	components/admin/admin-shell.tsx
#	lib/admin/outgoing-hosts-registry.ts
#	lib/admin/reachable-hosts.ts
#	scripts/lite/build.mjs
#	stores/policy-store.ts
2026-11-01 13:46:59 +01:00
Linus Rath 8b23c81372 fix: let the new build's service worker take over once a tab runs that build #523 2026-11-01 12:38:59 +01:00
Linus Rath da4c880c5f fix: open the offline outbox from the banner without leaving the page #523 2026-11-01 12:14:50 +01:00
Linus Rath 5fa1722392 feat: let admins forbid offline mode 2026-11-01 11:46:11 +01:00
Linus Rath db5ac82f53 feat: keep recent mail on this device and send mail written offline #523
Settings > Backup & reset gets "Keep mail on this device", off until the
user turns it on in this browser. While it is on:

- the JMAP client hands the server's answers to an encrypted cache in
  IndexedDB (AES-GCM, non-extractable key) and answers from it when the
  network is gone: the folder list, the last 30 days of the Inbox and of
  the folders the user opened, bodies and attachments, at most 250 MB,
  oldest out first; a background sync keeps it current
- read, flag, tags and moves made offline are queued and sent in order
  when the server answers again; deleting for good and emptying a folder
  are refused offline
- the composer, quick reply and the S/MIME and PGP plugins' sends that
  complete the composer's go to an outbox once every step up to the
  transport ran (checks, label, signature, plugin send checks); only the
  finished send waits, with files attached offline
- the service worker keeps this build's app shell, so the app also
  starts offline from the kept session and the last policy
- a full sign-out, the idle sign-out and signing one account out delete
  it, a sign-out the user starts asks first when mail is unsent, and the
  login page names what an automatic sign-out deleted; a policy fetch
  that forbids it (devices.noOffline) wipes that account

Not in Lite.
2026-11-01 11:46:11 +01:00
Linus Rath 91be465cbc feat: version the service worker by build and offer a reload after a deploy 2026-11-01 11:13:31 +01:00
Linus Rath a480ddb6d1 Merge branch 'feat/enterprise-pack-e' 2026-11-01 10:52:08 +01:00
Linus Rath 465320dbfb test: say no plugin checks sends in the composer draft-login test
The test's mocked onBeforeEmailSend had no size, so the composer took
it for a listening send check and built the check's message, which
reads the sending login's identities from a client the test mocks
without getIdentities; the send stopped there. The real bus without a
plugin has size 0, which the mock now says too.
2026-11-01 10:51:54 +01:00
Linus Rath 0401352e6e Merge branch 'feat/enterprise-pack-d'
# Conflicts:
#	components/email/thread-conversation-view.tsx
#	lib/admin/outgoing-hosts-registry.ts
2026-11-01 10:48:21 +01:00
Linus Rath 27e4f0cbac test: cover the file type the composer tells upload checks 2026-11-01 10:09:20 +01:00
Linus Rath 0c8d4ad93e fix: hold sends until required send checks have started, and check what really goes out
- The message for send checks is built after waiting for required
  checks that are still starting: a send right after sign-in gave them
  no external recipients and no file types.
- A plugin's forward is held too while a required check is down, also
  with no plugin listening.
- A plugin the admin forces on that hasn't reached this browser yet (a
  new device, a failed plugin sync) counts as starting.
- A check that stopped working says to reload or tell the admin.
- The files that were checked are the ones sent, and recipients a
  plugin adds after the check are checked again.
- A file Bulwark couldn't read is marked unreadable; a text file
  starting with "MZ" is text, Java and Android apps are told from ZIPs.

Changed assertions: runPluginSendCheck takes a builder and reports
guard-loading or guard-failed instead of guard-down; the composer test
of an auto-disabled guard expects the stopped_working text; the sniff
tests give programs a zero byte, as real ones have, and expect
unreadable on a file that can't be read.
2026-11-01 10:02:58 +01:00
Linus Rath fbf85972c5 fix: check links in plain-text mail and the address the browser really opens
Plain-text bodies render in the page, not in the body iframe, so their
links opened without the link check. Plugins now get each link as the
browser parses it (new URL(href).href) and that same string opens, so a
link check can't judge one host while another opens. With no link check
listening, clicks and middle-clicks stay with the browser as before.
2026-11-01 09:51:00 +01:00
Linus Rath c11d8ade44 test: cover the plugin, .eml preview, drag-out, export file and install banner paths of the device policies 2026-11-01 09:50:35 +01:00
Linus Rath a4b140b651 fix: keep out-of-office dates right when the time zone setting arrives or changes after the page opened 2026-11-01 09:48:58 +01:00
Linus Rath 9f8d134e85 fix: keep pictures in messages and the Files image preview from being saved under No downloads, and say the mobile app's notifications aren't covered yet 2026-11-01 09:47:28 +01:00
Linus Rath b58dc1d66b fix: apply the device policy and retention line of the account whose folder is open, and keep Copy to account from moving mail out of a restricted account 2026-11-01 09:42:19 +01:00
Linus Rath 61733d839f fix: show an announcement that arrives after its start, once in the Pro shell, and keep it closed when only its times move
- The banner judged its start and end by the time it was mounted, so an
  announcement fetched later than its start never showed in that tab.
- The Pro shell shows it once above its panes; email and folder tabs had
  none and split panes showed it twice.
- Screen readers get it from a live region that fills a moment after it
  is in the page; text present when a live region appears isn't read out
  reliably. The tests that checked the strip's role now check that region.
- Moving the start or end no longer shows a closed announcement again;
  the lib test that expected a new end time to reset it now expects the
  opposite.
2026-11-01 09:39:36 +01:00
Linus Rath e80f5ade81 feat: let admins turn off downloads, export, printing and the install prompt, and add a watermark
Organisation > Devices now sets policy.json `organisation.devices`, each
switch off by default and scoped per domain or group:

- No downloads: attachments and files only preview (reader, conversation
  view, Pro tab, list chips, .eml previews, the Files app). Download,
  Download all, Open in new tab, Save to Files, drag-out, the browser's
  PDF viewer (pdf.js instead) and media download controls go away.
- No export: no .eml export, View source, message drag-out, or folder and
  account export; a running export stops and its file is deleted when
  the switch turns on. Import stays.
- No printing: no Print buttons in mail, calendar and contacts; Ctrl+P
  prints a note; the reader frame prints blank.
- No install prompt: no card, and the browser's own banner is held back.
- Watermark: the user's address and the date over the reader,
  previews and every printout (mail, calendar, contacts, plugins).

A message follows its own account's policy; what isn't about one message
follows the strictest signed-in account. Every user path hides its
button, and the anchor and new-tab helpers refuse as a backstop
(lib/download-guard.ts), never the blob readers. The plugin APIs
`ui.downloadFile` and `ui.print` refuse too, and the office editor frame
loses `allow-downloads`.

Two assertions in components/mail/__tests__/blob-routing.test.tsx now
expect `{ kind: 'export' }` as the fifth argument of downloadBlob for an
.eml export: the export says what it is, so the backstop checks "No
export" rather than "No downloads" for it.
2026-11-01 08:52:34 +01:00
Linus Rath e73a1b375f feat: let link-check plugins reach an admin-set service with no third-party traffic
The plugin host tests compared api.host.features with an object of two
flags; they now include the new noThirdPartyTraffic flag.
2026-11-01 08:39:35 +01:00
Linus Rath b3369c7e78 feat: send every link click through the link check 2026-11-01 08:31:27 +01:00
Linus Rath c004587158 feat: keep sending blocked while a required send check isn't running 2026-11-01 08:22:32 +01:00
Linus Rath edf619a19d feat: give send-check plugins the authored text, external recipients and attachment types 2026-11-01 08:16:39 +01:00
Linus Rath 923ecce7d2 feat: say how long Trash and Junk keep mail 2026-11-01 08:07:06 +01:00
Linus Rath 6cbd53c827 fix: run plugin send checks for quick replies 2026-11-01 08:06:49 +01:00
Linus Rath 47784cc07a feat: offer admin out-of-office templates and show the absence dates in the user's time zone 2026-11-01 08:02:39 +01:00
Linus Rath b99003956a feat: show an admin announcement across the apps 2026-11-01 07:51:46 +01:00
Linus Rath 2a952f4b72 Merge branch 'feat/enterprise-pack-c'
# Conflicts:
#	lib/sign-out-cleanup.ts
2026-11-01 07:39:30 +01:00
Linus Rath ebb33619a0 Merge branch 'feat/enterprise-pack-a' 2026-11-01 07:36:59 +01:00
Linus Rath 1bb2a85de4 fix: translate the turned-off link note and tidy the label and phishing texts
The VS-NfD warning test now expects "BSI-approved products", the corrected wording.
2026-11-01 07:14:10 +01:00
Linus Rath f61fd7922c fix: find an invitation's copy in a group or shared account before answering from the banner #634 2026-11-01 07:09:25 +01:00
Linus Rath f0c0bbe0d2 test: cover another account's labels, removing trusted senders under the lock and the address field without timing 2026-11-01 07:08:45 +01:00
Linus Rath 13c57414a2 fix: report phishing per account from every view and keep a reported message's links off everywhere
- Pro tabs stamp a message of another login or a shared account with
  where it came from, so the report and the move use its account.
- A selection across accounts names every address its reports go to,
  and Undo says how many messages came back.
- A message the list doesn't hold runs the plugins' spam hooks too, and
  every open view shows a reported message as reported at once.
- A reported message hides its unsubscribe banner, and links are off in
  its attachment previews.
- Search results and All mail don't offer reporting the user's own sent
  mail; the Mountain View selection bar offers it.
- The focus goes back to the button that opened the menu.
- ARF names the delivered-to address (or leaves it out), says binary for
  bare line breaks and long lines, and refuses a message bigger than the
  server's upload limit before downloading it.

The phishing tests that compared one address now compare the list of
addresses, and the ARF builder test passes the encoding, not a flag.
2026-11-01 07:07:30 +01:00
Linus Rath cbd23db2fe fix: give mail import and export their own settings section and name the upload limit as the server does
- Settings > Backup & reset gets a Mail files section for Import mail
  and Export all mail, instead of sitting under settings backup.
- The pause message names Stalwart's 50000000-byte quota as 50 MB, not
  48 MB, and the dialog and settings texts mention .ost files.
- The old import's leftovers go: expandImportableEmails and
  EML_IMPORT_ACCEPT in lib/eml-import.ts, and the strings
  email_viewer.import_email, mailbox_context_menu.import_email and
  notifications.import_email_success/_error in all 30 locales.

lib/__tests__/eml-import.test.ts loses the tests of the removed
functions; its #891 checks that an .eml and an .eml in a ZIP keep their
Date header now run against the import's own sources.
2026-11-01 07:05:02 +01:00
Linus Rath 75aa66e0d9 feat: say when an import or export running in the background ends, and keep the focus in its dialog 2026-11-01 07:01:28 +01:00
Linus Rath 3d7a4298eb fix: list company calendars in the calendar list on phones 2026-11-01 06:56:03 +01:00
Linus Rath eb8fb84867 fix: let admins name msip_labels as the extra label header and refuse names the server won't take
The labels-section test's expected error text changes with the message, which now says why a name is refused.
2026-11-01 06:54:50 +01:00
Linus Rath 85deb006a8 fix: keep plugin raw sends from dropping or forging the classification label
Raw sends (api.jmap.sendRaw and submitRaw) now always lose label headers
a plugin wrote while the organisation uses labels. A crypto takeover is
matched to its raw send by a labelToken the composer puts in the
onComposeSend request (plugins that don't pass it back are matched by
identity, and refused when two takeovers are open), not by comparing
subjects. A raw send outside a takeover gets the default label, or is
refused when a label is required. The extra header is folded on the raw
path. The takeover code moves to lib/outgoing/classification-raw.ts;
the old test that let a raw send outside a takeover through unlabelled
now expects the forged header to be removed.
2026-11-01 06:52:44 +01:00
Linus Rath 9d4d3261da fix: clear exported mail from the browser's storage and say plainly where an export goes
- The private file an export writes in Firefox and Safari is deleted
  when the app starts and when someone signs in, not only at the next
  export, and at once on sign-out. Close keeps it until its download
  had time to finish. Each tab holds its own files under a Web Lock, so
  one tab's sweep no longer deletes another tab's running export.
- A browser whose private file system can't write files (Safari before
  26) is told the export stays in memory instead of being promised a
  download.
- The export's live region announces only the phase and pauses; the
  count next to it no longer floods screen readers, and the format
  group is named once.
2026-11-01 06:50:13 +01:00
Linus Rath 595f23556f fix: let Suggest times skip the edited event's own time and close on Escape from its button
Also says how many times it found to screen readers, and the attendee
line for an address the server won't look up reads "Couldn't look up
this address".
2026-11-01 06:49:29 +01:00
Linus Rath 3ef16f602e fix: keep a message's label through Undo send and take over labels only from internal senders
A sent message brought back by Undo, Cancel and edit or edit-as-new
reopened with the default label, because only drafts carried the
X-Bulwark-Label marker; it now falls back to the SIO-Label it went out
with. A reply, quick reply or plugin forward takes over the original's
label only when an internal sender set it and never one below the
default, since anyone outside can write the header. The tests written
for the earlier rule (any received label counts) now pass an internal
sender, which is why their originals changed.
2026-11-01 06:48:01 +01:00
Linus Rath 7102a6f0cb fix: read Outlook files more safely and put their special folders in the right place
- A message whose attachments are bigger than the server takes is
  skipped before anything is read (a 1 GB attachment took several GB in
  the worker and could crash it), and a worker that stops answering
  ends the import with a message instead of a wait that never ends.
- The items after a broken one in a PST folder are counted as
  unreadable in the summary instead of disappearing.
- Sent Items and Deleted Items are known from the PST's own entry IDs,
  and the Inbox and the others by their names in more languages, so a
  PST imported at the top level fills the user's own folders whatever
  its language. The hint about that shows only for the top level.
- Message-ID, In-Reply-To and Content-ID from the PST can't carry line
  breaks into the rebuilt headers.
2026-11-01 06:45:33 +01:00
Linus Rath 128f61646e fix: hold remote content per account and until scoped locks are known, also in previews and drafts 2026-11-01 06:42:46 +01:00