mirror of
https://github.com/acmesh-official/acme.sh
synced 2025-11-05 14:35:45 +08:00
Compare commits
679 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b7caf7a016 | ||
|
|
891198e4f3 | ||
|
|
38c5910be4 | ||
|
|
327e2fb0a4 | ||
|
|
c20c219990 | ||
|
|
4c30250782 | ||
|
|
caf23f9a04 | ||
|
|
beab808b76 | ||
|
|
6c8920f63e | ||
|
|
51be15f66d | ||
|
|
110e25e784 | ||
|
|
8414100d0b | ||
|
|
a3f4cb154e | ||
|
|
e6e22a1ca1 | ||
|
|
b937665b90 | ||
|
|
a7bc2293c0 | ||
|
|
0d25f7612b | ||
|
|
84e4181ed7 | ||
|
|
f66a29d1c3 | ||
|
|
dbd3881cea | ||
|
|
7eb6bbe65f | ||
|
|
a570fda1cb | ||
|
|
3b06fa6523 | ||
|
|
dcdbe2fbb8 | ||
|
|
dc1f36da43 | ||
|
|
05dbd395e6 | ||
|
|
69e7360cc3 | ||
|
|
7ef2533b98 | ||
|
|
97f87c4229 | ||
|
|
42a5cd961d | ||
|
|
bf00d3157f | ||
|
|
cf3ff4c136 | ||
|
|
7fe06adcfd | ||
|
|
ae3e5dbf2c | ||
|
|
20304590b4 | ||
|
|
2d8c0c0131 | ||
|
|
70f4cad2ca | ||
|
|
1f777a94a7 | ||
|
|
7560c64f46 | ||
|
|
bddde60522 | ||
|
|
e9366f8c76 | ||
|
|
4dba84d09e | ||
|
|
0cce2d6098 | ||
|
|
acbd8bce21 | ||
|
|
dea8a08b64 | ||
|
|
dde1bab1a8 | ||
|
|
799e402077 | ||
|
|
ce629e8e70 | ||
|
|
20cfc4ac66 | ||
|
|
132d5e8253 | ||
|
|
cb8b341fb4 | ||
|
|
982c54b605 | ||
|
|
67f543332a | ||
|
|
88ac4086c2 | ||
|
|
15f96b7239 | ||
|
|
0ea84ad799 | ||
|
|
1522b713da | ||
|
|
fe6b27bb59 | ||
|
|
df14b15397 | ||
|
|
7dd12044de | ||
|
|
06e12a30e7 | ||
|
|
d3fefd223d | ||
|
|
c0639c6608 | ||
|
|
05a2eb3df4 | ||
|
|
d4befeb536 | ||
|
|
f7f1168aad | ||
|
|
d6cf15368a | ||
|
|
a5fbf3fb80 | ||
|
|
3cf8f78745 | ||
|
|
59dab6eac7 | ||
|
|
553d861b8a | ||
|
|
7b5d94d062 | ||
|
|
cb021efaee | ||
|
|
c2344f3717 | ||
|
|
f537c606f7 | ||
|
|
c8f48a4a90 | ||
|
|
c2ad1b4e46 | ||
|
|
ba9d146d6c | ||
|
|
a5b04a0328 | ||
|
|
01249d0cb9 | ||
|
|
71c273fbcb | ||
|
|
aa9cbf7c55 | ||
|
|
429b18ed48 | ||
|
|
2690c05781 | ||
|
|
e3b688c9d8 | ||
|
|
41b6f18a5d | ||
|
|
5a59c39036 | ||
|
|
a02dd18ad7 | ||
|
|
16bdc7d0a3 | ||
|
|
40002e8040 | ||
|
|
6748c55c04 | ||
|
|
deb63b4adf | ||
|
|
015a9b9271 | ||
|
|
ab2305e259 | ||
|
|
b99c998057 | ||
|
|
6c0a7144f6 | ||
|
|
bf50fce5bd | ||
|
|
8718b156c4 | ||
|
|
7bbdd1f839 | ||
|
|
ffed1a4afa | ||
|
|
1bfd3642e8 | ||
|
|
577f4e0cc3 | ||
|
|
e2f05f3fc9 | ||
|
|
27f30631ed | ||
|
|
1ccfa96c2e | ||
|
|
a2c64e79ff | ||
|
|
7b623f85cd | ||
|
|
ed63eb6833 | ||
|
|
b8d0d3c242 | ||
|
|
fe1bfe9ae1 | ||
|
|
7154c9ee5d | ||
|
|
057c95bd1c | ||
|
|
0cafc00c4f | ||
|
|
75d2898efd | ||
|
|
764a4c99fa | ||
|
|
160513c671 | ||
|
|
a2af26635f | ||
|
|
63869deeb2 | ||
|
|
91e387e8b9 | ||
|
|
7d13146859 | ||
|
|
699d2b7e7e | ||
|
|
257de15c73 | ||
|
|
5a0225d033 | ||
|
|
bd2d0e6ad3 | ||
|
|
0c0d1d4e52 | ||
|
|
eab9603921 | ||
|
|
c07db3aa14 | ||
|
|
a19f7481b2 | ||
|
|
2905edce35 | ||
|
|
04a5d794ac | ||
|
|
264b9819ff | ||
|
|
4610204c83 | ||
|
|
ecf1f17cf4 | ||
|
|
9f942a6b65 | ||
|
|
f4ed1b32b8 | ||
|
|
ec0e871592 | ||
|
|
7a756ebc4d | ||
|
|
16dc21afff | ||
|
|
3a1c6d84f0 | ||
|
|
e684abdacd | ||
|
|
e275cb1efd | ||
|
|
60315e5b91 | ||
|
|
43b1a4bf5a | ||
|
|
cdb238e41c | ||
|
|
3871e44d9c | ||
|
|
5a51454d13 | ||
|
|
d102943a32 | ||
|
|
a0b27ddbd8 | ||
|
|
b950b04e89 | ||
|
|
c9a55f395b | ||
|
|
424da01878 | ||
|
|
3c933158c8 | ||
|
|
7221d488e5 | ||
|
|
1c16931e26 | ||
|
|
0a4b70dbd2 | ||
|
|
666c716bda | ||
|
|
be477d7ae3 | ||
|
|
6c8a623b88 | ||
|
|
ff8de34415 | ||
|
|
f8ca6d9833 | ||
|
|
dbab519004 | ||
|
|
e888c96591 | ||
|
|
59519f0493 | ||
|
|
e02f07d356 | ||
|
|
2c90d220b8 | ||
|
|
9feeba8d4b | ||
|
|
45090fc897 | ||
|
|
d761bdc1b1 | ||
|
|
287a8c76b5 | ||
|
|
a7dd86de71 | ||
|
|
c541a2e5de | ||
|
|
41dbf1ddac | ||
|
|
70ed6b96d1 | ||
|
|
ef26075a1c | ||
|
|
91c87446be | ||
|
|
dd207e1f02 | ||
|
|
e947870da9 | ||
|
|
f0b5f592dc | ||
|
|
773a2a6cfe | ||
|
|
c2a7e384ba | ||
|
|
4a8b35ef5f | ||
|
|
5cd0db32df | ||
|
|
ef01de6149 | ||
|
|
4e9749f655 | ||
|
|
abb7a1fd47 | ||
|
|
60bcee8c1d | ||
|
|
8ded524236 | ||
|
|
0a47f48191 | ||
|
|
8601267b90 | ||
|
|
6767e0c52d | ||
|
|
5141d1775d | ||
|
|
374af996d9 | ||
|
|
dcc9624c15 | ||
|
|
b3df1a2bf8 | ||
|
|
3fc3c02a4f | ||
|
|
874ddf9a32 | ||
|
|
69aeb70cc3 | ||
|
|
47e60cefe3 | ||
|
|
4ea7f3cda5 | ||
|
|
03288b521a | ||
|
|
4b0a7a6e1f | ||
|
|
383287adcd | ||
|
|
5c00afc6fe | ||
|
|
025e0e8093 | ||
|
|
35fb1f8585 | ||
|
|
9fb14eef0e | ||
|
|
5d6d0c6176 | ||
|
|
dd707242ef | ||
|
|
4f32f1285a | ||
|
|
a6ecdbae29 | ||
|
|
4904d100ff | ||
|
|
7a1f94bc20 | ||
|
|
f9320fff8f | ||
|
|
3dde83d8a0 | ||
|
|
f3e77a989c | ||
|
|
f3539b0354 | ||
|
|
4e5d4b9695 | ||
|
|
864315f6d1 | ||
|
|
713b7338ea | ||
|
|
53117b2f4c | ||
|
|
90623142e1 | ||
|
|
43503a20e5 | ||
|
|
ec53b27dfe | ||
|
|
238ecfc539 | ||
|
|
b888792940 | ||
|
|
e3d1ab52f8 | ||
|
|
f9c2874c35 | ||
|
|
2304f005e3 | ||
|
|
b95f836256 | ||
|
|
c94f9f21af | ||
|
|
fc336e3733 | ||
|
|
fc1df9f9a5 | ||
|
|
5a604bfdee | ||
|
|
281951a86b | ||
|
|
35ec3adadc | ||
|
|
b9256a1ba7 | ||
|
|
734c9a1aa5 | ||
|
|
6502a71083 | ||
|
|
f2634b44cd | ||
|
|
dcf9c467c3 | ||
|
|
3dcacc1f8d | ||
|
|
7cb81b0f35 | ||
|
|
8155ba5224 | ||
|
|
7169060425 | ||
|
|
ddb9dd4e45 | ||
|
|
2a05f24cb6 | ||
|
|
039e4c662d | ||
|
|
70351677a1 | ||
|
|
33cadfb97d | ||
|
|
5fbaeda217 | ||
|
|
b44ba0d21a | ||
|
|
b42532afe9 | ||
|
|
da6a335b87 | ||
|
|
0e8fef73bb | ||
|
|
7122a960fa | ||
|
|
d5b649a1a4 | ||
|
|
233c724b2d | ||
|
|
e1eb001872 | ||
|
|
5899d7034f | ||
|
|
23c3e9482f | ||
|
|
dd980d9dca | ||
|
|
d4ed50a915 | ||
|
|
d986c7d126 | ||
|
|
67a2a4f249 | ||
|
|
a6e87e7e08 | ||
|
|
33da8a7f62 | ||
|
|
68c533f777 | ||
|
|
671eecf203 | ||
|
|
2454ac8ef1 | ||
|
|
20f097faa4 | ||
|
|
5dba8b493d | ||
|
|
eb27013fba | ||
|
|
4f8d1c5c9d | ||
|
|
74168c3e05 | ||
|
|
cece848801 | ||
|
|
7ddbeaa078 | ||
|
|
2d4aa7ff8b | ||
|
|
79e044ac31 | ||
|
|
15ae5a5135 | ||
|
|
5684b7c329 | ||
|
|
7e96120353 | ||
|
|
cc36421fe5 | ||
|
|
683aa727d5 | ||
|
|
ea07b495ac | ||
|
|
8d211c3524 | ||
|
|
ab8df82563 | ||
|
|
8ba9c4ab97 | ||
|
|
2f70b8682e | ||
|
|
86dd4ea480 | ||
|
|
204e5f4418 | ||
|
|
044a9bb6d3 | ||
|
|
a31143328e | ||
|
|
2bb29a105c | ||
|
|
0013d98d04 | ||
|
|
916743f44b | ||
|
|
edebe65d95 | ||
|
|
c43fcd0af6 | ||
|
|
9a5c2b88dc | ||
|
|
aaee0414c8 | ||
|
|
d0c2fb9761 | ||
|
|
4f076c6924 | ||
|
|
51d4d1451a | ||
|
|
7b9d76dc65 | ||
|
|
f91aeea91c | ||
|
|
4cabf84be9 | ||
|
|
8a1f038a80 | ||
|
|
c9cab9ab74 | ||
|
|
bd78120bd5 | ||
|
|
0de3bf0ac7 | ||
|
|
2d144a8b43 | ||
|
|
1a140a5515 | ||
|
|
1ea8cfbfb0 | ||
|
|
64fda95186 | ||
|
|
7843c0c1b0 | ||
|
|
a3784854a7 | ||
|
|
8b7c000f47 | ||
|
|
5b8d7a3f29 | ||
|
|
328dbd57d4 | ||
|
|
a8c448f4cb | ||
|
|
de0419228f | ||
|
|
d8a4e47a13 | ||
|
|
bc920949cb | ||
|
|
0717f8591c | ||
|
|
affb65219e | ||
|
|
3e628f2678 | ||
|
|
ddabc38e3f | ||
|
|
c0097497be | ||
|
|
78198bfdaf | ||
|
|
2fb9c923f4 | ||
|
|
c485011ed1 | ||
|
|
0b8ae68213 | ||
|
|
0e73128f40 | ||
|
|
927c003d22 | ||
|
|
bd73823828 | ||
|
|
11582bc7d3 | ||
|
|
20ed4f96ba | ||
|
|
19790e9011 | ||
|
|
3a29e03458 | ||
|
|
e2eb685d76 | ||
|
|
86cb28fe34 | ||
|
|
bcc9679339 | ||
|
|
e5aeff50dc | ||
|
|
5f44c195e9 | ||
|
|
e4387e4aad | ||
|
|
b1b336804d | ||
|
|
9985c43817 | ||
|
|
190cac394c | ||
|
|
ae71a5abf6 | ||
|
|
df199c5788 | ||
|
|
c1ba4f1b55 | ||
|
|
afc0097b12 | ||
|
|
4e9f971c91 | ||
|
|
b1cc28bbda | ||
|
|
80d30bdd30 | ||
|
|
f27566669b | ||
|
|
29f12ddaf4 | ||
|
|
ed15ff0515 | ||
|
|
a8f71f79fe | ||
|
|
68c2478e0e | ||
|
|
be07fe9e9f | ||
|
|
4d8b661d51 | ||
|
|
ca0981645f | ||
|
|
bc7e02b47a | ||
|
|
55a55e9f74 | ||
|
|
b41d40da40 | ||
|
|
ba3e088b23 | ||
|
|
1b59b0b739 | ||
|
|
093cfcdf42 | ||
|
|
41801a60ad | ||
|
|
5ff0957861 | ||
|
|
6913b8beb5 | ||
|
|
c8d17bc363 | ||
|
|
2cbf1259a8 | ||
|
|
59dc513ac3 | ||
|
|
87b110bb86 | ||
|
|
1b3e1a7abe | ||
|
|
0afabc60ae | ||
|
|
2d4ea720eb | ||
|
|
9c757bbe6e | ||
|
|
40e0d72105 | ||
|
|
eba788e8c9 | ||
|
|
444b111a62 | ||
|
|
a364ab4ea7 | ||
|
|
be7840c827 | ||
|
|
a46e51e8db | ||
|
|
789ebb8990 | ||
|
|
e3cd96bf19 | ||
|
|
7746042adc | ||
|
|
dfe80556d3 | ||
|
|
543c4423a2 | ||
|
|
3bd4d32b8d | ||
|
|
56a686d3e0 | ||
|
|
2f97c789dd | ||
|
|
04ca808e80 | ||
|
|
9b79743c5d | ||
|
|
a386826808 | ||
|
|
668894fc4d | ||
|
|
dc882e6279 | ||
|
|
d6eebf82be | ||
|
|
799f509ba9 | ||
|
|
688a234127 | ||
|
|
095697900b | ||
|
|
6ccf617d62 | ||
|
|
b3b4811b2c | ||
|
|
966e4246e5 | ||
|
|
9377c4f3ad | ||
|
|
b876128635 | ||
|
|
c0da801580 | ||
|
|
149310e1ec | ||
|
|
4e625c18dc | ||
|
|
a5d5113be3 | ||
|
|
7900c493af | ||
|
|
76fe5d8831 | ||
|
|
37031721dd | ||
|
|
3cc283cbee | ||
|
|
35cf98fff2 | ||
|
|
ca41ea2d5c | ||
|
|
daffc4e6a4 | ||
|
|
5f3cb9019b | ||
|
|
4951b58b21 | ||
|
|
7be7586971 | ||
|
|
6d64098288 | ||
|
|
4351110082 | ||
|
|
6652138d3e | ||
|
|
c8d0d475e4 | ||
|
|
39b25029fc | ||
|
|
b5cabd6d8e | ||
|
|
b169a5c707 | ||
|
|
4f816c06b0 | ||
|
|
b5f49d9563 | ||
|
|
274fd5ab8b | ||
|
|
e48d7de763 | ||
|
|
f426940bd2 | ||
|
|
6c11dd12d7 | ||
|
|
c2b14d3075 | ||
|
|
8a144ebfee | ||
|
|
5440fcdf54 | ||
|
|
66b2d496af | ||
|
|
444a0282d7 | ||
|
|
f897ab4eb8 | ||
|
|
993c187e37 | ||
|
|
3ce67b282f | ||
|
|
606e59a5d0 | ||
|
|
0f26b1eafb | ||
|
|
d2a9d731ed | ||
|
|
80e6b1fc01 | ||
|
|
58a89edad7 | ||
|
|
bfe47eb152 | ||
|
|
32adc38e94 | ||
|
|
1584971908 | ||
|
|
025bebb3e2 | ||
|
|
4047adcc35 | ||
|
|
d4cf03c9fd | ||
|
|
5ba2068fc2 | ||
|
|
3ce7d410c8 | ||
|
|
74f28021e7 | ||
|
|
f90cbb636a | ||
|
|
c8929ca0cb | ||
|
|
9fb5bb620d | ||
|
|
ed58f32052 | ||
|
|
6d5743c506 | ||
|
|
a551619de6 | ||
|
|
873b113cb3 | ||
|
|
2280e66d73 | ||
|
|
2133897bbe | ||
|
|
bee5cb55a1 | ||
|
|
0a0838b616 | ||
|
|
b376dfa1e6 | ||
|
|
7ac0577b34 | ||
|
|
f16e060e87 | ||
|
|
9aaae24583 | ||
|
|
915ced7b92 | ||
|
|
5a36b9075f | ||
|
|
b5a7f46ecc | ||
|
|
4381657c5e | ||
|
|
d440b2f2b2 | ||
|
|
5b42aea9e7 | ||
|
|
e1d7a6b9ac | ||
|
|
38778f8adc | ||
|
|
8b7a86bd17 | ||
|
|
619bae745b | ||
|
|
2cf72bad30 | ||
|
|
e6959f093c | ||
|
|
8d783e8e1f | ||
|
|
f03098551e | ||
|
|
6887805402 | ||
|
|
7f9074adbf | ||
|
|
64847afc3f | ||
|
|
c4df8090e2 | ||
|
|
fe3523f47a | ||
|
|
199d846acb | ||
|
|
b07e479840 | ||
|
|
9bf37fde02 | ||
|
|
1054325b2d | ||
|
|
ef8cb11707 | ||
|
|
c23c40df8a | ||
|
|
77d606df34 | ||
|
|
e717c9dba2 | ||
|
|
3d312e2140 | ||
|
|
18de21f723 | ||
|
|
6aebaf6f47 | ||
|
|
641f6977a9 | ||
|
|
a092a2fa43 | ||
|
|
84c2b0c3d7 | ||
|
|
24ce7c1991 | ||
|
|
8be3465f94 | ||
|
|
227eac10f1 | ||
|
|
1cbd5485e7 | ||
|
|
610c3cf681 | ||
|
|
96d45cc341 | ||
|
|
8ba7d02fdb | ||
|
|
ef8a199a5a | ||
|
|
db83643c1e | ||
|
|
9b6f775276 | ||
|
|
69040dd668 | ||
|
|
14b5914233 | ||
|
|
a0eabd2298 | ||
|
|
9b27298d54 | ||
|
|
3075b4515a | ||
|
|
39bc417706 | ||
|
|
e11e32cd52 | ||
|
|
019a7bd66b | ||
|
|
4d89ce5d50 | ||
|
|
c31027b284 | ||
|
|
f17ec7a4f5 | ||
|
|
deec6aab1a | ||
|
|
3e8d9a1987 | ||
|
|
5e465a298f | ||
|
|
515c9e7811 | ||
|
|
03c8309703 | ||
|
|
2c28d6b10c | ||
|
|
df79443ed8 | ||
|
|
2b891f7f1d | ||
|
|
e4ed0b1884 | ||
|
|
c8c1c09189 | ||
|
|
08ae8cc3cb | ||
|
|
201673ca8a | ||
|
|
29e23ac9ce | ||
|
|
00483e8cdd | ||
|
|
83da01a2e1 | ||
|
|
7cd6ff054b | ||
|
|
6be2bb2289 | ||
|
|
439defca42 | ||
|
|
8a85bb2989 | ||
|
|
5e7519183d | ||
|
|
40e7eca1ee | ||
|
|
481f02de88 | ||
|
|
6a90856f0e | ||
|
|
dcbbee8adb | ||
|
|
225adcc836 | ||
|
|
0f607413d0 | ||
|
|
922553032b | ||
|
|
b49999721c | ||
|
|
de4c4eedd8 | ||
|
|
bcc984fc09 | ||
|
|
d53262fab6 | ||
|
|
532e44bcea | ||
|
|
3fb67629c1 | ||
|
|
6145465823 | ||
|
|
fb5091a388 | ||
|
|
d6c68f1a84 | ||
|
|
0d05f9ba80 | ||
|
|
a300df0020 | ||
|
|
a50158cbeb | ||
|
|
7278fd25e5 | ||
|
|
6fb8c0ec4c | ||
|
|
07cedc55e2 | ||
|
|
ae3cc81f03 | ||
|
|
97a45e3b02 | ||
|
|
451b290b79 | ||
|
|
499ea07934 | ||
|
|
afa06267a2 | ||
|
|
d4a6d9c076 | ||
|
|
c3f6112443 | ||
|
|
3411b736dd | ||
|
|
c603b9c40b | ||
|
|
1e2c5d038f | ||
|
|
9d6d96adf3 | ||
|
|
8d574ecb34 | ||
|
|
9ebb2ac2e4 | ||
|
|
7b935eec5d | ||
|
|
b209f66654 | ||
|
|
b98b4951b4 | ||
|
|
227d62a5dc | ||
|
|
7fae5553a8 | ||
|
|
6ead019873 | ||
|
|
6d2ab4d270 | ||
|
|
a6b58bc88d | ||
|
|
ea3c37d754 | ||
|
|
e58b00d9a2 | ||
|
|
b75e90f8c9 | ||
|
|
e82f3439c3 | ||
|
|
0bc8e3bee5 | ||
|
|
13f80acb2d | ||
|
|
8fe813acff | ||
|
|
0ed4fc6a12 | ||
|
|
b37bf06de8 | ||
|
|
27bbf0ccaf | ||
|
|
e88442cb46 | ||
|
|
930609e875 | ||
|
|
8752d08ce9 | ||
|
|
c46ceb06b4 | ||
|
|
92e4ecce3b | ||
|
|
8a2f673903 | ||
|
|
ac0dd90c37 | ||
|
|
9470850258 | ||
|
|
2982e9943e | ||
|
|
80e13bc24a | ||
|
|
9a677534a7 | ||
|
|
af08d67fad | ||
|
|
a2901d61ea | ||
|
|
aaae83efec | ||
|
|
7369298638 | ||
|
|
a761bd20fa | ||
|
|
01ace11293 | ||
|
|
205e95a246 | ||
|
|
2c2a43e1ec | ||
|
|
0c9a6da623 | ||
|
|
888d91d14a | ||
|
|
2c0cc87b4c | ||
|
|
ee0fadf247 | ||
|
|
9fb89d7fd2 | ||
|
|
af5c36e4ad | ||
|
|
a5f943e227 | ||
|
|
f8532ba812 | ||
|
|
fac4e151cc | ||
|
|
f3a0a25380 | ||
|
|
5a237795ea | ||
|
|
3a99a77104 | ||
|
|
5ce8050e46 | ||
|
|
5ae3a020bd | ||
|
|
af193291fa | ||
|
|
b39df5cef0 | ||
|
|
dc61c9e277 | ||
|
|
10a15e1188 | ||
|
|
a2bb6a4f1f | ||
|
|
38a19fa574 | ||
|
|
9ec4b59afb | ||
|
|
20877146df | ||
|
|
a7f2d89e3f | ||
|
|
190ec0c14c | ||
|
|
62dad721fc | ||
|
|
cc5cfc7525 | ||
|
|
795dee85ef | ||
|
|
dbd5bef038 | ||
|
|
dd2a420578 | ||
|
|
eeee30ca03 | ||
|
|
82e8792737 | ||
|
|
6b18b3df34 | ||
|
|
fcebed19b9 | ||
|
|
af5f6176b5 | ||
|
|
424cc46db0 | ||
|
|
ce47ccecc4 | ||
|
|
d940f17390 | ||
|
|
6351b5d0dc | ||
|
|
9c4ac24a66 | ||
|
|
bf66df2a29 | ||
|
|
962ce380cd | ||
|
|
9769afb944 | ||
|
|
052b45a510 | ||
|
|
84a96e862e | ||
|
|
3105235a7a | ||
|
|
71a32477e4 | ||
|
|
342bce2168 | ||
|
|
86d8cbc4d2 | ||
|
|
6b63bd6a44 | ||
|
|
225707c877 | ||
|
|
66da6f18e3 | ||
|
|
bdf8bf391c | ||
|
|
f66d9e1a22 | ||
|
|
ccd3d96942 | ||
|
|
00b6c6a437 | ||
|
|
21ef3b0ecf | ||
|
|
08d60fcbf2 | ||
|
|
4cda54774a | ||
|
|
613475ac26 | ||
|
|
20d23fcb92 | ||
|
|
6d84f59e6b | ||
|
|
748cb28017 |
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@@ -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
|
||||
|
||||
301
.github/workflows/DNS.yml
vendored
301
.github/workflows/DNS.yml
vendored
@@ -11,6 +11,9 @@ on:
|
||||
- 'dnsapi/*.sh'
|
||||
- '.github/workflows/DNS.yml'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
CheckToken:
|
||||
@@ -53,11 +56,18 @@ jobs:
|
||||
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
||||
CASE: le_test_dnsapi
|
||||
TEST_LOCAL: 1
|
||||
DEBUG: 1
|
||||
DEBUG: ${{ secrets.DEBUG }}
|
||||
http_proxy: ${{ secrets.http_proxy }}
|
||||
https_proxy: ${{ secrets.https_proxy }}
|
||||
TokenName1: ${{ secrets.TokenName1}}
|
||||
TokenName2: ${{ secrets.TokenName2}}
|
||||
TokenName3: ${{ secrets.TokenName3}}
|
||||
TokenName4: ${{ secrets.TokenName4}}
|
||||
TokenName5: ${{ secrets.TokenName5}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Clone acmetest
|
||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- name: Set env file
|
||||
run: |
|
||||
cd ../acmetest
|
||||
@@ -76,11 +86,13 @@ jobs:
|
||||
if [ "${{ secrets.TokenName5}}" ] ; then
|
||||
echo "${{ secrets.TokenName5}}=${{ secrets.TokenValue5}}" >> docker.env
|
||||
fi
|
||||
echo "TEST_DNS_NO_WILDCARD" >> docker.env
|
||||
echo "TEST_DNS_SLEEP" >> docker.env
|
||||
|
||||
- name: Run acmetest
|
||||
run: cd ../acmetest && ./rundocker.sh testall
|
||||
|
||||
|
||||
|
||||
|
||||
MacOS:
|
||||
runs-on: macos-latest
|
||||
needs: Docker
|
||||
@@ -92,33 +104,43 @@ jobs:
|
||||
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
||||
CASE: le_test_dnsapi
|
||||
TEST_LOCAL: 1
|
||||
DEBUG: 1
|
||||
DEBUG: ${{ secrets.DEBUG }}
|
||||
http_proxy: ${{ secrets.http_proxy }}
|
||||
https_proxy: ${{ secrets.https_proxy }}
|
||||
TokenName1: ${{ secrets.TokenName1}}
|
||||
TokenName2: ${{ secrets.TokenName2}}
|
||||
TokenName3: ${{ secrets.TokenName3}}
|
||||
TokenName4: ${{ secrets.TokenName4}}
|
||||
TokenName5: ${{ secrets.TokenName5}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install tools
|
||||
run: brew install socat
|
||||
- name: Clone acmetest
|
||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- name: Run acmetest
|
||||
run: |
|
||||
if [ "${{ secrets.TokenName1}}" ] ; then
|
||||
export ${{ secrets.TokenName1}}=${{ secrets.TokenValue1}}
|
||||
export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName2}}" ] ; then
|
||||
export ${{ secrets.TokenName2}}=${{ secrets.TokenValue2}}
|
||||
export ${{ secrets.TokenName2}}="${{ secrets.TokenValue2}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName3}}" ] ; then
|
||||
export ${{ secrets.TokenName3}}=${{ secrets.TokenValue3}}
|
||||
export ${{ secrets.TokenName3}}="${{ secrets.TokenValue3}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName4}}" ] ; then
|
||||
export ${{ secrets.TokenName4}}=${{ secrets.TokenValue4}}
|
||||
export ${{ secrets.TokenName4}}="${{ secrets.TokenValue4}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName5}}" ] ; then
|
||||
export ${{ secrets.TokenName5}}=${{ secrets.TokenValue5}}
|
||||
export ${{ secrets.TokenName5}}="${{ secrets.TokenValue5}}"
|
||||
fi
|
||||
cd ../acmetest
|
||||
./letest.sh
|
||||
|
||||
|
||||
|
||||
|
||||
Windows:
|
||||
runs-on: windows-latest
|
||||
needs: MacOS
|
||||
@@ -130,12 +152,19 @@ jobs:
|
||||
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
||||
CASE: le_test_dnsapi
|
||||
TEST_LOCAL: 1
|
||||
DEBUG: 1
|
||||
DEBUG: ${{ secrets.DEBUG }}
|
||||
http_proxy: ${{ secrets.http_proxy }}
|
||||
https_proxy: ${{ secrets.https_proxy }}
|
||||
TokenName1: ${{ secrets.TokenName1}}
|
||||
TokenName2: ${{ secrets.TokenName2}}
|
||||
TokenName3: ${{ secrets.TokenName3}}
|
||||
TokenName4: ${{ secrets.TokenName4}}
|
||||
TokenName5: ${{ secrets.TokenName5}}
|
||||
steps:
|
||||
- name: Set git to use LF
|
||||
run: |
|
||||
git config --global core.autocrlf false
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install cygwin base packages with chocolatey
|
||||
run: |
|
||||
choco config get cacheLocation
|
||||
@@ -143,37 +172,39 @@ jobs:
|
||||
shell: cmd
|
||||
- name: Install cygwin additional packages
|
||||
run: |
|
||||
C:\tools\cygwin\cygwinsetup.exe -qgnNdO -R C:/tools/cygwin -s http://mirrors.kernel.org/sourceware/cygwin/ -P socat,curl,cron,unzip,git
|
||||
C:\tools\cygwin\cygwinsetup.exe -qgnNdO -R C:/tools/cygwin -s https://mirrors.kernel.org/sourceware/cygwin/ -P socat,curl,cron,unzip,git
|
||||
shell: cmd
|
||||
- name: Set ENV
|
||||
shell: cmd
|
||||
run: |
|
||||
echo PATH=C:\tools\cygwin\bin;C:\tools\cygwin\usr\bin >> %GITHUB_ENV%
|
||||
- name: Clone acmetest
|
||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- name: Run acmetest
|
||||
shell: bash
|
||||
run: |
|
||||
if [ "${{ secrets.TokenName1}}" ] ; then
|
||||
export ${{ secrets.TokenName1}}=${{ secrets.TokenValue1}}
|
||||
export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName2}}" ] ; then
|
||||
export ${{ secrets.TokenName2}}=${{ secrets.TokenValue2}}
|
||||
export ${{ secrets.TokenName2}}="${{ secrets.TokenValue2}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName3}}" ] ; then
|
||||
export ${{ secrets.TokenName3}}=${{ secrets.TokenValue3}}
|
||||
export ${{ secrets.TokenName3}}="${{ secrets.TokenValue3}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName4}}" ] ; then
|
||||
export ${{ secrets.TokenName4}}=${{ secrets.TokenValue4}}
|
||||
export ${{ secrets.TokenName4}}="${{ secrets.TokenValue4}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName5}}" ] ; then
|
||||
export ${{ secrets.TokenName5}}=${{ secrets.TokenValue5}}
|
||||
export ${{ secrets.TokenName5}}="${{ secrets.TokenValue5}}"
|
||||
fi
|
||||
cd ../acmetest
|
||||
./letest.sh
|
||||
|
||||
|
||||
|
||||
FreeBSD:
|
||||
runs-on: macos-10.15
|
||||
runs-on: macos-12
|
||||
needs: Windows
|
||||
env:
|
||||
TEST_DNS : ${{ secrets.TEST_DNS }}
|
||||
@@ -183,37 +214,48 @@ jobs:
|
||||
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
||||
CASE: le_test_dnsapi
|
||||
TEST_LOCAL: 1
|
||||
DEBUG: 1
|
||||
DEBUG: ${{ secrets.DEBUG }}
|
||||
http_proxy: ${{ secrets.http_proxy }}
|
||||
https_proxy: ${{ secrets.https_proxy }}
|
||||
TokenName1: ${{ secrets.TokenName1}}
|
||||
TokenName2: ${{ secrets.TokenName2}}
|
||||
TokenName3: ${{ secrets.TokenName3}}
|
||||
TokenName4: ${{ secrets.TokenName4}}
|
||||
TokenName5: ${{ secrets.TokenName5}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Clone acmetest
|
||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- uses: vmactions/freebsd-vm@v0.1.4
|
||||
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- uses: vmactions/freebsd-vm@v0
|
||||
with:
|
||||
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
|
||||
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
|
||||
prepare: pkg install -y socat curl
|
||||
usesh: true
|
||||
copyback: false
|
||||
run: |
|
||||
if [ "${{ secrets.TokenName1}}" ] ; then
|
||||
export ${{ secrets.TokenName1}}=${{ secrets.TokenValue1}}
|
||||
export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName2}}" ] ; then
|
||||
export ${{ secrets.TokenName2}}=${{ secrets.TokenValue2}}
|
||||
export ${{ secrets.TokenName2}}="${{ secrets.TokenValue2}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName3}}" ] ; then
|
||||
export ${{ secrets.TokenName3}}=${{ secrets.TokenValue3}}
|
||||
export ${{ secrets.TokenName3}}="${{ secrets.TokenValue3}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName4}}" ] ; then
|
||||
export ${{ secrets.TokenName4}}=${{ secrets.TokenValue4}}
|
||||
export ${{ secrets.TokenName4}}="${{ secrets.TokenValue4}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName5}}" ] ; then
|
||||
export ${{ secrets.TokenName5}}=${{ secrets.TokenValue5}}
|
||||
export ${{ secrets.TokenName5}}="${{ secrets.TokenValue5}}"
|
||||
fi
|
||||
cd ../acmetest
|
||||
./letest.sh
|
||||
|
||||
Solaris:
|
||||
runs-on: macos-10.15
|
||||
|
||||
|
||||
|
||||
OpenBSD:
|
||||
runs-on: macos-12
|
||||
needs: FreeBSD
|
||||
env:
|
||||
TEST_DNS : ${{ secrets.TEST_DNS }}
|
||||
@@ -223,32 +265,201 @@ jobs:
|
||||
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
||||
CASE: le_test_dnsapi
|
||||
TEST_LOCAL: 1
|
||||
DEBUG: 1
|
||||
DEBUG: ${{ secrets.DEBUG }}
|
||||
http_proxy: ${{ secrets.http_proxy }}
|
||||
https_proxy: ${{ secrets.https_proxy }}
|
||||
TokenName1: ${{ secrets.TokenName1}}
|
||||
TokenName2: ${{ secrets.TokenName2}}
|
||||
TokenName3: ${{ secrets.TokenName3}}
|
||||
TokenName4: ${{ secrets.TokenName4}}
|
||||
TokenName5: ${{ secrets.TokenName5}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Clone acmetest
|
||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- uses: vmactions/solaris-vm@v0.0.5
|
||||
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- uses: vmactions/openbsd-vm@v0
|
||||
with:
|
||||
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
|
||||
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
|
||||
prepare: pkg_add socat curl
|
||||
usesh: true
|
||||
copyback: false
|
||||
run: |
|
||||
if [ "${{ secrets.TokenName1}}" ] ; then
|
||||
export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName2}}" ] ; then
|
||||
export ${{ secrets.TokenName2}}="${{ secrets.TokenValue2}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName3}}" ] ; then
|
||||
export ${{ secrets.TokenName3}}="${{ secrets.TokenValue3}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName4}}" ] ; then
|
||||
export ${{ secrets.TokenName4}}="${{ secrets.TokenValue4}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName5}}" ] ; then
|
||||
export ${{ secrets.TokenName5}}="${{ secrets.TokenValue5}}"
|
||||
fi
|
||||
cd ../acmetest
|
||||
./letest.sh
|
||||
|
||||
|
||||
|
||||
|
||||
NetBSD:
|
||||
runs-on: macos-12
|
||||
needs: OpenBSD
|
||||
env:
|
||||
TEST_DNS : ${{ secrets.TEST_DNS }}
|
||||
TestingDomain: ${{ secrets.TestingDomain }}
|
||||
TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
|
||||
TEST_DNS_NO_SUBDOMAIN: ${{ secrets.TEST_DNS_NO_SUBDOMAIN }}
|
||||
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
||||
CASE: le_test_dnsapi
|
||||
TEST_LOCAL: 1
|
||||
DEBUG: ${{ secrets.DEBUG }}
|
||||
http_proxy: ${{ secrets.http_proxy }}
|
||||
https_proxy: ${{ secrets.https_proxy }}
|
||||
TokenName1: ${{ secrets.TokenName1}}
|
||||
TokenName2: ${{ secrets.TokenName2}}
|
||||
TokenName3: ${{ secrets.TokenName3}}
|
||||
TokenName4: ${{ secrets.TokenName4}}
|
||||
TokenName5: ${{ secrets.TokenName5}}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Clone acmetest
|
||||
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- uses: vmactions/netbsd-vm@v0
|
||||
with:
|
||||
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
|
||||
prepare: |
|
||||
pkg_add curl socat
|
||||
usesh: true
|
||||
copyback: false
|
||||
run: |
|
||||
if [ "${{ secrets.TokenName1}}" ] ; then
|
||||
export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName2}}" ] ; then
|
||||
export ${{ secrets.TokenName2}}="${{ secrets.TokenValue2}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName3}}" ] ; then
|
||||
export ${{ secrets.TokenName3}}="${{ secrets.TokenValue3}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName4}}" ] ; then
|
||||
export ${{ secrets.TokenName4}}="${{ secrets.TokenValue4}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName5}}" ] ; then
|
||||
export ${{ secrets.TokenName5}}="${{ secrets.TokenValue5}}"
|
||||
fi
|
||||
cd ../acmetest
|
||||
./letest.sh
|
||||
|
||||
|
||||
|
||||
|
||||
DragonFlyBSD:
|
||||
runs-on: macos-12
|
||||
needs: NetBSD
|
||||
env:
|
||||
TEST_DNS : ${{ secrets.TEST_DNS }}
|
||||
TestingDomain: ${{ secrets.TestingDomain }}
|
||||
TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
|
||||
TEST_DNS_NO_SUBDOMAIN: ${{ secrets.TEST_DNS_NO_SUBDOMAIN }}
|
||||
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
||||
CASE: le_test_dnsapi
|
||||
TEST_LOCAL: 1
|
||||
DEBUG: ${{ secrets.DEBUG }}
|
||||
http_proxy: ${{ secrets.http_proxy }}
|
||||
https_proxy: ${{ secrets.https_proxy }}
|
||||
TokenName1: ${{ secrets.TokenName1}}
|
||||
TokenName2: ${{ secrets.TokenName2}}
|
||||
TokenName3: ${{ secrets.TokenName3}}
|
||||
TokenName4: ${{ secrets.TokenName4}}
|
||||
TokenName5: ${{ secrets.TokenName5}}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Clone acmetest
|
||||
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- uses: vmactions/dragonflybsd-vm@v0
|
||||
with:
|
||||
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
|
||||
prepare: |
|
||||
pkg install -y curl socat
|
||||
usesh: true
|
||||
copyback: false
|
||||
run: |
|
||||
if [ "${{ secrets.TokenName1}}" ] ; then
|
||||
export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName2}}" ] ; then
|
||||
export ${{ secrets.TokenName2}}="${{ secrets.TokenValue2}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName3}}" ] ; then
|
||||
export ${{ secrets.TokenName3}}="${{ secrets.TokenValue3}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName4}}" ] ; then
|
||||
export ${{ secrets.TokenName4}}="${{ secrets.TokenValue4}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName5}}" ] ; then
|
||||
export ${{ secrets.TokenName5}}="${{ secrets.TokenValue5}}"
|
||||
fi
|
||||
cd ../acmetest
|
||||
./letest.sh
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Solaris:
|
||||
runs-on: macos-12
|
||||
needs: DragonFlyBSD
|
||||
env:
|
||||
TEST_DNS : ${{ secrets.TEST_DNS }}
|
||||
TestingDomain: ${{ secrets.TestingDomain }}
|
||||
TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
|
||||
TEST_DNS_NO_SUBDOMAIN: ${{ secrets.TEST_DNS_NO_SUBDOMAIN }}
|
||||
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
||||
CASE: le_test_dnsapi
|
||||
TEST_LOCAL: 1
|
||||
DEBUG: ${{ secrets.DEBUG }}
|
||||
http_proxy: ${{ secrets.http_proxy }}
|
||||
https_proxy: ${{ secrets.https_proxy }}
|
||||
HTTPS_INSECURE: 1 # always set to 1 to ignore https error, since Solaris doesn't accept the expired ISRG X1 root
|
||||
TokenName1: ${{ secrets.TokenName1}}
|
||||
TokenName2: ${{ secrets.TokenName2}}
|
||||
TokenName3: ${{ secrets.TokenName3}}
|
||||
TokenName4: ${{ secrets.TokenName4}}
|
||||
TokenName5: ${{ secrets.TokenName5}}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Clone acmetest
|
||||
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- uses: vmactions/solaris-vm@v0
|
||||
with:
|
||||
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy HTTPS_INSECURE TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
|
||||
copyback: false
|
||||
prepare: pkgutil -y -i socat
|
||||
run: |
|
||||
pkg set-mediator -v -I default@1.1 openssl
|
||||
export PATH=/usr/gnu/bin:$PATH
|
||||
if [ "${{ secrets.TokenName1}}" ] ; then
|
||||
export ${{ secrets.TokenName1}}=${{ secrets.TokenValue1}}
|
||||
export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName2}}" ] ; then
|
||||
export ${{ secrets.TokenName2}}=${{ secrets.TokenValue2}}
|
||||
export ${{ secrets.TokenName2}}="${{ secrets.TokenValue2}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName3}}" ] ; then
|
||||
export ${{ secrets.TokenName3}}=${{ secrets.TokenValue3}}
|
||||
export ${{ secrets.TokenName3}}="${{ secrets.TokenValue3}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName4}}" ] ; then
|
||||
export ${{ secrets.TokenName4}}=${{ secrets.TokenValue4}}
|
||||
export ${{ secrets.TokenName4}}="${{ secrets.TokenValue4}}"
|
||||
fi
|
||||
if [ "${{ secrets.TokenName5}}" ] ; then
|
||||
export ${{ secrets.TokenName5}}=${{ secrets.TokenValue5}}
|
||||
export ${{ secrets.TokenName5}}="${{ secrets.TokenValue5}}"
|
||||
fi
|
||||
cd ../acmetest
|
||||
./letest.sh
|
||||
|
||||
|
||||
|
||||
71
.github/workflows/DragonFlyBSD.yml
vendored
Normal file
71
.github/workflows/DragonFlyBSD.yml
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
name: DragonFlyBSD
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
paths:
|
||||
- '*.sh'
|
||||
- '.github/workflows/DragonFlyBSD.yml'
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
paths:
|
||||
- '*.sh'
|
||||
- '.github/workflows/DragonFlyBSD.yml'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
|
||||
|
||||
|
||||
jobs:
|
||||
DragonFlyBSD:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
||||
CA_ECDSA: ""
|
||||
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: ""
|
||||
runs-on: macos-12
|
||||
env:
|
||||
TEST_LOCAL: 1
|
||||
TEST_ACME_Server: ${{ matrix.TEST_ACME_Server }}
|
||||
CA_ECDSA: ${{ matrix.CA_ECDSA }}
|
||||
CA: ${{ matrix.CA }}
|
||||
CA_EMAIL: ${{ matrix.CA_EMAIL }}
|
||||
TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: vmactions/cf-tunnel@v0
|
||||
id: tunnel
|
||||
with:
|
||||
protocol: http
|
||||
port: 8080
|
||||
- name: Set envs
|
||||
run: echo "TestingDomain=${{steps.tunnel.outputs.server}}" >> $GITHUB_ENV
|
||||
- name: Clone acmetest
|
||||
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- uses: vmactions/dragonflybsd-vm@v0
|
||||
with:
|
||||
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN'
|
||||
copyback: "false"
|
||||
nat: |
|
||||
"8080": "80"
|
||||
prepare: |
|
||||
pkg install -y curl socat
|
||||
usesh: true
|
||||
run: |
|
||||
cd ../acmetest \
|
||||
&& ./letest.sh
|
||||
|
||||
|
||||
37
.github/workflows/FreeBSD.yml
vendored
37
.github/workflows/FreeBSD.yml
vendored
@@ -14,6 +14,11 @@ on:
|
||||
- '*.sh'
|
||||
- '.github/workflows/FreeBSD.yml'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
|
||||
|
||||
jobs:
|
||||
FreeBSD:
|
||||
@@ -25,12 +30,18 @@ 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: ""
|
||||
runs-on: macos-10.15
|
||||
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
||||
CA_ECDSA: ""
|
||||
CA: ""
|
||||
CA_EMAIL: ""
|
||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
||||
ACME_USE_WGET: 1
|
||||
#- 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-12
|
||||
env:
|
||||
TEST_LOCAL: 1
|
||||
TEST_ACME_Server: ${{ matrix.TEST_ACME_Server }}
|
||||
@@ -38,9 +49,10 @@ jobs:
|
||||
CA: ${{ matrix.CA }}
|
||||
CA_EMAIL: ${{ matrix.CA_EMAIL }}
|
||||
TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
|
||||
ACME_USE_WGET: ${{ matrix.ACME_USE_WGET }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: vmactions/cf-tunnel@v0.0.3
|
||||
- uses: actions/checkout@v3
|
||||
- uses: vmactions/cf-tunnel@v0
|
||||
id: tunnel
|
||||
with:
|
||||
protocol: http
|
||||
@@ -48,14 +60,15 @@ jobs:
|
||||
- name: Set envs
|
||||
run: echo "TestingDomain=${{steps.tunnel.outputs.server}}" >> $GITHUB_ENV
|
||||
- name: Clone acmetest
|
||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- uses: vmactions/freebsd-vm@v0.1.5
|
||||
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- uses: vmactions/freebsd-vm@v0
|
||||
with:
|
||||
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN'
|
||||
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
|
||||
nat: |
|
||||
"8080": "80"
|
||||
prepare: pkg install -y socat curl
|
||||
prepare: pkg install -y socat curl wget
|
||||
usesh: true
|
||||
copyback: false
|
||||
run: |
|
||||
cd ../acmetest \
|
||||
&& ./letest.sh
|
||||
|
||||
11
.github/workflows/Linux.yml
vendored
11
.github/workflows/Linux.yml
vendored
@@ -15,6 +15,12 @@ on:
|
||||
- '.github/workflows/Linux.yml'
|
||||
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
|
||||
|
||||
|
||||
jobs:
|
||||
Linux:
|
||||
@@ -25,12 +31,13 @@ jobs:
|
||||
env:
|
||||
TEST_LOCAL: 1
|
||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
||||
TEST_ACME_Server: "LetsEncrypt.org_test"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Clone acmetest
|
||||
run: |
|
||||
cd .. \
|
||||
&& git clone https://github.com/acmesh-official/acmetest.git \
|
||||
&& git clone --depth=1 https://github.com/acmesh-official/acmetest.git \
|
||||
&& cp -r acme.sh acmetest/
|
||||
- name: Run acmetest
|
||||
run: |
|
||||
|
||||
19
.github/workflows/MacOS.yml
vendored
19
.github/workflows/MacOS.yml
vendored
@@ -14,6 +14,11 @@ on:
|
||||
- '*.sh'
|
||||
- '.github/workflows/MacOS.yml'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
|
||||
|
||||
jobs:
|
||||
MacOS:
|
||||
@@ -25,11 +30,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
|
||||
@@ -39,13 +44,13 @@ jobs:
|
||||
CA_EMAIL: ${{ matrix.CA_EMAIL }}
|
||||
TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install tools
|
||||
run: brew install socat
|
||||
- name: Clone acmetest
|
||||
run: |
|
||||
cd .. \
|
||||
&& git clone https://github.com/acmesh-official/acmetest.git \
|
||||
&& git clone --depth=1 https://github.com/acmesh-official/acmetest.git \
|
||||
&& cp -r acme.sh acmetest/
|
||||
- name: Run acmetest
|
||||
run: |
|
||||
|
||||
71
.github/workflows/NetBSD.yml
vendored
Normal file
71
.github/workflows/NetBSD.yml
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
name: NetBSD
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
paths:
|
||||
- '*.sh'
|
||||
- '.github/workflows/NetBSD.yml'
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
paths:
|
||||
- '*.sh'
|
||||
- '.github/workflows/NetBSD.yml'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
|
||||
|
||||
|
||||
jobs:
|
||||
NetBSD:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
||||
CA_ECDSA: ""
|
||||
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: ""
|
||||
runs-on: macos-12
|
||||
env:
|
||||
TEST_LOCAL: 1
|
||||
TEST_ACME_Server: ${{ matrix.TEST_ACME_Server }}
|
||||
CA_ECDSA: ${{ matrix.CA_ECDSA }}
|
||||
CA: ${{ matrix.CA }}
|
||||
CA_EMAIL: ${{ matrix.CA_EMAIL }}
|
||||
TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: vmactions/cf-tunnel@v0
|
||||
id: tunnel
|
||||
with:
|
||||
protocol: http
|
||||
port: 8080
|
||||
- name: Set envs
|
||||
run: echo "TestingDomain=${{steps.tunnel.outputs.server}}" >> $GITHUB_ENV
|
||||
- name: Clone acmetest
|
||||
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- uses: vmactions/netbsd-vm@v0
|
||||
with:
|
||||
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN'
|
||||
nat: |
|
||||
"8080": "80"
|
||||
prepare: |
|
||||
pkg_add curl socat
|
||||
usesh: true
|
||||
copyback: false
|
||||
run: |
|
||||
cd ../acmetest \
|
||||
&& ./letest.sh
|
||||
|
||||
|
||||
76
.github/workflows/OpenBSD.yml
vendored
Normal file
76
.github/workflows/OpenBSD.yml
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
name: OpenBSD
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
paths:
|
||||
- '*.sh'
|
||||
- '.github/workflows/OpenBSD.yml'
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
paths:
|
||||
- '*.sh'
|
||||
- '.github/workflows/OpenBSD.yml'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
|
||||
|
||||
jobs:
|
||||
OpenBSD:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
||||
CA_ECDSA: ""
|
||||
CA: ""
|
||||
CA_EMAIL: ""
|
||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
||||
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
||||
CA_ECDSA: ""
|
||||
CA: ""
|
||||
CA_EMAIL: ""
|
||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
||||
ACME_USE_WGET: 1
|
||||
#- 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-12
|
||||
env:
|
||||
TEST_LOCAL: 1
|
||||
TEST_ACME_Server: ${{ matrix.TEST_ACME_Server }}
|
||||
CA_ECDSA: ${{ matrix.CA_ECDSA }}
|
||||
CA: ${{ matrix.CA }}
|
||||
CA_EMAIL: ${{ matrix.CA_EMAIL }}
|
||||
TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
|
||||
ACME_USE_WGET: ${{ matrix.ACME_USE_WGET }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: vmactions/cf-tunnel@v0
|
||||
id: tunnel
|
||||
with:
|
||||
protocol: http
|
||||
port: 8080
|
||||
- name: Set envs
|
||||
run: echo "TestingDomain=${{steps.tunnel.outputs.server}}" >> $GITHUB_ENV
|
||||
- name: Clone acmetest
|
||||
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- uses: vmactions/openbsd-vm@v0
|
||||
with:
|
||||
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
|
||||
nat: |
|
||||
"8080": "80"
|
||||
prepare: pkg_add socat curl wget
|
||||
usesh: true
|
||||
copyback: false
|
||||
run: |
|
||||
cd ../acmetest \
|
||||
&& ./letest.sh
|
||||
|
||||
|
||||
24
.github/workflows/PebbleStrict.yml
vendored
24
.github/workflows/PebbleStrict.yml
vendored
@@ -13,6 +13,13 @@ on:
|
||||
- '*.sh'
|
||||
- '.github/workflows/PebbleStrict.yml'
|
||||
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
|
||||
|
||||
jobs:
|
||||
PebbleStrict:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -26,7 +33,7 @@ jobs:
|
||||
TEST_CA: "Pebble Intermediate CA"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install tools
|
||||
run: sudo apt-get install -y socat
|
||||
- name: Run Pebble
|
||||
@@ -34,15 +41,15 @@ jobs:
|
||||
- name: Set up Pebble
|
||||
run: curl --request POST --data '{"ip":"10.30.50.1"}' http://localhost:8055/set-default-ipv4
|
||||
- name: Clone acmetest
|
||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- name: Run acmetest
|
||||
run: cd ../acmetest && ./letest.sh
|
||||
|
||||
PebbleStrict_IPCert:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TestingDomain: 10.30.50.1
|
||||
ACME_DIRECTORY: https://localhost:14000/dir
|
||||
TestingDomain: 1.23.45.67
|
||||
TEST_ACME_Server: https://localhost:14000/dir
|
||||
HTTPS_INSECURE: 1
|
||||
Le_HTTPPort: 5002
|
||||
Le_TLSPort: 5001
|
||||
@@ -51,12 +58,15 @@ jobs:
|
||||
TEST_IPCERT: 1
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install tools
|
||||
run: sudo apt-get install -y socat
|
||||
- name: Run Pebble
|
||||
run: cd .. && curl https://raw.githubusercontent.com/letsencrypt/pebble/master/docker-compose.yml >docker-compose.yml && docker-compose up -d
|
||||
run: |
|
||||
docker run --rm -itd --name=pebble \
|
||||
-e PEBBLE_VA_ALWAYS_VALID=1 \
|
||||
-p 14000:14000 -p 15000:15000 letsencrypt/pebble:latest pebble -config /test/config/pebble-config.json -strict
|
||||
- name: Clone acmetest
|
||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- name: Run acmetest
|
||||
run: cd ../acmetest && ./letest.sh
|
||||
37
.github/workflows/Solaris.yml
vendored
37
.github/workflows/Solaris.yml
vendored
@@ -15,6 +15,11 @@ on:
|
||||
- '.github/workflows/Solaris.yml'
|
||||
|
||||
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
Solaris:
|
||||
strategy:
|
||||
@@ -25,12 +30,18 @@ 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: ""
|
||||
runs-on: macos-10.15
|
||||
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
||||
CA_ECDSA: ""
|
||||
CA: ""
|
||||
CA_EMAIL: ""
|
||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
||||
ACME_USE_WGET: 1
|
||||
#- 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-12
|
||||
env:
|
||||
TEST_LOCAL: 1
|
||||
TEST_ACME_Server: ${{ matrix.TEST_ACME_Server }}
|
||||
@@ -38,9 +49,10 @@ jobs:
|
||||
CA: ${{ matrix.CA }}
|
||||
CA_EMAIL: ${{ matrix.CA_EMAIL }}
|
||||
TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
|
||||
ACME_USE_WGET: ${{ matrix.ACME_USE_WGET }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: vmactions/cf-tunnel@v0.0.3
|
||||
- uses: actions/checkout@v3
|
||||
- uses: vmactions/cf-tunnel@v0
|
||||
id: tunnel
|
||||
with:
|
||||
protocol: http
|
||||
@@ -48,13 +60,14 @@ jobs:
|
||||
- name: Set envs
|
||||
run: echo "TestingDomain=${{steps.tunnel.outputs.server}}" >> $GITHUB_ENV
|
||||
- name: Clone acmetest
|
||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- uses: vmactions/solaris-vm@v0.0.5
|
||||
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- uses: vmactions/solaris-vm@v0
|
||||
with:
|
||||
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN'
|
||||
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
|
||||
copyback: "false"
|
||||
nat: |
|
||||
"8080": "80"
|
||||
prepare: pkgutil -y -i socat curl
|
||||
prepare: pkgutil -y -i socat curl wget
|
||||
run: |
|
||||
cd ../acmetest \
|
||||
&& ./letest.sh
|
||||
|
||||
27
.github/workflows/Ubuntu.yml
vendored
27
.github/workflows/Ubuntu.yml
vendored
@@ -14,6 +14,11 @@ on:
|
||||
- '*.sh'
|
||||
- '.github/workflows/Ubuntu.yml'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
|
||||
|
||||
jobs:
|
||||
Ubuntu:
|
||||
@@ -25,6 +30,12 @@ jobs:
|
||||
CA: ""
|
||||
CA_EMAIL: ""
|
||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
||||
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
||||
CA_ECDSA: ""
|
||||
CA: ""
|
||||
CA_EMAIL: ""
|
||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
||||
ACME_USE_WGET: 1
|
||||
- TEST_ACME_Server: "ZeroSSL.com"
|
||||
CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
|
||||
CA: "ZeroSSL RSA Domain Secure Site CA"
|
||||
@@ -57,10 +68,11 @@ jobs:
|
||||
NO_REVOKE: ${{ matrix.NO_REVOKE }}
|
||||
TEST_IPCERT: ${{ matrix.TEST_IPCERT }}
|
||||
TestingDomain: ${{ matrix.TestingDomain }}
|
||||
ACME_USE_WGET: ${{ matrix.ACME_USE_WGET }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install tools
|
||||
run: sudo apt-get install -y socat
|
||||
run: sudo apt-get install -y socat wget
|
||||
- name: Start StepCA
|
||||
if: ${{ matrix.TEST_ACME_Server=='https://localhost:9000/acme/acme/directory' }}
|
||||
run: |
|
||||
@@ -68,15 +80,20 @@ jobs:
|
||||
-p 9000:9000 \
|
||||
-e "DOCKER_STEPCA_INIT_NAME=Smallstep" \
|
||||
-e "DOCKER_STEPCA_INIT_DNS_NAMES=localhost,$(hostname -f)" \
|
||||
-e "DOCKER_STEPCA_INIT_REMOTE_MANAGEMENT=true" \
|
||||
-e "DOCKER_STEPCA_INIT_PASSWORD=test" \
|
||||
--name stepca \
|
||||
smallstep/step-ca \
|
||||
&& sleep 5 && docker exec stepca step ca provisioner add acme --type ACME \
|
||||
smallstep/step-ca:0.23.1
|
||||
|
||||
sleep 5
|
||||
docker exec stepca bash -c "echo test >test" \
|
||||
&& docker exec stepca step ca provisioner add acme --type ACME --admin-subject step --admin-password-file=/home/step/test \
|
||||
&& docker exec stepca kill -1 1 \
|
||||
&& docker exec stepca cat /home/step/certs/root_ca.crt | sudo bash -c "cat - >>/etc/ssl/certs/ca-certificates.crt"
|
||||
- name: Clone acmetest
|
||||
run: |
|
||||
cd .. \
|
||||
&& git clone https://github.com/acmesh-official/acmetest.git \
|
||||
&& git clone --depth=1 https://github.com/acmesh-official/acmetest.git \
|
||||
&& cp -r acme.sh acmetest/
|
||||
- name: Run acmetest
|
||||
run: |
|
||||
|
||||
21
.github/workflows/Windows.yml
vendored
21
.github/workflows/Windows.yml
vendored
@@ -15,6 +15,11 @@ on:
|
||||
- '.github/workflows/Windows.yml'
|
||||
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
|
||||
jobs:
|
||||
Windows:
|
||||
strategy:
|
||||
@@ -25,11 +30,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 }}
|
||||
@@ -44,7 +49,7 @@ jobs:
|
||||
- name: Set git to use LF
|
||||
run: |
|
||||
git config --global core.autocrlf false
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install cygwin base packages with chocolatey
|
||||
run: |
|
||||
choco config get cacheLocation
|
||||
@@ -52,7 +57,7 @@ jobs:
|
||||
shell: cmd
|
||||
- name: Install cygwin additional packages
|
||||
run: |
|
||||
C:\tools\cygwin\cygwinsetup.exe -qgnNdO -R C:/tools/cygwin -s http://mirrors.kernel.org/sourceware/cygwin/ -P socat,curl,cron,unzip,git,xxd
|
||||
C:\tools\cygwin\cygwinsetup.exe -qgnNdO -R C:/tools/cygwin -s https://mirrors.kernel.org/sourceware/cygwin/ -P socat,curl,cron,unzip,git,xxd
|
||||
shell: cmd
|
||||
- name: Set ENV
|
||||
shell: cmd
|
||||
@@ -64,7 +69,7 @@ jobs:
|
||||
echo "PATH=%PATH%"
|
||||
- name: Clone acmetest
|
||||
shell: cmd
|
||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- name: Run acmetest
|
||||
shell: cmd
|
||||
run: cd ../acmetest && bash.exe -c ./letest.sh
|
||||
|
||||
14
.github/workflows/dockerhub.yml
vendored
14
.github/workflows/dockerhub.yml
vendored
@@ -11,6 +11,10 @@ on:
|
||||
- "Dockerfile"
|
||||
- '.github/workflows/dockerhub.yml'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
|
||||
jobs:
|
||||
CheckToken:
|
||||
@@ -24,9 +28,9 @@ jobs:
|
||||
id: step_one
|
||||
run: |
|
||||
if [ "$DOCKER_PASSWORD" ] ; then
|
||||
echo "::set-output name=hasToken::true"
|
||||
echo "hasToken=true" >>$GITHUB_OUTPUT
|
||||
else
|
||||
echo "::set-output name=hasToken::false"
|
||||
echo "hasToken=false" >>$GITHUB_OUTPUT
|
||||
fi
|
||||
- name: Check the value
|
||||
run: echo ${{ steps.step_one.outputs.hasToken }}
|
||||
@@ -37,11 +41,11 @@ jobs:
|
||||
if: "contains(needs.CheckToken.outputs.hasToken, 'true')"
|
||||
steps:
|
||||
- name: checkout code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: login to docker hub
|
||||
run: |
|
||||
echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
|
||||
|
||||
19
.github/workflows/issue.yml
vendored
Normal file
19
.github/workflows/issue.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
name: "Update issues"
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
|
||||
jobs:
|
||||
comment:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: "Please upgrade to the latest code and try again first. Maybe it's already fixed. ```acme.sh --upgrade``` If it's still not working, please provide the log with `--debug 2`, otherwise, nobody can help you."
|
||||
|
||||
})
|
||||
30
.github/workflows/pr_dns.yml
vendored
Normal file
30
.github/workflows/pr_dns.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
name: Check dns api
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
branches:
|
||||
- 'dev'
|
||||
paths:
|
||||
- 'dnsapi/*.sh'
|
||||
|
||||
|
||||
jobs:
|
||||
welcome:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
await github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: `**Welcome**
|
||||
Please make sure you're read our [DNS API Dev Guide](../wiki/DNS-API-Dev-Guide) and [DNS-API-Test](../wiki/DNS-API-Test).
|
||||
Then reply on this message, otherwise, your code will not be reviewed or merged.
|
||||
We look forward to reviewing your Pull request shortly ✨
|
||||
`
|
||||
})
|
||||
|
||||
30
.github/workflows/pr_notify.yml
vendored
Normal file
30
.github/workflows/pr_notify.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
name: Check dns api
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
branches:
|
||||
- 'dev'
|
||||
paths:
|
||||
- 'notify/*.sh'
|
||||
|
||||
|
||||
jobs:
|
||||
welcome:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
await github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: `**Welcome**
|
||||
Please make sure you're read our [Code-of-conduct](../wiki/Code-of-conduct) and add the usage here: [notify](../wiki/notify).
|
||||
Then reply on this message, otherwise, your code will not be reviewed or merged.
|
||||
We look forward to reviewing your Pull request shortly ✨
|
||||
`
|
||||
})
|
||||
|
||||
11
.github/workflows/shellcheck.yml
vendored
11
.github/workflows/shellcheck.yml
vendored
@@ -13,20 +13,25 @@ on:
|
||||
- '**.sh'
|
||||
- '.github/workflows/shellcheck.yml'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
|
||||
jobs:
|
||||
ShellCheck:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install Shellcheck
|
||||
run: sudo apt-get install -y shellcheck
|
||||
- name: DoShellcheck
|
||||
run: shellcheck -V && shellcheck -e SC2181 **/*.sh && echo "shellcheck OK"
|
||||
run: shellcheck -V && shellcheck -e SC2181 -e SC2089 **/*.sh && echo "shellcheck OK"
|
||||
|
||||
shfmt:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install shfmt
|
||||
run: curl -sSL https://github.com/mvdan/sh/releases/download/v3.1.2/shfmt_v3.1.2_linux_amd64 -o ~/shfmt && chmod +x ~/shfmt
|
||||
- name: shfmt
|
||||
|
||||
12
Dockerfile
12
Dockerfile
@@ -1,4 +1,4 @@
|
||||
FROM alpine:3.15
|
||||
FROM alpine:3.17
|
||||
|
||||
RUN apk --no-cache add -f \
|
||||
openssl \
|
||||
@@ -12,7 +12,8 @@ RUN apk --no-cache add -f \
|
||||
oath-toolkit-oathtool \
|
||||
tar \
|
||||
libidn \
|
||||
jq
|
||||
jq \
|
||||
cronie
|
||||
|
||||
ENV LE_CONFIG_HOME /acme.sh
|
||||
|
||||
@@ -25,7 +26,7 @@ COPY ./ /install_acme.sh/
|
||||
RUN cd /install_acme.sh && ([ -f /install_acme.sh/acme.sh ] && /install_acme.sh/acme.sh --install || curl https://get.acme.sh | sh) && rm -rf /install_acme.sh/
|
||||
|
||||
|
||||
RUN ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh && crontab -l | grep acme.sh | sed 's#> /dev/null##' | crontab -
|
||||
RUN ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh && crontab -l | grep acme.sh | sed 's#> /dev/null#> /proc/1/fd/1 2>/proc/1/fd/2#' | crontab -
|
||||
|
||||
RUN for verb in help \
|
||||
version \
|
||||
@@ -64,11 +65,10 @@ RUN for verb in help \
|
||||
|
||||
RUN printf "%b" '#!'"/usr/bin/env sh\n \
|
||||
if [ \"\$1\" = \"daemon\" ]; then \n \
|
||||
trap \"echo stop && killall crond && exit 0\" SIGTERM SIGINT \n \
|
||||
crond && while true; do sleep 1; done;\n \
|
||||
exec crond -n -s -m off \n \
|
||||
else \n \
|
||||
exec -- \"\$@\"\n \
|
||||
fi" >/entry.sh && chmod +x /entry.sh
|
||||
fi\n" >/entry.sh && chmod +x /entry.sh
|
||||
|
||||
VOLUME /acme.sh
|
||||
|
||||
|
||||
57
README.md
57
README.md
@@ -1,10 +1,14 @@
|
||||
# An ACME Shell script: acme.sh
|
||||
|
||||
[](https://github.com/acmesh-official/acme.sh/actions/workflows/FreeBSD.yml)
|
||||
[](https://github.com/acmesh-official/acme.sh/actions/workflows/OpenBSD.yml)
|
||||
[](https://github.com/acmesh-official/acme.sh/actions/workflows/NetBSD.yml)
|
||||
[](https://github.com/acmesh-official/acme.sh/actions/workflows/MacOS.yml)
|
||||
[](https://github.com/acmesh-official/acme.sh/actions/workflows/Ubuntu.yml)
|
||||
[](https://github.com/acmesh-official/acme.sh/actions/workflows/Windows.yml)
|
||||
[](https://github.com/acmesh-official/acme.sh/actions/workflows/Solaris.yml)
|
||||
[](https://github.com/acmesh-official/acme.sh/actions/workflows/DragonFlyBSD.yml)
|
||||
|
||||
|
||||

|
||||

|
||||
@@ -47,14 +51,12 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa)
|
||||
- [ruby-china.org](https://ruby-china.org/topics/31983)
|
||||
- [Proxmox](https://pve.proxmox.com/wiki/Certificate_Management)
|
||||
- [pfsense](https://github.com/pfsense/FreeBSD-ports/pull/89)
|
||||
- [webfaction](https://community.webfaction.com/questions/19988/using-letsencrypt)
|
||||
- [Loadbalancer.org](https://www.loadbalancer.org/blog/loadbalancer-org-with-lets-encrypt-quick-and-dirty)
|
||||
- [discourse.org](https://meta.discourse.org/t/setting-up-lets-encrypt/40709)
|
||||
- [Centminmod](https://centminmod.com/letsencrypt-acmetool-https.html)
|
||||
- [splynx](https://forum.splynx.com/t/free-ssl-cert-for-splynx-lets-encrypt/297)
|
||||
- [archlinux](https://www.archlinux.org/packages/community/any/acme.sh)
|
||||
- [opnsense.org](https://github.com/opnsense/plugins/tree/master/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient)
|
||||
- [CentOS Web Panel](http://centos-webpanel.com/)
|
||||
- [CentOS Web Panel](https://control-webpanel.com)
|
||||
- [lnmp.org](https://lnmp.org/)
|
||||
- [more...](https://github.com/acmesh-official/acme.sh/wiki/Blogs-and-tutorials)
|
||||
|
||||
@@ -68,21 +70,23 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa)
|
||||
|4|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Solaris.yml)|Solaris
|
||||
|5|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Ubuntu.yml)| Ubuntu
|
||||
|6|NA|pfsense
|
||||
|7|NA|OpenBSD
|
||||
|8|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)| Debian
|
||||
|9|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|CentOS
|
||||
|10|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|openSUSE
|
||||
|11|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Alpine Linux (with curl)
|
||||
|12|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Archlinux
|
||||
|13|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|fedora
|
||||
|14|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Kali Linux
|
||||
|15|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Oracle Linux
|
||||
|16|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Mageia
|
||||
|17|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Gentoo Linux
|
||||
|18|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|ClearLinux
|
||||
|19|-----| Cloud Linux https://github.com/acmesh-official/acme.sh/issues/111
|
||||
|20|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/acmesh-official/acme.sh/wiki/How-to-run-on-OpenWRT)
|
||||
|21|[](https://github.com/acmesh-official/letest#here-are-the-latest-status)| Proxmox: See Proxmox VE Wiki. Version [4.x, 5.0, 5.1](https://pve.proxmox.com/wiki/HTTPS_Certificate_Configuration_(Version_4.x,_5.0_and_5.1)#Let.27s_Encrypt_using_acme.sh), version [5.2 and up](https://pve.proxmox.com/wiki/Certificate_Management)
|
||||
|7|[](https://github.com/acmesh-official/acme.sh/actions/workflows/OpenBSD.yml)|OpenBSD
|
||||
|8|[](https://github.com/acmesh-official/acme.sh/actions/workflows/NetBSD.yml)|NetBSD
|
||||
|9|[](https://github.com/acmesh-official/acme.sh/actions/workflows/DragonFlyBSD.yml)|DragonFlyBSD
|
||||
|10|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)| Debian
|
||||
|11|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|CentOS
|
||||
|12|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|openSUSE
|
||||
|13|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Alpine Linux (with curl)
|
||||
|14|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Archlinux
|
||||
|15|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|fedora
|
||||
|16|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Kali Linux
|
||||
|17|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Oracle Linux
|
||||
|18|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Mageia
|
||||
|19|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Gentoo Linux
|
||||
|10|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|ClearLinux
|
||||
|11|-----| Cloud Linux https://github.com/acmesh-official/acme.sh/issues/111
|
||||
|22|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/acmesh-official/acme.sh/wiki/How-to-run-on-OpenWRT)
|
||||
|23|[](https://github.com/acmesh-official/letest#here-are-the-latest-status)| Proxmox: See Proxmox VE Wiki. Version [4.x, 5.0, 5.1](https://pve.proxmox.com/wiki/HTTPS_Certificate_Configuration_(Version_4.x,_5.0_and_5.1)#Let.27s_Encrypt_using_acme.sh), version [5.2 and up](https://pve.proxmox.com/wiki/Certificate_Management)
|
||||
|
||||
|
||||
Check our [testing project](https://github.com/acmesh-official/acmetest):
|
||||
@@ -95,6 +99,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
|
||||
|
||||
@@ -354,10 +359,6 @@ Ok, it's done.
|
||||
|
||||
# 10. Issue ECC certificates
|
||||
|
||||
`Let's Encrypt` can now issue **ECDSA** certificates.
|
||||
|
||||
And we support them too!
|
||||
|
||||
Just set the `keylength` parameter with a prefix `ec-`.
|
||||
|
||||
For example:
|
||||
@@ -378,10 +379,12 @@ Please look at the `keylength` parameter above.
|
||||
|
||||
Valid values are:
|
||||
|
||||
1. **ec-256 (prime256v1, "ECDSA P-256")**
|
||||
1. **ec-256 (prime256v1, "ECDSA P-256", which is the default key type)**
|
||||
2. **ec-384 (secp384r1, "ECDSA P-384")**
|
||||
3. **ec-521 (secp521r1, "ECDSA P-521", which is not supported by Let's Encrypt yet.)**
|
||||
|
||||
4. **2048 (RSA2048)**
|
||||
5. **3072 (RSA3072)**
|
||||
6. **4096 (RSA4096)**
|
||||
|
||||
|
||||
# 11. Issue Wildcard certificates
|
||||
@@ -502,6 +505,12 @@ Support this project with your organization. Your logo will show up here with a
|
||||
<a href="https://opencollective.com/acmesh/organization/8/website"><img src="https://opencollective.com/acmesh/organization/8/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/acmesh/organization/9/website"><img src="https://opencollective.com/acmesh/organization/9/avatar.svg"></a>
|
||||
|
||||
|
||||
#### Sponsors
|
||||
|
||||
[](https://www.quantumca.com.cn/?__utm_source=acmesh-donation)
|
||||
|
||||
|
||||
# 19. License & Others
|
||||
|
||||
License is GPLv3
|
||||
|
||||
@@ -3,18 +3,29 @@
|
||||
# Uses command line uapi. --user option is needed only if run as root.
|
||||
# Returns 0 when success.
|
||||
#
|
||||
# Configure DEPLOY_CPANEL_AUTO_<...> options to enable or restrict automatic
|
||||
# detection of deployment targets through UAPI (if not set, defaults below are used.)
|
||||
# - ENABLED : 'true' for multi-site / wildcard capability; otherwise single-site mode.
|
||||
# - NOMATCH : 'true' to allow deployment to sites that do not match the certificate.
|
||||
# - INCLUDE : Comma-separated list - sites must match this field.
|
||||
# - EXCLUDE : Comma-separated list - sites must NOT match this field.
|
||||
# INCLUDE/EXCLUDE both support non-lexical, glob-style matches using '*'
|
||||
#
|
||||
# Please note that I am no longer using Github. If you want to report an issue
|
||||
# or contact me, visit https://forum.webseodesigners.com/web-design-seo-and-hosting-f16/
|
||||
#
|
||||
# Written by Santeri Kannisto <santeri.kannisto@webseodesigners.com>
|
||||
# Public domain, 2017-2018
|
||||
|
||||
#export DEPLOY_CPANEL_USER=myusername
|
||||
#
|
||||
# export DEPLOY_CPANEL_USER=myusername
|
||||
# export DEPLOY_CPANEL_AUTO_ENABLED='true'
|
||||
# export DEPLOY_CPANEL_AUTO_NOMATCH='false'
|
||||
# export DEPLOY_CPANEL_AUTO_INCLUDE='*'
|
||||
# export DEPLOY_CPANEL_AUTO_EXCLUDE=''
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#domain keyfile certfile cafile fullchain
|
||||
|
||||
cpanel_uapi_deploy() {
|
||||
_cdomain="$1"
|
||||
_ckey="$2"
|
||||
@@ -22,6 +33,9 @@ cpanel_uapi_deploy() {
|
||||
_cca="$4"
|
||||
_cfullchain="$5"
|
||||
|
||||
# re-declare vars inherited from acme.sh but not passed to make ShellCheck happy
|
||||
: "${Le_Alt:=""}"
|
||||
|
||||
_debug _cdomain "$_cdomain"
|
||||
_debug _ckey "$_ckey"
|
||||
_debug _ccert "$_ccert"
|
||||
@@ -32,31 +46,166 @@ cpanel_uapi_deploy() {
|
||||
_err "The command uapi is not found."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# declare useful constants
|
||||
uapi_error_response='status: 0'
|
||||
|
||||
# read cert and key files and urlencode both
|
||||
_cert=$(_url_encode <"$_ccert")
|
||||
_key=$(_url_encode <"$_ckey")
|
||||
|
||||
_debug _cert "$_cert"
|
||||
_debug _key "$_key"
|
||||
_debug2 _cert "$_cert"
|
||||
_debug2 _key "$_key"
|
||||
|
||||
if [ "$(id -u)" = 0 ]; then
|
||||
if [ -z "$DEPLOY_CPANEL_USER" ]; then
|
||||
_getdeployconf DEPLOY_CPANEL_USER
|
||||
# fallback to _readdomainconf for old installs
|
||||
if [ -z "${DEPLOY_CPANEL_USER:=$(_readdomainconf DEPLOY_CPANEL_USER)}" ]; then
|
||||
_err "It seems that you are root, please define the target user name: export DEPLOY_CPANEL_USER=username"
|
||||
return 1
|
||||
fi
|
||||
_savedomainconf DEPLOY_CPANEL_USER "$DEPLOY_CPANEL_USER"
|
||||
_response=$(uapi --user="$DEPLOY_CPANEL_USER" SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key")
|
||||
else
|
||||
_response=$(uapi SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key")
|
||||
fi
|
||||
error_response="status: 0"
|
||||
if test "${_response#*$error_response}" != "$_response"; then
|
||||
_err "Error in deploying certificate:"
|
||||
_err "$_response"
|
||||
return 1
|
||||
_debug DEPLOY_CPANEL_USER "$DEPLOY_CPANEL_USER"
|
||||
_savedeployconf DEPLOY_CPANEL_USER "$DEPLOY_CPANEL_USER"
|
||||
|
||||
_uapi_user="$DEPLOY_CPANEL_USER"
|
||||
fi
|
||||
|
||||
_debug response "$_response"
|
||||
_info "Certificate successfully deployed"
|
||||
return 0
|
||||
# Load all AUTO envars and set defaults - see above for usage
|
||||
__cpanel_initautoparam ENABLED 'true'
|
||||
__cpanel_initautoparam NOMATCH 'false'
|
||||
__cpanel_initautoparam INCLUDE '*'
|
||||
__cpanel_initautoparam EXCLUDE ''
|
||||
|
||||
# Auto mode
|
||||
if [ "$DEPLOY_CPANEL_AUTO_ENABLED" = "true" ]; then
|
||||
# call API for site config
|
||||
_response=$(uapi DomainInfo list_domains)
|
||||
# exit if error in response
|
||||
if [ -z "$_response" ] || [ "${_response#*"$uapi_error_response"}" != "$_response" ]; then
|
||||
_err "Error in deploying certificate - cannot retrieve sitelist:"
|
||||
_err "\n$_response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# parse response to create site list
|
||||
sitelist=$(__cpanel_parse_response "$_response")
|
||||
_debug "UAPI sites found: $sitelist"
|
||||
|
||||
# filter sitelist using configured domains
|
||||
# skip if NOMATCH is "true"
|
||||
if [ "$DEPLOY_CPANEL_AUTO_NOMATCH" = "true" ]; then
|
||||
_debug "DEPLOY_CPANEL_AUTO_NOMATCH is true"
|
||||
_info "UAPI nomatch mode is enabled - Will not validate sites are valid for the certificate"
|
||||
else
|
||||
_debug "DEPLOY_CPANEL_AUTO_NOMATCH is false"
|
||||
d="$(echo "${Le_Alt}," | sed -e "s/^$_cdomain,//" -e "s/,$_cdomain,/,/")"
|
||||
d="$(echo "$_cdomain,$d" | tr ',' '\n' | sed -e 's/\./\\./g' -e 's/\*/\[\^\.\]\*/g')"
|
||||
sitelist="$(echo "$sitelist" | grep -ix "$d")"
|
||||
_debug2 "Matched UAPI sites: $sitelist"
|
||||
fi
|
||||
|
||||
# filter sites that do not match $DEPLOY_CPANEL_AUTO_INCLUDE
|
||||
_info "Applying sitelist filter DEPLOY_CPANEL_AUTO_INCLUDE: $DEPLOY_CPANEL_AUTO_INCLUDE"
|
||||
sitelist="$(echo "$sitelist" | grep -ix "$(echo "$DEPLOY_CPANEL_AUTO_INCLUDE" | tr ',' '\n' | sed -e 's/\./\\./g' -e 's/\*/\.\*/g')")"
|
||||
_debug2 "Remaining sites: $sitelist"
|
||||
|
||||
# filter sites that match $DEPLOY_CPANEL_AUTO_EXCLUDE
|
||||
_info "Applying sitelist filter DEPLOY_CPANEL_AUTO_EXCLUDE: $DEPLOY_CPANEL_AUTO_EXCLUDE"
|
||||
sitelist="$(echo "$sitelist" | grep -vix "$(echo "$DEPLOY_CPANEL_AUTO_EXCLUDE" | tr ',' '\n' | sed -e 's/\./\\./g' -e 's/\*/\.\*/g')")"
|
||||
_debug2 "Remaining sites: $sitelist"
|
||||
|
||||
# counter for success / failure check
|
||||
successes=0
|
||||
if [ -n "$sitelist" ]; then
|
||||
sitetotal="$(echo "$sitelist" | wc -l)"
|
||||
_debug "$sitetotal sites to deploy"
|
||||
else
|
||||
sitetotal=0
|
||||
_debug "No sites to deploy"
|
||||
fi
|
||||
|
||||
# for each site: call uapi to publish cert and log result. Only return failure if all fail
|
||||
for site in $sitelist; do
|
||||
# call uapi to publish cert, check response for errors and log them.
|
||||
if [ -n "$_uapi_user" ]; then
|
||||
_response=$(uapi --user="$_uapi_user" SSL install_ssl domain="$site" cert="$_cert" key="$_key")
|
||||
else
|
||||
_response=$(uapi SSL install_ssl domain="$site" cert="$_cert" key="$_key")
|
||||
fi
|
||||
if [ "${_response#*"$uapi_error_response"}" != "$_response" ]; then
|
||||
_err "Error in deploying certificate to $site:"
|
||||
_err "$_response"
|
||||
else
|
||||
successes=$((successes + 1))
|
||||
_debug "$_response"
|
||||
_info "Succcessfully deployed to $site"
|
||||
fi
|
||||
done
|
||||
|
||||
# Raise error if all updates fail
|
||||
if [ "$sitetotal" -gt 0 ] && [ "$successes" -eq 0 ]; then
|
||||
_err "Could not deploy to any of $sitetotal sites via UAPI"
|
||||
_debug "successes: $successes, sitetotal: $sitetotal"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Successfully deployed certificate to $successes of $sitetotal sites via UAPI"
|
||||
return 0
|
||||
else
|
||||
# "classic" mode - will only try to deploy to the primary domain; will not check UAPI first
|
||||
if [ -n "$_uapi_user" ]; then
|
||||
_response=$(uapi --user="$_uapi_user" SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key")
|
||||
else
|
||||
_response=$(uapi SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key")
|
||||
fi
|
||||
|
||||
if [ "${_response#*"$uapi_error_response"}" != "$_response" ]; then
|
||||
_err "Error in deploying certificate:"
|
||||
_err "$_response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug response "$_response"
|
||||
_info "Certificate successfully deployed"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
######## Private functions #####################
|
||||
|
||||
# Internal utility to process YML from UAPI - looks at main_domain, sub_domains, addon domains and parked domains
|
||||
#[response]
|
||||
__cpanel_parse_response() {
|
||||
if [ $# -gt 0 ]; then resp="$*"; else resp="$(cat)"; fi
|
||||
|
||||
echo "$resp" |
|
||||
sed -En \
|
||||
-e 's/\r$//' \
|
||||
-e 's/^( *)([_.[:alnum:]]+) *: *(.*)/\1,\2,\3/p' \
|
||||
-e 's/^( *)- (.*)/\1,-,\2/p' |
|
||||
awk -F, '{
|
||||
level = length($1)/2;
|
||||
section[level] = $2;
|
||||
for (i in section) {if (i > level) {delete section[i]}}
|
||||
if (length($3) > 0) {
|
||||
prefix="";
|
||||
for (i=0; i < level; i++)
|
||||
{ prefix = (prefix)(section[i])("/") }
|
||||
printf("%s%s=%s\n", prefix, $2, $3);
|
||||
}
|
||||
}' |
|
||||
sed -En -e 's/^result\/data\/(main_domain|sub_domains\/-|addon_domains\/-|parked_domains\/-)=(.*)$/\2/p'
|
||||
}
|
||||
|
||||
# Load parameter by prefix+name - fallback to default if not set, and save to config
|
||||
#pname pdefault
|
||||
__cpanel_initautoparam() {
|
||||
pname="$1"
|
||||
pdefault="$2"
|
||||
pkey="DEPLOY_CPANEL_AUTO_$pname"
|
||||
|
||||
_getdeployconf "$pkey"
|
||||
[ -n "$(eval echo "\"\$$pkey\"")" ] || eval "$pkey=\"$pdefault\""
|
||||
_debug2 "$pkey" "$(eval echo "\"\$$pkey\"")"
|
||||
_savedeployconf "$pkey" "$(eval echo "\"\$$pkey\"")"
|
||||
}
|
||||
|
||||
@@ -273,16 +273,27 @@ _check_curl_version() {
|
||||
_minor="$(_getfield "$_cversion" 2 '.')"
|
||||
_debug2 "_minor" "$_minor"
|
||||
|
||||
if [ "$_major$_minor" -lt "740" ]; then
|
||||
if [ "$_major" -ge "8" ]; then
|
||||
#ok
|
||||
return 0
|
||||
fi
|
||||
if [ "$_major" = "7" ]; then
|
||||
if [ "$_minor" -lt "40" ]; then
|
||||
_err "curl v$_cversion doesn't support unit socket"
|
||||
_err "Please upgrade to curl 7.40 or later."
|
||||
return 1
|
||||
fi
|
||||
if [ "$_minor" -lt "50" ]; then
|
||||
_debug "Use short host name"
|
||||
export _CURL_NO_HOST=1
|
||||
else
|
||||
export _CURL_NO_HOST=
|
||||
fi
|
||||
return 0
|
||||
else
|
||||
_err "curl v$_cversion doesn't support unit socket"
|
||||
_err "Please upgrade to curl 7.40 or later."
|
||||
return 1
|
||||
fi
|
||||
if [ "$_major$_minor" -lt "750" ]; then
|
||||
_debug "Use short host name"
|
||||
export _CURL_NO_HOST=1
|
||||
else
|
||||
export _CURL_NO_HOST=
|
||||
fi
|
||||
return 0
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Here is the script to deploy the cert to G-Core CDN service (https://gcorelabs.com/ru/) using the G-Core Labs API (https://docs.gcorelabs.com/cdn/).
|
||||
# Here is the script to deploy the cert to G-Core CDN service (https://gcore.com/) using the G-Core Labs API (https://apidocs.gcore.com/cdn).
|
||||
# Returns 0 when success.
|
||||
#
|
||||
# Written by temoffey <temofffey@gmail.com>
|
||||
# Public domain, 2019
|
||||
# Update by DreamOfIce <admin@dreamofice.cn> in 2023
|
||||
|
||||
#export DEPLOY_GCORE_CDN_USERNAME=myusername
|
||||
#export DEPLOY_GCORE_CDN_PASSWORD=mypassword
|
||||
@@ -56,7 +57,7 @@ gcore_cdn_deploy() {
|
||||
_request="{\"username\":\"$Le_Deploy_gcore_cdn_username\",\"password\":\"$Le_Deploy_gcore_cdn_password\"}"
|
||||
_debug _request "$_request"
|
||||
export _H1="Content-Type:application/json"
|
||||
_response=$(_post "$_request" "https://api.gcdn.co/auth/jwt/login")
|
||||
_response=$(_post "$_request" "https://api.gcore.com/auth/jwt/login")
|
||||
_debug _response "$_response"
|
||||
_regex=".*\"access\":\"\([-._0-9A-Za-z]*\)\".*$"
|
||||
_debug _regex "$_regex"
|
||||
@@ -69,8 +70,8 @@ gcore_cdn_deploy() {
|
||||
fi
|
||||
|
||||
_info "Find CDN resource with cname $_cdomain"
|
||||
export _H2="Authorization:Token $_token"
|
||||
_response=$(_get "https://api.gcdn.co/resources")
|
||||
export _H2="Authorization:Bearer $_token"
|
||||
_response=$(_get "https://api.gcore.com/cdn/resources")
|
||||
_debug _response "$_response"
|
||||
_regex="\"primary_resource\":null},"
|
||||
_debug _regex "$_regex"
|
||||
@@ -102,7 +103,7 @@ gcore_cdn_deploy() {
|
||||
_date=$(date "+%d.%m.%Y %H:%M:%S")
|
||||
_request="{\"name\":\"$_cdomain ($_date)\",\"sslCertificate\":\"$_fullchain\",\"sslPrivateKey\":\"$_key\"}"
|
||||
_debug _request "$_request"
|
||||
_response=$(_post "$_request" "https://api.gcdn.co/sslData")
|
||||
_response=$(_post "$_request" "https://api.gcore.com/cdn/sslData")
|
||||
_debug _response "$_response"
|
||||
_regex=".*\"id\":\([0-9]*\).*$"
|
||||
_debug _regex "$_regex"
|
||||
@@ -117,7 +118,7 @@ gcore_cdn_deploy() {
|
||||
_info "Update CDN resource"
|
||||
_request="{\"originGroup\":$_originGroup,\"sslData\":$_sslDataAdd}"
|
||||
_debug _request "$_request"
|
||||
_response=$(_post "$_request" "https://api.gcdn.co/resources/$_resourceId" '' "PUT")
|
||||
_response=$(_post "$_request" "https://api.gcore.com/cdn/resources/$_resourceId" '' "PUT")
|
||||
_debug _response "$_response"
|
||||
_regex=".*\"sslData\":\([0-9]*\).*$"
|
||||
_debug _regex "$_regex"
|
||||
@@ -133,7 +134,7 @@ gcore_cdn_deploy() {
|
||||
_info "Not found old SSL certificate"
|
||||
else
|
||||
_info "Delete old SSL certificate"
|
||||
_response=$(_post '' "https://api.gcdn.co/sslData/$_sslDataOld" '' "DELETE")
|
||||
_response=$(_post '' "https://api.gcore.com/cdn/sslData/$_sslDataOld" '' "DELETE")
|
||||
_debug _response "$_response"
|
||||
fi
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ gitlab_deploy() {
|
||||
|
||||
error_response="error"
|
||||
|
||||
if test "${_response#*$error_response}" != "$_response"; then
|
||||
if test "${_response#*"$error_response"}" != "$_response"; then
|
||||
_err "Error in deploying certificate:"
|
||||
_err "$_response"
|
||||
return 1
|
||||
|
||||
@@ -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
|
||||
@@ -39,31 +44,20 @@ mailcow_deploy() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
# ECC or RSA
|
||||
if [ -z "${Le_Keylength}" ]; then
|
||||
Le_Keylength=""
|
||||
fi
|
||||
if _isEccKey "${Le_Keylength}"; 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"
|
||||
_real_key="$_ssl_path/key.pem"
|
||||
if ! cat "$_ckey" >"$_real_key"; then
|
||||
_err "Error: write key file to: $_real_key"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_real_fullchain="$_ssl_path/${_cert_name_prefix}cert.pem"
|
||||
_real_fullchain="$_ssl_path/cert.pem"
|
||||
if ! cat "$_cfullchain" >"$_real_fullchain"; then
|
||||
_err "Error: write cert file to: $_real_fullchain"
|
||||
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 --filter name=postfix-mailcow)"
|
||||
_reload="${DEPLOY_MAILCOW_RELOAD:-$DEFAULT_MAILCOW_RELOAD}"
|
||||
|
||||
_info "Run reload: $_reload"
|
||||
|
||||
132
deploy/proxmoxve.sh
Normal file
132
deploy/proxmoxve.sh
Normal file
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Deploy certificates to a proxmox virtual environment node using the API.
|
||||
#
|
||||
# Environment variables that can be set are:
|
||||
# `DEPLOY_PROXMOXVE_SERVER`: The hostname of the proxmox ve node. Defaults to
|
||||
# _cdomain.
|
||||
# `DEPLOY_PROXMOXVE_SERVER_PORT`: The port number the management interface is on.
|
||||
# Defaults to 8006.
|
||||
# `DEPLOY_PROXMOXVE_NODE_NAME`: The name of the node we'll be connecting to.
|
||||
# Defaults to the host portion of the server
|
||||
# domain name.
|
||||
# `DEPLOY_PROXMOXVE_USER`: The user we'll connect as. Defaults to root.
|
||||
# `DEPLOY_PROXMOXVE_USER_REALM`: The authentication realm the user authenticates
|
||||
# with. Defaults to pam.
|
||||
# `DEPLOY_PROXMOXVE_API_TOKEN_NAME`: The name of the API token created for the
|
||||
# user account. Defaults to acme.
|
||||
# `DEPLOY_PROXMOXVE_API_TOKEN_KEY`: The API token. Required.
|
||||
|
||||
proxmoxve_deploy() {
|
||||
_cdomain="$1"
|
||||
_ckey="$2"
|
||||
_ccert="$3"
|
||||
_cca="$4"
|
||||
_cfullchain="$5"
|
||||
|
||||
_debug _cdomain "$_cdomain"
|
||||
_debug2 _ckey "$_ckey"
|
||||
_debug _ccert "$_ccert"
|
||||
_debug _cca "$_cca"
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
# "Sane" defaults.
|
||||
_getdeployconf DEPLOY_PROXMOXVE_SERVER
|
||||
if [ -z "$DEPLOY_PROXMOXVE_SERVER" ]; then
|
||||
_target_hostname="$_cdomain"
|
||||
else
|
||||
_target_hostname="$DEPLOY_PROXMOXVE_SERVER"
|
||||
_savedeployconf DEPLOY_PROXMOXVE_SERVER "$DEPLOY_PROXMOXVE_SERVER"
|
||||
fi
|
||||
_debug2 DEPLOY_PROXMOXVE_SERVER "$_target_hostname"
|
||||
|
||||
_getdeployconf DEPLOY_PROXMOXVE_SERVER_PORT
|
||||
if [ -z "$DEPLOY_PROXMOXVE_SERVER_PORT" ]; then
|
||||
_target_port="8006"
|
||||
else
|
||||
_target_port="$DEPLOY_PROXMOXVE_SERVER_PORT"
|
||||
_savedeployconf DEPLOY_PROXMOXVE_SERVER_PORT "$DEPLOY_PROXMOXVE_SERVER_PORT"
|
||||
fi
|
||||
_debug2 DEPLOY_PROXMOXVE_SERVER_PORT "$_target_port"
|
||||
|
||||
_getdeployconf DEPLOY_PROXMOXVE_NODE_NAME
|
||||
if [ -z "$DEPLOY_PROXMOXVE_NODE_NAME" ]; then
|
||||
_node_name=$(echo "$_target_hostname" | cut -d. -f1)
|
||||
else
|
||||
_node_name="$DEPLOY_PROXMOXVE_NODE_NAME"
|
||||
_savedeployconf DEPLOY_PROXMOXVE_NODE_NAME "$DEPLOY_PROXMOXVE_NODE_NAME"
|
||||
fi
|
||||
_debug2 DEPLOY_PROXMOXVE_NODE_NAME "$_node_name"
|
||||
|
||||
# Complete URL.
|
||||
_target_url="https://${_target_hostname}:${_target_port}/api2/json/nodes/${_node_name}/certificates/custom"
|
||||
_debug TARGET_URL "$_target_url"
|
||||
|
||||
# More "sane" defaults.
|
||||
_getdeployconf DEPLOY_PROXMOXVE_USER
|
||||
if [ -z "$DEPLOY_PROXMOXVE_USER" ]; then
|
||||
_proxmoxve_user="root"
|
||||
else
|
||||
_proxmoxve_user="$DEPLOY_PROXMOXVE_USER"
|
||||
_savedeployconf DEPLOY_PROXMOXVE_USER "$DEPLOY_PROXMOXVE_USER"
|
||||
fi
|
||||
_debug2 DEPLOY_PROXMOXVE_USER "$_proxmoxve_user"
|
||||
|
||||
_getdeployconf DEPLOY_PROXMOXVE_USER_REALM
|
||||
if [ -z "$DEPLOY_PROXMOXVE_USER_REALM" ]; then
|
||||
_proxmoxve_user_realm="pam"
|
||||
else
|
||||
_proxmoxve_user_realm="$DEPLOY_PROXMOXVE_USER_REALM"
|
||||
_savedeployconf DEPLOY_PROXMOXVE_USER_REALM "$DEPLOY_PROXMOXVE_USER_REALM"
|
||||
fi
|
||||
_debug2 DEPLOY_PROXMOXVE_USER_REALM "$_proxmoxve_user_realm"
|
||||
|
||||
_getdeployconf DEPLOY_PROXMOXVE_API_TOKEN_NAME
|
||||
if [ -z "$DEPLOY_PROXMOXVE_API_TOKEN_NAME" ]; then
|
||||
_proxmoxve_api_token_name="acme"
|
||||
else
|
||||
_proxmoxve_api_token_name="$DEPLOY_PROXMOXVE_API_TOKEN_NAME"
|
||||
_savedeployconf DEPLOY_PROXMOXVE_API_TOKEN_NAME "$DEPLOY_PROXMOXVE_API_TOKEN_NAME"
|
||||
fi
|
||||
_debug2 DEPLOY_PROXMOXVE_API_TOKEN_NAME "$_proxmoxve_api_token_name"
|
||||
|
||||
# This is required.
|
||||
_getdeployconf DEPLOY_PROXMOXVE_API_TOKEN_KEY
|
||||
if [ -z "$DEPLOY_PROXMOXVE_API_TOKEN_KEY" ]; then
|
||||
_err "API key not provided."
|
||||
return 1
|
||||
else
|
||||
_proxmoxve_api_token_key="$DEPLOY_PROXMOXVE_API_TOKEN_KEY"
|
||||
_savedeployconf DEPLOY_PROXMOXVE_API_TOKEN_KEY "$DEPLOY_PROXMOXVE_API_TOKEN_KEY"
|
||||
fi
|
||||
_debug2 DEPLOY_PROXMOXVE_API_TOKEN_KEY _proxmoxve_api_token_key
|
||||
|
||||
# PVE API Token header value. Used in "Authorization: PVEAPIToken".
|
||||
_proxmoxve_header_api_token="${_proxmoxve_user}@${_proxmoxve_user_realm}!${_proxmoxve_api_token_name}=${_proxmoxve_api_token_key}"
|
||||
_debug2 "Auth Header" _proxmoxve_header_api_token
|
||||
|
||||
# Ugly. I hate putting heredocs inside functions because heredocs don't
|
||||
# account for whitespace correctly but it _does_ work and is several times
|
||||
# cleaner than anything else I had here.
|
||||
#
|
||||
# This dumps the json payload to a variable that should be passable to the
|
||||
# _psot function.
|
||||
_json_payload=$(
|
||||
cat <<HEREDOC
|
||||
{
|
||||
"certificates": "$(tr '\n' ':' <"$_cfullchain" | sed 's/:/\\n/g')",
|
||||
"key": "$(tr '\n' ':' <"$_ckey" | sed 's/:/\\n/g')",
|
||||
"node":"$_node_name",
|
||||
"restart":"1",
|
||||
"force":"1"
|
||||
}
|
||||
HEREDOC
|
||||
)
|
||||
_debug2 Payload "$_json_payload"
|
||||
|
||||
# Push certificates to server.
|
||||
export _HTTPS_INSECURE=1
|
||||
export _H1="Authorization: PVEAPIToken=${_proxmoxve_header_api_token}"
|
||||
_post "$_json_payload" "$_target_url" "" POST "application/json"
|
||||
|
||||
}
|
||||
@@ -53,7 +53,7 @@ qiniu_deploy() {
|
||||
sslcert_access_token="$(_make_access_token "$sslcert_path")"
|
||||
_debug sslcert_access_token "$sslcert_access_token"
|
||||
export _H1="Authorization: QBox $sslcert_access_token"
|
||||
sslcert_response=$(_post "$sslcerl_body" "$QINIU_API_BASE$sslcert_path" 0 "POST" "application/json" | _dbase64 "multiline")
|
||||
sslcert_response=$(_post "$sslcerl_body" "$QINIU_API_BASE$sslcert_path" 0 "POST" "application/json" | _dbase64)
|
||||
|
||||
if ! _contains "$sslcert_response" "certID"; then
|
||||
_err "Error in creating certificate:"
|
||||
@@ -75,7 +75,7 @@ qiniu_deploy() {
|
||||
update_access_token="$(_make_access_token "$update_path")"
|
||||
_debug update_access_token "$update_access_token"
|
||||
export _H1="Authorization: QBox $update_access_token"
|
||||
update_response=$(_post "$update_body" "$QINIU_API_BASE$update_path" 0 "PUT" "application/json" | _dbase64 "multiline")
|
||||
update_response=$(_post "$update_body" "$QINIU_API_BASE$update_path" 0 "PUT" "application/json" | _dbase64)
|
||||
|
||||
if _contains "$update_response" "error"; then
|
||||
_err "Error in updating domain $domain httpsconf:"
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
409
deploy/ssh.sh
409
deploy/ssh.sh
@@ -14,7 +14,7 @@
|
||||
# The following examples are for QNAP NAS running QTS 4.2
|
||||
# export DEPLOY_SSH_CMD="" # defaults to "ssh -T"
|
||||
# export DEPLOY_SSH_USER="admin" # required
|
||||
# export DEPLOY_SSH_SERVER="qnap" # defaults to domain name
|
||||
# export DEPLOY_SSH_SERVER="host1 host2:8022 192.168.0.1:9022" # defaults to domain name, support multiple servers with optional port
|
||||
# export DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem"
|
||||
# export DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem"
|
||||
# export DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem"
|
||||
@@ -23,6 +23,8 @@
|
||||
# export DEPLOY_SSH_BACKUP="" # yes or no, default to yes or previously saved value
|
||||
# export DEPLOY_SSH_BACKUP_PATH=".acme_ssh_deploy" # path on remote system. Defaults to .acme_ssh_deploy
|
||||
# export DEPLOY_SSH_MULTI_CALL="" # yes or no, default to no or previously saved value
|
||||
# export DEPLOY_SSH_USE_SCP="" yes or no, default to no
|
||||
# export DEPLOY_SSH_SCP_CMD="" defaults to "scp -q"
|
||||
#
|
||||
######## Public functions #####################
|
||||
|
||||
@@ -42,72 +44,134 @@ ssh_deploy() {
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
# USER is required to login by SSH to remote host.
|
||||
_migratedeployconf Le_Deploy_ssh_user DEPLOY_SSH_USER
|
||||
_getdeployconf DEPLOY_SSH_USER
|
||||
_debug2 DEPLOY_SSH_USER "$DEPLOY_SSH_USER"
|
||||
if [ -z "$DEPLOY_SSH_USER" ]; then
|
||||
if [ -z "$Le_Deploy_ssh_user" ]; then
|
||||
_err "DEPLOY_SSH_USER not defined."
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
Le_Deploy_ssh_user="$DEPLOY_SSH_USER"
|
||||
_savedomainconf Le_Deploy_ssh_user "$Le_Deploy_ssh_user"
|
||||
_err "DEPLOY_SSH_USER not defined."
|
||||
return 1
|
||||
fi
|
||||
_savedeployconf DEPLOY_SSH_USER "$DEPLOY_SSH_USER"
|
||||
|
||||
# SERVER is optional. If not provided then use _cdomain
|
||||
_migratedeployconf Le_Deploy_ssh_server DEPLOY_SSH_SERVER
|
||||
_getdeployconf DEPLOY_SSH_SERVER
|
||||
_debug2 DEPLOY_SSH_SERVER "$DEPLOY_SSH_SERVER"
|
||||
if [ -n "$DEPLOY_SSH_SERVER" ]; then
|
||||
Le_Deploy_ssh_server="$DEPLOY_SSH_SERVER"
|
||||
_savedomainconf Le_Deploy_ssh_server "$Le_Deploy_ssh_server"
|
||||
elif [ -z "$Le_Deploy_ssh_server" ]; then
|
||||
Le_Deploy_ssh_server="$_cdomain"
|
||||
if [ -z "$DEPLOY_SSH_SERVER" ]; then
|
||||
DEPLOY_SSH_SERVER="$_cdomain"
|
||||
fi
|
||||
_savedeployconf DEPLOY_SSH_SERVER "$DEPLOY_SSH_SERVER"
|
||||
|
||||
# CMD is optional. If not provided then use ssh
|
||||
_migratedeployconf Le_Deploy_ssh_cmd DEPLOY_SSH_CMD
|
||||
_getdeployconf DEPLOY_SSH_CMD
|
||||
_debug2 DEPLOY_SSH_CMD "$DEPLOY_SSH_CMD"
|
||||
if [ -n "$DEPLOY_SSH_CMD" ]; then
|
||||
Le_Deploy_ssh_cmd="$DEPLOY_SSH_CMD"
|
||||
_savedomainconf Le_Deploy_ssh_cmd "$Le_Deploy_ssh_cmd"
|
||||
elif [ -z "$Le_Deploy_ssh_cmd" ]; then
|
||||
Le_Deploy_ssh_cmd="ssh -T"
|
||||
if [ -z "$DEPLOY_SSH_CMD" ]; then
|
||||
DEPLOY_SSH_CMD="ssh -T"
|
||||
fi
|
||||
_savedeployconf DEPLOY_SSH_CMD "$DEPLOY_SSH_CMD"
|
||||
|
||||
# BACKUP is optional. If not provided then default to previously saved value or yes.
|
||||
_migratedeployconf Le_Deploy_ssh_backup DEPLOY_SSH_BACKUP
|
||||
_getdeployconf DEPLOY_SSH_BACKUP
|
||||
_debug2 DEPLOY_SSH_BACKUP "$DEPLOY_SSH_BACKUP"
|
||||
if [ "$DEPLOY_SSH_BACKUP" = "no" ]; then
|
||||
Le_Deploy_ssh_backup="no"
|
||||
elif [ -z "$Le_Deploy_ssh_backup" ] || [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
||||
Le_Deploy_ssh_backup="yes"
|
||||
if [ -z "$DEPLOY_SSH_BACKUP" ]; then
|
||||
DEPLOY_SSH_BACKUP="yes"
|
||||
fi
|
||||
_savedomainconf Le_Deploy_ssh_backup "$Le_Deploy_ssh_backup"
|
||||
_savedeployconf DEPLOY_SSH_BACKUP "$DEPLOY_SSH_BACKUP"
|
||||
|
||||
# BACKUP_PATH is optional. If not provided then default to previously saved value or .acme_ssh_deploy
|
||||
_migratedeployconf Le_Deploy_ssh_backup_path DEPLOY_SSH_BACKUP_PATH
|
||||
_getdeployconf DEPLOY_SSH_BACKUP_PATH
|
||||
_debug2 DEPLOY_SSH_BACKUP_PATH "$DEPLOY_SSH_BACKUP_PATH"
|
||||
if [ -n "$DEPLOY_SSH_BACKUP_PATH" ]; then
|
||||
Le_Deploy_ssh_backup_path="$DEPLOY_SSH_BACKUP_PATH"
|
||||
elif [ -z "$Le_Deploy_ssh_backup_path" ]; then
|
||||
Le_Deploy_ssh_backup_path=".acme_ssh_deploy"
|
||||
if [ -z "$DEPLOY_SSH_BACKUP_PATH" ]; then
|
||||
DEPLOY_SSH_BACKUP_PATH=".acme_ssh_deploy"
|
||||
fi
|
||||
_savedomainconf Le_Deploy_ssh_backup_path "$Le_Deploy_ssh_backup_path"
|
||||
_savedeployconf DEPLOY_SSH_BACKUP_PATH "$DEPLOY_SSH_BACKUP_PATH"
|
||||
|
||||
# MULTI_CALL is optional. If not provided then default to previously saved
|
||||
# value (which may be undefined... equivalent to "no").
|
||||
_migratedeployconf Le_Deploy_ssh_multi_call DEPLOY_SSH_MULTI_CALL
|
||||
_getdeployconf DEPLOY_SSH_MULTI_CALL
|
||||
_debug2 DEPLOY_SSH_MULTI_CALL "$DEPLOY_SSH_MULTI_CALL"
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
Le_Deploy_ssh_multi_call="yes"
|
||||
_savedomainconf Le_Deploy_ssh_multi_call "$Le_Deploy_ssh_multi_call"
|
||||
elif [ "$DEPLOY_SSH_MULTI_CALL" = "no" ]; then
|
||||
Le_Deploy_ssh_multi_call=""
|
||||
_cleardomainconf Le_Deploy_ssh_multi_call
|
||||
if [ -z "$DEPLOY_SSH_MULTI_CALL" ]; then
|
||||
DEPLOY_SSH_MULTI_CALL="no"
|
||||
fi
|
||||
_savedeployconf DEPLOY_SSH_MULTI_CALL "$DEPLOY_SSH_MULTI_CALL"
|
||||
|
||||
# KEYFILE is optional.
|
||||
# If provided then private key will be copied to provided filename.
|
||||
_migratedeployconf Le_Deploy_ssh_keyfile DEPLOY_SSH_KEYFILE
|
||||
_getdeployconf DEPLOY_SSH_KEYFILE
|
||||
_debug2 DEPLOY_SSH_KEYFILE "$DEPLOY_SSH_KEYFILE"
|
||||
if [ -n "$DEPLOY_SSH_KEYFILE" ]; then
|
||||
_savedeployconf DEPLOY_SSH_KEYFILE "$DEPLOY_SSH_KEYFILE"
|
||||
fi
|
||||
|
||||
_deploy_ssh_servers=$Le_Deploy_ssh_server
|
||||
for Le_Deploy_ssh_server in $_deploy_ssh_servers; do
|
||||
# CERTFILE is optional.
|
||||
# If provided then certificate will be copied or appended to provided filename.
|
||||
_migratedeployconf Le_Deploy_ssh_certfile DEPLOY_SSH_CERTFILE
|
||||
_getdeployconf DEPLOY_SSH_CERTFILE
|
||||
_debug2 DEPLOY_SSH_CERTFILE "$DEPLOY_SSH_CERTFILE"
|
||||
if [ -n "$DEPLOY_SSH_CERTFILE" ]; then
|
||||
_savedeployconf DEPLOY_SSH_CERTFILE "$DEPLOY_SSH_CERTFILE"
|
||||
fi
|
||||
|
||||
# CAFILE is optional.
|
||||
# If provided then CA intermediate certificate will be copied or appended to provided filename.
|
||||
_migratedeployconf Le_Deploy_ssh_cafile DEPLOY_SSH_CAFILE
|
||||
_getdeployconf DEPLOY_SSH_CAFILE
|
||||
_debug2 DEPLOY_SSH_CAFILE "$DEPLOY_SSH_CAFILE"
|
||||
if [ -n "$DEPLOY_SSH_CAFILE" ]; then
|
||||
_savedeployconf DEPLOY_SSH_CAFILE "$DEPLOY_SSH_CAFILE"
|
||||
fi
|
||||
|
||||
# FULLCHAIN is optional.
|
||||
# If provided then fullchain certificate will be copied or appended to provided filename.
|
||||
_migratedeployconf Le_Deploy_ssh_fullchain DEPLOY_SSH_FULLCHAIN
|
||||
_getdeployconf DEPLOY_SSH_FULLCHAIN
|
||||
_debug2 DEPLOY_SSH_FULLCHAIN "$DEPLOY_SSH_FULLCHAIN"
|
||||
if [ -n "$DEPLOY_SSH_FULLCHAIN" ]; then
|
||||
_savedeployconf DEPLOY_SSH_FULLCHAIN "$DEPLOY_SSH_FULLCHAIN"
|
||||
fi
|
||||
|
||||
# REMOTE_CMD is optional.
|
||||
# If provided then this command will be executed on remote host.
|
||||
_migratedeployconf Le_Deploy_ssh_remote_cmd DEPLOY_SSH_REMOTE_CMD
|
||||
_getdeployconf DEPLOY_SSH_REMOTE_CMD
|
||||
_debug2 DEPLOY_SSH_REMOTE_CMD "$DEPLOY_SSH_REMOTE_CMD"
|
||||
if [ -n "$DEPLOY_SSH_REMOTE_CMD" ]; then
|
||||
_savedeployconf DEPLOY_SSH_REMOTE_CMD "$DEPLOY_SSH_REMOTE_CMD"
|
||||
fi
|
||||
|
||||
# USE_SCP is optional. If not provided then default to previously saved
|
||||
# value (which may be undefined... equivalent to "no").
|
||||
_getdeployconf DEPLOY_SSH_USE_SCP
|
||||
_debug2 DEPLOY_SSH_USE_SCP "$DEPLOY_SSH_USE_SCP"
|
||||
if [ -z "$DEPLOY_SSH_USE_SCP" ]; then
|
||||
DEPLOY_SSH_USE_SCP="no"
|
||||
fi
|
||||
_savedeployconf DEPLOY_SSH_USE_SCP "$DEPLOY_SSH_USE_SCP"
|
||||
|
||||
# SCP_CMD is optional. If not provided then use scp
|
||||
_getdeployconf DEPLOY_SSH_SCP_CMD
|
||||
_debug2 DEPLOY_SSH_SCP_CMD "$DEPLOY_SSH_SCP_CMD"
|
||||
if [ -z "$DEPLOY_SSH_SCP_CMD" ]; then
|
||||
DEPLOY_SSH_SCP_CMD="scp -q"
|
||||
fi
|
||||
_savedeployconf DEPLOY_SSH_SCP_CMD "$DEPLOY_SSH_SCP_CMD"
|
||||
|
||||
if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
|
||||
DEPLOY_SSH_MULTI_CALL="yes"
|
||||
_info "Using scp as alternate method for copying files. Multicall Mode is implicit"
|
||||
elif [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
_info "Using MULTI_CALL mode... Required commands sent in multiple calls to remote host"
|
||||
else
|
||||
_info "Required commands batched and sent in single call to remote host"
|
||||
fi
|
||||
|
||||
_deploy_ssh_servers="$DEPLOY_SSH_SERVER"
|
||||
for DEPLOY_SSH_SERVER in $_deploy_ssh_servers; do
|
||||
_ssh_deploy
|
||||
done
|
||||
}
|
||||
@@ -117,16 +181,25 @@ _ssh_deploy() {
|
||||
_cmdstr=""
|
||||
_backupprefix=""
|
||||
_backupdir=""
|
||||
_local_cert_file=""
|
||||
_local_ca_file=""
|
||||
_local_full_file=""
|
||||
|
||||
_info "Deploy certificates to remote server $Le_Deploy_ssh_user@$Le_Deploy_ssh_server"
|
||||
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
||||
_info "Using MULTI_CALL mode... Required commands sent in multiple calls to remote host"
|
||||
else
|
||||
_info "Required commands batched and sent in single call to remote host"
|
||||
fi
|
||||
case $DEPLOY_SSH_SERVER in
|
||||
*:*)
|
||||
_host=${DEPLOY_SSH_SERVER%:*}
|
||||
_port=${DEPLOY_SSH_SERVER##*:}
|
||||
;;
|
||||
*)
|
||||
_host=$DEPLOY_SSH_SERVER
|
||||
_port=
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$Le_Deploy_ssh_backup" = "yes" ]; then
|
||||
_backupprefix="$Le_Deploy_ssh_backup_path/$_cdomain-backup"
|
||||
_info "Deploy certificates to remote server $DEPLOY_SSH_USER@$_host:$_port"
|
||||
|
||||
if [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
||||
_backupprefix="$DEPLOY_SSH_BACKUP_PATH/$_cdomain-backup"
|
||||
_backupdir="$_backupprefix-$(_utc_date | tr ' ' '-')"
|
||||
# run cleanup on the backup directory, erase all older
|
||||
# than 180 days (15552000 seconds).
|
||||
@@ -138,7 +211,7 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
|
||||
_cmdstr="mkdir -p $_backupdir; $_cmdstr"
|
||||
_info "Backup of old certificate files will be placed in remote directory $_backupdir"
|
||||
_info "Backup directories erased after 180 days."
|
||||
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
@@ -146,129 +219,184 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
|
||||
fi
|
||||
fi
|
||||
|
||||
# KEYFILE is optional.
|
||||
# If provided then private key will be copied to provided filename.
|
||||
_getdeployconf DEPLOY_SSH_KEYFILE
|
||||
_debug2 DEPLOY_SSH_KEYFILE "$DEPLOY_SSH_KEYFILE"
|
||||
if [ -n "$DEPLOY_SSH_KEYFILE" ]; then
|
||||
Le_Deploy_ssh_keyfile="$DEPLOY_SSH_KEYFILE"
|
||||
_savedomainconf Le_Deploy_ssh_keyfile "$Le_Deploy_ssh_keyfile"
|
||||
fi
|
||||
if [ -n "$Le_Deploy_ssh_keyfile" ]; then
|
||||
if [ "$Le_Deploy_ssh_backup" = "yes" ]; then
|
||||
if [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
||||
# backup file we are about to overwrite.
|
||||
_cmdstr="$_cmdstr cp $Le_Deploy_ssh_keyfile $_backupdir >/dev/null;"
|
||||
_cmdstr="$_cmdstr cp $DEPLOY_SSH_KEYFILE $_backupdir >/dev/null;"
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
fi
|
||||
fi
|
||||
# copy new certificate into file.
|
||||
_cmdstr="$_cmdstr echo \"$(cat "$_ckey")\" > $Le_Deploy_ssh_keyfile;"
|
||||
_info "will copy private key to remote file $Le_Deploy_ssh_keyfile"
|
||||
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
|
||||
# copy new key into file.
|
||||
if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
|
||||
# scp the file
|
||||
if ! _scp_remote_cmd "$_ckey" "$DEPLOY_SSH_KEYFILE"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
else
|
||||
# ssh echo to the file
|
||||
_cmdstr="$_cmdstr echo \"$(cat "$_ckey")\" > $DEPLOY_SSH_KEYFILE;"
|
||||
_info "will copy private key to remote file $DEPLOY_SSH_KEYFILE"
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# CERTFILE is optional.
|
||||
# If provided then certificate will be copied or appended to provided filename.
|
||||
_getdeployconf DEPLOY_SSH_CERTFILE
|
||||
_debug2 DEPLOY_SSH_CERTFILE "$DEPLOY_SSH_CERTFILE"
|
||||
if [ -n "$DEPLOY_SSH_CERTFILE" ]; then
|
||||
Le_Deploy_ssh_certfile="$DEPLOY_SSH_CERTFILE"
|
||||
_savedomainconf Le_Deploy_ssh_certfile "$Le_Deploy_ssh_certfile"
|
||||
fi
|
||||
if [ -n "$Le_Deploy_ssh_certfile" ]; then
|
||||
_pipe=">"
|
||||
if [ "$Le_Deploy_ssh_certfile" = "$Le_Deploy_ssh_keyfile" ]; then
|
||||
if [ "$DEPLOY_SSH_CERTFILE" = "$DEPLOY_SSH_KEYFILE" ]; then
|
||||
# if filename is same as previous file then append.
|
||||
_pipe=">>"
|
||||
elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
|
||||
elif [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
||||
# backup file we are about to overwrite.
|
||||
_cmdstr="$_cmdstr cp $Le_Deploy_ssh_certfile $_backupdir >/dev/null;"
|
||||
_cmdstr="$_cmdstr cp $DEPLOY_SSH_CERTFILE $_backupdir >/dev/null;"
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
fi
|
||||
fi
|
||||
|
||||
# copy new certificate into file.
|
||||
_cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" $_pipe $Le_Deploy_ssh_certfile;"
|
||||
_info "will copy certificate to remote file $Le_Deploy_ssh_certfile"
|
||||
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
|
||||
# scp the file
|
||||
_local_cert_file=$(_mktemp)
|
||||
if [ "$DEPLOY_SSH_CERTFILE" = "$DEPLOY_SSH_KEYFILE" ]; then
|
||||
cat "$_ckey" >>"$_local_cert_file"
|
||||
fi
|
||||
cat "$_ccert" >>"$_local_cert_file"
|
||||
if ! _scp_remote_cmd "$_local_cert_file" "$DEPLOY_SSH_CERTFILE"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
else
|
||||
# ssh echo to the file
|
||||
_cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" $_pipe $DEPLOY_SSH_CERTFILE;"
|
||||
_info "will copy certificate to remote file $DEPLOY_SSH_CERTFILE"
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# CAFILE is optional.
|
||||
# If provided then CA intermediate certificate will be copied or appended to provided filename.
|
||||
_getdeployconf DEPLOY_SSH_CAFILE
|
||||
_debug2 DEPLOY_SSH_CAFILE "$DEPLOY_SSH_CAFILE"
|
||||
if [ -n "$DEPLOY_SSH_CAFILE" ]; then
|
||||
Le_Deploy_ssh_cafile="$DEPLOY_SSH_CAFILE"
|
||||
_savedomainconf Le_Deploy_ssh_cafile "$Le_Deploy_ssh_cafile"
|
||||
fi
|
||||
if [ -n "$Le_Deploy_ssh_cafile" ]; then
|
||||
_pipe=">"
|
||||
if [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_keyfile" ] ||
|
||||
[ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_certfile" ]; then
|
||||
if [ "$DEPLOY_SSH_CAFILE" = "$DEPLOY_SSH_KEYFILE" ] ||
|
||||
[ "$DEPLOY_SSH_CAFILE" = "$DEPLOY_SSH_CERTFILE" ]; then
|
||||
# if filename is same as previous file then append.
|
||||
_pipe=">>"
|
||||
elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
|
||||
elif [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
||||
# backup file we are about to overwrite.
|
||||
_cmdstr="$_cmdstr cp $Le_Deploy_ssh_cafile $_backupdir >/dev/null;"
|
||||
_cmdstr="$_cmdstr cp $DEPLOY_SSH_CAFILE $_backupdir >/dev/null;"
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
fi
|
||||
fi
|
||||
|
||||
# copy new certificate into file.
|
||||
_cmdstr="$_cmdstr echo \"$(cat "$_cca")\" $_pipe $Le_Deploy_ssh_cafile;"
|
||||
_info "will copy CA file to remote file $Le_Deploy_ssh_cafile"
|
||||
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
|
||||
# scp the file
|
||||
_local_ca_file=$(_mktemp)
|
||||
if [ "$DEPLOY_SSH_CAFILE" = "$DEPLOY_SSH_KEYFILE" ]; then
|
||||
cat "$_ckey" >>"$_local_ca_file"
|
||||
fi
|
||||
if [ "$DEPLOY_SSH_CAFILE" = "$DEPLOY_SSH_CERTFILE" ]; then
|
||||
cat "$_ccert" >>"$_local_ca_file"
|
||||
fi
|
||||
cat "$_cca" >>"$_local_ca_file"
|
||||
if ! _scp_remote_cmd "$_local_ca_file" "$DEPLOY_SSH_CAFILE"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
else
|
||||
# ssh echo to the file
|
||||
_cmdstr="$_cmdstr echo \"$(cat "$_cca")\" $_pipe $DEPLOY_SSH_CAFILE;"
|
||||
_info "will copy CA file to remote file $DEPLOY_SSH_CAFILE"
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# FULLCHAIN is optional.
|
||||
# If provided then fullchain certificate will be copied or appended to provided filename.
|
||||
_getdeployconf DEPLOY_SSH_FULLCHAIN
|
||||
_debug2 DEPLOY_SSH_FULLCHAIN "$DEPLOY_SSH_FULLCHAIN"
|
||||
if [ -n "$DEPLOY_SSH_FULLCHAIN" ]; then
|
||||
Le_Deploy_ssh_fullchain="$DEPLOY_SSH_FULLCHAIN"
|
||||
_savedomainconf Le_Deploy_ssh_fullchain "$Le_Deploy_ssh_fullchain"
|
||||
fi
|
||||
if [ -n "$Le_Deploy_ssh_fullchain" ]; then
|
||||
_pipe=">"
|
||||
if [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_keyfile" ] ||
|
||||
[ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_certfile" ] ||
|
||||
[ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_cafile" ]; then
|
||||
if [ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_KEYFILE" ] ||
|
||||
[ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_CERTFILE" ] ||
|
||||
[ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_CAFILE" ]; then
|
||||
# if filename is same as previous file then append.
|
||||
_pipe=">>"
|
||||
elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
|
||||
elif [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
||||
# backup file we are about to overwrite.
|
||||
_cmdstr="$_cmdstr cp $Le_Deploy_ssh_fullchain $_backupdir >/dev/null;"
|
||||
_cmdstr="$_cmdstr cp $DEPLOY_SSH_FULLCHAIN $_backupdir >/dev/null;"
|
||||
if [ "$DEPLOY_SSH_FULLCHAIN" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
fi
|
||||
fi
|
||||
|
||||
# copy new certificate into file.
|
||||
_cmdstr="$_cmdstr echo \"$(cat "$_cfullchain")\" $_pipe $Le_Deploy_ssh_fullchain;"
|
||||
_info "will copy fullchain to remote file $Le_Deploy_ssh_fullchain"
|
||||
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
|
||||
# scp the file
|
||||
_local_full_file=$(_mktemp)
|
||||
if [ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_KEYFILE" ]; then
|
||||
cat "$_ckey" >>"$_local_full_file"
|
||||
fi
|
||||
if [ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_CERTFILE" ]; then
|
||||
cat "$_ccert" >>"$_local_full_file"
|
||||
fi
|
||||
if [ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_CAFILE" ]; then
|
||||
cat "$_cca" >>"$_local_full_file"
|
||||
fi
|
||||
cat "$_cfullchain" >>"$_local_full_file"
|
||||
if ! _scp_remote_cmd "$_local_full_file" "$DEPLOY_SSH_FULLCHAIN"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
else
|
||||
# ssh echo to the file
|
||||
_cmdstr="$_cmdstr echo \"$(cat "$_cfullchain")\" $_pipe $DEPLOY_SSH_FULLCHAIN;"
|
||||
_info "will copy fullchain to remote file $DEPLOY_SSH_FULLCHAIN"
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# REMOTE_CMD is optional.
|
||||
# If provided then this command will be executed on remote host.
|
||||
_getdeployconf DEPLOY_SSH_REMOTE_CMD
|
||||
_debug2 DEPLOY_SSH_REMOTE_CMD "$DEPLOY_SSH_REMOTE_CMD"
|
||||
if [ -n "$DEPLOY_SSH_REMOTE_CMD" ]; then
|
||||
Le_Deploy_ssh_remote_cmd="$DEPLOY_SSH_REMOTE_CMD"
|
||||
_savedomainconf Le_Deploy_ssh_remote_cmd "$Le_Deploy_ssh_remote_cmd"
|
||||
# cleanup local files if any
|
||||
if [ -f "$_local_cert_file" ]; then
|
||||
rm -f "$_local_cert_file"
|
||||
fi
|
||||
if [ -n "$Le_Deploy_ssh_remote_cmd" ]; then
|
||||
_cmdstr="$_cmdstr $Le_Deploy_ssh_remote_cmd;"
|
||||
_info "Will execute remote command $Le_Deploy_ssh_remote_cmd"
|
||||
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
||||
if [ -f "$_local_ca_file" ]; then
|
||||
rm -f "$_local_ca_file"
|
||||
fi
|
||||
if [ -f "$_local_full_file" ]; then
|
||||
rm -f "$_local_full_file"
|
||||
fi
|
||||
|
||||
if [ -n "$DEPLOY_SSH_REMOTE_CMD" ]; then
|
||||
_cmdstr="$_cmdstr $DEPLOY_SSH_REMOTE_CMD;"
|
||||
_info "Will execute remote command $DEPLOY_SSH_REMOTE_CMD"
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
@@ -282,17 +410,25 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
|
||||
return $_err_code
|
||||
fi
|
||||
fi
|
||||
# cleanup in case all is ok
|
||||
return 0
|
||||
}
|
||||
|
||||
#cmd
|
||||
_ssh_remote_cmd() {
|
||||
_cmd="$1"
|
||||
|
||||
_ssh_cmd="$DEPLOY_SSH_CMD"
|
||||
if [ -n "$_port" ]; then
|
||||
_ssh_cmd="$_ssh_cmd -p $_port"
|
||||
fi
|
||||
|
||||
_secure_debug "Remote commands to execute: $_cmd"
|
||||
_info "Submitting sequence of commands to remote server by ssh"
|
||||
_info "Submitting sequence of commands to remote server by $_ssh_cmd"
|
||||
|
||||
# quotations in bash cmd below intended. Squash travis spellcheck error
|
||||
# shellcheck disable=SC2029
|
||||
$Le_Deploy_ssh_cmd "$Le_Deploy_ssh_user@$Le_Deploy_ssh_server" sh -c "'$_cmd'"
|
||||
$_ssh_cmd "$DEPLOY_SSH_USER@$_host" sh -c "'$_cmd'"
|
||||
_err_code="$?"
|
||||
|
||||
if [ "$_err_code" != "0" ]; then
|
||||
@@ -301,3 +437,26 @@ _ssh_remote_cmd() {
|
||||
|
||||
return $_err_code
|
||||
}
|
||||
|
||||
# cmd scp
|
||||
_scp_remote_cmd() {
|
||||
_src=$1
|
||||
_dest=$2
|
||||
|
||||
_scp_cmd="$DEPLOY_SSH_SCP_CMD"
|
||||
if [ -n "$_port" ]; then
|
||||
_scp_cmd="$_scp_cmd -P $_port"
|
||||
fi
|
||||
|
||||
_secure_debug "Remote copy source $_src to destination $_dest"
|
||||
_info "Submitting secure copy by $_scp_cmd"
|
||||
|
||||
$_scp_cmd "$_src" "$DEPLOY_SSH_USER"@"$_host":"$_dest"
|
||||
_err_code="$?"
|
||||
|
||||
if [ "$_err_code" != "0" ]; then
|
||||
_err "Error code $_err_code returned from scp"
|
||||
fi
|
||||
|
||||
return $_err_code
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -103,7 +108,7 @@ synology_dsm_deploy() {
|
||||
_debug3 H1 "${_H1}"
|
||||
fi
|
||||
|
||||
response=$(_post "method=login&account=$encoded_username&passwd=$encoded_password&api=SYNO.API.Auth&version=$api_version&enable_syno_token=yes&otp_code=$otp_code" "$_base_url/webapi/auth.cgi?enable_syno_token=yes")
|
||||
response=$(_post "method=login&account=$encoded_username&passwd=$encoded_password&api=SYNO.API.Auth&version=$api_version&enable_syno_token=yes&otp_code=$otp_code&device_name=certrenewal&device_id=$SYNO_DID" "$_base_url/webapi/auth.cgi?enable_syno_token=yes")
|
||||
token=$(echo "$response" | grep "synotoken" | sed -n 's/.*"synotoken" *: *"\([^"]*\).*/\1/p')
|
||||
_debug3 response "$response"
|
||||
_debug token "$token"
|
||||
|
||||
@@ -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,66 @@ 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 "Checking if any chart release Apps is using the same certificate as TrueNAS web UI. Tool 'jq' is required"
|
||||
if _exists jq; then
|
||||
_info "Query all chart release"
|
||||
_release_list=$(_get "$_api_url/chart/release")
|
||||
_related_name_list=$(printf "%s" "$_release_list" | jq -r "[.[] | {name,certId: .config.ingress?.main.tls[]?.scaleCert} | select(.certId==$_active_cert_id) | .name ] | unique")
|
||||
_release_length=$(printf "%s" "$_related_name_list" | jq -r "length")
|
||||
_info "Found $_release_length related chart release in list: $_related_name_list"
|
||||
for i in $(seq 0 $((_release_length - 1))); do
|
||||
_release_name=$(echo "$_related_name_list" | jq -r ".[$i]")
|
||||
_info "Updating certificate from $_active_cert_id to $_cert_id for chart release: $_release_name"
|
||||
#Read the chart release configuration
|
||||
_chart_config=$(printf "%s" "$_release_list" | jq -r ".[] | select(.name==\"$_release_name\")")
|
||||
#Replace the old certificate id with the new one in path .config.ingress.main.tls[].scaleCert. Then update .config.ingress
|
||||
_updated_chart_config=$(printf "%s" "$_chart_config" | jq "(.config.ingress?.main.tls[]? | select(.scaleCert==$_active_cert_id) | .scaleCert ) |= $_cert_id | .config.ingress ")
|
||||
_update_chart_result="$(_post "{\"values\" : { \"ingress\" : $_updated_chart_config } }" "$_api_url/chart/release/id/$_release_name" "" "PUT" "application/json")"
|
||||
_debug3 _update_chart_result "$_update_chart_result"
|
||||
done
|
||||
else
|
||||
_info "Tool 'jq' does not exists, skip chart release checking"
|
||||
fi
|
||||
|
||||
_info "Deleting old certificate"
|
||||
_delete_result="$(_post "" "$_api_url/certificate/id/$_active_cert_id" "" "DELETE" "application/json")"
|
||||
|
||||
_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
|
||||
}
|
||||
|
||||
@@ -7,13 +7,16 @@
|
||||
#
|
||||
# VAULT_PREFIX - this contains the prefix path in vault
|
||||
# VAULT_ADDR - vault requires this to find your vault server
|
||||
# VAULT_SAVE_TOKEN - set to anything if you want to save the token
|
||||
# VAULT_RENEW_TOKEN - set to anything if you want to renew the token to default TTL before deploying
|
||||
# VAULT_KV_V2 - set to anything if you are using v2 of the kv engine
|
||||
#
|
||||
# additionally, you need to ensure that VAULT_TOKEN is avialable
|
||||
# to access the vault server
|
||||
|
||||
#returns 0 means success, otherwise error.
|
||||
|
||||
######## Public functions #####################
|
||||
######## Public functions #####################
|
||||
|
||||
#domain keyfile certfile cafile fullchain
|
||||
vault_deploy() {
|
||||
@@ -45,6 +48,26 @@ vault_deploy() {
|
||||
fi
|
||||
_savedeployconf VAULT_ADDR "$VAULT_ADDR"
|
||||
|
||||
_getdeployconf VAULT_SAVE_TOKEN
|
||||
_savedeployconf VAULT_SAVE_TOKEN "$VAULT_SAVE_TOKEN"
|
||||
|
||||
_getdeployconf VAULT_RENEW_TOKEN
|
||||
_savedeployconf VAULT_RENEW_TOKEN "$VAULT_RENEW_TOKEN"
|
||||
|
||||
_getdeployconf VAULT_KV_V2
|
||||
_savedeployconf VAULT_KV_V2 "$VAULT_KV_V2"
|
||||
|
||||
_getdeployconf VAULT_TOKEN
|
||||
if [ -z "$VAULT_TOKEN" ]; then
|
||||
_err "VAULT_TOKEN needs to be defined"
|
||||
return 1
|
||||
fi
|
||||
if [ -n "$VAULT_SAVE_TOKEN" ]; then
|
||||
_savedeployconf VAULT_TOKEN "$VAULT_TOKEN"
|
||||
fi
|
||||
|
||||
_migratedeployconf FABIO VAULT_FABIO_MODE
|
||||
|
||||
# JSON does not allow multiline strings.
|
||||
# So replacing new-lines with "\n" here
|
||||
_ckey=$(sed -z 's/\n/\\n/g' <"$2")
|
||||
@@ -52,26 +75,56 @@ vault_deploy() {
|
||||
_cca=$(sed -z 's/\n/\\n/g' <"$4")
|
||||
_cfullchain=$(sed -z 's/\n/\\n/g' <"$5")
|
||||
|
||||
URL="$VAULT_ADDR/v1/$VAULT_PREFIX/$_cdomain"
|
||||
export _H1="X-Vault-Token: $VAULT_TOKEN"
|
||||
|
||||
if [ -n "$FABIO" ]; then
|
||||
if [ -n "$VAULT_RENEW_TOKEN" ]; then
|
||||
URL="$VAULT_ADDR/v1/auth/token/renew-self"
|
||||
_info "Renew the Vault token to default TTL"
|
||||
if ! _post "" "$URL" >/dev/null; then
|
||||
_err "Failed to renew the Vault token"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
URL="$VAULT_ADDR/v1/$VAULT_PREFIX/$_cdomain"
|
||||
|
||||
if [ -n "$VAULT_FABIO_MODE" ]; then
|
||||
_info "Writing certificate and key to $URL in Fabio mode"
|
||||
if [ -n "$VAULT_KV_V2" ]; then
|
||||
_post "{ \"data\": {\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"} }" "$URL"
|
||||
_post "{ \"data\": {\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"} }" "$URL" >/dev/null || return 1
|
||||
else
|
||||
_post "{\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"}" "$URL"
|
||||
_post "{\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"}" "$URL" >/dev/null || return 1
|
||||
fi
|
||||
else
|
||||
if [ -n "$VAULT_KV_V2" ]; then
|
||||
_post "{\"data\": {\"value\": \"$_ccert\"}}" "$URL/cert.pem"
|
||||
_post "{\"data\": {\"value\": \"$_ckey\"}}" "$URL/cert.key"
|
||||
_post "{\"data\": {\"value\": \"$_cca\"}}" "$URL/chain.pem"
|
||||
_post "{\"data\": {\"value\": \"$_cfullchain\"}}" "$URL/fullchain.pem"
|
||||
_info "Writing certificate to $URL/cert.pem"
|
||||
_post "{\"data\": {\"value\": \"$_ccert\"}}" "$URL/cert.pem" >/dev/null || return 1
|
||||
_info "Writing key to $URL/cert.key"
|
||||
_post "{\"data\": {\"value\": \"$_ckey\"}}" "$URL/cert.key" >/dev/null || return 1
|
||||
_info "Writing CA certificate to $URL/ca.pem"
|
||||
_post "{\"data\": {\"value\": \"$_cca\"}}" "$URL/ca.pem" >/dev/null || return 1
|
||||
_info "Writing full-chain certificate to $URL/fullchain.pem"
|
||||
_post "{\"data\": {\"value\": \"$_cfullchain\"}}" "$URL/fullchain.pem" >/dev/null || return 1
|
||||
else
|
||||
_post "{\"value\": \"$_ccert\"}" "$URL/cert.pem"
|
||||
_post "{\"value\": \"$_ckey\"}" "$URL/cert.key"
|
||||
_post "{\"value\": \"$_cca\"}" "$URL/chain.pem"
|
||||
_post "{\"value\": \"$_cfullchain\"}" "$URL/fullchain.pem"
|
||||
_info "Writing certificate to $URL/cert.pem"
|
||||
_post "{\"value\": \"$_ccert\"}" "$URL/cert.pem" >/dev/null || return 1
|
||||
_info "Writing key to $URL/cert.key"
|
||||
_post "{\"value\": \"$_ckey\"}" "$URL/cert.key" >/dev/null || return 1
|
||||
_info "Writing CA certificate to $URL/ca.pem"
|
||||
_post "{\"value\": \"$_cca\"}" "$URL/ca.pem" >/dev/null || return 1
|
||||
_info "Writing full-chain certificate to $URL/fullchain.pem"
|
||||
_post "{\"value\": \"$_cfullchain\"}" "$URL/fullchain.pem" >/dev/null || return 1
|
||||
fi
|
||||
|
||||
# To make it compatible with the wrong ca path `chain.pem` which was used in former versions
|
||||
if _contains "$(_get "$URL/chain.pem")" "-----BEGIN CERTIFICATE-----"; then
|
||||
_err "The CA certificate has moved from chain.pem to ca.pem, if you don't depend on chain.pem anymore, you can delete it to avoid this warning"
|
||||
_info "Updating CA certificate to $URL/chain.pem for backward compatibility"
|
||||
if [ -n "$VAULT_KV_V2" ]; then
|
||||
_post "{\"data\": {\"value\": \"$_cca\"}}" "$URL/chain.pem" >/dev/null || return 1
|
||||
else
|
||||
_post "{\"value\": \"$_cca\"}" "$URL/chain.pem" >/dev/null || return 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#
|
||||
# VAULT_PREFIX - this contains the prefix path in vault
|
||||
# VAULT_ADDR - vault requires this to find your vault server
|
||||
# VAULT_SAVE_TOKEN - set to anything if you want to save the token
|
||||
# VAULT_RENEW_TOKEN - set to anything if you want to renew the token to default TTL before deploying
|
||||
#
|
||||
# additionally, you need to ensure that VAULT_TOKEN is avialable or
|
||||
# `vault auth` has applied the appropriate authorization for the vault binary
|
||||
@@ -33,15 +35,36 @@ vault_cli_deploy() {
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
# validate required env vars
|
||||
_getdeployconf VAULT_PREFIX
|
||||
if [ -z "$VAULT_PREFIX" ]; then
|
||||
_err "VAULT_PREFIX needs to be defined (contains prefix path in vault)"
|
||||
return 1
|
||||
fi
|
||||
_savedeployconf VAULT_PREFIX "$VAULT_PREFIX"
|
||||
|
||||
_getdeployconf VAULT_ADDR
|
||||
if [ -z "$VAULT_ADDR" ]; then
|
||||
_err "VAULT_ADDR needs to be defined (contains vault connection address)"
|
||||
return 1
|
||||
fi
|
||||
_savedeployconf VAULT_ADDR "$VAULT_ADDR"
|
||||
|
||||
_getdeployconf VAULT_SAVE_TOKEN
|
||||
_savedeployconf VAULT_SAVE_TOKEN "$VAULT_SAVE_TOKEN"
|
||||
|
||||
_getdeployconf VAULT_RENEW_TOKEN
|
||||
_savedeployconf VAULT_RENEW_TOKEN "$VAULT_RENEW_TOKEN"
|
||||
|
||||
_getdeployconf VAULT_TOKEN
|
||||
if [ -z "$VAULT_TOKEN" ]; then
|
||||
_err "VAULT_TOKEN needs to be defined"
|
||||
return 1
|
||||
fi
|
||||
if [ -n "$VAULT_SAVE_TOKEN" ]; then
|
||||
_savedeployconf VAULT_TOKEN "$VAULT_TOKEN"
|
||||
fi
|
||||
|
||||
_migratedeployconf FABIO VAULT_FABIO_MODE
|
||||
|
||||
VAULT_CMD=$(command -v vault)
|
||||
if [ ! $? ]; then
|
||||
@@ -49,13 +72,33 @@ vault_cli_deploy() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -n "$FABIO" ]; then
|
||||
if [ -n "$VAULT_RENEW_TOKEN" ]; then
|
||||
_info "Renew the Vault token to default TTL"
|
||||
if ! $VAULT_CMD token renew; then
|
||||
_err "Failed to renew the Vault token"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$VAULT_FABIO_MODE" ]; then
|
||||
_info "Writing certificate and key to ${VAULT_PREFIX}/${_cdomain} in Fabio mode"
|
||||
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}" cert=@"$_cfullchain" key=@"$_ckey" || return 1
|
||||
else
|
||||
_info "Writing certificate to ${VAULT_PREFIX}/${_cdomain}/cert.pem"
|
||||
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/cert.pem" value=@"$_ccert" || return 1
|
||||
_info "Writing key to ${VAULT_PREFIX}/${_cdomain}/cert.key"
|
||||
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/cert.key" value=@"$_ckey" || return 1
|
||||
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/chain.pem" value=@"$_cca" || return 1
|
||||
_info "Writing CA certificate to ${VAULT_PREFIX}/${_cdomain}/ca.pem"
|
||||
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/ca.pem" value=@"$_cca" || return 1
|
||||
_info "Writing full-chain certificate to ${VAULT_PREFIX}/${_cdomain}/fullchain.pem"
|
||||
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/fullchain.pem" value=@"$_cfullchain" || return 1
|
||||
|
||||
# To make it compatible with the wrong ca path `chain.pem` which was used in former versions
|
||||
if $VAULT_CMD kv get "${VAULT_PREFIX}/${_cdomain}/chain.pem" >/dev/null; then
|
||||
_err "The CA certificate has moved from chain.pem to ca.pem, if you don't depend on chain.pem anymore, you can delete it to avoid this warning"
|
||||
_info "Updating CA certificate to ${VAULT_PREFIX}/${_cdomain}/chain.pem for backward compatibility"
|
||||
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/chain.pem" value=@"$_cca" || return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
## Acmeproxy DNS provider to be used with acmeproxy (http://github.com/mdbraber/acmeproxy)
|
||||
## Acmeproxy DNS provider to be used with acmeproxy (https://github.com/mdbraber/acmeproxy)
|
||||
## API integration by Maarten den Braber
|
||||
##
|
||||
## Report any bugs via https://github.com/mdbraber/acme.sh
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#Arvan_Token="Apikey xxxx"
|
||||
# Arvan_Token="Apikey xxxx"
|
||||
|
||||
ARVAN_API_URL="https://napi.arvancloud.com/cdn/4.0/domains"
|
||||
#Author: Vahid Fardi
|
||||
#Report Bugs here: https://github.com/Neilpang/acme.sh
|
||||
ARVAN_API_URL="https://napi.arvancloud.ir/cdn/4.0/domains"
|
||||
# Author: Vahid Fardi
|
||||
# Report Bugs here: https://github.com/Neilpang/acme.sh
|
||||
#
|
||||
######## Public functions #####################
|
||||
|
||||
@@ -18,7 +18,7 @@ dns_arvan_add() {
|
||||
|
||||
if [ -z "$Arvan_Token" ]; then
|
||||
_err "You didn't specify \"Arvan_Token\" token yet."
|
||||
_err "You can get yours from here https://npanel.arvancloud.com/profile/api-keys"
|
||||
_err "You can get yours from here https://npanel.arvancloud.ir/profile/api-keys"
|
||||
return 1
|
||||
fi
|
||||
#save the api token to the account conf file.
|
||||
@@ -40,7 +40,7 @@ dns_arvan_add() {
|
||||
_info "response id is $response"
|
||||
_info "Added, OK"
|
||||
return 0
|
||||
elif _contains "$response" "Record Data is Duplicated"; then
|
||||
elif _contains "$response" "Record Data is duplicate"; then
|
||||
_info "Already exists, OK"
|
||||
return 0
|
||||
else
|
||||
@@ -141,6 +141,7 @@ _arvan_rest() {
|
||||
response="$(_post "$data" "$ARVAN_API_URL/$ep" "" "$mtd")"
|
||||
elif [ "$mtd" = "POST" ]; then
|
||||
export _H2="Content-Type: application/json"
|
||||
export _H3="Accept: application/json"
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$ARVAN_API_URL/$ep" "" "$mtd")"
|
||||
else
|
||||
|
||||
@@ -152,34 +152,23 @@ dns_aws_rm() {
|
||||
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=2
|
||||
i=1
|
||||
p=1
|
||||
|
||||
if aws_rest GET "2013-04-01/hostedzone"; then
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug2 "Checking domain: $h"
|
||||
if [ -z "$h" ]; then
|
||||
if _contains "$response" "<IsTruncated>true</IsTruncated>" && _contains "$response" "<NextMarker>"; then
|
||||
_debug "IsTruncated"
|
||||
_nextMarker="$(echo "$response" | _egrep_o "<NextMarker>.*</NextMarker>" | cut -d '>' -f 2 | cut -d '<' -f 1)"
|
||||
_debug "NextMarker" "$_nextMarker"
|
||||
if aws_rest GET "2013-04-01/hostedzone" "marker=$_nextMarker"; then
|
||||
_debug "Truncated request OK"
|
||||
i=2
|
||||
p=1
|
||||
continue
|
||||
else
|
||||
_err "Truncated request error."
|
||||
fi
|
||||
fi
|
||||
#not valid
|
||||
_err "Invalid domain"
|
||||
return 1
|
||||
fi
|
||||
# iterate over names (a.b.c.d -> b.c.d -> c.d -> d)
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug "Checking domain: $h"
|
||||
if [ -z "$h" ]; then
|
||||
_error "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# iterate over paginated result for list_hosted_zones
|
||||
aws_rest GET "2013-04-01/hostedzone"
|
||||
while true; do
|
||||
if _contains "$response" "<Name>$h.</Name>"; then
|
||||
hostedzone="$(echo "$response" | sed 's/<HostedZone>/#&/g' | tr '#' '\n' | _egrep_o "<HostedZone><Id>[^<]*<.Id><Name>$h.<.Name>.*<PrivateZone>false<.PrivateZone>.*<.HostedZone>")"
|
||||
hostedzone="$(echo "$response" | tr -d '\n' | sed 's/<HostedZone>/#&/g' | tr '#' '\n' | _egrep_o "<HostedZone><Id>[^<]*<.Id><Name>$h.<.Name>.*<PrivateZone>false<.PrivateZone>.*<.HostedZone>")"
|
||||
_debug hostedzone "$hostedzone"
|
||||
if [ "$hostedzone" ]; then
|
||||
_domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "<Id>.*<.Id>" | head -n 1 | _egrep_o ">.*<" | tr -d "<>")
|
||||
@@ -192,10 +181,19 @@ _get_root() {
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
if _contains "$response" "<IsTruncated>true</IsTruncated>" && _contains "$response" "<NextMarker>"; then
|
||||
_debug "IsTruncated"
|
||||
_nextMarker="$(echo "$response" | _egrep_o "<NextMarker>.*</NextMarker>" | cut -d '>' -f 2 | cut -d '<' -f 1)"
|
||||
_debug "NextMarker" "$_nextMarker"
|
||||
else
|
||||
break
|
||||
fi
|
||||
_debug "Checking domain: $h - Next Page "
|
||||
aws_rest GET "2013-04-01/hostedzone" "marker=$_nextMarker"
|
||||
done
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
|
||||
248
dnsapi/dns_bunny.sh
Normal file
248
dnsapi/dns_bunny.sh
Normal file
@@ -0,0 +1,248 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
## Will be called by acme.sh to add the TXT record via the Bunny DNS API.
|
||||
## returns 0 means success, otherwise error.
|
||||
|
||||
## Author: nosilver4u <nosilver4u at ewww.io>
|
||||
## GitHub: https://github.com/nosilver4u/acme.sh
|
||||
|
||||
##
|
||||
## Environment Variables Required:
|
||||
##
|
||||
## BUNNY_API_KEY="75310dc4-ca77-9ac3-9a19-f6355db573b49ce92ae1-2655-3ebd-61ac-3a3ae34834cc"
|
||||
##
|
||||
|
||||
##################### Public functions #####################
|
||||
|
||||
## Create the text record for validation.
|
||||
## Usage: fulldomain txtvalue
|
||||
## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs"
|
||||
dns_bunny_add() {
|
||||
fulldomain="$(echo "$1" | _lower_case)"
|
||||
txtvalue=$2
|
||||
|
||||
BUNNY_API_KEY="${BUNNY_API_KEY:-$(_readaccountconf_mutable BUNNY_API_KEY)}"
|
||||
# Check if API Key is set
|
||||
if [ -z "$BUNNY_API_KEY" ]; then
|
||||
BUNNY_API_KEY=""
|
||||
_err "You did not specify Bunny.net API key."
|
||||
_err "Please export BUNNY_API_KEY and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Using Bunny.net dns validation - add record"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
## save the env vars (key and domain split location) for later automated use
|
||||
_saveaccountconf_mutable BUNNY_API_KEY "$BUNNY_API_KEY"
|
||||
|
||||
## split the domain for Bunny API
|
||||
if ! _get_base_domain "$fulldomain"; then
|
||||
_err "domain not found in your account for addition"
|
||||
return 1
|
||||
fi
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
_debug _domain_id "$_domain_id"
|
||||
|
||||
## Set the header with our post type and auth key
|
||||
export _H1="Accept: application/json"
|
||||
export _H2="AccessKey: $BUNNY_API_KEY"
|
||||
export _H3="Content-Type: application/json"
|
||||
PURL="https://api.bunny.net/dnszone/$_domain_id/records"
|
||||
PBODY='{"Id":'$_domain_id',"Type":3,"Name":"'$_sub_domain'","Value":"'$txtvalue'","ttl":120}'
|
||||
|
||||
_debug PURL "$PURL"
|
||||
_debug PBODY "$PBODY"
|
||||
|
||||
## the create request - POST
|
||||
## args: BODY, URL, [need64, httpmethod]
|
||||
response="$(_post "$PBODY" "$PURL" "" "PUT")"
|
||||
|
||||
## check response
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error in response: $response"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
|
||||
## finished correctly
|
||||
return 0
|
||||
}
|
||||
|
||||
## Remove the txt record after validation.
|
||||
## Usage: fulldomain txtvalue
|
||||
## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs"
|
||||
dns_bunny_rm() {
|
||||
fulldomain="$(echo "$1" | _lower_case)"
|
||||
txtvalue=$2
|
||||
|
||||
BUNNY_API_KEY="${BUNNY_API_KEY:-$(_readaccountconf_mutable BUNNY_API_KEY)}"
|
||||
# Check if API Key Exists
|
||||
if [ -z "$BUNNY_API_KEY" ]; then
|
||||
BUNNY_API_KEY=""
|
||||
_err "You did not specify Bunny.net API key."
|
||||
_err "Please export BUNNY_API_KEY and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Using Bunny.net dns validation - remove record"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
## split the domain for Bunny API
|
||||
if ! _get_base_domain "$fulldomain"; then
|
||||
_err "Domain not found in your account for TXT record removal"
|
||||
return 1
|
||||
fi
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
_debug _domain_id "$_domain_id"
|
||||
|
||||
## Set the header with our post type and key auth key
|
||||
export _H1="Accept: application/json"
|
||||
export _H2="AccessKey: $BUNNY_API_KEY"
|
||||
## get URL for the list of DNS records
|
||||
GURL="https://api.bunny.net/dnszone/$_domain_id"
|
||||
|
||||
## 1) Get the domain/zone records
|
||||
## the fetch request - GET
|
||||
## args: URL, [onlyheader, timeout]
|
||||
domain_list="$(_get "$GURL")"
|
||||
|
||||
## check response
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error in domain_list response: $domain_list"
|
||||
return 1
|
||||
fi
|
||||
_debug2 domain_list "$domain_list"
|
||||
|
||||
## 2) search through records
|
||||
## check for what we are looking for: "Type":3,"Value":"$txtvalue","Name":"$_sub_domain"
|
||||
record="$(echo "$domain_list" | _egrep_o "\"Id\"\s*\:\s*\"*[0-9]+\"*,\s*\"Type\"[^}]*\"Value\"\s*\:\s*\"$txtvalue\"[^}]*\"Name\"\s*\:\s*\"$_sub_domain\"")"
|
||||
|
||||
if [ -n "$record" ]; then
|
||||
|
||||
## We found records
|
||||
rec_ids="$(echo "$record" | _egrep_o "Id\"\s*\:\s*\"*[0-9]+" | _egrep_o "[0-9]+")"
|
||||
_debug rec_ids "$rec_ids"
|
||||
if [ -n "$rec_ids" ]; then
|
||||
echo "$rec_ids" | while IFS= read -r rec_id; do
|
||||
## delete the record
|
||||
## delete URL for removing the one we dont want
|
||||
DURL="https://api.bunny.net/dnszone/$_domain_id/records/$rec_id"
|
||||
|
||||
## the removal request - DELETE
|
||||
## args: BODY, URL, [need64, httpmethod]
|
||||
response="$(_post "" "$DURL" "" "DELETE")"
|
||||
|
||||
## check response (sort of)
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error in remove response: $response"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
## finished correctly
|
||||
return 0
|
||||
}
|
||||
|
||||
##################### Private functions below #####################
|
||||
|
||||
## Split the domain provided into the "base domain" and the "start prefix".
|
||||
## This function searches for the longest subdomain in your account
|
||||
## for the full domain given and splits it into the base domain (zone)
|
||||
## and the prefix/record to be added/removed
|
||||
## USAGE: fulldomain
|
||||
## EG: "_acme-challenge.two.three.four.domain.com"
|
||||
## returns
|
||||
## _sub_domain="_acme-challenge.two"
|
||||
## _domain="three.four.domain.com" *IF* zone "three.four.domain.com" exists
|
||||
## _domain_id=234
|
||||
## if only "domain.com" exists it will return
|
||||
## _sub_domain="_acme-challenge.two.three.four"
|
||||
## _domain="domain.com"
|
||||
## _domain_id=234
|
||||
_get_base_domain() {
|
||||
# args
|
||||
fulldomain="$(echo "$1" | _lower_case)"
|
||||
_debug fulldomain "$fulldomain"
|
||||
|
||||
# domain max legal length = 253
|
||||
MAX_DOM=255
|
||||
page=1
|
||||
|
||||
## get a list of domains for the account to check thru
|
||||
## Set the headers
|
||||
export _H1="Accept: application/json"
|
||||
export _H2="AccessKey: $BUNNY_API_KEY"
|
||||
_debug BUNNY_API_KEY "$BUNNY_API_KEY"
|
||||
## get URL for the list of domains
|
||||
## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}}
|
||||
DOMURL="https://api.bunny.net/dnszone"
|
||||
|
||||
## while we dont have a matching domain we keep going
|
||||
while [ -z "$found" ]; do
|
||||
## get the domain list (current page)
|
||||
domain_list="$(_get "$DOMURL")"
|
||||
|
||||
## check response
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error in domain_list response: $domain_list"
|
||||
return 1
|
||||
fi
|
||||
_debug2 domain_list "$domain_list"
|
||||
|
||||
i=1
|
||||
while [ $i -gt 0 ]; do
|
||||
## get next longest domain
|
||||
_domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM")
|
||||
## check we got something back from our cut (or are we at the end)
|
||||
if [ -z "$_domain" ]; then
|
||||
break
|
||||
fi
|
||||
## we got part of a domain back - grep it out
|
||||
found="$(echo "$domain_list" | _egrep_o "\"Id\"\s*:\s*\"*[0-9]+\"*,\s*\"Domain\"\s*\:\s*\"$_domain\"")"
|
||||
## check if it exists
|
||||
if [ -n "$found" ]; then
|
||||
## exists - exit loop returning the parts
|
||||
sub_point=$(_math $i - 1)
|
||||
_sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$sub_point")
|
||||
_domain_id="$(echo "$found" | _egrep_o "Id\"\s*\:\s*\"*[0-9]+" | _egrep_o "[0-9]+")"
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _domain "$_domain"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
found=""
|
||||
return 0
|
||||
fi
|
||||
## increment cut point $i
|
||||
i=$(_math $i + 1)
|
||||
done
|
||||
|
||||
if [ -z "$found" ]; then
|
||||
page=$(_math $page + 1)
|
||||
nextpage="https://api.bunny.net/dnszone?page=$page"
|
||||
## Find the next page if we don't have a match.
|
||||
hasnextpage="$(echo "$domain_list" | _egrep_o "\"HasMoreItems\"\s*:\s*true")"
|
||||
if [ -z "$hasnextpage" ]; then
|
||||
_err "No record and no nextpage in Bunny.net domain search."
|
||||
found=""
|
||||
return 1
|
||||
fi
|
||||
_debug2 nextpage "$nextpage"
|
||||
DOMURL="$nextpage"
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
## We went through the entire domain zone list and didn't find one that matched.
|
||||
## If we ever get here, something is broken in the code...
|
||||
_err "Domain not found in Bunny.net account, but we should never get here!"
|
||||
found=""
|
||||
return 1
|
||||
}
|
||||
@@ -25,9 +25,16 @@ 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"
|
||||
_clearaccountconf_mutable CF_Zone_ID
|
||||
_clearaccountconf CF_Zone_ID
|
||||
fi
|
||||
else
|
||||
if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then
|
||||
CF_Key=""
|
||||
@@ -45,6 +52,14 @@ dns_cf_add() {
|
||||
#save the api key and email to the account conf file.
|
||||
_saveaccountconf_mutable CF_Key "$CF_Key"
|
||||
_saveaccountconf_mutable CF_Email "$CF_Email"
|
||||
|
||||
_clearaccountconf_mutable CF_Token
|
||||
_clearaccountconf_mutable CF_Account_ID
|
||||
_clearaccountconf_mutable CF_Zone_ID
|
||||
_clearaccountconf CF_Token
|
||||
_clearaccountconf CF_Account_ID
|
||||
_clearaccountconf CF_Zone_ID
|
||||
|
||||
fi
|
||||
|
||||
_debug "First detect the root zone"
|
||||
|
||||
@@ -78,7 +78,7 @@ dns_cloudns_rm() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
for i in $(echo "$response" | tr '{' "\n" | grep "$record"); do
|
||||
for i in $(echo "$response" | tr '{' "\n" | grep -- "$record"); do
|
||||
record_id=$(echo "$i" | tr ',' "\n" | grep -E '^"id"' | sed -re 's/^\"id\"\:\"([0-9]+)\"$/\1/g')
|
||||
|
||||
if [ -n "$record_id" ]; then
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
# cPanel_Hostname=hostname
|
||||
#
|
||||
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
|
||||
# Used to add txt record
|
||||
dns_cpanel_add() {
|
||||
fulldomain=$1
|
||||
@@ -120,7 +121,7 @@ _myget() {
|
||||
|
||||
_get_root() {
|
||||
_myget 'json-api/cpanel?cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=ZoneEdit&cpanel_jsonapi_func=fetchzones'
|
||||
_domains=$(echo "$_result" | sed 's/.*\(zones.*\[\).*/\1/' | cut -d':' -f2 | sed 's/"//g' | sed 's/{//g')
|
||||
_domains=$(echo "$_result" | _egrep_o '"[a-z0-9\.\-]*":\["; cPanel first' | cut -d':' -f1 | sed 's/"//g' | sed 's/{//g')
|
||||
_debug "_result is: $_result"
|
||||
_debug "_domains is: $_domains"
|
||||
if [ -z "$_domains" ]; then
|
||||
@@ -138,15 +139,15 @@ _get_root() {
|
||||
}
|
||||
|
||||
_successful_update() {
|
||||
if (echo "$_result" | grep -q 'newserial'); then return 0; fi
|
||||
return 1
|
||||
if (echo "$_result" | _egrep_o 'data":\[[^]]*]' | grep -q '"newserial":null'); then return 1; fi
|
||||
return 0
|
||||
}
|
||||
|
||||
_findentry() {
|
||||
_debug "In _findentry"
|
||||
#returns id of dns entry, if it exists
|
||||
_myget "json-api/cpanel?cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=ZoneEdit&cpanel_jsonapi_func=fetchzone_records&domain=$_domain"
|
||||
_id=$(echo "$_result" | sed "s/.*\(line.*$fulldomain.*$txtvalue\).*/\1/" | cut -d ':' -f 2 | cut -d ',' -f 1)
|
||||
_id=$(echo "$_result" | sed -e "s/},{/},\n{/g" | grep "$fulldomain" | grep "$txtvalue" | _egrep_o 'line":[0-9]+' | cut -d ':' -f 2)
|
||||
_debug "_result is: $_result"
|
||||
_debug "fulldomain. is $fulldomain."
|
||||
_debug "txtvalue is $txtvalue"
|
||||
|
||||
159
dnsapi/dns_curanet.sh
Normal file
159
dnsapi/dns_curanet.sh
Normal 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
|
||||
}
|
||||
185
dnsapi/dns_cx.sh
185
dnsapi/dns_cx.sh
@@ -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'
|
||||
|
||||
}
|
||||
@@ -44,7 +44,7 @@ dns_cyon_rm() {
|
||||
_cyon_load_credentials() {
|
||||
# Convert loaded password to/from base64 as needed.
|
||||
if [ "${CY_Password_B64}" ]; then
|
||||
CY_Password="$(printf "%s" "${CY_Password_B64}" | _dbase64 "multiline")"
|
||||
CY_Password="$(printf "%s" "${CY_Password_B64}" | _dbase64)"
|
||||
elif [ "${CY_Password}" ]; then
|
||||
CY_Password_B64="$(printf "%s" "${CY_Password}" | _base64)"
|
||||
fi
|
||||
|
||||
@@ -192,6 +192,7 @@ _get_base_domain() {
|
||||
## get URL for the list of domains
|
||||
## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}}
|
||||
DOMURL="https://api.digitalocean.com/v2/domains"
|
||||
found=""
|
||||
|
||||
## while we dont have a matching domain we keep going
|
||||
while [ -z "$found" ]; do
|
||||
@@ -205,9 +206,7 @@ _get_base_domain() {
|
||||
fi
|
||||
_debug2 domain_list "$domain_list"
|
||||
|
||||
## for each shortening of our $fulldomain, check if it exists in the $domain_list
|
||||
## can never start on 1 (aka whole $fulldomain) as $fulldomain starts with "_acme-challenge"
|
||||
i=2
|
||||
i=1
|
||||
while [ $i -gt 0 ]; do
|
||||
## get next longest domain
|
||||
_domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM")
|
||||
|
||||
248
dnsapi/dns_dnsservices.sh
Executable file
248
dnsapi/dns_dnsservices.sh
Executable file
@@ -0,0 +1,248 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#This file name is "dns_dnsservices.sh"
|
||||
#Script for Danish DNS registra and DNS hosting provider https://dns.services
|
||||
|
||||
#Author: Bjarke Bruun <bbruun@gmail.com>
|
||||
#Report Bugs here: https://github.com/acmesh-official/acme.sh/issues/4152
|
||||
|
||||
# Global variable to connect to the DNS.Services API
|
||||
DNSServices_API=https://dns.services/api
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: dns_dnsservices_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_dnsservices_add() {
|
||||
fulldomain="$1"
|
||||
txtvalue="$2"
|
||||
|
||||
_info "Using dns.services to create ACME DNS challenge"
|
||||
_debug2 add_fulldomain "$fulldomain"
|
||||
_debug2 add_txtvalue "$txtvalue"
|
||||
|
||||
# Read username/password from environment or .acme.sh/accounts.conf
|
||||
DnsServices_Username="${DnsServices_Username:-$(_readaccountconf_mutable DnsServices_Username)}"
|
||||
DnsServices_Password="${DnsServices_Password:-$(_readaccountconf_mutable DnsServices_Password)}"
|
||||
if [ -z "$DnsServices_Username" ] || [ -z "$DnsServices_Password" ]; then
|
||||
DnsServices_Username=""
|
||||
DnsServices_Password=""
|
||||
_err "You didn't specify dns.services api username and password yet."
|
||||
_err "Set environment variables DnsServices_Username and DnsServices_Password"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Setup GET/POST/DELETE headers
|
||||
_setup_headers
|
||||
|
||||
#save the credentials to the account conf file.
|
||||
_saveaccountconf_mutable DnsServices_Username "$DnsServices_Username"
|
||||
_saveaccountconf_mutable DnsServices_Password "$DnsServices_Password"
|
||||
|
||||
if ! _contains "$DnsServices_Username" "@"; then
|
||||
_err "It seems that the username variable DnsServices_Username has not been set/left blank"
|
||||
_err "or is not a valid email. Please correct and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _get_root "${fulldomain}"; then
|
||||
_err "Invalid domain ${fulldomain}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! createRecord "$fulldomain" "${txtvalue}"; then
|
||||
_err "Error creating TXT record in domain $fulldomain in $rootZoneName"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 challenge-created "Created $fulldomain"
|
||||
return 0
|
||||
}
|
||||
|
||||
#Usage: fulldomain txtvalue
|
||||
#Description: Remove the txt record after validation.
|
||||
dns_dnsservices_rm() {
|
||||
fulldomain="$1"
|
||||
txtvalue="$2"
|
||||
|
||||
_info "Using dns.services to remove DNS record $fulldomain TXT $txtvalue"
|
||||
_debug rm_fulldomain "$fulldomain"
|
||||
_debug rm_txtvalue "$txtvalue"
|
||||
|
||||
# Read username/password from environment or .acme.sh/accounts.conf
|
||||
DnsServices_Username="${DnsServices_Username:-$(_readaccountconf_mutable DnsServices_Username)}"
|
||||
DnsServices_Password="${DnsServices_Password:-$(_readaccountconf_mutable DnsServices_Password)}"
|
||||
if [ -z "$DnsServices_Username" ] || [ -z "$DnsServices_Password" ]; then
|
||||
DnsServices_Username=""
|
||||
DnsServices_Password=""
|
||||
_err "You didn't specify dns.services api username and password yet."
|
||||
_err "Set environment variables DnsServices_Username and DnsServices_Password"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Setup GET/POST/DELETE headers
|
||||
_setup_headers
|
||||
|
||||
if ! _get_root "${fulldomain}"; then
|
||||
_err "Invalid domain ${fulldomain}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 rm_rootDomainInfo "found root domain $rootZoneName for $fulldomain"
|
||||
|
||||
if ! deleteRecord "${fulldomain}" "${txtvalue}"; then
|
||||
_err "Error removing record: $fulldomain TXT ${txtvalue}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
_setup_headers() {
|
||||
# Set up API Headers for _get() and _post()
|
||||
# The <function>_add or <function>_rm must have been called before to work
|
||||
|
||||
if [ -z "$DnsServices_Username" ] || [ -z "$DnsServices_Password" ]; then
|
||||
_err "Could not setup BASIC authentication headers, they are missing"
|
||||
return 1
|
||||
fi
|
||||
|
||||
DnsServiceCredentials="$(printf "%s" "$DnsServices_Username:$DnsServices_Password" | _base64)"
|
||||
export _H1="Authorization: Basic $DnsServiceCredentials"
|
||||
export _H2="Content-Type: application/json"
|
||||
|
||||
# Just return if headers are set
|
||||
return 0
|
||||
}
|
||||
|
||||
_get_root() {
|
||||
domain="$1"
|
||||
_debug2 _get_root "Get the root domain of ${domain} for DNS API"
|
||||
|
||||
# Setup _get() and _post() headers
|
||||
#_setup_headers
|
||||
|
||||
result=$(_H1="$_H1" _H2="$_H2" _get "$DNSServices_API/dns")
|
||||
result2="$(printf "%s\n" "$result" | tr '[' '\n' | grep '"name"')"
|
||||
result3="$(printf "%s\n" "$result2" | tr '}' '\n' | grep '"name"' | sed "s,^\,,,g" | sed "s,$,},g")"
|
||||
useResult=""
|
||||
_debug2 _get_root "Got the following root domain(s) $result"
|
||||
_debug2 _get_root "- JSON: $result"
|
||||
|
||||
if [ "$(printf "%s\n" "$result" | tr '}' '\n' | grep -c '"name"')" -gt "1" ]; then
|
||||
checkMultiZones="true"
|
||||
_debug2 _get_root "- multiple zones found"
|
||||
else
|
||||
checkMultiZones="false"
|
||||
_debug2 _get_root "- single zone found"
|
||||
fi
|
||||
|
||||
# Find/isolate the root zone to work with in createRecord() and deleteRecord()
|
||||
rootZone=""
|
||||
if [ "$checkMultiZones" = "true" ]; then
|
||||
#rootZone=$(for x in $(printf "%s" "${result3}" | tr ',' '\n' | sed -n 's/.*"name":"\(.*\)",.*/\1/p'); do if [ "$(echo "$domain" | grep "$x")" != "" ]; then echo "$x"; fi; done)
|
||||
rootZone=$(for x in $(printf "%s\n" "${result3}" | tr ',' '\n' | grep name | cut -d'"' -f4); do if [ "$(echo "$domain" | grep "$x")" != "" ]; then echo "$x"; fi; done)
|
||||
if [ "$rootZone" != "" ]; then
|
||||
_debug2 _rootZone "- root zone for $domain is $rootZone"
|
||||
else
|
||||
_err "Could not find root zone for $domain, is it correctly typed?"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
rootZone=$(echo "$result" | tr '}' '\n' | _egrep_o '"name":"[^"]*' | cut -d'"' -f4)
|
||||
_debug2 _get_root "- only found 1 domain in API: $rootZone"
|
||||
fi
|
||||
|
||||
if [ -z "$rootZone" ]; then
|
||||
_err "Could not find root domain for $domain - is it correctly typed?"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Make sure we use the correct API zone data
|
||||
useResult="$(printf "%s\n" "${result3}" tr ',' '\n' | grep "$rootZone")"
|
||||
_debug2 _useResult "useResult=$useResult"
|
||||
|
||||
# Setup variables used by other functions to communicate with DNS.Services API
|
||||
#zoneInfo=$(printf "%s\n" "$useResult" | sed -E 's,.*(zones)(.*),\1\2,g' | sed -E 's,^(.*"name":")([^"]*)"(.*)$,\2,g')
|
||||
zoneInfo=$(printf "%s\n" "$useResult" | tr ',' '\n' | grep '"name"' | cut -d'"' -f4)
|
||||
rootZoneName="$rootZone"
|
||||
subDomainName="$(printf "%s\n" "$domain" | sed "s,\.$rootZone,,g")"
|
||||
subDomainNameClean="$(printf "%s\n" "$domain" | sed "s,_acme-challenge.,,g")"
|
||||
rootZoneDomainID=$(printf "%s\n" "$useResult" | tr ',' '\n' | grep domain_id | cut -d'"' -f4)
|
||||
rootZoneServiceID=$(printf "%s\n" "$useResult" | tr ',' '\n' | grep service_id | cut -d'"' -f4)
|
||||
|
||||
_debug2 _zoneInfo "Zone info from API : $zoneInfo"
|
||||
_debug2 _get_root "Root zone name : $rootZoneName"
|
||||
_debug2 _get_root "Root zone domain ID : $rootZoneDomainID"
|
||||
_debug2 _get_root "Root zone service ID: $rootZoneServiceID"
|
||||
_debug2 _get_root "Sub domain : $subDomainName"
|
||||
|
||||
_debug _get_root "Found valid root domain $rootZone for $subDomainNameClean"
|
||||
return 0
|
||||
}
|
||||
|
||||
createRecord() {
|
||||
fulldomain="$1"
|
||||
txtvalue="$2"
|
||||
|
||||
# Get root domain information - needed for DNS.Services API communication
|
||||
if [ -z "$rootZoneName" ] || [ -z "$rootZoneDomainID" ] || [ -z "$rootZoneServiceID" ]; then
|
||||
_get_root "$fulldomain"
|
||||
fi
|
||||
if [ -z "$rootZoneName" ] || [ -z "$rootZoneDomainID" ] || [ -z "$rootZoneServiceID" ]; then
|
||||
_err "Something happend - could not get the API zone information"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 createRecord "CNAME TXT value is: $txtvalue"
|
||||
|
||||
# Prepare data to send to API
|
||||
data="{\"name\":\"${fulldomain}\",\"type\":\"TXT\",\"content\":\"${txtvalue}\", \"ttl\":\"10\"}"
|
||||
|
||||
_debug2 createRecord "data to API: $data"
|
||||
result=$(_post "$data" "$DNSServices_API/service/$rootZoneServiceID/dns/$rootZoneDomainID/records" "" "POST")
|
||||
_debug2 createRecord "result from API: $result"
|
||||
|
||||
if [ "$(echo "$result" | _egrep_o "\"success\":true")" = "" ]; then
|
||||
_err "Failed to create TXT record $fulldomain with content $txtvalue in zone $rootZoneName"
|
||||
_err "$result"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Record \"$fulldomain TXT $txtvalue\" has been created"
|
||||
return 0
|
||||
}
|
||||
|
||||
deleteRecord() {
|
||||
fulldomain="$1"
|
||||
txtvalue="$2"
|
||||
|
||||
_log deleteRecord "Deleting $fulldomain TXT $txtvalue record"
|
||||
|
||||
if [ -z "$rootZoneName" ] || [ -z "$rootZoneDomainID" ] || [ -z "$rootZoneServiceID" ]; then
|
||||
_get_root "$fulldomain"
|
||||
fi
|
||||
|
||||
result="$(_H1="$_H1" _H2="$_H2" _get "$DNSServices_API/service/$rootZoneServiceID/dns/$rootZoneDomainID")"
|
||||
#recordInfo="$(echo "$result" | sed -e 's/:{/:{\n/g' -e 's/},/\n},\n/g' | grep "${txtvalue}")"
|
||||
#recordID="$(echo "$recordInfo" | sed -e 's/:{/:{\n/g' -e 's/},/\n},\n/g' | grep "${txtvalue}" | sed -E 's,.*(zones)(.*),\1\2,g' | sed -E 's,^(.*"id":")([^"]*)"(.*)$,\2,g')"
|
||||
recordID="$(printf "%s\n" "$result" | tr '}' '\n' | grep -- "$txtvalue" | tr ',' '\n' | grep '"id"' | cut -d'"' -f4)"
|
||||
_debug2 _recordID "recordID used for deletion of record: $recordID"
|
||||
|
||||
if [ -z "$recordID" ]; then
|
||||
_info "Record $fulldomain TXT $txtvalue not found or already deleted"
|
||||
return 0
|
||||
else
|
||||
_debug2 deleteRecord "Found recordID=$recordID"
|
||||
fi
|
||||
|
||||
_debug2 deleteRecord "DELETE request $DNSServices_API/service/$rootZoneServiceID/dns/$rootZoneDomainID/records/$recordID"
|
||||
_log "curl DELETE request $DNSServices_API/service/$rootZoneServiceID/dns/$rootZoneDomainID/records/$recordID"
|
||||
result="$(_H1="$_H1" _H2="$_H2" _post "" "$DNSServices_API/service/$rootZoneServiceID/dns/$rootZoneDomainID/records/$recordID" "" "DELETE")"
|
||||
_debug2 deleteRecord "API Delete result \"$result\""
|
||||
_log "curl API Delete result \"$result\""
|
||||
|
||||
# Return OK regardless
|
||||
return 0
|
||||
}
|
||||
@@ -94,8 +94,8 @@ _get_domain() {
|
||||
_your_hosts="$(echo "$_your_hosts" | awk '/\./ {print $1}')"
|
||||
for l in $_your_hosts; do
|
||||
#echo "host: $l"
|
||||
if test "${_full_domain#*$l}" != "$_full_domain"; then
|
||||
_record="${_full_domain%.$l}"
|
||||
if test "${_full_domain#*"$l"}" != "$_full_domain"; then
|
||||
_record=${_full_domain%."$l"}
|
||||
_host=$l
|
||||
_debug "The host is $_host and the record $_record"
|
||||
return 0
|
||||
@@ -143,7 +143,7 @@ _dns_dynv6_add_http() {
|
||||
return 1
|
||||
fi
|
||||
_get_zone_name "$_zone_id"
|
||||
record="${fulldomain%%.$_zone_name}"
|
||||
record=${fulldomain%%."$_zone_name"}
|
||||
_set_record TXT "$record" "$txtvalue"
|
||||
if _contains "$response" "$txtvalue"; then
|
||||
_info "Successfully added record"
|
||||
@@ -161,7 +161,7 @@ _dns_dynv6_rm_http() {
|
||||
return 1
|
||||
fi
|
||||
_get_zone_name "$_zone_id"
|
||||
record="${fulldomain%%.$_zone_name}"
|
||||
record=${fulldomain%%."$_zone_name"}
|
||||
_get_record_id "$_zone_id" "$record" "$txtvalue"
|
||||
_del_record "$_zone_id" "$_record_id"
|
||||
if [ -z "$response" ]; then
|
||||
|
||||
@@ -176,6 +176,7 @@ _EDGEDNS_credentials() {
|
||||
_debug "GettingEdge DNS credentials"
|
||||
_log "$(printf "ACME DNSAPI Edge DNS version %s" ${ACME_EDGEDNS_VERSION})"
|
||||
args_missing=0
|
||||
AKAMAI_ACCESS_TOKEN="${AKAMAI_ACCESS_TOKEN:-$(_readaccountconf_mutable AKAMAI_ACCESS_TOKEN)}"
|
||||
if [ -z "$AKAMAI_ACCESS_TOKEN" ]; then
|
||||
AKAMAI_ACCESS_TOKEN=""
|
||||
AKAMAI_CLIENT_TOKEN=""
|
||||
@@ -184,6 +185,7 @@ _EDGEDNS_credentials() {
|
||||
_err "AKAMAI_ACCESS_TOKEN is missing"
|
||||
args_missing=1
|
||||
fi
|
||||
AKAMAI_CLIENT_TOKEN="${AKAMAI_CLIENT_TOKEN:-$(_readaccountconf_mutable AKAMAI_CLIENT_TOKEN)}"
|
||||
if [ -z "$AKAMAI_CLIENT_TOKEN" ]; then
|
||||
AKAMAI_ACCESS_TOKEN=""
|
||||
AKAMAI_CLIENT_TOKEN=""
|
||||
@@ -192,6 +194,7 @@ _EDGEDNS_credentials() {
|
||||
_err "AKAMAI_CLIENT_TOKEN is missing"
|
||||
args_missing=1
|
||||
fi
|
||||
AKAMAI_HOST="${AKAMAI_HOST:-$(_readaccountconf_mutable AKAMAI_HOST)}"
|
||||
if [ -z "$AKAMAI_HOST" ]; then
|
||||
AKAMAI_ACCESS_TOKEN=""
|
||||
AKAMAI_CLIENT_TOKEN=""
|
||||
@@ -200,6 +203,7 @@ _EDGEDNS_credentials() {
|
||||
_err "AKAMAI_HOST is missing"
|
||||
args_missing=1
|
||||
fi
|
||||
AKAMAI_CLIENT_SECRET="${AKAMAI_CLIENT_SECRET:-$(_readaccountconf_mutable AKAMAI_CLIENT_SECRET)}"
|
||||
if [ -z "$AKAMAI_CLIENT_SECRET" ]; then
|
||||
AKAMAI_ACCESS_TOKEN=""
|
||||
AKAMAI_CLIENT_TOKEN=""
|
||||
@@ -414,7 +418,7 @@ _edgedns_make_data_to_sign() {
|
||||
_secure_debug2 "hdr" "$hdr"
|
||||
_edgedns_make_content_hash
|
||||
path="$(echo "$_request_url_path" | tr -d "\n\r" | sed 's/https\?:\/\///')"
|
||||
path="${path#*$AKAMAI_HOST}"
|
||||
path=${path#*"$AKAMAI_HOST"}
|
||||
_debug "hier path" "$path"
|
||||
# dont expose headers to sign so use MT string
|
||||
_mdata="$(printf "%s\thttps\t%s\t%s\t%s\t%s\t%s" "$_request_method" "$AKAMAI_HOST" "$path" "" "$_hash" "$hdr")"
|
||||
|
||||
146
dnsapi/dns_fornex.sh
Normal file
146
dnsapi/dns_fornex.sh
Normal 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
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Gandi LiveDNS v5 API
|
||||
# http://doc.livedns.gandi.net/
|
||||
# https://doc.livedns.gandi.net/
|
||||
# currently under beta
|
||||
#
|
||||
# Requires GANDI API KEY set in GANDI_LIVEDNS_KEY set as environment variable
|
||||
|
||||
@@ -39,7 +39,7 @@ dns_gcloud_rm() {
|
||||
_dns_gcloud_start_tr || return $?
|
||||
_dns_gcloud_get_rrdatas || return $?
|
||||
echo "$rrdatas" | _dns_gcloud_remove_rrs || return $?
|
||||
echo "$rrdatas" | grep -F -v "\"$txtvalue\"" | _dns_gcloud_add_rrs || return $?
|
||||
echo "$rrdatas" | grep -F -v -- "\"$txtvalue\"" | _dns_gcloud_add_rrs || return $?
|
||||
_dns_gcloud_execute_tr || return $?
|
||||
|
||||
_info "$fulldomain record added"
|
||||
@@ -98,7 +98,7 @@ _dns_gcloud_remove_rrs() {
|
||||
--ttl="$ttl" \
|
||||
--type=TXT \
|
||||
--zone="$managedZone" \
|
||||
--transaction-file="$tr"; then
|
||||
--transaction-file="$tr" --; then
|
||||
_debug tr "$(cat "$tr")"
|
||||
rm -r "$trd"
|
||||
_err "_dns_gcloud_remove_rrs: failed to remove RRs"
|
||||
@@ -113,7 +113,7 @@ _dns_gcloud_add_rrs() {
|
||||
--ttl="$ttl" \
|
||||
--type=TXT \
|
||||
--zone="$managedZone" \
|
||||
--transaction-file="$tr"; then
|
||||
--transaction-file="$tr" --; then
|
||||
_debug tr "$(cat "$tr")"
|
||||
rm -r "$trd"
|
||||
_err "_dns_gcloud_add_rrs: failed to add RRs"
|
||||
|
||||
187
dnsapi/dns_gcore.sh
Executable file
187
dnsapi/dns_gcore.sh
Executable file
@@ -0,0 +1,187 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
#GCORE_Key='773$7b7adaf2a2b32bfb1b83787b4ff32a67eb178e3ada1af733e47b1411f2461f7f4fa7ed7138e2772a46124377bad7384b3bb8d87748f87b3f23db4b8bbe41b2bb'
|
||||
#
|
||||
|
||||
GCORE_Api="https://api.gcorelabs.com/dns/v2"
|
||||
GCORE_Doc="https://apidocs.gcore.com/dns"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_gcore_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
GCORE_Key="${GCORE_Key:-$(_readaccountconf_mutable GCORE_Key)}"
|
||||
|
||||
if [ -z "$GCORE_Key" ]; then
|
||||
GCORE_Key=""
|
||||
_err "You didn't specify a Gcore api key yet."
|
||||
_err "You can get yours from here $GCORE_Doc"
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the api key to the account conf file.
|
||||
_saveaccountconf_mutable GCORE_Key "$GCORE_Key"
|
||||
|
||||
_debug "First detect the zone name"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _zone_name "$_zone_name"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_debug "Getting txt records"
|
||||
_gcore_rest GET "zones/$_zone_name/$fulldomain/TXT"
|
||||
payload=""
|
||||
|
||||
if echo "$response" | grep "record is not found" >/dev/null; then
|
||||
_info "Record doesn't exists"
|
||||
payload="{\"resource_records\":[{\"content\":[\"$txtvalue\"],\"enabled\":true}],\"ttl\":120}"
|
||||
elif echo "$response" | grep "$txtvalue" >/dev/null; then
|
||||
_info "Already exists, OK"
|
||||
return 0
|
||||
elif echo "$response" | tr -d " " | grep \"name\":\""$fulldomain"\",\"type\":\"TXT\" >/dev/null; then
|
||||
_info "Record with mismatch txtvalue, try update it"
|
||||
payload=$(echo "$response" | tr -d " " | sed 's/"updated_at":[0-9]\+,//g' | sed 's/"meta":{}}]}/"meta":{}},{"content":['\""$txtvalue"\"'],"enabled":true}]}/')
|
||||
fi
|
||||
|
||||
# For wildcard cert, the main root domain and the wildcard domain have the same txt subdomain name, so
|
||||
# we can not use updating anymore.
|
||||
# count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2)
|
||||
# _debug count "$count"
|
||||
# if [ "$count" = "0" ]; then
|
||||
_info "Adding record"
|
||||
if _gcore_rest PUT "zones/$_zone_name/$fulldomain/TXT" "$payload"; then
|
||||
if _contains "$response" "$txtvalue"; then
|
||||
_info "Added, OK"
|
||||
return 0
|
||||
elif _contains "$response" "rrset is already exists"; then
|
||||
_info "Already exists, OK"
|
||||
return 0
|
||||
else
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
}
|
||||
|
||||
#fulldomain txtvalue
|
||||
dns_gcore_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
GCORE_Key="${GCORE_Key:-$(_readaccountconf_mutable GCORE_Key)}"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _zone_name "$_zone_name"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_debug "Getting txt records"
|
||||
_gcore_rest GET "zones/$_zone_name/$fulldomain/TXT"
|
||||
|
||||
if echo "$response" | grep "record is not found" >/dev/null; then
|
||||
_info "No such txt recrod"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! echo "$response" | tr -d " " | grep \"name\":\""$fulldomain"\",\"type\":\"TXT\" >/dev/null; then
|
||||
_err "Error: $response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! echo "$response" | tr -d " " | grep \""$txtvalue"\" >/dev/null; then
|
||||
_info "No such txt recrod"
|
||||
return 0
|
||||
fi
|
||||
|
||||
count="$(echo "$response" | grep -o "content" | wc -l)"
|
||||
|
||||
if [ "$count" = "1" ]; then
|
||||
if ! _gcore_rest DELETE "zones/$_zone_name/$fulldomain/TXT"; then
|
||||
_err "Delete record error. $response"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
|
||||
payload="$(echo "$response" | tr -d " " | sed 's/"updated_at":[0-9]\+,//g' | sed 's/{"id":[0-9]\+,"content":\["'"$txtvalue"'"\],"enabled":true,"meta":{}}//' | sed 's/\[,/\[/' | sed 's/,,/,/' | sed 's/,\]/\]/')"
|
||||
if ! _gcore_rest PUT "zones/$_zone_name/$fulldomain/TXT" "$payload"; then
|
||||
_err "Delete record error. $response"
|
||||
fi
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#_acme-challenge.sub.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.sub or _acme-challenge
|
||||
# _domain=domain.com
|
||||
# _zone_name=domain.com or sub.domain.com
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=1
|
||||
p=1
|
||||
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _gcore_rest GET "zones/$h"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "\"name\":\"$h\""; then
|
||||
_zone_name=$h
|
||||
if [ "$_zone_name" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
_gcore_rest() {
|
||||
m=$1
|
||||
ep="$2"
|
||||
data="$3"
|
||||
_debug "$ep"
|
||||
|
||||
key_trimmed=$(echo "$GCORE_Key" | tr -d '"')
|
||||
|
||||
export _H1="Content-Type: application/json"
|
||||
export _H2="Authorization: APIKey $key_trimmed"
|
||||
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$GCORE_Api/$ep" "" "$m")"
|
||||
else
|
||||
response="$(_get "$GCORE_Api/$ep")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#Godaddy domain api
|
||||
# Get API key and secret from https://developer.godaddy.com/
|
||||
#
|
||||
#GD_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
# GD_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
# GD_Secret="asdfsdfsfsdfsdfdfsdf"
|
||||
#
|
||||
#GD_Secret="asdfsdfsfsdfsdfdfsdf"
|
||||
# Ex.: acme.sh --issue --staging --dns dns_gd -d "*.s.example.com" -d "s.example.com"
|
||||
|
||||
GD_Api="https://api.godaddy.com/v1"
|
||||
|
||||
@@ -20,8 +22,8 @@ dns_gd_add() {
|
||||
if [ -z "$GD_Key" ] || [ -z "$GD_Secret" ]; then
|
||||
GD_Key=""
|
||||
GD_Secret=""
|
||||
_err "You don't specify godaddy api key and secret yet."
|
||||
_err "Please create you key and try again."
|
||||
_err "You didn't specify godaddy api key and secret yet."
|
||||
_err "Please create your key and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
@@ -44,14 +46,15 @@ dns_gd_add() {
|
||||
fi
|
||||
|
||||
if _contains "$response" "$txtvalue"; then
|
||||
_info "The record is existing, skip"
|
||||
_info "This record already exists, skipping"
|
||||
return 0
|
||||
fi
|
||||
|
||||
_add_data="{\"data\":\"$txtvalue\"}"
|
||||
for t in $(echo "$response" | tr '{' "\n" | grep "\"name\":\"$_sub_domain\"" | tr ',' "\n" | grep '"data"' | cut -d : -f 2); do
|
||||
_debug2 t "$t"
|
||||
if [ "$t" ]; then
|
||||
# ignore empty (previously removed) records, to prevent useless _acme-challenge TXT entries
|
||||
if [ "$t" ] && [ "$t" != '""' ]; then
|
||||
_add_data="$_add_data,{\"data\":$t}"
|
||||
fi
|
||||
done
|
||||
@@ -59,13 +62,25 @@ dns_gd_add() {
|
||||
|
||||
_info "Adding record"
|
||||
if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]"; then
|
||||
_info "Added, sleeping 10 seconds"
|
||||
_sleep 10
|
||||
#todo: check if the record takes effect
|
||||
return 0
|
||||
_debug "Checking updated records of '${fulldomain}'"
|
||||
|
||||
if ! _gd_rest GET "domains/$_domain/records/TXT/$_sub_domain"; then
|
||||
_err "Validating TXT record for '${fulldomain}' with rest error [$?]." "$response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _contains "$response" "$txtvalue"; then
|
||||
_err "TXT record '${txtvalue}' for '${fulldomain}', value wasn't set!"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_err "Add txt record error, value '${txtvalue}' for '${fulldomain}' was not set."
|
||||
return 1
|
||||
fi
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
|
||||
_sleep 10
|
||||
_info "Added TXT record '${txtvalue}' for '${fulldomain}'."
|
||||
return 0
|
||||
}
|
||||
|
||||
#fulldomain
|
||||
@@ -107,11 +122,20 @@ dns_gd_rm() {
|
||||
fi
|
||||
done
|
||||
if [ -z "$_add_data" ]; then
|
||||
_add_data="{\"data\":\"\"}"
|
||||
# delete empty record
|
||||
_debug "Delete last record for '${fulldomain}'"
|
||||
if ! _gd_rest DELETE "domains/$_domain/records/TXT/$_sub_domain"; then
|
||||
_err "Cannot delete empty TXT record for '$fulldomain'"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
# remove specific TXT value, keeping other entries
|
||||
_debug2 _add_data "$_add_data"
|
||||
if ! _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]"; then
|
||||
_err "Cannot update TXT record for '$fulldomain'"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
_debug2 _add_data "$_add_data"
|
||||
|
||||
_gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]"
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
@@ -156,15 +180,15 @@ _gd_rest() {
|
||||
export _H1="Authorization: sso-key $GD_Key:$GD_Secret"
|
||||
export _H2="Content-Type: application/json"
|
||||
|
||||
if [ "$data" ]; then
|
||||
_debug data "$data"
|
||||
if [ "$data" ] || [ "$m" = "DELETE" ]; then
|
||||
_debug "data ($m): " "$data"
|
||||
response="$(_post "$data" "$GD_Api/$ep" "" "$m")"
|
||||
else
|
||||
response="$(_get "$GD_Api/$ep")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $ep"
|
||||
_err "error on rest call ($m): $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
|
||||
@@ -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
232
dnsapi/dns_geoscaling.sh
Executable 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:
|
||||
173
dnsapi/dns_googledomains.sh
Executable file
173
dnsapi/dns_googledomains.sh
Executable file
@@ -0,0 +1,173 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Author: Alex Leigh <leigh at alexleigh dot me>
|
||||
# Created: 2023-03-02
|
||||
|
||||
#GOOGLEDOMAINS_ACCESS_TOKEN="xxxx"
|
||||
#GOOGLEDOMAINS_ZONE="xxxx"
|
||||
GOOGLEDOMAINS_API="https://acmedns.googleapis.com/v1/acmeChallengeSets"
|
||||
|
||||
######## Public functions ########
|
||||
|
||||
#Usage: dns_googledomains_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_googledomains_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
_info "Invoking Google Domains ACME DNS API."
|
||||
|
||||
if ! _dns_googledomains_setup; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
zone="$(_dns_googledomains_get_zone "$fulldomain")"
|
||||
if [ -z "$zone" ]; then
|
||||
_err "Could not find a Google Domains-managed zone containing the requested domain."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug zone "$zone"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
_info "Adding TXT record for $fulldomain."
|
||||
if _dns_googledomains_api "$zone" ":rotateChallenges" "{\"accessToken\":\"$GOOGLEDOMAINS_ACCESS_TOKEN\",\"recordsToAdd\":[{\"fqdn\":\"$fulldomain\",\"digest\":\"$txtvalue\"}],\"keepExpiredRecords\":true}"; then
|
||||
if _contains "$response" "$txtvalue"; then
|
||||
_info "TXT record added."
|
||||
return 0
|
||||
else
|
||||
_err "Error adding TXT record."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
_err "Error adding TXT record."
|
||||
return 1
|
||||
}
|
||||
|
||||
#Usage: dns_googledomains_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_googledomains_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
_info "Invoking Google Domains ACME DNS API."
|
||||
|
||||
if ! _dns_googledomains_setup; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
zone="$(_dns_googledomains_get_zone "$fulldomain")"
|
||||
if [ -z "$zone" ]; then
|
||||
_err "Could not find a Google Domains-managed domain based on request."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug zone "$zone"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
_info "Removing TXT record for $fulldomain."
|
||||
if _dns_googledomains_api "$zone" ":rotateChallenges" "{\"accessToken\":\"$GOOGLEDOMAINS_ACCESS_TOKEN\",\"recordsToRemove\":[{\"fqdn\":\"$fulldomain\",\"digest\":\"$txtvalue\"}],\"keepExpiredRecords\":true}"; then
|
||||
if _contains "$response" "$txtvalue"; then
|
||||
_err "Error removing TXT record."
|
||||
return 1
|
||||
else
|
||||
_info "TXT record removed."
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
_err "Error removing TXT record."
|
||||
return 1
|
||||
}
|
||||
|
||||
######## Private functions ########
|
||||
|
||||
_dns_googledomains_setup() {
|
||||
if [ -n "$GOOGLEDOMAINS_SETUP_COMPLETED" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
GOOGLEDOMAINS_ACCESS_TOKEN="${GOOGLEDOMAINS_ACCESS_TOKEN:-$(_readaccountconf_mutable GOOGLEDOMAINS_ACCESS_TOKEN)}"
|
||||
GOOGLEDOMAINS_ZONE="${GOOGLEDOMAINS_ZONE:-$(_readaccountconf_mutable GOOGLEDOMAINS_ZONE)}"
|
||||
|
||||
if [ -z "$GOOGLEDOMAINS_ACCESS_TOKEN" ]; then
|
||||
GOOGLEDOMAINS_ACCESS_TOKEN=""
|
||||
_err "Google Domains access token was not specified."
|
||||
_err "Please visit Google Domains Security settings to provision an ACME DNS API access token."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$GOOGLEDOMAINS_ZONE" ]; then
|
||||
_savedomainconf GOOGLEDOMAINS_ACCESS_TOKEN "$GOOGLEDOMAINS_ACCESS_TOKEN"
|
||||
_savedomainconf GOOGLEDOMAINS_ZONE "$GOOGLEDOMAINS_ZONE"
|
||||
else
|
||||
_saveaccountconf_mutable GOOGLEDOMAINS_ACCESS_TOKEN "$GOOGLEDOMAINS_ACCESS_TOKEN"
|
||||
_clearaccountconf_mutable GOOGLEDOMAINS_ZONE
|
||||
_clearaccountconf GOOGLEDOMAINS_ZONE
|
||||
fi
|
||||
|
||||
_debug GOOGLEDOMAINS_ACCESS_TOKEN "$GOOGLEDOMAINS_ACCESS_TOKEN"
|
||||
_debug GOOGLEDOMAINS_ZONE "$GOOGLEDOMAINS_ZONE"
|
||||
|
||||
GOOGLEDOMAINS_SETUP_COMPLETED=1
|
||||
return 0
|
||||
}
|
||||
|
||||
_dns_googledomains_get_zone() {
|
||||
domain=$1
|
||||
|
||||
# Use zone directly if provided
|
||||
if [ "$GOOGLEDOMAINS_ZONE" ]; then
|
||||
if ! _dns_googledomains_api "$GOOGLEDOMAINS_ZONE"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "$GOOGLEDOMAINS_ZONE"
|
||||
return 0
|
||||
fi
|
||||
|
||||
i=2
|
||||
while true; do
|
||||
curr=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug curr "$curr"
|
||||
|
||||
if [ -z "$curr" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _dns_googledomains_api "$curr"; then
|
||||
echo "$curr"
|
||||
return 0
|
||||
fi
|
||||
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
_dns_googledomains_api() {
|
||||
zone=$1
|
||||
apimethod=$2
|
||||
data="$3"
|
||||
|
||||
if [ -z "$data" ]; then
|
||||
response="$(_get "$GOOGLEDOMAINS_API/$zone$apimethod")"
|
||||
else
|
||||
_debug data "$data"
|
||||
export _H1="Content-Type: application/json"
|
||||
response="$(_post "$data" "$GOOGLEDOMAINS_API/$zone$apimethod")"
|
||||
fi
|
||||
|
||||
_debug response "$response"
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "Error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "\"error\": {"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# HUAWEICLOUD_Username
|
||||
# HUAWEICLOUD_Password
|
||||
# HUAWEICLOUD_ProjectID
|
||||
# HUAWEICLOUD_DomainName
|
||||
|
||||
iam_api="https://iam.myhuaweicloud.com"
|
||||
dns_api="https://dns.ap-southeast-1.myhuaweicloud.com" # Should work
|
||||
@@ -14,6 +14,8 @@ dns_api="https://dns.ap-southeast-1.myhuaweicloud.com" # Should work
|
||||
#
|
||||
# Ref: https://support.huaweicloud.com/intl/zh-cn/api-dns/zh-cn_topic_0132421999.html
|
||||
#
|
||||
# About "DomainName" parameters see: https://support.huaweicloud.com/api-iam/iam_01_0006.html
|
||||
#
|
||||
|
||||
dns_huaweicloud_add() {
|
||||
fulldomain=$1
|
||||
@@ -21,16 +23,16 @@ dns_huaweicloud_add() {
|
||||
|
||||
HUAWEICLOUD_Username="${HUAWEICLOUD_Username:-$(_readaccountconf_mutable HUAWEICLOUD_Username)}"
|
||||
HUAWEICLOUD_Password="${HUAWEICLOUD_Password:-$(_readaccountconf_mutable HUAWEICLOUD_Password)}"
|
||||
HUAWEICLOUD_ProjectID="${HUAWEICLOUD_ProjectID:-$(_readaccountconf_mutable HUAWEICLOUD_ProjectID)}"
|
||||
HUAWEICLOUD_DomainName="${HUAWEICLOUD_DomainName:-$(_readaccountconf_mutable HUAWEICLOUD_DomainName)}"
|
||||
|
||||
# Check information
|
||||
if [ -z "${HUAWEICLOUD_Username}" ] || [ -z "${HUAWEICLOUD_Password}" ] || [ -z "${HUAWEICLOUD_ProjectID}" ]; then
|
||||
if [ -z "${HUAWEICLOUD_Username}" ] || [ -z "${HUAWEICLOUD_Password}" ] || [ -z "${HUAWEICLOUD_DomainName}" ]; then
|
||||
_err "Not enough information provided to dns_huaweicloud!"
|
||||
return 1
|
||||
fi
|
||||
|
||||
unset token # Clear token
|
||||
token="$(_get_token "${HUAWEICLOUD_Username}" "${HUAWEICLOUD_Password}" "${HUAWEICLOUD_ProjectID}")"
|
||||
token="$(_get_token "${HUAWEICLOUD_Username}" "${HUAWEICLOUD_Password}" "${HUAWEICLOUD_DomainName}")"
|
||||
if [ -z "${token}" ]; then # Check token
|
||||
_err "dns_api(dns_huaweicloud): Error getting token."
|
||||
return 1
|
||||
@@ -56,7 +58,7 @@ dns_huaweicloud_add() {
|
||||
# Do saving work if all succeeded
|
||||
_saveaccountconf_mutable HUAWEICLOUD_Username "${HUAWEICLOUD_Username}"
|
||||
_saveaccountconf_mutable HUAWEICLOUD_Password "${HUAWEICLOUD_Password}"
|
||||
_saveaccountconf_mutable HUAWEICLOUD_ProjectID "${HUAWEICLOUD_ProjectID}"
|
||||
_saveaccountconf_mutable HUAWEICLOUD_DomainName "${HUAWEICLOUD_DomainName}"
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -72,16 +74,16 @@ dns_huaweicloud_rm() {
|
||||
|
||||
HUAWEICLOUD_Username="${HUAWEICLOUD_Username:-$(_readaccountconf_mutable HUAWEICLOUD_Username)}"
|
||||
HUAWEICLOUD_Password="${HUAWEICLOUD_Password:-$(_readaccountconf_mutable HUAWEICLOUD_Password)}"
|
||||
HUAWEICLOUD_ProjectID="${HUAWEICLOUD_ProjectID:-$(_readaccountconf_mutable HUAWEICLOUD_ProjectID)}"
|
||||
HUAWEICLOUD_DomainName="${HUAWEICLOUD_DomainName:-$(_readaccountconf_mutable HUAWEICLOUD_DomainName)}"
|
||||
|
||||
# Check information
|
||||
if [ -z "${HUAWEICLOUD_Username}" ] || [ -z "${HUAWEICLOUD_Password}" ] || [ -z "${HUAWEICLOUD_ProjectID}" ]; then
|
||||
if [ -z "${HUAWEICLOUD_Username}" ] || [ -z "${HUAWEICLOUD_Password}" ] || [ -z "${HUAWEICLOUD_DomainName}" ]; then
|
||||
_err "Not enough information provided to dns_huaweicloud!"
|
||||
return 1
|
||||
fi
|
||||
|
||||
unset token # Clear token
|
||||
token="$(_get_token "${HUAWEICLOUD_Username}" "${HUAWEICLOUD_Password}" "${HUAWEICLOUD_ProjectID}")"
|
||||
token="$(_get_token "${HUAWEICLOUD_Username}" "${HUAWEICLOUD_Password}" "${HUAWEICLOUD_DomainName}")"
|
||||
if [ -z "${token}" ]; then # Check token
|
||||
_err "dns_api(dns_huaweicloud): Error getting token."
|
||||
return 1
|
||||
@@ -96,19 +98,59 @@ dns_huaweicloud_rm() {
|
||||
fi
|
||||
_debug "Zone ID is:" "${zoneid}"
|
||||
|
||||
# Remove all records
|
||||
# Therotically HuaweiCloud does not allow more than one record set
|
||||
# But remove them recurringly to increase robusty
|
||||
while [ "${record_id}" != "0" ]; do
|
||||
_debug "Removing Record"
|
||||
_rm_record "${token}" "${zoneid}" "${record_id}"
|
||||
record_id="$(_get_recordset_id "${token}" "${fulldomain}" "${zoneid}")"
|
||||
done
|
||||
record_id="$(_get_recordset_id "${token}" "${fulldomain}" "${zoneid}")"
|
||||
_recursive_rm_record "${token}" "${fulldomain}" "${zoneid}" "${record_id}"
|
||||
ret="$?"
|
||||
if [ "${ret}" != "0" ]; then
|
||||
_err "dns_api(dns_huaweicloud): Error removing record."
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
################### Private functions below ##################################
|
||||
|
||||
# _recursive_rm_record
|
||||
# remove all records from the record set
|
||||
#
|
||||
# _token=$1
|
||||
# _domain=$2
|
||||
# _zoneid=$3
|
||||
# _record_id=$4
|
||||
#
|
||||
# Returns 0 on success
|
||||
_recursive_rm_record() {
|
||||
_token=$1
|
||||
_domain=$2
|
||||
_zoneid=$3
|
||||
_record_id=$4
|
||||
|
||||
# Most likely to have problems will huaweicloud side if more than 50 attempts but still cannot fully remove the record set
|
||||
# Maybe can be removed manually in the dashboard
|
||||
_retry_cnt=50
|
||||
|
||||
# Remove all records
|
||||
# Therotically HuaweiCloud does not allow more than one record set
|
||||
# But remove them recurringly to increase robusty
|
||||
|
||||
while [ "${_record_id}" != "0" ] && [ "${_retry_cnt}" != "0" ]; do
|
||||
_debug "Removing Record"
|
||||
_retry_cnt=$((_retry_cnt - 1))
|
||||
_rm_record "${_token}" "${_zoneid}" "${_record_id}"
|
||||
_record_id="$(_get_recordset_id "${_token}" "${_domain}" "${_zoneid}")"
|
||||
_debug2 "Checking record exists: record_id=${_record_id}"
|
||||
done
|
||||
|
||||
# Check if retry count is reached
|
||||
if [ "${_retry_cnt}" = "0" ]; then
|
||||
_debug "Failed to remove record after 50 attempts, please try removing it manually in the dashboard"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# _get_zoneid
|
||||
#
|
||||
# _token=$1
|
||||
@@ -122,7 +164,7 @@ _get_zoneid() {
|
||||
|
||||
i=1
|
||||
while true; do
|
||||
h=$(printf "%s" "${_domain_string}" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "${_domain_string}" | cut -d . -f "$i"-100)
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
@@ -133,11 +175,11 @@ _get_zoneid() {
|
||||
if _contains "${response}" '"id"'; then
|
||||
zoneidlist=$(echo "${response}" | _egrep_o "\"id\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")
|
||||
zonenamelist=$(echo "${response}" | _egrep_o "\"name\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")
|
||||
_debug2 "Return Zone ID(s):" "${zoneidlist}"
|
||||
_debug2 "Return Zone Name(s):" "${zonenamelist}"
|
||||
_debug2 "Returned Zone ID(s):" "${zoneidlist}"
|
||||
_debug2 "Returned Zone Name(s):" "${zonenamelist}"
|
||||
zoneidnum=0
|
||||
zoneidcount=$(echo "${zoneidlist}" | grep -c '^')
|
||||
_debug "Retund Zone ID(s) Count:" "${zoneidcount}"
|
||||
_debug "Returned Zone ID(s) Count:" "${zoneidcount}"
|
||||
while [ "${zoneidnum}" -lt "${zoneidcount}" ]; do
|
||||
zoneidnum=$(_math "$zoneidnum" + 1)
|
||||
_zoneid=$(echo "${zoneidlist}" | sed -n "${zoneidnum}p")
|
||||
@@ -204,8 +246,7 @@ _add_record() {
|
||||
\"type\": \"TXT\",
|
||||
\"ttl\": 1,
|
||||
\"records\": [
|
||||
${_exist_record},
|
||||
\"\\\"${_txtvalue}\\\"\"
|
||||
${_exist_record},\"\\\"${_txtvalue}\\\"\"
|
||||
]
|
||||
}"
|
||||
fi
|
||||
@@ -213,19 +254,16 @@ _add_record() {
|
||||
_record_id="$(_get_recordset_id "${_token}" "${_domain}" "${zoneid}")"
|
||||
_debug "Record Set ID is:" "${_record_id}"
|
||||
|
||||
# Remove all records
|
||||
while [ "${_record_id}" != "0" ]; do
|
||||
_debug "Removing Record"
|
||||
_rm_record "${_token}" "${zoneid}" "${_record_id}"
|
||||
_record_id="$(_get_recordset_id "${_token}" "${_domain}" "${zoneid}")"
|
||||
done
|
||||
|
||||
# Add brand new records with all old and new records
|
||||
export _H2="Content-Type: application/json"
|
||||
export _H1="X-Auth-Token: ${_token}"
|
||||
|
||||
_debug2 "${_post_body}"
|
||||
_post "${_post_body}" "${dns_api}/v2/zones/${zoneid}/recordsets" >/dev/null
|
||||
if [ -z "${_exist_record}" ]; then
|
||||
_post "${_post_body}" "${dns_api}/v2/zones/${zoneid}/recordsets" >/dev/null
|
||||
else
|
||||
_post "${_post_body}" "${dns_api}/v2/zones/${zoneid}/recordsets/${_record_id}" false "PUT" >/dev/null
|
||||
fi
|
||||
_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")"
|
||||
if [ "$_code" != "202" ]; then
|
||||
_err "dns_huaweicloud: http code ${_code}"
|
||||
@@ -253,7 +291,7 @@ _rm_record() {
|
||||
_get_token() {
|
||||
_username=$1
|
||||
_password=$2
|
||||
_project=$3
|
||||
_domain_name=$3
|
||||
|
||||
_debug "Getting Token"
|
||||
body="{
|
||||
@@ -267,14 +305,14 @@ _get_token() {
|
||||
\"name\": \"${_username}\",
|
||||
\"password\": \"${_password}\",
|
||||
\"domain\": {
|
||||
\"name\": \"${_username}\"
|
||||
\"name\": \"${_domain_name}\"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
\"scope\": {
|
||||
\"project\": {
|
||||
\"id\": \"${_project}\"
|
||||
\"name\": \"ap-southeast-1\"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ dns_infomaniak_add() {
|
||||
domain_id=${zone_and_id#* }
|
||||
|
||||
# extract first part of domain
|
||||
key=${fulldomain%.$zone}
|
||||
key=${fulldomain%."$zone"}
|
||||
|
||||
_debug "zone:$zone id:$domain_id key:$key"
|
||||
|
||||
@@ -149,7 +149,7 @@ dns_infomaniak_rm() {
|
||||
domain_id=${zone_and_id#* }
|
||||
|
||||
# extract first part of domain
|
||||
key=${fulldomain%.$zone}
|
||||
key=${fulldomain%."$zone"}
|
||||
|
||||
_debug "zone:$zone id:$domain_id key:$key"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Supports IONOS DNS API Beta v1.0.0
|
||||
# Supports IONOS DNS API v1.0.1
|
||||
#
|
||||
# Usage:
|
||||
# Export IONOS_PREFIX and IONOS_SECRET before calling acme.sh:
|
||||
@@ -26,7 +26,7 @@ dns_ionos_add() {
|
||||
|
||||
_body="[{\"name\":\"$_sub_domain.$_domain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"ttl\":$IONOS_TXT_TTL,\"prio\":$IONOS_TXT_PRIO,\"disabled\":false}]"
|
||||
|
||||
if _ionos_rest POST "$IONOS_ROUTE_ZONES/$_zone_id/records" "$_body" && [ -z "$response" ]; then
|
||||
if _ionos_rest POST "$IONOS_ROUTE_ZONES/$_zone_id/records" "$_body" && [ "$_code" = "201" ]; then
|
||||
_info "TXT record has been created successfully."
|
||||
return 0
|
||||
fi
|
||||
@@ -47,7 +47,7 @@ dns_ionos_rm() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _ionos_rest DELETE "$IONOS_ROUTE_ZONES/$_zone_id/records/$_record_id" && [ -z "$response" ]; then
|
||||
if _ionos_rest DELETE "$IONOS_ROUTE_ZONES/$_zone_id/records/$_record_id" && [ "$_code" = "200" ]; then
|
||||
_info "TXT record has been deleted successfully."
|
||||
return 0
|
||||
fi
|
||||
@@ -85,7 +85,7 @@ _get_root() {
|
||||
p=1
|
||||
|
||||
if _ionos_rest GET "$IONOS_ROUTE_ZONES"; then
|
||||
response="$(echo "$response" | tr -d "\n")"
|
||||
_response="$(echo "$_response" | tr -d "\n")"
|
||||
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
@@ -93,7 +93,7 @@ _get_root() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
_zone="$(echo "$response" | _egrep_o "\"name\":\"$h\".*\}")"
|
||||
_zone="$(echo "$_response" | _egrep_o "\"name\":\"$h\".*\}")"
|
||||
if [ "$_zone" ]; then
|
||||
_zone_id=$(printf "%s\n" "$_zone" | _egrep_o "\"id\":\"[a-fA-F0-9\-]*\"" | _head_n 1 | cut -d : -f 2 | tr -d '\"')
|
||||
if [ "$_zone_id" ]; then
|
||||
@@ -120,9 +120,9 @@ _ionos_get_record() {
|
||||
txtrecord=$3
|
||||
|
||||
if _ionos_rest GET "$IONOS_ROUTE_ZONES/$zone_id?recordName=$fulldomain&recordType=TXT"; then
|
||||
response="$(echo "$response" | tr -d "\n")"
|
||||
_response="$(echo "$_response" | tr -d "\n")"
|
||||
|
||||
_record="$(echo "$response" | _egrep_o "\"name\":\"$fulldomain\"[^\}]*\"type\":\"TXT\"[^\}]*\"content\":\"\\\\\"$txtrecord\\\\\"\".*\}")"
|
||||
_record="$(echo "$_response" | _egrep_o "\"name\":\"$fulldomain\"[^\}]*\"type\":\"TXT\"[^\}]*\"content\":\"\\\\\"$txtrecord\\\\\"\".*\}")"
|
||||
if [ "$_record" ]; then
|
||||
_record_id=$(printf "%s\n" "$_record" | _egrep_o "\"id\":\"[a-fA-F0-9\-]*\"" | _head_n 1 | cut -d : -f 2 | tr -d '\"')
|
||||
|
||||
@@ -142,22 +142,30 @@ _ionos_rest() {
|
||||
|
||||
export _H1="X-API-Key: $IONOS_API_KEY"
|
||||
|
||||
# clear headers
|
||||
: >"$HTTP_HEADER"
|
||||
|
||||
if [ "$method" != "GET" ]; then
|
||||
export _H2="Accept: application/json"
|
||||
export _H3="Content-Type: application/json"
|
||||
|
||||
response="$(_post "$data" "$IONOS_API$route" "" "$method" "application/json")"
|
||||
_response="$(_post "$data" "$IONOS_API$route" "" "$method" "application/json")"
|
||||
else
|
||||
export _H2="Accept: */*"
|
||||
export _H3=
|
||||
response="$(_get "$IONOS_API$route")"
|
||||
|
||||
_response="$(_get "$IONOS_API$route")"
|
||||
fi
|
||||
|
||||
_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")"
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "Error $route: $response"
|
||||
_err "Error $route: $_response"
|
||||
return 1
|
||||
fi
|
||||
_debug2 "response" "$response"
|
||||
|
||||
_debug2 "_response" "$_response"
|
||||
_debug2 "_code" "$_code"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
157
dnsapi/dns_ipv64.sh
Executable file
157
dnsapi/dns_ipv64.sh
Executable file
@@ -0,0 +1,157 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#Created by Roman Lumetsberger, to use ipv64.net's API to add/remove text records
|
||||
#2022/11/29
|
||||
|
||||
# Pass credentials before "acme.sh --issue --dns dns_ipv64 ..."
|
||||
# --
|
||||
# export IPv64_Token="aaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
# --
|
||||
#
|
||||
|
||||
IPv64_API="https://ipv64.net/api"
|
||||
|
||||
######## Public functions ######################
|
||||
|
||||
#Usage: dns_ipv64_add _acme-challenge.domain.ipv64.net "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_ipv64_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
IPv64_Token="${IPv64_Token:-$(_readaccountconf_mutable IPv64_Token)}"
|
||||
if [ -z "$IPv64_Token" ]; then
|
||||
_err "You must export variable: IPv64_Token"
|
||||
_err "The API Key for your IPv64 account is necessary."
|
||||
_err "You can look it up in your IPv64 account."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Now save the credentials.
|
||||
_saveaccountconf_mutable IPv64_Token "$IPv64_Token"
|
||||
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain" "$fulldomain"
|
||||
return 1
|
||||
fi
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
# convert to lower case
|
||||
_domain="$(echo "$_domain" | _lower_case)"
|
||||
_sub_domain="$(echo "$_sub_domain" | _lower_case)"
|
||||
# Now add the TXT record
|
||||
_info "Trying to add TXT record"
|
||||
if _ipv64_rest "POST" "add_record=$_domain&praefix=$_sub_domain&type=TXT&content=$txtvalue"; then
|
||||
_info "TXT record has been successfully added."
|
||||
return 0
|
||||
else
|
||||
_err "Errors happened during adding the TXT record, response=$_response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
#Usage: fulldomain txtvalue
|
||||
#Usage: dns_ipv64_rm _acme-challenge.domain.ipv64.net "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
#Remove the txt record after validation.
|
||||
dns_ipv64_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
IPv64_Token="${IPv64_Token:-$(_readaccountconf_mutable IPv64_Token)}"
|
||||
if [ -z "$IPv64_Token" ]; then
|
||||
_err "You must export variable: IPv64_Token"
|
||||
_err "The API Key for your IPv64 account is necessary."
|
||||
_err "You can look it up in your IPv64 account."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain" "$fulldomain"
|
||||
return 1
|
||||
fi
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
# convert to lower case
|
||||
_domain="$(echo "$_domain" | _lower_case)"
|
||||
_sub_domain="$(echo "$_sub_domain" | _lower_case)"
|
||||
# Now delete the TXT record
|
||||
_info "Trying to delete TXT record"
|
||||
if _ipv64_rest "DELETE" "del_record=$_domain&praefix=$_sub_domain&type=TXT&content=$txtvalue"; then
|
||||
_info "TXT record has been successfully deleted."
|
||||
return 0
|
||||
else
|
||||
_err "Errors happened during deleting the TXT record, response=$_response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
_get_root() {
|
||||
domain="$1"
|
||||
i=1
|
||||
p=1
|
||||
|
||||
_ipv64_get "get_domains"
|
||||
domain_data=$_response
|
||||
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
#if _contains "$domain_data" "\""$h"\"\:"; then
|
||||
if _contains "$domain_data" "\"""$h""\"\:"; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||
_domain="$h"
|
||||
return 0
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
#send get request to api
|
||||
# $1 has to set the api-function
|
||||
_ipv64_get() {
|
||||
url="$IPv64_API?$1"
|
||||
export _H1="Authorization: Bearer $IPv64_Token"
|
||||
|
||||
_response=$(_get "$url")
|
||||
_response="$(echo "$_response" | _normalizeJson)"
|
||||
|
||||
if _contains "$_response" "429 Too Many Requests"; then
|
||||
_info "API throttled, sleeping to reset the limit"
|
||||
_sleep 10
|
||||
_response=$(_get "$url")
|
||||
_response="$(echo "$_response" | _normalizeJson)"
|
||||
fi
|
||||
}
|
||||
|
||||
_ipv64_rest() {
|
||||
url="$IPv64_API"
|
||||
export _H1="Authorization: Bearer $IPv64_Token"
|
||||
export _H2="Content-Type: application/x-www-form-urlencoded"
|
||||
_response=$(_post "$2" "$url" "" "$1")
|
||||
|
||||
if _contains "$_response" "429 Too Many Requests"; then
|
||||
_info "API throttled, sleeping to reset the limit"
|
||||
_sleep 10
|
||||
_response=$(_post "$2" "$url" "" "$1")
|
||||
fi
|
||||
|
||||
if ! _contains "$_response" "\"info\":\"success\""; then
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$_response"
|
||||
return 0
|
||||
}
|
||||
@@ -32,7 +32,11 @@ dns_ispconfig_rm() {
|
||||
#################### Private functions below ##################################
|
||||
|
||||
_ISPC_credentials() {
|
||||
if [ -z "${ISPC_User}" ] || [ -z "$ISPC_Password" ] || [ -z "${ISPC_Api}" ] || [ -n "${ISPC_Api_Insecure}" ]; then
|
||||
ISPC_User="${ISPC_User:-$(_readaccountconf_mutable ISPC_User)}"
|
||||
ISPC_Password="${ISPC_Password:-$(_readaccountconf_mutable ISPC_Password)}"
|
||||
ISPC_Api="${ISPC_Api:-$(_readaccountconf_mutable ISPC_Api)}"
|
||||
ISPC_Api_Insecure="${ISPC_Api_Insecure:-$(_readaccountconf_mutable ISPC_Api_Insecure)}"
|
||||
if [ -z "${ISPC_User}" ] || [ -z "${ISPC_Password}" ] || [ -z "${ISPC_Api}" ] || [ -z "${ISPC_Api_Insecure}" ]; then
|
||||
ISPC_User=""
|
||||
ISPC_Password=""
|
||||
ISPC_Api=""
|
||||
@@ -40,10 +44,10 @@ _ISPC_credentials() {
|
||||
_err "You haven't specified the ISPConfig Login data, URL and whether you want check the ISPC SSL cert. Please try again."
|
||||
return 1
|
||||
else
|
||||
_saveaccountconf ISPC_User "${ISPC_User}"
|
||||
_saveaccountconf ISPC_Password "${ISPC_Password}"
|
||||
_saveaccountconf ISPC_Api "${ISPC_Api}"
|
||||
_saveaccountconf ISPC_Api_Insecure "${ISPC_Api_Insecure}"
|
||||
_saveaccountconf_mutable ISPC_User "${ISPC_User}"
|
||||
_saveaccountconf_mutable ISPC_Password "${ISPC_Password}"
|
||||
_saveaccountconf_mutable ISPC_Api "${ISPC_Api}"
|
||||
_saveaccountconf_mutable ISPC_Api_Insecure "${ISPC_Api_Insecure}"
|
||||
# Set whether curl should use secure or insecure mode
|
||||
export HTTPS_INSECURE="${ISPC_Api_Insecure}"
|
||||
fi
|
||||
|
||||
@@ -5,51 +5,81 @@
|
||||
# Environment variables:
|
||||
#
|
||||
# - $KAS_Login (Kasserver API login name)
|
||||
# - $KAS_Authtype (Kasserver API auth type. Default: sha1)
|
||||
# - $KAS_Authtype (Kasserver API auth type. Default: plain)
|
||||
# - $KAS_Authdata (Kasserver API auth data.)
|
||||
#
|
||||
# Author: Martin Kammerlander, Phlegx Systems OG <martin.kammerlander@phlegx.com>
|
||||
# Updated by: Marc-Oliver Lange <git@die-lang.es>
|
||||
# Credits: Inspired by dns_he.sh. Thanks a lot man!
|
||||
# Git repo: https://github.com/phlegx/acme.sh
|
||||
# TODO: Better Error handling
|
||||
# Last update: squared GmbH <github@squaredgmbh.de>
|
||||
# Credits:
|
||||
# - dns_he.sh. Thanks a lot man!
|
||||
# - Martin Kammerlander, Phlegx Systems OG <martin.kammerlander@phlegx.com>
|
||||
# - Marc-Oliver Lange <git@die-lang.es>
|
||||
# - https://github.com/o1oo11oo/kasapi.sh
|
||||
########################################################################
|
||||
KAS_Api="https://kasapi.kasserver.com/dokumentation/formular.php"
|
||||
KAS_Api_GET="$(_get "https://kasapi.kasserver.com/soap/wsdl/KasApi.wsdl")"
|
||||
KAS_Api="$(echo "$KAS_Api_GET" | tr -d ' ' | grep -i "<soap:addresslocation=" | sed "s/='/\n/g" | grep -i "http" | sed "s/'\/>//g")"
|
||||
_info "[KAS] -> API URL $KAS_Api"
|
||||
|
||||
KAS_Auth_GET="$(_get "https://kasapi.kasserver.com/soap/wsdl/KasAuth.wsdl")"
|
||||
KAS_Auth="$(echo "$KAS_Auth_GET" | tr -d ' ' | grep -i "<soap:addresslocation=" | sed "s/='/\n/g" | grep -i "http" | sed "s/'\/>//g")"
|
||||
_info "[KAS] -> AUTH URL $KAS_Auth"
|
||||
|
||||
KAS_default_ratelimit=5 # TODO - Every response delivers a ratelimit (seconds) where KASAPI is blocking a request.
|
||||
|
||||
######## Public functions #####################
|
||||
dns_kas_add() {
|
||||
_fulldomain=$1
|
||||
_txtvalue=$2
|
||||
_info "Using DNS-01 All-inkl/Kasserver hook"
|
||||
_info "Adding $_fulldomain DNS TXT entry on All-inkl/Kasserver"
|
||||
_info "Check and Save Props"
|
||||
|
||||
_info "[KAS] -> Using DNS-01 All-inkl/Kasserver hook"
|
||||
_info "[KAS] -> Check and Save Props"
|
||||
_check_and_save
|
||||
_info "Checking Zone and Record_Name"
|
||||
|
||||
_info "[KAS] -> Adding $_fulldomain DNS TXT entry on all-inkl.com/Kasserver"
|
||||
_info "[KAS] -> Retriving Credential Token"
|
||||
_get_credential_token
|
||||
|
||||
_info "[KAS] -> Checking Zone and Record_Name"
|
||||
_get_zone_and_record_name "$_fulldomain"
|
||||
_info "Getting Record ID"
|
||||
|
||||
_info "[KAS] -> Checking for existing Record entries"
|
||||
_get_record_id
|
||||
|
||||
_info "Creating TXT DNS record"
|
||||
params="?kas_login=$KAS_Login"
|
||||
params="$params&kas_auth_type=$KAS_Authtype"
|
||||
params="$params&kas_auth_data=$KAS_Authdata"
|
||||
params="$params&var1=record_name"
|
||||
params="$params&wert1=$_record_name"
|
||||
params="$params&var2=record_type"
|
||||
params="$params&wert2=TXT"
|
||||
params="$params&var3=record_data"
|
||||
params="$params&wert3=$_txtvalue"
|
||||
params="$params&var4=record_aux"
|
||||
params="$params&wert4=0"
|
||||
params="$params&kas_action=add_dns_settings"
|
||||
params="$params&var5=zone_host"
|
||||
params="$params&wert5=$_zone"
|
||||
_debug2 "Wait for 10 seconds by default before calling KAS API."
|
||||
_sleep 10
|
||||
response="$(_get "$KAS_Api$params")"
|
||||
_debug2 "response" "$response"
|
||||
# If there is a record_id, delete the entry
|
||||
if [ -n "$_record_id" ]; then
|
||||
_info "[KAS] -> Existing records found. Now deleting old entries"
|
||||
for i in $_record_id; do
|
||||
_delete_RecordByID "$i"
|
||||
done
|
||||
else
|
||||
_info "[KAS] -> No record found."
|
||||
fi
|
||||
|
||||
if ! _contains "$response" "TRUE"; then
|
||||
_err "An unkown error occurred, please check manually."
|
||||
_info "[KAS] -> Creating TXT DNS record"
|
||||
action="add_dns_settings"
|
||||
kasReqParam="\"record_name\":\"$_record_name\""
|
||||
kasReqParam="$kasReqParam,\"record_type\":\"TXT\""
|
||||
kasReqParam="$kasReqParam,\"record_data\":\"$_txtvalue\""
|
||||
kasReqParam="$kasReqParam,\"record_aux\":\"0\""
|
||||
kasReqParam="$kasReqParam,\"zone_host\":\"$_zone\""
|
||||
response="$(_callAPI "$action" "$kasReqParam")"
|
||||
_debug2 "[KAS] -> Response" "$response"
|
||||
|
||||
if [ -z "$response" ]; then
|
||||
_info "[KAS] -> Response was empty, please check manually."
|
||||
return 1
|
||||
elif _contains "$response" "<SOAP-ENV:Fault>"; then
|
||||
faultstring="$(echo "$response" | tr -d '\n\r' | sed "s/<faultstring>/\n=> /g" | sed "s/<\/faultstring>/\n/g" | grep "=>" | sed "s/=> //g")"
|
||||
case "${faultstring}" in
|
||||
"record_already_exists")
|
||||
_info "[KAS] -> The record already exists, which must not be a problem. Please check manually."
|
||||
;;
|
||||
*)
|
||||
_err "[KAS] -> An error =>$faultstring<= occurred, please check manually."
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
elif ! _contains "$response" "<item><key xsi:type=\"xsd:string\">ReturnString</key><value xsi:type=\"xsd:string\">TRUE</value></item>"; then
|
||||
_err "[KAS] -> An unknown error occurred, please check manually."
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
@@ -58,45 +88,62 @@ dns_kas_add() {
|
||||
dns_kas_rm() {
|
||||
_fulldomain=$1
|
||||
_txtvalue=$2
|
||||
_info "Using DNS-01 All-inkl/Kasserver hook"
|
||||
_info "Cleaning up after All-inkl/Kasserver hook"
|
||||
_info "Removing $_fulldomain DNS TXT entry on All-inkl/Kasserver"
|
||||
|
||||
_info "Check and Save Props"
|
||||
_info "[KAS] -> Using DNS-01 All-inkl/Kasserver hook"
|
||||
_info "[KAS] -> Check and Save Props"
|
||||
_check_and_save
|
||||
_info "Checking Zone and Record_Name"
|
||||
|
||||
_info "[KAS] -> Cleaning up after All-inkl/Kasserver hook"
|
||||
_info "[KAS] -> Removing $_fulldomain DNS TXT entry on All-inkl/Kasserver"
|
||||
_info "[KAS] -> Retriving Credential Token"
|
||||
_get_credential_token
|
||||
|
||||
_info "[KAS] -> Checking Zone and Record_Name"
|
||||
_get_zone_and_record_name "$_fulldomain"
|
||||
_info "Getting Record ID"
|
||||
|
||||
_info "[KAS] -> Getting Record ID"
|
||||
_get_record_id
|
||||
|
||||
_info "[KAS] -> Removing entries with ID: $_record_id"
|
||||
# If there is a record_id, delete the entry
|
||||
if [ -n "$_record_id" ]; then
|
||||
params="?kas_login=$KAS_Login"
|
||||
params="$params&kas_auth_type=$KAS_Authtype"
|
||||
params="$params&kas_auth_data=$KAS_Authdata"
|
||||
params="$params&kas_action=delete_dns_settings"
|
||||
|
||||
for i in $_record_id; do
|
||||
params2="$params&var1=record_id"
|
||||
params2="$params2&wert1=$i"
|
||||
_debug2 "Wait for 10 seconds by default before calling KAS API."
|
||||
_sleep 10
|
||||
response="$(_get "$KAS_Api$params2")"
|
||||
_debug2 "response" "$response"
|
||||
if ! _contains "$response" "TRUE"; then
|
||||
_err "Either the txt record is not found or another error occurred, please check manually."
|
||||
return 1
|
||||
fi
|
||||
_delete_RecordByID "$i"
|
||||
done
|
||||
else # Cannot delete or unkown error
|
||||
_err "No record_id found that can be deleted. Please check manually."
|
||||
return 1
|
||||
_info "[KAS] -> No record_id found that can be deleted. Please check manually."
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
########################## PRIVATE FUNCTIONS ###########################
|
||||
# Delete Record ID
|
||||
_delete_RecordByID() {
|
||||
recId=$1
|
||||
action="delete_dns_settings"
|
||||
kasReqParam="\"record_id\":\"$recId\""
|
||||
response="$(_callAPI "$action" "$kasReqParam")"
|
||||
_debug2 "[KAS] -> Response" "$response"
|
||||
|
||||
if [ -z "$response" ]; then
|
||||
_info "[KAS] -> Response was empty, please check manually."
|
||||
return 1
|
||||
elif _contains "$response" "<SOAP-ENV:Fault>"; then
|
||||
faultstring="$(echo "$response" | tr -d '\n\r' | sed "s/<faultstring>/\n=> /g" | sed "s/<\/faultstring>/\n/g" | grep "=>" | sed "s/=> //g")"
|
||||
case "${faultstring}" in
|
||||
"record_id_not_found")
|
||||
_info "[KAS] -> The record was not found, which perhaps is not a problem. Please check manually."
|
||||
;;
|
||||
*)
|
||||
_err "[KAS] -> An error =>$faultstring<= occurred, please check manually."
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
elif ! _contains "$response" "<item><key xsi:type=\"xsd:string\">ReturnString</key><value xsi:type=\"xsd:string\">TRUE</value></item>"; then
|
||||
_err "[KAS] -> An unknown error occurred, please check manually."
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
# Checks for the ENV variables and saves them
|
||||
_check_and_save() {
|
||||
KAS_Login="${KAS_Login:-$(_readaccountconf_mutable KAS_Login)}"
|
||||
@@ -107,7 +154,7 @@ _check_and_save() {
|
||||
KAS_Login=
|
||||
KAS_Authtype=
|
||||
KAS_Authdata=
|
||||
_err "No auth details provided. Please set user credentials using the \$KAS_Login, \$KAS_Authtype, and \$KAS_Authdata environment variables."
|
||||
_err "[KAS] -> No auth details provided. Please set user credentials using the \$KAS_Login, \$KAS_Authtype, and \$KAS_Authdata environment variables."
|
||||
return 1
|
||||
fi
|
||||
_saveaccountconf_mutable KAS_Login "$KAS_Login"
|
||||
@@ -119,50 +166,116 @@ _check_and_save() {
|
||||
# Gets back the base domain/zone and record name.
|
||||
# See: https://github.com/Neilpang/acme.sh/wiki/DNS-API-Dev-Guide
|
||||
_get_zone_and_record_name() {
|
||||
params="?kas_login=$KAS_Login"
|
||||
params="?kas_login=$KAS_Login"
|
||||
params="$params&kas_auth_type=$KAS_Authtype"
|
||||
params="$params&kas_auth_data=$KAS_Authdata"
|
||||
params="$params&kas_action=get_domains"
|
||||
action="get_domains"
|
||||
response="$(_callAPI "$action")"
|
||||
_debug2 "[KAS] -> Response" "$response"
|
||||
|
||||
_debug2 "Wait for 10 seconds by default before calling KAS API."
|
||||
_sleep 10
|
||||
response="$(_get "$KAS_Api$params")"
|
||||
_debug2 "response" "$response"
|
||||
_zonen="$(echo "$response" | tr -d "\n\r" | tr -d " " | tr '[]' '<>' | sed "s/=>Array/\n=> Array/g" | tr ' ' '\n' | grep "domain_name" | tr '<' '\n' | grep "domain_name" | sed "s/domain_name>=>//g")"
|
||||
_domain="$1"
|
||||
_temp_domain="$(echo "$1" | sed 's/\.$//')"
|
||||
_rootzone="$_domain"
|
||||
for i in $_zonen; do
|
||||
l1=${#_rootzone}
|
||||
if [ -z "$response" ]; then
|
||||
_info "[KAS] -> Response was empty, please check manually."
|
||||
return 1
|
||||
elif _contains "$response" "<SOAP-ENV:Fault>"; then
|
||||
faultstring="$(echo "$response" | tr -d '\n\r' | sed "s/<faultstring>/\n=> /g" | sed "s/<\/faultstring>/\n/g" | grep "=>" | sed "s/=> //g")"
|
||||
_err "[KAS] -> Either no domains were found or another error =>$faultstring<= occurred, please check manually."
|
||||
return 1
|
||||
fi
|
||||
|
||||
zonen="$(echo "$response" | sed 's/<item>/\n/g' | sed -r 's/(.*<key xsi:type="xsd:string">domain_name<\/key><value xsi:type="xsd:string">)(.*)(<\/value.*)/\2/' | sed '/^</d')"
|
||||
domain="$1"
|
||||
temp_domain="$(echo "$1" | sed 's/\.$//')"
|
||||
rootzone="$domain"
|
||||
for i in $zonen; do
|
||||
l1=${#rootzone}
|
||||
l2=${#i}
|
||||
if _endswith "$_domain" "$i" && [ "$l1" -ge "$l2" ]; then
|
||||
_rootzone="$i"
|
||||
if _endswith "$domain" "$i" && [ "$l1" -ge "$l2" ]; then
|
||||
rootzone="$i"
|
||||
fi
|
||||
done
|
||||
_zone="${_rootzone}."
|
||||
_temp_record_name="$(echo "$_temp_domain" | sed "s/$_rootzone//g")"
|
||||
_record_name="$(echo "$_temp_record_name" | sed 's/\.$//')"
|
||||
_debug2 "Zone:" "$_zone"
|
||||
_debug2 "Domain:" "$_domain"
|
||||
_debug2 "Record_Name:" "$_record_name"
|
||||
_zone="${rootzone}."
|
||||
temp_record_name="$(echo "$temp_domain" | sed "s/$rootzone//g")"
|
||||
_record_name="$(echo "$temp_record_name" | sed 's/\.$//')"
|
||||
_debug "[KAS] -> Zone:" "$_zone"
|
||||
_debug "[KAS] -> Domain:" "$domain"
|
||||
_debug "[KAS] -> Record_Name:" "$_record_name"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Retrieve the DNS record ID
|
||||
_get_record_id() {
|
||||
params="?kas_login=$KAS_Login"
|
||||
params="$params&kas_auth_type=$KAS_Authtype"
|
||||
params="$params&kas_auth_data=$KAS_Authdata"
|
||||
params="$params&kas_action=get_dns_settings"
|
||||
params="$params&var1=zone_host"
|
||||
params="$params&wert1=$_zone"
|
||||
action="get_dns_settings"
|
||||
kasReqParam="\"zone_host\":\"$_zone\""
|
||||
response="$(_callAPI "$action" "$kasReqParam")"
|
||||
_debug2 "[KAS] -> Response" "$response"
|
||||
|
||||
_debug2 "Wait for 10 seconds by default before calling KAS API."
|
||||
_sleep 10
|
||||
response="$(_get "$KAS_Api$params")"
|
||||
_debug2 "response" "$response"
|
||||
_record_id="$(echo "$response" | tr -d "\n\r" | tr -d " " | tr '[]' '<>' | sed "s/=>Array/\n=> Array/g" | tr ' ' '\n' | grep "=>$_record_name<" | grep '>TXT<' | tr '<' '\n' | grep record_id | sed "s/record_id>=>//g")"
|
||||
_debug2 _record_id "$_record_id"
|
||||
if [ -z "$response" ]; then
|
||||
_info "[KAS] -> Response was empty, please check manually."
|
||||
return 1
|
||||
elif _contains "$response" "<SOAP-ENV:Fault>"; then
|
||||
faultstring="$(echo "$response" | tr -d '\n\r' | sed "s/<faultstring>/\n=> /g" | sed "s/<\/faultstring>/\n/g" | grep "=>" | sed "s/=> //g")"
|
||||
_err "[KAS] -> Either no domains were found or another error =>$faultstring<= occurred, please check manually."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_record_id="$(echo "$response" | tr -d '\n\r' | sed "s/<item xsi:type=\"ns2:Map\">/\n/g" | grep -i "$_record_name" | grep -i ">TXT<" | sed "s/<item><key xsi:type=\"xsd:string\">record_id<\/key><value xsi:type=\"xsd:string\">/=>/g" | grep -i "$_txtvalue" | sed "s/<\/value><\/item>/\n/g" | grep "=>" | sed "s/=>//g")"
|
||||
_debug "[KAS] -> Record Id: " "$_record_id"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Retrieve credential token
|
||||
_get_credential_token() {
|
||||
baseParamAuth="\"kas_login\":\"$KAS_Login\""
|
||||
baseParamAuth="$baseParamAuth,\"kas_auth_type\":\"$KAS_Authtype\""
|
||||
baseParamAuth="$baseParamAuth,\"kas_auth_data\":\"$KAS_Authdata\""
|
||||
baseParamAuth="$baseParamAuth,\"session_lifetime\":600"
|
||||
baseParamAuth="$baseParamAuth,\"session_update_lifetime\":\"Y\""
|
||||
|
||||
data='<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:xmethodsKasApiAuthentication" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:KasAuth><Params xsi:type="xsd:string">{'
|
||||
data="$data$baseParamAuth}</Params></ns1:KasAuth></SOAP-ENV:Body></SOAP-ENV:Envelope>"
|
||||
|
||||
_debug "[KAS] -> Be friendly and wait $KAS_default_ratelimit seconds by default before calling KAS API."
|
||||
_sleep $KAS_default_ratelimit
|
||||
|
||||
contentType="text/xml"
|
||||
export _H1="SOAPAction: urn:xmethodsKasApiAuthentication#KasAuth"
|
||||
response="$(_post "$data" "$KAS_Auth" "" "POST" "$contentType")"
|
||||
_debug2 "[KAS] -> Response" "$response"
|
||||
|
||||
if [ -z "$response" ]; then
|
||||
_info "[KAS] -> Response was empty, please check manually."
|
||||
return 1
|
||||
elif _contains "$response" "<SOAP-ENV:Fault>"; then
|
||||
faultstring="$(echo "$response" | tr -d '\n\r' | sed "s/<faultstring>/\n=> /g" | sed "s/<\/faultstring>/\n/g" | grep "=>" | sed "s/=> //g")"
|
||||
_err "[KAS] -> Could not retrieve login token or antoher error =>$faultstring<= occurred, please check manually."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_credential_token="$(echo "$response" | tr '\n' ' ' | sed 's/.*return xsi:type="xsd:string">\(.*\)<\/return>/\1/' | sed 's/<\/ns1:KasAuthResponse\(.*\)Envelope>.*//')"
|
||||
_debug "[KAS] -> Credential Token: " "$_credential_token"
|
||||
return 0
|
||||
}
|
||||
|
||||
_callAPI() {
|
||||
kasaction=$1
|
||||
kasReqParams=$2
|
||||
|
||||
baseParamAuth="\"kas_login\":\"$KAS_Login\""
|
||||
baseParamAuth="$baseParamAuth,\"kas_auth_type\":\"session\""
|
||||
baseParamAuth="$baseParamAuth,\"kas_auth_data\":\"$_credential_token\""
|
||||
|
||||
data='<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:xmethodsKasApi" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:KasApi><Params xsi:type="xsd:string">{'
|
||||
data="$data$baseParamAuth,\"kas_action\":\"$kasaction\""
|
||||
if [ -n "$kasReqParams" ]; then
|
||||
data="$data,\"KasRequestParams\":{$kasReqParams}"
|
||||
fi
|
||||
data="$data}</Params></ns1:KasApi></SOAP-ENV:Body></SOAP-ENV:Envelope>"
|
||||
|
||||
_debug2 "[KAS] -> Request" "$data"
|
||||
|
||||
_debug "[KAS] -> Be friendly and wait $KAS_default_ratelimit seconds by default before calling KAS API."
|
||||
_sleep $KAS_default_ratelimit
|
||||
|
||||
contentType="text/xml"
|
||||
export _H1="SOAPAction: urn:xmethodsKasApi#KasApi"
|
||||
response="$(_post "$data" "$KAS_Api" "" "POST" "$contentType")"
|
||||
_debug2 "[KAS] -> Response" "$response"
|
||||
echo "$response"
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
############################################################
|
||||
# KingHost API support #
|
||||
# http://api.kinghost.net/doc/ #
|
||||
# https://api.kinghost.net/doc/ #
|
||||
# #
|
||||
# Author: Felipe Keller Braz <felipebraz@kinghost.com.br> #
|
||||
# Report Bugs here: https://github.com/kinghost/acme.sh #
|
||||
|
||||
147
dnsapi/dns_la.sh
Normal file
147
dnsapi/dns_la.sh
Normal file
@@ -0,0 +1,147 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#LA_Id="test123"
|
||||
#LA_Key="d1j2fdo4dee3948"
|
||||
|
||||
LA_Api="https://api.dns.la/api"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: dns_la_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_la_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
LA_Id="${LA_Id:-$(_readaccountconf_mutable LA_Id)}"
|
||||
LA_Key="${LA_Key:-$(_readaccountconf_mutable LA_Key)}"
|
||||
|
||||
if [ -z "$LA_Id" ] || [ -z "$LA_Key" ]; then
|
||||
LA_Id=""
|
||||
LA_Key=""
|
||||
_err "You didn't specify a dnsla api id and key yet."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the api key and email to the account conf file.
|
||||
_saveaccountconf_mutable LA_Id "$LA_Id"
|
||||
_saveaccountconf_mutable LA_Key "$LA_Key"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_info "Adding record"
|
||||
if _la_rest "record.ashx?cmd=create&apiid=$LA_Id&apipass=$LA_Key&rtype=json&domainid=$_domain_id&host=$_sub_domain&recordtype=TXT&recorddata=$txtvalue&recordline="; then
|
||||
if _contains "$response" '"resultid":'; then
|
||||
_info "Added, OK"
|
||||
return 0
|
||||
elif _contains "$response" '"code":532'; then
|
||||
_info "Already exists, OK"
|
||||
return 0
|
||||
else
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
|
||||
}
|
||||
|
||||
#fulldomain txtvalue
|
||||
dns_la_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
LA_Id="${LA_Id:-$(_readaccountconf_mutable LA_Id)}"
|
||||
LA_Key="${LA_Key:-$(_readaccountconf_mutable LA_Key)}"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_debug "Getting txt records"
|
||||
if ! _la_rest "record.ashx?cmd=listn&apiid=$LA_Id&apipass=$LA_Key&rtype=json&domainid=$_domain_id&domain=$_domain&host=$_sub_domain&recordtype=TXT&recorddata=$txtvalue"; then
|
||||
_err "Error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _contains "$response" '"recordid":'; then
|
||||
_info "Don't need to remove."
|
||||
return 0
|
||||
fi
|
||||
|
||||
record_id=$(printf "%s" "$response" | grep '"recordid":' | cut -d : -f 2 | cut -d , -f 1 | tr -d '\r' | tr -d '\n')
|
||||
_debug "record_id" "$record_id"
|
||||
if [ -z "$record_id" ]; then
|
||||
_err "Can not get record id to remove."
|
||||
return 1
|
||||
fi
|
||||
if ! _la_rest "record.ashx?cmd=remove&apiid=$LA_Id&apipass=$LA_Key&rtype=json&domainid=$_domain_id&domain=$_domain&recordid=$record_id"; then
|
||||
_err "Delete record error."
|
||||
return 1
|
||||
fi
|
||||
_contains "$response" '"code":300'
|
||||
|
||||
}
|
||||
|
||||
#################### 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=1
|
||||
p=1
|
||||
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _la_rest "domain.ashx?cmd=get&apiid=$LA_Id&apipass=$LA_Key&rtype=json&domain=$h"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" '"domainid":'; then
|
||||
_domain_id=$(printf "%s" "$response" | grep '"domainid":' | cut -d : -f 2 | cut -d , -f 1 | tr -d '\r' | tr -d '\n')
|
||||
if [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain="$h"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
p="$i"
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
#Usage: URI
|
||||
_la_rest() {
|
||||
url="$LA_Api/$1"
|
||||
_debug "$url"
|
||||
|
||||
if ! response="$(_get "$url" | tr -d ' ' | tr "}" ",")"; then
|
||||
_err "Error: $url"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
@@ -3,10 +3,10 @@
|
||||
#Author: Rolph Haspers <r.haspers@global.leaseweb.com>
|
||||
#Utilize leaseweb.com API to finish dns-01 verifications.
|
||||
#Requires a Leaseweb API Key (export LSW_Key="Your Key")
|
||||
#See http://developer.leaseweb.com for more information.
|
||||
#See https://developer.leaseweb.com for more information.
|
||||
######## Public functions #####################
|
||||
|
||||
LSW_API="https://api.leaseweb.com/hosting/v2/domains/"
|
||||
LSW_API="https://api.leaseweb.com/hosting/v2/domains"
|
||||
|
||||
#Usage: dns_leaseweb_add _acme-challenge.www.domain.com
|
||||
dns_leaseweb_add() {
|
||||
|
||||
@@ -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/&/\&/')
|
||||
encoded_string=$(echo "$encoded_string" | sed 's/</\</')
|
||||
encoded_string=$(echo "$encoded_string" | sed 's/>/\>/')
|
||||
printf "%s" "$encoded_string"
|
||||
}
|
||||
|
||||
@@ -163,6 +163,7 @@ _retrieve_miab_env() {
|
||||
_saveaccountconf_mutable MIAB_Username "$MIAB_Username"
|
||||
_saveaccountconf_mutable MIAB_Password "$MIAB_Password"
|
||||
_saveaccountconf_mutable MIAB_Server "$MIAB_Server"
|
||||
return 0
|
||||
}
|
||||
|
||||
#Useage: _miab_rest "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" "custom/_acme-challenge.www.domain.com/txt "POST"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -150,7 +150,7 @@ _get_root() {
|
||||
_mydnsjp_retrieve_domain() {
|
||||
_debug "Login to MyDNS.JP"
|
||||
|
||||
response="$(_post "masterid=$MYDNSJP_MasterID&masterpwd=$MYDNSJP_Password" "$MYDNSJP_API/?MENU=100")"
|
||||
response="$(_post "MENU=100&masterid=$MYDNSJP_MasterID&masterpwd=$MYDNSJP_Password" "$MYDNSJP_API/members/")"
|
||||
cookie="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2)"
|
||||
|
||||
# If cookies is not empty then logon successful
|
||||
@@ -159,22 +159,8 @@ _mydnsjp_retrieve_domain() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "Retrieve DOMAIN INFO page"
|
||||
|
||||
export _H1="Cookie:${cookie}"
|
||||
|
||||
response="$(_get "$MYDNSJP_API/?MENU=300")"
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "Fail to retrieve DOMAIN INFO."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_root_domain=$(echo "$response" | grep "DNSINFO\[domainname\]" | sed 's/^.*value="\([^"]*\)".*/\1/')
|
||||
|
||||
# Logout
|
||||
response="$(_get "$MYDNSJP_API/?MENU=090")"
|
||||
|
||||
_debug _root_domain "$_root_domain"
|
||||
|
||||
if [ -z "$_root_domain" ]; then
|
||||
|
||||
@@ -82,7 +82,7 @@ _get_root() {
|
||||
_debug "Failed domain lookup via domains.getList api call. Trying domain lookup via domains.dns.getHosts api."
|
||||
# The above "getList" api will only return hosts *owned* by the calling user. However, if the calling
|
||||
# user is not the owner, but still has administrative rights, we must query the getHosts api directly.
|
||||
# See this comment and the official namecheap response: http://disq.us/p/1q6v9x9
|
||||
# See this comment and the official namecheap response: https://disq.us/p/1q6v9x9
|
||||
if ! _get_root_by_getHosts "$fulldomain"; then
|
||||
return 1
|
||||
fi
|
||||
@@ -259,7 +259,7 @@ _set_namecheap_TXT() {
|
||||
_debug hosts "$hosts"
|
||||
|
||||
if [ -z "$hosts" ]; then
|
||||
_error "Hosts not found"
|
||||
_err "Hosts not found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
@@ -313,7 +313,7 @@ _del_namecheap_TXT() {
|
||||
_debug hosts "$hosts"
|
||||
|
||||
if [ -z "$hosts" ]; then
|
||||
_error "Hosts not found"
|
||||
_err "Hosts not found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ _get_root() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "<domain>$host"; then
|
||||
if _contains "$response" ">$host</domain>"; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain="$host"
|
||||
return 0
|
||||
|
||||
59
dnsapi/dns_nanelo.sh
Normal file
59
dnsapi/dns_nanelo.sh
Normal file
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Official DNS API for Nanelo.com
|
||||
|
||||
# Provide the required API Key like this:
|
||||
# NANELO_TOKEN="FmD408PdqT1E269gUK57"
|
||||
|
||||
NANELO_API="https://api.nanelo.com/v1/"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_nanelo_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
NANELO_TOKEN="${NANELO_TOKEN:-$(_readaccountconf_mutable NANELO_TOKEN)}"
|
||||
if [ -z "$NANELO_TOKEN" ]; then
|
||||
NANELO_TOKEN=""
|
||||
_err "You didn't configure a Nanelo API Key yet."
|
||||
_err "Please set NANELO_TOKEN and try again."
|
||||
_err "Login to Nanelo.com and go to Settings > API Keys to get a Key"
|
||||
return 1
|
||||
fi
|
||||
_saveaccountconf_mutable NANELO_TOKEN "$NANELO_TOKEN"
|
||||
|
||||
_info "Adding TXT record to ${fulldomain}"
|
||||
response="$(_get "$NANELO_API$NANELO_TOKEN/dns/addrecord?type=TXT&ttl=60&name=${fulldomain}&value=${txtvalue}")"
|
||||
if _contains "${response}" 'success'; then
|
||||
return 0
|
||||
fi
|
||||
_err "Could not create resource record, please check the logs"
|
||||
_err "${response}"
|
||||
return 1
|
||||
}
|
||||
|
||||
dns_nanelo_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
NANELO_TOKEN="${NANELO_TOKEN:-$(_readaccountconf_mutable NANELO_TOKEN)}"
|
||||
if [ -z "$NANELO_TOKEN" ]; then
|
||||
NANELO_TOKEN=""
|
||||
_err "You didn't configure a Nanelo API Key yet."
|
||||
_err "Please set NANELO_TOKEN and try again."
|
||||
_err "Login to Nanelo.com and go to Settings > API Keys to get a Key"
|
||||
return 1
|
||||
fi
|
||||
_saveaccountconf_mutable NANELO_TOKEN "$NANELO_TOKEN"
|
||||
|
||||
_info "Deleting resource record $fulldomain"
|
||||
response="$(_get "$NANELO_API$NANELO_TOKEN/dns/deleterecord?type=TXT&ttl=60&name=${fulldomain}&value=${txtvalue}")"
|
||||
if _contains "${response}" 'success'; then
|
||||
return 0
|
||||
fi
|
||||
_err "Could not delete resource record, please check the logs"
|
||||
_err "${response}"
|
||||
return 1
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#NederHost_Key="sdfgikogfdfghjklkjhgfcdcfghjk"
|
||||
#NederHost_Key="sdfgikogfdfghjklkjhgfcdcfghj"
|
||||
|
||||
NederHost_Api="https://api.nederhost.nl/dns/v1"
|
||||
|
||||
@@ -112,12 +112,8 @@ _nederhost_rest() {
|
||||
export _H1="Authorization: Bearer $NederHost_Key"
|
||||
export _H2="Content-Type: application/json"
|
||||
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$NederHost_Api/$ep" "" "$m")"
|
||||
else
|
||||
response="$(_get "$NederHost_Api/$ep")"
|
||||
fi
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$NederHost_Api/$ep" "" "$m")"
|
||||
|
||||
_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")"
|
||||
_debug "http response code $_code"
|
||||
|
||||
@@ -18,15 +18,15 @@ dns_netlify_add() {
|
||||
NETLIFY_ACCESS_TOKEN=""
|
||||
_err "Please specify your Netlify Access Token and try again."
|
||||
return 1
|
||||
else
|
||||
_saveaccountconf_mutable NETLIFY_ACCESS_TOKEN "$NETLIFY_ACCESS_TOKEN"
|
||||
fi
|
||||
|
||||
_info "Using Netlify"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
_saveaccountconf_mutable NETLIFY_ACCESS_TOKEN "$NETLIFY_ACCESS_TOKEN"
|
||||
|
||||
if ! _get_root "$fulldomain" "$accesstoken"; then
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
@@ -62,9 +62,9 @@ dns_netlify_rm() {
|
||||
_debug txtdomain "$txtdomain"
|
||||
_debug txt "$txt"
|
||||
|
||||
_saveaccountconf_mutable NETLIFY_ACCESS_TOKEN "$NETLIFY_ACCESS_TOKEN"
|
||||
NETLIFY_ACCESS_TOKEN="${NETLIFY_ACCESS_TOKEN:-$(_readaccountconf_mutable NETLIFY_ACCESS_TOKEN)}"
|
||||
|
||||
if ! _get_root "$txtdomain" "$accesstoken"; then
|
||||
if ! _get_root "$txtdomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
@@ -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
|
||||
|
||||
@@ -159,7 +159,7 @@ _oci_config() {
|
||||
fi
|
||||
|
||||
if [ "$(printf "%s\n" "$OCI_CLI_KEY" | wc -l)" -eq 1 ]; then
|
||||
OCI_CLI_KEY=$(printf "%s" "$OCI_CLI_KEY" | _dbase64 multiline)
|
||||
OCI_CLI_KEY=$(printf "%s" "$OCI_CLI_KEY" | _dbase64)
|
||||
fi
|
||||
|
||||
return 0
|
||||
@@ -265,6 +265,7 @@ _signed_request() {
|
||||
_response="$(_get "https://${_sig_host}${_sig_target}")"
|
||||
elif [ "$_curl_method" = "PATCH" ]; then
|
||||
export _H1="$_date_header"
|
||||
# shellcheck disable=SC2090
|
||||
export _H2="$_sig_body_sha256"
|
||||
export _H3="$_sig_body_type"
|
||||
export _H4="$_sig_body_length"
|
||||
|
||||
@@ -57,16 +57,16 @@ _dns_openstack_create_recordset() {
|
||||
|
||||
if [ -z "$_recordset_id" ]; then
|
||||
_info "Creating a new recordset"
|
||||
if ! _recordset_id=$(openstack recordset create -c id -f value --type TXT --record "$txtvalue" "$_zone_id" "$fulldomain."); then
|
||||
if ! _recordset_id=$(openstack recordset create -c id -f value --type TXT --record="$txtvalue" "$_zone_id" "$fulldomain."); then
|
||||
_err "No recordset ID found after create"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_info "Updating existing recordset"
|
||||
# Build new list of --record <rec> args for update
|
||||
_record_args="--record $txtvalue"
|
||||
# Build new list of --record=<rec> args for update
|
||||
_record_args="--record=$txtvalue"
|
||||
for _rec in $_records; do
|
||||
_record_args="$_record_args --record $_rec"
|
||||
_record_args="$_record_args --record=$_rec"
|
||||
done
|
||||
# shellcheck disable=SC2086
|
||||
if ! _recordset_id=$(openstack recordset set -c id -f value $_record_args "$_zone_id" "$fulldomain."); then
|
||||
@@ -107,13 +107,13 @@ _dns_openstack_delete_recordset() {
|
||||
fi
|
||||
else
|
||||
_info "Found existing records, updating recordset"
|
||||
# Build new list of --record <rec> args for update
|
||||
# Build new list of --record=<rec> args for update
|
||||
_record_args=""
|
||||
for _rec in $_records; do
|
||||
if [ "$_rec" = "$txtvalue" ]; then
|
||||
continue
|
||||
fi
|
||||
_record_args="$_record_args --record $_rec"
|
||||
_record_args="$_record_args --record=$_rec"
|
||||
done
|
||||
# shellcheck disable=SC2086
|
||||
if ! openstack recordset set -c id -f value $_record_args "$_zone_id" "$fulldomain." >/dev/null; then
|
||||
|
||||
@@ -137,7 +137,7 @@ _get_root() {
|
||||
domain=$1
|
||||
i=2
|
||||
p=1
|
||||
if _opns_rest "GET" "/domain/get"; then
|
||||
if _opns_rest "GET" "/domain/searchPrimaryDomain"; then
|
||||
_domain_response="$response"
|
||||
else
|
||||
return 1
|
||||
@@ -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 "\"uuid\":\"[a-z0-9\-]*\",\"enabled\":\"1\",\"type\":\"primary\",\"domainname\":\"${h}\"" | cut -d ':' -f 2 | cut -d '"' -f 2)
|
||||
if [ -n "$id" ]; then
|
||||
_debug id "$id"
|
||||
_host=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
#'ovh-eu'
|
||||
OVH_EU='https://eu.api.ovh.com/1.0'
|
||||
|
||||
#'ovh-us'
|
||||
OVH_US='https://api.us.ovhcloud.com/1.0'
|
||||
|
||||
#'ovh-ca':
|
||||
OVH_CA='https://ca.api.ovh.com/1.0'
|
||||
|
||||
@@ -29,9 +32,6 @@ SYS_EU='https://eu.api.soyoustart.com/1.0'
|
||||
#'soyoustart-ca'
|
||||
SYS_CA='https://ca.api.soyoustart.com/1.0'
|
||||
|
||||
#'runabove-ca'
|
||||
RAV_CA='https://api.runabove.com/1.0'
|
||||
|
||||
wiki="https://github.com/acmesh-official/acme.sh/wiki/How-to-use-OVH-domain-api"
|
||||
|
||||
ovh_success="https://github.com/acmesh-official/acme.sh/wiki/OVH-Success"
|
||||
@@ -45,6 +45,10 @@ _ovh_get_api() {
|
||||
printf "%s" $OVH_EU
|
||||
return
|
||||
;;
|
||||
ovh-us | ovhus)
|
||||
printf "%s" $OVH_US
|
||||
return
|
||||
;;
|
||||
ovh-ca | ovhca)
|
||||
printf "%s" $OVH_CA
|
||||
return
|
||||
@@ -65,14 +69,15 @@ _ovh_get_api() {
|
||||
printf "%s" $SYS_CA
|
||||
return
|
||||
;;
|
||||
runabove-ca | runaboveca)
|
||||
printf "%s" $RAV_CA
|
||||
# raw API url starts with https://
|
||||
https*)
|
||||
printf "%s" "$1"
|
||||
return
|
||||
;;
|
||||
|
||||
*)
|
||||
|
||||
_err "Unknown parameter : $1"
|
||||
_err "Unknown endpoint : $1"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
@@ -92,7 +97,7 @@ _initAuth() {
|
||||
|
||||
if [ "$OVH_AK" != "$(_readaccountconf OVH_AK)" ]; then
|
||||
_info "It seems that your ovh key is changed, let's clear consumer key first."
|
||||
_clearaccountconf OVH_CK
|
||||
_clearaccountconf_mutable OVH_CK
|
||||
fi
|
||||
_saveaccountconf_mutable OVH_AK "$OVH_AK"
|
||||
_saveaccountconf_mutable OVH_AS "$OVH_AS"
|
||||
@@ -118,13 +123,14 @@ _initAuth() {
|
||||
#return and wait for retry.
|
||||
return 1
|
||||
fi
|
||||
_saveaccountconf_mutable OVH_CK "$OVH_CK"
|
||||
|
||||
_info "Checking authentication"
|
||||
|
||||
if ! _ovh_rest GET "domain" || _contains "$response" "INVALID_CREDENTIAL" || _contains "$response" "NOT_CREDENTIAL"; then
|
||||
_err "The consumer key is invalid: $OVH_CK"
|
||||
_err "Please retry to create a new one."
|
||||
_clearaccountconf OVH_CK
|
||||
_clearaccountconf_mutable OVH_CK
|
||||
return 1
|
||||
fi
|
||||
_info "Consumer key is ok."
|
||||
@@ -198,6 +204,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
|
||||
@@ -233,8 +241,7 @@ _ovh_authentication() {
|
||||
_secure_debug consumerKey "$consumerKey"
|
||||
|
||||
OVH_CK="$consumerKey"
|
||||
_saveaccountconf OVH_CK "$OVH_CK"
|
||||
|
||||
_saveaccountconf_mutable OVH_CK "$OVH_CK"
|
||||
_info "Please open this link to do authentication: $(__green "$validationUrl")"
|
||||
|
||||
_info "Here is a guide for you: $(__green "$wiki")"
|
||||
|
||||
@@ -41,7 +41,7 @@ pleskxml_init_checks_done=0
|
||||
NEWLINE='\
|
||||
'
|
||||
|
||||
pleskxml_tplt_get_domains="<packet><customer><get-domain-list><filter/></get-domain-list></customer></packet>"
|
||||
pleskxml_tplt_get_domains="<packet><webspace><get><filter/><dataset><gen_info/></dataset></get></webspace></packet>"
|
||||
# Get a list of domains that PLESK can manage, so we can check root domain + host for acme.sh
|
||||
# Also used to test credentials and URI.
|
||||
# No params.
|
||||
@@ -145,22 +145,25 @@ dns_pleskxml_rm() {
|
||||
)"
|
||||
|
||||
if [ -z "$reclist" ]; then
|
||||
_err "No TXT records found for root domain ${root_domain_name} (Plesk domain ID ${root_domain_id}). Exiting."
|
||||
_err "No TXT records found for root domain $fulldomain (Plesk domain ID ${root_domain_id}). Exiting."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "Got list of DNS TXT records for root domain '$root_domain_name':"
|
||||
_debug "Got list of DNS TXT records for root Plesk domain ID ${root_domain_id} of root domain $fulldomain:"
|
||||
_debug "$reclist"
|
||||
|
||||
# Extracting the id of the TXT record for the full domain (NOT case-sensitive) and corresponding value
|
||||
recid="$(
|
||||
_value "$reclist" |
|
||||
grep "<host>${fulldomain}.</host>" |
|
||||
grep -i "<host>${fulldomain}.</host>" |
|
||||
grep "<value>${txtvalue}</value>" |
|
||||
sed 's/^.*<id>\([0-9]\{1,\}\)<\/id>.*$/\1/'
|
||||
)"
|
||||
|
||||
_debug "Got id from line: $recid"
|
||||
|
||||
if ! _value "$recid" | grep '^[0-9]\{1,\}$' >/dev/null; then
|
||||
_err "DNS records for root domain '${root_domain_name}' (Plesk ID ${root_domain_id}) + host '${sub_domain_name}' do not contain the TXT record '${txtvalue}'"
|
||||
_err "DNS records for root domain '${fulldomain}.' (Plesk ID ${root_domain_id}) + host '${sub_domain_name}' do not contain the TXT record '${txtvalue}'"
|
||||
_err "Cannot delete TXT record. Exiting."
|
||||
return 1
|
||||
fi
|
||||
@@ -251,9 +254,12 @@ _call_api() {
|
||||
|
||||
# Detect any <status> that isn't "ok". None of the used calls should fail if the API is working correctly.
|
||||
# Also detect if there simply aren't any status lines (null result?) and report that, as well.
|
||||
# Remove <data></data> structure from result string, since it might contain <status> values that are related to the status of the domain and not to the API request
|
||||
|
||||
statuslines_count_total="$(echo "$pleskxml_prettyprint_result" | grep -c '^ *<status>[^<]*</status> *$')"
|
||||
statuslines_count_okay="$(echo "$pleskxml_prettyprint_result" | grep -c '^ *<status>ok</status> *$')"
|
||||
statuslines_count_total="$(echo "$pleskxml_prettyprint_result" | sed '/<data>/,/<\/data>/d' | grep -c '^ *<status>[^<]*</status> *$')"
|
||||
statuslines_count_okay="$(echo "$pleskxml_prettyprint_result" | sed '/<data>/,/<\/data>/d' | grep -c '^ *<status>ok</status> *$')"
|
||||
_debug "statuslines_count_total=$statuslines_count_total."
|
||||
_debug "statuslines_count_okay=$statuslines_count_okay."
|
||||
|
||||
if [ -z "$statuslines_count_total" ]; then
|
||||
|
||||
@@ -375,7 +381,7 @@ _pleskxml_get_root_domain() {
|
||||
# Output will be one line per known domain, containing 2 <name> tages and a single <id> tag
|
||||
# We don't actually need to check for type, name, *and* id, but it guarantees only usable lines are returned.
|
||||
|
||||
output="$(_api_response_split "$pleskxml_prettyprint_result" 'domain' '<type>domain</type>' | sed 's/<ascii-name>/<name>/g;s/<\/ascii-name>/<\/name>/g' | grep '<name>' | grep '<id>')"
|
||||
output="$(_api_response_split "$pleskxml_prettyprint_result" 'result' '<status>ok</status>' | sed 's/<ascii-name>/<name>/g;s/<\/ascii-name>/<\/name>/g' | grep '<name>' | grep '<id>')"
|
||||
|
||||
_debug 'Domains managed by Plesk server are (ignore the hacked output):'
|
||||
_debug "$output"
|
||||
|
||||
115
dnsapi/dns_rage4.sh
Executable file
115
dnsapi/dns_rage4.sh
Executable file
@@ -0,0 +1,115 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
#RAGE4_TOKEN="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
#
|
||||
#RAGE4_USERNAME="xxxx@sss.com"
|
||||
|
||||
RAGE4_Api="https://rage4.com/rapi/"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_rage4_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
unquotedtxtvalue=$(echo "$txtvalue" | tr -d \")
|
||||
|
||||
RAGE4_USERNAME="${RAGE4_USERNAME:-$(_readaccountconf_mutable RAGE4_USERNAME)}"
|
||||
RAGE4_TOKEN="${RAGE4_TOKEN:-$(_readaccountconf_mutable RAGE4_TOKEN)}"
|
||||
|
||||
if [ -z "$RAGE4_USERNAME" ] || [ -z "$RAGE4_TOKEN" ]; then
|
||||
RAGE4_USERNAME=""
|
||||
RAGE4_TOKEN=""
|
||||
_err "You didn't specify a Rage4 api token and username yet."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the api key and email to the account conf file.
|
||||
_saveaccountconf_mutable RAGE4_USERNAME "$RAGE4_USERNAME"
|
||||
_saveaccountconf_mutable RAGE4_TOKEN "$RAGE4_TOKEN"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _domain_id "$_domain_id"
|
||||
|
||||
_rage4_rest "createrecord/?id=$_domain_id&name=$fulldomain&content=$unquotedtxtvalue&type=TXT&active=true&ttl=1"
|
||||
return 0
|
||||
}
|
||||
|
||||
#fulldomain txtvalue
|
||||
dns_rage4_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
RAGE4_USERNAME="${RAGE4_USERNAME:-$(_readaccountconf_mutable RAGE4_USERNAME)}"
|
||||
RAGE4_TOKEN="${RAGE4_TOKEN:-$(_readaccountconf_mutable RAGE4_TOKEN)}"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _domain_id "$_domain_id"
|
||||
|
||||
_debug "Getting txt records"
|
||||
_rage4_rest "getrecords/?id=${_domain_id}"
|
||||
|
||||
_record_id=$(echo "$response" | sed -rn 's/.*"id":([[:digit:]]+)[^\}]*'"$txtvalue"'.*/\1/p')
|
||||
_rage4_rest "deleterecord/?id=${_record_id}"
|
||||
return 0
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _domain=domain.com
|
||||
# _domain_id=sdjkglgdfewsdfg
|
||||
_get_root() {
|
||||
domain=$1
|
||||
|
||||
if ! _rage4_rest "getdomains"; then
|
||||
return 1
|
||||
fi
|
||||
_debug _get_root_domain "$domain"
|
||||
|
||||
for line in $(echo "$response" | tr '}' '\n'); do
|
||||
__domain=$(echo "$line" | sed -rn 's/.*"name":"([^"]*)",.*/\1/p')
|
||||
__domain_id=$(echo "$line" | sed -rn 's/.*"id":([^,]*),.*/\1/p')
|
||||
if [ "$domain" != "${domain%"$__domain"*}" ]; then
|
||||
_domain_id="$__domain_id"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z "$_domain_id" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
_rage4_rest() {
|
||||
ep="$1"
|
||||
_debug "$ep"
|
||||
|
||||
username_trimmed=$(echo "$RAGE4_USERNAME" | tr -d '"')
|
||||
token_trimmed=$(echo "$RAGE4_TOKEN" | tr -d '"')
|
||||
auth=$(printf '%s:%s' "$username_trimmed" "$token_trimmed" | _base64)
|
||||
|
||||
export _H1="Content-Type: application/json"
|
||||
export _H2="Authorization: Basic $auth"
|
||||
|
||||
response="$(_get "$RAGE4_Api$ep")"
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
@@ -92,10 +92,10 @@ _get_root() {
|
||||
domains_list=$(echo "${response}" | grep dname | sed -r "s/.*dname=\"([^\"]+)\".*/\\1/g")
|
||||
|
||||
for ITEM in ${domains_list}; do
|
||||
IDN_ITEM="$(_idn "${ITEM}")"
|
||||
IDN_ITEM=${ITEM}
|
||||
case "${domain}" in
|
||||
*${IDN_ITEM}*)
|
||||
_domain=${IDN_ITEM}
|
||||
_domain="$(_idn "${ITEM}")"
|
||||
_debug _domain "${_domain}"
|
||||
return 0
|
||||
;;
|
||||
|
||||
@@ -76,7 +76,7 @@ dns_selectel_rm() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
_record_seg="$(echo "$response" | _egrep_o "\"content\" *: *\"$txtvalue\"[^}]*}")"
|
||||
_record_seg="$(echo "$response" | _egrep_o "[^{]*\"content\" *: *\"$txtvalue\"[^}]*}")"
|
||||
_debug2 "_record_seg" "$_record_seg"
|
||||
if [ -z "$_record_seg" ]; then
|
||||
_err "can not find _record_seg"
|
||||
@@ -120,7 +120,7 @@ _get_root() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "\"name\": \"$h\","; then
|
||||
if _contains "$response" "\"name\" *: *\"$h\","; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain=$h
|
||||
_debug "Getting domain id for $h"
|
||||
|
||||
94
dnsapi/dns_selfhost.sh
Normal file
94
dnsapi/dns_selfhost.sh
Normal file
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env sh
|
||||
#
|
||||
# Author: Marvin Edeler
|
||||
# Report Bugs here: https://github.com/Marvo2011/acme.sh/issues/1
|
||||
# Last Edit: 17.02.2022
|
||||
|
||||
dns_selfhost_add() {
|
||||
fulldomain=$1
|
||||
txt=$2
|
||||
_info "Calling acme-dns on selfhost"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txt"
|
||||
|
||||
SELFHOSTDNS_UPDATE_URL="https://selfhost.de/cgi-bin/api.pl"
|
||||
|
||||
# Get values, but don't save until we successfully validated
|
||||
SELFHOSTDNS_USERNAME="${SELFHOSTDNS_USERNAME:-$(_readaccountconf_mutable SELFHOSTDNS_USERNAME)}"
|
||||
SELFHOSTDNS_PASSWORD="${SELFHOSTDNS_PASSWORD:-$(_readaccountconf_mutable SELFHOSTDNS_PASSWORD)}"
|
||||
# These values are domain dependent, so read them from there
|
||||
SELFHOSTDNS_MAP="${SELFHOSTDNS_MAP:-$(_readdomainconf SELFHOSTDNS_MAP)}"
|
||||
# Selfhost api can't dynamically add TXT record,
|
||||
# so we have to store the last used RID of the domain to support a second RID for wildcard domains
|
||||
# (format: 'fulldomainA:lastRid fulldomainB:lastRid ...')
|
||||
SELFHOSTDNS_MAP_LAST_USED_INTERNAL=$(_readdomainconf SELFHOSTDNS_MAP_LAST_USED_INTERNAL)
|
||||
|
||||
if [ -z "${SELFHOSTDNS_USERNAME:-}" ] || [ -z "${SELFHOSTDNS_PASSWORD:-}" ]; then
|
||||
_err "SELFHOSTDNS_USERNAME and SELFHOSTDNS_PASSWORD must be set"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# get the domain entry from SELFHOSTDNS_MAP
|
||||
# only match full domains (at the beginning of the string or with a leading whitespace),
|
||||
# e.g. don't match mytest.example.com or sub.test.example.com for test.example.com
|
||||
# if the domain is defined multiple times only the last occurance will be matched
|
||||
mapEntry=$(echo "$SELFHOSTDNS_MAP" | sed -n -E "s/(^|^.*[[:space:]])($fulldomain)(:[[:digit:]]+)([:]?[[:digit:]]*)(.*)/\2\3\4/p")
|
||||
_debug2 mapEntry "$mapEntry"
|
||||
if test -z "$mapEntry"; then
|
||||
_err "SELFHOSTDNS_MAP must contain the fulldomain incl. prefix and at least one RID"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# get the RIDs from the map entry
|
||||
rid1=$(echo "$mapEntry" | cut -d: -f2)
|
||||
rid2=$(echo "$mapEntry" | cut -d: -f3)
|
||||
|
||||
# read last used rid domain
|
||||
lastUsedRidForDomainEntry=$(echo "$SELFHOSTDNS_MAP_LAST_USED_INTERNAL" | sed -n -E "s/(^|^.*[[:space:]])($fulldomain:[[:digit:]]+)(.*)/\2/p")
|
||||
_debug2 lastUsedRidForDomainEntry "$lastUsedRidForDomainEntry"
|
||||
lastUsedRidForDomain=$(echo "$lastUsedRidForDomainEntry" | cut -d: -f2)
|
||||
|
||||
rid="$rid1"
|
||||
if [ "$lastUsedRidForDomain" = "$rid" ] && ! test -z "$rid2"; then
|
||||
rid="$rid2"
|
||||
fi
|
||||
|
||||
_info "Trying to add $txt on selfhost for rid: $rid"
|
||||
|
||||
data="?username=$SELFHOSTDNS_USERNAME&password=$SELFHOSTDNS_PASSWORD&rid=$rid&content=$txt"
|
||||
response="$(_get "$SELFHOSTDNS_UPDATE_URL$data")"
|
||||
|
||||
if ! echo "$response" | grep "200 OK" >/dev/null; then
|
||||
_err "Invalid response of acme-dns for selfhost"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# write last used rid domain
|
||||
newLastUsedRidForDomainEntry="$fulldomain:$rid"
|
||||
if ! test -z "$lastUsedRidForDomainEntry"; then
|
||||
# replace last used rid entry for domain
|
||||
SELFHOSTDNS_MAP_LAST_USED_INTERNAL=$(echo "$SELFHOSTDNS_MAP_LAST_USED_INTERNAL" | sed -n -E "s/$lastUsedRidForDomainEntry/$newLastUsedRidForDomainEntry/p")
|
||||
else
|
||||
# add last used rid entry for domain
|
||||
if test -z "$SELFHOSTDNS_MAP_LAST_USED_INTERNAL"; then
|
||||
SELFHOSTDNS_MAP_LAST_USED_INTERNAL="$newLastUsedRidForDomainEntry"
|
||||
else
|
||||
SELFHOSTDNS_MAP_LAST_USED_INTERNAL="$SELFHOSTDNS_MAP_LAST_USED_INTERNAL $newLastUsedRidForDomainEntry"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Now that we know the values are good, save them
|
||||
_saveaccountconf_mutable SELFHOSTDNS_USERNAME "$SELFHOSTDNS_USERNAME"
|
||||
_saveaccountconf_mutable SELFHOSTDNS_PASSWORD "$SELFHOSTDNS_PASSWORD"
|
||||
# These values are domain dependent, so store them there
|
||||
_savedomainconf SELFHOSTDNS_MAP "$SELFHOSTDNS_MAP"
|
||||
_savedomainconf SELFHOSTDNS_MAP_LAST_USED_INTERNAL "$SELFHOSTDNS_MAP_LAST_USED_INTERNAL"
|
||||
}
|
||||
|
||||
dns_selfhost_rm() {
|
||||
fulldomain=$1
|
||||
txt=$2
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txt"
|
||||
_info "Creating and removing of records is not supported by selfhost API, will not delete anything."
|
||||
}
|
||||
@@ -53,7 +53,7 @@ dns_servercow_add() {
|
||||
if printf -- "%s" "$response" | grep "{\"name\":\"$_sub_domain\",\"ttl\":20,\"type\":\"TXT\"" >/dev/null; then
|
||||
_info "A txt record with the same name already exists."
|
||||
# trim the string on the left
|
||||
txtvalue_old=${response#*{\"name\":\"$_sub_domain\",\"ttl\":20,\"type\":\"TXT\",\"content\":\"}
|
||||
txtvalue_old=${response#*{\"name\":\""$_sub_domain"\",\"ttl\":20,\"type\":\"TXT\",\"content\":\"}
|
||||
# trim the string on the right
|
||||
txtvalue_old=${txtvalue_old%%\"*}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#!/usr/bin/env sh
|
||||
TRANSIP_Api_Url="https://api.transip.nl/v6"
|
||||
TRANSIP_Token_Read_Only="false"
|
||||
TRANSIP_Token_Global_Key="false"
|
||||
TRANSIP_Token_Expiration="30 minutes"
|
||||
# You can't reuse a label token, so we leave this empty normally
|
||||
TRANSIP_Token_Label=""
|
||||
@@ -96,7 +95,11 @@ _transip_get_token() {
|
||||
nonce=$(echo "TRANSIP$(_time)" | _digest sha1 hex | cut -c 1-32)
|
||||
_debug nonce "$nonce"
|
||||
|
||||
data="{\"login\":\"${TRANSIP_Username}\",\"nonce\":\"${nonce}\",\"read_only\":\"${TRANSIP_Token_Read_Only}\",\"expiration_time\":\"${TRANSIP_Token_Expiration}\",\"label\":\"${TRANSIP_Token_Label}\",\"global_key\":\"${TRANSIP_Token_Global_Key}\"}"
|
||||
# make IP whitelisting configurable
|
||||
TRANSIP_Token_Global_Key="${TRANSIP_Token_Global_Key:-$(_readaccountconf_mutable TRANSIP_Token_Global_Key)}"
|
||||
_saveaccountconf_mutable TRANSIP_Token_Global_Key "$TRANSIP_Token_Global_Key"
|
||||
|
||||
data="{\"login\":\"${TRANSIP_Username}\",\"nonce\":\"${nonce}\",\"read_only\":\"${TRANSIP_Token_Read_Only}\",\"expiration_time\":\"${TRANSIP_Token_Expiration}\",\"label\":\"${TRANSIP_Token_Label}\",\"global_key\":\"${TRANSIP_Token_Global_Key:-false}\"}"
|
||||
_debug data "$data"
|
||||
|
||||
#_signature=$(printf "%s" "$data" | openssl dgst -sha512 -sign "$TRANSIP_Key_File" | _base64)
|
||||
@@ -139,6 +142,18 @@ _transip_setup() {
|
||||
_saveaccountconf_mutable TRANSIP_Username "$TRANSIP_Username"
|
||||
_saveaccountconf_mutable TRANSIP_Key_File "$TRANSIP_Key_File"
|
||||
|
||||
# download key file if it's an URL
|
||||
if _startswith "$TRANSIP_Key_File" "http"; then
|
||||
_debug "download transip key file"
|
||||
TRANSIP_Key_URL=$TRANSIP_Key_File
|
||||
TRANSIP_Key_File="$(_mktemp)"
|
||||
chmod 600 "$TRANSIP_Key_File"
|
||||
if ! _get "$TRANSIP_Key_URL" >"$TRANSIP_Key_File"; then
|
||||
_err "Error getting key file from : $TRANSIP_Key_URL"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -f "$TRANSIP_Key_File" ]; then
|
||||
if ! grep "BEGIN PRIVATE KEY" "$TRANSIP_Key_File" >/dev/null 2>&1; then
|
||||
_err "Key file doesn't seem to be a valid key: ${TRANSIP_Key_File}"
|
||||
@@ -156,6 +171,12 @@ _transip_setup() {
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "${TRANSIP_Key_URL}" ]; then
|
||||
_debug "delete transip key file"
|
||||
rm "${TRANSIP_Key_File}"
|
||||
TRANSIP_Key_File=$TRANSIP_Key_URL
|
||||
fi
|
||||
|
||||
_get_root "$fulldomain" || return 1
|
||||
|
||||
return 0
|
||||
|
||||
160
dnsapi/dns_udr.sh
Normal file
160
dnsapi/dns_udr.sh
Normal 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
|
||||
}
|
||||
@@ -5,7 +5,8 @@
|
||||
#
|
||||
# ULTRA_PWD="some_password_goes_here"
|
||||
|
||||
ULTRA_API="https://restapi.ultradns.com/v2/"
|
||||
ULTRA_API="https://api.ultradns.com/v3/"
|
||||
ULTRA_AUTH_API="https://api.ultradns.com/v2/"
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "some_long_string_of_characters_go_here_from_lets_encrypt"
|
||||
dns_ultra_add() {
|
||||
@@ -121,7 +122,7 @@ _get_root() {
|
||||
return 1
|
||||
fi
|
||||
if _contains "${response}" "${h}." >/dev/null; then
|
||||
_domain_id=$(echo "$response" | _egrep_o "${h}")
|
||||
_domain_id=$(echo "$response" | _egrep_o "${h}" | head -1)
|
||||
if [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain="${h}"
|
||||
@@ -142,23 +143,25 @@ _ultra_rest() {
|
||||
ep="$2"
|
||||
data="$3"
|
||||
_debug "$ep"
|
||||
_debug TOKEN "${AUTH_TOKEN}"
|
||||
if [ -z "$AUTH_TOKEN" ]; then
|
||||
_ultra_login
|
||||
fi
|
||||
_debug TOKEN "$AUTH_TOKEN"
|
||||
|
||||
_ultra_login
|
||||
export _H1="Content-Type: application/json"
|
||||
export _H2="Authorization: Bearer ${AUTH_TOKEN}"
|
||||
export _H2="Authorization: Bearer $AUTH_TOKEN"
|
||||
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug data "${data}"
|
||||
response="$(_post "${data}" "${ULTRA_API}"/"${ep}" "" "${m}")"
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$ULTRA_API$ep" "" "$m")"
|
||||
else
|
||||
response="$(_get "$ULTRA_API/$ep")"
|
||||
response="$(_get "$ULTRA_API$ep")"
|
||||
fi
|
||||
}
|
||||
|
||||
_ultra_login() {
|
||||
export _H1=""
|
||||
export _H2=""
|
||||
AUTH_TOKEN=$(_post "grant_type=password&username=${ULTRA_USR}&password=${ULTRA_PWD}" "${ULTRA_API}authorization/token" | cut -d, -f3 | cut -d\" -f4)
|
||||
AUTH_TOKEN=$(_post "grant_type=password&username=${ULTRA_USR}&password=${ULTRA_PWD}" "${ULTRA_AUTH_API}authorization/token" | cut -d, -f3 | cut -d\" -f4)
|
||||
export AUTH_TOKEN
|
||||
}
|
||||
|
||||
142
dnsapi/dns_vercel.sh
Normal file
142
dnsapi/dns_vercel.sh
Normal file
@@ -0,0 +1,142 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Vercel DNS API
|
||||
#
|
||||
# This is your API token which can be acquired on the account page.
|
||||
# https://vercel.com/account/tokens
|
||||
#
|
||||
# VERCEL_TOKEN="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
|
||||
VERCEL_API="https://api.vercel.com"
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_vercel_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
VERCEL_TOKEN="${VERCEL_TOKEN:-$(_readaccountconf_mutable VERCEL_TOKEN)}"
|
||||
|
||||
if [ -z "$VERCEL_TOKEN" ]; then
|
||||
VERCEL_TOKEN=""
|
||||
_err "You have not set the Vercel API token yet."
|
||||
_err "Please visit https://vercel.com/account/tokens to generate it."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf_mutable VERCEL_TOKEN "$VERCEL_TOKEN"
|
||||
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_info "Adding record"
|
||||
if _vercel_rest POST "v2/domains/$_domain/records" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\"}"; then
|
||||
if printf -- "%s" "$response" | grep "\"uid\":\"" >/dev/null; then
|
||||
_info "Added"
|
||||
return 0
|
||||
else
|
||||
_err "Unexpected response while adding text record."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
_err "Add txt record error."
|
||||
}
|
||||
|
||||
dns_vercel_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_vercel_rest GET "v2/domains/$_domain/records"
|
||||
|
||||
count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$_sub_domain\",[^{]*\"type\":\"TXT\"" | wc -l | tr -d " ")
|
||||
|
||||
if [ "$count" = "0" ]; then
|
||||
_info "Don't need to remove."
|
||||
else
|
||||
_record_id=$(printf "%s" "$response" | _egrep_o "\"id\":[^,]*,\"slug\":\"[^,]*\",\"name\":\"$_sub_domain\",[^{]*\"type\":\"TXT\",\"value\":\"$txtvalue\"" | cut -d: -f2 | cut -d, -f1 | tr -d '"')
|
||||
|
||||
if [ "$_record_id" ]; then
|
||||
echo "$_record_id" | while read -r item; do
|
||||
if _vercel_rest DELETE "v2/domains/$_domain/records/$item"; then
|
||||
_info "removed record" "$item"
|
||||
return 0
|
||||
else
|
||||
_err "failed to remove record" "$item"
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
_get_root() {
|
||||
domain="$1"
|
||||
ep="$2"
|
||||
i=1
|
||||
p=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _vercel_rest GET "v4/domains/$h"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
_vercel_rest() {
|
||||
m="$1"
|
||||
ep="$2"
|
||||
data="$3"
|
||||
|
||||
path="$VERCEL_API/$ep"
|
||||
|
||||
export _H1="Content-Type: application/json"
|
||||
export _H2="Authorization: Bearer $VERCEL_TOKEN"
|
||||
|
||||
if [ "$m" != "GET" ]; then
|
||||
_secure_debug2 data "$data"
|
||||
response="$(_post "$data" "$path" "" "$m")"
|
||||
else
|
||||
response="$(_get "$path")"
|
||||
fi
|
||||
_ret="$?"
|
||||
_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")"
|
||||
_debug "http response code $_code"
|
||||
_secure_debug2 response "$response"
|
||||
if [ "$_ret" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
|
||||
response="$(printf "%s" "$response" | _normalizeJson)"
|
||||
return 0
|
||||
}
|
||||
@@ -3,10 +3,10 @@
|
||||
#
|
||||
#VULTR_API_KEY=000011112222333344445555666677778888
|
||||
|
||||
VULTR_Api="https://api.vultr.com/v1"
|
||||
VULTR_Api="https://api.vultr.com/v2"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_vultr_add() {
|
||||
fulldomain=$1
|
||||
@@ -31,14 +31,14 @@ dns_vultr_add() {
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_debug 'Getting txt records'
|
||||
_vultr_rest GET "dns/records?domain=$_domain"
|
||||
_vultr_rest GET "domains/$_domain/records"
|
||||
|
||||
if printf "%s\n" "$response" | grep -- "\"type\":\"TXT\",\"name\":\"$fulldomain\"" >/dev/null; then
|
||||
_err 'Error'
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _vultr_rest POST 'dns/create_record' "domain=$_domain&name=$_sub_domain&data=\"$txtvalue\"&type=TXT"; then
|
||||
if ! _vultr_rest POST "domains/$_domain/records" "{\"name\":\"$_sub_domain\",\"data\":\"$txtvalue\",\"type\":\"TXT\"}"; then
|
||||
_err "$response"
|
||||
return 1
|
||||
fi
|
||||
@@ -71,14 +71,14 @@ dns_vultr_rm() {
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_debug 'Getting txt records'
|
||||
_vultr_rest GET "dns/records?domain=$_domain"
|
||||
_vultr_rest GET "domains/$_domain/records"
|
||||
|
||||
if printf "%s\n" "$response" | grep -- "\"type\":\"TXT\",\"name\":\"$fulldomain\"" >/dev/null; then
|
||||
_err 'Error'
|
||||
return 1
|
||||
fi
|
||||
|
||||
_record_id="$(echo "$response" | tr '{}' '\n' | grep '"TXT"' | grep -- "$txtvalue" | tr ',' '\n' | grep -i 'RECORDID' | cut -d : -f 2)"
|
||||
_record_id="$(echo "$response" | tr '{}' '\n' | grep '"TXT"' | grep -- "$txtvalue" | tr ',' '\n' | grep -i 'id' | cut -d : -f 2 | tr -d '"')"
|
||||
_debug _record_id "$_record_id"
|
||||
if [ "$_record_id" ]; then
|
||||
_info "Successfully retrieved the record id for ACME challenge."
|
||||
@@ -87,7 +87,7 @@ dns_vultr_rm() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! _vultr_rest POST 'dns/delete_record' "domain=$_domain&RECORDID=$_record_id"; then
|
||||
if ! _vultr_rest DELETE "domains/$_domain/records/$_record_id"; then
|
||||
_err "$response"
|
||||
return 1
|
||||
fi
|
||||
@@ -112,11 +112,11 @@ _get_root() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _vultr_rest GET "dns/list"; then
|
||||
if ! _vultr_rest GET "domains"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if printf "%s\n" "$response" | grep '^\[.*\]' >/dev/null; then
|
||||
if printf "%s\n" "$response" | grep -E '^\{.*\}' >/dev/null; then
|
||||
if _contains "$response" "\"domain\":\"$_domain\""; then
|
||||
_sub_domain="$(echo "$fulldomain" | sed "s/\\.$_domain\$//")"
|
||||
return 0
|
||||
@@ -139,10 +139,10 @@ _vultr_rest() {
|
||||
data="$3"
|
||||
_debug "$ep"
|
||||
|
||||
api_key_trimmed=$(echo $VULTR_API_KEY | tr -d '"')
|
||||
api_key_trimmed=$(echo "$VULTR_API_KEY" | tr -d '"')
|
||||
|
||||
export _H1="Api-Key: $api_key_trimmed"
|
||||
export _H2='Content-Type: application/x-www-form-urlencoded'
|
||||
export _H1="Authorization: Bearer $api_key_trimmed"
|
||||
export _H2='Content-Type: application/json'
|
||||
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug data "$data"
|
||||
|
||||
@@ -12,7 +12,7 @@ RECORD=''
|
||||
|
||||
# Usage: dns_world4you_add <fqdn> <value>
|
||||
dns_world4you_add() {
|
||||
fqdn="$1"
|
||||
fqdn=$(echo "$1" | _lower_case)
|
||||
value="$2"
|
||||
_info "Using world4you to add record"
|
||||
_debug fulldomain "$fqdn"
|
||||
@@ -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
|
||||
@@ -49,33 +49,32 @@ dns_world4you_add() {
|
||||
ret=$(_post "$body" "$WORLD4YOU_API/$paketnr/dns" '' POST 'application/x-www-form-urlencoded')
|
||||
_resethttp
|
||||
|
||||
if _contains "$(_head_n 3 <"$HTTP_HEADER")" '302'; then
|
||||
if _contains "$(_head_n 1 <"$HTTP_HEADER")" '302'; then
|
||||
res=$(_get "$WORLD4YOU_API/$paketnr/dns")
|
||||
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/<[^>]*>//g' | 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
|
||||
else
|
||||
_err "$(_head_n 3 <"$HTTP_HEADER")"
|
||||
_err "View $HTTP_HEADER for debugging"
|
||||
msg=$(echo "$ret" | grep '"form-error-message"' | sed 's/^.*<div class="form-error-message">\([^<]*\)<\/div>.*$/\1/')
|
||||
_err "Unable to add record: my.world4you.com: $msg"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Usage: dns_world4you_rm <fqdn> <value>
|
||||
dns_world4you_rm() {
|
||||
fqdn="$1"
|
||||
fqdn=$(echo "$1" | _lower_case)
|
||||
value="$2"
|
||||
_info "Using world4you to remove record"
|
||||
_debug fulldomain "$fqdn"
|
||||
@@ -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
|
||||
@@ -114,26 +113,25 @@ dns_world4you_rm() {
|
||||
ret=$(_post "$body" "$WORLD4YOU_API/$paketnr/dns/record/delete" '' POST 'application/x-www-form-urlencoded')
|
||||
_resethttp
|
||||
|
||||
if _contains "$(_head_n 3 <"$HTTP_HEADER")" '302'; then
|
||||
if _contains "$(_head_n 1 <"$HTTP_HEADER")" '302'; then
|
||||
res=$(_get "$WORLD4YOU_API/$paketnr/dns")
|
||||
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/<[^>]*>//g' | 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
|
||||
else
|
||||
_err "$(_head_n 3 <"$HTTP_HEADER")"
|
||||
_err "View $HTTP_HEADER for debugging"
|
||||
msg=$(echo "$ret" | grep "form-error-message" | sed 's/^.*<div class="form-error-message">\([^<]*\)<\/div>.*$/\1/')
|
||||
_err "Unable to remove record: my.world4you.com: $msg"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
@@ -157,34 +155,47 @@ _login() {
|
||||
_saveaccountconf_mutable WORLD4YOU_USERNAME "$WORLD4YOU_USERNAME"
|
||||
_saveaccountconf_mutable WORLD4YOU_PASSWORD "$WORLD4YOU_PASSWORD"
|
||||
|
||||
_resethttp
|
||||
export ACME_HTTP_NO_REDIRECTS=1
|
||||
page=$(_get "$WORLD4YOU_API/login")
|
||||
_resethttp
|
||||
|
||||
if _contains "$(_head_n 1 <"$HTTP_HEADER")" '302'; then
|
||||
_info "Already logged in"
|
||||
_parse_sessid
|
||||
return 0
|
||||
fi
|
||||
|
||||
_info "Logging in..."
|
||||
|
||||
username="$WORLD4YOU_USERNAME"
|
||||
password="$WORLD4YOU_PASSWORD"
|
||||
csrf_token=$(_get "$WORLD4YOU_API/login" | grep '_csrf_token' | sed 's/^.*<input[^>]*value=\"\([^"]*\)\".*$/\1/')
|
||||
sessid=$(grep 'W4YSESSID' <"$HTTP_HEADER" | sed 's/^.*W4YSESSID=\([^;]*\);.*$/\1/')
|
||||
csrf_token=$(echo "$page" | grep '_csrf_token' | sed 's/^.*<input[^>]*value=\"\([^"]*\)\".*$/\1/')
|
||||
_parse_sessid
|
||||
|
||||
export _H1="Cookie: W4YSESSID=$sessid"
|
||||
export _H2="X-Requested-With: XMLHttpRequest"
|
||||
body="_username=$username&_password=$password&_csrf_token=$csrf_token"
|
||||
ret=$(_post "$body" "$WORLD4YOU_API/login" '' POST 'application/x-www-form-urlencoded')
|
||||
unset _H2
|
||||
|
||||
_debug ret "$ret"
|
||||
if _contains "$ret" "\"success\":true"; then
|
||||
_info "Successfully logged in"
|
||||
sessid=$(grep 'W4YSESSID' <"$HTTP_HEADER" | sed 's/^.*W4YSESSID=\([^;]*\);.*$/\1/')
|
||||
_parse_sessid
|
||||
else
|
||||
_err "Unable to log in: $(echo "$ret" | sed 's/^.*"message":"\([^\"]*\)".*$/\1/')"
|
||||
msg=$(echo "$ret" | sed 's/^.*"message":"\([^\"]*\)".*$/\1/')
|
||||
_err "Unable to log in: my.world4you.com: $msg"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Usage _get_paketnr <fqdn> <form>
|
||||
# Usage: _get_paketnr <fqdn> <form>
|
||||
_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 '<ul class="nav header-paket-list">' | sed 's/<li/\n<li/g' | sed 's/<[^>]*>/ /g' | sed 's/^.*>\([^>]*\)$/\1/')
|
||||
domain=''
|
||||
for domain in $domains; do
|
||||
if _contains "$fqdn" "$domain\$"; then
|
||||
@@ -199,6 +210,11 @@ _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 "$domains" | grep "$domain" | sed 's/^[^,]*, *\([0-9]*\).*$/\1/')
|
||||
return 0
|
||||
}
|
||||
|
||||
# Usage: _parse_sessid
|
||||
_parse_sessid() {
|
||||
sessid=$(grep 'W4YSESSID' <"$HTTP_HEADER" | _tail_n 1 | sed 's/^.*W4YSESSID=\([^;]*\);.*$/\1/')
|
||||
}
|
||||
|
||||
264
dnsapi/dns_yc.sh
Normal file
264
dnsapi/dns_yc.sh
Normal file
@@ -0,0 +1,264 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#YC_Zone_ID="" # DNS Zone ID
|
||||
#YC_Folder_ID="" # YC Folder ID
|
||||
#YC_SA_ID="" # Service Account ID
|
||||
#YC_SA_Key_ID="" # Service Account IAM Key ID
|
||||
#YC_SA_Key_File_Path="/path/to/private.key" # Path to private.key use instead of YC_SA_Key_File_PEM_b64
|
||||
#YC_SA_Key_File_PEM_b64="" # Base64 content of private.key use instead of YC_SA_Key_File_Path
|
||||
YC_Api="https://dns.api.cloud.yandex.net/dns/v1"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_yc_add() {
|
||||
fulldomain="$(echo "$1". | _lower_case)" # Add dot at end of domain name
|
||||
txtvalue=$2
|
||||
|
||||
YC_SA_Key_File_PEM_b64="${YC_SA_Key_File_PEM_b64:-$(_readaccountconf_mutable YC_SA_Key_File_PEM_b64)}"
|
||||
YC_SA_Key_File_Path="${YC_SA_Key_File_Path:-$(_readaccountconf_mutable YC_SA_Key_File_Path)}"
|
||||
|
||||
if [ "$YC_SA_Key_File_PEM_b64" ]; then
|
||||
echo "$YC_SA_Key_File_PEM_b64" | _dbase64 >private.key
|
||||
YC_SA_Key_File="private.key"
|
||||
_savedomainconf YC_SA_Key_File_PEM_b64 "$YC_SA_Key_File_PEM_b64"
|
||||
else
|
||||
YC_SA_Key_File="$YC_SA_Key_File_Path"
|
||||
_savedomainconf YC_SA_Key_File_Path "$YC_SA_Key_File_Path"
|
||||
fi
|
||||
|
||||
YC_Zone_ID="${YC_Zone_ID:-$(_readaccountconf_mutable YC_Zone_ID)}"
|
||||
YC_Folder_ID="${YC_Folder_ID:-$(_readaccountconf_mutable YC_Folder_ID)}"
|
||||
YC_SA_ID="${YC_SA_ID:-$(_readaccountconf_mutable YC_SA_ID)}"
|
||||
YC_SA_Key_ID="${YC_SA_Key_ID:-$(_readaccountconf_mutable YC_SA_Key_ID)}"
|
||||
|
||||
if [ "$YC_SA_ID" ] && [ "$YC_SA_Key_ID" ] && [ "$YC_SA_Key_File" ]; then
|
||||
if [ -f "$YC_SA_Key_File" ]; then
|
||||
if _isRSA "$YC_SA_Key_File" >/dev/null 2>&1; then
|
||||
if [ "$YC_Zone_ID" ]; then
|
||||
_savedomainconf YC_Zone_ID "$YC_Zone_ID"
|
||||
_savedomainconf YC_SA_ID "$YC_SA_ID"
|
||||
_savedomainconf YC_SA_Key_ID "$YC_SA_Key_ID"
|
||||
elif [ "$YC_Folder_ID" ]; then
|
||||
_savedomainconf YC_Folder_ID "$YC_Folder_ID"
|
||||
_saveaccountconf_mutable YC_SA_ID "$YC_SA_ID"
|
||||
_saveaccountconf_mutable YC_SA_Key_ID "$YC_SA_Key_ID"
|
||||
_clearaccountconf_mutable YC_Zone_ID
|
||||
_clearaccountconf YC_Zone_ID
|
||||
else
|
||||
_err "You didn't specify a Yandex Cloud Zone ID or Folder ID yet."
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_err "YC_SA_Key_File not a RSA file(_isRSA function return false)."
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_err "YC_SA_Key_File not found in path $YC_SA_Key_File."
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_clearaccountconf YC_Zone_ID
|
||||
_clearaccountconf YC_Folder_ID
|
||||
_clearaccountconf YC_SA_ID
|
||||
_clearaccountconf YC_SA_Key_ID
|
||||
_clearaccountconf YC_SA_Key_File_PEM_b64
|
||||
_clearaccountconf YC_SA_Key_File_Path
|
||||
_err "You didn't specify a YC_SA_ID or YC_SA_Key_ID or YC_SA_Key_File."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_debug "Getting txt records"
|
||||
if ! _yc_rest GET "zones/${_domain_id}:getRecordSet?type=TXT&name=$_sub_domain"; then
|
||||
_err "Error: $response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Adding record"
|
||||
if _yc_rest POST "zones/$_domain_id:upsertRecordSets" "{\"merges\": [ { \"name\":\"$_sub_domain\",\"type\":\"TXT\",\"ttl\":\"120\",\"data\":[\"$txtvalue\"]}]}"; then
|
||||
if _contains "$response" "\"done\": true"; then
|
||||
_info "Added, OK"
|
||||
return 0
|
||||
else
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
|
||||
}
|
||||
|
||||
#fulldomain txtvalue
|
||||
dns_yc_rm() {
|
||||
fulldomain="$(echo "$1". | _lower_case)" # Add dot at end of domain name
|
||||
txtvalue=$2
|
||||
|
||||
YC_Zone_ID="${YC_Zone_ID:-$(_readaccountconf_mutable YC_Zone_ID)}"
|
||||
YC_Folder_ID="${YC_Folder_ID:-$(_readaccountconf_mutable YC_Folder_ID)}"
|
||||
YC_SA_ID="${YC_SA_ID:-$(_readaccountconf_mutable YC_SA_ID)}"
|
||||
YC_SA_Key_ID="${YC_SA_Key_ID:-$(_readaccountconf_mutable YC_SA_Key_ID)}"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_debug "Getting txt records"
|
||||
if _yc_rest GET "zones/${_domain_id}:getRecordSet?type=TXT&name=$_sub_domain"; then
|
||||
exists_txtvalue=$(echo "$response" | _normalizeJson | _egrep_o "\"data\".*\][^,]*" | _egrep_o "[^:]*$")
|
||||
_debug exists_txtvalue "$exists_txtvalue"
|
||||
else
|
||||
_err "Error: $response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _yc_rest POST "zones/$_domain_id:updateRecordSets" "{\"deletions\": [ { \"name\":\"$_sub_domain\",\"type\":\"TXT\",\"ttl\":\"120\",\"data\":$exists_txtvalue}]}"; then
|
||||
if _contains "$response" "\"done\": true"; then
|
||||
_info "Delete, OK"
|
||||
return 0
|
||||
else
|
||||
_err "Delete record error."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
_err "Delete record error."
|
||||
return 1
|
||||
}
|
||||
|
||||
#################### 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=1
|
||||
p=1
|
||||
|
||||
# Use Zone ID directly if provided
|
||||
if [ "$YC_Zone_ID" ]; then
|
||||
if ! _yc_rest GET "zones/$YC_Zone_ID"; then
|
||||
return 1
|
||||
else
|
||||
if echo "$response" | tr -d " " | _egrep_o "\"id\":\"$YC_Zone_ID\"" >/dev/null; then
|
||||
_domain=$(echo "$response" | _egrep_o "\"zone\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | _head_n 1 | tr -d " ")
|
||||
if [ "$_domain" ]; then
|
||||
_cutlength=$((${#domain} - ${#_domain}))
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -c "1-$_cutlength")
|
||||
_domain_id=$YC_Zone_ID
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
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 [ "$YC_Folder_ID" ]; then
|
||||
if ! _yc_rest GET "zones?folderId=$YC_Folder_ID"; then
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
echo "You didn't specify a Yandex Cloud Folder ID."
|
||||
return 1
|
||||
fi
|
||||
if _contains "$response" "\"zone\": \"$h\""; then
|
||||
_domain_id=$(echo "$response" | _normalizeJson | _egrep_o "[^{]*\"zone\":\"$h\"[^}]*" | _egrep_o "\"id\"[^,]*" | _egrep_o "[^:]*$" | tr -d '"')
|
||||
_debug _domain_id "$_domain_id"
|
||||
if [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
_yc_rest() {
|
||||
m=$1
|
||||
ep="$2"
|
||||
data="$3"
|
||||
_debug "$ep"
|
||||
|
||||
if [ ! "$YC_Token" ]; then
|
||||
_debug "Login"
|
||||
_yc_login
|
||||
else
|
||||
_debug "Token already exists. Skip Login."
|
||||
fi
|
||||
|
||||
token_trimmed=$(echo "$YC_Token" | tr -d '"')
|
||||
|
||||
export _H1="Content-Type: application/json"
|
||||
export _H2="Authorization: Bearer $token_trimmed"
|
||||
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$YC_Api/$ep" "" "$m")"
|
||||
else
|
||||
response="$(_get "$YC_Api/$ep")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
|
||||
_yc_login() {
|
||||
header=$(echo "{\"typ\":\"JWT\",\"alg\":\"PS256\",\"kid\":\"$YC_SA_Key_ID\"}" | _normalizeJson | _base64 | _url_replace)
|
||||
_debug header "$header"
|
||||
|
||||
_current_timestamp=$(_time)
|
||||
_expire_timestamp=$(_math "$_current_timestamp" + 1200) # 20 minutes
|
||||
payload=$(echo "{\"iss\":\"$YC_SA_ID\",\"aud\":\"https://iam.api.cloud.yandex.net/iam/v1/tokens\",\"iat\":$_current_timestamp,\"exp\":$_expire_timestamp}" | _normalizeJson | _base64 | _url_replace)
|
||||
_debug payload "$payload"
|
||||
|
||||
#signature=$(printf "%s.%s" "$header" "$payload" | ${ACME_OPENSSL_BIN:-openssl} dgst -sign "$YC_SA_Key_File -sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1" | _base64 | _url_replace )
|
||||
_signature=$(printf "%s.%s" "$header" "$payload" | _sign "$YC_SA_Key_File" "sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1" | _url_replace)
|
||||
_debug2 _signature "$_signature"
|
||||
|
||||
rm -rf "$YC_SA_Key_File"
|
||||
|
||||
_jwt=$(printf "{\"jwt\": \"%s.%s.%s\"}" "$header" "$payload" "$_signature")
|
||||
_debug2 _jwt "$_jwt"
|
||||
|
||||
export _H1="Content-Type: application/json"
|
||||
_iam_response="$(_post "$_jwt" "https://iam.api.cloud.yandex.net/iam/v1/tokens" "" "POST")"
|
||||
_debug3 _iam_response "$(echo "$_iam_response" | _normalizeJson)"
|
||||
|
||||
YC_Token="$(echo "$_iam_response" | _normalizeJson | _egrep_o "\"iamToken\"[^,]*" | _egrep_o "[^:]*$" | tr -d '"')"
|
||||
_debug3 YC_Token
|
||||
|
||||
return 0
|
||||
}
|
||||
44
notify/callmebotWhatsApp.sh
Normal file
44
notify/callmebotWhatsApp.sh
Normal file
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#Support CallMeBot Whatsapp webhooks
|
||||
|
||||
#CALLMEBOT_YOUR_PHONE_NO=""
|
||||
#CALLMEBOT_API_KEY=""
|
||||
|
||||
callmebotWhatsApp_send() {
|
||||
_subject="$1"
|
||||
_content="$2"
|
||||
_statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped
|
||||
_debug "_statusCode" "$_statusCode"
|
||||
|
||||
CALLMEBOT_YOUR_PHONE_NO="${CALLMEBOT_YOUR_PHONE_NO:-$(_readaccountconf_mutable CALLMEBOT_YOUR_PHONE_NO)}"
|
||||
if [ -z "$CALLMEBOT_YOUR_PHONE_NO" ]; then
|
||||
CALLMEBOT_YOUR_PHONE_NO=""
|
||||
_err "You didn't specify a Slack webhook url CALLMEBOT_YOUR_PHONE_NO yet."
|
||||
return 1
|
||||
fi
|
||||
_saveaccountconf_mutable CALLMEBOT_YOUR_PHONE_NO "$CALLMEBOT_YOUR_PHONE_NO"
|
||||
|
||||
CALLMEBOT_API_KEY="${CALLMEBOT_API_KEY:-$(_readaccountconf_mutable CALLMEBOT_API_KEY)}"
|
||||
if [ "$CALLMEBOT_API_KEY" ]; then
|
||||
_saveaccountconf_mutable CALLMEBOT_API_KEY "$CALLMEBOT_API_KEY"
|
||||
fi
|
||||
|
||||
_waUrl="https://api.callmebot.com/whatsapp.php"
|
||||
|
||||
_Phone_No="$(printf "%s" "$CALLMEBOT_YOUR_PHONE_NO" | _url_encode)"
|
||||
_apikey="$(printf "%s" "$CALLMEBOT_API_KEY" | _url_encode)"
|
||||
_message="$(printf "*%s*\\n%s" "$_subject" "$_content" | _url_encode)"
|
||||
|
||||
_finalUrl="$_waUrl?phone=$_Phone_No&apikey=$_apikey&text=$_message"
|
||||
response="$(_get "$_finalUrl")"
|
||||
|
||||
if [ "$?" = "0" ] && _contains ".<p><b>Message queued.</b> You will receive it in a few seconds."; then
|
||||
_info "wa send success."
|
||||
return 0
|
||||
fi
|
||||
_err "wa send error."
|
||||
_debug "URL" "$_finalUrl"
|
||||
_debug "Response" "$response"
|
||||
return 1
|
||||
}
|
||||
57
notify/discord.sh
Normal file
57
notify/discord.sh
Normal 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
|
||||
}
|
||||
45
notify/slack_app.sh
Executable file
45
notify/slack_app.sh
Executable file
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#Support Slack APP notifications
|
||||
|
||||
#SLACK_APP_CHANNEL=""
|
||||
#SLACK_APP_TOKEN=""
|
||||
|
||||
slack_app_send() {
|
||||
_subject="$1"
|
||||
_content="$2"
|
||||
_statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped
|
||||
_debug "_statusCode" "$_statusCode"
|
||||
|
||||
SLACK_APP_CHANNEL="${SLACK_APP_CHANNEL:-$(_readaccountconf_mutable SLACK_APP_CHANNEL)}"
|
||||
if [ -n "$SLACK_APP_CHANNEL" ]; then
|
||||
_saveaccountconf_mutable SLACK_APP_CHANNEL "$SLACK_APP_CHANNEL"
|
||||
fi
|
||||
|
||||
SLACK_APP_TOKEN="${SLACK_APP_TOKEN:-$(_readaccountconf_mutable SLACK_APP_TOKEN)}"
|
||||
if [ -n "$SLACK_APP_TOKEN" ]; then
|
||||
_saveaccountconf_mutable SLACK_APP_TOKEN "$SLACK_APP_TOKEN"
|
||||
fi
|
||||
|
||||
_content="$(printf "*%s*\n%s" "$_subject" "$_content" | _json_encode)"
|
||||
_data="{\"text\": \"$_content\", "
|
||||
if [ -n "$SLACK_APP_CHANNEL" ]; then
|
||||
_data="$_data\"channel\": \"$SLACK_APP_CHANNEL\", "
|
||||
fi
|
||||
_data="$_data\"mrkdwn\": \"true\"}"
|
||||
|
||||
export _H1="Authorization: Bearer $SLACK_APP_TOKEN"
|
||||
|
||||
SLACK_APP_API_URL="https://slack.com/api/chat.postMessage"
|
||||
if _post "$_data" "$SLACK_APP_API_URL" "" "POST" "application/json; charset=utf-8"; then
|
||||
# shellcheck disable=SC2154
|
||||
SLACK_APP_RESULT_OK=$(echo "$response" | _egrep_o 'ok" *: *true')
|
||||
if [ "$?" = "0" ] && [ "$SLACK_APP_RESULT_OK" ]; then
|
||||
_info "slack send success."
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
_err "slack send error."
|
||||
_err "$response"
|
||||
return 1
|
||||
}
|
||||
@@ -169,7 +169,7 @@ _clean_email_header() {
|
||||
# email
|
||||
_email_has_display_name() {
|
||||
_email="$1"
|
||||
expr "$_email" : '^.*[<>"]' >/dev/null
|
||||
echo "$_email" | grep -q -E '^.*[<>"]'
|
||||
}
|
||||
|
||||
##
|
||||
@@ -249,7 +249,7 @@ _mime_encoded_word() {
|
||||
_text="$1"
|
||||
# (regex character ranges like [a-z] can be locale-dependent; enumerate ASCII chars to avoid that)
|
||||
_ascii='] $`"'"[!#%&'()*+,./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ~^_abcdefghijklmnopqrstuvwxyz{|}~-"
|
||||
if expr "$_text" : "^.*[^$_ascii]" >/dev/null; then
|
||||
if echo "$_text" | grep -q -E "^.*[^$_ascii]"; then
|
||||
# At least one non-ASCII char; convert entire thing to encoded word
|
||||
printf "%s" "=?UTF-8?B?$(printf "%s" "$_text" | _base64)?="
|
||||
else
|
||||
|
||||
49
notify/weixin_work.sh
Normal file
49
notify/weixin_work.sh
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user