From c4bf5eef73aa749393101f50683e4391ac8e46d2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 8 Mar 2017 21:51:25 +0800 Subject: [PATCH 001/115] add _upper_case and _lower_case --- acme.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/acme.sh b/acme.sh index eb1a8969..699ea268 100755 --- a/acme.sh +++ b/acme.sh @@ -299,6 +299,16 @@ _secure_debug3() { fi } +_upper_case() { + # shellcheck disable=SC2018,SC2019 + tr 'a-z' 'A-Z' +} + +_lower_case() { + # shellcheck disable=SC2018,SC2019 + tr 'A-Z' 'a-z' +} + _startswith() { _str="$1" _sub="$2" From ac690fceaf5a1fcba7632d340e709258f4fdbc3f Mon Sep 17 00:00:00 2001 From: thewer Date: Thu, 9 Mar 2017 22:28:30 +1000 Subject: [PATCH 002/115] Added DigitalOcean (native) API that requires only a read/write API key for DigitalOcean, updated 2 reads files. --- README.md | 1 + dnsapi/README.md | 13 +++ dnsapi/dns_dgon.sh | 205 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 219 insertions(+) create mode 100755 dnsapi/dns_dgon.sh diff --git a/README.md b/README.md index 7d5ab846..52231d0f 100644 --- a/README.md +++ b/README.md @@ -308,6 +308,7 @@ You don't have to do anything manually! 1. Domain-Offensive/Resellerinterface/Domainrobot API 1. Gandi LiveDNS API 1. Knot DNS API +1. DigitalOcean API (native) **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index 5b71e89f..fe243cb5 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -394,6 +394,19 @@ acme.sh --issue --dns dns_knot -d example.com -d www.example.com The `KNOT_SERVER` and `KNOT_KEY` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 20. Use DigitalOcean API (native) + +You need to obtain a read and write capable API key from your DigitalOcean account. See: https://www.digitalocean.com/help/api/ + +``` +export DO_API_KEY="75310dc4ca779ac39a19f6355db573b49ce92ae126553ebd61ac3a3ae34834cc" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_dgon -d example.com -d www.example.com +``` + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_dgon.sh b/dnsapi/dns_dgon.sh new file mode 100755 index 00000000..9ceede44 --- /dev/null +++ b/dnsapi/dns_dgon.sh @@ -0,0 +1,205 @@ +#!/usr/bin/env sh + +## Will be called by acme.sh to add the txt record to your api system. +## returns 0 means success, otherwise error. + +## Author: thewer +## GitHub: https://github.com/gitwer/acme.sh + +## +## Environment Variables Required: +## +## DO_API_KEY="75310dc4ca779ac39a19f6355db573b49ce92ae126553ebd61ac3a3ae34834cc" +## + +##################### Public functions ##################### + +## Create the text record for validation. +## Usage: fulldomain txtvalue +## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs" +dns_dgon_add() { + fulldomain="$(echo "$1" | _lower_case)" + txtvalue=$2 + _info "Using digitalocean dns validation - add record" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + ## save the env vars (key and domain split location) for later automated use + _saveaccountconf DO_API_KEY "$DO_API_KEY" + + ## split the domain for DO API + if ! _get_base_domain "$fulldomain"; then + _err "domain not found in your account for addition" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + ## Set the header with our post type and key auth key + export _H1="Content-Type: application/json" + export _H2="Authorization: Bearer $DO_API_KEY" + PURL='https://api.digitalocean.com/v2/domains/'$_domain'/records' + PBODY='{"type":"TXT","name":"'$_sub_domain'","data":"'$txtvalue'"}' + + _debug PURL "$PURL" + _debug PBODY "$PBODY" + + ## the create request - post + ## args: BODY, URL, [need64, httpmethod] + response="$(_post "$PBODY" "$PURL")" + + ## check response + if [ "$?" != "0" ]; then + _err "error in response: $response" + return 1 + fi + _debug2 response "$response" + + ## finished correctly + return 0 +} + +## Remove the txt record after validation. +## Usage: fulldomain txtvalue +## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs" +dns_dgon_rm() { + fulldomain="$(echo "$1" | _lower_case)" + txtvalue=$2 + _info "Using digitalocean dns validation - remove record" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + ## split the domain for DO API + if ! _get_base_domain "$fulldomain"; then + _err "domain not found in your account for removal" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + ## Set the header with our post type and key auth key + export _H1="Content-Type: application/json" + export _H2="Authorization: Bearer $DO_API_KEY" + ## get URL for the list of domains + ## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}} + GURL="https://api.digitalocean.com/v2/domains/$_domain/records" + + ## while we dont have a record ID we keep going + while [ -z "$record" ]; do + ## 1) get the URL + ## the create request - get + ## args: URL, [onlyheader, timeout] + domain_list="$(_get "$GURL")" + ## 2) find record + ## check for what we are looing for: "type":"A","name":"$_sub_domain" + record="$(echo "$domain_list" | _egrep_o "\"id\"\s*\:\s*\"*\d+\"*[^}]*\"name\"\s*\:\s*\"$_sub_domain\"[^}]*\"data\"\s*\:\s*\"$txtvalue\"")" + ## 3) check record and get next page + if [ -z "$record" ]; then + ## find the next page if we dont have a match + nextpage="$(echo "$domain_list" | _egrep_o "\"links\".*" | _egrep_o "\"next\".*" | _egrep_o "http.*page\=\d+")" + if [ -z "$nextpage" ]; then + _err "no record and no nextpage in digital ocean DNS removal" + return 1 + fi + _debug2 nextpage "$nextpage" + GURL="$nextpage" + fi + ## we break out of the loop when we have a record + done + + ## we found the record + rec_id="$(echo "$record" | _egrep_o "id\"\s*\:\s*\"*\d+" | _egrep_o "\d+")" + _debug rec_id "$rec_id" + + ## delete the record + ## delete URL for removing the one we dont want + DURL="https://api.digitalocean.com/v2/domains/$_domain/records/$rec_id" + + ## the create request - delete + ## args: BODY, URL, [need64, httpmethod] + response="$(_post "" "$DURL" "" "DELETE")" + + ## check response (sort of) + if [ "$?" != "0" ]; then + _err "error in remove response: $response" + return 1 + fi + _debug2 response "$response" + + ## finished correctly + return 0 +} + +##################### Private functions below ##################### + +## Split the domain provided into the "bade domain" and the "start prefix". +## This function searches for the longest subdomain in your account +## for the full domain given and splits it into the base domain (zone) +## and the prefix/record to be added/removed +## USAGE: fulldomain +## EG: "_acme-challenge.two.three.four.domain.com" +## returns +## _sub_domain="_acme-challenge.two" +## _domain="three.four.domain.com" *IF* zone "three.four.domain.com" exists +## if only "domain.com" exists it will return +## _sub_domain="_acme-challenge.two.three.four" +## _domain="domain.com" +_get_base_domain() { + # args + fulldomain="$(echo "$1" | tr '[:upper:]' '[:lower:]')" + _debug fulldomain "$fulldomain" + + # domain max legal length = 253 + MAX_DOM=255 + + ## get a list of domains for the account to check thru + ## Set the headers + export _H1="Content-Type: application/json" + export _H2="Authorization: Bearer $DO_API_KEY" + _debug DO_API_KEY "$DO_API_KEY" + ## get URL for the list of domains + ## havent seen this request paginated, tested with 18 domains (more requres manual requests with DO) + DOMURL="https://api.digitalocean.com/v2/domains" + + ## get the domain list (DO gives basically a full XFER!) + domain_list="$(_get "$DOMURL")" + + ## check response + if [ "$?" != "0" ]; then + _err "error in domain_list response: $domain_list" + return 1 + fi + _debug2 domain_list "$domain_list" + + ## for each shortening of our $fulldomain, check if it exists in the $domain_list + ## can never start on 1 (aka whole $fulldomain) as $fulldomain starts with "_acme-challenge" + i=2 + while [ $i -gt 0 ]; do + ## get next longest domain + _domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM") + ## check we got something back from our cut (or are we at the end) + if [ -z "$_domain" ]; then + ## we got to the end of the domain - invalid domain + _err "domain not found in DigitalOcean account" + return 1 + fi + ## we got part of a domain back - grep it out + found="$(echo "$domain_list" | _egrep_o "\"name\"\s*\:\s*\"$_domain\"")" + ## check if it exists + if [ ! -z "$found" ]; then + ## exists - exit loop returning the parts + sub_point=$(_math $i - 1) + _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$sub_point") + _debug _domain "$_domain" + _debug _sub_domain "$_sub_domain" + return 0 + fi + ## increment cut point $i + i=$(_math $i + 1) + done + + ## we went through the entire domain zone list and dint find one that matched + ## doesnt look like we can add in the record + _err "domain not found in DigitalOcean account, but we should never get here" + return 1 +} From 04683338a21bda18da6d3dafce6167de1fb699f2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 11 Mar 2017 10:06:40 +0800 Subject: [PATCH 003/115] fix cloudxns api https://github.com/Neilpang/acme.sh/issues/717 --- dnsapi/dns_cx.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index 2b6d5691..e2f0f099 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -209,8 +209,7 @@ _rest() { return 1 fi _debug2 response "$response" - if ! _contains "$response" '"message":"success"'; then - return 1 - fi - return 0 + + _contains "$response" '"code":1' + } From 4dd646a424a0f91267f3c198437319548dfb66be Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 13 Mar 2017 11:18:04 +0800 Subject: [PATCH 004/115] fix https://github.com/Neilpang/acme.sh/issues/719 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 699ea268..7906aa4c 100755 --- a/acme.sh +++ b/acme.sh @@ -4628,7 +4628,7 @@ install() { #Modify shebang if _exists bash; then _info "Good, bash is found, so change the shebang to use bash as preferred." - _shebang='#!/usr/bin/env bash' + _shebang='#!'"$(env bash -c "command -v bash")" _setShebang "$LE_WORKING_DIR/$PROJECT_ENTRY" "$_shebang" for subf in $_SUB_FOLDERS; do if [ -d "$LE_WORKING_DIR/$subf" ]; then From 3b7fbcd0c322b152d566dc65a6bca97cc483d4d5 Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Tue, 14 Mar 2017 13:24:09 +0200 Subject: [PATCH 005/115] Add DNS API support for ClouDNS --- dnsapi/README.md | 14 ++++ dnsapi/dns_cloudns.sh | 158 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100755 dnsapi/dns_cloudns.sh diff --git a/dnsapi/README.md b/dnsapi/README.md index fe243cb5..702efc1c 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -407,6 +407,20 @@ Ok, let's issue a cert now: acme.sh --issue --dns dns_dgon -d example.com -d www.example.com ``` +## 21. Use ClouDNS API + +You need to set the HTTP API user ID and password credentials. See: https://www.cloudns.net/wiki/article/42/ + +``` +export CLOUDNS_AUTH_ID=XXXXX +export CLOUDNS_AUTH_PASSWORD="YYYYYYYYY" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_cloudns -d example.com -d www.example.com +``` + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh new file mode 100755 index 00000000..9b93b1ca --- /dev/null +++ b/dnsapi/dns_cloudns.sh @@ -0,0 +1,158 @@ +#!/usr/bin/env sh + +#CLOUDNS_AUTH_ID=XXXXX +#CLOUDNS_AUTH_PASSWORD="YYYYYYYYY" +CLOUDNS_API="https://api.cloudns.net" + +######## Public functions ##################### + +#Usage: dns_cloudns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_cloudns_add() { + _info "Using cloudns" + + if ! _dns_cloudns_init_check; then + return 1 + fi + + zone="$(_dns_cloudns_get_zone_name $1)" + if [ -z "$zone" ]; then + _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." + return 1 + fi + + host="$(echo $1|sed "s/\.$zone\$//")" + record=$2 + record_id=$(_dns_cloudns_get_record_id "$zone" "$host") + + _debug zone "$zone" + _debug host "$host" + _debug record "$record" + _debug record_id "$record_id" + + + if [ -z "$record_id" ]; then + _info "Adding the TXT record for $1" + _dns_cloudns_http_api_call "dns/add-record.json" "domain-name=$zone&record-type=TXT&host=$host&record=$record&ttl=60" + if ! _contains "$response" "\"status\":\"Success\""; then + _err "Record cannot be added." + return 1 + fi + _info "Added." + else + _info "Updating the TXT record for $1" + _dns_cloudns_http_api_call "dns/mod-record.json" "domain-name=$zone&record-id=$record_id&record-type=TXT&host=$host&record=$record&ttl=60" + if ! _contains "$response" "\"status\":\"Success\""; then + _err "The TXT record for $1 cannot be updated." + return 1 + fi + _info "Updated." + fi + + return 0 +} + +#Usage: dns_cloudns_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_cloudns_rm() { + _info "Using cloudns" + + if ! _dns_cloudns_init_check; then + return 1 + fi + + if [ -z $zone]; then + zone="$(_dns_cloudns_get_zone_name $1)" + if [ -z "$zone" ]; then + _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." + return 1 + fi + fi + + host="$(echo $1|sed "s/\.$zone\$//")" + record=$2 + record_id=$(_dns_cloudns_get_record_id "$zone" "$host") + + _debug zone "$zone" + _debug host "$host" + _debug record "$record" + _debug record_id "$record_id" + + if [ ! -z "$record_id" ]; then + _info "Deleting the TXT record for $1" + _dns_cloudns_http_api_call "dns/delete-record.json" "domain-name=$zone&record-id=" + if ! _contains "$response" "\"status\":\"Success\""; then + _err "The TXT record for $1 cannot be deleted." + return 1 + fi + _info "Deleted." + fi + return 0 +} + +#################### Private functions below ################################## +_dns_cloudns_init_check() { + if [ ! -z $CLOUDNS_INIT_CHECK_COMPLETED]; then + return 0 + fi + + if [ -z "$CLOUDNS_AUTH_ID" ]; then + _err "CLOUDNS_AUTH_ID is not configured" + return 1 + fi + + if [ -z "$CLOUDNS_AUTH_PASSWORD" ]; then + _err "CLOUDNS_AUTH_PASSWORD is not configured" + return 1 + fi + + CLOUDNS_INIT_CHECK_COMPLETED=1 + + return 0 +} + +_dns_cloudns_get_zone_name() { + i=2 + while true; do + zoneForCheck=$(printf "%s" "$1" | cut -d . -f $i-100) + + if [ -z "$zoneForCheck" ]; then + # missing zone + return 1; + fi + + _debug zoneForCheck $zoneForCheck + + _dns_cloudns_http_api_call "dns/get-zone-info.json" "domain-name=$zoneForCheck" + + if ! _contains "$response" "\"status\":\"Failed\""; then + echo $zoneForCheck + return 0; + fi + + i=$(expr $i + 1) + done + return 1; +} + +_dns_cloudns_get_record_id() { + _dns_cloudns_http_api_call "dns/records.json" "domain-name=$1&host=$2&type=TXT" + if _contains "$response" "\"id\":"; then + echo $response | awk 'BEGIN { FS="\"" } {print $2}' + return 0 + fi + return 1 +} + +_dns_cloudns_http_api_call () { + method=$1 + + _debug CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" + _debug CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD" + + data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD&$2" + + response="$(_get "$CLOUDNS_API/$method?$data")" + + _debug response "$response" + + return 1; +} \ No newline at end of file From c7257e0a3c6b4883a1ccde8dbcf4338483d26f48 Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Tue, 14 Mar 2017 14:20:58 +0200 Subject: [PATCH 006/115] Add DNS API for ClouDNS --- dnsapi/dns_cloudns.sh | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 9b93b1ca..39d8c3a6 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -7,20 +7,20 @@ CLOUDNS_API="https://api.cloudns.net" ######## Public functions ##################### #Usage: dns_cloudns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_cloudns_add() { +dns_cloudns_add () { _info "Using cloudns" if ! _dns_cloudns_init_check; then - return 1 + return 1 fi zone="$(_dns_cloudns_get_zone_name $1)" if [ -z "$zone" ]; then - _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." - return 1 + _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." + return 1 fi - host="$(echo $1|sed "s/\.$zone\$//")" + host="$(echo $1 | sed "s/\.$zone\$//")" record=$2 record_id=$(_dns_cloudns_get_record_id "$zone" "$host") @@ -52,14 +52,14 @@ dns_cloudns_add() { } #Usage: dns_cloudns_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_cloudns_rm() { +dns_cloudns_rm () { _info "Using cloudns" if ! _dns_cloudns_init_check; then return 1 fi - if [ -z $zone]; then + if [ -z $zone ]; then zone="$(_dns_cloudns_get_zone_name $1)" if [ -z "$zone" ]; then _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." @@ -89,8 +89,8 @@ dns_cloudns_rm() { } #################### Private functions below ################################## -_dns_cloudns_init_check() { - if [ ! -z $CLOUDNS_INIT_CHECK_COMPLETED]; then +_dns_cloudns_init_check () { + if [ ! -z $CLOUDNS_INIT_CHECK_COMPLETED ]; then return 0 fi @@ -109,14 +109,13 @@ _dns_cloudns_init_check() { return 0 } -_dns_cloudns_get_zone_name() { +_dns_cloudns_get_zone_name () { i=2 while true; do zoneForCheck=$(printf "%s" "$1" | cut -d . -f $i-100) if [ -z "$zoneForCheck" ]; then - # missing zone - return 1; + return 1 fi _debug zoneForCheck $zoneForCheck @@ -125,15 +124,15 @@ _dns_cloudns_get_zone_name() { if ! _contains "$response" "\"status\":\"Failed\""; then echo $zoneForCheck - return 0; + return 0 fi i=$(expr $i + 1) done - return 1; + return 1 } -_dns_cloudns_get_record_id() { +_dns_cloudns_get_record_id () { _dns_cloudns_http_api_call "dns/records.json" "domain-name=$1&host=$2&type=TXT" if _contains "$response" "\"id\":"; then echo $response | awk 'BEGIN { FS="\"" } {print $2}' @@ -154,5 +153,5 @@ _dns_cloudns_http_api_call () { _debug response "$response" - return 1; + return 1 } \ No newline at end of file From 0dd6377fe666ded6d0919acd6e8fb8adc0d497ea Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Tue, 14 Mar 2017 14:25:50 +0200 Subject: [PATCH 007/115] Add DNS API for ClouDNS --- dnsapi/dns_cloudns.sh | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 39d8c3a6..1726b81a 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -7,7 +7,7 @@ CLOUDNS_API="https://api.cloudns.net" ######## Public functions ##################### #Usage: dns_cloudns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_cloudns_add () { +dns_cloudns_add() { _info "Using cloudns" if ! _dns_cloudns_init_check; then @@ -20,8 +20,8 @@ dns_cloudns_add () { return 1 fi - host="$(echo $1 | sed "s/\.$zone\$//")" - record=$2 + host="$(echo "$1" | sed "s/\.$zone\$//")" + record=$2 record_id=$(_dns_cloudns_get_record_id "$zone" "$host") _debug zone "$zone" @@ -52,14 +52,14 @@ dns_cloudns_add () { } #Usage: dns_cloudns_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_cloudns_rm () { +dns_cloudns_rm() { _info "Using cloudns" if ! _dns_cloudns_init_check; then - return 1 + return 1 fi - if [ -z $zone ]; then + if [ -z "$zone" ]; then zone="$(_dns_cloudns_get_zone_name $1)" if [ -z "$zone" ]; then _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." @@ -67,8 +67,8 @@ dns_cloudns_rm () { fi fi - host="$(echo $1|sed "s/\.$zone\$//")" - record=$2 + host="$(echo "$1" | sed "s/\.$zone\$//")" + record=$2 record_id=$(_dns_cloudns_get_record_id "$zone" "$host") _debug zone "$zone" @@ -89,8 +89,8 @@ dns_cloudns_rm () { } #################### Private functions below ################################## -_dns_cloudns_init_check () { - if [ ! -z $CLOUDNS_INIT_CHECK_COMPLETED ]; then +_dns_cloudns_init_check() { + if [ ! -z "$CLOUDNS_INIT_CHECK_COMPLETED" ]; then return 0 fi @@ -109,7 +109,7 @@ _dns_cloudns_init_check () { return 0 } -_dns_cloudns_get_zone_name () { +_dns_cloudns_get_zone_name() { i=2 while true; do zoneForCheck=$(printf "%s" "$1" | cut -d . -f $i-100) @@ -123,7 +123,7 @@ _dns_cloudns_get_zone_name () { _dns_cloudns_http_api_call "dns/get-zone-info.json" "domain-name=$zoneForCheck" if ! _contains "$response" "\"status\":\"Failed\""; then - echo $zoneForCheck + echo "$zoneForCheck" return 0 fi @@ -132,16 +132,16 @@ _dns_cloudns_get_zone_name () { return 1 } -_dns_cloudns_get_record_id () { +_dns_cloudns_get_record_id() { _dns_cloudns_http_api_call "dns/records.json" "domain-name=$1&host=$2&type=TXT" if _contains "$response" "\"id\":"; then - echo $response | awk 'BEGIN { FS="\"" } {print $2}' + echo "$response" | awk 'BEGIN { FS="\"" } {print $2}' return 0 fi return 1 } -_dns_cloudns_http_api_call () { +_dns_cloudns_http_api_call() { method=$1 _debug CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" From a15f87ae39d33e0d35838e4dc5c810bd934fc232 Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Tue, 14 Mar 2017 14:26:57 +0200 Subject: [PATCH 008/115] Add DNS API for ClouDNS --- dnsapi/dns_cloudns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 1726b81a..3eb10b33 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -127,7 +127,7 @@ _dns_cloudns_get_zone_name() { return 0 fi - i=$(expr $i + 1) + i=$(expr "$i" + 1) done return 1 } From 5df2ca3ef301fe8bbcf0c7e11c5ef9a1c0484aca Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Tue, 14 Mar 2017 14:38:02 +0200 Subject: [PATCH 009/115] Add DNS API for ClouDNS --- dnsapi/dns_cloudns.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 3eb10b33..cd83619f 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -14,7 +14,7 @@ dns_cloudns_add() { return 1 fi - zone="$(_dns_cloudns_get_zone_name $1)" + zone="$(_dns_cloudns_get_zone_name "$1")" if [ -z "$zone" ]; then _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." return 1 @@ -28,7 +28,6 @@ dns_cloudns_add() { _debug host "$host" _debug record "$record" _debug record_id "$record_id" - if [ -z "$record_id" ]; then _info "Adding the TXT record for $1" @@ -60,7 +59,7 @@ dns_cloudns_rm() { fi if [ -z "$zone" ]; then - zone="$(_dns_cloudns_get_zone_name $1)" + zone="$(_dns_cloudns_get_zone_name "$1")" if [ -z "$zone" ]; then _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." return 1 @@ -118,7 +117,7 @@ _dns_cloudns_get_zone_name() { return 1 fi - _debug zoneForCheck $zoneForCheck + _debug zoneForCheck "$zoneForCheck" _dns_cloudns_http_api_call "dns/get-zone-info.json" "domain-name=$zoneForCheck" @@ -127,7 +126,7 @@ _dns_cloudns_get_zone_name() { return 0 fi - i=$(expr "$i" + 1) + i=$(($i+1)) done return 1 } From f881d6c44ff6f5043399ae3b379c158aa2ec69e8 Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Tue, 14 Mar 2017 14:40:18 +0200 Subject: [PATCH 010/115] Add DNS API for ClouDNS --- dnsapi/dns_cloudns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index cd83619f..698cc26e 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -153,4 +153,4 @@ _dns_cloudns_http_api_call() { _debug response "$response" return 1 -} \ No newline at end of file +} From 55a5da2102c2bfe9e41e2d32e7e29c7eb301e9ce Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Tue, 14 Mar 2017 14:42:51 +0200 Subject: [PATCH 011/115] Add DNS API for ClouDNS --- dnsapi/dns_cloudns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 698cc26e..efa7ce7e 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -126,7 +126,7 @@ _dns_cloudns_get_zone_name() { return 0 fi - i=$(($i+1)) + i=$(($i + 1)) done return 1 } From 3d8598654c82128ac8e6be44f9f6127f9c778f09 Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Tue, 14 Mar 2017 14:43:43 +0200 Subject: [PATCH 012/115] Add DNS API for ClouDNS --- dnsapi/dns_cloudns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index efa7ce7e..d12db033 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -126,7 +126,7 @@ _dns_cloudns_get_zone_name() { return 0 fi - i=$(($i + 1)) + i=$((${i} + 1)) done return 1 } From ac11ba3d60534bc52478c6016e6025d4be8e93ad Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Tue, 14 Mar 2017 15:12:02 +0200 Subject: [PATCH 013/115] Add DNS API for ClouDNS --- dnsapi/dns_cloudns.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index d12db033..d000d6a2 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -28,7 +28,7 @@ dns_cloudns_add() { _debug host "$host" _debug record "$record" _debug record_id "$record_id" - + if [ -z "$record_id" ]; then _info "Adding the TXT record for $1" _dns_cloudns_http_api_call "dns/add-record.json" "domain-name=$zone&record-type=TXT&host=$host&record=$record&ttl=60" @@ -126,7 +126,7 @@ _dns_cloudns_get_zone_name() { return 0 fi - i=$((${i} + 1)) + i=$((i + 1)) done return 1 } From be972fc0b5dc13171380fe0c88ac371539d45ef9 Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Wed, 15 Mar 2017 10:00:21 +0200 Subject: [PATCH 014/115] fixes for the comments in #723 --- dnsapi/dns_cloudns.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index d000d6a2..a9615c58 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -126,7 +126,7 @@ _dns_cloudns_get_zone_name() { return 0 fi - i=$((i + 1)) + i=$(_math "$i" + 1) done return 1 } @@ -150,7 +150,7 @@ _dns_cloudns_http_api_call() { response="$(_get "$CLOUDNS_API/$method?$data")" - _debug response "$response" + _debug2 response "$response" - return 1 + return 0 } From f063dd195e44c099c0c65322049745af5cbb063a Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Wed, 15 Mar 2017 15:49:14 +0200 Subject: [PATCH 015/115] some additional fixes and removed awk --- dnsapi/dns_cloudns.sh | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index a9615c58..9f6f1679 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -77,7 +77,7 @@ dns_cloudns_rm() { if [ ! -z "$record_id" ]; then _info "Deleting the TXT record for $1" - _dns_cloudns_http_api_call "dns/delete-record.json" "domain-name=$zone&record-id=" + _dns_cloudns_http_api_call "dns/delete-record.json" "domain-name=$zone&record-id=$record_id" if ! _contains "$response" "\"status\":\"Success\""; then _err "The TXT record for $1 cannot be deleted." return 1 @@ -103,6 +103,13 @@ _dns_cloudns_init_check() { return 1 fi + _dns_cloudns_http_api_call "dns/login.json" "" + + if ! _contains "$response" "\"status\":\"Success\""; then + _err "Invalid CLOUDNS_AUTH_ID or CLOUDNS_AUTH_PASSWORD. Please check your login credentials." + return 1 + fi + CLOUDNS_INIT_CHECK_COMPLETED=1 return 0 @@ -134,7 +141,7 @@ _dns_cloudns_get_zone_name() { _dns_cloudns_get_record_id() { _dns_cloudns_http_api_call "dns/records.json" "domain-name=$1&host=$2&type=TXT" if _contains "$response" "\"id\":"; then - echo "$response" | awk 'BEGIN { FS="\"" } {print $2}' + echo "$response" | cut -d '"' -f 2 return 0 fi return 1 @@ -146,7 +153,11 @@ _dns_cloudns_http_api_call() { _debug CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" _debug CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD" - data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD&$2" + if [ -z $2 ]; then + data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD" + else + data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD&$2" + fi response="$(_get "$CLOUDNS_API/$method?$data")" From 136d1b04b5379401ab721dc0939f9b0aa24507cb Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Wed, 15 Mar 2017 15:52:05 +0200 Subject: [PATCH 016/115] some additional fixes and removed awk --- dnsapi/dns_cloudns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 9f6f1679..4bb2c267 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -153,7 +153,7 @@ _dns_cloudns_http_api_call() { _debug CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" _debug CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD" - if [ -z $2 ]; then + if [ -z "$2" ]; then data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD" else data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD&$2" From c0b20275885437ff540c747b4f936510215a74ce Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Wed, 15 Mar 2017 15:58:04 +0200 Subject: [PATCH 017/115] add ClouDNS to the list in the main README file --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 52231d0f..1cf29746 100644 --- a/README.md +++ b/README.md @@ -309,6 +309,7 @@ You don't have to do anything manually! 1. Gandi LiveDNS API 1. Knot DNS API 1. DigitalOcean API (native) +1. ClouDNS API **More APIs coming soon...** From 819d2bc560e260e09a41b1124794f8348b899f2d Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 15 Mar 2017 22:52:57 +0800 Subject: [PATCH 018/115] fix for wget. fix https://github.com/Neilpang/acme.sh/issues/724#issuecomment-286761682 --- dnsapi/dns_aws.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 84aa28d3..d5d52de0 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -143,7 +143,7 @@ aws_rest() { CanonicalHeaders="host:$aws_host\nx-amz-date:$RequestDate\n" SignedHeaders="host;x-amz-date" if [ -n "$AWS_SESSION_TOKEN" ]; then - export _H2="x-amz-security-token: $AWS_SESSION_TOKEN" + export _H3="x-amz-security-token: $AWS_SESSION_TOKEN" CanonicalHeaders="${CanonicalHeaders}x-amz-security-token:$AWS_SESSION_TOKEN\n" SignedHeaders="${SignedHeaders};x-amz-security-token" fi @@ -204,8 +204,8 @@ aws_rest() { Authorization="$Algorithm Credential=$AWS_ACCESS_KEY_ID/$CredentialScope, SignedHeaders=$SignedHeaders, Signature=$signature" _debug2 Authorization "$Authorization" - _H3="Authorization: $Authorization" - _debug _H3 "$_H3" + _H2="Authorization: $Authorization" + _debug _H2 "$_H2" url="$AWS_URL/$ep" From 5ffca2d1383c017f07897dd8c77c34beb15153c2 Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Wed, 15 Mar 2017 17:16:54 +0200 Subject: [PATCH 019/115] Update cotnact details --- dnsapi/dns_cloudns.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 4bb2c267..f48a8052 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -1,5 +1,8 @@ #!/usr/bin/env sh +# Author: Boyan Peychev +# Repository: https://github.com/ClouDNS/acme.sh/ + #CLOUDNS_AUTH_ID=XXXXX #CLOUDNS_AUTH_PASSWORD="YYYYYYYYY" CLOUDNS_API="https://api.cloudns.net" From 3e9478b58dda04923a2c1eeae9ad9613a04cc079 Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Wed, 15 Mar 2017 17:25:01 +0200 Subject: [PATCH 020/115] Update README information for ClouDNS --- README.md | 2 +- dnsapi/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1cf29746..5c1ddd80 100644 --- a/README.md +++ b/README.md @@ -309,7 +309,7 @@ You don't have to do anything manually! 1. Gandi LiveDNS API 1. Knot DNS API 1. DigitalOcean API (native) -1. ClouDNS API +1. ClouDNS.net API **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index 702efc1c..d419d5ed 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -407,7 +407,7 @@ Ok, let's issue a cert now: acme.sh --issue --dns dns_dgon -d example.com -d www.example.com ``` -## 21. Use ClouDNS API +## 21. Use ClouDNS.net API You need to set the HTTP API user ID and password credentials. See: https://www.cloudns.net/wiki/article/42/ From 7044236824af45431413297c6224e11dcc785733 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Wed, 15 Mar 2017 11:40:32 -0700 Subject: [PATCH 021/115] Create dns_dynu.sh Add DNS API support for Dynu. --- dnsapi/dns_dynu.sh | 135 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 dnsapi/dns_dynu.sh diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh new file mode 100644 index 00000000..963bdd2f --- /dev/null +++ b/dnsapi/dns_dynu.sh @@ -0,0 +1,135 @@ +#!/usr/bin/env sh + +my_dir="$(dirname "$0")" +source "$my_dir/acme.sh" + +#Client ID +Dynu_ClientId="0b71cae7-a099-4f6b-8ddf-94571cdb760d" +# +#Secret +Dynu_Secret="aCUEY4BDCV45KI8CSIC3sp2LKQ9" +# +#Token +Dynu_Token="" +# +#Endpoint +Dynu_EndPoint="https://api.dynu.com/v1" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_dynu_add() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$Dynu_ClientId" ] || [ -z "$Dynu_Secret" ]; then + Dynu_ClientId="" + Dynu_Secret="" + _err "Dynu client id and secret is not specified." + _err "Please create you API client id and secret and try again." + return 1 + fi + + #save the client id and secret to the account conf file. + _saveaccountconf Dynu_ClientId "$Dynu_ClientId" + _saveaccountconf Dynu_Secret "$Dynu_Secret" + + if [ -z "$Dynu_Token" ]; then + _info "Getting Dynu token" + if ! _dynu_authentication; then + _err "Can not get token." + fi + fi + + _debug "Detect root zone" + if ! _get_root "$fulldomain"; then + _err "Invalid domain" + return 1 + fi + + _debug _node "$_node" + _debug _domain_name "$_domain_name" + + _info "Creating TXT record" + if ! _dynu_rest POST "dns/record/add" "{\"domain_name\":\"$_domain_name\",\"node_name\":\"$_node\",\"record_type\":\"TXT\",\"text_data\":\"$txtvalue\",\"state\":true,\"ttl\":90}"; then + return 1 + fi + + if ! _contains "$response" "text_data"; then + _err "Could not add TXT record" + return 1 + fi + + return 0 +} + +#fulldomain +dns_dynu_rm() { + fulldomain=$1 +} + +######## Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _node=_acme-challenge.www +# _domain_name=domain.com +_get_root() { + domain=$1 + if ! _dynu_rest GET "dns/getroot/$domain"; then + return 1 + fi + + if ! _contains "$response" "domain_name"; then + _debug "Domain name not found" + return 1 + fi + + _domain_name=$(printf "%s" "$response" | tr -d "{}" | cut -d , -f 1 | cut -d : -f 2 | cut -d '"' -f 2) + _node=$(printf "%s" "$response" | tr -d "{}" | cut -d , -f 3 | cut -d : -f 2 | cut -d '"' -f 2) + return 0 +} + +_dynu_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + export _H1="Authorization: Bearer $Dynu_Token" + export _H2="Content-Type: application/json" + + if [ "$data" ]; then + _debug data "$data" + response="$(_post "$data" "$Dynu_EndPoint/$ep" "" "$m")" + else + echo "Getting $Dynu_EndPoint/$ep" + response="$(_get "$Dynu_EndPoint/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} + +_dynu_authentication() { + export _H1="Authorization: Basic $(printf "%s" "$Dynu_ClientId:$Dynu_Secret" | _base64)" + export _H2="Content-Type: application/json" + + response="$(_get "$Dynu_EndPoint/oauth2/token")" + if [ "$?" != "0" ]; then + _err "Authentication failed." + return 1 + fi + if _contains "$response" "accessToken"; then + Dynu_Token=$(printf "%s" "$response" | tr -d "[]" | cut -d , -f 2 | cut -d : -f 2 | cut -d '"' -f 2) + fi + if _contains "$Dynu_Token" "null"; then + Dynu_Token="" + fi + + _debug2 response "$response" + return 0 +} From c87cd0de73f263ad2ce9892213a912b3ad691d07 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 16 Mar 2017 18:02:36 +0800 Subject: [PATCH 022/115] fix https://github.com/Neilpang/acme.sh/issues/729 https://github.com/Neilpang/acme.sh/issues/721 --- acme.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 7906aa4c..671b0d33 100755 --- a/acme.sh +++ b/acme.sh @@ -3477,7 +3477,10 @@ issue() { if [ ! "$usingApache" ]; then if webroot_owner=$(_stat "$_currentRoot"); then _debug "Changing owner/group of .well-known to $webroot_owner" - chown -R "$webroot_owner" "$_currentRoot/.well-known" + if ! _exec "chown -R \"$webroot_owner\" \"$_currentRoot/.well-known\""; then + _debug "$(cat "$_EXEC_TEMP_ERR")" + _exec_err >/dev/null 2>&1 + fi else _debug "not chaning owner/group of webroot" fi From 5c78e0a462178ea5424b241b486252c331c2bd53 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Thu, 16 Mar 2017 13:42:30 -0700 Subject: [PATCH 023/115] removed source acme.sh --- dnsapi/dns_dynu.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index 963bdd2f..b12b0bbb 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -1,8 +1,5 @@ #!/usr/bin/env sh -my_dir="$(dirname "$0")" -source "$my_dir/acme.sh" - #Client ID Dynu_ClientId="0b71cae7-a099-4f6b-8ddf-94571cdb760d" # From 2aa75f034ff1730bc576737b28b8002c7100129b Mon Sep 17 00:00:00 2001 From: jtbr Date: Sun, 19 Mar 2017 16:10:09 +0100 Subject: [PATCH 024/115] Adds support for --ca-path option for using non-default curl/wget CA certs --- acme.sh | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 671b0d33..68a3799a 100755 --- a/acme.sh +++ b/acme.sh @@ -1479,7 +1479,9 @@ _inithttp() { _ACME_CURL="$_ACME_CURL --trace-ascii $_CURL_DUMP " fi - if [ "$CA_BUNDLE" ]; then + if [ "$CA_PATH" ]; then + _ACME_CURL="$_ACME_CURL --capath $CA_PATH " + elif [ "$CA_BUNDLE" ]; then _ACME_CURL="$_ACME_CURL --cacert $CA_BUNDLE " fi @@ -1490,8 +1492,10 @@ _inithttp() { if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then _ACME_WGET="$_ACME_WGET -d " fi - if [ "$CA_BUNDLE" ]; then - _ACME_WGET="$_ACME_WGET --ca-certificate $CA_BUNDLE " + if [ "$CA_PATH" ]; then + _ACME_WGET="$_ACME_WGET --ca-directory=$CA_PATH " + elif [ "$CA_BUNDLE" ]; then + _ACME_WGET="$_ACME_WGET --ca-certificate=$CA_BUNDLE " fi fi @@ -3702,6 +3706,12 @@ issue() { else _clearaccountconf "CA_BUNDLE" fi + + if [ "$CA_PATH" ]; then + _saveaccountconf CA_PATH "$CA_PATH" + else + _clearaccountconf "CA_PATH" + fi if [ "$HTTPS_INSECURE" ]; then _saveaccountconf HTTPS_INSECURE "$HTTPS_INSECURE" @@ -4918,6 +4928,7 @@ _process() { _stopRenewOnError="" #_insecure="" _ca_bundle="" + _ca_path="" _nocron="" _ecc="" _csr="" @@ -5232,6 +5243,11 @@ _process() { CA_BUNDLE="$_ca_bundle" shift ;; + --ca-path) + _ca_path="$2" + CA_PATH="$_ca_path" + shift + ;; --nocron) _nocron="1" ;; From f21dd9117dc470f47668439ede249916d0a8cd2c Mon Sep 17 00:00:00 2001 From: jtbr Date: Sun, 19 Mar 2017 17:55:26 +0100 Subject: [PATCH 025/115] Handle case of busybox netstat, with no pid support --- acme.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 671b0d33..d5d9f313 100755 --- a/acme.sh +++ b/acme.sh @@ -1131,8 +1131,12 @@ _ss() { elif netstat -help 2>&1 | grep -- '-P protocol' >/dev/null; then #for solaris netstat -an -P tcp | grep "\.$_port " | grep "LISTEN" - else + elif netstat -help 2>&1 | grep "\-p" > /dev/null; then + #for full linux netstat -ntpl | grep ":$_port " + else + #for busybox (embedded linux; no pid support) + netstat -ntl 2>/dev/null | grep ":$_port " fi fi return 0 From f19f21007c081074a47baba06582d53acfd8586a Mon Sep 17 00:00:00 2001 From: jtbr Date: Mon, 20 Mar 2017 18:51:45 +0100 Subject: [PATCH 026/115] formatting --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d5d9f313..043308e9 100755 --- a/acme.sh +++ b/acme.sh @@ -1131,7 +1131,7 @@ _ss() { elif netstat -help 2>&1 | grep -- '-P protocol' >/dev/null; then #for solaris netstat -an -P tcp | grep "\.$_port " | grep "LISTEN" - elif netstat -help 2>&1 | grep "\-p" > /dev/null; then + elif netstat -help 2>&1 | grep "\-p" >/dev/null; then #for full linux netstat -ntpl | grep ":$_port " else From 4bdab73dd51f9bad4c823ab199b5c85ff0808fe4 Mon Sep 17 00:00:00 2001 From: jtbr Date: Mon, 20 Mar 2017 18:53:08 +0100 Subject: [PATCH 027/115] formatting --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 68a3799a..67b52cfe 100755 --- a/acme.sh +++ b/acme.sh @@ -3706,7 +3706,7 @@ issue() { else _clearaccountconf "CA_BUNDLE" fi - + if [ "$CA_PATH" ]; then _saveaccountconf CA_PATH "$CA_PATH" else From 5c539af7d7645723b928389bc93da526f0dcfa60 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 22 Mar 2017 21:20:35 +0800 Subject: [PATCH 028/115] rename parameters --- README.md | 10 +++++----- acme.sh | 38 +++++++++++++++++++------------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 5c1ddd80..64609067 100644 --- a/README.md +++ b/README.md @@ -161,17 +161,17 @@ You **MUST** use this command to copy the certs to the target files, **DO NOT** **Apache** example: ```bash acme.sh --install-cert -d example.com \ ---certpath /path/to/certfile/in/apache/cert.pem \ ---keypath /path/to/keyfile/in/apache/key.pem \ ---fullchainpath /path/to/fullchain/certfile/apache/fullchain.pem \ +--cert-file /path/to/certfile/in/apache/cert.pem \ +--key-file /path/to/keyfile/in/apache/key.pem \ +--fullchain-file /path/to/fullchain/certfile/apache/fullchain.pem \ --reloadcmd "service apache2 force-reload" ``` **Nginx** example: ```bash acme.sh --install-cert -d example.com \ ---keypath /path/to/keyfile/in/nginx/key.pem \ ---fullchainpath /path/to/fullchain/nginx/cert.pem \ +--key-file /path/to/keyfile/in/nginx/key.pem \ +--fullchain-file /path/to/fullchain/nginx/cert.pem \ --reloadcmd "service nginx force-reload" ``` diff --git a/acme.sh b/acme.sh index f8a1c49d..15257687 100755 --- a/acme.sh +++ b/acme.sh @@ -4035,7 +4035,7 @@ deploy() { installcert() { _main_domain="$1" if [ -z "$_main_domain" ]; then - _usage "Usage: $PROJECT_ENTRY --installcert -d domain.com [--ecc] [--certpath cert-file-path] [--keypath key-file-path] [--capath ca-cert-file-path] [ --reloadCmd reloadCmd] [--fullchainpath fullchain-path]" + _usage "Usage: $PROJECT_ENTRY --installcert -d domain.com [--ecc] [--cert-file cert-file-path] [--key-file key-file-path] [--ca-file ca-cert-file-path] [ --reloadCmd reloadCmd] [--fullchain-file fullchain-path]" return 1 fi @@ -4785,10 +4785,10 @@ Parameters: These parameters are to install the cert to nginx/apache or anyother server after issue/renew a cert: - --certpath /path/to/real/cert/file After issue/renew, the cert will be copied to this path. - --keypath /path/to/real/key/file After issue/renew, the key will be copied to this path. - --capath /path/to/real/ca/file After issue/renew, the intermediate cert will be copied to this path. - --fullchainpath /path/to/fullchain/file After issue/renew, the fullchain cert will be copied to this path. + --cert-file /path/to/real/cert/file After issue/renew, the cert will be copied to this path. + --key-file /path/to/real/key/file After issue/renew, the key will be copied to this path. + --ca-file /path/to/real/ca/file After issue/renew, the intermediate cert will be copied to this path. + --fullchain-file /path/to/fullchain/file After issue/renew, the fullchain cert will be copied to this path. --reloadcmd \"service nginx reload\" After issue/renew, it's used to reload the server. @@ -4913,10 +4913,10 @@ _process() { _webroot="" _keylength="" _accountkeylength="" - _certpath="" - _keypath="" - _capath="" - _fullchainpath="" + _cert_file="" + _key_file="" + _ca_file="" + _fullchain_file="" _reloadcmd="" _password="" _accountconf="" @@ -5158,20 +5158,20 @@ _process() { shift ;; - --certpath) - _certpath="$2" + --cert-file | --certpath) + _cert_file="$2" shift ;; - --keypath) - _keypath="$2" + --key-file | --keypath) + _key_file="$2" shift ;; - --capath) - _capath="$2" + --ca-file | --capath) + _ca_file="$2" shift ;; - --fullchainpath) - _fullchainpath="$2" + --fullchain-file | --fullchainpath) + _fullchain_file="$2" shift ;; --reloadcmd | --reloadCmd) @@ -5393,7 +5393,7 @@ _process() { uninstall) uninstall "$_nocron" ;; upgrade) upgrade ;; issue) - issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_address" + issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_cert_file" "$_key_file" "$_ca_file" "$_reloadcmd" "$_fullchain_file" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_address" ;; deploy) deploy "$_domain" "$_deploy_hook" "$_ecc" @@ -5405,7 +5405,7 @@ _process() { showcsr "$_csr" "$_domain" ;; installcert) - installcert "$_domain" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" "$_ecc" + installcert "$_domain" "$_cert_file" "$_key_file" "$_ca_file" "$_reloadcmd" "$_fullchain_file" "$_ecc" ;; renew) renew "$_domain" "$_ecc" From 13fe54c938e964caefe74a9bb46087b6fbc4121f Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 22 Mar 2017 22:58:03 +0800 Subject: [PATCH 029/115] update doc --- acme.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 15257687..244f72e3 100755 --- a/acme.sh +++ b/acme.sh @@ -4785,10 +4785,10 @@ Parameters: These parameters are to install the cert to nginx/apache or anyother server after issue/renew a cert: - --cert-file /path/to/real/cert/file After issue/renew, the cert will be copied to this path. - --key-file /path/to/real/key/file After issue/renew, the key will be copied to this path. - --ca-file /path/to/real/ca/file After issue/renew, the intermediate cert will be copied to this path. - --fullchain-file /path/to/fullchain/file After issue/renew, the fullchain cert will be copied to this path. + --cert-file After issue/renew, the cert will be copied to this path. + --key-file After issue/renew, the key will be copied to this path. + --ca-file After issue/renew, the intermediate cert will be copied to this path. + --fullchain-file After issue/renew, the fullchain cert will be copied to this path. --reloadcmd \"service nginx reload\" After issue/renew, it's used to reload the server. @@ -4807,6 +4807,7 @@ Parameters: --stopRenewOnError, -se Only valid for '--renew-all' command. Stop if one cert has error in renewal. --insecure Do not check the server certificate, in some devices, the api server's certificate may not be trusted. --ca-bundle Specifices the path to the CA certificate bundle to verify api server's certificate. + --ca-path Specifies directory containing CA certificates in PEM format, used by wget or curl. --nocron Only valid for '--install' command, which means: do not install the default cron job. In this case, the certs will not be renewed automatically. --ecc Specifies to use the ECC cert. Valid for '--install-cert', '--renew', '--revoke', '--toPkcs' and '--createCSR' --csr Specifies the input csr. From 4ddafb8e84cc2c647f788a58f0ba148433dfa7e3 Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 23 Mar 2017 14:14:28 -0500 Subject: [PATCH 030/115] Added Infoblox reference --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 64609067..014f0db3 100644 --- a/README.md +++ b/README.md @@ -310,6 +310,7 @@ You don't have to do anything manually! 1. Knot DNS API 1. DigitalOcean API (native) 1. ClouDNS.net API +1. Infoblox NIOS API (https://www.infoblox.com/) **More APIs coming soon...** From d03929507058c13ce81a925a77b2320fcb9bb147 Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 23 Mar 2017 14:15:17 -0500 Subject: [PATCH 031/115] Added Infoblox references --- dnsapi/README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index d419d5ed..4543d9b4 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -421,6 +421,23 @@ Ok, let's issue a cert now: acme.sh --issue --dns dns_cloudns -d example.com -d www.example.com ``` +## 22. Use Infoblox API + +First you need to create/obtain API credentials on your Infoblox appliance. + +``` +export Infoblox_Creds="username:password" +export Infoblox_Server="ip or fqdn of infoblox appliance" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_infoblox -d example.com -d www.example.com +``` + +Note: This script will automatically create and delete the ephemeral txt record. +The `Infoblox_Creds` and `Infoblox_Server` 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. From b0561058c6a19e700d19ec9233d8d656f7cbed46 Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 23 Mar 2017 14:16:31 -0500 Subject: [PATCH 032/115] Infoblox API --- dnsapi/dns_infoblox.sh | 93 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 dnsapi/dns_infoblox.sh diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh new file mode 100644 index 00000000..e71c90c9 --- /dev/null +++ b/dnsapi/dns_infoblox.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env sh + +dns_infoblox_add() { + + ## Nothing to see here, just some housekeeping + fulldomain=$1 + txtvalue=$2 + baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue" + + _info "Using Infoblox API" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + ## Check for the credentials + if [ -z "$Infoblox_Creds" ] || [ -z "$Infoblox_Server" ]; then + Infoblox_Creds="" + Infoblox_Server="" + _err "You didn't specify the credentials or server yet (Infoblox_Creds and Infoblox_Server)." + _err "Please set them via EXPORT ([username:password] and [ip or hostname]) and try again." + return 1 + fi + + ## Save the credentials to the account file + _saveaccountconf Infoblox_Creds "$Infoblox_Creds" + _saveaccountconf Infoblox_Server "$Infoblox_Server" + + ## Base64 encode the credentials + Infoblox_CredsEncoded=$(printf "$Infoblox_Creds" | _base64) + + ## Construct the HTTP Authorization header + export _H1="Accept-Language:en-US" + export _H2="Authorization: Basic $Infoblox_CredsEncoded" + + ## Add the challenge record to the Infoblox grid member + result=$(_post "" "$baseurlnObject" "" "POST") + + ## Let's see if we get something intelligible back from the unit + if echo "$result" | egrep 'record:txt/.*:.*/default'; then + _info "Successfully created the txt record" + return 0 + else + _err "Error encountered during record addition" + _err "$result" + return 1 + fi + +} + +dns_infoblox_rm() { + + ## Nothing to see here, just some housekeeping + fulldomain=$1 + txtvalue=$2 + + _info "Using Infoblox API" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + ## Base64 encode the credentials + Infoblox_CredsEncoded=$(printf "$Infoblox_Creds" | _base64) + + ## Construct the HTTP Authorization header + export _H1="Accept-Language:en-US" + export _H2="Authorization: Basic $Infoblox_CredsEncoded" + + ## Does the record exist? Let's check. + baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&_return_type=xml-pretty" + result=$(_get "$baseurlnObject") + + ## Let's see if we get something intelligible back from the grid + if echo "$result" | egrep 'record:txt/.*:.*/default'; then + ## Extract the object reference + objRef=$(_egrep_o 'record:txt/.*:.*/default' <<<$result) + objRmUrl="https://$Infoblox_Server/wapi/v2.2.2/$objRef" + ## Delete them! All the stale records! + rmResult=$(_post "" "$objRmUrl" "" "DELETE") + ## Let's see if that worked + if echo "$rmResult" | egrep 'record:txt/.*:.*/default'; then + _info "Successfully deleted $objRef" + return 0 + else + _err "Error occurred during txt record delete" + _err "$rmResult" + return 1 + fi + else + _err "Record to delete didn't match an existing record" + _err "$result" + return 1 + fi +} + +#################### Private functions below ################################## From b1e4a7c61570137cf04901f3f92e3f4c8449b023 Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 23 Mar 2017 14:34:29 -0500 Subject: [PATCH 033/115] Fixed (hopefully) TravisCI errors --- dnsapi/dns_infoblox.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh index e71c90c9..347c69e7 100644 --- a/dnsapi/dns_infoblox.sh +++ b/dnsapi/dns_infoblox.sh @@ -25,7 +25,7 @@ dns_infoblox_add() { _saveaccountconf Infoblox_Server "$Infoblox_Server" ## Base64 encode the credentials - Infoblox_CredsEncoded=$(printf "$Infoblox_Creds" | _base64) + Infoblox_CredsEncoded=$(echo -n "$Infoblox_Creds" | _base64) ## Construct the HTTP Authorization header export _H1="Accept-Language:en-US" @@ -57,7 +57,7 @@ dns_infoblox_rm() { _debug txtvalue "$txtvalue" ## Base64 encode the credentials - Infoblox_CredsEncoded=$(printf "$Infoblox_Creds" | _base64) + Infoblox_CredsEncoded=$(echo -n "$Infoblox_Creds" | _base64) ## Construct the HTTP Authorization header export _H1="Accept-Language:en-US" @@ -70,7 +70,7 @@ dns_infoblox_rm() { ## Let's see if we get something intelligible back from the grid if echo "$result" | egrep 'record:txt/.*:.*/default'; then ## Extract the object reference - objRef=$(_egrep_o 'record:txt/.*:.*/default' <<<$result) + objRef=$(_egrep_o 'record:txt/.*:.*/default' <<< $result) objRmUrl="https://$Infoblox_Server/wapi/v2.2.2/$objRef" ## Delete them! All the stale records! rmResult=$(_post "" "$objRmUrl" "" "DELETE") From 2c37d946111034eacf23b20a38a511ab131b2f3c Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 23 Mar 2017 14:40:09 -0500 Subject: [PATCH 034/115] More bs --- dnsapi/dns_infoblox.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh index 347c69e7..975dc771 100644 --- a/dnsapi/dns_infoblox.sh +++ b/dnsapi/dns_infoblox.sh @@ -70,7 +70,7 @@ dns_infoblox_rm() { ## Let's see if we get something intelligible back from the grid if echo "$result" | egrep 'record:txt/.*:.*/default'; then ## Extract the object reference - objRef=$(_egrep_o 'record:txt/.*:.*/default' <<< $result) + objRef=$(_egrep_o 'record:txt/.*:.*/default' <<<$result) objRmUrl="https://$Infoblox_Server/wapi/v2.2.2/$objRef" ## Delete them! All the stale records! rmResult=$(_post "" "$objRmUrl" "" "DELETE") From 7dc548b4b8764f8d8f36898a9f19db1ba2adb92e Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 23 Mar 2017 15:06:37 -0500 Subject: [PATCH 035/115] MORE bs --- dnsapi/dns_infoblox.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh index 975dc771..8b9f9370 100644 --- a/dnsapi/dns_infoblox.sh +++ b/dnsapi/dns_infoblox.sh @@ -25,7 +25,7 @@ dns_infoblox_add() { _saveaccountconf Infoblox_Server "$Infoblox_Server" ## Base64 encode the credentials - Infoblox_CredsEncoded=$(echo -n "$Infoblox_Creds" | _base64) + Infoblox_CredsEncoded=$(printf "%b" "$Infoblox_Creds" | _base64) ## Construct the HTTP Authorization header export _H1="Accept-Language:en-US" @@ -57,7 +57,7 @@ dns_infoblox_rm() { _debug txtvalue "$txtvalue" ## Base64 encode the credentials - Infoblox_CredsEncoded=$(echo -n "$Infoblox_Creds" | _base64) + Infoblox_CredsEncoded=$(printf "%b" "$Infoblox_Creds" | _base64) ## Construct the HTTP Authorization header export _H1="Accept-Language:en-US" @@ -70,7 +70,7 @@ dns_infoblox_rm() { ## Let's see if we get something intelligible back from the grid if echo "$result" | egrep 'record:txt/.*:.*/default'; then ## Extract the object reference - objRef=$(_egrep_o 'record:txt/.*:.*/default' <<<$result) + objRef=$(printf "%b" "$result" | _egrep_o 'record:txt/.*:.*/default') objRmUrl="https://$Infoblox_Server/wapi/v2.2.2/$objRef" ## Delete them! All the stale records! rmResult=$(_post "" "$objRmUrl" "" "DELETE") From 1424e8a2de3f43947045a4861f3c3f9634d19748 Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 23 Mar 2017 20:20:04 -0500 Subject: [PATCH 036/115] Added attribution --- dnsapi/dns_infoblox.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh index 8b9f9370..3846e62e 100644 --- a/dnsapi/dns_infoblox.sh +++ b/dnsapi/dns_infoblox.sh @@ -1,5 +1,9 @@ #!/usr/bin/env sh +## Infoblox API integration by Jason Keller and Elijah Tenai +## +## Report any bugs via https://github.com/jasonkeller/acme.sh + dns_infoblox_add() { ## Nothing to see here, just some housekeeping From 8afd31902fdff51ee3ce66fe124892d8cb232b3e Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:24:26 +0000 Subject: [PATCH 037/115] spelling: application --- dnsapi/dns_ovh.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index faf5b42b..71642bd4 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -#Applcation Key +#Application Key #OVH_AK="sdfsdfsdfljlbjkljlkjsdfoiwje" # #Application Secret From 3d22708f670ebcf56325631d25ca3e769f9cf8ef Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:24:38 +0000 Subject: [PATCH 038/115] spelling: automatically --- dnsapi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 4543d9b4..9eb77915 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -302,7 +302,7 @@ acme.sh --issue --dns dns_freedns -d example.com -d www.example.com ``` Note that you cannot use acme.sh automatic DNS validation for FreeDNS public domains or for a subdomain that -you create under a FreeDNS public domain. You must own the top level domain in order to automaitcally +you create under a FreeDNS public domain. You must own the top level domain in order to automatically validate with acme.sh at FreeDNS. ## 16. Use cyon.ch From bcbecff6f6d4fed138a63255ae344bb70610d907 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:24:52 +0000 Subject: [PATCH 039/115] spelling: certificate --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 014f0db3..7a79bed4 100644 --- a/README.md +++ b/README.md @@ -329,7 +329,7 @@ Just set the `length` parameter with a prefix `ec-`. For example: -### Single domain ECC cerfiticate +### Single domain ECC certificate ```bash acme.sh --issue -w /home/wwwroot/example.com -d example.com --keylength ec-256 From 291c97dc81aeabacd40f14eda71d98bfa3f7a112 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:25:04 +0000 Subject: [PATCH 040/115] spelling: challenge --- dnsapi/dns_freedns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index f30c8958..14622ad1 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -112,7 +112,7 @@ dns_freedns_add() { # not produce accurate results as the value field is truncated # on this webpage. To get full value we would need to load # another page. However we don't really need this so long as - # there is only one TXT record for the acme chalenge subdomain. + # there is only one TXT record for the acme challenge subdomain. DNSvalue="$(echo "$line" | cut -d ',' -f 4 | sed 's/^[^"]*"//;s/".*//;s/<\/td>.*//')" if [ $found != 0 ]; then break From 9b2aa974ba57d9953a18ee218468c253770a34a0 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:25:31 +0000 Subject: [PATCH 041/115] spelling: changed --- dnsapi/dns_freedns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 14622ad1..7c1f009e 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -65,7 +65,7 @@ dns_freedns_add() { htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")" if [ "$?" != "0" ]; then if [ "$using_cached_cookies" = "true" ]; then - _err "Has your FreeDNS username and password channged? If so..." + _err "Has your FreeDNS username and password changed? If so..." _err "Please export as FREEDNS_User / FREEDNS_Password and try again." fi return 1 From b54ce3107897f60d784da78c29c8e2faf75df703 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:25:23 +0000 Subject: [PATCH 042/115] spelling: changing --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 244f72e3..bbefb6bc 100755 --- a/acme.sh +++ b/acme.sh @@ -3490,7 +3490,7 @@ issue() { _exec_err >/dev/null 2>&1 fi else - _debug "not chaning owner/group of webroot" + _debug "not changing owner/group of webroot" fi fi From 4cedbf80df52aeb39489caeb4646a9625f17ea8a Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:26:20 +0000 Subject: [PATCH 043/115] spelling: delimiter --- deploy/kong.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/kong.sh b/deploy/kong.sh index 3b9c5c79..80a4b02d 100755 --- a/deploy/kong.sh +++ b/deploy/kong.sh @@ -43,7 +43,7 @@ kong_deploy() { #Save kong url if it's succesful (First run case) _saveaccountconf KONG_URL "$KONG_URL" #Generate DEIM - delim="-----MultipartDelimeter$(date "+%s%N")" + delim="-----MultipartDelimiter$(date "+%s%N")" nl="\015\012" #Set Header _H1="Content-Type: multipart/form-data; boundary=$delim" From 506f36b26ddc0dae35a5bf11316ae0fbe53c4fda Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:26:43 +0000 Subject: [PATCH 044/115] spelling: embedded --- dnsapi/dns_pdns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_pdns.sh b/dnsapi/dns_pdns.sh index ebc02949..7d807c81 100755 --- a/dnsapi/dns_pdns.sh +++ b/dnsapi/dns_pdns.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -#PowerDNS Emdedded API +#PowerDNS Embedded API #https://doc.powerdns.com/md/httpapi/api_spec/ # #PDNS_Url="http://ns.example.com:8081" From 39f3239682b98a9ac9a83a646110dd24f7aba728 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:26:55 +0000 Subject: [PATCH 045/115] spelling: following --- dnsapi/dns_freedns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 7c1f009e..6383c589 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -10,7 +10,7 @@ # ######## Public functions ##################### -# Export FreeDNS userid and password in folowing variables... +# Export FreeDNS userid and password in following variables... # FREEDNS_User=username # FREEDNS_Password=password # login cookie is saved in acme account config file so userid / pw From d39b1082746f3b7672dfe34311704163ffbe62f1 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:27:04 +0000 Subject: [PATCH 046/115] spelling: function --- dnsapi/dns_freedns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 6383c589..aebbc68c 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -192,7 +192,7 @@ dns_freedns_rm() { # Need to read cookie from conf file again in case new value set # during login to FreeDNS when TXT record was created. - # acme.sh does not have a _readaccountconf() fuction + # acme.sh does not have a _readaccountconf() function FREEDNS_COOKIE="$(_read_conf "$ACCOUNT_CONF_PATH" "FREEDNS_COOKIE")" _debug "FreeDNS login cookies: $FREEDNS_COOKIE" From 357b514bc903e2e2c8acf500f760a8c7027df3ec Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:28:04 +0000 Subject: [PATCH 047/115] spelling: lines --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index bbefb6bc..22cd412c 100755 --- a/acme.sh +++ b/acme.sh @@ -879,7 +879,7 @@ _sign() { if ! _signedECText="$($_sign_openssl | $ACME_OPENSSL_BIN asn1parse -inform DER)"; then _err "Sign failed: $_sign_openssl" _err "Key file: $keyfile" - _err "Key content:$(wc -l <"$keyfile") lises" + _err "Key content:$(wc -l <"$keyfile") lines" return 1 fi _debug3 "_signedECText" "$_signedECText" From 84a6730b1a05edd91f74cd96ad902c88b8e373b7 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:28:37 +0000 Subject: [PATCH 048/115] spelling: obtain --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 22cd412c..d686834a 100755 --- a/acme.sh +++ b/acme.sh @@ -4812,7 +4812,7 @@ Parameters: --ecc Specifies to use the ECC cert. Valid for '--install-cert', '--renew', '--revoke', '--toPkcs' and '--createCSR' --csr Specifies the input csr. --pre-hook Command to be run before obtaining any certificates. - --post-hook Command to be run after attempting to obtain/renew certificates. No matter the obain/renew is success or failed. + --post-hook Command to be run after attempting to obtain/renew certificates. No matter the obtain/renew is success or failed. --renew-hook Command to be run once for each successfully renewed certificate. --deploy-hook The hook file to deploy cert --ocsp-must-staple, --ocsp Generate ocsp must Staple extension. From 00b34eb2a4adafde6dd338ceb03bc551b3519f73 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:28:57 +0000 Subject: [PATCH 049/115] spelling: occurred --- deploy/kong.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/kong.sh b/deploy/kong.sh index 80a4b02d..e1873f35 100755 --- a/deploy/kong.sh +++ b/deploy/kong.sh @@ -72,7 +72,7 @@ kong_deploy() { response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins/$ssl_uuid" "" "PATCH") fi if ! [ "$(echo "$response" | _egrep_o "ssl")" = "ssl" ]; then - _err "An error occured with cert upload. Check response:" + _err "An error occurred with cert upload. Check response:" _err "$response" return 1 fi From df14085ec8ab262020c35d235d29c8aeda4e5af5 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:29:11 +0000 Subject: [PATCH 050/115] spelling: oops --- deploy/exim4.sh | 4 ++-- deploy/vsftpd.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/deploy/exim4.sh b/deploy/exim4.sh index bf92b438..573f762b 100644 --- a/deploy/exim4.sh +++ b/deploy/exim4.sh @@ -79,7 +79,7 @@ exim4_deploy() { _info "Restore conf success" eval "$_reload" else - _err "Opps, error restore exim4 conf, please report bug to us." + _err "Oops, error restore exim4 conf, please report bug to us." fi return 1 fi @@ -105,7 +105,7 @@ exim4_deploy() { _info "Restore conf success" eval "$_reload" else - _err "Opps, error restore exim4 conf, please report bug to us." + _err "Oops, error restore exim4 conf, please report bug to us." fi return 1 fi diff --git a/deploy/vsftpd.sh b/deploy/vsftpd.sh index 1c6410a6..ed44e709 100644 --- a/deploy/vsftpd.sh +++ b/deploy/vsftpd.sh @@ -76,7 +76,7 @@ vsftpd_deploy() { _info "Restore conf success" eval "$_reload" else - _err "Opps, error restore vsftpd conf, please report bug to us." + _err "Oops, error restore vsftpd conf, please report bug to us." fi return 1 fi @@ -102,7 +102,7 @@ vsftpd_deploy() { _info "Restore conf success" eval "$_reload" else - _err "Opps, error restore vsftpd conf, please report bug to us." + _err "Oops, error restore vsftpd conf, please report bug to us." fi return 1 fi From 61a48a5b9f775c1f7eaa56aefcb116881f458b85 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:29:30 +0000 Subject: [PATCH 051/115] spelling: please --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d686834a..91919e76 100755 --- a/acme.sh +++ b/acme.sh @@ -2385,7 +2385,7 @@ _setApache() { _debug "Backup apache config file" "$httpdconf" if ! cp "$httpdconf" "$APACHE_CONF_BACKUP_DIR/"; then _err "Can not backup apache config file, so abort. Don't worry, the apache config is not changed." - _err "This might be a bug of $PROJECT_NAME , pleae report issue: $PROJECT" + _err "This might be a bug of $PROJECT_NAME , please report issue: $PROJECT" return 1 fi _info "JFYI, Config file $httpdconf is backuped to $APACHE_CONF_BACKUP_DIR/$httpdconfname" From 849bed4bef08cbf303f7a97129bea804424af3da Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:30:03 +0000 Subject: [PATCH 052/115] spelling: requires --- dnsapi/dns_dgon.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_dgon.sh b/dnsapi/dns_dgon.sh index 9ceede44..7e1f1fec 100755 --- a/dnsapi/dns_dgon.sh +++ b/dnsapi/dns_dgon.sh @@ -158,7 +158,7 @@ _get_base_domain() { export _H2="Authorization: Bearer $DO_API_KEY" _debug DO_API_KEY "$DO_API_KEY" ## get URL for the list of domains - ## havent seen this request paginated, tested with 18 domains (more requres manual requests with DO) + ## havent seen this request paginated, tested with 18 domains (more requires manual requests with DO) DOMURL="https://api.digitalocean.com/v2/domains" ## get the domain list (DO gives basically a full XFER!) From 997c517ba270727c7fa220e67a8680245c7b1b48 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:30:15 +0000 Subject: [PATCH 053/115] spelling: return --- dnsapi/dns_freedns.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index aebbc68c..6c8f95a9 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -53,7 +53,7 @@ dns_freedns_add() { i="$(_math "$i" - 1)" sub_domain="$(echo "$fulldomain" | cut -d. -f -"$i")" - # Sometimes FreeDNS does not reurn the subdomain page but rather + # Sometimes FreeDNS does not return the subdomain page but rather # returns a page regarding becoming a premium member. This usually # happens after a period of inactivity. Immediately trying again # returns the correct subdomain page. So, we will try twice to @@ -196,7 +196,7 @@ dns_freedns_rm() { FREEDNS_COOKIE="$(_read_conf "$ACCOUNT_CONF_PATH" "FREEDNS_COOKIE")" _debug "FreeDNS login cookies: $FREEDNS_COOKIE" - # Sometimes FreeDNS does not reurn the subdomain page but rather + # Sometimes FreeDNS does not return the subdomain page but rather # returns a page regarding becoming a premium member. This usually # happens after a period of inactivity. Immediately trying again # returns the correct subdomain page. So, we will try twice to From 0d6ce9f97773fce4ed811e7bfe2993fde48b739f Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:30:26 +0000 Subject: [PATCH 054/115] spelling: satisfy --- dnsapi/dns_cyon.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index c096d8b0..d7ad712c 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -50,7 +50,7 @@ _cyon_load_credentials() { fi if [ -z "${CY_Username}" ] || [ -z "${CY_Password}" ]; then - # Dummy entries to satify script checker. + # Dummy entries to satisfy script checker. CY_Username="" CY_Password="" CY_OTP_Secret="" From 00777a10ae38de2b3d59c94be3f9ebed098a9cd4 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:30:43 +0000 Subject: [PATCH 055/115] spelling: security --- dnsapi/dns_freedns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 6c8f95a9..77e4322c 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -341,7 +341,7 @@ _freedns_add_txt_record() { return 1 elif _contains "$htmlpage" "security code was incorrect"; then _debug "$htmlpage" - _err "FreeDNS failed to add TXT record for $subdomain as FreeDNS requested seurity code" + _err "FreeDNS failed to add TXT record for $subdomain as FreeDNS requested security code" _err "Note that you cannot use automatic DNS validation for FreeDNS public domains" return 1 fi From f3c984281c927cf37cb61a556670ffb36dd0e7a0 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:30:58 +0000 Subject: [PATCH 056/115] spelling: specified --- dnsapi/dns_gandi_livedns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_gandi_livedns.sh b/dnsapi/dns_gandi_livedns.sh index 41f42980..28b8f99d 100755 --- a/dnsapi/dns_gandi_livedns.sh +++ b/dnsapi/dns_gandi_livedns.sh @@ -19,7 +19,7 @@ dns_gandi_livedns_add() { txtvalue=$2 if [ -z "$GANDI_LIVEDNS_KEY" ]; then - _err "No API key specifed for Gandi LiveDNS." + _err "No API key specified for Gandi LiveDNS." _err "Create your key and export it as GANDI_LIVEDNS_KEY" return 1 fi From 8f73e241755a3ad419245e705bcbb597e9d33c3e Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:31:12 +0000 Subject: [PATCH 057/115] spelling: specifies --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 91919e76..28c0721f 100755 --- a/acme.sh +++ b/acme.sh @@ -4806,7 +4806,7 @@ Parameters: --listraw Only used for '--list' command, list the certs in raw format. --stopRenewOnError, -se Only valid for '--renew-all' command. Stop if one cert has error in renewal. --insecure Do not check the server certificate, in some devices, the api server's certificate may not be trusted. - --ca-bundle Specifices the path to the CA certificate bundle to verify api server's certificate. + --ca-bundle Specifies the path to the CA certificate bundle to verify api server's certificate. --ca-path Specifies directory containing CA certificates in PEM format, used by wget or curl. --nocron Only valid for '--install' command, which means: do not install the default cron job. In this case, the certs will not be renewed automatically. --ecc Specifies to use the ECC cert. Valid for '--install-cert', '--renew', '--revoke', '--toPkcs' and '--createCSR' From 7f32488b781b5b1910839839606c71a5e3a6f69e Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:31:35 +0000 Subject: [PATCH 058/115] spelling: subdomain --- dnsapi/dns_freedns.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 77e4322c..272a1243 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -302,12 +302,12 @@ _freedns_retrieve_subdomain_page() { export _H2="Accept-Language:en-US" url="https://freedns.afraid.org/subdomain/" - _debug "Retrieve subdmoain page from FreeDNS" + _debug "Retrieve subdomain page from FreeDNS" htmlpage="$(_get "$url")" if [ "$?" != "0" ]; then - _err "FreeDNS retrieve subdomins failed bad RC from _get" + _err "FreeDNS retrieve subdomains failed bad RC from _get" return 1 elif [ -z "$htmlpage" ]; then _err "FreeDNS returned empty subdomain page" From f94433e504c7787b93751755f3347455c61dc629 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:32:29 +0000 Subject: [PATCH 059/115] spelling: validation --- acme.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/acme.sh b/acme.sh index 28c0721f..ce5b1dbd 100755 --- a/acme.sh +++ b/acme.sh @@ -2258,16 +2258,16 @@ _initpath() { fi if [ -z "$TLS_CONF" ]; then - TLS_CONF="$DOMAIN_PATH/tls.valdation.conf" + TLS_CONF="$DOMAIN_PATH/tls.validation.conf" fi if [ -z "$TLS_CERT" ]; then - TLS_CERT="$DOMAIN_PATH/tls.valdation.cert" + TLS_CERT="$DOMAIN_PATH/tls.validation.cert" fi if [ -z "$TLS_KEY" ]; then - TLS_KEY="$DOMAIN_PATH/tls.valdation.key" + TLS_KEY="$DOMAIN_PATH/tls.validation.key" fi if [ -z "$TLS_CSR" ]; then - TLS_CSR="$DOMAIN_PATH/tls.valdation.csr" + TLS_CSR="$DOMAIN_PATH/tls.validation.csr" fi } @@ -2883,7 +2883,7 @@ _on_issue_err() { uri=$(echo "$ventry" | cut -d "$sep" -f 3) vtype=$(echo "$ventry" | cut -d "$sep" -f 4) _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) - __trigger_validaton "$uri" "$keyauthorization" + __trigger_validation "$uri" "$keyauthorization" done ) fi @@ -3105,7 +3105,7 @@ __get_domain_new_authz() { } #uri keyAuthorization -__trigger_validaton() { +__trigger_validation() { _debug2 "tigger domain validation." _t_url="$1" _debug2 _t_url "$_t_url" @@ -3531,7 +3531,7 @@ issue() { fi fi - if ! __trigger_validaton "$uri" "$keyauthorization"; then + if ! __trigger_validation "$uri" "$keyauthorization"; then _err "$d:Can not get challenge: $response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup From d0300d4443caf45f0619cba436b40128e09dc71d Mon Sep 17 00:00:00 2001 From: shar0119 Date: Mon, 27 Mar 2017 12:27:21 -0700 Subject: [PATCH 060/115] Changes as requested per Commit 9c90b21 In dnsapi/dns_dynu.sh line 115: export _H1="Authorization: Basic $(printf "%s" "$Dynu_ClientId:$Dynu_Secret" | _base64)" ^-- SC2155: Declare and assign separately to avoid masking return values. --- dnsapi/dns_dynu.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index b12b0bbb..c50c7a18 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -112,7 +112,9 @@ _dynu_rest() { } _dynu_authentication() { - export _H1="Authorization: Basic $(printf "%s" "$Dynu_ClientId:$Dynu_Secret" | _base64)" + realm = "$(printf "%s" "$Dynu_ClientId:$Dynu_Secret" | _base64)" + + export _H1="Authorization: Basic $realm" export _H2="Content-Type: application/json" response="$(_get "$Dynu_EndPoint/oauth2/token")" From cd8fcbf9c63a9a60726fb2bc3a889df55fdf87dd Mon Sep 17 00:00:00 2001 From: shar0119 Date: Mon, 27 Mar 2017 12:38:12 -0700 Subject: [PATCH 061/115] Spaces in assignment removed. --- dnsapi/dns_dynu.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index c50c7a18..19a24471 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -112,7 +112,7 @@ _dynu_rest() { } _dynu_authentication() { - realm = "$(printf "%s" "$Dynu_ClientId:$Dynu_Secret" | _base64)" + realm="$(printf "%s" "$Dynu_ClientId:$Dynu_Secret" | _base64)" export _H1="Authorization: Basic $realm" export _H2="Content-Type: application/json" From b7b934913ef0375700e3808801db5565b36ed193 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Mon, 27 Mar 2017 13:39:31 -0700 Subject: [PATCH 062/115] Removed unnecessary spaces --- dnsapi/dns_dynu.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index 19a24471..b81840d0 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -42,7 +42,7 @@ dns_dynu_add() { if ! _get_root "$fulldomain"; then _err "Invalid domain" return 1 - fi + fi _debug _node "$_node" _debug _domain_name "$_domain_name" @@ -83,7 +83,7 @@ _get_root() { _domain_name=$(printf "%s" "$response" | tr -d "{}" | cut -d , -f 1 | cut -d : -f 2 | cut -d '"' -f 2) _node=$(printf "%s" "$response" | tr -d "{}" | cut -d , -f 3 | cut -d : -f 2 | cut -d '"' -f 2) - return 0 + return 0 } _dynu_rest() { @@ -113,7 +113,7 @@ _dynu_rest() { _dynu_authentication() { realm="$(printf "%s" "$Dynu_ClientId:$Dynu_Secret" | _base64)" - + export _H1="Authorization: Basic $realm" export _H2="Content-Type: application/json" @@ -128,7 +128,7 @@ _dynu_authentication() { if _contains "$Dynu_Token" "null"; then Dynu_Token="" fi - + _debug2 response "$response" return 0 } From e137792efdb0986192b0b96cf728e670c4719c1b Mon Sep 17 00:00:00 2001 From: shar0119 Date: Tue, 28 Mar 2017 08:11:04 -0700 Subject: [PATCH 063/115] Commented out Dynu_ClientId and Dynu_Secret --- dnsapi/dns_dynu.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index b81840d0..03a45c1a 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -1,10 +1,10 @@ #!/usr/bin/env sh #Client ID -Dynu_ClientId="0b71cae7-a099-4f6b-8ddf-94571cdb760d" +#Dynu_ClientId="0b71cae7-a099-4f6b-8ddf-94571cdb760d" # #Secret -Dynu_Secret="aCUEY4BDCV45KI8CSIC3sp2LKQ9" +#Dynu_Secret="aCUEY4BDCV45KI8CSIC3sp2LKQ9" # #Token Dynu_Token="" From 58d4c74b0bc09e4f6480ad2845a81df8b882da61 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 29 Mar 2017 09:10:42 +0800 Subject: [PATCH 064/115] export Le_Domain for reloadcmd fix https://github.com/Neilpang/acme.sh/issues/558#issuecomment-289926193 --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index ce5b1dbd..28344c6d 100755 --- a/acme.sh +++ b/acme.sh @@ -4134,6 +4134,7 @@ _installcert() { export CERT_KEY_PATH export CA_CERT_PATH export CERT_FULLCHAIN_PATH + export Le_Domain cd "$DOMAIN_PATH" && eval "$_reload_cmd" ); then _info "$(__green "Reload success")" From 6cf7be4b7e8899e4ca1658027af535b40485afd3 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 29 Mar 2017 09:16:22 +0800 Subject: [PATCH 065/115] fix https://github.com/Neilpang/acme.sh/issues/751 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 28344c6d..7cb36afb 100755 --- a/acme.sh +++ b/acme.sh @@ -340,7 +340,7 @@ _hasfield() { _sep="," fi - for f in $(echo "$_str" | tr ',' ' '); do + for f in $(echo "$_str" | tr "$_sep" ' '); do if [ "$f" = "$_field" ]; then _debug2 "'$_str' contains '$_field'" return 0 #contains ok From d8ba26e664242338b4e10ae5c50320ef0122922d Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 30 Mar 2017 21:16:25 +0800 Subject: [PATCH 066/115] add retry for issuer cert --- acme.sh | 99 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 60 insertions(+), 39 deletions(-) diff --git a/acme.sh b/acme.sh index 7cb36afb..3bd9b024 100755 --- a/acme.sh +++ b/acme.sh @@ -138,8 +138,8 @@ _printargs() { _dlg_versions() { echo "Diagnosis versions: " echo "openssl:$ACME_OPENSSL_BIN" - if _exists "$ACME_OPENSSL_BIN"; then - $ACME_OPENSSL_BIN version 2>&1 + if _exists "${ACME_OPENSSL_BIN:-openssl}"; then + ${ACME_OPENSSL_BIN:-openssl} version 2>&1 else echo "$ACME_OPENSSL_BIN doesn't exists." fi @@ -790,19 +790,19 @@ _base64() { [ "" ] #urgly if [ "$1" ]; then _debug3 "base64 multiline:'$1'" - $ACME_OPENSSL_BIN base64 -e + ${ACME_OPENSSL_BIN:-openssl} base64 -e else _debug3 "base64 single line." - $ACME_OPENSSL_BIN base64 -e | tr -d '\r\n' + ${ACME_OPENSSL_BIN:-openssl} base64 -e | tr -d '\r\n' fi } #Usage: multiline _dbase64() { if [ "$1" ]; then - $ACME_OPENSSL_BIN base64 -d -A + ${ACME_OPENSSL_BIN:-openssl} base64 -d -A else - $ACME_OPENSSL_BIN base64 -d + ${ACME_OPENSSL_BIN:-openssl} base64 -d fi } @@ -819,9 +819,9 @@ _digest() { if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ] || [ "$alg" = "md5" ]; then if [ "$outputhex" ]; then - $ACME_OPENSSL_BIN dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' ' + ${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' ' else - $ACME_OPENSSL_BIN dgst -"$alg" -binary | _base64 + ${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -binary | _base64 fi else _err "$alg is not supported yet" @@ -844,9 +844,9 @@ _hmac() { if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then if [ "$outputhex" ]; then - ($ACME_OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" 2>/dev/null || $ACME_OPENSSL_BIN dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)") | cut -d = -f 2 | tr -d ' ' + (${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" 2>/dev/null || ${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)") | cut -d = -f 2 | tr -d ' ' else - $ACME_OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" -binary 2>/dev/null || $ACME_OPENSSL_BIN dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)" -binary + ${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" -binary 2>/dev/null || ${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)" -binary fi else _err "$alg is not supported yet" @@ -865,7 +865,7 @@ _sign() { return 1 fi - _sign_openssl="$ACME_OPENSSL_BIN dgst -sign $keyfile " + _sign_openssl="${ACME_OPENSSL_BIN:-openssl} dgst -sign $keyfile " if [ "$alg" = "sha256" ]; then _sign_openssl="$_sign_openssl -$alg" else @@ -876,7 +876,7 @@ _sign() { if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then $_sign_openssl | _base64 elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then - if ! _signedECText="$($_sign_openssl | $ACME_OPENSSL_BIN asn1parse -inform DER)"; then + if ! _signedECText="$($_sign_openssl | ${ACME_OPENSSL_BIN:-openssl} asn1parse -inform DER)"; then _err "Sign failed: $_sign_openssl" _err "Key file: $keyfile" _err "Key content:$(wc -l <"$keyfile") lines" @@ -948,10 +948,10 @@ _createkey() { if _isEccKey "$length"; then _debug "Using ec name: $eccname" - $ACME_OPENSSL_BIN ecparam -name "$eccname" -genkey 2>/dev/null >"$f" + ${ACME_OPENSSL_BIN:-openssl} ecparam -name "$eccname" -genkey 2>/dev/null >"$f" else _debug "Using RSA: $length" - $ACME_OPENSSL_BIN genrsa "$length" 2>/dev/null >"$f" + ${ACME_OPENSSL_BIN:-openssl} genrsa "$length" 2>/dev/null >"$f" fi if [ "$?" != "0" ]; then @@ -1038,9 +1038,9 @@ _createcsr() { _csr_cn="$(_idn "$domain")" _debug2 _csr_cn "$_csr_cn" if _contains "$(uname -a)" "MINGW"; then - $ACME_OPENSSL_BIN req -new -sha256 -key "$csrkey" -subj "//CN=$_csr_cn" -config "$csrconf" -out "$csr" + ${ACME_OPENSSL_BIN:-openssl} req -new -sha256 -key "$csrkey" -subj "//CN=$_csr_cn" -config "$csrconf" -out "$csr" else - $ACME_OPENSSL_BIN req -new -sha256 -key "$csrkey" -subj "/CN=$_csr_cn" -config "$csrconf" -out "$csr" + ${ACME_OPENSSL_BIN:-openssl} req -new -sha256 -key "$csrkey" -subj "/CN=$_csr_cn" -config "$csrconf" -out "$csr" fi } @@ -1052,7 +1052,7 @@ _signcsr() { cert="$4" _debug "_signcsr" - _msg="$($ACME_OPENSSL_BIN x509 -req -days 365 -in "$csr" -signkey "$key" -extensions v3_req -extfile "$conf" -out "$cert" 2>&1)" + _msg="$(${ACME_OPENSSL_BIN:-openssl} x509 -req -days 365 -in "$csr" -signkey "$key" -extensions v3_req -extfile "$conf" -out "$cert" 2>&1)" _ret="$?" _debug "$_msg" return $_ret @@ -1065,7 +1065,7 @@ _readSubjectFromCSR() { _usage "_readSubjectFromCSR mycsr.csr" return 1 fi - $ACME_OPENSSL_BIN req -noout -in "$_csrfile" -subject | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n' + ${ACME_OPENSSL_BIN:-openssl} req -noout -in "$_csrfile" -subject | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n' } #_csrfile @@ -1080,7 +1080,7 @@ _readSubjectAltNamesFromCSR() { _csrsubj="$(_readSubjectFromCSR "$_csrfile")" _debug _csrsubj "$_csrsubj" - _dnsAltnames="$($ACME_OPENSSL_BIN req -noout -text -in "$_csrfile" | grep "^ *DNS:.*" | tr -d ' \n')" + _dnsAltnames="$(${ACME_OPENSSL_BIN:-openssl} req -noout -text -in "$_csrfile" | grep "^ *DNS:.*" | tr -d ' \n')" _debug _dnsAltnames "$_dnsAltnames" if _contains "$_dnsAltnames," "DNS:$_csrsubj,"; then @@ -1101,7 +1101,7 @@ _readKeyLengthFromCSR() { return 1 fi - _outcsr="$($ACME_OPENSSL_BIN req -noout -text -in "$_csrfile")" + _outcsr="$(${ACME_OPENSSL_BIN:-openssl} req -noout -text -in "$_csrfile")" if _contains "$_outcsr" "Public Key Algorithm: id-ecPublicKey"; then _debug "ECC CSR" echo "$_outcsr" | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' ' @@ -1159,9 +1159,9 @@ toPkcs() { _initpath "$domain" "$_isEcc" if [ "$pfxPassword" ]; then - $ACME_OPENSSL_BIN pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" -password "pass:$pfxPassword" + ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" -password "pass:$pfxPassword" else - $ACME_OPENSSL_BIN pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" + ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" fi if [ "$?" = "0" ]; then @@ -1183,7 +1183,7 @@ toPkcs8() { _initpath "$domain" "$_isEcc" - $ACME_OPENSSL_BIN pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in "$CERT_KEY_PATH" -out "$CERT_PKCS8_PATH" + ${ACME_OPENSSL_BIN:-openssl} pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in "$CERT_KEY_PATH" -out "$CERT_PKCS8_PATH" if [ "$?" = "0" ]; then _info "Success, $CERT_PKCS8_PATH" @@ -1344,7 +1344,7 @@ _calcjwk() { if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then _debug "RSA key" - pub_exp=$($ACME_OPENSSL_BIN rsa -in "$keyfile" -noout -text | grep "^publicExponent:" | cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1) + pub_exp=$(${ACME_OPENSSL_BIN:-openssl} rsa -in "$keyfile" -noout -text | grep "^publicExponent:" | cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1) if [ "${#pub_exp}" = "5" ]; then pub_exp=0$pub_exp fi @@ -1353,7 +1353,7 @@ _calcjwk() { e=$(echo "$pub_exp" | _h2b | _base64) _debug3 e "$e" - modulus=$($ACME_OPENSSL_BIN rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2) + modulus=$(${ACME_OPENSSL_BIN:-openssl} rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2) _debug3 modulus "$modulus" n="$(printf "%s" "$modulus" | _h2b | _base64 | _url_replace)" _debug3 n "$n" @@ -1366,12 +1366,12 @@ _calcjwk() { JWK_HEADERPLACE_PART2='", "alg": "RS256", "jwk": '$jwk'}' elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then _debug "EC key" - crv="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")" + crv="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")" _debug3 crv "$crv" if [ -z "$crv" ]; then _debug "Let's try ASN1 OID" - crv_oid="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep "^ASN1 OID:" | cut -d ":" -f 2 | tr -d " \r\n")" + crv_oid="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep "^ASN1 OID:" | cut -d ":" -f 2 | tr -d " \r\n")" _debug3 crv_oid "$crv_oid" case "${crv_oid}" in "prime256v1") @@ -1391,15 +1391,15 @@ _calcjwk() { _debug3 crv "$crv" fi - pubi="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)" + pubi="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)" pubi=$(_math "$pubi" + 1) _debug3 pubi "$pubi" - pubj="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)" + pubj="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)" pubj=$(_math "$pubj" - 1) _debug3 pubj "$pubj" - pubtext="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")" + pubtext="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")" _debug3 pubtext "$pubtext" xlen="$(printf "%s" "$pubtext" | tr -d ':' | wc -c)" @@ -2017,7 +2017,7 @@ _starttlsserver() { return 1 fi - __S_OPENSSL="$ACME_OPENSSL_BIN s_server -cert $TLS_CERT -key $TLS_KEY " + __S_OPENSSL="${ACME_OPENSSL_BIN:-openssl} s_server -cert $TLS_CERT -key $TLS_KEY " if [ "$opaddr" ]; then __S_OPENSSL="$__S_OPENSSL -accept $opaddr:$port" else @@ -3635,6 +3635,7 @@ issue() { _rcert="$response" Le_LinkCert="$(grep -i '^Location.*$' "$HTTP_HEADER" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)" + _debug "Le_LinkCert" "$Le_LinkCert" _savedomainconf "Le_LinkCert" "$Le_LinkCert" if [ "$Le_LinkCert" ]; then @@ -3681,16 +3682,34 @@ issue() { if ! _contains "$Le_LinkIssuer" ":"; then Le_LinkIssuer="$API$Le_LinkIssuer" fi - + _debug Le_LinkIssuer "$Le_LinkIssuer" _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" if [ "$Le_LinkIssuer" ]; then - echo "$BEGIN_CERT" >"$CA_CERT_PATH" - _get "$Le_LinkIssuer" | _base64 "multiline" >>"$CA_CERT_PATH" - echo "$END_CERT" >>"$CA_CERT_PATH" - _info "The intermediate CA cert is in $(__green " $CA_CERT_PATH ")" - cat "$CA_CERT_PATH" >>"$CERT_FULLCHAIN_PATH" - _info "And the full chain certs is there: $(__green " $CERT_FULLCHAIN_PATH ")" + _link_issuer_retry=0; + _MAX_ISSUER_RETRY=5; + while [ "$_link_issuer_retry" -lt "$_MAX_ISSUER_RETRY" ]; do + _debug _link_issuer_retry "$_link_issuer_retry" + if _get "$Le_LinkIssuer" >"$CA_CERT_PATH.der"; then + echo "$BEGIN_CERT" >"$CA_CERT_PATH" + _base64 "multiline" <"$CA_CERT_PATH.der" >>"$CA_CERT_PATH" + echo "$END_CERT" >>"$CA_CERT_PATH" + + _info "The intermediate CA cert is in $(__green " $CA_CERT_PATH ")" + cat "$CA_CERT_PATH" >>"$CERT_FULLCHAIN_PATH" + _info "And the full chain certs is there: $(__green " $CERT_FULLCHAIN_PATH ")" + + rm -f "$CA_CERT_PATH.der" + break + fi + _link_issuer_retry=$(_math $_link_issuer_retry + 1) + _sleep "$_link_issuer_retry" + done + if [ "$_link_issuer_retry" = "$_MAX_ISSUER_RETRY" ]; then + _err "Max retry for issuer ca cert is reached." + fi + else + _debug "No Le_LinkIssuer header found." fi Le_CertCreateTime=$(_time) @@ -4463,7 +4482,7 @@ _precheck() { fi fi - if ! _exists "$ACME_OPENSSL_BIN"; then + if ! _exists "${ACME_OPENSSL_BIN:-openssl}"; then _err "Please install openssl first. ACME_OPENSSL_BIN=$ACME_OPENSSL_BIN" _err "We need openssl to generate keys." return 1 @@ -4705,6 +4724,7 @@ _uninstallalias() { cron() { IN_CRON=1 _initpath + _info "$(__green "===Starting cron===")" if [ "$AUTO_UPGRADE" = "1" ]; then export LE_WORKING_DIR ( @@ -4724,6 +4744,7 @@ cron() { renewAll _ret="$?" IN_CRON="" + _info "$(__green "===End cron===")" exit $_ret } From 232c7361a94cd0959abe175ccb7d5fdab43aefce Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 30 Mar 2017 21:34:15 +0800 Subject: [PATCH 067/115] fix format --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 3bd9b024..99525459 100755 --- a/acme.sh +++ b/acme.sh @@ -3686,8 +3686,8 @@ issue() { _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" if [ "$Le_LinkIssuer" ]; then - _link_issuer_retry=0; - _MAX_ISSUER_RETRY=5; + _link_issuer_retry=0 + _MAX_ISSUER_RETRY=5 while [ "$_link_issuer_retry" -lt "$_MAX_ISSUER_RETRY" ]; do _debug _link_issuer_retry "$_link_issuer_retry" if _get "$Le_LinkIssuer" >"$CA_CERT_PATH.der"; then From f3b434397b9928e36c7303ffaa9bbb8cf711bfc2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 3 Apr 2017 12:08:38 +0800 Subject: [PATCH 068/115] v2.6.8 support Docker --- Dockerfile | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 2 ++ acme.sh | 2 +- 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..8d0f6185 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,52 @@ +FROM alpine + +RUN apk update -f \ + && apk --no-cache add -f \ + openssl \ + curl \ + netcat-openbsd + +ENV LE_CONFIG_HOME /acme.sh + +ENV AUTO_UPGRADE 1 + +#Install +RUN mkdir -p /install_acme.sh/ +ADD ./ /install_acme.sh/ +RUN cd /install_acme.sh && ([ -f /install_acme.sh/acme.sh ] && /install_acme.sh/acme.sh --install || curl https://get.acme.sh | sh) +RUN rm -rf /install_acme.sh/ + +RUN ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh + +RUN for verb in help \ + version \ + install \ + uninstall \ + upgrade \ + issue \ + signcsr \ + deploy \ + install-cert \ + renew \ + renew-all \ + revoke \ + remove \ + list \ + showcsr \ + install-cronjob \ + uninstall-cronjob \ + cron \ + toPkcs \ + toPkcs8 \ + update-account \ + register-account \ + create-account-key \ + create-domain-key \ + createCSR \ + deactivate \ + ; do \ + printf -- "%b" "#!/usr/bin/env sh\n/root/.acme.sh/acme.sh --${verb} --config-home /acme.sh \"\$@\"" >/usr/local/bin/--${verb} && chmod +x /usr/local/bin/--${verb} \ + ; done + +ENTRYPOINT ["/root/.acme.sh/acme.sh", "--config-home", "/acme.sh"] +CMD ["--help"] diff --git a/README.md b/README.md index 7a79bed4..e0c1e7d6 100644 --- a/README.md +++ b/README.md @@ -7,11 +7,13 @@ - Purely written in Shell with no dependencies on python or the official Let's Encrypt client. - Just one script to issue, renew and install your certificates automatically. - DOES NOT require `root/sudoer` access. +- Docker friendly It's probably the `easiest&smallest&smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt. Wiki: https://github.com/Neilpang/acme.sh/wiki +For Docker Fans: [acme.sh :two_hearts: Docker ](https://github.com/Neilpang/acme.sh/wiki/Run-acme.sh-in-docker) Twitter: [@neilpangxa](https://twitter.com/neilpangxa) diff --git a/acme.sh b/acme.sh index 99525459..e2bc928f 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.6.7 +VER=2.6.8 PROJECT_NAME="acme.sh" From 1f4e64f81d7650e7811153cf73e527b94fc252c1 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 4 Apr 2017 00:21:39 +0800 Subject: [PATCH 069/115] Truncated request for more than 100 domains. --- dnsapi/dns_aws.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index d5d52de0..6fffd093 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -88,6 +88,19 @@ _get_root() { while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) if [ -z "$h" ]; then + if _contains "$response" "true" && _contains "$response" ""; then + _debug "IsTruncated" + _nextMarker="$(echo "$response" | _egrep_o ".*" | cut -d '>' -f 2 | cut -d '<' -f 1)" + _debug "NextMarker" "$_nextMarker" + if aws_rest GET "2013-04-01/hostedzone?marker=$_nextMarker"; then + _debug "Truncated request OK" + i=2 + p=1 + continue + else + _err "Truncated request error." + fi + fi #not valid return 1 fi From 66e38ae69e4487155cbc555f1230ac641e2b5f5a Mon Sep 17 00:00:00 2001 From: shar0119 Date: Mon, 3 Apr 2017 13:46:39 -0700 Subject: [PATCH 070/115] Updated Readme.md file (1 of 2) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e0c1e7d6..567ec5ba 100644 --- a/README.md +++ b/README.md @@ -313,6 +313,7 @@ You don't have to do anything manually! 1. DigitalOcean API (native) 1. ClouDNS.net API 1. Infoblox NIOS API (https://www.infoblox.com/) +1. Dynu API (https://www.dynu.com) **More APIs coming soon...** From afb67d375facf5065326362f2046452ee039bc94 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Mon, 3 Apr 2017 14:01:40 -0700 Subject: [PATCH 071/115] Updated README.md (2 of 2) --- dnsapi/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index 9eb77915..e8c263b0 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -438,6 +438,22 @@ acme.sh --issue --dns dns_infoblox -d example.com -d www.example.com Note: This script will automatically create and delete the ephemeral txt record. The `Infoblox_Creds` and `Infoblox_Server` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 23. Use Dynu API + +First you need to create/obtain API credentials from your Dynu account. See: https://www.dynu.com/resources/api/documentation + +``` +export Dynu_ClientId="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" +export Dynu_Secret="yyyyyyyyyyyyyyyyyyyyyyyyy" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_dynu -d example.com -d www.example.com +``` + +The `Dynu_ClientId` and `Dynu_Secret` 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. From fc9649dbc48bc89626d0f80fd7db20442cb17f0e Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 4 Apr 2017 10:02:45 +0800 Subject: [PATCH 072/115] fix aws --- dnsapi/dns_aws.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 6fffd093..137af895 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -92,7 +92,7 @@ _get_root() { _debug "IsTruncated" _nextMarker="$(echo "$response" | _egrep_o ".*" | cut -d '>' -f 2 | cut -d '<' -f 1)" _debug "NextMarker" "$_nextMarker" - if aws_rest GET "2013-04-01/hostedzone?marker=$_nextMarker"; then + if aws_rest GET "2013-04-01/hostedzone" "marker=$_nextMarker"; then _debug "Truncated request OK" i=2 p=1 @@ -220,7 +220,7 @@ aws_rest() { _H2="Authorization: $Authorization" _debug _H2 "$_H2" - url="$AWS_URL/$ep" + url="$AWS_URL/$ep?$qsr" if [ "$mtd" = "GET" ]; then response="$(_get "$url")" From 695482ded7248b25ecaa23e00571dd32d04f4ad4 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Mon, 3 Apr 2017 21:21:50 -0700 Subject: [PATCH 073/115] Added author name and link to report bugs --- dnsapi/dns_dynu.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index 03a45c1a..9bf2c064 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -11,7 +11,10 @@ Dynu_Token="" # #Endpoint Dynu_EndPoint="https://api.dynu.com/v1" - +# +#Author: David Kerr +#Report Bugs here: https://github.com/dkerr64/acme.sh +# ######## Public functions ##################### #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" From 6d7f6750e94bc969fed6469bff6402be538987a8 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Mon, 3 Apr 2017 21:22:58 -0700 Subject: [PATCH 074/115] Updated author name and link to report bugs --- dnsapi/dns_dynu.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index 9bf2c064..63992ed4 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -12,8 +12,8 @@ Dynu_Token="" #Endpoint Dynu_EndPoint="https://api.dynu.com/v1" # -#Author: David Kerr -#Report Bugs here: https://github.com/dkerr64/acme.sh +#Author: Dynu Systems, Inc. +#Report Bugs here: https://github.com/shar0119/acme.sh # ######## Public functions ##################### From fd77e463a150e2253aa7ca6658c17bddb62fef79 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 4 Apr 2017 14:34:23 +0800 Subject: [PATCH 075/115] fix aws --- dnsapi/dns_aws.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 137af895..6a723537 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -220,7 +220,10 @@ aws_rest() { _H2="Authorization: $Authorization" _debug _H2 "$_H2" - url="$AWS_URL/$ep?$qsr" + url="$AWS_URL/$ep" + if [ "$qsr" ]; then + url="$AWS_URL/$ep?$qsr" + fi if [ "$mtd" = "GET" ]; then response="$(_get "$url")" From f7217c5f2629d541a4584039a7d9c9313afdda7f Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 4 Apr 2017 15:54:45 +0800 Subject: [PATCH 076/115] fix format --- dnsapi/dns_aws.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 6a723537..21e86686 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -88,7 +88,7 @@ _get_root() { while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) if [ -z "$h" ]; then - if _contains "$response" "true" && _contains "$response" ""; then + if _contains "$response" "true" && _contains "$response" ""; then _debug "IsTruncated" _nextMarker="$(echo "$response" | _egrep_o ".*" | cut -d '>' -f 2 | cut -d '<' -f 1)" _debug "NextMarker" "$_nextMarker" From 7df062b7d7d9ff95f6a3b58f005431ccd3cd4ec8 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 4 Apr 2017 22:33:26 +0800 Subject: [PATCH 077/115] add more debug info --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index e2bc928f..8f47f8cc 100755 --- a/acme.sh +++ b/acme.sh @@ -1102,6 +1102,7 @@ _readKeyLengthFromCSR() { fi _outcsr="$(${ACME_OPENSSL_BIN:-openssl} req -noout -text -in "$_csrfile")" + _debug2 _outcsr "$_outcsr" if _contains "$_outcsr" "Public Key Algorithm: id-ecPublicKey"; then _debug "ECC CSR" echo "$_outcsr" | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' ' From 49d75a0cd4ba5112ca947a2b54ba72719ac4f73b Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 5 Apr 2017 20:46:17 +0800 Subject: [PATCH 078/115] minor, add more error message --- acme.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/acme.sh b/acme.sh index 8f47f8cc..850ac4b1 100755 --- a/acme.sh +++ b/acme.sh @@ -3121,6 +3121,10 @@ issue() { _usage "Usage: $PROJECT_ENTRY --issue -d a.com -w /path/to/webroot/a.com/ " return 1 fi + if [ -z "$1" ]; then + _usage "Please specify at least one validation method: '--webroot', '--standalone', '--apache', '--nginx' or '--dns' etc." + return 1 + fi _web_roots="$1" _main_domain="$2" _alt_domains="$3" From 3576754c217c643d9b66cba0e91d858ada5781bf Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 5 Apr 2017 20:54:53 +0800 Subject: [PATCH 079/115] fix https://github.com/Neilpang/acme.sh/issues/549 --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 850ac4b1..b6b0c842 100755 --- a/acme.sh +++ b/acme.sh @@ -107,7 +107,7 @@ __green() { if [ "$__INTERACTIVE" ]; then printf '\033[1;31;32m' fi - printf -- "$1" + printf -- "%b" "$1" if [ "$__INTERACTIVE" ]; then printf '\033[0m' fi @@ -117,7 +117,7 @@ __red() { if [ "$__INTERACTIVE" ]; then printf '\033[1;31;40m' fi - printf -- "$1" + printf -- "%b" "$1" if [ "$__INTERACTIVE" ]; then printf '\033[0m' fi From 482cb737025d691c730594abf8084c0bd1936bc6 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 6 Apr 2017 19:29:09 +0800 Subject: [PATCH 080/115] fix https://github.com/Neilpang/acme.sh/issues/758 --- acme.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index b6b0c842..11a30fa9 100755 --- a/acme.sh +++ b/acme.sh @@ -1105,10 +1105,10 @@ _readKeyLengthFromCSR() { _debug2 _outcsr "$_outcsr" if _contains "$_outcsr" "Public Key Algorithm: id-ecPublicKey"; then _debug "ECC CSR" - echo "$_outcsr" | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' ' + echo "$_outcsr" | tr "\t" " " | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' ' else _debug "RSA CSR" - echo "$_outcsr" | _egrep_o "(^ *|^RSA )Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1 + echo "$_outcsr" | tr "\t" " " | _egrep_o "(^ *|RSA )Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1 fi } @@ -3865,7 +3865,7 @@ renewAll() { return "$rc" else _ret="$rc" - _err "Error renew $d, Go ahead to next one." + _err "Error renew $d." fi fi done From 7f618e7ecc698f171135558b34b6980219b902d7 Mon Sep 17 00:00:00 2001 From: Kok Suan Lim Date: Sat, 8 Apr 2017 14:50:39 +0800 Subject: [PATCH 081/115] fix missing space bug on if statement --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 11a30fa9..f434f685 100755 --- a/acme.sh +++ b/acme.sh @@ -2565,7 +2565,7 @@ _checkConf() { if [ ! -f "$2" ] && ! echo "$2" | grep '*$' >/dev/null && echo "$2" | grep '*' >/dev/null; then _debug "wildcard" for _w_f in $2; do - if [ -f "$_w_f"] && _checkConf "$1" "$_w_f"; then + if [ -f "$_w_f" ] && _checkConf "$1" "$_w_f"; then return 0 fi done From fcdf41ba293658060e82c45b3c3ec368db270385 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 11 Apr 2017 21:37:56 +0800 Subject: [PATCH 082/115] support change account conf from env --- acme.sh | 20 +++++++++++++++++++- dnsapi/dns_cf.sh | 6 ++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index f434f685..3498fe75 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.6.8 +VER=2.6.9 PROJECT_NAME="acme.sh" @@ -1847,6 +1847,24 @@ _saveaccountconf() { _save_conf "$ACCOUNT_CONF_PATH" "$1" "$2" } +#key value +_saveaccountconf_mutable() { + _save_conf "$ACCOUNT_CONF_PATH" "SAVED_$1" "$2" + #remove later + _clearaccountconf "$1" +} + +#key +_readaccountconf() { + _read_conf "$ACCOUNT_CONF_PATH" "$1" +} + +#key +_readaccountconf_mutable() { + _rac_key="$1" + _readaccountconf "SAVED_$_rac_key" +} + #_clearaccountconf key _clearaccountconf() { _clear_conf "$ACCOUNT_CONF_PATH" "$1" diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 3718f9db..0442fbe0 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -14,6 +14,8 @@ dns_cf_add() { fulldomain=$1 txtvalue=$2 + CF_Key="${CF_Key:-$(_readaccountconf_mutable CF_Key )}" + CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email )}" if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then CF_Key="" CF_Email="" @@ -29,8 +31,8 @@ dns_cf_add() { fi #save the api key and email to the account conf file. - _saveaccountconf CF_Key "$CF_Key" - _saveaccountconf CF_Email "$CF_Email" + _saveaccountconf_mutable CF_Key "$CF_Key" + _saveaccountconf_mutable CF_Email "$CF_Email" _debug "First detect the root zone" if ! _get_root "$fulldomain"; then From eb0fc67461c07ed5eeae8605d616e88ec9b985dc Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 11 Apr 2017 22:29:49 +0800 Subject: [PATCH 083/115] fix format --- dnsapi/dns_cf.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 0442fbe0..228caa82 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -14,8 +14,8 @@ dns_cf_add() { fulldomain=$1 txtvalue=$2 - CF_Key="${CF_Key:-$(_readaccountconf_mutable CF_Key )}" - CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email )}" + CF_Key="${CF_Key:-$(_readaccountconf_mutable CF_Key)}" + CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}" if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then CF_Key="" CF_Email="" From 9a61d6293d14a401f57fed793b9b829788c5b134 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Thu, 13 Apr 2017 20:48:39 -0700 Subject: [PATCH 084/115] Implemented dns_dynu_rm() Implemented dns_dynu_rm() method. --- dnsapi/dns_dynu.sh | 93 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 86 insertions(+), 7 deletions(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index 63992ed4..a3a604ba 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -35,7 +35,7 @@ dns_dynu_add() { _saveaccountconf Dynu_Secret "$Dynu_Secret" if [ -z "$Dynu_Token" ]; then - _info "Getting Dynu token" + _info "Getting Dynu token." if ! _dynu_authentication; then _err "Can not get token." fi @@ -43,29 +43,76 @@ dns_dynu_add() { _debug "Detect root zone" if ! _get_root "$fulldomain"; then - _err "Invalid domain" + _err "Invalid domain." return 1 fi _debug _node "$_node" _debug _domain_name "$_domain_name" - _info "Creating TXT record" + _info "Creating TXT record." if ! _dynu_rest POST "dns/record/add" "{\"domain_name\":\"$_domain_name\",\"node_name\":\"$_node\",\"record_type\":\"TXT\",\"text_data\":\"$txtvalue\",\"state\":true,\"ttl\":90}"; then return 1 fi if ! _contains "$response" "text_data"; then - _err "Could not add TXT record" + _err "Could not add TXT record." return 1 fi return 0 } -#fulldomain +#Usage: rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_dynu_rm() { fulldomain=$1 + txtvalue=$2 + + if [ -z "$Dynu_ClientId" ] || [ -z "$Dynu_Secret" ]; then + Dynu_ClientId="" + Dynu_Secret="" + _err "Dynu client id and secret is not specified." + _err "Please create you API client id and secret and try again." + return 1 + fi + + #save the client id and secret to the account conf file. + _saveaccountconf Dynu_ClientId "$Dynu_ClientId" + _saveaccountconf Dynu_Secret "$Dynu_Secret" + + if [ -z "$Dynu_Token" ]; then + _info "Getting Dynu token." + if ! _dynu_authentication; then + _err "Can not get token." + fi + fi + + _debug "Detect root zone." + if ! _get_root "$fulldomain"; then + _err "Invalid domain." + return 1 + fi + + _debug _node "$_node" + _debug _domain_name "$_domain_name" + + _info "Checking for TXT record." + if ! _get_recordid "$fulldomain" "$txtvalue"; then + _err "Could not get TXT record id." + return 1 + fi + + if [ "$_dns_record_id" = "" ]; then + _err "TXT record not found." + return 1 + fi + + _info "Removing TXT record." + if ! _delete_txt_record "$_dns_record_id"; then + _err "Could not remove TXT record $_dns_record_id." + fi + + return 0 } ######## Private functions below ################################## @@ -80,7 +127,7 @@ _get_root() { fi if ! _contains "$response" "domain_name"; then - _debug "Domain name not found" + _debug "Domain name not found." return 1 fi @@ -89,6 +136,38 @@ _get_root() { return 0 } +_get_recordid() { + fulldomain=$1 + txtvalue=$2 + + if ! _dynu_rest GET "dns/record/get?hostname=$fulldomain&rrtype=TXT"; then + return 1 + fi + + if ! _contains "$response" "$txtvalue"; then + _dns_record_id=0 + return 0 + fi + + _dns_record_id=$(printf "%s" "$response" grep -o -e "{[^}]*}" | grep '"text_data":"This is another TXT record."' | grep -o -e ",[^,]*," | grep ',"id":' | tr -d ",," | cut -d : -f 2) + + return 0 +} + +_delete_txt_record() { + _dns_record_id=$1 + + if ! _dynu_rest GET "dns/record/delete/$_dns_record_id"; then + return 1 + fi + + if ! _contains "$response" "true"; then + return 1 + fi + + return 0 +} + _dynu_rest() { m=$1 ep="$2" @@ -102,7 +181,7 @@ _dynu_rest() { _debug data "$data" response="$(_post "$data" "$Dynu_EndPoint/$ep" "" "$m")" else - echo "Getting $Dynu_EndPoint/$ep" + _info "Getting $Dynu_EndPoint/$ep" response="$(_get "$Dynu_EndPoint/$ep")" fi From 394b1002b344db16ef8568f2933b162d9e87c9c5 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Thu, 13 Apr 2017 20:54:57 -0700 Subject: [PATCH 085/115] Corrected formatting error. Part of dns_dynu_rm() impementation. --- dnsapi/dns_dynu.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index a3a604ba..e784c3b8 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -112,7 +112,7 @@ dns_dynu_rm() { _err "Could not remove TXT record $_dns_record_id." fi - return 0 + return 0 } ######## Private functions below ################################## From 8470c60e067b522e3322f90bca980313ac110729 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Fri, 14 Apr 2017 12:46:00 -0700 Subject: [PATCH 086/115] Using _egrep_o() instead of grep -o -e Modified code to use egrep instead of grep -o -e. --- dnsapi/dns_dynu.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index e784c3b8..19e7fc7b 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -149,7 +149,7 @@ _get_recordid() { return 0 fi - _dns_record_id=$(printf "%s" "$response" grep -o -e "{[^}]*}" | grep '"text_data":"This is another TXT record."' | grep -o -e ",[^,]*," | grep ',"id":' | tr -d ",," | cut -d : -f 2) + _dns_record_id=$(printf "%s" "$response" | _egrep_o "{[^}]*}" | grep "\"text_data\":\"$txtvalue\"" | grep -Po '"id":\K[0-9]+') return 0 } From cd98951001ca5f9bbd79a6e35bca3653b1b1e0d8 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 16 Apr 2017 09:36:59 +0800 Subject: [PATCH 087/115] fix https://github.com/Neilpang/acme.sh/issues/794#issuecomment-294314606 --- dnsapi/dns_cf.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 228caa82..57a2e884 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -85,6 +85,17 @@ dns_cf_add() { dns_cf_rm() { fulldomain=$1 txtvalue=$2 + + CF_Key="${CF_Key:-$(_readaccountconf_mutable CF_Key)}" + CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}" + if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then + CF_Key="" + CF_Email="" + _err "You don't specify cloudflare api key and email yet." + _err "Please create you key and try again." + return 1 + fi + _debug "First detect the root zone" if ! _get_root "$fulldomain"; then _err "invalid domain" From 7883cc58912418d96cf4f2eff5dac8e15015aa4d Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 16 Apr 2017 11:16:48 +0800 Subject: [PATCH 088/115] fix docker cronjob --- Dockerfile | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 8d0f6185..feb89b0d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -48,5 +48,12 @@ RUN for verb in help \ printf -- "%b" "#!/usr/bin/env sh\n/root/.acme.sh/acme.sh --${verb} --config-home /acme.sh \"\$@\"" >/usr/local/bin/--${verb} && chmod +x /usr/local/bin/--${verb} \ ; done -ENTRYPOINT ["/root/.acme.sh/acme.sh", "--config-home", "/acme.sh"] +RUN printf "%b" '#!'"/usr/bin/env sh\n \ +if [ \"\$1\" = \"daemon\" ]; then \n \ + crond; tail -f /dev/null;\n \ +else \n \ + /root/.acme.sh/acme.sh --config-home /acme.sh \"\$@\"\n \ +fi" >/entry.sh && chmod +x /entry.sh + +ENTRYPOINT ["/entry.sh"] CMD ["--help"] From 3c07f57aade6d3995f16faa5f3ed3fac8d962d01 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 17 Apr 2017 19:08:34 +0800 Subject: [PATCH 089/115] minor remove spaces --- acme.sh | 26 +++++++++++++------------- dnsapi/dns_freedns.sh | 6 +++--- dnsapi/dns_ovh.sh | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/acme.sh b/acme.sh index 3498fe75..27bc4fb3 100755 --- a/acme.sh +++ b/acme.sh @@ -347,7 +347,7 @@ _hasfield() { fi done _debug2 "'$_str' does not contain '$_field'" - return 1 #not contains + return 1 #not contains } _getfield() { @@ -722,7 +722,7 @@ _url_encode() { "7e") printf "%s" "~" ;; - #other hex + #other hex *) printf '%%%s' "$_hex_code" ;; @@ -1025,7 +1025,7 @@ _createcsr() { else alt="DNS:$domainlist" fi - #multi + #multi _info "Multi domain" "$alt" printf -- "\nsubjectAltName=$alt" >>"$csrconf" fi @@ -1093,7 +1093,7 @@ _readSubjectAltNamesFromCSR() { printf "%s" "$_dnsAltnames" | sed "s/DNS://g" } -#_csrfile +#_csrfile _readKeyLengthFromCSR() { _csrfile="$1" if [ -z "$_csrfile" ]; then @@ -1192,7 +1192,7 @@ toPkcs8() { } -#[2048] +#[2048] createAccountKey() { _info "Creating account key" if [ -z "$1" ]; then @@ -2546,7 +2546,7 @@ _setNginx() { location ~ \"^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)\$\" { default_type text/plain; return 200 \"\$1.$_thumbpt\"; -} +} #NGINX_START " >>"$FOUND_REAL_NGINX_CONF" @@ -3133,7 +3133,7 @@ __trigger_validation() { _send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$_t_key_authz\"}" } -#webroot, domain domainlist keylength +#webroot, domain domainlist keylength issue() { if [ -z "$2" ]; then _usage "Usage: $PROJECT_ENTRY --issue -d a.com -w /path/to/webroot/a.com/ " @@ -3666,7 +3666,7 @@ issue() { #if ! _get "$Le_LinkCert" | _base64 "multiline" >> "$CERT_PATH" ; then # _debug "Get cert failed. Let's try last response." - # printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >> "$CERT_PATH" + # printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >> "$CERT_PATH" #fi if ! printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >>"$CERT_PATH"; then @@ -4807,7 +4807,7 @@ Commands: --create-domain-key Create an domain private key, professional use. --createCSR, -ccsr Create CSR , professional use. --deactivate Deactivate the domain authz, professional use. - + Parameters: --domain, -d domain.tld Specifies a domain, used to issue, renew or revoke etc. --force, -f Used to force to install or force to renew a cert immediately. @@ -4821,20 +4821,20 @@ Parameters: --apache Use apache mode. --dns [dns_cf|dns_dp|dns_cx|/path/to/api/file] Use dns mode or dns api. --dnssleep [$DEFAULT_DNS_SLEEP] The time in seconds to wait for all the txt records to take effect in dns api mode. Default $DEFAULT_DNS_SLEEP seconds. - + --keylength, -k [2048] Specifies the domain key length: 2048, 3072, 4096, 8192 or ec-256, ec-384. --accountkeylength, -ak [2048] Specifies the account key length. --log [/path/to/logfile] Specifies the log file. The default is: \"$DEFAULT_LOG_FILE\" if you don't give a file path here. --log-level 1|2 Specifies the log level, default is 1. --syslog [0|3|6|7] Syslog level, 0: disable syslog, 3: error, 6: info, 7: debug. - + These parameters are to install the cert to nginx/apache or anyother server after issue/renew a cert: - + --cert-file After issue/renew, the cert will be copied to this path. --key-file After issue/renew, the key will be copied to this path. --ca-file After issue/renew, the intermediate cert will be copied to this path. --fullchain-file After issue/renew, the fullchain cert will be copied to this path. - + --reloadcmd \"service nginx reload\" After issue/renew, it's used to reload the server. --accountconf Specifies a customized account config file. diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 272a1243..53da4118 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -53,7 +53,7 @@ dns_freedns_add() { i="$(_math "$i" - 1)" sub_domain="$(echo "$fulldomain" | cut -d. -f -"$i")" - # Sometimes FreeDNS does not return the subdomain page but rather + # Sometimes FreeDNS does not return the subdomain page but rather # returns a page regarding becoming a premium member. This usually # happens after a period of inactivity. Immediately trying again # returns the correct subdomain page. So, we will try twice to @@ -72,7 +72,7 @@ dns_freedns_add() { fi # Now convert the tables in the HTML to CSV. This litte gem from - # http://stackoverflow.com/questions/1403087/how-can-i-convert-an-html-table-to-csv + # http://stackoverflow.com/questions/1403087/how-can-i-convert-an-html-table-to-csv subdomain_csv="$(echo "$htmlpage" \ | grep -i -e ' Date: Wed, 19 Apr 2017 23:12:37 +0800 Subject: [PATCH 090/115] update doc --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e0c1e7d6..cf825625 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ - DOES NOT require `root/sudoer` access. - Docker friendly -It's probably the `easiest&smallest&smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt. +It's probably the `easiest & smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt. Wiki: https://github.com/Neilpang/acme.sh/wiki @@ -31,6 +31,7 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa) - [Centminmod](http://centminmod.com/letsencrypt-acmetool-https.html) - [splynx](https://forum.splynx.com/t/free-ssl-cert-for-splynx-lets-encrypt/297) - [archlinux](https://aur.archlinux.org/packages/acme.sh-git/) +- [opnsense.org](https://github.com/opnsense/plugins/tree/master/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient) - [more...](https://github.com/Neilpang/acme.sh/wiki/Blogs-and-tutorials) # Tested OS From 27a05ff27112a29e98aa51661040ef3176c07531 Mon Sep 17 00:00:00 2001 From: LAV45 Date: Sat, 15 Apr 2017 14:34:37 +0300 Subject: [PATCH 091/115] Add dns_vscale.sh --- README.md | 1 + dnsapi/README.md | 15 +++++ dnsapi/dns_vscale.sh | 149 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 165 insertions(+) create mode 100755 dnsapi/dns_vscale.sh diff --git a/README.md b/README.md index e0c1e7d6..47ea0126 100644 --- a/README.md +++ b/README.md @@ -313,6 +313,7 @@ You don't have to do anything manually! 1. DigitalOcean API (native) 1. ClouDNS.net API 1. Infoblox NIOS API (https://www.infoblox.com/) +1. VSCALE (https://vscale.io/) **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index 9eb77915..896dfcb7 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -438,6 +438,21 @@ acme.sh --issue --dns dns_infoblox -d example.com -d www.example.com Note: This script will automatically create and delete the ephemeral txt record. The `Infoblox_Creds` and `Infoblox_Server` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + +## 22. Use VSCALE API + +First you need to create/obtain API tokens on your [settings panel](https://vscale.io/panel/settings/tokens/). + +``` +VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns vscale -d example.com -d www.example.com +``` + + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_vscale.sh b/dnsapi/dns_vscale.sh new file mode 100755 index 00000000..e50b7d8b --- /dev/null +++ b/dnsapi/dns_vscale.sh @@ -0,0 +1,149 @@ +#!/usr/bin/env sh + +#This is the vscale.io api wrapper for acme.sh +# +#Author: Alex Loban +#Report Bugs here: https://github.com/LAV45/acme.sh + +#VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" +VSCALE_API_URL="https://api.vscale.io/v1" + +######## Public functions ##################### + +#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_vscale_add() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$VSCALE_API_KEY" ]; then + VSCALE_API_KEY="" + _err "You didn't specify the VSCALE api key yet." + _err "Please create you key and try again." + return 1 + fi + + _saveaccountconf VSCALE_API_KEY "$VSCALE_API_KEY" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _vscale_tmpl_json="{\"type\":\"TXT\",\"name\":\"$_sub_domain.$_domain\",\"content\":\"$txtvalue\"}" + + if _vscale_rest POST "domains/$_domain_id/records/" "$_vscale_tmpl_json"; then + response=$(printf "%s\n" "$response" | _egrep_o "{\"error\": \".+\"" | cut -d : -f 2) + if [ -z "$response" ]; then + _info "txt record updated success." + return 0 + fi + fi + + return 1 +} + +#fulldomain txtvalue +dns_vscale_rm() { + fulldomain=$1 + txtvalue=$2 + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _vscale_rest GET "domains/$_domain_id/records/" + + if [ -n "$response" ]; then + record_id=$(printf "%s\n" "$response" | _egrep_o "\"TXT\", \"id\": [0-9]+, \"name\": \"$_sub_domain.$_domain\"" | cut -d : -f 2 | tr -d ", \"name\"") + _debug record_id "$record_id" + if [ -z "$record_id" ]; then + _err "Can not get record id to remove." + return 1 + fi + if _vscale_rest DELETE "domains/$_domain_id/records/$record_id" && [ -z "$response" ]; then + _info "txt record deleted success." + return 0 + fi + _debug response "$response" + return 1 + fi + + return 1 +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=12345 +_get_root() { + domain=$1 + i=2 + p=1 + + if _vscale_rest GET "domains/"; then + response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')" + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + hostedzone="$(echo "$response" | _egrep_o "{.*\"name\":\s*\"$h\".*}")" + if [ "$hostedzone" ]; then + _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\":\s*[0-9]+" | _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 + fi + return 1 +} + +#method uri qstr data +_vscale_rest() { + mtd="$1" + ep="$2" + data="$3" + + _debug mtd "$mtd" + _debug ep "$ep" + + export _H1="Accept: application/json" + export _H2="Content-Type: application/json" + export _H3="X-Token: ${VSCALE_API_KEY}" + + if [ "$mtd" != "GET" ]; then + # both POST and DELETE. + _debug data "$data" + response="$(_post "$data" "$VSCALE_API_URL/$ep" "" "$mtd")" + else + response="$(_get "$VSCALE_API_URL/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} From dbe68684a054a11a6232803bafd0ba952380bc54 Mon Sep 17 00:00:00 2001 From: Aleksey Loban Date: Fri, 21 Apr 2017 12:30:01 +0300 Subject: [PATCH 092/115] Fix readme 'Use VSCALE API' [skip ci] --- dnsapi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 896dfcb7..82b47648 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -449,7 +449,7 @@ VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" Ok, let's issue a cert now: ``` -acme.sh --issue --dns vscale -d example.com -d www.example.com +acme.sh --issue --dns dns_vscale -d example.com -d www.example.com ``` From 020f9cd2a640a5347e46a650fdc4a3e059868ddc Mon Sep 17 00:00:00 2001 From: Aleksey Loban Date: Fri, 21 Apr 2017 13:15:39 +0300 Subject: [PATCH 093/115] small Fix readme [skip ci] --- dnsapi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 82b47648..d9f5c271 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -439,7 +439,7 @@ Note: This script will automatically create and delete the ephemeral txt record. The `Infoblox_Creds` and `Infoblox_Server` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. -## 22. Use VSCALE API +## 23. Use VSCALE API First you need to create/obtain API tokens on your [settings panel](https://vscale.io/panel/settings/tokens/). From a6e5876d964373c9fb68a16283f1097fb8b330c6 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Tue, 25 Apr 2017 19:33:54 -0700 Subject: [PATCH 094/115] Resolved conflict. Resolved conflict. --- dnsapi/README.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index e8c263b0..41cc80a8 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -438,7 +438,21 @@ acme.sh --issue --dns dns_infoblox -d example.com -d www.example.com Note: This script will automatically create and delete the ephemeral txt record. The `Infoblox_Creds` and `Infoblox_Server` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. -## 23. Use Dynu API + +## 23. Use VSCALE API + +First you need to create/obtain API tokens on your [settings panel](https://vscale.io/panel/settings/tokens/). + +``` +VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_vscale -d example.com -d www.example.com +``` + +## 24. Use Dynu API First you need to create/obtain API credentials from your Dynu account. See: https://www.dynu.com/resources/api/documentation From 9cf65e31cd599e567498d2d7972d858857d629b8 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Tue, 25 Apr 2017 19:37:56 -0700 Subject: [PATCH 095/115] Resolved conflict. Resolved conflict. --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 567ec5ba..cdcd40c3 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ - DOES NOT require `root/sudoer` access. - Docker friendly -It's probably the `easiest&smallest&smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt. +It's probably the `easiest & smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt. Wiki: https://github.com/Neilpang/acme.sh/wiki @@ -31,6 +31,7 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa) - [Centminmod](http://centminmod.com/letsencrypt-acmetool-https.html) - [splynx](https://forum.splynx.com/t/free-ssl-cert-for-splynx-lets-encrypt/297) - [archlinux](https://aur.archlinux.org/packages/acme.sh-git/) +- [opnsense.org](https://github.com/opnsense/plugins/tree/master/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient) - [more...](https://github.com/Neilpang/acme.sh/wiki/Blogs-and-tutorials) # Tested OS @@ -313,6 +314,7 @@ You don't have to do anything manually! 1. DigitalOcean API (native) 1. ClouDNS.net API 1. Infoblox NIOS API (https://www.infoblox.com/) +1. VSCALE (https://vscale.io/) 1. Dynu API (https://www.dynu.com) **More APIs coming soon...** From 0138e167e91164bffc86eee29b4f140a1d03c93e Mon Sep 17 00:00:00 2001 From: thecantero Date: Thu, 27 Apr 2017 18:23:43 +0800 Subject: [PATCH 096/115] Update to support Kong-v0.10.x The previous one is for Kong-v0.9.x only. This change will allow it to work with v0.10.x. More info at: https://github.com/Mashape/kong/blob/4f960abe33fe3d45510944f062e571d63dc3a673/UPGRADE.md#upgrade-to-010x https://getkong.org/docs/0.10.x/admin-api/#add-certificate --- deploy/kong.sh | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/deploy/kong.sh b/deploy/kong.sh index e1873f35..67eef693 100755 --- a/deploy/kong.sh +++ b/deploy/kong.sh @@ -31,14 +31,15 @@ kong_deploy() { _debug _cca "$_cca" _debug _cfullchain "$_cfullchain" - #Get uuid linked to the domain - uuid=$(_get "$KONG_URL/apis?request_host=$_cdomain" | _normalizeJson | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}') - if [ -z "$uuid" ]; then - _err "Unable to get Kong uuid for domain $_cdomain" - _err "Make sure that KONG_URL is correctly configured" - _err "Make sure that a Kong api request_host match the domain" - _err "Kong url: $KONG_URL" - return 1 + #Get ssl_uuid linked to the domain + ssl_uuid=$(_get "$KONG_URL/certificates/$_cdomain" | _normalizeJson | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}') + if [ -z "$ssl_uuid" ]; then + _debug "Unable to get Kong ssl_uuid for domain $_cdomain" + _debug "Make sure that KONG_URL is correctly configured" + _debug "Make sure that a Kong certificate match the sni" + _debug "Kong url: $KONG_URL" + _info "No existing certificate, creating..." + #return 1 fi #Save kong url if it's succesful (First run case) _saveaccountconf KONG_URL "$KONG_URL" @@ -48,12 +49,15 @@ kong_deploy() { #Set Header _H1="Content-Type: multipart/form-data; boundary=$delim" #Generate data for request (Multipart/form-data with mixed content) - #set name to ssl - content="--$delim${nl}Content-Disposition: form-data; name=\"name\"${nl}${nl}ssl" + content="--$delim${nl}" + if [ -z "$ssl_uuid" ]; then + #set sni to domain + content="$content{nl}Content-Disposition: form-data; name=\"snis\"${nl}${nl}$_cdomain" + fi #add key - content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"config.key\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")" + content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")" #Add cert - content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"config.cert\"; filename=\"$(basename "$_cfullchain")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_cfullchain")" + content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"cert\"; filename=\"$(basename "$_cfullchain")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_cfullchain")" #Close multipart content="$content${nl}--$delim--${nl}" #Convert CRLF @@ -61,17 +65,16 @@ kong_deploy() { #DEBUG _debug header "$_H1" _debug content "$content" - #Check if ssl plugins is aready enabled (if not => POST else => PATCH) - ssl_uuid=$(_get "$KONG_URL/apis/$uuid/plugins" | _egrep_o '"id":"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"[a-zA-Z0-9\-\,\"_\:]*"name":"ssl"' | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}') - _debug ssl_uuid "$ssl_uuid" + #Check if sslcreated (if not => POST else => PATCH) + if [ -z "$ssl_uuid" ]; then #Post certificate to Kong - response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins" "" "POST") + response=$(_post "$content" "$KONG_URL/certificates" "" "POST") else #patch - response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins/$ssl_uuid" "" "PATCH") + response=$(_post "$content" "$KONG_URL/certificates/$ssl_uuid" "" "PATCH") fi - if ! [ "$(echo "$response" | _egrep_o "ssl")" = "ssl" ]; then + if ! [ "$(echo "$response" | _egrep_o "created_at")" = "created_at" ]; then _err "An error occurred with cert upload. Check response:" _err "$response" return 1 From 3f1a76d9e4e8cb1ab79816db81df73dd663cca1a Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 27 Apr 2017 18:29:29 +0800 Subject: [PATCH 097/115] fix https://github.com/Neilpang/acme.sh/issues/808 --- acme.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 27bc4fb3..3506bdb9 100755 --- a/acme.sh +++ b/acme.sh @@ -2617,10 +2617,10 @@ _checkConf() { _isRealNginxConf() { _debug "_isRealNginxConf $1 $2" if [ -f "$2" ]; then - for _fln in $(grep -n "^ *server_name.* $1" "$2" | cut -d : -f 1); do + for _fln in $(tr "\t" ' ' <"$2" | grep -n "^ *server_name.* $1" | cut -d : -f 1); do _debug _fln "$_fln" if [ "$_fln" ]; then - _start=$(cat "$2" | _head_n "$_fln" | grep -n "^ *server *{" | _tail_n 1) + _start=$(tr "\t" ' ' <"$2" | _head_n "$_fln" | grep -n "^ *server *{" | _tail_n 1) _debug "_start" "$_start" _start_n=$(echo "$_start" | cut -d : -f 1) _start_nn=$(_math $_start_n + 1) @@ -2629,8 +2629,8 @@ _isRealNginxConf() { _left="$(sed -n "${_start_nn},99999p" "$2")" _debug2 _left "$_left" - if echo "$_left" | grep -n "^ *server *{" >/dev/null; then - _end=$(echo "$_left" | grep -n "^ *server *{" | _head_n 1) + if echo "$_left" | tr "\t" ' ' | grep -n "^ *server *{" >/dev/null; then + _end=$(echo "$_left" | tr "\t" ' ' | grep -n "^ *server *{" | _head_n 1) _debug "_end" "$_end" _end_n=$(echo "$_end" | cut -d : -f 1) _debug "_end_n" "$_end_n" From de3bac53bfb99e1b192bed48a1c5dcf694e2a606 Mon Sep 17 00:00:00 2001 From: thecantero Date: Thu, 27 Apr 2017 20:06:47 +0800 Subject: [PATCH 098/115] update README --- deploy/README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/deploy/README.md b/deploy/README.md index d8c2f57c..232fdb4a 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -21,8 +21,11 @@ acme.sh --deploy -d example.com --deploy-hook cpanel ## 2. Deploy ssl cert on kong proxy engine based on api. Before you can deploy your cert, you must [issue the cert first](https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert). +Currently supports Kong-v0.10.x. -(TODO) +```sh +acme.sh --deploy -d ftp.example.com --deploy-hook kong +``` ## 3. Deploy the cert to remote server through SSH access. From 4b02ee5b468814b2a19e9dd783b458264acbe776 Mon Sep 17 00:00:00 2001 From: thecantero Date: Thu, 27 Apr 2017 20:38:08 +0800 Subject: [PATCH 099/115] Typo fix --- deploy/kong.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/kong.sh b/deploy/kong.sh index 67eef693..79dc3916 100755 --- a/deploy/kong.sh +++ b/deploy/kong.sh @@ -67,7 +67,7 @@ kong_deploy() { _debug content "$content" #Check if sslcreated (if not => POST else => PATCH) - if [ -z "$ssl_uuid" ]; then + if [ ! -z "$ssl_uuid" ]; then #Post certificate to Kong response=$(_post "$content" "$KONG_URL/certificates" "" "POST") else From c140fe9bae8926e3724545330505edc3e1355833 Mon Sep 17 00:00:00 2001 From: thecantero Date: Thu, 27 Apr 2017 20:39:53 +0800 Subject: [PATCH 100/115] Typo Fix --- deploy/kong.sh | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/deploy/kong.sh b/deploy/kong.sh index 79dc3916..9d1f40a7 100755 --- a/deploy/kong.sh +++ b/deploy/kong.sh @@ -1,6 +1,3 @@ -#!/usr/bin/env sh - -# This deploy hook will deploy ssl cert on kong proxy engine based on api request_host parameter. # Note that ssl plugin should be available on Kong instance # The hook will match cdomain to request_host, in case of multiple domain it will always take the first # one (acme.sh behaviour). @@ -49,10 +46,9 @@ kong_deploy() { #Set Header _H1="Content-Type: multipart/form-data; boundary=$delim" #Generate data for request (Multipart/form-data with mixed content) - content="--$delim${nl}" if [ -z "$ssl_uuid" ]; then #set sni to domain - content="$content{nl}Content-Disposition: form-data; name=\"snis\"${nl}${nl}$_cdomain" + content="--$delim${nl}Content-Disposition: form-data; name=\"snis\"${nl}${nl}$_cdomain" fi #add key content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")" @@ -67,7 +63,7 @@ kong_deploy() { _debug content "$content" #Check if sslcreated (if not => POST else => PATCH) - if [ ! -z "$ssl_uuid" ]; then + if [ -z "$ssl_uuid" ]; then #Post certificate to Kong response=$(_post "$content" "$KONG_URL/certificates" "" "POST") else From 824ffa24f497a69bd4b0cb0cf10520b27d326514 Mon Sep 17 00:00:00 2001 From: Andre Cantero Date: Fri, 28 Apr 2017 00:21:21 +0800 Subject: [PATCH 101/115] Add shebang --- deploy/kong.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/deploy/kong.sh b/deploy/kong.sh index 9d1f40a7..dce92096 100755 --- a/deploy/kong.sh +++ b/deploy/kong.sh @@ -1,3 +1,4 @@ +#!/usr/bin/env sh # Note that ssl plugin should be available on Kong instance # The hook will match cdomain to request_host, in case of multiple domain it will always take the first # one (acme.sh behaviour). From 1231b71245588f107bc9667c16925afeac0f4e4e Mon Sep 17 00:00:00 2001 From: Andre Cantero Date: Fri, 28 Apr 2017 00:25:30 +0800 Subject: [PATCH 102/115] Update the notes --- deploy/kong.sh | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/deploy/kong.sh b/deploy/kong.sh index dce92096..d3a6bc47 100755 --- a/deploy/kong.sh +++ b/deploy/kong.sh @@ -1,11 +1,7 @@ #!/usr/bin/env sh -# Note that ssl plugin should be available on Kong instance -# The hook will match cdomain to request_host, in case of multiple domain it will always take the first -# one (acme.sh behaviour). -# If ssl config already exist it will update only cert and key not touching other parameter -# If ssl config doesn't exist it will only upload cert and key and not set other parameter -# Not that we deploy full chain -# See https://getkong.org/plugins/dynamic-ssl/ for other options +# If certificate already exist it will update only cert and key not touching other parameter +# If certificate doesn't exist it will only upload cert and key and not set other parameter +# Note that we deploy full chain # Written by Geoffroi Genot ######## Public functions ##################### From 5b3e3d9cf444e3c9e969244baedc18338f5b4ccc Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 30 Apr 2017 16:29:20 +0800 Subject: [PATCH 103/115] fix https://github.com/Neilpang/acme.sh/issues/812 --- acme.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 3506bdb9..7ce947ea 100755 --- a/acme.sh +++ b/acme.sh @@ -166,7 +166,14 @@ _syslog() { fi _logclass="$1" shift - logger -i -t "$PROJECT_NAME" -p "$_logclass" "$(_printargs "$@")" >/dev/null 2>&1 + if [ -z "$__logger_i" ]; then + if _contains "$(logger --help 2>&1)" "-i"; then + __logger_i="logger -i" + else + __logger_i="logger" + fi + fi + $__logger_i -t "$PROJECT_NAME" -p "$_logclass" "$(_printargs "$@")" >/dev/null 2>&1 } _log() { From 2310a9bbc0d043cc3340af8a933a0679004874ae Mon Sep 17 00:00:00 2001 From: shar0119 Date: Sun, 30 Apr 2017 10:32:56 -0700 Subject: [PATCH 104/115] Removed grep -Po Removed usage of grep -Po. --- dnsapi/dns_dynu.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index 19e7fc7b..f6eabde2 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -149,7 +149,7 @@ _get_recordid() { return 0 fi - _dns_record_id=$(printf "%s" "$response" | _egrep_o "{[^}]*}" | grep "\"text_data\":\"$txtvalue\"" | grep -Po '"id":\K[0-9]+') + _dns_record_id=$(printf "%s" "$response" | _egrep_o "{[^}]*}" | grep "\"text_data\":\"$txtvalue\"" | _egrep_o ",[^,]*," | grep ',"id":' | tr -d ",," | cut -d : -f 2) return 0 } From f5c381d5b466094f7c26573341deb517df5456b9 Mon Sep 17 00:00:00 2001 From: ka2er Date: Tue, 2 May 2017 00:45:29 +0200 Subject: [PATCH 105/115] less permissive permission on OVH API restrict authorization request to OVH /domain API and not whole OVH API. Not perfect due to some limitations in regex with *, but better security as the token don't give full access to the API. --- dnsapi/dns_ovh.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index 18f9c7dc..6c1edb4d 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -119,7 +119,7 @@ dns_ovh_add() { _info "Checking authentication" - response="$(_ovh_rest GET "domain/")" + response="$(_ovh_rest GET "domain")" if _contains "$response" "INVALID_CREDENTIAL"; then _err "The consumer key is invalid: $OVH_CK" _err "Please retry to create a new one." @@ -191,7 +191,7 @@ _ovh_authentication() { _H3="" _H4="" - _ovhdata='{"accessRules": [{"method": "GET","path": "/*"},{"method": "POST","path": "/*"},{"method": "PUT","path": "/*"},{"method": "DELETE","path": "/*"}],"redirection":"'$ovh_success'"}' + _ovhdata='{"accessRules": [{"method": "GET","path": "/auth/time"},{"method": "GET","path": "/domain"},{"method": "GET","path": "/domain/zone/*"},{"method": "GET","path": "/domain/zone/*/record"},{"method": "POST","path": "/domain/zone/*/record"},{"method": "POST","path": "/domain/zone/*/refresh"},{"method": "PUT","path": "/domain/zone/*/record/*"}],"redirection":"'$ovh_success'"}' response="$(_post "$_ovhdata" "$OVH_API/auth/credential")" _debug3 response "$response" From 1994c6828ecaaefa50beb8fb5616ed51a3b98c48 Mon Sep 17 00:00:00 2001 From: Matthew Turney Date: Mon, 5 Dec 2016 21:53:02 -0600 Subject: [PATCH 106/115] include dnsimple api Even though DNSimple is technically covered with lexicon not all systems can install python pip's easily. For these systems it is useful to have pure shell script API interactions. --- README.md | 1 + dnsapi/README.md | 36 +++++++-- dnsapi/dns_dnsimple.sh | 163 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 193 insertions(+), 7 deletions(-) create mode 100644 dnsapi/dns_dnsimple.sh diff --git a/README.md b/README.md index 0a320369..34b9243a 100644 --- a/README.md +++ b/README.md @@ -292,6 +292,7 @@ You don't have to do anything manually! 1. CloudFlare.com API 1. DNSPod.cn API +1. DNSimple API 1. CloudXNS.com API 1. GoDaddy.com API 1. OVH, kimsufi, soyoustart and runabove API diff --git a/dnsapi/README.md b/dnsapi/README.md index 12d76bef..ad03ea79 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -422,31 +422,31 @@ acme.sh --issue --dns dns_cloudns -d example.com -d www.example.com ``` ## 22. Use Infoblox API - + First you need to create/obtain API credentials on your Infoblox appliance. - + ``` export Infoblox_Creds="username:password" export Infoblox_Server="ip or fqdn of infoblox appliance" ``` - + Ok, let's issue a cert now: ``` acme.sh --issue --dns dns_infoblox -d example.com -d www.example.com ``` - + Note: This script will automatically create and delete the ephemeral txt record. The `Infoblox_Creds` and `Infoblox_Server` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. ## 23. Use VSCALE API - + First you need to create/obtain API tokens on your [settings panel](https://vscale.io/panel/settings/tokens/). - + ``` VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" ``` - + Ok, let's issue a cert now: ``` acme.sh --issue --dns dns_vscale -d example.com -d www.example.com @@ -468,6 +468,28 @@ acme.sh --issue --dns dns_dynu -d example.com -d www.example.com The `Dynu_ClientId` and `Dynu_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 25. Use DNSimple API + +First you need to login to your DNSimple account and generate a new oauth token. + +https://dnsimple.com/a/{your account id}/account/access_tokens + +Note that this is an _account_ token and not a user token. The account token is +needed to infer the `account_id` used in requests. A user token will not be able +to determine the correct account to use. + +``` +export DNSimple_OAUTH_TOKEN="sdfsdfsdfljlbjkljlkjsdfoiwje" +``` + +To issue the cert just specify the `dns_dnsimple` API. + +``` +acme.sh --issue --dns dns_dnsimple -d example.com +``` + +The `DNSimple_OAUTH_TOKEN` will be saved in `~/.acme.sh/account.conf` and will +be reused when needed. # Use custom API diff --git a/dnsapi/dns_dnsimple.sh b/dnsapi/dns_dnsimple.sh new file mode 100644 index 00000000..d714d36c --- /dev/null +++ b/dnsapi/dns_dnsimple.sh @@ -0,0 +1,163 @@ +#!/usr/bin/env sh + +# DNSimple domain api +# +# This is your oauth token which can be acquired on the account page. Please +# note that this must be an _account_ token and not a _user_ token. +# https://dnsimple.com/a//account/access_tokens +# DNSimple_OAUTH_TOKEN="sdfsdfsdfljlbjkljlkjsdfoiwje" + +DNSimple_API="https://api.dnsimple.com/v2" + +######## Public functions ##################### + +# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_dnsimple_add() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$DNSimple_OAUTH_TOKEN" ]; then + DNSimple_OAUTH_TOKEN="" + _err "You have not set the dnsimple oauth token yet." + _err "Please visit https://dnsimple.com/user to generate it." + return 1 + fi + + # save the oauth token for later + _saveaccountconf DNSimple_OAUTH_TOKEN "$DNSimple_OAUTH_TOKEN" + + _debug "Retrive account ID" + if ! _get_account_id; then + _err "failed to retrive account id" + return 1 + fi + _debug _account_id "$_account_id" + + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain "$_domain" + _debug _sub_domain "$_sub_domain" + + _debug "Getting txt records" + _dnsimple_rest GET "$_account_id/zones/$_domain/records?per_page=100" + + if ! _contains "$response" "\"id\":"; then + _err "Error" + return 1 + fi + + count=$(printf "%s" "$response" | _egrep_o "\"name\":\"$_sub_domain\"" | wc -l | _egrep_o "[0-9]+") + _debug count "$count" + + if [ "$count" = "0" ]; then + _info "Adding record" + if _dnsimple_rest POST "$_account_id/zones/$_domain/records" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then + if printf -- "%s" "$response" | grep "\"name\":\"$_sub_domain\"" >/dev/null; then + _info "Added" + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + else + _info "Updating record" + record_id=$(printf "%s" "$response" | _egrep_o "\"id\":[^,]*,\"zone_id\":\"[^,]*\",\"parent_id\":null,\"name\":\"$_sub_domain\"" | cut -d: -f2 | cut -d, -f1) + _debug "record_id" "$record_id" + + _dnsimple_rest PATCH "$_account_id/zones/$_domain/records/$record_id" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}" + if [ "$?" = "0" ]; then + _info "Updated!" + #todo: check if the record takes effect + return 0 + fi + _err "Update error" + return 1 + fi +} + +# fulldomain +dns_dnsimple_rm() { + fulldomain=$1 + +} + +#################### Private functions bellow ################################## +# _acme-challenge.www.domain.com +# returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_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 ! _dnsimple_rest GET "$_account_id/zones/$h"; then + return 1 + fi + + if _contains "$response" 'not found'; then + _debug "$h not found" + else + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 + fi + p="$i" + i=$(_math "$i" + 1) + done + return 1 +} + +_get_account_id() { + if ! _dnsimple_rest GET "whoami"; then + return 1 + fi + + if _contains "$response" "\"account\":null"; then + _err "no account associated with this token" + return 1 + fi + + if _contains "$response" "timeout"; then + _err "timeout retrieving account_id" + return 1 + fi + + _account_id=$(printf "%s" "$response" | _egrep_o "\"id\":[^,]*,\"email\":" | cut -d: -f2 | cut -d, -f1) + return 0 +} + +_dnsimple_rest() { + method=$1 + path="$2" + data="$3" + request_url="$DNSimple_API/$path" + _debug "$path" + + _H1="Accept: application/json" + _H2="Authorization: Bearer $DNSimple_OAUTH_TOKEN" + if [ "$data" ]; then + _H1="Content-Type: application/json" + _debug data "$data" + response="$(_post "$data" "$request_url" "" "$method")" + else + response="$(_get "$request_url")" + fi + + if [ "$?" != "0" ]; then + _err "error $request_url" + return 1 + fi + _debug2 response "$response" + return 0 +} From 2b092539618fc4ca627f9aa2b7b021488e222397 Mon Sep 17 00:00:00 2001 From: Matthew Turney Date: Tue, 6 Dec 2016 08:32:14 -0600 Subject: [PATCH 107/115] link to contributor repo for support issues relating to the dnsimple API integration --- dnsapi/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index ad03ea79..f53d8ad4 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -491,6 +491,9 @@ acme.sh --issue --dns dns_dnsimple -d example.com The `DNSimple_OAUTH_TOKEN` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +If you have any issues with this integration please report them to +https://github.com/pho3nixf1re/acme.sh/issues. + # Use custom API If your API is not supported yet, you can write your own DNS API. From f4e81953ce59731c3c46f7dc6937417851bd6e88 Mon Sep 17 00:00:00 2001 From: Matthew Turney Date: Sun, 12 Feb 2017 16:07:05 -0600 Subject: [PATCH 108/115] provide a more general purpose request function This allows for more flexibility in the future. Most importantly being able to do more than just GET requests but any HTTP method. Specifically needed for DELETE requests. --- acme.sh | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 7ce947ea..3ccd8dc4 100755 --- a/acme.sh +++ b/acme.sh @@ -1592,12 +1592,17 @@ _post() { return $_ret } -# url getheader timeout _get() { - _debug GET + _request "$1" "$2" "$3" GET +} + +# url getheader timeout +_request() { url="$1" onlyheader="$2" t="$3" + method="$4" + _debug method $method _debug url "$url" _debug "timeout" "$t" @@ -1611,6 +1616,9 @@ _get() { if [ "$t" ]; then _CURL="$_CURL --connect-timeout $t" fi + if [ "$method" ]; then + _CURL="$_CURL -X $method" + fi _debug "_CURL" "$_CURL" if [ "$onlyheader" ]; then $_CURL -I --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$url" @@ -1633,6 +1641,9 @@ _get() { if [ "$t" ]; then _WGET="$_WGET --timeout=$t" fi + if [ "$method" ]; then + _WGET="$_WGET --method=$method" + fi _debug "_WGET" "$_WGET" if [ "$onlyheader" ]; then $_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -S -O /dev/null "$url" 2>&1 | sed 's/^[ ]*//g' From f9b419d1e40c6056675891e846841158f36dc01a Mon Sep 17 00:00:00 2001 From: Matthew Turney Date: Sun, 12 Feb 2017 16:08:32 -0600 Subject: [PATCH 109/115] cleanup dns in dnsimple api integration Implement the `_rm()` method for the DNSimple integration. This also required some changes and cleanup to DRY up the code. --- dnsapi/dns_dnsimple.sh | 96 +++++++++++++++++++++++++++++++----------- 1 file changed, 72 insertions(+), 24 deletions(-) diff --git a/dnsapi/dns_dnsimple.sh b/dnsapi/dns_dnsimple.sh index d714d36c..dde6638e 100644 --- a/dnsapi/dns_dnsimple.sh +++ b/dnsapi/dns_dnsimple.sh @@ -26,49 +26,35 @@ dns_dnsimple_add() { # save the oauth token for later _saveaccountconf DNSimple_OAUTH_TOKEN "$DNSimple_OAUTH_TOKEN" - _debug "Retrive account ID" if ! _get_account_id; then _err "failed to retrive account id" return 1 fi - _debug _account_id "$_account_id" if ! _get_root "$fulldomain"; then _err "invalid domain" return 1 fi - _debug _domain "$_domain" - _debug _sub_domain "$_sub_domain" - _debug "Getting txt records" - _dnsimple_rest GET "$_account_id/zones/$_domain/records?per_page=100" + _get_records $_account_id $_domain $_sub_domain - if ! _contains "$response" "\"id\":"; then - _err "Error" - return 1 - fi - - count=$(printf "%s" "$response" | _egrep_o "\"name\":\"$_sub_domain\"" | wc -l | _egrep_o "[0-9]+") - _debug count "$count" - - if [ "$count" = "0" ]; then + if [ "$_records_count" = "0" ]; then _info "Adding record" if _dnsimple_rest POST "$_account_id/zones/$_domain/records" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then if printf -- "%s" "$response" | grep "\"name\":\"$_sub_domain\"" >/dev/null; then _info "Added" return 0 else - _err "Add txt record error." + _err "Unexpected response while adding text record." return 1 fi fi _err "Add txt record error." else _info "Updating record" - record_id=$(printf "%s" "$response" | _egrep_o "\"id\":[^,]*,\"zone_id\":\"[^,]*\",\"parent_id\":null,\"name\":\"$_sub_domain\"" | cut -d: -f2 | cut -d, -f1) - _debug "record_id" "$record_id" + _extract_record_id $_records $_sub_domain - _dnsimple_rest PATCH "$_account_id/zones/$_domain/records/$record_id" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}" + _dnsimple_rest PATCH "$_account_id/zones/$_domain/records/$_record_id" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}" if [ "$?" = "0" ]; then _info "Updated!" #todo: check if the record takes effect @@ -83,6 +69,31 @@ dns_dnsimple_add() { dns_dnsimple_rm() { fulldomain=$1 + if ! _get_account_id; then + _err "failed to retrive account id" + return 1 + fi + + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _get_records $_account_id $_domain $_sub_domain + _extract_record_id $_records $_sub_domain + + if [ "$_record_id" ]; then + _dnsimple_rest DELETE "$_account_id/zones/$_domain/records/$_record_id" + + if [ "$?" = "0" ]; then + _info "removed record" "$_record_id" + return 0 + fi + fi + + _err "failed to remove record" "$_record_id" + return 1 + } #################### Private functions bellow ################################## @@ -93,7 +104,7 @@ dns_dnsimple_rm() { _get_root() { domain=$1 i=2 - p=1 + previous=1 while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) if [ -z "$h" ]; then @@ -108,17 +119,24 @@ _get_root() { if _contains "$response" 'not found'; then _debug "$h not found" else - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$previous) _domain="$h" + + _debug _domain "$_domain" + _debug _sub_domain "$_sub_domain" + return 0 fi - p="$i" + + previous="$i" i=$(_math "$i" + 1) done return 1 } +# returns _account_id _get_account_id() { + _debug "retrive account id" if ! _dnsimple_rest GET "whoami"; then return 1 fi @@ -129,14 +147,44 @@ _get_account_id() { fi if _contains "$response" "timeout"; then - _err "timeout retrieving account_id" + _err "timeout retrieving account id" return 1 fi _account_id=$(printf "%s" "$response" | _egrep_o "\"id\":[^,]*,\"email\":" | cut -d: -f2 | cut -d, -f1) + _debug _account_id "$_account_id" + return 0 } +# returns +# _records +# _records_count +_get_records() { + account_id=$1 + domain=$2 + sub_domain=$3 + + _debug "fetching txt records" + _dnsimple_rest GET "$account_id/zones/$domain/records?per_page=100" + + if ! _contains "$response" "\"id\":"; then + _err "failed to retrieve records" + return 1 + fi + + _records_count=$(printf "%s" "$response" | _egrep_o "\"name\":\"$sub_domain\"" | wc -l | _egrep_o "[0-9]+") + _records=$response + _debug _records_count "$_records_count" +} + +# returns _record_id +_extract_record_id() { + _record_id=$(printf "%s" "$_records" | _egrep_o "\"id\":[^,]*,\"zone_id\":\"[^,]*\",\"parent_id\":null,\"name\":\"$_sub_domain\"" | cut -d: -f2 | cut -d, -f1) + _debug "_record_id" "$_record_id" +} + +# returns response _dnsimple_rest() { method=$1 path="$2" @@ -151,7 +199,7 @@ _dnsimple_rest() { _debug data "$data" response="$(_post "$data" "$request_url" "" "$method")" else - response="$(_get "$request_url")" + response="$(_request "$request_url" "" "" "$method")" fi if [ "$?" != "0" ]; then From 326ac485b35e2783365f5ab660caec28fc64d794 Mon Sep 17 00:00:00 2001 From: Matthew Turney Date: Sun, 12 Feb 2017 16:15:37 -0600 Subject: [PATCH 110/115] link to repo for dnsimple integration support --- dnsapi/dns_dnsimple.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/dnsapi/dns_dnsimple.sh b/dnsapi/dns_dnsimple.sh index dde6638e..f1c841dc 100644 --- a/dnsapi/dns_dnsimple.sh +++ b/dnsapi/dns_dnsimple.sh @@ -1,6 +1,7 @@ #!/usr/bin/env sh # DNSimple domain api +# https://github.com/pho3nixf1re/acme.sh/issues # # This is your oauth token which can be acquired on the account page. Please # note that this must be an _account_ token and not a _user_ token. From 2f4111a2e2ed01c27e070b375fa3f0179d0b46d3 Mon Sep 17 00:00:00 2001 From: Matthew Turney Date: Mon, 13 Feb 2017 11:37:34 -0600 Subject: [PATCH 111/115] fixup shellcheck style issues --- dnsapi/dns_dnsimple.sh | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/dnsapi/dns_dnsimple.sh b/dnsapi/dns_dnsimple.sh index f1c841dc..d92c6137 100644 --- a/dnsapi/dns_dnsimple.sh +++ b/dnsapi/dns_dnsimple.sh @@ -37,7 +37,7 @@ dns_dnsimple_add() { return 1 fi - _get_records $_account_id $_domain $_sub_domain + _get_records "$_account_id" "$_domain" "$_sub_domain" if [ "$_records_count" = "0" ]; then _info "Adding record" @@ -53,14 +53,17 @@ dns_dnsimple_add() { _err "Add txt record error." else _info "Updating record" - _extract_record_id $_records $_sub_domain + _extract_record_id "$_records" "$_sub_domain" + + if _dnsimple_rest \ + PATCH \ + "$_account_id/zones/$_domain/records/$_record_id" \ + "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then - _dnsimple_rest PATCH "$_account_id/zones/$_domain/records/$_record_id" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}" - if [ "$?" = "0" ]; then _info "Updated!" - #todo: check if the record takes effect return 0 fi + _err "Update error" return 1 fi @@ -80,13 +83,12 @@ dns_dnsimple_rm() { return 1 fi - _get_records $_account_id $_domain $_sub_domain - _extract_record_id $_records $_sub_domain + _get_records "$_account_id" "$_domain" "$_sub_domain" + _extract_record_id "$_records" "$_sub_domain" if [ "$_record_id" ]; then - _dnsimple_rest DELETE "$_account_id/zones/$_domain/records/$_record_id" - if [ "$?" = "0" ]; then + if _dnsimple_rest DELETE "$_account_id/zones/$_domain/records/$_record_id"; then _info "removed record" "$_record_id" return 0 fi @@ -193,8 +195,9 @@ _dnsimple_rest() { request_url="$DNSimple_API/$path" _debug "$path" - _H1="Accept: application/json" - _H2="Authorization: Bearer $DNSimple_OAUTH_TOKEN" + export _H1="Accept: application/json" + export _H2="Authorization: Bearer $DNSimple_OAUTH_TOKEN" + if [ "$data" ]; then _H1="Content-Type: application/json" _debug data "$data" From 5b21cbe0de81f858e29a5abf3e3c0c35ae6a18d3 Mon Sep 17 00:00:00 2001 From: Matthew Turney Date: Mon, 1 May 2017 20:56:04 -0500 Subject: [PATCH 112/115] Revert "provide a more general purpose request function" This reverts commit aa86652db8d3132fb7fe0c0253dded7deb7dce2c. This is not actually necessary and can be accomplished with the post function. --- acme.sh | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/acme.sh b/acme.sh index 3ccd8dc4..7ce947ea 100755 --- a/acme.sh +++ b/acme.sh @@ -1592,17 +1592,12 @@ _post() { return $_ret } -_get() { - _request "$1" "$2" "$3" GET -} - # url getheader timeout -_request() { +_get() { + _debug GET url="$1" onlyheader="$2" t="$3" - method="$4" - _debug method $method _debug url "$url" _debug "timeout" "$t" @@ -1616,9 +1611,6 @@ _request() { if [ "$t" ]; then _CURL="$_CURL --connect-timeout $t" fi - if [ "$method" ]; then - _CURL="$_CURL -X $method" - fi _debug "_CURL" "$_CURL" if [ "$onlyheader" ]; then $_CURL -I --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$url" @@ -1641,9 +1633,6 @@ _request() { if [ "$t" ]; then _WGET="$_WGET --timeout=$t" fi - if [ "$method" ]; then - _WGET="$_WGET --method=$method" - fi _debug "_WGET" "$_WGET" if [ "$onlyheader" ]; then $_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -S -O /dev/null "$url" 2>&1 | sed 's/^[ ]*//g' From 533238712536e3a11c2b09b4d0d480891cfd3d9f Mon Sep 17 00:00:00 2001 From: Matthew Turney Date: Tue, 2 May 2017 08:51:43 -0500 Subject: [PATCH 113/115] Use _post to send a DELETE request for DNSimple record removal. --- dnsapi/dns_dnsimple.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_dnsimple.sh b/dnsapi/dns_dnsimple.sh index d92c6137..0bfe2b99 100644 --- a/dnsapi/dns_dnsimple.sh +++ b/dnsapi/dns_dnsimple.sh @@ -198,12 +198,12 @@ _dnsimple_rest() { export _H1="Accept: application/json" export _H2="Authorization: Bearer $DNSimple_OAUTH_TOKEN" - if [ "$data" ]; then + if [ "$data" ] || [ "$method" = "DELETE" ]; then _H1="Content-Type: application/json" _debug data "$data" response="$(_post "$data" "$request_url" "" "$method")" else - response="$(_request "$request_url" "" "" "$method")" + response="$(_get "$request_url" "" "" "$method")" fi if [ "$?" != "0" ]; then From 4c38fec3b57e23d5aece5dfd92ac1f50abc6b150 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 3 May 2017 23:07:30 +0800 Subject: [PATCH 114/115] update doc --- README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 34b9243a..0cb800eb 100644 --- a/README.md +++ b/README.md @@ -136,13 +136,25 @@ root@v1:~# acme.sh -h acme.sh --issue -d example.com -w /home/wwwroot/example.com ``` +or: + +```bash +acme.sh --issue -d example.com -w /home/username/public_html +``` + +or: + +```bash +acme.sh --issue -d example.com -w /var/www/html +``` + **Example 2:** Multiple domains in the same cert. ```bash acme.sh --issue -d example.com -d www.example.com -d cp.example.com -w /home/wwwroot/example.com ``` -The parameter `/home/wwwroot/example.com` is the web root folder. You **MUST** have `write access` to this folder. +The parameter `/home/wwwroot/example.com` or `/home/username/public_html` or `/var/www/html` is the web root folder where you host your website files. You **MUST** have `write access` to this folder. Second argument **"example.com"** is the main domain you want to issue the cert for. You must have at least one domain there. From cc1d3b20b60a9f729bbd0f61f6563d2fe34772d4 Mon Sep 17 00:00:00 2001 From: wizard1024 Date: Fri, 5 May 2017 14:55:51 +0300 Subject: [PATCH 115/115] Update dns_aws.sh to work only with public zones --- dnsapi/dns_aws.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 21e86686..800c3d09 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -106,7 +106,7 @@ _get_root() { fi if _contains "$response" "$h."; then - hostedzone="$(echo "$response" | sed 's//#&/g' | tr '#' '\n' | _egrep_o "[^<]*<.Id>$h.<.Name>.*<.HostedZone>")" + hostedzone="$(echo "$response" | sed 's//#&/g' | tr '#' '\n' | _egrep_o "[^<]*<.Id>$h.<.Name>.*false<.PrivateZone>.*<.HostedZone>")" _debug hostedzone "$hostedzone" if [ -z "$hostedzone" ]; then _err "Error, can not get hostedzone."