Skip to content

Latest commit

 

History

History
957 lines (703 loc) · 36.2 KB

File metadata and controls

957 lines (703 loc) · 36.2 KB

Changelog

6.8.0 (2026.04.21)

Features and Improvements

  • 🔧 Generate mail URLs from app_url setting + route path (#1254)
  • ✨ Add admin UI for restoring deleted users (#1248)
  • ✨ Add maintenance task to remove unredeemed vouchers of deleted users (#1237)

Technical Changes

  • ⬆️ (deps): Bump the github-actions group with 3 updates (#1259)
  • ⬆️ (deps-dev): Bump the npm-dependencies group with 3 updates (#1258)
  • ⬆️ Update composer dependencies (#1257)
  • ♻️ Replace postmaster aliases with RFC address settings (#1252)
  • ⬆️ Bump phpunit/phpunit from 12.5.19 to 12.5.22 (#1251)

Bug Fixes

  • 🐛 Fix stale SMTP quota cache on user/alias update and global settings change (#1261)

Security

  • 🔒 Reject filter-DSL metacharacters in GpgKeyParser email argument (#1250)
  • 🔒 Enforce account-status checks on Keycloak API and consume TOTP backup codes (#1249)

6.7.0 (2026.04.18)

Features and Improvements

  • 💬 Use gender-inclusive language in German translations (#1245)
  • 💄 Align domain show page layout with user show page (#1244)
  • ✨ Add domain filter to all admin entity lists (#1243)
  • ✨ Add admin user show page with detail view and delete action (#1238)

Technical Changes

  • ⬆️ (deps-dev): Bump the npm-dependencies group with 5 updates (#1242)
  • ⬆️ (deps): Bump the github-actions group with 3 updates (#1241)
  • ⬆️ Update composer dependencies (#1240)

Bug Fixes

  • 🐛 Fix domain admin losing role when editing themselves (#1246)
  • 🐛 Fix admin status filter "All" option always reverting to "Active" (#1239)

6.6.1 (2026.04.08)

  • Fix 6.6.0 release (release immutability issue from GitHub)

6.6.0 (2026.04.08)

Features and Improvements

  • ✨ Restructure welcome page with security, OpenPGP, and invitation sections (#1235)
  • ✨ Improve domain invitation settings UI and naming consistency (#1224)
  • ✨ Show notice when invitations are disabled on voucher admin page (#1222)
  • ✨ Allow domain admins to view and edit their own domain settings (#1221)
  • ✨ Grant DOMAIN_ADMIN access to vouchers in admin panel (#1220)
  • ✨ Add per-domain invitation settings, replace REGISTRATION_OPEN (#1218)
  • 🚸 Make password change implications more explicit (#1211)

Technical Changes

  • ♻️ Refactor safe_html to use Symfony HTML Sanitizer config (#1233)
  • ♻️ Extract Domain invitation settings into Doctrine Embeddable (#1230)
  • 🌐 Generalize closed registration translations (#1219)
  • 🔨 Add make setup and make dev targets for easier onboarding (#1216)
  • ♻️ Remove PasswordStrengthHandler and umlaut password restriction (#1207)
  • ⬆️ Update composer dependencies (#1226, #1213, #1208)
  • ⬆️ Update npm dependencies (#1228, #1215, #1209)
  • ⬆️ Update GitHub Actions dependencies (#1227, #1214, #1210)
  • ⬆️ (deps): Bump vite from 8.0.3 to 8.0.5 (#1229)
  • ⬆️ (deps): Bump serialize-javascript from 7.0.4 to 7.0.5 (#1212)
  • ⬆️ (deps): Bump lodash from 4.17.23 to 4.18.1 (#1217)

Bug Fixes

  • 🐛 Fix flaky Behat tests caused by stale element references after modal delete (#1231)
  • 🐛 Allow quote characters in passwords (#1206)
  • 🐛 Fix release script: auth variable, JSON encoding, and timing (#1204)

6.5.0 (2026.03.18)

Features and Improvements

  • 🗃️ Wrap registration flow in database transaction (#1201)
  • 🐳 Switch to Alpine + Caddy, separate Node/PHP build stages (#1192)
  • ✨ Scope dashboard statistics for domain admins (#1181)
  • ✨ Link OpenPGP keys dashboard tile and enable domain admin access (#1170)
  • ✨ Restructure admin area for multi-role access with dashboard (#1169)
  • ✨ Add OpenPGP keys settings page (#1167)
  • 🔥 Remove Sonata Admin Bundle and rename settings to admin (#1166)
  • ✨ Add native User Admin under /settings/users/ (#1165)
  • ✨ Allow OpenPgpKey uploads to WKD for aliases (#1117)

Security

  • 🔒 Invalidate session on logout (#1200)
  • 🔒 Switch CI from pull_request_target to pull_request (#1189)
  • 🔒️ Add missing password validation constraints to RecoveryResetPassword (#1184)
  • 🔒 Extend DomainVoter for aliases and harden AliasController for domain admins (#1179)
  • 🔒 Fix serialize-javascript vulnerability (Dependabot #79) (#1177)
  • 🔒 Add domain authorization for user creation (#1176)
  • 🔒 Prevent domain admin privilege escalation to full admin (#1173)

Technical Changes

  • 🐳 Move Dovecot/Roundcube to mail profile and fix rootless Podman (#1198)
  • 🔇 Suppress Psalm InvalidAttribute false positives (#1196)
  • ♻️ Use Symfony's HTML Sanitizer for safe_html twig filter (#1186)
  • ⏪ Revert serialize-javascript vulnerability fix (#1177) (#1182)
  • 🧪 Add comprehensive domain admin access control Behat tests (#1180)
  • 📝 Add hierarchical AGENTS.md knowledge base (#1174)
  • ♻️ Refactor GpgKeyImporter into GpgKeyParser, introduce GpgKeyResult DTO, and remove dead code (#1172)
  • ♻️ Replace standalone delete pages with password-confirmation modal dialogs (#1164)
  • ♻️ Generalize confirm modal and replace inline JS with Stimulus controller (#1163)
  • ♻️ Remove redundant max-width constraints from page templates (#1162)
  • ♻️ Replace window.confirm() with accessible modal dialogs for delete confirmations (#1161)
  • ✅ Add JavaScript testing support to Behat via Symfony Panther (#1160)
  • ✅ Add unit tests for all remaining Stimulus controllers (#1158)
  • 💚 Fix SonarCloud PR decoration with pull_request_target (#1157)
  • ✅ Add Vitest unit tests for Stimulus controllers and sanitize utility (#1156)
  • 🎨 Widen page layout to max-w-7xl and remove redundant width wrappers (#1151)
  • ⬆️ Update composer dependencies (#1193, #1153)
  • ⬆️ Update npm dependencies (#1197, #1178, #1175, #1154)
  • ⬆️ Update GitHub Actions dependencies (#1195, #1155)

Bug Fixes

  • 🐛 Catch EntityNotFoundException in Admin\AliasController (#1188)
  • 🐛 Validate csrf token in MaintenanceController::run (#1185)
  • 🐛 Fix SonarCloud reliability issues in JS/TS controllers (#1159)

6.4.1 (2026.03.08)

Technical Changes

  • 💚 Scope Docker build concurrency group to git ref (#1147)
  • ♻️ Replace inline onchange handlers with Stimulus navigate controller (#1146)
  • 💚 Fix CI workflows for external (fork) contributions (#1145)
  • ♻️ Merge Builder/ + Sender/ into Mail/ mailer classes (#1144)
  • ♻️ Simplify locale parameters in services.yaml (#1143)
  • ⬆️ (deps-dev): Bump dompurify from 3.3.1 to 3.3.2 (#1118)

6.4.0 (2026.03.08)

Features and Improvements

  • 💄 Improve responsive table layout in settings pages (#1124)
  • 💄 Redesign settings navigation for responsiveness and scalability (#1120)

Security

  • 🔒 Add CSP nonces to inline dark mode scripts (#1142)
  • 🔒 Enable cryptographic signing for all Messenger handlers (#1134)
  • 🔒 Add missing CSRF validation and fix null-safety in settings controllers (#1132)

Technical Changes

  • 🔧 Remove redundant kernel.event_subscriber tag from services.yaml (#1141)
  • ♻️ Replace fluent setters with void setters in OpenPgpKey form model (#1140)
  • ♻️ Use Command::SUCCESS/FAILURE constants instead of literal integers (#1139)
  • ♻️ Add missing readonly keywords to stateless classes (#1137)
  • 🔥 Remove incorrect copy-paste docblocks from MailCryptKeyHandler (#1136)
  • ✅ Fix all PHPUnit deprecations and notices in test suite (#1133)
  • ♻️ Replace Sonata Alias admin with native settings view (#1125)
  • ♻️ Organize controllers into Account, Settings, and Api subdirectories (#1123)
  • ♻️ Replace Sonata Voucher admin with native settings view (#1122)
  • ♻️ Replace Sonata UserNotification admin with native settings view (#1121)
  • ♻️ Replace MAIL_CRYPT env variable with database-backed setting (#1119)
  • ♻️ Unify password confirmation forms and add password-confirmed domain deletion (#1116)
  • ⬆️ (deps): Bump svgo from 3.3.2 to 3.3.3 (#1115)
  • ⬆️ Update composer dependencies (#1112)

Bug Fixes

  • 🐛 Fix TotpSecretValidator return type to match Symfony's void signature (#1138)
  • 🐛 Fix mutable state bug in PasswordStrengthHandler (#1135)

6.3.0 (2026.03.01)

Features and Improvements

  • ✨ Add domain filter for webhook endpoints (#1078)
  • ✨ Add MTA-STS (RFC 8461) support (#1077)
  • ✨ Add domain deletion with CASCADE constraints and async event handling (#1075)
  • ✨ Native domain management and unified Settings UI (#1057)
  • ✨ Add domain field to Voucher entity (#1056)

Security

  • 🔒 Pin GitHub Actions to commit SHAs for supply chain security (#1099)

Technical Changes

  • 👷 Improve Dependabot and CI configuration (#1111, #1107, #1105, #1100, #1095, #1092)
  • 📌 Pin Symfony packages to ^7.4 to prevent unintended Symfony 8 upgrades (#1103)
  • 📝 Consolidate and update development documentation (#1076)
  • ♻️ Fix Makefile (#1074)
  • ♻️ Improve docker dovecot setup and mailcrypt integration (#1073)
  • ♻️ Refactor EmailAddress validator (#1071)
  • ♻️ AliasAdmin: Relax EmailAddress() constraint (#1070)
  • ♻️ Serve WKD keys directly from database instead of filesystem (#1067)
  • 🗃️ Rename database tables to remove virtual_ prefix (#1062)
  • ⬆️ Update dependencies (#1110, #1108, #1094, #1068)

Bug Fixes

  • 🐛 Allow composer-diff plugin in global Composer config (#1109)
  • 🐛 Fix misleading Prometheus exporter label for user count (#1081)
  • 🐛 Fix untranslated voucher-invalid flash message (#1069)

6.2.0 (2026.02.22)

Features and Improvements

  • 🔥 Remove unused environment variable (#1059)
  • ✨ Add real-time password strength meter (#1044)
  • ✨ Introduce configurable sending quotas (#955)

Technical Changes

  • ♻️ Migrate WEBMAIL_URL from env var to application setting (#1058)
  • ♻️ Group all authenticated routes under /account/ (#1055)
  • ♻️ Migrate JavaScript to TypeScript (#1054)
  • ♻️ Final cleanup: extract sanitize module, add confirm controller, fix CSRF (#1053)
  • ♻️ Replace password strength inline JS with Stimulus controller (#1052)
  • ♻️ Replace flash notification inline JS with Stimulus controller (#1051)
  • ♻️ Replace tooltip inline JS with Stimulus controller (#1050)
  • ♻️ Replace clipboard JS with @stimulus-components/clipboard (#1049)
  • ♻️ Replace dark mode inline JS with Stimulus controller (#1048)
  • ♻️ Replace inline dropdown JS with Stimulus controller (#1047)
  • ♻️ Activate Stimulus bridge and remove dead frontend code (#1046)
  • ♻️ Refactor registration into two-step flow with voucher check on start page (#1043)
  • 🌐 Remove %domain% variable from translations (#1042)
  • ♻️ Replace domain with app_name setting in browser page titles (#1041)
  • 📝 Merge copilot-instructions.md into AGENTS.md and update guidelines (#1040)
  • ♻️ Replace ReportWeeklyCommand with Scheduler and configurable setting (#1039)
  • ♻️ Refactor UserChangedListener to async ReportSuspiciousChildren pattern (#1038)
  • ♻️ Migrate ReservedName management from SonataAdmin to native Settings UI (#1037)
  • ♻️ Centralize cache key management and increase TTL to 24h (#1036)

Bug Fixes

  • 🐛 Fix optional settings not being saved (#1060)

6.1.0 (2026.02.10)

Features and Improvements

  • 🚸 Improve Error Handling in Dovecot Lua Adapter (#1034)
  • ✨ Add configurable Redis cache support via REDIS_URL (#1033)
  • ⚡ Add caching for Dovecot userdb lookup API (#1027)
  • ⚡ Add caching for Dovecot userdb lookup API (#1027)
  • ⚡ Use lightweight queries and repository methods for Postfix lookups (#1014)
  • ⚡ Add application-level caching for Postfix API endpoints (#1013)
  • ⚡ Throttle API token lastUsedTime updates to every 5 minutes (#1012)

Technical Changes

  • ✅ Add unit tests for 16 previously uncovered classes (#1029)
  • 👷 Add Rector CI workflow that comments on PRs with diffs (#1025)
  • ♻️ Modernize codebase for PHP 8.4 (#1024)
  • ♻️ Extract business logic from RecoveryController into RecoveryHandler (#1023)
  • ♻️ Modernize Event classes: use readonly constructor params, remove traits and setters (#1022)
  • ⬆️ Upgrade PHPUnit from 9.x to 12.x and modernize test suite (#1021)
  • ⬆️ Upgrade scheb/2fa-* from v7 to v8 (#1019)
  • ⬆️ Upgrade Doctrine bundles to latest major versions (#1018)
  • ⬆️ Upgrade Doctrine ORM from 2.x to 3.x (#1017)
  • ♻️ Clean up entity constructors: remove redundant defaults and fix OpenPgpKeys init (#1016)
  • ♻️ Migrate all entities from DateTime to DateTimeImmutable (#1015)

Bug Fixes

  • 🐛 Fix Xdebug blocking all HTTP requests in dev environment (#1032)
  • 🐛 Restore PHPUnit coverage and test result reporting for SonarCloud (#1028)

6.0.0 (2026.02.06)

  • BREAKING CHANGE: This release needs at least PHP 8.4
  • BREAKING CHANGE: The Lua script for Dovecot needs at least Dovecot 2.4

Features and Improvements

  • ✨ Add webhook event for user.reset (#1010)
  • ✨ Allow admins to reset user passwords in UserAdmin (#1007)

Technical Changes

  • ✨ Auto-update updatedTime via Doctrine listener and UpdatedTimeInterface (#1009)
  • ♻️ Encapsulate form model properties with getters/setters (#1006)
  • ♻️ Centralize validation in form models and admin classes (#1002)
  • ⬆️ Update to Debian Trixie and PHP 8.4 (#988)
  • ♻️ Extract UserResetService from Command (#1004)
  • ✅ Convert Controller functional tests to Behat features (#1005)
  • ♻️ Remove code duplication in user commands (#1003)
  • ♻️ Extract TOTP Backup Code Generation from Trait (#997)
  • 🗃️ Migrate 2FA Backup Codes from array to json (#996)

5.5.0 (2026.01.31)

With this release, Userli relies on Doctrine Migrations to handle database schema changes.

Features and Improvements

  • 🗃️ Add missing migration for webhook_deliveries indexes (#992)
  • 🗃️ Add Migration to add notes column (#991)
  • 🗃️ Migrate User roles from array to json (#979)
  • ✨ Add optional note to random alias (#872)
  • 🚸 Improve UX for deleting custom aliases (#873)
  • ✨ Add Filter for Event in Webhook Deliveries (#987)

Bug Fixes

  • 🐛 Fix the initial migration when the database is empty (#989)

5.4.1 (2026.01.23)

Bug Fixes

  • 🐛 Remove only unredeemed vouchers (#985)

5.4.0 (2026.01.17)

Features and Improvements

  • ✨ Add Schedule to remove inactive users (#980)
  • 🔥 Remove direct dependency to Dovecot (#978)

5.3.0 (2026.01.16)

Features and Improvements

  • ✨ Add Pagination for Webhook Deliveries (#962)
  • 💄 Fix Checkboxes for Firefox (#966)
  • ✨ Add Filter for Webhook Deliveries (#967)
  • ⬆️ Upgrade to Symfony 7.4 (#969)
  • 🚸 Prune only succesful webhook deliveries (#974)
  • ♻️ Refactor Retention API to return inactive users instead of deleted users (#976)
  • ♻️ Remove PlainPasswordTrait (#975)

Bug Fixes

  • 🐛 Remove novalidate attribute from login template (#972)

5.2.0 (2026.01.09)

Features and Improvements

  • 💄 Add Dark Mode (#957)
  • ♿️ Improve accessibility (#960)

5.1.1 (2025.12.11)

Bug Fixes

  • 🚑 Fix user creation in admin (#946)

5.1.0 (2025.12.11)

Features and Improvements

  • ✨ Use PHP CS Fixer (#917)
  • 📝 Update documentation for integrations
  • ⬆️ Update Symfony to 6.4.30 (#928)
  • 🔥 Remove Email Normalization in Postfix Controller (#930)
  • 🔒️ Add Psalm configuration file for static analysis (#918)
  • 🚨 Various fixes found by Psalm static analysis (#931, #932, #933, #934, #935, #936, #937, #938, #939, #940, #940)
  • ♻️ Email is required in User constructor (#943)
  • ♻️ Code is required in Voucher constructor (#944)

5.0.0 (2025.11.08)

Features and Improvements

  • ✨ Add option to force password update for users (#858)
  • ✨ Implement role hierarchy and reachable roles functionality (#866)
  • ✨ Introduce API Token Settings (#868)
  • 🔒️ Use session instead of query to transport the new recovery token (#876)
  • 🔒️ Show notification to the user and remove it after the password change (#877)
  • ✨ Introduce Webhook Settings (#874)
  • ♻️ Use Symfony Scheduler for recurring tasks (#882)
  • ♻️ Send welcome mails asynchronously (#883)
  • ✨ Introduce configurable Settings (#887, #888, #892)
  • 🐳 Build Docker Image for multiple platforms (#893)
  • 🐛 Postfix adapter: Handle '+'-delimiter in email local part
  • ⬆️ Update to symfony 6.4.26 (#895)
  • ✨ Add Settings to Userli Initialization (#911)

Database Changes

CREATE TABLE api_tokens (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(255) NOT NULL, scopes JSON NOT NULL COMMENT '(DC2Type:json)', token VARCHAR(64) NOT NULL, creation_time DATETIME NOT NULL COMMENT '(DC2Type:datetime_immutable)', last_used_time DATETIME DEFAULT NULL COMMENT '(DC2Type:datetime_immutable)', UNIQUE INDEX UNIQ_2CAD560E5F37A13B (token), INDEX idx_token (token), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB;
CREATE TABLE webhook_deliveries (id BINARY(16) NOT NULL COMMENT '(DC2Type:ulid)', endpoint_id INT NOT NULL, type VARCHAR(100) NOT NULL, request_body JSON NOT NULL COMMENT '(DC2Type:json)', request_headers JSON NOT NULL COMMENT '(DC2Type:json)', response_code INT DEFAULT NULL, response_body LONGTEXT DEFAULT NULL, success TINYINT(1) DEFAULT 0 NOT NULL, error LONGTEXT DEFAULT NULL, attempts INT DEFAULT 0 NOT NULL, dispatched_time DATETIME NOT NULL COMMENT '(DC2Type:datetime_immutable)', delivered_time DATETIME DEFAULT NULL COMMENT '(DC2Type:datetime_immutable)', INDEX IDX_3681F32D21AF7E36 (endpoint_id), INDEX IDX_3681F32DA80E9988 (dispatched_time), INDEX IDX_3681F32D6F00DFB2 (success), INDEX IDX_3681F32D8CDE5729 (type), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB;
CREATE TABLE user_notifications (id INT AUTO_INCREMENT NOT NULL, user_id INT NOT NULL, type VARCHAR(50) NOT NULL, creation_time DATETIME NOT NULL COMMENT '(DC2Type:datetime_immutable)', metadata JSON DEFAULT NULL COMMENT '(DC2Type:json)', INDEX IDX_8E8E1D83A76ED395 (user_id), INDEX idx_user_type_creation_time (user_id, type, creation_time), INDEX idx_user_type (user_id, type), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB;
CREATE TABLE webhook_endpoints (id INT AUTO_INCREMENT NOT NULL, url VARCHAR(2048) NOT NULL, secret VARCHAR(255) NOT NULL, events JSON DEFAULT NULL COMMENT '(DC2Type:json)', enabled TINYINT(1) DEFAULT 1 NOT NULL, creation_time DATETIME NOT NULL COMMENT '(DC2Type:datetime_immutable)', updated_time DATETIME NOT NULL COMMENT '(DC2Type:datetime_immutable)', INDEX IDX_E95677CC50F9BB84 (enabled), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB;
CREATE TABLE settings (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(255) NOT NULL, value LONGTEXT DEFAULT NULL, creation_time DATETIME NOT NULL COMMENT '(DC2Type:datetime_immutable)', updated_time DATETIME DEFAULT NULL COMMENT '(DC2Type:datetime_immutable)', UNIQUE INDEX UNIQ_SETTING_NAME (name), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB;
CREATE TABLE messenger_messages (id BIGINT AUTO_INCREMENT NOT NULL, body LONGTEXT NOT NULL, headers LONGTEXT NOT NULL, queue_name VARCHAR(190) NOT NULL, created_at DATETIME NOT NULL COMMENT '(DC2Type:datetime_immutable)', available_at DATETIME NOT NULL COMMENT '(DC2Type:datetime_immutable)', delivered_at DATETIME DEFAULT NULL COMMENT '(DC2Type:datetime_immutable)', INDEX IDX_75EA56E0FB7336F0 (queue_name), INDEX IDX_75EA56E0E3BD61CE (available_at), INDEX IDX_75EA56E016BA31DB (delivered_at), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB;
ALTER TABLE webhook_deliveries ADD CONSTRAINT FK_3681F32D21AF7E36 FOREIGN KEY (endpoint_id) REFERENCES webhook_endpoints (id) ON DELETE CASCADE;
ALTER TABLE user_notifications ADD CONSTRAINT FK_8E8E1D83A76ED395 FOREIGN KEY (user_id) REFERENCES virtual_users (id) ON DELETE CASCADE;
ALTER TABLE virtual_users ADD password_change_required TINYINT(1) DEFAULT 0 NOT NULL;
CREATE INDEX creation_time_idx ON virtual_users (creation_time);
CREATE INDEX deleted_idx ON virtual_users (deleted);
CREATE INDEX email_deleted_idx ON virtual_users (email, deleted);
CREATE INDEX domain_deleted_idx ON virtual_users (domain_id, deleted);
CREATE INDEX email_domain_idx ON virtual_users (email, domain_id);

4.2.0 (2025.09.03)

Features and Improvements

  • ✨ Store User Notifications (compromised passwords)
  • 🔒️ Obfuscate last login time
  • ✨ Implement role hierarchy and reachable roles functionality

Database Changes

  • Add user_notifications table to store user notifications
CREATE TABLE user_notifications
(
    id            INT AUTO_INCREMENT NOT NULL,
    user_id       INT         NOT NULL,
    type          VARCHAR(50) NOT NULL,
    creation_time DATETIME    NOT NULL COMMENT '(DC2Type:datetime_immutable)',
    metadata      JSON DEFAULT NULL COMMENT '(DC2Type:json)',
    INDEX         IDX_3F980AC8A76ED395 (user_id),
    INDEX         idx_user_type_creation_time (user_id, type, creation_time),
    INDEX         idx_user_type (user_id, type),
    PRIMARY KEY (id)
) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB;

ALTER TABLE user_notification
    ADD CONSTRAINT FK_3F980AC8A76ED395 FOREIGN KEY (user_id) REFERENCES virtual_users (id) ON DELETE CASCADE;

4.1.1 (2025.08.11)

  • ♻️ Recognize JSON Requests and return JSON responses
  • 🐛 Improve JSON Decoding for Dovecot Lua Auth Script

4.1.0 (2025.07.21)

Features and Improvements

  • 💄 Rework the UI using Tailwind CSS and Heroicons
  • 🚸 Show 2FA secret during initial configuration
  • 📝 Add Copilot Instructions

Technical Changes

  • ⬆️ Upgrade Symfony and related dependencies
  • ➖ Removed Bootstrap 3 and KnpMenuBundle
  • 🧑‍💻 Add support for remote debugging

4.0.0 (2025.04.12)

  • Remove UsersCheckPasswordCommand (breaking change)
  • Call webhook URLS on user created/deleted evens
  • Update README
  • Document how to test Dovecot integration
  • Userli-dovecot-adapter: Improve error logging
  • docker-compose: fix env vars
  • Move docker files into own directory
  • Add YAML, Markdown & Makefile to editorconfig
  • Remove obsolete ansible requirements.yml
  • Refactor: move user restore logic into its own handler
  • refactor: Add abstract UsersBaseCommand class
  • Don't allow to reset a deleted user
  • Add command to restore a deleted user
  • Rename MailCrypt trait to MailCryptEnabled
  • Update Makefile and documentation
  • Reset two-factor authentication with recovery process
  • Change booleans in docker compose env vars to integers
  • chore(deps): bump sonarsource/sonarqube-scan-action from 5.0.0 to 5.1.0
  • Add editorconfig
  • chore(deps-dev): bump the npm-dependencies group across 1 directory with 3 updates
  • VoucherCountCommand: Show both used and unused vouchers per default
  • fix: Enable mail_crypt for new users via admin backend
  • Dockerfile: Install gpg
  • Update and restructure documentation
  • Suppress deprecation warnings in 'fingers_crossed' log handler
  • Monolog: Fix config
  • Monolog: Log to syslog in prod env
  • Update GHA Runner to Ubuntu 24.04 (#736)
  • Makefile: Revert change done in #727
  • Docs: Fix broken links
  • Docs: How to docker/podman with SELinux
  • Docker compose: fix paths
  • Update dependencies
  • Fix typo in yarn package name on Debian/Ubuntu
  • Update to symfony 6.4.19
  • chore(deps-dev): bump the npm-dependencies group across 1 directory with 4 updates
  • Reintroduce make integration
  • Replace deprecated sonarcloud action
  • fix: Link to correct installation page
  • fix: Point to correct index.md
  • fix: Install correct Debian packages

3.12.1 (2025.02.28)

  • Fix Makefile

3.12.0 (2025.02.28)

  • Release Userli-Dovecot-Adapter as own tarball
  • Remove container variable in Dovecot Dockerfile
  • Say goodbye to Vagrant
  • Lua script: fix typo
  • Simplify Command and Repository Method
  • Deprecate Munin
  • Add command to get voucher count for User
  • Upgrade Symfony
  • Update npm dependencies
  • Use sqlite DB in release process to not depend on MySQL
  • Various improvements to documentation

3.11.1 (2024.12.27)

  • Fix displaying QR code when configuring 2FA
  • Dovecot lua auth: Fix encoding of payload
  • Dovecot lua auth: Fix quota attribute
  • Add docker image for human testing
  • Unify API access token handlers
  • Simplify apache config example
  • Improve documentation
  • Update dependencies

3.11.0 (2024.11.30)

  • Add retention API to update last login time for users
  • Add retention API to list deleted users
  • Do not filter displayed aliases in /alias
  • Support trusted proxies for userli behind reverse proxy
  • Fix postfix controller
  • Fix userdb attributes in dovecot lua auth script
  • Migrate large parts of release process to Makefile
  • Add Deprecation for UsersCheckPasswordCommand
  • Update dependencies

3.10.0 (2024.11.10)

  • Upgrade to Symfony 6.4.14 (#659)
  • Add API for Postfix (#644)
  • Add API for Dovecot (#651)

3.9.1 (2024.09.29)

  • Fix adding Users in Admin
  • Show email and domain filters per default in admin user list

3.9.0 (2024.09.27)

  • Add roundcube API endpoint to get list of aliases
  • Fix MailCryptKeyHandler create/update (#629)
  • Update dependencies

3.8.0 (2024.05.30)

  • Add Support for TOTP in KeyCloak API
  • Update dependencies

3.7.1 (2024.05.24)

  • Fix Readonly Attribute in Registration Form

3.7.0 (2024.05.20)

  • Move validation config from yaml to attributes
  • Adjust Validator Signatures
  • Add Types to Properties
  • Split StartController into specific Controllers
  • Vagrant provisioning: Install php-sqlite3
  • PasswordChange: Use builtin validators
  • Gather Coverage from Behat Tests
  • Add TestCase for DomainCreator
  • Make password not optional in PasswordUpdater
  • Add keycloak API endpoints
  • Update dependencies

3.6.0 (2024.04.15)

  • Remove URL-based localized routes, store locale in session
  • Check for invited by ROLE_SUSPICIOUS when assigning the role
  • Don't accept invite codes of suspicious users on registration
  • Add missing use to RecoveryController
  • Add missing default value for roles column
  • Require Node v18.x
  • Check whether user is suspicious before creating voucher
  • Bring back old logic of findOneBySource() in AliasRepository
  • Update dependencies

3.5.2 (2024.03.28)

  • Add fallback route for /recovery

3.5.1 (2024.03.24)

  • Migrate from deprecated $defaultName to name annotation
  • Update docs how to test checkpassword command

3.5.0 (2024.03.24)

  • Fix CSP Settings for Sonata Admin
  • Fix malformed expiry date for PGP key
  • Use mkdocs instead of hugo
  • Improve documentation
  • Migrate Doctrine mappings to PHP annotations
  • Make Project PHP 8 ready
  • Move routing configuration to annotations
  • Modernize form login
  • Fix regression in CRUD controllers
  • Modernize authentication and repositories
  • Fix malformed date for recovery page
  • Fix login for deleted user in UsersCheckPasswordCommand
  • Update dependencies
  • Upgrade to Symfony 6
  • Split index route in public (index) and authenticated (start)

3.4.0 (2024.01.05)

  • Adjust Admin List Order
  • Add __toString methods to Entities
  • Improve fixture loading while increasing the number of fixtures
  • Fix Filters in User Admin
  • Fix Filters in Alias Admin
  • Improve Performance for Alias and Voucher Admin
  • Use Autocomplete for loading Users in Alias and Voucher Admin

3.3.1 (2023.11.12)

  • Update dependencies

3.3.0 (2023.11.08)

  • Add command to delete a user alias.
  • Fix setting last_login_time on authentication through checkpassword command.

3.2.3 (2023.10.31)

  • Update dependencies

3.2.2 (2023.10.10)

  • Update dependencies

3.2.1 (2023.04.22)

  • Fix display of recovery token during registration process (Fixes #451)
  • Update dependencies

3.2.0 (2023.03.30)

  • Add Command to export metrics to Prometheus

3.1.0 (2022.10.26)

  • Add Two-factor authentication support

3.0.0 (2022.06.29)

  • Drop official support for PHP 7.3
  • Update to symfony 4.4.40
  • Update dependencies
  • Update translations
  • Rework Registration Config (removed HAS_SINA_BOX, added REGISTRATION_OPEN)

2.9.0 (2022.03.03)

  • Add Italian as supported language (Thanks J. Lavoie)
  • Update to symfony 4.4.38
  • Update dependencies

2.8.0 (2022.01.28)

  • Add console command to reset a user (app:users:reset)
  • Update dependencies
  • Many code style fixes

2.7.18 (2022.01.10)

  • Fix CheckPasswordCommand with latest symfony/process (Fixes #341)
  • Document cron job to delete obsolete maildirs. Thanks to 1resu.

2.7.17 (2021.12.30)

  • Set creationTime and updatedTime in all entity constructors (Fixes #207)
  • Update to symfony 4.3.36
  • Update dependencies

2.7.16 (2021.11.03)

  • Show correct random alias by forcing reload (Fixes #307)
  • Update German and Frensh translations
  • Update to symfony 4.3.33
  • Update dependencies

2.7.15 (2021.08.06)

  • Show correct random alias without reload (Fixes #307)
  • Make php7.3 serve traffic in vagrant
  • Update PHP and JS dependencies
  • Rename default git branch to main
  • Include default translations

2.7.14 (2021.08.04)

  • Don't print info line in RemoveUsersCommand with --list

2.7.13 (2021.08.04)

  • Add --list option to RemoveUsersCommand to list maildir directories
  • Add psalm static analysis CI job
  • Add contributors to README.md

2.7.12 (2021.06.25)

  • Fix query logic when listing inactive users in findInactiveUsers()

2.7.11 (2021.06.25)

  • Update PHP and JS dependencies
  • Add ROLE_PERMANANT to be used for excluding accounts in user cleanup
  • Update ansible roles to fix playbook run
  • Add console command app:users:list with option to list inactive users
  • Dispatch AliasCreatedEvent after validation (Fixes: #216)

2.7.10 (2021.05.20)

  • Really fix CVE-2021-21424
  • Upgrade to symfony 4.4.24
  • Update PHP and JS dependencies

2.7.9 (2021.05.14)

  • Fix CVE-2021-21424
  • Upgrade to symfony 4.4.23
  • Update PHP and JS dependencies

2.7.8 (2021.03.08)

  • Typo fixes
  • Update dependencies
  • Add placeholder for recovery code (Thanks xshadow)

2.7.7 (2020.11.25)

  • Limit permissions to set admin role to admin users
  • Move mail location and dovecot UID/GID settings to environment variables (Thanks 1resu)
  • Show footer on recovery page (Fixes: #141, thanks 1resu)
  • Add hint to clear the cache to docs (Thanks 1resu)
  • Open homepage link in same window (Thanks 1resu)
  • Change username input type in login forms (Thanks 1resu)

2.7.6 (2020.11.16)

  • Checkpassword: Don't throw an Exception on missing password

2.7.5 (2020.11.10)

  • Always initiate Web Key Directory for new domains
  • Improve style of pasted OpenPGP key (Thanks trashcan55)

2.7.4 (2020.10.27)

  • Fix verification of invite codes

2.7.3 (2020.10.21)

  • Improve OpenPGP key import filter:
    • Keep UIDs with valid email address but without realname
    • Drop UIDs with invalid email address that have the valid email address in realname

2.7.2 (2020.10.21)

  • Fix Munin account stats
  • Fix overwriting existing OpenPGP keys
  • Upgrade Travis CI for bionic and PHP7.3

2.7.1 (2020.10.20)

  • Downgrade twbs/bootstrap back to 3.3

2.7.0 (2020.10.20)

  • Add support to import OpenPGP keys and export them to an OpenPGP Web Key Directory.
  • Drop support for PHP 7.1 and 7.2
  • Allow to batch delete users (Fixes: #78)
  • Update Portugues translation (Thanks Silvério Santos)
  • Update dependencies

2.6.1 (2020.09.10)

  • Allow mails to be delivered to suspected spammers (Fixes: #212)
  • Update to symfony 4.4
  • Update translations

2.6.0 (2020.05.12)

  • Attempt to fix mail body translation string format (Fixes: #205)
  • Add new console command app:users:delete to delete users.

2.5.1 (2020.01.09)

  • Fix userDB lookups for accounts without mail_crypt when MAIL_CRYPT=3.
  • Add French translation (Thanks Nathan Bonnemains)

2.5.0 (2020.01.05)

  • Merge MAIL_CRYPT_* dotenv variables into a single one. Please see UPGRADING.md and the documentation for further information.
  • Update to symfony 4.3.9
  • Update Norwegian translation (Thanks Alan Nordhøy)
  • Allow to create first domain and account via web frontend (Fixes: #195)
  • Automatically create postmaster@domain for all domains (Fixes: #111)

2.4.0 (2019.11.18)

  • Skip check against HIBP service if unavailable
  • Add copy-to-clipboard for aliases (Fixes: #181) (Thanks @jelhan)
  • Add Swiss German to supported languages (Thanks wee)
  • Update dependencies

2.3.0 (2019.07.16)

  • Add manual language switcher (Fixes: #172)
  • Add Norwegian Bokmål as available translation
  • Block Spammers from authenticating via checkpassword (Fixes: #177)
  • Test passwords againt haveibeenpwned database (Fixes: #161)
  • Upgrade to symfony 4.3.2
  • Improve speed of Vagrant box

2.2.3 (2019.06.24)

  • Repair js copying of invite codes (Fixes: #165)
  • Several minor language fixes (Thanks to ssantos)
  • Start Norwegian translation (Thanks to Allan Nordhøy)
  • Switch to PHP-only checkpassword script for security reasons. This eliminates the requirement to setup sudo. See the updated docs for details.

2.2.2 (2019.06.14)

  • Delete aliases when deleting user (Fixes: #121)
  • Fix error when trying to register deleted username (Fixes: #176)
  • Remove link to registration from right navbar
  • Update PHP and JS dependecies

2.2.1 (2019.06.06)

  • Add org/organisation/... to reserved names
  • Update to symfony 4.2.9
  • Update PHP and JS dependecies
  • Rename ROLE_SUPPORT to ROLE_MULTIPLIER

2.2.0 (2019.05.22)

  • Add initial Spanish translation
  • Add initial Portuguese translation (Thanks to Bruno Gama)
  • Add plural forms of many reserved names
  • Update to symfony 4.2.8
  • Fix mailcrypt-encrypt-maildir script for paths with whitespaces
  • Fix release tarball creation, don't use tar option --transform

2.1.2 (2019.04.18)

  • Create release tarball in subdirectory
  • Add optional link to webmail (Fixes: #146)
  • Update to symfony 4.2.7

2.1.1 (2019.03.17)

  • Change default locale setting to 'en'
  • Don't resolve symlinks to not break sudo in checkpassword

2.1.0 (2019.03.17)

  • New shell script bin/mailcrypt-encrypt-maildir to encrypt legacy mailboxes
  • Update to symfony 4.2.4
  • Add sudo support to checkpassword script (Fixes: #127)
  • Update SecurityController to use AuthenticationUtils
  • Add CSRF protection to login forms (Fixes: #95)

2.0.2 (2019.03.06)

  • Add column and filter for hasRecoveryToken property on user in admin list (Fixes: #144)
  • Export number of users with Recovery Tokens to Munin
  • Recovery also works now with email localpart (Fixes: #148)
  • Fix release tar balls (Fixes: #150)

2.0.1 (2019.03.04)

  • We adopted the code of conduct from Contributor Covenant
  • Fix bug in CryptoSecretHandler::decrypt() that broke recovery token recreation.

2.0.0 (2019.02.23)

  • Rename project to Userli (Fixes: #133)
  • Add support for Dovecot's MailCrypt plugin. New users automatically get a MailCrypt key pair generated which is then passed to Dovecot via checkpassword. (Fixes: #83)
  • Add support for recovery tokens. New users automatically get a recovery token generated, which can be used to restore their account if the password got lost at a later time. (Fixes: #89, #106, #108)
  • Add support for direct registration links with prefilled invite vouchers. (Fixes: #117)
  • Move flash messages to upper right corner (Fixes: #129)
  • Always display footer when logged in (Fixes: #104)
  • Open external links in new window (Fixes: #100)
  • Add option to copy link as URL (Fixes: #117)
  • Explain purpose of alias addresses (Fixes: #45)
  • Remove trailing slash from default URLs
  • Adjust database to snake_case. See UPGRADE.md on how to adjust an older database. (Fixes: #112)
  • Add infobox with password policy to password change forms (Fixes: #130)
  • Turn autocompletion off for voucher form field at registration (Fixes: #32)
  • Started external docs at systemli.github.io/userli

1.6.2 (2019.02.08)

  • Update to symfony 4.1.11
  • Hide vouchers in secondary domains (Fixes: #110)
  • DomainAdmins are only allowed to create Alias in their domain (Fixes: #94)

1.6.1 (2019.01.14)

  • Update to symfony 4.1.10
  • Add quota to checkpassword (Fixes: #91)

1.6.0 (2019.01.04)

  • Add a role for detected spammers (Fixes: #77)
  • Split startpage into subpages (Fixes: #43)
  • Reverse order of vouchers, display newest vouchers first
  • Fix when users updatedTime is updated (Fixes: #71)
  • Don't show voucher menu to suspicious users (Fixes: #81)

1.5.3 (2018.12.13)

  • Add scripts to automate building and publishing of releases

1.5.2 (2018.12.07)

  • Start to list relevant changes in a dedicated changelog file.
  • Hide voucher stats from domain admins (Fixes: #72)
  • Improve message about custom alias limit (Fixes: #74)

1.5.1 (2018.11.28)

  • Fix passing passwords that start with special chars to checkpassword script