password-store

Simple password manager using gpg and ordinary unix directories
git clone https://git.zx2c4.com/password-store
Log | Files | Refs | README | LICENSE

commit e98c2f7af467964ab019ab1f13a09107b6e38da8
parent 4311b7728ec75eb9cf08302c57376ad0a46673a8
Author: Jason A. Donenfeld <Jason@zx2c4.com>
Date:   Mon,  6 Aug 2012 15:14:36 +0200

Be slicker and more like git.

Diffstat:
Mpassword-store.sh | 287++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
1 file changed, 173 insertions(+), 114 deletions(-)

diff --git a/password-store.sh b/password-store.sh @@ -16,44 +16,70 @@ by Jason Donenfeld Jason@zx2c4.com Usage: - $0 --init gpg-id + $program init gpg-id Initialize new password storage and use gpg-id for encryption. - $0 [--ls] + $program [ls] [subfolder] List passwords. - $0 pass-name - Show existing password. - $0 --insert [--multiline] pass-name + $program [show] [--clip,-c] pass-name + Show existing password and optionally put it on the clipboard. + If put on the clipboard, it will be cleared in 45 seconds. + $program insert [--multiline,-m] pass-name Insert new optionally multiline password. - $0 --generate [--no-symbols] pass-name pass-length + $program generate [--no-symbols,-n] [--clip,-c] pass-name pass-length Generate a new password of pass-length with optionally no symbols. - $0 --remove pass-name + Optionally put it on the clipboard and clear board after 45 seconds. + $program remove pass-name Remove existing password. - $0 --push + $program push If the password store is a git repository, push the latest changes. - $0 --pull + $program pull If the password store is a git repository, pull the latest changes. - $0 --help + $program help Show this text. _EOF } +isCommand() { + case "$1" in + init|ls|show|insert|generate|remove|push|pull|help) return 0 ;; + *) return 1 ;; + esac +} +clip() { + before="$(xclip -o -selection clipboard)" + echo "$1" | xclip -selection clipboard + (sleep 45s; echo "$before" | xclip -selection clipboard) & disown + echo "Copied $2 to clipboard. Will clear in 45 seconds." +} -if [[ $1 == "--init" ]]; then - if [[ $# -ne 2 ]]; then - echo "Usage: $0 $1 gpg-id" - exit 1 - fi - mkdir -v -p "$PREFIX" - echo "$2" > "$ID" - echo "Password store initialized for $2." - exit 0 -elif [[ $1 == "--help" ]]; then - usage - exit 0 +program="$0" +command="$1" +if isCommand "$command"; then + shift +else + command="show" fi +case "$command" in + init) + if [[ $# -ne 1 ]]; then + echo "Usage: $program $command gpg-id" + exit 1 + fi + gpg_id="$1" + mkdir -v -p "$PREFIX" + echo "gpg_id" > "$ID" + echo "Password store initialized for gpg_id." + exit 0 + ;; + help) + usage + exit 0 + ;; +esac + if ! [[ -f $ID ]]; then echo "You must run:" - echo " $0 --init your-gpg-id" + echo " $0 init your-gpg-id" echo "before you may use the password store." echo usage @@ -62,96 +88,129 @@ else ID="$(head -n 1 "$ID")" fi -if [[ $# -eq 0 ]] || [[ $1 == "--ls" ]]; then - tree "$PREFIX" | tail -n +2 | head -n -2 | sed 's/\(.*\)\.gpg$/\1/'; -elif [[ $1 == "--insert" ]]; then - if [[ $# -lt 2 ]]; then - echo "Usage: $0 $1 [--multiline] pass-name" - exit 1 - fi - ml=0 - if [[ $2 == "--multiline" ]]; then - shift - ml=1 - fi - mkdir -p -v "$PREFIX/$(dirname "$2")" +case "$command" in + show|ls) + clip=0 + if [[ $1 == "--clip" || $1 == "-c" ]]; then + clip=1 + shift + fi + path="$1" + if [[ -d $PREFIX/$path ]]; then + if [[ $path == "" ]]; then + echo "Password Store" + else + echo $path + fi + tree "$PREFIX/$path" | tail -n +2 | head -n -2 | sed 's/\(.*\)\.gpg$/\1/'; + else + passfile="$PREFIX/$path.gpg" + if ! [[ -f $passfile ]]; then + echo "$path is not in the password store." + exit 1 + fi + if [ $clip -eq 0 ]; then + exec gpg -q -d "$passfile" + else + clip $(gpg -q -d "$passfile") $path + fi + fi + ;; + insert) + ml=0 + if [[ $1 == "--multiline" || $1 == "-m" ]]; then + ml=1 + shift + fi + if [[ $# -ne 1 ]]; then + echo "Usage: $program $command [--multiline,-m] pass-name" + exit 1 + fi + path="$1" + mkdir -p -v "$PREFIX/$(dirname "$path")" - passfile="$PREFIX/$2.gpg" - if [[ $ml -eq 0 ]]; then - echo -n "Enter password for $2: " - head -n 1 | gpg -e -r "$ID" > "$passfile" - else - echo "Enter contents of $2 and press Ctrl+D when finished:" - echo - cat | gpg -e -r "$ID" > "$passfile" - fi - if [[ -d $GIT ]]; then - git add "$passfile" - git commit -m "Added given password for $2 to store." - fi -elif [[ $1 == "--generate" ]]; then - if [[ $# -lt 3 ]]; then - echo "Usage: $0 $1 [--no-symbols] pass-name pass-length" - exit 1 - fi - symbols="-y" - if [[ $2 == "--no-symbols" ]]; then - symbols="" - shift - fi - if ! [[ $3 =~ ^[0-9]+$ ]]; then - echo "pass-length \"$3\" must be a number." + passfile="$PREFIX/$path.gpg" + if [[ $ml -eq 0 ]]; then + echo -n "Enter password for $path: " + head -n 1 | gpg -e -r "$ID" > "$passfile" + else + echo "Enter contents of $path and press Ctrl+D when finished:" + echo + cat | gpg -e -r "$ID" > "$passfile" + fi + if [[ -d $GIT ]]; then + git add "$passfile" + git commit -m "Added given password for $path to store." + fi + ;; + generate) + clip=0 + symbols="-y" + while true; do + if [[ $1 == "--no-symbols" || $1 == "-n" ]]; then + symbols="" + shift + elif [[ $1 == "--clip" || $1 == "-c" ]]; then + clip=1 + shift + else + break + fi + done + if [[ $# -ne 2 ]]; then + echo "Usage: $program $command [--no-symbols,-n] [--clip,-c] pass-name pass-length" + exit 1 + fi + path="$1" + length="$2" + if ! [[ $length =~ ^[0-9]+$ ]]; then + echo "pass-length \"$length\" must be a number." + exit 1 + fi + mkdir -p -v "$PREFIX/$(dirname "$path")" + pass="$(pwgen -s $symbols $length 1)" + passfile="$PREFIX/$path.gpg" + echo $pass | gpg -e -r "$ID" > "$passfile" + if [[ -d $GIT ]]; then + git add "$passfile" + git commit -m "Added generated password for $path to store." + fi + + if [ $clip -eq 0 ]; then + echo "The generated password to $path is:" + echo "$pass" + else + clip "$pass" "$path" + fi + ;; + remove) + if [[ $# -ne 1 ]]; then + echo "Usage: $program $command pass-name" + exit + fi + path="$1" + passfile="$PREFIX/$path.gpg" + if ! [[ -f $passfile ]]; then + echo "$path is not in the password store." + exit 1 + fi + rm -i -v "$passfile" + if [[ -d $GIT ]] && ! [[ -f $passfile ]]; then + git rm -f "$passfile" + git commit -m "Removed $path from store." + fi + ;; + push|pull) + if [[ -d $GIT ]]; then + exec git $command $@ + else + echo "Error: the password store is not a git repository." + exit 1 + fi + ;; + *) + usage exit 1 - fi - mkdir -p -v "$PREFIX/$(dirname "$2")" - pass="$(pwgen -s $symbols $3 1)" - passfile="$PREFIX/$2.gpg" - echo $pass | gpg -e -r "$ID" > "$passfile" - if [[ -d $GIT ]]; then - git add "$passfile" - git commit -m "Added generated password for $2 to store." - fi - echo "The generated password to $2 is:" - echo "$pass" -elif [[ $1 == "--remove" ]]; then - if [[ $# -ne 2 ]]; then - echo "Usage: $0 $1 pass-name" - exit - fi - passfile="$PREFIX/$2.gpg" - if ! [[ -f $passfile ]]; then - echo "$2 is not in the password store." - exit 1 - fi - rm -i -v "$passfile" - if [[ -d $GIT ]] && ! [[ -f "$passfile" ]]; then - git rm -f "$passfile" - git commit -m "Removed $2 from store." - fi -elif [[ $1 == "--push" ]]; then - if [[ -d $GIT ]]; then - shift - exec git push $@ - else - echo "Error: the password store is not a git repository." - exit 1 - fi -elif [[ $1 == "--pull" ]]; then - if [[ -d $GIT ]]; then - shift - exec git pull $@ - else - echo "Error: the password store is not a git repository." - exit 1 - fi -elif [[ $# -eq 1 ]]; then - passfile="$PREFIX/$1.gpg" - if ! [[ -f $passfile ]]; then - echo "$1 is not in the password store." - exit 1 - fi - exec gpg -q -d "$passfile" -else - usage - exit 1 -fi + ;; +esac +exit 0