Commit Graph
542 Commits
Author SHA1 Message Date
Linus Rath 565d5c1095 feat: choose exact-address or same-domain matching for reply from received address #1000 2026-09-09 19:27:08 +02:00
Linus Rath c395226926 fix: reject wrong passwords server-side so the browser never shows its Basic Auth dialog #969 2026-09-09 19:21:40 +02:00
Linus Rath 8d8ef7e2f1 fix: unreadable native <select> option lists in dark themes #999
The browser paints a native <select>'s option list itself, so the
bg-muted / text-foreground classes on the control never reach it. Themes
whose --color-muted is translucent (Aurora Glass dark uses
rgba(255,255,255,0.05)) composited to a light popup with near-white
text, leaving every unselected option almost invisible.

Pin option background/colour to the popover tokens, which every built-in
theme defines as an opaque surface, and set color-scheme: dark on
selects under .dark so Safari (which ignores option colours) renders a
dark popup too. Fixes all ~40 native selects at once.

Adds a stylesheet test that locks the rules and asserts every built-in
theme's --color-popover stays opaque in each variant.
2026-09-09 18:30:59 +02:00
Linus Rath 07bbde4786 fix: make the iCal subscription size limit configurable and show the real error #692 2026-09-07 22:34:47 +02:00
Linus Rath 928e2e3794 feat: add a server-side switch for the Stalwart JMAP passthrough #904 2026-09-07 22:34:47 +02:00
Linus Rath e98109b80d fix: require a session for the translate API #903 2026-09-07 22:34:47 +02:00
Linus Rath e095805851 fix: use the selected server's issuer for SSO discovery #952 2026-09-07 22:34:47 +02:00
Linus Rath b4f12b6786 fix: resolve push previews for shared and group mailboxes #839 2026-09-07 22:34:47 +02:00
Linus Rath af234f64a4 fix: drop max_age=0 from OIDC re-authentication requests #938 2026-09-07 22:34:47 +02:00
Linus Rath 2c104f8191 Merge pull request #939 from paulhenry46/plugin_trad_fix
fix: add translations for plugin fetched from marketplace
2026-09-07 17:54:48 +02:00
Almost-Senseless-Coder 5771a213dd feat(auth): Send prompt=select_account to IdM when adding additional accounts. 2026-09-06 10:19:01 +02:00
Linus Rath c075b79cbb feat: global search palette and search tab in the Pro shell #641 2026-09-01 20:55:13 +02:00
Linus Rath 0db6bfdc64 feat: global search core: query parser, ranking, cross-account providers #641 2026-09-01 20:55:12 +02:00
Paulhenry Saux ee35d71582 fix: add translations for plugind from marketplace 2026-09-01 12:06:03 +02:00
Linus Rath 618636d55d fix: copy mock blob bytes into a plain ArrayBuffer for BodyInit compatibility 2026-08-31 23:47:17 +02:00
Linus Rath 1e9b6ac497 fix: FileNode + blob round-trip in dev mock JMAP, WOPI support for same-origin dev server 2026-08-31 23:45:27 +02:00
Linus Rath ca7fbbe416 feat: WOPI office document editing in Files (Collabora/OnlyOffice/EuroOffice) #425 2026-08-31 23:16:19 +02:00
Michael Richter 84617d6186 feat: OAuth handler for plugins; extended contacts and addressbook API 2026-08-31 09:55:06 +02:00
Linus Rath 39dcc6b219 fix: invalidate persisted update status after an upgrade 2026-08-29 12:46:39 +02:00
Linus Rath 4fe5701b3b feat: default sidebar apps for all users #931 2026-08-29 12:31:17 +02:00
Linus Rath 19756e4337 fix: pin resolved IP for stored custom JMAP endpoints and branding URLs 2026-08-26 23:02:19 +02:00
Linus Rath 3288589e52 fix: pin resolved IP at connect time to block DNS-rebinding SSRF (GHSA-24w9-8r42-8jwm) 2026-08-26 22:11:06 +02:00
Linus Rath 63fa2d2d93 fix: stop notifying for spam by using the JMAP emailPush delivery filter 2026-08-26 21:45:12 +02:00
Linus Rath 46ccd2267d fix: pin supported-calendar-component-set on created calendars #760 2026-08-25 19:16:20 +02:00
Linus Rath ed340cc2c1 feat: make Stalwart admin access to the dashboard configurable #870 2026-08-25 18:39:07 +02:00
Linus Rath 65e70a8088 feat: address bar reflects the focused Pro tab + live deep-link delivery to mounted surfaces 2026-08-20 15:35:41 +02:00
Linus Rath 3e5ed4f3c4 feat: folder tabs via drag & drop + sidebar in fullscreen email tabs 2026-08-20 15:06:45 +02:00
Linus Rath 2d5748e6c9 fix: leaving the Pro interface returns to the surface in use and keeps the settings scroll position 2026-08-20 14:35:05 +02:00
Linus Rath 50741d1131 Merge branch 'main' of https://github.com/bulwarkmail/webmail 2026-08-20 14:00:42 +02:00
Linus Rath 9a6cc23876 fix: refresh TOTP-minted tokens with the default client id when no OAuth client is configured #873 2026-08-20 13:59:57 +02:00
KazNIISA IT 5c484af1f7 fix(jmap): escape the JSON Pointer in keyword patches, and migrate a keyword honestly
A PatchObject key is a JSON Pointer (RFC 8620 section 5.3), so a slash
inside the member name it points at has to be escaped as `~1`. Keyword
patches were built as `keywords/${keyword}` verbatim, which is fine for
every flat keyword but wrong for a nested tag: `$label:work/clients`
became the pointer `keywords/$label:work/clients`, asking for the
`clients` member of the `$label:work` keyword rather than for the keyword
itself. The patch is not a boolean at that path, so the server rejects or
ignores it and the tag never lands.

