You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

282 lines
4.9 KiB

#!/bin/bash
set -euo pipefail
# This is needed for gpg to take over the TTY
# https://github.com/keybase/keybase-issues/issues/1712#issuecomment-141226705
export GPG_TTY=$(tty)
# Default options
[[ -z "${CHEST_DIR:-}" ]] && export CHEST_DIR="$HOME/.chest"
[[ -z "${CHEST_CLEAR_PASSWORD_CACHE:-}" ]] && export CHEST_CLEAR_PASSWORD_CACHE="true"
# Create chest folder on first run
mkdir -p "$CHEST_DIR"
# Usage
usage() {
echo "chest 0.4.0"
echo ""
echo "Usage: chest -e [folder|file]"
echo " chest -d [key]"
echo ""
echo " -h Help. Display this message and quit."
echo " -e Encrypt data and send to chest."
echo " -d Decrypt data from chest."
echo " -z Compress (zip) data before sending to chest."
echo " -r Remove original data after sending to chest."
echo " -l List items in chest."
echo " -k [key] Set key to save/retrieve."
echo " -p [password] Set password. (omit to be prompted)"
}
# Invalid options
invalid_options() {
echo "Error invalid option combination"
usage
exit 1
}
# Check GPG
check_gpg() {
command -v gpg >/dev/null 2>&1 || {
echo "Error chest requires gpg to be installed"; exit 1;
}
}
# Encrypt
encrypt() {
# Check GPG
check_gpg
# Check conflicting options
if [ $decrypt = true ] || [ $list = true ]
then
invalid_options
fi
# Input file
in_file=$item
# Output file
if [ $key = false ]
then
out_file=$in_file
else
out_file=$key
fi
out_file="$CHEST_DIR/${out_file}.tar"
if [ $zip = true ]
then
out_file="${out_file}.gz"
fi
out_file="${out_file}.gpg"
# Setup tar args
args=-cv
if [ $zip = true ]
then
args="${args}z"
fi
args="${args}f"
# Scriptable passwords
password_args=""
if [ "$prompt_password" = "false" ]
then
password_args="--batch --passphrase $password"
fi
# Move to chest
echo ""
echo "Moving data to chest"
tar $args - "$in_file" | gpg -c --cipher-algo AES256 $password_args > "$out_file"
# Send error exit code if tar/gpg fail
if [ "${PIPESTATUS[0]}${PIPESTATUS[1]}" != "00" ]
then
echo "Error couldn't move data to chest"
exit 1
fi
# Clear gpg password cache
if [ "$CHEST_CLEAR_PASSWORD_CACHE" = "true" ]
then
gpgconf --reload gpg-agent
fi
# Remove original
if [ $remove = true ]
then
rm -r "$in_file"
fi
}
# Decrypt
decrypt() {
# Check GPG
check_gpg
# Check conflicting options
if [ $encrypt = true ] || [ $zip = true ] || [ $remove = true ] || [ $list = true ] || [ $key != false ]
then
invalid_options
fi
# Key
key=$item
# Get filepath
t=".tar.gpg"
tgz=".tar.gz.gpg"
if [ -e "$CHEST_DIR/$key$t" ]
then
file_path="$CHEST_DIR/$key$t"
else
if [ -e "$CHEST_DIR/$key$tgz" ]
then
file_path="$CHEST_DIR/$key$tgz"
fi
fi
# Setup tar args
args=-xv
if [[ $file_path == *$tgz ]]
then
args="${args}z"
fi
args="${args}f"
# Scriptable passwords
password_args=""
if [ "$prompt_password" = "false" ]
then
password_args="--batch --passphrase $password"
fi
# Retrieve from chest to current dir
gpg -d $password_args "$file_path" | tar $args -
# Clear gpg password cache
if [ "$CHEST_CLEAR_PASSWORD_CACHE" = "true" ]
then
gpgconf --reload gpg-agent
fi
}
# List
list() {
# Check conflicting options
if [ $encrypt = true ] || [ $decrypt = true ] || [ $zip = true ] || [ $remove = true ] || [ $key != false ]
then
invalid_options
fi
# Search
search=$item
# Loop over all files in chest
chest_files="$CHEST_DIR/*"
for file in $chest_files; do
# Remove chest path
file=${file#$chest_files}
# Remove chest extensions
key=false
t=".tar.gpg"
tgz=".tar.gz.gpg"
if [[ $file == *$t ]]
then
key=${file%$t}
elif [[ $file == *$tgz ]]
then
key=${file%$tgz}
fi
# Check we've got a valid key
if [ "$key" != "false" ]
then
# Search keys
if [ "$search" != "" ]
then
if [[ $key == $search ]]
then
echo $key
fi
# Or show them all
else
echo $key
fi
fi
done
}
# Display usage if no args set
if [ -z "${1:-}" ]
then
usage
exit 1
fi
# Set defaults
encrypt=false
decrypt=false
zip=false
remove=false
list=false
key=false
prompt_password=true
# Parse options
optspec="hedzrlk:p:"
while getopts "$optspec" optchar
do
case "${optchar}" in
h)
usage
;;
e)
encrypt=true
;;
d)
decrypt=true
;;
z)
zip=true
;;
r)
remove=true
;;
l)
list=true
;;
k)
key=$OPTARG
;;
p)
prompt_password=false
password=$OPTARG
;;
esac
done
shift $(($OPTIND - 1))
item="${1:-}"
# Encrypt
if [ $encrypt = true ]
then
encrypt
elif [ $decrypt = true ]
then
decrypt
elif [ $list = true ]
then
list
fi