Commit Graph
1454 Commits
Author SHA1 Message Date
Linus Rath 4d404929e2 fix: show the message's own folders in Move to, in mail-client order, with recents and a filter
The Move lists (message menu, reader Move button and its phone panel,
selection toolbar, Move dialog) now share one model in lib/move-menu.ts.
In the desktop app the native copy of the menu lost the shared accounts'
headers and every folder's nesting, so Inbox, Sent, Spam and Trash
showed once per account with nothing to tell them apart.

- Only the message's own account at the top; other accounts a move can
  reach are submenus under their names.
- System folders first (Inbox, Sent, Archive, Spam, Trash), then the
  user's folders by name; subfolders nest, as submenus natively.
- The open folder shows greyed instead of missing.
- A Recent group, a filter field on long lists, and "Choose folder…"
  for the dialog, which has the filter too.

Tests changed: the open folder is now shown disabled rather than left
out, the own account of a shared-mailbox message is a submenu, and the
selection toolbar's filter field has its own label.
2026-11-04 05:20:14 +01:00
Linus Rath bce0c0b744 Merge branch 'feat/desktop-offline' into feat/do-keystore-fixes 2026-11-04 03:52:09 +01:00
Linus Rath 7443654459 Merge branch 'feat/do-package-fixes' into feat/desktop-offline 2026-11-04 03:43:04 +01:00
Linus Rath be8aba2ae7 Merge remote-tracking branch 'origin/main' into feat/desktop-offline
# Conflicts:
#	stores/auth-store.ts
2026-11-04 03:42:18 +01:00
Linus Rath d3308e7729 Merge branch 'feat/desktop-offline' into feat/do-keystore-fixes
# Conflicts:
#	lib/desktop/__tests__/policy-schema.test.ts
2026-11-04 03:31:22 +01:00
Linus Rath 9b61b79d5c fix: sign only CMS signed attributes through api.keystore, and ask a user about a managed plugin's keystore
The shell now takes a message's signed attributes where it took a digest,
so a page can't get a login or TLS digest signed. A quiet option lets a
plugin answer from what's allowed, for anything the user didn't ask for.

An admin's install no longer covers the certificates on someone's own
computer: a managed plugin gets `keystore` when that person says yes, also
when an update adds it, and it's forgotten once everyone has signed out.

