mirror of
https://github.com/acmesh-official/acme.sh
synced 2025-12-02 23:31:22 +08:00
Compare commits
974 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8fcecd59a0 | ||
|
|
f5ee618986 | ||
|
|
f2958818c8 | ||
|
|
20f604948f | ||
|
|
f72a4f966d | ||
|
|
ae25931b37 | ||
|
|
84fe6654cc | ||
|
|
64908e0080 | ||
|
|
d4e1899747 | ||
|
|
5b1e849bde | ||
|
|
fba6de76b1 | ||
|
|
8419b42e83 | ||
|
|
5f38c15b1f | ||
|
|
c3b72baa8e | ||
|
|
16d0416f22 | ||
|
|
b9aa4f4478 | ||
|
|
8d3ad3a8c1 | ||
|
|
5a689ce897 | ||
|
|
35e22703af | ||
|
|
41a2d0e06c | ||
|
|
4d95e35c06 | ||
|
|
4e553f34ba | ||
|
|
b910726c43 | ||
|
|
64e3cab6ab | ||
|
|
f3196396a2 | ||
|
|
148336929d | ||
|
|
2f3ec3a77f | ||
|
|
8d7a487013 | ||
|
|
622464ff5e | ||
|
|
b45a44e405 | ||
|
|
a196958bd6 | ||
|
|
f101418658 | ||
|
|
aa05a1e81d | ||
|
|
384bc62f25 | ||
|
|
46e62f1a9a | ||
|
|
c5c2014081 | ||
|
|
c668c603cc | ||
|
|
8f3b7c179e | ||
|
|
ea18c47011 | ||
|
|
ced7110a78 | ||
|
|
92f13eb8bf | ||
|
|
1312ef7e50 | ||
|
|
e992979113 | ||
|
|
d317b49940 | ||
|
|
6be53468c5 | ||
|
|
046094bdcb | ||
|
|
1064c270d9 | ||
|
|
2447fccf1e | ||
|
|
c43c711f72 | ||
|
|
f354e6de69 | ||
|
|
12615c46f8 | ||
|
|
b335840f97 | ||
|
|
c5efec678e | ||
|
|
83cb89e4f7 | ||
|
|
6bdf689d0f | ||
|
|
e164362069 | ||
|
|
72e3f33f28 | ||
|
|
ccfd907914 | ||
|
|
5a44e63cad | ||
|
|
d96cca3822 | ||
|
|
06580bf0e4 | ||
|
|
b21bd64764 | ||
|
|
6b97dc6734 | ||
|
|
4e3f328a02 | ||
|
|
8380ca2fdd | ||
|
|
ec678bc6d2 | ||
|
|
2b5e2d4760 | ||
|
|
89abad7980 | ||
|
|
d84da5bdbf | ||
|
|
5cc1d9521c | ||
|
|
a199fc6113 | ||
|
|
655e34b166 | ||
|
|
5ea3a02d6a | ||
|
|
15c68c9594 | ||
|
|
08438608d1 | ||
|
|
2da94e0fdf | ||
|
|
63165764dc | ||
|
|
103810ce20 | ||
|
|
f59356b96b | ||
|
|
4a8511f680 | ||
|
|
cd6698c688 | ||
|
|
c7ca9d7e36 | ||
|
|
d70b759cb9 | ||
|
|
ae3dda0f8f | ||
|
|
e229ba5945 | ||
|
|
dcc50093bb | ||
|
|
0831690f79 | ||
|
|
98ef51514f | ||
|
|
ac9993394c | ||
|
|
849c3fd9c9 | ||
|
|
da58fcbfce | ||
|
|
fa3cd9736f | ||
|
|
a0c5d17539 | ||
|
|
224cd04673 | ||
|
|
52243d0870 | ||
|
|
d519873fa4 | ||
|
|
a76dcd4ba1 | ||
|
|
2d07185300 | ||
|
|
518e1df257 | ||
|
|
e0def66959 | ||
|
|
772d970074 | ||
|
|
ba7d85145a | ||
|
|
fb73dceab0 | ||
|
|
13fd83e0ba | ||
|
|
719ba75fcc | ||
|
|
13ab98440c | ||
|
|
1752004301 | ||
|
|
536a5f7cff | ||
|
|
a69aece23a | ||
|
|
77d3815baa | ||
|
|
e225e17386 | ||
|
|
3290208749 | ||
|
|
3106187aac | ||
|
|
eae490b5b1 | ||
|
|
bcce77508a | ||
|
|
e9bdf02cfc | ||
|
|
77f659c9b9 | ||
|
|
c66e157a14 | ||
|
|
2c927277e2 | ||
|
|
29fe1c86da | ||
|
|
1ae9c48370 | ||
|
|
078a8b40e9 | ||
|
|
9daeae1695 | ||
|
|
014e016058 | ||
|
|
f41f93af3a | ||
|
|
51539521b1 | ||
|
|
522dec34a5 | ||
|
|
ea6d76cce6 | ||
|
|
7c7d61f61e | ||
|
|
184dde92a2 | ||
|
|
7e43c794fd | ||
|
|
c7285967d6 | ||
|
|
41f4baadb9 | ||
|
|
20082ec9fb | ||
|
|
8dae8c52c0 | ||
|
|
068076c0d5 | ||
|
|
c0ae44a41b | ||
|
|
593e8e1f63 | ||
|
|
707cf35f0a | ||
|
|
30f11d0e16 | ||
|
|
53d6ab6c23 | ||
|
|
280e44304a | ||
|
|
79fac4466e | ||
|
|
0e9f09e582 | ||
|
|
25d0fdf8ff | ||
|
|
1d089d4541 | ||
|
|
1c78663378 | ||
|
|
7666022840 | ||
|
|
946c8b498a | ||
|
|
406ca66c8d | ||
|
|
ed971df93a | ||
|
|
74c054b2a5 | ||
|
|
017a10189c | ||
|
|
f1c361855e | ||
|
|
3d72df4666 | ||
|
|
6f732a9957 | ||
|
|
447bf77dfe | ||
|
|
6621ef6a0b | ||
|
|
e327c8758e | ||
|
|
8a08de5691 | ||
|
|
3d7375be8b | ||
|
|
da754e9a71 | ||
|
|
cc9ec806b2 | ||
|
|
72cf037c0d | ||
|
|
8ae08b29e4 | ||
|
|
4967fa020f | ||
|
|
54f2640ef2 | ||
|
|
56246592c7 | ||
|
|
1ff5d71e12 | ||
|
|
67c42c5911 | ||
|
|
d0b514890a | ||
|
|
c0285fbc15 | ||
|
|
a438c841e1 | ||
|
|
19d7c2b336 | ||
|
|
afb6c70909 | ||
|
|
d9af496b13 | ||
|
|
a55cf40b1b | ||
|
|
b19008d1b8 | ||
|
|
6f88c81616 | ||
|
|
43cb230f19 | ||
|
|
fd6a59202d | ||
|
|
e353f66eaa | ||
|
|
9293bcfb1c | ||
|
|
d154118600 | ||
|
|
c2273d2c8e | ||
|
|
495ba01d8e | ||
|
|
f627a02886 | ||
|
|
5f9daa6640 | ||
|
|
9edda556de | ||
|
|
3891a52aeb | ||
|
|
1e5e3353f3 | ||
|
|
7aa4b8247c | ||
|
|
37339ddafc | ||
|
|
dcb51683c5 | ||
|
|
74a4a788b1 | ||
|
|
7909273a21 | ||
|
|
130e8dbd40 | ||
|
|
40e2ebed95 | ||
|
|
bf9b33acec | ||
|
|
7710a33b6c | ||
|
|
af3ea2d4fd | ||
|
|
52a3255936 | ||
|
|
5ab9ca1c0d | ||
|
|
461f602992 | ||
|
|
46180435cc | ||
|
|
7f2699c6da | ||
|
|
aede5c486b | ||
|
|
fb2407386f | ||
|
|
aa59c46c4c | ||
|
|
07afc4953a | ||
|
|
c5557fc488 | ||
|
|
8c14150536 | ||
|
|
c127903127 | ||
|
|
0881cf1379 | ||
|
|
d0a16b0ec0 | ||
|
|
290beb90a7 | ||
|
|
0a4ef17135 | ||
|
|
e0c32ce700 | ||
|
|
e65144a105 | ||
|
|
ae40445dba | ||
|
|
25a8240d12 | ||
|
|
1a4a180e8c | ||
|
|
aea10a3b93 | ||
|
|
f855862ade | ||
|
|
91d37c7875 | ||
|
|
5707b93110 | ||
|
|
81b2d0732f | ||
|
|
ec0538d251 | ||
|
|
eb0c629fad | ||
|
|
509d3f6d30 | ||
|
|
c576af7c6f | ||
|
|
f3682f0e8e | ||
|
|
1c58913eeb | ||
|
|
cfbc294832 | ||
|
|
64ad8b1dac | ||
|
|
fb079f9e50 | ||
|
|
39b09f8f87 | ||
|
|
53d26e5c5c | ||
|
|
e21f3e6c73 | ||
|
|
edd46eb3d1 | ||
|
|
e71238571a | ||
|
|
2867ec509e | ||
|
|
d853a9ebbe | ||
|
|
e0d2fa98f3 | ||
|
|
cc90f83463 | ||
|
|
9ea1238e1b | ||
|
|
1530abbd1a | ||
|
|
3bfcd18a03 | ||
|
|
6b7db22981 | ||
|
|
8adb8a6986 | ||
|
|
37e3e2f9c2 | ||
|
|
3c7be32ef5 | ||
|
|
051775b9b4 | ||
|
|
e0d5b91388 | ||
|
|
4dd2027428 | ||
|
|
42ab98b830 | ||
|
|
2b2bce6457 | ||
|
|
69ee816541 | ||
|
|
2cbf3f7e15 | ||
|
|
923eece3f5 | ||
|
|
d4fb313ff0 | ||
|
|
7dce465c06 | ||
|
|
5a30f5c00e | ||
|
|
fd406af962 | ||
|
|
9e5ae30372 | ||
|
|
0fe3538331 | ||
|
|
b0f5ad75ae | ||
|
|
a290f63a15 | ||
|
|
d078ce794e | ||
|
|
06f51a5c34 | ||
|
|
db96778064 | ||
|
|
d8918ea156 | ||
|
|
3503474bb8 | ||
|
|
eb1606b086 | ||
|
|
1330a092fa | ||
|
|
d3c74cfb45 | ||
|
|
d044545520 | ||
|
|
d1cdc1c6a0 | ||
|
|
dc8d91ea39 | ||
|
|
ae5a6d330d | ||
|
|
fe0bee21b0 | ||
|
|
c090c19bfe | ||
|
|
8fbec785e8 | ||
|
|
06fb3d9476 | ||
|
|
fe3e8a7bb6 | ||
|
|
ce2ff25edd | ||
|
|
65a1b892e3 | ||
|
|
e272fde95e | ||
|
|
d48bff0e20 | ||
|
|
6e61c34f0f | ||
|
|
2d9506eb54 | ||
|
|
b1988c7b67 | ||
|
|
fb5d72c29b | ||
|
|
ac148ce0e9 | ||
|
|
016dca654e | ||
|
|
6502bdecbe | ||
|
|
91a739af6e | ||
|
|
e232565971 | ||
|
|
472488ebe8 | ||
|
|
8de3698b23 | ||
|
|
a694b46914 | ||
|
|
c384ed960c | ||
|
|
2386d2e299 | ||
|
|
cc7e1a72c1 | ||
|
|
5cc0fa7c98 | ||
|
|
4ce848ab51 | ||
|
|
2e34e11b02 | ||
|
|
8eda5f36fb | ||
|
|
3dbe5d872b | ||
|
|
96a95ba9fe | ||
|
|
f594ed659e | ||
|
|
5c4bfbbd95 | ||
|
|
8733635638 | ||
|
|
928aa74e89 | ||
|
|
8fdfe673e8 | ||
|
|
494a6e6090 | ||
|
|
89bb7e6b0e | ||
|
|
52cfb9a041 | ||
|
|
3817ddef41 | ||
|
|
0f494c9dd6 | ||
|
|
3ff97ecf45 | ||
|
|
a10c0b516b | ||
|
|
5eb1469dbf | ||
|
|
9a90fe3794 | ||
|
|
1917c4b04a | ||
|
|
2b01d4a203 | ||
|
|
c5100219d1 | ||
|
|
a730a08161 | ||
|
|
17f5e557ed | ||
|
|
c33e5bc40f | ||
|
|
06d1a98ad2 | ||
|
|
afe6f4030e | ||
|
|
6e49c4ffe0 | ||
|
|
28d9f00610 | ||
|
|
8f688e5e13 | ||
|
|
5a182eddbf | ||
|
|
4b615cb3a9 | ||
|
|
b36247a091 | ||
|
|
6e77756d6a | ||
|
|
585c0c3818 | ||
|
|
6ff75f9a9f | ||
|
|
906ef43c00 | ||
|
|
4528957235 | ||
|
|
9d448a42a7 | ||
|
|
979e10f9d5 | ||
|
|
31f65b89bb | ||
|
|
86639dbc02 | ||
|
|
bf8c33703c | ||
|
|
ffe7ef4764 | ||
|
|
30dae70e2b | ||
|
|
557a747d55 | ||
|
|
fe273b3829 | ||
|
|
2439bb30e8 | ||
|
|
e48b6bd22d | ||
|
|
1de9ffacb0 | ||
|
|
b7c3e6099c | ||
|
|
d8163e9835 | ||
|
|
12b1916599 | ||
|
|
9d8cdb5976 | ||
|
|
29a7c1938a | ||
|
|
8636d3139e | ||
|
|
987571ce91 | ||
|
|
aa479948f9 | ||
|
|
fa3cee9d58 | ||
|
|
0021fb8a33 | ||
|
|
c8c727e6c6 | ||
|
|
b8494ab3cc | ||
|
|
2eda03f5de | ||
|
|
3a38358946 | ||
|
|
e7fc697e57 | ||
|
|
6c9845b9f3 | ||
|
|
9e146a8a5a | ||
|
|
433d9bfb02 | ||
|
|
94917e315e | ||
|
|
ced6852735 | ||
|
|
8dc55f417d | ||
|
|
3d338bba3c | ||
|
|
631398f700 | ||
|
|
7984d8cdfb | ||
|
|
783a6110ef | ||
|
|
5d4d53c3a1 | ||
|
|
3014955ece | ||
|
|
0481f20c6b | ||
|
|
76309601eb | ||
|
|
84dd864886 | ||
|
|
7924e01b15 | ||
|
|
dadc70630b | ||
|
|
effc37a702 | ||
|
|
deac3fc918 | ||
|
|
e6dea4c92c | ||
|
|
075e992fa0 | ||
|
|
565ca81b30 | ||
|
|
58c4eaaf86 | ||
|
|
77e8008752 | ||
|
|
2ba10fcbc7 | ||
|
|
4956a58026 | ||
|
|
92332fc385 | ||
|
|
9366f4b40e | ||
|
|
f49e8ec5ad | ||
|
|
cd33647087 | ||
|
|
71ebcac7f2 | ||
|
|
f06aee21eb | ||
|
|
5fbbc17376 | ||
|
|
a9d8830106 | ||
|
|
d21e6235ad | ||
|
|
289f79bbb0 | ||
|
|
768e9f4c09 | ||
|
|
62c776d90c | ||
|
|
464022bea2 | ||
|
|
61549b4a74 | ||
|
|
18df3dc07a | ||
|
|
3725724c54 | ||
|
|
500a005aac | ||
|
|
584cc6de2e | ||
|
|
2e5a6e21cf | ||
|
|
b79f63db78 | ||
|
|
7ed7a57d92 | ||
|
|
1eaf7c89b7 | ||
|
|
1fff8dd306 | ||
|
|
c3a3d02bea | ||
|
|
a9261970dd | ||
|
|
b7a3fe05a4 | ||
|
|
ab6b9006b7 | ||
|
|
d9a8b057c3 | ||
|
|
2ec6215b1c | ||
|
|
c59a8c9644 | ||
|
|
10de4b6b7b | ||
|
|
0be214e79e | ||
|
|
d6083c68fd | ||
|
|
22f7ac22d5 | ||
|
|
a00046f9b2 | ||
|
|
8a24275ba9 | ||
|
|
ca841252bd | ||
|
|
54195b16ad | ||
|
|
cb90167c76 | ||
|
|
ac4ae85a4a | ||
|
|
48b2a271cc | ||
|
|
596807055e | ||
|
|
cee20c4eb9 | ||
|
|
15fb47cb3d | ||
|
|
2635dfef96 | ||
|
|
7d7789ae96 | ||
|
|
cc69285420 | ||
|
|
99d3a283ef | ||
|
|
9b532584d6 | ||
|
|
7576eb38d9 | ||
|
|
8440d013f8 | ||
|
|
174c87a192 | ||
|
|
32b62d6d4f | ||
|
|
a0c2d312e9 | ||
|
|
5127a9ae3c | ||
|
|
b5653a1c06 | ||
|
|
671bd1022e | ||
|
|
94bba4ac9c | ||
|
|
fe1136aa95 | ||
|
|
8950ffcc5e | ||
|
|
2bc627970e | ||
|
|
44615c6fa2 | ||
|
|
00f55ea0bc | ||
|
|
be43cebf7d | ||
|
|
f38317d01f | ||
|
|
da839aae66 | ||
|
|
768e00ff1a | ||
|
|
40631f465e | ||
|
|
f665c73bb1 | ||
|
|
be067466fe | ||
|
|
3c309df6dd | ||
|
|
b7e6d98647 | ||
|
|
48942de75e | ||
|
|
fbcbc10174 | ||
|
|
342b48105f | ||
|
|
5f3e7f02cc | ||
|
|
bfccf29ccf | ||
|
|
1e3bb1f02b | ||
|
|
0dcf6771e7 | ||
|
|
062503c523 | ||
|
|
c3d7f2f170 | ||
|
|
faf6c16717 | ||
|
|
3d79d78134 | ||
|
|
35cab4ee73 | ||
|
|
a0edb8f2ad | ||
|
|
5cfe5e312b | ||
|
|
13f6ec04d5 | ||
|
|
2edc4a79b9 | ||
|
|
4661185719 | ||
|
|
895da5cbf0 | ||
|
|
ef9147512b | ||
|
|
abe05456f7 | ||
|
|
f9dfd3b348 | ||
|
|
9449501537 | ||
|
|
f3b5d5ab7b | ||
|
|
8ee5726e0c | ||
|
|
effa7fd57d | ||
|
|
6c039d2ad0 | ||
|
|
2dd8527566 | ||
|
|
fe811ce32e | ||
|
|
9fee0805c4 | ||
|
|
1987c32761 | ||
|
|
0ed2659698 | ||
|
|
9878856dfe | ||
|
|
ed01fd4edf | ||
|
|
9474933070 | ||
|
|
f3987b453c | ||
|
|
dcb4cb3a1e | ||
|
|
198b840059 | ||
|
|
42583cf3bb | ||
|
|
2e15371d61 | ||
|
|
339ff8ca77 | ||
|
|
268eaddad8 | ||
|
|
bb3cc1130b | ||
|
|
64ae3280e1 | ||
|
|
95235d69c2 | ||
|
|
d639c7be39 | ||
|
|
d7cafe25ff | ||
|
|
996f53373e | ||
|
|
6f55370ad4 | ||
|
|
fd511966a7 | ||
|
|
c4ddddd434 | ||
|
|
83a4db3b31 | ||
|
|
e35ef75949 | ||
|
|
d9dec6fe6b | ||
|
|
69bdbaed41 | ||
|
|
30f359e642 | ||
|
|
29d0a1714e | ||
|
|
fcb97f802f | ||
|
|
9ad05e640d | ||
|
|
449f00f960 | ||
|
|
8e64329d05 | ||
|
|
4284777556 | ||
|
|
81c496d96c | ||
|
|
65c06da275 | ||
|
|
5d0657c49a | ||
|
|
f6f6550bfb | ||
|
|
e01fb50359 | ||
|
|
28ce1c1249 | ||
|
|
7db592d27a | ||
|
|
b8e5c0d898 | ||
|
|
067c1771d0 | ||
|
|
349429b76e | ||
|
|
cc8f2afce9 | ||
|
|
2e97b20f94 | ||
|
|
1a163243ec | ||
|
|
75660e6f21 | ||
|
|
199ca77c2a | ||
|
|
1e2d2abbdf | ||
|
|
11b980f574 | ||
|
|
3274f9f155 | ||
|
|
f90f8824bb | ||
|
|
c7116d40ca | ||
|
|
6ef66399f8 | ||
|
|
2b8561f27d | ||
|
|
b20d8f195b | ||
|
|
6cf0eb9e1d | ||
|
|
c349e9aabe | ||
|
|
6ee38ceaba | ||
|
|
c60613fbcb | ||
|
|
bcc1b7b48a | ||
|
|
b19cb0805c | ||
|
|
7dfc5a78ba | ||
|
|
a077132d82 | ||
|
|
8ed6be6307 | ||
|
|
c490dd1563 | ||
|
|
d866b3df1f | ||
|
|
97f3fb4496 | ||
|
|
7530266330 | ||
|
|
6a53f356d2 | ||
|
|
075dc1e4e9 | ||
|
|
97b87d4ce4 | ||
|
|
e203e98375 | ||
|
|
9fcd104065 | ||
|
|
178e0ba87c | ||
|
|
cc40110d7e | ||
|
|
d58fb2bbc0 | ||
|
|
812333e9ae | ||
|
|
92bbdce435 | ||
|
|
bc62d49fc9 | ||
|
|
fe54d5b8ae | ||
|
|
7cc30c268b | ||
|
|
df60a2248a | ||
|
|
aa85d0ffeb | ||
|
|
1db963361c | ||
|
|
8a55b20284 | ||
|
|
beec349bc5 | ||
|
|
b025ed6057 | ||
|
|
27a54bcbaa | ||
|
|
6b20993d2a | ||
|
|
9ab16bdbb3 | ||
|
|
23088bc897 | ||
|
|
054a62de60 | ||
|
|
5aff548794 | ||
|
|
ff8fe7e018 | ||
|
|
c6617ebc9f | ||
|
|
15fa0c264f | ||
|
|
25468f55ff | ||
|
|
2340c55d76 | ||
|
|
13c1f4ab19 | ||
|
|
a160b798ca | ||
|
|
71f00a9efd | ||
|
|
967096f01c | ||
|
|
7616e94fd3 | ||
|
|
27ec69fb97 | ||
|
|
182d150eaa | ||
|
|
098ef976f7 | ||
|
|
ea724e343b | ||
|
|
85736d697c | ||
|
|
576a146ed2 | ||
|
|
69c5291e52 | ||
|
|
4875ef045a | ||
|
|
369cfc2413 | ||
|
|
491842ea34 | ||
|
|
9801876a2f | ||
|
|
9c28a04c65 | ||
|
|
596a1764ef | ||
|
|
8e09e1b248 | ||
|
|
d5674c85d7 | ||
|
|
ed6649b1d3 | ||
|
|
02baa778c5 | ||
|
|
5fd0e5add2 | ||
|
|
23eccb2f20 | ||
|
|
3c523fb824 | ||
|
|
5dbfc2786d | ||
|
|
c61495df52 | ||
|
|
6ad5ea1696 | ||
|
|
39fa27a2dc | ||
|
|
348bae53fe | ||
|
|
6bc00fc5e5 | ||
|
|
54c0f015f9 | ||
|
|
ea3e6dae93 | ||
|
|
80e52c73b0 | ||
|
|
5c893f0f39 | ||
|
|
e05dc99006 | ||
|
|
f864416e39 | ||
|
|
472dbd641c | ||
|
|
05141b4f52 | ||
|
|
784b914e07 | ||
|
|
4db7f6f59c | ||
|
|
edbf8509e1 | ||
|
|
a017fbadd3 | ||
|
|
201f4b7e4a | ||
|
|
c9ff536e24 | ||
|
|
238efb02c6 | ||
|
|
f7e12b629f | ||
|
|
7cbca7fc1e | ||
|
|
be7b87cda3 | ||
|
|
07979a13fb | ||
|
|
9073c4554f | ||
|
|
8694e0ad19 | ||
|
|
60fe987a5f | ||
|
|
86256162de | ||
|
|
db24ca3dc1 | ||
|
|
5e3aa2db1d | ||
|
|
b74a501fac | ||
|
|
490a7d4a78 | ||
|
|
b147195189 | ||
|
|
b561666d80 | ||
|
|
a0b5305e3e | ||
|
|
e7a6c17260 | ||
|
|
c8ee9e6447 | ||
|
|
f2d350002e | ||
|
|
fabd26f85b | ||
|
|
17dcf7d2e5 | ||
|
|
6f62995c96 | ||
|
|
f405f4bbc4 | ||
|
|
98124de362 | ||
|
|
1e4ea90021 | ||
|
|
053f4a9a2e | ||
|
|
2c7d2230b3 | ||
|
|
040e0d8387 | ||
|
|
b5c382f929 | ||
|
|
0c9c1ae673 | ||
|
|
da0e0bdaec | ||
|
|
1f5b6a6a35 | ||
|
|
d25b2890be | ||
|
|
d73438a397 | ||
|
|
e91538a554 | ||
|
|
8a3b514372 | ||
|
|
7eca955b79 | ||
|
|
4242354c03 | ||
|
|
8728389c88 | ||
|
|
6651801b3f | ||
|
|
9190ce3701 | ||
|
|
90e2064d72 | ||
|
|
943d419f98 | ||
|
|
551316bcb6 | ||
|
|
9dd5089940 | ||
|
|
06e7ebbdeb | ||
|
|
a83b16e12a | ||
|
|
91a8b97cf4 | ||
|
|
41754c92c3 | ||
|
|
e544995b83 | ||
|
|
45cf5c4c0f | ||
|
|
900eedfc2e | ||
|
|
faaa7bfa3a | ||
|
|
70366a98bd | ||
|
|
e88180b4d5 | ||
|
|
b639683ac1 | ||
|
|
918c8f9295 | ||
|
|
c2214cd4b5 | ||
|
|
7d7e5bac12 | ||
|
|
185b558561 | ||
|
|
4632035581 | ||
|
|
d7f81dff23 | ||
|
|
c849738c6f | ||
|
|
3cd7a2e6d6 | ||
|
|
0d4904f05d | ||
|
|
0b539a5977 | ||
|
|
395fdc9d61 | ||
|
|
3b3d7eff3c | ||
|
|
763c05313b | ||
|
|
9f80df3fcb | ||
|
|
f170ee9e59 | ||
|
|
339218508d | ||
|
|
f0c710b245 | ||
|
|
e66337a1db | ||
|
|
e087bccd33 | ||
|
|
8017774bf3 | ||
|
|
5f4d08ada5 | ||
|
|
1ad450d753 | ||
|
|
f1692b3436 | ||
|
|
2a9c56d9e3 | ||
|
|
39a5688464 | ||
|
|
e4e6173eff | ||
|
|
cf7334eb7d | ||
|
|
fdb96e91f1 | ||
|
|
844c5027ea | ||
|
|
8d0e485120 | ||
|
|
281ee1a853 | ||
|
|
a0bf29e600 | ||
|
|
d66c430e46 | ||
|
|
f511a52705 | ||
|
|
a674e410e0 | ||
|
|
fc63445c80 | ||
|
|
0c15655574 | ||
|
|
328b6d1cc6 | ||
|
|
b67d663a38 | ||
|
|
dd6c5c9eea | ||
|
|
2e87e64bd1 | ||
|
|
08c210d833 | ||
|
|
a9403013df | ||
|
|
05477c1a03 | ||
|
|
fcb6198a82 | ||
|
|
410d0bc125 | ||
|
|
abc62b9348 | ||
|
|
6fbf33c8f4 | ||
|
|
0ceb750dc7 | ||
|
|
a48c22d14f | ||
|
|
1521199e44 | ||
|
|
2910be82a4 | ||
|
|
07fdb087dc | ||
|
|
58150f5dcd | ||
|
|
e7a6ff39f9 | ||
|
|
b086afb272 | ||
|
|
7decf76883 | ||
|
|
d81369d63a | ||
|
|
c0fbe8237b | ||
|
|
58923b2846 | ||
|
|
d9f9477a52 | ||
|
|
966c744992 | ||
|
|
ddc91ce7c3 | ||
|
|
7e5107d90f | ||
|
|
c1668c9bdb | ||
|
|
7ddc2ccf1a | ||
|
|
3cd85fb395 | ||
|
|
b805ea9bf6 | ||
|
|
edd76f595a | ||
|
|
c131b63852 | ||
|
|
a70f377388 | ||
|
|
50f76446a9 | ||
|
|
15ce3ec41a | ||
|
|
b7b01999d9 | ||
|
|
956114fc42 | ||
|
|
bb3a986859 | ||
|
|
50fefc3bb0 | ||
|
|
c5eea2e7c5 | ||
|
|
19555a98ed | ||
|
|
9021f006f0 | ||
|
|
2d5f14388e | ||
|
|
ab47bf6451 | ||
|
|
d8bd45c2bd | ||
|
|
de692d3dcc | ||
|
|
4adb525513 | ||
|
|
72235a5f72 | ||
|
|
b6508cccec | ||
|
|
d9e7cf659e | ||
|
|
cf500cd817 | ||
|
|
f1338aca84 | ||
|
|
284de4ac5d | ||
|
|
19c4345162 | ||
|
|
d5d38b3331 | ||
|
|
bd04638d27 | ||
|
|
2f0d0e7c7a | ||
|
|
0b531e9fbc | ||
|
|
e3ebd582ec | ||
|
|
95ef046d0a | ||
|
|
21fd46d66b | ||
|
|
b3a801df11 | ||
|
|
a6d22e3b22 | ||
|
|
0415c050a5 | ||
|
|
014396cf11 | ||
|
|
70488f9c56 | ||
|
|
0052ab7148 | ||
|
|
f725040dd5 | ||
|
|
f131863642 | ||
|
|
8791047005 | ||
|
|
836a293f16 | ||
|
|
1177cc3f29 | ||
|
|
269847d19d | ||
|
|
df22f68088 | ||
|
|
d83d8552b8 | ||
|
|
365aa69afd | ||
|
|
578c338d40 | ||
|
|
389518e1b8 | ||
|
|
d42ff227f1 | ||
|
|
737e9e48ca | ||
|
|
f96d91cb6c | ||
|
|
85503655ab | ||
|
|
8d811760a9 | ||
|
|
4e0de22375 | ||
|
|
7cfbf100eb | ||
|
|
edbe026b49 | ||
|
|
1e967eceef | ||
|
|
7d20db93d3 | ||
|
|
fb05a42d2e | ||
|
|
9490ae1440 | ||
|
|
e932be0fb3 | ||
|
|
70b49980cb | ||
|
|
5e6ee5fd48 | ||
|
|
a2d872a9f0 | ||
|
|
e8bcde31b7 | ||
|
|
40cda9220a | ||
|
|
a494683bc8 | ||
|
|
2ba6a85eca | ||
|
|
0e58158a59 | ||
|
|
af740592c9 | ||
|
|
c9452c9f31 | ||
|
|
494a1603e4 | ||
|
|
5207e111e1 | ||
|
|
06995fb080 | ||
|
|
1f5cafc2d1 | ||
|
|
f190de39a6 | ||
|
|
272ab746a6 | ||
|
|
fce0bf6e59 | ||
|
|
5957786b2c | ||
|
|
4f3f4e23e4 | ||
|
|
5f5096e1d4 | ||
|
|
4b35aef728 | ||
|
|
6a0ed51f5e | ||
|
|
67360e93b8 | ||
|
|
f18f4c69f2 | ||
|
|
41435578d2 | ||
|
|
7f33ae3bee | ||
|
|
645135bf56 | ||
|
|
eb9005ad74 | ||
|
|
14089f8c6a | ||
|
|
49094120d9 | ||
|
|
fe4111a9f5 | ||
|
|
61613bee98 | ||
|
|
3ce967d8e5 | ||
|
|
aad9afad59 | ||
|
|
8cbbd022fc | ||
|
|
9b23cd6d19 | ||
|
|
d94f241d3c | ||
|
|
bb7c11adf1 | ||
|
|
5c295254bf | ||
|
|
236e8cc95c | ||
|
|
421973e0d9 | ||
|
|
e2a5af1cf7 | ||
|
|
65aa7b1084 | ||
|
|
f8c8330258 | ||
|
|
f5411ac9ab | ||
|
|
f31debc09c | ||
|
|
6654d7a919 | ||
|
|
44743b5f6f | ||
|
|
f80276584f | ||
|
|
cda41debfc | ||
|
|
2c50d01c26 | ||
|
|
01ebb6576d | ||
|
|
aaca0b6f76 | ||
|
|
84e1f3649f | ||
|
|
0ab2cfaf8b | ||
|
|
0545d6f083 | ||
|
|
d804228956 | ||
|
|
f7d70df2ba | ||
|
|
4daef52991 | ||
|
|
a329547682 | ||
|
|
f02af8d481 | ||
|
|
dd6c067832 | ||
|
|
dbc435506c | ||
|
|
f00e289014 | ||
|
|
1dffaba266 | ||
|
|
958a2f4274 | ||
|
|
21718a69d3 | ||
|
|
c650ae0e19 | ||
|
|
9ed435d04a | ||
|
|
fed6a0c24e | ||
|
|
44b9a8e7ed | ||
|
|
c16757b03a | ||
|
|
5d0dde5c15 | ||
|
|
f60356e8c7 | ||
|
|
cdf8f78962 | ||
|
|
4539d236df | ||
|
|
8718ac0c4b | ||
|
|
94787d537a | ||
|
|
bb8cff967e | ||
|
|
eca57beec1 | ||
|
|
58b4eb04f9 | ||
|
|
a9d46297c4 | ||
|
|
e9edecf34a | ||
|
|
71a5f0e84e | ||
|
|
fb22ee94d9 | ||
|
|
f03904ebce | ||
|
|
6cc9f49d97 | ||
|
|
f5f0680ec7 | ||
|
|
60e04b9065 | ||
|
|
025da92450 | ||
|
|
5de4aa091b | ||
|
|
1fe8235a85 | ||
|
|
0ab14399ae | ||
|
|
15dded712c | ||
|
|
8837f7e6e8 | ||
|
|
e8defd821a | ||
|
|
5d6effeff5 | ||
|
|
427c278012 | ||
|
|
a78a09f594 | ||
|
|
59fd48cfe2 | ||
|
|
cc78ab4855 | ||
|
|
063562261e | ||
|
|
70619dd0b7 | ||
|
|
63031fb278 | ||
|
|
7f924a56b3 | ||
|
|
114f2a1465 | ||
|
|
5d2777634a | ||
|
|
2d5b4a0003 | ||
|
|
adfa1704e2 | ||
|
|
ab3fd6be8f | ||
|
|
47702d075e | ||
|
|
341f000b9c | ||
|
|
0deea53931 | ||
|
|
8b3d792bec | ||
|
|
b82c48b66f | ||
|
|
fa91516dce | ||
|
|
4954b44d8e | ||
|
|
d132e51ac7 | ||
|
|
243b6ae985 | ||
|
|
8780ba3626 | ||
|
|
694194be2f | ||
|
|
c7f61f8b80 | ||
|
|
3a7c7fe4e8 | ||
|
|
668967a719 | ||
|
|
d15c14ab93 | ||
|
|
52b81608a1 | ||
|
|
048f754d83 | ||
|
|
d5ef3a3f8c | ||
|
|
e768e285ce | ||
|
|
a102d775b2 | ||
|
|
65e82b03ad | ||
|
|
80a636bd14 | ||
|
|
a4c57ee363 | ||
|
|
94bf54e7e0 | ||
|
|
b18ce5ade0 | ||
|
|
99793bb2c4 | ||
|
|
093936e594 | ||
|
|
036a37e351 | ||
|
|
d904df57ca | ||
|
|
d507979ec1 | ||
|
|
9bbcfead67 | ||
|
|
81036894c0 | ||
|
|
9044adecb5 | ||
|
|
24925a1739 | ||
|
|
74cdcde449 | ||
|
|
a9c4b8dd1a | ||
|
|
79ad0ff56b | ||
|
|
6a5ee72722 | ||
|
|
c6ec8bc0d9 |
40
.github/auto-comment.yml
vendored
40
.github/auto-comment.yml
vendored
@@ -1,40 +0,0 @@
|
||||
# Comment to a new issue.
|
||||
issuesOpened: >
|
||||
If this is a bug report, please upgrade to the latest code and try again:
|
||||
|
||||
如果有 bug, 请先更新到最新版试试:
|
||||
|
||||
```
|
||||
acme.sh --upgrade
|
||||
```
|
||||
|
||||
please also provide the log with `--debug 2`.
|
||||
|
||||
同时请提供调试输出 `--debug 2`
|
||||
|
||||
see: https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh
|
||||
|
||||
Without `--debug 2` log, your issue will NEVER get replied.
|
||||
|
||||
没有调试输出, 你的 issue 不会得到任何解答.
|
||||
|
||||
|
||||
pullRequestOpened: >
|
||||
First, NEVER send a PR to `master` branch, it will NEVER be accepted. Please send to the `dev` branch instead.
|
||||
|
||||
If this is a PR to support new DNS API or new notification API, please read this guide first:
|
||||
https://github.com/acmesh-official/acme.sh/wiki/DNS-API-Dev-Guide
|
||||
|
||||
Please check the guide items one by one.
|
||||
|
||||
Then add your usage here:
|
||||
https://github.com/acmesh-official/acme.sh/wiki/dnsapi
|
||||
|
||||
Or some other wiki pages:
|
||||
|
||||
https://github.com/acmesh-official/acme.sh/wiki/deployhooks
|
||||
|
||||
https://github.com/acmesh-official/acme.sh/wiki/notify
|
||||
|
||||
|
||||
|
||||
249
.github/workflows/DNS.yml
vendored
Normal file
249
.github/workflows/DNS.yml
vendored
Normal file
@@ -0,0 +1,249 @@
|
||||
name: DNS
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'dnsapi/*.sh'
|
||||
- '.github/workflows/DNS.yml'
|
||||
pull_request:
|
||||
branches:
|
||||
- 'dev'
|
||||
paths:
|
||||
- 'dnsapi/*.sh'
|
||||
- '.github/workflows/DNS.yml'
|
||||
|
||||
|
||||
jobs:
|
||||
CheckToken:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
hasToken: ${{ steps.step_one.outputs.hasToken }}
|
||||
steps:
|
||||
- name: Set the value
|
||||
id: step_one
|
||||
run: |
|
||||
if [ "${{secrets.TokenName1}}" ] ; then
|
||||
echo "::set-output name=hasToken::true"
|
||||
else
|
||||
echo "::set-output name=hasToken::false"
|
||||
fi
|
||||
- name: Check the value
|
||||
run: echo ${{ steps.step_one.outputs.hasToken }}
|
||||
|
||||
Fail:
|
||||
runs-on: ubuntu-latest
|
||||
needs: CheckToken
|
||||
if: "contains(needs.CheckToken.outputs.hasToken, 'false')"
|
||||
steps:
|
||||
- name: "Read this: https://github.com/acmesh-official/acme.sh/wiki/DNS-API-Test"
|
||||
run: |
|
||||
echo "Read this: https://github.com/acmesh-official/acme.sh/wiki/DNS-API-Test"
|
||||
if [ "${{github.actor}}" != "Neilpang" ]; then
|
||||
false
|
||||
fi
|
||||
|
||||
Docker:
|
||||
runs-on: ubuntu-latest
|
||||
needs: CheckToken
|
||||
if: "contains(needs.CheckToken.outputs.hasToken, 'true')"
|
||||
env:
|
||||
TEST_DNS : ${{ secrets.TEST_DNS }}
|
||||
TestingDomain: ${{ secrets.TestingDomain }}
|
||||
TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
|
||||
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
||||
CASE: le_test_dnsapi
|
||||
TEST_LOCAL: 1
|
||||
DEBUG: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Clone acmetest
|
||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- name: Set env file
|
||||
run: |
|
||||
cd ../acmetest
|
||||
if [ "${{ secrets.TokenName1}}" ] ; then
|
||||
echo "${{ secrets.TokenName1}}=${{ secrets.TokenValue1}}" >> docker.env
|
||||
fi
|
||||
if [ "${{ secrets.TokenName2}}" ] ; then
|
||||
echo "${{ secrets.TokenName2}}=${{ secrets.TokenValue2}}" >> docker.env
|
||||
fi
|
||||
if [ "${{ secrets.TokenName3}}" ] ; then
|
||||
echo "${{ secrets.TokenName3}}=${{ secrets.TokenValue3}}" >> docker.env
|
||||
fi
|
||||
if [ "${{ secrets.TokenName4}}" ] ; then
|
||||
echo "${{ secrets.TokenName4}}=${{ secrets.TokenValue4}}" >> docker.env
|
||||
fi
|
||||
if [ "${{ secrets.TokenName5}}" ] ; then
|
||||
echo "${{ secrets.TokenName5}}=${{ secrets.TokenValue5}}" >> docker.env
|
||||
fi
|
||||
echo "TEST_DNS_NO_WILDCARD" >> docker.env
|
||||
echo "TEST_DNS_SLEEP" >> docker.env
|
||||
- name: Run acmetest
|
||||
run: cd ../acmetest && ./rundocker.sh testall
|
||||
|
||||
MacOS:
|
||||
runs-on: macos-latest
|
||||
needs: Docker
|
||||
env:
|
||||
TEST_DNS : ${{ secrets.TEST_DNS }}
|
||||
TestingDomain: ${{ secrets.TestingDomain }}
|
||||
TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
|
||||
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
||||
CASE: le_test_dnsapi
|
||||
TEST_LOCAL: 1
|
||||
DEBUG: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install tools
|
||||
run: brew install socat
|
||||
- name: Clone acmetest
|
||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- name: Run acmetest
|
||||
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
|
||||
|
||||
Windows:
|
||||
runs-on: windows-latest
|
||||
needs: MacOS
|
||||
env:
|
||||
TEST_DNS : ${{ secrets.TEST_DNS }}
|
||||
TestingDomain: ${{ secrets.TestingDomain }}
|
||||
TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
|
||||
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
||||
CASE: le_test_dnsapi
|
||||
TEST_LOCAL: 1
|
||||
DEBUG: 1
|
||||
steps:
|
||||
- name: Set git to use LF
|
||||
run: |
|
||||
git config --global core.autocrlf false
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install cygwin base packages with chocolatey
|
||||
run: |
|
||||
choco config get cacheLocation
|
||||
choco install --no-progress cygwin
|
||||
shell: cmd
|
||||
- name: Install cygwin additional packages
|
||||
run: |
|
||||
C:\tools\cygwin\cygwinsetup.exe -qgnNdO -R C:/tools/cygwin -s http://mirrors.kernel.org/sourceware/cygwin/ -P socat,curl,cron,unzip,git
|
||||
shell: cmd
|
||||
- name: Set ENV
|
||||
shell: cmd
|
||||
run: |
|
||||
echo PATH=C:\tools\cygwin\bin;C:\tools\cygwin\usr\bin >> %GITHUB_ENV%
|
||||
- name: Clone acmetest
|
||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- name: Run acmetest
|
||||
shell: bash
|
||||
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
|
||||
|
||||
FreeBSD:
|
||||
runs-on: macos-latest
|
||||
needs: Windows
|
||||
env:
|
||||
TEST_DNS : ${{ secrets.TEST_DNS }}
|
||||
TestingDomain: ${{ secrets.TestingDomain }}
|
||||
TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
|
||||
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
||||
CASE: le_test_dnsapi
|
||||
TEST_LOCAL: 1
|
||||
DEBUG: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Clone acmetest
|
||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- uses: vmactions/freebsd-vm@v0.1.4
|
||||
with:
|
||||
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
|
||||
prepare: pkg install -y socat curl
|
||||
usesh: true
|
||||
run: |
|
||||
if [ "${{ secrets.TokenName1}}" ] ; then
|
||||
export ${{ secrets.TokenName1}}=${{ secrets.TokenValue1}}
|
||||
fi
|
||||
if [ "${{ secrets.TokenName2}}" ] ; then
|
||||
export ${{ secrets.TokenName2}}=${{ secrets.TokenValue2}}
|
||||
fi
|
||||
if [ "${{ secrets.TokenName3}}" ] ; then
|
||||
export ${{ secrets.TokenName3}}=${{ secrets.TokenValue3}}
|
||||
fi
|
||||
if [ "${{ secrets.TokenName4}}" ] ; then
|
||||
export ${{ secrets.TokenName4}}=${{ secrets.TokenValue4}}
|
||||
fi
|
||||
if [ "${{ secrets.TokenName5}}" ] ; then
|
||||
export ${{ secrets.TokenName5}}=${{ secrets.TokenValue5}}
|
||||
fi
|
||||
cd ../acmetest
|
||||
./letest.sh
|
||||
|
||||
Solaris:
|
||||
runs-on: macos-latest
|
||||
needs: FreeBSD
|
||||
env:
|
||||
TEST_DNS : ${{ secrets.TEST_DNS }}
|
||||
TestingDomain: ${{ secrets.TestingDomain }}
|
||||
TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
|
||||
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
||||
CASE: le_test_dnsapi
|
||||
TEST_LOCAL: 1
|
||||
DEBUG: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Clone acmetest
|
||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- uses: vmactions/solaris-vm@v0.0.3
|
||||
with:
|
||||
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
|
||||
prepare: pkgutil -y -i socat
|
||||
run: |
|
||||
pkg set-mediator -v -I default@1.1 openssl
|
||||
export PATH=/usr/gnu/bin:$PATH
|
||||
if [ "${{ secrets.TokenName1}}" ] ; then
|
||||
export ${{ secrets.TokenName1}}=${{ secrets.TokenValue1}}
|
||||
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
|
||||
60
.github/workflows/FreeBSD.yml
vendored
Normal file
60
.github/workflows/FreeBSD.yml
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
name: FreeBSD
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
paths:
|
||||
- '*.sh'
|
||||
- '.github/workflows/FreeBSD.yml'
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
paths:
|
||||
- '*.sh'
|
||||
- '.github/workflows/FreeBSD.yml'
|
||||
|
||||
|
||||
jobs:
|
||||
FreeBSD:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
||||
CA_ECDSA: ""
|
||||
CA: ""
|
||||
CA_EMAIL: ""
|
||||
- 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"
|
||||
runs-on: macos-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 }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: vmactions/cf-tunnel@v0.0.2
|
||||
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 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- uses: vmactions/freebsd-vm@v0.1.4
|
||||
with:
|
||||
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL'
|
||||
nat: |
|
||||
"8080": "80"
|
||||
prepare: pkg install -y socat curl
|
||||
usesh: true
|
||||
run: |
|
||||
cd ../acmetest \
|
||||
&& ./letest.sh
|
||||
|
||||
|
||||
40
.github/workflows/Linux.yml
vendored
Normal file
40
.github/workflows/Linux.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
name: Linux
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
paths:
|
||||
- '*.sh'
|
||||
- '.github/workflows/Linux.yml'
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
paths:
|
||||
- '*.sh'
|
||||
- '.github/workflows/Linux.yml'
|
||||
|
||||
|
||||
|
||||
jobs:
|
||||
Linux:
|
||||
strategy:
|
||||
matrix:
|
||||
os: ["ubuntu:latest", "debian:latest", "almalinux:latest", "fedora:latest", "centos:latest", "opensuse/leap:latest", "alpine:latest", "oraclelinux:8", "kalilinux/kali", "archlinux:latest", "mageia", "gentoo/stage3-amd64"]
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TEST_LOCAL: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Clone acmetest
|
||||
run: |
|
||||
cd .. \
|
||||
&& git clone https://github.com/acmesh-official/acmetest.git \
|
||||
&& cp -r acme.sh acmetest/
|
||||
- name: Run acmetest
|
||||
run: |
|
||||
cd ../acmetest \
|
||||
&& ./rundocker.sh testplat ${{ matrix.os }}
|
||||
|
||||
|
||||
|
||||
52
.github/workflows/MacOS.yml
vendored
Normal file
52
.github/workflows/MacOS.yml
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
name: MacOS
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
paths:
|
||||
- '*.sh'
|
||||
- '.github/workflows/MacOS.yml'
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
paths:
|
||||
- '*.sh'
|
||||
- '.github/workflows/MacOS.yml'
|
||||
|
||||
|
||||
jobs:
|
||||
MacOS:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
||||
CA_ECDSA: ""
|
||||
CA: ""
|
||||
CA_EMAIL: ""
|
||||
- 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"
|
||||
runs-on: macos-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 }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install tools
|
||||
run: brew install socat
|
||||
- name: Clone acmetest
|
||||
run: |
|
||||
cd .. \
|
||||
&& git clone https://github.com/acmesh-official/acmetest.git \
|
||||
&& cp -r acme.sh acmetest/
|
||||
- name: Run acmetest
|
||||
run: |
|
||||
cd ../acmetest \
|
||||
&& sudo --preserve-env ./letest.sh
|
||||
|
||||
|
||||
39
.github/workflows/PebbleStrict.yml
vendored
Normal file
39
.github/workflows/PebbleStrict.yml
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
name: PebbleStrict
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
paths:
|
||||
- '*.sh'
|
||||
- '.github/workflows/PebbleStrict.yml'
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
paths:
|
||||
- '*.sh'
|
||||
- '.github/workflows/PebbleStrict.yml'
|
||||
|
||||
jobs:
|
||||
PebbleStrict:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TestingDomain: example.com
|
||||
TestingAltDomains: www.example.com
|
||||
TEST_ACME_Server: https://localhost:14000/dir
|
||||
HTTPS_INSECURE: 1
|
||||
Le_HTTPPort: 5002
|
||||
TEST_LOCAL: 1
|
||||
TEST_CA: "Pebble Intermediate CA"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- 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
|
||||
- name: Set up Pebble
|
||||
run: curl --request POST --data '{"ip":"10.30.50.1"}' http://localhost:8055/set-default-ipv4
|
||||
- name: Clone acmetest
|
||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- name: Run acmetest
|
||||
run: cd ../acmetest && ./letest.sh
|
||||
58
.github/workflows/Solaris.yml
vendored
Normal file
58
.github/workflows/Solaris.yml
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
name: Solaris
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
paths:
|
||||
- '*.sh'
|
||||
- '.github/workflows/Solaris.yml'
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
paths:
|
||||
- '*.sh'
|
||||
- '.github/workflows/Solaris.yml'
|
||||
|
||||
|
||||
jobs:
|
||||
Solaris:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
||||
CA_ECDSA: ""
|
||||
CA: ""
|
||||
CA_EMAIL: ""
|
||||
- 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"
|
||||
runs-on: macos-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 }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: vmactions/cf-tunnel@v0.0.2
|
||||
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 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- uses: vmactions/solaris-vm@v0.0.3
|
||||
with:
|
||||
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL'
|
||||
nat: |
|
||||
"8080": "80"
|
||||
prepare: pkgutil -y -i socat curl
|
||||
run: |
|
||||
cd ../acmetest \
|
||||
&& ./letest.sh
|
||||
|
||||
54
.github/workflows/Ubuntu.yml
vendored
Normal file
54
.github/workflows/Ubuntu.yml
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
name: Ubuntu
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
paths:
|
||||
- '*.sh'
|
||||
- '.github/workflows/Ubuntu.yml'
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
paths:
|
||||
- '*.sh'
|
||||
- '.github/workflows/Ubuntu.yml'
|
||||
|
||||
|
||||
jobs:
|
||||
Ubuntu:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
||||
CA_ECDSA: ""
|
||||
CA: ""
|
||||
CA_EMAIL: ""
|
||||
- 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"
|
||||
|
||||
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 }}
|
||||
NO_ECC_384: ${{ matrix.NO_ECC_384 }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install tools
|
||||
run: sudo apt-get install -y socat
|
||||
- name: Clone acmetest
|
||||
run: |
|
||||
cd .. \
|
||||
&& git clone https://github.com/acmesh-official/acmetest.git \
|
||||
&& cp -r acme.sh acmetest/
|
||||
- name: Run acmetest
|
||||
run: |
|
||||
cd ../acmetest \
|
||||
&& sudo --preserve-env ./letest.sh
|
||||
|
||||
|
||||
70
.github/workflows/Windows.yml
vendored
Normal file
70
.github/workflows/Windows.yml
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
name: Windows
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
paths:
|
||||
- '*.sh'
|
||||
- '.github/workflows/Windows.yml'
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
paths:
|
||||
- '*.sh'
|
||||
- '.github/workflows/Windows.yml'
|
||||
|
||||
|
||||
jobs:
|
||||
Windows:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
||||
CA_ECDSA: ""
|
||||
CA: ""
|
||||
CA_EMAIL: ""
|
||||
- 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"
|
||||
runs-on: windows-latest
|
||||
env:
|
||||
TEST_ACME_Server: ${{ matrix.TEST_ACME_Server }}
|
||||
CA_ECDSA: ${{ matrix.CA_ECDSA }}
|
||||
CA: ${{ matrix.CA }}
|
||||
CA_EMAIL: ${{ matrix.CA_EMAIL }}
|
||||
TEST_LOCAL: 1
|
||||
#The 80 port is used by Windows server, we have to use a custom port, tunnel will also use this port.
|
||||
Le_HTTPPort: 8888
|
||||
steps:
|
||||
- name: Set git to use LF
|
||||
run: |
|
||||
git config --global core.autocrlf false
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install cygwin base packages with chocolatey
|
||||
run: |
|
||||
choco config get cacheLocation
|
||||
choco install --no-progress cygwin
|
||||
shell: cmd
|
||||
- name: Install cygwin additional packages
|
||||
run: |
|
||||
C:\tools\cygwin\cygwinsetup.exe -qgnNdO -R C:/tools/cygwin -s http://mirrors.kernel.org/sourceware/cygwin/ -P socat,curl,cron,unzip,git
|
||||
shell: cmd
|
||||
- name: Set ENV
|
||||
shell: cmd
|
||||
run: |
|
||||
echo PATH=C:\tools\cygwin\bin;C:\tools\cygwin\usr\bin;%PATH% >> %GITHUB_ENV%
|
||||
- name: Check ENV
|
||||
shell: cmd
|
||||
run: |
|
||||
echo "PATH=%PATH%"
|
||||
- name: Clone acmetest
|
||||
shell: cmd
|
||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- name: Run acmetest
|
||||
shell: cmd
|
||||
run: cd ../acmetest && bash.exe -c ./letest.sh
|
||||
|
||||
|
||||
|
||||
63
.github/workflows/dockerhub.yml
vendored
63
.github/workflows/dockerhub.yml
vendored
@@ -2,15 +2,68 @@
|
||||
name: Build DockerHub
|
||||
on:
|
||||
push:
|
||||
branches: [ master, dev ]
|
||||
branches:
|
||||
- '*'
|
||||
tags:
|
||||
- '*'
|
||||
paths:
|
||||
- '**.sh'
|
||||
- "Dockerfile"
|
||||
- '.github/workflows/dockerhub.yml'
|
||||
|
||||
|
||||
jobs:
|
||||
CheckToken:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
hasToken: ${{ steps.step_one.outputs.hasToken }}
|
||||
env:
|
||||
DOCKER_PASSWORD : ${{ secrets.DOCKER_PASSWORD }}
|
||||
steps:
|
||||
- name: Set the value
|
||||
id: step_one
|
||||
run: |
|
||||
if [ "$DOCKER_PASSWORD" ] ; then
|
||||
echo "::set-output name=hasToken::true"
|
||||
else
|
||||
echo "::set-output name=hasToken::false"
|
||||
fi
|
||||
- name: Check the value
|
||||
run: echo ${{ steps.step_one.outputs.hasToken }}
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
needs: CheckToken
|
||||
if: "contains(needs.CheckToken.outputs.hasToken, 'true')"
|
||||
steps:
|
||||
- name: trigger
|
||||
run: curl -X POST https://hub.docker.com/api/build/v1/source/1813a660-2ee5-4583-a238-dd54e9a6ebac/trigger/c8cd9f1f-f269-45bc-9750-a08327257f62/call/
|
||||
|
||||
|
||||
- name: checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
- name: login to docker hub
|
||||
run: |
|
||||
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
|
||||
|
||||
if [[ $GITHUB_REF == refs/heads/* ]]; then
|
||||
DOCKER_IMAGE_TAG=${GITHUB_REF#refs/heads/}
|
||||
|
||||
if [[ $DOCKER_IMAGE_TAG == master ]]; then
|
||||
DOCKER_IMAGE_TAG=latest
|
||||
AUTO_UPGRADE=1
|
||||
fi
|
||||
fi
|
||||
|
||||
docker buildx build \
|
||||
--tag ${DOCKER_IMAGE}:${DOCKER_IMAGE_TAG} \
|
||||
--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 .
|
||||
|
||||
33
.github/workflows/shellcheck.yml
vendored
Normal file
33
.github/workflows/shellcheck.yml
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
name: Shellcheck
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
paths:
|
||||
- '**.sh'
|
||||
- '.github/workflows/shellcheck.yml'
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
paths:
|
||||
- '**.sh'
|
||||
- '.github/workflows/shellcheck.yml'
|
||||
|
||||
jobs:
|
||||
ShellCheck:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install Shellcheck
|
||||
run: sudo apt-get install -y shellcheck
|
||||
- name: DoShellcheck
|
||||
run: shellcheck -V && shellcheck -e SC2181 **/*.sh && echo "shellcheck OK"
|
||||
|
||||
shfmt:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- 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
|
||||
run: ~/shfmt -l -w -i 2 . ; git diff --exit-code && echo "shfmt OK"
|
||||
37
.travis.yml
37
.travis.yml
@@ -1,37 +0,0 @@
|
||||
language: shell
|
||||
dist: trusty
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
env:
|
||||
global:
|
||||
- SHFMT_URL=https://github.com/mvdan/sh/releases/download/v0.4.0/shfmt_v0.4.0_linux_amd64
|
||||
|
||||
|
||||
install:
|
||||
- if [ "$TRAVIS_OS_NAME" = 'osx' ]; then
|
||||
brew update && brew install socat;
|
||||
export PATH="/usr/local/opt/openssl@1.1/bin:$PATH" ;
|
||||
fi
|
||||
|
||||
script:
|
||||
- echo "NGROK_TOKEN=$(echo "$NGROK_TOKEN" | wc -c)"
|
||||
- command -V openssl && openssl version
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then curl -sSL $SHFMT_URL -o ~/shfmt && chmod +x ~/shfmt && ~/shfmt -l -w -i 2 . ; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then git diff --exit-code && echo "shfmt OK" ; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -V ; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -e SC2181 **/*.sh && echo "shellcheck OK" ; fi
|
||||
- cd ..
|
||||
- git clone --depth 1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ./rundocker.sh testplat ubuntu:latest ; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ACME_OPENSSL_BIN="$ACME_OPENSSL_BIN" ./letest.sh ; fi
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
||||
|
||||
15
Dockerfile
15
Dockerfile
@@ -1,24 +1,26 @@
|
||||
FROM alpine:3.10
|
||||
FROM alpine:3.12
|
||||
|
||||
RUN apk update -f \
|
||||
&& apk --no-cache add -f \
|
||||
RUN apk --no-cache add -f \
|
||||
openssl \
|
||||
openssh-client \
|
||||
coreutils \
|
||||
bind-tools \
|
||||
curl \
|
||||
sed \
|
||||
socat \
|
||||
tzdata \
|
||||
oath-toolkit-oathtool \
|
||||
tar \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
libidn
|
||||
|
||||
ENV LE_CONFIG_HOME /acme.sh
|
||||
|
||||
ENV AUTO_UPGRADE 1
|
||||
ARG AUTO_UPGRADE=1
|
||||
|
||||
ENV AUTO_UPGRADE $AUTO_UPGRADE
|
||||
|
||||
#Install
|
||||
ADD ./ /install_acme.sh/
|
||||
COPY ./ /install_acme.sh/
|
||||
RUN cd /install_acme.sh && ([ -f /install_acme.sh/acme.sh ] && /install_acme.sh/acme.sh --install || curl https://get.acme.sh | sh) && rm -rf /install_acme.sh/
|
||||
|
||||
|
||||
@@ -52,6 +54,7 @@ RUN for verb in help \
|
||||
deactivate \
|
||||
deactivate-account \
|
||||
set-notify \
|
||||
set-default-ca \
|
||||
; do \
|
||||
printf -- "%b" "#!/usr/bin/env sh\n/root/.acme.sh/acme.sh --${verb} --config-home /acme.sh \"\$@\"" >/usr/local/bin/--${verb} && chmod +x /usr/local/bin/--${verb} \
|
||||
; done
|
||||
|
||||
100
README.md
100
README.md
@@ -1,21 +1,37 @@
|
||||
# An ACME Shell script: acme.sh [](https://travis-ci.org/acmesh-official/acme.sh)
|
||||
# An ACME Shell script: acme.sh
|
||||
|
||||
[](https://github.com/acmesh-official/acme.sh/actions/workflows/FreeBSD.yml)
|
||||
[](https://github.com/acmesh-official/acme.sh/actions/workflows/MacOS.yml)
|
||||
[](https://github.com/acmesh-official/acme.sh/actions/workflows/Ubuntu.yml)
|
||||
[](https://github.com/acmesh-official/acme.sh/actions/workflows/Windows.yml)
|
||||
[](https://github.com/acmesh-official/acme.sh/actions/workflows/Solaris.yml)
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
|
||||
<a href="https://opencollective.com/acmesh" alt="Financial Contributors on Open Collective"><img src="https://opencollective.com/acmesh/all/badge.svg?label=financial+contributors" /></a>
|
||||
[](https://gitter.im/acme-sh/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://hub.docker.com/r/neilpang/acme.sh "Click to view the image on Docker Hub")
|
||||
[](https://hub.docker.com/r/neilpang/acme.sh "Click to view the image on Docker Hub")
|
||||
|
||||
|
||||
|
||||
<a href="https://opencollective.com/acmesh" alt="Financial Contributors on Open Collective"><img src="https://opencollective.com/acmesh/all/badge.svg?label=financial+contributors" /></a> [](https://gitter.im/acme-sh/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
- An ACME protocol client written purely in Shell (Unix shell) language.
|
||||
- Full ACME protocol implementation.
|
||||
- Support ACME v1 and ACME v2
|
||||
- Support ACME v2 wildcard certs
|
||||
- Support ECDSA certs
|
||||
- Support SAN and wildcard certs
|
||||
- Simple, powerful and very easy to use. You only need 3 minutes to learn it.
|
||||
- Bash, dash and sh compatible.
|
||||
- Simplest shell script for Let's Encrypt free certificate client.
|
||||
- Purely written in Shell with no dependencies on python or the official Let's Encrypt client.
|
||||
- Purely written in Shell with no dependencies on python.
|
||||
- Just one script to issue, renew and install your certificates automatically.
|
||||
- DOES NOT require `root/sudoer` access.
|
||||
- Docker friendly
|
||||
- IPv6 support
|
||||
- Docker ready
|
||||
- IPv6 ready
|
||||
- Cron job notifications for renewal or error etc.
|
||||
|
||||
It's probably the `easiest & smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt.
|
||||
It's probably the `easiest & smartest` shell script to automatically issue & renew the free certificates.
|
||||
|
||||
Wiki: https://github.com/acmesh-official/acme.sh/wiki
|
||||
|
||||
@@ -29,7 +45,7 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa)
|
||||
# Who:
|
||||
- [FreeBSD.org](https://blog.crashed.org/letsencrypt-in-freebsd-org/)
|
||||
- [ruby-china.org](https://ruby-china.org/topics/31983)
|
||||
- [Proxmox](https://pve.proxmox.com/wiki/HTTPS_Certificate_Configuration_(Version_4.x_and_newer))
|
||||
- [Proxmox](https://pve.proxmox.com/wiki/Certificate_Management)
|
||||
- [pfsense](https://github.com/pfsense/FreeBSD-ports/pull/89)
|
||||
- [webfaction](https://community.webfaction.com/questions/19988/using-letsencrypt)
|
||||
- [Loadbalancer.org](https://www.loadbalancer.org/blog/loadbalancer-org-with-lets-encrypt-quick-and-dirty)
|
||||
@@ -46,37 +62,41 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa)
|
||||
|
||||
| NO | Status| Platform|
|
||||
|----|-------|---------|
|
||||
|1|[](https://github.com/acmesh-official/letest#here-are-the-latest-status)| Ubuntu
|
||||
|2|[](https://github.com/acmesh-official/letest#here-are-the-latest-status)| Debian
|
||||
|3|[](https://github.com/acmesh-official/letest#here-are-the-latest-status)|CentOS
|
||||
|4|[](https://github.com/acmesh-official/letest#here-are-the-latest-status)|Windows (cygwin with curl, openssl and crontab included)
|
||||
|5|[](https://github.com/acmesh-official/letest#here-are-the-latest-status)|FreeBSD
|
||||
|6|[](https://github.com/acmesh-official/letest#here-are-the-latest-status)|pfsense
|
||||
|7|[](https://github.com/acmesh-official/letest#here-are-the-latest-status)|openSUSE
|
||||
|8|[](https://github.com/acmesh-official/letest#here-are-the-latest-status)|Alpine Linux (with curl)
|
||||
|9|[](https://github.com/acmesh-official/letest#here-are-the-latest-status)|Archlinux
|
||||
|10|[](https://github.com/acmesh-official/letest#here-are-the-latest-status)|fedora
|
||||
|11|[](https://github.com/acmesh-official/letest#here-are-the-latest-status)|Kali Linux
|
||||
|12|[](https://github.com/acmesh-official/letest#here-are-the-latest-status)|Oracle Linux
|
||||
|13|[](https://github.com/acmesh-official/letest#here-are-the-latest-status)| Proxmox https://pve.proxmox.com/wiki/HTTPSCertificateConfiguration#Let.27s_Encrypt_using_acme.sh
|
||||
|14|-----| Cloud Linux https://github.com/acmesh-official/acme.sh/issues/111
|
||||
|15|[](https://github.com/acmesh-official/letest#here-are-the-latest-status)|OpenBSD
|
||||
|16|[](https://github.com/acmesh-official/letest#here-are-the-latest-status)|Mageia
|
||||
|17|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/acmesh-official/acme.sh/wiki/How-to-run-on-OpenWRT)
|
||||
|18|[](https://github.com/acmesh-official/letest#here-are-the-latest-status)|SunOS/Solaris
|
||||
|19|[](https://github.com/acmesh-official/letest#here-are-the-latest-status)|Gentoo Linux
|
||||
|20|[](https://travis-ci.org/acmesh-official/acme.sh)|Mac OSX
|
||||
|21|[](https://github.com/acmesh-official/letest#here-are-the-latest-status)|ClearLinux
|
||||
|1|[](https://github.com/acmesh-official/acme.sh/actions/workflows/MacOS.yml)|Mac OSX
|
||||
|2|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Windows.yml)|Windows (cygwin with curl, openssl and crontab included)
|
||||
|3|[](https://github.com/acmesh-official/acme.sh/actions/workflows/FreeBSD.yml)|FreeBSD
|
||||
|4|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Solaris.yml)|Solaris
|
||||
|5|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Ubuntu.yml)| Ubuntu
|
||||
|6|NA|pfsense
|
||||
|7|NA|OpenBSD
|
||||
|8|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)| Debian
|
||||
|9|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|CentOS
|
||||
|10|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|openSUSE
|
||||
|11|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Alpine Linux (with curl)
|
||||
|12|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Archlinux
|
||||
|13|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|fedora
|
||||
|14|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Kali Linux
|
||||
|15|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Oracle Linux
|
||||
|16|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Mageia
|
||||
|17|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Gentoo Linux
|
||||
|18|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|ClearLinux
|
||||
|19|-----| Cloud Linux https://github.com/acmesh-official/acme.sh/issues/111
|
||||
|20|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/acmesh-official/acme.sh/wiki/How-to-run-on-OpenWRT)
|
||||
|21|[](https://github.com/acmesh-official/letest#here-are-the-latest-status)| Proxmox: See Proxmox VE Wiki. Version [4.x, 5.0, 5.1](https://pve.proxmox.com/wiki/HTTPS_Certificate_Configuration_(Version_4.x,_5.0_and_5.1)#Let.27s_Encrypt_using_acme.sh), version [5.2 and up](https://pve.proxmox.com/wiki/Certificate_Management)
|
||||
|
||||
For all build statuses, check our [weekly build project](https://github.com/acmesh-official/acmetest):
|
||||
|
||||
Check our [testing project](https://github.com/acmesh-official/acmetest):
|
||||
|
||||
https://github.com/acmesh-official/acmetest
|
||||
|
||||
# Supported CA
|
||||
|
||||
- Letsencrypt.org CA(default)
|
||||
- [ZeroSSL.com CA](https://github.com/acmesh-official/acme.sh/wiki/ZeroSSL.com-CA)(default)
|
||||
- Letsencrypt.org CA
|
||||
- [BuyPass.com CA](https://github.com/acmesh-official/acme.sh/wiki/BuyPass.com-CA)
|
||||
- [SSL.com CA](https://github.com/acmesh-official/acme.sh/wiki/SSL.com-CA)
|
||||
- [Pebble strict Mode](https://github.com/letsencrypt/pebble)
|
||||
- Any other [RFC8555](https://tools.ietf.org/html/rfc8555)-compliant CA
|
||||
|
||||
# Supported modes
|
||||
|
||||
@@ -97,13 +117,13 @@ https://github.com/acmesh-official/acmetest
|
||||
Check this project: https://github.com/acmesh-official/get.acme.sh
|
||||
|
||||
```bash
|
||||
curl https://get.acme.sh | sh
|
||||
curl https://get.acme.sh | sh -s email=my@example.com
|
||||
```
|
||||
|
||||
Or:
|
||||
|
||||
```bash
|
||||
wget -O - https://get.acme.sh | sh
|
||||
wget -O - https://get.acme.sh | sh -s email=my@example.com
|
||||
```
|
||||
|
||||
|
||||
@@ -114,7 +134,7 @@ Clone this project and launch installation:
|
||||
```bash
|
||||
git clone https://github.com/acmesh-official/acme.sh.git
|
||||
cd ./acme.sh
|
||||
./acme.sh --install
|
||||
./acme.sh --install -m my@example.com
|
||||
```
|
||||
|
||||
You `don't have to be root` then, although `it is recommended`.
|
||||
@@ -246,7 +266,7 @@ More examples: https://github.com/acmesh-official/acme.sh/wiki/How-to-issue-a-ce
|
||||
|
||||
**(requires you to be root/sudoer, since it is required to interact with Apache server)**
|
||||
|
||||
If you are running a web server, Apache or Nginx, it is recommended to use the `Webroot mode`.
|
||||
If you are running a web server, it is recommended to use the `Webroot mode`.
|
||||
|
||||
Particularly, if you are running an Apache server, you can use Apache mode instead. This mode doesn't write any files to your web root folder.
|
||||
|
||||
@@ -266,7 +286,7 @@ More examples: https://github.com/acmesh-official/acme.sh/wiki/How-to-issue-a-ce
|
||||
|
||||
**(requires you to be root/sudoer, since it is required to interact with Nginx server)**
|
||||
|
||||
If you are running a web server, Apache or Nginx, it is recommended to use the `Webroot mode`.
|
||||
If you are running a web server, it is recommended to use the `Webroot mode`.
|
||||
|
||||
Particularly, if you are running an nginx server, you can use nginx mode instead. This mode doesn't write any files to your web root folder.
|
||||
|
||||
@@ -300,7 +320,7 @@ https://github.com/acmesh-official/acme.sh/wiki/dnsapi
|
||||
|
||||
See: https://github.com/acmesh-official/acme.sh/wiki/dns-manual-mode first.
|
||||
|
||||
If your dns provider doesn't support any api access, you can add the txt record by your hand.
|
||||
If your dns provider doesn't support any api access, you can add the txt record by hand.
|
||||
|
||||
```bash
|
||||
acme.sh --issue --dns -d example.com -d www.example.com -d cp.example.com
|
||||
@@ -456,7 +476,7 @@ TODO:
|
||||
|
||||
### Code Contributors
|
||||
|
||||
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
|
||||
This project exists thanks to all the people who contribute.
|
||||
<a href="https://github.com/acmesh-official/acme.sh/graphs/contributors"><img src="https://opencollective.com/acmesh/contributors.svg?width=890&button=false" /></a>
|
||||
|
||||
### Financial Contributors
|
||||
|
||||
92
deploy/cleverreach.sh
Normal file
92
deploy/cleverreach.sh
Normal file
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env sh
|
||||
# Here is the script to deploy the cert to your CleverReach Account using the CleverReach REST API.
|
||||
# Your OAuth needs the right scope, please contact CleverReach support for that.
|
||||
#
|
||||
# Written by Jan-Philipp Benecke <github@bnck.me>
|
||||
# Public domain, 2020
|
||||
#
|
||||
# Following environment variables must be set:
|
||||
#
|
||||
#export DEPLOY_CLEVERREACH_CLIENT_ID=myid
|
||||
#export DEPLOY_CLEVERREACH_CLIENT_SECRET=mysecret
|
||||
|
||||
cleverreach_deploy() {
|
||||
_cdomain="$1"
|
||||
_ckey="$2"
|
||||
_ccert="$3"
|
||||
_cca="$4"
|
||||
_cfullchain="$5"
|
||||
|
||||
_rest_endpoint="https://rest.cleverreach.com"
|
||||
|
||||
_debug _cdomain "$_cdomain"
|
||||
_debug _ckey "$_ckey"
|
||||
_debug _ccert "$_ccert"
|
||||
_debug _cca "$_cca"
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
_getdeployconf DEPLOY_CLEVERREACH_CLIENT_ID
|
||||
_getdeployconf DEPLOY_CLEVERREACH_CLIENT_SECRET
|
||||
_getdeployconf DEPLOY_CLEVERREACH_SUBCLIENT_ID
|
||||
|
||||
if [ -z "${DEPLOY_CLEVERREACH_CLIENT_ID}" ]; then
|
||||
_err "CleverReach Client ID is not found, please define DEPLOY_CLEVERREACH_CLIENT_ID."
|
||||
return 1
|
||||
fi
|
||||
if [ -z "${DEPLOY_CLEVERREACH_CLIENT_SECRET}" ]; then
|
||||
_err "CleverReach client secret is not found, please define DEPLOY_CLEVERREACH_CLIENT_SECRET."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_savedeployconf DEPLOY_CLEVERREACH_CLIENT_ID "${DEPLOY_CLEVERREACH_CLIENT_ID}"
|
||||
_savedeployconf DEPLOY_CLEVERREACH_CLIENT_SECRET "${DEPLOY_CLEVERREACH_CLIENT_SECRET}"
|
||||
_savedeployconf DEPLOY_CLEVERREACH_SUBCLIENT_ID "${DEPLOY_CLEVERREACH_SUBCLIENT_ID}"
|
||||
|
||||
_info "Obtaining a CleverReach access token"
|
||||
|
||||
_data="{\"grant_type\": \"client_credentials\", \"client_id\": \"${DEPLOY_CLEVERREACH_CLIENT_ID}\", \"client_secret\": \"${DEPLOY_CLEVERREACH_CLIENT_SECRET}\"}"
|
||||
_auth_result="$(_post "$_data" "$_rest_endpoint/oauth/token.php" "" "POST" "application/json")"
|
||||
|
||||
_debug _data "$_data"
|
||||
_debug _auth_result "$_auth_result"
|
||||
|
||||
_regex=".*\"access_token\":\"\([-._0-9A-Za-z]*\)\".*$"
|
||||
_debug _regex "$_regex"
|
||||
_access_token=$(echo "$_auth_result" | _json_decode | sed -n "s/$_regex/\1/p")
|
||||
|
||||
_debug _subclient "${DEPLOY_CLEVERREACH_SUBCLIENT_ID}"
|
||||
|
||||
if [ -n "${DEPLOY_CLEVERREACH_SUBCLIENT_ID}" ]; then
|
||||
_info "Obtaining token for sub-client ${DEPLOY_CLEVERREACH_SUBCLIENT_ID}"
|
||||
export _H1="Authorization: Bearer ${_access_token}"
|
||||
_subclient_token_result="$(_get "$_rest_endpoint/v3/clients/$DEPLOY_CLEVERREACH_SUBCLIENT_ID/token")"
|
||||
_access_token=$(echo "$_subclient_token_result" | sed -n "s/\"//p")
|
||||
|
||||
_debug _subclient_token_result "$_access_token"
|
||||
|
||||
_info "Destroying parent token at CleverReach, as it not needed anymore"
|
||||
_destroy_result="$(_post "" "$_rest_endpoint/v3/oauth/token.json" "" "DELETE" "application/json")"
|
||||
_debug _destroy_result "$_destroy_result"
|
||||
fi
|
||||
|
||||
_info "Uploading certificate and key to CleverReach"
|
||||
|
||||
_certData="{\"cert\":\"$(_json_encode <"$_cfullchain")\", \"key\":\"$(_json_encode <"$_ckey")\"}"
|
||||
export _H1="Authorization: Bearer ${_access_token}"
|
||||
_add_cert_result="$(_post "$_certData" "$_rest_endpoint/v3/ssl" "" "POST" "application/json")"
|
||||
|
||||
if [ -z "${DEPLOY_CLEVERREACH_SUBCLIENT_ID}" ]; then
|
||||
_info "Destroying token at CleverReach, as it not needed anymore"
|
||||
_destroy_result="$(_post "" "$_rest_endpoint/v3/oauth/token.json" "" "DELETE" "application/json")"
|
||||
_debug _destroy_result "$_destroy_result"
|
||||
fi
|
||||
|
||||
if ! echo "$_add_cert_result" | grep '"error":' >/dev/null; then
|
||||
_info "Uploaded certificate successfully"
|
||||
return 0
|
||||
else
|
||||
_debug _add_cert_result "$_add_cert_result"
|
||||
_err "Unable to update certificate"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
98
deploy/consul.sh
Normal file
98
deploy/consul.sh
Normal file
@@ -0,0 +1,98 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Here is a script to deploy cert to hashicorp consul using curl
|
||||
# (https://www.consul.io/)
|
||||
#
|
||||
# it requires following environment variables:
|
||||
#
|
||||
# CONSUL_PREFIX - this contains the prefix path in consul
|
||||
# CONSUL_HTTP_ADDR - consul requires this to find your consul server
|
||||
#
|
||||
# additionally, you need to ensure that CONSUL_HTTP_TOKEN is available
|
||||
# to access the consul server
|
||||
|
||||
#returns 0 means success, otherwise error.
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#domain keyfile certfile cafile fullchain
|
||||
consul_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"
|
||||
|
||||
# validate required env vars
|
||||
_getdeployconf CONSUL_PREFIX
|
||||
if [ -z "$CONSUL_PREFIX" ]; then
|
||||
_err "CONSUL_PREFIX needs to be defined (contains prefix path in vault)"
|
||||
return 1
|
||||
fi
|
||||
_savedeployconf CONSUL_PREFIX "$CONSUL_PREFIX"
|
||||
|
||||
_getdeployconf CONSUL_HTTP_ADDR
|
||||
if [ -z "$CONSUL_HTTP_ADDR" ]; then
|
||||
_err "CONSUL_HTTP_ADDR needs to be defined (contains consul connection address)"
|
||||
return 1
|
||||
fi
|
||||
_savedeployconf CONSUL_HTTP_ADDR "$CONSUL_HTTP_ADDR"
|
||||
|
||||
CONSUL_CMD=$(command -v consul)
|
||||
|
||||
# force CLI, but the binary does not exist => error
|
||||
if [ -n "$USE_CLI" ] && [ -z "$CONSUL_CMD" ]; then
|
||||
_err "Cannot find the consul binary!"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# use the CLI first
|
||||
if [ -n "$USE_CLI" ] || [ -n "$CONSUL_CMD" ]; then
|
||||
_info "Found consul binary, deploying with CLI"
|
||||
consul_deploy_cli "$CONSUL_CMD" "$CONSUL_PREFIX"
|
||||
else
|
||||
_info "Did not find consul binary, deploying with API"
|
||||
consul_deploy_api "$CONSUL_HTTP_ADDR" "$CONSUL_PREFIX" "$CONSUL_HTTP_TOKEN"
|
||||
fi
|
||||
}
|
||||
|
||||
consul_deploy_api() {
|
||||
CONSUL_HTTP_ADDR="$1"
|
||||
CONSUL_PREFIX="$2"
|
||||
CONSUL_HTTP_TOKEN="$3"
|
||||
|
||||
URL="$CONSUL_HTTP_ADDR/v1/kv/$CONSUL_PREFIX"
|
||||
export _H1="X-Consul-Token: $CONSUL_HTTP_TOKEN"
|
||||
|
||||
if [ -n "$FABIO" ]; then
|
||||
_post "$(cat "$_cfullchain")" "$URL/${_cdomain}-cert.pem" '' "PUT" || return 1
|
||||
_post "$(cat "$_ckey")" "$URL/${_cdomain}-key.pem" '' "PUT" || return 1
|
||||
else
|
||||
_post "$(cat "$_ccert")" "$URL/${_cdomain}/cert.pem" '' "PUT" || return 1
|
||||
_post "$(cat "$_ckey")" "$URL/${_cdomain}/cert.key" '' "PUT" || return 1
|
||||
_post "$(cat "$_cca")" "$URL/${_cdomain}/chain.pem" '' "PUT" || return 1
|
||||
_post "$(cat "$_cfullchain")" "$URL/${_cdomain}/fullchain.pem" '' "PUT" || return 1
|
||||
fi
|
||||
}
|
||||
|
||||
consul_deploy_cli() {
|
||||
CONSUL_CMD="$1"
|
||||
CONSUL_PREFIX="$2"
|
||||
|
||||
if [ -n "$FABIO" ]; then
|
||||
$CONSUL_CMD kv put "${CONSUL_PREFIX}/${_cdomain}-cert.pem" @"$_cfullchain" || return 1
|
||||
$CONSUL_CMD kv put "${CONSUL_PREFIX}/${_cdomain}-key.pem" @"$_ckey" || return 1
|
||||
else
|
||||
$CONSUL_CMD kv put "${CONSUL_PREFIX}/${_cdomain}/cert.pem" value=@"$_ccert" || return 1
|
||||
$CONSUL_CMD kv put "${CONSUL_PREFIX}/${_cdomain}/cert.key" value=@"$_ckey" || return 1
|
||||
$CONSUL_CMD kv put "${CONSUL_PREFIX}/${_cdomain}/chain.pem" value=@"$_cca" || return 1
|
||||
$CONSUL_CMD kv put "${CONSUL_PREFIX}/${_cdomain}/fullchain.pem" value=@"$_cfullchain" || return 1
|
||||
fi
|
||||
}
|
||||
@@ -91,7 +91,7 @@ docker_deploy() {
|
||||
_getdeployconf DEPLOY_DOCKER_CONTAINER_RELOAD_CMD
|
||||
_debug2 DEPLOY_DOCKER_CONTAINER_RELOAD_CMD "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD"
|
||||
if [ "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" ]; then
|
||||
_savedeployconf DEPLOY_DOCKER_CONTAINER_RELOAD_CMD "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD"
|
||||
_savedeployconf DEPLOY_DOCKER_CONTAINER_RELOAD_CMD "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" "base64"
|
||||
fi
|
||||
|
||||
_cid="$(_get_id "$DEPLOY_DOCKER_CONTAINER_LABEL")"
|
||||
@@ -275,6 +275,7 @@ _check_curl_version() {
|
||||
|
||||
if [ "$_major$_minor" -lt "740" ]; then
|
||||
_err "curl v$_cversion doesn't support unit socket"
|
||||
_err "Please upgrade to curl 7.40 or later."
|
||||
return 1
|
||||
fi
|
||||
if [ "$_major$_minor" -lt "750" ]; then
|
||||
|
||||
@@ -69,8 +69,8 @@ exim4_deploy() {
|
||||
cp "$_exim4_conf" "$_backup_conf"
|
||||
|
||||
_info "Modify exim4 conf: $_exim4_conf"
|
||||
if _setopt "$_exim4_conf" "tls_certificate" "=" "$_real_fullchain" \
|
||||
&& _setopt "$_exim4_conf" "tls_privatekey" "=" "$_real_key"; then
|
||||
if _setopt "$_exim4_conf" "tls_certificate" "=" "$_real_fullchain" &&
|
||||
_setopt "$_exim4_conf" "tls_privatekey" "=" "$_real_key"; then
|
||||
_info "Set config success!"
|
||||
else
|
||||
_err "Config exim4 server error, please report bug to us."
|
||||
|
||||
@@ -28,9 +28,11 @@ fritzbox_deploy() {
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
if ! _exists iconv; then
|
||||
if ! _exists perl; then
|
||||
_err "iconv or perl not found"
|
||||
return 1
|
||||
if ! _exists uconv; then
|
||||
if ! _exists perl; then
|
||||
_err "iconv or uconv or perl not found"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -64,9 +66,11 @@ fritzbox_deploy() {
|
||||
_info "Log in to the FRITZ!Box"
|
||||
_fritzbox_challenge="$(_get "${_fritzbox_url}/login_sid.lua" | sed -e 's/^.*<Challenge>//' -e 's/<\/Challenge>.*$//')"
|
||||
if _exists iconv; then
|
||||
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')"
|
||||
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | iconv -f ASCII -t UTF16LE | _digest md5 hex)"
|
||||
elif _exists uconv; then
|
||||
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | uconv -f ASCII -t UTF16LE | _digest md5 hex)"
|
||||
else
|
||||
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | perl -p -e 'use Encode qw/encode/; print encode("UTF-16LE","$_"); $_="";' | md5sum | awk '{print $1}')"
|
||||
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | perl -p -e 'use Encode qw/encode/; print encode("UTF-16LE","$_"); $_="";' | _digest md5 hex)"
|
||||
fi
|
||||
_fritzbox_sid="$(_get "${_fritzbox_url}/login_sid.lua?sid=0000000000000000&username=${_fritzbox_username}&response=${_fritzbox_challenge}-${_fritzbox_hash}" | sed -e 's/^.*<SID>//' -e 's/<\/SID>.*$//')"
|
||||
|
||||
|
||||
@@ -56,9 +56,9 @@ gcore_cdn_deploy() {
|
||||
_request="{\"username\":\"$Le_Deploy_gcore_cdn_username\",\"password\":\"$Le_Deploy_gcore_cdn_password\"}"
|
||||
_debug _request "$_request"
|
||||
export _H1="Content-Type:application/json"
|
||||
_response=$(_post "$_request" "https://api.gcdn.co/auth/signin")
|
||||
_response=$(_post "$_request" "https://api.gcdn.co/auth/jwt/login")
|
||||
_debug _response "$_response"
|
||||
_regex=".*\"token\":\"\([-._0-9A-Za-z]*\)\".*$"
|
||||
_regex=".*\"access\":\"\([-._0-9A-Za-z]*\)\".*$"
|
||||
_debug _regex "$_regex"
|
||||
_token=$(echo "$_response" | sed -n "s/$_regex/\1/p")
|
||||
_debug _token "$_token"
|
||||
@@ -72,12 +72,15 @@ gcore_cdn_deploy() {
|
||||
export _H2="Authorization:Token $_token"
|
||||
_response=$(_get "https://api.gcdn.co/resources")
|
||||
_debug _response "$_response"
|
||||
_regex=".*(\"id\".*?\"cname\":\"$_cdomain\".*?})"
|
||||
_regex="\"primary_resource\":null},"
|
||||
_debug _regex "$_regex"
|
||||
_response=$(echo "$_response" | sed "s/$_regex/$_regex\n/g")
|
||||
_debug _response "$_response"
|
||||
_regex="^.*\"cname\":\"$_cdomain\".*$"
|
||||
_debug _regex "$_regex"
|
||||
_resource=$(echo "$_response" | sed 's/},{/},\n{/g' | _egrep_o "$_regex")
|
||||
_resource=$(echo "$_response" | _egrep_o "$_regex")
|
||||
_debug _resource "$_resource"
|
||||
_regex=".*\"id\":\([0-9]*\).*\"rules\".*$"
|
||||
_regex=".*\"id\":\([0-9]*\).*$"
|
||||
_debug _regex "$_regex"
|
||||
_resourceId=$(echo "$_resource" | sed -n "s/$_regex/\1/p")
|
||||
_debug _resourceId "$_resourceId"
|
||||
|
||||
@@ -54,11 +54,6 @@ haproxy_deploy() {
|
||||
DEPLOY_HAPROXY_ISSUER_DEFAULT="no"
|
||||
DEPLOY_HAPROXY_RELOAD_DEFAULT="true"
|
||||
|
||||
if [ -f "${DOMAIN_CONF}" ]; then
|
||||
# shellcheck disable=SC1090
|
||||
. "${DOMAIN_CONF}"
|
||||
fi
|
||||
|
||||
_debug _cdomain "${_cdomain}"
|
||||
_debug _ckey "${_ckey}"
|
||||
_debug _ccert "${_ccert}"
|
||||
@@ -66,6 +61,8 @@ haproxy_deploy() {
|
||||
_debug _cfullchain "${_cfullchain}"
|
||||
|
||||
# PEM_PATH is optional. If not provided then assume "${DEPLOY_HAPROXY_PEM_PATH_DEFAULT}"
|
||||
_getdeployconf DEPLOY_HAPROXY_PEM_PATH
|
||||
_debug2 DEPLOY_HAPROXY_PEM_PATH "${DEPLOY_HAPROXY_PEM_PATH}"
|
||||
if [ -n "${DEPLOY_HAPROXY_PEM_PATH}" ]; then
|
||||
Le_Deploy_haproxy_pem_path="${DEPLOY_HAPROXY_PEM_PATH}"
|
||||
_savedomainconf Le_Deploy_haproxy_pem_path "${Le_Deploy_haproxy_pem_path}"
|
||||
@@ -82,6 +79,8 @@ haproxy_deploy() {
|
||||
fi
|
||||
|
||||
# PEM_NAME is optional. If not provided then assume "${DEPLOY_HAPROXY_PEM_NAME_DEFAULT}"
|
||||
_getdeployconf DEPLOY_HAPROXY_PEM_NAME
|
||||
_debug2 DEPLOY_HAPROXY_PEM_NAME "${DEPLOY_HAPROXY_PEM_NAME}"
|
||||
if [ -n "${DEPLOY_HAPROXY_PEM_NAME}" ]; then
|
||||
Le_Deploy_haproxy_pem_name="${DEPLOY_HAPROXY_PEM_NAME}"
|
||||
_savedomainconf Le_Deploy_haproxy_pem_name "${Le_Deploy_haproxy_pem_name}"
|
||||
@@ -90,6 +89,8 @@ haproxy_deploy() {
|
||||
fi
|
||||
|
||||
# BUNDLE is optional. If not provided then assume "${DEPLOY_HAPROXY_BUNDLE_DEFAULT}"
|
||||
_getdeployconf DEPLOY_HAPROXY_BUNDLE
|
||||
_debug2 DEPLOY_HAPROXY_BUNDLE "${DEPLOY_HAPROXY_BUNDLE}"
|
||||
if [ -n "${DEPLOY_HAPROXY_BUNDLE}" ]; then
|
||||
Le_Deploy_haproxy_bundle="${DEPLOY_HAPROXY_BUNDLE}"
|
||||
_savedomainconf Le_Deploy_haproxy_bundle "${Le_Deploy_haproxy_bundle}"
|
||||
@@ -98,6 +99,8 @@ haproxy_deploy() {
|
||||
fi
|
||||
|
||||
# ISSUER is optional. If not provided then assume "${DEPLOY_HAPROXY_ISSUER_DEFAULT}"
|
||||
_getdeployconf DEPLOY_HAPROXY_ISSUER
|
||||
_debug2 DEPLOY_HAPROXY_ISSUER "${DEPLOY_HAPROXY_ISSUER}"
|
||||
if [ -n "${DEPLOY_HAPROXY_ISSUER}" ]; then
|
||||
Le_Deploy_haproxy_issuer="${DEPLOY_HAPROXY_ISSUER}"
|
||||
_savedomainconf Le_Deploy_haproxy_issuer "${Le_Deploy_haproxy_issuer}"
|
||||
@@ -106,6 +109,8 @@ haproxy_deploy() {
|
||||
fi
|
||||
|
||||
# RELOAD is optional. If not provided then assume "${DEPLOY_HAPROXY_RELOAD_DEFAULT}"
|
||||
_getdeployconf DEPLOY_HAPROXY_RELOAD
|
||||
_debug2 DEPLOY_HAPROXY_RELOAD "${DEPLOY_HAPROXY_RELOAD}"
|
||||
if [ -n "${DEPLOY_HAPROXY_RELOAD}" ]; then
|
||||
Le_Deploy_haproxy_reload="${DEPLOY_HAPROXY_RELOAD}"
|
||||
_savedomainconf Le_Deploy_haproxy_reload "${Le_Deploy_haproxy_reload}"
|
||||
@@ -190,7 +195,7 @@ haproxy_deploy() {
|
||||
_info "Updating OCSP stapling info"
|
||||
_debug _ocsp "${_ocsp}"
|
||||
_info "Extracting OCSP URL"
|
||||
_ocsp_url=$(openssl x509 -noout -ocsp_uri -in "${_pem}")
|
||||
_ocsp_url=$(${ACME_OPENSSL_BIN:-openssl} x509 -noout -ocsp_uri -in "${_pem}")
|
||||
_debug _ocsp_url "${_ocsp_url}"
|
||||
|
||||
# Only process OCSP if URL was present
|
||||
@@ -203,9 +208,9 @@ haproxy_deploy() {
|
||||
# Only process the certificate if we have a .issuer file
|
||||
if [ -r "${_issuer}" ]; then
|
||||
# Check if issuer cert is also a root CA cert
|
||||
_subjectdn=$(openssl x509 -in "${_issuer}" -subject -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10)
|
||||
_subjectdn=$(${ACME_OPENSSL_BIN:-openssl} x509 -in "${_issuer}" -subject -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10)
|
||||
_debug _subjectdn "${_subjectdn}"
|
||||
_issuerdn=$(openssl x509 -in "${_issuer}" -issuer -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10)
|
||||
_issuerdn=$(${ACME_OPENSSL_BIN:-openssl} x509 -in "${_issuer}" -issuer -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10)
|
||||
_debug _issuerdn "${_issuerdn}"
|
||||
_info "Requesting OCSP response"
|
||||
# If the issuer is a CA cert then our command line has "-CAfile" added
|
||||
@@ -216,7 +221,7 @@ haproxy_deploy() {
|
||||
fi
|
||||
_debug _cafile_argument "${_cafile_argument}"
|
||||
# if OpenSSL/LibreSSL is v1.1 or above, the format for the -header option has changed
|
||||
_openssl_version=$(openssl version | cut -d' ' -f2)
|
||||
_openssl_version=$(${ACME_OPENSSL_BIN:-openssl} version | cut -d' ' -f2)
|
||||
_debug _openssl_version "${_openssl_version}"
|
||||
_openssl_major=$(echo "${_openssl_version}" | cut -d '.' -f1)
|
||||
_openssl_minor=$(echo "${_openssl_version}" | cut -d '.' -f2)
|
||||
@@ -226,7 +231,7 @@ haproxy_deploy() {
|
||||
_header_sep=" "
|
||||
fi
|
||||
# Request the OCSP response from the issuer and store it
|
||||
_openssl_ocsp_cmd="openssl ocsp \
|
||||
_openssl_ocsp_cmd="${ACME_OPENSSL_BIN:-openssl} ocsp \
|
||||
-issuer \"${_issuer}\" \
|
||||
-cert \"${_pem}\" \
|
||||
-url \"${_ocsp_url}\" \
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env sh
|
||||
# If certificate already exist it will update only cert and key not touching other parameter
|
||||
# If certificate doesn't exist it will only upload cert and key and not set other parameter
|
||||
# If certificate already exists it will update only cert and key, not touching other parameters
|
||||
# If certificate doesn't exist it will only upload cert and key, and not set other parameters
|
||||
# Note that we deploy full chain
|
||||
# Written by Geoffroi Genot <ggenot@voxbone.com>
|
||||
|
||||
@@ -45,7 +45,7 @@ kong_deploy() {
|
||||
#Generate data for request (Multipart/form-data with mixed content)
|
||||
if [ -z "$ssl_uuid" ]; then
|
||||
#set sni to domain
|
||||
content="--$delim${nl}Content-Disposition: form-data; name=\"snis\"${nl}${nl}$_cdomain"
|
||||
content="--$delim${nl}Content-Disposition: form-data; name=\"snis[]\"${nl}${nl}$_cdomain"
|
||||
fi
|
||||
#add key
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")"
|
||||
|
||||
280
deploy/lighttpd.sh
Normal file
280
deploy/lighttpd.sh
Normal file
@@ -0,0 +1,280 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Script for acme.sh to deploy certificates to lighttpd
|
||||
#
|
||||
# The following variables can be exported:
|
||||
#
|
||||
# export DEPLOY_LIGHTTPD_PEM_NAME="${domain}.pem"
|
||||
#
|
||||
# Defines the name of the PEM file.
|
||||
# Defaults to "<domain>.pem"
|
||||
#
|
||||
# export DEPLOY_LIGHTTPD_PEM_PATH="/etc/lighttpd"
|
||||
#
|
||||
# Defines location of PEM file for Lighttpd.
|
||||
# Defaults to /etc/lighttpd
|
||||
#
|
||||
# export DEPLOY_LIGHTTPD_RELOAD="systemctl reload lighttpd"
|
||||
#
|
||||
# OPTIONAL: Reload command used post deploy
|
||||
# This defaults to be a no-op (ie "true").
|
||||
# It is strongly recommended to set this something that makes sense
|
||||
# for your distro.
|
||||
#
|
||||
# export DEPLOY_LIGHTTPD_ISSUER="yes"
|
||||
#
|
||||
# OPTIONAL: Places CA file as "${DEPLOY_LIGHTTPD_PEM}.issuer"
|
||||
# Note: Required for OCSP stapling to work
|
||||
#
|
||||
# export DEPLOY_LIGHTTPD_BUNDLE="no"
|
||||
#
|
||||
# OPTIONAL: Deploy this certificate as part of a multi-cert bundle
|
||||
# This adds a suffix to the certificate based on the certificate type
|
||||
# eg RSA certificates will have .rsa as a suffix to the file name
|
||||
# Lighttpd will load all certificates and provide one or the other
|
||||
# depending on client capabilities
|
||||
# Note: This functionality requires Lighttpd was compiled against
|
||||
# a version of OpenSSL that supports this.
|
||||
#
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#domain keyfile certfile cafile fullchain
|
||||
lighttpd_deploy() {
|
||||
_cdomain="$1"
|
||||
_ckey="$2"
|
||||
_ccert="$3"
|
||||
_cca="$4"
|
||||
_cfullchain="$5"
|
||||
|
||||
# Some defaults
|
||||
DEPLOY_LIGHTTPD_PEM_PATH_DEFAULT="/etc/lighttpd"
|
||||
DEPLOY_LIGHTTPD_PEM_NAME_DEFAULT="${_cdomain}.pem"
|
||||
DEPLOY_LIGHTTPD_BUNDLE_DEFAULT="no"
|
||||
DEPLOY_LIGHTTPD_ISSUER_DEFAULT="yes"
|
||||
DEPLOY_LIGHTTPD_RELOAD_DEFAULT="true"
|
||||
|
||||
_debug _cdomain "${_cdomain}"
|
||||
_debug _ckey "${_ckey}"
|
||||
_debug _ccert "${_ccert}"
|
||||
_debug _cca "${_cca}"
|
||||
_debug _cfullchain "${_cfullchain}"
|
||||
|
||||
# PEM_PATH is optional. If not provided then assume "${DEPLOY_LIGHTTPD_PEM_PATH_DEFAULT}"
|
||||
_getdeployconf DEPLOY_LIGHTTPD_PEM_PATH
|
||||
_debug2 DEPLOY_LIGHTTPD_PEM_PATH "${DEPLOY_LIGHTTPD_PEM_PATH}"
|
||||
if [ -n "${DEPLOY_LIGHTTPD_PEM_PATH}" ]; then
|
||||
Le_Deploy_lighttpd_pem_path="${DEPLOY_LIGHTTPD_PEM_PATH}"
|
||||
_savedomainconf Le_Deploy_lighttpd_pem_path "${Le_Deploy_lighttpd_pem_path}"
|
||||
elif [ -z "${Le_Deploy_lighttpd_pem_path}" ]; then
|
||||
Le_Deploy_lighttpd_pem_path="${DEPLOY_LIGHTTPD_PEM_PATH_DEFAULT}"
|
||||
fi
|
||||
|
||||
# Ensure PEM_PATH exists
|
||||
if [ -d "${Le_Deploy_lighttpd_pem_path}" ]; then
|
||||
_debug "PEM_PATH ${Le_Deploy_lighttpd_pem_path} exists"
|
||||
else
|
||||
_err "PEM_PATH ${Le_Deploy_lighttpd_pem_path} does not exist"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# PEM_NAME is optional. If not provided then assume "${DEPLOY_LIGHTTPD_PEM_NAME_DEFAULT}"
|
||||
_getdeployconf DEPLOY_LIGHTTPD_PEM_NAME
|
||||
_debug2 DEPLOY_LIGHTTPD_PEM_NAME "${DEPLOY_LIGHTTPD_PEM_NAME}"
|
||||
if [ -n "${DEPLOY_LIGHTTPD_PEM_NAME}" ]; then
|
||||
Le_Deploy_lighttpd_pem_name="${DEPLOY_LIGHTTPD_PEM_NAME}"
|
||||
_savedomainconf Le_Deploy_lighttpd_pem_name "${Le_Deploy_lighttpd_pem_name}"
|
||||
elif [ -z "${Le_Deploy_lighttpd_pem_name}" ]; then
|
||||
Le_Deploy_lighttpd_pem_name="${DEPLOY_LIGHTTPD_PEM_NAME_DEFAULT}"
|
||||
fi
|
||||
|
||||
# BUNDLE is optional. If not provided then assume "${DEPLOY_LIGHTTPD_BUNDLE_DEFAULT}"
|
||||
_getdeployconf DEPLOY_LIGHTTPD_BUNDLE
|
||||
_debug2 DEPLOY_LIGHTTPD_BUNDLE "${DEPLOY_LIGHTTPD_BUNDLE}"
|
||||
if [ -n "${DEPLOY_LIGHTTPD_BUNDLE}" ]; then
|
||||
Le_Deploy_lighttpd_bundle="${DEPLOY_LIGHTTPD_BUNDLE}"
|
||||
_savedomainconf Le_Deploy_lighttpd_bundle "${Le_Deploy_lighttpd_bundle}"
|
||||
elif [ -z "${Le_Deploy_lighttpd_bundle}" ]; then
|
||||
Le_Deploy_lighttpd_bundle="${DEPLOY_LIGHTTPD_BUNDLE_DEFAULT}"
|
||||
fi
|
||||
|
||||
# ISSUER is optional. If not provided then assume "${DEPLOY_LIGHTTPD_ISSUER_DEFAULT}"
|
||||
_getdeployconf DEPLOY_LIGHTTPD_ISSUER
|
||||
_debug2 DEPLOY_LIGHTTPD_ISSUER "${DEPLOY_LIGHTTPD_ISSUER}"
|
||||
if [ -n "${DEPLOY_LIGHTTPD_ISSUER}" ]; then
|
||||
Le_Deploy_lighttpd_issuer="${DEPLOY_LIGHTTPD_ISSUER}"
|
||||
_savedomainconf Le_Deploy_lighttpd_issuer "${Le_Deploy_lighttpd_issuer}"
|
||||
elif [ -z "${Le_Deploy_lighttpd_issuer}" ]; then
|
||||
Le_Deploy_lighttpd_issuer="${DEPLOY_LIGHTTPD_ISSUER_DEFAULT}"
|
||||
fi
|
||||
|
||||
# RELOAD is optional. If not provided then assume "${DEPLOY_LIGHTTPD_RELOAD_DEFAULT}"
|
||||
_getdeployconf DEPLOY_LIGHTTPD_RELOAD
|
||||
_debug2 DEPLOY_LIGHTTPD_RELOAD "${DEPLOY_LIGHTTPD_RELOAD}"
|
||||
if [ -n "${DEPLOY_LIGHTTPD_RELOAD}" ]; then
|
||||
Le_Deploy_lighttpd_reload="${DEPLOY_LIGHTTPD_RELOAD}"
|
||||
_savedomainconf Le_Deploy_lighttpd_reload "${Le_Deploy_lighttpd_reload}"
|
||||
elif [ -z "${Le_Deploy_lighttpd_reload}" ]; then
|
||||
Le_Deploy_lighttpd_reload="${DEPLOY_LIGHTTPD_RELOAD_DEFAULT}"
|
||||
fi
|
||||
|
||||
# Set the suffix depending if we are creating a bundle or not
|
||||
if [ "${Le_Deploy_lighttpd_bundle}" = "yes" ]; then
|
||||
_info "Bundle creation requested"
|
||||
# Initialise $Le_Keylength if its not already set
|
||||
if [ -z "${Le_Keylength}" ]; then
|
||||
Le_Keylength=""
|
||||
fi
|
||||
if _isEccKey "${Le_Keylength}"; then
|
||||
_info "ECC key type detected"
|
||||
_suffix=".ecdsa"
|
||||
else
|
||||
_info "RSA key type detected"
|
||||
_suffix=".rsa"
|
||||
fi
|
||||
else
|
||||
_suffix=""
|
||||
fi
|
||||
_debug _suffix "${_suffix}"
|
||||
|
||||
# Set variables for later
|
||||
_pem="${Le_Deploy_lighttpd_pem_path}/${Le_Deploy_lighttpd_pem_name}${_suffix}"
|
||||
_issuer="${_pem}.issuer"
|
||||
_ocsp="${_pem}.ocsp"
|
||||
_reload="${Le_Deploy_lighttpd_reload}"
|
||||
|
||||
_info "Deploying PEM file"
|
||||
# Create a temporary PEM file
|
||||
_temppem="$(_mktemp)"
|
||||
_debug _temppem "${_temppem}"
|
||||
cat "${_ckey}" "${_ccert}" "${_cca}" >"${_temppem}"
|
||||
_ret="$?"
|
||||
|
||||
# Check that we could create the temporary file
|
||||
if [ "${_ret}" != "0" ]; then
|
||||
_err "Error code ${_ret} returned during PEM file creation"
|
||||
[ -f "${_temppem}" ] && rm -f "${_temppem}"
|
||||
return ${_ret}
|
||||
fi
|
||||
|
||||
# Move PEM file into place
|
||||
_info "Moving new certificate into place"
|
||||
_debug _pem "${_pem}"
|
||||
cat "${_temppem}" >"${_pem}"
|
||||
_ret=$?
|
||||
|
||||
# Clean up temp file
|
||||
[ -f "${_temppem}" ] && rm -f "${_temppem}"
|
||||
|
||||
# Deal with any failure of moving PEM file into place
|
||||
if [ "${_ret}" != "0" ]; then
|
||||
_err "Error code ${_ret} returned while moving new certificate into place"
|
||||
return ${_ret}
|
||||
fi
|
||||
|
||||
# Update .issuer file if requested
|
||||
if [ "${Le_Deploy_lighttpd_issuer}" = "yes" ]; then
|
||||
_info "Updating .issuer file"
|
||||
_debug _issuer "${_issuer}"
|
||||
cat "${_cca}" >"${_issuer}"
|
||||
_ret="$?"
|
||||
|
||||
if [ "${_ret}" != "0" ]; then
|
||||
_err "Error code ${_ret} returned while copying issuer/CA certificate into place"
|
||||
return ${_ret}
|
||||
fi
|
||||
else
|
||||
[ -f "${_issuer}" ] && _err "Issuer file update not requested but .issuer file exists"
|
||||
fi
|
||||
|
||||
# Update .ocsp file if certificate was requested with --ocsp/--ocsp-must-staple option
|
||||
if [ -z "${Le_OCSP_Staple}" ]; then
|
||||
Le_OCSP_Staple="0"
|
||||
fi
|
||||
if [ "${Le_OCSP_Staple}" = "1" ]; then
|
||||
_info "Updating OCSP stapling info"
|
||||
_debug _ocsp "${_ocsp}"
|
||||
_info "Extracting OCSP URL"
|
||||
_ocsp_url=$(${ACME_OPENSSL_BIN:-openssl} x509 -noout -ocsp_uri -in "${_pem}")
|
||||
_debug _ocsp_url "${_ocsp_url}"
|
||||
|
||||
# Only process OCSP if URL was present
|
||||
if [ "${_ocsp_url}" != "" ]; then
|
||||
# Extract the hostname from the OCSP URL
|
||||
_info "Extracting OCSP URL"
|
||||
_ocsp_host=$(echo "${_ocsp_url}" | cut -d/ -f3)
|
||||
_debug _ocsp_host "${_ocsp_host}"
|
||||
|
||||
# Only process the certificate if we have a .issuer file
|
||||
if [ -r "${_issuer}" ]; then
|
||||
# Check if issuer cert is also a root CA cert
|
||||
_subjectdn=$(${ACME_OPENSSL_BIN:-openssl} x509 -in "${_issuer}" -subject -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10)
|
||||
_debug _subjectdn "${_subjectdn}"
|
||||
_issuerdn=$(${ACME_OPENSSL_BIN:-openssl} x509 -in "${_issuer}" -issuer -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10)
|
||||
_debug _issuerdn "${_issuerdn}"
|
||||
_info "Requesting OCSP response"
|
||||
# If the issuer is a CA cert then our command line has "-CAfile" added
|
||||
if [ "${_subjectdn}" = "${_issuerdn}" ]; then
|
||||
_cafile_argument="-CAfile \"${_issuer}\""
|
||||
else
|
||||
_cafile_argument=""
|
||||
fi
|
||||
_debug _cafile_argument "${_cafile_argument}"
|
||||
# if OpenSSL/LibreSSL is v1.1 or above, the format for the -header option has changed
|
||||
_openssl_version=$(${ACME_OPENSSL_BIN:-openssl} version | cut -d' ' -f2)
|
||||
_debug _openssl_version "${_openssl_version}"
|
||||
_openssl_major=$(echo "${_openssl_version}" | cut -d '.' -f1)
|
||||
_openssl_minor=$(echo "${_openssl_version}" | cut -d '.' -f2)
|
||||
if [ "${_openssl_major}" -eq "1" ] && [ "${_openssl_minor}" -ge "1" ] || [ "${_openssl_major}" -ge "2" ]; then
|
||||
_header_sep="="
|
||||
else
|
||||
_header_sep=" "
|
||||
fi
|
||||
# Request the OCSP response from the issuer and store it
|
||||
_openssl_ocsp_cmd="${ACME_OPENSSL_BIN:-openssl} ocsp \
|
||||
-issuer \"${_issuer}\" \
|
||||
-cert \"${_pem}\" \
|
||||
-url \"${_ocsp_url}\" \
|
||||
-header Host${_header_sep}\"${_ocsp_host}\" \
|
||||
-respout \"${_ocsp}\" \
|
||||
-verify_other \"${_issuer}\" \
|
||||
${_cafile_argument} \
|
||||
| grep -q \"${_pem}: good\""
|
||||
_debug _openssl_ocsp_cmd "${_openssl_ocsp_cmd}"
|
||||
eval "${_openssl_ocsp_cmd}"
|
||||
_ret=$?
|
||||
else
|
||||
# Non fatal: No issuer file was present so no OCSP stapling file created
|
||||
_err "OCSP stapling in use but no .issuer file was present"
|
||||
fi
|
||||
else
|
||||
# Non fatal: No OCSP url was found int the certificate
|
||||
_err "OCSP update requested but no OCSP URL was found in certificate"
|
||||
fi
|
||||
|
||||
# Non fatal: Check return code of openssl command
|
||||
if [ "${_ret}" != "0" ]; then
|
||||
_err "Updating OCSP stapling failed with return code ${_ret}"
|
||||
fi
|
||||
else
|
||||
# An OCSP file was already present but certificate did not have OCSP extension
|
||||
if [ -f "${_ocsp}" ]; then
|
||||
_err "OCSP was not requested but .ocsp file exists."
|
||||
# Could remove the file at this step, although Lighttpd just ignores it in this case
|
||||
# rm -f "${_ocsp}" || _err "Problem removing stale .ocsp file"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Reload Lighttpd
|
||||
_debug _reload "${_reload}"
|
||||
eval "${_reload}"
|
||||
_ret=$?
|
||||
if [ "${_ret}" != "0" ]; then
|
||||
_err "Error code ${_ret} during reload"
|
||||
return ${_ret}
|
||||
else
|
||||
_info "Reload successful"
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
@@ -27,26 +27,43 @@ mailcow_deploy() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
_ssl_path="${_mailcow_path}/data/assets/ssl/"
|
||||
#Tests if _ssl_path is the mailcow root directory.
|
||||
if [ -f "${_mailcow_path}/generate_config.sh" ]; then
|
||||
_ssl_path="${_mailcow_path}/data/assets/ssl/"
|
||||
else
|
||||
_ssl_path="${_mailcow_path}"
|
||||
fi
|
||||
|
||||
if [ ! -d "$_ssl_path" ]; then
|
||||
_err "Cannot find mailcow ssl path: $_ssl_path"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# ECC or RSA
|
||||
if [ -z "${Le_Keylength}" ]; then
|
||||
Le_Keylength=""
|
||||
fi
|
||||
if _isEccKey "${Le_Keylength}"; then
|
||||
_info "ECC key type detected"
|
||||
_cert_name_prefix="ecdsa-"
|
||||
else
|
||||
_info "RSA key type detected"
|
||||
_cert_name_prefix=""
|
||||
fi
|
||||
_info "Copying key and cert"
|
||||
_real_key="$_ssl_path/key.pem"
|
||||
_real_key="$_ssl_path/${_cert_name_prefix}key.pem"
|
||||
if ! cat "$_ckey" >"$_real_key"; then
|
||||
_err "Error: write key file to: $_real_key"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_real_fullchain="$_ssl_path/cert.pem"
|
||||
_real_fullchain="$_ssl_path/${_cert_name_prefix}cert.pem"
|
||||
if ! cat "$_cfullchain" >"$_real_fullchain"; then
|
||||
_err "Error: write cert file to: $_real_fullchain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
DEFAULT_MAILCOW_RELOAD="cd ${_mailcow_path} && docker-compose restart postfix-mailcow dovecot-mailcow nginx-mailcow"
|
||||
DEFAULT_MAILCOW_RELOAD="docker restart $(docker ps -qaf name=postfix-mailcow); docker restart $(docker ps -qaf name=nginx-mailcow); docker restart $(docker ps -qaf name=dovecot-mailcow)"
|
||||
_reload="${DEPLOY_MAILCOW_RELOAD:-$DEFAULT_MAILCOW_RELOAD}"
|
||||
|
||||
_info "Run reload: $_reload"
|
||||
|
||||
262
deploy/openstack.sh
Normal file
262
deploy/openstack.sh
Normal file
@@ -0,0 +1,262 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# OpenStack Barbican deploy hook
|
||||
#
|
||||
# This requires you to have OpenStackClient and python-barbicanclient
|
||||
# installed.
|
||||
#
|
||||
# You will require Keystone V3 credentials loaded into your environment, which
|
||||
# could be either password or v3applicationcredential type.
|
||||
#
|
||||
# Author: Andy Botting <andy@andybotting.com>
|
||||
|
||||
openstack_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"
|
||||
|
||||
if ! _exists openstack; then
|
||||
_err "OpenStack client not found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_openstack_credentials || return $?
|
||||
|
||||
_info "Generate import pkcs12"
|
||||
_import_pkcs12="$(_mktemp)"
|
||||
if ! _openstack_to_pkcs "$_import_pkcs12" "$_ckey" "$_ccert" "$_cca"; then
|
||||
_err "Error creating pkcs12 certificate"
|
||||
return 1
|
||||
fi
|
||||
_debug _import_pkcs12 "$_import_pkcs12"
|
||||
_base64_pkcs12=$(_base64 "multiline" <"$_import_pkcs12")
|
||||
|
||||
secretHrefs=$(_openstack_get_secrets)
|
||||
_debug secretHrefs "$secretHrefs"
|
||||
_openstack_store_secret || return $?
|
||||
|
||||
if [ -n "$secretHrefs" ]; then
|
||||
_info "Cleaning up existing secret"
|
||||
_openstack_delete_secrets || return $?
|
||||
fi
|
||||
|
||||
_info "Certificate successfully deployed"
|
||||
return 0
|
||||
}
|
||||
|
||||
_openstack_store_secret() {
|
||||
if ! openstack secret store --name "$_cdomain." -t 'application/octet-stream' -e base64 --payload "$_base64_pkcs12"; then
|
||||
_err "Failed to create OpenStack secret"
|
||||
return 1
|
||||
fi
|
||||
return
|
||||
}
|
||||
|
||||
_openstack_delete_secrets() {
|
||||
echo "$secretHrefs" | while read -r secretHref; do
|
||||
_info "Deleting old secret $secretHref"
|
||||
if ! openstack secret delete "$secretHref"; then
|
||||
_err "Failed to delete OpenStack secret"
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
return
|
||||
}
|
||||
|
||||
_openstack_get_secrets() {
|
||||
if ! secretHrefs=$(openstack secret list -f value --name "$_cdomain." | cut -d' ' -f1); then
|
||||
_err "Failed to list secrets"
|
||||
return 1
|
||||
fi
|
||||
echo "$secretHrefs"
|
||||
}
|
||||
|
||||
_openstack_to_pkcs() {
|
||||
# The existing _toPkcs command can't allow an empty password, due to sh
|
||||
# -z test, so copied here and forcing the empty password.
|
||||
_cpfx="$1"
|
||||
_ckey="$2"
|
||||
_ccert="$3"
|
||||
_cca="$4"
|
||||
|
||||
${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" -password "pass:"
|
||||
}
|
||||
|
||||
_openstack_credentials() {
|
||||
_debug "Check OpenStack credentials"
|
||||
|
||||
# If we have OS_AUTH_URL already set in the environment, then assume we want
|
||||
# to use those, otherwise use stored credentials
|
||||
if [ -n "$OS_AUTH_URL" ]; then
|
||||
_debug "OS_AUTH_URL env var found, using environment"
|
||||
else
|
||||
_debug "OS_AUTH_URL not found, loading stored credentials"
|
||||
OS_AUTH_URL="${OS_AUTH_URL:-$(_readaccountconf_mutable OS_AUTH_URL)}"
|
||||
OS_IDENTITY_API_VERSION="${OS_IDENTITY_API_VERSION:-$(_readaccountconf_mutable OS_IDENTITY_API_VERSION)}"
|
||||
OS_AUTH_TYPE="${OS_AUTH_TYPE:-$(_readaccountconf_mutable OS_AUTH_TYPE)}"
|
||||
OS_APPLICATION_CREDENTIAL_ID="${OS_APPLICATION_CREDENTIAL_ID:-$(_readaccountconf_mutable OS_APPLICATION_CREDENTIAL_ID)}"
|
||||
OS_APPLICATION_CREDENTIAL_SECRET="${OS_APPLICATION_CREDENTIAL_SECRET:-$(_readaccountconf_mutable OS_APPLICATION_CREDENTIAL_SECRET)}"
|
||||
OS_USERNAME="${OS_USERNAME:-$(_readaccountconf_mutable OS_USERNAME)}"
|
||||
OS_PASSWORD="${OS_PASSWORD:-$(_readaccountconf_mutable OS_PASSWORD)}"
|
||||
OS_PROJECT_NAME="${OS_PROJECT_NAME:-$(_readaccountconf_mutable OS_PROJECT_NAME)}"
|
||||
OS_PROJECT_ID="${OS_PROJECT_ID:-$(_readaccountconf_mutable OS_PROJECT_ID)}"
|
||||
OS_USER_DOMAIN_NAME="${OS_USER_DOMAIN_NAME:-$(_readaccountconf_mutable OS_USER_DOMAIN_NAME)}"
|
||||
OS_USER_DOMAIN_ID="${OS_USER_DOMAIN_ID:-$(_readaccountconf_mutable OS_USER_DOMAIN_ID)}"
|
||||
OS_PROJECT_DOMAIN_NAME="${OS_PROJECT_DOMAIN_NAME:-$(_readaccountconf_mutable OS_PROJECT_DOMAIN_NAME)}"
|
||||
OS_PROJECT_DOMAIN_ID="${OS_PROJECT_DOMAIN_ID:-$(_readaccountconf_mutable OS_PROJECT_DOMAIN_ID)}"
|
||||
fi
|
||||
|
||||
# Check each var and either save or clear it depending on whether its set.
|
||||
# The helps us clear out old vars in the case where a user may want
|
||||
# to switch between password and app creds
|
||||
_debug "OS_AUTH_URL" "$OS_AUTH_URL"
|
||||
if [ -n "$OS_AUTH_URL" ]; then
|
||||
export OS_AUTH_URL
|
||||
_saveaccountconf_mutable OS_AUTH_URL "$OS_AUTH_URL"
|
||||
else
|
||||
unset OS_AUTH_URL
|
||||
_clearaccountconf SAVED_OS_AUTH_URL
|
||||
fi
|
||||
|
||||
_debug "OS_IDENTITY_API_VERSION" "$OS_IDENTITY_API_VERSION"
|
||||
if [ -n "$OS_IDENTITY_API_VERSION" ]; then
|
||||
export OS_IDENTITY_API_VERSION
|
||||
_saveaccountconf_mutable OS_IDENTITY_API_VERSION "$OS_IDENTITY_API_VERSION"
|
||||
else
|
||||
unset OS_IDENTITY_API_VERSION
|
||||
_clearaccountconf SAVED_OS_IDENTITY_API_VERSION
|
||||
fi
|
||||
|
||||
_debug "OS_AUTH_TYPE" "$OS_AUTH_TYPE"
|
||||
if [ -n "$OS_AUTH_TYPE" ]; then
|
||||
export OS_AUTH_TYPE
|
||||
_saveaccountconf_mutable OS_AUTH_TYPE "$OS_AUTH_TYPE"
|
||||
else
|
||||
unset OS_AUTH_TYPE
|
||||
_clearaccountconf SAVED_OS_AUTH_TYPE
|
||||
fi
|
||||
|
||||
_debug "OS_APPLICATION_CREDENTIAL_ID" "$OS_APPLICATION_CREDENTIAL_ID"
|
||||
if [ -n "$OS_APPLICATION_CREDENTIAL_ID" ]; then
|
||||
export OS_APPLICATION_CREDENTIAL_ID
|
||||
_saveaccountconf_mutable OS_APPLICATION_CREDENTIAL_ID "$OS_APPLICATION_CREDENTIAL_ID"
|
||||
else
|
||||
unset OS_APPLICATION_CREDENTIAL_ID
|
||||
_clearaccountconf SAVED_OS_APPLICATION_CREDENTIAL_ID
|
||||
fi
|
||||
|
||||
_secure_debug "OS_APPLICATION_CREDENTIAL_SECRET" "$OS_APPLICATION_CREDENTIAL_SECRET"
|
||||
if [ -n "$OS_APPLICATION_CREDENTIAL_SECRET" ]; then
|
||||
export OS_APPLICATION_CREDENTIAL_SECRET
|
||||
_saveaccountconf_mutable OS_APPLICATION_CREDENTIAL_SECRET "$OS_APPLICATION_CREDENTIAL_SECRET"
|
||||
else
|
||||
unset OS_APPLICATION_CREDENTIAL_SECRET
|
||||
_clearaccountconf SAVED_OS_APPLICATION_CREDENTIAL_SECRET
|
||||
fi
|
||||
|
||||
_debug "OS_USERNAME" "$OS_USERNAME"
|
||||
if [ -n "$OS_USERNAME" ]; then
|
||||
export OS_USERNAME
|
||||
_saveaccountconf_mutable OS_USERNAME "$OS_USERNAME"
|
||||
else
|
||||
unset OS_USERNAME
|
||||
_clearaccountconf SAVED_OS_USERNAME
|
||||
fi
|
||||
|
||||
_secure_debug "OS_PASSWORD" "$OS_PASSWORD"
|
||||
if [ -n "$OS_PASSWORD" ]; then
|
||||
export OS_PASSWORD
|
||||
_saveaccountconf_mutable OS_PASSWORD "$OS_PASSWORD"
|
||||
else
|
||||
unset OS_PASSWORD
|
||||
_clearaccountconf SAVED_OS_PASSWORD
|
||||
fi
|
||||
|
||||
_debug "OS_PROJECT_NAME" "$OS_PROJECT_NAME"
|
||||
if [ -n "$OS_PROJECT_NAME" ]; then
|
||||
export OS_PROJECT_NAME
|
||||
_saveaccountconf_mutable OS_PROJECT_NAME "$OS_PROJECT_NAME"
|
||||
else
|
||||
unset OS_PROJECT_NAME
|
||||
_clearaccountconf SAVED_OS_PROJECT_NAME
|
||||
fi
|
||||
|
||||
_debug "OS_PROJECT_ID" "$OS_PROJECT_ID"
|
||||
if [ -n "$OS_PROJECT_ID" ]; then
|
||||
export OS_PROJECT_ID
|
||||
_saveaccountconf_mutable OS_PROJECT_ID "$OS_PROJECT_ID"
|
||||
else
|
||||
unset OS_PROJECT_ID
|
||||
_clearaccountconf SAVED_OS_PROJECT_ID
|
||||
fi
|
||||
|
||||
_debug "OS_USER_DOMAIN_NAME" "$OS_USER_DOMAIN_NAME"
|
||||
if [ -n "$OS_USER_DOMAIN_NAME" ]; then
|
||||
export OS_USER_DOMAIN_NAME
|
||||
_saveaccountconf_mutable OS_USER_DOMAIN_NAME "$OS_USER_DOMAIN_NAME"
|
||||
else
|
||||
unset OS_USER_DOMAIN_NAME
|
||||
_clearaccountconf SAVED_OS_USER_DOMAIN_NAME
|
||||
fi
|
||||
|
||||
_debug "OS_USER_DOMAIN_ID" "$OS_USER_DOMAIN_ID"
|
||||
if [ -n "$OS_USER_DOMAIN_ID" ]; then
|
||||
export OS_USER_DOMAIN_ID
|
||||
_saveaccountconf_mutable OS_USER_DOMAIN_ID "$OS_USER_DOMAIN_ID"
|
||||
else
|
||||
unset OS_USER_DOMAIN_ID
|
||||
_clearaccountconf SAVED_OS_USER_DOMAIN_ID
|
||||
fi
|
||||
|
||||
_debug "OS_PROJECT_DOMAIN_NAME" "$OS_PROJECT_DOMAIN_NAME"
|
||||
if [ -n "$OS_PROJECT_DOMAIN_NAME" ]; then
|
||||
export OS_PROJECT_DOMAIN_NAME
|
||||
_saveaccountconf_mutable OS_PROJECT_DOMAIN_NAME "$OS_PROJECT_DOMAIN_NAME"
|
||||
else
|
||||
unset OS_PROJECT_DOMAIN_NAME
|
||||
_clearaccountconf SAVED_OS_PROJECT_DOMAIN_NAME
|
||||
fi
|
||||
|
||||
_debug "OS_PROJECT_DOMAIN_ID" "$OS_PROJECT_DOMAIN_ID"
|
||||
if [ -n "$OS_PROJECT_DOMAIN_ID" ]; then
|
||||
export OS_PROJECT_DOMAIN_ID
|
||||
_saveaccountconf_mutable OS_PROJECT_DOMAIN_ID "$OS_PROJECT_DOMAIN_ID"
|
||||
else
|
||||
unset OS_PROJECT_DOMAIN_ID
|
||||
_clearaccountconf SAVED_OS_PROJECT_DOMAIN_ID
|
||||
fi
|
||||
|
||||
if [ "$OS_AUTH_TYPE" = "v3applicationcredential" ]; then
|
||||
# Application Credential auth
|
||||
if [ -z "$OS_APPLICATION_CREDENTIAL_ID" ] || [ -z "$OS_APPLICATION_CREDENTIAL_SECRET" ]; then
|
||||
_err "When using OpenStack application credentials, OS_APPLICATION_CREDENTIAL_ID"
|
||||
_err "and OS_APPLICATION_CREDENTIAL_SECRET must be set."
|
||||
_err "Please check your credentials and try again."
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
# Password auth
|
||||
if [ -z "$OS_USERNAME" ] || [ -z "$OS_PASSWORD" ]; then
|
||||
_err "OpenStack username or password not found."
|
||||
_err "Please check your credentials and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$OS_PROJECT_NAME" ] && [ -z "$OS_PROJECT_ID" ]; then
|
||||
_err "When using password authentication, OS_PROJECT_NAME or"
|
||||
_err "OS_PROJECT_ID must be set."
|
||||
_err "Please check your credentials and try again."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
123
deploy/peplink.sh
Normal file
123
deploy/peplink.sh
Normal file
@@ -0,0 +1,123 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Script to deploy cert to Peplink Routers
|
||||
#
|
||||
# The following environment variables must be set:
|
||||
#
|
||||
# PEPLINK_Hostname - Peplink hostname
|
||||
# PEPLINK_Username - Peplink username to login
|
||||
# PEPLINK_Password - Peplink password to login
|
||||
#
|
||||
# The following environmental variables may be set if you don't like their
|
||||
# default values:
|
||||
#
|
||||
# PEPLINK_Certtype - Certificate type to target for replacement
|
||||
# defaults to "webadmin", can be one of:
|
||||
# * "chub" (ContentHub)
|
||||
# * "openvpn" (OpenVPN CA)
|
||||
# * "portal" (Captive Portal SSL)
|
||||
# * "webadmin" (Web Admin SSL)
|
||||
# * "webproxy" (Proxy Root CA)
|
||||
# * "wwan_ca" (Wi-Fi WAN CA)
|
||||
# * "wwan_client" (Wi-Fi WAN Client)
|
||||
# PEPLINK_Scheme - defaults to "https"
|
||||
# PEPLINK_Port - defaults to "443"
|
||||
#
|
||||
#returns 0 means success, otherwise error.
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
_peplink_get_cookie_data() {
|
||||
grep -i "\W$1=" | grep -i "^Set-Cookie:" | _tail_n 1 | _egrep_o "$1=[^;]*;" | tr -d ';'
|
||||
}
|
||||
|
||||
#domain keyfile certfile cafile fullchain
|
||||
peplink_deploy() {
|
||||
|
||||
_cdomain="$1"
|
||||
_ckey="$2"
|
||||
_cfullchain="$5"
|
||||
|
||||
_debug _cdomain "$_cdomain"
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
_debug _ckey "$_ckey"
|
||||
|
||||
# Get Hostname, Username and Password, but don't save until we successfully authenticate
|
||||
_getdeployconf PEPLINK_Hostname
|
||||
_getdeployconf PEPLINK_Username
|
||||
_getdeployconf PEPLINK_Password
|
||||
if [ -z "${PEPLINK_Hostname:-}" ] || [ -z "${PEPLINK_Username:-}" ] || [ -z "${PEPLINK_Password:-}" ]; then
|
||||
_err "PEPLINK_Hostname & PEPLINK_Username & PEPLINK_Password must be set"
|
||||
return 1
|
||||
fi
|
||||
_debug2 PEPLINK_Hostname "$PEPLINK_Hostname"
|
||||
_debug2 PEPLINK_Username "$PEPLINK_Username"
|
||||
_secure_debug2 PEPLINK_Password "$PEPLINK_Password"
|
||||
|
||||
# Optional certificate type, scheme, and port for Peplink
|
||||
_getdeployconf PEPLINK_Certtype
|
||||
_getdeployconf PEPLINK_Scheme
|
||||
_getdeployconf PEPLINK_Port
|
||||
|
||||
# Don't save the certificate type until we verify it exists and is supported
|
||||
_savedeployconf PEPLINK_Scheme "$PEPLINK_Scheme"
|
||||
_savedeployconf PEPLINK_Port "$PEPLINK_Port"
|
||||
|
||||
# Default vaules for certificate type, scheme, and port
|
||||
[ -n "${PEPLINK_Certtype}" ] || PEPLINK_Certtype="webadmin"
|
||||
[ -n "${PEPLINK_Scheme}" ] || PEPLINK_Scheme="https"
|
||||
[ -n "${PEPLINK_Port}" ] || PEPLINK_Port="443"
|
||||
|
||||
_debug2 PEPLINK_Certtype "$PEPLINK_Certtype"
|
||||
_debug2 PEPLINK_Scheme "$PEPLINK_Scheme"
|
||||
_debug2 PEPLINK_Port "$PEPLINK_Port"
|
||||
|
||||
_base_url="$PEPLINK_Scheme://$PEPLINK_Hostname:$PEPLINK_Port"
|
||||
_debug _base_url "$_base_url"
|
||||
|
||||
# Login, get the auth token from the cookie
|
||||
_info "Logging into $PEPLINK_Hostname:$PEPLINK_Port"
|
||||
encoded_username="$(printf "%s" "$PEPLINK_Username" | _url_encode)"
|
||||
encoded_password="$(printf "%s" "$PEPLINK_Password" | _url_encode)"
|
||||
response=$(_post "func=login&username=$encoded_username&password=$encoded_password" "$_base_url/cgi-bin/MANGA/api.cgi")
|
||||
auth_token=$(_peplink_get_cookie_data "bauth" <"$HTTP_HEADER")
|
||||
_debug3 response "$response"
|
||||
_debug auth_token "$auth_token"
|
||||
|
||||
if [ -z "$auth_token" ]; then
|
||||
_err "Unable to authenticate to $PEPLINK_Hostname:$PEPLINK_Port using $PEPLINK_Scheme."
|
||||
_err "Check your username and password."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_H1="Cookie: $auth_token"
|
||||
export _H1
|
||||
_debug2 H1 "${_H1}"
|
||||
|
||||
# Now that we know the hostnameusername and password are good, save them
|
||||
_savedeployconf PEPLINK_Hostname "$PEPLINK_Hostname"
|
||||
_savedeployconf PEPLINK_Username "$PEPLINK_Username"
|
||||
_savedeployconf PEPLINK_Password "$PEPLINK_Password"
|
||||
|
||||
_info "Generate form POST request"
|
||||
|
||||
encoded_key="$(_url_encode <"$_ckey")"
|
||||
encoded_fullchain="$(_url_encode <"$_cfullchain")"
|
||||
body="cert_type=$PEPLINK_Certtype&cert_uid=§ion=CERT_modify&key_pem=$encoded_key&key_pem_passphrase=&key_pem_passphrase_confirm=&cert_pem=$encoded_fullchain"
|
||||
_debug3 body "$body"
|
||||
|
||||
_info "Upload $PEPLINK_Certtype certificate to the Peplink"
|
||||
|
||||
response=$(_post "$body" "$_base_url/cgi-bin/MANGA/admin.cgi")
|
||||
_debug3 response "$response"
|
||||
|
||||
if echo "$response" | grep 'Success' >/dev/null; then
|
||||
# We've verified this certificate type is valid, so save it
|
||||
_savedeployconf PEPLINK_Certtype "$PEPLINK_Certtype"
|
||||
_info "Certificate was updated"
|
||||
return 0
|
||||
else
|
||||
_err "Unable to update certificate, error code $response"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
@@ -33,15 +33,7 @@ ssh_deploy() {
|
||||
_ccert="$3"
|
||||
_cca="$4"
|
||||
_cfullchain="$5"
|
||||
_err_code=0
|
||||
_cmdstr=""
|
||||
_backupprefix=""
|
||||
_backupdir=""
|
||||
|
||||
if [ -f "$DOMAIN_CONF" ]; then
|
||||
# shellcheck disable=SC1090
|
||||
. "$DOMAIN_CONF"
|
||||
fi
|
||||
_deploy_ssh_servers=""
|
||||
|
||||
_debug _cdomain "$_cdomain"
|
||||
_debug _ckey "$_ckey"
|
||||
@@ -50,6 +42,8 @@ ssh_deploy() {
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
# USER is required to login by SSH to remote host.
|
||||
_getdeployconf DEPLOY_SSH_USER
|
||||
_debug2 DEPLOY_SSH_USER "$DEPLOY_SSH_USER"
|
||||
if [ -z "$DEPLOY_SSH_USER" ]; then
|
||||
if [ -z "$Le_Deploy_ssh_user" ]; then
|
||||
_err "DEPLOY_SSH_USER not defined."
|
||||
@@ -61,6 +55,8 @@ ssh_deploy() {
|
||||
fi
|
||||
|
||||
# SERVER is optional. If not provided then use _cdomain
|
||||
_getdeployconf DEPLOY_SSH_SERVER
|
||||
_debug2 DEPLOY_SSH_SERVER "$DEPLOY_SSH_SERVER"
|
||||
if [ -n "$DEPLOY_SSH_SERVER" ]; then
|
||||
Le_Deploy_ssh_server="$DEPLOY_SSH_SERVER"
|
||||
_savedomainconf Le_Deploy_ssh_server "$Le_Deploy_ssh_server"
|
||||
@@ -69,6 +65,8 @@ ssh_deploy() {
|
||||
fi
|
||||
|
||||
# CMD is optional. If not provided then use ssh
|
||||
_getdeployconf DEPLOY_SSH_CMD
|
||||
_debug2 DEPLOY_SSH_CMD "$DEPLOY_SSH_CMD"
|
||||
if [ -n "$DEPLOY_SSH_CMD" ]; then
|
||||
Le_Deploy_ssh_cmd="$DEPLOY_SSH_CMD"
|
||||
_savedomainconf Le_Deploy_ssh_cmd "$Le_Deploy_ssh_cmd"
|
||||
@@ -77,6 +75,8 @@ ssh_deploy() {
|
||||
fi
|
||||
|
||||
# BACKUP is optional. If not provided then default to previously saved value or yes.
|
||||
_getdeployconf DEPLOY_SSH_BACKUP
|
||||
_debug2 DEPLOY_SSH_BACKUP "$DEPLOY_SSH_BACKUP"
|
||||
if [ "$DEPLOY_SSH_BACKUP" = "no" ]; then
|
||||
Le_Deploy_ssh_backup="no"
|
||||
elif [ -z "$Le_Deploy_ssh_backup" ] || [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
||||
@@ -85,6 +85,8 @@ ssh_deploy() {
|
||||
_savedomainconf Le_Deploy_ssh_backup "$Le_Deploy_ssh_backup"
|
||||
|
||||
# BACKUP_PATH is optional. If not provided then default to previously saved value or .acme_ssh_deploy
|
||||
_getdeployconf DEPLOY_SSH_BACKUP_PATH
|
||||
_debug2 DEPLOY_SSH_BACKUP_PATH "$DEPLOY_SSH_BACKUP_PATH"
|
||||
if [ -n "$DEPLOY_SSH_BACKUP_PATH" ]; then
|
||||
Le_Deploy_ssh_backup_path="$DEPLOY_SSH_BACKUP_PATH"
|
||||
elif [ -z "$Le_Deploy_ssh_backup_path" ]; then
|
||||
@@ -94,6 +96,8 @@ ssh_deploy() {
|
||||
|
||||
# MULTI_CALL is optional. If not provided then default to previously saved
|
||||
# value (which may be undefined... equivalent to "no").
|
||||
_getdeployconf DEPLOY_SSH_MULTI_CALL
|
||||
_debug2 DEPLOY_SSH_MULTI_CALL "$DEPLOY_SSH_MULTI_CALL"
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
Le_Deploy_ssh_multi_call="yes"
|
||||
_savedomainconf Le_Deploy_ssh_multi_call "$Le_Deploy_ssh_multi_call"
|
||||
@@ -102,6 +106,18 @@ ssh_deploy() {
|
||||
_cleardomainconf Le_Deploy_ssh_multi_call
|
||||
fi
|
||||
|
||||
_deploy_ssh_servers=$Le_Deploy_ssh_server
|
||||
for Le_Deploy_ssh_server in $_deploy_ssh_servers; do
|
||||
_ssh_deploy
|
||||
done
|
||||
}
|
||||
|
||||
_ssh_deploy() {
|
||||
_err_code=0
|
||||
_cmdstr=""
|
||||
_backupprefix=""
|
||||
_backupdir=""
|
||||
|
||||
_info "Deploy certificates to remote server $Le_Deploy_ssh_user@$Le_Deploy_ssh_server"
|
||||
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
||||
_info "Using MULTI_CALL mode... Required commands sent in multiple calls to remote host"
|
||||
@@ -132,6 +148,8 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
|
||||
|
||||
# KEYFILE is optional.
|
||||
# If provided then private key will be copied to provided filename.
|
||||
_getdeployconf DEPLOY_SSH_KEYFILE
|
||||
_debug2 DEPLOY_SSH_KEYFILE "$DEPLOY_SSH_KEYFILE"
|
||||
if [ -n "$DEPLOY_SSH_KEYFILE" ]; then
|
||||
Le_Deploy_ssh_keyfile="$DEPLOY_SSH_KEYFILE"
|
||||
_savedomainconf Le_Deploy_ssh_keyfile "$Le_Deploy_ssh_keyfile"
|
||||
@@ -154,6 +172,8 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
|
||||
|
||||
# CERTFILE is optional.
|
||||
# If provided then certificate will be copied or appended to provided filename.
|
||||
_getdeployconf DEPLOY_SSH_CERTFILE
|
||||
_debug2 DEPLOY_SSH_CERTFILE "$DEPLOY_SSH_CERTFILE"
|
||||
if [ -n "$DEPLOY_SSH_CERTFILE" ]; then
|
||||
Le_Deploy_ssh_certfile="$DEPLOY_SSH_CERTFILE"
|
||||
_savedomainconf Le_Deploy_ssh_certfile "$Le_Deploy_ssh_certfile"
|
||||
@@ -180,14 +200,16 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
|
||||
|
||||
# CAFILE is optional.
|
||||
# If provided then CA intermediate certificate will be copied or appended to provided filename.
|
||||
_getdeployconf DEPLOY_SSH_CAFILE
|
||||
_debug2 DEPLOY_SSH_CAFILE "$DEPLOY_SSH_CAFILE"
|
||||
if [ -n "$DEPLOY_SSH_CAFILE" ]; then
|
||||
Le_Deploy_ssh_cafile="$DEPLOY_SSH_CAFILE"
|
||||
_savedomainconf Le_Deploy_ssh_cafile "$Le_Deploy_ssh_cafile"
|
||||
fi
|
||||
if [ -n "$Le_Deploy_ssh_cafile" ]; then
|
||||
_pipe=">"
|
||||
if [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_keyfile" ] \
|
||||
|| [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_certfile" ]; then
|
||||
if [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_keyfile" ] ||
|
||||
[ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_certfile" ]; then
|
||||
# if filename is same as previous file then append.
|
||||
_pipe=">>"
|
||||
elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
|
||||
@@ -207,15 +229,17 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
|
||||
|
||||
# FULLCHAIN is optional.
|
||||
# If provided then fullchain certificate will be copied or appended to provided filename.
|
||||
_getdeployconf DEPLOY_SSH_FULLCHAIN
|
||||
_debug2 DEPLOY_SSH_FULLCHAIN "$DEPLOY_SSH_FULLCHAIN"
|
||||
if [ -n "$DEPLOY_SSH_FULLCHAIN" ]; then
|
||||
Le_Deploy_ssh_fullchain="$DEPLOY_SSH_FULLCHAIN"
|
||||
_savedomainconf Le_Deploy_ssh_fullchain "$Le_Deploy_ssh_fullchain"
|
||||
fi
|
||||
if [ -n "$Le_Deploy_ssh_fullchain" ]; then
|
||||
_pipe=">"
|
||||
if [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_keyfile" ] \
|
||||
|| [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_certfile" ] \
|
||||
|| [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_cafile" ]; then
|
||||
if [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_keyfile" ] ||
|
||||
[ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_certfile" ] ||
|
||||
[ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_cafile" ]; then
|
||||
# if filename is same as previous file then append.
|
||||
_pipe=">>"
|
||||
elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
|
||||
@@ -235,6 +259,8 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
|
||||
|
||||
# REMOTE_CMD is optional.
|
||||
# If provided then this command will be executed on remote host.
|
||||
_getdeployconf DEPLOY_SSH_REMOTE_CMD
|
||||
_debug2 DEPLOY_SSH_REMOTE_CMD "$DEPLOY_SSH_REMOTE_CMD"
|
||||
if [ -n "$DEPLOY_SSH_REMOTE_CMD" ]; then
|
||||
Le_Deploy_ssh_remote_cmd="$DEPLOY_SSH_REMOTE_CMD"
|
||||
_savedomainconf Le_Deploy_ssh_remote_cmd "$Le_Deploy_ssh_remote_cmd"
|
||||
|
||||
@@ -21,10 +21,6 @@
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
_syno_get_cookie_data() {
|
||||
grep "\W$1=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o "$1=[^;]*;" | tr -d ';'
|
||||
}
|
||||
|
||||
#domain keyfile certfile cafile fullchain
|
||||
synology_dsm_deploy() {
|
||||
|
||||
@@ -40,9 +36,7 @@ synology_dsm_deploy() {
|
||||
_getdeployconf SYNO_Password
|
||||
_getdeployconf SYNO_Create
|
||||
_getdeployconf SYNO_DID
|
||||
if [ -z "$SYNO_Username" ] || [ -z "$SYNO_Password" ]; then
|
||||
SYNO_Username=""
|
||||
SYNO_Password=""
|
||||
if [ -z "${SYNO_Username:-}" ] || [ -z "${SYNO_Password:-}" ]; then
|
||||
_err "SYNO_Username & SYNO_Password must be set"
|
||||
return 1
|
||||
fi
|
||||
@@ -70,75 +64,91 @@ synology_dsm_deploy() {
|
||||
|
||||
# Get the certificate description, but don't save it until we verfiy it's real
|
||||
_getdeployconf SYNO_Certificate
|
||||
if [ -z "${SYNO_Certificate:?}" ]; then
|
||||
_err "SYNO_Certificate needs to be defined (with the Certificate description name)"
|
||||
_debug SYNO_Certificate "${SYNO_Certificate:-}"
|
||||
|
||||
# shellcheck disable=SC1003 # We are not trying to escape a single quote
|
||||
if printf "%s" "$SYNO_Certificate" | grep '\\'; then
|
||||
_err "Do not use a backslash (\) in your certificate description"
|
||||
return 1
|
||||
fi
|
||||
_debug SYNO_Certificate "$SYNO_Certificate"
|
||||
|
||||
_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_version=$(echo "$response" | grep "SYNO.API.Auth" | sed -n 's/.*"maxVersion" *: *\([0-9]*\).*/\1/p')
|
||||
_debug3 response "$response"
|
||||
_debug3 api_version "$api_version"
|
||||
|
||||
# Login, get the token from JSON and session id from cookie
|
||||
_info "Logging into $SYNO_Hostname:$SYNO_Port"
|
||||
response=$(_get "$_base_url/webman/login.cgi?username=$SYNO_Username&passwd=$SYNO_Password&enable_syno_token=yes&device_id=$SYNO_DID")
|
||||
token=$(echo "$response" | grep "SynoToken" | sed -n 's/.*"SynoToken" *: *"\([^"]*\).*/\1/p')
|
||||
encoded_username="$(printf "%s" "$SYNO_Username" | _url_encode)"
|
||||
encoded_password="$(printf "%s" "$SYNO_Password" | _url_encode)"
|
||||
|
||||
if [ -n "$SYNO_DID" ]; then
|
||||
_H1="Cookie: did=$SYNO_DID"
|
||||
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" "$_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."
|
||||
return 1
|
||||
fi
|
||||
sid=$(echo "$response" | grep "sid" | sed -n 's/.*"sid" *: *"\([^"]*\).*/\1/p')
|
||||
|
||||
_H1="Cookie: $(_syno_get_cookie_data "id"); $(_syno_get_cookie_data "smid")"
|
||||
_H2="X-SYNO-TOKEN: $token"
|
||||
_H1="X-SYNO-TOKEN: $token"
|
||||
export _H1
|
||||
export _H2
|
||||
_debug2 H1 "${_H1}"
|
||||
_debug2 H2 "${_H2}"
|
||||
|
||||
# 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"
|
||||
_debug token "$token"
|
||||
|
||||
_info "Getting certificates in Synology DSM"
|
||||
response=$(_post "api=SYNO.Core.Certificate.CRT&method=list&version=1" "$_base_url/webapi/entry.cgi")
|
||||
response=$(_post "api=SYNO.Core.Certificate.CRT&method=list&version=1&_sid=$sid" "$_base_url/webapi/entry.cgi")
|
||||
_debug3 response "$response"
|
||||
id=$(echo "$response" | sed -n "s/.*\"desc\":\"$SYNO_Certificate\",\"id\":\"\([^\"]*\).*/\1/p")
|
||||
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
|
||||
if [ -z "$id" ] && [ -z "${SYNO_Create:-}" ]; then
|
||||
_err "Unable to find certificate: $SYNO_Certificate and \$SYNO_Create is not set"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# we've verified this certificate description is a thing, so save it
|
||||
_savedeployconf SYNO_Certificate "$SYNO_Certificate"
|
||||
|
||||
default=false
|
||||
if echo "$response" | sed -n "s/.*\"desc\":\"$SYNO_Certificate\",\([^{]*\).*/\1/p" | grep -- 'is_default":true' >/dev/null; then
|
||||
default=true
|
||||
fi
|
||||
_debug2 default "$default"
|
||||
_savedeployconf SYNO_Certificate "$SYNO_Certificate" "base64"
|
||||
|
||||
_info "Generate form POST request"
|
||||
nl="\015\012"
|
||||
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")\012"
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"cert\"; filename=\"$(basename "$_ccert")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ccert")\012"
|
||||
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")\012"
|
||||
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=\"as_default\"${nl}${nl}${default}"
|
||||
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"
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"as_default\"${nl}${nl}true"
|
||||
else
|
||||
_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"
|
||||
response=$(_post "$content" "$_base_url/webapi/entry.cgi?api=SYNO.Core.Certificate&method=import&version=1&SynoToken=$token" "" "POST" "multipart/form-data; boundary=${delim}")
|
||||
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
|
||||
|
||||
224
deploy/unifi.sh
224
deploy/unifi.sh
@@ -1,12 +1,43 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#Here is a script to deploy cert to unifi server.
|
||||
# Here is a script to deploy cert on a Unifi Controller or Cloud Key device.
|
||||
# It supports:
|
||||
# - self-hosted Unifi Controller
|
||||
# - Unifi Cloud Key (Gen1/2/2+)
|
||||
# - Unifi Cloud Key running UnifiOS (v2.0.0+, Gen2/2+ only)
|
||||
# Please report bugs to https://github.com/acmesh-official/acme.sh/issues/3359
|
||||
|
||||
#returns 0 means success, otherwise error.
|
||||
|
||||
# The deploy-hook automatically detects standard Unifi installations
|
||||
# for each of the supported environments. Most users should not need
|
||||
# to set any of these variables, but if you are running a self-hosted
|
||||
# Controller with custom locations, set these as necessary before running
|
||||
# the deploy hook. (Defaults shown below.)
|
||||
#
|
||||
# Settings for Unifi Controller:
|
||||
# Location of Java keystore or unifi.keystore.jks file:
|
||||
#DEPLOY_UNIFI_KEYSTORE="/usr/lib/unifi/data/keystore"
|
||||
# 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"
|
||||
#
|
||||
# Settings for Unifi Cloud Key Gen1 (nginx admin pages):
|
||||
# Directory where cloudkey.crt and cloudkey.key live:
|
||||
#DEPLOY_UNIFI_CLOUDKEY_CERTDIR="/etc/ssl/private"
|
||||
# Command to restart maintenance pages and Controller
|
||||
# (same setting as above, default is updated when running on Cloud Key Gen1):
|
||||
#DEPLOY_UNIFI_RELOAD="service nginx restart && service unifi restart"
|
||||
#
|
||||
# Settings for UnifiOS (Cloud Key Gen2):
|
||||
# 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"
|
||||
#
|
||||
# At least one of DEPLOY_UNIFI_KEYSTORE, DEPLOY_UNIFI_CLOUDKEY_CERTDIR,
|
||||
# or DEPLOY_UNIFI_CORE_CONFIG must exist to receive the deployed certs.
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
@@ -24,77 +55,160 @@ unifi_deploy() {
|
||||
_debug _cca "$_cca"
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
if ! _exists keytool; then
|
||||
_err "keytool not found"
|
||||
return 1
|
||||
fi
|
||||
_getdeployconf DEPLOY_UNIFI_KEYSTORE
|
||||
_getdeployconf DEPLOY_UNIFI_KEYPASS
|
||||
_getdeployconf DEPLOY_UNIFI_CLOUDKEY_CERTDIR
|
||||
_getdeployconf DEPLOY_UNIFI_CORE_CONFIG
|
||||
_getdeployconf DEPLOY_UNIFI_RELOAD
|
||||
|
||||
DEFAULT_UNIFI_KEYSTORE="/usr/lib/unifi/data/keystore"
|
||||
_unifi_keystore="${DEPLOY_UNIFI_KEYSTORE:-$DEFAULT_UNIFI_KEYSTORE}"
|
||||
DEFAULT_UNIFI_KEYPASS="aircontrolenterprise"
|
||||
_unifi_keypass="${DEPLOY_UNIFI_KEYPASS:-$DEFAULT_UNIFI_KEYPASS}"
|
||||
DEFAULT_UNIFI_RELOAD="service unifi restart"
|
||||
_reload="${DEPLOY_UNIFI_RELOAD:-$DEFAULT_UNIFI_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"
|
||||
|
||||
_debug _unifi_keystore "$_unifi_keystore"
|
||||
if [ ! -f "$_unifi_keystore" ]; then
|
||||
if [ -z "$DEPLOY_UNIFI_KEYSTORE" ]; then
|
||||
_err "unifi keystore is not found, please define DEPLOY_UNIFI_KEYSTORE"
|
||||
return 1
|
||||
else
|
||||
_err "It seems that the specified unifi keystore is not valid, please check."
|
||||
# Space-separated list of environments detected and installed:
|
||||
_services_updated=""
|
||||
|
||||
# Default reload commands accumulated as we auto-detect environments:
|
||||
_reload_cmd=""
|
||||
|
||||
# Unifi Controller environment (self hosted or any Cloud Key) --
|
||||
# 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
|
||||
fi
|
||||
fi
|
||||
if [ ! -w "$_unifi_keystore" ]; then
|
||||
_err "The file $_unifi_keystore is not writable, please change the permission."
|
||||
if [ ! -w "$_unifi_keystore" ]; then
|
||||
_err "The file $_unifi_keystore is not writable, please change the permission."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_unifi_keypass="${DEPLOY_UNIFI_KEYPASS:-aircontrolenterprise}"
|
||||
|
||||
_debug "Generate import pkcs12"
|
||||
_import_pkcs12="$(_mktemp)"
|
||||
_toPkcs "$_import_pkcs12" "$_ckey" "$_ccert" "$_cca" "$_unifi_keypass" unifi root
|
||||
# shellcheck disable=SC2181
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "Error generating pkcs12. Please re-run with --debug and report a bug."
|
||||
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"
|
||||
else
|
||||
_err "Error importing into Unifi Java keystore."
|
||||
_err "Please re-run with --debug and report a bug."
|
||||
rm "$_import_pkcs12"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if systemctl -q is-active unifi; then
|
||||
_reload_cmd="${_reload_cmd:+$_reload_cmd && }service unifi restart"
|
||||
fi
|
||||
_services_updated="${_services_updated} unifi"
|
||||
_info "Install Unifi Controller certificate success!"
|
||||
elif [ "$DEPLOY_UNIFI_KEYSTORE" ]; then
|
||||
_err "The specified DEPLOY_UNIFI_KEYSTORE='$DEPLOY_UNIFI_KEYSTORE' is not valid, please check."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Generate import pkcs12"
|
||||
_import_pkcs12="$(_mktemp)"
|
||||
_toPkcs "$_import_pkcs12" "$_ckey" "$_ccert" "$_cca" "$_unifi_keypass" unifi root
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "Oops, error creating import pkcs12, please report bug to us."
|
||||
# Cloud Key environment (non-UnifiOS -- nginx serves admin pages) --
|
||||
# auto-detect by file /etc/ssl/private/cloudkey.key:
|
||||
_cloudkey_certdir="${DEPLOY_UNIFI_CLOUDKEY_CERTDIR:-/etc/ssl/private}"
|
||||
if [ -f "${_cloudkey_certdir}/cloudkey.key" ]; then
|
||||
_info "Installing certificate for Cloud Key Gen1 (nginx admin pages)"
|
||||
_debug _cloudkey_certdir "$_cloudkey_certdir"
|
||||
if [ ! -w "$_cloudkey_certdir" ]; then
|
||||
_err "The directory $_cloudkey_certdir is not writable; please check permissions."
|
||||
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
|
||||
fi
|
||||
|
||||
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)
|
||||
|
||||
if systemctl -q is-active nginx; then
|
||||
_reload_cmd="${_reload_cmd:+$_reload_cmd && }service nginx restart"
|
||||
fi
|
||||
_info "Install Cloud Key Gen1 certificate success!"
|
||||
_services_updated="${_services_updated} nginx"
|
||||
elif [ "$DEPLOY_UNIFI_CLOUDKEY_CERTDIR" ]; then
|
||||
_err "The specified DEPLOY_UNIFI_CLOUDKEY_CERTDIR='$DEPLOY_UNIFI_CLOUDKEY_CERTDIR' is not valid, please check."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Modify unifi 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
|
||||
_info "Import keystore success!"
|
||||
rm "$_import_pkcs12"
|
||||
else
|
||||
_err "Import unifi keystore error, please report bug to us."
|
||||
rm "$_import_pkcs12"
|
||||
# UnifiOS environment -- auto-detect by /data/unifi-core/config/unifi-core.key:
|
||||
_unifi_core_config="${DEPLOY_UNIFI_CORE_CONFIG:-/data/unifi-core/config}"
|
||||
if [ -f "${_unifi_core_config}/unifi-core.key" ]; then
|
||||
_info "Installing certificate for UnifiOS"
|
||||
_debug _unifi_core_config "$_unifi_core_config"
|
||||
if [ ! -w "$_unifi_core_config" ]; then
|
||||
_err "The directory $_unifi_core_config is not writable; please check permissions."
|
||||
return 1
|
||||
fi
|
||||
|
||||
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
|
||||
_info "Install UnifiOS certificate success!"
|
||||
_services_updated="${_services_updated} unifi-core"
|
||||
elif [ "$DEPLOY_UNIFI_CORE_CONFIG" ]; then
|
||||
_err "The specified DEPLOY_UNIFI_CORE_CONFIG='$DEPLOY_UNIFI_CORE_CONFIG' is not valid, please check."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Run reload: $_reload"
|
||||
if eval "$_reload"; then
|
||||
if [ -z "$_services_updated" ]; then
|
||||
# None of the Unifi environments were auto-detected, so no deployment has occurred
|
||||
# (and none of DEPLOY_UNIFI_{KEYSTORE,CLOUDKEY_CERTDIR,CORE_CONFIG} were set).
|
||||
_err "Unable to detect Unifi environment in standard location."
|
||||
_err "(This deploy hook must be run on the Unifi device, not a remote machine.)"
|
||||
_err "For non-standard Unifi installations, set DEPLOY_UNIFI_KEYSTORE,"
|
||||
_err "DEPLOY_UNIFI_CLOUDKEY_CERTDIR, and/or DEPLOY_UNIFI_CORE_CONFIG as appropriate."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_reload_cmd="${DEPLOY_UNIFI_RELOAD:-$_reload_cmd}"
|
||||
if [ -z "$_reload_cmd" ]; then
|
||||
_err "Certificates were installed for services:${_services_updated},"
|
||||
_err "but none appear to be active. Please set DEPLOY_UNIFI_RELOAD"
|
||||
_err "to a command that will restart the necessary services."
|
||||
return 1
|
||||
fi
|
||||
_info "Reload services (this may take some time): $_reload_cmd"
|
||||
if eval "$_reload_cmd"; then
|
||||
_info "Reload success!"
|
||||
if [ "$DEPLOY_UNIFI_KEYSTORE" ]; then
|
||||
_savedomainconf DEPLOY_UNIFI_KEYSTORE "$DEPLOY_UNIFI_KEYSTORE"
|
||||
else
|
||||
_cleardomainconf DEPLOY_UNIFI_KEYSTORE
|
||||
fi
|
||||
if [ "$DEPLOY_UNIFI_KEYPASS" ]; then
|
||||
_savedomainconf DEPLOY_UNIFI_KEYPASS "$DEPLOY_UNIFI_KEYPASS"
|
||||
else
|
||||
_cleardomainconf DEPLOY_UNIFI_KEYPASS
|
||||
fi
|
||||
if [ "$DEPLOY_UNIFI_RELOAD" ]; then
|
||||
_savedomainconf DEPLOY_UNIFI_RELOAD "$DEPLOY_UNIFI_RELOAD"
|
||||
else
|
||||
_cleardomainconf DEPLOY_UNIFI_RELOAD
|
||||
fi
|
||||
return 0
|
||||
else
|
||||
_err "Reload error"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
|
||||
# Successful, so save all (non-default) config:
|
||||
_savedeployconf DEPLOY_UNIFI_KEYSTORE "$DEPLOY_UNIFI_KEYSTORE"
|
||||
_savedeployconf DEPLOY_UNIFI_KEYPASS "$DEPLOY_UNIFI_KEYPASS"
|
||||
_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"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
67
deploy/vault.sh
Normal file
67
deploy/vault.sh
Normal file
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Here is a script to deploy cert to hashicorp vault using curl
|
||||
# (https://www.vaultproject.io/)
|
||||
#
|
||||
# it requires following environment variables:
|
||||
#
|
||||
# VAULT_PREFIX - this contains the prefix path in vault
|
||||
# VAULT_ADDR - vault requires this to find your vault server
|
||||
#
|
||||
# additionally, you need to ensure that VAULT_TOKEN is avialable
|
||||
# to access the vault server
|
||||
|
||||
#returns 0 means success, otherwise error.
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#domain keyfile certfile cafile fullchain
|
||||
vault_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"
|
||||
|
||||
# validate required env vars
|
||||
_getdeployconf VAULT_PREFIX
|
||||
if [ -z "$VAULT_PREFIX" ]; then
|
||||
_err "VAULT_PREFIX needs to be defined (contains prefix path in vault)"
|
||||
return 1
|
||||
fi
|
||||
_savedeployconf VAULT_PREFIX "$VAULT_PREFIX"
|
||||
|
||||
_getdeployconf VAULT_ADDR
|
||||
if [ -z "$VAULT_ADDR" ]; then
|
||||
_err "VAULT_ADDR needs to be defined (contains vault connection address)"
|
||||
return 1
|
||||
fi
|
||||
_savedeployconf VAULT_ADDR "$VAULT_ADDR"
|
||||
|
||||
# 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")
|
||||
|
||||
URL="$VAULT_ADDR/v1/$VAULT_PREFIX/$_cdomain"
|
||||
export _H1="X-Vault-Token: $VAULT_TOKEN"
|
||||
|
||||
if [ -n "$FABIO" ]; then
|
||||
_post "{\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"}" "$URL"
|
||||
else
|
||||
_post "{\"value\": \"$_ccert\"}" "$URL/cert.pem"
|
||||
_post "{\"value\": \"$_ckey\"}" "$URL/cert.key"
|
||||
_post "{\"value\": \"$_cca\"}" "$URL/chain.pem"
|
||||
_post "{\"value\": \"$_cfullchain\"}" "$URL/fullchain.pem"
|
||||
fi
|
||||
|
||||
}
|
||||
@@ -43,19 +43,19 @@ vault_cli_deploy() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
VAULT_CMD=$(which vault)
|
||||
VAULT_CMD=$(command -v vault)
|
||||
if [ ! $? ]; then
|
||||
_err "cannot find vault binary!"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -n "$FABIO" ]; then
|
||||
$VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}" cert=@"$_cfullchain" key=@"$_ckey" || return 1
|
||||
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}" cert=@"$_cfullchain" key=@"$_ckey" || return 1
|
||||
else
|
||||
$VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/cert.pem" value=@"$_ccert" || return 1
|
||||
$VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/cert.key" value=@"$_ckey" || return 1
|
||||
$VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/chain.pem" value=@"$_cca" || return 1
|
||||
$VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/fullchain.pem" value=@"$_cfullchain" || return 1
|
||||
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/cert.pem" value=@"$_ccert" || return 1
|
||||
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/cert.key" value=@"$_ckey" || return 1
|
||||
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/chain.pem" value=@"$_cca" || return 1
|
||||
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/fullchain.pem" value=@"$_cfullchain" || return 1
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
@@ -65,9 +65,9 @@ vsftpd_deploy() {
|
||||
cp "$_vsftpd_conf" "$_backup_conf"
|
||||
|
||||
_info "Modify vsftpd conf: $_vsftpd_conf"
|
||||
if _setopt "$_vsftpd_conf" "rsa_cert_file" "=" "$_real_fullchain" \
|
||||
&& _setopt "$_vsftpd_conf" "rsa_private_key_file" "=" "$_real_key" \
|
||||
&& _setopt "$_vsftpd_conf" "ssl_enable" "=" "YES"; then
|
||||
if _setopt "$_vsftpd_conf" "rsa_cert_file" "=" "$_real_fullchain" &&
|
||||
_setopt "$_vsftpd_conf" "rsa_private_key_file" "=" "$_real_key" &&
|
||||
_setopt "$_vsftpd_conf" "ssl_enable" "=" "YES"; then
|
||||
_info "Set config success!"
|
||||
else
|
||||
_err "Config vsftpd server error, please report bug to us."
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#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.
|
||||
#
|
||||
|
||||
#Author: Adrian Fedoreanu
|
||||
#Report Bugs here: https://github.com/acmesh-official/acme.sh
|
||||
# or here... https://github.com/acmesh-official/acme.sh/issues/2851
|
||||
@@ -40,8 +40,35 @@ dns_1984hosting_add() {
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_1984hosting_add_txt_record "$_domain" "$_sub_domain" "$txtvalue"
|
||||
return $?
|
||||
_debug "Add TXT record $fulldomain with value '$txtvalue'"
|
||||
value="$(printf '%s' "$txtvalue" | _url_encode)"
|
||||
url="https://management.1984hosting.com/domains/entry/"
|
||||
|
||||
postdata="entry=new"
|
||||
postdata="$postdata&type=TXT"
|
||||
postdata="$postdata&ttl=900"
|
||||
postdata="$postdata&zone=$_domain"
|
||||
postdata="$postdata&host=$_sub_domain"
|
||||
postdata="$postdata&rdata=%22$value%22"
|
||||
_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"
|
||||
return 1
|
||||
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"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Added acme challenge TXT record for $fulldomain at 1984Hosting"
|
||||
return 0
|
||||
}
|
||||
|
||||
#Usage: fulldomain txtvalue
|
||||
@@ -66,67 +93,15 @@ dns_1984hosting_rm() {
|
||||
fi
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_1984hosting_delete_txt_record "$_domain" "$_sub_domain"
|
||||
return $?
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
# usage _1984hosting_add_txt_record domain subdomain value
|
||||
# returns 0 success
|
||||
_1984hosting_add_txt_record() {
|
||||
_debug "Add TXT record $1 with value '$3'"
|
||||
domain="$1"
|
||||
subdomain="$2"
|
||||
value="$(printf '%s' "$3" | _url_encode)"
|
||||
url="https://management.1984hosting.com/domains/entry/"
|
||||
|
||||
postdata="entry=new"
|
||||
postdata="$postdata&type=TXT"
|
||||
postdata="$postdata&ttl=3600"
|
||||
postdata="$postdata&zone=$domain"
|
||||
postdata="$postdata&host=$subdomain"
|
||||
postdata="$postdata&rdata=%22$value%22"
|
||||
_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 $subdomain bad RC from _post"
|
||||
return 1
|
||||
elif _contains "$response" "<html>"; then
|
||||
_err "1984Hosting failed to add TXT record for $subdomain. Check $HTTP_HEADER file"
|
||||
return 1
|
||||
elif [ "$response" = '{"auth": false, "ok": false}' ]; then
|
||||
_err "1984Hosting failed to add TXT record for $subdomain. Invalid or expired cookie"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Added acme challenge TXT record for $fulldomain at 1984Hosting"
|
||||
return 0
|
||||
}
|
||||
|
||||
# usage _1984hosting_delete_txt_record entry_id
|
||||
# returns 0 success
|
||||
_1984hosting_delete_txt_record() {
|
||||
_debug "Delete $fulldomain TXT record"
|
||||
domain="$1"
|
||||
subdomain="$2"
|
||||
url="https://management.1984hosting.com/domains"
|
||||
|
||||
_htmlget "$url" "$domain"
|
||||
_debug2 _response "$_response"
|
||||
zone_id="$(echo "$_response" | _egrep_o 'zone\/[0-9]+')"
|
||||
_debug2 zone_id "$zone_id"
|
||||
if [ -z "$zone_id" ]; then
|
||||
_err "Error getting zone_id for $1"
|
||||
url="https://management.1984hosting.com/domains"
|
||||
if ! _get_zone_id "$url" "$_domain"; then
|
||||
_err "invalid zone" "$_domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_htmlget "$url/$zone_id" "$subdomain"
|
||||
_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"
|
||||
@@ -148,12 +123,14 @@ _1984hosting_delete_txt_record() {
|
||||
return 0
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
# usage: _1984hosting_login username password
|
||||
# returns 0 success
|
||||
_1984hosting_login() {
|
||||
if ! _check_credentials; then return 1; fi
|
||||
|
||||
if _check_cookie; then
|
||||
if _check_cookies; then
|
||||
_debug "Already logged in"
|
||||
return 0
|
||||
fi
|
||||
@@ -163,14 +140,17 @@ _1984hosting_login() {
|
||||
password=$(printf '%s' "$One984HOSTING_Password" | _url_encode)
|
||||
url="https://management.1984hosting.com/accounts/checkuserauth/"
|
||||
|
||||
response="$(_post "username=$username&password=$password&otpkey=" "$url")"
|
||||
response="$(_post "username=$username&password=$password&otpkey=" $url)"
|
||||
response="$(echo "$response" | _normalizeJson)"
|
||||
_debug2 response "$response"
|
||||
|
||||
if [ "$response" = '{"loggedin": true, "ok": true}' ]; then
|
||||
One984HOSTING_COOKIE="$(grep '^Set-Cookie:' "$HTTP_HEADER" | _tail_n 1 | _egrep_o 'sessionid=[^;]*;' | tr -d ';')"
|
||||
export One984HOSTING_COOKIE
|
||||
_saveaccountconf_mutable One984HOSTING_COOKIE "$One984HOSTING_COOKIE"
|
||||
if _contains "$response" '"loggedin": true'; then
|
||||
One984HOSTING_SESSIONID_COOKIE="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _egrep_o 'sessionid=[^;]*;' | 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_SESSIONID_COOKIE "$One984HOSTING_SESSIONID_COOKIE"
|
||||
_saveaccountconf_mutable One984HOSTING_CSRFTOKEN_COOKIE "$One984HOSTING_CSRFTOKEN_COOKIE"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
@@ -187,22 +167,24 @@ _check_credentials() {
|
||||
return 0
|
||||
}
|
||||
|
||||
_check_cookie() {
|
||||
One984HOSTING_COOKIE="${One984HOSTING_COOKIE:-$(_readaccountconf_mutable One984HOSTING_COOKIE)}"
|
||||
if [ -z "$One984HOSTING_COOKIE" ]; then
|
||||
_debug "No cached cookie found"
|
||||
_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"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_authget "https://management.1984hosting.com/accounts/loginstatus/"
|
||||
response="$(echo "$_response" | _normalizeJson)"
|
||||
if [ "$_response" = '{"ok": true}' ]; then
|
||||
_debug "Cached cookie still valid"
|
||||
if _contains "$response" '"ok": true'; then
|
||||
_debug "Cached cookies still valid"
|
||||
return 0
|
||||
fi
|
||||
_debug "Cached cookie no longer valid"
|
||||
One984HOSTING_COOKIE=""
|
||||
_saveaccountconf_mutable One984HOSTING_COOKIE "$One984HOSTING_COOKIE"
|
||||
_debug "Cached cookies no longer valid"
|
||||
One984HOSTING_SESSIONID_COOKIE=""
|
||||
One984HOSTING_CSRFTOKEN_COOKIE=""
|
||||
_saveaccountconf_mutable One984HOSTING_SESSIONID_COOKIE "$One984HOSTING_SESSIONID_COOKIE"
|
||||
_saveaccountconf_mutable One984HOSTING_CSRFTOKEN_COOKIE "$One984HOSTING_CSRFTOKEN_COOKIE"
|
||||
return 1
|
||||
}
|
||||
|
||||
@@ -212,7 +194,7 @@ _check_cookie() {
|
||||
# _domain=domain.com
|
||||
_get_root() {
|
||||
domain="$1"
|
||||
i=2
|
||||
i=1
|
||||
p=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
@@ -223,7 +205,7 @@ _get_root() {
|
||||
fi
|
||||
|
||||
_authget "https://management.1984hosting.com/domains/soacheck/?zone=$h&nameserver=ns0.1984.is."
|
||||
if _contains "$_response" "serial"; then
|
||||
if _contains "$_response" "serial" && ! _contains "$_response" "null"; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain="$h"
|
||||
return 0
|
||||
@@ -234,21 +216,46 @@ _get_root() {
|
||||
return 1
|
||||
}
|
||||
|
||||
#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"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# add extra headers to request
|
||||
_authget() {
|
||||
export _H1="Cookie: $One984HOSTING_COOKIE"
|
||||
_response=$(_get "$1")
|
||||
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
|
||||
_htmlget() {
|
||||
export _H1="Cookie: $One984HOSTING_COOKIE"
|
||||
_response=$(_get "$1" | grep "$2" | _head_n 1)
|
||||
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
|
||||
}
|
||||
|
||||
# add extra headers to request
|
||||
_authpost() {
|
||||
export _H1="Cookie: $One984HOSTING_COOKIE"
|
||||
url="https://management.1984hosting.com/domains"
|
||||
_get_zone_id "$url" "$_domain"
|
||||
csrf_header="$(echo "$One984HOSTING_CSRFTOKEN_COOKIE" | _egrep_o "=[^=][0-9a-zA-Z]*" | tr -d "=")"
|
||||
export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE;$One984HOSTING_SESSIONID_COOKIE"
|
||||
export _H2="Referer: https://management.1984hosting.com/domains/$_zone_id"
|
||||
export _H3="X-CSRFToken: $csrf_header"
|
||||
_response=$(_post "$1" "$2")
|
||||
}
|
||||
|
||||
@@ -181,6 +181,7 @@ _describe_records_query() {
|
||||
|
||||
_clean() {
|
||||
_check_exist_query "$_domain" "$_sub_domain"
|
||||
# do not correct grammar here
|
||||
if ! _ali_rest "Check exist records" "ignore"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
150
dnsapi/dns_anx.sh
Normal file
150
dnsapi/dns_anx.sh
Normal file
@@ -0,0 +1,150 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Anexia CloudDNS acme.sh hook
|
||||
# Author: MA
|
||||
|
||||
#ANX_Token="xxxx"
|
||||
|
||||
ANX_API='https://engine.anexia-it.com/api/clouddns/v1'
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
dns_anx_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
_info "Using ANX CDNS API"
|
||||
|
||||
ANX_Token="${ANX_Token:-$(_readaccountconf_mutable ANX_Token)}"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
if [ "$ANX_Token" ]; then
|
||||
_saveaccountconf_mutable ANX_Token "$ANX_Token"
|
||||
else
|
||||
_err "You didn't specify a ANEXIA Engine API token."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Always add records, wildcard need two records with the same name
|
||||
_anx_rest POST "zone.json/${_domain}/records" "{\"name\":\"$_sub_domain\",\"type\":\"TXT\",\"rdata\":\"$txtvalue\"}"
|
||||
if _contains "$response" "$txtvalue"; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
dns_anx_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
_info "Using ANX CDNS API"
|
||||
|
||||
ANX_Token="${ANX_Token:-$(_readaccountconf_mutable ANX_Token)}"
|
||||
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_get_record_id
|
||||
|
||||
if _is_uuid "$_record_id"; then
|
||||
if ! _anx_rest DELETE "zone.json/${_domain}/records/$_record_id"; then
|
||||
_err "Delete record"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_info "No record found."
|
||||
fi
|
||||
echo "$response" | tr -d " " | grep \"status\":\"OK\" >/dev/null
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
_is_uuid() {
|
||||
pattern='^\{?[A-Z0-9a-z]{8}-[A-Z0-9a-z]{4}-[A-Z0-9a-z]{4}-[A-Z0-9a-z]{4}-[A-Z0-9a-z]{12}\}?$'
|
||||
if echo "$1" | _egrep_o "$pattern" >/dev/null; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
_get_record_id() {
|
||||
_debug subdomain "$_sub_domain"
|
||||
_debug domain "$_domain"
|
||||
|
||||
if _anx_rest GET "zone.json/${_domain}/records?name=$_sub_domain&type=TXT"; then
|
||||
_debug response "$response"
|
||||
if _contains "$response" "\"name\":\"$_sub_domain\"" >/dev/null; then
|
||||
_record_id=$(printf "%s\n" "$response" | _egrep_o "\[.\"identifier\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \")
|
||||
else
|
||||
_record_id=''
|
||||
fi
|
||||
else
|
||||
_err "Search existing record"
|
||||
fi
|
||||
}
|
||||
|
||||
_anx_rest() {
|
||||
m=$1
|
||||
ep="$2"
|
||||
data="$3"
|
||||
_debug "$ep"
|
||||
|
||||
export _H1="Content-Type: application/json"
|
||||
export _H2="Authorization: Token $ANX_Token"
|
||||
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "${ANX_API}/$ep" "" "$m")"
|
||||
else
|
||||
response="$(_get "${ANX_API}/$ep")"
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2181
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug response "$response"
|
||||
return 0
|
||||
}
|
||||
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=1
|
||||
p=1
|
||||
|
||||
_anx_rest GET "zone.json"
|
||||
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "\"name\":\"$h\""; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#Arvan_Token="xxxx"
|
||||
#Arvan_Token="Apikey xxxx"
|
||||
|
||||
ARVAN_API_URL="https://napi.arvancloud.com/cdn/4.0/domains"
|
||||
|
||||
#Author: Ehsan Aliakbar
|
||||
#Report Bugs here: https://github.com/Neilpang/acme.sh
|
||||
#Author: Vahid Fardi
|
||||
#Report Bugs here: https://github.com/Neilpang/acme.sh
|
||||
#
|
||||
######## Public functions #####################
|
||||
|
||||
@@ -38,6 +37,7 @@ dns_arvan_add() {
|
||||
_info "Adding record"
|
||||
if _arvan_rest POST "$_domain/dns-records" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":{\"text\":\"$txtvalue\"},\"ttl\":120}"; then
|
||||
if _contains "$response" "$txtvalue"; then
|
||||
_info "response id is $response"
|
||||
_info "Added, OK"
|
||||
return 0
|
||||
elif _contains "$response" "Record Data is Duplicated"; then
|
||||
@@ -49,7 +49,7 @@ dns_arvan_add() {
|
||||
fi
|
||||
fi
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
#Usage: fulldomain txtvalue
|
||||
@@ -73,33 +73,21 @@ dns_arvan_rm() {
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_debug "Getting txt records"
|
||||
shorted_txtvalue=$(printf "%s" "$txtvalue" | cut -d "-" -d "_" -f1)
|
||||
_arvan_rest GET "${_domain}/dns-records?search=$shorted_txtvalue"
|
||||
|
||||
_arvan_rest GET "${_domain}/dns-records"
|
||||
if ! printf "%s" "$response" | grep \"current_page\":1 >/dev/null; then
|
||||
_err "Error on Arvan Api"
|
||||
_err "Please create a github issue with debbug log"
|
||||
return 1
|
||||
fi
|
||||
|
||||
count=$(printf "%s\n" "$response" | _egrep_o "\"total\":[^,]*" | cut -d : -f 2)
|
||||
_debug count "$count"
|
||||
if [ "$count" = "0" ]; then
|
||||
_info "Don't need to remove."
|
||||
else
|
||||
record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1)
|
||||
_debug "record_id" "$record_id"
|
||||
if [ -z "$record_id" ]; then
|
||||
_err "Can not get record id to remove."
|
||||
return 1
|
||||
fi
|
||||
if ! _arvan_rest "DELETE" "${_domain}/dns-records/$record_id"; then
|
||||
_err "Delete record error."
|
||||
return 1
|
||||
fi
|
||||
_debug "$response"
|
||||
_contains "$response" 'dns record deleted'
|
||||
_record_id=$(echo "$response" | _egrep_o ".\"id\":\"[^\"]*\",\"type\":\"txt\",\"name\":\"_acme-challenge\",\"value\":{\"text\":\"$txtvalue\"}" | cut -d : -f 2 | cut -d , -f 1 | tr -d \")
|
||||
if ! _arvan_rest "DELETE" "${_domain}/dns-records/${_record_id}"; then
|
||||
_err "Error on Arvan Api"
|
||||
return 1
|
||||
fi
|
||||
_debug "$response"
|
||||
_contains "$response" 'dns record deleted'
|
||||
return 0
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
@@ -111,7 +99,7 @@ dns_arvan_rm() {
|
||||
# _domain_id=sdjkglgdfewsdfg
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=1
|
||||
i=2
|
||||
p=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
@@ -121,12 +109,11 @@ _get_root() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _arvan_rest GET "?search=$h"; then
|
||||
if ! _arvan_rest GET "$h"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "\"domain\":\"$h\"" || _contains "$response" '"total":1'; then
|
||||
_domain_id=$(echo "$response" | _egrep_o "\[.\"id\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||
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)
|
||||
_domain=$h
|
||||
@@ -146,7 +133,6 @@ _arvan_rest() {
|
||||
data="$3"
|
||||
|
||||
token_trimmed=$(echo "$Arvan_Token" | tr -d '"')
|
||||
|
||||
export _H1="Authorization: $token_trimmed"
|
||||
|
||||
if [ "$mtd" = "DELETE" ]; then
|
||||
@@ -160,4 +146,5 @@ _arvan_rest() {
|
||||
else
|
||||
response="$(_get "$ARVAN_API_URL/$ep$data")"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
171
dnsapi/dns_aurora.sh
Normal file
171
dnsapi/dns_aurora.sh
Normal file
@@ -0,0 +1,171 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
#AURORA_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
#
|
||||
#AURORA_Secret="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
|
||||
AURORA_Api="https://api.auroradns.eu"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_aurora_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
AURORA_Key="${AURORA_Key:-$(_readaccountconf_mutable AURORA_Key)}"
|
||||
AURORA_Secret="${AURORA_Secret:-$(_readaccountconf_mutable AURORA_Secret)}"
|
||||
|
||||
if [ -z "$AURORA_Key" ] || [ -z "$AURORA_Secret" ]; then
|
||||
AURORA_Key=""
|
||||
AURORA_Secret=""
|
||||
_err "You didn't specify an Aurora api key and secret yet."
|
||||
_err "You can get yours from here https://cp.pcextreme.nl/auroradns/users."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the api key and secret to the account conf file.
|
||||
_saveaccountconf_mutable AURORA_Key "$AURORA_Key"
|
||||
_saveaccountconf_mutable AURORA_Secret "$AURORA_Secret"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_info "Adding record"
|
||||
if _aurora_rest POST "zones/$_domain_id/records" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":300}"; then
|
||||
if _contains "$response" "$txtvalue"; then
|
||||
_info "Added, OK"
|
||||
return 0
|
||||
elif _contains "$response" "RecordExistsError"; then
|
||||
_info "Already exists, OK"
|
||||
return 0
|
||||
else
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
|
||||
}
|
||||
|
||||
#fulldomain txtvalue
|
||||
dns_aurora_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
AURORA_Key="${AURORA_Key:-$(_readaccountconf_mutable AURORA_Key)}"
|
||||
AURORA_Secret="${AURORA_Secret:-$(_readaccountconf_mutable AURORA_Secret)}"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_debug "Getting records"
|
||||
_aurora_rest GET "zones/${_domain_id}/records"
|
||||
|
||||
if ! _contains "$response" "$txtvalue"; then
|
||||
_info "Don't need to remove."
|
||||
else
|
||||
records=$(echo "$response" | _normalizeJson | tr -d "[]" | sed "s/},{/}|{/g" | tr "|" "\n")
|
||||
if [ "$(echo "$records" | wc -l)" -le 2 ]; then
|
||||
_err "Can not parse records."
|
||||
return 1
|
||||
fi
|
||||
record_id=$(echo "$records" | grep "\"type\": *\"TXT\"" | grep "\"name\": *\"$_sub_domain\"" | grep "\"content\": *\"$txtvalue\"" | _egrep_o "\"id\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | _head_n 1 | tr -d " ")
|
||||
_debug "record_id" "$record_id"
|
||||
if [ -z "$record_id" ]; then
|
||||
_err "Can not get record id to remove."
|
||||
return 1
|
||||
fi
|
||||
if ! _aurora_rest DELETE "zones/$_domain_id/records/$record_id"; then
|
||||
_err "Delete record error."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
return 0
|
||||
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
# _domain_id=sdjkglgdfewsdfg
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=1
|
||||
p=1
|
||||
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _aurora_rest GET "zones/$h"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "\"name\": \"$h\""; then
|
||||
_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)
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
_aurora_rest() {
|
||||
m=$1
|
||||
ep="$2"
|
||||
data="$3"
|
||||
_debug "$ep"
|
||||
|
||||
key_trimmed=$(echo "$AURORA_Key" | tr -d '"')
|
||||
secret_trimmed=$(echo "$AURORA_Secret" | tr -d '"')
|
||||
|
||||
timestamp=$(date -u +"%Y%m%dT%H%M%SZ")
|
||||
signature=$(printf "%s/%s%s" "$m" "$ep" "$timestamp" | _hmac sha256 "$(printf "%s" "$secret_trimmed" | _hex_dump | tr -d " ")" | _base64)
|
||||
authorization=$(printf "AuroraDNSv1 %s" "$(printf "%s:%s" "$key_trimmed" "$signature" | _base64)")
|
||||
|
||||
export _H1="Content-Type: application/json; charset=UTF-8"
|
||||
export _H2="X-AuroraDNS-Date: $timestamp"
|
||||
export _H3="Authorization: $authorization"
|
||||
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$AURORA_Api/$ep" "" "$m")"
|
||||
else
|
||||
response="$(_get "$AURORA_Api/$ep")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
@@ -32,7 +32,7 @@ dns_aws_add() {
|
||||
if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then
|
||||
AWS_ACCESS_KEY_ID=""
|
||||
AWS_SECRET_ACCESS_KEY=""
|
||||
_err "You haven't specifed the aws route53 api key id and and api key secret yet."
|
||||
_err "You haven't specified the aws route53 api key id and and api key secret yet."
|
||||
_err "Please create your key and try again. see $(__green $AWS_WIKI)"
|
||||
return 1
|
||||
fi
|
||||
@@ -222,21 +222,21 @@ _use_instance_role() {
|
||||
|
||||
_use_metadata() {
|
||||
_aws_creds="$(
|
||||
_get "$1" "" 1 \
|
||||
| _normalizeJson \
|
||||
| tr '{,}' '\n' \
|
||||
| while read -r _line; do
|
||||
_get "$1" "" 1 |
|
||||
_normalizeJson |
|
||||
tr '{,}' '\n' |
|
||||
while read -r _line; do
|
||||
_key="$(echo "${_line%%:*}" | tr -d '"')"
|
||||
_value="${_line#*:}"
|
||||
_debug3 "_key" "$_key"
|
||||
_secure_debug3 "_value" "$_value"
|
||||
case "$_key" in
|
||||
AccessKeyId) echo "AWS_ACCESS_KEY_ID=$_value" ;;
|
||||
SecretAccessKey) echo "AWS_SECRET_ACCESS_KEY=$_value" ;;
|
||||
Token) echo "AWS_SESSION_TOKEN=$_value" ;;
|
||||
AccessKeyId) echo "AWS_ACCESS_KEY_ID=$_value" ;;
|
||||
SecretAccessKey) echo "AWS_SECRET_ACCESS_KEY=$_value" ;;
|
||||
Token) echo "AWS_SESSION_TOKEN=$_value" ;;
|
||||
esac
|
||||
done \
|
||||
| paste -sd' ' -
|
||||
done |
|
||||
paste -sd' ' -
|
||||
)"
|
||||
_secure_debug "_aws_creds" "$_aws_creds"
|
||||
|
||||
|
||||
204
dnsapi/dns_azion.sh
Normal file
204
dnsapi/dns_azion.sh
Normal file
@@ -0,0 +1,204 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
#AZION_Email=""
|
||||
#AZION_Password=""
|
||||
#
|
||||
|
||||
AZION_Api="https://api.azionapi.net"
|
||||
|
||||
######## Public functions ########
|
||||
|
||||
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
# Used to add txt record
|
||||
dns_azion_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
_debug "Detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "Domain not found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
_debug _domain_id "$_domain_id"
|
||||
|
||||
_info "Add or update record"
|
||||
_get_record "$_domain_id" "$_sub_domain"
|
||||
if [ "$record_id" ]; then
|
||||
_payload="{\"record_type\": \"TXT\", \"entry\": \"$_sub_domain\", \"answers_list\": [$answers_list, \"$txtvalue\"], \"ttl\": 20}"
|
||||
if _azion_rest PUT "intelligent_dns/$_domain_id/records/$record_id" "$_payload"; then
|
||||
if _contains "$response" "$txtvalue"; then
|
||||
_info "Record updated."
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
else
|
||||
_payload="{\"record_type\": \"TXT\", \"entry\": \"$_sub_domain\", \"answers_list\": [\"$txtvalue\"], \"ttl\": 20}"
|
||||
if _azion_rest POST "intelligent_dns/$_domain_id/records" "$_payload"; then
|
||||
if _contains "$response" "$txtvalue"; then
|
||||
_info "Record added."
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
_err "Failed to add or update record."
|
||||
return 1
|
||||
}
|
||||
|
||||
# Usage: fulldomain txtvalue
|
||||
# Used to remove the txt record after validation
|
||||
dns_azion_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
_debug "Detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "Domain not found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
_debug _domain_id "$_domain_id"
|
||||
|
||||
_info "Removing record"
|
||||
_get_record "$_domain_id" "$_sub_domain"
|
||||
if [ "$record_id" ]; then
|
||||
if _azion_rest DELETE "intelligent_dns/$_domain_id/records/$record_id"; then
|
||||
_info "Record removed."
|
||||
return 0
|
||||
else
|
||||
_err "Failed to remove record."
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_info "Record not found or already removed."
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
# Usage: _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 ! _azion_rest GET "intelligent_dns"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
# not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "\"domain\":\"$h\""; then
|
||||
_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)
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
_get_record() {
|
||||
_domain_id=$1
|
||||
_record=$2
|
||||
|
||||
if ! _azion_rest GET "intelligent_dns/$_domain_id/records"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "\"entry\":\"$_record\""; then
|
||||
_json_record=$(echo "$response" | tr '{' "\n" | grep "\"entry\":\"$_record\"")
|
||||
if [ "$_json_record" ]; then
|
||||
record_id=$(echo "$_json_record" | _egrep_o "\"record_id\":[0-9]*" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||
answers_list=$(echo "$_json_record" | _egrep_o "\"answers_list\":\[.*\]" | _head_n 1 | cut -d : -f 2 | tr -d \[\])
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
_get_token() {
|
||||
AZION_Email="${AZION_Email:-$(_readaccountconf_mutable AZION_Email)}"
|
||||
AZION_Password="${AZION_Password:-$(_readaccountconf_mutable AZION_Password)}"
|
||||
|
||||
if ! _contains "$AZION_Email" "@"; then
|
||||
_err "It seems that the AZION_Email is not a valid email address. Revalidate your environments."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$AZION_Email" ] || [ -z "$AZION_Password" ]; then
|
||||
_err "You didn't specified a AZION_Email/AZION_Password to generate Azion token."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf_mutable AZION_Email "$AZION_Email"
|
||||
_saveaccountconf_mutable AZION_Password "$AZION_Password"
|
||||
|
||||
_basic_auth=$(printf "%s:%s" "$AZION_Email" "$AZION_Password" | _base64)
|
||||
_debug _basic_auth "$_basic_auth"
|
||||
|
||||
export _H1="Accept: application/json; version=3"
|
||||
export _H2="Content-Type: application/json"
|
||||
export _H3="Authorization: Basic $_basic_auth"
|
||||
|
||||
response="$(_post "" "$AZION_Api/tokens" "" "POST")"
|
||||
if _contains "$response" "\"token\":\"" >/dev/null; then
|
||||
_azion_token=$(echo "$response" | _egrep_o "\"token\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")
|
||||
export AZION_Token="$_azion_token"
|
||||
else
|
||||
_err "Failed to generate Azion token"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
_azion_rest() {
|
||||
_method=$1
|
||||
_uri="$2"
|
||||
_data="$3"
|
||||
|
||||
if [ -z "$AZION_Token" ]; then
|
||||
_get_token
|
||||
fi
|
||||
_debug2 token "$AZION_Token"
|
||||
|
||||
export _H1="Accept: application/json; version=3"
|
||||
export _H2="Content-Type: application/json"
|
||||
export _H3="Authorization: token $AZION_Token"
|
||||
|
||||
if [ "$_method" != "GET" ]; then
|
||||
_debug _data "$_data"
|
||||
response="$(_post "$_data" "$AZION_Api/$_uri" "" "$_method")"
|
||||
else
|
||||
response="$(_get "$AZION_Api/$_uri")"
|
||||
fi
|
||||
|
||||
_debug2 response "$response"
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $_method $_uri $_data"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
@@ -172,7 +172,7 @@ dns_azure_rm() {
|
||||
_azure_rest GET "$acmeRecordURI" "" "$accesstoken"
|
||||
timestamp="$(_time)"
|
||||
if [ "$_code" = "200" ]; then
|
||||
vlist="$(echo "$response" | _egrep_o "\"value\"\\s*:\\s*\\[\\s*\"[^\"]*\"\\s*]" | cut -d : -f 2 | tr -d "[]\"" | grep -v "$txtvalue")"
|
||||
vlist="$(echo "$response" | _egrep_o "\"value\"\\s*:\\s*\\[\\s*\"[^\"]*\"\\s*]" | cut -d : -f 2 | tr -d "[]\"" | grep -v -- "$txtvalue")"
|
||||
values=""
|
||||
comma=""
|
||||
for v in $vlist; do
|
||||
@@ -220,7 +220,7 @@ _azure_rest() {
|
||||
export _H2="accept: application/json"
|
||||
export _H3="Content-Type: application/json"
|
||||
# clear headers from previous request to avoid getting wrong http code on timeouts
|
||||
:>"$HTTP_HEADER"
|
||||
: >"$HTTP_HEADER"
|
||||
_debug "$ep"
|
||||
if [ "$m" != "GET" ]; then
|
||||
_secure_debug2 "data $data"
|
||||
|
||||
@@ -69,7 +69,7 @@ dns_cloudns_rm() {
|
||||
for i in $(echo "$response" | tr '{' "\n" | grep "$record"); do
|
||||
record_id=$(echo "$i" | tr ',' "\n" | grep -E '^"id"' | sed -re 's/^\"id\"\:\"([0-9]+)\"$/\1/g')
|
||||
|
||||
if [ ! -z "$record_id" ]; then
|
||||
if [ -n "$record_id" ]; then
|
||||
_debug zone "$zone"
|
||||
_debug host "$host"
|
||||
_debug record "$record"
|
||||
@@ -91,7 +91,7 @@ dns_cloudns_rm() {
|
||||
|
||||
#################### Private functions below ##################################
|
||||
_dns_cloudns_init_check() {
|
||||
if [ ! -z "$CLOUDNS_INIT_CHECK_COMPLETED" ]; then
|
||||
if [ -n "$CLOUDNS_INIT_CHECK_COMPLETED" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
@@ -164,7 +164,7 @@ _dns_cloudns_http_api_call() {
|
||||
_debug CLOUDNS_SUB_AUTH_ID "$CLOUDNS_SUB_AUTH_ID"
|
||||
_debug CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD"
|
||||
|
||||
if [ ! -z "$CLOUDNS_SUB_AUTH_ID" ]; then
|
||||
if [ -n "$CLOUDNS_SUB_AUTH_ID" ]; then
|
||||
auth_user="sub-auth-id=$CLOUDNS_SUB_AUTH_ID"
|
||||
else
|
||||
auth_user="auth-id=$CLOUDNS_AUTH_ID"
|
||||
|
||||
@@ -115,9 +115,9 @@ dns_conoha_rm() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
record_id=$(printf "%s" "$response" | _egrep_o '{[^}]*}' \
|
||||
| grep '"type":"TXT"' | grep "\"data\":\"$txtvalue\"" | _egrep_o "\"id\":\"[^\"]*\"" \
|
||||
| _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||
record_id=$(printf "%s" "$response" | _egrep_o '{[^}]*}' |
|
||||
grep '"type":"TXT"' | grep "\"data\":\"$txtvalue\"" | _egrep_o "\"id\":\"[^\"]*\"" |
|
||||
_head_n 1 | cut -d : -f 2 | tr -d \")
|
||||
if [ -z "$record_id" ]; then
|
||||
_err "Can not get record id to remove."
|
||||
return 1
|
||||
|
||||
@@ -30,16 +30,41 @@ dns_constellix_add() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Adding TXT record"
|
||||
if _constellix_rest POST "domains/${_domain_id}/records" "[{\"type\":\"txt\",\"add\":true,\"set\":{\"name\":\"${_sub_domain}\",\"ttl\":120,\"roundRobin\":[{\"value\":\"${txtvalue}\"}]}}]"; then
|
||||
if printf -- "%s" "$response" | grep "{\"success\":\"1 record(s) added, 0 record(s) updated, 0 record(s) deleted\"}" >/dev/null; then
|
||||
_info "Added"
|
||||
return 0
|
||||
# The TXT record might already exist when working with wildcard certificates. In that case, update the record by adding the new value.
|
||||
_debug "Search TXT record"
|
||||
if _constellix_rest GET "domains/${_domain_id}/records/TXT/search?exact=${_sub_domain}"; then
|
||||
if printf -- "%s" "$response" | grep "{\"errors\":\[\"Requested record was not found\"\]}" >/dev/null; then
|
||||
_info "Adding TXT record"
|
||||
if _constellix_rest POST "domains/${_domain_id}/records" "[{\"type\":\"txt\",\"add\":true,\"set\":{\"name\":\"${_sub_domain}\",\"ttl\":60,\"roundRobin\":[{\"value\":\"${txtvalue}\"}]}}]"; then
|
||||
if printf -- "%s" "$response" | grep "{\"success\":\"1 record(s) added, 0 record(s) updated, 0 record(s) deleted\"}" >/dev/null; then
|
||||
_info "Added"
|
||||
return 0
|
||||
else
|
||||
_err "Error adding TXT record"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
_err "Error adding TXT record"
|
||||
return 1
|
||||
_record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[0-9]*" | cut -d ':' -f 2)
|
||||
if _constellix_rest GET "domains/${_domain_id}/records/TXT/${_record_id}"; then
|
||||
_new_rr_values=$(printf "%s\n" "$response" | _egrep_o '"roundRobin":\[[^]]*\]' | sed "s/\]$/,{\"value\":\"${txtvalue}\"}]/")
|
||||
_debug _new_rr_values "$_new_rr_values"
|
||||
_info "Updating TXT record"
|
||||
if _constellix_rest PUT "domains/${_domain_id}/records/TXT/${_record_id}" "{\"name\":\"${_sub_domain}\",\"ttl\":60,${_new_rr_values}}"; then
|
||||
if printf -- "%s" "$response" | grep "{\"success\":\"Record.*updated successfully\"}" >/dev/null; then
|
||||
_info "Updated"
|
||||
return 0
|
||||
elif printf -- "%s" "$response" | grep "{\"errors\":\[\"Contents are identical\"\]}" >/dev/null; then
|
||||
_info "Already exists, no need to update"
|
||||
return 0
|
||||
else
|
||||
_err "Error updating TXT record"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Usage: fulldomain txtvalue
|
||||
@@ -61,16 +86,26 @@ dns_constellix_rm() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Removing TXT record"
|
||||
if _constellix_rest POST "domains/${_domain_id}/records" "[{\"type\":\"txt\",\"delete\":true,\"filter\":{\"field\":\"name\",\"op\":\"eq\",\"value\":\"${_sub_domain}\"}}]"; then
|
||||
if printf -- "%s" "$response" | grep "{\"success\":\"0 record(s) added, 0 record(s) updated, 1 record(s) deleted\"}" >/dev/null; then
|
||||
# The TXT record might have been removed already when working with some wildcard certificates.
|
||||
_debug "Search TXT record"
|
||||
if _constellix_rest GET "domains/${_domain_id}/records/TXT/search?exact=${_sub_domain}"; then
|
||||
if printf -- "%s" "$response" | grep "{\"errors\":\[\"Requested record was not found\"\]}" >/dev/null; then
|
||||
_info "Removed"
|
||||
return 0
|
||||
else
|
||||
_err "Error removing TXT record"
|
||||
return 1
|
||||
_info "Removing TXT record"
|
||||
if _constellix_rest POST "domains/${_domain_id}/records" "[{\"type\":\"txt\",\"delete\":true,\"filter\":{\"field\":\"name\",\"op\":\"eq\",\"value\":\"${_sub_domain}\"}}]"; then
|
||||
if printf -- "%s" "$response" | grep "{\"success\":\"0 record(s) added, 0 record(s) updated, 1 record(s) deleted\"}" >/dev/null; then
|
||||
_info "Removed"
|
||||
return 0
|
||||
else
|
||||
_err "Error removing TXT record"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
@@ -91,7 +126,7 @@ _get_root() {
|
||||
fi
|
||||
|
||||
if _contains "$response" "\"name\":\"$h\""; then
|
||||
_domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[0-9]+" | cut -d ':' -f 2)
|
||||
_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)
|
||||
_domain="$h"
|
||||
|
||||
@@ -18,23 +18,23 @@
|
||||
########
|
||||
|
||||
dns_cyon_add() {
|
||||
_cyon_load_credentials \
|
||||
&& _cyon_load_parameters "$@" \
|
||||
&& _cyon_print_header "add" \
|
||||
&& _cyon_login \
|
||||
&& _cyon_change_domain_env \
|
||||
&& _cyon_add_txt \
|
||||
&& _cyon_logout
|
||||
_cyon_load_credentials &&
|
||||
_cyon_load_parameters "$@" &&
|
||||
_cyon_print_header "add" &&
|
||||
_cyon_login &&
|
||||
_cyon_change_domain_env &&
|
||||
_cyon_add_txt &&
|
||||
_cyon_logout
|
||||
}
|
||||
|
||||
dns_cyon_rm() {
|
||||
_cyon_load_credentials \
|
||||
&& _cyon_load_parameters "$@" \
|
||||
&& _cyon_print_header "delete" \
|
||||
&& _cyon_login \
|
||||
&& _cyon_change_domain_env \
|
||||
&& _cyon_delete_txt \
|
||||
&& _cyon_logout
|
||||
_cyon_load_credentials &&
|
||||
_cyon_load_parameters "$@" &&
|
||||
_cyon_print_header "delete" &&
|
||||
_cyon_login &&
|
||||
_cyon_change_domain_env &&
|
||||
_cyon_delete_txt &&
|
||||
_cyon_logout
|
||||
}
|
||||
|
||||
#########################
|
||||
@@ -66,7 +66,7 @@ _cyon_load_credentials() {
|
||||
_debug "Save credentials to account.conf"
|
||||
_saveaccountconf CY_Username "${CY_Username}"
|
||||
_saveaccountconf CY_Password_B64 "$CY_Password_B64"
|
||||
if [ ! -z "${CY_OTP_Secret}" ]; then
|
||||
if [ -n "${CY_OTP_Secret}" ]; then
|
||||
_saveaccountconf CY_OTP_Secret "$CY_OTP_Secret"
|
||||
else
|
||||
_clearaccountconf CY_OTP_Secret
|
||||
@@ -164,7 +164,7 @@ _cyon_login() {
|
||||
# todo: instead of just checking if the env variable is defined, check if we actually need to do a 2FA auth request.
|
||||
|
||||
# 2FA authentication with OTP?
|
||||
if [ ! -z "${CY_OTP_Secret}" ]; then
|
||||
if [ -n "${CY_OTP_Secret}" ]; then
|
||||
_info " - Authorising with OTP code..."
|
||||
|
||||
if ! _exists oathtool; then
|
||||
|
||||
@@ -115,23 +115,23 @@ _da_api() {
|
||||
_debug response "$response"
|
||||
|
||||
case "${cmd}" in
|
||||
CMD_API_DNS_CONTROL)
|
||||
# Parse the result in general
|
||||
# error=0&text=Records Deleted&details=
|
||||
# error=1&text=Cannot View Dns Record&details=No domain provided
|
||||
err_field="$(_getfield "$response" 1 '&')"
|
||||
txt_field="$(_getfield "$response" 2 '&')"
|
||||
details_field="$(_getfield "$response" 3 '&')"
|
||||
error="$(_getfield "$err_field" 2 '=')"
|
||||
text="$(_getfield "$txt_field" 2 '=')"
|
||||
details="$(_getfield "$details_field" 2 '=')"
|
||||
_debug "error: ${error}, text: ${text}, details: ${details}"
|
||||
if [ "$error" != "0" ]; then
|
||||
_err "error $response"
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
CMD_API_SHOW_DOMAINS) ;;
|
||||
CMD_API_DNS_CONTROL)
|
||||
# Parse the result in general
|
||||
# error=0&text=Records Deleted&details=
|
||||
# error=1&text=Cannot View Dns Record&details=No domain provided
|
||||
err_field="$(_getfield "$response" 1 '&')"
|
||||
txt_field="$(_getfield "$response" 2 '&')"
|
||||
details_field="$(_getfield "$response" 3 '&')"
|
||||
error="$(_getfield "$err_field" 2 '=')"
|
||||
text="$(_getfield "$txt_field" 2 '=')"
|
||||
details="$(_getfield "$details_field" 2 '=')"
|
||||
_debug "error: ${error}, text: ${text}, details: ${details}"
|
||||
if [ "$error" != "0" ]; then
|
||||
_err "error $response"
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
CMD_API_SHOW_DOMAINS) ;;
|
||||
esac
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -20,21 +20,17 @@ dns_desec_add() {
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
DEDYN_TOKEN="${DEDYN_TOKEN:-$(_readaccountconf_mutable DEDYN_TOKEN)}"
|
||||
DEDYN_NAME="${DEDYN_NAME:-$(_readaccountconf_mutable DEDYN_NAME)}"
|
||||
|
||||
if [ -z "$DEDYN_TOKEN" ] || [ -z "$DEDYN_NAME" ]; then
|
||||
if [ -z "$DEDYN_TOKEN" ]; then
|
||||
DEDYN_TOKEN=""
|
||||
DEDYN_NAME=""
|
||||
_err "You did not specify DEDYN_TOKEN and DEDYN_NAME yet."
|
||||
_err "You did not specify DEDYN_TOKEN yet."
|
||||
_err "Please create your key and try again."
|
||||
_err "e.g."
|
||||
_err "export DEDYN_TOKEN=d41d8cd98f00b204e9800998ecf8427e"
|
||||
_err "export DEDYN_NAME=foobar.dedyn.io"
|
||||
return 1
|
||||
fi
|
||||
#save the api token and name to the account conf file.
|
||||
#save the api token to the account conf file.
|
||||
_saveaccountconf_mutable DEDYN_TOKEN "$DEDYN_TOKEN"
|
||||
_saveaccountconf_mutable DEDYN_NAME "$DEDYN_NAME"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain" "$REST_API/"; then
|
||||
@@ -47,7 +43,7 @@ dns_desec_add() {
|
||||
# Get existing TXT record
|
||||
_debug "Getting txt records"
|
||||
txtvalues="\"\\\"$txtvalue\\\"\""
|
||||
_desec_rest GET "$REST_API/$DEDYN_NAME/rrsets/$_sub_domain/TXT/"
|
||||
_desec_rest GET "$REST_API/$_domain/rrsets/$_sub_domain/TXT/"
|
||||
|
||||
if [ "$_code" = "200" ]; then
|
||||
oldtxtvalues="$(echo "$response" | _egrep_o "\"records\":\\[\"\\S*\"\\]" | cut -d : -f 2 | tr -d "[]\\\\\"" | sed "s/,/ /g")"
|
||||
@@ -61,9 +57,9 @@ dns_desec_add() {
|
||||
fi
|
||||
_debug txtvalues "$txtvalues"
|
||||
_info "Adding record"
|
||||
body="[{\"subname\":\"$_sub_domain\", \"type\":\"TXT\", \"records\":[$txtvalues], \"ttl\":60}]"
|
||||
body="[{\"subname\":\"$_sub_domain\", \"type\":\"TXT\", \"records\":[$txtvalues], \"ttl\":3600}]"
|
||||
|
||||
if _desec_rest PUT "$REST_API/$DEDYN_NAME/rrsets/" "$body"; then
|
||||
if _desec_rest PUT "$REST_API/$_domain/rrsets/" "$body"; then
|
||||
if _contains "$response" "$txtvalue"; then
|
||||
_info "Added, OK"
|
||||
return 0
|
||||
@@ -87,16 +83,13 @@ dns_desec_rm() {
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
DEDYN_TOKEN="${DEDYN_TOKEN:-$(_readaccountconf_mutable DEDYN_TOKEN)}"
|
||||
DEDYN_NAME="${DEDYN_NAME:-$(_readaccountconf_mutable DEDYN_NAME)}"
|
||||
|
||||
if [ -z "$DEDYN_TOKEN" ] || [ -z "$DEDYN_NAME" ]; then
|
||||
if [ -z "$DEDYN_TOKEN" ]; then
|
||||
DEDYN_TOKEN=""
|
||||
DEDYN_NAME=""
|
||||
_err "You did not specify DEDYN_TOKEN and DEDYN_NAME yet."
|
||||
_err "You did not specify DEDYN_TOKEN yet."
|
||||
_err "Please create your key and try again."
|
||||
_err "e.g."
|
||||
_err "export DEDYN_TOKEN=d41d8cd98f00b204e9800998ecf8427e"
|
||||
_err "export DEDYN_NAME=foobar.dedyn.io"
|
||||
return 1
|
||||
fi
|
||||
|
||||
@@ -112,7 +105,7 @@ dns_desec_rm() {
|
||||
# Get existing TXT record
|
||||
_debug "Getting txt records"
|
||||
txtvalues=""
|
||||
_desec_rest GET "$REST_API/$DEDYN_NAME/rrsets/$_sub_domain/TXT/"
|
||||
_desec_rest GET "$REST_API/$_domain/rrsets/$_sub_domain/TXT/"
|
||||
|
||||
if [ "$_code" = "200" ]; then
|
||||
oldtxtvalues="$(echo "$response" | _egrep_o "\"records\":\\[\"\\S*\"\\]" | cut -d : -f 2 | tr -d "[]\\\\\"" | sed "s/,/ /g")"
|
||||
@@ -130,8 +123,8 @@ dns_desec_rm() {
|
||||
_debug txtvalues "$txtvalues"
|
||||
|
||||
_info "Deleting record"
|
||||
body="[{\"subname\":\"$_sub_domain\", \"type\":\"TXT\", \"records\":[$txtvalues], \"ttl\":60}]"
|
||||
_desec_rest PUT "$REST_API/$DEDYN_NAME/rrsets/" "$body"
|
||||
body="[{\"subname\":\"$_sub_domain\", \"type\":\"TXT\", \"records\":[$txtvalues], \"ttl\":3600}]"
|
||||
_desec_rest PUT "$REST_API/$_domain/rrsets/" "$body"
|
||||
if [ "$_code" = "200" ]; then
|
||||
_info "Deleted, OK"
|
||||
return 0
|
||||
|
||||
@@ -22,7 +22,7 @@ dns_dgon_add() {
|
||||
txtvalue=$2
|
||||
|
||||
DO_API_KEY="${DO_API_KEY:-$(_readaccountconf_mutable DO_API_KEY)}"
|
||||
# Check if API Key Exist
|
||||
# Check if API Key Exists
|
||||
if [ -z "$DO_API_KEY" ]; then
|
||||
DO_API_KEY=""
|
||||
_err "You did not specify DigitalOcean API key."
|
||||
@@ -77,7 +77,7 @@ dns_dgon_rm() {
|
||||
txtvalue=$2
|
||||
|
||||
DO_API_KEY="${DO_API_KEY:-$(_readaccountconf_mutable DO_API_KEY)}"
|
||||
# Check if API Key Exist
|
||||
# Check if API Key Exists
|
||||
if [ -z "$DO_API_KEY" ]; then
|
||||
DO_API_KEY=""
|
||||
_err "You did not specify DigitalOcean API key."
|
||||
@@ -122,12 +122,12 @@ dns_dgon_rm() {
|
||||
## check for what we are looking for: "type":"A","name":"$_sub_domain"
|
||||
record="$(echo "$domain_list" | _egrep_o "\"id\"\s*\:\s*\"*[0-9]+\"*[^}]*\"name\"\s*\:\s*\"$_sub_domain\"[^}]*\"data\"\s*\:\s*\"$txtvalue\"")"
|
||||
|
||||
if [ ! -z "$record" ]; then
|
||||
if [ -n "$record" ]; then
|
||||
|
||||
## we found records
|
||||
rec_ids="$(echo "$record" | _egrep_o "id\"\s*\:\s*\"*[0-9]+" | _egrep_o "[0-9]+")"
|
||||
_debug rec_ids "$rec_ids"
|
||||
if [ ! -z "$rec_ids" ]; then
|
||||
if [ -n "$rec_ids" ]; then
|
||||
echo "$rec_ids" | while IFS= read -r rec_id; do
|
||||
## delete the record
|
||||
## delete URL for removing the one we dont want
|
||||
@@ -218,7 +218,7 @@ _get_base_domain() {
|
||||
## we got part of a domain back - grep it out
|
||||
found="$(echo "$domain_list" | _egrep_o "\"name\"\s*\:\s*\"$_domain\"")"
|
||||
## check if it exists
|
||||
if [ ! -z "$found" ]; then
|
||||
if [ -n "$found" ]; then
|
||||
## exists - exit loop returning the parts
|
||||
sub_point=$(_math $i - 1)
|
||||
_sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$sub_point")
|
||||
|
||||
@@ -67,14 +67,14 @@ _dns_do_list_rrs() {
|
||||
_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="$(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}" ]
|
||||
}
|
||||
|
||||
@@ -120,10 +120,10 @@ _get_root() {
|
||||
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')"
|
||||
_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)
|
||||
|
||||
@@ -89,7 +89,7 @@ add_record() {
|
||||
|
||||
_info "Adding record"
|
||||
|
||||
if ! _rest POST "Record.Create" "login_token=$DP_Id,$DP_Key&format=json&lang=en&domain_id=$_domain_id&sub_domain=$_sub_domain&record_type=TXT&value=$txtvalue&record_line=默认"; then
|
||||
if ! _rest POST "Record.Create" "login_token=$DP_Id,$DP_Key&format=json&lang=en&domain_id=$_domain_id&sub_domain=$_sub_domain&record_type=TXT&value=$txtvalue&record_line=%E9%BB%98%E8%AE%A4"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ dns_dpi_rm() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _rest POST "Record.List" "user_token=$DPI_Id,$DPI_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain"; then
|
||||
if ! _rest POST "Record.List" "login_token=$DPI_Id,$DPI_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain"; then
|
||||
_err "Record.Lis error."
|
||||
return 1
|
||||
fi
|
||||
@@ -63,19 +63,19 @@ dns_dpi_rm() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
record_id=$(echo "$response" | _egrep_o '{[^{]*"value":"'"$txtvalue"'"' | cut -d , -f 1 | cut -d : -f 2 | tr -d \")
|
||||
record_id=$(echo "$response" | tr "{" "\n" | grep -- "$txtvalue" | grep '^"id"' | cut -d : -f 2 | cut -d '"' -f 2)
|
||||
_debug record_id "$record_id"
|
||||
if [ -z "$record_id" ]; then
|
||||
_err "Can not get record id."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _rest POST "Record.Remove" "user_token=$DPI_Id,$DPI_Key&format=json&domain_id=$_domain_id&record_id=$record_id"; then
|
||||
if ! _rest POST "Record.Remove" "login_token=$DPI_Id,$DPI_Key&format=json&domain_id=$_domain_id&record_id=$record_id"; then
|
||||
_err "Record.Remove error."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_contains "$response" "Action completed successful"
|
||||
_contains "$response" "Operation successful"
|
||||
|
||||
}
|
||||
|
||||
@@ -89,11 +89,11 @@ add_record() {
|
||||
|
||||
_info "Adding record"
|
||||
|
||||
if ! _rest POST "Record.Create" "user_token=$DPI_Id,$DPI_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain&record_type=TXT&value=$txtvalue&record_line=default"; then
|
||||
if ! _rest POST "Record.Create" "login_token=$DPI_Id,$DPI_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain&record_type=TXT&value=$txtvalue&record_line=default"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
_contains "$response" "Action completed successful" || _contains "$response" "Domain record already exists"
|
||||
_contains "$response" "Operation successful" || _contains "$response" "Domain record already exists"
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
@@ -113,11 +113,11 @@ _get_root() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _rest POST "Domain.Info" "user_token=$DPI_Id,$DPI_Key&format=json&domain=$h"; then
|
||||
if ! _rest POST "Domain.Info" "login_token=$DPI_Id,$DPI_Key&format=json&domain=$h"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "Action completed successful"; then
|
||||
if _contains "$response" "Operation successful"; then
|
||||
_domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")
|
||||
_debug _domain_id "$_domain_id"
|
||||
if [ "$_domain_id" ]; then
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
DuckDNS_API="https://www.duckdns.org/update"
|
||||
|
||||
######## Public functions #####################
|
||||
######## Public functions ######################
|
||||
|
||||
#Usage: dns_duckdns_add _acme-challenge.domain.duckdns.org "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_duckdns_add() {
|
||||
@@ -91,13 +91,12 @@ dns_duckdns_rm() {
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
#fulldomain=_acme-challenge.domain.duckdns.org
|
||||
#returns
|
||||
# _duckdns_domain=domain
|
||||
# fulldomain may be 'domain.duckdns.org' (if using --domain-alias) or '_acme-challenge.domain.duckdns.org'
|
||||
# either way, return 'domain'. (duckdns does not allow further subdomains and restricts domains to [a-z0-9-].)
|
||||
_duckdns_get_domain() {
|
||||
|
||||
# We'll extract the domain/username from full domain
|
||||
_duckdns_domain="$(printf "%s" "$fulldomain" | _lower_case | _egrep_o '[.][^.][^.]*[.]duckdns.org' | cut -d . -f 2)"
|
||||
_duckdns_domain="$(printf "%s" "$fulldomain" | _lower_case | _egrep_o '^(_acme-challenge\.)?([a-z0-9-]+\.)+duckdns\.org' | sed -n 's/^\([^.]\{1,\}\.\)*\([a-z0-9-]\{1,\}\)\.duckdns\.org$/\2/p;')"
|
||||
|
||||
if [ -z "$_duckdns_domain" ]; then
|
||||
_err "Error extracting the domain."
|
||||
@@ -113,16 +112,21 @@ _duckdns_rest() {
|
||||
param="$2"
|
||||
_debug param "$param"
|
||||
url="$DuckDNS_API?$param"
|
||||
if [ -n "$DEBUG" ] && [ "$DEBUG" -gt 0 ]; then
|
||||
url="$url&verbose=true"
|
||||
fi
|
||||
_debug url "$url"
|
||||
|
||||
# DuckDNS uses GET to update domain info
|
||||
if [ "$method" = "GET" ]; then
|
||||
response="$(_get "$url")"
|
||||
_debug2 response "$response"
|
||||
if [ -n "$DEBUG" ] && [ "$DEBUG" -gt 0 ] && _contains "$response" "UPDATED" && _contains "$response" "OK"; then
|
||||
response="OK"
|
||||
fi
|
||||
else
|
||||
_err "Unsupported method"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -216,6 +216,10 @@ _dynu_authentication() {
|
||||
_err "Authentication failed."
|
||||
return 1
|
||||
fi
|
||||
if _contains "$response" "Authentication Exception"; then
|
||||
_err "Authentication failed."
|
||||
return 1
|
||||
fi
|
||||
if _contains "$response" "access_token"; then
|
||||
Dynu_Token=$(printf "%s" "$response" | tr -d "{}" | cut -d , -f 1 | cut -d : -f 2 | cut -d '"' -f 2)
|
||||
fi
|
||||
|
||||
@@ -1,35 +1,41 @@
|
||||
#!/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
|
||||
|
||||
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_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
#Usage: dns_dynv6_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_dynv6_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_info "Using dynv6 api"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
_get_keyfile
|
||||
_info "using keyfile $dynv6_keyfile"
|
||||
_get_domain "$fulldomain"
|
||||
_your_hosts="$(ssh -i "$dynv6_keyfile" api@dynv6.com hosts)"
|
||||
if ! _contains "$_your_hosts" "$_host"; then
|
||||
_debug "The host is $_host and the record $_record"
|
||||
_debug "Dynv6 returned $_your_hosts"
|
||||
_err "The host $_host does not exists on your dynv6 account"
|
||||
return 1
|
||||
fi
|
||||
_debug "found host on your account"
|
||||
returnval="$(ssh -i "$dynv6_keyfile" api@dynv6.com hosts \""$_host"\" records set \""$_record"\" txt data \""$txtvalue"\")"
|
||||
_debug "Dynv6 returend this after record was added: $returnval"
|
||||
if _contains "$returnval" "created"; then
|
||||
return 0
|
||||
elif _contains "$returnval" "updated"; then
|
||||
return 0
|
||||
_get_authentication
|
||||
if [ "$dynv6_token" ]; then
|
||||
_dns_dynv6_add_http
|
||||
return $?
|
||||
else
|
||||
_err "Something went wrong! it does not seem like the record was added succesfully"
|
||||
_info "using key file $dynv6_keyfile"
|
||||
_your_hosts="$(ssh -i "$dynv6_keyfile" api@dynv6.com hosts)"
|
||||
if ! _get_domain "$fulldomain" "$_your_hosts"; then
|
||||
_err "Host not found on your account"
|
||||
return 1
|
||||
fi
|
||||
_debug "found host on your account"
|
||||
returnval="$(ssh -i "$dynv6_keyfile" api@dynv6.com hosts \""$_host"\" records set \""$_record"\" txt data \""$txtvalue"\")"
|
||||
_debug "Dynv6 returned this after record was added: $returnval"
|
||||
if _contains "$returnval" "created"; then
|
||||
return 0
|
||||
elif _contains "$returnval" "updated"; then
|
||||
return 0
|
||||
else
|
||||
_err "Something went wrong! it does not seem like the record was added successfully"
|
||||
return 1
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
return 1
|
||||
@@ -39,28 +45,29 @@ dns_dynv6_add() {
|
||||
dns_dynv6_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_info "Using dynv6 api"
|
||||
_info "Using dynv6 API"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
_get_keyfile
|
||||
_info "using keyfile $dynv6_keyfile"
|
||||
_get_domain "$fulldomain"
|
||||
_your_hosts="$(ssh -i "$dynv6_keyfile" api@dynv6.com hosts)"
|
||||
if ! _contains "$_your_hosts" "$_host"; then
|
||||
_debug "The host is $_host and the record $_record"
|
||||
_debug "Dynv6 returned $_your_hosts"
|
||||
_err "The host $_host does not exists on your dynv6 account"
|
||||
return 1
|
||||
_get_authentication
|
||||
if [ "$dynv6_token" ]; then
|
||||
_dns_dynv6_rm_http
|
||||
return $?
|
||||
else
|
||||
_info "using key file $dynv6_keyfile"
|
||||
_your_hosts="$(ssh -i "$dynv6_keyfile" api@dynv6.com hosts)"
|
||||
if ! _get_domain "$fulldomain" "$_your_hosts"; then
|
||||
_err "Host not found on your account"
|
||||
return 1
|
||||
fi
|
||||
_debug "found host on your account"
|
||||
_info "$(ssh -i "$dynv6_keyfile" api@dynv6.com hosts "\"$_host\"" records del "\"$_record\"" txt)"
|
||||
return 0
|
||||
fi
|
||||
_debug "found host on your account"
|
||||
_info "$(ssh -i "$dynv6_keyfile" api@dynv6.com hosts "\"$_host\"" records del "\"$_record\"" txt)"
|
||||
return 0
|
||||
|
||||
}
|
||||
#################### Private functions below ##################################
|
||||
#Usage: No Input required
|
||||
#returns
|
||||
#dynv6_keyfile the path to the new keyfile that has been generated
|
||||
#dynv6_keyfile the path to the new key file that has been generated
|
||||
_generate_new_key() {
|
||||
dynv6_keyfile="$(eval echo ~"$USER")/.ssh/dynv6"
|
||||
_info "Path to key file used: $dynv6_keyfile"
|
||||
@@ -72,50 +79,207 @@ _generate_new_key() {
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
#Usage: _acme-challenge.www.example.dynv6.net
|
||||
|
||||
#Usage: _acme-challenge.www.example.dynv6.net "$_your_hosts"
|
||||
#where _your_hosts is the output of ssh -i ~/.ssh/dynv6.pub api@dynv6.com hosts
|
||||
#returns
|
||||
#_host= example.dynv6.net
|
||||
#_record=_acme-challenge.www
|
||||
#aborts if not a valid domain
|
||||
_get_domain() {
|
||||
#_your_hosts="$(ssh -i ~/.ssh/dynv6.pub api@dynv6.com hosts)"
|
||||
_full_domain="$1"
|
||||
_debug "getting domain for $_full_domain"
|
||||
if ! _contains "$_full_domain" 'dynv6.net' && ! _contains "$_full_domain" 'dns.army' && ! _contains "$_full_domain" 'dns.navy'; then
|
||||
_err "The hosts does not seem to be a dynv6 host"
|
||||
return 1
|
||||
fi
|
||||
_record="${_full_domain%.*}"
|
||||
_record="${_record%.*}"
|
||||
_record="${_record%.*}"
|
||||
_debug "The record we are ging to use is $_record"
|
||||
_host="$_full_domain"
|
||||
while [ "$(echo "$_host" | grep -o '\.' | wc -l)" != "2" ]; do
|
||||
_host="${_host#*.}"
|
||||
done
|
||||
_debug "And the host is $_host"
|
||||
return 0
|
||||
_your_hosts="$2"
|
||||
|
||||
_your_hosts="$(echo "$_your_hosts" | awk '/\./ {print $1}')"
|
||||
for l in $_your_hosts; do
|
||||
#echo "host: $l"
|
||||
if test "${_full_domain#*$l}" != "$_full_domain"; then
|
||||
_record="${_full_domain%.$l}"
|
||||
_host=$l
|
||||
_debug "The host is $_host and the record $_record"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
_err "Either their is no such host on your dnyv6 account or it cannot be accessed with this key"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Usage: No input required
|
||||
#returns
|
||||
#dynv6_keyfile path to the key that will be used
|
||||
_get_keyfile() {
|
||||
_debug "get keyfile method called"
|
||||
dynv6_keyfile="${dynv6_keyfile:-$(_readaccountconf_mutable dynv6_keyfile)}"
|
||||
_debug Your key is "$dynv6_keyfile"
|
||||
if [ -z "$dynv6_keyfile" ]; then
|
||||
if [ -z "$KEY" ]; then
|
||||
_err "You did not specify a key to use with dynv6"
|
||||
_info "Creating new dynv6 api key to add to dynv6.com"
|
||||
_generate_new_key
|
||||
_info "Please add this key to dynv6.com $(cat "$dynv6_keyfile.pub")"
|
||||
_info "Hit Enter to contiue"
|
||||
read -r _
|
||||
#save the credentials to the account conf file.
|
||||
else
|
||||
dynv6_keyfile="$KEY"
|
||||
_get_authentication() {
|
||||
dynv6_token="${DYNV6_TOKEN:-$(_readaccountconf_mutable dynv6_token)}"
|
||||
if [ "$dynv6_token" ]; then
|
||||
_debug "Found HTTP Token. Going to use the HTTP API and not the SSH API"
|
||||
if [ "$DYNV6_TOKEN" ]; then
|
||||
_saveaccountconf_mutable dynv6_token "$dynv6_token"
|
||||
fi
|
||||
else
|
||||
_debug "no HTTP token found. Looking for an SSH key"
|
||||
dynv6_keyfile="${dynv6_keyfile:-$(_readaccountconf_mutable dynv6_keyfile)}"
|
||||
_debug "Your key is $dynv6_keyfile"
|
||||
if [ -z "$dynv6_keyfile" ]; then
|
||||
if [ -z "$KEY" ]; then
|
||||
_err "You did not specify a key to use with dynv6"
|
||||
_info "Creating new dynv6 API key to add to dynv6.com"
|
||||
_generate_new_key
|
||||
_info "Please add this key to dynv6.com $(cat "$dynv6_keyfile.pub")"
|
||||
_info "Hit Enter to continue"
|
||||
read -r _
|
||||
#save the credentials to the account conf file.
|
||||
else
|
||||
dynv6_keyfile="$KEY"
|
||||
fi
|
||||
_saveaccountconf_mutable dynv6_keyfile "$dynv6_keyfile"
|
||||
fi
|
||||
_saveaccountconf_mutable dynv6_keyfile "$dynv6_keyfile"
|
||||
fi
|
||||
}
|
||||
|
||||
_dns_dynv6_add_http() {
|
||||
_debug "Got HTTP token form _get_authentication method. Going to use the HTTP API"
|
||||
if ! _get_zone_id "$fulldomain"; then
|
||||
_err "Could not find a matching zone for $fulldomain. Maybe your HTTP Token is not authorized to access the zone"
|
||||
return 1
|
||||
fi
|
||||
_get_zone_name "$_zone_id"
|
||||
record="${fulldomain%%.$_zone_name}"
|
||||
_set_record TXT "$record" "$txtvalue"
|
||||
if _contains "$response" "$txtvalue"; then
|
||||
_info "Successfully added record"
|
||||
return 0
|
||||
else
|
||||
_err "Something went wrong while adding the record"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
_dns_dynv6_rm_http() {
|
||||
_debug "Got HTTP token form _get_authentication method. Going to use the HTTP API"
|
||||
if ! _get_zone_id "$fulldomain"; then
|
||||
_err "Could not find a matching zone for $fulldomain. Maybe your HTTP Token is not authorized to access the zone"
|
||||
return 1
|
||||
fi
|
||||
_get_zone_name "$_zone_id"
|
||||
record="${fulldomain%%.$_zone_name}"
|
||||
_get_record_id "$_zone_id" "$record" "$txtvalue"
|
||||
_del_record "$_zone_id" "$_record_id"
|
||||
if [ -z "$response" ]; then
|
||||
_info "Successfully deleted record"
|
||||
return 0
|
||||
else
|
||||
_err "Something went wrong while deleting the record"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
#get the zoneid for a specifc record or zone
|
||||
#usage: _get_zone_id §record
|
||||
#where $record is the record to get the id for
|
||||
#returns _zone_id the id of the zone
|
||||
_get_zone_id() {
|
||||
record="$1"
|
||||
_debug "getting zone id for $record"
|
||||
_dynv6_rest GET zones
|
||||
|
||||
zones="$(echo "$response" | tr '}' '\n' | tr ',' '\n' | grep name | sed 's/\[//g' | tr -d '{' | tr -d '"')"
|
||||
#echo $zones
|
||||
|
||||
selected=""
|
||||
for z in $zones; do
|
||||
z="${z#name:}"
|
||||
_debug zone: "$z"
|
||||
if _contains "$record" "$z"; then
|
||||
_debug "$z found in $record"
|
||||
selected="$z"
|
||||
fi
|
||||
done
|
||||
if [ -z "$selected" ]; then
|
||||
_err "no zone found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
zone_id="$(echo "$response" | tr '}' '\n' | grep "$selected" | tr ',' '\n' | grep id | tr -d '"')"
|
||||
_zone_id="${zone_id#id:}"
|
||||
_debug "zone id: $_zone_id"
|
||||
}
|
||||
|
||||
_get_zone_name() {
|
||||
_zone_id="$1"
|
||||
_dynv6_rest GET zones/"$_zone_id"
|
||||
_zone_name="$(echo "$response" | tr ',' '\n' | tr -d '{' | grep name | tr -d '"')"
|
||||
_zone_name="${_zone_name#name:}"
|
||||
}
|
||||
|
||||
#usaage _get_record_id $zone_id $record
|
||||
# where zone_id is thevalue returned by _get_zone_id
|
||||
# and record ist in the form _acme.www for an fqdn of _acme.www.example.com
|
||||
# returns _record_id
|
||||
_get_record_id() {
|
||||
_zone_id="$1"
|
||||
record="$2"
|
||||
value="$3"
|
||||
_dynv6_rest GET "zones/$_zone_id/records"
|
||||
if ! _get_record_id_from_response "$response"; then
|
||||
_err "no such record $record found in zone $_zone_id"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
_get_record_id_from_response() {
|
||||
response="$1"
|
||||
_record_id="$(echo "$response" | tr '}' '\n' | grep "\"name\":\"$record\"" | grep "\"data\":\"$value\"" | tr ',' '\n' | grep id | tr -d '"' | tr -d 'id:')"
|
||||
#_record_id="${_record_id#id:}"
|
||||
if [ -z "$_record_id" ]; then
|
||||
_err "no such record: $record found in zone $_zone_id"
|
||||
return 1
|
||||
fi
|
||||
_debug "record id: $_record_id"
|
||||
return 0
|
||||
}
|
||||
#usage: _set_record TXT _acme_challenge.www longvalue 12345678
|
||||
#zone id is optional can also be set as vairable bevor calling this method
|
||||
_set_record() {
|
||||
type="$1"
|
||||
record="$2"
|
||||
value="$3"
|
||||
if [ "$4" ]; then
|
||||
_zone_id="$4"
|
||||
fi
|
||||
data="{\"name\": \"$record\", \"data\": \"$value\", \"type\": \"$type\"}"
|
||||
#data='{ "name": "acme.test.thorn.dynv6.net", "type": "A", "data": "192.168.0.1"}'
|
||||
echo "$data"
|
||||
#"{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":120}"
|
||||
_dynv6_rest POST "zones/$_zone_id/records" "$data"
|
||||
}
|
||||
_del_record() {
|
||||
_zone_id=$1
|
||||
_record_id=$2
|
||||
_dynv6_rest DELETE zones/"$_zone_id"/records/"$_record_id"
|
||||
}
|
||||
|
||||
_dynv6_rest() {
|
||||
m=$1 #method GET,POST,DELETE or PUT
|
||||
ep="$2" #the endpoint
|
||||
data="$3"
|
||||
_debug "$ep"
|
||||
|
||||
token_trimmed=$(echo "$dynv6_token" | tr -d '"')
|
||||
|
||||
export _H1="Authorization: Bearer $token_trimmed"
|
||||
export _H2="Content-Type: application/json"
|
||||
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$dynv6_api/$ep" "" "$m")"
|
||||
else
|
||||
response="$(_get "$dynv6_api/$ep")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#######################################################
|
||||
#
|
||||
# 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]
|
||||
|
||||
466
dnsapi/dns_edgedns.sh
Executable file
466
dnsapi/dns_edgedns.sh
Executable file
@@ -0,0 +1,466 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# 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
|
||||
# Edge DNS Zones and Recordsets, e.g. DNS—Zone Record Management authorization
|
||||
|
||||
# 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>
|
||||
|
||||
ACME_EDGEDNS_VERSION="0.1.0"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
# Usage: dns_edgedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
# Used to add txt record
|
||||
#
|
||||
dns_edgedns_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_debug "ENTERING DNS_EDGEDNS_ADD"
|
||||
_debug2 "fulldomain" "$fulldomain"
|
||||
_debug2 "txtvalue" "$txtvalue"
|
||||
|
||||
if ! _EDGEDNS_credentials; then
|
||||
_err "$@"
|
||||
return 1
|
||||
fi
|
||||
if ! _EDGEDNS_getZoneInfo "$fulldomain"; then
|
||||
_err "Invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 "Add: zone" "$zone"
|
||||
acmeRecordURI=$(printf "%s/%s/names/%s/types/TXT" "$edge_endpoint" "$zone" "$fulldomain")
|
||||
_debug3 "Add URL" "$acmeRecordURI"
|
||||
# Get existing TXT record
|
||||
_edge_result=$(_edgedns_rest GET "$acmeRecordURI")
|
||||
_api_status="$?"
|
||||
_debug3 "_edge_result" "$_edge_result"
|
||||
if [ "$_api_status" -ne 0 ]; then
|
||||
if [ "$curResult" = "FATAL" ]; then
|
||||
_err "$(printf "Fatal error: acme API function call : %s" "$retVal")"
|
||||
fi
|
||||
if [ "$_edge_result" != "404" ]; then
|
||||
_err "$(printf "Failure accessing Akamai Edge DNS API Server. Error: %s" "$_edge_result")"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
rdata="\"${txtvalue}\""
|
||||
record_op="POST"
|
||||
if [ "$_api_status" -eq 0 ]; then
|
||||
# record already exists. Get existing record data and update
|
||||
record_op="PUT"
|
||||
rdlist="${_edge_result#*\"rdata\":[}"
|
||||
rdlist="${rdlist%%]*}"
|
||||
rdlist=$(echo "$rdlist" | tr -d '"' | tr -d "\\\\")
|
||||
_debug3 "existing TXT found"
|
||||
_debug3 "record data" "$rdlist"
|
||||
# value already there?
|
||||
if _contains "$rdlist" "$txtvalue"; then
|
||||
return 0
|
||||
fi
|
||||
_txt_val=""
|
||||
while [ "$_txt_val" != "$rdlist" ] && [ "${rdlist}" ]; do
|
||||
_txt_val="${rdlist%%,*}"
|
||||
rdlist="${rdlist#*,}"
|
||||
rdata="${rdata},\"${_txt_val}\""
|
||||
done
|
||||
fi
|
||||
# Add the txtvalue TXT Record
|
||||
body="{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"ttl\":600, \"rdata\":"[${rdata}]"}"
|
||||
_debug3 "Add body '${body}'"
|
||||
_edge_result=$(_edgedns_rest "$record_op" "$acmeRecordURI" "$body")
|
||||
_api_status="$?"
|
||||
if [ "$_api_status" -eq 0 ]; then
|
||||
_log "$(printf "Text value %s added to recordset %s" "$txtvalue" "$fulldomain")"
|
||||
return 0
|
||||
else
|
||||
_err "$(printf "error adding TXT record for validation. Error: %s" "$_edge_result")"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Usage: dns_edgedns_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
# Used to delete txt record
|
||||
#
|
||||
dns_edgedns_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_debug "ENTERING DNS_EDGEDNS_RM"
|
||||
_debug2 "fulldomain" "$fulldomain"
|
||||
_debug2 "txtvalue" "$txtvalue"
|
||||
|
||||
if ! _EDGEDNS_credentials; then
|
||||
_err "$@"
|
||||
return 1
|
||||
fi
|
||||
if ! _EDGEDNS_getZoneInfo "$fulldomain"; then
|
||||
_err "Invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug2 "RM: zone" "${zone}"
|
||||
acmeRecordURI=$(printf "%s/%s/names/%s/types/TXT" "${edge_endpoint}" "$zone" "$fulldomain")
|
||||
_debug3 "RM URL" "$acmeRecordURI"
|
||||
# Get existing TXT record
|
||||
_edge_result=$(_edgedns_rest GET "$acmeRecordURI")
|
||||
_api_status="$?"
|
||||
if [ "$_api_status" -ne 0 ]; then
|
||||
if [ "$curResult" = "FATAL" ]; then
|
||||
_err "$(printf "Fatal error: acme API function call : %s" "$retVal")"
|
||||
fi
|
||||
if [ "$_edge_result" != "404" ]; then
|
||||
_err "$(printf "Failure accessing Akamai Edge DNS API Server. Error: %s" "$_edge_result")"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
_debug3 "_edge_result" "$_edge_result"
|
||||
record_op="DELETE"
|
||||
body=""
|
||||
if [ "$_api_status" -eq 0 ]; then
|
||||
# record already exists. Get existing record data and update
|
||||
rdlist="${_edge_result#*\"rdata\":[}"
|
||||
rdlist="${rdlist%%]*}"
|
||||
rdlist=$(echo "$rdlist" | tr -d '"' | tr -d "\\\\")
|
||||
_debug3 "rdlist" "$rdlist"
|
||||
if [ -n "$rdlist" ]; then
|
||||
record_op="PUT"
|
||||
comma=""
|
||||
rdata=""
|
||||
_txt_val=""
|
||||
while [ "$_txt_val" != "$rdlist" ] && [ "$rdlist" ]; do
|
||||
_txt_val="${rdlist%%,*}"
|
||||
rdlist="${rdlist#*,}"
|
||||
_debug3 "_txt_val" "$_txt_val"
|
||||
_debug3 "txtvalue" "$txtvalue"
|
||||
if ! _contains "$_txt_val" "$txtvalue"; then
|
||||
rdata="${rdata}${comma}\"${_txt_val}\""
|
||||
comma=","
|
||||
fi
|
||||
done
|
||||
if [ -z "$rdata" ]; then
|
||||
record_op="DELETE"
|
||||
else
|
||||
# Recreate the txtvalue TXT Record
|
||||
body="{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"ttl\":600, \"rdata\":"[${rdata}]"}"
|
||||
_debug3 "body" "$body"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
_edge_result=$(_edgedns_rest "$record_op" "$acmeRecordURI" "$body")
|
||||
_api_status="$?"
|
||||
if [ "$_api_status" -eq 0 ]; then
|
||||
_log "$(printf "Text value %s removed from recordset %s" "$txtvalue" "$fulldomain")"
|
||||
return 0
|
||||
else
|
||||
_err "$(printf "error removing TXT record for validation. Error: %s" "$_edge_result")"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
_EDGEDNS_credentials() {
|
||||
_debug "GettingEdge DNS credentials"
|
||||
_log "$(printf "ACME DNSAPI Edge DNS version %s" ${ACME_EDGEDNS_VERSION})"
|
||||
args_missing=0
|
||||
if [ -z "$AKAMAI_ACCESS_TOKEN" ]; then
|
||||
AKAMAI_ACCESS_TOKEN=""
|
||||
AKAMAI_CLIENT_TOKEN=""
|
||||
AKAMAI_HOST=""
|
||||
AKAMAI_CLIENT_SECRET=""
|
||||
_err "AKAMAI_ACCESS_TOKEN is missing"
|
||||
args_missing=1
|
||||
fi
|
||||
if [ -z "$AKAMAI_CLIENT_TOKEN" ]; then
|
||||
AKAMAI_ACCESS_TOKEN=""
|
||||
AKAMAI_CLIENT_TOKEN=""
|
||||
AKAMAI_HOST=""
|
||||
AKAMAI_CLIENT_SECRET=""
|
||||
_err "AKAMAI_CLIENT_TOKEN is missing"
|
||||
args_missing=1
|
||||
fi
|
||||
if [ -z "$AKAMAI_HOST" ]; then
|
||||
AKAMAI_ACCESS_TOKEN=""
|
||||
AKAMAI_CLIENT_TOKEN=""
|
||||
AKAMAI_HOST=""
|
||||
AKAMAI_CLIENT_SECRET=""
|
||||
_err "AKAMAI_HOST is missing"
|
||||
args_missing=1
|
||||
fi
|
||||
if [ -z "$AKAMAI_CLIENT_SECRET" ]; then
|
||||
AKAMAI_ACCESS_TOKEN=""
|
||||
AKAMAI_CLIENT_TOKEN=""
|
||||
AKAMAI_HOST=""
|
||||
AKAMAI_CLIENT_SECRET=""
|
||||
_err "AKAMAI_CLIENT_SECRET is missing"
|
||||
args_missing=1
|
||||
fi
|
||||
|
||||
if [ "$args_missing" = 1 ]; then
|
||||
_err "You have not properly specified the EdgeDNS Open Edgegrid API credentials. Please try again."
|
||||
return 1
|
||||
else
|
||||
_saveaccountconf_mutable AKAMAI_ACCESS_TOKEN "$AKAMAI_ACCESS_TOKEN"
|
||||
_saveaccountconf_mutable AKAMAI_CLIENT_TOKEN "$AKAMAI_CLIENT_TOKEN"
|
||||
_saveaccountconf_mutable AKAMAI_HOST "$AKAMAI_HOST"
|
||||
_saveaccountconf_mutable AKAMAI_CLIENT_SECRET "$AKAMAI_CLIENT_SECRET"
|
||||
# Set whether curl should use secure or insecure mode
|
||||
fi
|
||||
export HTTPS_INSECURE=0 # All Edgegrid API calls are secure
|
||||
edge_endpoint=$(printf "https://%s/config-dns/v2/zones" "$AKAMAI_HOST")
|
||||
_debug3 "Edge API Endpoint:" "$edge_endpoint"
|
||||
|
||||
}
|
||||
|
||||
_EDGEDNS_getZoneInfo() {
|
||||
_debug "Getting Zoneinfo"
|
||||
zoneEnd=false
|
||||
curZone=$1
|
||||
while [ -n "$zoneEnd" ]; do
|
||||
# we can strip the first part of the fulldomain, since its just the _acme-challenge string
|
||||
curZone="${curZone#*.}"
|
||||
# suffix . needed for zone -> domain.tld.
|
||||
# create zone get url
|
||||
get_zone_url=$(printf "%s/%s" "$edge_endpoint" "$curZone")
|
||||
_debug3 "Zone Get: " "${get_zone_url}"
|
||||
curResult=$(_edgedns_rest GET "$get_zone_url")
|
||||
retVal=$?
|
||||
if [ "$retVal" -ne 0 ]; then
|
||||
if [ "$curResult" = "FATAL" ]; then
|
||||
_err "$(printf "Fatal error: acme API function call : %s" "$retVal")"
|
||||
fi
|
||||
if [ "$curResult" != "404" ]; then
|
||||
_err "$(printf "Managed zone validation failed. Error response: %s" "$retVal")"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
if _contains "$curResult" "\"zone\":"; then
|
||||
_debug2 "Zone data" "${curResult}"
|
||||
zone=$(echo "${curResult}" | _egrep_o "\"zone\"\\s*:\\s*\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d "\"")
|
||||
_debug3 "Zone" "${zone}"
|
||||
zoneEnd=""
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ "${curZone#*.}" != "$curZone" ]; then
|
||||
_debug3 "$(printf "%s still contains a '.' - so we can check next higher level" "$curZone")"
|
||||
else
|
||||
zoneEnd=true
|
||||
_err "Couldn't retrieve zone data."
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
_err "Failed to retrieve zone data."
|
||||
return 2
|
||||
}
|
||||
|
||||
_edgedns_headers=""
|
||||
|
||||
_edgedns_rest() {
|
||||
_debug "Handling API Request"
|
||||
m=$1
|
||||
# Assume endpoint is complete path, including query args if applicable
|
||||
ep=$2
|
||||
body_data=$3
|
||||
_edgedns_content_type=""
|
||||
_request_url_path="$ep"
|
||||
_request_body="$body_data"
|
||||
_request_method="$m"
|
||||
_edgedns_headers=""
|
||||
tab=""
|
||||
_edgedns_headers="${_edgedns_headers}${tab}Host: ${AKAMAI_HOST}"
|
||||
tab="\t"
|
||||
# Set in acme.sh _post/_get
|
||||
#_edgedns_headers="${_edgedns_headers}${tab}User-Agent:ACME DNSAPI Edge DNS version ${ACME_EDGEDNS_VERSION}"
|
||||
_edgedns_headers="${_edgedns_headers}${tab}Accept: application/json,*/*"
|
||||
if [ "$m" != "GET" ] && [ "$m" != "DELETE" ]; then
|
||||
_edgedns_content_type="application/json"
|
||||
_debug3 "_request_body" "$_request_body"
|
||||
_body_len=$(echo "$_request_body" | tr -d "\n\r" | awk '{print length}')
|
||||
_edgedns_headers="${_edgedns_headers}${tab}Content-Length: ${_body_len}"
|
||||
fi
|
||||
_edgedns_make_auth_header
|
||||
_edgedns_headers="${_edgedns_headers}${tab}Authorization: ${_signed_auth_header}"
|
||||
_secure_debug2 "Made Auth Header" "$_signed_auth_header"
|
||||
hdr_indx=1
|
||||
work_header="${_edgedns_headers}${tab}"
|
||||
_debug3 "work_header" "$work_header"
|
||||
while [ "$work_header" ]; do
|
||||
entry="${work_header%%\\t*}"
|
||||
work_header="${work_header#*\\t}"
|
||||
export "$(printf "_H%s=%s" "$hdr_indx" "$entry")"
|
||||
_debug2 "Request Header " "$entry"
|
||||
hdr_indx=$((hdr_indx + 1))
|
||||
done
|
||||
|
||||
# clear headers from previous request to avoid getting wrong http code on timeouts
|
||||
: >"$HTTP_HEADER"
|
||||
_debug2 "$ep"
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug3 "Method data" "$data"
|
||||
# body url [needbase64] [POST|PUT|DELETE] [ContentType]
|
||||
response=$(_post "$_request_body" "$ep" false "$m" "$_edgedns_content_type")
|
||||
else
|
||||
response=$(_get "$ep")
|
||||
fi
|
||||
_ret="$?"
|
||||
if [ "$_ret" -ne 0 ]; then
|
||||
_err "$(printf "acme.sh API function call failed. Error: %s" "$_ret")"
|
||||
echo "FATAL"
|
||||
return "$_ret"
|
||||
fi
|
||||
_debug2 "response" "${response}"
|
||||
_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")"
|
||||
_debug2 "http response code" "$_code"
|
||||
if [ "$_code" = "200" ] || [ "$_code" = "201" ]; then
|
||||
# All good
|
||||
response="$(echo "${response}" | _normalizeJson)"
|
||||
echo "$response"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ "$_code" = "204" ]; then
|
||||
# Success, no body
|
||||
echo "$_code"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ "$_code" = "400" ]; then
|
||||
_err "Bad request presented"
|
||||
_log "$(printf "Headers: %s" "$_edgedns_headers")"
|
||||
_log "$(printf "Method: %s" "$_request_method")"
|
||||
_log "$(printf "URL: %s" "$ep")"
|
||||
_log "$(printf "Data: %s" "$data")"
|
||||
fi
|
||||
|
||||
if [ "$_code" = "403" ]; then
|
||||
_err "access denied make sure your Edgegrid cedentials are correct."
|
||||
fi
|
||||
|
||||
echo "$_code"
|
||||
return 1
|
||||
}
|
||||
|
||||
_edgedns_eg_timestamp() {
|
||||
_debug "Generating signature Timestamp"
|
||||
_debug3 "Retriving ntp time"
|
||||
_timeheaders="$(_get "https://www.ntp.org" "onlyheader")"
|
||||
_debug3 "_timeheaders" "$_timeheaders"
|
||||
_ntpdate="$(echo "$_timeheaders" | grep -i "Date:" | _head_n 1 | cut -d ':' -f 2- | tr -d "\r\n")"
|
||||
_debug3 "_ntpdate" "$_ntpdate"
|
||||
_ntpdate="$(echo "${_ntpdate}" | sed -e 's/^[[:space:]]*//')"
|
||||
_debug3 "_NTPDATE" "$_ntpdate"
|
||||
_ntptime="$(echo "${_ntpdate}" | _head_n 1 | cut -d " " -f 5 | tr -d "\r\n")"
|
||||
_debug3 "_ntptime" "$_ntptime"
|
||||
_eg_timestamp=$(date -u "+%Y%m%dT")
|
||||
_eg_timestamp="$(printf "%s%s+0000" "$_eg_timestamp" "$_ntptime")"
|
||||
_debug "_eg_timestamp" "$_eg_timestamp"
|
||||
}
|
||||
|
||||
_edgedns_new_nonce() {
|
||||
_debug "Generating Nonce"
|
||||
_nonce=$(echo "EDGEDNS$(_time)" | _digest sha1 hex | cut -c 1-32)
|
||||
_debug3 "_nonce" "$_nonce"
|
||||
}
|
||||
|
||||
_edgedns_make_auth_header() {
|
||||
_debug "Constructing Auth Header"
|
||||
_edgedns_new_nonce
|
||||
_edgedns_eg_timestamp
|
||||
# "Unsigned authorization header: 'EG1-HMAC-SHA256 client_token=block;access_token=block;timestamp=20200806T14:16:33+0000;nonce=72cde72c-82d9-4721-9854-2ba057929d67;'"
|
||||
_auth_header="$(printf "EG1-HMAC-SHA256 client_token=%s;access_token=%s;timestamp=%s;nonce=%s;" "$AKAMAI_CLIENT_TOKEN" "$AKAMAI_ACCESS_TOKEN" "$_eg_timestamp" "$_nonce")"
|
||||
_secure_debug2 "Unsigned Auth Header: " "$_auth_header"
|
||||
|
||||
_edgedns_sign_request
|
||||
_signed_auth_header="$(printf "%ssignature=%s" "$_auth_header" "$_signed_req")"
|
||||
_secure_debug2 "Signed Auth Header: " "${_signed_auth_header}"
|
||||
}
|
||||
|
||||
_edgedns_sign_request() {
|
||||
_debug2 "Signing http request"
|
||||
_edgedns_make_data_to_sign "$_auth_header"
|
||||
_secure_debug2 "Returned signed data" "$_mdata"
|
||||
_edgedns_make_signing_key "$_eg_timestamp"
|
||||
_edgedns_base64_hmac_sha256 "$_mdata" "$_signing_key"
|
||||
_signed_req="$_hmac_out"
|
||||
_secure_debug2 "Signed Request" "$_signed_req"
|
||||
}
|
||||
|
||||
_edgedns_make_signing_key() {
|
||||
_debug2 "Creating sigining key"
|
||||
ts=$1
|
||||
_edgedns_base64_hmac_sha256 "$ts" "$AKAMAI_CLIENT_SECRET"
|
||||
_signing_key="$_hmac_out"
|
||||
_secure_debug2 "Signing Key" "$_signing_key"
|
||||
|
||||
}
|
||||
|
||||
_edgedns_make_data_to_sign() {
|
||||
_debug2 "Processing data to sign"
|
||||
hdr=$1
|
||||
_secure_debug2 "hdr" "$hdr"
|
||||
_edgedns_make_content_hash
|
||||
path="$(echo "$_request_url_path" | tr -d "\n\r" | sed 's/https\?:\/\///')"
|
||||
path="${path#*$AKAMAI_HOST}"
|
||||
_debug "hier path" "$path"
|
||||
# dont expose headers to sign so use MT string
|
||||
_mdata="$(printf "%s\thttps\t%s\t%s\t%s\t%s\t%s" "$_request_method" "$AKAMAI_HOST" "$path" "" "$_hash" "$hdr")"
|
||||
_secure_debug2 "Data to Sign" "$_mdata"
|
||||
}
|
||||
|
||||
_edgedns_make_content_hash() {
|
||||
_debug2 "Generating content hash"
|
||||
_hash=""
|
||||
_debug2 "Request method" "${_request_method}"
|
||||
if [ "$_request_method" != "POST" ] || [ -z "$_request_body" ]; then
|
||||
return 0
|
||||
fi
|
||||
_debug2 "Req body" "$_request_body"
|
||||
_edgedns_base64_sha256 "$_request_body"
|
||||
_hash="$_sha256_out"
|
||||
_debug2 "Content hash" "$_hash"
|
||||
}
|
||||
|
||||
_edgedns_base64_hmac_sha256() {
|
||||
_debug2 "Generating hmac"
|
||||
data=$1
|
||||
key=$2
|
||||
encoded_data="$(echo "$data" | iconv -t utf-8)"
|
||||
encoded_key="$(echo "$key" | iconv -t utf-8)"
|
||||
_secure_debug2 "encoded data" "$encoded_data"
|
||||
_secure_debug2 "encoded key" "$encoded_key"
|
||||
|
||||
encoded_key_hex=$(printf "%s" "$encoded_key" | _hex_dump | tr -d ' ')
|
||||
data_sig="$(echo "$encoded_data" | tr -d "\n\r" | _hmac sha256 "$encoded_key_hex" | _base64)"
|
||||
|
||||
_secure_debug2 "data_sig:" "$data_sig"
|
||||
_hmac_out="$(echo "$data_sig" | tr -d "\n\r" | iconv -f utf-8)"
|
||||
_secure_debug2 "hmac" "$_hmac_out"
|
||||
}
|
||||
|
||||
_edgedns_base64_sha256() {
|
||||
_debug2 "Creating sha256 digest"
|
||||
trg=$1
|
||||
_secure_debug2 "digest data" "$trg"
|
||||
digest="$(echo "$trg" | tr -d "\n\r" | _digest "sha256")"
|
||||
_sha256_out="$(echo "$digest" | tr -d "\n\r" | iconv -f utf-8)"
|
||||
_secure_debug2 "digest decode" "$_sha256_out"
|
||||
}
|
||||
|
||||
#_edgedns_parse_edgerc() {
|
||||
# filepath=$1
|
||||
# section=$2
|
||||
#}
|
||||
@@ -303,10 +303,10 @@ _freedns_domain_id() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
domain_id="$(echo "$htmlpage" | tr -d " \t\r\n\v\f" | sed 's/<tr>/@<tr>/g' | tr '@' '\n' \
|
||||
| grep "<td>$search_domain</td>\|<td>$search_domain(.*)</td>" \
|
||||
| sed -n 's/.*\(edit\.php?edit_domain_id=[0-9a-zA-Z]*\).*/\1/p' \
|
||||
| cut -d = -f 2)"
|
||||
domain_id="$(echo "$htmlpage" | tr -d " \t\r\n\v\f" | sed 's/<tr>/@<tr>/g' | tr '@' '\n' |
|
||||
grep "<td>$search_domain</td>\|<td>$search_domain(.*)</td>" |
|
||||
sed -n 's/.*\(edit\.php?edit_domain_id=[0-9a-zA-Z]*\).*/\1/p' |
|
||||
cut -d = -f 2)"
|
||||
# The above beauty extracts domain ID from the html page...
|
||||
# strip out all blank space and new lines. Then insert newlines
|
||||
# before each table row <tr>
|
||||
@@ -349,11 +349,11 @@ _freedns_data_id() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
data_id="$(echo "$htmlpage" | tr -d " \t\r\n\v\f" | sed 's/<tr>/@<tr>/g' | tr '@' '\n' \
|
||||
| grep "<td[a-zA-Z=#]*>$record_type</td>" \
|
||||
| grep "<ahref.*>$search_domain</a>" \
|
||||
| sed -n 's/.*\(edit\.php?data_id=[0-9a-zA-Z]*\).*/\1/p' \
|
||||
| cut -d = -f 2)"
|
||||
data_id="$(echo "$htmlpage" | tr -d " \t\r\n\v\f" | sed 's/<tr>/@<tr>/g' | tr '@' '\n' |
|
||||
grep "<td[a-zA-Z=#]*>$record_type</td>" |
|
||||
grep "<ahref.*>$search_domain</a>" |
|
||||
sed -n 's/.*\(edit\.php?data_id=[0-9a-zA-Z]*\).*/\1/p' |
|
||||
cut -d = -f 2)"
|
||||
# The above beauty extracts data ID from the html page...
|
||||
# strip out all blank space and new lines. Then insert newlines
|
||||
# before each table row <tr>
|
||||
|
||||
@@ -69,9 +69,9 @@ 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"}' \
|
||||
&& _info "Removing record $(__green "success")"
|
||||
"{\"rrset_ttl\": 300, \"rrset_values\": $_new_rrset_values}" &&
|
||||
_contains "$response" '{"message": "DNS Record Created"}' &&
|
||||
_info "Removing record $(__green "success")"
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
@@ -125,9 +125,9 @@ _dns_gandi_append_record() {
|
||||
fi
|
||||
_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"}' \
|
||||
&& _info "Adding record $(__green "success")"
|
||||
"{\"rrset_ttl\": 300, \"rrset_values\": $_rrset_values}" &&
|
||||
_contains "$response" '{"message": "DNS Record Created"}' &&
|
||||
_info "Adding record $(__green "success")"
|
||||
}
|
||||
|
||||
_dns_gandi_existing_rrset_values() {
|
||||
@@ -145,8 +145,8 @@ _dns_gandi_existing_rrset_values() {
|
||||
return 1
|
||||
fi
|
||||
_debug "Already has TXT record."
|
||||
_rrset_values=$(echo "$response" | _egrep_o 'rrset_values.*\[.*\]' \
|
||||
| _egrep_o '\[".*\"]')
|
||||
_rrset_values=$(echo "$response" | _egrep_o 'rrset_values.*\[.*\]' |
|
||||
_egrep_o '\[".*\"]')
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
@@ -78,8 +78,8 @@ _dns_gcloud_execute_tr() {
|
||||
for i in $(seq 1 120); do
|
||||
if gcloud dns record-sets changes list \
|
||||
--zone="$managedZone" \
|
||||
--filter='status != done' \
|
||||
| grep -q '^.*'; then
|
||||
--filter='status != done' |
|
||||
grep -q '^.*'; then
|
||||
_info "_dns_gcloud_execute_tr: waiting for transaction to be comitted ($i/120)..."
|
||||
sleep 5
|
||||
else
|
||||
@@ -137,11 +137,11 @@ _dns_gcloud_find_zone() {
|
||||
# List domains and find the zone with the deepest sub-domain (in case of some levels of delegation)
|
||||
if ! match=$(gcloud dns managed-zones list \
|
||||
--format="value(name, dnsName)" \
|
||||
--filter="$filter" \
|
||||
| while read -r dnsName name; do
|
||||
--filter="$filter" |
|
||||
while read -r dnsName name; do
|
||||
printf "%s\t%s\t%s\n" "$(echo "$name" | awk -F"." '{print NF-1}')" "$dnsName" "$name"
|
||||
done \
|
||||
| sort -n -r | _head_n 1 | cut -f2,3 | grep '^.*'); then
|
||||
done |
|
||||
sort -n -r | _head_n 1 | cut -f2,3 | grep '^.*'); then
|
||||
_err "_dns_gcloud_find_zone: Can't find a matching managed zone! Perhaps wrong project or gcloud credentials?"
|
||||
return 1
|
||||
fi
|
||||
|
||||
@@ -91,7 +91,7 @@ dns_gd_rm() {
|
||||
fi
|
||||
|
||||
if ! _contains "$response" "$txtvalue"; then
|
||||
_info "The record is not existing, skip"
|
||||
_info "The record does not exist, skip"
|
||||
return 0
|
||||
fi
|
||||
|
||||
|
||||
@@ -157,9 +157,18 @@ _successful_update() {
|
||||
}
|
||||
|
||||
_findentry() {
|
||||
#args $1: fulldomain, $2: txtvalue
|
||||
#returns id of dns entry, if it exists
|
||||
_myget "action=dns_primary_changeDNSsetup&user_domain=$_domain"
|
||||
_id=$(echo "$_result" | _egrep_o "<td>$1</td>\s*<td>$2</td>[^?]*[^&]*&id=[^&]*" | sed 's/^.*=//')
|
||||
_debug3 "_result: $_result"
|
||||
|
||||
_tmp_result=$(echo "$_result" | tr -d '\n\r' | _egrep_o "<td>$1</td>\s*<td>$2</td>[^?]*[^&]*&id=[^&]*")
|
||||
_debug _tmp_result "$_tmp_result"
|
||||
if [ -z "${_tmp_result:-}" ]; then
|
||||
_debug "The variable is _tmp_result is not supposed to be empty, there may be something wrong with the script"
|
||||
fi
|
||||
|
||||
_id=$(echo "$_tmp_result" | sed 's/^.*=//')
|
||||
if [ -n "$_id" ]; then
|
||||
_debug "Entry found with _id=$_id"
|
||||
return 0
|
||||
|
||||
@@ -85,7 +85,7 @@ dns_he_rm() {
|
||||
_debug "The txt record is not found, just skip"
|
||||
return 0
|
||||
fi
|
||||
_record_id="$(echo "$response" | tr -d "#" | sed "s/<tr/#<tr/g" | tr -d "\n" | tr "#" "\n" | grep "$_full_domain" | grep '"dns_tr"' | grep "$_txt_value" | cut -d '"' -f 4)"
|
||||
_record_id="$(echo "$response" | tr -d "#" | sed "s/<tr/#<tr/g" | tr -d "\n" | tr "#" "\n" | grep "$_full_domain" | grep '"dns_tr"' | grep -- "$_txt_value" | cut -d '"' -f 4)"
|
||||
_debug2 _record_id "$_record_id"
|
||||
if [ -z "$_record_id" ]; then
|
||||
_err "Can not find record id"
|
||||
@@ -101,8 +101,8 @@ dns_he_rm() {
|
||||
body="$body&hosted_dns_editzone=1"
|
||||
body="$body&hosted_dns_delrecord=1"
|
||||
body="$body&hosted_dns_delconfirm=delete"
|
||||
_post "$body" "https://dns.he.net/" \
|
||||
| grep '<div id="dns_status" onClick="hideThis(this);">Successfully removed record.</div>' \
|
||||
_post "$body" "https://dns.he.net/" |
|
||||
grep '<div id="dns_status" onClick="hideThis(this);">Successfully removed record.</div>' \
|
||||
>/dev/null
|
||||
exit_code="$?"
|
||||
if [ "$exit_code" -eq 0 ]; then
|
||||
|
||||
252
dnsapi/dns_hetzner.sh
Normal file
252
dnsapi/dns_hetzner.sh
Normal file
@@ -0,0 +1,252 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
#HETZNER_Token="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
#
|
||||
|
||||
HETZNER_Api="https://dns.hetzner.com/api/v1"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
# Used to add txt record
|
||||
# Ref: https://dns.hetzner.com/api-docs/
|
||||
dns_hetzner_add() {
|
||||
full_domain=$1
|
||||
txt_value=$2
|
||||
|
||||
HETZNER_Token="${HETZNER_Token:-$(_readaccountconf_mutable HETZNER_Token)}"
|
||||
|
||||
if [ -z "$HETZNER_Token" ]; then
|
||||
HETZNER_Token=""
|
||||
_err "You didn't specify a Hetzner api token."
|
||||
_err "You can get yours from here https://dns.hetzner.com/settings/api-token."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the api key and email to the account conf file.
|
||||
_saveaccountconf_mutable HETZNER_Token "$HETZNER_Token"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
|
||||
if ! _get_root "$full_domain"; then
|
||||
_err "Invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_debug "Getting TXT records"
|
||||
if ! _find_record "$_sub_domain" "$txt_value"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$_record_id" ]; then
|
||||
_info "Adding record"
|
||||
if _hetzner_rest POST "records" "{\"zone_id\":\"${HETZNER_Zone_ID}\",\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txt_value\",\"ttl\":120}"; then
|
||||
if _contains "$response" "$txt_value"; then
|
||||
_info "Record added, OK"
|
||||
_sleep 2
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
_err "Add txt record error${_response_error}"
|
||||
return 1
|
||||
else
|
||||
_info "Found record id: $_record_id."
|
||||
_info "Record found, do nothing."
|
||||
return 0
|
||||
# we could modify a record, if the names for txt records for *.example.com and example.com would be not the same
|
||||
#if _hetzner_rest PUT "records/${_record_id}" "{\"zone_id\":\"${HETZNER_Zone_ID}\",\"type\":\"TXT\",\"name\":\"$full_domain\",\"value\":\"$txt_value\",\"ttl\":120}"; then
|
||||
# if _contains "$response" "$txt_value"; then
|
||||
# _info "Modified, OK"
|
||||
# return 0
|
||||
# fi
|
||||
#fi
|
||||
#_err "Add txt record error (modify)."
|
||||
#return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Usage: full_domain txt_value
|
||||
# Used to remove the txt record after validation
|
||||
dns_hetzner_rm() {
|
||||
full_domain=$1
|
||||
txt_value=$2
|
||||
|
||||
HETZNER_Token="${HETZNER_Token:-$(_readaccountconf_mutable HETZNER_Token)}"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$full_domain"; then
|
||||
_err "Invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_debug "Getting TXT records"
|
||||
if ! _find_record "$_sub_domain" "$txt_value"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$_record_id" ]; then
|
||||
_info "Remove not needed. Record not found."
|
||||
else
|
||||
if ! _hetzner_rest DELETE "records/$_record_id"; then
|
||||
_err "Delete record error${_response_error}"
|
||||
return 1
|
||||
fi
|
||||
_sleep 2
|
||||
_info "Record deleted"
|
||||
fi
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#returns
|
||||
# _record_id=a8d58f22d6931bf830eaa0ec6464bf81 if found; or 1 if error
|
||||
_find_record() {
|
||||
unset _record_id
|
||||
_record_name=$1
|
||||
_record_value=$2
|
||||
|
||||
if [ -z "$_record_value" ]; then
|
||||
_record_value='[^"]*'
|
||||
fi
|
||||
|
||||
_debug "Getting all records"
|
||||
_hetzner_rest GET "records?zone_id=${_domain_id}"
|
||||
|
||||
if _response_has_error; then
|
||||
_err "Error${_response_error}"
|
||||
return 1
|
||||
else
|
||||
_record_id=$(
|
||||
echo "$response" |
|
||||
grep -o "{[^\{\}]*\"name\":\"$_record_name\"[^\}]*}" |
|
||||
grep "\"value\":\"$_record_value\"" |
|
||||
while read -r record; do
|
||||
# test for type and
|
||||
if [ -n "$(echo "$record" | _egrep_o '"type":"TXT"')" ]; then
|
||||
echo "$record" | _egrep_o '"id":"[^"]*"' | cut -d : -f 2 | tr -d \"
|
||||
break
|
||||
fi
|
||||
done
|
||||
)
|
||||
fi
|
||||
}
|
||||
|
||||
#_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
|
||||
|
||||
domain_without_acme=$(echo "$domain" | cut -d . -f 2-)
|
||||
domain_param_name=$(echo "HETZNER_Zone_ID_for_${domain_without_acme}" | sed 's/[\.\-]/_/g')
|
||||
|
||||
_debug "Reading zone_id for '$domain_without_acme' from config..."
|
||||
HETZNER_Zone_ID=$(_readdomainconf "$domain_param_name")
|
||||
if [ "$HETZNER_Zone_ID" ]; then
|
||||
_debug "Found, using: $HETZNER_Zone_ID"
|
||||
if ! _hetzner_rest GET "zones/${HETZNER_Zone_ID}"; then
|
||||
_debug "Zone with id '$HETZNER_Zone_ID' does not exist."
|
||||
_cleardomainconf "$domain_param_name"
|
||||
unset HETZNER_Zone_ID
|
||||
else
|
||||
if _contains "$response" "\"id\":\"$HETZNER_Zone_ID\""; then
|
||||
_domain=$(printf "%s\n" "$response" | _egrep_o '"name":"[^"]*"' | cut -d : -f 2 | tr -d \" | head -n 1)
|
||||
if [ "$_domain" ]; then
|
||||
_cut_length=$((${#domain} - ${#_domain} - 1))
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -c "1-$_cut_length")
|
||||
_domain_id="$HETZNER_Zone_ID"
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
_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)
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
_debug h "$h"
|
||||
|
||||
_hetzner_rest GET "zones?name=$h"
|
||||
|
||||
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)
|
||||
_domain=$h
|
||||
HETZNER_Zone_ID=$_domain_id
|
||||
_savedomainconf "$domain_param_name" "$HETZNER_Zone_ID"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
#returns
|
||||
# _response_error
|
||||
_response_has_error() {
|
||||
unset _response_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)
|
||||
err_message=$(echo "$err_part" | _egrep_o '"message":"[^"]+"' | cut -d : -f 2 | tr -d \")
|
||||
|
||||
if [ -n "$err_code" ] && [ -n "$err_message" ]; then
|
||||
_response_error=" - message: ${err_message}, code: ${err_code}"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
#returns
|
||||
# response
|
||||
_hetzner_rest() {
|
||||
m=$1
|
||||
ep="$2"
|
||||
data="$3"
|
||||
_debug "$ep"
|
||||
|
||||
key_trimmed=$(echo "$HETZNER_Token" | tr -d \")
|
||||
|
||||
export _H1="Content-TType: application/json"
|
||||
export _H2="Auth-API-Token: $key_trimmed"
|
||||
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$HETZNER_Api/$ep" "" "$m")"
|
||||
else
|
||||
response="$(_get "$HETZNER_Api/$ep")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ] || _response_has_error; then
|
||||
_debug "Error$_response_error"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
@@ -42,7 +42,7 @@ dns_hexonet_add() {
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_debug "Getting txt records"
|
||||
_hexonet_rest "&command=QueryDNSZoneRRList&dnszone=${h}.&RRTYPE=TXT"
|
||||
_hexonet_rest "command=QueryDNSZoneRRList&dnszone=${h}.&RRTYPE=TXT"
|
||||
|
||||
if ! _contains "$response" "CODE=200"; then
|
||||
_err "Error"
|
||||
@@ -88,7 +88,7 @@ dns_hexonet_rm() {
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_debug "Getting txt records"
|
||||
_hexonet_rest "&command=QueryDNSZoneRRList&dnszone=${h}.&RRTYPE=TXT&RR=${txtvalue}"
|
||||
_hexonet_rest "command=QueryDNSZoneRRList&dnszone=${h}.&RRTYPE=TXT&RR=${_sub_domain}%20IN%20TXT%20\"${txtvalue}\""
|
||||
|
||||
if ! _contains "$response" "CODE=200"; then
|
||||
_err "Error"
|
||||
@@ -100,7 +100,7 @@ dns_hexonet_rm() {
|
||||
if [ "$count" = "0" ]; then
|
||||
_info "Don't need to remove."
|
||||
else
|
||||
if ! _hexonet_rest "&command=UpdateDNSZone&dnszone=${_domain}.&delrr0='${_sub_domain}%20IN%20TXT%20\"${txtvalue}\""; then
|
||||
if ! _hexonet_rest "command=UpdateDNSZone&dnszone=${_domain}.&delrr0=${_sub_domain}%20IN%20TXT%20\"${txtvalue}\""; then
|
||||
_err "Delete record error."
|
||||
return 1
|
||||
fi
|
||||
@@ -126,7 +126,7 @@ _get_root() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _hexonet_rest "&command=QueryDNSZoneRRList&dnszone=${h}."; then
|
||||
if ! _hexonet_rest "command=QueryDNSZoneRRList&dnszone=${h}."; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
|
||||
275
dnsapi/dns_huaweicloud.sh
Normal file
275
dnsapi/dns_huaweicloud.sh
Normal file
@@ -0,0 +1,275 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# HUAWEICLOUD_Username
|
||||
# HUAWEICLOUD_Password
|
||||
# HUAWEICLOUD_ProjectID
|
||||
|
||||
iam_api="https://iam.myhuaweicloud.com"
|
||||
dns_api="https://dns.ap-southeast-1.myhuaweicloud.com" # Should work
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
# Used to add txt record
|
||||
#
|
||||
# Ref: https://support.huaweicloud.com/intl/zh-cn/api-dns/zh-cn_topic_0132421999.html
|
||||
#
|
||||
|
||||
dns_huaweicloud_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
HUAWEICLOUD_Username="${HUAWEICLOUD_Username:-$(_readaccountconf_mutable HUAWEICLOUD_Username)}"
|
||||
HUAWEICLOUD_Password="${HUAWEICLOUD_Password:-$(_readaccountconf_mutable HUAWEICLOUD_Password)}"
|
||||
HUAWEICLOUD_ProjectID="${HUAWEICLOUD_ProjectID:-$(_readaccountconf_mutable HUAWEICLOUD_ProjectID)}"
|
||||
|
||||
# Check information
|
||||
if [ -z "${HUAWEICLOUD_Username}" ] || [ -z "${HUAWEICLOUD_Password}" ] || [ -z "${HUAWEICLOUD_ProjectID}" ]; then
|
||||
_err "Not enough information provided to dns_huaweicloud!"
|
||||
return 1
|
||||
fi
|
||||
|
||||
unset token # Clear token
|
||||
token="$(_get_token "${HUAWEICLOUD_Username}" "${HUAWEICLOUD_Password}" "${HUAWEICLOUD_ProjectID}")"
|
||||
if [ -z "${token}" ]; then # Check token
|
||||
_err "dns_api(dns_huaweicloud): Error getting token."
|
||||
return 1
|
||||
fi
|
||||
_debug "Access token is: ${token}"
|
||||
|
||||
unset zoneid
|
||||
zoneid="$(_get_zoneid "${token}" "${fulldomain}")"
|
||||
if [ -z "${zoneid}" ]; then
|
||||
_err "dns_api(dns_huaweicloud): Error getting zone id."
|
||||
return 1
|
||||
fi
|
||||
_debug "Zone ID is: ${zoneid}"
|
||||
|
||||
_debug "Adding Record"
|
||||
_add_record "${token}" "${fulldomain}" "${txtvalue}"
|
||||
ret="$?"
|
||||
if [ "${ret}" != "0" ]; then
|
||||
_err "dns_api(dns_huaweicloud): Error adding record."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Do saving work if all succeeded
|
||||
_saveaccountconf_mutable HUAWEICLOUD_Username "${HUAWEICLOUD_Username}"
|
||||
_saveaccountconf_mutable HUAWEICLOUD_Password "${HUAWEICLOUD_Password}"
|
||||
_saveaccountconf_mutable HUAWEICLOUD_ProjectID "${HUAWEICLOUD_ProjectID}"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Usage: fulldomain txtvalue
|
||||
# Used to remove the txt record after validation
|
||||
#
|
||||
# Ref: https://support.huaweicloud.com/intl/zh-cn/api-dns/dns_api_64005.html
|
||||
#
|
||||
|
||||
dns_huaweicloud_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
HUAWEICLOUD_Username="${HUAWEICLOUD_Username:-$(_readaccountconf_mutable HUAWEICLOUD_Username)}"
|
||||
HUAWEICLOUD_Password="${HUAWEICLOUD_Password:-$(_readaccountconf_mutable HUAWEICLOUD_Password)}"
|
||||
HUAWEICLOUD_ProjectID="${HUAWEICLOUD_ProjectID:-$(_readaccountconf_mutable HUAWEICLOUD_ProjectID)}"
|
||||
|
||||
# Check information
|
||||
if [ -z "${HUAWEICLOUD_Username}" ] || [ -z "${HUAWEICLOUD_Password}" ] || [ -z "${HUAWEICLOUD_ProjectID}" ]; then
|
||||
_err "Not enough information provided to dns_huaweicloud!"
|
||||
return 1
|
||||
fi
|
||||
|
||||
unset token # Clear token
|
||||
token="$(_get_token "${HUAWEICLOUD_Username}" "${HUAWEICLOUD_Password}" "${HUAWEICLOUD_ProjectID}")"
|
||||
if [ -z "${token}" ]; then # Check token
|
||||
_err "dns_api(dns_huaweicloud): Error getting token."
|
||||
return 1
|
||||
fi
|
||||
_debug "Access token is: ${token}"
|
||||
|
||||
unset zoneid
|
||||
zoneid="$(_get_zoneid "${token}" "${fulldomain}")"
|
||||
if [ -z "${zoneid}" ]; then
|
||||
_err "dns_api(dns_huaweicloud): Error getting zone id."
|
||||
return 1
|
||||
fi
|
||||
_debug "Zone ID is: ${zoneid}"
|
||||
|
||||
# Remove all records
|
||||
# Therotically HuaweiCloud does not allow more than one record set
|
||||
# But remove them recurringly to increase robusty
|
||||
while [ "${record_id}" != "0" ]; do
|
||||
_debug "Removing Record"
|
||||
_rm_record "${token}" "${zoneid}" "${record_id}"
|
||||
record_id="$(_get_recordset_id "${token}" "${fulldomain}" "${zoneid}")"
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
################### Private functions below ##################################
|
||||
|
||||
# _get_zoneid
|
||||
#
|
||||
# _token=$1
|
||||
# _domain_string=$2
|
||||
#
|
||||
# printf "%s" "${_zoneid}"
|
||||
_get_zoneid() {
|
||||
_token=$1
|
||||
_domain_string=$2
|
||||
export _H1="X-Auth-Token: ${_token}"
|
||||
|
||||
i=1
|
||||
while true; do
|
||||
h=$(printf "%s" "${_domain_string}" | cut -d . -f $i-100)
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
_debug "$h"
|
||||
response=$(_get "${dns_api}/v2/zones?name=${h}")
|
||||
|
||||
if _contains "${response}" "id"; then
|
||||
_debug "Get Zone ID Success."
|
||||
_zoneid=$(echo "${response}" | _egrep_o "\"id\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")
|
||||
printf "%s" "${_zoneid}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
_get_recordset_id() {
|
||||
_token=$1
|
||||
_domain=$2
|
||||
_zoneid=$3
|
||||
export _H1="X-Auth-Token: ${_token}"
|
||||
|
||||
response=$(_get "${dns_api}/v2/zones/${_zoneid}/recordsets?name=${_domain}")
|
||||
if _contains "${response}" "id"; then
|
||||
_id="$(echo "${response}" | _egrep_o "\"id\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")"
|
||||
printf "%s" "${_id}"
|
||||
return 0
|
||||
fi
|
||||
printf "%s" "0"
|
||||
return 1
|
||||
}
|
||||
|
||||
_add_record() {
|
||||
_token=$1
|
||||
_domain=$2
|
||||
_txtvalue=$3
|
||||
|
||||
# Get Existing Records
|
||||
export _H1="X-Auth-Token: ${_token}"
|
||||
response=$(_get "${dns_api}/v2/zones/${zoneid}/recordsets?name=${_domain}")
|
||||
|
||||
_debug2 "${response}"
|
||||
_exist_record=$(echo "${response}" | _egrep_o '"records":[^]]*' | sed 's/\"records\"\:\[//g')
|
||||
_debug "${_exist_record}"
|
||||
|
||||
# Check if record exist
|
||||
# Generate body data
|
||||
if [ -z "${_exist_record}" ]; then
|
||||
_post_body="{
|
||||
\"name\": \"${_domain}.\",
|
||||
\"description\": \"ACME Challenge\",
|
||||
\"type\": \"TXT\",
|
||||
\"ttl\": 1,
|
||||
\"records\": [
|
||||
\"\\\"${_txtvalue}\\\"\"
|
||||
]
|
||||
}"
|
||||
else
|
||||
_post_body="{
|
||||
\"name\": \"${_domain}.\",
|
||||
\"description\": \"ACME Challenge\",
|
||||
\"type\": \"TXT\",
|
||||
\"ttl\": 1,
|
||||
\"records\": [
|
||||
${_exist_record},
|
||||
\"\\\"${_txtvalue}\\\"\"
|
||||
]
|
||||
}"
|
||||
fi
|
||||
|
||||
_record_id="$(_get_recordset_id "${_token}" "${_domain}" "${zoneid}")"
|
||||
_debug "Record Set ID is: ${_record_id}"
|
||||
|
||||
# Remove all records
|
||||
while [ "${_record_id}" != "0" ]; do
|
||||
_debug "Removing Record"
|
||||
_rm_record "${_token}" "${zoneid}" "${_record_id}"
|
||||
_record_id="$(_get_recordset_id "${_token}" "${_domain}" "${zoneid}")"
|
||||
done
|
||||
|
||||
# Add brand new records with all old and new records
|
||||
export _H2="Content-Type: application/json"
|
||||
export _H1="X-Auth-Token: ${_token}"
|
||||
|
||||
_debug2 "${_post_body}"
|
||||
_post "${_post_body}" "${dns_api}/v2/zones/${zoneid}/recordsets" >/dev/null
|
||||
_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")"
|
||||
if [ "$_code" != "202" ]; then
|
||||
_err "dns_huaweicloud: http code ${_code}"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# _rm_record $token $zoneid $recordid
|
||||
# assume ${dns_api} exist
|
||||
# no output
|
||||
# return 0
|
||||
_rm_record() {
|
||||
_token=$1
|
||||
_zone_id=$2
|
||||
_record_id=$3
|
||||
|
||||
export _H2="Content-Type: application/json"
|
||||
export _H1="X-Auth-Token: ${_token}"
|
||||
|
||||
_post "" "${dns_api}/v2/zones/${_zone_id}/recordsets/${_record_id}" false "DELETE" >/dev/null
|
||||
return $?
|
||||
}
|
||||
|
||||
_get_token() {
|
||||
_username=$1
|
||||
_password=$2
|
||||
_project=$3
|
||||
|
||||
_debug "Getting Token"
|
||||
body="{
|
||||
\"auth\": {
|
||||
\"identity\": {
|
||||
\"methods\": [
|
||||
\"password\"
|
||||
],
|
||||
\"password\": {
|
||||
\"user\": {
|
||||
\"name\": \"${_username}\",
|
||||
\"password\": \"${_password}\",
|
||||
\"domain\": {
|
||||
\"name\": \"${_username}\"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
\"scope\": {
|
||||
\"project\": {
|
||||
\"id\": \"${_project}\"
|
||||
}
|
||||
}
|
||||
}
|
||||
}"
|
||||
export _H1="Content-Type: application/json;charset=utf8"
|
||||
_post "${body}" "${iam_api}/v3/auth/tokens" >/dev/null
|
||||
_code=$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")
|
||||
_token=$(grep "^X-Subject-Token" "$HTTP_HEADER" | cut -d " " -f 2-)
|
||||
_debug2 "${_code}"
|
||||
printf "%s" "${_token}"
|
||||
return 0
|
||||
}
|
||||
@@ -9,7 +9,6 @@ dns_infoblox_add() {
|
||||
## Nothing to see here, just some housekeeping
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&view=$Infoblox_View"
|
||||
|
||||
_info "Using Infoblox API"
|
||||
_debug fulldomain "$fulldomain"
|
||||
@@ -19,12 +18,13 @@ dns_infoblox_add() {
|
||||
if [ -z "$Infoblox_Creds" ] || [ -z "$Infoblox_Server" ]; then
|
||||
Infoblox_Creds=""
|
||||
Infoblox_Server=""
|
||||
_err "You didn't specify the credentials, server or infoblox view yet (Infoblox_Creds, Infoblox_Server and Infoblox_View)."
|
||||
_err "Please set them via EXPORT ([username:password], [ip or hostname]) and try again."
|
||||
_err "You didn't specify the Infoblox credentials or server (Infoblox_Creds; Infoblox_Server)."
|
||||
_err "Please set them via EXPORT Infoblox_Creds=username:password or EXPORT Infoblox_server=ip/hostname and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$Infoblox_View" ]; then
|
||||
_info "No Infoblox_View set, using fallback value 'default'"
|
||||
Infoblox_View="default"
|
||||
fi
|
||||
|
||||
@@ -33,6 +33,9 @@ dns_infoblox_add() {
|
||||
_saveaccountconf Infoblox_Server "$Infoblox_Server"
|
||||
_saveaccountconf Infoblox_View "$Infoblox_View"
|
||||
|
||||
## URLencode Infoblox View to deal with e.g. spaces
|
||||
Infoblox_ViewEncoded=$(printf "%b" "$Infoblox_View" | _url_encode)
|
||||
|
||||
## Base64 encode the credentials
|
||||
Infoblox_CredsEncoded=$(printf "%b" "$Infoblox_Creds" | _base64)
|
||||
|
||||
@@ -40,11 +43,14 @@ dns_infoblox_add() {
|
||||
export _H1="Accept-Language:en-US"
|
||||
export _H2="Authorization: Basic $Infoblox_CredsEncoded"
|
||||
|
||||
## Construct the request URL
|
||||
baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&view=${Infoblox_ViewEncoded}"
|
||||
|
||||
## Add the challenge record to the Infoblox grid member
|
||||
result="$(_post "" "$baseurlnObject" "" "POST")"
|
||||
|
||||
## Let's see if we get something intelligible back from the unit
|
||||
if [ "$(echo "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then
|
||||
if [ "$(echo "$result" | _egrep_o "record:txt/.*:.*/${Infoblox_ViewEncoded}")" ]; then
|
||||
_info "Successfully created the txt record"
|
||||
return 0
|
||||
else
|
||||
@@ -65,6 +71,9 @@ dns_infoblox_rm() {
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
## URLencode Infoblox View to deal with e.g. spaces
|
||||
Infoblox_ViewEncoded=$(printf "%b" "$Infoblox_View" | _url_encode)
|
||||
|
||||
## Base64 encode the credentials
|
||||
Infoblox_CredsEncoded="$(printf "%b" "$Infoblox_Creds" | _base64)"
|
||||
|
||||
@@ -73,18 +82,18 @@ dns_infoblox_rm() {
|
||||
export _H2="Authorization: Basic $Infoblox_CredsEncoded"
|
||||
|
||||
## Does the record exist? Let's check.
|
||||
baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&view=$Infoblox_View&_return_type=xml-pretty"
|
||||
baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&view=${Infoblox_ViewEncoded}&_return_type=xml-pretty"
|
||||
result="$(_get "$baseurlnObject")"
|
||||
|
||||
## Let's see if we get something intelligible back from the grid
|
||||
if [ "$(echo "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then
|
||||
if [ "$(echo "$result" | _egrep_o "record:txt/.*:.*/${Infoblox_ViewEncoded}")" ]; then
|
||||
## Extract the object reference
|
||||
objRef="$(printf "%b" "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")"
|
||||
objRef="$(printf "%b" "$result" | _egrep_o "record:txt/.*:.*/${Infoblox_ViewEncoded}")"
|
||||
objRmUrl="https://$Infoblox_Server/wapi/v2.2.2/$objRef"
|
||||
## Delete them! All the stale records!
|
||||
rmResult="$(_post "" "$objRmUrl" "" "DELETE")"
|
||||
## Let's see if that worked
|
||||
if [ "$(echo "$rmResult" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then
|
||||
if [ "$(echo "$rmResult" | _egrep_o "record:txt/.*:.*/${Infoblox_ViewEncoded}")" ]; then
|
||||
_info "Successfully deleted $objRef"
|
||||
return 0
|
||||
else
|
||||
|
||||
199
dnsapi/dns_infomaniak.sh
Executable file
199
dnsapi/dns_infomaniak.sh
Executable file
@@ -0,0 +1,199 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
###############################################################################
|
||||
# Infomaniak API integration
|
||||
#
|
||||
# To use this API you need visit the API dashboard of your account
|
||||
# once logged into https://manager.infomaniak.com add /api/dashboard to the URL
|
||||
#
|
||||
# Please report bugs to
|
||||
# https://github.com/acmesh-official/acme.sh/issues/3188
|
||||
#
|
||||
# Note: the URL looks like this:
|
||||
# https://manager.infomaniak.com/v3/<account_id>/api/dashboard
|
||||
# Then generate a token with the scope Domain
|
||||
# this is given as an environment variable INFOMANIAK_API_TOKEN
|
||||
###############################################################################
|
||||
|
||||
# base variables
|
||||
|
||||
DEFAULT_INFOMANIAK_API_URL="https://api.infomaniak.com"
|
||||
DEFAULT_INFOMANIAK_TTL=300
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: dns_infomaniak_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_infomaniak_add() {
|
||||
|
||||
INFOMANIAK_API_TOKEN="${INFOMANIAK_API_TOKEN:-$(_readaccountconf_mutable INFOMANIAK_API_TOKEN)}"
|
||||
INFOMANIAK_API_URL="${INFOMANIAK_API_URL:-$(_readaccountconf_mutable INFOMANIAK_API_URL)}"
|
||||
INFOMANIAK_TTL="${INFOMANIAK_TTL:-$(_readaccountconf_mutable INFOMANIAK_TTL)}"
|
||||
|
||||
if [ -z "$INFOMANIAK_API_TOKEN" ]; then
|
||||
INFOMANIAK_API_TOKEN=""
|
||||
_err "Please provide a valid Infomaniak API token in variable INFOMANIAK_API_TOKEN"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$INFOMANIAK_API_URL" ]; then
|
||||
INFOMANIAK_API_URL="$DEFAULT_INFOMANIAK_API_URL"
|
||||
fi
|
||||
|
||||
if [ -z "$INFOMANIAK_TTL" ]; then
|
||||
INFOMANIAK_TTL="$DEFAULT_INFOMANIAK_TTL"
|
||||
fi
|
||||
|
||||
#save the token to the account conf file.
|
||||
_saveaccountconf_mutable INFOMANIAK_API_TOKEN "$INFOMANIAK_API_TOKEN"
|
||||
|
||||
if [ "$INFOMANIAK_API_URL" != "$DEFAULT_INFOMANIAK_API_URL" ]; then
|
||||
_saveaccountconf_mutable INFOMANIAK_API_URL "$INFOMANIAK_API_URL"
|
||||
fi
|
||||
|
||||
if [ "$INFOMANIAK_TTL" != "$DEFAULT_INFOMANIAK_TTL" ]; then
|
||||
_saveaccountconf_mutable INFOMANIAK_TTL "$INFOMANIAK_TTL"
|
||||
fi
|
||||
|
||||
export _H1="Authorization: Bearer $INFOMANIAK_API_TOKEN"
|
||||
export _H2="Content-Type: application/json"
|
||||
|
||||
fulldomain="$1"
|
||||
txtvalue="$2"
|
||||
|
||||
_info "Infomaniak DNS API"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
fqdn=${fulldomain#_acme-challenge.}
|
||||
|
||||
# guess which base domain to add record to
|
||||
zone_and_id=$(_find_zone "$fqdn")
|
||||
if [ -z "$zone_and_id" ]; then
|
||||
_err "cannot find zone to modify"
|
||||
return 1
|
||||
fi
|
||||
zone=${zone_and_id% *}
|
||||
domain_id=${zone_and_id#* }
|
||||
|
||||
# extract first part of domain
|
||||
key=${fulldomain%.$zone}
|
||||
|
||||
_debug "zone:$zone id:$domain_id key:$key"
|
||||
|
||||
# payload
|
||||
data="{\"type\": \"TXT\", \"source\": \"$key\", \"target\": \"$txtvalue\", \"ttl\": $INFOMANIAK_TTL}"
|
||||
|
||||
# API call
|
||||
response=$(_post "$data" "${INFOMANIAK_API_URL}/1/domain/$domain_id/dns/record")
|
||||
if [ -n "$response" ] && echo "$response" | _contains '"result":"success"'; then
|
||||
_info "Record added"
|
||||
_debug "Response: $response"
|
||||
return 0
|
||||
fi
|
||||
_err "could not create record"
|
||||
_debug "Response: $response"
|
||||
return 1
|
||||
}
|
||||
|
||||
#Usage: fulldomain txtvalue
|
||||
#Remove the txt record after validation.
|
||||
dns_infomaniak_rm() {
|
||||
|
||||
INFOMANIAK_API_TOKEN="${INFOMANIAK_API_TOKEN:-$(_readaccountconf_mutable INFOMANIAK_API_TOKEN)}"
|
||||
INFOMANIAK_API_URL="${INFOMANIAK_API_URL:-$(_readaccountconf_mutable INFOMANIAK_API_URL)}"
|
||||
INFOMANIAK_TTL="${INFOMANIAK_TTL:-$(_readaccountconf_mutable INFOMANIAK_TTL)}"
|
||||
|
||||
if [ -z "$INFOMANIAK_API_TOKEN" ]; then
|
||||
INFOMANIAK_API_TOKEN=""
|
||||
_err "Please provide a valid Infomaniak API token in variable INFOMANIAK_API_TOKEN"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$INFOMANIAK_API_URL" ]; then
|
||||
INFOMANIAK_API_URL="$DEFAULT_INFOMANIAK_API_URL"
|
||||
fi
|
||||
|
||||
if [ -z "$INFOMANIAK_TTL" ]; then
|
||||
INFOMANIAK_TTL="$DEFAULT_INFOMANIAK_TTL"
|
||||
fi
|
||||
|
||||
#save the token to the account conf file.
|
||||
_saveaccountconf_mutable INFOMANIAK_API_TOKEN "$INFOMANIAK_API_TOKEN"
|
||||
|
||||
if [ "$INFOMANIAK_API_URL" != "$DEFAULT_INFOMANIAK_API_URL" ]; then
|
||||
_saveaccountconf_mutable INFOMANIAK_API_URL "$INFOMANIAK_API_URL"
|
||||
fi
|
||||
|
||||
if [ "$INFOMANIAK_TTL" != "$DEFAULT_INFOMANIAK_TTL" ]; then
|
||||
_saveaccountconf_mutable INFOMANIAK_TTL "$INFOMANIAK_TTL"
|
||||
fi
|
||||
|
||||
export _H1="Authorization: Bearer $INFOMANIAK_API_TOKEN"
|
||||
export _H2="ContentType: application/json"
|
||||
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_info "Infomaniak DNS API"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
fqdn=${fulldomain#_acme-challenge.}
|
||||
|
||||
# guess which base domain to add record to
|
||||
zone_and_id=$(_find_zone "$fqdn")
|
||||
if [ -z "$zone_and_id" ]; then
|
||||
_err "cannot find zone to modify"
|
||||
return 1
|
||||
fi
|
||||
zone=${zone_and_id% *}
|
||||
domain_id=${zone_and_id#* }
|
||||
|
||||
# extract first part of domain
|
||||
key=${fulldomain%.$zone}
|
||||
|
||||
_debug "zone:$zone id:$domain_id key:$key"
|
||||
|
||||
# find previous record
|
||||
# shellcheck disable=SC1004
|
||||
record_id=$(_get "${INFOMANIAK_API_URL}/1/domain/$domain_id/dns/record" | sed 's/.*"data":\[\(.*\)\]}/\1/; s/},{/}\
|
||||
{/g' | sed -n 's/.*"id":"*\([0-9]*\)"*.*"source_idn":"'"$fulldomain"'".*"target_idn":"'"$txtvalue"'".*/\1/p')
|
||||
if [ -z "$record_id" ]; then
|
||||
_err "could not find record to delete"
|
||||
return 1
|
||||
fi
|
||||
_debug "record_id: $record_id"
|
||||
|
||||
# API call
|
||||
response=$(_post "" "${INFOMANIAK_API_URL}/1/domain/$domain_id/dns/record/$record_id" "" DELETE)
|
||||
if [ -n "$response" ] && echo "$response" | _contains '"result":"success"'; then
|
||||
_info "Record deleted"
|
||||
return 0
|
||||
fi
|
||||
_err "could not delete record"
|
||||
return 1
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
_get_domain_id() {
|
||||
domain="$1"
|
||||
|
||||
# shellcheck disable=SC1004
|
||||
_get "${INFOMANIAK_API_URL}/1/product?service_name=domain&customer_name=$domain" | sed 's/.*"data":\[{\(.*\)}\]}/\1/; s/,/\
|
||||
/g' | sed -n 's/^"id":\(.*\)/\1/p'
|
||||
}
|
||||
|
||||
_find_zone() {
|
||||
zone="$1"
|
||||
|
||||
# find domain in list, removing . parts sequentialy
|
||||
while _contains "$zone" '\.'; do
|
||||
_debug "testing $zone"
|
||||
id=$(_get_domain_id "$zone")
|
||||
if [ -n "$id" ]; then
|
||||
echo "$zone $id"
|
||||
return
|
||||
fi
|
||||
zone=${zone#*.}
|
||||
done
|
||||
}
|
||||
@@ -261,6 +261,20 @@ _get_root() {
|
||||
xml_content='<?xml version="1.0" encoding="UTF-8"?>
|
||||
<methodCall>
|
||||
<methodName>nameserver.list</methodName>
|
||||
<params>
|
||||
<param>
|
||||
<value>
|
||||
<struct>
|
||||
<member>
|
||||
<name>pagelimit</name>
|
||||
<value>
|
||||
<int>9999</int>
|
||||
</value>
|
||||
</member>
|
||||
</struct>
|
||||
</value>
|
||||
</param>
|
||||
</params>
|
||||
</methodCall>'
|
||||
|
||||
response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
|
||||
|
||||
163
dnsapi/dns_ionos.sh
Executable file
163
dnsapi/dns_ionos.sh
Executable file
@@ -0,0 +1,163 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Supports IONOS DNS API Beta v1.0.0
|
||||
#
|
||||
# Usage:
|
||||
# Export IONOS_PREFIX and IONOS_SECRET before calling acme.sh:
|
||||
#
|
||||
# $ export IONOS_PREFIX="..."
|
||||
# $ export IONOS_SECRET="..."
|
||||
#
|
||||
# $ acme.sh --issue --dns dns_ionos ...
|
||||
|
||||
IONOS_API="https://api.hosting.ionos.com/dns"
|
||||
IONOS_ROUTE_ZONES="/v1/zones"
|
||||
|
||||
IONOS_TXT_TTL=60 # minimum accepted by API
|
||||
IONOS_TXT_PRIO=10
|
||||
|
||||
dns_ionos_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
if ! _ionos_init; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
_body="[{\"name\":\"$_sub_domain.$_domain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"ttl\":$IONOS_TXT_TTL,\"prio\":$IONOS_TXT_PRIO,\"disabled\":false}]"
|
||||
|
||||
if _ionos_rest POST "$IONOS_ROUTE_ZONES/$_zone_id/records" "$_body" && [ -z "$response" ]; then
|
||||
_info "TXT record has been created successfully."
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
dns_ionos_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
if ! _ionos_init; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _ionos_get_record "$fulldomain" "$_zone_id" "$txtvalue"; then
|
||||
_err "Could not find _acme-challenge TXT record."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _ionos_rest DELETE "$IONOS_ROUTE_ZONES/$_zone_id/records/$_record_id" && [ -z "$response" ]; then
|
||||
_info "TXT record has been deleted successfully."
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
_ionos_init() {
|
||||
IONOS_PREFIX="${IONOS_PREFIX:-$(_readaccountconf_mutable IONOS_PREFIX)}"
|
||||
IONOS_SECRET="${IONOS_SECRET:-$(_readaccountconf_mutable IONOS_SECRET)}"
|
||||
|
||||
if [ -z "$IONOS_PREFIX" ] || [ -z "$IONOS_SECRET" ]; then
|
||||
_err "You didn't specify an IONOS api prefix and secret yet."
|
||||
_err "Read https://beta.developer.hosting.ionos.de/docs/getstarted to learn how to get a prefix and secret."
|
||||
_err ""
|
||||
_err "Then set them before calling acme.sh:"
|
||||
_err "\$ export IONOS_PREFIX=\"...\""
|
||||
_err "\$ export IONOS_SECRET=\"...\""
|
||||
_err "\$ acme.sh --issue -d ... --dns dns_ionos"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf_mutable IONOS_PREFIX "$IONOS_PREFIX"
|
||||
_saveaccountconf_mutable IONOS_SECRET "$IONOS_SECRET"
|
||||
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "Cannot find this domain in your IONOS account."
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=1
|
||||
p=1
|
||||
|
||||
if _ionos_rest GET "$IONOS_ROUTE_ZONES"; then
|
||||
response="$(echo "$response" | tr -d "\n")"
|
||||
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
if [ -z "$h" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
_zone="$(echo "$response" | _egrep_o "\"name\":\"$h\".*\}")"
|
||||
if [ "$_zone" ]; then
|
||||
_zone_id=$(printf "%s\n" "$_zone" | _egrep_o "\"id\":\"[a-fA-F0-9\-]*\"" | _head_n 1 | cut -d : -f 2 | tr -d '\"')
|
||||
if [ "$_zone_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain=$h
|
||||
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
fi
|
||||
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
_ionos_get_record() {
|
||||
fulldomain=$1
|
||||
zone_id=$2
|
||||
txtrecord=$3
|
||||
|
||||
if _ionos_rest GET "$IONOS_ROUTE_ZONES/$zone_id?recordName=$fulldomain&recordType=TXT"; then
|
||||
response="$(echo "$response" | tr -d "\n")"
|
||||
|
||||
_record="$(echo "$response" | _egrep_o "\"name\":\"$fulldomain\"[^\}]*\"type\":\"TXT\"[^\}]*\"content\":\"\\\\\"$txtrecord\\\\\"\".*\}")"
|
||||
if [ "$_record" ]; then
|
||||
_record_id=$(printf "%s\n" "$_record" | _egrep_o "\"id\":\"[a-fA-F0-9\-]*\"" | _head_n 1 | cut -d : -f 2 | tr -d '\"')
|
||||
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
_ionos_rest() {
|
||||
method="$1"
|
||||
route="$2"
|
||||
data="$3"
|
||||
|
||||
IONOS_API_KEY="$(printf "%s.%s" "$IONOS_PREFIX" "$IONOS_SECRET")"
|
||||
|
||||
export _H1="X-API-Key: $IONOS_API_KEY"
|
||||
|
||||
if [ "$method" != "GET" ]; then
|
||||
export _H2="Accept: application/json"
|
||||
export _H3="Content-Type: application/json"
|
||||
|
||||
response="$(_post "$data" "$IONOS_API$route" "" "$method" "application/json")"
|
||||
else
|
||||
export _H2="Accept: */*"
|
||||
export _H3=
|
||||
response="$(_get "$IONOS_API$route")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "Error $route: $response"
|
||||
return 1
|
||||
fi
|
||||
_debug2 "response" "$response"
|
||||
|
||||
return 0
|
||||
}
|
||||
@@ -75,7 +75,7 @@ _ISPC_getZoneInfo() {
|
||||
# suffix . needed for zone -> domain.tld.
|
||||
curData="{\"session_id\":\"${sessionID}\",\"primary_id\":{\"origin\":\"${curZone}.\"}}"
|
||||
curResult="$(_post "${curData}" "${ISPC_Api}?dns_zone_get")"
|
||||
_debug "Calling _ISPC_getZoneInfo: '${curData}' '${ISPC_Api}?login'"
|
||||
_debug "Calling _ISPC_getZoneInfo: '${curData}' '${ISPC_Api}?dns_zone_get'"
|
||||
_debug "Result of _ISPC_getZoneInfo: '$curResult'"
|
||||
if _contains "${curResult}" '"id":"'; then
|
||||
zoneFound=true
|
||||
@@ -95,33 +95,47 @@ _ISPC_getZoneInfo() {
|
||||
server_id=$(echo "${curResult}" | _egrep_o "server_id.*" | cut -d ':' -f 2 | cut -d '"' -f 2)
|
||||
_debug "Server ID: '${server_id}'"
|
||||
case "${server_id}" in
|
||||
'' | *[!0-9]*)
|
||||
_err "Server ID is not numeric."
|
||||
return 1
|
||||
;;
|
||||
*) _info "Retrieved Server ID" ;;
|
||||
'' | *[!0-9]*)
|
||||
_err "Server ID is not numeric."
|
||||
return 1
|
||||
;;
|
||||
*) _info "Retrieved Server ID" ;;
|
||||
esac
|
||||
zone=$(echo "${curResult}" | _egrep_o "\"id.*" | cut -d ':' -f 2 | cut -d '"' -f 2)
|
||||
_debug "Zone: '${zone}'"
|
||||
case "${zone}" in
|
||||
'' | *[!0-9]*)
|
||||
_err "Zone ID is not numeric."
|
||||
return 1
|
||||
;;
|
||||
*) _info "Retrieved Zone ID" ;;
|
||||
'' | *[!0-9]*)
|
||||
_err "Zone ID is not numeric."
|
||||
return 1
|
||||
;;
|
||||
*) _info "Retrieved Zone ID" ;;
|
||||
esac
|
||||
client_id=$(echo "${curResult}" | _egrep_o "sys_userid.*" | cut -d ':' -f 2 | cut -d '"' -f 2)
|
||||
_debug "Client ID: '${client_id}'"
|
||||
case "${client_id}" in
|
||||
'' | *[!0-9]*)
|
||||
_err "Client ID is not numeric."
|
||||
return 1
|
||||
;;
|
||||
*) _info "Retrieved Client ID." ;;
|
||||
sys_userid=$(echo "${curResult}" | _egrep_o "sys_userid.*" | cut -d ':' -f 2 | cut -d '"' -f 2)
|
||||
_debug "SYS User ID: '${sys_userid}'"
|
||||
case "${sys_userid}" in
|
||||
'' | *[!0-9]*)
|
||||
_err "SYS User ID is not numeric."
|
||||
return 1
|
||||
;;
|
||||
*) _info "Retrieved SYS User ID." ;;
|
||||
esac
|
||||
zoneFound=""
|
||||
zoneEnd=""
|
||||
fi
|
||||
# Need to get client_id as it is different from sys_userid
|
||||
curData="{\"session_id\":\"${sessionID}\",\"sys_userid\":\"${sys_userid}\"}"
|
||||
curResult="$(_post "${curData}" "${ISPC_Api}?client_get_id")"
|
||||
_debug "Calling _ISPC_ClientGetID: '${curData}' '${ISPC_Api}?client_get_id'"
|
||||
_debug "Result of _ISPC_ClientGetID: '$curResult'"
|
||||
client_id=$(echo "${curResult}" | _egrep_o "response.*" | cut -d ':' -f 2 | cut -d '"' -f 2 | tr -d '{}')
|
||||
_debug "Client ID: '${client_id}'"
|
||||
case "${client_id}" in
|
||||
'' | *[!0-9]*)
|
||||
_err "Client ID is not numeric."
|
||||
return 1
|
||||
;;
|
||||
*) _info "Retrieved Client ID." ;;
|
||||
esac
|
||||
}
|
||||
|
||||
_ISPC_addTxt() {
|
||||
@@ -135,11 +149,11 @@ _ISPC_addTxt() {
|
||||
record_id=$(echo "${curResult}" | _egrep_o "\"response.*" | cut -d ':' -f 2 | cut -d '"' -f 2)
|
||||
_debug "Record ID: '${record_id}'"
|
||||
case "${record_id}" in
|
||||
'' | *[!0-9]*)
|
||||
_err "Couldn't add ACME Challenge TXT record to zone."
|
||||
return 1
|
||||
;;
|
||||
*) _info "Added ACME Challenge TXT record to zone." ;;
|
||||
'' | *[!0-9]*)
|
||||
_err "Couldn't add ACME Challenge TXT record to zone."
|
||||
return 1
|
||||
;;
|
||||
*) _info "Added ACME Challenge TXT record to zone." ;;
|
||||
esac
|
||||
}
|
||||
|
||||
@@ -153,24 +167,24 @@ _ISPC_rmTxt() {
|
||||
record_id=$(echo "${curResult}" | _egrep_o "\"id.*" | cut -d ':' -f 2 | cut -d '"' -f 2)
|
||||
_debug "Record ID: '${record_id}'"
|
||||
case "${record_id}" in
|
||||
'' | *[!0-9]*)
|
||||
_err "Record ID is not numeric."
|
||||
'' | *[!0-9]*)
|
||||
_err "Record ID is not numeric."
|
||||
return 1
|
||||
;;
|
||||
*)
|
||||
unset IFS
|
||||
_info "Retrieved Record ID."
|
||||
curData="{\"session_id\":\"${sessionID}\",\"primary_id\":\"${record_id}\",\"update_serial\":true}"
|
||||
curResult="$(_post "${curData}" "${ISPC_Api}?dns_txt_delete")"
|
||||
_debug "Calling _ISPC_rmTxt: '${curData}' '${ISPC_Api}?dns_txt_delete'"
|
||||
_debug "Result of _ISPC_rmTxt: '$curResult'"
|
||||
if _contains "${curResult}" '"code":"ok"'; then
|
||||
_info "Removed ACME Challenge TXT record from zone."
|
||||
else
|
||||
_err "Couldn't remove ACME Challenge TXT record from zone."
|
||||
return 1
|
||||
;;
|
||||
*)
|
||||
unset IFS
|
||||
_info "Retrieved Record ID."
|
||||
curData="{\"session_id\":\"${sessionID}\",\"primary_id\":\"${record_id}\",\"update_serial\":true}"
|
||||
curResult="$(_post "${curData}" "${ISPC_Api}?dns_txt_delete")"
|
||||
_debug "Calling _ISPC_rmTxt: '${curData}' '${ISPC_Api}?dns_txt_delete'"
|
||||
_debug "Result of _ISPC_rmTxt: '$curResult'"
|
||||
if _contains "${curResult}" '"code":"ok"'; then
|
||||
_info "Removed ACME Challenge TXT record from zone."
|
||||
else
|
||||
_err "Couldn't remove ACME Challenge TXT record from zone."
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ _get_root() {
|
||||
fi
|
||||
|
||||
# Try to remove a test record. With correct root domain, username and password this will return "OK: ..." regardless
|
||||
# of record in question existing or not.
|
||||
# of record in question existing or not.
|
||||
if _joker_rest "username=$JOKER_USERNAME&password=$JOKER_PASSWORD&zone=$h&label=jokerTXTUpdateTest&type=TXT&value="; then
|
||||
if _startswith "$response" "OK"; then
|
||||
_sub_domain="$(echo "$fulldomain" | sed "s/\\.$h\$//")"
|
||||
|
||||
150
dnsapi/dns_kappernet.sh
Normal file
150
dnsapi/dns_kappernet.sh
Normal file
@@ -0,0 +1,150 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# kapper.net domain api
|
||||
# for further questions please contact: support@kapper.net
|
||||
# please report issues here: https://github.com/acmesh-official/acme.sh/issues/2977
|
||||
|
||||
#KAPPERNETDNS_Key="yourKAPPERNETapikey"
|
||||
#KAPPERNETDNS_Secret="yourKAPPERNETapisecret"
|
||||
|
||||
KAPPERNETDNS_Api="https://dnspanel.kapper.net/API/1.2?APIKey=$KAPPERNETDNS_Key&APISecret=$KAPPERNETDNS_Secret"
|
||||
|
||||
###############################################################################
|
||||
# called with
|
||||
# fullhostname: something.example.com
|
||||
# txtvalue: someacmegenerated string
|
||||
dns_kappernet_add() {
|
||||
fullhostname=$1
|
||||
txtvalue=$2
|
||||
|
||||
KAPPERNETDNS_Key="${KAPPERNETDNS_Key:-$(_readaccountconf_mutable KAPPERNETDNS_Key)}"
|
||||
KAPPERNETDNS_Secret="${KAPPERNETDNS_Secret:-$(_readaccountconf_mutable KAPPERNETDNS_Secret)}"
|
||||
|
||||
if [ -z "$KAPPERNETDNS_Key" ] || [ -z "$KAPPERNETDNS_Secret" ]; then
|
||||
KAPPERNETDNS_Key=""
|
||||
KAPPERNETDNS_Secret=""
|
||||
_err "Please specify your kapper.net api key and secret."
|
||||
_err "If you have not received yours - send your mail to"
|
||||
_err "support@kapper.net to get your key and secret."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#store the api key and email to the account conf file.
|
||||
_saveaccountconf_mutable KAPPERNETDNS_Key "$KAPPERNETDNS_Key"
|
||||
_saveaccountconf_mutable KAPPERNETDNS_Secret "$KAPPERNETDNS_Secret"
|
||||
_debug "Checking Domain ..."
|
||||
if ! _get_root "$fullhostname"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _sub_domain "SUBDOMAIN: $_sub_domain"
|
||||
_debug _domain "DOMAIN: $_domain"
|
||||
|
||||
_info "Trying to add TXT DNS Record"
|
||||
data="%7B%22name%22%3A%22$fullhostname%22%2C%22type%22%3A%22TXT%22%2C%22content%22%3A%22$txtvalue%22%2C%22ttl%22%3A%223600%22%2C%22prio%22%3A%22%22%7D"
|
||||
if _kappernet_api GET "action=new&subject=$_domain&data=$data"; then
|
||||
|
||||
if _contains "$response" "{\"OK\":true"; then
|
||||
_info "Waiting 120 seconds for DNS to spread the new record"
|
||||
_sleep 120
|
||||
return 0
|
||||
else
|
||||
_err "Error creating a TXT DNS Record: $fullhostname TXT $txtvalue"
|
||||
_err "Error Message: $response"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
_err "Failed creating TXT Record"
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# called with
|
||||
# fullhostname: something.example.com
|
||||
dns_kappernet_rm() {
|
||||
fullhostname=$1
|
||||
txtvalue=$2
|
||||
|
||||
KAPPERNETDNS_Key="${KAPPERNETDNS_Key:-$(_readaccountconf_mutable KAPPERNETDNS_Key)}"
|
||||
KAPPERNETDNS_Secret="${KAPPERNETDNS_Secret:-$(_readaccountconf_mutable KAPPERNETDNS_Secret)}"
|
||||
|
||||
if [ -z "$KAPPERNETDNS_Key" ] || [ -z "$KAPPERNETDNS_Secret" ]; then
|
||||
KAPPERNETDNS_Key=""
|
||||
KAPPERNETDNS_Secret=""
|
||||
_err "Please specify your kapper.net api key and secret."
|
||||
_err "If you have not received yours - send your mail to"
|
||||
_err "support@kapper.net to get your key and secret."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#store the api key and email to the account conf file.
|
||||
_saveaccountconf_mutable KAPPERNETDNS_Key "$KAPPERNETDNS_Key"
|
||||
_saveaccountconf_mutable KAPPERNETDNS_Secret "$KAPPERNETDNS_Secret"
|
||||
|
||||
_info "Trying to remove the TXT Record: $fullhostname containing $txtvalue"
|
||||
data="%7B%22name%22%3A%22$fullhostname%22%2C%22type%22%3A%22TXT%22%2C%22content%22%3A%22$txtvalue%22%2C%22ttl%22%3A%223600%22%2C%22prio%22%3A%22%22%7D"
|
||||
if _kappernet_api GET "action=del&subject=$fullhostname&data=$data"; then
|
||||
if _contains "$response" "{\"OK\":true"; then
|
||||
return 0
|
||||
else
|
||||
_err "Error deleting DNS Record: $fullhostname containing $txtvalue"
|
||||
_err "Problem: $response"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
_err "Problem deleting TXT DNS record"
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
# called with hostname
|
||||
# e.g._acme-challenge.www.domain.com returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=2
|
||||
p=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
if ! _kappernet_api GET "action=list&subject=$h"; then
|
||||
return 1
|
||||
fi
|
||||
if _contains "$response" '"OK":false'; then
|
||||
_debug "$h not found"
|
||||
else
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain="$h"
|
||||
return 0
|
||||
fi
|
||||
p="$i"
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# calls the kapper.net DNS Panel API
|
||||
# with
|
||||
# method
|
||||
# param
|
||||
_kappernet_api() {
|
||||
method=$1
|
||||
param="$2"
|
||||
|
||||
_debug param "PARAMETER=$param"
|
||||
url="$KAPPERNETDNS_Api&$param"
|
||||
_debug url "URL=$url"
|
||||
|
||||
if [ "$method" = "GET" ]; then
|
||||
response="$(_get "$url")"
|
||||
else
|
||||
_err "Unsupported method"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
@@ -37,7 +37,7 @@ dns_kinghost_add() {
|
||||
_debug "Getting txt records"
|
||||
_kinghost_rest GET "dns" "name=$fulldomain&content=$txtvalue"
|
||||
|
||||
#This API call returns "status":"ok" if dns record does not exists
|
||||
#This API call returns "status":"ok" if dns record does not exist
|
||||
#We are creating a new txt record here, so we expect the "ok" status
|
||||
if ! echo "$response" | grep '"status":"ok"' >/dev/null; then
|
||||
_err "Error"
|
||||
|
||||
@@ -92,7 +92,7 @@ dns_lexicon_add() {
|
||||
_savedomainconf LEXICON_OPTS "$LEXICON_OPTS"
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
$lexicon_cmd "$PROVIDER" $LEXICON_OPTS create "${domain}" TXT --name="_acme-challenge.${domain}." --content="${txtvalue}"
|
||||
$lexicon_cmd "$PROVIDER" $LEXICON_OPTS create "${domain}" TXT --name="_acme-challenge.${domain}." --content="${txtvalue}" --output QUIET
|
||||
|
||||
}
|
||||
|
||||
@@ -108,6 +108,6 @@ dns_lexicon_rm() {
|
||||
domain=$(printf "%s" "$fulldomain" | cut -d . -f 2-999)
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
$lexicon_cmd "$PROVIDER" $LEXICON_OPTS delete "${domain}" TXT --name="_acme-challenge.${domain}." --content="${txtvalue}"
|
||||
$lexicon_cmd "$PROVIDER" $LEXICON_OPTS delete "${domain}" TXT --name="_acme-challenge.${domain}." --content="${txtvalue}" --output QUIET
|
||||
|
||||
}
|
||||
|
||||
@@ -106,6 +106,7 @@ dns_linode_v4_rm() {
|
||||
#################### Private functions below ##################################
|
||||
|
||||
_Linode_API() {
|
||||
LINODE_V4_API_KEY="${LINODE_V4_API_KEY:-$(_readaccountconf_mutable LINODE_V4_API_KEY)}"
|
||||
if [ -z "$LINODE_V4_API_KEY" ]; then
|
||||
LINODE_V4_API_KEY=""
|
||||
|
||||
@@ -115,7 +116,7 @@ _Linode_API() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf LINODE_V4_API_KEY "$LINODE_V4_API_KEY"
|
||||
_saveaccountconf_mutable LINODE_V4_API_KEY "$LINODE_V4_API_KEY"
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
@@ -47,7 +47,7 @@ dns_misaka_add() {
|
||||
if [ "$count" = "0" ]; then
|
||||
_info "Adding record"
|
||||
|
||||
if _misaka_rest PUT "zones/${_domain}/recordsets/${_sub_domain}/TXT" "{\"records\":[{\"value\":\"\\\"$txtvalue\\\"\"}],\"filters\":[],\"ttl\":1}"; then
|
||||
if _misaka_rest POST "zones/${_domain}/recordsets/${_sub_domain}/TXT" "{\"records\":[{\"value\":\"\\\"$txtvalue\\\"\"}],\"filters\":[],\"ttl\":1}"; then
|
||||
_debug response "$response"
|
||||
if _contains "$response" "$_sub_domain"; then
|
||||
_info "Added"
|
||||
@@ -61,7 +61,7 @@ dns_misaka_add() {
|
||||
else
|
||||
_info "Updating record"
|
||||
|
||||
_misaka_rest POST "zones/${_domain}/recordsets/${_sub_domain}/TXT?append=true" "{\"records\": [{\"value\": \"\\\"$txtvalue\\\"\"}],\"ttl\":1}"
|
||||
_misaka_rest PUT "zones/${_domain}/recordsets/${_sub_domain}/TXT?append=true" "{\"records\": [{\"value\": \"\\\"$txtvalue\\\"\"}],\"ttl\":1}"
|
||||
if [ "$?" = "0" ] && _contains "$response" "$_sub_domain"; then
|
||||
_info "Updated!"
|
||||
#todo: check if the record takes effect
|
||||
|
||||
@@ -157,7 +157,7 @@ _namecheap_set_publicip() {
|
||||
|
||||
if [ -z "$NAMECHEAP_SOURCEIP" ]; then
|
||||
_err "No Source IP specified for Namecheap API."
|
||||
_err "Use your public ip address or an url to retrieve it (e.g. https://ipconfig.co/ip) and export it as NAMECHEAP_SOURCEIP"
|
||||
_err "Use your public ip address or an url to retrieve it (e.g. https://ifconfig.co/ip) and export it as NAMECHEAP_SOURCEIP"
|
||||
return 1
|
||||
else
|
||||
_saveaccountconf NAMECHEAP_SOURCEIP "$NAMECHEAP_SOURCEIP"
|
||||
@@ -175,7 +175,7 @@ _namecheap_set_publicip() {
|
||||
_publicip=$(_get "$addr")
|
||||
else
|
||||
_err "No Source IP specified for Namecheap API."
|
||||
_err "Use your public ip address or an url to retrieve it (e.g. https://ipconfig.co/ip) and export it as NAMECHEAP_SOURCEIP"
|
||||
_err "Use your public ip address or an url to retrieve it (e.g. https://ifconfig.co/ip) and export it as NAMECHEAP_SOURCEIP"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
@@ -208,7 +208,7 @@ _namecheap_parse_host() {
|
||||
_hostid=$(echo "$_host" | _egrep_o ' HostId="[^"]*' | cut -d '"' -f 2)
|
||||
_hostname=$(echo "$_host" | _egrep_o ' Name="[^"]*' | cut -d '"' -f 2)
|
||||
_hosttype=$(echo "$_host" | _egrep_o ' Type="[^"]*' | cut -d '"' -f 2)
|
||||
_hostaddress=$(echo "$_host" | _egrep_o ' Address="[^"]*' | cut -d '"' -f 2)
|
||||
_hostaddress=$(echo "$_host" | _egrep_o ' Address="[^"]*' | cut -d '"' -f 2 | _xml_decode)
|
||||
_hostmxpref=$(echo "$_host" | _egrep_o ' MXPref="[^"]*' | cut -d '"' -f 2)
|
||||
_hostttl=$(echo "$_host" | _egrep_o ' TTL="[^"]*' | cut -d '"' -f 2)
|
||||
|
||||
@@ -405,3 +405,7 @@ _namecheap_set_tld_sld() {
|
||||
done
|
||||
|
||||
}
|
||||
|
||||
_xml_decode() {
|
||||
sed 's/"/"/g'
|
||||
}
|
||||
|
||||
@@ -119,16 +119,16 @@ login() {
|
||||
tmp=$(_post "{\"action\": \"login\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apipassword\": \"$NC_Apipw\", \"customernumber\": \"$NC_CID\"}}" "$end" "" "POST")
|
||||
sid=$(echo "$tmp" | tr '{}' '\n' | grep apisessionid | cut -d '"' -f 4)
|
||||
_debug "$tmp"
|
||||
if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then
|
||||
_err "$msg"
|
||||
if [ "$(_getfield "$tmp" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then
|
||||
_err "$tmp"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
logout() {
|
||||
tmp=$(_post "{\"action\": \"logout\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\"}}" "$end" "" "POST")
|
||||
_debug "$tmp"
|
||||
if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then
|
||||
_err "$msg"
|
||||
if [ "$(_getfield "$tmp" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then
|
||||
_err "$tmp"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
162
dnsapi/dns_netlify.sh
Normal file
162
dnsapi/dns_netlify.sh
Normal file
@@ -0,0 +1,162 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#NETLIFY_ACCESS_TOKEN="xxxx"
|
||||
|
||||
NETLIFY_HOST="api.netlify.com/api/v1/"
|
||||
NETLIFY_URL="https://$NETLIFY_HOST"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_netlify_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
NETLIFY_ACCESS_TOKEN="${NETLIFY_ACCESS_TOKEN:-$(_readaccountconf_mutable NETLIFY_ACCESS_TOKEN)}"
|
||||
|
||||
if [ -z "$NETLIFY_ACCESS_TOKEN" ]; then
|
||||
NETLIFY_ACCESS_TOKEN=""
|
||||
_err "Please specify your Netlify Access Token and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Using Netlify"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
_saveaccountconf_mutable NETLIFY_ACCESS_TOKEN "$NETLIFY_ACCESS_TOKEN"
|
||||
|
||||
if ! _get_root "$fulldomain" "$accesstoken"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
dnsRecordURI="dns_zones/$_domain_id/dns_records"
|
||||
|
||||
body="{\"type\":\"TXT\", \"hostname\":\"$_sub_domain\", \"value\":\"$txtvalue\", \"ttl\":\"10\"}"
|
||||
|
||||
_netlify_rest POST "$dnsRecordURI" "$body" "$NETLIFY_ACCESS_TOKEN"
|
||||
_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")"
|
||||
if [ "$_code" = "200" ] || [ "$_code" = '201' ]; then
|
||||
_info "validation value added"
|
||||
return 0
|
||||
else
|
||||
_err "error adding validation value ($_code)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_err "Not fully implemented!"
|
||||
return 1
|
||||
}
|
||||
|
||||
#Usage: dns_myapi_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
#Remove the txt record after validation.
|
||||
dns_netlify_rm() {
|
||||
_info "Using Netlify"
|
||||
txtdomain="$1"
|
||||
txt="$2"
|
||||
_debug txtdomain "$txtdomain"
|
||||
_debug txt "$txt"
|
||||
|
||||
_saveaccountconf_mutable NETLIFY_ACCESS_TOKEN "$NETLIFY_ACCESS_TOKEN"
|
||||
|
||||
if ! _get_root "$txtdomain" "$accesstoken"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
dnsRecordURI="dns_zones/$_domain_id/dns_records"
|
||||
|
||||
_netlify_rest GET "$dnsRecordURI" "" "$NETLIFY_ACCESS_TOKEN"
|
||||
|
||||
_record_id=$(echo "$response" | _egrep_o "\"type\":\"TXT\",[^\}]*\"value\":\"$txt\"" | head -n 1 | _egrep_o "\"id\":\"[^\"\}]*\"" | cut -d : -f 2 | tr -d \")
|
||||
_debug _record_id "$_record_id"
|
||||
if [ "$_record_id" ]; then
|
||||
_netlify_rest DELETE "$dnsRecordURI/$_record_id" "" "$NETLIFY_ACCESS_TOKEN"
|
||||
_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")"
|
||||
if [ "$_code" = "200" ] || [ "$_code" = '204' ]; then
|
||||
_info "validation value removed"
|
||||
return 0
|
||||
else
|
||||
_err "error removing validation value ($_code)"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
_get_root() {
|
||||
domain=$1
|
||||
accesstoken=$2
|
||||
i=1
|
||||
p=1
|
||||
|
||||
_netlify_rest GET "dns_zones" "" "$accesstoken"
|
||||
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug2 "Checking domain: $h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
_err "Invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
|
||||
_domain_id=$(echo "$response" | _egrep_o "\"[^\"]*\",\"name\":\"$h" | cut -d , -f 1 | tr -d \")
|
||||
if [ "$_domain_id" ]; then
|
||||
if [ "$i" = 1 ]; then
|
||||
#create the record at the domain apex (@) if only the domain name was provided as --domain-alias
|
||||
_sub_domain="@"
|
||||
else
|
||||
_sub_domain=$(echo "$domain" | cut -d . -f 1-$p)
|
||||
fi
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
_netlify_rest() {
|
||||
m=$1
|
||||
ep="$2"
|
||||
data="$3"
|
||||
_debug "$ep"
|
||||
|
||||
token_trimmed=$(echo "$NETLIFY_ACCESS_TOKEN" | tr -d '"')
|
||||
|
||||
export _H1="Content-Type: application/json"
|
||||
export _H2="Authorization: Bearer $token_trimmed"
|
||||
|
||||
: >"$HTTP_HEADER"
|
||||
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$NETLIFY_URL$ep" "" "$m")"
|
||||
else
|
||||
response="$(_get "$NETLIFY_URL$ep")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
@@ -166,7 +166,7 @@ _get_root() {
|
||||
if _contains "$_all_domains" "^$h$"; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain=$h
|
||||
_service=$(printf "%s" "$response" | grep "idn-name=\"$_domain\"" | sed -r "s/.*service=\"(.*)\".*$/\1/")
|
||||
_service=$(printf "%s" "$response" | grep -m 1 "idn-name=\"$_domain\"" | sed -r "s/.*service=\"(.*)\".*$/\1/")
|
||||
return 0
|
||||
fi
|
||||
p="$i"
|
||||
|
||||
168
dnsapi/dns_njalla.sh
Normal file
168
dnsapi/dns_njalla.sh
Normal file
@@ -0,0 +1,168 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
#NJALLA_Token="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
|
||||
NJALLA_Api="https://njal.la/api/1/"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_njalla_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
NJALLA_Token="${NJALLA_Token:-$(_readaccountconf_mutable NJALLA_Token)}"
|
||||
|
||||
if [ "$NJALLA_Token" ]; then
|
||||
_saveaccountconf_mutable NJALLA_Token "$NJALLA_Token"
|
||||
else
|
||||
NJALLA_Token=""
|
||||
_err "You didn't specify a Njalla api token yet."
|
||||
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"
|
||||
|
||||
# For wildcard cert, the main root domain and the wildcard domain have the same txt subdomain name, so
|
||||
# we can not use updating anymore.
|
||||
# count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2)
|
||||
# _debug count "$count"
|
||||
# if [ "$count" = "0" ]; then
|
||||
_info "Adding record"
|
||||
if _njalla_rest "{\"method\":\"add-record\",\"params\":{\"domain\":\"$_domain\",\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}}"; then
|
||||
if _contains "$response" "$txtvalue"; then
|
||||
_info "Added, OK"
|
||||
return 0
|
||||
else
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
|
||||
}
|
||||
|
||||
#fulldomain txtvalue
|
||||
dns_njalla_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
NJALLA_Token="${NJALLA_Token:-$(_readaccountconf_mutable NJALLA_Token)}"
|
||||
|
||||
if [ "$NJALLA_Token" ]; then
|
||||
_saveaccountconf_mutable NJALLA_Token "$NJALLA_Token"
|
||||
else
|
||||
NJALLA_Token=""
|
||||
_err "You didn't specify a Njalla api token yet."
|
||||
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"
|
||||
|
||||
_debug "Getting records for domain"
|
||||
if ! _njalla_rest "{\"method\":\"list-records\",\"params\":{\"domain\":\"${_domain}\"}}"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! echo "$response" | tr -d " " | grep "\"id\":" >/dev/null; then
|
||||
_err "Error: $response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
records=$(echo "$response" | _egrep_o "\"records\":\s?\[(.*)\]\}" | _egrep_o "\[.*\]" | _egrep_o "\{[^\{\}]*\"id\":[^\{\}]*\}")
|
||||
count=$(echo "$records" | wc -l)
|
||||
_debug count "$count"
|
||||
|
||||
if [ "$count" = "0" ]; then
|
||||
_info "Don't need to remove."
|
||||
else
|
||||
echo "$records" | while read -r record; do
|
||||
record_name=$(echo "$record" | _egrep_o "\"name\":\s?\"[^\"]*\"" | cut -d : -f 2 | tr -d " " | tr -d \")
|
||||
record_content=$(echo "$record" | _egrep_o "\"content\":\s?\"[^\"]*\"" | cut -d : -f 2 | tr -d " " | tr -d \")
|
||||
record_id=$(echo "$record" | _egrep_o "\"id\":\s?[0-9]+" | cut -d : -f 2 | tr -d " " | tr -d \")
|
||||
if [ "$_sub_domain" = "$record_name" ]; then
|
||||
if [ "$txtvalue" = "$record_content" ]; then
|
||||
_debug "record_id" "$record_id"
|
||||
if ! _njalla_rest "{\"method\":\"remove-record\",\"params\":{\"domain\":\"${_domain}\",\"id\":${record_id}}}"; then
|
||||
_err "Delete record error."
|
||||
return 1
|
||||
fi
|
||||
echo "$response" | tr -d " " | grep "\"result\"" >/dev/null
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
# _domain_id=sdjkglgdfewsdfg
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=1
|
||||
p=1
|
||||
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _njalla_rest "{\"method\":\"get-domain\",\"params\":{\"domain\":\"${h}\"}}"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "\"$h\""; then
|
||||
_domain_returned=$(echo "$response" | _egrep_o "\{\"name\": *\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \" | tr -d " ")
|
||||
if [ "$_domain_returned" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
_njalla_rest() {
|
||||
data="$1"
|
||||
|
||||
token_trimmed=$(echo "$NJALLA_Token" | tr -d '"')
|
||||
|
||||
export _H1="Content-Type: application/json"
|
||||
export _H2="Accept: application/json"
|
||||
export _H3="Authorization: Njalla $token_trimmed"
|
||||
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$NJALLA_Api" "" "POST")"
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $data"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
@@ -51,7 +51,7 @@ dns_nsd_rm() {
|
||||
Nsd_ZoneFile="${Nsd_ZoneFile:-$(_readdomainconf Nsd_ZoneFile)}"
|
||||
Nsd_Command="${Nsd_Command:-$(_readdomainconf Nsd_Command)}"
|
||||
|
||||
sed -i "/$fulldomain. $ttlvalue IN TXT \"$txtvalue\"/d" "$Nsd_ZoneFile"
|
||||
_sed_i "/$fulldomain. $ttlvalue IN TXT \"$txtvalue\"/d" "$Nsd_ZoneFile"
|
||||
_info "Removed TXT record for $fulldomain"
|
||||
_debug "Running $Nsd_Command"
|
||||
if eval "$Nsd_Command"; then
|
||||
|
||||
324
dnsapi/dns_oci.sh
Normal file
324
dnsapi/dns_oci.sh
Normal file
@@ -0,0 +1,324 @@
|
||||
#!/usr/bin/env sh
|
||||
#
|
||||
# Acme.sh DNS API plugin for Oracle Cloud Infrastructure
|
||||
# Copyright (c) 2021, Oracle and/or its affiliates
|
||||
#
|
||||
# The plugin will automatically use the default profile from an OCI SDK and CLI
|
||||
# configuration file, if it exists.
|
||||
#
|
||||
# Alternatively, set the following environment variables:
|
||||
# - OCI_CLI_TENANCY : OCID of tenancy that contains the target DNS zone
|
||||
# - OCI_CLI_USER : OCID of user with permission to add/remove records from zones
|
||||
# - OCI_CLI_REGION : Should point to the tenancy home region
|
||||
#
|
||||
# One of the following two variables is required:
|
||||
# - OCI_CLI_KEY_FILE: Path to private API signing key file in PEM format; or
|
||||
# - OCI_CLI_KEY : The private API signing key in PEM format
|
||||
#
|
||||
# NOTE: using an encrypted private key that needs a passphrase is not supported.
|
||||
#
|
||||
|
||||
dns_oci_add() {
|
||||
_fqdn="$1"
|
||||
_rdata="$2"
|
||||
|
||||
if _get_oci_zone; then
|
||||
|
||||
_add_record_body="{\"items\":[{\"domain\":\"${_sub_domain}.${_domain}\",\"rdata\":\"$_rdata\",\"rtype\":\"TXT\",\"ttl\": 30,\"operation\":\"ADD\"}]}"
|
||||
response=$(_signed_request "PATCH" "/20180115/zones/${_domain}/records" "$_add_record_body")
|
||||
if [ "$response" ]; then
|
||||
_info "Success: added TXT record for ${_sub_domain}.${_domain}."
|
||||
else
|
||||
_err "Error: failed to add TXT record for ${_sub_domain}.${_domain}."
|
||||
_err "Check that the user has permission to add records to this zone."
|
||||
return 1
|
||||
fi
|
||||
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
dns_oci_rm() {
|
||||
_fqdn="$1"
|
||||
_rdata="$2"
|
||||
|
||||
if _get_oci_zone; then
|
||||
|
||||
_remove_record_body="{\"items\":[{\"domain\":\"${_sub_domain}.${_domain}\",\"rdata\":\"$_rdata\",\"rtype\":\"TXT\",\"operation\":\"REMOVE\"}]}"
|
||||
response=$(_signed_request "PATCH" "/20180115/zones/${_domain}/records" "$_remove_record_body")
|
||||
if [ "$response" ]; then
|
||||
_info "Success: removed TXT record for ${_sub_domain}.${_domain}."
|
||||
else
|
||||
_err "Error: failed to remove TXT record for ${_sub_domain}.${_domain}."
|
||||
_err "Check that the user has permission to remove records from this zone."
|
||||
return 1
|
||||
fi
|
||||
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
_get_oci_zone() {
|
||||
|
||||
if ! _oci_config; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _get_zone "$_fqdn"; then
|
||||
_err "Error: DNS Zone not found for $_fqdn in $OCI_CLI_TENANCY"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
|
||||
}
|
||||
|
||||
_oci_config() {
|
||||
|
||||
_DEFAULT_OCI_CLI_CONFIG_FILE="$HOME/.oci/config"
|
||||
OCI_CLI_CONFIG_FILE="${OCI_CLI_CONFIG_FILE:-$(_readaccountconf_mutable OCI_CLI_CONFIG_FILE)}"
|
||||
|
||||
if [ -z "$OCI_CLI_CONFIG_FILE" ]; then
|
||||
OCI_CLI_CONFIG_FILE="$_DEFAULT_OCI_CLI_CONFIG_FILE"
|
||||
fi
|
||||
|
||||
if [ "$_DEFAULT_OCI_CLI_CONFIG_FILE" != "$OCI_CLI_CONFIG_FILE" ]; then
|
||||
_saveaccountconf_mutable OCI_CLI_CONFIG_FILE "$OCI_CLI_CONFIG_FILE"
|
||||
else
|
||||
_clearaccountconf_mutable OCI_CLI_CONFIG_FILE
|
||||
fi
|
||||
|
||||
_DEFAULT_OCI_CLI_PROFILE="DEFAULT"
|
||||
OCI_CLI_PROFILE="${OCI_CLI_PROFILE:-$(_readaccountconf_mutable OCI_CLI_PROFILE)}"
|
||||
if [ "$_DEFAULT_OCI_CLI_PROFILE" != "$OCI_CLI_PROFILE" ]; then
|
||||
_saveaccountconf_mutable OCI_CLI_PROFILE "$OCI_CLI_PROFILE"
|
||||
else
|
||||
OCI_CLI_PROFILE="$_DEFAULT_OCI_CLI_PROFILE"
|
||||
_clearaccountconf_mutable OCI_CLI_PROFILE
|
||||
fi
|
||||
|
||||
OCI_CLI_TENANCY="${OCI_CLI_TENANCY:-$(_readaccountconf_mutable OCI_CLI_TENANCY)}"
|
||||
if [ "$OCI_CLI_TENANCY" ]; then
|
||||
_saveaccountconf_mutable OCI_CLI_TENANCY "$OCI_CLI_TENANCY"
|
||||
elif [ -f "$OCI_CLI_CONFIG_FILE" ]; then
|
||||
_debug "Reading OCI_CLI_TENANCY value from: $OCI_CLI_CONFIG_FILE"
|
||||
OCI_CLI_TENANCY="${OCI_CLI_TENANCY:-$(_readini "$OCI_CLI_CONFIG_FILE" tenancy "$OCI_CLI_PROFILE")}"
|
||||
fi
|
||||
|
||||
if [ -z "$OCI_CLI_TENANCY" ]; then
|
||||
_err "Error: unable to read OCI_CLI_TENANCY from config file or environment variable."
|
||||
return 1
|
||||
fi
|
||||
|
||||
OCI_CLI_USER="${OCI_CLI_USER:-$(_readaccountconf_mutable OCI_CLI_USER)}"
|
||||
if [ "$OCI_CLI_USER" ]; then
|
||||
_saveaccountconf_mutable OCI_CLI_USER "$OCI_CLI_USER"
|
||||
elif [ -f "$OCI_CLI_CONFIG_FILE" ]; then
|
||||
_debug "Reading OCI_CLI_USER value from: $OCI_CLI_CONFIG_FILE"
|
||||
OCI_CLI_USER="${OCI_CLI_USER:-$(_readini "$OCI_CLI_CONFIG_FILE" user "$OCI_CLI_PROFILE")}"
|
||||
fi
|
||||
if [ -z "$OCI_CLI_USER" ]; then
|
||||
_err "Error: unable to read OCI_CLI_USER from config file or environment variable."
|
||||
return 1
|
||||
fi
|
||||
|
||||
OCI_CLI_REGION="${OCI_CLI_REGION:-$(_readaccountconf_mutable OCI_CLI_REGION)}"
|
||||
if [ "$OCI_CLI_REGION" ]; then
|
||||
_saveaccountconf_mutable OCI_CLI_REGION "$OCI_CLI_REGION"
|
||||
elif [ -f "$OCI_CLI_CONFIG_FILE" ]; then
|
||||
_debug "Reading OCI_CLI_REGION value from: $OCI_CLI_CONFIG_FILE"
|
||||
OCI_CLI_REGION="${OCI_CLI_REGION:-$(_readini "$OCI_CLI_CONFIG_FILE" region "$OCI_CLI_PROFILE")}"
|
||||
fi
|
||||
if [ -z "$OCI_CLI_REGION" ]; then
|
||||
_err "Error: unable to read OCI_CLI_REGION from config file or environment variable."
|
||||
return 1
|
||||
fi
|
||||
|
||||
OCI_CLI_KEY="${OCI_CLI_KEY:-$(_readaccountconf_mutable OCI_CLI_KEY)}"
|
||||
if [ -z "$OCI_CLI_KEY" ]; then
|
||||
_clearaccountconf_mutable OCI_CLI_KEY
|
||||
OCI_CLI_KEY_FILE="${OCI_CLI_KEY_FILE:-$(_readini "$OCI_CLI_CONFIG_FILE" key_file "$OCI_CLI_PROFILE")}"
|
||||
if [ "$OCI_CLI_KEY_FILE" ] && [ -f "$OCI_CLI_KEY_FILE" ]; then
|
||||
_debug "Reading OCI_CLI_KEY value from: $OCI_CLI_KEY_FILE"
|
||||
OCI_CLI_KEY=$(_base64 <"$OCI_CLI_KEY_FILE")
|
||||
_saveaccountconf_mutable OCI_CLI_KEY "$OCI_CLI_KEY"
|
||||
fi
|
||||
else
|
||||
_saveaccountconf_mutable OCI_CLI_KEY "$OCI_CLI_KEY"
|
||||
fi
|
||||
|
||||
if [ -z "$OCI_CLI_KEY_FILE" ] && [ -z "$OCI_CLI_KEY" ]; then
|
||||
_err "Error: unable to find key file path in OCI config file or OCI_CLI_KEY_FILE."
|
||||
_err "Error: unable to load private API signing key from OCI_CLI_KEY."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$(printf "%s\n" "$OCI_CLI_KEY" | wc -l)" -eq 1 ]; then
|
||||
OCI_CLI_KEY=$(printf "%s" "$OCI_CLI_KEY" | _dbase64 multiline)
|
||||
fi
|
||||
|
||||
return 0
|
||||
|
||||
}
|
||||
|
||||
# _get_zone(): retrieves the Zone name and OCID
|
||||
#
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
# _domain_ociid=ocid1.dns-zone.oc1..
|
||||
_get_zone() {
|
||||
domain=$1
|
||||
i=1
|
||||
p=1
|
||||
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
# not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
_domain_id=$(_signed_request "GET" "/20180115/zones/$h" "" "id")
|
||||
if [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain=$h
|
||||
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
return 0
|
||||
fi
|
||||
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
|
||||
}
|
||||
|
||||
#Usage: privatekey
|
||||
#Output MD5 fingerprint
|
||||
_fingerprint() {
|
||||
|
||||
pkey="$1"
|
||||
if [ -z "$pkey" ]; then
|
||||
_usage "Usage: _fingerprint privkey"
|
||||
return 1
|
||||
fi
|
||||
|
||||
printf "%s" "$pkey" | ${ACME_OPENSSL_BIN:-openssl} rsa -pubout -outform DER 2>/dev/null | ${ACME_OPENSSL_BIN:-openssl} md5 -c | cut -d = -f 2 | tr -d ' '
|
||||
|
||||
}
|
||||
|
||||
_signed_request() {
|
||||
|
||||
_sig_method="$1"
|
||||
_sig_target="$2"
|
||||
_sig_body="$3"
|
||||
_return_field="$4"
|
||||
|
||||
_key_fingerprint=$(_fingerprint "$OCI_CLI_KEY")
|
||||
_sig_host="dns.$OCI_CLI_REGION.oraclecloud.com"
|
||||
_sig_keyId="$OCI_CLI_TENANCY/$OCI_CLI_USER/$_key_fingerprint"
|
||||
_sig_alg="rsa-sha256"
|
||||
_sig_version="1"
|
||||
_sig_now="$(LC_ALL=C \date -u "+%a, %d %h %Y %H:%M:%S GMT")"
|
||||
|
||||
_request_method=$(printf %s "$_sig_method" | _lower_case)
|
||||
_curl_method=$(printf %s "$_sig_method" | _upper_case)
|
||||
|
||||
_request_target="(request-target): $_request_method $_sig_target"
|
||||
_date_header="date: $_sig_now"
|
||||
_host_header="host: $_sig_host"
|
||||
|
||||
_string_to_sign="$_request_target\n$_date_header\n$_host_header"
|
||||
_sig_headers="(request-target) date host"
|
||||
|
||||
if [ "$_sig_body" ]; then
|
||||
_secure_debug3 _sig_body "$_sig_body"
|
||||
_sig_body_sha256="x-content-sha256: $(printf %s "$_sig_body" | _digest sha256)"
|
||||
_sig_body_type="content-type: application/json"
|
||||
_sig_body_length="content-length: ${#_sig_body}"
|
||||
_string_to_sign="$_string_to_sign\n$_sig_body_sha256\n$_sig_body_type\n$_sig_body_length"
|
||||
_sig_headers="$_sig_headers x-content-sha256 content-type content-length"
|
||||
fi
|
||||
|
||||
_tmp_file=$(_mktemp)
|
||||
if [ -f "$_tmp_file" ]; then
|
||||
printf '%s' "$OCI_CLI_KEY" >"$_tmp_file"
|
||||
_signature=$(printf '%b' "$_string_to_sign" | _sign "$_tmp_file" sha256 | tr -d '\r\n')
|
||||
rm -f "$_tmp_file"
|
||||
fi
|
||||
|
||||
_signed_header="Authorization: Signature version=\"$_sig_version\",keyId=\"$_sig_keyId\",algorithm=\"$_sig_alg\",headers=\"$_sig_headers\",signature=\"$_signature\""
|
||||
_secure_debug3 _signed_header "$_signed_header"
|
||||
|
||||
if [ "$_curl_method" = "GET" ]; then
|
||||
export _H1="$_date_header"
|
||||
export _H2="$_signed_header"
|
||||
_response="$(_get "https://${_sig_host}${_sig_target}")"
|
||||
elif [ "$_curl_method" = "PATCH" ]; then
|
||||
export _H1="$_date_header"
|
||||
export _H2="$_sig_body_sha256"
|
||||
export _H3="$_sig_body_type"
|
||||
export _H4="$_sig_body_length"
|
||||
export _H5="$_signed_header"
|
||||
_response="$(_post "$_sig_body" "https://${_sig_host}${_sig_target}" "" "PATCH")"
|
||||
else
|
||||
_err "Unable to process method: $_curl_method."
|
||||
fi
|
||||
|
||||
_ret="$?"
|
||||
if [ "$_return_field" ]; then
|
||||
_response="$(echo "$_response" | sed 's/\\\"//g'))"
|
||||
_return=$(echo "${_response}" | _egrep_o "\"$_return_field\"\\s*:\\s*\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d "\"")
|
||||
else
|
||||
_return="$_response"
|
||||
fi
|
||||
|
||||
printf "%s" "$_return"
|
||||
return $_ret
|
||||
|
||||
}
|
||||
|
||||
# file key [section]
|
||||
_readini() {
|
||||
_file="$1"
|
||||
_key="$2"
|
||||
_section="${3:-DEFAULT}"
|
||||
|
||||
_start_n=$(grep -n '\['"$_section"']' "$_file" | cut -d : -f 1)
|
||||
_debug3 _start_n "$_start_n"
|
||||
if [ -z "$_start_n" ]; then
|
||||
_err "Can not find section: $_section"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_start_nn=$(_math "$_start_n" + 1)
|
||||
_debug3 "_start_nn" "$_start_nn"
|
||||
|
||||
_left="$(sed -n "${_start_nn},99999p" "$_file")"
|
||||
_debug3 _left "$_left"
|
||||
_end="$(echo "$_left" | grep -n "^\[" | _head_n 1)"
|
||||
_debug3 "_end" "$_end"
|
||||
if [ "$_end" ]; then
|
||||
_end_n=$(echo "$_end" | cut -d : -f 1)
|
||||
_debug3 "_end_n" "$_end_n"
|
||||
_seg_n=$(echo "$_left" | sed -n "1,${_end_n}p")
|
||||
else
|
||||
_seg_n="$_left"
|
||||
fi
|
||||
|
||||
_debug3 "_seg_n" "$_seg_n"
|
||||
_lineini="$(echo "$_seg_n" | grep "^ *$_key *= *")"
|
||||
_inivalue="$(printf "%b" "$(eval "echo $_lineini | sed \"s/^ *${_key} *= *//g\"")")"
|
||||
_debug2 _inivalue "$_inivalue"
|
||||
echo "$_inivalue"
|
||||
|
||||
}
|
||||
@@ -1,22 +1,9 @@
|
||||
#!/usr/bin/env sh
|
||||
# -*- mode: sh; tab-width: 2; indent-tabs-mode: s; coding: utf-8 -*-
|
||||
|
||||
# one.com ui wrapper for acme.sh
|
||||
# Author: github: @diseq
|
||||
# Created: 2019-02-17
|
||||
# Fixed by: @der-berni
|
||||
# Modified: 2020-04-07
|
||||
#
|
||||
# Use ONECOM_KeepCnameProxy to keep the CNAME DNS record
|
||||
# export ONECOM_KeepCnameProxy="1"
|
||||
#
|
||||
|
||||
#
|
||||
# export ONECOM_User="username"
|
||||
# export ONECOM_Password="password"
|
||||
#
|
||||
# Usage:
|
||||
# acme.sh --issue --dns dns_one -d example.com
|
||||
#
|
||||
# only single domain supported atm
|
||||
|
||||
dns_one_add() {
|
||||
fulldomain=$1
|
||||
@@ -36,27 +23,9 @@ dns_one_add() {
|
||||
subdomain="${_sub_domain}"
|
||||
maindomain=${_domain}
|
||||
|
||||
useProxy=0
|
||||
if [ "${_sub_domain}" = "_acme-challenge" ]; then
|
||||
subdomain="proxy${_sub_domain}"
|
||||
useProxy=1
|
||||
fi
|
||||
|
||||
_debug subdomain "$subdomain"
|
||||
_debug maindomain "$maindomain"
|
||||
|
||||
if [ $useProxy -eq 1 ]; then
|
||||
#Check if the CNAME exists
|
||||
_dns_one_getrecord "CNAME" "$_sub_domain" "$subdomain.$maindomain"
|
||||
if [ -z "$id" ]; then
|
||||
_info "$(__red "Add CNAME Proxy record: '$(__green "\"$_sub_domain\" => \"$subdomain.$maindomain\"")'")"
|
||||
_dns_one_addrecord "CNAME" "$_sub_domain" "$subdomain.$maindomain"
|
||||
|
||||
_info "Not valid yet, let's wait 1 hour to take effect."
|
||||
_sleep 3600
|
||||
fi
|
||||
fi
|
||||
|
||||
#Check if the TXT exists
|
||||
_dns_one_getrecord "TXT" "$subdomain" "$txtvalue"
|
||||
if [ -n "$id" ]; then
|
||||
@@ -92,26 +61,8 @@ dns_one_rm() {
|
||||
subdomain="${_sub_domain}"
|
||||
maindomain=${_domain}
|
||||
|
||||
useProxy=0
|
||||
if [ "${_sub_domain}" = "_acme-challenge" ]; then
|
||||
subdomain="proxy${_sub_domain}"
|
||||
useProxy=1
|
||||
fi
|
||||
|
||||
_debug subdomain "$subdomain"
|
||||
_debug maindomain "$maindomain"
|
||||
if [ $useProxy -eq 1 ]; then
|
||||
if [ "$ONECOM_KeepCnameProxy" = "1" ]; then
|
||||
_info "$(__red "Keeping CNAME Proxy record: '$(__green "\"$_sub_domain\" => \"$subdomain.$maindomain\"")'")"
|
||||
else
|
||||
#Check if the CNAME exists
|
||||
_dns_one_getrecord "CNAME" "$_sub_domain" "$subdomain.$maindomain"
|
||||
if [ -n "$id" ]; then
|
||||
_info "$(__red "Removing CNAME Proxy record: '$(__green "\"$_sub_domain\" => \"$subdomain.$maindomain\"")'")"
|
||||
_dns_one_delrecord "$id"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
#Check if the TXT exists
|
||||
_dns_one_getrecord "TXT" "$subdomain" "$txtvalue"
|
||||
@@ -136,7 +87,7 @@ dns_one_rm() {
|
||||
# _domain=domain.com
|
||||
_get_root() {
|
||||
domain="$1"
|
||||
i=2
|
||||
i=1
|
||||
p=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
@@ -163,8 +114,6 @@ _get_root() {
|
||||
_dns_one_login() {
|
||||
|
||||
# get credentials
|
||||
ONECOM_KeepCnameProxy="${ONECOM_KeepCnameProxy:-$(_readaccountconf_mutable ONECOM_KeepCnameProxy)}"
|
||||
ONECOM_KeepCnameProxy="${ONECOM_KeepCnameProxy:-0}"
|
||||
ONECOM_User="${ONECOM_User:-$(_readaccountconf_mutable ONECOM_User)}"
|
||||
ONECOM_Password="${ONECOM_Password:-$(_readaccountconf_mutable ONECOM_Password)}"
|
||||
if [ -z "$ONECOM_User" ] || [ -z "$ONECOM_Password" ]; then
|
||||
@@ -176,7 +125,6 @@ _dns_one_login() {
|
||||
fi
|
||||
|
||||
#save the api key and email to the account conf file.
|
||||
_saveaccountconf_mutable ONECOM_KeepCnameProxy "$ONECOM_KeepCnameProxy"
|
||||
_saveaccountconf_mutable ONECOM_User "$ONECOM_User"
|
||||
_saveaccountconf_mutable ONECOM_Password "$ONECOM_Password"
|
||||
|
||||
|
||||
348
dnsapi/dns_openstack.sh
Executable file
348
dnsapi/dns_openstack.sh
Executable file
@@ -0,0 +1,348 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# OpenStack Designate API plugin
|
||||
#
|
||||
# This requires you to have OpenStackClient and python-desginateclient
|
||||
# installed.
|
||||
#
|
||||
# You will require Keystone V3 credentials loaded into your environment, which
|
||||
# could be either password or v3applicationcredential type.
|
||||
#
|
||||
# Author: Andy Botting <andy@andybotting.com>
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
# Usage: dns_openstack_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_openstack_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
_dns_openstack_credentials || return $?
|
||||
_dns_openstack_check_setup || return $?
|
||||
_dns_openstack_find_zone || return $?
|
||||
_dns_openstack_get_recordset || return $?
|
||||
_debug _recordset_id "$_recordset_id"
|
||||
if [ -n "$_recordset_id" ]; then
|
||||
_dns_openstack_get_records || return $?
|
||||
_debug _records "$_records"
|
||||
fi
|
||||
_dns_openstack_create_recordset || return $?
|
||||
}
|
||||
|
||||
# Usage: dns_openstack_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
# Remove the txt record after validation.
|
||||
dns_openstack_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
_dns_openstack_credentials || return $?
|
||||
_dns_openstack_check_setup || return $?
|
||||
_dns_openstack_find_zone || return $?
|
||||
_dns_openstack_get_recordset || return $?
|
||||
_debug _recordset_id "$_recordset_id"
|
||||
if [ -n "$_recordset_id" ]; then
|
||||
_dns_openstack_get_records || return $?
|
||||
_debug _records "$_records"
|
||||
fi
|
||||
_dns_openstack_delete_recordset || return $?
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
_dns_openstack_create_recordset() {
|
||||
|
||||
if [ -z "$_recordset_id" ]; then
|
||||
_info "Creating a new recordset"
|
||||
if ! _recordset_id=$(openstack recordset create -c id -f value --type TXT --record "$txtvalue" "$_zone_id" "$fulldomain."); then
|
||||
_err "No recordset ID found after create"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_info "Updating existing recordset"
|
||||
# Build new list of --record <rec> args for update
|
||||
_record_args="--record $txtvalue"
|
||||
for _rec in $_records; do
|
||||
_record_args="$_record_args --record $_rec"
|
||||
done
|
||||
# shellcheck disable=SC2086
|
||||
if ! _recordset_id=$(openstack recordset set -c id -f value $_record_args "$_zone_id" "$fulldomain."); then
|
||||
_err "Recordset update failed"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
_max_retries=60
|
||||
_sleep_sec=5
|
||||
_retry_times=0
|
||||
while [ "$_retry_times" -lt "$_max_retries" ]; do
|
||||
_retry_times=$(_math "$_retry_times" + 1)
|
||||
_debug3 _retry_times "$_retry_times"
|
||||
|
||||
_record_status=$(openstack recordset show -c status -f value "$_zone_id" "$_recordset_id")
|
||||
_info "Recordset status is $_record_status"
|
||||
if [ "$_record_status" = "ACTIVE" ]; then
|
||||
return 0
|
||||
elif [ "$_record_status" = "ERROR" ]; then
|
||||
return 1
|
||||
else
|
||||
_sleep $_sleep_sec
|
||||
fi
|
||||
done
|
||||
|
||||
_err "Recordset failed to become ACTIVE"
|
||||
return 1
|
||||
}
|
||||
|
||||
_dns_openstack_delete_recordset() {
|
||||
|
||||
if [ "$_records" = "$txtvalue" ]; then
|
||||
_info "Only one record found, deleting recordset"
|
||||
if ! openstack recordset delete "$_zone_id" "$fulldomain." >/dev/null; then
|
||||
_err "Failed to delete recordset"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_info "Found existing records, updating recordset"
|
||||
# Build new list of --record <rec> args for update
|
||||
_record_args=""
|
||||
for _rec in $_records; do
|
||||
if [ "$_rec" = "$txtvalue" ]; then
|
||||
continue
|
||||
fi
|
||||
_record_args="$_record_args --record $_rec"
|
||||
done
|
||||
# shellcheck disable=SC2086
|
||||
if ! openstack recordset set -c id -f value $_record_args "$_zone_id" "$fulldomain." >/dev/null; then
|
||||
_err "Recordset update failed"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
_dns_openstack_get_root() {
|
||||
# Take the full fqdn and strip away pieces until we get an exact zone name
|
||||
# match. For example, _acme-challenge.something.domain.com might need to go
|
||||
# into something.domain.com or domain.com
|
||||
_zone_name=$1
|
||||
_zone_list=$2
|
||||
while [ "$_zone_name" != "" ]; do
|
||||
_zone_name="$(echo "$_zone_name" | sed 's/[^.]*\.*//')"
|
||||
echo "$_zone_list" | while read -r id name; do
|
||||
if _startswith "$_zone_name." "$name"; then
|
||||
echo "$id"
|
||||
fi
|
||||
done
|
||||
done | _head_n 1
|
||||
}
|
||||
|
||||
_dns_openstack_find_zone() {
|
||||
if ! _zone_list="$(openstack zone list -c id -c name -f value)"; then
|
||||
_err "Can't list zones. Check your OpenStack credentials"
|
||||
return 1
|
||||
fi
|
||||
_debug _zone_list "$_zone_list"
|
||||
|
||||
if ! _zone_id="$(_dns_openstack_get_root "$fulldomain" "$_zone_list")"; then
|
||||
_err "Can't find a matching zone. Check your OpenStack credentials"
|
||||
return 1
|
||||
fi
|
||||
_debug _zone_id "$_zone_id"
|
||||
}
|
||||
|
||||
_dns_openstack_get_records() {
|
||||
if ! _records=$(openstack recordset show -c records -f value "$_zone_id" "$fulldomain."); then
|
||||
_err "Failed to get records"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
_dns_openstack_get_recordset() {
|
||||
if ! _recordset_id=$(openstack recordset list -c id -f value --name "$fulldomain." "$_zone_id"); then
|
||||
_err "Failed to get recordset"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
_dns_openstack_check_setup() {
|
||||
if ! _exists openstack; then
|
||||
_err "OpenStack client not found"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
_dns_openstack_credentials() {
|
||||
_debug "Check OpenStack credentials"
|
||||
|
||||
# If we have OS_AUTH_URL already set in the environment, then assume we want
|
||||
# to use those, otherwise use stored credentials
|
||||
if [ -n "$OS_AUTH_URL" ]; then
|
||||
_debug "OS_AUTH_URL env var found, using environment"
|
||||
else
|
||||
_debug "OS_AUTH_URL not found, loading stored credentials"
|
||||
OS_AUTH_URL="${OS_AUTH_URL:-$(_readaccountconf_mutable OS_AUTH_URL)}"
|
||||
OS_IDENTITY_API_VERSION="${OS_IDENTITY_API_VERSION:-$(_readaccountconf_mutable OS_IDENTITY_API_VERSION)}"
|
||||
OS_AUTH_TYPE="${OS_AUTH_TYPE:-$(_readaccountconf_mutable OS_AUTH_TYPE)}"
|
||||
OS_APPLICATION_CREDENTIAL_ID="${OS_APPLICATION_CREDENTIAL_ID:-$(_readaccountconf_mutable OS_APPLICATION_CREDENTIAL_ID)}"
|
||||
OS_APPLICATION_CREDENTIAL_SECRET="${OS_APPLICATION_CREDENTIAL_SECRET:-$(_readaccountconf_mutable OS_APPLICATION_CREDENTIAL_SECRET)}"
|
||||
OS_USERNAME="${OS_USERNAME:-$(_readaccountconf_mutable OS_USERNAME)}"
|
||||
OS_PASSWORD="${OS_PASSWORD:-$(_readaccountconf_mutable OS_PASSWORD)}"
|
||||
OS_PROJECT_NAME="${OS_PROJECT_NAME:-$(_readaccountconf_mutable OS_PROJECT_NAME)}"
|
||||
OS_PROJECT_ID="${OS_PROJECT_ID:-$(_readaccountconf_mutable OS_PROJECT_ID)}"
|
||||
OS_USER_DOMAIN_NAME="${OS_USER_DOMAIN_NAME:-$(_readaccountconf_mutable OS_USER_DOMAIN_NAME)}"
|
||||
OS_USER_DOMAIN_ID="${OS_USER_DOMAIN_ID:-$(_readaccountconf_mutable OS_USER_DOMAIN_ID)}"
|
||||
OS_PROJECT_DOMAIN_NAME="${OS_PROJECT_DOMAIN_NAME:-$(_readaccountconf_mutable OS_PROJECT_DOMAIN_NAME)}"
|
||||
OS_PROJECT_DOMAIN_ID="${OS_PROJECT_DOMAIN_ID:-$(_readaccountconf_mutable OS_PROJECT_DOMAIN_ID)}"
|
||||
fi
|
||||
|
||||
# Check each var and either save or clear it depending on whether its set.
|
||||
# The helps us clear out old vars in the case where a user may want
|
||||
# to switch between password and app creds
|
||||
_debug "OS_AUTH_URL" "$OS_AUTH_URL"
|
||||
if [ -n "$OS_AUTH_URL" ]; then
|
||||
export OS_AUTH_URL
|
||||
_saveaccountconf_mutable OS_AUTH_URL "$OS_AUTH_URL"
|
||||
else
|
||||
unset OS_AUTH_URL
|
||||
_clearaccountconf SAVED_OS_AUTH_URL
|
||||
fi
|
||||
|
||||
_debug "OS_IDENTITY_API_VERSION" "$OS_IDENTITY_API_VERSION"
|
||||
if [ -n "$OS_IDENTITY_API_VERSION" ]; then
|
||||
export OS_IDENTITY_API_VERSION
|
||||
_saveaccountconf_mutable OS_IDENTITY_API_VERSION "$OS_IDENTITY_API_VERSION"
|
||||
else
|
||||
unset OS_IDENTITY_API_VERSION
|
||||
_clearaccountconf SAVED_OS_IDENTITY_API_VERSION
|
||||
fi
|
||||
|
||||
_debug "OS_AUTH_TYPE" "$OS_AUTH_TYPE"
|
||||
if [ -n "$OS_AUTH_TYPE" ]; then
|
||||
export OS_AUTH_TYPE
|
||||
_saveaccountconf_mutable OS_AUTH_TYPE "$OS_AUTH_TYPE"
|
||||
else
|
||||
unset OS_AUTH_TYPE
|
||||
_clearaccountconf SAVED_OS_AUTH_TYPE
|
||||
fi
|
||||
|
||||
_debug "OS_APPLICATION_CREDENTIAL_ID" "$OS_APPLICATION_CREDENTIAL_ID"
|
||||
if [ -n "$OS_APPLICATION_CREDENTIAL_ID" ]; then
|
||||
export OS_APPLICATION_CREDENTIAL_ID
|
||||
_saveaccountconf_mutable OS_APPLICATION_CREDENTIAL_ID "$OS_APPLICATION_CREDENTIAL_ID"
|
||||
else
|
||||
unset OS_APPLICATION_CREDENTIAL_ID
|
||||
_clearaccountconf SAVED_OS_APPLICATION_CREDENTIAL_ID
|
||||
fi
|
||||
|
||||
_secure_debug "OS_APPLICATION_CREDENTIAL_SECRET" "$OS_APPLICATION_CREDENTIAL_SECRET"
|
||||
if [ -n "$OS_APPLICATION_CREDENTIAL_SECRET" ]; then
|
||||
export OS_APPLICATION_CREDENTIAL_SECRET
|
||||
_saveaccountconf_mutable OS_APPLICATION_CREDENTIAL_SECRET "$OS_APPLICATION_CREDENTIAL_SECRET"
|
||||
else
|
||||
unset OS_APPLICATION_CREDENTIAL_SECRET
|
||||
_clearaccountconf SAVED_OS_APPLICATION_CREDENTIAL_SECRET
|
||||
fi
|
||||
|
||||
_debug "OS_USERNAME" "$OS_USERNAME"
|
||||
if [ -n "$OS_USERNAME" ]; then
|
||||
export OS_USERNAME
|
||||
_saveaccountconf_mutable OS_USERNAME "$OS_USERNAME"
|
||||
else
|
||||
unset OS_USERNAME
|
||||
_clearaccountconf SAVED_OS_USERNAME
|
||||
fi
|
||||
|
||||
_secure_debug "OS_PASSWORD" "$OS_PASSWORD"
|
||||
if [ -n "$OS_PASSWORD" ]; then
|
||||
export OS_PASSWORD
|
||||
_saveaccountconf_mutable OS_PASSWORD "$OS_PASSWORD"
|
||||
else
|
||||
unset OS_PASSWORD
|
||||
_clearaccountconf SAVED_OS_PASSWORD
|
||||
fi
|
||||
|
||||
_debug "OS_PROJECT_NAME" "$OS_PROJECT_NAME"
|
||||
if [ -n "$OS_PROJECT_NAME" ]; then
|
||||
export OS_PROJECT_NAME
|
||||
_saveaccountconf_mutable OS_PROJECT_NAME "$OS_PROJECT_NAME"
|
||||
else
|
||||
unset OS_PROJECT_NAME
|
||||
_clearaccountconf SAVED_OS_PROJECT_NAME
|
||||
fi
|
||||
|
||||
_debug "OS_PROJECT_ID" "$OS_PROJECT_ID"
|
||||
if [ -n "$OS_PROJECT_ID" ]; then
|
||||
export OS_PROJECT_ID
|
||||
_saveaccountconf_mutable OS_PROJECT_ID "$OS_PROJECT_ID"
|
||||
else
|
||||
unset OS_PROJECT_ID
|
||||
_clearaccountconf SAVED_OS_PROJECT_ID
|
||||
fi
|
||||
|
||||
_debug "OS_USER_DOMAIN_NAME" "$OS_USER_DOMAIN_NAME"
|
||||
if [ -n "$OS_USER_DOMAIN_NAME" ]; then
|
||||
export OS_USER_DOMAIN_NAME
|
||||
_saveaccountconf_mutable OS_USER_DOMAIN_NAME "$OS_USER_DOMAIN_NAME"
|
||||
else
|
||||
unset OS_USER_DOMAIN_NAME
|
||||
_clearaccountconf SAVED_OS_USER_DOMAIN_NAME
|
||||
fi
|
||||
|
||||
_debug "OS_USER_DOMAIN_ID" "$OS_USER_DOMAIN_ID"
|
||||
if [ -n "$OS_USER_DOMAIN_ID" ]; then
|
||||
export OS_USER_DOMAIN_ID
|
||||
_saveaccountconf_mutable OS_USER_DOMAIN_ID "$OS_USER_DOMAIN_ID"
|
||||
else
|
||||
unset OS_USER_DOMAIN_ID
|
||||
_clearaccountconf SAVED_OS_USER_DOMAIN_ID
|
||||
fi
|
||||
|
||||
_debug "OS_PROJECT_DOMAIN_NAME" "$OS_PROJECT_DOMAIN_NAME"
|
||||
if [ -n "$OS_PROJECT_DOMAIN_NAME" ]; then
|
||||
export OS_PROJECT_DOMAIN_NAME
|
||||
_saveaccountconf_mutable OS_PROJECT_DOMAIN_NAME "$OS_PROJECT_DOMAIN_NAME"
|
||||
else
|
||||
unset OS_PROJECT_DOMAIN_NAME
|
||||
_clearaccountconf SAVED_OS_PROJECT_DOMAIN_NAME
|
||||
fi
|
||||
|
||||
_debug "OS_PROJECT_DOMAIN_ID" "$OS_PROJECT_DOMAIN_ID"
|
||||
if [ -n "$OS_PROJECT_DOMAIN_ID" ]; then
|
||||
export OS_PROJECT_DOMAIN_ID
|
||||
_saveaccountconf_mutable OS_PROJECT_DOMAIN_ID "$OS_PROJECT_DOMAIN_ID"
|
||||
else
|
||||
unset OS_PROJECT_DOMAIN_ID
|
||||
_clearaccountconf SAVED_OS_PROJECT_DOMAIN_ID
|
||||
fi
|
||||
|
||||
if [ "$OS_AUTH_TYPE" = "v3applicationcredential" ]; then
|
||||
# Application Credential auth
|
||||
if [ -z "$OS_APPLICATION_CREDENTIAL_ID" ] || [ -z "$OS_APPLICATION_CREDENTIAL_SECRET" ]; then
|
||||
_err "When using OpenStack application credentials, OS_APPLICATION_CREDENTIAL_ID"
|
||||
_err "and OS_APPLICATION_CREDENTIAL_SECRET must be set."
|
||||
_err "Please check your credentials and try again."
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
# Password auth
|
||||
if [ -z "$OS_USERNAME" ] || [ -z "$OS_PASSWORD" ]; then
|
||||
_err "OpenStack username or password not found."
|
||||
_err "Please check your credentials and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$OS_PROJECT_NAME" ] && [ -z "$OS_PROJECT_ID" ]; then
|
||||
_err "When using password authentication, OS_PROJECT_NAME or"
|
||||
_err "OS_PROJECT_ID must be set."
|
||||
_err "Please check your credentials and try again."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
@@ -41,40 +41,40 @@ _ovh_get_api() {
|
||||
|
||||
case "${_ogaep}" in
|
||||
|
||||
ovh-eu | ovheu)
|
||||
printf "%s" $OVH_EU
|
||||
return
|
||||
;;
|
||||
ovh-ca | ovhca)
|
||||
printf "%s" $OVH_CA
|
||||
return
|
||||
;;
|
||||
kimsufi-eu | kimsufieu)
|
||||
printf "%s" $KSF_EU
|
||||
return
|
||||
;;
|
||||
kimsufi-ca | kimsufica)
|
||||
printf "%s" $KSF_CA
|
||||
return
|
||||
;;
|
||||
soyoustart-eu | soyoustarteu)
|
||||
printf "%s" $SYS_EU
|
||||
return
|
||||
;;
|
||||
soyoustart-ca | soyoustartca)
|
||||
printf "%s" $SYS_CA
|
||||
return
|
||||
;;
|
||||
runabove-ca | runaboveca)
|
||||
printf "%s" $RAV_CA
|
||||
return
|
||||
;;
|
||||
ovh-eu | ovheu)
|
||||
printf "%s" $OVH_EU
|
||||
return
|
||||
;;
|
||||
ovh-ca | ovhca)
|
||||
printf "%s" $OVH_CA
|
||||
return
|
||||
;;
|
||||
kimsufi-eu | kimsufieu)
|
||||
printf "%s" $KSF_EU
|
||||
return
|
||||
;;
|
||||
kimsufi-ca | kimsufica)
|
||||
printf "%s" $KSF_CA
|
||||
return
|
||||
;;
|
||||
soyoustart-eu | soyoustarteu)
|
||||
printf "%s" $SYS_EU
|
||||
return
|
||||
;;
|
||||
soyoustart-ca | soyoustartca)
|
||||
printf "%s" $SYS_CA
|
||||
return
|
||||
;;
|
||||
runabove-ca | runaboveca)
|
||||
printf "%s" $RAV_CA
|
||||
return
|
||||
;;
|
||||
|
||||
*)
|
||||
*)
|
||||
|
||||
_err "Unknown parameter : $1"
|
||||
return 1
|
||||
;;
|
||||
_err "Unknown parameter : $1"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
@@ -248,7 +248,7 @@ _ovh_authentication() {
|
||||
# _domain=domain.com
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=2
|
||||
i=1
|
||||
p=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
@@ -261,7 +261,9 @@ _get_root() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _contains "$response" "This service does not exist" >/dev/null && ! _contains "$response" "NOT_GRANTED_CALL" >/dev/null; then
|
||||
if ! _contains "$response" "This service does not exist" >/dev/null &&
|
||||
! _contains "$response" "This call has not been granted" >/dev/null &&
|
||||
! _contains "$response" "NOT_GRANTED_CALL" >/dev/null; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain="$h"
|
||||
return 0
|
||||
|
||||
@@ -103,7 +103,7 @@ set_record() {
|
||||
_build_record_string "$oldchallenge"
|
||||
done
|
||||
|
||||
if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root" "{\"rrsets\": [{\"changetype\": \"REPLACE\", \"name\": \"$full.\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [$_record_string]}]}"; then
|
||||
if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root" "{\"rrsets\": [{\"changetype\": \"REPLACE\", \"name\": \"$full.\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [$_record_string]}]}" "application/json"; then
|
||||
_err "Set txt record error."
|
||||
return 1
|
||||
fi
|
||||
@@ -126,7 +126,7 @@ rm_record() {
|
||||
|
||||
if _contains "$_existing_challenges" "$txtvalue"; then
|
||||
#Delete all challenges (PowerDNS API does not allow to delete content)
|
||||
if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root" "{\"rrsets\": [{\"changetype\": \"DELETE\", \"name\": \"$full.\", \"type\": \"TXT\"}]}"; then
|
||||
if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root" "{\"rrsets\": [{\"changetype\": \"DELETE\", \"name\": \"$full.\", \"type\": \"TXT\"}]}" "application/json"; then
|
||||
_err "Delete txt record error."
|
||||
return 1
|
||||
fi
|
||||
@@ -140,7 +140,7 @@ rm_record() {
|
||||
fi
|
||||
done
|
||||
#Recreate the existing challenges
|
||||
if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root" "{\"rrsets\": [{\"changetype\": \"REPLACE\", \"name\": \"$full.\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [$_record_string]}]}"; then
|
||||
if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root" "{\"rrsets\": [{\"changetype\": \"REPLACE\", \"name\": \"$full.\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [$_record_string]}]}" "application/json"; then
|
||||
_err "Set txt record error."
|
||||
return 1
|
||||
fi
|
||||
@@ -175,13 +175,13 @@ _get_root() {
|
||||
i=1
|
||||
|
||||
if _pdns_rest "GET" "/api/v1/servers/$PDNS_ServerId/zones"; then
|
||||
_zones_response="$response"
|
||||
_zones_response=$(echo "$response" | _normalizeJson)
|
||||
fi
|
||||
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
|
||||
if _contains "$_zones_response" "\"name\": \"$h.\""; then
|
||||
if _contains "$_zones_response" "\"name\":\"$h.\""; then
|
||||
_domain="$h."
|
||||
if [ -z "$h" ]; then
|
||||
_domain="=2E"
|
||||
@@ -203,12 +203,13 @@ _pdns_rest() {
|
||||
method=$1
|
||||
ep=$2
|
||||
data=$3
|
||||
ct=$4
|
||||
|
||||
export _H1="X-API-Key: $PDNS_Token"
|
||||
|
||||
if [ ! "$method" = "GET" ]; then
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$PDNS_Url$ep" "" "$method")"
|
||||
response="$(_post "$data" "$PDNS_Url$ep" "" "$method" "$ct")"
|
||||
else
|
||||
response="$(_get "$PDNS_Url$ep")"
|
||||
fi
|
||||
|
||||
@@ -136,11 +136,12 @@ dns_pleskxml_rm() {
|
||||
|
||||
# Reduce output to one line per DNS record, filtered for TXT records with a record ID only (which they should all have)
|
||||
# Also strip out spaces between tags, redundant <data> and </data> group tags and any <self-closing/> tags
|
||||
reclist="$(_api_response_split "$pleskxml_prettyprint_result" 'result' '<status>ok</status>' \
|
||||
| sed 's# \{1,\}<\([a-zA-Z]\)#<\1#g;s#</\{0,1\}data>##g;s#<[a-z][^/<>]*/>##g' \
|
||||
| grep "<site-id>${root_domain_id}</site-id>" \
|
||||
| grep '<id>[0-9]\{1,\}</id>' \
|
||||
| grep '<type>TXT</type>'
|
||||
reclist="$(
|
||||
_api_response_split "$pleskxml_prettyprint_result" 'result' '<status>ok</status>' |
|
||||
sed 's# \{1,\}<\([a-zA-Z]\)#<\1#g;s#</\{0,1\}data>##g;s#<[a-z][^/<>]*/>##g' |
|
||||
grep "<site-id>${root_domain_id}</site-id>" |
|
||||
grep '<id>[0-9]\{1,\}</id>' |
|
||||
grep '<type>TXT</type>'
|
||||
)"
|
||||
|
||||
if [ -z "$reclist" ]; then
|
||||
@@ -151,10 +152,11 @@ dns_pleskxml_rm() {
|
||||
_debug "Got list of DNS TXT records for root domain '$root_domain_name':"
|
||||
_debug "$reclist"
|
||||
|
||||
recid="$(_value "$reclist" \
|
||||
| grep "<host>${fulldomain}.</host>" \
|
||||
| grep "<value>${txtvalue}</value>" \
|
||||
| sed 's/^.*<id>\([0-9]\{1,\}\)<\/id>.*$/\1/'
|
||||
recid="$(
|
||||
_value "$reclist" |
|
||||
grep "<host>${fulldomain}.</host>" |
|
||||
grep "<value>${txtvalue}</value>" |
|
||||
sed 's/^.*<id>\([0-9]\{1,\}\)<\/id>.*$/\1/'
|
||||
)"
|
||||
|
||||
if ! _value "$recid" | grep '^[0-9]\{1,\}$' >/dev/null; then
|
||||
@@ -220,11 +222,11 @@ _countdots() {
|
||||
# Last line could change to <sed -n '/.../p'> instead, with suitable escaping of ['"/$],
|
||||
# if future Plesk XML API changes ever require extended regex
|
||||
_api_response_split() {
|
||||
printf '%s' "$1" \
|
||||
| sed 's/^ +//;s/ +$//' \
|
||||
| tr -d '\n\r' \
|
||||
| sed "s/<\/\{0,1\}$2>/${NEWLINE}/g" \
|
||||
| grep "$3"
|
||||
printf '%s' "$1" |
|
||||
sed 's/^ +//;s/ +$//' |
|
||||
tr -d '\n\r' |
|
||||
sed "s/<\/\{0,1\}$2>/${NEWLINE}/g" |
|
||||
grep "$3"
|
||||
}
|
||||
|
||||
#################### Private functions below (DNS functions) ##################################
|
||||
@@ -261,14 +263,15 @@ _call_api() {
|
||||
elif [ "$statuslines_count_okay" -ne "$statuslines_count_total" ]; then
|
||||
|
||||
# We have some status lines that aren't "ok". Any available details are in API response fields "status" "errcode" and "errtext"
|
||||
# Workaround for basic regex:
|
||||
# Workaround for basic regex:
|
||||
# - filter output to keep only lines like this: "SPACES<TAG>text</TAG>SPACES" (shouldn't be necessary with prettyprint but guarantees subsequent code is ok)
|
||||
# - then edit the 3 "useful" error tokens individually and remove closing tags on all lines
|
||||
# - then filter again to remove all lines not edited (which will be the lines not starting A-Z)
|
||||
errtext="$(_value "$pleskxml_prettyprint_result" \
|
||||
| grep '^ *<[a-z]\{1,\}>[^<]*<\/[a-z]\{1,\}> *$' \
|
||||
| sed 's/^ *<status>/Status: /;s/^ *<errcode>/Error code: /;s/^ *<errtext>/Error text: /;s/<\/.*$//' \
|
||||
| grep '^[A-Z]'
|
||||
errtext="$(
|
||||
_value "$pleskxml_prettyprint_result" |
|
||||
grep '^ *<[a-z]\{1,\}>[^<]*<\/[a-z]\{1,\}> *$' |
|
||||
sed 's/^ *<status>/Status: /;s/^ *<errcode>/Error code: /;s/^ *<errtext>/Error text: /;s/<\/.*$//' |
|
||||
grep '^[A-Z]'
|
||||
)"
|
||||
|
||||
fi
|
||||
|
||||
157
dnsapi/dns_porkbun.sh
Normal file
157
dnsapi/dns_porkbun.sh
Normal file
@@ -0,0 +1,157 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
#PORKBUN_API_KEY="pk1_0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||
#PORKBUN_SECRET_API_KEY="sk1_0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||
|
||||
PORKBUN_Api="https://porkbun.com/api/json/v3"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_porkbun_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
PORKBUN_API_KEY="${PORKBUN_API_KEY:-$(_readaccountconf_mutable PORKBUN_API_KEY)}"
|
||||
PORKBUN_SECRET_API_KEY="${PORKBUN_SECRET_API_KEY:-$(_readaccountconf_mutable PORKBUN_SECRET_API_KEY)}"
|
||||
|
||||
if [ -z "$PORKBUN_API_KEY" ] || [ -z "$PORKBUN_SECRET_API_KEY" ]; then
|
||||
PORKBUN_API_KEY=''
|
||||
PORKBUN_SECRET_API_KEY=''
|
||||
_err "You didn't specify a Porkbun api key and secret api key yet."
|
||||
_err "You can get yours from here https://porkbun.com/account/api."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the credentials to the account conf file.
|
||||
_saveaccountconf_mutable PORKBUN_API_KEY "$PORKBUN_API_KEY"
|
||||
_saveaccountconf_mutable PORKBUN_SECRET_API_KEY "$PORKBUN_SECRET_API_KEY"
|
||||
|
||||
_debug 'First detect the root zone'
|
||||
if ! _get_root "$fulldomain"; then
|
||||
return 1
|
||||
fi
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
# For wildcard cert, the main root domain and the wildcard domain have the same txt subdomain name, so
|
||||
# we can not use updating anymore.
|
||||
# count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2)
|
||||
# _debug count "$count"
|
||||
# if [ "$count" = "0" ]; then
|
||||
_info "Adding record"
|
||||
if _porkbun_rest POST "dns/create/$_domain" "{\"name\":\"$_sub_domain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"ttl\":120}"; then
|
||||
if _contains "$response" '\"status\":"SUCCESS"'; then
|
||||
_info "Added, OK"
|
||||
return 0
|
||||
elif _contains "$response" "The record already exists"; then
|
||||
_info "Already exists, OK"
|
||||
return 0
|
||||
else
|
||||
_err "Add txt record error. ($response)"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
|
||||
}
|
||||
|
||||
#fulldomain txtvalue
|
||||
dns_porkbun_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
PORKBUN_API_KEY="${PORKBUN_API_KEY:-$(_readaccountconf_mutable PORKBUN_API_KEY)}"
|
||||
PORKBUN_SECRET_API_KEY="${PORKBUN_SECRET_API_KEY:-$(_readaccountconf_mutable PORKBUN_SECRET_API_KEY)}"
|
||||
|
||||
_debug 'First detect the root zone'
|
||||
if ! _get_root "$fulldomain"; then
|
||||
return 1
|
||||
fi
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
count=$(echo "$response" | _egrep_o "\"count\": *[^,]*" | cut -d : -f 2 | tr -d " ")
|
||||
_debug count "$count"
|
||||
if [ "$count" = "0" ]; then
|
||||
_info "Don't need to remove."
|
||||
else
|
||||
record_id=$(echo "$response" | tr '{' '\n' | grep -- "$txtvalue" | cut -d, -f1 | cut -d: -f2 | tr -d \")
|
||||
_debug "record_id" "$record_id"
|
||||
if [ -z "$record_id" ]; then
|
||||
_err "Can not get record id to remove."
|
||||
return 1
|
||||
fi
|
||||
if ! _porkbun_rest POST "dns/delete/$_domain/$record_id"; then
|
||||
_err "Delete record error."
|
||||
return 1
|
||||
fi
|
||||
echo "$response" | tr -d " " | grep '\"status\":"SUCCESS"' >/dev/null
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _porkbun_rest POST "dns/retrieve/$h"; then
|
||||
if _contains "$response" "\"status\":\"SUCCESS\""; then
|
||||
_domain=$h
|
||||
_sub_domain="$(echo "$fulldomain" | sed "s/\\.$_domain\$//")"
|
||||
return 0
|
||||
else
|
||||
_debug "Go to next level of $_domain"
|
||||
fi
|
||||
else
|
||||
_debug "Go to next level of $_domain"
|
||||
fi
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
_porkbun_rest() {
|
||||
m=$1
|
||||
ep="$2"
|
||||
data="$3"
|
||||
_debug "$ep"
|
||||
|
||||
api_key_trimmed=$(echo "$PORKBUN_API_KEY" | tr -d '"')
|
||||
secret_api_key_trimmed=$(echo "$PORKBUN_SECRET_API_KEY" | tr -d '"')
|
||||
|
||||
test -z "$data" && data="{" || data="$(echo $data | cut -d'}' -f1),"
|
||||
data="$data\"apikey\":\"$api_key_trimmed\",\"secretapikey\":\"$secret_api_key_trimmed\"}"
|
||||
|
||||
export _H1="Content-Type: application/json"
|
||||
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$PORKBUN_Api/$ep" "" "$m")"
|
||||
else
|
||||
response="$(_get "$PORKBUN_Api/$ep")"
|
||||
fi
|
||||
|
||||
_sleep 3 # prevent rate limit
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
156
dnsapi/dns_rackcorp.sh
Normal file
156
dnsapi/dns_rackcorp.sh
Normal file
@@ -0,0 +1,156 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Provider: RackCorp (www.rackcorp.com)
|
||||
# Author: Stephen Dendtler (sdendtler@rackcorp.com)
|
||||
# Report Bugs here: https://github.com/senjoo/acme.sh
|
||||
# Alternate email contact: support@rackcorp.com
|
||||
#
|
||||
# You'll need an API key (Portal: ADMINISTRATION -> API)
|
||||
# Set the environment variables as below:
|
||||
#
|
||||
# export RACKCORP_APIUUID="UUIDHERE"
|
||||
# export RACKCORP_APISECRET="SECRETHERE"
|
||||
#
|
||||
|
||||
RACKCORP_API_ENDPOINT="https://api.rackcorp.net/api/rest/v2.4/json.php"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
dns_rackcorp_add() {
|
||||
fulldomain="$1"
|
||||
txtvalue="$2"
|
||||
|
||||
_debug fulldomain="$fulldomain"
|
||||
_debug txtvalue="$txtvalue"
|
||||
|
||||
if ! _rackcorp_validate; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "Searching for root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
return 1
|
||||
fi
|
||||
_debug _lookup "$_lookup"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_info "Creating TXT record."
|
||||
|
||||
if ! _rackcorp_api dns.record.create "\"name\":\"$_domain\",\"type\":\"TXT\",\"lookup\":\"$_lookup\",\"data\":\"$txtvalue\",\"ttl\":300"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#Usage: fulldomain txtvalue
|
||||
#Remove the txt record after validation.
|
||||
dns_rackcorp_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
_debug fulldomain="$fulldomain"
|
||||
_debug txtvalue="$txtvalue"
|
||||
|
||||
if ! _rackcorp_validate; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "Searching for root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
return 1
|
||||
fi
|
||||
_debug _lookup "$_lookup"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_info "Creating TXT record."
|
||||
|
||||
if ! _rackcorp_api dns.record.delete "\"name\":\"$_domain\",\"type\":\"TXT\",\"lookup\":\"$_lookup\",\"data\":\"$txtvalue\""; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#_acme-challenge.domain.com
|
||||
#returns
|
||||
# _lookup=_acme-challenge
|
||||
# _domain=domain.com
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=1
|
||||
p=1
|
||||
if ! _rackcorp_api dns.domain.getall "\"name\":\"$domain\""; then
|
||||
return 1
|
||||
fi
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug searchhost "$h"
|
||||
if [ -z "$h" ]; then
|
||||
_err "Could not find domain for record $domain in RackCorp using the provided credentials"
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
_rackcorp_api dns.domain.getall "\"exactName\":\"$h\""
|
||||
|
||||
if _contains "$response" "\"matches\":1"; then
|
||||
if _contains "$response" "\"name\":\"$h\""; then
|
||||
_lookup=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain="$h"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
_rackcorp_validate() {
|
||||
RACKCORP_APIUUID="${RACKCORP_APIUUID:-$(_readaccountconf_mutable RACKCORP_APIUUID)}"
|
||||
if [ -z "$RACKCORP_APIUUID" ]; then
|
||||
RACKCORP_APIUUID=""
|
||||
_err "You require a RackCorp API UUID (export RACKCORP_APIUUID=\"<api uuid>\")"
|
||||
_err "Please login to the portal and create an API key and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf_mutable RACKCORP_APIUUID "$RACKCORP_APIUUID"
|
||||
|
||||
RACKCORP_APISECRET="${RACKCORP_APISECRET:-$(_readaccountconf_mutable RACKCORP_APISECRET)}"
|
||||
if [ -z "$RACKCORP_APISECRET" ]; then
|
||||
RACKCORP_APISECRET=""
|
||||
_err "You require a RackCorp API secret (export RACKCORP_APISECRET=\"<api secret>\")"
|
||||
_err "Please login to the portal and create an API key and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf_mutable RACKCORP_APISECRET "$RACKCORP_APISECRET"
|
||||
|
||||
return 0
|
||||
}
|
||||
_rackcorp_api() {
|
||||
_rackcorpcmd=$1
|
||||
_rackcorpinputdata=$2
|
||||
_debug cmd "$_rackcorpcmd $_rackcorpinputdata"
|
||||
|
||||
export _H1="Accept: application/json"
|
||||
response="$(_post "{\"APIUUID\":\"$RACKCORP_APIUUID\",\"APISECRET\":\"$RACKCORP_APISECRET\",\"cmd\":\"$_rackcorpcmd\",$_rackcorpinputdata}" "$RACKCORP_API_ENDPOINT" "" "POST")"
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $response"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
if _contains "$response" "\"code\":\"OK\""; then
|
||||
_debug code "OK"
|
||||
else
|
||||
_debug code "FAILED"
|
||||
response=""
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
RACKSPACE_Endpoint="https://dns.api.rackspacecloud.com/v1.0"
|
||||
|
||||
# 20210923 - RS changed the fields in the API response; fix sed
|
||||
# 20190213 - The name & id fields swapped in the API response; fix sed
|
||||
# 20190101 - Duplicating file for new pull request to dev branch
|
||||
# Original - tcocca:rackspace_dnsapi https://github.com/acmesh-official/acme.sh/pull/1297
|
||||
@@ -73,14 +74,14 @@ _get_root_zone() {
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
if ! _rackspace_rest GET "$RACKSPACE_Tenant/domains"; then
|
||||
if ! _rackspace_rest GET "$RACKSPACE_Tenant/domains/search?name=$h"; then
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
|
||||
# Response looks like:
|
||||
# {"ttl":300,"accountId":12345,"id":1111111,"name":"example.com","emailAddress": ...<and so on>
|
||||
_domain_id=$(echo "$response" | sed -n "s/^.*\"id\":\([^,]*\),\"name\":\"$h\",.*/\1/p")
|
||||
# {"id":"12345","accountId":"1111111","name": "example.com","ttl":3600,"emailAddress": ... <and so on>
|
||||
_domain_id=$(echo "$response" | sed -n "s/^.*\"id\":\"\([^,]*\)\",\"accountId\":\"[0-9]*\",\"name\":\"$h\",.*/\1/p")
|
||||
_debug2 domain_id "$_domain_id"
|
||||
if [ -n "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#
|
||||
# REGRU_API_Password="test"
|
||||
#
|
||||
_domain=$_domain
|
||||
|
||||
REGRU_API_URL="https://api.reg.ru/api/regru2"
|
||||
|
||||
@@ -27,10 +26,20 @@ dns_regru_add() {
|
||||
_saveaccountconf_mutable REGRU_API_Username "$REGRU_API_Username"
|
||||
_saveaccountconf_mutable REGRU_API_Password "$REGRU_API_Password"
|
||||
|
||||
_info "Adding TXT record to ${fulldomain}"
|
||||
response="$(_get "$REGRU_API_URL/zone/add_txt?input_data={%22username%22:%22${REGRU_API_Username}%22,%22password%22:%22${REGRU_API_Password}%22,%22domains%22:[{%22dname%22:%22${_domain}%22}],%22subdomain%22:%22_acme-challenge%22,%22text%22:%22${txtvalue}%22,%22output_content_type%22:%22plain%22}&input_format=json")"
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _domain "$_domain"
|
||||
|
||||
if _contains "${response}" 'success'; then
|
||||
_subdomain=$(echo "$fulldomain" | sed -r "s/.$_domain//")
|
||||
_debug _subdomain "$_subdomain"
|
||||
|
||||
_info "Adding TXT record to ${fulldomain}"
|
||||
_regru_rest POST "zone/add_txt" "input_data={%22username%22:%22${REGRU_API_Username}%22,%22password%22:%22${REGRU_API_Password}%22,%22domains%22:[{%22dname%22:%22${_domain}%22}],%22subdomain%22:%22${_subdomain}%22,%22text%22:%22${txtvalue}%22,%22output_content_type%22:%22plain%22}&input_format=json"
|
||||
|
||||
if ! _contains "${response}" 'error'; then
|
||||
return 0
|
||||
fi
|
||||
_err "Could not create resource record, check logs"
|
||||
@@ -51,13 +60,67 @@ dns_regru_rm() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Deleting resource record $fulldomain"
|
||||
response="$(_get "$REGRU_API_URL/zone/remove_record?input_data={%22username%22:%22${REGRU_API_Username}%22,%22password%22:%22${REGRU_API_Password}%22,%22domains%22:[{%22dname%22:%22${_domain}%22}],%22subdomain%22:%22_acme-challenge%22,%22content%22:%22${txtvalue}%22,%22record_type%22:%22TXT%22,%22output_content_type%22:%22plain%22}&input_format=json")"
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _domain "$_domain"
|
||||
|
||||
if _contains "${response}" 'success'; then
|
||||
_subdomain=$(echo "$fulldomain" | sed -r "s/.$_domain//")
|
||||
_debug _subdomain "$_subdomain"
|
||||
|
||||
_info "Deleting resource record $fulldomain"
|
||||
_regru_rest POST "zone/remove_record" "input_data={%22username%22:%22${REGRU_API_Username}%22,%22password%22:%22${REGRU_API_Password}%22,%22domains%22:[{%22dname%22:%22${_domain}%22}],%22subdomain%22:%22${_subdomain}%22,%22content%22:%22${txtvalue}%22,%22record_type%22:%22TXT%22,%22output_content_type%22:%22plain%22}&input_format=json"
|
||||
|
||||
if ! _contains "${response}" 'error'; then
|
||||
return 0
|
||||
fi
|
||||
_err "Could not delete resource record, check logs"
|
||||
_err "${response}"
|
||||
return 1
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _domain=domain.com
|
||||
_get_root() {
|
||||
domain=$1
|
||||
|
||||
_regru_rest POST "service/get_list" "username=${REGRU_API_Username}&password=${REGRU_API_Password}&output_format=xml&servtype=domain"
|
||||
domains_list=$(echo "${response}" | grep dname | sed -r "s/.*dname=\"([^\"]+)\".*/\\1/g")
|
||||
|
||||
for ITEM in ${domains_list}; do
|
||||
case "${domain}" in
|
||||
*${ITEM}*)
|
||||
_domain=${ITEM}
|
||||
_debug _domain "${_domain}"
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
#returns
|
||||
# response
|
||||
_regru_rest() {
|
||||
m=$1
|
||||
ep="$2"
|
||||
data="$3"
|
||||
_debug "$ep"
|
||||
|
||||
export _H1="Content-Type: application/x-www-form-urlencoded"
|
||||
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$REGRU_API_URL/$ep" "" "$m")"
|
||||
else
|
||||
response="$(_get "$REGRU_API_URL/$ep?$data")"
|
||||
fi
|
||||
|
||||
_debug response "${response}"
|
||||
return 0
|
||||
}
|
||||
|
||||
176
dnsapi/dns_scaleway.sh
Executable file
176
dnsapi/dns_scaleway.sh
Executable file
@@ -0,0 +1,176 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Scaleway API
|
||||
# https://developers.scaleway.com/en/products/domain/dns/api/
|
||||
#
|
||||
# Requires Scaleway API token set in SCALEWAY_API_TOKEN
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
SCALEWAY_API="https://api.scaleway.com/domain/v2beta1"
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_scaleway_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
if ! _scaleway_check_config; then
|
||||
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"
|
||||
|
||||
_info "Adding record"
|
||||
_scaleway_create_TXT_record "$_domain" "$_sub_domain" "$txtvalue"
|
||||
if _contains "$response" "records"; then
|
||||
return 0
|
||||
else
|
||||
_err error "$response"
|
||||
return 1
|
||||
fi
|
||||
_info "Record added."
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
dns_scaleway_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
if ! _scaleway_check_config; then
|
||||
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"
|
||||
|
||||
_info "Deleting record"
|
||||
_scaleway_delete_TXT_record "$_domain" "$_sub_domain" "$txtvalue"
|
||||
if _contains "$response" "records"; then
|
||||
return 0
|
||||
else
|
||||
_err error "$response"
|
||||
return 1
|
||||
fi
|
||||
_info "Record deleted."
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
_scaleway_check_config() {
|
||||
SCALEWAY_API_TOKEN="${SCALEWAY_API_TOKEN:-$(_readaccountconf_mutable SCALEWAY_API_TOKEN)}"
|
||||
if [ -z "$SCALEWAY_API_TOKEN" ]; then
|
||||
_err "No API key specified for Scaleway API."
|
||||
_err "Create your key and export it as SCALEWAY_API_TOKEN"
|
||||
return 1
|
||||
fi
|
||||
if ! _scaleway_rest GET "dns-zones"; then
|
||||
_err "Invalid API key specified for Scaleway API."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf_mutable SCALEWAY_API_TOKEN "$SCALEWAY_API_TOKEN"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#_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)
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
_scaleway_rest GET "dns-zones/$h/records"
|
||||
|
||||
if ! _contains "$response" "subdomain not found" >/dev/null; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain="$h"
|
||||
return 0
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
_err "Unable to retrive DNS zone matching this domain"
|
||||
return 1
|
||||
}
|
||||
|
||||
# this function add a TXT record
|
||||
_scaleway_create_TXT_record() {
|
||||
txt_zone=$1
|
||||
txt_name=$2
|
||||
txt_value=$3
|
||||
|
||||
_scaleway_rest PATCH "dns-zones/$txt_zone/records" "{\"return_all_records\":false,\"changes\":[{\"add\":{\"records\":[{\"name\":\"$txt_name\",\"data\":\"$txt_value\",\"type\":\"TXT\",\"ttl\":60}]}}]}"
|
||||
|
||||
if _contains "$response" "records"; then
|
||||
return 0
|
||||
else
|
||||
_err "error1 $response"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# this function delete a TXT record based on name and content
|
||||
_scaleway_delete_TXT_record() {
|
||||
txt_zone=$1
|
||||
txt_name=$2
|
||||
txt_value=$3
|
||||
|
||||
_scaleway_rest PATCH "dns-zones/$txt_zone/records" "{\"return_all_records\":false,\"changes\":[{\"delete\":{\"id_fields\":{\"name\":\"$txt_name\",\"data\":\"$txt_value\",\"type\":\"TXT\"}}}]}"
|
||||
|
||||
if _contains "$response" "records"; then
|
||||
return 0
|
||||
else
|
||||
_err "error2 $response"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
_scaleway_rest() {
|
||||
m=$1
|
||||
ep="$2"
|
||||
data="$3"
|
||||
_debug "$ep"
|
||||
_scaleway_url="$SCALEWAY_API/$ep"
|
||||
_debug2 _scaleway_url "$_scaleway_url"
|
||||
export _H1="x-auth-token: $SCALEWAY_API_TOKEN"
|
||||
export _H2="Accept: application/json"
|
||||
export _H3="Content-Type: application/json"
|
||||
|
||||
if [ "$data" ] || [ "$m" != "GET" ]; then
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$_scaleway_url" "" "$m")"
|
||||
else
|
||||
response="$(_get "$_scaleway_url")"
|
||||
fi
|
||||
if [ "$?" != "0" ] || _contains "$response" "denied_authentication" || _contains "$response" "Method not allowed" || _contains "$response" "json parse error: unexpected EOF"; then
|
||||
_err "error $response"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
@@ -49,16 +49,42 @@ dns_servercow_add() {
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
if _servercow_api POST "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":20}"; then
|
||||
if printf -- "%s" "$response" | grep "ok" >/dev/null; then
|
||||
_info "Added, OK"
|
||||
return 0
|
||||
else
|
||||
_err "add txt record error."
|
||||
return 1
|
||||
# check whether a txt record already exists for the subdomain
|
||||
if printf -- "%s" "$response" | grep "{\"name\":\"$_sub_domain\",\"ttl\":20,\"type\":\"TXT\"" >/dev/null; then
|
||||
_info "A txt record with the same name already exists."
|
||||
# trim the string on the left
|
||||
txtvalue_old=${response#*{\"name\":\"$_sub_domain\",\"ttl\":20,\"type\":\"TXT\",\"content\":\"}
|
||||
# trim the string on the right
|
||||
txtvalue_old=${txtvalue_old%%\"*}
|
||||
|
||||
_debug txtvalue_old "$txtvalue_old"
|
||||
|
||||
_info "Add the new txtvalue to the existing txt record."
|
||||
if _servercow_api POST "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":[\"$txtvalue\",\"$txtvalue_old\"],\"ttl\":20}"; then
|
||||
if printf -- "%s" "$response" | grep "ok" >/dev/null; then
|
||||
_info "Added additional txtvalue, OK"
|
||||
return 0
|
||||
else
|
||||
_err "add txt record error."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
_err "add txt record error."
|
||||
return 1
|
||||
else
|
||||
_info "There is no txt record with the name yet."
|
||||
if _servercow_api POST "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":20}"; then
|
||||
if printf -- "%s" "$response" | grep "ok" >/dev/null; then
|
||||
_info "Added, OK"
|
||||
return 0
|
||||
else
|
||||
_err "add txt record error."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
_err "add txt record error."
|
||||
return 1
|
||||
fi
|
||||
_err "add txt record error."
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
261
dnsapi/dns_simply.sh
Normal file
261
dnsapi/dns_simply.sh
Normal file
@@ -0,0 +1,261 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
#SIMPLY_AccountName="accountname"
|
||||
#
|
||||
#SIMPLY_ApiKey="apikey"
|
||||
#
|
||||
#SIMPLY_Api="https://api.simply.com/1/[ACCOUNTNAME]/[APIKEY]"
|
||||
SIMPLY_Api_Default="https://api.simply.com/1"
|
||||
|
||||
#This is used for determining success of REST call
|
||||
SIMPLY_SUCCESS_CODE='"status": 200'
|
||||
|
||||
######## Public functions #####################
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_simply_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
if ! _simply_load_config; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
_simply_save_config
|
||||
|
||||
_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"
|
||||
|
||||
_info "Adding record"
|
||||
|
||||
if ! _simply_add_record "$_domain" "$_sub_domain" "$txtvalue"; then
|
||||
_err "Could not add DNS record"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
dns_simply_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
if ! _simply_load_config; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
_simply_save_config
|
||||
|
||||
_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 txtvalue "$txtvalue"
|
||||
|
||||
_info "Getting all existing records"
|
||||
|
||||
if ! _simply_get_all_records "$_domain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
records=$(echo "$response" | tr '{' "\n" | grep 'record_id\|type\|data\|\name' | sed 's/\"record_id/;\"record_id/' | tr "\n" ' ' | tr -d ' ' | tr ';' ' ')
|
||||
|
||||
nr_of_deleted_records=0
|
||||
_info "Fetching txt record"
|
||||
|
||||
for record in $records; do
|
||||
_debug record "$record"
|
||||
|
||||
record_data=$(echo "$record" | cut -d "," -f 3 | sed 's/"//g' | grep "data" | cut -d ":" -f 2)
|
||||
record_type=$(echo "$record" | cut -d "," -f 4 | sed 's/"//g' | grep "type" | cut -d ":" -f 2)
|
||||
|
||||
_debug2 record_data "$record_data"
|
||||
_debug2 record_type "$record_type"
|
||||
|
||||
if [ "$record_data" = "$txtvalue" ] && [ "$record_type" = "TXT" ]; then
|
||||
|
||||
record_id=$(echo "$record" | cut -d "," -f 1 | grep "record_id" | cut -d ":" -f 2)
|
||||
|
||||
_info "Deleting record $record"
|
||||
_debug2 record_id "$record_id"
|
||||
|
||||
if [ "$record_id" -gt 0 ]; then
|
||||
|
||||
if ! _simply_delete_record "$_domain" "$_sub_domain" "$record_id"; then
|
||||
_err "Record with id $record_id could not be deleted"
|
||||
return 1
|
||||
fi
|
||||
|
||||
nr_of_deleted_records=1
|
||||
break
|
||||
else
|
||||
_err "Fetching record_id could not be done, this should not happen, exiting function. Failing record is $record"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
if [ "$nr_of_deleted_records" -eq 0 ]; then
|
||||
_err "No record deleted, the DNS record needs to be removed manually."
|
||||
else
|
||||
_info "Deleted $nr_of_deleted_records record"
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
_simply_load_config() {
|
||||
SIMPLY_Api="${SIMPLY_Api:-$(_readaccountconf_mutable SIMPLY_Api)}"
|
||||
SIMPLY_AccountName="${SIMPLY_AccountName:-$(_readaccountconf_mutable SIMPLY_AccountName)}"
|
||||
SIMPLY_ApiKey="${SIMPLY_ApiKey:-$(_readaccountconf_mutable SIMPLY_ApiKey)}"
|
||||
|
||||
if [ -z "$SIMPLY_Api" ]; then
|
||||
SIMPLY_Api="$SIMPLY_Api_Default"
|
||||
fi
|
||||
|
||||
if [ -z "$SIMPLY_AccountName" ] || [ -z "$SIMPLY_ApiKey" ]; then
|
||||
SIMPLY_AccountName=""
|
||||
SIMPLY_ApiKey=""
|
||||
|
||||
_err "A valid Simply API account and apikey not provided."
|
||||
_err "Please provide a valid API user and try again."
|
||||
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
_simply_save_config() {
|
||||
if [ "$SIMPLY_Api" != "$SIMPLY_Api_Default" ]; then
|
||||
_saveaccountconf_mutable SIMPLY_Api "$SIMPLY_Api"
|
||||
fi
|
||||
_saveaccountconf_mutable SIMPLY_AccountName "$SIMPLY_AccountName"
|
||||
_saveaccountconf_mutable SIMPLY_ApiKey "$SIMPLY_ApiKey"
|
||||
}
|
||||
|
||||
_simply_get_all_records() {
|
||||
domain=$1
|
||||
|
||||
if ! _simply_rest GET "my/products/$domain/dns/records"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=2
|
||||
p=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _simply_rest GET "my/products/$h/dns"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _contains "$response" "$SIMPLY_SUCCESS_CODE"; then
|
||||
_debug "$h not found"
|
||||
else
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain="$h"
|
||||
return 0
|
||||
fi
|
||||
p="$i"
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
_simply_add_record() {
|
||||
domain=$1
|
||||
sub_domain=$2
|
||||
txtval=$3
|
||||
|
||||
data="{\"name\": \"$sub_domain\", \"type\":\"TXT\", \"data\": \"$txtval\", \"priority\":0, \"ttl\": 3600}"
|
||||
|
||||
if ! _simply_rest POST "my/products/$domain/dns/records" "$data"; then
|
||||
_err "Adding record not successfull!"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _contains "$response" "$SIMPLY_SUCCESS_CODE"; then
|
||||
_err "Call to API not sucessfull, see below message for more details"
|
||||
_err "$response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
_simply_delete_record() {
|
||||
domain=$1
|
||||
sub_domain=$2
|
||||
record_id=$3
|
||||
|
||||
_debug record_id "Delete record with id $record_id"
|
||||
|
||||
if ! _simply_rest DELETE "my/products/$domain/dns/records/$record_id"; then
|
||||
_err "Deleting record not successfull!"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _contains "$response" "$SIMPLY_SUCCESS_CODE"; then
|
||||
_err "Call to API not sucessfull, see below message for more details"
|
||||
_err "$response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
_simply_rest() {
|
||||
m=$1
|
||||
ep="$2"
|
||||
data="$3"
|
||||
|
||||
_debug2 data "$data"
|
||||
_debug2 ep "$ep"
|
||||
_debug2 m "$m"
|
||||
|
||||
export _H1="Content-Type: application/json"
|
||||
|
||||
if [ "$m" != "GET" ]; then
|
||||
response="$(_post "$data" "$SIMPLY_Api/$SIMPLY_AccountName/$SIMPLY_ApiKey/$ep" "" "$m")"
|
||||
else
|
||||
response="$(_get "$SIMPLY_Api/$SIMPLY_AccountName/$SIMPLY_ApiKey/$ep")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 response "$response"
|
||||
|
||||
if _contains "$response" "Invalid account authorization"; then
|
||||
_err "It seems that your api key or accountnumber is not correct."
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
162
dnsapi/dns_transip.sh
Normal file
162
dnsapi/dns_transip.sh
Normal file
@@ -0,0 +1,162 @@
|
||||
#!/usr/bin/env sh
|
||||
TRANSIP_Api_Url="https://api.transip.nl/v6"
|
||||
TRANSIP_Token_Read_Only="false"
|
||||
TRANSIP_Token_Global_Key="false"
|
||||
TRANSIP_Token_Expiration="30 minutes"
|
||||
# You can't reuse a label token, so we leave this empty normally
|
||||
TRANSIP_Token_Label=""
|
||||
|
||||
######## Public functions #####################
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_transip_add() {
|
||||
fulldomain="$1"
|
||||
_debug fulldomain="$fulldomain"
|
||||
txtvalue="$2"
|
||||
_debug txtvalue="$txtvalue"
|
||||
_transip_setup "$fulldomain" || return 1
|
||||
_info "Creating TXT record."
|
||||
if ! _transip_rest POST "domains/$_domain/dns" "{\"dnsEntry\":{\"name\":\"$_sub_domain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"expire\":300}}"; then
|
||||
_err "Could not add TXT record."
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
dns_transip_rm() {
|
||||
fulldomain=$1
|
||||
_debug fulldomain="$fulldomain"
|
||||
txtvalue=$2
|
||||
_debug txtvalue="$txtvalue"
|
||||
_transip_setup "$fulldomain" || return 1
|
||||
_info "Removing TXT record."
|
||||
if ! _transip_rest DELETE "domains/$_domain/dns" "{\"dnsEntry\":{\"name\":\"$_sub_domain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"expire\":300}}"; then
|
||||
_err "Could not remove TXT record $_sub_domain for $domain"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
_get_root() {
|
||||
domain="$1"
|
||||
i=2
|
||||
p=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain="$h"
|
||||
|
||||
if _transip_rest GET "domains/$h/dns" && _contains "$response" "dnsEntries"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
_err "Unable to parse this domain"
|
||||
return 1
|
||||
}
|
||||
|
||||
_transip_rest() {
|
||||
m="$1"
|
||||
ep="$2"
|
||||
data="$3"
|
||||
_debug ep "$ep"
|
||||
export _H1="Accept: application/json"
|
||||
export _H2="Authorization: Bearer $_token"
|
||||
export _H4="Content-Type: application/json"
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$TRANSIP_Api_Url/$ep" "" "$m")"
|
||||
retcode=$?
|
||||
else
|
||||
response="$(_get "$TRANSIP_Api_Url/$ep")"
|
||||
retcode=$?
|
||||
fi
|
||||
|
||||
if [ "$retcode" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
|
||||
_transip_get_token() {
|
||||
nonce=$(echo "TRANSIP$(_time)" | _digest sha1 hex | cut -c 1-32)
|
||||
_debug nonce "$nonce"
|
||||
|
||||
data="{\"login\":\"${TRANSIP_Username}\",\"nonce\":\"${nonce}\",\"read_only\":\"${TRANSIP_Token_Read_Only}\",\"expiration_time\":\"${TRANSIP_Token_Expiration}\",\"label\":\"${TRANSIP_Token_Label}\",\"global_key\":\"${TRANSIP_Token_Global_Key}\"}"
|
||||
_debug data "$data"
|
||||
|
||||
#_signature=$(printf "%s" "$data" | openssl dgst -sha512 -sign "$TRANSIP_Key_File" | _base64)
|
||||
_signature=$(printf "%s" "$data" | _sign "$TRANSIP_Key_File" "sha512")
|
||||
_debug2 _signature "$_signature"
|
||||
|
||||
export _H1="Signature: $_signature"
|
||||
export _H2="Content-Type: application/json"
|
||||
|
||||
response="$(_post "$data" "$TRANSIP_Api_Url/auth" "" "POST")"
|
||||
retcode=$?
|
||||
_debug2 response "$response"
|
||||
if [ "$retcode" != "0" ]; then
|
||||
_err "Authentication failed."
|
||||
return 1
|
||||
fi
|
||||
if _contains "$response" "token"; then
|
||||
_token="$(echo "$response" | _normalizeJson | sed -n 's/^{"token":"\(.*\)"}/\1/p')"
|
||||
_debug _token "$_token"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
_transip_setup() {
|
||||
fulldomain=$1
|
||||
|
||||
# retrieve the transip creds
|
||||
TRANSIP_Username="${TRANSIP_Username:-$(_readaccountconf_mutable TRANSIP_Username)}"
|
||||
TRANSIP_Key_File="${TRANSIP_Key_File:-$(_readaccountconf_mutable TRANSIP_Key_File)}"
|
||||
# check their vals for null
|
||||
if [ -z "$TRANSIP_Username" ] || [ -z "$TRANSIP_Key_File" ]; then
|
||||
TRANSIP_Username=""
|
||||
TRANSIP_Key_File=""
|
||||
_err "You didn't specify a TransIP username and api key file location"
|
||||
_err "Please set those values and try again."
|
||||
return 1
|
||||
fi
|
||||
# save the username and api key to the account conf file.
|
||||
_saveaccountconf_mutable TRANSIP_Username "$TRANSIP_Username"
|
||||
_saveaccountconf_mutable TRANSIP_Key_File "$TRANSIP_Key_File"
|
||||
|
||||
if [ -f "$TRANSIP_Key_File" ]; then
|
||||
if ! grep "BEGIN PRIVATE KEY" "$TRANSIP_Key_File" >/dev/null 2>&1; then
|
||||
_err "Key file doesn't seem to be a valid key: ${TRANSIP_Key_File}"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_err "Can't read private key file: ${TRANSIP_Key_File}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$_token" ]; then
|
||||
if ! _transip_get_token; then
|
||||
_err "Can not get token."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
_get_root "$fulldomain" || return 1
|
||||
|
||||
return 0
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
#
|
||||
#UNO_User="UExxxxxx"
|
||||
|
||||
Uno_Api="https://api.unoeuro.com/1"
|
||||
Uno_Api="https://api.simply.com/1"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
@@ -24,12 +24,6 @@ dns_unoeuro_add() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _contains "$UNO_User" "UE"; then
|
||||
_err "It seems that the UNO_User=$UNO_User is not a valid username."
|
||||
_err "Please check and retry."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the api key and email to the account conf file.
|
||||
_saveaccountconf_mutable UNO_Key "$UNO_Key"
|
||||
_saveaccountconf_mutable UNO_User "$UNO_User"
|
||||
|
||||
@@ -107,7 +107,7 @@ _get_root() {
|
||||
fi
|
||||
|
||||
if _startswith "$response" "\{\"data\":"; then
|
||||
if _contains "$response" "\"id\": \"$h\""; then
|
||||
if _contains "$response" "\"id\":\"$h\""; then
|
||||
_sub_domain="$(echo "$fulldomain" | sed "s/\\.$h\$//")"
|
||||
_domain=$h
|
||||
return 0
|
||||
|
||||
158
dnsapi/dns_veesp.sh
Normal file
158
dnsapi/dns_veesp.sh
Normal file
@@ -0,0 +1,158 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# bug reports to stepan@plyask.in
|
||||
|
||||
#
|
||||
# export VEESP_User="username"
|
||||
# export VEESP_Password="password"
|
||||
|
||||
VEESP_Api="https://secure.veesp.com/api"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_veesp_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
VEESP_Password="${VEESP_Password:-$(_readaccountconf_mutable VEESP_Password)}"
|
||||
VEESP_User="${VEESP_User:-$(_readaccountconf_mutable VEESP_User)}"
|
||||
VEESP_auth=$(printf "%s" "$VEESP_User:$VEESP_Password" | _base64)
|
||||
|
||||
if [ -z "$VEESP_Password" ] || [ -z "$VEESP_User" ]; then
|
||||
VEESP_Password=""
|
||||
VEESP_User=""
|
||||
_err "You don't specify veesp api key and email yet."
|
||||
_err "Please create you key and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the api key and email to the account conf file.
|
||||
_saveaccountconf_mutable VEESP_Password "$VEESP_Password"
|
||||
_saveaccountconf_mutable VEESP_User "$VEESP_User"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_info "Adding record"
|
||||
if VEESP_rest POST "service/$_service_id/dns/$_domain_id/records" "{\"name\":\"$fulldomain\",\"ttl\":1,\"priority\":0,\"type\":\"TXT\",\"content\":\"$txtvalue\"}"; then
|
||||
if _contains "$response" "\"success\":true"; then
|
||||
_info "Added"
|
||||
#todo: check if the record takes effect
|
||||
return 0
|
||||
else
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Usage: fulldomain txtvalue
|
||||
# Used to remove the txt record after validation
|
||||
dns_veesp_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
VEESP_Password="${VEESP_Password:-$(_readaccountconf_mutable VEESP_Password)}"
|
||||
VEESP_User="${VEESP_User:-$(_readaccountconf_mutable VEESP_User)}"
|
||||
VEESP_auth=$(printf "%s" "$VEESP_User:$VEESP_Password" | _base64)
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_debug "Getting txt records"
|
||||
VEESP_rest GET "service/$_service_id/dns/$_domain_id"
|
||||
|
||||
count=$(printf "%s\n" "$response" | _egrep_o "\"type\":\"TXT\",\"content\":\".\"$txtvalue.\"\"" | wc -l | tr -d " ")
|
||||
_debug count "$count"
|
||||
if [ "$count" = "0" ]; then
|
||||
_info "Don't need to remove."
|
||||
else
|
||||
record_id=$(printf "%s\n" "$response" | _egrep_o "{\"id\":[^}]*\"type\":\"TXT\",\"content\":\".\"$txtvalue.\"\"" | cut -d\" -f4)
|
||||
_debug "record_id" "$record_id"
|
||||
if [ -z "$record_id" ]; then
|
||||
_err "Can not get record id to remove."
|
||||
return 1
|
||||
fi
|
||||
if ! VEESP_rest DELETE "service/$_service_id/dns/$_domain_id/records/$record_id"; then
|
||||
_err "Delete record error."
|
||||
return 1
|
||||
fi
|
||||
_contains "$response" "\"success\":true"
|
||||
fi
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
# _domain_id=sdjkglgdfewsdfg
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=2
|
||||
p=1
|
||||
if ! VEESP_rest GET "dns"; then
|
||||
return 1
|
||||
fi
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "\"name\":\"$h\""; then
|
||||
_domain_id=$(printf "%s\n" "$response" | _egrep_o "\"domain_id\":[^,]*,\"name\":\"$h\"" | cut -d : -f 2 | cut -d , -f 1 | cut -d '"' -f 2)
|
||||
_debug _domain_id "$_domain_id"
|
||||
_service_id=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$h\",\"service_id\":[^}]*" | cut -d : -f 3 | cut -d '"' -f 2)
|
||||
_debug _service_id "$_service_id"
|
||||
if [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain="$h"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
VEESP_rest() {
|
||||
m=$1
|
||||
ep="$2"
|
||||
data="$3"
|
||||
_debug "$ep"
|
||||
|
||||
export _H1="Accept: application/json"
|
||||
export _H2="Authorization: Basic $VEESP_auth"
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug data "$data"
|
||||
export _H3="Content-Type: application/json"
|
||||
response="$(_post "$data" "$VEESP_Api/$ep" "" "$m")"
|
||||
else
|
||||
response="$(_get "$VEESP_Api/$ep")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
@@ -33,7 +33,7 @@ dns_vultr_add() {
|
||||
_debug 'Getting txt records'
|
||||
_vultr_rest GET "dns/records?domain=$_domain"
|
||||
|
||||
if printf "%s\n" "$response" | grep "\"type\":\"TXT\",\"name\":\"$fulldomain\"" >/dev/null; then
|
||||
if printf "%s\n" "$response" | grep -- "\"type\":\"TXT\",\"name\":\"$fulldomain\"" >/dev/null; then
|
||||
_err 'Error'
|
||||
return 1
|
||||
fi
|
||||
@@ -73,12 +73,12 @@ dns_vultr_rm() {
|
||||
_debug 'Getting txt records'
|
||||
_vultr_rest GET "dns/records?domain=$_domain"
|
||||
|
||||
if printf "%s\n" "$response" | grep "\"type\":\"TXT\",\"name\":\"$fulldomain\"" >/dev/null; then
|
||||
if printf "%s\n" "$response" | grep -- "\"type\":\"TXT\",\"name\":\"$fulldomain\"" >/dev/null; then
|
||||
_err 'Error'
|
||||
return 1
|
||||
fi
|
||||
|
||||
_record_id="$(echo "$response" | tr '{}' '\n' | grep '"TXT"' | grep "$txtvalue" | tr ',' '\n' | grep -i 'RECORDID' | cut -d : -f 2)"
|
||||
_record_id="$(echo "$response" | tr '{}' '\n' | grep '"TXT"' | grep -- "$txtvalue" | tr ',' '\n' | grep -i 'RECORDID' | cut -d : -f 2)"
|
||||
_debug _record_id "$_record_id"
|
||||
if [ "$_record_id" ]; then
|
||||
_info "Successfully retrieved the record id for ACME challenge."
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user