mirror of
				https://github.com/acmesh-official/acme.sh
				synced 2025-11-04 13:55:56 +08:00 
			
		
		
		
	Compare commits
	
		
			593 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					2068efdb38 | ||
| 
						 | 
					258ca1b434 | ||
| 
						 | 
					88bb7b780d | ||
| 
						 | 
					3805e5d37e | ||
| 
						 | 
					a2d6daaef4 | ||
| 
						 | 
					48e9006cd1 | ||
| 
						 | 
					a25a4b5d11 | ||
| 
						 | 
					309bec474f | ||
| 
						 | 
					d36440a06d | ||
| 
						 | 
					2a2f772412 | ||
| 
						 | 
					6a524bff9d | ||
| 
						 | 
					5def1169db | ||
| 
						 | 
					a07395fb56 | ||
| 
						 | 
					e25a375f43 | ||
| 
						 | 
					96801e3478 | ||
| 
						 | 
					90100aa169 | ||
| 
						 | 
					415f375ce6 | ||
| 
						 | 
					50d238b60f | ||
| 
						 | 
					5c3b41bd93 | ||
| 
						 | 
					3e0971c159 | ||
| 
						 | 
					57740fbd18 | ||
| 
						 | 
					16bc8f7040 | ||
| 
						 | 
					c145f24621 | ||
| 
						 | 
					cd3a4573f2 | ||
| 
						 | 
					8eab77f3c6 | ||
| 
						 | 
					4af339424a | ||
| 
						 | 
					4dd69a8b1a | ||
| 
						 | 
					baa1160594 | ||
| 
						 | 
					f438ff4bab | ||
| 
						 | 
					a25b2af66c | ||
| 
						 | 
					31b67ab92e | ||
| 
						 | 
					5303b36913 | ||
| 
						 | 
					a5c56c547d | ||
| 
						 | 
					ccf9a9976c | ||
| 
						 | 
					ab1efd923b | ||
| 
						 | 
					d6780f9e49 | ||
| 
						 | 
					8534e3b2f7 | ||
| 
						 | 
					8e6cf669ad | ||
| 
						 | 
					577380e98e | ||
| 
						 | 
					235b5b0c15 | ||
| 
						 | 
					aefed1d1b9 | ||
| 
						 | 
					d39649f30d | ||
| 
						 | 
					1546b7e5a9 | ||
| 
						 | 
					ff74778dea | ||
| 
						 | 
					29b21b828b | ||
| 
						 | 
					a6a0495392 | ||
| 
						 | 
					3281043e27 | ||
| 
						 | 
					f7299403f7 | ||
| 
						 | 
					a0d251a336 | ||
| 
						 | 
					8ca45d3d03 | ||
| 
						 | 
					d988542afc | ||
| 
						 | 
					4285d81ca9 | ||
| 
						 | 
					4286b2917e | ||
| 
						 | 
					d09b5cb80e | ||
| 
						 | 
					90fd18bf42 | ||
| 
						 | 
					cae6c8e5f5 | ||
| 
						 | 
					473340c53b | ||
| 
						 | 
					ae302ee600 | ||
| 
						 | 
					27934ac4ca | ||
| 
						 | 
					283ef9adb7 | ||
| 
						 | 
					377fe5ecde | ||
| 
						 | 
					c848d3ee22 | ||
| 
						 | 
					eb6be88fac | ||
| 
						 | 
					fceb728501 | ||
| 
						 | 
					a0df46258d | ||
| 
						 | 
					57d1db58db | ||
| 
						 | 
					d61b687853 | ||
| 
						 | 
					42ab7a5d72 | ||
| 
						 | 
					18cb11dcbf | ||
| 
						 | 
					e9d5407792 | ||
| 
						 | 
					a09b2c0074 | ||
| 
						 | 
					a460ac021f | ||
| 
						 | 
					bdee66fe29 | ||
| 
						 | 
					84a251c8c7 | ||
| 
						 | 
					cea763bb11 | ||
| 
						 | 
					accbda9d2f | ||
| 
						 | 
					7d64e141e4 | ||
| 
						 | 
					6a9b4db448 | ||
| 
						 | 
					e6a95ecd08 | ||
| 
						 | 
					10cb7585a7 | ||
| 
						 | 
					a577c7215f | ||
| 
						 | 
					e5244cf3c0 | ||
| 
						 | 
					c4d0aec536 | ||
| 
						 | 
					796647158e | ||
| 
						 | 
					266e9d0619 | ||
| 
						 | 
					9ec54ef89b | ||
| 
						 | 
					256cb90f3c | ||
| 
						 | 
					8f3a3b293d | ||
| 
						 | 
					975a7359a2 | ||
| 
						 | 
					ac7361a55e | ||
| 
						 | 
					bd41f50ba5 | ||
| 
						 | 
					a2038ab07e | ||
| 
						 | 
					6445a7674b | ||
| 
						 | 
					3bf2e89a1a | ||
| 
						 | 
					e6a13bf386 | ||
| 
						 | 
					42b2adc03e | ||
| 
						 | 
					f2b9af01e8 | ||
| 
						 | 
					9bd2d92755 | ||
| 
						 | 
					babe884b7c | ||
| 
						 | 
					200287254b | ||
| 
						 | 
					0b797f5964 | ||
| 
						 | 
					13a8c309f5 | ||
| 
						 | 
					528d2f29d3 | ||
| 
						 | 
					0aba5dc8de | ||
| 
						 | 
					72fcf5ab85 | ||
| 
						 | 
					dd9df068b0 | ||
| 
						 | 
					81772fb703 | ||
| 
						 | 
					6304566603 | ||
| 
						 | 
					5f8b60a0e5 | ||
| 
						 | 
					e2accaf70e | ||
| 
						 | 
					7b32bbfc26 | ||
| 
						 | 
					6963f3880d | ||
| 
						 | 
					6c3430b6e5 | ||
| 
						 | 
					c53f36a777 | ||
| 
						 | 
					bb4d378733 | ||
| 
						 | 
					333090a967 | ||
| 
						 | 
					c8f5646d53 | ||
| 
						 | 
					3002f6dfd5 | ||
| 
						 | 
					3f8a50e2ae | ||
| 
						 | 
					1a504118e5 | ||
| 
						 | 
					2e602ef6b0 | ||
| 
						 | 
					d55c3faaeb | ||
| 
						 | 
					6b185d20c0 | ||
| 
						 | 
					1bbc33a0cf | ||
| 
						 | 
					a71eba07a1 | ||
| 
						 | 
					422dd1fa4f | ||
| 
						 | 
					c4b2e5829e | ||
| 
						 | 
					1be222f6ed | ||
| 
						 | 
					5463f459e6 | ||
| 
						 | 
					14d7bfdab2 | ||
| 
						 | 
					ea722da3de | ||
| 
						 | 
					9aed1e2d17 | ||
| 
						 | 
					63c6ed3fd0 | ||
| 
						 | 
					744bfc1982 | ||
| 
						 | 
					d04434e3ec | ||
| 
						 | 
					dc3b7b5775 | ||
| 
						 | 
					17fbfd14db | ||
| 
						 | 
					d0f5aece5f | ||
| 
						 | 
					eeda3062e1 | ||
| 
						 | 
					168d712dec | ||
| 
						 | 
					e64ad5176e | ||
| 
						 | 
					0e1469f359 | ||
| 
						 | 
					7d2b6cfeaf | ||
| 
						 | 
					8e7d029946 | ||
| 
						 | 
					9dd62ae0f8 | ||
| 
						 | 
					e7dff4756f | ||
| 
						 | 
					fa98d72f3a | ||
| 
						 | 
					ccf0492890 | ||
| 
						 | 
					eb0ef6bd3d | ||
| 
						 | 
					841b762796 | ||
| 
						 | 
					63fb90806c | ||
| 
						 | 
					88ada80686 | ||
| 
						 | 
					7d5ddf5e6a | ||
| 
						 | 
					8f01919f62 | ||
| 
						 | 
					98394f99b5 | ||
| 
						 | 
					cae50e16a7 | ||
| 
						 | 
					4a2ac7bd2e | ||
| 
						 | 
					a3bdaa85f2 | ||
| 
						 | 
					40ef86f475 | ||
| 
						 | 
					4cee14f3c5 | ||
| 
						 | 
					48d9a8c180 | ||
| 
						 | 
					1d384e3192 | ||
| 
						 | 
					87f3dc4558 | ||
| 
						 | 
					8afec596aa | ||
| 
						 | 
					26e3263aec | ||
| 
						 | 
					08b4e1a744 | ||
| 
						 | 
					d68f0999a4 | ||
| 
						 | 
					2c9ed4c565 | ||
| 
						 | 
					be4f87c760 | ||
| 
						 | 
					b963dadc14 | ||
| 
						 | 
					26e7fd8b80 | ||
| 
						 | 
					b9a972bccd | ||
| 
						 | 
					bb7b9280d3 | ||
| 
						 | 
					395fbbfd14 | ||
| 
						 | 
					896dfe3def | ||
| 
						 | 
					6c4f33910c | ||
| 
						 | 
					0a301cdd21 | ||
| 
						 | 
					ce59fc6c10 | ||
| 
						 | 
					cbb74c984f | ||
| 
						 | 
					287623df58 | ||
| 
						 | 
					f8c1d97a25 | ||
| 
						 | 
					2a188905da | ||
| 
						 | 
					c2b1e38d7f | ||
| 
						 | 
					fcc0aef7f4 | ||
| 
						 | 
					eaa3de2dce | ||
| 
						 | 
					f3dc5dd12f | ||
| 
						 | 
					d2f0178fab | ||
| 
						 | 
					326c386b2e | ||
| 
						 | 
					6e68c4e2d6 | ||
| 
						 | 
					a79e96802f | ||
| 
						 | 
					65b22b493c | ||
| 
						 | 
					b73f5a4e94 | ||
| 
						 | 
					3b74ac841e | ||
| 
						 | 
					253bf776b5 | ||
| 
						 | 
					eef4acd07d | ||
| 
						 | 
					b6f00ea241 | ||
| 
						 | 
					0bd4a4f98f | ||
| 
						 | 
					0b52645bb6 | ||
| 
						 | 
					8e845d9f21 | ||
| 
						 | 
					d29aa43ba4 | ||
| 
						 | 
					450efea191 | ||
| 
						 | 
					241cfc4342 | ||
| 
						 | 
					7c67e3d7e2 | ||
| 
						 | 
					674790a511 | ||
| 
						 | 
					4e3c82e329 | ||
| 
						 | 
					df711b0ea2 | ||
| 
						 | 
					1019fd9a9d | ||
| 
						 | 
					8a420dd853 | ||
| 
						 | 
					f8bcfeb2ab | ||
| 
						 | 
					34e5beda6a | ||
| 
						 | 
					6185244754 | ||
| 
						 | 
					60d9509e39 | ||
| 
						 | 
					ded4469efe | ||
| 
						 | 
					1f95d8eedf | ||
| 
						 | 
					aa66dfff57 | ||
| 
						 | 
					25263ce40f | ||
| 
						 | 
					e85deb54e1 | ||
| 
						 | 
					4750fd159e | ||
| 
						 | 
					7eea9533e8 | ||
| 
						 | 
					ec675b9ad2 | ||
| 
						 | 
					486e77f474 | ||
| 
						 | 
					048059ba1f | ||
| 
						 | 
					ed3dda7da9 | ||
| 
						 | 
					fa93d68b08 | ||
| 
						 | 
					4e20d89d9c | ||
| 
						 | 
					b420ec6cb9 | ||
| 
						 | 
					375f6101e9 | ||
| 
						 | 
					2844d73dc7 | ||
| 
						 | 
					6c1176f853 | ||
| 
						 | 
					df037db0bb | ||
| 
						 | 
					949cc7d21b | ||
| 
						 | 
					9244529007 | ||
| 
						 | 
					319d49ddbe | ||
| 
						 | 
					96fcfdb6c6 | ||
| 
						 | 
					d61ef6b49a | ||
| 
						 | 
					804a6c8d47 | ||
| 
						 | 
					c487cd6af2 | ||
| 
						 | 
					6a2592a9d9 | ||
| 
						 | 
					0f48b15695 | ||
| 
						 | 
					4320b8a5a5 | ||
| 
						 | 
					a20707cd73 | ||
| 
						 | 
					5da1d3b73b | ||
| 
						 | 
					be15e63d41 | ||
| 
						 | 
					9bc5f686eb | ||
| 
						 | 
					5bed21dace | ||
| 
						 | 
					a97e651582 | ||
| 
						 | 
					dff641a665 | ||
| 
						 | 
					47a25cc3e8 | ||
| 
						 | 
					5e3a5f627a | ||
| 
						 | 
					9201e0a5b9 | ||
| 
						 | 
					4c80ed3208 | ||
| 
						 | 
					f34579e921 | ||
| 
						 | 
					cc1d3b20b6 | ||
| 
						 | 
					8051b6e8b6 | ||
| 
						 | 
					4c38fec3b5 | ||
| 
						 | 
					c4cdcf44c5 | ||
| 
						 | 
					347dab0c14 | ||
| 
						 | 
					a3d3ea2b4b | ||
| 
						 | 
					5332387125 | ||
| 
						 | 
					5b21cbe0de | ||
| 
						 | 
					2f4111a2e2 | ||
| 
						 | 
					326ac485b3 | ||
| 
						 | 
					f9b419d1e4 | ||
| 
						 | 
					f4e81953ce | ||
| 
						 | 
					2b09253961 | ||
| 
						 | 
					1994c6828e | ||
| 
						 | 
					f5c381d5b4 | ||
| 
						 | 
					7e2af8364f | ||
| 
						 | 
					0a2ab2aed2 | ||
| 
						 | 
					2310a9bbc0 | ||
| 
						 | 
					5b3e3d9cf4 | ||
| 
						 | 
					c97c79ab2f | ||
| 
						 | 
					1231b71245 | ||
| 
						 | 
					824ffa24f4 | ||
| 
						 | 
					148f869bec | ||
| 
						 | 
					c140fe9bae | ||
| 
						 | 
					4b02ee5b46 | ||
| 
						 | 
					de3bac53bf | ||
| 
						 | 
					3f1a76d9e4 | ||
| 
						 | 
					0138e167e9 | ||
| 
						 | 
					bcd2ee6204 | ||
| 
						 | 
					4c1d521711 | ||
| 
						 | 
					90c70fa5bf | ||
| 
						 | 
					8e15c48092 | ||
| 
						 | 
					9cf65e31cd | ||
| 
						 | 
					a6e5876d96 | ||
| 
						 | 
					937e723036 | ||
| 
						 | 
					12d876a005 | ||
| 
						 | 
					4e2426a2b4 | ||
| 
						 | 
					020f9cd2a6 | ||
| 
						 | 
					d7eebe9df0 | ||
| 
						 | 
					cebc5bf9fc | ||
| 
						 | 
					dbe68684a0 | ||
| 
						 | 
					27a05ff271 | ||
| 
						 | 
					1489ddc49a | ||
| 
						 | 
					9be2c1beb9 | ||
| 
						 | 
					8bcc19d91e | ||
| 
						 | 
					3c07f57aad | ||
| 
						 | 
					3262a916e0 | ||
| 
						 | 
					7883cc5891 | ||
| 
						 | 
					ded7a5438c | ||
| 
						 | 
					cd98951001 | ||
| 
						 | 
					8470c60e06 | ||
| 
						 | 
					394b1002b3 | ||
| 
						 | 
					9a61d6293d | ||
| 
						 | 
					192ad27f8f | ||
| 
						 | 
					eb0fc67461 | ||
| 
						 | 
					adbe5e9048 | ||
| 
						 | 
					fcdf41ba29 | ||
| 
						 | 
					7b40cbe8c1 | ||
| 
						 | 
					0933929cfe | ||
| 
						 | 
					7f618e7ecc | ||
| 
						 | 
					482cb73702 | ||
| 
						 | 
					96f79475f1 | ||
| 
						 | 
					3576754c21 | ||
| 
						 | 
					6c3a0bc72c | ||
| 
						 | 
					49d75a0cd4 | ||
| 
						 | 
					756dbac39f | ||
| 
						 | 
					7df062b7d7 | ||
| 
						 | 
					e485e8f60d | ||
| 
						 | 
					fde8ea081a | ||
| 
						 | 
					f7217c5f26 | ||
| 
						 | 
					fd77e463a1 | ||
| 
						 | 
					6d7f6750e9 | ||
| 
						 | 
					695482ded7 | ||
| 
						 | 
					fc9649dbc4 | ||
| 
						 | 
					afb67d375f | ||
| 
						 | 
					66e38ae69e | ||
| 
						 | 
					1f4e64f81d | ||
| 
						 | 
					ad541f713d | ||
| 
						 | 
					f3b434397b | ||
| 
						 | 
					1d5d49312c | ||
| 
						 | 
					232c7361a9 | ||
| 
						 | 
					721543653b | ||
| 
						 | 
					d8ba26e664 | ||
| 
						 | 
					7ecabeac97 | ||
| 
						 | 
					6cf7be4b7e | ||
| 
						 | 
					5f2e56674c | ||
| 
						 | 
					58d4c74b0b | ||
| 
						 | 
					e137792efd | ||
| 
						 | 
					b7b934913e | ||
| 
						 | 
					cd8fcbf9c6 | ||
| 
						 | 
					d0300d4443 | ||
| 
						 | 
					40acd9a4c3 | ||
| 
						 | 
					e66b4d5390 | ||
| 
						 | 
					f94433e504 | ||
| 
						 | 
					7f32488b78 | ||
| 
						 | 
					8f73e24175 | ||
| 
						 | 
					f3c984281c | ||
| 
						 | 
					00777a10ae | ||
| 
						 | 
					0d6ce9f977 | ||
| 
						 | 
					997c517ba2 | ||
| 
						 | 
					849bed4bef | ||
| 
						 | 
					61a48a5b9f | ||
| 
						 | 
					df14085ec8 | ||
| 
						 | 
					00b34eb2a4 | ||
| 
						 | 
					84a6730b1a | ||
| 
						 | 
					357b514bc9 | ||
| 
						 | 
					d39b108274 | ||
| 
						 | 
					39f3239682 | ||
| 
						 | 
					506f36b26d | ||
| 
						 | 
					4cedbf80df | ||
| 
						 | 
					b54ce31078 | ||
| 
						 | 
					9b2aa974ba | ||
| 
						 | 
					291c97dc81 | ||
| 
						 | 
					bcbecff6f6 | ||
| 
						 | 
					3d22708f67 | ||
| 
						 | 
					8afd31902f | ||
| 
						 | 
					d1a2208196 | ||
| 
						 | 
					42d1fe5422 | ||
| 
						 | 
					1424e8a2de | ||
| 
						 | 
					7dc548b4b8 | ||
| 
						 | 
					2c37d94611 | ||
| 
						 | 
					b1e4a7c615 | ||
| 
						 | 
					b0561058c6 | ||
| 
						 | 
					d039295070 | ||
| 
						 | 
					4ddafb8e84 | ||
| 
						 | 
					a536231ded | ||
| 
						 | 
					13fe54c938 | ||
| 
						 | 
					d54ffdd187 | ||
| 
						 | 
					5c539af7d7 | ||
| 
						 | 
					47d9a9cf20 | ||
| 
						 | 
					7f25205aeb | ||
| 
						 | 
					7ebecf3851 | ||
| 
						 | 
					0a5eaec0f2 | ||
| 
						 | 
					4bdab73dd5 | ||
| 
						 | 
					f19f21007c | ||
| 
						 | 
					f21dd9117d | ||
| 
						 | 
					2aa75f034f | ||
| 
						 | 
					5c78e0a462 | ||
| 
						 | 
					52cdedcba0 | ||
| 
						 | 
					c87cd0de73 | ||
| 
						 | 
					12530655df | ||
| 
						 | 
					7479706b29 | ||
| 
						 | 
					7044236824 | ||
| 
						 | 
					3e9478b58d | ||
| 
						 | 
					5ffca2d138 | ||
| 
						 | 
					a8d4a98621 | ||
| 
						 | 
					905f7f4ecc | ||
| 
						 | 
					819d2bc560 | ||
| 
						 | 
					c0b2027588 | ||
| 
						 | 
					136d1b04b5 | ||
| 
						 | 
					f063dd195e | ||
| 
						 | 
					be972fc0b5 | ||
| 
						 | 
					ac11ba3d60 | ||
| 
						 | 
					3d8598654c | ||
| 
						 | 
					55a5da2102 | ||
| 
						 | 
					f881d6c44f | ||
| 
						 | 
					5df2ca3ef3 | ||
| 
						 | 
					a15f87ae39 | ||
| 
						 | 
					0dd6377fe6 | ||
| 
						 | 
					c7257e0a3c | ||
| 
						 | 
					3b7fbcd0c3 | ||
| 
						 | 
					5fe91af6c3 | ||
| 
						 | 
					4dd646a424 | ||
| 
						 | 
					dcbd90ce04 | ||
| 
						 | 
					04683338a2 | ||
| 
						 | 
					b778f9c40e | ||
| 
						 | 
					e0a96be378 | ||
| 
						 | 
					ac690fceaf | ||
| 
						 | 
					1e5e03cc46 | ||
| 
						 | 
					d3c4cd8270 | ||
| 
						 | 
					17361df66b | ||
| 
						 | 
					7d0452c7e3 | ||
| 
						 | 
					dd0b0cae93 | ||
| 
						 | 
					c4bf5eef73 | ||
| 
						 | 
					2587639914 | ||
| 
						 | 
					bfa1ae59cc | ||
| 
						 | 
					9e8575c315 | ||
| 
						 | 
					e36340ce64 | ||
| 
						 | 
					63ec05a66c | ||
| 
						 | 
					6f1c72f5b4 | ||
| 
						 | 
					27924ffd5b | ||
| 
						 | 
					527029574c | ||
| 
						 | 
					cf3aeafcdb | ||
| 
						 | 
					f08a79d372 | ||
| 
						 | 
					eb2a26cfaa | ||
| 
						 | 
					5378d9ca26 | ||
| 
						 | 
					bce11af09a | ||
| 
						 | 
					f589a1d245 | ||
| 
						 | 
					68eb627d62 | ||
| 
						 | 
					9c87a5890d | ||
| 
						 | 
					e538a13e28 | ||
| 
						 | 
					6fb2a1ed39 | ||
| 
						 | 
					6b00787f45 | ||
| 
						 | 
					e735d8d4e5 | ||
| 
						 | 
					8cd4fd0b50 | ||
| 
						 | 
					8f4b0559ce | ||
| 
						 | 
					5288c54aad | ||
| 
						 | 
					51f8bec81b | ||
| 
						 | 
					49d3e5d324 | ||
| 
						 | 
					1fff0e5592 | ||
| 
						 | 
					8d53ec5353 | ||
| 
						 | 
					a1e1bfc71b | ||
| 
						 | 
					29992f54a3 | ||
| 
						 | 
					4ab6786163 | ||
| 
						 | 
					eaad34a69a | ||
| 
						 | 
					839f18d052 | ||
| 
						 | 
					58ef6d8385 | ||
| 
						 | 
					a0037c9333 | ||
| 
						 | 
					177b57e1c0 | ||
| 
						 | 
					810c129ca9 | ||
| 
						 | 
					f731a4c704 | ||
| 
						 | 
					39a1f1ef64 | ||
| 
						 | 
					d24a87caf1 | ||
| 
						 | 
					9683ffe13a | ||
| 
						 | 
					fab2d9dc6a | ||
| 
						 | 
					59f7a2f6ef | ||
| 
						 | 
					9b12407028 | ||
| 
						 | 
					96c4bb7fd0 | ||
| 
						 | 
					81532f375e | ||
| 
						 | 
					79eb8e2b35 | ||
| 
						 | 
					7c2e875494 | ||
| 
						 | 
					c715b4637d | ||
| 
						 | 
					c719a61ea7 | ||
| 
						 | 
					58e4d337e4 | ||
| 
						 | 
					509c802045 | ||
| 
						 | 
					4fd63f4e30 | ||
| 
						 | 
					f5c28c72fd | ||
| 
						 | 
					342128a457 | ||
| 
						 | 
					b1931828e1 | ||
| 
						 | 
					4410226db1 | ||
| 
						 | 
					945bd4b1b0 | ||
| 
						 | 
					77f1ea40cd | ||
| 
						 | 
					98c8c7ce0d | ||
| 
						 | 
					795bf9e101 | ||
| 
						 | 
					851fedf751 | ||
| 
						 | 
					5be6ab8c89 | ||
| 
						 | 
					3670412c7c | ||
| 
						 | 
					e6cd596dc9 | ||
| 
						 | 
					abf4278d09 | ||
| 
						 | 
					2b2b65fe18 | ||
| 
						 | 
					3d6a125bdc | ||
| 
						 | 
					9efd40a366 | ||
| 
						 | 
					383fa8401d | ||
| 
						 | 
					bf8ffade29 | ||
| 
						 | 
					1633d14547 | ||
| 
						 | 
					e55605dbe9 | ||
| 
						 | 
					cdec38ba12 | ||
| 
						 | 
					1cb6e9e7d0 | ||
| 
						 | 
					d1d2f6f451 | ||
| 
						 | 
					743f821f1e | ||
| 
						 | 
					b95a99e0c2 | ||
| 
						 | 
					3ebbeb103c | ||
| 
						 | 
					0d4035e996 | ||
| 
						 | 
					88ed5e506a | ||
| 
						 | 
					76a3371b40 | ||
| 
						 | 
					7b2fa1edb4 | ||
| 
						 | 
					1965035166 | ||
| 
						 | 
					76d4ff056a | ||
| 
						 | 
					a239a9efd5 | ||
| 
						 | 
					4747e7c5b9 | ||
| 
						 | 
					35ca729cb9 | ||
| 
						 | 
					a0fa7421d1 | ||
| 
						 | 
					ddf293bbcd | ||
| 
						 | 
					45d6e00ff1 | ||
| 
						 | 
					6dfc8fe0ea | ||
| 
						 | 
					96f106d6aa | ||
| 
						 | 
					044da37c95 | ||
| 
						 | 
					086444c73a | ||
| 
						 | 
					1efb2085e9 | ||
| 
						 | 
					e1c42eb6cc | ||
| 
						 | 
					a2da26cbdd | ||
| 
						 | 
					8796adfd63 | ||
| 
						 | 
					95a6c28d98 | ||
| 
						 | 
					85e1f4ea13 | ||
| 
						 | 
					d9c9114b3b | ||
| 
						 | 
					02140ce763 | ||
| 
						 | 
					af1cc3b331 | ||
| 
						 | 
					e852044b64 | ||
| 
						 | 
					f845b371ce | ||
| 
						 | 
					3a1bd3114b | ||
| 
						 | 
					a6d2e3a1e6 | ||
| 
						 | 
					93bce1b24c | ||
| 
						 | 
					7b87f29c9c | ||
| 
						 | 
					cb6f622957 | ||
| 
						 | 
					43d3b51bde | ||
| 
						 | 
					57e015155a | ||
| 
						 | 
					2436d7e0ba | ||
| 
						 | 
					e6e85b0c55 | ||
| 
						 | 
					e43fd39594 | ||
| 
						 | 
					52765466c1 | ||
| 
						 | 
					e02bede4f5 | ||
| 
						 | 
					113089be5d | ||
| 
						 | 
					dca163f54d | ||
| 
						 | 
					fc6cf4d963 | ||
| 
						 | 
					4126c7e188 | ||
| 
						 | 
					db50462920 | ||
| 
						 | 
					9310b44cef | ||
| 
						 | 
					6480250221 | ||
| 
						 | 
					b88e64f0d0 | ||
| 
						 | 
					c70432996a | ||
| 
						 | 
					c6dcf2a0e2 | ||
| 
						 | 
					2aec627503 | ||
| 
						 | 
					b7924ce58b | ||
| 
						 | 
					0bc745f68f | ||
| 
						 | 
					8acdf823a2 | ||
