#!/bin/sh
# shellcheck disable=SC2039

# Check if the script is being sourced or not.
# shellcheck disable=SC2142
alias is_sourced='[ "$_" != "$0" ] && [ "${-#*i}" != "$-" ]'

# Returns the subject hash of the certificate path provided.
alias subject_hash='openssl x509 -noout -subject_hash -in'

# Returns the issuer hash of the certificate path provided.
alias issuer_hash='openssl x509 -noout -issuer_hash -in'

find_root_cert () {
    # Returns the (first) root (self-signed) certificate found in the list
    # of file paths provided.
    local filename
    for filename in "$@"
    do
        if [ -f "$filename" ] && \
            [ "$(subject_hash "$filename")" = "$(issuer_hash "$filename")" ]
        then
            echo "$filename"
            break
        fi
    done
}

find_cert_by_issuer_hash () {
    # Gets a hash and a list of filenames, returns the
    # filename of the certificate with that issuer hash. Ignores self-signed
    # (root CA) certificates.
    local certhash filename
    certhash="$1"
    shift
    for filename in "$@"
    do
        if [ -f "$filename" ] && \
            [ "$(issuer_hash "$filename")" = "$certhash" ] && \
            [ "$(issuer_hash "$filename")" != "$(subject_hash "$filename")" ]
        then
            echo "$filename"
            break
        fi
    done
}

unbundle_cert () {
    # Recieves a file path, creates a directory named certs with all of the
    # individual certs contained within that file inside the directory (the
    # filenames are the subject hash for each certificate).
    local certificate
    mkdir -p certs
    awk '/-----BEGIN[A-Z0-9 ]*CERTIFICATE-----/ {n++}
        n > 0 {print > ("certs/cert" (1+n))}' "$1"
    for certificate in certs/cert*
    do
        [ -f "$certificate" ] || continue
        mv "$certificate" "certs/$(subject_hash "$certificate")"
    done
}

bundle_certs () {
    local filename issuer issued bundle
    if [ $# -eq 0 ]
    then
        echo "Usage: bundle_certs filename [filename2 [filename3 ...]]" >> /dev/stderr
        return 1
    fi
    for filename in "$@"
    do
        [ -f "$filename" ] && unbundle_cert "$filename"
    done
    issuer="$(find_root_cert certs/*)"
    if [ -z "$issuer" ]
    then
        echo "Failed to find root certificate." >> /dev/stderr
        return 1
    fi
    issued="$(find_cert_by_issuer_hash "$(basename "$issuer")" certs/*)"
    bundle="$(cat "$issued")"
    while [ -n "$issued" ]
    do
        issuer="$issued"
        issued="$(find_cert_by_issuer_hash "$(basename "$issuer")" certs/*)"
        [ -n "$issued" ] && bundle="$(echo "${bundle:-}"; cat "$issued")"
    done
    echo "$bundle"
    rm -r certs
}

if ! (is_sourced)
then
    set -eu
    if [ $# -eq 0 ]
    then
        echo "Usage: $(basename "$0") filename [filename2 [filename3 ...]]" >> /dev/stderr
        return 1
    else
        bundle_certs "$@"
    fi
fi
