Merge branch 'dev' into feature/hosting.de-plugin
						commit
						1dab353fdb
					
				|  | @ -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:  | ||||
|  |  | |||
							
								
								
									
										1
									
								
								acme.sh
								
								
								
								
							
							
						
						
									
										1
									
								
								acme.sh
								
								
								
								
							|  | @ -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 | ||||
|  |  | |||
|  | @ -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 | ||||
| ``` | ||||
|  | @ -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 | ||||
| } | ||||
|  | @ -11,7 +11,7 @@ | |||
| # | ||||
| # Only a username is required.  All others are optional. | ||||
| # | ||||
| # The following examples are for QNAP NAS running QTS 4.2  | ||||
| # The following examples are for QNAP NAS running QTS 4.2 | ||||
| # export DEPLOY_SSH_CMD=""  # defaults to ssh | ||||
| # export DEPLOY_SSH_USER="admin"  # required | ||||
| # export DEPLOY_SSH_SERVER="qnap"  # defaults to domain name | ||||
|  | @ -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 | ||||
|  |  | |||
							
								
								
									
										101
									
								
								dnsapi/README.md
								
								
								
								
							
							
						
						
									
										101
									
								
								dnsapi/README.md
								
								
								
								
							|  | @ -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. | ||||
|  | @ -940,4 +1037,4 @@ See:  https://github.com/Neilpang/acme.sh/wiki/DNS-API-Dev-Guide | |||
| 
 | ||||
| # Use lexicon DNS API | ||||
| 
 | ||||
| https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api | ||||
| https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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 | ||||
| } | ||||
|  | @ -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 | ||||
| } | ||||
|  | @ -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') | ||||
| } | ||||
|  | @ -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 | ||||
| } | ||||
|  | @ -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}" | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -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 | ||||
| } | ||||
|  | @ -50,34 +50,16 @@ dns_unoeuro_add() { | |||
|     _err "Error" | ||||
|     return 1 | ||||
|   fi | ||||
|   _info "Adding record" | ||||
| 
 | ||||
|   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 | ||||
|       if _contains "$response" "\"status\": 200" >/dev/null; then | ||||
|         _info "Added, OK" | ||||
|         return 0 | ||||
|       else | ||||
|         _err "Add txt record error." | ||||
|         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 _uno_rest POST "my/products/$h/dns/records" "{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":120}"; then | ||||
|     if _contains "$response" "\"status\": 200" >/dev/null; then | ||||
|       _info "Updated, OK" | ||||
|       _info "Added, OK" | ||||
|       return 0 | ||||
|     else | ||||
|       _err "Add txt record error." | ||||
|       return 1 | ||||
|     fi | ||||
|     _err "Update error" | ||||
|     return 1 | ||||
|   fi | ||||
| } | ||||
| 
 | ||||
|  | @ -122,23 +104,24 @@ 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) | ||||
|     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" | ||||
|     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" | ||||
| 
 | ||||
|     if [ -z "$record_id" ]; then | ||||
|       _err "Can not get record id to remove." | ||||
|       return 1 | ||||
|     fi | ||||
|       if [ -z "$record_id" ]; then | ||||
|         _err "Can not get record id to remove." | ||||
|         return 1 | ||||
|       fi | ||||
| 
 | ||||
|     if ! _uno_rest DELETE "my/products/$h/dns/records/$record_id"; then | ||||
|       _err "Delete record error." | ||||
|       return 1 | ||||
|     fi | ||||
|     _contains "$response" "\"status\": 200" | ||||
|       if ! _uno_rest DELETE "my/products/$h/dns/records/$record_id"; then | ||||
|         _err "Delete record error." | ||||
|         return 1 | ||||
|       fi | ||||
|       _contains "$response" "\"status\": 200" | ||||
|     done | ||||
|   fi | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| ####################  Private functions below ################################## | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Oliver Dick
						Oliver Dick