acme.sh/acme.sh

7996 lines
217 KiB
Bash
Raw Permalink Normal View History

#!/usr/bin/env sh
2016-04-25 12:01:37 +00:00
2022-11-23 13:55:19 +00:00
VER=3.0.6
2016-04-13 12:37:18 +00:00
2016-04-14 13:44:26 +00:00
PROJECT_NAME="acme.sh"
2016-04-13 12:37:18 +00:00
2016-04-14 13:44:26 +00:00
PROJECT_ENTRY="acme.sh"
2020-01-30 02:50:39 +00:00
PROJECT="https://github.com/acmesh-official/$PROJECT_NAME"
2016-03-08 12:44:12 +00:00
DEFAULT_INSTALL_HOME="$HOME/.$PROJECT_NAME"
_WINDOWS_SCHEDULER_NAME="$PROJECT_NAME.cron"
_SCRIPT_="$0"
_SUB_FOLDER_NOTIFY="notify"
_SUB_FOLDER_DNSAPI="dnsapi"
_SUB_FOLDER_DEPLOY="deploy"
_SUB_FOLDERS="$_SUB_FOLDER_DNSAPI $_SUB_FOLDER_DEPLOY $_SUB_FOLDER_NOTIFY"
CA_LETSENCRYPT_V2="https://acme-v02.api.letsencrypt.org/directory"
CA_LETSENCRYPT_V2_TEST="https://acme-staging-v02.api.letsencrypt.org/directory"
2018-01-06 04:45:24 +00:00
CA_BUYPASS="https://api.buypass.com/acme/directory"
CA_BUYPASS_TEST="https://api.test4.buypass.no/acme/directory"
CA_ZEROSSL="https://acme.zerossl.com/v2/DV90"
2022-02-04 05:49:58 +00:00
_ZERO_EAB_ENDPOINT="https://api.zerossl.com/acme/eab-credentials-email"
2021-06-21 13:31:00 +00:00
CA_SSLCOM_RSA="https://acme.ssl.com/sslcom-dv-rsa"
CA_SSLCOM_ECC="https://acme.ssl.com/sslcom-dv-ecc"
CA_GOOGLE="https://dv.acme-v02.api.pki.goog/directory"
CA_GOOGLE_TEST="https://dv.acme-v02.test-api.pki.goog/directory"
2021-06-13 06:29:26 +00:00
DEFAULT_CA=$CA_ZEROSSL
DEFAULT_STAGING_CA=$CA_LETSENCRYPT_V2_TEST
CA_NAMES="
2021-06-21 13:31:00 +00:00
ZeroSSL.com,zerossl
2020-08-18 15:28:06 +00:00
LetsEncrypt.org,letsencrypt
LetsEncrypt.org_test,letsencrypt_test,letsencrypttest
BuyPass.com,buypass
BuyPass.com_test,buypass_test,buypasstest
2021-06-21 13:31:00 +00:00
SSL.com,sslcom
Google.com,google
Google.com_test,googletest,google_test
"
CA_SERVERS="$CA_ZEROSSL,$CA_LETSENCRYPT_V2,$CA_LETSENCRYPT_V2_TEST,$CA_BUYPASS,$CA_BUYPASS_TEST,$CA_SSLCOM_RSA,$CA_GOOGLE,$CA_GOOGLE_TEST"
2016-11-13 13:47:58 +00:00
DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)"
2016-03-19 14:04:03 +00:00
DEFAULT_ACCOUNT_KEY_LENGTH=ec-256
DEFAULT_DOMAIN_KEY_LENGTH=ec-256
DEFAULT_OPENSSL_BIN="openssl"
2016-03-08 12:44:12 +00:00
VTYPE_HTTP="http-01"
VTYPE_DNS="dns-01"
VTYPE_ALPN="tls-alpn-01"
ID_TYPE_DNS="dns"
ID_TYPE_IP="ip"
LOCAL_ANY_ADDRESS="0.0.0.0"
DEFAULT_RENEW=60
2016-06-26 02:09:51 +00:00
2016-09-23 14:35:13 +00:00
NO_VALUE="no"
W_DNS="dns"
W_ALPN="alpn"
2018-02-12 13:49:22 +00:00
DNS_ALIAS_PREFIX="="
2016-03-08 12:44:12 +00:00
2017-02-06 12:42:54 +00:00
MODE_STATELESS="stateless"
STATE_VERIFIED="verified_ok"
2017-02-13 15:29:37 +00:00
NGINX="nginx:"
NGINX_START="#ACME_NGINX_START"
NGINX_END="#ACME_NGINX_END"
2017-02-13 15:29:37 +00:00
BEGIN_CSR="-----BEGIN [NEW ]\{0,4\}CERTIFICATE REQUEST-----"
END_CSR="-----END [NEW ]\{0,4\}CERTIFICATE REQUEST-----"
2016-03-17 13:18:09 +00:00
BEGIN_CERT="-----BEGIN CERTIFICATE-----"
END_CERT="-----END CERTIFICATE-----"
CONTENT_TYPE_JSON="application/jose+json"
2016-06-18 03:29:28 +00:00
RENEW_SKIP=2
2022-07-07 12:01:43 +00:00
CODE_DNS_MANUAL=3
2016-06-18 03:29:28 +00:00
B64CONF_START="__ACME_BASE64__START_"
B64CONF_END="__ACME_BASE64__END_"
ECC_SEP="_"
ECC_SUFFIX="${ECC_SEP}ecc"
2016-09-25 13:58:59 +00:00
LOG_LEVEL_1=1
LOG_LEVEL_2=2
LOG_LEVEL_3=3
DEFAULT_LOG_LEVEL="$LOG_LEVEL_1"
2017-02-19 04:13:18 +00:00
DEBUG_LEVEL_1=1
DEBUG_LEVEL_2=2
DEBUG_LEVEL_3=3
DEBUG_LEVEL_DEFAULT=$DEBUG_LEVEL_1
DEBUG_LEVEL_NONE=0
2019-10-03 12:37:46 +00:00
DOH_CLOUDFLARE=1
DOH_GOOGLE=2
DOH_ALI=3
DOH_DP=4
2019-10-03 12:37:46 +00:00
2017-02-19 05:24:00 +00:00
HIDDEN_VALUE="[hidden](please add '--output-insecure' to see this value)"
2017-02-11 13:15:36 +00:00
SYSLOG_ERROR="user.error"
2017-02-19 04:13:18 +00:00
SYSLOG_INFO="user.info"
2017-02-11 13:15:36 +00:00
SYSLOG_DEBUG="user.debug"
2017-02-19 04:13:18 +00:00
#error
2017-02-19 04:42:37 +00:00
SYSLOG_LEVEL_ERROR=3
2017-02-19 04:13:18 +00:00
#info
2017-02-19 04:42:37 +00:00
SYSLOG_LEVEL_INFO=6
2017-02-19 04:13:18 +00:00
#debug
2017-02-19 04:42:37 +00:00
SYSLOG_LEVEL_DEBUG=7
2017-02-19 04:13:18 +00:00
#debug2
2017-02-19 04:42:37 +00:00
SYSLOG_LEVEL_DEBUG_2=8
2017-02-19 04:13:18 +00:00
#debug3
2017-02-19 04:42:37 +00:00
SYSLOG_LEVEL_DEBUG_3=9
2017-02-19 04:13:18 +00:00
2017-02-19 04:42:37 +00:00
SYSLOG_LEVEL_DEFAULT=$SYSLOG_LEVEL_ERROR
2017-02-19 04:13:18 +00:00
#none
SYSLOG_LEVEL_NONE=0
NOTIFY_LEVEL_DISABLE=0
NOTIFY_LEVEL_ERROR=1
NOTIFY_LEVEL_RENEW=2
NOTIFY_LEVEL_SKIP=3
NOTIFY_LEVEL_DEFAULT=$NOTIFY_LEVEL_RENEW
NOTIFY_MODE_BULK=0
NOTIFY_MODE_CERT=1
NOTIFY_MODE_DEFAULT=$NOTIFY_MODE_BULK
_BASE64_ENCODED_CFGS="Le_PreHook Le_PostHook Le_RenewHook Le_Preferred_Chain Le_ReloadCmd"
2020-01-30 02:50:39 +00:00
_DEBUG_WIKI="https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh"
2016-03-08 12:44:12 +00:00
2020-01-30 02:50:39 +00:00
_PREPARE_LINK="https://github.com/acmesh-official/acme.sh/wiki/Install-preparations"
2020-01-30 02:50:39 +00:00
_STATELESS_WIKI="https://github.com/acmesh-official/acme.sh/wiki/Stateless-Mode"
2017-02-06 12:42:54 +00:00
2020-01-30 02:50:39 +00:00
_DNS_ALIAS_WIKI="https://github.com/acmesh-official/acme.sh/wiki/DNS-alias-mode"
2018-02-10 02:45:29 +00:00
2020-01-30 02:50:39 +00:00
_DNS_MANUAL_WIKI="https://github.com/acmesh-official/acme.sh/wiki/dns-manual-mode"
_DNS_API_WIKI="https://github.com/acmesh-official/acme.sh/wiki/dnsapi"
2020-01-30 02:50:39 +00:00
_NOTIFY_WIKI="https://github.com/acmesh-official/acme.sh/wiki/notify"
2020-01-30 02:50:39 +00:00
_SUDO_WIKI="https://github.com/acmesh-official/acme.sh/wiki/sudo"
2019-08-11 06:07:36 +00:00
_REVOKE_WIKI="https://github.com/acmesh-official/acme.sh/wiki/revokecert"
_ZEROSSL_WIKI="https://github.com/acmesh-official/acme.sh/wiki/ZeroSSL.com-CA"
2021-06-21 13:31:00 +00:00
_SSLCOM_WIKI="https://github.com/acmesh-official/acme.sh/wiki/SSL.com-CA"
2020-08-12 13:17:15 +00:00
_SERVER_WIKI="https://github.com/acmesh-official/acme.sh/wiki/Server"
_PREFERRED_CHAIN_WIKI="https://github.com/acmesh-official/acme.sh/wiki/Preferred-Chain"
_VALIDITY_WIKI="https://github.com/acmesh-official/acme.sh/wiki/Validity"
2020-12-23 12:45:43 +00:00
_DNSCHECK_WIKI="https://github.com/acmesh-official/acme.sh/wiki/dnscheck"
2017-08-22 12:27:13 +00:00
_DNS_MANUAL_ERR="The dns manual mode can not renew automatically, you must issue it again manually. You'd better use the other modes instead."
_DNS_MANUAL_WARN="It seems that you are using dns manual mode. please take care: $_DNS_MANUAL_ERR"
_DNS_MANUAL_ERROR="It seems that you are using dns manual mode. Read this link first: $_DNS_MANUAL_WIKI"
2016-09-06 11:37:41 +00:00
__INTERACTIVE=""
2016-11-09 11:30:39 +00:00
if [ -t 1 ]; then
2016-09-06 11:37:41 +00:00
__INTERACTIVE="1"
fi
2016-04-17 09:33:08 +00:00
__green() {
if [ "${__INTERACTIVE}${ACME_NO_COLOR:-0}" = "10" -o "${ACME_FORCE_COLOR}" = "1" ]; then
2019-10-27 03:43:40 +00:00
printf '\33[1;32m%b\33[0m' "$1"
return
2016-09-02 12:55:11 +00:00
fi
printf -- "%b" "$1"
}
__red() {
if [ "${__INTERACTIVE}${ACME_NO_COLOR:-0}" = "10" -o "${ACME_FORCE_COLOR}" = "1" ]; then
2019-10-27 03:43:40 +00:00
printf '\33[1;31m%b\33[0m' "$1"
return
2016-09-02 12:55:11 +00:00
fi
printf -- "%b" "$1"
}
2016-04-17 09:33:08 +00:00
2016-09-25 13:58:59 +00:00
_printargs() {
2018-03-14 08:52:58 +00:00
_exitstatus="$?"
if [ -z "$NO_TIMESTAMP" ] || [ "$NO_TIMESTAMP" = "0" ]; then
printf -- "%s" "[$(date)] "
fi
2016-11-09 11:30:39 +00:00
if [ -z "$2" ]; then
printf -- "%s" "$1"
else
printf -- "%s" "$1='$2'"
fi
2016-09-25 13:58:59 +00:00
printf "\n"
# return the saved exit status
return "$_exitstatus"
}
2016-11-04 14:03:41 +00:00
_dlg_versions() {
echo "Diagnosis versions: "
2017-02-25 11:08:00 +00:00
echo "openssl:$ACME_OPENSSL_BIN"
2017-03-30 13:16:25 +00:00
if _exists "${ACME_OPENSSL_BIN:-openssl}"; then
${ACME_OPENSSL_BIN:-openssl} version 2>&1
2016-11-04 14:03:41 +00:00
else
echo "$ACME_OPENSSL_BIN doesn't exist."
2016-11-04 14:03:41 +00:00
fi
2016-11-09 11:30:39 +00:00
2016-11-04 14:03:41 +00:00
echo "apache:"
2016-11-09 11:30:39 +00:00
if [ "$_APACHECTL" ] && _exists "$_APACHECTL"; then
2017-03-03 14:03:19 +00:00
$_APACHECTL -V 2>&1
2016-11-04 14:03:41 +00:00
else
echo "apache doesn't exist."
2016-11-04 14:03:41 +00:00
fi
2016-11-09 11:30:39 +00:00
2017-06-15 13:44:10 +00:00
echo "nginx:"
if _exists "nginx"; then
nginx -V 2>&1
else
echo "nginx doesn't exist."
2017-06-15 13:44:10 +00:00
fi
echo "socat:"
if _exists "socat"; then
socat -V 2>&1
2016-11-04 14:03:41 +00:00
else
_debug "socat doesn't exist."
2016-11-04 14:03:41 +00:00
fi
}
2017-02-11 13:15:36 +00:00
#class
_syslog() {
2018-03-14 08:52:58 +00:00
_exitstatus="$?"
2017-02-19 04:13:18 +00:00
if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" = "$SYSLOG_LEVEL_NONE" ]; then
2017-02-11 13:15:36 +00:00
return
fi
_logclass="$1"
shift
if [ -z "$__logger_i" ]; then
if _contains "$(logger --help 2>&1)" "-i"; then
__logger_i="logger -i"
else
__logger_i="logger"
fi
fi
$__logger_i -t "$PROJECT_NAME" -p "$_logclass" "$(_printargs "$@")" >/dev/null 2>&1
2018-03-14 08:52:58 +00:00
return "$_exitstatus"
2017-02-11 13:15:36 +00:00
}
2016-09-25 13:58:59 +00:00
_log() {
[ -z "$LOG_FILE" ] && return
2016-11-09 12:45:57 +00:00
_printargs "$@" >>"$LOG_FILE"
2016-09-25 13:58:59 +00:00
}
_info() {
2017-02-19 04:13:18 +00:00
_log "$@"
2017-02-19 04:42:37 +00:00
if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_INFO" ]; then
2017-02-19 04:13:18 +00:00
_syslog "$SYSLOG_INFO" "$@"
fi
2016-09-25 13:58:59 +00:00
_printargs "$@"
2016-03-08 12:44:12 +00:00
}
_err() {
2017-02-19 04:13:18 +00:00
_syslog "$SYSLOG_ERROR" "$@"
_log "$@"
if [ -z "$NO_TIMESTAMP" ] || [ "$NO_TIMESTAMP" = "0" ]; then
printf -- "%s" "[$(date)] " >&2
fi
2016-11-09 11:30:39 +00:00
if [ -z "$2" ]; then
2016-09-28 05:13:08 +00:00
__red "$1" >&2
else
__red "$1='$2'" >&2
fi
2016-09-27 13:27:43 +00:00
printf "\n" >&2
2016-03-08 12:44:12 +00:00
return 1
}
_usage() {
2016-11-09 11:30:39 +00:00
__red "$@" >&2
2016-09-28 05:13:08 +00:00
printf "\n" >&2
}
__debug_bash_helper() {
# At this point only do for --debug 3
if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -lt "$DEBUG_LEVEL_3" ]; then
return
fi
# Return extra debug info when running with bash, otherwise return empty
# string.
if [ -z "${BASH_VERSION}" ]; then
return
fi
# We are a bash shell at this point, return the filename, function name, and
# line number as a string
_dbh_saveIFS=$IFS
IFS=" "
# Must use eval or syntax error happens under dash. The eval should use
# single quotes as older versions of busybox had a bug with double quotes and
# eval.
# Use 'caller 1' as we want one level up the stack as we should be called
# by one of the _debug* functions
eval '_dbh_called=($(caller 1))'
IFS=$_dbh_saveIFS
eval '_dbh_file=${_dbh_called[2]}'
if [ -n "${_script_home}" ]; then
# Trim off the _script_home directory name
eval '_dbh_file=${_dbh_file#$_script_home/}'
fi
eval '_dbh_function=${_dbh_called[1]}'
eval '_dbh_lineno=${_dbh_called[0]}'
printf "%-40s " "$_dbh_file:${_dbh_function}:${_dbh_lineno}"
}
_debug() {
2017-02-19 04:13:18 +00:00
if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_1" ]; then
_log "$@"
2016-09-25 13:58:59 +00:00
fi
2017-02-19 04:42:37 +00:00
if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG" ]; then
2017-02-19 04:13:18 +00:00
_syslog "$SYSLOG_DEBUG" "$@"
fi
if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_1" ]; then
_bash_debug=$(__debug_bash_helper)
_printargs "${_bash_debug}$@" >&2
fi
}
2017-02-19 05:24:00 +00:00
#output the sensitive messages
_secure_debug() {
if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_1" ]; then
if [ "$OUTPUT_INSECURE" = "1" ]; then
_log "$@"
else
_log "$1" "$HIDDEN_VALUE"
fi
fi
if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG" ]; then
_syslog "$SYSLOG_DEBUG" "$1" "$HIDDEN_VALUE"
fi
if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_1" ]; then
if [ "$OUTPUT_INSECURE" = "1" ]; then
_printargs "$@" >&2
else
_printargs "$1" "$HIDDEN_VALUE" >&2
fi
fi
}
_debug2() {
2017-02-19 04:13:18 +00:00
if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_2" ]; then
_log "$@"
2016-09-25 13:58:59 +00:00
fi
2017-02-19 04:42:37 +00:00
if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_2" ]; then
2017-02-19 04:13:18 +00:00
_syslog "$SYSLOG_DEBUG" "$@"
fi
if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_2" ]; then
_bash_debug=$(__debug_bash_helper)
_printargs "${_bash_debug}$@" >&2
fi
}
2017-02-19 05:24:00 +00:00
_secure_debug2() {
if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_2" ]; then
if [ "$OUTPUT_INSECURE" = "1" ]; then
_log "$@"
else
_log "$1" "$HIDDEN_VALUE"
fi
fi
if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_2" ]; then
_syslog "$SYSLOG_DEBUG" "$1" "$HIDDEN_VALUE"
fi
if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_2" ]; then
if [ "$OUTPUT_INSECURE" = "1" ]; then
_printargs "$@" >&2
else
_printargs "$1" "$HIDDEN_VALUE" >&2
fi
fi
}
_debug3() {
2017-02-19 04:13:18 +00:00
if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_3" ]; then
_log "$@"
fi
2017-02-19 04:42:37 +00:00
if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_3" ]; then
2017-02-19 04:13:18 +00:00
_syslog "$SYSLOG_DEBUG" "$@"
2016-09-25 13:58:59 +00:00
fi
2017-02-19 04:13:18 +00:00
if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_3" ]; then
_bash_debug=$(__debug_bash_helper)
_printargs "${_bash_debug}$@" >&2
fi
}
2017-02-19 05:24:00 +00:00
_secure_debug3() {
if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_3" ]; then
if [ "$OUTPUT_INSECURE" = "1" ]; then
_log "$@"
else
_log "$1" "$HIDDEN_VALUE"
fi
fi
if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_3" ]; then
_syslog "$SYSLOG_DEBUG" "$1" "$HIDDEN_VALUE"
fi
if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_3" ]; then
if [ "$OUTPUT_INSECURE" = "1" ]; then
_printargs "$@" >&2
else
_printargs "$1" "$HIDDEN_VALUE" >&2
fi
fi
}
2017-03-08 13:51:25 +00:00
_upper_case() {
# shellcheck disable=SC2018,SC2019
tr '[a-z]' '[A-Z]'
2017-03-08 13:51:25 +00:00
}
_lower_case() {
# shellcheck disable=SC2018,SC2019
tr '[A-Z]' '[a-z]'
2017-03-08 13:51:25 +00:00
}
2016-11-09 11:30:39 +00:00
_startswith() {
2016-04-16 13:52:24 +00:00
_str="$1"
_sub="$2"
echo "$_str" | grep -- "^$_sub" >/dev/null 2>&1
2016-04-16 13:52:24 +00:00
}
2016-11-09 11:30:39 +00:00
_endswith() {
_str="$1"
_sub="$2"
echo "$_str" | grep -- "$_sub\$" >/dev/null 2>&1
}
2016-11-09 11:30:39 +00:00
_contains() {
2016-04-16 13:52:24 +00:00
_str="$1"
_sub="$2"
echo "$_str" | grep -- "$_sub" >/dev/null 2>&1
2016-04-16 13:52:24 +00:00
}
_hasfield() {
_str="$1"
_field="$2"
_sep="$3"
2016-11-09 11:30:39 +00:00
if [ -z "$_field" ]; then
_usage "Usage: str field [sep]"
return 1
fi
2016-11-09 11:30:39 +00:00
if [ -z "$_sep" ]; then
_sep=","
fi
2016-11-09 11:30:39 +00:00
for f in $(echo "$_str" | tr "$_sep" ' '); do
2016-11-09 11:30:39 +00:00
if [ "$f" = "$_field" ]; then
_debug2 "'$_str' contains '$_field'"
return 0 #contains ok
fi
done
_debug2 "'$_str' does not contain '$_field'"
2017-04-17 11:08:34 +00:00
return 1 #not contains
}
# str index [sep]
2016-11-09 11:30:39 +00:00
_getfield() {
_str="$1"
_findex="$2"
_sep="$3"
2016-11-09 11:30:39 +00:00
if [ -z "$_findex" ]; then
_usage "Usage: str field [sep]"
return 1
fi
2016-11-09 11:30:39 +00:00
if [ -z "$_sep" ]; then
_sep=","
fi
2016-11-09 14:28:12 +00:00
_ffi="$_findex"
2016-11-09 11:30:39 +00:00
while [ "$_ffi" -gt "0" ]; do
2016-11-09 14:28:12 +00:00
_fv="$(echo "$_str" | cut -d "$_sep" -f "$_ffi")"
2016-11-09 11:30:39 +00:00
if [ "$_fv" ]; then
printf -- "%s" "$_fv"
return 0
fi
2016-11-09 12:45:57 +00:00
_ffi="$(_math "$_ffi" - 1)"
done
2016-11-09 11:30:39 +00:00
printf -- "%s" "$_str"
}
2016-11-09 11:30:39 +00:00
_exists() {
cmd="$1"
2016-11-09 11:30:39 +00:00
if [ -z "$cmd" ]; then
_usage "Usage: _exists cmd"
return 1
fi
2016-11-17 05:17:29 +00:00
if eval type type >/dev/null 2>&1; then
eval type "$cmd" >/dev/null 2>&1
elif command >/dev/null 2>&1; then
2016-05-13 13:14:00 +00:00
command -v "$cmd" >/dev/null 2>&1
2016-11-17 05:20:20 +00:00
else
2016-11-11 13:13:33 +00:00
which "$cmd" >/dev/null 2>&1
2016-04-16 11:38:11 +00:00
fi
ret="$?"
_debug3 "$cmd exists=$ret"
return $ret
}
2016-04-17 09:33:08 +00:00
#a + b
2016-11-09 11:30:39 +00:00
_math() {
2016-11-12 02:58:20 +00:00
_m_opts="$@"
printf "%s" "$(($_m_opts))"
2016-04-17 09:33:08 +00:00
}
_h_char_2_dec() {
_ch=$1
case "${_ch}" in
2020-08-17 14:18:20 +00:00
a | A)
printf "10"
;;
b | B)
printf "11"
;;
c | C)
printf "12"
;;
d | D)
printf "13"
;;
e | E)
printf "14"
;;
f | F)
printf "15"
;;
*)
printf "%s" "$_ch"
;;
2016-05-13 13:14:00 +00:00
esac
2016-04-17 09:33:08 +00:00
}
2016-08-14 14:37:21 +00:00
_URGLY_PRINTF=""
2016-11-09 11:30:39 +00:00
if [ "$(printf '\x41')" != 'A' ]; then
2016-08-14 14:37:21 +00:00
_URGLY_PRINTF=1
fi
_ESCAPE_XARGS=""
2017-06-23 10:11:11 +00:00
if _exists xargs && [ "$(printf %s '\\x41' | xargs printf)" = 'A' ]; then
_ESCAPE_XARGS=1
fi
2016-03-08 12:44:12 +00:00
_h2b() {
if _exists xxd; then
if _contains "$(xxd --help 2>&1)" "assumes -c30"; then
if xxd -r -p -c 9999 2>/dev/null; then
return
fi
else
if xxd -r -p 2>/dev/null; then
return
fi
fi
2017-05-17 05:16:53 +00:00
fi
2016-03-08 12:44:12 +00:00
hex=$(cat)
2017-05-20 03:02:48 +00:00
ic=""
jc=""
2017-05-17 05:16:53 +00:00
_debug2 _URGLY_PRINTF "$_URGLY_PRINTF"
if [ -z "$_URGLY_PRINTF" ]; then
if [ "$_ESCAPE_XARGS" ] && _exists xargs; then
2017-05-20 03:02:48 +00:00
_debug2 "xargs"
echo "$hex" | _upper_case | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/g' | xargs printf
2017-05-20 03:02:48 +00:00
else
for h in $(echo "$hex" | _upper_case | sed 's/\([0-9A-F]\{2\}\)/ \1/g'); do
2017-05-20 03:02:48 +00:00
if [ -z "$h" ]; then
break
fi
printf "\x$h%s"
done
fi
2017-05-17 05:16:53 +00:00
else
for c in $(echo "$hex" | _upper_case | sed 's/\([0-9A-F]\)/ \1/g'); do
2017-05-20 03:02:48 +00:00
if [ -z "$ic" ]; then
ic=$c
continue
2016-04-17 09:33:08 +00:00
fi
2017-05-20 03:02:48 +00:00
jc=$c
2016-05-13 13:14:00 +00:00
ic="$(_h_char_2_dec "$ic")"
jc="$(_h_char_2_dec "$jc")"
2016-11-11 14:00:15 +00:00
printf '\'"$(printf "%o" "$(_math "$ic" \* 16 + $jc)")""%s"
2017-05-20 03:02:48 +00:00
ic=""
jc=""
2017-05-17 05:16:53 +00:00
done
fi
2016-11-11 13:13:33 +00:00
2016-03-08 12:44:12 +00:00
}
2017-01-30 04:07:50 +00:00
_is_solaris() {
_contains "${__OS__:=$(uname -a)}" "solaris" || _contains "${__OS__:=$(uname -a)}" "SunOS"
}
2017-02-05 05:16:51 +00:00
#_ascii_hex str
#this can only process ascii chars, should only be used when od command is missing as a backup way.
_ascii_hex() {
_debug2 "Using _ascii_hex"
_str="$1"
_str_len=${#_str}
_h_i=1
while [ "$_h_i" -le "$_str_len" ]; do
_str_c="$(printf "%s" "$_str" | cut -c "$_h_i")"
printf " %02x" "'$_str_c"
_h_i="$(_math "$_h_i" + 1)"
done
}
2017-01-30 04:07:50 +00:00
#stdin output hexstr splited by one space
#input:"abc"
#output: " 61 62 63"
_hex_dump() {
if _exists od; then
od -A n -v -t x1 | tr -s " " | sed 's/ $//' | tr -d "\r\t\n"
elif _exists hexdump; then
_debug3 "using hexdump"
hexdump -v -e '/1 ""' -e '/1 " %02x" ""'
elif _exists xxd; then
_debug3 "using xxd"
xxd -ps -c 20 -i | sed "s/ 0x/ /g" | tr -d ",\n" | tr -s " "
else
_debug3 "using _ascii_hex"
2017-02-05 05:16:51 +00:00
str=$(cat)
_ascii_hex "$str"
fi
2017-01-30 04:07:50 +00:00
}
#url encode, no-preserved chars
#A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
#41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a
#a b c d e f g h i j k l m n o p q r s t u v w x y z
#61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a
#0 1 2 3 4 5 6 7 8 9 - _ . ~
#30 31 32 33 34 35 36 37 38 39 2d 5f 2e 7e
#stdin stdout
_url_encode() {
_hex_str=$(_hex_dump)
_debug3 "_url_encode"
_debug3 "_hex_str" "$_hex_str"
for _hex_code in $_hex_str; do
#upper case
case "${_hex_code}" in
2020-08-17 14:18:20 +00:00
"41")
printf "%s" "A"
;;
"42")
printf "%s" "B"
;;
"43")
printf "%s" "C"
;;
"44")
printf "%s" "D"
;;
"45")
printf "%s" "E"
;;
"46")
printf "%s" "F"
;;
"47")
printf "%s" "G"
;;
"48")
printf "%s" "H"
;;
"49")
printf "%s" "I"
;;
"4a")
printf "%s" "J"
;;
"4b")
printf "%s" "K"
;;
"4c")
printf "%s" "L"
;;
"4d")
printf "%s" "M"
;;
"4e")
printf "%s" "N"
;;
"4f")