From: Steven Baltakatei Sandoval Date: Tue, 1 Oct 2024 16:40:00 +0000 (+0000) Subject: feat(user/bkotslu):v0.0.1: Add OTS lookup script X-Git-Url: https://zdv2.bktei.com/gitweb/BK-2020-03.git/commitdiff_plain/aa8be4bf5eaeac58707062fe0a5b506eea9cf3e6?ds=inline;hp=4a48bb01475653a635ca8db7941b0652cc0fb5a1 feat(user/bkotslu):v0.0.1: Add OTS lookup script - Note: Status: only archives OTS files from provided input dirs at the moment. --- diff --git a/user/bkotslu b/user/bkotslu new file mode 100755 index 0000000..f2e1220 --- /dev/null +++ b/user/bkotslu @@ -0,0 +1,264 @@ +#!/bin/bash +# Desc: Utility for backing up and retrieving ots files +# Version: 0.0.1 + +OTS_FCACHE_DIR="$HOME/.cache/bkotslu/"; +MAX_FIND_DEPTH=12; + +yell() { echo "$0: $*" >&2; } # print script path and all args to stderr +die() { yell "$*"; exit 111; } # same as yell() but non-zero exit status +must() { "$@" || 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: + bkotslu [ options ] [FILE...] + + OPTIONS: + -h, --help + Display help information. + --version + Display script version. + -v, --verbose + Display debugging info. + -i, --input-file + Define input file path for file to add ots file to. + -O, --output-dir + Define output directory path for storing ots backup files. + DEFAULT: $HOME/.cache/bkotslu/ + -- + Indicate end of options. + + EXAMPLE: + Hash foo.txt and lookup matching ots file + bkotslu -i foo.txt + + Archive ots files from home directory + bkotslu -I $HOME/ + +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' +bkotslu 0.0.1 +Copyright (C) 2024 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. + + GNU Coreutils 8.32 + Copyright (C) 2020 Free Software Foundation, Inc. + License GPLv3+: GNU GPL version 3 or later . + 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. +processArgs() { + # Desc: Processes arguments provided to script. + # Usage: processArgs "$@" + # Version: 1.0.0 + # 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. + # pathDirIn1 Path to input directory. + # pathFileIn1 Path to input file. + # arrayPosArgs 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. + # arrayPosArgs 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 + if [ $# -le 0 ]; then yell "FATAL:No arguments provided."; showUsage; fi; + 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]. + -i | --input-file) # Define input file path + if [ -f "$2" ]; then # If $2 is file that exists, set pathFileIn1 to $2, pop $2. + pathFileIn1="$2"; + vbm "DEBUG:Input file pathFileIn1 set to:${pathFileIn1}"; + shift; + else + die "FATAL: Specified input file does not exist:$2"; + fi;; + -I | --input-dir) # Define input directory path + if [ -d "$2" ]; then # If $2 is dir that exists, set pathDirIn1 to $2, pop $2. + pathDirIn1="$2"; + vbm "DEBUG:Input directory pathDirIn1 set to:${pathDirIn1}"; + shift; + else # Display error if $2 is not a valid dir. + die "FATAL:Specified input directory does not exist:$2"; + fi;; + -O | --output-dir) # Define output directory path + if [ -d "$2" ]; then # If $2 is dir that exists, set pathDirOut1 to $2, pop $2 + pathDirOut1="$2"; + vbm "DEBUG:Output directory pathDirOut1 set to:${pathDirOut1}"; + shift; + else + die "FATAL:Specified output directory is not valid:$2"; + fi;; + --) # End of all options. See [2]. + shift; + for arg in "$@"; do + vbm "DEBUG:adding to arrayPosArgs:$arg"; + arrayPosArgs+=("$arg"); + done; + break;; + -*) showUsage; die "FATAL: Unrecognized option.";; # Display usage + *) showUsage; die "FATAL: Unrecognized argument.";; # Handle unrecognized options. See [1]. + esac; + shift; + done; + + ## Identify ots file cache dir + if [[ -z "$pathDirOut1" ]]; then + vbm "STATUS:No output directory for caching OTS files specified."; + pathDirOut1="$OTS_FCACHE_DIR"; + vbm "STATUS:Assuming OTS files to be cached in:${pathDirOut1}"; + fi; + ## Create cache dir if necessary + if [[ ! -d "$pathDirOut1" ]]; then + vbm "STATUS:Creating OTS file cache directory:${pathDirOut1}"; + must mkdir -p "$pathDirOut1"; + fi; + + # End function + vbm "DEBUG:processArgs function ended."; + return 0; # Function finished. +}; # Evaluate script options from positional arguments (ex: $1, $2, $3, etc.). +get_ots_filehash() { + # Desc: Gets hash of an opentimestamp'd file from ots file + # Usage: get_ots_filehash FILE + # Example: get_ots_filehash foo.txt.ots + # Depends: ots 0.7.0, GNU grep 3.7, GNU Coreutils 8.32 + # vbm() verbose output + # BK-2020-03 yell() + # Input: arg1 OTS file path + # Output: stdout sha256 file hash (lowercase) + local output; + + vbm "DEBUG:Starting get_ots_filehash() on:$1"; + if output="$( "$(which ots)" info "$1" | \ + grep -E "^File sha256 hash: " | \ + head -n1 | \ + sed -E -e 's/(^File sha256 hash: )([0-9a-f]+$)/\2/g'; )" && \ + [[ -n "$output" ]]; then + vbm "STATUS:Read file hash via ots from:$1"; + printf "%s" "$output"; + return 0; + else + yell "ERROR:Encountered problem getting file hash via ots from:$1"; + return 1; + fi; +}; # Gets hash of file from ots file +get_ots_oldestblock() { + # Desc: Gets earliest Bitcoin block number from ots file + # Usage: get_ots_oldestblock FILE + # Example: get_ots_oldestblock foo.txt.ots + # Input: arg1 path OTS file path + # Output: stdout int Bitcoin block number + # Depends: OpenTimestamps 0.7.0, GNU grep 3.7, GNU Coreutils 8.32 + # vbm() + # BK-2020-03: yell() + local output; + + vbm "DEBUG:Starting get_ots_oldestblock() on:$1"; + if output="$( "$(which ots)" info "$1" | \ + grep -E "verify BitcoinBlockHeaderAttestation\([0-9]+\)" | \ + sort | head -n1 | \ + sed -E -e 's/(^ verify BitcoinBlockHeaderAttestation)\(([0-9]+)(\))/\2/g'; )" && \ + [[ -n "$output" ]]; then + vbm "STATUS:Retrieved Bitcoin block via ots from:$1"; + printf "%s" "$output"; + return 0; + else + yell "ERROR:Encountered problem getting Bitcoin block number via ots from:$1"; + return 1; + fi; +}; # Gets oldest Bitcoin block from ots file +cache_ots_file() { + # Desc: Scans and caches an OTS file for storing + if fhash="$(must get_ots_filehash "$line")" && \ + block="$(must get_ots_oldestblock "$line")"; then + fout="${fhash}_${block}.otsu"; # file name out + pout="${pathDirOut1}/${fout}"; # file path out + vbm "STATUS:Found OTS file at ${line} with hash ${fhash} and block ${block} and saving to ${pout}"; + must cp -n "$line" "$pout"; + else + yell "ERROR:Problem analyzing file with OpenTimestamps:${line}"; + fi; +}; # Scans a single OTS file + +main() { + processArgs "$@"; + + + # Scan provided dir for OTS files to cache. + if [[ -n "$pathDirIn1" ]]; then + while read -r line; do + line="$(readlink -f "$line")"; + cache_ots_file; + done < <(find "$pathDirIn1" -maxdepth "$MAX_FIND_DEPTH" -type f -name "*.ots"); + fi; + + # Lookup OTS file from archive for provided file. + if [[ -n "$pathFileIn1" ]]; then + : + fi; + + + + +}; # main program + +main "$@";