Merge remote-tracking branch 'upstream/master' into ssh-deploy
commit
94e9844179
@ -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
|
||||
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#Created by RaidenII, to use DuckDNS's API to add/remove text records
|
||||
#06/27/2017
|
||||
|
||||
# Currently only support single domain access
|
||||
# Due to the fact that DuckDNS uses StartSSL as cert provider, --insecure must be used with acme.sh
|
||||
|
||||
DuckDNS_API="https://www.duckdns.org/update"
|
||||
API_Params="domains=$DuckDNS_Domain&token=$DuckDNS_Token"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: dns_duckdns_add _acme-challenge.domain.duckdns.org "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_duckdns_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
# We'll extract the domain/username from full domain
|
||||
DuckDNS_Domain=$(echo "$fulldomain" | _lower_case | _egrep_o '.[^.]*.duckdns.org' | cut -d . -f 2)
|
||||
|
||||
if [ -z "$DuckDNS_Domain" ]; then
|
||||
_err "Error extracting the domain."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$DuckDNS_Token" ]; then
|
||||
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 DuckDNS_Domain "$DuckDNS_Domain"
|
||||
_saveaccountconf 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
|
||||
|
||||
# Now add the TXT record to DuckDNS
|
||||
_info "Trying to add TXT record"
|
||||
if _duckdns_rest GET "$API_Params&txt=$txtvalue" && [ "$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."
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
#Usage: fulldomain txtvalue
|
||||
#Remove the txt record after validation.
|
||||
dns_duckdns_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
# Now remove the TXT record from DuckDNS
|
||||
_info "Trying to remove TXT record"
|
||||
if _duckdns_rest GET "$API_Params&txt=&clear=true" && [ "$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."
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
#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
|
||||
}
|
@ -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
|
||||
}
|
@ -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 successfuly."
|
||||
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 successfuly."
|
||||
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:
|
@ -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
|
||||
}
|
@ -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'
|
||||
}
|
Loading…
Reference in New Issue