diff options
Diffstat (limited to 'tests/common/email/functions.nix')
| -rw-r--r-- | tests/common/email/functions.nix | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/tests/common/email/functions.nix b/tests/common/email/functions.nix new file mode 100644 index 0000000..7be1bfa --- /dev/null +++ b/tests/common/email/functions.nix @@ -0,0 +1,224 @@ +{ + pkgs, + vhackPackages, +}: { + scripts = { + expectNoNewMail = pkgs.writeShellScript "assert-empty-emails" '' + set -xe + + # fetchmail returns EXIT_CODE 1 when no new mail + fetchmail --verbose >&2 || [ "$?" -eq 1 ] || { + echo "Mail was not empty" >&2 + exit 1 + } + ''; + expectNewMail = pkgs.writeShellScript "assert-empty-emails" '' + set -xe + + # fetchmail returns EXIT_CODE 1 when no new mail + fetchmail --verbose >&2 || [ "$?" -ne 1 ] || { + echo "No new mail" >&2 + exit 1 + } + ''; + expectNewSpamMail = pkgs.writeShellScript "assert-empty-emails" '' + set -xe + + # fetchmail returns EXIT_CODE 1 when no new mail + fetchmail --folder JUNK --verbose >&2 || [ "$?" -ne 1 ] || { + echo "No new spam mail" >&2 + exit 1 + } + ''; + }; + + mkMailServer = serverName: userName: { + config, + lib, + nodes, + ... + }: { + age.identityPaths = ["${../../common/email/hostKey}"]; + + systemd.tmpfiles.rules = [ + #- path mode user group - content + "f /passwords/${userName} 777 root root - ${userName}-password" + ]; + + age.secrets = { + "mailDkim" = { + file = ../../common/email/dkim + "/${serverName}/private.age"; + mode = "600"; + owner = "rspamd"; + group = "rspamd"; + }; + }; + + # Disable rspamd. rspamd can't do the dns lookups in the sandbox for + # determining if something is spam or not. Therefore it just rejects every mail with + # 'Try again later.'. + # services.rspamd.enable = lib.mkForce false; + # users.users.rspamd.group = "rspamd"; + # users.groups.rspamd = {}; + # + # services.postfix.settings.main = { + # smtpd_milters = lib.mkForce []; + # non_smtpd_milters = lib.mkForce []; + # }; + # mailserver.dkim.enable = false; + services = { + rspamd = { + locals = { + "asn.conf".text = lib.mkForce '' + enabled = false; + ''; + "rbl.conf".text = lib.mkForce '' + enabled = false; + ''; + "greylist.conf".text = lib.mkForce '' + enabled = false; + ''; + }; + }; + }; + + # This DNS resolver is only there for rspamd (and apparently not even needed). But it + # also removes our own name server changes, so the test node could no longer find + # e.g. `acme.test` and so on. + # See: https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/work_items/100 + mailserver.localDnsResolver = false; + + vhack = { + mail = { + enable = true; + fqdn = serverName; + domains = [ + serverName + ]; + + security.dkimKeys."${serverName}" = { + dkimPrivateKeyPath = config.age.secrets."mailDkim".path; + dkimPublicKey = + builtins.readFile (../../common/email/dkim + "/${serverName}/public"); + keyAlgorithm = "rsa-sha-256"; + }; + + accounts = { + "${userName}@${serverName}" = { + passwordFile = "/passwords/${userName}"; + }; + }; + }; + }; + }; + + mkDnsZone = serverName: {config, ...}: let + cfg = config.vhack.mail; + + keyAlgoToKeyType = keyAlgo: + if keyAlgo == "ed25519-sha256" + then "ed25519" + else if keyAlgo == "rsa-sha-256" || keyAlgo == "rsa-sha-1" + then "rsa" + else builtins.throw "Impossible"; + in { + "${serverName}" = { + MX = [ + { + preference = 10; + exchange = "${serverName}."; + } + ]; + + # https://www.rfc-editor.org/rfc/rfc6376.html#section-3.6.1 + # https://www.rfc-editor.org/rfc/rfc6376.html#section-7.5 + DKIM = [ + { + selector = "mail"; + k = keyAlgoToKeyType cfg.security.dkimKeys."${serverName}".keyAlgorithm; + p = cfg.security.dkimKeys."${serverName}".dkimPublicKey; + s = ["email"]; + t = ["s"]; + } + ]; + + # https://www.rfc-editor.org/rfc/rfc7489.html#section-6.3 + DMARC = [ + { + adkim = "strict"; + aspf = "strict"; + fo = ["0" "1" "d" "s"]; + p = "quarantine"; + rua = "admin@vhack.eu"; + ruf = ["admin@vhack.eu"]; + } + ]; + + # https://www.rfc-editor.org/rfc/rfc7208.html + # NOTE(@bpeetz): This server might not be directly sending mail, but it is still required for + # the SMTP EHLO check. <2025-02-25> + TXT = [ + (builtins.concatStringsSep " " + [ + "v=spf1" # The version. + "+mx" # Allow mail from this domain MX record. + "-all" # Reject all other emails if the previous mechanism did not match. + ]) + ]; + }; + }; + + mkUser = user: mailServer: {nodes, ...}: { + environment.systemPackages = [ + vhackPackages.fetchmail-common-name + pkgs.msmtp + pkgs.procmail + ]; + + users.users."${user}" = {isNormalUser = true;}; + + systemd.tmpfiles.rules = [ + "d /home/${user}/mail 0700 ${user} users - -" + "L /home/${user}/.fetchmailrc - - - - /etc/homeSetup/.fetchmailrc" + "L /home/${user}/.procmailrc - - - - /etc/homeSetup/.procmailrc" + "L /home/${user}/.msmtprc - - - - /etc/homeSetup/.msmtprc" + ]; + + environment.etc = { + "homeSetup/.fetchmailrc" = { + text = '' + poll "${mailServer}" protocol IMAP + username "${user}@${mailServer}" + password "${user}-password" + ssl + mda procmail; + ''; + mode = "0600"; + inherit user; + }; + "homeSetup/.procmailrc" = { + text = '' + DEFAULT=$HOME/mail + ''; + mode = "0600"; + inherit user; + }; + "homeSetup/.msmtprc" = { + text = '' + account ${user} + host ${mailServer} + domain ${mailServer} + port 465 + from ${user}@${mailServer} + user ${user}@${mailServer} + password ${user}-password + auth on + tls on + tls_starttls off + ''; + mode = "0600"; + inherit user; + }; + }; + }; +} |
