# SPDX-FileCopyrightText: 2022 Luke Granger-Brown <depot@lukegb.com>
#
# SPDX-License-Identifier: Apache-2.0

{ depot, pkgs, config, lib, ... }:
let
  inherit (lib) mkIf mkOption types concatStringsSep unique optional mkAfter;

  pkg = depot.go.secretsmgr;
  cfg = config.my.vault.secretsmgr;

  jsonFormat = pkgs.formats.json { };

  dummyHostKey = pkgs.runCommandLocal "dummy-host-key" {
    nativeBuildInputs = [ config.programs.ssh.package ];
  } ''
    ssh-keygen -q -f $out -N ""
  '';
in
{
  options.my.vault.secretsmgr = {
    enable = mkOption {
      type = types.bool;
      default = config.my.vault.enable;
    };
    groups = mkOption {
      type = with types; listOf str;
      default = [];
    };
    restartableUnits = mkOption {
      type = with types; listOf str;
      default = [];
    };

    acmeCertificates.enable = mkOption {
      type = types.bool;
      default = true;
    };
    acmeCertificates.expiryThreshold = mkOption {
      type = types.str;
      default = "744h";
    };
    acmeCertificates.config = mkOption {
      type = jsonFormat.type;
      default = {};
    };
    acmeCertificates.mount = mkOption {
      type = types.str;
      default = "acme";
    };

    sshCertificates.enable = mkOption {
      type = types.bool;
      default = true;
    };
    sshCertificates.mount = mkOption {
      type = types.str;
      default = "ssh-host";
    };
    sshCertificates.expiryThreshold = mkOption {
      type = types.str;
      default = "72h";
    };
    sshCertificates.outputDir = mkOption {
      type = types.str;
      default = "/var/lib/secretsmgr/ssh";
    };
    sshCertificates.principals = mkOption {
      type = with types; listOf str;
      default = let inherit (config.networking) hostName; in [
        "${hostName}"
        "${hostName}.as205479.net"
        "${hostName}.int.as205479.net"
        "${hostName}.otter-acoustic.ts.net"
      ];
    };
    sshCertificates.role = mkOption {
      type = types.str;
      default = config.networking.hostName;
    };
  };

  config = mkIf cfg.enable {
    my.vault.secretsmgr.restartableUnits = mkIf cfg.sshCertificates.enable (mkAfter ["sshd.service"]);

    users.groups.secretsmgr = {};
    users.users.secretsmgr = {
      isSystemUser = true;
      group = "secretsmgr";
    };

    systemd.services.secretsmgr = {
      requires = ["vault-agent.service"];
      after = ["vault-agent.service"];
      restartIfChanged = true;

      serviceConfig = {
        User = "secretsmgr";
        Group = "secretsmgr";
        SupplementaryGroups = cfg.groups ++ [ "vault-agent" ];
        AmbientCapabilities = [ "CAP_SETGID" ];

        Type = "oneshot";
        ExecStart = concatStringsSep " " ([
          "${pkg}/bin/secretsmgr"
          "--logtostderr"
        ] ++ lib.optionals cfg.acmeCertificates.enable [
          "--acme_certificates_config=${jsonFormat.generate "secretsmgr-acme-certificates-config.json" cfg.acmeCertificates.config}"
          "--acme_certificates_expiry_threshold=${cfg.acmeCertificates.expiryThreshold}"
          "--acme_certificates_mount=${cfg.acmeCertificates.mount}"
        ] ++ [
          "--sign_ssh_host_keys=${toString cfg.sshCertificates.enable}"
        ] ++ lib.optionals cfg.sshCertificates.enable [
          "--ssh_host_key_ca_path=${cfg.sshCertificates.mount}"
          "--ssh_host_key_expiry_threshold=${cfg.sshCertificates.expiryThreshold}"
          "--ssh_host_key_output_dir=${cfg.sshCertificates.outputDir}"
          "--ssh_host_key_principals=${concatStringsSep "," cfg.sshCertificates.principals}"
          "--ssh_host_key_role=${cfg.sshCertificates.role}"
          "--ssh_dummy_host_key=${dummyHostKey}"
          "--sshd=${config.programs.ssh.package}/bin/sshd"
        ]);
      };
    };

    systemd.timers.secretsmgr = {
      requires = ["vault-agent.service"];
      after = ["vault-agent.service" "network-online.target"];
      wantedBy = ["timers.target"];

      timerConfig = {
        OnActiveSec = "30";
        OnUnitInactiveSec = "30min";
      };
    };

    systemd.tmpfiles.rules = [
      "d /var/lib/acme 0711 secretsmgr secretsmgr - -"
      "d /var/lib/secretsmgr 0711 secretsmgr secretsmgr - -"
      "d /var/lib/secretsmgr/ssh 0711 secretsmgr secretsmgr - -"
    ];

    security.polkit.extraConfig = lib.mkAfter ''
      // NixOS module: depot/lib/secretsmgr.nix
      polkit.addRule(function(action, subject) {
        if (action.id !== "org.freedesktop.systemd1.manage-units" ||
            subject.user !== "secretsmgr") {
          return polkit.Result.NOT_HANDLED;
        }

        var verb = action.lookup("verb");
        if (verb !== "restart" && verb !== "reload-or-restart" && verb != "reload-or-try-restart") {
          return polkit.Result.NOT_HANDLED;
        }

        var allowedUnits = ${builtins.toJSON (unique cfg.restartableUnits)};
        var unit = action.lookup("unit");
        for (var i = 0; i < allowedUnits.length; i++) {
          if (allowedUnits[i] === unit) {
            return polkit.Result.YES;
          }
        }
        return polkit.Result.NOT_HANDLED;
      });
    '';

  };

}