diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.* diff --git a/.siglog/manifest.8E47A1EC35A1551D.asc b/.siglog/manifest.8E47A1EC35A1551D.asc new file mode 100644 index 0000000..47c2e32 --- /dev/null +++ b/.siglog/manifest.8E47A1EC35A1551D.asc @@ -0,0 +1,16 @@ +-----BEGIN PGP SIGNATURE----- + +iQIzBAABCgAdFiEEZ1U/vaRrtxq9LgsLjkeh7DWhVR0FAl+t74IACgkQjkeh7DWh +VR3vnxAAoguALAHRSmNVASOmJ29S+F6vfAX7hU6XIst3RNP4l999ClS8e4K+9shu +i+grQCAXxN0rwBf7hmeVN0CJ8tjXRHY9mfoHknq5TcHWt5dwT5ddskN2MzdJKRU5 +o0hGr8BP5cLQTzykvWR+1J+7srt/17H0oU7ndD4JHqDqG62LGP9FobyJIclQOk19 +UvEBWHTNisSdac+38GMx1awrJ9LhQSueT6a9f5x5Io377T7zA1fnfV9YeK4zw7Ae +6bCBBv0E+LrllqWxPt9RL8cljHZyh8nty1Ic1hZGidz8iPgoOChkU0yQw4VXuKEv +FHaKxty+EAU9FKYQAehJxYQnvn2V7xliBon5hBUKyhQQg5agj72t4ArIJuZSS3QW +c3qwlAz9WnFi+SPfbsJCuG2YJEguOJY3zJCg5civ4wbR5HapiwKePmKX+UMB/1D/ +NiwSVfaJKwG+rqmXO94tHh/O33C7f/CwdLEtrBnphQisgvlBvmaRFC2HoX0VWpEE +1epTXkBEW+ty03k8YIX1VHshO2p2Oa9LPwTDc5AFwD77j48oVqcgiknIRDAY2wWT +RK3gjLRgtwVwI1eq5xubmpJ/N/jdEXdRcnqgpgHOFnaYYDlWZux3CwIYeV3VHc3Y +iGTZq5fVaD3aI+aIzQ59E/cv+W5k/mjl6VHxZAJlxiDR7DSvoyo= +=w+xm +-----END PGP SIGNATURE----- diff --git a/.siglog/manifest.txt b/.siglog/manifest.txt index 6771f29..549d031 100644 --- a/.siglog/manifest.txt +++ b/.siglog/manifest.txt @@ -1 +1,2 @@ -96a874a188c29e575822ba794e0ef4568abdcc8eef758d7ead1c5d17ed85b527 ./siglog +64263feac7b00952e9ec3b6c1fd11316faa58ff673c6bd085fac9f6f8d8389f6 .gitignore +6b4029dc96c118850d84e5600e73d8604cb463bd5c24faed904c21d65eca83fa siglog diff --git a/siglog b/siglog index fc31ef3..df06835 100755 --- a/siglog +++ b/siglog @@ -1,22 +1,65 @@ #! /usr/bin/env bash set -e +MIN_BASH_VERSION=4 +MIN_GPG_VERSION=2.2 +MIN_OPENSSL_VERSION=1.1 + die() { echo "$@" >&2 exit 1 } -checktools(){ +check_version(){ + [[ $2 == $3 ]] && return 0 + local IFS=. + local i ver1=($2) ver2=($3) + for ((i=${#ver1[@]}; i<${#ver2[@]}; i++)); + do ver1[i]=0; + done + for ((i=0; i<${#ver1[@]}; i++)); do + [[ -z ${ver2[i]} ]] && ver2[i]=0 + ((10#${ver1[i]} > 10#${ver2[i]})) && return 0 + ((10#${ver1[i]} < 10#${ver2[i]})) && die \ + "Error: ${1} ${3}+ not found" + done +} + +check_tools(){ + if [ -z "${BASH_VERSINFO}" ] \ + || [ -z "${BASH_VERSINFO[0]}" ] \ + || [ ${BASH_VERSINFO[0]} -lt ${MIN_BASH_VERSION} ]; then + die "Error: bash ${MIN_BASH_VERSION}+ not found"; + fi for cmd in "$@"; do - if ! command -v "$1" >/dev/null; then - printf "not found!\n"; - return 1; - fi + command -v "$1" >/dev/null || die "Error: $cmd not found" + case $cmd in + gpg) + version=$(gpg --version | head -n1 | cut -d" " -f3) + check_version "gpg" "${version}" "${MIN_GPG_VERSION}" + ;; + openssl) + version=$(openssl version | cut -d" " -f2 | sed 's/[a-z]//g') + check_version "openssl" "${version}" "${MIN_OPENSSL_VERSION}" + ;; + esac done } +get_temp(){ + echo "$( + mktemp \ + --quiet \ + --directory \ + -t "$(basename "$0").XXXXXX" 2>/dev/null + || mktemp \ + --quiet \ + --directory + )" +} + gpg_env(){ - GNUPGHOME=$(mktemp -d -p /dev/shm/); export GNUPGHOME + GNUPGHOME=$(get_temp); export GNUPGPHOME killall gpg-agent 2> /dev/null gpg-agent --daemon --extra-socket "$GNUPGHOME/S.gpg-agent" 2> /dev/null echo "export PATH=$GNUPGHOME:$PATH \ @@ -30,9 +73,11 @@ gpg_cleanup(){ } verify_file() { - filename="${1?}" - sig_count=0 - seen_fingerprints="" + local filename="${1?}" + local sig_count=0 + local seen_fingerprints="" + local fingerprint + local signer for sig_filename in "${filename%.*}".*.asc; do gpg --verify "${sig_filename}" "${filename}" >/dev/null 2>&1 || { echo "Invalid signature: ${sig_filename}"; @@ -64,26 +109,13 @@ verify_file() { } } -cmd_manifest() { - #TODO: If this is a git repo, use git to decide what files go in manifest - mkdir -p .siglog - find . \ - -type f \ - -not -path "./.git/*" \ - -not -path "./.siglog/*" \ - -exec openssl sha256 -r {} \; \ - | sed 's/ \*/ /g' \ - | LC_ALL=C sort -k2 \ - > .siglog/manifest.txt -} - -cmd_detach-verify() { +verify_files() { [ $# -lt 3 ] || die \ - "Usage: detach-verify (, (, /dev/null @@ -94,13 +126,45 @@ cmd_detach-verify() { gpg_cleanup } +get_files(){ + if command -v git >/dev/null; then + git ls-files | grep -v .siglog + else + find . \ + -type f \ + -not -path "./.git/*" \ + -not -path "./.siglog/*" + fi +} + +cmd_manifest() { + mkdir -p .${PROGRAM} + printf "$(get_files | xargs openssl sha256 -r)" \ + | sed -e 's/ \*/ /g' -e 's/ \.\// /g' \ + | LC_ALL=C sort -k2 \ + > .${PROGRAM}/manifest.txt +} + cmd_verify() { + ( [ -d ".${PROGRAM}" ] && ls .${PROGRAM}/*.asc >/dev/null 2>&1 ) \ + || die "Error: No signatures" cmd_manifest - for file in .siglog/*.asc; do - gpg --verify "$file" signatures/manifest.txt + for file in .${PROGRAM}/*.asc; do + gpg --verify "$file" .${PROGRAM}/manifest.txt done } +cmd_sign(){ + cmd_manifest + gpg --armor --detach-sig .${PROGRAM}/manifest.txt + local fingerprint=$( \ + gpg --list-packets .${PROGRAM}/manifest.txt.asc \ + | grep "issuer key ID" \ + | sed 's/.*\([A-Z0-9]\{16\}\).*/\1/g' \ + ) + mv .${PROGRAM}/manifest.{"txt.asc","${fingerprint}.asc"} +} + cmd_version() { cat <<-_EOF ============================================ @@ -115,17 +179,14 @@ cmd_version() { cmd_usage() { cmd_version - echo cat <<-_EOF Usage: - $PROGRAM detach-verify [ (,