Initial commit master
authorCian Bagshaw <cian@cianb.xyz>
Fri, 6 Oct 2023 00:43:07 +0000 (01:43 +0100)
committerCian Bagshaw <cian@cianb.xyz>
Fri, 6 Oct 2023 00:43:07 +0000 (01:43 +0100)
Moved from dotFiles repo

spass [new file with mode: 0644]

diff --git a/spass b/spass
new file mode 100644 (file)
index 0000000..c577461
--- /dev/null
+++ b/spass
@@ -0,0 +1,81 @@
+#!/bin/sh
+# spass - simple, secure password storage and retrieval
+
+[ -z "$XDG_DATA_HOME" ]        && XDG_DATA_HOME="$HOME/.local/share"
+[ -z "$PASSDIR" ]              && PASSDIR="$XDG_DATA_HOME/pass"
+
+all()          { basename -s ".gpg" -a "$PASSDIR"/*.gpg; }
+error()                { echo "$(basename "$0"): error: $1" 1>&2; stty echo; exit; }
+format()       { sed -n '/[^\S\r\n]/ { 1s/^/password: /; 2s/^/username: /; 3s/^/totp: /; 4s/^/notes: /; p }'; }
+
+if [ "$1" = "init" ]; then 
+       if [ -z "$2" ]
+               then error "gpg key not specified"
+               elif gpg -K "$2" >/dev/null 2>&1
+                       then mkdir -p "$PASSDIR"; echo "$2" > "$PASSDIR/.gpg-id"
+                       else error "gpg key doesn't exist"
+       fi;     exit
+elif [ -f "$PASSDIR/.gpg-id" ]
+       then GPG_ID="$(cat "$PASSDIR/.gpg-id")"
+       else error "password store not initialised!"
+fi; 
+
+show() {
+       [ ! -f "$PASSDIR/$1.gpg" ] && error "no such entry: $1"
+       gpg -dq "$PASSDIR/$1.gpg" | case "$2" in 
+               all)    format;;
+               notes)  sed -n 4p;;
+               totp)   sed -n 3p | oathtool --base32 --totp -;;
+               name)   sed -n 2p;;
+               *)              sed -n 1p;;
+       esac
+}
+
+dump() {
+       for f in $(all)
+               do printf "# %s\n%s\n\n" "$f" "$(show "$f" all)"
+       done | head -n -1;
+}
+
+add() { 
+       [ -z "$1" ] && error "entry name not specified"
+       printf "username: "; read -r u
+       stty -echo
+       printf "password: ";    read -r p1;     printf "\npassword (again): ";  read -r p2
+       printf "\ntotp: ";              read -r t1;     printf "\ntotp (again): ";              read -r t2
+       stty echo
+       printf "\nnotes: "; read -r n
+       [ "$p1" != "$p2" ] && error "passwords don't match"
+       [ "$t1" != "$t2" ] && error "totps don't match"
+       printf "%s\n%s\n%s\n%s" "$p1" "$u" "$t1" "$n" | gpg -eqr "$GPG_ID" -o "$PASSDIR/$1.gpg"
+}
+
+move() {
+       [ $# -lt 2 ] && error "source and destination not specified"
+       mv "$PASSDIR/$1.gpg" "$PASSDIR/$2.gpg"
+}
+
+remove () {
+       [ ! -f "$PASSDIR/$1.gpg" ] && error "entry does not exist: $1"
+       printf "are you sure you want to remove %s? [y/N] " $1; read -r c
+       [ "$c" = "y" ] || [ "$c" = "Y" ] && rm "$PASSDIR/$1.gpg" 
+}
+
+sel() {
+       [ -z "$1" ] && error "no menu program specified" 
+       ENTRY="$(all | $@)";                                                            [ -z "$ENTRY" ] && exit
+       INFO="$(printf "pass\nname\ntotp\nnotes" | "$@")";      [ -z "$INFO" ]  && exit
+       for p in $(pgrep "$(basename "$0")" | head -n -2); do kill "$p"; done
+       show "$ENTRY" "$INFO" | tr -d "\n" | xclip -selection clipboard
+       notify-send "$(basename "$0")" "$INFO copied to clipboard\nclearing in 10s"
+       sleep 10; xclip -selection clipboard < /dev/null
+}
+
+case "$1" in
+       mv)             shift; move "$@";;
+       rm)             shift; remove "$@";;
+       sel)    shift; sel "$@";;
+       add )   add     "$2";;
+       dump)   dump;;
+       *)              if [ -z "$1" ]; then all; else show "$@"; fi;;
+esac