commit c9128cf5f8fd469a173af00faa69e627de34bd5c
parent e7f0fcec1d172d250fb0c2e50d4aaff32da8d855
Author: Leah (ctucx) <leah@ctu.cx>
Date: Wed, 7 Sep 2022 17:13:15 +0200
parent e7f0fcec1d172d250fb0c2e50d4aaff32da8d855
Author: Leah (ctucx) <leah@ctu.cx>
Date: Wed, 7 Sep 2022 17:13:15 +0200
machines/osterei/maddy: implement mail and mailbox filtering
2 files changed, 179 insertions(+), 66 deletions(-)
M
|
124
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
M
|
121
+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
diff --git a/machines/osterei/maddy.nix b/machines/osterei/maddy.nix @@ -1,6 +1,42 @@ { config, lib, pkgs, ... }: -{ +let + maddy = pkgs.callPackage ../../pkgs/maddy.nix {}; + secrets = import ../../secrets/default.nix; + + writePythonScriptBin = name: packagesSelectionFun: text: + let + mkScriptName = s: (builtins.replaceStrings [ "\\" ] [ "-" ] s); + x = pkgs.writeTextFile { name = "unit-script.py"; executable = true; destination = "/bin/${mkScriptName name}"; text = "#!/usr/bin/env python3\n${text}"; }; + deriv = pkgs.stdenv.mkDerivation { + name = mkScriptName name; + buildInputs = [ (pkgs.python3.withPackages (pythonPackages: packagesSelectionFun pythonPackages)) ]; + unpackPhase = "true"; + installPhase = '' + mkdir -p $out/bin + cp ${x}/bin/${mkScriptName name} $out/bin/${mkScriptName name} + ''; + }; + in "${deriv}/bin/${mkScriptName name}"; + +in { + + nixpkgs.overlays = [ + (final: prev: { + maddy = maddy; + }) + ]; + + environment.etc."maddy/filters/mailbox/leah@ctu.cx.toml".text = "${builtins.toJSON secrets.maddy.mailboxFilter}"; + environment.etc."maddy/filters/receive.toml".text = "${builtins.toJSON secrets.maddy.receiveFilter}"; + + security.acme.certs."osterei.ctu.cx".reloadServices = [ "maddy.service" ]; + + systemd.services.maddy.serviceConfig.ReadOnlyPaths = [ "/etc/maddy/filters" ]; + + age.secrets.restic-maddy.file = ../../secrets/osterei/restic/maddy.age; + + networking.firewall.allowedTCPPorts = [ 25 143 465 587 993 ]; users.groups.maddy = {}; users.users.maddy = { @@ -10,24 +46,12 @@ extraGroups = [ "nginx" ]; }; - age.secrets.restic-maddy.file = ../../secrets/osterei/restic/maddy.age; - restic-backups.maddy = { user = "maddy"; passwordFile = config.age.secrets.restic-maddy.path; paths = [ "/var/lib/maddy" ]; }; - security.acme.certs."osterei.ctu.cx".reloadServices = [ "maddy.service" ]; - - networking.firewall.allowedTCPPorts = [ - 25 - 143 - 465 - 587 - 993 - ]; - services.maddy = { enable = true; user = "maddy"; @@ -37,13 +61,13 @@ localDomains = [ "$(hostname)" "$(primary_domain)" - "antifa.jetzt" "thein.ovh" "ctucx.de" "trans-agenda.de" ]; config = '' + #debug on log syslog tls file /var/lib/acme/osterei.ctu.cx/fullchain.pem /var/lib/acme/osterei.ctu.cx/key.pem @@ -79,6 +103,36 @@ storage.imapsql local_mailboxes { driver sqlite3 dsn imapsql.db + disable_recent false + compression zstd + + imap_filter { + command ${writePythonScriptBin "mailbox-filter.py" (ps: [ ps.toml ]) '' + from email.header import Header, decode_header, make_header + import sys, toml, re + + try: + account_name = sys.argv[1] + sender = sys.argv[2] + recipient = sys.argv[3] + subject = make_header(decode_header(sys.argv[4])) + + config= toml.load('/etc/maddy/filters/mailbox/' + account_name + '.toml') + + for type in [ 'recipient', 'subject', 'sender' ]: + if type not in config: + continue + + for key, value in config[type].items(): + if(re.search(str("^" + key + "$"), str(eval(type)))): + print(value.replace(",", "\n")) + sys.exit(0) + + except: + sys.exit(0) + ''} {account_name} {sender} {original_rcpt_to} {subject} + } + } # ---------------------------------------------------------------------------- @@ -92,21 +146,49 @@ spf { permerr_action ignore } + command ${writePythonScriptBin "receive-filter.py" (ps: [ ps.toml ]) '' + import sys, toml + + try: + sender = sys.argv[1] + recipient = sys.argv[2] + config = toml.load('/etc/maddy/filters/receive.toml') + + for type in [ 'recipient', 'sender' ]: + if type not in config: + continue + + if 'reject' in config[type]: + if(eval(type) in config[type]['reject']): + sys.exit(10) + + if('quarantine' in config[type]): + if(eval(type) in config[type]['quarantine']): + sys.exit(20) + + except SystemExit as e: + sys.exit(e) + + except: + pass + + sys.exit(0) + ''} {sender} {rcpts} { + run_on rcpt + + code 1 ignore + code 2 ignore + code 10 reject + code 20 quarantine + } } - # Insert handling for special-purpose local domains here. - # e.g. - # destination lists.example.org { - # deliver_to lmtp tcp://127.0.0.1:8024 - # } - destination postmaster $(local_domains) { modify { replace_rcpt static { entry postmaster postmaster@$(primary_domain) entry leon@thein.ovh leah@ctu.cx entry leah@thein.ovh leah@ctu.cx - entry leah@antifa.jetzt leah@ctu.cx } # Implement plus-address notation.
diff --git a/secrets/default.nix.age b/secrets/default.nix.age @@ -1,47 +1,78 @@ -----BEGIN AGE ENCRYPTED FILE----- -YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBFZFR6V04rSTJUMjI5VVU2 -VHpwV3pPSzNkTDBnZnI2ZCtQbkJWZE1DdUJzCjlIbjU3Q3F2L3BPa0VTcHJwSXFL -djVGbXJKS3R3T1UrbW1MWkFKNUhXeWsKLS0tIEVTWXErRVNQT0UrOWUxZStqLzBn -ZnUxSmZoSUVJTFJJQ1dhSGN4Sld6aEkKxjRFI78EI7wqnZmXpju30J1gkkhoT4xB -MQFSu2SJ1w7e9jjIZnpGcEzqbgYAWXfl1nq2suqtGljP+qEpiCgyP3a5ruANIvZi -GMRQvN3hBBh7LIP9qLd28Ab3uP/2ppJihqkYRmIm1WnBQ0xVysyCay/OMNDcIpht -eIBBv+jNXovnGnxjRhTY/7YTD1f9POnmtV1SCk+31hsb6n6xyPjf39duaPcbvXSU -fD5yHeRa06apsD4zaEvleXHE4Skv8NObLtSmcC3+p7xzxmHCmWv/OZjgfIIejzXC -2DhDdvP5f4j+6Iuwd/qLemLPJDXEUSQJZOOwGQlq52Fv5+LeUApScbH3SymmgXWA -rJ0Gn9PeNmXvJxkdfmgJSCA6/fDmVO/LmLswIGL4vtLD80QpjS9wJfpclsVjJMby -h6vVYdyNUIiXCb3nISGYeb3bCdPsXtl06hydIcMYheOvbW6X/j8asDCg+jD55o8H -6ShuEwtuqBNT6pvX5ZLfvrowvxkII6/t9O3zCn2hIDJkHENKcFG3H8N+IWy2DA9r -x81d7TGzcWGaNQnLT/aH9+WwOiXZuJQ9fBpick0YoMOQOJhW4aAYtCSzPlBD8eEB -tcKbDouc3HdzrOOWWjTkg0LXbEfZxuZPCppEPbmEpGPZzrSmPbnbEzOPkDZ6sIIb -cOWEtBNEhz3MV86M8sjOqlEO9Iu7EIdpBUkwp/NDK9BhTS4dh88rudBmMkj47phV -m5XoILlM8qCTTtSnRYS1kn9iMrJCQ8nlA0jKIQ6etTdsUNlZCqBAaSeWDwAxGYcr -oJvYXA3oUqbK11Q4ivpieXLfli5jzop6jBPTQfQn6n5oSsv4qhjfFo7c1MAlqyiW -/CJ2O08zFGIceShaqs/pygyf8G/goC/CspTlxKrUZMqy2jN8VeshRvzPc+eIGJCX -zseXC0uw7wH3Rd++GvABX5hob6kzuB9TmJS+f+eg1hmN0+hvfd9vEi34o7HvnNYm -qVjByKeq0r01dKHbQeW+Sq40JUjohH4duQ7xETr5C5d6BemWE20tEqVJGilgNUYk -4B6oXNpxaz0KZsHe0CZnNUJ4sh+MKC+uBSA8bgEoXtyPLX0eZkNYmUgUM9UBEyJf -tZ26bzwU8VnZqxMoguq/GGq9LX2r1Aw8QOSYJlMFJuwZAwYW9R1RZspp/MtjnOpy -3xb+XXWRoQNDw5dKobh6l90kw+2LcPipQ8DrTkd1di0bgUA1KNvmhl5MpA741cGZ -7msrbzhkN68bcKTiKYySCb71ahxHmKD8pOEXn7W285wIMJAwoQX03yYN98SZ8sEf -QgBciM/ckCHKRNBlN/D/Xf8Ge8fS3B8NCj7qnQG6/+ed3SDb2lIjQQ6fHsu02IXr -ReaqpKaYGzp3xkLeeLpw5nHaz2yKq0Uu1GWMiiWLqjjw0INYytypsgacx69H/R0P -NC9kPaSalyD2mbWcIpiL2bv/QSVeJH+NLTk1wAj0J/LzoImLx4V15bXtdNVS8o1W -Ptr3ULbKFntAdjoOg3ZYrVVBPGH1J+itLLqNtC+aOa5YBG/9Nu/rkUdfI/qlJ4US -YhAKm0b9HvLDyT5xXTEjEbW2JUSLp/w37vkmeg/xgJRW5uyJ0ZIiPT4n4r6VPPxP -gIISlDT0DlbzQvIXSRR2CUteBXjcfnmr1vBgqgORUX6hAZ8Fo3gH/qaU+WE/Ppf7 -tzrRv3L1xIBK8aX02kvn8gdEsWBVeB8gOCXcBoWbqB/UVX/czshG02yNGty5LXOZ -qSk4GkntEEmS1dx5SFMN6RQTcZ4ikgCPvRiaNeMrdqt7hOGSjEUReyOwnhzNka8Z -603qknQ0Ewi+vbfcJ1Kh51+9HuReAIFNUwsG4uXLFz5e68ABHaefN6upO/ltg0Ng -YeeOSbh/tSfbWWhFBHzF7nOfRyssTmQD9WJMR/icDwfh80xOmHa9xja4h8pEUTaI -AxYKzzgQfoc/ExicC8T3pH9Zyz1+jZj05Jsw0KygaAQsLSY8Bu10A55bf3nrUN6E -6OZ0L7SHdEcd1w7JJpotuaqt4Ow/aC11RRnI/Q9TkB3EUWHQ6/QKdi+mLshpSlq/ -tCu8FWfs1c4ij9cMmKoE2h74alHK8LrU+qmAkTsUZz1HdpmpFLQbLMv6d2GZJ2k1 -hg6P35/a1t2hz1UlW9xGuIh4on1ZeGrgj2E2QwbZNsxOs9zO7uIwzn4GojTiFdAa -qocmoXoMzOcUuGsLF8KR0ATnmemarHGZL8dfR77pGVKew/o5ibxUrDR91lRycqfZ -3qPKoX+x9hgA1SKRKIDJjXPJ+S4tmqJzuFE+blhsoONKY+1TmapWhULcxHoVedt2 -oML+LD5N9Lg1LSst8eidvsih+nbfgtLZ6RTVda43ORc/l00YyyX264/klFAZUCLn -oqLNVUcKNBNaKzrNDWAYLjeUof8KUT/v2Af/8FpDArJcqKeOIgS6311r35uQQ8va -XZt5mdsWEvZS33EbU7gEWA8O62ahItpRugbsBep6uzXGx23QYfGm6DoUcyag8/bT -gFii00RzS9H9APVF0C1XK+SGZJKv+nolnOynfKbGDpOcjLaKTr60SRzYVV8Lx6/A -aEpC/P3hWfXwErxaYpWFT0AEYEOz5pkTrpuIh60AJ6QaCZBKWqGlWKhJD2PMHQ== +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBNSTNDakJHUWxxVU5hY3Vw +eUlQemZrOTZHT2Jva3dPL0ZZTWxJelBoNmdzClFvNDdqdjRLT09oRmhseWlnckxS +SVJTZGJDWUozVjFPcnFpdHgrdlpCbk0KLS0tIHVzb21qeXE3TzZMWTFlVTAwbkM1 +YTYwYnpXY1pPVDdtZGk0bjg3WmkvTDQK6xuh5dKwQi1iSICbRunWARasV4+u7ky5 +V1+lJ+5NI+Q1/BLjtc3bRN3THSFCSVlRP1MWLw+nUY3D1jUd2PiYKKNF7He7JjyK +6IPk8DT8jETWvDLnQSEfcq5i0wdM1hiZ1lA1tClL72pyo6sbdnHZRFFcHuruBomo +qzQomXOb/Zatx7BilfzoxFaXULpBqHfYB6+Fmw4eLHFWO1U0PaFa/Yw0U7LGoOdQ +vF4/3SbhfnlxCJylFwL1pWlPzf3zz+JR8Jr2W5knhsTx/CsENyGqUVL1LkMBjFKq +AQY+2ONZY7f4TWgCoMBvBa28YMPATCHgLtgVOJMOThm4aTEtNR5LwKFKa4VATbla +cowXfh0Tv2u+JgOP1rmE6GJdQ0Xu9QkP3dNhEZqgP7/ZlT78pt55+8ASiJLHO8DW +c0ErL92j2REOSntMQ5eEAvK3fl9OHM+XQhNyh97pbbLeaqZ6FzIZJa4HHTlEK1hm +yZlZQBcATbB78Db2xEi46iUH53/geFzcgtpuEnP9xTzdSjra4pO/20CHmPGnPVFC +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 -----END AGE ENCRYPTED FILE-----