diff --git a/modules/programs/gpg.nix b/modules/programs/gpg.nix index 1c77d871e..dc3dd107f 100644 --- a/modules/programs/gpg.nix +++ b/modules/programs/gpg.nix @@ -35,6 +35,13 @@ in . ''; }; + + homedir = mkOption { + type = types.path; + example = literalExample "${config.xdg.dataHome}/gnupg"; + default = "${config.home.homeDirectory}/.gnupg"; + description = "Directory to store keychains and configuration."; + }; }; config = mkIf cfg.enable { @@ -60,7 +67,10 @@ in }; home.packages = [ pkgs.gnupg ]; + home.sessionVariables = { + GNUPGHOME = cfg.homedir; + }; - home.file.".gnupg/gpg.conf".text = cfgText; + home.file."${cfg.homedir}/gpg.conf".text = cfgText; }; } diff --git a/modules/services/gpg-agent.nix b/modules/services/gpg-agent.nix index 8237c6f7b..41a1ff39d 100644 --- a/modules/services/gpg-agent.nix +++ b/modules/services/gpg-agent.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs, ... }: +{ config, options, lib, pkgs, ... }: with lib; @@ -6,6 +6,8 @@ let cfg = config.services.gpg-agent; + homedir = config.programs.gpg.homedir; + gpgInitStr = '' GPG_TTY="$(tty)" export GPG_TTY @@ -13,6 +15,27 @@ let + optionalString cfg.enableSshSupport "${pkgs.gnupg}/bin/gpg-connect-agent updatestartuptty /bye > /dev/null"; + # mimic `gpgconf` output for use in `systemd` unit definitions. + # we cannot use `gpgconf` directly because it heavily depends on system + # state, but we need the values at build time. original: + # https://github.com/gpg/gnupg/blob/c6702d77d936b3e9d91b34d8fdee9599ab94ee1b/common/homedir.c#L672-L681 + gpgconf = dir: let + f = pkgs.runCommand dir {} '' + PATH=${pkgs.coreutils}/bin:${pkgs.xxd}/bin:$PATH + + if [[ ${homedir} = ${options.programs.gpg.homedir.default} ]] + then + echo -n "%t/gnupg/${dir}" > $out + else + hash=$(echo -n ${homedir} | sha1sum -b | xxd -r -p | base32 | \ + cut -c -24 | tr '[:upper:]' '[:lower:]' | \ + tr abcdefghijklmnopqrstuvwxyz234567 \ + ybndrfg8ejkmcpqxot1uwisza345h769) + echo -n "%t/gnupg/d.$hash/${dir}" > $out + fi + ''; + in "${builtins.readFile f}"; + in { @@ -154,7 +177,7 @@ in config = mkIf cfg.enable (mkMerge [ { - home.file.".gnupg/gpg-agent.conf".text = concatStringsSep "\n" ( + home.file."${homedir}/gpg-agent.conf".text = concatStringsSep "\n" ( optional (cfg.enableSshSupport) "enable-ssh-support" ++ optional (!cfg.grabKeyboardAndMouse) "no-grab" @@ -193,7 +216,7 @@ in (mkIf (cfg.sshKeys != null) { # Trailing newlines are important - home.file.".gnupg/sshcontrol".text = concatMapStrings (s: "${s}\n") cfg.sshKeys; + home.file."${homedir}/sshcontrol".text = concatMapStrings (s: "${s}\n") cfg.sshKeys; }) # The systemd units below are direct translations of the @@ -227,7 +250,7 @@ in }; Socket = { - ListenStream = "%t/gnupg/S.gpg-agent"; + ListenStream = gpgconf "S.gpg-agent"; FileDescriptorName = "std"; SocketMode = "0600"; DirectoryMode = "0700"; @@ -247,7 +270,7 @@ in }; Socket = { - ListenStream = "%t/gnupg/S.gpg-agent.ssh"; + ListenStream = gpgconf "S.gpg-agent.ssh"; FileDescriptorName = "ssh"; Service = "gpg-agent.service"; SocketMode = "0600"; @@ -268,7 +291,7 @@ in }; Socket = { - ListenStream = "%t/gnupg/S.gpg-agent.extra"; + ListenStream = gpgconf "S.gpg-agent.extra"; FileDescriptorName = "extra"; Service = "gpg-agent.service"; SocketMode = "0600"; diff --git a/tests/modules/programs/gpg/override-defaults.nix b/tests/modules/programs/gpg/override-defaults.nix index 905b984c5..3b00e451b 100644 --- a/tests/modules/programs/gpg/override-defaults.nix +++ b/tests/modules/programs/gpg/override-defaults.nix @@ -16,11 +16,13 @@ with lib; "0xYYYYYYYYYYYYY" ]; }; + + homedir = "${config.home.homeDirectory}/bar/foopg"; }; nmt.script = '' - assertFileExists home-files/.gnupg/gpg.conf - assertFileContent home-files/.gnupg/gpg.conf ${./override-defaults-expected.conf} + assertFileExists home-files/bar/foopg/gpg.conf + assertFileContent home-files/bar/foopg/gpg.conf ${./override-defaults-expected.conf} ''; }; } diff --git a/tests/modules/services/gpg-agent/default-homedir.nix b/tests/modules/services/gpg-agent/default-homedir.nix new file mode 100644 index 000000000..f7ebf5739 --- /dev/null +++ b/tests/modules/services/gpg-agent/default-homedir.nix @@ -0,0 +1,22 @@ +{ config, lib, pkgs, ... }: + +with lib; + +{ + config = { + services.gpg-agent.enable = true; + programs.gpg.enable = true; + + nixpkgs.overlays = + [ (self: super: { gnupg = pkgs.writeScriptBin "dummy-gnupg" ""; }) ]; + + nmt.script = '' + in="${config.systemd.user.sockets.gpg-agent.Socket.ListenStream}" + if [[ $in != "%t/gnupg/S.gpg-agent" ]] + then + echo $in + fail "gpg-agent socket directory not set to default value" + fi + ''; + }; +} diff --git a/tests/modules/services/gpg-agent/default.nix b/tests/modules/services/gpg-agent/default.nix new file mode 100644 index 000000000..cf34517b2 --- /dev/null +++ b/tests/modules/services/gpg-agent/default.nix @@ -0,0 +1,4 @@ +{ + gpg-agent-default-homedir = ./default-homedir.nix; + gpg-agent-override-homedir = ./override-homedir.nix; +} diff --git a/tests/modules/services/gpg-agent/override-homedir.nix b/tests/modules/services/gpg-agent/override-homedir.nix new file mode 100644 index 000000000..6705a0014 --- /dev/null +++ b/tests/modules/services/gpg-agent/override-homedir.nix @@ -0,0 +1,25 @@ +{ config, lib, pkgs, ... }: + +with lib; + +{ + config = { + services.gpg-agent.enable = true; + programs.gpg = { + enable = true; + homedir = "${config.home.homeDirectory}/foo/bar"; + }; + + nixpkgs.overlays = + [ (self: super: { gnupg = pkgs.writeScriptBin "dummy-gnupg" ""; }) ]; + + nmt.script = '' + in="${config.systemd.user.sockets.gpg-agent.Socket.ListenStream}" + if [[ $in != "%t/gnupg/d."????????????????????????"/S.gpg-agent" ]] + then + echo $in + fail "gpg-agent socket directory is malformed" + fi + ''; + }; +}