Route the keyword patch sites - setKeyword, removeKeyword, migrateKeyword
and the category-tab batch patch - through `keywordPointer`, which escapes
per RFC 6901 the way the calendar store already does for participant ids.
Flat keywords are untouched, so `$seen`/`$flagged` and friends keep the
exact pointers they had. The dev JMAP mock reads the escaping back, or
nested tags would behave differently against the mock than against a real
server.

migrateKeyword also took any answer as success: a method-level error on
the query read as "no message carries this keyword", one on the write was
ignored outright, and a per-message refusal was invisible - so a rename
that moved nothing still reported a clean migration. It now answers with
{ migrated, refused }, because the work is batched and a failure partway
through cannot undo the batches already applied. A whole batch the server
refuses stops the rest, which it would refuse too; a single message it
refuses does not, the mail behind it being unaffected. A query error
throws, nothing having been written yet, and so does a run that migrated
nothing at all - the case where the caller must not rename a tag over
messages that all kept the old keyword.

The walk over tagged mail was not paginating safely either. It stopped at
the first page shorter than the limit it asked for, but RFC 8620 section
5.5 lets a server clamp that limit, so a clamping server left most of the
mail unmigrated. Positions are also only comparable within one queryState,
which the walk ignored: mail arriving mid-walk shifts every later page. It
now restarts when the state changes under it, and gives up - before any
write, so the caller can simply repeat - once a mailbox has moved under it
three times, rather than mixing ids from states that no longer agree. A
page carrying no id it has not already seen ends the walk, which keeps it
bounded against a server that answers every position with the same page.
2026-08-18 08:15:22 +05:00
Linus Rath c78b964c69 perf: halve time-to-mail-list (lazy locale catalogs, code-split viewer/composer, shorter auth waterfall, boot snapshot) 2026-08-17 01:50:10 +02:00
Linus Rath 344542337a fix: don't export OG_WIDTH/OG_HEIGHT from the og-image route 2026-08-17 00:18:59 +02:00
Linus Rath 22aa328405 feat: branded OpenGraph/Twitter link previews with generated card image 2026-08-16 23:40:25 +02:00
Linus Rath 548200131b feat: pick push relay from an admin-defined list instead of a URL field 2026-08-16 23:13:36 +02:00
Linus Rath 526905aa22 feat: implement AddressBook/set in dev mock JMAP server 2026-08-16 23:08:59 +02:00
Linus Rath 5b8ddc352b feat: pick push relay from admin-defined list instead of a URL field 2026-08-16 23:04:22 +02:00
Linus Rath 5a42b3252b fix: iOS Safari zooms the viewport on every input focus #838 2026-08-16 23:02:27 +02:00
Linus Rath e44f35a203 fix: reuse cached access token on session restore #552 2026-08-16 22:20:07 +02:00
Linus Rath 76f9b96e1d feat: show the server dropdown on the OAuth-only login screen #799 2026-08-16 22:06:22 +02:00
Linus Rath 47cf0ed90d feat: rework pro split-screen shell, per-pane tab strips, drag & drop, pane-scoped overlays 2026-08-16 03:03:40 +02:00
zisisvakras 44360024bc fix: check the specific capability a request declares, not a broader one
contactUsing(), calendarUsing(), and fileUsing() checked the base
"principals" capability but then declared the separate
"principals:owner" sub-capability (RFC 9670) in the request's "using"
array. RFC 8620 section 3.3 requires a server to reject the whole
request if it declares a capability the server does not advertise, so
a server that supports base principals without the owner
sub-capability rejects every one of these requests with
unknownCapability.

