diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..efdba87 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +* text=auto +*.sh text eol=lf diff --git a/AliyunOpenAPI.sh b/AliyunOpenAPI.sh index fc1f48e..bb55973 100644 --- a/AliyunOpenAPI.sh +++ b/AliyunOpenAPI.sh @@ -8,16 +8,16 @@ done _AliAccessKeyId=$(printenv AliAccessKeyId) _AliAccessKeySecret=$(printenv AliAccessKeySecret) -_Format=JSON -_SignatureMethod=HMAC-SHA1 -_SignatureVersion=1.0 +_ali_format_rpc=JSON +_ali_signature_method=HMAC-SHA1 +_ali_signature_version=1.0 _urlencode_pycode="from sys import stdin;from urllib.parse import quote;print(quote(stdin.read(), '-_.~'))" # aliapi_rpc aliapi_rpc() { [[ $# -lt 6 ]] && return 66 # 公共查询参数键 - local _ali_common_key=( + local _api_common_key=( "Format" "AccessKeyId" "SignatureMethod" @@ -29,20 +29,22 @@ aliapi_rpc() { ) # 公共查询参数值 local _ali_common_value=( - "$_Format" + "$_ali_format_rpc" "$_AliAccessKeyId" - "$_SignatureMethod" - "$(_ali_sign_timestamp)" - "$_SignatureVersion" - "$(_ali_sign_nonce)" + "$_ali_signature_method" + "$(_ali_timestamp_rpc)" + "$_ali_signature_version" + "$(_ali_signature_nonce)" "$3" "$4" ) - local _ali_custom_key=() _ali_custom_value=() # 自定义查询参数键值 + # 自定义查询参数键值 + local _ali_custom_key=() _ali_custom_value=() read -r -a _ali_custom_key <<< "$5" read -r -a _ali_custom_value <<< "$6" - local _ali_key=() _ali_value=() # 合并查询键值 - read -r -a _ali_key <<< "${_ali_common_key[*]} ${_ali_custom_key[*]}" + # 合并查询键值 + local _ali_key=() _ali_value=() + read -r -a _ali_key <<< "${_api_common_key[*]} ${_ali_custom_key[*]}" read -r -a _ali_value <<< "${_ali_common_value[*]} ${_ali_custom_value[*]}" local _http_host=$1 _http_method=$2 local _query_str="" @@ -50,13 +52,14 @@ aliapi_rpc() { for (( i = 0; i < ${#_ali_key[@]}; ++i )); do _key=${_ali_key[$i]} _value=${_ali_value[$i]} - [[ $(grep -E "^.+\(\)$" <<< "$_value") == "$_value" ]] && _value=$(${_value//()/}) # 参数值如果是以 () 结束,代表需要执行命令获取值。 + # 参数值如果是以 () 结束,代表需要执行命令获取值。 + [[ $(grep -E "^.+\(\)$" <<< "$_value") == "$_value" ]] && _value=$(${_value//()/}) _value=$(_urlencode "$_value") _query_str+="$_key=$_value&" done - local _ali_signature - _ali_signature=$(_ali_sign "$_http_method" "$_query_str") - _query_str+="Signature=$(_urlencode "$_ali_signature")" + local _ali_signature_value + _ali_signature_value=$(_ali_signature_rpc "$_http_method" "$_query_str") + _query_str+="Signature=$(_urlencode "$_ali_signature_value")" local _curl_out _result_code _http_url="https://${_http_host}/?${_query_str}" _curl_out=$(mktemp) _result_code=$(curl -L -s -X "$_http_method" -o "$_curl_out" --write-out "%{http_code}" "$_http_url" || echo $?) @@ -65,20 +68,20 @@ aliapi_rpc() { [[ ${_result_code} -eq 200 ]] && return 0 || return 1 } -_ali_sign() { - local _http_method _str _query_str _sign_str - _http_method=$1 +_ali_signature_rpc() { + local _http_method=$1 _str _query_str _sign_str _str=$(echo -n "$2" | tr "&" "\n" | sort) _query_str=$(echo -n "$_str" | tr "\n" "&") _sign_str="${_http_method}&$(_urlencode "/")&$(_urlencode "$_query_str")" echo -n "$_sign_str" | openssl sha1 -hmac "${_AliAccessKeySecret}&" -binary | openssl base64 -e } -_ali_sign_timestamp() { - TZ="UTC" date "+%FT%TZ" +_ali_timestamp_rpc() { + # ISO8601 UTC + date -u +%FT%TZ } -_ali_sign_nonce() { +_ali_signature_nonce() { date "+%s%N" } diff --git a/example/UpdateSSLCert.sh b/example/UpdateSSLCert.sh index c66a0a4..e672b6a 100644 --- a/example/UpdateSSLCert.sh +++ b/example/UpdateSSLCert.sh @@ -1,13 +1,19 @@ #!/usr/bin/env bash -# https://help.aliyun.com/document_detail/126507.html -# https://help.aliyun.com/document_detail/106661.html +# CAS https://help.aliyun.com/document_detail/126507.html +# CDN https://help.aliyun.com/document_detail/106661.html -# 可用于 acme.sh 的 renewHook 脚本,可以自动更新阿里云 SSL 证书并更新对应 CDN 域名,然后删除对应域名旧的证书。 -# 每次 API 的执行都会检测是否失败,如果失败,会中断脚本执行并返回自定义错误代码 +# 可配合 acme.sh 使用的 renewHook 脚本:自动将新证书上传至阿里云并更新对应 CDN 域名,然后删除对应域名的旧证书。 +# 每次 API 执行都会检测是否失败,如果失败,会中断脚本执行并返回自定义错误代码。 -# acme.sh 导出的环境变量 -ENV_NAME=( +# 导出 AliAccessKeyId 和 AliAccessKeySecret +export AliAccessKeyId="" +export AliAccessKeySecret="" +# shellcheck disable=SC1091 +. ../AliyunOpenAPI.sh + +# acme.sh 执行 renewHook 时导出的环境变量列表 +ACME_ENV_LIST=( "CERT_PATH" "CERT_KEY_PATH" "CA_CERT_PATH" @@ -15,81 +21,77 @@ ENV_NAME=( "Le_Domain" ) # 检查环境变量是否存在 -for value in "${ENV_NAME[@]}" ; do +for value in "${ACME_ENV_LIST[@]}" ; do printenv "$value" > /dev/null || exit 1 done # 获取证书自定义函数 get_cert() { - sed -e "/^$/d" "$(printenv CERT_FULLCHAIN_PATH)" # 使用 sed 删除掉证书文件的空行 + # 使用 sed 删除掉证书文件的空行 + sed -e "/^$/d" "$(printenv CERT_FULLCHAIN_PATH)" } # 获取密钥自定义函数 get_key() { cat "$(printenv CERT_KEY_PATH)" } -# 导出 AliAccessKeyId 和 AliAccessKeySecret -export AliAccessKeyId="" -export AliAccessKeySecret="" - DOMAIN=$(printenv Le_Domain) -CERT_NAME="${DOMAIN}-$(date +%s)" # 证书名称 +# 证书名称 +CERT_NAME="${DOMAIN}-$(date +%s)" # 需要更新证书的 CDN 域名列表 DOMAIN_LIST=( "example.example.com" ) -# shellcheck disable=SC1091 -. ../AliyunOpenAPI.sh -ali_custom_name=( +api_custom_key=( "CurrentPage" "ShowSize" ) -# 获取第一页的 50 个结果,如果你的证书列表条目较多,可以考虑增加获取数量。 -ali_custom_value=( +api_custom_value=( "1" "50" ) # 获取证书列表 -result=$(aliapi_rpc "cas.aliyuncs.com" "GET" "2018-07-13" "DescribeUserCertificateList" "${ali_custom_name[*]}" "${ali_custom_value[*]}" || exit 101) +result=$(aliapi_rpc "cas.aliyuncs.com" "GET" "2018-07-13" "DescribeUserCertificateList" "${api_custom_key[*]}" "${api_custom_value[*]}" || exit 101) # 使用 jq 处理返回的 JSON 数据并提取出匹配当前证书域名的证书列表的 ID,用于稍后的删除旧证书操作。 cert_list=$(echo "$result" | jq -cr ".CertificateList|map(select(.common == \"${DOMAIN}\"))|map(.id)|.[]") -ali_custom_name=( + +api_custom_key=( "Cert" "Key" "Name" ) -# 使用自定义函数获取证书和密钥,保证内容可以被安全的传递过去 -ali_custom_value=( +# 使用自定义函数获取证书和密钥,保证内容可以被完整的传递。 +api_custom_value=( "get_cert()" "get_key()" "$CERT_NAME" ) # 上传新的证书 -aliapi_rpc "cas.aliyuncs.com" "GET" "2018-07-13" "CreateUserCertificate" "${ali_custom_name[*]}" "${ali_custom_value[*]}" || exit 102 +aliapi_rpc "cas.aliyuncs.com" "GET" "2018-07-13" "CreateUserCertificate" "${api_custom_key[*]}" "${api_custom_value[*]}" || exit 102 # 设置 CDN 域名列表使用新的证书 for domain in "${DOMAIN_LIST[@]}"; do - ali_custom_name=( + api_custom_key=( "DomainName" "ServerCertificateStatus" "CertName" "CertType" ) - ali_custom_value=( + api_custom_value=( "$domain" "on" "$CERT_NAME" "cas" ) - aliapi_rpc "cdn.aliyuncs.com" "GET" "2018-05-10" "SetDomainServerCertificate" "${ali_custom_name[*]}" "${ali_custom_value[*]}" || _exit 103 "Set cdn domain cert fail: $domain" + aliapi_rpc "cdn.aliyuncs.com" "GET" "2018-05-10" "SetDomainServerCertificate" "${api_custom_key[*]}" "${api_custom_value[*]}" || exit 103 done # 删除旧的证书 for id in ${cert_list}; do - ali_custom_name=( + api_custom_key=( "CertId" ) - ali_custom_value=( + api_custom_value=( "$id" ) - aliapi_rpc "cas.aliyuncs.com" "GET" "2018-07-13" "DeleteUserCertificate" "${ali_custom_name[*]}" "${ali_custom_value[*]}" || _exit 104 "Delete old cert fail: $id" + aliapi_rpc "cas.aliyuncs.com" "GET" "2018-07-13" "DeleteUserCertificate" "${api_custom_key[*]}" "${api_custom_value[*]}" || exit 104 done