mirror of
https://github.com/acmesh-official/acme.sh.git
synced 2025-12-27 06:02:08 +08:00
Compare commits
169 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2068efdb38 | ||
|
|
258ca1b434 | ||
|
|
88bb7b780d | ||
|
|
3805e5d37e | ||
|
|
a2d6daaef4 | ||
|
|
48e9006cd1 | ||
|
|
a25a4b5d11 | ||
|
|
309bec474f | ||
|
|
d36440a06d | ||
|
|
2a2f772412 | ||
|
|
6a524bff9d | ||
|
|
5def1169db | ||
|
|
a07395fb56 | ||
|
|
e25a375f43 | ||
|
|
96801e3478 | ||
|
|
90100aa169 | ||
|
|
415f375ce6 | ||
|
|
50d238b60f | ||
|
|
5c3b41bd93 | ||
|
|
3e0971c159 | ||
|
|
57740fbd18 | ||
|
|
16bc8f7040 | ||
|
|
c145f24621 | ||
|
|
cd3a4573f2 | ||
|
|
8eab77f3c6 | ||
|
|
4af339424a | ||
|
|
4dd69a8b1a | ||
|
|
baa1160594 | ||
|
|
f438ff4bab | ||
|
|
a25b2af66c | ||
|
|
31b67ab92e | ||
|
|
5303b36913 | ||
|
|
a5c56c547d | ||
|
|
ccf9a9976c | ||
|
|
ab1efd923b | ||
|
|
d6780f9e49 | ||
|
|
8534e3b2f7 | ||
|
|
8e6cf669ad | ||
|
|
577380e98e | ||
|
|
235b5b0c15 | ||
|
|
aefed1d1b9 | ||
|
|
d39649f30d | ||
|
|
1546b7e5a9 | ||
|
|
ff74778dea | ||
|
|
29b21b828b | ||
|
|
a6a0495392 | ||
|
|
3281043e27 | ||
|
|
f7299403f7 | ||
|
|
a0d251a336 | ||
|
|
8ca45d3d03 | ||
|
|
d988542afc | ||
|
|
4285d81ca9 | ||
|
|
4286b2917e | ||
|
|
d09b5cb80e | ||
|
|
90fd18bf42 | ||
|
|
cae6c8e5f5 | ||
|
|
473340c53b | ||
|
|
ae302ee600 | ||
|
|
27934ac4ca | ||
|
|
283ef9adb7 | ||
|
|
377fe5ecde | ||
|
|
c848d3ee22 | ||
|
|
eb6be88fac | ||
|
|
fceb728501 | ||
|
|
a0df46258d | ||
|
|
57d1db58db | ||
|
|
d61b687853 | ||
|
|
42ab7a5d72 | ||
|
|
18cb11dcbf | ||
|
|
e9d5407792 | ||
|
|
a09b2c0074 | ||
|
|
a460ac021f | ||
|
|
bdee66fe29 | ||
|
|
84a251c8c7 | ||
|
|
cea763bb11 | ||
|
|
accbda9d2f | ||
|
|
7d64e141e4 | ||
|
|
6a9b4db448 | ||
|
|
e6a95ecd08 | ||
|
|
10cb7585a7 | ||
|
|
a577c7215f | ||
|
|
e5244cf3c0 | ||
|
|
c4d0aec536 | ||
|
|
796647158e | ||
|
|
266e9d0619 | ||
|
|
9ec54ef89b | ||
|
|
256cb90f3c | ||
|
|
8f3a3b293d | ||
|
|
975a7359a2 | ||
|
|
ac7361a55e | ||
|
|
bd41f50ba5 | ||
|
|
a2038ab07e | ||
|
|
6445a7674b | ||
|
|
3bf2e89a1a | ||
|
|
e6a13bf386 | ||
|
|
42b2adc03e | ||
|
|
f2b9af01e8 | ||
|
|
9bd2d92755 | ||
|
|
babe884b7c | ||
|
|
200287254b | ||
|
|
0b797f5964 | ||
|
|
13a8c309f5 | ||
|
|
528d2f29d3 | ||
|
|
0aba5dc8de | ||
|
|
72fcf5ab85 | ||
|
|
dd9df068b0 | ||
|
|
81772fb703 | ||
|
|
6304566603 | ||
|
|
5f8b60a0e5 | ||
|
|
e2accaf70e | ||
|
|
7b32bbfc26 | ||
|
|
6963f3880d | ||
|
|
6c3430b6e5 | ||
|
|
c53f36a777 | ||
|
|
bb4d378733 | ||
|
|
333090a967 | ||
|
|
c8f5646d53 | ||
|
|
3002f6dfd5 | ||
|
|
3f8a50e2ae | ||
|
|
1a504118e5 | ||
|
|
2e602ef6b0 | ||
|
|
d55c3faaeb | ||
|
|
6b185d20c0 | ||
|
|
1bbc33a0cf | ||
|
|
a71eba07a1 | ||
|
|
422dd1fa4f | ||
|
|
c4b2e5829e | ||
|
|
1be222f6ed | ||
|
|
5463f459e6 | ||
|
|
14d7bfdab2 | ||
|
|
ea722da3de | ||
|
|
9aed1e2d17 | ||
|
|
63c6ed3fd0 | ||
|
|
744bfc1982 | ||
|
|
d04434e3ec | ||
|
|
dc3b7b5775 | ||
|
|
17fbfd14db | ||
|
|
d0f5aece5f | ||
|
|
eeda3062e1 | ||
|
|
168d712dec | ||
|
|
e64ad5176e | ||
|
|
0e1469f359 | ||
|
|
7d2b6cfeaf | ||
|
|
8e7d029946 | ||
|
|
9dd62ae0f8 | ||
|
|
e7dff4756f | ||
|
|
fa98d72f3a | ||
|
|
ccf0492890 | ||
|
|
eb0ef6bd3d | ||
|
|
841b762796 | ||
|
|
63fb90806c | ||
|
|
88ada80686 | ||
|
|
7d5ddf5e6a | ||
|
|
8f01919f62 | ||
|
|
98394f99b5 | ||
|
|
cae50e16a7 | ||
|
|
4a2ac7bd2e | ||
|
|
a3bdaa85f2 | ||
|
|
40ef86f475 | ||
|
|
4cee14f3c5 | ||
|
|
48d9a8c180 | ||
|
|
1d384e3192 | ||
|
|
87f3dc4558 | ||
|
|
8afec596aa | ||
|
|
ce59fc6c10 | ||
|
|
cbb74c984f | ||
|
|
287623df58 | ||
|
|
f8c1d97a25 | ||
|
|
2a188905da |
@@ -40,7 +40,7 @@ script:
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then ~/shfmt -l -w -i 2 . ; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then git diff --exit-code && echo "shfmt OK" ; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -V ; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck **/*.sh && echo "shellcheck OK" ; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -e SC2181 **/*.sh && echo "shellcheck OK" ; fi
|
||||
- cd ..
|
||||
- git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi
|
||||
|
||||
@@ -16,7 +16,7 @@ ADD ./ /install_acme.sh/
|
||||
RUN cd /install_acme.sh && ([ -f /install_acme.sh/acme.sh ] && /install_acme.sh/acme.sh --install || curl https://get.acme.sh | sh) && rm -rf /install_acme.sh/
|
||||
|
||||
|
||||
RUN ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh
|
||||
RUN ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh && crontab -l | sed 's#> /dev/null##' | crontab -
|
||||
|
||||
RUN for verb in help \
|
||||
version \
|
||||
@@ -44,15 +44,17 @@ RUN for verb in help \
|
||||
create-domain-key \
|
||||
createCSR \
|
||||
deactivate \
|
||||
deactivate-account \
|
||||
; do \
|
||||
printf -- "%b" "#!/usr/bin/env sh\n/root/.acme.sh/acme.sh --${verb} --config-home /acme.sh \"\$@\"" >/usr/local/bin/--${verb} && chmod +x /usr/local/bin/--${verb} \
|
||||
; done
|
||||
|
||||
RUN printf "%b" '#!'"/usr/bin/env sh\n \
|
||||
if [ \"\$1\" = \"daemon\" ]; then \n \
|
||||
crond -f\n \
|
||||
trap \"echo stop && killall crond && exit 0\" SIGTERM SIGINT \n \
|
||||
crond && while true; do sleep 1; done;\n \
|
||||
else \n \
|
||||
/root/.acme.sh/acme.sh --config-home /acme.sh \"\$@\"\n \
|
||||
exec -- \"\$@\"\n \
|
||||
fi" >/entry.sh && chmod +x /entry.sh
|
||||
|
||||
VOLUME /acme.sh
|
||||
|
||||
@@ -296,6 +296,9 @@ acme.sh --renew -d example.com
|
||||
|
||||
Ok, it's finished.
|
||||
|
||||
**Take care, this is dns manual mode, it can not be renewed automatically. you will have to add a new txt record to your domain by your hand when you renew your cert.**
|
||||
|
||||
**Please use dns api mode instead.**
|
||||
|
||||
# 9. Automatic DNS API integration
|
||||
|
||||
@@ -331,7 +334,11 @@ You don't have to do anything manually!
|
||||
1. Dynu API (https://www.dynu.com)
|
||||
1. DNSimple API
|
||||
1. NS1.com API
|
||||
|
||||
1. DuckDNS.org API
|
||||
1. Name.com API
|
||||
1. Dyn Managed DNS API
|
||||
1. Yandex PDD API (https://pdd.yandex.ru)
|
||||
1. Hurricane Electric DNS service (https://dns.he.net)
|
||||
|
||||
|
||||
And:
|
||||
|
||||
459
acme.sh
459
acme.sh
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
VER=2.7.2
|
||||
VER=2.7.3
|
||||
|
||||
PROJECT_NAME="acme.sh"
|
||||
|
||||
@@ -13,7 +13,8 @@ _SCRIPT_="$0"
|
||||
|
||||
_SUB_FOLDERS="dnsapi deploy"
|
||||
|
||||
DEFAULT_CA="https://acme-v01.api.letsencrypt.org"
|
||||
_OLD_CA_HOST="https://acme-v01.api.letsencrypt.org"
|
||||
DEFAULT_CA="https://acme-v01.api.letsencrypt.org/directory"
|
||||
DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf"
|
||||
|
||||
DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)"
|
||||
@@ -24,7 +25,8 @@ DEFAULT_DOMAIN_KEY_LENGTH=2048
|
||||
|
||||
DEFAULT_OPENSSL_BIN="openssl"
|
||||
|
||||
STAGE_CA="https://acme-staging.api.letsencrypt.org"
|
||||
STAGE_CA="https://acme-staging.api.letsencrypt.org/directory"
|
||||
_OLD_STAGE_CA_HOST="https://acme-staging.api.letsencrypt.org"
|
||||
|
||||
VTYPE_HTTP="http-01"
|
||||
VTYPE_DNS="dns-01"
|
||||
@@ -98,6 +100,10 @@ _PREPARE_LINK="https://github.com/Neilpang/acme.sh/wiki/Install-preparations"
|
||||
|
||||
_STATELESS_WIKI="https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode"
|
||||
|
||||
_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"
|
||||
|
||||
__INTERACTIVE=""
|
||||
if [ -t 1 ]; then
|
||||
__INTERACTIVE="1"
|
||||
@@ -364,6 +370,7 @@ _hasfield() {
|
||||
return 1 #not contains
|
||||
}
|
||||
|
||||
# str index [sep]
|
||||
_getfield() {
|
||||
_str="$1"
|
||||
_findex="$2"
|
||||
@@ -451,7 +458,7 @@ if [ "$(printf '\x41')" != 'A' ]; then
|
||||
fi
|
||||
|
||||
_ESCAPE_XARGS=""
|
||||
if [ "$(printf %s '\\x41' | xargs printf)" = 'A' ]; then
|
||||
if _exists xargs && [ "$(printf %s '\\x41' | xargs printf)" = 'A' ]; then
|
||||
_ESCAPE_XARGS=1
|
||||
fi
|
||||
|
||||
@@ -923,7 +930,7 @@ _sign() {
|
||||
|
||||
}
|
||||
|
||||
#keylength
|
||||
#keylength or isEcc flag (empty str => not ecc)
|
||||
_isEccKey() {
|
||||
_length="$1"
|
||||
|
||||
@@ -1136,7 +1143,12 @@ _readKeyLengthFromCSR() {
|
||||
echo "$_outcsr" | tr "\t" " " | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' '
|
||||
else
|
||||
_debug "RSA CSR"
|
||||
echo "$_outcsr" | tr "\t" " " | (_egrep_o "^ *Public.Key:.*" || _egrep_o "RSA Public.Key:.*") | cut -d '(' -f 2 | cut -d ' ' -f 1
|
||||
_rkl="$(echo "$_outcsr" | tr "\t" " " | _egrep_o "^ *Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1)"
|
||||
if [ "$_rkl" ]; then
|
||||
echo "$_rkl"
|
||||
else
|
||||
echo "$_outcsr" | tr "\t" " " | _egrep_o "RSA Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -1145,7 +1157,7 @@ _ss() {
|
||||
|
||||
if _exists "ss"; then
|
||||
_debug "Using: ss"
|
||||
ss -ntpl | grep ":$_port "
|
||||
ss -ntpl 2>/dev/null | grep ":$_port "
|
||||
return 0
|
||||
fi
|
||||
|
||||
@@ -1174,6 +1186,28 @@ _ss() {
|
||||
return 1
|
||||
}
|
||||
|
||||
#outfile key cert cacert [password [name [caname]]]
|
||||
_toPkcs() {
|
||||
_cpfx="$1"
|
||||
_ckey="$2"
|
||||
_ccert="$3"
|
||||
_cca="$4"
|
||||
pfxPassword="$5"
|
||||
pfxName="$6"
|
||||
pfxCaname="$7"
|
||||
|
||||
if [ "$pfxCaname" ]; then
|
||||
${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" -password "pass:$pfxPassword" -name "$pfxName" -caname "$pfxCaname"
|
||||
elif [ "$pfxName" ]; then
|
||||
${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" -password "pass:$pfxPassword" -name "$pfxName"
|
||||
elif [ "$pfxPassword" ]; then
|
||||
${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" -password "pass:$pfxPassword"
|
||||
else
|
||||
${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca"
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
#domain [password] [isEcc]
|
||||
toPkcs() {
|
||||
domain="$1"
|
||||
@@ -1187,11 +1221,7 @@ toPkcs() {
|
||||
|
||||
_initpath "$domain" "$_isEcc"
|
||||
|
||||
if [ "$pfxPassword" ]; then
|
||||
${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" -password "pass:$pfxPassword"
|
||||
else
|
||||
${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH"
|
||||
fi
|
||||
_toPkcs "$CERT_PFX_PATH" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$pfxPassword"
|
||||
|
||||
if [ "$?" = "0" ]; then
|
||||
_info "Success, Pfx is exported to: $CERT_PFX_PATH"
|
||||
@@ -1274,7 +1304,7 @@ createDomainKey() {
|
||||
|
||||
_initpath "$domain" "$_cdl"
|
||||
|
||||
if [ ! -f "$CERT_KEY_PATH" ] || ([ "$FORCE" ] && ! [ "$IS_RENEW" ]); then
|
||||
if [ ! -f "$CERT_KEY_PATH" ] || ([ "$FORCE" ] && ! [ "$IS_RENEW" ]) || [ "$Le_ForceNewDomainKey" = "1" ]; then
|
||||
if _createkey "$_cdl" "$CERT_KEY_PATH"; then
|
||||
_savedomainconf Le_Keylength "$_cdl"
|
||||
_info "The domain key is here: $(__green $CERT_KEY_PATH)"
|
||||
@@ -1341,6 +1371,10 @@ _time2str() {
|
||||
echo "$_t_s_a"
|
||||
fi
|
||||
|
||||
#Busybox
|
||||
if echo "$1" | awk '{ print strftime("%c", $0); }' 2>/dev/null; then
|
||||
return
|
||||
fi
|
||||
}
|
||||
|
||||
_normalizeJson() {
|
||||
@@ -1714,9 +1748,19 @@ _send_signed_request() {
|
||||
while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do
|
||||
_debug3 _request_retry_times "$_request_retry_times"
|
||||
if [ -z "$_CACHED_NONCE" ]; then
|
||||
_debug2 "Get nonce."
|
||||
nonceurl="$API/directory"
|
||||
_headers="$(_get "$nonceurl" "onlyheader")"
|
||||
_headers=""
|
||||
if [ "$ACME_NEW_NONCE" ]; then
|
||||
_debug2 "Get nonce. ACME_NEW_NONCE" "$ACME_NEW_NONCE"
|
||||
nonceurl="$ACME_NEW_NONCE"
|
||||
if _post "" "$nonceurl" "" "HEAD"; then
|
||||
_headers="$(cat "$HTTP_HEADER")"
|
||||
fi
|
||||
fi
|
||||
if [ -z "$_headers" ]; then
|
||||
_debug2 "Get nonce. ACME_DIRECTORY" "$ACME_DIRECTORY"
|
||||
nonceurl="$ACME_DIRECTORY"
|
||||
_headers="$(_get "$nonceurl" "onlyheader")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "Can not connect to $nonceurl to get nonce."
|
||||
@@ -2169,7 +2213,71 @@ __initHome() {
|
||||
fi
|
||||
}
|
||||
|
||||
#[domain] [keylength]
|
||||
#server
|
||||
_initAPI() {
|
||||
_api_server="${1:-$ACME_DIRECTORY}"
|
||||
_debug "_init api for server: $_api_server"
|
||||
|
||||
if [ "$_api_server" = "$DEFAULT_CA" ]; then
|
||||
#just for performance, hardcode the default entry points
|
||||
export ACME_KEY_CHANGE="https://acme-v01.api.letsencrypt.org/acme/key-change"
|
||||
export ACME_NEW_AUTHZ="https://acme-v01.api.letsencrypt.org/acme/new-authz"
|
||||
export ACME_NEW_ORDER="https://acme-v01.api.letsencrypt.org/acme/new-cert"
|
||||
export ACME_NEW_ORDER_RES="new-cert"
|
||||
export ACME_NEW_ACCOUNT="https://acme-v01.api.letsencrypt.org/acme/new-reg"
|
||||
export ACME_NEW_ACCOUNT_RES="new-reg"
|
||||
export ACME_REVOKE_CERT="https://acme-v01.api.letsencrypt.org/acme/revoke-cert"
|
||||
fi
|
||||
|
||||
if [ -z "$ACME_NEW_ACCOUNT" ]; then
|
||||
response=$(_get "$_api_server")
|
||||
if [ "$?" != "0" ]; then
|
||||
_debug2 "response" "$response"
|
||||
_err "Can not init api."
|
||||
return 1
|
||||
fi
|
||||
_debug2 "response" "$response"
|
||||
|
||||
ACME_KEY_CHANGE=$(echo "$response" | _egrep_o 'key-change" *: *"[^"]*"' | cut -d '"' -f 3)
|
||||
export ACME_KEY_CHANGE
|
||||
|
||||
ACME_NEW_AUTHZ=$(echo "$response" | _egrep_o 'new-authz" *: *"[^"]*"' | cut -d '"' -f 3)
|
||||
export ACME_NEW_AUTHZ
|
||||
|
||||
ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-cert" *: *"[^"]*"' | cut -d '"' -f 3)
|
||||
ACME_NEW_ORDER_RES="new-cert"
|
||||
if [ -z "$ACME_NEW_ORDER" ]; then
|
||||
ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-order" *: *"[^"]*"' | cut -d '"' -f 3)
|
||||
ACME_NEW_ORDER_RES="new-order"
|
||||
fi
|
||||
export ACME_NEW_ORDER
|
||||
export ACME_NEW_ORDER_RES
|
||||
|
||||
ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-reg" *: *"[^"]*"' | cut -d '"' -f 3)
|
||||
ACME_NEW_ACCOUNT_RES="new-reg"
|
||||
if [ -z "$ACME_NEW_ACCOUNT" ]; then
|
||||
ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-account" *: *"[^"]*"' | cut -d '"' -f 3)
|
||||
ACME_NEW_ACCOUNT_RES="new-account"
|
||||
fi
|
||||
export ACME_NEW_ACCOUNT
|
||||
export ACME_NEW_ACCOUNT_RES
|
||||
|
||||
ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revoke-cert" *: *"[^"]*"' | cut -d '"' -f 3)
|
||||
export ACME_REVOKE_CERT
|
||||
|
||||
ACME_NEW_NONCE=$(echo "$response" | _egrep_o 'new-nonce" *: *"[^"]*"' | cut -d '"' -f 3)
|
||||
export ACME_NEW_NONCE
|
||||
|
||||
fi
|
||||
|
||||
_debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE"
|
||||
_debug "ACME_NEW_AUTHZ" "$ACME_NEW_AUTHZ"
|
||||
_debug "ACME_NEW_ORDER" "$ACME_NEW_ORDER"
|
||||
_debug "ACME_NEW_ACCOUNT" "$ACME_NEW_ACCOUNT"
|
||||
_debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT"
|
||||
}
|
||||
|
||||
#[domain] [keylength or isEcc flag]
|
||||
_initpath() {
|
||||
|
||||
__initHome
|
||||
@@ -2189,17 +2297,19 @@ _initpath() {
|
||||
CA_HOME="$DEFAULT_CA_HOME"
|
||||
fi
|
||||
|
||||
if [ -z "$API" ]; then
|
||||
if [ -z "$ACME_DIRECTORY" ]; then
|
||||
if [ -z "$STAGE" ]; then
|
||||
API="$DEFAULT_CA"
|
||||
ACME_DIRECTORY="$DEFAULT_CA"
|
||||
else
|
||||
API="$STAGE_CA"
|
||||
_info "Using stage api:$API"
|
||||
ACME_DIRECTORY="$STAGE_CA"
|
||||
_info "Using stage ACME_DIRECTORY: $ACME_DIRECTORY"
|
||||
fi
|
||||
fi
|
||||
|
||||
_API_HOST="$(echo "$API" | cut -d : -f 2 | tr -d '/')"
|
||||
CA_DIR="$CA_HOME/$_API_HOST"
|
||||
_ACME_SERVER_HOST="$(echo "$ACME_DIRECTORY" | cut -d : -f 2 | tr -s / | cut -d / -f 2)"
|
||||
_debug2 "_ACME_SERVER_HOST" "$_ACME_SERVER_HOST"
|
||||
|
||||
CA_DIR="$CA_HOME/$_ACME_SERVER_HOST"
|
||||
|
||||
_DEFAULT_CA_CONF="$CA_DIR/ca.conf"
|
||||
|
||||
@@ -2924,9 +3034,9 @@ _on_issue_err() {
|
||||
fi
|
||||
|
||||
#trigger the validation to flush the pending authz
|
||||
_debug2 "_chk_vlist" "$_chk_vlist"
|
||||
if [ "$_chk_vlist" ]; then
|
||||
(
|
||||
_debug2 "_chk_vlist" "$_chk_vlist"
|
||||
_debug2 "start to deactivate authz"
|
||||
ventries=$(echo "$_chk_vlist" | tr "$dvsep" ' ')
|
||||
for ventry in $ventries; do
|
||||
@@ -2940,6 +3050,10 @@ _on_issue_err() {
|
||||
)
|
||||
fi
|
||||
|
||||
if [ "$IS_RENEW" = "1" ] && _hasfield "$Le_Webroot" "dns"; then
|
||||
_err "$_DNS_MANUAL_ERR"
|
||||
fi
|
||||
|
||||
if [ "$DEBUG" ] && [ "$DEBUG" -gt "0" ]; then
|
||||
_debug "$(_dlg_versions)"
|
||||
fi
|
||||
@@ -2972,6 +3086,10 @@ _on_issue_success() {
|
||||
fi
|
||||
fi
|
||||
|
||||
if _hasfield "$Le_Webroot" "dns"; then
|
||||
_err "$_DNS_MANUAL_WARN"
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
updateaccount() {
|
||||
@@ -2998,14 +3116,13 @@ _regAccount() {
|
||||
_initpath
|
||||
_reg_length="$1"
|
||||
|
||||
mkdir -p "$CA_DIR"
|
||||
if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then
|
||||
mkdir -p "$CA_DIR"
|
||||
_info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH"
|
||||
mv "$_OLD_ACCOUNT_KEY" "$ACCOUNT_KEY_PATH"
|
||||
fi
|
||||
|
||||
if [ ! -f "$ACCOUNT_JSON_PATH" ] && [ -f "$_OLD_ACCOUNT_JSON" ]; then
|
||||
mkdir -p "$CA_DIR"
|
||||
_info "mv $_OLD_ACCOUNT_JSON to $ACCOUNT_JSON_PATH"
|
||||
mv "$_OLD_ACCOUNT_JSON" "$ACCOUNT_JSON_PATH"
|
||||
fi
|
||||
@@ -3020,9 +3137,9 @@ _regAccount() {
|
||||
if ! _calcjwk "$ACCOUNT_KEY_PATH"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
_initAPI
|
||||
_updateTos=""
|
||||
_reg_res="new-reg"
|
||||
_reg_res="$ACME_NEW_ACCOUNT_RES"
|
||||
while true; do
|
||||
_debug AGREEMENT "$AGREEMENT"
|
||||
|
||||
@@ -3035,7 +3152,7 @@ _regAccount() {
|
||||
if [ -z "$_updateTos" ]; then
|
||||
_info "Registering account"
|
||||
|
||||
if ! _send_signed_request "$API/acme/new-reg" "$regjson"; then
|
||||
if ! _send_signed_request "${ACME_NEW_ACCOUNT}" "$regjson"; then
|
||||
_err "Register account Error: $response"
|
||||
return 1
|
||||
fi
|
||||
@@ -3052,7 +3169,7 @@ _regAccount() {
|
||||
|
||||
_accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")"
|
||||
_debug "_accUri" "$_accUri"
|
||||
|
||||
_savecaconf "ACCOUNT_URL" "$_accUri"
|
||||
_tos="$(echo "$responseHeaders" | grep "^Link:.*rel=\"terms-of-service\"" | _head_n 1 | _egrep_o "<.*>" | tr -d '<>')"
|
||||
_debug "_tos" "$_tos"
|
||||
if [ -z "$_tos" ]; then
|
||||
@@ -3073,11 +3190,14 @@ _regAccount() {
|
||||
return 1
|
||||
fi
|
||||
if [ "$code" = '202' ]; then
|
||||
_info "Update success."
|
||||
_info "Update account tos info success."
|
||||
|
||||
CA_KEY_HASH="$(__calcAccountKeyHash)"
|
||||
_debug "Calc CA_KEY_HASH" "$CA_KEY_HASH"
|
||||
_savecaconf CA_KEY_HASH "$CA_KEY_HASH"
|
||||
elif [ "$code" = '403' ]; then
|
||||
_err "It seems that the account key is already deactivated, please use a new account key."
|
||||
return 1
|
||||
else
|
||||
_err "Update account error."
|
||||
return 1
|
||||
@@ -3090,6 +3210,68 @@ _regAccount() {
|
||||
|
||||
}
|
||||
|
||||
#Implement deactivate account
|
||||
deactivateaccount() {
|
||||
_initpath
|
||||
|
||||
if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then
|
||||
_info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH"
|
||||
mv "$_OLD_ACCOUNT_KEY" "$ACCOUNT_KEY_PATH"
|
||||
fi
|
||||
|
||||
if [ ! -f "$ACCOUNT_JSON_PATH" ] && [ -f "$_OLD_ACCOUNT_JSON" ]; then
|
||||
_info "mv $_OLD_ACCOUNT_JSON to $ACCOUNT_JSON_PATH"
|
||||
mv "$_OLD_ACCOUNT_JSON" "$ACCOUNT_JSON_PATH"
|
||||
fi
|
||||
|
||||
if [ ! -f "$ACCOUNT_KEY_PATH" ]; then
|
||||
_err "Account key is not found at: $ACCOUNT_KEY_PATH"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_accUri=$(_readcaconf "ACCOUNT_URL")
|
||||
_debug _accUri "$_accUri"
|
||||
|
||||
if [ -z "$_accUri" ]; then
|
||||
_err "The account url is empty, please run '--update-account' first to update the account info first,"
|
||||
_err "Then try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _calcjwk "$ACCOUNT_KEY_PATH"; then
|
||||
return 1
|
||||
fi
|
||||
_initAPI
|
||||
|
||||
if _send_signed_request "$_accUri" "{\"resource\": \"reg\", \"status\":\"deactivated\"}" && _contains "$response" '"deactivated"'; then
|
||||
_info "Deactivate account success for $_accUri."
|
||||
_accid=$(echo "$response" | _egrep_o "\"id\" *: *[^,]*," | cut -d : -f 2 | tr -d ' ,')
|
||||
elif [ "$code" = "403" ]; then
|
||||
_info "The account is already deactivated."
|
||||
_accid=$(_getfield "$_accUri" "999" "/")
|
||||
else
|
||||
_err "Deactivate: account failed for $_accUri."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "Account id: $_accid"
|
||||
if [ "$_accid" ]; then
|
||||
_deactivated_account_path="$CA_DIR/deactivated/$_accid"
|
||||
_debug _deactivated_account_path "$_deactivated_account_path"
|
||||
if mkdir -p "$_deactivated_account_path"; then
|
||||
_info "Moving deactivated account info to $_deactivated_account_path/"
|
||||
mv "$CA_CONF" "$_deactivated_account_path/"
|
||||
mv "$ACCOUNT_JSON_PATH" "$_deactivated_account_path/"
|
||||
mv "$ACCOUNT_KEY_PATH" "$_deactivated_account_path/"
|
||||
else
|
||||
_err "Can not create dir: $_deactivated_account_path, try to remove the deactivated account key."
|
||||
rm -f "$CA_CONF"
|
||||
rm -f "$ACCOUNT_JSON_PATH"
|
||||
rm -f "$ACCOUNT_KEY_PATH"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# domain folder file
|
||||
_findHook() {
|
||||
_hookdomain="$1"
|
||||
@@ -3121,12 +3303,12 @@ _findHook() {
|
||||
__get_domain_new_authz() {
|
||||
_gdnd="$1"
|
||||
_info "Getting new-authz for domain" "$_gdnd"
|
||||
|
||||
_initAPI
|
||||
_Max_new_authz_retry_times=5
|
||||
_authz_i=0
|
||||
while [ "$_authz_i" -lt "$_Max_new_authz_retry_times" ]; do
|
||||
_debug "Try new-authz for the $_authz_i time."
|
||||
if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$_gdnd")\"}}"; then
|
||||
if ! _send_signed_request "${ACME_NEW_AUTHZ}" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$_gdnd")\"}}"; then
|
||||
_err "Can not get domain new authz."
|
||||
return 1
|
||||
fi
|
||||
@@ -3204,13 +3386,16 @@ issue() {
|
||||
if [ "$_web_roots" = "dns-cx" ]; then
|
||||
_web_roots="dns_cx"
|
||||
fi
|
||||
_debug "Using api: $API"
|
||||
|
||||
if [ ! "$IS_RENEW" ]; then
|
||||
_initpath "$_main_domain" "$_key_length"
|
||||
mkdir -p "$DOMAIN_PATH"
|
||||
fi
|
||||
|
||||
_debug "Using ACME_DIRECTORY: $ACME_DIRECTORY"
|
||||
|
||||
_initAPI
|
||||
|
||||
if [ -f "$DOMAIN_CONF" ]; then
|
||||
Le_NextRenewTime=$(_readdomainconf Le_NextRenewTime)
|
||||
_debug Le_NextRenewTime "$Le_NextRenewTime"
|
||||
@@ -3244,7 +3429,7 @@ issue() {
|
||||
_cleardomainconf "Le_LocalAddress"
|
||||
fi
|
||||
|
||||
Le_API="$API"
|
||||
Le_API="$ACME_DIRECTORY"
|
||||
_savedomainconf "Le_API" "$Le_API"
|
||||
|
||||
if [ "$_alt_domains" = "$NO_VALUE" ]; then
|
||||
@@ -3277,7 +3462,7 @@ issue() {
|
||||
else
|
||||
_key=$(_readdomainconf Le_Keylength)
|
||||
_debug "Read key length:$_key"
|
||||
if [ ! -f "$CERT_KEY_PATH" ] || [ "$_key_length" != "$_key" ]; then
|
||||
if [ ! -f "$CERT_KEY_PATH" ] || [ "$_key_length" != "$_key" ] || [ "$Le_ForceNewDomainKey" = "1" ]; then
|
||||
if ! createDomainKey "$_main_domain" "$_key_length"; then
|
||||
_err "Create domain key error."
|
||||
_clearup
|
||||
@@ -3392,11 +3577,11 @@ issue() {
|
||||
if [ "$d_api" ]; then
|
||||
_info "Found domain api file: $d_api"
|
||||
else
|
||||
_err "Add the following TXT record:"
|
||||
_err "Domain: '$(__green "$txtdomain")'"
|
||||
_err "TXT value: '$(__green "$txt")'"
|
||||
_err "Please be aware that you prepend _acme-challenge. before your domain"
|
||||
_err "so the resulting subdomain will be: $txtdomain"
|
||||
_info "$(__red "Add the following TXT record:")"
|
||||
_info "$(__red "Domain: '$(__green "$txtdomain")'")"
|
||||
_info "$(__red "TXT value: '$(__green "$txt")'")"
|
||||
_info "$(__red "Please be aware that you prepend _acme-challenge. before your domain")"
|
||||
_info "$(__red "so the resulting subdomain will be: $txtdomain")"
|
||||
continue
|
||||
fi
|
||||
|
||||
@@ -3420,7 +3605,7 @@ issue() {
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_clearup
|
||||
_on_issue_err "$_post_hook"
|
||||
_on_issue_err "$_post_hook" "$vlist"
|
||||
return 1
|
||||
fi
|
||||
dnsadded='1'
|
||||
@@ -3683,7 +3868,7 @@ issue() {
|
||||
_info "Verify finished, start to sign."
|
||||
der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)"
|
||||
|
||||
if ! _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then
|
||||
if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"$ACME_NEW_ORDER_RES\", \"csr\": \"$der\"}" "needbase64"; then
|
||||
_err "Sign failed."
|
||||
_on_issue_err "$_post_hook"
|
||||
return 1
|
||||
@@ -3736,7 +3921,8 @@ issue() {
|
||||
|
||||
Le_LinkIssuer=$(grep -i '^Link' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2 | cut -d ';' -f 1 | tr -d '<>')
|
||||
if ! _contains "$Le_LinkIssuer" ":"; then
|
||||
Le_LinkIssuer="$API$Le_LinkIssuer"
|
||||
_info "$(__red "Relative issuer link found.")"
|
||||
Le_LinkIssuer="$_ACME_SERVER_HOST$Le_LinkIssuer"
|
||||
fi
|
||||
_debug Le_LinkIssuer "$Le_LinkIssuer"
|
||||
_savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer"
|
||||
@@ -3806,6 +3992,12 @@ issue() {
|
||||
_cleardomainconf Le_Listen_V4
|
||||
fi
|
||||
|
||||
if [ "$Le_ForceNewDomainKey" = "1" ]; then
|
||||
_savedomainconf "Le_ForceNewDomainKey" "$Le_ForceNewDomainKey"
|
||||
else
|
||||
_cleardomainconf Le_ForceNewDomainKey
|
||||
fi
|
||||
|
||||
Le_NextRenewTime=$(_math "$Le_CertCreateTime" + "$Le_RenewalDays" \* 24 \* 60 \* 60)
|
||||
|
||||
Le_NextRenewTimeStr=$(_time2str "$Le_NextRenewTime")
|
||||
@@ -3852,7 +4044,15 @@ renew() {
|
||||
. "$DOMAIN_CONF"
|
||||
|
||||
if [ "$Le_API" ]; then
|
||||
API="$Le_API"
|
||||
if [ "$_OLD_CA_HOST" = "$Le_API" ]; then
|
||||
export Le_API="$DEFAULT_CA"
|
||||
_savedomainconf Le_API "$Le_API"
|
||||
fi
|
||||
if [ "$_OLD_STAGE_CA_HOST" = "$Le_API" ]; then
|
||||
export Le_API="$STAGE_CA"
|
||||
_savedomainconf Le_API "$Le_API"
|
||||
fi
|
||||
export ACME_DIRECTORY="$Le_API"
|
||||
#reload ca configs
|
||||
ACCOUNT_KEY_PATH=""
|
||||
ACCOUNT_JSON_PATH=""
|
||||
@@ -3867,6 +4067,11 @@ renew() {
|
||||
return "$RENEW_SKIP"
|
||||
fi
|
||||
|
||||
if [ "$IN_CRON" = "1" ] && [ -z "$Le_CertCreateTime" ]; then
|
||||
_info "Skip invalid cert for: $Le_Domain"
|
||||
return 0
|
||||
fi
|
||||
|
||||
IS_RENEW="1"
|
||||
issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" "$Le_PreHook" "$Le_PostHook" "$Le_RenewHook" "$Le_LocalAddress"
|
||||
res="$?"
|
||||
@@ -4228,15 +4433,19 @@ _installcert() {
|
||||
installcronjob() {
|
||||
_c_home="$1"
|
||||
_initpath
|
||||
if ! _exists "crontab"; then
|
||||
_err "crontab doesn't exist, so, we can not install cron jobs."
|
||||
_CRONTAB="crontab"
|
||||
if ! _exists "$_CRONTAB" && _exists "fcrontab"; then
|
||||
_CRONTAB="fcrontab"
|
||||
fi
|
||||
if ! _exists "$_CRONTAB"; then
|
||||
_err "crontab/fcrontab doesn't exist, so, we can not install cron jobs."
|
||||
_err "All your certs will not be renewed automatically."
|
||||
_err "You must add your own cron job to call '$PROJECT_ENTRY --cron' everyday."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Installing cron job"
|
||||
if ! crontab -l | grep "$PROJECT_ENTRY --cron"; then
|
||||
if ! $_CRONTAB -l | grep "$PROJECT_ENTRY --cron"; then
|
||||
if [ -f "$LE_WORKING_DIR/$PROJECT_ENTRY" ]; then
|
||||
lesh="\"$LE_WORKING_DIR\"/$PROJECT_ENTRY"
|
||||
else
|
||||
@@ -4250,15 +4459,15 @@ installcronjob() {
|
||||
_t=$(_time)
|
||||
random_minute=$(_math $_t % 60)
|
||||
if _exists uname && uname -a | grep SunOS >/dev/null; then
|
||||
crontab -l | {
|
||||
$_CRONTAB -l | {
|
||||
cat
|
||||
echo "$random_minute 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry> /dev/null"
|
||||
} | crontab --
|
||||
} | $_CRONTAB --
|
||||
else
|
||||
crontab -l | {
|
||||
$_CRONTAB -l | {
|
||||
cat
|
||||
echo "$random_minute 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry> /dev/null"
|
||||
} | crontab -
|
||||
} | $_CRONTAB -
|
||||
fi
|
||||
fi
|
||||
if [ "$?" != "0" ]; then
|
||||
@@ -4270,16 +4479,21 @@ installcronjob() {
|
||||
}
|
||||
|
||||
uninstallcronjob() {
|
||||
if ! _exists "crontab"; then
|
||||
_CRONTAB="crontab"
|
||||
if ! _exists "$_CRONTAB" && _exists "fcrontab"; then
|
||||
_CRONTAB="fcrontab"
|
||||
fi
|
||||
|
||||
if ! _exists "$_CRONTAB"; then
|
||||
return
|
||||
fi
|
||||
_info "Removing cron job"
|
||||
cr="$(crontab -l | grep "$PROJECT_ENTRY --cron")"
|
||||
cr="$($_CRONTAB -l | grep "$PROJECT_ENTRY --cron")"
|
||||
if [ "$cr" ]; then
|
||||
if _exists uname && uname -a | grep solaris >/dev/null; then
|
||||
crontab -l | sed "/$PROJECT_ENTRY --cron/d" | crontab --
|
||||
$_CRONTAB -l | sed "/$PROJECT_ENTRY --cron/d" | $_CRONTAB --
|
||||
else
|
||||
crontab -l | sed "/$PROJECT_ENTRY --cron/d" | crontab -
|
||||
$_CRONTAB -l | sed "/$PROJECT_ENTRY --cron/d" | $_CRONTAB -
|
||||
fi
|
||||
LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 9 | tr -d '"')"
|
||||
_info LE_WORKING_DIR "$LE_WORKING_DIR"
|
||||
@@ -4319,8 +4533,10 @@ revoke() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
_initAPI
|
||||
|
||||
data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}"
|
||||
uri="$API/acme/revoke-cert"
|
||||
uri="${ACME_REVOKE_CERT}"
|
||||
|
||||
if [ -f "$CERT_KEY_PATH" ]; then
|
||||
_info "Try domain key first."
|
||||
@@ -4390,26 +4606,51 @@ _deactivate() {
|
||||
_d_type="$2"
|
||||
_initpath
|
||||
|
||||
if ! __get_domain_new_authz "$_d_domain"; then
|
||||
_err "Can not get domain new authz token."
|
||||
return 1
|
||||
fi
|
||||
|
||||
authzUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")"
|
||||
_debug "authzUri" "$authzUri"
|
||||
|
||||
if [ "$code" ] && [ ! "$code" = '201' ]; then
|
||||
_err "new-authz error: $response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
entries="$(echo "$response" | _egrep_o '{ *"type":"[^"]*", *"status": *"valid", *"uri"[^}]*')"
|
||||
if [ -z "$entries" ]; then
|
||||
_info "No valid entries found."
|
||||
if [ -z "$thumbprint" ]; then
|
||||
thumbprint="$(__calc_account_thumbprint)"
|
||||
fi
|
||||
_debug "Trigger validation."
|
||||
vtype="$VTYPE_HTTP"
|
||||
entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')"
|
||||
_debug entry "$entry"
|
||||
if [ -z "$entry" ]; then
|
||||
_err "Error, can not get domain token $d"
|
||||
return 1
|
||||
fi
|
||||
token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')"
|
||||
_debug token "$token"
|
||||
|
||||
uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d : -f 2,3 | tr -d '"')"
|
||||
_debug uri "$uri"
|
||||
|
||||
keyauthorization="$token.$thumbprint"
|
||||
_debug keyauthorization "$keyauthorization"
|
||||
__trigger_validation "$uri" "$keyauthorization"
|
||||
|
||||
fi
|
||||
|
||||
_d_i=0
|
||||
_d_max_retry=9
|
||||
_d_max_retry=$(echo "$entries" | wc -l)
|
||||
while [ "$_d_i" -lt "$_d_max_retry" ]; do
|
||||
_info "Deactivate: $_d_domain"
|
||||
_d_i="$(_math $_d_i + 1)"
|
||||
|
||||
if ! __get_domain_new_authz "$_d_domain"; then
|
||||
_err "Can not get domain new authz token."
|
||||
return 1
|
||||
fi
|
||||
|
||||
authzUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")"
|
||||
_debug "authzUri" "$authzUri"
|
||||
|
||||
if [ ! -z "$code" ] && [ ! "$code" = '201' ]; then
|
||||
_err "new-authz error: $response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
entry="$(printf "%s\n" "$response" | _egrep_o '{"type":"[^"]*","status":"valid","uri"[^}]*')"
|
||||
entry="$(echo "$entries" | sed -n "${_d_i}p")"
|
||||
_debug entry "$entry"
|
||||
|
||||
if [ -z "$entry" ]; then
|
||||
@@ -4431,16 +4672,16 @@ _deactivate() {
|
||||
|
||||
_info "Deactivate: $_vtype"
|
||||
|
||||
if ! _send_signed_request "$authzUri" "{\"resource\": \"authz\", \"status\":\"deactivated\"}"; then
|
||||
if _send_signed_request "$authzUri" "{\"resource\": \"authz\", \"status\":\"deactivated\"}" && _contains "$response" '"deactivated"'; then
|
||||
_info "Deactivate: $_vtype success."
|
||||
else
|
||||
_err "Can not deactivate $_vtype."
|
||||
return 1
|
||||
break
|
||||
fi
|
||||
|
||||
_info "Deactivate: $_vtype success."
|
||||
|
||||
done
|
||||
_debug "$_d_i"
|
||||
if [ "$_d_i" -lt "$_d_max_retry" ]; then
|
||||
if [ "$_d_i" -eq "$_d_max_retry" ]; then
|
||||
_info "Deactivated success!"
|
||||
else
|
||||
_err "Deactivate failed."
|
||||
@@ -4452,6 +4693,7 @@ deactivate() {
|
||||
_d_domain_list="$1"
|
||||
_d_type="$2"
|
||||
_initpath
|
||||
_initAPI
|
||||
_debug _d_domain_list "$_d_domain_list"
|
||||
if [ -z "$(echo $_d_domain_list | cut -d , -f 1)" ]; then
|
||||
_usage "Usage: $PROJECT_ENTRY --deactivate -d domain.com [-d domain.com]"
|
||||
@@ -4499,9 +4741,7 @@ _detect_profile() {
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -z "$DETECTED_PROFILE" ]; then
|
||||
echo "$DETECTED_PROFILE"
|
||||
fi
|
||||
echo "$DETECTED_PROFILE"
|
||||
}
|
||||
|
||||
_initconf() {
|
||||
@@ -4530,7 +4770,7 @@ _precheck() {
|
||||
fi
|
||||
|
||||
if [ -z "$_nocron" ]; then
|
||||
if ! _exists "crontab"; then
|
||||
if ! _exists "crontab" && ! _exists "fcrontab"; then
|
||||
_err "It is recommended to install crontab first. try to install 'cron, crontab, crontabs or vixie-cron'."
|
||||
_err "We need to set cron job to renew the certs automatically."
|
||||
_err "Otherwise, your certs will not be able to be renewed automatically."
|
||||
@@ -4589,6 +4829,8 @@ _installalias() {
|
||||
_setopt "$_envfile" "export LE_WORKING_DIR" "=" "\"$LE_WORKING_DIR\""
|
||||
if [ "$_c_home" ]; then
|
||||
_setopt "$_envfile" "export LE_CONFIG_HOME" "=" "\"$LE_CONFIG_HOME\""
|
||||
else
|
||||
_sed_i "/^export LE_CONFIG_HOME/d" "$_envfile"
|
||||
fi
|
||||
_setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\""
|
||||
|
||||
@@ -4610,6 +4852,8 @@ _installalias() {
|
||||
_setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\""
|
||||
if [ "$_c_home" ]; then
|
||||
_setopt "$_cshfile" "setenv LE_CONFIG_HOME" " " "\"$LE_CONFIG_HOME\""
|
||||
else
|
||||
_sed_i "/^setenv LE_CONFIG_HOME/d" "$_cshfile"
|
||||
fi
|
||||
_setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\""
|
||||
_setopt "$_csh_profile" "source \"$_cshfile\""
|
||||
@@ -4674,20 +4918,24 @@ install() {
|
||||
|
||||
_info "Installing to $LE_WORKING_DIR"
|
||||
|
||||
if ! mkdir -p "$LE_WORKING_DIR"; then
|
||||
_err "Can not create working dir: $LE_WORKING_DIR"
|
||||
return 1
|
||||
if [ ! -d "$LE_WORKING_DIR" ]; then
|
||||
if ! mkdir -p "$LE_WORKING_DIR"; then
|
||||
_err "Can not create working dir: $LE_WORKING_DIR"
|
||||
return 1
|
||||
fi
|
||||
|
||||
chmod 700 "$LE_WORKING_DIR"
|
||||
fi
|
||||
|
||||
chmod 700 "$LE_WORKING_DIR"
|
||||
if [ ! -d "$LE_CONFIG_HOME" ]; then
|
||||
if ! mkdir -p "$LE_CONFIG_HOME"; then
|
||||
_err "Can not create config dir: $LE_CONFIG_HOME"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! mkdir -p "$LE_CONFIG_HOME"; then
|
||||
_err "Can not create config dir: $LE_CONFIG_HOME"
|
||||
return 1
|
||||
chmod 700 "$LE_CONFIG_HOME"
|
||||
fi
|
||||
|
||||
chmod 700 "$LE_CONFIG_HOME"
|
||||
|
||||
cp "$PROJECT_ENTRY" "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/$PROJECT_ENTRY"
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
@@ -4845,6 +5093,7 @@ Commands:
|
||||
--toPkcs8 Convert to pkcs8 format.
|
||||
--update-account Update account info.
|
||||
--register-account Register account key.
|
||||
--deactivate-account Deactivate the account.
|
||||
--create-account-key Create an account private key, professional use.
|
||||
--create-domain-key Create an domain private key, professional use.
|
||||
--createCSR, -ccsr Create CSR , professional use.
|
||||
@@ -4879,6 +5128,7 @@ Parameters:
|
||||
|
||||
--reloadcmd \"service nginx reload\" After issue/renew, it's used to reload the server.
|
||||
|
||||
--server SERVER ACME Directory Resource URI. (default: https://acme-v01.api.letsencrypt.org/directory)
|
||||
--accountconf Specifies a customized account config file.
|
||||
--home Specifies the home dir for $PROJECT_NAME .
|
||||
--cert-home Specifies the home dir to save all the certs, only valid for '--install' command.
|
||||
@@ -4904,6 +5154,7 @@ Parameters:
|
||||
--renew-hook Command to be run once for each successfully renewed certificate.
|
||||
--deploy-hook The hook file to deploy cert
|
||||
--ocsp-must-staple, --ocsp Generate ocsp must Staple extension.
|
||||
--always-force-new-domain-key Generate new domain key when renewal. Otherwise, the domain key is not changed by default.
|
||||
--auto-upgrade [0|1] Valid for '--upgrade' command, indicating whether to upgrade automatically in future.
|
||||
--listen-v4 Force standalone/tls server to listen at ipv4.
|
||||
--listen-v6 Force standalone/tls server to listen at ipv6.
|
||||
@@ -5039,6 +5290,7 @@ _process() {
|
||||
_openssl_bin=""
|
||||
_syslog=""
|
||||
_use_wget=""
|
||||
_server=""
|
||||
while [ ${#} -gt 0 ]; do
|
||||
case "${1}" in
|
||||
|
||||
@@ -5122,6 +5374,9 @@ _process() {
|
||||
--registeraccount | --register-account)
|
||||
_CMD="registeraccount"
|
||||
;;
|
||||
--deactivate-account)
|
||||
_CMD="deactivateaccount"
|
||||
;;
|
||||
--domain | -d)
|
||||
_dvalue="$2"
|
||||
|
||||
@@ -5155,6 +5410,12 @@ _process() {
|
||||
--staging | --test)
|
||||
STAGE="1"
|
||||
;;
|
||||
--server)
|
||||
ACME_DIRECTORY="$2"
|
||||
_server="$ACME_DIRECTORY"
|
||||
export ACME_DIRECTORY
|
||||
shift
|
||||
;;
|
||||
--debug)
|
||||
if [ -z "$2" ] || _startswith "$2" "-"; then
|
||||
DEBUG="$DEBUG_LEVEL_DEFAULT"
|
||||
@@ -5222,7 +5483,7 @@ _process() {
|
||||
;;
|
||||
--dns)
|
||||
wvalue="dns"
|
||||
if ! _startswith "$2" "-"; then
|
||||
if [ "$2" ] && ! _startswith "$2" "-"; then
|
||||
wvalue="$2"
|
||||
shift
|
||||
fi
|
||||
@@ -5377,6 +5638,14 @@ _process() {
|
||||
--ocsp-must-staple | --ocsp)
|
||||
Le_OCSP_Staple="1"
|
||||
;;
|
||||
--always-force-new-domain-key)
|
||||
if [ -z "$2" ] || _startswith "$2" "-"; then
|
||||
Le_ForceNewDomainKey=1
|
||||
else
|
||||
Le_ForceNewDomainKey="$2"
|
||||
shift
|
||||
fi
|
||||
;;
|
||||
--log | --logfile)
|
||||
_log="1"
|
||||
_logfile="$2"
|
||||
@@ -5478,6 +5747,9 @@ _process() {
|
||||
|
||||
if [ "$DEBUG" ]; then
|
||||
version
|
||||
if [ "$_server" ]; then
|
||||
_debug "Using server: $_server"
|
||||
fi
|
||||
fi
|
||||
|
||||
case "${_CMD}" in
|
||||
@@ -5520,6 +5792,9 @@ _process() {
|
||||
updateaccount)
|
||||
updateaccount
|
||||
;;
|
||||
deactivateaccount)
|
||||
deactivateaccount
|
||||
;;
|
||||
list)
|
||||
list "$_listraw"
|
||||
;;
|
||||
|
||||
@@ -80,3 +80,21 @@ acme.sh --deploy -d ftp.example.com --deploy-hook exim4
|
||||
```sh
|
||||
acme.sh --deploy -d ftp.example.com --deploy-hook keychain
|
||||
```
|
||||
|
||||
## 7. Deploy to cpanel host.
|
||||
|
||||
```
|
||||
acme.sh --deploy -d example.com --deploy-hook cpanel_uapi
|
||||
```
|
||||
|
||||
If you are login as root, please specify the username to deploy cert to:
|
||||
|
||||
```sh
|
||||
export DEPLOY_CPANEL_USER=username
|
||||
acme.sh --deploy -d example.com --deploy-hook cpanel_uapi
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#Here is the script to deploy the cert to your cpanel account by the cpanel APIs.
|
||||
|
||||
#returns 0 means success, otherwise error.
|
||||
|
||||
#export DEPLOY_CPANEL_USER=myusername
|
||||
#export DEPLOY_CPANEL_PASSWORD=PASSWORD
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#domain keyfile certfile cafile fullchain
|
||||
cpanel_deploy() {
|
||||
_cdomain="$1"
|
||||
_ckey="$2"
|
||||
_ccert="$3"
|
||||
_cca="$4"
|
||||
_cfullchain="$5"
|
||||
|
||||
_debug _cdomain "$_cdomain"
|
||||
_debug _ckey "$_ckey"
|
||||
_debug _ccert "$_ccert"
|
||||
_debug _cca "$_cca"
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
_err "Not implemented yet"
|
||||
return 1
|
||||
|
||||
}
|
||||
64
deploy/cpanel_uapi.sh
Normal file
64
deploy/cpanel_uapi.sh
Normal file
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env sh
|
||||
# Here is the script to deploy the cert to your cpanel using the cpanel API.
|
||||
# Uses command line uapi. --user option is needed only if run as root.
|
||||
# Returns 0 when success.
|
||||
# Written by Santeri Kannisto <santeri.kannisto@2globalnomads.info>
|
||||
# Public domain, 2017
|
||||
|
||||
#export DEPLOY_CPANEL_USER=myusername
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#domain keyfile certfile cafile fullchain
|
||||
|
||||
cpanel_uapi_deploy() {
|
||||
_cdomain="$1"
|
||||
_ckey="$2"
|
||||
_ccert="$3"
|
||||
_cca="$4"
|
||||
_cfullchain="$5"
|
||||
|
||||
_debug _cdomain "$_cdomain"
|
||||
_debug _ckey "$_ckey"
|
||||
_debug _ccert "$_ccert"
|
||||
_debug _cca "$_cca"
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
if ! _exists uapi; then
|
||||
_err "The command uapi is not found."
|
||||
return 1
|
||||
fi
|
||||
if ! _exists php; then
|
||||
_err "The command php is not found."
|
||||
return 1
|
||||
fi
|
||||
# read cert and key files and urlencode both
|
||||
_certstr=$(cat "$_ccert")
|
||||
_keystr=$(cat "$_ckey")
|
||||
_cert=$(php -r "echo urlencode(\"$_certstr\");")
|
||||
_key=$(php -r "echo urlencode(\"$_keystr\");")
|
||||
|
||||
_debug _cert "$_cert"
|
||||
_debug _key "$_key"
|
||||
|
||||
if [ "$(id -u)" = 0 ]; then
|
||||
if [ -z "$DEPLOY_CPANEL_USER" ]; then
|
||||
_err "It seems that you are root, please define the target user name: export DEPLOY_CPANEL_USER=username"
|
||||
return 1
|
||||
fi
|
||||
_savedomainconf DEPLOY_CPANEL_USER "$DEPLOY_CPANEL_USER"
|
||||
_response=$(uapi --user="$DEPLOY_CPANEL_USER" SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key")
|
||||
else
|
||||
_response=$(uapi SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key")
|
||||
fi
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
_err "Error in deploying certificate:"
|
||||
_err "$_response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug response "$_response"
|
||||
_info "Certificate successfully deployed"
|
||||
return 0
|
||||
}
|
||||
100
deploy/unifi.sh
Normal file
100
deploy/unifi.sh
Normal file
@@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#Here is a script to deploy cert to unifi server.
|
||||
|
||||
#returns 0 means success, otherwise error.
|
||||
|
||||
#DEPLOY_UNIFI_KEYSTORE="/usr/lib/unifi/data/keystore"
|
||||
#DEPLOY_UNIFI_KEYPASS="aircontrolenterprise"
|
||||
#DEPLOY_UNIFI_RELOAD="service unifi restart"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#domain keyfile certfile cafile fullchain
|
||||
unifi_deploy() {
|
||||
_cdomain="$1"
|
||||
_ckey="$2"
|
||||
_ccert="$3"
|
||||
_cca="$4"
|
||||
_cfullchain="$5"
|
||||
|
||||
_debug _cdomain "$_cdomain"
|
||||
_debug _ckey "$_ckey"
|
||||
_debug _ccert "$_ccert"
|
||||
_debug _cca "$_cca"
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
if ! _exists keytool; then
|
||||
_err "keytool not found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
DEFAULT_UNIFI_KEYSTORE="/usr/lib/unifi/data/keystore"
|
||||
_unifi_keystore="${DEPLOY_UNIFI_KEYSTORE:-$DEFAULT_UNIFI_KEYSTORE}"
|
||||
DEFAULT_UNIFI_KEYPASS="aircontrolenterprise"
|
||||
_unifi_keypass="${DEPLOY_UNIFI_KEYPASS:-$DEFAULT_UNIFI_KEYPASS}"
|
||||
DEFAULT_UNIFI_RELOAD="service unifi restart"
|
||||
_reload="${DEPLOY_UNIFI_RELOAD:-$DEFAULT_UNIFI_RELOAD}"
|
||||
|
||||
_debug _unifi_keystore "$_unifi_keystore"
|
||||
if [ ! -f "$_unifi_keystore" ]; then
|
||||
if [ -z "$DEPLOY_UNIFI_KEYSTORE" ]; then
|
||||
_err "unifi keystore is not found, please define DEPLOY_UNIFI_KEYSTORE"
|
||||
return 1
|
||||
else
|
||||
_err "It seems that the specified unifi keystore is not valid, please check."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
if [ ! -w "$_unifi_keystore" ]; then
|
||||
_err "The file $_unifi_keystore is not writable, please change the permission."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Generate import pkcs12"
|
||||
_import_pkcs12="$(_mktemp)"
|
||||
_toPkcs "$_import_pkcs12" "$_ckey" "$_ccert" "$_cca" "$_unifi_keypass" unifi root
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "Oops, error creating import pkcs12, please report bug to us."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Modify unifi keystore: $_unifi_keystore"
|
||||
if keytool -importkeystore \
|
||||
-deststorepass "$_unifi_keypass" -destkeypass "$_unifi_keypass" -destkeystore "$_unifi_keystore" \
|
||||
-srckeystore "$_import_pkcs12" -srcstoretype PKCS12 -srcstorepass "$_unifi_keypass" \
|
||||
-alias unifi -noprompt; then
|
||||
_info "Import keystore success!"
|
||||
rm "$_import_pkcs12"
|
||||
else
|
||||
_err "Import unifi keystore error, please report bug to us."
|
||||
rm "$_import_pkcs12"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Run reload: $_reload"
|
||||
if eval "$_reload"; then
|
||||
_info "Reload success!"
|
||||
if [ "$DEPLOY_UNIFI_KEYSTORE" ]; then
|
||||
_savedomainconf DEPLOY_UNIFI_KEYSTORE "$DEPLOY_UNIFI_KEYSTORE"
|
||||
else
|
||||
_cleardomainconf DEPLOY_UNIFI_KEYSTORE
|
||||
fi
|
||||
if [ "$DEPLOY_UNIFI_KEYPASS" ]; then
|
||||
_savedomainconf DEPLOY_UNIFI_KEYPASS "$DEPLOY_UNIFI_KEYPASS"
|
||||
else
|
||||
_cleardomainconf DEPLOY_UNIFI_KEYPASS
|
||||
fi
|
||||
if [ "$DEPLOY_UNIFI_RELOAD" ]; then
|
||||
_savedomainconf DEPLOY_UNIFI_RELOAD "$DEPLOY_UNIFI_RELOAD"
|
||||
else
|
||||
_cleardomainconf DEPLOY_UNIFI_RELOAD
|
||||
fi
|
||||
return 0
|
||||
else
|
||||
_err "Reload error"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
|
||||
}
|
||||
@@ -505,6 +505,102 @@ Ok, let's issue a cert now:
|
||||
acme.sh --issue --dns dns_nsone -d example.com -d www.example.com
|
||||
```
|
||||
|
||||
## 27. Use DuckDNS.org API
|
||||
|
||||
```
|
||||
export DuckDNS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
|
||||
```
|
||||
|
||||
Please note that since DuckDNS uses StartSSL as their cert provider, thus
|
||||
--insecure may need to be used when issuing certs:
|
||||
```
|
||||
acme.sh --insecure --issue --dns dns_duckdns -d mydomain.duckdns.org
|
||||
```
|
||||
|
||||
For issues, please report to https://github.com/raidenii/acme.sh/issues.
|
||||
|
||||
## 28. Use Name.com API
|
||||
|
||||
You'll need to fill out the form at https://www.name.com/reseller/apply to apply
|
||||
for API username and token.
|
||||
|
||||
```
|
||||
export Namecom_Username="testuser"
|
||||
export Namecom_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||
```
|
||||
|
||||
And now you can issue certs with:
|
||||
|
||||
```
|
||||
acme.sh --issue --dns dns_namecom -d example.com -d www.example.com
|
||||
```
|
||||
|
||||
For issues, please report to https://github.com/raidenii/acme.sh/issues.
|
||||
|
||||
## 29. Use Dyn Managed DNS API to automatically issue cert
|
||||
|
||||
First, login to your Dyn Managed DNS account: https://portal.dynect.net/login/
|
||||
|
||||
It is recommended to add a new user specific for API access.
|
||||
|
||||
The minimum "Zones & Records Permissions" required are:
|
||||
```
|
||||
RecordAdd
|
||||
RecordUpdate
|
||||
RecordDelete
|
||||
RecordGet
|
||||
ZoneGet
|
||||
ZoneAddNode
|
||||
ZoneRemoveNode
|
||||
ZonePublish
|
||||
```
|
||||
|
||||
Pass the API user credentials to the environment:
|
||||
```
|
||||
export DYN_Customer="customer"
|
||||
export DYN_Username="apiuser"
|
||||
export DYN_Password="secret"
|
||||
```
|
||||
|
||||
Ok, let's issue a cert now:
|
||||
```
|
||||
acme.sh --issue --dns dns_dyn -d example.com -d www.example.com
|
||||
```
|
||||
|
||||
The `DYN_Customer`, `DYN_Username` and `DYN_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||
|
||||
## 30. Use pdd.yandex.ru API
|
||||
|
||||
```
|
||||
export PDD_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||
```
|
||||
|
||||
Follow these instructions to get the token for your domain https://tech.yandex.com/domain/doc/concepts/access-docpage/
|
||||
```
|
||||
acme.sh --issue --dns dns_yandex -d mydomain.example.org
|
||||
```
|
||||
|
||||
For issues, please report to https://github.com/non7top/acme.sh/issues.
|
||||
|
||||
## 31. Use Hurricane Electric
|
||||
|
||||
Hurricane Electric doesn't have an API so just set your login credentials like so:
|
||||
|
||||
```
|
||||
export HE_Username="yourusername"
|
||||
export HE_Password="password"
|
||||
```
|
||||
|
||||
Then you can issue your certificate:
|
||||
|
||||
```
|
||||
acme.sh --issue --dns dns_he -d example.com -d www.example.com
|
||||
```
|
||||
|
||||
The `HE_Username` and `HE_Password` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||
|
||||
Please report any issues to https://github.com/angel333/acme.sh or to <me@ondrejsimek.com>.
|
||||
|
||||
# Use custom API
|
||||
|
||||
If your API is not supported yet, you can write your own DNS API.
|
||||
|
||||
@@ -208,7 +208,7 @@ aws_rest() {
|
||||
kServiceH="$(printf "$Service%s" | _hmac "$Hash" "$kRegionH" hex)"
|
||||
_debug2 kServiceH "$kServiceH"
|
||||
|
||||
kSigningH="$(printf "aws4_request%s" | _hmac "$Hash" "$kServiceH" hex)"
|
||||
kSigningH="$(printf "%s" "aws4_request" | _hmac "$Hash" "$kServiceH" hex)"
|
||||
_debug2 kSigningH "$kSigningH"
|
||||
|
||||
signature="$(printf "$StringToSign%s" | _hmac "$Hash" "$kSigningH" hex)"
|
||||
|
||||
128
dnsapi/dns_duckdns.sh
Executable file
128
dnsapi/dns_duckdns.sh
Executable file
@@ -0,0 +1,128 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#Created by RaidenII, to use DuckDNS's API to add/remove text records
|
||||
#06/27/2017
|
||||
|
||||
# Pass credentials before "acme.sh --issue --dns dns_duckdns ..."
|
||||
# --
|
||||
# export DuckDNS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
|
||||
# --
|
||||
#
|
||||
# Due to the fact that DuckDNS uses StartSSL as cert provider, --insecure may need to be used with acme.sh
|
||||
|
||||
DuckDNS_API="https://www.duckdns.org/update"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: dns_duckdns_add _acme-challenge.domain.duckdns.org "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_duckdns_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
DuckDNS_Token="${DuckDNS_Token:-$(_readaccountconf_mutable DuckDNS_Token)}"
|
||||
if [ -z "$DuckDNS_Token" ]; then
|
||||
_err "You must export variable: DuckDNS_Token"
|
||||
_err "The token for your DuckDNS account is necessary."
|
||||
_err "You can look it up in your DuckDNS account."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Now save the credentials.
|
||||
_saveaccountconf_mutable DuckDNS_Token "$DuckDNS_Token"
|
||||
|
||||
# Unfortunately, DuckDNS does not seems to support lookup domain through API
|
||||
# So I assume your credentials (which are your domain and token) are correct
|
||||
# If something goes wrong, we will get a KO response from DuckDNS
|
||||
|
||||
if ! _duckdns_get_domain; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Now add the TXT record to DuckDNS
|
||||
_info "Trying to add TXT record"
|
||||
if _duckdns_rest GET "domains=$_duckdns_domain&token=$DuckDNS_Token&txt=$txtvalue"; then
|
||||
if [ "$response" = "OK" ]; then
|
||||
_info "TXT record has been successfully added to your DuckDNS domain."
|
||||
_info "Note that all subdomains under this domain uses the same TXT record."
|
||||
return 0
|
||||
else
|
||||
_err "Errors happened during adding the TXT record, response=$response"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_err "Errors happened during adding the TXT record."
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
#Usage: fulldomain txtvalue
|
||||
#Remove the txt record after validation.
|
||||
dns_duckdns_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
DuckDNS_Token="${DuckDNS_Token:-$(_readaccountconf_mutable DuckDNS_Token)}"
|
||||
if [ -z "$DuckDNS_Token" ]; then
|
||||
_err "You must export variable: DuckDNS_Token"
|
||||
_err "The token for your DuckDNS account is necessary."
|
||||
_err "You can look it up in your DuckDNS account."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _duckdns_get_domain; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Now remove the TXT record from DuckDNS
|
||||
_info "Trying to remove TXT record"
|
||||
if _duckdns_rest GET "domains=$_duckdns_domain&token=$DuckDNS_Token&txt=&clear=true"; then
|
||||
if [ "$response" = "OK" ]; then
|
||||
_info "TXT record has been successfully removed from your DuckDNS domain."
|
||||
return 0
|
||||
else
|
||||
_err "Errors happened during removing the TXT record, response=$response"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_err "Errors happened during removing the TXT record."
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
#fulldomain=_acme-challenge.domain.duckdns.org
|
||||
#returns
|
||||
# _duckdns_domain=domain
|
||||
_duckdns_get_domain() {
|
||||
|
||||
# We'll extract the domain/username from full domain
|
||||
_duckdns_domain="$(printf "%s" "$fulldomain" | _lower_case | _egrep_o '[.][^.][^.]*[.]duckdns.org' | cut -d . -f 2)"
|
||||
|
||||
if [ -z "$_duckdns_domain" ]; then
|
||||
_err "Error extracting the domain."
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#Usage: method URI
|
||||
_duckdns_rest() {
|
||||
method=$1
|
||||
param="$2"
|
||||
_debug param "$param"
|
||||
url="$DuckDNS_API?$param"
|
||||
_debug url "$url"
|
||||
|
||||
# DuckDNS uses GET to update domain info
|
||||
if [ "$method" = "GET" ]; then
|
||||
response="$(_get "$url")"
|
||||
else
|
||||
_err "Unsupported method"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
339
dnsapi/dns_dyn.sh
Normal file
339
dnsapi/dns_dyn.sh
Normal file
@@ -0,0 +1,339 @@
|
||||
#!/usr/bin/env sh
|
||||
#
|
||||
# Dyn.com Domain API
|
||||
#
|
||||
# Author: Gerd Naschenweng
|
||||
# https://github.com/magicdude4eva
|
||||
#
|
||||
# Dyn Managed DNS API
|
||||
# https://help.dyn.com/dns-api-knowledge-base/
|
||||
#
|
||||
# It is recommended to add a "Dyn Managed DNS" user specific for API access.
|
||||
# The "Zones & Records Permissions" required by this script are:
|
||||
# --
|
||||
# RecordAdd
|
||||
# RecordUpdate
|
||||
# RecordDelete
|
||||
# RecordGet
|
||||
# ZoneGet
|
||||
# ZoneAddNode
|
||||
# ZoneRemoveNode
|
||||
# ZonePublish
|
||||
# --
|
||||
#
|
||||
# Pass credentials before "acme.sh --issue --dns dns_dyn ..."
|
||||
# --
|
||||
# export DYN_Customer="customer"
|
||||
# export DYN_Username="apiuser"
|
||||
# export DYN_Password="secret"
|
||||
# --
|
||||
|
||||
DYN_API="https://api.dynect.net/REST"
|
||||
|
||||
#REST_API
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "Challenge-code"
|
||||
dns_dyn_add() {
|
||||
fulldomain="$1"
|
||||
txtvalue="$2"
|
||||
|
||||
DYN_Customer="${DYN_Customer:-$(_readaccountconf_mutable DYN_Customer)}"
|
||||
DYN_Username="${DYN_Username:-$(_readaccountconf_mutable DYN_Username)}"
|
||||
DYN_Password="${DYN_Password:-$(_readaccountconf_mutable DYN_Password)}"
|
||||
if [ -z "$DYN_Customer" ] || [ -z "$DYN_Username" ] || [ -z "$DYN_Password" ]; then
|
||||
DYN_Customer=""
|
||||
DYN_Username=""
|
||||
DYN_Password=""
|
||||
_err "You must export variables: DYN_Customer, DYN_Username and DYN_Password"
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the config variables to the account conf file.
|
||||
_saveaccountconf_mutable DYN_Customer "$DYN_Customer"
|
||||
_saveaccountconf_mutable DYN_Username "$DYN_Username"
|
||||
_saveaccountconf_mutable DYN_Password "$DYN_Password"
|
||||
|
||||
if ! _dyn_get_authtoken; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$_dyn_authtoken" ]; then
|
||||
_dyn_end_session
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _dyn_get_zone; then
|
||||
_dyn_end_session
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _dyn_add_record; then
|
||||
_dyn_end_session
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _dyn_publish_zone; then
|
||||
_dyn_end_session
|
||||
return 1
|
||||
fi
|
||||
|
||||
_dyn_end_session
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#Usage: fulldomain txtvalue
|
||||
#Remove the txt record after validation.
|
||||
dns_dyn_rm() {
|
||||
fulldomain="$1"
|
||||
txtvalue="$2"
|
||||
|
||||
DYN_Customer="${DYN_Customer:-$(_readaccountconf_mutable DYN_Customer)}"
|
||||
DYN_Username="${DYN_Username:-$(_readaccountconf_mutable DYN_Username)}"
|
||||
DYN_Password="${DYN_Password:-$(_readaccountconf_mutable DYN_Password)}"
|
||||
if [ -z "$DYN_Customer" ] || [ -z "$DYN_Username" ] || [ -z "$DYN_Password" ]; then
|
||||
DYN_Customer=""
|
||||
DYN_Username=""
|
||||
DYN_Password=""
|
||||
_err "You must export variables: DYN_Customer, DYN_Username and DYN_Password"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _dyn_get_authtoken; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$_dyn_authtoken" ]; then
|
||||
_dyn_end_session
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _dyn_get_zone; then
|
||||
_dyn_end_session
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _dyn_get_record_id; then
|
||||
_dyn_end_session
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$_dyn_record_id" ]; then
|
||||
_dyn_end_session
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _dyn_rm_record; then
|
||||
_dyn_end_session
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _dyn_publish_zone; then
|
||||
_dyn_end_session
|
||||
return 1
|
||||
fi
|
||||
|
||||
_dyn_end_session
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
#get Auth-Token
|
||||
_dyn_get_authtoken() {
|
||||
|
||||
_info "Start Dyn API Session"
|
||||
|
||||
data="{\"customer_name\":\"$DYN_Customer\", \"user_name\":\"$DYN_Username\", \"password\":\"$DYN_Password\"}"
|
||||
dyn_url="$DYN_API/Session/"
|
||||
method="POST"
|
||||
|
||||
_debug data "$data"
|
||||
_debug dyn_url "$dyn_url"
|
||||
|
||||
export _H1="Content-Type: application/json"
|
||||
|
||||
response="$(_post "$data" "$dyn_url" "" "$method")"
|
||||
sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')"
|
||||
|
||||
_debug response "$response"
|
||||
_debug sessionstatus "$sessionstatus"
|
||||
|
||||
if [ "$sessionstatus" = "success" ]; then
|
||||
_dyn_authtoken="$(printf "%s\n" "$response" | _egrep_o '"token" *: *"[^"]*' | _head_n 1 | sed 's#^"token" *: *"##')"
|
||||
_info "Token received"
|
||||
_debug _dyn_authtoken "$_dyn_authtoken"
|
||||
return 0
|
||||
fi
|
||||
|
||||
_dyn_authtoken=""
|
||||
_err "get token failed"
|
||||
return 1
|
||||
}
|
||||
|
||||
#fulldomain=_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _dyn_zone=domain.com
|
||||
_dyn_get_zone() {
|
||||
i=2
|
||||
while true; do
|
||||
domain="$(printf "%s" "$fulldomain" | cut -d . -f "$i-100")"
|
||||
if [ -z "$domain" ]; then
|
||||
break
|
||||
fi
|
||||
|
||||
dyn_url="$DYN_API/Zone/$domain/"
|
||||
|
||||
export _H1="Auth-Token: $_dyn_authtoken"
|
||||
export _H2="Content-Type: application/json"
|
||||
|
||||
response="$(_get "$dyn_url" "" "")"
|
||||
sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')"
|
||||
|
||||
_debug dyn_url "$dyn_url"
|
||||
_debug response "$response"
|
||||
_debug sessionstatus "$sessionstatus"
|
||||
|
||||
if [ "$sessionstatus" = "success" ]; then
|
||||
_dyn_zone="$domain"
|
||||
return 0
|
||||
fi
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
|
||||
_dyn_zone=""
|
||||
_err "get zone failed"
|
||||
return 1
|
||||
}
|
||||
|
||||
#add TXT record
|
||||
_dyn_add_record() {
|
||||
|
||||
_info "Adding TXT record"
|
||||
|
||||
data="{\"rdata\":{\"txtdata\":\"$txtvalue\"},\"ttl\":\"300\"}"
|
||||
dyn_url="$DYN_API/TXTRecord/$_dyn_zone/$fulldomain/"
|
||||
method="POST"
|
||||
|
||||
export _H1="Auth-Token: $_dyn_authtoken"
|
||||
export _H2="Content-Type: application/json"
|
||||
|
||||
response="$(_post "$data" "$dyn_url" "" "$method")"
|
||||
sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')"
|
||||
|
||||
_debug response "$response"
|
||||
_debug sessionstatus "$sessionstatus"
|
||||
|
||||
if [ "$sessionstatus" = "success" ]; then
|
||||
_info "TXT Record successfully added"
|
||||
return 0
|
||||
fi
|
||||
|
||||
_err "add TXT record failed"
|
||||
return 1
|
||||
}
|
||||
|
||||
#publish the zone
|
||||
_dyn_publish_zone() {
|
||||
|
||||
_info "Publishing zone"
|
||||
|
||||
data="{\"publish\":\"true\"}"
|
||||
dyn_url="$DYN_API/Zone/$_dyn_zone/"
|
||||
method="PUT"
|
||||
|
||||
export _H1="Auth-Token: $_dyn_authtoken"
|
||||
export _H2="Content-Type: application/json"
|
||||
|
||||
response="$(_post "$data" "$dyn_url" "" "$method")"
|
||||
sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')"
|
||||
|
||||
_debug response "$response"
|
||||
_debug sessionstatus "$sessionstatus"
|
||||
|
||||
if [ "$sessionstatus" = "success" ]; then
|
||||
_info "Zone published"
|
||||
return 0
|
||||
fi
|
||||
|
||||
_err "publish zone failed"
|
||||
return 1
|
||||
}
|
||||
|
||||
#get record_id of TXT record so we can delete the record
|
||||
_dyn_get_record_id() {
|
||||
|
||||
_info "Getting record_id of TXT record"
|
||||
|
||||
dyn_url="$DYN_API/TXTRecord/$_dyn_zone/$fulldomain/"
|
||||
|
||||
export _H1="Auth-Token: $_dyn_authtoken"
|
||||
export _H2="Content-Type: application/json"
|
||||
|
||||
response="$(_get "$dyn_url" "" "")"
|
||||
sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')"
|
||||
|
||||
_debug response "$response"
|
||||
_debug sessionstatus "$sessionstatus"
|
||||
|
||||
if [ "$sessionstatus" = "success" ]; then
|
||||
_dyn_record_id="$(printf "%s\n" "$response" | _egrep_o "\"data\" *: *\[\"/REST/TXTRecord/$_dyn_zone/$fulldomain/[^\"]*" | _head_n 1 | sed "s#^\"data\" *: *\[\"/REST/TXTRecord/$_dyn_zone/$fulldomain/##")"
|
||||
_debug _dyn_record_id "$_dyn_record_id"
|
||||
return 0
|
||||
fi
|
||||
|
||||
_dyn_record_id=""
|
||||
_err "getting record_id failed"
|
||||
return 1
|
||||
}
|
||||
|
||||
#delete TXT record
|
||||
_dyn_rm_record() {
|
||||
|
||||
_info "Deleting TXT record"
|
||||
|
||||
dyn_url="$DYN_API/TXTRecord/$_dyn_zone/$fulldomain/$_dyn_record_id/"
|
||||
method="DELETE"
|
||||
|
||||
_debug dyn_url "$dyn_url"
|
||||
|
||||
export _H1="Auth-Token: $_dyn_authtoken"
|
||||
export _H2="Content-Type: application/json"
|
||||
|
||||
response="$(_post "" "$dyn_url" "" "$method")"
|
||||
sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')"
|
||||
|
||||
_debug response "$response"
|
||||
_debug sessionstatus "$sessionstatus"
|
||||
|
||||
if [ "$sessionstatus" = "success" ]; then
|
||||
_info "TXT record successfully deleted"
|
||||
return 0
|
||||
fi
|
||||
|
||||
_err "delete TXT record failed"
|
||||
return 1
|
||||
}
|
||||
|
||||
#logout
|
||||
_dyn_end_session() {
|
||||
|
||||
_info "End Dyn API Session"
|
||||
|
||||
dyn_url="$DYN_API/Session/"
|
||||
method="DELETE"
|
||||
|
||||
_debug dyn_url "$dyn_url"
|
||||
|
||||
export _H1="Auth-Token: $_dyn_authtoken"
|
||||
export _H2="Content-Type: application/json"
|
||||
|
||||
response="$(_post "" "$dyn_url" "" "$method")"
|
||||
|
||||
_debug response "$response"
|
||||
|
||||
_dyn_authtoken=""
|
||||
return 0
|
||||
}
|
||||
175
dnsapi/dns_he.sh
Executable file
175
dnsapi/dns_he.sh
Executable file
@@ -0,0 +1,175 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
########################################################################
|
||||
# Hurricane Electric hook script for acme.sh
|
||||
#
|
||||
# Environment variables:
|
||||
#
|
||||
# - $HE_Username (your dns.he.net username)
|
||||
# - $HE_Password (your dns.he.net password)
|
||||
#
|
||||
# Author: Ondrej Simek <me@ondrejsimek.com>
|
||||
# Git repo: https://github.com/angel333/acme.sh
|
||||
|
||||
#-- dns_he_add() - Add TXT record --------------------------------------
|
||||
# Usage: dns_he_add _acme-challenge.subdomain.domain.com "XyZ123..."
|
||||
|
||||
dns_he_add() {
|
||||
_full_domain=$1
|
||||
_txt_value=$2
|
||||
_info "Using DNS-01 Hurricane Electric hook"
|
||||
|
||||
if [ -z "$HE_Username" ] || [ -z "$HE_Password" ]; then
|
||||
HE_Username=
|
||||
HE_Password=
|
||||
_err "No auth details provided. Please set user credentials using the \$HE_Username and \$HE_Password envoronment variables."
|
||||
return 1
|
||||
fi
|
||||
_saveaccountconf HE_Username "$HE_Username"
|
||||
_saveaccountconf HE_Password "$HE_Password"
|
||||
|
||||
# Fills in the $_zone_id
|
||||
_find_zone "$_full_domain" || return 1
|
||||
_debug "Zone id \"$_zone_id\" will be used."
|
||||
|
||||
body="email=${HE_Username}&pass=${HE_Password}"
|
||||
body="$body&account="
|
||||
body="$body&menu=edit_zone"
|
||||
body="$body&Type=TXT"
|
||||
body="$body&hosted_dns_zoneid=$_zone_id"
|
||||
body="$body&hosted_dns_recordid="
|
||||
body="$body&hosted_dns_editzone=1"
|
||||
body="$body&Priority="
|
||||
body="$body&Name=$_full_domain"
|
||||
body="$body&Content=$_txt_value"
|
||||
body="$body&TTL=300"
|
||||
body="$body&hosted_dns_editrecord=Submit"
|
||||
response="$(_post "$body" "https://dns.he.net/")"
|
||||
exit_code="$?"
|
||||
if [ "$exit_code" -eq 0 ]; then
|
||||
_info "TXT record added successfully."
|
||||
else
|
||||
_err "Couldn't add the TXT record."
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return "$exit_code"
|
||||
}
|
||||
|
||||
#-- dns_he_rm() - Remove TXT record ------------------------------------
|
||||
# Usage: dns_he_rm _acme-challenge.subdomain.domain.com "XyZ123..."
|
||||
|
||||
dns_he_rm() {
|
||||
_full_domain=$1
|
||||
_txt_value=$2
|
||||
_info "Cleaning up after DNS-01 Hurricane Electric hook"
|
||||
|
||||
# fills in the $_zone_id
|
||||
_find_zone "$_full_domain" || return 1
|
||||
_debug "Zone id \"$_zone_id\" will be used."
|
||||
|
||||
# Find the record id to clean
|
||||
body="email=${HE_Username}&pass=${HE_Password}"
|
||||
body="$body&hosted_dns_zoneid=$_zone_id"
|
||||
body="$body&menu=edit_zone"
|
||||
body="$body&hosted_dns_editzone="
|
||||
domain_regex="$(echo "$_full_domain" | sed 's/\./\\./g')" # escape dots
|
||||
_record_id=$(_post "$body" "https://dns.he.net/" \
|
||||
| tr -d '\n' \
|
||||
| _egrep_o "data=\""${_txt_value}"([^>]+>){6}[^<]+<[^;]+;deleteRecord\('[0-9]+','${domain_regex}','TXT'\)" \
|
||||
| _egrep_o "[0-9]+','${domain_regex}','TXT'\)$" \
|
||||
| _egrep_o "^[0-9]+"
|
||||
)
|
||||
# The series of egreps above could have been done a bit shorter but
|
||||
# I wanted to double-check whether it's the correct record (in case
|
||||
# HE changes their website somehow).
|
||||
|
||||
# Remove the record
|
||||
body="email=${HE_Username}&pass=${HE_Password}"
|
||||
body="$body&menu=edit_zone"
|
||||
body="$body&hosted_dns_zoneid=$_zone_id"
|
||||
body="$body&hosted_dns_recordid=$_record_id"
|
||||
body="$body&hosted_dns_editzone=1"
|
||||
body="$body&hosted_dns_delrecord=1"
|
||||
body="$body&hosted_dns_delconfirm=delete"
|
||||
_post "$body" "https://dns.he.net/" \
|
||||
| grep '<div id="dns_status" onClick="hideThis(this);">Successfully removed record.</div>' \
|
||||
>/dev/null
|
||||
exit_code="$?"
|
||||
if [ "$exit_code" -eq 0 ]; then
|
||||
_info "Record removed successfully."
|
||||
else
|
||||
_err "Could not clean (remove) up the record. Please go to HE administration interface and clean it by hand."
|
||||
return "$exit_code"
|
||||
fi
|
||||
}
|
||||
|
||||
########################## PRIVATE FUNCTIONS ###########################
|
||||
|
||||
#-- _find_zone() -------------------------------------------------------
|
||||
# Returns the most specific zone found in administration interface.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# _find_zone first.second.third.co.uk
|
||||
#
|
||||
# ... will return the first zone that exists in admin out of these:
|
||||
# - "first.second.third.co.uk"
|
||||
# - "second.third.co.uk"
|
||||
# - "third.co.uk"
|
||||
# - "co.uk" <-- unlikely
|
||||
# - "uk" <-'
|
||||
#
|
||||
# (another approach would be something like this:
|
||||
# https://github.com/hlandau/acme/blob/master/_doc/dns.hook
|
||||
# - that's better if there are multiple pages. It's so much simpler.
|
||||
# )
|
||||
|
||||
_find_zone() {
|
||||
|
||||
_domain="$1"
|
||||
|
||||
body="email=${HE_Username}&pass=${HE_Password}"
|
||||
_matches=$(_post "$body" "https://dns.he.net/" \
|
||||
| _egrep_o "delete_dom.*name=\"[^\"]+\" value=\"[0-9]+"
|
||||
)
|
||||
# Zone names and zone IDs are in same order
|
||||
_zone_ids=$(echo "$_matches" | cut -d '"' -f 5)
|
||||
_zone_names=$(echo "$_matches" | cut -d '"' -f 3)
|
||||
_debug2 "These are the zones on this HE account:"
|
||||
_debug2 "$_zone_names"
|
||||
_debug2 "And these are their respective IDs:"
|
||||
_debug2 "$_zone_ids"
|
||||
|
||||
# Walk through all possible zone names
|
||||
_strip_counter=1
|
||||
while true; do
|
||||
_attempted_zone=$(echo "$_domain" | cut -d . -f ${_strip_counter}-)
|
||||
|
||||
# All possible zone names have been tried
|
||||
if [ -z "$_attempted_zone" ]; then
|
||||
_err "No zone for domain \"$_domain\" found."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "Looking for zone \"${_attempted_zone}\""
|
||||
|
||||
# Take care of "." and only match whole lines. Note that grep -F
|
||||
# cannot be used because there's no way to make it match whole
|
||||
# lines.
|
||||
regex="^$(echo "$_attempted_zone" | sed 's/\./\\./g')$"
|
||||
line_num=$(echo "$_zone_names" \
|
||||
| grep -n "$regex" \
|
||||
| cut -d : -f 1
|
||||
)
|
||||
|
||||
if [ -n "$line_num" ]; then
|
||||
_zone_id=$(echo "$_zone_ids" | sed "${line_num}q;d")
|
||||
_debug "Found relevant zone \"$_attempted_zone\" with id \"$_zone_id\" - will be used for domain \"$_domain\"."
|
||||
return 0
|
||||
fi
|
||||
|
||||
_debug "Zone \"$_attempted_zone\" doesn't exist, let's try a less specific zone."
|
||||
_strip_counter=$(_math "$_strip_counter" + 1)
|
||||
done
|
||||
}
|
||||
# vim: et:ts=2:sw=2:
|
||||
@@ -41,10 +41,10 @@ dns_infoblox_add() {
|
||||
export _H2="Authorization: Basic $Infoblox_CredsEncoded"
|
||||
|
||||
## Add the challenge record to the Infoblox grid member
|
||||
result=$(_post "" "$baseurlnObject" "" "POST")
|
||||
result="$(_post "" "$baseurlnObject" "" "POST")"
|
||||
|
||||
## Let's see if we get something intelligible back from the unit
|
||||
if echo "$result" | egrep "record:txt/.*:.*/$Infoblox_View"; then
|
||||
if [ "$(echo "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then
|
||||
_info "Successfully created the txt record"
|
||||
return 0
|
||||
else
|
||||
@@ -66,7 +66,7 @@ dns_infoblox_rm() {
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
## Base64 encode the credentials
|
||||
Infoblox_CredsEncoded=$(printf "%b" "$Infoblox_Creds" | _base64)
|
||||
Infoblox_CredsEncoded="$(printf "%b" "$Infoblox_Creds" | _base64)"
|
||||
|
||||
## Construct the HTTP Authorization header
|
||||
export _H1="Accept-Language:en-US"
|
||||
@@ -74,17 +74,17 @@ dns_infoblox_rm() {
|
||||
|
||||
## Does the record exist? Let's check.
|
||||
baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&view=$Infoblox_View&_return_type=xml-pretty"
|
||||
result=$(_get "$baseurlnObject")
|
||||
result="$(_get "$baseurlnObject")"
|
||||
|
||||
## Let's see if we get something intelligible back from the grid
|
||||
if echo "$result" | egrep "record:txt/.*:.*/$Infoblox_View"; then
|
||||
if [ "$(echo "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then
|
||||
## Extract the object reference
|
||||
objRef=$(printf "%b" "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")
|
||||
objRef="$(printf "%b" "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")"
|
||||
objRmUrl="https://$Infoblox_Server/wapi/v2.2.2/$objRef"
|
||||
## Delete them! All the stale records!
|
||||
rmResult=$(_post "" "$objRmUrl" "" "DELETE")
|
||||
rmResult="$(_post "" "$objRmUrl" "" "DELETE")"
|
||||
## Let's see if that worked
|
||||
if echo "$rmResult" | egrep "record:txt/.*:.*/$Infoblox_View"; then
|
||||
if [ "$(echo "$rmResult" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then
|
||||
_info "Successfully deleted $objRef"
|
||||
return 0
|
||||
else
|
||||
|
||||
@@ -68,7 +68,7 @@ dns_linode_rm() {
|
||||
_parameters="&DomainID=$_domain_id"
|
||||
|
||||
if _rest GET "domain.resource.list" "$_parameters" && [ -n "$response" ]; then
|
||||
response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')"
|
||||
response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")"
|
||||
|
||||
resource="$(echo "$response" | _egrep_o "{.*\"NAME\":\s*\"$_sub_domain\".*}")"
|
||||
if [ "$resource" ]; then
|
||||
@@ -128,7 +128,7 @@ _get_root() {
|
||||
p=1
|
||||
|
||||
if _rest GET "domain.list"; then
|
||||
response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')"
|
||||
response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")"
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug h "$h"
|
||||
|
||||
193
dnsapi/dns_namecom.sh
Executable file
193
dnsapi/dns_namecom.sh
Executable file
@@ -0,0 +1,193 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#Author: RaidneII
|
||||
#Created 06/28/2017
|
||||
#Utilize name.com API to finish dns-01 verifications.
|
||||
######## Public functions #####################
|
||||
|
||||
Namecom_API="https://api.name.com/api"
|
||||
|
||||
#Usage: dns_namecom_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_namecom_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
# First we need name.com credentials.
|
||||
if [ -z "$Namecom_Username" ]; then
|
||||
Namecom_Username=""
|
||||
_err "Username for name.com is missing."
|
||||
_err "Please specify that in your environment variable."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$Namecom_Token" ]; then
|
||||
Namecom_Token=""
|
||||
_err "API token for name.com is missing."
|
||||
_err "Please specify that in your environment variable."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Save them in configuration.
|
||||
_saveaccountconf Namecom_Username "$Namecom_Username"
|
||||
_saveaccountconf Namecom_Token "$Namecom_Token"
|
||||
|
||||
# Login in using API
|
||||
if ! _namecom_login; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Find domain in domain list.
|
||||
if ! _namecom_get_root "$fulldomain"; then
|
||||
_err "Unable to find domain specified."
|
||||
_namecom_logout
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Add TXT record.
|
||||
_namecom_addtxt_json="{\"hostname\":\"$_sub_domain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"ttl\":\"300\",\"priority\":\"10\"}"
|
||||
if _namecom_rest POST "dns/create/$_domain" "$_namecom_addtxt_json"; then
|
||||
retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100")
|
||||
if [ "$retcode" ]; then
|
||||
_info "Successfully added TXT record, ready for validation."
|
||||
_namecom_logout
|
||||
return 0
|
||||
else
|
||||
_err "Unable to add the DNS record."
|
||||
_namecom_logout
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
#Usage: fulldomain txtvalue
|
||||
#Remove the txt record after validation.
|
||||
dns_namecom_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
if ! _namecom_login; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Find domain in domain list.
|
||||
if ! _namecom_get_root "$fulldomain"; then
|
||||
_err "Unable to find domain specified."
|
||||
_namecom_logout
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Get the record id.
|
||||
if _namecom_rest GET "dns/list/$_domain"; then
|
||||
retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100")
|
||||
if [ "$retcode" ]; then
|
||||
_record_id=$(printf "%s\n" "$response" | _egrep_o "\"record_id\":\"[0-9]+\",\"name\":\"$fulldomain\",\"type\":\"TXT\"" | cut -d \" -f 4)
|
||||
_debug record_id "$_record_id"
|
||||
_info "Successfully retrieved the record id for ACME challenge."
|
||||
else
|
||||
_err "Unable to retrieve the record id."
|
||||
_namecom_logout
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Remove the DNS record using record id.
|
||||
_namecom_rmtxt_json="{\"record_id\":\"$_record_id\"}"
|
||||
if _namecom_rest POST "dns/delete/$_domain" "$_namecom_rmtxt_json"; then
|
||||
retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100")
|
||||
if [ "$retcode" ]; then
|
||||
_info "Successfully removed the TXT record."
|
||||
_namecom_logout
|
||||
return 0
|
||||
else
|
||||
_err "Unable to remove the DNS record."
|
||||
_namecom_logout
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
_namecom_rest() {
|
||||
method=$1
|
||||
param=$2
|
||||
data=$3
|
||||
|
||||
export _H1="Content-Type: application/json"
|
||||
export _H2="Api-Session-Token: $sessionkey"
|
||||
if [ "$method" != "GET" ]; then
|
||||
response="$(_post "$data" "$Namecom_API/$param" "" "$method")"
|
||||
else
|
||||
response="$(_get "$Namecom_API/$param")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $param"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
|
||||
_namecom_login() {
|
||||
namecom_login_json="{\"username\":\"$Namecom_Username\",\"api_token\":\"$Namecom_Token\"}"
|
||||
|
||||
if _namecom_rest POST "login" "$namecom_login_json"; then
|
||||
retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100")
|
||||
if [ "$retcode" ]; then
|
||||
_info "Successfully logged in. Fetching session token..."
|
||||
sessionkey=$(printf "%s\n" "$response" | _egrep_o "\"session_token\":\".+" | cut -d \" -f 4)
|
||||
if [ ! -z "$sessionkey" ]; then
|
||||
_debug sessionkey "$sessionkey"
|
||||
_info "Session key obtained."
|
||||
else
|
||||
_err "Unable to get session key."
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_err "Logging in failed."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
_namecom_logout() {
|
||||
if _namecom_rest GET "logout"; then
|
||||
retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100")
|
||||
if [ "$retcode" ]; then
|
||||
_info "Successfully logged out."
|
||||
else
|
||||
_err "Error logging out."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
_namecom_get_root() {
|
||||
domain=$1
|
||||
i=2
|
||||
p=1
|
||||
|
||||
if ! _namecom_rest GET "domain/list"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Need to exclude the last field (tld)
|
||||
numfields=$(echo "$domain" | _egrep_o "\." | wc -l)
|
||||
while [ $i -le "$numfields" ]; do
|
||||
host=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug host "$host"
|
||||
if [ -z "$host" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "$host"; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain="$host"
|
||||
return 0
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
107
dnsapi/dns_yandex.sh
Executable file
107
dnsapi/dns_yandex.sh
Executable file
@@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env sh
|
||||
# Author: non7top@gmail.com
|
||||
# 07 Jul 2017
|
||||
# report bugs at https://github.com/non7top/acme.sh
|
||||
|
||||
# Values to export:
|
||||
# export PDD_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_yandex_add() {
|
||||
fulldomain="${1}"
|
||||
txtvalue="${2}"
|
||||
_debug "Calling: dns_yandex_add() '${fulldomain}' '${txtvalue}'"
|
||||
_PDD_credentials || return 1
|
||||
export _H1="PddToken: $PDD_Token"
|
||||
|
||||
curDomain=$(_PDD_get_domain "$fulldomain")
|
||||
_debug "Found suitable domain in pdd: $curDomain"
|
||||
curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")"
|
||||
curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}"
|
||||
curUri="https://pddimp.yandex.ru/api2/admin/dns/add"
|
||||
curResult="$(_post "${curData}" "${curUri}")"
|
||||
_debug "Result: $curResult"
|
||||
}
|
||||
|
||||
#Usage: dns_myapi_rm _acme-challenge.www.domain.com
|
||||
dns_yandex_rm() {
|
||||
fulldomain="${1}"
|
||||
_debug "Calling: dns_yandex_rm() '${fulldomain}'"
|
||||
_PDD_credentials || return 1
|
||||
export _H1="PddToken: $PDD_Token"
|
||||
record_id=$(pdd_get_record_id "${fulldomain}")
|
||||
_debug "Result: $record_id"
|
||||
|
||||
curDomain=$(_PDD_get_domain "$fulldomain")
|
||||
_debug "Found suitable domain in pdd: $curDomain"
|
||||
curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")"
|
||||
|
||||
curUri="https://pddimp.yandex.ru/api2/admin/dns/del"
|
||||
curData="domain=${curDomain}&record_id=${record_id}"
|
||||
curResult="$(_post "${curData}" "${curUri}")"
|
||||
_debug "Result: $curResult"
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
_PDD_get_domain() {
|
||||
fulldomain="${1}"
|
||||
__page=1
|
||||
__last=0
|
||||
while [ $__last -eq 0 ]; do
|
||||
uri1="https://pddimp.yandex.ru/api2/admin/domain/domains?page=${__page}&on_page=20"
|
||||
res1=$(_get "$uri1" | _normalizeJson)
|
||||
#_debug "$res1"
|
||||
__found=$(echo "$res1" | sed -n -e 's#.* "found": \([^,]*\),.*#\1#p')
|
||||
_debug "found: $__found results on page"
|
||||
if [ "$__found" -lt 20 ]; then
|
||||
_debug "last page: $__page"
|
||||
__last=1
|
||||
fi
|
||||
|
||||
__all_domains="$__all_domains $(echo "$res1" | sed -e "s@,@\n@g" | grep '"name"' | cut -d: -f2 | sed -e 's@"@@g')"
|
||||
|
||||
__page=$(_math $__page + 1)
|
||||
done
|
||||
|
||||
k=2
|
||||
while [ $k -lt 10 ]; do
|
||||
__t=$(echo "$fulldomain" | cut -d . -f $k-100)
|
||||
_debug "finding zone for domain $__t"
|
||||
for d in $__all_domains; do
|
||||
if [ "$d" = "$__t" ]; then
|
||||
echo "$__t"
|
||||
return
|
||||
fi
|
||||
done
|
||||
k=$(_math $k + 1)
|
||||
done
|
||||
_err "No suitable domain found in your account"
|
||||
return 1
|
||||
}
|
||||
|
||||
_PDD_credentials() {
|
||||
if [ -z "${PDD_Token}" ]; then
|
||||
PDD_Token=""
|
||||
_err "You need to export PDD_Token=xxxxxxxxxxxxxxxxx"
|
||||
_err "You can get it at https://pddimp.yandex.ru/api2/admin/get_token"
|
||||
return 1
|
||||
else
|
||||
_saveaccountconf PDD_Token "${PDD_Token}"
|
||||
fi
|
||||
}
|
||||
|
||||
pdd_get_record_id() {
|
||||
fulldomain="${1}"
|
||||
|
||||
curDomain=$(_PDD_get_domain "$fulldomain")
|
||||
_debug "Found suitable domain in pdd: $curDomain"
|
||||
curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")"
|
||||
|
||||
curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}"
|
||||
curResult="$(_get "${curUri}" | _normalizeJson)"
|
||||
_debug "Result: $curResult"
|
||||
echo "$curResult" | _egrep_o "{[^{]*\"content\":[^{]*\"subdomain\":\"${curSubdomain}\"" | sed -n -e 's#.* "record_id": \(.*\),[^,]*#\1#p'
|
||||
}
|
||||
Reference in New Issue
Block a user