Skip to content

Commit

Permalink
Improve handling of challenging file names when 'core.quotePath=true'
Browse files Browse the repository at this point in the history
As described in issue #78 transcrypt could fail to properly handle:

- file names with non-ASCII characters when Git's configuration
  option 'core.quotePath' is set to 'true' (as it is by default)
- file names containing spaces

This change improves handling of non-ASCII or space characters in
filenames and adds a test to exercise and confirm the fix.

Changes in particular:

- fix handling of space characters in file name in pre-commit hook
- override repository's 'core.quotePath' setting in commands that
  output paths to ensure 'core.quotePath=false' is always applied
  even when 'core.quotePath' is explicitly or implicitly (default)
  set to true.
  • Loading branch information
jmurty committed May 4, 2020
1 parent 9fd84ff commit 5164902
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 13 deletions.
12 changes: 6 additions & 6 deletions tests/_test_helper.bash
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,22 @@ function nuke_git_repo {
function cleanup_all {
nuke_git_repo
rm $BATS_TEST_DIRNAME/.gitattributes
rm $BATS_TEST_DIRNAME/sensitive_file
rm -f $BATS_TEST_DIRNAME/sensitive_file
}

function init_transcrypt {
$BATS_TEST_DIRNAME/../transcrypt --cipher=aes-256-cbc --password=abc123 --yes
}

function encrypt_named_file {
filename=$1
filename="$1"
content=$2
if [ "$content" ]; then
echo "$content" > $filename
echo "$content" > "$filename"
fi
echo "$filename filter=crypt diff=crypt merge=crypt" >> .gitattributes
git add .gitattributes $filename
git commit -m "Encrypt file $filename"
echo "\"$filename\" filter=crypt diff=crypt merge=crypt" >> .gitattributes
git add .gitattributes "$filename"
run git commit -m "Encrypt file \"$filename\""
}

function setup {
Expand Down
43 changes: 43 additions & 0 deletions tests/test_crypt.bats
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,46 @@ function check_repo_is_clean {
[ "${lines[0]}" != "$SECRET_CONTENT" ]
[ "${lines[0]}" = "$SECRET_CONTENT_ENC" ]
}

@test "crypt: handle challenging file names when 'core.quotePath=true'" {
# Set core.quotePath=true which is the Git default prior to encrypting a
# file with non-ASCII characters and spaces in the name, to confirm
# transcrypt can handle the file properly.
# For info about the 'core.quotePath' setting see
# https://git-scm.com/docs/git-config#Documentation/git-config.txt-corequotePath
git config --local --add core.quotePath true

FILENAME="Mig – røve" # Danish
SECRET_CONTENT_ENC="U2FsdGVkX19Fp9SwTyQ+tz1OgHNIN0OJ+6sMgHIqPMzfdZ6rZ2iVquS293WnjJMx"

encrypt_named_file "$FILENAME" "$SECRET_CONTENT"
[[ "${lines[0]}" = *"Encrypt file \"$FILENAME\"" ]]

# Working copy is decrypted
run cat "$FILENAME"
[ "$status" -eq 0 ]
[ "${lines[0]}" = "$SECRET_CONTENT" ]

# Git internal copy is encrypted
run git show HEAD:"$FILENAME" --no-textconv
[ "$status" -eq 0 ]
[ "${lines[0]}" = "$SECRET_CONTENT_ENC" ]

# transcrypt --show-raw shows encrypted content
run ../transcrypt --show-raw "$FILENAME"
[ "$status" -eq 0 ]
[ "${lines[0]}" = "==> $FILENAME <==" ]
[ "${lines[1]}" = "$SECRET_CONTENT_ENC" ]

# git ls-crypt lists encrypted file
run git ls-crypt
[ "$status" -eq 0 ]
[ "${lines[0]}" = "$FILENAME" ]

# transcrypt --list lists encrypted file"
run ../transcrypt --list
[ "$status" -eq 0 ]
[ "${lines[0]}" = "$FILENAME" ]

rm "$FILENAME"
}
2 changes: 1 addition & 1 deletion tests/test_init.bats
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ SETUP_SKIP_INIT_TRANSCRYPT=1
[ `git config --get diff.crypt.binary` = "true" ]
[ `git config --get merge.renormalize` = "true" ]

[[ `git config --get alias.ls-crypt` = "!git ls-files"* ]]
[[ `git config --get alias.ls-crypt` = "!git -c core.quotePath=false ls-files"* ]]
}

@test "init: show details for --display" {
Expand Down
2 changes: 1 addition & 1 deletion tests/test_pre_commit.bats
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ load $BATS_TEST_DIRNAME/_test_helper.bash
run git log --format=oneline
[ "$status" -eq 0 ]
[[ "${lines[0]}" = *"Added more" ]]
[[ "${lines[1]}" = *"Encrypt file sensitive_file" ]]
[[ "${lines[1]}" = *"Encrypt file \"sensitive_file\"" ]]
}

@test "pre-commit: reject commit of encrypted file with unencrypted content" {
Expand Down
12 changes: 7 additions & 5 deletions transcrypt
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,8 @@ save_helper_hooks() {
cat <<-'EOF' >"$pre_commit_hook_installed"
#!/usr/bin/env bash
# Transcrypt pre-commit hook: fail if secret file in staging lacks the magic prefix "Salted" in B64
for secret_file in $(git ls-files | git check-attr --stdin filter | awk 'BEGIN { FS = ":" }; /crypt$/{ print $1 }'); do
IFS=$'\n'
for secret_file in $(git -c core.quotePath=false ls-files | git -c core.quotePath=false check-attr --stdin filter | awk 'BEGIN { FS = ":" }; /crypt$/{ print $1 }'); do
# Get prefix of raw file in Git's index using the :FILENAME revision syntax
firstbytes=$(git show :$secret_file | head -c 8)
# An empty file does not need to be, and is not, encrypted
Expand All @@ -401,6 +402,7 @@ save_helper_hooks() {
exit 1
fi
done
unset IFS
EOF

# Activate hook by copying it to the pre-commit script name, if safe to do so
Expand Down Expand Up @@ -455,7 +457,7 @@ save_configuration() {
git config merge.crypt.name 'Merge transcrypt secret files'

# add a git alias for listing encrypted files
git config alias.ls-crypt "!git ls-files | git check-attr --stdin filter | awk 'BEGIN { FS = \":\" }; /crypt$/{ print \$1 }'"
git config alias.ls-crypt "!git -c core.quotePath=false ls-files | git -c core.quotePath=false check-attr --stdin filter | awk 'BEGIN { FS = \":\" }; /crypt$/{ print \$1 }'"
}

# display the current configuration settings
Expand Down Expand Up @@ -622,7 +624,7 @@ uninstall_transcrypt() {
list_files() {
if [[ $IS_BARE == 'false' ]]; then
cd "$REPO" || die 1 'could not change into the "%s" directory' "$REPO"
git ls-files | git check-attr --stdin filter | awk 'BEGIN { FS = ":" }; /crypt$/{ print $1 }'
git -c core.quotePath=false ls-files | git -c core.quotePath=false check-attr --stdin filter | awk 'BEGIN { FS = ":" }; /crypt$/{ print $1 }'
fi
}

Expand All @@ -631,8 +633,8 @@ show_raw_file() {
if [[ -f $show_file ]]; then
# ensure the file is currently being tracked
local escaped_file=${show_file//\//\\\/}
if git ls-files --others -- "$show_file" | awk "/${escaped_file}/{ exit 1 }"; then
file_paths=$(git ls-tree --name-only --full-name HEAD "$show_file")
if git -c core.quotePath=false ls-files --others -- "$show_file" | awk "/${escaped_file}/{ exit 1 }"; then
file_paths=$(git -c core.quotePath=false ls-tree --name-only --full-name HEAD "$show_file")
else
die 1 'the file "%s" is not currently being tracked by git' "$show_file"
fi
Expand Down

0 comments on commit 5164902

Please sign in to comment.