Compare commits

..

133 Commits
3.0.2 ... 3.0.4

Author SHA1 Message Date
neil
e6959f093c Merge pull request #4070 from acmesh-official/dev
sync
2022-05-06 18:06:37 +08:00
neilpang
8d783e8e1f fix https://github.com/acmesh-official/acme.sh/issues/4069 2022-05-06 18:04:29 +08:00
neilpang
f03098551e start 3.0.4 2022-05-04 18:44:37 +08:00
neil
6887805402 Merge pull request #4067 from acmesh-official/dev
sync
2022-05-04 18:36:45 +08:00
neil
7f9074adbf fix format 2022-05-03 21:35:26 +08:00
neil
64847afc3f save the default key length 2022-05-03 21:19:29 +08:00
neil
641f6977a9 Merge pull request #4065 from acmesh-official/dev
sync
2022-05-03 18:38:45 +08:00
neil
84c2b0c3d7 Merge pull request #4063 from nicolaspn/OVH_DNS_refresh_after_delete_txt_record
Ovh dns refresh after delete txt record
2022-05-02 23:34:14 +08:00
nicolaspn
24ce7c1991 Add call dns OVH API for refresh domain after delete TXT record 2022-05-02 16:16:56 +02:00
neil
8be3465f94 Merge pull request #4061 from acmesh-official/dev
Dev
2022-04-30 22:47:57 +08:00
neil
8ba7d02fdb Merge pull request #4059 from NerLOR/master
dns_world4you: fix _parse_paket_nr
2022-04-29 14:48:31 +08:00
neil
ef8a199a5a Merge pull request #4057 from mrakopes/master
issue 3007 - fix base64 decoding logic for single- and multi-line encoded string
2022-04-29 09:25:39 +08:00
Lorenz Stechauner
db83643c1e dns_world4you: fix _parse_paket_nr
Signed-off-by: Lorenz Stechauner <lorenz.stechauner@necronda.net>
2022-04-28 20:49:55 +02:00
mrakopes
9b6f775276 fix base64 decoding logic for single- ane multi-line encoded string 2022-04-28 13:25:22 +02:00
neilpang
69040dd668 fix format 2022-04-28 18:09:26 +08:00
neilpang
14b5914233 fix renew bug 2022-04-28 18:06:07 +08:00
neil
a0eabd2298 Merge pull request #4049 from Aarup/dev
Removed GratisDNS api
2022-04-25 16:10:39 +08:00
Jakob Aarup Skov
9b27298d54 Removed GratisDNS api 2022-04-25 09:43:38 +02:00
neil
3075b4515a Merge pull request #4045 from axelhahn/4044-use-challenge-alias-false
handle challenge-alias "false"
2022-04-21 16:35:29 +08:00
neil
39bc417706 Update acme.sh 2022-04-21 07:02:53 +08:00
neil
e11e32cd52 Merge pull request #4035 from ccope-netgate/master
LoopiaAPI error handling isn't compatible with FreeBSD
2022-04-21 06:58:44 +08:00
Hahn Axel (hahn)
019a7bd66b handle challenge-alias "false" 2022-04-20 16:03:36 +02:00
neil
4d89ce5d50 read csr with empty subject
https://github.com/acmesh-official/acme.sh/issues/4024
2022-04-20 09:14:53 +08:00
Sing Yu Chan
c31027b284 use sleep infinity instead sleep 1 2022-04-20 09:04:13 +08:00
neil
f17ec7a4f5 Merge pull request #4037 from ahwayakchih/master
Update dns_mydevil.sh
2022-04-20 09:01:29 +08:00
neil
deec6aab1a Merge pull request #4039 from DerVerruckteFuchs/1984-update-URL
1984 update url
2022-04-20 09:00:14 +08:00
Bruce Lam
3e8d9a1987 added: ipv6 identifier support 2022-04-20 08:23:22 +08:00
DerVerruckteFuchs
5e465a298f Update 1984 Hosting's URL 2022-04-15 23:04:10 -04:00
Marcin Konicki
515c9e7811 Fix DNS handling for MyDevil.net
MyDevil updated their tool to require y|n confirmation when deleting record.
2022-04-15 10:38:45 +02:00
Christopher Cope
03c8309703 Fix dns_loopia on FreeBSD 2022-04-13 15:41:44 -04:00
neilpang
2c28d6b10c fix for renew server 2022-04-13 20:20:28 +08:00
neil
df79443ed8 Merge pull request #3997 from tumarov/fornex_com_support
fornex.com API support
2022-04-12 11:01:53 +08:00
neil
2b891f7f1d Update dns_fornex.sh 2022-04-12 10:11:05 +08:00
neil
e4ed0b1884 Merge pull request #4029 from quthla/patch-1
Store Mailcow deploy parameters
2022-04-12 10:06:35 +08:00
neil
c8c1c09189 Merge pull request #4032 from acmesh-official/dev
sync
2022-04-12 10:05:22 +08:00
quthla
08ae8cc3cb Fix 2022-04-11 11:39:21 +02:00
quthla
201673ca8a Store Mailcow deploy parameters 2022-04-11 00:29:55 +02:00
Bruce Lam
29e23ac9ce Due to down of cloudxns.net, remove dns_cx.sh 2022-04-10 19:57:25 +08:00
neilpang
00483e8cdd exclude zerossl tests in the CI
It's not stable
2022-04-10 19:42:49 +08:00
neil
83da01a2e1 Merge pull request #4027 from acmesh-official/dev
sync
2022-04-10 14:49:09 +08:00
neil
7cd6ff054b add 2022-04-10 14:48:10 +08:00
neilpang
6be2bb2289 Update acme.sh
revert only when there is no `--server` specified.
2022-04-08 22:28:21 +08:00
neilpang
439defca42 switch from staging api to production api
https://github.com/acmesh-official/acme.sh/issues/2401
2022-04-08 22:15:26 +08:00
neil
8a85bb2989 Merge pull request #4017 from exogee-technology/dev
Fix / Netlify API should only match exact domain matches.
2022-04-08 21:03:54 +08:00
neil
5e7519183d Merge pull request #4020 from sjau/dns_ispconfig_typo
dns_ispconfig: add missing brackets
2022-04-07 17:29:25 +08:00
hyper_ch
40e7eca1ee dns_ispconfig: adding missing brackets 2022-04-07 11:07:06 +02:00
Kevin Brown
481f02de88 Also check for the closing quote so that only exact domain matches are found. 2022-04-06 14:29:25 +10:00
neilpang
6a90856f0e don't renew cert if valid-to is set to an absolute date
don't renew cert if valid-to is set to an absolute date
2022-04-05 17:05:33 +08:00
neil
dcbbee8adb Merge pull request #4012 from acmesh-official/dev
Support "NotBefore" and NotAfter
2022-04-03 22:01:00 +08:00
neilpang
225adcc836 fix renewal for validto
fix renewal for validto
2022-04-03 21:58:41 +08:00
neilpang
0f607413d0 fix for solaris time format 2022-04-03 20:05:30 +08:00
neilpang
922553032b typo 2022-04-02 09:35:17 +08:00
neilpang
b49999721c Update acme.sh 2022-04-01 21:58:29 +08:00
neilpang
de4c4eedd8 Support NotBefore and NotAfter
Add `--valid-from` and `--valid-to`:
https://github.com/acmesh-official/acme.sh/wiki/Validity
2022-04-01 21:22:42 +08:00
neilpang
bcc984fc09 minor 2022-03-31 09:46:42 +08:00
neilpang
d53262fab6 fix update account
fix https://github.com/acmesh-official/acme.sh/issues/4009
2022-03-31 09:35:32 +08:00
neilpang
532e44bcea normalize domains
fix https://github.com/acmesh-official/acme.sh/issues/4005
2022-03-30 23:37:38 +08:00
neilpang
3fb67629c1 Update README.md 2022-03-30 23:06:07 +08:00
neil
6145465823 Merge pull request #4006 from acmesh-official/dev
sync
2022-03-30 23:03:44 +08:00
neilpang
fb5091a388 support Google ACME server
see: https://github.com/acmesh-official/acme.sh/wiki/Server
2022-03-30 22:47:12 +08:00
neilpang
0d05f9ba80 Update acme.sh
fix https://github.com/acmesh-official/acme.sh/issues/4001
2022-03-27 12:08:24 +08:00
neil
a300df0020 Update dns_fornex.sh 2022-03-25 15:48:17 +08:00
neil
a50158cbeb Merge pull request #3982 from waldner/master
Geoscaling: read credentials when removing records too
2022-03-24 15:15:58 +08:00
Timur Umarov
7278fd25e5 Added fornex.com api 2022-03-23 17:46:38 +03:00
neil
6fb8c0ec4c Merge pull request #3989 from abiessmann/deploy_routeros_handle_remote_errors
deploy/routeros: handle errors
2022-03-20 13:30:58 +08:00
neil
07cedc55e2 Merge pull request #3978 from nikolajbrinch/dev
Fixes Simply.com to use REST API version 2 with Basic Auth
2022-03-20 13:19:13 +08:00
neil
ae3cc81f03 Merge pull request #2924 from ianepperson/master
Add Discord notification
2022-03-20 12:43:43 +08:00
neil
97a45e3b02 Update discord.sh 2022-03-20 12:43:23 +08:00
neil
451b290b79 Update discord.sh 2022-03-20 12:42:35 +08:00
neil
499ea07934 Merge pull request #3993 from imgrant/deploy-truenas-s3-feature
feat: Configure TrueNAS S3 certificate
2022-03-20 12:34:58 +08:00
Ian Grant
afa06267a2 style: Neaten up some of the info & error messages, fix some typos 2022-03-19 20:39:48 +00:00
Ian Grant
d4a6d9c076 fix: Adjust the sed extraction of certificate ID from JSON response
Prior to this, an error in the regex didn't match. Resolves #3992 (TrueNAS deploy hook fails to set certificate for FTP or WebDAV)
2022-03-19 20:38:47 +00:00
Ian Grant
c3f6112443 feat: Configure certificate for TrueNAS S3 service (MinIO) 2022-03-19 20:36:11 +00:00
Andreas Bießmann
3411b736dd deploy/routeros: add error handling for scp
In order to stop processing on failure to copy certificate
to remote side, fail on error of scp command.

Signed-off-by: Andreas Bießmann <andreas@biessmann.org>
2022-03-18 09:10:12 +01:00
Andreas Bießmann
c603b9c40b deploy/routeros: add error handling for ssh
In order to detect errorneous scripts on remote side, catch return code
and handle it respectively.

Signed-off-by: Andreas Bießmann <andreas@biessmann.org>
Reviewed-by: Ross Shen @sjtuross
2022-03-18 09:07:59 +01:00
neil
1e2c5d038f Merge pull request #3986 from abiessmann/fix_depoly_routeros
deploy/routeros.sh: fix routeros script
2022-03-17 21:25:59 +08:00
Andreas Bießmann
9d6d96adf3 deploy/routeros.sh: fix routeros script
Commit c46ceb06b4 introduced an error in
routeros script.

Fix it!

Signed-off-by: Andreas Bießmann <andreas@biessmann.org>
2022-03-17 12:24:42 +01:00
waldner
8d574ecb34 Geoscaling: get creds for removal too 2022-03-15 18:56:54 +01:00
neil
9ebb2ac2e4 Merge pull request #3980 from acmesh-official/dev
sync
2022-03-14 23:02:08 +08:00
neil
7b935eec5d Merge pull request #3979 from dislazy/dev
fix(notify):remove nofity,move weixin_work.sh to notify
2022-03-11 13:56:53 +08:00
bosong
b209f66654 fix(notify):remove nofity,move weixin_work.sh to notify 2022-03-11 13:41:12 +08:00
neil
b98b4951b4 Merge pull request #3669 from youuy/master
Add Weixin Work notify hook
2022-03-11 12:21:55 +08:00
Nikolaj Brinch Jørgensen
227d62a5dc Fixes Simply.com to use REST API version 2 with Basic Auth 2022-03-10 11:13:38 +01:00
neil
7fae5553a8 Merge pull request #3977 from gabbe/Encode_password
Accept some special characters in password and some error handling
2022-03-10 09:10:17 +08:00
Gabriel Thörnblad
6ead019873 Accept some special characters in password and added a little bit better error handling 2022-03-09 17:12:09 +01:00
neil
e58b00d9a2 Merge pull request #3964 from gabbe/Loopia_API_is_updated
Update dns_loopia.sh
2022-03-07 21:52:03 +08:00
Gabriel Thörnblad
b75e90f8c9 Double quote variables (shellcheck suggestions) 2022-03-07 10:28:09 +01:00
Gabriel Thörnblad
e82f3439c3 Trigger CI 2022-03-07 10:13:45 +01:00
neil
0bc8e3bee5 Merge pull request #3965 from waldner/master
geoscaling DNS API
2022-03-07 09:08:01 +08:00
waldner
13f80acb2d geoscaling DNS API 2022-03-05 19:34:36 +01:00
neil
8fe813acff Merge pull request #3932 from peterlh/master
Added curanet dns support
2022-03-05 18:58:14 +08:00
Gabriel Thörnblad
0ed4fc6a12 Update dns_loopia.sh
Loopia API is now less tolerant so we need another <value> tag surrounding the <struct>
2022-03-04 13:38:05 +01:00
neil
e88442cb46 Merge pull request #3947 from abiessmann/deploy_routeros_fixes
deploy/routeros.sh fixes
2022-02-22 21:52:36 +08:00
neil
930609e875 Merge pull request #3948 from richard-9000/richard-9000-patch-1
dns_opnsense.sh - Fixed the domain parse regex
2022-02-22 21:41:22 +08:00
richard-9000
8752d08ce9 dns_opnsense.sh - Fixed the domain parse regex
Extended the regex to skip the new transferkey and hmac sections of opnsense bind.
2022-02-19 10:52:24 -08:00
Andreas Bießmann
c46ceb06b4 deploy/routeros.sh: change DEPLOY_SCRIPT_CMD
This set the owner of script to ssh user, have the comment line in script
as real comment and removes policy since this is set from current user,
at least for RouterOS 7.x.

Signed-off-by: Andreas Bießmann <andreas@biessmann.org>
2022-02-19 14:13:01 +01:00
Andreas Bießmann
92e4ecce3b deploy/routeros.sh: remove all certificates
As the script is applying the fullchain which includes three certificates,
delete all of them before applying updated certificate.

Signed-off-by: Andreas Bießmann <andreas@biessmann.org>
2022-02-19 14:13:01 +01:00
Andreas Bießmann
8a2f673903 deploy/routeros.sh: make ssh/scp configurable
In order to modify ssh/scp commands make them configurable via
environment variables.

