mirror of
https://github.com/acmesh-official/acme.sh.git
synced 2025-12-26 13:42:09 +08:00
Compare commits
154 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26e3263aec | ||
|
|
08b4e1a744 | ||
|
|
d68f0999a4 | ||
|
|
2c9ed4c565 | ||
|
|
be4f87c760 | ||
|
|
b963dadc14 | ||
|
|
26e7fd8b80 | ||
|
|
b9a972bccd | ||
|
|
bb7b9280d3 | ||
|
|
395fbbfd14 | ||
|
|
896dfe3def | ||
|
|
6c4f33910c | ||
|
|
0a301cdd21 | ||
|
|
c2b1e38d7f | ||
|
|
fcc0aef7f4 | ||
|
|
eaa3de2dce | ||
|
|
f3dc5dd12f | ||
|
|
d2f0178fab | ||
|
|
326c386b2e | ||
|
|
6e68c4e2d6 | ||
|
|
a79e96802f | ||
|
|
65b22b493c | ||
|
|
b73f5a4e94 | ||
|
|
3b74ac841e | ||
|
|
253bf776b5 | ||
|
|
eef4acd07d | ||
|
|
b6f00ea241 | ||
|
|
0bd4a4f98f | ||
|
|
0b52645bb6 | ||
|
|
8e845d9f21 | ||
|
|
d29aa43ba4 | ||
|
|
450efea191 | ||
|
|
241cfc4342 | ||
|
|
7c67e3d7e2 | ||
|
|
674790a511 | ||
|
|
4e3c82e329 | ||
|
|
df711b0ea2 | ||
|
|
1019fd9a9d | ||
|
|
8a420dd853 | ||
|
|
f8bcfeb2ab | ||
|
|
34e5beda6a | ||
|
|
6185244754 | ||
|
|
60d9509e39 | ||
|
|
ded4469efe | ||
|
|
1f95d8eedf | ||
|
|
aa66dfff57 | ||
|
|
25263ce40f | ||
|
|
e85deb54e1 | ||
|
|
4750fd159e | ||
|
|
7eea9533e8 | ||
|
|
ec675b9ad2 | ||
|
|
486e77f474 | ||
|
|
048059ba1f | ||
|
|
ed3dda7da9 | ||
|
|
fa93d68b08 | ||
|
|
4e20d89d9c | ||
|
|
b420ec6cb9 | ||
|
|
375f6101e9 | ||
|
|
2844d73dc7 | ||
|
|
6c1176f853 | ||
|
|
df037db0bb | ||
|
|
949cc7d21b | ||
|
|
9244529007 | ||
|
|
319d49ddbe | ||
|
|
96fcfdb6c6 | ||
|
|
d61ef6b49a | ||
|
|
804a6c8d47 | ||
|
|
c487cd6af2 | ||
|
|
6a2592a9d9 | ||
|
|
0f48b15695 | ||
|
|
4320b8a5a5 | ||
|
|
a20707cd73 | ||
|
|
5da1d3b73b | ||
|
|
be15e63d41 | ||
|
|
9bc5f686eb | ||
|
|
5bed21dace | ||
|
|
a97e651582 | ||
|
|
dff641a665 | ||
|
|
47a25cc3e8 | ||
|
|
5e3a5f627a | ||
|
|
9201e0a5b9 | ||
|
|
4c80ed3208 | ||
|
|
f34579e921 | ||
|
|
cc1d3b20b6 | ||
|
|
8051b6e8b6 | ||
|
|
4c38fec3b5 | ||
|
|
c4cdcf44c5 | ||
|
|
347dab0c14 | ||
|
|
a3d3ea2b4b | ||
|
|
5332387125 | ||
|
|
5b21cbe0de | ||
|
|
2f4111a2e2 | ||
|
|
326ac485b3 | ||
|
|
f9b419d1e4 | ||
|
|
f4e81953ce | ||
|
|
2b09253961 | ||
|
|
1994c6828e | ||
|
|
f5c381d5b4 | ||
|
|
7e2af8364f | ||
|
|
0a2ab2aed2 | ||
|
|
2310a9bbc0 | ||
|
|
5b3e3d9cf4 | ||
|
|
c97c79ab2f | ||
|
|
1231b71245 | ||
|
|
824ffa24f4 | ||
|
|
148f869bec | ||
|
|
c140fe9bae | ||
|
|
4b02ee5b46 | ||
|
|
de3bac53bf | ||
|
|
3f1a76d9e4 | ||
|
|
0138e167e9 | ||
|
|
bcd2ee6204 | ||
|
|
4c1d521711 | ||
|
|
90c70fa5bf | ||
|
|
8e15c48092 | ||
|
|
9cf65e31cd | ||
|
|
a6e5876d96 | ||
|
|
937e723036 | ||
|
|
12d876a005 | ||
|
|
4e2426a2b4 | ||
|
|
020f9cd2a6 | ||
|
|
d7eebe9df0 | ||
|
|
cebc5bf9fc | ||
|
|
dbe68684a0 | ||
|
|
27a05ff271 | ||
|
|
1489ddc49a | ||
|
|
9be2c1beb9 | ||
|
|
8bcc19d91e | ||
|
|
3c07f57aad | ||
|
|
3262a916e0 | ||
|
|
7883cc5891 | ||
|
|
ded7a5438c | ||
|
|
cd98951001 | ||
|
|
8470c60e06 | ||
|
|
394b1002b3 | ||
|
|
9a61d6293d | ||
|
|
192ad27f8f | ||
|
|
eb0fc67461 | ||
|
|
adbe5e9048 | ||
|
|
fcdf41ba29 | ||
|
|
6d7f6750e9 | ||
|
|
695482ded7 | ||
|
|
afb67d375f | ||
|
|
66e38ae69e | ||
|
|
e137792efd | ||
|
|
b7b934913e | ||
|
|
cd8fcbf9c6 | ||
|
|
d0300d4443 | ||
|
|
5c78e0a462 | ||
|
|
7044236824 | ||
|
|
1e5e03cc46 | ||
|
|
d3c4cd8270 | ||
|
|
17361df66b | ||
|
|
7d0452c7e3 |
19
Dockerfile
19
Dockerfile
@@ -4,17 +4,17 @@ RUN apk update -f \
|
||||
&& apk --no-cache add -f \
|
||||
openssl \
|
||||
curl \
|
||||
netcat-openbsd
|
||||
netcat-openbsd \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
|
||||
ENV LE_CONFIG_HOME /acme.sh
|
||||
|
||||
ENV AUTO_UPGRADE 1
|
||||
|
||||
#Install
|
||||
RUN mkdir -p /install_acme.sh/
|
||||
ADD ./ /install_acme.sh/
|
||||
RUN cd /install_acme.sh && ([ -f /install_acme.sh/acme.sh ] && /install_acme.sh/acme.sh --install || curl https://get.acme.sh | sh)
|
||||
RUN rm -rf /install_acme.sh/
|
||||
RUN cd /install_acme.sh && ([ -f /install_acme.sh/acme.sh ] && /install_acme.sh/acme.sh --install || curl https://get.acme.sh | sh) && rm -rf /install_acme.sh/
|
||||
|
||||
|
||||
RUN ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh
|
||||
|
||||
@@ -48,5 +48,14 @@ RUN for verb in help \
|
||||
printf -- "%b" "#!/usr/bin/env sh\n/root/.acme.sh/acme.sh --${verb} --config-home /acme.sh \"\$@\"" >/usr/local/bin/--${verb} && chmod +x /usr/local/bin/--${verb} \
|
||||
; done
|
||||
|
||||
ENTRYPOINT ["/root/.acme.sh/acme.sh", "--config-home", "/acme.sh"]
|
||||
RUN printf "%b" '#!'"/usr/bin/env sh\n \
|
||||
if [ \"\$1\" = \"daemon\" ]; then \n \
|
||||
crond -f\n \
|
||||
else \n \
|
||||
/root/.acme.sh/acme.sh --config-home /acme.sh \"\$@\"\n \
|
||||
fi" >/entry.sh && chmod +x /entry.sh
|
||||
|
||||
VOLUME /acme.sh
|
||||
|
||||
ENTRYPOINT ["/entry.sh"]
|
||||
CMD ["--help"]
|
||||
|
||||
45
README.md
45
README.md
@@ -1,4 +1,6 @@
|
||||
# An ACME Shell script: acme.sh [](https://travis-ci.org/Neilpang/acme.sh)
|
||||
|
||||
[](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.
|
||||
- Simple, powerful and very easy to use. You only need 3 minutes to learn it.
|
||||
@@ -8,8 +10,9 @@
|
||||
- Just one script to issue, renew and install your certificates automatically.
|
||||
- DOES NOT require `root/sudoer` access.
|
||||
- Docker friendly
|
||||
- IPv6 support
|
||||
|
||||
It's probably the `easiest&smallest&smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt.
|
||||
It's probably the `easiest & smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt.
|
||||
|
||||
Wiki: https://github.com/Neilpang/acme.sh/wiki
|
||||
|
||||
@@ -31,6 +34,7 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa)
|
||||
- [Centminmod](http://centminmod.com/letsencrypt-acmetool-https.html)
|
||||
- [splynx](https://forum.splynx.com/t/free-ssl-cert-for-splynx-lets-encrypt/297)
|
||||
- [archlinux](https://aur.archlinux.org/packages/acme.sh-git/)
|
||||
- [opnsense.org](https://github.com/opnsense/plugins/tree/master/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient)
|
||||
- [more...](https://github.com/Neilpang/acme.sh/wiki/Blogs-and-tutorials)
|
||||
|
||||
# Tested OS
|
||||
@@ -58,7 +62,7 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa)
|
||||
|19|[](https://github.com/Neilpang/letest#here-are-the-latest-status)|Gentoo Linux
|
||||
|20|[](https://travis-ci.org/Neilpang/acme.sh)|Mac OSX
|
||||
|
||||
For all build statuses, check our [daily build project](https://github.com/Neilpang/acmetest):
|
||||
For all build statuses, check our [weekly build project](https://github.com/Neilpang/acmetest):
|
||||
|
||||
https://github.com/Neilpang/acmetest
|
||||
|
||||
@@ -135,13 +139,25 @@ root@v1:~# acme.sh -h
|
||||
acme.sh --issue -d example.com -w /home/wwwroot/example.com
|
||||
```
|
||||
|
||||
or:
|
||||
|
||||
```bash
|
||||
acme.sh --issue -d example.com -w /home/username/public_html
|
||||
```
|
||||
|
||||
or:
|
||||
|
||||
```bash
|
||||
acme.sh --issue -d example.com -w /var/www/html
|
||||
```
|
||||
|
||||
**Example 2:** Multiple domains in the same cert.
|
||||
|
||||
```bash
|
||||
acme.sh --issue -d example.com -d www.example.com -d cp.example.com -w /home/wwwroot/example.com
|
||||
```
|
||||
|
||||
The parameter `/home/wwwroot/example.com` is the web root folder. You **MUST** have `write access` to this folder.
|
||||
The parameter `/home/wwwroot/example.com` or `/home/username/public_html` or `/var/www/html` is the web root folder where you host your website files. You **MUST** have `write access` to this folder.
|
||||
|
||||
Second argument **"example.com"** is the main domain you want to issue the cert for.
|
||||
You must have at least one domain there.
|
||||
@@ -183,7 +199,7 @@ The ownership and permission info of existing files are preserved. You may want
|
||||
|
||||
Install/copy the issued 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 restarted automatically by the command: `service apache2 restart` or `service nginx restart`.
|
||||
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`.
|
||||
|
||||
|
||||
# 4. Use Standalone server to issue cert
|
||||
@@ -293,14 +309,12 @@ You don't have to do anything manually!
|
||||
1. DNSPod.cn API
|
||||
1. CloudXNS.com API
|
||||
1. GoDaddy.com API
|
||||
1. OVH, kimsufi, soyoustart and runabove API
|
||||
1. AWS Route 53
|
||||
1. PowerDNS.com API
|
||||
1. lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api
|
||||
(DigitalOcean, DNSimple, DNSMadeEasy, DNSPark, EasyDNS, Namesilo, NS1, PointHQ, Rage4 and Vultr etc.)
|
||||
1. OVH, kimsufi, soyoustart and runabove API
|
||||
1. nsupdate API
|
||||
1. LuaDNS.com API
|
||||
1. DNSMadeEasy.com API
|
||||
1. nsupdate API
|
||||
1. AWS Route 53
|
||||
1. aliyun.com(阿里云) API
|
||||
1. ISPConfig 3.1 API
|
||||
1. Alwaysdata.com API
|
||||
@@ -313,7 +327,20 @@ You don't have to do anything manually!
|
||||
1. DigitalOcean API (native)
|
||||
1. ClouDNS.net API
|
||||
1. Infoblox NIOS API (https://www.infoblox.com/)
|
||||
1. VSCALE (https://vscale.io/)
|
||||
1. Dynu API (https://www.dynu.com)
|
||||
1. DNSimple API
|
||||
1. NS1.com API
|
||||
|
||||
|
||||
|
||||
And:
|
||||
|
||||
1. lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api
|
||||
(DigitalOcean, DNSimple, DNSMadeEasy, DNSPark, EasyDNS, Namesilo, NS1, PointHQ, Rage4 and Vultr etc.)
|
||||
|
||||
|
||||
|
||||
**More APIs coming soon...**
|
||||
|
||||
If your DNS provider is not on the supported list above, you can write your own DNS API script easily. If you do, please consider submitting a [Pull Request](https://github.com/Neilpang/acme.sh/pulls) and contribute it to the project.
|
||||
|
||||
180
acme.sh
180
acme.sh
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
VER=2.6.8
|
||||
VER=2.7.2
|
||||
|
||||
PROJECT_NAME="acme.sh"
|
||||
|
||||
@@ -104,21 +104,21 @@ if [ -t 1 ]; then
|
||||
fi
|
||||
|
||||
__green() {
|
||||
if [ "$__INTERACTIVE" ]; then
|
||||
if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then
|
||||
printf '\033[1;31;32m'
|
||||
fi
|
||||
printf -- "%b" "$1"
|
||||
if [ "$__INTERACTIVE" ]; then
|
||||
if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then
|
||||
printf '\033[0m'
|
||||
fi
|
||||
}
|
||||
|
||||
__red() {
|
||||
if [ "$__INTERACTIVE" ]; then
|
||||
if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then
|
||||
printf '\033[1;31;40m'
|
||||
fi
|
||||
printf -- "%b" "$1"
|
||||
if [ "$__INTERACTIVE" ]; then
|
||||
if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then
|
||||
printf '\033[0m'
|
||||
fi
|
||||
}
|
||||
@@ -151,6 +151,13 @@ _dlg_versions() {
|
||||
echo "apache doesn't exists."
|
||||
fi
|
||||
|
||||
echo "nginx:"
|
||||
if _exists "nginx"; then
|
||||
nginx -V 2>&1
|
||||
else
|
||||
echo "nginx doesn't exists."
|
||||
fi
|
||||
|
||||
echo "nc:"
|
||||
if _exists "nc"; then
|
||||
nc -h 2>&1
|
||||
@@ -166,7 +173,14 @@ _syslog() {
|
||||
fi
|
||||
_logclass="$1"
|
||||
shift
|
||||
logger -i -t "$PROJECT_NAME" -p "$_logclass" "$(_printargs "$@")" >/dev/null 2>&1
|
||||
if [ -z "$__logger_i" ]; then
|
||||
if _contains "$(logger --help 2>&1)" "-i"; then
|
||||
__logger_i="logger -i"
|
||||
else
|
||||
__logger_i="logger"
|
||||
fi
|
||||
fi
|
||||
$__logger_i -t "$PROJECT_NAME" -p "$_logclass" "$(_printargs "$@")" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
_log() {
|
||||
@@ -347,7 +361,7 @@ _hasfield() {
|
||||
fi
|
||||
done
|
||||
_debug2 "'$_str' does not contain '$_field'"
|
||||
return 1 #not contains
|
||||
return 1 #not contains
|
||||
}
|
||||
|
||||
_getfield() {
|
||||
@@ -436,34 +450,48 @@ if [ "$(printf '\x41')" != 'A' ]; then
|
||||
_URGLY_PRINTF=1
|
||||
fi
|
||||
|
||||
_h2b() {
|
||||
hex=$(cat)
|
||||
i=1
|
||||
j=2
|
||||
_ESCAPE_XARGS=""
|
||||
if [ "$(printf %s '\\x41' | xargs printf)" = 'A' ]; then
|
||||
_ESCAPE_XARGS=1
|
||||
fi
|
||||
|
||||
_debug3 _URGLY_PRINTF "$_URGLY_PRINTF"
|
||||
while true; do
|
||||
if [ -z "$_URGLY_PRINTF" ]; then
|
||||
h="$(printf "%s" "$hex" | cut -c $i-$j)"
|
||||
if [ -z "$h" ]; then
|
||||
break
|
||||
fi
|
||||
printf "\x$h%s"
|
||||
_h2b() {
|
||||
if _exists xxd; then
|
||||
xxd -r -p
|
||||
return
|
||||
fi
|
||||
|
||||
hex=$(cat)
|
||||
ic=""
|
||||
jc=""
|
||||
_debug2 _URGLY_PRINTF "$_URGLY_PRINTF"
|
||||
if [ -z "$_URGLY_PRINTF" ]; then
|
||||
if [ "$_ESCAPE_XARGS" ] && _exists xargs; then
|
||||
_debug2 "xargs"
|
||||
echo "$hex" | _upper_case | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/g' | xargs printf
|
||||
else
|
||||
ic="$(printf "%s" "$hex" | cut -c $i)"
|
||||
jc="$(printf "%s" "$hex" | cut -c $j)"
|
||||
if [ -z "$ic$jc" ]; then
|
||||
break
|
||||
for h in $(echo "$hex" | _upper_case | sed 's/\([0-9A-F]\{2\}\)/ \1/g'); do
|
||||
if [ -z "$h" ]; then
|
||||
break
|
||||
fi
|
||||
printf "\x$h%s"
|
||||
done
|
||||
fi
|
||||
else
|
||||
for c in $(echo "$hex" | _upper_case | sed 's/\([0-9A-F]\)/ \1/g'); do
|
||||
if [ -z "$ic" ]; then
|
||||
ic=$c
|
||||
continue
|
||||
fi
|
||||
jc=$c
|
||||
ic="$(_h_char_2_dec "$ic")"
|
||||
jc="$(_h_char_2_dec "$jc")"
|
||||
printf '\'"$(printf "%o" "$(_math "$ic" \* 16 + $jc)")""%s"
|
||||
fi
|
||||
ic=""
|
||||
jc=""
|
||||
done
|
||||
fi
|
||||
|
||||
i="$(_math "$i" + 2)"
|
||||
j="$(_math "$j" + 2)"
|
||||
|
||||
done
|
||||
}
|
||||
|
||||
_is_solaris() {
|
||||
@@ -722,7 +750,7 @@ _url_encode() {
|
||||
"7e")
|
||||
printf "%s" "~"
|
||||
;;
|
||||
#other hex
|
||||
#other hex
|
||||
*)
|
||||
printf '%%%s' "$_hex_code"
|
||||
;;
|
||||
@@ -1025,7 +1053,7 @@ _createcsr() {
|
||||
else
|
||||
alt="DNS:$domainlist"
|
||||
fi
|
||||
#multi
|
||||
#multi
|
||||
_info "Multi domain" "$alt"
|
||||
printf -- "\nsubjectAltName=$alt" >>"$csrconf"
|
||||
fi
|
||||
@@ -1065,7 +1093,7 @@ _readSubjectFromCSR() {
|
||||
_usage "_readSubjectFromCSR mycsr.csr"
|
||||
return 1
|
||||
fi
|
||||
${ACME_OPENSSL_BIN:-openssl} req -noout -in "$_csrfile" -subject | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n'
|
||||
${ACME_OPENSSL_BIN:-openssl} req -noout -in "$_csrfile" -subject | tr ',' "\n" | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d ' \n'
|
||||
}
|
||||
|
||||
#_csrfile
|
||||
@@ -1093,7 +1121,7 @@ _readSubjectAltNamesFromCSR() {
|
||||
printf "%s" "$_dnsAltnames" | sed "s/DNS://g"
|
||||
}
|
||||
|
||||
#_csrfile
|
||||
#_csrfile
|
||||
_readKeyLengthFromCSR() {
|
||||
_csrfile="$1"
|
||||
if [ -z "$_csrfile" ]; then
|
||||
@@ -1108,7 +1136,7 @@ _readKeyLengthFromCSR() {
|
||||
echo "$_outcsr" | tr "\t" " " | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' '
|
||||
else
|
||||
_debug "RSA CSR"
|
||||
echo "$_outcsr" | tr "\t" " " | _egrep_o "(^ *|RSA )Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1
|
||||
echo "$_outcsr" | tr "\t" " " | (_egrep_o "^ *Public.Key:.*" || _egrep_o "RSA Public.Key:.*") | cut -d '(' -f 2 | cut -d ' ' -f 1
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -1192,7 +1220,7 @@ toPkcs8() {
|
||||
|
||||
}
|
||||
|
||||
#[2048]
|
||||
#[2048]
|
||||
createAccountKey() {
|
||||
_info "Creating account key"
|
||||
if [ -z "$1" ]; then
|
||||
@@ -1237,17 +1265,20 @@ createDomainKey() {
|
||||
fi
|
||||
|
||||
domain=$1
|
||||
length=$2
|
||||
_cdl=$2
|
||||
|
||||
if [ -z "$length" ]; then
|
||||
if [ -z "$_cdl" ]; then
|
||||
_debug "Use DEFAULT_DOMAIN_KEY_LENGTH=$DEFAULT_DOMAIN_KEY_LENGTH"
|
||||
length="$DEFAULT_DOMAIN_KEY_LENGTH"
|
||||
_cdl="$DEFAULT_DOMAIN_KEY_LENGTH"
|
||||
fi
|
||||
|
||||
_initpath "$domain" "$length"
|
||||
_initpath "$domain" "$_cdl"
|
||||
|
||||
if [ ! -f "$CERT_KEY_PATH" ] || ([ "$FORCE" ] && ! [ "$IS_RENEW" ]); then
|
||||
_createkey "$length" "$CERT_KEY_PATH"
|
||||
if _createkey "$_cdl" "$CERT_KEY_PATH"; then
|
||||
_savedomainconf Le_Keylength "$_cdl"
|
||||
_info "The domain key is here: $(__green $CERT_KEY_PATH)"
|
||||
fi
|
||||
else
|
||||
if [ "$IS_RENEW" ]; then
|
||||
_info "Domain key exists, skip"
|
||||
@@ -1702,7 +1733,7 @@ _send_signed_request() {
|
||||
nonce="$_CACHED_NONCE"
|
||||
_debug2 nonce "$nonce"
|
||||
|
||||
protected="$JWK_HEADERPLACE_PART1$nonce$JWK_HEADERPLACE_PART2"
|
||||
protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2"
|
||||
_debug3 protected "$protected"
|
||||
|
||||
protected64="$(printf "%s" "$protected" | _base64 | _url_replace)"
|
||||
@@ -1847,6 +1878,24 @@ _saveaccountconf() {
|
||||
_save_conf "$ACCOUNT_CONF_PATH" "$1" "$2"
|
||||
}
|
||||
|
||||
#key value
|
||||
_saveaccountconf_mutable() {
|
||||
_save_conf "$ACCOUNT_CONF_PATH" "SAVED_$1" "$2"
|
||||
#remove later
|
||||
_clearaccountconf "$1"
|
||||
}
|
||||
|
||||
#key
|
||||
_readaccountconf() {
|
||||
_read_conf "$ACCOUNT_CONF_PATH" "$1"
|
||||
}
|
||||
|
||||
#key
|
||||
_readaccountconf_mutable() {
|
||||
_rac_key="$1"
|
||||
_readaccountconf "SAVED_$_rac_key"
|
||||
}
|
||||
|
||||
#_clearaccountconf key
|
||||
_clearaccountconf() {
|
||||
_clear_conf "$ACCOUNT_CONF_PATH" "$1"
|
||||
@@ -2528,7 +2577,7 @@ _setNginx() {
|
||||
location ~ \"^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)\$\" {
|
||||
default_type text/plain;
|
||||
return 200 \"\$1.$_thumbpt\";
|
||||
}
|
||||
}
|
||||
#NGINX_START
|
||||
" >>"$FOUND_REAL_NGINX_CONF"
|
||||
|
||||
@@ -2537,7 +2586,7 @@ location ~ \"^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)\$\" {
|
||||
_err "write nginx conf error, but don't worry, the file is restored."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug3 "Modified config:$(cat $FOUND_REAL_NGINX_CONF)"
|
||||
_info "nginx conf is done, let's check it again."
|
||||
if ! _exec "nginx -t" >/dev/null; then
|
||||
_exec_err
|
||||
@@ -2599,10 +2648,10 @@ _checkConf() {
|
||||
_isRealNginxConf() {
|
||||
_debug "_isRealNginxConf $1 $2"
|
||||
if [ -f "$2" ]; then
|
||||
for _fln in $(grep -n "^ *server_name.* $1" "$2" | cut -d : -f 1); do
|
||||
for _fln in $(tr "\t" ' ' <"$2" | grep -n "^ *server_name.* $1" | cut -d : -f 1); do
|
||||
_debug _fln "$_fln"
|
||||
if [ "$_fln" ]; then
|
||||
_start=$(cat "$2" | _head_n "$_fln" | grep -n "^ *server *{" | _tail_n 1)
|
||||
_start=$(tr "\t" ' ' <"$2" | _head_n "$_fln" | grep -n "^ *server *{" | _tail_n 1)
|
||||
_debug "_start" "$_start"
|
||||
_start_n=$(echo "$_start" | cut -d : -f 1)
|
||||
_start_nn=$(_math $_start_n + 1)
|
||||
@@ -2611,8 +2660,8 @@ _isRealNginxConf() {
|
||||
|
||||
_left="$(sed -n "${_start_nn},99999p" "$2")"
|
||||
_debug2 _left "$_left"
|
||||
if echo "$_left" | grep -n "^ *server *{" >/dev/null; then
|
||||
_end=$(echo "$_left" | grep -n "^ *server *{" | _head_n 1)
|
||||
if echo "$_left" | tr "\t" ' ' | grep -n "^ *server *{" >/dev/null; then
|
||||
_end=$(echo "$_left" | tr "\t" ' ' | grep -n "^ *server *{" | _head_n 1)
|
||||
_debug "_end" "$_end"
|
||||
_end_n=$(echo "$_end" | cut -d : -f 1)
|
||||
_debug "_end_n" "$_end_n"
|
||||
@@ -2623,12 +2672,14 @@ _isRealNginxConf() {
|
||||
|
||||
_debug "_seg_n" "$_seg_n"
|
||||
|
||||
if [ "$(echo "$_seg_n" | _egrep_o "^ *ssl *on *;")" ]; then
|
||||
if [ "$(echo "$_seg_n" | _egrep_o "^ *ssl *on *;")" ] \
|
||||
|| [ "$(echo "$_seg_n" | _egrep_o "listen .* ssl[ |;]")" ]; then
|
||||
_debug "ssl on, skip"
|
||||
return 1
|
||||
else
|
||||
FOUND_REAL_NGINX_CONF_LN=$_fln
|
||||
_debug3 "found FOUND_REAL_NGINX_CONF_LN" "$FOUND_REAL_NGINX_CONF_LN"
|
||||
return 0
|
||||
fi
|
||||
FOUND_REAL_NGINX_CONF_LN=$_fln
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
fi
|
||||
@@ -2679,7 +2730,7 @@ _clearup() {
|
||||
_clearupdns() {
|
||||
_debug "_clearupdns"
|
||||
if [ "$dnsadded" != 1 ] || [ -z "$vlist" ]; then
|
||||
_debug "Dns not added, skip."
|
||||
_debug "skip dns."
|
||||
return
|
||||
fi
|
||||
|
||||
@@ -3115,7 +3166,7 @@ __trigger_validation() {
|
||||
_send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$_t_key_authz\"}"
|
||||
}
|
||||
|
||||
#webroot, domain domainlist keylength
|
||||
#webroot, domain domainlist keylength
|
||||
issue() {
|
||||
if [ -z "$2" ]; then
|
||||
_usage "Usage: $PROJECT_ENTRY --issue -d a.com -w /path/to/webroot/a.com/ "
|
||||
@@ -3648,7 +3699,7 @@ issue() {
|
||||
|
||||
#if ! _get "$Le_LinkCert" | _base64 "multiline" >> "$CERT_PATH" ; then
|
||||
# _debug "Get cert failed. Let's try last response."
|
||||
# printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >> "$CERT_PATH"
|
||||
# printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >> "$CERT_PATH"
|
||||
#fi
|
||||
|
||||
if ! printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >>"$CERT_PATH"; then
|
||||
@@ -3889,6 +3940,10 @@ signcsr() {
|
||||
return 1
|
||||
fi
|
||||
_debug _csrsubj "$_csrsubj"
|
||||
if _contains "$_csrsubj" ' ' || ! _contains "$_csrsubj" '.'; then
|
||||
_info "It seems that the subject: $_csrsubj is not a valid domain name. Drop it."
|
||||
_csrsubj=""
|
||||
fi
|
||||
|
||||
_csrdomainlist=$(_readSubjectAltNamesFromCSR "$_csrfile")
|
||||
if [ "$?" != "0" ]; then
|
||||
@@ -4596,6 +4651,11 @@ install() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$_c_home" ] && [ "$LE_CONFIG_HOME" != "$LE_WORKING_DIR" ]; then
|
||||
_info "Using config home: $LE_CONFIG_HOME"
|
||||
_c_home="$LE_CONFIG_HOME"
|
||||
fi
|
||||
|
||||
#convert from le
|
||||
if [ -d "$HOME/.le" ]; then
|
||||
for envfile in "le.env" "le.sh.env"; do
|
||||
@@ -4789,7 +4849,7 @@ Commands:
|
||||
--create-domain-key Create an domain private key, professional use.
|
||||
--createCSR, -ccsr Create CSR , professional use.
|
||||
--deactivate Deactivate the domain authz, professional use.
|
||||
|
||||
|
||||
Parameters:
|
||||
--domain, -d domain.tld Specifies a domain, used to issue, renew or revoke etc.
|
||||
--force, -f Used to force to install or force to renew a cert immediately.
|
||||
@@ -4803,20 +4863,20 @@ Parameters:
|
||||
--apache Use apache mode.
|
||||
--dns [dns_cf|dns_dp|dns_cx|/path/to/api/file] Use dns mode or dns api.
|
||||
--dnssleep [$DEFAULT_DNS_SLEEP] The time in seconds to wait for all the txt records to take effect in dns api mode. Default $DEFAULT_DNS_SLEEP seconds.
|
||||
|
||||
|
||||
--keylength, -k [2048] Specifies the domain key length: 2048, 3072, 4096, 8192 or ec-256, ec-384.
|
||||
--accountkeylength, -ak [2048] Specifies the account key length.
|
||||
--log [/path/to/logfile] Specifies the log file. The default is: \"$DEFAULT_LOG_FILE\" if you don't give a file path here.
|
||||
--log-level 1|2 Specifies the log level, default is 1.
|
||||
--syslog [0|3|6|7] Syslog level, 0: disable syslog, 3: error, 6: info, 7: debug.
|
||||
|
||||
|
||||
These parameters are to install the cert to nginx/apache or anyother server after issue/renew a cert:
|
||||
|
||||
|
||||
--cert-file After issue/renew, the cert will be copied to this path.
|
||||
--key-file After issue/renew, the key will be copied to this path.
|
||||
--ca-file After issue/renew, the intermediate cert will be copied to this path.
|
||||
--fullchain-file After issue/renew, the fullchain cert will be copied to this path.
|
||||
|
||||
|
||||
--reloadcmd \"service nginx reload\" After issue/renew, it's used to reload the server.
|
||||
|
||||
--accountconf Specifies a customized account config file.
|
||||
@@ -4836,6 +4896,7 @@ Parameters:
|
||||
--ca-bundle Specifies the path to the CA certificate bundle to verify api server's certificate.
|
||||
--ca-path Specifies directory containing CA certificates in PEM format, used by wget or curl.
|
||||
--nocron Only valid for '--install' command, which means: do not install the default cron job. In this case, the certs will not be renewed automatically.
|
||||
--no-color Do not output color text.
|
||||
--ecc Specifies to use the ECC cert. Valid for '--install-cert', '--renew', '--revoke', '--toPkcs' and '--createCSR'
|
||||
--csr Specifies the input csr.
|
||||
--pre-hook Command to be run before obtaining any certificates.
|
||||
@@ -5283,6 +5344,9 @@ _process() {
|
||||
--nocron)
|
||||
_nocron="1"
|
||||
;;
|
||||
--no-color)
|
||||
export ACME_NO_COLOR=1
|
||||
;;
|
||||
--ecc)
|
||||
_ecc="isEcc"
|
||||
;;
|
||||
|
||||
@@ -21,8 +21,11 @@ acme.sh --deploy -d example.com --deploy-hook cpanel
|
||||
## 2. Deploy ssl cert on kong proxy engine based on api.
|
||||
|
||||
Before you can deploy your cert, you must [issue the cert first](https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert).
|
||||
Currently supports Kong-v0.10.x.
|
||||
|
||||
(TODO)
|
||||
```sh
|
||||
acme.sh --deploy -d ftp.example.com --deploy-hook kong
|
||||
```
|
||||
|
||||
## 3. Deploy the cert to remote server through SSH access.
|
||||
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# This deploy hook will deploy ssl cert on kong proxy engine based on api request_host parameter.
|
||||
# Note that ssl plugin should be available on Kong instance
|
||||
# The hook will match cdomain to request_host, in case of multiple domain it will always take the first
|
||||
# one (acme.sh behaviour).
|
||||
# If ssl config already exist it will update only cert and key not touching other parameter
|
||||
# If ssl config doesn't exist it will only upload cert and key and not set other parameter
|
||||
# Not that we deploy full chain
|
||||
# See https://getkong.org/plugins/dynamic-ssl/ for other options
|
||||
# If certificate already exist it will update only cert and key not touching other parameter
|
||||
# If certificate doesn't exist it will only upload cert and key and not set other parameter
|
||||
# Note that we deploy full chain
|
||||
# Written by Geoffroi Genot <ggenot@voxbone.com>
|
||||
|
||||
######## Public functions #####################
|
||||
@@ -31,14 +25,15 @@ kong_deploy() {
|
||||
_debug _cca "$_cca"
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
#Get uuid linked to the domain
|
||||
uuid=$(_get "$KONG_URL/apis?request_host=$_cdomain" | _normalizeJson | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}')
|
||||
if [ -z "$uuid" ]; then
|
||||
_err "Unable to get Kong uuid for domain $_cdomain"
|
||||
_err "Make sure that KONG_URL is correctly configured"
|
||||
_err "Make sure that a Kong api request_host match the domain"
|
||||
_err "Kong url: $KONG_URL"
|
||||
return 1
|
||||
#Get ssl_uuid linked to the domain
|
||||
ssl_uuid=$(_get "$KONG_URL/certificates/$_cdomain" | _normalizeJson | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}')
|
||||
if [ -z "$ssl_uuid" ]; then
|
||||
_debug "Unable to get Kong ssl_uuid for domain $_cdomain"
|
||||
_debug "Make sure that KONG_URL is correctly configured"
|
||||
_debug "Make sure that a Kong certificate match the sni"
|
||||
_debug "Kong url: $KONG_URL"
|
||||
_info "No existing certificate, creating..."
|
||||
#return 1
|
||||
fi
|
||||
#Save kong url if it's succesful (First run case)
|
||||
_saveaccountconf KONG_URL "$KONG_URL"
|
||||
@@ -48,12 +43,14 @@ kong_deploy() {
|
||||
#Set Header
|
||||
_H1="Content-Type: multipart/form-data; boundary=$delim"
|
||||
#Generate data for request (Multipart/form-data with mixed content)
|
||||
#set name to ssl
|
||||
content="--$delim${nl}Content-Disposition: form-data; name=\"name\"${nl}${nl}ssl"
|
||||
if [ -z "$ssl_uuid" ]; then
|
||||
#set sni to domain
|
||||
content="--$delim${nl}Content-Disposition: form-data; name=\"snis\"${nl}${nl}$_cdomain"
|
||||
fi
|
||||
#add key
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"config.key\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")"
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")"
|
||||
#Add cert
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"config.cert\"; filename=\"$(basename "$_cfullchain")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_cfullchain")"
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"cert\"; filename=\"$(basename "$_cfullchain")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_cfullchain")"
|
||||
#Close multipart
|
||||
content="$content${nl}--$delim--${nl}"
|
||||
#Convert CRLF
|
||||
@@ -61,17 +58,16 @@ kong_deploy() {
|
||||
#DEBUG
|
||||
_debug header "$_H1"
|
||||
_debug content "$content"
|
||||
#Check if ssl plugins is aready enabled (if not => POST else => PATCH)
|
||||
ssl_uuid=$(_get "$KONG_URL/apis/$uuid/plugins" | _egrep_o '"id":"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"[a-zA-Z0-9\-\,\"_\:]*"name":"ssl"' | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}')
|
||||
_debug ssl_uuid "$ssl_uuid"
|
||||
#Check if sslcreated (if not => POST else => PATCH)
|
||||
|
||||
if [ -z "$ssl_uuid" ]; then
|
||||
#Post certificate to Kong
|
||||
response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins" "" "POST")
|
||||
response=$(_post "$content" "$KONG_URL/certificates" "" "POST")
|
||||
else
|
||||
#patch
|
||||
response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins/$ssl_uuid" "" "PATCH")
|
||||
response=$(_post "$content" "$KONG_URL/certificates/$ssl_uuid" "" "PATCH")
|
||||
fi
|
||||
if ! [ "$(echo "$response" | _egrep_o "ssl")" = "ssl" ]; then
|
||||
if ! [ "$(echo "$response" | _egrep_o "created_at")" = "created_at" ]; then
|
||||
_err "An error occurred with cert upload. Check response:"
|
||||
_err "$response"
|
||||
return 1
|
||||
|
||||
@@ -140,7 +140,7 @@ Finally, make the DNS server and update Key available to `acme.sh`
|
||||
|
||||
```
|
||||
export NSUPDATE_SERVER="dns.example.com"
|
||||
export NSUPDATE_KEY="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=="
|
||||
export NSUPDATE_KEY="/path/to/your/nsupdate.key"
|
||||
```
|
||||
|
||||
Ok, let's issue a cert now:
|
||||
@@ -422,22 +422,89 @@ acme.sh --issue --dns dns_cloudns -d example.com -d www.example.com
|
||||
```
|
||||
|
||||
## 22. Use Infoblox API
|
||||
|
||||
|
||||
First you need to create/obtain API credentials on your Infoblox appliance.
|
||||
|
||||
|
||||
```
|
||||
export Infoblox_Creds="username:password"
|
||||
export Infoblox_Server="ip or fqdn of infoblox appliance"
|
||||
```
|
||||
|
||||
|
||||
Ok, let's issue a cert now:
|
||||
```
|
||||
acme.sh --issue --dns dns_infoblox -d example.com -d www.example.com
|
||||
```
|
||||
|
||||
|
||||
Note: This script will automatically create and delete the ephemeral txt record.
|
||||
The `Infoblox_Creds` and `Infoblox_Server` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||
|
||||
|
||||
## 23. Use VSCALE API
|
||||
|
||||
First you need to create/obtain API tokens on your [settings panel](https://vscale.io/panel/settings/tokens/).
|
||||
|
||||
```
|
||||
VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
```
|
||||
|
||||
Ok, let's issue a cert now:
|
||||
```
|
||||
acme.sh --issue --dns dns_vscale -d example.com -d www.example.com
|
||||
```
|
||||
|
||||
## 24. Use Dynu API
|
||||
|
||||
First you need to create/obtain API credentials from your Dynu account. See: https://www.dynu.com/resources/api/documentation
|
||||
|
||||
```
|
||||
export Dynu_ClientId="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
export Dynu_Secret="yyyyyyyyyyyyyyyyyyyyyyyyy"
|
||||
```
|
||||
|
||||
Ok, let's issue a cert now:
|
||||
```
|
||||
acme.sh --issue --dns dns_dynu -d example.com -d www.example.com
|
||||
```
|
||||
|
||||
The `Dynu_ClientId` and `Dynu_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||
|
||||
## 25. Use DNSimple API
|
||||
|
||||
First you need to login to your DNSimple account and generate a new oauth token.
|
||||
|
||||
https://dnsimple.com/a/{your account id}/account/access_tokens
|
||||
|
||||
Note that this is an _account_ token and not a user token. The account token is
|
||||
needed to infer the `account_id` used in requests. A user token will not be able
|
||||
to determine the correct account to use.
|
||||
|
||||
```
|
||||
export DNSimple_OAUTH_TOKEN="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
```
|
||||
|
||||
To issue the cert just specify the `dns_dnsimple` API.
|
||||
|
||||
```
|
||||
acme.sh --issue --dns dns_dnsimple -d example.com
|
||||
```
|
||||
|
||||
The `DNSimple_OAUTH_TOKEN` will be saved in `~/.acme.sh/account.conf` and will
|
||||
be reused when needed.
|
||||
|
||||
If you have any issues with this integration please report them to
|
||||
https://github.com/pho3nixf1re/acme.sh/issues.
|
||||
|
||||
## 26. Use NS1.com API
|
||||
|
||||
```
|
||||
export NS1_Key="fdmlfsdklmfdkmqsdfk"
|
||||
```
|
||||
|
||||
Ok, let's issue a cert now:
|
||||
```
|
||||
acme.sh --issue --dns dns_nsone -d example.com -d www.example.com
|
||||
```
|
||||
|
||||
# Use custom API
|
||||
|
||||
If your API is not supported yet, you can write your own DNS API.
|
||||
|
||||
@@ -106,7 +106,7 @@ _get_root() {
|
||||
fi
|
||||
|
||||
if _contains "$response" "<Name>$h.</Name>"; then
|
||||
hostedzone="$(echo "$response" | sed 's/<HostedZone>/#&/g' | tr '#' '\n' | _egrep_o "<HostedZone><Id>[^<]*<.Id><Name>$h.<.Name>.*<.HostedZone>")"
|
||||
hostedzone="$(echo "$response" | sed 's/<HostedZone>/#&/g' | tr '#' '\n' | _egrep_o "<HostedZone><Id>[^<]*<.Id><Name>$h.<.Name>.*<PrivateZone>false<.PrivateZone>.*<.HostedZone>")"
|
||||
_debug hostedzone "$hostedzone"
|
||||
if [ -z "$hostedzone" ]; then
|
||||
_err "Error, can not get hostedzone."
|
||||
|
||||
@@ -14,6 +14,8 @@ dns_cf_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
CF_Key="${CF_Key:-$(_readaccountconf_mutable CF_Key)}"
|
||||
CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}"
|
||||
if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then
|
||||
CF_Key=""
|
||||
CF_Email=""
|
||||
@@ -29,8 +31,8 @@ dns_cf_add() {
|
||||
fi
|
||||
|
||||
#save the api key and email to the account conf file.
|
||||
_saveaccountconf CF_Key "$CF_Key"
|
||||
_saveaccountconf CF_Email "$CF_Email"
|
||||
_saveaccountconf_mutable CF_Key "$CF_Key"
|
||||
_saveaccountconf_mutable CF_Email "$CF_Email"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
@@ -83,6 +85,17 @@ dns_cf_add() {
|
||||
dns_cf_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
CF_Key="${CF_Key:-$(_readaccountconf_mutable CF_Key)}"
|
||||
CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}"
|
||||
if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then
|
||||
CF_Key=""
|
||||
CF_Email=""
|
||||
_err "You don't specify cloudflare api key and email yet."
|
||||
_err "Please create you key and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
|
||||
215
dnsapi/dns_dnsimple.sh
Normal file
215
dnsapi/dns_dnsimple.sh
Normal file
@@ -0,0 +1,215 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# DNSimple domain api
|
||||
# https://github.com/pho3nixf1re/acme.sh/issues
|
||||
#
|
||||
# This is your oauth token which can be acquired on the account page. Please
|
||||
# note that this must be an _account_ token and not a _user_ token.
|
||||
# https://dnsimple.com/a/<your account id>/account/access_tokens
|
||||
# DNSimple_OAUTH_TOKEN="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
|
||||
DNSimple_API="https://api.dnsimple.com/v2"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_dnsimple_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
if [ -z "$DNSimple_OAUTH_TOKEN" ]; then
|
||||
DNSimple_OAUTH_TOKEN=""
|
||||
_err "You have not set the dnsimple oauth token yet."
|
||||
_err "Please visit https://dnsimple.com/user to generate it."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# save the oauth token for later
|
||||
_saveaccountconf DNSimple_OAUTH_TOKEN "$DNSimple_OAUTH_TOKEN"
|
||||
|
||||
if ! _get_account_id; then
|
||||
_err "failed to retrive account id"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_get_records "$_account_id" "$_domain" "$_sub_domain"
|
||||
|
||||
if [ "$_records_count" = "0" ]; then
|
||||
_info "Adding record"
|
||||
if _dnsimple_rest POST "$_account_id/zones/$_domain/records" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then
|
||||
if printf -- "%s" "$response" | grep "\"name\":\"$_sub_domain\"" >/dev/null; then
|
||||
_info "Added"
|
||||
return 0
|
||||
else
|
||||
_err "Unexpected response while adding text record."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
_err "Add txt record error."
|
||||
else
|
||||
_info "Updating record"
|
||||
_extract_record_id "$_records" "$_sub_domain"
|
||||
|
||||
if _dnsimple_rest \
|
||||
PATCH \
|
||||
"$_account_id/zones/$_domain/records/$_record_id" \
|
||||
"{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then
|
||||
|
||||
_info "Updated!"
|
||||
return 0
|
||||
fi
|
||||
|
||||
_err "Update error"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# fulldomain
|
||||
dns_dnsimple_rm() {
|
||||
fulldomain=$1
|
||||
|
||||
if ! _get_account_id; then
|
||||
_err "failed to retrive account id"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_get_records "$_account_id" "$_domain" "$_sub_domain"
|
||||
_extract_record_id "$_records" "$_sub_domain"
|
||||
|
||||
if [ "$_record_id" ]; then
|
||||
|
||||
if _dnsimple_rest DELETE "$_account_id/zones/$_domain/records/$_record_id"; then
|
||||
_info "removed record" "$_record_id"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
_err "failed to remove record" "$_record_id"
|
||||
return 1
|
||||
|
||||
}
|
||||
|
||||
#################### Private functions bellow ##################################
|
||||
# _acme-challenge.www.domain.com
|
||||
# returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=2
|
||||
previous=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
if [ -z "$h" ]; then
|
||||
# not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _dnsimple_rest GET "$_account_id/zones/$h"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" 'not found'; then
|
||||
_debug "$h not found"
|
||||
else
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$previous)
|
||||
_domain="$h"
|
||||
|
||||
_debug _domain "$_domain"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
|
||||
return 0
|
||||
fi
|
||||
|
||||
previous="$i"
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# returns _account_id
|
||||
_get_account_id() {
|
||||
_debug "retrive account id"
|
||||
if ! _dnsimple_rest GET "whoami"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "\"account\":null"; then
|
||||
_err "no account associated with this token"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "timeout"; then
|
||||
_err "timeout retrieving account id"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_account_id=$(printf "%s" "$response" | _egrep_o "\"id\":[^,]*,\"email\":" | cut -d: -f2 | cut -d, -f1)
|
||||
_debug _account_id "$_account_id"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# returns
|
||||
# _records
|
||||
# _records_count
|
||||
_get_records() {
|
||||
account_id=$1
|
||||
domain=$2
|
||||
sub_domain=$3
|
||||
|
||||
_debug "fetching txt records"
|
||||
_dnsimple_rest GET "$account_id/zones/$domain/records?per_page=100"
|
||||
|
||||
if ! _contains "$response" "\"id\":"; then
|
||||
_err "failed to retrieve records"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_records_count=$(printf "%s" "$response" | _egrep_o "\"name\":\"$sub_domain\"" | wc -l | _egrep_o "[0-9]+")
|
||||
_records=$response
|
||||
_debug _records_count "$_records_count"
|
||||
}
|
||||
|
||||
# returns _record_id
|
||||
_extract_record_id() {
|
||||
_record_id=$(printf "%s" "$_records" | _egrep_o "\"id\":[^,]*,\"zone_id\":\"[^,]*\",\"parent_id\":null,\"name\":\"$_sub_domain\"" | cut -d: -f2 | cut -d, -f1)
|
||||
_debug "_record_id" "$_record_id"
|
||||
}
|
||||
|
||||
# returns response
|
||||
_dnsimple_rest() {
|
||||
method=$1
|
||||
path="$2"
|
||||
data="$3"
|
||||
request_url="$DNSimple_API/$path"
|
||||
_debug "$path"
|
||||
|
||||
export _H1="Accept: application/json"
|
||||
export _H2="Authorization: Bearer $DNSimple_OAUTH_TOKEN"
|
||||
|
||||
if [ "$data" ] || [ "$method" = "DELETE" ]; then
|
||||
_H1="Content-Type: application/json"
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$request_url" "" "$method")"
|
||||
else
|
||||
response="$(_get "$request_url" "" "" "$method")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $request_url"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
228
dnsapi/dns_dynu.sh
Normal file
228
dnsapi/dns_dynu.sh
Normal file
@@ -0,0 +1,228 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#Client ID
|
||||
#Dynu_ClientId="0b71cae7-a099-4f6b-8ddf-94571cdb760d"
|
||||
#
|
||||
#Secret
|
||||
#Dynu_Secret="aCUEY4BDCV45KI8CSIC3sp2LKQ9"
|
||||
#
|
||||
#Token
|
||||
Dynu_Token=""
|
||||
#
|
||||
#Endpoint
|
||||
Dynu_EndPoint="https://api.dynu.com/v1"
|
||||
#
|
||||
#Author: Dynu Systems, Inc.
|
||||
#Report Bugs here: https://github.com/shar0119/acme.sh
|
||||
#
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_dynu_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
if [ -z "$Dynu_ClientId" ] || [ -z "$Dynu_Secret" ]; then
|
||||
Dynu_ClientId=""
|
||||
Dynu_Secret=""
|
||||
_err "Dynu client id and secret is not specified."
|
||||
_err "Please create you API client id and secret and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the client id and secret to the account conf file.
|
||||
_saveaccountconf Dynu_ClientId "$Dynu_ClientId"
|
||||
_saveaccountconf Dynu_Secret "$Dynu_Secret"
|
||||
|
||||
if [ -z "$Dynu_Token" ]; then
|
||||
_info "Getting Dynu token."
|
||||
if ! _dynu_authentication; then
|
||||
_err "Can not get token."
|
||||
fi
|
||||
fi
|
||||
|
||||
_debug "Detect root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "Invalid domain."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug _node "$_node"
|
||||
_debug _domain_name "$_domain_name"
|
||||
|
||||
_info "Creating TXT record."
|
||||
if ! _dynu_rest POST "dns/record/add" "{\"domain_name\":\"$_domain_name\",\"node_name\":\"$_node\",\"record_type\":\"TXT\",\"text_data\":\"$txtvalue\",\"state\":true,\"ttl\":90}"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _contains "$response" "text_data"; then
|
||||
_err "Could not add TXT record."
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#Usage: rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_dynu_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
if [ -z "$Dynu_ClientId" ] || [ -z "$Dynu_Secret" ]; then
|
||||
Dynu_ClientId=""
|
||||
Dynu_Secret=""
|
||||
_err "Dynu client id and secret is not specified."
|
||||
_err "Please create you API client id and secret and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the client id and secret to the account conf file.
|
||||
_saveaccountconf Dynu_ClientId "$Dynu_ClientId"
|
||||
_saveaccountconf Dynu_Secret "$Dynu_Secret"
|
||||
|
||||
if [ -z "$Dynu_Token" ]; then
|
||||
_info "Getting Dynu token."
|
||||
if ! _dynu_authentication; then
|
||||
_err "Can not get token."
|
||||
fi
|
||||
fi
|
||||
|
||||
_debug "Detect root zone."
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "Invalid domain."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug _node "$_node"
|
||||
_debug _domain_name "$_domain_name"
|
||||
|
||||
_info "Checking for TXT record."
|
||||
if ! _get_recordid "$fulldomain" "$txtvalue"; then
|
||||
_err "Could not get TXT record id."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$_dns_record_id" = "" ]; then
|
||||
_err "TXT record not found."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Removing TXT record."
|
||||
if ! _delete_txt_record "$_dns_record_id"; then
|
||||
_err "Could not remove TXT record $_dns_record_id."
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
######## Private functions below ##################################
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _node=_acme-challenge.www
|
||||
# _domain_name=domain.com
|
||||
_get_root() {
|
||||
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
|
||||
|
||||
if ! _dynu_rest GET "dns/get/$h"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
|
||||
_domain_name=$h
|
||||
_node=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
return 0
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
|
||||
}
|
||||
|
||||
_get_recordid() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
if ! _dynu_rest GET "dns/record/get?hostname=$fulldomain&rrtype=TXT"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _contains "$response" "$txtvalue"; then
|
||||
_dns_record_id=0
|
||||
return 0
|
||||
fi
|
||||
|
||||
_dns_record_id=$(printf "%s" "$response" | _egrep_o "{[^}]*}" | grep "\"text_data\":\"$txtvalue\"" | _egrep_o ",[^,]*," | grep ',"id":' | tr -d ",," | cut -d : -f 2)
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
_delete_txt_record() {
|
||||
_dns_record_id=$1
|
||||
|
||||
if ! _dynu_rest GET "dns/record/delete/$_dns_record_id"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _contains "$response" "true"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
_dynu_rest() {
|
||||
m=$1
|
||||
ep="$2"
|
||||
data="$3"
|
||||
_debug "$ep"
|
||||
|
||||
export _H1="Authorization: Bearer $Dynu_Token"
|
||||
export _H2="Content-Type: application/json"
|
||||
|
||||
if [ "$data" ]; then
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$Dynu_EndPoint/$ep" "" "$m")"
|
||||
else
|
||||
_info "Getting $Dynu_EndPoint/$ep"
|
||||
response="$(_get "$Dynu_EndPoint/$ep")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
|
||||
_dynu_authentication() {
|
||||
realm="$(printf "%s" "$Dynu_ClientId:$Dynu_Secret" | _base64)"
|
||||
|
||||
export _H1="Authorization: Basic $realm"
|
||||
export _H2="Content-Type: application/json"
|
||||
|
||||
response="$(_get "$Dynu_EndPoint/oauth2/token")"
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "Authentication failed."
|
||||
return 1
|
||||
fi
|
||||
if _contains "$response" "accessToken"; then
|
||||
Dynu_Token=$(printf "%s" "$response" | tr -d "[]" | cut -d , -f 2 | cut -d : -f 2 | cut -d '"' -f 2)
|
||||
fi
|
||||
if _contains "$Dynu_Token" "null"; then
|
||||
Dynu_Token=""
|
||||
fi
|
||||
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
@@ -53,7 +53,7 @@ dns_freedns_add() {
|
||||
i="$(_math "$i" - 1)"
|
||||
sub_domain="$(echo "$fulldomain" | cut -d. -f -"$i")"
|
||||
|
||||
# Sometimes FreeDNS does not return the subdomain page but rather
|
||||
# Sometimes FreeDNS does not return the subdomain page but rather
|
||||
# returns a page regarding becoming a premium member. This usually
|
||||
# happens after a period of inactivity. Immediately trying again
|
||||
# returns the correct subdomain page. So, we will try twice to
|
||||
@@ -72,7 +72,7 @@ dns_freedns_add() {
|
||||
fi
|
||||
|
||||
# Now convert the tables in the HTML to CSV. This litte gem from
|
||||
# http://stackoverflow.com/questions/1403087/how-can-i-convert-an-html-table-to-csv
|
||||
# http://stackoverflow.com/questions/1403087/how-can-i-convert-an-html-table-to-csv
|
||||
subdomain_csv="$(echo "$htmlpage" \
|
||||
| grep -i -e '</\?TABLE\|</\?TD\|</\?TR\|</\?TH' \
|
||||
| sed 's/^[\ \t]*//g' \
|
||||
@@ -196,7 +196,7 @@ dns_freedns_rm() {
|
||||
FREEDNS_COOKIE="$(_read_conf "$ACCOUNT_CONF_PATH" "FREEDNS_COOKIE")"
|
||||
_debug "FreeDNS login cookies: $FREEDNS_COOKIE"
|
||||
|
||||
# Sometimes FreeDNS does not return the subdomain page but rather
|
||||
# Sometimes FreeDNS does not return the subdomain page but rather
|
||||
# returns a page regarding becoming a premium member. This usually
|
||||
# happens after a period of inactivity. Immediately trying again
|
||||
# returns the correct subdomain page. So, we will try twice to
|
||||
|
||||
@@ -37,7 +37,7 @@ dns_gandi_livedns_add() {
|
||||
_debug sub_domain "$_sub_domain"
|
||||
|
||||
_gandi_livedns_rest PUT "domains/$_domain/records/$_sub_domain/TXT" "{\"rrset_ttl\": 300, \"rrset_values\":[\"$txtvalue\"]}" \
|
||||
&& _contains "$response" '{"message": "Zone Record Created"}' \
|
||||
&& _contains "$response" '{"message": "DNS Record Created"}' \
|
||||
&& _info "Add $(__green "success")"
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ dns_infoblox_add() {
|
||||
## Nothing to see here, just some housekeeping
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue"
|
||||
baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&view=$Infoblox_View"
|
||||
|
||||
_info "Using Infoblox API"
|
||||
_debug fulldomain "$fulldomain"
|
||||
@@ -19,14 +19,19 @@ dns_infoblox_add() {
|
||||
if [ -z "$Infoblox_Creds" ] || [ -z "$Infoblox_Server" ]; then
|
||||
Infoblox_Creds=""
|
||||
Infoblox_Server=""
|
||||
_err "You didn't specify the credentials or server yet (Infoblox_Creds and Infoblox_Server)."
|
||||
_err "Please set them via EXPORT ([username:password] and [ip or hostname]) and try again."
|
||||
_err "You didn't specify the credentials, server or infoblox view yet (Infoblox_Creds, Infoblox_Server and Infoblox_View)."
|
||||
_err "Please set them via EXPORT ([username:password], [ip or hostname]) and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$Infoblox_View" ]; then
|
||||
Infoblox_View="default"
|
||||
fi
|
||||
|
||||
## Save the credentials to the account file
|
||||
_saveaccountconf Infoblox_Creds "$Infoblox_Creds"
|
||||
_saveaccountconf Infoblox_Server "$Infoblox_Server"
|
||||
_saveaccountconf Infoblox_View "$Infoblox_View"
|
||||
|
||||
## Base64 encode the credentials
|
||||
Infoblox_CredsEncoded=$(printf "%b" "$Infoblox_Creds" | _base64)
|
||||
@@ -39,7 +44,7 @@ dns_infoblox_add() {
|
||||
result=$(_post "" "$baseurlnObject" "" "POST")
|
||||
|
||||
## Let's see if we get something intelligible back from the unit
|
||||
if echo "$result" | egrep 'record:txt/.*:.*/default'; then
|
||||
if echo "$result" | egrep "record:txt/.*:.*/$Infoblox_View"; then
|
||||
_info "Successfully created the txt record"
|
||||
return 0
|
||||
else
|
||||
@@ -68,18 +73,18 @@ dns_infoblox_rm() {
|
||||
export _H2="Authorization: Basic $Infoblox_CredsEncoded"
|
||||
|
||||
## Does the record exist? Let's check.
|
||||
baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&_return_type=xml-pretty"
|
||||
baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&view=$Infoblox_View&_return_type=xml-pretty"
|
||||
result=$(_get "$baseurlnObject")
|
||||
|
||||
## Let's see if we get something intelligible back from the grid
|
||||
if echo "$result" | egrep 'record:txt/.*:.*/default'; then
|
||||
if echo "$result" | egrep "record:txt/.*:.*/$Infoblox_View"; then
|
||||
## Extract the object reference
|
||||
objRef=$(printf "%b" "$result" | _egrep_o 'record:txt/.*:.*/default')
|
||||
objRef=$(printf "%b" "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")
|
||||
objRmUrl="https://$Infoblox_Server/wapi/v2.2.2/$objRef"
|
||||
## Delete them! All the stale records!
|
||||
rmResult=$(_post "" "$objRmUrl" "" "DELETE")
|
||||
## Let's see if that worked
|
||||
if echo "$rmResult" | egrep 'record:txt/.*:.*/default'; then
|
||||
if echo "$rmResult" | egrep "record:txt/.*:.*/$Infoblox_View"; then
|
||||
_info "Successfully deleted $objRef"
|
||||
return 0
|
||||
else
|
||||
|
||||
158
dnsapi/dns_nsone.sh
Normal file
158
dnsapi/dns_nsone.sh
Normal file
@@ -0,0 +1,158 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# bug reports to dev@1e.ca
|
||||
|
||||
#
|
||||
#NS1_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
#
|
||||
|
||||
NS1_Api="https://api.nsone.net/v1"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_nsone_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
if [ -z "$NS1_Key" ]; then
|
||||
NS1_Key=""
|
||||
_err "You didn't specify nsone dns api key yet."
|
||||
_err "Please create you key and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the api key and email to the account conf file.
|
||||
_saveaccountconf NS1_Key "$NS1_Key"
|
||||
|
||||
_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"
|
||||
_nsone_rest GET "zones/${_domain}"
|
||||
|
||||
if ! _contains "$response" "\"records\":"; then
|
||||
_err "Error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
count=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain\",[^{]*\"type\":\"TXT\"" | wc -l | tr -d " ")
|
||||
_debug count "$count"
|
||||
if [ "$count" = "0" ]; then
|
||||
_info "Adding record"
|
||||
|
||||
if _nsone_rest PUT "zones/$_domain/$fulldomain/TXT" "{\"answers\":[{\"answer\":[\"$txtvalue\"]}],\"type\":\"TXT\",\"domain\":\"$fulldomain\",\"zone\":\"$_domain\"}"; then
|
||||
if _contains "$response" "$fulldomain"; then
|
||||
_info "Added"
|
||||
#todo: check if the record takes effect
|
||||
return 0
|
||||
else
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
_err "Add txt record error."
|
||||
else
|
||||
_info "Updating record"
|
||||
record_id=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain.\",[^{]*\"type\":\"TXT\",\"id\":\"[^,]*\"" | _head_n 1 | cut -d: -f7 | cut -d, -f1)
|
||||
_debug "record_id" "$record_id"
|
||||
|
||||
_nsone_rest POST "zones/$_domain/$fulldomain/TXT" "{\"answers\": [{\"answer\": [\"$txtvalue\"]}],\"type\": \"TXT\",\"domain\":\"$fulldomain\",\"zone\": \"$_domain\"}"
|
||||
if [ "$?" = "0" ] && _contains "$response" "$fulldomain"; then
|
||||
_info "Updated!"
|
||||
#todo: check if the record takes effect
|
||||
return 0
|
||||
fi
|
||||
_err "Update error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
#fulldomain
|
||||
dns_nsone_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_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"
|
||||
_nsone_rest GET "zones/${_domain}/$fulldomain/TXT"
|
||||
|
||||
count=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain\",.*\"type\":\"TXT\"" | wc -l | tr -d " ")
|
||||
_debug count "$count"
|
||||
if [ "$count" = "0" ]; then
|
||||
_info "Don't need to remove."
|
||||
else
|
||||
if ! _nsone_rest DELETE "zones/${_domain}/$fulldomain/TXT"; then
|
||||
_err "Delete record error."
|
||||
return 1
|
||||
fi
|
||||
_contains "$response" ""
|
||||
fi
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
# _domain_id=sdjkglgdfewsdfg
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=2
|
||||
p=1
|
||||
if ! _nsone_rest GET "zones"; then
|
||||
return 1
|
||||
fi
|
||||
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" "\"zone\":\"$h\""; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain="$h"
|
||||
return 0
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
_nsone_rest() {
|
||||
m=$1
|
||||
ep="$2"
|
||||
data="$3"
|
||||
_debug "$ep"
|
||||
|
||||
export _H1="Accept: application/json"
|
||||
export _H2="X-NSONE-Key: $NS1_Key"
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$NS1_Api/$ep" "" "$m")"
|
||||
else
|
||||
response="$(_get "$NS1_Api/$ep")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
#'ovh-eu'
|
||||
OVH_EU='https://eu.api.ovh.com/1.0'
|
||||
|
||||
#'ovh-ca':
|
||||
#'ovh-ca':
|
||||
OVH_CA='https://ca.api.ovh.com/1.0'
|
||||
|
||||
#'kimsufi-eu'
|
||||
@@ -119,7 +119,7 @@ dns_ovh_add() {
|
||||
|
||||
_info "Checking authentication"
|
||||
|
||||
response="$(_ovh_rest GET "domain/")"
|
||||
response="$(_ovh_rest GET "domain")"
|
||||
if _contains "$response" "INVALID_CREDENTIAL"; then
|
||||
_err "The consumer key is invalid: $OVH_CK"
|
||||
_err "Please retry to create a new one."
|
||||
@@ -191,7 +191,7 @@ _ovh_authentication() {
|
||||
_H3=""
|
||||
_H4=""
|
||||
|
||||
_ovhdata='{"accessRules": [{"method": "GET","path": "/*"},{"method": "POST","path": "/*"},{"method": "PUT","path": "/*"},{"method": "DELETE","path": "/*"}],"redirection":"'$ovh_success'"}'
|
||||
_ovhdata='{"accessRules": [{"method": "GET","path": "/auth/time"},{"method": "GET","path": "/domain"},{"method": "GET","path": "/domain/zone/*"},{"method": "GET","path": "/domain/zone/*/record"},{"method": "POST","path": "/domain/zone/*/record"},{"method": "POST","path": "/domain/zone/*/refresh"},{"method": "PUT","path": "/domain/zone/*/record/*"}],"redirection":"'$ovh_success'"}'
|
||||
|
||||
response="$(_post "$_ovhdata" "$OVH_API/auth/credential")"
|
||||
_debug3 response "$response"
|
||||
@@ -238,7 +238,7 @@ _get_root() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _contains "$response" "This service does not exist" >/dev/null; then
|
||||
if ! _contains "$response" "This service does not exist" >/dev/null && ! _contains "$response" "NOT_GRANTED_CALL" >/dev/null; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain="$h"
|
||||
return 0
|
||||
|
||||
149
dnsapi/dns_vscale.sh
Executable file
149
dnsapi/dns_vscale.sh
Executable file
@@ -0,0 +1,149 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#This is the vscale.io api wrapper for acme.sh
|
||||
#
|
||||
#Author: Alex Loban
|
||||
#Report Bugs here: https://github.com/LAV45/acme.sh
|
||||
|
||||
#VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
VSCALE_API_URL="https://api.vscale.io/v1"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_vscale_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
if [ -z "$VSCALE_API_KEY" ]; then
|
||||
VSCALE_API_KEY=""
|
||||
_err "You didn't specify the VSCALE api key yet."
|
||||
_err "Please create you key and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf VSCALE_API_KEY "$VSCALE_API_KEY"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_vscale_tmpl_json="{\"type\":\"TXT\",\"name\":\"$_sub_domain.$_domain\",\"content\":\"$txtvalue\"}"
|
||||
|
||||
if _vscale_rest POST "domains/$_domain_id/records/" "$_vscale_tmpl_json"; then
|
||||
response=$(printf "%s\n" "$response" | _egrep_o "{\"error\": \".+\"" | cut -d : -f 2)
|
||||
if [ -z "$response" ]; then
|
||||
_info "txt record updated success."
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
#fulldomain txtvalue
|
||||
dns_vscale_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_debug "Getting txt records"
|
||||
_vscale_rest GET "domains/$_domain_id/records/"
|
||||
|
||||
if [ -n "$response" ]; then
|
||||
record_id=$(printf "%s\n" "$response" | _egrep_o "\"TXT\", \"id\": [0-9]+, \"name\": \"$_sub_domain.$_domain\"" | cut -d : -f 2 | tr -d ", \"name\"")
|
||||
_debug record_id "$record_id"
|
||||
if [ -z "$record_id" ]; then
|
||||
_err "Can not get record id to remove."
|
||||
return 1
|
||||
fi
|
||||
if _vscale_rest DELETE "domains/$_domain_id/records/$record_id" && [ -z "$response" ]; then
|
||||
_info "txt record deleted success."
|
||||
return 0
|
||||
fi
|
||||
_debug response "$response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
# _domain_id=12345
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=2
|
||||
p=1
|
||||
|
||||
if _vscale_rest GET "domains/"; then
|
||||
response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')"
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
hostedzone="$(echo "$response" | _egrep_o "{.*\"name\":\s*\"$h\".*}")"
|
||||
if [ "$hostedzone" ]; then
|
||||
_domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ )
|
||||
if [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
#method uri qstr data
|
||||
_vscale_rest() {
|
||||
mtd="$1"
|
||||
ep="$2"
|
||||
data="$3"
|
||||
|
||||
_debug mtd "$mtd"
|
||||
_debug ep "$ep"
|
||||
|
||||
export _H1="Accept: application/json"
|
||||
export _H2="Content-Type: application/json"
|
||||
export _H3="X-Token: ${VSCALE_API_KEY}"
|
||||
|
||||
if [ "$mtd" != "GET" ]; then
|
||||
# both POST and DELETE.
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$VSCALE_API_URL/$ep" "" "$mtd")"
|
||||
else
|
||||
response="$(_get "$VSCALE_API_URL/$ep")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
Reference in New Issue
Block a user