| 
						 | 
					52f8b787c9 | ||
| 
						 | 
					ad153ae041 | ||
| 
						 | 
					2527f8f599 | ||
| 
						 | 
					72af092cc1 | ||
| 
						 | 
					2751060b91 | ||
| 
						 | 
					b3449db2f8 | ||
| 
						 | 
					7db28745c8 | ||
| 
						 | 
					6921211461 | ||
| 
						 | 
					9f90618a70 | ||
| 
						 | 
					302c41edc9 | ||
| 
						 | 
					5d943a35f8 | ||
| 
						 | 
					03f8d6e946 | ||
| 
						 | 
					9d725af602 | ||
| 
						 | 
					3e1418d662 | ||
| 
						 | 
					884f70fb39 | ||
| 
						 | 
					9499a1142b | ||
| 
						 | 
					6e8dcdce78 | ||
| 
						 | 
					ce9fae82bd | ||
| 
						 | 
					afa3fc8bf9 | ||
| 
						 | 
					09eccf6fc0 | ||
| 
						 | 
					edfefb6763 | ||
| 
						 | 
					98b3dcbf37 | ||
| 
						 | 
					2698ef6c5f | ||
| 
						 | 
					46b2ee3bae | ||
| 
						 | 
					e7ee3a7dd5 | ||
| 
						 | 
					0085e6f83b | ||
| 
						 | 
					c90fa3bcfc | ||
| 
						 | 
					0ec9b9823f | ||
| 
						 | 
					e82ea94bb6 | ||
| 
						 | 
					a9b15f1c36 | ||
| 
						 | 
					764963e986 | ||
| 
						 | 
					22b83d7630 | ||
| 
						 | 
					0b5bff01e1 | ||
| 
						 | 
					4fe7b6cd65 | ||
| 
						 | 
					49e1f7d8bf | ||
| 
						 | 
					803fb243bf | 
@@ -26,9 +26,9 @@ install:
 | 
			
		||||
      _old_path="$PATH";
 | 
			
		||||
      echo "PATH=$PATH";
 | 
			
		||||
      export PATH="";
 | 
			
		||||
      export OPENSSL_BIN="/usr/local/openssl";
 | 
			
		||||
      export ACME_OPENSSL_BIN="/usr/local/openssl";
 | 
			
		||||
      openssl version 2>&1 || true;
 | 
			
		||||
      $OPENSSL_BIN version 2>&1 || true;
 | 
			
		||||
      $ACME_OPENSSL_BIN version 2>&1 || true;
 | 
			
		||||
      export PATH="$_old_path";
 | 
			
		||||
    fi
 | 
			
		||||
  
 | 
			
		||||
