diff options
author | Ayush Agarwal <ayush@fastmail.in> | 2022-02-16 21:45:41 +0530 |
---|---|---|
committer | Ayush Agarwal <ayush@fastmail.in> | 2022-02-16 21:45:41 +0530 |
commit | f20a54de2e860f0993e2cab4ce9943ad9a0e2a29 (patch) | |
tree | 61311944ea3d45d8f9a4cb1f260031ef7b1b0235 /tessen | |
parent | e56585a3956d1802ec2bc95311ddde0d9abb41d8 (diff) |
feat: add support for gopass in the 1st menu
this feels like a hack as mentioned in the comments but if gopass
authors keep their output format stable, this should work
adding support for gopass mounts was somewhat tricky but worked out in
the end
Diffstat (limited to 'tessen')
-rwxr-xr-x | tessen | 100 |
1 files changed, 100 insertions, 0 deletions
@@ -51,6 +51,106 @@ get_pass_files() { if ! [[ -s "$tmp_prefix/$tsn_passfile".gpg ]]; then _die fi + + unset -v tmp_pass_files tmp_prefix +} + +# FIRST MENU: generate a list of gopass files, let the user select one +# this function feels like a hack to me. ideally, the issues that led to this +# hack should be fixed in gopass but if anyone has any suggestions about making +# this function better, please raise a PR +get_gopass_files() { + local line path_files file mount_name tmp_tsn_passfile + local -A tmp_gopass_files + local -a mount_name_arr + + # this feels like a hack and it's dependent on the output of `gopass config` + # + # still, this block of code saves us from using coreutils + # + # to be clear, this is needed to confirm whether the filename entered in the + # dmenu actually exists or not because dmenu backends will happily print the + # input received from a user even if that input doesn't exist in the menu + # presented to the user + # + # if you're wondering why I didn't just use `gopass ls -f`, it's because in + # an apparent effort to be user-friendly, `gopass show -n invalid-input` + # doesn't seem to exit with an error + # https://github.com/gopasspw/gopass/issues/551 + # like drew devault wrote on his blog, I hate the stale bot + # https://drewdevault.com/2021/10/26/stalebot.html + shopt -s nullglob globstar + while read -r line || [[ -n "$line" ]]; do + # we could've used `gopass config path` but since we have parse the output + # of `gopass config` because of possible mounts, better to just use `gopass + # config` + # we assume that we'll encounter `path: ...` only once and as soon as we + # do, we parse the list of all the files inside the dir and store them in + # an associative array with the name of the files as the index and the path + # as the value + if [[ "$line" == path* ]] && [[ -d "${line#* }" ]]; then + path_files=("${line#* }"/**/*.gpg) + path_files=("${path_files[@]#"${line#* }"/}") + path_files=("${path_files[@]%.gpg}") + for file in "${path_files[@]}"; do + tmp_gopass_files["$file"]="${line#* }" + done + fi + # similarly, we go through the mount points, generate the list of files + # inside those mount points, add those files to the associative array with + # the file names as the index and the location of the mount point as the + # value + # + # there's no easy way to parse and associate file names with mount points + # so we'll have to resort to some ugly hacks again + if [[ "$line" == mount* ]]; then + # remove the quotes from the parsed line + line="${line//\"/}" + # the mount name needs to be extracted to distinguish files with + # potentially identical names + mount_name="${line#mount *}" + mount_name="${mount_name% =>*}" + mount_name_arr+=("$mount_name") + if [[ -d "${line#*=> }" ]]; then + path_files=("${line#*=> }"/**/*.gpg) + path_files=("${path_files[@]#"${line#*=> }"/}") + path_files=("$mount_name"/"${path_files[@]%.gpg}") + for file in "${path_files[@]}"; do + tmp_gopass_files["$file"]="${line#*=> }" + done + fi + fi + done < <(gopass config) + shopt -u nullglob globstar + + # the actual menu + tsn_passfile="$(printf "%s\n" "${!tmp_gopass_files[@]}" \ + | "$dmenu_backend" "${dmenu_backend_opts[*]}")" + + if [[ -z "$tsn_passfile" ]]; then + _die + fi + + # remove the mount name for the path check to be successful + # initialize the temp variable with the value of tsn_passfile in case an + # entry from the gopass path is chosen + tmp_tsn_passfile="$tsn_passfile" + for idx in "${mount_name_arr[@]}"; do + if [[ "${tsn_passfile%%/*}" == "$idx" ]]; then + tmp_tsn_passfile="${tsn_passfile#*/}" + fi + done + + # we had to use an associative array to keep track of the absolute path of + # the selected file because it is possible to give invalid input to dmenu + # while making a selection and tessen should exit in that case + if [[ -n "${tmp_gopass_files["$tsn_passfile"]}" ]]; then + if ! [[ -f "${tmp_gopass_files["$tsn_passfile"]}"/"$tmp_tsn_passfile".gpg ]]; then + _die "the selected file was not found" + fi + fi + + unset -v tmp_gopass_files line path_files file mount_name mount_name_arr tmp_tsn_passfile } # parse the password store file for username, password, otp, custom autotype, |