From dce1ad0dc41d3fb5eb754e5e135761910f275968 Mon Sep 17 00:00:00 2001 From: James Murty Date: Sat, 27 Feb 2021 22:02:40 +1100 Subject: [PATCH] Let user set a custom path to openssl #108 Add the optional `--set-openssl-path` argument to tell transcrypt to use an explicit path to the openssl binary, instead of whatever version is found on the user's `$PATH`. The OpenSSL path can be changed on init, during an upgrade, or along with any other transcrypt command (even by itself). The openssl path is saved as a new `transcrypt.openssl-path` Git config local setting in the repository, alongside the other transcrypt settings like cipher, password etc. --- CHANGELOG.md | 7 +++++++ README.md | 3 +++ man/transcrypt.1.ronn | 3 +++ tests/test_init.bats | 42 ++++++++++++++++++++++++++++++++++++++++++ transcrypt | 37 ++++++++++++++++++++++++++----------- 5 files changed, 81 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc45674..8b4d880 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,13 @@ The format is based on [Keep a Changelog][1], and this project adheres to ## [Unreleased] +### Added + +- Add `--set-openssl-path` option to configure transcrypt to use a specific + openssl version instead of the default version found in `$PATH`. This will be + most useful to macOS users who might want to use a newer version of OpenSSL. + This option can be used on init, on upgrade, or by itself. + ### Fixed - Respect Git `core.hooksPath` setting when installing the pre-commit hook. (#104) diff --git a/README.md b/README.md index 6f2623b..0983ae8 100644 --- a/README.md +++ b/README.md @@ -201,6 +201,9 @@ directory. the password to derive the key from; defaults to 30 random base64 characters + --set-openssl-path=PATH_TO_OPENSSL + use OpenSSL at this path; defaults to 'openssl' in $PATH + -y, --yes assume yes and accept defaults for non-specified options diff --git a/man/transcrypt.1.ronn b/man/transcrypt.1.ronn index d9c3df0..ef0d072 100644 --- a/man/transcrypt.1.ronn +++ b/man/transcrypt.1.ronn @@ -25,6 +25,9 @@ The transcrypt source code and full documentation may be downloaded from the password to derive the key from; defaults to 30 random base64 characters + * `--set-openssl-path`=: + use OpenSSL at this path; defaults to 'openssl' in $PATH + * `-y`, `--yes`: assume yes and accept defaults for non-specified options diff --git a/tests/test_init.bats b/tests/test_init.bats index cc1fb60..6c7a953 100755 --- a/tests/test_init.bats +++ b/tests/test_init.bats @@ -97,3 +97,45 @@ SETUP_SKIP_INIT_TRANSCRYPT=1 [[ "${lines[6]}" = " PASSWORD: abc123" ]] [[ "${lines[8]}" = " transcrypt -c aes-256-cbc -p 'abc123'" ]] } + +@test "init: transcrypt.openssl-path config setting defaults to 'openssl'" { + init_transcrypt + [[ "$(git config --get transcrypt.openssl-path)" = 'openssl' ]] +} + +@test "init: --set-openssl-path changes transcrypt.openssl-path" { + init_transcrypt + [[ "$(git config --get transcrypt.openssl-path)" = 'openssl' ]] +} + +@test "init: --set-openssl-path is applied during init" { + init_transcrypt + run ../transcrypt --set-openssl-path=/test/path + [[ "$(git config --get transcrypt.openssl-path)" = "/test/path" ]] +} + +@test "init: --set-openssl-path is applied during upgrade" { + init_transcrypt + [[ "$(git config --get transcrypt.openssl-path)" = 'openssl' ]] + + # Set openssl path + FULL_OPENSSL_PATH=$(which openssl) + + "$BATS_TEST_DIRNAME"/../transcrypt --upgrade --yes --set-openssl-path="$FULL_OPENSSL_PATH" + [[ "$(git config --get transcrypt.openssl-path)" = "$FULL_OPENSSL_PATH" ]] + [[ ! "$(git config --get transcrypt.openssl-path)" = 'openssl' ]] +} + +@test "init: transcrypt.openssl-path config setting is retained with --upgrade" { + init_transcrypt + [[ "$(git config --get transcrypt.openssl-path)" = 'openssl' ]] + + # Set openssl path + FULL_OPENSSL_PATH=$(which openssl) + run ../transcrypt --set-openssl-path="$FULL_OPENSSL_PATH"'' + + # Retain transcrypt.openssl-path config setting on upgrade + "$BATS_TEST_DIRNAME"/../transcrypt --upgrade --yes + [[ "$(git config --get transcrypt.openssl-path)" = "$FULL_OPENSSL_PATH" ]] + [[ ! "$(git config --get transcrypt.openssl-path)" = 'openssl' ]] +} diff --git a/transcrypt b/transcrypt index ecd92f4..2ccd088 100755 --- a/transcrypt +++ b/transcrypt @@ -132,8 +132,9 @@ git_clean() { else cipher=$(git config --get --local transcrypt.cipher) password=$(git config --get --local transcrypt.password) - salt=$(openssl dgst -hmac "${filename}:${password}" -sha256 "$filename" | tr -d '\r\n' | tail -c16) - ENC_PASS=$password openssl enc -"$cipher" -md MD5 -pass env:ENC_PASS -e -a -S "$salt" -in "$tempfile" + openssl_path=$(git config --get --local transcrypt.openssl-path) + salt=$("${openssl_path}" dgst -hmac "${filename}:${password}" -sha256 "$filename" | tr -d '\r\n' | tail -c16) + ENC_PASS=$password "$openssl_path" enc "-${cipher}" -md MD5 -pass env:ENC_PASS -e -a -S "$salt" -in "$tempfile" fi } @@ -142,7 +143,8 @@ git_smudge() { trap 'rm -f "$tempfile"' EXIT cipher=$(git config --get --local transcrypt.cipher) password=$(git config --get --local transcrypt.password) - tee "$tempfile" | ENC_PASS=$password openssl enc -"$cipher" -md MD5 -pass env:ENC_PASS -d -a 2>/dev/null || cat "$tempfile" + openssl_path=$(git config --get --local transcrypt.openssl-path) + tee "$tempfile" | ENC_PASS=$password "$openssl_path" enc "-${cipher}" -md MD5 -pass env:ENC_PASS -d -a 2>/dev/null || cat "$tempfile" } git_textconv() { @@ -153,7 +155,8 @@ git_textconv() { fi cipher=$(git config --get --local transcrypt.cipher) password=$(git config --get --local transcrypt.password) - ENC_PASS=$password openssl enc -"$cipher" -md MD5 -pass env:ENC_PASS -d -a -in "$filename" 2>/dev/null || cat "$filename" + openssl_path=$(git config --get --local transcrypt.openssl-path) + ENC_PASS=$password "$openssl_path" enc "-${cipher}" -md MD5 -pass env:ENC_PASS -d -a -in "$filename" 2>/dev/null || cat "$filename" } # shellcheck disable=SC2005,SC2002,SC2181 @@ -209,7 +212,7 @@ run_safety_checks() { fi # check for dependencies - for cmd in {column,grep,mktemp,openssl,sed,tee}; do + for cmd in {column,grep,mktemp,"${openssl_path}",sed,tee}; do command -v "$cmd" >/dev/null || die 'required command "%s" was not found' "$cmd" done @@ -226,12 +229,12 @@ run_safety_checks() { # unset the cipher variable if it is not supported by openssl validate_cipher() { local list_cipher_commands - if openssl list-cipher-commands &>/dev/null; then + if "${openssl_path}" list-cipher-commands &>/dev/null; then # OpenSSL < v1.1.0 - list_cipher_commands='openssl list-cipher-commands' + list_cipher_commands="${openssl_path} list-cipher-commands" else # OpenSSL >= v1.1.0 - list_cipher_commands='openssl list -cipher-commands' + list_cipher_commands="${openssl_path} list -cipher-commands" fi local supported @@ -284,7 +287,7 @@ get_password() { if [[ $answer =~ $YES_REGEX ]] || [[ ! $answer ]]; then local password_length=30 local random_base64 - random_base64=$(openssl rand -base64 $password_length) + random_base64=$(${openssl_path} rand -base64 $password_length) password=$random_base64 else printf 'Password: ' @@ -493,6 +496,7 @@ save_configuration() { git config transcrypt.version "$VERSION" git config transcrypt.cipher "$cipher" git config transcrypt.password "$password" + git config transcrypt.openssl-path "$openssl_path" # write the filter settings if [[ -d $(git rev-parse --git-common-dir) ]]; then @@ -661,8 +665,8 @@ uninstall_transcrypt() { pre_commit_hook="${GIT_HOOKS}/pre-commit" pre_commit_hook_installed="${GIT_HOOKS}/pre-commit-crypt" if [[ -f "$pre_commit_hook" ]]; then - hook_md5=$(openssl md5 -hex <"$pre_commit_hook") - installed_md5=$(openssl md5 -hex <"$pre_commit_hook_installed") + hook_md5=$("${openssl_path}" md5 -hex <"$pre_commit_hook") + installed_md5=$("${openssl_path}" md5 -hex <"$pre_commit_hook_installed") if [[ "$hook_md5" = "$installed_md5" ]]; then rm "$pre_commit_hook" else @@ -736,6 +740,8 @@ upgrade_transcrypt() { # Keep current cipher and password cipher=$(git config --get --local transcrypt.cipher) password=$(git config --get --local transcrypt.password) + # Keep current openssl-path, or set to default if no existing value + openssl_path=$(git config --get --local transcrypt.openssl-path 2>/dev/null || printf '%s' "$openssl_path") # Keep contents of .gitattributes ORIG_GITATTRIBUTES=$(cat "$GIT_ATTRIBUTES") @@ -887,6 +893,9 @@ help() { the password to derive the key from; defaults to 30 random base64 characters + --set-openssl-path=PATH_TO_OPENSSL + use OpenSSL at this path; defaults to 'openssl' in \$PATH + -y, --yes assume yes and accept defaults for non-specified options @@ -988,6 +997,7 @@ rekey='' show_file='' uninstall='' upgrade='' +openssl_path='openssl' # used to bypass certain safety checks requires_existing_config='' @@ -1031,6 +1041,11 @@ while [[ "${1:-}" != '' ]]; do --password=*) password=${1#*=} ;; + --set-openssl-path=*) + openssl_path=${1#*=} + # Immediately apply config setting + git config transcrypt.openssl-path "$openssl_path" + ;; -y | --yes) interactive='' ;;