Fixed to check the specific sub-capability being declared instead of
assuming it from the broader one. The calendar agenda route had the
same mismatch and is fixed the same way. Note that RFC 9670 section
1.5.2 places principals:owner in accountCapabilities rather than the
session capabilities, so on compliant servers the sub-capability is
simply never declared, which is the intent. Nothing is lost by
omitting it.

The file share test asserted the old behavior by expecting the owner
capability to be declared against a server that advertises only base
principals. It now asserts the capability is omitted in that case and
declared only when the server advertises it. The same pair of
assertions is added for the contacts, calendars, and agenda route
request builders, so each site this commit touches is covered against
regression.
2026-08-12 17:34:20 +03:00
Linus Rath 11b6bdd8a6 fix: sync PWA title bar colour with the active theme #671 2026-08-06 18:23:21 +02:00
Linus Rath d55aba3890 fix: honor configured PWA theme color in desktop title bar #671 2026-08-06 17:40:41 +02:00
Linus Rath e2da05c130 feat: deep links for mail, calendar, contacts, files, settings and improve screen reader support
#733 #722 #721  #720  #719
2026-08-06 16:47:20 +02:00
Linus Rath 6f293bbf04 Merge pull request #729 from MrDeik/agent/push-notification-onboarding
feat: add background notification onboarding
2026-08-06 14:47:31 +02:00
Ninad Chandorkar b797ea88b8 feat: add a refresh button to the mail list toolbar
The only ways to re-fetch mail are the browser refresh gestures (F5,
Ctrl/Cmd+R, pull-to-refresh) that useRefreshGesture intercepts. On a
desktop that is discoverable enough, but there is no visible control,
and users who reach for one find nothing.

Extract the gesture's inline onRefresh into a shared handleManualRefresh
with a spinner state, then reuse it for a refresh button next to the
filter control in the mail-list toolbar. The icon spins while the fetch
is in flight and the button is disabled until it settles, so repeated
clicks can't stack requests.

Uses the existing common.refresh translation key, so no new strings.

Also guard the login submit with rememberMeEnabled: the checkbox is only
rendered when the server has a SESSION_SECRET, but the value was passed
through unconditionally, asking for a credential cookie the server will
not write.
2026-08-05 23:37:36 +05:30
Linus Rath da17464e05 Merge pull request #737 from dealerweb/fix/internal-mailto-links
fix: open address links in the built-in composer
2026-08-05 17:20:18 +02:00
Linus Rath 0fe484efda fix: time out stalled JMAP requests so sends can't hang forever #702 2026-08-05 17:19:10 +02:00
dealerweb 04996a3af1 fix: open address links in the built-in composer
Clicking an address in the app's own chrome - the recipient card, the
contact sidebar, the contact details - handed a mailto: URL to the OS
mail handler. In a webmail client that goes nowhere: the browser asks
which application should open the link, and the message is composed
somewhere else, if at all. Only users who registered Bulwark itself as
their system mailto handler got a usable result, and even then via a
detour through the OS into a new tab.

A new MailtoLink component sends the click to the built-in composer
instead. It stays a real anchor with an href, so "Copy email address",
middle click and assistive technology keep working; only the plain
left click is redirected, and only when a listener takes it - otherwise
the browser's own behaviour still applies. Modified clicks are left
alone.

The request reaches the mail page through a window event, the way
`bulwark:rate-limit-blocked` already does, rather than threading a
callback through three component levels and five call sites. It goes to
openMailtoDraft rather than the protocol path: an in-app click carries
its own context - the account being read - so the account picker that an
external mailto: needs would only get in the way here.

Message content is deliberately untouched. Plain text bodies render into
the main document rather than the sandboxed frame and their sanitizer
permits mailto:, so a document-wide interceptor would have swept up
untrusted links too; a component cannot be reached from message HTML at
all.
2026-08-05 14:42:24 +02:00