Signed-off-by: Andreas Bießmann <andreas@biessmann.org>
2022-02-19 14:12:59 +01:00
peter
9a677534a7 added more debug info when rm recordid is empty 2022-02-13 14:00:14 +01:00
peter
af08d67fad rem. ; 2022-02-12 23:41:26 +01:00
peter
a2901d61ea check for return values 2022-02-12 23:39:33 +01:00
peter
aaae83efec check for return values 2022-02-12 20:18:08 +01:00
neil
7369298638 Merge pull request #3921 from andischerer/master
Added united-domains Reselling DNS API
2022-02-11 21:24:40 +08:00
neil
a761bd20fa Merge pull request #3934 from mac-zhou/dev
Add environment variables ROUTER_OS_PORT
2022-02-11 21:13:27 +08:00
neilpang
01ace11293 Update dns_ispconfig.sh
fix https://github.com/acmesh-official/acme.sh/issues/3895#issuecomment-1035409954
2022-02-11 21:11:04 +08:00
Mac_Zhou
205e95a246 Add environment variables ROUTER_OS_PORT 2022-02-10 11:29:09 +08:00
neil
2c2a43e1ec Update dns_cf.sh
if CF_Zone_ID is used,  save it to domain conf instead.
2022-02-09 18:08:55 +08:00
peter
0c9a6da623 more specific delete of records 2022-02-08 17:18:48 +01:00
Andreas Scherer
888d91d14a FIX dns_udr api: loop variable 2022-02-08 15:57:19 +01:00
peter
2c0cc87b4c final commit 2022-02-08 13:49:04 +01:00
peter
ee0fadf247 shfmt 2022-02-08 13:34:42 +01:00
peter
9fb89d7fd2 shfmt 2022-02-08 13:33:43 +01:00
peter
af5c36e4ad shfmt' 2022-02-08 13:32:15 +01:00
peter
a5f943e227 removed unused variable 2022-02-08 13:24:31 +01:00
peter
f8532ba812 removed unused variable 2022-02-08 13:21:02 +01:00
peter
fac4e151cc description 2022-02-08 13:19:22 +01:00
Andreas Scherer
f3a0a25380 FIX dns_udr api: ttl, xargs, cleanup 2022-02-08 08:05:48 +01:00
neil
5a237795ea Merge pull request #3928 from johnelliott/missing-oathtool-dep-error
Add err log for missing oathtool in Synology
2022-02-08 14:26:06 +08:00
John Elliott
3a99a77104 Update return statement 2022-02-07 21:55:12 -08:00
John Elliott
5ce8050e46 Update missing oathtool check 2022-02-07 11:58:14 -08:00
John Elliott
5ae3a020bd Add err log for missing oathtool in Synology
Alerts the user that the oathtool is missing and the TOTP can't be
generated.
2022-02-07 11:53:24 -08:00
neilpang
af193291fa Update acme.sh
fix https://github.com/acmesh-official/acme.sh/issues/3127#issuecomment-1030742187
2022-02-06 16:17:04 +08:00
neil
b39df5cef0 Merge pull request #3906 from NerLOR/master
Adapt dns_world4you to new world4you website behaviour
2022-02-06 09:52:45 +08:00
peter
dc61c9e277 description 2022-02-05 22:21:18 +01:00
peter
10a15e1188 nothing 2022-02-05 21:12:36 +01:00
peterlh
a2bb6a4f1f changed gettoken to use _post
changed gettoken to use _post instead of curl+jq
2022-02-05 21:07:04 +01:00
peterlh
38a19fa574 created dns_curanet.sh 2022-02-05 20:54:30 +01:00
neilpang
9ec4b59afb start v3.0.3
start v3.0.3
2022-02-05 21:28:07 +08:00
Lorenz Stechauner
20877146df Merge branch 'acmesh-official:master' into master 2022-02-04 20:36:31 +01:00
Andreas Scherer
a7f2d89e3f Added united-domains Reselling DNS API 2022-02-01 14:46:20 +01:00
Lorenz Stechauner
190ec0c14c Adapt dns_world4you to new world4you website behaviour 2022-01-24 16:47:47 +01:00
Leo
6d84f59e6b Add Weixin Work notify hook 2021-08-21 04:11:21 +08:00
Ian Epperson
748cb28017 Add Discord notification 2020-05-13 10:39:11 -07:00
30 changed files with 1321 additions and 545 deletions

2
.github/FUNDING.yml vendored
View File

@@ -3,7 +3,7 @@
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: acmesh
ko_fi: # Replace with a single Ko-fi username
ko_fi: neilpang
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username

View File

@@ -25,11 +25,11 @@ jobs:
CA: ""
CA_EMAIL: ""
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
- TEST_ACME_Server: "ZeroSSL.com"
CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
CA: "ZeroSSL RSA Domain Secure Site CA"
CA_EMAIL: "githubtest@acme.sh"
TEST_PREFERRED_CHAIN: ""
#- TEST_ACME_Server: "ZeroSSL.com"
# CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
# CA: "ZeroSSL RSA Domain Secure Site CA"
# CA_EMAIL: "githubtest@acme.sh"
# TEST_PREFERRED_CHAIN: ""
runs-on: macos-10.15
env:
TEST_LOCAL: 1

View File

@@ -25,11 +25,11 @@ jobs:
CA: ""
CA_EMAIL: ""
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
- TEST_ACME_Server: "ZeroSSL.com"
CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
CA: "ZeroSSL RSA Domain Secure Site CA"
CA_EMAIL: "githubtest@acme.sh"
TEST_PREFERRED_CHAIN: ""
#- TEST_ACME_Server: "ZeroSSL.com"
# CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
# CA: "ZeroSSL RSA Domain Secure Site CA"
# CA_EMAIL: "githubtest@acme.sh"
# TEST_PREFERRED_CHAIN: ""
runs-on: macos-latest
env:
TEST_LOCAL: 1

View File

@@ -25,11 +25,11 @@ jobs:
CA: ""
CA_EMAIL: ""
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
- TEST_ACME_Server: "ZeroSSL.com"
CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
CA: "ZeroSSL RSA Domain Secure Site CA"
CA_EMAIL: "githubtest@acme.sh"
TEST_PREFERRED_CHAIN: ""
#- TEST_ACME_Server: "ZeroSSL.com"
# CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
# CA: "ZeroSSL RSA Domain Secure Site CA"
# CA_EMAIL: "githubtest@acme.sh"
# TEST_PREFERRED_CHAIN: ""
runs-on: macos-10.15
env:
TEST_LOCAL: 1

View File

@@ -25,11 +25,11 @@ jobs:
CA: ""
CA_EMAIL: ""
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
- TEST_ACME_Server: "ZeroSSL.com"
CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
CA: "ZeroSSL RSA Domain Secure Site CA"
CA_EMAIL: "githubtest@acme.sh"
TEST_PREFERRED_CHAIN: ""
#- TEST_ACME_Server: "ZeroSSL.com"
# CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
# CA: "ZeroSSL RSA Domain Secure Site CA"
# CA_EMAIL: "githubtest@acme.sh"
# TEST_PREFERRED_CHAIN: ""
runs-on: windows-latest
env:
TEST_ACME_Server: ${{ matrix.TEST_ACME_Server }}

View File

@@ -65,7 +65,8 @@ 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 && while true; do sleep 1; done;\n \
crond && sleep infinity &\n \
wait \n \
else \n \
exec -- \"\$@\"\n \
fi" >/entry.sh && chmod +x /entry.sh

View File

