mirror of
https://github.com/acmesh-official/acme.sh
synced 2025-11-24 18:01:56 +08:00
Compare commits
166 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b7caf7a016 | ||
|
|
891198e4f3 | ||
|
|
38c5910be4 | ||
|
|
327e2fb0a4 | ||
|
|
c20c219990 | ||
|
|
4c30250782 | ||
|
|
caf23f9a04 | ||
|
|
beab808b76 | ||
|
|
6c8920f63e | ||
|
|
51be15f66d | ||
|
|
110e25e784 | ||
|
|
8414100d0b | ||
|
|
a3f4cb154e | ||
|
|
e6e22a1ca1 | ||
|
|
b937665b90 | ||
|
|
a7bc2293c0 | ||
|
|
0d25f7612b | ||
|
|
84e4181ed7 | ||
|
|
f66a29d1c3 | ||
|
|
dbd3881cea | ||
|
|
7eb6bbe65f | ||
|
|
a570fda1cb | ||
|
|
3b06fa6523 | ||
|
|
dcdbe2fbb8 | ||
|
|
dc1f36da43 | ||
|
|
05dbd395e6 | ||
|
|
69e7360cc3 | ||
|
|
7ef2533b98 | ||
|
|
97f87c4229 | ||
|
|
42a5cd961d | ||
|
|
bf00d3157f | ||
|
|
cf3ff4c136 | ||
|
|
7fe06adcfd | ||
|
|
ae3e5dbf2c | ||
|
|
20304590b4 | ||
|
|
2d8c0c0131 | ||
|
|
70f4cad2ca | ||
|
|
1f777a94a7 | ||
|
|
7560c64f46 | ||
|
|
bddde60522 | ||
|
|
e9366f8c76 | ||
|
|
4dba84d09e | ||
|
|
0cce2d6098 | ||
|
|
acbd8bce21 | ||
|
|
dea8a08b64 | ||
|
|
dde1bab1a8 | ||
|
|
799e402077 | ||
|
|
ce629e8e70 | ||
|
|
20cfc4ac66 | ||
|
|
132d5e8253 | ||
|
|
cb8b341fb4 | ||
|
|
982c54b605 | ||
|
|
67f543332a | ||
|
|
88ac4086c2 | ||
|
|
15f96b7239 | ||
|
|
0ea84ad799 | ||
|
|
1522b713da | ||
|
|
fe6b27bb59 | ||
|
|
df14b15397 | ||
|
|
7dd12044de | ||
|
|
06e12a30e7 | ||
|
|
d3fefd223d | ||
|
|
c0639c6608 | ||
|
|
05a2eb3df4 | ||
|
|
d4befeb536 | ||
|
|
f7f1168aad | ||
|
|
d6cf15368a | ||
|
|
a5fbf3fb80 | ||
|
|
3cf8f78745 | ||
|
|
59dab6eac7 | ||
|
|
553d861b8a | ||
|
|
7b5d94d062 | ||
|
|
cb021efaee | ||
|
|
c2344f3717 | ||
|
|
f537c606f7 | ||
|
|
c8f48a4a90 | ||
|
|
c2ad1b4e46 | ||
|
|
ba9d146d6c | ||
|
|
a5b04a0328 | ||
|
|
01249d0cb9 | ||
|
|
71c273fbcb | ||
|
|
aa9cbf7c55 | ||
|
|
429b18ed48 | ||
|
|
2690c05781 | ||
|
|
e3b688c9d8 | ||
|
|
41b6f18a5d | ||
|
|
5a59c39036 | ||
|
|
a02dd18ad7 | ||
|
|
16bdc7d0a3 | ||
|
|
40002e8040 | ||
|
|
6748c55c04 | ||
|
|
deb63b4adf | ||
|
|
015a9b9271 | ||
|
|
ab2305e259 | ||
|
|
b99c998057 | ||
|
|
6c0a7144f6 | ||
|
|
bf50fce5bd | ||
|
|
8718b156c4 | ||
|
|
7bbdd1f839 | ||
|
|
ffed1a4afa | ||
|
|
1bfd3642e8 | ||
|
|
577f4e0cc3 | ||
|
|
e2f05f3fc9 | ||
|
|
27f30631ed | ||
|
|
1ccfa96c2e | ||
|
|
a2c64e79ff | ||
|
|
7b623f85cd | ||
|
|
ed63eb6833 | ||
|
|
b8d0d3c242 | ||
|
|
fe1bfe9ae1 | ||
|
|
7154c9ee5d | ||
|
|
057c95bd1c | ||
|
|
0cafc00c4f | ||
|
|
75d2898efd | ||
|
|
764a4c99fa | ||
|
|
160513c671 | ||
|
|
a2af26635f | ||
|
|
63869deeb2 | ||
|
|
91e387e8b9 | ||
|
|
7d13146859 | ||
|
|
699d2b7e7e | ||
|
|
257de15c73 | ||
|
|
5a0225d033 | ||
|
|
bd2d0e6ad3 | ||
|
|
0c0d1d4e52 | ||
|
|
eab9603921 | ||
|
|
c07db3aa14 | ||
|
|
a19f7481b2 | ||
|
|
2905edce35 | ||
|
|
04a5d794ac | ||
|
|
264b9819ff | ||
|
|
4610204c83 | ||
|
|
ecf1f17cf4 | ||
|
|
9f942a6b65 | ||
|
|
f4ed1b32b8 | ||
|
|
ec0e871592 | ||
|
|
7a756ebc4d | ||
|
|
affb65219e | ||
|
|
78198bfdaf | ||
|
|
190cac394c | ||
|
|
be07fe9e9f | ||
|
|
ca0981645f | ||
|
|
bc7e02b47a | ||
|
|
55a55e9f74 | ||
|
|
b41d40da40 | ||
|
|
ba3e088b23 | ||
|
|
40e0d72105 | ||
|
|
dfe80556d3 | ||
|
|
095697900b | ||
|
|
d2a9d731ed | ||
|
|
3ce7d410c8 | ||
|
|
74f28021e7 | ||
|
|
f90cbb636a | ||
|
|
c8929ca0cb | ||
|
|
9fb5bb620d | ||
|
|
ed58f32052 | ||
|
|
6d2ab4d270 | ||
|
|
a6b58bc88d | ||
|
|
ea3c37d754 | ||
|
|
b37bf06de8 | ||
|
|
27bbf0ccaf | ||
|
|
71a32477e4 | ||
|
|
08d60fcbf2 | ||
|
|
4cda54774a | ||
|
|
613475ac26 | ||
|
|
20d23fcb92 |
70
.github/workflows/DNS.yml
vendored
70
.github/workflows/DNS.yml
vendored
@@ -121,19 +121,19 @@ jobs:
|
||||
- name: Run acmetest
|
||||
run: |
|
||||
if [ "${{ secrets.TokenName1}}" ] ; then
|
||||
export ${{ secrets.TokenName1}}=${{ secrets.TokenValue1}}
|
||||
export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName2}}" ] ; then
|
||||
export ${{ secrets.TokenName2}}=${{ secrets.TokenValue2}}
|
||||
export ${{ secrets.TokenName2}}="${{ secrets.TokenValue2}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName3}}" ] ; then
|
||||
export ${{ secrets.TokenName3}}=${{ secrets.TokenValue3}}
|
||||
export ${{ secrets.TokenName3}}="${{ secrets.TokenValue3}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName4}}" ] ; then
|
||||
export ${{ secrets.TokenName4}}=${{ secrets.TokenValue4}}
|
||||
export ${{ secrets.TokenName4}}="${{ secrets.TokenValue4}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName5}}" ] ; then
|
||||
export ${{ secrets.TokenName5}}=${{ secrets.TokenValue5}}
|
||||
export ${{ secrets.TokenName5}}="${{ secrets.TokenValue5}}"
|
||||
fi
|
||||
cd ../acmetest
|
||||
./letest.sh
|
||||
@@ -184,19 +184,19 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
if [ "${{ secrets.TokenName1}}" ] ; then
|
||||
export ${{ secrets.TokenName1}}=${{ secrets.TokenValue1}}
|
||||
export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName2}}" ] ; then
|
||||
export ${{ secrets.TokenName2}}=${{ secrets.TokenValue2}}
|
||||
export ${{ secrets.TokenName2}}="${{ secrets.TokenValue2}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName3}}" ] ; then
|
||||
export ${{ secrets.TokenName3}}=${{ secrets.TokenValue3}}
|
||||
export ${{ secrets.TokenName3}}="${{ secrets.TokenValue3}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName4}}" ] ; then
|
||||
export ${{ secrets.TokenName4}}=${{ secrets.TokenValue4}}
|
||||
export ${{ secrets.TokenName4}}="${{ secrets.TokenValue4}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName5}}" ] ; then
|
||||
export ${{ secrets.TokenName5}}=${{ secrets.TokenValue5}}
|
||||
export ${{ secrets.TokenName5}}="${{ secrets.TokenValue5}}"
|
||||
fi
|
||||
cd ../acmetest
|
||||
./letest.sh
|
||||
@@ -234,19 +234,19 @@ jobs:
|
||||
copyback: false
|
||||
run: |
|
||||
if [ "${{ secrets.TokenName1}}" ] ; then
|
||||
export ${{ secrets.TokenName1}}=${{ secrets.TokenValue1}}
|
||||
export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName2}}" ] ; then
|
||||
export ${{ secrets.TokenName2}}=${{ secrets.TokenValue2}}
|
||||
export ${{ secrets.TokenName2}}="${{ secrets.TokenValue2}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName3}}" ] ; then
|
||||
export ${{ secrets.TokenName3}}=${{ secrets.TokenValue3}}
|
||||
export ${{ secrets.TokenName3}}="${{ secrets.TokenValue3}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName4}}" ] ; then
|
||||
export ${{ secrets.TokenName4}}=${{ secrets.TokenValue4}}
|
||||
export ${{ secrets.TokenName4}}="${{ secrets.TokenValue4}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName5}}" ] ; then
|
||||
export ${{ secrets.TokenName5}}=${{ secrets.TokenValue5}}
|
||||
export ${{ secrets.TokenName5}}="${{ secrets.TokenValue5}}"
|
||||
fi
|
||||
cd ../acmetest
|
||||
./letest.sh
|
||||
@@ -285,19 +285,19 @@ jobs:
|
||||
copyback: false
|
||||
run: |
|
||||
if [ "${{ secrets.TokenName1}}" ] ; then
|
||||
export ${{ secrets.TokenName1}}=${{ secrets.TokenValue1}}
|
||||
export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName2}}" ] ; then
|
||||
export ${{ secrets.TokenName2}}=${{ secrets.TokenValue2}}
|
||||
export ${{ secrets.TokenName2}}="${{ secrets.TokenValue2}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName3}}" ] ; then
|
||||
export ${{ secrets.TokenName3}}=${{ secrets.TokenValue3}}
|
||||
export ${{ secrets.TokenName3}}="${{ secrets.TokenValue3}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName4}}" ] ; then
|
||||
export ${{ secrets.TokenName4}}=${{ secrets.TokenValue4}}
|
||||
export ${{ secrets.TokenName4}}="${{ secrets.TokenValue4}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName5}}" ] ; then
|
||||
export ${{ secrets.TokenName5}}=${{ secrets.TokenValue5}}
|
||||
export ${{ secrets.TokenName5}}="${{ secrets.TokenValue5}}"
|
||||
fi
|
||||
cd ../acmetest
|
||||
./letest.sh
|
||||
@@ -337,19 +337,19 @@ jobs:
|
||||
copyback: false
|
||||
run: |
|
||||
if [ "${{ secrets.TokenName1}}" ] ; then
|
||||
export ${{ secrets.TokenName1}}=${{ secrets.TokenValue1}}
|
||||
export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName2}}" ] ; then
|
||||
export ${{ secrets.TokenName2}}=${{ secrets.TokenValue2}}
|
||||
export ${{ secrets.TokenName2}}="${{ secrets.TokenValue2}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName3}}" ] ; then
|
||||
export ${{ secrets.TokenName3}}=${{ secrets.TokenValue3}}
|
||||
export ${{ secrets.TokenName3}}="${{ secrets.TokenValue3}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName4}}" ] ; then
|
||||
export ${{ secrets.TokenName4}}=${{ secrets.TokenValue4}}
|
||||
export ${{ secrets.TokenName4}}="${{ secrets.TokenValue4}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName5}}" ] ; then
|
||||
export ${{ secrets.TokenName5}}=${{ secrets.TokenValue5}}
|
||||
export ${{ secrets.TokenName5}}="${{ secrets.TokenValue5}}"
|
||||
fi
|
||||
cd ../acmetest
|
||||
./letest.sh
|
||||
@@ -389,19 +389,19 @@ jobs:
|
||||
copyback: false
|
||||
run: |
|
||||
if [ "${{ secrets.TokenName1}}" ] ; then
|
||||
export ${{ secrets.TokenName1}}=${{ secrets.TokenValue1}}
|
||||
export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName2}}" ] ; then
|
||||
export ${{ secrets.TokenName2}}=${{ secrets.TokenValue2}}
|
||||
export ${{ secrets.TokenName2}}="${{ secrets.TokenValue2}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName3}}" ] ; then
|
||||
export ${{ secrets.TokenName3}}=${{ secrets.TokenValue3}}
|
||||
export ${{ secrets.TokenName3}}="${{ secrets.TokenValue3}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName4}}" ] ; then
|
||||
export ${{ secrets.TokenName4}}=${{ secrets.TokenValue4}}
|
||||
export ${{ secrets.TokenName4}}="${{ secrets.TokenValue4}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName5}}" ] ; then
|
||||
export ${{ secrets.TokenName5}}=${{ secrets.TokenValue5}}
|
||||
export ${{ secrets.TokenName5}}="${{ secrets.TokenValue5}}"
|
||||
fi
|
||||
cd ../acmetest
|
||||
./letest.sh
|
||||
@@ -445,19 +445,19 @@ jobs:
|
||||
pkg set-mediator -v -I default@1.1 openssl
|
||||
export PATH=/usr/gnu/bin:$PATH
|
||||
if [ "${{ secrets.TokenName1}}" ] ; then
|
||||
export ${{ secrets.TokenName1}}=${{ secrets.TokenValue1}}
|
||||
export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName2}}" ] ; then
|
||||
export ${{ secrets.TokenName2}}=${{ secrets.TokenValue2}}
|
||||
export ${{ secrets.TokenName2}}="${{ secrets.TokenValue2}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName3}}" ] ; then
|
||||
export ${{ secrets.TokenName3}}=${{ secrets.TokenValue3}}
|
||||
export ${{ secrets.TokenName3}}="${{ secrets.TokenValue3}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName4}}" ] ; then
|
||||
export ${{ secrets.TokenName4}}=${{ secrets.TokenValue4}}
|
||||
export ${{ secrets.TokenName4}}="${{ secrets.TokenValue4}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName5}}" ] ; then
|
||||
export ${{ secrets.TokenName5}}=${{ secrets.TokenValue5}}
|
||||
export ${{ secrets.TokenName5}}="${{ secrets.TokenValue5}}"
|
||||
fi
|
||||
cd ../acmetest
|
||||
./letest.sh
|
||||
|
||||
1
.github/workflows/NetBSD.yml
vendored
1
.github/workflows/NetBSD.yml
vendored
@@ -61,7 +61,6 @@ jobs:
|
||||
nat: |
|
||||
"8080": "80"
|
||||
prepare: |
|
||||
export PKG_PATH="https://cdn.NetBSD.org/pub/pkgsrc/packages/NetBSD/$(uname -p)/$(uname -r|cut -f '1 2' -d.)/All/"
|
||||
pkg_add curl socat
|
||||
usesh: true
|
||||
copyback: false
|
||||
|
||||
9
.github/workflows/Ubuntu.yml
vendored
9
.github/workflows/Ubuntu.yml
vendored
@@ -80,9 +80,14 @@ jobs:
|
||||
-p 9000:9000 \
|
||||
-e "DOCKER_STEPCA_INIT_NAME=Smallstep" \
|
||||
-e "DOCKER_STEPCA_INIT_DNS_NAMES=localhost,$(hostname -f)" \
|
||||
-e "DOCKER_STEPCA_INIT_REMOTE_MANAGEMENT=true" \
|
||||
-e "DOCKER_STEPCA_INIT_PASSWORD=test" \
|
||||
--name stepca \
|
||||
smallstep/step-ca \
|
||||
&& sleep 5 && docker exec stepca step ca provisioner add acme --type ACME \
|
||||
smallstep/step-ca:0.23.1
|
||||
|
||||
sleep 5
|
||||
docker exec stepca bash -c "echo test >test" \
|
||||
&& docker exec stepca step ca provisioner add acme --type ACME --admin-subject step --admin-password-file=/home/step/test \
|
||||
&& docker exec stepca kill -1 1 \
|
||||
&& docker exec stepca cat /home/step/certs/root_ca.crt | sudo bash -c "cat - >>/etc/ssl/certs/ca-certificates.crt"
|
||||
- name: Clone acmetest
|
||||
|
||||
8
.github/workflows/dockerhub.yml
vendored
8
.github/workflows/dockerhub.yml
vendored
@@ -28,9 +28,9 @@ jobs:
|
||||
id: step_one
|
||||
run: |
|
||||
if [ "$DOCKER_PASSWORD" ] ; then
|
||||
echo "::set-output name=hasToken::true"
|
||||
echo "hasToken=true" >>$GITHUB_OUTPUT
|
||||
else
|
||||
echo "::set-output name=hasToken::false"
|
||||
echo "hasToken=false" >>$GITHUB_OUTPUT
|
||||
fi
|
||||
- name: Check the value
|
||||
run: echo ${{ steps.step_one.outputs.hasToken }}
|
||||
@@ -43,9 +43,9 @@ jobs:
|
||||
- name: checkout code
|
||||
uses: actions/checkout@v3
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: login to docker hub
|
||||
run: |
|
||||
echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
|
||||
|
||||
13
Dockerfile
13
Dockerfile
@@ -1,4 +1,4 @@
|
||||
FROM alpine:3.16.3
|
||||
FROM alpine:3.17
|
||||
|
||||
RUN apk --no-cache add -f \
|
||||
openssl \
|
||||
@@ -12,7 +12,8 @@ RUN apk --no-cache add -f \
|
||||
oath-toolkit-oathtool \
|
||||
tar \
|
||||
libidn \
|
||||
jq
|
||||
jq \
|
||||
cronie
|
||||
|
||||
ENV LE_CONFIG_HOME /acme.sh
|
||||
|
||||
@@ -25,7 +26,7 @@ COPY ./ /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 && crontab -l | grep acme.sh | sed 's#> /dev/null##' | crontab -
|
||||
RUN ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh && crontab -l | grep acme.sh | sed 's#> /dev/null#> /proc/1/fd/1 2>/proc/1/fd/2#' | crontab -
|
||||
|
||||
RUN for verb in help \
|
||||
version \
|
||||
@@ -64,12 +65,10 @@ RUN for verb in help \
|
||||
|
||||
RUN printf "%b" '#!'"/usr/bin/env sh\n \
|
||||
if [ \"\$1\" = \"daemon\" ]; then \n \
|
||||
trap \"echo stop && killall crond && exit 0\" SIGTERM SIGINT \n \
|
||||
crond && sleep infinity &\n \
|
||||
wait \n \
|
||||
exec crond -n -s -m off \n \
|
||||
else \n \
|
||||
exec -- \"\$@\"\n \
|
||||
fi" >/entry.sh && chmod +x /entry.sh
|
||||
fi\n" >/entry.sh && chmod +x /entry.sh
|
||||
|
||||
VOLUME /acme.sh
|
||||
|
||||
|
||||
14
README.md
14
README.md
@@ -51,14 +51,12 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa)
|
||||
- [ruby-china.org](https://ruby-china.org/topics/31983)
|
||||
- [Proxmox](https://pve.proxmox.com/wiki/Certificate_Management)
|
||||
- [pfsense](https://github.com/pfsense/FreeBSD-ports/pull/89)
|
||||
- [webfaction](https://community.webfaction.com/questions/19988/using-letsencrypt)
|
||||
- [Loadbalancer.org](https://www.loadbalancer.org/blog/loadbalancer-org-with-lets-encrypt-quick-and-dirty)
|
||||
- [discourse.org](https://meta.discourse.org/t/setting-up-lets-encrypt/40709)
|
||||
- [Centminmod](https://centminmod.com/letsencrypt-acmetool-https.html)
|
||||
- [splynx](https://forum.splynx.com/t/free-ssl-cert-for-splynx-lets-encrypt/297)
|
||||
- [archlinux](https://www.archlinux.org/packages/community/any/acme.sh)
|
||||
- [opnsense.org](https://github.com/opnsense/plugins/tree/master/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient)
|
||||
- [CentOS Web Panel](http://centos-webpanel.com/)
|
||||
- [CentOS Web Panel](https://control-webpanel.com)
|
||||
- [lnmp.org](https://lnmp.org/)
|
||||
- [more...](https://github.com/acmesh-official/acme.sh/wiki/Blogs-and-tutorials)
|
||||
|
||||
@@ -361,10 +359,6 @@ Ok, it's done.
|
||||
|
||||
# 10. Issue ECC certificates
|
||||
|
||||
`Let's Encrypt` can now issue **ECDSA** certificates.
|
||||
|
||||
And we support them too!
|
||||
|
||||
Just set the `keylength` parameter with a prefix `ec-`.
|
||||
|
||||
For example:
|
||||
@@ -385,10 +379,12 @@ Please look at the `keylength` parameter above.
|
||||
|
||||
Valid values are:
|
||||
|
||||
1. **ec-256 (prime256v1, "ECDSA P-256")**
|
||||
1. **ec-256 (prime256v1, "ECDSA P-256", which is the default key type)**
|
||||
2. **ec-384 (secp384r1, "ECDSA P-384")**
|
||||
3. **ec-521 (secp521r1, "ECDSA P-521", which is not supported by Let's Encrypt yet.)**
|
||||
|
||||
4. **2048 (RSA2048)**
|
||||
5. **3072 (RSA3072)**
|
||||
6. **4096 (RSA4096)**
|
||||
|
||||
|
||||
# 11. Issue Wildcard certificates
|
||||
|
||||
252
acme.sh
252
acme.sh
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
VER=3.0.5
|
||||
VER=3.0.6
|
||||
|
||||
PROJECT_NAME="acme.sh"
|
||||
|
||||
@@ -53,8 +53,8 @@ CA_SERVERS="$CA_ZEROSSL,$CA_LETSENCRYPT_V2,$CA_LETSENCRYPT_V2_TEST,$CA_BUYPASS,$
|
||||
|
||||
DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)"
|
||||
|
||||
DEFAULT_ACCOUNT_KEY_LENGTH=2048
|
||||
DEFAULT_DOMAIN_KEY_LENGTH=2048
|
||||
DEFAULT_ACCOUNT_KEY_LENGTH=ec-256
|
||||
DEFAULT_DOMAIN_KEY_LENGTH=ec-256
|
||||
|
||||
DEFAULT_OPENSSL_BIN="openssl"
|
||||
|
||||
@@ -1637,7 +1637,7 @@ _stat() {
|
||||
#keyfile
|
||||
_isRSA() {
|
||||
keyfile=$1
|
||||
if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1 || ${ACME_OPENSSL_BIN:-openssl} rsa -in "$keyfile" -noout -text | grep "^publicExponent:" >/dev/null 2>&1; then
|
||||
if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1 || ${ACME_OPENSSL_BIN:-openssl} rsa -in "$keyfile" -noout -text 2>&1 | grep "^publicExponent:" 2>&1 >/dev/null; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
@@ -1646,7 +1646,7 @@ _isRSA() {
|
||||
#keyfile
|
||||
_isEcc() {
|
||||
keyfile=$1
|
||||
if grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1 || ${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" >/dev/null 2>&1; then
|
||||
if grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1 || ${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" 2>&1 >/dev/null; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
@@ -1744,7 +1744,7 @@ _calcjwk() {
|
||||
_debug3 x64 "$x64"
|
||||
|
||||
xend=$(_math "$xend" + 1)
|
||||
y="$(printf "%s" "$pubtext" | cut -d : -f "$xend"-10000)"
|
||||
y="$(printf "%s" "$pubtext" | cut -d : -f "$xend"-2048)"
|
||||
_debug3 y "$y"
|
||||
|
||||
y64="$(printf "%s" "$y" | tr -d : | _h2b | _base64 | _url_replace)"
|
||||
@@ -1852,9 +1852,15 @@ _inithttp() {
|
||||
_ACME_CURL="$_ACME_CURL --cacert $CA_BUNDLE "
|
||||
fi
|
||||
|
||||
if _contains "$(curl --help 2>&1)" "--globoff"; then
|
||||
if _contains "$(curl --help 2>&1)" "--globoff" || _contains "$(curl --help curl 2>&1)" "--globoff"; then
|
||||
_ACME_CURL="$_ACME_CURL -g "
|
||||
fi
|
||||
|
||||
#don't use --fail-with-body
|
||||
##from curl 7.76: return fail on HTTP errors but keep the body
|
||||
#if _contains "$(curl --help http 2>&1)" "--fail-with-body"; then
|
||||
# _ACME_CURL="$_ACME_CURL --fail-with-body "
|
||||
#fi
|
||||
fi
|
||||
|
||||
if [ -z "$_ACME_WGET" ] && _exists "wget"; then
|
||||
@@ -1872,11 +1878,11 @@ _inithttp() {
|
||||
elif [ "$CA_BUNDLE" ]; then
|
||||
_ACME_WGET="$_ACME_WGET --ca-certificate=$CA_BUNDLE "
|
||||
fi
|
||||
fi
|
||||
|
||||
#from wget 1.14: do not skip body on 404 error
|
||||
if [ "$_ACME_WGET" ] && _contains "$($_ACME_WGET --help 2>&1)" "--content-on-error"; then
|
||||
_ACME_WGET="$_ACME_WGET --content-on-error "
|
||||
#from wget 1.14: do not skip body on 404 error
|
||||
if _contains "$(wget --help 2>&1)" "--content-on-error"; then
|
||||
_ACME_WGET="$_ACME_WGET --content-on-error "
|
||||
fi
|
||||
fi
|
||||
|
||||
__HTTP_INITIALIZED=1
|
||||
@@ -2058,7 +2064,7 @@ _get() {
|
||||
fi
|
||||
_debug "_WGET" "$_WGET"
|
||||
if [ "$onlyheader" ]; then
|
||||
_wget_out = "$($_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -S -O /dev/null "$url" 2>&1)"
|
||||
_wget_out="$($_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -S -O /dev/null "$url" 2>&1)"
|
||||
if _contains "$_WGET" " -d "; then
|
||||
# Demultiplex wget debug output
|
||||
echo "$_wget_out" >&2
|
||||
@@ -2223,6 +2229,20 @@ _send_signed_request() {
|
||||
_debug3 _body "$_body"
|
||||
fi
|
||||
|
||||
_retryafter=$(echo "$responseHeaders" | grep -i "^Retry-After *: *[0-9]\+ *" | cut -d : -f 2 | tr -d ' ' | tr -d '\r')
|
||||
if [ "$code" = '503' ]; then
|
||||
_sleep_overload_retry_sec=$_retryafter
|
||||
if [ -z "$_sleep_overload_retry_sec" ]; then
|
||||
_sleep_overload_retry_sec=5
|
||||
fi
|
||||
if [ $_sleep_overload_retry_sec -le 600 ]; then
|
||||
_info "It seems the CA server is currently overloaded, let's wait and retry. Sleeping $_sleep_overload_retry_sec seconds."
|
||||
_sleep $_sleep_overload_retry_sec
|
||||
continue
|
||||
else
|
||||
_info "The retryafter=$_retryafter is too large > 600, not retry anymore."
|
||||
fi
|
||||
fi
|
||||
if _contains "$_body" "JWS has invalid anti-replay nonce" || _contains "$_body" "JWS has an invalid anti-replay nonce"; then
|
||||
_info "It seems the CA server is busy now, let's wait and retry. Sleeping $_sleep_retry_sec seconds."
|
||||
_CACHED_NONCE=""
|
||||
@@ -2352,6 +2372,26 @@ _readdomainconf() {
|
||||
_read_conf "$DOMAIN_CONF" "$1"
|
||||
}
|
||||
|
||||
#_migratedomainconf oldkey newkey base64encode
|
||||
_migratedomainconf() {
|
||||
_old_key="$1"
|
||||
_new_key="$2"
|
||||
_b64encode="$3"
|
||||
_value=$(_readdomainconf "$_old_key")
|
||||
if [ -z "$_value" ]; then
|
||||
return 1 # oldkey is not found
|
||||
fi
|
||||
_savedomainconf "$_new_key" "$_value" "$_b64encode"
|
||||
_cleardomainconf "$_old_key"
|
||||
_debug "Domain config $_old_key has been migrated to $_new_key"
|
||||
}
|
||||
|
||||
#_migratedeployconf oldkey newkey base64encode
|
||||
_migratedeployconf() {
|
||||
_migratedomainconf "$1" "SAVED_$2" "$3" ||
|
||||
_migratedomainconf "SAVED_$1" "SAVED_$2" "$3" # try only when oldkey itself is not found
|
||||
}
|
||||
|
||||
#key value base64encode
|
||||
_savedeployconf() {
|
||||
_savedomainconf "SAVED_$1" "$2" "$3"
|
||||
@@ -2366,12 +2406,14 @@ _getdeployconf() {
|
||||
if [ "$_rac_value" ]; then
|
||||
if _startswith "$_rac_value" '"' && _endswith "$_rac_value" '"'; then
|
||||
_debug2 "trim quotation marks"
|
||||
eval "export $_rac_key=$_rac_value"
|
||||
eval $_rac_key=$_rac_value
|
||||
export $_rac_key
|
||||
fi
|
||||
return 0 # do nothing
|
||||
fi
|
||||
_saved=$(_readdomainconf "SAVED_$_rac_key")
|
||||
eval "export $_rac_key=\"\$_saved\""
|
||||
_saved="$(_readdomainconf "SAVED_$_rac_key")"
|
||||
eval $_rac_key=\$_saved
|
||||
export $_rac_key
|
||||
}
|
||||
|
||||
#_saveaccountconf key value base64encode
|
||||
@@ -2835,12 +2877,14 @@ _initpath() {
|
||||
|
||||
if _isEccKey "$_ilength"; then
|
||||
DOMAIN_PATH="$domainhomeecc"
|
||||
else
|
||||
elif [ -z "$__SELECTED_RSA_KEY" ]; then
|
||||
if [ ! -d "$domainhome" ] && [ -d "$domainhomeecc" ]; then
|
||||
_info "The domain '$domain' seems to have a ECC cert already, please add '$(__red "--ecc")' parameter if you want to use that cert."
|
||||
_info "The domain '$domain' seems to have a ECC cert already, lets use ecc cert."
|
||||
DOMAIN_PATH="$domainhomeecc"
|
||||
fi
|
||||
fi
|
||||
_debug DOMAIN_PATH "$DOMAIN_PATH"
|
||||
export DOMAIN_PATH
|
||||
fi
|
||||
|
||||
if [ -z "$DOMAIN_BACKUP_PATH" ]; then
|
||||
@@ -2892,22 +2936,6 @@ _initpath() {
|
||||
|
||||
}
|
||||
|
||||
_exec() {
|
||||
if [ -z "$_EXEC_TEMP_ERR" ]; then
|
||||
_EXEC_TEMP_ERR="$(_mktemp)"
|
||||
fi
|
||||
|
||||
if [ "$_EXEC_TEMP_ERR" ]; then
|
||||
eval "$@ 2>>$_EXEC_TEMP_ERR"
|
||||
else
|
||||
eval "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
_exec_err() {
|
||||
[ "$_EXEC_TEMP_ERR" ] && _err "$(cat "$_EXEC_TEMP_ERR")" && echo "" >"$_EXEC_TEMP_ERR"
|
||||
}
|
||||
|
||||
_apachePath() {
|
||||
_APACHECTL="apachectl"
|
||||
if ! _exists apachectl; then
|
||||
@@ -2920,8 +2948,7 @@ _apachePath() {
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! _exec $_APACHECTL -V >/dev/null; then
|
||||
_exec_err
|
||||
if ! $_APACHECTL -V >/dev/null; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
@@ -2973,8 +3000,7 @@ _restoreApache() {
|
||||
|
||||
cat "$APACHE_CONF_BACKUP_DIR/$httpdconfname" >"$httpdconf"
|
||||
_debug "Restored: $httpdconf."
|
||||
if ! _exec $_APACHECTL -t; then
|
||||
_exec_err
|
||||
if ! $_APACHECTL -t; then
|
||||
_err "Sorry, restore apache config error, please contact me."
|
||||
return 1
|
||||
fi
|
||||
@@ -2992,8 +3018,7 @@ _setApache() {
|
||||
#test the conf first
|
||||
_info "Checking if there is an error in the apache config file before starting."
|
||||
|
||||
if ! _exec "$_APACHECTL" -t >/dev/null; then
|
||||
_exec_err
|
||||
if ! $_APACHECTL -t >/dev/null; then
|
||||
_err "The apache config file has error, please fix it first, then try again."
|
||||
_err "Don't worry, there is nothing changed to your system."
|
||||
return 1
|
||||
@@ -3054,8 +3079,7 @@ Allow from all
|
||||
chmod 755 "$ACME_DIR"
|
||||
fi
|
||||
|
||||
if ! _exec "$_APACHECTL" graceful; then
|
||||
_exec_err
|
||||
if ! $_APACHECTL graceful; then
|
||||
_err "$_APACHECTL graceful error, please contact me."
|
||||
_restoreApache
|
||||
return 1
|
||||
@@ -3140,8 +3164,7 @@ _setNginx() {
|
||||
return 1
|
||||
fi
|
||||
_info "Check the nginx conf before setting up."
|
||||
if ! _exec "nginx -t" >/dev/null; then
|
||||
_exec_err
|
||||
if ! nginx -t >/dev/null; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
@@ -3168,16 +3191,14 @@ location ~ \"^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)\$\" {
|
||||
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
|
||||
if ! nginx -t >/dev/null; then
|
||||
_err "It seems that nginx conf was broken, let's restore."
|
||||
cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Reload nginx"
|
||||
if ! _exec "nginx -s reload" >/dev/null; then
|
||||
_exec_err
|
||||
if ! nginx -s reload >/dev/null; then
|
||||
_err "It seems that nginx reload error, let's restore."
|
||||
cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF"
|
||||
return 1
|
||||
@@ -3302,8 +3323,7 @@ _restoreNginx() {
|
||||
done
|
||||
|
||||
_info "Reload nginx"
|
||||
if ! _exec "nginx -s reload" >/dev/null; then
|
||||
_exec_err
|
||||
if ! nginx -s reload >/dev/null; then
|
||||
_err "It seems that nginx reload error, please report bug."
|
||||
return 1
|
||||
fi
|
||||
@@ -3995,7 +4015,7 @@ _ns_purge_cf() {
|
||||
|
||||
#checks if cf server is available
|
||||
_ns_is_available_cf() {
|
||||
if _get "https://cloudflare-dns.com" "" 1 >/dev/null 2>&1; then
|
||||
if _get "https://cloudflare-dns.com" "" 10 >/dev/null; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
@@ -4003,7 +4023,7 @@ _ns_is_available_cf() {
|
||||
}
|
||||
|
||||
_ns_is_available_google() {
|
||||
if _get "https://dns.google" "" 1 >/dev/null 2>&1; then
|
||||
if _get "https://dns.google" "" 10 >/dev/null; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
@@ -4019,7 +4039,7 @@ _ns_lookup_google() {
|
||||
}
|
||||
|
||||
_ns_is_available_ali() {
|
||||
if _get "https://dns.alidns.com" "" 1 >/dev/null 2>&1; then
|
||||
if _get "https://dns.alidns.com" "" 10 >/dev/null; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
@@ -4035,7 +4055,7 @@ _ns_lookup_ali() {
|
||||
}
|
||||
|
||||
_ns_is_available_dp() {
|
||||
if _get "https://doh.pub" "" 1 >/dev/null 2>&1; then
|
||||
if _get "https://doh.pub" "" 10 >/dev/null; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
@@ -4641,28 +4661,26 @@ $_authorizations_map"
|
||||
thumbprint="$(__calc_account_thumbprint)"
|
||||
fi
|
||||
|
||||
keyauthorization=""
|
||||
|
||||
if echo "$response" | grep '"status":"valid"' >/dev/null 2>&1; then
|
||||
_debug "$d is already valid."
|
||||
keyauthorization="$STATE_VERIFIED"
|
||||
_debug keyauthorization "$keyauthorization"
|
||||
fi
|
||||
|
||||
entry="$(echo "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')"
|
||||
_debug entry "$entry"
|
||||
keyauthorization=""
|
||||
if [ -z "$entry" ]; then
|
||||
if ! _startswith "$d" '*.'; then
|
||||
_debug "Not a wildcard domain, lets check whether the validation is already valid."
|
||||
if echo "$response" | grep '"status":"valid"' >/dev/null 2>&1; then
|
||||
_debug "$d is already valid."
|
||||
keyauthorization="$STATE_VERIFIED"
|
||||
_debug keyauthorization "$keyauthorization"
|
||||
fi
|
||||
fi
|
||||
if [ -z "$keyauthorization" ]; then
|
||||
_err "Error, can not get domain token entry $d for $vtype"
|
||||
_supported_vtypes="$(echo "$response" | _egrep_o "\"challenges\":\[[^]]*]" | tr '{' "\n" | grep type | cut -d '"' -f 4 | tr "\n" ' ')"
|
||||
if [ "$_supported_vtypes" ]; then
|
||||
_err "The supported validation types are: $_supported_vtypes, but you specified: $vtype"
|
||||
fi
|
||||
_clearup
|
||||
_on_issue_err "$_post_hook"
|
||||
return 1
|
||||
|
||||
if [ -z "$keyauthorization" -a -z "$entry" ]; then
|
||||
_err "Error, can not get domain token entry $d for $vtype"
|
||||
_supported_vtypes="$(echo "$response" | _egrep_o "\"challenges\":\[[^]]*]" | tr '{' "\n" | grep type | cut -d '"' -f 4 | tr "\n" ' ')"
|
||||
if [ "$_supported_vtypes" ]; then
|
||||
_err "The supported validation types are: $_supported_vtypes, but you specified: $vtype"
|
||||
fi
|
||||
_clearup
|
||||
_on_issue_err "$_post_hook"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$keyauthorization" ]; then
|
||||
@@ -4688,12 +4706,6 @@ $_authorizations_map"
|
||||
fi
|
||||
keyauthorization="$token.$thumbprint"
|
||||
_debug keyauthorization "$keyauthorization"
|
||||
|
||||
if printf "%s" "$response" | grep '"status":"valid"' >/dev/null 2>&1; then
|
||||
_debug "$d is already verified."
|
||||
keyauthorization="$STATE_VERIFIED"
|
||||
_debug keyauthorization "$keyauthorization"
|
||||
fi
|
||||
fi
|
||||
|
||||
dvlist="$d$sep$keyauthorization$sep$uri$sep$vtype$sep$_currentRoot"
|
||||
@@ -4917,18 +4929,6 @@ $_authorizations_map"
|
||||
if ! chmod a+r "$wellknown_path/$token"; then
|
||||
_debug "chmod failed, but we just continue."
|
||||
fi
|
||||
if [ ! "$usingApache" ]; then
|
||||
if webroot_owner=$(_stat "$_currentRoot"); then
|
||||
_debug "Changing owner/group of .well-known to $webroot_owner"
|
||||
if ! _exec "chown -R \"$webroot_owner\" \"$_currentRoot/.well-known\""; then
|
||||
_debug "$(cat "$_EXEC_TEMP_ERR")"
|
||||
_exec_err >/dev/null 2>&1
|
||||
fi
|
||||
else
|
||||
_debug "not changing owner/group of webroot"
|
||||
fi
|
||||
fi
|
||||
|
||||
fi
|
||||
elif [ "$vtype" = "$VTYPE_ALPN" ]; then
|
||||
acmevalidationv1="$(printf "%s" "$keyauthorization" | _digest "sha256" "hex")"
|
||||
@@ -5743,6 +5743,7 @@ deploy() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 DOMAIN_CONF "$DOMAIN_CONF"
|
||||
. "$DOMAIN_CONF"
|
||||
|
||||
_savedomainconf Le_DeployHook "$_hooks"
|
||||
@@ -6102,8 +6103,22 @@ revoke() {
|
||||
|
||||
uri="${ACME_REVOKE_CERT}"
|
||||
|
||||
_info "Try account key first."
|
||||
if _send_signed_request "$uri" "$data" "" "$ACCOUNT_KEY_PATH"; then
|
||||
if [ -z "$response" ]; then
|
||||
_info "Revoke success."
|
||||
rm -f "$CERT_PATH"
|
||||
cat "$CERT_KEY_PATH" >"$CERT_KEY_PATH.revoked"
|
||||
cat "$CSR_PATH" >"$CSR_PATH.revoked"
|
||||
return 0
|
||||
else
|
||||
_err "Revoke error."
|
||||
_debug "$response"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -f "$CERT_KEY_PATH" ]; then
|
||||
_info "Try domain key first."
|
||||
_info "Try domain key."
|
||||
if _send_signed_request "$uri" "$data" "" "$CERT_KEY_PATH"; then
|
||||
if [ -z "$response" ]; then
|
||||
_info "Revoke success."
|
||||
@@ -6119,21 +6134,6 @@ revoke() {
|
||||
else
|
||||
_info "Domain key file doesn't exist."
|
||||
fi
|
||||
|
||||
_info "Try account key."
|
||||
|
||||
if _send_signed_request "$uri" "$data" "" "$ACCOUNT_KEY_PATH"; then
|
||||
if [ -z "$response" ]; then
|
||||
_info "Revoke success."
|
||||
rm -f "$CERT_PATH"
|
||||
cat "$CERT_KEY_PATH" >"$CERT_KEY_PATH.revoked"
|
||||
cat "$CSR_PATH" >"$CSR_PATH.revoked"
|
||||
return 0
|
||||
else
|
||||
_err "Revoke error."
|
||||
_debug "$response"
|
||||
fi
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
@@ -6707,6 +6707,13 @@ _send_notify() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
_nsource="$NOTIFY_SOURCE"
|
||||
if [ -z "$_nsource" ]; then
|
||||
_nsource="$(hostname)"
|
||||
fi
|
||||
|
||||
_nsubject="$_nsubject by $_nsource"
|
||||
|
||||
_send_err=0
|
||||
for _n_hook in $(echo "$_nhooks" | tr ',' " "); do
|
||||
_n_hook_file="$(_findHook "" $_SUB_FOLDER_NOTIFY "$_n_hook")"
|
||||
@@ -6761,11 +6768,12 @@ setnotify() {
|
||||
_nhook="$1"
|
||||
_nlevel="$2"
|
||||
_nmode="$3"
|
||||
_nsource="$4"
|
||||
|
||||
_initpath
|
||||
|
||||
if [ -z "$_nhook$_nlevel$_nmode" ]; then
|
||||
_usage "Usage: $PROJECT_ENTRY --set-notify [--notify-hook <hookname>] [--notify-level <0|1|2|3>] [--notify-mode <0|1>]"
|
||||
if [ -z "$_nhook$_nlevel$_nmode$_nsource" ]; then
|
||||
_usage "Usage: $PROJECT_ENTRY --set-notify [--notify-hook <hookname>] [--notify-level <0|1|2|3>] [--notify-mode <0|1>] [--notify-source <hostname>]"
|
||||
_usage "$_NOTIFY_WIKI"
|
||||
return 1
|
||||
fi
|
||||
@@ -6782,6 +6790,12 @@ setnotify() {
|
||||
_saveaccountconf "NOTIFY_MODE" "$NOTIFY_MODE"
|
||||
fi
|
||||
|
||||
if [ "$_nsource" ]; then
|
||||
_info "Set notify source to: $_nsource"
|
||||
export "NOTIFY_SOURCE=$_nsource"
|
||||
_saveaccountconf "NOTIFY_SOURCE" "$NOTIFY_SOURCE"
|
||||
fi
|
||||
|
||||
if [ "$_nhook" ]; then
|
||||
_info "Set notify hook to: $_nhook"
|
||||
if [ "$_nhook" = "$NO_VALUE" ]; then
|
||||
@@ -6942,6 +6956,7 @@ Parameters:
|
||||
0: Bulk mode. Send all the domain's notifications in one message(mail).
|
||||
1: Cert mode. Send a message for every single cert.
|
||||
--notify-hook <hookname> Set the notify hook
|
||||
--notify-source <server name> Set the server name in the notification message
|
||||
--revoke-reason <0-10> The reason for revocation, can be used in conjunction with the '--revoke' command.
|
||||
See: $_REVOKE_WIKI
|
||||
|
||||
@@ -7099,7 +7114,9 @@ _selectServer() {
|
||||
_getCAShortName() {
|
||||
caurl="$1"
|
||||
if [ -z "$caurl" ]; then
|
||||
caurl="$DEFAULT_CA"
|
||||
#use letsencrypt as default value if the Le_API is empty
|
||||
#this case can only come from the old upgrading.
|
||||
caurl="$CA_LETSENCRYPT_V2"
|
||||
fi
|
||||
if [ "$CA_SSLCOM_ECC" = "$caurl" ]; then
|
||||
caurl="$CA_SSLCOM_RSA" #just hack to get the short name
|
||||
@@ -7216,6 +7233,7 @@ _process() {
|
||||
_notify_hook=""
|
||||
_notify_level=""
|
||||
_notify_mode=""
|
||||
_notify_source=""
|
||||
_revoke_reason=""
|
||||
_eab_kid=""
|
||||
_eab_hmac_key=""
|
||||
@@ -7461,6 +7479,9 @@ _process() {
|
||||
--keylength | -k)
|
||||
_keylength="$2"
|
||||
shift
|
||||
if [ "$_keylength" ] && ! _isEccKey "$_keylength"; then
|
||||
export __SELECTED_RSA_KEY=1
|
||||
fi
|
||||
;;
|
||||
-ak | --accountkeylength)
|
||||
_accountkeylength="$2"
|
||||
@@ -7496,7 +7517,7 @@ _process() {
|
||||
shift
|
||||
;;
|
||||
--home)
|
||||
export LE_WORKING_DIR="$2"
|
||||
export LE_WORKING_DIR="$(echo "$2" | sed 's|/$||')"
|
||||
shift
|
||||
;;
|
||||
--cert-home | --certhome)
|
||||
@@ -7708,6 +7729,15 @@ _process() {
|
||||
_notify_mode="$_nmode"
|
||||
shift
|
||||
;;
|
||||
--notify-source)
|
||||
_nsource="$2"
|
||||
if _startswith "$_nsource" "-"; then
|
||||
_err "'$_nsource' is not valid host name for '$1'"
|
||||
return 1
|
||||
fi
|
||||
_notify_source="$_nsource"
|
||||
shift
|
||||
;;
|
||||
--revoke-reason)
|
||||
_revoke_reason="$2"
|
||||
if _startswith "$_revoke_reason" "-"; then
|
||||
@@ -7862,7 +7892,7 @@ _process() {
|
||||
createCSR "$_domain" "$_altdomains" "$_ecc"
|
||||
;;
|
||||
setnotify)
|
||||
setnotify "$_notify_hook" "$_notify_level" "$_notify_mode"
|
||||
setnotify "$_notify_hook" "$_notify_level" "$_notify_mode" "$_notify_source"
|
||||
;;
|
||||
setdefaultca)
|
||||
setdefaultca
|
||||
|
||||
@@ -273,16 +273,27 @@ _check_curl_version() {
|
||||
_minor="$(_getfield "$_cversion" 2 '.')"
|
||||
_debug2 "_minor" "$_minor"
|
||||
|
||||
if [ "$_major$_minor" -lt "740" ]; then
|
||||
if [ "$_major" -ge "8" ]; then
|
||||
#ok
|
||||
return 0
|
||||
fi
|
||||
if [ "$_major" = "7" ]; then
|
||||
if [ "$_minor" -lt "40" ]; then
|
||||
_err "curl v$_cversion doesn't support unit socket"
|
||||
_err "Please upgrade to curl 7.40 or later."
|
||||
return 1
|
||||
fi
|
||||
if [ "$_minor" -lt "50" ]; then
|
||||
_debug "Use short host name"
|
||||
export _CURL_NO_HOST=1
|
||||
else
|
||||
export _CURL_NO_HOST=
|
||||
fi
|
||||
return 0
|
||||
else
|
||||
_err "curl v$_cversion doesn't support unit socket"
|
||||
_err "Please upgrade to curl 7.40 or later."
|
||||
return 1
|
||||
fi
|
||||
if [ "$_major$_minor" -lt "750" ]; then
|
||||
_debug "Use short host name"
|
||||
export _CURL_NO_HOST=1
|
||||
else
|
||||
export _CURL_NO_HOST=
|
||||
fi
|
||||
return 0
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Here is the script to deploy the cert to G-Core CDN service (https://gcorelabs.com/ru/) using the G-Core Labs API (https://docs.gcorelabs.com/cdn/).
|
||||
# Here is the script to deploy the cert to G-Core CDN service (https://gcore.com/) using the G-Core Labs API (https://apidocs.gcore.com/cdn).
|
||||
# Returns 0 when success.
|
||||
#
|
||||
# Written by temoffey <temofffey@gmail.com>
|
||||
# Public domain, 2019
|
||||
# Update by DreamOfIce <admin@dreamofice.cn> in 2023
|
||||
|
||||
#export DEPLOY_GCORE_CDN_USERNAME=myusername
|
||||
#export DEPLOY_GCORE_CDN_PASSWORD=mypassword
|
||||
@@ -56,7 +57,7 @@ gcore_cdn_deploy() {
|
||||
_request="{\"username\":\"$Le_Deploy_gcore_cdn_username\",\"password\":\"$Le_Deploy_gcore_cdn_password\"}"
|
||||
_debug _request "$_request"
|
||||
export _H1="Content-Type:application/json"
|
||||
_response=$(_post "$_request" "https://api.gcdn.co/auth/jwt/login")
|
||||
_response=$(_post "$_request" "https://api.gcore.com/auth/jwt/login")
|
||||
_debug _response "$_response"
|
||||
_regex=".*\"access\":\"\([-._0-9A-Za-z]*\)\".*$"
|
||||
_debug _regex "$_regex"
|
||||
@@ -69,8 +70,8 @@ gcore_cdn_deploy() {
|
||||
fi
|
||||
|
||||
_info "Find CDN resource with cname $_cdomain"
|
||||
export _H2="Authorization:Token $_token"
|
||||
_response=$(_get "https://api.gcdn.co/resources")
|
||||
export _H2="Authorization:Bearer $_token"
|
||||
_response=$(_get "https://api.gcore.com/cdn/resources")
|
||||
_debug _response "$_response"
|
||||
_regex="\"primary_resource\":null},"
|
||||
_debug _regex "$_regex"
|
||||
@@ -102,7 +103,7 @@ gcore_cdn_deploy() {
|
||||
_date=$(date "+%d.%m.%Y %H:%M:%S")
|
||||
_request="{\"name\":\"$_cdomain ($_date)\",\"sslCertificate\":\"$_fullchain\",\"sslPrivateKey\":\"$_key\"}"
|
||||
_debug _request "$_request"
|
||||
_response=$(_post "$_request" "https://api.gcdn.co/sslData")
|
||||
_response=$(_post "$_request" "https://api.gcore.com/cdn/sslData")
|
||||
_debug _response "$_response"
|
||||
_regex=".*\"id\":\([0-9]*\).*$"
|
||||
_debug _regex "$_regex"
|
||||
@@ -117,7 +118,7 @@ gcore_cdn_deploy() {
|
||||
_info "Update CDN resource"
|
||||
_request="{\"originGroup\":$_originGroup,\"sslData\":$_sslDataAdd}"
|
||||
_debug _request "$_request"
|
||||
_response=$(_post "$_request" "https://api.gcdn.co/resources/$_resourceId" '' "PUT")
|
||||
_response=$(_post "$_request" "https://api.gcore.com/cdn/resources/$_resourceId" '' "PUT")
|
||||
_debug _response "$_response"
|
||||
_regex=".*\"sslData\":\([0-9]*\).*$"
|
||||
_debug _regex "$_regex"
|
||||
@@ -133,7 +134,7 @@ gcore_cdn_deploy() {
|
||||
_info "Not found old SSL certificate"
|
||||
else
|
||||
_info "Delete old SSL certificate"
|
||||
_response=$(_post '' "https://api.gcdn.co/sslData/$_sslDataOld" '' "DELETE")
|
||||
_response=$(_post '' "https://api.gcore.com/cdn/sslData/$_sslDataOld" '' "DELETE")
|
||||
_debug _response "$_response"
|
||||
fi
|
||||
|
||||
|
||||
409
deploy/ssh.sh
409
deploy/ssh.sh
@@ -14,7 +14,7 @@
|
||||
# The following examples are for QNAP NAS running QTS 4.2
|
||||
# export DEPLOY_SSH_CMD="" # defaults to "ssh -T"
|
||||
# export DEPLOY_SSH_USER="admin" # required
|
||||
# export DEPLOY_SSH_SERVER="qnap" # defaults to domain name
|
||||
# export DEPLOY_SSH_SERVER="host1 host2:8022 192.168.0.1:9022" # defaults to domain name, support multiple servers with optional port
|
||||
# export DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem"
|
||||
# export DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem"
|
||||
# export DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem"
|
||||
@@ -23,6 +23,8 @@
|
||||
# export DEPLOY_SSH_BACKUP="" # yes or no, default to yes or previously saved value
|
||||
# export DEPLOY_SSH_BACKUP_PATH=".acme_ssh_deploy" # path on remote system. Defaults to .acme_ssh_deploy
|
||||
# export DEPLOY_SSH_MULTI_CALL="" # yes or no, default to no or previously saved value
|
||||
# export DEPLOY_SSH_USE_SCP="" yes or no, default to no
|
||||
# export DEPLOY_SSH_SCP_CMD="" defaults to "scp -q"
|
||||
#
|
||||
######## Public functions #####################
|
||||
|
||||
@@ -42,72 +44,134 @@ ssh_deploy() {
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
# USER is required to login by SSH to remote host.
|
||||
_migratedeployconf Le_Deploy_ssh_user DEPLOY_SSH_USER
|
||||
_getdeployconf DEPLOY_SSH_USER
|
||||
_debug2 DEPLOY_SSH_USER "$DEPLOY_SSH_USER"
|
||||
if [ -z "$DEPLOY_SSH_USER" ]; then
|
||||
if [ -z "$Le_Deploy_ssh_user" ]; then
|
||||
_err "DEPLOY_SSH_USER not defined."
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
Le_Deploy_ssh_user="$DEPLOY_SSH_USER"
|
||||
_savedomainconf Le_Deploy_ssh_user "$Le_Deploy_ssh_user"
|
||||
_err "DEPLOY_SSH_USER not defined."
|
||||
return 1
|
||||
fi
|
||||
_savedeployconf DEPLOY_SSH_USER "$DEPLOY_SSH_USER"
|
||||
|
||||
# SERVER is optional. If not provided then use _cdomain
|
||||
_migratedeployconf Le_Deploy_ssh_server DEPLOY_SSH_SERVER
|
||||
_getdeployconf DEPLOY_SSH_SERVER
|
||||
_debug2 DEPLOY_SSH_SERVER "$DEPLOY_SSH_SERVER"
|
||||
if [ -n "$DEPLOY_SSH_SERVER" ]; then
|
||||
Le_Deploy_ssh_server="$DEPLOY_SSH_SERVER"
|
||||
_savedomainconf Le_Deploy_ssh_server "$Le_Deploy_ssh_server"
|
||||
elif [ -z "$Le_Deploy_ssh_server" ]; then
|
||||
Le_Deploy_ssh_server="$_cdomain"
|
||||
if [ -z "$DEPLOY_SSH_SERVER" ]; then
|
||||
DEPLOY_SSH_SERVER="$_cdomain"
|
||||
fi
|
||||
_savedeployconf DEPLOY_SSH_SERVER "$DEPLOY_SSH_SERVER"
|
||||
|
||||
# CMD is optional. If not provided then use ssh
|
||||
_migratedeployconf Le_Deploy_ssh_cmd DEPLOY_SSH_CMD
|
||||
_getdeployconf DEPLOY_SSH_CMD
|
||||
_debug2 DEPLOY_SSH_CMD "$DEPLOY_SSH_CMD"
|
||||
if [ -n "$DEPLOY_SSH_CMD" ]; then
|
||||
Le_Deploy_ssh_cmd="$DEPLOY_SSH_CMD"
|
||||
_savedomainconf Le_Deploy_ssh_cmd "$Le_Deploy_ssh_cmd"
|
||||
elif [ -z "$Le_Deploy_ssh_cmd" ]; then
|
||||
Le_Deploy_ssh_cmd="ssh -T"
|
||||
if [ -z "$DEPLOY_SSH_CMD" ]; then
|
||||
DEPLOY_SSH_CMD="ssh -T"
|
||||
fi
|
||||
_savedeployconf DEPLOY_SSH_CMD "$DEPLOY_SSH_CMD"
|
||||
|
||||
# BACKUP is optional. If not provided then default to previously saved value or yes.
|
||||
_migratedeployconf Le_Deploy_ssh_backup DEPLOY_SSH_BACKUP
|
||||
_getdeployconf DEPLOY_SSH_BACKUP
|
||||
_debug2 DEPLOY_SSH_BACKUP "$DEPLOY_SSH_BACKUP"
|
||||
if [ "$DEPLOY_SSH_BACKUP" = "no" ]; then
|
||||
Le_Deploy_ssh_backup="no"
|
||||
elif [ -z "$Le_Deploy_ssh_backup" ] || [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
||||
Le_Deploy_ssh_backup="yes"
|
||||
if [ -z "$DEPLOY_SSH_BACKUP" ]; then
|
||||
DEPLOY_SSH_BACKUP="yes"
|
||||
fi
|
||||
_savedomainconf Le_Deploy_ssh_backup "$Le_Deploy_ssh_backup"
|
||||
_savedeployconf DEPLOY_SSH_BACKUP "$DEPLOY_SSH_BACKUP"
|
||||
|
||||
# BACKUP_PATH is optional. If not provided then default to previously saved value or .acme_ssh_deploy
|
||||
_migratedeployconf Le_Deploy_ssh_backup_path DEPLOY_SSH_BACKUP_PATH
|
||||
_getdeployconf DEPLOY_SSH_BACKUP_PATH
|
||||
_debug2 DEPLOY_SSH_BACKUP_PATH "$DEPLOY_SSH_BACKUP_PATH"
|
||||
if [ -n "$DEPLOY_SSH_BACKUP_PATH" ]; then
|
||||
Le_Deploy_ssh_backup_path="$DEPLOY_SSH_BACKUP_PATH"
|
||||
elif [ -z "$Le_Deploy_ssh_backup_path" ]; then
|
||||
Le_Deploy_ssh_backup_path=".acme_ssh_deploy"
|
||||
if [ -z "$DEPLOY_SSH_BACKUP_PATH" ]; then
|
||||
DEPLOY_SSH_BACKUP_PATH=".acme_ssh_deploy"
|
||||
fi
|
||||
_savedomainconf Le_Deploy_ssh_backup_path "$Le_Deploy_ssh_backup_path"
|
||||
_savedeployconf DEPLOY_SSH_BACKUP_PATH "$DEPLOY_SSH_BACKUP_PATH"
|
||||
|
||||
# MULTI_CALL is optional. If not provided then default to previously saved
|
||||
# value (which may be undefined... equivalent to "no").
|
||||
_migratedeployconf Le_Deploy_ssh_multi_call DEPLOY_SSH_MULTI_CALL
|
||||
_getdeployconf DEPLOY_SSH_MULTI_CALL
|
||||
_debug2 DEPLOY_SSH_MULTI_CALL "$DEPLOY_SSH_MULTI_CALL"
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
Le_Deploy_ssh_multi_call="yes"
|
||||
_savedomainconf Le_Deploy_ssh_multi_call "$Le_Deploy_ssh_multi_call"
|
||||
elif [ "$DEPLOY_SSH_MULTI_CALL" = "no" ]; then
|
||||
Le_Deploy_ssh_multi_call=""
|
||||
_cleardomainconf Le_Deploy_ssh_multi_call
|
||||
if [ -z "$DEPLOY_SSH_MULTI_CALL" ]; then
|
||||
DEPLOY_SSH_MULTI_CALL="no"
|
||||
fi
|
||||
_savedeployconf DEPLOY_SSH_MULTI_CALL "$DEPLOY_SSH_MULTI_CALL"
|
||||
|
||||
# KEYFILE is optional.
|
||||
# If provided then private key will be copied to provided filename.
|
||||
_migratedeployconf Le_Deploy_ssh_keyfile DEPLOY_SSH_KEYFILE
|
||||
_getdeployconf DEPLOY_SSH_KEYFILE
|
||||
_debug2 DEPLOY_SSH_KEYFILE "$DEPLOY_SSH_KEYFILE"
|
||||
if [ -n "$DEPLOY_SSH_KEYFILE" ]; then
|
||||
_savedeployconf DEPLOY_SSH_KEYFILE "$DEPLOY_SSH_KEYFILE"
|
||||
fi
|
||||
|
||||
_deploy_ssh_servers=$Le_Deploy_ssh_server
|
||||
for Le_Deploy_ssh_server in $_deploy_ssh_servers; do
|
||||
# CERTFILE is optional.
|
||||
# If provided then certificate will be copied or appended to provided filename.
|
||||
_migratedeployconf Le_Deploy_ssh_certfile DEPLOY_SSH_CERTFILE
|
||||
_getdeployconf DEPLOY_SSH_CERTFILE
|
||||
_debug2 DEPLOY_SSH_CERTFILE "$DEPLOY_SSH_CERTFILE"
|
||||
if [ -n "$DEPLOY_SSH_CERTFILE" ]; then
|
||||
_savedeployconf DEPLOY_SSH_CERTFILE "$DEPLOY_SSH_CERTFILE"
|
||||
fi
|
||||
|
||||
# CAFILE is optional.
|
||||
# If provided then CA intermediate certificate will be copied or appended to provided filename.
|
||||
_migratedeployconf Le_Deploy_ssh_cafile DEPLOY_SSH_CAFILE
|
||||
_getdeployconf DEPLOY_SSH_CAFILE
|
||||
_debug2 DEPLOY_SSH_CAFILE "$DEPLOY_SSH_CAFILE"
|
||||
if [ -n "$DEPLOY_SSH_CAFILE" ]; then
|
||||
_savedeployconf DEPLOY_SSH_CAFILE "$DEPLOY_SSH_CAFILE"
|
||||
fi
|
||||
|
||||
# FULLCHAIN is optional.
|
||||
# If provided then fullchain certificate will be copied or appended to provided filename.
|
||||
_migratedeployconf Le_Deploy_ssh_fullchain DEPLOY_SSH_FULLCHAIN
|
||||
_getdeployconf DEPLOY_SSH_FULLCHAIN
|
||||
_debug2 DEPLOY_SSH_FULLCHAIN "$DEPLOY_SSH_FULLCHAIN"
|
||||
if [ -n "$DEPLOY_SSH_FULLCHAIN" ]; then
|
||||
_savedeployconf DEPLOY_SSH_FULLCHAIN "$DEPLOY_SSH_FULLCHAIN"
|
||||
fi
|
||||
|
||||
# REMOTE_CMD is optional.
|
||||
# If provided then this command will be executed on remote host.
|
||||
_migratedeployconf Le_Deploy_ssh_remote_cmd DEPLOY_SSH_REMOTE_CMD
|
||||
_getdeployconf DEPLOY_SSH_REMOTE_CMD
|
||||
_debug2 DEPLOY_SSH_REMOTE_CMD "$DEPLOY_SSH_REMOTE_CMD"
|
||||
if [ -n "$DEPLOY_SSH_REMOTE_CMD" ]; then
|
||||
_savedeployconf DEPLOY_SSH_REMOTE_CMD "$DEPLOY_SSH_REMOTE_CMD"
|
||||
fi
|
||||
|
||||
# USE_SCP is optional. If not provided then default to previously saved
|
||||
# value (which may be undefined... equivalent to "no").
|
||||
_getdeployconf DEPLOY_SSH_USE_SCP
|
||||
_debug2 DEPLOY_SSH_USE_SCP "$DEPLOY_SSH_USE_SCP"
|
||||
if [ -z "$DEPLOY_SSH_USE_SCP" ]; then
|
||||
DEPLOY_SSH_USE_SCP="no"
|
||||
fi
|
||||
_savedeployconf DEPLOY_SSH_USE_SCP "$DEPLOY_SSH_USE_SCP"
|
||||
|
||||
# SCP_CMD is optional. If not provided then use scp
|
||||
_getdeployconf DEPLOY_SSH_SCP_CMD
|
||||
_debug2 DEPLOY_SSH_SCP_CMD "$DEPLOY_SSH_SCP_CMD"
|
||||
if [ -z "$DEPLOY_SSH_SCP_CMD" ]; then
|
||||
DEPLOY_SSH_SCP_CMD="scp -q"
|
||||
fi
|
||||
_savedeployconf DEPLOY_SSH_SCP_CMD "$DEPLOY_SSH_SCP_CMD"
|
||||
|
||||
if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
|
||||
DEPLOY_SSH_MULTI_CALL="yes"
|
||||
_info "Using scp as alternate method for copying files. Multicall Mode is implicit"
|
||||
elif [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
_info "Using MULTI_CALL mode... Required commands sent in multiple calls to remote host"
|
||||
else
|
||||
_info "Required commands batched and sent in single call to remote host"
|
||||
fi
|
||||
|
||||
_deploy_ssh_servers="$DEPLOY_SSH_SERVER"
|
||||
for DEPLOY_SSH_SERVER in $_deploy_ssh_servers; do
|
||||
_ssh_deploy
|
||||
done
|
||||
}
|
||||
@@ -117,16 +181,25 @@ _ssh_deploy() {
|
||||
_cmdstr=""
|
||||
_backupprefix=""
|
||||
_backupdir=""
|
||||
_local_cert_file=""
|
||||
_local_ca_file=""
|
||||
_local_full_file=""
|
||||
|
||||
_info "Deploy certificates to remote server $Le_Deploy_ssh_user@$Le_Deploy_ssh_server"
|
||||
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
||||
_info "Using MULTI_CALL mode... Required commands sent in multiple calls to remote host"
|
||||
else
|
||||
_info "Required commands batched and sent in single call to remote host"
|
||||
fi
|
||||
case $DEPLOY_SSH_SERVER in
|
||||
*:*)
|
||||
_host=${DEPLOY_SSH_SERVER%:*}
|
||||
_port=${DEPLOY_SSH_SERVER##*:}
|
||||
;;
|
||||
*)
|
||||
_host=$DEPLOY_SSH_SERVER
|
||||
_port=
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$Le_Deploy_ssh_backup" = "yes" ]; then
|
||||
_backupprefix="$Le_Deploy_ssh_backup_path/$_cdomain-backup"
|
||||
_info "Deploy certificates to remote server $DEPLOY_SSH_USER@$_host:$_port"
|
||||
|
||||
if [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
||||
_backupprefix="$DEPLOY_SSH_BACKUP_PATH/$_cdomain-backup"
|
||||
_backupdir="$_backupprefix-$(_utc_date | tr ' ' '-')"
|
||||
# run cleanup on the backup directory, erase all older
|
||||
# than 180 days (15552000 seconds).
|
||||
@@ -138,7 +211,7 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
|
||||
_cmdstr="mkdir -p $_backupdir; $_cmdstr"
|
||||
_info "Backup of old certificate files will be placed in remote directory $_backupdir"
|
||||
_info "Backup directories erased after 180 days."
|
||||
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
@@ -146,129 +219,184 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
|
||||
fi
|
||||
fi
|
||||
|
||||
# KEYFILE is optional.
|
||||
# If provided then private key will be copied to provided filename.
|
||||
_getdeployconf DEPLOY_SSH_KEYFILE
|
||||
_debug2 DEPLOY_SSH_KEYFILE "$DEPLOY_SSH_KEYFILE"
|
||||
if [ -n "$DEPLOY_SSH_KEYFILE" ]; then
|
||||
Le_Deploy_ssh_keyfile="$DEPLOY_SSH_KEYFILE"
|
||||
_savedomainconf Le_Deploy_ssh_keyfile "$Le_Deploy_ssh_keyfile"
|
||||
fi
|
||||
if [ -n "$Le_Deploy_ssh_keyfile" ]; then
|
||||
if [ "$Le_Deploy_ssh_backup" = "yes" ]; then
|
||||
if [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
||||
# backup file we are about to overwrite.
|
||||
_cmdstr="$_cmdstr cp $Le_Deploy_ssh_keyfile $_backupdir >/dev/null;"
|
||||
_cmdstr="$_cmdstr cp $DEPLOY_SSH_KEYFILE $_backupdir >/dev/null;"
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
fi
|
||||
fi
|
||||
# copy new certificate into file.
|
||||
_cmdstr="$_cmdstr echo \"$(cat "$_ckey")\" > $Le_Deploy_ssh_keyfile;"
|
||||
_info "will copy private key to remote file $Le_Deploy_ssh_keyfile"
|
||||
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
|
||||
# copy new key into file.
|
||||
if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
|
||||
# scp the file
|
||||
if ! _scp_remote_cmd "$_ckey" "$DEPLOY_SSH_KEYFILE"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
else
|
||||
# ssh echo to the file
|
||||
_cmdstr="$_cmdstr echo \"$(cat "$_ckey")\" > $DEPLOY_SSH_KEYFILE;"
|
||||
_info "will copy private key to remote file $DEPLOY_SSH_KEYFILE"
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# CERTFILE is optional.
|
||||
# If provided then certificate will be copied or appended to provided filename.
|
||||
_getdeployconf DEPLOY_SSH_CERTFILE
|
||||
_debug2 DEPLOY_SSH_CERTFILE "$DEPLOY_SSH_CERTFILE"
|
||||
if [ -n "$DEPLOY_SSH_CERTFILE" ]; then
|
||||
Le_Deploy_ssh_certfile="$DEPLOY_SSH_CERTFILE"
|
||||
_savedomainconf Le_Deploy_ssh_certfile "$Le_Deploy_ssh_certfile"
|
||||
fi
|
||||
if [ -n "$Le_Deploy_ssh_certfile" ]; then
|
||||
_pipe=">"
|
||||
if [ "$Le_Deploy_ssh_certfile" = "$Le_Deploy_ssh_keyfile" ]; then
|
||||
if [ "$DEPLOY_SSH_CERTFILE" = "$DEPLOY_SSH_KEYFILE" ]; then
|
||||
# if filename is same as previous file then append.
|
||||
_pipe=">>"
|
||||
elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
|
||||
elif [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
||||
# backup file we are about to overwrite.
|
||||
_cmdstr="$_cmdstr cp $Le_Deploy_ssh_certfile $_backupdir >/dev/null;"
|
||||
_cmdstr="$_cmdstr cp $DEPLOY_SSH_CERTFILE $_backupdir >/dev/null;"
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
fi
|
||||
fi
|
||||
|
||||
# copy new certificate into file.
|
||||
_cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" $_pipe $Le_Deploy_ssh_certfile;"
|
||||
_info "will copy certificate to remote file $Le_Deploy_ssh_certfile"
|
||||
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
|
||||
# scp the file
|
||||
_local_cert_file=$(_mktemp)
|
||||
if [ "$DEPLOY_SSH_CERTFILE" = "$DEPLOY_SSH_KEYFILE" ]; then
|
||||
cat "$_ckey" >>"$_local_cert_file"
|
||||
fi
|
||||
cat "$_ccert" >>"$_local_cert_file"
|
||||
if ! _scp_remote_cmd "$_local_cert_file" "$DEPLOY_SSH_CERTFILE"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
else
|
||||
# ssh echo to the file
|
||||
_cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" $_pipe $DEPLOY_SSH_CERTFILE;"
|
||||
_info "will copy certificate to remote file $DEPLOY_SSH_CERTFILE"
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# CAFILE is optional.
|
||||
# If provided then CA intermediate certificate will be copied or appended to provided filename.
|
||||
_getdeployconf DEPLOY_SSH_CAFILE
|
||||
_debug2 DEPLOY_SSH_CAFILE "$DEPLOY_SSH_CAFILE"
|
||||
if [ -n "$DEPLOY_SSH_CAFILE" ]; then
|
||||
Le_Deploy_ssh_cafile="$DEPLOY_SSH_CAFILE"
|
||||
_savedomainconf Le_Deploy_ssh_cafile "$Le_Deploy_ssh_cafile"
|
||||
fi
|
||||
if [ -n "$Le_Deploy_ssh_cafile" ]; then
|
||||
_pipe=">"
|
||||
if [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_keyfile" ] ||
|
||||
[ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_certfile" ]; then
|
||||
if [ "$DEPLOY_SSH_CAFILE" = "$DEPLOY_SSH_KEYFILE" ] ||
|
||||
[ "$DEPLOY_SSH_CAFILE" = "$DEPLOY_SSH_CERTFILE" ]; then
|
||||
# if filename is same as previous file then append.
|
||||
_pipe=">>"
|
||||
elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
|
||||
elif [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
||||
# backup file we are about to overwrite.
|
||||
_cmdstr="$_cmdstr cp $Le_Deploy_ssh_cafile $_backupdir >/dev/null;"
|
||||
_cmdstr="$_cmdstr cp $DEPLOY_SSH_CAFILE $_backupdir >/dev/null;"
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
fi
|
||||
fi
|
||||
|
||||
# copy new certificate into file.
|
||||
_cmdstr="$_cmdstr echo \"$(cat "$_cca")\" $_pipe $Le_Deploy_ssh_cafile;"
|
||||
_info "will copy CA file to remote file $Le_Deploy_ssh_cafile"
|
||||
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
|
||||
# scp the file
|
||||
_local_ca_file=$(_mktemp)
|
||||
if [ "$DEPLOY_SSH_CAFILE" = "$DEPLOY_SSH_KEYFILE" ]; then
|
||||
cat "$_ckey" >>"$_local_ca_file"
|
||||
fi
|
||||
if [ "$DEPLOY_SSH_CAFILE" = "$DEPLOY_SSH_CERTFILE" ]; then
|
||||
cat "$_ccert" >>"$_local_ca_file"
|
||||
fi
|
||||
cat "$_cca" >>"$_local_ca_file"
|
||||
if ! _scp_remote_cmd "$_local_ca_file" "$DEPLOY_SSH_CAFILE"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
else
|
||||
# ssh echo to the file
|
||||
_cmdstr="$_cmdstr echo \"$(cat "$_cca")\" $_pipe $DEPLOY_SSH_CAFILE;"
|
||||
_info "will copy CA file to remote file $DEPLOY_SSH_CAFILE"
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# FULLCHAIN is optional.
|
||||
# If provided then fullchain certificate will be copied or appended to provided filename.
|
||||
_getdeployconf DEPLOY_SSH_FULLCHAIN
|
||||
_debug2 DEPLOY_SSH_FULLCHAIN "$DEPLOY_SSH_FULLCHAIN"
|
||||
if [ -n "$DEPLOY_SSH_FULLCHAIN" ]; then
|
||||
Le_Deploy_ssh_fullchain="$DEPLOY_SSH_FULLCHAIN"
|
||||
_savedomainconf Le_Deploy_ssh_fullchain "$Le_Deploy_ssh_fullchain"
|
||||
fi
|
||||
if [ -n "$Le_Deploy_ssh_fullchain" ]; then
|
||||
_pipe=">"
|
||||
if [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_keyfile" ] ||
|
||||
[ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_certfile" ] ||
|
||||
[ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_cafile" ]; then
|
||||
if [ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_KEYFILE" ] ||
|
||||
[ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_CERTFILE" ] ||
|
||||
[ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_CAFILE" ]; then
|
||||
# if filename is same as previous file then append.
|
||||
_pipe=">>"
|
||||
elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
|
||||
elif [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
||||
# backup file we are about to overwrite.
|
||||
_cmdstr="$_cmdstr cp $Le_Deploy_ssh_fullchain $_backupdir >/dev/null;"
|
||||
_cmdstr="$_cmdstr cp $DEPLOY_SSH_FULLCHAIN $_backupdir >/dev/null;"
|
||||
if [ "$DEPLOY_SSH_FULLCHAIN" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
fi
|
||||
fi
|
||||
|
||||
# copy new certificate into file.
|
||||
_cmdstr="$_cmdstr echo \"$(cat "$_cfullchain")\" $_pipe $Le_Deploy_ssh_fullchain;"
|
||||
_info "will copy fullchain to remote file $Le_Deploy_ssh_fullchain"
|
||||
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
|
||||
# scp the file
|
||||
_local_full_file=$(_mktemp)
|
||||
if [ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_KEYFILE" ]; then
|
||||
cat "$_ckey" >>"$_local_full_file"
|
||||
fi
|
||||
if [ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_CERTFILE" ]; then
|
||||
cat "$_ccert" >>"$_local_full_file"
|
||||
fi
|
||||
if [ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_CAFILE" ]; then
|
||||
cat "$_cca" >>"$_local_full_file"
|
||||
fi
|
||||
cat "$_cfullchain" >>"$_local_full_file"
|
||||
if ! _scp_remote_cmd "$_local_full_file" "$DEPLOY_SSH_FULLCHAIN"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
else
|
||||
# ssh echo to the file
|
||||
_cmdstr="$_cmdstr echo \"$(cat "$_cfullchain")\" $_pipe $DEPLOY_SSH_FULLCHAIN;"
|
||||
_info "will copy fullchain to remote file $DEPLOY_SSH_FULLCHAIN"
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# REMOTE_CMD is optional.
|
||||
# If provided then this command will be executed on remote host.
|
||||
_getdeployconf DEPLOY_SSH_REMOTE_CMD
|
||||
_debug2 DEPLOY_SSH_REMOTE_CMD "$DEPLOY_SSH_REMOTE_CMD"
|
||||
if [ -n "$DEPLOY_SSH_REMOTE_CMD" ]; then
|
||||
Le_Deploy_ssh_remote_cmd="$DEPLOY_SSH_REMOTE_CMD"
|
||||
_savedomainconf Le_Deploy_ssh_remote_cmd "$Le_Deploy_ssh_remote_cmd"
|
||||
# cleanup local files if any
|
||||
if [ -f "$_local_cert_file" ]; then
|
||||
rm -f "$_local_cert_file"
|
||||
fi
|
||||
if [ -n "$Le_Deploy_ssh_remote_cmd" ]; then
|
||||
_cmdstr="$_cmdstr $Le_Deploy_ssh_remote_cmd;"
|
||||
_info "Will execute remote command $Le_Deploy_ssh_remote_cmd"
|
||||
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
||||
if [ -f "$_local_ca_file" ]; then
|
||||
rm -f "$_local_ca_file"
|
||||
fi
|
||||
if [ -f "$_local_full_file" ]; then
|
||||
rm -f "$_local_full_file"
|
||||
fi
|
||||
|
||||
if [ -n "$DEPLOY_SSH_REMOTE_CMD" ]; then
|
||||
_cmdstr="$_cmdstr $DEPLOY_SSH_REMOTE_CMD;"
|
||||
_info "Will execute remote command $DEPLOY_SSH_REMOTE_CMD"
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
@@ -282,17 +410,25 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
|
||||
return $_err_code
|
||||
fi
|
||||
fi
|
||||
# cleanup in case all is ok
|
||||
return 0
|
||||
}
|
||||
|
||||
#cmd
|
||||
_ssh_remote_cmd() {
|
||||
_cmd="$1"
|
||||
|
||||
_ssh_cmd="$DEPLOY_SSH_CMD"
|
||||
if [ -n "$_port" ]; then
|
||||
_ssh_cmd="$_ssh_cmd -p $_port"
|
||||
fi
|
||||
|
||||
_secure_debug "Remote commands to execute: $_cmd"
|
||||
_info "Submitting sequence of commands to remote server by ssh"
|
||||
_info "Submitting sequence of commands to remote server by $_ssh_cmd"
|
||||
|
||||
# quotations in bash cmd below intended. Squash travis spellcheck error
|
||||
# shellcheck disable=SC2029
|
||||
$Le_Deploy_ssh_cmd "$Le_Deploy_ssh_user@$Le_Deploy_ssh_server" sh -c "'$_cmd'"
|
||||
$_ssh_cmd "$DEPLOY_SSH_USER@$_host" sh -c "'$_cmd'"
|
||||
_err_code="$?"
|
||||
|
||||
if [ "$_err_code" != "0" ]; then
|
||||
@@ -301,3 +437,26 @@ _ssh_remote_cmd() {
|
||||
|
||||
return $_err_code
|
||||
}
|
||||
|
||||
# cmd scp
|
||||
_scp_remote_cmd() {
|
||||
_src=$1
|
||||
_dest=$2
|
||||
|
||||
_scp_cmd="$DEPLOY_SSH_SCP_CMD"
|
||||
if [ -n "$_port" ]; then
|
||||
_scp_cmd="$_scp_cmd -P $_port"
|
||||
fi
|
||||
|
||||
_secure_debug "Remote copy source $_src to destination $_dest"
|
||||
_info "Submitting secure copy by $_scp_cmd"
|
||||
|
||||
$_scp_cmd "$_src" "$DEPLOY_SSH_USER"@"$_host":"$_dest"
|
||||
_err_code="$?"
|
||||
|
||||
if [ "$_err_code" != "0" ]; then
|
||||
_err "Error code $_err_code returned from scp"
|
||||
fi
|
||||
|
||||
return $_err_code
|
||||
}
|
||||
|
||||
@@ -184,6 +184,27 @@ truenas_deploy() {
|
||||
_info "S3 certificate is not configured or is not the same as TrueNAS web UI"
|
||||
fi
|
||||
|
||||
_info "Checking if any chart release Apps is using the same certificate as TrueNAS web UI. Tool 'jq' is required"
|
||||
if _exists jq; then
|
||||
_info "Query all chart release"
|
||||
_release_list=$(_get "$_api_url/chart/release")
|
||||
_related_name_list=$(printf "%s" "$_release_list" | jq -r "[.[] | {name,certId: .config.ingress?.main.tls[]?.scaleCert} | select(.certId==$_active_cert_id) | .name ] | unique")
|
||||
_release_length=$(printf "%s" "$_related_name_list" | jq -r "length")
|
||||
_info "Found $_release_length related chart release in list: $_related_name_list"
|
||||
for i in $(seq 0 $((_release_length - 1))); do
|
||||
_release_name=$(echo "$_related_name_list" | jq -r ".[$i]")
|
||||
_info "Updating certificate from $_active_cert_id to $_cert_id for chart release: $_release_name"
|
||||
#Read the chart release configuration
|
||||
_chart_config=$(printf "%s" "$_release_list" | jq -r ".[] | select(.name==\"$_release_name\")")
|
||||
#Replace the old certificate id with the new one in path .config.ingress.main.tls[].scaleCert. Then update .config.ingress
|
||||
_updated_chart_config=$(printf "%s" "$_chart_config" | jq "(.config.ingress?.main.tls[]? | select(.scaleCert==$_active_cert_id) | .scaleCert ) |= $_cert_id | .config.ingress ")
|
||||
_update_chart_result="$(_post "{\"values\" : { \"ingress\" : $_updated_chart_config } }" "$_api_url/chart/release/id/$_release_name" "" "PUT" "application/json")"
|
||||
_debug3 _update_chart_result "$_update_chart_result"
|
||||
done
|
||||
else
|
||||
_info "Tool 'jq' does not exists, skip chart release checking"
|
||||
fi
|
||||
|
||||
_info "Deleting old certificate"
|
||||
_delete_result="$(_post "" "$_api_url/certificate/id/$_active_cert_id" "" "DELETE" "application/json")"
|
||||
|
||||
|
||||
@@ -7,13 +7,16 @@
|
||||
#
|
||||
# VAULT_PREFIX - this contains the prefix path in vault
|
||||
# VAULT_ADDR - vault requires this to find your vault server
|
||||
# VAULT_SAVE_TOKEN - set to anything if you want to save the token
|
||||
# VAULT_RENEW_TOKEN - set to anything if you want to renew the token to default TTL before deploying
|
||||
# VAULT_KV_V2 - set to anything if you are using v2 of the kv engine
|
||||
#
|
||||
# additionally, you need to ensure that VAULT_TOKEN is avialable
|
||||
# to access the vault server
|
||||
|
||||
#returns 0 means success, otherwise error.
|
||||
|
||||
######## Public functions #####################
|
||||
######## Public functions #####################
|
||||
|
||||
#domain keyfile certfile cafile fullchain
|
||||
vault_deploy() {
|
||||
@@ -45,6 +48,26 @@ vault_deploy() {
|
||||
fi
|
||||
_savedeployconf VAULT_ADDR "$VAULT_ADDR"
|
||||
|
||||
_getdeployconf VAULT_SAVE_TOKEN
|
||||
_savedeployconf VAULT_SAVE_TOKEN "$VAULT_SAVE_TOKEN"
|
||||
|
||||
_getdeployconf VAULT_RENEW_TOKEN
|
||||
_savedeployconf VAULT_RENEW_TOKEN "$VAULT_RENEW_TOKEN"
|
||||
|
||||
_getdeployconf VAULT_KV_V2
|
||||
_savedeployconf VAULT_KV_V2 "$VAULT_KV_V2"
|
||||
|
||||
_getdeployconf VAULT_TOKEN
|
||||
if [ -z "$VAULT_TOKEN" ]; then
|
||||
_err "VAULT_TOKEN needs to be defined"
|
||||
return 1
|
||||
fi
|
||||
if [ -n "$VAULT_SAVE_TOKEN" ]; then
|
||||
_savedeployconf VAULT_TOKEN "$VAULT_TOKEN"
|
||||
fi
|
||||
|
||||
_migratedeployconf FABIO VAULT_FABIO_MODE
|
||||
|
||||
# JSON does not allow multiline strings.
|
||||
# So replacing new-lines with "\n" here
|
||||
_ckey=$(sed -z 's/\n/\\n/g' <"$2")
|
||||
@@ -52,26 +75,56 @@ vault_deploy() {
|
||||
_cca=$(sed -z 's/\n/\\n/g' <"$4")
|
||||
_cfullchain=$(sed -z 's/\n/\\n/g' <"$5")
|
||||
|
||||
URL="$VAULT_ADDR/v1/$VAULT_PREFIX/$_cdomain"
|
||||
export _H1="X-Vault-Token: $VAULT_TOKEN"
|
||||
|
||||
if [ -n "$FABIO" ]; then
|
||||
if [ -n "$VAULT_RENEW_TOKEN" ]; then
|
||||
URL="$VAULT_ADDR/v1/auth/token/renew-self"
|
||||
_info "Renew the Vault token to default TTL"
|
||||
if ! _post "" "$URL" >/dev/null; then
|
||||
_err "Failed to renew the Vault token"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
URL="$VAULT_ADDR/v1/$VAULT_PREFIX/$_cdomain"
|
||||
|
||||
if [ -n "$VAULT_FABIO_MODE" ]; then
|
||||
_info "Writing certificate and key to $URL in Fabio mode"
|
||||
if [ -n "$VAULT_KV_V2" ]; then
|
||||
_post "{ \"data\": {\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"} }" "$URL"
|
||||
_post "{ \"data\": {\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"} }" "$URL" >/dev/null || return 1
|
||||
else
|
||||
_post "{\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"}" "$URL"
|
||||
_post "{\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"}" "$URL" >/dev/null || return 1
|
||||
fi
|
||||
else
|
||||
if [ -n "$VAULT_KV_V2" ]; then
|
||||
_post "{\"data\": {\"value\": \"$_ccert\"}}" "$URL/cert.pem"
|
||||
_post "{\"data\": {\"value\": \"$_ckey\"}}" "$URL/cert.key"
|
||||
_post "{\"data\": {\"value\": \"$_cca\"}}" "$URL/chain.pem"
|
||||
_post "{\"data\": {\"value\": \"$_cfullchain\"}}" "$URL/fullchain.pem"
|
||||
_info "Writing certificate to $URL/cert.pem"
|
||||
_post "{\"data\": {\"value\": \"$_ccert\"}}" "$URL/cert.pem" >/dev/null || return 1
|
||||
_info "Writing key to $URL/cert.key"
|
||||
_post "{\"data\": {\"value\": \"$_ckey\"}}" "$URL/cert.key" >/dev/null || return 1
|
||||
_info "Writing CA certificate to $URL/ca.pem"
|
||||
_post "{\"data\": {\"value\": \"$_cca\"}}" "$URL/ca.pem" >/dev/null || return 1
|
||||
_info "Writing full-chain certificate to $URL/fullchain.pem"
|
||||
_post "{\"data\": {\"value\": \"$_cfullchain\"}}" "$URL/fullchain.pem" >/dev/null || return 1
|
||||
else
|
||||
_post "{\"value\": \"$_ccert\"}" "$URL/cert.pem"
|
||||
_post "{\"value\": \"$_ckey\"}" "$URL/cert.key"
|
||||
_post "{\"value\": \"$_cca\"}" "$URL/chain.pem"
|
||||
_post "{\"value\": \"$_cfullchain\"}" "$URL/fullchain.pem"
|
||||
_info "Writing certificate to $URL/cert.pem"
|
||||
_post "{\"value\": \"$_ccert\"}" "$URL/cert.pem" >/dev/null || return 1
|
||||
_info "Writing key to $URL/cert.key"
|
||||
_post "{\"value\": \"$_ckey\"}" "$URL/cert.key" >/dev/null || return 1
|
||||
_info "Writing CA certificate to $URL/ca.pem"
|
||||
_post "{\"value\": \"$_cca\"}" "$URL/ca.pem" >/dev/null || return 1
|
||||
_info "Writing full-chain certificate to $URL/fullchain.pem"
|
||||
_post "{\"value\": \"$_cfullchain\"}" "$URL/fullchain.pem" >/dev/null || return 1
|
||||
fi
|
||||
|
||||
# To make it compatible with the wrong ca path `chain.pem` which was used in former versions
|
||||
if _contains "$(_get "$URL/chain.pem")" "-----BEGIN CERTIFICATE-----"; then
|
||||
_err "The CA certificate has moved from chain.pem to ca.pem, if you don't depend on chain.pem anymore, you can delete it to avoid this warning"
|
||||
_info "Updating CA certificate to $URL/chain.pem for backward compatibility"
|
||||
if [ -n "$VAULT_KV_V2" ]; then
|
||||
_post "{\"data\": {\"value\": \"$_cca\"}}" "$URL/chain.pem" >/dev/null || return 1
|
||||
else
|
||||
_post "{\"value\": \"$_cca\"}" "$URL/chain.pem" >/dev/null || return 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#
|
||||
# VAULT_PREFIX - this contains the prefix path in vault
|
||||
# VAULT_ADDR - vault requires this to find your vault server
|
||||
# VAULT_SAVE_TOKEN - set to anything if you want to save the token
|
||||
# VAULT_RENEW_TOKEN - set to anything if you want to renew the token to default TTL before deploying
|
||||
#
|
||||
# additionally, you need to ensure that VAULT_TOKEN is avialable or
|
||||
# `vault auth` has applied the appropriate authorization for the vault binary
|
||||
@@ -33,15 +35,36 @@ vault_cli_deploy() {
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
# validate required env vars
|
||||
_getdeployconf VAULT_PREFIX
|
||||
if [ -z "$VAULT_PREFIX" ]; then
|
||||
_err "VAULT_PREFIX needs to be defined (contains prefix path in vault)"
|
||||
return 1
|
||||
fi
|
||||
_savedeployconf VAULT_PREFIX "$VAULT_PREFIX"
|
||||
|
||||
_getdeployconf VAULT_ADDR
|
||||
if [ -z "$VAULT_ADDR" ]; then
|
||||
_err "VAULT_ADDR needs to be defined (contains vault connection address)"
|
||||
return 1
|
||||
fi
|
||||
_savedeployconf VAULT_ADDR "$VAULT_ADDR"
|
||||
|
||||
_getdeployconf VAULT_SAVE_TOKEN
|
||||
_savedeployconf VAULT_SAVE_TOKEN "$VAULT_SAVE_TOKEN"
|
||||
|
||||
_getdeployconf VAULT_RENEW_TOKEN
|
||||
_savedeployconf VAULT_RENEW_TOKEN "$VAULT_RENEW_TOKEN"
|
||||
|
||||
_getdeployconf VAULT_TOKEN
|
||||
if [ -z "$VAULT_TOKEN" ]; then
|
||||
_err "VAULT_TOKEN needs to be defined"
|
||||
return 1
|
||||
fi
|
||||
if [ -n "$VAULT_SAVE_TOKEN" ]; then
|
||||
_savedeployconf VAULT_TOKEN "$VAULT_TOKEN"
|
||||
fi
|
||||
|
||||
_migratedeployconf FABIO VAULT_FABIO_MODE
|
||||
|
||||
VAULT_CMD=$(command -v vault)
|
||||
if [ ! $? ]; then
|
||||
@@ -49,13 +72,33 @@ vault_cli_deploy() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -n "$FABIO" ]; then
|
||||
if [ -n "$VAULT_RENEW_TOKEN" ]; then
|
||||
_info "Renew the Vault token to default TTL"
|
||||
if ! $VAULT_CMD token renew; then
|
||||
_err "Failed to renew the Vault token"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$VAULT_FABIO_MODE" ]; then
|
||||
_info "Writing certificate and key to ${VAULT_PREFIX}/${_cdomain} in Fabio mode"
|
||||
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}" cert=@"$_cfullchain" key=@"$_ckey" || return 1
|
||||
else
|
||||
_info "Writing certificate to ${VAULT_PREFIX}/${_cdomain}/cert.pem"
|
||||
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/cert.pem" value=@"$_ccert" || return 1
|
||||
_info "Writing key to ${VAULT_PREFIX}/${_cdomain}/cert.key"
|
||||
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/cert.key" value=@"$_ckey" || return 1
|
||||
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/chain.pem" value=@"$_cca" || return 1
|
||||
_info "Writing CA certificate to ${VAULT_PREFIX}/${_cdomain}/ca.pem"
|
||||
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/ca.pem" value=@"$_cca" || return 1
|
||||
_info "Writing full-chain certificate to ${VAULT_PREFIX}/${_cdomain}/fullchain.pem"
|
||||
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/fullchain.pem" value=@"$_cfullchain" || return 1
|
||||
|
||||
# To make it compatible with the wrong ca path `chain.pem` which was used in former versions
|
||||
if $VAULT_CMD kv get "${VAULT_PREFIX}/${_cdomain}/chain.pem" >/dev/null; then
|
||||
_err "The CA certificate has moved from chain.pem to ca.pem, if you don't depend on chain.pem anymore, you can delete it to avoid this warning"
|
||||
_info "Updating CA certificate to ${VAULT_PREFIX}/${_cdomain}/chain.pem for backward compatibility"
|
||||
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/chain.pem" value=@"$_cca" || return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#Arvan_Token="Apikey xxxx"
|
||||
# Arvan_Token="Apikey xxxx"
|
||||
|
||||
ARVAN_API_URL="https://napi.arvancloud.com/cdn/4.0/domains"
|
||||
#Author: Vahid Fardi
|
||||
#Report Bugs here: https://github.com/Neilpang/acme.sh
|
||||
ARVAN_API_URL="https://napi.arvancloud.ir/cdn/4.0/domains"
|
||||
# Author: Vahid Fardi
|
||||
# Report Bugs here: https://github.com/Neilpang/acme.sh
|
||||
#
|
||||
######## Public functions #####################
|
||||
|
||||
@@ -18,7 +18,7 @@ dns_arvan_add() {
|
||||
|
||||
if [ -z "$Arvan_Token" ]; then
|
||||
_err "You didn't specify \"Arvan_Token\" token yet."
|
||||
_err "You can get yours from here https://npanel.arvancloud.com/profile/api-keys"
|
||||
_err "You can get yours from here https://npanel.arvancloud.ir/profile/api-keys"
|
||||
return 1
|
||||
fi
|
||||
#save the api token to the account conf file.
|
||||
@@ -40,7 +40,7 @@ dns_arvan_add() {
|
||||
_info "response id is $response"
|
||||
_info "Added, OK"
|
||||
return 0
|
||||
elif _contains "$response" "Record Data is Duplicated"; then
|
||||
elif _contains "$response" "Record Data is duplicate"; then
|
||||
_info "Already exists, OK"
|
||||
return 0
|
||||
else
|
||||
@@ -141,6 +141,7 @@ _arvan_rest() {
|
||||
response="$(_post "$data" "$ARVAN_API_URL/$ep" "" "$mtd")"
|
||||
elif [ "$mtd" = "POST" ]; then
|
||||
export _H2="Content-Type: application/json"
|
||||
export _H3="Accept: application/json"
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$ARVAN_API_URL/$ep" "" "$mtd")"
|
||||
else
|
||||
|
||||
@@ -78,7 +78,7 @@ dns_cloudns_rm() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
for i in $(echo "$response" | tr '{' "\n" | grep "$record"); do
|
||||
for i in $(echo "$response" | tr '{' "\n" | grep -- "$record"); do
|
||||
record_id=$(echo "$i" | tr ',' "\n" | grep -E '^"id"' | sed -re 's/^\"id\"\:\"([0-9]+)\"$/\1/g')
|
||||
|
||||
if [ -n "$record_id" ]; then
|
||||
|
||||
187
dnsapi/dns_gcore.sh
Executable file
187
dnsapi/dns_gcore.sh
Executable file
@@ -0,0 +1,187 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
#GCORE_Key='773$7b7adaf2a2b32bfb1b83787b4ff32a67eb178e3ada1af733e47b1411f2461f7f4fa7ed7138e2772a46124377bad7384b3bb8d87748f87b3f23db4b8bbe41b2bb'
|
||||
#
|
||||
|
||||
GCORE_Api="https://api.gcorelabs.com/dns/v2"
|
||||
GCORE_Doc="https://apidocs.gcore.com/dns"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_gcore_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
GCORE_Key="${GCORE_Key:-$(_readaccountconf_mutable GCORE_Key)}"
|
||||
|
||||
if [ -z "$GCORE_Key" ]; then
|
||||
GCORE_Key=""
|
||||
_err "You didn't specify a Gcore api key yet."
|
||||
_err "You can get yours from here $GCORE_Doc"
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the api key to the account conf file.
|
||||
_saveaccountconf_mutable GCORE_Key "$GCORE_Key"
|
||||
|
||||
_debug "First detect the zone name"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _zone_name "$_zone_name"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_debug "Getting txt records"
|
||||
_gcore_rest GET "zones/$_zone_name/$fulldomain/TXT"
|
||||
payload=""
|
||||
|
||||
if echo "$response" | grep "record is not found" >/dev/null; then
|
||||
_info "Record doesn't exists"
|
||||
payload="{\"resource_records\":[{\"content\":[\"$txtvalue\"],\"enabled\":true}],\"ttl\":120}"
|
||||
elif echo "$response" | grep "$txtvalue" >/dev/null; then
|
||||
_info "Already exists, OK"
|
||||
return 0
|
||||
elif echo "$response" | tr -d " " | grep \"name\":\""$fulldomain"\",\"type\":\"TXT\" >/dev/null; then
|
||||
_info "Record with mismatch txtvalue, try update it"
|
||||
payload=$(echo "$response" | tr -d " " | sed 's/"updated_at":[0-9]\+,//g' | sed 's/"meta":{}}]}/"meta":{}},{"content":['\""$txtvalue"\"'],"enabled":true}]}/')
|
||||
fi
|
||||
|
||||
# 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 _gcore_rest PUT "zones/$_zone_name/$fulldomain/TXT" "$payload"; then
|
||||
if _contains "$response" "$txtvalue"; then
|
||||
_info "Added, OK"
|
||||
return 0
|
||||
elif _contains "$response" "rrset is already exists"; then
|
||||
_info "Already exists, OK"
|
||||
return 0
|
||||
else
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
}
|
||||
|
||||
#fulldomain txtvalue
|
||||
dns_gcore_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
GCORE_Key="${GCORE_Key:-$(_readaccountconf_mutable GCORE_Key)}"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _zone_name "$_zone_name"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_debug "Getting txt records"
|
||||
_gcore_rest GET "zones/$_zone_name/$fulldomain/TXT"
|
||||
|
||||
if echo "$response" | grep "record is not found" >/dev/null; then
|
||||
_info "No such txt recrod"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! echo "$response" | tr -d " " | grep \"name\":\""$fulldomain"\",\"type\":\"TXT\" >/dev/null; then
|
||||
_err "Error: $response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! echo "$response" | tr -d " " | grep \""$txtvalue"\" >/dev/null; then
|
||||
_info "No such txt recrod"
|
||||
return 0
|
||||
fi
|
||||
|
||||
count="$(echo "$response" | grep -o "content" | wc -l)"
|
||||
|
||||
if [ "$count" = "1" ]; then
|
||||
if ! _gcore_rest DELETE "zones/$_zone_name/$fulldomain/TXT"; then
|
||||
_err "Delete record error. $response"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
|
||||
payload="$(echo "$response" | tr -d " " | sed 's/"updated_at":[0-9]\+,//g' | sed 's/{"id":[0-9]\+,"content":\["'"$txtvalue"'"\],"enabled":true,"meta":{}}//' | sed 's/\[,/\[/' | sed 's/,,/,/' | sed 's/,\]/\]/')"
|
||||
if ! _gcore_rest PUT "zones/$_zone_name/$fulldomain/TXT" "$payload"; then
|
||||
_err "Delete record error. $response"
|
||||
fi
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#_acme-challenge.sub.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.sub or _acme-challenge
|
||||
# _domain=domain.com
|
||||
# _zone_name=domain.com or sub.domain.com
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=1
|
||||
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 ! _gcore_rest GET "zones/$h"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "\"name\":\"$h\""; then
|
||||
_zone_name=$h
|
||||
if [ "$_zone_name" ]; 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
|
||||
}
|
||||
|
||||
_gcore_rest() {
|
||||
m=$1
|
||||
ep="$2"
|
||||
data="$3"
|
||||
_debug "$ep"
|
||||
|
||||
key_trimmed=$(echo "$GCORE_Key" | tr -d '"')
|
||||
|
||||
export _H1="Content-Type: application/json"
|
||||
export _H2="Authorization: APIKey $key_trimmed"
|
||||
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$GCORE_Api/$ep" "" "$m")"
|
||||
else
|
||||
response="$(_get "$GCORE_Api/$ep")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
@@ -22,8 +22,8 @@ dns_gd_add() {
|
||||
if [ -z "$GD_Key" ] || [ -z "$GD_Secret" ]; then
|
||||
GD_Key=""
|
||||
GD_Secret=""
|
||||
_err "You don't specify godaddy api key and secret yet."
|
||||
_err "Please create you key and try again."
|
||||
_err "You didn't specify godaddy api key and secret yet."
|
||||
_err "Please create your key and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
@@ -46,7 +46,7 @@ dns_gd_add() {
|
||||
fi
|
||||
|
||||
if _contains "$response" "$txtvalue"; then
|
||||
_info "The record is existing, skip"
|
||||
_info "This record already exists, skipping"
|
||||
return 0
|
||||
fi
|
||||
|
||||
|
||||
173
dnsapi/dns_googledomains.sh
Executable file
173
dnsapi/dns_googledomains.sh
Executable file
@@ -0,0 +1,173 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Author: Alex Leigh <leigh at alexleigh dot me>
|
||||
# Created: 2023-03-02
|
||||
|
||||
#GOOGLEDOMAINS_ACCESS_TOKEN="xxxx"
|
||||
#GOOGLEDOMAINS_ZONE="xxxx"
|
||||
GOOGLEDOMAINS_API="https://acmedns.googleapis.com/v1/acmeChallengeSets"
|
||||
|
||||
######## Public functions ########
|
||||
|
||||
#Usage: dns_googledomains_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_googledomains_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
_info "Invoking Google Domains ACME DNS API."
|
||||
|
||||
if ! _dns_googledomains_setup; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
zone="$(_dns_googledomains_get_zone "$fulldomain")"
|
||||
if [ -z "$zone" ]; then
|
||||
_err "Could not find a Google Domains-managed zone containing the requested domain."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug zone "$zone"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
_info "Adding TXT record for $fulldomain."
|
||||
if _dns_googledomains_api "$zone" ":rotateChallenges" "{\"accessToken\":\"$GOOGLEDOMAINS_ACCESS_TOKEN\",\"recordsToAdd\":[{\"fqdn\":\"$fulldomain\",\"digest\":\"$txtvalue\"}],\"keepExpiredRecords\":true}"; then
|
||||
if _contains "$response" "$txtvalue"; then
|
||||
_info "TXT record added."
|
||||
return 0
|
||||
else
|
||||
_err "Error adding TXT record."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
_err "Error adding TXT record."
|
||||
return 1
|
||||
}
|
||||
|
||||
#Usage: dns_googledomains_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_googledomains_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
_info "Invoking Google Domains ACME DNS API."
|
||||
|
||||
if ! _dns_googledomains_setup; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
zone="$(_dns_googledomains_get_zone "$fulldomain")"
|
||||
if [ -z "$zone" ]; then
|
||||
_err "Could not find a Google Domains-managed domain based on request."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug zone "$zone"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
_info "Removing TXT record for $fulldomain."
|
||||
if _dns_googledomains_api "$zone" ":rotateChallenges" "{\"accessToken\":\"$GOOGLEDOMAINS_ACCESS_TOKEN\",\"recordsToRemove\":[{\"fqdn\":\"$fulldomain\",\"digest\":\"$txtvalue\"}],\"keepExpiredRecords\":true}"; then
|
||||
if _contains "$response" "$txtvalue"; then
|
||||
_err "Error removing TXT record."
|
||||
return 1
|
||||
else
|
||||
_info "TXT record removed."
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
_err "Error removing TXT record."
|
||||
return 1
|
||||
}
|
||||
|
||||
######## Private functions ########
|
||||
|
||||
_dns_googledomains_setup() {
|
||||
if [ -n "$GOOGLEDOMAINS_SETUP_COMPLETED" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
GOOGLEDOMAINS_ACCESS_TOKEN="${GOOGLEDOMAINS_ACCESS_TOKEN:-$(_readaccountconf_mutable GOOGLEDOMAINS_ACCESS_TOKEN)}"
|
||||
GOOGLEDOMAINS_ZONE="${GOOGLEDOMAINS_ZONE:-$(_readaccountconf_mutable GOOGLEDOMAINS_ZONE)}"
|
||||
|
||||
if [ -z "$GOOGLEDOMAINS_ACCESS_TOKEN" ]; then
|
||||
GOOGLEDOMAINS_ACCESS_TOKEN=""
|
||||
_err "Google Domains access token was not specified."
|
||||
_err "Please visit Google Domains Security settings to provision an ACME DNS API access token."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$GOOGLEDOMAINS_ZONE" ]; then
|
||||
_savedomainconf GOOGLEDOMAINS_ACCESS_TOKEN "$GOOGLEDOMAINS_ACCESS_TOKEN"
|
||||
_savedomainconf GOOGLEDOMAINS_ZONE "$GOOGLEDOMAINS_ZONE"
|
||||
else
|
||||
_saveaccountconf_mutable GOOGLEDOMAINS_ACCESS_TOKEN "$GOOGLEDOMAINS_ACCESS_TOKEN"
|
||||
_clearaccountconf_mutable GOOGLEDOMAINS_ZONE
|
||||
_clearaccountconf GOOGLEDOMAINS_ZONE
|
||||
fi
|
||||
|
||||
_debug GOOGLEDOMAINS_ACCESS_TOKEN "$GOOGLEDOMAINS_ACCESS_TOKEN"
|
||||
_debug GOOGLEDOMAINS_ZONE "$GOOGLEDOMAINS_ZONE"
|
||||
|
||||
GOOGLEDOMAINS_SETUP_COMPLETED=1
|
||||
return 0
|
||||
}
|
||||
|
||||
_dns_googledomains_get_zone() {
|
||||
domain=$1
|
||||
|
||||
# Use zone directly if provided
|
||||
if [ "$GOOGLEDOMAINS_ZONE" ]; then
|
||||
if ! _dns_googledomains_api "$GOOGLEDOMAINS_ZONE"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "$GOOGLEDOMAINS_ZONE"
|
||||
return 0
|
||||
fi
|
||||
|
||||
i=2
|
||||
while true; do
|
||||
curr=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug curr "$curr"
|
||||
|
||||
if [ -z "$curr" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _dns_googledomains_api "$curr"; then
|
||||
echo "$curr"
|
||||
return 0
|
||||
fi
|
||||
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
_dns_googledomains_api() {
|
||||
zone=$1
|
||||
apimethod=$2
|
||||
data="$3"
|
||||
|
||||
if [ -z "$data" ]; then
|
||||
response="$(_get "$GOOGLEDOMAINS_API/$zone$apimethod")"
|
||||
else
|
||||
_debug data "$data"
|
||||
export _H1="Content-Type: application/json"
|
||||
response="$(_post "$data" "$GOOGLEDOMAINS_API/$zone$apimethod")"
|
||||
fi
|
||||
|
||||
_debug response "$response"
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "Error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "\"error\": {"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
@@ -23,7 +23,7 @@ dns_huaweicloud_add() {
|
||||
|
||||
HUAWEICLOUD_Username="${HUAWEICLOUD_Username:-$(_readaccountconf_mutable HUAWEICLOUD_Username)}"
|
||||
HUAWEICLOUD_Password="${HUAWEICLOUD_Password:-$(_readaccountconf_mutable HUAWEICLOUD_Password)}"
|
||||
HUAWEICLOUD_DomainName="${HUAWEICLOUD_DomainName:-$(_readaccountconf_mutable HUAWEICLOUD_Username)}"
|
||||
HUAWEICLOUD_DomainName="${HUAWEICLOUD_DomainName:-$(_readaccountconf_mutable HUAWEICLOUD_DomainName)}"
|
||||
|
||||
# Check information
|
||||
if [ -z "${HUAWEICLOUD_Username}" ] || [ -z "${HUAWEICLOUD_Password}" ] || [ -z "${HUAWEICLOUD_DomainName}" ]; then
|
||||
@@ -74,7 +74,7 @@ dns_huaweicloud_rm() {
|
||||
|
||||
HUAWEICLOUD_Username="${HUAWEICLOUD_Username:-$(_readaccountconf_mutable HUAWEICLOUD_Username)}"
|
||||
HUAWEICLOUD_Password="${HUAWEICLOUD_Password:-$(_readaccountconf_mutable HUAWEICLOUD_Password)}"
|
||||
HUAWEICLOUD_DomainName="${HUAWEICLOUD_DomainName:-$(_readaccountconf_mutable HUAWEICLOUD_Username)}"
|
||||
HUAWEICLOUD_DomainName="${HUAWEICLOUD_DomainName:-$(_readaccountconf_mutable HUAWEICLOUD_DomainName)}"
|
||||
|
||||
# Check information
|
||||
if [ -z "${HUAWEICLOUD_Username}" ] || [ -z "${HUAWEICLOUD_Password}" ] || [ -z "${HUAWEICLOUD_DomainName}" ]; then
|
||||
@@ -98,19 +98,59 @@ dns_huaweicloud_rm() {
|
||||
fi
|
||||
_debug "Zone ID is:" "${zoneid}"
|
||||
|
||||
# Remove all records
|
||||
# Therotically HuaweiCloud does not allow more than one record set
|
||||
# But remove them recurringly to increase robusty
|
||||
while [ "${record_id}" != "0" ]; do
|
||||
_debug "Removing Record"
|
||||
_rm_record "${token}" "${zoneid}" "${record_id}"
|
||||
record_id="$(_get_recordset_id "${token}" "${fulldomain}" "${zoneid}")"
|
||||
done
|
||||
record_id="$(_get_recordset_id "${token}" "${fulldomain}" "${zoneid}")"
|
||||
_recursive_rm_record "${token}" "${fulldomain}" "${zoneid}" "${record_id}"
|
||||
ret="$?"
|
||||
if [ "${ret}" != "0" ]; then
|
||||
_err "dns_api(dns_huaweicloud): Error removing record."
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
################### Private functions below ##################################
|
||||
|
||||
# _recursive_rm_record
|
||||
# remove all records from the record set
|
||||
#
|
||||
# _token=$1
|
||||
# _domain=$2
|
||||
# _zoneid=$3
|
||||
# _record_id=$4
|
||||
#
|
||||
# Returns 0 on success
|
||||
_recursive_rm_record() {
|
||||
_token=$1
|
||||
_domain=$2
|
||||
_zoneid=$3
|
||||
_record_id=$4
|
||||
|
||||
# Most likely to have problems will huaweicloud side if more than 50 attempts but still cannot fully remove the record set
|
||||
# Maybe can be removed manually in the dashboard
|
||||
_retry_cnt=50
|
||||
|
||||
# Remove all records
|
||||
# Therotically HuaweiCloud does not allow more than one record set
|
||||
# But remove them recurringly to increase robusty
|
||||
|
||||
while [ "${_record_id}" != "0" ] && [ "${_retry_cnt}" != "0" ]; do
|
||||
_debug "Removing Record"
|
||||
_retry_cnt=$((_retry_cnt - 1))
|
||||
_rm_record "${_token}" "${_zoneid}" "${_record_id}"
|
||||
_record_id="$(_get_recordset_id "${_token}" "${_domain}" "${_zoneid}")"
|
||||
_debug2 "Checking record exists: record_id=${_record_id}"
|
||||
done
|
||||
|
||||
# Check if retry count is reached
|
||||
if [ "${_retry_cnt}" = "0" ]; then
|
||||
_debug "Failed to remove record after 50 attempts, please try removing it manually in the dashboard"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# _get_zoneid
|
||||
#
|
||||
# _token=$1
|
||||
@@ -124,7 +164,7 @@ _get_zoneid() {
|
||||
|
||||
i=1
|
||||
while true; do
|
||||
h=$(printf "%s" "${_domain_string}" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "${_domain_string}" | cut -d . -f "$i"-100)
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
@@ -135,11 +175,11 @@ _get_zoneid() {
|
||||
if _contains "${response}" '"id"'; then
|
||||
zoneidlist=$(echo "${response}" | _egrep_o "\"id\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")
|
||||
zonenamelist=$(echo "${response}" | _egrep_o "\"name\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")
|
||||
_debug2 "Return Zone ID(s):" "${zoneidlist}"
|
||||
_debug2 "Return Zone Name(s):" "${zonenamelist}"
|
||||
_debug2 "Returned Zone ID(s):" "${zoneidlist}"
|
||||
_debug2 "Returned Zone Name(s):" "${zonenamelist}"
|
||||
zoneidnum=0
|
||||
zoneidcount=$(echo "${zoneidlist}" | grep -c '^')
|
||||
_debug "Retund Zone ID(s) Count:" "${zoneidcount}"
|
||||
_debug "Returned Zone ID(s) Count:" "${zoneidcount}"
|
||||
while [ "${zoneidnum}" -lt "${zoneidcount}" ]; do
|
||||
zoneidnum=$(_math "$zoneidnum" + 1)
|
||||
_zoneid=$(echo "${zoneidlist}" | sed -n "${zoneidnum}p")
|
||||
@@ -206,8 +246,7 @@ _add_record() {
|
||||
\"type\": \"TXT\",
|
||||
\"ttl\": 1,
|
||||
\"records\": [
|
||||
${_exist_record},
|
||||
\"\\\"${_txtvalue}\\\"\"
|
||||
${_exist_record},\"\\\"${_txtvalue}\\\"\"
|
||||
]
|
||||
}"
|
||||
fi
|
||||
@@ -215,19 +254,16 @@ _add_record() {
|
||||
_record_id="$(_get_recordset_id "${_token}" "${_domain}" "${zoneid}")"
|
||||
_debug "Record Set ID is:" "${_record_id}"
|
||||
|
||||
# Remove all records
|
||||
while [ "${_record_id}" != "0" ]; do
|
||||
_debug "Removing Record"
|
||||
_rm_record "${_token}" "${zoneid}" "${_record_id}"
|
||||
_record_id="$(_get_recordset_id "${_token}" "${_domain}" "${zoneid}")"
|
||||
done
|
||||
|
||||
# Add brand new records with all old and new records
|
||||
export _H2="Content-Type: application/json"
|
||||
export _H1="X-Auth-Token: ${_token}"
|
||||
|
||||
_debug2 "${_post_body}"
|
||||
_post "${_post_body}" "${dns_api}/v2/zones/${zoneid}/recordsets" >/dev/null
|
||||
if [ -z "${_exist_record}" ]; then
|
||||
_post "${_post_body}" "${dns_api}/v2/zones/${zoneid}/recordsets" >/dev/null
|
||||
else
|
||||
_post "${_post_body}" "${dns_api}/v2/zones/${zoneid}/recordsets/${_record_id}" false "PUT" >/dev/null
|
||||
fi
|
||||
_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")"
|
||||
if [ "$_code" != "202" ]; then
|
||||
_err "dns_huaweicloud: http code ${_code}"
|
||||
|
||||
157
dnsapi/dns_ipv64.sh
Executable file
157
dnsapi/dns_ipv64.sh
Executable file
@@ -0,0 +1,157 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#Created by Roman Lumetsberger, to use ipv64.net's API to add/remove text records
|
||||
#2022/11/29
|
||||
|
||||
# Pass credentials before "acme.sh --issue --dns dns_ipv64 ..."
|
||||
# --
|
||||
# export IPv64_Token="aaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
# --
|
||||
#
|
||||
|
||||
IPv64_API="https://ipv64.net/api"
|
||||
|
||||
######## Public functions ######################
|
||||
|
||||
#Usage: dns_ipv64_add _acme-challenge.domain.ipv64.net "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_ipv64_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
IPv64_Token="${IPv64_Token:-$(_readaccountconf_mutable IPv64_Token)}"
|
||||
if [ -z "$IPv64_Token" ]; then
|
||||
_err "You must export variable: IPv64_Token"
|
||||
_err "The API Key for your IPv64 account is necessary."
|
||||
_err "You can look it up in your IPv64 account."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Now save the credentials.
|
||||
_saveaccountconf_mutable IPv64_Token "$IPv64_Token"
|
||||
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain" "$fulldomain"
|
||||
return 1
|
||||
fi
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
# convert to lower case
|
||||
_domain="$(echo "$_domain" | _lower_case)"
|
||||
_sub_domain="$(echo "$_sub_domain" | _lower_case)"
|
||||
# Now add the TXT record
|
||||
_info "Trying to add TXT record"
|
||||
if _ipv64_rest "POST" "add_record=$_domain&praefix=$_sub_domain&type=TXT&content=$txtvalue"; then
|
||||
_info "TXT record has been successfully added."
|
||||
return 0
|
||||
else
|
||||
_err "Errors happened during adding the TXT record, response=$_response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
#Usage: fulldomain txtvalue
|
||||
#Usage: dns_ipv64_rm _acme-challenge.domain.ipv64.net "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
#Remove the txt record after validation.
|
||||
dns_ipv64_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
IPv64_Token="${IPv64_Token:-$(_readaccountconf_mutable IPv64_Token)}"
|
||||
if [ -z "$IPv64_Token" ]; then
|
||||
_err "You must export variable: IPv64_Token"
|
||||
_err "The API Key for your IPv64 account is necessary."
|
||||
_err "You can look it up in your IPv64 account."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain" "$fulldomain"
|
||||
return 1
|
||||
fi
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
# convert to lower case
|
||||
_domain="$(echo "$_domain" | _lower_case)"
|
||||
_sub_domain="$(echo "$_sub_domain" | _lower_case)"
|
||||
# Now delete the TXT record
|
||||
_info "Trying to delete TXT record"
|
||||
if _ipv64_rest "DELETE" "del_record=$_domain&praefix=$_sub_domain&type=TXT&content=$txtvalue"; then
|
||||
_info "TXT record has been successfully deleted."
|
||||
return 0
|
||||
else
|
||||
_err "Errors happened during deleting the TXT record, response=$_response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
_get_root() {
|
||||
domain="$1"
|
||||
i=1
|
||||
p=1
|
||||
|
||||
_ipv64_get "get_domains"
|
||||
domain_data=$_response
|
||||
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
#if _contains "$domain_data" "\""$h"\"\:"; then
|
||||
if _contains "$domain_data" "\"""$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
|
||||
}
|
||||
|
||||
#send get request to api
|
||||
# $1 has to set the api-function
|
||||
_ipv64_get() {
|
||||
url="$IPv64_API?$1"
|
||||
export _H1="Authorization: Bearer $IPv64_Token"
|
||||
|
||||
_response=$(_get "$url")
|
||||
_response="$(echo "$_response" | _normalizeJson)"
|
||||
|
||||
if _contains "$_response" "429 Too Many Requests"; then
|
||||
_info "API throttled, sleeping to reset the limit"
|
||||
_sleep 10
|
||||
_response=$(_get "$url")
|
||||
_response="$(echo "$_response" | _normalizeJson)"
|
||||
fi
|
||||
}
|
||||
|
||||
_ipv64_rest() {
|
||||
url="$IPv64_API"
|
||||
export _H1="Authorization: Bearer $IPv64_Token"
|
||||
export _H2="Content-Type: application/x-www-form-urlencoded"
|
||||
_response=$(_post "$2" "$url" "" "$1")
|
||||
|
||||
if _contains "$_response" "429 Too Many Requests"; then
|
||||
_info "API throttled, sleeping to reset the limit"
|
||||
_sleep 10
|
||||
_response=$(_post "$2" "$url" "" "$1")
|
||||
fi
|
||||
|
||||
if ! _contains "$_response" "\"info\":\"success\""; then
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$_response"
|
||||
return 0
|
||||
}
|
||||
@@ -215,7 +215,7 @@ _get_record_id() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
_record_id="$(echo "$response" | tr -d '\n\r' | sed "s/<item xsi:type=\"ns2:Map\">/\n/g" | grep -i "$_record_name" | grep -i ">TXT<" | sed "s/<item><key xsi:type=\"xsd:string\">record_id<\/key><value xsi:type=\"xsd:string\">/=>/g" | sed "s/<\/value><\/item>/\n/g" | grep "=>" | sed "s/=>//g")"
|
||||
_record_id="$(echo "$response" | tr -d '\n\r' | sed "s/<item xsi:type=\"ns2:Map\">/\n/g" | grep -i "$_record_name" | grep -i ">TXT<" | sed "s/<item><key xsi:type=\"xsd:string\">record_id<\/key><value xsi:type=\"xsd:string\">/=>/g" | grep -i "$_txtvalue" | sed "s/<\/value><\/item>/\n/g" | grep "=>" | sed "s/=>//g")"
|
||||
_debug "[KAS] -> Record Id: " "$_record_id"
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#See https://developer.leaseweb.com for more information.
|
||||
######## Public functions #####################
|
||||
|
||||
LSW_API="https://api.leaseweb.com/hosting/v2/domains/"
|
||||
LSW_API="https://api.leaseweb.com/hosting/v2/domains"
|
||||
|
||||
#Usage: dns_leaseweb_add _acme-challenge.www.domain.com
|
||||
dns_leaseweb_add() {
|
||||
|
||||
59
dnsapi/dns_nanelo.sh
Normal file
59
dnsapi/dns_nanelo.sh
Normal file
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Official DNS API for Nanelo.com
|
||||
|
||||
# Provide the required API Key like this:
|
||||
# NANELO_TOKEN="FmD408PdqT1E269gUK57"
|
||||
|
||||
NANELO_API="https://api.nanelo.com/v1/"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_nanelo_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
NANELO_TOKEN="${NANELO_TOKEN:-$(_readaccountconf_mutable NANELO_TOKEN)}"
|
||||
if [ -z "$NANELO_TOKEN" ]; then
|
||||
NANELO_TOKEN=""
|
||||
_err "You didn't configure a Nanelo API Key yet."
|
||||
_err "Please set NANELO_TOKEN and try again."
|
||||
_err "Login to Nanelo.com and go to Settings > API Keys to get a Key"
|
||||
return 1
|
||||
fi
|
||||
_saveaccountconf_mutable NANELO_TOKEN "$NANELO_TOKEN"
|
||||
|
||||
_info "Adding TXT record to ${fulldomain}"
|
||||
response="$(_get "$NANELO_API$NANELO_TOKEN/dns/addrecord?type=TXT&ttl=60&name=${fulldomain}&value=${txtvalue}")"
|
||||
if _contains "${response}" 'success'; then
|
||||
return 0
|
||||
fi
|
||||
_err "Could not create resource record, please check the logs"
|
||||
_err "${response}"
|
||||
return 1
|
||||
}
|
||||
|
||||
dns_nanelo_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
NANELO_TOKEN="${NANELO_TOKEN:-$(_readaccountconf_mutable NANELO_TOKEN)}"
|
||||
if [ -z "$NANELO_TOKEN" ]; then
|
||||
NANELO_TOKEN=""
|
||||
_err "You didn't configure a Nanelo API Key yet."
|
||||
_err "Please set NANELO_TOKEN and try again."
|
||||
_err "Login to Nanelo.com and go to Settings > API Keys to get a Key"
|
||||
return 1
|
||||
fi
|
||||
_saveaccountconf_mutable NANELO_TOKEN "$NANELO_TOKEN"
|
||||
|
||||
_info "Deleting resource record $fulldomain"
|
||||
response="$(_get "$NANELO_API$NANELO_TOKEN/dns/deleterecord?type=TXT&ttl=60&name=${fulldomain}&value=${txtvalue}")"
|
||||
if _contains "${response}" 'success'; then
|
||||
return 0
|
||||
fi
|
||||
_err "Could not delete resource record, please check the logs"
|
||||
_err "${response}"
|
||||
return 1
|
||||
}
|
||||
@@ -57,16 +57,16 @@ _dns_openstack_create_recordset() {
|
||||
|
||||
if [ -z "$_recordset_id" ]; then
|
||||
_info "Creating a new recordset"
|
||||
if ! _recordset_id=$(openstack recordset create -c id -f value --type TXT --record "$txtvalue" "$_zone_id" "$fulldomain."); then
|
||||
if ! _recordset_id=$(openstack recordset create -c id -f value --type TXT --record="$txtvalue" "$_zone_id" "$fulldomain."); then
|
||||
_err "No recordset ID found after create"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_info "Updating existing recordset"
|
||||
# Build new list of --record <rec> args for update
|
||||
_record_args="--record $txtvalue"
|
||||
# Build new list of --record=<rec> args for update
|
||||
_record_args="--record=$txtvalue"
|
||||
for _rec in $_records; do
|
||||
_record_args="$_record_args --record $_rec"
|
||||
_record_args="$_record_args --record=$_rec"
|
||||
done
|
||||
# shellcheck disable=SC2086
|
||||
if ! _recordset_id=$(openstack recordset set -c id -f value $_record_args "$_zone_id" "$fulldomain."); then
|
||||
@@ -107,13 +107,13 @@ _dns_openstack_delete_recordset() {
|
||||
fi
|
||||
else
|
||||
_info "Found existing records, updating recordset"
|
||||
# Build new list of --record <rec> args for update
|
||||
# Build new list of --record=<rec> args for update
|
||||
_record_args=""
|
||||
for _rec in $_records; do
|
||||
if [ "$_rec" = "$txtvalue" ]; then
|
||||
continue
|
||||
fi
|
||||
_record_args="$_record_args --record $_rec"
|
||||
_record_args="$_record_args --record=$_rec"
|
||||
done
|
||||
# shellcheck disable=SC2086
|
||||
if ! openstack recordset set -c id -f value $_record_args "$_zone_id" "$fulldomain." >/dev/null; then
|
||||
|
||||
@@ -137,7 +137,7 @@ _get_root() {
|
||||
domain=$1
|
||||
i=2
|
||||
p=1
|
||||
if _opns_rest "GET" "/domain/searchMasterDomain"; then
|
||||
if _opns_rest "GET" "/domain/searchPrimaryDomain"; then
|
||||
_domain_response="$response"
|
||||
else
|
||||
return 1
|
||||
@@ -150,7 +150,7 @@ _get_root() {
|
||||
return 1
|
||||
fi
|
||||
_debug h "$h"
|
||||
id=$(echo "$_domain_response" | _egrep_o "\"uuid\":\"[a-z0-9\-]*\",\"enabled\":\"1\",\"type\":\"master\",\"domainname\":\"${h}\"" | cut -d ':' -f 2 | cut -d '"' -f 2)
|
||||
id=$(echo "$_domain_response" | _egrep_o "\"uuid\":\"[a-z0-9\-]*\",\"enabled\":\"1\",\"type\":\"primary\",\"domainname\":\"${h}\"" | cut -d ':' -f 2 | cut -d '"' -f 2)
|
||||
if [ -n "$id" ]; then
|
||||
_debug id "$id"
|
||||
_host=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
#'ovh-eu'
|
||||
OVH_EU='https://eu.api.ovh.com/1.0'
|
||||
|
||||
#'ovh-us'
|
||||
OVH_US='https://api.us.ovhcloud.com/1.0'
|
||||
|
||||
#'ovh-ca':
|
||||
OVH_CA='https://ca.api.ovh.com/1.0'
|
||||
|
||||
@@ -29,9 +32,6 @@ SYS_EU='https://eu.api.soyoustart.com/1.0'
|
||||
#'soyoustart-ca'
|
||||
SYS_CA='https://ca.api.soyoustart.com/1.0'
|
||||
|
||||
#'runabove-ca'
|
||||
RAV_CA='https://api.runabove.com/1.0'
|
||||
|
||||
wiki="https://github.com/acmesh-official/acme.sh/wiki/How-to-use-OVH-domain-api"
|
||||
|
||||
ovh_success="https://github.com/acmesh-official/acme.sh/wiki/OVH-Success"
|
||||
@@ -45,6 +45,10 @@ _ovh_get_api() {
|
||||
printf "%s" $OVH_EU
|
||||
return
|
||||
;;
|
||||
ovh-us | ovhus)
|
||||
printf "%s" $OVH_US
|
||||
return
|
||||
;;
|
||||
ovh-ca | ovhca)
|
||||
printf "%s" $OVH_CA
|
||||
return
|
||||
@@ -65,14 +69,15 @@ _ovh_get_api() {
|
||||
printf "%s" $SYS_CA
|
||||
return
|
||||
;;
|
||||
runabove-ca | runaboveca)
|
||||
printf "%s" $RAV_CA
|
||||
# raw API url starts with https://
|
||||
https*)
|
||||
printf "%s" "$1"
|
||||
return
|
||||
;;
|
||||
|
||||
*)
|
||||
|
||||
_err "Unknown parameter : $1"
|
||||
_err "Unknown endpoint : $1"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -41,7 +41,7 @@ pleskxml_init_checks_done=0
|
||||
NEWLINE='\
|
||||
'
|
||||
|
||||
pleskxml_tplt_get_domains="<packet><customer><get-domain-list><filter/></get-domain-list></customer></packet>"
|
||||
pleskxml_tplt_get_domains="<packet><webspace><get><filter/><dataset><gen_info/></dataset></get></webspace></packet>"
|
||||
# Get a list of domains that PLESK can manage, so we can check root domain + host for acme.sh
|
||||
# Also used to test credentials and URI.
|
||||
# No params.
|
||||
@@ -145,22 +145,25 @@ dns_pleskxml_rm() {
|
||||
)"
|
||||
|
||||
if [ -z "$reclist" ]; then
|
||||
_err "No TXT records found for root domain ${root_domain_name} (Plesk domain ID ${root_domain_id}). Exiting."
|
||||
_err "No TXT records found for root domain $fulldomain (Plesk domain ID ${root_domain_id}). Exiting."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "Got list of DNS TXT records for root domain '$root_domain_name':"
|
||||
_debug "Got list of DNS TXT records for root Plesk domain ID ${root_domain_id} of root domain $fulldomain:"
|
||||
_debug "$reclist"
|
||||
|
||||
# Extracting the id of the TXT record for the full domain (NOT case-sensitive) and corresponding value
|
||||
recid="$(
|
||||
_value "$reclist" |
|
||||
grep "<host>${fulldomain}.</host>" |
|
||||
grep -i "<host>${fulldomain}.</host>" |
|
||||
grep "<value>${txtvalue}</value>" |
|
||||
sed 's/^.*<id>\([0-9]\{1,\}\)<\/id>.*$/\1/'
|
||||
)"
|
||||
|
||||
_debug "Got id from line: $recid"
|
||||
|
||||
if ! _value "$recid" | grep '^[0-9]\{1,\}$' >/dev/null; then
|
||||
_err "DNS records for root domain '${root_domain_name}' (Plesk ID ${root_domain_id}) + host '${sub_domain_name}' do not contain the TXT record '${txtvalue}'"
|
||||
_err "DNS records for root domain '${fulldomain}.' (Plesk ID ${root_domain_id}) + host '${sub_domain_name}' do not contain the TXT record '${txtvalue}'"
|
||||
_err "Cannot delete TXT record. Exiting."
|
||||
return 1
|
||||
fi
|
||||
@@ -251,9 +254,12 @@ _call_api() {
|
||||
|
||||
# Detect any <status> that isn't "ok". None of the used calls should fail if the API is working correctly.
|
||||
# Also detect if there simply aren't any status lines (null result?) and report that, as well.
|
||||
# Remove <data></data> structure from result string, since it might contain <status> values that are related to the status of the domain and not to the API request
|
||||
|
||||
statuslines_count_total="$(echo "$pleskxml_prettyprint_result" | grep -c '^ *<status>[^<]*</status> *$')"
|
||||
statuslines_count_okay="$(echo "$pleskxml_prettyprint_result" | grep -c '^ *<status>ok</status> *$')"
|
||||
statuslines_count_total="$(echo "$pleskxml_prettyprint_result" | sed '/<data>/,/<\/data>/d' | grep -c '^ *<status>[^<]*</status> *$')"
|
||||
statuslines_count_okay="$(echo "$pleskxml_prettyprint_result" | sed '/<data>/,/<\/data>/d' | grep -c '^ *<status>ok</status> *$')"
|
||||
_debug "statuslines_count_total=$statuslines_count_total."
|
||||
_debug "statuslines_count_okay=$statuslines_count_okay."
|
||||
|
||||
if [ -z "$statuslines_count_total" ]; then
|
||||
|
||||
@@ -375,7 +381,7 @@ _pleskxml_get_root_domain() {
|
||||
# Output will be one line per known domain, containing 2 <name> tages and a single <id> tag
|
||||
# We don't actually need to check for type, name, *and* id, but it guarantees only usable lines are returned.
|
||||
|
||||
output="$(_api_response_split "$pleskxml_prettyprint_result" 'domain' '<type>domain</type>' | sed 's/<ascii-name>/<name>/g;s/<\/ascii-name>/<\/name>/g' | grep '<name>' | grep '<id>')"
|
||||
output="$(_api_response_split "$pleskxml_prettyprint_result" 'result' '<status>ok</status>' | sed 's/<ascii-name>/<name>/g;s/<\/ascii-name>/<\/name>/g' | grep '<name>' | grep '<id>')"
|
||||
|
||||
_debug 'Domains managed by Plesk server are (ignore the hacked output):'
|
||||
_debug "$output"
|
||||
|
||||
@@ -78,7 +78,7 @@ dns_vultr_rm() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
_record_id="$(echo "$response" | tr '{}' '\n' | grep '"TXT"' | grep -- "$txtvalue" | tr ',' '\n' | grep -i 'id' | cut -d : -f 2)"
|
||||
_record_id="$(echo "$response" | tr '{}' '\n' | grep '"TXT"' | grep -- "$txtvalue" | tr ',' '\n' | grep -i 'id' | cut -d : -f 2 | tr -d '"')"
|
||||
_debug _record_id "$_record_id"
|
||||
if [ "$_record_id" ]; then
|
||||
_info "Successfully retrieved the record id for ACME challenge."
|
||||
@@ -116,7 +116,7 @@ _get_root() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if printf "%s\n" "$response" | grep '^\{.*\}' >/dev/null; then
|
||||
if printf "%s\n" "$response" | grep -E '^\{.*\}' >/dev/null; then
|
||||
if _contains "$response" "\"domain\":\"$_domain\""; then
|
||||
_sub_domain="$(echo "$fulldomain" | sed "s/\\.$_domain\$//")"
|
||||
return 0
|
||||
|
||||
@@ -169,7 +169,7 @@ _clean_email_header() {
|
||||
# email
|
||||
_email_has_display_name() {
|
||||
_email="$1"
|
||||
expr "$_email" : '^.*[<>"]' >/dev/null
|
||||
echo "$_email" | grep -q -E '^.*[<>"]'
|
||||
}
|
||||
|
||||
##
|
||||
@@ -249,7 +249,7 @@ _mime_encoded_word() {
|
||||
_text="$1"
|
||||
# (regex character ranges like [a-z] can be locale-dependent; enumerate ASCII chars to avoid that)
|
||||
_ascii='] $`"'"[!#%&'()*+,./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ~^_abcdefghijklmnopqrstuvwxyz{|}~-"
|
||||
if expr "$_text" : "^.*[^$_ascii]" >/dev/null; then
|
||||
if echo "$_text" | grep -q -E "^.*[^$_ascii]"; then
|
||||
# At least one non-ASCII char; convert entire thing to encoded word
|
||||
printf "%s" "=?UTF-8?B?$(printf "%s" "$_text" | _base64)?="
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user