BASEDIR="${SCRIPTDIR}"
ORIGARGS=("${@}")
+noglob_set() {
+ if [[ -n "${ZSH_VERSION:-}" ]]; then
+ set +o noglob
+ else
+ set +f
+ fi
+}
+
+noglob_clear() {
+ if [[ -n "${ZSH_VERSION:-}" ]]; then
+ set -o noglob
+ else
+ set -f
+ fi
+}
+
# Generate json.sh path matching string
json_path() {
if [ ! "${1}" = "-p" ]; then
# Get sub-dictionary from json
get_json_dict_value() {
local filter
- echo "$(json_path "${1:-}" "${2:-}")"
filter="$(printf 's/.*\[%s\][[:space:]]*\(.*\)/\\1/p' "$(json_path "${1:-}" "${2:-}")")"
sed -n "${filter}" | jsonsh
}
local ESCAPE
local CHAR
- if echo "test string" | egrep -ao --color=never "test" >/dev/null 2>&1
+ if echo "test string" | grep -Eao --color=never "test" >/dev/null 2>&1
then
- GREP='egrep -ao --color=never'
+ GREP='grep -Eao --color=never'
else
- GREP='egrep -ao'
+ GREP='grep -Eao'
fi
+ # shellcheck disable=SC2196
if echo "test string" | egrep -ao "test" >/dev/null 2>&1
then
ESCAPE='(\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})'
local SPACE='[[:space:]]+'
# Force zsh to expand $A into multiple words
- local is_wordsplit_disabled=$(unsetopt 2>/dev/null | grep -c '^shwordsplit$')
- if [ $is_wordsplit_disabled != 0 ]; then setopt shwordsplit; fi
- $GREP "$STRING|$NUMBER|$KEYWORD|$SPACE|." | egrep -v "^$SPACE$"
- if [ $is_wordsplit_disabled != 0 ]; then unsetopt shwordsplit; fi
+ local is_wordsplit_disabled
+ is_wordsplit_disabled="$(unsetopt 2>/dev/null | grep -c '^shwordsplit$')"
+ if [ "${is_wordsplit_disabled}" != "0" ]; then setopt shwordsplit; fi
+ $GREP "$STRING|$NUMBER|$KEYWORD|$SPACE|." | grep -Ev "^$SPACE$"
+ if [ "${is_wordsplit_disabled}" != "0" ]; then unsetopt shwordsplit; fi
}
parse_array () {
}
parse_value () {
- local jpath="${1:+$1,}${2:-}" isleaf=0 isempty=0 print=0
+ local jpath="${1:+$1,}${2:-}"
case "$token" in
'{') parse_object "$jpath" ;;
'[') parse_array "$jpath" ;;
# At this point, the only valid single-character tokens are digits.
''|[!0-9]) throw "EXPECTED value GOT ${token:-EOF}" ;;
- *) value=$token
+ *) value="${token/\\\///}"
# replace solidus ("\/") in json strings with normalized value: "/"
- value=$(echo "$value" | sed 's#\\/#/#g')
- isleaf=1
- [ "$value" = '""' ] && isempty=1
;;
esac
[ "$value" = '' ] && return
# Create (identifiable) temporary files
_mktemp() {
- # shellcheck disable=SC2068
- mktemp ${@:-} "${TMPDIR:-/tmp}/dehydrated-XXXXXX"
+ mktemp "${TMPDIR:-/tmp}/dehydrated-XXXXXX"
}
# Check for script dependencies
fi
# Allow globbing
- [[ -n "${ZSH_VERSION:-}" ]] && set +o noglob || set +f
+ noglob_set
for check_config_d in "${CONFIG_D}"/*.sh; do
if [[ -f "${check_config_d}" ]] && [[ -r "${check_config_d}" ]]; then
done
# Disable globbing
- [[ -n "${ZSH_VERSION:-}" ]] && set -o noglob || set -f
+ noglob_clear
fi
# Check for missing dependencies
fi
fi
+ # shellcheck disable=SC1090
[[ -f "${ACCOUNTDIR}/${CAHASH}/config" ]] && . "${ACCOUNTDIR}/${CAHASH}/config"
ACCOUNT_KEY="${ACCOUNTDIR}/${CAHASH}/account_key.pem"
ACCOUNT_KEY_JSON="${ACCOUNTDIR}/${CAHASH}/registration_info.json"
grep -q newOrder <<< "${CA_DIRECTORY}" && API=2 || API=1
fi
- if [[ ${API} -eq 1 ]]; then
- # shellcheck disable=SC2015
+ # shellcheck disable=SC2015
+ if [[ "${API}" = "1" ]]; then
CA_NEW_CERT="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value new-cert)" &&
CA_NEW_AUTHZ="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value new-authz)" &&
CA_NEW_REG="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value new-reg)" &&
# Since reg URI is missing from directory we will assume it is the same as CA_NEW_REG without the new part
CA_REG=${CA_NEW_REG/new-reg/reg}
else
- # shellcheck disable=SC2015
CA_NEW_ORDER="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value newOrder)" &&
CA_NEW_NONCE="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value newNonce)" &&
CA_NEW_ACCOUNT="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value newAccount)" &&
CA_REQUIRES_EAB="$(printf "%s" "${CA_DIRECTORY}" | get_json_bool_value -p '"meta","externalAccountRequired"' || echo false)" &&
CA_REVOKE_CERT="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value revokeCert)" ||
_exiterr "Problem retrieving ACME/CA-URLs, check if your configured CA points to the directory entrypoint."
- # Since acct URI is missing from directory we will assume it is the same as CA_NEW_ACCOUNT without the new part
- CA_ACCOUNT=${CA_NEW_ACCOUNT/new-acct/acct}
fi
# Export some environment variables to be used in hook script
if [[ ! "${PARAM_ACCEPT_TERMS:-}" = "yes" ]]; then
printf '\n' >&2
printf 'To use dehydrated with this certificate authority you have to agree to their terms of service which you can find here: %s\n\n' "${CA_TERMS}" >&2
- printf 'To accept these terms of service run `%s --register --accept-terms`.\n' "${0}" >&2
+ printf 'To accept these terms of service run "%s --register --accept-terms".\n' "${0}" >&2
exit 1
fi
echo "+ Generating account key..."
generated="true"
- local tmp_account_key="$(_mktemp)"
+ local tmp_account_key
+ tmp_account_key="$(_mktemp)"
_openssl genrsa -out "${tmp_account_key}" "${KEYSIZE}"
cat "${tmp_account_key}" > "${ACCOUNT_KEY}"
rm "${tmp_account_key}"
# Read account information or request from CA if missing
if [[ -e "${ACCOUNT_KEY_JSON}" ]]; then
if [[ ${API} -eq 1 ]]; then
- ACCOUNT_ID="$(cat "${ACCOUNT_KEY_JSON}" | jsonsh | get_json_int_value id)"
+ ACCOUNT_ID="$(jsonsh < "${ACCOUNT_KEY_JSON}" | get_json_int_value id)"
ACCOUNT_URL="${CA_REG}/${ACCOUNT_ID}"
else
if [[ -e "${ACCOUNT_ID_JSON}" ]]; then
- ACCOUNT_URL="$(cat "${ACCOUNT_ID_JSON}" | jsonsh | get_json_string_value url)"
+ ACCOUNT_URL="$(jsonsh < "${ACCOUNT_ID_JSON}" | get_json_string_value url)"
fi
# if account URL is not storred, fetch it from the CA
if [[ -z "${ACCOUNT_URL:-}" ]]; then
# Convert hex string to binary data
hex2bin() {
# Remove spaces, add leading zero, escape as hex string and parse with printf
- printf -- "$(cat | _sed -e 's/[[:space:]]//g' -e 's/^(.(.{2})*)$/0\1/' -e 's/(.{2})/\\x\1/g')"
+ # shellcheck disable=SC2059
+ printf "%b" "$(cat | _sed -e 's/[[:space:]]//g' -e 's/^(.(.{2})*)$/0\1/' -e 's/(.{2})/\\x\1/g')"
}
# Convert binary data to hex string
fi
set +e
+ # shellcheck disable=SC2086
if [[ "${1}" = "head" ]]; then
statuscode="$(curl ${ip_version:-} ${CURL_OPTS} -A "dehydrated/${VERSION} curl/${CURL_VERSION}" -s -w "%{http_code}" -o "${tempcont}" "${2}" -I)"
curlret="${?}"
# An exclusive hook for the {1}-request error might be useful (e.g., for sending an e-mail to admins)
if [[ -n "${HOOK}" ]]; then
- errtxt="$(cat ${tempcont})"
- errheaders="$(cat ${tempheaders})"
+ errtxt="$(cat "${tempcont}")"
+ errheaders="$(cat "${tempheaders}")"
"${HOOK}" "request_failure" "${statuscode}" "${errtxt}" "${1}" "${errheaders}" || _exiterr 'request_failure hook returned with non-zero exit code'
fi
# SANs used, extract these
altnames="$( <<<"${reqtext}" awk '/X509v3 Subject Alternative Name:/{print;getline;print;}' | tail -n1 )"
# split to one per line:
- # shellcheck disable=SC1003
- altnames="$( <<<"${altnames}" _sed -e 's/^[[:space:]]*//; s/, /\'$'\n''/g' )"
+ altnames="$( <<<"${altnames}" _sed -e 's/^[[:space:]]*//; s/, /'"'$'\n'"'/g' )"
# we can only get DNS: ones signed
if grep -qEv '^(DNS|othername):' <<<"${altnames}"; then
_exiterr "Certificate signing request contains non-DNS Subject Alternative Names"
if [[ ${num_pending_challenges} -ne 0 ]]; then
echo " + Deploying challenge tokens..."
if [[ -n "${HOOK}" ]] && [[ "${HOOK_CHAIN}" = "yes" ]]; then
- "${HOOK}" "deploy_challenge" ${deploy_args[@]} || _exiterr 'deploy_challenge hook returned with non-zero exit code'
+ "${HOOK}" "deploy_challenge" "${deploy_args[@]}" || _exiterr 'deploy_challenge hook returned with non-zero exit code'
elif [[ -n "${HOOK}" ]]; then
# Run hook script to deploy the challenge token
local idx=0
while [ ${idx} -lt ${num_pending_challenges} ]; do
- "${HOOK}" "deploy_challenge" ${deploy_args[${idx}]} || _exiterr 'deploy_challenge hook returned with non-zero exit code'
+ "${HOOK}" "deploy_challenge" "${deploy_args[${idx}]}" || _exiterr 'deploy_challenge hook returned with non-zero exit code'
idx=$((idx+1))
done
fi
echo " + Cleaning challenge tokens..."
# Clean challenge tokens using chained hook
- [[ -n "${HOOK}" ]] && [[ "${HOOK_CHAIN}" = "yes" ]] && ("${HOOK}" "clean_challenge" ${deploy_args[@]} || _exiterr 'clean_challenge hook returned with non-zero exit code')
+ [[ -n "${HOOK}" ]] && [[ "${HOOK_CHAIN}" = "yes" ]] && ("${HOOK}" "clean_challenge" "${deploy_args[@]}" || _exiterr 'clean_challenge hook returned with non-zero exit code')
# Clean remaining challenge tokens if validation has failed
local idx=0
# Delete alpn verification certificates
[[ "${CHALLENGETYPE}" = "tls-alpn-01" ]] && rm -f "${ALPNCERTDIR}/${challenge_names[${idx}]}.crt.pem" "${ALPNCERTDIR}/${challenge_names[${idx}]}.key.pem"
# Clean challenge token using non-chained hook
- [[ -n "${HOOK}" ]] && [[ "${HOOK_CHAIN}" != "yes" ]] && ("${HOOK}" "clean_challenge" ${deploy_args[${idx}]} || _exiterr 'clean_challenge hook returned with non-zero exit code')
+ [[ -n "${HOOK}" ]] && [[ "${HOOK_CHAIN}" != "yes" ]] && ("${HOOK}" "clean_challenge" "${deploy_args[${idx}]}" || _exiterr 'clean_challenge hook returned with non-zero exit code')
idx=$((idx+1))
done
foundaltchain=1
fi
if [ "${foundaltchain}" = "0" ]; then
- while read altcrturl; do
+ while read -r altcrturl; do
if [ "${foundaltchain}" = "0" ]; then
altcrt="$(signed_request "${altcrturl}" "")"
altcn="$(get_last_cn "${altcrt}")"
tmp_openssl_cnf="$(_mktemp)"
cat "${OPENSSL_CNF}" > "${tmp_openssl_cnf}"
printf "\n[SAN]\nsubjectAltName=DNS:%s\n" "${altname}" >> "${tmp_openssl_cnf}"
- printf "1.3.6.1.5.5.7.1.31=critical,DER:04:20:${acmevalidation}\n" >> "${tmp_openssl_cnf}"
+ printf "1.3.6.1.5.5.7.1.31=critical,DER:04:20:%s\n" "${acmevalidation}" >> "${tmp_openssl_cnf}"
SUBJ="/CN=${altname}/"
[[ "${OSTYPE:0:5}" = "MINGW" ]] && SUBJ="/${SUBJ}"
_openssl req -x509 -new -sha256 -nodes -newkey rsa:2048 -keyout "${alpncertdir}/${altname}.key.pem" -out "${alpncertdir}/${altname}.crt.pem" -subj "${SUBJ}" -extensions SAN -config "${tmp_openssl_cnf}"
if [[ ! -r "${certdir}/privkey.pem" ]] || [[ "${PRIVATE_KEY_RENEW}" = "yes" ]]; then
echo " + Generating private key..."
privkey="privkey-${timestamp}.pem"
- local tmp_privkey="$(_mktemp)"
+ local tmp_privkey
+ tmp_privkey="$(_mktemp)"
case "${KEY_ALGO}" in
rsa) _openssl genrsa -out "${tmp_privkey}" "${KEYSIZE}";;
prime256v1|secp384r1) _openssl ecparam -genkey -name "${KEY_ALGO}" -out "${tmp_privkey}";;
revision="$(cd "${SCRIPTDIR}"; git rev-parse HEAD 2>/dev/null || echo "unknown")"
echo "GIT-Revision: ${revision}"
echo ""
+ # shellcheck disable=SC1091
if [[ "${OSTYPE}" =~ (BSD|Darwin) ]]; then
echo "OS: $(uname -sr)"
elif [[ -e /etc/os-release ]]; then
elif [[ -e /usr/lib/os-release ]]; then
( . /usr/lib/os-release && echo "OS: $PRETTY_NAME" )
else
- echo "OS: $(cat /etc/issue | grep -v ^$ | head -n1 | _sed 's/\\(r|n|l) .*//g')"
+ echo "OS: $(grep -v '^$' /etc/issue | head -n1 | _sed 's/\\(r|n|l) .*//g')"
fi
echo "Used software:"
[[ -n "${BASH_VERSION:-}" ]] && echo " bash: ${BASH_VERSION}"
if [[ -n "${PARAM_DOMAIN:-}" ]]; then
DOMAINS_TXT="$(_mktemp)"
if [[ -n "${PARAM_ALIAS:-}" ]]; then
- printf -- "${PARAM_DOMAIN} > ${PARAM_ALIAS}" > "${DOMAINS_TXT}"
+ printf "%s > %s" "${PARAM_DOMAIN}" "${PARAM_ALIAS}" > "${DOMAINS_TXT}"
else
- printf -- "${PARAM_DOMAIN}" > "${DOMAINS_TXT}"
+ printf "%s" "${PARAM_DOMAIN}" > "${DOMAINS_TXT}"
fi
elif [[ -e "${DOMAINS_TXT}" ]]; then
if [[ ! -r "${DOMAINS_TXT}" ]]; then
alias="$(grep -Eo '>[^ ]+' <<< "${line}" || true)"
line="$(_sed -e 's/>[^ ]+[ ]*//g' <<< "${line}")"
aliascount="$(grep -Eo '>' <<< "${alias}" | awk 'END {print NR}' || true )"
- [ ${aliascount} -gt 1 ] && _exiterr "Only one alias per line is allowed in domains.txt!"
+ [ "${aliascount}" -gt 1 ] && _exiterr "Only one alias per line is allowed in domains.txt!"
domain="$(printf '%s\n' "${line}" | cut -d' ' -f1)"
morenames="$(printf '%s\n' "${line}" | cut -s -d' ' -f2-)"
- [ ${aliascount} -lt 1 ] && alias="${domain}" || alias="${alias#>}"
+ [ "${aliascount}" -lt 1 ] && alias="${domain}" || alias="${alias#>}"
export alias
if [[ -z "${morenames}" ]];then
if [[ ! "${skip}" = "yes" ]]; then
update_ocsp="yes"
[[ -z "${csr}" ]] || printf "%s" "${csr}" > "${certdir}/cert-${timestamp}.csr"
+ # shellcheck disable=SC2086
if [[ "${PARAM_KEEP_GOING:-}" = "yes" ]]; then
skip_exit_hook=yes
- sign_domain "${certdir}" ${timestamp} ${domain} ${morenames} &
+ sign_domain "${certdir}" "${timestamp}" "${domain}" ${morenames} &
wait $! || exit_with_errorcode=1
skip_exit_hook=no
else
- sign_domain "${certdir}" ${timestamp} ${domain} ${morenames}
+ sign_domain "${certdir}" "${timestamp}" "${domain}" ${morenames}
fi
fi
# gen cert
certfile="$(_mktemp)"
+ # shellcheck disable=SC2086
sign_csr "${csr}" ${altnames} 3> "${certfile}"
# print cert
fi
# Allow globbing
- [[ -n "${ZSH_VERSION:-}" ]] && set +o noglob || set +f
+ noglob_set
# Loop over all certificate directories
for certdir in "${CERTDIR}/"*; do
fi
}
- # shellcheck disable=SC2199
- [[ -z "${@}" ]] && eval set -- "--help"
+ [[ -z "${*}" ]] && eval set -- "--help"
while (( ${#} )); do
case "${1}" in