From eb28a1bebbbefb5b854aa540a280ecd154c662e4 Mon Sep 17 00:00:00 2001 From: h7x4 Date: Fri, 2 Aug 2024 18:06:40 +0200 Subject: [PATCH] home/gpg: add key fetcher unit --- home/programs/gpg/declarative-key-fetcher.nix | 107 ++++++++++++++++++ home/programs/gpg/default.nix | 10 ++ 2 files changed, 117 insertions(+) create mode 100644 home/programs/gpg/declarative-key-fetcher.nix diff --git a/home/programs/gpg/declarative-key-fetcher.nix b/home/programs/gpg/declarative-key-fetcher.nix new file mode 100644 index 0000000..cf7b0fa --- /dev/null +++ b/home/programs/gpg/declarative-key-fetcher.nix @@ -0,0 +1,107 @@ +{ config, pkgs, lib, ... }: +let + cfg = config.programs.gpg; +in +{ + # TODO: Create proper descriptions + options = { + programs.gpg.fetch-keys = { + enable = lib.mkEnableOption "auto fetching of gpg keys by fingerprint"; + keys = lib.mkOption { + description = ""; + default = { }; + type = lib.types.attrsOf (lib.types.submodule ({ name, ... }: { + options = { + id = lib.mkOption { + description = ""; + default = name; + example = ""; + type = lib.types.str; + }; + + keyserver = lib.mkOption { + description = "If marked as null, use config"; + default = null; + example = "hkps://keys.openpgp.org"; + type = with lib.types; nullOr str; + apply = v: if v == null then "@NULL@" else v; + }; + + trust = lib.mkOption { + description = "If marked as null, it's mutable"; + default = null; + example = 4; + type = with lib.types; nullOr (ints.between 1 5); + }; + }; + })); + }; + }; + }; + + config = { + # TODO: Fix the module so that this unit runs whenever something changes + systemd.user.services.gpg-fetch-keys = let + fetchKeysApplication = let + recvKeysByKeyserver = lib.pipe cfg.fetch-keys.keys [ + lib.attrValues + (lib.foldl (acc: key: acc // { + ${key.keyserver} = (acc.${key.keyserver} or []) ++ [ key.id ]; + }) { }) + (lib.mapAttrsToList (keyserver: ids: + if keyserver == "@NULL@" + then "gpg --recv-keys ${lib.escapeShellArgs ids}" + else "gpg --keyserver ${lib.escapeShellArg keyserver} --recv-keys ${lib.escapeShellArgs ids}")) + (lib.concatStringsSep "\n") + ]; + + # Taken from modules/programs/gpg.nix + # Slightly modified in order not to read files + importTrustBashFunctions = let + gpg = "${cfg.package}/bin/gpg"; + in '' + function importTrust() { + local keyId trust + keyId="$1" + trust="$2" + { echo trust; echo "$trust"; (( trust == 5 )) && echo y; echo quit; } \ + | ${gpg} --no-tty --command-fd 0 --edit-key "$keyId" + } + ''; + + trustKeys = lib.pipe cfg.fetch-keys.keys [ + lib.attrValues + (lib.filter (key: key.trust != null)) + (map ({ id, trust, ... }: "importTrust '${id}' '${toString trust}'")) + (lib.concatStringsSep "\n") + ]; + in pkgs.writeShellApplication { + name = "fetch-gpg-keys"; + runtimeInputs = [ cfg.package ]; + text = lib.concatStringsSep "\n" [ + recvKeysByKeyserver + importTrustBashFunctions + trustKeys + ]; + }; + in lib.mkIf cfg.fetch-keys.enable { + Unit = { + Description = "Fetch declaratively listed gpg keys"; + Documentation = [ "man:gpg(1)" ]; + X-Restart-Triggers = [ "${fetchKeysApplication}" ]; + X-SwitchMethod = "restart"; + }; + + Service = { + Type = "oneshot"; + CPUSchedulingPolicy = "idle"; + IOSchedulingClass = "idle"; + ExecStart = "${lib.getExe fetchKeysApplication}"; + + Environment = [ + "GNUPGHOME=${cfg.homedir}" + ]; + }; + }; + }; +} diff --git a/home/programs/gpg/default.nix b/home/programs/gpg/default.nix index 52aa597..e058184 100644 --- a/home/programs/gpg/default.nix +++ b/home/programs/gpg/default.nix @@ -2,6 +2,7 @@ { imports = [ ./auto-refresh-keys.nix + ./declarative-key-fetcher.nix ]; programs.gpg = { @@ -17,6 +18,15 @@ "hkps://pgp.mit.edu" ]; }; + + fetch-keys = { + enable = true; + keys = { + "495A898FC1A0276F51EA3155355E5D82B18F4E71" = { trust = 4; }; + "490872D2A1D6451C9A3AA544D33368A59745C2F0" = { }; + "D231FBC3E4C3B668103982D8BC9E348039A74F7F" = { }; + }; + }; }; services.gpg-agent = {