Commit Graph
119 Commits
Author SHA1 Message Date
Linus Rath dccf4e8b9f chore: merge feat/desktop-offline into the windows branch 2026-11-03 07:31:32 +01:00
Linus Rath d6ae3d172b feat: merge opening files and sharing into the installed app
# Conflicts:
#	components/mail/mail-app.tsx
#	lib/__tests__/sw-harness.ts
2026-11-03 07:11:39 +01:00
Linus Rath f716ea66ee fix: ask before a share starts a message and save nothing until the first edit
Any site could POST a form to the share target on load: with no clicks
the composer opened with its subject and file, and autosave stored a
real draft on the server 2 seconds later. The worker can't see where a
POST came from, and Chromium's link capturing accepts form submissions,
so an installed-app window proves nothing either.

- every share landing now asks first, in every window and browser; a
  text landing address gets the same question. Nothing goes up before
  the answer.
- handed-in text and files are the composer's starting state: no
  autosave, page-close save or sign-out flush before the first real
  edit.
- the worker ignores frames, keeps at most 5 entries and 100 MB for 15
  minutes, sweeps on activate, on each share and from a page timer,
  and seals what it keeps with a key passed in the landing fragment.
  Offline wipes clear it too.
- the server fallback uses the fragment and caps by encoded length:
  3000 Japanese characters made a 27 KB `Location` and a 431.
- a second compose handoff waits until the composer closes, also one
  set aside by reading a message, where it used to replace the first.
- a launch leaving the mail page saves what was just typed first.
- an expired handoff or a missing stored file now says so; shares get
  the control-character stripping and limits of `parseMailto`.

Existing tests changed because the landing moved from the query to the
fragment, stored entries gained a sealed part, and a share now asks
first.
2026-11-03 07:08:38 +01:00
Linus Rath bb2393cf04 feat: open messages and drafts in their own windows and save all attachments to a folder
An installed app had no title bar of its own, no way to save attachments
except a zip, and "pop out" stayed inside the page. A new window was a
second copy of the app that had to restore the session itself, and on
start-up that evicts any login made without "Remember me" from the list
every window shares.

- Title bar: `display_override` with `window-controls-overlay`, one
  `--titlebar-inset` variable at the page roots and skeletons, and a drag
  strip with the window title. 0 without an overlay, so nothing moves.
- Save all to a folder: `showDirectoryPicker`, asking the device policy
  before the picker and before each file, with the zip as the fallback.
- Pop-out routes `/popout/message/<id>` and `/popout/compose`, on offer in
  an installed app or when the desktop bridge has windows. Hidden in Lite.
- A pop-out borrows the main window's session and never evicts or starts a
  token timer. Every renewal now takes a Web Lock, so two windows can't
  send the same refresh token, which Stalwart 1.0 may treat as a replay.
- A draft moves to its window under the same id. A closing window hands
  unsaved text to the main window to save, since its own request wouldn't
  survive the close.
- Read state, drafts, theme and language follow across windows, and
  `html[data-desktop]` gates the app-like behaviour in `app/desktop.css`.
2026-11-03 06:50:21 +01:00
Linus Rath 51c09a1a69 fix: never let a notification's buttons go round plugins, session limits or Trash
Review of the notification actions. With a plugin that may stop a move
or read change, or a silent tab holding the login, the message now
opens instead of the route acting. The route answers 401 under a
session limit, and neither path touches a message since moved to Trash
or Junk. A tab that thawed declines an old click, Archive follows the
gate of the notification's login and files into a shared-out Archive
as the app's button does, Reply opens a composer in the Pro shell, the
route retries once when another client made the folder first and
leaves no empty folder behind, and logins match however the server
address is written.

Two assertions of this feature's own tests change: the route answers
401, not 403, when a login's scopes can't be worked out, since that now
also covers session limits; a tab's message to the page now carries
`at`.

The Pro shell's mail surface now reads a parked link's query from the
handoff: the address bar may have none by its first render, which lost
`?slot=` and `?owner=` there too.
2026-11-03 06:28:04 +01:00
Linus Rath 2bb0797996 feat: archive, mark read or reply right from a new mail notification
A notification for one message gets buttons where the browser has room
for them, and a click on its body works as before. The service worker
has no login, so an open tab takes the action first, through the store
actions. With no tab open a new same-origin route, /api/push/action,
does Mark read and Archive with the context cookie. When the cookie is
gone, the token has expired or the login can't be told apart, the
message opens in the app instead. Reply opens the composer through a
`?reply=1` link, with any text typed on the notification.

- `public/sw.js`: buttons, asking open tabs, the route, `sync` handling
- `app/api/push/action`: same-origin, checks the login and the account,
  honours the admin's Archive gate, files by the mirrored archive mode
- `lib/pwa-notify`: the page's side, the mirror for the worker, and
  `requestOutboxSync`, which the offline queue calls
- Background Sync, thin version: a `sync` event tells open tabs to flush

