mirror of
https://github.com/acmesh-official/acme.sh.git
synced 2025-06-01 07:32:51 +00:00
Compare commits
757 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
42bbd1b44a | ||
|
fdeaf861e3 | ||
|
8e032a27c4 | ||
|
5bfd43b718 | ||
|
ce7f4cb9a8 | ||
|
99a4cf9e07 | ||
|
184cb0b9a8 | ||
|
c2ccc1f980 | ||
|
8a4b436314 | ||
|
42aaf7c2a0 | ||
|
eb00852a71 | ||
|
b0535d8b40 | ||
|
8b4d93cc14 | ||
|
e2d0923122 | ||
|
2928d84339 | ||
|
b5e3883891 | ||
|
d01aefd1eb | ||
|
e1d447847f | ||
|
bed1c311e3 | ||
|
1ce8d3ae9b | ||
|
676d76696b | ||
|
1d18432f8d | ||
|
277f13ff9d | ||
|
2d365efe56 | ||
|
e81635f23d | ||
|
827315e059 | ||
|
e55a54f3d4 | ||
|
5e8b40faf6 | ||
|
45b9982172 | ||
|
9b267bb572 | ||
|
20c7bfaff2 | ||
|
dd29f970a2 | ||
|
1d87d9b370 | ||
|
40b6db6a27 | ||
|
9ba662a53e | ||
|
dc228c3dbb | ||
|
dd5dd422d1 | ||
|
73fdf4b957 | ||
|
a1de13657e | ||
|
93c19356d0 | ||
|
8a27c902ff | ||
|
be35b55444 | ||
|
a16ccf40c2 | ||
|
5c7b1cd5f2 | ||
|
fc5e593e2d | ||
|
f1dc79f0b5 | ||
|
34ea97dcea | ||
|
f2931163aa | ||
|
7e320d2748 | ||
|
45660902ed | ||
|
72318cb687 | ||
|
f277223a65 | ||
|
262fa74f5e | ||
|
ebdd221c72 | ||
|
2b8d162c9e | ||
|
dc8cf0e02e | ||
|
a054f6a97b | ||
|
63d11c3eea | ||
|
dd2199c472 | ||
|
661c3bbdb0 | ||
|
5236e81068 | ||
|
c459b5eb9d | ||
|
384f0fb89a | ||
|
1d628bcf9e | ||
|
b8644f49ec | ||
|
091c1f7ef1 | ||
|
c838c3fa73 | ||
|
8bb9106b42 | ||
|
a7e3b0d184 | ||
|
449c542d5a | ||
|
7f19f8cf0e | ||
|
b2eb704394 | ||
|
899da0c6ea | ||
|
def41a7878 | ||
|
6dbe49089e | ||
|
5883e5159f | ||
|
26a5d48f63 | ||
|
aa6feb4b62 | ||
|
2fef0ebea8 | ||
|
66dd51a09a | ||
|
077868604d | ||
|
6c555cb666 | ||
|
0ae80272fb | ||
|
7bef7cf9e2 | ||
|
6fa24cad18 | ||
|
6313020ba9 | ||
|
b2eead386d | ||
|
b826123d98 | ||
|
cf537070d8 | ||
|
7a00a1dced | ||
|
80c37ebab2 | ||
|
5fb4136bcd | ||
|
6a249ca1dd | ||
|
5610d4782f | ||
|
fef4574c3c | ||
|
65239c7c25 | ||
|
1b123054b3 | ||
|
b29d17f522 | ||
|
04aefbf28d | ||
|
f8fcf02448 | ||
|
0e4fd5269b | ||
|
6328496bfb | ||
|
524b40b75f | ||
|
0241552c0d | ||
|
fd3f6687ce | ||
|
93d63749e6 | ||
|
41bf5450d9 | ||
|
d37553e7b8 | ||
|
101d7138c2 | ||
|
11de3aed51 | ||
|
4bb41cf886 | ||
|
1ae7dd9b11 | ||
|
a3250fac6d | ||
|
fabe6317ef | ||
|
23a4af9a52 | ||
|
9526dbadad | ||
|
6ad469c637 | ||
|
b30cdf0873 | ||
|
234bc93ddb | ||
|
42862852b8 | ||
|
7a6101c417 | ||
|
588123ed11 | ||
|
ac9852f9df | ||
|
d093476da5 | ||
|
9ad794f2cc | ||
|
b0f566a80d | ||
|
d3f3a70350 | ||
|
3f262fe872 | ||
|
150c708726 | ||
|
7512dbffbb | ||
|
3cfa882fe1 | ||
|
35f3b7088d | ||
|
07220a324d | ||
|
c7cecd5b4f | ||
|
ab1a2045d9 | ||
|
5e9a067e87 | ||
|
4cc460be64 | ||
|
112bfccfd5 | ||
|
b29cb08956 | ||
|
e42ad9be24 | ||
|
02da1700e0 | ||
|
a9f97e1fe2 | ||
|
d75077c6f9 | ||
|
b81939f02d | ||
|
0e1d90dd0c | ||
|
03e9c612b9 | ||
|
f981c782bb | ||
|
3fbdb7a007 | ||
|
2997a15ba8 | ||
|
b4c02eca16 | ||
|
223dc87cef | ||
|
3ccdae0634 | ||
|
11af6f49c6 | ||
|
22dfedf6ae | ||
|
157d3f9dc9 | ||
|
f3b2ab5e60 | ||
|
fca53a0c2c | ||
|
6d302889fa | ||
|
a94ac63e74 | ||
|
19e73f8889 | ||
|
aacc26179e | ||
|
36f060dcf6 | ||
|
cb12c8dfd5 | ||
|
9cd1d1a9dc | ||
|
ebaf4c9c01 | ||
|
44240339d9 | ||
|
9110375173 | ||
|
c3557bbe3f | ||
|
cd924099e4 | ||
|
f2a311bb81 | ||
|
d7855e8fe5 | ||
|
1e52efa867 | ||
|
5d6f1bd2d7 | ||
|
48ccaa8b91 | ||
|
54ac0048c4 | ||
|
276e089419 | ||
|
3b8608761b | ||
|
413a91646c | ||
|
4299c6a802 | ||
|
4232923641 | ||
|
75b4bb306b | ||
|
4e0686f73c | ||
|
709f1e76d3 | ||
|
0c2d7b9c06 | ||
|
412e14a41c | ||
|
532b425dd9 | ||
|
2bb5fbdee5 | ||
|
38c41b72d6 | ||
|
30e89c3cdc | ||
|
b665014707 | ||
|
e98e7a232f | ||
|
5f7ad72d45 | ||
|
9c25365b12 | ||
|
0cc74b7cfe | ||
|
8a972ea213 | ||
|
2229bcc98b | ||
|
1bfd4672e1 | ||
|
15e9e8575a | ||
|
d7bafa6dfa | ||
|
35632f2109 | ||
|
08807b498e | ||
|
e8a453c567 | ||
|
717802611a | ||
|
b6a77e0231 | ||
|
21b966c8e6 | ||
|
64a1e88982 | ||
|
34c8b882c6 | ||
|
fa420d70cc | ||
|
2c67934191 | ||
|
821adcf178 | ||
|
8bf9482bc0 | ||
|
fe8ad3548b | ||
|
4f17bc0d86 | ||
|
1a43c81840 | ||
|
d3cf3f7a5c | ||
|
4f96a2a667 | ||
|
7b63ebfcaa | ||
|
724f3aa301 | ||
|
1ff326c89c | ||
|
2663f500cf | ||
|
43ed998ed6 | ||
|
a3032ab945 | ||
|
af9425ed8f | ||
|
d058ac6174 | ||
|
a4e7806d21 | ||
|
03906cc055 | ||
|
10833dcf39 | ||
|
a00323412b | ||
|
838a20ea95 | ||
|
e8ed8cbfcd | ||
|
5c78a5e4fe | ||
|
30ed4af38d | ||
|
6a9304dd1c | ||
|
1782eeb785 | ||
|
1aabb7d6de | ||
|
d4b8f9700b | ||
|
2ebecf1aa0 | ||
|
7031df4948 | ||
|
e0381dd757 | ||
|
9b2eae24d2 | ||
|
7362e8de4d | ||
|
87beb0a5f2 | ||
|
fc69cea4f7 | ||
|
ad4780a1ac | ||
|
72f487d2e3 | ||
|
0c10bd7dd7 | ||
|
b0418cb394 | ||
|
a30c81dadc | ||
|
40df6e87db | ||
|
0dff1dce8f | ||
|
ffd3b3e6b5 | ||
|
1305b0d8dd | ||
|
5fc41a3ea2 | ||
|
fc87fc7cab | ||
|
8887a0a6d3 | ||
|
ba7764aeaf | ||
|
28afe6f29f | ||
|
138ab6dbbd | ||
|
26c2fc21c8 | ||
|
fef74c3bca | ||
|
c390f1bfee | ||
|
f6698d4a84 | ||
|
4193196c8b | ||
|
da06dc3728 | ||
|
a0b8be5941 | ||
|
fe971680ea | ||
|
254eb8f304 | ||
|
c9d15901d1 | ||
|
59b3f5fb19 | ||
|
dbe9dd47ce | ||
|
8e35f8c3aa | ||
|
80970a0ac6 | ||
|
432f6ac4d7 | ||
|
eaf11009d1 | ||
|
df93fb773f | ||
|
f6887a4dac | ||
|
1c58c4c409 | ||
|
a972901438 | ||
|
25703296a6 | ||
|
7ebe97b931 | ||
|
76719d1bf5 | ||
|
cb113437f6 | ||
|
e6b3e42d61 | ||
|
c20b0169a9 | ||
|
89342bcb75 | ||
|
e036eea362 | ||
|
2044d633e9 | ||
|
8cb684e6bd | ||
|
997bd3392f | ||
|
ad44c87746 | ||
|
45ea2f82ba | ||
|
df6aa99ec2 | ||
|
1029dd3504 | ||
|
114eb6288d | ||
|
2ea37e6a0d | ||
|
ea2330b49f | ||
|
610bb2b85c | ||
|
fca6e9b932 | ||
|
fc7f86104e | ||
|
d057a9bb6d | ||
|
167aba6f26 | ||
|
9ecd84080b | ||
|
22d260f4e6 | ||
|
ea94477cd4 | ||
|
522c953860 | ||
|
f86ee84457 | ||
|
2d282597ca | ||
|
8635d89cc8 | ||
|
dc341ef9c1 | ||
|
beb31ab2fa | ||
|
e0214a2c2a | ||
|
5275daa66c | ||
|
fb27261568 | ||
|
5a20ce81e3 | ||
|
1454b85671 | ||
|
fc4dba4468 | ||
|
adff28dade | ||
|
c345ecae63 | ||
|
e6461380c6 | ||
|
deb2a3e415 | ||
|
c71dcd7611 | ||
|
c1e05664ed | ||
|
0f1e5f4fa4 | ||
|
8860915fb9 | ||
|
f0d486d1ff | ||
|
0fa20da990 | ||
|
b27767e8f4 | ||
|
0b2edd28df | ||
|
dd634382d7 | ||
|
c7fb155733 | ||
|
1eaa2cc619 | ||
|
92a47aaac5 | ||
|
fcffe8beb9 | ||
|
02fb40c507 | ||
|
dc6ea97877 | ||
|
031d53b04f | ||
|
3006c90fb8 | ||
|
9cec2688ed | ||
|
65c3dc21f4 | ||
|
cefa7d940a | ||
|
fab292d2de | ||
|
00bbe68f78 | ||
|
fa3591f4f2 | ||
|
10cfc6838d | ||
|
42e78f9a3e | ||
|
0122eabd44 | ||
|
435bb3f1d3 | ||
|
1d59d43286 | ||
|
fe30bf7d09 | ||
|
5f68ad4e19 | ||
|
3fc39aad33 | ||
|
a94653ba77 | ||
|
d8637b2c0f | ||
|
f1b6016157 | ||
|
de99d6d9fc | ||
|
bb8386ab85 | ||
|
ca6226359b | ||
|
adfafe5c54 | ||
|
a8d8fefceb | ||
|
3bb5943b20 | ||
|
57da04b5ec | ||
|
e711d168df | ||
|
833632eee3 | ||
|
abc76299c0 | ||
|
c96fcf319a | ||
|
5214a7c3ec | ||
|
1700f064b3 | ||
|
de902166a8 | ||
|
2f08bd1965 | ||
|
13c68cd799 | ||
|
c7d78f4594 | ||
|
2f1ca949f0 | ||
|
a6488ff9ac | ||
|
cb5eae888d | ||
|
b6f7710621 | ||
|
3e36f05a8c | ||
|
bcb7e5f2c8 | ||
|
3cefcd8204 | ||
|
4cd1871816 | ||
|
7aaa9583fa | ||
|
dd582c0306 | ||
|
5cded5b53e | ||
|
0a64567822 | ||
|
7ca861805d | ||
|
6b6faa8129 | ||
|
f84577bcda | ||
|
37f9fd3498 | ||
|
11aef82993 | ||
|
9861e2d724 | ||
|
7ae0d0caa3 | ||
|
93d2c9a3f0 | ||
|
60569fdd83 | ||
|
0f61e9c15e | ||
|
d81fc155cb | ||
|
60f7750d77 | ||
|
9bdfd8f4fe | ||
|
945b7de76f | ||
|
3c35eadbc4 | ||
|
ab86e056a2 | ||
|
a2bc79ddd5 | ||
|
51151293d7 | ||
|
5789e80d74 | ||
|
65868ab8a7 | ||
|
89586530a5 | ||
|
0d93145834 | ||
|
617f4acfd6 | ||
|
fe4113d623 | ||
|
9a0e15cced | ||
|
e0c63d58b2 | ||
|
f7f8ea9b97 | ||
|
58cad98cd8 | ||
|
2f8fb360aa | ||
|
05ec3922f1 | ||
|
1c9423ef31 | ||
|
74ffbb2172 | ||
|
cc9c85cc1a | ||
|
a8f252e45d | ||
|
b821836dc4 | ||
|
a42fef0905 | ||
|
f7e09af5c9 | ||
|
304cb56337 | ||
|
6b7b5caf54 | ||
|
fd461fe015 | ||
|
2797d2c535 | ||
|
f440656572 | ||
|
b1d019146a | ||
|
1dbc58d4e0 | ||
|
47ccb28482 | ||
|
744dea00ca | ||
|
373c2b379c | ||
|
95b51cf9e6 | ||
|
a375e924b4 | ||
|
957bbab440 | ||
|
bd48c99383 | ||
|
d989617825 | ||
|
177d9b7cb0 | ||
|
7a1305c1bb | ||
|
52d1d421a3 | ||
|
c3cc13595d | ||
|
adc8031e34 | ||
|
0974c74a89 | ||
|
c64aae6f39 | ||
|
b7b1714637 | ||
|
d8525493a1 | ||
|
30d0945855 | ||
|
ffde1f8343 | ||
|
96c35b41ed | ||
|
dc2979926f | ||
|
ff357dd3fb | ||
|
f35e15204d | ||
|
3ae4ba3300 | ||
|
8bb29f53d1 | ||
|
2e3c1ef4ac | ||
|
ada7e12b5a | ||
|
b8949ba3dd | ||
|
73fe47ba79 | ||
|
577920de86 | ||
|
0d8a314bcf | ||
|
e7cfde1904 | ||
|
517baa3235 | ||
|
aa41df4e7d | ||
|
d73953af3d | ||
|
54eec82311 | ||
|
dab244ad25 | ||
|
dbe7cb8dbb | ||
|
e814cccc44 | ||
|
1078fdc157 | ||
|
4bf4259dda | ||
|
03b53cbb60 | ||
|
7ef1340e2a | ||
|
c0b87adee5 | ||
|
4a8c2251e0 | ||
|
d1df5f3021 | ||
|
e1acea52f8 | ||
|
2e9f159225 | ||
|
2fcda9a73a | ||
|
78ba205f4d | ||
|
f44dec2c8d | ||
|
8c07af6fc7 | ||
|
cd01104de9 | ||
|
28f438a6bd | ||
|
9ff89b570f | ||
|
bc90376489 | ||
|
43b5ea801f | ||
|
9863e7ea6e | ||
|
ebaa39b03f | ||
|
fa3d7ad14b | ||
|
c51104f956 | ||
|
84795ff4d9 | ||
|
cc5c722e29 | ||
|
4fcddd1893 | ||
|
c8604255e4 | ||
|
492826a7f2 | ||
|
5e64781d65 | ||
|
2d4b900e33 | ||
|
d2481f5790 | ||
|
49f6104f03 | ||
|
2728d2aa6e | ||
|
0588fc6b7c | ||
|
e3cd52cab4 | ||
|
b2c6b9a320 | ||
|
39fa40ab12 | ||
|
0bf87bf4af | ||
|
92d37f6eaf | ||
|
d3b022fe17 | ||
|
79640f6b7d | ||
|
2cbdf274b1 | ||
|
6af5293315 | ||
|
bd3a2b1bb5 | ||
|
ff090d2f74 | ||
|
68e3a12a91 | ||
|
50eda6b678 | ||
|
192ec598a3 | ||
|
5b449999a5 | ||
|
afed62f6de | ||
|
59d1e16f9c | ||
|
dbe0d477d6 | ||
|
7248560169 | ||
|
f840f7d75b | ||
|
6e14a073ff | ||
|
cf3839ecec | ||
|
aa8cf76fb1 | ||
|
10b4bb598a | ||
|
de14d59bb3 | ||
|
d76272f0ea | ||
|
e04093efe2 | ||
|
bd6bbba948 | ||
|
37e4f35c93 | ||
|
0084cb7403 | ||
|
99e5c159a7 | ||
|
802121d54a | ||
|
160b2e95c9 | ||
|
7ec692cdef | ||
|
3dca67112d | ||
|
f8dac5905c | ||
|
48e4e41e05 | ||
|
22374b81de | ||
|
b9157e29cb | ||
|
bd247c35f2 | ||
|
7da9a45c61 | ||
|
122dfa12ac | ||
|
1905830b20 | ||
|
bfb41ce123 | ||
|
85e3ecfe0b | ||
|
9e073c954d | ||
|
b79c3f5cc4 | ||
|
ad5acb80fe | ||
|
7b7c834b08 | ||
|
42827be7c3 | ||
|
7022d27b8e | ||
|
ab911f1ce9 | ||
|
a6a1de50c8 | ||
|
97723fbbc9 | ||
|
2e58cf1168 | ||
|
3ca97d7258 | ||
|
9786dccdee | ||
|
a3612f53dd | ||
|
112257c49e | ||
|
d8e2b96bce | ||
|
6992659ba9 | ||
|
05696d443a | ||
|
f59a925897 | ||
|
afacdfcb95 | ||
|
8cb1b6b5d5 | ||
|
f7d9d53ad2 | ||
|
f4315e2c6f | ||
|
f0ac566c93 | ||
|
50f6a459cf | ||
|
179c80ae6d | ||
|
6e72f161a6 | ||
|
f71d8d7348 | ||
|
a12a3640a7 | ||
|
3b7bc5a56a | ||
|
e09d45c844 | ||
|
36fc321096 | ||
|
98a7a01dbb | ||
|
0f7be90500 | ||
|
7aaf4432d4 | ||
|
884a8995b4 | ||
|
bb42595275 | ||
|
a4bd89c938 | ||
|
f364d4fbef | ||
|
f899d0d8ed | ||
|
074cf00a7c | ||
|
15d10eeebc | ||
|
bea71f3411 | ||
|
eb99803b53 | ||
|
a60d0c4108 | ||
|
1cc3a13c49 | ||
|
feffbba6de | ||
|
6ea09444ec | ||
|
f1f486dacf | ||
|
fec4af3194 | ||
|
5342c7c82b | ||
|
8454ffa331 | ||
|
199977be6a | ||
|
00dbc3881f | ||
|
d93a5b2d20 | ||
|
8ca5ca6594 | ||
|
fe890c62f4 | ||
|
ed72b090af | ||
|
e15513bfdd | ||
|
dbe569c0d9 | ||
|
f2e1b589b5 | ||
|
377a37e4c9 | ||
|
6e163208b4 | ||
|
87a7bde618 | ||
|
37b0498699 | ||
|
59f976dc48 | ||
|
8565a853a8 | ||
|
dfd49e46ad | ||
|
73bbaced62 | ||
|
0c8870cb7f | ||
|
1a90f66f73 | ||
|
558e706bde | ||
|
1a08be0a3f | ||
|
29b2960805 | ||
|
f7f3a0bf0d | ||
|
ae4c186f55 | ||
|
af534a73fc | ||
|
772bbdc862 | ||
|
86521ec443 | ||
|
e3c4c9265d | ||
|
b3f8612e61 | ||
|
27b1dd04c4 | ||
|
46a876445f | ||
|
9bb58e47a7 | ||
|
b8447fcab8 | ||
|
3abcfd8fa9 | ||
|
f4ff2d5d2e | ||
|
09b41aa667 | ||
|
87dc4fe388 | ||
|
eed8a7f078 | ||
|
c18364c755 | ||
|
04946e992e | ||
|
5533782152 | ||
|
3f42487f0a | ||
|
8bdcd22486 | ||
|
b32d22731b | ||
|
b788cc24d1 | ||
|
94948f6d34 | ||
|
e5b76ed4c4 | ||
|
29a2920a2c | ||
|
089d35708b | ||
|
9b0b5bce9f | ||
|
ef20a0128f | ||
|
3039e4eb6d | ||
|
9143cd1485 | ||
|
13d31ecb7f | ||
|
a936b2f1f6 | ||
|
8d00f489cd | ||
|
b793dbf977 | ||
|
d52b38777a | ||
|
56cf93dff2 | ||
|
67d84cadad | ||
|
b384a24c0e | ||
|
66a68edbe6 | ||
|
dcf3d7234e | ||
|
0da839cce3 | ||
|
b6f62ac446 | ||
|
15ee036db1 | ||
|
6db8ae451a | ||
|
a7f3d413ef | ||
|
3b7be478aa | ||
|
7f39cdc856 | ||
|
80006f4730 | ||
|
a51025fe8f | ||
|
c42ed9c693 | ||
|
c48c8d07de | ||
|
4d4b6edbc2 | ||
|
2014ca9feb | ||
|
a9f631f404 | ||
|
ba468bb5e4 | ||
|
cf86d57a9f | ||
|
9e958f4e32 | ||
|
c7f6f20c9d | ||
|
1984f44ffe | ||
|
02de281e40 | ||
|
ae035deb92 | ||
|
edd1b60c3d | ||
|
55a3709bd1 | ||
|
d1fc01a407 | ||
|
65293f81d9 | ||
|
0afb0f7958 | ||
|
dd958872a8 | ||
|
62a2ce1d35 | ||
|
b556908cab | ||
|
e69a19db5c | ||
|
d86414febb | ||
|
832318fab1 | ||
|
80ad62ff56 | ||
|
ee50f254df | ||
|
cc0be6cd90 | ||
|
a7455d7edd | ||
|
b7c370fff7 | ||
|
8fd3a64e35 | ||
|
3761fb4377 | ||
|
0472f5da6a | ||
|
09041fb81d | ||
|
299a157409 | ||
|
53ede7b0d8 | ||
|
cd13aee3e7 | ||
|
8b3acb719e | ||
|
2961a90e7f | ||
|
db8a2d0c65 | ||
|
a6b5f0c9d4 | ||
|
8d136c6a25 | ||
|
4d94270cde | ||
|
e0d96bcb39 | ||
|
0d7b831661 | ||
|
0c9e4f67a8 | ||
|
da2c386b60 | ||
|
4770364d42 | ||
|
db3f131dfc | ||
|
d7f58c64f8 | ||
|
41b6aebe7c | ||
|
7d50332246 | ||
|
0d0478245f | ||
|
f680ede980 | ||
|
d108072bfb | ||
|
8cc7c5349a | ||
|
fb33ea2a0b | ||
|
63fca33b04 | ||
|
0548ad2fc6 | ||
|
623d615cd7 | ||
|
126df9647b | ||
|
2e2e7cd054 | ||
|
0ebc9f7a44 | ||
|
a8fba65cbd | ||
|
0b0476e196 | ||
|
f99d6dac08 | ||
|
cd2b7cd943 | ||
|
af759f2330 | ||
|
bb5f3cc326 | ||
|
7623025b90 | ||
|
56c98e9295 | ||
|
df753e2619 | ||
|
cbb7082afd | ||
|
6ee72e119c | ||
|
778ee02803 | ||
|
b3529dc748 | ||
|
13c7182948 | ||
|
edc76795d4 | ||
|
ed56d52af3 | ||
|
fb457968ec | ||
|
0bea2e2b94 | ||
|
72d02f442e | ||
|
bcf63b5d27 | ||
|
92dbe6cdf8 | ||
|
0781e8cf12 | ||
|
b71a088da7 | ||
|
d76fb566a2 | ||
|
24a40af103 | ||
|
4a60292f82 | ||
|
7eea866869 | ||
|
4ab5456a98 | ||
|
8881a9f40e |
92
.github/workflows/DNS.yml
vendored
92
.github/workflows/DNS.yml
vendored
@ -1,5 +1,6 @@
|
||||
name: DNS
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
paths:
|
||||
- 'dnsapi/*.sh'
|
||||
@ -65,7 +66,7 @@ jobs:
|
||||
TokenName4: ${{ secrets.TokenName4}}
|
||||
TokenName5: ${{ secrets.TokenName5}}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Clone acmetest
|
||||
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- name: Set env file
|
||||
@ -113,7 +114,7 @@ jobs:
|
||||
TokenName4: ${{ secrets.TokenName4}}
|
||||
TokenName5: ${{ secrets.TokenName5}}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install tools
|
||||
run: brew install socat
|
||||
- name: Clone acmetest
|
||||
@ -164,7 +165,7 @@ jobs:
|
||||
- name: Set git to use LF
|
||||
run: |
|
||||
git config --global core.autocrlf false
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install cygwin base packages with chocolatey
|
||||
run: |
|
||||
choco config get cacheLocation
|
||||
@ -204,7 +205,7 @@ jobs:
|
||||
|
||||
|
||||
FreeBSD:
|
||||
runs-on: macos-12
|
||||
runs-on: ubuntu-latest
|
||||
needs: Windows
|
||||
env:
|
||||
TEST_DNS : ${{ secrets.TEST_DNS }}
|
||||
@ -223,10 +224,10 @@ jobs:
|
||||
TokenName4: ${{ secrets.TokenName4}}
|
||||
TokenName5: ${{ secrets.TokenName5}}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Clone acmetest
|
||||
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- uses: vmactions/freebsd-vm@v0
|
||||
- uses: vmactions/freebsd-vm@v1
|
||||
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 socat curl
|
||||
@ -255,7 +256,7 @@ jobs:
|
||||
|
||||
|
||||
OpenBSD:
|
||||
runs-on: macos-12
|
||||
runs-on: ubuntu-latest
|
||||
needs: FreeBSD
|
||||
env:
|
||||
TEST_DNS : ${{ secrets.TEST_DNS }}
|
||||
@ -274,13 +275,13 @@ jobs:
|
||||
TokenName4: ${{ secrets.TokenName4}}
|
||||
TokenName5: ${{ secrets.TokenName5}}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- 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
|
||||
- uses: vmactions/openbsd-vm@v1
|
||||
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 socat curl
|
||||
prepare: pkg_add socat curl libiconv
|
||||
usesh: true
|
||||
copyback: false
|
||||
run: |
|
||||
@ -306,7 +307,7 @@ jobs:
|
||||
|
||||
|
||||
NetBSD:
|
||||
runs-on: macos-12
|
||||
runs-on: ubuntu-latest
|
||||
needs: OpenBSD
|
||||
env:
|
||||
TEST_DNS : ${{ secrets.TEST_DNS }}
|
||||
@ -325,14 +326,14 @@ jobs:
|
||||
TokenName4: ${{ secrets.TokenName4}}
|
||||
TokenName5: ${{ secrets.TokenName5}}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- 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
|
||||
- uses: vmactions/netbsd-vm@v1
|
||||
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
|
||||
/usr/sbin/pkg_add curl socat
|
||||
usesh: true
|
||||
copyback: false
|
||||
run: |
|
||||
@ -358,7 +359,7 @@ jobs:
|
||||
|
||||
|
||||
DragonFlyBSD:
|
||||
runs-on: macos-12
|
||||
runs-on: ubuntu-latest
|
||||
needs: NetBSD
|
||||
env:
|
||||
TEST_DNS : ${{ secrets.TEST_DNS }}
|
||||
@ -377,14 +378,14 @@ jobs:
|
||||
TokenName4: ${{ secrets.TokenName4}}
|
||||
TokenName5: ${{ secrets.TokenName5}}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- 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
|
||||
- uses: vmactions/dragonflybsd-vm@v1
|
||||
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
|
||||
pkg install -y curl socat libnghttp2
|
||||
usesh: true
|
||||
copyback: false
|
||||
run: |
|
||||
@ -413,7 +414,7 @@ jobs:
|
||||
|
||||
|
||||
Solaris:
|
||||
runs-on: macos-12
|
||||
runs-on: ubuntu-latest
|
||||
needs: DragonFlyBSD
|
||||
env:
|
||||
TEST_DNS : ${{ secrets.TEST_DNS }}
|
||||
@ -433,10 +434,10 @@ jobs:
|
||||
TokenName4: ${{ secrets.TokenName4}}
|
||||
TokenName5: ${{ secrets.TokenName5}}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- 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
|
||||
- uses: vmactions/solaris-vm@v1
|
||||
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
|
||||
@ -463,3 +464,52 @@ jobs:
|
||||
./letest.sh
|
||||
|
||||
|
||||
Omnios:
|
||||
runs-on: ubuntu-latest
|
||||
needs: Solaris
|
||||
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 Omnios 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@v4
|
||||
- name: Clone acmetest
|
||||
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- uses: vmactions/omnios-vm@v1
|
||||
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: pkg install socat
|
||||
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
|
||||
|
||||
|
||||
|
142
.github/workflows/DragonFlyBSD.yml
vendored
142
.github/workflows/DragonFlyBSD.yml
vendored
@ -1,71 +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
|
||||
|
||||
|
||||
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)
|
||||
#- 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: ubuntu-latest
|
||||
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@v4
|
||||
- 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@v1
|
||||
with:
|
||||
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 curl socat libnghttp2
|
||||
usesh: true
|
||||
copyback: false
|
||||
run: |
|
||||
cd ../acmetest \
|
||||
&& ./letest.sh
|
||||
|
||||
|
||||
|
10
.github/workflows/FreeBSD.yml
vendored
10
.github/workflows/FreeBSD.yml
vendored
@ -29,19 +29,19 @@ jobs:
|
||||
CA_ECDSA: ""
|
||||
CA: ""
|
||||
CA_EMAIL: ""
|
||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
||||
TEST_PREFERRED_CHAIN: (STAGING)
|
||||
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
||||
CA_ECDSA: ""
|
||||
CA: ""
|
||||
CA_EMAIL: ""
|
||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
||||
TEST_PREFERRED_CHAIN: (STAGING)
|
||||
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
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TEST_LOCAL: 1
|
||||
TEST_ACME_Server: ${{ matrix.TEST_ACME_Server }}
|
||||
@ -51,7 +51,7 @@ jobs:
|
||||
TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
|
||||
ACME_USE_WGET: ${{ matrix.ACME_USE_WGET }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: vmactions/cf-tunnel@v0
|
||||
id: tunnel
|
||||
with:
|
||||
@ -61,7 +61,7 @@ jobs:
|
||||
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/freebsd-vm@v0
|
||||
- uses: vmactions/freebsd-vm@v1
|
||||
with:
|
||||
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
|
||||
nat: |
|
||||
|
6
.github/workflows/Linux.yml
vendored
6
.github/workflows/Linux.yml
vendored
@ -26,14 +26,14 @@ jobs:
|
||||
Linux:
|
||||
strategy:
|
||||
matrix:
|
||||
os: ["ubuntu:latest", "debian:latest", "almalinux:latest", "fedora:latest", "centos:7", "opensuse/leap:latest", "alpine:latest", "oraclelinux:8", "kalilinux/kali", "archlinux:latest", "mageia", "gentoo/stage3"]
|
||||
os: ["ubuntu:latest", "debian:latest", "almalinux:latest", "fedora:latest", "opensuse/leap:latest", "alpine:latest", "oraclelinux:8", "kalilinux/kali", "archlinux:latest", "mageia", "gentoo/stage3"]
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TEST_LOCAL: 1
|
||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
||||
TEST_PREFERRED_CHAIN: (STAGING)
|
||||
TEST_ACME_Server: "LetsEncrypt.org_test"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Clone acmetest
|
||||
run: |
|
||||
cd .. \
|
||||
|
4
.github/workflows/MacOS.yml
vendored
4
.github/workflows/MacOS.yml
vendored
@ -29,7 +29,7 @@ jobs:
|
||||
CA_ECDSA: ""
|
||||
CA: ""
|
||||
CA_EMAIL: ""
|
||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
||||
TEST_PREFERRED_CHAIN: (STAGING)
|
||||
#- TEST_ACME_Server: "ZeroSSL.com"
|
||||
# CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
|
||||
# CA: "ZeroSSL RSA Domain Secure Site CA"
|
||||
@ -44,7 +44,7 @@ jobs:
|
||||
CA_EMAIL: ${{ matrix.CA_EMAIL }}
|
||||
TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install tools
|
||||
run: brew install socat
|
||||
- name: Clone acmetest
|
||||
|
142
.github/workflows/NetBSD.yml
vendored
142
.github/workflows/NetBSD.yml
vendored
@ -1,71 +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
|
||||
|
||||
|
||||
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)
|
||||
#- 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: ubuntu-latest
|
||||
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@v4
|
||||
- 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@v1
|
||||
with:
|
||||
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
|
||||
nat: |
|
||||
"8080": "80"
|
||||
prepare: |
|
||||
/usr/sbin/pkg_add curl socat
|
||||
usesh: true
|
||||
copyback: false
|
||||
run: |
|
||||
cd ../acmetest \
|
||||
&& ./letest.sh
|
||||
|
||||
|
||||
|
75
.github/workflows/Omnios.yml
vendored
Normal file
75
.github/workflows/Omnios.yml
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
name: Omnios
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
paths:
|
||||
- '*.sh'
|
||||
- '.github/workflows/Omnios.yml'
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
paths:
|
||||
- '*.sh'
|
||||
- '.github/workflows/Omnios.yml'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
|
||||
|
||||
jobs:
|
||||
Omnios:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
||||
CA_ECDSA: ""
|
||||
CA: ""
|
||||
CA_EMAIL: ""
|
||||
TEST_PREFERRED_CHAIN: (STAGING)
|
||||
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
||||
CA_ECDSA: ""
|
||||
CA: ""
|
||||
CA_EMAIL: ""
|
||||
TEST_PREFERRED_CHAIN: (STAGING)
|
||||
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: ubuntu-latest
|
||||
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@v4
|
||||
- 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/omnios-vm@v1
|
||||
with:
|
||||
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
|
||||
nat: |
|
||||
"8080": "80"
|
||||
prepare: pkg install socat wget
|
||||
copyback: false
|
||||
run: |
|
||||
cd ../acmetest \
|
||||
&& ./letest.sh
|
||||
|
||||
|
12
.github/workflows/OpenBSD.yml
vendored
12
.github/workflows/OpenBSD.yml
vendored
@ -29,19 +29,19 @@ jobs:
|
||||
CA_ECDSA: ""
|
||||
CA: ""
|
||||
CA_EMAIL: ""
|
||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
||||
TEST_PREFERRED_CHAIN: (STAGING)
|
||||
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
||||
CA_ECDSA: ""
|
||||
CA: ""
|
||||
CA_EMAIL: ""
|
||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
||||
TEST_PREFERRED_CHAIN: (STAGING)
|
||||
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
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TEST_LOCAL: 1
|
||||
TEST_ACME_Server: ${{ matrix.TEST_ACME_Server }}
|
||||
@ -51,7 +51,7 @@ jobs:
|
||||
TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
|
||||
ACME_USE_WGET: ${{ matrix.ACME_USE_WGET }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: vmactions/cf-tunnel@v0
|
||||
id: tunnel
|
||||
with:
|
||||
@ -61,12 +61,12 @@ jobs:
|
||||
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
|
||||
- uses: vmactions/openbsd-vm@v1
|
||||
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
|
||||
prepare: pkg_add socat curl wget libnghttp2
|
||||
usesh: true
|
||||
copyback: false
|
||||
run: |
|
||||
|
6
.github/workflows/PebbleStrict.yml
vendored
6
.github/workflows/PebbleStrict.yml
vendored
@ -33,11 +33,11 @@ jobs:
|
||||
TEST_CA: "Pebble Intermediate CA"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- 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: cd .. && curl https://raw.githubusercontent.com/letsencrypt/pebble/master/docker-compose.yml >docker-compose.yml && docker compose up -d
|
||||
- name: Set up Pebble
|
||||
run: curl --request POST --data '{"ip":"10.30.50.1"}' http://localhost:8055/set-default-ipv4
|
||||
- name: Clone acmetest
|
||||
@ -58,7 +58,7 @@ jobs:
|
||||
TEST_IPCERT: 1
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install tools
|
||||
run: sudo apt-get install -y socat
|
||||
- name: Run Pebble
|
||||
|
149
.github/workflows/Solaris.yml
vendored
149
.github/workflows/Solaris.yml
vendored
@ -1,74 +1,75 @@
|
||||
name: Solaris
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
paths:
|
||||
- '*.sh'
|
||||
- '.github/workflows/Solaris.yml'
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
paths:
|
||||
- '*.sh'
|
||||
- '.github/workflows/Solaris.yml'
|
||||
|
||||
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
Solaris:
|
||||
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/solaris-vm@v0
|
||||
with:
|
||||
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 wget
|
||||
run: |
|
||||
cd ../acmetest \
|
||||
&& ./letest.sh
|
||||
|
||||
name: Solaris
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
paths:
|
||||
- '*.sh'
|
||||
- '.github/workflows/Solaris.yml'
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
paths:
|
||||
- '*.sh'
|
||||
- '.github/workflows/Solaris.yml'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
|
||||
|
||||
jobs:
|
||||
Solaris:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
||||
CA_ECDSA: ""
|
||||
CA: ""
|
||||
CA_EMAIL: ""
|
||||
TEST_PREFERRED_CHAIN: (STAGING)
|
||||
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
||||
CA_ECDSA: ""
|
||||
CA: ""
|
||||
CA_EMAIL: ""
|
||||
TEST_PREFERRED_CHAIN: (STAGING)
|
||||
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: ubuntu-latest
|
||||
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@v4
|
||||
- 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/solaris-vm@v1
|
||||
with:
|
||||
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
|
||||
nat: |
|
||||
"8080": "80"
|
||||
prepare: pkgutil -y -i socat curl wget
|
||||
copyback: false
|
||||
run: |
|
||||
cd ../acmetest \
|
||||
&& ./letest.sh
|
||||
|
||||
|
||||
|
6
.github/workflows/Ubuntu.yml
vendored
6
.github/workflows/Ubuntu.yml
vendored
@ -29,12 +29,12 @@ jobs:
|
||||
CA_ECDSA: ""
|
||||
CA: ""
|
||||
CA_EMAIL: ""
|
||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
||||
TEST_PREFERRED_CHAIN: (STAGING)
|
||||
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
||||
CA_ECDSA: ""
|
||||
CA: ""
|
||||
CA_EMAIL: ""
|
||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
||||
TEST_PREFERRED_CHAIN: (STAGING)
|
||||
ACME_USE_WGET: 1
|
||||
- TEST_ACME_Server: "ZeroSSL.com"
|
||||
CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
|
||||
@ -70,7 +70,7 @@ jobs:
|
||||
TestingDomain: ${{ matrix.TestingDomain }}
|
||||
ACME_USE_WGET: ${{ matrix.ACME_USE_WGET }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install tools
|
||||
run: sudo apt-get install -y socat wget
|
||||
- name: Start StepCA
|
||||
|
4
.github/workflows/Windows.yml
vendored
4
.github/workflows/Windows.yml
vendored
@ -29,7 +29,7 @@ jobs:
|
||||
CA_ECDSA: ""
|
||||
CA: ""
|
||||
CA_EMAIL: ""
|
||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
||||
TEST_PREFERRED_CHAIN: (STAGING)
|
||||
#- TEST_ACME_Server: "ZeroSSL.com"
|
||||
# CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
|
||||
# CA: "ZeroSSL RSA Domain Secure Site CA"
|
||||
@ -49,7 +49,7 @@ jobs:
|
||||
- name: Set git to use LF
|
||||
run: |
|
||||
git config --global core.autocrlf false
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install cygwin base packages with chocolatey
|
||||
run: |
|
||||
choco config get cacheLocation
|
||||
|
19
.github/workflows/dockerhub.yml
vendored
19
.github/workflows/dockerhub.yml
vendored
@ -15,6 +15,8 @@ concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
DOCKER_IMAGE: neilpang/acme.sh
|
||||
|
||||
jobs:
|
||||
CheckToken:
|
||||
@ -41,9 +43,16 @@ jobs:
|
||||
if: "contains(needs.CheckToken.outputs.hasToken, 'true')"
|
||||
steps:
|
||||
- name: checkout code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Extract Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5.5.1
|
||||
with:
|
||||
images: ${DOCKER_IMAGE}
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: login to docker hub
|
||||
@ -51,8 +60,6 @@ jobs:
|
||||
echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
|
||||
- name: build and push the image
|
||||
run: |
|
||||
DOCKER_IMAGE=neilpang/acme.sh
|
||||
|
||||
if [[ $GITHUB_REF == refs/tags/* ]]; then
|
||||
DOCKER_IMAGE_TAG=${GITHUB_REF#refs/tags/}
|
||||
fi
|
||||
@ -66,8 +73,14 @@ jobs:
|
||||
fi
|
||||
fi
|
||||
|
||||
DOCKER_LABELS=()
|
||||
while read -r label; do
|
||||
DOCKER_LABELS+=(--label "${label}")
|
||||
done <<<"${DOCKER_METADATA_OUTPUT_LABELS}"
|
||||
|
||||
docker buildx build \
|
||||
--tag ${DOCKER_IMAGE}:${DOCKER_IMAGE_TAG} \
|
||||
"${DOCKER_LABELS[@]}" \
|
||||
--output "type=image,push=true" \
|
||||
--build-arg AUTO_UPGRADE=${AUTO_UPGRADE} \
|
||||
--platform linux/arm64/v8,linux/amd64,linux/arm/v6,linux/arm/v7,linux/386,linux/ppc64le,linux/s390x .
|
||||
|
13
.github/workflows/pr_dns.yml
vendored
13
.github/workflows/pr_dns.yml
vendored
@ -4,8 +4,6 @@ on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
branches:
|
||||
- 'dev'
|
||||
paths:
|
||||
- 'dnsapi/*.sh'
|
||||
|
||||
@ -22,9 +20,14 @@ jobs:
|
||||
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 ✨
|
||||
READ ME !!!!!
|
||||
Read me !!!!!!
|
||||
First thing: don't send PR to the master branch, please send to the dev branch instead.
|
||||
Please read the [DNS API Dev Guide](../wiki/DNS-API-Dev-Guide).
|
||||
You MUST pass the [DNS-API-Test](../wiki/DNS-API-Test).
|
||||
Then reply on this message, otherwise, your code will not be reviewed or merged.
|
||||
Please also make sure to add/update the usage here: https://github.com/acmesh-official/acme.sh/wiki/dnsapi2
|
||||
注意: 必须通过了 [DNS-API-Test](../wiki/DNS-API-Test) 才会被 review. 无论是修改, 还是新加的 dns api, 都必须确保通过这个测试.
|
||||
`
|
||||
})
|
||||
|
||||
|
4
.github/workflows/pr_notify.yml
vendored
4
.github/workflows/pr_notify.yml
vendored
@ -1,4 +1,4 @@
|
||||
name: Check dns api
|
||||
name: Check notify api
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
@ -22,7 +22,7 @@ jobs:
|
||||
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).
|
||||
Please make sure you've 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 ✨
|
||||
`
|
||||
|
4
.github/workflows/shellcheck.yml
vendored
4
.github/workflows/shellcheck.yml
vendored
@ -22,7 +22,7 @@ jobs:
|
||||
ShellCheck:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install Shellcheck
|
||||
run: sudo apt-get install -y shellcheck
|
||||
- name: DoShellcheck
|
||||
@ -31,7 +31,7 @@ jobs:
|
||||
shfmt:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- 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.17
|
||||
FROM alpine:3.21
|
||||
|
||||
RUN apk --no-cache add -f \
|
||||
openssl \
|
||||
@ -15,14 +15,18 @@ RUN apk --no-cache add -f \
|
||||
jq \
|
||||
cronie
|
||||
|
||||
ENV LE_CONFIG_HOME /acme.sh
|
||||
ENV LE_CONFIG_HOME=/acme.sh
|
||||
|
||||
ARG AUTO_UPGRADE=1
|
||||
|
||||
ENV AUTO_UPGRADE $AUTO_UPGRADE
|
||||
ENV AUTO_UPGRADE=$AUTO_UPGRADE
|
||||
|
||||
#Install
|
||||
COPY ./ /install_acme.sh/
|
||||
COPY ./acme.sh /install_acme.sh/acme.sh
|
||||
COPY ./deploy /install_acme.sh/deploy
|
||||
COPY ./dnsapi /install_acme.sh/dnsapi
|
||||
COPY ./notify /install_acme.sh/notify
|
||||
|
||||
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/
|
||||
|
||||
|
||||
|
35
README.md
35
README.md
@ -8,7 +8,7 @@
|
||||
[](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)
|
||||
|
||||
[](https://github.com/acmesh-official/acme.sh/actions/workflows/Omnios.yml)
|
||||
|
||||

|
||||

|
||||
@ -73,20 +73,21 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa)
|
||||
|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)
|
||||
|10|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Omnios.yml)|Omnios
|
||||
|11|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)| Debian
|
||||
|12|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|CentOS
|
||||
|13|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|openSUSE
|
||||
|14|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Alpine Linux (with curl)
|
||||
|15|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Archlinux
|
||||
|16|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|fedora
|
||||
|17|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Kali Linux
|
||||
|18|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Oracle Linux
|
||||
|19|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Mageia
|
||||
|10|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Gentoo Linux
|
||||
|11|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|ClearLinux
|
||||
|22|-----| Cloud Linux https://github.com/acmesh-official/acme.sh/issues/111
|
||||
|23|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/acmesh-official/acme.sh/wiki/How-to-run-on-OpenWRT)
|
||||
|24|[](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):
|
||||
@ -506,10 +507,6 @@ Support this project with your organization. Your logo will show up here with 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
|
||||
|
||||
|
88
deploy/ali_cdn.sh
Normal file
88
deploy/ali_cdn.sh
Normal file
@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034,SC2154
|
||||
|
||||
# Script to create certificate to Alibaba Cloud CDN
|
||||
#
|
||||
# Docs: https://github.com/acmesh-official/acme.sh/wiki/deployhooks#33-deploy-your-certificate-to-cdn-or-dcdn-of-alibaba-cloud-aliyun
|
||||
#
|
||||
# This deployment required following variables
|
||||
# export Ali_Key="ALIACCESSKEY"
|
||||
# export Ali_Secret="ALISECRETKEY"
|
||||
# The credentials are shared with all the Alibaba Cloud deploy hooks and dnsapi
|
||||
#
|
||||
# To specify the CDN domain that is different from the certificate CN, usually used for multi-domain or wildcard certificates
|
||||
# export DEPLOY_ALI_CDN_DOMAIN="cdn.example.com"
|
||||
# If you have multiple CDN domains using the same certificate, just
|
||||
# export DEPLOY_ALI_CDN_DOMAIN="cdn1.example.com cdn2.example.com"
|
||||
#
|
||||
# For DCDN, see ali_dcdn deploy hook
|
||||
|
||||
Ali_CDN_API="https://cdn.aliyuncs.com/"
|
||||
|
||||
ali_cdn_deploy() {
|
||||
_cdomain="$1"
|
||||
_ckey="$2"
|
||||
_ccert="$3"
|
||||
_cca="$4"
|
||||
_cfullchain="$5"
|
||||
|
||||
_debug _cdomain "$_cdomain"
|
||||
_debug _ckey "$_ckey"
|
||||
_debug _ccert "$_ccert"
|
||||
_debug _cca "$_cca"
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
# Load dnsapi/dns_ali.sh to reduce the duplicated codes
|
||||
# https://github.com/acmesh-official/acme.sh/pull/5205#issuecomment-2357867276
|
||||
dnsapi_ali="$(_findHook "$_cdomain" "$_SUB_FOLDER_DNSAPI" dns_ali)"
|
||||
# shellcheck source=/dev/null
|
||||
if ! . "$dnsapi_ali"; then
|
||||
_err "Error loading file $dnsapi_ali. Please check your API file and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_prepare_ali_credentials || return 1
|
||||
|
||||
_getdeployconf DEPLOY_ALI_CDN_DOMAIN
|
||||
if [ "$DEPLOY_ALI_CDN_DOMAIN" ]; then
|
||||
_savedeployconf DEPLOY_ALI_CDN_DOMAIN "$DEPLOY_ALI_CDN_DOMAIN"
|
||||
else
|
||||
DEPLOY_ALI_CDN_DOMAIN="$_cdomain"
|
||||
fi
|
||||
|
||||
# read cert and key files and urlencode both
|
||||
_cert=$(_url_encode upper-hex <"$_cfullchain")
|
||||
_key=$(_url_encode upper-hex <"$_ckey")
|
||||
|
||||
_debug2 _cert "$_cert"
|
||||
_debug2 _key "$_key"
|
||||
|
||||
## update domain ssl config
|
||||
for domain in $DEPLOY_ALI_CDN_DOMAIN; do
|
||||
_set_cdn_domain_ssl_certificate_query "$domain" "$_cert" "$_key"
|
||||
if _ali_rest "Set CDN domain SSL certificate for $domain" "" POST; then
|
||||
_info "Domain $domain certificate has been deployed successfully"
|
||||
fi
|
||||
done
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# domain pub pri
|
||||
_set_cdn_domain_ssl_certificate_query() {
|
||||
endpoint=$Ali_CDN_API
|
||||
query=''
|
||||
query=$query'AccessKeyId='$Ali_Key
|
||||
query=$query'&Action=SetCdnDomainSSLCertificate'
|
||||
query=$query'&CertType=upload'
|
||||
query=$query'&DomainName='$1
|
||||
query=$query'&Format=json'
|
||||
query=$query'&SSLPri='$3
|
||||
query=$query'&SSLProtocol=on'
|
||||
query=$query'&SSLPub='$2
|
||||
query=$query'&SignatureMethod=HMAC-SHA1'
|
||||
query=$query"&SignatureNonce=$(_ali_nonce)"
|
||||
query=$query'&SignatureVersion=1.0'
|
||||
query=$query'&Timestamp='$(_timestamp)
|
||||
query=$query'&Version=2018-05-10'
|
||||
}
|
88
deploy/ali_dcdn.sh
Normal file
88
deploy/ali_dcdn.sh
Normal file
@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034,SC2154
|
||||
|
||||
# Script to create certificate to Alibaba Cloud DCDN
|
||||
#
|
||||
# Docs: https://github.com/acmesh-official/acme.sh/wiki/deployhooks#33-deploy-your-certificate-to-cdn-or-dcdn-of-alibaba-cloud-aliyun
|
||||
#
|
||||
# This deployment required following variables
|
||||
# export Ali_Key="ALIACCESSKEY"
|
||||
# export Ali_Secret="ALISECRETKEY"
|
||||
# The credentials are shared with all the Alibaba Cloud deploy hooks and dnsapi
|
||||
#
|
||||
# To specify the DCDN domain that is different from the certificate CN, usually used for multi-domain or wildcard certificates
|
||||
# export DEPLOY_ALI_DCDN_DOMAIN="dcdn.example.com"
|
||||
# If you have multiple CDN domains using the same certificate, just
|
||||
# export DEPLOY_ALI_DCDN_DOMAIN="dcdn1.example.com dcdn2.example.com"
|
||||
#
|
||||
# For regular CDN, see ali_cdn deploy hook
|
||||
|
||||
Ali_DCDN_API="https://dcdn.aliyuncs.com/"
|
||||
|
||||
ali_dcdn_deploy() {
|
||||
_cdomain="$1"
|
||||
_ckey="$2"
|
||||
_ccert="$3"
|
||||
_cca="$4"
|
||||
_cfullchain="$5"
|
||||
|
||||
_debug _cdomain "$_cdomain"
|
||||
_debug _ckey "$_ckey"
|
||||
_debug _ccert "$_ccert"
|
||||
_debug _cca "$_cca"
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
# Load dnsapi/dns_ali.sh to reduce the duplicated codes
|
||||
# https://github.com/acmesh-official/acme.sh/pull/5205#issuecomment-2357867276
|
||||
dnsapi_ali="$(_findHook "$_cdomain" "$_SUB_FOLDER_DNSAPI" dns_ali)"
|
||||
# shellcheck source=/dev/null
|
||||
if ! . "$dnsapi_ali"; then
|
||||
_err "Error loading file $dnsapi_ali. Please check your API file and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_prepare_ali_credentials || return 1
|
||||
|
||||
_getdeployconf DEPLOY_ALI_DCDN_DOMAIN
|
||||
if [ "$DEPLOY_ALI_DCDN_DOMAIN" ]; then
|
||||
_savedeployconf DEPLOY_ALI_DCDN_DOMAIN "$DEPLOY_ALI_DCDN_DOMAIN"
|
||||
else
|
||||
DEPLOY_ALI_DCDN_DOMAIN="$_cdomain"
|
||||
fi
|
||||
|
||||
# read cert and key files and urlencode both
|
||||
_cert=$(_url_encode upper-hex <"$_cfullchain")
|
||||
_key=$(_url_encode upper-hex <"$_ckey")
|
||||
|
||||
_debug2 _cert "$_cert"
|
||||
_debug2 _key "$_key"
|
||||
|
||||
## update domain ssl config
|
||||
for domain in $DEPLOY_ALI_DCDN_DOMAIN; do
|
||||
_set_dcdn_domain_ssl_certificate_query "$domain" "$_cert" "$_key"
|
||||
if _ali_rest "Set DCDN domain SSL certificate for $domain" "" POST; then
|
||||
_info "Domain $domain certificate has been deployed successfully"
|
||||
fi
|
||||
done
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# domain pub pri
|
||||
_set_dcdn_domain_ssl_certificate_query() {
|
||||
endpoint=$Ali_DCDN_API
|
||||
query=''
|
||||
query=$query'AccessKeyId='$Ali_Key
|
||||
query=$query'&Action=SetDcdnDomainSSLCertificate'
|
||||
query=$query'&CertType=upload'
|
||||
query=$query'&DomainName='$1
|
||||
query=$query'&Format=json'
|
||||
query=$query'&SSLPri='$3
|
||||
query=$query'&SSLProtocol=on'
|
||||
query=$query'&SSLPub='$2
|
||||
query=$query'&SignatureMethod=HMAC-SHA1'
|
||||
query=$query"&SignatureNonce=$(_ali_nonce)"
|
||||
query=$query'&SignatureVersion=1.0'
|
||||
query=$query'&Timestamp='$(_timestamp)
|
||||
query=$query'&Version=2018-01-15'
|
||||
}
|
@ -18,6 +18,7 @@ docker_deploy() {
|
||||
_ccert="$3"
|
||||
_cca="$4"
|
||||
_cfullchain="$5"
|
||||
_cpfx="$6"
|
||||
_debug _cdomain "$_cdomain"
|
||||
_getdeployconf DEPLOY_DOCKER_CONTAINER_LABEL
|
||||
_debug2 DEPLOY_DOCKER_CONTAINER_LABEL "$DEPLOY_DOCKER_CONTAINER_LABEL"
|
||||
@ -88,6 +89,12 @@ docker_deploy() {
|
||||
_savedeployconf DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE "$DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE"
|
||||
fi
|
||||
|
||||
_getdeployconf DEPLOY_DOCKER_CONTAINER_PFX_FILE
|
||||
_debug2 DEPLOY_DOCKER_CONTAINER_PFX_FILE "$DEPLOY_DOCKER_CONTAINER_PFX_FILE"
|
||||
if [ "$DEPLOY_DOCKER_CONTAINER_PFX_FILE" ]; then
|
||||
_savedeployconf DEPLOY_DOCKER_CONTAINER_PFX_FILE "$DEPLOY_DOCKER_CONTAINER_PFX_FILE"
|
||||
fi
|
||||
|
||||
_getdeployconf DEPLOY_DOCKER_CONTAINER_RELOAD_CMD
|
||||
_debug2 DEPLOY_DOCKER_CONTAINER_RELOAD_CMD "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD"
|
||||
if [ "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" ]; then
|
||||
@ -125,6 +132,12 @@ docker_deploy() {
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$DEPLOY_DOCKER_CONTAINER_PFX_FILE" ]; then
|
||||
if ! _docker_cp "$_cid" "$_cpfx" "$DEPLOY_DOCKER_CONTAINER_PFX_FILE"; then
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" ]; then
|
||||
_info "Reloading: $DEPLOY_DOCKER_CONTAINER_RELOAD_CMD"
|
||||
if ! _docker_exec "$_cid" "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD"; then
|
||||
|
@ -109,6 +109,5 @@ exim4_deploy() {
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
|
||||
}
|
||||
|
@ -36,6 +36,19 @@
|
||||
# Note: This functionality requires HAProxy was compiled against
|
||||
# a version of OpenSSL that supports this.
|
||||
#
|
||||
# export DEPLOY_HAPROXY_HOT_UPDATE="yes"
|
||||
# export DEPLOY_HAPROXY_STATS_SOCKET="UNIX:/run/haproxy/admin.sock"
|
||||
#
|
||||
# OPTIONAL: Deploy the certificate over the HAProxy stats socket without
|
||||
# needing to reload HAProxy. Default is "no".
|
||||
#
|
||||
# Require the socat binary. DEPLOY_HAPROXY_STATS_SOCKET variable uses the socat
|
||||
# address format.
|
||||
#
|
||||
# export DEPLOY_HAPROXY_MASTER_CLI="UNIX:/run/haproxy-master.sock"
|
||||
#
|
||||
# OPTIONAL: To use the master CLI with DEPLOY_HAPROXY_HOT_UPDATE="yes" instead
|
||||
# of a stats socket, use this variable.
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
@ -46,6 +59,7 @@ haproxy_deploy() {
|
||||
_ccert="$3"
|
||||
_cca="$4"
|
||||
_cfullchain="$5"
|
||||
_cmdpfx=""
|
||||
|
||||
# Some defaults
|
||||
DEPLOY_HAPROXY_PEM_PATH_DEFAULT="/etc/haproxy"
|
||||
@ -53,6 +67,8 @@ haproxy_deploy() {
|
||||
DEPLOY_HAPROXY_BUNDLE_DEFAULT="no"
|
||||
DEPLOY_HAPROXY_ISSUER_DEFAULT="no"
|
||||
DEPLOY_HAPROXY_RELOAD_DEFAULT="true"
|
||||
DEPLOY_HAPROXY_HOT_UPDATE_DEFAULT="no"
|
||||
DEPLOY_HAPROXY_STATS_SOCKET_DEFAULT="UNIX:/run/haproxy/admin.sock"
|
||||
|
||||
_debug _cdomain "${_cdomain}"
|
||||
_debug _ckey "${_ckey}"
|
||||
@ -86,6 +102,11 @@ haproxy_deploy() {
|
||||
_savedomainconf Le_Deploy_haproxy_pem_name "${Le_Deploy_haproxy_pem_name}"
|
||||
elif [ -z "${Le_Deploy_haproxy_pem_name}" ]; then
|
||||
Le_Deploy_haproxy_pem_name="${DEPLOY_HAPROXY_PEM_NAME_DEFAULT}"
|
||||
# We better not have '*' as the first character
|
||||
if [ "${Le_Deploy_haproxy_pem_name%%"${Le_Deploy_haproxy_pem_name#?}"}" = '*' ]; then
|
||||
# removes the first characters and add a _ instead
|
||||
Le_Deploy_haproxy_pem_name="_${Le_Deploy_haproxy_pem_name#?}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# BUNDLE is optional. If not provided then assume "${DEPLOY_HAPROXY_BUNDLE_DEFAULT}"
|
||||
@ -118,6 +139,36 @@ haproxy_deploy() {
|
||||
Le_Deploy_haproxy_reload="${DEPLOY_HAPROXY_RELOAD_DEFAULT}"
|
||||
fi
|
||||
|
||||
# HOT_UPDATE is optional. If not provided then assume "${DEPLOY_HAPROXY_HOT_UPDATE_DEFAULT}"
|
||||
_getdeployconf DEPLOY_HAPROXY_HOT_UPDATE
|
||||
_debug2 DEPLOY_HAPROXY_HOT_UPDATE "${DEPLOY_HAPROXY_HOT_UPDATE}"
|
||||
if [ -n "${DEPLOY_HAPROXY_HOT_UPDATE}" ]; then
|
||||
Le_Deploy_haproxy_hot_update="${DEPLOY_HAPROXY_HOT_UPDATE}"
|
||||
_savedomainconf Le_Deploy_haproxy_hot_update "${Le_Deploy_haproxy_hot_update}"
|
||||
elif [ -z "${Le_Deploy_haproxy_hot_update}" ]; then
|
||||
Le_Deploy_haproxy_hot_update="${DEPLOY_HAPROXY_HOT_UPDATE_DEFAULT}"
|
||||
fi
|
||||
|
||||
# STATS_SOCKET is optional. If not provided then assume "${DEPLOY_HAPROXY_STATS_SOCKET_DEFAULT}"
|
||||
_getdeployconf DEPLOY_HAPROXY_STATS_SOCKET
|
||||
_debug2 DEPLOY_HAPROXY_STATS_SOCKET "${DEPLOY_HAPROXY_STATS_SOCKET}"
|
||||
if [ -n "${DEPLOY_HAPROXY_STATS_SOCKET}" ]; then
|
||||
Le_Deploy_haproxy_stats_socket="${DEPLOY_HAPROXY_STATS_SOCKET}"
|
||||
_savedomainconf Le_Deploy_haproxy_stats_socket "${Le_Deploy_haproxy_stats_socket}"
|
||||
elif [ -z "${Le_Deploy_haproxy_stats_socket}" ]; then
|
||||
Le_Deploy_haproxy_stats_socket="${DEPLOY_HAPROXY_STATS_SOCKET_DEFAULT}"
|
||||
fi
|
||||
|
||||
# MASTER_CLI is optional. No defaults are used. When the master CLI is used,
|
||||
# all commands are sent with a prefix.
|
||||
_getdeployconf DEPLOY_HAPROXY_MASTER_CLI
|
||||
_debug2 DEPLOY_HAPROXY_MASTER_CLI "${DEPLOY_HAPROXY_MASTER_CLI}"
|
||||
if [ -n "${DEPLOY_HAPROXY_MASTER_CLI}" ]; then
|
||||
Le_Deploy_haproxy_stats_socket="${DEPLOY_HAPROXY_MASTER_CLI}"
|
||||
_savedomainconf Le_Deploy_haproxy_stats_socket "${Le_Deploy_haproxy_stats_socket}"
|
||||
_cmdpfx="@1 " # command prefix used for master CLI only.
|
||||
fi
|
||||
|
||||
# Set the suffix depending if we are creating a bundle or not
|
||||
if [ "${Le_Deploy_haproxy_bundle}" = "yes" ]; then
|
||||
_info "Bundle creation requested"
|
||||
@ -142,12 +193,13 @@ haproxy_deploy() {
|
||||
_issuer="${_pem}.issuer"
|
||||
_ocsp="${_pem}.ocsp"
|
||||
_reload="${Le_Deploy_haproxy_reload}"
|
||||
_statssock="${Le_Deploy_haproxy_stats_socket}"
|
||||
|
||||
_info "Deploying PEM file"
|
||||
# Create a temporary PEM file
|
||||
_temppem="$(_mktemp)"
|
||||
_debug _temppem "${_temppem}"
|
||||
cat "${_ckey}" "${_ccert}" "${_cca}" >"${_temppem}"
|
||||
cat "${_ccert}" "${_cca}" "${_ckey}" | grep . >"${_temppem}"
|
||||
_ret="$?"
|
||||
|
||||
# Check that we could create the temporary file
|
||||
@ -265,15 +317,86 @@ haproxy_deploy() {
|
||||
fi
|
||||
fi
|
||||
|
||||
# Reload HAProxy
|
||||
_debug _reload "${_reload}"
|
||||
eval "${_reload}"
|
||||
_ret=$?
|
||||
if [ "${_ret}" != "0" ]; then
|
||||
_err "Error code ${_ret} during reload"
|
||||
return ${_ret}
|
||||
if [ "${Le_Deploy_haproxy_hot_update}" = "yes" ]; then
|
||||
# set the socket name for messages
|
||||
if [ -n "${_cmdpfx}" ]; then
|
||||
_socketname="master CLI"
|
||||
else
|
||||
_socketname="stats socket"
|
||||
fi
|
||||
|
||||
# Update certificate over HAProxy stats socket or master CLI.
|
||||
if _exists socat; then
|
||||
# look for the certificate on the stats socket, to chose between updating or creating one
|
||||
_socat_cert_cmd="echo '${_cmdpfx}show ssl cert' | socat '${_statssock}' - | grep -q '^${_pem}$'"
|
||||
_debug _socat_cert_cmd "${_socat_cert_cmd}"
|
||||
eval "${_socat_cert_cmd}"
|
||||
_ret=$?
|
||||
if [ "${_ret}" != "0" ]; then
|
||||
_newcert="1"
|
||||
_info "Creating new certificate '${_pem}' over HAProxy ${_socketname}."
|
||||
# certificate wasn't found, it's a new one. We should check if the crt-list exists and creates/inserts the certificate.
|
||||
_socat_crtlist_show_cmd="echo '${_cmdpfx}show ssl crt-list' | socat '${_statssock}' - | grep -q '^${Le_Deploy_haproxy_pem_path}$'"
|
||||
_debug _socat_crtlist_show_cmd "${_socat_crtlist_show_cmd}"
|
||||
eval "${_socat_crtlist_show_cmd}"
|
||||
_ret=$?
|
||||
if [ "${_ret}" != "0" ]; then
|
||||
_err "Couldn't find '${Le_Deploy_haproxy_pem_path}' in haproxy 'show ssl crt-list'"
|
||||
return "${_ret}"
|
||||
fi
|
||||
# create a new certificate
|
||||
_socat_new_cmd="echo '${_cmdpfx}new ssl cert ${_pem}' | socat '${_statssock}' - | grep -q 'New empty'"
|
||||
_debug _socat_new_cmd "${_socat_new_cmd}"
|
||||
eval "${_socat_new_cmd}"
|
||||
_ret=$?
|
||||
if [ "${_ret}" != "0" ]; then
|
||||
_err "Couldn't create '${_pem}' in haproxy"
|
||||
return "${_ret}"
|
||||
fi
|
||||
else
|
||||
_info "Update existing certificate '${_pem}' over HAProxy ${_socketname}."
|
||||
fi
|
||||
_socat_cert_set_cmd="echo -e '${_cmdpfx}set ssl cert ${_pem} <<\n$(cat "${_pem}")\n' | socat '${_statssock}' - | grep -q 'Transaction created'"
|
||||
_secure_debug _socat_cert_set_cmd "${_socat_cert_set_cmd}"
|
||||
eval "${_socat_cert_set_cmd}"
|
||||
_ret=$?
|
||||
if [ "${_ret}" != "0" ]; then
|
||||
_err "Can't update '${_pem}' in haproxy"
|
||||
return "${_ret}"
|
||||
fi
|
||||
_socat_cert_commit_cmd="echo '${_cmdpfx}commit ssl cert ${_pem}' | socat '${_statssock}' - | grep -q '^Success!$'"
|
||||
_debug _socat_cert_commit_cmd "${_socat_cert_commit_cmd}"
|
||||
eval "${_socat_cert_commit_cmd}"
|
||||
_ret=$?
|
||||
if [ "${_ret}" != "0" ]; then
|
||||
_err "Can't commit '${_pem}' in haproxy"
|
||||
return ${_ret}
|
||||
fi
|
||||
if [ "${_newcert}" = "1" ]; then
|
||||
# if this is a new certificate, it needs to be inserted into the crt-list`
|
||||
_socat_cert_add_cmd="echo '${_cmdpfx}add ssl crt-list ${Le_Deploy_haproxy_pem_path} ${_pem}' | socat '${_statssock}' - | grep -q 'Success!'"
|
||||
_debug _socat_cert_add_cmd "${_socat_cert_add_cmd}"
|
||||
eval "${_socat_cert_add_cmd}"
|
||||
_ret=$?
|
||||
if [ "${_ret}" != "0" ]; then
|
||||
_err "Can't update '${_pem}' in haproxy"
|
||||
return "${_ret}"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
_err "'socat' is not available, couldn't update over ${_socketname}"
|
||||
fi
|
||||
else
|
||||
_info "Reload successful"
|
||||
# Reload HAProxy
|
||||
_debug _reload "${_reload}"
|
||||
eval "${_reload}"
|
||||
_ret=$?
|
||||
if [ "${_ret}" != "0" ]; then
|
||||
_err "Error code ${_ret} during reload"
|
||||
return ${_ret}
|
||||
else
|
||||
_info "Reload successful"
|
||||
fi
|
||||
fi
|
||||
|
||||
return 0
|
||||
|
183
deploy/panos.sh
183
deploy/panos.sh
@ -7,11 +7,18 @@
|
||||
#
|
||||
# Firewall admin with superuser and IP address is required.
|
||||
#
|
||||
# export PANOS_USER="" # required
|
||||
# export PANOS_PASS="" # required
|
||||
# export PANOS_HOST="" # required
|
||||
# REQURED:
|
||||
# export PANOS_HOST=""
|
||||
# export PANOS_USER="" #User *MUST* have Commit and Import Permissions in XML API for Admin Role
|
||||
# export PANOS_PASS=""
|
||||
#
|
||||
# OPTIONAL
|
||||
# export PANOS_TEMPLATE="" #Template Name of panorama managed devices
|
||||
#
|
||||
# The script will automatically generate a new API key if
|
||||
# no key is found, or if a saved key has expired or is invalid.
|
||||
|
||||
# This function is to parse the XML
|
||||
# This function is to parse the XML response from the firewall
|
||||
parse_response() {
|
||||
type=$2
|
||||
if [ "$type" = 'keygen' ]; then
|
||||
@ -23,25 +30,46 @@ parse_response() {
|
||||
message="PAN-OS Key could not be set."
|
||||
fi
|
||||
else
|
||||
status=$(echo "$1" | sed 's/^.*"\([a-z]*\)".*/\1/g')
|
||||
message=$(echo "$1" | sed 's/^.*<result>\(.*\)<\/result.*/\1/g')
|
||||
status=$(echo "$1" | tr -d '\n' | sed 's/^.*"\([a-z]*\)".*/\1/g')
|
||||
message=$(echo "$1" | tr -d '\n' | sed 's/.*\(<result>\|<msg>\|<line>\)\([^<]*\).*/\2/g')
|
||||
_debug "Firewall message: $message"
|
||||
if [ "$type" = 'keytest' ] && [ "$status" != "success" ]; then
|
||||
_debug "**** API Key has EXPIRED or is INVALID ****"
|
||||
unset _panos_key
|
||||
fi
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
#This function is used to deploy to the firewall
|
||||
deployer() {
|
||||
content=""
|
||||
type=$1 # Types are keygen, cert, key, commit
|
||||
_debug "**** Deploying $type *****"
|
||||
type=$1 # Types are keytest, keygen, cert, key, commit
|
||||
panos_url="https://$_panos_host/api/"
|
||||
|
||||
#Test API Key by performing a lookup
|
||||
if [ "$type" = 'keytest' ]; then
|
||||
_debug "**** Testing saved API Key ****"
|
||||
_H1="Content-Type: application/x-www-form-urlencoded"
|
||||
# Get Version Info to test key
|
||||
content="type=version&key=$_panos_key"
|
||||
## Exclude all scopes for the empty commit
|
||||
#_exclude_scope="<policy-and-objects>exclude</policy-and-objects><device-and-network>exclude</device-and-network><shared-object>exclude</shared-object>"
|
||||
#content="type=commit&action=partial&key=$_panos_key&cmd=<commit><partial>$_exclude_scope<admin><member>acmekeytest</member></admin></partial></commit>"
|
||||
fi
|
||||
|
||||
# Generate API Key
|
||||
if [ "$type" = 'keygen' ]; then
|
||||
_debug "**** Generating new API Key ****"
|
||||
_H1="Content-Type: application/x-www-form-urlencoded"
|
||||
content="type=keygen&user=$_panos_user&password=$_panos_pass"
|
||||
# content="$content${nl}--$delim${nl}Content-Disposition: form-data; type=\"keygen\"; user=\"$_panos_user\"; password=\"$_panos_pass\"${nl}Content-Type: application/octet-stream${nl}${nl}"
|
||||
fi
|
||||
|
||||
# Deploy Cert or Key
|
||||
if [ "$type" = 'cert' ] || [ "$type" = 'key' ]; then
|
||||
#Generate DEIM
|
||||
_debug "**** Deploying $type ****"
|
||||
#Generate DELIM
|
||||
delim="-----MultipartDelimiter$(date "+%s%N")"
|
||||
nl="\015\012"
|
||||
#Set Header
|
||||
@ -53,6 +81,9 @@ deployer() {
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"\r\n\r\n$_panos_key"
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"format\"\r\n\r\npem"
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"file\"; filename=\"$(basename "$_cfullchain")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_cfullchain")"
|
||||
if [ "$_panos_template" ]; then
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"target-tpl\"\r\n\r\n$_panos_template"
|
||||
fi
|
||||
fi
|
||||
if [ "$type" = 'key' ]; then
|
||||
panos_url="${panos_url}?type=import"
|
||||
@ -61,7 +92,10 @@ deployer() {
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"\r\n\r\n$_panos_key"
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"format\"\r\n\r\npem"
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"passphrase\"\r\n\r\n123456"
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"file\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")"
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"file\"; filename=\"$(basename "$_cdomain.key")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")"
|
||||
if [ "$_panos_template" ]; then
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"target-tpl\"\r\n\r\n$_panos_template"
|
||||
fi
|
||||
fi
|
||||
#Close multipart
|
||||
content="$content${nl}--$delim--${nl}${nl}"
|
||||
@ -69,16 +103,25 @@ deployer() {
|
||||
content=$(printf %b "$content")
|
||||
fi
|
||||
|
||||
# Commit changes
|
||||
if [ "$type" = 'commit' ]; then
|
||||
_debug "**** Committing changes ****"
|
||||
export _H1="Content-Type: application/x-www-form-urlencoded"
|
||||
cmd=$(printf "%s" "<commit><partial><$_panos_user></$_panos_user></partial></commit>" | _url_encode)
|
||||
content="type=commit&key=$_panos_key&cmd=$cmd"
|
||||
#Check for force commit - will commit ALL uncommited changes to the firewall. Use with caution!
|
||||
if [ "$FORCE" ]; then
|
||||
_debug "Force switch detected. Committing ALL changes to the firewall."
|
||||
cmd=$(printf "%s" "<commit><partial><force><admin><member>$_panos_user</member></admin></force></partial></commit>" | _url_encode)
|
||||
else
|
||||
_exclude_scope="<policy-and-objects>exclude</policy-and-objects><device-and-network>exclude</device-and-network>"
|
||||
cmd=$(printf "%s" "<commit><partial>$_exclude_scope<admin><member>$_panos_user</member></admin></partial></commit>" | _url_encode)
|
||||
fi
|
||||
content="type=commit&action=partial&key=$_panos_key&cmd=$cmd"
|
||||
fi
|
||||
|
||||
response=$(_post "$content" "$panos_url" "" "POST")
|
||||
parse_response "$response" "$type"
|
||||
# Saving response to variables
|
||||
response_status=$status
|
||||
#DEBUG
|
||||
_debug response_status "$response_status"
|
||||
if [ "$response_status" = "success" ]; then
|
||||
_debug "Successfully deployed $type"
|
||||
@ -92,43 +135,95 @@ deployer() {
|
||||
|
||||
# This is the main function that will call the other functions to deploy everything.
|
||||
panos_deploy() {
|
||||
_cdomain="$1"
|
||||
_cdomain=$(echo "$1" | sed 's/*/WILDCARD_/g') #Wildcard Safe Filename
|
||||
_ckey="$2"
|
||||
_cfullchain="$5"
|
||||
# PANOS ENV VAR check
|
||||
if [ -z "$PANOS_USER" ] || [ -z "$PANOS_PASS" ] || [ -z "$PANOS_HOST" ]; then
|
||||
_debug "No ENV variables found lets check for saved variables"
|
||||
_getdeployconf PANOS_USER
|
||||
_getdeployconf PANOS_PASS
|
||||
_getdeployconf PANOS_HOST
|
||||
_panos_user=$PANOS_USER
|
||||
_panos_pass=$PANOS_PASS
|
||||
_panos_host=$PANOS_HOST
|
||||
if [ -z "$_panos_user" ] && [ -z "$_panos_pass" ] && [ -z "$_panos_host" ]; then
|
||||
_err "No host, user and pass found.. If this is the first time deploying please set PANOS_HOST, PANOS_USER and PANOS_PASS in environment variables. Delete them after you have succesfully deployed certs."
|
||||
return 1
|
||||
else
|
||||
_debug "Using saved env variables."
|
||||
fi
|
||||
else
|
||||
_debug "Detected ENV variables to be saved to the deploy conf."
|
||||
# Encrypt and save user
|
||||
_savedeployconf PANOS_USER "$PANOS_USER" 1
|
||||
_savedeployconf PANOS_PASS "$PANOS_PASS" 1
|
||||
_savedeployconf PANOS_HOST "$PANOS_HOST" 1
|
||||
_panos_user="$PANOS_USER"
|
||||
_panos_pass="$PANOS_PASS"
|
||||
_panos_host="$PANOS_HOST"
|
||||
|
||||
# VALID FILE CHECK
|
||||
if [ ! -f "$_ckey" ] || [ ! -f "$_cfullchain" ]; then
|
||||
_err "Unable to find a valid key and/or cert. If this is an ECDSA/ECC cert, use the --ecc flag when deploying."
|
||||
return 1
|
||||
fi
|
||||
_debug "Let's use username and pass to generate token."
|
||||
if [ -z "$_panos_user" ] || [ -z "$_panos_pass" ] || [ -z "$_panos_host" ]; then
|
||||
_err "Please pass username and password and host as env variables PANOS_USER, PANOS_PASS and PANOS_HOST"
|
||||
|
||||
# PANOS_HOST
|
||||
if [ "$PANOS_HOST" ]; then
|
||||
_debug "Detected ENV variable PANOS_HOST. Saving to file."
|
||||
_savedeployconf PANOS_HOST "$PANOS_HOST" 1
|
||||
else
|
||||
_debug "Attempting to load variable PANOS_HOST from file."
|
||||
_getdeployconf PANOS_HOST
|
||||
fi
|
||||
|
||||
# PANOS USER
|
||||
if [ "$PANOS_USER" ]; then
|
||||
_debug "Detected ENV variable PANOS_USER. Saving to file."
|
||||
_savedeployconf PANOS_USER "$PANOS_USER" 1
|
||||
else
|
||||
_debug "Attempting to load variable PANOS_USER from file."
|
||||
_getdeployconf PANOS_USER
|
||||
fi
|
||||
|
||||
# PANOS_PASS
|
||||
if [ "$PANOS_PASS" ]; then
|
||||
_debug "Detected ENV variable PANOS_PASS. Saving to file."
|
||||
_savedeployconf PANOS_PASS "$PANOS_PASS" 1
|
||||
else
|
||||
_debug "Attempting to load variable PANOS_PASS from file."
|
||||
_getdeployconf PANOS_PASS
|
||||
fi
|
||||
|
||||
# PANOS_KEY
|
||||
_getdeployconf PANOS_KEY
|
||||
if [ "$PANOS_KEY" ]; then
|
||||
_debug "Detected saved key."
|
||||
_panos_key=$PANOS_KEY
|
||||
else
|
||||
_debug "No key detected"
|
||||
unset _panos_key
|
||||
fi
|
||||
|
||||
# PANOS_TEMPLATE
|
||||
if [ "$PANOS_TEMPLATE" ]; then
|
||||
_debug "Detected ENV variable PANOS_TEMPLATE. Saving to file."
|
||||
_savedeployconf PANOS_TEMPLATE "$PANOS_TEMPLATE" 1
|
||||
else
|
||||
_debug "Attempting to load variable PANOS_TEMPLATE from file."
|
||||
_getdeployconf PANOS_TEMPLATE
|
||||
fi
|
||||
|
||||
#Store variables
|
||||
_panos_host=$PANOS_HOST
|
||||
_panos_user=$PANOS_USER
|
||||
_panos_pass=$PANOS_PASS
|
||||
_panos_template=$PANOS_TEMPLATE
|
||||
|
||||
#Test API Key if found. If the key is invalid, the variable _panos_key will be unset.
|
||||
if [ "$_panos_host" ] && [ "$_panos_key" ]; then
|
||||
_debug "**** Testing API KEY ****"
|
||||
deployer keytest
|
||||
fi
|
||||
|
||||
# Check for valid variables
|
||||
if [ -z "$_panos_host" ]; then
|
||||
_err "No host found. If this is your first time deploying, please set PANOS_HOST in ENV variables. You can delete it after you have successfully deployed the certs."
|
||||
return 1
|
||||
elif [ -z "$_panos_user" ]; then
|
||||
_err "No user found. If this is your first time deploying, please set PANOS_USER in ENV variables. You can delete it after you have successfully deployed the certs."
|
||||
return 1
|
||||
elif [ -z "$_panos_pass" ]; then
|
||||
_err "No password found. If this is your first time deploying, please set PANOS_PASS in ENV variables. You can delete it after you have successfully deployed the certs."
|
||||
return 1
|
||||
else
|
||||
_debug "Getting PANOS KEY"
|
||||
deployer keygen
|
||||
# Generate a new API key if no valid API key is found
|
||||
if [ -z "$_panos_key" ]; then
|
||||
_err "Missing apikey."
|
||||
_debug "**** Generating new PANOS API KEY ****"
|
||||
deployer keygen
|
||||
_savedeployconf PANOS_KEY "$_panos_key" 1
|
||||
fi
|
||||
|
||||
# Confirm that a valid key was generated
|
||||
if [ -z "$_panos_key" ]; then
|
||||
_err "Unable to generate an API key. The user and pass may be invalid or not authorized to generate a new key. Please check the PANOS_USER and PANOS_PASS credentials and try again"
|
||||
return 1
|
||||
else
|
||||
deployer cert
|
||||
|
120
deploy/proxmoxbs.sh
Normal file
120
deploy/proxmoxbs.sh
Normal file
@ -0,0 +1,120 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Deploy certificates to a proxmox backup server using the API.
|
||||
#
|
||||
# Environment variables that can be set are:
|
||||
# `DEPLOY_PROXMOXBS_SERVER`: The hostname of the proxmox backup server. Defaults to
|
||||
# _cdomain.
|
||||
# `DEPLOY_PROXMOXBS_SERVER_PORT`: The port number the management interface is on.
|
||||
# Defaults to 8007.
|
||||
# `DEPLOY_PROXMOXBS_USER`: The user we'll connect as. Defaults to root.
|
||||
# `DEPLOY_PROXMOXBS_USER_REALM`: The authentication realm the user authenticates
|
||||
# with. Defaults to pam.
|
||||
# `DEPLOY_PROXMOXBS_API_TOKEN_NAME`: The name of the API token created for the
|
||||
# user account. Defaults to acme.
|
||||
# `DEPLOY_PROXMOXBS_API_TOKEN_KEY`: The API token. Required.
|
||||
|
||||
proxmoxbs_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_PROXMOXBS_SERVER
|
||||
if [ -z "$DEPLOY_PROXMOXBS_SERVER" ]; then
|
||||
_target_hostname="$_cdomain"
|
||||
else
|
||||
_target_hostname="$DEPLOY_PROXMOXBS_SERVER"
|
||||
_savedeployconf DEPLOY_PROXMOXBS_SERVER "$DEPLOY_PROXMOXBS_SERVER"
|
||||
fi
|
||||
_debug2 DEPLOY_PROXMOXBS_SERVER "$_target_hostname"
|
||||
|
||||
_getdeployconf DEPLOY_PROXMOXBS_SERVER_PORT
|
||||
if [ -z "$DEPLOY_PROXMOXBS_SERVER_PORT" ]; then
|
||||
_target_port="8007"
|
||||
else
|
||||
_target_port="$DEPLOY_PROXMOXBS_SERVER_PORT"
|
||||
_savedeployconf DEPLOY_PROXMOXBS_SERVER_PORT "$DEPLOY_PROXMOXBS_SERVER_PORT"
|
||||
fi
|
||||
_debug2 DEPLOY_PROXMOXBS_SERVER_PORT "$_target_port"
|
||||
|
||||
# Complete URL.
|
||||
_target_url="https://${_target_hostname}:${_target_port}/api2/json/nodes/localhost/certificates/custom"
|
||||
_debug TARGET_URL "$_target_url"
|
||||
|
||||
# More "sane" defaults.
|
||||
_getdeployconf DEPLOY_PROXMOXBS_USER
|
||||
if [ -z "$DEPLOY_PROXMOXBS_USER" ]; then
|
||||
_proxmoxbs_user="root"
|
||||
else
|
||||
_proxmoxbs_user="$DEPLOY_PROXMOXBS_USER"
|
||||
_savedeployconf DEPLOY_PROXMOXBS_USER "$DEPLOY_PROXMOXBS_USER"
|
||||
fi
|
||||
_debug2 DEPLOY_PROXMOXBS_USER "$_proxmoxbs_user"
|
||||
|
||||
_getdeployconf DEPLOY_PROXMOXBS_USER_REALM
|
||||
if [ -z "$DEPLOY_PROXMOXBS_USER_REALM" ]; then
|
||||
_proxmoxbs_user_realm="pam"
|
||||
else
|
||||
_proxmoxbs_user_realm="$DEPLOY_PROXMOXBS_USER_REALM"
|
||||
_savedeployconf DEPLOY_PROXMOXBS_USER_REALM "$DEPLOY_PROXMOXBS_USER_REALM"
|
||||
fi
|
||||
_debug2 DEPLOY_PROXMOXBS_USER_REALM "$_proxmoxbs_user_realm"
|
||||
|
||||
_getdeployconf DEPLOY_PROXMOXBS_API_TOKEN_NAME
|
||||
if [ -z "$DEPLOY_PROXMOXBS_API_TOKEN_NAME" ]; then
|
||||
_proxmoxbs_api_token_name="acme"
|
||||
else
|
||||
_proxmoxbs_api_token_name="$DEPLOY_PROXMOXBS_API_TOKEN_NAME"
|
||||
_savedeployconf DEPLOY_PROXMOXBS_API_TOKEN_NAME "$DEPLOY_PROXMOXBS_API_TOKEN_NAME"
|
||||
fi
|
||||
_debug2 DEPLOY_PROXMOXBS_API_TOKEN_NAME "$_proxmoxbs_api_token_name"
|
||||
|
||||
# This is required.
|
||||
_getdeployconf DEPLOY_PROXMOXBS_API_TOKEN_KEY
|
||||
if [ -z "$DEPLOY_PROXMOXBS_API_TOKEN_KEY" ]; then
|
||||
_err "API key not provided."
|
||||
return 1
|
||||
else
|
||||
_proxmoxbs_api_token_key="$DEPLOY_PROXMOXBS_API_TOKEN_KEY"
|
||||
_savedeployconf DEPLOY_PROXMOXBS_API_TOKEN_KEY "$DEPLOY_PROXMOXBS_API_TOKEN_KEY"
|
||||
fi
|
||||
_debug2 DEPLOY_PROXMOXBS_API_TOKEN_KEY "$_proxmoxbs_api_token_key"
|
||||
|
||||
# PBS API Token header value. Used in "Authorization: PBSAPIToken".
|
||||
_proxmoxbs_header_api_token="${_proxmoxbs_user}@${_proxmoxbs_user_realm}!${_proxmoxbs_api_token_name}:${_proxmoxbs_api_token_key}"
|
||||
_debug2 "Auth Header" "$_proxmoxbs_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":"localhost",
|
||||
"restart":true,
|
||||
"force":true
|
||||
}
|
||||
HEREDOC
|
||||
)
|
||||
_debug2 Payload "$_json_payload"
|
||||
|
||||
_info "Push certificates to server"
|
||||
export HTTPS_INSECURE=1
|
||||
export _H1="Authorization: PBSAPIToken=${_proxmoxbs_header_api_token}"
|
||||
_post "$_json_payload" "$_target_url" "" POST "application/json"
|
||||
|
||||
}
|
@ -99,11 +99,11 @@ proxmoxve_deploy() {
|
||||
_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
|
||||
_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
|
||||
_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
|
||||
@ -124,8 +124,8 @@ HEREDOC
|
||||
)
|
||||
_debug2 Payload "$_json_payload"
|
||||
|
||||
# Push certificates to server.
|
||||
export _HTTPS_INSECURE=1
|
||||
_info "Push certificates to server"
|
||||
export HTTPS_INSECURE=1
|
||||
export _H1="Authorization: PVEAPIToken=${_proxmoxve_header_api_token}"
|
||||
_post "$_json_payload" "$_target_url" "" POST "application/json"
|
||||
|
||||
|
@ -137,17 +137,18 @@ routeros_deploy() {
|
||||
return $_err_code
|
||||
fi
|
||||
|
||||
DEPLOY_SCRIPT_CMD="/system script add name=\"LE Cert Deploy - $_cdomain\" owner=$ROUTER_OS_USERNAME \
|
||||
DEPLOY_SCRIPT_CMD=":do {/system script remove \"LECertDeploy-$_cdomain\" } on-error={ }; \
|
||||
/system script add name=\"LECertDeploy-$_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=\\\"\\\";\
|
||||
\n/certificate import file-name=\\\"$_cdomain.cer\\\" passphrase=\\\"\\\";\
|
||||
\n/certificate import file-name=\\\"$_cdomain.key\\\" passphrase=\\\"\\\";\
|
||||
\ndelay 1;\
|
||||
\n/file remove $_cdomain.cer;\
|
||||
\n/file remove $_cdomain.key;\
|
||||
\n:do {/file remove $_cdomain.cer; } on-error={ }\
|
||||
\n:do {/file remove $_cdomain.key; } on-error={ }\
|
||||
\ndelay 2;\
|
||||
\n/ip service set www-ssl certificate=$_cdomain.cer_0;\
|
||||
\n$ROUTER_OS_ADDITIONAL_SERVICES;\
|
||||
@ -158,11 +159,11 @@ source=\"/certificate remove [ find name=$_cdomain.cer_0 ];\
|
||||
return $_err_code
|
||||
fi
|
||||
|
||||
if ! _ssh_remote_cmd "/system script run \"LE Cert Deploy - $_cdomain\""; then
|
||||
if ! _ssh_remote_cmd "/system script run \"LECertDeploy-$_cdomain\""; then
|
||||
return $_err_code
|
||||
fi
|
||||
|
||||
if ! _ssh_remote_cmd "/system script remove \"LE Cert Deploy - $_cdomain\""; then
|
||||
if ! _ssh_remote_cmd "/system script remove \"LECertDeploy-$_cdomain\""; then
|
||||
return $_err_code
|
||||
fi
|
||||
|
||||
|
200
deploy/ruckus.sh
Executable file
200
deploy/ruckus.sh
Executable file
@ -0,0 +1,200 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Here is a script to deploy cert to Ruckus ZoneDirector / Unleashed.
|
||||
#
|
||||
# Public domain, 2024, Tony Rielly <https://github.com/ms264556>
|
||||
#
|
||||
# ```sh
|
||||
# acme.sh --deploy -d ruckus.example.com --deploy-hook ruckus
|
||||
# ```
|
||||
#
|
||||
# Then you need to set the environment variables for the
|
||||
# deploy script to work.
|
||||
#
|
||||
# ```sh
|
||||
# export RUCKUS_HOST=myruckus.example.com
|
||||
# export RUCKUS_USER=myruckususername
|
||||
# export RUCKUS_PASS=myruckuspassword
|
||||
#
|
||||
# acme.sh --deploy -d myruckus.example.com --deploy-hook ruckus
|
||||
# ```
|
||||
#
|
||||
# returns 0 means success, otherwise error.
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#domain keyfile certfile cafile fullchain
|
||||
ruckus_deploy() {
|
||||
_cdomain="$1"
|
||||
_ckey="$2"
|
||||
_ccert="$3"
|
||||
_cca="$4"
|
||||
_cfullchain="$5"
|
||||
_err_code=0
|
||||
|
||||
_debug _cdomain "$_cdomain"
|
||||
_debug _ckey "$_ckey"
|
||||
_debug _ccert "$_ccert"
|
||||
_debug _cca "$_cca"
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
_getdeployconf RUCKUS_HOST
|
||||
_getdeployconf RUCKUS_USER
|
||||
_getdeployconf RUCKUS_PASS
|
||||
|
||||
if [ -z "$RUCKUS_HOST" ]; then
|
||||
_debug "Using _cdomain as RUCKUS_HOST, please set if not correct."
|
||||
RUCKUS_HOST="$_cdomain"
|
||||
fi
|
||||
|
||||
if [ -z "$RUCKUS_USER" ]; then
|
||||
_err "Need to set the env variable RUCKUS_USER"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$RUCKUS_PASS" ]; then
|
||||
_err "Need to set the env variable RUCKUS_PASS"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_savedeployconf RUCKUS_HOST "$RUCKUS_HOST"
|
||||
_savedeployconf RUCKUS_USER "$RUCKUS_USER"
|
||||
_savedeployconf RUCKUS_PASS "$RUCKUS_PASS"
|
||||
|
||||
_debug RUCKUS_HOST "$RUCKUS_HOST"
|
||||
_debug RUCKUS_USER "$RUCKUS_USER"
|
||||
_secure_debug RUCKUS_PASS "$RUCKUS_PASS"
|
||||
|
||||
export ACME_HTTP_NO_REDIRECTS=1
|
||||
|
||||
_info "Discovering the login URL"
|
||||
_get "https://$RUCKUS_HOST" >/dev/null
|
||||
_login_url="$(_response_header 'Location')"
|
||||
if [ -n "$_login_url" ]; then
|
||||
_login_path=$(echo "$_login_url" | sed 's|https\?://[^/]\+||')
|
||||
if [ -z "$_login_path" ]; then
|
||||
# redirect was to a different host
|
||||
_err "Connection failed: redirected to a different host. Configure Unleashed with a Preferred Master or Management Interface."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "${_login_url}" ]; then
|
||||
_err "Connection failed: couldn't find login page."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_base_url=$(dirname "$_login_url")
|
||||
_login_page=$(basename "$_login_url")
|
||||
|
||||
if [ "$_login_page" = "index.html" ]; then
|
||||
_err "Connection temporarily unavailable: Unleashed Rebuilding."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$_login_page" = "wizard.jsp" ]; then
|
||||
_err "Connection failed: Setup Wizard not complete."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Login"
|
||||
_username_encoded="$(printf "%s" "$RUCKUS_USER" | _url_encode)"
|
||||
_password_encoded="$(printf "%s" "$RUCKUS_PASS" | _url_encode)"
|
||||
_login_query="$(printf "%s" "username=${_username_encoded}&password=${_password_encoded}&ok=Log+In")"
|
||||
_post "$_login_query" "$_login_url" >/dev/null
|
||||
|
||||
_login_code="$(_response_code)"
|
||||
if [ "$_login_code" = "200" ]; then
|
||||
_err "Login failed: incorrect credentials."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Collect Session Cookie"
|
||||
_H1="Cookie: $(_response_cookie)"
|
||||
export _H1
|
||||
_info "Collect CSRF Token"
|
||||
_H2="X-CSRF-Token: $(_response_header 'HTTP_X_CSRF_TOKEN')"
|
||||
export _H2
|
||||
|
||||
if _isRSA "$_ckey" >/dev/null 2>&1; then
|
||||
_debug "Using RSA certificate."
|
||||
else
|
||||
_info "Verifying ECC certificate support."
|
||||
|
||||
_ul_version="$(_get_unleashed_version)"
|
||||
if [ -z "$_ul_version" ]; then
|
||||
_err "Your controller doesn't support ECC certificates. Please deploy an RSA certificate."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_ul_version_major="$(echo "$_ul_version" | cut -d . -f 1)"
|
||||
_ul_version_minor="$(echo "$_ul_version" | cut -d . -f 2)"
|
||||
if [ "$_ul_version_major" -lt "200" ]; then
|
||||
_err "ZoneDirector doesn't support ECC certificates. Please deploy an RSA certificate."
|
||||
return 1
|
||||
elif [ "$_ul_version_minor" -lt "13" ]; then
|
||||
_err "Unleashed $_ul_version_major.$_ul_version_minor doesn't support ECC certificates. Please deploy an RSA certificate or upgrade to Unleashed 200.13+."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "ECC certificates OK for Unleashed $_ul_version_major.$_ul_version_minor."
|
||||
fi
|
||||
|
||||
_info "Uploading certificate"
|
||||
_post_upload "uploadcert" "$_cfullchain"
|
||||
|
||||
_info "Uploading private key"
|
||||
_post_upload "uploadprivatekey" "$_ckey"
|
||||
|
||||
_info "Replacing certificate"
|
||||
_replace_cert_ajax='<ajax-request action="docmd" comp="system" updater="rid.0.5" xcmd="replace-cert" checkAbility="6" timeout="-1"><xcmd cmd="replace-cert" cn="'$RUCKUS_HOST'"/></ajax-request>'
|
||||
_post "$_replace_cert_ajax" "$_base_url/_cmdstat.jsp" >/dev/null
|
||||
|
||||
_info "Rebooting"
|
||||
_cert_reboot_ajax='<ajax-request action="docmd" comp="worker" updater="rid.0.5" xcmd="cert-reboot" checkAbility="6"><xcmd cmd="cert-reboot" action="undefined"/></ajax-request>'
|
||||
_post "$_cert_reboot_ajax" "$_base_url/_cmdstat.jsp" >/dev/null
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
_response_code() {
|
||||
_egrep_o <"$HTTP_HEADER" "^HTTP[^ ]* .*$" | cut -d " " -f 2-100 | tr -d "\f\n" | _egrep_o "^[0-9]*"
|
||||
}
|
||||
|
||||
_response_header() {
|
||||
grep <"$HTTP_HEADER" -i "^$1:" | cut -d ':' -f 2- | tr -d "\r\n\t "
|
||||
}
|
||||
|
||||
_response_cookie() {
|
||||
_response_header 'Set-Cookie' | sed 's/;.*//'
|
||||
}
|
||||
|
||||
_get_unleashed_version() {
|
||||
_post '<ajax-request action="getstat" comp="system"><sysinfo/></ajax-request>' "$_base_url/_cmdstat.jsp" | _egrep_o "version-num=\"[^\"]*\"" | cut -d '"' -f 2
|
||||
}
|
||||
|
||||
_post_upload() {
|
||||
_post_action="$1"
|
||||
_post_file="$2"
|
||||
|
||||
_post_boundary="----FormBoundary$(date "+%s%N")"
|
||||
|
||||
_post_data="$({
|
||||
printf -- "--%s\r\n" "$_post_boundary"
|
||||
printf -- "Content-Disposition: form-data; name=\"u\"; filename=\"%s\"\r\n" "$_post_action"
|
||||
printf -- "Content-Type: application/octet-stream\r\n\r\n"
|
||||
printf -- "%s\r\n" "$(cat "$_post_file")"
|
||||
|
||||
printf -- "--%s\r\n" "$_post_boundary"
|
||||
printf -- "Content-Disposition: form-data; name=\"action\"\r\n\r\n"
|
||||
printf -- "%s\r\n" "$_post_action"
|
||||
|
||||
printf -- "--%s\r\n" "$_post_boundary"
|
||||
printf -- "Content-Disposition: form-data; name=\"callback\"\r\n\r\n"
|
||||
printf -- "%s\r\n" "uploader_$_post_action"
|
||||
|
||||
printf -- "--%s--\r\n\r\n" "$_post_boundary"
|
||||
})"
|
||||
|
||||
_post "$_post_data" "$_base_url/_upload.jsp?request_type=xhr" "" "" "multipart/form-data; boundary=$_post_boundary" >/dev/null
|
||||
}
|
@ -10,46 +10,89 @@
|
||||
|
||||
#domain keyfile certfile cafile fullchain
|
||||
strongswan_deploy() {
|
||||
_cdomain="$1"
|
||||
_ckey="$2"
|
||||
_ccert="$3"
|
||||
_cca="$4"
|
||||
_cfullchain="$5"
|
||||
|
||||
_cdomain="${1}"
|
||||
_ckey="${2}"
|
||||
_ccert="${3}"
|
||||
_cca="${4}"
|
||||
_cfullchain="${5}"
|
||||
_info "Using strongswan"
|
||||
|
||||
if [ -x /usr/sbin/ipsec ]; then
|
||||
_ipsec=/usr/sbin/ipsec
|
||||
elif [ -x /usr/sbin/strongswan ]; then
|
||||
_ipsec=/usr/sbin/strongswan
|
||||
elif [ -x /usr/local/sbin/ipsec ]; then
|
||||
_ipsec=/usr/local/sbin/ipsec
|
||||
else
|
||||
if _exists ipsec; then
|
||||
_ipsec=ipsec
|
||||
elif _exists strongswan; then
|
||||
_ipsec=strongswan
|
||||
fi
|
||||
if _exists swanctl; then
|
||||
_swanctl=swanctl
|
||||
fi
|
||||
# For legacy stroke mode
|
||||
if [ -n "${_ipsec}" ]; then
|
||||
_info "${_ipsec} command detected"
|
||||
_confdir=$(${_ipsec} --confdir)
|
||||
if [ -z "${_confdir}" ]; then
|
||||
_err "no strongswan --confdir is detected"
|
||||
return 1
|
||||
fi
|
||||
_info _confdir "${_confdir}"
|
||||
__deploy_cert "$@" "stroke" "${_confdir}"
|
||||
${_ipsec} reload
|
||||
fi
|
||||
# For modern vici mode
|
||||
if [ -n "${_swanctl}" ]; then
|
||||
_info "${_swanctl} command detected"
|
||||
for _dir in /usr/local/etc/swanctl /etc/swanctl /etc/strongswan/swanctl; do
|
||||
if [ -d ${_dir} ]; then
|
||||
_confdir=${_dir}
|
||||
_info _confdir "${_confdir}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [ -z "${_confdir}" ]; then
|
||||
_err "no swanctl config dir is found"
|
||||
return 1
|
||||
fi
|
||||
__deploy_cert "$@" "vici" "${_confdir}"
|
||||
${_swanctl} --load-creds
|
||||
fi
|
||||
if [ -z "${_swanctl}" ] && [ -z "${_ipsec}" ]; then
|
||||
_err "no strongswan or ipsec command is detected"
|
||||
_err "no swanctl is detected"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info _ipsec "$_ipsec"
|
||||
|
||||
_confdir=$($_ipsec --confdir)
|
||||
if [ $? -ne 0 ] || [ -z "$_confdir" ]; then
|
||||
_err "no strongswan --confdir is detected"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info _confdir "$_confdir"
|
||||
|
||||
_debug _cdomain "$_cdomain"
|
||||
_debug _ckey "$_ckey"
|
||||
_debug _ccert "$_ccert"
|
||||
_debug _cca "$_cca"
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
cat "$_ckey" >"${_confdir}/ipsec.d/private/$(basename "$_ckey")"
|
||||
cat "$_ccert" >"${_confdir}/ipsec.d/certs/$(basename "$_ccert")"
|
||||
cat "$_cca" >"${_confdir}/ipsec.d/cacerts/$(basename "$_cca")"
|
||||
cat "$_cfullchain" >"${_confdir}/ipsec.d/cacerts/$(basename "$_cfullchain")"
|
||||
|
||||
$_ipsec reload
|
||||
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
__deploy_cert() {
|
||||
_cdomain="${1}"
|
||||
_ckey="${2}"
|
||||
_ccert="${3}"
|
||||
_cca="${4}"
|
||||
_cfullchain="${5}"
|
||||
_swan_mode="${6}"
|
||||
_confdir="${7}"
|
||||
_debug _cdomain "${_cdomain}"
|
||||
_debug _ckey "${_ckey}"
|
||||
_debug _ccert "${_ccert}"
|
||||
_debug _cca "${_cca}"
|
||||
_debug _cfullchain "${_cfullchain}"
|
||||
_debug _swan_mode "${_swan_mode}"
|
||||
_debug _confdir "${_confdir}"
|
||||
if [ "${_swan_mode}" = "vici" ]; then
|
||||
_dir_private="private"
|
||||
_dir_cert="x509"
|
||||
_dir_ca="x509ca"
|
||||
elif [ "${_swan_mode}" = "stroke" ]; then
|
||||
_dir_private="ipsec.d/private"
|
||||
_dir_cert="ipsec.d/certs"
|
||||
_dir_ca="ipsec.d/cacerts"
|
||||
else
|
||||
_err "unknown StrongSwan mode ${_swan_mode}"
|
||||
return 1
|
||||
fi
|
||||
cat "${_ckey}" >"${_confdir}/${_dir_private}/$(basename "${_ckey}")"
|
||||
cat "${_ccert}" >"${_confdir}/${_dir_cert}/$(basename "${_ccert}")"
|
||||
cat "${_cca}" >"${_confdir}/${_dir_ca}/$(basename "${_cca}")"
|
||||
if [ "${_swan_mode}" = "stroke" ]; then
|
||||
cat "${_cfullchain}" >"${_confdir}/${_dir_ca}/$(basename "${_cfullchain}")"
|
||||
fi
|
||||
}
|
||||
|
@ -1,34 +1,53 @@
|
||||
#!/usr/bin/env sh
|
||||
#!/bin/bash
|
||||
|
||||
# Here is a script to deploy cert to Synology DSM
|
||||
#
|
||||
# It requires following environment variables:
|
||||
#
|
||||
# SYNO_Username - Synology Username to login (must be an administrator)
|
||||
# SYNO_Password - Synology Password to login
|
||||
# SYNO_Certificate - Certificate description to target for replacement
|
||||
#
|
||||
# The following environmental variables may be set if you don't like their
|
||||
# default values:
|
||||
#
|
||||
# SYNO_Scheme - defaults to http
|
||||
# SYNO_Hostname - defaults to localhost
|
||||
# SYNO_Port - defaults to 5000
|
||||
# SYNO_DID - device ID to skip OTP - defaults to empty
|
||||
# SYNO_TOTP_SECRET - TOTP secret to generate OTP - defaults to empty
|
||||
#
|
||||
################################################################################
|
||||
# ACME.sh 3rd party deploy plugin for Synology DSM
|
||||
################################################################################
|
||||
# Authors: Brian Hartvigsen (creator), https://github.com/tresni
|
||||
# Martin Arndt (contributor), https://troublezone.net/
|
||||
# Updated: 2023-07-03
|
||||
# Issues: https://github.com/acmesh-official/acme.sh/issues/2727
|
||||
################################################################################
|
||||
# Usage (shown values are the examples):
|
||||
# 1. Set required environment variables:
|
||||
# - use automatically created temp admin user to authenticate
|
||||
# export SYNO_USE_TEMP_ADMIN=1
|
||||
# - or provide your own admin user credential to authenticate
|
||||
# 1. export SYNO_USERNAME="adminUser"
|
||||
# 2. export SYNO_PASSWORD="adminPassword"
|
||||
# 2. Set optional environment variables
|
||||
# - common optional variables
|
||||
# - export SYNO_SCHEME="http" - defaults to "http"
|
||||
# - export SYNO_HOSTNAME="localhost" - defaults to "localhost"
|
||||
# - export SYNO_PORT="5000" - defaults to "5000"
|
||||
# - export SYNO_CREATE=1 - to allow creating the cert if it doesn't exist
|
||||
# - export SYNO_CERTIFICATE="" - to replace a specific cert by its
|
||||
# description
|
||||
# - temp admin optional variables
|
||||
# - export SYNO_LOCAL_HOSTNAME=1 - if set to 1, force to treat hostname is
|
||||
# targeting current local machine (since
|
||||
# this method only locally supported)
|
||||
# - exsiting admin 2FA-OTP optional variables
|
||||
# - export SYNO_OTP_CODE="XXXXXX" - if set, script won't require to
|
||||
# interactive input the OTP code
|
||||
# - export SYNO_DEVICE_NAME="CertRenewal" - if set, script won't require to
|
||||
# interactive input the device name
|
||||
# - export SYNO_DEVICE_ID="" - (deprecated, auth with OTP code instead)
|
||||
# required for omitting 2FA-OTP
|
||||
# 3. Run command:
|
||||
# acme.sh --deploy --deploy-hook synology_dsm -d example.com
|
||||
################################################################################
|
||||
# Dependencies:
|
||||
# -------------
|
||||
# - jq and curl
|
||||
# - oathtool (When using 2 Factor Authentication and SYNO_TOTP_SECRET is set)
|
||||
#
|
||||
#returns 0 means success, otherwise error.
|
||||
|
||||
######## Public functions #####################
|
||||
# - curl
|
||||
# - synouser & synogroup & synosetkeyvalue (Required for SYNO_USE_TEMP_ADMIN=1)
|
||||
################################################################################
|
||||
# Return value:
|
||||
# 0 means success, otherwise error.
|
||||
################################################################################
|
||||
|
||||
########## Public functions ####################################################
|
||||
#domain keyfile certfile cafile fullchain
|
||||
synology_dsm_deploy() {
|
||||
|
||||
_cdomain="$1"
|
||||
_ckey="$2"
|
||||
_ccert="$3"
|
||||
@ -36,148 +55,391 @@ synology_dsm_deploy() {
|
||||
|
||||
_debug _cdomain "$_cdomain"
|
||||
|
||||
# Get Username and Password, but don't save until we successfully authenticate
|
||||
_getdeployconf SYNO_Username
|
||||
_getdeployconf SYNO_Password
|
||||
_getdeployconf SYNO_Create
|
||||
_getdeployconf SYNO_DID
|
||||
_getdeployconf SYNO_TOTP_SECRET
|
||||
if [ -z "${SYNO_Username:-}" ] || [ -z "${SYNO_Password:-}" ]; then
|
||||
_err "SYNO_Username & SYNO_Password must be set"
|
||||
# Get username and password, but don't save until we authenticated successfully
|
||||
_migratedeployconf SYNO_Username SYNO_USERNAME
|
||||
_migratedeployconf SYNO_Password SYNO_PASSWORD
|
||||
_migratedeployconf SYNO_Device_ID SYNO_DEVICE_ID
|
||||
_migratedeployconf SYNO_Device_Name SYNO_DEVICE_NAME
|
||||
_getdeployconf SYNO_USERNAME
|
||||
_getdeployconf SYNO_PASSWORD
|
||||
_getdeployconf SYNO_DEVICE_ID
|
||||
_getdeployconf SYNO_DEVICE_NAME
|
||||
|
||||
# Prepare to use temp admin if SYNO_USE_TEMP_ADMIN is set
|
||||
_getdeployconf SYNO_USE_TEMP_ADMIN
|
||||
_check2cleardeployconfexp SYNO_USE_TEMP_ADMIN
|
||||
_debug2 SYNO_USE_TEMP_ADMIN "$SYNO_USE_TEMP_ADMIN"
|
||||
|
||||
if [ -n "$SYNO_USE_TEMP_ADMIN" ]; then
|
||||
if ! _exists synouser || ! _exists synogroup || ! _exists synosetkeyvalue; then
|
||||
_err "Missing required tools to creat temp admin user, please set SYNO_USERNAME and SYNO_PASSWORD instead."
|
||||
_err "Notice: temp admin user authorization method only supports local deployment on DSM."
|
||||
return 1
|
||||
fi
|
||||
if synouser --help 2>&1 | grep -q 'Permission denied'; then
|
||||
_err "For creating temp admin user, the deploy script must be run as root."
|
||||
return 1
|
||||
fi
|
||||
|
||||
[ -n "$SYNO_USERNAME" ] || _savedeployconf SYNO_USERNAME ""
|
||||
[ -n "$SYNO_PASSWORD" ] || _savedeployconf SYNO_PASSWORD ""
|
||||
|
||||
_debug "Setting temp admin user credential..."
|
||||
SYNO_USERNAME=sc-acmesh-tmp
|
||||
SYNO_PASSWORD=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 16)
|
||||
# Set 2FA-OTP settings to empty consider they won't be needed.
|
||||
SYNO_DEVICE_ID=
|
||||
SYNO_DEVICE_NAME=
|
||||
SYNO_OTP_CODE=
|
||||
else
|
||||
_debug2 SYNO_USERNAME "$SYNO_USERNAME"
|
||||
_secure_debug2 SYNO_PASSWORD "$SYNO_PASSWORD"
|
||||
_debug2 SYNO_DEVICE_NAME "$SYNO_DEVICE_NAME"
|
||||
_secure_debug2 SYNO_DEVICE_ID "$SYNO_DEVICE_ID"
|
||||
fi
|
||||
|
||||
if [ -z "$SYNO_USERNAME" ] || [ -z "$SYNO_PASSWORD" ]; then
|
||||
_err "You must set either SYNO_USE_TEMP_ADMIN, or set both SYNO_USERNAME and SYNO_PASSWORD."
|
||||
return 1
|
||||
fi
|
||||
_debug2 SYNO_Username "$SYNO_Username"
|
||||
_secure_debug2 SYNO_Password "$SYNO_Password"
|
||||
|
||||
# Optional scheme, hostname, and port for Synology DSM
|
||||
_getdeployconf SYNO_Scheme
|
||||
_getdeployconf SYNO_Hostname
|
||||
_getdeployconf SYNO_Port
|
||||
# Optional scheme, hostname and port for Synology DSM
|
||||
_migratedeployconf SYNO_Scheme SYNO_SCHEME
|
||||
_migratedeployconf SYNO_Hostname SYNO_HOSTNAME
|
||||
_migratedeployconf SYNO_Port SYNO_PORT
|
||||
_getdeployconf SYNO_SCHEME
|
||||
_getdeployconf SYNO_HOSTNAME
|
||||
_getdeployconf SYNO_PORT
|
||||
|
||||
# default vaules for scheme, hostname, and port
|
||||
# defaulting to localhost and http because it's localhost...
|
||||
[ -n "${SYNO_Scheme}" ] || SYNO_Scheme="http"
|
||||
[ -n "${SYNO_Hostname}" ] || SYNO_Hostname="localhost"
|
||||
[ -n "${SYNO_Port}" ] || SYNO_Port="5000"
|
||||
# Default values for scheme, hostname and port
|
||||
# Defaulting to localhost and http, because it's localhost…
|
||||
[ -n "$SYNO_SCHEME" ] || SYNO_SCHEME=http
|
||||
[ -n "$SYNO_HOSTNAME" ] || SYNO_HOSTNAME=localhost
|
||||
[ -n "$SYNO_PORT" ] || SYNO_PORT=5000
|
||||
_savedeployconf SYNO_SCHEME "$SYNO_SCHEME"
|
||||
_savedeployconf SYNO_HOSTNAME "$SYNO_HOSTNAME"
|
||||
_savedeployconf SYNO_PORT "$SYNO_PORT"
|
||||
_debug2 SYNO_SCHEME "$SYNO_SCHEME"
|
||||
_debug2 SYNO_HOSTNAME "$SYNO_HOSTNAME"
|
||||
_debug2 SYNO_PORT "$SYNO_PORT"
|
||||
|
||||
_savedeployconf SYNO_Scheme "$SYNO_Scheme"
|
||||
_savedeployconf SYNO_Hostname "$SYNO_Hostname"
|
||||
_savedeployconf SYNO_Port "$SYNO_Port"
|
||||
|
||||
_debug2 SYNO_Scheme "$SYNO_Scheme"
|
||||
_debug2 SYNO_Hostname "$SYNO_Hostname"
|
||||
_debug2 SYNO_Port "$SYNO_Port"
|
||||
|
||||
# Get the certificate description, but don't save it until we verfiy it's real
|
||||
_getdeployconf SYNO_Certificate
|
||||
_debug SYNO_Certificate "${SYNO_Certificate:-}"
|
||||
# Get the certificate description, but don't save it until we verify it's real
|
||||
_migratedeployconf SYNO_Certificate SYNO_CERTIFICATE "base64"
|
||||
_getdeployconf SYNO_CERTIFICATE
|
||||
_check2cleardeployconfexp SYNO_CERTIFICATE
|
||||
_debug SYNO_CERTIFICATE "${SYNO_CERTIFICATE:-}"
|
||||
|
||||
# shellcheck disable=SC1003 # We are not trying to escape a single quote
|
||||
if printf "%s" "$SYNO_Certificate" | grep '\\'; then
|
||||
if printf "%s" "$SYNO_CERTIFICATE" | grep '\\'; then
|
||||
_err "Do not use a backslash (\) in your certificate description"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_base_url="$SYNO_Scheme://$SYNO_Hostname:$SYNO_Port"
|
||||
_debug "Getting API version..."
|
||||
_base_url="$SYNO_SCHEME://$SYNO_HOSTNAME:$SYNO_PORT"
|
||||
_debug _base_url "$_base_url"
|
||||
|
||||
_debug "Getting API version"
|
||||
response=$(_get "$_base_url/webapi/query.cgi?api=SYNO.API.Info&version=1&method=query&query=SYNO.API.Auth")
|
||||
api_path=$(echo "$response" | grep "SYNO.API.Auth" | sed -n 's/.*"path" *: *"\([^"]*\)".*/\1/p')
|
||||
api_version=$(echo "$response" | grep "SYNO.API.Auth" | sed -n 's/.*"maxVersion" *: *\([0-9]*\).*/\1/p')
|
||||
_debug3 response "$response"
|
||||
_debug3 api_path "$api_path"
|
||||
_debug3 api_version "$api_version"
|
||||
|
||||
# Login, get the token from JSON and session id from cookie
|
||||
_info "Logging into $SYNO_Hostname:$SYNO_Port"
|
||||
encoded_username="$(printf "%s" "$SYNO_Username" | _url_encode)"
|
||||
encoded_password="$(printf "%s" "$SYNO_Password" | _url_encode)"
|
||||
# Login, get the session ID and SynoToken from JSON
|
||||
_info "Logging into $SYNO_HOSTNAME:$SYNO_PORT..."
|
||||
encoded_username="$(printf "%s" "$SYNO_USERNAME" | _url_encode)"
|
||||
encoded_password="$(printf "%s" "$SYNO_PASSWORD" | _url_encode)"
|
||||
|
||||
# ## START ## - DEPRECATED, for backward compatibility
|
||||
_getdeployconf SYNO_TOTP_SECRET
|
||||
|
||||
otp_code=""
|
||||
if [ -n "$SYNO_TOTP_SECRET" ]; then
|
||||
if _exists oathtool; then
|
||||
otp_code="$(oathtool --base32 --totp "${SYNO_TOTP_SECRET}" 2>/dev/null)"
|
||||
else
|
||||
_info "WARNING: Usage of SYNO_TOTP_SECRET is deprecated!"
|
||||
_info " See synology_dsm.sh script or ACME.sh Wiki page for details:"
|
||||
_info " https://github.com/acmesh-official/acme.sh/wiki/Synology-NAS-Guide"
|
||||
if ! _exists oathtool; then
|
||||
_err "oathtool could not be found, install oathtool to use SYNO_TOTP_SECRET"
|
||||
return 1
|
||||
fi
|
||||
DEPRECATED_otp_code="$(oathtool --base32 --totp "$SYNO_TOTP_SECRET" 2>/dev/null)"
|
||||
|
||||
if [ -z "$SYNO_DEVICE_ID" ]; then
|
||||
_getdeployconf SYNO_DID
|
||||
[ -n "$SYNO_DID" ] || SYNO_DEVICE_ID="$SYNO_DID"
|
||||
fi
|
||||
if [ -n "$SYNO_DEVICE_ID" ]; then
|
||||
_H1="Cookie: did=$SYNO_DEVICE_ID"
|
||||
export _H1
|
||||
_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=$DEPRECATED_otp_code&device_name=certrenewal&device_id=$SYNO_DEVICE_ID" "$_base_url/webapi/$api_path?enable_syno_token=yes")
|
||||
_debug3 response "$response"
|
||||
# ## END ## - DEPRECATED, for backward compatibility
|
||||
# If SYNO_DEVICE_ID or SYNO_OTP_CODE is set, we treat current account enabled 2FA-OTP.
|
||||
# Notice that if SYNO_USE_TEMP_ADMIN=1, both variables will be unset
|
||||
else
|
||||
if [ -n "$SYNO_DEVICE_ID" ] || [ -n "$SYNO_OTP_CODE" ]; then
|
||||
response='{"error":{"code":403}}'
|
||||
# Assume the current account disabled 2FA-OTP, try to log in right away.
|
||||
else
|
||||
if [ -n "$SYNO_USE_TEMP_ADMIN" ]; then
|
||||
_getdeployconf SYNO_LOCAL_HOSTNAME
|
||||
_debug SYNO_LOCAL_HOSTNAME "${SYNO_LOCAL_HOSTNAME:-}"
|
||||
if [ "$SYNO_HOSTNAME" != "localhost" ] && [ "$SYNO_HOSTNAME" != "127.0.0.1" ]; then
|
||||
if [ "$SYNO_LOCAL_HOSTNAME" != "1" ]; then
|
||||
_err "SYNO_USE_TEMP_ADMIN=1 only support local deployment, though if you are sure that the hostname $SYNO_HOSTNAME is targeting to your **current local machine**, execute 'export SYNO_LOCAL_HOSTNAME=1' then rerun."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
_debug "Creating temp admin user in Synology DSM..."
|
||||
if synogroup --help | grep -q '\-\-memberadd '; then
|
||||
_temp_admin_create "$SYNO_USERNAME" "$SYNO_PASSWORD"
|
||||
synogroup --memberadd administrators "$SYNO_USERNAME" >/dev/null
|
||||
elif synogroup --help | grep -q '\-\-member '; then
|
||||
# For supporting DSM 6.x which only has `--member` parameter.
|
||||
cur_admins=$(synogroup --get administrators | awk -F '[][]' '/Group Members/,0{if(NF>1)printf "%s ", $2}')
|
||||
if [ -n "$cur_admins" ]; then
|
||||
_temp_admin_create "$SYNO_USERNAME" "$SYNO_PASSWORD"
|
||||
_secure_debug3 admin_users "$cur_admins$SYNO_USERNAME"
|
||||
# shellcheck disable=SC2086
|
||||
synogroup --member administrators $cur_admins $SYNO_USERNAME >/dev/null
|
||||
else
|
||||
_err "The tool synogroup may be broken, please set SYNO_USERNAME and SYNO_PASSWORD instead."
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_err "Unsupported synogroup tool detected, please set SYNO_USERNAME and SYNO_PASSWORD instead."
|
||||
return 1
|
||||
fi
|
||||
# havig a workaround to temporary disable enforce 2FA-OTP, will restore
|
||||
# it soon (after a single request), though if any accident occurs like
|
||||
# unexpected interruption, this setting can be easily reverted manually.
|
||||
otp_enforce_option=$(synogetkeyvalue /etc/synoinfo.conf otp_enforce_option)
|
||||
if [ -n "$otp_enforce_option" ] && [ "${otp_enforce_option:-"none"}" != "none" ]; then
|
||||
synosetkeyvalue /etc/synoinfo.conf otp_enforce_option none
|
||||
_info "Enforcing 2FA-OTP has been disabled to complete temp admin authentication."
|
||||
_info "Notice: it will be restored soon, if not, you can restore it manually via Control Panel."
|
||||
_info "previous_otp_enforce_option" "$otp_enforce_option"
|
||||
else
|
||||
otp_enforce_option=""
|
||||
fi
|
||||
fi
|
||||
response=$(_get "$_base_url/webapi/$api_path?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&enable_syno_token=yes")
|
||||
if [ -n "$SYNO_USE_TEMP_ADMIN" ] && [ -n "$otp_enforce_option" ]; then
|
||||
synosetkeyvalue /etc/synoinfo.conf otp_enforce_option "$otp_enforce_option"
|
||||
_info "Restored previous enforce 2FA-OTP option."
|
||||
fi
|
||||
_debug3 response "$response"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$SYNO_DID" ]; then
|
||||
_H1="Cookie: did=$SYNO_DID"
|
||||
export _H1
|
||||
_debug3 H1 "${_H1}"
|
||||
error_code=$(echo "$response" | grep '"error":' | grep -o '"code":[0-9]*' | grep -o '[0-9]*')
|
||||
_debug2 error_code "$error_code"
|
||||
# Account has 2FA-OTP enabled, since error 403 reported.
|
||||
# https://global.download.synology.com/download/Document/Software/DeveloperGuide/Os/DSM/All/enu/DSM_Login_Web_API_Guide_enu.pdf
|
||||
if [ "$error_code" == "403" ]; then
|
||||
if [ -z "$SYNO_DEVICE_NAME" ]; then
|
||||
printf "Enter device name or leave empty for default (CertRenewal): "
|
||||
read -r SYNO_DEVICE_NAME
|
||||
[ -n "$SYNO_DEVICE_NAME" ] || SYNO_DEVICE_NAME="CertRenewal"
|
||||
fi
|
||||
|
||||
if [ -n "$SYNO_DEVICE_ID" ]; then
|
||||
# Omit OTP code with SYNO_DEVICE_ID.
|
||||
response=$(_get "$_base_url/webapi/$api_path?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&enable_syno_token=yes&device_name=$SYNO_DEVICE_NAME&device_id=$SYNO_DEVICE_ID")
|
||||
_secure_debug3 response "$response"
|
||||
else
|
||||
# Require the OTP code if still unset.
|
||||
if [ -z "$SYNO_OTP_CODE" ]; then
|
||||
printf "Enter OTP code for user '%s': " "$SYNO_USERNAME"
|
||||
read -r SYNO_OTP_CODE
|
||||
fi
|
||||
_secure_debug SYNO_OTP_CODE "${SYNO_OTP_CODE:-}"
|
||||
|
||||
if [ -z "$SYNO_OTP_CODE" ]; then
|
||||
response='{"error":{"code":404}}'
|
||||
else
|
||||
response=$(_get "$_base_url/webapi/$api_path?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&enable_syno_token=yes&enable_device_token=yes&device_name=$SYNO_DEVICE_NAME&otp_code=$SYNO_OTP_CODE")
|
||||
_secure_debug3 response "$response"
|
||||
|
||||
id_property='device_id'
|
||||
[ "${api_version}" -gt '6' ] || id_property='did'
|
||||
SYNO_DEVICE_ID=$(echo "$response" | grep "$id_property" | sed -n 's/.*"'$id_property'" *: *"\([^"]*\).*/\1/p')
|
||||
_secure_debug2 SYNO_DEVICE_ID "$SYNO_DEVICE_ID"
|
||||
fi
|
||||
fi
|
||||
error_code=$(echo "$response" | grep '"error":' | grep -o '"code":[0-9]*' | grep -o '[0-9]*')
|
||||
_debug2 error_code "$error_code"
|
||||
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&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"
|
||||
|
||||
if [ -z "$token" ]; then
|
||||
_err "Unable to authenticate to $SYNO_Hostname:$SYNO_Port using $SYNO_Scheme."
|
||||
_err "Check your username and password."
|
||||
_err "If two-factor authentication is enabled for the user, set SYNO_TOTP_SECRET."
|
||||
if [ -n "$error_code" ]; then
|
||||
if [ "$error_code" == "403" ] && [ -n "$SYNO_DEVICE_ID" ]; then
|
||||
_cleardeployconf SYNO_DEVICE_ID
|
||||
_err "Failed to authenticate with SYNO_DEVICE_ID (may expired or invalid), please try again in a new terminal window."
|
||||
elif [ "$error_code" == "404" ]; then
|
||||
_err "Failed to authenticate with provided 2FA-OTP code, please try again in a new terminal window."
|
||||
elif [ "$error_code" == "406" ]; then
|
||||
if [ -n "$SYNO_USE_TEMP_ADMIN" ]; then
|
||||
_err "Failed with unexcepted error, please report this by providing full log with '--debug 3'."
|
||||
else
|
||||
_err "Enforce auth with 2FA-OTP enabled, please configure the user to enable 2FA-OTP to continue."
|
||||
fi
|
||||
elif [ "$error_code" == "400" ]; then
|
||||
_err "Failed to authenticate, no such account or incorrect password."
|
||||
elif [ "$error_code" == "401" ]; then
|
||||
_err "Failed to authenticate with a non-existent account."
|
||||
elif [ "$error_code" == "408" ] || [ "$error_code" == "409" ] || [ "$error_code" == "410" ]; then
|
||||
_err "Failed to authenticate, the account password has expired or must be changed."
|
||||
else
|
||||
_err "Failed to authenticate with error: $error_code."
|
||||
fi
|
||||
_temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
|
||||
return 1
|
||||
fi
|
||||
|
||||
sid=$(echo "$response" | grep "sid" | sed -n 's/.*"sid" *: *"\([^"]*\).*/\1/p')
|
||||
token=$(echo "$response" | grep "synotoken" | sed -n 's/.*"synotoken" *: *"\([^"]*\).*/\1/p')
|
||||
_debug "Session ID" "$sid"
|
||||
_debug SynoToken "$token"
|
||||
if [ -z "$sid" ] || [ -z "$token" ]; then
|
||||
# Still can't get necessary info even got no errors, may Synology have API updated?
|
||||
_err "Unable to authenticate to $_base_url, you may report this by providing full log with '--debug 3'."
|
||||
_temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_H1="X-SYNO-TOKEN: $token"
|
||||
export _H1
|
||||
_debug2 H1 "${_H1}"
|
||||
|
||||
# Now that we know the username and password are good, save them
|
||||
_savedeployconf SYNO_Username "$SYNO_Username"
|
||||
_savedeployconf SYNO_Password "$SYNO_Password"
|
||||
_savedeployconf SYNO_DID "$SYNO_DID"
|
||||
_savedeployconf SYNO_TOTP_SECRET "$SYNO_TOTP_SECRET"
|
||||
# Now that we know the username and password are good, save them if not in temp admin mode.
|
||||
if [ -n "$SYNO_USE_TEMP_ADMIN" ]; then
|
||||
_cleardeployconf SYNO_USERNAME
|
||||
_cleardeployconf SYNO_PASSWORD
|
||||
_cleardeployconf SYNO_DEVICE_ID
|
||||
_cleardeployconf SYNO_DEVICE_NAME
|
||||
_savedeployconf SYNO_USE_TEMP_ADMIN "$SYNO_USE_TEMP_ADMIN"
|
||||
_savedeployconf SYNO_LOCAL_HOSTNAME "$SYNO_LOCAL_HOSTNAME"
|
||||
else
|
||||
_savedeployconf SYNO_USERNAME "$SYNO_USERNAME"
|
||||
_savedeployconf SYNO_PASSWORD "$SYNO_PASSWORD"
|
||||
_savedeployconf SYNO_DEVICE_ID "$SYNO_DEVICE_ID"
|
||||
_savedeployconf SYNO_DEVICE_NAME "$SYNO_DEVICE_NAME"
|
||||
fi
|
||||
|
||||
_info "Getting certificates in Synology DSM"
|
||||
_info "Getting certificates in Synology DSM..."
|
||||
response=$(_post "api=SYNO.Core.Certificate.CRT&method=list&version=1&_sid=$sid" "$_base_url/webapi/entry.cgi")
|
||||
_debug3 response "$response"
|
||||
escaped_certificate="$(printf "%s" "$SYNO_Certificate" | sed 's/\([].*^$[]\)/\\\1/g;s/"/\\\\"/g')"
|
||||
escaped_certificate="$(printf "%s" "$SYNO_CERTIFICATE" | sed 's/\([].*^$[]\)/\\\1/g;s/"/\\\\"/g')"
|
||||
_debug escaped_certificate "$escaped_certificate"
|
||||
id=$(echo "$response" | sed -n "s/.*\"desc\":\"$escaped_certificate\",\"id\":\"\([^\"]*\).*/\1/p")
|
||||
_debug2 id "$id"
|
||||
|
||||
if [ -z "$id" ] && [ -z "${SYNO_Create:-}" ]; then
|
||||
_err "Unable to find certificate: $SYNO_Certificate and \$SYNO_Create is not set"
|
||||
error_code=$(echo "$response" | grep '"error":' | grep -o '"code":[0-9]*' | grep -o '[0-9]*')
|
||||
_debug2 error_code "$error_code"
|
||||
if [ -n "$error_code" ]; then
|
||||
if [ "$error_code" -eq 105 ]; then
|
||||
_err "Current user is not administrator and does not have sufficient permission for deploying."
|
||||
else
|
||||
_err "Failed to fetch certificate info: $error_code, please try again or contact Synology to learn more."
|
||||
fi
|
||||
_temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# we've verified this certificate description is a thing, so save it
|
||||
_savedeployconf SYNO_Certificate "$SYNO_Certificate" "base64"
|
||||
_migratedeployconf SYNO_Create SYNO_CREATE
|
||||
_getdeployconf SYNO_CREATE
|
||||
_debug2 SYNO_CREATE "$SYNO_CREATE"
|
||||
|
||||
_info "Generate form POST request"
|
||||
if [ -z "$id" ] && [ -z "$SYNO_CREATE" ]; then
|
||||
_err "Unable to find certificate: $SYNO_CERTIFICATE and $SYNO_CREATE is not set."
|
||||
_temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# We've verified this certificate description is a thing, so save it
|
||||
_savedeployconf SYNO_CERTIFICATE "$SYNO_CERTIFICATE" "base64"
|
||||
|
||||
_info "Generating form POST request..."
|
||||
nl="\0015\0012"
|
||||
delim="--------------------------$(_utc_date | tr -d -- '-: ')"
|
||||
content="--$delim${nl}Content-Disposition: form-data; name=\"key\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")\0012"
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"cert\"; filename=\"$(basename "$_ccert")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ccert")\0012"
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"inter_cert\"; filename=\"$(basename "$_cca")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_cca")\0012"
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"id\"${nl}${nl}$id"
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"desc\"${nl}${nl}${SYNO_Certificate}"
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"desc\"${nl}${nl}${SYNO_CERTIFICATE}"
|
||||
if echo "$response" | sed -n "s/.*\"desc\":\"$escaped_certificate\",\([^{]*\).*/\1/p" | grep -- 'is_default":true' >/dev/null; then
|
||||
_debug2 default "this is the default certificate"
|
||||
_debug2 default "This is the default certificate"
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"as_default\"${nl}${nl}true"
|
||||
else
|
||||
_debug2 default "this is NOT the default certificate"
|
||||
_debug2 default "This is NOT the default certificate"
|
||||
fi
|
||||
content="$content${nl}--$delim--${nl}"
|
||||
content="$(printf "%b_" "$content")"
|
||||
content="${content%_}" # protect trailing \n
|
||||
|
||||
_info "Upload certificate to the Synology DSM"
|
||||
_info "Upload certificate to the Synology DSM."
|
||||
response=$(_post "$content" "$_base_url/webapi/entry.cgi?api=SYNO.Core.Certificate&method=import&version=1&SynoToken=$token&_sid=$sid" "" "POST" "multipart/form-data; boundary=${delim}")
|
||||
_debug3 response "$response"
|
||||
|
||||
if ! echo "$response" | grep '"error":' >/dev/null; then
|
||||
if echo "$response" | grep '"restart_httpd":true' >/dev/null; then
|
||||
_info "http services were restarted"
|
||||
_info "Restart HTTP services succeeded."
|
||||
else
|
||||
_info "http services were NOT restarted"
|
||||
_info "Restart HTTP services failed."
|
||||
fi
|
||||
_temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
|
||||
_logout
|
||||
return 0
|
||||
else
|
||||
_err "Unable to update certificate, error code $response"
|
||||
_temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
|
||||
_err "Unable to update certificate, got error response: $response."
|
||||
_logout
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
_logout() {
|
||||
# Logout CERT user only to not occupy a permanent session, e.g. in DSM's "Connected Users" widget (based on previous variables)
|
||||
response=$(_get "$_base_url/webapi/$api_path?api=SYNO.API.Auth&version=$api_version&method=logout&_sid=$sid")
|
||||
_debug3 response "$response"
|
||||
}
|
||||
|
||||
_temp_admin_create() {
|
||||
_username="$1"
|
||||
_password="$2"
|
||||
synouser --del "$_username" >/dev/null 2>/dev/null
|
||||
synouser --add "$_username" "$_password" "" 0 "" 0 >/dev/null
|
||||
}
|
||||
|
||||
_temp_admin_cleanup() {
|
||||
_flag=$1
|
||||
_username=$2
|
||||
|
||||
if [ -n "${_flag}" ]; then
|
||||
_debug "Cleanuping temp admin info..."
|
||||
synouser --del "$_username" >/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
#_cleardeployconf key
|
||||
_cleardeployconf() {
|
||||
_cleardomainconf "SAVED_$1"
|
||||
}
|
||||
|
||||
# key
|
||||
_check2cleardeployconfexp() {
|
||||
_key="$1"
|
||||
_clear_key="CLEAR_$_key"
|
||||
# Clear saved settings if explicitly requested
|
||||
if [ -n "$(eval echo \$"$_clear_key")" ]; then
|
||||
_debug2 "$_key: value cleared from config, exported value will be ignored."
|
||||
_cleardeployconf "$_key"
|
||||
eval "$_key"=
|
||||
export "$_key"=
|
||||
eval SAVED_"$_key"=
|
||||
export SAVED_"$_key"=
|
||||
fi
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
#
|
||||
# Following environment variables must be set:
|
||||
#
|
||||
# export DEPLOY_TRUENAS_APIKEY="<API_KEY_GENERATED_IN_THE_WEB_UI"
|
||||
# export DEPLOY_TRUENAS_APIKEY="<API_KEY_GENERATED_IN_THE_WEB_UI>"
|
||||
#
|
||||
# The following environmental variables may be set if you don't like their
|
||||
# default values:
|
||||
@ -64,6 +64,20 @@ truenas_deploy() {
|
||||
_response=$(_get "$_api_url/system/state")
|
||||
_info "TrueNAS system state: $_response."
|
||||
|
||||
_info "Getting TrueNAS version"
|
||||
_response=$(_get "$_api_url/system/version")
|
||||
|
||||
if echo "$_response" | grep -q "SCALE"; then
|
||||
_truenas_os=$(echo "$_response" | cut -d '-' -f 2)
|
||||
_truenas_version=$(echo "$_response" | cut -d '-' -f 3 | tr -d '"' | cut -d '.' -f 1,2)
|
||||
else
|
||||
_truenas_os="unknown"
|
||||
_truenas_version="unknown"
|
||||
fi
|
||||
|
||||
_info "Detected TrueNAS system os: $_truenas_os"
|
||||
_info "Detected TrueNAS system version: $_truenas_version"
|
||||
|
||||
if [ -z "$_response" ]; then
|
||||
_err "Unable to authenticate to $_api_url."
|
||||
_err 'Check your connection settings are correct, e.g.'
|
||||
@ -115,27 +129,106 @@ truenas_deploy() {
|
||||
|
||||
_debug3 _activate_result "$_activate_result"
|
||||
|
||||
_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: ,')
|
||||
_truenas_version_23_10="23.10"
|
||||
_truenas_version_24_10="24.10"
|
||||
|
||||
if [ "$_webdav_cert_id" = "$_active_cert_id" ]; then
|
||||
_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 | grep '"certssl":' | sed -n 's/.*: \([0-9]\{1,\}\),\{0,1\}$/\1/p')
|
||||
if [ "$_webdav_new_cert_id" -eq "$_cert_id" ]; then
|
||||
_info "WebDAV certificate updated successfully"
|
||||
else
|
||||
_err "Unable to set WebDAV certificate"
|
||||
_debug3 _activate_webdav_cert "$_activate_webdav_cert"
|
||||
_check_version=$(printf "%s\n%s" "$_truenas_version_23_10" "$_truenas_version" | sort -V | head -n 1)
|
||||
if [ "$_truenas_os" != "SCALE" ] || [ "$_check_version" != "$_truenas_version_23_10" ]; then
|
||||
_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 "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 | grep '"certssl":' | sed -n 's/.*: \([0-9]\{1,\}\),\{0,1\}$/\1/p')
|
||||
if [ "$_webdav_new_cert_id" -eq "$_cert_id" ]; then
|
||||
_info "WebDAV certificate updated successfully"
|
||||
else
|
||||
_err "Unable to set WebDAV certificate"
|
||||
_debug3 _activate_webdav_cert "$_activate_webdav_cert"
|
||||
_debug3 _webdav_new_cert_id "$_webdav_new_cert_id"
|
||||
return 1
|
||||
fi
|
||||
_debug3 _webdav_new_cert_id "$_webdav_new_cert_id"
|
||||
return 1
|
||||
else
|
||||
_info "WebDAV certificate is not configured or is not the same as TrueNAS web UI"
|
||||
fi
|
||||
|
||||
_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
|
||||
fi
|
||||
|
||||
if [ "$_truenas_os" = "SCALE" ]; then
|
||||
_check_version=$(printf "%s\n%s" "$_truenas_version_24_10" "$_truenas_version" | sort -V | head -n 1)
|
||||
if [ "$_check_version" != "$_truenas_version_24_10" ]; then
|
||||
_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
|
||||
else
|
||||
_info "Checking if any app is using the same certificate as TrueNAS web UI. Tool 'jq' is required"
|
||||
if _exists jq; then
|
||||
_info "Query all apps"
|
||||
_app_list=$(_get "$_api_url/app")
|
||||
_app_id_list=$(printf "%s" "$_app_list" | jq -r '.[].name')
|
||||
_app_length=$(echo "$_app_id_list" | wc -l)
|
||||
_info "Found $_app_length apps"
|
||||
_info "Checking for each app if an update is needed"
|
||||
for i in $(seq 1 "$_app_length"); do
|
||||
_app_id=$(echo "$_app_id_list" | sed -n "${i}p")
|
||||
_app_config="$(_post "\"$_app_id\"" "$_api_url/app/config" "" "POST" "application/json")"
|
||||
# Check if the app use the same certificate TrueNAS web UI
|
||||
_app_active_cert_config=$(echo "$_app_config" | tr -d '\000-\037' | _json_decode | jq -r ".ix_certificates[\"$_active_cert_id\"]")
|
||||
if [ "$_app_active_cert_config" != "null" ]; then
|
||||
_info "Updating certificate from $_active_cert_id to $_cert_id for app: $_app_id"
|
||||
#Replace the old certificate id with the new one in path
|
||||
_update_app_result="$(_post "{\"values\" : { \"network\": { \"certificate_id\": $_cert_id } } }" "$_api_url/app/id/$_app_id" "" "PUT" "application/json")"
|
||||
_debug3 _update_app_result "$_update_app_result"
|
||||
fi
|
||||
done
|
||||
else
|
||||
_info "Tool 'jq' does not exists, skip app checking"
|
||||
fi
|
||||
fi
|
||||
_debug3 _webdav_new_cert_id "$_webdav_new_cert_id"
|
||||
else
|
||||
_info "WebDAV certificate is not configured or is not the same as TrueNAS web UI"
|
||||
fi
|
||||
|
||||
_info "Checking if FTP certificate is the same as the TrueNAS web UI"
|
||||
@ -161,50 +254,6 @@ truenas_deploy() {
|
||||
_info "FTP certificate is not configured or is not the same as TrueNAS web UI"
|
||||
fi
|
||||
|
||||
_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")"
|
||||
|
||||
|
325
deploy/truenas_ws.sh
Normal file
325
deploy/truenas_ws.sh
Normal file
@ -0,0 +1,325 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# TrueNAS deploy script for SCALE/CORE using websocket
|
||||
# It is recommend to use a wildcard certificate
|
||||
#
|
||||
# Websocket Documentation: https://www.truenas.com/docs/api/scale_websocket_api.html
|
||||
#
|
||||
# Tested with TrueNAS Scale - Electric Eel 24.10
|
||||
# Changes certificate in the following services:
|
||||
# - Web UI
|
||||
# - FTP
|
||||
# - iX Apps
|
||||
#
|
||||
# The following environment variables must be set:
|
||||
# ------------------------------------------------
|
||||
#
|
||||
# # API KEY
|
||||
# # Use the folowing URL to create a new API token: <TRUENAS_HOSTNAME OR IP>/ui/apikeys
|
||||
# export DEPLOY_TRUENAS_APIKEY="<API_KEY_GENERATED_IN_THE_WEB_UI"
|
||||
#
|
||||
|
||||
### Private functions
|
||||
|
||||
# Call websocket method
|
||||
# Usage:
|
||||
# _ws_response=$(_ws_call "math.dummycalc" "'{"x": 4, "y": 5}'")
|
||||
# _info "$_ws_response"
|
||||
#
|
||||
# Output:
|
||||
# {"z": 9}
|
||||
#
|
||||
# Arguments:
|
||||
# $@ - midclt arguments for call
|
||||
#
|
||||
# Returns:
|
||||
# JSON/JOBID
|
||||
_ws_call() {
|
||||
_debug "_ws_call arg1" "$1"
|
||||
_debug "_ws_call arg2" "$2"
|
||||
_debug "_ws_call arg3" "$3"
|
||||
if [ $# -eq 3 ]; then
|
||||
_ws_response=$(midclt -K "$DEPLOY_TRUENAS_APIKEY" call "$1" "$2" "$3")
|
||||
fi
|
||||
if [ $# -eq 2 ]; then
|
||||
_ws_response=$(midclt -K "$DEPLOY_TRUENAS_APIKEY" call "$1" "$2")
|
||||
fi
|
||||
if [ $# -eq 1 ]; then
|
||||
_ws_response=$(midclt -K "$DEPLOY_TRUENAS_APIKEY" call "$1")
|
||||
fi
|
||||
_debug "_ws_response" "$_ws_response"
|
||||
printf "%s" "$_ws_response"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Upload certificate with webclient api
|
||||
_ws_upload_cert() {
|
||||
|
||||
/usr/bin/env python - <<EOF
|
||||
|
||||
import sys
|
||||
|
||||
from truenas_api_client import Client
|
||||
with Client() as c:
|
||||
|
||||
### Login with API key
|
||||
print("I:Trying to upload new certificate...")
|
||||
ret = c.call("auth.login_with_api_key", "${DEPLOY_TRUENAS_APIKEY}")
|
||||
if ret:
|
||||
### upload certificate
|
||||
with open('$1', 'r') as file:
|
||||
fullchain = file.read()
|
||||
with open('$2', 'r') as file:
|
||||
privatekey = file.read()
|
||||
ret = c.call("certificate.create", {"name": "$3", "create_type": "CERTIFICATE_CREATE_IMPORTED", "certificate": fullchain, "privatekey": privatekey, "passphrase": ""}, job=True)
|
||||
print("R:" + str(ret["id"]))
|
||||
sys.exit(0)
|
||||
else:
|
||||
print("R:0")
|
||||
print("E:_ws_upload_cert error!")
|
||||
sys.exit(7)
|
||||
|
||||
EOF
|
||||
|
||||
return $?
|
||||
|
||||
}
|
||||
|
||||
# Check argument is a number
|
||||
# Usage:
|
||||
#
|
||||
# Output:
|
||||
# n/a
|
||||
#
|
||||
# Arguments:
|
||||
# $1 - Anything
|
||||
#
|
||||
# Returns:
|
||||
# 0: true
|
||||
# 1: false
|
||||
_ws_check_jobid() {
|
||||
case "$1" in
|
||||
[0-9]*)
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
return 1
|
||||
}
|
||||
|
||||
# Wait for job to finish and return result as JSON
|
||||
# Usage:
|
||||
# _ws_result=$(_ws_get_job_result "$_ws_jobid")
|
||||
# _new_certid=$(printf "%s" "$_ws_result" | jq -r '."id"')
|
||||
#
|
||||
# Output:
|
||||
# JSON result of the job
|
||||
#
|
||||
# Arguments:
|
||||
# $1 - JobID
|
||||
#
|
||||
# Returns:
|
||||
# n/a
|
||||
_ws_get_job_result() {
|
||||
while true; do
|
||||
sleep 2
|
||||
_ws_response=$(_ws_call "core.get_jobs" "[[\"id\", \"=\", $1]]")
|
||||
if [ "$(printf "%s" "$_ws_response" | jq -r '.[]."state"')" != "RUNNING" ]; then
|
||||
_ws_result="$(printf "%s" "$_ws_response" | jq '.[]."result"')"
|
||||
_debug "_ws_result" "$_ws_result"
|
||||
printf "%s" "$_ws_result"
|
||||
_ws_error="$(printf "%s" "$_ws_response" | jq '.[]."error"')"
|
||||
if [ "$_ws_error" != "null" ]; then
|
||||
_err "Job $1 failed:"
|
||||
_err "$_ws_error"
|
||||
return 7
|
||||
fi
|
||||
break
|
||||
fi
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
########################
|
||||
### Public functions ###
|
||||
########################
|
||||
|
||||
# truenas_ws_deploy
|
||||
#
|
||||
# Deploy new certificate to TrueNAS services
|
||||
#
|
||||
# Arguments
|
||||
# 1: Domain
|
||||
# 2: Key-File
|
||||
# 3: Certificate-File
|
||||
# 4: CA-File
|
||||
# 5: FullChain-File
|
||||
# Returns:
|
||||
# 0: Success
|
||||
# 1: Missing API Key
|
||||
# 2: TrueNAS not ready
|
||||
# 3: Not a JobID
|
||||
# 4: FTP cert error
|
||||
# 5: WebUI cert error
|
||||
# 6: Job error
|
||||
# 7: WS call error
|
||||
#
|
||||
truenas_ws_deploy() {
|
||||
_domain="$1"
|
||||
_file_key="$2"
|
||||
_file_cert="$3"
|
||||
_file_ca="$4"
|
||||
_file_fullchain="$5"
|
||||
_debug _domain "$_domain"
|
||||
_debug _file_key "$_file_key"
|
||||
_debug _file_cert "$_file_cert"
|
||||
_debug _file_ca "$_file_ca"
|
||||
_debug _file_fullchain "$_file_fullchain"
|
||||
|
||||
########## Environment check
|
||||
|
||||
_info "Checking environment variables..."
|
||||
_getdeployconf DEPLOY_TRUENAS_APIKEY
|
||||
# Check API Key
|
||||
if [ -z "$DEPLOY_TRUENAS_APIKEY" ]; then
|
||||
_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"
|
||||
_info "Environment variables: OK"
|
||||
|
||||
########## Health check
|
||||
|
||||
_info "Checking TrueNAS health..."
|
||||
_ws_response=$(_ws_call "system.ready" | tr '[:lower:]' '[:upper:]')
|
||||
_ws_ret=$?
|
||||
if [ $_ws_ret -gt 0 ]; then
|
||||
_err "Error calling system.ready:"
|
||||
_err "$_ws_response"
|
||||
return $_ws_ret
|
||||
fi
|
||||
|
||||
if [ "$_ws_response" != "TRUE" ]; then
|
||||
_err "TrueNAS is not ready."
|
||||
_err "Please check environment variables DEPLOY_TRUENAS_APIKEY, DEPLOY_TRUENAS_HOSTNAME and DEPLOY_TRUENAS_PROTOCOL."
|
||||
_err "Verify API key."
|
||||
return 2
|
||||
fi
|
||||
_savedeployconf DEPLOY_TRUENAS_APIKEY "$DEPLOY_TRUENAS_APIKEY"
|
||||
_info "TrueNAS health: OK"
|
||||
|
||||
########## System info
|
||||
|
||||
_info "Gather system info..."
|
||||
_ws_response=$(_ws_call "system.info")
|
||||
_truenas_version=$(printf "%s" "$_ws_response" | jq -r '."version"')
|
||||
_info "TrueNAS version: $_truenas_version"
|
||||
|
||||
########## Gather current certificate
|
||||
|
||||
_info "Gather current WebUI certificate..."
|
||||
_ws_response="$(_ws_call "system.general.config")"
|
||||
_ui_certificate_id=$(printf "%s" "$_ws_response" | jq -r '."ui_certificate"."id"')
|
||||
_ui_certificate_name=$(printf "%s" "$_ws_response" | jq -r '."ui_certificate"."name"')
|
||||
_info "Current WebUI certificate ID: $_ui_certificate_id"
|
||||
_info "Current WebUI certificate name: $_ui_certificate_name"
|
||||
|
||||
########## Upload new certificate
|
||||
|
||||
_info "Upload new certificate..."
|
||||
_certname="acme_$(_utc_date | tr -d '\-\:' | tr ' ' '_')"
|
||||
_info "New WebUI certificate name: $_certname"
|
||||
_debug _certname "$_certname"
|
||||
_ws_out=$(_ws_upload_cert "$_file_fullchain" "$_file_key" "$_certname")
|
||||
|
||||
echo "$_ws_out" | while IFS= read -r LINE; do
|
||||
case "$LINE" in
|
||||
I:*)
|
||||
_info "${LINE#I:}"
|
||||
;;
|
||||
D:*)
|
||||
_debug "${LINE#D:}"
|
||||
;;
|
||||
E*)
|
||||
_err "${LINE#E:}"
|
||||
;;
|
||||
*) ;;
|
||||
|
||||
esac
|
||||
done
|
||||
|
||||
_new_certid=$(echo "$_ws_out" | grep 'R:' | cut -d ':' -f 2)
|
||||
|
||||
_info "New certificate ID: $_new_certid"
|
||||
|
||||
########## FTP
|
||||
|
||||
_info "Replace FTP certificate..."
|
||||
_ws_response=$(_ws_call "ftp.update" "{\"ssltls_certificate\": $_new_certid}")
|
||||
_ftp_certid=$(printf "%s" "$_ws_response" | jq -r '."ssltls_certificate"')
|
||||
if [ "$_ftp_certid" != "$_new_certid" ]; then
|
||||
_err "Cannot set FTP certificate."
|
||||
_debug "_ws_response" "$_ws_response"
|
||||
return 4
|
||||
fi
|
||||
|
||||
########## ix Apps (SCALE only)
|
||||
|
||||
_info "Replace app certificates..."
|
||||
_ws_response=$(_ws_call "app.query")
|
||||
for _app_name in $(printf "%s" "$_ws_response" | jq -r '.[]."name"'); do
|
||||
_info "Checking app $_app_name..."
|
||||
_ws_response=$(_ws_call "app.config" "$_app_name")
|
||||
if [ "$(printf "%s" "$_ws_response" | jq -r '."network" | has("certificate_id")')" = "true" ]; then
|
||||
_info "App has certificate option, setup new certificate..."
|
||||
_info "App will be redeployed after updating the certificate."
|
||||
_ws_jobid=$(_ws_call "app.update" "$_app_name" "{\"values\": {\"network\": {\"certificate_id\": $_new_certid}}}")
|
||||
_debug "_ws_jobid" "$_ws_jobid"
|
||||
if ! _ws_check_jobid "$_ws_jobid"; then
|
||||
_err "No JobID returned from websocket method."
|
||||
return 3
|
||||
fi
|
||||
_ws_result=$(_ws_get_job_result "$_ws_jobid")
|
||||
_ws_ret=$?
|
||||
if [ $_ws_ret -gt 0 ]; then
|
||||
return $_ws_ret
|
||||
fi
|
||||
_debug "_ws_result" "$_ws_result"
|
||||
_info "App certificate replaced."
|
||||
else
|
||||
_info "App has no certificate option, skipping..."
|
||||
fi
|
||||
done
|
||||
|
||||
########## WebUI
|
||||
|
||||
_info "Replace WebUI certificate..."
|
||||
_ws_response=$(_ws_call "system.general.update" "{\"ui_certificate\": $_new_certid}")
|
||||
_changed_certid=$(printf "%s" "$_ws_response" | jq -r '."ui_certificate"."id"')
|
||||
if [ "$_changed_certid" != "$_new_certid" ]; then
|
||||
_err "WebUI certificate change error.."
|
||||
return 5
|
||||
else
|
||||
_info "WebUI certificate replaced."
|
||||
fi
|
||||
_info "Restarting WebUI..."
|
||||
_ws_response=$(_ws_call "system.general.ui_restart")
|
||||
_info "Waiting for UI restart..."
|
||||
sleep 6
|
||||
|
||||
########## Certificates
|
||||
|
||||
_info "Deleting old certificate..."
|
||||
_ws_jobid=$(_ws_call "certificate.delete" "$_ui_certificate_id")
|
||||
if ! _ws_check_jobid "$_ws_jobid"; then
|
||||
_err "No JobID returned from websocket method."
|
||||
return 3
|
||||
fi
|
||||
_ws_result=$(_ws_get_job_result "$_ws_jobid")
|
||||
_ws_ret=$?
|
||||
if [ $_ws_ret -gt 0 ]; then
|
||||
return $_ws_ret
|
||||
fi
|
||||
|
||||
_info "Have a nice day...bye!"
|
||||
|
||||
}
|
145
deploy/unifi.sh
145
deploy/unifi.sh
@ -5,6 +5,15 @@
|
||||
# - self-hosted Unifi Controller
|
||||
# - Unifi Cloud Key (Gen1/2/2+)
|
||||
# - Unifi Cloud Key running UnifiOS (v2.0.0+, Gen2/2+ only)
|
||||
# - Unifi Dream Machine
|
||||
# This has not been tested on other "all-in-one" devices such as
|
||||
# UDM Pro or Unifi Express.
|
||||
#
|
||||
# OS Version v2.0.0+
|
||||
# Network Application version 7.0.0+
|
||||
# OS version ~3.1 removed java and keytool from the UnifiOS.
|
||||
# Using PKCS12 format keystore appears to work fine.
|
||||
#
|
||||
# Please report bugs to https://github.com/acmesh-official/acme.sh/issues/3359
|
||||
|
||||
#returns 0 means success, otherwise error.
|
||||
@ -21,7 +30,9 @@
|
||||
# Keystore password (built into Unifi Controller, not a user-set password):
|
||||
#DEPLOY_UNIFI_KEYPASS="aircontrolenterprise"
|
||||
# Command to restart Unifi Controller:
|
||||
#DEPLOY_UNIFI_RELOAD="service unifi restart"
|
||||
# DEPLOY_UNIFI_RELOAD="systemctl restart unifi"
|
||||
# System Properties file location for controller
|
||||
#DEPLOY_UNIFI_SYSTEM_PROPERTIES="/usr/lib/unifi/data/system.properties"
|
||||
#
|
||||
# Settings for Unifi Cloud Key Gen1 (nginx admin pages):
|
||||
# Directory where cloudkey.crt and cloudkey.key live:
|
||||
@ -34,7 +45,7 @@
|
||||
# Directory where unifi-core.crt and unifi-core.key live:
|
||||
#DEPLOY_UNIFI_CORE_CONFIG="/data/unifi-core/config/"
|
||||
# Command to restart unifi-core:
|
||||
#DEPLOY_UNIFI_RELOAD="systemctl restart unifi-core"
|
||||
# DEPLOY_UNIFI_OS_RELOAD="systemctl restart unifi-core"
|
||||
#
|
||||
# At least one of DEPLOY_UNIFI_KEYSTORE, DEPLOY_UNIFI_CLOUDKEY_CERTDIR,
|
||||
# or DEPLOY_UNIFI_CORE_CONFIG must exist to receive the deployed certs.
|
||||
@ -60,12 +71,16 @@ unifi_deploy() {
|
||||
_getdeployconf DEPLOY_UNIFI_CLOUDKEY_CERTDIR
|
||||
_getdeployconf DEPLOY_UNIFI_CORE_CONFIG
|
||||
_getdeployconf DEPLOY_UNIFI_RELOAD
|
||||
_getdeployconf DEPLOY_UNIFI_SYSTEM_PROPERTIES
|
||||
_getdeployconf DEPLOY_UNIFI_OS_RELOAD
|
||||
|
||||
_debug2 DEPLOY_UNIFI_KEYSTORE "$DEPLOY_UNIFI_KEYSTORE"
|
||||
_debug2 DEPLOY_UNIFI_KEYPASS "$DEPLOY_UNIFI_KEYPASS"
|
||||
_debug2 DEPLOY_UNIFI_CLOUDKEY_CERTDIR "$DEPLOY_UNIFI_CLOUDKEY_CERTDIR"
|
||||
_debug2 DEPLOY_UNIFI_CORE_CONFIG "$DEPLOY_UNIFI_CORE_CONFIG"
|
||||
_debug2 DEPLOY_UNIFI_RELOAD "$DEPLOY_UNIFI_RELOAD"
|
||||
_debug2 DEPLOY_UNIFI_OS_RELOAD "$DEPLOY_UNIFI_OS_RELOAD"
|
||||
_debug2 DEPLOY_UNIFI_SYSTEM_PROPERTIES "$DEPLOY_UNIFI_SYSTEM_PROPERTIES"
|
||||
|
||||
# Space-separated list of environments detected and installed:
|
||||
_services_updated=""
|
||||
@ -74,14 +89,16 @@ unifi_deploy() {
|
||||
_reload_cmd=""
|
||||
|
||||
# Unifi Controller environment (self hosted or any Cloud Key) --
|
||||
# auto-detect by file /usr/lib/unifi/data/keystore:
|
||||
# auto-detect by file /usr/lib/unifi/data/keystore
|
||||
_unifi_keystore="${DEPLOY_UNIFI_KEYSTORE:-/usr/lib/unifi/data/keystore}"
|
||||
if [ -f "$_unifi_keystore" ]; then
|
||||
_info "Installing certificate for Unifi Controller (Java keystore)"
|
||||
_debug _unifi_keystore "$_unifi_keystore"
|
||||
if ! _exists keytool; then
|
||||
_err "keytool not found"
|
||||
return 1
|
||||
_do_keytool=0
|
||||
_info "Installing certificate for Unifi Controller (PKCS12 keystore)."
|
||||
else
|
||||
_do_keytool=1
|
||||
_info "Installing certificate for Unifi Controller (Java keystore)"
|
||||
fi
|
||||
if [ ! -w "$_unifi_keystore" ]; then
|
||||
_err "The file $_unifi_keystore is not writable, please change the permission."
|
||||
@ -92,6 +109,7 @@ unifi_deploy() {
|
||||
|
||||
_debug "Generate import pkcs12"
|
||||
_import_pkcs12="$(_mktemp)"
|
||||
_debug "_toPkcs $_import_pkcs12 $_ckey $_ccert $_cca $_unifi_keypass unifi root"
|
||||
_toPkcs "$_import_pkcs12" "$_ckey" "$_ccert" "$_cca" "$_unifi_keypass" unifi root
|
||||
# shellcheck disable=SC2181
|
||||
if [ "$?" != "0" ]; then
|
||||
@ -99,22 +117,77 @@ unifi_deploy() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "Import into keystore: $_unifi_keystore"
|
||||
if keytool -importkeystore \
|
||||
-deststorepass "$_unifi_keypass" -destkeypass "$_unifi_keypass" -destkeystore "$_unifi_keystore" \
|
||||
-srckeystore "$_import_pkcs12" -srcstoretype PKCS12 -srcstorepass "$_unifi_keypass" \
|
||||
-alias unifi -noprompt; then
|
||||
_debug "Import keystore success!"
|
||||
rm "$_import_pkcs12"
|
||||
# Save the existing keystore in case something goes wrong.
|
||||
mv -f "${_unifi_keystore}" "${_unifi_keystore}"_original
|
||||
_info "Previous keystore saved to ${_unifi_keystore}_original."
|
||||
|
||||
if [ "$_do_keytool" -eq 1 ]; then
|
||||
_debug "Import into keystore: $_unifi_keystore"
|
||||
if keytool -importkeystore \
|
||||
-deststorepass "$_unifi_keypass" -destkeypass "$_unifi_keypass" -destkeystore "$_unifi_keystore" \
|
||||
-srckeystore "$_import_pkcs12" -srcstoretype PKCS12 -srcstorepass "$_unifi_keypass" \
|
||||
-alias unifi -noprompt; then
|
||||
_debug "Import keystore success!"
|
||||
else
|
||||
_err "Error importing into Unifi Java keystore."
|
||||
_err "Please re-run with --debug and report a bug."
|
||||
_info "Restoring original keystore."
|
||||
mv -f "${_unifi_keystore}"_original "${_unifi_keystore}"
|
||||
rm "$_import_pkcs12"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_err "Error importing into Unifi Java keystore."
|
||||
_err "Please re-run with --debug and report a bug."
|
||||
rm "$_import_pkcs12"
|
||||
return 1
|
||||
_debug "Copying new keystore to $_unifi_keystore"
|
||||
cp -f "$_import_pkcs12" "$_unifi_keystore"
|
||||
fi
|
||||
|
||||
if systemctl -q is-active unifi; then
|
||||
_reload_cmd="${_reload_cmd:+$_reload_cmd && }service unifi restart"
|
||||
# correct file ownership according to the directory, the keystore is placed in
|
||||
_unifi_keystore_dir=$(dirname "${_unifi_keystore}")
|
||||
_unifi_keystore_dir_owner=$(find "${_unifi_keystore_dir}" -maxdepth 0 -printf '%u\n')
|
||||
_unifi_keystore_owner=$(find "${_unifi_keystore}" -maxdepth 0 -printf '%u\n')
|
||||
if ! [ "${_unifi_keystore_owner}" = "${_unifi_keystore_dir_owner}" ]; then
|
||||
_debug "Changing keystore owner to ${_unifi_keystore_dir_owner}"
|
||||
chown "$_unifi_keystore_dir_owner" "${_unifi_keystore}" >/dev/null 2>&1 # fail quietly if we're not running as root
|
||||
fi
|
||||
|
||||
# Update unifi service for certificate cipher compatibility
|
||||
_unifi_system_properties="${DEPLOY_UNIFI_SYSTEM_PROPERTIES:-/usr/lib/unifi/data/system.properties}"
|
||||
if ${ACME_OPENSSL_BIN:-openssl} pkcs12 \
|
||||
-in "$_import_pkcs12" \
|
||||
-password pass:aircontrolenterprise \
|
||||
-nokeys | ${ACME_OPENSSL_BIN:-openssl} x509 -text \
|
||||
-noout | grep -i "signature" | grep -iq ecdsa >/dev/null 2>&1; then
|
||||
if [ -f "$(dirname "${DEPLOY_UNIFI_KEYSTORE}")/system.properties" ]; then
|
||||
_unifi_system_properties="$(dirname "${DEPLOY_UNIFI_KEYSTORE}")/system.properties"
|
||||
else
|
||||
_unifi_system_properties="/usr/lib/unifi/data/system.properties"
|
||||
fi
|
||||
if [ -f "${_unifi_system_properties}" ]; then
|
||||
cp -f "${_unifi_system_properties}" "${_unifi_system_properties}"_original
|
||||
_info "Updating system configuration for cipher compatibility."
|
||||
_info "Saved original system config to ${_unifi_system_properties}_original"
|
||||
sed -i '/unifi\.https\.ciphers/d' "${_unifi_system_properties}"
|
||||
echo "unifi.https.ciphers=ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES128-GCM-SHA256" >>"${_unifi_system_properties}"
|
||||
sed -i '/unifi\.https\.sslEnabledProtocols/d' "${_unifi_system_properties}"
|
||||
echo "unifi.https.sslEnabledProtocols=TLSv1.3,TLSv1.2" >>"${_unifi_system_properties}"
|
||||
_info "System configuration updated."
|
||||
fi
|
||||
fi
|
||||
|
||||
rm "$_import_pkcs12"
|
||||
|
||||
# Restarting unifi-core will bring up unifi, doing it out of order results in
|
||||
# a certificate error, and breaks wifiman.
|
||||
# Restart if we aren't doing Unifi OS (e.g. unifi-core service), otherwise stop for later restart.
|
||||
_unifi_reload="${DEPLOY_UNIFI_RELOAD:-systemctl restart unifi}"
|
||||
if [ ! -f "${DEPLOY_UNIFI_CORE_CONFIG:-/data/unifi-core/config}/unifi-core.key" ]; then
|
||||
_reload_cmd="${_reload_cmd:+$_reload_cmd && }$_unifi_reload"
|
||||
else
|
||||
_info "Stopping Unifi Controller for later restart."
|
||||
_unifi_stop=$(echo "${_unifi_reload}" | sed -e 's/restart/stop/')
|
||||
$_unifi_stop
|
||||
_reload_cmd="${_reload_cmd:+$_reload_cmd && }$_unifi_reload"
|
||||
_info "Unifi Controller stopped."
|
||||
fi
|
||||
_services_updated="${_services_updated} unifi"
|
||||
_info "Install Unifi Controller certificate success!"
|
||||
@ -134,13 +207,24 @@ unifi_deploy() {
|
||||
return 1
|
||||
fi
|
||||
# Cloud Key expects to load the keystore from /etc/ssl/private/unifi.keystore.jks.
|
||||
# Normally /usr/lib/unifi/data/keystore is a symlink there (so the keystore was
|
||||
# updated above), but if not, we don't know how to handle this installation:
|
||||
if ! cmp -s "$_unifi_keystore" "${_cloudkey_certdir}/unifi.keystore.jks"; then
|
||||
_err "Unsupported Cloud Key configuration: keystore not found at '${_cloudkey_certdir}/unifi.keystore.jks'"
|
||||
return 1
|
||||
# It appears that unifi won't start if this is a symlink, so we'll copy it instead.
|
||||
|
||||
# if ! cmp -s "$_unifi_keystore" "${_cloudkey_certdir}/unifi.keystore.jks"; then
|
||||
# _err "Unsupported Cloud Key configuration: keystore not found at '${_cloudkey_certdir}/unifi.keystore.jks'"
|
||||
# return 1
|
||||
# fi
|
||||
|
||||
_info "Updating ${_cloudkey_certdir}/unifi.keystore.jks"
|
||||
if [ -e "${_cloudkey_certdir}/unifi.keystore.jks" ]; then
|
||||
if [ -L "${_cloudkey_certdir}/unifi.keystore.jks" ]; then
|
||||
rm -f "${_cloudkey_certdir}/unifi.keystore.jks"
|
||||
else
|
||||
mv "${_cloudkey_certdir}/unifi.keystore.jks" "${_cloudkey_certdir}/unifi.keystore.jks_original"
|
||||
fi
|
||||
fi
|
||||
|
||||
cp "${_unifi_keystore}" "${_cloudkey_certdir}/unifi.keystore.jks"
|
||||
|
||||
cat "$_cfullchain" >"${_cloudkey_certdir}/cloudkey.crt"
|
||||
cat "$_ckey" >"${_cloudkey_certdir}/cloudkey.key"
|
||||
(cd "$_cloudkey_certdir" && tar -cf cert.tar cloudkey.crt cloudkey.key unifi.keystore.jks)
|
||||
@ -165,12 +249,17 @@ unifi_deploy() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Save the existing certs in case something goes wrong.
|
||||
cp -f "${_unifi_core_config}"/unifi-core.crt "${_unifi_core_config}"/unifi-core_original.crt
|
||||
cp -f "${_unifi_core_config}"/unifi-core.key "${_unifi_core_config}"/unifi-core_original.key
|
||||
_info "Previous certificate and key saved to ${_unifi_core_config}/unifi-core_original.crt.key."
|
||||
|
||||
cat "$_cfullchain" >"${_unifi_core_config}/unifi-core.crt"
|
||||
cat "$_ckey" >"${_unifi_core_config}/unifi-core.key"
|
||||
|
||||
if systemctl -q is-active unifi-core; then
|
||||
_reload_cmd="${_reload_cmd:+$_reload_cmd && }systemctl restart unifi-core"
|
||||
fi
|
||||
_unifi_os_reload="${DEPLOY_UNIFI_OS_RELOAD:-systemctl restart unifi-core}"
|
||||
_reload_cmd="${_reload_cmd:+$_reload_cmd && }$_unifi_os_reload"
|
||||
|
||||
_info "Install UnifiOS certificate success!"
|
||||
_services_updated="${_services_updated} unifi-core"
|
||||
elif [ "$DEPLOY_UNIFI_CORE_CONFIG" ]; then
|
||||
@ -209,6 +298,8 @@ unifi_deploy() {
|
||||
_savedeployconf DEPLOY_UNIFI_CLOUDKEY_CERTDIR "$DEPLOY_UNIFI_CLOUDKEY_CERTDIR"
|
||||
_savedeployconf DEPLOY_UNIFI_CORE_CONFIG "$DEPLOY_UNIFI_CORE_CONFIG"
|
||||
_savedeployconf DEPLOY_UNIFI_RELOAD "$DEPLOY_UNIFI_RELOAD"
|
||||
_savedeployconf DEPLOY_UNIFI_OS_RELOAD "$DEPLOY_UNIFI_OS_RELOAD"
|
||||
_savedeployconf DEPLOY_UNIFI_SYSTEM_PROPERTIES "$DEPLOY_UNIFI_SYSTEM_PROPERTIES"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
106
deploy/vault.sh
106
deploy/vault.sh
@ -70,20 +70,25 @@ vault_deploy() {
|
||||
|
||||
# JSON does not allow multiline strings.
|
||||
# So replacing new-lines with "\n" here
|
||||
_ckey=$(sed -z 's/\n/\\n/g' <"$2")
|
||||
_ccert=$(sed -z 's/\n/\\n/g' <"$3")
|
||||
_cca=$(sed -z 's/\n/\\n/g' <"$4")
|
||||
_cfullchain=$(sed -z 's/\n/\\n/g' <"$5")
|
||||
_ckey=$(sed -e ':a' -e N -e '$ ! ba' -e 's/\n/\\n/g' <"$2")
|
||||
_ccert=$(sed -e ':a' -e N -e '$ ! ba' -e 's/\n/\\n/g' <"$3")
|
||||
_cca=$(sed -e ':a' -e N -e '$ ! ba' -e 's/\n/\\n/g' <"$4")
|
||||
_cfullchain=$(sed -e ':a' -e N -e '$ ! ba' -e 's/\n/\\n/g' <"$5")
|
||||
|
||||
export _H1="X-Vault-Token: $VAULT_TOKEN"
|
||||
|
||||
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
|
||||
_response=$(_post "" "$URL")
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "Failed to renew the Vault token"
|
||||
return 1
|
||||
fi
|
||||
if echo "$_response" | grep -q '"errors":\['; then
|
||||
_err "Failed to renew the Vault token: $_response"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
URL="$VAULT_ADDR/v1/$VAULT_PREFIX/$_cdomain"
|
||||
@ -91,29 +96,85 @@ vault_deploy() {
|
||||
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" >/dev/null || return 1
|
||||
_response=$(_post "{ \"data\": {\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"} }" "$URL")
|
||||
if [ "$?" != "0" ]; then return 1; fi
|
||||
if echo "$_response" | grep -q '"errors":\['; then
|
||||
_err "Vault error: $_response"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_post "{\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"}" "$URL" >/dev/null || return 1
|
||||
_response=$(_post "{\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"}" "$URL")
|
||||
if [ "$?" != "0" ]; then return 1; fi
|
||||
if echo "$_response" | grep -q '"errors":\['; then
|
||||
_err "Vault error: $_response"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if [ -n "$VAULT_KV_V2" ]; then
|
||||
_info "Writing certificate to $URL/cert.pem"
|
||||
_post "{\"data\": {\"value\": \"$_ccert\"}}" "$URL/cert.pem" >/dev/null || return 1
|
||||
_response=$(_post "{\"data\": {\"value\": \"$_ccert\"}}" "$URL/cert.pem")
|
||||
if [ "$?" != "0" ]; then return 1; fi
|
||||
if echo "$_response" | grep -q '"errors":\['; then
|
||||
_err "Vault error writing cert.pem: $_response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Writing key to $URL/cert.key"
|
||||
_post "{\"data\": {\"value\": \"$_ckey\"}}" "$URL/cert.key" >/dev/null || return 1
|
||||
_response=$(_post "{\"data\": {\"value\": \"$_ckey\"}}" "$URL/cert.key")
|
||||
if [ "$?" != "0" ]; then return 1; fi
|
||||
if echo "$_response" | grep -q '"errors":\['; then
|
||||
_err "Vault error writing cert.key: $_response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Writing CA certificate to $URL/ca.pem"
|
||||
_post "{\"data\": {\"value\": \"$_cca\"}}" "$URL/ca.pem" >/dev/null || return 1
|
||||
_response=$(_post "{\"data\": {\"value\": \"$_cca\"}}" "$URL/ca.pem")
|
||||
if [ "$?" != "0" ]; then return 1; fi
|
||||
if echo "$_response" | grep -q '"errors":\['; then
|
||||
_err "Vault error writing ca.pem: $_response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Writing full-chain certificate to $URL/fullchain.pem"
|
||||
_post "{\"data\": {\"value\": \"$_cfullchain\"}}" "$URL/fullchain.pem" >/dev/null || return 1
|
||||
_response=$(_post "{\"data\": {\"value\": \"$_cfullchain\"}}" "$URL/fullchain.pem")
|
||||
if [ "$?" != "0" ]; then return 1; fi
|
||||
if echo "$_response" | grep -q '"errors":\['; then
|
||||
_err "Vault error writing fullchain.pem: $_response"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_info "Writing certificate to $URL/cert.pem"
|
||||
_post "{\"value\": \"$_ccert\"}" "$URL/cert.pem" >/dev/null || return 1
|
||||
_response=$(_post "{\"value\": \"$_ccert\"}" "$URL/cert.pem")
|
||||
if [ "$?" != "0" ]; then return 1; fi
|
||||
if echo "$_response" | grep -q '"errors":\['; then
|
||||
_err "Vault error writing cert.pem: $_response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Writing key to $URL/cert.key"
|
||||
_post "{\"value\": \"$_ckey\"}" "$URL/cert.key" >/dev/null || return 1
|
||||
_response=$(_post "{\"value\": \"$_ckey\"}" "$URL/cert.key")
|
||||
if [ "$?" != "0" ]; then return 1; fi
|
||||
if echo "$_response" | grep -q '"errors":\['; then
|
||||
_err "Vault error writing cert.key: $_response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Writing CA certificate to $URL/ca.pem"
|
||||
_post "{\"value\": \"$_cca\"}" "$URL/ca.pem" >/dev/null || return 1
|
||||
_response=$(_post "{\"value\": \"$_cca\"}" "$URL/ca.pem")
|
||||
if [ "$?" != "0" ]; then return 1; fi
|
||||
if echo "$_response" | grep -q '"errors":\['; then
|
||||
_err "Vault error writing ca.pem: $_response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Writing full-chain certificate to $URL/fullchain.pem"
|
||||
_post "{\"value\": \"$_cfullchain\"}" "$URL/fullchain.pem" >/dev/null || return 1
|
||||
_response=$(_post "{\"value\": \"$_cfullchain\"}" "$URL/fullchain.pem")
|
||||
if [ "$?" != "0" ]; then return 1; fi
|
||||
if echo "$_response" | grep -q '"errors":\['; then
|
||||
_err "Vault error writing fullchain.pem: $_response"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# To make it compatible with the wrong ca path `chain.pem` which was used in former versions
|
||||
@ -121,11 +182,20 @@ vault_deploy() {
|
||||
_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
|
||||
_response=$(_post "{\"data\": {\"value\": \"$_cca\"}}" "$URL/chain.pem")
|
||||
if [ "$?" != "0" ]; then return 1; fi
|
||||
if echo "$_response" | grep -q '"errors":\['; then
|
||||
_err "Vault error writing chain.pem: $_response"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_post "{\"value\": \"$_cca\"}" "$URL/chain.pem" >/dev/null || return 1
|
||||
_response=$(_post "{\"value\": \"$_cca\"}" "$URL/chain.pem")
|
||||
if [ "$?" != "0" ]; then return 1; fi
|
||||
if echo "$_response" | grep -q '"errors":\['; then
|
||||
_err "Vault error writing chain.pem: $_response"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
}
|
||||
|
@ -106,5 +106,5 @@ vsftpd_deploy() {
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
|
||||
}
|
||||
|
@ -1,46 +1,42 @@
|
||||
#!/usr/bin/env sh
|
||||
#This file name is "dns_1984hosting.sh"
|
||||
#So, here must be a method dns_1984hosting_add()
|
||||
#Which will be called by acme.sh to add the txt record to your api system.
|
||||
#returns 0 means success, otherwise error.
|
||||
# shellcheck disable=SC2034
|
||||
dns_1984hosting_info='1984.hosting
|
||||
Domains: 1984.is
|
||||
Site: 1984.hosting
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_1984hosting
|
||||
Options:
|
||||
One984HOSTING_Username Username
|
||||
One984HOSTING_Password Password
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2851
|
||||
Author: Adrian Fedoreanu
|
||||
'
|
||||
|
||||
#Author: Adrian Fedoreanu
|
||||
#Report Bugs here: https://github.com/acmesh-official/acme.sh
|
||||
# or here... https://github.com/acmesh-official/acme.sh/issues/2851
|
||||
#
|
||||
######## Public functions #####################
|
||||
######## Public functions #####################
|
||||
|
||||
# Export 1984HOSTING username and password in following variables
|
||||
#
|
||||
# One984HOSTING_Username=username
|
||||
# One984HOSTING_Password=password
|
||||
#
|
||||
# sessionid cookie is saved in ~/.acme.sh/account.conf
|
||||
# username/password need to be set only when changed.
|
||||
|
||||
#Usage: dns_1984hosting_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
# Usage: dns_1984hosting_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
# Add a text record.
|
||||
dns_1984hosting_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
_info "Add TXT record using 1984Hosting"
|
||||
_info "Add TXT record using 1984Hosting."
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
if ! _1984hosting_login; then
|
||||
_err "1984Hosting login failed for user $One984HOSTING_Username. Check $HTTP_HEADER file"
|
||||
_err "1984Hosting login failed for user $One984HOSTING_Username. Check $HTTP_HEADER file."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "First detect the root zone"
|
||||
_debug "First detect the root zone."
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain" "$fulldomain"
|
||||
_err "Invalid domain '$fulldomain'."
|
||||
return 1
|
||||
fi
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_debug "Add TXT record $fulldomain with value '$txtvalue'"
|
||||
_debug "Add TXT record $fulldomain with value '$txtvalue'."
|
||||
value="$(printf '%s' "$txtvalue" | _url_encode)"
|
||||
url="https://1984.hosting/domains/entry/"
|
||||
|
||||
@ -53,102 +49,108 @@ dns_1984hosting_add() {
|
||||
_debug2 postdata "$postdata"
|
||||
|
||||
_authpost "$postdata" "$url"
|
||||
response="$(echo "$_response" | _normalizeJson)"
|
||||
_debug2 response "$response"
|
||||
|
||||
if _contains "$response" '"haserrors": true'; then
|
||||
_err "1984Hosting failed to add TXT record for $_sub_domain bad RC from _post"
|
||||
if _contains "$_response" '"haserrors": true'; then
|
||||
_err "1984Hosting failed to add TXT record for $_sub_domain bad RC from _post."
|
||||
return 1
|
||||
elif _contains "$response" "html>"; then
|
||||
_err "1984Hosting failed to add TXT record for $_sub_domain. Check $HTTP_HEADER file"
|
||||
elif _contains "$_response" "html>"; then
|
||||
_err "1984Hosting failed to add TXT record for $_sub_domain. Check $HTTP_HEADER file."
|
||||
return 1
|
||||
elif _contains "$response" '"auth": false'; then
|
||||
_err "1984Hosting failed to add TXT record for $_sub_domain. Invalid or expired cookie"
|
||||
elif _contains "$_response" '"auth": false'; then
|
||||
_err "1984Hosting failed to add TXT record for $_sub_domain. Invalid or expired cookie."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Added acme challenge TXT record for $fulldomain at 1984Hosting"
|
||||
_info "Added acme challenge TXT record for $fulldomain at 1984Hosting."
|
||||
return 0
|
||||
}
|
||||
|
||||
#Usage: fulldomain txtvalue
|
||||
#Remove the txt record after validation.
|
||||
# Usage: fulldomain txtvalue
|
||||
# Remove the txt record after validation.
|
||||
dns_1984hosting_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
_info "Delete TXT record using 1984Hosting"
|
||||
_info "Delete TXT record using 1984Hosting."
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
if ! _1984hosting_login; then
|
||||
_err "1984Hosting login failed for user $One984HOSTING_Username. Check $HTTP_HEADER file"
|
||||
_err "1984Hosting login failed for user $One984HOSTING_Username. Check $HTTP_HEADER file."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "First detect the root zone"
|
||||
_debug "First detect the root zone."
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain" "$fulldomain"
|
||||
_err "Invalid domain '$fulldomain'."
|
||||
return 1
|
||||
fi
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
_debug "Delete $fulldomain TXT record"
|
||||
_debug "Delete $fulldomain TXT record."
|
||||
|
||||
url="https://1984.hosting/domains"
|
||||
if ! _get_zone_id "$url" "$_domain"; then
|
||||
_err "invalid zone" "$_domain"
|
||||
_err "Invalid zone '$_domain'."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_htmlget "$url/$_zone_id" "$txtvalue"
|
||||
_debug2 _response "$_response"
|
||||
entry_id="$(echo "$_response" | _egrep_o 'entry_[0-9]+' | sed 's/entry_//')"
|
||||
_debug2 entry_id "$entry_id"
|
||||
if [ -z "$entry_id" ]; then
|
||||
_err "Error getting TXT entry_id for $1"
|
||||
_err "Error getting TXT entry_id for $1."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_authpost "entry=$entry_id" "$url/delentry/"
|
||||
response="$(echo "$_response" | _normalizeJson)"
|
||||
_debug2 response "$response"
|
||||
|
||||
if ! _contains "$response" '"ok": true'; then
|
||||
_err "1984Hosting failed to delete TXT record for $entry_id bad RC from _post"
|
||||
if ! _contains "$_response" '"ok": true'; then
|
||||
_err "1984Hosting failed to delete TXT record for $entry_id bad RC from _post."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Deleted acme challenge TXT record for $fulldomain at 1984Hosting"
|
||||
_info "Deleted acme challenge TXT record for $fulldomain at 1984Hosting."
|
||||
return 0
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
# usage: _1984hosting_login username password
|
||||
# returns 0 success
|
||||
_1984hosting_login() {
|
||||
if ! _check_credentials; then return 1; fi
|
||||
|
||||
if _check_cookies; then
|
||||
_debug "Already logged in"
|
||||
_debug "Already logged in."
|
||||
return 0
|
||||
fi
|
||||
|
||||
_debug "Login to 1984Hosting as user $One984HOSTING_Username"
|
||||
_debug "Login to 1984Hosting as user $One984HOSTING_Username."
|
||||
username=$(printf '%s' "$One984HOSTING_Username" | _url_encode)
|
||||
password=$(printf '%s' "$One984HOSTING_Password" | _url_encode)
|
||||
url="https://1984.hosting/accounts/checkuserauth/"
|
||||
url="https://1984.hosting/api/auth/"
|
||||
|
||||
_get "https://1984.hosting/accounts/login/" | grep "csrfmiddlewaretoken"
|
||||
csrftoken="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _egrep_o 'csrftoken=[^;]*;' | tr -d ';')"
|
||||
sessionid="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _egrep_o 'cookie1984nammnamm=[^;]*;' | tr -d ';')"
|
||||
|
||||
if [ -z "$csrftoken" ] || [ -z "$sessionid" ]; then
|
||||
_err "One or more cookies are empty: '$csrftoken', '$sessionid'."
|
||||
return 1
|
||||
fi
|
||||
|
||||
export _H1="Cookie: $csrftoken; $sessionid"
|
||||
export _H2="Referer: https://1984.hosting/accounts/login/"
|
||||
csrf_header=$(echo "$csrftoken" | sed 's/csrftoken=//' | _head_n 1)
|
||||
export _H3="X-CSRFToken: $csrf_header"
|
||||
|
||||
response="$(_post "username=$username&password=$password&otpkey=" $url)"
|
||||
response="$(echo "$response" | _normalizeJson)"
|
||||
_debug2 response "$response"
|
||||
|
||||
if _contains "$response" '"loggedin": true'; then
|
||||
One984HOSTING_SESSIONID_COOKIE="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _egrep_o 'sessionid=[^;]*;' | tr -d ';')"
|
||||
One984HOSTING_SESSIONID_COOKIE="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _egrep_o 'cookie1984nammnamm=[^;]*;' | tr -d ';')"
|
||||
One984HOSTING_CSRFTOKEN_COOKIE="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _egrep_o 'csrftoken=[^;]*;' | tr -d ';')"
|
||||
export One984HOSTING_SESSIONID_COOKIE
|
||||
export One984HOSTING_CSRFTOKEN_COOKIE
|
||||
_saveaccountconf_mutable One984HOSTING_Username "$One984HOSTING_Username"
|
||||
_saveaccountconf_mutable One984HOSTING_Password "$One984HOSTING_Password"
|
||||
_saveaccountconf_mutable One984HOSTING_SESSIONID_COOKIE "$One984HOSTING_SESSIONID_COOKIE"
|
||||
_saveaccountconf_mutable One984HOSTING_CSRFTOKEN_COOKIE "$One984HOSTING_CSRFTOKEN_COOKIE"
|
||||
return 0
|
||||
@ -157,9 +159,13 @@ _1984hosting_login() {
|
||||
}
|
||||
|
||||
_check_credentials() {
|
||||
One984HOSTING_Username="${One984HOSTING_Username:-$(_readaccountconf_mutable One984HOSTING_Username)}"
|
||||
One984HOSTING_Password="${One984HOSTING_Password:-$(_readaccountconf_mutable One984HOSTING_Password)}"
|
||||
if [ -z "$One984HOSTING_Username" ] || [ -z "$One984HOSTING_Password" ]; then
|
||||
One984HOSTING_Username=""
|
||||
One984HOSTING_Password=""
|
||||
_clearaccountconf_mutable One984HOSTING_Username
|
||||
_clearaccountconf_mutable One984HOSTING_Password
|
||||
_err "You haven't specified 1984Hosting username or password yet."
|
||||
_err "Please export as One984HOSTING_Username / One984HOSTING_Password and try again."
|
||||
return 1
|
||||
@ -171,42 +177,43 @@ _check_cookies() {
|
||||
One984HOSTING_SESSIONID_COOKIE="${One984HOSTING_SESSIONID_COOKIE:-$(_readaccountconf_mutable One984HOSTING_SESSIONID_COOKIE)}"
|
||||
One984HOSTING_CSRFTOKEN_COOKIE="${One984HOSTING_CSRFTOKEN_COOKIE:-$(_readaccountconf_mutable One984HOSTING_CSRFTOKEN_COOKIE)}"
|
||||
if [ -z "$One984HOSTING_SESSIONID_COOKIE" ] || [ -z "$One984HOSTING_CSRFTOKEN_COOKIE" ]; then
|
||||
_debug "No cached cookie(s) found"
|
||||
_debug "No cached cookie(s) found."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_authget "https://1984.hosting/accounts/loginstatus/"
|
||||
if _contains "$response" '"ok": true'; then
|
||||
_debug "Cached cookies still valid"
|
||||
_authget "https://1984.hosting/api/auth/"
|
||||
if _contains "$_response" '"ok": true'; then
|
||||
_debug "Cached cookies still valid."
|
||||
return 0
|
||||
fi
|
||||
_debug "Cached cookies no longer valid"
|
||||
|
||||
_debug "Cached cookies no longer valid. Clearing cookies."
|
||||
One984HOSTING_SESSIONID_COOKIE=""
|
||||
One984HOSTING_CSRFTOKEN_COOKIE=""
|
||||
_saveaccountconf_mutable One984HOSTING_SESSIONID_COOKIE "$One984HOSTING_SESSIONID_COOKIE"
|
||||
_saveaccountconf_mutable One984HOSTING_CSRFTOKEN_COOKIE "$One984HOSTING_CSRFTOKEN_COOKIE"
|
||||
_clearaccountconf_mutable One984HOSTING_SESSIONID_COOKIE
|
||||
_clearaccountconf_mutable One984HOSTING_CSRFTOKEN_COOKIE
|
||||
return 1
|
||||
}
|
||||
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
# _acme-challenge.www.domain.com
|
||||
# Returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
_get_root() {
|
||||
domain="$1"
|
||||
i=1
|
||||
p=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
|
||||
# not valid
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
_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)
|
||||
_authget "https://1984.hosting/domains/zonestatus/$h/?cached=no"
|
||||
if _contains "$_response" '"ok": true'; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||
_domain="$h"
|
||||
return 0
|
||||
fi
|
||||
@ -216,46 +223,46 @@ _get_root() {
|
||||
return 1
|
||||
}
|
||||
|
||||
#usage: _get_zone_id url domain.com
|
||||
#returns zone id for domain.com
|
||||
# Usage: _get_zone_id url domain.com
|
||||
# Returns zone id for domain.com
|
||||
_get_zone_id() {
|
||||
url=$1
|
||||
domain=$2
|
||||
_htmlget "$url" "$domain"
|
||||
_debug2 _response "$_response"
|
||||
_zone_id="$(echo "$_response" | _egrep_o 'zone\/[0-9]+' | _head_n 1)"
|
||||
_debug2 _zone_id "$_zone_id"
|
||||
if [ -z "$_zone_id" ]; then
|
||||
_err "Error getting _zone_id for $2"
|
||||
_err "Error getting _zone_id for $2."
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# add extra headers to request
|
||||
# Add extra headers to request
|
||||
_authget() {
|
||||
export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE;$One984HOSTING_SESSIONID_COOKIE"
|
||||
export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE; $One984HOSTING_SESSIONID_COOKIE"
|
||||
_response=$(_get "$1" | _normalizeJson)
|
||||
_debug2 _response "$_response"
|
||||
}
|
||||
|
||||
# truncate huge HTML response
|
||||
# echo: Argument list too long
|
||||
# Truncate huge HTML response
|
||||
_htmlget() {
|
||||
export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE;$One984HOSTING_SESSIONID_COOKIE"
|
||||
export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE; $One984HOSTING_SESSIONID_COOKIE"
|
||||
_response=$(_get "$1" | grep "$2")
|
||||
if _contains "$_response" "@$2"; then
|
||||
_response=$(echo "$_response" | grep -v "[@]" | _head_n 1)
|
||||
fi
|
||||
_debug2 _response "$_response"
|
||||
}
|
||||
|
||||
# add extra headers to request
|
||||
# Add extra headers to request
|
||||
_authpost() {
|
||||
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 _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE; $One984HOSTING_SESSIONID_COOKIE"
|
||||
export _H2="Referer: https://1984.hosting/domains/$_zone_id"
|
||||
export _H3="X-CSRFToken: $csrf_header"
|
||||
_response=$(_post "$1" "$2")
|
||||
_response="$(_post "$1" "$2" | _normalizeJson)"
|
||||
_debug2 _response "$_response"
|
||||
}
|
||||
|
@ -1,18 +1,18 @@
|
||||
#!/usr/bin/env sh
|
||||
#
|
||||
#Author: Wolfgang Ebner
|
||||
#Author: Sven Neubuaer
|
||||
#Report Bugs here: https://github.com/dampfklon/acme.sh
|
||||
#
|
||||
# Usage:
|
||||
# export ACMEDNS_BASE_URL="https://auth.acme-dns.io"
|
||||
#
|
||||
# You can optionally define an already existing account:
|
||||
#
|
||||
# export ACMEDNS_USERNAME="<username>"
|
||||
# export ACMEDNS_PASSWORD="<password>"
|
||||
# export ACMEDNS_SUBDOMAIN="<subdomain>"
|
||||
#
|
||||
# shellcheck disable=SC2034
|
||||
dns_acmedns_info='acme-dns Server API
|
||||
The acme-dns is a limited DNS server with RESTful API to handle ACME DNS challenges.
|
||||
Site: github.com/joohoi/acme-dns
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_acmedns
|
||||
Options:
|
||||
ACMEDNS_USERNAME Username. Optional.
|
||||
ACMEDNS_PASSWORD Password. Optional.
|
||||
ACMEDNS_SUBDOMAIN Subdomain. Optional.
|
||||
ACMEDNS_BASE_URL API endpoint. Default: "https://auth.acme-dns.io".
|
||||
Issues: github.com/dampfklon/acme.sh
|
||||
Author: Wolfgang Ebner, Sven Neubuaer
|
||||
'
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: dns_acmedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
|
18
dnsapi/dns_acmeproxy.sh
Normal file → Executable file
18
dnsapi/dns_acmeproxy.sh
Normal file → Executable file
@ -1,9 +1,17 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
## 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
|
||||
# shellcheck disable=SC2034
|
||||
dns_acmeproxy_info='AcmeProxy Server API
|
||||
AcmeProxy can be used to as a single host in your network to request certificates through a DNS API.
|
||||
Clients can connect with the one AcmeProxy host so you do not need to store DNS API credentials on every single host.
|
||||
Site: github.com/mdbraber/acmeproxy
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_acmeproxy
|
||||
Options:
|
||||
ACMEPROXY_ENDPOINT API Endpoint
|
||||
ACMEPROXY_USERNAME Username
|
||||
ACMEPROXY_PASSWORD Password
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2251
|
||||
Author: Maarten den Braber
|
||||
'
|
||||
|
||||
dns_acmeproxy_add() {
|
||||
fulldomain="${1}"
|
||||
|
@ -1,10 +1,17 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_active24_info='Active24.cz
|
||||
Site: Active24.cz
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_active24
|
||||
Options:
|
||||
Active24_ApiKey API Key. Called "Identifier" in the Active24 Admin
|
||||
Active24_ApiSecret API Secret. Called "Secret key" in the Active24 Admin
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2059
|
||||
'
|
||||
|
||||
#ACTIVE24_Token="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
|
||||
ACTIVE24_Api="https://api.active24.com"
|
||||
|
||||
######## Public functions #####################
|
||||
Active24_Api="https://rest.active24.cz"
|
||||
# export Active24_ApiKey=ak48l3h7-ak5d-qn4t-p8gc-b6fs8c3l
|
||||
# export Active24_ApiSecret=ajvkeo3y82ndsu2smvxy3o36496dcascksldncsq
|
||||
|
||||
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
# Used to add txt record
|
||||
@ -15,8 +22,8 @@ dns_active24_add() {
|
||||
_active24_init
|
||||
|
||||
_info "Adding txt record"
|
||||
if _active24_rest POST "dns/$_domain/txt/v1" "{\"name\":\"$_sub_domain\",\"text\":\"$txtvalue\",\"ttl\":0}"; then
|
||||
if _contains "$response" "errors"; then
|
||||
if _active24_rest POST "/v2/service/$_service_id/dns/record" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":300}"; then
|
||||
if _contains "$response" "error"; then
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
else
|
||||
@ -24,6 +31,7 @@ dns_active24_add() {
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
}
|
||||
@ -37,19 +45,25 @@ dns_active24_rm() {
|
||||
_active24_init
|
||||
|
||||
_debug "Getting txt records"
|
||||
_active24_rest GET "dns/$_domain/records/v1"
|
||||
# The API needs to send data in body in order the filter to work
|
||||
# TODO: web can also add content $txtvalue to filter and then get the id from response
|
||||
_active24_rest GET "/v2/service/$_service_id/dns/record" "{\"page\":1,\"descending\":true,\"sortBy\":\"name\",\"rowsPerPage\":100,\"totalRecords\":0,\"filters\":{\"type\":[\"TXT\"],\"name\":\"${_sub_domain}\"}}"
|
||||
#_active24_rest GET "/v2/service/$_service_id/dns/record?rowsPerPage=100"
|
||||
|
||||
if _contains "$response" "errors"; then
|
||||
if _contains "$response" "error"; then
|
||||
_err "Error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
hash_ids=$(echo "$response" | _egrep_o "[^{]+${txtvalue}[^}]+" | _egrep_o "hashId\":\"[^\"]+" | cut -c10-)
|
||||
# Note: it might never be more than one record actually, NEEDS more INVESTIGATION
|
||||
record_ids=$(printf "%s" "$response" | _egrep_o "[^{]+${txtvalue}[^}]+" | _egrep_o '"id" *: *[^,]+' | cut -d ':' -f 2)
|
||||
_debug2 record_ids "$record_ids"
|
||||
|
||||
for hash_id in $hash_ids; do
|
||||
_debug "Removing hash_id" "$hash_id"
|
||||
if _active24_rest DELETE "dns/$_domain/$hash_id/v1" ""; then
|
||||
if _contains "$response" "errors"; then
|
||||
for redord_id in $record_ids; do
|
||||
_debug "Removing record_id" "$redord_id"
|
||||
_debug "txtvalue" "$txtvalue"
|
||||
if _active24_rest DELETE "/v2/service/$_service_id/dns/record/$redord_id" ""; then
|
||||
if _contains "$response" "error"; then
|
||||
_err "Unable to remove txt record."
|
||||
return 1
|
||||
else
|
||||
@ -63,23 +77,17 @@ dns_active24_rm() {
|
||||
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
|
||||
|
||||
if ! _active24_rest GET "dns/domains/v1"; then
|
||||
if ! _active24_rest GET "/v1/user/self/service"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
i=2
|
||||
p=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
_debug "h" "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
@ -87,7 +95,7 @@ _get_root() {
|
||||
fi
|
||||
|
||||
if _contains "$response" "\"$h\"" >/dev/null; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
@ -97,21 +105,98 @@ _get_root() {
|
||||
return 1
|
||||
}
|
||||
|
||||
_active24_rest() {
|
||||
m=$1
|
||||
ep="$2"
|
||||
data="$3"
|
||||
_debug "$ep"
|
||||
_active24_init() {
|
||||
Active24_ApiKey="${Active24_ApiKey:-$(_readaccountconf_mutable Active24_ApiKey)}"
|
||||
Active24_ApiSecret="${Active24_ApiSecret:-$(_readaccountconf_mutable Active24_ApiSecret)}"
|
||||
#Active24_ServiceId="${Active24_ServiceId:-$(_readaccountconf_mutable Active24_ServiceId)}"
|
||||
|
||||
export _H1="Authorization: Bearer $ACTIVE24_Token"
|
||||
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug "data" "$data"
|
||||
response="$(_post "$data" "$ACTIVE24_Api/$ep" "" "$m" "application/json")"
|
||||
else
|
||||
response="$(_get "$ACTIVE24_Api/$ep")"
|
||||
if [ -z "$Active24_ApiKey" ] || [ -z "$Active24_ApiSecret" ]; then
|
||||
Active24_ApiKey=""
|
||||
Active24_ApiSecret=""
|
||||
_err "You don't specify Active24 api key and ApiSecret yet."
|
||||
_err "Please create your key and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the credentials to the account conf file.
|
||||
_saveaccountconf_mutable Active24_ApiKey "$Active24_ApiKey"
|
||||
_saveaccountconf_mutable Active24_ApiSecret "$Active24_ApiSecret"
|
||||
|
||||
_debug "A24 API CHECK"
|
||||
if ! _active24_rest GET "/v2/check"; then
|
||||
_err "A24 API check failed with: $response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! echo "$response" | tr -d " " | grep \"verified\":true >/dev/null; then
|
||||
_err "A24 API check failed with: $response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
_active24_get_service_id "$_domain"
|
||||
_debug _service_id "$_service_id"
|
||||
}
|
||||
|
||||
_active24_get_service_id() {
|
||||
_d=$1
|
||||
if ! _active24_rest GET "/v1/user/self/zone/${_d}"; then
|
||||
return 1
|
||||
else
|
||||
response=$(echo "$response" | _json_decode)
|
||||
_service_id=$(echo "$response" | _egrep_o '"id" *: *[^,]+' | cut -d ':' -f 2)
|
||||
fi
|
||||
}
|
||||
|
||||
_active24_rest() {
|
||||
m=$1
|
||||
ep_qs=$2 # with query string
|
||||
# ep=$2
|
||||
ep=$(printf "%s" "$ep_qs" | cut -d '?' -f1) # no query string
|
||||
data="$3"
|
||||
|
||||
_debug "A24 $ep"
|
||||
_debug "A24 $Active24_ApiKey"
|
||||
_debug "A24 $Active24_ApiSecret"
|
||||
|
||||
timestamp=$(_time)
|
||||
datez=$(date -u +"%Y%m%dT%H%M%SZ")
|
||||
canonicalRequest="${m} ${ep} ${timestamp}"
|
||||
signature=$(printf "%s" "$canonicalRequest" | _hmac sha1 "$(printf "%s" "$Active24_ApiSecret" | _hex_dump | tr -d " ")" hex)
|
||||
authorization64="$(printf "%s:%s" "$Active24_ApiKey" "$signature" | _base64)"
|
||||
|
||||
export _H1="Date: ${datez}"
|
||||
export _H2="Accept: application/json"
|
||||
export _H3="Content-Type: application/json"
|
||||
export _H4="Authorization: Basic ${authorization64}"
|
||||
|
||||
_debug2 H1 "$_H1"
|
||||
_debug2 H2 "$_H2"
|
||||
_debug2 H3 "$_H3"
|
||||
_debug2 H4 "$_H4"
|
||||
|
||||
# _sleep 1
|
||||
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug2 "${m} $Active24_Api${ep_qs}"
|
||||
_debug "data" "$data"
|
||||
response="$(_post "$data" "$Active24_Api${ep_qs}" "" "$m" "application/json")"
|
||||
else
|
||||
if [ -z "$data" ]; then
|
||||
_debug2 "GET $Active24_Api${ep_qs}"
|
||||
response="$(_get "$Active24_Api${ep_qs}")"
|
||||
else
|
||||
_debug2 "GET $Active24_Api${ep_qs} with data: ${data}"
|
||||
response="$(_post "$data" "$Active24_Api${ep_qs}" "" "$m" "application/json")"
|
||||
fi
|
||||
fi
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
@ -119,23 +204,3 @@ _active24_rest() {
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
|
||||
_active24_init() {
|
||||
ACTIVE24_Token="${ACTIVE24_Token:-$(_readaccountconf_mutable ACTIVE24_Token)}"
|
||||
if [ -z "$ACTIVE24_Token" ]; then
|
||||
ACTIVE24_Token=""
|
||||
_err "You didn't specify a Active24 api token yet."
|
||||
_err "Please create the token and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf_mutable ACTIVE24_Token "$ACTIVE24_Token"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
}
|
||||
|
@ -1,12 +1,13 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
#AD_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
|
||||
#This is the Alwaysdata api wrapper for acme.sh
|
||||
#
|
||||
#Author: Paul Koppen
|
||||
#Report Bugs here: https://github.com/wpk-/acme.sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_ad_info='AlwaysData.com
|
||||
Site: AlwaysData.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_ad
|
||||
Options:
|
||||
AD_API_KEY API Key
|
||||
Issues: github.com/acmesh-official/acme.sh/pull/503
|
||||
Author: Paul Koppen
|
||||
'
|
||||
|
||||
AD_API_URL="https://$AD_API_KEY:@api.alwaysdata.com/v1"
|
||||
|
||||
@ -94,7 +95,7 @@ _get_root() {
|
||||
if _ad_rest GET "domain/"; then
|
||||
response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')"
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
@ -105,7 +106,7 @@ _get_root() {
|
||||
if [ "$hostedzone" ]; then
|
||||
_domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ )
|
||||
if [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
|
@ -1,27 +1,27 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_ali_info='AlibabaCloud.com
|
||||
Domains: Aliyun.com
|
||||
Site: AlibabaCloud.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_ali
|
||||
Options:
|
||||
Ali_Key API Key
|
||||
Ali_Secret API Secret
|
||||
'
|
||||
|
||||
Ali_API="https://alidns.aliyuncs.com/"
|
||||
# NOTICE:
|
||||
# This file is referenced by Alibaba Cloud Services deploy hooks
|
||||
# https://github.com/acmesh-official/acme.sh/pull/5205#issuecomment-2357867276
|
||||
# Be careful when modifying this file, especially when making breaking changes for common functions
|
||||
|
||||
#Ali_Key="LTqIA87hOKdjevsf5"
|
||||
#Ali_Secret="0p5EYueFNq501xnCPzKNbx6K51qPH2"
|
||||
Ali_DNS_API="https://alidns.aliyuncs.com/"
|
||||
|
||||
#Usage: dns_ali_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_ali_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
Ali_Key="${Ali_Key:-$(_readaccountconf_mutable Ali_Key)}"
|
||||
Ali_Secret="${Ali_Secret:-$(_readaccountconf_mutable Ali_Secret)}"
|
||||
if [ -z "$Ali_Key" ] || [ -z "$Ali_Secret" ]; then
|
||||
Ali_Key=""
|
||||
Ali_Secret=""
|
||||
_err "You don't specify aliyun api key and secret yet."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the api key and secret to the account conf file.
|
||||
_saveaccountconf_mutable Ali_Key "$Ali_Key"
|
||||
_saveaccountconf_mutable Ali_Secret "$Ali_Secret"
|
||||
_prepare_ali_credentials || return 1
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
@ -46,14 +46,74 @@ dns_ali_rm() {
|
||||
_clean
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#################### Alibaba Cloud common functions below ####################
|
||||
|
||||
_prepare_ali_credentials() {
|
||||
Ali_Key="${Ali_Key:-$(_readaccountconf_mutable Ali_Key)}"
|
||||
Ali_Secret="${Ali_Secret:-$(_readaccountconf_mutable Ali_Secret)}"
|
||||
if [ -z "$Ali_Key" ] || [ -z "$Ali_Secret" ]; then
|
||||
Ali_Key=""
|
||||
Ali_Secret=""
|
||||
_err "You don't specify aliyun api key and secret yet."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the api key and secret to the account conf file.
|
||||
_saveaccountconf_mutable Ali_Key "$Ali_Key"
|
||||
_saveaccountconf_mutable Ali_Secret "$Ali_Secret"
|
||||
}
|
||||
|
||||
# act ign mtd
|
||||
_ali_rest() {
|
||||
act="$1"
|
||||
ign="$2"
|
||||
mtd="${3:-GET}"
|
||||
|
||||
signature=$(printf "%s" "$mtd&%2F&$(printf "%s" "$query" | _url_encode upper-hex)" | _hmac "sha1" "$(printf "%s" "$Ali_Secret&" | _hex_dump | tr -d " ")" | _base64)
|
||||
signature=$(printf "%s" "$signature" | _url_encode upper-hex)
|
||||
url="$endpoint?Signature=$signature"
|
||||
|
||||
if [ "$mtd" = "GET" ]; then
|
||||
url="$url&$query"
|
||||
response="$(_get "$url")"
|
||||
else
|
||||
response="$(_post "$query" "$url" "" "$mtd" "application/x-www-form-urlencoded")"
|
||||
fi
|
||||
|
||||
_ret="$?"
|
||||
_debug2 response "$response"
|
||||
if [ "$_ret" != "0" ]; then
|
||||
_err "Error <$act>"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$ign" ]; then
|
||||
message="$(echo "$response" | _egrep_o "\"Message\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")"
|
||||
if [ "$message" ]; then
|
||||
_err "$message"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
_ali_nonce() {
|
||||
#_head_n 1 </dev/urandom | _digest "sha256" hex | cut -c 1-31
|
||||
#Not so good...
|
||||
date +"%s%N" | sed 's/%N//g'
|
||||
}
|
||||
|
||||
_timestamp() {
|
||||
date -u +"%Y-%m-%dT%H%%3A%M%%3A%SZ"
|
||||
}
|
||||
|
||||
#################### Private functions below ####################
|
||||
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=2
|
||||
i=1
|
||||
p=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
@ -65,7 +125,7 @@ _get_root() {
|
||||
fi
|
||||
|
||||
if _contains "$response" "PageNumber"; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_domain="$h"
|
||||
_debug _domain "$_domain"
|
||||
@ -77,52 +137,10 @@ _get_root() {
|
||||
return 1
|
||||
}
|
||||
|
||||
_ali_rest() {
|
||||
signature=$(printf "%s" "GET&%2F&$(_ali_urlencode "$query")" | _hmac "sha1" "$(printf "%s" "$Ali_Secret&" | _hex_dump | tr -d " ")" | _base64)
|
||||
signature=$(_ali_urlencode "$signature")
|
||||
url="$Ali_API?$query&Signature=$signature"
|
||||
|
||||
if ! response="$(_get "$url")"; then
|
||||
_err "Error <$1>"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 response "$response"
|
||||
if [ -z "$2" ]; then
|
||||
message="$(echo "$response" | _egrep_o "\"Message\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")"
|
||||
if [ "$message" ]; then
|
||||
_err "$message"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
_ali_urlencode() {
|
||||
_str="$1"
|
||||
_str_len=${#_str}
|
||||
_u_i=1
|
||||
while [ "$_u_i" -le "$_str_len" ]; do
|
||||
_str_c="$(printf "%s" "$_str" | cut -c "$_u_i")"
|
||||
case $_str_c in [a-zA-Z0-9.~_-])
|
||||
printf "%s" "$_str_c"
|
||||
;;
|
||||
*)
|
||||
printf "%%%02X" "'$_str_c"
|
||||
;;
|
||||
esac
|
||||
_u_i="$(_math "$_u_i" + 1)"
|
||||
done
|
||||
}
|
||||
|
||||
_ali_nonce() {
|
||||
#_head_n 1 </dev/urandom | _digest "sha256" hex | cut -c 1-31
|
||||
#Not so good...
|
||||
date +"%s%N"
|
||||
}
|
||||
|
||||
_check_exist_query() {
|
||||
_qdomain="$1"
|
||||
_qsubdomain="$2"
|
||||
endpoint=$Ali_DNS_API
|
||||
query=''
|
||||
query=$query'AccessKeyId='$Ali_Key
|
||||
query=$query'&Action=DescribeDomainRecords'
|
||||
@ -138,6 +156,7 @@ _check_exist_query() {
|
||||
}
|
||||
|
||||
_add_record_query() {
|
||||
endpoint=$Ali_DNS_API
|
||||
query=''
|
||||
query=$query'AccessKeyId='$Ali_Key
|
||||
query=$query'&Action=AddDomainRecord'
|
||||
@ -154,6 +173,7 @@ _add_record_query() {
|
||||
}
|
||||
|
||||
_delete_record_query() {
|
||||
endpoint=$Ali_DNS_API
|
||||
query=''
|
||||
query=$query'AccessKeyId='$Ali_Key
|
||||
query=$query'&Action=DeleteDomainRecord'
|
||||
@ -167,6 +187,7 @@ _delete_record_query() {
|
||||
}
|
||||
|
||||
_describe_records_query() {
|
||||
endpoint=$Ali_DNS_API
|
||||
query=''
|
||||
query=$query'AccessKeyId='$Ali_Key
|
||||
query=$query'&Action=DescribeDomainRecords'
|
||||
@ -197,7 +218,3 @@ _clean() {
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
_timestamp() {
|
||||
date -u +"%Y-%m-%dT%H%%3A%M%%3A%SZ"
|
||||
}
|
||||
|
185
dnsapi/dns_alviy.sh
Normal file
185
dnsapi/dns_alviy.sh
Normal file
@ -0,0 +1,185 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_alviy_info='Alviy.com
|
||||
Site: Alviy.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_alviy
|
||||
Options:
|
||||
Alviy_token API token. Get it from the https://cloud.alviy.com/token
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/5115
|
||||
'
|
||||
|
||||
Alviy_Api="https://cloud.alviy.com/api/v1"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: dns_alviy_add _acme-challenge.www.domain.com "content"
|
||||
dns_alviy_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
Alviy_token="${Alviy_token:-$(_readaccountconf_mutable Alviy_token)}"
|
||||
if [ -z "$Alviy_token" ]; then
|
||||
Alviy_token=""
|
||||
_err "Please specify Alviy token."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the api key and email to the account conf file.
|
||||
_saveaccountconf_mutable Alviy_token "$Alviy_token"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_debug "Getting existing records"
|
||||
if _alviy_txt_exists "$_domain" "$fulldomain" "$txtvalue"; then
|
||||
_info "This record already exists, skipping"
|
||||
return 0
|
||||
fi
|
||||
|
||||
_add_data="{\"content\":\"$txtvalue\",\"type\":\"TXT\"}"
|
||||
_debug2 _add_data "$_add_data"
|
||||
_info "Adding record"
|
||||
if _alviy_rest POST "zone/$_domain/domain/$fulldomain/" "$_add_data"; then
|
||||
_debug "Checking updated records of '${fulldomain}'"
|
||||
|
||||
if ! _alviy_txt_exists "$_domain" "$fulldomain" "$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
|
||||
|
||||
_sleep 10
|
||||
_info "Added TXT record '${txtvalue}' for '${fulldomain}'."
|
||||
return 0
|
||||
}
|
||||
|
||||
#fulldomain
|
||||
dns_alviy_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
Alviy_token="${Alviy_token:-$(_readaccountconf_mutable Alviy_token)}"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
if ! _alviy_txt_exists "$_domain" "$fulldomain" "$txtvalue"; then
|
||||
_info "The record does not exist, skip"
|
||||
return 0
|
||||
fi
|
||||
|
||||
_add_data=""
|
||||
uuid=$(echo "$response" | tr "{" "\n" | grep "$txtvalue" | tr "," "\n" | grep uuid | cut -d \" -f4)
|
||||
# delete record
|
||||
_debug "Delete TXT record for '${fulldomain}'"
|
||||
if ! _alviy_rest DELETE "zone/$_domain/record/$uuid" "{\"confirm\":1}"; then
|
||||
_err "Cannot delete empty TXT record for '$fulldomain'"
|
||||
return 1
|
||||
fi
|
||||
_info "The record '$fulldomain'='$txtvalue' deleted"
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=3
|
||||
a="init"
|
||||
while [ -n "$a" ]; do
|
||||
a=$(printf "%s" "$domain" | cut -d . -f $i-)
|
||||
i=$((i + 1))
|
||||
done
|
||||
n=$((i - 3))
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $n-)
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
_alviy_rest GET "zone/$domain/"
|
||||
_debug "can't get host from $domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _alviy_rest GET "zone/$h/"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" '"code":"NOT_FOUND"'; then
|
||||
_debug "$h not found"
|
||||
else
|
||||
s=$((n - 1))
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f -$s)
|
||||
_domain="$h"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
_alviy_txt_exists() {
|
||||
zone=$1
|
||||
domain=$2
|
||||
content_data=$3
|
||||
_debug "Getting existing records"
|
||||
|
||||
if ! _alviy_rest GET "zone/$zone/domain/$domain/TXT/"; then
|
||||
_info "The record does not exist"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _contains "$response" "$3"; then
|
||||
_info "The record has other value"
|
||||
return 1
|
||||
fi
|
||||
# GOOD code return - TRUE function
|
||||
return 0
|
||||
}
|
||||
|
||||
_alviy_rest() {
|
||||
method=$1
|
||||
path="$2"
|
||||
content_data="$3"
|
||||
_debug "$path"
|
||||
|
||||
export _H1="Authorization: Bearer $Alviy_token"
|
||||
export _H2="Content-Type: application/json"
|
||||
|
||||
if [ "$content_data" ] || [ "$method" = "DELETE" ]; then
|
||||
_debug "data ($method): " "$content_data"
|
||||
response="$(_post "$content_data" "$Alviy_Api/$path" "" "$method")"
|
||||
else
|
||||
response="$(_get "$Alviy_Api/$path")"
|
||||
fi
|
||||
_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")"
|
||||
if [ "$_code" = "401" ]; then
|
||||
_err "It seems that your api key or secret is not correct."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$_code" != "200" ]; then
|
||||
_err "API call error ($method): $path Response code $_code"
|
||||
fi
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error on rest call ($method): $path. Response:"
|
||||
_err "$response"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
@ -1,9 +1,12 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Anexia CloudDNS acme.sh hook
|
||||
# Author: MA
|
||||
|
||||
#ANX_Token="xxxx"
|
||||
# shellcheck disable=SC2034
|
||||
dns_anx_info='Anexia.com CloudDNS
|
||||
Site: Anexia.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_anx
|
||||
Options:
|
||||
ANX_Token API Token
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/3238
|
||||
'
|
||||
|
||||
ANX_API='https://engine.anexia-it.com/api/clouddns/v1'
|
||||
|
||||
@ -127,18 +130,17 @@ _get_root() {
|
||||
i=1
|
||||
p=1
|
||||
|
||||
_anx_rest GET "zone.json"
|
||||
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
_anx_rest GET "zone.json/${h}"
|
||||
if _contains "$response" "\"name\":\"$h\""; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
|
177
dnsapi/dns_artfiles.sh
Normal file
177
dnsapi/dns_artfiles.sh
Normal file
@ -0,0 +1,177 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_artfiles_info='ArtFiles.de
|
||||
Site: ArtFiles.de
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_artfiles
|
||||
Options:
|
||||
AF_API_USERNAME API Username
|
||||
AF_API_PASSWORD API Password
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/4718
|
||||
Author: Martin Arndt <https://troublezone.net/>
|
||||
'
|
||||
|
||||
########## API configuration ###################################################
|
||||
|
||||
AF_API_SUCCESS='status":"OK'
|
||||
AF_URL_DCP='https://dcp.c.artfiles.de/api/'
|
||||
AF_URL_DNS=${AF_URL_DCP}'dns/{*}_dns.html?domain='
|
||||
AF_URL_DOMAINS=${AF_URL_DCP}'domain/get_domains.html'
|
||||
|
||||
########## Public functions ####################################################
|
||||
|
||||
# Adds a new TXT record for given ACME challenge value & domain.
|
||||
# Usage: dns_artfiles_add _acme-challenge.www.example.com "ACME challenge value"
|
||||
dns_artfiles_add() {
|
||||
domain="$1"
|
||||
txtValue="$2"
|
||||
_info 'Using ArtFiles.de DNS addition API…'
|
||||
_debug 'Domain' "$domain"
|
||||
_debug 'txtValue' "$txtValue"
|
||||
|
||||
_set_credentials
|
||||
_saveaccountconf_mutable 'AF_API_USERNAME' "$AF_API_USERNAME"
|
||||
_saveaccountconf_mutable 'AF_API_PASSWORD' "$AF_API_PASSWORD"
|
||||
|
||||
_set_headers
|
||||
_get_zone "$domain"
|
||||
_dns 'GET'
|
||||
if ! _contains "$response" 'TXT'; then
|
||||
_err 'Retrieving TXT records failed.'
|
||||
|
||||
return 1
|
||||
fi
|
||||
|
||||
_clean_records
|
||||
_dns 'SET' "$(printf -- '%s\n_acme-challenge "%s"' "$response" "$txtValue")"
|
||||
if ! _contains "$response" "$AF_API_SUCCESS"; then
|
||||
_err 'Adding ACME challenge value failed.'
|
||||
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Removes the existing TXT record for given ACME challenge value & domain.
|
||||
# Usage: dns_artfiles_rm _acme-challenge.www.example.com "ACME challenge value"
|
||||
dns_artfiles_rm() {
|
||||
domain="$1"
|
||||
txtValue="$2"
|
||||
_info 'Using ArtFiles.de DNS removal API…'
|
||||
_debug 'Domain' "$domain"
|
||||
_debug 'txtValue' "$txtValue"
|
||||
|
||||
_set_credentials
|
||||
_set_headers
|
||||
_get_zone "$domain"
|
||||
if ! _dns 'GET'; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _contains "$response" "$txtValue"; then
|
||||
_err 'Retrieved TXT records are missing given ACME challenge value.'
|
||||
|
||||
return 1
|
||||
fi
|
||||
|
||||
_clean_records
|
||||
response="$(printf -- '%s' "$response" | sed '/_acme-challenge "'"$txtValue"'"/d')"
|
||||
_dns 'SET' "$response"
|
||||
if ! _contains "$response" "$AF_API_SUCCESS"; then
|
||||
_err 'Removing ACME challenge value failed.'
|
||||
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
########## Private functions ###################################################
|
||||
|
||||
# Cleans awful TXT records response of ArtFiles's API & pretty prints it.
|
||||
# Usage: _clean_records
|
||||
_clean_records() {
|
||||
_info 'Cleaning TXT records…'
|
||||
# Extract TXT part, strip trailing quote sign (ACME.sh API guidelines forbid
|
||||
# usage of SED's GNU extensions, hence couldn't omit it via regex), strip '\'
|
||||
# from '\"' & turn '\n' into real LF characters.
|
||||
# Yup, awful API to use - but that's all we got to get this working, so… ;)
|
||||
_debug2 'Raw ' "$response"
|
||||
response="$(printf -- '%s' "$response" | sed 's/^.*TXT":"\([^}]*\).*$/\1/;s/,".*$//;s/.$//;s/\\"/"/g;s/\\n/\n/g')"
|
||||
_debug2 'Clean' "$response"
|
||||
}
|
||||
|
||||
# Executes an HTTP GET or POST request for getting or setting DNS records,
|
||||
# containing given payload upon POST.
|
||||
# Usage: _dns [GET | SET] [payload]
|
||||
_dns() {
|
||||
_info 'Executing HTTP request…'
|
||||
action="$1"
|
||||
payload="$(printf -- '%s' "$2" | _url_encode)"
|
||||
url="$(printf -- '%s%s' "$AF_URL_DNS" "$domain" | sed 's/{\*}/'"$(printf -- '%s' "$action" | _lower_case)"'/')"
|
||||
|
||||
if [ "$action" = 'SET' ]; then
|
||||
_debug2 'Payload' "$payload"
|
||||
response="$(_post '' "$url&TXT=$payload" '' 'POST' 'application/x-www-form-urlencoded')"
|
||||
else
|
||||
response="$(_get "$url" '' 10)"
|
||||
fi
|
||||
|
||||
if ! _contains "$response" "$AF_API_SUCCESS"; then
|
||||
_err "DNS API error: $response"
|
||||
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug 'Response' "$response"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Gets the root domain zone for given domain.
|
||||
# Usage: _get_zone _acme-challenge.www.example.com
|
||||
_get_zone() {
|
||||
fqdn="$1"
|
||||
domains="$(_get "$AF_URL_DOMAINS" '' 10)"
|
||||
_info 'Getting domain zone…'
|
||||
_debug2 'FQDN' "$fqdn"
|
||||
_debug2 'Domains' "$domains"
|
||||
|
||||
while _contains "$fqdn" "."; do
|
||||
if _contains "$domains" "$fqdn"; then
|
||||
domain="$fqdn"
|
||||
_info "Found root domain zone: $domain"
|
||||
break
|
||||
else
|
||||
fqdn="${fqdn#*.}"
|
||||
_debug2 'FQDN' "$fqdn"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$domain" = "$fqdn" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
_err 'Couldn'\''t find root domain zone.'
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Sets the credentials for accessing ArtFiles's API
|
||||
# Usage: _set_credentials
|
||||
_set_credentials() {
|
||||
_info 'Setting credentials…'
|
||||
AF_API_USERNAME="${AF_API_USERNAME:-$(_readaccountconf_mutable AF_API_USERNAME)}"
|
||||
AF_API_PASSWORD="${AF_API_PASSWORD:-$(_readaccountconf_mutable AF_API_PASSWORD)}"
|
||||
if [ -z "$AF_API_USERNAME" ] || [ -z "$AF_API_PASSWORD" ]; then
|
||||
_err 'Missing ArtFiles.de username and/or password.'
|
||||
_err 'Please ensure both are set via export command & try again.'
|
||||
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Adds the HTTP Authorization & Content-Type headers to a follow-up request.
|
||||
# Usage: _set_headers
|
||||
_set_headers() {
|
||||
_info 'Setting headers…'
|
||||
encoded="$(printf -- '%s:%s' "$AF_API_USERNAME" "$AF_API_PASSWORD" | _base64)"
|
||||
export _H1="Authorization: Basic $encoded"
|
||||
export _H2='Content-Type: application/json'
|
||||
}
|
@ -1,11 +1,16 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Arvan_Token="Apikey xxxx"
|
||||
# shellcheck disable=SC2034
|
||||
dns_arvan_info='ArvanCloud.ir
|
||||
Site: ArvanCloud.ir
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_arvan
|
||||
Options:
|
||||
Arvan_Token API Token
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2796
|
||||
Author: Vahid Fardi
|
||||
'
|
||||
|
||||
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 #####################
|
||||
|
||||
#Usage: dns_arvan_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
@ -102,7 +107,7 @@ _get_root() {
|
||||
i=2
|
||||
p=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
@ -115,7 +120,7 @@ _get_root() {
|
||||
if _contains "$response" "\"domain\":\"$h\""; then
|
||||
_domain_id=$(echo "$response" | cut -d : -f 3 | cut -d , -f 1 | tr -d \")
|
||||
if [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
|
@ -1,9 +1,15 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
#AURORA_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
#
|
||||
#AURORA_Secret="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
# shellcheck disable=SC2034
|
||||
dns_aurora_info='versio.nl AuroraDNS
|
||||
Domains: pcextreme.nl
|
||||
Site: versio.nl
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_aurora
|
||||
Options:
|
||||
AURORA_Key API Key
|
||||
AURORA_Secret API Secret
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/3459
|
||||
Author: Jasper Zonneveld
|
||||
'
|
||||
|
||||
AURORA_Api="https://api.auroradns.eu"
|
||||
|
||||
@ -111,7 +117,7 @@ _get_root() {
|
||||
p=1
|
||||
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
@ -126,7 +132,7 @@ _get_root() {
|
||||
_domain_id=$(echo "$response" | _normalizeJson | tr -d "{}" | tr "," "\n" | grep "\"id\": *\"" | cut -d : -f 2 | tr -d \" | _head_n 1 | tr -d " ")
|
||||
_debug _domain_id "$_domain_id"
|
||||
if [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
|
@ -1,16 +1,15 @@
|
||||
#!/usr/bin/env sh
|
||||
# -*- mode: sh; tab-width: 2; indent-tabs-mode: s; coding: utf-8 -*-
|
||||
|
||||
# This is the InternetX autoDNS xml api wrapper for acme.sh
|
||||
# Author: auerswald@gmail.com
|
||||
# Created: 2018-01-14
|
||||
#
|
||||
# export AUTODNS_USER="username"
|
||||
# export AUTODNS_PASSWORD="password"
|
||||
# export AUTODNS_CONTEXT="context"
|
||||
#
|
||||
# Usage:
|
||||
# acme.sh --issue --dns dns_autodns -d example.com
|
||||
# shellcheck disable=SC2034
|
||||
dns_autodns_info='InternetX autoDNS
|
||||
InternetX autoDNS XML API
|
||||
Site: InternetX.com/autodns/
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_autodns
|
||||
Options:
|
||||
AUTODNS_USER Username
|
||||
AUTODNS_PASSWORD Password
|
||||
AUTODNS_CONTEXT Context
|
||||
Author: <auerswald@gmail.com>
|
||||
'
|
||||
|
||||
AUTODNS_API="https://gateway.autodns.com"
|
||||
|
||||
@ -111,7 +110,7 @@ _get_autodns_zone() {
|
||||
p=1
|
||||
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
_debug h "$h"
|
||||
|
||||
if [ -z "$h" ]; then
|
||||
@ -129,7 +128,7 @@ _get_autodns_zone() {
|
||||
if _contains "$autodns_response" "<summary>1</summary>" >/dev/null; then
|
||||
_zone="$(echo "$autodns_response" | _egrep_o '<name>[^<]*</name>' | cut -d '>' -f 2 | cut -d '<' -f 1)"
|
||||
_system_ns="$(echo "$autodns_response" | _egrep_o '<system_ns>[^<]*</system_ns>' | cut -d '>' -f 2 | cut -d '<' -f 1)"
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||
return 0
|
||||
fi
|
||||
|
||||
|
@ -1,13 +1,15 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_aws_info='Amazon AWS Route53 domain API
|
||||
Site: docs.aws.amazon.com/route53/
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_aws
|
||||
Options:
|
||||
AWS_ACCESS_KEY_ID API Key ID
|
||||
AWS_SECRET_ACCESS_KEY API Secret
|
||||
'
|
||||
|
||||
#
|
||||
#AWS_ACCESS_KEY_ID="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
#
|
||||
#AWS_SECRET_ACCESS_KEY="xxxxxxx"
|
||||
|
||||
#This is the Amazon Route53 api wrapper for acme.sh
|
||||
#All `_sleep` commands are included to avoid Route53 throttling, see
|
||||
#https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/DNSLimitations.html#limits-api-requests
|
||||
# All `_sleep` commands are included to avoid Route53 throttling, see
|
||||
# https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/DNSLimitations.html#limits-api-requests
|
||||
|
||||
AWS_HOST="route53.amazonaws.com"
|
||||
AWS_URL="https://$AWS_HOST"
|
||||
@ -145,7 +147,6 @@ dns_aws_rm() {
|
||||
fi
|
||||
_sleep 1
|
||||
return 1
|
||||
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
@ -157,7 +158,7 @@ _get_root() {
|
||||
|
||||
# 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)
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100 | sed 's/\./\\./g')
|
||||
_debug "Checking domain: $h"
|
||||
if [ -z "$h" ]; then
|
||||
_error "invalid domain"
|
||||
@ -173,7 +174,7 @@ _get_root() {
|
||||
if [ "$hostedzone" ]; then
|
||||
_domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "<Id>.*<.Id>" | head -n 1 | _egrep_o ">.*<" | tr -d "<>")
|
||||
if [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
@ -207,24 +208,40 @@ _use_container_role() {
|
||||
}
|
||||
|
||||
_use_instance_role() {
|
||||
_url="http://169.254.169.254/latest/meta-data/iam/security-credentials/"
|
||||
_debug "_url" "$_url"
|
||||
if ! _get "$_url" true 1 | _head_n 1 | grep -Fq 200; then
|
||||
_instance_role_name_url="http://169.254.169.254/latest/meta-data/iam/security-credentials/"
|
||||
|
||||
if _get "$_instance_role_name_url" true 1 | _head_n 1 | grep -Fq 401; then
|
||||
_debug "Using IMDSv2"
|
||||
_token_url="http://169.254.169.254/latest/api/token"
|
||||
export _H1="X-aws-ec2-metadata-token-ttl-seconds: 21600"
|
||||
_token="$(_post "" "$_token_url" "" "PUT")"
|
||||
_secure_debug3 "_token" "$_token"
|
||||
if [ -z "$_token" ]; then
|
||||
_debug "Unable to fetch IMDSv2 token from instance metadata"
|
||||
return 1
|
||||
fi
|
||||
export _H1="X-aws-ec2-metadata-token: $_token"
|
||||
fi
|
||||
|
||||
if ! _get "$_instance_role_name_url" true 1 | _head_n 1 | grep -Fq 200; then
|
||||
_debug "Unable to fetch IAM role from instance metadata"
|
||||
return 1
|
||||
fi
|
||||
_aws_role=$(_get "$_url" "" 1)
|
||||
_debug "_aws_role" "$_aws_role"
|
||||
_use_metadata "$_url$_aws_role"
|
||||
|
||||
_instance_role_name=$(_get "$_instance_role_name_url" "" 1)
|
||||
_debug "_instance_role_name" "$_instance_role_name"
|
||||
_use_metadata "$_instance_role_name_url$_instance_role_name" "$_token"
|
||||
|
||||
}
|
||||
|
||||
_use_metadata() {
|
||||
export _H1="X-aws-ec2-metadata-token: $2"
|
||||
_aws_creds="$(
|
||||
_get "$1" "" 1 |
|
||||
_normalizeJson |
|
||||
tr '{,}' '\n' |
|
||||
while read -r _line; do
|
||||
_key="$(echo "${_line%%:*}" | tr -d '"')"
|
||||
_key="$(echo "${_line%%:*}" | tr -d '\"')"
|
||||
_value="${_line#*:}"
|
||||
_debug3 "_key" "$_key"
|
||||
_secure_debug3 "_value" "$_value"
|
||||
|
@ -1,9 +1,13 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
#AZION_Email=""
|
||||
#AZION_Password=""
|
||||
#
|
||||
# shellcheck disable=SC2034
|
||||
dns_azion_info='Azion.om
|
||||
Site: Azion.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_azion
|
||||
Options:
|
||||
AZION_Email Email
|
||||
AZION_Password Password
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/3555
|
||||
'
|
||||
|
||||
AZION_Api="https://api.azionapi.net"
|
||||
|
||||
@ -96,7 +100,7 @@ _get_root() {
|
||||
fi
|
||||
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
# not valid
|
||||
@ -107,7 +111,7 @@ _get_root() {
|
||||
_domain_id=$(echo "$response" | tr '{' "\n" | grep "\"domain\":\"$h\"" | _egrep_o "\"id\":[0-9]*" | _head_n 1 | 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)
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
|
@ -1,13 +1,25 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_azure_info='Azure
|
||||
Site: Azure.microsoft.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_azure
|
||||
Options:
|
||||
AZUREDNS_SUBSCRIPTIONID Subscription ID
|
||||
AZUREDNS_TENANTID Tenant ID
|
||||
AZUREDNS_APPID App ID. App ID of the service principal
|
||||
AZUREDNS_CLIENTSECRET Client Secret. Secret from creating the service principal
|
||||
AZUREDNS_MANAGEDIDENTITY Use Managed Identity. Use Managed Identity assigned to a resource instead of a service principal. "true"/"false"
|
||||
AZUREDNS_BEARERTOKEN Bearer Token. Used instead of service principal credentials or managed identity. Optional.
|
||||
'
|
||||
|
||||
WIKI="https://github.com/acmesh-official/acme.sh/wiki/How-to-use-Azure-DNS"
|
||||
wiki=https://github.com/acmesh-official/acme.sh/wiki/How-to-use-Azure-DNS
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
# Used to add txt record
|
||||
#
|
||||
# Ref: https://docs.microsoft.com/en-us/rest/api/dns/recordsets/createorupdate
|
||||
# Ref: https://learn.microsoft.com/en-us/rest/api/dns/record-sets/create-or-update?view=rest-dns-2018-05-01&tabs=HTTP
|
||||
#
|
||||
|
||||
dns_azure_add() {
|
||||
@ -20,6 +32,7 @@ dns_azure_add() {
|
||||
AZUREDNS_TENANTID=""
|
||||
AZUREDNS_APPID=""
|
||||
AZUREDNS_CLIENTSECRET=""
|
||||
AZUREDNS_BEARERTOKEN=""
|
||||
_err "You didn't specify the Azure Subscription ID"
|
||||
return 1
|
||||
fi
|
||||
@ -34,37 +47,45 @@ dns_azure_add() {
|
||||
_saveaccountconf_mutable AZUREDNS_TENANTID ""
|
||||
_saveaccountconf_mutable AZUREDNS_APPID ""
|
||||
_saveaccountconf_mutable AZUREDNS_CLIENTSECRET ""
|
||||
_saveaccountconf_mutable AZUREDNS_BEARERTOKEN ""
|
||||
else
|
||||
_info "You didn't ask to use Azure managed identity, checking service principal credentials"
|
||||
_info "You didn't ask to use Azure managed identity, checking service principal credentials or provided bearer token"
|
||||
AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}"
|
||||
AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}"
|
||||
AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}"
|
||||
AZUREDNS_BEARERTOKEN="${AZUREDNS_BEARERTOKEN:-$(_readaccountconf_mutable AZUREDNS_BEARERTOKEN)}"
|
||||
if [ -z "$AZUREDNS_BEARERTOKEN" ]; then
|
||||
if [ -z "$AZUREDNS_TENANTID" ]; then
|
||||
AZUREDNS_SUBSCRIPTIONID=""
|
||||
AZUREDNS_TENANTID=""
|
||||
AZUREDNS_APPID=""
|
||||
AZUREDNS_CLIENTSECRET=""
|
||||
AZUREDNS_BEARERTOKEN=""
|
||||
_err "You didn't specify the Azure Tenant ID "
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$AZUREDNS_TENANTID" ]; then
|
||||
AZUREDNS_SUBSCRIPTIONID=""
|
||||
AZUREDNS_TENANTID=""
|
||||
AZUREDNS_APPID=""
|
||||
AZUREDNS_CLIENTSECRET=""
|
||||
_err "You didn't specify the Azure Tenant ID "
|
||||
return 1
|
||||
fi
|
||||
if [ -z "$AZUREDNS_APPID" ]; then
|
||||
AZUREDNS_SUBSCRIPTIONID=""
|
||||
AZUREDNS_TENANTID=""
|
||||
AZUREDNS_APPID=""
|
||||
AZUREDNS_CLIENTSECRET=""
|
||||
AZUREDNS_BEARERTOKEN=""
|
||||
_err "You didn't specify the Azure App ID"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$AZUREDNS_APPID" ]; then
|
||||
AZUREDNS_SUBSCRIPTIONID=""
|
||||
AZUREDNS_TENANTID=""
|
||||
AZUREDNS_APPID=""
|
||||
AZUREDNS_CLIENTSECRET=""
|
||||
_err "You didn't specify the Azure App ID"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$AZUREDNS_CLIENTSECRET" ]; then
|
||||
AZUREDNS_SUBSCRIPTIONID=""
|
||||
AZUREDNS_TENANTID=""
|
||||
AZUREDNS_APPID=""
|
||||
AZUREDNS_CLIENTSECRET=""
|
||||
_err "You didn't specify the Azure Client Secret"
|
||||
return 1
|
||||
if [ -z "$AZUREDNS_CLIENTSECRET" ]; then
|
||||
AZUREDNS_SUBSCRIPTIONID=""
|
||||
AZUREDNS_TENANTID=""
|
||||
AZUREDNS_APPID=""
|
||||
AZUREDNS_CLIENTSECRET=""
|
||||
AZUREDNS_BEARERTOKEN=""
|
||||
_err "You didn't specify the Azure Client Secret"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_info "Using provided bearer token"
|
||||
fi
|
||||
|
||||
#save account details to account conf file, don't opt in for azure manages identity check.
|
||||
@ -72,9 +93,14 @@ dns_azure_add() {
|
||||
_saveaccountconf_mutable AZUREDNS_TENANTID "$AZUREDNS_TENANTID"
|
||||
_saveaccountconf_mutable AZUREDNS_APPID "$AZUREDNS_APPID"
|
||||
_saveaccountconf_mutable AZUREDNS_CLIENTSECRET "$AZUREDNS_CLIENTSECRET"
|
||||
_saveaccountconf_mutable AZUREDNS_BEARERTOKEN "$AZUREDNS_BEARERTOKEN"
|
||||
fi
|
||||
|
||||
accesstoken=$(_azure_getaccess_token "$AZUREDNS_MANAGEDIDENTITY" "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
|
||||
if [ -z "$AZUREDNS_BEARERTOKEN" ]; then
|
||||
accesstoken=$(_azure_getaccess_token "$AZUREDNS_MANAGEDIDENTITY" "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
|
||||
else
|
||||
accesstoken=$(echo "$AZUREDNS_BEARERTOKEN" | sed "s/Bearer //g")
|
||||
fi
|
||||
|
||||
if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then
|
||||
_err "invalid domain"
|
||||
@ -124,7 +150,7 @@ dns_azure_add() {
|
||||
# Usage: fulldomain txtvalue
|
||||
# Used to remove the txt record after validation
|
||||
#
|
||||
# Ref: https://docs.microsoft.com/en-us/rest/api/dns/recordsets/delete
|
||||
# Ref: https://learn.microsoft.com/en-us/rest/api/dns/record-sets/delete?view=rest-dns-2018-05-01&tabs=HTTP
|
||||
#
|
||||
dns_azure_rm() {
|
||||
fulldomain=$1
|
||||
@ -136,6 +162,7 @@ dns_azure_rm() {
|
||||
AZUREDNS_TENANTID=""
|
||||
AZUREDNS_APPID=""
|
||||
AZUREDNS_CLIENTSECRET=""
|
||||
AZUREDNS_BEARERTOKEN=""
|
||||
_err "You didn't specify the Azure Subscription ID "
|
||||
return 1
|
||||
fi
|
||||
@ -144,40 +171,51 @@ dns_azure_rm() {
|
||||
if [ "$AZUREDNS_MANAGEDIDENTITY" = true ]; then
|
||||
_info "Using Azure managed identity"
|
||||
else
|
||||
_info "You didn't ask to use Azure managed identity, checking service principal credentials"
|
||||
_info "You didn't ask to use Azure managed identity, checking service principal credentials or provided bearer token"
|
||||
AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}"
|
||||
AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}"
|
||||
AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}"
|
||||
AZUREDNS_BEARERTOKEN="${AZUREDNS_BEARERTOKEN:-$(_readaccountconf_mutable AZUREDNS_BEARERTOKEN)}"
|
||||
if [ -z "$AZUREDNS_BEARERTOKEN" ]; then
|
||||
if [ -z "$AZUREDNS_TENANTID" ]; then
|
||||
AZUREDNS_SUBSCRIPTIONID=""
|
||||
AZUREDNS_TENANTID=""
|
||||
AZUREDNS_APPID=""
|
||||
AZUREDNS_CLIENTSECRET=""
|
||||
AZUREDNS_BEARERTOKEN=""
|
||||
_err "You didn't specify the Azure Tenant ID "
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$AZUREDNS_TENANTID" ]; then
|
||||
AZUREDNS_SUBSCRIPTIONID=""
|
||||
AZUREDNS_TENANTID=""
|
||||
AZUREDNS_APPID=""
|
||||
AZUREDNS_CLIENTSECRET=""
|
||||
_err "You didn't specify the Azure Tenant ID "
|
||||
return 1
|
||||
fi
|
||||
if [ -z "$AZUREDNS_APPID" ]; then
|
||||
AZUREDNS_SUBSCRIPTIONID=""
|
||||
AZUREDNS_TENANTID=""
|
||||
AZUREDNS_APPID=""
|
||||
AZUREDNS_CLIENTSECRET=""
|
||||
AZUREDNS_BEARERTOKEN=""
|
||||
_err "You didn't specify the Azure App ID"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$AZUREDNS_APPID" ]; then
|
||||
AZUREDNS_SUBSCRIPTIONID=""
|
||||
AZUREDNS_TENANTID=""
|
||||
AZUREDNS_APPID=""
|
||||
AZUREDNS_CLIENTSECRET=""
|
||||
_err "You didn't specify the Azure App ID"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$AZUREDNS_CLIENTSECRET" ]; then
|
||||
AZUREDNS_SUBSCRIPTIONID=""
|
||||
AZUREDNS_TENANTID=""
|
||||
AZUREDNS_APPID=""
|
||||
AZUREDNS_CLIENTSECRET=""
|
||||
_err "You didn't specify the Azure Client Secret"
|
||||
return 1
|
||||
if [ -z "$AZUREDNS_CLIENTSECRET" ]; then
|
||||
AZUREDNS_SUBSCRIPTIONID=""
|
||||
AZUREDNS_TENANTID=""
|
||||
AZUREDNS_APPID=""
|
||||
AZUREDNS_CLIENTSECRET=""
|
||||
AZUREDNS_BEARERTOKEN=""
|
||||
_err "You didn't specify the Azure Client Secret"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_info "Using provided bearer token"
|
||||
fi
|
||||
fi
|
||||
|
||||
accesstoken=$(_azure_getaccess_token "$AZUREDNS_MANAGEDIDENTITY" "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
|
||||
if [ -z "$AZUREDNS_BEARERTOKEN" ]; then
|
||||
accesstoken=$(_azure_getaccess_token "$AZUREDNS_MANAGEDIDENTITY" "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
|
||||
else
|
||||
accesstoken=$(echo "$AZUREDNS_BEARERTOKEN" | sed "s/Bearer //g")
|
||||
fi
|
||||
|
||||
if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then
|
||||
_err "invalid domain"
|
||||
@ -256,10 +294,10 @@ _azure_rest() {
|
||||
if [ "$_code" = "401" ]; then
|
||||
# we have an invalid access token set to expired
|
||||
_saveaccountconf_mutable AZUREDNS_TOKENVALIDTO "0"
|
||||
_err "access denied make sure your Azure settings are correct. See $WIKI"
|
||||
_err "Access denied. Invalid access token. Make sure your Azure settings are correct. See: $wiki"
|
||||
return 1
|
||||
fi
|
||||
# See https://docs.microsoft.com/en-us/azure/architecture/best-practices/retry-service-specific#general-rest-and-retry-guidelines for retryable HTTP codes
|
||||
# See https://learn.microsoft.com/en-us/azure/architecture/best-practices/retry-service-specific#general-rest-and-retry-guidelines for retryable HTTP codes
|
||||
if [ "$_ret" != "0" ] || [ -z "$_code" ] || [ "$_code" = "408" ] || [ "$_code" = "500" ] || [ "$_code" = "503" ] || [ "$_code" = "504" ]; then
|
||||
_request_retry_times="$(_math "$_request_retry_times" + 1)"
|
||||
_info "REST call error $_code retrying $ep in $_request_retry_times s"
|
||||
@ -277,14 +315,14 @@ _azure_rest() {
|
||||
return 0
|
||||
}
|
||||
|
||||
## Ref: https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-service-to-service#request-an-access-token
|
||||
## Ref: https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-client-creds-grant-flow#request-an-access-token
|
||||
_azure_getaccess_token() {
|
||||
managedIdentity=$1
|
||||
tenantID=$2
|
||||
clientID=$3
|
||||
clientSecret=$4
|
||||
|
||||
accesstoken="${AZUREDNS_BEARERTOKEN:-$(_readaccountconf_mutable AZUREDNS_BEARERTOKEN)}"
|
||||
accesstoken="${AZUREDNS_ACCESSTOKEN:-$(_readaccountconf_mutable AZUREDNS_ACCESSTOKEN)}"
|
||||
expires_on="${AZUREDNS_TOKENVALIDTO:-$(_readaccountconf_mutable AZUREDNS_TOKENVALIDTO)}"
|
||||
|
||||
# can we reuse the bearer token?
|
||||
@ -301,9 +339,18 @@ _azure_getaccess_token() {
|
||||
_debug "getting new bearer token"
|
||||
|
||||
if [ "$managedIdentity" = true ]; then
|
||||
# https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/how-to-use-vm-token#get-a-token-using-http
|
||||
export _H1="Metadata: true"
|
||||
response="$(_get http://169.254.169.254/metadata/identity/oauth2/token\?api-version=2018-02-01\&resource=https://management.azure.com/)"
|
||||
# https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/how-to-use-vm-token#get-a-token-using-http
|
||||
if [ -n "$IDENTITY_ENDPOINT" ]; then
|
||||
# Some Azure environments may set IDENTITY_ENDPOINT (formerly MSI_ENDPOINT) to have an alternative metadata endpoint
|
||||
url="$IDENTITY_ENDPOINT?api-version=2019-08-01&resource=https://management.azure.com/"
|
||||
headers="X-IDENTITY-HEADER: $IDENTITY_HEADER"
|
||||
else
|
||||
url="http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/"
|
||||
headers="Metadata: true"
|
||||
fi
|
||||
|
||||
export _H1="$headers"
|
||||
response="$(_get "$url")"
|
||||
response="$(echo "$response" | _normalizeJson)"
|
||||
accesstoken=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||
expires_on=$(echo "$response" | _egrep_o "\"expires_on\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||
@ -321,14 +368,14 @@ _azure_getaccess_token() {
|
||||
fi
|
||||
|
||||
if [ -z "$accesstoken" ]; then
|
||||
_err "no acccess token received. Check your Azure settings see $WIKI"
|
||||
_err "No acccess token received. Check your Azure settings. See: $wiki"
|
||||
return 1
|
||||
fi
|
||||
if [ "$_ret" != "0" ]; then
|
||||
_err "error $response"
|
||||
return 1
|
||||
fi
|
||||
_saveaccountconf_mutable AZUREDNS_BEARERTOKEN "$accesstoken"
|
||||
_saveaccountconf_mutable AZUREDNS_ACCESSTOKEN "$accesstoken"
|
||||
_saveaccountconf_mutable AZUREDNS_TOKENVALIDTO "$expires_on"
|
||||
printf "%s" "$accesstoken"
|
||||
return 0
|
||||
@ -341,15 +388,18 @@ _get_root() {
|
||||
i=1
|
||||
p=1
|
||||
|
||||
## Ref: https://docs.microsoft.com/en-us/rest/api/dns/zones/list
|
||||
## returns up to 100 zones in one response therefore handling more results is not not implemented
|
||||
## (ZoneListResult with continuation token for the next page of results)
|
||||
## Per https://docs.microsoft.com/en-us/azure/azure-subscription-service-limits#dns-limits you are limited to 100 Zone/subscriptions anyways
|
||||
## Ref: https://learn.microsoft.com/en-us/rest/api/dns/zones/list?view=rest-dns-2018-05-01&tabs=HTTP
|
||||
## returns up to 100 zones in one response. Handling more results is not implemented
|
||||
## (ZoneListResult with continuation token for the next page of results)
|
||||
##
|
||||
## TODO: handle more than 100 results, as per:
|
||||
## https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/azure-subscription-service-limits#azure-dns-limits
|
||||
## The new limit is 250 Public DNS zones per subscription, while the old limit was only 100
|
||||
##
|
||||
_azure_rest GET "https://management.azure.com/subscriptions/$subscriptionId/providers/Microsoft.Network/dnszones?\$top=500&api-version=2017-09-01" "" "$accesstoken"
|
||||
# Find matching domain name in Json response
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
_debug2 "Checking domain: $h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
@ -364,7 +414,7 @@ _get_root() {
|
||||
#create the record at the domain apex (@) if only the domain name was provided as --domain-alias
|
||||
_sub_domain="@"
|
||||
else
|
||||
_sub_domain=$(echo "$domain" | cut -d . -f 1-$p)
|
||||
_sub_domain=$(echo "$domain" | cut -d . -f 1-"$p")
|
||||
fi
|
||||
_domain=$h
|
||||
return 0
|
||||
|
281
dnsapi/dns_beget.sh
Executable file
281
dnsapi/dns_beget.sh
Executable file
@ -0,0 +1,281 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_beget_info='Beget.com
|
||||
Site: Beget.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_beget
|
||||
Options:
|
||||
BEGET_User API user
|
||||
BEGET_Password API password
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/6200
|
||||
Author: ARNik arnik@arnik.ru
|
||||
'
|
||||
|
||||
Beget_Api="https://api.beget.com/api"
|
||||
|
||||
#################### Public functions ####################
|
||||
|
||||
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
# Used to add txt record
|
||||
dns_beget_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_debug "dns_beget_add() $fulldomain $txtvalue"
|
||||
fulldomain=$(echo "$fulldomain" | _lower_case)
|
||||
|
||||
Beget_Username="${Beget_Username:-$(_readaccountconf_mutable Beget_Username)}"
|
||||
Beget_Password="${Beget_Password:-$(_readaccountconf_mutable Beget_Password)}"
|
||||
|
||||
if [ -z "$Beget_Username" ] || [ -z "$Beget_Password" ]; then
|
||||
Beget_Username=""
|
||||
Beget_Password=""
|
||||
_err "You must export variables: Beget_Username, and Beget_Password"
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the credentials to the account conf file.
|
||||
_saveaccountconf_mutable Beget_Username "$Beget_Username"
|
||||
_saveaccountconf_mutable Beget_Password "$Beget_Password"
|
||||
|
||||
_info "Prepare subdomain."
|
||||
if ! _prepare_subdomain "$fulldomain"; then
|
||||
_err "Can't prepare subdomain."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Get domain records"
|
||||
data="{\"fqdn\":\"$fulldomain\"}"
|
||||
res=$(_api_call "$Beget_Api/dns/getData" "$data")
|
||||
if ! _is_api_reply_ok "$res"; then
|
||||
_err "Can't get domain records."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Add new TXT record"
|
||||
data="{\"fqdn\":\"$fulldomain\",\"records\":{"
|
||||
data=${data}$(_parce_records "$res" "A")
|
||||
data=${data}$(_parce_records "$res" "AAAA")
|
||||
data=${data}$(_parce_records "$res" "CAA")
|
||||
data=${data}$(_parce_records "$res" "MX")
|
||||
data=${data}$(_parce_records "$res" "SRV")
|
||||
data=${data}$(_parce_records "$res" "TXT")
|
||||
data=$(echo "$data" | sed 's/,$//')
|
||||
data=${data}'}}'
|
||||
|
||||
str=$(_txt_to_dns_json "$txtvalue")
|
||||
data=$(_add_record "$data" "TXT" "$str")
|
||||
|
||||
res=$(_api_call "$Beget_Api/dns/changeRecords" "$data")
|
||||
if ! _is_api_reply_ok "$res"; then
|
||||
_err "Can't change domain records."
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Usage: fulldomain txtvalue
|
||||
# Used to remove the txt record after validation
|
||||
dns_beget_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_debug "dns_beget_rm() $fulldomain $txtvalue"
|
||||
fulldomain=$(echo "$fulldomain" | _lower_case)
|
||||
|
||||
Beget_Username="${Beget_Username:-$(_readaccountconf_mutable Beget_Username)}"
|
||||
Beget_Password="${Beget_Password:-$(_readaccountconf_mutable Beget_Password)}"
|
||||
|
||||
_info "Get current domain records"
|
||||
data="{\"fqdn\":\"$fulldomain\"}"
|
||||
res=$(_api_call "$Beget_Api/dns/getData" "$data")
|
||||
if ! _is_api_reply_ok "$res"; then
|
||||
_err "Can't get domain records."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Remove TXT record"
|
||||
data="{\"fqdn\":\"$fulldomain\",\"records\":{"
|
||||
data=${data}$(_parce_records "$res" "A")
|
||||
data=${data}$(_parce_records "$res" "AAAA")
|
||||
data=${data}$(_parce_records "$res" "CAA")
|
||||
data=${data}$(_parce_records "$res" "MX")
|
||||
data=${data}$(_parce_records "$res" "SRV")
|
||||
data=${data}$(_parce_records "$res" "TXT")
|
||||
data=$(echo "$data" | sed 's/,$//')
|
||||
data=${data}'}}'
|
||||
|
||||
str=$(_txt_to_dns_json "$txtvalue")
|
||||
data=$(_rm_record "$data" "$str")
|
||||
|
||||
res=$(_api_call "$Beget_Api/dns/changeRecords" "$data")
|
||||
if ! _is_api_reply_ok "$res"; then
|
||||
_err "Can't change domain records."
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#################### Private functions below ####################
|
||||
|
||||
# Create subdomain if needed
|
||||
# Usage: _prepare_subdomain [fulldomain]
|
||||
_prepare_subdomain() {
|
||||
fulldomain=$1
|
||||
|
||||
_info "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"
|
||||
|
||||
if [ -z "$_sub_domain" ]; then
|
||||
_debug "$fulldomain is a root domain."
|
||||
return 0
|
||||
fi
|
||||
|
||||
_info "Get subdomain list"
|
||||
res=$(_api_call "$Beget_Api/domain/getSubdomainList")
|
||||
if ! _is_api_reply_ok "$res"; then
|
||||
_err "Can't get subdomain list."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$res" "\"fqdn\":\"$fulldomain\""; then
|
||||
_debug "Subdomain $fulldomain already exist."
|
||||
return 0
|
||||
fi
|
||||
|
||||
_info "Subdomain $fulldomain does not exist. Let's create one."
|
||||
data="{\"subdomain\":\"$_sub_domain\",\"domain_id\":$_domain_id}"
|
||||
res=$(_api_call "$Beget_Api/domain/addSubdomainVirtual" "$data")
|
||||
if ! _is_api_reply_ok "$res"; then
|
||||
_err "Can't create subdomain."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "Cleanup subdomen records"
|
||||
data="{\"fqdn\":\"$fulldomain\",\"records\":{}}"
|
||||
res=$(_api_call "$Beget_Api/dns/changeRecords" "$data")
|
||||
if ! _is_api_reply_ok "$res"; then
|
||||
_debug "Can't cleanup $fulldomain records."
|
||||
fi
|
||||
|
||||
data="{\"fqdn\":\"www.$fulldomain\",\"records\":{}}"
|
||||
res=$(_api_call "$Beget_Api/dns/changeRecords" "$data")
|
||||
if ! _is_api_reply_ok "$res"; then
|
||||
_debug "Can't cleanup www.$fulldomain records."
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Usage: _get_root _acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
# _domain_id=32436365
|
||||
_get_root() {
|
||||
fulldomain=$1
|
||||
i=1
|
||||
p=1
|
||||
|
||||
_debug "Get domain list"
|
||||
res=$(_api_call "$Beget_Api/domain/getList")
|
||||
if ! _is_api_reply_ok "$res"; then
|
||||
_err "Can't get domain list."
|
||||
return 1
|
||||
fi
|
||||
|
||||
while true; do
|
||||
h=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-100)
|
||||
_debug h "$h"
|
||||
|
||||
if [ -z "$h" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$res" "$h"; then
|
||||
_domain_id=$(echo "$res" | _egrep_o "\"id\":[0-9]*,\"fqdn\":\"$h\"" | cut -d , -f1 | cut -d : -f2)
|
||||
if [ "$_domain_id" ]; then
|
||||
if [ "$h" != "$fulldomain" ]; then
|
||||
_sub_domain=$(echo "$fulldomain" | cut -d . -f 1-"$p")
|
||||
else
|
||||
_sub_domain=""
|
||||
fi
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
p="$i"
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# Parce DNS records from json string
|
||||
# Usage: _parce_records [j_str] [record_name]
|
||||
_parce_records() {
|
||||
j_str=$1
|
||||
record_name=$2
|
||||
res="\"$record_name\":["
|
||||
res=${res}$(echo "$j_str" | _egrep_o "\"$record_name\":\[.*" | cut -d '[' -f2 | cut -d ']' -f1)
|
||||
res=${res}"],"
|
||||
echo "$res"
|
||||
}
|
||||
|
||||
# Usage: _add_record [data] [record_name] [record_data]
|
||||
_add_record() {
|
||||
data=$1
|
||||
record_name=$2
|
||||
record_data=$3
|
||||
echo "$data" | sed "s/\"$record_name\":\[/\"$record_name\":\[$record_data,/" | sed "s/,\]/\]/"
|
||||
}
|
||||
|
||||
# Usage: _rm_record [data] [record_data]
|
||||
_rm_record() {
|
||||
data=$1
|
||||
record_data=$2
|
||||
echo "$data" | sed "s/$record_data//g" | sed "s/,\+/,/g" |
|
||||
sed "s/{,/{/g" | sed "s/,}/}/g" |
|
||||
sed "s/\[,/\[/g" | sed "s/,\]/\]/g"
|
||||
}
|
||||
|
||||
_txt_to_dns_json() {
|
||||
echo "{\"ttl\":600,\"txtdata\":\"$1\"}"
|
||||
}
|
||||
|
||||
# Usage: _api_call [api_url] [input_data]
|
||||
_api_call() {
|
||||
api_url="$1"
|
||||
input_data="$2"
|
||||
|
||||
_debug "_api_call $api_url"
|
||||
_debug "Request: $input_data"
|
||||
|
||||
# res=$(curl -s -L -D ./http.header \
|
||||
# "$api_url" \
|
||||
# --data-urlencode login=$Beget_Username \
|
||||
# --data-urlencode passwd=$Beget_Password \
|
||||
# --data-urlencode input_format=json \
|
||||
# --data-urlencode output_format=json \
|
||||
# --data-urlencode "input_data=$input_data")
|
||||
|
||||
url="$api_url?login=$Beget_Username&passwd=$Beget_Password&input_format=json&output_format=json"
|
||||
if [ -n "$input_data" ]; then
|
||||
url=${url}"&input_data="
|
||||
url=${url}$(echo "$input_data" | _url_encode)
|
||||
fi
|
||||
res=$(_get "$url")
|
||||
|
||||
_debug "Reply: $res"
|
||||
echo "$res"
|
||||
}
|
||||
|
||||
# Usage: _is_api_reply_ok [api_reply]
|
||||
_is_api_reply_ok() {
|
||||
_contains "$1" '^{"status":"success","answer":{"status":"success","result":.*}}$'
|
||||
}
|
88
dnsapi/dns_bookmyname.sh
Normal file
88
dnsapi/dns_bookmyname.sh
Normal file
@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_bookmyname_info='BookMyName.com
|
||||
Site: BookMyName.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_bookmyname
|
||||
Options:
|
||||
BOOKMYNAME_USERNAME Username
|
||||
BOOKMYNAME_PASSWORD Password
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/3209
|
||||
Author: Neilpang
|
||||
'
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
# BookMyName urls:
|
||||
# https://BOOKMYNAME_USERNAME:BOOKMYNAME_PASSWORD@www.bookmyname.com/dyndns/?hostname=_acme-challenge.domain.tld&type=txt&ttl=300&do=add&value="XXXXXXXX"'
|
||||
# https://BOOKMYNAME_USERNAME:BOOKMYNAME_PASSWORD@www.bookmyname.com/dyndns/?hostname=_acme-challenge.domain.tld&type=txt&ttl=300&do=remove&value="XXXXXXXX"'
|
||||
|
||||
# Output:
|
||||
#good: update done, cid 123456, domain id 456789, type txt, ip XXXXXXXX
|
||||
#good: remove done 1, cid 123456, domain id 456789, ttl 300, type txt, ip XXXXXXXX
|
||||
|
||||
# Be careful, BMN DNS servers can be slow to pick up changes; using dnssleep is thus advised.
|
||||
|
||||
# Usage:
|
||||
# export BOOKMYNAME_USERNAME="ABCDE-FREE"
|
||||
# export BOOKMYNAME_PASSWORD="MyPassword"
|
||||
# /usr/local/ssl/acme.sh/acme.sh --dns dns_bookmyname --dnssleep 600 --issue -d domain.tld
|
||||
|
||||
#Usage: dns_bookmyname_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_bookmyname_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_info "Using bookmyname"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
BOOKMYNAME_USERNAME="${BOOKMYNAME_USERNAME:-$(_readaccountconf_mutable BOOKMYNAME_USERNAME)}"
|
||||
BOOKMYNAME_PASSWORD="${BOOKMYNAME_PASSWORD:-$(_readaccountconf_mutable BOOKMYNAME_PASSWORD)}"
|
||||
|
||||
if [ -z "$BOOKMYNAME_USERNAME" ] || [ -z "$BOOKMYNAME_PASSWORD" ]; then
|
||||
BOOKMYNAME_USERNAME=""
|
||||
BOOKMYNAME_PASSWORD=""
|
||||
_err "You didn't specify BookMyName username and password yet."
|
||||
_err "Please specify them and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the credentials to the account conf file.
|
||||
_saveaccountconf_mutable BOOKMYNAME_USERNAME "$BOOKMYNAME_USERNAME"
|
||||
_saveaccountconf_mutable BOOKMYNAME_PASSWORD "$BOOKMYNAME_PASSWORD"
|
||||
|
||||
uri="https://${BOOKMYNAME_USERNAME}:${BOOKMYNAME_PASSWORD}@www.bookmyname.com/dyndns/"
|
||||
data="?hostname=${fulldomain}&type=TXT&ttl=300&do=add&value=${txtvalue}"
|
||||
result="$(_get "${uri}${data}")"
|
||||
_debug "Result: $result"
|
||||
|
||||
if ! _startswith "$result" 'good: update done, cid '; then
|
||||
_err "Can't add $fulldomain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
#Usage: fulldomain txtvalue
|
||||
#Remove the txt record after validation.
|
||||
dns_bookmyname_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_info "Using bookmyname"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
BOOKMYNAME_USERNAME="${BOOKMYNAME_USERNAME:-$(_readaccountconf_mutable BOOKMYNAME_USERNAME)}"
|
||||
BOOKMYNAME_PASSWORD="${BOOKMYNAME_PASSWORD:-$(_readaccountconf_mutable BOOKMYNAME_PASSWORD)}"
|
||||
|
||||
uri="https://${BOOKMYNAME_USERNAME}:${BOOKMYNAME_PASSWORD}@www.bookmyname.com/dyndns/"
|
||||
data="?hostname=${fulldomain}&type=TXT&ttl=300&do=remove&value=${txtvalue}"
|
||||
result="$(_get "${uri}${data}")"
|
||||
_debug "Result: $result"
|
||||
|
||||
if ! _startswith "$result" 'good: remove done 1, cid '; then
|
||||
_info "Can't remove $fulldomain"
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
@ -1,16 +1,13 @@
|
||||
#!/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"
|
||||
##
|
||||
# shellcheck disable=SC2034
|
||||
dns_bunny_info='Bunny.net
|
||||
Site: Bunny.net/dns/
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_bunny
|
||||
Options:
|
||||
BUNNY_API_KEY API Key
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/4296
|
||||
Author: <nosilver4u@ewww.io>
|
||||
'
|
||||
|
||||
##################### Public functions #####################
|
||||
|
||||
@ -199,7 +196,7 @@ _get_base_domain() {
|
||||
_debug2 domain_list "$domain_list"
|
||||
|
||||
i=1
|
||||
while [ $i -gt 0 ]; do
|
||||
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)
|
||||
@ -211,7 +208,7 @@ _get_base_domain() {
|
||||
## check if it exists
|
||||
if [ -n "$found" ]; then
|
||||
## exists - exit loop returning the parts
|
||||
sub_point=$(_math $i - 1)
|
||||
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"
|
||||
@ -221,11 +218,11 @@ _get_base_domain() {
|
||||
return 0
|
||||
fi
|
||||
## increment cut point $i
|
||||
i=$(_math $i + 1)
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
|
||||
if [ -z "$found" ]; then
|
||||
page=$(_math $page + 1)
|
||||
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")"
|
||||
|
@ -1,13 +1,16 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
#CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
#
|
||||
#CF_Email="xxxx@sss.com"
|
||||
|
||||
#CF_Token="xxxx"
|
||||
#CF_Account_ID="xxxx"
|
||||
#CF_Zone_ID="xxxx"
|
||||
# shellcheck disable=SC2034
|
||||
dns_cf_info='CloudFlare
|
||||
Site: CloudFlare.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_cf
|
||||
Options:
|
||||
CF_Key API Key
|
||||
CF_Email Your account email
|
||||
OptionsAlt:
|
||||
CF_Token API Token
|
||||
CF_Account_ID Account ID
|
||||
CF_Zone_ID Zone ID. Optional.
|
||||
'
|
||||
|
||||
CF_Api="https://api.cloudflare.com/client/v4"
|
||||
|
||||
@ -183,7 +186,7 @@ _get_root() {
|
||||
fi
|
||||
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
@ -203,7 +206,7 @@ _get_root() {
|
||||
if _contains "$response" "\"name\":\"$h\"" || _contains "$response" '"total_count":1'; then
|
||||
_domain_id=$(echo "$response" | _egrep_o "\[.\"id\": *\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \" | tr -d " ")
|
||||
if [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
|
@ -1,10 +1,15 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Author: Radek Sprta <sprta@vshosting.cz>
|
||||
|
||||
#CLOUDDNS_EMAIL=XXXXX
|
||||
#CLOUDDNS_PASSWORD="YYYYYYYYY"
|
||||
#CLOUDDNS_CLIENT_ID=XXXXX
|
||||
# shellcheck disable=SC2034
|
||||
dns_clouddns_info='vshosting.cz CloudDNS
|
||||
Site: github.com/vshosting/clouddns
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_clouddns
|
||||
Options:
|
||||
CLOUDDNS_EMAIL Email
|
||||
CLOUDDNS_PASSWORD Password
|
||||
CLOUDDNS_CLIENT_ID Client ID
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2699
|
||||
Author: Radek Sprta <sprta@vshosting.cz>
|
||||
'
|
||||
|
||||
CLOUDDNS_API='https://admin.vshosting.cloud/clouddns'
|
||||
CLOUDDNS_LOGIN_API='https://admin.vshosting.cloud/api/public/auth/login'
|
||||
|
@ -1,12 +1,15 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_cloudns_info='ClouDNS.net
|
||||
Site: ClouDNS.net
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_cloudns
|
||||
Options:
|
||||
CLOUDNS_AUTH_ID Regular auth ID
|
||||
CLOUDNS_SUB_AUTH_ID Sub auth ID
|
||||
CLOUDNS_AUTH_PASSWORD Auth Password
|
||||
Author: Boyan Peychev <boyan@cloudns.net>
|
||||
'
|
||||
|
||||
# Author: Boyan Peychev <boyan at cloudns dot net>
|
||||
# Repository: https://github.com/ClouDNS/acme.sh/
|
||||
# Editor: I Komang Suryadana
|
||||
|
||||
#CLOUDNS_AUTH_ID=XXXXX
|
||||
#CLOUDNS_SUB_AUTH_ID=XXXXX
|
||||
#CLOUDNS_AUTH_PASSWORD="YYYYYYYYY"
|
||||
CLOUDNS_API="https://api.cloudns.net"
|
||||
DOMAIN_TYPE=
|
||||
DOMAIN_MASTER=
|
||||
@ -161,7 +164,7 @@ _dns_cloudns_get_zone_info() {
|
||||
_dns_cloudns_get_zone_name() {
|
||||
i=2
|
||||
while true; do
|
||||
zoneForCheck=$(printf "%s" "$1" | cut -d . -f $i-100)
|
||||
zoneForCheck=$(printf "%s" "$1" | cut -d . -f "$i"-100)
|
||||
|
||||
if [ -z "$zoneForCheck" ]; then
|
||||
return 1
|
||||
|
@ -1,7 +1,14 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# DNS API for acme.sh for Core-Networks (https://beta.api.core-networks.de/doc/).
|
||||
# created by 5ll and francis
|
||||
# shellcheck disable=SC2034
|
||||
dns_cn_info='Core-Networks.de
|
||||
Site: beta.api.Core-Networks.de/doc/
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_cn
|
||||
Options:
|
||||
CN_User User
|
||||
CN_Password Password
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2142
|
||||
Author: 5ll, francis
|
||||
'
|
||||
|
||||
CN_API="https://beta.api.core-networks.de"
|
||||
|
||||
@ -124,7 +131,7 @@ _cn_get_root() {
|
||||
p=1
|
||||
while true; do
|
||||
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
_debug h "$h"
|
||||
_debug _H1 "${_H1}"
|
||||
|
||||
@ -142,7 +149,7 @@ _cn_get_root() {
|
||||
fi
|
||||
|
||||
if _contains "$_cn_zonelist" "\"name\":\"$h\"" >/dev/null; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||
_domain=$h
|
||||
return 0
|
||||
else
|
||||
|
@ -1,4 +1,15 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_conoha_info='ConoHa.jp
|
||||
Domains: ConoHa.io
|
||||
Site: ConoHa.jp
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_conoha
|
||||
Options:
|
||||
CONOHA_Username Username
|
||||
CONOHA_Password Password
|
||||
CONOHA_TenantId TenantId
|
||||
CONOHA_IdentityServiceApi Identity Service API. E.g. "https://identity.xxxx.conoha.io/v2.0"
|
||||
'
|
||||
|
||||
CONOHA_DNS_EP_PREFIX_REGEXP="https://dns-service\."
|
||||
|
||||
@ -226,7 +237,7 @@ _get_root() {
|
||||
i=2
|
||||
p=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100).
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100).
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
@ -240,7 +251,7 @@ _get_root() {
|
||||
if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
|
||||
_domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \")
|
||||
if [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
|
@ -1,10 +1,16 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Author: Wout Decre <wout@canodus.be>
|
||||
# shellcheck disable=SC2034
|
||||
dns_constellix_info='Constellix.com
|
||||
Site: Constellix.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_constellix
|
||||
Options:
|
||||
CONSTELLIX_Key API Key
|
||||
CONSTELLIX_Secret API Secret
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2724
|
||||
Author: Wout Decre <wout@canodus.be>
|
||||
'
|
||||
|
||||
CONSTELLIX_Api="https://api.dns.constellix.com/v1"
|
||||
#CONSTELLIX_Key="XXX"
|
||||
#CONSTELLIX_Secret="XXX"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
@ -116,7 +122,7 @@ _get_root() {
|
||||
p=1
|
||||
_debug "Detecting root zone"
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
if [ -z "$h" ]; then
|
||||
return 1
|
||||
fi
|
||||
@ -128,7 +134,7 @@ _get_root() {
|
||||
if _contains "$response" "\"name\":\"$h\""; then
|
||||
_domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[0-9]*" | cut -d ':' -f 2)
|
||||
if [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d '.' -f 1-$p)
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d '.' -f 1-"$p")
|
||||
_domain="$h"
|
||||
|
||||
_debug _domain_id "$_domain_id"
|
||||
|
@ -1,18 +1,18 @@
|
||||
#!/usr/bin/env sh
|
||||
#
|
||||
#Author: Bjarne Saltbaek
|
||||
#Report Bugs here: https://github.com/acmesh-official/acme.sh/issues/3732
|
||||
#
|
||||
#
|
||||
# shellcheck disable=SC2034
|
||||
dns_cpanel_info='cPanel Server API
|
||||
Manage DNS via cPanel Dashboard.
|
||||
Site: cPanel.net
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_cpanel
|
||||
Options:
|
||||
cPanel_Username Username
|
||||
cPanel_Apitoken API Token
|
||||
cPanel_Hostname Server URL. E.g. "https://hostname:port"
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/3732
|
||||
Author: Bjarne Saltbaek
|
||||
'
|
||||
|
||||
######## Public functions #####################
|
||||
#
|
||||
# Export CPANEL username,api token and hostname in the following variables
|
||||
#
|
||||
# cPanel_Username=username
|
||||
# cPanel_Apitoken=apitoken
|
||||
# cPanel_Hostname=hostname
|
||||
#
|
||||
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
|
||||
# Used to add txt record
|
||||
dns_cpanel_add() {
|
||||
|
@ -1,9 +1,15 @@
|
||||
#!/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
|
||||
# shellcheck disable=SC2034
|
||||
dns_curanet_info='Curanet.dk
|
||||
Domains: scannet.dk wannafind.dk dandomain.dk
|
||||
Site: Curanet.dk
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_curanet
|
||||
Options:
|
||||
CURANET_AUTHCLIENTID Auth ClientID. Requires scope dns
|
||||
CURANET_AUTHSECRET Auth Secret
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/3933
|
||||
Author: Peter L. Hansen <peter@r12.dk>
|
||||
'
|
||||
|
||||
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"
|
||||
@ -136,7 +142,7 @@ _get_root() {
|
||||
i=1
|
||||
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
|
@ -1,21 +1,15 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
########
|
||||
# Custom cyon.ch DNS API for use with [acme.sh](https://github.com/acmesh-official/acme.sh)
|
||||
#
|
||||
# Usage: acme.sh --issue --dns dns_cyon -d www.domain.com
|
||||
#
|
||||
# Dependencies:
|
||||
# -------------
|
||||
# - oathtool (When using 2 Factor Authentication)
|
||||
#
|
||||
# Issues:
|
||||
# -------
|
||||
# Any issues / questions / suggestions can be posted here:
|
||||
# https://github.com/noplanman/cyon-api/issues
|
||||
#
|
||||
# Author: Armando Lüscher <armando@noplanman.ch>
|
||||
########
|
||||
# shellcheck disable=SC2034
|
||||
dns_cyon_info='cyon.ch
|
||||
Site: cyon.ch
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_cyon
|
||||
Options:
|
||||
CY_Username Username
|
||||
CY_Password API Token
|
||||
CY_OTP_Secret OTP token. Only required if using 2FA
|
||||
Issues: github.com/noplanman/cyon-api/issues
|
||||
Author: Armando Lüscher <armando@noplanman.ch>
|
||||
'
|
||||
|
||||
dns_cyon_add() {
|
||||
_cyon_load_credentials &&
|
||||
@ -221,10 +215,8 @@ _cyon_change_domain_env() {
|
||||
|
||||
if ! _cyon_check_if_2fa_missed "${domain_env_response}"; then return 1; fi
|
||||
|
||||
domain_env_success="$(printf "%s" "${domain_env_response}" | _egrep_o '"authenticated":\w*' | cut -d : -f 2)"
|
||||
|
||||
# Bail if domain environment change fails.
|
||||
if [ "${domain_env_success}" != "true" ]; then
|
||||
if [ "$(printf "%s" "${domain_env_response}" | _cyon_get_environment_change_status)" != "true" ]; then
|
||||
_err " $(printf "%s" "${domain_env_response}" | _cyon_get_response_message)"
|
||||
_err ""
|
||||
return 1
|
||||
@ -238,7 +230,7 @@ _cyon_add_txt() {
|
||||
_info " - Adding DNS TXT entry..."
|
||||
|
||||
add_txt_url="https://my.cyon.ch/domain/dnseditor/add-record-async"
|
||||
add_txt_data="zone=${fulldomain_idn}.&ttl=900&type=TXT&value=${txtvalue}"
|
||||
add_txt_data="name=${fulldomain_idn}.&ttl=900&type=TXT&dnscontent=${txtvalue}"
|
||||
|
||||
add_txt_response="$(_post "$add_txt_data" "$add_txt_url")"
|
||||
_debug add_txt_response "${add_txt_response}"
|
||||
@ -247,9 +239,10 @@ _cyon_add_txt() {
|
||||
|
||||
add_txt_message="$(printf "%s" "${add_txt_response}" | _cyon_get_response_message)"
|
||||
add_txt_status="$(printf "%s" "${add_txt_response}" | _cyon_get_response_status)"
|
||||
add_txt_validation="$(printf "%s" "${add_txt_response}" | _cyon_get_validation_status)"
|
||||
|
||||
# Bail if adding TXT entry fails.
|
||||
if [ "${add_txt_status}" != "true" ]; then
|
||||
if [ "${add_txt_status}" != "true" ] || [ "${add_txt_validation}" != "true" ]; then
|
||||
_err " ${add_txt_message}"
|
||||
_err ""
|
||||
return 1
|
||||
@ -311,13 +304,21 @@ _cyon_get_response_message() {
|
||||
}
|
||||
|
||||
_cyon_get_response_status() {
|
||||
_egrep_o '"status":\w*' | cut -d : -f 2
|
||||
_egrep_o '"status":[a-zA-z0-9]*' | cut -d : -f 2
|
||||
}
|
||||
|
||||
_cyon_get_validation_status() {
|
||||
_egrep_o '"valid":[a-zA-z0-9]*' | cut -d : -f 2
|
||||
}
|
||||
|
||||
_cyon_get_response_success() {
|
||||
_egrep_o '"onSuccess":"[^"]*"' | cut -d : -f 2 | tr -d '"'
|
||||
}
|
||||
|
||||
_cyon_get_environment_change_status() {
|
||||
_egrep_o '"authenticated":[a-zA-z0-9]*' | cut -d : -f 2
|
||||
}
|
||||
|
||||
_cyon_check_if_2fa_missed() {
|
||||
# Did we miss the 2FA?
|
||||
if test "${1#*multi_factor_form}" != "${1}"; then
|
||||
|
@ -1,31 +1,14 @@
|
||||
#!/usr/bin/env sh
|
||||
# -*- mode: sh; tab-width: 2; indent-tabs-mode: s; coding: utf-8 -*-
|
||||
# vim: et ts=2 sw=2
|
||||
#
|
||||
# DirectAdmin 1.41.0 API
|
||||
# The DirectAdmin interface has it's own Let's encrypt functionality, but this
|
||||
# script can be used to generate certificates for names which are not hosted on
|
||||
# DirectAdmin
|
||||
#
|
||||
# User must provide login data and URL to DirectAdmin incl. port.
|
||||
# You can create login key, by using the Login Keys function
|
||||
# ( https://da.example.com:8443/CMD_LOGIN_KEYS ), which only has access to
|
||||
# - CMD_API_DNS_CONTROL
|
||||
# - CMD_API_SHOW_DOMAINS
|
||||
#
|
||||
# See also https://www.directadmin.com/api.php and
|
||||
# https://www.directadmin.com/features.php?id=1298
|
||||
#
|
||||
# Report bugs to https://github.com/TigerP/acme.sh/issues
|
||||
#
|
||||
# Values to export:
|
||||
# export DA_Api="https://remoteUser:remotePassword@da.example.com:8443"
|
||||
# export DA_Api_Insecure=1
|
||||
#
|
||||
# Set DA_Api_Insecure to 1 for insecure and 0 for secure -> difference is
|
||||
# whether ssl cert is checked for validity (0) or whether it is just accepted
|
||||
# (1)
|
||||
#
|
||||
# shellcheck disable=SC2034
|
||||
dns_da_info='DirectAdmin Server API
|
||||
Site: DirectAdmin.com/api.php
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_da
|
||||
Options:
|
||||
DA_Api API Server URL. E.g. "https://remoteUser:remotePassword@da.domain.tld:8443"
|
||||
DA_Api_Insecure Insecure TLS. 0: check for cert validity, 1: always accept
|
||||
Issues: github.com/TigerP/acme.sh/issues
|
||||
'
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
# Usage: dns_myapi_add _acme-challenge.www.example.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
@ -78,7 +61,7 @@ _get_root() {
|
||||
# response will contain "list[]=example.com&list[]=example.org"
|
||||
_da_api CMD_API_SHOW_DOMAINS "" "${domain}"
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
# not valid
|
||||
@ -86,7 +69,7 @@ _get_root() {
|
||||
return 1
|
||||
fi
|
||||
if _contains "$response" "$h" >/dev/null; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
|
@ -1,16 +1,13 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#Created by RaidenII, to use DuckDNS's API to add/remove text records
|
||||
#modified by helbgd @ 03/13/2018 to support ddnss.de
|
||||
#modified by mod242 @ 04/24/2018 to support different ddnss domains
|
||||
#Please note: the Wildcard Feature must be turned on for the Host record
|
||||
#and the checkbox for TXT needs to be enabled
|
||||
|
||||
# Pass credentials before "acme.sh --issue --dns dns_ddnss ..."
|
||||
# --
|
||||
# export DDNSS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
|
||||
# --
|
||||
#
|
||||
# shellcheck disable=SC2034
|
||||
dns_ddnss_info='DDNSS.de
|
||||
Site: DDNSS.de
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_ddnss
|
||||
Options:
|
||||
DDNSS_Token API Token
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2230
|
||||
Author: RaidenII, helbgd, mod242
|
||||
'
|
||||
|
||||
DDNSS_DNS_API="https://ddnss.de/upd.php"
|
||||
|
||||
|
@ -1,11 +1,13 @@
|
||||
#!/usr/bin/env sh
|
||||
#
|
||||
# deSEC.io Domain API
|
||||
#
|
||||
# Author: Zheng Qian
|
||||
#
|
||||
# deSEC API doc
|
||||
# https://desec.readthedocs.io/en/latest/
|
||||
# shellcheck disable=SC2034
|
||||
dns_desec_info='deSEC.io
|
||||
Site: desec.readthedocs.io/en/latest/
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_desec
|
||||
Options:
|
||||
DDNSS_Token API Token
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2180
|
||||
Author: Zheng Qian
|
||||
'
|
||||
|
||||
REST_API="https://desec.io/api/v1/domains"
|
||||
|
||||
@ -174,7 +176,7 @@ _get_root() {
|
||||
i=2
|
||||
p=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
@ -186,7 +188,7 @@ _get_root() {
|
||||
fi
|
||||
|
||||
if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
|
@ -1,18 +1,15 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
########################################################################
|
||||
# https://dyndnsfree.de hook script for acme.sh
|
||||
#
|
||||
# Environment variables:
|
||||
#
|
||||
# - $DF_user (your dyndnsfree.de username)
|
||||
# - $DF_password (your dyndnsfree.de password)
|
||||
#
|
||||
# Author: Thilo Gass <thilo.gass@gmail.com>
|
||||
# Git repo: https://github.com/ThiloGa/acme.sh
|
||||
|
||||
#-- dns_df_add() - Add TXT record --------------------------------------
|
||||
# Usage: dns_df_add _acme-challenge.subdomain.domain.com "XyZ123..."
|
||||
# shellcheck disable=SC2034
|
||||
dns_df_info='DynDnsFree.de
|
||||
Domains: dynup.de
|
||||
Site: DynDnsFree.de
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_df
|
||||
Options:
|
||||
DF_user Username
|
||||
DF_password Password
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2897
|
||||
Author: Thilo Gass <thilo.gass@gmail.com>
|
||||
'
|
||||
|
||||
dyndnsfree_api="https://dynup.de/acme.php"
|
||||
|
||||
|
@ -1,16 +1,12 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
## Will be called by acme.sh to add the txt record to your api system.
|
||||
## returns 0 means success, otherwise error.
|
||||
|
||||
## Author: thewer <github at thewer.com>
|
||||
## GitHub: https://github.com/gitwer/acme.sh
|
||||
|
||||
##
|
||||
## Environment Variables Required:
|
||||
##
|
||||
## DO_API_KEY="75310dc4ca779ac39a19f6355db573b49ce92ae126553ebd61ac3a3ae34834cc"
|
||||
##
|
||||
# shellcheck disable=SC2034
|
||||
dns_dgon_info='DigitalOcean.com
|
||||
Site: DigitalOcean.com/help/api/
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dgon
|
||||
Options:
|
||||
DO_API_KEY API Key
|
||||
Author: <github@thewer.com>
|
||||
'
|
||||
|
||||
##################### Public functions #####################
|
||||
|
||||
@ -207,7 +203,7 @@ _get_base_domain() {
|
||||
_debug2 domain_list "$domain_list"
|
||||
|
||||
i=1
|
||||
while [ $i -gt 0 ]; do
|
||||
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)
|
||||
@ -219,14 +215,14 @@ _get_base_domain() {
|
||||
## check if it exists
|
||||
if [ -n "$found" ]; then
|
||||
## exists - exit loop returning the parts
|
||||
sub_point=$(_math $i - 1)
|
||||
sub_point=$(_math "$i" - 1)
|
||||
_sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$sub_point")
|
||||
_debug _domain "$_domain"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
return 0
|
||||
fi
|
||||
## increment cut point $i
|
||||
i=$(_math $i + 1)
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
|
||||
if [ -z "$found" ]; then
|
||||
|
188
dnsapi/dns_dnsexit.sh
Normal file
188
dnsapi/dns_dnsexit.sh
Normal file
@ -0,0 +1,188 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_dnsexit_info='DNSExit.com
|
||||
Site: DNSExit.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_dnsexit
|
||||
Options:
|
||||
DNSEXIT_API_KEY API Key
|
||||
DNSEXIT_AUTH_USER Username
|
||||
DNSEXIT_AUTH_PASS Password
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/4719
|
||||
Author: Samuel Jimenez
|
||||
'
|
||||
|
||||
DNSEXIT_API_URL="https://api.dnsexit.com/dns/"
|
||||
DNSEXIT_HOSTS_URL="https://update.dnsexit.com/ipupdate/hosts.jsp"
|
||||
|
||||
######## Public functions #####################
|
||||
#Usage: dns_dnsexit_add _acme-challenge.*.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_dnsexit_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_info "Using DNSExit.com"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
_debug 'Load account auth'
|
||||
if ! get_account_info; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug 'First detect the root zone'
|
||||
if ! _get_root "$fulldomain"; then
|
||||
return 1
|
||||
fi
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
if ! _dnsexit_rest "{\"domain\":\"$_domain\",\"add\":{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":0,\"overwrite\":false}}"; then
|
||||
_err "$response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 _response "$response"
|
||||
return 0
|
||||
}
|
||||
|
||||
#Usage: fulldomain txtvalue
|
||||
#Remove the txt record after validation.
|
||||
dns_dnsexit_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_info "Using DNSExit.com"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
_debug 'Load account auth'
|
||||
if ! get_account_info; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug 'First detect the root zone'
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "$response"
|
||||
return 1
|
||||
fi
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
if ! _dnsexit_rest "{\"domain\":\"$_domain\",\"delete\":{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\"}}"; then
|
||||
_err "$response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 _response "$response"
|
||||
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
|
||||
_domain=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
_debug h "$_domain"
|
||||
if [ -z "$_domain" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug login "$DNSEXIT_AUTH_USER"
|
||||
_debug password "$DNSEXIT_AUTH_PASS"
|
||||
_debug domain "$_domain"
|
||||
|
||||
_dnsexit_http "login=$DNSEXIT_AUTH_USER&password=$DNSEXIT_AUTH_PASS&domain=$_domain"
|
||||
|
||||
if _contains "$response" "0=$_domain"; then
|
||||
_sub_domain="$(echo "$fulldomain" | sed "s/\\.$_domain\$//")"
|
||||
return 0
|
||||
else
|
||||
_debug "Go to next level of $_domain"
|
||||
fi
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
_dnsexit_rest() {
|
||||
m=POST
|
||||
ep=""
|
||||
data="$1"
|
||||
_debug _dnsexit_rest "$ep"
|
||||
_debug data "$data"
|
||||
|
||||
api_key_trimmed=$(echo "$DNSEXIT_API_KEY" | tr -d '"')
|
||||
|
||||
export _H1="apikey: $api_key_trimmed"
|
||||
export _H2='Content-Type: application/json'
|
||||
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$DNSEXIT_API_URL/$ep" "" "$m")"
|
||||
else
|
||||
response="$(_get "$DNSEXIT_API_URL/$ep")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "Error $ep"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
|
||||
_dnsexit_http() {
|
||||
m=GET
|
||||
param="$1"
|
||||
_debug param "$param"
|
||||
_debug get "$DNSEXIT_HOSTS_URL?$param"
|
||||
|
||||
response="$(_get "$DNSEXIT_HOSTS_URL?$param")"
|
||||
|
||||
_debug response "$response"
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "Error $param"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
|
||||
get_account_info() {
|
||||
|
||||
DNSEXIT_API_KEY="${DNSEXIT_API_KEY:-$(_readaccountconf_mutable DNSEXIT_API_KEY)}"
|
||||
if test -z "$DNSEXIT_API_KEY"; then
|
||||
DNSEXIT_API_KEY=''
|
||||
_err 'DNSEXIT_API_KEY was not exported'
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf_mutable DNSEXIT_API_KEY "$DNSEXIT_API_KEY"
|
||||
|
||||
DNSEXIT_AUTH_USER="${DNSEXIT_AUTH_USER:-$(_readaccountconf_mutable DNSEXIT_AUTH_USER)}"
|
||||
if test -z "$DNSEXIT_AUTH_USER"; then
|
||||
DNSEXIT_AUTH_USER=""
|
||||
_err 'DNSEXIT_AUTH_USER was not exported'
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf_mutable DNSEXIT_AUTH_USER "$DNSEXIT_AUTH_USER"
|
||||
|
||||
DNSEXIT_AUTH_PASS="${DNSEXIT_AUTH_PASS:-$(_readaccountconf_mutable DNSEXIT_AUTH_PASS)}"
|
||||
if test -z "$DNSEXIT_AUTH_PASS"; then
|
||||
DNSEXIT_AUTH_PASS=""
|
||||
_err 'DNSEXIT_AUTH_PASS was not exported'
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf_mutable DNSEXIT_AUTH_PASS "$DNSEXIT_AUTH_PASS"
|
||||
|
||||
return 0
|
||||
}
|
@ -1,15 +1,14 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# dnsHome.de API for acme.sh
|
||||
#
|
||||
# This Script adds the necessary TXT record to a Subdomain
|
||||
#
|
||||
# Author dnsHome.de (https://github.com/dnsHome-de)
|
||||
#
|
||||
# Report Bugs to https://github.com/acmesh-official/acme.sh/issues/3819
|
||||
#
|
||||
# export DNSHOME_Subdomain=""
|
||||
# export DNSHOME_SubdomainPassword=""
|
||||
# shellcheck disable=SC2034
|
||||
dns_dnshome_info='dnsHome.de
|
||||
Site: dnsHome.de
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_dnshome
|
||||
Options:
|
||||
DNSHOME_Subdomain Subdomain
|
||||
DNSHOME_SubdomainPassword Subdomain Password
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/3819
|
||||
Author: dnsHome.de https://github.com/dnsHome-de
|
||||
'
|
||||
|
||||
# Usage: add subdomain.ddnsdomain.tld "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
# Used to add txt record
|
||||
|
@ -1,12 +1,12 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# DNSimple domain api
|
||||
# https://github.com/pho3nixf1re/acme.sh/issues
|
||||
#
|
||||
# This is your oauth token which can be acquired on the account page. Please
|
||||
# note that this must be an _account_ token and not a _user_ token.
|
||||
# https://dnsimple.com/a/<your account id>/account/access_tokens
|
||||
# DNSimple_OAUTH_TOKEN="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
# shellcheck disable=SC2034
|
||||
dns_dnsimple_info='DNSimple.com
|
||||
Site: DNSimple.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dnsimple
|
||||
Options:
|
||||
DNSimple_OAUTH_TOKEN OAuth Token
|
||||
Issues: github.com/pho3nixf1re/acme.sh/issues
|
||||
'
|
||||
|
||||
DNSimple_API="https://api.dnsimple.com/v2"
|
||||
|
||||
@ -92,7 +92,7 @@ _get_root() {
|
||||
i=2
|
||||
previous=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
if [ -z "$h" ]; then
|
||||
# not valid
|
||||
return 1
|
||||
@ -105,7 +105,7 @@ _get_root() {
|
||||
if _contains "$response" 'not found'; then
|
||||
_debug "$h not found"
|
||||
else
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$previous)
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$previous")
|
||||
_domain="$h"
|
||||
|
||||
_debug _domain "$_domain"
|
||||
|
@ -1,12 +1,15 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_dnsservices_info='DNS.Services
|
||||
Site: DNS.Services
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_dnsservices
|
||||
Options:
|
||||
DnsServices_Username Username
|
||||
DnsServices_Password Password
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/4152
|
||||
Author: Bjarke Bruun <bbruun@gmail.com>
|
||||
'
|
||||
|
||||
#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 #####################
|
||||
|
148
dnsapi/dns_do.sh
148
dnsapi/dns_do.sh
@ -1,148 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# DNS API for Domain-Offensive / Resellerinterface / Domainrobot
|
||||
|
||||
# Report bugs at https://github.com/seidler2547/acme.sh/issues
|
||||
|
||||
# set these environment variables to match your customer ID and password:
|
||||
# DO_PID="KD-1234567"
|
||||
# DO_PW="cdfkjl3n2"
|
||||
|
||||
DO_URL="https://soap.resellerinterface.de/"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_do_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
if _dns_do_authenticate; then
|
||||
_info "Adding TXT record to ${_domain} as ${fulldomain}"
|
||||
_dns_do_soap createRR origin "${_domain}" name "${fulldomain}" type TXT data "${txtvalue}" ttl 300
|
||||
if _contains "${response}" '>success<'; then
|
||||
return 0
|
||||
fi
|
||||
_err "Could not create resource record, check logs"
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
#fulldomain
|
||||
dns_do_rm() {
|
||||
fulldomain=$1
|
||||
if _dns_do_authenticate; then
|
||||
if _dns_do_list_rrs; then
|
||||
_dns_do_had_error=0
|
||||
for _rrid in ${_rr_list}; do
|
||||
_info "Deleting resource record $_rrid for $_domain"
|
||||
_dns_do_soap deleteRR origin "${_domain}" rrid "${_rrid}"
|
||||
if ! _contains "${response}" '>success<'; then
|
||||
_dns_do_had_error=1
|
||||
_err "Could not delete resource record for ${_domain}, id ${_rrid}"
|
||||
fi
|
||||
done
|
||||
return $_dns_do_had_error
|
||||
fi
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
_dns_do_authenticate() {
|
||||
_info "Authenticating as ${DO_PID}"
|
||||
_dns_do_soap authPartner partner "${DO_PID}" password "${DO_PW}"
|
||||
if _contains "${response}" '>success<'; then
|
||||
_get_root "$fulldomain"
|
||||
_debug "_domain $_domain"
|
||||
return 0
|
||||
else
|
||||
_err "Authentication failed, are DO_PID and DO_PW set correctly?"
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
_dns_do_list_rrs() {
|
||||
_dns_do_soap getRRList origin "${_domain}"
|
||||
if ! _contains "${response}" 'SOAP-ENC:Array'; then
|
||||
_err "getRRList origin ${_domain} failed"
|
||||
return 1
|
||||
fi
|
||||
_rr_list="$(echo "${response}" |
|
||||
tr -d "\n\r\t" |
|
||||
sed -e 's/<item xsi:type="ns2:Map">/\n/g' |
|
||||
grep ">$(_regexcape "$fulldomain")</value>" |
|
||||
sed -e 's/<\/item>/\n/g' |
|
||||
grep '>id</key><value' |
|
||||
_egrep_o '>[0-9]{1,16}<' |
|
||||
tr -d '><')"
|
||||
[ "${_rr_list}" ]
|
||||
}
|
||||
|
||||
_dns_do_soap() {
|
||||
func="$1"
|
||||
shift
|
||||
# put the parameters to xml
|
||||
body="<tns:${func} xmlns:tns=\"${DO_URL}\">"
|
||||
while [ "$1" ]; do
|
||||
_k="$1"
|
||||
shift
|
||||
_v="$1"
|
||||
shift
|
||||
body="$body<$_k>$_v</$_k>"
|
||||
done
|
||||
body="$body</tns:${func}>"
|
||||
_debug2 "SOAP request ${body}"
|
||||
|
||||
# build SOAP XML
|
||||
_xml='<?xml version="1.0" encoding="UTF-8"?>
|
||||
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
|
||||
<env:Body>'"$body"'</env:Body>
|
||||
</env:Envelope>'
|
||||
|
||||
# set SOAP headers
|
||||
export _H1="SOAPAction: ${DO_URL}#${func}"
|
||||
|
||||
if ! response="$(_post "${_xml}" "${DO_URL}")"; then
|
||||
_err "Error <$1>"
|
||||
return 1
|
||||
fi
|
||||
_debug2 "SOAP response $response"
|
||||
|
||||
# retrieve cookie header
|
||||
_H2="$(_egrep_o 'Cookie: [^;]+' <"$HTTP_HEADER" | _head_n 1)"
|
||||
export _H2
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=1
|
||||
|
||||
_dns_do_soap getDomainList
|
||||
_all_domains="$(echo "${response}" |
|
||||
tr -d "\n\r\t " |
|
||||
_egrep_o 'domain</key><value[^>]+>[^<]+' |
|
||||
sed -e 's/^domain<\/key><value[^>]*>//g')"
|
||||
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
if [ -z "$h" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "${_all_domains}" "^$(_regexcape "$h")\$"; then
|
||||
_domain="$h"
|
||||
return 0
|
||||
fi
|
||||
|
||||
i=$(_math $i + 1)
|
||||
done
|
||||
_debug "$domain not found"
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
_regexcape() {
|
||||
echo "$1" | sed -e 's/\([]\.$*^[]\)/\\\1/g'
|
||||
}
|
@ -1,14 +1,16 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_doapi_info='Domain-Offensive do.de
|
||||
Official LetsEncrypt API for do.de / Domain-Offensive.
|
||||
This API is also available to private customers/individuals.
|
||||
Site: do.de
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_doapi
|
||||
Options:
|
||||
DO_LETOKEN LetsEncrypt Token
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2057
|
||||
'
|
||||
|
||||
# Official Let's Encrypt API for do.de / Domain-Offensive
|
||||
#
|
||||
# This is different from the dns_do adapter, because dns_do is only usable for enterprise customers
|
||||
# This API is also available to private customers/individuals
|
||||
#
|
||||
# Provide the required LetsEncrypt token like this:
|
||||
# DO_LETOKEN="FmD408PdqT1E269gUK57"
|
||||
|
||||
DO_API="https://www.do.de/api/letsencrypt"
|
||||
DO_API="https://my.do.de/api/letsencrypt"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
|
@ -1,4 +1,13 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_domeneshop_info='DomeneShop.no
|
||||
Site: DomeneShop.no
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_domeneshop
|
||||
Options:
|
||||
DOMENESHOP_Token Token
|
||||
DOMENESHOP_Secret Secret
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2457
|
||||
'
|
||||
|
||||
DOMENESHOP_Api_Endpoint="https://api.domeneshop.no/v0"
|
||||
|
||||
@ -84,7 +93,7 @@ _get_domainid() {
|
||||
i=2
|
||||
p=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
_debug "h" "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
@ -93,7 +102,7 @@ _get_domainid() {
|
||||
|
||||
if _contains "$response" "\"$h\"" >/dev/null; then
|
||||
# We have found the domain name.
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||
_domain=$h
|
||||
_domainid=$(printf "%s" "$response" | _egrep_o "[^{]*\"domain\":\"$_domain\"[^}]*" | _egrep_o "\"id\":[0-9]+" | cut -d : -f 2)
|
||||
return 0
|
||||
|
@ -1,10 +1,12 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Dnspod.cn Domain api
|
||||
#
|
||||
#DP_Id="1234"
|
||||
#
|
||||
#DP_Key="sADDsdasdgdsf"
|
||||
# shellcheck disable=SC2034
|
||||
dns_dp_info='DNSPod.cn
|
||||
Site: DNSPod.cn
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dp
|
||||
Options:
|
||||
DP_Id Id
|
||||
DP_Key Key
|
||||
'
|
||||
|
||||
REST_API="https://dnsapi.cn"
|
||||
|
||||
@ -107,7 +109,7 @@ _get_root() {
|
||||
i=2
|
||||
p=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
@ -121,7 +123,7 @@ _get_root() {
|
||||
_domain_id=$(printf "%s\n" "$response" | _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)
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_domain="$h"
|
||||
_debug _domain "$_domain"
|
||||
|
@ -1,10 +1,12 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Dnspod.com Domain api
|
||||
#
|
||||
#DPI_Id="1234"
|
||||
#
|
||||
#DPI_Key="sADDsdasdgdsf"
|
||||
# shellcheck disable=SC2034
|
||||
dns_dpi_info='DNSPod.com
|
||||
Site: DNSPod.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dpi
|
||||
Options:
|
||||
DPI_Id Id
|
||||
DPI_Key Key
|
||||
'
|
||||
|
||||
REST_API="https://api.dnspod.com"
|
||||
|
||||
@ -107,7 +109,7 @@ _get_root() {
|
||||
i=2
|
||||
p=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
@ -121,7 +123,7 @@ _get_root() {
|
||||
_domain_id=$(printf "%s\n" "$response" | _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)
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_domain="$h"
|
||||
_debug _domain "$_domain"
|
||||
|
@ -1,10 +1,14 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_dreamhost_info='DreamHost.com
|
||||
Site: DreamHost.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dreamhost
|
||||
Options:
|
||||
DH_API_KEY API Key
|
||||
Issues: github.com/RhinoLance/acme.sh
|
||||
Author: RhinoLance
|
||||
'
|
||||
|
||||
#Author: RhinoLance
|
||||
#Report Bugs here: https://github.com/RhinoLance/acme.sh
|
||||
#
|
||||
|
||||
#define the api endpoint
|
||||
DH_API_ENDPOINT="https://api.dreamhost.com/"
|
||||
querystring=""
|
||||
|
||||
|
@ -1,14 +1,12 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#Created by RaidenII, to use DuckDNS's API to add/remove text records
|
||||
#06/27/2017
|
||||
|
||||
# Pass credentials before "acme.sh --issue --dns dns_duckdns ..."
|
||||
# --
|
||||
# export DuckDNS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
|
||||
# --
|
||||
#
|
||||
# Due to the fact that DuckDNS uses StartSSL as cert provider, --insecure may need to be used with acme.sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_duckdns_info='DuckDNS.org
|
||||
Site: www.DuckDNS.org
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_duckdns
|
||||
Options:
|
||||
DuckDNS_Token API Token
|
||||
Author: RaidenII
|
||||
'
|
||||
|
||||
DuckDNS_API="https://www.duckdns.org/update"
|
||||
|
||||
|
@ -1,7 +1,13 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#DD_API_User="xxxxx"
|
||||
#DD_API_Key="xxxxxx"
|
||||
# shellcheck disable=SC2034
|
||||
dns_durabledns_info='DurableDNS.com
|
||||
Site: DurableDNS.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_durabledns
|
||||
Options:
|
||||
DD_API_User API User
|
||||
DD_API_Key API Key
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2281
|
||||
'
|
||||
|
||||
_DD_BASE="https://durabledns.com/services/dns"
|
||||
|
||||
@ -104,7 +110,7 @@ _get_root() {
|
||||
i=1
|
||||
p=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
@ -112,7 +118,7 @@ _get_root() {
|
||||
fi
|
||||
|
||||
if _contains "$response" ">$h.</origin>"; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
|
@ -1,10 +1,16 @@
|
||||
#!/usr/bin/env sh
|
||||
#
|
||||
# Dyn.com Domain API
|
||||
#
|
||||
# Author: Gerd Naschenweng
|
||||
# https://github.com/magicdude4eva
|
||||
#
|
||||
# shellcheck disable=SC2034
|
||||
dns_dyn_info='Dyn.com
|
||||
Domains: dynect.net
|
||||
Site: Dyn.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dyn
|
||||
Options:
|
||||
DYN_Customer Customer
|
||||
DYN_Username API Username
|
||||
DYN_Password Secret
|
||||
Author: Gerd Naschenweng <https://github.com/magicdude4eva>
|
||||
'
|
||||
|
||||
# Dyn Managed DNS API
|
||||
# https://help.dyn.com/dns-api-knowledge-base/
|
||||
#
|
||||
@ -20,13 +26,6 @@
|
||||
# ZoneRemoveNode
|
||||
# ZonePublish
|
||||
# --
|
||||
#
|
||||
# Pass credentials before "acme.sh --issue --dns dns_dyn ..."
|
||||
# --
|
||||
# export DYN_Customer="customer"
|
||||
# export DYN_Username="apiuser"
|
||||
# export DYN_Password="secret"
|
||||
# --
|
||||
|
||||
DYN_API="https://api.dynect.net/REST"
|
||||
|
||||
|
@ -1,20 +1,21 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_dynu_info='Dynu.com
|
||||
Site: Dynu.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dynu
|
||||
Options:
|
||||
Dynu_ClientId Client ID
|
||||
Dynu_Secret Secret
|
||||
Issues: github.com/shar0119/acme.sh
|
||||
Author: Dynu Systems Inc
|
||||
'
|
||||
|
||||
#Client ID
|
||||
#Dynu_ClientId="0b71cae7-a099-4f6b-8ddf-94571cdb760d"
|
||||
#
|
||||
#Secret
|
||||
#Dynu_Secret="aCUEY4BDCV45KI8CSIC3sp2LKQ9"
|
||||
#
|
||||
#Token
|
||||
Dynu_Token=""
|
||||
#
|
||||
#Endpoint
|
||||
Dynu_EndPoint="https://api.dynu.com/v2"
|
||||
#
|
||||
#Author: Dynu Systems, Inc.
|
||||
#Report Bugs here: https://github.com/shar0119/acme.sh
|
||||
#
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
@ -125,7 +126,7 @@ _get_root() {
|
||||
i=2
|
||||
p=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
@ -139,7 +140,7 @@ _get_root() {
|
||||
if _contains "$response" "\"domainName\":\"$h\"" >/dev/null; then
|
||||
dnsId=$(printf "%s" "$response" | tr -d "{}" | cut -d , -f 2 | cut -d : -f 2)
|
||||
_domain_name=$h
|
||||
_node=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_node=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||
return 0
|
||||
fi
|
||||
p=$i
|
||||
|
@ -1,16 +1,23 @@
|
||||
#!/usr/bin/env sh
|
||||
#Author StefanAbl
|
||||
#Usage specify a private keyfile to use with dynv6 'export KEY="path/to/keyfile"'
|
||||
#or use the HTTP REST API by by specifying a token 'export DYNV6_TOKEN="value"
|
||||
#if no keyfile is specified, you will be asked if you want to create one in /home/$USER/.ssh/dynv6 and /home/$USER/.ssh/dynv6.pub
|
||||
# shellcheck disable=SC2034
|
||||
dns_dynv6_info='DynV6.com
|
||||
Site: DynV6.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_dynv6
|
||||
Options:
|
||||
DYNV6_TOKEN REST API token. Get from https://DynV6.com/keys
|
||||
OptionsAlt:
|
||||
KEY Path to SSH private key file. E.g. "/root/.ssh/dynv6"
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2702
|
||||
Author: StefanAbl
|
||||
'
|
||||
|
||||
dynv6_api="https://dynv6.com/api/v2"
|
||||
######## Public functions #####################
|
||||
# Please Read this guide first: https://github.com/Neilpang/acme.sh/wiki/DNS-API-Dev-Guide
|
||||
#Usage: dns_dynv6_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_dynv6_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
fulldomain="$(echo "$1" | _lower_case)"
|
||||
txtvalue="$2"
|
||||
_info "Using dynv6 api"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
@ -36,15 +43,14 @@ dns_dynv6_add() {
|
||||
_err "Something went wrong! it does not seem like the record was added successfully"
|
||||
return 1
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
return 1
|
||||
|
||||
}
|
||||
#Usage: fulldomain txtvalue
|
||||
#Remove the txt record after validation.
|
||||
dns_dynv6_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
fulldomain="$(echo "$1" | _lower_case)"
|
||||
txtvalue="$2"
|
||||
_info "Using dynv6 API"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
@ -199,7 +205,7 @@ _get_zone_id() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
zone_id="$(echo "$response" | tr '}' '\n' | grep "$selected" | tr ',' '\n' | grep id | tr -d '"')"
|
||||
zone_id="$(echo "$response" | tr '}' '\n' | grep "$selected" | tr ',' '\n' | grep '"id":' | tr -d '"')"
|
||||
_zone_id="${zone_id#id:}"
|
||||
_debug "zone id: $_zone_id"
|
||||
}
|
||||
|
@ -1,14 +1,17 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_easydns_info='easyDNS.net
|
||||
Site: easyDNS.net
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_easydns
|
||||
Options:
|
||||
EASYDNS_Token API Token
|
||||
EASYDNS_Key API Key
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2647
|
||||
Author: Neilpang, wurzelpanzer <wurzelpanzer@maximolider.net>
|
||||
'
|
||||
|
||||
#######################################################
|
||||
#
|
||||
# easyDNS REST API for acme.sh by Neilpang based on dns_cf.sh
|
||||
#
|
||||
# API Documentation: https://sandbox.rest.easydns.net:3001/
|
||||
#
|
||||
# Author: wurzelpanzer [wurzelpanzer@maximolider.net]
|
||||
# Report Bugs here: https://github.com/acmesh-official/acme.sh/issues/2647
|
||||
#
|
||||
|
||||
#################### Public functions #################
|
||||
|
||||
#EASYDNS_Key="xxxxxxxxxxxxxxxxxxxxxxxx"
|
||||
@ -118,7 +121,7 @@ _get_root() {
|
||||
i=1
|
||||
p=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
@ -130,7 +133,7 @@ _get_root() {
|
||||
fi
|
||||
|
||||
if _contains "$response" "\"status\":200"; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
|
163
dnsapi/dns_edgecenter.sh
Normal file
163
dnsapi/dns_edgecenter.sh
Normal file
@ -0,0 +1,163 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
|
||||
# EdgeCenter DNS API integration for acme.sh
|
||||
# Author: Konstantin Ruchev <konstantin.ruchev@edgecenter.ru>
|
||||
dns_edgecenter_info='edgecenter DNS API
|
||||
Site: https://edgecenter.ru
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_edgecenter
|
||||
Options:
|
||||
EDGECENTER_API_KEY auth APIKey'
|
||||
|
||||
EDGECENTER_API="https://api.edgecenter.ru"
|
||||
DOMAIN_TYPE=
|
||||
DOMAIN_MASTER=
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: dns_edgecenter_add _acme-challenge.www.domain.com "TXT_RECORD_VALUE"
|
||||
dns_edgecenter_add() {
|
||||
fulldomain="$1"
|
||||
txtvalue="$2"
|
||||
|
||||
_info "Using EdgeCenter DNS API"
|
||||
|
||||
if ! _dns_edgecenter_init_check; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "Detecting root zone for $fulldomain"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
subdomain="${fulldomain%."$_zone"}"
|
||||
subdomain=${subdomain%.}
|
||||
|
||||
_debug "Zone: $_zone"
|
||||
_debug "Subdomain: $subdomain"
|
||||
_debug "TXT value: $txtvalue"
|
||||
|
||||
payload='{"resource_records": [ { "content": ["'"$txtvalue"'"] } ], "ttl": 60 }'
|
||||
_dns_edgecenter_http_api_call "post" "dns/v2/zones/$_zone/$subdomain.$_zone/txt" "$payload"
|
||||
|
||||
if _contains "$response" '"error":"rrset is already exists"'; then
|
||||
_debug "RRSet exists, merging values"
|
||||
_dns_edgecenter_http_api_call "get" "dns/v2/zones/$_zone/$subdomain.$_zone/txt"
|
||||
current="$response"
|
||||
newlist=""
|
||||
for v in $(echo "$current" | sed -n 's/.*"content":\["\([^"]*\)"\].*/\1/p'); do
|
||||
newlist="$newlist {\"content\":[\"$v\"]},"
|
||||
done
|
||||
newlist="$newlist{\"content\":[\"$txtvalue\"]}"
|
||||
putdata="{\"resource_records\":[${newlist}]}
|
||||
"
|
||||
_dns_edgecenter_http_api_call "put" "dns/v2/zones/$_zone/$subdomain.$_zone/txt" "$putdata"
|
||||
_info "Updated existing RRSet with new TXT value."
|
||||
return 0
|
||||
fi
|
||||
|
||||
if _contains "$response" '"exception":'; then
|
||||
_err "Record cannot be added."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "TXT record added successfully."
|
||||
return 0
|
||||
}
|
||||
|
||||
#Usage: dns_edgecenter_rm _acme-challenge.www.domain.com "TXT_RECORD_VALUE"
|
||||
dns_edgecenter_rm() {
|
||||
fulldomain="$1"
|
||||
txtvalue="$2"
|
||||
|
||||
_info "Removing TXT record for $fulldomain"
|
||||
|
||||
if ! _dns_edgecenter_init_check; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _get_root "$fulldomain"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
subdomain="${fulldomain%."$_zone"}"
|
||||
subdomain=${subdomain%.}
|
||||
|
||||
_dns_edgecenter_http_api_call "delete" "dns/v2/zones/$_zone/$subdomain.$_zone/txt"
|
||||
|
||||
if [ -z "$response" ]; then
|
||||
_info "TXT record deleted successfully."
|
||||
else
|
||||
_info "TXT record may not have been deleted: $response"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
_dns_edgecenter_init_check() {
|
||||
EDGECENTER_API_KEY="${EDGECENTER_API_KEY:-$(_readaccountconf_mutable EDGECENTER_API_KEY)}"
|
||||
if [ -z "$EDGECENTER_API_KEY" ]; then
|
||||
_err "EDGECENTER_API_KEY was not exported."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf_mutable EDGECENTER_API_KEY "$EDGECENTER_API_KEY"
|
||||
export _H1="Authorization: APIKey $EDGECENTER_API_KEY"
|
||||
|
||||
_dns_edgecenter_http_api_call "get" "dns/v2/clients/me/features"
|
||||
if ! _contains "$response" '"id":'; then
|
||||
_err "Invalid API key."
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
_get_root() {
|
||||
domain="$1"
|
||||
i=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-)
|
||||
if [ -z "$h" ]; then
|
||||
return 1
|
||||
fi
|
||||
_dns_edgecenter_http_api_call "get" "dns/v2/zones/$h"
|
||||
if ! _contains "$response" 'zone is not found'; then
|
||||
_zone="$h"
|
||||
return 0
|
||||
fi
|
||||
i=$((i + 1))
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
_dns_edgecenter_http_api_call() {
|
||||
mtd="$1"
|
||||
endpoint="$2"
|
||||
data="$3"
|
||||
|
||||
export _H1="Authorization: APIKey $EDGECENTER_API_KEY"
|
||||
|
||||
case "$mtd" in
|
||||
get)
|
||||
response="$(_get "$EDGECENTER_API/$endpoint")"
|
||||
;;
|
||||
post)
|
||||
response="$(_post "$data" "$EDGECENTER_API/$endpoint")"
|
||||
;;
|
||||
delete)
|
||||
response="$(_post "" "$EDGECENTER_API/$endpoint" "" "DELETE")"
|
||||
;;
|
||||
put)
|
||||
response="$(_post "$data" "$EDGECENTER_API/$endpoint" "" "PUT")"
|
||||
;;
|
||||
*)
|
||||
_err "Unknown HTTP method $mtd"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
_debug "HTTP $mtd response: $response"
|
||||
return 0
|
||||
}
|
@ -1,4 +1,15 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_edgedns_info='Akamai.com Edge DNS
|
||||
Site: techdocs.Akamai.com/edge-dns/reference/edge-dns-api
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_edgedns
|
||||
Options: Specify individual credentials
|
||||
AKAMAI_HOST Host
|
||||
AKAMAI_ACCESS_TOKEN Access token
|
||||
AKAMAI_CLIENT_TOKEN Client token
|
||||
AKAMAI_CLIENT_SECRET Client secret
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/3157
|
||||
'
|
||||
|
||||
# Akamai Edge DNS v2 API
|
||||
# User must provide Open Edgegrid API credentials to the EdgeDNS installation. The remote user in EdgeDNS must have CRUD access to
|
||||
@ -6,18 +17,10 @@
|
||||
|
||||
# Report bugs to https://control.akamai.com/apps/support-ui/#/contact-support
|
||||
|
||||
# Values to export:
|
||||
# --EITHER--
|
||||
# *** TBD. NOT IMPLEMENTED YET ***
|
||||
# specify Edgegrid credentials file and section
|
||||
# AKAMAI_EDGERC=<full file path>
|
||||
# AKAMAI_EDGERC_SECTION="default"
|
||||
## --OR--
|
||||
# specify indiviual credentials
|
||||
# export AKAMAI_HOST = <host>
|
||||
# export AKAMAI_ACCESS_TOKEN = <access token>
|
||||
# export AKAMAI_CLIENT_TOKEN = <client token>
|
||||
# export AKAMAI_CLIENT_SECRET = <client secret>
|
||||
# Specify Edgegrid credentials file and section.
|
||||
# AKAMAI_EDGERC Edge RC. Full file path
|
||||
# AKAMAI_EDGERC_SECTION Edge RC Section. E.g. "default"
|
||||
|
||||
ACME_EDGEDNS_VERSION="0.1.0"
|
||||
|
||||
|
@ -1,18 +1,14 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#This is the euserv.eu api wrapper for acme.sh
|
||||
#
|
||||
#Author: Michael Brueckner
|
||||
#Report Bugs: https://www.github.com/initit/acme.sh or mbr@initit.de
|
||||
|
||||
#
|
||||
#EUSERV_Username="username"
|
||||
#
|
||||
#EUSERV_Password="password"
|
||||
#
|
||||
# Dependencies:
|
||||
# -------------
|
||||
# - none -
|
||||
# shellcheck disable=SC2034
|
||||
dns_euserv_info='EUserv.com
|
||||
Domains: EUserv.eu
|
||||
Site: EUserv.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_euserv
|
||||
Options:
|
||||
EUSERV_Username Username
|
||||
EUSERV_Password Password
|
||||
Author: Michael Brueckner
|
||||
'
|
||||
|
||||
EUSERV_Api="https://api.euserv.net"
|
||||
|
||||
@ -155,7 +151,7 @@ _get_root() {
|
||||
response="$_euserv_domain_orders"
|
||||
|
||||
while true; do
|
||||
h=$(echo "$domain" | cut -d . -f $i-100)
|
||||
h=$(echo "$domain" | cut -d . -f "$i"-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
@ -163,7 +159,7 @@ _get_root() {
|
||||
fi
|
||||
|
||||
if _contains "$response" "$h"; then
|
||||
_sub_domain=$(echo "$domain" | cut -d . -f 1-$p)
|
||||
_sub_domain=$(echo "$domain" | cut -d . -f 1-"$p")
|
||||
_domain="$h"
|
||||
if ! _euserv_get_domain_id "$_domain"; then
|
||||
_err "invalid domain"
|
||||
|
@ -1,4 +1,12 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_exoscale_info='Exoscale.com
|
||||
Site: Exoscale.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_exoscale
|
||||
Options:
|
||||
EXOSCALE_API_KEY API Key
|
||||
EXOSCALE_SECRET_KEY API Secret key
|
||||
'
|
||||
|
||||
EXOSCALE_API=https://api.exoscale.com/dns/v1
|
||||
|
||||
@ -111,7 +119,7 @@ _get_root() {
|
||||
i=2
|
||||
p=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
@ -122,7 +130,7 @@ _get_root() {
|
||||
_domain_id=$(echo "$response" | tr '{' "\n" | grep "\"name\":\"$h\"" | _egrep_o "\"id\":[^,]+" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||
_domain_token=$(echo "$response" | tr '{' "\n" | grep "\"name\":\"$h\"" | _egrep_o "\"token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||
if [ "$_domain_token" ] && [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
|
@ -1,8 +1,15 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_fornex_info='Fornex.com
|
||||
Site: Fornex.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_fornex
|
||||
Options:
|
||||
FORNEX_API_KEY API Key
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/3998
|
||||
Author: Timur Umarov <inbox@tumarov.com>
|
||||
'
|
||||
|
||||
#Author: Timur Umarov <inbox@tumarov.com>
|
||||
|
||||
FORNEX_API_URL="https://fornex.com/api/dns/v0.1"
|
||||
FORNEX_API_URL="https://fornex.com/api"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
@ -23,12 +30,10 @@ dns_fornex_add() {
|
||||
fi
|
||||
|
||||
_info "Adding record"
|
||||
if _rest POST "$_domain/entry_set/add/" "host=$fulldomain&type=TXT&value=$txtvalue&apikey=$FORNEX_API_KEY"; then
|
||||
if _rest POST "dns/domain/$_domain/entry_set/" "{\"host\" : \"${fulldomain}\" , \"type\" : \"TXT\" , \"value\" : \"${txtvalue}\" , \"ttl\" : null}"; then
|
||||
_debug _response "$response"
|
||||
if _contains "$response" '"ok": true' || _contains "$response" 'Такая запись уже существует.'; then
|
||||
_info "Added, OK"
|
||||
return 0
|
||||
fi
|
||||
_info "Added, OK"
|
||||
return 0
|
||||
fi
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
@ -51,21 +56,21 @@ dns_fornex_rm() {
|
||||
fi
|
||||
|
||||
_debug "Getting txt records"
|
||||
_rest GET "$_domain/entry_set.json?apikey=$FORNEX_API_KEY"
|
||||
_rest GET "dns/domain/$_domain/entry_set?type=TXT&q=$fulldomain"
|
||||
|
||||
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')"
|
||||
_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
|
||||
if ! _rest DELETE "dns/domain/$_domain/entry_set/$_record_id/"; then
|
||||
_err "Delete record error."
|
||||
return 1
|
||||
fi
|
||||
@ -83,18 +88,18 @@ _get_root() {
|
||||
|
||||
i=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
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
|
||||
if ! _rest GET "dns/domain/"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "\"$h\"" >/dev/null; then
|
||||
if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
|
||||
_domain=$h
|
||||
return 0
|
||||
else
|
||||
@ -127,7 +132,9 @@ _rest() {
|
||||
data="$3"
|
||||
_debug "$ep"
|
||||
|
||||
export _H1="Accept: application/json"
|
||||
export _H1="Authorization: Api-Key $FORNEX_API_KEY"
|
||||
export _H2="Content-Type: application/json"
|
||||
export _H3="Accept: application/json"
|
||||
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug data "$data"
|
||||
|
@ -1,14 +1,15 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_freedns_info='FreeDNS
|
||||
Site: FreeDNS.afraid.org
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_freedns
|
||||
Options:
|
||||
FREEDNS_User Username
|
||||
FREEDNS_Password Password
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2305
|
||||
Author: David Kerr <https://github.com/dkerr64>
|
||||
'
|
||||
|
||||
#This file name is "dns_freedns.sh"
|
||||
#So, here must be a method dns_freedns_add()
|
||||
#Which will be called by acme.sh to add the txt record to your api system.
|
||||
#returns 0 means success, otherwise error.
|
||||
#
|
||||
#Author: David Kerr
|
||||
#Report Bugs here: https://github.com/dkerr64/acme.sh
|
||||
#or here... https://github.com/acmesh-official/acme.sh/issues/2305
|
||||
#
|
||||
######## Public functions #####################
|
||||
|
||||
# Export FreeDNS userid and password in following variables...
|
||||
|
105
dnsapi/dns_freemyip.sh
Normal file
105
dnsapi/dns_freemyip.sh
Normal file
@ -0,0 +1,105 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_freemyip_info='FreeMyIP.com
|
||||
Site: freemyip.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_freemyip
|
||||
Options:
|
||||
FREEMYIP_Token API Token
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/{XXXX}
|
||||
Author: Recolic Keghart <root@recolic.net>, @Giova96
|
||||
'
|
||||
|
||||
FREEMYIP_DNS_API="https://freemyip.com/update?"
|
||||
|
||||
################ Public functions ################
|
||||
|
||||
#Usage: dns_freemyip_add fulldomain txtvalue
|
||||
dns_freemyip_add() {
|
||||
fulldomain="$1"
|
||||
txtvalue="$2"
|
||||
|
||||
_info "Add TXT record $txtvalue for $fulldomain using freemyip.com api"
|
||||
|
||||
FREEMYIP_Token="${FREEMYIP_Token:-$(_readaccountconf_mutable FREEMYIP_Token)}"
|
||||
if [ -z "$FREEMYIP_Token" ]; then
|
||||
FREEMYIP_Token=""
|
||||
_err "You don't specify FREEMYIP_Token yet."
|
||||
_err "Please specify your token and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the credentials to the account conf file.
|
||||
_saveaccountconf_mutable FREEMYIP_Token "$FREEMYIP_Token"
|
||||
|
||||
if _is_root_domain_published "$fulldomain"; then
|
||||
_err "freemyip API don't allow you to set multiple TXT record for the same subdomain!"
|
||||
_err "You must apply certificate for only one domain at a time!"
|
||||
_err "===="
|
||||
_err "For example, aaa.yourdomain.freemyip.com and bbb.yourdomain.freemyip.com and yourdomain.freemyip.com ALWAYS share the same TXT record. They will overwrite each other if you apply multiple domain at the same time."
|
||||
_debug "If you are testing this workflow in github pipeline or acmetest, please set TEST_DNS_NO_SUBDOMAIN=1 and TEST_DNS_NO_WILDCARD=1"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# txtvalue must be url-encoded. But it's not necessary for acme txt value.
|
||||
_freemyip_get_until_ok "${FREEMYIP_DNS_API}token=$FREEMYIP_Token&domain=$fulldomain&txt=$txtvalue" 2>&1
|
||||
return $?
|
||||
}
|
||||
|
||||
#Usage: dns_freemyip_rm fulldomain txtvalue
|
||||
dns_freemyip_rm() {
|
||||
fulldomain="$1"
|
||||
txtvalue="$2"
|
||||
|
||||
_info "Delete TXT record $txtvalue for $fulldomain using freemyip.com api"
|
||||
|
||||
FREEMYIP_Token="${FREEMYIP_Token:-$(_readaccountconf_mutable FREEMYIP_Token)}"
|
||||
if [ -z "$FREEMYIP_Token" ]; then
|
||||
FREEMYIP_Token=""
|
||||
_err "You don't specify FREEMYIP_Token yet."
|
||||
_err "Please specify your token and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the credentials to the account conf file.
|
||||
_saveaccountconf_mutable FREEMYIP_Token "$FREEMYIP_Token"
|
||||
|
||||
# Leave the TXT record as empty or "null" to delete the record.
|
||||
_freemyip_get_until_ok "${FREEMYIP_DNS_API}token=$FREEMYIP_Token&domain=$fulldomain&txt=" 2>&1
|
||||
return $?
|
||||
}
|
||||
|
||||
################ Private functions below ################
|
||||
_get_root() {
|
||||
_fmi_d="$1"
|
||||
|
||||
echo "$_fmi_d" | rev | cut -d '.' -f 1-3 | rev
|
||||
}
|
||||
|
||||
# There is random failure while calling freemyip API too fast. This function automatically retry until success.
|
||||
_freemyip_get_until_ok() {
|
||||
_fmi_url="$1"
|
||||
for i in $(seq 1 8); do
|
||||
_debug "HTTP GET freemyip.com API '$_fmi_url', retry $i/8..."
|
||||
_get "$_fmi_url" | tee /dev/fd/2 | grep OK && return 0
|
||||
_sleep 1 # DO NOT send the request too fast
|
||||
done
|
||||
_err "Failed to request freemyip API: $_fmi_url . Server does not say 'OK'"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Verify in public dns if domain is already there.
|
||||
_is_root_domain_published() {
|
||||
_fmi_d="$1"
|
||||
_webroot="$(_get_root "$_fmi_d")"
|
||||
|
||||
_info "Verifying '""$_fmi_d""' freemyip webroot (""$_webroot"") is not published yet"
|
||||
for i in $(seq 1 3); do
|
||||
_debug "'$_webroot' ns lookup, retry $i/3..."
|
||||
if [ "$(_ns_lookup "$_fmi_d" TXT)" ]; then
|
||||
_debug "'$_webroot' already has a TXT record published!"
|
||||
return 0
|
||||
fi
|
||||
_sleep 10 # Give it some time to propagate the TXT record
|
||||
done
|
||||
return 1
|
||||
}
|
@ -1,31 +1,42 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_gandi_livedns_info='Gandi.net LiveDNS
|
||||
Site: Gandi.net/domain/dns
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_gandi_livedns
|
||||
Options:
|
||||
GANDI_LIVEDNS_KEY API Key
|
||||
Issues: github.com/fcrozat/acme.sh
|
||||
Author: Frédéric Crozat <fcrozat@suse.com>, Dominik Röttsches <drott@google.com>
|
||||
'
|
||||
|
||||
# Gandi LiveDNS v5 API
|
||||
# https://doc.livedns.gandi.net/
|
||||
# https://api.gandi.net/docs/livedns/
|
||||
# https://api.gandi.net/docs/authentication/ for token + apikey (deprecated) authentication
|
||||
# currently under beta
|
||||
#
|
||||
# Requires GANDI API KEY set in GANDI_LIVEDNS_KEY set as environment variable
|
||||
#
|
||||
#Author: Frédéric Crozat <fcrozat@suse.com>
|
||||
# Dominik Röttsches <drott@google.com>
|
||||
#Report Bugs here: https://github.com/fcrozat/acme.sh
|
||||
#
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
GANDI_LIVEDNS_API="https://dns.api.gandi.net/api/v5"
|
||||
GANDI_LIVEDNS_API="https://api.gandi.net/v5/livedns"
|
||||
|
||||
#Usage: dns_gandi_livedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_gandi_livedns_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
if [ -z "$GANDI_LIVEDNS_KEY" ]; then
|
||||
_err "No API key specified for Gandi LiveDNS."
|
||||
_err "Create your key and export it as GANDI_LIVEDNS_KEY"
|
||||
if [ -z "$GANDI_LIVEDNS_KEY" ] && [ -z "$GANDI_LIVEDNS_TOKEN" ]; then
|
||||
_err "No Token or API key (deprecated) specified for Gandi LiveDNS."
|
||||
_err "Create your token or key and export it as GANDI_LIVEDNS_KEY or GANDI_LIVEDNS_TOKEN respectively"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf GANDI_LIVEDNS_KEY "$GANDI_LIVEDNS_KEY"
|
||||
# Keep only one secret in configuration
|
||||
if [ -n "$GANDI_LIVEDNS_TOKEN" ]; then
|
||||
_saveaccountconf GANDI_LIVEDNS_TOKEN "$GANDI_LIVEDNS_TOKEN"
|
||||
_clearaccountconf GANDI_LIVEDNS_KEY
|
||||
elif [ -n "$GANDI_LIVEDNS_KEY" ]; then
|
||||
_saveaccountconf GANDI_LIVEDNS_KEY "$GANDI_LIVEDNS_KEY"
|
||||
_clearaccountconf GANDI_LIVEDNS_TOKEN
|
||||
fi
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
@ -70,7 +81,7 @@ dns_gandi_livedns_rm() {
|
||||
_gandi_livedns_rest PUT \
|
||||
"domains/$_domain/records/$_sub_domain/TXT" \
|
||||
"{\"rrset_ttl\": 300, \"rrset_values\": $_new_rrset_values}" &&
|
||||
_contains "$response" '{"message": "DNS Record Created"}' &&
|
||||
_contains "$response" '{"message":"DNS Record Created"}' &&
|
||||
_info "Removing record $(__green "success")"
|
||||
}
|
||||
|
||||
@ -84,7 +95,7 @@ _get_root() {
|
||||
i=2
|
||||
p=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
@ -101,7 +112,7 @@ _get_root() {
|
||||
elif _contains "$response" '"code": 404'; then
|
||||
_debug "$h not found"
|
||||
else
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||
_domain="$h"
|
||||
return 0
|
||||
fi
|
||||
@ -126,7 +137,7 @@ _dns_gandi_append_record() {
|
||||
_debug new_rrset_values "$_rrset_values"
|
||||
_gandi_livedns_rest PUT "domains/$_domain/records/$sub_domain/TXT" \
|
||||
"{\"rrset_ttl\": 300, \"rrset_values\": $_rrset_values}" &&
|
||||
_contains "$response" '{"message": "DNS Record Created"}' &&
|
||||
_contains "$response" '{"message":"DNS Record Created"}' &&
|
||||
_info "Adding record $(__green "success")"
|
||||
}
|
||||
|
||||
@ -136,11 +147,11 @@ _dns_gandi_existing_rrset_values() {
|
||||
if ! _gandi_livedns_rest GET "domains/$domain/records/$sub_domain"; then
|
||||
return 1
|
||||
fi
|
||||
if ! _contains "$response" '"rrset_type": "TXT"'; then
|
||||
if ! _contains "$response" '"rrset_type":"TXT"'; then
|
||||
_debug "Does not have a _acme-challenge TXT record yet."
|
||||
return 1
|
||||
fi
|
||||
if _contains "$response" '"rrset_values": \[\]'; then
|
||||
if _contains "$response" '"rrset_values":\[\]'; then
|
||||
_debug "Empty rrset_values for TXT record, no previous TXT record."
|
||||
return 1
|
||||
fi
|
||||
@ -157,7 +168,12 @@ _gandi_livedns_rest() {
|
||||
_debug "$ep"
|
||||
|
||||
export _H1="Content-Type: application/json"
|
||||
export _H2="X-Api-Key: $GANDI_LIVEDNS_KEY"
|
||||
|
||||
if [ -n "$GANDI_LIVEDNS_TOKEN" ]; then
|
||||
export _H2="Authorization: Bearer $GANDI_LIVEDNS_TOKEN"
|
||||
else
|
||||
export _H2="Authorization: Apikey $GANDI_LIVEDNS_KEY"
|
||||
fi
|
||||
|
||||
if [ "$m" = "GET" ]; then
|
||||
response="$(_get "$GANDI_LIVEDNS_API/$ep")"
|
||||
|
@ -1,6 +1,12 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Author: Janos Lenart <janos@lenart.io>
|
||||
# shellcheck disable=SC2034
|
||||
dns_gcloud_info='Google Cloud DNS
|
||||
Site: Cloud.Google.com/dns
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_gcloud
|
||||
Options:
|
||||
CLOUDSDK_ACTIVE_CONFIG_NAME Active config name. E.g. "default"
|
||||
Author: Janos Lenart <janos@lenart.io>
|
||||
'
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
@ -42,7 +48,7 @@ dns_gcloud_rm() {
|
||||
echo "$rrdatas" | grep -F -v -- "\"$txtvalue\"" | _dns_gcloud_add_rrs || return $?
|
||||
_dns_gcloud_execute_tr || return $?
|
||||
|
||||
_info "$fulldomain record added"
|
||||
_info "$fulldomain record removed"
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
@ -1,11 +1,15 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_gcore_info='Gcore.com
|
||||
Site: Gcore.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_gcore
|
||||
Options:
|
||||
GCORE_Key API Key
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/4460
|
||||
'
|
||||
|
||||
#
|
||||
#GCORE_Key='773$7b7adaf2a2b32bfb1b83787b4ff32a67eb178e3ada1af733e47b1411f2461f7f4fa7ed7138e2772a46124377bad7384b3bb8d87748f87b3f23db4b8bbe41b2bb'
|
||||
#
|
||||
|
||||
GCORE_Api="https://api.gcorelabs.com/dns/v2"
|
||||
GCORE_Doc="https://apidocs.gcore.com/dns"
|
||||
GCORE_Api="https://api.gcore.com/dns/v2"
|
||||
GCORE_Doc="https://api.gcore.com/docs/dns"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
@ -24,7 +28,7 @@ dns_gcore_add() {
|
||||
fi
|
||||
|
||||
#save the api key to the account conf file.
|
||||
_saveaccountconf_mutable GCORE_Key "$GCORE_Key"
|
||||
_saveaccountconf_mutable GCORE_Key "$GCORE_Key" "base64"
|
||||
|
||||
_debug "First detect the zone name"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
@ -134,7 +138,7 @@ _get_root() {
|
||||
p=1
|
||||
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
@ -148,7 +152,7 @@ _get_root() {
|
||||
if _contains "$response" "\"name\":\"$h\""; then
|
||||
_zone_name=$h
|
||||
if [ "$_zone_name" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
|
@ -1,12 +1,12 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#Godaddy domain api
|
||||
# Get API key and secret from https://developer.godaddy.com/
|
||||
#
|
||||
# GD_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
# GD_Secret="asdfsdfsfsdfsdfdfsdf"
|
||||
#
|
||||
# Ex.: acme.sh --issue --staging --dns dns_gd -d "*.s.example.com" -d "s.example.com"
|
||||
# shellcheck disable=SC2034
|
||||
dns_gd_info='GoDaddy.com
|
||||
Site: GoDaddy.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_gd
|
||||
Options:
|
||||
GD_Key API Key
|
||||
GD_Secret API Secret
|
||||
'
|
||||
|
||||
GD_Api="https://api.godaddy.com/v1"
|
||||
|
||||
@ -148,7 +148,7 @@ _get_root() {
|
||||
i=2
|
||||
p=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
@ -161,7 +161,7 @@ _get_root() {
|
||||
if _contains "$response" '"code":"NOT_FOUND"'; then
|
||||
_debug "$h not found"
|
||||
else
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||
_domain="$h"
|
||||
return 0
|
||||
fi
|
||||
|
@ -1,12 +1,12 @@
|
||||
#!/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)
|
||||
# shellcheck disable=SC2034
|
||||
dns_geoscaling_info='GeoScaling.com
|
||||
Site: GeoScaling.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_geoscaling
|
||||
Options:
|
||||
GEOSCALING_Username Username. This is usually NOT an email address
|
||||
GEOSCALING_Password Password
|
||||
'
|
||||
|
||||
#-- dns_geoscaling_add() - Add TXT record --------------------------------------
|
||||
# Usage: dns_geoscaling_add _acme-challenge.subdomain.domain.com "XyZ123..."
|
||||
@ -202,7 +202,7 @@ find_zone() {
|
||||
# Walk through all possible zone names
|
||||
strip_counter=1
|
||||
while true; do
|
||||
attempted_zone=$(echo "${domain}" | cut -d . -f ${strip_counter}-)
|
||||
attempted_zone=$(echo "${domain}" | cut -d . -f "${strip_counter}"-)
|
||||
|
||||
# All possible zone names have been tried
|
||||
if [ -z "${attempted_zone}" ]; then
|
||||
|
@ -1,10 +1,15 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_googledomains_info='Google Domains
|
||||
Site: Domains.Google.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_googledomains
|
||||
Options:
|
||||
GOOGLEDOMAINS_ACCESS_TOKEN API Access Token
|
||||
GOOGLEDOMAINS_ZONE Zone
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/4545
|
||||
Author: Alex Leigh <leigh@alexleigh.me>
|
||||
'
|
||||
|
||||
# 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 ########
|
||||
@ -127,7 +132,7 @@ _dns_googledomains_get_zone() {
|
||||
|
||||
i=2
|
||||
while true; do
|
||||
curr=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
curr=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
_debug curr "$curr"
|
||||
|
||||
if [ -z "$curr" ]; then
|
||||
|
@ -1,15 +1,14 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
########################################################################
|
||||
# Hurricane Electric hook script for acme.sh
|
||||
#
|
||||
# Environment variables:
|
||||
#
|
||||
# - $HE_Username (your dns.he.net username)
|
||||
# - $HE_Password (your dns.he.net password)
|
||||
#
|
||||
# Author: Ondrej Simek <me@ondrejsimek.com>
|
||||
# Git repo: https://github.com/angel333/acme.sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_he_info='Hurricane Electric HE.net
|
||||
Site: dns.he.net
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_he
|
||||
Options:
|
||||
HE_Username Username
|
||||
HE_Password Password
|
||||
Issues: github.com/angel333/acme.sh/issues/
|
||||
Author: Ondrej Simek <me@ondrejsimek.com>
|
||||
'
|
||||
|
||||
#-- dns_he_add() - Add TXT record --------------------------------------
|
||||
# Usage: dns_he_add _acme-challenge.subdomain.domain.com "XyZ123..."
|
||||
@ -144,7 +143,7 @@ _find_zone() {
|
||||
# Walk through all possible zone names
|
||||
_strip_counter=1
|
||||
while true; do
|
||||
_attempted_zone=$(echo "$_domain" | cut -d . -f ${_strip_counter}-)
|
||||
_attempted_zone=$(echo "$_domain" | cut -d . -f "${_strip_counter}"-)
|
||||
|
||||
# All possible zone names have been tried
|
||||
if [ -z "$_attempted_zone" ]; then
|
||||
|
44
dnsapi/dns_he_ddns.sh
Normal file
44
dnsapi/dns_he_ddns.sh
Normal file
@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_he_ddns_info='Hurricane Electric HE.net DDNS
|
||||
Site: dns.he.net
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_he_ddns
|
||||
Options:
|
||||
HE_DDNS_KEY The DDNS key
|
||||
Author: Markku Leiniö
|
||||
'
|
||||
|
||||
HE_DDNS_URL="https://dyn.dns.he.net/nic/update"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: dns_he_ddns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_he_ddns_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
HE_DDNS_KEY="${HE_DDNS_KEY:-$(_readaccountconf_mutable HE_DDNS_KEY)}"
|
||||
if [ -z "$HE_DDNS_KEY" ]; then
|
||||
HE_DDNS_KEY=""
|
||||
_err "You didn't specify a DDNS key for accessing the TXT record in HE API."
|
||||
return 1
|
||||
fi
|
||||
#Save the DDNS key to the account conf file.
|
||||
_saveaccountconf_mutable HE_DDNS_KEY "$HE_DDNS_KEY"
|
||||
|
||||
_info "Using Hurricane Electric DDNS API"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
response="$(_post "hostname=$fulldomain&password=$HE_DDNS_KEY&txt=$txtvalue" "$HE_DDNS_URL")"
|
||||
_info "Response: $response"
|
||||
_contains "$response" "good" && return 0 || return 1
|
||||
}
|
||||
|
||||
# dns_he_ddns_rm() is not doing anything because the API call always updates the
|
||||
# contents of the existing record (that the API key gives access to).
|
||||
|
||||
dns_he_ddns_rm() {
|
||||
fulldomain=$1
|
||||
_debug "Delete TXT record called for '${fulldomain}', not doing anything."
|
||||
return 0
|
||||
}
|
18
dnsapi/dns_hetzner.sh
Normal file → Executable file
18
dnsapi/dns_hetzner.sh
Normal file → Executable file
@ -1,8 +1,12 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
#HETZNER_Token="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
#
|
||||
# shellcheck disable=SC2034
|
||||
dns_hetzner_info='Hetzner.com
|
||||
Site: Hetzner.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_hetzner
|
||||
Options:
|
||||
HETZNER_Token API Token
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2943
|
||||
'
|
||||
|
||||
HETZNER_Api="https://dns.hetzner.com/api/v1"
|
||||
|
||||
@ -177,7 +181,7 @@ _get_root() {
|
||||
|
||||
_debug "Trying to get zone id by domain name for '$domain_without_acme'."
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
@ -189,7 +193,7 @@ _get_root() {
|
||||
if _contains "$response" "\"name\":\"$h\"" || _contains "$response" '"total_entries":1'; then
|
||||
_domain_id=$(echo "$response" | _egrep_o "\[.\"id\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||
if [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||
_domain=$h
|
||||
HETZNER_Zone_ID=$_domain_id
|
||||
_savedomainconf "$domain_param_name" "$HETZNER_Zone_ID"
|
||||
@ -208,7 +212,7 @@ _get_root() {
|
||||
_response_has_error() {
|
||||
unset _response_error
|
||||
|
||||
err_part="$(echo "$response" | _egrep_o '"error":{[^}]*}')"
|
||||
err_part="$(echo "$response" | _egrep_o '"error":\{[^\}]*\}')"
|
||||
|
||||
if [ -n "$err_part" ]; then
|
||||
err_code=$(echo "$err_part" | _egrep_o '"code":[0-9]+' | cut -d : -f 2)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user