Commit Graph
1395 Commits
Author SHA1 Message Date
Linus Rath 4b2970ba80 Merge pull request #706 from polastre/check-account-capabilities
fix(jmap): hide Contacts and Calendars when account lacks capability
2026-08-06 00:54:13 +02:00
Linus Rath ab1f89d633 Merge pull request #740 from koolninad/feat/mail-list-refresh-button
feat: add a refresh button to the mail list toolbar
2026-08-06 00:33:40 +02:00
Linus Rath 57d802db85 Merge pull request #704 from guisea/fix/sent-attachment-list-hidden-when-unwrapped
fix: keep sent message/rfc822 attachment visible after inline unwrapping
2026-08-06 00:30:23 +02:00
Linus Rath 87a65e7dd9 Merge pull request #742 from paulhenry46/stalwart-public-keys-encryption-at-rest
feat: manage public keys and at rest encryption
2026-08-06 00:29:02 +02:00
Paulhenry Saux 3b519c3b3b feat: manage public keys and at rest encryption 2026-08-05 21:46:42 +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 e27f17b796 Merge pull request #736 from dealerweb/fix/calendar-parse-debug-log
fix: route the calendar parse dump through the debug logger
2026-08-05 17:20:32 +02:00
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 151af5ced0 Merge branch 'main' of https://github.com/bulwarkmail/webmail 2026-08-05 17:19:40 +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
dealerweb 264a8493fb fix: route the calendar parse dump through the debug logger
Opening a message with a calendar invitation printed the whole parsed
event to the console on every render - title, description, attendees and
location included - through a leftover `[PARSE DEBUG]` console.log.

The surrounding file already logs via debug.log('calendar', ...) in 22
places, which honours the debugMode setting and its category filters, so
this one line was the outlier. It also ran JSON.stringify with
indentation unconditionally, even though nothing was listening.

Passing the object to debug.log instead leaves the formatting to the
logger, so nothing is serialised unless the calendar debug category is
actually switched on.
2026-08-05 14:40:21 +02:00
Linus Rath e94a1429d5 Merge pull request #724 from paulhenry46/userlogout-api-hook
feat: implement existing hooks onBeforeLogout and onAfterLogout + new plugin API method
2026-08-01 23:09:39 +02:00
Linus Rath 15982c2468 Merge pull request #708 from paulhenry46/user-api-plugin
feat(plugins): add 2 new methods : getAccounts and getIdentities
2026-08-01 23:06:53 +02:00
Paulhenry Saux d15c58f8da feat: implement logout hook and add a new plugin api method to perform logout 2026-08-01 21:46:33 +02:00
Paulhenry Saux 6698ec8456 Merge branch 'bulwarkmail:main' into user-api-plugin 2026-08-01 20:24:08 +02:00
Linus Rath e738941950 Merge branch 'main' of https://github.com/bulwarkmail/webmail 2026-08-01 12:28:21 +02:00
Linus Rath 1890cade08 fix: surface underlying network error cause in JMAP passthrough failures 2026-08-01 11:47:16 +02:00
Linus Rath fc7fec44a8 Merge pull request #714 from MathyV/respect-max-calls
fix: make bulwark respect server limits
2026-07-31 05:43:26 +02:00
Mathy Vanvoorden 1652a0ec62 fix: make bulwark respect server limits
If you have a large number of tags, getTagCounts would not be able to get the
unread counts because it did not respect maxCallsInRequest, even though the
value was actually read out, it was just ignored. There are also other places
where the limits were not respected.

Batching is now generalized in a helper that also takes maxObjectsInSet, which
also was ignored, into account and is applied to all functions.

In addition, the dev mock now also advertises and enforces the limits, so these
issues can get picked up during development.

Possible closes #699
Possibly closes #399
2026-07-30 22:11:40 +02:00
Linus Rath e659fe3d38 feat: allow contact cards for organizations #701 2026-07-30 19:44:36 +02:00
Linus Rath 348e032dce fix: files show creation date instead of modification date #700 2026-07-30 19:41:02 +02:00
Linus Rath a6c15b8ad6 fix: empty folder stopped after 500 emails #711 2026-07-30 19:40:25 +02:00
Linus Rath 5a2bc6b671 Merge branch 'main' of https://github.com/bulwarkmail/webmail
# Conflicts:
#	app/api/dev-jmap/[...path]/route.ts
2026-07-30 19:17:43 +02:00
Linus Rath 59bc7fd64c fix: reply to own thread message addresses original recipients #703 2026-07-30 19:02:39 +02:00
Linus Rath aa7a814b86 test: rewrite mock email content 2026-07-30 18:44:53 +02:00
Linus Rath c5c6509867 Merge pull request #710 from MathyV/nested-tags
Nested tags
2026-07-30 18:41:22 +02:00
Linus Rath 1cdbf75270 fix: use full tag path in drag-drop toasts, fresh email in context menu markAsRead
Nested tag toasts from drag-and-drop only showed the leaf name for
non-root tags, contradicting the comment above it and making two
same-named leaves under different parents (e.g. Personal/Receipts vs
Work/Receipts) indistinguishable in the toast.

