commit dff3b23881b023519f9385031481c92f10686d8b Author: Dylan Araps Date: Sun Feb 24 22:36:47 2019 +0200 initial diff --git a/pash b/pash new file mode 100755 index 0000000..74cd6df --- /dev/null +++ b/pash @@ -0,0 +1,148 @@ +#!/usr/bin/env bash +# +# pash - simple password manager. + +pw_add() { + [[ $OSTYPE == linux* ]] && + check_entropy + + generate_password + + [[ $password ]] || + die "Failed to generate a password." + + gpg2 -co "$1.gpg" <<< "$password" +} + +pw_del() { + read -rn 1 -p "Delete pass file '$1'? [y/n]: "; printf '\n' + + [[ $REPLY == [yY] ]] && + rm "$1.gpg" +} + +pw_show() { + read -r password < <(gpg2 -dq "$1.gpg" || + die "Failed to decrypt '$1'." + ) +} + +pw_list() { + pw_files=(*.gpg) + + [[ ! -f ${pw_files[0]} ]] && { + printf '%s\n' "No stored passwords." + exit + } + + printf '\e[1m%s\e[m:\n' "Stored Passwords" + printf -- ' - %s\n' "${pw_files[@]//.gpg}" +} + +generate_password() { + # Grab '$length' number of lines from '/dev/urandom'. + # '$length' also controls the generated password length. + # This is a simple way to ensure that pash grabs enough + # data from '/dev/urandom' to meet the length requirement. + # example: 50 lines from /dev/urandom == 50 char password + mapfile -tn "${length:=50}" rand &2 + exit 1 +} + +usage() { printf '%s' "\ +pash - simple password manager. +usage: pash [add,del,show,list] [name] [-n] [-l length] + +-n Limit passwords to alphanumeric characters. +-l length Length of generated passwords. +-q Don't print password to stdout. +-h Print this message. +-v Show version. +" +exit 1 +} + +get_args() { + # The first two arguments aren't flags, skip them. + shift 2 + + while getopts ":ncvql:" opt; do case $opt in + n) plain=1 ;; + l) length=$((OPTARG>300?300:OPTARG)) ;; + c) clipboard=1 ;; + q) quiet=1 ;; + v) printf '%s\n' "pash 0.01"; exit ;; + ?) usage ;; + esac; done +} + +main() { + get_args "$@" + + hash gpg2 2>/dev/null || + die "GPG not found." + + [[ -r /dev/urandom ]] || + die "/dev/urandom is not readable." + + 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 + + [[ -z $quiet && $password ]] && + printf '%s\n' "$password" + + [[ $clipboard && $password ]] && hash xclip 2>/dev/null && + xclip -selection clipboard &>/dev/null <<< "$password" +} + +main "$@"