about summary refs log tree commit diff stats
path: root/modules/by-name/st
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--modules/by-name/st/stalwart-mail/module.nix102
-rw-r--r--modules/by-name/st/stalwart-mail/settings.nix56
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 = {