{ config, pkgs, ... }:

let
  luaPam = pkgs.callPackage ./custom/luaPam.nix {};
  luaPosix = pkgs.callPackage ./custom/luaPosix.nix {};
  luaSha2 = pkgs.callPackage ./custom/luaSha2.nix {};
  prosodyAuth = pkgs.callPackage ./custom/prosody-auth.nix {};
  prosodyVirtHost = name: {
    enabled = true;
    domain = name;
    ssl = {
      key = "/var/lib/acme/yggdrasil.li/key.pem";
      cert = "/var/lib/acme/yggdrasil.li/fullchain.pem";
    };
  };
  myDomains = [ "dirty-haskell.org" "www.dirty-haskell.org" "lists.dirty-haskell.org" "l.dirty-haskell.org"
                "files.141.li" "f.141.li" "ymir.141.li" "141.li" "www.141.li" "lists.141.li" "l.141.li" "bragi.141.li"
                "ymir.xmpp.li" "xmpp.li" "www.xmpp.li" "lists.xmpp.li" "l.xmpp.li" "muc.xmpp.li" "proxy.xmpp.li"
                "files.yggdrasil.li" "f.yggdrasil.li" "ymir.yggdrasil.li" "git.yggdrasil.li" "www.yggdrasil.li" "yggdrasil.li" "lists.yggdrasil.li" "l.yggdrasil.li" "bragi.yggdrasil.li"
                "files.praseodym.org" "f.praseodym.org" "ymir.praseodym.org" "praseodym.org" "www.praseodym.org" "lists.praseodym.org" "l.praseodym.org"
                "git.rheperire.org" "api.rheperire.org" "www.rheperire.org" "rheperire.org"
                "ymir.kleen.li" "kleen.li" "www.kleen.li"
                "ymir.nights.email" "nights.email" "www.nights.email"
              ];
