mirror of
				https://github.com/acmesh-official/acme.sh
				synced 2025-11-04 13:55:56 +08:00 
			
		
		
		
	Compare commits
	
		
			971 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					fc7f86104e | ||
| 
						 | 
					d057a9bb6d | ||
| 
						 | 
					167aba6f26 | ||
| 
						 | 
					9ecd84080b | ||
| 
						 | 
					22d260f4e6 | ||
| 
						 | 
					ea94477cd4 | ||
| 
						 | 
					522c953860 | ||
| 
						 | 
					f86ee84457 | ||
| 
						 | 
					2d282597ca | ||
| 
						 | 
					8635d89cc8 | ||
| 
						 | 
					dc341ef9c1 | ||
| 
						 | 
					beb31ab2fa | ||
| 
						 | 
					e0214a2c2a | ||
| 
						 | 
					5275daa66c | ||
| 
						 | 
					fb27261568 | ||
| 
						 | 
					5a20ce81e3 | ||
| 
						 | 
					1454b85671 | ||
| 
						 | 
					fc4dba4468 | ||
| 
						 | 
					adff28dade | ||
| 
						 | 
					c345ecae63 | ||
| 
						 | 
					e6461380c6 | ||
| 
						 | 
					deb2a3e415 | ||
| 
						 | 
					c71dcd7611 | ||
| 
						 | 
					c1e05664ed | ||
| 
						 | 
					0f1e5f4fa4 | ||
| 
						 | 
					0fa20da990 | ||
| 
						 | 
					02fb40c507 | ||
| 
						 | 
					dc6ea97877 | ||
| 
						 | 
					031d53b04f | ||
| 
						 | 
					3006c90fb8 | ||
| 
						 | 
					9cec2688ed | ||
| 
						 | 
					65c3dc21f4 | ||
| 
						 | 
					cefa7d940a | ||
| 
						 | 
					fab292d2de | ||
| 
						 | 
					00bbe68f78 | ||
| 
						 | 
					fa3591f4f2 | ||
| 
						 | 
					10cfc6838d | ||
| 
						 | 
					42e78f9a3e | ||
| 
						 | 
					0122eabd44 | ||
| 
						 | 
					435bb3f1d3 | ||
| 
						 | 
					1d59d43286 | ||
| 
						 | 
					fe30bf7d09 | ||
| 
						 | 
					5f68ad4e19 | ||
| 
						 | 
					3fc39aad33 | ||
| 
						 | 
					a94653ba77 | ||
| 
						 | 
					d8637b2c0f | ||
| 
						 | 
					f1b6016157 | ||
| 
						 | 
					de99d6d9fc | ||
| 
						 | 
					bb8386ab85 | ||
| 
						 | 
					ca6226359b | ||
| 
						 | 
					adfafe5c54 | ||
| 
						 | 
					a8d8fefceb | ||
| 
						 | 
					3bb5943b20 | ||
| 
						 | 
					57da04b5ec | ||
| 
						 | 
					e711d168df | ||
| 
						 | 
					1700f064b3 | ||
| 
						 | 
					de902166a8 | ||
| 
						 | 
					2f08bd1965 | ||
| 
						 | 
					13c68cd799 | ||
| 
						 | 
					c7d78f4594 | ||
| 
						 | 
					2f1ca949f0 | ||
| 
						 | 
					a6488ff9ac | ||
| 
						 | 
					cb5eae888d | ||
| 
						 | 
					b6f7710621 | ||
| 
						 | 
					3e36f05a8c | ||
| 
						 | 
					bcb7e5f2c8 | ||
| 
						 | 
					3cefcd8204 | ||
| 
						 | 
					4cd1871816 | ||
| 
						 | 
					7aaa9583fa | ||
| 
						 | 
					dd582c0306 | ||
| 
						 | 
					5cded5b53e | ||
| 
						 | 
					0a64567822 | ||
| 
						 | 
					7ca861805d | ||
| 
						 | 
					6b6faa8129 | ||
| 
						 | 
					f84577bcda | ||
| 
						 | 
					37f9fd3498 | ||
| 
						 | 
					11aef82993 | ||
| 
						 | 
					9861e2d724 | ||
| 
						 | 
					7ae0d0caa3 | ||
| 
						 | 
					93d2c9a3f0 | ||
| 
						 | 
					60569fdd83 | ||
| 
						 | 
					0f61e9c15e | ||
| 
						 | 
					d81fc155cb | ||
| 
						 | 
					60f7750d77 | ||
| 
						 | 
					9bdfd8f4fe | ||
| 
						 | 
					945b7de76f | ||
| 
						 | 
					3c35eadbc4 | ||
| 
						 | 
					ab86e056a2 | ||
| 
						 | 
					a2bc79ddd5 | ||
| 
						 | 
					5789e80d74 | ||
| 
						 | 
					65868ab8a7 | ||
| 
						 | 
					89586530a5 | ||
| 
						 | 
					0d93145834 | ||
| 
						 | 
					fe4113d623 | ||
| 
						 | 
					9a0e15cced | ||
| 
						 | 
					e0c63d58b2 | ||
| 
						 | 
					f7f8ea9b97 | ||
| 
						 | 
					58cad98cd8 | ||
| 
						 | 
					74ffbb2172 | ||
| 
						 | 
					cc9c85cc1a | ||
| 
						 | 
					a8f252e45d | ||
| 
						 | 
					f7e09af5c9 | ||
| 
						 | 
					304cb56337 | ||
| 
						 | 
					6b7b5caf54 | ||
| 
						 | 
					fd461fe015 | ||
| 
						 | 
					2797d2c535 | ||
| 
						 | 
					f440656572 | ||
| 
						 | 
					b1d019146a | ||
| 
						 | 
					1dbc58d4e0 | ||
| 
						 | 
					47ccb28482 | ||
| 
						 | 
					744dea00ca | ||
| 
						 | 
					373c2b379c | ||
| 
						 | 
					957bbab440 | ||
| 
						 | 
					bd48c99383 | ||
| 
						 | 
					52d1d421a3 | ||
| 
						 | 
					c3cc13595d | ||
| 
						 | 
					adc8031e34 | ||
| 
						 | 
					0974c74a89 | ||
| 
						 | 
					c64aae6f39 | ||
| 
						 | 
					b7b1714637 | ||
| 
						 | 
					d8525493a1 | ||
| 
						 | 
					30d0945855 | ||
| 
						 | 
					ffde1f8343 | ||
| 
						 | 
					96c35b41ed | ||
| 
						 | 
					dc2979926f | ||
| 
						 | 
					ff357dd3fb | ||
| 
						 | 
					f35e15204d | ||
| 
						 | 
					3ae4ba3300 | ||
| 
						 | 
					0d8a314bcf | ||
| 
						 | 
					e7cfde1904 | ||
| 
						 | 
					aa41df4e7d | ||
| 
						 | 
					d73953af3d | ||
| 
						 | 
					54eec82311 | ||
| 
						 | 
					dab244ad25 | ||
| 
						 | 
					dbe7cb8dbb | ||
| 
						 | 
					e814cccc44 | ||
| 
						 | 
					1078fdc157 | ||
| 
						 | 
					4bf4259dda | ||
| 
						 | 
					03b53cbb60 | ||
| 
						 | 
					7ef1340e2a | ||
| 
						 | 
					c0b87adee5 | ||
| 
						 | 
					4a8c2251e0 | ||
| 
						 | 
					d1df5f3021 | ||
| 
						 | 
					e1acea52f8 | ||
| 
						 | 
					2e9f159225 | ||
| 
						 | 
					2fcda9a73a | ||
| 
						 | 
					78ba205f4d | ||
| 
						 | 
					f44dec2c8d | ||
| 
						 | 
					8c07af6fc7 | ||
| 
						 | 
					cd01104de9 | ||
| 
						 | 
					28f438a6bd | ||
| 
						 | 
					9ff89b570f | ||
| 
						 | 
					bc90376489 | ||
| 
						 | 
					43b5ea801f | ||
| 
						 | 
					9863e7ea6e | ||
| 
						 | 
					ebaa39b03f | ||
| 
						 | 
					fa3d7ad14b | ||
| 
						 | 
					c51104f956 | ||
| 
						 | 
					84795ff4d9 | ||
| 
						 | 
					cc5c722e29 | ||
| 
						 | 
					4fcddd1893 | ||
| 
						 | 
					c8604255e4 | ||
| 
						 | 
					492826a7f2 | ||
| 
						 | 
					5e64781d65 | ||
| 
						 | 
					2d4b900e33 | ||
| 
						 | 
					d2481f5790 | ||
| 
						 | 
					49f6104f03 | ||
| 
						 | 
					2728d2aa6e | ||
| 
						 | 
					0588fc6b7c | ||
| 
						 | 
					e3cd52cab4 | ||
| 
						 | 
					b2c6b9a320 | ||
| 
						 | 
					39fa40ab12 | ||
| 
						 | 
					0bf87bf4af | ||
| 
						 | 
					92d37f6eaf | ||
| 
						 | 
					d3b022fe17 | ||
| 
						 | 
					79640f6b7d | ||
| 
						 | 
					2cbdf274b1 | ||
| 
						 | 
					6af5293315 | ||
| 
						 | 
					bd3a2b1bb5 | ||
| 
						 | 
					ff090d2f74 | ||
| 
						 | 
					68e3a12a91 | ||
| 
						 | 
					50eda6b678 | ||
| 
						 | 
					192ec598a3 | ||
| 
						 | 
					5b449999a5 | ||
| 
						 | 
					afed62f6de | ||
| 
						 | 
					59d1e16f9c | ||
| 
						 | 
					dbe0d477d6 | ||
| 
						 | 
					7248560169 | ||
| 
						 | 
					f840f7d75b | ||
| 
						 | 
					6e14a073ff | ||
| 
						 | 
					cf3839ecec | ||
| 
						 | 
					aa8cf76fb1 | ||
| 
						 | 
					10b4bb598a | ||
| 
						 | 
					de14d59bb3 | ||
| 
						 | 
					d76272f0ea | ||
| 
						 | 
					e04093efe2 | ||
| 
						 | 
					bd6bbba948 | ||
| 
						 | 
					37e4f35c93 | ||
| 
						 | 
					0084cb7403 | ||
| 
						 | 
					99e5c159a7 | ||
| 
						 | 
					802121d54a | ||
| 
						 | 
					160b2e95c9 | ||
| 
						 | 
					7ec692cdef | ||
| 
						 | 
					3dca67112d | ||
| 
						 | 
					f8dac5905c | ||
| 
						 | 
					48e4e41e05 | ||
| 
						 | 
					22374b81de | ||
| 
						 | 
					b9157e29cb | ||
| 
						 | 
					bd247c35f2 | ||
| 
						 | 
					7da9a45c61 | ||
| 
						 | 
					122dfa12ac | ||
| 
						 | 
					1905830b20 | ||
| 
						 | 
					bfb41ce123 | ||
| 
						 | 
					85e3ecfe0b | ||
| 
						 | 
					9e073c954d | ||
| 
						 | 
					b79c3f5cc4 | ||
| 
						 | 
					ad5acb80fe | ||
| 
						 | 
					7b7c834b08 | ||
| 
						 | 
					42827be7c3 | ||
| 
						 | 
					7022d27b8e | ||
| 
						 | 
					ab911f1ce9 | ||
| 
						 | 
					a6a1de50c8 | ||
| 
						 | 
					97723fbbc9 | ||
| 
						 | 
					2e58cf1168 | ||
| 
						 | 
					3ca97d7258 | ||
| 
						 | 
					9786dccdee | ||
| 
						 | 
					a3612f53dd | ||
| 
						 | 
					112257c49e | ||
| 
						 | 
					d8e2b96bce | ||
| 
						 | 
					6992659ba9 | ||
| 
						 | 
					05696d443a | ||
| 
						 | 
					f59a925897 | ||
| 
						 | 
					afacdfcb95 | ||
| 
						 | 
					8cb1b6b5d5 | ||
| 
						 | 
					f7d9d53ad2 | ||
| 
						 | 
					f4315e2c6f | ||
| 
						 | 
					f0ac566c93 | ||
| 
						 | 
					50f6a459cf | ||
| 
						 | 
					179c80ae6d | ||
| 
						 | 
					6e72f161a6 | ||
| 
						 | 
					f71d8d7348 | ||
| 
						 | 
					a12a3640a7 | ||
| 
						 | 
					3b7bc5a56a | ||
| 
						 | 
					e09d45c844 | ||
| 
						 | 
					36fc321096 | ||
| 
						 | 
					98a7a01dbb | ||
| 
						 | 
					0f7be90500 | ||
| 
						 | 
					7aaf4432d4 | ||
| 
						 | 
					884a8995b4 | ||
| 
						 | 
					bb42595275 | ||
| 
						 | 
					a4bd89c938 | ||
| 
						 | 
					f364d4fbef | ||
| 
						 | 
					f899d0d8ed | ||
| 
						 | 
					074cf00a7c | ||
| 
						 | 
					15d10eeebc | ||
| 
						 | 
					bea71f3411 | ||
| 
						 | 
					eb99803b53 | ||
| 
						 | 
					a60d0c4108 | ||
| 
						 | 
					1cc3a13c49 | ||
| 
						 | 
					feffbba6de | ||
| 
						 | 
					6ea09444ec | ||
| 
						 | 
					f1f486dacf | ||
| 
						 | 
					fec4af3194 | ||
| 
						 | 
					5342c7c82b | ||
| 
						 | 
					8454ffa331 | ||
| 
						 | 
					199977be6a | ||
| 
						 | 
					00dbc3881f | ||
| 
						 | 
					d93a5b2d20 | ||
| 
						 | 
					8ca5ca6594 | ||
| 
						 | 
					fe890c62f4 | ||
| 
						 | 
					e15513bfdd | ||
| 
						 | 
					dbe569c0d9 | ||
| 
						 | 
					f2e1b589b5 | ||
| 
						 | 
					377a37e4c9 | ||
| 
						 | 
					6e163208b4 | ||
| 
						 | 
					87a7bde618 | ||
| 
						 | 
					37b0498699 | ||
| 
						 | 
					59f976dc48 | ||
| 
						 | 
					8565a853a8 | ||
| 
						 | 
					dfd49e46ad | ||
| 
						 | 
					73bbaced62 | ||
| 
						 | 
					0c8870cb7f | ||
| 
						 | 
					1a90f66f73 | ||
| 
						 | 
					558e706bde | ||
| 
						 | 
					1a08be0a3f | ||
| 
						 | 
					29b2960805 | ||
| 
						 | 
					f7f3a0bf0d | ||
| 
						 | 
					ae4c186f55 | ||
| 
						 | 
					af534a73fc | ||
| 
						 | 
					772bbdc862 | ||
| 
						 | 
					86521ec443 | ||
| 
						 | 
					e3c4c9265d | ||
| 
						 | 
					b3f8612e61 | ||
| 
						 | 
					27b1dd04c4 | ||
| 
						 | 
					46a876445f | ||
| 
						 | 
					9bb58e47a7 | ||
| 
						 | 
					b8447fcab8 | ||
| 
						 | 
					3abcfd8fa9 | ||
| 
						 | 
					f4ff2d5d2e | ||
| 
						 | 
					09b41aa667 | ||
| 
						 | 
					87dc4fe388 | ||
| 
						 | 
					eed8a7f078 | ||
| 
						 | 
					c18364c755 | ||
| 
						 | 
					04946e992e | ||
| 
						 | 
					5533782152 | ||
| 
						 | 
					3f42487f0a | ||
| 
						 | 
					8bdcd22486 | ||
| 
						 | 
					b32d22731b | ||
| 
						 | 
					b788cc24d1 | ||
| 
						 | 
					94948f6d34 | ||
| 
						 | 
					e5b76ed4c4 | ||
| 
						 | 
					29a2920a2c | ||
| 
						 | 
					089d35708b | ||
| 
						 | 
					9b0b5bce9f | ||
| 
						 | 
					ef20a0128f | ||
| 
						 | 
					3039e4eb6d | ||
| 
						 | 
					9143cd1485 | ||
| 
						 | 
					13d31ecb7f | ||
| 
						 | 
					a936b2f1f6 | ||
| 
						 | 
					8d00f489cd | ||
| 
						 | 
					b793dbf977 | ||
| 
						 | 
					d52b38777a | ||
| 
						 | 
					56cf93dff2 | ||
| 
						 | 
					67d84cadad | ||
| 
						 | 
					b384a24c0e | ||
| 
						 | 
					66a68edbe6 | ||
| 
						 | 
					dcf3d7234e | ||
| 
						 | 
					0da839cce3 | ||
| 
						 | 
					b6f62ac446 | ||
| 
						 | 
					15ee036db1 | ||
| 
						 | 
					6db8ae451a | ||
| 
						 | 
					a7f3d413ef | ||
| 
						 | 
					3b7be478aa | ||
| 
						 | 
					7f39cdc856 | ||
| 
						 | 
					80006f4730 | ||
| 
						 | 
					a51025fe8f | ||
| 
						 | 
					c42ed9c693 | ||
| 
						 | 
					c48c8d07de | ||
| 
						 | 
					4d4b6edbc2 | ||
| 
						 | 
					2014ca9feb | ||
| 
						 | 
					a9f631f404 | ||
| 
						 | 
					ba468bb5e4 | ||
| 
						 | 
					cf86d57a9f | ||
| 
						 | 
					9e958f4e32 | ||
| 
						 | 
					c7f6f20c9d | ||
| 
						 | 
					1984f44ffe | ||
| 
						 | 
					02de281e40 | ||
| 
						 | 
					ae035deb92 | ||
| 
						 | 
					edd1b60c3d | ||
| 
						 | 
					55a3709bd1 | ||
| 
						 | 
					d1fc01a407 | ||
| 
						 | 
					65293f81d9 | ||
| 
						 | 
					0afb0f7958 | ||
| 
						 | 
					dd958872a8 | ||
| 
						 | 
					62a2ce1d35 | ||
| 
						 | 
					b556908cab | ||
| 
						 | 
					e69a19db5c | ||
| 
						 | 
					d86414febb | ||
| 
						 | 
					832318fab1 | ||
| 
						 | 
					80ad62ff56 | ||
| 
						 | 
					ee50f254df | ||
| 
						 | 
					cc0be6cd90 | ||
| 
						 | 
					a7455d7edd | ||
| 
						 | 
					b7c370fff7 | ||
| 
						 | 
					8fd3a64e35 | ||
| 
						 | 
					3761fb4377 | ||
| 
						 | 
					0472f5da6a | ||
| 
						 | 
					09041fb81d | ||
| 
						 | 
					299a157409 | ||
| 
						 | 
					53ede7b0d8 | ||
| 
						 | 
					cd13aee3e7 | ||
| 
						 | 
					8b3acb719e | ||
| 
						 | 
					2961a90e7f | ||
| 
						 | 
					db8a2d0c65 | ||
| 
						 | 
					a6b5f0c9d4 | ||
| 
						 | 
					8d136c6a25 | ||
| 
						 | 
					4d94270cde | ||
| 
						 | 
					e0d96bcb39 | ||
| 
						 | 
					0d7b831661 | ||
| 
						 | 
					0c9e4f67a8 | ||
| 
						 | 
					da2c386b60 | ||
| 
						 | 
					4770364d42 | ||
| 
						 | 
					db3f131dfc | ||
| 
						 | 
					d7f58c64f8 | ||
| 
						 | 
					41b6aebe7c | ||
| 
						 | 
					7d50332246 | ||
| 
						 | 
					0d0478245f | ||
| 
						 | 
					f680ede980 | ||
| 
						 | 
					b7caf7a016 | ||
| 
						 | 
					891198e4f3 | ||
| 
						 | 
					38c5910be4 | ||
| 
						 | 
					327e2fb0a4 | ||
| 
						 | 
					c20c219990 | ||
| 
						 | 
					4c30250782 | ||
| 
						 | 
					caf23f9a04 | ||
| 
						 | 
					beab808b76 | ||
| 
						 | 
					6c8920f63e | ||
| 
						 | 
					d108072bfb | ||
| 
						 | 
					8cc7c5349a | ||
| 
						 | 
					fb33ea2a0b | ||
| 
						 | 
					63fca33b04 | ||
| 
						 | 
					0548ad2fc6 | ||
| 
						 | 
					623d615cd7 | ||
| 
						 | 
					126df9647b | ||
| 
						 | 
					2e2e7cd054 | ||
| 
						 | 
					0ebc9f7a44 | ||
| 
						 | 
					a8fba65cbd | ||
| 
						 | 
					0b0476e196 | ||
| 
						 | 
					f99d6dac08 | ||
| 
						 | 
					cd2b7cd943 | ||
| 
						 | 
					af759f2330 | ||
| 
						 | 
					51be15f66d | ||
| 
						 | 
					110e25e784 | ||
| 
						 | 
					8414100d0b | ||
| 
						 | 
					a3f4cb154e | ||
| 
						 | 
					e6e22a1ca1 | ||
| 
						 | 
					bb5f3cc326 | ||
| 
						 | 
					7623025b90 | ||
| 
						 | 
					56c98e9295 | ||
| 
						 | 
					b937665b90 | ||
| 
						 | 
					a7bc2293c0 | ||
| 
						 | 
					0d25f7612b | ||
| 
						 | 
					84e4181ed7 | ||
| 
						 | 
					f66a29d1c3 | ||
| 
						 | 
					dbd3881cea | ||
| 
						 | 
					df753e2619 | ||
| 
						 | 
					7eb6bbe65f | ||
| 
						 | 
					a570fda1cb | ||
| 
						 | 
					3b06fa6523 | ||
| 
						 | 
					dcdbe2fbb8 | ||
| 
						 | 
					dc1f36da43 | ||
| 
						 | 
					cbb7082afd | ||
| 
						 | 
					6ee72e119c | ||
| 
						 | 
					05dbd395e6 | ||
| 
						 | 
					69e7360cc3 | ||
| 
						 | 
					7ef2533b98 | ||
| 
						 | 
					97f87c4229 | ||
| 
						 | 
					42a5cd961d | ||
| 
						 | 
					bf00d3157f | ||
| 
						 | 
					cf3ff4c136 | ||
| 
						 | 
					7fe06adcfd | ||
| 
						 | 
					ae3e5dbf2c | ||
| 
						 | 
					20304590b4 | ||
| 
						 | 
					2d8c0c0131 | ||
| 
						 | 
					70f4cad2ca | ||
| 
						 | 
					1f777a94a7 | ||
| 
						 | 
					7560c64f46 | ||
| 
						 | 
					bddde60522 | ||
| 
						 | 
					e9366f8c76 | ||
| 
						 | 
					4dba84d09e | ||
| 
						 | 
					0cce2d6098 | ||
| 
						 | 
					acbd8bce21 | ||
| 
						 | 
					dea8a08b64 | ||
| 
						 | 
					dde1bab1a8 | ||
| 
						 | 
					799e402077 | ||
| 
						 | 
					ce629e8e70 | ||
| 
						 | 
					20cfc4ac66 | ||
| 
						 | 
					132d5e8253 | ||
| 
						 | 
					cb8b341fb4 | ||
| 
						 | 
					982c54b605 | ||
| 
						 | 
					67f543332a | ||
| 
						 | 
					88ac4086c2 | ||
| 
						 | 
					15f96b7239 | ||
| 
						 | 
					0ea84ad799 | ||
| 
						 | 
					1522b713da | ||
| 
						 | 
					fe6b27bb59 | ||
| 
						 | 
					df14b15397 | ||
| 
						 | 
					7dd12044de | ||
| 
						 | 
					06e12a30e7 | ||
| 
						 | 
					d3fefd223d | ||
| 
						 | 
					c0639c6608 | ||
| 
						 | 
					05a2eb3df4 | ||
| 
						 | 
					d4befeb536 | ||
| 
						 | 
					f7f1168aad | ||
| 
						 | 
					d6cf15368a | ||
| 
						 | 
					a5fbf3fb80 | ||
| 
						 | 
					3cf8f78745 | ||
| 
						 | 
					59dab6eac7 | ||
| 
						 | 
					553d861b8a | ||
| 
						 | 
					7b5d94d062 | ||
| 
						 | 
					cb021efaee | ||
| 
						 | 
					c2344f3717 | ||
| 
						 | 
					f537c606f7 | ||
| 
						 | 
					c8f48a4a90 | ||
| 
						 | 
					c2ad1b4e46 | ||
| 
						 | 
					ba9d146d6c | ||
| 
						 | 
					a5b04a0328 | ||
| 
						 | 
					01249d0cb9 | ||
| 
						 | 
					71c273fbcb | ||
| 
						 | 
					aa9cbf7c55 | ||
| 
						 | 
					429b18ed48 | ||
| 
						 | 
					2690c05781 | ||
| 
						 | 
					e3b688c9d8 | ||
| 
						 | 
					41b6f18a5d | ||
| 
						 | 
					5a59c39036 | ||
| 
						 | 
					a02dd18ad7 | ||
| 
						 | 
					16bdc7d0a3 | ||
| 
						 | 
					40002e8040 | ||
| 
						 | 
					6748c55c04 | ||
| 
						 | 
					deb63b4adf | ||
| 
						 | 
					015a9b9271 | ||
| 
						 | 
					ab2305e259 | ||
| 
						 | 
					b99c998057 | ||
| 
						 | 
					6c0a7144f6 | ||
| 
						 | 
					bf50fce5bd | ||
| 
						 | 
					8718b156c4 | ||
| 
						 | 
					7bbdd1f839 | ||
| 
						 | 
					ffed1a4afa | ||
| 
						 | 
					1bfd3642e8 | ||
| 
						 | 
					577f4e0cc3 | ||
| 
						 | 
					e2f05f3fc9 | ||
| 
						 | 
					27f30631ed | ||
| 
						 | 
					1ccfa96c2e | ||
| 
						 | 
					a2c64e79ff | ||
| 
						 | 
					7b623f85cd | ||
| 
						 | 
					ed63eb6833 | ||
| 
						 | 
					b8d0d3c242 | ||
| 
						 | 
					fe1bfe9ae1 | ||
| 
						 | 
					7154c9ee5d | ||
| 
						 | 
					057c95bd1c | ||
| 
						 | 
					0cafc00c4f | ||
| 
						 | 
					75d2898efd | ||
| 
						 | 
					764a4c99fa | ||
| 
						 | 
					160513c671 | ||
| 
						 | 
					a2af26635f | ||
| 
						 | 
					63869deeb2 | ||
| 
						 | 
					91e387e8b9 | ||
| 
						 | 
					7d13146859 | ||
| 
						 | 
					699d2b7e7e | ||
| 
						 | 
					257de15c73 | ||
| 
						 | 
					5a0225d033 | ||
| 
						 | 
					bd2d0e6ad3 | ||
| 
						 | 
					0c0d1d4e52 | ||
| 
						 | 
					eab9603921 | ||
| 
						 | 
					c07db3aa14 | ||
| 
						 | 
					a19f7481b2 | ||
| 
						 | 
					2905edce35 | ||
| 
						 | 
					04a5d794ac | ||
| 
						 | 
					264b9819ff | ||
| 
						 | 
					4610204c83 | ||
| 
						 | 
					ecf1f17cf4 | ||
| 
						 | 
					9f942a6b65 | ||
| 
						 | 
					f4ed1b32b8 | ||
| 
						 | 
					ec0e871592 | ||
| 
						 | 
					7a756ebc4d | ||
| 
						 | 
					16dc21afff | ||
| 
						 | 
					3a1c6d84f0 | ||
| 
						 | 
					e684abdacd | ||
| 
						 | 
					e275cb1efd | ||
| 
						 | 
					60315e5b91 | ||
| 
						 | 
					43b1a4bf5a | ||
| 
						 | 
					cdb238e41c | ||
| 
						 | 
					3871e44d9c | ||
| 
						 | 
					5a51454d13 | ||
| 
						 | 
					d102943a32 | ||
| 
						 | 
					a0b27ddbd8 | ||
| 
						 | 
					b950b04e89 | ||
| 
						 | 
					c9a55f395b | ||
| 
						 | 
					424da01878 | ||
| 
						 | 
					3c933158c8 | ||
| 
						 | 
					7221d488e5 | ||
| 
						 | 
					1c16931e26 | ||
| 
						 | 
					0a4b70dbd2 | ||
| 
						 | 
					666c716bda | ||
| 
						 | 
					be477d7ae3 | ||
| 
						 | 
					6c8a623b88 | ||
| 
						 | 
					ff8de34415 | ||
| 
						 | 
					f8ca6d9833 | ||
| 
						 | 
					dbab519004 | ||
| 
						 | 
					e888c96591 | ||
| 
						 | 
					59519f0493 | ||
| 
						 | 
					e02f07d356 | ||
| 
						 | 
					2c90d220b8 | ||
| 
						 | 
					9feeba8d4b | ||
| 
						 | 
					45090fc897 | ||
| 
						 | 
					d761bdc1b1 | ||
| 
						 | 
					287a8c76b5 | ||
| 
						 | 
					a7dd86de71 | ||
| 
						 | 
					c541a2e5de | ||
| 
						 | 
					41dbf1ddac | ||
| 
						 | 
					70ed6b96d1 | ||
| 
						 | 
					ef26075a1c | ||
| 
						 | 
					91c87446be | ||
| 
						 | 
					dd207e1f02 | ||
| 
						 | 
					e947870da9 | ||
| 
						 | 
					f0b5f592dc | ||
| 
						 | 
					773a2a6cfe | ||
| 
						 | 
					c2a7e384ba | ||
| 
						 | 
					4a8b35ef5f | ||
| 
						 | 
					5cd0db32df | ||
| 
						 | 
					ef01de6149 | ||
| 
						 | 
					4e9749f655 | ||
| 
						 | 
					abb7a1fd47 | ||
| 
						 | 
					60bcee8c1d | ||
| 
						 | 
					8ded524236 | ||
| 
						 | 
					0a47f48191 | ||
| 
						 | 
					8601267b90 | ||
| 
						 | 
					6767e0c52d | ||
| 
						 | 
					5141d1775d | ||
| 
						 | 
					374af996d9 | ||
| 
						 | 
					dcc9624c15 | ||
| 
						 | 
					b3df1a2bf8 | ||
| 
						 | 
					3fc3c02a4f | ||
| 
						 | 
					874ddf9a32 | ||
| 
						 | 
					69aeb70cc3 | ||
| 
						 | 
					47e60cefe3 | ||
| 
						 | 
					4ea7f3cda5 | ||
| 
						 | 
					03288b521a | ||
| 
						 | 
					4b0a7a6e1f | ||
| 
						 | 
					383287adcd | ||
| 
						 | 
					5c00afc6fe | ||
| 
						 | 
					025e0e8093 | ||
| 
						 | 
					35fb1f8585 | ||
| 
						 | 
					9fb14eef0e | ||
| 
						 | 
					5d6d0c6176 | ||
| 
						 | 
					dd707242ef | ||
| 
						 | 
					4f32f1285a | ||
| 
						 | 
					a6ecdbae29 | ||
| 
						 | 
					4904d100ff | ||
| 
						 | 
					7a1f94bc20 | ||
| 
						 | 
					f9320fff8f | ||
| 
						 | 
					3dde83d8a0 | ||
| 
						 | 
					f3e77a989c | ||
| 
						 | 
					f3539b0354 | ||
| 
						 | 
					4e5d4b9695 | ||
| 
						 | 
					864315f6d1 | ||
| 
						 | 
					713b7338ea | ||
| 
						 | 
					53117b2f4c | ||
| 
						 | 
					90623142e1 | ||
| 
						 | 
					43503a20e5 | ||
| 
						 | 
					ec53b27dfe | ||
| 
						 | 
					238ecfc539 | ||
| 
						 | 
					b888792940 | ||
| 
						 | 
					e3d1ab52f8 | ||
| 
						 | 
					f9c2874c35 | ||
| 
						 | 
					2304f005e3 | ||
| 
						 | 
					b95f836256 | ||
| 
						 | 
					c94f9f21af | ||
| 
						 | 
					fc336e3733 | ||
| 
						 | 
					fc1df9f9a5 | ||
| 
						 | 
					5a604bfdee | ||
| 
						 | 
					281951a86b | ||
| 
						 | 
					35ec3adadc | ||
| 
						 | 
					b9256a1ba7 | ||
| 
						 | 
					734c9a1aa5 | ||
| 
						 | 
					6502a71083 | ||
| 
						 | 
					f2634b44cd | ||
| 
						 | 
					dcf9c467c3 | ||
| 
						 | 
					3dcacc1f8d | ||
| 
						 | 
					7cb81b0f35 | ||
| 
						 | 
					8155ba5224 | ||
| 
						 | 
					7169060425 | ||
| 
						 | 
					ddb9dd4e45 | ||
| 
						 | 
					2a05f24cb6 | ||
| 
						 | 
					039e4c662d | ||
| 
						 | 
					70351677a1 | ||
| 
						 | 
					33cadfb97d | ||
| 
						 | 
					5fbaeda217 | ||
| 
						 | 
					b44ba0d21a | ||
| 
						 | 
					b42532afe9 | ||
| 
						 | 
					da6a335b87 | ||
| 
						 | 
					0e8fef73bb | ||
| 
						 | 
					7122a960fa | ||
| 
						 | 
					d5b649a1a4 | ||
| 
						 | 
					233c724b2d | ||
| 
						 | 
					e1eb001872 | ||
| 
						 | 
					5899d7034f | ||
| 
						 | 
					23c3e9482f | ||
| 
						 | 
					dd980d9dca | ||
| 
						 | 
					d4ed50a915 | ||
| 
						 | 
					d986c7d126 | ||
| 
						 | 
					67a2a4f249 | ||
| 
						 | 
					a6e87e7e08 | ||
| 
						 | 
					33da8a7f62 | ||
| 
						 | 
					68c533f777 | ||
| 
						 | 
					671eecf203 | ||
| 
						 | 
					2454ac8ef1 | ||
| 
						 | 
					20f097faa4 | ||
| 
						 | 
					5dba8b493d | ||
| 
						 | 
					eb27013fba | ||
| 
						 | 
					4f8d1c5c9d | ||
| 
						 | 
					74168c3e05 | ||
| 
						 | 
					cece848801 | ||
| 
						 | 
					7ddbeaa078 | ||
| 
						 | 
					2d4aa7ff8b | ||
| 
						 | 
					79e044ac31 | ||
| 
						 | 
					15ae5a5135 | ||
| 
						 | 
					5684b7c329 | ||
| 
						 | 
					7e96120353 | ||
| 
						 | 
					cc36421fe5 | ||
| 
						 | 
					683aa727d5 | ||
| 
						 | 
					ea07b495ac | ||
| 
						 | 
					8d211c3524 | ||
| 
						 | 
					ab8df82563 | ||
| 
						 | 
					8ba9c4ab97 | ||
| 
						 | 
					2f70b8682e | ||
| 
						 | 
					86dd4ea480 | ||
| 
						 | 
					204e5f4418 | ||
| 
						 | 
					044a9bb6d3 | ||
| 
						 | 
					a31143328e | ||
| 
						 | 
					2bb29a105c | ||
| 
						 | 
					0013d98d04 | ||
| 
						 | 
					916743f44b | ||
| 
						 | 
					edebe65d95 | ||
| 
						 | 
					c43fcd0af6 | ||
| 
						 | 
					9a5c2b88dc | ||
| 
						 | 
					aaee0414c8 | ||
| 
						 | 
					d0c2fb9761 | ||
| 
						 | 
					4f076c6924 | ||
| 
						 | 
					51d4d1451a | ||
| 
						 | 
					7b9d76dc65 | ||
| 
						 | 
					f91aeea91c | ||
| 
						 | 
					4cabf84be9 | ||
| 
						 | 
					8a1f038a80 | ||
| 
						 | 
					c9cab9ab74 | ||
| 
						 | 
					bd78120bd5 | ||
| 
						 | 
					0de3bf0ac7 | ||
| 
						 | 
					2d144a8b43 | ||
| 
						 | 
					1a140a5515 | ||
| 
						 | 
					1ea8cfbfb0 | ||
| 
						 | 
					64fda95186 | ||
| 
						 | 
					7843c0c1b0 | ||
| 
						 | 
					a3784854a7 | ||
| 
						 | 
					8b7c000f47 | ||
| 
						 | 
					5b8d7a3f29 | ||
| 
						 | 
					328dbd57d4 | ||
| 
						 | 
					a8c448f4cb | ||
| 
						 | 
					de0419228f | ||
| 
						 | 
					d8a4e47a13 | ||
| 
						 | 
					bc920949cb | ||
| 
						 | 
					0717f8591c | ||
| 
						 | 
					affb65219e | ||
| 
						 | 
					3e628f2678 | ||
| 
						 | 
					ddabc38e3f | ||
| 
						 | 
					c0097497be | ||
| 
						 | 
					78198bfdaf | ||
| 
						 | 
					2fb9c923f4 | ||
| 
						 | 
					c485011ed1 | ||
| 
						 | 
					0b8ae68213 | ||
| 
						 | 
					0e73128f40 | ||
| 
						 | 
					927c003d22 | ||
| 
						 | 
					bd73823828 | ||
| 
						 | 
					11582bc7d3 | ||
| 
						 | 
					20ed4f96ba | ||
| 
						 | 
					19790e9011 | ||
| 
						 | 
					3a29e03458 | ||
| 
						 | 
					e2eb685d76 | ||
| 
						 | 
					86cb28fe34 | ||
| 
						 | 
					bcc9679339 | ||
| 
						 | 
					e5aeff50dc | ||
| 
						 | 
					5f44c195e9 | ||
| 
						 | 
					e4387e4aad | ||
| 
						 | 
					b1b336804d | ||
| 
						 | 
					9985c43817 | ||
| 
						 | 
					190cac394c | ||
| 
						 | 
					ae71a5abf6 | ||
| 
						 | 
					df199c5788 | ||
| 
						 | 
					c1ba4f1b55 | ||
| 
						 | 
					afc0097b12 | ||
| 
						 | 
					4e9f971c91 | ||
| 
						 | 
					b1cc28bbda | ||
| 
						 | 
					80d30bdd30 | ||
| 
						 | 
					f27566669b | ||
| 
						 | 
					29f12ddaf4 | ||
| 
						 | 
					ed15ff0515 | ||
| 
						 | 
					a8f71f79fe | ||
| 
						 | 
					68c2478e0e | ||
| 
						 | 
					be07fe9e9f | ||
| 
						 | 
					4d8b661d51 | ||
| 
						 | 
					ca0981645f | ||
| 
						 | 
					bc7e02b47a | ||
| 
						 | 
					55a55e9f74 | ||
| 
						 | 
					b41d40da40 | ||
| 
						 | 
					ba3e088b23 | ||
| 
						 | 
					1b59b0b739 | ||
| 
						 | 
					093cfcdf42 | ||
| 
						 | 
					41801a60ad | ||
| 
						 | 
					5ff0957861 | ||
| 
						 | 
					6913b8beb5 | ||
| 
						 | 
					c8d17bc363 | ||
| 
						 | 
					2cbf1259a8 | ||
| 
						 | 
					59dc513ac3 | ||
| 
						 | 
					87b110bb86 | ||
| 
						 | 
					1b3e1a7abe | ||
| 
						 | 
					0afabc60ae | ||
| 
						 | 
					2d4ea720eb | ||
| 
						 | 
					9c757bbe6e | ||
| 
						 | 
					40e0d72105 | ||
| 
						 | 
					eba788e8c9 | ||
| 
						 | 
					444b111a62 | ||
| 
						 | 
					a364ab4ea7 | ||
| 
						 | 
					be7840c827 | ||
| 
						 | 
					a46e51e8db | ||
| 
						 | 
					789ebb8990 | ||
| 
						 | 
					e3cd96bf19 | ||
| 
						 | 
					7746042adc | ||
| 
						 | 
					dfe80556d3 | ||
| 
						 | 
					b3529dc748 | ||
| 
						 | 
					543c4423a2 | ||
| 
						 | 
					3bd4d32b8d | ||
| 
						 | 
					56a686d3e0 | ||
| 
						 | 
					2f97c789dd | ||
| 
						 | 
					04ca808e80 | ||
| 
						 | 
					9b79743c5d | ||
| 
						 | 
					a386826808 | ||
| 
						 | 
					668894fc4d | ||
| 
						 | 
					dc882e6279 | ||
| 
						 | 
					d6eebf82be | ||
| 
						 | 
					799f509ba9 | ||
| 
						 | 
					688a234127 | ||
| 
						 | 
					095697900b | ||
| 
						 | 
					6ccf617d62 | ||
| 
						 | 
					b3b4811b2c | ||
| 
						 | 
					966e4246e5 | ||
| 
						 | 
					9377c4f3ad | ||
| 
						 | 
					b876128635 | ||
| 
						 | 
					c0da801580 | ||
| 
						 | 
					149310e1ec | ||
| 
						 | 
					4e625c18dc | ||
| 
						 | 
					a5d5113be3 | ||
| 
						 | 
					7900c493af | ||
| 
						 | 
					76fe5d8831 | ||
| 
						 | 
					37031721dd | ||
| 
						 | 
					3cc283cbee | ||
| 
						 | 
					35cf98fff2 | ||
| 
						 | 
					ca41ea2d5c | ||
| 
						 | 
					daffc4e6a4 | ||
| 
						 | 
					5f3cb9019b | ||
| 
						 | 
					13c7182948 | ||
| 
						 | 
					4951b58b21 | ||
| 
						 | 
					7be7586971 | ||
| 
						 | 
					edc76795d4 | ||
| 
						 | 
					6d64098288 | ||
| 
						 | 
					4351110082 | ||
| 
						 | 
					6652138d3e | ||
| 
						 | 
					c8d0d475e4 | ||
| 
						 | 
					39b25029fc | ||
| 
						 | 
					b5cabd6d8e | ||
| 
						 | 
					b169a5c707 | ||
| 
						 | 
					4f816c06b0 | ||
| 
						 | 
					b5f49d9563 | ||
| 
						 | 
					274fd5ab8b | ||
| 
						 | 
					e48d7de763 | ||
| 
						 | 
					f426940bd2 | ||
| 
						 | 
					6c11dd12d7 | ||
| 
						 | 
					c2b14d3075 | ||
| 
						 | 
					8a144ebfee | ||
| 
						 | 
					5440fcdf54 | ||
| 
						 | 
					66b2d496af | ||
| 
						 | 
					444a0282d7 | ||
| 
						 | 
					f897ab4eb8 | ||
| 
						 | 
					993c187e37 | ||
| 
						 | 
					3ce67b282f | ||
| 
						 | 
					606e59a5d0 | ||
| 
						 | 
					0f26b1eafb | ||
| 
						 | 
					d2a9d731ed | ||
| 
						 | 
					80e6b1fc01 | ||
| 
						 | 
					58a89edad7 | ||
| 
						 | 
					bfe47eb152 | ||
| 
						 | 
					32adc38e94 | ||
| 
						 | 
					1584971908 | ||
| 
						 | 
					025bebb3e2 | ||
| 
						 | 
					4047adcc35 | ||
| 
						 | 
					d4cf03c9fd | ||
| 
						 | 
					5ba2068fc2 | ||
| 
						 | 
					3ce7d410c8 | ||
| 
						 | 
					74f28021e7 | ||
| 
						 | 
					f90cbb636a | ||
| 
						 | 
					c8929ca0cb | ||
| 
						 | 
					9fb5bb620d | ||
| 
						 | 
					ed58f32052 | ||
| 
						 | 
					6d5743c506 | ||
| 
						 | 
					a551619de6 | ||
| 
						 | 
					873b113cb3 | ||
| 
						 | 
					2280e66d73 | ||
| 
						 | 
					2133897bbe | ||
| 
						 | 
					bee5cb55a1 | ||
| 
						 | 
					0a0838b616 | ||
| 
						 | 
					b376dfa1e6 | ||
| 
						 | 
					7ac0577b34 | ||
| 
						 | 
					f16e060e87 | ||
| 
						 | 
					9aaae24583 | ||
| 
						 | 
					915ced7b92 | ||
| 
						 | 
					5a36b9075f | ||
| 
						 | 
					b5a7f46ecc | ||
| 
						 | 
					4381657c5e | ||
| 
						 | 
					d440b2f2b2 | ||
| 
						 | 
					5b42aea9e7 | ||
| 
						 | 
					e1d7a6b9ac | ||
| 
						 | 
					38778f8adc | ||
| 
						 | 
					8b7a86bd17 | ||
| 
						 | 
					619bae745b | ||
| 
						 | 
					2cf72bad30 | ||
| 
						 | 
					c4df8090e2 | ||
| 
						 | 
					fe3523f47a | ||
| 
						 | 
					199d846acb | ||
| 
						 | 
					b07e479840 | ||
| 
						 | 
					9bf37fde02 | ||
| 
						 | 
					1054325b2d | ||
| 
						 | 
					ef8cb11707 | ||
| 
						 | 
					c23c40df8a | ||
| 
						 | 
					77d606df34 | ||
| 
						 | 
					e717c9dba2 | ||
| 
						 | 
					3d312e2140 | ||
| 
						 | 
					18de21f723 | ||
| 
						 | 
					6aebaf6f47 | ||
| 
						 | 
					a092a2fa43 | ||
| 
						 | 
					227eac10f1 | ||
| 
						 | 
					1cbd5485e7 | ||
| 
						 | 
					610c3cf681 | ||
| 
						 | 
					96d45cc341 | ||
| 
						 | 
					d6c68f1a84 | ||
| 
						 | 
					6d2ab4d270 | ||
| 
						 | 
					a6b58bc88d | ||
| 
						 | 
					ea3c37d754 | ||
| 
						 | 
					b37bf06de8 | ||
| 
						 | 
					27bbf0ccaf | ||
| 
						 | 
					ed56d52af3 | ||
| 
						 | 
					fb457968ec | ||
| 
						 | 
					0bea2e2b94 | ||
| 
						 | 
					72d02f442e | ||
| 
						 | 
					bcf63b5d27 | ||
| 
						 | 
					ac0dd90c37 | ||
| 
						 | 
					9470850258 | ||
| 
						 | 
					2982e9943e | ||
| 
						 | 
					80e13bc24a | ||
| 
						 | 
					62dad721fc | ||
| 
						 | 
					cc5cfc7525 | ||
| 
						 | 
					795dee85ef | ||
| 
						 | 
					dbd5bef038 | ||
| 
						 | 
					dd2a420578 | ||
| 
						 | 
					eeee30ca03 | ||
| 
						 | 
					82e8792737 | ||
| 
						 | 
					6b18b3df34 | ||
| 
						 | 
					fcebed19b9 | ||
| 
						 | 
					af5f6176b5 | ||
| 
						 | 
					424cc46db0 | ||
| 
						 | 
					ce47ccecc4 | ||
| 
						 | 
					d940f17390 | ||
| 
						 | 
					6351b5d0dc | ||
| 
						 | 
					9c4ac24a66 | ||
| 
						 | 
					bf66df2a29 | ||
| 
						 | 
					962ce380cd | ||
| 
						 | 
					9769afb944 | ||
| 
						 | 
					052b45a510 | ||
| 
						 | 
					84a96e862e | ||
| 
						 | 
					3105235a7a | ||
| 
						 | 
					71a32477e4 | ||
| 
						 | 
					342bce2168 | ||
| 
						 | 
					86d8cbc4d2 | ||
| 
						 | 
					6b63bd6a44 | ||
| 
						 | 
					225707c877 | ||
| 
						 | 
					66da6f18e3 | ||
| 
						 | 
					bdf8bf391c | ||
| 
						 | 
					f66d9e1a22 | ||
| 
						 | 
					ccd3d96942 | ||
| 
						 | 
					00b6c6a437 | ||
| 
						 | 
					21ef3b0ecf | ||
| 
						 | 
					08d60fcbf2 | ||
| 
						 | 
					4cda54774a | ||
| 
						 | 
					613475ac26 | ||
| 
						 | 
					20d23fcb92 | ||
| 
						 | 
					92dbe6cdf8 | ||
| 
						 | 
					0781e8cf12 | ||
| 
						 | 
					b71a088da7 | ||
| 
						 | 
					d76fb566a2 | ||
| 
						 | 
					24a40af103 | ||
| 
						 | 
					4a60292f82 | ||
| 
						 | 
					7eea866869 | ||
| 
						 | 
					4ab5456a98 | ||
| 
						 | 
					8881a9f40e | 
							
								
								
									
										769
									
								
								.github/workflows/DNS.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										769
									
								
								.github/workflows/DNS.yml
									
									
									
									
										vendored
									
									
								
							@@ -1,254 +1,515 @@
 | 
			
		||||
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.repository_owner}}" != "acmesh-official" ]; 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_NO_SUBDOMAIN: ${{ secrets.TEST_DNS_NO_SUBDOMAIN }}
 | 
			
		||||
      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_NO_SUBDOMAIN: ${{ secrets.TEST_DNS_NO_SUBDOMAIN }}
 | 
			
		||||
      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_NO_SUBDOMAIN: ${{ secrets.TEST_DNS_NO_SUBDOMAIN }}
 | 
			
		||||
      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-10.15
 | 
			
		||||
    needs: Windows
 | 
			
		||||
    env:
 | 
			
		||||
      TEST_DNS : ${{ secrets.TEST_DNS }}
 | 
			
		||||
      TestingDomain: ${{ secrets.TestingDomain }}
 | 
			
		||||
      TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
 | 
			
		||||
      TEST_DNS_NO_SUBDOMAIN: ${{ secrets.TEST_DNS_NO_SUBDOMAIN }}
 | 
			
		||||
      TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
 | 
			
		||||
      CASE: le_test_dnsapi
 | 
			
		||||
      TEST_LOCAL: 1
 | 
			
		||||
      DEBUG: 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_NO_SUBDOMAIN 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-10.15
 | 
			
		||||
    needs: FreeBSD
 | 
			
		||||
    env:
 | 
			
		||||
      TEST_DNS : ${{ secrets.TEST_DNS }}
 | 
			
		||||
      TestingDomain: ${{ secrets.TestingDomain }}
 | 
			
		||||
      TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
 | 
			
		||||
      TEST_DNS_NO_SUBDOMAIN: ${{ secrets.TEST_DNS_NO_SUBDOMAIN }}
 | 
			
		||||
      TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
 | 
			
		||||
      CASE: le_test_dnsapi
 | 
			
		||||
      TEST_LOCAL: 1
 | 
			
		||||
      DEBUG: 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.5
 | 
			
		||||
      with:
 | 
			
		||||
        envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
 | 
			
		||||
        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
 | 
			
		||||
name: DNS
 | 
			
		||||
on:
 | 
			
		||||
  workflow_dispatch:
 | 
			
		||||
  push:
 | 
			
		||||
    paths:
 | 
			
		||||
      - 'dnsapi/*.sh'
 | 
			
		||||
      - '.github/workflows/DNS.yml'
 | 
			
		||||
  pull_request:
 | 
			
		||||
    branches:
 | 
			
		||||
      - 'dev'
 | 
			
		||||
    paths:
 | 
			
		||||
      - 'dnsapi/*.sh'
 | 
			
		||||
      - '.github/workflows/DNS.yml'
 | 
			
		||||
 | 
			
		||||
concurrency: 
 | 
			
		||||
  group: ${{ github.workflow }}-${{ github.ref }}
 | 
			
		||||
  cancel-in-progress: true
 | 
			
		||||
 | 
			
		||||
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.repository_owner}}" != "acmesh-official" ]; 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_NO_SUBDOMAIN: ${{ secrets.TEST_DNS_NO_SUBDOMAIN }}
 | 
			
		||||
      TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
 | 
			
		||||
      CASE: le_test_dnsapi
 | 
			
		||||
      TEST_LOCAL: 1
 | 
			
		||||
      DEBUG: ${{ secrets.DEBUG }}
 | 
			
		||||
      http_proxy: ${{ secrets.http_proxy }}
 | 
			
		||||
      https_proxy: ${{ secrets.https_proxy }}
 | 
			
		||||
      TokenName1: ${{ secrets.TokenName1}}
 | 
			
		||||
      TokenName2: ${{ secrets.TokenName2}}
 | 
			
		||||
      TokenName3: ${{ secrets.TokenName3}}
 | 
			
		||||
      TokenName4: ${{ secrets.TokenName4}}
 | 
			
		||||
      TokenName5: ${{ secrets.TokenName5}}
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
    - name: Clone acmetest
 | 
			
		||||
      run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git  && cp -r acme.sh acmetest/
 | 
			
		||||
    - name: Set env file
 | 
			
		||||
      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
 | 
			
		||||
 | 
			
		||||
    - 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_NO_SUBDOMAIN: ${{ secrets.TEST_DNS_NO_SUBDOMAIN }}
 | 
			
		||||
      TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
 | 
			
		||||
      CASE: le_test_dnsapi
 | 
			
		||||
      TEST_LOCAL: 1
 | 
			
		||||
      DEBUG: ${{ secrets.DEBUG }}
 | 
			
		||||
      http_proxy: ${{ secrets.http_proxy }}
 | 
			
		||||
      https_proxy: ${{ secrets.https_proxy }}
 | 
			
		||||
      TokenName1: ${{ secrets.TokenName1}}
 | 
			
		||||
      TokenName2: ${{ secrets.TokenName2}}
 | 
			
		||||
      TokenName3: ${{ secrets.TokenName3}}
 | 
			
		||||
      TokenName4: ${{ secrets.TokenName4}}
 | 
			
		||||
      TokenName5: ${{ secrets.TokenName5}}
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
    - name: Install tools
 | 
			
		||||
      run:  brew install socat
 | 
			
		||||
    - name: Clone acmetest
 | 
			
		||||
      run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git  && cp -r acme.sh acmetest/
 | 
			
		||||
    - name: Run acmetest
 | 
			
		||||
      run: |
 | 
			
		||||
        if [ "${{ secrets.TokenName1}}" ] ; then
 | 
			
		||||
          export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}"
 | 
			
		||||
        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_NO_SUBDOMAIN: ${{ secrets.TEST_DNS_NO_SUBDOMAIN }}
 | 
			
		||||
      TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
 | 
			
		||||
      CASE: le_test_dnsapi
 | 
			
		||||
      TEST_LOCAL: 1
 | 
			
		||||
      DEBUG: ${{ secrets.DEBUG }}
 | 
			
		||||
      http_proxy: ${{ secrets.http_proxy }}
 | 
			
		||||
      https_proxy: ${{ secrets.https_proxy }}
 | 
			
		||||
      TokenName1: ${{ secrets.TokenName1}}
 | 
			
		||||
      TokenName2: ${{ secrets.TokenName2}}
 | 
			
		||||
      TokenName3: ${{ secrets.TokenName3}}
 | 
			
		||||
      TokenName4: ${{ secrets.TokenName4}}
 | 
			
		||||
      TokenName5: ${{ secrets.TokenName5}}
 | 
			
		||||
    steps:
 | 
			
		||||
    - name: Set git to use LF
 | 
			
		||||
      run: |
 | 
			
		||||
          git config --global core.autocrlf false
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
    - 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 https://mirrors.kernel.org/sourceware/cygwin/ -P socat,curl,cron,unzip,git
 | 
			
		||||
      shell: cmd
 | 
			
		||||
    - name: Set ENV
 | 
			
		||||
      shell: cmd
 | 
			
		||||
      run: |
 | 
			
		||||
          echo PATH=C:\tools\cygwin\bin;C:\tools\cygwin\usr\bin >> %GITHUB_ENV%
 | 
			
		||||
    - name: Clone acmetest
 | 
			
		||||
      run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git  && cp -r acme.sh acmetest/
 | 
			
		||||
    - name: Run acmetest
 | 
			
		||||
      shell: bash
 | 
			
		||||
      run: |
 | 
			
		||||
        if [ "${{ secrets.TokenName1}}" ] ; then
 | 
			
		||||
          export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}"
 | 
			
		||||
        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: ubuntu-latest
 | 
			
		||||
    needs: Windows
 | 
			
		||||
    env:
 | 
			
		||||
      TEST_DNS : ${{ secrets.TEST_DNS }}
 | 
			
		||||
      TestingDomain: ${{ secrets.TestingDomain }}
 | 
			
		||||
      TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
 | 
			
		||||
      TEST_DNS_NO_SUBDOMAIN: ${{ secrets.TEST_DNS_NO_SUBDOMAIN }}
 | 
			
		||||
      TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
 | 
			
		||||
      CASE: le_test_dnsapi
 | 
			
		||||
      TEST_LOCAL: 1
 | 
			
		||||
      DEBUG: ${{ secrets.DEBUG }}
 | 
			
		||||
      http_proxy: ${{ secrets.http_proxy }}
 | 
			
		||||
      https_proxy: ${{ secrets.https_proxy }}
 | 
			
		||||
      TokenName1: ${{ secrets.TokenName1}}
 | 
			
		||||
      TokenName2: ${{ secrets.TokenName2}}
 | 
			
		||||
      TokenName3: ${{ secrets.TokenName3}}
 | 
			
		||||
      TokenName4: ${{ secrets.TokenName4}}
 | 
			
		||||
      TokenName5: ${{ secrets.TokenName5}}
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
    - name: Clone acmetest
 | 
			
		||||
      run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git  && cp -r acme.sh acmetest/
 | 
			
		||||
    - uses: vmactions/freebsd-vm@v1
 | 
			
		||||
      with:
 | 
			
		||||
        envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
 | 
			
		||||
        prepare: pkg install -y socat curl
 | 
			
		||||
        usesh: true
 | 
			
		||||
        copyback: false
 | 
			
		||||
        run: |
 | 
			
		||||
          if [ "${{ secrets.TokenName1}}" ] ; then
 | 
			
		||||
            export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}"
 | 
			
		||||
          fi
 | 
			
		||||
          if [ "${{ secrets.TokenName2}}" ] ; then
 | 
			
		||||
            export ${{ secrets.TokenName2}}="${{ secrets.TokenValue2}}"
 | 
			
		||||
          fi
 | 
			
		||||
          if [ "${{ secrets.TokenName3}}" ] ; then
 | 
			
		||||
            export ${{ secrets.TokenName3}}="${{ secrets.TokenValue3}}"
 | 
			
		||||
          fi
 | 
			
		||||
          if [ "${{ secrets.TokenName4}}" ] ; then
 | 
			
		||||
            export ${{ secrets.TokenName4}}="${{ secrets.TokenValue4}}"
 | 
			
		||||
          fi
 | 
			
		||||
          if [ "${{ secrets.TokenName5}}" ] ; then
 | 
			
		||||
            export ${{ secrets.TokenName5}}="${{ secrets.TokenValue5}}"
 | 
			
		||||
          fi
 | 
			
		||||
          cd ../acmetest
 | 
			
		||||
          ./letest.sh
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  OpenBSD:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    needs: FreeBSD
 | 
			
		||||
    env:
 | 
			
		||||
      TEST_DNS : ${{ secrets.TEST_DNS }}
 | 
			
		||||
      TestingDomain: ${{ secrets.TestingDomain }}
 | 
			
		||||
      TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
 | 
			
		||||
      TEST_DNS_NO_SUBDOMAIN: ${{ secrets.TEST_DNS_NO_SUBDOMAIN }}
 | 
			
		||||
      TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
 | 
			
		||||
      CASE: le_test_dnsapi
 | 
			
		||||
      TEST_LOCAL: 1
 | 
			
		||||
      DEBUG: ${{ secrets.DEBUG }}
 | 
			
		||||
      http_proxy: ${{ secrets.http_proxy }}
 | 
			
		||||
      https_proxy: ${{ secrets.https_proxy }}
 | 
			
		||||
      TokenName1: ${{ secrets.TokenName1}}
 | 
			
		||||
      TokenName2: ${{ secrets.TokenName2}}
 | 
			
		||||
      TokenName3: ${{ secrets.TokenName3}}
 | 
			
		||||
      TokenName4: ${{ secrets.TokenName4}}
 | 
			
		||||
      TokenName5: ${{ secrets.TokenName5}}
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
    - name: Clone acmetest
 | 
			
		||||
      run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git  && cp -r acme.sh acmetest/
 | 
			
		||||
    - uses: vmactions/openbsd-vm@v1
 | 
			
		||||
      with:
 | 
			
		||||
        envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
 | 
			
		||||
        prepare: pkg_add socat curl
 | 
			
		||||
        usesh: true
 | 
			
		||||
        copyback: false
 | 
			
		||||
        run: |
 | 
			
		||||
          if [ "${{ secrets.TokenName1}}" ] ; then
 | 
			
		||||
            export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}"
 | 
			
		||||
          fi
 | 
			
		||||
          if [ "${{ secrets.TokenName2}}" ] ; then
 | 
			
		||||
            export ${{ secrets.TokenName2}}="${{ secrets.TokenValue2}}"
 | 
			
		||||
          fi
 | 
			
		||||
          if [ "${{ secrets.TokenName3}}" ] ; then
 | 
			
		||||
            export ${{ secrets.TokenName3}}="${{ secrets.TokenValue3}}"
 | 
			
		||||
          fi
 | 
			
		||||
          if [ "${{ secrets.TokenName4}}" ] ; then
 | 
			
		||||
            export ${{ secrets.TokenName4}}="${{ secrets.TokenValue4}}"
 | 
			
		||||
          fi
 | 
			
		||||
          if [ "${{ secrets.TokenName5}}" ] ; then
 | 
			
		||||
            export ${{ secrets.TokenName5}}="${{ secrets.TokenValue5}}"
 | 
			
		||||
          fi
 | 
			
		||||
          cd ../acmetest
 | 
			
		||||
          ./letest.sh
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  NetBSD:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    needs: OpenBSD
 | 
			
		||||
    env:
 | 
			
		||||
      TEST_DNS : ${{ secrets.TEST_DNS }}
 | 
			
		||||
      TestingDomain: ${{ secrets.TestingDomain }}
 | 
			
		||||
      TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
 | 
			
		||||
      TEST_DNS_NO_SUBDOMAIN: ${{ secrets.TEST_DNS_NO_SUBDOMAIN }}
 | 
			
		||||
      TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
 | 
			
		||||
      CASE: le_test_dnsapi
 | 
			
		||||
      TEST_LOCAL: 1
 | 
			
		||||
      DEBUG: ${{ secrets.DEBUG }}
 | 
			
		||||
      http_proxy: ${{ secrets.http_proxy }}
 | 
			
		||||
      https_proxy: ${{ secrets.https_proxy }}
 | 
			
		||||
      TokenName1: ${{ secrets.TokenName1}}
 | 
			
		||||
      TokenName2: ${{ secrets.TokenName2}}
 | 
			
		||||
      TokenName3: ${{ secrets.TokenName3}}
 | 
			
		||||
      TokenName4: ${{ secrets.TokenName4}}
 | 
			
		||||
      TokenName5: ${{ secrets.TokenName5}}
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
    - name: Clone acmetest
 | 
			
		||||
      run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git  && cp -r acme.sh acmetest/
 | 
			
		||||
    - uses: vmactions/netbsd-vm@v1
 | 
			
		||||
      with:
 | 
			
		||||
        envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
 | 
			
		||||
        prepare: |
 | 
			
		||||
          /usr/sbin/pkg_add curl socat
 | 
			
		||||
        usesh: true
 | 
			
		||||
        copyback: false
 | 
			
		||||
        run: |
 | 
			
		||||
          if [ "${{ secrets.TokenName1}}" ] ; then
 | 
			
		||||
            export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}"
 | 
			
		||||
          fi
 | 
			
		||||
          if [ "${{ secrets.TokenName2}}" ] ; then
 | 
			
		||||
            export ${{ secrets.TokenName2}}="${{ secrets.TokenValue2}}"
 | 
			
		||||
          fi
 | 
			
		||||
          if [ "${{ secrets.TokenName3}}" ] ; then
 | 
			
		||||
            export ${{ secrets.TokenName3}}="${{ secrets.TokenValue3}}"
 | 
			
		||||
          fi
 | 
			
		||||
          if [ "${{ secrets.TokenName4}}" ] ; then
 | 
			
		||||
            export ${{ secrets.TokenName4}}="${{ secrets.TokenValue4}}"
 | 
			
		||||
          fi
 | 
			
		||||
          if [ "${{ secrets.TokenName5}}" ] ; then
 | 
			
		||||
            export ${{ secrets.TokenName5}}="${{ secrets.TokenValue5}}"
 | 
			
		||||
          fi
 | 
			
		||||
          cd ../acmetest
 | 
			
		||||
          ./letest.sh
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  DragonFlyBSD:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    needs: NetBSD
 | 
			
		||||
    env:
 | 
			
		||||
      TEST_DNS : ${{ secrets.TEST_DNS }}
 | 
			
		||||
      TestingDomain: ${{ secrets.TestingDomain }}
 | 
			
		||||
      TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
 | 
			
		||||
      TEST_DNS_NO_SUBDOMAIN: ${{ secrets.TEST_DNS_NO_SUBDOMAIN }}
 | 
			
		||||
      TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
 | 
			
		||||
      CASE: le_test_dnsapi
 | 
			
		||||
      TEST_LOCAL: 1
 | 
			
		||||
      DEBUG: ${{ secrets.DEBUG }}
 | 
			
		||||
      http_proxy: ${{ secrets.http_proxy }}
 | 
			
		||||
      https_proxy: ${{ secrets.https_proxy }}
 | 
			
		||||
      TokenName1: ${{ secrets.TokenName1}}
 | 
			
		||||
      TokenName2: ${{ secrets.TokenName2}}
 | 
			
		||||
      TokenName3: ${{ secrets.TokenName3}}
 | 
			
		||||
      TokenName4: ${{ secrets.TokenName4}}
 | 
			
		||||
      TokenName5: ${{ secrets.TokenName5}}
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
    - name: Clone acmetest
 | 
			
		||||
      run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git  && cp -r acme.sh acmetest/
 | 
			
		||||
    - uses: vmactions/dragonflybsd-vm@v1
 | 
			
		||||
      with:
 | 
			
		||||
        envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
 | 
			
		||||
        prepare: |
 | 
			
		||||
          pkg install -y curl socat libnghttp2
 | 
			
		||||
        usesh: true
 | 
			
		||||
        copyback: false
 | 
			
		||||
        run: |
 | 
			
		||||
          if [ "${{ secrets.TokenName1}}" ] ; then
 | 
			
		||||
            export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}"
 | 
			
		||||
          fi
 | 
			
		||||
          if [ "${{ secrets.TokenName2}}" ] ; then
 | 
			
		||||
            export ${{ secrets.TokenName2}}="${{ secrets.TokenValue2}}"
 | 
			
		||||
          fi
 | 
			
		||||
          if [ "${{ secrets.TokenName3}}" ] ; then
 | 
			
		||||
            export ${{ secrets.TokenName3}}="${{ secrets.TokenValue3}}"
 | 
			
		||||
          fi
 | 
			
		||||
          if [ "${{ secrets.TokenName4}}" ] ; then
 | 
			
		||||
            export ${{ secrets.TokenName4}}="${{ secrets.TokenValue4}}"
 | 
			
		||||
          fi
 | 
			
		||||
          if [ "${{ secrets.TokenName5}}" ] ; then
 | 
			
		||||
            export ${{ secrets.TokenName5}}="${{ secrets.TokenValue5}}"
 | 
			
		||||
          fi
 | 
			
		||||
          cd ../acmetest
 | 
			
		||||
          ./letest.sh
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  Solaris:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    needs: DragonFlyBSD
 | 
			
		||||
    env:
 | 
			
		||||
      TEST_DNS : ${{ secrets.TEST_DNS }}
 | 
			
		||||
      TestingDomain: ${{ secrets.TestingDomain }}
 | 
			
		||||
      TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
 | 
			
		||||
      TEST_DNS_NO_SUBDOMAIN: ${{ secrets.TEST_DNS_NO_SUBDOMAIN }}
 | 
			
		||||
      TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
 | 
			
		||||
      CASE: le_test_dnsapi
 | 
			
		||||
      TEST_LOCAL: 1
 | 
			
		||||
      DEBUG: ${{ secrets.DEBUG }}
 | 
			
		||||
      http_proxy: ${{ secrets.http_proxy }}
 | 
			
		||||
      https_proxy: ${{ secrets.https_proxy }}
 | 
			
		||||
      HTTPS_INSECURE: 1 # always set to 1 to ignore https error, since Solaris doesn't accept the expired ISRG X1 root
 | 
			
		||||
      TokenName1: ${{ secrets.TokenName1}}
 | 
			
		||||
      TokenName2: ${{ secrets.TokenName2}}
 | 
			
		||||
      TokenName3: ${{ secrets.TokenName3}}
 | 
			
		||||
      TokenName4: ${{ secrets.TokenName4}}
 | 
			
		||||
      TokenName5: ${{ secrets.TokenName5}}
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
    - name: Clone acmetest
 | 
			
		||||
      run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git  && cp -r acme.sh acmetest/
 | 
			
		||||
    - uses: vmactions/solaris-vm@v1
 | 
			
		||||
      with:
 | 
			
		||||
        envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy HTTPS_INSECURE TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
 | 
			
		||||
        copyback: false
 | 
			
		||||
        prepare: 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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  Omnios:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    needs: Solaris
 | 
			
		||||
    env:
 | 
			
		||||
      TEST_DNS : ${{ secrets.TEST_DNS }}
 | 
			
		||||
      TestingDomain: ${{ secrets.TestingDomain }}
 | 
			
		||||
      TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
 | 
			
		||||
      TEST_DNS_NO_SUBDOMAIN: ${{ secrets.TEST_DNS_NO_SUBDOMAIN }}
 | 
			
		||||
      TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
 | 
			
		||||
      CASE: le_test_dnsapi
 | 
			
		||||
      TEST_LOCAL: 1
 | 
			
		||||
      DEBUG: ${{ secrets.DEBUG }}
 | 
			
		||||
      http_proxy: ${{ secrets.http_proxy }}
 | 
			
		||||
      https_proxy: ${{ secrets.https_proxy }}
 | 
			
		||||
      HTTPS_INSECURE: 1 # always set to 1 to ignore https error, since Omnios doesn't accept the expired ISRG X1 root
 | 
			
		||||
      TokenName1: ${{ secrets.TokenName1}}
 | 
			
		||||
      TokenName2: ${{ secrets.TokenName2}}
 | 
			
		||||
      TokenName3: ${{ secrets.TokenName3}}
 | 
			
		||||
      TokenName4: ${{ secrets.TokenName4}}
 | 
			
		||||
      TokenName5: ${{ secrets.TokenName5}}
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
    - name: Clone acmetest
 | 
			
		||||
      run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git  && cp -r acme.sh acmetest/
 | 
			
		||||
    - uses: vmactions/omnios-vm@v1
 | 
			
		||||
      with:
 | 
			
		||||
        envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy HTTPS_INSECURE TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
 | 
			
		||||
        copyback: false
 | 
			
		||||
        prepare: pkg install socat
 | 
			
		||||
        run: |
 | 
			
		||||
          if [ "${{ secrets.TokenName1}}" ] ; then
 | 
			
		||||
            export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}"
 | 
			
		||||
          fi
 | 
			
		||||
          if [ "${{ secrets.TokenName2}}" ] ; then
 | 
			
		||||
            export ${{ secrets.TokenName2}}="${{ secrets.TokenValue2}}"
 | 
			
		||||
          fi
 | 
			
		||||
          if [ "${{ secrets.TokenName3}}" ] ; then
 | 
			
		||||
            export ${{ secrets.TokenName3}}="${{ secrets.TokenValue3}}"
 | 
			
		||||
          fi
 | 
			
		||||
          if [ "${{ secrets.TokenName4}}" ] ; then
 | 
			
		||||
            export ${{ secrets.TokenName4}}="${{ secrets.TokenValue4}}"
 | 
			
		||||
          fi
 | 
			
		||||
          if [ "${{ secrets.TokenName5}}" ] ; then
 | 
			
		||||
            export ${{ secrets.TokenName5}}="${{ secrets.TokenValue5}}"
 | 
			
		||||
          fi
 | 
			
		||||
          cd ../acmetest
 | 
			
		||||
          ./letest.sh
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										71
									
								
								.github/workflows/DragonFlyBSD.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								.github/workflows/DragonFlyBSD.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
			
		||||
name: DragonFlyBSD
 | 
			
		||||
on:
 | 
			
		||||
  push:
 | 
			
		||||
    branches:
 | 
			
		||||
      - '*'
 | 
			
		||||
    paths:
 | 
			
		||||
      - '*.sh'
 | 
			
		||||
      - '.github/workflows/DragonFlyBSD.yml'
 | 
			
		||||
 | 
			
		||||
  pull_request:
 | 
			
		||||
    branches:
 | 
			
		||||
      - dev
 | 
			
		||||
    paths:
 | 
			
		||||
      - '*.sh'
 | 
			
		||||
      - '.github/workflows/DragonFlyBSD.yml'
 | 
			
		||||
 | 
			
		||||
concurrency: 
 | 
			
		||||
  group: ${{ github.workflow }}-${{ github.ref }}
 | 
			
		||||
  cancel-in-progress: true
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  DragonFlyBSD:
 | 
			
		||||
    strategy:
 | 
			
		||||
      matrix:
 | 
			
		||||
        include:
 | 
			
		||||
         - TEST_ACME_Server: "LetsEncrypt.org_test"
 | 
			
		||||
           CA_ECDSA: ""
 | 
			
		||||
           CA: ""
 | 
			
		||||
           CA_EMAIL: ""
 | 
			
		||||
           TEST_PREFERRED_CHAIN: (STAGING)
 | 
			
		||||
         #- TEST_ACME_Server: "ZeroSSL.com"
 | 
			
		||||
         #  CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
 | 
			
		||||
         #  CA: "ZeroSSL RSA Domain Secure Site CA"
 | 
			
		||||
         #  CA_EMAIL: "githubtest@acme.sh"
 | 
			
		||||
         #  TEST_PREFERRED_CHAIN: ""
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    env:
 | 
			
		||||
      TEST_LOCAL: 1
 | 
			
		||||
      TEST_ACME_Server: ${{ matrix.TEST_ACME_Server }}
 | 
			
		||||
      CA_ECDSA: ${{ matrix.CA_ECDSA }}
 | 
			
		||||
      CA: ${{ matrix.CA }}
 | 
			
		||||
      CA_EMAIL: ${{ matrix.CA_EMAIL }}
 | 
			
		||||
      TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
 | 
			
		||||
      ACME_USE_WGET: ${{ matrix.ACME_USE_WGET }}
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
    - uses: vmactions/cf-tunnel@v0
 | 
			
		||||
      id: tunnel
 | 
			
		||||
      with:
 | 
			
		||||
        protocol: http
 | 
			
		||||
        port: 8080
 | 
			
		||||
    - name: Set envs
 | 
			
		||||
      run: echo "TestingDomain=${{steps.tunnel.outputs.server}}" >> $GITHUB_ENV
 | 
			
		||||
    - name: Clone acmetest
 | 
			
		||||
      run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git  && cp -r acme.sh acmetest/
 | 
			
		||||
    - uses: vmactions/dragonflybsd-vm@v1
 | 
			
		||||
      with:
 | 
			
		||||
        envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
 | 
			
		||||
        nat: |
 | 
			
		||||
          "8080": "80"
 | 
			
		||||
        prepare: |
 | 
			
		||||
          pkg install -y curl socat libnghttp2
 | 
			
		||||
        usesh: true
 | 
			
		||||
        copyback: false
 | 
			
		||||
        run: |
 | 
			
		||||
          cd ../acmetest \
 | 
			
		||||
          && ./letest.sh
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										29
									
								
								.github/workflows/FreeBSD.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								.github/workflows/FreeBSD.yml
									
									
									
									
										vendored
									
									
								
							@@ -14,6 +14,11 @@ on:
 | 
			
		||||
      - '*.sh'
 | 
			
		||||
      - '.github/workflows/FreeBSD.yml'
 | 
			
		||||
 | 
			
		||||
concurrency: 
 | 
			
		||||
  group: ${{ github.workflow }}-${{ github.ref }}
 | 
			
		||||
  cancel-in-progress: true
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  FreeBSD:
 | 
			
		||||
@@ -24,13 +29,19 @@ jobs:
 | 
			
		||||
           CA_ECDSA: ""
 | 
			
		||||
           CA: ""
 | 
			
		||||
           CA_EMAIL: ""
 | 
			
		||||
           TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
 | 
			
		||||
           TEST_PREFERRED_CHAIN: (STAGING)
 | 
			
		||||
         - TEST_ACME_Server: "LetsEncrypt.org_test"
 | 
			
		||||
           CA_ECDSA: ""
 | 
			
		||||
           CA: ""
 | 
			
		||||
           CA_EMAIL: ""
 | 
			
		||||
           TEST_PREFERRED_CHAIN: (STAGING)
 | 
			
		||||
           ACME_USE_WGET: 1
 | 
			
		||||
         #- TEST_ACME_Server: "ZeroSSL.com"
 | 
			
		||||
         #  CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
 | 
			
		||||
         #  CA: "ZeroSSL RSA Domain Secure Site CA"
 | 
			
		||||
         #  CA_EMAIL: "githubtest@acme.sh"
 | 
			
		||||
         #  TEST_PREFERRED_CHAIN: ""
 | 
			
		||||
    runs-on: macos-10.15
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    env:
 | 
			
		||||
      TEST_LOCAL: 1
 | 
			
		||||
      TEST_ACME_Server: ${{ matrix.TEST_ACME_Server }}
 | 
			
		||||
@@ -38,9 +49,10 @@ jobs:
 | 
			
		||||
      CA: ${{ matrix.CA }}
 | 
			
		||||
      CA_EMAIL: ${{ matrix.CA_EMAIL }}
 | 
			
		||||
      TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
 | 
			
		||||
      ACME_USE_WGET: ${{ matrix.ACME_USE_WGET }}
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v2
 | 
			
		||||
    - uses: vmactions/cf-tunnel@v0.0.3
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
    - uses: vmactions/cf-tunnel@v0
 | 
			
		||||
      id: tunnel
 | 
			
		||||
      with:
 | 
			
		||||
        protocol: http
 | 
			
		||||
@@ -48,14 +60,15 @@ jobs:
 | 
			
		||||
    - name: Set envs
 | 
			
		||||
      run: echo "TestingDomain=${{steps.tunnel.outputs.server}}" >> $GITHUB_ENV
 | 
			
		||||
    - name: Clone acmetest
 | 
			
		||||
      run: cd .. && git clone https://github.com/acmesh-official/acmetest.git  && cp -r acme.sh acmetest/
 | 
			
		||||
    - uses: vmactions/freebsd-vm@v0.1.5
 | 
			
		||||
      run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git  && cp -r acme.sh acmetest/
 | 
			
		||||
    - uses: vmactions/freebsd-vm@v1
 | 
			
		||||
      with:
 | 
			
		||||
        envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN'
 | 
			
		||||
        envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
 | 
			
		||||
        nat: |
 | 
			
		||||
          "8080": "80"
 | 
			
		||||
        prepare: pkg install -y socat curl
 | 
			
		||||
        prepare: pkg install -y socat curl wget
 | 
			
		||||
        usesh: true
 | 
			
		||||
        copyback: false
 | 
			
		||||
        run: |
 | 
			
		||||
          cd ../acmetest \
 | 
			
		||||
          && ./letest.sh
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										15
									
								
								.github/workflows/Linux.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										15
									
								
								.github/workflows/Linux.yml
									
									
									
									
										vendored
									
									
								
							@@ -15,22 +15,29 @@ on:
 | 
			
		||||
      - '.github/workflows/Linux.yml'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
concurrency: 
 | 
			
		||||
  group: ${{ github.workflow }}-${{ github.ref }}
 | 
			
		||||
  cancel-in-progress: true
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  Linux:
 | 
			
		||||
    strategy:
 | 
			
		||||
      matrix:
 | 
			
		||||
        os: ["ubuntu:latest", "debian:latest", "almalinux:latest", "fedora:latest", "centos:7", "opensuse/leap:latest", "alpine:latest", "oraclelinux:8", "kalilinux/kali", "archlinux:latest", "mageia", "gentoo/stage3"]
 | 
			
		||||
        os: ["ubuntu:latest", "debian:latest", "almalinux:latest", "fedora:latest", "opensuse/leap:latest", "alpine:latest", "oraclelinux:8", "kalilinux/kali", "archlinux:latest", "mageia", "gentoo/stage3"]
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    env:
 | 
			
		||||
      TEST_LOCAL: 1
 | 
			
		||||
      TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
 | 
			
		||||
      TEST_PREFERRED_CHAIN: (STAGING)
 | 
			
		||||
      TEST_ACME_Server: "LetsEncrypt.org_test"
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v2
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
    - name: Clone acmetest
 | 
			
		||||
      run: |
 | 
			
		||||
          cd .. \
 | 
			
		||||
          && git clone https://github.com/acmesh-official/acmetest.git \
 | 
			
		||||
          && git clone --depth=1 https://github.com/acmesh-official/acmetest.git \
 | 
			
		||||
          && cp -r acme.sh acmetest/
 | 
			
		||||
    - name: Run acmetest
 | 
			
		||||
      run: |
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								.github/workflows/MacOS.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								.github/workflows/MacOS.yml
									
									
									
									
										vendored
									
									
								
							@@ -14,6 +14,11 @@ on:
 | 
			
		||||
      - '*.sh'
 | 
			
		||||
      - '.github/workflows/MacOS.yml'
 | 
			
		||||
 | 
			
		||||
concurrency: 
 | 
			
		||||
  group: ${{ github.workflow }}-${{ github.ref }}
 | 
			
		||||
  cancel-in-progress: true
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  MacOS:
 | 
			
		||||
@@ -24,7 +29,7 @@ jobs:
 | 
			
		||||
           CA_ECDSA: ""
 | 
			
		||||
           CA: ""
 | 
			
		||||
           CA_EMAIL: ""
 | 
			
		||||
           TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
 | 
			
		||||
           TEST_PREFERRED_CHAIN: (STAGING)
 | 
			
		||||
         #- TEST_ACME_Server: "ZeroSSL.com"
 | 
			
		||||
         #  CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
 | 
			
		||||
         #  CA: "ZeroSSL RSA Domain Secure Site CA"
 | 
			
		||||
@@ -39,13 +44,13 @@ jobs:
 | 
			
		||||
      CA_EMAIL: ${{ matrix.CA_EMAIL }}
 | 
			
		||||
      TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v2
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
    - name: Install tools
 | 
			
		||||
      run:  brew install socat
 | 
			
		||||
    - name: Clone acmetest
 | 
			
		||||
      run: |
 | 
			
		||||
          cd .. \
 | 
			
		||||
          && git clone https://github.com/acmesh-official/acmetest.git \
 | 
			
		||||
          && git clone --depth=1 https://github.com/acmesh-official/acmetest.git \
 | 
			
		||||
          && cp -r acme.sh acmetest/
 | 
			
		||||
    - name: Run acmetest
 | 
			
		||||
      run: |
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										71
									
								
								.github/workflows/NetBSD.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								.github/workflows/NetBSD.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
			
		||||
name: NetBSD
 | 
			
		||||
on:
 | 
			
		||||
  push:
 | 
			
		||||
    branches:
 | 
			
		||||
      - '*'
 | 
			
		||||
    paths:
 | 
			
		||||
      - '*.sh'
 | 
			
		||||
      - '.github/workflows/NetBSD.yml'
 | 
			
		||||
 | 
			
		||||
  pull_request:
 | 
			
		||||
    branches:
 | 
			
		||||
      - dev
 | 
			
		||||
    paths:
 | 
			
		||||
      - '*.sh'
 | 
			
		||||
      - '.github/workflows/NetBSD.yml'
 | 
			
		||||
 | 
			
		||||
concurrency: 
 | 
			
		||||
  group: ${{ github.workflow }}-${{ github.ref }}
 | 
			
		||||
  cancel-in-progress: true
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  NetBSD:
 | 
			
		||||
    strategy:
 | 
			
		||||
      matrix:
 | 
			
		||||
        include:
 | 
			
		||||
         - TEST_ACME_Server: "LetsEncrypt.org_test"
 | 
			
		||||
           CA_ECDSA: ""
 | 
			
		||||
           CA: ""
 | 
			
		||||
           CA_EMAIL: ""
 | 
			
		||||
           TEST_PREFERRED_CHAIN: (STAGING)
 | 
			
		||||
         #- TEST_ACME_Server: "ZeroSSL.com"
 | 
			
		||||
         #  CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
 | 
			
		||||
         #  CA: "ZeroSSL RSA Domain Secure Site CA"
 | 
			
		||||
         #  CA_EMAIL: "githubtest@acme.sh"
 | 
			
		||||
         #  TEST_PREFERRED_CHAIN: ""
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    env:
 | 
			
		||||
      TEST_LOCAL: 1
 | 
			
		||||
      TEST_ACME_Server: ${{ matrix.TEST_ACME_Server }}
 | 
			
		||||
      CA_ECDSA: ${{ matrix.CA_ECDSA }}
 | 
			
		||||
      CA: ${{ matrix.CA }}
 | 
			
		||||
      CA_EMAIL: ${{ matrix.CA_EMAIL }}
 | 
			
		||||
      TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
 | 
			
		||||
      ACME_USE_WGET: ${{ matrix.ACME_USE_WGET }}
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
    - uses: vmactions/cf-tunnel@v0
 | 
			
		||||
      id: tunnel
 | 
			
		||||
      with:
 | 
			
		||||
        protocol: http
 | 
			
		||||
        port: 8080
 | 
			
		||||
    - name: Set envs
 | 
			
		||||
      run: echo "TestingDomain=${{steps.tunnel.outputs.server}}" >> $GITHUB_ENV
 | 
			
		||||
    - name: Clone acmetest
 | 
			
		||||
      run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git  && cp -r acme.sh acmetest/
 | 
			
		||||
    - uses: vmactions/netbsd-vm@v1
 | 
			
		||||
      with:
 | 
			
		||||
        envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
 | 
			
		||||
        nat: |
 | 
			
		||||
          "8080": "80"
 | 
			
		||||
        prepare: |
 | 
			
		||||
          /usr/sbin/pkg_add curl socat
 | 
			
		||||
        usesh: true
 | 
			
		||||
        copyback: false
 | 
			
		||||
        run: |
 | 
			
		||||
          cd ../acmetest \
 | 
			
		||||
          && ./letest.sh
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										75
									
								
								.github/workflows/Omnios.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								.github/workflows/Omnios.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,75 @@
 | 
			
		||||
name: Omnios
 | 
			
		||||
on:
 | 
			
		||||
  push:
 | 
			
		||||
    branches:
 | 
			
		||||
      - '*'
 | 
			
		||||
    paths:
 | 
			
		||||
      - '*.sh'
 | 
			
		||||
      - '.github/workflows/Omnios.yml'
 | 
			
		||||
 | 
			
		||||
  pull_request:
 | 
			
		||||
    branches:
 | 
			
		||||
      - dev
 | 
			
		||||
    paths:
 | 
			
		||||
      - '*.sh'
 | 
			
		||||
      - '.github/workflows/Omnios.yml'
 | 
			
		||||
 | 
			
		||||
concurrency: 
 | 
			
		||||
  group: ${{ github.workflow }}-${{ github.ref }}
 | 
			
		||||
  cancel-in-progress: true
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  Omnios:
 | 
			
		||||
    strategy:
 | 
			
		||||
      matrix:
 | 
			
		||||
        include:
 | 
			
		||||
         - TEST_ACME_Server: "LetsEncrypt.org_test"
 | 
			
		||||
           CA_ECDSA: ""
 | 
			
		||||
           CA: ""
 | 
			
		||||
           CA_EMAIL: ""
 | 
			
		||||
           TEST_PREFERRED_CHAIN: (STAGING)
 | 
			
		||||
         - TEST_ACME_Server: "LetsEncrypt.org_test"
 | 
			
		||||
           CA_ECDSA: ""
 | 
			
		||||
           CA: ""
 | 
			
		||||
           CA_EMAIL: ""
 | 
			
		||||
           TEST_PREFERRED_CHAIN: (STAGING)
 | 
			
		||||
           ACME_USE_WGET: 1
 | 
			
		||||
         #- TEST_ACME_Server: "ZeroSSL.com"
 | 
			
		||||
         #  CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
 | 
			
		||||
         #  CA: "ZeroSSL RSA Domain Secure Site CA"
 | 
			
		||||
         #  CA_EMAIL: "githubtest@acme.sh"
 | 
			
		||||
         #  TEST_PREFERRED_CHAIN: ""
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    env:
 | 
			
		||||
      TEST_LOCAL: 1
 | 
			
		||||
      TEST_ACME_Server: ${{ matrix.TEST_ACME_Server }}
 | 
			
		||||
      CA_ECDSA: ${{ matrix.CA_ECDSA }}
 | 
			
		||||
      CA: ${{ matrix.CA }}
 | 
			
		||||
      CA_EMAIL: ${{ matrix.CA_EMAIL }}
 | 
			
		||||
      TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
 | 
			
		||||
      ACME_USE_WGET: ${{ matrix.ACME_USE_WGET }}
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
    - uses: vmactions/cf-tunnel@v0
 | 
			
		||||
      id: tunnel
 | 
			
		||||
      with:
 | 
			
		||||
        protocol: http
 | 
			
		||||
        port: 8080
 | 
			
		||||
    - name: Set envs
 | 
			
		||||
      run: echo "TestingDomain=${{steps.tunnel.outputs.server}}" >> $GITHUB_ENV
 | 
			
		||||
    - name: Clone acmetest
 | 
			
		||||
      run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git  && cp -r acme.sh acmetest/
 | 
			
		||||
    - uses: vmactions/omnios-vm@v1
 | 
			
		||||
      with:
 | 
			
		||||
        envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
 | 
			
		||||
        nat: |
 | 
			
		||||
          "8080": "80"
 | 
			
		||||
        prepare: pkg install socat wget
 | 
			
		||||
        copyback: false
 | 
			
		||||
        run: |
 | 
			
		||||
          cd ../acmetest \
 | 
			
		||||
          && ./letest.sh
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										76
									
								
								.github/workflows/OpenBSD.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								.github/workflows/OpenBSD.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,76 @@
 | 
			
		||||
name: OpenBSD
 | 
			
		||||
on:
 | 
			
		||||
  push:
 | 
			
		||||
    branches:
 | 
			
		||||
      - '*'
 | 
			
		||||
    paths:
 | 
			
		||||
      - '*.sh'
 | 
			
		||||
      - '.github/workflows/OpenBSD.yml'
 | 
			
		||||
 | 
			
		||||
  pull_request:
 | 
			
		||||
    branches:
 | 
			
		||||
      - dev
 | 
			
		||||
    paths:
 | 
			
		||||
      - '*.sh'
 | 
			
		||||
      - '.github/workflows/OpenBSD.yml'
 | 
			
		||||
 | 
			
		||||
concurrency: 
 | 
			
		||||
  group: ${{ github.workflow }}-${{ github.ref }}
 | 
			
		||||
  cancel-in-progress: true
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  OpenBSD:
 | 
			
		||||
    strategy:
 | 
			
		||||
      matrix:
 | 
			
		||||
        include:
 | 
			
		||||
         - TEST_ACME_Server: "LetsEncrypt.org_test"
 | 
			
		||||
           CA_ECDSA: ""
 | 
			
		||||
           CA: ""
 | 
			
		||||
           CA_EMAIL: ""
 | 
			
		||||
           TEST_PREFERRED_CHAIN: (STAGING)
 | 
			
		||||
         - TEST_ACME_Server: "LetsEncrypt.org_test"
 | 
			
		||||
           CA_ECDSA: ""
 | 
			
		||||
           CA: ""
 | 
			
		||||
           CA_EMAIL: ""
 | 
			
		||||
           TEST_PREFERRED_CHAIN: (STAGING)
 | 
			
		||||
           ACME_USE_WGET: 1
 | 
			
		||||
         #- TEST_ACME_Server: "ZeroSSL.com"
 | 
			
		||||
         #  CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
 | 
			
		||||
         #  CA: "ZeroSSL RSA Domain Secure Site CA"
 | 
			
		||||
         #  CA_EMAIL: "githubtest@acme.sh"
 | 
			
		||||
         #  TEST_PREFERRED_CHAIN: ""
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    env:
 | 
			
		||||
      TEST_LOCAL: 1
 | 
			
		||||
      TEST_ACME_Server: ${{ matrix.TEST_ACME_Server }}
 | 
			
		||||
      CA_ECDSA: ${{ matrix.CA_ECDSA }}
 | 
			
		||||
      CA: ${{ matrix.CA }}
 | 
			
		||||
      CA_EMAIL: ${{ matrix.CA_EMAIL }}
 | 
			
		||||
      TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
 | 
			
		||||
      ACME_USE_WGET: ${{ matrix.ACME_USE_WGET }}
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
    - uses: vmactions/cf-tunnel@v0
 | 
			
		||||
      id: tunnel
 | 
			
		||||
      with:
 | 
			
		||||
        protocol: http
 | 
			
		||||
        port: 8080
 | 
			
		||||
    - name: Set envs
 | 
			
		||||
      run: echo "TestingDomain=${{steps.tunnel.outputs.server}}" >> $GITHUB_ENV
 | 
			
		||||
    - name: Clone acmetest
 | 
			
		||||
      run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git  && cp -r acme.sh acmetest/
 | 
			
		||||
    - uses: vmactions/openbsd-vm@v1
 | 
			
		||||
      with:
 | 
			
		||||
        envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
 | 
			
		||||
        nat: |
 | 
			
		||||
          "8080": "80"
 | 
			
		||||
        prepare: pkg_add socat curl wget libnghttp2
 | 
			
		||||
        usesh: true
 | 
			
		||||
        copyback: false
 | 
			
		||||
        run: |
 | 
			
		||||
          cd ../acmetest \
 | 
			
		||||
          && ./letest.sh
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										26
									
								
								.github/workflows/PebbleStrict.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								.github/workflows/PebbleStrict.yml
									
									
									
									
										vendored
									
									
								
							@@ -13,6 +13,13 @@ on:
 | 
			
		||||
      - '*.sh'
 | 
			
		||||
      - '.github/workflows/PebbleStrict.yml'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
concurrency: 
 | 
			
		||||
  group: ${{ github.workflow }}-${{ github.ref }}
 | 
			
		||||
  cancel-in-progress: true
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  PebbleStrict:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
@@ -26,23 +33,23 @@ jobs:
 | 
			
		||||
      TEST_CA: "Pebble Intermediate CA"
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v2
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
    - name: Install tools
 | 
			
		||||
      run: sudo apt-get install -y socat
 | 
			
		||||
    - name: Run Pebble
 | 
			
		||||
      run: cd .. && curl https://raw.githubusercontent.com/letsencrypt/pebble/master/docker-compose.yml >docker-compose.yml && docker-compose up -d
 | 
			
		||||
      run: cd .. && curl https://raw.githubusercontent.com/letsencrypt/pebble/master/docker-compose.yml >docker-compose.yml && docker compose up -d
 | 
			
		||||
    - name: Set up Pebble
 | 
			
		||||
      run: curl --request POST --data '{"ip":"10.30.50.1"}' http://localhost:8055/set-default-ipv4
 | 
			
		||||
    - name: Clone acmetest
 | 
			
		||||
      run: cd .. && git clone https://github.com/acmesh-official/acmetest.git  && cp -r acme.sh acmetest/
 | 
			
		||||
      run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git  && cp -r acme.sh acmetest/
 | 
			
		||||
    - name: Run acmetest
 | 
			
		||||
      run: cd ../acmetest && ./letest.sh
 | 
			
		||||
 | 
			
		||||
  PebbleStrict_IPCert:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    env:
 | 
			
		||||
      TestingDomain: 10.30.50.1
 | 
			
		||||
      ACME_DIRECTORY: https://localhost:14000/dir
 | 
			
		||||
      TestingDomain: 1.23.45.67
 | 
			
		||||
      TEST_ACME_Server: https://localhost:14000/dir
 | 
			
		||||
      HTTPS_INSECURE: 1
 | 
			
		||||
      Le_HTTPPort: 5002
 | 
			
		||||
      Le_TLSPort: 5001
 | 
			
		||||
@@ -51,12 +58,15 @@ jobs:
 | 
			
		||||
      TEST_IPCERT: 1
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v2
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
    - name: Install tools
 | 
			
		||||
      run: sudo apt-get install -y socat
 | 
			
		||||
    - name: Run Pebble
 | 
			
		||||
      run: cd .. && curl https://raw.githubusercontent.com/letsencrypt/pebble/master/docker-compose.yml >docker-compose.yml && docker-compose up -d
 | 
			
		||||
      run: |
 | 
			
		||||
        docker run --rm -itd --name=pebble \
 | 
			
		||||
        -e PEBBLE_VA_ALWAYS_VALID=1 \
 | 
			
		||||
        -p 14000:14000 -p 15000:15000   letsencrypt/pebble:latest pebble -config /test/config/pebble-config.json -strict
 | 
			
		||||
    - name: Clone acmetest
 | 
			
		||||
      run: cd .. && git clone https://github.com/acmesh-official/acmetest.git  && cp -r acme.sh acmetest/
 | 
			
		||||
      run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git  && cp -r acme.sh acmetest/
 | 
			
		||||
    - name: Run acmetest
 | 
			
		||||
      run: cd ../acmetest && ./letest.sh
 | 
			
		||||
							
								
								
									
										136
									
								
								.github/workflows/Solaris.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										136
									
								
								.github/workflows/Solaris.yml
									
									
									
									
										vendored
									
									
								
							@@ -1,61 +1,75 @@
 | 
			
		||||
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_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
 | 
			
		||||
         #- TEST_ACME_Server: "ZeroSSL.com"
 | 
			
		||||
         #  CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
 | 
			
		||||
         #  CA: "ZeroSSL RSA Domain Secure Site CA"
 | 
			
		||||
         #  CA_EMAIL: "githubtest@acme.sh"
 | 
			
		||||
         #  TEST_PREFERRED_CHAIN: ""
 | 
			
		||||
    runs-on: macos-10.15
 | 
			
		||||
    env:
 | 
			
		||||
      TEST_LOCAL: 1
 | 
			
		||||
      TEST_ACME_Server: ${{ matrix.TEST_ACME_Server }}
 | 
			
		||||
      CA_ECDSA: ${{ matrix.CA_ECDSA }}
 | 
			
		||||
      CA: ${{ matrix.CA }}
 | 
			
		||||
      CA_EMAIL: ${{ matrix.CA_EMAIL }}
 | 
			
		||||
      TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v2
 | 
			
		||||
    - uses: vmactions/cf-tunnel@v0.0.3
 | 
			
		||||
      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.5
 | 
			
		||||
      with:
 | 
			
		||||
        envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN'
 | 
			
		||||
        nat: |
 | 
			
		||||
          "8080": "80"
 | 
			
		||||
        prepare: pkgutil -y -i socat curl
 | 
			
		||||
        run: |
 | 
			
		||||
          cd ../acmetest \
 | 
			
		||||
          && ./letest.sh
 | 
			
		||||
 | 
			
		||||
name: Solaris
 | 
			
		||||
on:
 | 
			
		||||
  push:
 | 
			
		||||
    branches:
 | 
			
		||||
      - '*'
 | 
			
		||||
    paths:
 | 
			
		||||
      - '*.sh'
 | 
			
		||||
      - '.github/workflows/Solaris.yml'
 | 
			
		||||
 | 
			
		||||
  pull_request:
 | 
			
		||||
    branches:
 | 
			
		||||
      - dev
 | 
			
		||||
    paths:
 | 
			
		||||
      - '*.sh'
 | 
			
		||||
      - '.github/workflows/Solaris.yml'
 | 
			
		||||
 | 
			
		||||
concurrency: 
 | 
			
		||||
  group: ${{ github.workflow }}-${{ github.ref }}
 | 
			
		||||
  cancel-in-progress: true
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  Solaris:
 | 
			
		||||
    strategy:
 | 
			
		||||
      matrix:
 | 
			
		||||
        include:
 | 
			
		||||
         - TEST_ACME_Server: "LetsEncrypt.org_test"
 | 
			
		||||
           CA_ECDSA: ""
 | 
			
		||||
           CA: ""
 | 
			
		||||
           CA_EMAIL: ""
 | 
			
		||||
           TEST_PREFERRED_CHAIN: (STAGING)
 | 
			
		||||
         - TEST_ACME_Server: "LetsEncrypt.org_test"
 | 
			
		||||
           CA_ECDSA: ""
 | 
			
		||||
           CA: ""
 | 
			
		||||
           CA_EMAIL: ""
 | 
			
		||||
           TEST_PREFERRED_CHAIN: (STAGING)
 | 
			
		||||
           ACME_USE_WGET: 1
 | 
			
		||||
         #- TEST_ACME_Server: "ZeroSSL.com"
 | 
			
		||||
         #  CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
 | 
			
		||||
         #  CA: "ZeroSSL RSA Domain Secure Site CA"
 | 
			
		||||
         #  CA_EMAIL: "githubtest@acme.sh"
 | 
			
		||||
         #  TEST_PREFERRED_CHAIN: ""
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    env:
 | 
			
		||||
      TEST_LOCAL: 1
 | 
			
		||||
      TEST_ACME_Server: ${{ matrix.TEST_ACME_Server }}
 | 
			
		||||
      CA_ECDSA: ${{ matrix.CA_ECDSA }}
 | 
			
		||||
      CA: ${{ matrix.CA }}
 | 
			
		||||
      CA_EMAIL: ${{ matrix.CA_EMAIL }}
 | 
			
		||||
      TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
 | 
			
		||||
      ACME_USE_WGET: ${{ matrix.ACME_USE_WGET }}
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
    - uses: vmactions/cf-tunnel@v0
 | 
			
		||||
      id: tunnel
 | 
			
		||||
      with:
 | 
			
		||||
        protocol: http
 | 
			
		||||
        port: 8080
 | 
			
		||||
    - name: Set envs
 | 
			
		||||
      run: echo "TestingDomain=${{steps.tunnel.outputs.server}}" >> $GITHUB_ENV
 | 
			
		||||
    - name: Clone acmetest
 | 
			
		||||
      run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git  && cp -r acme.sh acmetest/
 | 
			
		||||
    - uses: vmactions/solaris-vm@v1
 | 
			
		||||
      with:
 | 
			
		||||
        envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
 | 
			
		||||
        nat: |
 | 
			
		||||
          "8080": "80"
 | 
			
		||||
        prepare: pkgutil -y -i socat curl wget
 | 
			
		||||
        copyback: false
 | 
			
		||||
        run: |
 | 
			
		||||
          cd ../acmetest \
 | 
			
		||||
          && ./letest.sh
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										29
									
								
								.github/workflows/Ubuntu.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								.github/workflows/Ubuntu.yml
									
									
									
									
										vendored
									
									
								
							@@ -14,6 +14,11 @@ on:
 | 
			
		||||
      - '*.sh'
 | 
			
		||||
      - '.github/workflows/Ubuntu.yml'
 | 
			
		||||
 | 
			
		||||
concurrency: 
 | 
			
		||||
  group: ${{ github.workflow }}-${{ github.ref }}
 | 
			
		||||
  cancel-in-progress: true
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  Ubuntu:
 | 
			
		||||
@@ -24,7 +29,13 @@ jobs:
 | 
			
		||||
           CA_ECDSA: ""
 | 
			
		||||
           CA: ""
 | 
			
		||||
           CA_EMAIL: ""
 | 
			
		||||
           TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
 | 
			
		||||
           TEST_PREFERRED_CHAIN: (STAGING)
 | 
			
		||||
         - TEST_ACME_Server: "LetsEncrypt.org_test"
 | 
			
		||||
           CA_ECDSA: ""
 | 
			
		||||
           CA: ""
 | 
			
		||||
           CA_EMAIL: ""
 | 
			
		||||
           TEST_PREFERRED_CHAIN: (STAGING)
 | 
			
		||||
           ACME_USE_WGET: 1
 | 
			
		||||
         - TEST_ACME_Server: "ZeroSSL.com"
 | 
			
		||||
           CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
 | 
			
		||||
           CA: "ZeroSSL RSA Domain Secure Site CA"
 | 
			
		||||
@@ -57,10 +68,11 @@ jobs:
 | 
			
		||||
      NO_REVOKE: ${{ matrix.NO_REVOKE }}
 | 
			
		||||
      TEST_IPCERT: ${{ matrix.TEST_IPCERT }}
 | 
			
		||||
      TestingDomain: ${{ matrix.TestingDomain }}
 | 
			
		||||
      ACME_USE_WGET: ${{ matrix.ACME_USE_WGET }}
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v2
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
    - name: Install tools
 | 
			
		||||
      run: sudo apt-get install -y socat
 | 
			
		||||
      run: sudo apt-get install -y socat wget
 | 
			
		||||
    - name: Start StepCA
 | 
			
		||||
      if: ${{ matrix.TEST_ACME_Server=='https://localhost:9000/acme/acme/directory' }}
 | 
			
		||||
      run: |
 | 
			
		||||
@@ -68,15 +80,20 @@ jobs:
 | 
			
		||||
            -p 9000:9000 \
 | 
			
		||||
            -e "DOCKER_STEPCA_INIT_NAME=Smallstep" \
 | 
			
		||||
            -e "DOCKER_STEPCA_INIT_DNS_NAMES=localhost,$(hostname -f)" \
 | 
			
		||||
            -e "DOCKER_STEPCA_INIT_REMOTE_MANAGEMENT=true" \
 | 
			
		||||
            -e "DOCKER_STEPCA_INIT_PASSWORD=test" \
 | 
			
		||||
            --name stepca \
 | 
			
		||||
            smallstep/step-ca \
 | 
			
		||||
            && sleep 5 && docker exec  stepca step ca provisioner add acme --type ACME \
 | 
			
		||||
            smallstep/step-ca:0.23.1
 | 
			
		||||
 | 
			
		||||
            sleep 5
 | 
			
		||||
            docker exec  stepca bash -c "echo test >test" \
 | 
			
		||||
            && docker exec stepca step ca provisioner add acme --type ACME --admin-subject  step --admin-password-file=/home/step/test \
 | 
			
		||||
            && docker exec  stepca kill -1 1 \
 | 
			
		||||
            && docker exec  stepca cat /home/step/certs/root_ca.crt | sudo bash -c "cat - >>/etc/ssl/certs/ca-certificates.crt"
 | 
			
		||||
    - name: Clone acmetest
 | 
			
		||||
      run: |
 | 
			
		||||
          cd .. \
 | 
			
		||||
          && git clone https://github.com/acmesh-official/acmetest.git \
 | 
			
		||||
          && git clone --depth=1 https://github.com/acmesh-official/acmetest.git \
 | 
			
		||||
          && cp -r acme.sh acmetest/
 | 
			
		||||
    - name: Run acmetest
 | 
			
		||||
      run: |
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										13
									
								
								.github/workflows/Windows.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								.github/workflows/Windows.yml
									
									
									
									
										vendored
									
									
								
							@@ -15,6 +15,11 @@ on:
 | 
			
		||||
      - '.github/workflows/Windows.yml'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
concurrency: 
 | 
			
		||||
  group: ${{ github.workflow }}-${{ github.ref }}
 | 
			
		||||
  cancel-in-progress: true
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  Windows:
 | 
			
		||||
    strategy:
 | 
			
		||||
@@ -24,7 +29,7 @@ jobs:
 | 
			
		||||
           CA_ECDSA: ""
 | 
			
		||||
           CA: ""
 | 
			
		||||
           CA_EMAIL: ""
 | 
			
		||||
           TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
 | 
			
		||||
           TEST_PREFERRED_CHAIN: (STAGING)
 | 
			
		||||
         #- TEST_ACME_Server: "ZeroSSL.com"
 | 
			
		||||
         #  CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
 | 
			
		||||
         #  CA: "ZeroSSL RSA Domain Secure Site CA"
 | 
			
		||||
@@ -44,7 +49,7 @@ jobs:
 | 
			
		||||
    - name: Set git to use LF
 | 
			
		||||
      run: |
 | 
			
		||||
          git config --global core.autocrlf false
 | 
			
		||||
    - uses: actions/checkout@v2
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
    - name: Install cygwin base packages with chocolatey
 | 
			
		||||
      run: |
 | 
			
		||||
          choco config get cacheLocation
 | 
			
		||||
@@ -52,7 +57,7 @@ jobs:
 | 
			
		||||
      shell: cmd
 | 
			
		||||
    - name: Install cygwin additional packages
 | 
			
		||||
      run: |
 | 
			
		||||
          C:\tools\cygwin\cygwinsetup.exe -qgnNdO -R C:/tools/cygwin -s http://mirrors.kernel.org/sourceware/cygwin/ -P socat,curl,cron,unzip,git,xxd
 | 
			
		||||
          C:\tools\cygwin\cygwinsetup.exe -qgnNdO -R C:/tools/cygwin -s https://mirrors.kernel.org/sourceware/cygwin/ -P socat,curl,cron,unzip,git,xxd
 | 
			
		||||
      shell: cmd
 | 
			
		||||
    - name: Set ENV
 | 
			
		||||
      shell: cmd
 | 
			
		||||
@@ -64,7 +69,7 @@ jobs:
 | 
			
		||||
          echo "PATH=%PATH%"
 | 
			
		||||
    - name: Clone acmetest
 | 
			
		||||
      shell: cmd
 | 
			
		||||
      run: cd .. && git clone https://github.com/acmesh-official/acmetest.git  && cp -r acme.sh acmetest/
 | 
			
		||||
      run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git  && cp -r acme.sh acmetest/
 | 
			
		||||
    - name: Run acmetest
 | 
			
		||||
      shell: cmd
 | 
			
		||||
      run: cd ../acmetest && bash.exe -c ./letest.sh
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								.github/workflows/dockerhub.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								.github/workflows/dockerhub.yml
									
									
									
									
										vendored
									
									
								
							@@ -11,7 +11,11 @@ on:
 | 
			
		||||
      - "Dockerfile"
 | 
			
		||||
      - '.github/workflows/dockerhub.yml'
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
concurrency:
 | 
			
		||||
  group: ${{ github.workflow }}-${{ github.ref }}
 | 
			
		||||
  cancel-in-progress: true
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  CheckToken:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
@@ -24,9 +28,9 @@ jobs:
 | 
			
		||||
        id: step_one
 | 
			
		||||
        run: |
 | 
			
		||||
          if [ "$DOCKER_PASSWORD" ] ; then
 | 
			
		||||
            echo "::set-output name=hasToken::true"
 | 
			
		||||
            echo "hasToken=true" >>$GITHUB_OUTPUT
 | 
			
		||||
          else
 | 
			
		||||
            echo "::set-output name=hasToken::false"
 | 
			
		||||
            echo "hasToken=false" >>$GITHUB_OUTPUT
 | 
			
		||||
          fi
 | 
			
		||||
      - name: Check the value
 | 
			
		||||
        run: echo ${{ steps.step_one.outputs.hasToken }}
 | 
			
		||||
@@ -37,11 +41,11 @@ jobs:
 | 
			
		||||
    if: "contains(needs.CheckToken.outputs.hasToken, 'true')"
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: checkout code
 | 
			
		||||
        uses: actions/checkout@v2
 | 
			
		||||
        uses: actions/checkout@v4
 | 
			
		||||
      - name: Set up QEMU
 | 
			
		||||
        uses: docker/setup-qemu-action@v1
 | 
			
		||||
        uses: docker/setup-qemu-action@v2
 | 
			
		||||
      - name: Set up Docker Buildx
 | 
			
		||||
        uses: docker/setup-buildx-action@v1
 | 
			
		||||
        uses: docker/setup-buildx-action@v2
 | 
			
		||||
      - name: login to docker hub
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										19
									
								
								.github/workflows/issue.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								.github/workflows/issue.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
name: "Update issues"
 | 
			
		||||
on:
 | 
			
		||||
  issues:
 | 
			
		||||
    types: [opened]
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  comment:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
      - uses: actions/github-script@v6
 | 
			
		||||
        with:
 | 
			
		||||
          script: |
 | 
			
		||||
            github.rest.issues.createComment({
 | 
			
		||||
              issue_number: context.issue.number,
 | 
			
		||||
              owner: context.repo.owner,
 | 
			
		||||
              repo: context.repo.repo,
 | 
			
		||||
              body: "Please upgrade to the latest code and try again first. Maybe it's already fixed.              ```acme.sh --upgrade```              If it's still not working, please provide the log with `--debug 2`, otherwise, nobody can help you."
 | 
			
		||||
              
 | 
			
		||||
            })
 | 
			
		||||
							
								
								
									
										30
									
								
								.github/workflows/pr_dns.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								.github/workflows/pr_dns.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
name: Check dns api
 | 
			
		||||
 | 
			
		||||
on:
 | 
			
		||||
  pull_request_target:
 | 
			
		||||
    types:
 | 
			
		||||
      - opened
 | 
			
		||||
    paths:
 | 
			
		||||
      - 'dnsapi/*.sh'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  welcome:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
      - uses: actions/github-script@v6
 | 
			
		||||
        with:
 | 
			
		||||
          script: |
 | 
			
		||||
            await github.rest.issues.createComment({
 | 
			
		||||
              issue_number: context.issue.number,
 | 
			
		||||
              owner: context.repo.owner,
 | 
			
		||||
              repo: context.repo.repo,
 | 
			
		||||
              body: `**Welcome**
 | 
			
		||||
                First thing: don't send PR to the master branch, please send to the dev branch instead.
 | 
			
		||||
                Please make sure you've read our [DNS API Dev Guide](../wiki/DNS-API-Dev-Guide) and [DNS-API-Test](../wiki/DNS-API-Test).
 | 
			
		||||
                Then reply on this message, otherwise, your code will not be reviewed or merged.
 | 
			
		||||
                We look forward to reviewing your Pull request shortly ✨
 | 
			
		||||
                注意: 必须通过了 [DNS-API-Test](../wiki/DNS-API-Test) 才会被 review. 无论是修改, 还是新加的 dns api, 都必须确保通过这个测试.
 | 
			
		||||
                `
 | 
			
		||||
            })
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										30
									
								
								.github/workflows/pr_notify.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								.github/workflows/pr_notify.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
name: Check dns api
 | 
			
		||||
 | 
			
		||||
on:
 | 
			
		||||
  pull_request_target:
 | 
			
		||||
    types:
 | 
			
		||||
      - opened
 | 
			
		||||
    branches:
 | 
			
		||||
      - 'dev'
 | 
			
		||||
    paths:
 | 
			
		||||
      - 'notify/*.sh'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  welcome:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
      - uses: actions/github-script@v6
 | 
			
		||||
        with:
 | 
			
		||||
          script: |
 | 
			
		||||
            await github.rest.issues.createComment({
 | 
			
		||||
              issue_number: context.issue.number,
 | 
			
		||||
              owner: context.repo.owner,
 | 
			
		||||
              repo: context.repo.repo,
 | 
			
		||||
              body: `**Welcome**
 | 
			
		||||
                Please make sure you've read our [Code-of-conduct](../wiki/Code-of-conduct) and  add the usage here: [notify](../wiki/notify).
 | 
			
		||||
                Then reply on this message, otherwise, your code will not be reviewed or merged.
 | 
			
		||||
                We look forward to reviewing your Pull request shortly ✨
 | 
			
		||||
                `
 | 
			
		||||
            })
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										11
									
								
								.github/workflows/shellcheck.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								.github/workflows/shellcheck.yml
									
									
									
									
										vendored
									
									
								
							@@ -13,20 +13,25 @@ on:
 | 
			
		||||
      - '**.sh'
 | 
			
		||||
      - '.github/workflows/shellcheck.yml'
 | 
			
		||||
 | 
			
		||||
concurrency: 
 | 
			
		||||
  group: ${{ github.workflow }}-${{ github.ref }}
 | 
			
		||||
  cancel-in-progress: true
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  ShellCheck:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v2
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
    - name: Install Shellcheck
 | 
			
		||||
      run: sudo apt-get install -y shellcheck
 | 
			
		||||
    - name: DoShellcheck
 | 
			
		||||
      run: shellcheck -V  && shellcheck -e SC2181 **/*.sh && echo "shellcheck OK"
 | 
			
		||||
      run: shellcheck -V  && shellcheck -e SC2181 -e SC2089 **/*.sh && echo "shellcheck OK"
 | 
			
		||||
 | 
			
		||||
  shfmt:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v2
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
    - name: Install shfmt
 | 
			
		||||
      run: curl -sSL https://github.com/mvdan/sh/releases/download/v3.1.2/shfmt_v3.1.2_linux_amd64 -o ~/shfmt && chmod +x ~/shfmt
 | 
			
		||||
    - name: shfmt
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										13
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								Dockerfile
									
									
									
									
									
								
							@@ -1,4 +1,4 @@
 | 
			
		||||
FROM alpine:3.15
 | 
			
		||||
FROM alpine:3.17
 | 
			
		||||
 | 
			
		||||
RUN apk --no-cache add -f \
 | 
			
		||||
  openssl \
 | 
			
		||||
@@ -12,7 +12,8 @@ RUN apk --no-cache add -f \
 | 
			
		||||
  oath-toolkit-oathtool \
 | 
			
		||||
  tar \
 | 
			
		||||
  libidn \
 | 
			
		||||
  jq
 | 
			
		||||
  jq \
 | 
			
		||||
  cronie
 | 
			
		||||
 | 
			
		||||
ENV LE_CONFIG_HOME /acme.sh
 | 
			
		||||
 | 
			
		||||
@@ -25,7 +26,7 @@ COPY ./ /install_acme.sh/
 | 
			
		||||
RUN cd /install_acme.sh && ([ -f /install_acme.sh/acme.sh ] && /install_acme.sh/acme.sh --install || curl https://get.acme.sh | sh) && rm -rf /install_acme.sh/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
RUN ln -s  /root/.acme.sh/acme.sh  /usr/local/bin/acme.sh && crontab -l | grep acme.sh | sed 's#> /dev/null##' | crontab -
 | 
			
		||||
RUN ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh && crontab -l | grep acme.sh | sed 's#> /dev/null#> /proc/1/fd/1 2>/proc/1/fd/2#' | crontab -
 | 
			
		||||
 | 
			
		||||
RUN for verb in help \
 | 
			
		||||
  version \
 | 
			
		||||
@@ -64,12 +65,10 @@ RUN for verb in help \
 | 
			
		||||
 | 
			
		||||
RUN printf "%b" '#!'"/usr/bin/env sh\n \
 | 
			
		||||
if [ \"\$1\" = \"daemon\" ];  then \n \
 | 
			
		||||
 trap \"echo stop && killall crond && exit 0\" SIGTERM SIGINT \n \
 | 
			
		||||
 crond && sleep infinity &\n \
 | 
			
		||||
 wait \n \
 | 
			
		||||
 exec crond -n -s -m off \n \
 | 
			
		||||
else \n \
 | 
			
		||||
 exec -- \"\$@\"\n \
 | 
			
		||||
fi" >/entry.sh && chmod +x /entry.sh
 | 
			
		||||
fi\n" >/entry.sh && chmod +x /entry.sh
 | 
			
		||||
 | 
			
		||||
VOLUME /acme.sh
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										53
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										53
									
								
								README.md
									
									
									
									
									
								
							@@ -1,10 +1,14 @@
 | 
			
		||||
# An ACME Shell script: acme.sh 
 | 
			
		||||
 | 
			
		||||
[](https://github.com/acmesh-official/acme.sh/actions/workflows/FreeBSD.yml)
 | 
			
		||||
[](https://github.com/acmesh-official/acme.sh/actions/workflows/OpenBSD.yml)
 | 
			
		||||
[](https://github.com/acmesh-official/acme.sh/actions/workflows/NetBSD.yml)
 | 
			
		||||
[](https://github.com/acmesh-official/acme.sh/actions/workflows/MacOS.yml)
 | 
			
		||||
[](https://github.com/acmesh-official/acme.sh/actions/workflows/Ubuntu.yml)
 | 
			
		||||
[](https://github.com/acmesh-official/acme.sh/actions/workflows/Windows.yml)
 | 
			
		||||
[](https://github.com/acmesh-official/acme.sh/actions/workflows/Solaris.yml)
 | 
			
		||||
[](https://github.com/acmesh-official/acme.sh/actions/workflows/DragonFlyBSD.yml)
 | 
			
		||||
[](https://github.com/acmesh-official/acme.sh/actions/workflows/Omnios.yml)
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||

 | 
			
		||||
@@ -47,14 +51,12 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa)
 | 
			
		||||
- [ruby-china.org](https://ruby-china.org/topics/31983)
 | 
			
		||||
- [Proxmox](https://pve.proxmox.com/wiki/Certificate_Management)
 | 
			
		||||
- [pfsense](https://github.com/pfsense/FreeBSD-ports/pull/89)
 | 
			
		||||
- [webfaction](https://community.webfaction.com/questions/19988/using-letsencrypt)
 | 
			
		||||
- [Loadbalancer.org](https://www.loadbalancer.org/blog/loadbalancer-org-with-lets-encrypt-quick-and-dirty)
 | 
			
		||||
- [discourse.org](https://meta.discourse.org/t/setting-up-lets-encrypt/40709)
 | 
			
		||||
- [Centminmod](https://centminmod.com/letsencrypt-acmetool-https.html)
 | 
			
		||||
- [splynx](https://forum.splynx.com/t/free-ssl-cert-for-splynx-lets-encrypt/297)
 | 
			
		||||
- [archlinux](https://www.archlinux.org/packages/community/any/acme.sh)
 | 
			
		||||
- [opnsense.org](https://github.com/opnsense/plugins/tree/master/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient)
 | 
			
		||||
- [CentOS Web Panel](http://centos-webpanel.com/)
 | 
			
		||||
- [CentOS Web Panel](https://control-webpanel.com)
 | 
			
		||||
- [lnmp.org](https://lnmp.org/)
 | 
			
		||||
- [more...](https://github.com/acmesh-official/acme.sh/wiki/Blogs-and-tutorials)
 | 
			
		||||
 | 
			
		||||
@@ -68,21 +70,24 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa)
 | 
			
		||||
|4|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Solaris.yml)|Solaris
 | 
			
		||||
|5|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Ubuntu.yml)| Ubuntu
 | 
			
		||||
|6|NA|pfsense
 | 
			
		||||
|7|NA|OpenBSD
 | 
			
		||||
|8|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)| Debian
 | 
			
		||||
|9|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|CentOS
 | 
			
		||||
|10|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|openSUSE
 | 
			
		||||
|11|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Alpine Linux (with curl)
 | 
			
		||||
|12|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Archlinux
 | 
			
		||||
|13|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|fedora
 | 
			
		||||
|14|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Kali Linux
 | 
			
		||||
|15|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Oracle Linux
 | 
			
		||||
|16|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Mageia
 | 
			
		||||
|17|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Gentoo Linux
 | 
			
		||||
|18|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|ClearLinux
 | 
			
		||||
|19|-----| Cloud Linux  https://github.com/acmesh-official/acme.sh/issues/111
 | 
			
		||||
|20|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/acmesh-official/acme.sh/wiki/How-to-run-on-OpenWRT)
 | 
			
		||||
|21|[](https://github.com/acmesh-official/letest#here-are-the-latest-status)| Proxmox: See Proxmox VE Wiki. Version [4.x, 5.0, 5.1](https://pve.proxmox.com/wiki/HTTPS_Certificate_Configuration_(Version_4.x,_5.0_and_5.1)#Let.27s_Encrypt_using_acme.sh), version [5.2 and up](https://pve.proxmox.com/wiki/Certificate_Management)
 | 
			
		||||
|7|[](https://github.com/acmesh-official/acme.sh/actions/workflows/OpenBSD.yml)|OpenBSD
 | 
			
		||||
|8|[](https://github.com/acmesh-official/acme.sh/actions/workflows/NetBSD.yml)|NetBSD
 | 
			
		||||
|9|[](https://github.com/acmesh-official/acme.sh/actions/workflows/DragonFlyBSD.yml)|DragonFlyBSD
 | 
			
		||||
|10|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Omnios.yml)|Omnios
 | 
			
		||||
|11|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)| Debian
 | 
			
		||||
|12|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|CentOS
 | 
			
		||||
|13|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|openSUSE
 | 
			
		||||
|14|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Alpine Linux (with curl)
 | 
			
		||||
|15|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Archlinux
 | 
			
		||||
|16|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|fedora
 | 
			
		||||
|17|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Kali Linux
 | 
			
		||||
|18|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Oracle Linux
 | 
			
		||||
|19|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Mageia
 | 
			
		||||
|10|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Gentoo Linux
 | 
			
		||||
|11|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|ClearLinux
 | 
			
		||||
|22|-----| Cloud Linux  https://github.com/acmesh-official/acme.sh/issues/111
 | 
			
		||||
|23|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/acmesh-official/acme.sh/wiki/How-to-run-on-OpenWRT)
 | 
			
		||||
|24|[](https://github.com/acmesh-official/letest#here-are-the-latest-status)| Proxmox: See Proxmox VE Wiki. Version [4.x, 5.0, 5.1](https://pve.proxmox.com/wiki/HTTPS_Certificate_Configuration_(Version_4.x,_5.0_and_5.1)#Let.27s_Encrypt_using_acme.sh), version [5.2 and up](https://pve.proxmox.com/wiki/Certificate_Management)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Check our [testing project](https://github.com/acmesh-official/acmetest):
 | 
			
		||||
@@ -355,10 +360,6 @@ Ok, it's done.
 | 
			
		||||
 | 
			
		||||
# 10. Issue ECC certificates
 | 
			
		||||
 | 
			
		||||
`Let's Encrypt` can now issue **ECDSA** certificates.
 | 
			
		||||
 | 
			
		||||
And we support them too!
 | 
			
		||||
 | 
			
		||||
Just set the `keylength` parameter with a prefix `ec-`.
 | 
			
		||||
 | 
			
		||||
For example:
 | 
			
		||||
@@ -379,10 +380,12 @@ Please look at the `keylength` parameter above.
 | 
			
		||||
 | 
			
		||||
Valid values are:
 | 
			
		||||
 | 
			
		||||
1. **ec-256 (prime256v1, "ECDSA P-256")**
 | 
			
		||||
1. **ec-256 (prime256v1, "ECDSA P-256", which is the default key type)**
 | 
			
		||||
2. **ec-384 (secp384r1,  "ECDSA P-384")**
 | 
			
		||||
3. **ec-521 (secp521r1,  "ECDSA P-521", which is not supported by Let's Encrypt yet.)**
 | 
			
		||||
 | 
			
		||||
4. **2048   (RSA2048)**
 | 
			
		||||
5. **3072   (RSA3072)**
 | 
			
		||||
6. **4096   (RSA4096)**
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 11. Issue Wildcard certificates
 | 
			
		||||
@@ -503,6 +506,8 @@ Support this project with your organization. Your logo will show up here with a
 | 
			
		||||
<a href="https://opencollective.com/acmesh/organization/8/website"><img src="https://opencollective.com/acmesh/organization/8/avatar.svg"></a>
 | 
			
		||||
<a href="https://opencollective.com/acmesh/organization/9/website"><img src="https://opencollective.com/acmesh/organization/9/avatar.svg"></a>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 19. License & Others
 | 
			
		||||
 | 
			
		||||
License is GPLv3
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										157
									
								
								deploy/ali_cdn.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								deploy/ali_cdn.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,157 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
# Script to create certificate to Alibaba Cloud CDN
 | 
			
		||||
#
 | 
			
		||||
# This deployment required following variables
 | 
			
		||||
# export Ali_Key="ALIACCESSKEY"
 | 
			
		||||
# export Ali_Secret="ALISECRETKEY"
 | 
			
		||||
# export DEPLOY_ALI_CDN_DOMAIN="cdn.example.com"
 | 
			
		||||
# If you have more than one domain, just
 | 
			
		||||
# export DEPLOY_ALI_CDN_DOMAIN="cdn1.example.com cdn2.example.com"
 | 
			
		||||
#
 | 
			
		||||
# The credentials are shared with all domains, also shared with dns_ali api
 | 
			
		||||
 | 
			
		||||
Ali_API="https://cdn.aliyuncs.com/"
 | 
			
		||||
 | 
			
		||||
ali_cdn_deploy() {
 | 
			
		||||
  _cdomain="$1"
 | 
			
		||||
  _ckey="$2"
 | 
			
		||||
  _ccert="$3"
 | 
			
		||||
  _cca="$4"
 | 
			
		||||
  _cfullchain="$5"
 | 
			
		||||
 | 
			
		||||
  _debug _cdomain "$_cdomain"
 | 
			
		||||
  _debug _ckey "$_ckey"
 | 
			
		||||
  _debug _ccert "$_ccert"
 | 
			
		||||
  _debug _cca "$_cca"
 | 
			
		||||
  _debug _cfullchain "$_cfullchain"
 | 
			
		||||
 | 
			
		||||
  Ali_Key="${Ali_Key:-$(_readaccountconf_mutable Ali_Key)}"
 | 
			
		||||
  Ali_Secret="${Ali_Secret:-$(_readaccountconf_mutable Ali_Secret)}"
 | 
			
		||||
  if [ -z "$Ali_Key" ] || [ -z "$Ali_Secret" ]; then
 | 
			
		||||
    Ali_Key=""
 | 
			
		||||
    Ali_Secret=""
 | 
			
		||||
    _err "You don't specify aliyun api key and secret yet."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  #save the api key and secret to the account conf file.
 | 
			
		||||
  _saveaccountconf_mutable Ali_Key "$Ali_Key"
 | 
			
		||||
  _saveaccountconf_mutable Ali_Secret "$Ali_Secret"
 | 
			
		||||
 | 
			
		||||
  _getdeployconf DEPLOY_ALI_CDN_DOMAIN
 | 
			
		||||
  if [ "$DEPLOY_ALI_CDN_DOMAIN" ]; then
 | 
			
		||||
    _savedeployconf DEPLOY_ALI_CDN_DOMAIN "$DEPLOY_ALI_CDN_DOMAIN"
 | 
			
		||||
  else
 | 
			
		||||
    DEPLOY_ALI_CDN_DOMAIN="$_cdomain"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # read cert and key files and urlencode both
 | 
			
		||||
  _cert=$(_url_encode_upper <"$_cfullchain")
 | 
			
		||||
  _key=$(_url_encode_upper <"$_ckey")
 | 
			
		||||
 | 
			
		||||
  _debug2 _cert "$_cert"
 | 
			
		||||
  _debug2 _key "$_key"
 | 
			
		||||
 | 
			
		||||
  ## update domain ssl config
 | 
			
		||||
  for domain in $DEPLOY_ALI_CDN_DOMAIN; do
 | 
			
		||||
    _set_cdn_domain_ssl_certificate_query "$domain" "$_cert" "$_key"
 | 
			
		||||
    if _ali_rest "Set CDN domain SSL certificate for $domain" "" POST; then
 | 
			
		||||
      _info "Domain $domain certificate has been deployed successfully"
 | 
			
		||||
    fi
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
 | 
			
		||||
# act ign mtd
 | 
			
		||||
_ali_rest() {
 | 
			
		||||
  act="$1"
 | 
			
		||||
  ign="$2"
 | 
			
		||||
  mtd="$3"
 | 
			
		||||
 | 
			
		||||
  signature=$(printf "%s" "$mtd&%2F&$(_ali_urlencode "$query")" | _hmac "sha1" "$(printf "%s" "$Ali_Secret&" | _hex_dump | tr -d " ")" | _base64)
 | 
			
		||||
  signature=$(_ali_urlencode "$signature")
 | 
			
		||||
  url="$Ali_API?$query&Signature=$signature"
 | 
			
		||||
 | 
			
		||||
  if [ "$mtd" = "GET" ]; then
 | 
			
		||||
    response="$(_get "$url")"
 | 
			
		||||
  else
 | 
			
		||||
    # post payload is not supported yet because of signature
 | 
			
		||||
    response="$(_post "" "$url")"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _ret="$?"
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
  if [ "$_ret" != "0" ]; then
 | 
			
		||||
    _err "Error <$act>"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "$ign" ]; then
 | 
			
		||||
    message="$(echo "$response" | _egrep_o "\"Message\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")"
 | 
			
		||||
    if [ "$message" ]; then
 | 
			
		||||
      _err "$message"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_ali_urlencode() {
 | 
			
		||||
  _str="$1"
 | 
			
		||||
  _str_len=${#_str}
 | 
			
		||||
  _u_i=1
 | 
			
		||||
  while [ "$_u_i" -le "$_str_len" ]; do
 | 
			
		||||
    _str_c="$(printf "%s" "$_str" | cut -c "$_u_i")"
 | 
			
		||||
    case $_str_c in [a-zA-Z0-9.~_-])
 | 
			
		||||
      printf "%s" "$_str_c"
 | 
			
		||||
      ;;
 | 
			
		||||
    *)
 | 
			
		||||
      printf "%%%02X" "'$_str_c"
 | 
			
		||||
      ;;
 | 
			
		||||
    esac
 | 
			
		||||
    _u_i="$(_math "$_u_i" + 1)"
 | 
			
		||||
  done
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_ali_nonce() {
 | 
			
		||||
  #_head_n 1 </dev/urandom | _digest "sha256" hex | cut -c 1-31
 | 
			
		||||
  #Not so good...
 | 
			
		||||
  date +"%s%N" | sed 's/%N//g'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_timestamp() {
 | 
			
		||||
  date -u +"%Y-%m-%dT%H%%3A%M%%3A%SZ"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# stdin stdout
 | 
			
		||||
_url_encode_upper() {
 | 
			
		||||
  encoded=$(_url_encode)
 | 
			
		||||
 | 
			
		||||
  for match in $(echo "$encoded" | _egrep_o '%..' | sort -u); do
 | 
			
		||||
    upper=$(echo "$match" | _upper_case)
 | 
			
		||||
    encoded=$(echo "$encoded" | sed "s/$match/$upper/g")
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  echo "$encoded"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# domain pub pri
 | 
			
		||||
_set_cdn_domain_ssl_certificate_query() {
 | 
			
		||||
  query=''
 | 
			
		||||
  query=$query'AccessKeyId='$Ali_Key
 | 
			
		||||
  query=$query'&Action=SetCdnDomainSSLCertificate'
 | 
			
		||||
  query=$query'&CertType=upload'
 | 
			
		||||
  query=$query'&DomainName='$1
 | 
			
		||||
  query=$query'&Format=json'
 | 
			
		||||
  query=$query'&SSLPri='$3
 | 
			
		||||
  query=$query'&SSLProtocol=on'
 | 
			
		||||
  query=$query'&SSLPub='$2
 | 
			
		||||
  query=$query'&SignatureMethod=HMAC-SHA1'
 | 
			
		||||
  query=$query"&SignatureNonce=$(_ali_nonce)"
 | 
			
		||||
  query=$query'&SignatureVersion=1.0'
 | 
			
		||||
  query=$query'&Timestamp='$(_timestamp)
 | 
			
		||||
  query=$query'&Version=2018-05-10'
 | 
			
		||||
}
 | 
			
		||||
@@ -3,18 +3,29 @@
 | 
			
		||||
# Uses command line uapi.  --user option is needed only if run as root.
 | 
			
		||||
# Returns 0 when success.
 | 
			
		||||
#
 | 
			
		||||
# Configure DEPLOY_CPANEL_AUTO_<...> options to enable or restrict automatic
 | 
			
		||||
# detection of deployment targets through UAPI (if not set, defaults below are used.)
 | 
			
		||||
# - ENABLED : 'true' for multi-site / wildcard capability; otherwise single-site mode.
 | 
			
		||||
# - NOMATCH : 'true' to allow deployment to sites that do not match the certificate.
 | 
			
		||||
# - INCLUDE : Comma-separated list - sites must match this field.
 | 
			
		||||
# - EXCLUDE : Comma-separated list - sites must NOT match this field.
 | 
			
		||||
# INCLUDE/EXCLUDE both support non-lexical, glob-style matches using '*'
 | 
			
		||||
#
 | 
			
		||||
# Please note that I am no longer using Github. If you want to report an issue
 | 
			
		||||
# or contact me, visit https://forum.webseodesigners.com/web-design-seo-and-hosting-f16/
 | 
			
		||||
#
 | 
			
		||||
# Written by Santeri Kannisto <santeri.kannisto@webseodesigners.com>
 | 
			
		||||
# Public domain, 2017-2018
 | 
			
		||||
 | 
			
		||||
#export DEPLOY_CPANEL_USER=myusername
 | 
			
		||||
#
 | 
			
		||||
# export DEPLOY_CPANEL_USER=myusername
 | 
			
		||||
# export DEPLOY_CPANEL_AUTO_ENABLED='true'
 | 
			
		||||
# export DEPLOY_CPANEL_AUTO_NOMATCH='false'
 | 
			
		||||
# export DEPLOY_CPANEL_AUTO_INCLUDE='*'
 | 
			
		||||
# export DEPLOY_CPANEL_AUTO_EXCLUDE=''
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#domain keyfile certfile cafile fullchain
 | 
			
		||||
 | 
			
		||||
cpanel_uapi_deploy() {
 | 
			
		||||
  _cdomain="$1"
 | 
			
		||||
  _ckey="$2"
 | 
			
		||||
@@ -22,6 +33,9 @@ cpanel_uapi_deploy() {
 | 
			
		||||
  _cca="$4"
 | 
			
		||||
  _cfullchain="$5"
 | 
			
		||||
 | 
			
		||||
  # re-declare vars inherited from acme.sh but not passed to make ShellCheck happy
 | 
			
		||||
  : "${Le_Alt:=""}"
 | 
			
		||||
 | 
			
		||||
  _debug _cdomain "$_cdomain"
 | 
			
		||||
  _debug _ckey "$_ckey"
 | 
			
		||||
  _debug _ccert "$_ccert"
 | 
			
		||||
@@ -32,31 +46,166 @@ cpanel_uapi_deploy() {
 | 
			
		||||
    _err "The command uapi is not found."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # declare useful constants
 | 
			
		||||
  uapi_error_response='status: 0'
 | 
			
		||||
 | 
			
		||||
  # read cert and key files and urlencode both
 | 
			
		||||
  _cert=$(_url_encode <"$_ccert")
 | 
			
		||||
  _key=$(_url_encode <"$_ckey")
 | 
			
		||||
 | 
			
		||||
  _debug _cert "$_cert"
 | 
			
		||||
  _debug _key "$_key"
 | 
			
		||||
  _debug2 _cert "$_cert"
 | 
			
		||||
  _debug2 _key "$_key"
 | 
			
		||||
 | 
			
		||||
  if [ "$(id -u)" = 0 ]; then
 | 
			
		||||
    if [ -z "$DEPLOY_CPANEL_USER" ]; then
 | 
			
		||||
    _getdeployconf DEPLOY_CPANEL_USER
 | 
			
		||||
    # fallback to _readdomainconf for old installs
 | 
			
		||||
    if [ -z "${DEPLOY_CPANEL_USER:=$(_readdomainconf DEPLOY_CPANEL_USER)}" ]; then
 | 
			
		||||
      _err "It seems that you are root, please define the target user name: export DEPLOY_CPANEL_USER=username"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    _savedomainconf DEPLOY_CPANEL_USER "$DEPLOY_CPANEL_USER"
 | 
			
		||||
    _response=$(uapi --user="$DEPLOY_CPANEL_USER" SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key")
 | 
			
		||||
  else
 | 
			
		||||
    _response=$(uapi SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key")
 | 
			
		||||
  fi
 | 
			
		||||
  error_response="status: 0"
 | 
			
		||||
  if test "${_response#*$error_response}" != "$_response"; then
 | 
			
		||||
    _err "Error in deploying certificate:"
 | 
			
		||||
    _err "$_response"
 | 
			
		||||
    return 1
 | 
			
		||||
    _debug DEPLOY_CPANEL_USER "$DEPLOY_CPANEL_USER"
 | 
			
		||||
    _savedeployconf DEPLOY_CPANEL_USER "$DEPLOY_CPANEL_USER"
 | 
			
		||||
 | 
			
		||||
    _uapi_user="$DEPLOY_CPANEL_USER"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug response "$_response"
 | 
			
		||||
  _info "Certificate successfully deployed"
 | 
			
		||||
  return 0
 | 
			
		||||
  # Load all AUTO envars and set defaults - see above for usage
 | 
			
		||||
  __cpanel_initautoparam ENABLED 'true'
 | 
			
		||||
  __cpanel_initautoparam NOMATCH 'false'
 | 
			
		||||
  __cpanel_initautoparam INCLUDE '*'
 | 
			
		||||
  __cpanel_initautoparam EXCLUDE ''
 | 
			
		||||
 | 
			
		||||
  # Auto mode
 | 
			
		||||
  if [ "$DEPLOY_CPANEL_AUTO_ENABLED" = "true" ]; then
 | 
			
		||||
    # call API for site config
 | 
			
		||||
    _response=$(uapi DomainInfo list_domains)
 | 
			
		||||
    # exit if error in response
 | 
			
		||||
    if [ -z "$_response" ] || [ "${_response#*"$uapi_error_response"}" != "$_response" ]; then
 | 
			
		||||
      _err "Error in deploying certificate - cannot retrieve sitelist:"
 | 
			
		||||
      _err "\n$_response"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # parse response to create site list
 | 
			
		||||
    sitelist=$(__cpanel_parse_response "$_response")
 | 
			
		||||
    _debug "UAPI sites found: $sitelist"
 | 
			
		||||
 | 
			
		||||
    # filter sitelist using configured domains
 | 
			
		||||
    # skip if NOMATCH is "true"
 | 
			
		||||
    if [ "$DEPLOY_CPANEL_AUTO_NOMATCH" = "true" ]; then
 | 
			
		||||
      _debug "DEPLOY_CPANEL_AUTO_NOMATCH is true"
 | 
			
		||||
      _info "UAPI nomatch mode is enabled - Will not validate sites are valid for the certificate"
 | 
			
		||||
    else
 | 
			
		||||
      _debug "DEPLOY_CPANEL_AUTO_NOMATCH is false"
 | 
			
		||||
      d="$(echo "${Le_Alt}," | sed -e "s/^$_cdomain,//" -e "s/,$_cdomain,/,/")"
 | 
			
		||||
      d="$(echo "$_cdomain,$d" | tr ',' '\n' | sed -e 's/\./\\./g' -e 's/\*/\[\^\.\]\*/g')"
 | 
			
		||||
      sitelist="$(echo "$sitelist" | grep -ix "$d")"
 | 
			
		||||
      _debug2 "Matched UAPI sites: $sitelist"
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # filter sites that do not match $DEPLOY_CPANEL_AUTO_INCLUDE
 | 
			
		||||
    _info "Applying sitelist filter DEPLOY_CPANEL_AUTO_INCLUDE: $DEPLOY_CPANEL_AUTO_INCLUDE"
 | 
			
		||||
    sitelist="$(echo "$sitelist" | grep -ix "$(echo "$DEPLOY_CPANEL_AUTO_INCLUDE" | tr ',' '\n' | sed -e 's/\./\\./g' -e 's/\*/\.\*/g')")"
 | 
			
		||||
    _debug2 "Remaining sites: $sitelist"
 | 
			
		||||
 | 
			
		||||
    # filter sites that match $DEPLOY_CPANEL_AUTO_EXCLUDE
 | 
			
		||||
    _info "Applying sitelist filter DEPLOY_CPANEL_AUTO_EXCLUDE: $DEPLOY_CPANEL_AUTO_EXCLUDE"
 | 
			
		||||
    sitelist="$(echo "$sitelist" | grep -vix "$(echo "$DEPLOY_CPANEL_AUTO_EXCLUDE" | tr ',' '\n' | sed -e 's/\./\\./g' -e 's/\*/\.\*/g')")"
 | 
			
		||||
    _debug2 "Remaining sites: $sitelist"
 | 
			
		||||
 | 
			
		||||
    # counter for success / failure check
 | 
			
		||||
    successes=0
 | 
			
		||||
    if [ -n "$sitelist" ]; then
 | 
			
		||||
      sitetotal="$(echo "$sitelist" | wc -l)"
 | 
			
		||||
      _debug "$sitetotal sites to deploy"
 | 
			
		||||
    else
 | 
			
		||||
      sitetotal=0
 | 
			
		||||
      _debug "No sites to deploy"
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # for each site: call uapi to publish cert and log result. Only return failure if all fail
 | 
			
		||||
    for site in $sitelist; do
 | 
			
		||||
      # call uapi to publish cert, check response for errors and log them.
 | 
			
		||||
      if [ -n "$_uapi_user" ]; then
 | 
			
		||||
        _response=$(uapi --user="$_uapi_user" SSL install_ssl domain="$site" cert="$_cert" key="$_key")
 | 
			
		||||
      else
 | 
			
		||||
        _response=$(uapi SSL install_ssl domain="$site" cert="$_cert" key="$_key")
 | 
			
		||||
      fi
 | 
			
		||||
      if [ "${_response#*"$uapi_error_response"}" != "$_response" ]; then
 | 
			
		||||
        _err "Error in deploying certificate to $site:"
 | 
			
		||||
        _err "$_response"
 | 
			
		||||
      else
 | 
			
		||||
        successes=$((successes + 1))
 | 
			
		||||
        _debug "$_response"
 | 
			
		||||
        _info "Succcessfully deployed to $site"
 | 
			
		||||
      fi
 | 
			
		||||
    done
 | 
			
		||||
 | 
			
		||||
    # Raise error if all updates fail
 | 
			
		||||
    if [ "$sitetotal" -gt 0 ] && [ "$successes" -eq 0 ]; then
 | 
			
		||||
      _err "Could not deploy to any of $sitetotal sites via UAPI"
 | 
			
		||||
      _debug "successes: $successes, sitetotal: $sitetotal"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    _info "Successfully deployed certificate to $successes of $sitetotal sites via UAPI"
 | 
			
		||||
    return 0
 | 
			
		||||
  else
 | 
			
		||||
    # "classic" mode - will only try to deploy to the primary domain; will not check UAPI first
 | 
			
		||||
    if [ -n "$_uapi_user" ]; then
 | 
			
		||||
      _response=$(uapi --user="$_uapi_user" SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key")
 | 
			
		||||
    else
 | 
			
		||||
      _response=$(uapi SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key")
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if [ "${_response#*"$uapi_error_response"}" != "$_response" ]; then
 | 
			
		||||
      _err "Error in deploying certificate:"
 | 
			
		||||
      _err "$_response"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    _debug response "$_response"
 | 
			
		||||
    _info "Certificate successfully deployed"
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
########  Private functions #####################
 | 
			
		||||
 | 
			
		||||
# Internal utility to process YML from UAPI - looks at main_domain, sub_domains, addon domains and parked domains
 | 
			
		||||
#[response]
 | 
			
		||||
__cpanel_parse_response() {
 | 
			
		||||
  if [ $# -gt 0 ]; then resp="$*"; else resp="$(cat)"; fi
 | 
			
		||||
 | 
			
		||||
  echo "$resp" |
 | 
			
		||||
    sed -En \
 | 
			
		||||
      -e 's/\r$//' \
 | 
			
		||||
      -e 's/^( *)([_.[:alnum:]]+) *: *(.*)/\1,\2,\3/p' \
 | 
			
		||||
      -e 's/^( *)- (.*)/\1,-,\2/p' |
 | 
			
		||||
    awk -F, '{
 | 
			
		||||
      level = length($1)/2;
 | 
			
		||||
      section[level] = $2;
 | 
			
		||||
      for (i in section) {if (i > level) {delete section[i]}}
 | 
			
		||||
      if (length($3) > 0) {
 | 
			
		||||
        prefix="";
 | 
			
		||||
        for (i=0; i < level; i++)
 | 
			
		||||
          { prefix = (prefix)(section[i])("/") }
 | 
			
		||||
        printf("%s%s=%s\n", prefix, $2, $3);
 | 
			
		||||
      }
 | 
			
		||||
    }' |
 | 
			
		||||
    sed -En -e 's/^result\/data\/(main_domain|sub_domains\/-|addon_domains\/-|parked_domains\/-)=(.*)$/\2/p'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Load parameter by prefix+name - fallback to default if not set, and save to config
 | 
			
		||||
#pname pdefault
 | 
			
		||||
__cpanel_initautoparam() {
 | 
			
		||||
  pname="$1"
 | 
			
		||||
  pdefault="$2"
 | 
			
		||||
  pkey="DEPLOY_CPANEL_AUTO_$pname"
 | 
			
		||||
 | 
			
		||||
  _getdeployconf "$pkey"
 | 
			
		||||
  [ -n "$(eval echo "\"\$$pkey\"")" ] || eval "$pkey=\"$pdefault\""
 | 
			
		||||
  _debug2 "$pkey" "$(eval echo "\"\$$pkey\"")"
 | 
			
		||||
  _savedeployconf "$pkey" "$(eval echo "\"\$$pkey\"")"
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -273,16 +273,27 @@ _check_curl_version() {
 | 
			
		||||
  _minor="$(_getfield "$_cversion" 2 '.')"
 | 
			
		||||
  _debug2 "_minor" "$_minor"
 | 
			
		||||
 | 
			
		||||
  if [ "$_major$_minor" -lt "740" ]; then
 | 
			
		||||
  if [ "$_major" -ge "8" ]; then
 | 
			
		||||
    #ok
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
  if [ "$_major" = "7" ]; then
 | 
			
		||||
    if [ "$_minor" -lt "40" ]; then
 | 
			
		||||
      _err "curl v$_cversion doesn't support unit socket"
 | 
			
		||||
      _err "Please upgrade to curl 7.40 or later."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    if [ "$_minor" -lt "50" ]; then
 | 
			
		||||
      _debug "Use short host name"
 | 
			
		||||
      export _CURL_NO_HOST=1
 | 
			
		||||
    else
 | 
			
		||||
      export _CURL_NO_HOST=
 | 
			
		||||
    fi
 | 
			
		||||
    return 0
 | 
			
		||||
  else
 | 
			
		||||
    _err "curl v$_cversion doesn't support unit socket"
 | 
			
		||||
    _err "Please upgrade to curl 7.40 or later."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  if [ "$_major$_minor" -lt "750" ]; then
 | 
			
		||||
    _debug "Use short host name"
 | 
			
		||||
    export _CURL_NO_HOST=1
 | 
			
		||||
  else
 | 
			
		||||
    export _CURL_NO_HOST=
 | 
			
		||||
  fi
 | 
			
		||||
  return 0
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,11 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
# Here is the script to deploy the cert to G-Core CDN service (https://gcorelabs.com/ru/) using the G-Core Labs API (https://docs.gcorelabs.com/cdn/).
 | 
			
		||||
# Here is the script to deploy the cert to G-Core CDN service (https://gcore.com/) using the G-Core Labs API (https://apidocs.gcore.com/cdn).
 | 
			
		||||
# Returns 0 when success.
 | 
			
		||||
#
 | 
			
		||||
# Written by temoffey <temofffey@gmail.com>
 | 
			
		||||
# Public domain, 2019
 | 
			
		||||
# Update by DreamOfIce <admin@dreamofice.cn> in 2023
 | 
			
		||||
 | 
			
		||||
#export DEPLOY_GCORE_CDN_USERNAME=myusername
 | 
			
		||||
#export DEPLOY_GCORE_CDN_PASSWORD=mypassword
 | 
			
		||||
@@ -56,7 +57,7 @@ gcore_cdn_deploy() {
 | 
			
		||||
  _request="{\"username\":\"$Le_Deploy_gcore_cdn_username\",\"password\":\"$Le_Deploy_gcore_cdn_password\"}"
 | 
			
		||||
  _debug _request "$_request"
 | 
			
		||||
  export _H1="Content-Type:application/json"
 | 
			
		||||
  _response=$(_post "$_request" "https://api.gcdn.co/auth/jwt/login")
 | 
			
		||||
  _response=$(_post "$_request" "https://api.gcore.com/auth/jwt/login")
 | 
			
		||||
  _debug _response "$_response"
 | 
			
		||||
  _regex=".*\"access\":\"\([-._0-9A-Za-z]*\)\".*$"
 | 
			
		||||
  _debug _regex "$_regex"
 | 
			
		||||
@@ -69,8 +70,8 @@ gcore_cdn_deploy() {
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Find CDN resource with cname $_cdomain"
 | 
			
		||||
  export _H2="Authorization:Token $_token"
 | 
			
		||||
  _response=$(_get "https://api.gcdn.co/resources")
 | 
			
		||||
  export _H2="Authorization:Bearer $_token"
 | 
			
		||||
  _response=$(_get "https://api.gcore.com/cdn/resources")
 | 
			
		||||
  _debug _response "$_response"
 | 
			
		||||
  _regex="\"primary_resource\":null},"
 | 
			
		||||
  _debug _regex "$_regex"
 | 
			
		||||
@@ -102,7 +103,7 @@ gcore_cdn_deploy() {
 | 
			
		||||
  _date=$(date "+%d.%m.%Y %H:%M:%S")
 | 
			
		||||
  _request="{\"name\":\"$_cdomain ($_date)\",\"sslCertificate\":\"$_fullchain\",\"sslPrivateKey\":\"$_key\"}"
 | 
			
		||||
  _debug _request "$_request"
 | 
			
		||||
  _response=$(_post "$_request" "https://api.gcdn.co/sslData")
 | 
			
		||||
  _response=$(_post "$_request" "https://api.gcore.com/cdn/sslData")
 | 
			
		||||
  _debug _response "$_response"
 | 
			
		||||
  _regex=".*\"id\":\([0-9]*\).*$"
 | 
			
		||||
  _debug _regex "$_regex"
 | 
			
		||||
@@ -117,7 +118,7 @@ gcore_cdn_deploy() {
 | 
			
		||||
  _info "Update CDN resource"
 | 
			
		||||
  _request="{\"originGroup\":$_originGroup,\"sslData\":$_sslDataAdd}"
 | 
			
		||||
  _debug _request "$_request"
 | 
			
		||||
  _response=$(_post "$_request" "https://api.gcdn.co/resources/$_resourceId" '' "PUT")
 | 
			
		||||
  _response=$(_post "$_request" "https://api.gcore.com/cdn/resources/$_resourceId" '' "PUT")
 | 
			
		||||
  _debug _response "$_response"
 | 
			
		||||
  _regex=".*\"sslData\":\([0-9]*\).*$"
 | 
			
		||||
  _debug _regex "$_regex"
 | 
			
		||||
@@ -133,7 +134,7 @@ gcore_cdn_deploy() {
 | 
			
		||||
    _info "Not found old SSL certificate"
 | 
			
		||||
  else
 | 
			
		||||
    _info "Delete old SSL certificate"
 | 
			
		||||
    _response=$(_post '' "https://api.gcdn.co/sslData/$_sslDataOld" '' "DELETE")
 | 
			
		||||
    _response=$(_post '' "https://api.gcore.com/cdn/sslData/$_sslDataOld" '' "DELETE")
 | 
			
		||||
    _debug _response "$_response"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -67,7 +67,7 @@ gitlab_deploy() {
 | 
			
		||||
 | 
			
		||||
  error_response="error"
 | 
			
		||||
 | 
			
		||||
  if test "${_response#*$error_response}" != "$_response"; then
 | 
			
		||||
  if test "${_response#*"$error_response"}" != "$_response"; then
 | 
			
		||||
    _err "Error in deploying certificate:"
 | 
			
		||||
    _err "$_response"
 | 
			
		||||
    return 1
 | 
			
		||||
 
 | 
			
		||||
@@ -36,6 +36,19 @@
 | 
			
		||||
# Note: This functionality requires HAProxy was compiled against
 | 
			
		||||
# a version of OpenSSL that supports this.
 | 
			
		||||
#
 | 
			
		||||
# export DEPLOY_HAPROXY_HOT_UPDATE="yes"
 | 
			
		||||
# export DEPLOY_HAPROXY_STATS_SOCKET="UNIX:/run/haproxy/admin.sock"
 | 
			
		||||
#
 | 
			
		||||
# OPTIONAL: Deploy the certificate over the HAProxy stats socket without
 | 
			
		||||
# needing to reload HAProxy. Default is "no".
 | 
			
		||||
#
 | 
			
		||||
# Require the socat binary. DEPLOY_HAPROXY_STATS_SOCKET variable uses the socat
 | 
			
		||||
# address format.
 | 
			
		||||
#
 | 
			
		||||
# export DEPLOY_HAPROXY_MASTER_CLI="UNIX:/run/haproxy-master.sock"
 | 
			
		||||
#
 | 
			
		||||
# OPTIONAL: To use the master CLI with DEPLOY_HAPROXY_HOT_UPDATE="yes" instead
 | 
			
		||||
# of a stats socket, use this variable.
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
@@ -46,6 +59,7 @@ haproxy_deploy() {
 | 
			
		||||
  _ccert="$3"
 | 
			
		||||
  _cca="$4"
 | 
			
		||||
  _cfullchain="$5"
 | 
			
		||||
  _cmdpfx=""
 | 
			
		||||
 | 
			
		||||
  # Some defaults
 | 
			
		||||
  DEPLOY_HAPROXY_PEM_PATH_DEFAULT="/etc/haproxy"
 | 
			
		||||
@@ -53,6 +67,8 @@ haproxy_deploy() {
 | 
			
		||||
  DEPLOY_HAPROXY_BUNDLE_DEFAULT="no"
 | 
			
		||||
  DEPLOY_HAPROXY_ISSUER_DEFAULT="no"
 | 
			
		||||
  DEPLOY_HAPROXY_RELOAD_DEFAULT="true"
 | 
			
		||||
  DEPLOY_HAPROXY_HOT_UPDATE_DEFAULT="no"
 | 
			
		||||
  DEPLOY_HAPROXY_STATS_SOCKET_DEFAULT="UNIX:/run/haproxy/admin.sock"
 | 
			
		||||
 | 
			
		||||
  _debug _cdomain "${_cdomain}"
 | 
			
		||||
  _debug _ckey "${_ckey}"
 | 
			
		||||
@@ -86,6 +102,11 @@ haproxy_deploy() {
 | 
			
		||||
    _savedomainconf Le_Deploy_haproxy_pem_name "${Le_Deploy_haproxy_pem_name}"
 | 
			
		||||
  elif [ -z "${Le_Deploy_haproxy_pem_name}" ]; then
 | 
			
		||||
    Le_Deploy_haproxy_pem_name="${DEPLOY_HAPROXY_PEM_NAME_DEFAULT}"
 | 
			
		||||
    # We better not have '*' as the first character
 | 
			
		||||
    if [ "${Le_Deploy_haproxy_pem_name%%"${Le_Deploy_haproxy_pem_name#?}"}" = '*' ]; then
 | 
			
		||||
      # removes the first characters and add a _ instead
 | 
			
		||||
      Le_Deploy_haproxy_pem_name="_${Le_Deploy_haproxy_pem_name#?}"
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # BUNDLE is optional. If not provided then assume "${DEPLOY_HAPROXY_BUNDLE_DEFAULT}"
 | 
			
		||||
@@ -118,6 +139,36 @@ haproxy_deploy() {
 | 
			
		||||
    Le_Deploy_haproxy_reload="${DEPLOY_HAPROXY_RELOAD_DEFAULT}"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # HOT_UPDATE is optional. If not provided then assume "${DEPLOY_HAPROXY_HOT_UPDATE_DEFAULT}"
 | 
			
		||||
  _getdeployconf DEPLOY_HAPROXY_HOT_UPDATE
 | 
			
		||||
  _debug2 DEPLOY_HAPROXY_HOT_UPDATE "${DEPLOY_HAPROXY_HOT_UPDATE}"
 | 
			
		||||
  if [ -n "${DEPLOY_HAPROXY_HOT_UPDATE}" ]; then
 | 
			
		||||
    Le_Deploy_haproxy_hot_update="${DEPLOY_HAPROXY_HOT_UPDATE}"
 | 
			
		||||
    _savedomainconf Le_Deploy_haproxy_hot_update "${Le_Deploy_haproxy_hot_update}"
 | 
			
		||||
  elif [ -z "${Le_Deploy_haproxy_hot_update}" ]; then
 | 
			
		||||
    Le_Deploy_haproxy_hot_update="${DEPLOY_HAPROXY_HOT_UPDATE_DEFAULT}"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # STATS_SOCKET is optional. If not provided then assume "${DEPLOY_HAPROXY_STATS_SOCKET_DEFAULT}"
 | 
			
		||||
  _getdeployconf DEPLOY_HAPROXY_STATS_SOCKET
 | 
			
		||||
  _debug2 DEPLOY_HAPROXY_STATS_SOCKET "${DEPLOY_HAPROXY_STATS_SOCKET}"
 | 
			
		||||
  if [ -n "${DEPLOY_HAPROXY_STATS_SOCKET}" ]; then
 | 
			
		||||
    Le_Deploy_haproxy_stats_socket="${DEPLOY_HAPROXY_STATS_SOCKET}"
 | 
			
		||||
    _savedomainconf Le_Deploy_haproxy_stats_socket "${Le_Deploy_haproxy_stats_socket}"
 | 
			
		||||
  elif [ -z "${Le_Deploy_haproxy_stats_socket}" ]; then
 | 
			
		||||
    Le_Deploy_haproxy_stats_socket="${DEPLOY_HAPROXY_STATS_SOCKET_DEFAULT}"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # MASTER_CLI is optional. No defaults are used. When the master CLI is used,
 | 
			
		||||
  # all commands are sent with a prefix.
 | 
			
		||||
  _getdeployconf DEPLOY_HAPROXY_MASTER_CLI
 | 
			
		||||
  _debug2 DEPLOY_HAPROXY_MASTER_CLI "${DEPLOY_HAPROXY_MASTER_CLI}"
 | 
			
		||||
  if [ -n "${DEPLOY_HAPROXY_MASTER_CLI}" ]; then
 | 
			
		||||
    Le_Deploy_haproxy_stats_socket="${DEPLOY_HAPROXY_MASTER_CLI}"
 | 
			
		||||
    _savedomainconf Le_Deploy_haproxy_stats_socket "${Le_Deploy_haproxy_stats_socket}"
 | 
			
		||||
    _cmdpfx="@1 " # command prefix used for master CLI only.
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Set the suffix depending if we are creating a bundle or not
 | 
			
		||||
  if [ "${Le_Deploy_haproxy_bundle}" = "yes" ]; then
 | 
			
		||||
    _info "Bundle creation requested"
 | 
			
		||||
@@ -142,12 +193,13 @@ haproxy_deploy() {
 | 
			
		||||
  _issuer="${_pem}.issuer"
 | 
			
		||||
  _ocsp="${_pem}.ocsp"
 | 
			
		||||
  _reload="${Le_Deploy_haproxy_reload}"
 | 
			
		||||
  _statssock="${Le_Deploy_haproxy_stats_socket}"
 | 
			
		||||
 | 
			
		||||
  _info "Deploying PEM file"
 | 
			
		||||
  # Create a temporary PEM file
 | 
			
		||||
  _temppem="$(_mktemp)"
 | 
			
		||||
  _debug _temppem "${_temppem}"
 | 
			
		||||
  cat "${_ckey}" "${_ccert}" "${_cca}" >"${_temppem}"
 | 
			
		||||
  cat "${_ccert}" "${_cca}" "${_ckey}" | grep . >"${_temppem}"
 | 
			
		||||
  _ret="$?"
 | 
			
		||||
 | 
			
		||||
  # Check that we could create the temporary file
 | 
			
		||||
@@ -265,15 +317,86 @@ haproxy_deploy() {
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Reload HAProxy
 | 
			
		||||
  _debug _reload "${_reload}"
 | 
			
		||||
  eval "${_reload}"
 | 
			
		||||
  _ret=$?
 | 
			
		||||
  if [ "${_ret}" != "0" ]; then
 | 
			
		||||
    _err "Error code ${_ret} during reload"
 | 
			
		||||
    return ${_ret}
 | 
			
		||||
  if [ "${Le_Deploy_haproxy_hot_update}" = "yes" ]; then
 | 
			
		||||
    # set the socket name for messages
 | 
			
		||||
    if [ -n "${_cmdpfx}" ]; then
 | 
			
		||||
      _socketname="master CLI"
 | 
			
		||||
    else
 | 
			
		||||
      _socketname="stats socket"
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # Update certificate over HAProxy stats socket or master CLI.
 | 
			
		||||
    if _exists socat; then
 | 
			
		||||
      # look for the certificate on the stats socket, to chose between updating or creating one
 | 
			
		||||
      _socat_cert_cmd="echo '${_cmdpfx}show ssl cert' | socat '${_statssock}' - | grep -q '^${_pem}$'"
 | 
			
		||||
      _debug _socat_cert_cmd "${_socat_cert_cmd}"
 | 
			
		||||
      eval "${_socat_cert_cmd}"
 | 
			
		||||
      _ret=$?
 | 
			
		||||
      if [ "${_ret}" != "0" ]; then
 | 
			
		||||
        _newcert="1"
 | 
			
		||||
        _info "Creating new certificate '${_pem}' over HAProxy ${_socketname}."
 | 
			
		||||
        # certificate wasn't found, it's a new one. We should check if the crt-list exists and creates/inserts the certificate.
 | 
			
		||||
        _socat_crtlist_show_cmd="echo '${_cmdpfx}show ssl crt-list' | socat '${_statssock}' - | grep -q '^${Le_Deploy_haproxy_pem_path}$'"
 | 
			
		||||
        _debug _socat_crtlist_show_cmd "${_socat_crtlist_show_cmd}"
 | 
			
		||||
        eval "${_socat_crtlist_show_cmd}"
 | 
			
		||||
        _ret=$?
 | 
			
		||||
        if [ "${_ret}" != "0" ]; then
 | 
			
		||||
          _err "Couldn't find '${Le_Deploy_haproxy_pem_path}' in haproxy 'show ssl crt-list'"
 | 
			
		||||
          return "${_ret}"
 | 
			
		||||
        fi
 | 
			
		||||
        # create a new certificate
 | 
			
		||||
        _socat_new_cmd="echo '${_cmdpfx}new ssl cert ${_pem}' | socat '${_statssock}' - | grep -q 'New empty'"
 | 
			
		||||
        _debug _socat_new_cmd "${_socat_new_cmd}"
 | 
			
		||||
        eval "${_socat_new_cmd}"
 | 
			
		||||
        _ret=$?
 | 
			
		||||
        if [ "${_ret}" != "0" ]; then
 | 
			
		||||
          _err "Couldn't create '${_pem}' in haproxy"
 | 
			
		||||
          return "${_ret}"
 | 
			
		||||
        fi
 | 
			
		||||
      else
 | 
			
		||||
        _info "Update existing certificate '${_pem}' over HAProxy ${_socketname}."
 | 
			
		||||
      fi
 | 
			
		||||
      _socat_cert_set_cmd="echo -e '${_cmdpfx}set ssl cert ${_pem} <<\n$(cat "${_pem}")\n' | socat '${_statssock}' - | grep -q 'Transaction created'"
 | 
			
		||||
      _debug _socat_cert_set_cmd "${_socat_cert_set_cmd}"
 | 
			
		||||
      eval "${_socat_cert_set_cmd}"
 | 
			
		||||
      _ret=$?
 | 
			
		||||
      if [ "${_ret}" != "0" ]; then
 | 
			
		||||
        _err "Can't update '${_pem}' in haproxy"
 | 
			
		||||
        return "${_ret}"
 | 
			
		||||
      fi
 | 
			
		||||
      _socat_cert_commit_cmd="echo '${_cmdpfx}commit ssl cert ${_pem}' | socat '${_statssock}' - | grep -q '^Success!$'"
 | 
			
		||||
      _debug _socat_cert_commit_cmd "${_socat_cert_commit_cmd}"
 | 
			
		||||
      eval "${_socat_cert_commit_cmd}"
 | 
			
		||||
      _ret=$?
 | 
			
		||||
      if [ "${_ret}" != "0" ]; then
 | 
			
		||||
        _err "Can't commit '${_pem}' in haproxy"
 | 
			
		||||
        return ${_ret}
 | 
			
		||||
      fi
 | 
			
		||||
      if [ "${_newcert}" = "1" ]; then
 | 
			
		||||
        # if this is a new certificate, it needs to be inserted into the crt-list`
 | 
			
		||||
        _socat_cert_add_cmd="echo '${_cmdpfx}add ssl crt-list ${Le_Deploy_haproxy_pem_path} ${_pem}' | socat '${_statssock}' - | grep -q 'Success!'"
 | 
			
		||||
        _debug _socat_cert_add_cmd "${_socat_cert_add_cmd}"
 | 
			
		||||
        eval "${_socat_cert_add_cmd}"
 | 
			
		||||
        _ret=$?
 | 
			
		||||
        if [ "${_ret}" != "0" ]; then
 | 
			
		||||
          _err "Can't update '${_pem}' in haproxy"
 | 
			
		||||
          return "${_ret}"
 | 
			
		||||
        fi
 | 
			
		||||
      fi
 | 
			
		||||
    else
 | 
			
		||||
      _err "'socat' is not available, couldn't update over ${_socketname}"
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    _info "Reload successful"
 | 
			
		||||
    # Reload HAProxy
 | 
			
		||||
    _debug _reload "${_reload}"
 | 
			
		||||
    eval "${_reload}"
 | 
			
		||||
    _ret=$?
 | 
			
		||||
    if [ "${_ret}" != "0" ]; then
 | 
			
		||||
      _err "Error code ${_ret} during reload"
 | 
			
		||||
      return ${_ret}
 | 
			
		||||
    else
 | 
			
		||||
      _info "Reload successful"
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
 
 | 
			
		||||
@@ -44,30 +44,20 @@ mailcow_deploy() {
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # ECC or RSA
 | 
			
		||||
  length=$(_readdomainconf Le_Keylength)
 | 
			
		||||
  if _isEccKey "$length"; then
 | 
			
		||||
    _info "ECC key type detected"
 | 
			
		||||
    _cert_name_prefix="ecdsa-"
 | 
			
		||||
  else
 | 
			
		||||
    _info "RSA key type detected"
 | 
			
		||||
    _cert_name_prefix=""
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Copying key and cert"
 | 
			
		||||
  _real_key="$_ssl_path/${_cert_name_prefix}key.pem"
 | 
			
		||||
  _real_key="$_ssl_path/key.pem"
 | 
			
		||||
  if ! cat "$_ckey" >"$_real_key"; then
 | 
			
		||||
    _err "Error: write key file to: $_real_key"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _real_fullchain="$_ssl_path/${_cert_name_prefix}cert.pem"
 | 
			
		||||
  _real_fullchain="$_ssl_path/cert.pem"
 | 
			
		||||
  if ! cat "$_cfullchain" >"$_real_fullchain"; then
 | 
			
		||||
    _err "Error: write cert file to: $_real_fullchain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  DEFAULT_MAILCOW_RELOAD="docker restart \$(docker ps --quiet --filter name=nginx-mailcow --filter name=dovecot-mailcow)"
 | 
			
		||||
  DEFAULT_MAILCOW_RELOAD="docker restart \$(docker ps --quiet --filter name=nginx-mailcow --filter name=dovecot-mailcow --filter name=postfix-mailcow)"
 | 
			
		||||
  _reload="${DEPLOY_MAILCOW_RELOAD:-$DEFAULT_MAILCOW_RELOAD}"
 | 
			
		||||
 | 
			
		||||
  _info "Run reload: $_reload"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										183
									
								
								deploy/panos.sh
									
									
									
									
									
								
							
							
						
						
									
										183
									
								
								deploy/panos.sh
									
									
									
									
									
								
							@@ -7,11 +7,18 @@
 | 
			
		||||
#
 | 
			
		||||
# Firewall admin with superuser and IP address is required.
 | 
			
		||||
#
 | 
			
		||||
# export PANOS_USER=""  # required
 | 
			
		||||
# export PANOS_PASS=""  # required
 | 
			
		||||
# export PANOS_HOST=""  # required
 | 
			
		||||
# REQURED:
 | 
			
		||||
#     export PANOS_HOST=""
 | 
			
		||||
#     export PANOS_USER=""    #User *MUST* have Commit and Import Permissions in XML API for Admin Role
 | 
			
		||||
#     export PANOS_PASS=""
 | 
			
		||||
#
 | 
			
		||||
# OPTIONAL
 | 
			
		||||
#    export PANOS_TEMPLATE="" #Template Name of panorama managed devices
 | 
			
		||||
#
 | 
			
		||||
# The script will automatically generate a new API key if
 | 
			
		||||
# no key is found, or if a saved key has expired or is invalid.
 | 
			
		||||
 | 
			
		||||
# This function is to parse the XML
 | 
			
		||||
# This function is to parse the XML response from the firewall
 | 
			
		||||
parse_response() {
 | 
			
		||||
  type=$2
 | 
			
		||||
  if [ "$type" = 'keygen' ]; then
 | 
			
		||||
@@ -23,25 +30,46 @@ parse_response() {
 | 
			
		||||
      message="PAN-OS Key could not be set."
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    status=$(echo "$1" | sed 's/^.*"\([a-z]*\)".*/\1/g')
 | 
			
		||||
    message=$(echo "$1" | sed 's/^.*<result>\(.*\)<\/result.*/\1/g')
 | 
			
		||||
    status=$(echo "$1" | tr -d '\n' | sed 's/^.*"\([a-z]*\)".*/\1/g')
 | 
			
		||||
    message=$(echo "$1" | tr -d '\n' | sed 's/.*\(<result>\|<msg>\|<line>\)\([^<]*\).*/\2/g')
 | 
			
		||||
    _debug "Firewall message:  $message"
 | 
			
		||||
    if [ "$type" = 'keytest' ] && [ "$status" != "success" ]; then
 | 
			
		||||
      _debug "****  API Key has EXPIRED or is INVALID ****"
 | 
			
		||||
      unset _panos_key
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#This function is used to deploy to the firewall
 | 
			
		||||
deployer() {
 | 
			
		||||
  content=""
 | 
			
		||||
  type=$1 # Types are keygen, cert, key, commit
 | 
			
		||||
  _debug "**** Deploying $type *****"
 | 
			
		||||
  type=$1 # Types are keytest, keygen, cert, key, commit
 | 
			
		||||
  panos_url="https://$_panos_host/api/"
 | 
			
		||||
 | 
			
		||||
  #Test API Key by performing a lookup
 | 
			
		||||
  if [ "$type" = 'keytest' ]; then
 | 
			
		||||
    _debug "**** Testing saved API Key ****"
 | 
			
		||||
    _H1="Content-Type: application/x-www-form-urlencoded"
 | 
			
		||||
    # Get Version Info to test key
 | 
			
		||||
    content="type=version&key=$_panos_key"
 | 
			
		||||
    ## Exclude all scopes for the empty commit
 | 
			
		||||
    #_exclude_scope="<policy-and-objects>exclude</policy-and-objects><device-and-network>exclude</device-and-network><shared-object>exclude</shared-object>"
 | 
			
		||||
    #content="type=commit&action=partial&key=$_panos_key&cmd=<commit><partial>$_exclude_scope<admin><member>acmekeytest</member></admin></partial></commit>"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Generate API Key
 | 
			
		||||
  if [ "$type" = 'keygen' ]; then
 | 
			
		||||
    _debug "**** Generating new API Key ****"
 | 
			
		||||
    _H1="Content-Type: application/x-www-form-urlencoded"
 | 
			
		||||
    content="type=keygen&user=$_panos_user&password=$_panos_pass"
 | 
			
		||||
    # content="$content${nl}--$delim${nl}Content-Disposition: form-data; type=\"keygen\"; user=\"$_panos_user\"; password=\"$_panos_pass\"${nl}Content-Type: application/octet-stream${nl}${nl}"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Deploy Cert or Key
 | 
			
		||||
  if [ "$type" = 'cert' ] || [ "$type" = 'key' ]; then
 | 
			
		||||
    #Generate DEIM
 | 
			
		||||
    _debug "**** Deploying $type ****"
 | 
			
		||||
    #Generate DELIM
 | 
			
		||||
    delim="-----MultipartDelimiter$(date "+%s%N")"
 | 
			
		||||
    nl="\015\012"
 | 
			
		||||
    #Set Header
 | 
			
		||||
@@ -53,6 +81,9 @@ deployer() {
 | 
			
		||||
      content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"\r\n\r\n$_panos_key"
 | 
			
		||||
      content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"format\"\r\n\r\npem"
 | 
			
		||||
      content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"file\"; filename=\"$(basename "$_cfullchain")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_cfullchain")"
 | 
			
		||||
      if [ "$_panos_template" ]; then
 | 
			
		||||
        content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"target-tpl\"\r\n\r\n$_panos_template"
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
    if [ "$type" = 'key' ]; then
 | 
			
		||||
      panos_url="${panos_url}?type=import"
 | 
			
		||||
@@ -61,7 +92,10 @@ deployer() {
 | 
			
		||||
      content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"\r\n\r\n$_panos_key"
 | 
			
		||||
      content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"format\"\r\n\r\npem"
 | 
			
		||||
      content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"passphrase\"\r\n\r\n123456"
 | 
			
		||||
      content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"file\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")"
 | 
			
		||||
      content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"file\"; filename=\"$(basename "$_cdomain.key")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")"
 | 
			
		||||
      if [ "$_panos_template" ]; then
 | 
			
		||||
        content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"target-tpl\"\r\n\r\n$_panos_template"
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
    #Close multipart
 | 
			
		||||
    content="$content${nl}--$delim--${nl}${nl}"
 | 
			
		||||
@@ -69,16 +103,25 @@ deployer() {
 | 
			
		||||
    content=$(printf %b "$content")
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Commit changes
 | 
			
		||||
  if [ "$type" = 'commit' ]; then
 | 
			
		||||
    _debug "**** Committing changes ****"
 | 
			
		||||
    export _H1="Content-Type: application/x-www-form-urlencoded"
 | 
			
		||||
    cmd=$(printf "%s" "<commit><partial><$_panos_user></$_panos_user></partial></commit>" | _url_encode)
 | 
			
		||||
    content="type=commit&key=$_panos_key&cmd=$cmd"
 | 
			
		||||
    #Check for force commit - will commit ALL uncommited changes to the firewall. Use with caution!
 | 
			
		||||
    if [ "$FORCE" ]; then
 | 
			
		||||
      _debug "Force switch detected.  Committing ALL changes to the firewall."
 | 
			
		||||
      cmd=$(printf "%s" "<commit><partial><force><admin><member>$_panos_user</member></admin></force></partial></commit>" | _url_encode)
 | 
			
		||||
    else
 | 
			
		||||
      _exclude_scope="<policy-and-objects>exclude</policy-and-objects><device-and-network>exclude</device-and-network>"
 | 
			
		||||
      cmd=$(printf "%s" "<commit><partial>$_exclude_scope<admin><member>$_panos_user</member></admin></partial></commit>" | _url_encode)
 | 
			
		||||
    fi
 | 
			
		||||
    content="type=commit&action=partial&key=$_panos_key&cmd=$cmd"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  response=$(_post "$content" "$panos_url" "" "POST")
 | 
			
		||||
  parse_response "$response" "$type"
 | 
			
		||||
  # Saving response to variables
 | 
			
		||||
  response_status=$status
 | 
			
		||||
  #DEBUG
 | 
			
		||||
  _debug response_status "$response_status"
 | 
			
		||||
  if [ "$response_status" = "success" ]; then
 | 
			
		||||
    _debug "Successfully deployed $type"
 | 
			
		||||
@@ -92,43 +135,95 @@ deployer() {
 | 
			
		||||
 | 
			
		||||
# This is the main function that will call the other functions to deploy everything.
 | 
			
		||||
panos_deploy() {
 | 
			
		||||
  _cdomain="$1"
 | 
			
		||||
  _cdomain=$(echo "$1" | sed 's/*/WILDCARD_/g') #Wildcard Safe Filename
 | 
			
		||||
  _ckey="$2"
 | 
			
		||||
  _cfullchain="$5"
 | 
			
		||||
  # PANOS ENV VAR check
 | 
			
		||||
  if [ -z "$PANOS_USER" ] || [ -z "$PANOS_PASS" ] || [ -z "$PANOS_HOST" ]; then
 | 
			
		||||
    _debug "No ENV variables found lets check for saved variables"
 | 
			
		||||
    _getdeployconf PANOS_USER
 | 
			
		||||
    _getdeployconf PANOS_PASS
 | 
			
		||||
    _getdeployconf PANOS_HOST
 | 
			
		||||
    _panos_user=$PANOS_USER
 | 
			
		||||
    _panos_pass=$PANOS_PASS
 | 
			
		||||
    _panos_host=$PANOS_HOST
 | 
			
		||||
    if [ -z "$_panos_user" ] && [ -z "$_panos_pass" ] && [ -z "$_panos_host" ]; then
 | 
			
		||||
      _err "No host, user and pass found.. If this is the first time deploying please set PANOS_HOST, PANOS_USER and PANOS_PASS in environment variables. Delete them after you have succesfully deployed certs."
 | 
			
		||||
      return 1
 | 
			
		||||
    else
 | 
			
		||||
      _debug "Using saved env variables."
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    _debug "Detected ENV variables to be saved to the deploy conf."
 | 
			
		||||
    # Encrypt and save user
 | 
			
		||||
    _savedeployconf PANOS_USER "$PANOS_USER" 1
 | 
			
		||||
    _savedeployconf PANOS_PASS "$PANOS_PASS" 1
 | 
			
		||||
    _savedeployconf PANOS_HOST "$PANOS_HOST" 1
 | 
			
		||||
    _panos_user="$PANOS_USER"
 | 
			
		||||
    _panos_pass="$PANOS_PASS"
 | 
			
		||||
    _panos_host="$PANOS_HOST"
 | 
			
		||||
 | 
			
		||||
  # VALID FILE CHECK
 | 
			
		||||
  if [ ! -f "$_ckey" ] || [ ! -f "$_cfullchain" ]; then
 | 
			
		||||
    _err "Unable to find a valid key and/or cert.  If this is an ECDSA/ECC cert, use the --ecc flag when deploying."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug "Let's use username and pass to generate token."
 | 
			
		||||
  if [ -z "$_panos_user" ] || [ -z "$_panos_pass" ] || [ -z "$_panos_host" ]; then
 | 
			
		||||
    _err "Please pass username and password and host as env variables PANOS_USER, PANOS_PASS and PANOS_HOST"
 | 
			
		||||
 | 
			
		||||
  # PANOS_HOST
 | 
			
		||||
  if [ "$PANOS_HOST" ]; then
 | 
			
		||||
    _debug "Detected ENV variable PANOS_HOST. Saving to file."
 | 
			
		||||
    _savedeployconf PANOS_HOST "$PANOS_HOST" 1
 | 
			
		||||
  else
 | 
			
		||||
    _debug "Attempting to load variable PANOS_HOST from file."
 | 
			
		||||
    _getdeployconf PANOS_HOST
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # PANOS USER
 | 
			
		||||
  if [ "$PANOS_USER" ]; then
 | 
			
		||||
    _debug "Detected ENV variable PANOS_USER. Saving to file."
 | 
			
		||||
    _savedeployconf PANOS_USER "$PANOS_USER" 1
 | 
			
		||||
  else
 | 
			
		||||
    _debug "Attempting to load variable PANOS_USER from file."
 | 
			
		||||
    _getdeployconf PANOS_USER
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # PANOS_PASS
 | 
			
		||||
  if [ "$PANOS_PASS" ]; then
 | 
			
		||||
    _debug "Detected ENV variable PANOS_PASS. Saving to file."
 | 
			
		||||
    _savedeployconf PANOS_PASS "$PANOS_PASS" 1
 | 
			
		||||
  else
 | 
			
		||||
    _debug "Attempting to load variable PANOS_PASS from file."
 | 
			
		||||
    _getdeployconf PANOS_PASS
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # PANOS_KEY
 | 
			
		||||
  _getdeployconf PANOS_KEY
 | 
			
		||||
  if [ "$PANOS_KEY" ]; then
 | 
			
		||||
    _debug "Detected saved key."
 | 
			
		||||
    _panos_key=$PANOS_KEY
 | 
			
		||||
  else
 | 
			
		||||
    _debug "No key detected"
 | 
			
		||||
    unset _panos_key
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # PANOS_TEMPLATE
 | 
			
		||||
  if [ "$PANOS_TEMPLATE" ]; then
 | 
			
		||||
    _debug "Detected ENV variable PANOS_TEMPLATE. Saving to file."
 | 
			
		||||
    _savedeployconf PANOS_TEMPLATE "$PANOS_TEMPLATE" 1
 | 
			
		||||
  else
 | 
			
		||||
    _debug "Attempting to load variable PANOS_TEMPLATE from file."
 | 
			
		||||
    _getdeployconf PANOS_TEMPLATE
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  #Store variables
 | 
			
		||||
  _panos_host=$PANOS_HOST
 | 
			
		||||
  _panos_user=$PANOS_USER
 | 
			
		||||
  _panos_pass=$PANOS_PASS
 | 
			
		||||
  _panos_template=$PANOS_TEMPLATE
 | 
			
		||||
 | 
			
		||||
  #Test API Key if found.  If the key is invalid, the variable _panos_key will be unset.
 | 
			
		||||
  if [ "$_panos_host" ] && [ "$_panos_key" ]; then
 | 
			
		||||
    _debug "**** Testing API KEY ****"
 | 
			
		||||
    deployer keytest
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Check for valid variables
 | 
			
		||||
  if [ -z "$_panos_host" ]; then
 | 
			
		||||
    _err "No host found. If this is your first time deploying, please set PANOS_HOST in ENV variables. You can delete it after you have successfully deployed the certs."
 | 
			
		||||
    return 1
 | 
			
		||||
  elif [ -z "$_panos_user" ]; then
 | 
			
		||||
    _err "No user found. If this is your first time deploying, please set PANOS_USER in ENV variables. You can delete it after you have successfully deployed the certs."
 | 
			
		||||
    return 1
 | 
			
		||||
  elif [ -z "$_panos_pass" ]; then
 | 
			
		||||
    _err "No password found. If this is your first time deploying, please set PANOS_PASS in ENV variables. You can delete it after you have successfully deployed the certs."
 | 
			
		||||
    return 1
 | 
			
		||||
  else
 | 
			
		||||
    _debug "Getting PANOS KEY"
 | 
			
		||||
    deployer keygen
 | 
			
		||||
    # Generate a new API key if no valid API key is found
 | 
			
		||||
    if [ -z "$_panos_key" ]; then
 | 
			
		||||
      _err "Missing apikey."
 | 
			
		||||
      _debug "**** Generating new PANOS API KEY ****"
 | 
			
		||||
      deployer keygen
 | 
			
		||||
      _savedeployconf PANOS_KEY "$_panos_key" 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # Confirm that a valid key was generated
 | 
			
		||||
    if [ -z "$_panos_key" ]; then
 | 
			
		||||
      _err "Unable to generate an API key.  The user and pass may be invalid or not authorized to generate a new key.  Please check the PANOS_USER and PANOS_PASS credentials and try again"
 | 
			
		||||
      return 1
 | 
			
		||||
    else
 | 
			
		||||
      deployer cert
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										132
									
								
								deploy/proxmoxve.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								deploy/proxmoxve.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,132 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
# Deploy certificates to a proxmox virtual environment node using the API.
 | 
			
		||||
#
 | 
			
		||||
# Environment variables that can be set are:
 | 
			
		||||
# `DEPLOY_PROXMOXVE_SERVER`: The hostname of the proxmox ve node. Defaults to
 | 
			
		||||
#                            _cdomain.
 | 
			
		||||
# `DEPLOY_PROXMOXVE_SERVER_PORT`: The port number the management interface is on.
 | 
			
		||||
#                                 Defaults to 8006.
 | 
			
		||||
# `DEPLOY_PROXMOXVE_NODE_NAME`: The name of the node we'll be connecting to.
 | 
			
		||||
#                               Defaults to the host portion of the server
 | 
			
		||||
#                               domain name.
 | 
			
		||||
# `DEPLOY_PROXMOXVE_USER`: The user we'll connect as. Defaults to root.
 | 
			
		||||
# `DEPLOY_PROXMOXVE_USER_REALM`: The authentication realm the user authenticates
 | 
			
		||||
#                                with. Defaults to pam.
 | 
			
		||||
# `DEPLOY_PROXMOXVE_API_TOKEN_NAME`: The name of the API token created for the
 | 
			
		||||
#                                    user account. Defaults to acme.
 | 
			
		||||
# `DEPLOY_PROXMOXVE_API_TOKEN_KEY`: The API token. Required.
 | 
			
		||||
 | 
			
		||||
proxmoxve_deploy() {
 | 
			
		||||
  _cdomain="$1"
 | 
			
		||||
  _ckey="$2"
 | 
			
		||||
  _ccert="$3"
 | 
			
		||||
  _cca="$4"
 | 
			
		||||
  _cfullchain="$5"
 | 
			
		||||
 | 
			
		||||
  _debug _cdomain "$_cdomain"
 | 
			
		||||
  _debug2 _ckey "$_ckey"
 | 
			
		||||
  _debug _ccert "$_ccert"
 | 
			
		||||
  _debug _cca "$_cca"
 | 
			
		||||
  _debug _cfullchain "$_cfullchain"
 | 
			
		||||
 | 
			
		||||
  # "Sane" defaults.
 | 
			
		||||
  _getdeployconf DEPLOY_PROXMOXVE_SERVER
 | 
			
		||||
  if [ -z "$DEPLOY_PROXMOXVE_SERVER" ]; then
 | 
			
		||||
    _target_hostname="$_cdomain"
 | 
			
		||||
  else
 | 
			
		||||
    _target_hostname="$DEPLOY_PROXMOXVE_SERVER"
 | 
			
		||||
    _savedeployconf DEPLOY_PROXMOXVE_SERVER "$DEPLOY_PROXMOXVE_SERVER"
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 DEPLOY_PROXMOXVE_SERVER "$_target_hostname"
 | 
			
		||||
 | 
			
		||||
  _getdeployconf DEPLOY_PROXMOXVE_SERVER_PORT
 | 
			
		||||
  if [ -z "$DEPLOY_PROXMOXVE_SERVER_PORT" ]; then
 | 
			
		||||
    _target_port="8006"
 | 
			
		||||
  else
 | 
			
		||||
    _target_port="$DEPLOY_PROXMOXVE_SERVER_PORT"
 | 
			
		||||
    _savedeployconf DEPLOY_PROXMOXVE_SERVER_PORT "$DEPLOY_PROXMOXVE_SERVER_PORT"
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 DEPLOY_PROXMOXVE_SERVER_PORT "$_target_port"
 | 
			
		||||
 | 
			
		||||
  _getdeployconf DEPLOY_PROXMOXVE_NODE_NAME
 | 
			
		||||
  if [ -z "$DEPLOY_PROXMOXVE_NODE_NAME" ]; then
 | 
			
		||||
    _node_name=$(echo "$_target_hostname" | cut -d. -f1)
 | 
			
		||||
  else
 | 
			
		||||
    _node_name="$DEPLOY_PROXMOXVE_NODE_NAME"
 | 
			
		||||
    _savedeployconf DEPLOY_PROXMOXVE_NODE_NAME "$DEPLOY_PROXMOXVE_NODE_NAME"
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 DEPLOY_PROXMOXVE_NODE_NAME "$_node_name"
 | 
			
		||||
 | 
			
		||||
  # Complete URL.
 | 
			
		||||
  _target_url="https://${_target_hostname}:${_target_port}/api2/json/nodes/${_node_name}/certificates/custom"
 | 
			
		||||
  _debug TARGET_URL "$_target_url"
 | 
			
		||||
 | 
			
		||||
  # More "sane" defaults.
 | 
			
		||||
  _getdeployconf DEPLOY_PROXMOXVE_USER
 | 
			
		||||
  if [ -z "$DEPLOY_PROXMOXVE_USER" ]; then
 | 
			
		||||
    _proxmoxve_user="root"
 | 
			
		||||
  else
 | 
			
		||||
    _proxmoxve_user="$DEPLOY_PROXMOXVE_USER"
 | 
			
		||||
    _savedeployconf DEPLOY_PROXMOXVE_USER "$DEPLOY_PROXMOXVE_USER"
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 DEPLOY_PROXMOXVE_USER "$_proxmoxve_user"
 | 
			
		||||
 | 
			
		||||
  _getdeployconf DEPLOY_PROXMOXVE_USER_REALM
 | 
			
		||||
  if [ -z "$DEPLOY_PROXMOXVE_USER_REALM" ]; then
 | 
			
		||||
    _proxmoxve_user_realm="pam"
 | 
			
		||||
  else
 | 
			
		||||
    _proxmoxve_user_realm="$DEPLOY_PROXMOXVE_USER_REALM"
 | 
			
		||||
    _savedeployconf DEPLOY_PROXMOXVE_USER_REALM "$DEPLOY_PROXMOXVE_USER_REALM"
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 DEPLOY_PROXMOXVE_USER_REALM "$_proxmoxve_user_realm"
 | 
			
		||||
 | 
			
		||||
  _getdeployconf DEPLOY_PROXMOXVE_API_TOKEN_NAME
 | 
			
		||||
  if [ -z "$DEPLOY_PROXMOXVE_API_TOKEN_NAME" ]; then
 | 
			
		||||
    _proxmoxve_api_token_name="acme"
 | 
			
		||||
  else
 | 
			
		||||
    _proxmoxve_api_token_name="$DEPLOY_PROXMOXVE_API_TOKEN_NAME"
 | 
			
		||||
    _savedeployconf DEPLOY_PROXMOXVE_API_TOKEN_NAME "$DEPLOY_PROXMOXVE_API_TOKEN_NAME"
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 DEPLOY_PROXMOXVE_API_TOKEN_NAME "$_proxmoxve_api_token_name"
 | 
			
		||||
 | 
			
		||||
  # This is required.
 | 
			
		||||
  _getdeployconf DEPLOY_PROXMOXVE_API_TOKEN_KEY
 | 
			
		||||
  if [ -z "$DEPLOY_PROXMOXVE_API_TOKEN_KEY" ]; then
 | 
			
		||||
    _err "API key not provided."
 | 
			
		||||
    return 1
 | 
			
		||||
  else
 | 
			
		||||
    _proxmoxve_api_token_key="$DEPLOY_PROXMOXVE_API_TOKEN_KEY"
 | 
			
		||||
    _savedeployconf DEPLOY_PROXMOXVE_API_TOKEN_KEY "$DEPLOY_PROXMOXVE_API_TOKEN_KEY"
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 DEPLOY_PROXMOXVE_API_TOKEN_KEY "$_proxmoxve_api_token_key"
 | 
			
		||||
 | 
			
		||||
  # PVE API Token header value. Used in "Authorization: PVEAPIToken".
 | 
			
		||||
  _proxmoxve_header_api_token="${_proxmoxve_user}@${_proxmoxve_user_realm}!${_proxmoxve_api_token_name}=${_proxmoxve_api_token_key}"
 | 
			
		||||
  _debug2 "Auth Header" "$_proxmoxve_header_api_token"
 | 
			
		||||
 | 
			
		||||
  # Ugly. I hate putting heredocs inside functions because heredocs don't
 | 
			
		||||
  # account for whitespace correctly but it _does_ work and is several times
 | 
			
		||||
  # cleaner than anything else I had here.
 | 
			
		||||
  #
 | 
			
		||||
  # This dumps the json payload to a variable that should be passable to the
 | 
			
		||||
  # _psot function.
 | 
			
		||||
  _json_payload=$(
 | 
			
		||||
    cat <<HEREDOC
 | 
			
		||||
{
 | 
			
		||||
  "certificates": "$(tr '\n' ':' <"$_cfullchain" | sed 's/:/\\n/g')",
 | 
			
		||||
  "key": "$(tr '\n' ':' <"$_ckey" | sed 's/:/\\n/g')",
 | 
			
		||||
  "node":"$_node_name",
 | 
			
		||||
  "restart":"1",
 | 
			
		||||
  "force":"1"
 | 
			
		||||
}
 | 
			
		||||
HEREDOC
 | 
			
		||||
  )
 | 
			
		||||
  _debug2 Payload "$_json_payload"
 | 
			
		||||
 | 
			
		||||
  _info "Push certificates to server"
 | 
			
		||||
  export HTTPS_INSECURE=1
 | 
			
		||||
  export _H1="Authorization: PVEAPIToken=${_proxmoxve_header_api_token}"
 | 
			
		||||
  _post "$_json_payload" "$_target_url" "" POST "application/json"
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -53,7 +53,7 @@ qiniu_deploy() {
 | 
			
		||||
  sslcert_access_token="$(_make_access_token "$sslcert_path")"
 | 
			
		||||
  _debug sslcert_access_token "$sslcert_access_token"
 | 
			
		||||
  export _H1="Authorization: QBox $sslcert_access_token"
 | 
			
		||||
  sslcert_response=$(_post "$sslcerl_body" "$QINIU_API_BASE$sslcert_path" 0 "POST" "application/json" | _dbase64 "multiline")
 | 
			
		||||
  sslcert_response=$(_post "$sslcerl_body" "$QINIU_API_BASE$sslcert_path" 0 "POST" "application/json" | _dbase64)
 | 
			
		||||
 | 
			
		||||
  if ! _contains "$sslcert_response" "certID"; then
 | 
			
		||||
    _err "Error in creating certificate:"
 | 
			
		||||
@@ -75,7 +75,7 @@ qiniu_deploy() {
 | 
			
		||||
    update_access_token="$(_make_access_token "$update_path")"
 | 
			
		||||
    _debug update_access_token "$update_access_token"
 | 
			
		||||
    export _H1="Authorization: QBox $update_access_token"
 | 
			
		||||
    update_response=$(_post "$update_body" "$QINIU_API_BASE$update_path" 0 "PUT" "application/json" | _dbase64 "multiline")
 | 
			
		||||
    update_response=$(_post "$update_body" "$QINIU_API_BASE$update_path" 0 "PUT" "application/json" | _dbase64)
 | 
			
		||||
 | 
			
		||||
    if _contains "$update_response" "error"; then
 | 
			
		||||
      _err "Error in updating domain $domain httpsconf:"
 | 
			
		||||
 
 | 
			
		||||
@@ -137,7 +137,8 @@ routeros_deploy() {
 | 
			
		||||
    return $_err_code
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  DEPLOY_SCRIPT_CMD="/system script add name=\"LE Cert Deploy - $_cdomain\" owner=$ROUTER_OS_USERNAME \
 | 
			
		||||
  DEPLOY_SCRIPT_CMD=":do {/system script remove \"LECertDeploy-$_cdomain\" } on-error={ }; \
 | 
			
		||||
/system script add name=\"LECertDeploy-$_cdomain\" owner=$ROUTER_OS_USERNAME \
 | 
			
		||||
comment=\"generated by routeros deploy script in acme.sh\" \
 | 
			
		||||
source=\"/certificate remove [ find name=$_cdomain.cer_0 ];\
 | 
			
		||||
\n/certificate remove [ find name=$_cdomain.cer_1 ];\
 | 
			
		||||
@@ -146,8 +147,8 @@ source=\"/certificate remove [ find name=$_cdomain.cer_0 ];\
 | 
			
		||||
\n/certificate import file-name=$_cdomain.cer passphrase=\\\"\\\";\
 | 
			
		||||
\n/certificate import file-name=$_cdomain.key passphrase=\\\"\\\";\
 | 
			
		||||
\ndelay 1;\
 | 
			
		||||
\n/file remove $_cdomain.cer;\
 | 
			
		||||
\n/file remove $_cdomain.key;\
 | 
			
		||||
\n:do {/file remove $_cdomain.cer; } on-error={ }\
 | 
			
		||||
\n:do {/file remove $_cdomain.key; } on-error={ }\
 | 
			
		||||
\ndelay 2;\
 | 
			
		||||
\n/ip service set www-ssl certificate=$_cdomain.cer_0;\
 | 
			
		||||
\n$ROUTER_OS_ADDITIONAL_SERVICES;\
 | 
			
		||||
@@ -158,11 +159,11 @@ source=\"/certificate remove [ find name=$_cdomain.cer_0 ];\
 | 
			
		||||
    return $_err_code
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! _ssh_remote_cmd "/system script run \"LE Cert Deploy - $_cdomain\""; then
 | 
			
		||||
  if ! _ssh_remote_cmd "/system script run \"LECertDeploy-$_cdomain\""; then
 | 
			
		||||
    return $_err_code
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! _ssh_remote_cmd "/system script remove \"LE Cert Deploy - $_cdomain\""; then
 | 
			
		||||
  if ! _ssh_remote_cmd "/system script remove \"LECertDeploy-$_cdomain\""; then
 | 
			
		||||
    return $_err_code
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										409
									
								
								deploy/ssh.sh
									
									
									
									
									
								
							
							
						
						
									
										409
									
								
								deploy/ssh.sh
									
									
									
									
									
								
							@@ -14,7 +14,7 @@
 | 
			
		||||
# The following examples are for QNAP NAS running QTS 4.2
 | 
			
		||||
# export DEPLOY_SSH_CMD=""  # defaults to "ssh -T"
 | 
			
		||||
# export DEPLOY_SSH_USER="admin"  # required
 | 
			
		||||
# export DEPLOY_SSH_SERVER="qnap"  # defaults to domain name
 | 
			
		||||
# export DEPLOY_SSH_SERVER="host1 host2:8022 192.168.0.1:9022"  # defaults to domain name, support multiple servers with optional port
 | 
			
		||||
# export DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem"
 | 
			
		||||
# export DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem"
 | 
			
		||||
# export DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem"
 | 
			
		||||
@@ -23,6 +23,8 @@
 | 
			
		||||
# export DEPLOY_SSH_BACKUP=""  # yes or no, default to yes or previously saved value
 | 
			
		||||
# export DEPLOY_SSH_BACKUP_PATH=".acme_ssh_deploy"  # path on remote system. Defaults to .acme_ssh_deploy
 | 
			
		||||
# export DEPLOY_SSH_MULTI_CALL=""  # yes or no, default to no or previously saved value
 | 
			
		||||
# export DEPLOY_SSH_USE_SCP="" yes or no, default to no
 | 
			
		||||
# export DEPLOY_SSH_SCP_CMD="" defaults to "scp -q"
 | 
			
		||||
#
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
@@ -42,72 +44,134 @@ ssh_deploy() {
 | 
			
		||||
  _debug _cfullchain "$_cfullchain"
 | 
			
		||||
 | 
			
		||||
  # USER is required to login by SSH to remote host.
 | 
			
		||||
  _migratedeployconf Le_Deploy_ssh_user DEPLOY_SSH_USER
 | 
			
		||||
  _getdeployconf DEPLOY_SSH_USER
 | 
			
		||||
  _debug2 DEPLOY_SSH_USER "$DEPLOY_SSH_USER"
 | 
			
		||||
  if [ -z "$DEPLOY_SSH_USER" ]; then
 | 
			
		||||
    if [ -z "$Le_Deploy_ssh_user" ]; then
 | 
			
		||||
      _err "DEPLOY_SSH_USER not defined."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    Le_Deploy_ssh_user="$DEPLOY_SSH_USER"
 | 
			
		||||
    _savedomainconf Le_Deploy_ssh_user "$Le_Deploy_ssh_user"
 | 
			
		||||
    _err "DEPLOY_SSH_USER not defined."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _savedeployconf DEPLOY_SSH_USER "$DEPLOY_SSH_USER"
 | 
			
		||||
 | 
			
		||||
  # SERVER is optional. If not provided then use _cdomain
 | 
			
		||||
  _migratedeployconf Le_Deploy_ssh_server DEPLOY_SSH_SERVER
 | 
			
		||||
  _getdeployconf DEPLOY_SSH_SERVER
 | 
			
		||||
  _debug2 DEPLOY_SSH_SERVER "$DEPLOY_SSH_SERVER"
 | 
			
		||||
  if [ -n "$DEPLOY_SSH_SERVER" ]; then
 | 
			
		||||
    Le_Deploy_ssh_server="$DEPLOY_SSH_SERVER"
 | 
			
		||||
    _savedomainconf Le_Deploy_ssh_server "$Le_Deploy_ssh_server"
 | 
			
		||||
  elif [ -z "$Le_Deploy_ssh_server" ]; then
 | 
			
		||||
    Le_Deploy_ssh_server="$_cdomain"
 | 
			
		||||
  if [ -z "$DEPLOY_SSH_SERVER" ]; then
 | 
			
		||||
    DEPLOY_SSH_SERVER="$_cdomain"
 | 
			
		||||
  fi
 | 
			
		||||
  _savedeployconf DEPLOY_SSH_SERVER "$DEPLOY_SSH_SERVER"
 | 
			
		||||
 | 
			
		||||
  # CMD is optional. If not provided then use ssh
 | 
			
		||||
  _migratedeployconf Le_Deploy_ssh_cmd DEPLOY_SSH_CMD
 | 
			
		||||
  _getdeployconf DEPLOY_SSH_CMD
 | 
			
		||||
  _debug2 DEPLOY_SSH_CMD "$DEPLOY_SSH_CMD"
 | 
			
		||||
  if [ -n "$DEPLOY_SSH_CMD" ]; then
 | 
			
		||||
    Le_Deploy_ssh_cmd="$DEPLOY_SSH_CMD"
 | 
			
		||||
    _savedomainconf Le_Deploy_ssh_cmd "$Le_Deploy_ssh_cmd"
 | 
			
		||||
  elif [ -z "$Le_Deploy_ssh_cmd" ]; then
 | 
			
		||||
    Le_Deploy_ssh_cmd="ssh -T"
 | 
			
		||||
  if [ -z "$DEPLOY_SSH_CMD" ]; then
 | 
			
		||||
    DEPLOY_SSH_CMD="ssh -T"
 | 
			
		||||
  fi
 | 
			
		||||
  _savedeployconf DEPLOY_SSH_CMD "$DEPLOY_SSH_CMD"
 | 
			
		||||
 | 
			
		||||
  # BACKUP is optional. If not provided then default to previously saved value or yes.
 | 
			
		||||
  _migratedeployconf Le_Deploy_ssh_backup DEPLOY_SSH_BACKUP
 | 
			
		||||
  _getdeployconf DEPLOY_SSH_BACKUP
 | 
			
		||||
  _debug2 DEPLOY_SSH_BACKUP "$DEPLOY_SSH_BACKUP"
 | 
			
		||||
  if [ "$DEPLOY_SSH_BACKUP" = "no" ]; then
 | 
			
		||||
    Le_Deploy_ssh_backup="no"
 | 
			
		||||
  elif [ -z "$Le_Deploy_ssh_backup" ] || [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
 | 
			
		||||
    Le_Deploy_ssh_backup="yes"
 | 
			
		||||
  if [ -z "$DEPLOY_SSH_BACKUP" ]; then
 | 
			
		||||
    DEPLOY_SSH_BACKUP="yes"
 | 
			
		||||
  fi
 | 
			
		||||
  _savedomainconf Le_Deploy_ssh_backup "$Le_Deploy_ssh_backup"
 | 
			
		||||
  _savedeployconf DEPLOY_SSH_BACKUP "$DEPLOY_SSH_BACKUP"
 | 
			
		||||
 | 
			
		||||
  # BACKUP_PATH is optional. If not provided then default to previously saved value or .acme_ssh_deploy
 | 
			
		||||
  _migratedeployconf Le_Deploy_ssh_backup_path DEPLOY_SSH_BACKUP_PATH
 | 
			
		||||
  _getdeployconf DEPLOY_SSH_BACKUP_PATH
 | 
			
		||||
  _debug2 DEPLOY_SSH_BACKUP_PATH "$DEPLOY_SSH_BACKUP_PATH"
 | 
			
		||||
  if [ -n "$DEPLOY_SSH_BACKUP_PATH" ]; then
 | 
			
		||||
    Le_Deploy_ssh_backup_path="$DEPLOY_SSH_BACKUP_PATH"
 | 
			
		||||
  elif [ -z "$Le_Deploy_ssh_backup_path" ]; then
 | 
			
		||||
    Le_Deploy_ssh_backup_path=".acme_ssh_deploy"
 | 
			
		||||
  if [ -z "$DEPLOY_SSH_BACKUP_PATH" ]; then
 | 
			
		||||
    DEPLOY_SSH_BACKUP_PATH=".acme_ssh_deploy"
 | 
			
		||||
  fi
 | 
			
		||||
  _savedomainconf Le_Deploy_ssh_backup_path "$Le_Deploy_ssh_backup_path"
 | 
			
		||||
  _savedeployconf DEPLOY_SSH_BACKUP_PATH "$DEPLOY_SSH_BACKUP_PATH"
 | 
			
		||||
 | 
			
		||||
  # MULTI_CALL is optional. If not provided then default to previously saved
 | 
			
		||||
  # value (which may be undefined... equivalent to "no").
 | 
			
		||||
  _migratedeployconf Le_Deploy_ssh_multi_call DEPLOY_SSH_MULTI_CALL
 | 
			
		||||
  _getdeployconf DEPLOY_SSH_MULTI_CALL
 | 
			
		||||
  _debug2 DEPLOY_SSH_MULTI_CALL "$DEPLOY_SSH_MULTI_CALL"
 | 
			
		||||
  if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
 | 
			
		||||
    Le_Deploy_ssh_multi_call="yes"
 | 
			
		||||
    _savedomainconf Le_Deploy_ssh_multi_call "$Le_Deploy_ssh_multi_call"
 | 
			
		||||
  elif [ "$DEPLOY_SSH_MULTI_CALL" = "no" ]; then
 | 
			
		||||
    Le_Deploy_ssh_multi_call=""
 | 
			
		||||
    _cleardomainconf Le_Deploy_ssh_multi_call
 | 
			
		||||
  if [ -z "$DEPLOY_SSH_MULTI_CALL" ]; then
 | 
			
		||||
    DEPLOY_SSH_MULTI_CALL="no"
 | 
			
		||||
  fi
 | 
			
		||||
  _savedeployconf DEPLOY_SSH_MULTI_CALL "$DEPLOY_SSH_MULTI_CALL"
 | 
			
		||||
 | 
			
		||||
  # KEYFILE is optional.
 | 
			
		||||
  # If provided then private key will be copied to provided filename.
 | 
			
		||||
  _migratedeployconf Le_Deploy_ssh_keyfile DEPLOY_SSH_KEYFILE
 | 
			
		||||
  _getdeployconf DEPLOY_SSH_KEYFILE
 | 
			
		||||
  _debug2 DEPLOY_SSH_KEYFILE "$DEPLOY_SSH_KEYFILE"
 | 
			
		||||
  if [ -n "$DEPLOY_SSH_KEYFILE" ]; then
 | 
			
		||||
    _savedeployconf DEPLOY_SSH_KEYFILE "$DEPLOY_SSH_KEYFILE"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _deploy_ssh_servers=$Le_Deploy_ssh_server
 | 
			
		||||
  for Le_Deploy_ssh_server in $_deploy_ssh_servers; do
 | 
			
		||||
  # CERTFILE is optional.
 | 
			
		||||
  # If provided then certificate will be copied or appended to provided filename.
 | 
			
		||||
  _migratedeployconf Le_Deploy_ssh_certfile DEPLOY_SSH_CERTFILE
 | 
			
		||||
  _getdeployconf DEPLOY_SSH_CERTFILE
 | 
			
		||||
  _debug2 DEPLOY_SSH_CERTFILE "$DEPLOY_SSH_CERTFILE"
 | 
			
		||||
  if [ -n "$DEPLOY_SSH_CERTFILE" ]; then
 | 
			
		||||
    _savedeployconf DEPLOY_SSH_CERTFILE "$DEPLOY_SSH_CERTFILE"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # CAFILE is optional.
 | 
			
		||||
  # If provided then CA intermediate certificate will be copied or appended to provided filename.
 | 
			
		||||
  _migratedeployconf Le_Deploy_ssh_cafile DEPLOY_SSH_CAFILE
 | 
			
		||||
  _getdeployconf DEPLOY_SSH_CAFILE
 | 
			
		||||
  _debug2 DEPLOY_SSH_CAFILE "$DEPLOY_SSH_CAFILE"
 | 
			
		||||
  if [ -n "$DEPLOY_SSH_CAFILE" ]; then
 | 
			
		||||
    _savedeployconf DEPLOY_SSH_CAFILE "$DEPLOY_SSH_CAFILE"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # FULLCHAIN is optional.
 | 
			
		||||
  # If provided then fullchain certificate will be copied or appended to provided filename.
 | 
			
		||||
  _migratedeployconf Le_Deploy_ssh_fullchain DEPLOY_SSH_FULLCHAIN
 | 
			
		||||
  _getdeployconf DEPLOY_SSH_FULLCHAIN
 | 
			
		||||
  _debug2 DEPLOY_SSH_FULLCHAIN "$DEPLOY_SSH_FULLCHAIN"
 | 
			
		||||
  if [ -n "$DEPLOY_SSH_FULLCHAIN" ]; then
 | 
			
		||||
    _savedeployconf DEPLOY_SSH_FULLCHAIN "$DEPLOY_SSH_FULLCHAIN"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # REMOTE_CMD is optional.
 | 
			
		||||
  # If provided then this command will be executed on remote host.
 | 
			
		||||
  _migratedeployconf Le_Deploy_ssh_remote_cmd DEPLOY_SSH_REMOTE_CMD
 | 
			
		||||
  _getdeployconf DEPLOY_SSH_REMOTE_CMD
 | 
			
		||||
  _debug2 DEPLOY_SSH_REMOTE_CMD "$DEPLOY_SSH_REMOTE_CMD"
 | 
			
		||||
  if [ -n "$DEPLOY_SSH_REMOTE_CMD" ]; then
 | 
			
		||||
    _savedeployconf DEPLOY_SSH_REMOTE_CMD "$DEPLOY_SSH_REMOTE_CMD"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # USE_SCP is optional. If not provided then default to previously saved
 | 
			
		||||
  # value (which may be undefined... equivalent to "no").
 | 
			
		||||
  _getdeployconf DEPLOY_SSH_USE_SCP
 | 
			
		||||
  _debug2 DEPLOY_SSH_USE_SCP "$DEPLOY_SSH_USE_SCP"
 | 
			
		||||
  if [ -z "$DEPLOY_SSH_USE_SCP" ]; then
 | 
			
		||||
    DEPLOY_SSH_USE_SCP="no"
 | 
			
		||||
  fi
 | 
			
		||||
  _savedeployconf DEPLOY_SSH_USE_SCP "$DEPLOY_SSH_USE_SCP"
 | 
			
		||||
 | 
			
		||||
  # SCP_CMD is optional. If not provided then use scp
 | 
			
		||||
  _getdeployconf DEPLOY_SSH_SCP_CMD
 | 
			
		||||
  _debug2 DEPLOY_SSH_SCP_CMD "$DEPLOY_SSH_SCP_CMD"
 | 
			
		||||
  if [ -z "$DEPLOY_SSH_SCP_CMD" ]; then
 | 
			
		||||
    DEPLOY_SSH_SCP_CMD="scp -q"
 | 
			
		||||
  fi
 | 
			
		||||
  _savedeployconf DEPLOY_SSH_SCP_CMD "$DEPLOY_SSH_SCP_CMD"
 | 
			
		||||
 | 
			
		||||
  if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
 | 
			
		||||
    DEPLOY_SSH_MULTI_CALL="yes"
 | 
			
		||||
    _info "Using scp as alternate method for copying files. Multicall Mode is implicit"
 | 
			
		||||
  elif [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
 | 
			
		||||
    _info "Using MULTI_CALL mode... Required commands sent in multiple calls to remote host"
 | 
			
		||||
  else
 | 
			
		||||
    _info "Required commands batched and sent in single call to remote host"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _deploy_ssh_servers="$DEPLOY_SSH_SERVER"
 | 
			
		||||
  for DEPLOY_SSH_SERVER in $_deploy_ssh_servers; do
 | 
			
		||||
    _ssh_deploy
 | 
			
		||||
  done
 | 
			
		||||
}
 | 
			
		||||
@@ -117,16 +181,25 @@ _ssh_deploy() {
 | 
			
		||||
  _cmdstr=""
 | 
			
		||||
  _backupprefix=""
 | 
			
		||||
  _backupdir=""
 | 
			
		||||
  _local_cert_file=""
 | 
			
		||||
  _local_ca_file=""
 | 
			
		||||
  _local_full_file=""
 | 
			
		||||
 | 
			
		||||
  _info "Deploy certificates to remote server $Le_Deploy_ssh_user@$Le_Deploy_ssh_server"
 | 
			
		||||
  if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
 | 
			
		||||
    _info "Using MULTI_CALL mode... Required commands sent in multiple calls to remote host"
 | 
			
		||||
  else
 | 
			
		||||
    _info "Required commands batched and sent in single call to remote host"
 | 
			
		||||
  fi
 | 
			
		||||
  case $DEPLOY_SSH_SERVER in
 | 
			
		||||
  *:*)
 | 
			
		||||
    _host=${DEPLOY_SSH_SERVER%:*}
 | 
			
		||||
    _port=${DEPLOY_SSH_SERVER##*:}
 | 
			
		||||
    ;;
 | 
			
		||||
  *)
 | 
			
		||||
    _host=$DEPLOY_SSH_SERVER
 | 
			
		||||
    _port=
 | 
			
		||||
    ;;
 | 
			
		||||
  esac
 | 
			
		||||
 | 
			
		||||
  if [ "$Le_Deploy_ssh_backup" = "yes" ]; then
 | 
			
		||||
    _backupprefix="$Le_Deploy_ssh_backup_path/$_cdomain-backup"
 | 
			
		||||
  _info "Deploy certificates to remote server $DEPLOY_SSH_USER@$_host:$_port"
 | 
			
		||||
 | 
			
		||||
  if [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
 | 
			
		||||
    _backupprefix="$DEPLOY_SSH_BACKUP_PATH/$_cdomain-backup"
 | 
			
		||||
    _backupdir="$_backupprefix-$(_utc_date | tr ' ' '-')"
 | 
			
		||||
    # run cleanup on the backup directory, erase all older
 | 
			
		||||
    # than 180 days (15552000 seconds).
 | 
			
		||||
@@ -138,7 +211,7 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
 | 
			
		||||
    _cmdstr="mkdir -p $_backupdir; $_cmdstr"
 | 
			
		||||
    _info "Backup of old certificate files will be placed in remote directory $_backupdir"
 | 
			
		||||
    _info "Backup directories erased after 180 days."
 | 
			
		||||
    if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
 | 
			
		||||
    if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
 | 
			
		||||
      if ! _ssh_remote_cmd "$_cmdstr"; then
 | 
			
		||||
        return $_err_code
 | 
			
		||||
      fi
 | 
			
		||||
@@ -146,129 +219,184 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # KEYFILE is optional.
 | 
			
		||||
  # If provided then private key will be copied to provided filename.
 | 
			
		||||
  _getdeployconf DEPLOY_SSH_KEYFILE
 | 
			
		||||
  _debug2 DEPLOY_SSH_KEYFILE "$DEPLOY_SSH_KEYFILE"
 | 
			
		||||
  if [ -n "$DEPLOY_SSH_KEYFILE" ]; then
 | 
			
		||||
    Le_Deploy_ssh_keyfile="$DEPLOY_SSH_KEYFILE"
 | 
			
		||||
    _savedomainconf Le_Deploy_ssh_keyfile "$Le_Deploy_ssh_keyfile"
 | 
			
		||||
  fi
 | 
			
		||||
  if [ -n "$Le_Deploy_ssh_keyfile" ]; then
 | 
			
		||||
    if [ "$Le_Deploy_ssh_backup" = "yes" ]; then
 | 
			
		||||
    if [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
 | 
			
		||||
      # backup file we are about to overwrite.
 | 
			
		||||
      _cmdstr="$_cmdstr cp $Le_Deploy_ssh_keyfile $_backupdir >/dev/null;"
 | 
			
		||||
      _cmdstr="$_cmdstr cp $DEPLOY_SSH_KEYFILE $_backupdir >/dev/null;"
 | 
			
		||||
      if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
 | 
			
		||||
        if ! _ssh_remote_cmd "$_cmdstr"; then
 | 
			
		||||
          return $_err_code
 | 
			
		||||
        fi
 | 
			
		||||
        _cmdstr=""
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
    # copy new certificate into file.
 | 
			
		||||
    _cmdstr="$_cmdstr echo \"$(cat "$_ckey")\" > $Le_Deploy_ssh_keyfile;"
 | 
			
		||||
    _info "will copy private key to remote file $Le_Deploy_ssh_keyfile"
 | 
			
		||||
    if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
 | 
			
		||||
      if ! _ssh_remote_cmd "$_cmdstr"; then
 | 
			
		||||
 | 
			
		||||
    # copy new key into file.
 | 
			
		||||
    if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
 | 
			
		||||
      # scp the file
 | 
			
		||||
      if ! _scp_remote_cmd "$_ckey" "$DEPLOY_SSH_KEYFILE"; then
 | 
			
		||||
        return $_err_code
 | 
			
		||||
      fi
 | 
			
		||||
      _cmdstr=""
 | 
			
		||||
    else
 | 
			
		||||
      # ssh echo to the file
 | 
			
		||||
      _cmdstr="$_cmdstr echo \"$(cat "$_ckey")\" > $DEPLOY_SSH_KEYFILE;"
 | 
			
		||||
      _info "will copy private key to remote file $DEPLOY_SSH_KEYFILE"
 | 
			
		||||
      if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
 | 
			
		||||
        if ! _ssh_remote_cmd "$_cmdstr"; then
 | 
			
		||||
          return $_err_code
 | 
			
		||||
        fi
 | 
			
		||||
        _cmdstr=""
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # CERTFILE is optional.
 | 
			
		||||
  # If provided then certificate will be copied or appended to provided filename.
 | 
			
		||||
  _getdeployconf DEPLOY_SSH_CERTFILE
 | 
			
		||||
  _debug2 DEPLOY_SSH_CERTFILE "$DEPLOY_SSH_CERTFILE"
 | 
			
		||||
  if [ -n "$DEPLOY_SSH_CERTFILE" ]; then
 | 
			
		||||
    Le_Deploy_ssh_certfile="$DEPLOY_SSH_CERTFILE"
 | 
			
		||||
    _savedomainconf Le_Deploy_ssh_certfile "$Le_Deploy_ssh_certfile"
 | 
			
		||||
  fi
 | 
			
		||||
  if [ -n "$Le_Deploy_ssh_certfile" ]; then
 | 
			
		||||
    _pipe=">"
 | 
			
		||||
    if [ "$Le_Deploy_ssh_certfile" = "$Le_Deploy_ssh_keyfile" ]; then
 | 
			
		||||
    if [ "$DEPLOY_SSH_CERTFILE" = "$DEPLOY_SSH_KEYFILE" ]; then
 | 
			
		||||
      # if filename is same as previous file then append.
 | 
			
		||||
      _pipe=">>"
 | 
			
		||||
    elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
 | 
			
		||||
    elif [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
 | 
			
		||||
      # backup file we are about to overwrite.
 | 
			
		||||
      _cmdstr="$_cmdstr cp $Le_Deploy_ssh_certfile $_backupdir >/dev/null;"
 | 
			
		||||
      _cmdstr="$_cmdstr cp $DEPLOY_SSH_CERTFILE $_backupdir >/dev/null;"
 | 
			
		||||
      if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
 | 
			
		||||
        if ! _ssh_remote_cmd "$_cmdstr"; then
 | 
			
		||||
          return $_err_code
 | 
			
		||||
        fi
 | 
			
		||||
        _cmdstr=""
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # copy new certificate into file.
 | 
			
		||||
    _cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" $_pipe $Le_Deploy_ssh_certfile;"
 | 
			
		||||
    _info "will copy certificate to remote file $Le_Deploy_ssh_certfile"
 | 
			
		||||
    if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
 | 
			
		||||
      if ! _ssh_remote_cmd "$_cmdstr"; then
 | 
			
		||||
    if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
 | 
			
		||||
      # scp the file
 | 
			
		||||
      _local_cert_file=$(_mktemp)
 | 
			
		||||
      if [ "$DEPLOY_SSH_CERTFILE" = "$DEPLOY_SSH_KEYFILE" ]; then
 | 
			
		||||
        cat "$_ckey" >>"$_local_cert_file"
 | 
			
		||||
      fi
 | 
			
		||||
      cat "$_ccert" >>"$_local_cert_file"
 | 
			
		||||
      if ! _scp_remote_cmd "$_local_cert_file" "$DEPLOY_SSH_CERTFILE"; then
 | 
			
		||||
        return $_err_code
 | 
			
		||||
      fi
 | 
			
		||||
      _cmdstr=""
 | 
			
		||||
    else
 | 
			
		||||
      # ssh echo to the file
 | 
			
		||||
      _cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" $_pipe $DEPLOY_SSH_CERTFILE;"
 | 
			
		||||
      _info "will copy certificate to remote file $DEPLOY_SSH_CERTFILE"
 | 
			
		||||
      if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
 | 
			
		||||
        if ! _ssh_remote_cmd "$_cmdstr"; then
 | 
			
		||||
          return $_err_code
 | 
			
		||||
        fi
 | 
			
		||||
        _cmdstr=""
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # CAFILE is optional.
 | 
			
		||||
  # If provided then CA intermediate certificate will be copied or appended to provided filename.
 | 
			
		||||
  _getdeployconf DEPLOY_SSH_CAFILE
 | 
			
		||||
  _debug2 DEPLOY_SSH_CAFILE "$DEPLOY_SSH_CAFILE"
 | 
			
		||||
  if [ -n "$DEPLOY_SSH_CAFILE" ]; then
 | 
			
		||||
    Le_Deploy_ssh_cafile="$DEPLOY_SSH_CAFILE"
 | 
			
		||||
    _savedomainconf Le_Deploy_ssh_cafile "$Le_Deploy_ssh_cafile"
 | 
			
		||||
  fi
 | 
			
		||||
  if [ -n "$Le_Deploy_ssh_cafile" ]; then
 | 
			
		||||
    _pipe=">"
 | 
			
		||||
    if [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_keyfile" ] ||
 | 
			
		||||
      [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_certfile" ]; then
 | 
			
		||||
    if [ "$DEPLOY_SSH_CAFILE" = "$DEPLOY_SSH_KEYFILE" ] ||
 | 
			
		||||
      [ "$DEPLOY_SSH_CAFILE" = "$DEPLOY_SSH_CERTFILE" ]; then
 | 
			
		||||
      # if filename is same as previous file then append.
 | 
			
		||||
      _pipe=">>"
 | 
			
		||||
    elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
 | 
			
		||||
    elif [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
 | 
			
		||||
      # backup file we are about to overwrite.
 | 
			
		||||
      _cmdstr="$_cmdstr cp $Le_Deploy_ssh_cafile $_backupdir >/dev/null;"
 | 
			
		||||
      _cmdstr="$_cmdstr cp $DEPLOY_SSH_CAFILE $_backupdir >/dev/null;"
 | 
			
		||||
      if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
 | 
			
		||||
        if ! _ssh_remote_cmd "$_cmdstr"; then
 | 
			
		||||
          return $_err_code
 | 
			
		||||
        fi
 | 
			
		||||
        _cmdstr=""
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # copy new certificate into file.
 | 
			
		||||
    _cmdstr="$_cmdstr echo \"$(cat "$_cca")\" $_pipe $Le_Deploy_ssh_cafile;"
 | 
			
		||||
    _info "will copy CA file to remote file $Le_Deploy_ssh_cafile"
 | 
			
		||||
    if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
 | 
			
		||||
      if ! _ssh_remote_cmd "$_cmdstr"; then
 | 
			
		||||
    if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
 | 
			
		||||
      # scp the file
 | 
			
		||||
      _local_ca_file=$(_mktemp)
 | 
			
		||||
      if [ "$DEPLOY_SSH_CAFILE" = "$DEPLOY_SSH_KEYFILE" ]; then
 | 
			
		||||
        cat "$_ckey" >>"$_local_ca_file"
 | 
			
		||||
      fi
 | 
			
		||||
      if [ "$DEPLOY_SSH_CAFILE" = "$DEPLOY_SSH_CERTFILE" ]; then
 | 
			
		||||
        cat "$_ccert" >>"$_local_ca_file"
 | 
			
		||||
      fi
 | 
			
		||||
      cat "$_cca" >>"$_local_ca_file"
 | 
			
		||||
      if ! _scp_remote_cmd "$_local_ca_file" "$DEPLOY_SSH_CAFILE"; then
 | 
			
		||||
        return $_err_code
 | 
			
		||||
      fi
 | 
			
		||||
      _cmdstr=""
 | 
			
		||||
    else
 | 
			
		||||
      # ssh echo to the file
 | 
			
		||||
      _cmdstr="$_cmdstr echo \"$(cat "$_cca")\" $_pipe $DEPLOY_SSH_CAFILE;"
 | 
			
		||||
      _info "will copy CA file to remote file $DEPLOY_SSH_CAFILE"
 | 
			
		||||
      if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
 | 
			
		||||
        if ! _ssh_remote_cmd "$_cmdstr"; then
 | 
			
		||||
          return $_err_code
 | 
			
		||||
        fi
 | 
			
		||||
        _cmdstr=""
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # FULLCHAIN is optional.
 | 
			
		||||
  # If provided then fullchain certificate will be copied or appended to provided filename.
 | 
			
		||||
  _getdeployconf DEPLOY_SSH_FULLCHAIN
 | 
			
		||||
  _debug2 DEPLOY_SSH_FULLCHAIN "$DEPLOY_SSH_FULLCHAIN"
 | 
			
		||||
  if [ -n "$DEPLOY_SSH_FULLCHAIN" ]; then
 | 
			
		||||
    Le_Deploy_ssh_fullchain="$DEPLOY_SSH_FULLCHAIN"
 | 
			
		||||
    _savedomainconf Le_Deploy_ssh_fullchain "$Le_Deploy_ssh_fullchain"
 | 
			
		||||
  fi
 | 
			
		||||
  if [ -n "$Le_Deploy_ssh_fullchain" ]; then
 | 
			
		||||
    _pipe=">"
 | 
			
		||||
    if [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_keyfile" ] ||
 | 
			
		||||
      [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_certfile" ] ||
 | 
			
		||||
      [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_cafile" ]; then
 | 
			
		||||
    if [ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_KEYFILE" ] ||
 | 
			
		||||
      [ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_CERTFILE" ] ||
 | 
			
		||||
      [ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_CAFILE" ]; then
 | 
			
		||||
      # if filename is same as previous file then append.
 | 
			
		||||
      _pipe=">>"
 | 
			
		||||
    elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
 | 
			
		||||
    elif [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
 | 
			
		||||
      # backup file we are about to overwrite.
 | 
			
		||||
      _cmdstr="$_cmdstr cp $Le_Deploy_ssh_fullchain $_backupdir >/dev/null;"
 | 
			
		||||
      _cmdstr="$_cmdstr cp $DEPLOY_SSH_FULLCHAIN $_backupdir >/dev/null;"
 | 
			
		||||
      if [ "$DEPLOY_SSH_FULLCHAIN" = "yes" ]; then
 | 
			
		||||
        if ! _ssh_remote_cmd "$_cmdstr"; then
 | 
			
		||||
          return $_err_code
 | 
			
		||||
        fi
 | 
			
		||||
        _cmdstr=""
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # copy new certificate into file.
 | 
			
		||||
    _cmdstr="$_cmdstr echo \"$(cat "$_cfullchain")\" $_pipe $Le_Deploy_ssh_fullchain;"
 | 
			
		||||
    _info "will copy fullchain to remote file $Le_Deploy_ssh_fullchain"
 | 
			
		||||
    if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
 | 
			
		||||
      if ! _ssh_remote_cmd "$_cmdstr"; then
 | 
			
		||||
    if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
 | 
			
		||||
      # scp the file
 | 
			
		||||
      _local_full_file=$(_mktemp)
 | 
			
		||||
      if [ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_KEYFILE" ]; then
 | 
			
		||||
        cat "$_ckey" >>"$_local_full_file"
 | 
			
		||||
      fi
 | 
			
		||||
      if [ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_CERTFILE" ]; then
 | 
			
		||||
        cat "$_ccert" >>"$_local_full_file"
 | 
			
		||||
      fi
 | 
			
		||||
      if [ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_CAFILE" ]; then
 | 
			
		||||
        cat "$_cca" >>"$_local_full_file"
 | 
			
		||||
      fi
 | 
			
		||||
      cat "$_cfullchain" >>"$_local_full_file"
 | 
			
		||||
      if ! _scp_remote_cmd "$_local_full_file" "$DEPLOY_SSH_FULLCHAIN"; then
 | 
			
		||||
        return $_err_code
 | 
			
		||||
      fi
 | 
			
		||||
      _cmdstr=""
 | 
			
		||||
    else
 | 
			
		||||
      # ssh echo to the file
 | 
			
		||||
      _cmdstr="$_cmdstr echo \"$(cat "$_cfullchain")\" $_pipe $DEPLOY_SSH_FULLCHAIN;"
 | 
			
		||||
      _info "will copy fullchain to remote file $DEPLOY_SSH_FULLCHAIN"
 | 
			
		||||
      if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
 | 
			
		||||
        if ! _ssh_remote_cmd "$_cmdstr"; then
 | 
			
		||||
          return $_err_code
 | 
			
		||||
        fi
 | 
			
		||||
        _cmdstr=""
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # REMOTE_CMD is optional.
 | 
			
		||||
  # If provided then this command will be executed on remote host.
 | 
			
		||||
  _getdeployconf DEPLOY_SSH_REMOTE_CMD
 | 
			
		||||
  _debug2 DEPLOY_SSH_REMOTE_CMD "$DEPLOY_SSH_REMOTE_CMD"
 | 
			
		||||
  if [ -n "$DEPLOY_SSH_REMOTE_CMD" ]; then
 | 
			
		||||
    Le_Deploy_ssh_remote_cmd="$DEPLOY_SSH_REMOTE_CMD"
 | 
			
		||||
    _savedomainconf Le_Deploy_ssh_remote_cmd "$Le_Deploy_ssh_remote_cmd"
 | 
			
		||||
  # cleanup local files if any
 | 
			
		||||
  if [ -f "$_local_cert_file" ]; then
 | 
			
		||||
    rm -f "$_local_cert_file"
 | 
			
		||||
  fi
 | 
			
		||||
  if [ -n "$Le_Deploy_ssh_remote_cmd" ]; then
 | 
			
		||||
    _cmdstr="$_cmdstr $Le_Deploy_ssh_remote_cmd;"
 | 
			
		||||
    _info "Will execute remote command $Le_Deploy_ssh_remote_cmd"
 | 
			
		||||
    if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
 | 
			
		||||
  if [ -f "$_local_ca_file" ]; then
 | 
			
		||||
    rm -f "$_local_ca_file"
 | 
			
		||||
  fi
 | 
			
		||||
  if [ -f "$_local_full_file" ]; then
 | 
			
		||||
    rm -f "$_local_full_file"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -n "$DEPLOY_SSH_REMOTE_CMD" ]; then
 | 
			
		||||
    _cmdstr="$_cmdstr $DEPLOY_SSH_REMOTE_CMD;"
 | 
			
		||||
    _info "Will execute remote command $DEPLOY_SSH_REMOTE_CMD"
 | 
			
		||||
    if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
 | 
			
		||||
      if ! _ssh_remote_cmd "$_cmdstr"; then
 | 
			
		||||
        return $_err_code
 | 
			
		||||
      fi
 | 
			
		||||
@@ -282,17 +410,25 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
 | 
			
		||||
      return $_err_code
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
  # cleanup in case all is ok
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#cmd
 | 
			
		||||
_ssh_remote_cmd() {
 | 
			
		||||
  _cmd="$1"
 | 
			
		||||
 | 
			
		||||
  _ssh_cmd="$DEPLOY_SSH_CMD"
 | 
			
		||||
  if [ -n "$_port" ]; then
 | 
			
		||||
    _ssh_cmd="$_ssh_cmd -p $_port"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _secure_debug "Remote commands to execute: $_cmd"
 | 
			
		||||
  _info "Submitting sequence of commands to remote server by ssh"
 | 
			
		||||
  _info "Submitting sequence of commands to remote server by $_ssh_cmd"
 | 
			
		||||
 | 
			
		||||
  # quotations in bash cmd below intended.  Squash travis spellcheck error
 | 
			
		||||
  # shellcheck disable=SC2029
 | 
			
		||||
  $Le_Deploy_ssh_cmd "$Le_Deploy_ssh_user@$Le_Deploy_ssh_server" sh -c "'$_cmd'"
 | 
			
		||||
  $_ssh_cmd "$DEPLOY_SSH_USER@$_host" sh -c "'$_cmd'"
 | 
			
		||||
  _err_code="$?"
 | 
			
		||||
 | 
			
		||||
  if [ "$_err_code" != "0" ]; then
 | 
			
		||||
@@ -301,3 +437,26 @@ _ssh_remote_cmd() {
 | 
			
		||||
 | 
			
		||||
  return $_err_code
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# cmd scp
 | 
			
		||||
_scp_remote_cmd() {
 | 
			
		||||
  _src=$1
 | 
			
		||||
  _dest=$2
 | 
			
		||||
 | 
			
		||||
  _scp_cmd="$DEPLOY_SSH_SCP_CMD"
 | 
			
		||||
  if [ -n "$_port" ]; then
 | 
			
		||||
    _scp_cmd="$_scp_cmd -P $_port"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _secure_debug "Remote copy source $_src to destination $_dest"
 | 
			
		||||
  _info "Submitting secure copy by $_scp_cmd"
 | 
			
		||||
 | 
			
		||||
  $_scp_cmd "$_src" "$DEPLOY_SSH_USER"@"$_host":"$_dest"
 | 
			
		||||
  _err_code="$?"
 | 
			
		||||
 | 
			
		||||
  if [ "$_err_code" != "0" ]; then
 | 
			
		||||
    _err "Error code $_err_code returned from scp"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  return $_err_code
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,34 +1,53 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
# Here is a script to deploy cert to Synology DSM
 | 
			
		||||
#
 | 
			
		||||
# It requires following environment variables:
 | 
			
		||||
#
 | 
			
		||||
# SYNO_Username - Synology Username to login (must be an administrator)
 | 
			
		||||
# SYNO_Password - Synology Password to login
 | 
			
		||||
# SYNO_Certificate - Certificate description to target for replacement
 | 
			
		||||
#
 | 
			
		||||
# The following environmental variables may be set if you don't like their
 | 
			
		||||
# default values:
 | 
			
		||||
#
 | 
			
		||||
# SYNO_Scheme - defaults to http
 | 
			
		||||
# SYNO_Hostname - defaults to localhost
 | 
			
		||||
# SYNO_Port - defaults to 5000
 | 
			
		||||
# SYNO_DID - device ID to skip OTP - defaults to empty
 | 
			
		||||
# SYNO_TOTP_SECRET - TOTP secret to generate OTP - defaults to empty
 | 
			
		||||
#
 | 
			
		||||
################################################################################
 | 
			
		||||
# ACME.sh 3rd party deploy plugin for Synology DSM
 | 
			
		||||
################################################################################
 | 
			
		||||
# Authors: Brian Hartvigsen (creator), https://github.com/tresni
 | 
			
		||||
#          Martin Arndt (contributor), https://troublezone.net/
 | 
			
		||||
# Updated: 2023-07-03
 | 
			
		||||
# Issues:  https://github.com/acmesh-official/acme.sh/issues/2727
 | 
			
		||||
################################################################################
 | 
			
		||||
# Usage (shown values are the examples):
 | 
			
		||||
# 1. Set required environment variables:
 | 
			
		||||
# - use automatically created temp admin user to authenticate
 | 
			
		||||
#   export SYNO_USE_TEMP_ADMIN=1
 | 
			
		||||
# - or provide your own admin user credential to authenticate
 | 
			
		||||
#   1. export SYNO_USERNAME="adminUser"
 | 
			
		||||
#   2. export SYNO_PASSWORD="adminPassword"
 | 
			
		||||
# 2. Set optional environment variables
 | 
			
		||||
# - common optional variables
 | 
			
		||||
#   - export SYNO_SCHEME="http"         - defaults to "http"
 | 
			
		||||
#   - export SYNO_HOSTNAME="localhost"  - defaults to "localhost"
 | 
			
		||||
#   - export SYNO_PORT="5000"           - defaults to "5000"
 | 
			
		||||
#   - export SYNO_CREATE=1 - to allow creating the cert if it doesn't exist
 | 
			
		||||
#   - export SYNO_CERTIFICATE="" - to replace a specific cert by its
 | 
			
		||||
#                                    description
 | 
			
		||||
# - temp admin optional variables
 | 
			
		||||
#   - export SYNO_LOCAL_HOSTNAME=1   - if set to 1, force to treat hostname is
 | 
			
		||||
#                                      targeting current local machine (since
 | 
			
		||||
#                                      this method only locally supported)
 | 
			
		||||
# - exsiting admin 2FA-OTP optional variables
 | 
			
		||||
#   - export SYNO_OTP_CODE="XXXXXX" - if set, script won't require to
 | 
			
		||||
#                                     interactive input the OTP code
 | 
			
		||||
#   - export SYNO_DEVICE_NAME="CertRenewal" - if set, script won't require to
 | 
			
		||||
#                                             interactive input the device name
 | 
			
		||||
#   - export SYNO_DEVICE_ID=""      - (deprecated, auth with OTP code instead)
 | 
			
		||||
#                                     required for omitting 2FA-OTP
 | 
			
		||||
# 3. Run command:
 | 
			
		||||
# acme.sh --deploy --deploy-hook synology_dsm -d example.com
 | 
			
		||||
################################################################################
 | 
			
		||||
# Dependencies:
 | 
			
		||||
# -------------
 | 
			
		||||
# - jq and curl
 | 
			
		||||
# - oathtool (When using 2 Factor Authentication and SYNO_TOTP_SECRET is set)
 | 
			
		||||
#
 | 
			
		||||
#returns 0 means success, otherwise error.
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
# - curl
 | 
			
		||||
# - synouser & synogroup & synosetkeyvalue (Required for SYNO_USE_TEMP_ADMIN=1)
 | 
			
		||||
################################################################################
 | 
			
		||||
# Return value:
 | 
			
		||||
# 0 means success, otherwise error.
 | 
			
		||||
################################################################################
 | 
			
		||||
 | 
			
		||||
########## Public functions ####################################################
 | 
			
		||||
#domain keyfile certfile cafile fullchain
 | 
			
		||||
synology_dsm_deploy() {
 | 
			
		||||
 | 
			
		||||
  _cdomain="$1"
 | 
			
		||||
  _ckey="$2"
 | 
			
		||||
  _ccert="$3"
 | 
			
		||||
@@ -36,148 +55,391 @@ synology_dsm_deploy() {
 | 
			
		||||
 | 
			
		||||
  _debug _cdomain "$_cdomain"
 | 
			
		||||
 | 
			
		||||
  # Get Username and Password, but don't save until we successfully authenticate
 | 
			
		||||
  _getdeployconf SYNO_Username
 | 
			
		||||
  _getdeployconf SYNO_Password
 | 
			
		||||
  _getdeployconf SYNO_Create
 | 
			
		||||
  _getdeployconf SYNO_DID
 | 
			
		||||
  _getdeployconf SYNO_TOTP_SECRET
 | 
			
		||||
  if [ -z "${SYNO_Username:-}" ] || [ -z "${SYNO_Password:-}" ]; then
 | 
			
		||||
    _err "SYNO_Username & SYNO_Password must be set"
 | 
			
		||||
  # Get username and password, but don't save until we authenticated successfully
 | 
			
		||||
  _migratedeployconf SYNO_Username SYNO_USERNAME
 | 
			
		||||
  _migratedeployconf SYNO_Password SYNO_PASSWORD
 | 
			
		||||
  _migratedeployconf SYNO_Device_ID SYNO_DEVICE_ID
 | 
			
		||||
  _migratedeployconf SYNO_Device_Name SYNO_DEVICE_NAME
 | 
			
		||||
  _getdeployconf SYNO_USERNAME
 | 
			
		||||
  _getdeployconf SYNO_PASSWORD
 | 
			
		||||
  _getdeployconf SYNO_DEVICE_ID
 | 
			
		||||
  _getdeployconf SYNO_DEVICE_NAME
 | 
			
		||||
 | 
			
		||||
  # Prepare to use temp admin if SYNO_USE_TEMP_ADMIN is set
 | 
			
		||||
  _getdeployconf SYNO_USE_TEMP_ADMIN
 | 
			
		||||
  _check2cleardeployconfexp SYNO_USE_TEMP_ADMIN
 | 
			
		||||
  _debug2 SYNO_USE_TEMP_ADMIN "$SYNO_USE_TEMP_ADMIN"
 | 
			
		||||
 | 
			
		||||
  if [ -n "$SYNO_USE_TEMP_ADMIN" ]; then
 | 
			
		||||
    if ! _exists synouser || ! _exists synogroup || ! _exists synosetkeyvalue; then
 | 
			
		||||
      _err "Missing required tools to creat temp admin user, please set SYNO_USERNAME and SYNO_PASSWORD instead."
 | 
			
		||||
      _err "Notice: temp admin user authorization method only supports local deployment on DSM."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    if synouser --help 2>&1 | grep -q 'Permission denied'; then
 | 
			
		||||
      _err "For creating temp admin user, the deploy script must be run as root."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    [ -n "$SYNO_USERNAME" ] || _savedeployconf SYNO_USERNAME ""
 | 
			
		||||
    [ -n "$SYNO_PASSWORD" ] || _savedeployconf SYNO_PASSWORD ""
 | 
			
		||||
 | 
			
		||||
    _debug "Setting temp admin user credential..."
 | 
			
		||||
    SYNO_USERNAME=sc-acmesh-tmp
 | 
			
		||||
    SYNO_PASSWORD=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 16)
 | 
			
		||||
    # Set 2FA-OTP settings to empty consider they won't be needed.
 | 
			
		||||
    SYNO_DEVICE_ID=
 | 
			
		||||
    SYNO_DEVICE_NAME=
 | 
			
		||||
    SYNO_OTP_CODE=
 | 
			
		||||
  else
 | 
			
		||||
    _debug2 SYNO_USERNAME "$SYNO_USERNAME"
 | 
			
		||||
    _secure_debug2 SYNO_PASSWORD "$SYNO_PASSWORD"
 | 
			
		||||
    _debug2 SYNO_DEVICE_NAME "$SYNO_DEVICE_NAME"
 | 
			
		||||
    _secure_debug2 SYNO_DEVICE_ID "$SYNO_DEVICE_ID"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "$SYNO_USERNAME" ] || [ -z "$SYNO_PASSWORD" ]; then
 | 
			
		||||
    _err "You must set either SYNO_USE_TEMP_ADMIN, or set both SYNO_USERNAME and SYNO_PASSWORD."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 SYNO_Username "$SYNO_Username"
 | 
			
		||||
  _secure_debug2 SYNO_Password "$SYNO_Password"
 | 
			
		||||
 | 
			
		||||
  # Optional scheme, hostname, and port for Synology DSM
 | 
			
		||||
  _getdeployconf SYNO_Scheme
 | 
			
		||||
  _getdeployconf SYNO_Hostname
 | 
			
		||||
  _getdeployconf SYNO_Port
 | 
			
		||||
  # Optional scheme, hostname and port for Synology DSM
 | 
			
		||||
  _migratedeployconf SYNO_Scheme SYNO_SCHEME
 | 
			
		||||
  _migratedeployconf SYNO_Hostname SYNO_HOSTNAME
 | 
			
		||||
  _migratedeployconf SYNO_Port SYNO_PORT
 | 
			
		||||
  _getdeployconf SYNO_SCHEME
 | 
			
		||||
  _getdeployconf SYNO_HOSTNAME
 | 
			
		||||
  _getdeployconf SYNO_PORT
 | 
			
		||||
 | 
			
		||||
  # default vaules for scheme, hostname, and port
 | 
			
		||||
  # defaulting to localhost and http because it's localhost...
 | 
			
		||||
  [ -n "${SYNO_Scheme}" ] || SYNO_Scheme="http"
 | 
			
		||||
  [ -n "${SYNO_Hostname}" ] || SYNO_Hostname="localhost"
 | 
			
		||||
  [ -n "${SYNO_Port}" ] || SYNO_Port="5000"
 | 
			
		||||
  # Default values for scheme, hostname and port
 | 
			
		||||
  # Defaulting to localhost and http, because it's localhost…
 | 
			
		||||
  [ -n "$SYNO_SCHEME" ] || SYNO_SCHEME=http
 | 
			
		||||
  [ -n "$SYNO_HOSTNAME" ] || SYNO_HOSTNAME=localhost
 | 
			
		||||
  [ -n "$SYNO_PORT" ] || SYNO_PORT=5000
 | 
			
		||||
  _savedeployconf SYNO_SCHEME "$SYNO_SCHEME"
 | 
			
		||||
  _savedeployconf SYNO_HOSTNAME "$SYNO_HOSTNAME"
 | 
			
		||||
  _savedeployconf SYNO_PORT "$SYNO_PORT"
 | 
			
		||||
  _debug2 SYNO_SCHEME "$SYNO_SCHEME"
 | 
			
		||||
  _debug2 SYNO_HOSTNAME "$SYNO_HOSTNAME"
 | 
			
		||||
  _debug2 SYNO_PORT "$SYNO_PORT"
 | 
			
		||||
 | 
			
		||||
  _savedeployconf SYNO_Scheme "$SYNO_Scheme"
 | 
			
		||||
  _savedeployconf SYNO_Hostname "$SYNO_Hostname"
 | 
			
		||||
  _savedeployconf SYNO_Port "$SYNO_Port"
 | 
			
		||||
 | 
			
		||||
  _debug2 SYNO_Scheme "$SYNO_Scheme"
 | 
			
		||||
  _debug2 SYNO_Hostname "$SYNO_Hostname"
 | 
			
		||||
  _debug2 SYNO_Port "$SYNO_Port"
 | 
			
		||||
 | 
			
		||||
  # Get the certificate description, but don't save it until we verfiy it's real
 | 
			
		||||
  _getdeployconf SYNO_Certificate
 | 
			
		||||
  _debug SYNO_Certificate "${SYNO_Certificate:-}"
 | 
			
		||||
  # Get the certificate description, but don't save it until we verify it's real
 | 
			
		||||
  _migratedeployconf SYNO_Certificate SYNO_CERTIFICATE "base64"
 | 
			
		||||
  _getdeployconf SYNO_CERTIFICATE
 | 
			
		||||
  _check2cleardeployconfexp SYNO_CERTIFICATE
 | 
			
		||||
  _debug SYNO_CERTIFICATE "${SYNO_CERTIFICATE:-}"
 | 
			
		||||
 | 
			
		||||
  # shellcheck disable=SC1003 # We are not trying to escape a single quote
 | 
			
		||||
  if printf "%s" "$SYNO_Certificate" | grep '\\'; then
 | 
			
		||||
  if printf "%s" "$SYNO_CERTIFICATE" | grep '\\'; then
 | 
			
		||||
    _err "Do not use a backslash (\) in your certificate description"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _base_url="$SYNO_Scheme://$SYNO_Hostname:$SYNO_Port"
 | 
			
		||||
  _debug "Getting API version..."
 | 
			
		||||
  _base_url="$SYNO_SCHEME://$SYNO_HOSTNAME:$SYNO_PORT"
 | 
			
		||||
  _debug _base_url "$_base_url"
 | 
			
		||||
 | 
			
		||||
  _debug "Getting API version"
 | 
			
		||||
  response=$(_get "$_base_url/webapi/query.cgi?api=SYNO.API.Info&version=1&method=query&query=SYNO.API.Auth")
 | 
			
		||||
  api_path=$(echo "$response" | grep "SYNO.API.Auth" | sed -n 's/.*"path" *: *"\([^"]*\)".*/\1/p')
 | 
			
		||||
  api_version=$(echo "$response" | grep "SYNO.API.Auth" | sed -n 's/.*"maxVersion" *: *\([0-9]*\).*/\1/p')
 | 
			
		||||
  _debug3 response "$response"
 | 
			
		||||
  _debug3 api_path "$api_path"
 | 
			
		||||
  _debug3 api_version "$api_version"
 | 
			
		||||
 | 
			
		||||
  # Login, get the token from JSON and session id from cookie
 | 
			
		||||
  _info "Logging into $SYNO_Hostname:$SYNO_Port"
 | 
			
		||||
  encoded_username="$(printf "%s" "$SYNO_Username" | _url_encode)"
 | 
			
		||||
  encoded_password="$(printf "%s" "$SYNO_Password" | _url_encode)"
 | 
			
		||||
  # Login, get the session ID and SynoToken from JSON
 | 
			
		||||
  _info "Logging into $SYNO_HOSTNAME:$SYNO_PORT..."
 | 
			
		||||
  encoded_username="$(printf "%s" "$SYNO_USERNAME" | _url_encode)"
 | 
			
		||||
  encoded_password="$(printf "%s" "$SYNO_PASSWORD" | _url_encode)"
 | 
			
		||||
 | 
			
		||||
  # ## START ## - DEPRECATED, for backward compatibility
 | 
			
		||||
  _getdeployconf SYNO_TOTP_SECRET
 | 
			
		||||
 | 
			
		||||
  otp_code=""
 | 
			
		||||
  if [ -n "$SYNO_TOTP_SECRET" ]; then
 | 
			
		||||
    if _exists oathtool; then
 | 
			
		||||
      otp_code="$(oathtool --base32 --totp "${SYNO_TOTP_SECRET}" 2>/dev/null)"
 | 
			
		||||
    else
 | 
			
		||||
    _info "WARNING: Usage of SYNO_TOTP_SECRET is deprecated!"
 | 
			
		||||
    _info "         See synology_dsm.sh script or ACME.sh Wiki page for details:"
 | 
			
		||||
    _info "         https://github.com/acmesh-official/acme.sh/wiki/Synology-NAS-Guide"
 | 
			
		||||
    if ! _exists oathtool; then
 | 
			
		||||
      _err "oathtool could not be found, install oathtool to use SYNO_TOTP_SECRET"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    DEPRECATED_otp_code="$(oathtool --base32 --totp "$SYNO_TOTP_SECRET" 2>/dev/null)"
 | 
			
		||||
 | 
			
		||||
    if [ -z "$SYNO_DEVICE_ID" ]; then
 | 
			
		||||
      _getdeployconf SYNO_DID
 | 
			
		||||
      [ -n "$SYNO_DID" ] || SYNO_DEVICE_ID="$SYNO_DID"
 | 
			
		||||
    fi
 | 
			
		||||
    if [ -n "$SYNO_DEVICE_ID" ]; then
 | 
			
		||||
      _H1="Cookie: did=$SYNO_DEVICE_ID"
 | 
			
		||||
      export _H1
 | 
			
		||||
      _debug3 H1 "${_H1}"
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    response=$(_post "method=login&account=$encoded_username&passwd=$encoded_password&api=SYNO.API.Auth&version=$api_version&enable_syno_token=yes&otp_code=$DEPRECATED_otp_code&device_name=certrenewal&device_id=$SYNO_DEVICE_ID" "$_base_url/webapi/$api_path?enable_syno_token=yes")
 | 
			
		||||
    _debug3 response "$response"
 | 
			
		||||
  # ## END ## - DEPRECATED, for backward compatibility
 | 
			
		||||
  # If SYNO_DEVICE_ID or SYNO_OTP_CODE is set, we treat current account enabled 2FA-OTP.
 | 
			
		||||
  # Notice that if SYNO_USE_TEMP_ADMIN=1, both variables will be unset
 | 
			
		||||
  else
 | 
			
		||||
    if [ -n "$SYNO_DEVICE_ID" ] || [ -n "$SYNO_OTP_CODE" ]; then
 | 
			
		||||
      response='{"error":{"code":403}}'
 | 
			
		||||
    # Assume the current account disabled 2FA-OTP, try to log in right away.
 | 
			
		||||
    else
 | 
			
		||||
      if [ -n "$SYNO_USE_TEMP_ADMIN" ]; then
 | 
			
		||||
        _getdeployconf SYNO_LOCAL_HOSTNAME
 | 
			
		||||
        _debug SYNO_LOCAL_HOSTNAME "${SYNO_LOCAL_HOSTNAME:-}"
 | 
			
		||||
        if [ "$SYNO_LOCAL_HOSTNAME" != "1" ] && [ "$SYNO_LOCAL_HOSTNAME" == "$SYNO_HOSTNAME" ]; then
 | 
			
		||||
          if [ "$SYNO_HOSTNAME" != "localhost" ] && [ "$SYNO_HOSTNAME" != "127.0.0.1" ]; then
 | 
			
		||||
            _err "SYNO_USE_TEMP_ADMIN=1 only support local deployment, though if you are sure that the hostname $SYNO_HOSTNAME is targeting to your **current local machine**, execute 'export SYNO_LOCAL_HOSTNAME=1' then rerun."
 | 
			
		||||
            return 1
 | 
			
		||||
          fi
 | 
			
		||||
        fi
 | 
			
		||||
        _debug "Creating temp admin user in Synology DSM..."
 | 
			
		||||
        if synogroup --help | grep -q '\-\-memberadd '; then
 | 
			
		||||
          _temp_admin_create "$SYNO_USERNAME" "$SYNO_PASSWORD"
 | 
			
		||||
          synogroup --memberadd administrators "$SYNO_USERNAME" >/dev/null
 | 
			
		||||
        elif synogroup --help | grep -q '\-\-member '; then
 | 
			
		||||
          # For supporting DSM 6.x which only has `--member` parameter.
 | 
			
		||||
          cur_admins=$(synogroup --get administrators | awk -F '[][]' '/Group Members/,0{if(NF>1)printf "%s ", $2}')
 | 
			
		||||
          if [ -n "$cur_admins" ]; then
 | 
			
		||||
            _temp_admin_create "$SYNO_USERNAME" "$SYNO_PASSWORD"
 | 
			
		||||
            _secure_debug3 admin_users "$cur_admins$SYNO_USERNAME"
 | 
			
		||||
            # shellcheck disable=SC2086
 | 
			
		||||
            synogroup --member administrators $cur_admins $SYNO_USERNAME >/dev/null
 | 
			
		||||
          else
 | 
			
		||||
            _err "The tool synogroup may be broken, please set SYNO_USERNAME and SYNO_PASSWORD instead."
 | 
			
		||||
            return 1
 | 
			
		||||
          fi
 | 
			
		||||
        else
 | 
			
		||||
          _err "Unsupported synogroup tool detected, please set SYNO_USERNAME and SYNO_PASSWORD instead."
 | 
			
		||||
          return 1
 | 
			
		||||
        fi
 | 
			
		||||
        # havig a workaround to temporary disable enforce 2FA-OTP, will restore
 | 
			
		||||
        # it soon (after a single request), though if any accident occurs like
 | 
			
		||||
        # unexpected interruption, this setting can be easily reverted manually.
 | 
			
		||||
        otp_enforce_option=$(synogetkeyvalue /etc/synoinfo.conf otp_enforce_option)
 | 
			
		||||
        if [ -n "$otp_enforce_option" ] && [ "${otp_enforce_option:-"none"}" != "none" ]; then
 | 
			
		||||
          synosetkeyvalue /etc/synoinfo.conf otp_enforce_option none
 | 
			
		||||
          _info "Enforcing 2FA-OTP has been disabled to complete temp admin authentication."
 | 
			
		||||
          _info "Notice: it will be restored soon, if not, you can restore it manually via Control Panel."
 | 
			
		||||
          _info "previous_otp_enforce_option" "$otp_enforce_option"
 | 
			
		||||
        else
 | 
			
		||||
          otp_enforce_option=""
 | 
			
		||||
        fi
 | 
			
		||||
      fi
 | 
			
		||||
      response=$(_get "$_base_url/webapi/$api_path?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&enable_syno_token=yes")
 | 
			
		||||
      if [ -n "$SYNO_USE_TEMP_ADMIN" ] && [ -n "$otp_enforce_option" ]; then
 | 
			
		||||
        synosetkeyvalue /etc/synoinfo.conf otp_enforce_option "$otp_enforce_option"
 | 
			
		||||
        _info "Restored previous enforce 2FA-OTP option."
 | 
			
		||||
      fi
 | 
			
		||||
      _debug3 response "$response"
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -n "$SYNO_DID" ]; then
 | 
			
		||||
    _H1="Cookie: did=$SYNO_DID"
 | 
			
		||||
    export _H1
 | 
			
		||||
    _debug3 H1 "${_H1}"
 | 
			
		||||
  error_code=$(echo "$response" | grep '"error":' | grep -o '"code":[0-9]*' | grep -o '[0-9]*')
 | 
			
		||||
  _debug2 error_code "$error_code"
 | 
			
		||||
  # Account has 2FA-OTP enabled, since error 403 reported.
 | 
			
		||||
  # https://global.download.synology.com/download/Document/Software/DeveloperGuide/Os/DSM/All/enu/DSM_Login_Web_API_Guide_enu.pdf
 | 
			
		||||
  if [ "$error_code" == "403" ]; then
 | 
			
		||||
    if [ -z "$SYNO_DEVICE_NAME" ]; then
 | 
			
		||||
      printf "Enter device name or leave empty for default (CertRenewal): "
 | 
			
		||||
      read -r SYNO_DEVICE_NAME
 | 
			
		||||
      [ -n "$SYNO_DEVICE_NAME" ] || SYNO_DEVICE_NAME="CertRenewal"
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if [ -n "$SYNO_DEVICE_ID" ]; then
 | 
			
		||||
      # Omit OTP code with SYNO_DEVICE_ID.
 | 
			
		||||
      response=$(_get "$_base_url/webapi/$api_path?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&enable_syno_token=yes&device_name=$SYNO_DEVICE_NAME&device_id=$SYNO_DEVICE_ID")
 | 
			
		||||
      _secure_debug3 response "$response"
 | 
			
		||||
    else
 | 
			
		||||
      # Require the OTP code if still unset.
 | 
			
		||||
      if [ -z "$SYNO_OTP_CODE" ]; then
 | 
			
		||||
        printf "Enter OTP code for user '%s': " "$SYNO_USERNAME"
 | 
			
		||||
        read -r SYNO_OTP_CODE
 | 
			
		||||
      fi
 | 
			
		||||
      _secure_debug SYNO_OTP_CODE "${SYNO_OTP_CODE:-}"
 | 
			
		||||
 | 
			
		||||
      if [ -z "$SYNO_OTP_CODE" ]; then
 | 
			
		||||
        response='{"error":{"code":404}}'
 | 
			
		||||
      else
 | 
			
		||||
        response=$(_get "$_base_url/webapi/$api_path?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&enable_syno_token=yes&enable_device_token=yes&device_name=$SYNO_DEVICE_NAME&otp_code=$SYNO_OTP_CODE")
 | 
			
		||||
        _secure_debug3 response "$response"
 | 
			
		||||
 | 
			
		||||
        id_property='device_id'
 | 
			
		||||
        [ "${api_version}" -gt '6' ] || id_property='did'
 | 
			
		||||
        SYNO_DEVICE_ID=$(echo "$response" | grep "$id_property" | sed -n 's/.*"'$id_property'" *: *"\([^"]*\).*/\1/p')
 | 
			
		||||
        _secure_debug2 SYNO_DEVICE_ID "$SYNO_DEVICE_ID"
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
    error_code=$(echo "$response" | grep '"error":' | grep -o '"code":[0-9]*' | grep -o '[0-9]*')
 | 
			
		||||
    _debug2 error_code "$error_code"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  response=$(_post "method=login&account=$encoded_username&passwd=$encoded_password&api=SYNO.API.Auth&version=$api_version&enable_syno_token=yes&otp_code=$otp_code" "$_base_url/webapi/auth.cgi?enable_syno_token=yes")
 | 
			
		||||
  token=$(echo "$response" | grep "synotoken" | sed -n 's/.*"synotoken" *: *"\([^"]*\).*/\1/p')
 | 
			
		||||
  _debug3 response "$response"
 | 
			
		||||
  _debug token "$token"
 | 
			
		||||
 | 
			
		||||
  if [ -z "$token" ]; then
 | 
			
		||||
    _err "Unable to authenticate to $SYNO_Hostname:$SYNO_Port using $SYNO_Scheme."
 | 
			
		||||
    _err "Check your username and password."
 | 
			
		||||
    _err "If two-factor authentication is enabled for the user, set SYNO_TOTP_SECRET."
 | 
			
		||||
  if [ -n "$error_code" ]; then
 | 
			
		||||
    if [ "$error_code" == "403" ] && [ -n "$SYNO_DEVICE_ID" ]; then
 | 
			
		||||
      _cleardeployconf SYNO_DEVICE_ID
 | 
			
		||||
      _err "Failed to authenticate with SYNO_DEVICE_ID (may expired or invalid), please try again in a new terminal window."
 | 
			
		||||
    elif [ "$error_code" == "404" ]; then
 | 
			
		||||
      _err "Failed to authenticate with provided 2FA-OTP code, please try again in a new terminal window."
 | 
			
		||||
    elif [ "$error_code" == "406" ]; then
 | 
			
		||||
      if [ -n "$SYNO_USE_TEMP_ADMIN" ]; then
 | 
			
		||||
        _err "Failed with unexcepted error, please report this by providing full log with '--debug 3'."
 | 
			
		||||
      else
 | 
			
		||||
        _err "Enforce auth with 2FA-OTP enabled, please configure the user to enable 2FA-OTP to continue."
 | 
			
		||||
      fi
 | 
			
		||||
    elif [ "$error_code" == "400" ]; then
 | 
			
		||||
      _err "Failed to authenticate, no such account or incorrect password."
 | 
			
		||||
    elif [ "$error_code" == "401" ]; then
 | 
			
		||||
      _err "Failed to authenticate with a non-existent account."
 | 
			
		||||
    elif [ "$error_code" == "408" ] || [ "$error_code" == "409" ] || [ "$error_code" == "410" ]; then
 | 
			
		||||
      _err "Failed to authenticate, the account password has expired or must be changed."
 | 
			
		||||
    else
 | 
			
		||||
      _err "Failed to authenticate with error: $error_code."
 | 
			
		||||
    fi
 | 
			
		||||
    _temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  sid=$(echo "$response" | grep "sid" | sed -n 's/.*"sid" *: *"\([^"]*\).*/\1/p')
 | 
			
		||||
  token=$(echo "$response" | grep "synotoken" | sed -n 's/.*"synotoken" *: *"\([^"]*\).*/\1/p')
 | 
			
		||||
  _debug "Session ID" "$sid"
 | 
			
		||||
  _debug SynoToken "$token"
 | 
			
		||||
  if [ -z "$sid" ] || [ -z "$token" ]; then
 | 
			
		||||
    # Still can't get necessary info even got no errors, may Synology have API updated?
 | 
			
		||||
    _err "Unable to authenticate to $_base_url, you may report this by providing full log with '--debug 3'."
 | 
			
		||||
    _temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _H1="X-SYNO-TOKEN: $token"
 | 
			
		||||
  export _H1
 | 
			
		||||
  _debug2 H1 "${_H1}"
 | 
			
		||||
 | 
			
		||||
  # Now that we know the username and password are good, save them
 | 
			
		||||
  _savedeployconf SYNO_Username "$SYNO_Username"
 | 
			
		||||
  _savedeployconf SYNO_Password "$SYNO_Password"
 | 
			
		||||
  _savedeployconf SYNO_DID "$SYNO_DID"
 | 
			
		||||
  _savedeployconf SYNO_TOTP_SECRET "$SYNO_TOTP_SECRET"
 | 
			
		||||
  # Now that we know the username and password are good, save them if not in temp admin mode.
 | 
			
		||||
  if [ -n "$SYNO_USE_TEMP_ADMIN" ]; then
 | 
			
		||||
    _cleardeployconf SYNO_USERNAME
 | 
			
		||||
    _cleardeployconf SYNO_PASSWORD
 | 
			
		||||
    _cleardeployconf SYNO_DEVICE_ID
 | 
			
		||||
    _cleardeployconf SYNO_DEVICE_NAME
 | 
			
		||||
    _savedeployconf SYNO_USE_TEMP_ADMIN "$SYNO_USE_TEMP_ADMIN"
 | 
			
		||||
    _savedeployconf SYNO_LOCAL_HOSTNAME "$SYNO_HOSTNAME"
 | 
			
		||||
  else
 | 
			
		||||
    _savedeployconf SYNO_USERNAME "$SYNO_USERNAME"
 | 
			
		||||
    _savedeployconf SYNO_PASSWORD "$SYNO_PASSWORD"
 | 
			
		||||
    _savedeployconf SYNO_DEVICE_ID "$SYNO_DEVICE_ID"
 | 
			
		||||
    _savedeployconf SYNO_DEVICE_NAME "$SYNO_DEVICE_NAME"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Getting certificates in Synology DSM"
 | 
			
		||||
  _info "Getting certificates in Synology DSM..."
 | 
			
		||||
  response=$(_post "api=SYNO.Core.Certificate.CRT&method=list&version=1&_sid=$sid" "$_base_url/webapi/entry.cgi")
 | 
			
		||||
  _debug3 response "$response"
 | 
			
		||||
  escaped_certificate="$(printf "%s" "$SYNO_Certificate" | sed 's/\([].*^$[]\)/\\\1/g;s/"/\\\\"/g')"
 | 
			
		||||
  escaped_certificate="$(printf "%s" "$SYNO_CERTIFICATE" | sed 's/\([].*^$[]\)/\\\1/g;s/"/\\\\"/g')"
 | 
			
		||||
  _debug escaped_certificate "$escaped_certificate"
 | 
			
		||||
  id=$(echo "$response" | sed -n "s/.*\"desc\":\"$escaped_certificate\",\"id\":\"\([^\"]*\).*/\1/p")
 | 
			
		||||
  _debug2 id "$id"
 | 
			
		||||
 | 
			
		||||
  if [ -z "$id" ] && [ -z "${SYNO_Create:-}" ]; then
 | 
			
		||||
    _err "Unable to find certificate: $SYNO_Certificate and \$SYNO_Create is not set"
 | 
			
		||||
  error_code=$(echo "$response" | grep '"error":' | grep -o '"code":[0-9]*' | grep -o '[0-9]*')
 | 
			
		||||
  _debug2 error_code "$error_code"
 | 
			
		||||
  if [ -n "$error_code" ]; then
 | 
			
		||||
    if [ "$error_code" -eq 105 ]; then
 | 
			
		||||
      _err "Current user is not administrator and does not have sufficient permission for deploying."
 | 
			
		||||
    else
 | 
			
		||||
      _err "Failed to fetch certificate info: $error_code, please try again or contact Synology to learn more."
 | 
			
		||||
    fi
 | 
			
		||||
    _temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # we've verified this certificate description is a thing, so save it
 | 
			
		||||
  _savedeployconf SYNO_Certificate "$SYNO_Certificate" "base64"
 | 
			
		||||
  _migratedeployconf SYNO_Create SYNO_CREATE
 | 
			
		||||
  _getdeployconf SYNO_CREATE
 | 
			
		||||
  _debug2 SYNO_CREATE "$SYNO_CREATE"
 | 
			
		||||
 | 
			
		||||
  _info "Generate form POST request"
 | 
			
		||||
  if [ -z "$id" ] && [ -z "$SYNO_CREATE" ]; then
 | 
			
		||||
    _err "Unable to find certificate: $SYNO_CERTIFICATE and $SYNO_CREATE is not set."
 | 
			
		||||
    _temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # We've verified this certificate description is a thing, so save it
 | 
			
		||||
  _savedeployconf SYNO_CERTIFICATE "$SYNO_CERTIFICATE" "base64"
 | 
			
		||||
 | 
			
		||||
  _info "Generating form POST request..."
 | 
			
		||||
  nl="\0015\0012"
 | 
			
		||||
  delim="--------------------------$(_utc_date | tr -d -- '-: ')"
 | 
			
		||||
  content="--$delim${nl}Content-Disposition: form-data; name=\"key\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")\0012"
 | 
			
		||||
  content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"cert\"; filename=\"$(basename "$_ccert")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ccert")\0012"
 | 
			
		||||
  content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"inter_cert\"; filename=\"$(basename "$_cca")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_cca")\0012"
 | 
			
		||||
  content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"id\"${nl}${nl}$id"
 | 
			
		||||
  content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"desc\"${nl}${nl}${SYNO_Certificate}"
 | 
			
		||||
  content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"desc\"${nl}${nl}${SYNO_CERTIFICATE}"
 | 
			
		||||
  if echo "$response" | sed -n "s/.*\"desc\":\"$escaped_certificate\",\([^{]*\).*/\1/p" | grep -- 'is_default":true' >/dev/null; then
 | 
			
		||||
    _debug2 default "this is the default certificate"
 | 
			
		||||
    _debug2 default "This is the default certificate"
 | 
			
		||||
    content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"as_default\"${nl}${nl}true"
 | 
			
		||||
  else
 | 
			
		||||
    _debug2 default "this is NOT the default certificate"
 | 
			
		||||
    _debug2 default "This is NOT the default certificate"
 | 
			
		||||
  fi
 | 
			
		||||
  content="$content${nl}--$delim--${nl}"
 | 
			
		||||
  content="$(printf "%b_" "$content")"
 | 
			
		||||
  content="${content%_}" # protect trailing \n
 | 
			
		||||
 | 
			
		||||
  _info "Upload certificate to the Synology DSM"
 | 
			
		||||
  _info "Upload certificate to the Synology DSM."
 | 
			
		||||
  response=$(_post "$content" "$_base_url/webapi/entry.cgi?api=SYNO.Core.Certificate&method=import&version=1&SynoToken=$token&_sid=$sid" "" "POST" "multipart/form-data; boundary=${delim}")
 | 
			
		||||
  _debug3 response "$response"
 | 
			
		||||
 | 
			
		||||
  if ! echo "$response" | grep '"error":' >/dev/null; then
 | 
			
		||||
    if echo "$response" | grep '"restart_httpd":true' >/dev/null; then
 | 
			
		||||
      _info "http services were restarted"
 | 
			
		||||
      _info "Restart HTTP services succeeded."
 | 
			
		||||
    else
 | 
			
		||||
      _info "http services were NOT restarted"
 | 
			
		||||
      _info "Restart HTTP services failed."
 | 
			
		||||
    fi
 | 
			
		||||
    _temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
 | 
			
		||||
    _logout
 | 
			
		||||
    return 0
 | 
			
		||||
  else
 | 
			
		||||
    _err "Unable to update certificate, error code $response"
 | 
			
		||||
    _temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
 | 
			
		||||
    _err "Unable to update certificate, got error response: $response."
 | 
			
		||||
    _logout
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
_logout() {
 | 
			
		||||
  # Logout CERT user only to not occupy a permanent session, e.g. in DSM's "Connected Users" widget (based on previous variables)
 | 
			
		||||
  response=$(_get "$_base_url/webapi/$api_path?api=SYNO.API.Auth&version=$api_version&method=logout&_sid=$sid")
 | 
			
		||||
  _debug3 response "$response"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_temp_admin_create() {
 | 
			
		||||
  _username="$1"
 | 
			
		||||
  _password="$2"
 | 
			
		||||
  synouser --del "$_username" >/dev/null 2>/dev/null
 | 
			
		||||
  synouser --add "$_username" "$_password" "" 0 "scruelt@hotmail.com" 0 >/dev/null
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_temp_admin_cleanup() {
 | 
			
		||||
  _flag=$1
 | 
			
		||||
  _username=$2
 | 
			
		||||
 | 
			
		||||
  if [ -n "${_flag}" ]; then
 | 
			
		||||
    _debug "Cleanuping temp admin info..."
 | 
			
		||||
    synouser --del "$_username" >/dev/null
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#_cleardeployconf   key
 | 
			
		||||
_cleardeployconf() {
 | 
			
		||||
  _cleardomainconf "SAVED_$1"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# key
 | 
			
		||||
_check2cleardeployconfexp() {
 | 
			
		||||
  _key="$1"
 | 
			
		||||
  _clear_key="CLEAR_$_key"
 | 
			
		||||
  # Clear saved settings if explicitly requested
 | 
			
		||||
  if [ -n "$(eval echo \$"$_clear_key")" ]; then
 | 
			
		||||
    _debug2 "$_key: value cleared from config, exported value will be ignored."
 | 
			
		||||
    _cleardeployconf "$_key"
 | 
			
		||||
    eval "$_key"=
 | 
			
		||||
    export "$_key"=
 | 
			
		||||
    eval SAVED_"$_key"=
 | 
			
		||||
    export SAVED_"$_key"=
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -184,6 +184,27 @@ truenas_deploy() {
 | 
			
		||||
    _info "S3 certificate is not configured or is not the same as TrueNAS web UI"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Checking if any chart release Apps is using the same certificate as TrueNAS web UI. Tool 'jq' is required"
 | 
			
		||||
  if _exists jq; then
 | 
			
		||||
    _info "Query all chart release"
 | 
			
		||||
    _release_list=$(_get "$_api_url/chart/release")
 | 
			
		||||
    _related_name_list=$(printf "%s" "$_release_list" | jq -r "[.[] | {name,certId: .config.ingress?.main.tls[]?.scaleCert} | select(.certId==$_active_cert_id) | .name ] | unique")
 | 
			
		||||
    _release_length=$(printf "%s" "$_related_name_list" | jq -r "length")
 | 
			
		||||
    _info "Found $_release_length related chart release in list: $_related_name_list"
 | 
			
		||||
    for i in $(seq 0 $((_release_length - 1))); do
 | 
			
		||||
      _release_name=$(echo "$_related_name_list" | jq -r ".[$i]")
 | 
			
		||||
      _info "Updating certificate from $_active_cert_id to $_cert_id for chart release: $_release_name"
 | 
			
		||||
      #Read the chart release configuration
 | 
			
		||||
      _chart_config=$(printf "%s" "$_release_list" | jq -r ".[] | select(.name==\"$_release_name\")")
 | 
			
		||||
      #Replace the old certificate id with the new one in path .config.ingress.main.tls[].scaleCert. Then update .config.ingress
 | 
			
		||||
      _updated_chart_config=$(printf "%s" "$_chart_config" | jq "(.config.ingress?.main.tls[]? | select(.scaleCert==$_active_cert_id) | .scaleCert  ) |= $_cert_id | .config.ingress ")
 | 
			
		||||
      _update_chart_result="$(_post "{\"values\" : { \"ingress\" : $_updated_chart_config } }" "$_api_url/chart/release/id/$_release_name" "" "PUT" "application/json")"
 | 
			
		||||
      _debug3 _update_chart_result "$_update_chart_result"
 | 
			
		||||
    done
 | 
			
		||||
  else
 | 
			
		||||
    _info "Tool 'jq' does not exists, skip chart release checking"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Deleting old certificate"
 | 
			
		||||
  _delete_result="$(_post "" "$_api_url/certificate/id/$_active_cert_id" "" "DELETE" "application/json")"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,15 @@
 | 
			
		||||
#   - self-hosted Unifi Controller
 | 
			
		||||
#   - Unifi Cloud Key (Gen1/2/2+)
 | 
			
		||||
#   - Unifi Cloud Key running UnifiOS (v2.0.0+, Gen2/2+ only)
 | 
			
		||||
#   - Unifi Dream Machine
 | 
			
		||||
#       This has not been tested on other "all-in-one" devices such as
 | 
			
		||||
#       UDM Pro or Unifi Express.
 | 
			
		||||
#
 | 
			
		||||
#       OS Version v2.0.0+
 | 
			
		||||
#       Network Application version 7.0.0+
 | 
			
		||||
#       OS version ~3.1 removed java and keytool from the UnifiOS.
 | 
			
		||||
#       Using PKCS12 format keystore appears to work fine.
 | 
			
		||||
#
 | 
			
		||||
# Please report bugs to https://github.com/acmesh-official/acme.sh/issues/3359
 | 
			
		||||
 | 
			
		||||
#returns 0 means success, otherwise error.
 | 
			
		||||
@@ -74,14 +83,16 @@ unifi_deploy() {
 | 
			
		||||
  _reload_cmd=""
 | 
			
		||||
 | 
			
		||||
  # Unifi Controller environment (self hosted or any Cloud Key) --
 | 
			
		||||
  # auto-detect by file /usr/lib/unifi/data/keystore:
 | 
			
		||||
  # auto-detect by file /usr/lib/unifi/data/keystore
 | 
			
		||||
  _unifi_keystore="${DEPLOY_UNIFI_KEYSTORE:-/usr/lib/unifi/data/keystore}"
 | 
			
		||||
  if [ -f "$_unifi_keystore" ]; then
 | 
			
		||||
    _info "Installing certificate for Unifi Controller (Java keystore)"
 | 
			
		||||
    _debug _unifi_keystore "$_unifi_keystore"
 | 
			
		||||
    if ! _exists keytool; then
 | 
			
		||||
      _err "keytool not found"
 | 
			
		||||
      return 1
 | 
			
		||||
      _do_keytool=0
 | 
			
		||||
      _info "Installing certificate for Unifi Controller (PKCS12 keystore)."
 | 
			
		||||
    else
 | 
			
		||||
      _do_keytool=1
 | 
			
		||||
      _info "Installing certificate for Unifi Controller (Java keystore)"
 | 
			
		||||
    fi
 | 
			
		||||
    if [ ! -w "$_unifi_keystore" ]; then
 | 
			
		||||
      _err "The file $_unifi_keystore is not writable, please change the permission."
 | 
			
		||||
@@ -92,6 +103,7 @@ unifi_deploy() {
 | 
			
		||||
 | 
			
		||||
    _debug "Generate import pkcs12"
 | 
			
		||||
    _import_pkcs12="$(_mktemp)"
 | 
			
		||||
    _debug "_toPkcs $_import_pkcs12 $_ckey $_ccert $_cca $_unifi_keypass unifi root"
 | 
			
		||||
    _toPkcs "$_import_pkcs12" "$_ckey" "$_ccert" "$_cca" "$_unifi_keypass" unifi root
 | 
			
		||||
    # shellcheck disable=SC2181
 | 
			
		||||
    if [ "$?" != "0" ]; then
 | 
			
		||||
@@ -99,22 +111,57 @@ unifi_deploy() {
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    _debug "Import into keystore: $_unifi_keystore"
 | 
			
		||||
    if keytool -importkeystore \
 | 
			
		||||
      -deststorepass "$_unifi_keypass" -destkeypass "$_unifi_keypass" -destkeystore "$_unifi_keystore" \
 | 
			
		||||
      -srckeystore "$_import_pkcs12" -srcstoretype PKCS12 -srcstorepass "$_unifi_keypass" \
 | 
			
		||||
      -alias unifi -noprompt; then
 | 
			
		||||
      _debug "Import keystore success!"
 | 
			
		||||
      rm "$_import_pkcs12"
 | 
			
		||||
    # Save the existing keystore in case something goes wrong.
 | 
			
		||||
    mv -f "${_unifi_keystore}" "${_unifi_keystore}"_original
 | 
			
		||||
    _info "Previous keystore saved to ${_unifi_keystore}_original."
 | 
			
		||||
 | 
			
		||||
    if [ "$_do_keytool" -eq 1 ]; then
 | 
			
		||||
      _debug "Import into keystore: $_unifi_keystore"
 | 
			
		||||
      if keytool -importkeystore \
 | 
			
		||||
        -deststorepass "$_unifi_keypass" -destkeypass "$_unifi_keypass" -destkeystore "$_unifi_keystore" \
 | 
			
		||||
        -srckeystore "$_import_pkcs12" -srcstoretype PKCS12 -srcstorepass "$_unifi_keypass" \
 | 
			
		||||
        -alias unifi -noprompt; then
 | 
			
		||||
        _debug "Import keystore success!"
 | 
			
		||||
      else
 | 
			
		||||
        _err "Error importing into Unifi Java keystore."
 | 
			
		||||
        _err "Please re-run with --debug and report a bug."
 | 
			
		||||
        _info "Restoring original keystore."
 | 
			
		||||
        mv -f "${_unifi_keystore}"_original "${_unifi_keystore}"
 | 
			
		||||
        rm "$_import_pkcs12"
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
    else
 | 
			
		||||
      _err "Error importing into Unifi Java keystore."
 | 
			
		||||
      _err "Please re-run with --debug and report a bug."
 | 
			
		||||
      rm "$_import_pkcs12"
 | 
			
		||||
      return 1
 | 
			
		||||
      _debug "Copying new keystore to $_unifi_keystore"
 | 
			
		||||
      cp -f "$_import_pkcs12" "$_unifi_keystore"
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # Update unifi service for certificate cipher compatibility
 | 
			
		||||
    if ${ACME_OPENSSL_BIN:-openssl} pkcs12 \
 | 
			
		||||
      -in "$_import_pkcs12" \
 | 
			
		||||
      -password pass:aircontrolenterprise \
 | 
			
		||||
      -nokeys | ${ACME_OPENSSL_BIN:-openssl} x509 -text \
 | 
			
		||||
      -noout | grep -i "signature" | grep -iq ecdsa >/dev/null 2>&1; then
 | 
			
		||||
      cp -f /usr/lib/unifi/data/system.properties /usr/lib/unifi/data/system.properties_original
 | 
			
		||||
      _info "Updating system configuration for cipher compatibility."
 | 
			
		||||
      _info "Saved original system config to /usr/lib/unifi/data/system.properties_original"
 | 
			
		||||
      sed -i '/unifi\.https\.ciphers/d' /usr/lib/unifi/data/system.properties
 | 
			
		||||
      echo "unifi.https.ciphers=ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES128-GCM-SHA256" >>/usr/lib/unifi/data/system.properties
 | 
			
		||||
      sed -i '/unifi\.https\.sslEnabledProtocols/d' /usr/lib/unifi/data/system.properties
 | 
			
		||||
      echo "unifi.https.sslEnabledProtocols=TLSv1.3,TLSv1.2" >>/usr/lib/unifi/data/system.properties
 | 
			
		||||
      _info "System configuration updated."
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    rm "$_import_pkcs12"
 | 
			
		||||
 | 
			
		||||
    # Restarting unifi-core will bring up unifi, doing it out of order results in
 | 
			
		||||
    # a certificate error, and breaks wifiman.
 | 
			
		||||
    # Restart if we aren't doing unifi-core, otherwise stop for later restart.
 | 
			
		||||
    if systemctl -q is-active unifi; then
 | 
			
		||||
      _reload_cmd="${_reload_cmd:+$_reload_cmd && }service unifi restart"
 | 
			
		||||
      if [ ! -f "${DEPLOY_UNIFI_CORE_CONFIG:-/data/unifi-core/config}/unifi-core.key" ]; then
 | 
			
		||||
        _reload_cmd="${_reload_cmd:+$_reload_cmd && }systemctl restart unifi"
 | 
			
		||||
      else
 | 
			
		||||
        _reload_cmd="${_reload_cmd:+$_reload_cmd && }systemctl stop unifi"
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
    _services_updated="${_services_updated} unifi"
 | 
			
		||||
    _info "Install Unifi Controller certificate success!"
 | 
			
		||||
@@ -165,6 +212,11 @@ unifi_deploy() {
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # Save the existing certs in case something goes wrong.
 | 
			
		||||
    cp -f "${_unifi_core_config}"/unifi-core.crt "${_unifi_core_config}"/unifi-core_original.crt
 | 
			
		||||
    cp -f "${_unifi_core_config}"/unifi-core.key "${_unifi_core_config}"/unifi-core_original.key
 | 
			
		||||
    _info "Previous certificate and key saved to ${_unifi_core_config}/unifi-core_original.crt/key."
 | 
			
		||||
 | 
			
		||||
    cat "$_cfullchain" >"${_unifi_core_config}/unifi-core.crt"
 | 
			
		||||
    cat "$_ckey" >"${_unifi_core_config}/unifi-core.key"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -7,13 +7,16 @@
 | 
			
		||||
#
 | 
			
		||||
# VAULT_PREFIX - this contains the prefix path in vault
 | 
			
		||||
# VAULT_ADDR - vault requires this to find your vault server
 | 
			
		||||
# VAULT_SAVE_TOKEN - set to anything if you want to save the token
 | 
			
		||||
# VAULT_RENEW_TOKEN - set to anything if you want to renew the token to default TTL before deploying
 | 
			
		||||
# VAULT_KV_V2 - set to anything if you are using v2 of the kv engine
 | 
			
		||||
#
 | 
			
		||||
# additionally, you need to ensure that VAULT_TOKEN is avialable
 | 
			
		||||
# to access the vault server
 | 
			
		||||
 | 
			
		||||
#returns 0 means success, otherwise error.
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
######## Public functions #####################
 | 
			
		||||
 | 
			
		||||
#domain keyfile certfile cafile fullchain
 | 
			
		||||
vault_deploy() {
 | 
			
		||||
@@ -45,33 +48,83 @@ vault_deploy() {
 | 
			
		||||
  fi
 | 
			
		||||
  _savedeployconf VAULT_ADDR "$VAULT_ADDR"
 | 
			
		||||
 | 
			
		||||
  _getdeployconf VAULT_SAVE_TOKEN
 | 
			
		||||
  _savedeployconf VAULT_SAVE_TOKEN "$VAULT_SAVE_TOKEN"
 | 
			
		||||
 | 
			
		||||
  _getdeployconf VAULT_RENEW_TOKEN
 | 
			
		||||
  _savedeployconf VAULT_RENEW_TOKEN "$VAULT_RENEW_TOKEN"
 | 
			
		||||
 | 
			
		||||
  _getdeployconf VAULT_KV_V2
 | 
			
		||||
  _savedeployconf VAULT_KV_V2 "$VAULT_KV_V2"
 | 
			
		||||
 | 
			
		||||
  _getdeployconf VAULT_TOKEN
 | 
			
		||||
  if [ -z "$VAULT_TOKEN" ]; then
 | 
			
		||||
    _err "VAULT_TOKEN needs to be defined"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  if [ -n "$VAULT_SAVE_TOKEN" ]; then
 | 
			
		||||
    _savedeployconf VAULT_TOKEN "$VAULT_TOKEN"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _migratedeployconf FABIO VAULT_FABIO_MODE
 | 
			
		||||
 | 
			
		||||
  # JSON does not allow multiline strings.
 | 
			
		||||
  # So replacing new-lines with "\n" here
 | 
			
		||||
  _ckey=$(sed -z 's/\n/\\n/g' <"$2")
 | 
			
		||||
  _ccert=$(sed -z 's/\n/\\n/g' <"$3")
 | 
			
		||||
  _cca=$(sed -z 's/\n/\\n/g' <"$4")
 | 
			
		||||
  _cfullchain=$(sed -z 's/\n/\\n/g' <"$5")
 | 
			
		||||
  _ckey=$(sed -e ':a' -e N -e '$ ! ba' -e 's/\n/\\n/g' <"$2")
 | 
			
		||||
  _ccert=$(sed -e ':a' -e N -e '$ ! ba' -e 's/\n/\\n/g' <"$3")
 | 
			
		||||
  _cca=$(sed -e ':a' -e N -e '$ ! ba' -e 's/\n/\\n/g' <"$4")
 | 
			
		||||
  _cfullchain=$(sed -e ':a' -e N -e '$ ! ba' -e 's/\n/\\n/g' <"$5")
 | 
			
		||||
 | 
			
		||||
  URL="$VAULT_ADDR/v1/$VAULT_PREFIX/$_cdomain"
 | 
			
		||||
  export _H1="X-Vault-Token: $VAULT_TOKEN"
 | 
			
		||||
 | 
			
		||||
  if [ -n "$FABIO" ]; then
 | 
			
		||||
  if [ -n "$VAULT_RENEW_TOKEN" ]; then
 | 
			
		||||
    URL="$VAULT_ADDR/v1/auth/token/renew-self"
 | 
			
		||||
    _info "Renew the Vault token to default TTL"
 | 
			
		||||
    if ! _post "" "$URL" >/dev/null; then
 | 
			
		||||
      _err "Failed to renew the Vault token"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  URL="$VAULT_ADDR/v1/$VAULT_PREFIX/$_cdomain"
 | 
			
		||||
 | 
			
		||||
  if [ -n "$VAULT_FABIO_MODE" ]; then
 | 
			
		||||
    _info "Writing certificate and key to $URL in Fabio mode"
 | 
			
		||||
    if [ -n "$VAULT_KV_V2" ]; then
 | 
			
		||||
      _post "{ \"data\": {\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"} }" "$URL"
 | 
			
		||||
      _post "{ \"data\": {\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"} }" "$URL" >/dev/null || return 1
 | 
			
		||||
    else
 | 
			
		||||
      _post "{\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"}" "$URL"
 | 
			
		||||
      _post "{\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"}" "$URL" >/dev/null || return 1
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    if [ -n "$VAULT_KV_V2" ]; then
 | 
			
		||||
      _post "{\"data\": {\"value\": \"$_ccert\"}}" "$URL/cert.pem"
 | 
			
		||||
      _post "{\"data\": {\"value\": \"$_ckey\"}}" "$URL/cert.key"
 | 
			
		||||
      _post "{\"data\": {\"value\": \"$_cca\"}}" "$URL/chain.pem"
 | 
			
		||||
      _post "{\"data\": {\"value\": \"$_cfullchain\"}}" "$URL/fullchain.pem"
 | 
			
		||||
      _info "Writing certificate to $URL/cert.pem"
 | 
			
		||||
      _post "{\"data\": {\"value\": \"$_ccert\"}}" "$URL/cert.pem" >/dev/null || return 1
 | 
			
		||||
      _info "Writing key to $URL/cert.key"
 | 
			
		||||
      _post "{\"data\": {\"value\": \"$_ckey\"}}" "$URL/cert.key" >/dev/null || return 1
 | 
			
		||||
      _info "Writing CA certificate to $URL/ca.pem"
 | 
			
		||||
      _post "{\"data\": {\"value\": \"$_cca\"}}" "$URL/ca.pem" >/dev/null || return 1
 | 
			
		||||
      _info "Writing full-chain certificate to $URL/fullchain.pem"
 | 
			
		||||
      _post "{\"data\": {\"value\": \"$_cfullchain\"}}" "$URL/fullchain.pem" >/dev/null || return 1
 | 
			
		||||
    else
 | 
			
		||||
      _post "{\"value\": \"$_ccert\"}" "$URL/cert.pem"
 | 
			
		||||
      _post "{\"value\": \"$_ckey\"}" "$URL/cert.key"
 | 
			
		||||
      _post "{\"value\": \"$_cca\"}" "$URL/chain.pem"
 | 
			
		||||
      _post "{\"value\": \"$_cfullchain\"}" "$URL/fullchain.pem"
 | 
			
		||||
      _info "Writing certificate to $URL/cert.pem"
 | 
			
		||||
      _post "{\"value\": \"$_ccert\"}" "$URL/cert.pem" >/dev/null || return 1
 | 
			
		||||
      _info "Writing key to $URL/cert.key"
 | 
			
		||||
      _post "{\"value\": \"$_ckey\"}" "$URL/cert.key" >/dev/null || return 1
 | 
			
		||||
      _info "Writing CA certificate to $URL/ca.pem"
 | 
			
		||||
      _post "{\"value\": \"$_cca\"}" "$URL/ca.pem" >/dev/null || return 1
 | 
			
		||||
      _info "Writing full-chain certificate to $URL/fullchain.pem"
 | 
			
		||||
      _post "{\"value\": \"$_cfullchain\"}" "$URL/fullchain.pem" >/dev/null || return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # To make it compatible with the wrong ca path `chain.pem` which was used in former versions
 | 
			
		||||
    if _contains "$(_get "$URL/chain.pem")" "-----BEGIN CERTIFICATE-----"; then
 | 
			
		||||
      _err "The CA certificate has moved from chain.pem to ca.pem, if you don't depend on chain.pem anymore, you can delete it to avoid this warning"
 | 
			
		||||
      _info "Updating CA certificate to $URL/chain.pem for backward compatibility"
 | 
			
		||||
      if [ -n "$VAULT_KV_V2" ]; then
 | 
			
		||||
        _post "{\"data\": {\"value\": \"$_cca\"}}" "$URL/chain.pem" >/dev/null || return 1
 | 
			
		||||
      else
 | 
			
		||||
        _post "{\"value\": \"$_cca\"}" "$URL/chain.pem" >/dev/null || return 1
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,8 @@
 | 
			
		||||
#
 | 
			
		||||
# VAULT_PREFIX - this contains the prefix path in vault
 | 
			
		||||
# VAULT_ADDR - vault requires this to find your vault server
 | 
			
		||||
# VAULT_SAVE_TOKEN - set to anything if you want to save the token
 | 
			
		||||
# VAULT_RENEW_TOKEN - set to anything if you want to renew the token to default TTL before deploying
 | 
			
		||||
#
 | 
			
		||||
# additionally, you need to ensure that VAULT_TOKEN is avialable or
 | 
			
		||||
# `vault auth` has applied the appropriate authorization for the vault binary
 | 
			
		||||
@@ -33,15 +35,36 @@ vault_cli_deploy() {
 | 
			
		||||
  _debug _cfullchain "$_cfullchain"
 | 
			
		||||
 | 
			
		||||
  # validate required env vars
 | 
			
		||||
  _getdeployconf VAULT_PREFIX
 | 
			
		||||
  if [ -z "$VAULT_PREFIX" ]; then
 | 
			
		||||
    _err "VAULT_PREFIX needs to be defined (contains prefix path in vault)"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _savedeployconf VAULT_PREFIX "$VAULT_PREFIX"
 | 
			
		||||
 | 
			
		||||
  _getdeployconf VAULT_ADDR
 | 
			
		||||
  if [ -z "$VAULT_ADDR" ]; then
 | 
			
		||||
    _err "VAULT_ADDR needs to be defined (contains vault connection address)"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _savedeployconf VAULT_ADDR "$VAULT_ADDR"
 | 
			
		||||
 | 
			
		||||
  _getdeployconf VAULT_SAVE_TOKEN
 | 
			
		||||
  _savedeployconf VAULT_SAVE_TOKEN "$VAULT_SAVE_TOKEN"
 | 
			
		||||
 | 
			
		||||
  _getdeployconf VAULT_RENEW_TOKEN
 | 
			
		||||
  _savedeployconf VAULT_RENEW_TOKEN "$VAULT_RENEW_TOKEN"
 | 
			
		||||
 | 
			
		||||
  _getdeployconf VAULT_TOKEN
 | 
			
		||||
  if [ -z "$VAULT_TOKEN" ]; then
 | 
			
		||||
    _err "VAULT_TOKEN needs to be defined"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  if [ -n "$VAULT_SAVE_TOKEN" ]; then
 | 
			
		||||
    _savedeployconf VAULT_TOKEN "$VAULT_TOKEN"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _migratedeployconf FABIO VAULT_FABIO_MODE
 | 
			
		||||
 | 
			
		||||
  VAULT_CMD=$(command -v vault)
 | 
			
		||||
  if [ ! $? ]; then
 | 
			
		||||
@@ -49,13 +72,33 @@ vault_cli_deploy() {
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -n "$FABIO" ]; then
 | 
			
		||||
  if [ -n "$VAULT_RENEW_TOKEN" ]; then
 | 
			
		||||
    _info "Renew the Vault token to default TTL"
 | 
			
		||||
    if ! $VAULT_CMD token renew; then
 | 
			
		||||
      _err "Failed to renew the Vault token"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -n "$VAULT_FABIO_MODE" ]; then
 | 
			
		||||
    _info "Writing certificate and key to ${VAULT_PREFIX}/${_cdomain} in Fabio mode"
 | 
			
		||||
    $VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}" cert=@"$_cfullchain" key=@"$_ckey" || return 1
 | 
			
		||||
  else
 | 
			
		||||
    _info "Writing certificate to ${VAULT_PREFIX}/${_cdomain}/cert.pem"
 | 
			
		||||
    $VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/cert.pem" value=@"$_ccert" || return 1
 | 
			
		||||
    _info "Writing key to ${VAULT_PREFIX}/${_cdomain}/cert.key"
 | 
			
		||||
    $VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/cert.key" value=@"$_ckey" || return 1
 | 
			
		||||
    $VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/chain.pem" value=@"$_cca" || return 1
 | 
			
		||||
    _info "Writing CA certificate to ${VAULT_PREFIX}/${_cdomain}/ca.pem"
 | 
			
		||||
    $VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/ca.pem" value=@"$_cca" || return 1
 | 
			
		||||
    _info "Writing full-chain certificate to ${VAULT_PREFIX}/${_cdomain}/fullchain.pem"
 | 
			
		||||
    $VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/fullchain.pem" value=@"$_cfullchain" || return 1
 | 
			
		||||
 | 
			
		||||
    # To make it compatible with the wrong ca path `chain.pem` which was used in former versions
 | 
			
		||||
    if $VAULT_CMD kv get "${VAULT_PREFIX}/${_cdomain}/chain.pem" >/dev/null; then
 | 
			
		||||
      _err "The CA certificate has moved from chain.pem to ca.pem, if you don't depend on chain.pem anymore, you can delete it to avoid this warning"
 | 
			
		||||
      _info "Updating CA certificate to ${VAULT_PREFIX}/${_cdomain}/chain.pem for backward compatibility"
 | 
			
		||||
      $VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/chain.pem" value=@"$_cca" || return 1
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,46 +1,42 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
#This file name is "dns_1984hosting.sh"
 | 
			
		||||
#So, here must be a method dns_1984hosting_add()
 | 
			
		||||
#Which will be called by acme.sh to add the txt record to your api system.
 | 
			
		||||
#returns 0 means success, otherwise error.
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_1984hosting_info='1984.hosting
 | 
			
		||||
Domains: 1984.is
 | 
			
		||||
Site: 1984.hosting
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_1984hosting
 | 
			
		||||
Options:
 | 
			
		||||
 One984HOSTING_Username Username
 | 
			
		||||
 One984HOSTING_Password Password
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/2851
 | 
			
		||||
Author: Adrian Fedoreanu
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
#Author: Adrian Fedoreanu
 | 
			
		||||
#Report Bugs here: https://github.com/acmesh-official/acme.sh
 | 
			
		||||
# or here... https://github.com/acmesh-official/acme.sh/issues/2851
 | 
			
		||||
#
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
######## Public functions #####################
 | 
			
		||||
 | 
			
		||||
# Export 1984HOSTING username and password in following variables
 | 
			
		||||
#
 | 
			
		||||
#  One984HOSTING_Username=username
 | 
			
		||||
#  One984HOSTING_Password=password
 | 
			
		||||
#
 | 
			
		||||
# sessionid cookie is saved in ~/.acme.sh/account.conf
 | 
			
		||||
# username/password need to be set only when changed.
 | 
			
		||||
 | 
			
		||||
#Usage: dns_1984hosting_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
# Usage: dns_1984hosting_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
# Add a text record.
 | 
			
		||||
dns_1984hosting_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  _info "Add TXT record using 1984Hosting"
 | 
			
		||||
  _info "Add TXT record using 1984Hosting."
 | 
			
		||||
  _debug fulldomain "$fulldomain"
 | 
			
		||||
  _debug txtvalue "$txtvalue"
 | 
			
		||||
 | 
			
		||||
  if ! _1984hosting_login; then
 | 
			
		||||
    _err "1984Hosting login failed for user $One984HOSTING_Username. Check $HTTP_HEADER file"
 | 
			
		||||
    _err "1984Hosting login failed for user $One984HOSTING_Username. Check $HTTP_HEADER file."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  _debug "First detect the root zone."
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "invalid domain" "$fulldomain"
 | 
			
		||||
    _err "Invalid domain '$fulldomain'."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug _sub_domain "$_sub_domain"
 | 
			
		||||
  _debug _domain "$_domain"
 | 
			
		||||
 | 
			
		||||
  _debug "Add TXT record $fulldomain with value '$txtvalue'"
 | 
			
		||||
  _debug "Add TXT record $fulldomain with value '$txtvalue'."
 | 
			
		||||
  value="$(printf '%s' "$txtvalue" | _url_encode)"
 | 
			
		||||
  url="https://1984.hosting/domains/entry/"
 | 
			
		||||
 | 
			
		||||
@@ -53,92 +49,96 @@ dns_1984hosting_add() {
 | 
			
		||||
  _debug2 postdata "$postdata"
 | 
			
		||||
 | 
			
		||||
  _authpost "$postdata" "$url"
 | 
			
		||||
  response="$(echo "$_response" | _normalizeJson)"
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
 | 
			
		||||
  if _contains "$response" '"haserrors": true'; then
 | 
			
		||||
    _err "1984Hosting failed to add TXT record for $_sub_domain bad RC from _post"
 | 
			
		||||
  if _contains "$_response" '"haserrors": true'; then
 | 
			
		||||
    _err "1984Hosting failed to add TXT record for $_sub_domain bad RC from _post."
 | 
			
		||||
    return 1
 | 
			
		||||
  elif _contains "$response" "html>"; then
 | 
			
		||||
    _err "1984Hosting failed to add TXT record for $_sub_domain. Check $HTTP_HEADER file"
 | 
			
		||||
  elif _contains "$_response" "html>"; then
 | 
			
		||||
    _err "1984Hosting failed to add TXT record for $_sub_domain. Check $HTTP_HEADER file."
 | 
			
		||||
    return 1
 | 
			
		||||
  elif _contains "$response" '"auth": false'; then
 | 
			
		||||
    _err "1984Hosting failed to add TXT record for $_sub_domain. Invalid or expired cookie"
 | 
			
		||||
  elif _contains "$_response" '"auth": false'; then
 | 
			
		||||
    _err "1984Hosting failed to add TXT record for $_sub_domain. Invalid or expired cookie."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Added acme challenge TXT record for $fulldomain at 1984Hosting"
 | 
			
		||||
  _info "Added acme challenge TXT record for $fulldomain at 1984Hosting."
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#Usage: fulldomain txtvalue
 | 
			
		||||
#Remove the txt record after validation.
 | 
			
		||||
# Usage: fulldomain txtvalue
 | 
			
		||||
# Remove the txt record after validation.
 | 
			
		||||
dns_1984hosting_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  _info "Delete TXT record using 1984Hosting"
 | 
			
		||||
  _info "Delete TXT record using 1984Hosting."
 | 
			
		||||
  _debug fulldomain "$fulldomain"
 | 
			
		||||
  _debug txtvalue "$txtvalue"
 | 
			
		||||
 | 
			
		||||
  if ! _1984hosting_login; then
 | 
			
		||||
    _err "1984Hosting login failed for user $One984HOSTING_Username. Check $HTTP_HEADER file"
 | 
			
		||||
    _err "1984Hosting login failed for user $One984HOSTING_Username. Check $HTTP_HEADER file."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  _debug "First detect the root zone."
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "invalid domain" "$fulldomain"
 | 
			
		||||
    _err "Invalid domain '$fulldomain'."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug _sub_domain "$_sub_domain"
 | 
			
		||||
  _debug _domain "$_domain"
 | 
			
		||||
  _debug "Delete $fulldomain TXT record"
 | 
			
		||||
  _debug "Delete $fulldomain TXT record."
 | 
			
		||||
 | 
			
		||||
  url="https://1984.hosting/domains"
 | 
			
		||||
  if ! _get_zone_id "$url" "$_domain"; then
 | 
			
		||||
    _err "invalid zone" "$_domain"
 | 
			
		||||
    _err "Invalid zone '$_domain'."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _htmlget "$url/$_zone_id" "$txtvalue"
 | 
			
		||||
  _debug2 _response "$_response"
 | 
			
		||||
  entry_id="$(echo "$_response" | _egrep_o 'entry_[0-9]+' | sed 's/entry_//')"
 | 
			
		||||
  _debug2 entry_id "$entry_id"
 | 
			
		||||
  if [ -z "$entry_id" ]; then
 | 
			
		||||
    _err "Error getting TXT entry_id for $1"
 | 
			
		||||
    _err "Error getting TXT entry_id for $1."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _authpost "entry=$entry_id" "$url/delentry/"
 | 
			
		||||
  response="$(echo "$_response" | _normalizeJson)"
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
 | 
			
		||||
  if ! _contains "$response" '"ok": true'; then
 | 
			
		||||
    _err "1984Hosting failed to delete TXT record for $entry_id bad RC from _post"
 | 
			
		||||
  if ! _contains "$_response" '"ok": true'; then
 | 
			
		||||
    _err "1984Hosting failed to delete TXT record for $entry_id bad RC from _post."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Deleted acme challenge TXT record for $fulldomain at 1984Hosting"
 | 
			
		||||
  _info "Deleted acme challenge TXT record for $fulldomain at 1984Hosting."
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
 | 
			
		||||
# usage: _1984hosting_login username password
 | 
			
		||||
# returns 0 success
 | 
			
		||||
_1984hosting_login() {
 | 
			
		||||
  if ! _check_credentials; then return 1; fi
 | 
			
		||||
 | 
			
		||||
  if _check_cookies; then
 | 
			
		||||
    _debug "Already logged in"
 | 
			
		||||
    _debug "Already logged in."
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug "Login to 1984Hosting as user $One984HOSTING_Username"
 | 
			
		||||
  _debug "Login to 1984Hosting as user $One984HOSTING_Username."
 | 
			
		||||
  username=$(printf '%s' "$One984HOSTING_Username" | _url_encode)
 | 
			
		||||
  password=$(printf '%s' "$One984HOSTING_Password" | _url_encode)
 | 
			
		||||
  url="https://1984.hosting/accounts/checkuserauth/"
 | 
			
		||||
  url="https://1984.hosting/api/auth/"
 | 
			
		||||
 | 
			
		||||
  _get "https://1984.hosting/accounts/login/" | grep "csrfmiddlewaretoken"
 | 
			
		||||
  csrftoken="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _egrep_o 'csrftoken=[^;]*;' | tr -d ';')"
 | 
			
		||||
  sessionid="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _egrep_o 'sessionid=[^;]*;' | tr -d ';')"
 | 
			
		||||
 | 
			
		||||
  if [ -z "$csrftoken" ] || [ -z "$sessionid" ]; then
 | 
			
		||||
    _err "One or more cookies are empty: '$csrftoken', '$sessionid'."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  export _H1="Cookie: $csrftoken; $sessionid"
 | 
			
		||||
  export _H2="Referer: https://1984.hosting/accounts/login/"
 | 
			
		||||
  csrf_header=$(echo "$csrftoken" | sed 's/csrftoken=//' | _head_n 1)
 | 
			
		||||
  export _H3="X-CSRFToken: $csrf_header"
 | 
			
		||||
 | 
			
		||||
  response="$(_post "username=$username&password=$password&otpkey=" $url)"
 | 
			
		||||
  response="$(echo "$response" | _normalizeJson)"
 | 
			
		||||
@@ -149,6 +149,8 @@ _1984hosting_login() {
 | 
			
		||||
    One984HOSTING_CSRFTOKEN_COOKIE="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _egrep_o 'csrftoken=[^;]*;' | tr -d ';')"
 | 
			
		||||
    export One984HOSTING_SESSIONID_COOKIE
 | 
			
		||||
    export One984HOSTING_CSRFTOKEN_COOKIE
 | 
			
		||||
    _saveaccountconf_mutable One984HOSTING_Username "$One984HOSTING_Username"
 | 
			
		||||
    _saveaccountconf_mutable One984HOSTING_Password "$One984HOSTING_Password"
 | 
			
		||||
    _saveaccountconf_mutable One984HOSTING_SESSIONID_COOKIE "$One984HOSTING_SESSIONID_COOKIE"
 | 
			
		||||
    _saveaccountconf_mutable One984HOSTING_CSRFTOKEN_COOKIE "$One984HOSTING_CSRFTOKEN_COOKIE"
 | 
			
		||||
    return 0
 | 
			
		||||
@@ -157,9 +159,13 @@ _1984hosting_login() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_check_credentials() {
 | 
			
		||||
  One984HOSTING_Username="${One984HOSTING_Username:-$(_readaccountconf_mutable One984HOSTING_Username)}"
 | 
			
		||||
  One984HOSTING_Password="${One984HOSTING_Password:-$(_readaccountconf_mutable One984HOSTING_Password)}"
 | 
			
		||||
  if [ -z "$One984HOSTING_Username" ] || [ -z "$One984HOSTING_Password" ]; then
 | 
			
		||||
    One984HOSTING_Username=""
 | 
			
		||||
    One984HOSTING_Password=""
 | 
			
		||||
    _clearaccountconf_mutable One984HOSTING_Username
 | 
			
		||||
    _clearaccountconf_mutable One984HOSTING_Password
 | 
			
		||||
    _err "You haven't specified 1984Hosting username or password yet."
 | 
			
		||||
    _err "Please export as One984HOSTING_Username / One984HOSTING_Password and try again."
 | 
			
		||||
    return 1
 | 
			
		||||
@@ -171,42 +177,43 @@ _check_cookies() {
 | 
			
		||||
  One984HOSTING_SESSIONID_COOKIE="${One984HOSTING_SESSIONID_COOKIE:-$(_readaccountconf_mutable One984HOSTING_SESSIONID_COOKIE)}"
 | 
			
		||||
  One984HOSTING_CSRFTOKEN_COOKIE="${One984HOSTING_CSRFTOKEN_COOKIE:-$(_readaccountconf_mutable One984HOSTING_CSRFTOKEN_COOKIE)}"
 | 
			
		||||
  if [ -z "$One984HOSTING_SESSIONID_COOKIE" ] || [ -z "$One984HOSTING_CSRFTOKEN_COOKIE" ]; then
 | 
			
		||||
    _debug "No cached cookie(s) found"
 | 
			
		||||
    _debug "No cached cookie(s) found."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _authget "https://1984.hosting/accounts/loginstatus/"
 | 
			
		||||
  if _contains "$response" '"ok": true'; then
 | 
			
		||||
    _debug "Cached cookies still valid"
 | 
			
		||||
  _authget "https://1984.hosting/api/auth/"
 | 
			
		||||
  if _contains "$_response" '"ok": true'; then
 | 
			
		||||
    _debug "Cached cookies still valid."
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
  _debug "Cached cookies no longer valid"
 | 
			
		||||
 | 
			
		||||
  _debug "Cached cookies no longer valid. Clearing cookies."
 | 
			
		||||
  One984HOSTING_SESSIONID_COOKIE=""
 | 
			
		||||
  One984HOSTING_CSRFTOKEN_COOKIE=""
 | 
			
		||||
  _saveaccountconf_mutable One984HOSTING_SESSIONID_COOKIE "$One984HOSTING_SESSIONID_COOKIE"
 | 
			
		||||
  _saveaccountconf_mutable One984HOSTING_CSRFTOKEN_COOKIE "$One984HOSTING_CSRFTOKEN_COOKIE"
 | 
			
		||||
  _clearaccountconf_mutable One984HOSTING_SESSIONID_COOKIE
 | 
			
		||||
  _clearaccountconf_mutable One984HOSTING_CSRFTOKEN_COOKIE
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#_acme-challenge.www.domain.com
 | 
			
		||||
#returns
 | 
			
		||||
# _sub_domain=_acme-challenge.www
 | 
			
		||||
# _domain=domain.com
 | 
			
		||||
# _acme-challenge.www.domain.com
 | 
			
		||||
# Returns
 | 
			
		||||
#  _sub_domain=_acme-challenge.www
 | 
			
		||||
#  _domain=domain.com
 | 
			
		||||
_get_root() {
 | 
			
		||||
  domain="$1"
 | 
			
		||||
  i=1
 | 
			
		||||
  p=1
 | 
			
		||||
  while true; do
 | 
			
		||||
    h=$(printf "%s" "$domain" | cut -d . -f $i-100)
 | 
			
		||||
    h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
 | 
			
		||||
 | 
			
		||||
    # not valid
 | 
			
		||||
    if [ -z "$h" ]; then
 | 
			
		||||
      #not valid
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    _authget "https://1984.hosting/domains/soacheck/?zone=$h&nameserver=ns0.1984.is."
 | 
			
		||||
    if _contains "$_response" "serial" && ! _contains "$_response" "null"; then
 | 
			
		||||
      _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
 | 
			
		||||
    _authget "https://1984.hosting/domains/zonestatus/$h/?cached=no"
 | 
			
		||||
    if _contains "$_response" '"ok": true'; then
 | 
			
		||||
      _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
 | 
			
		||||
      _domain="$h"
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
@@ -216,46 +223,46 @@ _get_root() {
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#usage: _get_zone_id url domain.com
 | 
			
		||||
#returns zone id for domain.com
 | 
			
		||||
# Usage: _get_zone_id url domain.com
 | 
			
		||||
# Returns zone id for domain.com
 | 
			
		||||
_get_zone_id() {
 | 
			
		||||
  url=$1
 | 
			
		||||
  domain=$2
 | 
			
		||||
  _htmlget "$url" "$domain"
 | 
			
		||||
  _debug2 _response "$_response"
 | 
			
		||||
  _zone_id="$(echo "$_response" | _egrep_o 'zone\/[0-9]+' | _head_n 1)"
 | 
			
		||||
  _debug2 _zone_id "$_zone_id"
 | 
			
		||||
  if [ -z "$_zone_id" ]; then
 | 
			
		||||
    _err "Error getting _zone_id for $2"
 | 
			
		||||
    _err "Error getting _zone_id for $2."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# add extra headers to request
 | 
			
		||||
# Add extra headers to request
 | 
			
		||||
_authget() {
 | 
			
		||||
  export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE;$One984HOSTING_SESSIONID_COOKIE"
 | 
			
		||||
  export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE; $One984HOSTING_SESSIONID_COOKIE"
 | 
			
		||||
  _response=$(_get "$1" | _normalizeJson)
 | 
			
		||||
  _debug2 _response "$_response"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# truncate huge HTML response
 | 
			
		||||
# echo: Argument list too long
 | 
			
		||||
# Truncate huge HTML response
 | 
			
		||||
_htmlget() {
 | 
			
		||||
  export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE;$One984HOSTING_SESSIONID_COOKIE"
 | 
			
		||||
  export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE; $One984HOSTING_SESSIONID_COOKIE"
 | 
			
		||||
  _response=$(_get "$1" | grep "$2")
 | 
			
		||||
  if _contains "$_response" "@$2"; then
 | 
			
		||||
    _response=$(echo "$_response" | grep -v "[@]" | _head_n 1)
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 _response "$_response"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# add extra headers to request
 | 
			
		||||
# Add extra headers to request
 | 
			
		||||
_authpost() {
 | 
			
		||||
  url="https://1984.hosting/domains"
 | 
			
		||||
  _get_zone_id "$url" "$_domain"
 | 
			
		||||
  csrf_header="$(echo "$One984HOSTING_CSRFTOKEN_COOKIE" | _egrep_o "=[^=][0-9a-zA-Z]*" | tr -d "=")"
 | 
			
		||||
  export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE;$One984HOSTING_SESSIONID_COOKIE"
 | 
			
		||||
  export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE; $One984HOSTING_SESSIONID_COOKIE"
 | 
			
		||||
  export _H2="Referer: https://1984.hosting/domains/$_zone_id"
 | 
			
		||||
  export _H3="X-CSRFToken: $csrf_header"
 | 
			
		||||
  _response=$(_post "$1" "$2")
 | 
			
		||||
  _response="$(_post "$1" "$2" | _normalizeJson)"
 | 
			
		||||
  _debug2 _response "$_response"
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,18 +1,18 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
#
 | 
			
		||||
#Author: Wolfgang Ebner
 | 
			
		||||
#Author: Sven Neubuaer
 | 
			
		||||
#Report Bugs here: https://github.com/dampfklon/acme.sh
 | 
			
		||||
#
 | 
			
		||||
# Usage:
 | 
			
		||||
# export ACMEDNS_BASE_URL="https://auth.acme-dns.io"
 | 
			
		||||
#
 | 
			
		||||
# You can optionally define an already existing account:
 | 
			
		||||
#
 | 
			
		||||
# export ACMEDNS_USERNAME="<username>"
 | 
			
		||||
# export ACMEDNS_PASSWORD="<password>"
 | 
			
		||||
# export ACMEDNS_SUBDOMAIN="<subdomain>"
 | 
			
		||||
#
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_acmedns_info='acme-dns Server API
 | 
			
		||||
 The acme-dns is a limited DNS server with RESTful API to handle ACME DNS challenges.
 | 
			
		||||
Site: github.com/joohoi/acme-dns
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_acmedns
 | 
			
		||||
Options:
 | 
			
		||||
 ACMEDNS_USERNAME Username. Optional.
 | 
			
		||||
 ACMEDNS_PASSWORD Password. Optional.
 | 
			
		||||
 ACMEDNS_SUBDOMAIN Subdomain. Optional.
 | 
			
		||||
 ACMEDNS_BASE_URL API endpoint. Default: "https://auth.acme-dns.io".
 | 
			
		||||
Issues: github.com/dampfklon/acme.sh
 | 
			
		||||
Author: Wolfgang Ebner, Sven Neubuaer
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: dns_acmedns_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								dnsapi/dns_acmeproxy.sh
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										18
									
								
								dnsapi/dns_acmeproxy.sh
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							@@ -1,9 +1,17 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
## Acmeproxy DNS provider to be used with acmeproxy (http://github.com/mdbraber/acmeproxy)
 | 
			
		||||
## API integration by Maarten den Braber
 | 
			
		||||
##
 | 
			
		||||
## Report any bugs via https://github.com/mdbraber/acme.sh
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_acmeproxy_info='AcmeProxy Server API
 | 
			
		||||
 AcmeProxy can be used to as a single host in your network to request certificates through a DNS API.
 | 
			
		||||
 Clients can connect with the one AcmeProxy host so you do not need to store DNS API credentials on every single host.
 | 
			
		||||
Site: github.com/mdbraber/acmeproxy
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_acmeproxy
 | 
			
		||||
Options:
 | 
			
		||||
 ACMEPROXY_ENDPOINT API Endpoint
 | 
			
		||||
 ACMEPROXY_USERNAME Username
 | 
			
		||||
 ACMEPROXY_PASSWORD Password
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/2251
 | 
			
		||||
Author: Maarten den Braber
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
dns_acmeproxy_add() {
 | 
			
		||||
  fulldomain="${1}"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,13 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#ACTIVE24_Token="sdfsdfsdfljlbjkljlkjsdfoiwje"
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_active24_info='Active24.com
 | 
			
		||||
Site: Active24.com
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_active24
 | 
			
		||||
Options:
 | 
			
		||||
 ACTIVE24_Token API Token
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/2059
 | 
			
		||||
Author: Milan Pála
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
ACTIVE24_Api="https://api.active24.com"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,13 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
#AD_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje"
 | 
			
		||||
 | 
			
		||||
#This is the Alwaysdata api wrapper for acme.sh
 | 
			
		||||
#
 | 
			
		||||
#Author: Paul Koppen
 | 
			
		||||
#Report Bugs here: https://github.com/wpk-/acme.sh
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_ad_info='AlwaysData.com
 | 
			
		||||
Site: AlwaysData.com
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_ad
 | 
			
		||||
Options:
 | 
			
		||||
 AD_API_KEY API Key
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/pull/503
 | 
			
		||||
Author: Paul Koppen
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
AD_API_URL="https://$AD_API_KEY:@api.alwaysdata.com/v1"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,16 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_ali_info='AlibabaCloud.com
 | 
			
		||||
Domains: Aliyun.com
 | 
			
		||||
Site: AlibabaCloud.com
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_ali
 | 
			
		||||
Options:
 | 
			
		||||
 Ali_Key API Key
 | 
			
		||||
 Ali_Secret API Secret
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
Ali_API="https://alidns.aliyuncs.com/"
 | 
			
		||||
 | 
			
		||||
#Ali_Key="LTqIA87hOKdjevsf5"
 | 
			
		||||
#Ali_Secret="0p5EYueFNq501xnCPzKNbx6K51qPH2"
 | 
			
		||||
 | 
			
		||||
#Usage: dns_ali_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_ali_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
@@ -117,7 +123,7 @@ _ali_urlencode() {
 | 
			
		||||
_ali_nonce() {
 | 
			
		||||
  #_head_n 1 </dev/urandom | _digest "sha256" hex | cut -c 1-31
 | 
			
		||||
  #Not so good...
 | 
			
		||||
  date +"%s%N"
 | 
			
		||||
  date +"%s%N" | sed 's/%N//g'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_check_exist_query() {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										184
									
								
								dnsapi/dns_alviy.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								dnsapi/dns_alviy.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,184 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# Alviy domain api
 | 
			
		||||
#
 | 
			
		||||
# Get API key and secret from https://cloud.alviy.com/token
 | 
			
		||||
#
 | 
			
		||||
# Alviy_token="some-secret-key"
 | 
			
		||||
#
 | 
			
		||||
# Ex.: acme.sh --issue --staging --dns dns_alviy -d "*.s.example.com" -d "s.example.com"
 | 
			
		||||
 | 
			
		||||
Alviy_Api="https://cloud.alviy.com/api/v1"
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: dns_alviy_add  _acme-challenge.www.domain.com   "content"
 | 
			
		||||
dns_alviy_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  Alviy_token="${Alviy_token:-$(_readaccountconf_mutable Alviy_token)}"
 | 
			
		||||
  if [ -z "$Alviy_token" ]; then
 | 
			
		||||
    Alviy_token=""
 | 
			
		||||
    _err "Please specify Alviy token."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  #save the api key and email to the account conf file.
 | 
			
		||||
  _saveaccountconf_mutable Alviy_token "$Alviy_token"
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "invalid domain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug _sub_domain "$_sub_domain"
 | 
			
		||||
  _debug _domain "$_domain"
 | 
			
		||||
 | 
			
		||||
  _debug "Getting existing records"
 | 
			
		||||
  if _alviy_txt_exists "$_domain" "$fulldomain" "$txtvalue"; then
 | 
			
		||||
    _info "This record already exists, skipping"
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _add_data="{\"content\":\"$txtvalue\",\"type\":\"TXT\"}"
 | 
			
		||||
  _debug2 _add_data "$_add_data"
 | 
			
		||||
  _info "Adding record"
 | 
			
		||||
  if _alviy_rest POST "zone/$_domain/domain/$fulldomain/" "$_add_data"; then
 | 
			
		||||
    _debug "Checking updated records of '${fulldomain}'"
 | 
			
		||||
 | 
			
		||||
    if ! _alviy_txt_exists "$_domain" "$fulldomain" "$txtvalue"; then
 | 
			
		||||
      _err "TXT record '${txtvalue}' for '${fulldomain}', value wasn't set!"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
  else
 | 
			
		||||
    _err "Add txt record error, value '${txtvalue}' for '${fulldomain}' was not set."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _sleep 10
 | 
			
		||||
  _info "Added TXT record '${txtvalue}' for '${fulldomain}'."
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#fulldomain
 | 
			
		||||
dns_alviy_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  Alviy_token="${Alviy_token:-$(_readaccountconf_mutable Alviy_token)}"
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "invalid domain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug _sub_domain "$_sub_domain"
 | 
			
		||||
  _debug _domain "$_domain"
 | 
			
		||||
 | 
			
		||||
  if ! _alviy_txt_exists "$_domain" "$fulldomain" "$txtvalue"; then
 | 
			
		||||
    _info "The record does not exist, skip"
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _add_data=""
 | 
			
		||||
  uuid=$(echo "$response" | tr "{" "\n" | grep "$txtvalue" | tr "," "\n" | grep uuid | cut -d \" -f4)
 | 
			
		||||
  # delete record
 | 
			
		||||
  _debug "Delete TXT record for '${fulldomain}'"
 | 
			
		||||
  if ! _alviy_rest DELETE "zone/$_domain/record/$uuid" "{\"confirm\":1}"; then
 | 
			
		||||
    _err "Cannot delete empty TXT record for '$fulldomain'"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _info "The record '$fulldomain'='$txtvalue' deleted"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
#_acme-challenge.www.domain.com
 | 
			
		||||
#returns
 | 
			
		||||
# _sub_domain=_acme-challenge.www
 | 
			
		||||
# _domain=domain.com
 | 
			
		||||
_get_root() {
 | 
			
		||||
  domain=$1
 | 
			
		||||
  i=3
 | 
			
		||||
  a="init"
 | 
			
		||||
  while [ -n "$a" ]; do
 | 
			
		||||
    a=$(printf "%s" "$domain" | cut -d . -f $i-)
 | 
			
		||||
    i=$((i + 1))
 | 
			
		||||
  done
 | 
			
		||||
  n=$((i - 3))
 | 
			
		||||
  h=$(printf "%s" "$domain" | cut -d . -f $n-)
 | 
			
		||||
  if [ -z "$h" ]; then
 | 
			
		||||
    #not valid
 | 
			
		||||
    _alviy_rest GET "zone/$domain/"
 | 
			
		||||
    _debug "can't get host from $domain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! _alviy_rest GET "zone/$h/"; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if _contains "$response" '"code":"NOT_FOUND"'; then
 | 
			
		||||
    _debug "$h not found"
 | 
			
		||||
  else
 | 
			
		||||
    s=$((n - 1))
 | 
			
		||||
    _sub_domain=$(printf "%s" "$domain" | cut -d . -f -$s)
 | 
			
		||||
    _domain="$h"
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_alviy_txt_exists() {
 | 
			
		||||
  zone=$1
 | 
			
		||||
  domain=$2
 | 
			
		||||
  content_data=$3
 | 
			
		||||
  _debug "Getting existing records"
 | 
			
		||||
 | 
			
		||||
  if ! _alviy_rest GET "zone/$zone/domain/$domain/TXT/"; then
 | 
			
		||||
    _info "The record does not exist"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! _contains "$response" "$3"; then
 | 
			
		||||
    _info "The record has other value"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  # GOOD code return - TRUE function
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_alviy_rest() {
 | 
			
		||||
  method=$1
 | 
			
		||||
  path="$2"
 | 
			
		||||
  content_data="$3"
 | 
			
		||||
  _debug "$path"
 | 
			
		||||
 | 
			
		||||
  export _H1="Authorization: Bearer $Alviy_token"
 | 
			
		||||
  export _H2="Content-Type: application/json"
 | 
			
		||||
 | 
			
		||||
  if [ "$content_data" ] || [ "$method" = "DELETE" ]; then
 | 
			
		||||
    _debug "data ($method): " "$content_data"
 | 
			
		||||
    response="$(_post "$content_data" "$Alviy_Api/$path" "" "$method")"
 | 
			
		||||
  else
 | 
			
		||||
    response="$(_get "$Alviy_Api/$path")"
 | 
			
		||||
  fi
 | 
			
		||||
  _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")"
 | 
			
		||||
  if [ "$_code" = "401" ]; then
 | 
			
		||||
    _err "It seems that your api key or secret is not correct."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ "$_code" != "200" ]; then
 | 
			
		||||
    _err "API call error ($method): $path Response code $_code"
 | 
			
		||||
  fi
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "error on rest call ($method): $path. Response:"
 | 
			
		||||
    _err "$response"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
@@ -1,9 +1,12 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
# Anexia CloudDNS acme.sh hook
 | 
			
		||||
# Author: MA
 | 
			
		||||
 | 
			
		||||
#ANX_Token="xxxx"
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_anx_info='Anexia.com CloudDNS
 | 
			
		||||
Site: Anexia.com
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_anx
 | 
			
		||||
Options:
 | 
			
		||||
 ANX_Token API Token
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/3238
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
ANX_API='https://engine.anexia-it.com/api/clouddns/v1'
 | 
			
		||||
 | 
			
		||||
@@ -127,8 +130,6 @@ _get_root() {
 | 
			
		||||
  i=1
 | 
			
		||||
  p=1
 | 
			
		||||
 | 
			
		||||
  _anx_rest GET "zone.json"
 | 
			
		||||
 | 
			
		||||
  while true; do
 | 
			
		||||
    h=$(printf "%s" "$domain" | cut -d . -f $i-100)
 | 
			
		||||
    _debug h "$h"
 | 
			
		||||
@@ -137,6 +138,7 @@ _get_root() {
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    _anx_rest GET "zone.json/${h}"
 | 
			
		||||
    if _contains "$response" "\"name\":\"$h\""; then
 | 
			
		||||
      _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
 | 
			
		||||
      _domain=$h
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										177
									
								
								dnsapi/dns_artfiles.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								dnsapi/dns_artfiles.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,177 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_artfiles_info='ArtFiles.de
 | 
			
		||||
Site: ArtFiles.de
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_artfiles
 | 
			
		||||
Options:
 | 
			
		||||
 AF_API_USERNAME API Username
 | 
			
		||||
 AF_API_PASSWORD API Password
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/4718
 | 
			
		||||
Author: Martin Arndt <https://troublezone.net/>
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
########## API configuration ###################################################
 | 
			
		||||
 | 
			
		||||
AF_API_SUCCESS='status":"OK'
 | 
			
		||||
AF_URL_DCP='https://dcp.c.artfiles.de/api/'
 | 
			
		||||
AF_URL_DNS=${AF_URL_DCP}'dns/{*}_dns.html?domain='
 | 
			
		||||
AF_URL_DOMAINS=${AF_URL_DCP}'domain/get_domains.html'
 | 
			
		||||
 | 
			
		||||
########## Public functions ####################################################
 | 
			
		||||
 | 
			
		||||
# Adds a new TXT record for given ACME challenge value & domain.
 | 
			
		||||
# Usage: dns_artfiles_add _acme-challenge.www.example.com "ACME challenge value"
 | 
			
		||||
dns_artfiles_add() {
 | 
			
		||||
  domain="$1"
 | 
			
		||||
  txtValue="$2"
 | 
			
		||||
  _info 'Using ArtFiles.de DNS addition API…'
 | 
			
		||||
  _debug 'Domain' "$domain"
 | 
			
		||||
  _debug 'txtValue' "$txtValue"
 | 
			
		||||
 | 
			
		||||
  _set_credentials
 | 
			
		||||
  _saveaccountconf_mutable 'AF_API_USERNAME' "$AF_API_USERNAME"
 | 
			
		||||
  _saveaccountconf_mutable 'AF_API_PASSWORD' "$AF_API_PASSWORD"
 | 
			
		||||
 | 
			
		||||
  _set_headers
 | 
			
		||||
  _get_zone "$domain"
 | 
			
		||||
  _dns 'GET'
 | 
			
		||||
  if ! _contains "$response" 'TXT'; then
 | 
			
		||||
    _err 'Retrieving TXT records failed.'
 | 
			
		||||
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _clean_records
 | 
			
		||||
  _dns 'SET' "$(printf -- '%s\n_acme-challenge "%s"' "$response" "$txtValue")"
 | 
			
		||||
  if ! _contains "$response" "$AF_API_SUCCESS"; then
 | 
			
		||||
    _err 'Adding ACME challenge value failed.'
 | 
			
		||||
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Removes the existing TXT record for given ACME challenge value & domain.
 | 
			
		||||
# Usage: dns_artfiles_rm _acme-challenge.www.example.com "ACME challenge value"
 | 
			
		||||
dns_artfiles_rm() {
 | 
			
		||||
  domain="$1"
 | 
			
		||||
  txtValue="$2"
 | 
			
		||||
  _info 'Using ArtFiles.de DNS removal API…'
 | 
			
		||||
  _debug 'Domain' "$domain"
 | 
			
		||||
  _debug 'txtValue' "$txtValue"
 | 
			
		||||
 | 
			
		||||
  _set_credentials
 | 
			
		||||
  _set_headers
 | 
			
		||||
  _get_zone "$domain"
 | 
			
		||||
  if ! _dns 'GET'; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! _contains "$response" "$txtValue"; then
 | 
			
		||||
    _err 'Retrieved TXT records are missing given ACME challenge value.'
 | 
			
		||||
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _clean_records
 | 
			
		||||
  response="$(printf -- '%s' "$response" | sed '/_acme-challenge "'"$txtValue"'"/d')"
 | 
			
		||||
  _dns 'SET' "$response"
 | 
			
		||||
  if ! _contains "$response" "$AF_API_SUCCESS"; then
 | 
			
		||||
    _err 'Removing ACME challenge value failed.'
 | 
			
		||||
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
########## Private functions ###################################################
 | 
			
		||||
 | 
			
		||||
# Cleans awful TXT records response of ArtFiles's API & pretty prints it.
 | 
			
		||||
# Usage: _clean_records
 | 
			
		||||
_clean_records() {
 | 
			
		||||
  _info 'Cleaning TXT records…'
 | 
			
		||||
  # Extract TXT part, strip trailing quote sign (ACME.sh API guidelines forbid
 | 
			
		||||
  # usage of SED's GNU extensions, hence couldn't omit it via regex), strip '\'
 | 
			
		||||
  # from '\"' & turn '\n' into real LF characters.
 | 
			
		||||
  # Yup, awful API to use - but that's all we got to get this working, so… ;)
 | 
			
		||||
  _debug2 'Raw  ' "$response"
 | 
			
		||||
  response="$(printf -- '%s' "$response" | sed 's/^.*TXT":"\([^}]*\).*$/\1/;s/,".*$//;s/.$//;s/\\"/"/g;s/\\n/\n/g')"
 | 
			
		||||
  _debug2 'Clean' "$response"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Executes an HTTP GET or POST request for getting or setting DNS records,
 | 
			
		||||
# containing given payload upon POST.
 | 
			
		||||
# Usage: _dns [GET | SET] [payload]
 | 
			
		||||
_dns() {
 | 
			
		||||
  _info 'Executing HTTP request…'
 | 
			
		||||
  action="$1"
 | 
			
		||||
  payload="$(printf -- '%s' "$2" | _url_encode)"
 | 
			
		||||
  url="$(printf -- '%s%s' "$AF_URL_DNS" "$domain" | sed 's/{\*}/'"$(printf -- '%s' "$action" | _lower_case)"'/')"
 | 
			
		||||
 | 
			
		||||
  if [ "$action" = 'SET' ]; then
 | 
			
		||||
    _debug2 'Payload' "$payload"
 | 
			
		||||
    response="$(_post '' "$url&TXT=$payload" '' 'POST' 'application/x-www-form-urlencoded')"
 | 
			
		||||
  else
 | 
			
		||||
    response="$(_get "$url" '' 10)"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! _contains "$response" "$AF_API_SUCCESS"; then
 | 
			
		||||
    _err "DNS API error: $response"
 | 
			
		||||
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug 'Response' "$response"
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Gets the root domain zone for given domain.
 | 
			
		||||
# Usage: _get_zone _acme-challenge.www.example.com
 | 
			
		||||
_get_zone() {
 | 
			
		||||
  fqdn="$1"
 | 
			
		||||
  domains="$(_get "$AF_URL_DOMAINS" '' 10)"
 | 
			
		||||
  _info 'Getting domain zone…'
 | 
			
		||||
  _debug2 'FQDN' "$fqdn"
 | 
			
		||||
  _debug2 'Domains' "$domains"
 | 
			
		||||
 | 
			
		||||
  while _contains "$fqdn" "."; do
 | 
			
		||||
    if _contains "$domains" "$fqdn"; then
 | 
			
		||||
      domain="$fqdn"
 | 
			
		||||
      _info "Found root domain zone: $domain"
 | 
			
		||||
      break
 | 
			
		||||
    else
 | 
			
		||||
      fqdn="${fqdn#*.}"
 | 
			
		||||
      _debug2 'FQDN' "$fqdn"
 | 
			
		||||
    fi
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  if [ "$domain" = "$fqdn" ]; then
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _err 'Couldn'\''t find root domain zone.'
 | 
			
		||||
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Sets the credentials for accessing ArtFiles's API
 | 
			
		||||
# Usage: _set_credentials
 | 
			
		||||
_set_credentials() {
 | 
			
		||||
  _info 'Setting credentials…'
 | 
			
		||||
  AF_API_USERNAME="${AF_API_USERNAME:-$(_readaccountconf_mutable AF_API_USERNAME)}"
 | 
			
		||||
  AF_API_PASSWORD="${AF_API_PASSWORD:-$(_readaccountconf_mutable AF_API_PASSWORD)}"
 | 
			
		||||
  if [ -z "$AF_API_USERNAME" ] || [ -z "$AF_API_PASSWORD" ]; then
 | 
			
		||||
    _err 'Missing ArtFiles.de username and/or password.'
 | 
			
		||||
    _err 'Please ensure both are set via export command & try again.'
 | 
			
		||||
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Adds the HTTP Authorization & Content-Type headers to a follow-up request.
 | 
			
		||||
# Usage: _set_headers
 | 
			
		||||
_set_headers() {
 | 
			
		||||
  _info 'Setting headers…'
 | 
			
		||||
  encoded="$(printf -- '%s:%s' "$AF_API_USERNAME" "$AF_API_PASSWORD" | _base64)"
 | 
			
		||||
  export _H1="Authorization: Basic $encoded"
 | 
			
		||||
  export _H2='Content-Type: application/json'
 | 
			
		||||
}
 | 
			
		||||
@@ -1,11 +1,16 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_arvan_info='ArvanCloud.ir
 | 
			
		||||
Site: ArvanCloud.ir
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_arvan
 | 
			
		||||
Options:
 | 
			
		||||
 Arvan_Token API Token
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/2796
 | 
			
		||||
Author: Vahid Fardi
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
#Arvan_Token="Apikey xxxx"
 | 
			
		||||
ARVAN_API_URL="https://napi.arvancloud.ir/cdn/4.0/domains"
 | 
			
		||||
 | 
			
		||||
ARVAN_API_URL="https://napi.arvancloud.com/cdn/4.0/domains"
 | 
			
		||||
#Author: Vahid Fardi
 | 
			
		||||
#Report Bugs here: https://github.com/Neilpang/acme.sh
 | 
			
		||||
#
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: dns_arvan_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
@@ -18,7 +23,7 @@ dns_arvan_add() {
 | 
			
		||||
 | 
			
		||||
  if [ -z "$Arvan_Token" ]; then
 | 
			
		||||
    _err "You didn't specify \"Arvan_Token\" token yet."
 | 
			
		||||
    _err "You can get yours from here https://npanel.arvancloud.com/profile/api-keys"
 | 
			
		||||
    _err "You can get yours from here https://npanel.arvancloud.ir/profile/api-keys"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  #save the api token to the account conf file.
 | 
			
		||||
@@ -40,7 +45,7 @@ dns_arvan_add() {
 | 
			
		||||
      _info "response id is $response"
 | 
			
		||||
      _info "Added, OK"
 | 
			
		||||
      return 0
 | 
			
		||||
    elif _contains "$response" "Record Data is Duplicated"; then
 | 
			
		||||
    elif _contains "$response" "Record Data is duplicate"; then
 | 
			
		||||
      _info "Already exists, OK"
 | 
			
		||||
      return 0
 | 
			
		||||
    else
 | 
			
		||||
@@ -141,6 +146,7 @@ _arvan_rest() {
 | 
			
		||||
    response="$(_post "$data" "$ARVAN_API_URL/$ep" "" "$mtd")"
 | 
			
		||||
  elif [ "$mtd" = "POST" ]; then
 | 
			
		||||
    export _H2="Content-Type: application/json"
 | 
			
		||||
    export _H3="Accept: application/json"
 | 
			
		||||
    _debug data "$data"
 | 
			
		||||
    response="$(_post "$data" "$ARVAN_API_URL/$ep" "" "$mtd")"
 | 
			
		||||
  else
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,15 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
#AURORA_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
 | 
			
		||||
#
 | 
			
		||||
#AURORA_Secret="sdfsdfsdfljlbjkljlkjsdfoiwje"
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_aurora_info='versio.nl AuroraDNS
 | 
			
		||||
Domains: pcextreme.nl
 | 
			
		||||
Site: versio.nl
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_aurora
 | 
			
		||||
Options:
 | 
			
		||||
 AURORA_Key API Key
 | 
			
		||||
 AURORA_Secret API Secret
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/3459
 | 
			
		||||
Author: Jasper Zonneveld
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
AURORA_Api="https://api.auroradns.eu"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +1,15 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# -*- mode: sh; tab-width: 2; indent-tabs-mode: s; coding: utf-8 -*-
 | 
			
		||||
 | 
			
		||||
# This is the InternetX autoDNS xml api wrapper for acme.sh
 | 
			
		||||
# Author: auerswald@gmail.com
 | 
			
		||||
# Created: 2018-01-14
 | 
			
		||||
#
 | 
			
		||||
#     export AUTODNS_USER="username"
 | 
			
		||||
#     export AUTODNS_PASSWORD="password"
 | 
			
		||||
#     export AUTODNS_CONTEXT="context"
 | 
			
		||||
#
 | 
			
		||||
# Usage:
 | 
			
		||||
#     acme.sh --issue --dns dns_autodns -d example.com
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_autodns_info='InternetX autoDNS
 | 
			
		||||
 InternetX autoDNS XML API
 | 
			
		||||
Site: InternetX.com/autodns/
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_autodns
 | 
			
		||||
Options:
 | 
			
		||||
 AUTODNS_USER Username
 | 
			
		||||
 AUTODNS_PASSWORD Password
 | 
			
		||||
 AUTODNS_CONTEXT Context
 | 
			
		||||
Author: <auerswald@gmail.com>
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
AUTODNS_API="https://gateway.autodns.com"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,13 +1,15 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_aws_info='Amazon AWS Route53 domain API
 | 
			
		||||
Site: docs.aws.amazon.com/route53/
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_aws
 | 
			
		||||
Options:
 | 
			
		||||
 AWS_ACCESS_KEY_ID API Key ID
 | 
			
		||||
 AWS_SECRET_ACCESS_KEY API Secret
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
#AWS_ACCESS_KEY_ID="sdfsdfsdfljlbjkljlkjsdfoiwje"
 | 
			
		||||
#
 | 
			
		||||
#AWS_SECRET_ACCESS_KEY="xxxxxxx"
 | 
			
		||||
 | 
			
		||||
#This is the Amazon Route53 api wrapper for acme.sh
 | 
			
		||||
#All `_sleep` commands are included to avoid Route53 throttling, see
 | 
			
		||||
#https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/DNSLimitations.html#limits-api-requests
 | 
			
		||||
# All `_sleep` commands are included to avoid Route53 throttling, see
 | 
			
		||||
# https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/DNSLimitations.html#limits-api-requests
 | 
			
		||||
 | 
			
		||||
AWS_HOST="route53.amazonaws.com"
 | 
			
		||||
AWS_URL="https://$AWS_HOST"
 | 
			
		||||
@@ -145,41 +147,29 @@ dns_aws_rm() {
 | 
			
		||||
  fi
 | 
			
		||||
  _sleep 1
 | 
			
		||||
  return 1
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
 | 
			
		||||
_get_root() {
 | 
			
		||||
  domain=$1
 | 
			
		||||
  i=2
 | 
			
		||||
  i=1
 | 
			
		||||
  p=1
 | 
			
		||||
 | 
			
		||||
  if aws_rest GET "2013-04-01/hostedzone"; then
 | 
			
		||||
    while true; do
 | 
			
		||||
      h=$(printf "%s" "$domain" | cut -d . -f $i-100)
 | 
			
		||||
      _debug2 "Checking domain: $h"
 | 
			
		||||
      if [ -z "$h" ]; then
 | 
			
		||||
        if _contains "$response" "<IsTruncated>true</IsTruncated>" && _contains "$response" "<NextMarker>"; then
 | 
			
		||||
          _debug "IsTruncated"
 | 
			
		||||
          _nextMarker="$(echo "$response" | _egrep_o "<NextMarker>.*</NextMarker>" | cut -d '>' -f 2 | cut -d '<' -f 1)"
 | 
			
		||||
          _debug "NextMarker" "$_nextMarker"
 | 
			
		||||
          if aws_rest GET "2013-04-01/hostedzone" "marker=$_nextMarker"; then
 | 
			
		||||
            _debug "Truncated request OK"
 | 
			
		||||
            i=2
 | 
			
		||||
            p=1
 | 
			
		||||
            continue
 | 
			
		||||
          else
 | 
			
		||||
            _err "Truncated request error."
 | 
			
		||||
          fi
 | 
			
		||||
        fi
 | 
			
		||||
        #not valid
 | 
			
		||||
        _err "Invalid domain"
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
  # iterate over names (a.b.c.d -> b.c.d -> c.d -> d)
 | 
			
		||||
  while true; do
 | 
			
		||||
    h=$(printf "%s" "$domain" | cut -d . -f $i-100 | sed 's/\./\\./g')
 | 
			
		||||
    _debug "Checking domain: $h"
 | 
			
		||||
    if [ -z "$h" ]; then
 | 
			
		||||
      _error "invalid domain"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # iterate over paginated result for list_hosted_zones
 | 
			
		||||
    aws_rest GET "2013-04-01/hostedzone"
 | 
			
		||||
    while true; do
 | 
			
		||||
      if _contains "$response" "<Name>$h.</Name>"; then
 | 
			
		||||
        hostedzone="$(echo "$response" | sed 's/<HostedZone>/#&/g' | tr '#' '\n' | _egrep_o "<HostedZone><Id>[^<]*<.Id><Name>$h.<.Name>.*<PrivateZone>false<.PrivateZone>.*<.HostedZone>")"
 | 
			
		||||
        hostedzone="$(echo "$response" | tr -d '\n' | sed 's/<HostedZone>/#&/g' | tr '#' '\n' | _egrep_o "<HostedZone><Id>[^<]*<.Id><Name>$h.<.Name>.*<PrivateZone>false<.PrivateZone>.*<.HostedZone>")"
 | 
			
		||||
        _debug hostedzone "$hostedzone"
 | 
			
		||||
        if [ "$hostedzone" ]; then
 | 
			
		||||
          _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "<Id>.*<.Id>" | head -n 1 | _egrep_o ">.*<" | tr -d "<>")
 | 
			
		||||
@@ -192,10 +182,19 @@ _get_root() {
 | 
			
		||||
          return 1
 | 
			
		||||
        fi
 | 
			
		||||
      fi
 | 
			
		||||
      p=$i
 | 
			
		||||
      i=$(_math "$i" + 1)
 | 
			
		||||
      if _contains "$response" "<IsTruncated>true</IsTruncated>" && _contains "$response" "<NextMarker>"; then
 | 
			
		||||
        _debug "IsTruncated"
 | 
			
		||||
        _nextMarker="$(echo "$response" | _egrep_o "<NextMarker>.*</NextMarker>" | cut -d '>' -f 2 | cut -d '<' -f 1)"
 | 
			
		||||
        _debug "NextMarker" "$_nextMarker"
 | 
			
		||||
      else
 | 
			
		||||
        break
 | 
			
		||||
      fi
 | 
			
		||||
      _debug "Checking domain: $h - Next Page "
 | 
			
		||||
      aws_rest GET "2013-04-01/hostedzone" "marker=$_nextMarker"
 | 
			
		||||
    done
 | 
			
		||||
  fi
 | 
			
		||||
    p=$i
 | 
			
		||||
    i=$(_math "$i" + 1)
 | 
			
		||||
  done
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -209,24 +208,40 @@ _use_container_role() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_use_instance_role() {
 | 
			
		||||
  _url="http://169.254.169.254/latest/meta-data/iam/security-credentials/"
 | 
			
		||||
  _debug "_url" "$_url"
 | 
			
		||||
  if ! _get "$_url" true 1 | _head_n 1 | grep -Fq 200; then
 | 
			
		||||
  _instance_role_name_url="http://169.254.169.254/latest/meta-data/iam/security-credentials/"
 | 
			
		||||
 | 
			
		||||
  if _get "$_instance_role_name_url" true 1 | _head_n 1 | grep -Fq 401; then
 | 
			
		||||
    _debug "Using IMDSv2"
 | 
			
		||||
    _token_url="http://169.254.169.254/latest/api/token"
 | 
			
		||||
    export _H1="X-aws-ec2-metadata-token-ttl-seconds: 21600"
 | 
			
		||||
    _token="$(_post "" "$_token_url" "" "PUT")"
 | 
			
		||||
    _secure_debug3 "_token" "$_token"
 | 
			
		||||
    if [ -z "$_token" ]; then
 | 
			
		||||
      _debug "Unable to fetch IMDSv2 token from instance metadata"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    export _H1="X-aws-ec2-metadata-token: $_token"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! _get "$_instance_role_name_url" true 1 | _head_n 1 | grep -Fq 200; then
 | 
			
		||||
    _debug "Unable to fetch IAM role from instance metadata"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _aws_role=$(_get "$_url" "" 1)
 | 
			
		||||
  _debug "_aws_role" "$_aws_role"
 | 
			
		||||
  _use_metadata "$_url$_aws_role"
 | 
			
		||||
 | 
			
		||||
  _instance_role_name=$(_get "$_instance_role_name_url" "" 1)
 | 
			
		||||
  _debug "_instance_role_name" "$_instance_role_name"
 | 
			
		||||
  _use_metadata "$_instance_role_name_url$_instance_role_name" "$_token"
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_use_metadata() {
 | 
			
		||||
  export _H1="X-aws-ec2-metadata-token: $2"
 | 
			
		||||
  _aws_creds="$(
 | 
			
		||||
    _get "$1" "" 1 |
 | 
			
		||||
      _normalizeJson |
 | 
			
		||||
      tr '{,}' '\n' |
 | 
			
		||||
      while read -r _line; do
 | 
			
		||||
        _key="$(echo "${_line%%:*}" | tr -d '"')"
 | 
			
		||||
        _key="$(echo "${_line%%:*}" | tr -d '\"')"
 | 
			
		||||
        _value="${_line#*:}"
 | 
			
		||||
        _debug3 "_key" "$_key"
 | 
			
		||||
        _secure_debug3 "_value" "$_value"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,13 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
#AZION_Email=""
 | 
			
		||||
#AZION_Password=""
 | 
			
		||||
#
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_azion_info='Azion.om
 | 
			
		||||
Site: Azion.com
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_azion
 | 
			
		||||
Options:
 | 
			
		||||
 AZION_Email Email
 | 
			
		||||
 AZION_Password Password
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/3555
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
AZION_Api="https://api.azionapi.net"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,15 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
WIKI="https://github.com/acmesh-official/acme.sh/wiki/How-to-use-Azure-DNS"
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_azure_info='Azure
 | 
			
		||||
Site: Azure.microsoft.com
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_azure
 | 
			
		||||
Options:
 | 
			
		||||
 AZUREDNS_SUBSCRIPTIONID Subscription ID
 | 
			
		||||
 AZUREDNS_TENANTID Tenant ID
 | 
			
		||||
 AZUREDNS_APPID App ID. App ID of the service principal
 | 
			
		||||
 AZUREDNS_CLIENTSECRET Client Secret. Secret from creating the service principal
 | 
			
		||||
 AZUREDNS_MANAGEDIDENTITY Use Managed Identity. Use Managed Identity assigned to a resource instead of a service principal. "true"/"false"
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										88
									
								
								dnsapi/dns_bookmyname.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								dnsapi/dns_bookmyname.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,88 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_bookmyname_info='BookMyName.com
 | 
			
		||||
Site: BookMyName.com
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_bookmyname
 | 
			
		||||
Options:
 | 
			
		||||
 BOOKMYNAME_USERNAME Username
 | 
			
		||||
 BOOKMYNAME_PASSWORD Password
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/3209
 | 
			
		||||
Author: Neilpang
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
# BookMyName urls:
 | 
			
		||||
# https://BOOKMYNAME_USERNAME:BOOKMYNAME_PASSWORD@www.bookmyname.com/dyndns/?hostname=_acme-challenge.domain.tld&type=txt&ttl=300&do=add&value="XXXXXXXX"'
 | 
			
		||||
# https://BOOKMYNAME_USERNAME:BOOKMYNAME_PASSWORD@www.bookmyname.com/dyndns/?hostname=_acme-challenge.domain.tld&type=txt&ttl=300&do=remove&value="XXXXXXXX"'
 | 
			
		||||
 | 
			
		||||
# Output:
 | 
			
		||||
#good: update done, cid 123456, domain id 456789, type txt, ip XXXXXXXX
 | 
			
		||||
#good: remove done 1, cid 123456, domain id 456789, ttl 300, type txt, ip XXXXXXXX
 | 
			
		||||
 | 
			
		||||
# Be careful, BMN DNS servers can be slow to pick up changes; using dnssleep is thus advised.
 | 
			
		||||
 | 
			
		||||
# Usage:
 | 
			
		||||
# export BOOKMYNAME_USERNAME="ABCDE-FREE"
 | 
			
		||||
# export BOOKMYNAME_PASSWORD="MyPassword"
 | 
			
		||||
# /usr/local/ssl/acme.sh/acme.sh --dns dns_bookmyname --dnssleep 600 --issue -d domain.tld
 | 
			
		||||
 | 
			
		||||
#Usage: dns_bookmyname_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_bookmyname_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
  _info "Using bookmyname"
 | 
			
		||||
  _debug fulldomain "$fulldomain"
 | 
			
		||||
  _debug txtvalue "$txtvalue"
 | 
			
		||||
 | 
			
		||||
  BOOKMYNAME_USERNAME="${BOOKMYNAME_USERNAME:-$(_readaccountconf_mutable BOOKMYNAME_USERNAME)}"
 | 
			
		||||
  BOOKMYNAME_PASSWORD="${BOOKMYNAME_PASSWORD:-$(_readaccountconf_mutable BOOKMYNAME_PASSWORD)}"
 | 
			
		||||
 | 
			
		||||
  if [ -z "$BOOKMYNAME_USERNAME" ] || [ -z "$BOOKMYNAME_PASSWORD" ]; then
 | 
			
		||||
    BOOKMYNAME_USERNAME=""
 | 
			
		||||
    BOOKMYNAME_PASSWORD=""
 | 
			
		||||
    _err "You didn't specify BookMyName username and password yet."
 | 
			
		||||
    _err "Please specify them and try again."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  #save the credentials to the account conf file.
 | 
			
		||||
  _saveaccountconf_mutable BOOKMYNAME_USERNAME "$BOOKMYNAME_USERNAME"
 | 
			
		||||
  _saveaccountconf_mutable BOOKMYNAME_PASSWORD "$BOOKMYNAME_PASSWORD"
 | 
			
		||||
 | 
			
		||||
  uri="https://${BOOKMYNAME_USERNAME}:${BOOKMYNAME_PASSWORD}@www.bookmyname.com/dyndns/"
 | 
			
		||||
  data="?hostname=${fulldomain}&type=TXT&ttl=300&do=add&value=${txtvalue}"
 | 
			
		||||
  result="$(_get "${uri}${data}")"
 | 
			
		||||
  _debug "Result: $result"
 | 
			
		||||
 | 
			
		||||
  if ! _startswith "$result" 'good: update done, cid '; then
 | 
			
		||||
    _err "Can't add $fulldomain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#Usage: fulldomain txtvalue
 | 
			
		||||
#Remove the txt record after validation.
 | 
			
		||||
dns_bookmyname_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
  _info "Using bookmyname"
 | 
			
		||||
  _debug fulldomain "$fulldomain"
 | 
			
		||||
  _debug txtvalue "$txtvalue"
 | 
			
		||||
 | 
			
		||||
  BOOKMYNAME_USERNAME="${BOOKMYNAME_USERNAME:-$(_readaccountconf_mutable BOOKMYNAME_USERNAME)}"
 | 
			
		||||
  BOOKMYNAME_PASSWORD="${BOOKMYNAME_PASSWORD:-$(_readaccountconf_mutable BOOKMYNAME_PASSWORD)}"
 | 
			
		||||
 | 
			
		||||
  uri="https://${BOOKMYNAME_USERNAME}:${BOOKMYNAME_PASSWORD}@www.bookmyname.com/dyndns/"
 | 
			
		||||
  data="?hostname=${fulldomain}&type=TXT&ttl=300&do=remove&value=${txtvalue}"
 | 
			
		||||
  result="$(_get "${uri}${data}")"
 | 
			
		||||
  _debug "Result: $result"
 | 
			
		||||
 | 
			
		||||
  if ! _startswith "$result" 'good: remove done 1, cid '; then
 | 
			
		||||
    _info "Can't remove $fulldomain"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
							
								
								
									
										245
									
								
								dnsapi/dns_bunny.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										245
									
								
								dnsapi/dns_bunny.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,245 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_bunny_info='Bunny.net
 | 
			
		||||
Site: Bunny.net/dns/
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_bunny
 | 
			
		||||
Options:
 | 
			
		||||
 BUNNY_API_KEY API Key
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/4296
 | 
			
		||||
Author: <nosilver4u@ewww.io>
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
#####################  Public functions  #####################
 | 
			
		||||
 | 
			
		||||
## Create the text record for validation.
 | 
			
		||||
## Usage: fulldomain txtvalue
 | 
			
		||||
## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_bunny_add() {
 | 
			
		||||
  fulldomain="$(echo "$1" | _lower_case)"
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  BUNNY_API_KEY="${BUNNY_API_KEY:-$(_readaccountconf_mutable BUNNY_API_KEY)}"
 | 
			
		||||
  # Check if API Key is set
 | 
			
		||||
  if [ -z "$BUNNY_API_KEY" ]; then
 | 
			
		||||
    BUNNY_API_KEY=""
 | 
			
		||||
    _err "You did not specify Bunny.net API key."
 | 
			
		||||
    _err "Please export BUNNY_API_KEY and try again."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Using Bunny.net dns validation - add record"
 | 
			
		||||
  _debug fulldomain "$fulldomain"
 | 
			
		||||
  _debug txtvalue "$txtvalue"
 | 
			
		||||
 | 
			
		||||
  ## save the env vars (key and domain split location) for later automated use
 | 
			
		||||
  _saveaccountconf_mutable BUNNY_API_KEY "$BUNNY_API_KEY"
 | 
			
		||||
 | 
			
		||||
  ## split the domain for Bunny API
 | 
			
		||||
  if ! _get_base_domain "$fulldomain"; then
 | 
			
		||||
    _err "domain not found in your account for addition"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug _sub_domain "$_sub_domain"
 | 
			
		||||
  _debug _domain "$_domain"
 | 
			
		||||
  _debug _domain_id "$_domain_id"
 | 
			
		||||
 | 
			
		||||
  ## Set the header with our post type and auth key
 | 
			
		||||
  export _H1="Accept: application/json"
 | 
			
		||||
  export _H2="AccessKey: $BUNNY_API_KEY"
 | 
			
		||||
  export _H3="Content-Type: application/json"
 | 
			
		||||
  PURL="https://api.bunny.net/dnszone/$_domain_id/records"
 | 
			
		||||
  PBODY='{"Id":'$_domain_id',"Type":3,"Name":"'$_sub_domain'","Value":"'$txtvalue'","ttl":120}'
 | 
			
		||||
 | 
			
		||||
  _debug PURL "$PURL"
 | 
			
		||||
  _debug PBODY "$PBODY"
 | 
			
		||||
 | 
			
		||||
  ## the create request - POST
 | 
			
		||||
  ## args: BODY, URL, [need64, httpmethod]
 | 
			
		||||
  response="$(_post "$PBODY" "$PURL" "" "PUT")"
 | 
			
		||||
 | 
			
		||||
  ## check response
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "error in response: $response"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
 | 
			
		||||
  ## finished correctly
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
## Remove the txt record after validation.
 | 
			
		||||
## Usage: fulldomain txtvalue
 | 
			
		||||
## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_bunny_rm() {
 | 
			
		||||
  fulldomain="$(echo "$1" | _lower_case)"
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  BUNNY_API_KEY="${BUNNY_API_KEY:-$(_readaccountconf_mutable BUNNY_API_KEY)}"
 | 
			
		||||
  # Check if API Key Exists
 | 
			
		||||
  if [ -z "$BUNNY_API_KEY" ]; then
 | 
			
		||||
    BUNNY_API_KEY=""
 | 
			
		||||
    _err "You did not specify Bunny.net API key."
 | 
			
		||||
    _err "Please export BUNNY_API_KEY and try again."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Using Bunny.net dns validation - remove record"
 | 
			
		||||
  _debug fulldomain "$fulldomain"
 | 
			
		||||
  _debug txtvalue "$txtvalue"
 | 
			
		||||
 | 
			
		||||
  ## split the domain for Bunny API
 | 
			
		||||
  if ! _get_base_domain "$fulldomain"; then
 | 
			
		||||
    _err "Domain not found in your account for TXT record removal"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug _sub_domain "$_sub_domain"
 | 
			
		||||
  _debug _domain "$_domain"
 | 
			
		||||
  _debug _domain_id "$_domain_id"
 | 
			
		||||
 | 
			
		||||
  ## Set the header with our post type and key auth key
 | 
			
		||||
  export _H1="Accept: application/json"
 | 
			
		||||
  export _H2="AccessKey: $BUNNY_API_KEY"
 | 
			
		||||
  ## get URL for the list of DNS records
 | 
			
		||||
  GURL="https://api.bunny.net/dnszone/$_domain_id"
 | 
			
		||||
 | 
			
		||||
  ## 1) Get the domain/zone records
 | 
			
		||||
  ## the fetch request - GET
 | 
			
		||||
  ## args: URL, [onlyheader, timeout]
 | 
			
		||||
  domain_list="$(_get "$GURL")"
 | 
			
		||||
 | 
			
		||||
  ## check response
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "error in domain_list response: $domain_list"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 domain_list "$domain_list"
 | 
			
		||||
 | 
			
		||||
  ## 2) search through records
 | 
			
		||||
  ## check for what we are looking for: "Type":3,"Value":"$txtvalue","Name":"$_sub_domain"
 | 
			
		||||
  record="$(echo "$domain_list" | _egrep_o "\"Id\"\s*\:\s*\"*[0-9]+\"*,\s*\"Type\"[^}]*\"Value\"\s*\:\s*\"$txtvalue\"[^}]*\"Name\"\s*\:\s*\"$_sub_domain\"")"
 | 
			
		||||
 | 
			
		||||
  if [ -n "$record" ]; then
 | 
			
		||||
 | 
			
		||||
    ## We found records
 | 
			
		||||
    rec_ids="$(echo "$record" | _egrep_o "Id\"\s*\:\s*\"*[0-9]+" | _egrep_o "[0-9]+")"
 | 
			
		||||
    _debug rec_ids "$rec_ids"
 | 
			
		||||
    if [ -n "$rec_ids" ]; then
 | 
			
		||||
      echo "$rec_ids" | while IFS= read -r rec_id; do
 | 
			
		||||
        ## delete the record
 | 
			
		||||
        ## delete URL for removing the one we dont want
 | 
			
		||||
        DURL="https://api.bunny.net/dnszone/$_domain_id/records/$rec_id"
 | 
			
		||||
 | 
			
		||||
        ## the removal request - DELETE
 | 
			
		||||
        ## args: BODY, URL, [need64, httpmethod]
 | 
			
		||||
        response="$(_post "" "$DURL" "" "DELETE")"
 | 
			
		||||
 | 
			
		||||
        ## check response (sort of)
 | 
			
		||||
        if [ "$?" != "0" ]; then
 | 
			
		||||
          _err "error in remove response: $response"
 | 
			
		||||
          return 1
 | 
			
		||||
        fi
 | 
			
		||||
        _debug2 response "$response"
 | 
			
		||||
 | 
			
		||||
      done
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  ## finished correctly
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#####################  Private functions below  #####################
 | 
			
		||||
 | 
			
		||||
## Split the domain provided into the "base domain" and the "start prefix".
 | 
			
		||||
## This function searches for the longest subdomain in your account
 | 
			
		||||
## for the full domain given and splits it into the base domain (zone)
 | 
			
		||||
## and the prefix/record to be added/removed
 | 
			
		||||
## USAGE: fulldomain
 | 
			
		||||
## EG: "_acme-challenge.two.three.four.domain.com"
 | 
			
		||||
## returns
 | 
			
		||||
## _sub_domain="_acme-challenge.two"
 | 
			
		||||
## _domain="three.four.domain.com" *IF* zone "three.four.domain.com" exists
 | 
			
		||||
## _domain_id=234
 | 
			
		||||
## if only "domain.com" exists it will return
 | 
			
		||||
## _sub_domain="_acme-challenge.two.three.four"
 | 
			
		||||
## _domain="domain.com"
 | 
			
		||||
## _domain_id=234
 | 
			
		||||
_get_base_domain() {
 | 
			
		||||
  # args
 | 
			
		||||
  fulldomain="$(echo "$1" | _lower_case)"
 | 
			
		||||
  _debug fulldomain "$fulldomain"
 | 
			
		||||
 | 
			
		||||
  # domain max legal length = 253
 | 
			
		||||
  MAX_DOM=255
 | 
			
		||||
  page=1
 | 
			
		||||
 | 
			
		||||
  ## get a list of domains for the account to check thru
 | 
			
		||||
  ## Set the headers
 | 
			
		||||
  export _H1="Accept: application/json"
 | 
			
		||||
  export _H2="AccessKey: $BUNNY_API_KEY"
 | 
			
		||||
  _debug BUNNY_API_KEY "$BUNNY_API_KEY"
 | 
			
		||||
  ## get URL for the list of domains
 | 
			
		||||
  ## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}}
 | 
			
		||||
  DOMURL="https://api.bunny.net/dnszone"
 | 
			
		||||
 | 
			
		||||
  ## while we dont have a matching domain we keep going
 | 
			
		||||
  while [ -z "$found" ]; do
 | 
			
		||||
    ## get the domain list (current page)
 | 
			
		||||
    domain_list="$(_get "$DOMURL")"
 | 
			
		||||
 | 
			
		||||
    ## check response
 | 
			
		||||
    if [ "$?" != "0" ]; then
 | 
			
		||||
      _err "error in domain_list response: $domain_list"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    _debug2 domain_list "$domain_list"
 | 
			
		||||
 | 
			
		||||
    i=1
 | 
			
		||||
    while [ $i -gt 0 ]; do
 | 
			
		||||
      ## get next longest domain
 | 
			
		||||
      _domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM")
 | 
			
		||||
      ## check we got something back from our cut (or are we at the end)
 | 
			
		||||
      if [ -z "$_domain" ]; then
 | 
			
		||||
        break
 | 
			
		||||
      fi
 | 
			
		||||
      ## we got part of a domain back - grep it out
 | 
			
		||||
      found="$(echo "$domain_list" | _egrep_o "\"Id\"\s*:\s*\"*[0-9]+\"*,\s*\"Domain\"\s*\:\s*\"$_domain\"")"
 | 
			
		||||
      ## check if it exists
 | 
			
		||||
      if [ -n "$found" ]; then
 | 
			
		||||
        ## exists - exit loop returning the parts
 | 
			
		||||
        sub_point=$(_math $i - 1)
 | 
			
		||||
        _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$sub_point")
 | 
			
		||||
        _domain_id="$(echo "$found" | _egrep_o "Id\"\s*\:\s*\"*[0-9]+" | _egrep_o "[0-9]+")"
 | 
			
		||||
        _debug _domain_id "$_domain_id"
 | 
			
		||||
        _debug _domain "$_domain"
 | 
			
		||||
        _debug _sub_domain "$_sub_domain"
 | 
			
		||||
        found=""
 | 
			
		||||
        return 0
 | 
			
		||||
      fi
 | 
			
		||||
      ## increment cut point $i
 | 
			
		||||
      i=$(_math $i + 1)
 | 
			
		||||
    done
 | 
			
		||||
 | 
			
		||||
    if [ -z "$found" ]; then
 | 
			
		||||
      page=$(_math $page + 1)
 | 
			
		||||
      nextpage="https://api.bunny.net/dnszone?page=$page"
 | 
			
		||||
      ## Find the next page if we don't have a match.
 | 
			
		||||
      hasnextpage="$(echo "$domain_list" | _egrep_o "\"HasMoreItems\"\s*:\s*true")"
 | 
			
		||||
      if [ -z "$hasnextpage" ]; then
 | 
			
		||||
        _err "No record and no nextpage in Bunny.net domain search."
 | 
			
		||||
        found=""
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
      _debug2 nextpage "$nextpage"
 | 
			
		||||
      DOMURL="$nextpage"
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  ## We went through the entire domain zone list and didn't find one that matched.
 | 
			
		||||
  ## If we ever get here, something is broken in the code...
 | 
			
		||||
  _err "Domain not found in Bunny.net account, but we should never get here!"
 | 
			
		||||
  found=""
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
@@ -1,13 +1,16 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
#CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
 | 
			
		||||
#
 | 
			
		||||
#CF_Email="xxxx@sss.com"
 | 
			
		||||
 | 
			
		||||
#CF_Token="xxxx"
 | 
			
		||||
#CF_Account_ID="xxxx"
 | 
			
		||||
#CF_Zone_ID="xxxx"
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_cf_info='CloudFlare
 | 
			
		||||
Site: CloudFlare.com
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_cf
 | 
			
		||||
Options:
 | 
			
		||||
 CF_Key API Key
 | 
			
		||||
 CF_Email Your account email
 | 
			
		||||
OptionsAlt:
 | 
			
		||||
 CF_Token API Token
 | 
			
		||||
 CF_Account_ID Account ID
 | 
			
		||||
 CF_Zone_ID Zone ID. Optional.
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
CF_Api="https://api.cloudflare.com/client/v4"
 | 
			
		||||
 | 
			
		||||
@@ -32,7 +35,8 @@ dns_cf_add() {
 | 
			
		||||
    else
 | 
			
		||||
      _saveaccountconf_mutable CF_Token "$CF_Token"
 | 
			
		||||
      _saveaccountconf_mutable CF_Account_ID "$CF_Account_ID"
 | 
			
		||||
      _saveaccountconf_mutable CF_Zone_ID "$CF_Zone_ID"
 | 
			
		||||
      _clearaccountconf_mutable CF_Zone_ID
 | 
			
		||||
      _clearaccountconf CF_Zone_ID
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then
 | 
			
		||||
@@ -51,6 +55,14 @@ dns_cf_add() {
 | 
			
		||||
    #save the api key and email to the account conf file.
 | 
			
		||||
    _saveaccountconf_mutable CF_Key "$CF_Key"
 | 
			
		||||
    _saveaccountconf_mutable CF_Email "$CF_Email"
 | 
			
		||||
 | 
			
		||||
    _clearaccountconf_mutable CF_Token
 | 
			
		||||
    _clearaccountconf_mutable CF_Account_ID
 | 
			
		||||
    _clearaccountconf_mutable CF_Zone_ID
 | 
			
		||||
    _clearaccountconf CF_Token
 | 
			
		||||
    _clearaccountconf CF_Account_ID
 | 
			
		||||
    _clearaccountconf CF_Zone_ID
 | 
			
		||||
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,15 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
# Author: Radek Sprta <sprta@vshosting.cz>
 | 
			
		||||
 | 
			
		||||
#CLOUDDNS_EMAIL=XXXXX
 | 
			
		||||
#CLOUDDNS_PASSWORD="YYYYYYYYY"
 | 
			
		||||
#CLOUDDNS_CLIENT_ID=XXXXX
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_clouddns_info='vshosting.cz CloudDNS
 | 
			
		||||
Site: github.com/vshosting/clouddns
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_clouddns
 | 
			
		||||
Options:
 | 
			
		||||
 CLOUDDNS_EMAIL Email
 | 
			
		||||
 CLOUDDNS_PASSWORD Password
 | 
			
		||||
 CLOUDDNS_CLIENT_ID Client ID
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/2699
 | 
			
		||||
Author: Radek Sprta <sprta@vshosting.cz>
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
CLOUDDNS_API='https://admin.vshosting.cloud/clouddns'
 | 
			
		||||
CLOUDDNS_LOGIN_API='https://admin.vshosting.cloud/api/public/auth/login'
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,15 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_cloudns_info='ClouDNS.net
 | 
			
		||||
Site: ClouDNS.net
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_cloudns
 | 
			
		||||
Options:
 | 
			
		||||
 CLOUDNS_AUTH_ID Regular auth ID
 | 
			
		||||
 CLOUDNS_SUB_AUTH_ID Sub auth ID
 | 
			
		||||
 CLOUDNS_AUTH_PASSWORD Auth Password
 | 
			
		||||
Author: Boyan Peychev <boyan@cloudns.net>
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
# Author: Boyan Peychev <boyan at cloudns dot net>
 | 
			
		||||
# Repository: https://github.com/ClouDNS/acme.sh/
 | 
			
		||||
# Editor: I Komang Suryadana
 | 
			
		||||
 | 
			
		||||
#CLOUDNS_AUTH_ID=XXXXX
 | 
			
		||||
#CLOUDNS_SUB_AUTH_ID=XXXXX
 | 
			
		||||
#CLOUDNS_AUTH_PASSWORD="YYYYYYYYY"
 | 
			
		||||
CLOUDNS_API="https://api.cloudns.net"
 | 
			
		||||
DOMAIN_TYPE=
 | 
			
		||||
DOMAIN_MASTER=
 | 
			
		||||
@@ -78,7 +81,7 @@ dns_cloudns_rm() {
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  for i in $(echo "$response" | tr '{' "\n" | grep "$record"); do
 | 
			
		||||
  for i in $(echo "$response" | tr '{' "\n" | grep -- "$record"); do
 | 
			
		||||
    record_id=$(echo "$i" | tr ',' "\n" | grep -E '^"id"' | sed -re 's/^\"id\"\:\"([0-9]+)\"$/\1/g')
 | 
			
		||||
 | 
			
		||||
    if [ -n "$record_id" ]; then
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,14 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
# DNS API for acme.sh for Core-Networks (https://beta.api.core-networks.de/doc/).
 | 
			
		||||
# created by 5ll and francis
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_cn_info='Core-Networks.de
 | 
			
		||||
Site: beta.api.Core-Networks.de/doc/
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_cn
 | 
			
		||||
Options:
 | 
			
		||||
 CN_User User
 | 
			
		||||
 CN_Password Password
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/2142
 | 
			
		||||
Author: 5ll, francis
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
CN_API="https://beta.api.core-networks.de"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,15 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_conoha_info='ConoHa.jp
 | 
			
		||||
Domains: ConoHa.io
 | 
			
		||||
Site: ConoHa.jp
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_conoha
 | 
			
		||||
Options:
 | 
			
		||||
 CONOHA_Username Username
 | 
			
		||||
 CONOHA_Password Password
 | 
			
		||||
 CONOHA_TenantId TenantId
 | 
			
		||||
 CONOHA_IdentityServiceApi Identity Service API. E.g. "https://identity.xxxx.conoha.io/v2.0"
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
CONOHA_DNS_EP_PREFIX_REGEXP="https://dns-service\."
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,16 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
# Author: Wout Decre <wout@canodus.be>
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_constellix_info='Constellix.com
 | 
			
		||||
Site: Constellix.com
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_constellix
 | 
			
		||||
Options:
 | 
			
		||||
 CONSTELLIX_Key API Key
 | 
			
		||||
 CONSTELLIX_Secret API Secret
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/2724
 | 
			
		||||
Author: Wout Decre <wout@canodus.be>
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
CONSTELLIX_Api="https://api.dns.constellix.com/v1"
 | 
			
		||||
#CONSTELLIX_Key="XXX"
 | 
			
		||||
#CONSTELLIX_Secret="XXX"
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,18 +1,19 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
#
 | 
			
		||||
#Author: Bjarne Saltbaek
 | 
			
		||||
#Report Bugs here: https://github.com/acmesh-official/acme.sh/issues/3732
 | 
			
		||||
#
 | 
			
		||||
#
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_cpanel_info='cPanel Server API
 | 
			
		||||
 Manage DNS via cPanel Dashboard.
 | 
			
		||||
Site: cPanel.net
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_cpanel
 | 
			
		||||
Options:
 | 
			
		||||
 cPanel_Username Username
 | 
			
		||||
 cPanel_Apitoken API Token
 | 
			
		||||
 cPanel_Hostname Server URL. E.g. "https://hostname:port"
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/3732
 | 
			
		||||
Author: Bjarne Saltbaek
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
#
 | 
			
		||||
# Export CPANEL username,api token and hostname in the following variables
 | 
			
		||||
#
 | 
			
		||||
# cPanel_Username=username
 | 
			
		||||
# cPanel_Apitoken=apitoken
 | 
			
		||||
# cPanel_Hostname=hostname
 | 
			
		||||
#
 | 
			
		||||
# Usage: add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
 | 
			
		||||
# Used to add txt record
 | 
			
		||||
dns_cpanel_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
@@ -120,7 +121,7 @@ _myget() {
 | 
			
		||||
 | 
			
		||||
_get_root() {
 | 
			
		||||
  _myget 'json-api/cpanel?cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=ZoneEdit&cpanel_jsonapi_func=fetchzones'
 | 
			
		||||
  _domains=$(echo "$_result" | sed 's/.*\(zones.*\[\).*/\1/' | cut -d':' -f2 | sed 's/"//g' | sed 's/{//g')
 | 
			
		||||
  _domains=$(echo "$_result" | _egrep_o '"[a-z0-9\.\-]*":\["; cPanel first' | cut -d':' -f1 | sed 's/"//g' | sed 's/{//g')
 | 
			
		||||
  _debug "_result is: $_result"
 | 
			
		||||
  _debug "_domains is: $_domains"
 | 
			
		||||
  if [ -z "$_domains" ]; then
 | 
			
		||||
@@ -138,15 +139,15 @@ _get_root() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_successful_update() {
 | 
			
		||||
  if (echo "$_result" | grep -q 'newserial'); then return 0; fi
 | 
			
		||||
  return 1
 | 
			
		||||
  if (echo "$_result" | _egrep_o 'data":\[[^]]*]' | grep -q '"newserial":null'); then return 1; fi
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_findentry() {
 | 
			
		||||
  _debug "In _findentry"
 | 
			
		||||
  #returns id of dns entry, if it exists
 | 
			
		||||
  _myget "json-api/cpanel?cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=ZoneEdit&cpanel_jsonapi_func=fetchzone_records&domain=$_domain"
 | 
			
		||||
  _id=$(echo "$_result" | sed "s/.*\(line.*$fulldomain.*$txtvalue\).*/\1/" | cut -d ':' -f 2 | cut -d ',' -f 1)
 | 
			
		||||
  _id=$(echo "$_result" | sed -e "s/},{/},\n{/g" | grep "$fulldomain" | grep "$txtvalue" | _egrep_o 'line":[0-9]+' | cut -d ':' -f 2)
 | 
			
		||||
  _debug "_result is: $_result"
 | 
			
		||||
  _debug "fulldomain. is $fulldomain."
 | 
			
		||||
  _debug "txtvalue is $txtvalue"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,15 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#Script to use with curanet.dk, scannet.dk, wannafind.dk, dandomain.dk DNS management.
 | 
			
		||||
#Requires api credentials with scope: dns
 | 
			
		||||
#Author: Peter L. Hansen <peter@r12.dk>
 | 
			
		||||
#Version 1.0
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_curanet_info='Curanet.dk
 | 
			
		||||
Domains: scannet.dk wannafind.dk dandomain.dk
 | 
			
		||||
Site: Curanet.dk
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_curanet
 | 
			
		||||
Options:
 | 
			
		||||
 CURANET_AUTHCLIENTID Auth ClientID. Requires scope dns
 | 
			
		||||
 CURANET_AUTHSECRET Auth Secret
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/3933
 | 
			
		||||
Author: Peter L. Hansen <peter@r12.dk>
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
CURANET_REST_URL="https://api.curanet.dk/dns/v1/Domains"
 | 
			
		||||
CURANET_AUTH_URL="https://apiauth.dk.team.blue/auth/realms/Curanet/protocol/openid-connect/token"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,21 +1,15 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
########
 | 
			
		||||
# Custom cyon.ch DNS API for use with [acme.sh](https://github.com/acmesh-official/acme.sh)
 | 
			
		||||
#
 | 
			
		||||
# Usage: acme.sh --issue --dns dns_cyon -d www.domain.com
 | 
			
		||||
#
 | 
			
		||||
# Dependencies:
 | 
			
		||||
# -------------
 | 
			
		||||
# - oathtool (When using 2 Factor Authentication)
 | 
			
		||||
#
 | 
			
		||||
# Issues:
 | 
			
		||||
# -------
 | 
			
		||||
# Any issues / questions / suggestions can be posted here:
 | 
			
		||||
# https://github.com/noplanman/cyon-api/issues
 | 
			
		||||
#
 | 
			
		||||
# Author: Armando Lüscher <armando@noplanman.ch>
 | 
			
		||||
########
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_cyon_info='cyon.ch
 | 
			
		||||
Site: cyon.ch
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_cyon
 | 
			
		||||
Options:
 | 
			
		||||
 CY_Username Username
 | 
			
		||||
 CY_Password API Token
 | 
			
		||||
 CY_OTP_Secret OTP token. Only required if using 2FA
 | 
			
		||||
Issues: github.com/noplanman/cyon-api/issues
 | 
			
		||||
Author: Armando Lüscher <armando@noplanman.ch>
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
dns_cyon_add() {
 | 
			
		||||
  _cyon_load_credentials &&
 | 
			
		||||
@@ -44,7 +38,7 @@ dns_cyon_rm() {
 | 
			
		||||
_cyon_load_credentials() {
 | 
			
		||||
  # Convert loaded password to/from base64 as needed.
 | 
			
		||||
  if [ "${CY_Password_B64}" ]; then
 | 
			
		||||
    CY_Password="$(printf "%s" "${CY_Password_B64}" | _dbase64 "multiline")"
 | 
			
		||||
    CY_Password="$(printf "%s" "${CY_Password_B64}" | _dbase64)"
 | 
			
		||||
  elif [ "${CY_Password}" ]; then
 | 
			
		||||
    CY_Password_B64="$(printf "%s" "${CY_Password}" | _base64)"
 | 
			
		||||
  fi
 | 
			
		||||
 
 | 
			
		||||
@@ -1,31 +1,14 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# -*- mode: sh; tab-width: 2; indent-tabs-mode: s; coding: utf-8 -*-
 | 
			
		||||
# vim: et ts=2 sw=2
 | 
			
		||||
#
 | 
			
		||||
# DirectAdmin 1.41.0 API
 | 
			
		||||
# The DirectAdmin interface has it's own Let's encrypt functionality, but this
 | 
			
		||||
# script can be used to generate certificates for names which are not hosted on
 | 
			
		||||
# DirectAdmin
 | 
			
		||||
#
 | 
			
		||||
# User must provide login data and URL to DirectAdmin incl. port.
 | 
			
		||||
# You can create login key, by using the Login Keys function
 | 
			
		||||
# ( https://da.example.com:8443/CMD_LOGIN_KEYS ), which only has access to
 | 
			
		||||
# - CMD_API_DNS_CONTROL
 | 
			
		||||
# - CMD_API_SHOW_DOMAINS
 | 
			
		||||
#
 | 
			
		||||
# See also https://www.directadmin.com/api.php and
 | 
			
		||||
# https://www.directadmin.com/features.php?id=1298
 | 
			
		||||
#
 | 
			
		||||
# Report bugs to https://github.com/TigerP/acme.sh/issues
 | 
			
		||||
#
 | 
			
		||||
# Values to export:
 | 
			
		||||
# export DA_Api="https://remoteUser:remotePassword@da.example.com:8443"
 | 
			
		||||
# export DA_Api_Insecure=1
 | 
			
		||||
#
 | 
			
		||||
# Set DA_Api_Insecure to 1 for insecure and 0 for secure -> difference is
 | 
			
		||||
# whether ssl cert is checked for validity (0) or whether it is just accepted
 | 
			
		||||
# (1)
 | 
			
		||||
#
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_da_info='DirectAdmin Server API
 | 
			
		||||
Site: DirectAdmin.com/api.php
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_da
 | 
			
		||||
Options:
 | 
			
		||||
 DA_Api API Server URL. E.g. "https://remoteUser:remotePassword@da.domain.tld:8443"
 | 
			
		||||
 DA_Api_Insecure Insecure TLS. 0: check for cert validity, 1: always accept
 | 
			
		||||
Issues: github.com/TigerP/acme.sh/issues
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
# Usage: dns_myapi_add  _acme-challenge.www.example.com  "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +1,13 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#Created by RaidenII, to use DuckDNS's API to add/remove text records
 | 
			
		||||
#modified by helbgd @ 03/13/2018 to support ddnss.de
 | 
			
		||||
#modified by mod242 @ 04/24/2018 to support different ddnss domains
 | 
			
		||||
#Please note: the Wildcard Feature must be turned on for the Host record
 | 
			
		||||
#and the checkbox for TXT needs to be enabled
 | 
			
		||||
 | 
			
		||||
# Pass credentials before "acme.sh --issue --dns dns_ddnss ..."
 | 
			
		||||
# --
 | 
			
		||||
# export DDNSS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
 | 
			
		||||
# --
 | 
			
		||||
#
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_ddnss_info='DDNSS.de
 | 
			
		||||
Site: DDNSS.de
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_ddnss
 | 
			
		||||
Options:
 | 
			
		||||
 DDNSS_Token API Token
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/2230
 | 
			
		||||
Author: RaidenII, helbgd, mod242
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
DDNSS_DNS_API="https://ddnss.de/upd.php"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,13 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
#
 | 
			
		||||
# deSEC.io Domain API
 | 
			
		||||
#
 | 
			
		||||
# Author: Zheng Qian
 | 
			
		||||
#
 | 
			
		||||
# deSEC API doc
 | 
			
		||||
# https://desec.readthedocs.io/en/latest/
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_desec_info='deSEC.io
 | 
			
		||||
Site: desec.readthedocs.io/en/latest/
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_desec
 | 
			
		||||
Options:
 | 
			
		||||
 DDNSS_Token API Token
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/2180
 | 
			
		||||
Author: Zheng Qian
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
REST_API="https://desec.io/api/v1/domains"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,18 +1,15 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
########################################################################
 | 
			
		||||
# https://dyndnsfree.de hook script for acme.sh
 | 
			
		||||
#
 | 
			
		||||
# Environment variables:
 | 
			
		||||
#
 | 
			
		||||
#  - $DF_user      (your dyndnsfree.de username)
 | 
			
		||||
#  - $DF_password  (your dyndnsfree.de password)
 | 
			
		||||
#
 | 
			
		||||
# Author: Thilo Gass <thilo.gass@gmail.com>
 | 
			
		||||
# Git repo: https://github.com/ThiloGa/acme.sh
 | 
			
		||||
 | 
			
		||||
#-- dns_df_add() - Add TXT record --------------------------------------
 | 
			
		||||
# Usage: dns_df_add _acme-challenge.subdomain.domain.com "XyZ123..."
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_df_info='DynDnsFree.de
 | 
			
		||||
Domains: dynup.de
 | 
			
		||||
Site: DynDnsFree.de
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_df
 | 
			
		||||
Options:
 | 
			
		||||
 DF_user Username
 | 
			
		||||
 DF_password Password
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/2897
 | 
			
		||||
Author: Thilo Gass <thilo.gass@gmail.com>
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
dyndnsfree_api="https://dynup.de/acme.php"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +1,12 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
## Will be called by acme.sh to add the txt record to your api system.
 | 
			
		||||
## returns 0 means success, otherwise error.
 | 
			
		||||
 | 
			
		||||
## Author: thewer <github at thewer.com>
 | 
			
		||||
## GitHub: https://github.com/gitwer/acme.sh
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
## Environment Variables Required:
 | 
			
		||||
##
 | 
			
		||||
## DO_API_KEY="75310dc4ca779ac39a19f6355db573b49ce92ae126553ebd61ac3a3ae34834cc"
 | 
			
		||||
##
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_dgon_info='DigitalOcean.com
 | 
			
		||||
Site: DigitalOcean.com/help/api/
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dgon
 | 
			
		||||
Options:
 | 
			
		||||
 DO_API_KEY API Key
 | 
			
		||||
Author: <github@thewer.com>
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
#####################  Public functions  #####################
 | 
			
		||||
 | 
			
		||||
@@ -192,6 +188,7 @@ _get_base_domain() {
 | 
			
		||||
  ## get URL for the list of domains
 | 
			
		||||
  ## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}}
 | 
			
		||||
  DOMURL="https://api.digitalocean.com/v2/domains"
 | 
			
		||||
  found=""
 | 
			
		||||
 | 
			
		||||
  ## while we dont have a matching domain we keep going
 | 
			
		||||
  while [ -z "$found" ]; do
 | 
			
		||||
@@ -205,9 +202,7 @@ _get_base_domain() {
 | 
			
		||||
    fi
 | 
			
		||||
    _debug2 domain_list "$domain_list"
 | 
			
		||||
 | 
			
		||||
    ## for each shortening of our $fulldomain, check if it exists in the $domain_list
 | 
			
		||||
    ## can never start on 1 (aka whole $fulldomain) as $fulldomain starts with "_acme-challenge"
 | 
			
		||||
    i=2
 | 
			
		||||
    i=1
 | 
			
		||||
    while [ $i -gt 0 ]; do
 | 
			
		||||
      ## get next longest domain
 | 
			
		||||
      _domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM")
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										188
									
								
								dnsapi/dns_dnsexit.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										188
									
								
								dnsapi/dns_dnsexit.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,188 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_dnsexit_info='DNSExit.com
 | 
			
		||||
Site: DNSExit.com
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_dnsexit
 | 
			
		||||
Options:
 | 
			
		||||
 DNSEXIT_API_KEY API Key
 | 
			
		||||
 DNSEXIT_AUTH_USER Username
 | 
			
		||||
 DNSEXIT_AUTH_PASS Password
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/4719
 | 
			
		||||
Author: Samuel Jimenez
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
DNSEXIT_API_URL="https://api.dnsexit.com/dns/"
 | 
			
		||||
DNSEXIT_HOSTS_URL="https://update.dnsexit.com/ipupdate/hosts.jsp"
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
#Usage: dns_dnsexit_add   _acme-challenge.*.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_dnsexit_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
  _info "Using DNSExit.com"
 | 
			
		||||
  _debug fulldomain "$fulldomain"
 | 
			
		||||
  _debug txtvalue "$txtvalue"
 | 
			
		||||
 | 
			
		||||
  _debug 'Load account auth'
 | 
			
		||||
  if ! get_account_info; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug 'First detect the root zone'
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug _sub_domain "$_sub_domain"
 | 
			
		||||
  _debug _domain "$_domain"
 | 
			
		||||
 | 
			
		||||
  if ! _dnsexit_rest "{\"domain\":\"$_domain\",\"add\":{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":0,\"overwrite\":false}}"; then
 | 
			
		||||
    _err "$response"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug2 _response "$response"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#Usage: fulldomain txtvalue
 | 
			
		||||
#Remove the txt record after validation.
 | 
			
		||||
dns_dnsexit_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
  _info "Using DNSExit.com"
 | 
			
		||||
  _debug fulldomain "$fulldomain"
 | 
			
		||||
  _debug txtvalue "$txtvalue"
 | 
			
		||||
 | 
			
		||||
  _debug 'Load account auth'
 | 
			
		||||
  if ! get_account_info; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug 'First detect the root zone'
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "$response"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug _sub_domain "$_sub_domain"
 | 
			
		||||
  _debug _domain "$_domain"
 | 
			
		||||
 | 
			
		||||
  if ! _dnsexit_rest "{\"domain\":\"$_domain\",\"delete\":{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\"}}"; then
 | 
			
		||||
    _err "$response"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug2 _response "$response"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
#_acme-challenge.www.domain.com
 | 
			
		||||
#returns
 | 
			
		||||
# _sub_domain=_acme-challenge.www
 | 
			
		||||
# _domain=domain.com
 | 
			
		||||
_get_root() {
 | 
			
		||||
  domain=$1
 | 
			
		||||
  i=1
 | 
			
		||||
  while true; do
 | 
			
		||||
    _domain=$(printf "%s" "$domain" | cut -d . -f $i-100)
 | 
			
		||||
    _debug h "$_domain"
 | 
			
		||||
    if [ -z "$_domain" ]; then
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    _debug login "$DNSEXIT_AUTH_USER"
 | 
			
		||||
    _debug password "$DNSEXIT_AUTH_PASS"
 | 
			
		||||
    _debug domain "$_domain"
 | 
			
		||||
 | 
			
		||||
    _dnsexit_http "login=$DNSEXIT_AUTH_USER&password=$DNSEXIT_AUTH_PASS&domain=$_domain"
 | 
			
		||||
 | 
			
		||||
    if _contains "$response" "0=$_domain"; then
 | 
			
		||||
      _sub_domain="$(echo "$fulldomain" | sed "s/\\.$_domain\$//")"
 | 
			
		||||
      return 0
 | 
			
		||||
    else
 | 
			
		||||
      _debug "Go to next level of $_domain"
 | 
			
		||||
    fi
 | 
			
		||||
    i=$(_math "$i" + 1)
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_dnsexit_rest() {
 | 
			
		||||
  m=POST
 | 
			
		||||
  ep=""
 | 
			
		||||
  data="$1"
 | 
			
		||||
  _debug _dnsexit_rest "$ep"
 | 
			
		||||
  _debug data "$data"
 | 
			
		||||
 | 
			
		||||
  api_key_trimmed=$(echo "$DNSEXIT_API_KEY" | tr -d '"')
 | 
			
		||||
 | 
			
		||||
  export _H1="apikey: $api_key_trimmed"
 | 
			
		||||
  export _H2='Content-Type: application/json'
 | 
			
		||||
 | 
			
		||||
  if [ "$m" != "GET" ]; then
 | 
			
		||||
    _debug data "$data"
 | 
			
		||||
    response="$(_post "$data" "$DNSEXIT_API_URL/$ep" "" "$m")"
 | 
			
		||||
  else
 | 
			
		||||
    response="$(_get "$DNSEXIT_API_URL/$ep")"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "Error $ep"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_dnsexit_http() {
 | 
			
		||||
  m=GET
 | 
			
		||||
  param="$1"
 | 
			
		||||
  _debug param "$param"
 | 
			
		||||
  _debug get "$DNSEXIT_HOSTS_URL?$param"
 | 
			
		||||
 | 
			
		||||
  response="$(_get "$DNSEXIT_HOSTS_URL?$param")"
 | 
			
		||||
 | 
			
		||||
  _debug response "$response"
 | 
			
		||||
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "Error $param"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
get_account_info() {
 | 
			
		||||
 | 
			
		||||
  DNSEXIT_API_KEY="${DNSEXIT_API_KEY:-$(_readaccountconf_mutable DNSEXIT_API_KEY)}"
 | 
			
		||||
  if test -z "$DNSEXIT_API_KEY"; then
 | 
			
		||||
    DNSEXIT_API_KEY=''
 | 
			
		||||
    _err 'DNSEXIT_API_KEY was not exported'
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _saveaccountconf_mutable DNSEXIT_API_KEY "$DNSEXIT_API_KEY"
 | 
			
		||||
 | 
			
		||||
  DNSEXIT_AUTH_USER="${DNSEXIT_AUTH_USER:-$(_readaccountconf_mutable DNSEXIT_AUTH_USER)}"
 | 
			
		||||
  if test -z "$DNSEXIT_AUTH_USER"; then
 | 
			
		||||
    DNSEXIT_AUTH_USER=""
 | 
			
		||||
    _err 'DNSEXIT_AUTH_USER was not exported'
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _saveaccountconf_mutable DNSEXIT_AUTH_USER "$DNSEXIT_AUTH_USER"
 | 
			
		||||
 | 
			
		||||
  DNSEXIT_AUTH_PASS="${DNSEXIT_AUTH_PASS:-$(_readaccountconf_mutable DNSEXIT_AUTH_PASS)}"
 | 
			
		||||
  if test -z "$DNSEXIT_AUTH_PASS"; then
 | 
			
		||||
    DNSEXIT_AUTH_PASS=""
 | 
			
		||||
    _err 'DNSEXIT_AUTH_PASS was not exported'
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _saveaccountconf_mutable DNSEXIT_AUTH_PASS "$DNSEXIT_AUTH_PASS"
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
@@ -1,15 +1,14 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
# dnsHome.de API for acme.sh
 | 
			
		||||
#
 | 
			
		||||
# This Script adds the necessary TXT record to a Subdomain
 | 
			
		||||
#
 | 
			
		||||
# Author dnsHome.de (https://github.com/dnsHome-de)
 | 
			
		||||
#
 | 
			
		||||
# Report Bugs to https://github.com/acmesh-official/acme.sh/issues/3819
 | 
			
		||||
#
 | 
			
		||||
# export DNSHOME_Subdomain=""
 | 
			
		||||
# export DNSHOME_SubdomainPassword=""
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_dnshome_info='dnsHome.de
 | 
			
		||||
Site: dnsHome.de
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_dnshome
 | 
			
		||||
Options:
 | 
			
		||||
 DNSHOME_Subdomain Subdomain
 | 
			
		||||
 DNSHOME_SubdomainPassword Subdomain Password
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/3819
 | 
			
		||||
Author: dnsHome.de https://github.com/dnsHome-de
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
# Usage: add subdomain.ddnsdomain.tld "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
# Used to add txt record
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,12 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
# DNSimple domain api
 | 
			
		||||
# https://github.com/pho3nixf1re/acme.sh/issues
 | 
			
		||||
#
 | 
			
		||||
# This is your oauth token which can be acquired on the account page. Please
 | 
			
		||||
# note that this must be an _account_ token and not a _user_ token.
 | 
			
		||||
# https://dnsimple.com/a/<your account id>/account/access_tokens
 | 
			
		||||
# DNSimple_OAUTH_TOKEN="sdfsdfsdfljlbjkljlkjsdfoiwje"
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_dnsimple_info='DNSimple.com
 | 
			
		||||
Site: DNSimple.com
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dnsimple
 | 
			
		||||
Options:
 | 
			
		||||
 DNSimple_OAUTH_TOKEN OAuth Token
 | 
			
		||||
Issues: github.com/pho3nixf1re/acme.sh/issues
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
DNSimple_API="https://api.dnsimple.com/v2"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										251
									
								
								dnsapi/dns_dnsservices.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										251
									
								
								dnsapi/dns_dnsservices.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,251 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_dnsservices_info='DNS.Services
 | 
			
		||||
Site: DNS.Services
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_dnsservices
 | 
			
		||||
Options:
 | 
			
		||||
 DnsServices_Username Username
 | 
			
		||||
 DnsServices_Password Password
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/4152
 | 
			
		||||
Author: Bjarke Bruun <bbruun@gmail.com>
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
DNSServices_API=https://dns.services/api
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: dns_dnsservices_add  _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_dnsservices_add() {
 | 
			
		||||
  fulldomain="$1"
 | 
			
		||||
  txtvalue="$2"
 | 
			
		||||
 | 
			
		||||
  _info "Using dns.services to create ACME DNS challenge"
 | 
			
		||||
  _debug2 add_fulldomain "$fulldomain"
 | 
			
		||||
  _debug2 add_txtvalue "$txtvalue"
 | 
			
		||||
 | 
			
		||||
  # Read username/password from environment or .acme.sh/accounts.conf
 | 
			
		||||
  DnsServices_Username="${DnsServices_Username:-$(_readaccountconf_mutable DnsServices_Username)}"
 | 
			
		||||
  DnsServices_Password="${DnsServices_Password:-$(_readaccountconf_mutable DnsServices_Password)}"
 | 
			
		||||
  if [ -z "$DnsServices_Username" ] || [ -z "$DnsServices_Password" ]; then
 | 
			
		||||
    DnsServices_Username=""
 | 
			
		||||
    DnsServices_Password=""
 | 
			
		||||
    _err "You didn't specify dns.services api username and password yet."
 | 
			
		||||
    _err "Set environment variables DnsServices_Username and DnsServices_Password"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Setup GET/POST/DELETE headers
 | 
			
		||||
  _setup_headers
 | 
			
		||||
 | 
			
		||||
  #save the credentials to the account conf file.
 | 
			
		||||
  _saveaccountconf_mutable DnsServices_Username "$DnsServices_Username"
 | 
			
		||||
  _saveaccountconf_mutable DnsServices_Password "$DnsServices_Password"
 | 
			
		||||
 | 
			
		||||
  if ! _contains "$DnsServices_Username" "@"; then
 | 
			
		||||
    _err "It seems that the username variable DnsServices_Username has not been set/left blank"
 | 
			
		||||
    _err "or is not a valid email. Please correct and try again."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! _get_root "${fulldomain}"; then
 | 
			
		||||
    _err "Invalid domain ${fulldomain}"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! createRecord "$fulldomain" "${txtvalue}"; then
 | 
			
		||||
    _err "Error creating TXT record in domain $fulldomain in $rootZoneName"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug2 challenge-created "Created $fulldomain"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#Usage: fulldomain txtvalue
 | 
			
		||||
#Description: Remove the txt record after validation.
 | 
			
		||||
dns_dnsservices_rm() {
 | 
			
		||||
  fulldomain="$1"
 | 
			
		||||
  txtvalue="$2"
 | 
			
		||||
 | 
			
		||||
  _info "Using dns.services to remove DNS record $fulldomain TXT $txtvalue"
 | 
			
		||||
  _debug rm_fulldomain "$fulldomain"
 | 
			
		||||
  _debug rm_txtvalue "$txtvalue"
 | 
			
		||||
 | 
			
		||||
  # Read username/password from environment or .acme.sh/accounts.conf
 | 
			
		||||
  DnsServices_Username="${DnsServices_Username:-$(_readaccountconf_mutable DnsServices_Username)}"
 | 
			
		||||
  DnsServices_Password="${DnsServices_Password:-$(_readaccountconf_mutable DnsServices_Password)}"
 | 
			
		||||
  if [ -z "$DnsServices_Username" ] || [ -z "$DnsServices_Password" ]; then
 | 
			
		||||
    DnsServices_Username=""
 | 
			
		||||
    DnsServices_Password=""
 | 
			
		||||
    _err "You didn't specify dns.services api username and password yet."
 | 
			
		||||
    _err "Set environment variables DnsServices_Username and DnsServices_Password"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Setup GET/POST/DELETE headers
 | 
			
		||||
  _setup_headers
 | 
			
		||||
 | 
			
		||||
  if ! _get_root "${fulldomain}"; then
 | 
			
		||||
    _err "Invalid domain ${fulldomain}"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug2 rm_rootDomainInfo "found root domain $rootZoneName for $fulldomain"
 | 
			
		||||
 | 
			
		||||
  if ! deleteRecord "${fulldomain}" "${txtvalue}"; then
 | 
			
		||||
    _err "Error removing record: $fulldomain TXT ${txtvalue}"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
 | 
			
		||||
_setup_headers() {
 | 
			
		||||
  # Set up API Headers for _get() and _post()
 | 
			
		||||
  # The <function>_add or <function>_rm must have been called before to work
 | 
			
		||||
 | 
			
		||||
  if [ -z "$DnsServices_Username" ] || [ -z "$DnsServices_Password" ]; then
 | 
			
		||||
    _err "Could not setup BASIC authentication headers, they are missing"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  DnsServiceCredentials="$(printf "%s" "$DnsServices_Username:$DnsServices_Password" | _base64)"
 | 
			
		||||
  export _H1="Authorization: Basic $DnsServiceCredentials"
 | 
			
		||||
  export _H2="Content-Type: application/json"
 | 
			
		||||
 | 
			
		||||
  # Just return if headers are set
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_get_root() {
 | 
			
		||||
  domain="$1"
 | 
			
		||||
  _debug2 _get_root "Get the root domain of ${domain} for DNS API"
 | 
			
		||||
 | 
			
		||||
  # Setup _get() and _post() headers
 | 
			
		||||
  #_setup_headers
 | 
			
		||||
 | 
			
		||||
  result=$(_H1="$_H1" _H2="$_H2" _get "$DNSServices_API/dns")
 | 
			
		||||
  result2="$(printf "%s\n" "$result" | tr '[' '\n' | grep '"name"')"
 | 
			
		||||
  result3="$(printf "%s\n" "$result2" | tr '}' '\n' | grep '"name"' | sed "s,^\,,,g" | sed "s,$,},g")"
 | 
			
		||||
  useResult=""
 | 
			
		||||
  _debug2 _get_root "Got the following root domain(s) $result"
 | 
			
		||||
  _debug2 _get_root "- JSON: $result"
 | 
			
		||||
 | 
			
		||||
  if [ "$(printf "%s\n" "$result" | tr '}' '\n' | grep -c '"name"')" -gt "1" ]; then
 | 
			
		||||
    checkMultiZones="true"
 | 
			
		||||
    _debug2 _get_root "- multiple zones found"
 | 
			
		||||
  else
 | 
			
		||||
    checkMultiZones="false"
 | 
			
		||||
    _debug2 _get_root "- single zone found"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Find/isolate the root zone to work with in createRecord() and deleteRecord()
 | 
			
		||||
  rootZone=""
 | 
			
		||||
  if [ "$checkMultiZones" = "true" ]; then
 | 
			
		||||
    #rootZone=$(for x in $(printf "%s" "${result3}" | tr ',' '\n' | sed -n 's/.*"name":"\(.*\)",.*/\1/p'); do if [ "$(echo "$domain" | grep "$x")" != "" ]; then echo "$x"; fi; done)
 | 
			
		||||
    rootZone=$(for x in $(printf "%s\n" "${result3}" | tr ',' '\n' | grep name | cut -d'"' -f4); do if [ "$(echo "$domain" | grep "$x")" != "" ]; then echo "$x"; fi; done)
 | 
			
		||||
    if [ "$rootZone" != "" ]; then
 | 
			
		||||
      _debug2 _rootZone "- root zone for $domain is $rootZone"
 | 
			
		||||
    else
 | 
			
		||||
      _err "Could not find root zone for $domain, is it correctly typed?"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    rootZone=$(echo "$result" | tr '}' '\n' | _egrep_o '"name":"[^"]*' | cut -d'"' -f4)
 | 
			
		||||
    _debug2 _get_root "- only found 1 domain in API: $rootZone"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "$rootZone" ]; then
 | 
			
		||||
    _err "Could not find root domain for $domain - is it correctly typed?"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Make sure we use the correct API zone data
 | 
			
		||||
  useResult="$(printf "%s\n" "${result3}" tr ',' '\n' | grep "$rootZone")"
 | 
			
		||||
  _debug2 _useResult "useResult=$useResult"
 | 
			
		||||
 | 
			
		||||
  # Setup variables used by other functions to communicate with DNS.Services API
 | 
			
		||||
  #zoneInfo=$(printf "%s\n" "$useResult" | sed -E 's,.*(zones)(.*),\1\2,g' | sed -E 's,^(.*"name":")([^"]*)"(.*)$,\2,g')
 | 
			
		||||
  zoneInfo=$(printf "%s\n" "$useResult" | tr ',' '\n' | grep '"name"' | cut -d'"' -f4)
 | 
			
		||||
  rootZoneName="$rootZone"
 | 
			
		||||
  subDomainName="$(printf "%s\n" "$domain" | sed "s,\.$rootZone,,g")"
 | 
			
		||||
  subDomainNameClean="$(printf "%s\n" "$domain" | sed "s,_acme-challenge.,,g")"
 | 
			
		||||
  rootZoneDomainID=$(printf "%s\n" "$useResult" | tr ',' '\n' | grep domain_id | cut -d'"' -f4)
 | 
			
		||||
  rootZoneServiceID=$(printf "%s\n" "$useResult" | tr ',' '\n' | grep service_id | cut -d'"' -f4)
 | 
			
		||||
 | 
			
		||||
  _debug2 _zoneInfo "Zone info from API  : $zoneInfo"
 | 
			
		||||
  _debug2 _get_root "Root zone name      : $rootZoneName"
 | 
			
		||||
  _debug2 _get_root "Root zone domain ID : $rootZoneDomainID"
 | 
			
		||||
  _debug2 _get_root "Root zone service ID: $rootZoneServiceID"
 | 
			
		||||
  _debug2 _get_root "Sub domain          : $subDomainName"
 | 
			
		||||
 | 
			
		||||
  _debug _get_root "Found valid root domain $rootZone for $subDomainNameClean"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
createRecord() {
 | 
			
		||||
  fulldomain="$1"
 | 
			
		||||
  txtvalue="$2"
 | 
			
		||||
 | 
			
		||||
  # Get root domain information - needed for DNS.Services API communication
 | 
			
		||||
  if [ -z "$rootZoneName" ] || [ -z "$rootZoneDomainID" ] || [ -z "$rootZoneServiceID" ]; then
 | 
			
		||||
    _get_root "$fulldomain"
 | 
			
		||||
  fi
 | 
			
		||||
  if [ -z "$rootZoneName" ] || [ -z "$rootZoneDomainID" ] || [ -z "$rootZoneServiceID" ]; then
 | 
			
		||||
    _err "Something happend - could not get the API zone information"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug2 createRecord "CNAME TXT value is: $txtvalue"
 | 
			
		||||
 | 
			
		||||
  # Prepare data to send to API
 | 
			
		||||
  data="{\"name\":\"${fulldomain}\",\"type\":\"TXT\",\"content\":\"${txtvalue}\", \"ttl\":\"10\"}"
 | 
			
		||||
 | 
			
		||||
  _debug2 createRecord "data to API: $data"
 | 
			
		||||
  result=$(_post "$data" "$DNSServices_API/service/$rootZoneServiceID/dns/$rootZoneDomainID/records" "" "POST")
 | 
			
		||||
  _debug2 createRecord "result from API: $result"
 | 
			
		||||
 | 
			
		||||
  if [ "$(echo "$result" | _egrep_o "\"success\":true")" = "" ]; then
 | 
			
		||||
    _err "Failed to create TXT record $fulldomain with content $txtvalue in zone $rootZoneName"
 | 
			
		||||
    _err "$result"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Record \"$fulldomain TXT $txtvalue\" has been created"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
deleteRecord() {
 | 
			
		||||
  fulldomain="$1"
 | 
			
		||||
  txtvalue="$2"
 | 
			
		||||
 | 
			
		||||
  _log deleteRecord "Deleting $fulldomain TXT $txtvalue record"
 | 
			
		||||
 | 
			
		||||
  if [ -z "$rootZoneName" ] || [ -z "$rootZoneDomainID" ] || [ -z "$rootZoneServiceID" ]; then
 | 
			
		||||
    _get_root "$fulldomain"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  result="$(_H1="$_H1" _H2="$_H2" _get "$DNSServices_API/service/$rootZoneServiceID/dns/$rootZoneDomainID")"
 | 
			
		||||
  #recordInfo="$(echo "$result" | sed -e 's/:{/:{\n/g' -e 's/},/\n},\n/g' | grep "${txtvalue}")"
 | 
			
		||||
  #recordID="$(echo "$recordInfo" | sed -e 's/:{/:{\n/g' -e 's/},/\n},\n/g' | grep "${txtvalue}" | sed -E 's,.*(zones)(.*),\1\2,g' | sed -E 's,^(.*"id":")([^"]*)"(.*)$,\2,g')"
 | 
			
		||||
  recordID="$(printf "%s\n" "$result" | tr '}' '\n' | grep -- "$txtvalue" | tr ',' '\n' | grep '"id"' | cut -d'"' -f4)"
 | 
			
		||||
  _debug2 _recordID "recordID used for deletion of record: $recordID"
 | 
			
		||||
 | 
			
		||||
  if [ -z "$recordID" ]; then
 | 
			
		||||
    _info "Record $fulldomain TXT $txtvalue not found or already deleted"
 | 
			
		||||
    return 0
 | 
			
		||||
  else
 | 
			
		||||
    _debug2 deleteRecord "Found recordID=$recordID"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug2 deleteRecord "DELETE request $DNSServices_API/service/$rootZoneServiceID/dns/$rootZoneDomainID/records/$recordID"
 | 
			
		||||
  _log "curl DELETE request $DNSServices_API/service/$rootZoneServiceID/dns/$rootZoneDomainID/records/$recordID"
 | 
			
		||||
  result="$(_H1="$_H1" _H2="$_H2" _post "" "$DNSServices_API/service/$rootZoneServiceID/dns/$rootZoneDomainID/records/$recordID" "" "DELETE")"
 | 
			
		||||
  _debug2 deleteRecord "API Delete result \"$result\""
 | 
			
		||||
  _log "curl API Delete result \"$result\""
 | 
			
		||||
 | 
			
		||||
  # Return OK regardless
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										148
									
								
								dnsapi/dns_do.sh
									
									
									
									
									
								
							
							
						
						
									
										148
									
								
								dnsapi/dns_do.sh
									
									
									
									
									
								
							@@ -1,148 +0,0 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
# DNS API for Domain-Offensive / Resellerinterface / Domainrobot
 | 
			
		||||
 | 
			
		||||
# Report bugs at https://github.com/seidler2547/acme.sh/issues
 | 
			
		||||
 | 
			
		||||
# set these environment variables to match your customer ID and password:
 | 
			
		||||
# DO_PID="KD-1234567"
 | 
			
		||||
# DO_PW="cdfkjl3n2"
 | 
			
		||||
 | 
			
		||||
DO_URL="https://soap.resellerinterface.de/"
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: dns_myapi_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_do_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
  if _dns_do_authenticate; then
 | 
			
		||||
    _info "Adding TXT record to ${_domain} as ${fulldomain}"
 | 
			
		||||
    _dns_do_soap createRR origin "${_domain}" name "${fulldomain}" type TXT data "${txtvalue}" ttl 300
 | 
			
		||||
    if _contains "${response}" '>success<'; then
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
    _err "Could not create resource record, check logs"
 | 
			
		||||
  fi
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#fulldomain
 | 
			
		||||
dns_do_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  if _dns_do_authenticate; then
 | 
			
		||||
    if _dns_do_list_rrs; then
 | 
			
		||||
      _dns_do_had_error=0
 | 
			
		||||
      for _rrid in ${_rr_list}; do
 | 
			
		||||
        _info "Deleting resource record $_rrid for $_domain"
 | 
			
		||||
        _dns_do_soap deleteRR origin "${_domain}" rrid "${_rrid}"
 | 
			
		||||
        if ! _contains "${response}" '>success<'; then
 | 
			
		||||
          _dns_do_had_error=1
 | 
			
		||||
          _err "Could not delete resource record for ${_domain}, id ${_rrid}"
 | 
			
		||||
        fi
 | 
			
		||||
      done
 | 
			
		||||
      return $_dns_do_had_error
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
_dns_do_authenticate() {
 | 
			
		||||
  _info "Authenticating as ${DO_PID}"
 | 
			
		||||
  _dns_do_soap authPartner partner "${DO_PID}" password "${DO_PW}"
 | 
			
		||||
  if _contains "${response}" '>success<'; then
 | 
			
		||||
    _get_root "$fulldomain"
 | 
			
		||||
    _debug "_domain $_domain"
 | 
			
		||||
    return 0
 | 
			
		||||
  else
 | 
			
		||||
    _err "Authentication failed, are DO_PID and DO_PW set correctly?"
 | 
			
		||||
  fi
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_dns_do_list_rrs() {
 | 
			
		||||
  _dns_do_soap getRRList origin "${_domain}"
 | 
			
		||||
  if ! _contains "${response}" 'SOAP-ENC:Array'; then
 | 
			
		||||
    _err "getRRList origin ${_domain} failed"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _rr_list="$(echo "${response}" |
 | 
			
		||||
    tr -d "\n\r\t" |
 | 
			
		||||
    sed -e 's/<item xsi:type="ns2:Map">/\n/g' |
 | 
			
		||||
    grep ">$(_regexcape "$fulldomain")</value>" |
 | 
			
		||||
    sed -e 's/<\/item>/\n/g' |
 | 
			
		||||
    grep '>id</key><value' |
 | 
			
		||||
    _egrep_o '>[0-9]{1,16}<' |
 | 
			
		||||
    tr -d '><')"
 | 
			
		||||
  [ "${_rr_list}" ]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_dns_do_soap() {
 | 
			
		||||
  func="$1"
 | 
			
		||||
  shift
 | 
			
		||||
  # put the parameters to xml
 | 
			
		||||
  body="<tns:${func} xmlns:tns=\"${DO_URL}\">"
 | 
			
		||||
  while [ "$1" ]; do
 | 
			
		||||
    _k="$1"
 | 
			
		||||
    shift
 | 
			
		||||
    _v="$1"
 | 
			
		||||
    shift
 | 
			
		||||
    body="$body<$_k>$_v</$_k>"
 | 
			
		||||
  done
 | 
			
		||||
  body="$body</tns:${func}>"
 | 
			
		||||
  _debug2 "SOAP request ${body}"
 | 
			
		||||
 | 
			
		||||
  # build SOAP XML
 | 
			
		||||
  _xml='<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
 | 
			
		||||
  <env:Body>'"$body"'</env:Body>
 | 
			
		||||
</env:Envelope>'
 | 
			
		||||
 | 
			
		||||
  # set SOAP headers
 | 
			
		||||
  export _H1="SOAPAction: ${DO_URL}#${func}"
 | 
			
		||||
 | 
			
		||||
  if ! response="$(_post "${_xml}" "${DO_URL}")"; then
 | 
			
		||||
    _err "Error <$1>"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 "SOAP response $response"
 | 
			
		||||
 | 
			
		||||
  # retrieve cookie header
 | 
			
		||||
  _H2="$(_egrep_o 'Cookie: [^;]+' <"$HTTP_HEADER" | _head_n 1)"
 | 
			
		||||
  export _H2
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_get_root() {
 | 
			
		||||
  domain=$1
 | 
			
		||||
  i=1
 | 
			
		||||
 | 
			
		||||
  _dns_do_soap getDomainList
 | 
			
		||||
  _all_domains="$(echo "${response}" |
 | 
			
		||||
    tr -d "\n\r\t " |
 | 
			
		||||
    _egrep_o 'domain</key><value[^>]+>[^<]+' |
 | 
			
		||||
    sed -e 's/^domain<\/key><value[^>]*>//g')"
 | 
			
		||||
 | 
			
		||||
  while true; do
 | 
			
		||||
    h=$(printf "%s" "$domain" | cut -d . -f $i-100)
 | 
			
		||||
    if [ -z "$h" ]; then
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if _contains "${_all_domains}" "^$(_regexcape "$h")\$"; then
 | 
			
		||||
      _domain="$h"
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    i=$(_math $i + 1)
 | 
			
		||||
  done
 | 
			
		||||
  _debug "$domain not found"
 | 
			
		||||
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_regexcape() {
 | 
			
		||||
  echo "$1" | sed -e 's/\([]\.$*^[]\)/\\\1/g'
 | 
			
		||||
}
 | 
			
		||||
@@ -1,12 +1,15 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
# Official Let's Encrypt API for do.de / Domain-Offensive
 | 
			
		||||
#
 | 
			
		||||
# This is different from the dns_do adapter, because dns_do is only usable for enterprise customers
 | 
			
		||||
# This API is also available to private customers/individuals
 | 
			
		||||
#
 | 
			
		||||
# Provide the required LetsEncrypt token like this:
 | 
			
		||||
# DO_LETOKEN="FmD408PdqT1E269gUK57"
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_doapi_info='Domain-Offensive do.de
 | 
			
		||||
 Official LetsEncrypt API for do.de / Domain-Offensive.
 | 
			
		||||
 This is different from the dns_do adapter, because dns_do is only usable for enterprise customers.
 | 
			
		||||
 This API is also available to private customers/individuals.
 | 
			
		||||
Site: do.de
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_doapi
 | 
			
		||||
Options:
 | 
			
		||||
 DO_LETOKEN LetsEncrypt Token
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/2057
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
DO_API="https://www.do.de/api/letsencrypt"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,13 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_domeneshop_info='DomeneShop.no
 | 
			
		||||
Site: DomeneShop.no
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_domeneshop
 | 
			
		||||
Options:
 | 
			
		||||
 DOMENESHOP_Token Token
 | 
			
		||||
 DOMENESHOP_Secret Secret
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/2457
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
DOMENESHOP_Api_Endpoint="https://api.domeneshop.no/v0"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,12 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
# Dnspod.cn Domain api
 | 
			
		||||
#
 | 
			
		||||
#DP_Id="1234"
 | 
			
		||||
#
 | 
			
		||||
#DP_Key="sADDsdasdgdsf"
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_dp_info='DNSPod.cn
 | 
			
		||||
Site: DNSPod.cn
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dp
 | 
			
		||||
Options:
 | 
			
		||||
 DP_Id Id
 | 
			
		||||
 DP_Key Key
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
REST_API="https://dnsapi.cn"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,12 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
# Dnspod.com Domain api
 | 
			
		||||
#
 | 
			
		||||
#DPI_Id="1234"
 | 
			
		||||
#
 | 
			
		||||
#DPI_Key="sADDsdasdgdsf"
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_dpi_info='DNSPod.com
 | 
			
		||||
Site: DNSPod.com
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dpi
 | 
			
		||||
Options:
 | 
			
		||||
 DPI_Id Id
 | 
			
		||||
 DPI_Key Key
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
REST_API="https://api.dnspod.com"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,14 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_dreamhost_info='DreamHost.com
 | 
			
		||||
Site: DreamHost.com
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dreamhost
 | 
			
		||||
Options:
 | 
			
		||||
 DH_API_KEY API Key
 | 
			
		||||
Issues: github.com/RhinoLance/acme.sh
 | 
			
		||||
Author: RhinoLance
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
#Author: RhinoLance
 | 
			
		||||
#Report Bugs here: https://github.com/RhinoLance/acme.sh
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
#define the api endpoint
 | 
			
		||||
DH_API_ENDPOINT="https://api.dreamhost.com/"
 | 
			
		||||
querystring=""
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,12 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#Created by RaidenII, to use DuckDNS's API to add/remove text records
 | 
			
		||||
#06/27/2017
 | 
			
		||||
 | 
			
		||||
# Pass credentials before "acme.sh --issue --dns dns_duckdns ..."
 | 
			
		||||
# --
 | 
			
		||||
# export DuckDNS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
 | 
			
		||||
# --
 | 
			
		||||
#
 | 
			
		||||
# Due to the fact that DuckDNS uses StartSSL as cert provider, --insecure may need to be used with acme.sh
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_duckdns_info='DuckDNS.org
 | 
			
		||||
Site: www.DuckDNS.org
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_duckdns
 | 
			
		||||
Options:
 | 
			
		||||
 DuckDNS_Token API Token
 | 
			
		||||
Author: RaidenII
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
DuckDNS_API="https://www.duckdns.org/update"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,13 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#DD_API_User="xxxxx"
 | 
			
		||||
#DD_API_Key="xxxxxx"
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_durabledns_info='DurableDNS.com
 | 
			
		||||
Site: DurableDNS.com
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_durabledns
 | 
			
		||||
Options:
 | 
			
		||||
 DD_API_User API User
 | 
			
		||||
 DD_API_Key API Key
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/2281
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
_DD_BASE="https://durabledns.com/services/dns"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,16 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
#
 | 
			
		||||
# Dyn.com Domain API
 | 
			
		||||
#
 | 
			
		||||
# Author: Gerd Naschenweng
 | 
			
		||||
# https://github.com/magicdude4eva
 | 
			
		||||
#
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_dyn_info='Dyn.com
 | 
			
		||||
Domains: dynect.net
 | 
			
		||||
Site: Dyn.com
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dyn
 | 
			
		||||
Options:
 | 
			
		||||
 DYN_Customer Customer
 | 
			
		||||
 DYN_Username API Username
 | 
			
		||||
 DYN_Password Secret
 | 
			
		||||
Author: Gerd Naschenweng <https://github.com/magicdude4eva>
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
# Dyn Managed DNS API
 | 
			
		||||
# https://help.dyn.com/dns-api-knowledge-base/
 | 
			
		||||
#
 | 
			
		||||
@@ -20,13 +26,6 @@
 | 
			
		||||
# ZoneRemoveNode
 | 
			
		||||
# ZonePublish
 | 
			
		||||
# --
 | 
			
		||||
#
 | 
			
		||||
# Pass credentials before "acme.sh --issue --dns dns_dyn ..."
 | 
			
		||||
# --
 | 
			
		||||
# export DYN_Customer="customer"
 | 
			
		||||
# export DYN_Username="apiuser"
 | 
			
		||||
# export DYN_Password="secret"
 | 
			
		||||
# --
 | 
			
		||||
 | 
			
		||||
DYN_API="https://api.dynect.net/REST"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,20 +1,21 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_dynu_info='Dynu.com
 | 
			
		||||
Site: Dynu.com
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dynu
 | 
			
		||||
Options:
 | 
			
		||||
 Dynu_ClientId Client ID
 | 
			
		||||
 Dynu_Secret Secret
 | 
			
		||||
Issues: github.com/shar0119/acme.sh
 | 
			
		||||
Author: Dynu Systems Inc
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
#Client ID
 | 
			
		||||
#Dynu_ClientId="0b71cae7-a099-4f6b-8ddf-94571cdb760d"
 | 
			
		||||
#
 | 
			
		||||
#Secret
 | 
			
		||||
#Dynu_Secret="aCUEY4BDCV45KI8CSIC3sp2LKQ9"
 | 
			
		||||
#
 | 
			
		||||
#Token
 | 
			
		||||
Dynu_Token=""
 | 
			
		||||
#
 | 
			
		||||
#Endpoint
 | 
			
		||||
Dynu_EndPoint="https://api.dynu.com/v2"
 | 
			
		||||
#
 | 
			
		||||
#Author: Dynu Systems, Inc.
 | 
			
		||||
#Report Bugs here: https://github.com/shar0119/acme.sh
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +1,23 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
#Author StefanAbl
 | 
			
		||||
#Usage specify a private keyfile to use with dynv6 'export KEY="path/to/keyfile"'
 | 
			
		||||
#or use the HTTP REST API by by specifying a token 'export DYNV6_TOKEN="value"
 | 
			
		||||
#if no keyfile is specified, you will be asked if you want to create one in /home/$USER/.ssh/dynv6 and /home/$USER/.ssh/dynv6.pub
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_dynv6_info='DynV6.com
 | 
			
		||||
Site: DynV6.com
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_dynv6
 | 
			
		||||
Options:
 | 
			
		||||
 DYNV6_TOKEN REST API token. Get from https://DynV6.com/keys
 | 
			
		||||
OptionsAlt:
 | 
			
		||||
 KEY Path to SSH private key file. E.g. "/root/.ssh/dynv6"
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/2702
 | 
			
		||||
Author: StefanAbl
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
dynv6_api="https://dynv6.com/api/v2"
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
# Please Read this guide first: https://github.com/Neilpang/acme.sh/wiki/DNS-API-Dev-Guide
 | 
			
		||||
#Usage: dns_dynv6_add  _acme-challenge.www.domain.com  "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_dynv6_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
  fulldomain="$(echo "$1" | _lower_case)"
 | 
			
		||||
  txtvalue="$2"
 | 
			
		||||
  _info "Using dynv6 api"
 | 
			
		||||
  _debug fulldomain "$fulldomain"
 | 
			
		||||
  _debug txtvalue "$txtvalue"
 | 
			
		||||
@@ -43,8 +50,8 @@ dns_dynv6_add() {
 | 
			
		||||
#Usage: fulldomain txtvalue
 | 
			
		||||
#Remove the txt record after validation.
 | 
			
		||||
dns_dynv6_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
  fulldomain="$(echo "$1" | _lower_case)"
 | 
			
		||||
  txtvalue="$2"
 | 
			
		||||
  _info "Using dynv6 API"
 | 
			
		||||
  _debug fulldomain "$fulldomain"
 | 
			
		||||
  _debug txtvalue "$txtvalue"
 | 
			
		||||
@@ -94,8 +101,8 @@ _get_domain() {
 | 
			
		||||
  _your_hosts="$(echo "$_your_hosts" | awk '/\./ {print $1}')"
 | 
			
		||||
  for l in $_your_hosts; do
 | 
			
		||||
    #echo "host: $l"
 | 
			
		||||
    if test "${_full_domain#*$l}" != "$_full_domain"; then
 | 
			
		||||
      _record="${_full_domain%.$l}"
 | 
			
		||||
    if test "${_full_domain#*"$l"}" != "$_full_domain"; then
 | 
			
		||||
      _record=${_full_domain%."$l"}
 | 
			
		||||
      _host=$l
 | 
			
		||||
      _debug "The host is $_host and the record $_record"
 | 
			
		||||
      return 0
 | 
			
		||||
@@ -143,7 +150,7 @@ _dns_dynv6_add_http() {
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _get_zone_name "$_zone_id"
 | 
			
		||||
  record="${fulldomain%%.$_zone_name}"
 | 
			
		||||
  record=${fulldomain%%."$_zone_name"}
 | 
			
		||||
  _set_record TXT "$record" "$txtvalue"
 | 
			
		||||
  if _contains "$response" "$txtvalue"; then
 | 
			
		||||
    _info "Successfully added record"
 | 
			
		||||
@@ -161,7 +168,7 @@ _dns_dynv6_rm_http() {
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _get_zone_name "$_zone_id"
 | 
			
		||||
  record="${fulldomain%%.$_zone_name}"
 | 
			
		||||
  record=${fulldomain%%."$_zone_name"}
 | 
			
		||||
  _get_record_id "$_zone_id" "$record" "$txtvalue"
 | 
			
		||||
  _del_record "$_zone_id" "$_record_id"
 | 
			
		||||
  if [ -z "$response" ]; then
 | 
			
		||||
@@ -199,7 +206,7 @@ _get_zone_id() {
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  zone_id="$(echo "$response" | tr '}' '\n' | grep "$selected" | tr ',' '\n' | grep id | tr -d '"')"
 | 
			
		||||
  zone_id="$(echo "$response" | tr '}' '\n' | grep "$selected" | tr ',' '\n' | grep '"id":' | tr -d '"')"
 | 
			
		||||
  _zone_id="${zone_id#id:}"
 | 
			
		||||
  _debug "zone id: $_zone_id"
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,17 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_easydns_info='easyDNS.net
 | 
			
		||||
Site: easyDNS.net
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_easydns
 | 
			
		||||
Options:
 | 
			
		||||
 EASYDNS_Token API Token
 | 
			
		||||
 EASYDNS_Key API Key
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/2647
 | 
			
		||||
Author: Neilpang, wurzelpanzer <wurzelpanzer@maximolider.net>
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
#######################################################
 | 
			
		||||
#
 | 
			
		||||
# easyDNS REST API for acme.sh by Neilpang based on dns_cf.sh
 | 
			
		||||
#
 | 
			
		||||
# API Documentation: https://sandbox.rest.easydns.net:3001/
 | 
			
		||||
#
 | 
			
		||||
# Author: wurzelpanzer [wurzelpanzer@maximolider.net]
 | 
			
		||||
# Report Bugs here: https://github.com/acmesh-official/acme.sh/issues/2647
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
####################  Public functions #################
 | 
			
		||||
 | 
			
		||||
#EASYDNS_Key="xxxxxxxxxxxxxxxxxxxxxxxx"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,15 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_edgedns_info='Akamai.com Edge DNS
 | 
			
		||||
Site: techdocs.Akamai.com/edge-dns/reference/edge-dns-api
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_edgedns
 | 
			
		||||
Options: Specify individual credentials
 | 
			
		||||
 AKAMAI_HOST Host
 | 
			
		||||
 AKAMAI_ACCESS_TOKEN Access token
 | 
			
		||||
 AKAMAI_CLIENT_TOKEN Client token
 | 
			
		||||
 AKAMAI_CLIENT_SECRET Client secret
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/3157
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
# Akamai Edge DNS v2  API
 | 
			
		||||
# User must provide Open Edgegrid API credentials to the EdgeDNS installation. The remote user in EdgeDNS must have CRUD access to
 | 
			
		||||
@@ -6,18 +17,10 @@
 | 
			
		||||
 | 
			
		||||
# Report bugs to https://control.akamai.com/apps/support-ui/#/contact-support
 | 
			
		||||
 | 
			
		||||
# Values to export:
 | 
			
		||||
# --EITHER--
 | 
			
		||||
# *** TBD. NOT IMPLEMENTED YET ***
 | 
			
		||||
# specify Edgegrid credentials file and section
 | 
			
		||||
# AKAMAI_EDGERC=<full file path>
 | 
			
		||||
# AKAMAI_EDGERC_SECTION="default"
 | 
			
		||||
## --OR--
 | 
			
		||||
# specify indiviual credentials
 | 
			
		||||
# export AKAMAI_HOST = <host>
 | 
			
		||||
# export AKAMAI_ACCESS_TOKEN = <access token>
 | 
			
		||||
# export AKAMAI_CLIENT_TOKEN = <client token>
 | 
			
		||||
# export AKAMAI_CLIENT_SECRET = <client secret>
 | 
			
		||||
# Specify Edgegrid credentials file and section.
 | 
			
		||||
# AKAMAI_EDGERC Edge RC. Full file path
 | 
			
		||||
# AKAMAI_EDGERC_SECTION Edge RC Section. E.g. "default"
 | 
			
		||||
 | 
			
		||||
ACME_EDGEDNS_VERSION="0.1.0"
 | 
			
		||||
 | 
			
		||||
@@ -176,6 +179,7 @@ _EDGEDNS_credentials() {
 | 
			
		||||
  _debug "GettingEdge DNS credentials"
 | 
			
		||||
  _log "$(printf "ACME DNSAPI Edge DNS version %s" ${ACME_EDGEDNS_VERSION})"
 | 
			
		||||
  args_missing=0
 | 
			
		||||
  AKAMAI_ACCESS_TOKEN="${AKAMAI_ACCESS_TOKEN:-$(_readaccountconf_mutable AKAMAI_ACCESS_TOKEN)}"
 | 
			
		||||
  if [ -z "$AKAMAI_ACCESS_TOKEN" ]; then
 | 
			
		||||
    AKAMAI_ACCESS_TOKEN=""
 | 
			
		||||
    AKAMAI_CLIENT_TOKEN=""
 | 
			
		||||
@@ -184,6 +188,7 @@ _EDGEDNS_credentials() {
 | 
			
		||||
    _err "AKAMAI_ACCESS_TOKEN is missing"
 | 
			
		||||
    args_missing=1
 | 
			
		||||
  fi
 | 
			
		||||
  AKAMAI_CLIENT_TOKEN="${AKAMAI_CLIENT_TOKEN:-$(_readaccountconf_mutable AKAMAI_CLIENT_TOKEN)}"
 | 
			
		||||
  if [ -z "$AKAMAI_CLIENT_TOKEN" ]; then
 | 
			
		||||
    AKAMAI_ACCESS_TOKEN=""
 | 
			
		||||
    AKAMAI_CLIENT_TOKEN=""
 | 
			
		||||
@@ -192,6 +197,7 @@ _EDGEDNS_credentials() {
 | 
			
		||||
    _err "AKAMAI_CLIENT_TOKEN is missing"
 | 
			
		||||
    args_missing=1
 | 
			
		||||
  fi
 | 
			
		||||
  AKAMAI_HOST="${AKAMAI_HOST:-$(_readaccountconf_mutable AKAMAI_HOST)}"
 | 
			
		||||
  if [ -z "$AKAMAI_HOST" ]; then
 | 
			
		||||
    AKAMAI_ACCESS_TOKEN=""
 | 
			
		||||
    AKAMAI_CLIENT_TOKEN=""
 | 
			
		||||
@@ -200,6 +206,7 @@ _EDGEDNS_credentials() {
 | 
			
		||||
    _err "AKAMAI_HOST is missing"
 | 
			
		||||
    args_missing=1
 | 
			
		||||
  fi
 | 
			
		||||
  AKAMAI_CLIENT_SECRET="${AKAMAI_CLIENT_SECRET:-$(_readaccountconf_mutable AKAMAI_CLIENT_SECRET)}"
 | 
			
		||||
  if [ -z "$AKAMAI_CLIENT_SECRET" ]; then
 | 
			
		||||
    AKAMAI_ACCESS_TOKEN=""
 | 
			
		||||
    AKAMAI_CLIENT_TOKEN=""
 | 
			
		||||
@@ -414,7 +421,7 @@ _edgedns_make_data_to_sign() {
 | 
			
		||||
  _secure_debug2 "hdr" "$hdr"
 | 
			
		||||
  _edgedns_make_content_hash
 | 
			
		||||
  path="$(echo "$_request_url_path" | tr -d "\n\r" | sed 's/https\?:\/\///')"
 | 
			
		||||
  path="${path#*$AKAMAI_HOST}"
 | 
			
		||||
  path=${path#*"$AKAMAI_HOST"}
 | 
			
		||||
  _debug "hier path" "$path"
 | 
			
		||||
  # dont expose headers to sign so use MT string
 | 
			
		||||
  _mdata="$(printf "%s\thttps\t%s\t%s\t%s\t%s\t%s" "$_request_method" "$AKAMAI_HOST" "$path" "" "$_hash" "$hdr")"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,18 +1,14 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#This is the euserv.eu api wrapper for acme.sh
 | 
			
		||||
#
 | 
			
		||||
#Author: Michael Brueckner
 | 
			
		||||
#Report Bugs: https://www.github.com/initit/acme.sh  or  mbr@initit.de
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
#EUSERV_Username="username"
 | 
			
		||||
#
 | 
			
		||||
#EUSERV_Password="password"
 | 
			
		||||
#
 | 
			
		||||
# Dependencies:
 | 
			
		||||
# -------------
 | 
			
		||||
# - none -
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_euserv_info='EUserv.com
 | 
			
		||||
Domains: EUserv.eu
 | 
			
		||||
Site: EUserv.com
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_euserv
 | 
			
		||||
Options:
 | 
			
		||||
 EUSERV_Username Username
 | 
			
		||||
 EUSERV_Password Password
 | 
			
		||||
Author: Michael Brueckner
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
EUSERV_Api="https://api.euserv.net"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,12 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_exoscale_info='Exoscale.com
 | 
			
		||||
Site: Exoscale.com
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_exoscale
 | 
			
		||||
Options:
 | 
			
		||||
 EXOSCALE_API_KEY API Key
 | 
			
		||||
 EXOSCALE_SECRET_KEY API Secret key
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
EXOSCALE_API=https://api.exoscale.com/dns/v1
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,13 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#Author: Timur Umarov <inbox@tumarov.com>
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_fornex_info='Fornex.com
 | 
			
		||||
Site: Fornex.com
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_fornex
 | 
			
		||||
Options:
 | 
			
		||||
 FORNEX_API_KEY API Key
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/3998
 | 
			
		||||
Author: Timur Umarov <inbox@tumarov.com>
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
FORNEX_API_URL="https://fornex.com/api/dns/v0.1"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,15 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_freedns_info='FreeDNS
 | 
			
		||||
Site: FreeDNS.afraid.org
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_freedns
 | 
			
		||||
Options:
 | 
			
		||||
 FREEDNS_User Username
 | 
			
		||||
 FREEDNS_Password Password
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/2305
 | 
			
		||||
Author: David Kerr <https://github.com/dkerr64>
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
#This file name is "dns_freedns.sh"
 | 
			
		||||
#So, here must be a method dns_freedns_add()
 | 
			
		||||
#Which will be called by acme.sh to add the txt record to your api system.
 | 
			
		||||
#returns 0 means success, otherwise error.
 | 
			
		||||
#
 | 
			
		||||
#Author: David Kerr
 | 
			
		||||
#Report Bugs here: https://github.com/dkerr64/acme.sh
 | 
			
		||||
#or here... https://github.com/acmesh-official/acme.sh/issues/2305
 | 
			
		||||
#
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
# Export FreeDNS userid and password in following variables...
 | 
			
		||||
 
 | 
			
		||||
@@ -1,31 +1,42 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_gandi_livedns_info='Gandi.net LiveDNS
 | 
			
		||||
Site: Gandi.net/domain/dns
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_gandi_livedns
 | 
			
		||||
Options:
 | 
			
		||||
 GANDI_LIVEDNS_KEY API Key
 | 
			
		||||
Issues: github.com/fcrozat/acme.sh
 | 
			
		||||
Author: Frédéric Crozat <fcrozat@suse.com>, Dominik Röttsches <drott@google.com>
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
# Gandi LiveDNS v5 API
 | 
			
		||||
# http://doc.livedns.gandi.net/
 | 
			
		||||
# https://api.gandi.net/docs/livedns/
 | 
			
		||||
# https://api.gandi.net/docs/authentication/ for token + apikey (deprecated) authentication
 | 
			
		||||
# currently under beta
 | 
			
		||||
#
 | 
			
		||||
# Requires GANDI API KEY set in GANDI_LIVEDNS_KEY set as environment variable
 | 
			
		||||
#
 | 
			
		||||
#Author: Frédéric Crozat <fcrozat@suse.com>
 | 
			
		||||
#        Dominik Röttsches <drott@google.com>
 | 
			
		||||
#Report Bugs here: https://github.com/fcrozat/acme.sh
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
GANDI_LIVEDNS_API="https://dns.api.gandi.net/api/v5"
 | 
			
		||||
GANDI_LIVEDNS_API="https://api.gandi.net/v5/livedns"
 | 
			
		||||
 | 
			
		||||
#Usage: dns_gandi_livedns_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_gandi_livedns_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  if [ -z "$GANDI_LIVEDNS_KEY" ]; then
 | 
			
		||||
    _err "No API key specified for Gandi LiveDNS."
 | 
			
		||||
    _err "Create your key and export it as GANDI_LIVEDNS_KEY"
 | 
			
		||||
  if [ -z "$GANDI_LIVEDNS_KEY" ] && [ -z "$GANDI_LIVEDNS_TOKEN" ]; then
 | 
			
		||||
    _err "No Token or API key (deprecated) specified for Gandi LiveDNS."
 | 
			
		||||
    _err "Create your token or key and export it as GANDI_LIVEDNS_KEY or GANDI_LIVEDNS_TOKEN respectively"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _saveaccountconf GANDI_LIVEDNS_KEY "$GANDI_LIVEDNS_KEY"
 | 
			
		||||
  # Keep only one secret in configuration
 | 
			
		||||
  if [ -n "$GANDI_LIVEDNS_TOKEN" ]; then
 | 
			
		||||
    _saveaccountconf GANDI_LIVEDNS_TOKEN "$GANDI_LIVEDNS_TOKEN"
 | 
			
		||||
    _clearaccountconf GANDI_LIVEDNS_KEY
 | 
			
		||||
  elif [ -n "$GANDI_LIVEDNS_KEY" ]; then
 | 
			
		||||
    _saveaccountconf GANDI_LIVEDNS_KEY "$GANDI_LIVEDNS_KEY"
 | 
			
		||||
    _clearaccountconf GANDI_LIVEDNS_TOKEN
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
@@ -70,7 +81,7 @@ dns_gandi_livedns_rm() {
 | 
			
		||||
  _gandi_livedns_rest PUT \
 | 
			
		||||
    "domains/$_domain/records/$_sub_domain/TXT" \
 | 
			
		||||
    "{\"rrset_ttl\": 300, \"rrset_values\": $_new_rrset_values}" &&
 | 
			
		||||
    _contains "$response" '{"message": "DNS Record Created"}' &&
 | 
			
		||||
    _contains "$response" '{"message":"DNS Record Created"}' &&
 | 
			
		||||
    _info "Removing record $(__green "success")"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -126,7 +137,7 @@ _dns_gandi_append_record() {
 | 
			
		||||
  _debug new_rrset_values "$_rrset_values"
 | 
			
		||||
  _gandi_livedns_rest PUT "domains/$_domain/records/$sub_domain/TXT" \
 | 
			
		||||
    "{\"rrset_ttl\": 300, \"rrset_values\": $_rrset_values}" &&
 | 
			
		||||
    _contains "$response" '{"message": "DNS Record Created"}' &&
 | 
			
		||||
    _contains "$response" '{"message":"DNS Record Created"}' &&
 | 
			
		||||
    _info "Adding record $(__green "success")"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -136,11 +147,11 @@ _dns_gandi_existing_rrset_values() {
 | 
			
		||||
  if ! _gandi_livedns_rest GET "domains/$domain/records/$sub_domain"; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  if ! _contains "$response" '"rrset_type": "TXT"'; then
 | 
			
		||||
  if ! _contains "$response" '"rrset_type":"TXT"'; then
 | 
			
		||||
    _debug "Does not have a _acme-challenge TXT record yet."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  if _contains "$response" '"rrset_values": \[\]'; then
 | 
			
		||||
  if _contains "$response" '"rrset_values":\[\]'; then
 | 
			
		||||
    _debug "Empty rrset_values for TXT record, no previous TXT record."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
@@ -157,7 +168,12 @@ _gandi_livedns_rest() {
 | 
			
		||||
  _debug "$ep"
 | 
			
		||||
 | 
			
		||||
  export _H1="Content-Type: application/json"
 | 
			
		||||
  export _H2="X-Api-Key: $GANDI_LIVEDNS_KEY"
 | 
			
		||||
 | 
			
		||||
  if [ -n "$GANDI_LIVEDNS_TOKEN" ]; then
 | 
			
		||||
    export _H2="Authorization: Bearer $GANDI_LIVEDNS_TOKEN"
 | 
			
		||||
  else
 | 
			
		||||
    export _H2="Authorization: Apikey $GANDI_LIVEDNS_KEY"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ "$m" = "GET" ]; then
 | 
			
		||||
    response="$(_get "$GANDI_LIVEDNS_API/$ep")"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,12 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
# Author: Janos Lenart <janos@lenart.io>
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_gcloud_info='Google Cloud DNS
 | 
			
		||||
Site: Cloud.Google.com/dns
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_gcloud
 | 
			
		||||
Options:
 | 
			
		||||
 CLOUDSDK_ACTIVE_CONFIG_NAME Active config name. E.g. "default"
 | 
			
		||||
Author: Janos Lenart <janos@lenart.io>
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
@@ -39,10 +45,10 @@ dns_gcloud_rm() {
 | 
			
		||||
  _dns_gcloud_start_tr || return $?
 | 
			
		||||
  _dns_gcloud_get_rrdatas || return $?
 | 
			
		||||
  echo "$rrdatas" | _dns_gcloud_remove_rrs || return $?
 | 
			
		||||
  echo "$rrdatas" | grep -F -v "\"$txtvalue\"" | _dns_gcloud_add_rrs || return $?
 | 
			
		||||
  echo "$rrdatas" | grep -F -v -- "\"$txtvalue\"" | _dns_gcloud_add_rrs || return $?
 | 
			
		||||
  _dns_gcloud_execute_tr || return $?
 | 
			
		||||
 | 
			
		||||
  _info "$fulldomain record added"
 | 
			
		||||
  _info "$fulldomain record removed"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
@@ -98,7 +104,7 @@ _dns_gcloud_remove_rrs() {
 | 
			
		||||
    --ttl="$ttl" \
 | 
			
		||||
    --type=TXT \
 | 
			
		||||
    --zone="$managedZone" \
 | 
			
		||||
    --transaction-file="$tr"; then
 | 
			
		||||
    --transaction-file="$tr" --; then
 | 
			
		||||
    _debug tr "$(cat "$tr")"
 | 
			
		||||
    rm -r "$trd"
 | 
			
		||||
    _err "_dns_gcloud_remove_rrs: failed to remove RRs"
 | 
			
		||||
@@ -113,7 +119,7 @@ _dns_gcloud_add_rrs() {
 | 
			
		||||
    --ttl="$ttl" \
 | 
			
		||||
    --type=TXT \
 | 
			
		||||
    --zone="$managedZone" \
 | 
			
		||||
    --transaction-file="$tr"; then
 | 
			
		||||
    --transaction-file="$tr" --; then
 | 
			
		||||
    _debug tr "$(cat "$tr")"
 | 
			
		||||
    rm -r "$trd"
 | 
			
		||||
    _err "_dns_gcloud_add_rrs: failed to add RRs"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										191
									
								
								dnsapi/dns_gcore.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										191
									
								
								dnsapi/dns_gcore.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,191 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_gcore_info='Gcore.com
 | 
			
		||||
Site: Gcore.com
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_gcore
 | 
			
		||||
Options:
 | 
			
		||||
 GCORE_Key API Key
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/4460
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
GCORE_Api="https://api.gcore.com/dns/v2"
 | 
			
		||||
GCORE_Doc="https://api.gcore.com/docs/dns"
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: add  _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_gcore_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  GCORE_Key="${GCORE_Key:-$(_readaccountconf_mutable GCORE_Key)}"
 | 
			
		||||
 | 
			
		||||
  if [ -z "$GCORE_Key" ]; then
 | 
			
		||||
    GCORE_Key=""
 | 
			
		||||
    _err "You didn't specify a Gcore api key yet."
 | 
			
		||||
    _err "You can get yours from here $GCORE_Doc"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  #save the api key to the account conf file.
 | 
			
		||||
  _saveaccountconf_mutable GCORE_Key "$GCORE_Key"
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the zone name"
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "invalid domain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug _zone_name "$_zone_name"
 | 
			
		||||
  _debug _sub_domain "$_sub_domain"
 | 
			
		||||
  _debug _domain "$_domain"
 | 
			
		||||
 | 
			
		||||
  _debug "Getting txt records"
 | 
			
		||||
  _gcore_rest GET "zones/$_zone_name/$fulldomain/TXT"
 | 
			
		||||
  payload=""
 | 
			
		||||
 | 
			
		||||
  if echo "$response" | grep "record is not found" >/dev/null; then
 | 
			
		||||
    _info "Record doesn't exists"
 | 
			
		||||
    payload="{\"resource_records\":[{\"content\":[\"$txtvalue\"],\"enabled\":true}],\"ttl\":120}"
 | 
			
		||||
  elif echo "$response" | grep "$txtvalue" >/dev/null; then
 | 
			
		||||
    _info "Already exists, OK"
 | 
			
		||||
    return 0
 | 
			
		||||
  elif echo "$response" | tr -d " " | grep \"name\":\""$fulldomain"\",\"type\":\"TXT\" >/dev/null; then
 | 
			
		||||
    _info "Record with mismatch txtvalue, try update it"
 | 
			
		||||
    payload=$(echo "$response" | tr -d " " | sed 's/"updated_at":[0-9]\+,//g' | sed 's/"meta":{}}]}/"meta":{}},{"content":['\""$txtvalue"\"'],"enabled":true}]}/')
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # For wildcard cert, the main root domain and the wildcard domain have the same txt subdomain name, so
 | 
			
		||||
  # we can not use updating anymore.
 | 
			
		||||
  #  count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2)
 | 
			
		||||
  #  _debug count "$count"
 | 
			
		||||
  #  if [ "$count" = "0" ]; then
 | 
			
		||||
  _info "Adding record"
 | 
			
		||||
  if _gcore_rest PUT "zones/$_zone_name/$fulldomain/TXT" "$payload"; then
 | 
			
		||||
    if _contains "$response" "$txtvalue"; then
 | 
			
		||||
      _info "Added, OK"
 | 
			
		||||
      return 0
 | 
			
		||||
    elif _contains "$response" "rrset is already exists"; then
 | 
			
		||||
      _info "Already exists, OK"
 | 
			
		||||
      return 0
 | 
			
		||||
    else
 | 
			
		||||
      _err "Add txt record error."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
  _err "Add txt record error."
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#fulldomain txtvalue
 | 
			
		||||
dns_gcore_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  GCORE_Key="${GCORE_Key:-$(_readaccountconf_mutable GCORE_Key)}"
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "invalid domain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug _zone_name "$_zone_name"
 | 
			
		||||
  _debug _sub_domain "$_sub_domain"
 | 
			
		||||
  _debug _domain "$_domain"
 | 
			
		||||
 | 
			
		||||
  _debug "Getting txt records"
 | 
			
		||||
  _gcore_rest GET "zones/$_zone_name/$fulldomain/TXT"
 | 
			
		||||
 | 
			
		||||
  if echo "$response" | grep "record is not found" >/dev/null; then
 | 
			
		||||
    _info "No such txt recrod"
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! echo "$response" | tr -d " " | grep \"name\":\""$fulldomain"\",\"type\":\"TXT\" >/dev/null; then
 | 
			
		||||
    _err "Error: $response"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! echo "$response" | tr -d " " | grep \""$txtvalue"\" >/dev/null; then
 | 
			
		||||
    _info "No such txt recrod"
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  count="$(echo "$response" | grep -o "content" | wc -l)"
 | 
			
		||||
 | 
			
		||||
  if [ "$count" = "1" ]; then
 | 
			
		||||
    if ! _gcore_rest DELETE "zones/$_zone_name/$fulldomain/TXT"; then
 | 
			
		||||
      _err "Delete record error. $response"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  payload="$(echo "$response" | tr -d " " | sed 's/"updated_at":[0-9]\+,//g' | sed 's/{"id":[0-9]\+,"content":\["'"$txtvalue"'"\],"enabled":true,"meta":{}}//' | sed 's/\[,/\[/' | sed 's/,,/,/' | sed 's/,\]/\]/')"
 | 
			
		||||
  if ! _gcore_rest PUT "zones/$_zone_name/$fulldomain/TXT" "$payload"; then
 | 
			
		||||
    _err "Delete record error. $response"
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
#_acme-challenge.sub.domain.com
 | 
			
		||||
#returns
 | 
			
		||||
# _sub_domain=_acme-challenge.sub or _acme-challenge
 | 
			
		||||
# _domain=domain.com
 | 
			
		||||
# _zone_name=domain.com or sub.domain.com
 | 
			
		||||
_get_root() {
 | 
			
		||||
  domain=$1
 | 
			
		||||
  i=1
 | 
			
		||||
  p=1
 | 
			
		||||
 | 
			
		||||
  while true; do
 | 
			
		||||
    h=$(printf "%s" "$domain" | cut -d . -f $i-100)
 | 
			
		||||
    _debug h "$h"
 | 
			
		||||
    if [ -z "$h" ]; then
 | 
			
		||||
      #not valid
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if ! _gcore_rest GET "zones/$h"; then
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if _contains "$response" "\"name\":\"$h\""; then
 | 
			
		||||
      _zone_name=$h
 | 
			
		||||
      if [ "$_zone_name" ]; then
 | 
			
		||||
        _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
 | 
			
		||||
        _domain=$h
 | 
			
		||||
        return 0
 | 
			
		||||
      fi
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    p=$i
 | 
			
		||||
    i=$(_math "$i" + 1)
 | 
			
		||||
  done
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_gcore_rest() {
 | 
			
		||||
  m=$1
 | 
			
		||||
  ep="$2"
 | 
			
		||||
  data="$3"
 | 
			
		||||
  _debug "$ep"
 | 
			
		||||
 | 
			
		||||
  key_trimmed=$(echo "$GCORE_Key" | tr -d '"')
 | 
			
		||||
 | 
			
		||||
  export _H1="Content-Type: application/json"
 | 
			
		||||
  export _H2="Authorization: APIKey $key_trimmed"
 | 
			
		||||
 | 
			
		||||
  if [ "$m" != "GET" ]; then
 | 
			
		||||
    _debug data "$data"
 | 
			
		||||
    response="$(_post "$data" "$GCORE_Api/$ep" "" "$m")"
 | 
			
		||||
  else
 | 
			
		||||
    response="$(_get "$GCORE_Api/$ep")"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "error $ep"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
@@ -1,10 +1,12 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#Godaddy domain api
 | 
			
		||||
#
 | 
			
		||||
#GD_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
 | 
			
		||||
#
 | 
			
		||||
#GD_Secret="asdfsdfsfsdfsdfdfsdf"
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_gd_info='GoDaddy.com
 | 
			
		||||
Site: GoDaddy.com
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_gd
 | 
			
		||||
Options:
 | 
			
		||||
 GD_Key API Key
 | 
			
		||||
 GD_Secret API Secret
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
GD_Api="https://api.godaddy.com/v1"
 | 
			
		||||
 | 
			
		||||
@@ -20,8 +22,8 @@ dns_gd_add() {
 | 
			
		||||
  if [ -z "$GD_Key" ] || [ -z "$GD_Secret" ]; then
 | 
			
		||||
    GD_Key=""
 | 
			
		||||
    GD_Secret=""
 | 
			
		||||
    _err "You don't specify godaddy api key and secret yet."
 | 
			
		||||
    _err "Please create you key and try again."
 | 
			
		||||
    _err "You didn't specify godaddy api key and secret yet."
 | 
			
		||||
    _err "Please create your key and try again."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
@@ -44,14 +46,15 @@ dns_gd_add() {
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if _contains "$response" "$txtvalue"; then
 | 
			
		||||
    _info "The record is existing, skip"
 | 
			
		||||
    _info "This record already exists, skipping"
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _add_data="{\"data\":\"$txtvalue\"}"
 | 
			
		||||
  for t in $(echo "$response" | tr '{' "\n" | grep "\"name\":\"$_sub_domain\"" | tr ',' "\n" | grep '"data"' | cut -d : -f 2); do
 | 
			
		||||
    _debug2 t "$t"
 | 
			
		||||
    if [ "$t" ]; then
 | 
			
		||||
    # ignore empty (previously removed) records, to prevent useless _acme-challenge TXT entries
 | 
			
		||||
    if [ "$t" ] && [ "$t" != '""' ]; then
 | 
			
		||||
      _add_data="$_add_data,{\"data\":$t}"
 | 
			
		||||
    fi
 | 
			
		||||
  done
 | 
			
		||||
@@ -59,13 +62,25 @@ dns_gd_add() {
 | 
			
		||||
 | 
			
		||||
  _info "Adding record"
 | 
			
		||||
  if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]"; then
 | 
			
		||||
    _info "Added, sleeping 10 seconds"
 | 
			
		||||
    _sleep 10
 | 
			
		||||
    #todo: check if the record takes effect
 | 
			
		||||
    return 0
 | 
			
		||||
    _debug "Checking updated records of '${fulldomain}'"
 | 
			
		||||
 | 
			
		||||
    if ! _gd_rest GET "domains/$_domain/records/TXT/$_sub_domain"; then
 | 
			
		||||
      _err "Validating TXT record for '${fulldomain}' with rest error [$?]." "$response"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if ! _contains "$response" "$txtvalue"; then
 | 
			
		||||
      _err "TXT record '${txtvalue}' for '${fulldomain}', value wasn't set!"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    _err "Add txt record error, value '${txtvalue}' for '${fulldomain}' was not set."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _err "Add txt record error."
 | 
			
		||||
  return 1
 | 
			
		||||
 | 
			
		||||
  _sleep 10
 | 
			
		||||
  _info "Added TXT record '${txtvalue}' for '${fulldomain}'."
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#fulldomain
 | 
			
		||||
@@ -107,11 +122,20 @@ dns_gd_rm() {
 | 
			
		||||
    fi
 | 
			
		||||
  done
 | 
			
		||||
  if [ -z "$_add_data" ]; then
 | 
			
		||||
    _add_data="{\"data\":\"\"}"
 | 
			
		||||
    # delete empty record
 | 
			
		||||
    _debug "Delete last record for '${fulldomain}'"
 | 
			
		||||
    if ! _gd_rest DELETE "domains/$_domain/records/TXT/$_sub_domain"; then
 | 
			
		||||
      _err "Cannot delete empty TXT record for '$fulldomain'"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    # remove specific TXT value, keeping other entries
 | 
			
		||||
    _debug2 _add_data "$_add_data"
 | 
			
		||||
    if ! _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]"; then
 | 
			
		||||
      _err "Cannot update TXT record for '$fulldomain'"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 _add_data "$_add_data"
 | 
			
		||||
 | 
			
		||||
  _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
@@ -156,15 +180,15 @@ _gd_rest() {
 | 
			
		||||
  export _H1="Authorization: sso-key $GD_Key:$GD_Secret"
 | 
			
		||||
  export _H2="Content-Type: application/json"
 | 
			
		||||
 | 
			
		||||
  if [ "$data" ]; then
 | 
			
		||||
    _debug data "$data"
 | 
			
		||||
  if [ "$data" ] || [ "$m" = "DELETE" ]; then
 | 
			
		||||
    _debug "data ($m): " "$data"
 | 
			
		||||
    response="$(_post "$data" "$GD_Api/$ep" "" "$m")"
 | 
			
		||||
  else
 | 
			
		||||
    response="$(_get "$GD_Api/$ep")"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "error $ep"
 | 
			
		||||
    _err "error on rest call ($m): $ep"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,12 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
########################################################################
 | 
			
		||||
# Geoscaling hook script for acme.sh
 | 
			
		||||
#
 | 
			
		||||
# Environment variables:
 | 
			
		||||
#
 | 
			
		||||
#  - $GEOSCALING_Username  (your Geoscaling username - this is usually NOT an amail address)
 | 
			
		||||
#  - $GEOSCALING_Password  (your Geoscaling password)
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_geoscaling_info='GeoScaling.com
 | 
			
		||||
Site: GeoScaling.com
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_geoscaling
 | 
			
		||||
Options:
 | 
			
		||||
 GEOSCALING_Username Username. This is usually NOT an email address
 | 
			
		||||
 GEOSCALING_Password Password
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
#-- dns_geoscaling_add() - Add TXT record --------------------------------------
 | 
			
		||||
# Usage: dns_geoscaling_add _acme-challenge.subdomain.domain.com "XyZ123..."
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										178
									
								
								dnsapi/dns_googledomains.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										178
									
								
								dnsapi/dns_googledomains.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,178 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_googledomains_info='Google Domains
 | 
			
		||||
Site: Domains.Google.com
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_googledomains
 | 
			
		||||
Options:
 | 
			
		||||
 GOOGLEDOMAINS_ACCESS_TOKEN API Access Token
 | 
			
		||||
 GOOGLEDOMAINS_ZONE Zone
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/4545
 | 
			
		||||
Author: Alex Leigh <leigh@alexleigh.me>
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
GOOGLEDOMAINS_API="https://acmedns.googleapis.com/v1/acmeChallengeSets"
 | 
			
		||||
 | 
			
		||||
######## Public functions ########
 | 
			
		||||
 | 
			
		||||
#Usage: dns_googledomains_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_googledomains_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  _info "Invoking Google Domains ACME DNS API."
 | 
			
		||||
 | 
			
		||||
  if ! _dns_googledomains_setup; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  zone="$(_dns_googledomains_get_zone "$fulldomain")"
 | 
			
		||||
  if [ -z "$zone" ]; then
 | 
			
		||||
    _err "Could not find a Google Domains-managed zone containing the requested domain."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug zone "$zone"
 | 
			
		||||
  _debug txtvalue "$txtvalue"
 | 
			
		||||
 | 
			
		||||
  _info "Adding TXT record for $fulldomain."
 | 
			
		||||
  if _dns_googledomains_api "$zone" ":rotateChallenges" "{\"accessToken\":\"$GOOGLEDOMAINS_ACCESS_TOKEN\",\"recordsToAdd\":[{\"fqdn\":\"$fulldomain\",\"digest\":\"$txtvalue\"}],\"keepExpiredRecords\":true}"; then
 | 
			
		||||
    if _contains "$response" "$txtvalue"; then
 | 
			
		||||
      _info "TXT record added."
 | 
			
		||||
      return 0
 | 
			
		||||
    else
 | 
			
		||||
      _err "Error adding TXT record."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _err "Error adding TXT record."
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#Usage: dns_googledomains_rm   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_googledomains_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  _info "Invoking Google Domains ACME DNS API."
 | 
			
		||||
 | 
			
		||||
  if ! _dns_googledomains_setup; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  zone="$(_dns_googledomains_get_zone "$fulldomain")"
 | 
			
		||||
  if [ -z "$zone" ]; then
 | 
			
		||||
    _err "Could not find a Google Domains-managed domain based on request."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug zone "$zone"
 | 
			
		||||
  _debug txtvalue "$txtvalue"
 | 
			
		||||
 | 
			
		||||
  _info "Removing TXT record for $fulldomain."
 | 
			
		||||
  if _dns_googledomains_api "$zone" ":rotateChallenges" "{\"accessToken\":\"$GOOGLEDOMAINS_ACCESS_TOKEN\",\"recordsToRemove\":[{\"fqdn\":\"$fulldomain\",\"digest\":\"$txtvalue\"}],\"keepExpiredRecords\":true}"; then
 | 
			
		||||
    if _contains "$response" "$txtvalue"; then
 | 
			
		||||
      _err "Error removing TXT record."
 | 
			
		||||
      return 1
 | 
			
		||||
    else
 | 
			
		||||
      _info "TXT record removed."
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _err "Error removing TXT record."
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
######## Private functions ########
 | 
			
		||||
 | 
			
		||||
_dns_googledomains_setup() {
 | 
			
		||||
  if [ -n "$GOOGLEDOMAINS_SETUP_COMPLETED" ]; then
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  GOOGLEDOMAINS_ACCESS_TOKEN="${GOOGLEDOMAINS_ACCESS_TOKEN:-$(_readaccountconf_mutable GOOGLEDOMAINS_ACCESS_TOKEN)}"
 | 
			
		||||
  GOOGLEDOMAINS_ZONE="${GOOGLEDOMAINS_ZONE:-$(_readaccountconf_mutable GOOGLEDOMAINS_ZONE)}"
 | 
			
		||||
 | 
			
		||||
  if [ -z "$GOOGLEDOMAINS_ACCESS_TOKEN" ]; then
 | 
			
		||||
    GOOGLEDOMAINS_ACCESS_TOKEN=""
 | 
			
		||||
    _err "Google Domains access token was not specified."
 | 
			
		||||
    _err "Please visit Google Domains Security settings to provision an ACME DNS API access token."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ "$GOOGLEDOMAINS_ZONE" ]; then
 | 
			
		||||
    _savedomainconf GOOGLEDOMAINS_ACCESS_TOKEN "$GOOGLEDOMAINS_ACCESS_TOKEN"
 | 
			
		||||
    _savedomainconf GOOGLEDOMAINS_ZONE "$GOOGLEDOMAINS_ZONE"
 | 
			
		||||
  else
 | 
			
		||||
    _saveaccountconf_mutable GOOGLEDOMAINS_ACCESS_TOKEN "$GOOGLEDOMAINS_ACCESS_TOKEN"
 | 
			
		||||
    _clearaccountconf_mutable GOOGLEDOMAINS_ZONE
 | 
			
		||||
    _clearaccountconf GOOGLEDOMAINS_ZONE
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug GOOGLEDOMAINS_ACCESS_TOKEN "$GOOGLEDOMAINS_ACCESS_TOKEN"
 | 
			
		||||
  _debug GOOGLEDOMAINS_ZONE "$GOOGLEDOMAINS_ZONE"
 | 
			
		||||
 | 
			
		||||
  GOOGLEDOMAINS_SETUP_COMPLETED=1
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_dns_googledomains_get_zone() {
 | 
			
		||||
  domain=$1
 | 
			
		||||
 | 
			
		||||
  # Use zone directly if provided
 | 
			
		||||
  if [ "$GOOGLEDOMAINS_ZONE" ]; then
 | 
			
		||||
    if ! _dns_googledomains_api "$GOOGLEDOMAINS_ZONE"; then
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    echo "$GOOGLEDOMAINS_ZONE"
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  i=2
 | 
			
		||||
  while true; do
 | 
			
		||||
    curr=$(printf "%s" "$domain" | cut -d . -f $i-100)
 | 
			
		||||
    _debug curr "$curr"
 | 
			
		||||
 | 
			
		||||
    if [ -z "$curr" ]; then
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if _dns_googledomains_api "$curr"; then
 | 
			
		||||
      echo "$curr"
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    i=$(_math "$i" + 1)
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_dns_googledomains_api() {
 | 
			
		||||
  zone=$1
 | 
			
		||||
  apimethod=$2
 | 
			
		||||
  data="$3"
 | 
			
		||||
 | 
			
		||||
  if [ -z "$data" ]; then
 | 
			
		||||
    response="$(_get "$GOOGLEDOMAINS_API/$zone$apimethod")"
 | 
			
		||||
  else
 | 
			
		||||
    _debug data "$data"
 | 
			
		||||
    export _H1="Content-Type: application/json"
 | 
			
		||||
    response="$(_post "$data" "$GOOGLEDOMAINS_API/$zone$apimethod")"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug response "$response"
 | 
			
		||||
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "Error"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if _contains "$response" "\"error\": {"; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
@@ -1,15 +1,14 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
########################################################################
 | 
			
		||||
# Hurricane Electric hook script for acme.sh
 | 
			
		||||
#
 | 
			
		||||
# Environment variables:
 | 
			
		||||
#
 | 
			
		||||
#  - $HE_Username  (your dns.he.net username)
 | 
			
		||||
#  - $HE_Password  (your dns.he.net password)
 | 
			
		||||
#
 | 
			
		||||
# Author: Ondrej Simek <me@ondrejsimek.com>
 | 
			
		||||
# Git repo: https://github.com/angel333/acme.sh
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_he_info='Hurricane Electric HE.net
 | 
			
		||||
Site: dns.he.net
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_he
 | 
			
		||||
Options:
 | 
			
		||||
 HE_Username Username
 | 
			
		||||
 HE_Password Password
 | 
			
		||||
Issues: github.com/angel333/acme.sh/issues/
 | 
			
		||||
Author: Ondrej Simek <me@ondrejsimek.com>
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
#-- dns_he_add() - Add TXT record --------------------------------------
 | 
			
		||||
# Usage: dns_he_add _acme-challenge.subdomain.domain.com "XyZ123..."
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,12 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
#HETZNER_Token="sdfsdfsdfljlbjkljlkjsdfoiwje"
 | 
			
		||||
#
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_hetzner_info='Hetzner.com
 | 
			
		||||
Site: Hetzner.com
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_hetzner
 | 
			
		||||
Options:
 | 
			
		||||
 HETZNER_Token API Token
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/2943
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
HETZNER_Api="https://dns.hetzner.com/api/v1"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,13 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Hexonet_Login="username!roleId"
 | 
			
		||||
#
 | 
			
		||||
# Hexonet_Password="rolePassword"
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_hexonet_info='Hexonet.com
 | 
			
		||||
Site: Hexonet.com
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_hexonet
 | 
			
		||||
Options:
 | 
			
		||||
 Hexonet_Login Login. E.g. "username!roleId"
 | 
			
		||||
 Hexonet_Password Role Password
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/2389
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
Hexonet_Api="https://coreapi.1api.net/api/call.cgi"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,13 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
# hosting.de API
 | 
			
		||||
 | 
			
		||||
# Values to export:
 | 
			
		||||
# export HOSTINGDE_ENDPOINT='https://secure.hosting.de'
 | 
			
		||||
# export HOSTINGDE_APIKEY='xxxxx'
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_hostingde_info='Hosting.de
 | 
			
		||||
Site: Hosting.de
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_hostingde
 | 
			
		||||
Options:
 | 
			
		||||
 HOSTINGDE_ENDPOINT Endpoint. E.g. "https://secure.hosting.de"
 | 
			
		||||
 HOSTINGDE_APIKEY API Key
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/2058
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,14 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
# HUAWEICLOUD_Username
 | 
			
		||||
# HUAWEICLOUD_Password
 | 
			
		||||
# HUAWEICLOUD_ProjectID
 | 
			
		||||
# shellcheck disable=SC2034
 | 
			
		||||
dns_huaweicloud_info='HuaweiCloud.com
 | 
			
		||||
Site: HuaweiCloud.com
 | 
			
		||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_huaweicloud
 | 
			
		||||
Options:
 | 
			
		||||
 HUAWEICLOUD_Username Username
 | 
			
		||||
 HUAWEICLOUD_Password Password
 | 
			
		||||
 HUAWEICLOUD_DomainName DomainName
 | 
			
		||||
Issues: github.com/acmesh-official/acme.sh/issues/3265
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
iam_api="https://iam.myhuaweicloud.com"
 | 
			
		||||
dns_api="https://dns.ap-southeast-1.myhuaweicloud.com" # Should work
 | 
			
		||||
@@ -14,6 +20,8 @@ dns_api="https://dns.ap-southeast-1.myhuaweicloud.com" # Should work
 | 
			
		||||
#
 | 
			
		||||
# Ref: https://support.huaweicloud.com/intl/zh-cn/api-dns/zh-cn_topic_0132421999.html
 | 
			
		||||
#
 | 
			
		||||
# About "DomainName" parameters see: https://support.huaweicloud.com/api-iam/iam_01_0006.html
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
dns_huaweicloud_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
@@ -21,16 +29,16 @@ dns_huaweicloud_add() {
 | 
			
		||||
 | 
			
		||||
  HUAWEICLOUD_Username="${HUAWEICLOUD_Username:-$(_readaccountconf_mutable HUAWEICLOUD_Username)}"
 | 
			
		||||
  HUAWEICLOUD_Password="${HUAWEICLOUD_Password:-$(_readaccountconf_mutable HUAWEICLOUD_Password)}"
 | 
			
		||||
  HUAWEICLOUD_ProjectID="${HUAWEICLOUD_ProjectID:-$(_readaccountconf_mutable HUAWEICLOUD_ProjectID)}"
 | 
			
		||||
  HUAWEICLOUD_DomainName="${HUAWEICLOUD_DomainName:-$(_readaccountconf_mutable HUAWEICLOUD_DomainName)}"
 | 
			
		||||
 | 
			
		||||
  # Check information
 | 
			
		||||
  if [ -z "${HUAWEICLOUD_Username}" ] || [ -z "${HUAWEICLOUD_Password}" ] || [ -z "${HUAWEICLOUD_ProjectID}" ]; then
 | 
			
		||||
  if [ -z "${HUAWEICLOUD_Username}" ] || [ -z "${HUAWEICLOUD_Password}" ] || [ -z "${HUAWEICLOUD_DomainName}" ]; then
 | 
			
		||||
    _err "Not enough information provided to dns_huaweicloud!"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  unset token # Clear token
 | 
			
		||||
  token="$(_get_token "${HUAWEICLOUD_Username}" "${HUAWEICLOUD_Password}" "${HUAWEICLOUD_ProjectID}")"
 | 
			
		||||
  token="$(_get_token "${HUAWEICLOUD_Username}" "${HUAWEICLOUD_Password}" "${HUAWEICLOUD_DomainName}")"
 | 
			
		||||
  if [ -z "${token}" ]; then # Check token
 | 
			
		||||
    _err "dns_api(dns_huaweicloud): Error getting token."
 | 
			
		||||
    return 1
 | 
			
		||||
@@ -56,7 +64,7 @@ dns_huaweicloud_add() {
 | 
			
		||||
  # Do saving work if all succeeded
 | 
			
		||||
  _saveaccountconf_mutable HUAWEICLOUD_Username "${HUAWEICLOUD_Username}"
 | 
			
		||||
  _saveaccountconf_mutable HUAWEICLOUD_Password "${HUAWEICLOUD_Password}"
 | 
			
		||||
  _saveaccountconf_mutable HUAWEICLOUD_ProjectID "${HUAWEICLOUD_ProjectID}"
 | 
			
		||||
  _saveaccountconf_mutable HUAWEICLOUD_DomainName "${HUAWEICLOUD_DomainName}"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -72,16 +80,16 @@ dns_huaweicloud_rm() {
 | 
			
		||||
 | 
			
		||||
  HUAWEICLOUD_Username="${HUAWEICLOUD_Username:-$(_readaccountconf_mutable HUAWEICLOUD_Username)}"
 | 
			
		||||
  HUAWEICLOUD_Password="${HUAWEICLOUD_Password:-$(_readaccountconf_mutable HUAWEICLOUD_Password)}"
 | 
			
		||||
  HUAWEICLOUD_ProjectID="${HUAWEICLOUD_ProjectID:-$(_readaccountconf_mutable HUAWEICLOUD_ProjectID)}"
 | 
			
		||||
  HUAWEICLOUD_DomainName="${HUAWEICLOUD_DomainName:-$(_readaccountconf_mutable HUAWEICLOUD_DomainName)}"
 | 
			
		||||
 | 
			
		||||
  # Check information
 | 
			
		||||
  if [ -z "${HUAWEICLOUD_Username}" ] || [ -z "${HUAWEICLOUD_Password}" ] || [ -z "${HUAWEICLOUD_ProjectID}" ]; then
 | 
			
		||||
  if [ -z "${HUAWEICLOUD_Username}" ] || [ -z "${HUAWEICLOUD_Password}" ] || [ -z "${HUAWEICLOUD_DomainName}" ]; then
 | 
			
		||||
    _err "Not enough information provided to dns_huaweicloud!"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  unset token # Clear token
 | 
			
		||||
  token="$(_get_token "${HUAWEICLOUD_Username}" "${HUAWEICLOUD_Password}" "${HUAWEICLOUD_ProjectID}")"
 | 
			
		||||
  token="$(_get_token "${HUAWEICLOUD_Username}" "${HUAWEICLOUD_Password}" "${HUAWEICLOUD_DomainName}")"
 | 
			
		||||
  if [ -z "${token}" ]; then # Check token
 | 
			
		||||
    _err "dns_api(dns_huaweicloud): Error getting token."
 | 
			
		||||
    return 1
 | 
			
		||||
@@ -96,19 +104,59 @@ dns_huaweicloud_rm() {
 | 
			
		||||
  fi
 | 
			
		||||
  _debug "Zone ID is:" "${zoneid}"
 | 
			
		||||
 | 
			
		||||
  # Remove all records
 | 
			
		||||
  # Therotically HuaweiCloud does not allow more than one record set
 | 
			
		||||
  # But remove them recurringly to increase robusty
 | 
			
		||||
  while [ "${record_id}" != "0" ]; do
 | 
			
		||||
    _debug "Removing Record"
 | 
			
		||||
    _rm_record "${token}" "${zoneid}" "${record_id}"
 | 
			
		||||
    record_id="$(_get_recordset_id "${token}" "${fulldomain}" "${zoneid}")"
 | 
			
		||||
  done
 | 
			
		||||
  record_id="$(_get_recordset_id "${token}" "${fulldomain}" "${zoneid}")"
 | 
			
		||||
  _recursive_rm_record "${token}" "${fulldomain}" "${zoneid}" "${record_id}"
 | 
			
		||||
  ret="$?"
 | 
			
		||||
  if [ "${ret}" != "0" ]; then
 | 
			
		||||
    _err "dns_api(dns_huaweicloud): Error removing record."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
###################  Private functions below ##################################
 | 
			
		||||
 | 
			
		||||
# _recursive_rm_record
 | 
			
		||||
# remove all records from the record set
 | 
			
		||||
#
 | 
			
		||||
# _token=$1
 | 
			
		||||
# _domain=$2
 | 
			
		||||
# _zoneid=$3
 | 
			
		||||
# _record_id=$4
 | 
			
		||||
#
 | 
			
		||||
# Returns 0 on success
 | 
			
		||||
_recursive_rm_record() {
 | 
			
		||||
  _token=$1
 | 
			
		||||
  _domain=$2
 | 
			
		||||
  _zoneid=$3
 | 
			
		||||
  _record_id=$4
 | 
			
		||||
 | 
			
		||||
  # Most likely to have problems will huaweicloud side if more than 50 attempts but still cannot fully remove the record set
 | 
			
		||||
  # Maybe can be removed manually in the dashboard
 | 
			
		||||
  _retry_cnt=50
 | 
			
		||||
 | 
			
		||||
  # Remove all records
 | 
			
		||||
  # Therotically HuaweiCloud does not allow more than one record set
 | 
			
		||||
  # But remove them recurringly to increase robusty
 | 
			
		||||
 | 
			
		||||
  while [ "${_record_id}" != "0" ] && [ "${_retry_cnt}" != "0" ]; do
 | 
			
		||||
    _debug "Removing Record"
 | 
			
		||||
    _retry_cnt=$((_retry_cnt - 1))
 | 
			
		||||
    _rm_record "${_token}" "${_zoneid}" "${_record_id}"
 | 
			
		||||
    _record_id="$(_get_recordset_id "${_token}" "${_domain}" "${_zoneid}")"
 | 
			
		||||
    _debug2 "Checking record exists: record_id=${_record_id}"
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  # Check if retry count is reached
 | 
			
		||||
  if [ "${_retry_cnt}" = "0" ]; then
 | 
			
		||||
    _debug "Failed to remove record after 50 attempts, please try removing it manually in the dashboard"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# _get_zoneid
 | 
			
		||||
#
 | 
			
		||||
# _token=$1
 | 
			
		||||
@@ -122,7 +170,7 @@ _get_zoneid() {
 | 
			
		||||
 | 
			
		||||
  i=1
 | 
			
		||||
  while true; do
 | 
			
		||||
    h=$(printf "%s" "${_domain_string}" | cut -d . -f $i-100)
 | 
			
		||||
    h=$(printf "%s" "${_domain_string}" | cut -d . -f "$i"-100)
 | 
			
		||||
    if [ -z "$h" ]; then
 | 
			
		||||
      #not valid
 | 
			
		||||
      return 1
 | 
			
		||||
@@ -133,11 +181,11 @@ _get_zoneid() {
 | 
			
		||||
    if _contains "${response}" '"id"'; then
 | 
			
		||||
      zoneidlist=$(echo "${response}" | _egrep_o "\"id\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")
 | 
			
		||||
      zonenamelist=$(echo "${response}" | _egrep_o "\"name\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")
 | 
			
		||||
      _debug2 "Return Zone ID(s):" "${zoneidlist}"
 | 
			
		||||
      _debug2 "Return Zone Name(s):" "${zonenamelist}"
 | 
			
		||||
      _debug2 "Returned Zone ID(s):" "${zoneidlist}"
 | 
			
		||||
      _debug2 "Returned Zone Name(s):" "${zonenamelist}"
 | 
			
		||||
      zoneidnum=0
 | 
			
		||||
      zoneidcount=$(echo "${zoneidlist}" | grep -c '^')
 | 
			
		||||
      _debug "Retund Zone ID(s) Count:" "${zoneidcount}"
 | 
			
		||||
      _debug "Returned Zone ID(s) Count:" "${zoneidcount}"
 | 
			
		||||
      while [ "${zoneidnum}" -lt "${zoneidcount}" ]; do
 | 
			
		||||
        zoneidnum=$(_math "$zoneidnum" + 1)
 | 
			
		||||
        _zoneid=$(echo "${zoneidlist}" | sed -n "${zoneidnum}p")
 | 
			
		||||
@@ -162,7 +210,7 @@ _get_recordset_id() {
 | 
			
		||||
  _zoneid=$3
 | 
			
		||||
  export _H1="X-Auth-Token: ${_token}"
 | 
			
		||||
 | 
			
		||||
  response=$(_get "${dns_api}/v2/zones/${_zoneid}/recordsets?name=${_domain}")
 | 
			
		||||
  response=$(_get "${dns_api}/v2/zones/${_zoneid}/recordsets?name=${_domain}&status=ACTIVE")
 | 
			
		||||
  if _contains "${response}" '"id"'; then
 | 
			
		||||
    _id="$(echo "${response}" | _egrep_o "\"id\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")"
 | 
			
		||||
    printf "%s" "${_id}"
 | 
			
		||||
@@ -179,7 +227,7 @@ _add_record() {
 | 
			
		||||
 | 
			
		||||
  # Get Existing Records
 | 
			
		||||
  export _H1="X-Auth-Token: ${_token}"
 | 
			
		||||
  response=$(_get "${dns_api}/v2/zones/${zoneid}/recordsets?name=${_domain}")
 | 
			
		||||
  response=$(_get "${dns_api}/v2/zones/${zoneid}/recordsets?name=${_domain}&status=ACTIVE")
 | 
			
		||||
 | 
			
		||||
  _debug2 "${response}"
 | 
			
		||||
  _exist_record=$(echo "${response}" | _egrep_o '"records":[^]]*' | sed 's/\"records\"\:\[//g')
 | 
			
		||||
@@ -204,8 +252,7 @@ _add_record() {
 | 
			
		||||
      \"type\": \"TXT\",
 | 
			
		||||
      \"ttl\": 1,
 | 
			
		||||
      \"records\": [
 | 
			
		||||
        ${_exist_record},
 | 
			
		||||
        \"\\\"${_txtvalue}\\\"\"
 | 
			
		||||
        ${_exist_record},\"\\\"${_txtvalue}\\\"\"
 | 
			
		||||
      ]
 | 
			
		||||
    }"
 | 
			
		||||
  fi
 | 
			
		||||
@@ -213,19 +260,16 @@ _add_record() {
 | 
			
		||||
  _record_id="$(_get_recordset_id "${_token}" "${_domain}" "${zoneid}")"
 | 
			
		||||
  _debug "Record Set ID is:" "${_record_id}"
 | 
			
		||||
 | 
			
		||||
  # Remove all records
 | 
			
		||||
  while [ "${_record_id}" != "0" ]; do
 | 
			
		||||
    _debug "Removing Record"
 | 
			
		||||
    _rm_record "${_token}" "${zoneid}" "${_record_id}"
 | 
			
		||||
    _record_id="$(_get_recordset_id "${_token}" "${_domain}" "${zoneid}")"
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  # Add brand new records with all old and new records
 | 
			
		||||
  export _H2="Content-Type: application/json"
 | 
			
		||||
  export _H1="X-Auth-Token: ${_token}"
 | 
			
		||||
 | 
			
		||||
  _debug2 "${_post_body}"
 | 
			
		||||
  _post "${_post_body}" "${dns_api}/v2/zones/${zoneid}/recordsets" >/dev/null
 | 
			
		||||
  if [ -z "${_exist_record}" ]; then
 | 
			
		||||
    _post "${_post_body}" "${dns_api}/v2/zones/${zoneid}/recordsets" >/dev/null
 | 
			
		||||
  else
 | 
			
		||||
    _post "${_post_body}" "${dns_api}/v2/zones/${zoneid}/recordsets/${_record_id}" false "PUT" >/dev/null
 | 
			
		||||
  fi
 | 
			
		||||
  _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")"
 | 
			
		||||
  if [ "$_code" != "202" ]; then
 | 
			
		||||
    _err "dns_huaweicloud: http code ${_code}"
 | 
			
		||||
@@ -253,7 +297,7 @@ _rm_record() {
 | 
			
		||||
_get_token() {
 | 
			
		||||
  _username=$1
 | 
			
		||||
  _password=$2
 | 
			
		||||
  _project=$3
 | 
			
		||||
  _domain_name=$3
 | 
			
		||||
 | 
			
		||||
  _debug "Getting Token"
 | 
			
		||||
  body="{
 | 
			
		||||
@@ -267,14 +311,14 @@ _get_token() {
 | 
			
		||||
            \"name\": \"${_username}\",
 | 
			
		||||
            \"password\": \"${_password}\",
 | 
			
		||||
            \"domain\": {
 | 
			
		||||
              \"name\": \"${_username}\"
 | 
			
		||||
              \"name\": \"${_domain_name}\"
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      \"scope\": {
 | 
			
		||||
        \"project\": {
 | 
			
		||||
          \"id\": \"${_project}\"
 | 
			
		||||
          \"name\": \"ap-southeast-1\"
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user