diff --git a/hm/password/default.nix b/hm/password/default.nix index caecc50..a5cc8de 100644 --- a/hm/password/default.nix +++ b/hm/password/default.nix @@ -6,6 +6,36 @@ in config = { home.packages = with pkgs; [ pwgen + (pkgs.writeShellApplication { + name = "install-passwords"; + runtimeInputs = [ yq gawk moreutils ]; + text = (lib.strings.concatLines (map + (file: '' + ( + echo "===== Preparing to write ${file.path}" + temp="$(mktemp --tmpdir="${builtins.dirOf file.path}")" + cat "${file.template}" > "$temp" + '' + (lib.strings.concatLines (map + (password: (if password.selector == null then '' + echo "Reading ${password.path} for substituting ${password.variable}" + value="$(pass "${password.path}" | head -n1)" + '' else '' + echo "Reading ${password.path} -> ${password.selector} for substituting ${password.variable}" + value="$(pass "${password.path}" | tail -n +2 | yq -r '.${password.selector}')" + '') + '' + key="${password.variable}" + K="$key" V="$value" awk '{ gsub (ENVIRON["K"], ENVIRON["V"]); print }' "$temp" | sponge "$temp" + '') + (lib.attrsets.attrValues file.passwords))) + '' + echo "Moving the file in place" + chown "${file.owner}" "$temp" + chmod u=r "$temp" + mv -f "$temp" "${file.path}" + ) + '') + config.frogeye.passwordFiles) + ); + }) ]; programs = { bash.shellAliases = { @@ -16,4 +46,67 @@ in xsession.windowManager.i3.config.keybindings."${mod}+c" = "exec --no-startup-id ${config.programs.rofi.pass.package}/bin/rofi-pass --last-used"; # TODO Try autopass.cr }; + options = { + frogeye.passwordFiles = + let + defaultvar = "@PASSWORD@"; + pwtype = { name, ... }: { + options = { + variable = lib.mkOption { + type = lib.types.str; + default = name; + description = "String in the template that will be substituted by the actual password"; + }; + path = lib.mkOption { + type = lib.types.str; + description = "Path to the password store entry"; + }; + selector = lib.mkOption { + type = lib.types.str; + default = null; + description = "If set, will parse the password metadata as YML and use selector (yq) instead of the password."; + }; + }; + }; + mainConfig = config; + in + lib.mkOption { + default = [ ]; + type = lib.types.listOf (lib.types.submodule ({ config, ... }: { + options = { + path = lib.mkOption { + type = lib.types.str; + description = "Where to place the file."; + }; + owner = lib.mkOption { + type = lib.types.str; + default = mainConfig.home.username; + description = "Who will own the file."; + }; + template = lib.mkOption { + type = lib.types.path; + default = pkgs.writeTextFile { + name = "pwfile-template"; + text = config.text; + }; + description = "Path to the template used to make the file. Exclusive with `text`."; + }; + text = lib.mkOption { + type = lib.types.str; + default = defaultvar; + description = "Content of the template used to make the file. Exclusive with `template`."; + }; + passwords = lib.mkOption { + default = lib.optionalAttrs (config.password != null) { ${defaultvar} = config.password; }; + type = lib.types.attrsOf (lib.types.submodule pwtype); + description = "Paths to passwords that will substitute the variables in the template. Exclusive with `password`"; + }; + password = lib.mkOption { + type = lib.types.submodule ({ ... }@args: pwtype (args // { name = defaultvar; })); + description = "Path to password that will substitute '@PASSWORD@' in the template. Exclusive with `passwords`."; + }; + }; + })); + }; + }; }