Merge branch 'dev' into feature/hosting.de-plugin

This commit is contained in:
Oliver Dick 2018-08-30 14:28:50 +02:00 committed by GitHub
commit 1dab353fdb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 1126 additions and 52 deletions

View File

@ -321,6 +321,11 @@ You don't have to do anything manually!
1. acme-dns (https://github.com/joohoi/acme-dns)
1. TELE3 (https://www.tele3.cz)
1. EUSERV.EU (https://www.euserv.eu)
1. DNSPod.com API (https://www.dnspod.com)
1. Google Cloud DNS API
1. ConoHa (https://www.conoha.jp)
1. netcup DNS API (https://www.netcup.de)
1. GratisDNS.dk (https://gratisdns.dk)
1. hosting.de (https://www.hosting.de)
And:

View File

@ -1327,6 +1327,7 @@ createDomainKey() {
if _createkey "$_cdl" "$CERT_KEY_PATH"; then
_savedomainconf Le_Keylength "$_cdl"
_info "The domain key is here: $(__green $CERT_KEY_PATH)"
return 0
fi
else
if [ "$IS_RENEW" ]; then

View File

@ -275,3 +275,24 @@ acme.sh --deploy -d haproxy.example.com --deploy-hook haproxy
```
The path for the PEM file will be stored with the domain configuration and will be available when renewing, so that deploy will happen automatically when renewed.
## 11. Deploy your cert to Gitlab pages
You must define the API key and the informations for the project and Gitlab page you are updating the certificate for.
```sh
# The token can be created in your user settings under "Access Tokens"
export GITLAB_TOKEN="xxxxxxxxxxx"
# The project ID is displayed on the home page of the project
export GITLAB_PROJECT_ID=12345678
# The domain must match the one defined for the Gitlab page, without "https://"
export GITLAB_DOMAIN="www.mydomain.com"
```
You can then deploy the certificate as follows
```sh
acme.sh --deploy -d www.mydomain.com --deploy-hook gitlab
```

80
deploy/gitlab.sh Normal file
View File

@ -0,0 +1,80 @@
#!/usr/bin/env sh
# Script to deploy certificate to a Gitlab hosted page
# The following variables exported from environment will be used.
# If not set then values previously saved in domain.conf file are used.
# All the variables are required
# export GITLAB_TOKEN="xxxxxxx"
# export GITLAB_PROJECT_ID=012345
# export GITLAB_DOMAIN="mydomain.com"
gitlab_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 [ -z "$GITLAB_TOKEN" ]; then
if [ -z "$Le_Deploy_gitlab_token" ]; then
_err "GITLAB_TOKEN not defined."
return 1
fi
else
Le_Deploy_gitlab_token="$GITLAB_TOKEN"
_savedomainconf Le_Deploy_gitlab_token "$Le_Deploy_gitlab_token"
fi
if [ -z "$GITLAB_PROJECT_ID" ]; then
if [ -z "$Le_Deploy_gitlab_project_id" ]; then
_err "GITLAB_PROJECT_ID not defined."
return 1
fi
else
Le_Deploy_gitlab_project_id="$GITLAB_PROJECT_ID"
_savedomainconf Le_Deploy_gitlab_project_id "$Le_Deploy_gitlab_project_id"
fi
if [ -z "$GITLAB_DOMAIN" ]; then
if [ -z "$Le_Deploy_gitlab_domain" ]; then
_err "GITLAB_DOMAIN not defined."
return 1
fi
else
Le_Deploy_gitlab_domain="$GITLAB_DOMAIN"
_savedomainconf Le_Deploy_gitlab_domain "$Le_Deploy_gitlab_domain"
fi
string_fullchain=$(_url_encode <"$_cfullchain")
string_key=$(_url_encode <"$_ckey")
body="certificate=$string_fullchain&key=$string_key"
export _H1="PRIVATE-TOKEN: $Le_Deploy_gitlab_token"
gitlab_url="https://gitlab.com/api/v4/projects/$Le_Deploy_gitlab_project_id/pages/domains/$Le_Deploy_gitlab_domain"
_response=$(_post "$body" "$gitlab_url" 0 PUT | _dbase64 "multiline")
error_response="error"
if test "${_response#*$error_response}" != "$_response"; then
_err "Error in deploying certificate:"
_err "$_response"
return 1
fi
_debug response "$_response"
_info "Certificate successfully deployed"
return 0
}

View File

@ -101,7 +101,7 @@ ssh_deploy() {
fi
# CERTFILE is optional.
# If provided then private key will be copied or appended to provided filename.
# If provided then certificate will be copied or appended to provided filename.
if [ -n "$DEPLOY_SSH_CERTFILE" ]; then
Le_Deploy_ssh_certfile="$DEPLOY_SSH_CERTFILE"
_savedomainconf Le_Deploy_ssh_certfile "$Le_Deploy_ssh_certfile"
@ -190,7 +190,7 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
_info "Backup directories erased after 180 days."
fi
_debug "Remote commands to execute: $_cmdstr"
_secure_debug "Remote commands to execute: " "$_cmdstr"
_info "Submitting sequence of commands to remote server by ssh"
# quotations in bash cmd below intended. Squash travis spellcheck error
# shellcheck disable=SC2029

View File

@ -876,6 +876,7 @@ acme.sh --issue --dns dns_tele3 -d example.com -d *.example.com
```
The TELE3_Key and TELE3_Secret will be saved in ~/.acme.sh/account.conf and will be reused when needed.
## 47. Use Euserv.eu API
First you need to login to your euserv.eu account and activate your API Administration (API Verwaltung).
@ -897,7 +898,102 @@ acme.sh --issue --dns dns_euserv -d example.com -d *.example.com --insecure
The `EUSERV_Username` and `EUSERV_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
Please report any issues to https://github.com/initit/acme.sh or to <github@initit.de>
## 48. Use hosting.de API
## 48. Use DNSPod.com domain API to automatically issue cert
First you need to get your API Key and ID by this [get-the-user-token](https://www.dnspod.com/docs/info.html#get-the-user-token).
```
export DPI_Id="1234"
export DPI_Key="sADDsdasdgdsf"
```
Ok, let's issue a cert now:
```
acme.sh --issue --dns dns_dpi -d example.com -d www.example.com
```
The `DPI_Id` and `DPI_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
## 49. Use Google Cloud DNS API to automatically issue cert
First you need to authenticate to gcloud.
```
gcloud init
```
**The `dns_gcloud` script uses the active gcloud configuration and credentials.**
There is no logic inside `dns_gcloud` to override the project and other settings.
If needed, create additional [gcloud configurations](https://cloud.google.com/sdk/gcloud/reference/topic/configurations).
You can change the configuration being used without *activating* it; simply set the `CLOUDSDK_ACTIVE_CONFIG_NAME` environment variable.
To issue a certificate you can:
```
export CLOUDSDK_ACTIVE_CONFIG_NAME=default # see the note above
acme.sh --issue --dns dns_gcloud -d example.com -d '*.example.com'
```
`dns_gcloud` also supports [DNS alias mode](https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode).
## 50. Use ConoHa API
First you need to login to your ConoHa account to get your API credentials.
```
export CONOHA_Username="xxxxxx"
export CONOHA_Password="xxxxxx"
export CONOHA_TenantId="xxxxxx"
export CONOHA_IdentityServiceApi="https://identity.xxxx.conoha.io/v2.0"
```
To issue a cert:
```
acme.sh --issue --dns dns_conoha -d example.com -d www.example.com
```
The `CONOHA_Username`, `CONOHA_Password`, `CONOHA_TenantId` and `CONOHA_IdentityServiceApi` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
## 51. Use netcup DNS API to automatically issue cert
First you need to login in your CCP account to get your API Key and API Password.
```
export NC_Apikey="<Apikey>"
export NC_Apipw="<Apipassword>"
export NC_CID="<Customernumber>"
```
Now, let's issue a cert:
```
acme.sh --issue --dns dns_netcup -d example.com -d www.example.com
```
The `NC_Apikey`,`NC_Apipw` and `NC_CID` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
## 52. Use GratisDNS.dk
GratisDNS.dk (https://gratisdns.dk/) does not provide an API to update DNS records (other than IPv4 and IPv6
dynamic DNS addresses). The acme.sh plugin therefore retrieves and updates domain TXT records by logging
into the GratisDNS website to read the HTML and posting updates as HTTP. The plugin needs to know your
userid and password for the GratisDNS website.
```sh
export GDNSDK_Username="..."
export GDNSDK_Password="..."
```
The username and password will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
Now you can issue a certificate.
Note: It usually takes a few minutes (usually 3-4 minutes) before the changes propagates to gratisdns.dk nameservers (ns3.gratisdns.dk often are slow),
and in rare cases I have seen over 5 minutes before google DNS catches it. Therefor a DNS sleep of at least 300 seconds are recommended-
```sh
acme.sh --issue --dns dns_gdnsdk --dnssleep 300 -d example.com -d *.example.com
```
## 53. Use hosting.de API
Create an API key in your hosting.de account here: https://secure.hosting.de
@ -920,6 +1016,7 @@ acme.sh --issue --dns dns_hostingde -d example.com -d *.example.com
```
The hosting.de API key and endpoint will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
# Use custom API
If your API is not supported yet, you can write your own DNS API.

View File

@ -29,7 +29,7 @@ dns_aws_add() {
if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then
AWS_ACCESS_KEY_ID=""
AWS_SECRET_ACCESS_KEY=""
_err "You don't specify aws route53 api key id and and api key secret yet."
_err "You haven't specifed the aws route53 api key id and and api key secret yet."
_err "Please create your key and try again. see $(__green $AWS_WIKI)"
return 1
fi
@ -62,7 +62,7 @@ dns_aws_add() {
fi
if [ "$_resource_record" ] && _contains "$response" "$txtvalue"; then
_info "The txt record already exists, skip"
_info "The TXT record already exists. Skipping."
return 0
fi
@ -71,7 +71,7 @@ dns_aws_add() {
_aws_tmpl_xml="<ChangeResourceRecordSetsRequest xmlns=\"https://route53.amazonaws.com/doc/2013-04-01/\"><ChangeBatch><Changes><Change><Action>UPSERT</Action><ResourceRecordSet><Name>$fulldomain</Name><Type>TXT</Type><TTL>300</TTL><ResourceRecords>$_resource_record<ResourceRecord><Value>\"$txtvalue\"</Value></ResourceRecord></ResourceRecords></ResourceRecordSet></Change></Changes></ChangeBatch></ChangeResourceRecordSetsRequest>"
if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then
_info "txt record updated success."
_info "TXT record updated successfully."
return 0
fi
@ -99,7 +99,7 @@ dns_aws_rm() {
_debug _sub_domain "$_sub_domain"
_debug _domain "$_domain"
_info "Geting existing records for $fulldomain"
_info "Getting existing records for $fulldomain"
if ! aws_rest GET "2013-04-01$_domain_id/rrset" "name=$fulldomain&type=TXT"; then
return 1
fi
@ -108,14 +108,14 @@ dns_aws_rm() {
_resource_record="$(echo "$response" | sed 's/<ResourceRecordSet>/"/g' | tr '"' "\n" | grep "<Name>$fulldomain.</Name>" | _egrep_o "<ResourceRecords.*</ResourceRecords>" | sed "s/<ResourceRecords>//" | sed "s#</ResourceRecords>##")"
_debug "_resource_record" "$_resource_record"
else
_debug "no records exists, skip"
_debug "no records exist, skip"
return 0
fi
_aws_tmpl_xml="<ChangeResourceRecordSetsRequest xmlns=\"https://route53.amazonaws.com/doc/2013-04-01/\"><ChangeBatch><Changes><Change><Action>DELETE</Action><ResourceRecordSet><ResourceRecords>$_resource_record</ResourceRecords><Name>$fulldomain.</Name><Type>TXT</Type><TTL>300</TTL></ResourceRecordSet></Change></Changes></ChangeBatch></ChangeResourceRecordSetsRequest>"
if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then
_info "txt record deleted success."
_info "TXT record deleted successfully."
return 0
fi
@ -163,7 +163,7 @@ _get_root() {
_domain=$h
return 0
fi
_err "Can not find domain id: $h"
_err "Can't find domain with id: $h"
return 1
fi
fi

253
dnsapi/dns_conoha.sh Executable file
View File

@ -0,0 +1,253 @@
#!/usr/bin/env sh
CONOHA_DNS_EP_PREFIX_REGEXP="https://dns-service\."
######## Public functions #####################
#Usage: dns_conoha_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_conoha_add() {
fulldomain=$1
txtvalue=$2
_info "Using conoha"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
_debug "Check uesrname and password"
CONOHA_Username="${CONOHA_Username:-$(_readaccountconf_mutable CONOHA_Username)}"
CONOHA_Password="${CONOHA_Password:-$(_readaccountconf_mutable CONOHA_Password)}"
CONOHA_TenantId="${CONOHA_TenantId:-$(_readaccountconf_mutable CONOHA_TenantId)}"
CONOHA_IdentityServiceApi="${CONOHA_IdentityServiceApi:-$(_readaccountconf_mutable CONOHA_IdentityServiceApi)}"
if [ -z "$CONOHA_Username" ] || [ -z "$CONOHA_Password" ] || [ -z "$CONOHA_TenantId" ] || [ -z "$CONOHA_IdentityServiceApi" ]; then
CONOHA_Username=""
CONOHA_Password=""
CONOHA_TenantId=""
CONOHA_IdentityServiceApi=""
_err "You didn't specify a conoha api username and password yet."
_err "Please create the user and try again."
return 1
fi
_saveaccountconf_mutable CONOHA_Username "$CONOHA_Username"
_saveaccountconf_mutable CONOHA_Password "$CONOHA_Password"
_saveaccountconf_mutable CONOHA_TenantId "$CONOHA_TenantId"
_saveaccountconf_mutable CONOHA_IdentityServiceApi "$CONOHA_IdentityServiceApi"
if token="$(_conoha_get_accesstoken "$CONOHA_IdentityServiceApi/tokens" "$CONOHA_Username" "$CONOHA_Password" "$CONOHA_TenantId")"; then
accesstoken="$(printf "%s" "$token" | sed -n 1p)"
CONOHA_Api="$(printf "%s" "$token" | sed -n 2p)"
else
return 1
fi
_debug "First detect the root zone"
if ! _get_root "$fulldomain" "$CONOHA_Api" "$accesstoken"; then
_err "invalid domain"
return 1
fi
_debug _domain_id "$_domain_id"
_debug _sub_domain "$_sub_domain"
_debug _domain "$_domain"
_info "Adding record"
body="{\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"data\":\"$txtvalue\",\"ttl\":60}"
if _conoha_rest POST "$CONOHA_Api/v1/domains/$_domain_id/records" "$body" "$accesstoken"; then
if _contains "$response" '"data":"'"$txtvalue"'"'; then
_info "Added, OK"
return 0
else
_err "Add txt record error."
return 1
fi
fi
_err "Add txt record error."
return 1
}
#Usage: fulldomain txtvalue
#Remove the txt record after validation.
dns_conoha_rm() {
fulldomain=$1
txtvalue=$2
_info "Using conoha"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
_debug "Check uesrname and password"
CONOHA_Username="${CONOHA_Username:-$(_readaccountconf_mutable CONOHA_Username)}"
CONOHA_Password="${CONOHA_Password:-$(_readaccountconf_mutable CONOHA_Password)}"
CONOHA_TenantId="${CONOHA_TenantId:-$(_readaccountconf_mutable CONOHA_TenantId)}"
CONOHA_IdentityServiceApi="${CONOHA_IdentityServiceApi:-$(_readaccountconf_mutable CONOHA_IdentityServiceApi)}"
if [ -z "$CONOHA_Username" ] || [ -z "$CONOHA_Password" ] || [ -z "$CONOHA_TenantId" ] || [ -z "$CONOHA_IdentityServiceApi" ]; then
CONOHA_Username=""
CONOHA_Password=""
CONOHA_TenantId=""
CONOHA_IdentityServiceApi=""
_err "You didn't specify a conoha api username and password yet."
_err "Please create the user and try again."
return 1
fi
_saveaccountconf_mutable CONOHA_Username "$CONOHA_Username"
_saveaccountconf_mutable CONOHA_Password "$CONOHA_Password"
_saveaccountconf_mutable CONOHA_TenantId "$CONOHA_TenantId"
_saveaccountconf_mutable CONOHA_IdentityServiceApi "$CONOHA_IdentityServiceApi"
if token="$(_conoha_get_accesstoken "$CONOHA_IdentityServiceApi/tokens" "$CONOHA_Username" "$CONOHA_Password" "$CONOHA_TenantId")"; then
accesstoken="$(printf "%s" "$token" | sed -n 1p)"
CONOHA_Api="$(printf "%s" "$token" | sed -n 2p)"
else
return 1
fi
_debug "First detect the root zone"
if ! _get_root "$fulldomain" "$CONOHA_Api" "$accesstoken"; then
_err "invalid domain"
return 1
fi
_debug _domain_id "$_domain_id"
_debug _sub_domain "$_sub_domain"
_debug _domain "$_domain"
_debug "Getting txt records"
if ! _conoha_rest GET "$CONOHA_Api/v1/domains/$_domain_id/records" "" "$accesstoken"; then
_err "Error"
return 1
fi
record_id=$(printf "%s" "$response" | _egrep_o '{[^}]*}' \
| grep '"type":"TXT"' | grep "\"data\":\"$txtvalue\"" | _egrep_o "\"id\":\"[^\"]*\"" \
| _head_n 1 | cut -d : -f 2 | tr -d \")
if [ -z "$record_id" ]; then
_err "Can not get record id to remove."
return 1
fi
_debug record_id "$record_id"
_info "Removing the txt record"
if ! _conoha_rest DELETE "$CONOHA_Api/v1/domains/$_domain_id/records/$record_id" "" "$accesstoken"; then
_err "Delete record error."
return 1
fi
return 0
}
#################### Private functions below ##################################
_conoha_rest() {
m="$1"
ep="$2"
data="$3"
accesstoken="$4"
export _H1="Accept: application/json"
export _H2="Content-Type: application/json"
if [ -n "$accesstoken" ]; then
export _H3="X-Auth-Token: $accesstoken"
fi
_debug "$ep"
if [ "$m" != "GET" ]; then
_secure_debug2 data "$data"
response="$(_post "$data" "$ep" "" "$m")"
else
response="$(_get "$ep")"
fi
_ret="$?"
_secure_debug2 response "$response"
if [ "$_ret" != "0" ]; then
_err "error $ep"
return 1
fi
response="$(printf "%s" "$response" | _normalizeJson)"
return 0
}
_conoha_get_accesstoken() {
ep="$1"
username="$2"
password="$3"
tenantId="$4"
accesstoken="$(_readaccountconf_mutable conoha_accesstoken)"
expires="$(_readaccountconf_mutable conoha_tokenvalidto)"
CONOHA_Api="$(_readaccountconf_mutable conoha_dns_ep)"
# can we reuse the access token?
if [ -n "$accesstoken" ] && [ -n "$expires" ] && [ -n "$CONOHA_Api" ]; then
utc_date="$(_utc_date | sed "s/ /T/")"
if expr "$utc_date" "<" "$expires" >/dev/null; then
# access token is still valid - reuse it
_debug "reusing access token"
printf "%s\n%s\n" "$accesstoken" "$CONOHA_Api"
return 0
else
_debug "access token expired"
fi
fi
_debug "getting new access token"
body="$(printf '{"auth":{"passwordCredentials":{"username":"%s","password":"%s"},"tenantId":"%s"}}' "$username" "$password" "$tenantId")"
if ! _conoha_rest POST "$ep" "$body" ""; then
_err error "$response"
return 1
fi
accesstoken=$(printf "%s" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
expires=$(printf "%s" "$response" | _egrep_o "\"expires\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2-4 | tr -d \" | tr -d Z) #expect UTC
if [ -z "$accesstoken" ] || [ -z "$expires" ]; then
_err "no acccess token received. Check your Conoha settings see $WIKI"
return 1
fi
_saveaccountconf_mutable conoha_accesstoken "$accesstoken"
_saveaccountconf_mutable conoha_tokenvalidto "$expires"
CONOHA_Api=$(printf "%s" "$response" | _egrep_o 'publicURL":"'"$CONOHA_DNS_EP_PREFIX_REGEXP"'[^"]*"' | _head_n 1 | cut -d : -f 2-3 | tr -d \")
if [ -z "$CONOHA_Api" ]; then
_err "failed to get conoha dns endpoint url"
return 1
fi
_saveaccountconf_mutable conoha_dns_ep "$CONOHA_Api"
printf "%s\n%s\n" "$accesstoken" "$CONOHA_Api"
return 0
}
#_acme-challenge.www.domain.com
#returns
# _sub_domain=_acme-challenge.www
# _domain=domain.com
# _domain_id=sdjkglgdfewsdfg
_get_root() {
domain="$1"
ep="$2"
accesstoken="$3"
i=2
p=1
while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100).
_debug h "$h"
if [ -z "$h" ]; then
#not valid
return 1
fi
if ! _conoha_rest GET "$ep/v1/domains?name=$h" "" "$accesstoken"; then
return 1
fi
if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
_domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \")
if [ "$_domain_id" ]; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_domain=$h
return 0
fi
return 1
fi
p=$i
i=$(_math "$i" + 1)
done
return 1
}

161
dnsapi/dns_dpi.sh Executable file
View File

@ -0,0 +1,161 @@
#!/usr/bin/env sh
# Dnspod.com Domain api
#
#DPI_Id="1234"
#
#DPI_Key="sADDsdasdgdsf"
REST_API="https://api.dnspod.com"
######## Public functions #####################
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_dpi_add() {
fulldomain=$1
txtvalue=$2
DPI_Id="${DPI_Id:-$(_readaccountconf_mutable DPI_Id)}"
DPI_Key="${DPI_Key:-$(_readaccountconf_mutable DPI_Key)}"
if [ -z "$DPI_Id" ] || [ -z "$DPI_Key" ]; then
DPI_Id=""
DPI_Key=""
_err "You don't specify dnspod api key and key id yet."
_err "Please create you key and try again."
return 1
fi
#save the api key and email to the account conf file.
_saveaccountconf_mutable DPI_Id "$DPI_Id"
_saveaccountconf_mutable DPI_Key "$DPI_Key"
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain"
return 1
fi
add_record "$_domain" "$_sub_domain" "$txtvalue"
}
#fulldomain txtvalue
dns_dpi_rm() {
fulldomain=$1
txtvalue=$2
DPI_Id="${DPI_Id:-$(_readaccountconf_mutable DPI_Id)}"
DPI_Key="${DPI_Key:-$(_readaccountconf_mutable DPI_Key)}"
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain"
return 1
fi
if ! _rest POST "Record.List" "user_token=$DPI_Id,$DPI_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain"; then
_err "Record.Lis error."
return 1
fi
if _contains "$response" 'No records'; then
_info "Don't need to remove."
return 0
fi
record_id=$(echo "$response" | _egrep_o '{[^{]*"value":"'"$txtvalue"'"' | cut -d , -f 1 | cut -d : -f 2 | tr -d \")
_debug record_id "$record_id"
if [ -z "$record_id" ]; then
_err "Can not get record id."
return 1
fi
if ! _rest POST "Record.Remove" "user_token=$DPI_Id,$DPI_Key&format=json&domain_id=$_domain_id&record_id=$record_id"; then
_err "Record.Remove error."
return 1
fi
_contains "$response" "Action completed successful"
}
#add the txt record.
#usage: root sub txtvalue
add_record() {
root=$1
sub=$2
txtvalue=$3
fulldomain="$sub.$root"
_info "Adding record"
if ! _rest POST "Record.Create" "user_token=$DPI_Id,$DPI_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain&record_type=TXT&value=$txtvalue&record_line=default"; then
return 1
fi
_contains "$response" "Action completed successful" || _contains "$response" "Domain record already exists"
}
#################### Private functions below ##################################
#_acme-challenge.www.domain.com
#returns
# _sub_domain=_acme-challenge.www
# _domain=domain.com
# _domain_id=sdjkglgdfewsdfg
_get_root() {
domain=$1
i=2
p=1
while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
if [ -z "$h" ]; then
#not valid
return 1
fi
if ! _rest POST "Domain.Info" "user_token=$DPI_Id,$DPI_Key&format=json&domain=$h"; then
return 1
fi
if _contains "$response" "Action completed successful"; then
_domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")
_debug _domain_id "$_domain_id"
if [ "$_domain_id" ]; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_debug _sub_domain "$_sub_domain"
_domain="$h"
_debug _domain "$_domain"
return 0
fi
return 1
fi
p="$i"
i=$(_math "$i" + 1)
done
return 1
}
#Usage: method URI data
_rest() {
m="$1"
ep="$2"
data="$3"
_debug "$ep"
url="$REST_API/$ep"
_debug url "$url"
if [ "$m" = "GET" ]; then
response="$(_get "$url" | tr -d '\r')"
else
_debug2 data "$data"
response="$(_post "$data" "$url" | tr -d '\r')"
fi
if [ "$?" != "0" ]; then
_err "error $ep"
return 1
fi
_debug2 response "$response"
return 0
}

167
dnsapi/dns_gcloud.sh Executable file
View File

@ -0,0 +1,167 @@
#!/usr/bin/env sh
# Author: Janos Lenart <janos@lenart.io>
######## Public functions #####################
# Usage: dns_gcloud_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_gcloud_add() {
fulldomain=$1
txtvalue=$2
_info "Using gcloud"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
_dns_gcloud_find_zone || return $?
# Add an extra RR
_dns_gcloud_start_tr || return $?
_dns_gcloud_get_rrdatas || return $?
echo "$rrdatas" | _dns_gcloud_remove_rrs || return $?
printf "%s\n%s\n" "$rrdatas" "\"$txtvalue\"" | grep -v '^$' | _dns_gcloud_add_rrs || return $?
_dns_gcloud_execute_tr || return $?
_info "$fulldomain record added"
}
# Usage: dns_gcloud_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
# Remove the txt record after validation.
dns_gcloud_rm() {
fulldomain=$1
txtvalue=$2
_info "Using gcloud"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
_dns_gcloud_find_zone || return $?
# Remove one RR
_dns_gcloud_start_tr || return $?
_dns_gcloud_get_rrdatas || return $?
echo "$rrdatas" | _dns_gcloud_remove_rrs || return $?
echo "$rrdatas" | grep -F -v "\"$txtvalue\"" | _dns_gcloud_add_rrs || return $?
_dns_gcloud_execute_tr || return $?
_info "$fulldomain record added"
}
#################### Private functions below ##################################
_dns_gcloud_start_tr() {
if ! trd=$(mktemp -d); then
_err "_dns_gcloud_start_tr: failed to create temporary directory"
return 1
fi
tr="$trd/tr.yaml"
_debug tr "$tr"
if ! gcloud dns record-sets transaction start \
--transaction-file="$tr" \
--zone="$managedZone"; then
rm -r "$trd"
_err "_dns_gcloud_start_tr: failed to execute transaction"
return 1
fi
}
_dns_gcloud_execute_tr() {
if ! gcloud dns record-sets transaction execute \
--transaction-file="$tr" \
--zone="$managedZone"; then
_debug tr "$(cat "$tr")"
rm -r "$trd"
_err "_dns_gcloud_execute_tr: failed to execute transaction"
return 1
fi
rm -r "$trd"
for i in $(seq 1 120); do
if gcloud dns record-sets changes list \
--zone="$managedZone" \
--filter='status != done' \
| grep -q '^.*'; then
_info "_dns_gcloud_execute_tr: waiting for transaction to be comitted ($i/120)..."
sleep 5
else
return 0
fi
done
_err "_dns_gcloud_execute_tr: transaction is still pending after 10 minutes"
rm -r "$trd"
return 1
}
_dns_gcloud_remove_rrs() {
if ! xargs --no-run-if-empty gcloud dns record-sets transaction remove \
--name="$fulldomain." \
--ttl="$ttl" \
--type=TXT \
--zone="$managedZone" \
--transaction-file="$tr"; then
_debug tr "$(cat "$tr")"
rm -r "$trd"
_err "_dns_gcloud_remove_rrs: failed to remove RRs"
return 1
fi
}
_dns_gcloud_add_rrs() {
ttl=60
if ! xargs --no-run-if-empty gcloud dns record-sets transaction add \
--name="$fulldomain." \
--ttl="$ttl" \
--type=TXT \
--zone="$managedZone" \
--transaction-file="$tr"; then
_debug tr "$(cat "$tr")"
rm -r "$trd"
_err "_dns_gcloud_add_rrs: failed to add RRs"
return 1
fi
}
_dns_gcloud_find_zone() {
# Prepare a filter that matches zones that are suiteable for this entry.
# For example, _acme-challenge.something.domain.com might need to go into something.domain.com or domain.com;
# this function finds the longest postfix that has a managed zone.
part="$fulldomain"
filter="dnsName=( "
while [ "$part" != "" ]; do
filter="$filter$part. "
part="$(echo "$part" | sed 's/[^.]*\.*//')"
done
filter="$filter)"
_debug filter "$filter"
# List domains and find the longest match (in case of some levels of delegation)
if ! match=$(gcloud dns managed-zones list \
--format="value(name, dnsName)" \
--filter="$filter" \
| while read -r dnsName name; do
printf "%s\t%s\t%s\n" "${#dnsName}" "$dnsName" "$name"
done \
| sort -n -r | _head_n 1 | cut -f2,3 | grep '^.*'); then
_err "_dns_gcloud_find_zone: Can't find a matching managed zone! Perhaps wrong project or gcloud credentials?"
return 1
fi
dnsName=$(echo "$match" | cut -f2)
_debug dnsName "$dnsName"
managedZone=$(echo "$match" | cut -f1)
_debug managedZone "$managedZone"
}
_dns_gcloud_get_rrdatas() {
if ! rrdatas=$(gcloud dns record-sets list \
--zone="$managedZone" \
--name="$fulldomain." \
--type=TXT \
--format="value(ttl,rrdatas)"); then
_err "_dns_gcloud_get_rrdatas: Failed to list record-sets"
rm -r "$trd"
return 1
fi
ttl=$(echo "$rrdatas" | cut -f1)
rrdatas=$(echo "$rrdatas" | cut -f2 | sed 's/","/"\n"/g')
}

168
dnsapi/dns_gdnsdk.sh Executable file
View File

@ -0,0 +1,168 @@
#!/usr/bin/env sh
#Author: Herman Sletteng
#Report Bugs here: https://github.com/loial/acme.sh
#
#
# Note, gratisdns requires a login first, so the script needs to handle
# temporary cookies. Since acme.sh _get/_post currently don't directly support
# cookies, I've defined wrapper functions _myget/_mypost to set the headers
GDNSDK_API="https://admin.gratisdns.com"
######## Public functions #####################
#Usage: dns_gdnsdk_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_gdnsdk_add() {
fulldomain=$1
txtvalue=$2
_info "Using gratisdns.dk"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
if ! _gratisdns_login; then
_err "Login failed!"
return 1
fi
#finding domain zone
if ! _get_domain; then
_err "No matching root domain for $fulldomain found"
return 1
fi
# adding entry
_info "Adding the entry"
_mypost "action=dns_primary_record_added_txt&user_domain=$_domain&name=$fulldomain&txtdata=$txtvalue&ttl=1"
if _successful_update; then return 0; fi
_err "Couldn't create entry!"
return 1
}
#Usage: fulldomain txtvalue
#Remove the txt record after validation.
dns_gdnsdk_rm() {
fulldomain=$1
txtvalue=$2
_info "Using gratisdns.dk"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
if ! _gratisdns_login; then
_err "Login failed!"
return 1
fi
if ! _get_domain; then
_err "No matching root domain for $fulldomain found"
return 1
fi
_findentry "$fulldomain" "$txtvalue"
if [ -z "$_id" ]; then
_info "Entry doesn't exist, nothing to delete"
return 0
fi
_debug "Deleting record..."
_mypost "action=dns_primary_delete_txt&user_domain=$_domain&id=$_id"
# removing entry
if _successful_update; then return 0; fi
_err "Couldn't delete entry!"
return 1
}
#################### Private functions below ##################################
_checkcredentials() {
GDNSDK_Username="${GDNSDK_Username:-$(_readaccountconf_mutable GDNSDK_Username)}"
GDNSDK_Password="${GDNSDK_Password:-$(_readaccountconf_mutable GDNSDK_Password)}"
if [ -z "$GDNSDK_Username" ] || [ -z "$GDNSDK_Password" ]; then
GDNSDK_Username=""
GDNSDK_Password=""
_err "You haven't specified gratisdns.dk username and password yet."
_err "Please add credentials and try again."
return 1
fi
#save the credentials to the account conf file.
_saveaccountconf_mutable GDNSDK_Username "$GDNSDK_Username"
_saveaccountconf_mutable GDNSDK_Password "$GDNSDK_Password"
return 0
}
_checkcookie() {
GDNSDK_Cookie="${GDNSDK_Cookie:-$(_readaccountconf_mutable GDNSDK_Cookie)}"
if [ -z "$GDNSDK_Cookie" ]; then
_debug "No cached cookie found"
return 1
fi
_myget "action="
if (echo "$_result" | grep -q "logmeout"); then
_debug "Cached cookie still valid"
return 0
fi
_debug "Cached cookie no longer valid"
GDNSDK_Cookie=""
_saveaccountconf_mutable GDNSDK_Cookie "$GDNSDK_Cookie"
return 1
}
_gratisdns_login() {
if ! _checkcredentials; then return 1; fi
if _checkcookie; then
_debug "Already logged in"
return 0
fi
_debug "Logging into GratisDNS with user $GDNSDK_Username"
if ! _mypost "login=$GDNSDK_Username&password=$GDNSDK_Password&action=logmein"; then
_err "GratisDNS login failed for user $GDNSDK_Username bad RC from _post"
return 1
fi
GDNSDK_Cookie="$(grep -A 15 '302 Found' "$HTTP_HEADER" | _egrep_o 'Cookie: [^;]*' | _head_n 1 | cut -d ' ' -f2)"
if [ -z "$GDNSDK_Cookie" ]; then
_err "GratisDNS login failed for user $GDNSDK_Username. Check $HTTP_HEADER file"
return 1
fi
export GDNSDK_Cookie
_saveaccountconf_mutable GDNSDK_Cookie "$GDNSDK_Cookie"
return 0
}
_myget() {
#Adds cookie to request
export _H1="Cookie: $GDNSDK_Cookie"
_result=$(_get "$GDNSDK_API?$1")
}
_mypost() {
#Adds cookie to request
export _H1="Cookie: $GDNSDK_Cookie"
_result=$(_post "$1" "$GDNSDK_API")
}
_get_domain() {
_myget 'action=dns_primarydns'
_domains=$(echo "$_result" | _egrep_o ' domain="[[:alnum:].-_]+' | sed 's/^.*"//')
if [ -z "$_domains" ]; then
_err "Primary domain list not found!"
return 1
fi
for _domain in $_domains; do
if (_endswith "$fulldomain" "$_domain"); then
_debug "Root domain: $_domain"
return 0
fi
done
return 1
}
_successful_update() {
if (echo "$_result" | grep -q 'table-success'); then return 0; fi
return 1
}
_findentry() {
#returns id of dns entry, if it exists
_myget "action=dns_primary_changeDNSsetup&user_domain=$_domain"
_id=$(echo "$_result" | _egrep_o "<td>$1</td>\s*<td>$2</td>[^?]*[^&]*&id=[^&]*" | sed 's/^.*=//')
if [ -n "$_id" ]; then
_debug "Entry found with _id=$_id"
return 0
fi
return 1
}

View File

@ -78,7 +78,11 @@ dns_lexicon_add() {
domain=$(printf "%s" "$fulldomain" | cut -d . -f 2-999)
$lexicon_cmd "$PROVIDER" create "${domain}" TXT --name="_acme-challenge.${domain}." --content="${txtvalue}"
_secure_debug LEXICON_OPTS "$LEXICON_OPTS"
_savedomainconf LEXICON_OPTS "$LEXICON_OPTS"
# shellcheck disable=SC2086
$lexicon_cmd "$PROVIDER" $LEXICON_OPTS create "${domain}" TXT --name="_acme-challenge.${domain}." --content="${txtvalue}"
}
@ -93,6 +97,7 @@ dns_lexicon_rm() {
domain=$(printf "%s" "$fulldomain" | cut -d . -f 2-999)
$lexicon_cmd "$PROVIDER" delete "${domain}" TXT --name="_acme-challenge.${domain}." --content="${txtvalue}"
# shellcheck disable=SC2086
$lexicon_cmd "$PROVIDER" $LEXICON_OPTS delete "${domain}" TXT --name="_acme-challenge.${domain}." --content="${txtvalue}"
}

133
dnsapi/dns_netcup.sh Normal file
View File

@ -0,0 +1,133 @@
#!/usr/bin/env sh
#developed by linux-insideDE
NC_Apikey="${NC_Apikey:-$(_readaccountconf_mutable NC_Apikey)}"
NC_Apipw="${NC_Apipw:-$(_readaccountconf_mutable NC_Apipw)}"
NC_CID="${NC_CID:-$(_readaccountconf_mutable NC_CID)}"
end="https://ccp.netcup.net/run/webservice/servers/endpoint.php?JSON"
client=""
dns_netcup_add() {
login
if [ "$NC_Apikey" = "" ] || [ "$NC_Apipw" = "" ] || [ "$NC_CID" = "" ]; then
_err "No Credentials given"
return 1
fi
_saveaccountconf_mutable NC_Apikey "$NC_Apikey"
_saveaccountconf_mutable NC_Apipw "$NC_Apipw"
_saveaccountconf_mutable NC_CID "$NC_CID"
fulldomain=$1
txtvalue=$2
domain=""
exit=$(echo "$fulldomain" | tr -dc '.' | wc -c)
exit=$(_math "$exit" + 1)
i=$exit
while
[ "$exit" -gt 0 ]
do
tmp=$(echo "$fulldomain" | cut -d'.' -f"$exit")
if [ "$(_math "$i" - "$exit")" -eq 0 ]; then
domain="$tmp"
else
domain="$tmp.$domain"
fi
if [ "$(_math "$i" - "$exit")" -ge 1 ]; then
msg=$(_post "{\"action\": \"updateDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\",\"clientrequestid\": \"$client\" , \"domainname\": \"$domain\", \"dnsrecordset\": { \"dnsrecords\": [ {\"id\": \"\", \"hostname\": \"$fulldomain.\", \"type\": \"TXT\", \"priority\": \"\", \"destination\": \"$txtvalue\", \"deleterecord\": \"false\", \"state\": \"yes\"} ]}}}" "$end" "" "POST")
_debug "$msg"
if [ "$(_getfield "$msg" "5" | sed 's/"statuscode"://g')" != 5028 ]; then
if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then
_err "$msg"
return 1
else
break
fi
fi
fi
exit=$(_math "$exit" - 1)
done
logout
}
dns_netcup_rm() {
login
fulldomain=$1
txtvalue=$2
domain=""
exit=$(echo "$fulldomain" | tr -dc '.' | wc -c)
exit=$(_math "$exit" + 1)
i=$exit
rec=""
while
[ "$exit" -gt 0 ]
do
tmp=$(echo "$fulldomain" | cut -d'.' -f"$exit")
if [ "$(_math "$i" - "$exit")" -eq 0 ]; then
domain="$tmp"
else
domain="$tmp.$domain"
fi
if [ "$(_math "$i" - "$exit")" -ge 1 ]; then
msg=$(_post "{\"action\": \"infoDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\", \"domainname\": \"$domain\"}}" "$end" "" "POST")
rec=$(echo "$msg" | sed 's/\[//g' | sed 's/\]//g' | sed 's/{\"serverrequestid\".*\"dnsrecords\"://g' | sed 's/},{/};{/g' | sed 's/{//g' | sed 's/}//g')
_debug "$msg"
if [ "$(_getfield "$msg" "5" | sed 's/"statuscode"://g')" != 5028 ]; then
if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then
_err "$msg"
return 1
else
break
fi
fi
fi
exit=$(_math "$exit" - 1)
done
ida=0000
idv=0001
ids=0000000000
i=1
while
[ "$i" -ne 0 ]
do
specrec=$(_getfield "$rec" "$i" ";")
idv="$ida"
ida=$(_getfield "$specrec" "1" "," | sed 's/\"id\":\"//g' | sed 's/\"//g')
txtv=$(_getfield "$specrec" "5" "," | sed 's/\"destination\":\"//g' | sed 's/\"//g')
i=$(_math "$i" + 1)
if [ "$txtvalue" = "$txtv" ]; then
i=0
ids="$ida"
fi
if [ "$ida" = "$idv" ]; then
i=0
fi
done
msg=$(_post "{\"action\": \"updateDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\",\"clientrequestid\": \"$client\" , \"domainname\": \"$domain\", \"dnsrecordset\": { \"dnsrecords\": [ {\"id\": \"$ids\", \"hostname\": \"$fulldomain.\", \"type\": \"TXT\", \"priority\": \"\", \"destination\": \"$txtvalue\", \"deleterecord\": \"TRUE\", \"state\": \"yes\"} ]}}}" "$end" "" "POST")
_debug "$msg"
if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then
_err "$msg"
return 1
fi
logout
}
login() {
tmp=$(_post "{\"action\": \"login\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apipassword\": \"$NC_Apipw\", \"customernumber\": \"$NC_CID\"}}" "$end" "" "POST")
sid=$(_getfield "$tmp" "8" | sed s/\"responsedata\":\{\"apisessionid\":\"//g | sed 's/\"\}\}//g')
_debug "$tmp"
if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then
_err "$msg"
return 1
fi
}
logout() {
tmp=$(_post "{\"action\": \"logout\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\"}}" "$end" "" "POST")
_debug "$tmp"
if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then
_err "$msg"
return 1
fi
}

View File

@ -50,8 +50,6 @@ dns_unoeuro_add() {
_err "Error"
return 1
fi
if ! _contains "$response" "$_sub_domain" >/dev/null; then
_info "Adding record"
if _uno_rest POST "my/products/$h/dns/records" "{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":120}"; then
@ -63,22 +61,6 @@ dns_unoeuro_add() {
return 1
fi
fi
_err "Add txt record error."
else
_info "Updating record"
record_line_number=$(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1)
record_line_number=$(_math "$record_line_number" - 1)
record_id=$(echo "$response" | _head_n "$record_line_number" | _tail_n 1 1 | _egrep_o "[0-9]{1,}")
_debug "record_id" "$record_id"
_uno_rest PUT "my/products/$h/dns/records/$record_id" "{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":120}"
if _contains "$response" "\"status\": 200" >/dev/null; then
_info "Updated, OK"
return 0
fi
_err "Update error"
return 1
fi
}
#fulldomain txtvalue
@ -122,8 +104,9 @@ dns_unoeuro_rm() {
if ! _contains "$response" "$_sub_domain"; then
_info "Don't need to remove."
else
record_line_number=$(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1)
for record_line_number in $(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1); do
record_line_number=$(_math "$record_line_number" - 1)
_debug "record_line_number" "$record_line_number"
record_id=$(echo "$response" | _head_n "$record_line_number" | _tail_n 1 1 | _egrep_o "[0-9]{1,}")
_debug "record_id" "$record_id"
@ -137,8 +120,8 @@ dns_unoeuro_rm() {
return 1
fi
_contains "$response" "\"status\": 200"
done
fi
}
#################### Private functions below ##################################