Skip to content

Instantly share code, notes, and snippets.

@massenz
Created November 3, 2023 06:54
Show Gist options
  • Save massenz/102d0a3cfe3a51eebd27d5c1c7088a58 to your computer and use it in GitHub Desktop.
Save massenz/102d0a3cfe3a51eebd27d5c1c7088a58 to your computer and use it in GitHub Desktop.
Shell script to archive & encrypt folders
#!/usr/bin/env zsh
#
# Snapshot archive of all contents in the folder defined in a variable
# called $SOURCE, using $TAR_OPTS tar options.
#
# Created MM, 2012-01-21
# Revised MM, 2023-11-03
set -eu
source ${COMMON_UTILS}/utils
BASEDIR=$(abspath $(dirname $0))
function usage {
printf "Usage: %s [-n | -h] DEST SOURCES\n\n" $(basename "$0")
cat << EOF
Snapshot archive of all contents in the SOURCE folder, using \$TAR_OPTS tar options.
If the -n flag is specified, it will abort if the destination file (or its
encrypted version) are already present.
Requires a virtualenv called 'crytto' with this package installed (pip install crytto)
Options:
-n Non-interactive mode. Abort if the destination file already exists.
-h Prints this help and exits
Arguments:
SOURCES Required. The source folders to archive and encrypt.
DEST Required. Destination path for the encrypted archive: omit any
file extension, .tar.gz.enc will be automatically appended
EOF
}
function check_mount {
local tag="$1"
if [[ ! -e "$tag" ]]; then
msg "Attempting to mount destination folder ${DEST}"
mount $DEST
if [[ ! -e "$tag" ]]; then
fatal "No tag file [${tag}] on ${DEST}, aborting"
fi
fi
}
function validate {
local file_extension_regex='^.+\.[^.]+$'
if [[ ! -x $(which filecrypt) ]]; then
fatal "Missing filecrypt executable in virtualenv ${VENV}"
fi
if [[ -z ${SOURCES} ]]; then
fatal "At least one SOURCE folder must be specified"
fi
if [[ ${DEST} =~ ${file_extension_regex} ]]
then
usage
fatal "DEST should have no extension"
fi
if [[ -e ${DEST}.tar.gz.enc ]]; then
if [[ ${ASK} == "n" ]]; then
fatal "Encrypted archive $(basename ${DEST}) already exists, aborting"
fi
read -p "File ${DEST}.tar.gz.enc already exists, overwrite? [y/N] " overwrite
if [[ $overwrite != 'y' ]]; then
fatal "Snapshot canceled"
fi
fi
}
declare ASK="y"
while getopts ":hn" opt; do
case ${opt} in
h)
usage
exit 0
;;
n)
ASK="n"
;;
\?)
echo "Invalid option: -$OPTARG" >&2
usage
exit 1
;;
esac
done
shift $((OPTIND -1))
if [[ ${ASK} == "n" ]]; then
msg "Non-Interactive option given (-n)"
fi
if [[ $# < 2 ]]
then
usage
fatal "Not enough arguments"
fi
declare -r DEST="${1:-}"
shift 1
declare -r SOURCES=$@
declare -r TMP_DIR=$(mktemp -d)
declare -r TAG="$(dirname ${DEST})/tag"
declare -r TARBALL="${TMP_DIR}/$(basename ${DEST}).tar.gz"
declare -r VENV="crytto"
# Activates Virtualenv with the `crytto` module installed
source ${WORKON_HOME}/${VENV}/bin/activate
validate
check_mount $TAG
msg "Archiving files in ${SOURCES}: creating snapshot in ${DEST}"
msg "Creating temporary plaintext tarball in ${TARBALL}"
if [[ ! -f ${TARBALL} ]]
then
# We deactivate exit-on-error, as tar will throw some errors
# which are safe to ignore.
set +e
# We use J (xz compression) instead of z (gzip), as apparently
# it should provide better compression.
sudo tar caJf "${TARBALL}" ${TAR_OPTS} ${SOURCES}
set -e
else
msg "${TARBALL} exists, skipping archive"
fi
if [[ ! -f "${TARBALL}" ]]
then
fatal "Failed to create snapshot"
fi
sudo chown ${USER}:users "${TARBALL}"
msg "Encrypting ${TARBALL} to ${TARBALL}.enc"
filecrypt -o ${TARBALL}.enc ${TARBALL}
msg "Moving ${TARBALL}.enc to ${DEST}"
mv "${TARBALL}.enc" "${DEST}.tar.gz.enc"
success "Created snapshot archive $(ls ${DEST}*)"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment