#!/usr/bin/env bash # # pash - simple password manager. pw_add() { yn "Generate a password?" case $REPLY in [yY]) password=$("${gpg[0]}" --armor --gen-random 0 50) password=${password:0:50} ;; *) read -rsp "Enter password: " password ;; esac [[ $password ]] || die "Failed to generate a password." "${gpg[0]}" -co "$1.gpg" <<< "$password" } pw_del() { yn "Delete pass file '$1'?" [[ $REPLY == [yY] ]] && rm "$1.gpg" } pw_show() { read -r password < <("${gpg[0]}" -dq "$1.gpg") [[ ${FUNCNAME[1]} != pw_copy ]] && printf '%s\n' "$password" } pw_copy() { pw_show "$1" if [[ $TMUX ]]; then tmux load-buffer "$password" else hash xclip && xclip -selection clipboard <<< "$password" fi } pw_list() { shopt -s globstar nullglob printf '%s\n' "pash" for pwrd in **; do [[ -d $pwrd ]] && dir=/ || dir= nest=${pwrd//[^\/]} pwrd=${pwrd//[^[:print:]]/^[} pwrd=${pwrd//.gpg} printf '%s\n' "${nest//\//│ }├─ ${pwrd##*/}${dir}" done printf '└%s\b┘\n' "${nest//\//──┴}" } yn() { read -rn 1 -p "$1 [y/n]: " printf '\n' } die() { printf 'error: %s\n' "$1" >&2 exit 1 } usage() { printf '%s' "\ pash 0.1.0 - simple password manager. => [a]dd [name] - Create a new password entry. => [c]opy [name] - Copy entry to the clipboard. => [d]el [name] - Delete a password entry. => [l]ist - List all entries. => [s]how [name] - Show password for an entry. " exit 1 } main() { [[ $1 == -? || -z $1 ]] && usage mapfile -t gpg < <(type -p gpg gpg2) && [[ ! -x ${gpg[0]} ]] && die "GPG not found." mkdir -p "${pass_dir:=${XDG_DATA_HOME:=$HOME/.local/share}/pash}" || die "Couldn't create password directory." cd "$pass_dir" || die "Can't access password directory." [[ $1 == [ads]* && -z $2 ]] && die "Missing [name] argument." [[ $1 == [ds]* && ! -f $2.gpg ]] && die "Pass file '$2' doesn't exist." [[ $1 == [a]* && -f $2.gpg ]] && die "Pass file '$2' already exists." [[ $2 == */* && $2 == *../* ]] && die "Category went out of bounds." [[ $2 == /* ]] && die "Category can't start with '/'." [[ $2 == */* ]] && { mkdir -p "${2%/*}" || die "Couldn't create category '${2%/*}'.";} umask 077 case $1 in a*) pw_add "$2" ;; c*) pw_copy "$2" ;; d*) pw_del "$2" ;; s*) pw_show "$2" ;; l*) pw_list ;; *) usage esac } main "$@"