mirror of
				https://github.com/hiskang/acme.sh
				synced 2025-11-04 04:17:40 +00:00 
			
		
		
		
	Merge branch 'dev' into dnsapi/dns_dnsever
This commit is contained in:
		
						commit
						ac09468214
					
				
							
								
								
									
										144
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										144
									
								
								README.md
									
									
									
									
									
								
							@ -3,6 +3,8 @@
 | 
			
		||||
[](https://gitter.im/acme-sh/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
 | 
			
		||||
- An ACME protocol client written purely in Shell (Unix shell) language.
 | 
			
		||||
- Full ACME protocol implementation.
 | 
			
		||||
- Support ACME v1 and ACME v2
 | 
			
		||||
- Support ACME v2 wildcard certs
 | 
			
		||||
- Simple, powerful and very easy to use. You only need 3 minutes to learn it.
 | 
			
		||||
- Bash, dash and sh compatible.
 | 
			
		||||
- Simplest shell script for Let's Encrypt free certificate client.
 | 
			
		||||
@ -127,7 +129,7 @@ Ok, you are ready to issue certs now.
 | 
			
		||||
 | 
			
		||||
Show help message:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
```sh
 | 
			
		||||
root@v1:~# acme.sh -h
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
@ -164,16 +166,16 @@ You must have at least one domain there.
 | 
			
		||||
 | 
			
		||||
You must point and bind all the domains to the same webroot dir: `/home/wwwroot/example.com`.
 | 
			
		||||
 | 
			
		||||
Generated/issued certs will be placed in `~/.acme.sh/example.com/`
 | 
			
		||||
The certs will be placed in `~/.acme.sh/example.com/`
 | 
			
		||||
 | 
			
		||||
The issued cert will be renewed automatically every **60** days.
 | 
			
		||||
The certs will be renewed automatically every **60** days.
 | 
			
		||||
 | 
			
		||||
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 3. Install the issued cert to Apache/Nginx etc.
 | 
			
		||||
# 3. Install the cert to Apache/Nginx etc.
 | 
			
		||||
 | 
			
		||||
After you issue a cert, you probably want to install/copy the cert to your Apache/Nginx or other servers.
 | 
			
		||||
After the cert is generated, you probably want to install/copy the cert to your Apache/Nginx or other servers.
 | 
			
		||||
You **MUST** use this command to copy the certs to the target files, **DO NOT** use the certs files in **~/.acme.sh/** folder, they are for internal use only, the folder structure may change in the future.
 | 
			
		||||
 | 
			
		||||
**Apache** example:
 | 
			
		||||
@ -195,9 +197,9 @@ acme.sh --install-cert -d example.com \
 | 
			
		||||
 | 
			
		||||
Only the domain is required, all the other parameters are optional.
 | 
			
		||||
 | 
			
		||||
The ownership and permission info of existing files are preserved. You may want to precreate the files to have defined ownership and permission.
 | 
			
		||||
The ownership and permission info of existing files are preserved. You can pre-create the files to define the ownership and permission.
 | 
			
		||||
 | 
			
		||||
Install/copy the issued cert/key to the production Apache or Nginx path.
 | 
			
		||||
Install/copy the cert/key to the production Apache or Nginx path.
 | 
			
		||||
 | 
			
		||||
The cert will be renewed every **60** days by default (which is configurable). Once the cert is renewed, the Apache/Nginx service will be reloaded automatically by the command: `service apache2 force-reload` or `service nginx force-reload`.
 | 
			
		||||
 | 
			
		||||
@ -240,7 +242,7 @@ Particularly, if you are running an Apache server, you should use Apache mode in
 | 
			
		||||
 | 
			
		||||
Just set string "apache" as the second argument and it will force use of apache plugin automatically.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
```sh
 | 
			
		||||
acme.sh --issue --apache -d example.com -d www.example.com -d cp.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
@ -260,47 +262,13 @@ It will configure nginx server automatically to verify the domain and then resto
 | 
			
		||||
 | 
			
		||||
So, the config is not changed.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
```sh
 | 
			
		||||
acme.sh --issue --nginx -d example.com -d www.example.com -d cp.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
 | 
			
		||||
 | 
			
		||||
# 8. Use DNS mode:
 | 
			
		||||
 | 
			
		||||
Support the `dns-01` challenge.
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
acme.sh --issue --dns -d example.com -d www.example.com -d cp.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
You should get an output like below:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
Add the following txt record:
 | 
			
		||||
Domain:_acme-challenge.example.com
 | 
			
		||||
Txt value:9ihDbjYfTExAYeDs4DBUeuTo18KBzwvTEjUnSwd32-c
 | 
			
		||||
 | 
			
		||||
Add the following txt record:
 | 
			
		||||
Domain:_acme-challenge.www.example.com
 | 
			
		||||
Txt value:9ihDbjxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
 | 
			
		||||
 | 
			
		||||
Please add those txt records to the domains. Waiting for the dns to take effect.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Then just rerun with `renew` argument:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
acme.sh --renew -d example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Ok, it's finished.
 | 
			
		||||
 | 
			
		||||
**Take care, this is dns manual mode, it can not be renewed automatically. you will have to add a new txt record to your domain by your hand when you renew your cert.**
 | 
			
		||||
 | 
			
		||||
**Please use dns api mode instead.**
 | 
			
		||||
 | 
			
		||||
# 9. Automatic DNS API integration
 | 
			
		||||
# 8. Automatic DNS API integration
 | 
			
		||||
 | 
			
		||||
If your DNS provider supports API access, we can use that API to automatically issue the certs.
 | 
			
		||||
 | 
			
		||||
@ -343,8 +311,10 @@ You don't have to do anything manually!
 | 
			
		||||
1. INWX (https://www.inwx.de/)
 | 
			
		||||
1. Servercow (https://servercow.de)
 | 
			
		||||
1. Namesilo (https://www.namesilo.com)
 | 
			
		||||
1. InternetX autoDNS API (https://internetx.com)
 | 
			
		||||
1. Azure DNS
 | 
			
		||||
1. selectel.com(selectel.ru) DNS API
 | 
			
		||||
1. DNSEver(https://www.dnsever.com)
 | 
			
		||||
 | 
			
		||||
And: 
 | 
			
		||||
 | 
			
		||||
1. lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api
 | 
			
		||||
@ -358,6 +328,39 @@ If your DNS provider is not on the supported list above, you can write your own
 | 
			
		||||
 | 
			
		||||
For more details: [How to use DNS API](dnsapi)
 | 
			
		||||
 | 
			
		||||
# 9. Use DNS manual mode:
 | 
			
		||||
 | 
			
		||||
If your dns provider doesn't support any api access, you will have to add the txt record by your hand.
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
acme.sh --issue --dns -d example.com -d www.example.com -d cp.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
You should get an output like below:
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
Add the following txt record:
 | 
			
		||||
Domain:_acme-challenge.example.com
 | 
			
		||||
Txt value:9ihDbjYfTExAYeDs4DBUeuTo18KBzwvTEjUnSwd32-c
 | 
			
		||||
 | 
			
		||||
Add the following txt record:
 | 
			
		||||
Domain:_acme-challenge.www.example.com
 | 
			
		||||
Txt value:9ihDbjxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
 | 
			
		||||
 | 
			
		||||
Please add those txt records to the domains. Waiting for the dns to take effect.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Then just rerun with `renew` argument:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
acme.sh --renew -d example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Ok, it's done.
 | 
			
		||||
 | 
			
		||||
**Take care, this is dns manual mode, it can not be renewed automatically. you will have to add a new txt record to your domain by your hand when you renew your cert.**
 | 
			
		||||
 | 
			
		||||
**Please use dns api mode instead.**
 | 
			
		||||
 | 
			
		||||
# 10. Issue ECC certificates
 | 
			
		||||
 | 
			
		||||
@ -390,36 +393,60 @@ Valid values are:
 | 
			
		||||
3. **ec-521 (secp521r1,  "ECDSA P-521", which is not supported by Let's Encrypt yet.)**
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 11. How to renew the issued certs
 | 
			
		||||
 | 
			
		||||
# 11. Issue Wildcard certificates
 | 
			
		||||
 | 
			
		||||
It's simple, just give a wildcard domain as the `-d` parameter.
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
acme.sh  --issue -d example.com  -d *.example.com  --dns dns_cf
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 12. How to renew the certs
 | 
			
		||||
 | 
			
		||||
No, you don't need to renew the certs manually. All the certs will be renewed automatically every **60** days.
 | 
			
		||||
 | 
			
		||||
However, you can also force to renew any cert:
 | 
			
		||||
However, you can also force to renew a cert:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
```sh
 | 
			
		||||
acme.sh --renew -d example.com --force
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
or, for ECC cert:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
```sh
 | 
			
		||||
acme.sh --renew -d example.com --force --ecc
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 12. How to upgrade `acme.sh`
 | 
			
		||||
# 13. How to stop cert renewal
 | 
			
		||||
 | 
			
		||||
To stop renewal of a cert, you can execute the following to remove the cert from the renewal list:
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
acme.sh --remove -d example.com [--ecc]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The cert/key file is not removed from the disk.
 | 
			
		||||
 | 
			
		||||
You can remove the respective directory (e.g. `~/.acme.sh/example.com`) by yourself.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 14. How to upgrade `acme.sh`
 | 
			
		||||
 | 
			
		||||
acme.sh is in constant development, so it's strongly recommended to use the latest code.
 | 
			
		||||
 | 
			
		||||
You can update acme.sh to the latest code:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
```sh
 | 
			
		||||
acme.sh --upgrade
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
You can also enable auto upgrade:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
```sh
 | 
			
		||||
acme.sh --upgrade --auto-upgrade
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
@ -427,31 +454,30 @@ Then **acme.sh** will be kept up to date automatically.
 | 
			
		||||
 | 
			
		||||
Disable auto upgrade:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
```sh
 | 
			
		||||
acme.sh --upgrade --auto-upgrade 0
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 13. Issue a cert from an existing CSR
 | 
			
		||||
# 15. Issue a cert from an existing CSR
 | 
			
		||||
 | 
			
		||||
https://github.com/Neilpang/acme.sh/wiki/Issue-a-cert-from-existing-CSR
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 14. Under the Hood
 | 
			
		||||
# 16. Under the Hood
 | 
			
		||||
 | 
			
		||||
Speak ACME language using shell, directly to "Let's Encrypt".
 | 
			
		||||
 | 
			
		||||
TODO:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 15. Acknowledgments
 | 
			
		||||
# 17. Acknowledgments
 | 
			
		||||
 | 
			
		||||
1. Acme-tiny: https://github.com/diafygi/acme-tiny
 | 
			
		||||
2. ACME protocol: https://github.com/ietf-wg-acme/acme
 | 
			
		||||
3. Certbot: https://github.com/certbot/certbot
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 16. License & Others
 | 
			
		||||
# 18. License & Others
 | 
			
		||||
 | 
			
		||||
License is GPLv3
 | 
			
		||||
 | 
			
		||||
@ -460,7 +486,7 @@ Please Star and Fork me.
 | 
			
		||||
[Issues](https://github.com/Neilpang/acme.sh/issues) and [pull requests](https://github.com/Neilpang/acme.sh/pulls) are welcome.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 17. Donate
 | 
			
		||||
# 19. Donate
 | 
			
		||||
Your donation makes **acme.sh** better:
 | 
			
		||||
 | 
			
		||||
1. PayPal/Alipay(支付宝)/Wechat(微信): [https://donate.acme.sh/](https://donate.acme.sh/)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										419
									
								
								acme.sh
									
									
									
									
									
								
							
							
						
						
									
										419
									
								
								acme.sh
									
									
									
									
									
								
							@ -13,8 +13,14 @@ _SCRIPT_="$0"
 | 
			
		||||
 | 
			
		||||
_SUB_FOLDERS="dnsapi deploy"
 | 
			
		||||
 | 
			
		||||
_OLD_CA_HOST="https://acme-v01.api.letsencrypt.org"
 | 
			
		||||
DEFAULT_CA="https://acme-v01.api.letsencrypt.org/directory"
 | 
			
		||||
LETSENCRYPT_CA_V1="https://acme-v01.api.letsencrypt.org/directory"
 | 
			
		||||
LETSENCRYPT_STAGING_CA_V1="https://acme-staging.api.letsencrypt.org/directory"
 | 
			
		||||
 | 
			
		||||
LETSENCRYPT_CA_V2="https://acme-v02.api.letsencrypt.org/directory"
 | 
			
		||||
LETSENCRYPT_STAGING_CA_V2="https://acme-staging-v02.api.letsencrypt.org/directory"
 | 
			
		||||
 | 
			
		||||
DEFAULT_CA=$LETSENCRYPT_CA_V1
 | 
			
		||||
DEFAULT_STAGING_CA=$LETSENCRYPT_STAGING_CA_V1
 | 
			
		||||
 | 
			
		||||
DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)"
 | 
			
		||||
DEFAULT_ACCOUNT_EMAIL=""
 | 
			
		||||
@ -24,13 +30,13 @@ DEFAULT_DOMAIN_KEY_LENGTH=2048
 | 
			
		||||
 | 
			
		||||
DEFAULT_OPENSSL_BIN="openssl"
 | 
			
		||||
 | 
			
		||||
STAGE_CA="https://acme-staging.api.letsencrypt.org/directory"
 | 
			
		||||
_OLD_CA_HOST="https://acme-v01.api.letsencrypt.org"
 | 
			
		||||
_OLD_STAGE_CA_HOST="https://acme-staging.api.letsencrypt.org"
 | 
			
		||||
 | 
			
		||||
VTYPE_HTTP="http-01"
 | 
			
		||||
VTYPE_DNS="dns-01"
 | 
			
		||||
VTYPE_TLS="tls-sni-01"
 | 
			
		||||
#VTYPE_TLS2="tls-sni-02"
 | 
			
		||||
VTYPE_TLS2="tls-sni-02"
 | 
			
		||||
 | 
			
		||||
LOCAL_ANY_ADDRESS="0.0.0.0"
 | 
			
		||||
 | 
			
		||||
@ -991,7 +997,7 @@ _createkey() {
 | 
			
		||||
_is_idn() {
 | 
			
		||||
  _is_idn_d="$1"
 | 
			
		||||
  _debug2 _is_idn_d "$_is_idn_d"
 | 
			
		||||
  _idn_temp=$(printf "%s" "$_is_idn_d" | tr -d '0-9' | tr -d 'a-z' | tr -d 'A-Z' | tr -d '.,-')
 | 
			
		||||
  _idn_temp=$(printf "%s" "$_is_idn_d" | tr -d '0-9' | tr -d 'a-z' | tr -d 'A-Z' | tr -d '*.,-')
 | 
			
		||||
  _debug2 _idn_temp "$_idn_temp"
 | 
			
		||||
  [ "$_idn_temp" ]
 | 
			
		||||
}
 | 
			
		||||
@ -1044,13 +1050,14 @@ _createcsr() {
 | 
			
		||||
  if [ -z "$domainlist" ] || [ "$domainlist" = "$NO_VALUE" ]; then
 | 
			
		||||
    #single domain
 | 
			
		||||
    _info "Single domain" "$domain"
 | 
			
		||||
    printf -- "\nsubjectAltName=DNS:$domain" >>"$csrconf"
 | 
			
		||||
  else
 | 
			
		||||
    domainlist="$(_idn "$domainlist")"
 | 
			
		||||
    _debug2 domainlist "$domainlist"
 | 
			
		||||
    if _contains "$domainlist" ","; then
 | 
			
		||||
      alt="DNS:$(echo "$domainlist" | sed "s/,/,DNS:/g")"
 | 
			
		||||
      alt="DNS:$domain,DNS:$(echo "$domainlist" | sed "s/,,/,/g" | sed "s/,/,DNS:/g")"
 | 
			
		||||
    else
 | 
			
		||||
      alt="DNS:$domainlist"
 | 
			
		||||
      alt="DNS:$domain,DNS:$domainlist"
 | 
			
		||||
    fi
 | 
			
		||||
    #multi
 | 
			
		||||
    _info "Multi domain" "$alt"
 | 
			
		||||
@ -1421,7 +1428,7 @@ _calcjwk() {
 | 
			
		||||
 | 
			
		||||
    JWK_HEADER='{"alg": "RS256", "jwk": '$jwk'}'
 | 
			
		||||
    JWK_HEADERPLACE_PART1='{"nonce": "'
 | 
			
		||||
    JWK_HEADERPLACE_PART2='", "alg": "RS256", "jwk": '$jwk'}'
 | 
			
		||||
    JWK_HEADERPLACE_PART2='", "alg": "RS256"'
 | 
			
		||||
  elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
 | 
			
		||||
    _debug "EC key"
 | 
			
		||||
    crv="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")"
 | 
			
		||||
@ -1490,7 +1497,7 @@ _calcjwk() {
 | 
			
		||||
 | 
			
		||||
    JWK_HEADER='{"alg": "ES'$__ECC_KEY_LEN'", "jwk": '$jwk'}'
 | 
			
		||||
    JWK_HEADERPLACE_PART1='{"nonce": "'
 | 
			
		||||
    JWK_HEADERPLACE_PART2='", "alg": "ES'$__ECC_KEY_LEN'", "jwk": '$jwk'}'
 | 
			
		||||
    JWK_HEADERPLACE_PART2='", "alg": "ES'$__ECC_KEY_LEN'"'
 | 
			
		||||
  else
 | 
			
		||||
    _err "Only RSA or EC key is supported."
 | 
			
		||||
    return 1
 | 
			
		||||
@ -1580,7 +1587,7 @@ _inithttp() {
 | 
			
		||||
# body  url [needbase64] [POST|PUT]
 | 
			
		||||
_post() {
 | 
			
		||||
  body="$1"
 | 
			
		||||
  url="$2"
 | 
			
		||||
  _post_url="$2"
 | 
			
		||||
  needbase64="$3"
 | 
			
		||||
  httpmethod="$4"
 | 
			
		||||
 | 
			
		||||
@ -1588,7 +1595,7 @@ _post() {
 | 
			
		||||
    httpmethod="POST"
 | 
			
		||||
  fi
 | 
			
		||||
  _debug $httpmethod
 | 
			
		||||
  _debug "url" "$url"
 | 
			
		||||
  _debug "_post_url" "$_post_url"
 | 
			
		||||
  _debug2 "body" "$body"
 | 
			
		||||
 | 
			
		||||
  _inithttp
 | 
			
		||||
@ -1600,9 +1607,9 @@ _post() {
 | 
			
		||||
    fi
 | 
			
		||||
    _debug "_CURL" "$_CURL"
 | 
			
		||||
    if [ "$needbase64" ]; then
 | 
			
		||||
      response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$url" | _base64)"
 | 
			
		||||
      response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)"
 | 
			
		||||
    else
 | 
			
		||||
      response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$url")"
 | 
			
		||||
      response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")"
 | 
			
		||||
    fi
 | 
			
		||||
    _ret="$?"
 | 
			
		||||
    if [ "$_ret" != "0" ]; then
 | 
			
		||||
@ -1620,15 +1627,15 @@ _post() {
 | 
			
		||||
    _debug "_WGET" "$_WGET"
 | 
			
		||||
    if [ "$needbase64" ]; then
 | 
			
		||||
      if [ "$httpmethod" = "POST" ]; then
 | 
			
		||||
        response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)"
 | 
			
		||||
        response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)"
 | 
			
		||||
      else
 | 
			
		||||
        response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)"
 | 
			
		||||
        response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)"
 | 
			
		||||
      fi
 | 
			
		||||
    else
 | 
			
		||||
      if [ "$httpmethod" = "POST" ]; then
 | 
			
		||||
        response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER")"
 | 
			
		||||
        response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER")"
 | 
			
		||||
      else
 | 
			
		||||
        response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER")"
 | 
			
		||||
        response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER")"
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
    _ret="$?"
 | 
			
		||||
@ -1656,7 +1663,7 @@ _get() {
 | 
			
		||||
  onlyheader="$2"
 | 
			
		||||
  t="$3"
 | 
			
		||||
  _debug url "$url"
 | 
			
		||||
  _debug "timeout" "$t"
 | 
			
		||||
  _debug "timeout=$t"
 | 
			
		||||
 | 
			
		||||
  _inithttp
 | 
			
		||||
 | 
			
		||||
@ -1776,7 +1783,15 @@ _send_signed_request() {
 | 
			
		||||
    nonce="$_CACHED_NONCE"
 | 
			
		||||
    _debug2 nonce "$nonce"
 | 
			
		||||
 | 
			
		||||
    protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2"
 | 
			
		||||
    if [ "$ACME_VERSION" = "2" ]; then
 | 
			
		||||
      if [ "$url" = "$ACME_NEW_ACCOUNT" ] || [ "$url" = "$ACME_REVOKE_CERT" ]; then
 | 
			
		||||
        protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}'
 | 
			
		||||
      else
 | 
			
		||||
        protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"kid\": \"${ACCOUNT_URL}\""'}'
 | 
			
		||||
      fi
 | 
			
		||||
    else
 | 
			
		||||
      protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}'
 | 
			
		||||
    fi
 | 
			
		||||
    _debug3 protected "$protected"
 | 
			
		||||
 | 
			
		||||
    protected64="$(printf "%s" "$protected" | _base64 | _url_replace)"
 | 
			
		||||
@ -1791,7 +1806,11 @@ _send_signed_request() {
 | 
			
		||||
    sig="$(printf "%s" "$_sig_t" | _url_replace)"
 | 
			
		||||
    _debug3 sig "$sig"
 | 
			
		||||
 | 
			
		||||
    if [ "$ACME_VERSION" = "2" ]; then
 | 
			
		||||
      body="{\"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}"
 | 
			
		||||
    else
 | 
			
		||||
      body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}"
 | 
			
		||||
    fi
 | 
			
		||||
    _debug3 body "$body"
 | 
			
		||||
 | 
			
		||||
    response="$(_post "$body" "$url" "$needbase64")"
 | 
			
		||||
@ -2170,9 +2189,15 @@ _initAPI() {
 | 
			
		||||
    _debug2 "response" "$response"
 | 
			
		||||
 | 
			
		||||
    ACME_KEY_CHANGE=$(echo "$response" | _egrep_o 'key-change" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
    if [ -z "$ACME_KEY_CHANGE" ]; then
 | 
			
		||||
      ACME_KEY_CHANGE=$(echo "$response" | _egrep_o 'keyChange" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
    fi
 | 
			
		||||
    export ACME_KEY_CHANGE
 | 
			
		||||
 | 
			
		||||
    ACME_NEW_AUTHZ=$(echo "$response" | _egrep_o 'new-authz" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
    if [ -z "$ACME_NEW_AUTHZ" ]; then
 | 
			
		||||
      ACME_NEW_AUTHZ=$(echo "$response" | _egrep_o 'newAuthz" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
    fi
 | 
			
		||||
    export ACME_NEW_AUTHZ
 | 
			
		||||
 | 
			
		||||
    ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-cert" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
@ -2180,6 +2205,9 @@ _initAPI() {
 | 
			
		||||
    if [ -z "$ACME_NEW_ORDER" ]; then
 | 
			
		||||
      ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-order" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
      ACME_NEW_ORDER_RES="new-order"
 | 
			
		||||
      if [ -z "$ACME_NEW_ORDER" ]; then
 | 
			
		||||
        ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'newOrder" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
    export ACME_NEW_ORDER
 | 
			
		||||
    export ACME_NEW_ORDER_RES
 | 
			
		||||
@ -2189,17 +2217,32 @@ _initAPI() {
 | 
			
		||||
    if [ -z "$ACME_NEW_ACCOUNT" ]; then
 | 
			
		||||
      ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-account" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
      ACME_NEW_ACCOUNT_RES="new-account"
 | 
			
		||||
      if [ -z "$ACME_NEW_ACCOUNT" ]; then
 | 
			
		||||
        ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'newAccount" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
        if [ "$ACME_NEW_ACCOUNT" ]; then
 | 
			
		||||
          export ACME_VERSION=2
 | 
			
		||||
        fi
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
    export ACME_NEW_ACCOUNT
 | 
			
		||||
    export ACME_NEW_ACCOUNT_RES
 | 
			
		||||
 | 
			
		||||
    ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revoke-cert" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
    if [ -z "$ACME_REVOKE_CERT" ]; then
 | 
			
		||||
      ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revokeCert" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
    fi
 | 
			
		||||
    export ACME_REVOKE_CERT
 | 
			
		||||
 | 
			
		||||
    ACME_NEW_NONCE=$(echo "$response" | _egrep_o 'new-nonce" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
    if [ -z "$ACME_NEW_NONCE" ]; then
 | 
			
		||||
      ACME_NEW_NONCE=$(echo "$response" | _egrep_o 'newNonce" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
    fi
 | 
			
		||||
    export ACME_NEW_NONCE
 | 
			
		||||
 | 
			
		||||
    ACME_AGREEMENT=$(echo "$response" | _egrep_o 'terms-of-service" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
    if [ -z "$ACME_AGREEMENT" ]; then
 | 
			
		||||
      ACME_AGREEMENT=$(echo "$response" | _egrep_o 'termsOfService" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
    fi
 | 
			
		||||
    export ACME_AGREEMENT
 | 
			
		||||
 | 
			
		||||
    _debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE"
 | 
			
		||||
@ -2208,12 +2251,16 @@ _initAPI() {
 | 
			
		||||
    _debug "ACME_NEW_ACCOUNT" "$ACME_NEW_ACCOUNT"
 | 
			
		||||
    _debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT"
 | 
			
		||||
    _debug "ACME_AGREEMENT" "$ACME_AGREEMENT"
 | 
			
		||||
    _debug "ACME_NEW_NONCE" "$ACME_NEW_NONCE"
 | 
			
		||||
    _debug "ACME_VERSION" "$ACME_VERSION"
 | 
			
		||||
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[domain]  [keylength or isEcc flag]
 | 
			
		||||
_initpath() {
 | 
			
		||||
  domain="$1"
 | 
			
		||||
  _ilength="$2"
 | 
			
		||||
 | 
			
		||||
  __initHome
 | 
			
		||||
 | 
			
		||||
@ -2232,11 +2279,16 @@ _initpath() {
 | 
			
		||||
    CA_HOME="$DEFAULT_CA_HOME"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ "$ACME_VERSION" = "2" ]; then
 | 
			
		||||
    DEFAULT_CA="$LETSENCRYPT_CA_V2"
 | 
			
		||||
    DEFAULT_STAGING_CA="$LETSENCRYPT_STAGING_CA_V2"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "$ACME_DIRECTORY" ]; then
 | 
			
		||||
    if [ -z "$STAGE" ]; then
 | 
			
		||||
      ACME_DIRECTORY="$DEFAULT_CA"
 | 
			
		||||
    else
 | 
			
		||||
      ACME_DIRECTORY="$STAGE_CA"
 | 
			
		||||
      ACME_DIRECTORY="$DEFAULT_STAGING_CA"
 | 
			
		||||
      _info "Using stage ACME_DIRECTORY: $ACME_DIRECTORY"
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
@ -2296,13 +2348,10 @@ _initpath() {
 | 
			
		||||
    ACME_OPENSSL_BIN="$DEFAULT_OPENSSL_BIN"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "$1" ]; then
 | 
			
		||||
  if [ -z "$domain" ]; then
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  domain="$1"
 | 
			
		||||
  _ilength="$2"
 | 
			
		||||
 | 
			
		||||
  if [ -z "$DOMAIN_PATH" ]; then
 | 
			
		||||
    domainhome="$CERT_HOME/$domain"
 | 
			
		||||
    domainhomeecc="$CERT_HOME/$domain$ECC_SUFFIX"
 | 
			
		||||
@ -2548,10 +2597,7 @@ _setNginx() {
 | 
			
		||||
  _d="$1"
 | 
			
		||||
  _croot="$2"
 | 
			
		||||
  _thumbpt="$3"
 | 
			
		||||
  if ! _exists "nginx"; then
 | 
			
		||||
    _err "nginx command is not found."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  FOUND_REAL_NGINX_CONF=""
 | 
			
		||||
  FOUND_REAL_NGINX_CONF_LN=""
 | 
			
		||||
  BACKUP_NGINX_CONF=""
 | 
			
		||||
@ -2561,6 +2607,10 @@ _setNginx() {
 | 
			
		||||
  if [ -z "$_start_f" ]; then
 | 
			
		||||
    _debug "find start conf from nginx command"
 | 
			
		||||
    if [ -z "$NGINX_CONF" ]; then
 | 
			
		||||
      if ! _exists "nginx"; then
 | 
			
		||||
        _err "nginx command is not found."
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
      NGINX_CONF="$(nginx -V 2>&1 | _egrep_o "--conf-path=[^ ]* " | tr -d " ")"
 | 
			
		||||
      _debug NGINX_CONF "$NGINX_CONF"
 | 
			
		||||
      NGINX_CONF="$(echo "$NGINX_CONF" | cut -d = -f 2)"
 | 
			
		||||
@ -2605,6 +2655,10 @@ _setNginx() {
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! _exists "nginx"; then
 | 
			
		||||
    _err "nginx command is not found."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _info "Check the nginx conf before setting up."
 | 
			
		||||
  if ! _exec "nginx -t" >/dev/null; then
 | 
			
		||||
    _exec_err
 | 
			
		||||
@ -2697,7 +2751,7 @@ _isRealNginxConf() {
 | 
			
		||||
    for _fln in $(tr "\t" ' ' <"$2" | grep -n "^ *server_name.* $1" | cut -d : -f 1); do
 | 
			
		||||
      _debug _fln "$_fln"
 | 
			
		||||
      if [ "$_fln" ]; then
 | 
			
		||||
        _start=$(tr "\t" ' ' <"$2" | _head_n "$_fln" | grep -n "^ *server *{" | _tail_n 1)
 | 
			
		||||
        _start=$(tr "\t" ' ' <"$2" | _head_n "$_fln" | grep -n "^ *server *" | grep -v server_name | _tail_n 1)
 | 
			
		||||
        _debug "_start" "$_start"
 | 
			
		||||
        _start_n=$(echo "$_start" | cut -d : -f 1)
 | 
			
		||||
        _start_nn=$(_math $_start_n + 1)
 | 
			
		||||
@ -2706,8 +2760,8 @@ _isRealNginxConf() {
 | 
			
		||||
 | 
			
		||||
        _left="$(sed -n "${_start_nn},99999p" "$2")"
 | 
			
		||||
        _debug2 _left "$_left"
 | 
			
		||||
        if echo "$_left" | tr "\t" ' ' | grep -n "^ *server *{" >/dev/null; then
 | 
			
		||||
          _end=$(echo "$_left" | tr "\t" ' ' | 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"
 | 
			
		||||
@ -2718,8 +2772,20 @@ _isRealNginxConf() {
 | 
			
		||||
 | 
			
		||||
        _debug "_seg_n" "$_seg_n"
 | 
			
		||||
 | 
			
		||||
        if [ "$(echo "$_seg_n" | _egrep_o "^ *ssl  *on *;")" ] \
 | 
			
		||||
          || [ "$(echo "$_seg_n" | _egrep_o "listen .* ssl[ |;]")" ]; then
 | 
			
		||||
        _skip_ssl=1
 | 
			
		||||
        for _listen_i in $(echo "$_seg_n" | tr "\t" ' ' | grep "^ *listen" | tr -d " "); do
 | 
			
		||||
          if [ "$_listen_i" ]; then
 | 
			
		||||
            if [ "$(echo "$_listen_i" | _egrep_o "listen.*ssl[ |;]")" ]; then
 | 
			
		||||
              _debug2 "$_listen_i is ssl"
 | 
			
		||||
            else
 | 
			
		||||
              _debug2 "$_listen_i is plain text"
 | 
			
		||||
              _skip_ssl=""
 | 
			
		||||
              break
 | 
			
		||||
            fi
 | 
			
		||||
          fi
 | 
			
		||||
        done
 | 
			
		||||
 | 
			
		||||
        if [ "$_skip_ssl" = "1" ]; then
 | 
			
		||||
          _debug "ssl on, skip"
 | 
			
		||||
        else
 | 
			
		||||
          FOUND_REAL_NGINX_CONF_LN=$_fln
 | 
			
		||||
@ -2818,7 +2884,11 @@ _clearupdns() {
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
 | 
			
		||||
      txtdomain="_acme-challenge.$d"
 | 
			
		||||
      _dns_root_d="$d"
 | 
			
		||||
      if _startswith "$_dns_root_d" "*."; then
 | 
			
		||||
        _dns_root_d="$(echo "$_dns_root_d" | sed 's/*.//')"
 | 
			
		||||
      fi
 | 
			
		||||
      txtdomain="_acme-challenge.$_dns_root_d"
 | 
			
		||||
 | 
			
		||||
      if ! $rmcommand "$txtdomain" "$txt"; then
 | 
			
		||||
        _err "Error removing txt for domain:$txtdomain"
 | 
			
		||||
@ -2951,6 +3021,7 @@ _on_issue_err() {
 | 
			
		||||
  _chk_post_hook="$1"
 | 
			
		||||
  _chk_vlist="$2"
 | 
			
		||||
  _debug _on_issue_err
 | 
			
		||||
 | 
			
		||||
  if [ "$LOG_FILE" ]; then
 | 
			
		||||
    _err "Please check log file for more details: $LOG_FILE"
 | 
			
		||||
  else
 | 
			
		||||
@ -3052,6 +3123,8 @@ _regAccount() {
 | 
			
		||||
  _initpath
 | 
			
		||||
  _reg_length="$1"
 | 
			
		||||
  _debug3 _regAccount "$_regAccount"
 | 
			
		||||
  _initAPI
 | 
			
		||||
 | 
			
		||||
  mkdir -p "$CA_DIR"
 | 
			
		||||
  if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then
 | 
			
		||||
    _info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH"
 | 
			
		||||
@ -3073,12 +3146,19 @@ _regAccount() {
 | 
			
		||||
  if ! _calcjwk "$ACCOUNT_KEY_PATH"; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _initAPI
 | 
			
		||||
 | 
			
		||||
  if [ "$ACME_VERSION" = "2" ]; then
 | 
			
		||||
    regjson='{"termsOfServiceAgreed": true}'
 | 
			
		||||
    if [ "$ACCOUNT_EMAIL" ]; then
 | 
			
		||||
      regjson='{"contact": ["mailto: '$ACCOUNT_EMAIL'"], "termsOfServiceAgreed": true}'
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    _reg_res="$ACME_NEW_ACCOUNT_RES"
 | 
			
		||||
    regjson='{"resource": "'$_reg_res'", "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}'
 | 
			
		||||
    if [ "$ACCOUNT_EMAIL" ]; then
 | 
			
		||||
      regjson='{"resource": "'$_reg_res'", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}'
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Registering account"
 | 
			
		||||
 | 
			
		||||
@ -3090,7 +3170,7 @@ _regAccount() {
 | 
			
		||||
  if [ "$code" = "" ] || [ "$code" = '201' ]; then
 | 
			
		||||
    echo "$response" >"$ACCOUNT_JSON_PATH"
 | 
			
		||||
    _info "Registered"
 | 
			
		||||
  elif [ "$code" = '409' ]; then
 | 
			
		||||
  elif [ "$code" = '409' ] || [ "$code" = '200' ]; then
 | 
			
		||||
    _info "Already registered"
 | 
			
		||||
  else
 | 
			
		||||
    _err "Register account Error: $response"
 | 
			
		||||
@ -3100,8 +3180,8 @@ _regAccount() {
 | 
			
		||||
  _accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")"
 | 
			
		||||
  _debug "_accUri" "$_accUri"
 | 
			
		||||
  _savecaconf "ACCOUNT_URL" "$_accUri"
 | 
			
		||||
  export ACCOUNT_URL="$ACCOUNT_URL"
 | 
			
		||||
 | 
			
		||||
  echo "$response" >"$ACCOUNT_JSON_PATH"
 | 
			
		||||
  CA_KEY_HASH="$(__calcAccountKeyHash)"
 | 
			
		||||
  _debug "Calc CA_KEY_HASH" "$CA_KEY_HASH"
 | 
			
		||||
  _savecaconf CA_KEY_HASH "$CA_KEY_HASH"
 | 
			
		||||
@ -3113,7 +3193,6 @@ _regAccount() {
 | 
			
		||||
 | 
			
		||||
  ACCOUNT_THUMBPRINT="$(__calc_account_thumbprint)"
 | 
			
		||||
  _info "ACCOUNT_THUMBPRINT" "$ACCOUNT_THUMBPRINT"
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#Implement deactivate account
 | 
			
		||||
@ -3149,7 +3228,12 @@ deactivateaccount() {
 | 
			
		||||
  fi
 | 
			
		||||
  _initAPI
 | 
			
		||||
 | 
			
		||||
  if _send_signed_request "$_accUri" "{\"resource\": \"reg\", \"status\":\"deactivated\"}" && _contains "$response" '"deactivated"'; then
 | 
			
		||||
  if [ "$ACME_VERSION" = "2" ]; then
 | 
			
		||||
    _djson="{\"status\":\"deactivated\"}"
 | 
			
		||||
  else
 | 
			
		||||
    _djson="{\"resource\": \"reg\", \"status\":\"deactivated\"}"
 | 
			
		||||
  fi
 | 
			
		||||
  if _send_signed_request "$_accUri" "$_djson" && _contains "$response" '"deactivated"'; then
 | 
			
		||||
    _info "Deactivate account success for $_accUri."
 | 
			
		||||
    _accid=$(echo "$response" | _egrep_o "\"id\" *: *[^,]*," | cut -d : -f 2 | tr -d ' ,')
 | 
			
		||||
  elif [ "$code" = "403" ]; then
 | 
			
		||||
@ -3237,7 +3321,7 @@ __get_domain_new_authz() {
 | 
			
		||||
    _err "new-authz retry reach the max $_Max_new_authz_retry_times times."
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ ! -z "$code" ] && [ ! "$code" = '201' ]; then
 | 
			
		||||
  if [ "$code" ] && [ "$code" != '201' ]; then
 | 
			
		||||
    _err "new-authz error: $response"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
@ -3251,7 +3335,11 @@ __trigger_validation() {
 | 
			
		||||
  _debug2 _t_url "$_t_url"
 | 
			
		||||
  _t_key_authz="$2"
 | 
			
		||||
  _debug2 _t_key_authz "$_t_key_authz"
 | 
			
		||||
  if [ "$ACME_VERSION" = "2" ]; then
 | 
			
		||||
    _send_signed_request "$_t_url" "{\"keyAuthorization\": \"$_t_key_authz\"}"
 | 
			
		||||
  else
 | 
			
		||||
    _send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$_t_key_authz\"}"
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#webroot, domain domainlist  keylength
 | 
			
		||||
@ -3267,6 +3355,7 @@ issue() {
 | 
			
		||||
  _web_roots="$1"
 | 
			
		||||
  _main_domain="$2"
 | 
			
		||||
  _alt_domains="$3"
 | 
			
		||||
 | 
			
		||||
  if _contains "$_main_domain" ","; then
 | 
			
		||||
    _main_domain=$(echo "$2,$3" | cut -d , -f 1)
 | 
			
		||||
    _alt_domains=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//")
 | 
			
		||||
@ -3393,33 +3482,110 @@ issue() {
 | 
			
		||||
  sep='#'
 | 
			
		||||
  dvsep=','
 | 
			
		||||
  if [ -z "$vlist" ]; then
 | 
			
		||||
    if [ "$ACME_VERSION" = "2" ]; then
 | 
			
		||||
      #make new order request
 | 
			
		||||
      _identifiers="{\"type\":\"dns\",\"value\":\"$_main_domain\"}"
 | 
			
		||||
      for d in $(echo "$_alt_domains" | tr ',' ' '); do
 | 
			
		||||
        if [ "$d" ]; then
 | 
			
		||||
          _identifiers="$_identifiers,{\"type\":\"dns\",\"value\":\"$d\"}"
 | 
			
		||||
        fi
 | 
			
		||||
      done
 | 
			
		||||
      _debug2 _identifiers "$_identifiers"
 | 
			
		||||
      if ! _send_signed_request "$ACME_NEW_ORDER" "{\"identifiers\": [$_identifiers]}"; then
 | 
			
		||||
        _err "Create new order error."
 | 
			
		||||
        _clearup
 | 
			
		||||
        _on_issue_err "$_post_hook"
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
 | 
			
		||||
      Le_OrderFinalize="$(echo "$response" | tr -d '\r\n' | _egrep_o '"finalize" *: *"[^"]*"' | cut -d '"' -f 4)"
 | 
			
		||||
      _debug Le_OrderFinalize "$Le_OrderFinalize"
 | 
			
		||||
      if [ -z "$Le_OrderFinalize" ]; then
 | 
			
		||||
        _err "Create new order error. Le_OrderFinalize not found. $response"
 | 
			
		||||
        _clearup
 | 
			
		||||
        _on_issue_err "$_post_hook"
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
 | 
			
		||||
      #for dns manual mode
 | 
			
		||||
      _savedomainconf "Le_OrderFinalize" "$Le_OrderFinalize"
 | 
			
		||||
 | 
			
		||||
      _authorizations_seg="$(echo "$response" | tr -d '\r\n' | _egrep_o '"authorizations" *: *\[[^\]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')"
 | 
			
		||||
      _debug2 _authorizations_seg "$_authorizations_seg"
 | 
			
		||||
      if [ -z "$_authorizations_seg" ]; then
 | 
			
		||||
        _err "_authorizations_seg not found."
 | 
			
		||||
        _clearup
 | 
			
		||||
        _on_issue_err "$_post_hook"
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
 | 
			
		||||
      #domain and authz map
 | 
			
		||||
      _authorizations_map=""
 | 
			
		||||
      for _authz_url in $(echo "$_authorizations_seg" | tr ',' ' '); do
 | 
			
		||||
        _debug2 "_authz_url" "$_authz_url"
 | 
			
		||||
        if ! response="$(_get "$_authz_url")"; then
 | 
			
		||||
          _err "get to authz error."
 | 
			
		||||
          _clearup
 | 
			
		||||
          _on_issue_err "$_post_hook"
 | 
			
		||||
          return 1
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        response="$(echo "$response" | _normalizeJson)"
 | 
			
		||||
        _debug2 response "$response"
 | 
			
		||||
        _d="$(echo "$response" | _egrep_o '"value" *: *"[^"]*"' | cut -d : -f 2 | tr -d ' "')"
 | 
			
		||||
        if _contains "$response" "\"wildcard\" *: *true"; then
 | 
			
		||||
          _d="*.$_d"
 | 
			
		||||
        fi
 | 
			
		||||
        _debug2 _d "$_d"
 | 
			
		||||
        _authorizations_map="$_d,$response
 | 
			
		||||
$_authorizations_map"
 | 
			
		||||
      done
 | 
			
		||||
      _debug2 _authorizations_map "$_authorizations_map"
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    alldomains=$(echo "$_main_domain,$_alt_domains" | tr ',' ' ')
 | 
			
		||||
    _index=1
 | 
			
		||||
    _index=0
 | 
			
		||||
    _currentRoot=""
 | 
			
		||||
    for d in $alldomains; do
 | 
			
		||||
      _info "Getting webroot for domain" "$d"
 | 
			
		||||
      _index=$(_math $_index + 1)
 | 
			
		||||
      _w="$(echo $_web_roots | cut -d , -f $_index)"
 | 
			
		||||
      _debug _w "$_w"
 | 
			
		||||
      if [ "$_w" ]; then
 | 
			
		||||
        _currentRoot="$_w"
 | 
			
		||||
      fi
 | 
			
		||||
      _debug "_currentRoot" "$_currentRoot"
 | 
			
		||||
      _index=$(_math $_index + 1)
 | 
			
		||||
 | 
			
		||||
      vtype="$VTYPE_HTTP"
 | 
			
		||||
      #todo, v2 wildcard force to use dns
 | 
			
		||||
      if _startswith "$_currentRoot" "dns"; then
 | 
			
		||||
        vtype="$VTYPE_DNS"
 | 
			
		||||
      fi
 | 
			
		||||
 | 
			
		||||
      if [ "$_currentRoot" = "$W_TLS" ]; then
 | 
			
		||||
        if [ "$ACME_VERSION" = "2" ]; then
 | 
			
		||||
          vtype="$VTYPE_TLS2"
 | 
			
		||||
        else
 | 
			
		||||
          vtype="$VTYPE_TLS"
 | 
			
		||||
        fi
 | 
			
		||||
      fi
 | 
			
		||||
 | 
			
		||||
      if [ "$ACME_VERSION" = "2" ]; then
 | 
			
		||||
        response="$(echo "$_authorizations_map" | grep "^$d," | sed "s/$d,//")"
 | 
			
		||||
        _debug2 "response" "$response"
 | 
			
		||||
        if [ -z "$response" ]; then
 | 
			
		||||
          _err "get to authz error."
 | 
			
		||||
          _clearup
 | 
			
		||||
          _on_issue_err "$_post_hook"
 | 
			
		||||
          return 1
 | 
			
		||||
        fi
 | 
			
		||||
      else
 | 
			
		||||
        if ! __get_domain_new_authz "$d"; then
 | 
			
		||||
          _clearup
 | 
			
		||||
          _on_issue_err "$_post_hook"
 | 
			
		||||
          return 1
 | 
			
		||||
        fi
 | 
			
		||||
      fi
 | 
			
		||||
 | 
			
		||||
      if [ -z "$thumbprint" ]; then
 | 
			
		||||
        thumbprint="$(__calc_account_thumbprint)"
 | 
			
		||||
@ -3428,7 +3594,7 @@ issue() {
 | 
			
		||||
      entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')"
 | 
			
		||||
      _debug entry "$entry"
 | 
			
		||||
      if [ -z "$entry" ]; then
 | 
			
		||||
        _err "Error, can not get domain token $d"
 | 
			
		||||
        _err "Error, can not get domain token entry $d"
 | 
			
		||||
        _clearup
 | 
			
		||||
        _on_issue_err "$_post_hook"
 | 
			
		||||
        return 1
 | 
			
		||||
@ -3436,14 +3602,30 @@ issue() {
 | 
			
		||||
      token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')"
 | 
			
		||||
      _debug token "$token"
 | 
			
		||||
 | 
			
		||||
      if [ -z "$token" ]; then
 | 
			
		||||
        _err "Error, can not get domain token $entry"
 | 
			
		||||
        _clearup
 | 
			
		||||
        _on_issue_err "$_post_hook"
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
      if [ "$ACME_VERSION" = "2" ]; then
 | 
			
		||||
        uri="$(printf "%s\n" "$entry" | _egrep_o '"url":"[^"]*' | cut -d '"' -f 4 | _head_n 1)"
 | 
			
		||||
      else
 | 
			
		||||
        uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d '"' -f 4)"
 | 
			
		||||
      fi
 | 
			
		||||
      _debug uri "$uri"
 | 
			
		||||
 | 
			
		||||
      if [ -z "$uri" ]; then
 | 
			
		||||
        _err "Error, can not get domain uri. $entry"
 | 
			
		||||
        _clearup
 | 
			
		||||
        _on_issue_err "$_post_hook"
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
      keyauthorization="$token.$thumbprint"
 | 
			
		||||
      _debug keyauthorization "$keyauthorization"
 | 
			
		||||
 | 
			
		||||
      if printf "%s" "$response" | grep '"status":"valid"' >/dev/null 2>&1; then
 | 
			
		||||
        _debug "$d is already verified, skip."
 | 
			
		||||
        _debug "$d is already verified."
 | 
			
		||||
        keyauthorization="$STATE_VERIFIED"
 | 
			
		||||
        _debug keyauthorization "$keyauthorization"
 | 
			
		||||
      fi
 | 
			
		||||
@ -3463,7 +3645,7 @@ issue() {
 | 
			
		||||
      keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2)
 | 
			
		||||
      vtype=$(echo "$ventry" | cut -d "$sep" -f 4)
 | 
			
		||||
      _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5)
 | 
			
		||||
 | 
			
		||||
      _debug d "$d"
 | 
			
		||||
      if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then
 | 
			
		||||
        _debug "$d is already verified, skip $vtype."
 | 
			
		||||
        continue
 | 
			
		||||
@ -3471,12 +3653,16 @@ issue() {
 | 
			
		||||
 | 
			
		||||
      if [ "$vtype" = "$VTYPE_DNS" ]; then
 | 
			
		||||
        dnsadded='0'
 | 
			
		||||
        txtdomain="_acme-challenge.$d"
 | 
			
		||||
        _dns_root_d="$d"
 | 
			
		||||
        if _startswith "$_dns_root_d" "*."; then
 | 
			
		||||
          _dns_root_d="$(echo "$_dns_root_d" | sed 's/*.//')"
 | 
			
		||||
        fi
 | 
			
		||||
        txtdomain="_acme-challenge.$_dns_root_d"
 | 
			
		||||
        _debug txtdomain "$txtdomain"
 | 
			
		||||
        txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _url_replace)"
 | 
			
		||||
        _debug txt "$txt"
 | 
			
		||||
 | 
			
		||||
        d_api="$(_findHook "$d" dnsapi "$_currentRoot")"
 | 
			
		||||
        d_api="$(_findHook "$_dns_root_d" dnsapi "$_currentRoot")"
 | 
			
		||||
 | 
			
		||||
        _debug d_api "$d_api"
 | 
			
		||||
 | 
			
		||||
@ -3685,13 +3871,17 @@ issue() {
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if [ ! -z "$code" ] && [ ! "$code" = '202' ]; then
 | 
			
		||||
    if [ "$code" ] && [ "$code" != '202' ]; then
 | 
			
		||||
      if [ "$ACME_VERSION" = "2" ] && [ "$code" = '200' ]; then
 | 
			
		||||
        _debug "trigger validation code: $code"
 | 
			
		||||
      else
 | 
			
		||||
        _err "$d:Challenge error: $response"
 | 
			
		||||
        _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
 | 
			
		||||
        _clearup
 | 
			
		||||
        _on_issue_err "$_post_hook" "$vlist"
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    waittimes=0
 | 
			
		||||
    if [ -z "$MAX_RETRY_TIMES" ]; then
 | 
			
		||||
@ -3773,18 +3963,42 @@ issue() {
 | 
			
		||||
  _info "Verify finished, start to sign."
 | 
			
		||||
  der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)"
 | 
			
		||||
 | 
			
		||||
  if [ "$ACME_VERSION" = "2" ]; then
 | 
			
		||||
    if ! _send_signed_request "${Le_OrderFinalize}" "{\"csr\": \"$der\"}"; then
 | 
			
		||||
      _err "Sign failed."
 | 
			
		||||
      _on_issue_err "$_post_hook"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    if [ "$code" != "200" ]; then
 | 
			
		||||
      _err "Sign failed, code is not 200."
 | 
			
		||||
      _on_issue_err "$_post_hook"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    Le_LinkCert="$(echo "$response" | tr -d '\r\n' | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)"
 | 
			
		||||
 | 
			
		||||
    if ! _get "$Le_LinkCert" >"$CERT_PATH"; then
 | 
			
		||||
      _err "Sign failed, code is not 200."
 | 
			
		||||
      _on_issue_err "$_post_hook"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if [ "$(grep -- "$BEGIN_CERT" "$CERT_PATH" | wc -l)" -gt "1" ]; then
 | 
			
		||||
      _debug "Found cert chain"
 | 
			
		||||
      cat "$CERT_PATH" >"$CERT_FULLCHAIN_PATH"
 | 
			
		||||
      _end_n="$(grep -n -- "$END_CERT" "$CERT_FULLCHAIN_PATH" | _head_n 1 | cut -d : -f 1)"
 | 
			
		||||
      _debug _end_n "$_end_n"
 | 
			
		||||
      sed -n "1,${_end_n}p" "$CERT_FULLCHAIN_PATH" >"$CERT_PATH"
 | 
			
		||||
      _end_n="$(_math $_end_n + 1)"
 | 
			
		||||
      sed -n "${_end_n},9999p" "$CERT_FULLCHAIN_PATH" >"$CA_CERT_PATH"
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"$ACME_NEW_ORDER_RES\", \"csr\": \"$der\"}" "needbase64"; then
 | 
			
		||||
      _err "Sign failed."
 | 
			
		||||
      _on_issue_err "$_post_hook"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    _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
 | 
			
		||||
    echo "$BEGIN_CERT" >"$CERT_PATH"
 | 
			
		||||
 | 
			
		||||
    #if ! _get "$Le_LinkCert" | _base64 "multiline"  >> "$CERT_PATH" ; then
 | 
			
		||||
@ -3798,6 +4012,12 @@ issue() {
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    echo "$END_CERT" >>"$CERT_PATH"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug "Le_LinkCert" "$Le_LinkCert"
 | 
			
		||||
  _savedomainconf "Le_LinkCert" "$Le_LinkCert"
 | 
			
		||||
 | 
			
		||||
  if [ "$Le_LinkCert" ]; then
 | 
			
		||||
    _info "$(__green "Cert success.")"
 | 
			
		||||
    cat "$CERT_PATH"
 | 
			
		||||
 | 
			
		||||
@ -3824,7 +4044,12 @@ issue() {
 | 
			
		||||
 | 
			
		||||
  _cleardomainconf "Le_Vlist"
 | 
			
		||||
 | 
			
		||||
  if [ "$ACME_VERSION" = "2" ]; then
 | 
			
		||||
    _debug "v2 chain."
 | 
			
		||||
  else
 | 
			
		||||
    Le_LinkIssuer=$(grep -i '^Link' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2 | cut -d ';' -f 1 | tr -d '<>')
 | 
			
		||||
 | 
			
		||||
    if [ "$Le_LinkIssuer" ]; then
 | 
			
		||||
      if ! _contains "$Le_LinkIssuer" ":"; then
 | 
			
		||||
        _info "$(__red "Relative issuer link found.")"
 | 
			
		||||
        Le_LinkIssuer="$_ACME_SERVER_HOST$Le_LinkIssuer"
 | 
			
		||||
@ -3832,23 +4057,24 @@ issue() {
 | 
			
		||||
      _debug Le_LinkIssuer "$Le_LinkIssuer"
 | 
			
		||||
      _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer"
 | 
			
		||||
 | 
			
		||||
  if [ "$Le_LinkIssuer" ]; then
 | 
			
		||||
      _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 [ "$ACME_VERSION" = "2" ]; then
 | 
			
		||||
          if _get "$Le_LinkIssuer" >"$CA_CERT_PATH"; then
 | 
			
		||||
            break
 | 
			
		||||
          fi
 | 
			
		||||
        else
 | 
			
		||||
          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
 | 
			
		||||
        fi
 | 
			
		||||
        _link_issuer_retry=$(_math $_link_issuer_retry + 1)
 | 
			
		||||
        _sleep "$_link_issuer_retry"
 | 
			
		||||
      done
 | 
			
		||||
@ -3858,6 +4084,9 @@ issue() {
 | 
			
		||||
    else
 | 
			
		||||
      _debug "No Le_LinkIssuer header found."
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
  [ -f "$CA_CERT_PATH" ] && _info "The intermediate CA cert is in $(__green " $CA_CERT_PATH ")"
 | 
			
		||||
  [ -f "$CERT_FULLCHAIN_PATH" ] && _info "And the full chain certs is there: $(__green " $CERT_FULLCHAIN_PATH ")"
 | 
			
		||||
 | 
			
		||||
  Le_CertCreateTime=$(_time)
 | 
			
		||||
  _savedomainconf "Le_CertCreateTime" "$Le_CertCreateTime"
 | 
			
		||||
@ -3957,7 +4186,7 @@ renew() {
 | 
			
		||||
      _savedomainconf Le_API "$Le_API"
 | 
			
		||||
    fi
 | 
			
		||||
    if [ "$_OLD_STAGE_CA_HOST" = "$Le_API" ]; then
 | 
			
		||||
      export Le_API="$STAGE_CA"
 | 
			
		||||
      export Le_API="$DEFAULT_STAGING_CA"
 | 
			
		||||
      _savedomainconf Le_API "$Le_API"
 | 
			
		||||
    fi
 | 
			
		||||
    export ACME_DIRECTORY="$Le_API"
 | 
			
		||||
@ -4045,8 +4274,6 @@ signcsr() {
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _initpath
 | 
			
		||||
 | 
			
		||||
  _csrsubj=$(_readSubjectFromCSR "$_csrfile")
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "Can not read subject from csr: $_csrfile"
 | 
			
		||||
@ -4083,6 +4310,9 @@ signcsr() {
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "$ACME_VERSION" ] && _contains "$_csrsubj,$_csrdomainlist" "*."; then
 | 
			
		||||
    export ACME_VERSION=2
 | 
			
		||||
  fi
 | 
			
		||||
  _initpath "$_csrsubj" "$_csrkeylength"
 | 
			
		||||
  mkdir -p "$DOMAIN_PATH"
 | 
			
		||||
 | 
			
		||||
@ -4448,7 +4678,11 @@ revoke() {
 | 
			
		||||
 | 
			
		||||
  _initAPI
 | 
			
		||||
 | 
			
		||||
  if [ "$ACME_VERSION" = "2" ]; then
 | 
			
		||||
    data="{\"certificate\": \"$cert\"}"
 | 
			
		||||
  else
 | 
			
		||||
    data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}"
 | 
			
		||||
  fi
 | 
			
		||||
  uri="${ACME_REVOKE_CERT}"
 | 
			
		||||
 | 
			
		||||
  if [ -f "$CERT_KEY_PATH" ]; then
 | 
			
		||||
@ -4519,6 +4753,34 @@ _deactivate() {
 | 
			
		||||
  _d_type="$2"
 | 
			
		||||
  _initpath
 | 
			
		||||
 | 
			
		||||
  if [ "$ACME_VERSION" = "2" ]; then
 | 
			
		||||
    _identifiers="{\"type\":\"dns\",\"value\":\"$_d_domain\"}"
 | 
			
		||||
    if ! _send_signed_request "$ACME_NEW_ORDER" "{\"identifiers\": [$_identifiers]}"; then
 | 
			
		||||
      _err "Can not get domain new order."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    _authorizations_seg="$(echo "$response" | tr -d '\r\n' | _egrep_o '"authorizations" *: *\[[^\]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')"
 | 
			
		||||
    _debug2 _authorizations_seg "$_authorizations_seg"
 | 
			
		||||
    if [ -z "$_authorizations_seg" ]; then
 | 
			
		||||
      _err "_authorizations_seg not found."
 | 
			
		||||
      _clearup
 | 
			
		||||
      _on_issue_err "$_post_hook"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    authzUri="$_authorizations_seg"
 | 
			
		||||
    _debug2 "authzUri" "$authzUri"
 | 
			
		||||
    if ! response="$(_get "$authzUri")"; then
 | 
			
		||||
      _err "get to authz error."
 | 
			
		||||
      _clearup
 | 
			
		||||
      _on_issue_err "$_post_hook"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    response="$(echo "$response" | _normalizeJson)"
 | 
			
		||||
    _debug2 response "$response"
 | 
			
		||||
    _URL_NAME="url"
 | 
			
		||||
  else
 | 
			
		||||
    if ! __get_domain_new_authz "$_d_domain"; then
 | 
			
		||||
      _err "Can not get domain new authz token."
 | 
			
		||||
      return 1
 | 
			
		||||
@ -4526,20 +4788,21 @@ _deactivate() {
 | 
			
		||||
 | 
			
		||||
    authzUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")"
 | 
			
		||||
    _debug "authzUri" "$authzUri"
 | 
			
		||||
 | 
			
		||||
    if [ "$code" ] && [ ! "$code" = '201' ]; then
 | 
			
		||||
      _err "new-authz error: $response"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    _URL_NAME="uri"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  entries="$(echo "$response" | _egrep_o '{ *"type":"[^"]*", *"status": *"valid", *"uri"[^}]*')"
 | 
			
		||||
  entries="$(echo "$response" | _egrep_o "{ *\"type\":\"[^\"]*\", *\"status\": *\"valid\", *\"$_URL_NAME\"[^}]*")"
 | 
			
		||||
  if [ -z "$entries" ]; then
 | 
			
		||||
    _info "No valid entries found."
 | 
			
		||||
    if [ -z "$thumbprint" ]; then
 | 
			
		||||
      thumbprint="$(__calc_account_thumbprint)"
 | 
			
		||||
    fi
 | 
			
		||||
    _debug "Trigger validation."
 | 
			
		||||
    vtype="$VTYPE_HTTP"
 | 
			
		||||
    vtype="$VTYPE_DNS"
 | 
			
		||||
    entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')"
 | 
			
		||||
    _debug entry "$entry"
 | 
			
		||||
    if [ -z "$entry" ]; then
 | 
			
		||||
@ -4549,7 +4812,7 @@ _deactivate() {
 | 
			
		||||
    token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')"
 | 
			
		||||
    _debug token "$token"
 | 
			
		||||
 | 
			
		||||
    uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d : -f 2,3 | tr -d '"')"
 | 
			
		||||
    uri="$(printf "%s\n" "$entry" | _egrep_o "\"$_URL_NAME\":\"[^\"]*" | cut -d : -f 2,3 | tr -d '"')"
 | 
			
		||||
    _debug uri "$uri"
 | 
			
		||||
 | 
			
		||||
    keyauthorization="$token.$thumbprint"
 | 
			
		||||
@ -4575,7 +4838,7 @@ _deactivate() {
 | 
			
		||||
    _debug _vtype "$_vtype"
 | 
			
		||||
    _info "Found $_vtype"
 | 
			
		||||
 | 
			
		||||
    uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d : -f 2,3 | tr -d '"')"
 | 
			
		||||
    uri="$(printf "%s\n" "$entry" | _egrep_o "\"$_URL_NAME\":\"[^\"]*" | cut -d : -f 2,3 | tr -d '"')"
 | 
			
		||||
    _debug uri "$uri"
 | 
			
		||||
 | 
			
		||||
    if [ "$_d_type" ] && [ "$_d_type" != "$_vtype" ]; then
 | 
			
		||||
@ -4585,7 +4848,13 @@ _deactivate() {
 | 
			
		||||
 | 
			
		||||
    _info "Deactivate: $_vtype"
 | 
			
		||||
 | 
			
		||||
    if _send_signed_request "$authzUri" "{\"resource\": \"authz\", \"status\":\"deactivated\"}" && _contains "$response" '"deactivated"'; then
 | 
			
		||||
    if [ "$ACME_VERSION" = "2" ]; then
 | 
			
		||||
      _djson="{\"status\":\"deactivated\"}"
 | 
			
		||||
    else
 | 
			
		||||
      _djson="{\"resource\": \"authz\", \"status\":\"deactivated\"}"
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if _send_signed_request "$authzUri" "$_djson" && _contains "$response" '"deactivated"'; then
 | 
			
		||||
      _info "Deactivate: $_vtype success."
 | 
			
		||||
    else
 | 
			
		||||
      _err "Can not deactivate $_vtype."
 | 
			
		||||
@ -4894,8 +5163,14 @@ install() {
 | 
			
		||||
  if [ -z "$NO_DETECT_SH" ]; then
 | 
			
		||||
    #Modify shebang
 | 
			
		||||
    if _exists bash; then
 | 
			
		||||
      _bash_path="$(bash -c "command -v bash 2>/dev/null")"
 | 
			
		||||
      if [ -z "$_bash_path" ]; then
 | 
			
		||||
        _bash_path="$(bash -c 'echo $SHELL')"
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
    if [ "$_bash_path" ]; then
 | 
			
		||||
      _info "Good, bash is found, so change the shebang to use bash as preferred."
 | 
			
		||||
      _shebang='#!'"$(env bash -c "command -v bash")"
 | 
			
		||||
      _shebang='#!'"$_bash_path"
 | 
			
		||||
      _setShebang "$LE_WORKING_DIR/$PROJECT_ENTRY" "$_shebang"
 | 
			
		||||
      for subf in $_SUB_FOLDERS; do
 | 
			
		||||
        if [ -d "$LE_WORKING_DIR/$subf" ]; then
 | 
			
		||||
@ -5000,7 +5275,7 @@ Commands:
 | 
			
		||||
  --renew, -r              Renew a cert.
 | 
			
		||||
  --renew-all              Renew all the certs.
 | 
			
		||||
  --revoke                 Revoke a cert.
 | 
			
		||||
  --remove                 Remove the cert from $PROJECT
 | 
			
		||||
  --remove                 Remove the cert from list of certs known to $PROJECT_NAME.
 | 
			
		||||
  --list                   List all the certs.
 | 
			
		||||
  --showcsr                Show the content of a csr.
 | 
			
		||||
  --install-cronjob        Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job.
 | 
			
		||||
@ -5307,6 +5582,10 @@ _process() {
 | 
			
		||||
            return 1
 | 
			
		||||
          fi
 | 
			
		||||
 | 
			
		||||
          if _startswith "$_dvalue" "*."; then
 | 
			
		||||
            _debug "Wildcard domain"
 | 
			
		||||
            export ACME_VERSION=2
 | 
			
		||||
          fi
 | 
			
		||||
          if [ -z "$_domain" ]; then
 | 
			
		||||
            _domain="$_dvalue"
 | 
			
		||||
          else
 | 
			
		||||
@ -5510,7 +5789,7 @@ _process() {
 | 
			
		||||
        HTTPS_INSECURE="1"
 | 
			
		||||
        ;;
 | 
			
		||||
      --ca-bundle)
 | 
			
		||||
        _ca_bundle="$(_readlink -f "$2")"
 | 
			
		||||
        _ca_bundle="$(_readlink "$2")"
 | 
			
		||||
        CA_BUNDLE="$_ca_bundle"
 | 
			
		||||
        shift
 | 
			
		||||
        ;;
 | 
			
		||||
 | 
			
		||||
@ -679,6 +679,60 @@ acme.sh --issue --dns dns_dnsever -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
The DNSEVER_ID and DNSEVER_PW will be saved in ~/.acme.sh/account.conf and will be reused when needed.
 | 
			
		||||
 | 
			
		||||
## 36. Use autoDNS (InternetX)
 | 
			
		||||
 | 
			
		||||
[InternetX](https://www.internetx.com/) offers an [xml api](https://help.internetx.com/display/API/AutoDNS+XML-API)  with your standard login credentials, set them like so:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
export AUTODNS_USER="yourusername"
 | 
			
		||||
export AUTODNS_PASSWORD="password"
 | 
			
		||||
export AUTODNS_CONTEXT="context"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Then you can issue your certificates with:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
acme.sh --issue --dns dns_autodns -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `AUTODNS_USER`, `AUTODNS_PASSWORD` and `AUTODNS_CONTEXT` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
 | 
			
		||||
 | 
			
		||||
## 37. Use Azure DNS
 | 
			
		||||
 | 
			
		||||
You have to create a service principal first. See:[How to use Azure DNS](../../../wiki/How-to-use-Azure-DNS)
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
export AZUREDNS_SUBSCRIPTIONID="12345678-9abc-def0-1234-567890abcdef"
 | 
			
		||||
export AZUREDNS_TENANTID="11111111-2222-3333-4444-555555555555"
 | 
			
		||||
export AZUREDNS_APPID="3b5033b5-7a66-43a5-b3b9-a36b9e7c25ed"
 | 
			
		||||
export AZUREDNS_CLIENTSECRET="1b0224ef-34d4-5af9-110f-77f527d561bd"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Then you can issue your certificates with:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
acme.sh --issue --dns dns_azure -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
`AZUREDNS_SUBSCRIPTIONID`, `AZUREDNS_TENANTID`,`AZUREDNS_APPID` and `AZUREDNS_CLIENTSECRET` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
 | 
			
		||||
 | 
			
		||||
## 38. Use selectel.com(selectel.ru) domain API to automatically issue cert
 | 
			
		||||
 | 
			
		||||
First you need to login to your account to get your API key from: https://my.selectel.ru/profile/apikeys.
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
export SL_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Ok, let's issue a cert now:
 | 
			
		||||
```
 | 
			
		||||
acme.sh --issue --dns dns_selectel -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `SL_Key` 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.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										264
									
								
								dnsapi/dns_autodns.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										264
									
								
								dnsapi/dns_autodns.sh
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,264 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# -*- mode: sh; tab-width: 2; indent-tabs-mode: s; coding: utf-8 -*-
 | 
			
		||||
 | 
			
		||||
# This is the InternetX autoDNS xml api wrapper for acme.sh
 | 
			
		||||
# Author: auerswald@gmail.com
 | 
			
		||||
# Created: 2018-01-14
 | 
			
		||||
#
 | 
			
		||||
#     export AUTODNS_USER="username"
 | 
			
		||||
#     export AUTODNS_PASSWORD="password"
 | 
			
		||||
#     export AUTODNS_CONTEXT="context"
 | 
			
		||||
#
 | 
			
		||||
# Usage:
 | 
			
		||||
#     acme.sh --issue --dns dns_autodns -d example.com
 | 
			
		||||
 | 
			
		||||
AUTODNS_API="https://gateway.autodns.com"
 | 
			
		||||
 | 
			
		||||
# Arguments:
 | 
			
		||||
#   txtdomain
 | 
			
		||||
#   txt
 | 
			
		||||
dns_autodns_add() {
 | 
			
		||||
  fulldomain="$1"
 | 
			
		||||
  txtvalue="$2"
 | 
			
		||||
 | 
			
		||||
  AUTODNS_USER="${AUTODNS_USER:-$(_readaccountconf_mutable AUTODNS_USER)}"
 | 
			
		||||
  AUTODNS_PASSWORD="${AUTODNS_PASSWORD:-$(_readaccountconf_mutable AUTODNS_PASSWORD)}"
 | 
			
		||||
  AUTODNS_CONTEXT="${AUTODNS_CONTEXT:-$(_readaccountconf_mutable AUTODNS_CONTEXT)}"
 | 
			
		||||
 | 
			
		||||
  if [ -z "$AUTODNS_USER" ] || [ -z "$AUTODNS_CONTEXT" ] || [ -z "$AUTODNS_PASSWORD" ]; then
 | 
			
		||||
    _err "You don't specify autodns user, password and context."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _saveaccountconf_mutable AUTODNS_USER "$AUTODNS_USER"
 | 
			
		||||
  _saveaccountconf_mutable AUTODNS_PASSWORD "$AUTODNS_PASSWORD"
 | 
			
		||||
  _saveaccountconf_mutable AUTODNS_CONTEXT "$AUTODNS_CONTEXT"
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
 | 
			
		||||
  if ! _get_autodns_zone "$fulldomain"; then
 | 
			
		||||
    _err "invalid domain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug _sub_domain "$_sub_domain"
 | 
			
		||||
  _debug _zone "$_zone"
 | 
			
		||||
  _debug _system_ns "$_system_ns"
 | 
			
		||||
 | 
			
		||||
  _info "Adding TXT record"
 | 
			
		||||
 | 
			
		||||
  autodns_response="$(_autodns_zone_update "$_zone" "$_sub_domain" "$txtvalue" "$_system_ns")"
 | 
			
		||||
 | 
			
		||||
  if [ "$?" -eq "0" ]; then
 | 
			
		||||
    _info "Added, OK"
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Arguments:
 | 
			
		||||
#   txtdomain
 | 
			
		||||
#   txt
 | 
			
		||||
dns_autodns_rm() {
 | 
			
		||||
  fulldomain="$1"
 | 
			
		||||
  txtvalue="$2"
 | 
			
		||||
 | 
			
		||||
  AUTODNS_USER="${AUTODNS_USER:-$(_readaccountconf_mutable AUTODNS_USER)}"
 | 
			
		||||
  AUTODNS_PASSWORD="${AUTODNS_PASSWORD:-$(_readaccountconf_mutable AUTODNS_PASSWORD)}"
 | 
			
		||||
  AUTODNS_CONTEXT="${AUTODNS_CONTEXT:-$(_readaccountconf_mutable AUTODNS_CONTEXT)}"
 | 
			
		||||
 | 
			
		||||
  if [ -z "$AUTODNS_USER" ] || [ -z "$AUTODNS_CONTEXT" ] || [ -z "$AUTODNS_PASSWORD" ]; then
 | 
			
		||||
    _err "You don't specify autodns user, password and context."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
 | 
			
		||||
  if ! _get_autodns_zone "$fulldomain"; then
 | 
			
		||||
    _err "zone not found"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug _sub_domain "$_sub_domain"
 | 
			
		||||
  _debug _zone "$_zone"
 | 
			
		||||
  _debug _system_ns "$_system_ns"
 | 
			
		||||
 | 
			
		||||
  _info "Delete TXT record"
 | 
			
		||||
 | 
			
		||||
  autodns_response="$(_autodns_zone_cleanup "$_zone" "$_sub_domain" "$txtvalue" "$_system_ns")"
 | 
			
		||||
 | 
			
		||||
  if [ "$?" -eq "0" ]; then
 | 
			
		||||
    _info "Deleted, OK"
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
 | 
			
		||||
# Arguments:
 | 
			
		||||
#   fulldomain
 | 
			
		||||
# Returns:
 | 
			
		||||
#   _sub_domain=_acme-challenge.www
 | 
			
		||||
#   _zone=domain.com
 | 
			
		||||
#   _system_ns
 | 
			
		||||
_get_autodns_zone() {
 | 
			
		||||
  domain="$1"
 | 
			
		||||
 | 
			
		||||
  i=2
 | 
			
		||||
  p=1
 | 
			
		||||
 | 
			
		||||
  while true; do
 | 
			
		||||
    h=$(printf "%s" "$domain" | cut -d . -f $i-100)
 | 
			
		||||
    _debug h "$h"
 | 
			
		||||
 | 
			
		||||
    if [ -z "$h" ]; then
 | 
			
		||||
      # not valid
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    autodns_response="$(_autodns_zone_inquire "$h")"
 | 
			
		||||
 | 
			
		||||
    if [ "$?" -ne "0" ]; then
 | 
			
		||||
      _err "invalid domain"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if _contains "$autodns_response" "<summary>1</summary>" >/dev/null; then
 | 
			
		||||
      _zone="$(echo "$autodns_response" | _egrep_o '<name>[^<]*</name>' | cut -d '>' -f 2 | cut -d '<' -f 1)"
 | 
			
		||||
      _system_ns="$(echo "$autodns_response" | _egrep_o '<system_ns>[^<]*</system_ns>' | cut -d '>' -f 2 | cut -d '<' -f 1)"
 | 
			
		||||
      _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    p=$i
 | 
			
		||||
    i=$(_math "$i" + 1)
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_build_request_auth_xml() {
 | 
			
		||||
  printf "<auth>
 | 
			
		||||
    <user>%s</user>
 | 
			
		||||
    <password>%s</password>
 | 
			
		||||
    <context>%s</context>
 | 
			
		||||
  </auth>" "$AUTODNS_USER" "$AUTODNS_PASSWORD" "$AUTODNS_CONTEXT"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Arguments:
 | 
			
		||||
#   zone
 | 
			
		||||
_build_zone_inquire_xml() {
 | 
			
		||||
  printf "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
 | 
			
		||||
  <request>
 | 
			
		||||
    %s
 | 
			
		||||
    <task>
 | 
			
		||||
      <code>0205</code>
 | 
			
		||||
      <view>
 | 
			
		||||
        <children>1</children>
 | 
			
		||||
        <limit>1</limit>
 | 
			
		||||
      </view>
 | 
			
		||||
      <where>
 | 
			
		||||
        <key>name</key>
 | 
			
		||||
        <operator>eq</operator>
 | 
			
		||||
        <value>%s</value>
 | 
			
		||||
      </where>
 | 
			
		||||
    </task>
 | 
			
		||||
  </request>" "$(_build_request_auth_xml)" "$1"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Arguments:
 | 
			
		||||
#   zone
 | 
			
		||||
#   subdomain
 | 
			
		||||
#   txtvalue
 | 
			
		||||
#   system_ns
 | 
			
		||||
_build_zone_update_xml() {
 | 
			
		||||
  printf "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
 | 
			
		||||
  <request>
 | 
			
		||||
    %s
 | 
			
		||||
    <task>
 | 
			
		||||
      <code>0202001</code>
 | 
			
		||||
      <default>
 | 
			
		||||
        <rr_add>
 | 
			
		||||
          <name>%s</name>
 | 
			
		||||
          <ttl>600</ttl>
 | 
			
		||||
          <type>TXT</type>
 | 
			
		||||
          <value>%s</value>
 | 
			
		||||
        </rr_add>
 | 
			
		||||
      </default>
 | 
			
		||||
      <zone>
 | 
			
		||||
        <name>%s</name>
 | 
			
		||||
        <system_ns>%s</system_ns>
 | 
			
		||||
      </zone>
 | 
			
		||||
    </task>
 | 
			
		||||
  </request>" "$(_build_request_auth_xml)" "$2" "$3" "$1" "$4"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Arguments:
 | 
			
		||||
#   zone
 | 
			
		||||
_autodns_zone_inquire() {
 | 
			
		||||
  request_data="$(_build_zone_inquire_xml "$1")"
 | 
			
		||||
  autodns_response="$(_autodns_api_call "$request_data")"
 | 
			
		||||
  ret="$?"
 | 
			
		||||
 | 
			
		||||
  printf "%s" "$autodns_response"
 | 
			
		||||
  return "$ret"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Arguments:
 | 
			
		||||
#   zone
 | 
			
		||||
#   subdomain
 | 
			
		||||
#   txtvalue
 | 
			
		||||
#   system_ns
 | 
			
		||||
_autodns_zone_update() {
 | 
			
		||||
  request_data="$(_build_zone_update_xml "$1" "$2" "$3" "$4")"
 | 
			
		||||
  autodns_response="$(_autodns_api_call "$request_data")"
 | 
			
		||||
  ret="$?"
 | 
			
		||||
 | 
			
		||||
  printf "%s" "$autodns_response"
 | 
			
		||||
  return "$ret"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Arguments:
 | 
			
		||||
#   zone
 | 
			
		||||
#   subdomain
 | 
			
		||||
#   txtvalue
 | 
			
		||||
#   system_ns
 | 
			
		||||
_autodns_zone_cleanup() {
 | 
			
		||||
  request_data="$(_build_zone_update_xml "$1" "$2" "$3" "$4")"
 | 
			
		||||
  # replace 'rr_add>' with 'rr_rem>' in request_data
 | 
			
		||||
  request_data="$(printf -- "%s" "$request_data" | sed 's/rr_add>/rr_rem>/g')"
 | 
			
		||||
  autodns_response="$(_autodns_api_call "$request_data")"
 | 
			
		||||
  ret="$?"
 | 
			
		||||
 | 
			
		||||
  printf "%s" "$autodns_response"
 | 
			
		||||
  return "$ret"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Arguments:
 | 
			
		||||
#   request_data
 | 
			
		||||
_autodns_api_call() {
 | 
			
		||||
  request_data="$1"
 | 
			
		||||
 | 
			
		||||
  _debug request_data "$request_data"
 | 
			
		||||
 | 
			
		||||
  autodns_response="$(_post "$request_data" "$AUTODNS_API")"
 | 
			
		||||
  ret="$?"
 | 
			
		||||
 | 
			
		||||
  _debug autodns_response "$autodns_response"
 | 
			
		||||
 | 
			
		||||
  if [ "$ret" -ne "0" ]; then
 | 
			
		||||
    _err "error"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if _contains "$autodns_response" "<type>success</type>" >/dev/null; then
 | 
			
		||||
    _info "success"
 | 
			
		||||
    printf "%s" "$autodns_response"
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
@ -19,18 +19,19 @@ dns_aws_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  AWS_ACCESS_KEY_ID="${AWS_ACCESS_KEY_ID:-$(_readaccountconf_mutable AWS_ACCESS_KEY_ID)}"
 | 
			
		||||
  AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY:-$(_readaccountconf_mutable AWS_SECRET_ACCESS_KEY)}"
 | 
			
		||||
  if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then
 | 
			
		||||
    AWS_ACCESS_KEY_ID=""
 | 
			
		||||
    AWS_SECRET_ACCESS_KEY=""
 | 
			
		||||
    _err "You don't specify aws route53 api key id and and api key secret yet."
 | 
			
		||||
    _err "Please create you key and try again. see $(__green $AWS_WIKI)"
 | 
			
		||||
    _err "Please create your key and try again. see $(__green $AWS_WIKI)"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "$AWS_SESSION_TOKEN" ]; then
 | 
			
		||||
    _saveaccountconf AWS_ACCESS_KEY_ID "$AWS_ACCESS_KEY_ID"
 | 
			
		||||
    _saveaccountconf AWS_SECRET_ACCESS_KEY "$AWS_SECRET_ACCESS_KEY"
 | 
			
		||||
  fi
 | 
			
		||||
  #save for future use
 | 
			
		||||
  _saveaccountconf_mutable AWS_ACCESS_KEY_ID "$AWS_ACCESS_KEY_ID"
 | 
			
		||||
  _saveaccountconf_mutable AWS_SECRET_ACCESS_KEY "$AWS_SECRET_ACCESS_KEY"
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
@ -56,6 +57,8 @@ dns_aws_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  AWS_ACCESS_KEY_ID="${AWS_ACCESS_KEY_ID:-$(_readaccountconf_mutable AWS_ACCESS_KEY_ID)}"
 | 
			
		||||
  AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY:-$(_readaccountconf_mutable AWS_SECRET_ACCESS_KEY)}"
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "invalid domain"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										249
									
								
								dnsapi/dns_azure.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										249
									
								
								dnsapi/dns_azure.sh
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,249 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
# Usage: add  _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
# Used to add txt record
 | 
			
		||||
#
 | 
			
		||||
# Ref: https://docs.microsoft.com/en-us/rest/api/dns/recordsets/createorupdate
 | 
			
		||||
#
 | 
			
		||||
dns_azure_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  AZUREDNS_SUBSCRIPTIONID="${AZUREDNS_SUBSCRIPTIONID:-$(_readaccountconf_mutable AZUREDNS_SUBSCRIPTIONID)}"
 | 
			
		||||
  AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}"
 | 
			
		||||
  AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}"
 | 
			
		||||
  AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}"
 | 
			
		||||
 | 
			
		||||
  if [ -z "$AZUREDNS_SUBSCRIPTIONID" ]; then
 | 
			
		||||
    AZUREDNS_SUBSCRIPTIONID=""
 | 
			
		||||
    AZUREDNS_TENANTID=""
 | 
			
		||||
    AZUREDNS_APPID=""
 | 
			
		||||
    AZUREDNS_CLIENTSECRET=""
 | 
			
		||||
    _err "You didn't specify the Azure Subscription ID "
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "$AZUREDNS_TENANTID" ]; then
 | 
			
		||||
    AZUREDNS_SUBSCRIPTIONID=""
 | 
			
		||||
    AZUREDNS_TENANTID=""
 | 
			
		||||
    AZUREDNS_APPID=""
 | 
			
		||||
    AZUREDNS_CLIENTSECRET=""
 | 
			
		||||
    _err "You didn't specify the Azure Tenant ID "
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "$AZUREDNS_APPID" ]; then
 | 
			
		||||
    AZUREDNS_SUBSCRIPTIONID=""
 | 
			
		||||
    AZUREDNS_TENANTID=""
 | 
			
		||||
    AZUREDNS_APPID=""
 | 
			
		||||
    AZUREDNS_CLIENTSECRET=""
 | 
			
		||||
    _err "You didn't specify the Azure App ID"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "$AZUREDNS_CLIENTSECRET" ]; then
 | 
			
		||||
    AZUREDNS_SUBSCRIPTIONID=""
 | 
			
		||||
    AZUREDNS_TENANTID=""
 | 
			
		||||
    AZUREDNS_APPID=""
 | 
			
		||||
    AZUREDNS_CLIENTSECRET=""
 | 
			
		||||
    _err "You didn't specify the Azure Client Secret"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  #save account details to account conf file.
 | 
			
		||||
  _saveaccountconf_mutable AZUREDNS_SUBSCRIPTIONID "$AZUREDNS_SUBSCRIPTIONID"
 | 
			
		||||
  _saveaccountconf_mutable AZUREDNS_TENANTID "$AZUREDNS_TENANTID"
 | 
			
		||||
  _saveaccountconf_mutable AZUREDNS_APPID "$AZUREDNS_APPID"
 | 
			
		||||
  _saveaccountconf_mutable AZUREDNS_CLIENTSECRET "$AZUREDNS_CLIENTSECRET"
 | 
			
		||||
 | 
			
		||||
  accesstoken=$(_azure_getaccess_token "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
 | 
			
		||||
 | 
			
		||||
  if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then
 | 
			
		||||
    _err "invalid domain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug _domain_id "$_domain_id"
 | 
			
		||||
  _debug _sub_domain "$_sub_domain"
 | 
			
		||||
  _debug _domain "$_domain"
 | 
			
		||||
 | 
			
		||||
  acmeRecordURI="https://management.azure.com$(printf '%s' "$_domain_id" | sed 's/\\//g')/TXT/$_sub_domain?api-version=2017-09-01"
 | 
			
		||||
  _debug "$acmeRecordURI"
 | 
			
		||||
  body="{\"properties\": {\"TTL\": 3600, \"TXTRecords\": [{\"value\": [\"$txtvalue\"]}]}}"
 | 
			
		||||
  _azure_rest PUT "$acmeRecordURI" "$body" "$accesstoken"
 | 
			
		||||
  if [ "$_code" = "200" ] || [ "$_code" = '201' ]; then
 | 
			
		||||
    _info "validation record added"
 | 
			
		||||
  else
 | 
			
		||||
    _err "error adding validation record ($_code)"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Usage: fulldomain txtvalue
 | 
			
		||||
# Used to remove the txt record after validation
 | 
			
		||||
#
 | 
			
		||||
# Ref: https://docs.microsoft.com/en-us/rest/api/dns/recordsets/delete
 | 
			
		||||
#
 | 
			
		||||
dns_azure_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  AZUREDNS_SUBSCRIPTIONID="${AZUREDNS_SUBSCRIPTIONID:-$(_readaccountconf_mutable AZUREDNS_SUBSCRIPTIONID)}"
 | 
			
		||||
  AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}"
 | 
			
		||||
  AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}"
 | 
			
		||||
  AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}"
 | 
			
		||||
 | 
			
		||||
  if [ -z "$AZUREDNS_SUBSCRIPTIONID" ]; then
 | 
			
		||||
    AZUREDNS_SUBSCRIPTIONID=""
 | 
			
		||||
    AZUREDNS_TENANTID=""
 | 
			
		||||
    AZUREDNS_APPID=""
 | 
			
		||||
    AZUREDNS_CLIENTSECRET=""
 | 
			
		||||
    _err "You didn't specify the Azure Subscription ID "
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "$AZUREDNS_TENANTID" ]; then
 | 
			
		||||
    AZUREDNS_SUBSCRIPTIONID=""
 | 
			
		||||
    AZUREDNS_TENANTID=""
 | 
			
		||||
    AZUREDNS_APPID=""
 | 
			
		||||
    AZUREDNS_CLIENTSECRET=""
 | 
			
		||||
    _err "You didn't specify the Azure Tenant ID "
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "$AZUREDNS_APPID" ]; then
 | 
			
		||||
    AZUREDNS_SUBSCRIPTIONID=""
 | 
			
		||||
    AZUREDNS_TENANTID=""
 | 
			
		||||
    AZUREDNS_APPID=""
 | 
			
		||||
    AZUREDNS_CLIENTSECRET=""
 | 
			
		||||
    _err "You didn't specify the Azure App ID"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "$AZUREDNS_CLIENTSECRET" ]; then
 | 
			
		||||
    AZUREDNS_SUBSCRIPTIONID=""
 | 
			
		||||
    AZUREDNS_TENANTID=""
 | 
			
		||||
    AZUREDNS_APPID=""
 | 
			
		||||
    AZUREDNS_CLIENTSECRET=""
 | 
			
		||||
    _err "You didn't specify the Azure Client Secret"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  accesstoken=$(_azure_getaccess_token "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
 | 
			
		||||
 | 
			
		||||
  if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then
 | 
			
		||||
    _err "invalid domain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug _domain_id "$_domain_id"
 | 
			
		||||
  _debug _sub_domain "$_sub_domain"
 | 
			
		||||
  _debug _domain "$_domain"
 | 
			
		||||
 | 
			
		||||
  acmeRecordURI="https://management.azure.com$(printf '%s' "$_domain_id" | sed 's/\\//g')/TXT/$_sub_domain?api-version=2017-09-01"
 | 
			
		||||
  _debug "$acmeRecordURI"
 | 
			
		||||
  body="{\"properties\": {\"TTL\": 3600, \"TXTRecords\": [{\"value\": [\"$txtvalue\"]}]}}"
 | 
			
		||||
  _azure_rest DELETE "$acmeRecordURI" "" "$accesstoken"
 | 
			
		||||
  if [ "$_code" = "200" ] || [ "$_code" = '204' ]; then
 | 
			
		||||
    _info "validation record removed"
 | 
			
		||||
  else
 | 
			
		||||
    _err "error removing validation record ($_code)"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
###################  Private functions below ##################################
 | 
			
		||||
 | 
			
		||||
_azure_rest() {
 | 
			
		||||
  m=$1
 | 
			
		||||
  ep="$2"
 | 
			
		||||
  data="$3"
 | 
			
		||||
  accesstoken="$4"
 | 
			
		||||
 | 
			
		||||
  export _H1="authorization: Bearer $accesstoken"
 | 
			
		||||
  export _H2="accept: application/json"
 | 
			
		||||
  export _H3="Content-Type: application/json"
 | 
			
		||||
 | 
			
		||||
  _debug "$ep"
 | 
			
		||||
  if [ "$m" != "GET" ]; then
 | 
			
		||||
    _debug data "$data"
 | 
			
		||||
    response="$(_post "$data" "$ep" "" "$m")"
 | 
			
		||||
  else
 | 
			
		||||
    response="$(_get "$ep")"
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
 | 
			
		||||
  _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")"
 | 
			
		||||
  _debug2 "http response code $_code"
 | 
			
		||||
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "error $ep"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
## Ref: https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-service-to-service#request-an-access-token
 | 
			
		||||
_azure_getaccess_token() {
 | 
			
		||||
  TENANTID=$1
 | 
			
		||||
  clientID=$2
 | 
			
		||||
  clientSecret=$3
 | 
			
		||||
 | 
			
		||||
  export _H1="accept: application/json"
 | 
			
		||||
  export _H2="Content-Type: application/x-www-form-urlencoded"
 | 
			
		||||
 | 
			
		||||
  body="resource=$(printf "%s" 'https://management.core.windows.net/' | _url_encode)&client_id=$(printf "%s" "$clientID" | _url_encode)&client_secret=$(printf "%s" "$clientSecret" | _url_encode)&grant_type=client_credentials"
 | 
			
		||||
  _debug data "$body"
 | 
			
		||||
  response="$(_post "$body" "https://login.windows.net/$TENANTID/oauth2/token" "" "POST")"
 | 
			
		||||
  accesstoken=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
 | 
			
		||||
  _debug2 "response $response"
 | 
			
		||||
 | 
			
		||||
  if [ -z "$accesstoken" ]; then
 | 
			
		||||
    _err "no acccess token received"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "error $response"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  printf "%s" "$accesstoken"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_get_root() {
 | 
			
		||||
  domain=$1
 | 
			
		||||
  subscriptionId=$2
 | 
			
		||||
  accesstoken=$3
 | 
			
		||||
  i=2
 | 
			
		||||
  p=1
 | 
			
		||||
 | 
			
		||||
  ## Ref: https://docs.microsoft.com/en-us/rest/api/dns/zones/list
 | 
			
		||||
  ## returns up to 100 zones in one response therefore handling more results is not not implemented
 | 
			
		||||
  ## (ZoneListResult with  continuation token for the next page of results)
 | 
			
		||||
  ## Per https://docs.microsoft.com/en-us/azure/azure-subscription-service-limits#dns-limits you are limited to 100 Zone/subscriptions anyways
 | 
			
		||||
  ##
 | 
			
		||||
  _azure_rest GET "https://management.azure.com/subscriptions/$subscriptionId/providers/Microsoft.Network/dnszones?api-version=2017-09-01" "" "$accesstoken"
 | 
			
		||||
 | 
			
		||||
  # Find matching domain name is Json response
 | 
			
		||||
  while true; do
 | 
			
		||||
    h=$(printf "%s" "$domain" | cut -d . -f $i-100)
 | 
			
		||||
    _debug2 "Checking domain: $h"
 | 
			
		||||
    if [ -z "$h" ]; then
 | 
			
		||||
      #not valid
 | 
			
		||||
      _err "Invalid domain"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
 | 
			
		||||
      _domain_id=$(echo "$response" | _egrep_o "\{\"id\":\"[^\"]*$h\"" | head -n 1 | cut -d : -f 2 | tr -d \")
 | 
			
		||||
      if [ "$_domain_id" ]; then
 | 
			
		||||
        _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
 | 
			
		||||
        _domain=$h
 | 
			
		||||
        return 0
 | 
			
		||||
      fi
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    p=$i
 | 
			
		||||
    i=$(_math "$i" + 1)
 | 
			
		||||
  done
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
@ -51,9 +51,11 @@ dns_cf_add() {
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2)
 | 
			
		||||
  _debug count "$count"
 | 
			
		||||
  if [ "$count" = "0" ]; then
 | 
			
		||||
  # For wildcard cert, the main root domain and the wildcard domain have the same txt subdomain name, so
 | 
			
		||||
  # we can not use updating anymore.
 | 
			
		||||
  #  count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2)
 | 
			
		||||
  #  _debug count "$count"
 | 
			
		||||
  #  if [ "$count" = "0" ]; then
 | 
			
		||||
  _info "Adding record"
 | 
			
		||||
  if _cf_rest POST "zones/$_domain_id/dns_records" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then
 | 
			
		||||
    if printf -- "%s" "$response" | grep "$fulldomain" >/dev/null; then
 | 
			
		||||
@ -65,19 +67,20 @@ dns_cf_add() {
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
  _err "Add txt record error."
 | 
			
		||||
  else
 | 
			
		||||
    _info "Updating record"
 | 
			
		||||
    record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1)
 | 
			
		||||
    _debug "record_id" "$record_id"
 | 
			
		||||
 | 
			
		||||
    _cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}"
 | 
			
		||||
    if [ "$?" = "0" ]; then
 | 
			
		||||
      _info "Updated, OK"
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
    _err "Update error"
 | 
			
		||||
  return 1
 | 
			
		||||
  fi
 | 
			
		||||
  #  else
 | 
			
		||||
  #    _info "Updating record"
 | 
			
		||||
  #    record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1)
 | 
			
		||||
  #    _debug "record_id" "$record_id"
 | 
			
		||||
  #
 | 
			
		||||
  #    _cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}"
 | 
			
		||||
  #    if [ "$?" = "0" ]; then
 | 
			
		||||
  #      _info "Updated, OK"
 | 
			
		||||
  #      return 0
 | 
			
		||||
  #    fi
 | 
			
		||||
  #    _err "Update error"
 | 
			
		||||
  #    return 1
 | 
			
		||||
  #  fi
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -35,53 +35,9 @@ dns_inwx_add() {
 | 
			
		||||
  fi
 | 
			
		||||
  _debug _sub_domain "$_sub_domain"
 | 
			
		||||
  _debug _domain "$_domain"
 | 
			
		||||
  _debug "Getting txt records"
 | 
			
		||||
 | 
			
		||||
  xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
  <methodCall>
 | 
			
		||||
  <methodName>nameserver.info</methodName>
 | 
			
		||||
  <params>
 | 
			
		||||
   <param>
 | 
			
		||||
    <value>
 | 
			
		||||
     <struct>
 | 
			
		||||
      <member>
 | 
			
		||||
       <name>domain</name>
 | 
			
		||||
       <value>
 | 
			
		||||
        <string>%s</string>
 | 
			
		||||
       </value>
 | 
			
		||||
      </member>
 | 
			
		||||
      <member>
 | 
			
		||||
       <name>type</name>
 | 
			
		||||
       <value>
 | 
			
		||||
        <string>TXT</string>
 | 
			
		||||
       </value>
 | 
			
		||||
      </member>
 | 
			
		||||
      <member>
 | 
			
		||||
       <name>name</name>
 | 
			
		||||
       <value>
 | 
			
		||||
        <string>%s</string>
 | 
			
		||||
       </value>
 | 
			
		||||
      </member>
 | 
			
		||||
     </struct>
 | 
			
		||||
    </value>
 | 
			
		||||
   </param>
 | 
			
		||||
  </params>
 | 
			
		||||
  </methodCall>' "$_domain" "$_sub_domain")
 | 
			
		||||
  response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
 | 
			
		||||
 | 
			
		||||
  if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then
 | 
			
		||||
    _err "Error could net get txt records"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! printf "%s" "$response" | grep "count" >/dev/null; then
 | 
			
		||||
  _info "Adding record"
 | 
			
		||||
  _inwx_add_record "$_domain" "$_sub_domain" "$txtvalue"
 | 
			
		||||
  else
 | 
			
		||||
    _record_id=$(printf '%s' "$response" | _egrep_o '.*(<member><name>record){1}(.*)([0-9]+){1}' | _egrep_o '<name>id<\/name><value><int>[0-9]+' | _egrep_o '[0-9]+')
 | 
			
		||||
    _info "Updating record"
 | 
			
		||||
    _inwx_update_record "$_record_id" "$txtvalue"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -147,7 +103,7 @@ dns_inwx_rm() {
 | 
			
		||||
  </methodCall>' "$_domain" "$_sub_domain")
 | 
			
		||||
  response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
 | 
			
		||||
 | 
			
		||||
  if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then
 | 
			
		||||
  if ! _contains "$response" "Command completed successfully"; then
 | 
			
		||||
    _err "Error could not get txt records"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
@ -78,13 +78,7 @@ _ovh_get_api() {
 | 
			
		||||
  esac
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: add  _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_ovh_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
_initAuth() {
 | 
			
		||||
  if [ -z "$OVH_AK" ] || [ -z "$OVH_AS" ]; then
 | 
			
		||||
    OVH_AK=""
 | 
			
		||||
    OVH_AS=""
 | 
			
		||||
@ -119,14 +113,26 @@ dns_ovh_add() {
 | 
			
		||||
 | 
			
		||||
  _info "Checking authentication"
 | 
			
		||||
 | 
			
		||||
  response="$(_ovh_rest GET "domain")"
 | 
			
		||||
  if _contains "$response" "INVALID_CREDENTIAL"; then
 | 
			
		||||
  if ! _ovh_rest GET "domain" || _contains "$response" "INVALID_CREDENTIAL"; then
 | 
			
		||||
    _err "The consumer key is invalid: $OVH_CK"
 | 
			
		||||
    _err "Please retry to create a new one."
 | 
			
		||||
    _clearaccountconf OVH_CK
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _info "Consumer key is ok."
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: add  _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_ovh_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  if ! _initAuth; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
@ -137,49 +143,58 @@ dns_ovh_add() {
 | 
			
		||||
  _debug _sub_domain "$_sub_domain"
 | 
			
		||||
  _debug _domain "$_domain"
 | 
			
		||||
 | 
			
		||||
  _debug "Getting txt records"
 | 
			
		||||
  _ovh_rest GET "domain/zone/$_domain/record?fieldType=TXT&subDomain=$_sub_domain"
 | 
			
		||||
 | 
			
		||||
  if _contains "$response" '\[\]' || _contains "$response" "This service does not exist"; then
 | 
			
		||||
  _info "Adding record"
 | 
			
		||||
  if _ovh_rest POST "domain/zone/$_domain/record" "{\"fieldType\":\"TXT\",\"subDomain\":\"$_sub_domain\",\"target\":\"$txtvalue\",\"ttl\":60}"; then
 | 
			
		||||
    if _contains "$response" "$txtvalue"; then
 | 
			
		||||
      _ovh_rest POST "domain/zone/$_domain/refresh"
 | 
			
		||||
      _debug "Refresh:$response"
 | 
			
		||||
        _info "Added, sleeping 10 seconds"
 | 
			
		||||
        sleep 10
 | 
			
		||||
      _info "Added, sleep 10 seconds."
 | 
			
		||||
      _sleep 10
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
  _err "Add txt record error."
 | 
			
		||||
  else
 | 
			
		||||
    _info "Updating record"
 | 
			
		||||
    record_id=$(printf "%s" "$response" | tr -d "[]" | cut -d , -f 1)
 | 
			
		||||
    if [ -z "$record_id" ]; then
 | 
			
		||||
      _err "Can not get record id."
 | 
			
		||||
  return 1
 | 
			
		||||
    fi
 | 
			
		||||
    _debug "record_id" "$record_id"
 | 
			
		||||
 | 
			
		||||
    if _ovh_rest PUT "domain/zone/$_domain/record/$record_id" "{\"target\":\"$txtvalue\",\"subDomain\":\"$_sub_domain\",\"ttl\":60}"; then
 | 
			
		||||
      if _contains "$response" "null"; then
 | 
			
		||||
        _ovh_rest POST "domain/zone/$_domain/refresh"
 | 
			
		||||
        _debug "Refresh:$response"
 | 
			
		||||
        _info "Updated, sleeping 10 seconds"
 | 
			
		||||
        sleep 10
 | 
			
		||||
        return 0
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
    _err "Update error"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#fulldomain
 | 
			
		||||
dns_ovh_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  if ! _initAuth; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "invalid domain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug _sub_domain "$_sub_domain"
 | 
			
		||||
  _debug _domain "$_domain"
 | 
			
		||||
  _debug "Getting txt records"
 | 
			
		||||
  if ! _ovh_rest GET "domain/zone/$_domain/record?fieldType=TXT&subDomain=$_sub_domain"; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  for rid in $(echo "$response" | tr '][,' '   '); do
 | 
			
		||||
    _debug rid "$rid"
 | 
			
		||||
    if ! _ovh_rest GET "domain/zone/$_domain/record/$rid"; then
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    if _contains "$response" "\"target\":\"$txtvalue\""; then
 | 
			
		||||
      _debug "Found txt id:$rid"
 | 
			
		||||
      if ! _ovh_rest DELETE "domain/zone/$_domain/record/$rid"; then
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
@ -191,7 +206,7 @@ _ovh_authentication() {
 | 
			
		||||
  _H3=""
 | 
			
		||||
  _H4=""
 | 
			
		||||
 | 
			
		||||
  _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'"}'
 | 
			
		||||
  _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/*"},{"method": "DELETE","path": "/domain/zone/*/record/*"}],"redirection":"'$ovh_success'"}'
 | 
			
		||||
 | 
			
		||||
  response="$(_post "$_ovhdata" "$OVH_API/auth/credential")"
 | 
			
		||||
  _debug3 response "$response"
 | 
			
		||||
@ -279,15 +294,15 @@ _ovh_rest() {
 | 
			
		||||
  export _H3="X-Ovh-Timestamp: $_ovh_t"
 | 
			
		||||
  export _H4="X-Ovh-Consumer: $OVH_CK"
 | 
			
		||||
  export _H5="Content-Type: application/json;charset=utf-8"
 | 
			
		||||
  if [ "$data" ] || [ "$m" = "POST" ] || [ "$m" = "PUT" ]; then
 | 
			
		||||
  if [ "$data" ] || [ "$m" = "POST" ] || [ "$m" = "PUT" ] || [ "$m" = "DELETE" ]; then
 | 
			
		||||
    _debug data "$data"
 | 
			
		||||
    response="$(_post "$data" "$_ovh_url" "" "$m")"
 | 
			
		||||
  else
 | 
			
		||||
    response="$(_get "$_ovh_url")"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "error $ep"
 | 
			
		||||
  if [ "$?" != "0" ] || _contains "$response" "INVALID_CREDENTIAL"; then
 | 
			
		||||
    _err "error $response"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										161
									
								
								dnsapi/dns_selectel.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								dnsapi/dns_selectel.sh
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,161 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
#SL_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
SL_Api="https://api.selectel.ru/domains/v1"
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: add  _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_selectel_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  SL_Key="${SL_Key:-$(_readaccountconf_mutable SL_Key)}"
 | 
			
		||||
 | 
			
		||||
  if [ -z "$SL_Key" ]; then
 | 
			
		||||
    SL_Key=""
 | 
			
		||||
    _err "You don't specify selectel.ru api key yet."
 | 
			
		||||
    _err "Please create you key and try again."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  #save the api key to the account conf file.
 | 
			
		||||
  _saveaccountconf_mutable SL_Key "$SL_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"
 | 
			
		||||
 | 
			
		||||
  _info "Adding record"
 | 
			
		||||
  if _sl_rest POST "/$_domain_id/records/" "{\"type\": \"TXT\", \"ttl\": 60, \"name\": \"$fulldomain\", \"content\": \"$txtvalue\"}"; then
 | 
			
		||||
    if _contains "$response" "$txtvalue" || _contains "$response" "record_already_exists"; then
 | 
			
		||||
      _info "Added, OK"
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
  _err "Add txt record error."
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#fulldomain txtvalue
 | 
			
		||||
dns_selectel_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  SL_Key="${SL_Key:-$(_readaccountconf_mutable SL_Key)}"
 | 
			
		||||
 | 
			
		||||
  if [ -z "$SL_Key" ]; then
 | 
			
		||||
    SL_Key=""
 | 
			
		||||
    _err "You don't specify slectel api key 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"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug _domain_id "$_domain_id"
 | 
			
		||||
  _debug _sub_domain "$_sub_domain"
 | 
			
		||||
  _debug _domain "$_domain"
 | 
			
		||||
 | 
			
		||||
  _debug "Getting txt records"
 | 
			
		||||
  _sl_rest GET "/${_domain_id}/records/"
 | 
			
		||||
 | 
			
		||||
  if ! _contains "$response" "$txtvalue"; then
 | 
			
		||||
    _err "Txt record not found"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _record_seg="$(echo "$response" | _egrep_o "\"content\" *: *\"$txtvalue\"[^}]*}")"
 | 
			
		||||
  _debug2 "_record_seg" "$_record_seg"
 | 
			
		||||
  if [ -z "$_record_seg" ]; then
 | 
			
		||||
    _err "can not find _record_seg"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _record_id="$(echo "$_record_seg" | tr "," "\n" | tr "}" "\n" | tr -d " " | grep "\"id\"" | cut -d : -f 2)"
 | 
			
		||||
  _debug2 "_record_id" "$_record_id"
 | 
			
		||||
  if [ -z "$_record_id" ]; then
 | 
			
		||||
    _err "can not find _record_id"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! _sl_rest DELETE "/$_domain_id/records/$_record_id"; then
 | 
			
		||||
    _err "Delete record error."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
#_acme-challenge.www.domain.com
 | 
			
		||||
#returns
 | 
			
		||||
# _sub_domain=_acme-challenge.www
 | 
			
		||||
# _domain=domain.com
 | 
			
		||||
# _domain_id=sdjkglgdfewsdfg
 | 
			
		||||
_get_root() {
 | 
			
		||||
  domain=$1
 | 
			
		||||
 | 
			
		||||
  if ! _sl_rest GET "/"; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  i=2
 | 
			
		||||
  p=1
 | 
			
		||||
  while true; do
 | 
			
		||||
    h=$(printf "%s" "$domain" | cut -d . -f $i-100)
 | 
			
		||||
    _debug h "$h"
 | 
			
		||||
    if [ -z "$h" ]; then
 | 
			
		||||
      #not valid
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if _contains "$response" "\"name\": \"$h\","; then
 | 
			
		||||
      _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
 | 
			
		||||
      _domain=$h
 | 
			
		||||
      _debug "Getting domain id for $h"
 | 
			
		||||
      if ! _sl_rest GET "/$h"; then
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
      _domain_id="$(echo "$response" | tr "," "\n" | tr "}" "\n" | tr -d " " | grep "\"id\":" | cut -d : -f 2)"
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
    p=$i
 | 
			
		||||
    i=$(_math "$i" + 1)
 | 
			
		||||
  done
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_sl_rest() {
 | 
			
		||||
  m=$1
 | 
			
		||||
  ep="$2"
 | 
			
		||||
  data="$3"
 | 
			
		||||
  _debug "$ep"
 | 
			
		||||
 | 
			
		||||
  export _H1="X-Token: $SL_Key"
 | 
			
		||||
  export _H2="Content-Type: application/json"
 | 
			
		||||
 | 
			
		||||
  if [ "$m" != "GET" ]; then
 | 
			
		||||
    _debug data "$data"
 | 
			
		||||
    response="$(_post "$data" "$SL_Api/$ep" "" "$m")"
 | 
			
		||||
  else
 | 
			
		||||
    response="$(_get "$SL_Api/$ep")"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "error $ep"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
@ -18,7 +18,6 @@ dns_yandex_add() {
 | 
			
		||||
 | 
			
		||||
  curDomain=$(_PDD_get_domain "$fulldomain")
 | 
			
		||||
  _debug "Found suitable domain in pdd: $curDomain"
 | 
			
		||||
  curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")"
 | 
			
		||||
  curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}"
 | 
			
		||||
  curUri="https://pddimp.yandex.ru/api2/admin/dns/add"
 | 
			
		||||
  curResult="$(_post "${curData}" "${curUri}")"
 | 
			
		||||
@ -36,7 +35,6 @@ dns_yandex_rm() {
 | 
			
		||||
 | 
			
		||||
  curDomain=$(_PDD_get_domain "$fulldomain")
 | 
			
		||||
  _debug "Found suitable domain in pdd: $curDomain"
 | 
			
		||||
  curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")"
 | 
			
		||||
 | 
			
		||||
  curUri="https://pddimp.yandex.ru/api2/admin/dns/del"
 | 
			
		||||
  curData="domain=${curDomain}&record_id=${record_id}"
 | 
			
		||||
@ -61,7 +59,7 @@ _PDD_get_domain() {
 | 
			
		||||
      __last=1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    __all_domains="$__all_domains $(echo "$res1" | sed -e "s@,@\n@g" | grep '"name"' | cut -d: -f2 | sed -e 's@"@@g')"
 | 
			
		||||
    __all_domains="$__all_domains $(echo "$res1" | tr "," "\n" | grep '"name"' | cut -d: -f2 | sed -e 's@"@@g')"
 | 
			
		||||
 | 
			
		||||
    __page=$(_math $__page + 1)
 | 
			
		||||
  done
 | 
			
		||||
@ -72,6 +70,8 @@ _PDD_get_domain() {
 | 
			
		||||
    _debug "finding zone for domain $__t"
 | 
			
		||||
    for d in $__all_domains; do
 | 
			
		||||
      if [ "$d" = "$__t" ]; then
 | 
			
		||||
        p=$(_math $k - 1)
 | 
			
		||||
        curSubdomain="$(echo "$fulldomain" | cut -d . -f "1-$p")"
 | 
			
		||||
        echo "$__t"
 | 
			
		||||
        return
 | 
			
		||||
      fi
 | 
			
		||||
@ -98,7 +98,6 @@ pdd_get_record_id() {
 | 
			
		||||
 | 
			
		||||
  curDomain=$(_PDD_get_domain "$fulldomain")
 | 
			
		||||
  _debug "Found suitable domain in pdd: $curDomain"
 | 
			
		||||
  curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")"
 | 
			
		||||
 | 
			
		||||
  curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}"
 | 
			
		||||
  curResult="$(_get "${curUri}" | _normalizeJson)"
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user