0

I'm trying to check all files with specific extension on the current folder to see if those lines that contain key=value pairs where the key is username, password or key have the value in the form ENC(...).

If any username, password or key is not paired with an ENC(...) value, I need to detect this and fail with an error.

I currently have written code that searches for ENC(...), but that's all it does -- it isn't also looking for username, password or key.


Current Code

#!/bin/bash
pattern='username password key'
find='ENC('   
FILE=test.properties  #need to search for *.properties on that folder 

if test -f "$FILE"; then
    echo "$FILE exists."
#need to check on the line that has a word in pattern if has the value of $find
# for example on the *.properties on line starting with username if it has the value of $find
    while read -r line
    do
        case $line in 
            *${find}*) 
                echo $line " encrypted" 
                ;;
        esac
    done < $FILE
else 
    echo "$FILE does not exist."    
fi

Test Case

The following, when run, creates a directory where the script should emit output like that given below:

#!/bin/sh
testdir="$(mktemp -d "testdir.XXXXXX")" || exit
cd "$testdir" || exit

cat >a-good.properties <<EOF
# comments do not have any effect, neither do other keys
otherkey=also_ignored
# but other keys _can_ have encrypted values, it just doesn't matter
yet_another_key_but_encrypted=ENC(fffggghhh)

username=ENC(aaabbbccc)
password=ENC(bbbcccddd)
key=ENC(dddeeefff)
EOF

# a log with no key, value or password doesn't matter
cat >b-irrelevant.properties <<EOF
other_key=other_value
EOF

cat >c-bad.properties <<EOF
# this log has unencrypted data, we should fail when it exists
username=someone
password=ThisIsASecretDontTellAnyone
key=ThisIsAnotherSecret
EOF

echo "Test-suite files created in directory $testdir" >&2

Desired Output

a-good.properties exists.
username=ENC(aaabbbccc) is encrypted
password=ENC(bbbcccddd) is encrypted
key=ENC(dddeeefff) is encrypted
b-irrelevant.properties exists.
c-bad.properties exists.
ERROR: username should be encrypted but is not.
ERROR: password should be encrypted but is not.
ERROR: key should be encrypted but is not.