@@ -95,6 +95,7 @@ https://github.com/acmesh-official/acmetest
- Letsencrypt.org CA
- [BuyPass.com CA](https://github.com/acmesh-official/acme.sh/wiki/BuyPass.com-CA)
- [SSL.com CA](https://github.com/acmesh-official/acme.sh/wiki/SSL.com-CA)
- [Google.com Public CA](https://github.com/acmesh-official/acme.sh/wiki/Google-Public-CA)
- [Pebble strict Mode](https://github.com/letsencrypt/pebble)
- Any other [RFC8555](https://tools.ietf.org/html/rfc8555)-compliant CA

271
acme.sh
View File

@@ -1,6 +1,6 @@
#!/usr/bin/env sh
VER=3.0.2
VER=3.0.4
PROJECT_NAME="acme.sh"
@@ -34,6 +34,9 @@ _ZERO_EAB_ENDPOINT="https://api.zerossl.com/acme/eab-credentials-email"
CA_SSLCOM_RSA="https://acme.ssl.com/sslcom-dv-rsa"
CA_SSLCOM_ECC="https://acme.ssl.com/sslcom-dv-ecc"
CA_GOOGLE="https://dv.acme-v02.api.pki.goog/directory"
CA_GOOGLE_TEST="https://dv.acme-v02.test-api.pki.goog/directory"
DEFAULT_CA=$CA_ZEROSSL
DEFAULT_STAGING_CA=$CA_LETSENCRYPT_V2_TEST
@@ -44,9 +47,11 @@ LetsEncrypt.org_test,letsencrypt_test,letsencrypttest
BuyPass.com,buypass
BuyPass.com_test,buypass_test,buypasstest
SSL.com,sslcom
Google.com,google
Google.com_test,googletest,google_test
"
CA_SERVERS="$CA_ZEROSSL,$CA_LETSENCRYPT_V2,$CA_LETSENCRYPT_V2_TEST,$CA_BUYPASS,$CA_BUYPASS_TEST,$CA_SSLCOM_RSA"
CA_SERVERS="$CA_ZEROSSL,$CA_LETSENCRYPT_V2,$CA_LETSENCRYPT_V2_TEST,$CA_BUYPASS,$CA_BUYPASS_TEST,$CA_SSLCOM_RSA,$CA_GOOGLE,$CA_GOOGLE_TEST"
DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)"
@@ -172,6 +177,8 @@ _SERVER_WIKI="https://github.com/acmesh-official/acme.sh/wiki/Server"
_PREFERRED_CHAIN_WIKI="https://github.com/acmesh-official/acme.sh/wiki/Preferred-Chain"
_VALIDITY_WIKI="https://github.com/acmesh-official/acme.sh/wiki/Validity"
_DNSCHECK_WIKI="https://github.com/acmesh-official/acme.sh/wiki/dnscheck"
_DNS_MANUAL_ERR="The dns manual mode can not renew automatically, you must issue it again manually. You'd better use the other modes instead."
@@ -976,9 +983,9 @@ _base64() {
#Usage: multiline
_dbase64() {
if [ "$1" ]; then
${ACME_OPENSSL_BIN:-openssl} base64 -d -A
else
${ACME_OPENSSL_BIN:-openssl} base64 -d
else
${ACME_OPENSSL_BIN:-openssl} base64 -d -A
fi
}
@@ -1141,13 +1148,19 @@ _createkey() {
_debug "Use length $length"
if ! touch "$f" >/dev/null 2>&1; then
_f_path="$(dirname "$f")"
_debug _f_path "$_f_path"
if ! mkdir -p "$_f_path"; then
_err "Can not create path: $_f_path"
if ! [ -e "$f" ]; then
if ! touch "$f" >/dev/null 2>&1; then
_f_path="$(dirname "$f")"
_debug _f_path "$_f_path"
if ! mkdir -p "$_f_path"; then
_err "Can not create path: $_f_path"
return 1
fi
fi
if ! touch "$f" >/dev/null 2>&1; then
return 1
fi
chmod 600 "$f"
fi
if _isEccKey "$length"; then
@@ -1495,7 +1508,6 @@ _create_account_key() {
else
#generate account key
if _createkey "$length" "$ACCOUNT_KEY_PATH"; then
chmod 600 "$ACCOUNT_KEY_PATH"
_info "Create account key ok."
return 0
else
@@ -1593,23 +1605,22 @@ _durl_replace_base64() {
_time2str() {
#BSD
if date -u -r "$1" 2>/dev/null; then
if date -u -r "$1" -j "+%Y-%m-%dT%H:%M:%SZ" 2>/dev/null; then
return
fi
#Linux
if date -u -d@"$1" 2>/dev/null; then
if date -u --date=@"$1" "+%Y-%m-%dT%H:%M:%SZ" 2>/dev/null; then
return
fi
#Solaris
if _exists adb; then
_t_s_a=$(echo "0t${1}=Y" | adb)
echo "$_t_s_a"
if printf "%(%Y-%m-%dT%H:%M:%SZ)T\n" $1 2>/dev/null; then
return
fi
#Busybox
if echo "$1" | awk '{ print strftime("%c", $0); }' 2>/dev/null; then
if echo "$1" | awk '{ print strftime("%Y-%m-%dT%H:%M:%SZ", $0); }' 2>/dev/null; then
return
fi
}
@@ -1768,6 +1779,27 @@ _time() {
date -u "+%s"
}
#support 2 formats:
# 2022-04-01 08:10:33 to 1648800633
#or 2022-04-01T08:10:33Z to 1648800633
_date2time() {
#Linux
if date -u -d "$(echo "$1" | tr -d "Z" | tr "T" ' ')" +"%s" 2>/dev/null; then
return
fi
#Solaris
if gdate -u -d "$(echo "$1" | tr -d "Z" | tr "T" ' ')" +"%s" 2>/dev/null; then
return
fi
#Mac/BSD
if date -u -j -f "%Y-%m-%d %H:%M:%S" "$(echo "$1" | tr -d "Z" | tr "T" ' ')" +"%s" 2>/dev/null; then
return
fi
_err "Can not parse _date2time $1"
return 1
}
_utc_date() {
date -u "+%Y-%m-%d %H:%M:%S"
}
@@ -1840,7 +1872,9 @@ _inithttp() {
_ACME_WGET="$_ACME_WGET --max-redirect 0 "
fi
if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
_ACME_WGET="$_ACME_WGET -d "
if [ "$_ACME_WGET" ] && _contains "$($_ACME_WGET --help 2>&1)" "--debug"; then
_ACME_WGET="$_ACME_WGET -d "
fi
fi
if [ "$CA_PATH" ]; then
_ACME_WGET="$_ACME_WGET --ca-directory=$CA_PATH "
@@ -2657,6 +2691,13 @@ _initAPI() {
return 1
}
_clearCA() {
export ACME_DIRECTORY=
export CA_CONF=
export ACCOUNT_KEY_PATH=
export ACCOUNT_JSON_PATH=
}
#[domain] [keylength or isEcc flag]
_initpath() {
domain="$1"
@@ -3746,7 +3787,7 @@ updateaccount() {
_email="$(_getAccountEmail)"
if [ "$ACCOUNT_EMAIL" ]; then
if [ "$_email" ]; then
updjson='{"contact": ["mailto:'$_email'"]}'
else
updjson='{"contact": []}'
@@ -3756,7 +3797,7 @@ updateaccount() {
if [ "$code" = '200' ]; then
echo "$response" >"$ACCOUNT_JSON_PATH"
_info "account update success for $_accUri."
_info "Account update success for $_accUri."
else
_info "Error. The account was not updated."
return 1
@@ -4195,6 +4236,40 @@ _getIdType() {
fi
}
# beginTime dateTo
# beginTime is full string format("2022-04-01T08:10:33Z"), beginTime can be empty, to use current time
# dateTo can be ether in full string format("2022-04-01T08:10:33Z") or in delta format(+5d or +20h)
_convertValidaty() {
_beginTime="$1"
_dateTo="$2"
_debug2 "_beginTime" "$_beginTime"
_debug2 "_dateTo" "$_dateTo"
if _startswith "$_dateTo" "+"; then
_v_begin=$(_time)
if [ "$_beginTime" ]; then
_v_begin="$(_date2time "$_beginTime")"
fi
_debug2 "_v_begin" "$_v_begin"
if _endswith "$_dateTo" "h"; then
_v_end=$(_math "$_v_begin + 60 * 60 * $(echo "$_dateTo" | tr -d '+h')")
elif _endswith "$_dateTo" "d"; then
_v_end=$(_math "$_v_begin + 60 * 60 * 24 * $(echo "$_dateTo" | tr -d '+d')")
else
_err "Not recognized format for _dateTo: $_dateTo"
return 1
fi
_debug2 "_v_end" "$_v_end"
_time2str "$_v_end"
else
if [ "$(_time)" -gt "$(_date2time "$_dateTo")" ]; then
_err "The validaty to is in the past: _dateTo = $_dateTo"
return 1
fi
echo "$_dateTo"
fi
}
#webroot, domain domainlist keylength
issue() {
if [ -z "$2" ]; then
@@ -4228,6 +4303,8 @@ issue() {
_local_addr="${13}"
_challenge_alias="${14}"
_preferred_chain="${15}"
_valid_from="${16}"
_valid_to="${17}"
if [ -z "$_ACME_IS_RENEW" ]; then
_initpath "$_main_domain" "$_key_length"
@@ -4247,11 +4324,24 @@ issue() {
Le_NextRenewTime=$(_readdomainconf Le_NextRenewTime)
_debug Le_NextRenewTime "$Le_NextRenewTime"
if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then
_valid_to_saved=$(_readdomainconf Le_Valid_to)
if [ "$_valid_to_saved" ] && ! _startswith "$_valid_to_saved" "+"; then
_info "The domain is set to be valid to: $_valid_to_saved"
_info "It can not be renewed automatically"
_info "See: $_VALIDITY_WIKI"
return $RENEW_SKIP
fi
_saved_domain=$(_readdomainconf Le_Domain)
_debug _saved_domain "$_saved_domain"
_saved_alt=$(_readdomainconf Le_Alt)
_debug _saved_alt "$_saved_alt"
if [ "$_saved_domain,$_saved_alt" = "$_main_domain,$_alt_domains" ]; then
_normized_saved_domains="$(echo "$_saved_domain,$_saved_alt" | tr "," "\n" | sort | tr '\n' ',')"
_debug _normized_saved_domains "$_normized_saved_domains"
_normized_domains="$(echo "$_main_domain,$_alt_domains" | tr "," "\n" | sort | tr '\n' ',')"
_debug _normized_domains "$_normized_domains"
if [ "$_normized_saved_domains" = "$_normized_domains" ]; then
_info "Domains not changed."
_info "Skip, Next renewal time is: $(__green "$(_readdomainconf Le_NextRenewTimeStr)")"
_info "Add '$(__red '--force')' to force to renew."
@@ -4299,10 +4389,6 @@ issue() {
_alt_domains=""
fi
if [ "$_key_length" = "$NO_VALUE" ]; then
_key_length=""
fi
if ! _on_before_issue "$_web_roots" "$_main_domain" "$_alt_domains" "$_pre_hook" "$_local_addr"; then
_err "_on_before_issue."
return 1
@@ -4363,12 +4449,52 @@ issue() {
_identifiers="$_identifiers,{\"type\":\"$(_getIdType "$d")\",\"value\":\"$(_idn "$d")\"}"
done
_debug2 _identifiers "$_identifiers"
if ! _send_signed_request "$ACME_NEW_ORDER" "{\"identifiers\": [$_identifiers]}"; then
_notBefore=""
_notAfter=""
if [ "$_valid_from" ]; then
_savedomainconf "Le_Valid_From" "$_valid_from"
_debug2 "_valid_from" "$_valid_from"
_notBefore="$(_convertValidaty "" "$_valid_from")"
if [ "$?" != "0" ]; then
_err "Can not parse _valid_from: $_valid_from"
return 1
fi
if [ "$(_time)" -gt "$(_date2time "$_notBefore")" ]; then
_notBefore=""
fi
else
_cleardomainconf "Le_Valid_From"
fi
_debug2 _notBefore "$_notBefore"
if [ "$_valid_to" ]; then
_debug2 "_valid_to" "$_valid_to"
_savedomainconf "Le_Valid_To" "$_valid_to"
_notAfter="$(_convertValidaty "$_notBefore" "$_valid_to")"
if [ "$?" != "0" ]; then
_err "Can not parse _valid_to: $_valid_to"
return 1
fi
else
_cleardomainconf "Le_Valid_To"
fi
_debug2 "_notAfter" "$_notAfter"
_newOrderObj="{\"identifiers\": [$_identifiers]"
if [ "$_notBefore" ]; then
_newOrderObj="$_newOrderObj,\"notBefore\": \"$_notBefore\""
fi
if [ "$_notAfter" ]; then
_newOrderObj="$_newOrderObj,\"notAfter\": \"$_notAfter\""
fi
if ! _send_signed_request "$ACME_NEW_ORDER" "$_newOrderObj}"; then
_err "Create new order error."
_clearup
_on_issue_err "$_post_hook"
return 1
fi
Le_LinkOrder="$(echo "$responseHeaders" | grep -i '^Location.*$' | _tail_n 1 | tr -d "\r\n " | cut -d ":" -f 2-)"
_debug Le_LinkOrder "$Le_LinkOrder"
Le_OrderFinalize="$(echo "$response" | _egrep_o '"finalize" *: *"[^"]*"' | cut -d '"' -f 4)"
@@ -4407,7 +4533,7 @@ issue() {
response="$(echo "$response" | _normalizeJson)"
_debug2 response "$response"
_d="$(echo "$response" | _egrep_o '"value" *: *"[^"]*"' | cut -d : -f 2 | tr -d ' "')"
_d="$(echo "$response" | _egrep_o '"value" *: *"[^"]*"' | cut -d : -f 2- | tr -d ' "')"
if _contains "$response" "\"wildcard\" *: *true"; then
_d="*.$_d"
fi
@@ -4557,6 +4683,7 @@ $_authorizations_map"
_dns_root_d="$(echo "$_dns_root_d" | sed 's/*.//')"
fi
_d_alias="$(_getfield "$_challenge_alias" "$_alias_index")"
test "$_d_alias" = "$NO_VALUE" && _d_alias=""
_alias_index="$(_math "$_alias_index" + 1)"
_debug "_d_alias" "$_d_alias"
if [ "$_d_alias" ]; then
@@ -4851,7 +4978,7 @@ $_authorizations_map"
return 1
fi
_debug "sleep 2 secs to verify again"
sleep 2
_sleep 2
_debug "checking"
_send_signed_request "$uri"
@@ -5028,7 +5155,7 @@ $_authorizations_map"
Le_CertCreateTime=$(_time)
_savedomainconf "Le_CertCreateTime" "$Le_CertCreateTime"
Le_CertCreateTimeStr=$(date -u)
Le_CertCreateTimeStr=$(_time2str "$Le_CertCreateTime")
_savedomainconf "Le_CertCreateTimeStr" "$Le_CertCreateTimeStr"
if [ -z "$Le_RenewalDays" ] || [ "$Le_RenewalDays" -lt "0" ]; then
@@ -5068,13 +5195,20 @@ $_authorizations_map"
else
_cleardomainconf Le_ForceNewDomainKey
fi
Le_NextRenewTime=$(_math "$Le_CertCreateTime" + "$Le_RenewalDays" \* 24 \* 60 \* 60)
Le_NextRenewTimeStr=$(_time2str "$Le_NextRenewTime")
if [ "$_notAfter" ]; then
Le_NextRenewTime=$(_date2time "$_notAfter")
Le_NextRenewTimeStr="$_notAfter"
if [ "$_valid_to" ] && ! _startswith "$_valid_to" "+"; then
_info "The domain is set to be valid to: $_valid_to"
_info "It can not be renewed automatically"
_info "See: $_VALIDITY_WIKI"
fi
else
Le_NextRenewTime=$(_math "$Le_CertCreateTime" + "$Le_RenewalDays" \* 24 \* 60 \* 60)
Le_NextRenewTimeStr=$(_time2str "$Le_NextRenewTime")
Le_NextRenewTime=$(_math "$Le_NextRenewTime" - 86400)
fi
_savedomainconf "Le_NextRenewTimeStr" "$Le_NextRenewTimeStr"
Le_NextRenewTime=$(_math "$Le_NextRenewTime" - 86400)
_savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime"
if [ "$_real_cert$_real_key$_real_ca$_reload_cmd$_real_fullchain" ]; then
@@ -5119,7 +5253,8 @@ renew() {
fi
_isEcc="$2"
#the server specified from commandline
_acme_server_back="$ACME_DIRECTORY"
_initpath "$Le_Domain" "$_isEcc"
_set_level=${NOTIFY_LEVEL:-$NOTIFY_LEVEL_DEFAULT}
_info "$(__green "Renew: '$Le_Domain'")"
@@ -5140,16 +5275,36 @@ renew() {
Le_API="$CA_LETSENCRYPT_V2"
fi
if [ "$Le_API" ]; then
if [ "$_acme_server_back" ]; then
export ACME_DIRECTORY="$_acme_server_back"
else
export ACME_DIRECTORY="$Le_API"
fi
case "$Le_API" in
"$CA_LETSENCRYPT_V2_TEST")
_info "Switching back to $CA_LETSENCRYPT_V2"
Le_API="$CA_LETSENCRYPT_V2"
;;
"$CA_BUYPASS_TEST")
_info "Switching back to $CA_BUYPASS"
Le_API="$CA_BUYPASS"
;;
"$CA_GOOGLE_TEST")
_info "Switching back to $CA_GOOGLE"
Le_API="$CA_GOOGLE"
;;
esac
if [ "$Le_API" ] && [ "$ACME_DIRECTORY" ]; then
if [ "$Le_API" != "$ACME_DIRECTORY" ]; then
_clearAPI
fi
export ACME_DIRECTORY="$Le_API"
#reload ca configs
ACCOUNT_KEY_PATH=""
ACCOUNT_JSON_PATH=""
CA_CONF=""
_debug3 "initpath again."
_debug2 "initpath again."
_initpath "$Le_Domain" "$_isEcc"
fi
@@ -5175,7 +5330,11 @@ renew() {
Le_PostHook="$(_readdomainconf Le_PostHook)"
Le_RenewHook="$(_readdomainconf Le_RenewHook)"
Le_Preferred_Chain="$(_readdomainconf Le_Preferred_Chain)"
issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" "$Le_PreHook" "$Le_PostHook" "$Le_RenewHook" "$Le_LocalAddress" "$Le_ChallengeAlias" "$Le_Preferred_Chain"
#when renew from an old version, the empty Le_Keylength means 2048
if [ -z "$Le_Keylength" ]; then
Le_Keylength=2048
fi
issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" "$Le_PreHook" "$Le_PostHook" "$Le_RenewHook" "$Le_LocalAddress" "$Le_ChallengeAlias" "$Le_Preferred_Chain" "$Le_Valid_From" "$Le_Valid_To"
res="$?"
if [ "$res" != "0" ]; then
return "$res"
@@ -5205,6 +5364,7 @@ renew() {
#renewAll [stopRenewOnError]
renewAll() {
_initpath
_clearCA
_stopRenewOnError="$1"
_debug "_stopRenewOnError" "$_stopRenewOnError"
_ret="0"
@@ -5395,10 +5555,13 @@ showcsr() {
_initpath
_csrsubj=$(_readSubjectFromCSR "$_csrfile")
if [ "$?" != "0" ] || [ -z "$_csrsubj" ]; then
if [ "$?" != "0" ]; then
_err "Can not read subject from csr: $_csrfile"
return 1
fi
if [ -z "$_csrsubj" ]; then
_info "The Subject is empty"
fi
_info "Subject=$_csrsubj"
@@ -5611,8 +5774,9 @@ _installcert() {
if [ -f "$_real_key" ]; then
cat "$CERT_KEY_PATH" >"$_real_key" || return 1
else
cat "$CERT_KEY_PATH" >"$_real_key" || return 1
touch "$_real_key" || return 1
chmod 600 "$_real_key"
cat "$CERT_KEY_PATH" >"$_real_key" || return 1
fi
fi
@@ -6610,6 +6774,11 @@ Parameters:
If no match, the default offered chain will be used. (default: empty)
See: $_PREFERRED_CHAIN_WIKI
--valid-to <date-time> Request the NotAfter field of the cert.
See: $_VALIDITY_WIKI
--valid-from <date-time> Request the NotBefore field of the cert.
See: $_VALIDITY_WIKI
-f, --force Force install, force cert renewal or override sudo restrictions.
--staging, --test Use staging server, for testing.
--debug [0|1|2|3] Output debug info. Defaults to 1 if argument is omitted.
@@ -6801,6 +6970,10 @@ _processAccountConf() {
}
_checkSudo() {
if [ -z "__INTERACTIVE" ]; then
#don't check if it's not in an interactive shell
return 0
fi
if [ "$SUDO_GID" ] && [ "$SUDO_COMMAND" ] && [ "$SUDO_USER" ] && [ "$SUDO_UID" ]; then
if [ "$SUDO_USER" = "root" ] && [ "$SUDO_UID" = "0" ]; then
#it's root using sudo, no matter it's using sudo or not, just fine
@@ -6922,8 +7095,8 @@ _process() {
_altdomains="$NO_VALUE"
_webroot=""
_challenge_alias=""
_keylength=""
_accountkeylength=""
_keylength="$DEFAULT_DOMAIN_KEY_LENGTH"
_accountkeylength="$DEFAULT_ACCOUNT_KEY_LENGTH"
_cert_file=""
_key_file=""
_ca_file=""
@@ -6970,6 +7143,8 @@ _process() {
_eab_kid=""
_eab_hmac_key=""
_preferred_chain=""
_valid_from=""
_valid_to=""
while [ ${#} -gt 0 ]; do
case "${1}" in
@@ -7277,6 +7452,14 @@ _process() {
Le_RenewalDays="$_days"
shift
;;
--valid-from)
_valid_from="$2"
shift
;;
--valid-to)
_valid_to="$2"
shift
;;
--httpport)
_httpport="$2"
Le_HTTPPort="$_httpport"
@@ -7538,7 +7721,7 @@ _process() {
uninstall) uninstall "$_nocron" ;;
upgrade) upgrade ;;
issue)
issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_cert_file" "$_key_file" "$_ca_file" "$_reloadcmd" "$_fullchain_file" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_address" "$_challenge_alias" "$_preferred_chain"
issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_cert_file" "$_key_file" "$_ca_file" "$_reloadcmd" "$_fullchain_file" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_address" "$_challenge_alias" "$_preferred_chain" "$_valid_from" "$_valid_to"
;;
deploy)
deploy "$_domain" "$_deploy_hook" "$_ecc"

View File

@@ -20,18 +20,23 @@ mailcow_deploy() {
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
_mailcow_path="${DEPLOY_MAILCOW_PATH}"
_getdeployconf DEPLOY_MAILCOW_PATH
_getdeployconf DEPLOY_MAILCOW_RELOAD
if [ -z "$_mailcow_path" ]; then
_debug DEPLOY_MAILCOW_PATH "$DEPLOY_MAILCOW_PATH"
_debug DEPLOY_MAILCOW_RELOAD "$DEPLOY_MAILCOW_RELOAD"
if [ -z "$DEPLOY_MAILCOW_PATH" ]; then
_err "Mailcow path is not found, please define DEPLOY_MAILCOW_PATH."
return 1
fi
#Tests if _ssl_path is the mailcow root directory.
if [ -f "${_mailcow_path}/generate_config.sh" ]; then
_ssl_path="${_mailcow_path}/data/assets/ssl/"
else
_ssl_path="${_mailcow_path}"
_savedeployconf DEPLOY_MAILCOW_PATH "$DEPLOY_MAILCOW_PATH"
[ -n "$DEPLOY_MAILCOW_RELOAD" ] && _savedeployconf DEPLOY_MAILCOW_RELOAD "$DEPLOY_MAILCOW_RELOAD"
_ssl_path="$DEPLOY_MAILCOW_PATH"
if [ -f "$DEPLOY_MAILCOW_PATH/generate_config.sh" ]; then
_ssl_path="$DEPLOY_MAILCOW_PATH/data/assets/ssl/"
fi
if [ ! -d "$_ssl_path" ]; then
@@ -40,16 +45,15 @@ mailcow_deploy() {
fi
# ECC or RSA
if [ -z "${Le_Keylength}" ]; then
Le_Keylength=""
fi
if _isEccKey "${Le_Keylength}"; then
length=$(_readdomainconf Le_Keylength)
if _isEccKey "$length"; then
_info "ECC key type detected"
_cert_name_prefix="ecdsa-"
else
_info "RSA key type detected"
_cert_name_prefix=""
fi
_info "Copying key and cert"
_real_key="$_ssl_path/${_cert_name_prefix}key.pem"
if ! cat "$_ckey" >"$_real_key"; then
@@ -63,7 +67,7 @@ mailcow_deploy() {
return 1
fi
DEFAULT_MAILCOW_RELOAD="docker restart $(docker ps -qaf name=postfix-mailcow); docker restart $(docker ps -qaf name=nginx-mailcow); docker restart $(docker ps -qaf name=dovecot-mailcow)"
DEFAULT_MAILCOW_RELOAD="docker restart \$(docker ps --quiet --filter name=nginx-mailcow --filter name=dovecot-mailcow)"
_reload="${DEPLOY_MAILCOW_RELOAD:-$DEFAULT_MAILCOW_RELOAD}"
_info "Run reload: $_reload"

View File

@@ -23,6 +23,7 @@
# ```sh
# export ROUTER_OS_USERNAME=certuser
# export ROUTER_OS_HOST=router.example.com
# export ROUTER_OS_PORT=22
#
# acme.sh --deploy -d ftp.example.com --deploy-hook routeros
# ```
@@ -48,6 +49,16 @@
# One optional thing to do as well is to create a script that updates
# all the required services and run that script in a single command.
#
# To adopt parameters to `scp` and/or `ssh` set the optional
# `ROUTER_OS_SSH_CMD` and `ROUTER_OS_SCP_CMD` variables accordingly,
# see ssh(1) and scp(1) for parameters to those commands.
#
# Example:
# ```ssh
# export ROUTER_OS_SSH_CMD="ssh -i /acme.sh/.ssh/router.example.com -o UserKnownHostsFile=/acme.sh/.ssh/known_hosts"
# export ROUTER_OS_SCP_CMD="scp -i /acme.sh/.ssh/router.example.com -o UserKnownHostsFile=/acme.sh/.ssh/known_hosts"
# ````
#
# returns 0 means success, otherwise error.
######## Public functions #####################
@@ -59,6 +70,7 @@ routeros_deploy() {
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_err_code=0
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
@@ -80,6 +92,27 @@ routeros_deploy() {
return 1
fi
_getdeployconf ROUTER_OS_PORT
if [ -z "$ROUTER_OS_PORT" ]; then
_debug "Using default port 22 as ROUTER_OS_PORT, please set if not correct."
ROUTER_OS_PORT=22
fi
_getdeployconf ROUTER_OS_SSH_CMD
if [ -z "$ROUTER_OS_SSH_CMD" ]; then
_debug "Use default ssh setup."
ROUTER_OS_SSH_CMD="ssh -p $ROUTER_OS_PORT"
fi
_getdeployconf ROUTER_OS_SCP_CMD
if [ -z "$ROUTER_OS_SCP_CMD" ]; then
_debug "USe default scp setup."
ROUTER_OS_SCP_CMD="scp -P $ROUTER_OS_PORT"
fi
_getdeployconf ROUTER_OS_ADDITIONAL_SERVICES
if [ -z "$ROUTER_OS_ADDITIONAL_SERVICES" ]; then
@@ -89,16 +122,26 @@ routeros_deploy() {
_savedeployconf ROUTER_OS_HOST "$ROUTER_OS_HOST"
_savedeployconf ROUTER_OS_USERNAME "$ROUTER_OS_USERNAME"
_savedeployconf ROUTER_OS_PORT "$ROUTER_OS_PORT"
_savedeployconf ROUTER_OS_SSH_CMD "$ROUTER_OS_SSH_CMD"
_savedeployconf ROUTER_OS_SCP_CMD "$ROUTER_OS_SCP_CMD"
_savedeployconf ROUTER_OS_ADDITIONAL_SERVICES "$ROUTER_OS_ADDITIONAL_SERVICES"
_info "Trying to push key '$_ckey' to router"
scp "$_ckey" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.key"
_info "Trying to push cert '$_cfullchain' to router"
scp "$_cfullchain" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.cer"
DEPLOY_SCRIPT_CMD="/system script add name=\"LE Cert Deploy - $_cdomain\" owner=admin policy=ftp,read,write,password,sensitive \
source=\"## generated by routeros deploy script in acme.sh;\
\n/certificate remove [ find name=$_cdomain.cer_0 ];\
# push key to routeros
if ! _scp_certificate "$_ckey" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.key"; then
return $_err_code
fi
# push certificate chain to routeros
if ! _scp_certificate "$_cfullchain" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.cer"; then
return $_err_code
fi
DEPLOY_SCRIPT_CMD="/system script add name=\"LE Cert Deploy - $_cdomain\" owner=$ROUTER_OS_USERNAME \
comment=\"generated by routeros deploy script in acme.sh\" \
source=\"/certificate remove [ find name=$_cdomain.cer_0 ];\
\n/certificate remove [ find name=$_cdomain.cer_1 ];\
\n/certificate remove [ find name=$_cdomain.cer_2 ];\
\ndelay 1;\
\n/certificate import file-name=$_cdomain.cer passphrase=\\\"\\\";\
\n/certificate import file-name=$_cdomain.key passphrase=\\\"\\\";\
@@ -110,12 +153,51 @@ source=\"## generated by routeros deploy script in acme.sh;\
\n$ROUTER_OS_ADDITIONAL_SERVICES;\
\n\"
"
# shellcheck disable=SC2029
ssh "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" "$DEPLOY_SCRIPT_CMD"
# shellcheck disable=SC2029
ssh "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" "/system script run \"LE Cert Deploy - $_cdomain\""
# shellcheck disable=SC2029
ssh "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" "/system script remove \"LE Cert Deploy - $_cdomain\""
if ! _ssh_remote_cmd "$DEPLOY_SCRIPT_CMD"; then
return $_err_code
fi
if ! _ssh_remote_cmd "/system script run \"LE Cert Deploy - $_cdomain\""; then
return $_err_code
fi
if ! _ssh_remote_cmd "/system script remove \"LE Cert Deploy - $_cdomain\""; then
return $_err_code
fi
return 0
}
# inspired by deploy/ssh.sh
_ssh_remote_cmd() {
_cmd="$1"
_secure_debug "Remote commands to execute: $_cmd"
_info "Submitting sequence of commands to routeros"
# quotations in bash cmd below intended. Squash travis spellcheck error
# shellcheck disable=SC2029
$ROUTER_OS_SSH_CMD "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" "$_cmd"
_err_code="$?"
if [ "$_err_code" != "0" ]; then
_err "Error code $_err_code returned from routeros"
fi
return $_err_code
}
_scp_certificate() {
_src="$1"
_dst="$2"
_secure_debug "scp '$_src' to '$_dst'"
_info "Push key '$_src' to routeros"
$ROUTER_OS_SCP_CMD "$_src" "$_dst"
_err_code="$?"
if [ "$_err_code" != "0" ]; then
_err "Error code $_err_code returned from scp"
fi
return $_err_code
}

View File

@@ -94,7 +94,12 @@ synology_dsm_deploy() {
otp_code=""
if [ -n "$SYNO_TOTP_SECRET" ]; then
otp_code="$(oathtool --base32 --totp "${SYNO_TOTP_SECRET}" 2>/dev/null)"
if _exists oathtool; then
otp_code="$(oathtool --base32 --totp "${SYNO_TOTP_SECRET}" 2>/dev/null)"
else
_err "oathtool could not be found, install oathtool to use SYNO_TOTP_SECRET"
return 1
fi
fi
if [ -n "$SYNO_DID" ]; then

View File

@@ -38,7 +38,7 @@ truenas_deploy() {
_getdeployconf DEPLOY_TRUENAS_APIKEY
if [ -z "$DEPLOY_TRUENAS_APIKEY" ]; then
_err "TrueNAS Api Key is not found, please define DEPLOY_TRUENAS_APIKEY."
_err "TrueNAS API key not found, please set the DEPLOY_TRUENAS_APIKEY environment variable."
return 1
fi
_secure_debug2 DEPLOY_TRUENAS_APIKEY "$DEPLOY_TRUENAS_APIKEY"
@@ -62,15 +62,14 @@ truenas_deploy() {
_info "Testing Connection TrueNAS"
_response=$(_get "$_api_url/system/state")
_info "TrueNAS System State: $_response."
_info "TrueNAS system state: $_response."
if [ -z "$_response" ]; then
_err "Unable to authenticate to $_api_url."
_err 'Check your Connection and set DEPLOY_TRUENAS_HOSTNAME="192.168.178.x".'
_err 'or'
_err 'set DEPLOY_TRUENAS_HOSTNAME="<truenas_dnsname>".'
_err 'Check your Connection and set DEPLOY_TRUENAS_SCHEME="https".'
_err "Check your Api Key."
_err 'Check your connection settings are correct, e.g.'
_err 'DEPLOY_TRUENAS_HOSTNAME="192.168.x.y" or DEPLOY_TRUENAS_HOSTNAME="truenas.example.com".'
_err 'DEPLOY_TRUENAS_SCHEME="https" or DEPLOY_TRUENAS_SCHEME="http".'
_err "Verify your TrueNAS API key is valid and set correctly, e.g. DEPLOY_TRUENAS_APIKEY=xxxx...."
return 1
fi
@@ -78,7 +77,7 @@ truenas_deploy() {
_savedeployconf DEPLOY_TRUENAS_HOSTNAME "$DEPLOY_TRUENAS_HOSTNAME"
_savedeployconf DEPLOY_TRUENAS_SCHEME "$DEPLOY_TRUENAS_SCHEME"
_info "Getting active certificate from TrueNAS"
_info "Getting current active certificate from TrueNAS"
_response=$(_get "$_api_url/system/general")
_active_cert_id=$(echo "$_response" | grep -B2 '"name":' | grep 'id' | tr -d -- '"id: ,')
_active_cert_name=$(echo "$_response" | grep '"name":' | sed -n 's/.*: "\(.\{1,\}\)",$/\1/p')
@@ -88,14 +87,14 @@ truenas_deploy() {
_debug Active_UI_http_redirect "$_param_httpsredirect"
if [ "$DEPLOY_TRUENAS_SCHEME" = "http" ] && [ "$_param_httpsredirect" = "true" ]; then
_info "http Redirect active"
_info "HTTP->HTTPS redirection is enabled"
_info "Setting DEPLOY_TRUENAS_SCHEME to 'https'"
DEPLOY_TRUENAS_SCHEME="https"
_api_url="$DEPLOY_TRUENAS_SCHEME://$DEPLOY_TRUENAS_HOSTNAME/api/v2.0"
_savedeployconf DEPLOY_TRUENAS_SCHEME "$DEPLOY_TRUENAS_SCHEME"
fi
_info "Upload new certifikate to TrueNAS"
_info "Uploading new certificate to TrueNAS"
_certname="Letsencrypt_$(_utc_date | tr ' ' '_' | tr -d -- ':')"
_debug3 _certname "$_certname"
@@ -104,30 +103,30 @@ truenas_deploy() {
_debug3 _add_cert_result "$_add_cert_result"
_info "Getting Certificate list to get new Cert ID"
_info "Fetching list of installed certificates"
_cert_list=$(_get "$_api_url/system/general/ui_certificate_choices")
_cert_id=$(echo "$_cert_list" | grep "$_certname" | sed -n 's/.*"\([0-9]\{1,\}\)".*$/\1/p')
_debug3 _cert_id "$_cert_id"
_info "Activate Certificate ID: $_cert_id"
_info "Current activate certificate ID: $_cert_id"
_activateData="{\"ui_certificate\": \"${_cert_id}\"}"
_activate_result="$(_post "$_activateData" "$_api_url/system/general" "" "PUT" "application/json")"
_debug3 _activate_result "$_activate_result"
_info "Check if WebDAV certificate is the same as the WEB UI"
_info "Checking if WebDAV certificate is the same as the TrueNAS web UI"
_webdav_list=$(_get "$_api_url/webdav")
_webdav_cert_id=$(echo "$_webdav_list" | grep '"certssl":' | tr -d -- '"certsl: ,')
if [ "$_webdav_cert_id" = "$_active_cert_id" ]; then
_info "Update the WebDAV Certificate"
_info "Updating the WebDAV certificate"
_debug _webdav_cert_id "$_webdav_cert_id"
_webdav_data="{\"certssl\": \"${_cert_id}\"}"
_activate_webdav_cert="$(_post "$_webdav_data" "$_api_url/webdav" "" "PUT" "application/json")"
_webdav_new_cert_id=$(echo "$_activate_webdav_cert" | _json_decode | sed -n 's/.*: \([0-9]\{1,\}\) }$/\1/p')
_webdav_new_cert_id=$(echo "$_activate_webdav_cert" | _json_decode | grep '"certssl":' | sed -n 's/.*: \([0-9]\{1,\}\),\{0,1\}$/\1/p')
if [ "$_webdav_new_cert_id" -eq "$_cert_id" ]; then
_info "WebDAV Certificate update successfully"
_info "WebDAV certificate updated successfully"
else
_err "Unable to set WebDAV certificate"
_debug3 _activate_webdav_cert "$_activate_webdav_cert"
@@ -136,21 +135,21 @@ truenas_deploy() {
fi
_debug3 _webdav_new_cert_id "$_webdav_new_cert_id"
else
_info "WebDAV certificate not set or not the same as Web UI"
_info "WebDAV certificate is not configured or is not the same as TrueNAS web UI"
fi
_info "Check if FTP certificate is the same as the WEB UI"
_info "Checking if FTP certificate is the same as the TrueNAS web UI"
_ftp_list=$(_get "$_api_url/ftp")
_ftp_cert_id=$(echo "$_ftp_list" | grep '"ssltls_certificate":' | tr -d -- '"certislfa:_ ,')
if [ "$_ftp_cert_id" = "$_active_cert_id" ]; then
_info "Update the FTP Certificate"
_info "Updating the FTP certificate"
_debug _ftp_cert_id "$_ftp_cert_id"
_ftp_data="{\"ssltls_certificate\": \"${_cert_id}\"}"
_activate_ftp_cert="$(_post "$_ftp_data" "$_api_url/ftp" "" "PUT" "application/json")"
_ftp_new_cert_id=$(echo "$_activate_ftp_cert" | _json_decode | sed -n 's/.*: \([0-9]\{1,\}\) }$/\1/p')
_ftp_new_cert_id=$(echo "$_activate_ftp_cert" | _json_decode | grep '"ssltls_certificate":' | sed -n 's/.*: \([0-9]\{1,\}\),\{0,1\}$/\1/p')
if [ "$_ftp_new_cert_id" -eq "$_cert_id" ]; then
_info "FTP Certificate update successfully"
_info "FTP certificate updated successfully"
else
_err "Unable to set FTP certificate"
_debug3 _activate_ftp_cert "$_activate_ftp_cert"
@@ -159,22 +158,45 @@ truenas_deploy() {
fi
_debug3 _activate_ftp_cert "$_activate_ftp_cert"
else
_info "FTP certificate not set or not the same as Web UI"
_info "FTP certificate is not configured or is not the same as TrueNAS web UI"
fi
_info "Delete old Certificate"
_info "Checking if S3 certificate is the same as the TrueNAS web UI"
_s3_list=$(_get "$_api_url/s3")
_s3_cert_id=$(echo "$_s3_list" | grep '"certificate":' | tr -d -- '"certifa:_ ,')
if [ "$_s3_cert_id" = "$_active_cert_id" ]; then
_info "Updating the S3 certificate"
_debug _s3_cert_id "$_s3_cert_id"
_s3_data="{\"certificate\": \"${_cert_id}\"}"
_activate_s3_cert="$(_post "$_s3_data" "$_api_url/s3" "" "PUT" "application/json")"
_s3_new_cert_id=$(echo "$_activate_s3_cert" | _json_decode | grep '"certificate":' | sed -n 's/.*: \([0-9]\{1,\}\),\{0,1\}$/\1/p')
if [ "$_s3_new_cert_id" -eq "$_cert_id" ]; then
_info "S3 certificate updated successfully"
else
_err "Unable to set S3 certificate"
_debug3 _activate_s3_cert "$_activate_s3_cert"
_debug3 _s3_new_cert_id "$_s3_new_cert_id"
return 1
fi
_debug3 _activate_s3_cert "$_activate_s3_cert"
else
_info "S3 certificate is not configured or is not the same as TrueNAS web UI"
fi
_info "Deleting old certificate"
_delete_result="$(_post "" "$_api_url/certificate/id/$_active_cert_id" "" "DELETE" "application/json")"
_debug3 _delete_result "$_delete_result"
_info "Reload WebUI from TrueNAS"
_info "Reloading TrueNAS web UI"
_restart_UI=$(_get "$_api_url/system/general/ui_restart")
_debug2 _restart_UI "$_restart_UI"
if [ -n "$_add_cert_result" ] && [ -n "$_activate_result" ]; then
return 0
else
_err "Certupdate was not succesfull, please use --debug"
_err "Certificate update was not succesful, please try again with --debug"
return 1
fi
}

View File

@@ -42,7 +42,7 @@ dns_1984hosting_add() {
_debug "Add TXT record $fulldomain with value '$txtvalue'"
value="$(printf '%s' "$txtvalue" | _url_encode)"
url="https://management.1984hosting.com/domains/entry/"
url="https://1984.hosting/domains/entry/"
postdata="entry=new"
postdata="$postdata&type=TXT"
@@ -95,7 +95,7 @@ dns_1984hosting_rm() {
_debug _domain "$_domain"
_debug "Delete $fulldomain TXT record"
url="https://management.1984hosting.com/domains"
url="https://1984.hosting/domains"
if ! _get_zone_id "$url" "$_domain"; then
_err "invalid zone" "$_domain"
return 1
@@ -138,7 +138,7 @@ _1984hosting_login() {
_debug "Login to 1984Hosting as user $One984HOSTING_Username"
username=$(printf '%s' "$One984HOSTING_Username" | _url_encode)
password=$(printf '%s' "$One984HOSTING_Password" | _url_encode)
url="https://management.1984hosting.com/accounts/checkuserauth/"
url="https://1984.hosting/accounts/checkuserauth/"
response="$(_post "username=$username&password=$password&otpkey=" $url)"
response="$(echo "$response" | _normalizeJson)"
@@ -175,7 +175,7 @@ _check_cookies() {
return 1
fi
_authget "https://management.1984hosting.com/accounts/loginstatus/"
_authget "https://1984.hosting/accounts/loginstatus/"
if _contains "$response" '"ok": true'; then
_debug "Cached cookies still valid"
return 0
@@ -204,7 +204,7 @@ _get_root() {
return 1
fi
_authget "https://management.1984hosting.com/domains/soacheck/?zone=$h&nameserver=ns0.1984.is."
_authget "https://1984.hosting/domains/soacheck/?zone=$h&nameserver=ns0.1984.is."
if _contains "$_response" "serial" && ! _contains "$_response" "null"; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_domain="$h"
@@ -251,11 +251,11 @@ _htmlget() {
# add extra headers to request
_authpost() {
url="https://management.1984hosting.com/domains"
url="https://1984.hosting/domains"
_get_zone_id "$url" "$_domain"
csrf_header="$(echo "$One984HOSTING_CSRFTOKEN_COOKIE" | _egrep_o "=[^=][0-9a-zA-Z]*" | tr -d "=")"
export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE;$One984HOSTING_SESSIONID_COOKIE"
export _H2="Referer: https://management.1984hosting.com/domains/$_zone_id"
export _H2="Referer: https://1984.hosting/domains/$_zone_id"
export _H3="X-CSRFToken: $csrf_header"
_response=$(_post "$1" "$2")
}

View File

@@ -25,9 +25,15 @@ dns_cf_add() {
CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}"
if [ "$CF_Token" ]; then
_saveaccountconf_mutable CF_Token "$CF_Token"
_saveaccountconf_mutable CF_Account_ID "$CF_Account_ID"
_saveaccountconf_mutable CF_Zone_ID "$CF_Zone_ID"
if [ "$CF_Zone_ID" ]; then
_savedomainconf CF_Token "$CF_Token"
_savedomainconf CF_Account_ID "$CF_Account_ID"
_savedomainconf CF_Zone_ID "$CF_Zone_ID"
else
_saveaccountconf_mutable CF_Token "$CF_Token"
_saveaccountconf_mutable CF_Account_ID "$CF_Account_ID"
_saveaccountconf_mutable CF_Zone_ID "$CF_Zone_ID"
fi
else
if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then
CF_Key=""

159
dnsapi/dns_curanet.sh Normal file
View File

@@ -0,0 +1,159 @@
#!/usr/bin/env sh
#Script to use with curanet.dk, scannet.dk, wannafind.dk, dandomain.dk DNS management.
#Requires api credentials with scope: dns
#Author: Peter L. Hansen <peter@r12.dk>
#Version 1.0
CURANET_REST_URL="https://api.curanet.dk/dns/v1/Domains"
CURANET_AUTH_URL="https://apiauth.dk.team.blue/auth/realms/Curanet/protocol/openid-connect/token"
CURANET_ACCESS_TOKEN=""
######## Public functions #####################
#Usage: dns_curanet_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_curanet_add() {
fulldomain=$1
txtvalue=$2
_info "Using curanet"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
CURANET_AUTHCLIENTID="${CURANET_AUTHCLIENTID:-$(_readaccountconf_mutable CURANET_AUTHCLIENTID)}"
CURANET_AUTHSECRET="${CURANET_AUTHSECRET:-$(_readaccountconf_mutable CURANET_AUTHSECRET)}"
if [ -z "$CURANET_AUTHCLIENTID" ] || [ -z "$CURANET_AUTHSECRET" ]; then
CURANET_AUTHCLIENTID=""
CURANET_AUTHSECRET=""
_err "You don't specify curanet api client and secret."
_err "Please create your auth info and try again."
return 1
fi
#save the credentials to the account conf file.
_saveaccountconf_mutable CURANET_AUTHCLIENTID "$CURANET_AUTHCLIENTID"
_saveaccountconf_mutable CURANET_AUTHSECRET "$CURANET_AUTHSECRET"
if ! _get_token; then
_err "Unable to get token"
return 1
fi
if ! _get_root "$fulldomain"; then
_err "Invalid domain"
return 1
fi
export _H1="Content-Type: application/json-patch+json"
export _H2="Accept: application/json"
export _H3="Authorization: Bearer $CURANET_ACCESS_TOKEN"
data="{\"name\": \"$fulldomain\",\"type\": \"TXT\",\"ttl\": 60,\"priority\": 0,\"data\": \"$txtvalue\"}"
response="$(_post "$data" "$CURANET_REST_URL/${_domain}/Records" "" "")"
if _contains "$response" "$txtvalue"; then
_debug "TXT record added OK"
else
_err "Unable to add TXT record"
return 1
fi
return 0
}
#Usage: fulldomain txtvalue
#Remove the txt record after validation.
dns_curanet_rm() {
fulldomain=$1
txtvalue=$2
_info "Using curanet"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
CURANET_AUTHCLIENTID="${CURANET_AUTHCLIENTID:-$(_readaccountconf_mutable CURANET_AUTHCLIENTID)}"
CURANET_AUTHSECRET="${CURANET_AUTHSECRET:-$(_readaccountconf_mutable CURANET_AUTHSECRET)}"
if ! _get_token; then
_err "Unable to get token"
return 1
fi
if ! _get_root "$fulldomain"; then
_err "Invalid domain"
return 1
fi
_debug "Getting current record list to identify TXT to delete"
export _H1="Content-Type: application/json"
export _H2="Accept: application/json"
export _H3="Authorization: Bearer $CURANET_ACCESS_TOKEN"
response="$(_get "$CURANET_REST_URL/${_domain}/Records" "" "")"
if ! _contains "$response" "$txtvalue"; then
_err "Unable to delete record (does not contain $txtvalue )"
return 1
fi
recordid=$(echo "$response" | _egrep_o "{\"id\":[0-9]+,\"name\":\"$fulldomain\",\"type\":\"TXT\",\"ttl\":60,\"priority\":0,\"data\":\"..$txtvalue" | _egrep_o "id\":[0-9]+" | cut -c 5-)
if [ -z "$recordid" ]; then
_err "Unable to get recordid"
_debug "regex {\"id\":[0-9]+,\"name\":\"$fulldomain\",\"type\":\"TXT\",\"ttl\":60,\"priority\":0,\"data\":\"..$txtvalue"
_debug "response $response"
return 1
fi
_debug "Deleting recordID $recordid"
response="$(_post "" "$CURANET_REST_URL/${_domain}/Records/$recordid" "" "DELETE")"
return 0
}
#################### Private functions below ##################################
_get_token() {
response="$(_post "grant_type=client_credentials&client_id=$CURANET_AUTHCLIENTID&client_secret=$CURANET_AUTHSECRET&scope=dns" "$CURANET_AUTH_URL" "" "")"
if ! _contains "$response" "access_token"; then
_err "Unable get access token"
return 1
fi
CURANET_ACCESS_TOKEN=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]+" | cut -c 17-)
if [ -z "$CURANET_ACCESS_TOKEN" ]; then
_err "Unable to get token"
return 1
fi
return 0
}
#_acme-challenge.www.domain.com
#returns
# _domain=domain.com
# _domain_id=sdjkglgdfewsdfg
_get_root() {
domain=$1
i=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
export _H1="Content-Type: application/json"
export _H2="Accept: application/json"
export _H3="Authorization: Bearer $CURANET_ACCESS_TOKEN"
response="$(_get "$CURANET_REST_URL/$h/Records" "" "")"
if [ ! "$(echo "$response" | _egrep_o "Entity not found")" ]; then
_domain=$h
return 0
fi
i=$(_math "$i" + 1)
done
return 1
}

View File

@@ -1,185 +0,0 @@
#!/usr/bin/env sh
# CloudXNS Domain api
#
#CX_Key="1234"
#
#CX_Secret="sADDsdasdgdsf"
CX_Api="https://www.cloudxns.net/api2"
#REST_API
######## Public functions #####################
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_cx_add() {
fulldomain=$1
txtvalue=$2
CX_Key="${CX_Key:-$(_readaccountconf_mutable CX_Key)}"
CX_Secret="${CX_Secret:-$(_readaccountconf_mutable CX_Secret)}"
if [ -z "$CX_Key" ] || [ -z "$CX_Secret" ]; then
CX_Key=""
CX_Secret=""
_err "You don't specify cloudxns.net api key or secret yet."
_err "Please create you key and try again."
return 1
fi
REST_API="$CX_Api"
#save the api key and email to the account conf file.
_saveaccountconf_mutable CX_Key "$CX_Key"
_saveaccountconf_mutable CX_Secret "$CX_Secret"
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain"
return 1
fi
add_record "$_domain" "$_sub_domain" "$txtvalue"
}
#fulldomain txtvalue
dns_cx_rm() {
fulldomain=$1
txtvalue=$2
CX_Key="${CX_Key:-$(_readaccountconf_mutable CX_Key)}"
CX_Secret="${CX_Secret:-$(_readaccountconf_mutable CX_Secret)}"
REST_API="$CX_Api"
if _get_root "$fulldomain"; then
record_id=""
existing_records "$_domain" "$_sub_domain" "$txtvalue"
if [ "$record_id" ]; then
_rest DELETE "record/$record_id/$_domain_id" "{}"
_info "Deleted record ${fulldomain}"
fi
fi
}
#usage: root sub
#return if the sub record already exists.
#echos the existing records count.
# '0' means doesn't exist
existing_records() {
_debug "Getting txt records"
root=$1
sub=$2
if ! _rest GET "record/$_domain_id?:domain_id?host_id=0&offset=0&row_num=100"; then
return 1
fi
seg=$(printf "%s\n" "$response" | _egrep_o '"record_id":[^{]*host":"'"$_sub_domain"'"[^}]*\}')
_debug seg "$seg"
if [ -z "$seg" ]; then
return 0
fi
if printf "%s" "$response" | grep '"type":"TXT"' >/dev/null; then
record_id=$(printf "%s\n" "$seg" | _egrep_o '"record_id":"[^"]*"' | cut -d : -f 2 | tr -d \" | _head_n 1)
_debug record_id "$record_id"
return 0
fi
}
#add the txt record.
#usage: root sub txtvalue
add_record() {
root=$1
sub=$2
txtvalue=$3
fulldomain="$sub.$root"
_info "Adding record"
if ! _rest POST "record" "{\"domain_id\": $_domain_id, \"host\":\"$_sub_domain\", \"value\":\"$txtvalue\", \"type\":\"TXT\",\"ttl\":600, \"line_id\":1}"; then
return 1
fi
return 0
}
#################### Private functions below ##################################
#_acme-challenge.www.domain.com
#returns
# _sub_domain=_acme-challenge.www
# _domain=domain.com
# _domain_id=sdjkglgdfewsdfg
_get_root() {
domain=$1
i=2
p=1
if ! _rest GET "domain"; then
return 1
fi
while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
_debug h "$h"
if [ -z "$h" ]; then
#not valid
return 1
fi
if _contains "$response" "$h."; then
seg=$(printf "%s\n" "$response" | _egrep_o '"id":[^{]*"'"$h"'."[^}]*}')
_debug seg "$seg"
_domain_id=$(printf "%s\n" "$seg" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")
_debug _domain_id "$_domain_id"
if [ "$_domain_id" ]; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_debug _sub_domain "$_sub_domain"
_domain="$h"
_debug _domain "$_domain"
return 0
fi
return 1
fi
p="$i"
i=$(_math "$i" + 1)
done
return 1
}
#Usage: method URI data
_rest() {
m=$1
ep="$2"
_debug ep "$ep"
url="$REST_API/$ep"
_debug url "$url"
cdate=$(date -u "+%Y-%m-%d %H:%M:%S UTC")
_debug cdate "$cdate"
data="$3"
_debug data "$data"
sec="$CX_Key$url$data$cdate$CX_Secret"
_debug sec "$sec"
hmac=$(printf "%s" "$sec" | _digest md5 hex)
_debug hmac "$hmac"
export _H1="API-KEY: $CX_Key"
export _H2="API-REQUEST-DATE: $cdate"
export _H3="API-HMAC: $hmac"
export _H4="Content-Type: application/json"
if [ "$data" ]; then
response="$(_post "$data" "$url" "" "$m")"
else
response="$(_get "$url")"
fi
if [ "$?" != "0" ]; then
_err "error $ep"
return 1
fi
_debug2 response "$response"
_contains "$response" '"code":1'
}

146
dnsapi/dns_fornex.sh Normal file
View File

@@ -0,0 +1,146 @@
#!/usr/bin/env sh
#Author: Timur Umarov <inbox@tumarov.com>
FORNEX_API_URL="https://fornex.com/api/dns/v0.1"
######## Public functions #####################
#Usage: dns_fornex_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_fornex_add() {
fulldomain=$1
txtvalue=$2
if ! _Fornex_API; then
return 1
fi
if ! _get_root "$fulldomain"; then
_err "Unable to determine root domain"
return 1
else
_debug _domain "$_domain"
fi
_info "Adding record"
if _rest POST "$_domain/entry_set/add/" "host=$fulldomain&type=TXT&value=$txtvalue&apikey=$FORNEX_API_KEY"; then
_debug _response "$response"
if _contains "$response" '"ok": true' || _contains "$response" 'Такая запись уже существует.'; then
_info "Added, OK"
return 0
fi
fi
_err "Add txt record error."
return 1
}
#Usage: dns_fornex_rm _acme-challenge.www.domain.com
dns_fornex_rm() {
fulldomain=$1
txtvalue=$2
if ! _Fornex_API; then
return 1
fi
if ! _get_root "$fulldomain"; then
_err "Unable to determine root domain"
return 1
else
_debug _domain "$_domain"
fi
_debug "Getting txt records"
_rest GET "$_domain/entry_set.json?apikey=$FORNEX_API_KEY"
if ! _contains "$response" "$txtvalue"; then
_err "Txt record not found"
return 1
fi
_record_id="$(echo "$response" | _egrep_o "{[^{]*\"value\"*:*\"$txtvalue\"[^}]*}" | sed -n -e 's#.*"id": \([0-9]*\).*#\1#p')"
_debug "_record_id" "$_record_id"
if [ -z "$_record_id" ]; then
_err "can not find _record_id"
return 1
fi
if ! _rest POST "$_domain/entry_set/$_record_id/delete/" "apikey=$FORNEX_API_KEY"; then
_err "Delete record error."
return 1
fi
return 0
}
#################### Private functions below ##################################
#_acme-challenge.www.domain.com
#returns
# _sub_domain=_acme-challenge.www
# _domain=domain.com
_get_root() {
domain=$1
i=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 ! _rest GET "domain_list.json?q=$h&apikey=$FORNEX_API_KEY"; then
return 1
fi
if _contains "$response" "\"$h\"" >/dev/null; then
_domain=$h
return 0
else
_debug "$h not found"
fi
i=$(_math "$i" + 1)
done
return 1
}
_Fornex_API() {
FORNEX_API_KEY="${FORNEX_API_KEY:-$(_readaccountconf_mutable FORNEX_API_KEY)}"
if [ -z "$FORNEX_API_KEY" ]; then
FORNEX_API_KEY=""
_err "You didn't specify the Fornex API key yet."
_err "Please create your key and try again."
return 1
fi
_saveaccountconf_mutable FORNEX_API_KEY "$FORNEX_API_KEY"
}
#method method action data
_rest() {
m=$1
ep="$2"
data="$3"
_debug "$ep"
export _H1="Accept: application/json"
if [ "$m" != "GET" ]; then
_debug data "$data"
response="$(_post "$data" "$FORNEX_API_URL/$ep" "" "$m")"
else
response="$(_get "$FORNEX_API_URL/$ep" | _normalizeJson)"
fi
_ret="$?"
if [ "$_ret" != "0" ]; then
_err "error $ep"
return 1
fi
_debug2 response "$response"
return 0
}

View File

@@ -1,177 +0,0 @@
#!/usr/bin/env sh
#Author: Herman Sletteng
#Report Bugs here: https://github.com/loial/acme.sh
#
#
# Note, gratisdns requires a login first, so the script needs to handle
# temporary cookies. Since acme.sh _get/_post currently don't directly support
# cookies, I've defined wrapper functions _myget/_mypost to set the headers
GDNSDK_API="https://admin.gratisdns.com"
######## Public functions #####################
#Usage: dns_gdnsdk_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_gdnsdk_add() {
fulldomain=$1
txtvalue=$2
_info "Using gratisdns.dk"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
if ! _gratisdns_login; then
_err "Login failed!"
return 1
fi
#finding domain zone
if ! _get_domain; then
_err "No matching root domain for $fulldomain found"
return 1
fi
# adding entry
_info "Adding the entry"
_mypost "action=dns_primary_record_added_txt&user_domain=$_domain&name=$fulldomain&txtdata=$txtvalue&ttl=1"
if _successful_update; then return 0; fi
_err "Couldn't create entry!"
return 1
}
#Usage: fulldomain txtvalue
#Remove the txt record after validation.
dns_gdnsdk_rm() {
fulldomain=$1
txtvalue=$2
_info "Using gratisdns.dk"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
if ! _gratisdns_login; then
_err "Login failed!"
return 1
fi
if ! _get_domain; then
_err "No matching root domain for $fulldomain found"
return 1
fi
_findentry "$fulldomain" "$txtvalue"
if [ -z "$_id" ]; then
_info "Entry doesn't exist, nothing to delete"
return 0
fi
_debug "Deleting record..."
_mypost "action=dns_primary_delete_txt&user_domain=$_domain&id=$_id"
# removing entry
if _successful_update; then return 0; fi
_err "Couldn't delete entry!"
return 1
}
#################### Private functions below ##################################
_checkcredentials() {
GDNSDK_Username="${GDNSDK_Username:-$(_readaccountconf_mutable GDNSDK_Username)}"
GDNSDK_Password="${GDNSDK_Password:-$(_readaccountconf_mutable GDNSDK_Password)}"
if [ -z "$GDNSDK_Username" ] || [ -z "$GDNSDK_Password" ]; then
GDNSDK_Username=""
GDNSDK_Password=""
_err "You haven't specified gratisdns.dk username and password yet."
_err "Please add credentials and try again."
return 1
fi
#save the credentials to the account conf file.
_saveaccountconf_mutable GDNSDK_Username "$GDNSDK_Username"
_saveaccountconf_mutable GDNSDK_Password "$GDNSDK_Password"
return 0
}
_checkcookie() {
GDNSDK_Cookie="${GDNSDK_Cookie:-$(_readaccountconf_mutable GDNSDK_Cookie)}"
if [ -z "$GDNSDK_Cookie" ]; then
_debug "No cached cookie found"
return 1
fi
_myget "action="
if (echo "$_result" | grep -q "logmeout"); then
_debug "Cached cookie still valid"
return 0
fi
_debug "Cached cookie no longer valid"
GDNSDK_Cookie=""
_saveaccountconf_mutable GDNSDK_Cookie "$GDNSDK_Cookie"
return 1
}
_gratisdns_login() {
if ! _checkcredentials; then return 1; fi
if _checkcookie; then
_debug "Already logged in"
return 0
fi
_debug "Logging into GratisDNS with user $GDNSDK_Username"
if ! _mypost "login=$GDNSDK_Username&password=$GDNSDK_Password&action=logmein"; then
_err "GratisDNS login failed for user $GDNSDK_Username bad RC from _post"
return 1
fi
GDNSDK_Cookie="$(grep -A 15 '302 Found' "$HTTP_HEADER" | _egrep_o 'Cookie: [^;]*' | _head_n 1 | cut -d ' ' -f2)"
if [ -z "$GDNSDK_Cookie" ]; then
_err "GratisDNS login failed for user $GDNSDK_Username. Check $HTTP_HEADER file"
return 1
fi
export GDNSDK_Cookie
_saveaccountconf_mutable GDNSDK_Cookie "$GDNSDK_Cookie"
return 0
}
_myget() {
#Adds cookie to request
export _H1="Cookie: $GDNSDK_Cookie"
_result=$(_get "$GDNSDK_API?$1")
}
_mypost() {
#Adds cookie to request
export _H1="Cookie: $GDNSDK_Cookie"
_result=$(_post "$1" "$GDNSDK_API")
}
_get_domain() {
_myget 'action=dns_primarydns'
_domains=$(echo "$_result" | _egrep_o ' domain="[[:alnum:]._-]+' | sed 's/^.*"//')
if [ -z "$_domains" ]; then
_err "Primary domain list not found!"
return 1
fi
for _domain in $_domains; do
if (_endswith "$fulldomain" "$_domain"); then
_debug "Root domain: $_domain"
return 0
fi
done
return 1
}
_successful_update() {
if (echo "$_result" | grep -q 'table-success'); then return 0; fi
return 1
}
_findentry() {
#args $1: fulldomain, $2: txtvalue
#returns id of dns entry, if it exists
_myget "action=dns_primary_changeDNSsetup&user_domain=$_domain"
_debug3 "_result: $_result"
_tmp_result=$(echo "$_result" | tr -d '\n\r' | _egrep_o "<td>$1</td>\s*<td>$2</td>[^?]*[^&]*&id=[^&]*")
_debug _tmp_result "$_tmp_result"
if [ -z "${_tmp_result:-}" ]; then
_debug "The variable is _tmp_result is not supposed to be empty, there may be something wrong with the script"
fi
_id=$(echo "$_tmp_result" | sed 's/^.*=//')
if [ -n "$_id" ]; then
_debug "Entry found with _id=$_id"
return 0
fi
return 1
}

232
dnsapi/dns_geoscaling.sh Executable file
View File

@@ -0,0 +1,232 @@
#!/usr/bin/env sh
########################################################################
# Geoscaling hook script for acme.sh
#
# Environment variables:
#
# - $GEOSCALING_Username (your Geoscaling username - this is usually NOT an amail address)
# - $GEOSCALING_Password (your Geoscaling password)
#-- dns_geoscaling_add() - Add TXT record --------------------------------------
# Usage: dns_geoscaling_add _acme-challenge.subdomain.domain.com "XyZ123..."
dns_geoscaling_add() {
full_domain=$1
txt_value=$2
_info "Using DNS-01 Geoscaling DNS2 hook"
GEOSCALING_Username="${GEOSCALING_Username:-$(_readaccountconf_mutable GEOSCALING_Username)}"
GEOSCALING_Password="${GEOSCALING_Password:-$(_readaccountconf_mutable GEOSCALING_Password)}"
if [ -z "$GEOSCALING_Username" ] || [ -z "$GEOSCALING_Password" ]; then
GEOSCALING_Username=
GEOSCALING_Password=
_err "No auth details provided. Please set user credentials using the \$GEOSCALING_Username and \$GEOSCALING_Password environment variables."
return 1
fi
_saveaccountconf_mutable GEOSCALING_Username "${GEOSCALING_Username}"
_saveaccountconf_mutable GEOSCALING_Password "${GEOSCALING_Password}"
# Fills in the $zone_id and $zone_name
find_zone "${full_domain}" || return 1
_debug "Zone id '${zone_id}' will be used."
# We're logged in here
# we should add ${full_domain} minus the trailing ${zone_name}
prefix=$(echo "${full_domain}" | sed "s|\\.${zone_name}\$||")
body="id=${zone_id}&name=${prefix}&type=TXT&content=${txt_value}&ttl=300&prio=0"
do_post "$body" "https://www.geoscaling.com/dns2/ajax/add_record.php"
exit_code="$?"
if [ "${exit_code}" -eq 0 ]; then
_info "TXT record added successfully."
else
_err "Couldn't add the TXT record."
fi
do_logout
return "${exit_code}"
}
#-- dns_geoscaling_rm() - Remove TXT record ------------------------------------
# Usage: dns_geoscaling_rm _acme-challenge.subdomain.domain.com "XyZ123..."
dns_geoscaling_rm() {
full_domain=$1
txt_value=$2
_info "Cleaning up after DNS-01 Geoscaling DNS2 hook"
GEOSCALING_Username="${GEOSCALING_Username:-$(_readaccountconf_mutable GEOSCALING_Username)}"
GEOSCALING_Password="${GEOSCALING_Password:-$(_readaccountconf_mutable GEOSCALING_Password)}"
if [ -z "$GEOSCALING_Username" ] || [ -z "$GEOSCALING_Password" ]; then
GEOSCALING_Username=
GEOSCALING_Password=
_err "No auth details provided. Please set user credentials using the \$GEOSCALING_Username and \$GEOSCALING_Password environment variables."
return 1
fi
_saveaccountconf_mutable GEOSCALING_Username "${GEOSCALING_Username}"
_saveaccountconf_mutable GEOSCALING_Password "${GEOSCALING_Password}"
# fills in the $zone_id
find_zone "${full_domain}" || return 1
_debug "Zone id '${zone_id}' will be used."
# Here we're logged in
# Find the record id to clean
# get the domain
response=$(do_get "https://www.geoscaling.com/dns2/index.php?module=domain&id=${zone_id}")
_debug2 "response" "$response"
table="$(echo "${response}" | tr -d '\n' | sed 's|.*<div class="box"><div class="boxtitle">Basic Records</div><div class="boxtext"><table|<table|; s|</table>.*|</table>|')"
_debug2 table "${table}"
names=$(echo "${table}" | _egrep_o 'id="[0-9]+\.name">[^<]*</td>' | sed 's|</td>||; s|.*>||')
ids=$(echo "${table}" | _egrep_o 'id="[0-9]+\.name">[^<]*</td>' | sed 's|\.name">.*||; s|id="||')
types=$(echo "${table}" | _egrep_o 'id="[0-9]+\.type">[^<]*</td>' | sed 's|</td>||; s|.*>||')
values=$(echo "${table}" | _egrep_o 'id="[0-9]+\.content">[^<]*</td>' | sed 's|</td>||; s|.*>||')
_debug2 names "${names}"
_debug2 ids "${ids}"
_debug2 types "${types}"
_debug2 values "${values}"
# look for line whose name is ${full_domain}, whose type is TXT, and whose value is ${txt_value}
line_num="$(echo "${values}" | grep -F -n -- "${txt_value}" | _head_n 1 | cut -d ':' -f 1)"
_debug2 line_num "${line_num}"
found_id=
if [ -n "$line_num" ]; then
type=$(echo "${types}" | sed -n "${line_num}p")
name=$(echo "${names}" | sed -n "${line_num}p")
id=$(echo "${ids}" | sed -n "${line_num}p")
_debug2 type "$type"
_debug2 name "$name"
_debug2 id "$id"
_debug2 full_domain "$full_domain"
if [ "${type}" = "TXT" ] && [ "${name}" = "${full_domain}" ]; then
found_id=${id}
fi
fi
if [ "${found_id}" = "" ]; then
_err "Can not find record id."
return 0
fi
# Remove the record
body="id=${zone_id}&record_id=${found_id}"
response=$(do_post "$body" "https://www.geoscaling.com/dns2/ajax/delete_record.php")
exit_code="$?"
if [ "$exit_code" -eq 0 ]; then
_info "Record removed successfully."
else
_err "Could not clean (remove) up the record. Please go to Geoscaling administration interface and clean it by hand."
fi
do_logout
return "${exit_code}"
}
########################## PRIVATE FUNCTIONS ###########################
do_get() {
_url=$1
export _H1="Cookie: $geoscaling_phpsessid_cookie"
_get "${_url}"
}
do_post() {
_body=$1
_url=$2
export _H1="Cookie: $geoscaling_phpsessid_cookie"
_post "${_body}" "${_url}"
}
do_login() {
_info "Logging in..."
username_encoded="$(printf "%s" "${GEOSCALING_Username}" | _url_encode)"
password_encoded="$(printf "%s" "${GEOSCALING_Password}" | _url_encode)"
body="username=${username_encoded}&password=${password_encoded}"
response=$(_post "$body" "https://www.geoscaling.com/dns2/index.php?module=auth")
_debug2 response "${response}"
#retcode=$(grep '^HTTP[^ ]*' "${HTTP_HEADER}" | _head_n 1 | _egrep_o '[0-9]+$')
retcode=$(grep '^HTTP[^ ]*' "${HTTP_HEADER}" | _head_n 1 | cut -d ' ' -f 2)
if [ "$retcode" != "302" ]; then
_err "Geoscaling login failed for user ${GEOSCALING_Username}. Check ${HTTP_HEADER} file"
return 1
fi
geoscaling_phpsessid_cookie="$(grep -i '^set-cookie:' "${HTTP_HEADER}" | _egrep_o 'PHPSESSID=[^;]*;' | tr -d ';')"
return 0
}
do_logout() {
_info "Logging out."
response="$(do_get "https://www.geoscaling.com/dns2/index.php?module=auth")"
_debug2 response "$response"
return 0
}
find_zone() {
domain="$1"
# do login
do_login || return 1
# get zones
response="$(do_get "https://www.geoscaling.com/dns2/index.php?module=domains")"
table="$(echo "${response}" | tr -d '\n' | sed 's|.*<div class="box"><div class="boxtitle">Your domains</div><div class="boxtext"><table|<table|; s|</table>.*|</table>|')"
_debug2 table "${table}"
zone_names="$(echo "${table}" | _egrep_o '<b>[^<]*</b>' | sed 's|<b>||;s|</b>||')"
_debug2 _matches "${zone_names}"
# Zone names and zone IDs are in same order
zone_ids=$(echo "${table}" | _egrep_o '<a href=.index\.php\?module=domain&id=[0-9]+. onclick="javascript:show_loader\(\);">' | sed 's|.*id=||;s|. .*||')
_debug2 "These are the zones on this Geoscaling account:"
_debug2 "zone_names" "${zone_names}"
_debug2 "And these are their respective IDs:"
_debug2 "zone_ids" "${zone_ids}"
if [ -z "${zone_names}" ] || [ -z "${zone_ids}" ]; then
_err "Can not get zone names or IDs."
return 1
fi
# Walk through all possible zone names
strip_counter=1
while true; do
attempted_zone=$(echo "${domain}" | cut -d . -f ${strip_counter}-)
# All possible zone names have been tried
if [ -z "${attempted_zone}" ]; then
_err "No zone for domain '${domain}' found."
return 1
fi
_debug "Looking for zone '${attempted_zone}'"
line_num="$(echo "${zone_names}" | grep -n "^${attempted_zone}\$" | _head_n 1 | cut -d : -f 1)"
_debug2 line_num "${line_num}"
if [ "$line_num" ]; then
zone_id=$(echo "${zone_ids}" | sed -n "${line_num}p")
zone_name=$(echo "${zone_names}" | sed -n "${line_num}p")
if [ -z "${zone_id}" ]; then
_err "Can not find zone id."
return 1
fi
_debug "Found relevant zone '${attempted_zone}' with id '${zone_id}' - will be used for domain '${domain}'."
return 0
fi
_debug "Zone '${attempted_zone}' doesn't exist, let's try a less specific zone."
strip_counter=$(_math "${strip_counter}" + 1)
done
}
# vim: et:ts=2:sw=2:

View File

@@ -32,7 +32,7 @@ dns_ispconfig_rm() {
#################### Private functions below ##################################
_ISPC_credentials() {
if [ -z "${ISPC_User}" ] || [ -z "$ISPC_Password" ] || [ -z "${ISPC_Api}" ] || [ -n "${ISPC_Api_Insecure}" ]; then
if [ -z "${ISPC_User}" ] || [ -z "${ISPC_Password}" ] || [ -z "${ISPC_Api}" ] || [ -z "${ISPC_Api_Insecure}" ]; then
ISPC_User=""
ISPC_Password=""
ISPC_Api=""

View File

@@ -32,8 +32,12 @@ dns_loopia_add() {
_info "Adding record"
_loopia_add_sub_domain "$_domain" "$_sub_domain"
_loopia_add_record "$_domain" "$_sub_domain" "$txtvalue"
if ! _loopia_add_sub_domain "$_domain" "$_sub_domain"; then
return 1
fi
if ! _loopia_add_record "$_domain" "$_sub_domain" "$txtvalue"; then
return 1
fi
}
@@ -70,12 +74,13 @@ dns_loopia_rm() {
<value><string>%s</string></value>
</param>
</params>
</methodCall>' "$LOOPIA_User" "$LOOPIA_Password" "$_domain" "$_sub_domain")
</methodCall>' "$LOOPIA_User" "$Encoded_Password" "$_domain" "$_sub_domain")
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
if ! _contains "$response" "OK"; then
_err "Error could not get txt records"
err_response=$(echo "$response" | sed 's/.*<string>\(.*\)<\/string>.*/\1/')
_err "Error could not get txt records: $err_response"
return 1
fi
}
@@ -101,6 +106,12 @@ _loopia_load_config() {
return 1
fi
if _contains "$LOOPIA_Password" "'" || _contains "$LOOPIA_Password" '"'; then
_err "Password contains quoute or double quoute and this is not supported by dns_loopia.sh"
return 1
fi
Encoded_Password=$(_xml_encode "$LOOPIA_Password")
return 0
}
@@ -133,11 +144,12 @@ _loopia_get_records() {
<value><string>%s</string></value>
</param>
</params>
</methodCall>' $LOOPIA_User $LOOPIA_Password "$domain" "$sub_domain")
</methodCall>' "$LOOPIA_User" "$Encoded_Password" "$domain" "$sub_domain")
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
if ! _contains "$response" "<array>"; then
_err "Error"
err_response=$(echo "$response" | sed 's/.*<string>\(.*\)<\/string>.*/\1/')
_err "Error: $err_response"
return 1
fi
return 0
@@ -162,7 +174,7 @@ _get_root() {
<value><string>%s</string></value>
</param>
</params>
</methodCall>' $LOOPIA_User $LOOPIA_Password)
</methodCall>' "$LOOPIA_User" "$Encoded_Password")
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
while true; do
@@ -206,32 +218,35 @@ _loopia_add_record() {
<value><string>%s</string></value>
</param>
<param>
<struct>
<member>
<name>type</name>
<value><string>TXT</string></value>
</member>
<member>
<name>priority</name>
<value><int>0</int></value>
</member>
<member>
<name>ttl</name>
<value><int>300</int></value>
</member>
<member>
<name>rdata</name>
<value><string>%s</string></value>
</member>
</struct>
<value>
<struct>
<member>
<name>type</name>
<value><string>TXT</string></value>
</member>
<member>
<name>priority</name>
<value><int>0</int></value>
</member>
<member>
<name>ttl</name>
<value><int>300</int></value>
</member>
<member>
<name>rdata</name>
<value><string>%s</string></value>
</member>
</struct>
</value>
</param>
</params>
</methodCall>' $LOOPIA_User $LOOPIA_Password "$domain" "$sub_domain" "$txtval")
</methodCall>' "$LOOPIA_User" "$Encoded_Password" "$domain" "$sub_domain" "$txtval")
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
if ! _contains "$response" "OK"; then
_err "Error"
err_response=$(echo "$response" | sed 's/.*<string>\(.*\)<\/string>.*/\1/')
_err "Error: $err_response"
return 1
fi
return 0
@@ -255,7 +270,7 @@ _sub_domain_exists() {
<value><string>%s</string></value>
</param>
</params>
</methodCall>' $LOOPIA_User $LOOPIA_Password "$domain")
</methodCall>' "$LOOPIA_User" "$Encoded_Password" "$domain")
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
@@ -290,13 +305,22 @@ _loopia_add_sub_domain() {
<value><string>%s</string></value>
</param>
</params>
</methodCall>' $LOOPIA_User $LOOPIA_Password "$domain" "$sub_domain")
</methodCall>' "$LOOPIA_User" "$Encoded_Password" "$domain" "$sub_domain")
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
if ! _contains "$response" "OK"; then
_err "Error"
err_response=$(echo "$response" | sed 's/.*<string>\(.*\)<\/string>.*/\1/')
_err "Error: $err_response"
return 1
fi
return 0
}
_xml_encode() {
encoded_string=$1
encoded_string=$(echo "$encoded_string" | sed 's/&/\&amp;/')
encoded_string=$(echo "$encoded_string" | sed 's/</\&lt;/')
encoded_string=$(echo "$encoded_string" | sed 's/>/\&gt;/')
printf "%s" "$encoded_string"
}

View File

@@ -74,7 +74,7 @@ dns_mydevil_rm() {
validRecords="^${num}${w}${fulldomain}${w}TXT${w}${any}${txtvalue}$"
for id in $(devil dns list "$domain" | tail -n+2 | grep "${validRecords}" | cut -w -s -f 1); do
_info "Removing record $id from domain $domain"
devil dns del "$domain" "$id" || _err "Could not remove DNS record."
echo "y" | devil dns del "$domain" "$id" || _err "Could not remove DNS record."
done
}
@@ -87,7 +87,9 @@ mydevil_get_domain() {
domain=""
for domain in $(devil dns list | cut -w -s -f 1 | tail -n+2); do
_debug "Checking domain: $domain"
if _endswith "$fulldomain" "$domain"; then
_debug "Fulldomain '$fulldomain' matches '$domain'"
printf -- "%s" "$domain"
return 0
fi

View File

@@ -114,7 +114,7 @@ _get_root() {
fi
if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
_domain_id=$(echo "$response" | _egrep_o "\"[^\"]*\",\"name\":\"$h" | cut -d , -f 1 | tr -d \")
_domain_id=$(echo "$response" | _egrep_o "\"[^\"]*\",\"name\":\"$h\"" | cut -d , -f 1 | tr -d \")
if [ "$_domain_id" ]; then
if [ "$i" = 1 ]; then
#create the record at the domain apex (@) if only the domain name was provided as --domain-alias

View File

@@ -150,8 +150,7 @@ _get_root() {
return 1
fi
_debug h "$h"
id=$(echo "$_domain_response" | _egrep_o "\"[^\"]*\":{\"enabled\":\"1\",\"type\":{\"master\":{\"value\":\"master\",\"selected\":1},\"slave\":{\"value\":\"slave\",\"selected\":0}},\"masterip\":{\"\":{[^}]*}}(,\"allownotifyslave\":{\"\":{[^}]*}},|,)\"domainname\":\"${h}\"" | cut -d ':' -f 1 | cut -d '"' -f 2)
id=$(echo "$_domain_response" | _egrep_o "\"[^\"]*\":{\"enabled\":\"1\",\"type\":{\"master\":{\"value\":\"master\",\"selected\":1},\"slave\":{\"value\":\"slave\",\"selected\":0}},\"masterip\":{\"[^\"]*\":{[^}]*}},\"transferkeyalgo\":{[^{]*{[^{]*{[^{]*{[^{]*{[^{]*{[^{]*{[^{]*{[^}]*}},\"transferkey\":\"[^\"]*\"(,\"allownotifyslave\":{\"\":{[^}]*}},|,)\"domainname\":\"${h}\"" | cut -d ':' -f 1 | cut -d '"' -f 2)
if [ -n "$id" ]; then
_debug id "$id"
_host=$(printf "%s" "$domain" | cut -d . -f 1-$p)

View File

@@ -198,6 +198,8 @@ dns_ovh_rm() {
if ! _ovh_rest DELETE "domain/zone/$_domain/record/$rid"; then
return 1
fi
_ovh_rest POST "domain/zone/$_domain/refresh"
_debug "Refresh:$response"
return 0
fi
done

View File

@@ -5,8 +5,8 @@
#SIMPLY_AccountName="accountname"
#SIMPLY_ApiKey="apikey"
#
#SIMPLY_Api="https://api.simply.com/1/[ACCOUNTNAME]/[APIKEY]"
SIMPLY_Api_Default="https://api.simply.com/1"
#SIMPLY_Api="https://api.simply.com/2/"
SIMPLY_Api_Default="https://api.simply.com/2"
#This is used for determining success of REST call
SIMPLY_SUCCESS_CODE='"status":200'
@@ -237,12 +237,18 @@ _simply_rest() {
_debug2 ep "$ep"
_debug2 m "$m"
export _H1="Content-Type: application/json"
basicauth=$(printf "%s:%s" "$SIMPLY_AccountName" "$SIMPLY_ApiKey" | _base64)
if [ "$basicauth" ]; then
export _H1="Authorization: Basic $basicauth"
fi
export _H2="Content-Type: application/json"
if [ "$m" != "GET" ]; then
response="$(_post "$data" "$SIMPLY_Api/$SIMPLY_AccountName/$SIMPLY_ApiKey/$ep" "" "$m")"
response="$(_post "$data" "$SIMPLY_Api/$ep" "" "$m")"
else
response="$(_get "$SIMPLY_Api/$SIMPLY_AccountName/$SIMPLY_ApiKey/$ep")"
response="$(_get "$SIMPLY_Api/$ep")"
fi
if [ "$?" != "0" ]; then

160
dnsapi/dns_udr.sh Normal file
View File

@@ -0,0 +1,160 @@
#!/usr/bin/env sh
# united-domains Reselling (https://www.ud-reselling.com/) DNS API
# Author: Andreas Scherer (https://github.com/andischerer)
# Created: 2021-02-01
#
# Set the environment variables as below:
#
# export UDR_USER="your_username_goes_here"
# export UDR_PASS="some_password_goes_here"
#
UDR_API="https://api.domainreselling.de/api/call.cgi"
UDR_TTL="30"
######## Public functions #####################
#Usage: add _acme-challenge.www.domain.com "some_long_string_of_characters_go_here_from_lets_encrypt"
dns_udr_add() {
fulldomain=$1
txtvalue=$2
UDR_USER="${UDR_USER:-$(_readaccountconf_mutable UDR_USER)}"
UDR_PASS="${UDR_PASS:-$(_readaccountconf_mutable UDR_PASS)}"
if [ -z "$UDR_USER" ] || [ -z "$UDR_PASS" ]; then
UDR_USER=""
UDR_PASS=""
_err "You didn't specify an UD-Reselling username and password yet"
return 1
fi
# save the username and password to the account conf file.
_saveaccountconf_mutable UDR_USER "$UDR_USER"
_saveaccountconf_mutable UDR_PASS "$UDR_PASS"
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain"
return 1
fi
_debug _dnszone "${_dnszone}"
_debug "Getting txt records"
if ! _udr_rest "QueryDNSZoneRRList" "dnszone=${_dnszone}"; then
return 1
fi
rr="${fulldomain}. ${UDR_TTL} IN TXT ${txtvalue}"
_debug resource_record "${rr}"
if _contains "$response" "$rr" >/dev/null; then
_err "Error, it would appear that this record already exists. Please review existing TXT records for this domain."
return 1
fi
_info "Adding record"
if ! _udr_rest "UpdateDNSZone" "dnszone=${_dnszone}&addrr0=${rr}"; then
_err "Adding the record did not succeed, please verify/check."
return 1
fi
_info "Added, OK"
return 0
}
dns_udr_rm() {
fulldomain=$1
txtvalue=$2
UDR_USER="${UDR_USER:-$(_readaccountconf_mutable UDR_USER)}"
UDR_PASS="${UDR_PASS:-$(_readaccountconf_mutable UDR_PASS)}"
if [ -z "$UDR_USER" ] || [ -z "$UDR_PASS" ]; then
UDR_USER=""
UDR_PASS=""
_err "You didn't specify an UD-Reselling username and password yet"
return 1
fi
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain"
return 1
fi
_debug _dnszone "${_dnszone}"
_debug "Getting txt records"
if ! _udr_rest "QueryDNSZoneRRList" "dnszone=${_dnszone}"; then
return 1
fi
rr="${fulldomain}. ${UDR_TTL} IN TXT ${txtvalue}"
_debug resource_record "${rr}"
if _contains "$response" "$rr" >/dev/null; then
if ! _udr_rest "UpdateDNSZone" "dnszone=${_dnszone}&delrr0=${rr}"; then
_err "Deleting the record did not succeed, please verify/check."
return 1
fi
_info "Removed, OK"
return 0
else
_info "Text record is not present, will not delete anything."
return 0
fi
}
#################### Private functions below ##################################
#_acme-challenge.www.domain.com
#returns
# _sub_domain=_acme-challenge.www
# _domain=domain.com
_get_root() {
domain=$1
i=1
if ! _udr_rest "QueryDNSZoneList" ""; then
return 1
fi
while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
_debug h "$h"
if [ -z "$h" ]; then
#not valid
return 1
fi
if _contains "${response}" "${h}." >/dev/null; then
_dnszone=$(echo "$response" | _egrep_o "${h}")
if [ "$_dnszone" ]; then
return 0
fi
return 1
fi
i=$(_math "$i" + 1)
done
return 1
}
_udr_rest() {
if [ -n "$2" ]; then
data="command=$1&$2"
else
data="command=$1"
fi
_debug data "${data}"
response="$(_post "${data}" "${UDR_API}?s_login=${UDR_USER}&s_pw=${UDR_PASS}" "" "POST")"
_code=$(echo "$response" | _egrep_o "code = ([0-9]+)" | _head_n 1 | cut -d = -f 2 | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
_description=$(echo "$response" | _egrep_o "description = .*" | _head_n 1 | cut -d = -f 2 | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
_debug response_code "$_code"
_debug response_description "$_description"
if [ ! "$_code" = "200" ]; then
_err "DNS-API-Error: $_description"
return 1
fi
return 0
}

View File

@@ -24,7 +24,7 @@ dns_world4you_add() {
fi
export _H1="Cookie: W4YSESSID=$sessid"
form=$(_get "$WORLD4YOU_API/dashboard/paketuebersicht")
form=$(_get "$WORLD4YOU_API/")
_get_paketnr "$fqdn" "$form"
paketnr="$PAKETNR"
if [ -z "$paketnr" ]; then
@@ -54,15 +54,14 @@ dns_world4you_add() {
if _contains "$res" "successfully"; then
return 0
else
msg=$(echo "$res" | tr '\n' '\t' | sed 's/.*<h3 class="mb-5">[^\t]*\t *\([^\t]*\)\t.*/\1/')
if _contains "$msg" '^<\!DOCTYPE html>'; then
msg='Unknown error'
fi
_err "Unable to add record: $msg"
if _contains "$msg" '^<\!DOCTYPE html>'; then
msg=$(echo "$res" | grep -A 15 'data-type="danger"' | grep "<h3[^>]*>[^<]" | sed 's/<[^>]*>\|^\s*//g')
if [ "$msg" = '' ]; then
_err "Unable to add record: Unknown error"
echo "$ret" >'error-01.html'
echo "$res" >'error-02.html'
_err "View error-01.html and error-02.html for debugging"
else
_err "Unable to add record: my.world4you.com: $msg"
fi
return 1
fi
@@ -87,7 +86,7 @@ dns_world4you_rm() {
fi
export _H1="Cookie: W4YSESSID=$sessid"
form=$(_get "$WORLD4YOU_API/dashboard/paketuebersicht")
form=$(_get "$WORLD4YOU_API/")
_get_paketnr "$fqdn" "$form"
paketnr="$PAKETNR"
if [ -z "$paketnr" ]; then
@@ -119,15 +118,14 @@ dns_world4you_rm() {
if _contains "$res" "successfully"; then
return 0
else
msg=$(echo "$res" | tr '\n' '\t' | sed 's/.*<h3 class="mb-5">[^\t]*\t *\([^\t]*\)\t.*/\1/')
if _contains "$msg" '^<\!DOCTYPE html>'; then
msg='Unknown error'
fi
_err "Unable to remove record: $msg"
if _contains "$msg" '^<\!DOCTYPE html>'; then
msg=$(echo "$res" | grep -A 15 'data-type="danger"' | grep "<h3[^>]*>[^<]" | sed 's/<[^>]*>\|^\s*//g')
if [ "$msg" = '' ]; then
_err "Unable to remove record: Unknown error"
echo "$ret" >'error-01.html'
echo "$res" >'error-02.html'
_err "View error-01.html and error-02.html for debugging"
else
_err "Unable to remove record: my.world4you.com: $msg"
fi
return 1
fi
@@ -184,7 +182,7 @@ _get_paketnr() {
fqdn="$1"
form="$2"
domains=$(echo "$form" | grep '^ *[A-Za-z0-9_\.-]*\.[A-Za-z0-9_-]*$' | sed 's/^ *\(.*\)$/\1/')
domains=$(echo "$form" | grep 'header-paket-domain' | sed 's/<[^>]*>//g' | sed 's/^.*>\([^>]*\)$/\1/')
domain=''
for domain in $domains; do
if _contains "$fqdn" "$domain\$"; then
@@ -199,6 +197,6 @@ _get_paketnr() {
TLD="$domain"
_debug domain "$domain"
RECORD=$(echo "$fqdn" | cut -c"1-$((${#fqdn} - ${#TLD} - 1))")
PAKETNR=$(echo "$form" | grep "data-textfilter=\".* $domain " | _head_n 1 | sed 's/^.* \([0-9]*\) .*$/\1/')
PAKETNR=$(echo "$form" | grep "data-textfilter=\".* $domain " | _tail_n 1 | sed "s|.*$WORLD4YOU_API/\\([0-9]*\\)/.*|\\1|")
return 0
}

57
notify/discord.sh Normal file
View File

@@ -0,0 +1,57 @@
#!/usr/bin/env sh
#Support Discord webhooks
# Required:
#DISCORD_WEBHOOK_URL=""
# Optional:
#DISCORD_USERNAME=""
#DISCORD_AVATAR_URL=""
discord_send() {
_subject="$1"
_content="$2"
_statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped
_debug "_statusCode" "$_statusCode"
DISCORD_WEBHOOK_URL="${DISCORD_WEBHOOK_URL:-$(_readaccountconf_mutable DISCORD_WEBHOOK_URL)}"
if [ -z "$DISCORD_WEBHOOK_URL" ]; then
DISCORD_WEBHOOK_URL=""
_err "You didn't specify a Discord webhook url DISCORD_WEBHOOK_URL yet."
return 1
fi
_saveaccountconf_mutable DISCORD_WEBHOOK_URL "$DISCORD_WEBHOOK_URL"
DISCORD_USERNAME="${DISCORD_USERNAME:-$(_readaccountconf_mutable DISCORD_USERNAME)}"
if [ "$DISCORD_USERNAME" ]; then
_saveaccountconf_mutable DISCORD_USERNAME "$DISCORD_USERNAME"
fi
DISCORD_AVATAR_URL="${DISCORD_AVATAR_URL:-$(_readaccountconf_mutable DISCORD_AVATAR_URL)}"
if [ "$DISCORD_AVATAR_URL" ]; then
_saveaccountconf_mutable DISCORD_AVATAR_URL "$DISCORD_AVATAR_URL"
fi
export _H1="Content-Type: application/json"
_content="$(printf "**%s**\n%s" "$_subject" "$_content" | _json_encode)"
_data="{\"content\": \"$_content\" "
if [ "$DISCORD_USERNAME" ]; then
_data="$_data, \"username\": \"$DISCORD_USERNAME\" "
fi
if [ "$DISCORD_AVATAR_URL" ]; then
_data="$_data, \"avatar_url\": \"$DISCORD_AVATAR_URL\" "
fi
_data="$_data}"
if _post "$_data" "$DISCORD_WEBHOOK_URL?wait=true"; then
# shellcheck disable=SC2154
if [ "$response" ]; then
_info "discord send success."
return 0
fi
fi
_err "discord send error."
_err "$response"
return 1
}

49
notify/weixin_work.sh Normal file
View File

@@ -0,0 +1,49 @@
#!/usr/bin/env sh
#Support weixin work webhooks api
#WEIXIN_WORK_WEBHOOK="xxxx"
#optional
#WEIXIN_WORK_KEYWORD="yyyy"
#`WEIXIN_WORK_SIGNING_KEY`="SEC08ffdbd403cbc3fc8a65xxxxxxxxxxxxxxxxxxxx"
# subject content statusCode
weixin_work_send() {
_subject="$1"
_content="$2"
_statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped
_debug "_subject" "$_subject"
_debug "_content" "$_content"
_debug "_statusCode" "$_statusCode"
WEIXIN_WORK_WEBHOOK="${WEIXIN_WORK_WEBHOOK:-$(_readaccountconf_mutable WEIXIN_WORK_WEBHOOK)}"
if [ -z "$WEIXIN_WORK_WEBHOOK" ]; then
WEIXIN_WORK_WEBHOOK=""
_err "You didn't specify a weixin_work webhooks WEIXIN_WORK_WEBHOOK yet."
_err "You can get yours from https://work.weixin.qq.com/api/doc/90000/90136/91770"
return 1
fi
_saveaccountconf_mutable WEIXIN_WORK_WEBHOOK "$WEIXIN_WORK_WEBHOOK"
WEIXIN_WORK_KEYWORD="${WEIXIN_WORK_KEYWORD:-$(_readaccountconf_mutable WEIXIN_WORK_KEYWORD)}"
if [ "$WEIXIN_WORK_KEYWORD" ]; then
_saveaccountconf_mutable WEIXIN_WORK_KEYWORD "$WEIXIN_WORK_KEYWORD"
fi
_content=$(echo "$_content" | _json_encode)
_subject=$(echo "$_subject" | _json_encode)
_data="{\"msgtype\": \"text\", \"text\": {\"content\": \"[$WEIXIN_WORK_KEYWORD]\n$_subject\n$_content\"}}"
response="$(_post "$_data" "$WEIXIN_WORK_WEBHOOK" "" "POST" "application/json")"
if [ "$?" = "0" ] && _contains "$response" "errmsg\":\"ok"; then
_info "weixin_work webhooks event fired success."
return 0
fi
_err "weixin_work webhooks event fired error."
_err "$response"
return 1
}