{ inputs, pkgs, lib, config, hosts, credentials, ... }:
let
  domain = "sourcephile.fr";
  domainID = lib.replaceStrings ["."] ["_"] domain;
  inherit (config) networking;
  inherit (config.security) gnupg;
  inherit (config.services) knot;
  inherit (config.users) users;
in
{
services.knot.zones."${domain}" = {
  conf = ''
    remote:
      - id: ns_iodine
        address: 127.0.0.1@1053
    acl:
      - id: acl_localhost_acme_${domainID}
        address: 127.0.0.1
        action: update
        update-owner: name
        update-owner-match: equal
        update-owner-name: [_acme-challenge, _acme-challenge.hut, _acme-challenge.code]
        update-type: [TXT]
      - id: acl_tsig_acme_${domainID}
        key: acme_${domainID}
        action: update
        update-owner: name
        update-owner-match: equal
        update-owner-name: [_acme-challenge]
        update-type: [TXT]
      - id: acl_tsig_losurdo_${domainID}
        key: losurdo_${domainID}
        action: update
        update-owner: name
        update-owner-match: equal
        update-owner-name: [losurdo, lan.losurdo]
        update-type: [A, AAAA]

    mod-dnsproxy:
      - id: proxy_iodine
        remote: ns_iodine
        fallback: off

    zone:
      - domain: ${domain}
        file: ${domain}.zone
        serial-policy: increment
        semantic-checks: on
        notify: secondary_gandi
        acl: acl_gandi
        acl: acl_localhost_acme_${domainID}
        acl: acl_tsig_acme_${domainID}
        acl: acl_tsig_losurdo_${domainID}
        dnssec-signing: on
        dnssec-policy: rsa

      - domain: i.${domain}
        module: mod-dnsproxy/proxy_iodine

      - domain: whoami4.${domain}
        module: mod-whoami
        file: "${pkgs.writeText "whoami4.zone" ''
          $TTL 1
          @ SOA ns root.${domain}. (
            0     ; SERIAL
            86400 ; REFRESH
            86400 ; RETRY
            86400 ; EXPIRE
            1 ; MINIMUM
          )
          $TTL 86400
          @ NS ns
          ns A ${hosts.mermet._module.args.ipv4}
        ''}"
  '';
  # TODO: increase the TTL once things have settled down
  data = ''
    $ORIGIN ${domain}.
    $TTL 500

    ; SOA (Start Of Authority)
    @ SOA ns root (
      ${toString inputs.self.lastModified} ; Serial number
      24h   ; Refresh
      15m   ; Retry
      1000h ; Expire (1000h)
      1d    ; Negative caching
    )

    ; NS (Name Server)
    @ NS ns
    @ NS ns6.gandi.net.
    i NS ns
    whoami4 NS ns.whoami4
    ns.whoami4 A ${hosts.mermet._module.args.ipv4}

    ; A (DNS -> IPv4)
    @            A ${hosts.mermet._module.args.ipv4}
    mermet       A ${hosts.mermet._module.args.ipv4}
    autoconfig   A ${hosts.mermet._module.args.ipv4}
    doc          A ${hosts.mermet._module.args.ipv4}
    git          A ${hosts.mermet._module.args.ipv4}
    imap         A ${hosts.mermet._module.args.ipv4}
    mail         A ${hosts.mermet._module.args.ipv4}
    mails        A ${hosts.mermet._module.args.ipv4}
    news         A ${hosts.mermet._module.args.ipv4}
    public-inbox A ${hosts.mermet._module.args.ipv4}
    ns           A ${hosts.mermet._module.args.ipv4}
    pop          A ${hosts.mermet._module.args.ipv4}
    smtp         A ${hosts.mermet._module.args.ipv4}
    submission   A ${hosts.mermet._module.args.ipv4}
    www          A ${hosts.mermet._module.args.ipv4}
    lemoutona5pattes A ${hosts.mermet._module.args.ipv4}
    covid19      A ${hosts.mermet._module.args.ipv4}
    croc         A ${hosts.mermet._module.args.ipv4}
    stun         A ${hosts.mermet._module.args.ipv4}
    turn         A ${hosts.mermet._module.args.ipv4}
    whoami       A ${hosts.mermet._module.args.ipv4}
    code          A ${hosts.mermet._module.args.ipv4}
    builds.code   A ${hosts.mermet._module.args.ipv4}
    dispatch.code A ${hosts.mermet._module.args.ipv4}
    git.code      A ${hosts.mermet._module.args.ipv4}
    hg.code       A ${hosts.mermet._module.args.ipv4}
    hub.code      A ${hosts.mermet._module.args.ipv4}
    lists.code    A ${hosts.mermet._module.args.ipv4}
    meta.code     A ${hosts.mermet._module.args.ipv4}
    man.code      A ${hosts.mermet._module.args.ipv4}
    pages.code    A ${hosts.mermet._module.args.ipv4}
    paste.code    A ${hosts.mermet._module.args.ipv4}
    todo.code     A ${hosts.mermet._module.args.ipv4}
    miniflux      A ${hosts.mermet._module.args.ipv4}

    ; CNAME (Canonical Name)
    openconcerto     CNAME losurdo
    xmpp             CNAME mermet
    tmp              CNAME mermet
    proxy65          CNAME mermet
    cryptpad         CNAME losurdo
    cryptpad-api     CNAME losurdo
    cryptpad-files   CNAME losurdo
    cryptpad-sandbox CNAME losurdo
    mumble           CNAME mermet
    freeciv          CNAME losurdo
    nix-serve        CNAME losurdo
    nix-extracache   CNAME losurdo
    nix-localcache   CNAME lan.losurdo
    hut              CNAME code
    builds.hut       CNAME builds.code
    dispatch.hut     CNAME dispatch.code
    git.hut          CNAME git.code
    hg.hut           CNAME hg.code
    hub.hut          CNAME hub.code
    lists.hut        CNAME lists.code
    meta.hut         CNAME meta.code
    man.hut          CNAME man.code
    pages.hut        CNAME pages.code
    paste.hut        CNAME paste.code
    todo.hut         CNAME todo.code
    sftp             CNAME losurdo

    ; DMARC (Domain-based Message Authentication, Reporting and Conformance)
    _dmarc 3600 IN TXT "v=DMARC1; p=none; pct=100; rua=mailto:root+dmarc+aggregate@sourcephile.fr; ruf=mailto:root+dmarc+forensic@sourcephile.fr"

    ; SPF (Sender Policy Framework)
    @ 3600 IN TXT "v=spf1 mx ip4:${hosts.mermet._module.args.ipv4} -all"

    ; MX (Mail eXchange)
    @ 1800 MX 5 mail
    lists.code 1800 MX 5 mail
    todo.code  1800 MX 5 mail

    ; SRV (SeRVice)
    _git._tcp.git             18000 IN SRV 0 0 9418 git
    _stun._udp                18000 IN SRV 0 5 3478 stun
    _xmpp-client._tcp         18000 IN SRV 0 5 5222 xmpp
    _xmpp-server._tcp         18000 IN SRV 0 5 5269 xmpp
    _xmpp-server._tcp.salons  18000 IN SRV 0 5 5269 xmpp

    ; CAA (Certificate Authority Authorization)
    ; DOC: https://blog.qualys.com/ssllabs/2017/03/13/caa-mandated-by-cabrowser-forum
    @ CAA 128 issue "letsencrypt.org"
  '';
};
users.groups.keys.members = [ users.knot.name ];
services.knot = {
  keyFiles = [
    gnupg.secrets."knot/tsig/${domain}/acme.conf".path
    # Generated with: keymgr -t losurdo_${domainID}
    "/run/credentials/knot.service/losurdo.conf"
  ];
};
networking.nftables.ruleset = ''
  table inet filter {
    # Gandi DNS
    set output-net-knot-ipv4 {
      type ipv4_addr
      elements = { 217.70.177.40 }
    }
    set output-net-knot-ipv6 {
      type ipv6_addr
      elements = { 2001:4b98:d:1::40 }
    }
  }
'';
security.gnupg.secrets = {
  "knot/tsig/${domain}/acme.conf" = {
    # Generated with: keymgr -t acme_${domainID}
    user = users.knot.name;
  };
};
systemd.services.knot = {
  serviceConfig = {
    LoadCredentialEncrypted = "losurdo.conf:${credentials}/knot/tsig/losurdo.conf.secret";
  };
  /*
  preStart = ''
    test ! -d "$CREDENTIALS_DIRECTORY" ||
    ln -fns "$CREDENTIALS_DIRECTORY" /var/lib/knot/credentials
  '';
  */
  after = [
    gnupg.secrets."knot/tsig/${domain}/acme.conf".service
  ];
  wants = [
    gnupg.secrets."knot/tsig/${domain}/acme.conf".service
  ];
};
/* Useless since the zone is public
services.unbound.settings = {
  stub-zone = {
    name = domain;
    stub-addr = "127.0.0.1@5353";
  };
};
'';
*/
}