Changed test assertions: the fixture plugin needs a grant now, as managed
alone is no longer enough, and the bridge gets an options argument.
2026-11-04 03:23:45 +01:00
Linus Rath 149d08d87b test: load the preview route once before its cases, so a slow import can't spill into them 2026-11-04 03:13:59 +01:00
Linus Rath f39cff2377 fix: call no relay from the worker in no-third-party mode, and handle several accounts in one push side by side 2026-11-04 03:13:59 +01:00
Linus Rath d8e2a4f42c fix: keep a waiting re-sync from undoing what another tab turned off, and note the relay on refresh 2026-11-04 03:13:59 +01:00
Linus Rath 9432345440 fix: keep a nothing-new notification from closing or replacing a real one 2026-11-04 03:13:59 +01:00
Linus Rath 8cb218ce3c fix: apply email notifications off and do not disturb per login, not to every login's mail 2026-11-04 03:13:59 +01:00
Linus Rath 248f9c261b fix: take down push for logins with no connection when signing out of everything 2026-11-04 03:13:59 +01:00
Linus Rath 9bc31b54ab fix: keep notifications generic after the browser closed when the organisation has idle limits 2026-11-04 03:13:59 +01:00
Linus Rath 6dbda4424e fix: stop a stuck push setup from holding up every tab and login 2026-11-04 03:13:58 +01:00
Linus Rath bc8653de8b fix: only replace a browser subscription on the relay's own answer, and move the other logins along 2026-11-04 03:13:58 +01:00
Linus Rath 226b9383ce fix: show a generic notification instead of guessing which login a push is for 2026-11-04 03:13:58 +01:00
Linus Rath f0617a61b1 fix: only treat a server subscription as this browser's when its device id matches 2026-11-04 03:13:58 +01:00
Linus Rath 6ffa0a3715 fix: show the real sender and subject for a push after the browser was closed 2026-11-04 03:13:57 +01:00
Linus Rath 5c62c57657 fix: replace a browser subscription the push service gave up on 2026-11-04 03:13:57 +01:00
Linus Rath a6ef818149 fix: end a login's push registration when it signs out, is removed or wiped 2026-11-04 03:13:57 +01:00
Linus Rath 8b4fb72357 fix: say in plain words why push could not be turned on or off 2026-11-04 03:13:57 +01:00
Linus Rath d520af51b2 fix: restore push when the browser replaces its subscription with no tab open 2026-11-04 03:13:56 +01:00
Linus Rath 8a69c35206 fix: open a notification in the app window, not a pop-out or a frame 2026-11-04 03:13:56 +01:00
Linus Rath 33249ca57a fix: show a notification even if building it fails 2026-11-04 03:13:56 +01:00
Linus Rath 2c462c304e fix: show the right preview when an account id is in more than one login 2026-11-04 03:13:56 +01:00
Linus Rath fc6a209727 fix: keep push notifications off screen with email notifications off or do not disturb on 2026-11-04 03:13:56 +01:00
Linus Rath 7fb0242a7b fix: open the new message from its notification however much older mail is unread 2026-11-04 03:13:56 +01:00
Linus Rath 376465ed80 fix: notify for every account a state-change push names 2026-11-04 03:13:56 +01:00
Linus Rath 6ca6448b5e fix: remove the record from the old relay when push moves to another one 2026-11-04 03:13:56 +01:00
Linus Rath 2551823006 fix: let tabs take turns setting up push so two can't race into two subscriptions 2026-11-04 03:13:55 +01:00
Linus Rath 4586f16c2e fix: remove the unverified subscription when push verification fails, and poll through a network blip 2026-11-04 03:13:55 +01:00
Linus Rath 3a805d1631 fix: restart push verification when the mail server skipped it after a quick off and on 2026-11-04 03:13:55 +01:00
Linus Rath 1c201b0772 fix: stop private files with odd casing and links reaching Docker builds 2026-11-04 03:04:12 +01:00
Linus Rath ab21bf2df3 fix: keep a desktop sign-in in the browser's page until the user says yes
The hand-off parked a password before its question, for up to five
minutes, and on a shared computer another local user could ask for
someone's sign-in with a link of their own. Now nothing leaves the page
before the yes, and the instance has a switch for such machines.

- `/check` tests a password and keeps nothing, `/park` runs on the yes and
  hands over tokens wherever the server allows, a password as a last
  resort
- `/discard` and a timer take out what SSO has to park first, and a no
  revokes the refresh token, and the shared store's TTL is the real expiry
- `DESKTOP_BROWSER_SIGN_IN`, default on, closes the routes, the page's
  hand-off and the app's button; the question says which device asked