in rec {
  imports =
    [
      ./ymir/hw.nix
      ./ymir/mlmmj-expose.nix
      ./custom/zsh.nix
      ./users.nix
      ./custom/tinc/def.nix
      ./custom/tinc/yggdrasil.nix
      ./custom/ymir-nginx.nix
      ./custom/uucp.nix
      ./custom/unit-status-mail.nix
    ];

  boot.loader.grub = {
    enable = true;
    version = 2;
    device = "/dev/vda";
  };

  boot.kernel.sysctl = {
    "net.ipv4.tcp_keepalive_time" = 60;
    "net.ipv4.tcp_keepalive_intvl" = 10;
    "net.ipv4.tcp_keepalive_probes" = 6;
  };

  nixpkgs.config.allowUnfree = true;

  nixpkgs.config.packageOverrides = pkgs:
    rec {
      prosody = pkgs.callPackage ./customized/prosody.nix ({
          inherit (pkgs.lua51Packages) luasocket luaexpat luafilesystem luabitop luaevent luazlib luasec;
          lua5 = pkgs.lua5_1;
          communityModules = ["mod_carbons" "mod_reload_modules" "mod_csi" "mod_cloud_notify" "mod_csi_pump" "mod_smacks" "mod_track_muc_joins" "mod_watchuntrusted"];
          extraModules = [prosodyAuth];
          extraLibs = [luaPam luaPosix luaSha2];
        });
      uwsgi = pkgs.callPackage ./customized/uwsgi.nix {
        extraPlugins = {
          cgi = {
            name = "cgi";
            interpreter = pkgs.python3.interpreter;
            path = "plugins/cgi";
            inputs = [ pkgs.python3 ];
            install = ''
              ${pkgs.python3.executable} -m compileall $out/${pkgs.python3.sitePackages}/
              ${pkgs.python3.executable} -O -m compileall $out/${pkgs.python3.sitePackages}/
            '';
          };
        };
        plugins = [];
      };
      cgit = pkgs.stdenv.lib.overrideDerivation pkgs.cgit (oldAttrs : {
        buildInputs = oldAttrs.buildInputs ++ [
          pkgs.perl
          pkgs.python3
          pkgs.makeWrapper
        ];
        postInstall = let
          pythonEnv = pkgs.python3.buildEnv.override { extraLibs = with pkgs.python3Packages; [ pygments markdown ]; };
        in ''
          wrapProgram $out/lib/cgit/filters/syntax-highlighting.py --prefix PYTHONPATH ':' ${pythonEnv}/lib/*/site-packages
          wrapProgram $out/lib/cgit/filters/about-formatting.sh --prefix PATH ':' ${pkgs.coreutils}/bin
          tmpFile=$(mktemp)
          chmod +x $tmpFile
          echo "#!${pythonEnv}/bin/python3" >$tmpFile
          tail -n +2 $out/lib/cgit/filters/html-converters/md2html >>$tmpFile
          mv -v $tmpFile $out/lib/cgit/filters/html-converters/md2html
          wrapProgram $out/lib/cgit/filters/html-converters/md2html --prefix PYTHONPATH ':' ${pythonEnv}/lib/*/site-packages
          wrapProgram $out/lib/cgit/filters/html-converters/man2html --prefix PATH ':' ${pkgs.groff}/bin
        '';
      });
      push2bin = pkgs.writeScriptBin "push2bin" ''
        #!${pkgs.zsh}/bin/zsh

        PATH=${pkgs.coreutils}/bin:${pkgs.gawk}/bin

        baseDir=/srv/www/files
        baseUrl="https://f.141.li"

        tmpFile=$(mktemp "''${baseDir}/.upload.XXXXXXXXXX")

        function zshexit() { [[ -n "''${tmpFile}" && -e "''${tmpFile}" ]] && rm -f "''${tmpFile}" }

        prefix=$(tee "''${tmpFile}" | sha512sum | awk '{ print $1; }' | head -c 10)
        prefix=''${prefix:l}
        filename="$1"
 
        [[ -z "''${prefix}" || -z "''${filename}" ]] && exit 2
        [[ ! -f "''${tmpFile}" || $(stat -c '%s' "''${tmpFile}") == "0" ]] && exit 3
 
        mkdir -p "''${baseDir}/''${prefix}"
        mv "''${tmpFile}" "''${baseDir}/''${prefix}/''${filename}"
 
        chmod 755 "''${baseDir}/''${prefix}"
        chmod 644 "''${baseDir}/''${prefix}/''${filename}"
 
        printf "%s/%s/%s" "''${baseUrl}" "''${prefix}" "''${filename}"
      '';
      
    };

  environment.systemPackages = with pkgs; [
    git
    mosh
    rsync
    tmux
    zsh
    mlmmj
  ];

  networking = {
    hostName = "ymir";
    hostId = "1c5c994e";
    firewall = {
      enable = true;
      allowPing = true;
      allowedTCPPorts = [ 22 # ssh
                          25 # smtp
                          143 # imap
                          993 # imaps
                          5000 # xmpp proxy
                          5222 # xmpp.s2c
                          5269 # xmpp.s2s
                          655 # tinc.yggdrasil
                          656 # tinc.laeradhr
                          80 # http
                          443 # https
                          9418 # git
                          64738 # murmur
                          53 # DNS
                          6523 # Obby
                        ];
      allowedUDPPorts = [ 64738 # murmur
                          53 # DNS
                        ];
      allowedUDPPortRanges = [ { from = 60000; to = 61000; } # mosh
                             ];
    };
    enableIPv6 = true;
    interfaces."ens3" = {
      useDHCP = true;
      ipv6Address = "2a03:4000:6:d004::";
      ipv6PrefixLength = 64;
    };
    dnsExtensionMechanism = true;
    nameservers = [ "::1" "127.0.0.1" "10.141.1.1" "8.8.8.8" "8.8.4.4" ];
    domain = "niflheim.yggdrasil";
    search = [ "niflheim.yggdrasil" "yggdrasil" "asgard.yggdrasil" ];
  };

  users.extraUsers.root = let
    template = (import users/gkleen.nix);
    in {
        inherit (template) shell;
        openssh.authorizedKeys.keyFiles = template.openssh.authorizedKeys.keyFiles;
      };

  services.ntp = {
    enable = false;
  };

  # List services that you want to enable:

  services.openssh = {
    enable = true;
    passwordAuthentication = false;
    extraConfig = ''
      AllowGroups ssh
    '';
  };
  users.groups."ssh" = {
    members = ["gitolite" "uucp" "root"];
  };

  services.fcron = {
    enable = true;
    systab = ''
      %weekly,erroronlymail  * *   nix-collect-garbage --delete-older-than '7d'
    '';
  };

  users.groups."ssl" = {
    members = [ "prosody"
                "nginx"
                "postfix"
                "murmur"
                "infinoted"
              ];
  };

  services.timesyncd = {
    enable = true;
  };

  services.prosody = {
    enable = true;
    admins = [
               "gkleen@xmpp.li"
               "gkleen@praseodym.org"
               "gkleen@141.li"
               "gkleen@yggdrasil.li"
             ];
    allowRegistration = false;
    extraModules = [ "private"
                     "auth_custom"
                     "carbons"
                     "reload_modules"
                     "smacks"
                     "csi"
                     "csi_pump"
                     "cloud_notify"
                     "pep"
                     "disco"
                     "admin_adhoc"
                     "watchuntrusted"
                   ];
    extraConfig = ''
      reload_modules = { "group", "tls" }
      authentication="custom"
      custom_alias_file="/etc/prosody/aliases"
      custom_alias_secret_file="/etc/prosody/alias_secret"

      Component "alias.xmpp.li"
        Include "/etc/prosody/alias.xmpp.li.cfg.lua"

      Component "muc.xmpp.li" "muc"
        restrict_room_creation = true
        max_history_messages = 100
        name = "Multi-user chats"

      Component "proxy.xmpp.li" "proxy65"
        proxy65_acl = {"xmpp.li", "yggdrasil.li", "praseodym.org", "141.li", "nights.email"};
    '';

    virtualHosts = builtins.listToAttrs (map (name: { inherit name; value = prosodyVirtHost name; })
      ["xmpp.li" "yggdrasil.li" "praseodym.org" "141.li" "nights.email"]);
  };
  security.pam.services."xmpp".text = ''
    auth requisite  pam_succeed_if.so user ingroup xmpp
    auth required   pam_unix.so audit
  '';
  users.groups."shadow" = {
    members = [ "prosody"
              ];
  };
  users.groups."xmpp" = {};
  system.activationScripts."shadow-perms" = ''
    chown root:shadow /etc/shadow
    chmod 0640 /etc/shadow
  '';

  services.yggdrasilTinc = {
    enable = true;
    connect = false;
    useDNS = false;
    interfaceConfig = {
      ip4 = [ { address = "10.141.5.1"; prefixLength = 16; } ];
    };
  };

  services.customTinc.networks = ((import ./custom/tinc/laeradhr.nix) {
     inherit (pkgs) stdenv nettools openresolv;
    name = "ymir";
    connect = false;
    useDNS = false;
    ipConf = {
      ip4 = [ { address = "10.142.0.3"; prefixLength = 16; } ];
    };
    });

  users.extraUsers."nginx".extraGroups = ["uwsgi"];

  services.uwsgi = {
    enable = true;
    plugins = ["python3" "cgi"];
    instance = {
      type = "emperor";
      uid = "root"; gid = "root";
      vassals = {
        "git.yggdrasil.li" =  {
          type = "normal";
          processes = 1;
          threads = 8;
          chdir = "${pkgs.cgit}/cgit";
          cgi = "${pkgs.cgit}/cgit/cgit.cgi";
          env = [
            "CGIT_CONFIG=/etc/cgit/git.yggdrasil.li"
          ];
          socket = "/tmp/git.yggdrasil.li.sock";
          chmod-socket = "660";
          chown-socket = "uwsgi:nginx";
          uid = "uwsgi"; gid = "uwsgi";
        };
        "git.rheperire.org" =  {
          type = "normal";
          processes = 1;
          threads = 8;
          chdir = "${pkgs.cgit}/cgit";
          cgi = "${pkgs.cgit}/cgit/cgit.cgi";
          env = [
            "CGIT_CONFIG=/etc/cgit/git.rheperire.org"
          ];
          socket = "/tmp/git.rheperire.org.sock";
          chmod-socket = "660";
          chown-socket = "uwsgi:nginx";
          uid = "uwsgi"; gid = "uwsgi";
        };
      };
    };
  };
  
  users.extraUsers."uwsgi".extraGroups = ["gitolite"];

  environment.etc."cgit/git.yggdrasil.li" = {
    enable = true;
    text = ''
      robots=noindex, nofollow
      virtual-root=/
      enable-git-config=1
      remove-suffix=1

      root-title=git.yggdrasil.li
      root-desc=

      enable-http-clone=1

      enable-commit-graph=1
      snapshots=tar tar.gz tar.bz2 tar.xz zip
      side-by-side-diffs=1

      source-filter=${pkgs.cgit}/lib/cgit/filters/syntax-highlighting.py
      about-filter=${pkgs.cgit}/lib/cgit/filters/about-formatting.sh

      readme=:README.md
      readme=:README.txt
      readme=:README
      readme=:readme.md
      readme=:readme.txt
      readme=:readme

      clone-prefix=git://git.yggdrasil.li https://git.yggdrasil.li

      strict-export=git-daemon-export-ok
      section-from-path=2
      scan-path=/srv/git/repositories
    '';
  };
  environment.etc."cgit/git.rheperire.org" = {
    enable = true;
    text = ''
      robots=noindex, nofollow
      virtual-root=/
      enable-git-config=1
      remove-suffix=1

      root-title=git.rheperire.org
      root-desc=

      enable-http-clone=1

      enable-commit-graph=1
      snapshots=tar tar.gz tar.bz2 tar.xz zip
      side-by-side-diffs=1

      source-filter=${pkgs.cgit}/lib/cgit/filters/syntax-highlighting.py
      about-filter=${pkgs.cgit}/lib/cgit/filters/about-formatting.sh

      readme=:README.md
      readme=:README.txt
      readme=:README
      readme=:readme.md
      readme=:readme.txt
      readme=:readme

      clone-prefix=git://git.rheperire.org https://git.rheperire.org

      strict-export=git-daemon-export-ok
      project-list=${pkgs.writeText "project-list" ''
        rheperire.git
        cryptoids.git
      ''}
      section-from-path=2
      scan-path=/srv/git/repositories
    '';
  };

  services.gitolite = {
    enable = true;
    adminPubkey = builtins.readFile (builtins.head (import ./users/gkleen.nix).openssh.authorizedKeys.keyFiles);
    dataDir = "/srv/git";
    user = "gitolite";
    extraGitoliteRc = ''
      $RC{UMASK} = 0027;
      $RC{GIT_CONFIG_KEYS} = 'gitweb\.(owner|description|category)';
      $RC{LOG_DEST} = 'syslog';
      $RC{ROLES}{AUTHORS} = 1;
      $RC{GROUPLIST_PGM} = 'printf "@self-key-managers"';
      $RC{HOSTNAME} = '${networking.hostName}';
      $RC{LOCAL_CODE} = "$rc{GL_ADMIN_BASE}/local";
      push(@{$RC{ENABLE}}, qw(create fork D cgit repo-specific-hooks macros));
    '';
  };

  services.gitDaemon = {
    enable = true;
    basePath = services.gitolite.dataDir + "/repositories";
    user = "gitolite";
    group = "gitolite";
  };

  services.postfix = {
    enable = true;
    hostname = "ymir.yggdrasil.li";
    recipientDelimiter = "+";
    setSendmail = true;
    postmasterAlias = ""; rootAlias = ""; extraAliases = "";
    virtual = ''
      blog@dirty-haskell.org dirty-haskell@lists.yggdrasil.li
      @nights.email some@nights.email
    '';
    #destination = ["yggdrasil.li" "ymir.yggdrasil.li" "praseodym.org" "ymir.praseodym.org" "141.li" "ymir.141.li" "xmpp.li" "ymir.xmpp.li" "dirty-haskell.org" "explainuxul.de" "www.explainuxul.de" "lmu.li" "www.lmu.li" "localhost.yggdrasil.li" "localhost"];
    destination = [''regexp:${pkgs.writeText "destination" ''
        /\.?yggdrasil\.li$/ ACCEPT
        /\.?praseodym\.org$/ ACCEPT
        /\.?141\.li$/ ACCEPT
        /\.?xmpp\.li$/ ACCEPT
        /\.?kleen\.li$/ ACCEPT
        /\.?dirty-haskell\.org$/ ACCEPT
        /\.?nights\.email$/ ACCEPT
        /\.?yggdrasil$/ ACCEPT
        /\.?localdomain$/ ACCEPT
        /^localhost$/ ACCEPT
        /\.?ymir$/ ACCEPT
      ''}''];
    sslCert = "/var/lib/acme/yggdrasil.li/fullchain.pem";
    sslKey = "/var/lib/acme/yggdrasil.li/key.pem";
    config = {
      #the dh params
      smtpd_tls_dh1024_param_file = "/etc/ssl/dhparam.pem";
      smtpd_tls_dh512_param_file = "/etc/ssl/dhparam.pem";
      #enable ECDH
      smtpd_tls_eecdh_grade = "strong";
      #enabled SSL protocols, don't allow SSLv2 and SSLv3
      smtpd_tls_protocols = [ "!SSLv2" "!SSLv3"];
      smtpd_tls_mandatory_protocols = ["!SSLv2" "!SSLv3"];
      #allowed ciphers for smtpd_tls_security_level=encrypt
      smtpd_tls_mandatory_ciphers = "high";
      #allowed ciphers for smtpd_tls_security_level=may
      #smtpd_tls_ciphers = high
      #enforce the server cipher preference
      tls_preempt_cipherlist = true;
      #disable following ciphers for smtpd_tls_security_level=encrypt
      smtpd_tls_mandatory_exclude_ciphers = ["aNULL" "MD5" "DES" "ADH" "RC4" "PSD" "SRP" "3DES" "eNULL"];
      #disable following ciphers for smtpd_tls_security_level=may
      smtpd_tls_exclude_ciphers = ["aNULL" "MD5" "DES" "ADH" "RC4" "PSD" "SRP" "3DES" "eNULL"];
      #enable TLS logging to see the ciphers for inbound connections
      smtpd_tls_loglevel = "1";
      #enable TLS logging to see the ciphers for outbound connections
      smtp_tls_loglevel = "1";

      smtp_dns_support_level = "dnssec";
      smtp_tls_security_level = "dane";

      transport_maps = ''regexp:${pkgs.writeText "transport" ''
        /@(lists?|l)\./ mlmmj:
        /@subs?\.(lists?|l)\./ mlmmj-subs:
      ''} regexp:/srv/mail/transport pipemap:{texthash:/srv/mail/discard,static:{discard:}}'';

      local_recipient_maps = "";

      luser_relay = ''gkleen+''${local}'';
      
      # 10 GiB
      message_size_limit = "10737418240";
      # 10 GiB
      mailbox_size_limit = "10737418240";

      mailbox_transport_maps = "pipemap:{unix:passwd.byname, static:{lmtp:unix:private/dovecot-lmtp}}";
      #mailbox_command = ${pkgs.dovecot}/libexec/dovecot/dovecot-lda -f "$SENDER" -a "$RECIPIENT"

      smtpd_sasl_type = "dovecot";
      smtpd_sasl_path = "private/dovecot-auth";

      smtpd_sasl_auth_enable = true;
      smtpd_sasl_security_options = ["noanonymous" "noplaintext"];
      smtpd_sasl_tls_security_options = "noanonymous";
      smtpd_tls_auth_only = true;

      smtpd_delay_reject = true;
      smtpd_helo_required = true;
      smtpd_helo_restrictions = "permit";

      smtpd_recipient_restrictions = [
        "reject_unauth_pipelining"
        "reject_non_fqdn_recipient"
        "reject_unknown_recipient_domain"
        "permit_mynetworks"
        "permit_sasl_authenticated"
        "reject_non_fqdn_helo_hostname"
        "reject_invalid_helo_hostname"
        "reject_unauth_destination"
        ''check_client_access regexp:${pkgs.writeText "spfpolicy" ''
          /(^|\.)tu-muenchen\.de$/ DUNNO
          /(^|\.)tum\.de$/ DUNNO
          /(^|\.)lmu\.de$/ DUNNO
          /(^|\.)uni-muenchen\.de$/ DUNNO
          /(^|\.)lrz\.de$/ DUNNO
          /(^|\.)badw-muenchen\.de$/ DUNNO
          /(^|\.)badw\.de$/ DUNNO
          /(^|\.)hm\.edu$/ DUNNO
          /(^|\.)hswt\.de$/ DUNNO
          /(^|\.)mhn\.de$/ DUNNO
          /(^|\.)mwn\.de$/ DUNNO
          /(^|\.)boulderwelt\.de$/ DUNNO
          /.*/ spfcheck
        ''}''
      ];
      smtpd_restriction_classes = "spfcheck";
      spfcheck = "check_policy_service unix:private/policy-spf";

      smtpd_relay_restrictions = [
        "permit_mynetworks"
        "permit_sasl_authenticated"
        "reject_unauth_destination"
      ];

      mlmmj_destination_recipient_limit = "1";
      mlmmj-subs_destination_recipient_limit = "1";
      policy-spf_time_limit = "3600s";
      propagate_unmatched_extensions = ["canonical" "virtual" "alias"];

      milter_default_action = "accept";
      milter_protocol = "2";
      smtpd_milters = "local:private/dkim";
      non_smtpd_milters = "local:private/dkim";

      alias_maps = ''texthash:${pkgs.writeText "aliases" ''
        postmaster gkleen
        webmaster gkleen
        abuse gkleen
        noc gkleen
        security gkleen
        hostmaster gkleen
        usenet gkleen
        news gkleen
        www gkleen
        uucp gkleen
        ftp gkleen
        root gkleen
      ''} texthash:/srv/mail/spm
      '';

      queue_run_delay = "10s";
      minimal_backoff_time = "1m";
      maximal_backoff_time = "10m";
      maximal_queue_lifetime = "100m";
      bounce_queue_lifetime = "20m";

      sender_canonical_maps = "tcp:localhost:10001";
      sender_canonical_classes = "envelope_sender";
      recipient_canonical_maps = "tcp:localhost:10002";
      recipient_canonical_classes = ["envelope_recipient" "header_recipient"];
    };
    masterConfig = {
      uucp = {
        type = "unix";
        private = true;
        privileged = true;
        chroot = false;
        command = "pipe";
        args = [ "flags=Fqhu" "user=uucp" ''argv=${config.security.wrapperDir}/uux -z -a $sender - $nexthop!rmail ($recipient)'' ];
      };
      mlmmj = {
        type = "unix";
        private = true;
        privileged = true;
        chroot = false;
        command = "pipe";
        args = [ "flags=ORhu" "user=mlmmj" ''argv=${pkgs.mlmmj}/bin/mlmmj-receive -F -L /var/spool/lists/''${user}'' ];
      };
      mlmmj-subs = {
        type = "unix";
        private = true;
        privileged = true;
        chroot = false;
        command = "pipe";
        args = [ "flags=Fqhu" "user=uucp" ''argv=${pkgs.mlmmj-exposed}/bin/mlmmj-exposed /var/spool/lists/''${user} ''${extension}'' ];
      };
      policy-spf = {
        type = "unix";
        private = true;
        privileged = true;
        chroot = false;
        command = "spawn";
        args = [ "user=nobody" ''argv=${pkgs.python3Packages.pypolicyd-spf}/bin/policyd-spf ${./ymir/spf.conf}'' ];
      };
    };
    networks = ["127.0.0.0/8" "[::ffff:127.0.0.0]/104" "[::1]/128" "10.141.0.0/16"];
  };

  services.postsrsd = {
    enable = true;
    domain = "srs.141.li";
    separator = "+";
    excludeDomains = [ ".yggdrasil.li" "yggdrasil.li"
                       ".praseodym.org" "praseodym.org"
                       ".141.li" "141.li"
                       ".xmpp.li" "xmpp.li"
                       ".kleen.li" "kleen.li"
                       ".nights.email" "nights.email"
                       ".lmu.li" "lmu.li"
                       ".dirty-haskell.org" "dirty-haskell.org"
                     ];
  };

  systemd.timers."mlmmj-maintd" = {
    description = "run mlmmj maintenance daemon";
    wantedBy = [ "multi-user.target" ];

    timerConfig = {
      OnActiveSec = "10m";
      OnUnitActiveSec = "10m";
    };
  };

  systemd.services."mlmmj-maintd" = {
    description = "mlmmj maintenance daemon";

    serviceConfig = {
      User = "mlmmj";
      Group = "mlmmj";
      ExecStart = "${pkgs.mlmmj}/bin/mlmmj-maintd -F -d /var/spool/lists";
    };
  };

  services.opendkim = {
    enable = true;
    user = "postfix"; group = "postfix";
    socket = "local:/var/lib/postfix/queue/private/dkim";
    domains = ''csl:${pkgs.lib.concatStringsSep "," myDomains}'';
    keyPath = "/var/lib/dkim/";
    selector = "ymir";
    configFile = builtins.toFile "opendkim.conf" ''
      Syslog true
      MTACommand ${config.security.wrapperDir}/sendmail
      LogResults true
    '';
  };

  services.postgrey = {
    enable = false;
    socket = {
      path = "/var/lib/postfix/queue/private/policy-greylist";
      mode = "0777";
    };
    delay = 60;
    autoWhitelist = 1;
    maxAge = 7;
    retryWindow = 1;
  };

  services.dovecot2 = {
    enable = true;
    enableImap = true;
    enableLmtp = true;
    enablePop3 = false;
    enablePAM = true;
    sslServerCert = "/var/lib/acme/yggdrasil.li/fullchain.pem";
    sslServerKey = "/var/lib/acme/yggdrasil.li/key.pem";
    mailLocation = "maildir:~/mail:LAYOUT=index:UTF-8";
    extraConfig = ''
      mail_plugins = $mail_plugins quota
      mailbox_list_index = yes
      postmaster_address = postmaster@yggdrasil.li
      recipient_delimiter = +
      auth_username_format = %n

      service auth {
        unix_listener /var/lib/postfix/queue/private/dovecot-auth {
          mode = 0600
          user = postfix
          group = postfix
        }
      }

      service lmtp {
        unix_listener /var/lib/postfix/queue/private/dovecot-lmtp {
          mode = 0600
          user = postfix
          group = postfix
        }
      }

      namespace inbox {
        separator = /
        inbox = yes
        prefix = 
      }

      plugin {
        quota = maildir:User quota
        quota_rule = *:storage=1GB
        quota_rule2 = Trash:storage=+10%%
        quota_status_overquota = "552 5.2.2 Mailbox is full"
        quota_status_success = DUNNO
        quota_status_nouser = DUNNO
      }

      # service quota-status {
      #   executable = quota-status -p postfix
      #   unix_listener /var/lib/postfix/queue/private/policy-quota {
      #     mode = 0660
      #     user = postfix
      #     group = postfix
      #     # You can choose any port you want
      #   }
      #   client_limit = 1
      # }
    '';
  };
  security.pam.services.dovecot2.text = ''
    auth requisite  pam_succeed_if.so user ingroup mail
    auth required   pam_unix.so audit
    account sufficient pam_unix.so
  '';
  users.groups."mail" = {};

  users.extraUsers."mlmmj" = {
    isSystemUser = true;
    home = "/var/spool/lists";
    createHome = true;
    group = "mlmmj";
  };

  users.extraGroups."mlmmj" = {};

  users.extraGroups."mladmin" = {
    members = [ "gkleen" ];
  };
  
  users.extraGroups."infinoted" = {
    members = [ "infinoted" "gitolite" ];
  };

  security.sudo.extraConfig = ''
    %mladmin ALL=(mlmmj) NOPASSWD: ALL
    %infinoted ALL=(infinoted) NOPASSWD: ALL
  '';

  security.polkit = {
      enable = true;
      extraConfig = ''
        polkit.addRule(function(action, subject) {
          if (    action.id == "org.freedesktop.systemd1.manage-units"
               && action.lookup("unit") == "infinoted.service"
               && subject.isInGroup("infinoted")
             ) {
              return polkit.Result.YES;
          }
        });
      '';
    };

  security.wrappers = { "newgrp".source = "${pkgs.shadow}/bin/newgrp"; };

  security.acme = {
    certs = {
      "yggdrasil.li" = {
        allowKeysForGroup = true;
        group = "ssl";
        webroot = "/srv/www/acme/yggdrasil.li";
        email = "phikeebaogobaegh@141.li";
        extraDomains = builtins.listToAttrs (builtins.map (name: { inherit name; value = "/srv/www/acme/${name}"; }) myDomains);
        activationDelay = "6h";
        postDelay = ''
          systemctl reload nginx.service
          ${pkgs.prosody}/bin/prosodyctl reload
        '';
      };
    };
  };

  systemd.services."acme-yggdrasil.li".requires = [ "nginx.service" ]; 

  services.uucp = {
    enable = true;
    nodeName = "ymir";
    remoteNodes = ["isaac" "hel"]; # legacy name for odin
    sshUser = {
      openssh.authorizedKeys.keys = [ ''no-port-forwarding,no-X11-forwarding,no-agent-forwarding,command="${config.security.wrapperDir}/uucico" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEgtDHA7oDIaRwggGGznNaKZF68rFTziqefSCn1t9ZKe uucp@odin''
                                      ''no-port-forwarding,no-X11-forwarding,no-agent-forwarding,command="${config.security.wrapperDir}/uucico" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOWBybBQKbPucqBgULQ1phv7IKFWl1Xc4drkCx3D5mIz uucp@hel''
                                    ];
    };
    sshConfig = ''
      Host isaac
        Hostname odin.asgard.yggdrasil
        IdentityFile ~/.ssh/odin
      Host hel
        Hostname hel.midgard.yggdrasil
        IdentityFile ~/.ssh/hel
    '';
    commandPath = ["${pkgs.rmail}/bin" "${pkgs.push2bin}/bin"];
    defaultCommands = ["rmail" "push2bin"];
  };

  services.atd = {
    enable = true;
  };

  users.groups."filebin" = {
    members = ["gkleen" "uucp"];
  };

  services.nsd = {
    enable = true;
    verbosity = 3;
    interfaces = [ "10.142.0.3" "188.68.51.254" "2a03:4000:6:d004::" ];
    ipTransparent = true;
    remoteControl = {
      enable = true;
    };
    zones = {
      "inwx" = {
        notify = [ "217.70.142.96 NOKEY"
                 ];
        provideXFR = [ "217.70.142.96 NOKEY"
                     ];
        outgoingInterface = "188.68.51.254";
        children = (import ./ymir/zones/index.nix { inherit (pkgs) lib; });
        dnssec = true;
        dnssecPolicy = {
          coverage = "2mo";
        };
      };
    };
  };

  services.unbound = {
    enable = true;
    allowedAccess = ["127.0.0.0/8" "::ffff:127.0.0.0/104" "::1/128" "10.141.0.0/16"];
    interfaces = ["127.0.0.1" "::1" "10.141.5.1"];
    extraConfig = ''
      verbosity: 1
    
      private-domain: "yggdrasil"
    
      domain-insecure: "10.in-addr.arpa"
      domain-insecure: "yggdrasil"

      local-zone: "10.in-addr.arpa" nodefault

      forward-zone:
        name: "10.in-addr.arpa"
        forward-addr: 10.141.1.1
      forward-zone:
        name: "yggdrasil"
        forward-addr: 10.141.1.1
    '';
  };

  services.infinoted = {
    enable = true;
    keyFile = "/var/lib/acme/yggdrasil.li/key.pem";
    certificateFile = "/var/lib/acme/yggdrasil.li/fullchain.pem";
    plugins = [ "note-text" "note-chat" "logging" "autosave" "certificate-auth" "directory-sync" ];
    extraConfig = ''
      [certificate-auth]
      ca-list=/var/lib/infinoted/ca.cert.pem
      ca-key=/var/lib/infinoted/ca.key.pem
      accept-unauthenticated-clients=true

      [autosave]
      interval=5

      [directory-sync]
      directory=/var/lib/infinoted/dirsync
      interval=5
      hook=${pkgs.writeScript "git-sync.sh" ''
        #!${pkgs.zsh}/bin/zsh

        git -C ''${2:h} rev-parse --is-inside-work-tree &>/dev/null || exit 0

        repository=$(git -C ''${2:h} rev-parse --show-toplevel)
        [[ $? -ne 0 ]] && exit $?

        git() {
            $(whence -cp git) -C ''${repository} ''${@}
        }

        typeset -a changeSet
        changeSet=()
        git diff -z --name-only | \
            while IFS= read -r -d $'\0' change; do changeSet=(''${changeSet} ''${change}); done

        [[ ''${changeSet[(i)$(realpath ''${2} --relative-to=''${repository})]} -le ''${#changeSet} ]] || exit 0

        commitMessage=$(printf "%s modified via infinoted" $(realpath ''${2} --relative-to=''${repository}))
        git add ''${2}
        git commit -m ''${commitMessage} --no-edit ''${2}
        git push
      ''}
    '';
  };

  users.extraUsers."infinoted" = {
    home = "/var/lib/infinoted";
    createHome = true;
  };

  services.haveged = {
    enable = true;
  };

  system.autoUpgrade.enable = true;
  system.stateVersion = "17.09";

  systemd.services."nixos-upgrade".path = with pkgs; [ git ];
  systemd.services."nixos-upgrade".preStart = ''
    git -C /etc/nixos pull
    git -C /etc/nixos submodule update
  '';

  systemd.status-mail = {
    onFailure = [ "nixos-upgrade" ];
  };
}