mirror of https://github.com/sobolevn/git-secret
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.
217 lines
5.2 KiB
Bash
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."
|
|
}
|