all repos — pw @ 2b87c05c6e3773f299a566323756fac133cab6bc

minimal password store

pw (view raw)

  1#!/usr/bin/env bash
  2# pw - a mnml password manager
  3
  4command -v gpg >/dev/null 2>&1 && gpg=gpg
  5command -v gpg2 >/dev/null 2>&1 && gpg=gpg2
  6
  7# check if xclip or pbcopy exist
  8# command -v xclip >/dev/null 2>&1 && copy="xclip -rmlastnl -selection clipboard"
  9# command -v pbcopy >/dev/null 2>&1 && copy="pbcopy | tr -d '\n'"
 10
 11# export PW_DIR to your own path
 12[[ -z "$PW_DIR" ]] && PW_DIR="$HOME/.pw"
 13
 14init() {
 15    if [[ ! -e "$PW_DIR" ]]; then
 16        mkdir -p "$PW_DIR"
 17        printf "pw: password directory initialized at %s\n" "$PW_DIR"
 18    else
 19        printf "PW_DIR is %s\n" "$PW_DIR"
 20        die "$PW_DIR exists"
 21    fi
 22}
 23
 24add() {
 25    # $1: path to file
 26    # $2 [optional]: password text
 27    [[ -z "$PW_KEY" ]] && die "\$PW_KEY not set"
 28
 29    if [[ "$#" -eq 2 ]]; then
 30        pass="$2"
 31    else
 32        # uses default length of 25 chars, unless PW_LEN is set
 33        pass="$(pwgen "${PW_LEN:-25}" 1 -s)"
 34        printf "pw: generated password for %s\n" "$1"
 35    fi
 36    if [[ ! -f "$PW_DIR/$1.gpg" ]]; then
 37        printf "%s" "$pass" | "$gpg" -aer "$PW_KEY" -o "$PW_DIR/$1.gpg"
 38        printf "pw: %s/%s.gpg created\n" "$PW_DIR" "$1"
 39    else
 40        die "the file $PW_DIR/$1.gpg exists"
 41    fi
 42    (
 43        cd $PW_DIR
 44        git add .
 45        git commit -m "$(date)"
 46        remote="$(git remote show)"
 47        branch="$(git branch --show-current)"
 48        git pull -r "$remote" "$branch"
 49        git push "$remote" "$branch"
 50    )
 51}
 52
 53list() {
 54    for f in "$PW_DIR"/*.gpg; do
 55        printf '%s\n' "$(basename "${f%.gpg}")"
 56    done
 57}
 58
 59del() {
 60    checkf "$PW_DIR/$1.gpg"
 61    read -rn 1 -p "pw: are you sure you want to delete $1? [y/n]: "
 62    printf "\n"
 63    [[ "$REPLY" == [yY] ]] && {
 64        rm -f "$PW_DIR/$1.gpg"
 65        printf "pw: deleted %s" "$1"
 66    }
 67}
 68
 69show() {
 70    checkf "$PW_DIR/$1.gpg"
 71    "$gpg" --decrypt --quiet --use-agent "$PW_DIR/$1.gpg"
 72}
 73
 74# TODO: rework having to checkf twice
 75
 76copy() {
 77    checkf "$PW_DIR/$1.gpg"
 78    if [[ "$OSTYPE" =~ darwin* ]]; then
 79        show "$1" | head -1 | pbcopy | tr -d '\n'
 80    else
 81        show "$1" | head -1 | xclip -rmlastnl -selection clipboard
 82    fi
 83    printf "pw: copied %s to clipboard\n" "$1"
 84}
 85
 86usage() {
 87    usage="
 88pw - mnml password manager
 89
 90usage: pw [options] [NAME]
 91All options except -i and -h require a NAME argument.
 92
 93options:
 94  -i            Initializes password directory at \$HOME/.pw or at \$PW_DIR, if it exists.
 95  -a            Add a password.
 96  -g            Generate a password.
 97  -s            Print password to STDOUT.
 98  -l            List out all passwords.
 99  -c            Copy existing password to clipboard.
100  -d            Delete password.
101  -h            Display this help message and exit.
102
103Requires PW_KEY to be set. Optionally, set PW_DIR for custom directory location.
104Set PW_LEN to an integer of your choice, to override the default password length of 25.
105"
106
107    printf "%s" "$usage"
108    exit 1
109}
110
111checkf() {
112    [[ ! -f "$1" ]] &&
113        die "$1 does not exist"
114}
115
116die() {
117    printf "error: %s\n" "$1" >&2
118    exit 1
119}
120
121
122main() {
123    [[ -z "$1" ]] && {
124        usage
125    }
126
127    while getopts "ila:g:s:c:d:h" options
128    do
129        # shellcheck disable=SC2221,SC2222
130        case "$options" in
131            i) init ;;
132            l) list ;;
133            g) add "$OPTARG" ;;
134            a)
135               read -rsp "enter password: " pass
136               printf "\n"
137               add "$OPTARG" "$pass"
138               ;;
139            s) show "$OPTARG" ;;
140            c) copy "$OPTARG" ;;
141            d) del "$OPTARG" ;;
142            *|h) usage ;;
143        esac
144    done
145
146    shift $(( OPTIND -1 ))
147}
148
149main "$@"