# The certificate for the ACME service is exported as:
#
#   config.test-support.acme.caCert
#
# This value can be used inside the configuration of other test nodes to inject
# the test certificate into security.pki.certificateFiles or into package
# overlays.
#
# {
#   acme = { nodes, lib, ... }: {
#     imports = [ ./common/acme/server ];
#     networking.nameservers = lib.mkForce [
#       nodes.mydnsresolver.networking.primaryIPAddress
#     ];
#   };
#
#   dnsmyresolver = ...;
# }
#
# Keep in mind, that currently only _one_ resolver is supported, if you have
# more than one resolver in networking.nameservers only the first one will be
# used.
#
# Also make sure that whenever you use a resolver from a different test node
# that it has to be started _before_ the ACME service.
{
  config,
  pkgs,
  lib,
  ...
}: let
  testCerts = import ./certs/snakeoil-certs.nix;
  inherit (testCerts) domain;

  pebbleConf.pebble = {
    listenAddress = "0.0.0.0:443";
    managementListenAddress = "0.0.0.0:15000";

    # The cert and key are used only for the Web Front End (WFE)
    certificate = testCerts.${domain}.cert;
    privateKey = testCerts.${domain}.key;

    httpPort = 80;
    tlsPort = 443;
    ocspResponderURL = "http://${domain}:4002";
    strict = true;
  };

  pebbleConfFile = pkgs.writeText "pebble.conf" (builtins.toJSON pebbleConf);
in {
  options.test-support.acme = {
    caDomain = lib.mkOption {
      type = lib.types.str;
      default = domain;
      readOnly = true;
      description = ''
        A domain name to use with the `nodes` attribute to
        identify the CA server in the `client` config.
      '';
    };
    caCert = lib.mkOption {
      type = lib.types.path;
      readOnly = true;
      default = testCerts.ca.cert;
      description = ''
        A certificate file to use with the `nodes` attribute to
        inject the test CA certificate used in the ACME server into
        {option}`security.pki.certificateFiles`.
      '';
    };
  };

  config = {
    networking = {
      # This has priority 140, because modules/testing/test-instrumentation.nix
      # already overrides this with priority 150.
      nameservers = lib.mkOverride 140 ["127.0.0.1"];
      firewall.allowedTCPPorts = [
        80
        443
        15000
        4002
      ];

      extraHosts = ''
        127.0.0.1 ${domain}
        ${config.networking.primaryIPAddress} ${domain}
      '';
    };

    systemd.services = {
      pebble = {
        enable = true;
        description = "Pebble ACME server";
        wantedBy = ["network.target"];
        environment = {
          # We're not testing lego, we're just testing our configuration.
          # No need to sleep.
          PEBBLE_VA_NOSLEEP = "1";
        };

        serviceConfig = {
          RuntimeDirectory = "pebble";
          WorkingDirectory = "/run/pebble";

          # Required to bind on privileged ports.
          AmbientCapabilities = ["CAP_NET_BIND_SERVICE"];

          ExecStart = "${pkgs.pebble}/bin/pebble -config ${pebbleConfFile}";
        };
      };
    };
  };
}