From 84bf6e47121b1c0de1701f97fedeaf888e101649 Mon Sep 17 00:00:00 2001 From: Florian Brandes Date: Fri, 12 Jul 2024 12:53:11 +0200 Subject: [PATCH] wip: add module.nix Signed-off-by: Florian Brandes --- .gitignore | 1 + config.example | 1 - default.nix | 7 -- flake.nix | 1 + module.nix | 198 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 200 insertions(+), 8 deletions(-) create mode 100644 module.nix diff --git a/.gitignore b/.gitignore index 29ee88c..ec86951 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ config.ini *.pfx *.crt *.pem +*.pw !tests/privkey.pem !tests/signer.pem diff --git a/config.example b/config.example index b39ac16..3663644 100644 --- a/config.example +++ b/config.example @@ -14,7 +14,6 @@ sender = foo@example.com # start_tls = false # smime_cert = /path/to/cert # smime_cert_private = /path/to/cert.key -# smime_to_cert = /path/to/recipient_cert [emails] # If you want to encrypt outgoing email, add the recipient certificate to the email diff --git a/default.nix b/default.nix index 7b4999f..59ce8f2 100644 --- a/default.nix +++ b/default.nix @@ -22,13 +22,6 @@ pkgs.python3Packages.buildPythonPackage rec { nativeCheckInputs = [ pkgs.python3Packages.pytestCheckHook ]; pythonImportsCheck = [ "smtprd_ng" ]; - postInstall = '' - install -D -m 644 systemd/smtprd-ng.service \ - $out/lib/systemd/system/smtprd-ng.service - substituteInPlace $out/lib/systemd/system/smtprd-ng.service \ - --replace-fail @smtprd@ "$out/bin/smtprd-ng" - ''; - meta = { description = "SMTP forwarding relay daemon with signing and encryption"; homepage = "https://app.radicle.xyz/nodes/seed.radicle.garden/rad:z3gWc1qgaeZaoGwL4WTstLNoqjayM"; diff --git a/flake.nix b/flake.nix index 3620b7c..7114680 100644 --- a/flake.nix +++ b/flake.nix @@ -21,6 +21,7 @@ ]; in { + nixosModules.smtprd-ng = import ./module.nix; overlays.default = import ./overlay.nix { inherit self; }; } // flake-utils.lib.eachSystem supportedSystems ( diff --git a/module.nix b/module.nix new file mode 100644 index 0000000..8d08c3e --- /dev/null +++ b/module.nix @@ -0,0 +1,198 @@ +{ config +, lib +, pkgs +, ... +}: +with lib; +let + cfg = config.smtprd-ng; + smtprd-ng = pkgs.callPackage ./. { }; + + emails = submodule { + options = { + email = mkOption { + type = types.str; + description = '' + Email to relay locally received emails to. + ''; + }; + certificate = mkOption { + type = types.nullOr types.path; + description = '' + Path to the public S/MIME certificate for this receiver. Emails will be encrypted with this certificate. + ''; + }; + }; + }; + +in +{ + options.smtprd-ng = { + enable = mkEnableOption "smtprd-ng"; + + package = mkOption { + type = types.package; + default = smtprd-ng; + description = mdDoc '' + The smtprd-ng package to use. + ''; + }; + + server = { + hostname = mkOption { + type = types.str; + default = "localhost"; + description = mdDoc '' + The hostname the local SMTP server should listen on. + ''; + }; + port = mkOption { + type = types.port; + default = 8025; + description = mdDoc '' + The port the local SMTP server should listen on. + ''; + }; + }; + client = { + hostname = mkOption { + type = types.str; + default = ""; + description = mdDoc '' + The hostname of the remote SMTP server. + ''; + }; + port = mkOption { + type = types.port; + default = 587; + description = mdDoc '' + The port of the remote SMTP server. + ''; + }; + username = mkOption { + type = types.nullOr types.str; + default = null; + description = mdDoc '' + The username to login to the remote SMTP server. + ''; + }; + password_file = mkOption { + type = types.nullOr types.path; + default = null; + description = mdDoc '' + The path to the file containing the password to login to the remote SMTP server. + Should not be in /nix/store! + ''; + }; + sender = mkOption { + type = types.nullOr types.str; + default = null; + description = mdDoc '' + The email of the sender. Some SMTP servers require this to be the real FROM email address of the user. + ''; + }; + use_tls = mkOption { + type = types.bool; + default = false; + description = mdDoc '' + Use TLS to connect. Mutually exclusive with `start_tls` + ''; + }; + start_tls = mkOption { + type = types.bool; + default = false; + description = mdDoc '' + Use STARTLS to connect. Mutually exclusive with `use_tls` + ''; + }; + smime_cert = mkOption { + type = types.nullOr types.path; + default = null; + description = mdDoc '' + The path to the S/MIME certificate used to sign messages. + If empty, will neither encrypt, nor sign relayed messages. + ''; + }; + smime_cert_private = mkOption { + type = types.nullOr types.path; + default = null; + description = mdDoc '' + The path to the S/MIME private key for the certificate used to sign messages. + Should not be in /nix/store! + ''; + }; + }; + emails = mkOption { + type = nullOr (listOf emails); + default = null; + description = '' + A required list of recipients. A certificate is optional, but required if + messages should be signed and encrypted. + ''; + example = [ + { + email = "monitoring.foo@example.com"; + certificate = "`/path/to/certificate`"; + } + { + email = "unencrypted@example.com"; + certificate = "`null`"; + } + ]; + }; + }; + + config = mkIf cfg.enable { + + assertions = [ + { + assertion = cfg.client.use_tls == true && cfg.client.start_tls == true; + message = "Use either TLS or STARTTLS, not both."; + } + { + assertion = cfg.client.smime_cert != null && cfg.client.smime_cert_private == null; + message = "If a S/MIME certificate should be used to sign messages, the private key to this certificate must be supplied."; + } + { + assertion = cfg.emails != null; + message = "At least one recipient must be configured."; + } + ]; + + configFile = { + text = generators.toINI { } { + server = { + hostname = cfg.server.hostname; + port = cfg.server.port; + }; + client = { + hostname = cfg.client.hostname; + port = cfg.client.port; + username = cfg.client.username; + password_file = cfg.client.password_file; + sender = cfg.client.sender; + use_tls = cfg.client.use_tls; + start_tls = cfg.client.start_tls; + smime_cert = cfg.client.smime_cert; + smime_cert_private = cfg.client.smime_cert_private; + }; + emails = cfg.emails; + }; + + systemd.services = { + smtprd-ng = { + description = "Run local SMTP relay"; + wantedBy = [ "multi-user.target" ]; + requires = [ "network.target" ]; + serviceConfig = { + DynamicUser = true; + User = "smtprd-ng"; + Group = "smtprd-ng"; + Restart = "on-failure"; + ExecStart = "${cfg.package}/bin/smtprd-ng --config ${configFile}"; + }; + }; + }; + }; + }; +}