- tokens from a typed password stay a password account under the name
  typed (#1432)
- redeem refuses a server of the user's own when the device's rule says
  no
- the park budget is reserved before going upstream, and only failures
  count
- "Not now" ends the flow in the app at once, and the question names the
  account

`desktop-handoff-routes.test.ts` now tests the two-step flow against the
real budgets. `sso-start-route.test.ts`'s config mock answers the new
setting, and the SSO test's expected answer has the account in it.
2026-11-04 02:40:37 +01:00
Linus Rath 1c98e74149 Merge branch 'feat/desktop-offline' into feat/do-browser-signin
# Conflicts:
#	lib/desktop/languages.ts
2026-11-04 01:40:31 +01:00
Linus Rath 37844ce3e5 fix: use the registration endpoint a mail server names when the desktop app signs in through the browser 2026-11-04 01:25:39 +01:00
Linus Rath c8c98e79d4 feat: sign in to the desktop app in your browser, with your password manager
The desktop login page gets "Sign in with your browser…" as its main
button. On an instance it opens the instance's real login page in the
system browser, with a PKCE challenge. The page checks the password or
runs SSO, parks the sign-in under a one-time code, asks once, and sends
the code to the app's loopback listener. This browser gets no session
out of it, and the app's own page redeems the code, so SameSite=Strict
is fine. Standalone runs the mail server's OAuth against the listener,
with a page from main for a server with no OAuth at all.

- `/api/auth/desktop-handoff/park` and `redeem`, and `sso/complete` parks
  tokens the same way for a loopback target
- `auth.claim()`: the calls are taken once per document, in the first
  render, in `WindowControlsHost`
- `BrowserSignIn` policy, default on, with its ADMX and samples
- strings in all 30 languages, and the old button's are gone

`runDesktopBrowserSignIn`'s tests changed because the code no longer goes
through the callback page's address: it's redeemed where it arrives.
2026-11-04 01:09:12 +01:00
Linus Rath 889f6ffbd1 fix: fail requests under way when the desktop app closes its connections, and forget client certificates per account 2026-11-04 00:56:09 +01:00
Linus Rath 423fe28b0b Merge branch 'main' into feat/do-ci-fix 2026-11-03 19:50:46 +01:00
Linus Rath ac2f7cba2b test: allow keystore as the one bare plugin permission, since it has no actions and the S/MIME manifest uses the name 2026-11-03 19:49:56 +01:00
Linus Rath 529d334496 Merge branch 'fix/ui-bug-hunt' 2026-11-03 19:44:46 +01:00
Linus Rath 1e9afb733a fix: let the Docker image build see the script its Next config imports 2026-11-03 19:19:35 +01:00
Linus Rath 5849f9dc42 Merge branch 'main' into feat/desktop-offline 2026-11-03 19:07:04 +01:00
Linus Rath 151cedf992 Merge branch 'feat/do-app-lock' into feat/desktop-offline 2026-11-03 18:46:05 +01:00
Linus Rath deb73cc6e2 Merge branch 'feat/do-native-ui' into feat/desktop-offline 2026-11-03 18:28:49 +01:00
Linus Rath 335e1edc10 Merge branch 'feat/desktop-offline' into feat/do-app-lock
# Conflicts:
#	components/settings/general-settings.tsx
#	hooks/use-calendar-alerts.ts
#	lib/desktop/app-lock-state.ts
#	lib/desktop/policy-schema.ts
#	lib/desktop/types.ts
2026-11-03 17:52:30 +01:00
Linus Rath 3d5b02b75f fix: stop a page reporting once consent goes, and let nothing on disk aim the desktop app's telemetry
A review found that an open page kept sending to a DSN after consent was
taken back, that a state file or config file could name where telemetry
goes, and that `BULWARK_TELEMETRY=off` did nothing on the desktop build.
A due heartbeat now waits a random 30 s to 10 min, a refusal from the
collector isn't retried, crash files go at sign-out and account switch,
and server builds parse stacks as they did.

Existing assertions changed in the desktop telemetry tests: the catch-up
wait is now a range, the endpoint comes from the shell, and the platform
is `desktop` against the collector's patched branch.
2026-11-03 17:38:04 +01:00
Linus Rath 3f264367af fix: harden the app lock: forget in an order that can't leave a sign-in without a PIN, hear wipes and clear subjects while locked, and refuse obvious PINs 2026-11-03 17:08:02 +01:00
Linus Rath 383e579eec feat: run the app to the top of the window, with the window's controls in its own toolbars
The desktop app and an installed PWA had a row across the whole window
with the title and the window controls. That row is gone. The rail,
sidebar, list and reader run to the top of the window in their own
colours, and the controls sit in the top row of whatever is rightmost.

- `lib/window-controls-overlay.ts` finds and marks those rows before
  paint, and they reserve the controls' width through
  `--titlebar-right-inset`
- the rows and the rail are the drag area, everything clickable is
  `no-drag`, and an invisible band lets a page with no row still move
- settings and the admin shell get a row only under the overlay, Pro's
  tab strip and Mountain View's bar match the controls' height
- Alt floats the menu over the top left, in `window-menu-bar.tsx`
- skeletons carry the same marks, so nothing shifts when the app loads
2026-11-03 16:52:42 +01:00
Linus Rath 03cdf69bf2 feat: let desktop users opt in to usage info and crash reports, each with its own switch 2026-11-03 15:55:17 +01:00