style(user/bksum):Rename bksumsign.sh to bksum
[BK-2020-03.git] / user / bksumsign.sh
diff --git a/user/bksumsign.sh b/user/bksumsign.sh
deleted file mode 100755 (executable)
index de17450..0000000
+++ /dev/null
@@ -1,477 +0,0 @@
-#!/usr/bin/env bash
-# Desc: Create and sign a checksum
-# Input: stdin: file list (newline delimited)
-#        arg(s): file paths (IFS delimited)
-# Output: file containing sha256 hashes and file paths
-# Depends: bash v5.1.16, date (GNU Coreutils 8.32), gpg v2.2.27, ots v0.7.0
-# Version: 0.0.1
-
-declare -Ag appRollCall # Associative array for storing app status
-declare -Ag fileRollCall # Associative array for storing file status
-declare -Ag dirRollCall # Associative array for storing dir status
-declare -ag arrPosArgs; # positional arguments
-declare -ag arrStdin; # standard input lines
-declare -ag arrInFiles; # input files
-
-yell() { echo "$0: $*" >&2; } # print script path and all args to stderr
-die() { yell "$*"; exit 111; } # same as yell() but non-zero exit status
-try() { "$@" || die "cannot $*"; } # runs args as command, reports args if command fails
-vbm() {
-    # Description: Prints verbose message ("vbm") to stderr if opVerbose is set to "true".
-    # Usage: vbm "DEBUG :verbose message here"
-    # Version 0.2.0
-    # Input: arg1: string
-    #        vars: opVerbose
-    # Output: stderr
-    # Depends: bash 5.1.16, GNU-coreutils 8.30 (echo, date)
-
-    if [ "$opVerbose" = "true" ]; then
-       functionTime="$(date --iso-8601=ns)"; # Save current time in nano seconds.
-       echo "[$functionTime]:$0:""$*" 1>&2;  # Display argument text.
-    fi
-
-    # End function
-    return 0; # Function finished.
-} # Displays message if opVerbose true
-showUsage() {
-    # Desc: Display script usage information
-    # Usage: showUsage
-    # Version 0.0.2
-    # Input: none
-    # Output: stdout
-    # Depends: GNU-coreutils 8.30 (cat)
-    cat <<'EOF'
-    USAGE:
-        bksumsign.sh [ options ] [FILE...]
-
-    DESCRIPTION:
-        Creates sha256 checksum of files.
-
-    OPTIONS:
-        -h, --help
-                Display help information.
-        --version
-                Display script version.
-        -v, --verbose
-                Display debugging info.
-        -o, --output-file
-                Define output file path. By default, the file
-                name includes the full ISO-8601 timestamp
-                without separators, e.g.:
-                    20220920T2117+0000..SHA256SUM
-        -s, --sign
-                Sign with GnuPG the checksum file.
-        -t, --timestamp
-                Timestamp with OpenTimestamps the checksum file
-                (and GnuPG signature if -s/--sign specified).
-        --
-                Indicate end of options.
-
-    EXAMPLE:
-      bksumsign.sh file.txt
-      bksumsign.sh file1.txt file2.txt
-      bksumsign.sh -v -- file1.txt file2.txt
-      bksumsign.sh -v -t -- file1.txt file2.txt
-      find . -type f | bksumsign.sh
-      find . -type f | bksumsign.sh -v -s -t -- file.txt
-
-    NOTE:
-        If GNU Coreutils 8.32 `sha256sum` used, checksum file
-        can be verified using:
-        sha256sum --check 20220920T2117+0000..SHA256SUM
-EOF
-} # Display information on how to use this script.
-showVersion() {
-    # Desc: Displays script version and license information.
-    # Usage: showVersion
-    # Version: 0.0.2
-    # Input: scriptVersion   var containing version string
-    # Output: stdout
-    # Depends: vbm(), yell, GNU-coreutils 8.30
-
-    # Initialize function
-    vbm "DEBUG:showVersion function called."
-
-    cat <<'EOF'
-bksumsign 0.0.1
-Copyright (C) 2022 Steven Baltakatei Sandoval
-License GPLv3: GNU GPL version 3
-This is free software; you are free to change and redistribute it.
-There is NO WARRANTY, to the extent permitted by law.
-
-EOF
-    
-    # End function
-    vbm "DEBUG:showVersion function ended."
-    return 0; # Function finished.
-} # Display script version.
-checkapp() {
-    # Desc: If arg is a command, save result in assoc array 'appRollCall'
-    # Usage: checkapp arg1 arg2 arg3 ...
-    # Version: 0.1.1
-    # Input: global assoc. array 'appRollCall'
-    # Output: adds/updates key(value) to global assoc array 'appRollCall'
-    # Depends: bash 5.0.3
-    local returnState    
-
-    #===Process Args===
-    for arg in "$@"; do
-       if command -v "$arg" 1>/dev/null 2>&1; then # Check if arg is a valid command
-           appRollCall[$arg]="true";
-           if ! [ "$returnState" = "false" ]; then returnState="true"; fi;
-       else
-           appRollCall[$arg]="false"; returnState="false";
-       fi;
-    done;
-
-    #===Determine function return code===
-    if [ "$returnState" = "true" ]; then
-       return 0;
-    else
-       return 1;
-    fi;
-} # Check that app exists
-checkfile() {
-    # Desc: If arg is a file path, save result in assoc array 'fileRollCall'
-    # Usage: checkfile arg1 arg2 arg3 ...
-    # Version: 0.1.2
-    # Input: global assoc. array 'fileRollCall'
-    # Output: adds/updates key(value) to global assoc array 'fileRollCall';
-    # Output: returns 0 if app found, 1 otherwise
-    # Depends: bash 5.0.3
-    local returnState
-
-    #===Process Args===
-    for arg in "$@"; do
-       if [ -f "$arg" ]; then
-           fileRollCall["$arg"]="true";
-           if ! [ "$returnState" = "false" ]; then returnState="true"; fi;
-        elif [ -z "$arg" ]; then
-            fileRollCall["(no name)"]="false"; returnState="false";
-       else
-           fileRollCall["$arg"]="false"; returnState="false";
-       fi;
-    done;
-    
-    #===Determine function return code===
-    if [ "$returnState" = "true" ]; then
-       return 0;
-    else
-       return 1;
-    fi;
-} # Check that file exists
-checkdir() {
-    # Desc: If arg is a dir path, save result in assoc array 'dirRollCall'
-    # Usage: checkdir arg1 arg2 arg3 ...
-    # Version 0.1.2
-    # Input: global assoc. array 'dirRollCall'
-    # Output: adds/updates key(value) to global assoc array 'dirRollCall';
-    # Output: returns 0 if all args are dirs; 1 otherwise
-    # Depends: Bash 5.0.3
-    local returnState
-
-    #===Process Args===
-    for arg in "$@"; do
-       if [ -z "$arg" ]; then
-           dirRollCall["(Unspecified Dirname(s))"]="false"; returnState="false";
-       elif [ -d "$arg" ]; then
-           dirRollCall["$arg"]="true";
-           if ! [ "$returnState" = "false" ]; then returnState="true"; fi
-       else
-           dirRollCall["$arg"]="false"; returnState="false";
-       fi
-    done
-    
-    #===Determine function return code===
-    if [ "$returnState" = "true" ]; then
-       return 0;
-    else
-       return 1;
-    fi
-} # Check that dir exists
-displayMissing() {
-    # Desc: Displays missing apps, files, and dirs
-    # Usage: displayMissing
-    # Version 1.0.0
-    # Input: associative arrays: appRollCall, fileRollCall, dirRollCall
-    # Output: stderr: messages indicating missing apps, file, or dirs
-    # Output: returns exit code 0 if nothing missing; 1 otherwise
-    # Depends: bash 5, checkAppFileDir()
-    local missingApps value appMissing missingFiles fileMissing
-    local missingDirs dirMissing
-
-    #==BEGIN Display errors==
-    #===BEGIN Display Missing Apps===
-    missingApps="Missing apps  :";
-    #for key in "${!appRollCall[@]}"; do echo "DEBUG:$key => ${appRollCall[$key]}"; done
-    for key in "${!appRollCall[@]}"; do
-       value="${appRollCall[$key]}";
-       if [ "$value" = "false" ]; then
-           #echo "DEBUG:Missing apps: $key => $value";
-           missingApps="$missingApps""$key ";
-           appMissing="true";
-       fi;
-    done;
-    if [ "$appMissing" = "true" ]; then  # Only indicate if an app is missing.
-       echo "$missingApps" 1>&2;
-    fi;
-    unset value;
-    #===END Display Missing Apps===
-
-    #===BEGIN Display Missing Files===
-    missingFiles="Missing files:";
-    #for key in "${!fileRollCall[@]}"; do echo "DEBUG:$key => ${fileRollCall[$key]}"; done
-    for key in "${!fileRollCall[@]}"; do
-       value="${fileRollCall[$key]}";
-       if [ "$value" = "false" ]; then
-           #echo "DEBUG:Missing files: $key => $value";
-           missingFiles="$missingFiles""$key ";
-           fileMissing="true";
-       fi;
-    done;
-    if [ "$fileMissing" = "true" ]; then  # Only indicate if an app is missing.
-       echo "$missingFiles" 1>&2;
-    fi;
-    unset value;
-    #===END Display Missing Files===
-
-    #===BEGIN Display Missing Directories===
-    missingDirs="Missing dirs:";
-    #for key in "${!dirRollCall[@]}"; do echo "DEBUG:$key => ${dirRollCall[$key]}"; done
-    for key in "${!dirRollCall[@]}"; do
-       value="${dirRollCall[$key]}";
-       if [ "$value" = "false" ]; then
-           #echo "DEBUG:Missing dirs: $key => $value";
-           missingDirs="$missingDirs""$key ";
-           dirMissing="true";
-       fi;
-    done;
-    if [ "$dirMissing" = "true" ]; then  # Only indicate if an dir is missing.
-       echo "$missingDirs" 1>&2;
-    fi;
-    unset value;
-    #===END Display Missing Directories===
-
-    #==END Display errors==
-    #==BEGIN Determine function return code===
-    if [ "$appMissing" == "true" ] || [ "$fileMissing" == "true" ] || [ "$dirMissing" == "true" ]; then
-       return 1;
-    else
-       return 0;
-    fi
-    #==END Determine function return code===
-} # Display missing apps, files, dirs
-processArgs() {
-    # Desc: Processes arguments provided to script
-    # Usage: processArgs "$@"
-    # Version: 1.0.0 (modified)
-    # Input: "$@"          (list of arguments provided to the function)
-    # Output: Sets following variables used by other functions:
-    #   opVerbose            Indicates verbose mode enable status.  (ex: "true", "false")
-    #   pathDirOut1          Path to output directory.
-    #   pathFileOut1         Path to output file.
-    #   opFileOut1_overwrite Indicates whether file pathFileOut1 should be overwritten (ex: "true", "false").
-    #   arrPosArgs         Array of remaining positional argments
-    # Depends:
-    #   yell()           Displays messages to stderr.
-    #   vbm()            Displays messsages to stderr if opVerbose set to "true".
-    #   showUsage()      Displays usage information about parent script.
-    #   showVersion()    Displays version about parent script.
-    #   arrPosArgs     Global array for storing non-option positional arguments (i.e. arguments following the `--` option).
-    # External dependencies: bash (5.1.16), echo
-    # Ref./Attrib.:
-    #  [1]: Marco Aurelio (2014-05-08). "echo that outputs to stderr". https://stackoverflow.com/a/23550347
-    #  [2]: "Handling positional parameters" (2018-05-12). https://wiki.bash-hackers.org/scripting/posparams
-
-    # Initialize function
-    vbm "DEBUG:processArgs function called."
-
-    # Perform work
-    while [ ! $# -eq 0 ]; do   # While number of arguments ($#) is not (!) equal to (-eq) zero (0).
-       #yell "DEBUG:Starting processArgs while loop." # Debug stderr message. See [1].
-        #yell "DEBUG:Provided arguments are:""$*"      # Debug stderr message. See [1].
-       case "$1" in
-           -h | --help) showUsage; exit 1;; # Display usage.
-           --version) showVersion; exit 1;; # Show version
-           -v | --verbose) opVerbose="true"; vbm "DEBUG:Verbose mode enabled.";; # Enable verbose mode. See [1].
-           -o | --output-file) # Define output file path
-               if [ -f "$2" ]; then # If $2 is file that exists, prompt user to continue to overwrite, set pathFileOut1 to $2, pop $2.
-                   yell "Specified output file $2 already exists. Overwrite? (y/n):"
-                   read -r m; case $m in
-                               y | Y | yes) opFileOut1_overwrite="true";;
-                               n | N | no) opFileOut1_overwrite="false";;
-                               *) yell "Invalid selection. Exiting."; exit 1;;
-                           esac
-                   if [ "$opFileOut1_overwrite" == "true" ]; then
-                       pathFileOut1="$2";
-                       shift;
-                       vbm "DEBUG:Output file pathFileOut1 set to:""$2";
-                   else
-                       yell "ERORR:Exiting in order to not overwrite output file:""$pathFileOut1";
-                       exit 1;
-                   fi
-               else
-                   pathFileOut1="$2";
-                   shift;
-                   vbm "DEBUG:Output file pathFileOut1 set to:""$2";
-               fi ;;
-            -s | --sign) # sign with gpg
-                opSign="true"; vbm "DEBUG:Signing mode enabled.";;
-            -t | --timestamp) # timestamp with ots
-                opTimestamp="true"; vbm "DEBUG:Timestamp mode enabled.";;
-            --) # End of all options. See [2].
-                shift;
-                for arg in "$@"; do
-                    vbm "DEBUG:adding to arrPosArgs:$arg";
-                    arrPosArgs+=("$arg");
-                done;
-                break;;
-            -*) showUsage; yell "ERROR: Unrecognized option."; exit 1;; # Display usage
-            *)
-                for arg in "$@"; do
-                    vbm "DEBUG:adding to arrPosArgs:$arg";
-                    arrPosArgs+=("$arg");
-                done;
-                break;;
-       esac;
-       shift;
-    done;
-   
-    # End function
-    vbm "DEBUG:processArgs function ended."
-    return  0; # Function finished.
-} # Evaluate script options from positional arguments (ex: $1, $2, $3, etc.).
-processStdin() {
-    # Desc: Save stdin lines to array
-    # Input:  stdin         standard input
-    #         arrStdin    array for storing stdin lines
-    # Output: arrStdin    array for storing stdin lines
-    # Ref/Attrib: [1] https://unix.stackexchange.com/a/484643 Check if no command line arguments and STDIN is empty
-    
-    if [[ -t 0 ]]; then
-        return 1; # error if file descriptor 0 (stdin) open
-    else
-        while read -r line; do
-            arrStdin+=("$line"); done;
-        return 0;
-    fi; 
-}; # Save stdin to array
-checkInput() {
-    # Desc: Check that files (specified by positional arguments and
-    #   standard input lines) exist and are in the same directory.
-    # Input: arrPosArgs[@]    positional arguments
-    #        arrStdin[@]      standard input lines
-    # Output: return code 0     success
-    #         return code 1     failure
-    #         arrInFiles        list of verified files
-    # Depends: displayMissing(), checkfile();
-    local flagMissing flagDirErr workDir;
-
-    # Check that positional arguments are files
-    for elem in "${arrPosArgs[@]}"; do
-        if checkfile "$elem"; then
-            arrInFiles+=("$elem");
-        else
-            flagMissing="true";
-        fi;
-    done;
-
-    # Check that stdin lines are files
-    for elem in "${arrStdin[@]}"; do
-        if checkfile "$elem"; then
-            arrInFiles+=("$elem");
-        else
-            flagMissing="true";
-        fi;
-    done;
-
-    # Check that all files are in the same directory
-    if [[ "$flagMissing" != "true" ]]; then
-        workDir="$( dirname "$( readlink -f "${arrInFiles[0]}" )" )";
-        for elem in "${arrInFiles[@]}"; do
-            elem="$(readlink -f "$elem")"; # full path            
-            if [[ "$(dirname "$elem")" != "$workDir" ]]; then
-                flagDirErr="true";
-            fi;
-        done;
-    fi;
-    
-    # Return non-zero if displayMissing() reports files missing.
-    if [[ "$flagMissing" == "true" ]]; then
-        displayMissing; return 1; fi;
-    if [[ "$flagDirErr" == "true" ]]; then
-        yell "ERROR:All files not in same directory.";
-        return 1; fi;
-    return 0;
-}; # Check positional arguments
-checkDepends() {
-    # Desc: Check if expected commands available
-
-    checkapp date sha256sum;
-    if [[ $opSign == "true" ]]; then checkapp gpg; fi;
-    if [[ $opTimestamp == "true" ]]; then checkapp ots; fi;
-    
-    # Return failure is displayMissing() reports apps missing.
-    if ! displayMissing; then return 1; else return 0; fi;
-}; # Check dependencies
-main() {
-    # Input: pathFileOut1   option-specified output file path
-    #        appRollCall    assoc-array for checkapp(), displayMissing()
-    #        fileRollCall   assoc-array for checkfile(), displayMissing()
-    #        dirRollCall    assoc-array for checkdir(), displayMissing()
-    #        arrPosArgs     array for processArgs()
-    #        arrStdin       array for processStdin()
-    #        arrInFiles     array for checkInput()
-    #        (args)         for processArgs()
-    #        (stdin)        for processStdin()
-    # Output: file    written to $pathSumOut
-    #         file    written to $pathSigOut
-    #       
-    local fileSumOut dirOut pathSumOut pathSigOut;
-    
-    # Check dependencies and input
-    if ! checkDepends; then die "FATAL:Missing apps."; fi;
-    processArgs "$@";
-    processStdin;
-    vbm "DEBUG:$(declare -p arrPosArgs)";
-    vbm "DEBUG:$(declare -p arrStdin)";
-    if ! [[ "${#arrPosArgs[@]}" -ge 1 || "${#arrStdin[@]}" -ge 1 ]]; then
-        yell "ERROR:No positional arguments or stdin lines.";
-        showUsage; exit 1; fi;
-    if ! checkInput; then die "FATAL:Invalid file list."; fi;
-    vbm "DEBUG:$(declare -p arrInFiles)";
-
-    # Do work
-    if [[ -n "$pathFileOut1" ]]; then
-        pathSumOut="$pathFileOut1";
-    else
-        dirOut="$( dirname "${arrInFiles[0]}" )";
-        fileSumOut="$(date +%Y%m%dT%H%M%S%z)..SHA256SUMS";
-        pathSumOut="$dirOut"/"$fileSumOut";
-    fi;
-    pathSigOut="$pathSumOut".asc;
-    for file in "${arrInFiles[@]}"; do
-        sha256sum "$file" >> "$pathSumOut";
-    done;
-
-    # Do optional work
-    ## Sign checksum file.
-    if [[ $opSign == "true" ]]; then
-        try gpg --detach-sign --armor --output "$pathSigOut" "$pathSumOut";
-    fi;
-    ## Timestamp checksum file.
-    if [[ $opTimestamp == "true" ]]; then
-        try ots s "$pathSumOut"; fi;
-
-    ## Timestamp checksum signature file.
-    if [[ $opTimestamp == "true" && $opSign == "true" ]]; then
-        try ots s "$pathSigOut";
-    fi;
-
-    return 0;
-}; # main program
-
-main "$@";
-
-# Author: Steven Baltakatei Sandoval
-# License: GPLv3+