mirror of https://github.com/lukechilds/chest.git
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
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
|
|
|