Created
July 5, 2026 04:35
-
-
Save felipealfonsog/2762179ac42d090e6535bf9a1e2b6dc9 to your computer and use it in GitHub Desktop.
crypttar - tar + age/gpg, no FUSE
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # | |
| # crypttar v1.1.0 — portable encrypted archives using tar + age/gpg. | |
| # macOS/Linux. No FUSE, no mounts, no APFS/LUKS dependency. | |
| # | |
| # Core flows: | |
| # folder -> tar stream (+ embedded .MANIFEST) -> age/gpg -> encrypted archive | |
| # tarball -> age/gpg -> encrypted archive | |
| # | |
| set -euo pipefail | |
| VERSION="v1.1.0" | |
| SCRIPT_NAME="$(basename "$0")" | |
| umask 077 | |
| # Keep tar/perl/macOS locale warnings out of the flow when the user's locale is unsupported. | |
| # This does not alter the user's shell config; it only affects this process and its children. | |
| export LC_ALL=C | |
| export LANG=C | |
| # ----------------------------------------------------------------------------- | |
| # Utilities | |
| # ----------------------------------------------------------------------------- | |
| die() { | |
| printf 'Error: %s\n' "$1" >&2 | |
| exit 1 | |
| } | |
| have() { | |
| command -v "$1" >/dev/null 2>&1 | |
| } | |
| require_tool() { | |
| case "$1" in | |
| age) | |
| have age || die "age is not installed. macOS: brew install age | Arch: sudo pacman -S age" | |
| ;; | |
| gpg) | |
| have gpg || die "gpg is not installed. macOS: brew install gnupg | Arch: sudo pacman -S gnupg" | |
| ;; | |
| tar) | |
| have tar || die "tar is required but was not found." | |
| ;; | |
| shasum) | |
| have shasum || die "shasum is required but was not found." | |
| ;; | |
| *) | |
| have "$1" || die "$1 is required but was not found." | |
| ;; | |
| esac | |
| } | |
| confirm() { | |
| local prompt="$1" | |
| local ans | |
| while true; do | |
| printf '%s [y/N]: ' "$prompt" >&2 | |
| IFS= read -r ans | |
| case "$ans" in | |
| [yY]|[yY][eE][sS]) return 0 ;; | |
| ""|[nN]|[nN][oO]) return 1 ;; | |
| *) printf 'Please answer y or n.\n' >&2 ;; | |
| esac | |
| done | |
| } | |
| choose_crypto_tool() { | |
| # Prompts go to stderr. Selected value only goes to stdout. | |
| local ans | |
| while true; do | |
| printf 'Encryption tool: 1) age 2) gpg [1]: ' >&2 | |
| IFS= read -r ans | |
| case "${ans:-1}" in | |
| 1|age|AGE) | |
| require_tool age | |
| printf 'age\n' | |
| return 0 | |
| ;; | |
| 2|gpg|GPG) | |
| require_tool gpg | |
| printf 'gpg\n' | |
| return 0 | |
| ;; | |
| *) | |
| printf 'Invalid option. Choose 1/age or 2/gpg.\n' >&2 | |
| ;; | |
| esac | |
| done | |
| } | |
| choose_compression() { | |
| # Prompts go to stderr. Selected value only goes to stdout. | |
| local ans | |
| while true; do | |
| printf 'Compression: 1) none 2) gzip [2]: ' >&2 | |
| IFS= read -r ans | |
| case "${ans:-2}" in | |
| 1|none|NONE|no|NO) | |
| printf 'none\n' | |
| return 0 | |
| ;; | |
| 2|gzip|GZIP|gz|GZ|yes|YES) | |
| printf 'gzip\n' | |
| return 0 | |
| ;; | |
| *) | |
| printf 'Invalid option. Choose 1/none or 2/gzip.\n' >&2 | |
| ;; | |
| esac | |
| done | |
| } | |
| sha256_file() { | |
| local file="$1" | |
| require_tool shasum | |
| shasum -a 256 "$file" > "${file}.sha256" | |
| } | |
| verify_sha256_file() { | |
| local file="$1" | |
| local sumfile="${file}.sha256" | |
| [ -f "$file" ] || die "Not a file: $file" | |
| [ -f "$sumfile" ] || die "Missing checksum file: $sumfile" | |
| require_tool shasum | |
| shasum -a 256 -c "$sumfile" | |
| } | |
| infer_crypto_tool() { | |
| case "$1" in | |
| *.age) printf 'age\n' ;; | |
| *.gpg) printf 'gpg\n' ;; | |
| *) die "Cannot infer encryption tool from extension. Expected .age or .gpg" ;; | |
| esac | |
| } | |
| strip_crypto_ext() { | |
| case "$1" in | |
| *.age) printf '%s\n' "${1%.age}" ;; | |
| *.gpg) printf '%s\n' "${1%.gpg}" ;; | |
| *) printf '%s\n' "$1" ;; | |
| esac | |
| } | |
| infer_tar_mode_from_plain_name() { | |
| case "$1" in | |
| *.tar.gz|*.tgz) printf 'gzip\n' ;; | |
| *.tar) printf 'plain\n' ;; | |
| *) die "After removing .age/.gpg, filename must end in .tar, .tar.gz, or .tgz" ;; | |
| esac | |
| } | |
| is_plain_tarball() { | |
| case "$1" in | |
| *.tar|*.tar.gz|*.tgz) return 0 ;; | |
| *) return 1 ;; | |
| esac | |
| } | |
| file_size_bytes() { | |
| # Cross-platform macOS/BSD + GNU stat. | |
| if stat -f '%z' "$1" >/dev/null 2>&1; then | |
| stat -f '%z' "$1" | |
| else | |
| stat -c '%s' "$1" | |
| fi | |
| } | |
| mtime_epoch() { | |
| if stat -f '%m' "$1" >/dev/null 2>&1; then | |
| stat -f '%m' "$1" | |
| else | |
| stat -c '%Y' "$1" | |
| fi | |
| } | |
| mode_octal() { | |
| if stat -f '%Lp' "$1" >/dev/null 2>&1; then | |
| stat -f '%Lp' "$1" | |
| else | |
| stat -c '%a' "$1" | |
| fi | |
| } | |
| maybe_pv() { | |
| if have pv; then | |
| pv | |
| else | |
| cat | |
| fi | |
| } | |
| # ----------------------------------------------------------------------------- | |
| # Manifest | |
| # ----------------------------------------------------------------------------- | |
| make_folder_manifest() { | |
| # make_folder_manifest <src_dir> <compression> <tool> <outfile> <manifest_file> | |
| local src="$1" | |
| local compression="$2" | |
| local tool="$3" | |
| local outfile="$4" | |
| local manifest="$5" | |
| local abs_src host os uname_s tar_v crypto_v pv_v total_bytes total_entries | |
| abs_src="$(cd "$(dirname "$src")" && pwd -P)/$(basename "$src")" | |
| host="$(hostname 2>/dev/null || printf 'unknown')" | |
| os="$(uname -s 2>/dev/null || printf 'unknown')" | |
| uname_s="$(uname -a 2>/dev/null || printf 'unknown')" | |
| tar_v="$(tar --version 2>/dev/null | head -n 1 || tar --help 2>/dev/null | head -n 1 || printf 'tar version unavailable')" | |
| case "$tool" in | |
| age) crypto_v="$(age --version 2>/dev/null || printf 'age version unavailable')" ;; | |
| gpg) crypto_v="$(gpg --version 2>/dev/null | head -n 1 || printf 'gpg version unavailable')" ;; | |
| *) crypto_v="unknown" ;; | |
| esac | |
| if have pv; then | |
| pv_v="$(pv --version 2>/dev/null | head -n 1 || printf 'pv available')" | |
| else | |
| pv_v="not installed" | |
| fi | |
| total_entries="$(find "$src" | wc -l | tr -d ' ')" | |
| total_bytes="$(du -sk "$src" 2>/dev/null | awk '{print $1 * 1024}' || printf 'unknown')" | |
| { | |
| printf 'crypttar_manifest_version=1\n' | |
| printf 'crypttar_version=%s\n' "$VERSION" | |
| printf 'created_at_utc=%s\n' "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" | |
| printf 'host=%s\n' "$host" | |
| printf 'os=%s\n' "$os" | |
| printf 'uname=%s\n' "$uname_s" | |
| printf 'source_type=directory\n' | |
| printf 'source_basename=%s\n' "$(basename "$src")" | |
| printf 'source_path_at_creation=%s\n' "$abs_src" | |
| printf 'compression=%s\n' "$compression" | |
| printf 'encryption_tool=%s\n' "$tool" | |
| printf 'output_file=%s\n' "$outfile" | |
| printf 'tar_version=%s\n' "$tar_v" | |
| printf 'crypto_version=%s\n' "$crypto_v" | |
| printf 'pv=%s\n' "$pv_v" | |
| printf 'total_entries=%s\n' "$total_entries" | |
| printf 'approx_total_bytes=%s\n' "$total_bytes" | |
| printf '\n' | |
| printf '[inventory]\n' | |
| printf '# type<TAB>mode<TAB>mtime_epoch<TAB>size_bytes<TAB>relative_path\n' | |
| # Use relative paths. Avoid checksumming every file by default; the encrypted archive itself gets SHA256. | |
| ( | |
| cd "$(dirname "$src")" | |
| find "$(basename "$src")" -print | sort | while IFS= read -r p; do | |
| if [ -d "$p" ]; then | |
| printf 'dir\t%s\t%s\t-\t%s\n' "$(mode_octal "$p")" "$(mtime_epoch "$p")" "$p" | |
| elif [ -f "$p" ]; then | |
| printf 'file\t%s\t%s\t%s\t%s\n' "$(mode_octal "$p")" "$(mtime_epoch "$p")" "$(file_size_bytes "$p")" "$p" | |
| elif [ -L "$p" ]; then | |
| printf 'symlink\t%s\t%s\t-\t%s -> %s\n' "$(mode_octal "$p")" "$(mtime_epoch "$p")" "$p" "$(readlink "$p" 2>/dev/null || printf '?')" | |
| else | |
| printf 'other\t%s\t%s\t-\t%s\n' "$(mode_octal "$p" 2>/dev/null || printf '?')" "$(mtime_epoch "$p" 2>/dev/null || printf '?')" "$p" | |
| fi | |
| done | |
| ) | |
| } > "$manifest" | |
| } | |
| # ----------------------------------------------------------------------------- | |
| # Current-directory pickers | |
| # ----------------------------------------------------------------------------- | |
| pick_from_current_dir() { | |
| # pick_from_current_dir dir|tarball|encrypted | |
| # Menu/prompt go to stderr. The selected path only goes to stdout. | |
| local kind="$1" | |
| local title prompt item ans idx | |
| local items=() | |
| case "$kind" in | |
| dir) | |
| title="Directories in current directory" | |
| prompt="Directory to encrypt" | |
| while IFS= read -r item; do | |
| [ -n "$item" ] && items+=("$item") | |
| done < <(find . -maxdepth 1 -type d ! -name . -print | sed 's#^\./##' | sort) | |
| ;; | |
| tarball) | |
| title="Plain tarballs in current directory" | |
| prompt="Tarball to encrypt" | |
| while IFS= read -r item; do | |
| [ -n "$item" ] && items+=("$item") | |
| done < <(find . -maxdepth 1 -type f \( -name '*.tar' -o -name '*.tar.gz' -o -name '*.tgz' \) -print | sed 's#^\./##' | sort) | |
| ;; | |
| encrypted) | |
| title="Encrypted archives in current directory" | |
| prompt="Encrypted archive" | |
| while IFS= read -r item; do | |
| [ -n "$item" ] && items+=("$item") | |
| done < <(find . -maxdepth 1 -type f \( -name '*.tar.age' -o -name '*.tar.gpg' -o -name '*.tar.gz.age' -o -name '*.tar.gz.gpg' -o -name '*.tgz.age' -o -name '*.tgz.gpg' \) -print | sed 's#^\./##' | sort) | |
| ;; | |
| *) die "Internal error: invalid picker kind '$kind'" ;; | |
| esac | |
| printf '\n%s:\n' "$title" >&2 | |
| if [ "${#items[@]}" -gt 0 ]; then | |
| idx=1 | |
| for item in "${items[@]}"; do | |
| printf ' %d) %s\n' "$idx" "$item" >&2 | |
| idx=$((idx + 1)) | |
| done | |
| else | |
| printf ' (none found)\n' >&2 | |
| fi | |
| printf '\n%s — type number or path: ' "$prompt" >&2 | |
| IFS= read -r ans | |
| [ -n "$ans" ] || die "No input provided." | |
| case "$ans" in | |
| *[!0-9]*|'') | |
| printf '%s\n' "$ans" | |
| ;; | |
| *) | |
| [ "$ans" -ge 1 ] 2>/dev/null || die "Invalid selection." | |
| [ "$ans" -le "${#items[@]}" ] || die "Invalid selection." | |
| printf '%s\n' "${items[$((ans - 1))]}" | |
| ;; | |
| esac | |
| } | |
| # ----------------------------------------------------------------------------- | |
| # Encryption | |
| # ----------------------------------------------------------------------------- | |
| encrypt_stdin_to_file() { | |
| local tool="$1" | |
| local outfile="$2" | |
| case "$tool" in | |
| age) | |
| require_tool age | |
| age -p -o "$outfile" | |
| ;; | |
| gpg) | |
| require_tool gpg | |
| gpg --symmetric --cipher-algo AES256 \ | |
| --s2k-mode 3 --s2k-count 65000000 --s2k-digest-algo SHA512 \ | |
| -o "$outfile" | |
| ;; | |
| *) die "Internal error: invalid encryption tool '$tool'" ;; | |
| esac | |
| } | |
| output_or_fail() { | |
| local outfile="$1" | |
| if [ -e "$outfile" ]; then | |
| confirm "Overwrite '$outfile'?" || die "Cancelled." | |
| rm -f -- "$outfile" "${outfile}.sha256" | |
| fi | |
| } | |
| encrypt_folder() { | |
| local src="$1" | |
| [ -d "$src" ] || die "Not a directory: $src" | |
| src="${src%/}" | |
| local base parent compression tar_ext tool crypto_ext outfile tmpdir manifest | |
| base="$(basename "$src")" | |
| parent="$(cd "$(dirname "$src")" && pwd -P)" | |
| require_tool tar | |
| compression="$(choose_compression)" | |
| tool="$(choose_crypto_tool)" | |
| if [ "$compression" = "gzip" ]; then | |
| tar_ext=".tar.gz" | |
| else | |
| tar_ext=".tar" | |
| fi | |
| if [ "$tool" = "age" ]; then | |
| crypto_ext=".age" | |
| else | |
| crypto_ext=".gpg" | |
| fi | |
| outfile="${PWD}/${base}${tar_ext}${crypto_ext}" | |
| output_or_fail "$outfile" | |
| tmpdir="$(mktemp -d "${TMPDIR:-/tmp}/crypttar.XXXXXX")" | |
| CRYPTTAR_TMPDIR="$tmpdir" | |
| trap 'rm -rf -- "$CRYPTTAR_TMPDIR"' EXIT | |
| manifest="${tmpdir}/.MANIFEST" | |
| make_folder_manifest "$src" "$compression" "$tool" "$outfile" "$manifest" | |
| printf '\nEncrypting folder\n' >&2 | |
| printf ' Source: %s\n' "$src" >&2 | |
| printf ' Compression: %s\n' "$compression" >&2 | |
| printf ' Tool: %s\n' "$tool" >&2 | |
| printf ' Manifest: embedded as .MANIFEST\n' >&2 | |
| printf ' Output: %s\n\n' "$outfile" >&2 | |
| if [ "$compression" = "gzip" ]; then | |
| tar -czf - -C "$tmpdir" .MANIFEST -C "$parent" "$base" | maybe_pv | encrypt_stdin_to_file "$tool" "$outfile" | |
| else | |
| tar -cf - -C "$tmpdir" .MANIFEST -C "$parent" "$base" | maybe_pv | encrypt_stdin_to_file "$tool" "$outfile" | |
| fi | |
| rm -rf -- "$tmpdir" | |
| trap - EXIT | |
| sha256_file "$outfile" | |
| printf '\nDone: %s\nSHA256: %s.sha256\n' "$outfile" "$outfile" >&2 | |
| printf 'Verifying SHA256...\n' >&2 | |
| verify_sha256_file "$outfile" >&2 | |
| if confirm "Delete original plaintext directory '$src'?"; then | |
| printf 'Warning: secure deletion is not guaranteed on flash/SSD media.\n' >&2 | |
| confirm "Confirm deletion?" && rm -rf -- "$src" | |
| fi | |
| } | |
| encrypt_tarball() { | |
| local src="$1" | |
| [ -f "$src" ] || die "Not a file: $src" | |
| is_plain_tarball "$src" || die "Expected a plain tarball ending in .tar, .tar.gz, or .tgz" | |
| local tool crypto_ext outfile | |
| tool="$(choose_crypto_tool)" | |
| if [ "$tool" = "age" ]; then | |
| crypto_ext=".age" | |
| else | |
| crypto_ext=".gpg" | |
| fi | |
| outfile="${PWD}/$(basename "$src")${crypto_ext}" | |
| output_or_fail "$outfile" | |
| printf '\nEncrypting existing tarball\n' >&2 | |
| printf ' Source: %s\n' "$src" >&2 | |
| printf ' Tool: %s\n' "$tool" >&2 | |
| printf ' Manifest: not embedded; existing tarball is encrypted as-is\n' >&2 | |
| printf ' Output: %s\n\n' "$outfile" >&2 | |
| case "$tool" in | |
| age) | |
| require_tool age | |
| age -p -o "$outfile" "$src" | |
| ;; | |
| gpg) | |
| require_tool gpg | |
| gpg --symmetric --cipher-algo AES256 \ | |
| --s2k-mode 3 --s2k-count 65000000 --s2k-digest-algo SHA512 \ | |
| -o "$outfile" "$src" | |
| ;; | |
| esac | |
| sha256_file "$outfile" | |
| printf '\nDone: %s\nSHA256: %s.sha256\n' "$outfile" "$outfile" >&2 | |
| printf 'Verifying SHA256...\n' >&2 | |
| verify_sha256_file "$outfile" >&2 | |
| if confirm "Delete original plaintext tarball '$src'?"; then | |
| printf 'Warning: secure deletion is not guaranteed on flash/SSD media.\n' >&2 | |
| confirm "Confirm deletion?" && rm -f -- "$src" | |
| fi | |
| } | |
| # ----------------------------------------------------------------------------- | |
| # Decryption / listing / verification | |
| # ----------------------------------------------------------------------------- | |
| decrypt_to_stdout() { | |
| local tool="$1" | |
| local src="$2" | |
| case "$tool" in | |
| age) | |
| require_tool age | |
| age -d "$src" | |
| ;; | |
| gpg) | |
| require_tool gpg | |
| gpg --decrypt "$src" | |
| ;; | |
| *) die "Internal error: invalid decrypt tool '$tool'" ;; | |
| esac | |
| } | |
| decrypt_archive() { | |
| local src="$1" | |
| [ -f "$src" ] || die "Not a file: $src" | |
| local tool plain_name tar_mode default_dest destdir | |
| tool="$(infer_crypto_tool "$src")" | |
| require_tool tar | |
| plain_name="$(strip_crypto_ext "$src")" | |
| tar_mode="$(infer_tar_mode_from_plain_name "$plain_name")" | |
| default_dest="$(dirname "$src")" | |
| printf 'Extract destination [%s]: ' "$default_dest" >&2 | |
| IFS= read -r destdir | |
| destdir="${destdir:-$default_dest}" | |
| mkdir -p "$destdir" | |
| printf '\nDecrypting and extracting\n' >&2 | |
| printf ' Source: %s\n' "$src" >&2 | |
| printf ' Tool: %s\n' "$tool" >&2 | |
| printf ' Archive: %s\n' "$tar_mode" >&2 | |
| printf ' Destination: %s\n\n' "$destdir" >&2 | |
| if [ "$tar_mode" = "gzip" ]; then | |
| decrypt_to_stdout "$tool" "$src" | tar -xzf - -C "$destdir" | |
| else | |
| decrypt_to_stdout "$tool" "$src" | tar -xf - -C "$destdir" | |
| fi | |
| printf '\nDone. Extracted into: %s\n' "$destdir" >&2 | |
| } | |
| list_archive() { | |
| local src="$1" | |
| [ -f "$src" ] || die "Not a file: $src" | |
| local tool plain_name tar_mode | |
| tool="$(infer_crypto_tool "$src")" | |
| require_tool tar | |
| plain_name="$(strip_crypto_ext "$src")" | |
| tar_mode="$(infer_tar_mode_from_plain_name "$plain_name")" | |
| if [ "$tar_mode" = "gzip" ]; then | |
| decrypt_to_stdout "$tool" "$src" | tar -tzf - | |
| else | |
| decrypt_to_stdout "$tool" "$src" | tar -tf - | |
| fi | |
| } | |
| verify_sha256() { | |
| verify_sha256_file "$1" | |
| } | |
| # ----------------------------------------------------------------------------- | |
| # Help / menu | |
| # ----------------------------------------------------------------------------- | |
| show_help() { | |
| cat <<EOF_HELP | |
| $SCRIPT_NAME $VERSION — portable encrypted archives using tar + age/gpg | |
| USAGE | |
| $SCRIPT_NAME | |
| $SCRIPT_NAME encrypt-folder <directory> | |
| $SCRIPT_NAME encrypt-tarball <file.tar|file.tar.gz|file.tgz> | |
| $SCRIPT_NAME decrypt <file.tar[.gz].age|file.tar[.gz].gpg> | |
| $SCRIPT_NAME list <file.tar[.gz].age|file.tar[.gz].gpg> | |
| $SCRIPT_NAME verify <encrypted-file> | |
| $SCRIPT_NAME version | |
| $SCRIPT_NAME help | |
| INTERACTIVE FLOW | |
| 1) Encrypt folder from current directory | |
| - Choose a directory by number or path. | |
| - Choose compression: none or gzip. | |
| - Choose encryption: age or gpg. | |
| - Output is automatic: folder.tar.age, folder.tar.gz.age, folder.tar.gpg, etc. | |
| - A .MANIFEST file is embedded at archive root. | |
| - A .sha256 file is generated and immediately verified. | |
| 2) Encrypt existing tarball from current directory | |
| - Choose an existing .tar, .tar.gz, or .tgz by number or path. | |
| - Choose encryption: age or gpg. | |
| - The tarball is encrypted as-is; no repacking. | |
| - A .sha256 file is generated and immediately verified. | |
| DESIGN | |
| - No FUSE. | |
| - No mounted encrypted volume. | |
| - No LUKS/APFS dependency. | |
| - Folder encryption streams tar directly into age/gpg. | |
| - No plaintext .tar temporary file is created for folder encryption. | |
| - Existing tarballs are encrypted directly. | |
| - Decryption infers age/gpg and gzip/plain tar from the filename. | |
| - Locale is forced to C inside the script to avoid macOS tar/perl locale warnings. | |
| REQUIREMENTS | |
| macOS: | |
| brew install age gnupg | |
| Arch Linux: | |
| sudo pacman -S age gnupg | |
| Optional progress meter: | |
| brew install pv | |
| sudo pacman -S pv | |
| EOF_HELP | |
| } | |
| show_version() { | |
| printf '%s %s\n' "$SCRIPT_NAME" "$VERSION" | |
| } | |
| interactive_menu() { | |
| local opt path | |
| printf '========================================\n' | |
| printf ' crypttar %s - tar + age/gpg, no FUSE\n' "$VERSION" | |
| printf ' Current directory: %s\n' "$PWD" | |
| printf '========================================\n\n' | |
| printf '1) Encrypt a folder from current directory\n' | |
| printf '2) Encrypt an existing tarball from current directory\n' | |
| printf '3) Decrypt/extract encrypted archive\n' | |
| printf '4) List encrypted archive contents\n' | |
| printf '5) Verify encrypted archive SHA256\n' | |
| printf '6) Help\n' | |
| printf '7) Exit\n\n' | |
| printf 'Choose [1-7]: ' | |
| IFS= read -r opt | |
| case "$opt" in | |
| 1) | |
| path="$(pick_from_current_dir dir)" | |
| encrypt_folder "$path" | |
| ;; | |
| 2) | |
| path="$(pick_from_current_dir tarball)" | |
| encrypt_tarball "$path" | |
| ;; | |
| 3) | |
| path="$(pick_from_current_dir encrypted)" | |
| decrypt_archive "$path" | |
| ;; | |
| 4) | |
| path="$(pick_from_current_dir encrypted)" | |
| list_archive "$path" | |
| ;; | |
| 5) | |
| path="$(pick_from_current_dir encrypted)" | |
| verify_sha256 "$path" | |
| ;; | |
| 6) | |
| show_help | |
| ;; | |
| 7) | |
| printf 'Bye.\n' | |
| ;; | |
| *) | |
| die "Invalid option." | |
| ;; | |
| esac | |
| } | |
| # ----------------------------------------------------------------------------- | |
| # Entry point | |
| # ----------------------------------------------------------------------------- | |
| case "${1:-}" in | |
| encrypt-folder) | |
| [ "$#" -eq 2 ] || die "Usage: $SCRIPT_NAME encrypt-folder <directory>" | |
| encrypt_folder "$2" | |
| ;; | |
| encrypt-tarball) | |
| [ "$#" -eq 2 ] || die "Usage: $SCRIPT_NAME encrypt-tarball <file.tar|file.tar.gz|file.tgz>" | |
| encrypt_tarball "$2" | |
| ;; | |
| decrypt) | |
| [ "$#" -eq 2 ] || die "Usage: $SCRIPT_NAME decrypt <encrypted-archive>" | |
| decrypt_archive "$2" | |
| ;; | |
| list) | |
| [ "$#" -eq 2 ] || die "Usage: $SCRIPT_NAME list <encrypted-archive>" | |
| list_archive "$2" | |
| ;; | |
| verify) | |
| [ "$#" -eq 2 ] || die "Usage: $SCRIPT_NAME verify <encrypted-file>" | |
| verify_sha256 "$2" | |
| ;; | |
| version|--version|-V) | |
| show_version | |
| ;; | |
| help|-h|--help) | |
| show_help | |
| ;; | |
| "") | |
| interactive_menu | |
| ;; | |
| *) | |
| die "Unknown command: $1. Use '$SCRIPT_NAME help'." | |
| ;; | |
| esac |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment