Matthew Meszaros
00a0a67e0b
Merge pull request #647 from warmbly/fix/unibox-sent-folder-messages
...
feat: advance IMAP folder sync cursors to the selected view and drop the message-map entry when NEW_EMAIL fails to publish (#645 )
2026-09-22 12:03:11 +00:00
Matthew Meszaros
fb453921db
feat: keep a failed message-map rollback pending on the mailbox and retry it at the start of every IMAP, Gmail and Graph sync pass, skipping the pass until it succeeds so an unpublished arrival is never read as known
2026-09-22 04:59:27 -07:00
Matthew Meszaros
9009c6ec24
feat: build inbound bounce and complaint reports before NEW_EMAIL but publish them only after it succeeds, so a message re-offered after a failed arrival publish does not apply its deliverability report twice
2026-09-22 04:49:26 -07:00
Matthew Meszaros
4a6f0c17c7
feat: advance each IMAP folder's sync cursor to the SELECT view its search ran against instead of the earlier LIST-STATUS, so Sent copies appended between the two are no longer skipped, and drop the message-map entry when NEW_EMAIL fails to publish so an unpublished message is re-offered instead of read as known ( #645 )
2026-09-22 04:39:18 -07:00
Matthew Meszaros
c01b7b8dd5
Merge pull request #646 from warmbly/fix/permission-denied-error
...
feat: gate the dashboard version pill's update actions on a two-factor session and give admin_mfa_required its own dialog variant pointing at Settings > Security
2026-09-22 10:45:58 +00:00
Matthew Meszaros
62ea7ef906
feat: gate the dashboard version pill's update actions on a session that presented a second factor, carry session_mfa_verified on the web User model, pass the API error code into the permission-denied event and give admin_mfa_required its own two-factor dialog variant linking to Settings > Security instead of the Roles & access advice, and document the rule on the updates page
2026-09-22 03:42:56 -07:00
Matthew Meszaros
cc898cc040
Merge pull request #641 from warmbly/fix/password-change-session-revocation
...
feat: end every session on a password change and answer with a fresh token pair for the calling device
v0.5.11
2026-09-21 12:03:31 +00:00
Matthew Meszaros
e1989f9116
Merge remote-tracking branch 'origin/main' into fix/password-change-session-revocation
...
# Conflicts:
# internal/app/auth/reset_password.go
2026-09-21 04:56:50 -07:00
Matthew Meszaros
711e89f9fe
Merge pull request #643 from warmbly/fix/sso-link-existing-password-account
...
feat: attach a provider identity to an existing password account only after its password is presented
2026-09-21 11:33:46 +00:00
Matthew Meszaros
eac3f6d615
Merge remote-tracking branch 'origin/main' into fix/sso-link-existing-password-account
...
# Conflicts:
# docs/content/docs/guides/security.mdx
2026-09-21 04:28:20 -07:00
Matthew Meszaros
db0f0c6132
feat: carry the caller's session into ReissueSession from the request instead of looking it up, evict every revoked session from the cache and write a revoked tombstone where the delete is refused, and answer a password change whose reissue failed with the distinct 409 password_changed_sign_in_again that the dashboard turns into a sign-out, documented in error-codes, the endpoint reference and OpenAPI
2026-09-21 04:23:46 -07:00
Matthew Meszaros
ff2204f8ef
feat: route the sso_link completion through the one login path (completeLogin) so the ban check, the 2FA gate, login recording and device memory apply before a parked identity is attached, carry the session provider into every 2FA challenge so a Google or Apple sign-in on a 2FA account is recorded as such, make IdentityRepository.Link report a pair another account holds as ErrIdentityTaken instead of silently updating nothing, refuse a spent address budget before charging a link try, drop the dead expiry check and the duplicate link fields on the web Session model
2026-09-21 03:57:29 -07:00
Matthew Meszaros
e0db7d3c72
Merge pull request #642 from warmbly/fix/reset-token-invalidation-after-password-change
...
feat: refuse a password reset link issued before the password was last changed
2026-09-21 10:50:49 +00:00
Matthew Meszaros
ae143caf3f
Merge pull request #644 from warmbly/fix/account-name-validation
...
feat: validate every person, workspace and company name through internal/pkg/displayname on each write path and render stored names safely in platform email
2026-09-21 10:47:13 +00:00
Matthew Meszaros
4578980b34
feat: fall back to My Organization when the first name is blank in displayname.DefaultWorkspace, and only treat a scheme as a link when a non-space follows its colon so names like Big Data: EU pass in both the Go and web validators
2026-09-21 03:42:17 -07:00
Matthew Meszaros
a1b7a8ad9b
feat: attach a parked federated identity only after the ban check and, on a 2FA account, only once the second factor passes by carrying it through the 2FA pending record into twofa.VerifyLogin, charge each sso_link password attempt atomically before the check, treat an identity a parallel challenge already linked as a re-login instead of a refusal, ask for no password when the identity cannot be linked, end an exhausted or expired challenge with sso_link_expired so the dashboard returns to the email step, and document the code in error-codes, the API reference and OpenAPI
2026-09-21 03:35:17 -07:00
Matthew Meszaros
9426c0da51
feat: validate every person, workspace and company name through internal/pkg/displayname on each write path (profile, onboarding, setup, IdP sign-in, org create and rename, org import, enterprise inquiry, admin testers, warmblyctl) with a 400 invalid_name code, render stored names in platform email through the same rules, mirror them in the web forms, check the org slug format, and document the rules in error-codes, security and AGENTS.md
2026-09-21 03:34:03 -07:00
Matthew Meszaros
0f60fd9b84
feat: attach a Google, Apple or OIDC identity to an existing password account only after that account's password is presented: resolveFederatedUser parks the sign-in as link_required with a single-use sso_link pending token, POST /auth/sso/link checks the password against the provider-asserted address on the sign-in failure budget and links then issues the session through finishLoginAs, the dashboard collects it on a new login step, and the API reference, endpoints list, security guide and OpenAPI spec describe the third login result
2026-09-21 03:25:29 -07:00
Matthew Meszaros
36eb5e72e9
feat: stamp users.password_changed_at on every password write and refuse a password reset link issued at or before it, so a link requested earlier dies when the password is changed from settings, by another reset link or by warmblyctl, with the rule documented on the reset endpoint and the security guide
2026-09-21 03:23:14 -07:00
Matthew Meszaros
7626aaefe4
feat: end every session on a password change, the calling one included, and answer POST /auth/me/password with the token pair of a fresh session for that device; the dashboard stores the new pair, and the endpoint reference, security guide and OpenAPI document the response
2026-09-21 03:18:27 -07:00
Matthew Meszaros
f11df9268f
Merge pull request #640 from warmbly/fix/admin-list-pagination
...
feat: make every admin panel list page past the first and filter by id, and report failed admin requests
2026-09-21 09:29:48 +00:00
Matthew Meszaros
4dde9708c9
feat: honour an ascending created_at sort on the admin users list with a matching id tiebreak, and record an admin API failure whose call omitted the method as GET, the method axios sent
2026-09-21 02:24:36 -07:00
Matthew Meszaros
cc244e5159
feat: make every admin panel list page past the first and filter by id: bind query-string ids through models.ParamUUID since gin cannot set a uuid.UUID, page the explorers and secondary lists by an opaque offset cursor with an id tiebreak instead of an id keyset that disagreed with the sort, page the audit log on (created_at, id) with an inclusive YYYY-MM-DD end day and read next_cursor on its page, cast every before-date bound to timestamptz, coalesce nullable audit ip and user agent, and report failed admin queries and 5xx mutations to PostHog or Sentry with method, path, status, code and request id
2026-09-21 02:11:38 -07:00
Matthew Meszaros
c19e431d36
Merge pull request #638 from warmbly/feat/warmup-mail-retention
...
feat: platform-owned retention of warmup mail in mailboxes, per-message record pruning, and a deletion strike limited to the first day
2026-09-21 08:59:26 +00:00
Matthew Meszaros
3ea6118a27
feat: redeliver a warmup retention delete when the mailbox is not loaded on the worker, drop the stored body when the IMAP message is already gone on a redelivery while returning a search failure rather than treating it as absence, and encode the accepted warmup_retention_days range (0, or 3 to 3650) in both OpenAPI schemas
2026-09-21 01:21:28 -07:00
Matthew Meszaros
0a5e7947b4
feat: return a failed warmup retention delete from the worker so the bus redelivers it up to five times, re-key a Graph message in the map on every move so the sender copy's body can be dropped, never expunge a whole IMAP folder for one message (UID EXPUNGE, else MOVE to Trash, else refuse), build the two retention indexes concurrently in their own migrations 000193 and 000194, keep the dashboard stepper off 1 and 2 days, and describe retention as applying wherever the placement files warmup mail
2026-09-21 01:11:22 -07:00
Matthew Meszaros
1513419a2a
feat: delete warmup mail from each mailbox once past a per-mailbox retention window (email_accounts.warmup_retention_days, else retention.warmup_mail_days, default 30) via a consumer sweep that retires the receipt and sender copy and a worker delete action that trashes on Gmail, deletes on Graph, expunges on IMAP and drops the stored body, prune per-message warmup records after retention.warmup_event_days, and count a warmup deletion as tampering only within 24 hours of arrival and never for a retired message, judging Gmail's Trash label on the same rule
2026-09-21 00:52:02 -07:00
Matthew Meszaros
79850ec9cb
Merge pull request #636 from warmbly/fix/upgrade-dialog-provider-boundary
...
feat: keep the global modals inside UpgradeDialogProvider so the mailbox allowance dialog can offer an upgrade
v0.5.10
2026-09-20 18:11:48 +00:00
Matthew Meszaros
eaa7cfb129
feat: mount the global modals inside UpgradeDialogProvider so the mailbox-allowance dialog can offer the plan that lifts the cap instead of throwing UpgradeDialogProvider not found, and assert the provider boundary so a sibling cannot drift back outside it
2026-09-20 20:08:24 +02:00
Matthew Meszaros
e919d415b0
Merge pull request #634 from warmbly/fix/warmup-pool-reciprocity
...
feat: reciprocal warmup pool: free mailboxes write back to the paying mailboxes that wrote to them, draws favour the inbox owed the most, and inbound volume is capped per day (#633 )
v0.5.9
2026-09-20 17:58:42 +00:00
Matthew Meszaros
bb96cfb030
feat: assert the quarantine term in the tampering-versus-rates band tests and require the expiry to be nil or set on both sides before comparing
2026-09-20 10:53:51 -07:00
Matthew Meszaros
0ea00926c9
feat: apply the warmup inbound cap inside the candidate query before the tier is sized or sampled and count mail dispatched today alongside verified arrivals, judge the tampering band apart from the rate bands and keep the more severe finding, and bound received analytics by UTC instants instead of a session-timezone date cast
2026-09-20 10:15:33 -07:00
Matthew Meszaros
26594391c8
feat: judge tampering with received warmup mail on a ladder inside the health bands, one deletion warns, two pause for seven days and four or two spam flags block for thirty, instead of a review-required block on the first deletion ( #635 )
2026-09-20 09:50:42 -07:00
Matthew Meszaros
d6384d3c0e
feat: make cross-tier warmup an exchange so a proven free mailbox writes back to the paying mailboxes that wrote to it, favour the inbox owed the most on every draw, cap what any inbox receives per day inside WarmupPartnerCandidates so a thin tier is neither starved nor flooded, and surface received counts in the mailbox drawer, warmup analytics and the API ( #633 )
2026-09-20 09:42:53 -07:00
Matthew Meszaros
93a0545955
Merge pull request #632 from warmbly/feat/geoip-mirror-and-resilient-fetch
...
feat: mirror the GeoIP databases and stop a single failed fetch costing a container its geo data
2026-09-20 16:08:00 +00:00
Matthew Meszaros
6026168334
feat: stop blocking boot on the GeoIP download and swap the database in when it lands, retry a refused mirror with backoff honouring Retry-After, revalidate a database older than a week with If-Modified-Since instead of keeping the first copy forever, and add a twice-weekly job mirroring both MaxMind editions to a private bucket so the fleet stops spending a 30-a-day allowance per boot
2026-09-20 17:55:38 +02:00
Matthew Meszaros
a5136f5bf6
Merge pull request #631 from warmbly/fix/inbox-awaiting-reply-actions
...
feat: make Archive leave every working unibox view, fix Awaiting reply's address match, and add row and multi-select triage actions
v0.5.8
2026-09-20 14:24:42 +00:00
Matthew Meszaros
36b7bbfdfb
Merge pull request #630 from warmbly/fix/widen-unibox-email-mailbox
...
feat: widen unibox_emails.mailbox to bigint so high UIDVALIDITY folders can sync
2026-09-20 14:22:59 +00:00
Matthew Meszaros
78fe43b8d2
feat: widen unibox_emails.mailbox to bigint so a folder whose UIDVALIDITY is at or above 2^31 can have its mail filed and listed instead of failing to bind against int4, finishing the widening 000179 started
2026-09-20 16:18:14 +02:00
Matthew Meszaros
7b93e48bd4
feat: make Archive mean something everywhere by keeping filed conversations out of every working unibox view except All mail and the Archive folder, read a mailbox address out of the raw From header so Awaiting reply stops missing every thread sent as "Name <addr>", file and mark read by thread id rather than by message id, and add per-row triage actions plus a multi-select selection bar to the conversation list
2026-09-20 07:16:35 -07:00
Matthew Meszaros
1e11d90cae
Merge pull request #628 from warmbly/fix/unibox-seen-follows-provider
...
Follow the provider's read state in the unibox
2026-09-20 14:01:05 +00:00
Matthew Meszaros
bf8d4b2aa4
Merge pull request #629 from warmbly/ci/serialize-release-runs
...
feat: serialize release workflow runs so two tags cannot race the buildx cache
v0.5.7
2026-09-20 13:57:48 +00:00
Matthew Meszaros
f615c3f4d5
feat: serialize release workflow runs on one concurrency group so two tags pushed close together queue instead of racing the shared buildx cache scope and failing the second build on a missing layer blob
2026-09-20 15:57:02 +02:00
Matthew Meszaros
48ecca2400
feat: follow the provider's read state in the unibox by storing seen from the \Seen flag on every IMAP, Gmail and Graph arrival, carrying read-state changes onto unibox_emails.seen in the FLAGS_ADD/FLAGS_REMOVE and UPDATE_EMAIL handlers, and backfilling existing rows from their flags in 000190
2026-09-20 06:54:29 -07:00
Matthew Meszaros
ab22cb5c6b
Merge pull request #627 from warmbly/fix/public-object-acl-and-passkey-challenge-budget
...
feat: store public objects on buckets that refuse ACLs, and give the passkey login challenge its own per-IP budget
2026-09-20 13:45:59 +00:00
Matthew Meszaros
5b16a09b02
feat: write public objects without a canned ACL so a bucket whose ownership is owner-enforced still stores avatars, form assets, OAuth logos and email-body images, give the passkey login challenge its own per-IP budget separate from the one password sign-in draws on, and surface the API's own message at upload and passkey call sites instead of a generic sentence
2026-09-20 15:40:52 +02:00
Matthew Meszaros
63e26f35f1
Merge pull request #626 from warmbly/brand/email-signature-steel
...
Add steel Warmbly wordmark for theme-agnostic email signatures
2026-09-20 12:59:13 +00:00
Matthew Meszaros
742a173b51
Add steel Warmbly wordmark for theme-agnostic email signatures
2026-09-20 14:58:07 +02:00
Matthew Meszaros
a6630fd9b8
Merge pull request #625 from warmbly/brand/email-signature-dark
...
Add white Warmbly wordmark for dark-mode email signatures
v0.5.6
2026-09-20 11:41:10 +00:00
Matthew Meszaros
876076942a
Add white Warmbly wordmark for dark-mode email signatures
2026-09-20 13:40:13 +02:00