From f7586982cca2ffc67d43a9941afa53bfa759c719 Mon Sep 17 00:00:00 2001 From: elquimista Date: Thu, 20 Mar 2025 22:10:04 -0400 Subject: [PATCH] Add local extensions --- .extensions/meta.bash | 81 +++++++++++++++++++++++++++++++++++++++ .extensions/tail.bash | 13 +++++++ .extensions/tailedit.bash | 32 ++++++++++++++++ 3 files changed, 126 insertions(+) create mode 100755 .extensions/meta.bash create mode 100755 .extensions/tail.bash create mode 100755 .extensions/tailedit.bash diff --git a/.extensions/meta.bash b/.extensions/meta.bash new file mode 100755 index 00000000..4da45c72 --- /dev/null +++ b/.extensions/meta.bash @@ -0,0 +1,81 @@ +#!/bin/bash + +regex_opts='i' +first_match_only='1' +property='' +clip='' + + +while getopts 'auUCc' opt; do + case $opt in + u) + property='user|username|login' + ;; + U) + property='url|http' + ;; + c) + clip='y' + ;; + C) + regex_opts='' + ;; + a) + first_match_only='0' + ;; + \?) + exit 1 + ;; + esac +done + +shift $(($OPTIND - 1)) +path=$1 + +[[ -z $path ]] && die + +check_sneaky_paths "$path" +passfile="$PREFIX/$path.gpg" +property=${property:-$2} + +[[ -f $passfile ]] || die "Error: $path is not in the password store." + +# This function returns a perl script +# It's an ugly way to include a nicely indented script here +get_perl_source() { + cat <; # skip password +my \$needle="$1"; # thing to search for + +sub trim { my \$s = shift; \$s =~ s/^\s+|\s+\$//g; return \$s }; + +while(<>){ + if(/^\s* # read any whitespace before the property name + (.+?): # property name and : + \s* # read any whitespace after : + (.*) # capture the rest of the line + /x){ + my \$prop_name = \$1; + my \$prop_val = \$2; + if(\$needle){ + # we are searching a specific prop + if(\$prop_name =~ /(\$needle)/$regex_opts){ + # this one matches; print the value + print \$prop_val; + exit if $first_match_only; + } + } else { + # not searching; just printing all metadata props + print trim(\$prop_name); + } + } +} +EOF +} + +value=$($GPG -d "${GPG_OPTS[@]}" "$passfile" | perl -l <(get_perl_source "$property" ) ) +if [[ -n $clip ]]; then + clip "$value" +else + echo "$value" +fi diff --git a/.extensions/tail.bash b/.extensions/tail.bash new file mode 100755 index 00000000..99495895 --- /dev/null +++ b/.extensions/tail.bash @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +path=$1 +passfile="$PREFIX/$path.gpg" +check_sneaky_paths "$path" + +if [[ -f $passfile ]]; then + $GPG -d "${GPG_OPTS[@]}" "$passfile" | tail -n +2 || exit $? +elif [[ -z $path ]]; then + die "" +else + die "Error: $path is not in the password store." +fi diff --git a/.extensions/tailedit.bash b/.extensions/tailedit.bash new file mode 100755 index 00000000..9c008567 --- /dev/null +++ b/.extensions/tailedit.bash @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +[[ $# -ne 1 ]] && die "Usage: $PROGRAM $COMMAND pass-name" + +path=${1%/} +check_sneaky_paths "$path" +mkdir -p -v "$PREFIX/$(dirname -- "$path")" +set_gpg_recipients "$(dirname -- "$path")" +passfile="$PREFIX/$path.gpg" +set_git "$passfile" + +tmpdir #Defines $SECURE_TMPDIR +tmp_file="$(mktemp -u "$SECURE_TMPDIR/XXXXXX")-${path//\//-}.txt" + +action="Add" +if [[ -f $passfile ]]; then + $GPG -d "${GPG_OPTS[@]}" "$passfile" | tail -n +2 > "$tmp_file" || exit 1 + action="Edit" +fi +${EDITOR:-vi} "$tmp_file" +[[ -f $tmp_file ]] || die "New password not saved." +$GPG -d -o - "${GPG_OPTS[@]}" "$passfile" 2>/dev/null | tail -n +2 | diff - "$tmp_file" &>/dev/null && die "Password unchanged." + +tmp_file_joined="$(mktemp -u "$SECURE_TMPDIR/XXXXXX")-${path//\//-}.txt" + +$GPG -d "${GPG_OPTS[@]}" "$passfile" | head -n 1 > "$tmp_file_joined" +cat "$tmp_file" >> "$tmp_file_joined" + +while ! $GPG -e "${GPG_RECIPIENT_ARGS[@]}" -o "$passfile" "${GPG_OPTS[@]}" "$tmp_file_joined"; do + yesno "GPG encryption failed. Would you like to try again?" +done +git_add_file "$passfile" "$action password for $path using ${EDITOR:-vi}."