...and the exit status should be an error.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
John Kon
  • 47
  • 1
  • 6
  • for a single file will check if the value exists but not based on pattern – John Kon Mar 23 '22 at 02:08
  • 1
    FYI, `echo $line " encrypted"` is quoting the exact _wrong_ thing. `echo "$line" encrypted` would be better, or `echo "$line encrypted"` would be even better than that. `printf '%s encrypted\n' "$line"` would be even better than both, for the reasons described in [Why is printf better than echo?](https://unix.stackexchange.com/questions/65803/why-is-printf-better-than-echo). – Charles Duffy Mar 23 '22 at 02:09
  • ...right now, if your line contained `ENC( * )`, your `echo` would print a list of files in your current directory in place of the `*`. Consider running your code through http://shellcheck.net/ to catch that class of problem. – Charles Duffy Mar 23 '22 at 02:10
  • As for the question, though -- it says what you're trying to do, it shows your code, but it doesn't show how that code fails. Be sure you're _actually asking a question_. "Why does this code do X instead of Y?" is an example of a question -- that should be [edit]ed into the question itself, not added as a comment. – Charles Duffy Mar 23 '22 at 02:10
  • Also, because of the `exit 1`, you're exiting when you find _any_ line without `ENC(` in it. If inspecting only the first line is what you want to do, why use a `while read` loop built to read multiple lines in the first place? – Charles Duffy Mar 23 '22 at 02:13
  • Keep in mind, you can run `read -r line <"$FILE"` without any `while` if all you want to do is read the very first line. – Charles Duffy Mar 23 '22 at 02:14
  • 1
    (Also, sh, or bash? If you're really targeting bash, you don't need `case` because you can use `[[ $line = *"$find"* ]]`, and you should take out the sh tag; whereas if you're targeting sh, you should take out the bash tag). – Charles Duffy Mar 23 '22 at 02:17
  • You're showing us the output you have (though it would be better as text rather than a screenshot), but please also be explicit in showing an exact sample of the output you _want_. – Charles Duffy Mar 23 '22 at 02:35
  • @CharlesDuffy thats the output that i need ..i need to find the lines that start from a pattern word example if there is a line starting with "password" if it has the value "ENC(" at the moment it only show all the lines that has the value "ENC(" – John Kon Mar 23 '22 at 02:39
  • "for example if there is a line starting with password if it has the value ENC(" -- then _what_? That sentence describes a condition, but doesn't describe the desired response associated with that condition. – Charles Duffy Mar 23 '22 at 02:48
  • One thing that's adding to the confusion here is that you're showing us example _output_, but not showing us the example input that corresponds with that output. – Charles Duffy Mar 23 '22 at 02:50
  • ...if the input file contains exactly `password=ENC(cEjemHosjc/hjA8sad)`, then isn't the output _already_ what you want it to be? – Charles Duffy Mar 23 '22 at 02:50
  • If what you want to match is exactly `password=ENC(*)`, then change `*${find}*)` to `password=ENC(*)` (I don't see any good reason to use `find` variable here) – Charles Duffy Mar 23 '22 at 02:52
  • (btw, I'm out for the evening; any future participation will be about 8 hours out). – Charles Duffy Mar 23 '22 at 02:53
  • @CharlesDuffy thanks for your time. the input file will be all *.properties files inside the scripts folder for example.. and need to check if the values of certain words (from pattern) will have encrypted value ( after the = they have ENC( ) ....otherwise if the "pattern" isnt encrypted that means that the value will not start with ENC( will give exit 1 – John Kon Mar 23 '22 at 06:29
  • Ahh! That's finally a good explanation of what you're trying to achieve; thank you for that. – Charles Duffy Mar 23 '22 at 11:12
  • BTW, in the future, you should look for duplicates for as many parts of the problem as possible, and narrow the question to only ask about specific problems we don't have a duplicate for. For example, we already have a duplicate for [Loop through all the files with a specific extension](https://stackoverflow.com/questions/14505047/loop-through-all-the-files-with-a-specific-extension) for the looping part. – Charles Duffy Mar 23 '22 at 11:48
  • The bigger thing is that example output is only helpful to people _when it's paired with example input_. We shouldn't need to guess what your expected input format is -- I'm going to edit the question a bit further to demonstrate what a question with a [mre] looks like, including adding my own guesses at sample input; please do validate them. – Charles Duffy Mar 23 '22 at 11:51
  • Done. Does this make sense in terms of what it would take to write a better question next time? – Charles Duffy Mar 23 '22 at 12:05
  • @CharlesDuffy your edit was accurate .thanks for you time.. i had check for duplicates but had not find the parts i needed .i will have it in mind for the future – John Kon Mar 23 '22 at 12:18

1 Answers1

2

Switching from glob-style expressions (as used with case) to ERE-syntax regular expressions will make your task easier.

Given the description of the problem you're trying to solve from the comments, implementing this in native bash (as opposed to using tools like grep) might look like:

#!/usr/bin/env bash
case $BASH_VERSION in '') echo "ERROR: must be run with bash" >&2; exit 1;; esac

faults_found=0
encryption_required_re='^[[:space:]]*(username|password|key)=(.*)$'
encryption_present_re='ENC[(][^)]+[)]'

for file in *.properties; do
    if [[ -f $file ]]; then
        echo "$file exists" >&2
    else
        continue # no properties files found so the glob didn't expand
    fi
    while IFS= read -r line; do
        # ignore lines that do not match encryption_required_re
        [[ $line =~ $encryption_required_re ]] || continue
        key=${BASH_REMATCH[1]}; value=${BASH_REMATCH[2]}
        # ignore lines where value matches encryption_present_re
        [[ $value =~ $encryption_present_re ]] && {
          printf '%s\n' "$key=$value encrypted" >&2
          continue
        }
        # flag so the script fails on exit, and print an alert to stderr
        (( ++faults_found ))
        printf '%s\n' "ERROR: $file: $key should be encrypted but is not" >&2
    done <"$file"
done

# exit with status 1 if faults_found is nonzero
exit $(( faults_found ? 1 : 0 ))

See a repl running this code (modified only for ease-of-testing) at https://replit.com/@CharlesDuffy2/NavyThirdVerification#example.bash


Otherwise, a quick-and-dirty approach with grep might look like:

#!/bin/sh
if grep -Ee '^(username|password|key)=' *.properties \
   | grep -Ev '=ENC[(].*[)]'; then
  echo "ERROR: Found unencrypted secrets" >&2
  exit 1
else
  echo "No unencrypted secrets found" >&2
  exit 0
fi

...note that this one writes those unencrypted secrets to your terminal, which may be undesired behavior.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441