@ -1,30 +1,28 @@
#!/usr/bin/env bash
# Global variables:
WORKING_DIRECTORY = " $PWD " # shellcheck disable=2034
# Folders:
SECRETS_DIR= ".gitsecret"
SECRETS_DIR_KEYS= " $SECRETS_DIR /keys "
SECRETS_DIR_PATHS= " $SECRETS_DIR /paths "
_SECRETS_DIR = ".gitsecret"
_SECRETS_DIR_KEYS = " ${ _SECRETS_DIR } /keys "
_SECRETS_DIR_PATHS= " ${ _SECRETS_DIR } /paths "
# Files:
SECRETS_DIR_KEYS_MAPPING= " $SECRETS_DIR_KEYS /mapping.cfg " # shellcheck disable=2034
SECRETS_DIR_KEYS_TRUSTDB= " $SECRETS_DIR_KEYS /trustdb.gpg " # shellcheck disable=2034
_SECRETS_DIR_KEYS_MAPPING= " ${ _SECRETS_DIR_KEYS } /mapping.cfg "
_SECRETS_DIR_KEYS_TRUSTDB= " ${ _SECRETS_DIR_KEYS } /trustdb.gpg "
SECRETS_DIR_PATHS_MAPPING= " $SECRETS_DIR_PATHS /mapping.cfg " # shellcheck disable=2034
_ SECRETS_DIR_PATHS_MAPPING= " ${ _SECRETS_DIR_PATHS } /mapping.cfg "
: " ${ SECRETS_EXTENSION : = ".secret" } "
# Commands:
: " ${ SECRETS_GPG_COMMAND : = "gpg" } "
GPGLOCAL = " $SECRETS_GPG_COMMAND --homedir= $SECRETS_DIR_KEYS --no-permission-warning "
# Inner b ash:
# B ash:
function _function_exists {
declare -f -F " $1 " > /dev/null 2>& 1
local function_name = " $1 " # required
declare -f -F " $function_name " > /dev/null 2>& 1
echo $?
}
@ -60,34 +58,46 @@ function _os_based {
# File System:
function _set_config {
# First parameter is the KEY, second is VALUE, third is filename.
# This function creates a line in the config, or alters it.
local key = " $1 " # required
local value = " $2 " # required
local filename = " $3 " # required
# The exit status is 0 (true) if the name was found, 1 (false) if not:
local contains
contains = $( grep -Fq " $1 " " $3 " ; echo " $? " )
contains = $( grep -Fq " $ key" " $filename " ; echo " $? " )
# Append or alter?
if [ [ " $contains " -eq 0 ] ] ; then
_os_based __replace_in_file " $@ "
elif [ [ " $contains " -eq 1 ] ] ; then
echo " $1 = $2 " >> " $3 "
echo " ${ key } = ${ value } " >> " $filename "
fi
}
function _file_has_line {
# First parameter is the KEY, second is the filename.
# First parameter is the key, second is the filename.
local key = " $1 " # required
local filename = " $2 " # required
local contains
contains = $( grep -qw " $1 " " $2 " ; echo $? )
contains = $( grep -qw " $key " " $filename " ; echo $? )
# 0 on contains, 1 for error.
echo " $contains " ;
echo " $contains "
}
function _delete_line {
local escaped_path
escaped_path = $( echo " $1 " | sed -e 's/[\/&]/\\&/g' )
sed -i.bak " / $escaped_path /d " " $2 "
escaped_path = $( echo " $1 " | sed -e 's/[\/&]/\\&/g' ) # required
local line = " $2 " # required
sed -i.bak " / $escaped_path /d " " $line "
}
@ -103,14 +113,17 @@ function _temporary_file {
function _unique_filename {
# First parameter is base-path, second is filename,
# third is optional extension.
local n = 0 result = $2
local n = 0
local base_path = " $1 "
local result = " $2 "
while true; do
if [ [ ! -f " $1 / $result " ] ] ; then
if [ [ ! -f " $ base_path / $result " ] ] ; then
break
fi
n = $(( n + 1 ))
result = " ${ 2 } - ${ n } "
result = " ${ 2 } - ${ n } " # calling to the original "$2"
done
echo " $result "
}
@ -119,7 +132,8 @@ function _unique_filename {
# Manuals:
function _show_manual_for {
local function_name = " $1 "
local function_name = " $1 " # required
man " git-secret- ${ function_name } "
exit 0
}
@ -128,39 +142,132 @@ function _show_manual_for {
# VCS:
function _check_ignore {
git check-ignore --no-index -q " $1 " ;
echo $?
local filename = " $1 " # required
local result
result = " $( git check-ignore --no-index -q " $filename " > /dev/null 2>& 1; echo $? ) "
echo " $result "
}
function _add_ignored_file {
if [ [ ! -f ".gitignore" ] ] ; then
touch ".gitignore"
function _git_normalize_filename {
local filename = " $1 " # required
local result
result = $( git ls-files --full-name -o " $filename " )
echo " $result "
}
function _maybe_create_gitignore {
# This function creates '.gitignore' if it was missing.
local full_path
full_path = $( _append_root_path '.gitignore' )
if [ [ ! -f " $full_path " ] ] ; then
touch " $full_path "
fi
}
echo " $1 " >> ".gitignore"
function _add_ignored_file {
# This function adds a line with the filename into the '.gitgnore' file.
# It also creates '.gitignore' if it's not there
local filename = " $1 " # required
_maybe_create_gitignore
local full_path
full_path = $( _append_root_path '.gitignore' )
echo " $filename " >> " $full_path "
}
function _is_inside_git_tree {
git rev-parse --is-inside-work-tree >/dev/null 2>& 1
echo $?
# Checks if we are working inside the `git` tree.
local result
result = $( git rev-parse --is-inside-work-tree > /dev/null 2>& 1; echo $? )
echo " $result "
}
function _get_git_root_path {
# We need this function to get the location of the `.git` folder,
# since `.gitsecret` must be on the same level.
local result
result = $( git rev-parse --show-toplevel)
echo " $result "
}
# Relative paths:
function _append_root_path {
# This function adds root path to any other path.
local path = " $1 " # required
local root_path
root_path = $( _get_git_root_path)
echo " $root_path / $path "
}
function _get_secrets_dir {
_append_root_path " ${ _SECRETS_DIR } "
}
function _get_secrets_dir_keys {
_append_root_path " ${ _SECRETS_DIR_KEYS } "
}
function _get_secrets_dir_path {
_append_root_path " ${ _SECRETS_DIR_PATHS } "
}
function _get_secrets_dir_keys_mapping {
_append_root_path " ${ _SECRETS_DIR_KEYS_MAPPING } "
}
function _get_secrets_dir_keys_trustdb {
_append_root_path " ${ _SECRETS_DIR_KEYS_TRUSTDB } "
}
function _get_secrets_dir_paths_mapping {
_append_root_path " ${ _SECRETS_DIR_PATHS_MAPPING } "
}
# Logic:
function _get_gpg_local {
# This function is required to return proper `gpg` command.
# This function was created due to this bug:
# https://github.com/sobolevn/git-secret/issues/85
local homedir
homedir = $( _get_secrets_dir_keys)
local gpg_local = " $SECRETS_GPG_COMMAND --homedir= $homedir --no-permission-warning "
echo " $gpg_local "
}
function _abort {
>& 2 echo " $1 abort. "
local message = " $1 " # required
>& 2 echo " $message abort. "
exit 1
}
@ -171,8 +278,11 @@ function _find_and_clean {
# optional:
local verbose = ${ 2 :- "" } # can be empty or should be equal to "v"
local root
root = $( _get_git_root_path)
# shellcheck disable=2086
find . -name " $pattern " -type f -print0 | xargs -0 rm -f$verbose
find " $root " -path " $pattern " -type f -print0 | xargs -0 rm -f$verbose
}
@ -196,11 +306,25 @@ function _find_and_clean_formated {
}
function _list_all_added_files {
local path_mappings
path_mappings = $( _get_secrets_dir_paths_mapping)
if [ [ ! -s " $path_mappings " ] ] ; then
_abort " $path_mappings is missing. "
fi
while read -r line; do
echo " $line "
done < " $path_mappings "
}
function _secrets_dir_exists {
local root_path
root_path = $( _get_git_root_path)
# This function checks if "$_SECRETS_DIR" exists and.
local full_path = " $root_path / $SECRETS_DIR "
local full_path
full_path = $( _get_secrets_dir)
if [ [ ! -d " $full_path " ] ] ; then
_abort " $full_path does not exist. "
@ -208,16 +332,42 @@ function _secrets_dir_exists {
}
function _secrets_dir_is_not_ignored {
# This function checks that "${_SECRETS_DIR}" is not ignored.
local git_secret_dir
git_secret_dir = $( _get_secrets_dir)
local ignores
ignores = $( _check_ignore " ${ _SECRETS_DIR } / " )
if [ [ ! $ignores -eq 1 ] ] ; then
_abort " ' $git_secret_dir /' is ignored. "
fi
}
function _user_required {
# This function does a bunch of validations:
# 1. It calls `_secrets_dir_exists` to verify that "$_SECRETS_DIR" exists.
# 2. It ensures that "$_SECRETS_DIR_KEYS_TRUSTDB" exists.
# 3. It ensures that there are added public keys.
_secrets_dir_exists
local error_message = "no users found. run 'git secret tell' before adding files."
if [ [ ! -f " $SECRETS_DIR_KEYS_TRUSTDB " ] ] ; then
local trustdb
trustdb = $( _get_secrets_dir_keys_trustdb)
local error_message = "no users found. run 'git secret tell'."
if [ [ ! -f " $trustdb " ] ] ; then
_abort " $error_message "
fi
local gpg_local
gpg_local = $( _get_gpg_local)
local keys_exist
keys_exist = $( $GPGLOCAL -n --list-keys)
keys_exist = $( $ gpg_local -n --list-keys)
if [ [ -z " $keys_exist " ] ] ; then
_abort " $error_message "
fi
@ -236,17 +386,35 @@ function _get_encrypted_filename {
}
function _get_users_in_keyring {
function _parse_keyring_users {
# First argument must be a `sed` pattern
local sed_pattern = " $1 "
local result
result = $( $GPGLOCAL --list-public-keys --with-colon | sed -n 's/.*<\(.*\)>.*/\1/p' )
local gpg_local
gpg_local = $( _get_gpg_local)
result = $( $gpg_local --list-public-keys --with-colon | sed -n " $sed_pattern " )
echo " $result "
}
function _get_users_in_keyring {
# This function is required to show the users in the keyring.
# `whoknows` command uses it internally.
# It basically just parses the `gpg` public keys
_parse_keyring_users 's/.*<\(.*\)>.*/\1/p'
}
function _get_recepients {
local result
result = $( $GPGLOCAL --list-public-keys --with-colon | sed -n 's/.*<\(.*\)>.*/-r\1/p' )
echo " $result "
# This function is required to create an encrypted file for different users.
# These users are called 'recepients' in the `gpg` terms.
# It basically just parses the `gpg` public keys
_parse_keyring_users 's/.*<\(.*\)>.*/-r\1/p'
}
@ -278,9 +446,9 @@ function _decrypt {
fi
if [ [ ! -z " $passphrase " ] ] ; then
echo " $passphrase " | $base --batch --yes --no-tty --passphrase-fd 0 \
" $encrypted_filename " > /dev/null 2>& 1
echo " $passphrase " | $base --quiet -- batch --yes --no-tty --passphrase-fd 0 \
" $encrypted_filename "
else
$base " $encrypted_filename " > /dev/null 2>& 1
$base --quiet " $encrypted_filename "
fi
}