@@ -40,11 +40,11 @@ script:
 | 
			
		||||
  - if [ "$TRAVIS_OS_NAME" = "linux" ]; then ~/shfmt -l -w -i 2 . ; fi
 | 
			
		||||
  - if [ "$TRAVIS_OS_NAME" = "linux" ]; then git diff --exit-code && echo "shfmt OK" ; fi
 | 
			
		||||
  - if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -V ; fi
 | 
			
		||||
  - if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck **/*.sh && echo "shellcheck OK" ; fi
 | 
			
		||||
  - if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -e SC2181 **/*.sh && echo "shellcheck OK" ; fi
 | 
			
		||||
  - cd ..
 | 
			
		||||
  - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest
 | 
			
		||||
  - if [ "$TRAVIS_OS_NAME" = "linux" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi
 | 
			
		||||
  - if [ "$TRAVIS_OS_NAME" = "osx" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" OPENSSL_BIN="$OPENSSL_BIN" ./letest.sh ; fi
 | 
			
		||||
  - if [ "$TRAVIS_OS_NAME" = "osx" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ACME_OPENSSL_BIN="$ACME_OPENSSL_BIN" ./letest.sh ; fi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
matrix:
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										63
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
			
		||||
FROM alpine
 | 
			
		||||
 | 
			
		||||
RUN apk update -f \
 | 
			
		||||
  && apk --no-cache add -f \
 | 
			
		||||
  openssl \
 | 
			
		||||
  curl \
 | 
			
		||||
  netcat-openbsd \
 | 
			
		||||
  && rm -rf /var/cache/apk/*
 | 
			
		||||
 | 
			
		||||
ENV LE_CONFIG_HOME /acme.sh
 | 
			
		||||
 | 
			
		||||
ENV AUTO_UPGRADE 1
 | 
			
		||||
 | 
			
		||||
#Install
 | 
			
		||||
ADD ./ /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 | sed 's#> /dev/null##' | crontab -
 | 
			
		||||
 | 
			
		||||
RUN for verb in help \ 
 | 
			
		||||
  version \
 | 
			
		||||
  install \
 | 
			
		||||
  uninstall \
 | 
			
		||||
  upgrade \
 | 
			
		||||
  issue \
 | 
			
		||||
  signcsr \
 | 
			
		||||
  deploy \
 | 
			
		||||
  install-cert \
 | 
			
		||||
  renew \
 | 
			
		||||
  renew-all \
 | 
			
		||||
  revoke \
 | 
			
		||||
  remove \
 | 
			
		||||
  list \
 | 
			
		||||
  showcsr \
 | 
			
		||||
  install-cronjob \
 | 
			
		||||
  uninstall-cronjob \
 | 
			
		||||
  cron \
 | 
			
		||||
  toPkcs \
 | 
			
		||||
  toPkcs8 \
 | 
			
		||||
  update-account \
 | 
			
		||||
  register-account \
 | 
			
		||||
  create-account-key \
 | 
			
		||||
  create-domain-key \
 | 
			
		||||
  createCSR \
 | 
			
		||||
  deactivate \
 | 
			
		||||
  deactivate-account \
 | 
			
		||||
  ; do \
 | 
			
		||||
    printf -- "%b" "#!/usr/bin/env sh\n/root/.acme.sh/acme.sh --${verb} --config-home /acme.sh \"\$@\"" >/usr/local/bin/--${verb} && chmod +x /usr/local/bin/--${verb} \
 | 
			
		||||
  ; done
 | 
			
		||||
 | 
			
		||||
RUN printf "%b" '#!'"/usr/bin/env sh\n \
 | 
			
		||||
if [ \"\$1\" = \"daemon\" ];  then \n \
 | 
			
		||||
 trap \"echo stop && killall crond && exit 0\" SIGTERM SIGINT \n \
 | 
			
		||||
 crond && while true; do sleep 1; done;\n \
 | 
			
		||||
else \n \
 | 
			
		||||
 exec -- \"\$@\"\n \
 | 
			
		||||
fi" >/entry.sh && chmod +x /entry.sh
 | 
			
		||||
 | 
			
		||||
VOLUME /acme.sh
 | 
			
		||||
 | 
			
		||||
ENTRYPOINT ["/entry.sh"]
 | 
			
		||||
CMD ["--help"]
 | 
			
		||||
							
								
								
									
										130
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										130
									
								
								README.md
									
									
									
									
									
								
							@@ -1,4 +1,6 @@
 | 
			
		||||
# An ACME Shell script: acme.sh [](https://travis-ci.org/Neilpang/acme.sh)
 | 
			
		||||
 | 
			
		||||
[](https://gitter.im/acme-sh/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
 | 
			
		||||
- An ACME protocol client written purely in Shell (Unix shell) language.
 | 
			
		||||
- Full ACME protocol implementation.
 | 
			
		||||
- Simple, powerful and very easy to use. You only need 3 minutes to learn it.
 | 
			
		||||
@@ -7,17 +9,33 @@
 | 
			
		||||
- Purely written in Shell with no dependencies on python or the official Let's Encrypt client.
 | 
			
		||||
- Just one script to issue, renew and install your certificates automatically.
 | 
			
		||||
- DOES NOT require `root/sudoer` access.
 | 
			
		||||
- Docker friendly
 | 
			
		||||
- IPv6 support
 | 
			
		||||
 | 
			
		||||
It's probably the `easiest&smallest&smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt.
 | 
			
		||||
It's probably the `easiest & smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt.
 | 
			
		||||
 | 
			
		||||
Wiki: https://github.com/Neilpang/acme.sh/wiki
 | 
			
		||||
 | 
			
		||||
For Docker Fans: [acme.sh :two_hearts: Docker ](https://github.com/Neilpang/acme.sh/wiki/Run-acme.sh-in-docker)
 | 
			
		||||
 | 
			
		||||
Twitter: [@neilpangxa](https://twitter.com/neilpangxa)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# [中文说明](https://github.com/Neilpang/acme.sh/wiki/%E8%AF%B4%E6%98%8E)
 | 
			
		||||
 | 
			
		||||
# Who are using **acme.sh**
 | 
			
		||||
- [FreeBSD.org](https://blog.crashed.org/letsencrypt-in-freebsd-org/)
 | 
			
		||||
- [ruby-china.org](https://ruby-china.org/topics/31983)
 | 
			
		||||
- [Proxmox](https://pve.proxmox.com/wiki/HTTPS_Certificate_Configuration_(Version_4.x_and_newer))
 | 
			
		||||
- [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](http://centminmod.com/letsencrypt-acmetool-https.html)
 | 
			
		||||
- [splynx](https://forum.splynx.com/t/free-ssl-cert-for-splynx-lets-encrypt/297)
 | 
			
		||||
- [archlinux](https://aur.archlinux.org/packages/acme.sh-git/)
 | 
			
		||||
- [opnsense.org](https://github.com/opnsense/plugins/tree/master/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient)
 | 
			
		||||
- [more...](https://github.com/Neilpang/acme.sh/wiki/Blogs-and-tutorials)
 | 
			
		||||
 | 
			
		||||
# Tested OS
 | 
			
		||||
 | 
			
		||||
@@ -44,7 +62,7 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa)
 | 
			
		||||
|19|[](https://github.com/Neilpang/letest#here-are-the-latest-status)|Gentoo Linux
 | 
			
		||||
|20|[](https://travis-ci.org/Neilpang/acme.sh)|Mac OSX
 | 
			
		||||
 | 
			
		||||
For all build statuses, check our [daily build project](https://github.com/Neilpang/acmetest):
 | 
			
		||||
For all build statuses, check our [weekly build project](https://github.com/Neilpang/acmetest):
 | 
			
		||||
 | 
			
		||||
https://github.com/Neilpang/acmetest
 | 
			
		||||
 | 
			
		||||
@@ -54,6 +72,7 @@ https://github.com/Neilpang/acmetest
 | 
			
		||||
- Webroot mode
 | 
			
		||||
- Standalone mode
 | 
			
		||||
- Apache mode
 | 
			
		||||
- Nginx mode ( Beta )
 | 
			
		||||
- DNS mode
 | 
			
		||||
- [Stateless mode](https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode)
 | 
			
		||||
 | 
			
		||||
@@ -120,13 +139,25 @@ root@v1:~# acme.sh -h
 | 
			
		||||
acme.sh --issue -d example.com -w /home/wwwroot/example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
or:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
acme.sh --issue -d example.com -w /home/username/public_html
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
or:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
acme.sh --issue -d example.com -w /var/www/html
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Example 2:** Multiple domains in the same cert.
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
acme.sh --issue -d example.com -d www.example.com -d cp.example.com -w /home/wwwroot/example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The parameter `/home/wwwroot/example.com` is the web root folder. You **MUST** have `write access` to this folder.
 | 
			
		||||
The parameter `/home/wwwroot/example.com` or `/home/username/public_html` or `/var/www/html` is the web root folder where you host your website files. You **MUST** have `write access` to this folder.
 | 
			
		||||
 | 
			
		||||
Second argument **"example.com"** is the main domain you want to issue the cert for.
 | 
			
		||||
You must have at least one domain there.
 | 
			
		||||
@@ -148,17 +179,17 @@ You **MUST** use this command to copy the certs to the target files, **DO NOT**
 | 
			
		||||
**Apache** example:
 | 
			
		||||
```bash
 | 
			
		||||
acme.sh --install-cert -d example.com \
 | 
			
		||||
--certpath      /path/to/certfile/in/apache/cert.pem  \
 | 
			
		||||
--keypath       /path/to/keyfile/in/apache/key.pem  \
 | 
			
		||||
--fullchainpath /path/to/fullchain/certfile/apache/fullchain.pem \
 | 
			
		||||
--cert-file      /path/to/certfile/in/apache/cert.pem  \
 | 
			
		||||
--key-file       /path/to/keyfile/in/apache/key.pem  \
 | 
			
		||||
--fullchain-file /path/to/fullchain/certfile/apache/fullchain.pem \
 | 
			
		||||
--reloadcmd     "service apache2 force-reload"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Nginx** example:
 | 
			
		||||
```bash
 | 
			
		||||
acme.sh --install-cert -d example.com \
 | 
			
		||||
--keypath       /path/to/keyfile/in/nginx/key.pem  \
 | 
			
		||||
--fullchainpath /path/to/fullchain/nginx/cert.pem \
 | 
			
		||||
--key-file       /path/to/keyfile/in/nginx/key.pem  \
 | 
			
		||||
--fullchain-file /path/to/fullchain/nginx/cert.pem \
 | 
			
		||||
--reloadcmd     "service nginx force-reload"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
@@ -168,7 +199,7 @@ The ownership and permission info of existing files are preserved. You may want
 | 
			
		||||
 | 
			
		||||
Install/copy the issued cert/key to the production Apache or Nginx path.
 | 
			
		||||
 | 
			
		||||
The cert will be `renewed every **60** days by default` (which is configurable). Once the cert is renewed, the Apache/Nginx service will be restarted automatically by the command: `service apache2 restart` or `service nginx restart`.
 | 
			
		||||
The cert will be renewed every **60** days by default (which is configurable). Once the cert is renewed, the Apache/Nginx service will be reloaded automatically by the command: `service apache2 force-reload` or `service nginx force-reload`.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 4. Use Standalone server to issue cert
 | 
			
		||||
@@ -215,8 +246,27 @@ acme.sh --issue --apache -d example.com -d www.example.com -d cp.example.com
 | 
			
		||||
 | 
			
		||||
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
 | 
			
		||||
 | 
			
		||||
# 7. Use Nginx mode
 | 
			
		||||
 | 
			
		||||
# 7. Use DNS mode:
 | 
			
		||||
**(requires you to be root/sudoer, since it is required to interact with Nginx server)**
 | 
			
		||||
 | 
			
		||||
If you are running a web server, Apache or Nginx, it is recommended to use the `Webroot mode`.
 | 
			
		||||
 | 
			
		||||
Particularly, if you are running an nginx server, you can use nginx mode instead. This mode doesn't write any files to your web root folder.
 | 
			
		||||
 | 
			
		||||
Just set string "nginx" as the second argument.
 | 
			
		||||
 | 
			
		||||
It will configure nginx server automatically to verify the domain and then restore the nginx config to the original version.
 | 
			
		||||
 | 
			
		||||
So, the config is not changed.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
acme.sh --issue --nginx -d example.com -d www.example.com -d cp.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
 | 
			
		||||
 | 
			
		||||
# 8. Use DNS mode:
 | 
			
		||||
 | 
			
		||||
Support the `dns-01` challenge.
 | 
			
		||||
 | 
			
		||||
@@ -246,8 +296,11 @@ acme.sh --renew -d example.com
 | 
			
		||||
 | 
			
		||||
Ok, it's finished.
 | 
			
		||||
 | 
			
		||||
**Take care, this is dns manual mode, it can not be renewed automatically. you will have to add a new txt record to your domain by your hand when you renew your cert.**
 | 
			
		||||
 | 
			
		||||
# 8. Automatic DNS API integration
 | 
			
		||||
**Please use dns api mode instead.**
 | 
			
		||||
 | 
			
		||||
# 9. Automatic DNS API integration
 | 
			
		||||
 | 
			
		||||
If your DNS provider supports API access, we can use that API to automatically issue the certs.
 | 
			
		||||
 | 
			
		||||
@@ -259,20 +312,42 @@ You don't have to do anything manually!
 | 
			
		||||
1. DNSPod.cn API
 | 
			
		||||
1. CloudXNS.com API
 | 
			
		||||
1. GoDaddy.com API
 | 
			
		||||
1. OVH, kimsufi, soyoustart and runabove API
 | 
			
		||||
1. AWS Route 53
 | 
			
		||||
1. PowerDNS.com API
 | 
			
		||||
1. lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api
 | 
			
		||||
   (DigitalOcean, DNSimple, DNSMadeEasy, DNSPark, EasyDNS, Namesilo, NS1, PointHQ, Rage4 and Vultr etc.)
 | 
			
		||||
1. OVH, kimsufi, soyoustart and runabove API
 | 
			
		||||
1. nsupdate API
 | 
			
		||||
1. LuaDNS.com API
 | 
			
		||||
1. DNSMadeEasy.com API
 | 
			
		||||
1. nsupdate API
 | 
			
		||||
1. AWS Route 53
 | 
			
		||||
1. aliyun.com(阿里云) API
 | 
			
		||||
1. ISPConfig 3.1 API
 | 
			
		||||
1. Alwaysdata.com API
 | 
			
		||||
1. Linode.com API
 | 
			
		||||
1. FreeDNS (https://freedns.afraid.org/)
 | 
			
		||||
1. cyon.ch
 | 
			
		||||
1. Domain-Offensive/Resellerinterface/Domainrobot API
 | 
			
		||||
1. Gandi LiveDNS API
 | 
			
		||||
1. Knot DNS API
 | 
			
		||||
1. DigitalOcean API (native)
 | 
			
		||||
1. ClouDNS.net API
 | 
			
		||||
1. Infoblox NIOS API (https://www.infoblox.com/)
 | 
			
		||||
1. VSCALE (https://vscale.io/)
 | 
			
		||||
1. Dynu API (https://www.dynu.com)
 | 
			
		||||
1. DNSimple API
 | 
			
		||||
1. NS1.com API
 | 
			
		||||
1. DuckDNS.org API
 | 
			
		||||
1. Name.com API
 | 
			
		||||
1. Dyn Managed DNS API
 | 
			
		||||
1. Yandex PDD API (https://pdd.yandex.ru)
 | 
			
		||||
1. Hurricane Electric DNS service (https://dns.he.net)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
And: 
 | 
			
		||||
 | 
			
		||||
1. lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api
 | 
			
		||||
   (DigitalOcean, DNSimple, DNSMadeEasy, DNSPark, EasyDNS, Namesilo, NS1, PointHQ, Rage4 and Vultr etc.)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
   
 | 
			
		||||
**More APIs coming soon...**
 | 
			
		||||
 | 
			
		||||
If your DNS provider is not on the supported list above, you can write your own DNS API script easily. If you do, please consider submitting a [Pull Request](https://github.com/Neilpang/acme.sh/pulls) and contribute it to the project.
 | 
			
		||||
@@ -280,7 +355,7 @@ If your DNS provider is not on the supported list above, you can write your own
 | 
			
		||||
For more details: [How to use DNS API](dnsapi)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 9. Issue ECC certificates
 | 
			
		||||
# 10. Issue ECC certificates
 | 
			
		||||
 | 
			
		||||
`Let's Encrypt` can now issue **ECDSA** certificates.
 | 
			
		||||
 | 
			
		||||
@@ -290,7 +365,7 @@ Just set the `length` parameter with a prefix `ec-`.
 | 
			
		||||
 | 
			
		||||
For example:
 | 
			
		||||
 | 
			
		||||
### Single domain ECC cerfiticate
 | 
			
		||||
### Single domain ECC certificate
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
acme.sh --issue -w /home/wwwroot/example.com -d example.com --keylength ec-256
 | 
			
		||||
@@ -311,7 +386,7 @@ Valid values are:
 | 
			
		||||
3. **ec-521 (secp521r1,  "ECDSA P-521", which is not supported by Let's Encrypt yet.)**
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 10. How to renew the issued certs
 | 
			
		||||
# 11. How to renew the issued certs
 | 
			
		||||
 | 
			
		||||
No, you don't need to renew the certs manually. All the certs will be renewed automatically every **60** days.
 | 
			
		||||
 | 
			
		||||
@@ -328,7 +403,7 @@ acme.sh --renew -d example.com --force --ecc
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 11. How to upgrade `acme.sh`
 | 
			
		||||
# 12. How to upgrade `acme.sh`
 | 
			
		||||
 | 
			
		||||
acme.sh is in constant development, so it's strongly recommended to use the latest code.
 | 
			
		||||
 | 
			
		||||
@@ -353,26 +428,26 @@ acme.sh --upgrade --auto-upgrade 0
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 12. Issue a cert from an existing CSR
 | 
			
		||||
# 13. Issue a cert from an existing CSR
 | 
			
		||||
 | 
			
		||||
https://github.com/Neilpang/acme.sh/wiki/Issue-a-cert-from-existing-CSR
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Under the Hood
 | 
			
		||||
# 14. Under the Hood
 | 
			
		||||
 | 
			
		||||
Speak ACME language using shell, directly to "Let's Encrypt".
 | 
			
		||||
 | 
			
		||||
TODO:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Acknowledgments
 | 
			
		||||
# 15. Acknowledgments
 | 
			
		||||
 | 
			
		||||
1. Acme-tiny: https://github.com/diafygi/acme-tiny
 | 
			
		||||
2. ACME protocol: https://github.com/ietf-wg-acme/acme
 | 
			
		||||
3. Certbot: https://github.com/certbot/certbot
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# License & Others
 | 
			
		||||
# 16. License & Others
 | 
			
		||||
 | 
			
		||||
License is GPLv3
 | 
			
		||||
 | 
			
		||||
@@ -381,8 +456,9 @@ Please Star and Fork me.
 | 
			
		||||
[Issues](https://github.com/Neilpang/acme.sh/issues) and [pull requests](https://github.com/Neilpang/acme.sh/pulls) are welcome.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Donate
 | 
			
		||||
 | 
			
		||||
1. PayPal: donate@acme.sh
 | 
			
		||||
# 17. Donate
 | 
			
		||||
Your donation makes **acme.sh** better:
 | 
			
		||||
 | 
			
		||||
1. PayPal/Alipay(支付宝)/Wechat(微信): [https://donate.acme.sh/](https://donate.acme.sh/)
 | 
			
		||||
  
 | 
			
		||||
[Donate List](https://github.com/Neilpang/acme.sh/wiki/Donate-list)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,30 +1,100 @@
 | 
			
		||||
# Using deploy api
 | 
			
		||||
 | 
			
		||||
Before you can deploy your cert, you must [issue the cert first](https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert).
 | 
			
		||||
 | 
			
		||||
Here are the scripts to deploy the certs/key to the server/services.
 | 
			
		||||
 | 
			
		||||
## 1. Deploy the certs to your cpanel host.
 | 
			
		||||
 | 
			
		||||
(cpanel deploy hook is not finished yet, this is just an example.)
 | 
			
		||||
 | 
			
		||||
Before you can deploy your cert, you must [issue the cert first](https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Then you can deploy now:
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
export DEPLOY_CPANEL_USER=myusername
 | 
			
		||||
export DEPLOY_CPANEL_PASSWORD=PASSWORD
 | 
			
		||||
acme.sh --deploy -d example.com --deploy --deploy-hook cpanel
 | 
			
		||||
acme.sh --deploy -d example.com --deploy-hook cpanel
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## 2. Deploy ssl cert on kong proxy engine based on api.
 | 
			
		||||
 | 
			
		||||
Before you can deploy your cert, you must [issue the cert first](https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert).
 | 
			
		||||
Currently supports Kong-v0.10.x.
 | 
			
		||||
 | 
			
		||||
(TODO)
 | 
			
		||||
```sh
 | 
			
		||||
acme.sh --deploy -d ftp.example.com --deploy-hook kong
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## 3. Deploy the cert to remote server through SSH access.
 | 
			
		||||
 | 
			
		||||
(TODO)
 | 
			
		||||
 | 
			
		||||
## 4. Deploy the cert to local vsftpd server.
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The default vsftpd conf file is `/etc/vsftpd.conf`,  if your vsftpd conf is not in the default location, you can specify one:
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
export DEPLOY_VSFTPD_CONF="/etc/vsftpd.conf"
 | 
			
		||||
 | 
			
		||||
acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The default command to restart vsftpd server is `service vsftpd restart`, if it doesn't work, you can specify one:
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
export DEPLOY_VSFTPD_RELOAD="/etc/init.d/vsftpd restart"
 | 
			
		||||
 | 
			
		||||
acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## 5. Deploy the cert to local exim4 server.
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
acme.sh --deploy -d ftp.example.com --deploy-hook exim4
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The default exim4 conf file is `/etc/exim/exim.conf`,  if your exim4 conf is not in the default location, you can specify one:
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
export DEPLOY_EXIM4_CONF="/etc/exim4/exim4.conf.template"
 | 
			
		||||
 | 
			
		||||
acme.sh --deploy -d ftp.example.com --deploy-hook exim4
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The default command to restart exim4 server is `service exim4 restart`, if it doesn't work, you can specify one:
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
export DEPLOY_EXIM4_RELOAD="/etc/init.d/exim4 restart"
 | 
			
		||||
 | 
			
		||||
acme.sh --deploy -d ftp.example.com --deploy-hook exim4
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## 6. Deploy the cert to OSX Keychain
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
acme.sh --deploy -d ftp.example.com --deploy-hook keychain
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## 7. Deploy to cpanel host.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
acme.sh  --deploy  -d example.com  --deploy-hook cpanel_uapi
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
If you are login as root, please specify the username to deploy cert to:
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
export DEPLOY_CPANEL_USER=username
 | 
			
		||||
acme.sh  --deploy  -d example.com  --deploy-hook cpanel_uapi
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										26
									
								
								deploy/apache.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								deploy/apache.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#Here is a script to deploy cert to apache server.
 | 
			
		||||
 | 
			
		||||
#returns 0 means success, otherwise error.
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#domain keyfile certfile cafile fullchain
 | 
			
		||||
apache_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"
 | 
			
		||||
 | 
			
		||||
  _err "Deploy cert to apache server, Not implemented yet"
 | 
			
		||||
  return 1
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										64
									
								
								deploy/cpanel_uapi.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								deploy/cpanel_uapi.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# Here is the script to deploy the cert to your cpanel using the cpanel API.
 | 
			
		||||
# Uses command line uapi.  --user option is needed only if run as root.
 | 
			
		||||
# Returns 0 when success.
 | 
			
		||||
# Written by Santeri Kannisto <santeri.kannisto@2globalnomads.info>
 | 
			
		||||
# Public domain, 2017
 | 
			
		||||
 | 
			
		||||
#export DEPLOY_CPANEL_USER=myusername
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#domain keyfile certfile cafile fullchain
 | 
			
		||||
 | 
			
		||||
cpanel_uapi_deploy() {
 | 
			
		||||
  _cdomain="$1"
 | 
			
		||||
  _ckey="$2"
 | 
			
		||||
  _ccert="$3"
 | 
			
		||||
  _cca="$4"
 | 
			
		||||
  _cfullchain="$5"
 | 
			
		||||
 | 
			
		||||
  _debug _cdomain "$_cdomain"
 | 
			
		||||
  _debug _ckey "$_ckey"
 | 
			
		||||
  _debug _ccert "$_ccert"
 | 
			
		||||
  _debug _cca "$_cca"
 | 
			
		||||
  _debug _cfullchain "$_cfullchain"
 | 
			
		||||
 | 
			
		||||
  if ! _exists uapi; then
 | 
			
		||||
    _err "The command uapi is not found."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  if ! _exists php; then
 | 
			
		||||
    _err "The command php is not found."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  # read cert and key files and urlencode both
 | 
			
		||||
  _certstr=$(cat "$_ccert")
 | 
			
		||||
  _keystr=$(cat "$_ckey")
 | 
			
		||||
  _cert=$(php -r "echo urlencode(\"$_certstr\");")
 | 
			
		||||
  _key=$(php -r "echo urlencode(\"$_keystr\");")
 | 
			
		||||
 | 
			
		||||
  _debug _cert "$_cert"
 | 
			
		||||
  _debug _key "$_key"
 | 
			
		||||
 | 
			
		||||
  if [ "$(id -u)" = 0 ]; then
 | 
			
		||||
    if [ -z "$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
 | 
			
		||||
 | 
			
		||||
  if [ $? -ne 0 ]; then
 | 
			
		||||
    _err "Error in deploying certificate:"
 | 
			
		||||
    _err "$_response"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug response "$_response"
 | 
			
		||||
  _info "Certificate successfully deployed"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
@@ -1,16 +1,13 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#Here is the script to deploy the cert to your cpanel account by the cpanel APIs.
 | 
			
		||||
#Here is a script to deploy cert to dovecot server.
 | 
			
		||||
 | 
			
		||||
#returns 0 means success, otherwise error.
 | 
			
		||||
 | 
			
		||||
#export DEPLOY_CPANEL_USER=myusername
 | 
			
		||||
#export DEPLOY_CPANEL_PASSWORD=PASSWORD
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#domain keyfile certfile cafile fullchain
 | 
			
		||||
cpanel_deploy() {
 | 
			
		||||
dovecot_deploy() {
 | 
			
		||||
  _cdomain="$1"
 | 
			
		||||
  _ckey="$2"
 | 
			
		||||
  _ccert="$3"
 | 
			
		||||
							
								
								
									
										114
									
								
								deploy/exim4.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								deploy/exim4.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,114 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#Here is a script to deploy cert to exim4 server.
 | 
			
		||||
 | 
			
		||||
#returns 0 means success, otherwise error.
 | 
			
		||||
 | 
			
		||||
#DEPLOY_EXIM4_CONF="/etc/exim/exim.conf"
 | 
			
		||||
#DEPLOY_EXIM4_RELOAD="service exim4 restart"
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#domain keyfile certfile cafile fullchain
 | 
			
		||||
exim4_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"
 | 
			
		||||
 | 
			
		||||
  _ssl_path="/etc/acme.sh/exim4"
 | 
			
		||||
  if ! mkdir -p "$_ssl_path"; then
 | 
			
		||||
    _err "Can not create folder:$_ssl_path"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Copying key and cert"
 | 
			
		||||
  _real_key="$_ssl_path/exim4.key"
 | 
			
		||||
  if ! cat "$_ckey" >"$_real_key"; then
 | 
			
		||||
    _err "Error: write key file to: $_real_key"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _real_fullchain="$_ssl_path/exim4.pem"
 | 
			
		||||
  if ! cat "$_cfullchain" >"$_real_fullchain"; then
 | 
			
		||||
    _err "Error: write key file to: $_real_fullchain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  DEFAULT_EXIM4_RELOAD="service exim4 restart"
 | 
			
		||||
  _reload="${DEPLOY_EXIM4_RELOAD:-$DEFAULT_EXIM4_RELOAD}"
 | 
			
		||||
 | 
			
		||||
  if [ -z "$IS_RENEW" ]; then
 | 
			
		||||
    DEFAULT_EXIM4_CONF="/etc/exim/exim.conf"
 | 
			
		||||
    if [ ! -f "$DEFAULT_EXIM4_CONF" ]; then
 | 
			
		||||
      DEFAULT_EXIM4_CONF="/etc/exim4/exim4.conf.template"
 | 
			
		||||
    fi
 | 
			
		||||
    _exim4_conf="${DEPLOY_EXIM4_CONF:-$DEFAULT_EXIM4_CONF}"
 | 
			
		||||
    _debug _exim4_conf "$_exim4_conf"
 | 
			
		||||
    if [ ! -f "$_exim4_conf" ]; then
 | 
			
		||||
      if [ -z "$DEPLOY_EXIM4_CONF" ]; then
 | 
			
		||||
        _err "exim4 conf is not found, please define DEPLOY_EXIM4_CONF"
 | 
			
		||||
        return 1
 | 
			
		||||
      else
 | 
			
		||||
        _err "It seems that the specified exim4 conf is not valid, please check."
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
    if [ ! -w "$_exim4_conf" ]; then
 | 
			
		||||
      _err "The file $_exim4_conf is not writable, please change the permission."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    _backup_conf="$DOMAIN_BACKUP_PATH/exim4.conf.bak"
 | 
			
		||||
    _info "Backup $_exim4_conf to $_backup_conf"
 | 
			
		||||
    cp "$_exim4_conf" "$_backup_conf"
 | 
			
		||||
 | 
			
		||||
    _info "Modify exim4 conf: $_exim4_conf"
 | 
			
		||||
    if _setopt "$_exim4_conf" "tls_certificate" "=" "$_real_fullchain" \
 | 
			
		||||
      && _setopt "$_exim4_conf" "tls_privatekey" "=" "$_real_key"; then
 | 
			
		||||
      _info "Set config success!"
 | 
			
		||||
    else
 | 
			
		||||
      _err "Config exim4 server error, please report bug to us."
 | 
			
		||||
      _info "Restoring exim4 conf"
 | 
			
		||||
      if cat "$_backup_conf" >"$_exim4_conf"; then
 | 
			
		||||
        _info "Restore conf success"
 | 
			
		||||
        eval "$_reload"
 | 
			
		||||
      else
 | 
			
		||||
        _err "Oops, error restore exim4 conf, please report bug to us."
 | 
			
		||||
      fi
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Run reload: $_reload"
 | 
			
		||||
  if eval "$_reload"; then
 | 
			
		||||
    _info "Reload success!"
 | 
			
		||||
    if [ "$DEPLOY_EXIM4_CONF" ]; then
 | 
			
		||||
      _savedomainconf DEPLOY_EXIM4_CONF "$DEPLOY_EXIM4_CONF"
 | 
			
		||||
    else
 | 
			
		||||
      _cleardomainconf DEPLOY_EXIM4_CONF
 | 
			
		||||
    fi
 | 
			
		||||
    if [ "$DEPLOY_EXIM4_RELOAD" ]; then
 | 
			
		||||
      _savedomainconf DEPLOY_EXIM4_RELOAD "$DEPLOY_EXIM4_RELOAD"
 | 
			
		||||
    else
 | 
			
		||||
      _cleardomainconf DEPLOY_EXIM4_RELOAD
 | 
			
		||||
    fi
 | 
			
		||||
    return 0
 | 
			
		||||
  else
 | 
			
		||||
    _err "Reload error, restoring"
 | 
			
		||||
    if cat "$_backup_conf" >"$_exim4_conf"; then
 | 
			
		||||
      _info "Restore conf success"
 | 
			
		||||
      eval "$_reload"
 | 
			
		||||
    else
 | 
			
		||||
      _err "Oops, error restore exim4 conf, please report bug to us."
 | 
			
		||||
    fi
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  return 0
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								deploy/haproxy.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								deploy/haproxy.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#Here is a script to deploy cert to haproxy server.
 | 
			
		||||
 | 
			
		||||
#returns 0 means success, otherwise error.
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#domain keyfile certfile cafile fullchain
 | 
			
		||||
haproxy_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"
 | 
			
		||||
 | 
			
		||||
  _err "deploy cert to haproxy server, Not implemented yet"
 | 
			
		||||
  return 1
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										31
									
								
								deploy/keychain.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								deploy/keychain.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#Here is a sample custom api script.
 | 
			
		||||
#This file name is "myapi.sh"
 | 
			
		||||
#So, here must be a method   myapi_deploy()
 | 
			
		||||
#Which will be called by acme.sh to deploy the cert
 | 
			
		||||
#returns 0 means success, otherwise error.
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#domain keyfile certfile cafile fullchain
 | 
			
		||||
keychain_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"
 | 
			
		||||
 | 
			
		||||
  /usr/bin/security import "$_ckey" -k "/Library/Keychains/System.keychain"
 | 
			
		||||
  /usr/bin/security import "$_ccert" -k "/Library/Keychains/System.keychain"
 | 
			
		||||
  /usr/bin/security import "$_cca" -k "/Library/Keychains/System.keychain"
 | 
			
		||||
  /usr/bin/security import "$_cfullchain" -k "/Library/Keychains/System.keychain"
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
@@ -1,13 +1,7 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
# This deploy hook will deploy ssl cert on kong proxy engine based on api request_host parameter.
 | 
			
		||||
# Note that ssl plugin should be available on Kong instance
 | 
			
		||||
# The hook will match cdomain to request_host, in case of multiple domain it will always take the first
 | 
			
		||||
# one (acme.sh behaviour).
 | 
			
		||||
# If ssl config already exist it will update only cert and key not touching other parameter
 | 
			
		||||
# If ssl config doesn't exist it will only upload cert and key and not set other parameter
 | 
			
		||||
# Not that we deploy full chain
 | 
			
		||||
# See https://getkong.org/plugins/dynamic-ssl/ for other options
 | 
			
		||||
# If certificate already exist it will update only cert and key not touching other parameter
 | 
			
		||||
# If certificate  doesn't exist it will only upload cert and key and not set other parameter
 | 
			
		||||
# Note that we deploy full chain
 | 
			
		||||
# Written by Geoffroi Genot <ggenot@voxbone.com>
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
@@ -31,29 +25,32 @@ kong_deploy() {
 | 
			
		||||
  _debug _cca "$_cca"
 | 
			
		||||
  _debug _cfullchain "$_cfullchain"
 | 
			
		||||
 | 
			
		||||
  #Get uuid linked to the domain
 | 
			
		||||
  uuid=$(_get "$KONG_URL/apis?request_host=$_cdomain" | _normalizeJson | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}')
 | 
			
		||||
  if [ -z "$uuid" ]; then
 | 
			
		||||
    _err "Unable to get Kong uuid for domain $_cdomain"
 | 
			
		||||
    _err "Make sure that KONG_URL is correctly configured"
 | 
			
		||||
    _err "Make sure that a Kong api request_host match the domain"
 | 
			
		||||
    _err "Kong url: $KONG_URL"
 | 
			
		||||
    return 1
 | 
			
		||||
  #Get ssl_uuid linked to the domain
 | 
			
		||||
  ssl_uuid=$(_get "$KONG_URL/certificates/$_cdomain" | _normalizeJson | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}')
 | 
			
		||||
  if [ -z "$ssl_uuid" ]; then
 | 
			
		||||
    _debug "Unable to get Kong ssl_uuid for domain $_cdomain"
 | 
			
		||||
    _debug "Make sure that KONG_URL is correctly configured"
 | 
			
		||||
    _debug "Make sure that a Kong certificate match the sni"
 | 
			
		||||
    _debug "Kong url: $KONG_URL"
 | 
			
		||||
    _info "No existing certificate, creating..."
 | 
			
		||||
    #return 1
 | 
			
		||||
  fi
 | 
			
		||||
  #Save kong url if it's succesful (First run case)
 | 
			
		||||
  _saveaccountconf KONG_URL "$KONG_URL"
 | 
			
		||||
  #Generate DEIM
 | 
			
		||||
  delim="-----MultipartDelimeter$(date "+%s%N")"
 | 
			
		||||
  delim="-----MultipartDelimiter$(date "+%s%N")"
 | 
			
		||||
  nl="\015\012"
 | 
			
		||||
  #Set Header
 | 
			
		||||
  _H1="Content-Type: multipart/form-data; boundary=$delim"
 | 
			
		||||
  #Generate data for request (Multipart/form-data with mixed content)
 | 
			
		||||
  #set name to ssl
 | 
			
		||||
  content="--$delim${nl}Content-Disposition: form-data; name=\"name\"${nl}${nl}ssl"
 | 
			
		||||
  if [ -z "$ssl_uuid" ]; then
 | 
			
		||||
    #set sni to domain
 | 
			
		||||
    content="--$delim${nl}Content-Disposition: form-data; name=\"snis\"${nl}${nl}$_cdomain"
 | 
			
		||||
  fi
 | 
			
		||||
  #add key
 | 
			
		||||
  content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"config.key\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")"
 | 
			
		||||
  content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")"
 | 
			
		||||
  #Add cert
 | 
			
		||||
  content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"config.cert\"; filename=\"$(basename "$_cfullchain")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_cfullchain")"
 | 
			
		||||
  content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"cert\"; filename=\"$(basename "$_cfullchain")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_cfullchain")"
 | 
			
		||||
  #Close multipart
 | 
			
		||||
  content="$content${nl}--$delim--${nl}"
 | 
			
		||||
  #Convert CRLF
 | 
			
		||||
@@ -61,18 +58,17 @@ kong_deploy() {
 | 
			
		||||
  #DEBUG
 | 
			
		||||
  _debug header "$_H1"
 | 
			
		||||
  _debug content "$content"
 | 
			
		||||
  #Check if ssl plugins is aready enabled (if not => POST else => PATCH)
 | 
			
		||||
  ssl_uuid=$(_get "$KONG_URL/apis/$uuid/plugins" | _egrep_o '"id":"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"[a-zA-Z0-9\-\,\"_\:]*"name":"ssl"' | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}')
 | 
			
		||||
  _debug ssl_uuid "$ssl_uuid"
 | 
			
		||||
  #Check if sslcreated (if not => POST else => PATCH)
 | 
			
		||||
 | 
			
		||||
  if [ -z "$ssl_uuid" ]; then
 | 
			
		||||
    #Post certificate to Kong
 | 
			
		||||
    response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins" "" "POST")
 | 
			
		||||
    response=$(_post "$content" "$KONG_URL/certificates" "" "POST")
 | 
			
		||||
  else
 | 
			
		||||
    #patch
 | 
			
		||||
    response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins/$ssl_uuid" "" "PATCH")
 | 
			
		||||
    response=$(_post "$content" "$KONG_URL/certificates/$ssl_uuid" "" "PATCH")
 | 
			
		||||
  fi
 | 
			
		||||
  if ! [ "$(echo "$response" | _egrep_o "ssl")" = "ssl" ]; then
 | 
			
		||||
    _err "An error occured with cert upload. Check response:"
 | 
			
		||||
  if ! [ "$(echo "$response" | _egrep_o "created_at")" = "created_at" ]; then
 | 
			
		||||
    _err "An error occurred with cert upload. Check response:"
 | 
			
		||||
    _err "$response"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										26
									
								
								deploy/mysqld.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								deploy/mysqld.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#Here is a script to deploy cert to mysqld server.
 | 
			
		||||
 | 
			
		||||
#returns 0 means success, otherwise error.
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#domain keyfile certfile cafile fullchain
 | 
			
		||||
mysqld_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"
 | 
			
		||||
 | 
			
		||||
  _err "deploy cert to mysqld server, Not implemented yet"
 | 
			
		||||
  return 1
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								deploy/nginx.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								deploy/nginx.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#Here is a script to deploy cert to nginx server.
 | 
			
		||||
 | 
			
		||||
#returns 0 means success, otherwise error.
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#domain keyfile certfile cafile fullchain
 | 
			
		||||
nginx_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"
 | 
			
		||||
 | 
			
		||||
  _err "deploy cert to nginx server, Not implemented yet"
 | 
			
		||||
  return 1
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								deploy/opensshd.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								deploy/opensshd.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#Here is a script to deploy cert to opensshd server.
 | 
			
		||||
 | 
			
		||||
#returns 0 means success, otherwise error.
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#domain keyfile certfile cafile fullchain
 | 
			
		||||
opensshd_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"
 | 
			
		||||
 | 
			
		||||
  _err "deploy cert to opensshd server, Not implemented yet"
 | 
			
		||||
  return 1
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								deploy/pureftpd.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								deploy/pureftpd.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#Here is a script to deploy cert to pureftpd server.
 | 
			
		||||
 | 
			
		||||
#returns 0 means success, otherwise error.
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#domain keyfile certfile cafile fullchain
 | 
			
		||||
pureftpd_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"
 | 
			
		||||
 | 
			
		||||
  _err "deploy cert to pureftpd server, Not implemented yet"
 | 
			
		||||
  return 1
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										100
									
								
								deploy/unifi.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								deploy/unifi.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,100 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#Here is a script to deploy cert to unifi server.
 | 
			
		||||
 | 
			
		||||
#returns 0 means success, otherwise error.
 | 
			
		||||
 | 
			
		||||
#DEPLOY_UNIFI_KEYSTORE="/usr/lib/unifi/data/keystore"
 | 
			
		||||
#DEPLOY_UNIFI_KEYPASS="aircontrolenterprise"
 | 
			
		||||
#DEPLOY_UNIFI_RELOAD="service unifi restart"
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#domain keyfile certfile cafile fullchain
 | 
			
		||||
unifi_deploy() {
 | 
			
		||||
  _cdomain="$1"
 | 
			
		||||
  _ckey="$2"
 | 
			
		||||
  _ccert="$3"
 | 
			
		||||
  _cca="$4"
 | 
			
		||||
  _cfullchain="$5"
 | 
			
		||||
 | 
			
		||||
  _debug _cdomain "$_cdomain"
 | 
			
		||||
  _debug _ckey "$_ckey"
 | 
			
		||||
  _debug _ccert "$_ccert"
 | 
			
		||||
  _debug _cca "$_cca"
 | 
			
		||||
  _debug _cfullchain "$_cfullchain"
 | 
			
		||||
 | 
			
		||||
  if ! _exists keytool; then
 | 
			
		||||
    _err "keytool not found"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  DEFAULT_UNIFI_KEYSTORE="/usr/lib/unifi/data/keystore"
 | 
			
		||||
  _unifi_keystore="${DEPLOY_UNIFI_KEYSTORE:-$DEFAULT_UNIFI_KEYSTORE}"
 | 
			
		||||
  DEFAULT_UNIFI_KEYPASS="aircontrolenterprise"
 | 
			
		||||
  _unifi_keypass="${DEPLOY_UNIFI_KEYPASS:-$DEFAULT_UNIFI_KEYPASS}"
 | 
			
		||||
  DEFAULT_UNIFI_RELOAD="service unifi restart"
 | 
			
		||||
  _reload="${DEPLOY_UNIFI_RELOAD:-$DEFAULT_UNIFI_RELOAD}"
 | 
			
		||||
 | 
			
		||||
  _debug _unifi_keystore "$_unifi_keystore"
 | 
			
		||||
  if [ ! -f "$_unifi_keystore" ]; then
 | 
			
		||||
    if [ -z "$DEPLOY_UNIFI_KEYSTORE" ]; then
 | 
			
		||||
      _err "unifi keystore is not found, please define DEPLOY_UNIFI_KEYSTORE"
 | 
			
		||||
      return 1
 | 
			
		||||
    else
 | 
			
		||||
      _err "It seems that the specified unifi keystore is not valid, please check."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
  if [ ! -w "$_unifi_keystore" ]; then
 | 
			
		||||
    _err "The file $_unifi_keystore is not writable, please change the permission."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Generate import pkcs12"
 | 
			
		||||
  _import_pkcs12="$(_mktemp)"
 | 
			
		||||
  _toPkcs "$_import_pkcs12" "$_ckey" "$_ccert" "$_cca" "$_unifi_keypass" unifi root
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "Oops, error creating import pkcs12, please report bug to us."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Modify unifi keystore: $_unifi_keystore"
 | 
			
		||||
  if keytool -importkeystore \
 | 
			
		||||
    -deststorepass "$_unifi_keypass" -destkeypass "$_unifi_keypass" -destkeystore "$_unifi_keystore" \
 | 
			
		||||
    -srckeystore "$_import_pkcs12" -srcstoretype PKCS12 -srcstorepass "$_unifi_keypass" \
 | 
			
		||||
    -alias unifi -noprompt; then
 | 
			
		||||
    _info "Import keystore success!"
 | 
			
		||||
    rm "$_import_pkcs12"
 | 
			
		||||
  else
 | 
			
		||||
    _err "Import unifi keystore error, please report bug to us."
 | 
			
		||||
    rm "$_import_pkcs12"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Run reload: $_reload"
 | 
			
		||||
  if eval "$_reload"; then
 | 
			
		||||
    _info "Reload success!"
 | 
			
		||||
    if [ "$DEPLOY_UNIFI_KEYSTORE" ]; then
 | 
			
		||||
      _savedomainconf DEPLOY_UNIFI_KEYSTORE "$DEPLOY_UNIFI_KEYSTORE"
 | 
			
		||||
    else
 | 
			
		||||
      _cleardomainconf DEPLOY_UNIFI_KEYSTORE
 | 
			
		||||
    fi
 | 
			
		||||
    if [ "$DEPLOY_UNIFI_KEYPASS" ]; then
 | 
			
		||||
      _savedomainconf DEPLOY_UNIFI_KEYPASS "$DEPLOY_UNIFI_KEYPASS"
 | 
			
		||||
    else
 | 
			
		||||
      _cleardomainconf DEPLOY_UNIFI_KEYPASS
 | 
			
		||||
    fi
 | 
			
		||||
    if [ "$DEPLOY_UNIFI_RELOAD" ]; then
 | 
			
		||||
      _savedomainconf DEPLOY_UNIFI_RELOAD "$DEPLOY_UNIFI_RELOAD"
 | 
			
		||||
    else
 | 
			
		||||
      _cleardomainconf DEPLOY_UNIFI_RELOAD
 | 
			
		||||
    fi
 | 
			
		||||
    return 0
 | 
			
		||||
  else
 | 
			
		||||
    _err "Reload error"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  return 0
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										110
									
								
								deploy/vsftpd.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								deploy/vsftpd.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,110 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#Here is a script to deploy cert to vsftpd server.
 | 
			
		||||
 | 
			
		||||
#returns 0 means success, otherwise error.
 | 
			
		||||
 | 
			
		||||
#DEPLOY_VSFTPD_CONF="/etc/vsftpd.conf"
 | 
			
		||||
#DEPLOY_VSFTPD_RELOAD="service vsftpd restart"
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#domain keyfile certfile cafile fullchain
 | 
			
		||||
vsftpd_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"
 | 
			
		||||
 | 
			
		||||
  _ssl_path="/etc/acme.sh/vsftpd"
 | 
			
		||||
  if ! mkdir -p "$_ssl_path"; then
 | 
			
		||||
    _err "Can not create folder:$_ssl_path"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Copying key and cert"
 | 
			
		||||
  _real_key="$_ssl_path/vsftpd.key"
 | 
			
		||||
  if ! cat "$_ckey" >"$_real_key"; then
 | 
			
		||||
    _err "Error: write key file to: $_real_key"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _real_fullchain="$_ssl_path/vsftpd.chain.pem"
 | 
			
		||||
  if ! cat "$_cfullchain" >"$_real_fullchain"; then
 | 
			
		||||
    _err "Error: write key file to: $_real_fullchain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  DEFAULT_VSFTPD_RELOAD="service vsftpd restart"
 | 
			
		||||
  _reload="${DEPLOY_VSFTPD_RELOAD:-$DEFAULT_VSFTPD_RELOAD}"
 | 
			
		||||
 | 
			
		||||
  if [ -z "$IS_RENEW" ]; then
 | 
			
		||||
    DEFAULT_VSFTPD_CONF="/etc/vsftpd.conf"
 | 
			
		||||
    _vsftpd_conf="${DEPLOY_VSFTPD_CONF:-$DEFAULT_VSFTPD_CONF}"
 | 
			
		||||
    if [ ! -f "$_vsftpd_conf" ]; then
 | 
			
		||||
      if [ -z "$DEPLOY_VSFTPD_CONF" ]; then
 | 
			
		||||
        _err "vsftpd conf is not found, please define DEPLOY_VSFTPD_CONF"
 | 
			
		||||
        return 1
 | 
			
		||||
      else
 | 
			
		||||
        _err "It seems that the specified vsftpd conf is not valid, please check."
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
    if [ ! -w "$_vsftpd_conf" ]; then
 | 
			
		||||
      _err "The file $_vsftpd_conf is not writable, please change the permission."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    _backup_conf="$DOMAIN_BACKUP_PATH/vsftpd.conf.bak"
 | 
			
		||||
    _info "Backup $_vsftpd_conf to $_backup_conf"
 | 
			
		||||
    cp "$_vsftpd_conf" "$_backup_conf"
 | 
			
		||||
 | 
			
		||||
    _info "Modify vsftpd conf: $_vsftpd_conf"
 | 
			
		||||
    if _setopt "$_vsftpd_conf" "rsa_cert_file" "=" "$_real_fullchain" \
 | 
			
		||||
      && _setopt "$_vsftpd_conf" "rsa_private_key_file" "=" "$_real_key" \
 | 
			
		||||
      && _setopt "$_vsftpd_conf" "ssl_enable" "=" "YES"; then
 | 
			
		||||
      _info "Set config success!"
 | 
			
		||||
    else
 | 
			
		||||
      _err "Config vsftpd server error, please report bug to us."
 | 
			
		||||
      _info "Restoring vsftpd conf"
 | 
			
		||||
      if cat "$_backup_conf" >"$_vsftpd_conf"; then
 | 
			
		||||
        _info "Restore conf success"
 | 
			
		||||
        eval "$_reload"
 | 
			
		||||
      else
 | 
			
		||||
        _err "Oops, error restore vsftpd conf, please report bug to us."
 | 
			
		||||
      fi
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Run reload: $_reload"
 | 
			
		||||
  if eval "$_reload"; then
 | 
			
		||||
    _info "Reload success!"
 | 
			
		||||
    if [ "$DEPLOY_VSFTPD_CONF" ]; then
 | 
			
		||||
      _savedomainconf DEPLOY_VSFTPD_CONF "$DEPLOY_VSFTPD_CONF"
 | 
			
		||||
    else
 | 
			
		||||
      _cleardomainconf DEPLOY_VSFTPD_CONF
 | 
			
		||||
    fi
 | 
			
		||||
    if [ "$DEPLOY_VSFTPD_RELOAD" ]; then
 | 
			
		||||
      _savedomainconf DEPLOY_VSFTPD_RELOAD "$DEPLOY_VSFTPD_RELOAD"
 | 
			
		||||
    else
 | 
			
		||||
      _cleardomainconf DEPLOY_VSFTPD_RELOAD
 | 
			
		||||
    fi
 | 
			
		||||
    return 0
 | 
			
		||||
  else
 | 
			
		||||
    _err "Reload error, restoring"
 | 
			
		||||
    if cat "$_backup_conf" >"$_vsftpd_conf"; then
 | 
			
		||||
      _info "Restore conf success"
 | 
			
		||||
      eval "$_reload"
 | 
			
		||||
    else
 | 
			
		||||
      _err "Oops, error restore vsftpd conf, please report bug to us."
 | 
			
		||||
    fi
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										300
									
								
								dnsapi/README.md
									
									
									
									
									
								
							
							
						
						
									
										300
									
								
								dnsapi/README.md
									
									
									
									
									
								
							@@ -140,7 +140,7 @@ Finally, make the DNS server and update Key available to `acme.sh`
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
export NSUPDATE_SERVER="dns.example.com"
 | 
			
		||||
export NSUPDATE_KEY="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=="
 | 
			
		||||
export NSUPDATE_KEY="/path/to/your/nsupdate.key"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Ok, let's issue a cert now:
 | 
			
		||||
@@ -302,9 +302,305 @@ acme.sh --issue --dns dns_freedns -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Note that you cannot use acme.sh automatic DNS validation for FreeDNS public domains or for a subdomain that
 | 
			
		||||
you create under a FreeDNS public domain.  You must own the top level domain in order to automaitcally
 | 
			
		||||
you create under a FreeDNS public domain.  You must own the top level domain in order to automatically
 | 
			
		||||
validate with acme.sh at FreeDNS.
 | 
			
		||||
 | 
			
		||||
## 16. Use cyon.ch
 | 
			
		||||
 | 
			
		||||
You only need to set your cyon.ch login credentials.
 | 
			
		||||
If you also have 2 Factor Authentication (OTP) enabled, you need to set your secret token too and have `oathtool` installed.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
export CY_Username="your_cyon_username"
 | 
			
		||||
export CY_Password="your_cyon_password"
 | 
			
		||||
export CY_OTP_Secret="your_otp_secret" # Only required if using 2FA
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
To issue a cert:
 | 
			
		||||
```
 | 
			
		||||
acme.sh --issue --dns dns_cyon -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `CY_Username`, `CY_Password` and `CY_OTP_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
 | 
			
		||||
 | 
			
		||||
## 17. Use Domain-Offensive/Resellerinterface/Domainrobot API
 | 
			
		||||
 | 
			
		||||
You will need your login credentials (Partner ID+Password) to the Resellerinterface, and export them before you run `acme.sh`:
 | 
			
		||||
```
 | 
			
		||||
export DO_PID="KD-1234567"
 | 
			
		||||
export DO_PW="cdfkjl3n2"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Ok, let's issue a cert now:
 | 
			
		||||
```
 | 
			
		||||
acme.sh --issue --dns dns_do -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## 18. Use Gandi LiveDNS API
 | 
			
		||||
 | 
			
		||||
You must enable the new Gandi LiveDNS API first and the create your api key, See: http://doc.livedns.gandi.net/
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
export GANDI_LIVEDNS_KEY="fdmlfsdklmfdkmqsdfk"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Ok, let's issue a cert now:
 | 
			
		||||
```
 | 
			
		||||
acme.sh --issue --dns dns_gandi_livedns -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## 19. Use Knot (knsupdate) DNS API to automatically issue cert
 | 
			
		||||
 | 
			
		||||
First, generate a TSIG key for updating the zone.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
keymgr tsig generate acme_key algorithm hmac-sha512 > /etc/knot/acme.key
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Include this key in your knot configuration file.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
include: /etc/knot/acme.key
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Next, configure your zone to allow dynamic updates.
 | 
			
		||||
 | 
			
		||||
Dynamic updates for the zone are allowed via proper ACL rule with the `update` action. For in-depth instructions, please see [Knot DNS's documentation](https://www.knot-dns.cz/documentation/).
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
acl:
 | 
			
		||||
  - id: acme_acl
 | 
			
		||||
    address: 192.168.1.0/24
 | 
			
		||||
    key: acme_key
 | 
			
		||||
    action: update
 | 
			
		||||
 | 
			
		||||
zone:
 | 
			
		||||
  - domain: example.com
 | 
			
		||||
    file: example.com.zone
 | 
			
		||||
    acl: acme_acl
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Finally, make the DNS server and TSIG Key available to `acme.sh`
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
export KNOT_SERVER="dns.example.com"
 | 
			
		||||
export KNOT_KEY=`grep \# /etc/knot/acme.key | cut -d' ' -f2`
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Ok, let's issue a cert now:
 | 
			
		||||
```
 | 
			
		||||
acme.sh --issue --dns dns_knot -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `KNOT_SERVER` and `KNOT_KEY` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
 | 
			
		||||
 | 
			
		||||
## 20. Use DigitalOcean API (native)
 | 
			
		||||
 | 
			
		||||
You need to obtain a read and write capable API key from your DigitalOcean account. See: https://www.digitalocean.com/help/api/
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
export DO_API_KEY="75310dc4ca779ac39a19f6355db573b49ce92ae126553ebd61ac3a3ae34834cc"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Ok, let's issue a cert now:
 | 
			
		||||
```
 | 
			
		||||
acme.sh --issue --dns dns_dgon -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## 21. Use ClouDNS.net API
 | 
			
		||||
 | 
			
		||||
You need to set the HTTP API user ID and password credentials. See: https://www.cloudns.net/wiki/article/42/
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
export CLOUDNS_AUTH_ID=XXXXX
 | 
			
		||||
export CLOUDNS_AUTH_PASSWORD="YYYYYYYYY"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Ok, let's issue a cert now:
 | 
			
		||||
```
 | 
			
		||||
acme.sh --issue --dns dns_cloudns -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## 22. Use Infoblox API
 | 
			
		||||
 | 
			
		||||
First you need to create/obtain API credentials on your Infoblox appliance.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
export Infoblox_Creds="username:password"
 | 
			
		||||
export Infoblox_Server="ip or fqdn of infoblox appliance"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Ok, let's issue a cert now:
 | 
			
		||||
```
 | 
			
		||||
acme.sh --issue --dns dns_infoblox -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Note: This script will automatically create and delete the ephemeral txt record.
 | 
			
		||||
The `Infoblox_Creds` and `Infoblox_Server` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## 23. Use VSCALE API
 | 
			
		||||
 | 
			
		||||
First you need to create/obtain API tokens on your [settings panel](https://vscale.io/panel/settings/tokens/).
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Ok, let's issue a cert now:
 | 
			
		||||
```
 | 
			
		||||
acme.sh --issue --dns dns_vscale -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
##  24. Use Dynu API
 | 
			
		||||
 | 
			
		||||
First you need to create/obtain API credentials from your Dynu account. See: https://www.dynu.com/resources/api/documentation
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
export Dynu_ClientId="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
 | 
			
		||||
export Dynu_Secret="yyyyyyyyyyyyyyyyyyyyyyyyy"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Ok, let's issue a cert now:
 | 
			
		||||
```
 | 
			
		||||
acme.sh --issue --dns dns_dynu -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `Dynu_ClientId` and `Dynu_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
 | 
			
		||||
 | 
			
		||||
## 25. Use DNSimple API
 | 
			
		||||
 | 
			
		||||
First you need to login to your DNSimple account and generate a new oauth token.
 | 
			
		||||
 | 
			
		||||
https://dnsimple.com/a/{your account id}/account/access_tokens
 | 
			
		||||
 | 
			
		||||
Note that this is an _account_ token and not a user token. The account token is
 | 
			
		||||
needed to infer the `account_id` used in requests. A user token will not be able
 | 
			
		||||
to determine the correct account to use.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
export DNSimple_OAUTH_TOKEN="sdfsdfsdfljlbjkljlkjsdfoiwje"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
To issue the cert just specify the `dns_dnsimple` API.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
acme.sh --issue --dns dns_dnsimple -d example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `DNSimple_OAUTH_TOKEN` will be saved in `~/.acme.sh/account.conf` and will
 | 
			
		||||
be reused when needed.
 | 
			
		||||
 | 
			
		||||
If you have any issues with this integration please report them to
 | 
			
		||||
https://github.com/pho3nixf1re/acme.sh/issues.
 | 
			
		||||
 | 
			
		||||
## 26. Use NS1.com API
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
export NS1_Key="fdmlfsdklmfdkmqsdfk"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Ok, let's issue a cert now:
 | 
			
		||||
```
 | 
			
		||||
acme.sh --issue --dns dns_nsone -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## 27. Use DuckDNS.org API
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
export DuckDNS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Please note that since DuckDNS uses StartSSL as their cert provider, thus 
 | 
			
		||||
--insecure may need to be used when issuing certs:
 | 
			
		||||
```
 | 
			
		||||
acme.sh --insecure --issue --dns dns_duckdns -d mydomain.duckdns.org
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
For issues, please report to https://github.com/raidenii/acme.sh/issues.
 | 
			
		||||
 | 
			
		||||
## 28. Use Name.com API
 | 
			
		||||
 | 
			
		||||
You'll need to fill out the form at https://www.name.com/reseller/apply to apply
 | 
			
		||||
for API username and token.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
export Namecom_Username="testuser"
 | 
			
		||||
export Namecom_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
And now you can issue certs with:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
acme.sh --issue --dns dns_namecom -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
For issues, please report to https://github.com/raidenii/acme.sh/issues.
 | 
			
		||||
 | 
			
		||||
## 29. Use Dyn Managed DNS API to automatically issue cert
 | 
			
		||||
 | 
			
		||||
First, login to your Dyn Managed DNS account: https://portal.dynect.net/login/
 | 
			
		||||
 | 
			
		||||
It is recommended to add a new user specific for API access.
 | 
			
		||||
 | 
			
		||||
The minimum "Zones & Records Permissions" required are:
 | 
			
		||||
```
 | 
			
		||||
RecordAdd
 | 
			
		||||
RecordUpdate
 | 
			
		||||
RecordDelete
 | 
			
		||||
RecordGet
 | 
			
		||||
ZoneGet
 | 
			
		||||
ZoneAddNode
 | 
			
		||||
ZoneRemoveNode
 | 
			
		||||
ZonePublish
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Pass the API user credentials to the environment:
 | 
			
		||||
```
 | 
			
		||||
export DYN_Customer="customer"
 | 
			
		||||
export DYN_Username="apiuser"
 | 
			
		||||
export DYN_Password="secret"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Ok, let's issue a cert now:
 | 
			
		||||
```
 | 
			
		||||
acme.sh --issue --dns dns_dyn -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `DYN_Customer`, `DYN_Username` and `DYN_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
 | 
			
		||||
 | 
			
		||||
## 30. Use pdd.yandex.ru API
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
export PDD_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Follow these instructions to get the token for your domain https://tech.yandex.com/domain/doc/concepts/access-docpage/
 | 
			
		||||
```
 | 
			
		||||
acme.sh --issue --dns dns_yandex -d mydomain.example.org
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
For issues, please report to https://github.com/non7top/acme.sh/issues.
 | 
			
		||||
 | 
			
		||||
## 31. Use Hurricane Electric
 | 
			
		||||
 | 
			
		||||
Hurricane Electric doesn't have an API so just set your login credentials like so:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
export HE_Username="yourusername"
 | 
			
		||||
export HE_Password="password"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Then you can issue your certificate:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
acme.sh --issue --dns dns_he -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `HE_Username` and `HE_Password` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
 | 
			
		||||
 | 
			
		||||
Please report any issues to https://github.com/angel333/acme.sh or to <me@ondrejsimek.com>.
 | 
			
		||||
 | 
			
		||||
# Use custom API
 | 
			
		||||
 | 
			
		||||
If your API is not supported yet, you can write your own DNS API.
 | 
			
		||||
 
 | 
			
		||||
@@ -88,12 +88,25 @@ _get_root() {
 | 
			
		||||
    while true; do
 | 
			
		||||
      h=$(printf "%s" "$domain" | cut -d . -f $i-100)
 | 
			
		||||
      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
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
 | 
			
		||||
      if _contains "$response" "<Name>$h.</Name>"; then
 | 
			
		||||
        hostedzone="$(echo "$response" | sed 's/<HostedZone>/#&/g' | tr '#' '\n' | _egrep_o "<HostedZone><Id>[^<]*<.Id><Name>$h.<.Name>.*<.HostedZone>")"
 | 
			
		||||
        hostedzone="$(echo "$response" | sed 's/<HostedZone>/#&/g' | tr '#' '\n' | _egrep_o "<HostedZone><Id>[^<]*<.Id><Name>$h.<.Name>.*<PrivateZone>false<.PrivateZone>.*<.HostedZone>")"
 | 
			
		||||
        _debug hostedzone "$hostedzone"
 | 
			
		||||
        if [ -z "$hostedzone" ]; then
 | 
			
		||||
          _err "Error, can not get hostedzone."
 | 
			
		||||
@@ -143,7 +156,7 @@ aws_rest() {
 | 
			
		||||
  CanonicalHeaders="host:$aws_host\nx-amz-date:$RequestDate\n"
 | 
			
		||||
  SignedHeaders="host;x-amz-date"
 | 
			
		||||
  if [ -n "$AWS_SESSION_TOKEN" ]; then
 | 
			
		||||
    export _H2="x-amz-security-token: $AWS_SESSION_TOKEN"
 | 
			
		||||
    export _H3="x-amz-security-token: $AWS_SESSION_TOKEN"
 | 
			
		||||
    CanonicalHeaders="${CanonicalHeaders}x-amz-security-token:$AWS_SESSION_TOKEN\n"
 | 
			
		||||
    SignedHeaders="${SignedHeaders};x-amz-security-token"
 | 
			
		||||
  fi
 | 
			
		||||
@@ -181,10 +194,10 @@ aws_rest() {
 | 
			
		||||
 | 
			
		||||
  #kSecret="wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" ############################
 | 
			
		||||
 | 
			
		||||
  _debug2 kSecret "$kSecret"
 | 
			
		||||
  _secure_debug2 kSecret "$kSecret"
 | 
			
		||||
 | 
			
		||||
  kSecretH="$(printf "%s" "$kSecret" | _hex_dump | tr -d " ")"
 | 
			
		||||
  _debug2 kSecretH "$kSecretH"
 | 
			
		||||
  _secure_debug2 kSecretH "$kSecretH"
 | 
			
		||||
 | 
			
		||||
  kDateH="$(printf "$RequestDateOnly%s" | _hmac "$Hash" "$kSecretH" hex)"
 | 
			
		||||
  _debug2 kDateH "$kDateH"
 | 
			
		||||
@@ -195,7 +208,7 @@ aws_rest() {
 | 
			
		||||
  kServiceH="$(printf "$Service%s" | _hmac "$Hash" "$kRegionH" hex)"
 | 
			
		||||
  _debug2 kServiceH "$kServiceH"
 | 
			
		||||
 | 
			
		||||
  kSigningH="$(printf "aws4_request%s" | _hmac "$Hash" "$kServiceH" hex)"
 | 
			
		||||
  kSigningH="$(printf "%s" "aws4_request" | _hmac "$Hash" "$kServiceH" hex)"
 | 
			
		||||
  _debug2 kSigningH "$kSigningH"
 | 
			
		||||
 | 
			
		||||
  signature="$(printf "$StringToSign%s" | _hmac "$Hash" "$kSigningH" hex)"
 | 
			
		||||
@@ -204,10 +217,13 @@ aws_rest() {
 | 
			
		||||
  Authorization="$Algorithm Credential=$AWS_ACCESS_KEY_ID/$CredentialScope, SignedHeaders=$SignedHeaders, Signature=$signature"
 | 
			
		||||
  _debug2 Authorization "$Authorization"
 | 
			
		||||
 | 
			
		||||
  _H3="Authorization: $Authorization"
 | 
			
		||||
  _debug _H3 "$_H3"
 | 
			
		||||
  _H2="Authorization: $Authorization"
 | 
			
		||||
  _debug _H2 "$_H2"
 | 
			
		||||
 | 
			
		||||
  url="$AWS_URL/$ep"
 | 
			
		||||
  if [ "$qsr" ]; then
 | 
			
		||||
    url="$AWS_URL/$ep?$qsr"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ "$mtd" = "GET" ]; then
 | 
			
		||||
    response="$(_get "$url")"
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,8 @@ dns_cf_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  CF_Key="${CF_Key:-$(_readaccountconf_mutable CF_Key)}"
 | 
			
		||||
  CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}"
 | 
			
		||||
  if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then
 | 
			
		||||
    CF_Key=""
 | 
			
		||||
    CF_Email=""
 | 
			
		||||
@@ -29,8 +31,8 @@ dns_cf_add() {
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  #save the api key and email to the account conf file.
 | 
			
		||||
  _saveaccountconf CF_Key "$CF_Key"
 | 
			
		||||
  _saveaccountconf CF_Email "$CF_Email"
 | 
			
		||||
  _saveaccountconf_mutable CF_Key "$CF_Key"
 | 
			
		||||
  _saveaccountconf_mutable CF_Email "$CF_Email"
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
@@ -83,6 +85,17 @@ dns_cf_add() {
 | 
			
		||||
dns_cf_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  CF_Key="${CF_Key:-$(_readaccountconf_mutable CF_Key)}"
 | 
			
		||||
  CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}"
 | 
			
		||||
  if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then
 | 
			
		||||
    CF_Key=""
 | 
			
		||||
    CF_Email=""
 | 
			
		||||
    _err "You don't specify cloudflare api key and email yet."
 | 
			
		||||
    _err "Please create you key and try again."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "invalid domain"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										170
									
								
								dnsapi/dns_cloudns.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										170
									
								
								dnsapi/dns_cloudns.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,170 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
# Author: Boyan Peychev <boyan at cloudns dot net>
 | 
			
		||||
# Repository: https://github.com/ClouDNS/acme.sh/
 | 
			
		||||
 | 
			
		||||
#CLOUDNS_AUTH_ID=XXXXX
 | 
			
		||||
#CLOUDNS_AUTH_PASSWORD="YYYYYYYYY"
 | 
			
		||||
CLOUDNS_API="https://api.cloudns.net"
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: dns_cloudns_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_cloudns_add() {
 | 
			
		||||
  _info "Using cloudns"
 | 
			
		||||
 | 
			
		||||
  if ! _dns_cloudns_init_check; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  zone="$(_dns_cloudns_get_zone_name "$1")"
 | 
			
		||||
  if [ -z "$zone" ]; then
 | 
			
		||||
    _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  host="$(echo "$1" | sed "s/\.$zone\$//")"
 | 
			
		||||
  record=$2
 | 
			
		||||
  record_id=$(_dns_cloudns_get_record_id "$zone" "$host")
 | 
			
		||||
 | 
			
		||||
  _debug zone "$zone"
 | 
			
		||||
  _debug host "$host"
 | 
			
		||||
  _debug record "$record"
 | 
			
		||||
  _debug record_id "$record_id"
 | 
			
		||||
 | 
			
		||||
  if [ -z "$record_id" ]; then
 | 
			
		||||
    _info "Adding the TXT record for $1"
 | 
			
		||||
    _dns_cloudns_http_api_call "dns/add-record.json" "domain-name=$zone&record-type=TXT&host=$host&record=$record&ttl=60"
 | 
			
		||||
    if ! _contains "$response" "\"status\":\"Success\""; then
 | 
			
		||||
      _err "Record cannot be added."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    _info "Added."
 | 
			
		||||
  else
 | 
			
		||||
    _info "Updating the TXT record for $1"
 | 
			
		||||
    _dns_cloudns_http_api_call "dns/mod-record.json" "domain-name=$zone&record-id=$record_id&record-type=TXT&host=$host&record=$record&ttl=60"
 | 
			
		||||
    if ! _contains "$response" "\"status\":\"Success\""; then
 | 
			
		||||
      _err "The TXT record for $1 cannot be updated."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    _info "Updated."
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#Usage: dns_cloudns_rm   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_cloudns_rm() {
 | 
			
		||||
  _info "Using cloudns"
 | 
			
		||||
 | 
			
		||||
  if ! _dns_cloudns_init_check; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "$zone" ]; then
 | 
			
		||||
    zone="$(_dns_cloudns_get_zone_name "$1")"
 | 
			
		||||
    if [ -z "$zone" ]; then
 | 
			
		||||
      _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  host="$(echo "$1" | sed "s/\.$zone\$//")"
 | 
			
		||||
  record=$2
 | 
			
		||||
  record_id=$(_dns_cloudns_get_record_id "$zone" "$host")
 | 
			
		||||
 | 
			
		||||
  _debug zone "$zone"
 | 
			
		||||
  _debug host "$host"
 | 
			
		||||
  _debug record "$record"
 | 
			
		||||
  _debug record_id "$record_id"
 | 
			
		||||
 | 
			
		||||
  if [ ! -z "$record_id" ]; then
 | 
			
		||||
    _info "Deleting the TXT record for $1"
 | 
			
		||||
    _dns_cloudns_http_api_call "dns/delete-record.json" "domain-name=$zone&record-id=$record_id"
 | 
			
		||||
    if ! _contains "$response" "\"status\":\"Success\""; then
 | 
			
		||||
      _err "The TXT record for $1 cannot be deleted."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    _info "Deleted."
 | 
			
		||||
  fi
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
_dns_cloudns_init_check() {
 | 
			
		||||
  if [ ! -z "$CLOUDNS_INIT_CHECK_COMPLETED" ]; then
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "$CLOUDNS_AUTH_ID" ]; then
 | 
			
		||||
    _err "CLOUDNS_AUTH_ID is not configured"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "$CLOUDNS_AUTH_PASSWORD" ]; then
 | 
			
		||||
    _err "CLOUDNS_AUTH_PASSWORD is not configured"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _dns_cloudns_http_api_call "dns/login.json" ""
 | 
			
		||||
 | 
			
		||||
  if ! _contains "$response" "\"status\":\"Success\""; then
 | 
			
		||||
    _err "Invalid CLOUDNS_AUTH_ID or CLOUDNS_AUTH_PASSWORD. Please check your login credentials."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  CLOUDNS_INIT_CHECK_COMPLETED=1
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_dns_cloudns_get_zone_name() {
 | 
			
		||||
  i=2
 | 
			
		||||
  while true; do
 | 
			
		||||
    zoneForCheck=$(printf "%s" "$1" | cut -d . -f $i-100)
 | 
			
		||||
 | 
			
		||||
    if [ -z "$zoneForCheck" ]; then
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    _debug zoneForCheck "$zoneForCheck"
 | 
			
		||||
 | 
			
		||||
    _dns_cloudns_http_api_call "dns/get-zone-info.json" "domain-name=$zoneForCheck"
 | 
			
		||||
 | 
			
		||||
    if ! _contains "$response" "\"status\":\"Failed\""; then
 | 
			
		||||
      echo "$zoneForCheck"
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    i=$(_math "$i" + 1)
 | 
			
		||||
  done
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_dns_cloudns_get_record_id() {
 | 
			
		||||
  _dns_cloudns_http_api_call "dns/records.json" "domain-name=$1&host=$2&type=TXT"
 | 
			
		||||
  if _contains "$response" "\"id\":"; then
 | 
			
		||||
    echo "$response" | cut -d '"' -f 2
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_dns_cloudns_http_api_call() {
 | 
			
		||||
  method=$1
 | 
			
		||||
 | 
			
		||||
  _debug CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID"
 | 
			
		||||
  _debug CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD"
 | 
			
		||||
 | 
			
		||||
  if [ -z "$2" ]; then
 | 
			
		||||
    data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD"
 | 
			
		||||
  else
 | 
			
		||||
    data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD&$2"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  response="$(_get "$CLOUDNS_API/$method?$data")"
 | 
			
		||||
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
@@ -209,8 +209,7 @@ _rest() {
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
  if ! _contains "$response" '"message":"success"'; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  return 0
 | 
			
		||||
 | 
			
		||||
  _contains "$response" '"code":1'
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										328
									
								
								dnsapi/dns_cyon.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										328
									
								
								dnsapi/dns_cyon.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,328 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
########
 | 
			
		||||
# Custom cyon.ch DNS API for use with [acme.sh](https://github.com/Neilpang/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>
 | 
			
		||||
########
 | 
			
		||||
 | 
			
		||||
dns_cyon_add() {
 | 
			
		||||
  _cyon_load_credentials \
 | 
			
		||||
    && _cyon_load_parameters "$@" \
 | 
			
		||||
    && _cyon_print_header "add" \
 | 
			
		||||
    && _cyon_login \
 | 
			
		||||
    && _cyon_change_domain_env \
 | 
			
		||||
    && _cyon_add_txt \
 | 
			
		||||
    && _cyon_logout
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dns_cyon_rm() {
 | 
			
		||||
  _cyon_load_credentials \
 | 
			
		||||
    && _cyon_load_parameters "$@" \
 | 
			
		||||
    && _cyon_print_header "delete" \
 | 
			
		||||
    && _cyon_login \
 | 
			
		||||
    && _cyon_change_domain_env \
 | 
			
		||||
    && _cyon_delete_txt \
 | 
			
		||||
    && _cyon_logout
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#########################
 | 
			
		||||
### PRIVATE FUNCTIONS ###
 | 
			
		||||
#########################
 | 
			
		||||
 | 
			
		||||
_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")"
 | 
			
		||||
  elif [ "${CY_Password}" ]; then
 | 
			
		||||
    CY_Password_B64="$(printf "%s" "${CY_Password}" | _base64)"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "${CY_Username}" ] || [ -z "${CY_Password}" ]; then
 | 
			
		||||
    # Dummy entries to satisfy script checker.
 | 
			
		||||
    CY_Username=""
 | 
			
		||||
    CY_Password=""
 | 
			
		||||
    CY_OTP_Secret=""
 | 
			
		||||
 | 
			
		||||
    _err ""
 | 
			
		||||
    _err "You haven't set your cyon.ch login credentials yet."
 | 
			
		||||
    _err "Please set the required cyon environment variables."
 | 
			
		||||
    _err ""
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Save the login credentials to the account.conf file.
 | 
			
		||||
  _debug "Save credentials to account.conf"
 | 
			
		||||
  _saveaccountconf CY_Username "${CY_Username}"
 | 
			
		||||
  _saveaccountconf CY_Password_B64 "$CY_Password_B64"
 | 
			
		||||
  if [ ! -z "${CY_OTP_Secret}" ]; then
 | 
			
		||||
    _saveaccountconf CY_OTP_Secret "$CY_OTP_Secret"
 | 
			
		||||
  else
 | 
			
		||||
    _clearaccountconf CY_OTP_Secret
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_cyon_is_idn() {
 | 
			
		||||
  _idn_temp="$(printf "%s" "${1}" | tr -d "0-9a-zA-Z.,-_")"
 | 
			
		||||
  _idn_temp2="$(printf "%s" "${1}" | grep -o "xn--")"
 | 
			
		||||
  [ "$_idn_temp" ] || [ "$_idn_temp2" ]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_cyon_load_parameters() {
 | 
			
		||||
  # Read the required parameters to add the TXT entry.
 | 
			
		||||
  # shellcheck disable=SC2018,SC2019
 | 
			
		||||
  fulldomain="$(printf "%s" "${1}" | tr "A-Z" "a-z")"
 | 
			
		||||
  fulldomain_idn="${fulldomain}"
 | 
			
		||||
 | 
			
		||||
  # Special case for IDNs, as cyon needs a domain environment change,
 | 
			
		||||
  # which uses the "pretty" instead of the punycode version.
 | 
			
		||||
  if _cyon_is_idn "${fulldomain}"; then
 | 
			
		||||
    if ! _exists idn; then
 | 
			
		||||
      _err "Please install idn to process IDN names."
 | 
			
		||||
      _err ""
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    fulldomain="$(idn -u "${fulldomain}")"
 | 
			
		||||
    fulldomain_idn="$(idn -a "${fulldomain}")"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug fulldomain "${fulldomain}"
 | 
			
		||||
  _debug fulldomain_idn "${fulldomain_idn}"
 | 
			
		||||
 | 
			
		||||
  txtvalue="${2}"
 | 
			
		||||
  _debug txtvalue "${txtvalue}"
 | 
			
		||||
 | 
			
		||||
  # This header is required for curl calls.
 | 
			
		||||
  _H1="X-Requested-With: XMLHttpRequest"
 | 
			
		||||
  export _H1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_cyon_print_header() {
 | 
			
		||||
  if [ "${1}" = "add" ]; then
 | 
			
		||||
    _info ""
 | 
			
		||||
    _info "+---------------------------------------------+"
 | 
			
		||||
    _info "| Adding DNS TXT entry to your cyon.ch domain |"
 | 
			
		||||
    _info "+---------------------------------------------+"
 | 
			
		||||
    _info ""
 | 
			
		||||
    _info "  * Full Domain: ${fulldomain}"
 | 
			
		||||
    _info "  * TXT Value:   ${txtvalue}"
 | 
			
		||||
    _info ""
 | 
			
		||||
  elif [ "${1}" = "delete" ]; then
 | 
			
		||||
    _info ""
 | 
			
		||||
    _info "+-------------------------------------------------+"
 | 
			
		||||
    _info "| Deleting DNS TXT entry from your cyon.ch domain |"
 | 
			
		||||
    _info "+-------------------------------------------------+"
 | 
			
		||||
    _info ""
 | 
			
		||||
    _info "  * Full Domain: ${fulldomain}"
 | 
			
		||||
    _info ""
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_cyon_get_cookie_header() {
 | 
			
		||||
  printf "Cookie: %s" "$(grep "cyon=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'cyon=[^;]*;' | tr -d ';')"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_cyon_login() {
 | 
			
		||||
  _info "  - Logging in..."
 | 
			
		||||
 | 
			
		||||
  username_encoded="$(printf "%s" "${CY_Username}" | _url_encode)"
 | 
			
		||||
  password_encoded="$(printf "%s" "${CY_Password}" | _url_encode)"
 | 
			
		||||
 | 
			
		||||
  login_url="https://my.cyon.ch/auth/index/dologin-async"
 | 
			
		||||
  login_data="$(printf "%s" "username=${username_encoded}&password=${password_encoded}&pathname=%2F")"
 | 
			
		||||
 | 
			
		||||
  login_response="$(_post "$login_data" "$login_url")"
 | 
			
		||||
  _debug login_response "${login_response}"
 | 
			
		||||
 | 
			
		||||
  # Bail if login fails.
 | 
			
		||||
  if [ "$(printf "%s" "${login_response}" | _cyon_get_response_success)" != "success" ]; then
 | 
			
		||||
    _err "    $(printf "%s" "${login_response}" | _cyon_get_response_message)"
 | 
			
		||||
    _err ""
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "    success"
 | 
			
		||||
 | 
			
		||||
  # NECESSARY!! Load the main page after login, to get the new cookie.
 | 
			
		||||
  _H2="$(_cyon_get_cookie_header)"
 | 
			
		||||
  export _H2
 | 
			
		||||
 | 
			
		||||
  _get "https://my.cyon.ch/" >/dev/null
 | 
			
		||||
 | 
			
		||||
  # todo: instead of just checking if the env variable is defined, check if we actually need to do a 2FA auth request.
 | 
			
		||||
 | 
			
		||||
  # 2FA authentication with OTP?
 | 
			
		||||
  if [ ! -z "${CY_OTP_Secret}" ]; then
 | 
			
		||||
    _info "  - Authorising with OTP code..."
 | 
			
		||||
 | 
			
		||||
    if ! _exists oathtool; then
 | 
			
		||||
      _err "Please install oathtool to use 2 Factor Authentication."
 | 
			
		||||
      _err ""
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # Get OTP code with the defined secret.
 | 
			
		||||
    otp_code="$(oathtool --base32 --totp "${CY_OTP_Secret}" 2>/dev/null)"
 | 
			
		||||
 | 
			
		||||
    login_otp_url="https://my.cyon.ch/auth/multi-factor/domultifactorauth-async"
 | 
			
		||||
    login_otp_data="totpcode=${otp_code}&pathname=%2F&rememberme=0"
 | 
			
		||||
 | 
			
		||||
    login_otp_response="$(_post "$login_otp_data" "$login_otp_url")"
 | 
			
		||||
    _debug login_otp_response "${login_otp_response}"
 | 
			
		||||
 | 
			
		||||
    # Bail if OTP authentication fails.
 | 
			
		||||
    if [ "$(printf "%s" "${login_otp_response}" | _cyon_get_response_success)" != "success" ]; then
 | 
			
		||||
      _err "    $(printf "%s" "${login_otp_response}" | _cyon_get_response_message)"
 | 
			
		||||
      _err ""
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    _info "    success"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_cyon_logout() {
 | 
			
		||||
  _info "  - Logging out..."
 | 
			
		||||
 | 
			
		||||
  _get "https://my.cyon.ch/auth/index/dologout" >/dev/null
 | 
			
		||||
 | 
			
		||||
  _info "    success"
 | 
			
		||||
  _info ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_cyon_change_domain_env() {
 | 
			
		||||
  _info "  - Changing domain environment..."
 | 
			
		||||
 | 
			
		||||
  # Get the "example.com" part of the full domain name.
 | 
			
		||||
  domain_env="$(printf "%s" "${fulldomain}" | sed -E -e 's/.*\.(.*\..*)$/\1/')"
 | 
			
		||||
  _debug "Changing domain environment to ${domain_env}"
 | 
			
		||||
 | 
			
		||||
  gloo_item_key="$(_get "https://my.cyon.ch/domain/" | tr '\n' ' ' | sed -E -e "s/.*data-domain=\"${domain_env}\"[^<]*data-itemkey=\"([^\"]*).*/\1/")"
 | 
			
		||||
  _debug gloo_item_key "${gloo_item_key}"
 | 
			
		||||
 | 
			
		||||
  domain_env_url="https://my.cyon.ch/user/environment/setdomain/d/${domain_env}/gik/${gloo_item_key}"
 | 
			
		||||
 | 
			
		||||
  domain_env_response="$(_get "${domain_env_url}")"
 | 
			
		||||
  _debug domain_env_response "${domain_env_response}"
 | 
			
		||||
 | 
			
		||||
  if ! _cyon_check_if_2fa_missed "${domain_env_response}"; then return 1; fi
 | 
			
		||||
 | 
			
		||||
  domain_env_success="$(printf "%s" "${domain_env_response}" | _egrep_o '"authenticated":\w*' | cut -d : -f 2)"
 | 
			
		||||
 | 
			
		||||
  # Bail if domain environment change fails.
 | 
			
		||||
  if [ "${domain_env_success}" != "true" ]; then
 | 
			
		||||
    _err "    $(printf "%s" "${domain_env_response}" | _cyon_get_response_message)"
 | 
			
		||||
    _err ""
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "    success"
 | 
			
		||||
  _info ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_cyon_add_txt() {
 | 
			
		||||
  _info "  - Adding DNS TXT entry..."
 | 
			
		||||
 | 
			
		||||
  add_txt_url="https://my.cyon.ch/domain/dnseditor/add-record-async"
 | 
			
		||||
  add_txt_data="zone=${fulldomain_idn}.&ttl=900&type=TXT&value=${txtvalue}"
 | 
			
		||||
 | 
			
		||||
  add_txt_response="$(_post "$add_txt_data" "$add_txt_url")"
 | 
			
		||||
  _debug add_txt_response "${add_txt_response}"
 | 
			
		||||
 | 
			
		||||
  if ! _cyon_check_if_2fa_missed "${add_txt_response}"; then return 1; fi
 | 
			
		||||
 | 
			
		||||
  add_txt_message="$(printf "%s" "${add_txt_response}" | _cyon_get_response_message)"
 | 
			
		||||
  add_txt_status="$(printf "%s" "${add_txt_response}" | _cyon_get_response_status)"
 | 
			
		||||
 | 
			
		||||
  # Bail if adding TXT entry fails.
 | 
			
		||||
  if [ "${add_txt_status}" != "true" ]; then
 | 
			
		||||
    _err "    ${add_txt_message}"
 | 
			
		||||
    _err ""
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "    success (TXT|${fulldomain_idn}.|${txtvalue})"
 | 
			
		||||
  _info ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_cyon_delete_txt() {
 | 
			
		||||
  _info "  - Deleting DNS TXT entry..."
 | 
			
		||||
 | 
			
		||||
  list_txt_url="https://my.cyon.ch/domain/dnseditor/list-async"
 | 
			
		||||
 | 
			
		||||
  list_txt_response="$(_get "${list_txt_url}" | sed -e 's/data-hash/\\ndata-hash/g')"
 | 
			
		||||
  _debug list_txt_response "${list_txt_response}"
 | 
			
		||||
 | 
			
		||||
  if ! _cyon_check_if_2fa_missed "${list_txt_response}"; then return 1; fi
 | 
			
		||||
 | 
			
		||||
  # Find and delete all acme challenge entries for the $fulldomain.
 | 
			
		||||
  _dns_entries="$(printf "%b\n" "${list_txt_response}" | sed -n 's/data-hash=\\"\([^"]*\)\\" data-identifier=\\"\([^"]*\)\\".*/\1 \2/p')"
 | 
			
		||||
 | 
			
		||||
  printf "%s" "${_dns_entries}" | while read -r _hash _identifier; do
 | 
			
		||||
    dns_type="$(printf "%s" "$_identifier" | cut -d'|' -f1)"
 | 
			
		||||
    dns_domain="$(printf "%s" "$_identifier" | cut -d'|' -f2)"
 | 
			
		||||
 | 
			
		||||
    if [ "${dns_type}" != "TXT" ] || [ "${dns_domain}" != "${fulldomain_idn}." ]; then
 | 
			
		||||
      continue
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    hash_encoded="$(printf "%s" "${_hash}" | _url_encode)"
 | 
			
		||||
    identifier_encoded="$(printf "%s" "${_identifier}" | _url_encode)"
 | 
			
		||||
 | 
			
		||||
    delete_txt_url="https://my.cyon.ch/domain/dnseditor/delete-record-async"
 | 
			
		||||
    delete_txt_data="$(printf "%s" "hash=${hash_encoded}&identifier=${identifier_encoded}")"
 | 
			
		||||
 | 
			
		||||
    delete_txt_response="$(_post "$delete_txt_data" "$delete_txt_url")"
 | 
			
		||||
    _debug delete_txt_response "${delete_txt_response}"
 | 
			
		||||
 | 
			
		||||
    if ! _cyon_check_if_2fa_missed "${delete_txt_response}"; then return 1; fi
 | 
			
		||||
 | 
			
		||||
    delete_txt_message="$(printf "%s" "${delete_txt_response}" | _cyon_get_response_message)"
 | 
			
		||||
    delete_txt_status="$(printf "%s" "${delete_txt_response}" | _cyon_get_response_status)"
 | 
			
		||||
 | 
			
		||||
    # Skip if deleting TXT entry fails.
 | 
			
		||||
    if [ "${delete_txt_status}" != "true" ]; then
 | 
			
		||||
      _err "    ${delete_txt_message} (${_identifier})"
 | 
			
		||||
    else
 | 
			
		||||
      _info "    success (${_identifier})"
 | 
			
		||||
    fi
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  _info "    done"
 | 
			
		||||
  _info ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_cyon_get_response_message() {
 | 
			
		||||
  _egrep_o '"message":"[^"]*"' | cut -d : -f 2 | tr -d '"'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_cyon_get_response_status() {
 | 
			
		||||
  _egrep_o '"status":\w*' | cut -d : -f 2
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_cyon_get_response_success() {
 | 
			
		||||
  _egrep_o '"onSuccess":"[^"]*"' | cut -d : -f 2 | tr -d '"'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_cyon_check_if_2fa_missed() {
 | 
			
		||||
  # Did we miss the 2FA?
 | 
			
		||||
  if test "${1#*multi_factor_form}" != "${1}"; then
 | 
			
		||||
    _err "    Missed OTP authentication!"
 | 
			
		||||
    _err ""
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										205
									
								
								dnsapi/dns_dgon.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										205
									
								
								dnsapi/dns_dgon.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,205 @@
 | 
			
		||||
#!/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"
 | 
			
		||||
##
 | 
			
		||||
 | 
			
		||||
#####################  Public functions  #####################
 | 
			
		||||
 | 
			
		||||
## Create the text record for validation.
 | 
			
		||||
## Usage: fulldomain txtvalue
 | 
			
		||||
## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_dgon_add() {
 | 
			
		||||
  fulldomain="$(echo "$1" | _lower_case)"
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
  _info "Using digitalocean dns validation - add record"
 | 
			
		||||
  _debug fulldomain "$fulldomain"
 | 
			
		||||
  _debug txtvalue "$txtvalue"
 | 
			
		||||
 | 
			
		||||
  ## save the env vars (key and domain split location) for later automated use
 | 
			
		||||
  _saveaccountconf DO_API_KEY "$DO_API_KEY"
 | 
			
		||||
 | 
			
		||||
  ## split the domain for DO 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"
 | 
			
		||||
 | 
			
		||||
  ## Set the header with our post type and key auth key
 | 
			
		||||
  export _H1="Content-Type: application/json"
 | 
			
		||||
  export _H2="Authorization: Bearer $DO_API_KEY"
 | 
			
		||||
  PURL='https://api.digitalocean.com/v2/domains/'$_domain'/records'
 | 
			
		||||
  PBODY='{"type":"TXT","name":"'$_sub_domain'","data":"'$txtvalue'"}'
 | 
			
		||||
 | 
			
		||||
  _debug PURL "$PURL"
 | 
			
		||||
  _debug PBODY "$PBODY"
 | 
			
		||||
 | 
			
		||||
  ## the create request - post
 | 
			
		||||
  ## args: BODY, URL, [need64, httpmethod]
 | 
			
		||||
  response="$(_post "$PBODY" "$PURL")"
 | 
			
		||||
 | 
			
		||||
  ## 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_dgon_rm() {
 | 
			
		||||
  fulldomain="$(echo "$1" | _lower_case)"
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
  _info "Using digitalocean dns validation - remove record"
 | 
			
		||||
  _debug fulldomain "$fulldomain"
 | 
			
		||||
  _debug txtvalue "$txtvalue"
 | 
			
		||||
 | 
			
		||||
  ## split the domain for DO API
 | 
			
		||||
  if ! _get_base_domain "$fulldomain"; then
 | 
			
		||||
    _err "domain not found in your account for removal"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug _sub_domain "$_sub_domain"
 | 
			
		||||
  _debug _domain "$_domain"
 | 
			
		||||
 | 
			
		||||
  ## Set the header with our post type and key auth key
 | 
			
		||||
  export _H1="Content-Type: application/json"
 | 
			
		||||
  export _H2="Authorization: Bearer $DO_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"}}
 | 
			
		||||
  GURL="https://api.digitalocean.com/v2/domains/$_domain/records"
 | 
			
		||||
 | 
			
		||||
  ## while we dont have a record ID we keep going
 | 
			
		||||
  while [ -z "$record" ]; do
 | 
			
		||||
    ## 1) get the URL
 | 
			
		||||
    ## the create request - get
 | 
			
		||||
    ## args: URL, [onlyheader, timeout]
 | 
			
		||||
    domain_list="$(_get "$GURL")"
 | 
			
		||||
    ## 2) find record
 | 
			
		||||
    ## check for what we are looing for: "type":"A","name":"$_sub_domain"
 | 
			
		||||
    record="$(echo "$domain_list" | _egrep_o "\"id\"\s*\:\s*\"*\d+\"*[^}]*\"name\"\s*\:\s*\"$_sub_domain\"[^}]*\"data\"\s*\:\s*\"$txtvalue\"")"
 | 
			
		||||
    ## 3) check record and get next page
 | 
			
		||||
    if [ -z "$record" ]; then
 | 
			
		||||
      ## find the next page if we dont have a match
 | 
			
		||||
      nextpage="$(echo "$domain_list" | _egrep_o "\"links\".*" | _egrep_o "\"next\".*" | _egrep_o "http.*page\=\d+")"
 | 
			
		||||
      if [ -z "$nextpage" ]; then
 | 
			
		||||
        _err "no record and no nextpage in digital ocean DNS removal"
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
      _debug2 nextpage "$nextpage"
 | 
			
		||||
      GURL="$nextpage"
 | 
			
		||||
    fi
 | 
			
		||||
    ## we break out of the loop when we have a record
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  ## we found the record
 | 
			
		||||
  rec_id="$(echo "$record" | _egrep_o "id\"\s*\:\s*\"*\d+" | _egrep_o "\d+")"
 | 
			
		||||
  _debug rec_id "$rec_id"
 | 
			
		||||
 | 
			
		||||
  ## delete the record
 | 
			
		||||
  ## delete URL for removing the one we dont want
 | 
			
		||||
  DURL="https://api.digitalocean.com/v2/domains/$_domain/records/$rec_id"
 | 
			
		||||
 | 
			
		||||
  ## the create 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"
 | 
			
		||||
 | 
			
		||||
  ## finished correctly
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#####################  Private functions below  #####################
 | 
			
		||||
 | 
			
		||||
## Split the domain provided into the "bade 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
 | 
			
		||||
## if only "domain.com" exists it will return
 | 
			
		||||
## _sub_domain="_acme-challenge.two.three.four"
 | 
			
		||||
## _domain="domain.com"
 | 
			
		||||
_get_base_domain() {
 | 
			
		||||
  # args
 | 
			
		||||
  fulldomain="$(echo "$1" | tr '[:upper:]' '[:lower:]')"
 | 
			
		||||
  _debug fulldomain "$fulldomain"
 | 
			
		||||
 | 
			
		||||
  # domain max legal length = 253
 | 
			
		||||
  MAX_DOM=255
 | 
			
		||||
 | 
			
		||||
  ## get a list of domains for the account to check thru
 | 
			
		||||
  ## Set the headers
 | 
			
		||||
  export _H1="Content-Type: application/json"
 | 
			
		||||
  export _H2="Authorization: Bearer $DO_API_KEY"
 | 
			
		||||
  _debug DO_API_KEY "$DO_API_KEY"
 | 
			
		||||
  ## get URL for the list of domains
 | 
			
		||||
  ## havent seen this request paginated, tested with 18 domains (more requires manual requests with DO)
 | 
			
		||||
  DOMURL="https://api.digitalocean.com/v2/domains"
 | 
			
		||||
 | 
			
		||||
  ## get the domain list (DO gives basically a full XFER!)
 | 
			
		||||
  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"
 | 
			
		||||
 | 
			
		||||
  ## 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
 | 
			
		||||
  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
 | 
			
		||||
      ## we got to the end of the domain - invalid domain
 | 
			
		||||
      _err "domain not found in DigitalOcean account"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    ## we got part of a domain back - grep it out
 | 
			
		||||
    found="$(echo "$domain_list" | _egrep_o "\"name\"\s*\:\s*\"$_domain\"")"
 | 
			
		||||
    ## check if it exists
 | 
			
		||||
    if [ ! -z "$found" ]; then
 | 
			
		||||
      ## exists - exit loop returning the parts
 | 
			
		||||
      sub_point=$(_math $i - 1)
 | 
			
		||||
      _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$sub_point")
 | 
			
		||||
      _debug _domain "$_domain"
 | 
			
		||||
      _debug _sub_domain "$_sub_domain"
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
    ## increment cut point $i
 | 
			
		||||
    i=$(_math $i + 1)
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  ## we went through the entire domain zone list and dint find one that matched
 | 
			
		||||
  ## doesnt look like we can add in the record
 | 
			
		||||
  _err "domain not found in DigitalOcean account, but we should never get here"
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										215
									
								
								dnsapi/dns_dnsimple.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										215
									
								
								dnsapi/dns_dnsimple.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,215 @@
 | 
			
		||||
#!/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"
 | 
			
		||||
 | 
			
		||||
DNSimple_API="https://api.dnsimple.com/v2"
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
# Usage: add  _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_dnsimple_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  if [ -z "$DNSimple_OAUTH_TOKEN" ]; then
 | 
			
		||||
    DNSimple_OAUTH_TOKEN=""
 | 
			
		||||
    _err "You have not set the dnsimple oauth token yet."
 | 
			
		||||
    _err "Please visit https://dnsimple.com/user to generate it."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # save the oauth token for later
 | 
			
		||||
  _saveaccountconf DNSimple_OAUTH_TOKEN "$DNSimple_OAUTH_TOKEN"
 | 
			
		||||
 | 
			
		||||
  if ! _get_account_id; then
 | 
			
		||||
    _err "failed to retrive account id"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "invalid domain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _get_records "$_account_id" "$_domain" "$_sub_domain"
 | 
			
		||||
 | 
			
		||||
  if [ "$_records_count" = "0" ]; then
 | 
			
		||||
    _info "Adding record"
 | 
			
		||||
    if _dnsimple_rest POST "$_account_id/zones/$_domain/records" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then
 | 
			
		||||
      if printf -- "%s" "$response" | grep "\"name\":\"$_sub_domain\"" >/dev/null; then
 | 
			
		||||
        _info "Added"
 | 
			
		||||
        return 0
 | 
			
		||||
      else
 | 
			
		||||
        _err "Unexpected response while adding text record."
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
    _err "Add txt record error."
 | 
			
		||||
  else
 | 
			
		||||
    _info "Updating record"
 | 
			
		||||
    _extract_record_id "$_records" "$_sub_domain"
 | 
			
		||||
 | 
			
		||||
    if _dnsimple_rest \
 | 
			
		||||
      PATCH \
 | 
			
		||||
      "$_account_id/zones/$_domain/records/$_record_id" \
 | 
			
		||||
      "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then
 | 
			
		||||
 | 
			
		||||
      _info "Updated!"
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    _err "Update error"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# fulldomain
 | 
			
		||||
dns_dnsimple_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
 | 
			
		||||
  if ! _get_account_id; then
 | 
			
		||||
    _err "failed to retrive account id"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "invalid domain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _get_records "$_account_id" "$_domain" "$_sub_domain"
 | 
			
		||||
  _extract_record_id "$_records" "$_sub_domain"
 | 
			
		||||
 | 
			
		||||
  if [ "$_record_id" ]; then
 | 
			
		||||
 | 
			
		||||
    if _dnsimple_rest DELETE "$_account_id/zones/$_domain/records/$_record_id"; then
 | 
			
		||||
      _info "removed record" "$_record_id"
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _err "failed to remove record" "$_record_id"
 | 
			
		||||
  return 1
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions bellow ##################################
 | 
			
		||||
# _acme-challenge.www.domain.com
 | 
			
		||||
# returns
 | 
			
		||||
#   _sub_domain=_acme-challenge.www
 | 
			
		||||
#   _domain=domain.com
 | 
			
		||||
_get_root() {
 | 
			
		||||
  domain=$1
 | 
			
		||||
  i=2
 | 
			
		||||
  previous=1
 | 
			
		||||
  while true; do
 | 
			
		||||
    h=$(printf "%s" "$domain" | cut -d . -f $i-100)
 | 
			
		||||
    if [ -z "$h" ]; then
 | 
			
		||||
      # not valid
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if ! _dnsimple_rest GET "$_account_id/zones/$h"; then
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if _contains "$response" 'not found'; then
 | 
			
		||||
      _debug "$h not found"
 | 
			
		||||
    else
 | 
			
		||||
      _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$previous)
 | 
			
		||||
      _domain="$h"
 | 
			
		||||
 | 
			
		||||
      _debug _domain "$_domain"
 | 
			
		||||
      _debug _sub_domain "$_sub_domain"
 | 
			
		||||
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    previous="$i"
 | 
			
		||||
    i=$(_math "$i" + 1)
 | 
			
		||||
  done
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# returns _account_id
 | 
			
		||||
_get_account_id() {
 | 
			
		||||
  _debug "retrive account id"
 | 
			
		||||
  if ! _dnsimple_rest GET "whoami"; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if _contains "$response" "\"account\":null"; then
 | 
			
		||||
    _err "no account associated with this token"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if _contains "$response" "timeout"; then
 | 
			
		||||
    _err "timeout retrieving account id"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _account_id=$(printf "%s" "$response" | _egrep_o "\"id\":[^,]*,\"email\":" | cut -d: -f2 | cut -d, -f1)
 | 
			
		||||
  _debug _account_id "$_account_id"
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# returns
 | 
			
		||||
#   _records
 | 
			
		||||
#   _records_count
 | 
			
		||||
_get_records() {
 | 
			
		||||
  account_id=$1
 | 
			
		||||
  domain=$2
 | 
			
		||||
  sub_domain=$3
 | 
			
		||||
 | 
			
		||||
  _debug "fetching txt records"
 | 
			
		||||
  _dnsimple_rest GET "$account_id/zones/$domain/records?per_page=100"
 | 
			
		||||
 | 
			
		||||
  if ! _contains "$response" "\"id\":"; then
 | 
			
		||||
    _err "failed to retrieve records"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _records_count=$(printf "%s" "$response" | _egrep_o "\"name\":\"$sub_domain\"" | wc -l | _egrep_o "[0-9]+")
 | 
			
		||||
  _records=$response
 | 
			
		||||
  _debug _records_count "$_records_count"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# returns _record_id
 | 
			
		||||
_extract_record_id() {
 | 
			
		||||
  _record_id=$(printf "%s" "$_records" | _egrep_o "\"id\":[^,]*,\"zone_id\":\"[^,]*\",\"parent_id\":null,\"name\":\"$_sub_domain\"" | cut -d: -f2 | cut -d, -f1)
 | 
			
		||||
  _debug "_record_id" "$_record_id"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# returns response
 | 
			
		||||
_dnsimple_rest() {
 | 
			
		||||
  method=$1
 | 
			
		||||
  path="$2"
 | 
			
		||||
  data="$3"
 | 
			
		||||
  request_url="$DNSimple_API/$path"
 | 
			
		||||
  _debug "$path"
 | 
			
		||||
 | 
			
		||||
  export _H1="Accept: application/json"
 | 
			
		||||
  export _H2="Authorization: Bearer $DNSimple_OAUTH_TOKEN"
 | 
			
		||||
 | 
			
		||||
  if [ "$data" ] || [ "$method" = "DELETE" ]; then
 | 
			
		||||
    _H1="Content-Type: application/json"
 | 
			
		||||
    _debug data "$data"
 | 
			
		||||
    response="$(_post "$data" "$request_url" "" "$method")"
 | 
			
		||||
  else
 | 
			
		||||
    response="$(_get "$request_url" "" "" "$method")"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "error $request_url"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										148
									
								
								dnsapi/dns_do.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										148
									
								
								dnsapi/dns_do.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,148 @@
 | 
			
		||||
#!/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'
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										128
									
								
								dnsapi/dns_duckdns.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										128
									
								
								dnsapi/dns_duckdns.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,128 @@
 | 
			
		||||
#!/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
 | 
			
		||||
 | 
			
		||||
DuckDNS_API="https://www.duckdns.org/update"
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: dns_duckdns_add _acme-challenge.domain.duckdns.org "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_duckdns_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  DuckDNS_Token="${DuckDNS_Token:-$(_readaccountconf_mutable DuckDNS_Token)}"
 | 
			
		||||
  if [ -z "$DuckDNS_Token" ]; then
 | 
			
		||||
    _err "You must export variable: DuckDNS_Token"
 | 
			
		||||
    _err "The token for your DuckDNS account is necessary."
 | 
			
		||||
    _err "You can look it up in your DuckDNS account."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Now save the credentials.
 | 
			
		||||
  _saveaccountconf_mutable DuckDNS_Token "$DuckDNS_Token"
 | 
			
		||||
 | 
			
		||||
  # Unfortunately, DuckDNS does not seems to support lookup domain through API
 | 
			
		||||
  # So I assume your credentials (which are your domain and token) are correct
 | 
			
		||||
  # If something goes wrong, we will get a KO response from DuckDNS
 | 
			
		||||
 | 
			
		||||
  if ! _duckdns_get_domain; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Now add the TXT record to DuckDNS
 | 
			
		||||
  _info "Trying to add TXT record"
 | 
			
		||||
  if _duckdns_rest GET "domains=$_duckdns_domain&token=$DuckDNS_Token&txt=$txtvalue"; then
 | 
			
		||||
    if [ "$response" = "OK" ]; then
 | 
			
		||||
      _info "TXT record has been successfully added to your DuckDNS domain."
 | 
			
		||||
      _info "Note that all subdomains under this domain uses the same TXT record."
 | 
			
		||||
      return 0
 | 
			
		||||
    else
 | 
			
		||||
      _err "Errors happened during adding the TXT record, response=$response"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    _err "Errors happened during adding the TXT record."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#Usage: fulldomain txtvalue
 | 
			
		||||
#Remove the txt record after validation.
 | 
			
		||||
dns_duckdns_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  DuckDNS_Token="${DuckDNS_Token:-$(_readaccountconf_mutable DuckDNS_Token)}"
 | 
			
		||||
  if [ -z "$DuckDNS_Token" ]; then
 | 
			
		||||
    _err "You must export variable: DuckDNS_Token"
 | 
			
		||||
    _err "The token for your DuckDNS account is necessary."
 | 
			
		||||
    _err "You can look it up in your DuckDNS account."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! _duckdns_get_domain; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Now remove the TXT record from DuckDNS
 | 
			
		||||
  _info "Trying to remove TXT record"
 | 
			
		||||
  if _duckdns_rest GET "domains=$_duckdns_domain&token=$DuckDNS_Token&txt=&clear=true"; then
 | 
			
		||||
    if [ "$response" = "OK" ]; then
 | 
			
		||||
      _info "TXT record has been successfully removed from your DuckDNS domain."
 | 
			
		||||
      return 0
 | 
			
		||||
    else
 | 
			
		||||
      _err "Errors happened during removing the TXT record, response=$response"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    _err "Errors happened during removing the TXT record."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
 | 
			
		||||
#fulldomain=_acme-challenge.domain.duckdns.org
 | 
			
		||||
#returns
 | 
			
		||||
# _duckdns_domain=domain
 | 
			
		||||
_duckdns_get_domain() {
 | 
			
		||||
 | 
			
		||||
  # We'll extract the domain/username from full domain
 | 
			
		||||
  _duckdns_domain="$(printf "%s" "$fulldomain" | _lower_case | _egrep_o '[.][^.][^.]*[.]duckdns.org' | cut -d . -f 2)"
 | 
			
		||||
 | 
			
		||||
  if [ -z "$_duckdns_domain" ]; then
 | 
			
		||||
    _err "Error extracting the domain."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#Usage: method URI
 | 
			
		||||
_duckdns_rest() {
 | 
			
		||||
  method=$1
 | 
			
		||||
  param="$2"
 | 
			
		||||
  _debug param "$param"
 | 
			
		||||
  url="$DuckDNS_API?$param"
 | 
			
		||||
  _debug url "$url"
 | 
			
		||||
 | 
			
		||||
  # DuckDNS uses GET to update domain info
 | 
			
		||||
  if [ "$method" = "GET" ]; then
 | 
			
		||||
    response="$(_get "$url")"
 | 
			
		||||
  else
 | 
			
		||||
    _err "Unsupported method"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										339
									
								
								dnsapi/dns_dyn.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										339
									
								
								dnsapi/dns_dyn.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,339 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
#
 | 
			
		||||
# Dyn.com Domain API
 | 
			
		||||
#
 | 
			
		||||
# Author: Gerd Naschenweng
 | 
			
		||||
# https://github.com/magicdude4eva
 | 
			
		||||
#
 | 
			
		||||
# Dyn Managed DNS API
 | 
			
		||||
# https://help.dyn.com/dns-api-knowledge-base/
 | 
			
		||||
#
 | 
			
		||||
# It is recommended to add a "Dyn Managed DNS" user specific for API access.
 | 
			
		||||
# The "Zones & Records Permissions" required by this script are:
 | 
			
		||||
# --
 | 
			
		||||
# RecordAdd
 | 
			
		||||
# RecordUpdate
 | 
			
		||||
# RecordDelete
 | 
			
		||||
# RecordGet
 | 
			
		||||
# ZoneGet
 | 
			
		||||
# ZoneAddNode
 | 
			
		||||
# 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"
 | 
			
		||||
 | 
			
		||||
#REST_API
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: add  _acme-challenge.www.domain.com   "Challenge-code"
 | 
			
		||||
dns_dyn_add() {
 | 
			
		||||
  fulldomain="$1"
 | 
			
		||||
  txtvalue="$2"
 | 
			
		||||
 | 
			
		||||
  DYN_Customer="${DYN_Customer:-$(_readaccountconf_mutable DYN_Customer)}"
 | 
			
		||||
  DYN_Username="${DYN_Username:-$(_readaccountconf_mutable DYN_Username)}"
 | 
			
		||||
  DYN_Password="${DYN_Password:-$(_readaccountconf_mutable DYN_Password)}"
 | 
			
		||||
  if [ -z "$DYN_Customer" ] || [ -z "$DYN_Username" ] || [ -z "$DYN_Password" ]; then
 | 
			
		||||
    DYN_Customer=""
 | 
			
		||||
    DYN_Username=""
 | 
			
		||||
    DYN_Password=""
 | 
			
		||||
    _err "You must export variables: DYN_Customer, DYN_Username and DYN_Password"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  #save the config variables to the account conf file.
 | 
			
		||||
  _saveaccountconf_mutable DYN_Customer "$DYN_Customer"
 | 
			
		||||
  _saveaccountconf_mutable DYN_Username "$DYN_Username"
 | 
			
		||||
  _saveaccountconf_mutable DYN_Password "$DYN_Password"
 | 
			
		||||
 | 
			
		||||
  if ! _dyn_get_authtoken; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "$_dyn_authtoken" ]; then
 | 
			
		||||
    _dyn_end_session
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! _dyn_get_zone; then
 | 
			
		||||
    _dyn_end_session
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! _dyn_add_record; then
 | 
			
		||||
    _dyn_end_session
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! _dyn_publish_zone; then
 | 
			
		||||
    _dyn_end_session
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _dyn_end_session
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#Usage: fulldomain txtvalue
 | 
			
		||||
#Remove the txt record after validation.
 | 
			
		||||
dns_dyn_rm() {
 | 
			
		||||
  fulldomain="$1"
 | 
			
		||||
  txtvalue="$2"
 | 
			
		||||
 | 
			
		||||
  DYN_Customer="${DYN_Customer:-$(_readaccountconf_mutable DYN_Customer)}"
 | 
			
		||||
  DYN_Username="${DYN_Username:-$(_readaccountconf_mutable DYN_Username)}"
 | 
			
		||||
  DYN_Password="${DYN_Password:-$(_readaccountconf_mutable DYN_Password)}"
 | 
			
		||||
  if [ -z "$DYN_Customer" ] || [ -z "$DYN_Username" ] || [ -z "$DYN_Password" ]; then
 | 
			
		||||
    DYN_Customer=""
 | 
			
		||||
    DYN_Username=""
 | 
			
		||||
    DYN_Password=""
 | 
			
		||||
    _err "You must export variables: DYN_Customer, DYN_Username and DYN_Password"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! _dyn_get_authtoken; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "$_dyn_authtoken" ]; then
 | 
			
		||||
    _dyn_end_session
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! _dyn_get_zone; then
 | 
			
		||||
    _dyn_end_session
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! _dyn_get_record_id; then
 | 
			
		||||
    _dyn_end_session
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "$_dyn_record_id" ]; then
 | 
			
		||||
    _dyn_end_session
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! _dyn_rm_record; then
 | 
			
		||||
    _dyn_end_session
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! _dyn_publish_zone; then
 | 
			
		||||
    _dyn_end_session
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _dyn_end_session
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
 | 
			
		||||
#get Auth-Token
 | 
			
		||||
_dyn_get_authtoken() {
 | 
			
		||||
 | 
			
		||||
  _info "Start Dyn API Session"
 | 
			
		||||
 | 
			
		||||
  data="{\"customer_name\":\"$DYN_Customer\", \"user_name\":\"$DYN_Username\", \"password\":\"$DYN_Password\"}"
 | 
			
		||||
  dyn_url="$DYN_API/Session/"
 | 
			
		||||
  method="POST"
 | 
			
		||||
 | 
			
		||||
  _debug data "$data"
 | 
			
		||||
  _debug dyn_url "$dyn_url"
 | 
			
		||||
 | 
			
		||||
  export _H1="Content-Type: application/json"
 | 
			
		||||
 | 
			
		||||
  response="$(_post "$data" "$dyn_url" "" "$method")"
 | 
			
		||||
  sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')"
 | 
			
		||||
 | 
			
		||||
  _debug response "$response"
 | 
			
		||||
  _debug sessionstatus "$sessionstatus"
 | 
			
		||||
 | 
			
		||||
  if [ "$sessionstatus" = "success" ]; then
 | 
			
		||||
    _dyn_authtoken="$(printf "%s\n" "$response" | _egrep_o '"token" *: *"[^"]*' | _head_n 1 | sed 's#^"token" *: *"##')"
 | 
			
		||||
    _info "Token received"
 | 
			
		||||
    _debug _dyn_authtoken "$_dyn_authtoken"
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _dyn_authtoken=""
 | 
			
		||||
  _err "get token failed"
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#fulldomain=_acme-challenge.www.domain.com
 | 
			
		||||
#returns
 | 
			
		||||
# _dyn_zone=domain.com
 | 
			
		||||
_dyn_get_zone() {
 | 
			
		||||
  i=2
 | 
			
		||||
  while true; do
 | 
			
		||||
    domain="$(printf "%s" "$fulldomain" | cut -d . -f "$i-100")"
 | 
			
		||||
    if [ -z "$domain" ]; then
 | 
			
		||||
      break
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    dyn_url="$DYN_API/Zone/$domain/"
 | 
			
		||||
 | 
			
		||||
    export _H1="Auth-Token: $_dyn_authtoken"
 | 
			
		||||
    export _H2="Content-Type: application/json"
 | 
			
		||||
 | 
			
		||||
    response="$(_get "$dyn_url" "" "")"
 | 
			
		||||
    sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')"
 | 
			
		||||
 | 
			
		||||
    _debug dyn_url "$dyn_url"
 | 
			
		||||
    _debug response "$response"
 | 
			
		||||
    _debug sessionstatus "$sessionstatus"
 | 
			
		||||
 | 
			
		||||
    if [ "$sessionstatus" = "success" ]; then
 | 
			
		||||
      _dyn_zone="$domain"
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
    i=$(_math "$i" + 1)
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  _dyn_zone=""
 | 
			
		||||
  _err "get zone failed"
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#add TXT record
 | 
			
		||||
_dyn_add_record() {
 | 
			
		||||
 | 
			
		||||
  _info "Adding TXT record"
 | 
			
		||||
 | 
			
		||||
  data="{\"rdata\":{\"txtdata\":\"$txtvalue\"},\"ttl\":\"300\"}"
 | 
			
		||||
  dyn_url="$DYN_API/TXTRecord/$_dyn_zone/$fulldomain/"
 | 
			
		||||
  method="POST"
 | 
			
		||||
 | 
			
		||||
  export _H1="Auth-Token: $_dyn_authtoken"
 | 
			
		||||
  export _H2="Content-Type: application/json"
 | 
			
		||||
 | 
			
		||||
  response="$(_post "$data" "$dyn_url" "" "$method")"
 | 
			
		||||
  sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')"
 | 
			
		||||
 | 
			
		||||
  _debug response "$response"
 | 
			
		||||
  _debug sessionstatus "$sessionstatus"
 | 
			
		||||
 | 
			
		||||
  if [ "$sessionstatus" = "success" ]; then
 | 
			
		||||
    _info "TXT Record successfully added"
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _err "add TXT record failed"
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#publish the zone
 | 
			
		||||
_dyn_publish_zone() {
 | 
			
		||||
 | 
			
		||||
  _info "Publishing zone"
 | 
			
		||||
 | 
			
		||||
  data="{\"publish\":\"true\"}"
 | 
			
		||||
  dyn_url="$DYN_API/Zone/$_dyn_zone/"
 | 
			
		||||
  method="PUT"
 | 
			
		||||
 | 
			
		||||
  export _H1="Auth-Token: $_dyn_authtoken"
 | 
			
		||||
  export _H2="Content-Type: application/json"
 | 
			
		||||
 | 
			
		||||
  response="$(_post "$data" "$dyn_url" "" "$method")"
 | 
			
		||||
  sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')"
 | 
			
		||||
 | 
			
		||||
  _debug response "$response"
 | 
			
		||||
  _debug sessionstatus "$sessionstatus"
 | 
			
		||||
 | 
			
		||||
  if [ "$sessionstatus" = "success" ]; then
 | 
			
		||||
    _info "Zone published"
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _err "publish zone failed"
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#get record_id of TXT record so we can delete the record
 | 
			
		||||
_dyn_get_record_id() {
 | 
			
		||||
 | 
			
		||||
  _info "Getting record_id of TXT record"
 | 
			
		||||
 | 
			
		||||
  dyn_url="$DYN_API/TXTRecord/$_dyn_zone/$fulldomain/"
 | 
			
		||||
 | 
			
		||||
  export _H1="Auth-Token: $_dyn_authtoken"
 | 
			
		||||
  export _H2="Content-Type: application/json"
 | 
			
		||||
 | 
			
		||||
  response="$(_get "$dyn_url" "" "")"
 | 
			
		||||
  sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')"
 | 
			
		||||
 | 
			
		||||
  _debug response "$response"
 | 
			
		||||
  _debug sessionstatus "$sessionstatus"
 | 
			
		||||
 | 
			
		||||
  if [ "$sessionstatus" = "success" ]; then
 | 
			
		||||
    _dyn_record_id="$(printf "%s\n" "$response" | _egrep_o "\"data\" *: *\[\"/REST/TXTRecord/$_dyn_zone/$fulldomain/[^\"]*" | _head_n 1 | sed "s#^\"data\" *: *\[\"/REST/TXTRecord/$_dyn_zone/$fulldomain/##")"
 | 
			
		||||
    _debug _dyn_record_id "$_dyn_record_id"
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _dyn_record_id=""
 | 
			
		||||
  _err "getting record_id failed"
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#delete TXT record
 | 
			
		||||
_dyn_rm_record() {
 | 
			
		||||
 | 
			
		||||
  _info "Deleting TXT record"
 | 
			
		||||
 | 
			
		||||
  dyn_url="$DYN_API/TXTRecord/$_dyn_zone/$fulldomain/$_dyn_record_id/"
 | 
			
		||||
  method="DELETE"
 | 
			
		||||
 | 
			
		||||
  _debug dyn_url "$dyn_url"
 | 
			
		||||
 | 
			
		||||
  export _H1="Auth-Token: $_dyn_authtoken"
 | 
			
		||||
  export _H2="Content-Type: application/json"
 | 
			
		||||
 | 
			
		||||
  response="$(_post "" "$dyn_url" "" "$method")"
 | 
			
		||||
  sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')"
 | 
			
		||||
 | 
			
		||||
  _debug response "$response"
 | 
			
		||||
  _debug sessionstatus "$sessionstatus"
 | 
			
		||||
 | 
			
		||||
  if [ "$sessionstatus" = "success" ]; then
 | 
			
		||||
    _info "TXT record successfully deleted"
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _err "delete TXT record failed"
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#logout
 | 
			
		||||
_dyn_end_session() {
 | 
			
		||||
 | 
			
		||||
  _info "End Dyn API Session"
 | 
			
		||||
 | 
			
		||||
  dyn_url="$DYN_API/Session/"
 | 
			
		||||
  method="DELETE"
 | 
			
		||||
 | 
			
		||||
  _debug dyn_url "$dyn_url"
 | 
			
		||||
 | 
			
		||||
  export _H1="Auth-Token: $_dyn_authtoken"
 | 
			
		||||
  export _H2="Content-Type: application/json"
 | 
			
		||||
 | 
			
		||||
  response="$(_post "" "$dyn_url" "" "$method")"
 | 
			
		||||
 | 
			
		||||
  _debug response "$response"
 | 
			
		||||
 | 
			
		||||
  _dyn_authtoken=""
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										228
									
								
								dnsapi/dns_dynu.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								dnsapi/dns_dynu.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,228 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#Client ID
 | 
			
		||||
#Dynu_ClientId="0b71cae7-a099-4f6b-8ddf-94571cdb760d"
 | 
			
		||||
#
 | 
			
		||||
#Secret
 | 
			
		||||
#Dynu_Secret="aCUEY4BDCV45KI8CSIC3sp2LKQ9"
 | 
			
		||||
#
 | 
			
		||||
#Token
 | 
			
		||||
Dynu_Token=""
 | 
			
		||||
#
 | 
			
		||||
#Endpoint
 | 
			
		||||
Dynu_EndPoint="https://api.dynu.com/v1"
 | 
			
		||||
#
 | 
			
		||||
#Author: Dynu Systems, Inc.
 | 
			
		||||
#Report Bugs here: https://github.com/shar0119/acme.sh
 | 
			
		||||
#
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_dynu_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  if [ -z "$Dynu_ClientId" ] || [ -z "$Dynu_Secret" ]; then
 | 
			
		||||
    Dynu_ClientId=""
 | 
			
		||||
    Dynu_Secret=""
 | 
			
		||||
    _err "Dynu client id and secret is not specified."
 | 
			
		||||
    _err "Please create you API client id and secret and try again."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  #save the client id and secret to the account conf file.
 | 
			
		||||
  _saveaccountconf Dynu_ClientId "$Dynu_ClientId"
 | 
			
		||||
  _saveaccountconf Dynu_Secret "$Dynu_Secret"
 | 
			
		||||
 | 
			
		||||
  if [ -z "$Dynu_Token" ]; then
 | 
			
		||||
    _info "Getting Dynu token."
 | 
			
		||||
    if ! _dynu_authentication; then
 | 
			
		||||
      _err "Can not get token."
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug "Detect root zone"
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "Invalid domain."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug _node "$_node"
 | 
			
		||||
  _debug _domain_name "$_domain_name"
 | 
			
		||||
 | 
			
		||||
  _info "Creating TXT record."
 | 
			
		||||
  if ! _dynu_rest POST "dns/record/add" "{\"domain_name\":\"$_domain_name\",\"node_name\":\"$_node\",\"record_type\":\"TXT\",\"text_data\":\"$txtvalue\",\"state\":true,\"ttl\":90}"; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! _contains "$response" "text_data"; then
 | 
			
		||||
    _err "Could not add TXT record."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#Usage: rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_dynu_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  if [ -z "$Dynu_ClientId" ] || [ -z "$Dynu_Secret" ]; then
 | 
			
		||||
    Dynu_ClientId=""
 | 
			
		||||
    Dynu_Secret=""
 | 
			
		||||
    _err "Dynu client id and secret is not specified."
 | 
			
		||||
    _err "Please create you API client id and secret and try again."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  #save the client id and secret to the account conf file.
 | 
			
		||||
  _saveaccountconf Dynu_ClientId "$Dynu_ClientId"
 | 
			
		||||
  _saveaccountconf Dynu_Secret "$Dynu_Secret"
 | 
			
		||||
 | 
			
		||||
  if [ -z "$Dynu_Token" ]; then
 | 
			
		||||
    _info "Getting Dynu token."
 | 
			
		||||
    if ! _dynu_authentication; then
 | 
			
		||||
      _err "Can not get token."
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug "Detect root zone."
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "Invalid domain."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug _node "$_node"
 | 
			
		||||
  _debug _domain_name "$_domain_name"
 | 
			
		||||
 | 
			
		||||
  _info "Checking for TXT record."
 | 
			
		||||
  if ! _get_recordid "$fulldomain" "$txtvalue"; then
 | 
			
		||||
    _err "Could not get TXT record id."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ "$_dns_record_id" = "" ]; then
 | 
			
		||||
    _err "TXT record not found."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Removing TXT record."
 | 
			
		||||
  if ! _delete_txt_record "$_dns_record_id"; then
 | 
			
		||||
    _err "Could not remove TXT record $_dns_record_id."
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
########  Private functions below ##################################
 | 
			
		||||
#_acme-challenge.www.domain.com
 | 
			
		||||
#returns
 | 
			
		||||
# _node=_acme-challenge.www
 | 
			
		||||
# _domain_name=domain.com
 | 
			
		||||
_get_root() {
 | 
			
		||||
  domain=$1
 | 
			
		||||
  i=2
 | 
			
		||||
  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 ! _dynu_rest GET "dns/get/$h"; then
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
 | 
			
		||||
      _domain_name=$h
 | 
			
		||||
      _node=$(printf "%s" "$domain" | cut -d . -f 1-$p)
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
    p=$i
 | 
			
		||||
    i=$(_math "$i" + 1)
 | 
			
		||||
  done
 | 
			
		||||
  return 1
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_get_recordid() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  if ! _dynu_rest GET "dns/record/get?hostname=$fulldomain&rrtype=TXT"; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! _contains "$response" "$txtvalue"; then
 | 
			
		||||
    _dns_record_id=0
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _dns_record_id=$(printf "%s" "$response" | _egrep_o "{[^}]*}" | grep "\"text_data\":\"$txtvalue\"" | _egrep_o ",[^,]*," | grep ',"id":' | tr -d ",," | cut -d : -f 2)
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_delete_txt_record() {
 | 
			
		||||
  _dns_record_id=$1
 | 
			
		||||
 | 
			
		||||
  if ! _dynu_rest GET "dns/record/delete/$_dns_record_id"; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! _contains "$response" "true"; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_dynu_rest() {
 | 
			
		||||
  m=$1
 | 
			
		||||
  ep="$2"
 | 
			
		||||
  data="$3"
 | 
			
		||||
  _debug "$ep"
 | 
			
		||||
 | 
			
		||||
  export _H1="Authorization: Bearer $Dynu_Token"
 | 
			
		||||
  export _H2="Content-Type: application/json"
 | 
			
		||||
 | 
			
		||||
  if [ "$data" ]; then
 | 
			
		||||
    _debug data "$data"
 | 
			
		||||
    response="$(_post "$data" "$Dynu_EndPoint/$ep" "" "$m")"
 | 
			
		||||
  else
 | 
			
		||||
    _info "Getting $Dynu_EndPoint/$ep"
 | 
			
		||||
    response="$(_get "$Dynu_EndPoint/$ep")"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "error $ep"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_dynu_authentication() {
 | 
			
		||||
  realm="$(printf "%s" "$Dynu_ClientId:$Dynu_Secret" | _base64)"
 | 
			
		||||
 | 
			
		||||
  export _H1="Authorization: Basic $realm"
 | 
			
		||||
  export _H2="Content-Type: application/json"
 | 
			
		||||
 | 
			
		||||
  response="$(_get "$Dynu_EndPoint/oauth2/token")"
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "Authentication failed."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  if _contains "$response" "accessToken"; then
 | 
			
		||||
    Dynu_Token=$(printf "%s" "$response" | tr -d "[]" | cut -d , -f 2 | cut -d : -f 2 | cut -d '"' -f 2)
 | 
			
		||||
  fi
 | 
			
		||||
  if _contains "$Dynu_Token" "null"; then
 | 
			
		||||
    Dynu_Token=""
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
@@ -10,7 +10,7 @@
 | 
			
		||||
#
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
# Export FreeDNS userid and password in folowing variables...
 | 
			
		||||
# Export FreeDNS userid and password in following variables...
 | 
			
		||||
#  FREEDNS_User=username
 | 
			
		||||
#  FREEDNS_Password=password
 | 
			
		||||
# login cookie is saved in acme account config file so userid / pw
 | 
			
		||||
@@ -53,7 +53,7 @@ dns_freedns_add() {
 | 
			
		||||
  i="$(_math "$i" - 1)"
 | 
			
		||||
  sub_domain="$(echo "$fulldomain" | cut -d. -f -"$i")"
 | 
			
		||||
 | 
			
		||||
  # Sometimes FreeDNS does not reurn the subdomain page but rather 
 | 
			
		||||
  # Sometimes FreeDNS does not return the subdomain page but rather
 | 
			
		||||
  # returns a page regarding becoming a premium member.  This usually
 | 
			
		||||
  # happens after a period of inactivity.  Immediately trying again
 | 
			
		||||
  # returns the correct subdomain page.  So, we will try twice to
 | 
			
		||||
@@ -65,14 +65,14 @@ dns_freedns_add() {
 | 
			
		||||
    htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")"
 | 
			
		||||
    if [ "$?" != "0" ]; then
 | 
			
		||||
      if [ "$using_cached_cookies" = "true" ]; then
 | 
			
		||||
        _err "Has your FreeDNS username and password channged?  If so..."
 | 
			
		||||
        _err "Has your FreeDNS username and password changed?  If so..."
 | 
			
		||||
        _err "Please export as FREEDNS_User / FREEDNS_Password and try again."
 | 
			
		||||
      fi
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # Now convert the tables in the HTML to CSV.  This litte gem from
 | 
			
		||||
    # http://stackoverflow.com/questions/1403087/how-can-i-convert-an-html-table-to-csv    
 | 
			
		||||
    # http://stackoverflow.com/questions/1403087/how-can-i-convert-an-html-table-to-csv
 | 
			
		||||
    subdomain_csv="$(echo "$htmlpage" \
 | 
			
		||||
      | grep -i -e '</\?TABLE\|</\?TD\|</\?TR\|</\?TH' \
 | 
			
		||||
      | sed 's/^[\ \t]*//g' \
 | 
			
		||||
@@ -112,7 +112,7 @@ dns_freedns_add() {
 | 
			
		||||
          # not produce accurate results as the value field is truncated
 | 
			
		||||
          # on this webpage. To get full value we would need to load
 | 
			
		||||
          # another page. However we don't really need this so long as
 | 
			
		||||
          # there is only one TXT record for the acme chalenge subdomain.
 | 
			
		||||
          # there is only one TXT record for the acme challenge subdomain.
 | 
			
		||||
          DNSvalue="$(echo "$line" | cut -d ',' -f 4 | sed 's/^[^"]*"//;s/".*//;s/<\/td>.*//')"
 | 
			
		||||
          if [ $found != 0 ]; then
 | 
			
		||||
            break
 | 
			
		||||
@@ -192,11 +192,11 @@ dns_freedns_rm() {
 | 
			
		||||
 | 
			
		||||
  # Need to read cookie from conf file again in case new value set
 | 
			
		||||
  # during login to FreeDNS when TXT record was created.
 | 
			
		||||
  # acme.sh does not have a _readaccountconf() fuction
 | 
			
		||||
  # acme.sh does not have a _readaccountconf() function
 | 
			
		||||
  FREEDNS_COOKIE="$(_read_conf "$ACCOUNT_CONF_PATH" "FREEDNS_COOKIE")"
 | 
			
		||||
  _debug "FreeDNS login cookies: $FREEDNS_COOKIE"
 | 
			
		||||
 | 
			
		||||
  # Sometimes FreeDNS does not reurn the subdomain page but rather 
 | 
			
		||||
  # Sometimes FreeDNS does not return the subdomain page but rather
 | 
			
		||||
  # returns a page regarding becoming a premium member.  This usually
 | 
			
		||||
  # happens after a period of inactivity.  Immediately trying again
 | 
			
		||||
  # returns the correct subdomain page.  So, we will try twice to
 | 
			
		||||
@@ -302,12 +302,12 @@ _freedns_retrieve_subdomain_page() {
 | 
			
		||||
  export _H2="Accept-Language:en-US"
 | 
			
		||||
  url="https://freedns.afraid.org/subdomain/"
 | 
			
		||||
 | 
			
		||||
  _debug "Retrieve subdmoain page from FreeDNS"
 | 
			
		||||
  _debug "Retrieve subdomain page from FreeDNS"
 | 
			
		||||
 | 
			
		||||
  htmlpage="$(_get "$url")"
 | 
			
		||||
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "FreeDNS retrieve subdomins failed bad RC from _get"
 | 
			
		||||
    _err "FreeDNS retrieve subdomains failed bad RC from _get"
 | 
			
		||||
    return 1
 | 
			
		||||
  elif [ -z "$htmlpage" ]; then
 | 
			
		||||
    _err "FreeDNS returned empty subdomain page"
 | 
			
		||||
@@ -341,7 +341,7 @@ _freedns_add_txt_record() {
 | 
			
		||||
    return 1
 | 
			
		||||
  elif _contains "$htmlpage" "security code was incorrect"; then
 | 
			
		||||
    _debug "$htmlpage"
 | 
			
		||||
    _err "FreeDNS failed to add TXT record for $subdomain as FreeDNS requested seurity code"
 | 
			
		||||
    _err "FreeDNS failed to add TXT record for $subdomain as FreeDNS requested security code"
 | 
			
		||||
    _err "Note that you cannot use automatic DNS validation for FreeDNS public domains"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										123
									
								
								dnsapi/dns_gandi_livedns.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										123
									
								
								dnsapi/dns_gandi_livedns.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,123 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
# Gandi LiveDNS v5 API
 | 
			
		||||
# http://doc.livedns.gandi.net/
 | 
			
		||||
# currently under beta
 | 
			
		||||
#
 | 
			
		||||
# Requires GANDI API KEY set in GANDI_LIVEDNS_KEY set as environment variable
 | 
			
		||||
#
 | 
			
		||||
#Author: Frédéric Crozat <fcrozat@suse.com>
 | 
			
		||||
#Report Bugs here: https://github.com/fcrozat/acme.sh
 | 
			
		||||
#
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
GANDI_LIVEDNS_API="https://dns.beta.gandi.net/api/v5"
 | 
			
		||||
 | 
			
		||||
#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"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _saveaccountconf GANDI_LIVEDNS_KEY "$GANDI_LIVEDNS_KEY"
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "invalid domain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug fulldomain "$fulldomain"
 | 
			
		||||
  _debug txtvalue "$txtvalue"
 | 
			
		||||
  _debug domain "$_domain"
 | 
			
		||||
  _debug sub_domain "$_sub_domain"
 | 
			
		||||
 | 
			
		||||
  _gandi_livedns_rest PUT "domains/$_domain/records/$_sub_domain/TXT" "{\"rrset_ttl\": 300, \"rrset_values\":[\"$txtvalue\"]}" \
 | 
			
		||||
    && _contains "$response" '{"message": "DNS Record Created"}' \
 | 
			
		||||
    && _info "Add $(__green "success")"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#Usage: fulldomain txtvalue
 | 
			
		||||
#Remove the txt record after validation.
 | 
			
		||||
dns_gandi_livedns_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "invalid domain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug fulldomain "$fulldomain"
 | 
			
		||||
  _debug domain "$_domain"
 | 
			
		||||
  _debug sub_domain "$_sub_domain"
 | 
			
		||||
 | 
			
		||||
  _gandi_livedns_rest DELETE "domains/$_domain/records/$_sub_domain/TXT" ""
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
#_acme-challenge.www.domain.com
 | 
			
		||||
#returns
 | 
			
		||||
# _sub_domain=_acme-challenge.www
 | 
			
		||||
# _domain=domain.com
 | 
			
		||||
_get_root() {
 | 
			
		||||
  domain=$1
 | 
			
		||||
  i=2
 | 
			
		||||
  p=1
 | 
			
		||||
  while true; do
 | 
			
		||||
    h=$(printf "%s" "$domain" | cut -d . -f $i-100)
 | 
			
		||||
    _debug h "$h"
 | 
			
		||||
    if [ -z "$h" ]; then
 | 
			
		||||
      #not valid
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if ! _gandi_livedns_rest GET "domains/$h"; then
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if _contains "$response" '"code": 401'; then
 | 
			
		||||
      _err "$response"
 | 
			
		||||
      return 1
 | 
			
		||||
    elif _contains "$response" '"code": 404'; then
 | 
			
		||||
      _debug "$h not found"
 | 
			
		||||
    else
 | 
			
		||||
      _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
 | 
			
		||||
      _domain="$h"
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
    p="$i"
 | 
			
		||||
    i=$(_math "$i" + 1)
 | 
			
		||||
  done
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_gandi_livedns_rest() {
 | 
			
		||||
  m=$1
 | 
			
		||||
  ep="$2"
 | 
			
		||||
  data="$3"
 | 
			
		||||
  _debug "$ep"
 | 
			
		||||
 | 
			
		||||
  export _H1="Content-Type: application/json"
 | 
			
		||||
  export _H2="X-Api-Key: $GANDI_LIVEDNS_KEY"
 | 
			
		||||
 | 
			
		||||
  if [ "$m" = "GET" ]; then
 | 
			
		||||
    response="$(_get "$GANDI_LIVEDNS_API/$ep")"
 | 
			
		||||
  else
 | 
			
		||||
    _debug data "$data"
 | 
			
		||||
    response="$(_post "$data" "$GANDI_LIVEDNS_API/$ep" "" "$m")"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "error $ep"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
@@ -40,7 +40,7 @@ dns_gd_add() {
 | 
			
		||||
  if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[{\"data\":\"$txtvalue\"}]"; then
 | 
			
		||||
    if [ "$response" = "{}" ]; then
 | 
			
		||||
      _info "Added, sleeping 10 seconds"
 | 
			
		||||
      sleep 10
 | 
			
		||||
      _sleep 10
 | 
			
		||||
      #todo: check if the record takes effect
 | 
			
		||||
      return 0
 | 
			
		||||
    else
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										175
									
								
								dnsapi/dns_he.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										175
									
								
								dnsapi/dns_he.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,175 @@
 | 
			
		||||
#!/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
 | 
			
		||||
 | 
			
		||||
#-- dns_he_add() - Add TXT record --------------------------------------
 | 
			
		||||
# Usage: dns_he_add _acme-challenge.subdomain.domain.com "XyZ123..."
 | 
			
		||||
 | 
			
		||||
dns_he_add() {
 | 
			
		||||
  _full_domain=$1
 | 
			
		||||
  _txt_value=$2
 | 
			
		||||
  _info "Using DNS-01 Hurricane Electric hook"
 | 
			
		||||
 | 
			
		||||
  if [ -z "$HE_Username" ] || [ -z "$HE_Password" ]; then
 | 
			
		||||
    HE_Username=
 | 
			
		||||
    HE_Password=
 | 
			
		||||
    _err "No auth details provided. Please set user credentials using the \$HE_Username and \$HE_Password envoronment variables."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _saveaccountconf HE_Username "$HE_Username"
 | 
			
		||||
  _saveaccountconf HE_Password "$HE_Password"
 | 
			
		||||
 | 
			
		||||
  # Fills in the $_zone_id
 | 
			
		||||
  _find_zone "$_full_domain" || return 1
 | 
			
		||||
  _debug "Zone id \"$_zone_id\" will be used."
 | 
			
		||||
 | 
			
		||||
  body="email=${HE_Username}&pass=${HE_Password}"
 | 
			
		||||
  body="$body&account="
 | 
			
		||||
  body="$body&menu=edit_zone"
 | 
			
		||||
  body="$body&Type=TXT"
 | 
			
		||||
  body="$body&hosted_dns_zoneid=$_zone_id"
 | 
			
		||||
  body="$body&hosted_dns_recordid="
 | 
			
		||||
  body="$body&hosted_dns_editzone=1"
 | 
			
		||||
  body="$body&Priority="
 | 
			
		||||
  body="$body&Name=$_full_domain"
 | 
			
		||||
  body="$body&Content=$_txt_value"
 | 
			
		||||
  body="$body&TTL=300"
 | 
			
		||||
  body="$body&hosted_dns_editrecord=Submit"
 | 
			
		||||
  response="$(_post "$body" "https://dns.he.net/")"
 | 
			
		||||
  exit_code="$?"
 | 
			
		||||
  if [ "$exit_code" -eq 0 ]; then
 | 
			
		||||
    _info "TXT record added successfully."
 | 
			
		||||
  else
 | 
			
		||||
    _err "Couldn't add the TXT record."
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
  return "$exit_code"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-- dns_he_rm() - Remove TXT record ------------------------------------
 | 
			
		||||
# Usage: dns_he_rm _acme-challenge.subdomain.domain.com "XyZ123..."
 | 
			
		||||
 | 
			
		||||
dns_he_rm() {
 | 
			
		||||
  _full_domain=$1
 | 
			
		||||
  _txt_value=$2
 | 
			
		||||
  _info "Cleaning up after DNS-01 Hurricane Electric hook"
 | 
			
		||||
 | 
			
		||||
  # fills in the $_zone_id
 | 
			
		||||
  _find_zone "$_full_domain" || return 1
 | 
			
		||||
  _debug "Zone id \"$_zone_id\" will be used."
 | 
			
		||||
 | 
			
		||||
  # Find the record id to clean
 | 
			
		||||
  body="email=${HE_Username}&pass=${HE_Password}"
 | 
			
		||||
  body="$body&hosted_dns_zoneid=$_zone_id"
 | 
			
		||||
  body="$body&menu=edit_zone"
 | 
			
		||||
  body="$body&hosted_dns_editzone="
 | 
			
		||||
  domain_regex="$(echo "$_full_domain" | sed 's/\./\\./g')" # escape dots
 | 
			
		||||
  _record_id=$(_post "$body" "https://dns.he.net/" \
 | 
			
		||||
    | tr -d '\n' \
 | 
			
		||||
    | _egrep_o "data=\""${_txt_value}"([^>]+>){6}[^<]+<[^;]+;deleteRecord\('[0-9]+','${domain_regex}','TXT'\)" \
 | 
			
		||||
    | _egrep_o "[0-9]+','${domain_regex}','TXT'\)$" \
 | 
			
		||||
    | _egrep_o "^[0-9]+"
 | 
			
		||||
  )
 | 
			
		||||
  # The series of egreps above could have been done a bit shorter but
 | 
			
		||||
  #  I wanted to double-check whether it's the correct record (in case
 | 
			
		||||
  #  HE changes their website somehow).
 | 
			
		||||
 | 
			
		||||
  # Remove the record
 | 
			
		||||
  body="email=${HE_Username}&pass=${HE_Password}"
 | 
			
		||||
  body="$body&menu=edit_zone"
 | 
			
		||||
  body="$body&hosted_dns_zoneid=$_zone_id"
 | 
			
		||||
  body="$body&hosted_dns_recordid=$_record_id"
 | 
			
		||||
  body="$body&hosted_dns_editzone=1"
 | 
			
		||||
  body="$body&hosted_dns_delrecord=1"
 | 
			
		||||
  body="$body&hosted_dns_delconfirm=delete"
 | 
			
		||||
  _post "$body" "https://dns.he.net/" \
 | 
			
		||||
    | grep '<div id="dns_status" onClick="hideThis(this);">Successfully removed record.</div>' \
 | 
			
		||||
      >/dev/null
 | 
			
		||||
  exit_code="$?"
 | 
			
		||||
  if [ "$exit_code" -eq 0 ]; then
 | 
			
		||||
    _info "Record removed successfully."
 | 
			
		||||
  else
 | 
			
		||||
    _err "Could not clean (remove) up the record. Please go to HE administration interface and clean it by hand."
 | 
			
		||||
    return "$exit_code"
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
########################## PRIVATE FUNCTIONS ###########################
 | 
			
		||||
 | 
			
		||||
#-- _find_zone() -------------------------------------------------------
 | 
			
		||||
# Returns the most specific zone found in administration interface.
 | 
			
		||||
#
 | 
			
		||||
# Example:
 | 
			
		||||
#
 | 
			
		||||
# _find_zone first.second.third.co.uk
 | 
			
		||||
#
 | 
			
		||||
# ... will return the first zone that exists in admin out of these:
 | 
			
		||||
# - "first.second.third.co.uk"
 | 
			
		||||
# - "second.third.co.uk"
 | 
			
		||||
# - "third.co.uk"
 | 
			
		||||
# - "co.uk" <-- unlikely
 | 
			
		||||
# - "uk"    <-'
 | 
			
		||||
#
 | 
			
		||||
# (another approach would be something like this:
 | 
			
		||||
#   https://github.com/hlandau/acme/blob/master/_doc/dns.hook
 | 
			
		||||
#   - that's better if there are multiple pages. It's so much simpler.
 | 
			
		||||
# )
 | 
			
		||||
 | 
			
		||||
_find_zone() {
 | 
			
		||||
 | 
			
		||||
  _domain="$1"
 | 
			
		||||
 | 
			
		||||
  body="email=${HE_Username}&pass=${HE_Password}"
 | 
			
		||||
  _matches=$(_post "$body" "https://dns.he.net/" \
 | 
			
		||||
    | _egrep_o "delete_dom.*name=\"[^\"]+\" value=\"[0-9]+"
 | 
			
		||||
  )
 | 
			
		||||
  # Zone names and zone IDs are in same order
 | 
			
		||||
  _zone_ids=$(echo "$_matches" | cut -d '"' -f 5)
 | 
			
		||||
  _zone_names=$(echo "$_matches" | cut -d '"' -f 3)
 | 
			
		||||
  _debug2 "These are the zones on this HE account:"
 | 
			
		||||
  _debug2 "$_zone_names"
 | 
			
		||||
  _debug2 "And these are their respective IDs:"
 | 
			
		||||
  _debug2 "$_zone_ids"
 | 
			
		||||
 | 
			
		||||
  # Walk through all possible zone names
 | 
			
		||||
  _strip_counter=1
 | 
			
		||||
  while true; do
 | 
			
		||||
    _attempted_zone=$(echo "$_domain" | cut -d . -f ${_strip_counter}-)
 | 
			
		||||
 | 
			
		||||
    # All possible zone names have been tried
 | 
			
		||||
    if [ -z "$_attempted_zone" ]; then
 | 
			
		||||
      _err "No zone for domain \"$_domain\" found."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    _debug "Looking for zone \"${_attempted_zone}\""
 | 
			
		||||
 | 
			
		||||
    # Take care of "." and only match whole lines. Note that grep -F
 | 
			
		||||
    # cannot be used because there's no way to make it match whole
 | 
			
		||||
    # lines.
 | 
			
		||||
    regex="^$(echo "$_attempted_zone" | sed 's/\./\\./g')$"
 | 
			
		||||
    line_num=$(echo "$_zone_names" \
 | 
			
		||||
      | grep -n "$regex" \
 | 
			
		||||
      | cut -d : -f 1
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    if [ -n "$line_num" ]; then
 | 
			
		||||
      _zone_id=$(echo "$_zone_ids" | sed "${line_num}q;d")
 | 
			
		||||
      _debug "Found relevant zone \"$_attempted_zone\" with id \"$_zone_id\" - will be used for domain \"$_domain\"."
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    _debug "Zone \"$_attempted_zone\" doesn't exist, let's try a less specific zone."
 | 
			
		||||
    _strip_counter=$(_math "$_strip_counter" + 1)
 | 
			
		||||
  done
 | 
			
		||||
}
 | 
			
		||||
# vim: et:ts=2:sw=2:
 | 
			
		||||
							
								
								
									
										102
									
								
								dnsapi/dns_infoblox.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								dnsapi/dns_infoblox.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,102 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
## Infoblox API integration by Jason Keller and Elijah Tenai
 | 
			
		||||
##
 | 
			
		||||
## Report any bugs via https://github.com/jasonkeller/acme.sh
 | 
			
		||||
 | 
			
		||||
dns_infoblox_add() {
 | 
			
		||||
 | 
			
		||||
  ## Nothing to see here, just some housekeeping
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
  baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&view=$Infoblox_View"
 | 
			
		||||
 | 
			
		||||
  _info "Using Infoblox API"
 | 
			
		||||
  _debug fulldomain "$fulldomain"
 | 
			
		||||
  _debug txtvalue "$txtvalue"
 | 
			
		||||
 | 
			
		||||
  ## Check for the credentials
 | 
			
		||||
  if [ -z "$Infoblox_Creds" ] || [ -z "$Infoblox_Server" ]; then
 | 
			
		||||
    Infoblox_Creds=""
 | 
			
		||||
    Infoblox_Server=""
 | 
			
		||||
    _err "You didn't specify the credentials, server or infoblox view yet (Infoblox_Creds, Infoblox_Server and Infoblox_View)."
 | 
			
		||||
    _err "Please set them via EXPORT ([username:password], [ip or hostname]) and try again."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "$Infoblox_View" ]; then
 | 
			
		||||
    Infoblox_View="default"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  ## Save the credentials to the account file
 | 
			
		||||
  _saveaccountconf Infoblox_Creds "$Infoblox_Creds"
 | 
			
		||||
  _saveaccountconf Infoblox_Server "$Infoblox_Server"
 | 
			
		||||
  _saveaccountconf Infoblox_View "$Infoblox_View"
 | 
			
		||||
 | 
			
		||||
  ## Base64 encode the credentials
 | 
			
		||||
  Infoblox_CredsEncoded=$(printf "%b" "$Infoblox_Creds" | _base64)
 | 
			
		||||
 | 
			
		||||
  ## Construct the HTTP Authorization header
 | 
			
		||||
  export _H1="Accept-Language:en-US"
 | 
			
		||||
  export _H2="Authorization: Basic $Infoblox_CredsEncoded"
 | 
			
		||||
 | 
			
		||||
  ## Add the challenge record to the Infoblox grid member
 | 
			
		||||
  result="$(_post "" "$baseurlnObject" "" "POST")"
 | 
			
		||||
 | 
			
		||||
  ## Let's see if we get something intelligible back from the unit
 | 
			
		||||
  if [ "$(echo "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then
 | 
			
		||||
    _info "Successfully created the txt record"
 | 
			
		||||
    return 0
 | 
			
		||||
  else
 | 
			
		||||
    _err "Error encountered during record addition"
 | 
			
		||||
    _err "$result"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dns_infoblox_rm() {
 | 
			
		||||
 | 
			
		||||
  ## Nothing to see here, just some housekeeping
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  _info "Using Infoblox API"
 | 
			
		||||
  _debug fulldomain "$fulldomain"
 | 
			
		||||
  _debug txtvalue "$txtvalue"
 | 
			
		||||
 | 
			
		||||
  ## Base64 encode the credentials
 | 
			
		||||
  Infoblox_CredsEncoded="$(printf "%b" "$Infoblox_Creds" | _base64)"
 | 
			
		||||
 | 
			
		||||
  ## Construct the HTTP Authorization header
 | 
			
		||||
  export _H1="Accept-Language:en-US"
 | 
			
		||||
  export _H2="Authorization: Basic $Infoblox_CredsEncoded"
 | 
			
		||||
 | 
			
		||||
  ## Does the record exist?  Let's check.
 | 
			
		||||
  baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&view=$Infoblox_View&_return_type=xml-pretty"
 | 
			
		||||
  result="$(_get "$baseurlnObject")"
 | 
			
		||||
 | 
			
		||||
  ## Let's see if we get something intelligible back from the grid
 | 
			
		||||
  if [ "$(echo "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then
 | 
			
		||||
    ## Extract the object reference
 | 
			
		||||
    objRef="$(printf "%b" "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")"
 | 
			
		||||
    objRmUrl="https://$Infoblox_Server/wapi/v2.2.2/$objRef"
 | 
			
		||||
    ## Delete them! All the stale records!
 | 
			
		||||
    rmResult="$(_post "" "$objRmUrl" "" "DELETE")"
 | 
			
		||||
    ## Let's see if that worked
 | 
			
		||||
    if [ "$(echo "$rmResult" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then
 | 
			
		||||
      _info "Successfully deleted $objRef"
 | 
			
		||||
      return 0
 | 
			
		||||
    else
 | 
			
		||||
      _err "Error occurred during txt record delete"
 | 
			
		||||
      _err "$rmResult"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    _err "Record to delete didn't match an existing record"
 | 
			
		||||
    _err "$result"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
							
								
								
									
										95
									
								
								dnsapi/dns_knot.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								dnsapi/dns_knot.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,95 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: dns_knot_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_knot_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
  _checkKey || return 1
 | 
			
		||||
  [ -n "${KNOT_SERVER}" ] || KNOT_SERVER="localhost"
 | 
			
		||||
  # save the dns server and key to the account.conf file.
 | 
			
		||||
  _saveaccountconf KNOT_SERVER "${KNOT_SERVER}"
 | 
			
		||||
  _saveaccountconf KNOT_KEY "${KNOT_KEY}"
 | 
			
		||||
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "Domain does not exist."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Adding ${fulldomain}. 60 TXT \"${txtvalue}\""
 | 
			
		||||
 | 
			
		||||
  knsupdate -y "${KNOT_KEY}" <<EOF
 | 
			
		||||
server ${KNOT_SERVER}
 | 
			
		||||
zone ${_domain}.
 | 
			
		||||
update add ${fulldomain}. 60 TXT "${txtvalue}"
 | 
			
		||||
send
 | 
			
		||||
quit
 | 
			
		||||
EOF
 | 
			
		||||
 | 
			
		||||
  if [ $? -ne 0 ]; then
 | 
			
		||||
    _err "Error updating domain."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Domain TXT record successfully added."
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#Usage: dns_knot_rm   _acme-challenge.www.domain.com
 | 
			
		||||
dns_knot_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  _checkKey || return 1
 | 
			
		||||
  [ -n "${KNOT_SERVER}" ] || KNOT_SERVER="localhost"
 | 
			
		||||
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "Domain does not exist."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Removing ${fulldomain}. TXT"
 | 
			
		||||
 | 
			
		||||
  knsupdate -y "${KNOT_KEY}" <<EOF
 | 
			
		||||
server ${KNOT_SERVER}
 | 
			
		||||
zone ${_domain}.
 | 
			
		||||
update del ${fulldomain}. TXT
 | 
			
		||||
send
 | 
			
		||||
quit
 | 
			
		||||
EOF
 | 
			
		||||
 | 
			
		||||
  if [ $? -ne 0 ]; then
 | 
			
		||||
    _err "error updating domain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Domain TXT record successfully deleted."
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
# _acme-challenge.www.domain.com
 | 
			
		||||
# returns
 | 
			
		||||
# _domain=domain.com
 | 
			
		||||
_get_root() {
 | 
			
		||||
  domain=$1
 | 
			
		||||
  i="$(echo "$fulldomain" | tr '.' ' ' | wc -w)"
 | 
			
		||||
  i=$(_math "$i" - 1)
 | 
			
		||||
 | 
			
		||||
  while true; do
 | 
			
		||||
    h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
 | 
			
		||||
    if [ -z "$h" ]; then
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    _domain="$h"
 | 
			
		||||
    return 0
 | 
			
		||||
  done
 | 
			
		||||
  _debug "$domain not found"
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_checkKey() {
 | 
			
		||||
  if [ -z "${KNOT_KEY}" ]; then
 | 
			
		||||
    _err "You must specify a TSIG key to authenticate the request."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
@@ -34,7 +34,7 @@ dns_lexicon_add() {
 | 
			
		||||
  # shellcheck disable=SC2018,SC2019
 | 
			
		||||
  Lx_name=$(echo LEXICON_"${PROVIDER}"_USERNAME | tr 'a-z' 'A-Z')
 | 
			
		||||
  Lx_name_v=$(eval echo \$"$Lx_name")
 | 
			
		||||
  _debug "$Lx_name" "$Lx_name_v"
 | 
			
		||||
  _secure_debug "$Lx_name" "$Lx_name_v"
 | 
			
		||||
  if [ "$Lx_name_v" ]; then
 | 
			
		||||
    _saveaccountconf "$Lx_name" "$Lx_name_v"
 | 
			
		||||
    eval export "$Lx_name"
 | 
			
		||||
@@ -43,7 +43,7 @@ dns_lexicon_add() {
 | 
			
		||||
  # shellcheck disable=SC2018,SC2019
 | 
			
		||||
  Lx_token=$(echo LEXICON_"${PROVIDER}"_TOKEN | tr 'a-z' 'A-Z')
 | 
			
		||||
  Lx_token_v=$(eval echo \$"$Lx_token")
 | 
			
		||||
  _debug "$Lx_token" "$Lx_token_v"
 | 
			
		||||
  _secure_debug "$Lx_token" "$Lx_token_v"
 | 
			
		||||
  if [ "$Lx_token_v" ]; then
 | 
			
		||||
    _saveaccountconf "$Lx_token" "$Lx_token_v"
 | 
			
		||||
    eval export "$Lx_token"
 | 
			
		||||
@@ -52,7 +52,7 @@ dns_lexicon_add() {
 | 
			
		||||
  # shellcheck disable=SC2018,SC2019
 | 
			
		||||
  Lx_password=$(echo LEXICON_"${PROVIDER}"_PASSWORD | tr 'a-z' 'A-Z')
 | 
			
		||||
  Lx_password_v=$(eval echo \$"$Lx_password")
 | 
			
		||||
  _debug "$Lx_password" "$Lx_password_v"
 | 
			
		||||
  _secure_debug "$Lx_password" "$Lx_password_v"
 | 
			
		||||
  if [ "$Lx_password_v" ]; then
 | 
			
		||||
    _saveaccountconf "$Lx_password" "$Lx_password_v"
 | 
			
		||||
    eval export "$Lx_password"
 | 
			
		||||
@@ -61,7 +61,7 @@ dns_lexicon_add() {
 | 
			
		||||
  # shellcheck disable=SC2018,SC2019
 | 
			
		||||
  Lx_domaintoken=$(echo LEXICON_"${PROVIDER}"_DOMAINTOKEN | tr 'a-z' 'A-Z')
 | 
			
		||||
  Lx_domaintoken_v=$(eval echo \$"$Lx_domaintoken")
 | 
			
		||||
  _debug "$Lx_domaintoken" "$Lx_domaintoken_v"
 | 
			
		||||
  _secure_debug "$Lx_domaintoken" "$Lx_domaintoken_v"
 | 
			
		||||
  if [ "$Lx_domaintoken_v" ]; then
 | 
			
		||||
    eval export "$Lx_domaintoken"
 | 
			
		||||
    _saveaccountconf "$Lx_domaintoken" "$Lx_domaintoken_v"
 | 
			
		||||
 
 | 
			
		||||
@@ -68,7 +68,7 @@ dns_linode_rm() {
 | 
			
		||||
  _parameters="&DomainID=$_domain_id"
 | 
			
		||||
 | 
			
		||||
  if _rest GET "domain.resource.list" "$_parameters" && [ -n "$response" ]; then
 | 
			
		||||
    response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')"
 | 
			
		||||
    response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")"
 | 
			
		||||
 | 
			
		||||
    resource="$(echo "$response" | _egrep_o "{.*\"NAME\":\s*\"$_sub_domain\".*}")"
 | 
			
		||||
    if [ "$resource" ]; then
 | 
			
		||||
@@ -128,7 +128,7 @@ _get_root() {
 | 
			
		||||
  p=1
 | 
			
		||||
 | 
			
		||||
  if _rest GET "domain.list"; then
 | 
			
		||||
    response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')"
 | 
			
		||||
    response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")"
 | 
			
		||||
    while true; do
 | 
			
		||||
      h=$(printf "%s" "$domain" | cut -d . -f $i-100)
 | 
			
		||||
      _debug h "$h"
 | 
			
		||||
 
 | 
			
		||||
@@ -81,7 +81,36 @@ dns_lua_add() {
 | 
			
		||||
#fulldomain
 | 
			
		||||
dns_lua_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "invalid domain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug _domain_id "$_domain_id"
 | 
			
		||||
  _debug _sub_domain "$_sub_domain"
 | 
			
		||||
  _debug _domain "$_domain"
 | 
			
		||||
 | 
			
		||||
  _debug "Getting txt records"
 | 
			
		||||
  _LUA_rest GET "zones/${_domain_id}/records"
 | 
			
		||||
 | 
			
		||||
  count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | wc -l | tr -d " ")
 | 
			
		||||
  _debug count "$count"
 | 
			
		||||
  if [ "$count" = "0" ]; then
 | 
			
		||||
    _info "Don't need to remove."
 | 
			
		||||
  else
 | 
			
		||||
    record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | _head_n 1 | cut -d: -f2 | cut -d, -f1)
 | 
			
		||||
    _debug "record_id" "$record_id"
 | 
			
		||||
    if [ -z "$record_id" ]; then
 | 
			
		||||
      _err "Can not get record id to remove."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    if ! _LUA_rest DELETE "/zones/$_domain_id/records/$record_id"; then
 | 
			
		||||
      _err "Delete record error."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    _contains "$response" "$record_id"
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
@@ -129,7 +158,7 @@ _LUA_rest() {
 | 
			
		||||
 | 
			
		||||
  export _H1="Accept: application/json"
 | 
			
		||||
  export _H2="Authorization: Basic $LUA_auth"
 | 
			
		||||
  if [ "$data" ]; then
 | 
			
		||||
  if [ "$m" != "GET" ]; then
 | 
			
		||||
    _debug data "$data"
 | 
			
		||||
    response="$(_post "$data" "$LUA_Api/$ep" "" "$m")"
 | 
			
		||||
  else
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										31
									
								
								dnsapi/dns_me.sh
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										31
									
								
								dnsapi/dns_me.sh
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							@@ -78,7 +78,36 @@ dns_me_add() {
 | 
			
		||||
#fulldomain
 | 
			
		||||
dns_me_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "invalid domain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug _domain_id "$_domain_id"
 | 
			
		||||
  _debug _sub_domain "$_sub_domain"
 | 
			
		||||
  _debug _domain "$_domain"
 | 
			
		||||
 | 
			
		||||
  _debug "Getting txt records"
 | 
			
		||||
  _me_rest GET "${_domain_id}/records?recordName=$_sub_domain&type=TXT"
 | 
			
		||||
 | 
			
		||||
  count=$(printf "%s\n" "$response" | _egrep_o "\"totalRecords\":[^,]*" | cut -d : -f 2)
 | 
			
		||||
  _debug count "$count"
 | 
			
		||||
  if [ "$count" = "0" ]; then
 | 
			
		||||
    _info "Don't need to remove."
 | 
			
		||||
  else
 | 
			
		||||
    record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*" | cut -d : -f 2 | head -n 1)
 | 
			
		||||
    _debug "record_id" "$record_id"
 | 
			
		||||
    if [ -z "$record_id" ]; then
 | 
			
		||||
      _err "Can not get record id to remove."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    if ! _me_rest DELETE "$_domain_id/records/$record_id"; then
 | 
			
		||||
      _err "Delete record error."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    _contains "$response" ''
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
@@ -130,7 +159,7 @@ _me_rest() {
 | 
			
		||||
  export _H2="x-dnsme-requestDate: $cdate"
 | 
			
		||||
  export _H3="x-dnsme-hmac: $hmac"
 | 
			
		||||
 | 
			
		||||
  if [ "$data" ]; then
 | 
			
		||||
  if [ "$m" != "GET" ]; then
 | 
			
		||||
    _debug data "$data"
 | 
			
		||||
    response="$(_post "$data" "$ME_Api/$ep" "" "$m")"
 | 
			
		||||
  else
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										193
									
								
								dnsapi/dns_namecom.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										193
									
								
								dnsapi/dns_namecom.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,193 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#Author: RaidneII
 | 
			
		||||
#Created 06/28/2017
 | 
			
		||||
#Utilize name.com API to finish dns-01 verifications.
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
Namecom_API="https://api.name.com/api"
 | 
			
		||||
 | 
			
		||||
#Usage: dns_namecom_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_namecom_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  # First we need name.com credentials.
 | 
			
		||||
  if [ -z "$Namecom_Username" ]; then
 | 
			
		||||
    Namecom_Username=""
 | 
			
		||||
    _err "Username for name.com is missing."
 | 
			
		||||
    _err "Please specify that in your environment variable."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "$Namecom_Token" ]; then
 | 
			
		||||
    Namecom_Token=""
 | 
			
		||||
    _err "API token for name.com is missing."
 | 
			
		||||
    _err "Please specify that in your environment variable."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Save them in configuration.
 | 
			
		||||
  _saveaccountconf Namecom_Username "$Namecom_Username"
 | 
			
		||||
  _saveaccountconf Namecom_Token "$Namecom_Token"
 | 
			
		||||
 | 
			
		||||
  # Login in using API
 | 
			
		||||
  if ! _namecom_login; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Find domain in domain list.
 | 
			
		||||
  if ! _namecom_get_root "$fulldomain"; then
 | 
			
		||||
    _err "Unable to find domain specified."
 | 
			
		||||
    _namecom_logout
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Add TXT record.
 | 
			
		||||
  _namecom_addtxt_json="{\"hostname\":\"$_sub_domain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"ttl\":\"300\",\"priority\":\"10\"}"
 | 
			
		||||
  if _namecom_rest POST "dns/create/$_domain" "$_namecom_addtxt_json"; then
 | 
			
		||||
    retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100")
 | 
			
		||||
    if [ "$retcode" ]; then
 | 
			
		||||
      _info "Successfully added TXT record, ready for validation."
 | 
			
		||||
      _namecom_logout
 | 
			
		||||
      return 0
 | 
			
		||||
    else
 | 
			
		||||
      _err "Unable to add the DNS record."
 | 
			
		||||
      _namecom_logout
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#Usage: fulldomain txtvalue
 | 
			
		||||
#Remove the txt record after validation.
 | 
			
		||||
dns_namecom_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  if ! _namecom_login; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Find domain in domain list.
 | 
			
		||||
  if ! _namecom_get_root "$fulldomain"; then
 | 
			
		||||
    _err "Unable to find domain specified."
 | 
			
		||||
    _namecom_logout
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Get the record id.
 | 
			
		||||
  if _namecom_rest GET "dns/list/$_domain"; then
 | 
			
		||||
    retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100")
 | 
			
		||||
    if [ "$retcode" ]; then
 | 
			
		||||
      _record_id=$(printf "%s\n" "$response" | _egrep_o "\"record_id\":\"[0-9]+\",\"name\":\"$fulldomain\",\"type\":\"TXT\"" | cut -d \" -f 4)
 | 
			
		||||
      _debug record_id "$_record_id"
 | 
			
		||||
      _info "Successfully retrieved the record id for ACME challenge."
 | 
			
		||||
    else
 | 
			
		||||
      _err "Unable to retrieve the record id."
 | 
			
		||||
      _namecom_logout
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Remove the DNS record using record id.
 | 
			
		||||
  _namecom_rmtxt_json="{\"record_id\":\"$_record_id\"}"
 | 
			
		||||
  if _namecom_rest POST "dns/delete/$_domain" "$_namecom_rmtxt_json"; then
 | 
			
		||||
    retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100")
 | 
			
		||||
    if [ "$retcode" ]; then
 | 
			
		||||
      _info "Successfully removed the TXT record."
 | 
			
		||||
      _namecom_logout
 | 
			
		||||
      return 0
 | 
			
		||||
    else
 | 
			
		||||
      _err "Unable to remove the DNS record."
 | 
			
		||||
      _namecom_logout
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
_namecom_rest() {
 | 
			
		||||
  method=$1
 | 
			
		||||
  param=$2
 | 
			
		||||
  data=$3
 | 
			
		||||
 | 
			
		||||
  export _H1="Content-Type: application/json"
 | 
			
		||||
  export _H2="Api-Session-Token: $sessionkey"
 | 
			
		||||
  if [ "$method" != "GET" ]; then
 | 
			
		||||
    response="$(_post "$data" "$Namecom_API/$param" "" "$method")"
 | 
			
		||||
  else
 | 
			
		||||
    response="$(_get "$Namecom_API/$param")"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "error $param"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_namecom_login() {
 | 
			
		||||
  namecom_login_json="{\"username\":\"$Namecom_Username\",\"api_token\":\"$Namecom_Token\"}"
 | 
			
		||||
 | 
			
		||||
  if _namecom_rest POST "login" "$namecom_login_json"; then
 | 
			
		||||
    retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100")
 | 
			
		||||
    if [ "$retcode" ]; then
 | 
			
		||||
      _info "Successfully logged in. Fetching session token..."
 | 
			
		||||
      sessionkey=$(printf "%s\n" "$response" | _egrep_o "\"session_token\":\".+" | cut -d \" -f 4)
 | 
			
		||||
      if [ ! -z "$sessionkey" ]; then
 | 
			
		||||
        _debug sessionkey "$sessionkey"
 | 
			
		||||
        _info "Session key obtained."
 | 
			
		||||
      else
 | 
			
		||||
        _err "Unable to get session key."
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
    else
 | 
			
		||||
      _err "Logging in failed."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_namecom_logout() {
 | 
			
		||||
  if _namecom_rest GET "logout"; then
 | 
			
		||||
    retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100")
 | 
			
		||||
    if [ "$retcode" ]; then
 | 
			
		||||
      _info "Successfully logged out."
 | 
			
		||||
    else
 | 
			
		||||
      _err "Error logging out."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_namecom_get_root() {
 | 
			
		||||
  domain=$1
 | 
			
		||||
  i=2
 | 
			
		||||
  p=1
 | 
			
		||||
 | 
			
		||||
  if ! _namecom_rest GET "domain/list"; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Need to exclude the last field (tld)
 | 
			
		||||
  numfields=$(echo "$domain" | _egrep_o "\." | wc -l)
 | 
			
		||||
  while [ $i -le "$numfields" ]; do
 | 
			
		||||
    host=$(printf "%s" "$domain" | cut -d . -f $i-100)
 | 
			
		||||
    _debug host "$host"
 | 
			
		||||
    if [ -z "$host" ]; then
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if _contains "$response" "$host"; then
 | 
			
		||||
      _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
 | 
			
		||||
      _domain="$host"
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
    p=$i
 | 
			
		||||
    i=$(_math "$i" + 1)
 | 
			
		||||
  done
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										158
									
								
								dnsapi/dns_nsone.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								dnsapi/dns_nsone.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,158 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
# bug reports to dev@1e.ca
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
#NS1_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
NS1_Api="https://api.nsone.net/v1"
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: add  _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_nsone_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  if [ -z "$NS1_Key" ]; then
 | 
			
		||||
    NS1_Key=""
 | 
			
		||||
    _err "You didn't specify nsone dns api key yet."
 | 
			
		||||
    _err "Please create you key and try again."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  #save the api key and email to the account conf file.
 | 
			
		||||
  _saveaccountconf NS1_Key "$NS1_Key"
 | 
			
		||||
 | 
			
		||||
  _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 txt records"
 | 
			
		||||
  _nsone_rest GET "zones/${_domain}"
 | 
			
		||||
 | 
			
		||||
  if ! _contains "$response" "\"records\":"; then
 | 
			
		||||
    _err "Error"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  count=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain\",[^{]*\"type\":\"TXT\"" | wc -l | tr -d " ")
 | 
			
		||||
  _debug count "$count"
 | 
			
		||||
  if [ "$count" = "0" ]; then
 | 
			
		||||
    _info "Adding record"
 | 
			
		||||
 | 
			
		||||
    if _nsone_rest PUT "zones/$_domain/$fulldomain/TXT" "{\"answers\":[{\"answer\":[\"$txtvalue\"]}],\"type\":\"TXT\",\"domain\":\"$fulldomain\",\"zone\":\"$_domain\"}"; then
 | 
			
		||||
      if _contains "$response" "$fulldomain"; then
 | 
			
		||||
        _info "Added"
 | 
			
		||||
        #todo: check if the record takes effect
 | 
			
		||||
        return 0
 | 
			
		||||
      else
 | 
			
		||||
        _err "Add txt record error."
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
    _err "Add txt record error."
 | 
			
		||||
  else
 | 
			
		||||
    _info "Updating record"
 | 
			
		||||
    record_id=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain.\",[^{]*\"type\":\"TXT\",\"id\":\"[^,]*\"" | _head_n 1 | cut -d: -f7 | cut -d, -f1)
 | 
			
		||||
    _debug "record_id" "$record_id"
 | 
			
		||||
 | 
			
		||||
    _nsone_rest POST "zones/$_domain/$fulldomain/TXT" "{\"answers\": [{\"answer\": [\"$txtvalue\"]}],\"type\": \"TXT\",\"domain\":\"$fulldomain\",\"zone\": \"$_domain\"}"
 | 
			
		||||
    if [ "$?" = "0" ] && _contains "$response" "$fulldomain"; then
 | 
			
		||||
      _info "Updated!"
 | 
			
		||||
      #todo: check if the record takes effect
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
    _err "Update error"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#fulldomain
 | 
			
		||||
dns_nsone_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
  _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 txt records"
 | 
			
		||||
  _nsone_rest GET "zones/${_domain}/$fulldomain/TXT"
 | 
			
		||||
 | 
			
		||||
  count=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain\",.*\"type\":\"TXT\"" | wc -l | tr -d " ")
 | 
			
		||||
  _debug count "$count"
 | 
			
		||||
  if [ "$count" = "0" ]; then
 | 
			
		||||
    _info "Don't need to remove."
 | 
			
		||||
  else
 | 
			
		||||
    if ! _nsone_rest DELETE "zones/${_domain}/$fulldomain/TXT"; then
 | 
			
		||||
      _err "Delete record error."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    _contains "$response" ""
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
#_acme-challenge.www.domain.com
 | 
			
		||||
#returns
 | 
			
		||||
# _sub_domain=_acme-challenge.www
 | 
			
		||||
# _domain=domain.com
 | 
			
		||||
# _domain_id=sdjkglgdfewsdfg
 | 
			
		||||
_get_root() {
 | 
			
		||||
  domain=$1
 | 
			
		||||
  i=2
 | 
			
		||||
  p=1
 | 
			
		||||
  if ! _nsone_rest GET "zones"; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  while true; do
 | 
			
		||||
    h=$(printf "%s" "$domain" | cut -d . -f $i-100)
 | 
			
		||||
    _debug h "$h"
 | 
			
		||||
    if [ -z "$h" ]; then
 | 
			
		||||
      #not valid
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if _contains "$response" "\"zone\":\"$h\""; then
 | 
			
		||||
      _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
 | 
			
		||||
      _domain="$h"
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
    p=$i
 | 
			
		||||
    i=$(_math "$i" + 1)
 | 
			
		||||
  done
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_nsone_rest() {
 | 
			
		||||
  m=$1
 | 
			
		||||
  ep="$2"
 | 
			
		||||
  data="$3"
 | 
			
		||||
  _debug "$ep"
 | 
			
		||||
 | 
			
		||||
  export _H1="Accept: application/json"
 | 
			
		||||
  export _H2="X-NSONE-Key: $NS1_Key"
 | 
			
		||||
  if [ "$m" != "GET" ]; then
 | 
			
		||||
    _debug data "$data"
 | 
			
		||||
    response="$(_post "$data" "$NS1_Api/$ep" "" "$m")"
 | 
			
		||||
  else
 | 
			
		||||
    response="$(_get "$NS1_Api/$ep")"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "error $ep"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#Applcation Key
 | 
			
		||||
#Application Key
 | 
			
		||||
#OVH_AK="sdfsdfsdfljlbjkljlkjsdfoiwje"
 | 
			
		||||
#
 | 
			
		||||
#Application Secret
 | 
			
		||||
@@ -14,7 +14,7 @@
 | 
			
		||||
#'ovh-eu'
 | 
			
		||||
OVH_EU='https://eu.api.ovh.com/1.0'
 | 
			
		||||
 | 
			
		||||
#'ovh-ca': 
 | 
			
		||||
#'ovh-ca':
 | 
			
		||||
OVH_CA='https://ca.api.ovh.com/1.0'
 | 
			
		||||
 | 
			
		||||
#'kimsufi-eu'
 | 
			
		||||
@@ -119,7 +119,7 @@ dns_ovh_add() {
 | 
			
		||||
 | 
			
		||||
  _info "Checking authentication"
 | 
			
		||||
 | 
			
		||||
  response="$(_ovh_rest GET "domain/")"
 | 
			
		||||
  response="$(_ovh_rest GET "domain")"
 | 
			
		||||
  if _contains "$response" "INVALID_CREDENTIAL"; then
 | 
			
		||||
    _err "The consumer key is invalid: $OVH_CK"
 | 
			
		||||
    _err "Please retry to create a new one."
 | 
			
		||||
@@ -191,7 +191,7 @@ _ovh_authentication() {
 | 
			
		||||
  _H3=""
 | 
			
		||||
  _H4=""
 | 
			
		||||
 | 
			
		||||
  _ovhdata='{"accessRules": [{"method": "GET","path": "/*"},{"method": "POST","path": "/*"},{"method": "PUT","path": "/*"},{"method": "DELETE","path": "/*"}],"redirection":"'$ovh_success'"}'
 | 
			
		||||
  _ovhdata='{"accessRules": [{"method": "GET","path": "/auth/time"},{"method": "GET","path": "/domain"},{"method": "GET","path": "/domain/zone/*"},{"method": "GET","path": "/domain/zone/*/record"},{"method": "POST","path": "/domain/zone/*/record"},{"method": "POST","path": "/domain/zone/*/refresh"},{"method": "PUT","path": "/domain/zone/*/record/*"}],"redirection":"'$ovh_success'"}'
 | 
			
		||||
 | 
			
		||||
  response="$(_post "$_ovhdata" "$OVH_API/auth/credential")"
 | 
			
		||||
  _debug3 response "$response"
 | 
			
		||||
@@ -207,7 +207,7 @@ _ovh_authentication() {
 | 
			
		||||
    _err "Unable to get consumerKey"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug consumerKey "$consumerKey"
 | 
			
		||||
  _secure_debug consumerKey "$consumerKey"
 | 
			
		||||
 | 
			
		||||
  OVH_CK="$consumerKey"
 | 
			
		||||
  _saveaccountconf OVH_CK "$OVH_CK"
 | 
			
		||||
@@ -238,7 +238,7 @@ _get_root() {
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if ! _contains "$response" "This service does not exist" >/dev/null; then
 | 
			
		||||
    if ! _contains "$response" "This service does not exist" >/dev/null && ! _contains "$response" "NOT_GRANTED_CALL" >/dev/null; then
 | 
			
		||||
      _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
 | 
			
		||||
      _domain="$h"
 | 
			
		||||
      return 0
 | 
			
		||||
@@ -269,7 +269,7 @@ _ovh_rest() {
 | 
			
		||||
  _ovh_t="$(_ovh_timestamp)"
 | 
			
		||||
  _debug2 _ovh_t "$_ovh_t"
 | 
			
		||||
  _ovh_p="$OVH_AS+$OVH_CK+$m+$_ovh_url+$data+$_ovh_t"
 | 
			
		||||
  _debug _ovh_p "$_ovh_p"
 | 
			
		||||
  _secure_debug _ovh_p "$_ovh_p"
 | 
			
		||||
  _ovh_hex="$(printf "%s" "$_ovh_p" | _digest sha1 hex)"
 | 
			
		||||
  _debug2 _ovh_hex "$_ovh_hex"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#PowerDNS Emdedded API
 | 
			
		||||
#PowerDNS Embedded API
 | 
			
		||||
#https://doc.powerdns.com/md/httpapi/api_spec/
 | 
			
		||||
#
 | 
			
		||||
#PDNS_Url="http://ns.example.com:8081"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										149
									
								
								dnsapi/dns_vscale.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										149
									
								
								dnsapi/dns_vscale.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,149 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#This is the vscale.io api wrapper for acme.sh
 | 
			
		||||
#
 | 
			
		||||
#Author: Alex Loban
 | 
			
		||||
#Report Bugs here: https://github.com/LAV45/acme.sh
 | 
			
		||||
 | 
			
		||||
#VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje"
 | 
			
		||||
VSCALE_API_URL="https://api.vscale.io/v1"
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: dns_myapi_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_vscale_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  if [ -z "$VSCALE_API_KEY" ]; then
 | 
			
		||||
    VSCALE_API_KEY=""
 | 
			
		||||
    _err "You didn't specify the VSCALE api key yet."
 | 
			
		||||
    _err "Please create you key and try again."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _saveaccountconf VSCALE_API_KEY "$VSCALE_API_KEY"
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "invalid domain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug _domain_id "$_domain_id"
 | 
			
		||||
  _debug _sub_domain "$_sub_domain"
 | 
			
		||||
  _debug _domain "$_domain"
 | 
			
		||||
 | 
			
		||||
  _vscale_tmpl_json="{\"type\":\"TXT\",\"name\":\"$_sub_domain.$_domain\",\"content\":\"$txtvalue\"}"
 | 
			
		||||
 | 
			
		||||
  if _vscale_rest POST "domains/$_domain_id/records/" "$_vscale_tmpl_json"; then
 | 
			
		||||
    response=$(printf "%s\n" "$response" | _egrep_o "{\"error\": \".+\"" | cut -d : -f 2)
 | 
			
		||||
    if [ -z "$response" ]; then
 | 
			
		||||
      _info "txt record updated success."
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#fulldomain txtvalue
 | 
			
		||||
dns_vscale_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "invalid domain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug _domain_id "$_domain_id"
 | 
			
		||||
  _debug _sub_domain "$_sub_domain"
 | 
			
		||||
  _debug _domain "$_domain"
 | 
			
		||||
 | 
			
		||||
  _debug "Getting txt records"
 | 
			
		||||
  _vscale_rest GET "domains/$_domain_id/records/"
 | 
			
		||||
 | 
			
		||||
  if [ -n "$response" ]; then
 | 
			
		||||
    record_id=$(printf "%s\n" "$response" | _egrep_o "\"TXT\", \"id\": [0-9]+, \"name\": \"$_sub_domain.$_domain\"" | cut -d : -f 2 | tr -d ", \"name\"")
 | 
			
		||||
    _debug record_id "$record_id"
 | 
			
		||||
    if [ -z "$record_id" ]; then
 | 
			
		||||
      _err "Can not get record id to remove."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    if _vscale_rest DELETE "domains/$_domain_id/records/$record_id" && [ -z "$response" ]; then
 | 
			
		||||
      _info "txt record deleted success."
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
    _debug response "$response"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
#_acme-challenge.www.domain.com
 | 
			
		||||
#returns
 | 
			
		||||
# _sub_domain=_acme-challenge.www
 | 
			
		||||
# _domain=domain.com
 | 
			
		||||
# _domain_id=12345
 | 
			
		||||
_get_root() {
 | 
			
		||||
  domain=$1
 | 
			
		||||
  i=2
 | 
			
		||||
  p=1
 | 
			
		||||
 | 
			
		||||
  if _vscale_rest GET "domains/"; then
 | 
			
		||||
    response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')"
 | 
			
		||||
    while true; do
 | 
			
		||||
      h=$(printf "%s" "$domain" | cut -d . -f $i-100)
 | 
			
		||||
      _debug h "$h"
 | 
			
		||||
      if [ -z "$h" ]; then
 | 
			
		||||
        #not valid
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
 | 
			
		||||
      hostedzone="$(echo "$response" | _egrep_o "{.*\"name\":\s*\"$h\".*}")"
 | 
			
		||||
      if [ "$hostedzone" ]; then
 | 
			
		||||
        _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ )
 | 
			
		||||
        if [ "$_domain_id" ]; then
 | 
			
		||||
          _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
 | 
			
		||||
          _domain=$h
 | 
			
		||||
          return 0
 | 
			
		||||
        fi
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
      p=$i
 | 
			
		||||
      i=$(_math "$i" + 1)
 | 
			
		||||
    done
 | 
			
		||||
  fi
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#method uri qstr data
 | 
			
		||||
_vscale_rest() {
 | 
			
		||||
  mtd="$1"
 | 
			
		||||
  ep="$2"
 | 
			
		||||
  data="$3"
 | 
			
		||||
 | 
			
		||||
  _debug mtd "$mtd"
 | 
			
		||||
  _debug ep "$ep"
 | 
			
		||||
 | 
			
		||||
  export _H1="Accept: application/json"
 | 
			
		||||
  export _H2="Content-Type: application/json"
 | 
			
		||||
  export _H3="X-Token: ${VSCALE_API_KEY}"
 | 
			
		||||
 | 
			
		||||
  if [ "$mtd" != "GET" ]; then
 | 
			
		||||
    # both POST and DELETE.
 | 
			
		||||
    _debug data "$data"
 | 
			
		||||
    response="$(_post "$data" "$VSCALE_API_URL/$ep" "" "$mtd")"
 | 
			
		||||
  else
 | 
			
		||||
    response="$(_get "$VSCALE_API_URL/$ep")"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "error $ep"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										107
									
								
								dnsapi/dns_yandex.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										107
									
								
								dnsapi/dns_yandex.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,107 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# Author: non7top@gmail.com
 | 
			
		||||
# 07 Jul 2017
 | 
			
		||||
# report bugs at https://github.com/non7top/acme.sh
 | 
			
		||||
 | 
			
		||||
# Values to export:
 | 
			
		||||
# export PDD_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: dns_myapi_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_yandex_add() {
 | 
			
		||||
  fulldomain="${1}"
 | 
			
		||||
  txtvalue="${2}"
 | 
			
		||||
  _debug "Calling: dns_yandex_add() '${fulldomain}' '${txtvalue}'"
 | 
			
		||||
  _PDD_credentials || return 1
 | 
			
		||||
  export _H1="PddToken: $PDD_Token"
 | 
			
		||||
 | 
			
		||||
  curDomain=$(_PDD_get_domain "$fulldomain")
 | 
			
		||||
  _debug "Found suitable domain in pdd: $curDomain"
 | 
			
		||||
  curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")"
 | 
			
		||||
  curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}"
 | 
			
		||||
  curUri="https://pddimp.yandex.ru/api2/admin/dns/add"
 | 
			
		||||
  curResult="$(_post "${curData}" "${curUri}")"
 | 
			
		||||
  _debug "Result: $curResult"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#Usage: dns_myapi_rm   _acme-challenge.www.domain.com
 | 
			
		||||
dns_yandex_rm() {
 | 
			
		||||
  fulldomain="${1}"
 | 
			
		||||
  _debug "Calling: dns_yandex_rm() '${fulldomain}'"
 | 
			
		||||
  _PDD_credentials || return 1
 | 
			
		||||
  export _H1="PddToken: $PDD_Token"
 | 
			
		||||
  record_id=$(pdd_get_record_id "${fulldomain}")
 | 
			
		||||
  _debug "Result: $record_id"
 | 
			
		||||
 | 
			
		||||
  curDomain=$(_PDD_get_domain "$fulldomain")
 | 
			
		||||
  _debug "Found suitable domain in pdd: $curDomain"
 | 
			
		||||
  curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")"
 | 
			
		||||
 | 
			
		||||
  curUri="https://pddimp.yandex.ru/api2/admin/dns/del"
 | 
			
		||||
  curData="domain=${curDomain}&record_id=${record_id}"
 | 
			
		||||
  curResult="$(_post "${curData}" "${curUri}")"
 | 
			
		||||
  _debug "Result: $curResult"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
 | 
			
		||||
_PDD_get_domain() {
 | 
			
		||||
  fulldomain="${1}"
 | 
			
		||||
  __page=1
 | 
			
		||||
  __last=0
 | 
			
		||||
  while [ $__last -eq 0 ]; do
 | 
			
		||||
    uri1="https://pddimp.yandex.ru/api2/admin/domain/domains?page=${__page}&on_page=20"
 | 
			
		||||
    res1=$(_get "$uri1" | _normalizeJson)
 | 
			
		||||
    #_debug "$res1"
 | 
			
		||||
    __found=$(echo "$res1" | sed -n -e 's#.* "found": \([^,]*\),.*#\1#p')
 | 
			
		||||
    _debug "found: $__found results on page"
 | 
			
		||||
    if [ "$__found" -lt 20 ]; then
 | 
			
		||||
      _debug "last page: $__page"
 | 
			
		||||
      __last=1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    __all_domains="$__all_domains $(echo "$res1" | sed -e "s@,@\n@g" | grep '"name"' | cut -d: -f2 | sed -e 's@"@@g')"
 | 
			
		||||
 | 
			
		||||
    __page=$(_math $__page + 1)
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  k=2
 | 
			
		||||
  while [ $k -lt 10 ]; do
 | 
			
		||||
    __t=$(echo "$fulldomain" | cut -d . -f $k-100)
 | 
			
		||||
    _debug "finding zone for domain $__t"
 | 
			
		||||
    for d in $__all_domains; do
 | 
			
		||||
      if [ "$d" = "$__t" ]; then
 | 
			
		||||
        echo "$__t"
 | 
			
		||||
        return
 | 
			
		||||
      fi
 | 
			
		||||
    done
 | 
			
		||||
    k=$(_math $k + 1)
 | 
			
		||||
  done
 | 
			
		||||
  _err "No suitable domain found in your account"
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_PDD_credentials() {
 | 
			
		||||
  if [ -z "${PDD_Token}" ]; then
 | 
			
		||||
    PDD_Token=""
 | 
			
		||||
    _err "You need to export PDD_Token=xxxxxxxxxxxxxxxxx"
 | 
			
		||||
    _err "You can get it at https://pddimp.yandex.ru/api2/admin/get_token"
 | 
			
		||||
    return 1
 | 
			
		||||
  else
 | 
			
		||||
    _saveaccountconf PDD_Token "${PDD_Token}"
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pdd_get_record_id() {
 | 
			
		||||
  fulldomain="${1}"
 | 
			
		||||
 | 
			
		||||
  curDomain=$(_PDD_get_domain "$fulldomain")
 | 
			
		||||
  _debug "Found suitable domain in pdd: $curDomain"
 | 
			
		||||
  curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")"
 | 
			
		||||
 | 
			
		||||
  curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}"
 | 
			
		||||
  curResult="$(_get "${curUri}" | _normalizeJson)"
 | 
			
		||||
  _debug "Result: $curResult"
 | 
			
		||||
  echo "$curResult" | _egrep_o "{[^{]*\"content\":[^{]*\"subdomain\":\"${curSubdomain}\"" | sed -n -e 's#.* "record_id": \(.*\),[^,]*#\1#p'
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user