diff options
Diffstat (limited to '')
-rw-r--r-- | modules/by-name/st/stalwart-mail/module.nix | 102 | ||||
-rw-r--r-- | modules/by-name/st/stalwart-mail/settings.nix | 56 |
2 files changed, 102 insertions, 56 deletions
diff --git a/modules/by-name/st/stalwart-mail/module.nix b/modules/by-name/st/stalwart-mail/module.nix index 1ad76c7..4565bf4 100644 --- a/modules/by-name/st/stalwart-mail/module.nix +++ b/modules/by-name/st/stalwart-mail/module.nix @@ -18,7 +18,7 @@ in { options.vhack.stalwart-mail = { enable = lib.mkEnableOption "starwart-mail"; - package = lib.mkPackageOption vhackPackages "stalwart-mail-free" {}; + package = lib.mkPackageOption vhackPackages "stalwart-mail-patched" {}; admin = lib.mkOption { description = '' @@ -41,8 +41,8 @@ in { }; principals = lib.mkOption { - default = []; - type = lib.types.listOf (lib.types.submodule { + default = null; + type = lib.types.nullOr (lib.types.listOf (lib.types.submodule { options = { name = lib.mkOption { type = lib.types.str; @@ -61,7 +61,32 @@ in { }; secret = lib.mkOption { - type = lib.types.str; + type = let + prefix = pre: lib.types.strMatching "^${lib.strings.escapeRegex pre}.*"; + in + lib.types.oneOf [ + (prefix "$argon2") + (prefix "$pbkdf2") + (prefix "$scrypt") + (prefix "$2") # bcrypt + (prefix "$6$") # sha-512 + (prefix "$5$") # sha-256 + (prefix "$sha1") + (prefix "$1") # md5 + (prefix "_") # BSDi crypt + (prefix "{SHA}") # base64 sha + (prefix "{SSHA}") # base64 salted sha + + # unix crypt + (prefix "{CRYPT}") + (prefix "{crypt}") + + # Plain text + (prefix "{PLAIN}") + (prefix "{plain}") + (prefix "{CLEAR}") + (prefix "{clear}") + ]; description = '' Sets the password for the user account. Passwords can be stored hashed or in plain text (not recommended). @@ -77,7 +102,7 @@ in { ''; }; }; - }); + })); }; dataDirectory = lib.mkOption { @@ -160,25 +185,16 @@ in { # However, this decision could obviously be reversed in the future. <2025-02-08> enable = false; inherit (cfg) package; - # dataDir = cfg.dataDirectory; }; - # FIXME(@bpeetz): This is currently needed for a successful acme http-01 challenge. - # We could also use the DNS challenge. <2025-03-01> nginx.virtualHosts."${cfg.fqdn}" = { - enableACME = false; - extraConfig = - # This is copied directly from the nixos nginx module. - # Rule for legitimate ACME Challenge requests (like /.well-known/acme-challenge/xxxxxxxxx) - # We use ^~ here, so that we don't check any regexes (which could - # otherwise easily override this intended match accidentally). - '' - location ^~ /.well-known/acme-challenge/ { - root ${config.security.acme.certs.${cfg.fqdn}.webroot}; - auth_basic off; - auth_request off; - } - ''; + locations."/" = { + proxyPass = "http://${builtins.elemAt config.services.stalwart-mail.settings.server.listener.http.bind 0}"; + recommendedProxySettings = true; + }; + + useACMEHost = "${cfg.fqdn}"; + forceSSL = true; }; redis = { @@ -209,7 +225,7 @@ in { security.acme.certs = { "${cfg.fqdn}" = { domain = cfg.fqdn; - group = "stalwart-mail"; + group = "stalwart-mail-certificates"; }; }; @@ -239,7 +255,7 @@ in { { directory = "${config.services.redis.servers."stalwart-mail".settings.dir}"; user = "stalwart-mail"; - group = "redis"; + group = "redis-stalwart-mail"; mode = "0770"; } ]; @@ -249,20 +265,31 @@ in { # service is restarted on a potentially large number of files. # That would cause unnecessary and unwanted delays. users = { - groups.stalwart-mail = { - gid = config.vhack.constants.ids.gids.stalwart-mail; - }; - users.stalwart-mail = { - isSystemUser = true; - group = "stalwart-mail"; - uid = config.vhack.constants.ids.uids.stalwart-mail; - }; - groups.redis-stalwart-mail = { - gid = config.vhack.constants.ids.gids.redis-stalwart-mail; + groups = { + stalwart-mail = { + gid = config.vhack.constants.ids.gids.stalwart-mail; + }; + stalwart-mail-certificates = { + gid = config.vhack.constants.ids.gids.stalwart-mail-certificates; + }; + redis-stalwart-mail = { + gid = config.vhack.constants.ids.gids.redis-stalwart-mail; + }; }; - users.redis-stalwart-mail = { - group = "redis-stalwart-mail"; - uid = config.vhack.constants.ids.uids.redis-stalwart-mail; + users = { + nginx = { + extraGroups = ["stalwart-mail-certificates"]; + }; + stalwart-mail = { + isSystemUser = true; + group = "stalwart-mail"; + uid = config.vhack.constants.ids.uids.stalwart-mail; + extraGroups = ["stalwart-mail-certificates"]; + }; + redis-stalwart-mail = { + group = "redis-stalwart-mail"; + uid = config.vhack.constants.ids.uids.redis-stalwart-mail; + }; }; }; @@ -321,8 +348,7 @@ in { ${lib.getExe cfg.package} --config="$CACHE_DIRECTORY/mutable_config_file.toml" ''; - Restart = "on-failure"; - RestartSec = 5; + Restart = "no"; KillMode = "process"; KillSignal = "SIGINT"; diff --git a/modules/by-name/st/stalwart-mail/settings.nix b/modules/by-name/st/stalwart-mail/settings.nix index 7032ae0..907cea9 100644 --- a/modules/by-name/st/stalwart-mail/settings.nix +++ b/modules/by-name/st/stalwart-mail/settings.nix @@ -18,6 +18,11 @@ if cfg.security != null then cfg.security.verificationMode else "disable"; + + directory = + if cfg.principals == null + then "internal" + else "in-memory"; in { config.services.stalwart-mail.settings = lib.mkIf cfg.enable { # https://www.rfc-editor.org/rfc/rfc6376.html#section-3.3 @@ -219,7 +224,7 @@ in { require = true; }; rcpt = { - directory = "'in-memory'"; + directory = "'${directory}'"; catch-all = true; subaddressing = true; }; @@ -236,7 +241,7 @@ in { }; auth = { mechanisms = ["LOGIN" "PLAIN"]; - directory = "'in-memory'"; + directory = "'${directory}'"; require = true; must-match-sender = true; errors = { @@ -339,13 +344,13 @@ in { hostname = cfg.fqdn; listener = { - # TODO(@bpeetz): Add this <2025-02-08> - # # HTTP (used for jmap) - # "http" = { - # bind = ["[::]:8080"]; - # protocol = "http"; - # tls.implicit = true; - # }; + # HTTP (used for jmap) + "http" = { + bind = ["127.0.0.1:8112"]; + protocol = "http"; + # handled by ngnix + tls.implicit = false; + }; # IMAP "imap" = { @@ -401,11 +406,12 @@ in { certificate = "default"; }; - # TODO(@bpeetz): Configure that <2025-02-07> - # http = { - # url = ""; - # allowed-endpoint = ["404"]; - # }; + http = { + url = "protocol + '://' + config_get('server.hostname') + ':' + local_port"; + + # We are behind a nginx proxy, and can thus trust this header. + use-x-forwarded = true; + }; auto-ban = { # Ban if the same IP fails to login 10 times in a day @@ -467,6 +473,14 @@ in { # Perform “maintenance” every day at 3 am local time. purge.frequency = "0 3 *"; }; + "rocksdb-directory" = lib.mkIf (cfg.principals == null) { + type = "rocksdb"; + path = "${cfg.dataDirectory}/storage/directory"; + compression = "lz4"; + + # Perform “maintenance” every day at 1 am local time. + purge.frequency = "0 1 *"; + }; "rocksdb-full-text-search" = { type = "rocksdb"; path = "${cfg.dataDirectory}/storage/full-text-search"; @@ -505,7 +519,7 @@ in { full-text.default-language = "en"; fts = "rocksdb-full-text-search"; - directory = "in-memory"; + directory = "${directory}"; lookup = "redis"; @@ -516,9 +530,15 @@ in { encryption.enable = false; }; - directory."in-memory" = { - type = "memory"; - inherit (cfg) principals; + directory = { + "in-memory" = lib.mkIf (cfg.principals != null) { + type = "memory"; + inherit (cfg) principals; + }; + "internal" = lib.mkIf (cfg.principals == null) { + type = "internal"; + store = "rocksdb-directory"; + }; }; certificate = { |