#!/usr/bin/env bash # # pash - simple password manager. pw_add() { yn "Generate a password?" case $REPLY in [yY]) [[ $OSTYPE == linux* ]] && check_entropy pw_gen ;; *) read -rsp "Enter password: " password ;; esac [[ $password ]] || die "Failed to generate a password." [[ $1 == */* ]] && { mkdir -p "${1%/*}" || die "Couldn't create category '${1%/*}'.";} "${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") } pw_list() { shopt -s globstar nullglob for pwrd in **; do [[ -d $pwrd ]] && dir=/ nest=${pwrd//[^\/]} pwrd=${pwrd//[^[:print:]]/^[} pwrd=${pwrd//.gpg} if [[ -z $tree ]]; then printf '%s\n' "$pwrd" else printf '%s\n' "${nest//\//│ }├─ ${pwrd##*/}${dir}" dir= fi done } pw_gen() { [[ -r /dev/urandom ]] || die "/dev/urandom is not readable." mapfile -tn "${length:=50}" rand &2 exit 1 } copy() { [[ $TMUX ]] && { tmux load-buffer "$password" return } hash xclip 2>/dev/null && xclip -selection clipboard &>/dev/null <<< "$password" } usage() { printf '%s' "\ pash - simple password manager. usage: pash [add|del|show|list] [name] [-n,-q,-c] [-l length] -c Copy password to clipboard. -l length Length of generated passwords. -n Limit passwords to alphanumeric characters. -q Don't print password to stdout. -t Print list output as a tree. -h Print this message. -v Show version. " exit 1 } get_args() { [[ $1 != l* ]] && shift 1 shift 1 while getopts ":ncvqtl:" opt; do case $opt in c) clipboard=1 ;; l) length=${OPTARG//[^0-9]} ;; n) plain=1 ;; q) quiet=1 ;; t) tree=1 ;; v) printf '%s\n' "pash 0.01"; exit ;; ?) usage ;; esac; done } main() { get_args "$@" 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." case $1 in a*) pw_add "$2" ;; d*) pw_del "$2" ;; s*) pw_show "$2" ;; l*) pw_list ;; *) usage ;; esac [[ $clipboard && $password ]] && copy [[ -z $quiet && $password ]] && printf '%s\n' "$password" } main "$@"