Two push-preview-route assertions change: they match the whole answer
for a named message, which now also carries `login`, what the action
route checks so a stale notification can't act on whoever holds the
cookie slot now.
2026-11-03 05:26:43 +01:00
Linus Rath c021031642 test: cover app launches and shares through the service worker on both servers 2026-11-03 05:26:03 +01:00
Linus Rath 72117c8a71 Merge branch 'main' into feat/proofreading
# Conflicts:
#	components/admin/admin-shell.tsx
2026-11-02 21:27:17 +01:00
Linus Rath dfbeeed142 test: check proofreading at phone width and right to left #1397 2026-11-02 20:59:25 +01:00
Linus Rath 39e137fd22 test: check proofreading in the browser with a test checker plugin #1397 2026-11-02 20:07:55 +01:00
Szymon Chroboczek 62906e45dc fix: preserve mailbox owner in push notification links 2026-11-02 12:47:44 +01:00
Linus Rath 562a3270e3 test: cover the external recipient warning and lost-message naming in the offline spec #523 2026-11-01 14:37:39 +01:00
Linus Rath 46012f2b80 test: cover offline mode, the outbox and the reload after a deploy against the test servers #523 2026-11-01 12:48:46 +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 5b50a23390 test: wait for the message list and a finished Go back before sending in the plugin spec 2026-11-01 10:38:32 +01:00
Linus Rath 0a319cde2e test: fix the quote in a spec title 2026-11-01 10:15:22 +01:00
Linus Rath b9630959b9 test: cover blocked links, held sends and admin-page rules, and wait on conditions instead of clocks 2026-11-01 10:12:49 +01:00
Linus Rath 9b9cbccea9 test: cover another account's folder in the Pro shell, a policy changed while the tab is open, and that blocked paths start no download 2026-11-01 10:05:32 +01:00
Linus Rath 5d48e2a4ef test: cover announcements, out-of-office templates, the retention line and the device policies on the test servers 2026-11-01 09:14:08 +01:00
Linus Rath 7e901cb96b test: cover the link check and the send checks plugins on the test servers 2026-11-01 08:57:20 +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 7f80fd9612 test: cover Undo send keeping the label, Undo after a report and a lock in a group scope on the test servers 2026-11-01 07:36:05 +01:00
Linus Rath dc041a8e17 test: expect the fourth message of the mbox in the phone import 2026-11-01 07:14:48 +01:00
Linus Rath e5159c84ae test: send both answers when the delegate is invited too, answer from the team mailbox banner and check the out-of-office lock 2026-11-01 07:13:47 +01:00
Linus Rath cabcd141d7 test: cover the account export, shared folders, special folders and what a ZIP round trip loses 2026-11-01 07:11:42 +01:00
Linus Rath d9b62dfe9d fix: date imported mbox mail by its Date header unless the envelope line is the arrival time
Thunderbird's envelope line is when a message was copied into the folder, so a migrated folder showed years of mail on one day. The envelope date now counts only on Bulwark's own export lines and on lines with a time zone. The mbox writer tests now expect the export's own envelope sender, bulwark-export, in place of MAILER-DAEMON, which marks those lines.
2026-11-01 06:39:07 +01:00
Linus Rath 0fcdc2ece4 fix: reach a company calendar on a private address only when its host names the intranet 2026-11-01 06:35:56 +01:00
Linus Rath 45d1a0041d test: cover phishing reports, labels and the locked remote-content block against the test servers 2026-11-01 06:07:53 +01:00
Linus Rath 962873800e test: cover suggest times, answering for others, the out-of-office block and company calendars against the test servers 2026-11-01 06:05:25 +01:00
Linus Rath 4676be28e5 test: let held uploads go quietly when the import is cancelled 2026-11-01 05:47:58 +01:00
Linus Rath c74426ffca test: cover mbox and PST import and folder export against the test servers 2026-11-01 05:45:21 +01:00
Linus Rath be07e4780f test: add helpers for the enterprise specs on the test servers 2026-11-01 04:20:02 +01:00
Linus Rath 3f02ae0448 test: add multi-instance scenarios for a three-replica rig behind a round-robin load balancer #1066 2026-11-01 01:33:45 +01:00
Linus Rath 5b8cf60bd9 ci: run the integration suite in the playwright image that matches the installed version 2026-10-31 18:53:00 +01:00
Linus Rath 57a3b97b5e test: cover booking cards end to end on both test servers 2026-10-30 05:58:53 +01:00
Linus Rath ef39fc8615 test: sign the org specs in to the admin through the API, not the login form 2026-10-28 11:06:09 +01:00
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 68756cd088 test: answer the paged archive calls in the recovery spec and check the Trash link stays away from an empty archive #1319 2026-10-28 09:08:44 +01:00
Linus Rath da37d96449 test: cover per-tag saves, the group tag view and the delete warning on phones 2026-10-28 09:01:47 +01:00
Linus Rath 3a03bc363b Merge branch 'feat/org-templates' into feat/org-features 2026-10-28 09:01:42 +01:00
Linus Rath 9d9a50e407 test: cover migrating a browser's templates and hidden personal templates against the test servers 2026-10-28 08:33:05 +01:00
Linus Rath b6d49aac4f test: check that the team inbox badge names bob where the server shares names 2026-10-28 08:25:02 +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 fcd9930e4a test: cover recovering deleted items against the test servers #1319 2026-10-28 08:08:34 +01:00
Linus Rath 62bed18fe8 Merge branch 'feat/org-features' into feat/org-teaminbox 2026-10-28 07:38:25 +01:00
Linus Rath 8d8bc26602 test: check that the team inbox names are kept in the team Inbox on Stalwart v1.0.0 2026-10-28 07:19:08 +01:00
Linus Rath 97d686b916 test: check that the 1.0 test build was asked for shared tags and stayed online 2026-10-28 07:18:16 +01:00