diff --git a/CHANGELOG.md b/CHANGELOG.md index 91e31deb..8ffe88ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,31 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [0.5.0] - 2023-12-27 + +## Added +- Performance enhancements: + - Messages are parsed only once and their offsets stored in the database, which avoids having to parse them on every `FETCH` request. + - Background full-text indexing. + - Optimization of database access functions. +- Storage layer improvements: + - In addition to `FoundationDB` and `SQLite`, now it is also possible to use `RocksDB`, `PostgreSQL` and `mySQL` as a storage backend. + - Blobs can now be stored in any of the supported data stores, it is no longer limited to the file system or S3/MinIO. + - Full-text searching con now be done internally or delegated to `ElasticSearch`. + - Spam databases can now be stored in any of the supported data stores or `Redis`. It is no longer necessary to have an SQL server to use the spam filter. +- Internal directory: + - User account, groups and mailing lists can now be managed directly from Stalwart without the need of an external LDAP or SQL directory. + - HTTP API to manage users, groups, domains and mailing lists. +- IMAP4rev1 `Recent` flag support, which improves compatibility with old IMAP clients. +- LDAP bind authentication, to support some LDAP servers such as `lldap` which do not expose the userPassword attribute. +- Messages marked a spam by the spam filter can now be automatically moved to the account's `Junk Mail` folder. + +### Changed + +### Fixed +- Spamhaus DNSBL return codes. +- CLI tool reports authentication errors rather than a parsing error. + ## [0.4.2] - 2023-11-01 ## Added diff --git a/crates/install/src/main.rs b/crates/install/src/main.rs index 445af062..ba81ffd5 100644 --- a/crates/install/src/main.rs +++ b/crates/install/src/main.rs @@ -33,6 +33,7 @@ use base64::{engine::general_purpose, Engine}; use clap::{Parser, ValueEnum}; use dialoguer::{console::Term, theme::ColorfulTheme, Input, Select}; use openssl::rsa::Rsa; +use pwhash::sha512_crypt; use rand::{distributions::Alphanumeric, thread_rng, Rng}; const CONFIG_URL: &str = "https://get.stalw.art/resources/config.zip"; @@ -189,6 +190,7 @@ fn main() -> std::io::Result<()> { let mut download_url = None; // Obtain database engine + let mut is_internal = false; if component != Component::Smtp { let backend = select::( "Which database would you like to use?", @@ -240,18 +242,6 @@ fn main() -> std::io::Result<()> { Blob::Internal, )?; - let directory = select::( - "Do you already have a directory or database containing your user accounts?", - &[ - &format!("No, I want Stalwart to manage my user accounts in {store}"), - "Yes, it's an LDAP server", - "Yes, it's an PostgreSQL database", - "Yes, it's an MySQL database", - "Yes, it's an SQLite database", - ], - Directory::Internal, - )?; - let fts = select::( "Where would you like to store the full-text index?", &[&store, "ElasticSearch"], @@ -264,6 +254,19 @@ fn main() -> std::io::Result<()> { SpamDb::Internal, )?; + let directory = select::( + "Do you already have a directory or database containing your user accounts?", + &[ + &format!("No, I want Stalwart to store my user accounts in {store}"), + "Yes, it's an LDAP server", + "Yes, it's an PostgreSQL database", + "Yes, it's an MySQL database", + "Yes, it's an SQLite database", + ], + Directory::Internal, + )?; + is_internal = matches!(directory, Directory::Internal); + // Update settings sed( cfg_path.join("config.toml"), @@ -631,6 +634,22 @@ fn main() -> std::io::Result<()> { } } + if is_internal { + let secret = thread_rng() + .sample_iter(Alphanumeric) + .take(12) + .map(char::from) + .collect::(); + let hashed_secret = sha512_crypt::hash(&secret).unwrap(); + eprintln!( + "\nšŸ”‘ To create the administrator account 'admin' with password '{secret}', execute:\nšŸ”‘ ", + ); + eprintln!( + "šŸ”‘ $ SET_ADMIN_USER=\"admin\" SET_ADMIN_PASS=\"{hashed_secret}\" {}/bin/stalwart-mail --config={}/etc/config.toml", + base_path.display(), base_path.display() + ) + } + eprintln!("\nšŸŽ‰ Installation completed!\n\nāœ… {dkim_instructions}\n"); Ok(()) diff --git a/crates/store/src/dispatch/lookup.rs b/crates/store/src/dispatch/lookup.rs index a1893778..355bdbe9 100644 --- a/crates/store/src/dispatch/lookup.rs +++ b/crates/store/src/dispatch/lookup.rs @@ -34,6 +34,7 @@ use crate::{ impl LookupStore { #[allow(unreachable_patterns)] + #[allow(unused_variables)] pub async fn query( &self, query: &str, diff --git a/resources/config.zip b/resources/config.zip index b6b723a8..8ea3b059 100644 Binary files a/resources/config.zip and b/resources/config.zip differ diff --git a/resources/config/directory/imap.toml b/resources/config/directory/imap.toml index c4f9400a..73c7c231 100644 --- a/resources/config/directory/imap.toml +++ b/resources/config/directory/imap.toml @@ -10,10 +10,11 @@ disable = true [directory."imap".pool] max-connections = 10 -min-connections = 0 -max-lifetime = "30m" -idle-timeout = "10m" -connect-timeout = "30s" + +[directory."imap".pool.timeout] +create = "30s" +wait = "30s" +recycle = "30s" [directory."imap".tls] implicit = true diff --git a/resources/config/directory/ldap.toml b/resources/config/directory/ldap.toml index 61aadc74..11ea5894 100644 --- a/resources/config/directory/ldap.toml +++ b/resources/config/directory/ldap.toml @@ -6,6 +6,7 @@ type = "ldap" address = "ldap://localhost:389" base-dn = "dc=example,dc=org" +timeout = "30s" disable = true [directory."ldap".bind] diff --git a/resources/config/directory/lmtp.toml b/resources/config/directory/lmtp.toml index 7b911997..2732be78 100644 --- a/resources/config/directory/lmtp.toml +++ b/resources/config/directory/lmtp.toml @@ -14,10 +14,11 @@ rcpt = 5 [directory."lmtp".pool] max-connections = 10 -min-connections = 0 -max-lifetime = "30m" -idle-timeout = "10m" -connect-timeout = "30s" + +[directory."lmtp".pool.timeout] +create = "30s" +wait = "30s" +recycle = "30s" [directory."lmtp".tls] implicit = false