You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
git-secret/src/commands/git_secret_hide.sh

217 lines
5.2 KiB
Bash

#!/usr/bin/env bash
# shellcheck disable=2016
AWK_FSDB_UPDATE_HASH='
BEGIN { FS=":"; OFS=":"; }
{
if ( key == $1 )
{
print key,hash;
}
else
{
print $1,$2;
}
}
'
function _optional_clean {
local clean="$1"
if [[ $clean -eq 1 ]]; then
_find_and_clean_formatted "*$SECRETS_EXTENSION"
fi
}
function _optional_delete {
local delete="$1"
if [[ $delete -eq 1 ]]; then
local path_mappings
path_mappings=$(_get_secrets_dir_paths_mapping)
# We use custom formatting here:
if [[ -n "$_SECRETS_VERBOSE" ]]; then
echo && _message 'removing unencrypted files:'
fi
while read -r line; do
# So the formatting would not be repeated several times here:
local filename
filename=$(_get_record_filename "$line")
_find_and_clean "*$filename"
done < "$path_mappings"
if [[ -n "$_SECRETS_VERBOSE" ]]; then
echo
fi
fi
}
function _get_checksum_local {
local checksum="$SECRETS_CHECKSUM_COMMAND"
echo "$checksum"
}
function _get_file_hash {
local input_path="$1" # Required
local checksum_local
local file_hash
checksum_local="$(_get_checksum_local)"
file_hash=$($checksum_local "$input_path" | gawk '{print $1}')
echo "$file_hash"
}
function _fsdb_update_hash {
local key="$1"
local hash="$2"
local fsdb # path_mappings
fsdb=$(_get_secrets_dir_paths_mapping)
_gawk_inplace -v key="'$key'" -v hash="$hash" "'$AWK_FSDB_UPDATE_HASH'" "$fsdb"
}
function hide {
local clean=0
local preserve=0
local delete=0
local update_only_modified=0
local force_continue=0
OPTIND=1
while getopts 'cFPdmvh' opt; do
case "$opt" in
c) clean=1;;
F) force_continue=1;;
P) preserve=1;;
d) delete=1;;
m) update_only_modified=1;;
v) _SECRETS_VERBOSE=1;;
h) _show_manual_for 'hide';;
*) _invalid_option_for 'hide';;
esac
done
shift $((OPTIND-1))
[ "$1" = '--' ] && shift
if [ $# -ne 0 ]; then
_abort "hide does not understand params: $*"
fi
# We need user to continue:
_user_required
# If -c option was provided, it would clean the hidden files
# before creating new ones.
_optional_clean "$clean"
# Encrypting files:
local path_mappings
path_mappings=$(_get_secrets_dir_paths_mapping)
local num_mappings
num_mappings=$(gawk 'END{print NR}' "$path_mappings")
# make sure all the unencrypted files needed are present
local to_hide=()
while read -r record; do
to_hide+=("$record") # add record to array
done < "$path_mappings"
local recipients
recipients=$(_get_recipients)
local secrets_dir_keys
secrets_dir_keys=$(_get_secrets_dir_keys)
local counter=0
for record in "${to_hide[@]}"; do
local filename
local fsdb_file_hash
local encrypted_filename
filename=$(_get_record_filename "$record")
fsdb_file_hash=$(_get_record_hash "$record")
encrypted_filename=$(_get_encrypted_filename "$filename")
local input_path
local output_path
input_path=$(_append_root_path "$filename")
output_path=$(_append_root_path "$encrypted_filename")
# Checking that file is valid:
if [[ ! -f "$input_path" ]]; then
# this catches the case where some decrypted files don't exist
_warn_or_abort "file not found: $input_path" "1" "$force_continue"
else
file_hash=$(_get_file_hash "$input_path")
# encrypt file only if required
if [[ "$update_only_modified" -eq 0 ]] || [[ "$fsdb_file_hash" != "$file_hash" ]]; then
local args=( --homedir "$secrets_dir_keys" "--no-permission-warning" --use-agent --yes "--trust-model=always" --encrypt )
# we depend on $recipients being split on whitespace
# shellcheck disable=SC2206
args+=( $recipients -o "$output_path" "$input_path" )
set +e # disable 'set -e' so we can capture exit_code
# see https://github.com/bats-core/bats-core#file-descriptor-3-read-this-if-bats-hangs for info about 3>&-
local gpg_output
gpg_output=$($SECRETS_GPG_COMMAND "${args[@]}" 3>&-) # we leave stderr alone
local exit_code=$?
set -e # re-enable set -e
local error=0
if [[ "$exit_code" -ne 0 ]] || [[ ! -f "$output_path" ]]; then
error=1
fi
if [[ "$error" -ne 0 ]] || [[ -n "$_SECRETS_VERBOSE" ]]; then
if [[ -n "$gpg_output" ]]; then
echo "$gpg_output"
fi
fi
if [[ ! -f "$output_path" ]]; then
# if gpg can't encrypt a file we asked it to, that's an error unless in force_continue mode.
_warn_or_abort "problem encrypting file with gpg: exit code $exit_code: $filename" "$exit_code" "$force_continue"
else
counter=$((counter+1))
if [[ "$preserve" == 1 ]]; then
local perms
perms=$($SECRETS_OCTAL_PERMS_COMMAND "$input_path")
chmod "$perms" "$output_path"
fi
fi
# Update file hash for future use of -m
local key="$filename"
local hash="$file_hash"
_fsdb_update_hash "$key" "$hash"
fi
fi
done
# If -d option was provided, it would delete the source files
# after we have already hidden them.
_optional_delete "$delete"
_message "done. $counter of $num_mappings files are hidden."
}