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 7ea239e376bbdf88e2a2c9eb2f77363eafa7a612
parent 65a4751b3802ca84904385646b95ff15bae89e70
Author: Jason A. Donenfeld <Jason@zx2c4.com>
Date:   Mon, 17 Sep 2012 18:24:06 +0200

Abstract potentially platform specific commands into their own commands.

Diffstat:
MMakefile | 18+++++++++++++++---
Dcontrib/osx-ramdisk.patch | 36------------------------------------
Msrc/password-store.sh | 83+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Asrc/platform/darwin.sh | 32++++++++++++++++++++++++++++++++
4 files changed, 97 insertions(+), 72 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,21 +1,33 @@ PREFIX ?= /usr DESTDIR ?= BINDIR ?= $(PREFIX)/bin +LIBDIR ?= $(PREFIX)/lib MANDIR ?= $(PREFIX)/share/man SYSCONFDIR ?= /etc -.PHONY: install uninstall +PLATFORMFILE := src/platform/$(shell uname | tr '[:upper:]' '[:lower:]').sh + +.PHONY: install uninstall install-platform all: @echo "Password store is a shell script, so there is nothing to do. Try \"make install\" instead." install: - @mkdir -p $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man1 $(DESTDIR)$(SYSCONFDIR)/bash_completion.d + @mkdir -p $(DESTDIR)$(BINDIR) $(DESTDIR)$(LIBDIR) $(DESTDIR)$(MANDIR)/man1 $(DESTDIR)$(SYSCONFDIR)/bash_completion.d @install -m 0755 -v src/password-store.sh $(DESTDIR)$(BINDIR)/pass @install -m 0644 -v man/pass.1 $(DESTDIR)$(MANDIR)/man1/pass.1 @install -m 0644 -v contrib/pass.bash-completion $(DESTDIR)$(SYSCONFDIR)/bash_completion.d/password-store # Uncomment to install the zsh completion file too. # @install -m 0644 -v contrib/pass.zsh-completion $(DESTDIR)$(PREFIX)/share/zsh/site-functions/_pass + @$(MAKE) install-platform + +ifneq ($(strip $(wildcard $(PLATFORMFILE))),) +install-platform: + @install -m 0644 -v $(PLATFORMFILE) $(DESTDIR)$(LIBDIR)/password-store.platform.sh + sed -i "" 's:.*platform-defined-functions.*:source $(DESTDIR)$(LIBDIR)/password-store.platform.sh:' $(DESTDIR)$(BINDIR)/pass +else +install-platform: +endif uninstall: - @rm -vf $(DESTDIR)$(BINDIR)/pass $(DESTDIR)$(MANDIR)/man1/pass.1 $(DESTDIR)$(SYSCONFDIR)/bash_completion.d/password-store + @rm -vf $(DESTDIR)$(BINDIR)/pass $(DESTDIR)$(MANDIR)/man1/pass.1 $(DESTDIR)$(SYSCONFDIR)/bash_completion.d/password-store $(DESTDIR)$(LIBDIR)/password-store.platform.sh diff --git a/contrib/osx-ramdisk.patch b/contrib/osx-ramdisk.patch @@ -1,36 +0,0 @@ -From 9f640573906bf7f98133006d09cb2bddca5ec5ae Mon Sep 17 00:00:00 2001 -From: "Jason A. Donenfeld" <Jason@zx2c4.com> -Date: Wed, 12 Sep 2012 21:08:56 +0200 -Subject: [PATCH] Use ramdisk for volatile storage in OSX. - ---- - src/password-store.sh | 13 +++++++++++++ - 1 file changed, 13 insertions(+) - -diff --git a/src/password-store.sh b/src/password-store.sh -index c736d7b..33a0e97 100755 ---- a/src/password-store.sh -+++ b/src/password-store.sh -@@ -239,6 +239,19 @@ case "$command" in - - if [[ -d /dev/shm && -w /dev/shm && -x /dev/shm ]]; then - tmp_dir="$(TMPDIR=/dev/shm mktemp -t $template -d)" -+ elif [[ $(uname) = "Darwin" ]]; then -+ cleanup_tmp() { -+ [[ -d $tmp_dir ]] || return -+ rm -rf "$tmp_file" "$tmp_dir" 2>/dev/null -+ umount "$tmp_dir" -+ diskutil quiet eject "$ramdisk_dev" -+ rmdir "$tmp_dir" -+ } -+ trap cleanup_tmp INT TERM EXIT -+ tmp_dir="$(mktemp -t $template -d)" -+ ramdisk_dev="$(hdid -drivekey system-image=yes -nomount 'ram://32768' | cut -d ' ' -f 1)" # 32768 sectors = 16 mb -+ newfs_hfs -M 700 "$ramdisk_dev" &>/dev/null || exit 1 -+ mount -t hfs -o noatime -o nobrowse "$ramdisk_dev" "$tmp_dir" || exit 1 - else - prompt=$(echo "Your system does not have /dev/shm, which means that it may" - echo "be difficult to entirely erase the temporary non-encrypted" --- -1.7.12 - diff --git a/src/password-store.sh b/src/password-store.sh @@ -7,11 +7,11 @@ umask 077 PREFIX="${PASSWORD_STORE_DIR:-$HOME/.password-store}" ID="$PREFIX/.gpg-id" -GIT="$PREFIX/.git" +GIT_DIR="$PREFIX/.git" GPG_OPTS="--quiet --yes --batch" -export GIT_DIR="$GIT" -export GIT_WORK_TREE="$PREFIX" +export GIT_DIR +export GIT_DIR_WORK_TREE="$PREFIX" version() { cat <<_EOF @@ -67,6 +67,10 @@ isCommand() { *) return 1 ;; esac } + +# +# BEGIN Platform definable +# clip() { # This base64 business is a disgusting hack to deal with newline inconsistancies # in shell. There must be a better way to deal with this, but because I'm a dolt, @@ -89,6 +93,29 @@ clip() { ) & disown echo "Copied $2 to clipboard. Will clear in 45 seconds." } +tmpdir() { + if [[ -d /dev/shm && -w /dev/shm && -x /dev/shm ]]; then + tmp_dir="$(TMPDIR=/dev/shm mktemp -t "$template" -d)" + else + prompt=$(echo "Your system does not have /dev/shm, which means that it may" + echo "be difficult to entirely erase the temporary non-encrypted" + echo "password file after editing. Are you sure you would like to" + echo -n "continue? [y/N] ") + read -p "$prompt" yesno + [[ $yesno == "y" || $yesno == "Y" ]] || exit 1 + tmp_dir="$(mktemp -t "$template" -d)" + fi + +} +GPG="gpg" +GETOPT="getopt" + +# source /path/to/platform-defined-functions +# +# END Platform definable +# + + program="$(basename "$0")" command="$1" if isCommand "$command"; then @@ -134,7 +161,7 @@ case "$command" in show|ls|list) clip=0 - opts="$(getopt -o c -l clip -n $program -- "$@")" + opts="$($GETOPT -o c -l clip -n $program -- "$@")" err=$? eval set -- "$opts" while true; do case $1 in @@ -162,9 +189,9 @@ case "$command" in exit 1 fi if [ $clip -eq 0 ]; then - exec gpg -d $GPG_OPTS "$passfile" + exec $GPG -d $GPG_OPTS "$passfile" else - clip "$(gpg -d $GPG_OPTS "$passfile" | head -n 1)" "$path" + clip "$($GPG -d $GPG_OPTS "$passfile" | head -n 1)" "$path" fi fi ;; @@ -173,7 +200,7 @@ case "$command" in noecho=0 force=0 - opts="$(getopt -o mnf -l multiline,no-echo,force -n $program -- "$@")" + opts="$($GETOPT -o mnf -l multiline,no-echo,force -n $program -- "$@")" err=$? eval set -- "$opts" while true; do case $1 in @@ -201,7 +228,7 @@ case "$command" in if [[ $multiline -eq 1 ]]; then echo "Enter contents of $path and press Ctrl+D when finished:" echo - cat | gpg -e -r "$ID" -o "$passfile" $GPG_OPTS + cat | $GPG -e -r "$ID" -o "$passfile" $GPG_OPTS elif [[ $noecho -eq 1 ]]; then while true; do read -p "Enter password for $path: " -s password @@ -209,7 +236,7 @@ case "$command" in read -p "Retype password for $path: " -s password_again echo if [[ $password == $password_again ]]; then - gpg -e -r "$ID" -o "$passfile" $GPG_OPTS <<<"$password" + $GPG -e -r "$ID" -o "$passfile" $GPG_OPTS <<<"$password" break else echo "Error: the entered passwords do not match." @@ -217,9 +244,9 @@ case "$command" in done else read -p "Enter password for $path: " -e password - gpg -e -r "$ID" -o "$passfile" $GPG_OPTS <<<"$password" + $GPG -e -r "$ID" -o "$passfile" $GPG_OPTS <<<"$password" fi - if [[ -d $GIT ]]; then + if [[ -d $GIT_DIR ]]; then git add "$passfile" git commit -m "Added given password for $path to store." fi @@ -237,31 +264,21 @@ case "$command" in trap 'rm -rf "$tmp_dir" "$tmp_file"' INT TERM EXIT - if [[ -d /dev/shm && -w /dev/shm && -x /dev/shm ]]; then - tmp_dir="$(TMPDIR=/dev/shm mktemp -t $template -d)" - else - prompt=$(echo "Your system does not have /dev/shm, which means that it may" - echo "be difficult to entirely erase the temporary non-encrypted" - echo "password file after editing. Are you sure you would like to" - echo -n "continue? [y/N] ") - read -p "$prompt" yesno - [[ $yesno == "y" || $yesno == "Y" ]] || exit 1 - tmp_dir="$(mktemp -t $template -d)" - fi - tmp_file="$(TMPDIR="$tmp_dir" mktemp -t $template)" + tmpdir #Defines $tmp_dir + tmp_file="$(TMPDIR="$tmp_dir" mktemp -t "$template")" action="Added" if [[ -f $passfile ]]; then - gpg -d -o "$tmp_file" $GPG_OPTS "$passfile" || exit 1 + $GPG -d -o "$tmp_file" $GPG_OPTS "$passfile" || exit 1 action="Edited" fi ${EDITOR:-vi} "$tmp_file" - while ! gpg -e -r "$ID" -o "$passfile" $GPG_OPTS "$tmp_file"; do + while ! $GPG -e -r "$ID" -o "$passfile" $GPG_OPTS "$tmp_file"; do echo "GPG encryption failed. Retrying." sleep 1 done - if [[ -d $GIT ]]; then + if [[ -d $GIT_DIR ]]; then git add "$passfile" git commit -m "$action password for $path using ${EDITOR:-vi}." fi @@ -270,7 +287,7 @@ case "$command" in clip=0 symbols="-y" - opts="$(getopt -o nc -l no-symbols,clip -n $program -- "$@")" + opts="$($GETOPT -o nc -l no-symbols,clip -n $program -- "$@")" err=$? eval set -- "$opts" while true; do case $1 in @@ -292,8 +309,8 @@ case "$command" in mkdir -p -v "$PREFIX/$(dirname "$path")" pass="$(pwgen -s $symbols $length 1)" passfile="$PREFIX/$path.gpg" - gpg -e -r "$ID" -o "$passfile" $GPG_OPTS <<<"$pass" - if [[ -d $GIT ]]; then + $GPG -e -r "$ID" -o "$passfile" $GPG_OPTS <<<"$pass" + if [[ -d $GIT_DIR ]]; then git add "$passfile" git commit -m "Added generated password for $path to store." fi @@ -308,7 +325,7 @@ case "$command" in delete|rm|remove) recursive="" force="-i" - opts="$(getopt -o rf -l recursive,force -n $program -- "$@")" + opts="$($GETOPT -o rf -l recursive,force -n $program -- "$@")" err=$? eval set -- "$opts" while true; do case $1 in @@ -331,13 +348,13 @@ case "$command" in fi fi rm $recursive $force -v "$passfile" - if [[ -d $GIT && ! -e $passfile ]]; then + if [[ -d $GIT_DIR && ! -e $passfile ]]; then git rm -r "$passfile" git commit -m "Removed $path from store." fi ;; push|pull) - if [[ -d $GIT ]]; then + if [[ -d $GIT_DIR ]]; then exec git $command "$@" else echo "Error: the password store is not a git repository." @@ -345,7 +362,7 @@ case "$command" in fi ;; git) - if [[ $1 == "init" || -d $GIT ]]; then + if [[ $1 == "init" || -d $GIT_DIR ]]; then exec git "$@" else echo "Error: the password store is not a git repository." diff --git a/src/platform/darwin.sh b/src/platform/darwin.sh @@ -0,0 +1,32 @@ +clip() { + before="$(pbpaste | openssl base64)" + echo -n "$1" | pbcopy + ( + sleep 45 + now="$(pbpaste | openssl base64)" + if [[ $now != $(echo -n "$1" | openssl base64) ]]; then + before="$now" + fi + echo "$before" | openssl base64 -d | pbcopy + ) & disown + echo "Copied $2 to clipboard. Will clear in 45 seconds." +} + +tmpdir() { + cleanup_tmp() { + [[ -d $tmp_dir ]] || return + rm -rf "$tmp_file" "$tmp_dir" 2>/dev/null + umount "$tmp_dir" + diskutil quiet eject "$ramdisk_dev" + rmdir "$tmp_dir" + } + trap cleanup_tmp INT TERM EXIT + tmp_dir="$(mktemp -t $template -d)" + ramdisk_dev="$(hdid -drivekey system-image=yes -nomount 'ram://32768' | cut -d ' ' -f 1)" # 32768 sectors = 16 mb + [[ -z $ramdisk_dev ]] && exit 1 + newfs_hfs -M 700 "$ramdisk_dev" &>/dev/null || exit 1 + mount -t hfs -o noatime -o nobrowse "$ramdisk_dev" "$tmp_dir" || exit 1 +} + +GPG="gpg2" +GETOPT="$(brew --prefix gnu-getopt 2>/dev/null || echo /usr/local)/bin/getopt"