The context menu's markAsRead handler was the one action left reading
the stale contextMenu.data instead of the live-refreshed
contextMenuEmail introduced alongside it, so it could act on outdated
email state while every sibling handler was already updated.
2026-07-30 18:39:49 +02:00
Mathy Vanvoorden ea7892b497 feat: Change the dev mode defaults to include nested tags 2026-07-29 19:52:31 +02:00
Mathy Vanvoorden d52dfebad4 Fix Catalan translation warnings 2026-07-29 19:16:31 +02:00
Mathy Vanvoorden 7bb58f4f9f Add translations for new tag functionality 2026-07-29 19:14:28 +02:00
Mathy Vanvoorden f1e1ed1df7 fix: make the tint of selected rows work the same way in dark and light mode 2026-07-29 17:18:42 +02:00
Mathy Vanvoorden d9d9f91a86 feat: Make it easier to handle multiple tags
- Tags can now be removed straight from the email header
- Tagging control now allows the user to (de)select multiple tags in one go
2026-07-29 17:18:42 +02:00
Mathy Vanvoorden 108406a885 feat: improve visualization of tags
Previously tags where very much focused on color coding email and less about
adding additional information. They were also visualized in different ways in
different locations.

This commit gets rid of all "Color-coding" references, aligns visualization of
the tags across the whole project and tries to improve user experience of using
tags in general.

A search box is shown in the tagging control so the user can quickly search for
a tag if they have a huge (more than 10) amount of tags.
2026-07-29 17:18:42 +02:00
Mathy Vanvoorden 013ef7d557 fix: remove unused code
This code is nowhere used, so to prevent extra work during an upcoming refactor
of tags, it is removed and some related tests are now actually made useful
2026-07-29 17:18:42 +02:00
Mathy Vanvoorden 56d11b5759 fix: remove the reset-to-defaults button from tag settings
If you carefully crafted your tags and then click this button by accident, all
your hard work is gone. A confirmation message would be the other solution but
since I have difficulty to grasp when you would need such a button, I propose
to just remove it.
2026-07-29 17:18:42 +02:00
Mathy Vanvoorden 0c1e238223 feat: allow hidden tags, either permanent or when there are no unread messages 2026-07-29 17:18:42 +02:00
Mathy Vanvoorden ca0ba818b7 feat: Add nesting of tags in a tree
- levels are joined by forward slashes in the keywords
- behaviour is opt-in for now
- long paths are shortened if there is not enough display room

Closes #687.
2026-07-29 17:18:38 +02:00
Linus Rath ce97a54aaa Merge pull request #705 from guisea/fix/forward-as-attachment-filename-privacy
fix: strip from/to names from forward-as-attachment filenames
2026-07-29 17:15:12 +02:00
Linus Rath b605b6d49d Merge pull request #707 from paulhenry46/prf-secu-fix
fix(plugins): prevent a privileged plugin to get PRF secret of anothe…
2026-07-29 17:14:52 +02:00
Linus Rath cea3ec0fe6 Merge pull request #709 from MathyV/fix-animations
fix: restore animations and replace tailwind.config.ts
2026-07-29 16:53:46 +02:00
Mathy Vanvoorden f56ca594dc fix: restore animations and replace tailwind.config.ts
- tailwind.config.ts is not actually being used so removed
- moved animate-fade-in to globals.css
- added tw-animate-css package to make animate-in work
- added a definition for animate-shake as it doesn't exist in tw-animate-css
2026-07-29 15:59:45 +02:00
Paulhenry Saux 66ff523553 feat(plugins): add 2 new methods : user.getAccounts and user.getIdentities 2026-07-29 13:14:09 +02:00
Paulhenry Saux 7969fd09eb fix(plugins): prevent a privileged plugin to get PRF secret of another privileged plugin 2026-07-29 11:30:12 +02:00
Aaron Guise 3108b2f336 fix: avoid leaving TZ="undefined" when restoring an unset timezone
process.env coerces assigned values to strings, so
process.env.TZ = originalTZ left the literal string "undefined"
behind (instead of clearing TZ) when it was unset before the test
ran. Delete the var in that case instead of assigning undefined.
2026-07-29 13:31:56 +12:00
local 57f2185f0f fix(jmap): hide Contacts and Calendars when account lacks capability
supportsContacts and supportsCalendars checked the server-wide session
capability. An account with jmap-contact-* / dav-card-* revoked still got
Contacts, and one with jmap-calendar-* / dav-cal-* revoked still got
Calendars, with every action failing on an authorization error.
2026-07-28 17:15:07 -07:00
Aaron Guise 71565e9328 test: restore TZ after pinning it in forward-as-attachment tests
Setting process.env.TZ at module scope without restoring it could leak
into other test files sharing the same Vitest worker. Match the
beforeAll/afterAll restore pattern already used in
lib/__tests__/calendar-utils.test.ts.
2026-07-29 11:47:42 +12:00
Aaron Guise edd11ac27b fix: strip from/to names from forward-as-attachment filenames
buildForwardAsAttachmentPayload named the synthetic .eml attachment
using the user's own emailDownloadTemplate, which by default embeds
sender/recipient display names. Since this attachment can go to an
external recipient (e.g. an upstream spam gateway, or anyone else),
the filename now always renders as "{date}-{subject}.eml" regardless
of the user's configured template, while still honoring their
space/case/diacritics preferences.
2026-07-29 11:41:34 +12:00
Aaron Guise aad6bbd028 fix: keep the message/rfc822 attachment visible after inline unwrapping
The "empty outer body + message/rfc822 attachment" unwrap heuristic
(built for Outlook's blank-body forwards) was also matching Forward as
attachment sends, which intentionally use a blank body. Once unwrapped
for inline preview, the .eml attachment itself was filtered out of the
attachment list, so a sent forward-as-attachment message with a large
attached .eml appeared to have no attachments at all.
2026-07-29 11:40:34 +12:00
Linus Rath f81b02ead9 Merge pull request #697 from shukiv/fix-impersonation-stale-account
fix(impersonation): reconcile stale account chip after handoff
2026-07-27 17:06:15 +02:00