diff options
33 files changed, 494 insertions, 68 deletions
@@ -1,16 +1,32 @@ +2014-02-20 - 0.3 - Silvio Rhatto <rhatto@riseup.net> + + Try to find a similar file at keyringer_get_file + + Added xclip action (#33) + + Check key expirations (#37) + + Proper error handling at edit action + + New actions: find, mv, rmdir + + Support for RELATIVE_FOLDER at git action + + New actions: shell (#34), help, mkdir, teardown + 2013-11-26 - 0.2.9 Silvio Rhatto <rhatto@riseup.net> - Added 'tree' action + Added 'tree' action - Added 'rm' alias to 'del' action + Added 'rm' alias to 'del' action - Set .gitignore during initialization and when using tmp inside the repository + Set .gitignore during initialization and when using tmp inside the repository - Pass options to git-rm at del action + Pass options to git-rm at del action - Simpler ramdisk/tmpfs check at keyringer_check_tmp + Simpler ramdisk/tmpfs check at keyringer_check_tmp - Better mode check on keyringer_check_tmp (closes #30) + Better mode check on keyringer_check_tmp (closes #30) Fixed minor typos @@ -56,7 +56,9 @@ tarball: release: @make build_man git commit -a -m "Keyringer $(VERSION)" - git tag -s $(VERSION) -m "Keyringer $(VERSION)" @make tarball - gpg --armor --detach-sign --output ../tarballs/keyringer-$(VERSION).tar.bz2.asc ../tarballs/keyringer-$(VERSION).tar.bz2 + gpg --use-agent --armor --detach-sign --output ../tarballs/keyringer-$(VERSION).tar.bz2.asc ../tarballs/keyringer-$(VERSION).tar.bz2 scp ../tarballs/keyringer-$(VERSION).tar.bz2* keyringer:/var/sites/keyringer/releases/ + # We're doing tagging afterwards: + # http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=568375 + git tag -s $(VERSION) -m "Keyringer $(VERSION)" diff --git a/development.mdwn b/development.mdwn index 3400643..cf969fe 100644 --- a/development.mdwn +++ b/development.mdwn @@ -60,6 +60,7 @@ Update the debian branch: git-import-orig --upstream-vcs-tag=$VERSION ../tarballs/keyringer-$VERSION.tar.bz2 dch -e # fine tune the changelog prepared by git-dch git commit -a -m "Updating debian/changelog" + git-buildpackage --git-tag-only --git-sign-tags Push everything: @@ -74,10 +75,6 @@ Run lintian (or [add it to your pbuilder hooks](http://askubuntu.com/questions/1 lintian --info --display-info --pedantic --color auto \ ../build-area/keyringer_$VERSION*.changes -Create a signed tag in the debian branch: - - git-buildpackage --git-tag-only --git-sign-tags - Notes: * `git-import-orig` takes care of running `pristine-tar commit`, of merging of the tag and orig tarball into the upstream branch, and then it merges the result into the debian branch. With the above configuration, it also runs git-dch to do the bulk of the work in `debian/changelog`. @@ -101,9 +98,7 @@ Setup: Teardown: - rm -rf ~/code/tests/keyringer - rm ~/.keyringer/test - sed -i -e '/^test=/d' ~/.keyringer/config + keyringer test teardown -y Translation ----------- @@ -1,6 +1,6 @@ [[!meta title="Keyringer: encrypted and distributed secret sharing software"]] -Keyringer lets you manage and share secrets using GPG and git with custom +Keyringer lets you manage and share secrets using GnuPG and Git with custom commands to encrypt, decrypt, recrypt, create key pairs, etc. - Project page: [https://keyringer.pw](https://keyringer.pw) @@ -73,6 +73,9 @@ Fill it with your friends key IDs. Now encrypt a secret just for then: In other words, if keyringer finds a recipient file matching a given path, it will use it instead of the global recipients file. +Each recipient list is defined in a file placed at `config/recipients` in your +keyring repository. Take care to add just trustable recipients. + Managing secrets ---------------- @@ -111,17 +114,18 @@ Appending information to a secret Editing a secret -To edit a secret, use - - keyringer <keyring> edit <file> + keyringer <keyring> edit <secret> Use this option with caution as it keeps temporary unencrypted data -into keyringer temp folder and at your editor's temp files. +into a temporary folder. Listing secrets keyringer <keyring> ls [arguments] +Each `<secret>` is stored as a file inside the `keys/` folder of your keyring +directory. + Git wrapper ----------- @@ -155,18 +159,6 @@ Example: keyringer <keyring> preferences add KEYID=0123456789ABCDEF0123456789ABCDE012345678 -Notes ------ - - 1. The `<file>` is any file inside the `keys/` folder of your - keyring directory. - - 2. Never decrypt a key and write it to the disk, except - if you're adding it to your personall keyring. - - 3. Recipients are defined at file `config/recipients`. - Take care to add just trustable recipients. - Concepts -------- @@ -207,6 +199,9 @@ given key), but it's possible to: - Or to consider an integration with gpg's --hidden-recipient option. +Never decrypt a key and write it to the disk, except if you're adding it to +your personall keyring. + Requirements ------------ @@ -3,21 +3,22 @@ # Keyringer key management system. # # Copyright (C) 2010 Silvio Rhatto - rhatto at riseup.net -# +# # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation, either version 3 of the License, # or any later version. -# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # +# Initialize a new keyring function keyringer_init { BASEDIR="$3" URL="$4" @@ -104,6 +105,7 @@ function keyringer_init { fi } +# Action dispatcher function keyringer_dispatch { BASEDIR="`keyringer_config $KEYRING`" @@ -120,7 +122,7 @@ function keyringer_dispatch { # Config NAME="keyringer" -KEYRINGER_VERSION="0.2.9" +KEYRINGER_VERSION="0.3" CONFIG_VERSION="0.1" CONFIG_BASE="$HOME/.$NAME" CONFIG="$CONFIG_BASE/config" @@ -131,10 +133,12 @@ ACTION="$2" # Turn off pathname expansion so expansion can work properly set -f -# Export preferences and version for other scripts +# Export globals for other scripts export PREFERENCES="`dirname $CONFIG`/$KEYRING" export KEYRINGER_VERSION export CONFIG_VERSION +export KEYRING +export CONFIG # Set functions location if [ -e "`dirname $(readlink -f $0)`/lib/$NAME/functions" ]; then @@ -160,12 +164,14 @@ source "$LIB" || exit 1 # Setup main configuration and load preferences keyringer_config_load -if [ -z "$ACTION" ]; then +# Dispatch +if [ -z "$KEYRING" ]; then keyringer_usage exit 1 -fi - -if [ "$ACTION" == "init" ]; then +elif [ -z "$ACTION" ]; then + # Run shell if no action were given + keyringer $KEYRING shell +elif [ "$ACTION" == "init" ]; then keyringer_init $* elif keyringer_has_action "$ACTION"; then keyringer_dispatch $* diff --git a/lib/keyringer/actions/append b/lib/keyringer/actions/append index e307056..fbb6c1c 100755 --- a/lib/keyringer/actions/append +++ b/lib/keyringer/actions/append @@ -17,4 +17,4 @@ fi # Append content to an existing secret ( keyringer_exec decrypt "$BASEDIR" "$FILE" && cat ) | \ - keyringer_exec encrypt-batch $BASEDIR $FILE + keyringer_exec encrypt-batch "$BASEDIR" "$FILE" diff --git a/lib/keyringer/actions/clip b/lib/keyringer/actions/clip new file mode 120000 index 0000000..8b8c16c --- /dev/null +++ b/lib/keyringer/actions/clip @@ -0,0 +1 @@ +xclip
\ No newline at end of file diff --git a/lib/keyringer/actions/commands b/lib/keyringer/actions/commands index 2605666..cb49c02 100755 --- a/lib/keyringer/actions/commands +++ b/lib/keyringer/actions/commands @@ -7,4 +7,5 @@ LIB="`dirname $0`/../functions" source "$LIB" || exit 1 +# Dispatch keyringer_show_actions diff --git a/lib/keyringer/actions/decrypt b/lib/keyringer/actions/decrypt index 2b1401c..b63b74e 100755 --- a/lib/keyringer/actions/decrypt +++ b/lib/keyringer/actions/decrypt @@ -11,7 +11,7 @@ source "$LIB" || exit 1 keyringer_get_file "$2" # Decrypt -$GPG --quiet --use-agent -d "$KEYDIR/$FILE" +$GPG --use-agent -d "$KEYDIR/$FILE" # Exit exit "$?" diff --git a/lib/keyringer/actions/edit b/lib/keyringer/actions/edit index 9a3e488..03ccdab 100755 --- a/lib/keyringer/actions/edit +++ b/lib/keyringer/actions/edit @@ -24,6 +24,7 @@ keyringer_set_tmpfile $BASENAME.$EXTENSION # Decrypt the information to the file $GPG --yes -o "$TMPWORK" --use-agent -d "$KEYDIR/$FILE" +# Action check if [ "$BASENAME" == "edit" ]; then APP="$EDITOR" elif [ "$BASENAME" == "open" ]; then @@ -43,5 +44,18 @@ $APP "$TMPWORK" # Encrypt again $GPG --yes -o "$KEYDIR/$FILE" --use-agent --armor -e -s $(keyringer_recipients "$RECIPIENTS_FILE") "$TMPWORK" +# Check exit status +errcrypt="$?" + # Remove temp file keyringer_unset_tmpfile "$TMPWORK" + +# Check exit status again +errwipe="$?" + +# Error handling must be done after temp file removal +if [ "$errcrypt" != "0" ]; then + exit "$errcrypt" +elif [ "$errwipe" != "0" ]; then + exit $errwipe +fi diff --git a/lib/keyringer/actions/encrypt b/lib/keyringer/actions/encrypt index 0a40bc1..e9bf453 100755 --- a/lib/keyringer/actions/encrypt +++ b/lib/keyringer/actions/encrypt @@ -106,12 +106,13 @@ else keyringer_encrypt $FILE $UNENCRYPTED_FILE fi +# Check exit status err="$?" - if [ "$err" != "0" ]; then exit "$err" fi +# Wipe information if [ "$UNENCRYPTED_FILE" != "-" ]; then echo "Done. PLEASE WIPE the non-encrypted $UNENCRYPTED_FILE." fi @@ -121,4 +122,5 @@ if [ -d "$BASEDIR/.git" ]; then keyringer_exec git "$BASEDIR" add "keys/$FILE" fi +# Done exit "$?" diff --git a/lib/keyringer/actions/find b/lib/keyringer/actions/find new file mode 100755 index 0000000..21afc7a --- /dev/null +++ b/lib/keyringer/actions/find @@ -0,0 +1,19 @@ +#!/bin/bash +# +# Find secrets. +# + +# Load functions +LIB="`dirname $0`/../functions" +source "$LIB" || exit 1 + +# Aditional parameters +CWD="`pwd`" + +# Avoid leading slash +shift +ARGS="`echo "$*" | sed -e "s|^/*||"`" + +# Run find command +cd "$KEYDIR/$RELATIVE_PATH" && find -iname "*$ARGS*" | sed -e 's|^./||g' +cd "$CWD" diff --git a/lib/keyringer/actions/genpair b/lib/keyringer/actions/genpair index f048bc7..6898b0f 100755 --- a/lib/keyringer/actions/genpair +++ b/lib/keyringer/actions/genpair @@ -184,7 +184,7 @@ source "$LIB" || exit 1 # Aditional parameters KEYTYPE="$2" -FILE="$3" +FILE="$RELATIVE_PATH/$3" NODE="$4" OUTFILE="$5" CWD="`pwd`" diff --git a/lib/keyringer/actions/git b/lib/keyringer/actions/git index 3c4f435..108ccea 100755 --- a/lib/keyringer/actions/git +++ b/lib/keyringer/actions/git @@ -12,5 +12,13 @@ CWD="`pwd`" # Run git command shift -mkdir -p "$BASEDIR" && cd "$BASEDIR" && git $* + +# Set working folder +if [ ! -z "$RELATIVE_PATH" ]; then + WORK="$KEYDIR/$RELATIVE_PATH" +else + WORK="$BASEDIR" +fi + +mkdir -p "$WORK" && cd "$WORK" && git $* cd "$CWD" diff --git a/lib/keyringer/actions/help b/lib/keyringer/actions/help new file mode 120000 index 0000000..ae18295 --- /dev/null +++ b/lib/keyringer/actions/help @@ -0,0 +1 @@ +usage
\ No newline at end of file diff --git a/lib/keyringer/actions/ls b/lib/keyringer/actions/ls index bb66263..93f5f75 100755 --- a/lib/keyringer/actions/ls +++ b/lib/keyringer/actions/ls @@ -15,5 +15,5 @@ shift ARGS="`echo "$*" | sed -e "s|^/*||"`" # Run list command -cd "$KEYDIR" && ls $ARGS +cd "$KEYDIR/$RELATIVE_PATH" && ls $ARGS cd "$CWD" diff --git a/lib/keyringer/actions/mkdir b/lib/keyringer/actions/mkdir new file mode 100755 index 0000000..b31eb0b --- /dev/null +++ b/lib/keyringer/actions/mkdir @@ -0,0 +1,19 @@ +#!/bin/bash +# +# Create folders. +# + +# Load functions +LIB="`dirname $0`/../functions" +source "$LIB" || exit 1 + +# Aditional parameters +CWD="`pwd`" + +# Avoid leading slash +shift +ARGS="`echo "$*" | sed -e "s|^/*||"`" + +# Run mkdir command +cd "$KEYDIR/$RELATIVE_PATH" && mkdir -p $ARGS +cd "$CWD" diff --git a/lib/keyringer/actions/mv b/lib/keyringer/actions/mv new file mode 100755 index 0000000..aaf6772 --- /dev/null +++ b/lib/keyringer/actions/mv @@ -0,0 +1,28 @@ +#!/bin/bash +# +# Move secrets. +# + +# Load functions +LIB="`dirname $0`/../functions" +source "$LIB" || exit 1 + +# Avoid leading slash +ORIG="$(keyringer_filename `echo "$2" | sed -e "s|^/*||"`)" +DEST="`echo "$3" | sed -e "s|^/*||"`" + +# Set destination +if [ ! -d "$KEYDIR/$RELATIVE_PATH/$DEST" ]; then + keyringer_get_new_file $DEST +else + FILE="$DEST" +fi + +# Check if secret exists +if ! echo "$ORIG" | grep -q '*' && [ ! -e "$KEYDIR/$RELATIVE_PATH/$ORIG" ]; then + echo "Secret not found: $ORIG" + exit 1 +fi + +# Run move command +keyringer_exec git "$BASEDIR" mv $ORIG $FILE diff --git a/lib/keyringer/actions/options b/lib/keyringer/actions/options index 8508aea..3bf0e43 100755 --- a/lib/keyringer/actions/options +++ b/lib/keyringer/actions/options @@ -17,6 +17,7 @@ if [ ! -e "$OPTIONS" ]; then keyringer_exec git "$BASEDIR" add config/options fi +# Dispatch if [ "$COMMAND" == "ls" ]; then cat "$OPTIONS" elif [ "$COMMAND" == "edit" ]; then diff --git a/lib/keyringer/actions/preferences b/lib/keyringer/actions/preferences index e82848d..f7507a7 100755 --- a/lib/keyringer/actions/preferences +++ b/lib/keyringer/actions/preferences @@ -7,8 +7,10 @@ LIB="`dirname $0`/../functions" source "$LIB" || exit 1 +# Options COMMAND="$2" +# Syntax check if [ -z "$COMMAND" ]; then echo "Usage: keyringer <keyring> preferences <command> [arguments]" echo "Available commands:" @@ -24,6 +26,7 @@ if [ ! -e "$PREFERENCES" ]; then touch "$PREFERENCES" fi +# Dispatch if [ "$COMMAND" == "ls" ]; then cat "$PREFERENCES" elif [ "$COMMAND" == "edit" ]; then diff --git a/lib/keyringer/actions/recipients b/lib/keyringer/actions/recipients index 7093a6b..4149786 100755 --- a/lib/keyringer/actions/recipients +++ b/lib/keyringer/actions/recipients @@ -13,6 +13,7 @@ keyringer_get_command "$2" # Set recipients file keyringer_set_new_recipients "$3" +# Syntax check and dispatcher if [ "$COMMAND" == "ls" ]; then if [ ! -z "$3" ]; then if [ -e "$RECIPIENTS_FILE" ]; then diff --git a/lib/keyringer/actions/recrypt b/lib/keyringer/actions/recrypt index 014fef7..696399b 100755 --- a/lib/keyringer/actions/recrypt +++ b/lib/keyringer/actions/recrypt @@ -7,6 +7,7 @@ LIB="`dirname $0`/../functions" source "$LIB" || exit 1 +# Recrypt a single secret function keyringer_recrypt { # Get file keyringer_get_file "$1" @@ -34,6 +35,7 @@ function keyringer_recrypt { echo "$recrypted" > "$KEYDIR/$FILE" } +# Syntax check and dispatcher if [ ! -z "$2" ]; then keyringer_recrypt $2 else diff --git a/lib/keyringer/actions/rmdir b/lib/keyringer/actions/rmdir new file mode 100755 index 0000000..398cf11 --- /dev/null +++ b/lib/keyringer/actions/rmdir @@ -0,0 +1,19 @@ +#!/bin/bash +# +# Remove folders. +# + +# Load functions +LIB="`dirname $0`/../functions" +source "$LIB" || exit 1 + +# Aditional parameters +CWD="`pwd`" + +# Avoid leading slash +shift +ARGS="`echo "$*" | sed -e "s|^/*||"`" + +# Run rmdir command +cd "$KEYDIR/$RELATIVE_PATH" && rmdir $ARGS +cd "$CWD" diff --git a/lib/keyringer/actions/shell b/lib/keyringer/actions/shell new file mode 100755 index 0000000..ab170b1 --- /dev/null +++ b/lib/keyringer/actions/shell @@ -0,0 +1,57 @@ +#!/bin/bash +# +# Interactive shell. +# + +# Load functions +LIB="`dirname $0`/../functions" +source "$LIB" || exit 1 + +# Basic parameters +SHELLPATH="/" + +# Show usage +keyringer_usage $KEYRING + +# While a "quit" command isn't entered, read STDIN +while read -rep "keyringer:/${KEYRING}${SHELLPATH}> " STDIN; do + if [ "$STDIN" == "quit" ] || [ "$STDIN" == "exit" ] || [ "$STDIN" == "bye" ]; then + break + elif [ "$STDIN" == "shell" ]; then + echo "Why you need nesting?" + elif [[ "$STDIN" == "cd"* ]]; then + + # Update current path + OLDPATH="$SHELLPATH" + SHELLPATH="`echo $STDIN | sed -e 's/^cd//' | cut -d ' ' -f 2`" + + # Fix current path + if [ "$SHELLPATH" == "/" ] || [ "$SHELLPATH" == "" ]; then + SHELLPATH="/" + elif [[ "$SHELLPATH" == ".."* ]]; then + ARGS="$SHELLPATH" + SHELLPATH="$OLDPATH" + for colons in `echo $ARGS | sed -e 's|/| |g'`; do + SHELLPATH="`dirname $SHELLPATH | sed -e 's|^\.||'`" + done + fi + + # Ensure path is absolute + if echo "$SHELLPATH" | grep -v -q -e "^/"; then + SHELLPATH="/$OLDPATH/$SHELLPATH" + fi + + # Removing multiple slashes + SHELLPATH="`echo $SHELLPATH | sed -e 's/\/\+/\//g'`" + + # Check if path exists + if [ ! -d "$KEYDIR/$SHELLPATH" ]; then + echo "No such folder $SHELLPATH" + SHELLPATH="$OLDPATH" + fi + + elif [[ -n "$STDIN" && "$STDIN" != "#"* ]]; then + # If line is not empty or commented, process command + RELATIVE_PATH="$SHELLPATH" keyringer "$KEYRING" $STDIN + fi +done diff --git a/lib/keyringer/actions/teardown b/lib/keyringer/actions/teardown new file mode 100755 index 0000000..64da740 --- /dev/null +++ b/lib/keyringer/actions/teardown @@ -0,0 +1,28 @@ +#!/bin/bash +# +# Remove a keyring. +# + +# Load functions +LIB="`dirname $0`/../functions" +source "$LIB" || exit 1 + +# Options +CONFIRM="$2" + +# Confirmation +if [ -z "$CONFIRM" ] || [ "$CONFIRM" != "-y" ]; then + echo "WARNING: about to remove the LOCAL copy of $KEYRING" + echo "WARNING: This will irrevocably destroy $KEYDIR" + echo "WARNING: the action cannot be undone!" + + read -rep "Are you sure to WIPE keyring $KEYRING (type YES to confirm)? " key + if [ "$key" != "YES" ]; then + exit 1 + fi +fi + +# Teardown +keyringer_shred `dirname $KEYDIR` +keyringer_shred $HOME/.keyringer/$KEYRING +sed -i -e "/^$KEYRING=/d" $HOME/.keyringer/config diff --git a/lib/keyringer/actions/tree b/lib/keyringer/actions/tree index 8e94cb0..8f9d7cd 100755 --- a/lib/keyringer/actions/tree +++ b/lib/keyringer/actions/tree @@ -1,6 +1,6 @@ #!/bin/bash # -# List keys. +# List keys, tree version. # # Thanks http://www.centerkey.com/tree/ @@ -27,5 +27,5 @@ else fi # Run list command -cd "$KEYDIR" && $TREE $ARGS +cd "$KEYDIR/$RELATIVE_PATH" && $TREE $ARGS cd "$CWD" diff --git a/lib/keyringer/actions/usage b/lib/keyringer/actions/usage index f4ac0fa..2ca7639 100755 --- a/lib/keyringer/actions/usage +++ b/lib/keyringer/actions/usage @@ -7,4 +7,5 @@ LIB="`dirname $0`/../functions" source "$LIB" || exit 1 -keyringer_usage +# Dispatch +keyringer_usage $KEYRING diff --git a/lib/keyringer/actions/xclip b/lib/keyringer/actions/xclip new file mode 100755 index 0000000..b28984f --- /dev/null +++ b/lib/keyringer/actions/xclip @@ -0,0 +1,59 @@ +#!/bin/bash +# +# Decrypt secret header to clipboard. +# + +# Copy contents to clipboard. +# Function thanks to Password Store by Jason A. Donenfeld <Jason@zx2c4.com> +# distributed under GPLv2+: http://www.zx2c4.com/projects/password-store/ +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, + # we're going with this for now. + + before="$(xclip -o -selection clipboard | base64)" + echo -n "$1" | xclip -selection clipboard + ( + sleep 45 + now="$(xclip -o -selection clipboard | base64)" + if [[ $now != $(echo -n "$1" | base64) ]]; then + before="$now" + fi + + # It might be nice to programatically check to see if klipper exists, + # as well as checking for other common clipboard managers. But for now, + # this works fine -- if qdbus isn't there or if klipper isn't running, + # this essentially becomes a no-op. + # + # Clipboard managers frequently write their history out in plaintext, + # so we axe it here: + qdbus org.kde.klipper /klipper org.kde.klipper.klipper.clearClipboardHistory &>/dev/null + + echo "$before" | base64 -d | xclip -selection clipboard + ) & disown + echo "Copied $2 to clipboard. Will clear in 45 seconds." +} + +# Load functions +LIB="`dirname $0`/../functions" +source "$LIB" || exit 1 + +# Check for xclip +if ! which xclip; then + echo "fatal: xclip not found" + exit 1 +fi + +# Get file +keyringer_get_file "$2" + +# Decrypt +pass="$($GPG --use-agent -d "$KEYDIR/$FILE" | head -n 1)" + +# Copy to clipboard +if [ ! -z "$pass" ]; then + clip "$pass" "$2" +fi + +# Exit +exit "$?" diff --git a/lib/keyringer/completions/bash/keyringer b/lib/keyringer/completions/bash/keyringer index eeda27f..a640583 100644 --- a/lib/keyringer/completions/bash/keyringer +++ b/lib/keyringer/completions/bash/keyringer @@ -70,10 +70,10 @@ _keyringer() { # Process config source $config/config - keyrings="`ls --color=never $config | sed -e 's/config//' | xargs`" + keyrings="`ls --color=never $config | sed -e '/^config$/d' | xargs`" # Available instances - instances="`echo $keyrings | sed -e 's/ /\\\|/g'`" + instances="`echo $keyrings | sed -e 's/ /$\\\|^/g' -e 's/^/^/' -e 's/$/$/'`" # The current instance instance="${COMP_WORDS[1]}" @@ -94,7 +94,7 @@ _keyringer() { recipients) opts="ls edit" ;; - ls|tree|encrypt|encrypt-batch|decrypt|edit|append|append-batch|del|rm|recrypt|open) + ls|tree|mkdir|encrypt|encrypt-batch|decrypt|edit|append|append-batch|del|rm|recrypt|open|clip|xclip) cur="`echo ${cur} | sed -e "s|^/*||"`" # avoid leading slash opts="$(bash -c "set -f && export KEYRINGER_CHECK_VERSION=false && keyringer $instance ls -p -d ${cur}*" 2> /dev/null)" ;; diff --git a/lib/keyringer/completions/zsh/_keyringer b/lib/keyringer/completions/zsh/_keyringer index 5717b00..1a6d8c6 100644 --- a/lib/keyringer/completions/zsh/_keyringer +++ b/lib/keyringer/completions/zsh/_keyringer @@ -20,9 +20,9 @@ _keyringer() { # Process config source $config/config - local keyrings="`ls --color=never $config | sed -e 's/config//' | xargs`" + local keyrings="`ls --color=never $config | sed -e '/^config$/d' | xargs`" local keyring_path="`eval echo '$'$words[2]`" - local instances="`echo $keyrings | sed -e 's/ /\\\|/g'`" + local instances="`echo $keyrings | sed -e 's/ /$\\\|^/g' -e 's/^/^/' -e 's/$/$/'`" _arguments \ '1: :->keyring' \ @@ -50,7 +50,7 @@ _keyringer() { recipients) compadd "$@" ls edit ;; - ls|tree|encrypt|encrypt-batch|decrypt|edit|append|append-batch|del|rm|recrypt|open) + ls|tree|mkdir|encrypt|encrypt-batch|decrypt|edit|append|append-batch|del|rm|recrypt|open|clip|xclip) words[4]="`echo $words[4] | sed -e "s|^/*||"`" # avoid leading slash compadd "$@" $(KEYRINGER_CHECK_VERSION=false keyringer $words[2] ls -p -d $words[4]'*' 2> /dev/null) ;; diff --git a/lib/keyringer/functions b/lib/keyringer/functions index bef00d9..014c2c9 100755 --- a/lib/keyringer/functions +++ b/lib/keyringer/functions @@ -206,10 +206,17 @@ function keyringer_shred { echo "$message $path using $tool..." if [ -d "$path" ]; then - find $path -exec $tool -f {} \; - rmdir $path + if [ "$tool" == "wipe" ] || [ "$tool" == "rm" ]; then + $tool -rf $path + else + find $path -exec $tool -uf {} \; + fi else - $tool -f "$path" + if [ "$tool" == "wipe" ] || [ "$tool" == "rm" ]; then + $tool -f "$path" + else + $tool -uf "$path" + fi fi } @@ -283,9 +290,9 @@ function keyringer_set_env { fi if [ ! -z "$KEYID" ]; then - GPG="gpg -u $KEYID" + GPG="gpg --quiet -u $KEYID" else - GPG="gpg" + GPG="gpg --quiet" fi # Check keyring config version @@ -398,14 +405,39 @@ function keyringer_upgrade { # Get a file argument function keyringer_get_file { - FILE="$(keyringer_filename "$1")" + FILE="$(keyringer_filename "$RELATIVE_PATH/$1")" if [ -z "$FILE" ]; then keyringer_action_usage exit 1 elif [ ! -f "$KEYDIR/$FILE" ]; then - echo "File not found: $KEYDIR/$FILE" - exit 1 + # Try to find a similar file + count=0 + candidates=(`keyringer_exec find "$BASEDIR" "$1" | grep -e '.asc$'`) + + if [ ! -z "$candidates" ]; then + echo "Could not find exact match \"$1\", please chose one" + echo "of the following secrets:" + echo "" + + for candidate in ${candidates[@]}; do + echo -e "\t[$count] $candidate" + let count++ + done + + echo "" + read -p "Enter option: " option + + if [[ "$option" =~ ^[0-9]+$ ]] && [ ! -z "${candidates[$option]}" ]; then + FILE="$(keyringer_filename "$RELATIVE_PATH/${candidates[$option]}")" + else + echo "Invalid option" + exit 1 + fi + else + echo "File not found: $KEYDIR/$FILE" + exit 1 + fi fi } @@ -427,7 +459,7 @@ function keyringer_get_new_file { fi # Complete file name - FILE="$(keyringer_filename "$FILE")" + FILE="$RELATIVE_PATH/$(keyringer_filename "$FILE")" if [ -z "$*" ]; then keyringer_action_usage @@ -474,9 +506,10 @@ function keyringer_usage { printf "Usage: %s <keyring> <action> [arguments]\n\n" "$BASENAME" printf "Available commands: \n\n" keyringer_show_actions | sed -e 's/^/\t/' - printf "\tinit <path> [remote]\n\n" $BASENAME - if [ ! -z "$keyrings" ]; then + # Display only when not in a keyring context + if [ ! -z "$keyrings" ] && [ -z "$1" ]; then + printf "\tinit <path> [remote]\n\n" $BASENAME printf "Available keyrings: %s \n" "$keyrings" fi } @@ -533,6 +566,31 @@ EOF echo "Please check for this key or fix the recipient file." exit 1 fi + + # Current date + seconds="`date +%s`" + + # Check the main key + expiry="`gpg --with-colons --fixed-list-mode --list-keys "$recipient" | grep ^pub | cut -d : -f 7`" + + # Check if key is expired + if [ ! -z "$expiry" ] && [[ "$seconds" -gt "$expiry" ]]; then + echo "Fatal: primary key for $recipient expired on `date --date="@$expiry"`" + exit 1 + else + # Check the subkeys + for expiry in `gpg --with-colons --fixed-list-mode --list-keys "$recipient" | grep ^sub | cut -d : -f 7`; do + if [[ "$seconds" -lt "$expiry" ]]; then + not_expired="1" + fi + + if [ "$not_expired" != "1" ]; then + echo "Fatal: key $recipient has no keys suitable for encryption: all subkeys expired." + exit 1 + fi + done + fi + fi done } @@ -546,7 +604,7 @@ function keyringer_set_recipients { candidate_no_extension="`echo $1 | sed -e 's/.asc$//'`" # Find the first matching recipient - while [ ! -z "$candidate" ] && [ "$candidate" != "." ] && [ "$candidate" != "/" ]; do + while [ ! -z "$candidate" ] && [ "$candidate" != "." ] && [ "$candidate" != "/" ] && [ "$candidate" != "/." ]; do if [ -e "$RECIPIENTS/$candidate" ]; then RECIPIENTS_FILE="$RECIPIENTS/$candidate" RECIPIENTS_FILE_BASE="$RECIPIENTS_BASE/$candidate" diff --git a/share/man/keyringer.1 b/share/man/keyringer.1 index c0fed1c..8402b9c 100644 --- a/share/man/keyringer.1 +++ b/share/man/keyringer.1 @@ -31,6 +31,11 @@ and other read/write operations on secrets. Configuration actions, handling repository metadata. .SH REPOSITORY LOOKUP AND MANIPULATION ACTIONS .TP +.B find <\f[I]expression\f[]> +Find secrets in the repository. +.RS +.RE +.TP .B init <\f[I]path\f[]> [\f[I]remote\f[]] Initialize a new keyringer repository. If a \f[I]remote\f[] URL is specified, keyringer will clone an existing @@ -60,6 +65,16 @@ command. .RS .RE .TP +.B mkdir <\f[I]path\f[]> +Create a directory inside the repository \f[I]keys\f[] folder. +.RS +.RE +.TP +.B :rmdir <\f[I]path\f[]> +Remove an empty folder inside the repository \f[I]keys\f[] folder. +.RS +.RE +.TP .B tree <\f[I]path\f[]> List contents from the toplevel repository \f[I]keys\f[] folder or from relative paths if \f[I]path\f[] is specified using a tree-like format. @@ -67,6 +82,25 @@ Like the ls wrapper, this is a wrapper around the \f[I]TREE(1)\f[] command. .RS .RE +.TP +.B shell +Run keyringer on interactive mode from a built-in command-line prompt +where all other actions can be called and are operated from the current +selected keyring. +.RS +.PP +An additional "cd" internal command is available for directory +navigation. +.PP +All <\f[I]secret\f[]> parameters from actions invoked from the shell are +called relatively from the current selected directory. +.RE +.TP +.B teardown +Remove permanently a local copy of a repository, very dangerous if you +have just a single copy. +.RS +.RE .SH SECRET MANIPULATION ACTIONS .PP All secret manipulation actions operate upon a \f[I]secret\f[] which is @@ -115,6 +149,11 @@ Alias for \f[I]del\f[] action. .RS .RE .TP +.B mv <\f[I]secret\f[]> <\f[I]dest\f[]> +Rename a secret. +.RS +.RE +.TP .B edit <\f[I]secret\f[]> Edit a secret by temporarily decrypting it, opening the decrypted copy into the text editor defined by the \f[I]$EDITOR\f[] environment @@ -162,6 +201,17 @@ If no \f[I]secret\f[] is given, all secrets in the repository are re-encrypted. .RS .RE +.TP +.B clip <\f[I]secret\f[]> +Copy the first line of a secret to the clipboard, following +password-store convention. +.RS +.RE +.TP +.B xclip <\f[I]secret\f[]> +Alis to clip action. +.RS +.RE .SH CONFIGURATION ACTIONS .TP .B commands @@ -200,6 +250,11 @@ Show keyringer usage information. .RS .RE .TP +.B help +Alias for usage action. +.RS +.RE +.TP .B recipients <\f[I]ls\f[]|\f[I]edit\f[]> <\f[I]recipients-file\f[]> List, create or edit recipients configuration. .RS diff --git a/share/man/keyringer.1.mdwn b/share/man/keyringer.1.mdwn index d4b71e3..e8df829 100644 --- a/share/man/keyringer.1.mdwn +++ b/share/man/keyringer.1.mdwn @@ -37,6 +37,9 @@ Keyringer has three types of actions: # REPOSITORY LOOKUP AND MANIPULATION ACTIONS +find <*expression*> +: Find secrets in the repository. + init <*path*> [*remote*] : Initialize a new keyringer repository. If a *remote* URL is specified, keyringer will clone an existing repository. @@ -56,11 +59,31 @@ ls <*path*> if *path* is specified. Like the git wrapper, this is a wrapper around the *LS(1)* command. +mkdir <*path*> +: Create a directory inside the repository *keys* folder. + +:rmdir <*path*> +: Remove an empty folder inside the repository *keys* folder. + tree <*path*> : List contents from the toplevel repository *keys* folder or from relative paths if *path* is specified using a tree-like format. Like the ls wrapper, this is a wrapper around the *TREE(1)* command. +shell +: Run keyringer on interactive mode from a built-in command-line prompt where + all other actions can be called and are operated from the current selected + keyring. + + An additional "cd" internal command is available for directory navigation. + + All <*secret*> parameters from actions invoked from the shell are called + relatively from the current selected directory. + +teardown +: Remove permanently a local copy of a repository, very dangerous if you + have just a single copy. + # SECRET MANIPULATION ACTIONS All secret manipulation actions operate upon a *secret* which is the pathname @@ -96,6 +119,9 @@ del <*secret*> rm <*secret*> : Alias for *del* action. +mv <*secret*> <*dest*> +: Rename a secret. + edit <*secret*> : Edit a secret by temporarily decrypting it, opening the decrypted copy into the text editor defined by the *$EDITOR* environment variable and then re-encrypting it. @@ -124,6 +150,12 @@ recrypt <*secret*> into the recipient configuration. If no *secret* is given, all secrets in the repository are re-encrypted. +clip <*secret*> +: Copy the first line of a secret to the clipboard, following password-store convention. + +xclip <*secret*> +: Alis to clip action. + # CONFIGURATION ACTIONS commands @@ -151,6 +183,9 @@ preferences <*ls*|*edit*|*add*> usage : Show keyringer usage information. +help +: Alias for usage action. + recipients <*ls*|*edit*> <*recipients-file*> : List, create or edit recipients configuration. |