Commit Graph
2780 Commits
Author SHA1 Message Date
Matthew Meszaros 5a967cc3ce feat: let an IMAP mailbox exclude folders from sync (email_accounts.sync_skip_folders, migration 000196) so a folder another tool fills never reaches the unified inbox: the worker drops skipped folders and their subfolders before the walk, retires an already-synced one with its stored mail, and removes mail that later moves into one only when its Message-ID is found there; PUT /emails/:id/sync and the drawer's Sync card set the list, GET reports it with the server's folder list, warmbly mailbox skip-folders mirrors it, with docs, OpenAPI and error-code invalid_sync_folder 2026-09-22 05:15:49 -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
Matthew Meszaros 6703e0570a Merge pull request #624 from warmbly/brand/email-signature-wordmark
Add Warmbly wordmark for email signatures
v0.5.5
2026-09-20 11:32:39 +00:00
Matthew Meszaros e04fe778b5 Merge pull request #623 from warmbly/fix/gmail-app-password-connect
feat: fall back to 587 STARTTLS when a mailbox's port 465 never answers, store the port that signed in, and make mailbox connect errors readable
2026-09-20 11:29:39 +00:00
Matthew Meszaros 56286f94e8 Add Warmbly wordmark for email signatures 2026-09-20 13:26:33 +02:00
Matthew Meszaros 4e37b968a2 feat: say in the mailboxes guide and the submission dialer comment that a refusal or an unresolvable name arriving before 587 is dialled is returned as is while a later one lets a connecting 587 be used, instead of claiming 587 would fail the same way 2026-09-20 13:25:46 +02:00
Matthew Meszaros c20d1c99f2 feat: race a 587 STARTTLS dial against a mailbox's silent port 465 on every send and connect check so the fleet keeps sending where outbound 465 is blocked, store a connect that passed that way with 587, name the port actually used in a refusal, make the Google app-password hint say Google itself refused the pair and name the alias and wrong-account causes, and render long error toasts wide, dismissable and longer-lived instead of a narrow four-second column 2026-09-20 13:16:52 +02:00