mirror of
				https://github.com/acmesh-official/acme.sh
				synced 2025-11-04 22:11:07 +08:00 
			
		
		
		
	Compare commits
	
		
			891 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					26e3263aec | ||
| 
						 | 
					08b4e1a744 | ||
| 
						 | 
					d68f0999a4 | ||
| 
						 | 
					2c9ed4c565 | ||
| 
						 | 
					be4f87c760 | ||
| 
						 | 
					b963dadc14 | ||
| 
						 | 
					26e7fd8b80 | ||
| 
						 | 
					b9a972bccd | ||
| 
						 | 
					bb7b9280d3 | ||
| 
						 | 
					395fbbfd14 | ||
| 
						 | 
					896dfe3def | ||
| 
						 | 
					6c4f33910c | ||
| 
						 | 
					0a301cdd21 | ||
| 
						 | 
					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 | ||
| 
						 | 
					50d7b8452d | ||
| 
						 | 
					d88f8e862b | ||
| 
						 | 
					fd72cced13 | ||
| 
						 | 
					a6feb0a887 | ||
| 
						 | 
					cd9c3a79e5 | ||
| 
						 | 
					f3685bdef9 | ||
| 
						 | 
					e2edf20833 | ||
| 
						 | 
					31e39f1f6d | ||
| 
						 | 
					d47c5eaf60 | ||
| 
						 | 
					b8e515a738 | ||
| 
						 | 
					0984585d58 | ||
| 
						 | 
					f3e0eb705b | ||
| 
						 | 
					04e0f87c03 | ||
| 
						 | 
					8ccfcd272f | ||
| 
						 | 
					ba69062a36 | ||
| 
						 | 
					cea24b5f70 | ||
| 
						 | 
					f3a71f62a1 | ||
| 
						 | 
					4e4a6d8397 | ||
| 
						 | 
					d8beaf727f | ||
| 
						 | 
					c961c865ee | ||
| 
						 | 
					34f25fa590 | ||
| 
						 | 
					7af1155c11 | ||
| 
						 | 
					c9d7daab70 | ||
| 
						 | 
					981077516b | ||
| 
						 | 
					7c488b5913 | ||
| 
						 | 
					0e44f587a5 | ||
| 
						 | 
					e593d86b80 | ||
| 
						 | 
					339a8ad610 | ||
| 
						 | 
					d1190febec | ||
| 
						 | 
					5d2c5b01a8 | ||
| 
						 | 
					0f954c20ff | ||
| 
						 | 
					d6edff3182 | ||
| 
						 | 
					dba26c3240 | ||
| 
						 | 
					0ca5b7996c | ||
| 
						 | 
					63e1d3610c | ||
| 
						 | 
					b4325026b1 | ||
| 
						 | 
					b072ef2e82 | ||
| 
						 | 
					562a4c056e | ||
| 
						 | 
					bb8248556d | ||
| 
						 | 
					b22b085b50 | ||
| 
						 | 
					e82ea94bb6 | ||
| 
						 | 
					a50252382a | ||
| 
						 | 
					9bdb799b41 | ||
| 
						 | 
					259cefab72 | ||
| 
						 | 
					09ed421948 | ||
| 
						 | 
					87f5ec5be5 | ||
| 
						 | 
					f78b656f5f | ||
| 
						 | 
					e6b940e247 | ||
| 
						 | 
					50a9680f17 | ||
| 
						 | 
					f2a6dc4dfd | ||
| 
						 | 
					67e3dd36b3 | ||
| 
						 | 
					6c4cc357b5 | ||
| 
						 | 
					94965a418f | ||
| 
						 | 
					40e6ba1100 | ||
| 
						 | 
					0aed065a75 | ||
| 
						 | 
					70b63a5ed4 | ||
| 
						 | 
					1476a9ecf1 | ||
| 
						 | 
					600a235140 | ||
| 
						 | 
					ffa9f104db | ||
| 
						 | 
					b807ec0956 | ||
| 
						 | 
					5f8daeeb6d | ||
| 
						 | 
					aec8307417 | ||
| 
						 | 
					e96a1b01b9 | ||
| 
						 | 
					d78ba322bf | ||
| 
						 | 
					ab5c1b0a3a | ||
| 
						 | 
					53fa16d39f | ||
| 
						 | 
					05cf405cb5 | ||
| 
						 | 
					5d833336d3 | ||
| 
						 | 
					13be9d8d79 | ||
| 
						 | 
					bb6326f4d4 | ||
| 
						 | 
					c070407ab2 | ||
| 
						 | 
					6b27bdadcd | ||
| 
						 | 
					1c22c2f76a | ||
| 
						 | 
					aa262d4124 | ||
| 
						 | 
					646c0bfcb9 | ||
| 
						 | 
					da68775472 | ||
| 
						 | 
					bcf96608d1 | ||
| 
						 | 
					dd17ac5045 | ||
| 
						 | 
					59182dbc97 | ||
| 
						 | 
					11df7187b3 | ||
| 
						 | 
					0899803294 | ||
| 
						 | 
					4742e0951c | ||
| 
						 | 
					c3b1eb0837 | ||
| 
						 | 
					542d7977db | ||
| 
						 | 
					11927a768e | ||
| 
						 | 
					ecd5bcec0c | ||
| 
						 | 
					911a2084d4 | ||
| 
						 | 
					839bf0e2c9 | ||
| 
						 | 
					25555b8c3e | ||
| 
						 | 
					cd7ac94f35 | ||
| 
						 | 
					68aea3af9e | ||
| 
						 | 
					cdb3216cc9 | ||
| 
						 | 
					78f0201dfa | ||
| 
						 | 
					2cd47b0240 | ||
| 
						 | 
					be83a6a37a | ||
| 
						 | 
					8ca99e85b0 | ||
| 
						 | 
					f5b546b3c8 | ||
| 
						 | 
					50c9d17830 | ||
| 
						 | 
					d87af4788e | ||
| 
						 | 
					0f21537f14 | ||
| 
						 | 
					0533bde9f2 | ||
| 
						 | 
					32b3717c32 | ||
| 
						 | 
					d950f801af | ||
| 
						 | 
					a8ab028b84 | ||
| 
						 | 
					2aff36e74b | ||
| 
						 | 
					db7e4bf940 | ||
| 
						 | 
					ee20015d44 | ||
| 
						 | 
					80941f8413 | ||
| 
						 | 
					cf909db159 | ||
| 
						 | 
					27dbe77fad | ||
| 
						 | 
					38f2334360 | ||
| 
						 | 
					6489a48e1f | ||
| 
						 | 
					ca24d1762e | ||
| 
						 | 
					2f4b84c074 | ||
| 
						 | 
					6ae810a1fa | ||
| 
						 | 
					3e3f695536 | ||
| 
						 | 
					3ca93f4a4c | ||
| 
						 | 
					f2d9930773 | ||
| 
						 | 
					2fbf399156 | ||
| 
						 | 
					5fe91d6577 | ||
| 
						 | 
					753d0e7df7 | ||
| 
						 | 
					e2cc350fbc | ||
| 
						 | 
					07feb87dee | ||
| 
						 | 
					1699e94f0f | ||
| 
						 | 
					8a1e335bf5 | ||
| 
						 | 
					5413bf8753 | ||
| 
						 | 
					c4c5ecd03d | ||
| 
						 | 
					3b67cf4378 | ||
| 
						 | 
					f3c937f9ed | ||
| 
						 | 
					671a699472 | ||
| 
						 | 
					cc4fa1c6bd | ||
| 
						 | 
					d11d476126 | ||
| 
						 | 
					1ce06c7cdd | ||
| 
						 | 
					800f02ba38 | ||
| 
						 | 
					79964b0e85 | ||
| 
						 | 
					0924d11bbf | ||
| 
						 | 
					3cf85634eb | ||
| 
						 | 
					ec01175d37 | ||
| 
						 | 
					5bb518ff0f | ||
| 
						 | 
					5415381cf4 | ||
| 
						 | 
					129ae06354 | ||
| 
						 | 
					058e5d5f4b | ||
| 
						 | 
					2ec493f033 | ||
| 
						 | 
					a33e8a8509 | ||
| 
						 | 
					7b4be7be40 | ||
| 
						 | 
					b90917a529 | ||
| 
						 | 
					180f05f6f0 | ||
| 
						 | 
					b2686e5b6d | ||
| 
						 | 
					831b95f13a | ||
| 
						 | 
					331b599a81 | ||
| 
						 | 
					3ef817ebc2 | ||
| 
						 | 
					d0f7c309ab | ||
| 
						 | 
					e5079b9dad | ||
| 
						 | 
					9e773c9143 | ||
| 
						 | 
					fe600441c9 | ||
| 
						 | 
					291b56db93 | ||
| 
						 | 
					ec9975c3d9 | ||
| 
						 | 
					9e57161941 | ||
| 
						 | 
					20444bf253 | ||
| 
						 | 
					e428c4402e | ||
| 
						 | 
					15af89d51c | ||
| 
						 | 
					ed95865696 | ||
| 
						 | 
					8c71bd57e7 | ||
| 
						 | 
					d204be4b2c | ||
| 
						 | 
					4743171b4f | ||
| 
						 | 
					1fb800f7a7 | ||
| 
						 | 
					3a3b0dd5c1 | ||
| 
						 | 
					2959281d42 | ||
| 
						 | 
					e2c939fb97 | ||
| 
						 | 
					51d0e4325e | ||
| 
						 | 
					08b6cf0231 | ||
| 
						 | 
					059147b74a | ||
| 
						 | 
					c96ceeb1bd | ||
| 
						 | 
					0a3b6c4813 | ||
| 
						 | 
					8636a15695 | ||
| 
						 | 
					96db9362c5 | ||
| 
						 | 
					f81f93e9c3 | ||
| 
						 | 
					a3a04b5f76 | ||
| 
						 | 
					329174b6d9 | ||
| 
						 | 
					b171aff418 | ||
| 
						 | 
					1f6ffa3e88 | ||
| 
						 | 
					24d2a8b9d5 | ||
| 
						 | 
					4d8b99a307 | ||
| 
						 | 
					f9085fedd7 | ||
| 
						 | 
					c4236e58d1 | ||
| 
						 | 
					eb91f9575a | ||
| 
						 | 
					947d14ffeb | ||
| 
						 | 
					b3f915b5b2 | ||
| 
						 | 
					03d3f3afc3 | ||
| 
						 | 
					2728170c01 | ||
| 
						 | 
					c107f3632a | ||
| 
						 | 
					7d1c5fca0b | ||
| 
						 | 
					e71887e1a8 | ||
| 
						 | 
					39d1eeda23 | ||
| 
						 | 
					b482f3ce94 | ||
| 
						 | 
					122cc48c29 | ||
| 
						 | 
					c7c57cfa0e | ||
| 
						 | 
					1f9ca20dfd | ||
| 
						 | 
					5efbaa4849 | ||
| 
						 | 
					c6f55bc4ab | ||
| 
						 | 
					b28a3db3d6 | ||
| 
						 | 
					b9ece28f68 | ||
| 
						 | 
					79b4907cb9 | ||
| 
						 | 
					dfbc244b00 | ||
| 
						 | 
					b23d5e26e2 | ||
| 
						 | 
					f1f3074306 | ||
| 
						 | 
					f162ad193f | ||
| 
						 | 
					5254f300f9 | ||
| 
						 | 
					c0d0100ca8 | ||
| 
						 | 
					21f201e371 | ||
| 
						 | 
					bbc378ed8f | ||
| 
						 | 
					e2d494321c | ||
| 
						 | 
					c2df8043db | ||
| 
						 | 
					df62150b5a | ||
| 
						 | 
					eea52a5fa6 | ||
| 
						 | 
					2d9015b840 | ||
| 
						 | 
					187ef29914 | ||
| 
						 | 
					c12be766e9 | ||
| 
						 | 
					2168458f11 | ||
| 
						 | 
					8cf0725593 | ||
| 
						 | 
					8379f015d7 | ||
| 
						 | 
					f08c01800f | ||
| 
						 | 
					a62706678e | ||
| 
						 | 
					e4468562d2 | ||
| 
						 | 
					7316bf7bc5 | ||
| 
						 | 
					3747b7d930 | ||
| 
						 | 
					5be3f22d06 | ||
| 
						 | 
					c572ce946b | ||
| 
						 | 
					d69f0289ca | ||
| 
						 | 
					048e5210f7 | ||
| 
						 | 
					219e9115c0 | ||
| 
						 | 
					b43416af97 | ||
| 
						 | 
					6d84da588b | ||
| 
						 | 
					569d6c557c | ||
| 
						 | 
					58bb94d7c7 | ||
| 
						 | 
					4f8f775e69 | ||
| 
						 | 
					5eed02f7e9 | ||
| 
						 | 
					983f1f28ca | ||
| 
						 | 
					192ede5e64 | ||
| 
						 | 
					803a7aa878 | ||
| 
						 | 
					93f3098aec | ||
| 
						 | 
					dbd94d047b | ||
| 
						 | 
					be39ab32d1 | ||
| 
						 | 
					8b1fb3cb0c | ||
| 
						 | 
					9e04222ee6 | ||
| 
						 | 
					72349507c4 | ||
| 
						 | 
					79db8daddd | ||
| 
						 | 
					b967f83f20 | ||
| 
						 | 
					74a7592b4b | ||
| 
						 | 
					486f23538f | ||
| 
						 | 
					df86ff2191 | ||
| 
						 | 
					41266f05e9 | ||
| 
						 | 
					d2aa331838 | ||
| 
						 | 
					670cb9d223 | ||
| 
						 | 
					a205762bf0 | ||
| 
						 | 
					2ffab66d97 | ||
| 
						 | 
					10a6aec998 | ||
| 
						 | 
					7cbe31baad | ||
| 
						 | 
					8a09dc1b9b | ||
| 
						 | 
					fa6e174651 | ||
| 
						 | 
					8dee328eae | ||
| 
						 | 
					340155e6a6 | ||
| 
						 | 
					7fe19a030a | ||
| 
						 | 
					11e0ccdc91 | ||
| 
						 | 
					e55b2f4f8d | ||
| 
						 | 
					d78c1f695e | ||
| 
						 | 
					cfbb3e86b3 | ||
| 
						 | 
					fa6234e417 | ||
| 
						 | 
					9eeae9ad7e | ||
| 
						 | 
					28688488ff | ||
| 
						 | 
					41d804719f | ||
| 
						 | 
					bc18168662 | ||
| 
						 | 
					1fadae82c7 | ||
| 
						 | 
					791c62ca64 | ||
| 
						 | 
					4441a6ff59 | ||
| 
						 | 
					63a7002477 | ||
| 
						 | 
					a746139c53 | ||
| 
						 | 
					697a060132 | ||
| 
						 | 
					7834c25253 | ||
| 
						 | 
					2e7cbfcff5 | ||
| 
						 | 
					5b771039fc | ||
| 
						 | 
					2f1bc5864f | ||
| 
						 | 
					16d79ebaac | ||
| 
						 | 
					e009ec8b93 | ||
| 
						 | 
					738ece513f | ||
| 
						 | 
					5a7b7b51c5 | ||
| 
						 | 
					5bba9bddfd | ||
| 
						 | 
					a3c0c7546d | ||
| 
						 | 
					05d7ae4efa | ||
| 
						 | 
					44483dba21 | ||
| 
						 | 
					3498a5856a | ||
| 
						 | 
					cd79b0343a | ||
| 
						 | 
					abba00d595 | ||
| 
						 | 
					88a8d7d901 | ||
| 
						 | 
					d5c00071d3 | ||
| 
						 | 
					c7a6cf5463 | ||
| 
						 | 
					2ce2a15fc6 | ||
| 
						 | 
					ce4be4e91e | ||
| 
						 | 
					82dc2244c0 | ||
| 
						 | 
					ab45b7783f | ||
| 
						 | 
					4a56b2406b | ||
| 
						 | 
					e0cd2cdb9c | ||
| 
						 | 
					7575094cf3 | ||
| 
						 | 
					40a3ae04b6 | ||
| 
						 | 
					ac26f84170 | ||
| 
						 | 
					fa574fe833 | ||
| 
						 | 
					9a6e18ce80 | ||
| 
						 | 
					8f9034fc8b | ||
| 
						 | 
					3e5b102445 | ||
| 
						 | 
					d8b1a8d439 | ||
| 
						 | 
					54ae008dd7 | ||
| 
						 | 
					9c1747581f | ||
| 
						 | 
					ae4f7b6d7a | ||
| 
						 | 
					c947322a69 | ||
| 
						 | 
					14db45215f | ||
| 
						 | 
					d20831e41a | ||
| 
						 | 
					1bb902984b | ||
| 
						 | 
					09f1c58872 | ||
| 
						 | 
					7f944c2c8b | ||
| 
						 | 
					1c02b85802 | ||
| 
						 | 
					a2801649b4 | ||
| 
						 | 
					15777732d3 | ||
| 
						 | 
					b875037150 | ||
| 
						 | 
					a6d583cb5e | ||
| 
						 | 
					9882f3429a | ||
| 
						 | 
					29d47c4de2 | ||
| 
						 | 
					a9b15f1c36 | ||
| 
						 | 
					ce38ecb966 | ||
| 
						 | 
					13ffa17048 | ||
| 
						 | 
					a387682dfb | ||
| 
						 | 
					f6ed197cd3 | ||
| 
						 | 
					243593cdaa | ||
| 
						 | 
					1e2d559859 | ||
| 
						 | 
					20ea859183 | ||
| 
						 | 
					86b24ea059 | ||
| 
						 | 
					07af42476d | ||
| 
						 | 
					87edf71e93 | ||
| 
						 | 
					e3ea2ed420 | ||
| 
						 | 
					8f9a1881a4 | ||
| 
						 | 
					a8c6111197 | ||
| 
						 | 
					3de8570022 | ||
| 
						 | 
					a0311b0134 | ||
| 
						 | 
					158a628c0e | ||
| 
						 | 
					422e5026d6 | ||
| 
						 | 
					797cbb9b20 | ||
| 
						 | 
					be68fbd4f5 | ||
| 
						 | 
					e440223b40 | ||
| 
						 | 
					5766250288 | ||
| 
						 | 
					870274ad9d | ||
| 
						 | 
					9d6abcd9be | ||
| 
						 | 
					432771dfe3 | ||
| 
						 | 
					69925ce823 | ||
| 
						 | 
					e9f9f515bd | ||
| 
						 | 
					efd96153d8 | ||
| 
						 | 
					c7b8f223ee | ||
| 
						 | 
					a0636d5a87 | ||
| 
						 | 
					c7b16249b8 | ||
| 
						 | 
					031e885e4d | ||
| 
						 | 
					796e2cc156 | ||
| 
						 | 
					7af784adce | ||
| 
						 | 
					a988a91e2e | ||
| 
						 | 
					a8b564fa64 | ||
| 
						 | 
					b97e140389 | ||
| 
						 | 
					e51bef6d12 | ||
| 
						 | 
					4bd31f4967 | ||
| 
						 | 
					7ff7a7c527 | ||
| 
						 | 
					c4a375b3a5 | ||
| 
						 | 
					e3698edd19 | ||
| 
						 | 
					e591d5cfe4 | ||
| 
						 | 
					a2e62f8e1d | ||
| 
						 | 
					764963e986 | ||
| 
						 | 
					4da493f3f3 | ||
| 
						 | 
					dec90f7e5e | ||
| 
						 | 
					2ea5b283a8 | ||
| 
						 | 
					eb23549cd6 | ||
| 
						 | 
					cd90062850 | ||
| 
						 | 
					3ec72fcee9 | ||
| 
						 | 
					b9091e14b3 | ||
| 
						 | 
					5daefc0194 | ||
| 
						 | 
					44edb2bd2f | ||
| 
						 | 
					201aa24448 | ||
| 
						 | 
					e799ef2977 | ||
| 
						 | 
					0c538f7527 | ||
| 
						 | 
					ca7202eb0a | ||
| 
						 | 
					d5ec5f80ff | ||
| 
						 | 
					0c944a03fe | ||
| 
						 | 
					79a267ab08 | ||
| 
						 | 
					f9a6988ece | ||
| 
						 | 
					95e06de5de | ||
| 
						 | 
					f530a5074b | ||
| 
						 | 
					439580b91b | ||
| 
						 | 
					4c2a384159 | ||
| 
						 | 
					22b83d7630 | ||
| 
						 | 
					cfd0b040e4 | ||
| 
						 | 
					b001840dee | ||
| 
						 | 
					0b5bff01e1 | ||
| 
						 | 
					4fe7b6cd65 | ||
| 
						 | 
					49e1f7d8bf | ||
| 
						 | 
					803fb243bf | ||
| 
						 | 
					20a6ab3d1a | ||
| 
						 | 
					21f16b50f3 | ||
| 
						 | 
					f58e83ee87 | ||
| 
						 | 
					a9b4a2a1ac | ||
| 
						 | 
					5be1449db5 | ||
| 
						 | 
					37d7f89c6d | ||
| 
						 | 
					57e58ce76c | ||
| 
						 | 
					1d9f76e2c8 | ||
| 
						 | 
					56e0269e5e | ||
| 
						 | 
					662df85e54 | ||
| 
						 | 
					2be4a5e486 | ||
| 
						 | 
					a43d697225 | ||
| 
						 | 
					f06c1e6c78 | ||
| 
						 | 
					b5d1918401 | ||
| 
						 | 
					d018be5d36 | ||
| 
						 | 
					67184d7b20 | ||
| 
						 | 
					dfdd48b990 | ||
| 
						 | 
					cae9cee295 | ||
| 
						 | 
					067d586c1c | ||
| 
						 | 
					d22b7938da | ||
| 
						 | 
					29b7510957 | ||
| 
						 | 
					9d548d81ac | ||
| 
						 | 
					3c33cdfa3d | ||
| 
						 | 
					288485b209 | ||
| 
						 | 
					1cbf416b10 | ||
| 
						 | 
					3b46d3dd74 | ||
| 
						 | 
					c243829234 | ||
| 
						 | 
					fd80faa389 | ||
| 
						 | 
					e7d4352292 | ||
| 
						 | 
					610e0f21d6 | ||
| 
						 | 
					7e512bad96 | ||
| 
						 | 
					98c4ce0c45 | ||
| 
						 | 
					93fc48a2db | ||
| 
						 | 
					d7eea12a6f | ||
| 
						 | 
					2a1e06f8a9 | ||
| 
						 | 
					02d54a783a | ||
| 
						 | 
					5961d44339 | ||
| 
						 | 
					fb3be8509d | ||
| 
						 | 
					97be53741d | ||
| 
						 | 
					0d2c26735e | ||
| 
						 | 
					2d0a8ddb58 | ||
| 
						 | 
					72518d4827 | ||
| 
						 | 
					c6cd744186 | ||
| 
						 | 
					ae2db62f1c | ||
| 
						 | 
					8c76b8bc36 | ||
| 
						 | 
					18256c4923 | ||
| 
						 | 
					f345cc66cf | ||
| 
						 | 
					5dbf664a6b | ||
| 
						 | 
					d7c6679d70 | ||
| 
						 | 
					cae203be71 | ||
| 
						 | 
					8a29fbc850 | ||
| 
						 | 
					00bcbd367f | ||
| 
						 | 
					1befee5aca | ||
| 
						 | 
					5982f4bcf0 | ||
| 
						 | 
					2399476a21 | ||
| 
						 | 
					9e45ac939b | ||
| 
						 | 
					34f231f9f3 | ||
| 
						 | 
					f940b2a58e | ||
| 
						 | 
					0383c33558 | ||
| 
						 | 
					3afa4b210d | ||
| 
						 | 
					998783eb9d | ||
| 
						 | 
					54d61bdc4a | ||
| 
						 | 
					2d279c4c5c | ||
| 
						 | 
					0fb206fe15 | ||
| 
						 | 
					5d6fd8099f | ||
| 
						 | 
					800e3f4599 | ||
| 
						 | 
					35c61f52fe | ||
| 
						 | 
					3db446633c | ||
| 
						 | 
					e3b4a0213c | ||
| 
						 | 
					9910ff5fa1 | ||
| 
						 | 
					049be10406 | ||
| 
						 | 
					9aa3be7f9f | ||
| 
						 | 
					aba5c634ae | ||
| 
						 | 
					9774b01b0e | ||
| 
						 | 
					ecf0a710e1 | ||
| 
						 | 
					a61fe418b2 | 
							
								
								
									
										25
									
								
								.github/ISSUE_TEMPLATE.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								.github/ISSUE_TEMPLATE.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
<!--
 | 
			
		||||
请确保已经更新到最新的代码, 然后贴上来 `--debug 2` 的调试输出. 没有调试输出,我帮不了你.
 | 
			
		||||
如何调试 https://github.com/Neilpang/acme.sh/wiki/How-to-debug-acme.sh
 | 
			
		||||
 | 
			
		||||
If it is a bug report:
 | 
			
		||||
- make sure you are able to repro it on the latest released version. 
 | 
			
		||||
You can install the latest version by: `acme.sh --upgrade`
 | 
			
		||||
 | 
			
		||||
- Search the existing issues.
 | 
			
		||||
- Refer to the [WIKI](https://wiki.acme.sh).
 | 
			
		||||
- Debug info [Debug](https://github.com/Neilpang/acme.sh/wiki/How-to-debug-acme.sh).
 | 
			
		||||
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
Steps to reproduce
 | 
			
		||||
------------------
 | 
			
		||||
 | 
			
		||||
Debug log
 | 
			
		||||
-----------------
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
acme.sh  --issue .....   --debug 2
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										9
									
								
								.github/PULL_REQUEST_TEMPLATE.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								.github/PULL_REQUEST_TEMPLATE.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
<!--
 | 
			
		||||
 | 
			
		||||
Do NOT send pull request to `master` branch.
 | 
			
		||||
 | 
			
		||||
Please send to `dev` branch instead.
 | 
			
		||||
 | 
			
		||||
Any PR to `master` branch will NOT be merged.
 | 
			
		||||
 | 
			
		||||
-->
 | 
			
		||||
							
								
								
									
										53
									
								
								.travis.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								.travis.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
language: shell
 | 
			
		||||
sudo: required
 | 
			
		||||
 | 
			
		||||
os:
 | 
			
		||||
  - linux
 | 
			
		||||
  - osx
 | 
			
		||||
 | 
			
		||||
env:
 | 
			
		||||
  global:
 | 
			
		||||
    - SHFMT_URL=https://github.com/mvdan/sh/releases/download/v0.4.0/shfmt_v0.4.0_linux_amd64
 | 
			
		||||
 | 
			
		||||
addons:
 | 
			
		||||
  apt:
 | 
			
		||||
    sources:
 | 
			
		||||
    - debian-sid    # Grab shellcheck from the Debian repo (o_O)
 | 
			
		||||
    packages:
 | 
			
		||||
    - shellcheck
 | 
			
		||||
 | 
			
		||||
install:
 | 
			
		||||
  - if [ "$TRAVIS_OS_NAME" = 'osx' ]; then
 | 
			
		||||
      brew update && brew install openssl;
 | 
			
		||||
      brew info openssl;
 | 
			
		||||
      ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/;
 | 
			
		||||
      ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/;
 | 
			
		||||
      ln -s /usr/local/Cellar/openssl/1.0.2j/bin/openssl /usr/local/openssl;
 | 
			
		||||
      _old_path="$PATH";
 | 
			
		||||
      echo "PATH=$PATH";
 | 
			
		||||
      export PATH="";
 | 
			
		||||
      export ACME_OPENSSL_BIN="/usr/local/openssl";
 | 
			
		||||
      openssl version 2>&1 || true;
 | 
			
		||||
      $ACME_OPENSSL_BIN version 2>&1 || true;
 | 
			
		||||
      export PATH="$_old_path";
 | 
			
		||||
    fi
 | 
			
		||||
  
 | 
			
		||||
script:
 | 
			
		||||
  - echo "NGROK_TOKEN=$(echo "$NGROK_TOKEN" | wc -c)"
 | 
			
		||||
  - command -V openssl && openssl version
 | 
			
		||||
  - if [ "$TRAVIS_OS_NAME" = "linux" ]; then curl -sSL $SHFMT_URL -o ~/shfmt ; fi
 | 
			
		||||
  - if [ "$TRAVIS_OS_NAME" = "linux" ]; then chmod +x ~/shfmt ; fi
 | 
			
		||||
  - 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
 | 
			
		||||
  - 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" ACME_OPENSSL_BIN="$ACME_OPENSSL_BIN" ./letest.sh ; fi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
matrix:
 | 
			
		||||
  fast_finish: true
 | 
			
		||||
  
 | 
			
		||||
  
 | 
			
		||||
							
								
								
									
										61
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,61 @@
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
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 \
 | 
			
		||||
  ; 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 \
 | 
			
		||||
 crond -f\n \
 | 
			
		||||
else \n \
 | 
			
		||||
 /root/.acme.sh/acme.sh --config-home /acme.sh \"\$@\"\n \
 | 
			
		||||
fi" >/entry.sh && chmod +x /entry.sh
 | 
			
		||||
 | 
			
		||||
VOLUME /acme.sh
 | 
			
		||||
 | 
			
		||||
ENTRYPOINT ["/entry.sh"]
 | 
			
		||||
CMD ["--help"]
 | 
			
		||||
							
								
								
									
										311
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										311
									
								
								README.md
									
									
									
									
									
								
							@@ -1,21 +1,44 @@
 | 
			
		||||
# An ACME Shell script: acme.sh
 | 
			
		||||
# 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.
 | 
			
		||||
- Fully ACME protocol implementation.
 | 
			
		||||
- Simple, powerful and very easy to use. You only need 3 minutes to learn.
 | 
			
		||||
- Bash, dash and sh compatible. 
 | 
			
		||||
- Full ACME protocol implementation.
 | 
			
		||||
- Simple, powerful and very easy to use. You only need 3 minutes to learn it.
 | 
			
		||||
- Bash, dash and sh compatible.
 | 
			
		||||
- Simplest shell script for Let's Encrypt free certificate client.
 | 
			
		||||
- Purely written in Shell with no dependencies on python or Let's Encrypt official client.
 | 
			
		||||
- Just one script, to issue, renew and install your certificates automatically.
 | 
			
		||||
- 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)
 | 
			
		||||
 | 
			
		||||
#Tested OS
 | 
			
		||||
# 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
 | 
			
		||||
 | 
			
		||||
| NO | Status| Platform|
 | 
			
		||||
|----|-------|---------|
 | 
			
		||||
|1|[](https://github.com/Neilpang/letest#here-are-the-latest-status)| Ubuntu
 | 
			
		||||
@@ -36,42 +59,44 @@ Wiki: https://github.com/Neilpang/acme.sh/wiki
 | 
			
		||||
|16|[](https://github.com/Neilpang/letest#here-are-the-latest-status)|Mageia
 | 
			
		||||
|17|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/Neilpang/acme.sh/wiki/How-to-run-on-OpenWRT)
 | 
			
		||||
|18|[](https://github.com/Neilpang/letest#here-are-the-latest-status)|SunOS/Solaris
 | 
			
		||||
|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
 | 
			
		||||
 | 
			
		||||
# Supported Mode
 | 
			
		||||
 | 
			
		||||
1. Webroot mode
 | 
			
		||||
2. Standalone mode
 | 
			
		||||
3. Apache mode
 | 
			
		||||
4. Dns mode
 | 
			
		||||
# Supported modes
 | 
			
		||||
 | 
			
		||||
- Webroot mode
 | 
			
		||||
- Standalone mode
 | 
			
		||||
- Apache mode
 | 
			
		||||
- Nginx mode ( Beta )
 | 
			
		||||
- DNS mode
 | 
			
		||||
- [Stateless mode](https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 1. How to install
 | 
			
		||||
 | 
			
		||||
### 1. Install online:
 | 
			
		||||
### 1. Install online
 | 
			
		||||
 | 
			
		||||
Check this project: https://github.com/Neilpang/get.acme.sh
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
curl https://get.acme.sh | sh
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Or:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
wget -O -  https://get.acme.sh | sh
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### 2. Or, Install from git:
 | 
			
		||||
### 2. Or, Install from git
 | 
			
		||||
 | 
			
		||||
Clone this project: 
 | 
			
		||||
Clone this project and launch installation:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
git clone https://github.com/Neilpang/acme.sh.git
 | 
			
		||||
@@ -81,14 +106,14 @@ cd ./acme.sh
 | 
			
		||||
 | 
			
		||||
You `don't have to be root` then, although `it is recommended`.
 | 
			
		||||
 | 
			
		||||
Advanced Installation:  https://github.com/Neilpang/acme.sh/wiki/How-to-install
 | 
			
		||||
Advanced Installation: https://github.com/Neilpang/acme.sh/wiki/How-to-install
 | 
			
		||||
 | 
			
		||||
The installer will perform 3 actions:
 | 
			
		||||
 | 
			
		||||
1. Create and copy `acme.sh` to your home dir (`$HOME`):  `~/.acme.sh/`.
 | 
			
		||||
All certs will be placed in this folder.
 | 
			
		||||
2. Create alias for: `acme.sh=~/.acme.sh/acme.sh`. 
 | 
			
		||||
3. Create everyday cron job to check and renew the cert if needed.
 | 
			
		||||
1. Create and copy `acme.sh` to your home dir (`$HOME`): `~/.acme.sh/`.
 | 
			
		||||
All certs will be placed in this folder too.
 | 
			
		||||
2. Create alias for: `acme.sh=~/.acme.sh/acme.sh`.
 | 
			
		||||
3. Create daily cron job to check and renew the certs if needed.
 | 
			
		||||
 | 
			
		||||
Cron entry example:
 | 
			
		||||
 | 
			
		||||
@@ -96,18 +121,17 @@ Cron entry example:
 | 
			
		||||
0 0 * * * "/home/user/.acme.sh"/acme.sh --cron --home "/home/user/.acme.sh" > /dev/null
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
After the installation, you must close current terminal and reopen again to make the alias take effect.
 | 
			
		||||
After the installation, you must close the current terminal and reopen it to make the alias take effect.
 | 
			
		||||
 | 
			
		||||
Ok, you are ready to issue certs now.
 | 
			
		||||
 | 
			
		||||
Ok, you are ready to issue cert now.
 | 
			
		||||
Show help message:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
root@v1:~# acme.sh -h
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 
 | 
			
		||||
# 2. Just issue a cert:
 | 
			
		||||
 | 
			
		||||
# 2. Just issue a cert
 | 
			
		||||
 | 
			
		||||
**Example 1:** Single domain.
 | 
			
		||||
 | 
			
		||||
@@ -115,50 +139,74 @@ 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 
 | 
			
		||||
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 cert for.
 | 
			
		||||
You must have at least a domain there.
 | 
			
		||||
Second argument **"example.com"** is the main domain you want to issue the cert for.
 | 
			
		||||
You must have at least one domain there.
 | 
			
		||||
 | 
			
		||||
You must point and bind all the domains to the same webroot dir: `/home/wwwroot/example.com`.
 | 
			
		||||
 | 
			
		||||
Generate/issued certs will be placed in `~/.acme.sh/example.com/`
 | 
			
		||||
Generated/issued certs will be placed in `~/.acme.sh/example.com/`
 | 
			
		||||
 | 
			
		||||
The issued cert will be renewed every **60** days automatically.
 | 
			
		||||
The issued cert will be renewed automatically every **60** days.
 | 
			
		||||
 | 
			
		||||
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 3. Install the issued cert to apache/nginx etc.
 | 
			
		||||
# 3. Install the issued cert to Apache/Nginx etc.
 | 
			
		||||
 | 
			
		||||
After you issue a cert, you probably want to install/copy the cert to your nginx/apache or other servers you may be using.
 | 
			
		||||
After you issue a cert, you probably want to install/copy the cert to your Apache/Nginx or other servers.
 | 
			
		||||
You **MUST** use this command to copy the certs to the target files, **DO NOT** use the certs files in **~/.acme.sh/** folder, they are for internal use only, the folder structure may change in the future.
 | 
			
		||||
 | 
			
		||||
**Apache** example:
 | 
			
		||||
```bash
 | 
			
		||||
acme.sh --installcert -d example.com \
 | 
			
		||||
--certpath /path/to/certfile/in/apache/nginx  \
 | 
			
		||||
--keypath  /path/to/keyfile/in/apache/nginx  \
 | 
			
		||||
--capath   /path/to/ca/certfile/apache/nginx   \
 | 
			
		||||
--fullchainpath path/to/fullchain/certfile/apache/nginx \
 | 
			
		||||
--reloadcmd  "service apache2|nginx reload"
 | 
			
		||||
acme.sh --install-cert -d example.com \
 | 
			
		||||
--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 \
 | 
			
		||||
--key-file       /path/to/keyfile/in/nginx/key.pem  \
 | 
			
		||||
--fullchain-file /path/to/fullchain/nginx/cert.pem \
 | 
			
		||||
--reloadcmd     "service nginx force-reload"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Only the domain is required, all the other parameters are optional.
 | 
			
		||||
 | 
			
		||||
Install/copy the issued cert/key to the production apache or nginx path.
 | 
			
		||||
The ownership and permission info of existing files are preserved. You may want to precreate the files to have defined ownership and permission.
 | 
			
		||||
 | 
			
		||||
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 reloaded automatically by the command: `service apache2 force-reload` or `service nginx force-reload`.
 | 
			
		||||
 | 
			
		||||
The cert will be `renewed every **60** days by default` (which is configurable). Once the cert is renewed, the apache/nginx will be automatically reloaded by the command: `service apache2 reload` or `service nginx reload`.
 | 
			
		||||
 | 
			
		||||
# 4. Use Standalone server to issue cert
 | 
			
		||||
 | 
			
		||||
**(requires you be root/sudoer, or you have permission to listen tcp 80 port)**
 | 
			
		||||
**(requires you to be root/sudoer or have permission to listen on port 80 (TCP))**
 | 
			
		||||
 | 
			
		||||
The tcp `80` port **MUST** be free to listen, otherwise you will be prompted to free the `80` port and try again.
 | 
			
		||||
Port `80` (TCP) **MUST** be free to listen on, otherwise you will be prompted to free it and try again.
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
acme.sh --issue --standalone -d example.com -d www.example.com -d cp.example.com
 | 
			
		||||
@@ -166,13 +214,14 @@ acme.sh --issue --standalone -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
 | 
			
		||||
 | 
			
		||||
# 5. Use Standalone tls server to issue cert
 | 
			
		||||
 | 
			
		||||
**(requires you be root/sudoer, or you have permission to listen tcp 443 port)**
 | 
			
		||||
# 5. Use Standalone TLS server to issue cert
 | 
			
		||||
 | 
			
		||||
**(requires you to be root/sudoer or have permission to listen on port 443 (TCP))**
 | 
			
		||||
 | 
			
		||||
acme.sh supports `tls-sni-01` validation.
 | 
			
		||||
 | 
			
		||||
The tcp `443` port **MUST** be free to listen, otherwise you will be prompted to free the `443` port and try again.
 | 
			
		||||
Port `443` (TCP) **MUST** be free to listen on, otherwise you will be prompted to free it and try again.
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
acme.sh --issue --tls -d example.com -d www.example.com -d cp.example.com
 | 
			
		||||
@@ -180,31 +229,52 @@ acme.sh --issue --tls -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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 6. Use Apache mode
 | 
			
		||||
 | 
			
		||||
**(requires you be root/sudoer, since it is required to interact with apache server)**
 | 
			
		||||
**(requires you to be root/sudoer, since it is required to interact with Apache server)**
 | 
			
		||||
 | 
			
		||||
If you are running a web server, apache or nginx, it is recommended to use the `Webroot mode`.
 | 
			
		||||
If you are running a web server, Apache or Nginx, it is recommended to use the `Webroot mode`.
 | 
			
		||||
 | 
			
		||||
Particularly, if you are running an apache server, you should use apache mode instead. This mode doesn't write any files to your web root folder.
 | 
			
		||||
Particularly, if you are running an Apache server, you should use Apache mode instead. This mode doesn't write any files to your web root folder.
 | 
			
		||||
 | 
			
		||||
Just set string "apache" as the second argument, it will force use of apache plugin automatically.
 | 
			
		||||
Just set string "apache" as the second argument and it will force use of apache plugin automatically.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
acme.sh --issue --apache -d example.com -d www.example.com -d user.example.com
 | 
			
		||||
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 DNS mode:
 | 
			
		||||
# 7. Use Nginx 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.
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
acme.sh --issue --dns -d example.com -d www.example.com -d user.example.com
 | 
			
		||||
acme.sh --issue --dns -d example.com -d www.example.com -d cp.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
You should get the output like below:
 | 
			
		||||
You should get an output like below:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
Add the following txt record:
 | 
			
		||||
@@ -216,7 +286,6 @@ Domain:_acme-challenge.www.example.com
 | 
			
		||||
Txt value:9ihDbjxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
 | 
			
		||||
 | 
			
		||||
Please add those txt records to the domains. Waiting for the dns to take effect.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Then just rerun with `renew` argument:
 | 
			
		||||
@@ -227,50 +296,78 @@ acme.sh --renew -d example.com
 | 
			
		||||
 | 
			
		||||
Ok, it's finished.
 | 
			
		||||
 | 
			
		||||
# 8. Automatic DNS API integration
 | 
			
		||||
 | 
			
		||||
If your DNS provider supports API access, we can use API to automatically issue the certs.
 | 
			
		||||
# 9. Automatic DNS API integration
 | 
			
		||||
 | 
			
		||||
You don't have do anything manually!
 | 
			
		||||
If your DNS provider supports API access, we can use that API to automatically issue the certs.
 | 
			
		||||
 | 
			
		||||
You don't have to do anything manually!
 | 
			
		||||
 | 
			
		||||
### Currently acme.sh supports:
 | 
			
		||||
 | 
			
		||||
1. Cloudflare.com API
 | 
			
		||||
2. Dnspod.cn API
 | 
			
		||||
3. Cloudxns.com API
 | 
			
		||||
4. Godaddy.com API
 | 
			
		||||
5. OVH, kimsufi, soyoustart and runabove API
 | 
			
		||||
6. AWS Route 53, see: https://github.com/Neilpang/acme.sh/issues/65
 | 
			
		||||
7. PowerDNS API
 | 
			
		||||
8. 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. CloudFlare.com API
 | 
			
		||||
1. DNSPod.cn API
 | 
			
		||||
1. CloudXNS.com API
 | 
			
		||||
1. GoDaddy.com API
 | 
			
		||||
1. PowerDNS.com API
 | 
			
		||||
1. OVH, kimsufi, soyoustart and runabove API
 | 
			
		||||
1. nsupdate API
 | 
			
		||||
1. LuaDNS.com API
 | 
			
		||||
1. DNSMadeEasy.com 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
 | 
			
		||||
 | 
			
		||||
##### More APIs are coming soon...
 | 
			
		||||
 | 
			
		||||
If your DNS provider is not on the supported list above, you can write your own script API easily. If you do please consider submitting a [Pull Request](https://github.com/Neilpang/acme.sh/pulls) and contribute to the project.
 | 
			
		||||
 | 
			
		||||
For more details: [How to use dns api](dnsapi)
 | 
			
		||||
And: 
 | 
			
		||||
 | 
			
		||||
# 9. Issue ECC certificate:
 | 
			
		||||
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.)
 | 
			
		||||
 | 
			
		||||
`Let's Encrypt` now can issue **ECDSA** certificates.
 | 
			
		||||
 | 
			
		||||
And we also support it.
 | 
			
		||||
   
 | 
			
		||||
**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.
 | 
			
		||||
 | 
			
		||||
For more details: [How to use DNS API](dnsapi)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 10. Issue ECC certificates
 | 
			
		||||
 | 
			
		||||
`Let's Encrypt` can now issue **ECDSA** certificates.
 | 
			
		||||
 | 
			
		||||
And we support them too!
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
acme.sh --issue -w /home/wwwroot/example.com -d example.com --keylength ec-256
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
SAN multi domain ECC certificate:
 | 
			
		||||
### SAN multi domain ECC certificate
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
acme.sh --issue -w /home/wwwroot/example.com -d example.com -d www.example.com --keylength  ec-256
 | 
			
		||||
acme.sh --issue -w /home/wwwroot/example.com -d example.com -d www.example.com --keylength ec-256
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Please look at the last parameter above.
 | 
			
		||||
@@ -282,67 +379,79 @@ Valid values are:
 | 
			
		||||
3. **ec-521 (secp521r1,  "ECDSA P-521", which is not supported by Let's Encrypt yet.)**
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 10. How to renew the cert
 | 
			
		||||
# 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.
 | 
			
		||||
No, you don't need to renew the certs manually. All the certs will be renewed automatically every **60** days.
 | 
			
		||||
 | 
			
		||||
However, you can also force to renew any cert:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
acme.sh --renew  -d  example.com --force
 | 
			
		||||
acme.sh --renew -d example.com --force
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
or, for ECC cert:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
acme.sh --renew  -d  example.com  --force --ecc
 | 
			
		||||
acme.sh --renew -d example.com --force --ecc
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
# 11. How to upgrade `acme.sh`
 | 
			
		||||
acme.sh is in developing, it's strongly recommended to use the latest code.
 | 
			
		||||
 | 
			
		||||
# 12. How to upgrade `acme.sh`
 | 
			
		||||
 | 
			
		||||
acme.sh is in constant development, so it's strongly recommended to use the latest code.
 | 
			
		||||
 | 
			
		||||
You can update acme.sh to the latest code:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
acme.sh --upgrade
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
You can enable auto upgrade:
 | 
			
		||||
You can also enable auto upgrade:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
acme.sh  --upgrade  --auto-upgrade
 | 
			
		||||
acme.sh --upgrade --auto-upgrade
 | 
			
		||||
```
 | 
			
		||||
Then **acme.sh** will keep up to date automatically.
 | 
			
		||||
 | 
			
		||||
Then **acme.sh** will be kept up to date automatically.
 | 
			
		||||
 | 
			
		||||
Disable auto upgrade:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
acme.sh  --upgrade  --auto-upgrade 0
 | 
			
		||||
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:
 | 
			
		||||
 | 
			
		||||
# Acknowledgment
 | 
			
		||||
 | 
			
		||||
# 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
 | 
			
		||||
 | 
			
		||||
Please Star and Fork me.
 | 
			
		||||
 | 
			
		||||
[Issues](https://github.com/Neilpang/acme.sh/issues) and [pull requests](https://github.com/Neilpang/acme.sh/pulls) are welcomed.
 | 
			
		||||
[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)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										82
									
								
								deploy/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								deploy/README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
			
		||||
# 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.)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Then you can deploy now:
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
export DEPLOY_CPANEL_USER=myusername
 | 
			
		||||
export DEPLOY_CPANEL_PASSWORD=PASSWORD
 | 
			
		||||
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.
 | 
			
		||||
 | 
			
		||||
```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
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										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
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								deploy/cpanel.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								deploy/cpanel.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#Here is the script to deploy the cert to your cpanel account by the cpanel APIs.
 | 
			
		||||
 | 
			
		||||
#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() {
 | 
			
		||||
  _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 "Not implemented yet"
 | 
			
		||||
  return 1
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								deploy/dovecot.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								deploy/dovecot.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#Here is a script to deploy cert to dovecot server.
 | 
			
		||||
 | 
			
		||||
#returns 0 means success, otherwise error.
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#domain keyfile certfile cafile fullchain
 | 
			
		||||
dovecot_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 "Not implemented yet"
 | 
			
		||||
  return 1
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										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
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										77
									
								
								deploy/kong.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										77
									
								
								deploy/kong.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,77 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
# If certificate already exist it will update only cert and key not touching other parameter
 | 
			
		||||
# If certificate  doesn't exist it will only upload cert and key and not set other parameter
 | 
			
		||||
# Note that we deploy full chain
 | 
			
		||||
# Written by Geoffroi Genot <ggenot@voxbone.com>
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#domain keyfile certfile cafile fullchain
 | 
			
		||||
kong_deploy() {
 | 
			
		||||
  _cdomain="$1"
 | 
			
		||||
  _ckey="$2"
 | 
			
		||||
  _ccert="$3"
 | 
			
		||||
  _cca="$4"
 | 
			
		||||
  _cfullchain="$5"
 | 
			
		||||
  _info "Deploying certificate on Kong instance"
 | 
			
		||||
  if [ -z "$KONG_URL" ]; then
 | 
			
		||||
    _debug "KONG_URL Not set, using default http://localhost:8001"
 | 
			
		||||
    KONG_URL="http://localhost:8001"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug _cdomain "$_cdomain"
 | 
			
		||||
  _debug _ckey "$_ckey"
 | 
			
		||||
  _debug _ccert "$_ccert"
 | 
			
		||||
  _debug _cca "$_cca"
 | 
			
		||||
  _debug _cfullchain "$_cfullchain"
 | 
			
		||||
 | 
			
		||||
  #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="-----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)
 | 
			
		||||
  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=\"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=\"cert\"; filename=\"$(basename "$_cfullchain")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_cfullchain")"
 | 
			
		||||
  #Close multipart
 | 
			
		||||
  content="$content${nl}--$delim--${nl}"
 | 
			
		||||
  #Convert CRLF
 | 
			
		||||
  content=$(printf %b "$content")
 | 
			
		||||
  #DEBUG
 | 
			
		||||
  _debug header "$_H1"
 | 
			
		||||
  _debug content "$content"
 | 
			
		||||
  #Check if sslcreated (if not => POST else => PATCH)
 | 
			
		||||
 | 
			
		||||
  if [ -z "$ssl_uuid" ]; then
 | 
			
		||||
    #Post certificate to Kong
 | 
			
		||||
    response=$(_post "$content" "$KONG_URL/certificates" "" "POST")
 | 
			
		||||
  else
 | 
			
		||||
    #patch
 | 
			
		||||
    response=$(_post "$content" "$KONG_URL/certificates/$ssl_uuid" "" "PATCH")
 | 
			
		||||
  fi
 | 
			
		||||
  if ! [ "$(echo "$response" | _egrep_o "created_at")" = "created_at" ]; then
 | 
			
		||||
    _err "An error occurred with cert upload. Check response:"
 | 
			
		||||
    _err "$response"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug response "$response"
 | 
			
		||||
  _info "Certificate successfully deployed"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										28
									
								
								deploy/myapi.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										28
									
								
								deploy/myapi.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
#!/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
 | 
			
		||||
myapi_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 "Not implemented yet"
 | 
			
		||||
  return 1
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										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
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										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
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										504
									
								
								dnsapi/README.md
									
									
									
									
									
								
							
							
						
						
									
										504
									
								
								dnsapi/README.md
									
									
									
									
									
								
							@@ -1,99 +1,80 @@
 | 
			
		||||
# How to use dns api
 | 
			
		||||
# How to use DNS API
 | 
			
		||||
 | 
			
		||||
## Use CloudFlare domain api to automatically issue cert
 | 
			
		||||
## 1. Use CloudFlare domain API to automatically issue cert
 | 
			
		||||
 | 
			
		||||
For now, we support clourflare integeration.
 | 
			
		||||
 | 
			
		||||
First you need to login to your clourflare account to get your api key.
 | 
			
		||||
First you need to login to your CloudFlare account to get your API key.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
export CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
 | 
			
		||||
 | 
			
		||||
export CF_Email="xxxx@sss.com"
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Ok, let's issue cert now:
 | 
			
		||||
Ok, let's issue a cert now:
 | 
			
		||||
```
 | 
			
		||||
acme.sh   --issue   --dns dns_cf   -d example.com  -d www.example.com
 | 
			
		||||
acme.sh --issue --dns dns_cf -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `CF_Key` and `CF_Email`  will be saved in `~/.acme.sh/account.conf`, when next time you use cloudflare api, it will reuse this key.
 | 
			
		||||
The `CF_Key` and `CF_Email` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## 2. Use DNSPod.cn domain API to automatically issue cert
 | 
			
		||||
 | 
			
		||||
## Use Dnspod.cn domain api to automatically issue cert
 | 
			
		||||
 | 
			
		||||
For now, we support dnspod.cn integeration.
 | 
			
		||||
 | 
			
		||||
First you need to login to your dnspod.cn account to get your api key and key id.
 | 
			
		||||
First you need to login to your DNSPod account to get your API Key and ID.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
export DP_Id="1234"
 | 
			
		||||
 | 
			
		||||
export DP_Key="sADDsdasdgdsf"
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Ok, let's issue cert now:
 | 
			
		||||
Ok, let's issue a cert now:
 | 
			
		||||
```
 | 
			
		||||
acme.sh   --issue   --dns dns_dp   -d example.com  -d www.example.com
 | 
			
		||||
acme.sh --issue --dns dns_dp -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `DP_Id` and `DP_Key`  will be saved in `~/.acme.sh/account.conf`, when next time you use dnspod.cn api, it will reuse this key.
 | 
			
		||||
The `DP_Id` and `DP_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Use Cloudxns.com domain api to automatically issue cert
 | 
			
		||||
## 3. Use CloudXNS.com domain API to automatically issue cert
 | 
			
		||||
 | 
			
		||||
For now, we support Cloudxns.com integeration.
 | 
			
		||||
 | 
			
		||||
First you need to login to your Cloudxns.com account to get your api key and key secret.
 | 
			
		||||
First you need to login to your CloudXNS account to get your API Key and Secret.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
export CX_Key="1234"
 | 
			
		||||
 | 
			
		||||
export CX_Secret="sADDsdasdgdsf"
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Ok, let's issue cert now:
 | 
			
		||||
Ok, let's issue a cert now:
 | 
			
		||||
```
 | 
			
		||||
acme.sh   --issue   --dns dns_cx   -d example.com  -d www.example.com
 | 
			
		||||
acme.sh --issue --dns dns_cx -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `CX_Key` and `CX_Secret`  will be saved in `~/.acme.sh/account.conf`, when next time you use Cloudxns.com api, it will reuse this key.
 | 
			
		||||
The `CX_Key` and `CX_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Use Godaddy.com domain api to automatically issue cert
 | 
			
		||||
## 4. Use GoDaddy.com domain API to automatically issue cert
 | 
			
		||||
 | 
			
		||||
We support Godaddy integration.
 | 
			
		||||
 | 
			
		||||
First you need to login to your Godaddy account to get your api key and api secret.
 | 
			
		||||
First you need to login to your GoDaddy account to get your API Key and Secret.
 | 
			
		||||
 | 
			
		||||
https://developer.godaddy.com/keys/
 | 
			
		||||
 | 
			
		||||
Please Create a Production key, instead of a Test key.
 | 
			
		||||
 | 
			
		||||
Please create a Production key, instead of a Test key.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
export GD_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
 | 
			
		||||
 | 
			
		||||
export GD_Secret="asdfsdafdsfdsfdsfdsfdsafd"
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Ok, let's issue cert now:
 | 
			
		||||
Ok, let's issue a cert now:
 | 
			
		||||
```
 | 
			
		||||
acme.sh   --issue   --dns dns_gd   -d example.com  -d www.example.com
 | 
			
		||||
acme.sh --issue --dns dns_gd -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `GD_Key` and `GD_Secret`  will be saved in `~/.acme.sh/account.conf`, when next time you use cloudflare api, it will reuse this key.
 | 
			
		||||
The `GD_Key` and `GD_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
 | 
			
		||||
 | 
			
		||||
## Use PowerDNS embedded api to automatically issue cert
 | 
			
		||||
 | 
			
		||||
We support PowerDNS embedded API integration.
 | 
			
		||||
## 5. Use PowerDNS embedded API to automatically issue cert
 | 
			
		||||
 | 
			
		||||
First you need to enable api and set your api-token in PowerDNS configuration.
 | 
			
		||||
First you need to login to your PowerDNS account to enable the API and set your API-Token in the configuration.
 | 
			
		||||
 | 
			
		||||
https://doc.powerdns.com/md/httpapi/README/
 | 
			
		||||
 | 
			
		||||
@@ -102,38 +83,445 @@ export PDNS_Url="http://ns.example.com:8081"
 | 
			
		||||
export PDNS_ServerId="localhost"
 | 
			
		||||
export PDNS_Token="0123456789ABCDEF"
 | 
			
		||||
export PDNS_Ttl=60
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Ok, let's issue cert now:
 | 
			
		||||
Ok, let's issue a cert now:
 | 
			
		||||
```
 | 
			
		||||
acme.sh   --issue   --dns dns_pdns   -d example.com  -d www.example.com
 | 
			
		||||
acme.sh --issue --dns dns_pdns -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `PDNS_Url`, `PDNS_ServerId`, `PDNS_Token` and `PDNS_Ttl` will be saved in `~/.acme.sh/account.conf`.
 | 
			
		||||
The `PDNS_Url`, `PDNS_ServerId`, `PDNS_Token` and `PDNS_Ttl` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
 | 
			
		||||
 | 
			
		||||
## Use OVH/kimsufi/soyoustart/runabove API
 | 
			
		||||
 | 
			
		||||
## 6. Use OVH/kimsufi/soyoustart/runabove API to automatically issue cert
 | 
			
		||||
 | 
			
		||||
https://github.com/Neilpang/acme.sh/wiki/How-to-use-OVH-domain-api
 | 
			
		||||
 | 
			
		||||
# Use custom api
 | 
			
		||||
 | 
			
		||||
If your api is not supported yet,  you can write your own dns api.
 | 
			
		||||
## 7. Use nsupdate to automatically issue cert
 | 
			
		||||
 | 
			
		||||
Let's assume you want to name it 'myapi',
 | 
			
		||||
First, generate a key for updating the zone
 | 
			
		||||
```
 | 
			
		||||
b=$(dnssec-keygen -a hmac-sha512 -b 512 -n USER -K /tmp foo)
 | 
			
		||||
cat > /etc/named/keys/update.key <<EOF
 | 
			
		||||
key "update" {
 | 
			
		||||
    algorithm hmac-sha512;
 | 
			
		||||
    secret "$(awk '/^Key/{print $2}' /tmp/$b.private)";
 | 
			
		||||
};
 | 
			
		||||
EOF
 | 
			
		||||
rm -f /tmp/$b.{private,key}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
1. Create a bash script named  `~/.acme.sh/dns_myapi.sh`,
 | 
			
		||||
2. In the script, you must have a function named `dns_myapi_add()`. Which will be called by acme.sh to add dns records.
 | 
			
		||||
3. Then you can use your api to issue cert like:
 | 
			
		||||
Include this key in your named configuration
 | 
			
		||||
```
 | 
			
		||||
include "/etc/named/keys/update.key";
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Next, configure your zone to allow dynamic updates.
 | 
			
		||||
 | 
			
		||||
Depending on your named version, use either
 | 
			
		||||
```
 | 
			
		||||
zone "example.com" {
 | 
			
		||||
    type master;
 | 
			
		||||
    allow-update { key "update"; };
 | 
			
		||||
};
 | 
			
		||||
```
 | 
			
		||||
or
 | 
			
		||||
```
 | 
			
		||||
zone "example.com" {
 | 
			
		||||
    type master;
 | 
			
		||||
    update-policy {
 | 
			
		||||
        grant update subdomain example.com.;
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Finally, make the DNS server and update Key available to `acme.sh`
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
acme.sh  --issue  --dns  dns_myapi  -d example.com  -d www.example.com
 | 
			
		||||
export NSUPDATE_SERVER="dns.example.com"
 | 
			
		||||
export NSUPDATE_KEY="/path/to/your/nsupdate.key"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Ok, let's issue a cert now:
 | 
			
		||||
```
 | 
			
		||||
acme.sh --issue --dns dns_nsupdate -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `NSUPDATE_SERVER` and `NSUPDATE_KEY` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## 8. Use LuaDNS domain API
 | 
			
		||||
 | 
			
		||||
Get your API token at https://api.luadns.com/settings
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
export LUA_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
 | 
			
		||||
export LUA_Email="xxxx@sss.com"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
To issue a cert:
 | 
			
		||||
```
 | 
			
		||||
acme.sh --issue --dns dns_lua -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `LUA_Key` and `LUA_Email` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## 9. Use DNSMadeEasy domain API
 | 
			
		||||
 | 
			
		||||
Get your API credentials at https://cp.dnsmadeeasy.com/account/info
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
export ME_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
 | 
			
		||||
export ME_Secret="qdfqsdfkjdskfj"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
To issue a cert:
 | 
			
		||||
```
 | 
			
		||||
acme.sh --issue --dns dns_me -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `ME_Key` and `ME_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## 10. Use Amazon Route53 domain API
 | 
			
		||||
 | 
			
		||||
https://github.com/Neilpang/acme.sh/wiki/How-to-use-Amazon-Route53-API
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
export  AWS_ACCESS_KEY_ID=XXXXXXXXXX
 | 
			
		||||
export  AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXX
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
To issue a cert:
 | 
			
		||||
```
 | 
			
		||||
acme.sh --issue --dns dns_aws -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
 | 
			
		||||
 | 
			
		||||
## 11. Use Aliyun domain API to automatically issue cert
 | 
			
		||||
 | 
			
		||||
First you need to login to your Aliyun account to get your API key.
 | 
			
		||||
[https://ak-console.aliyun.com/#/accesskey](https://ak-console.aliyun.com/#/accesskey)
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
export Ali_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
 | 
			
		||||
export Ali_Secret="jlsdflanljkljlfdsaklkjflsa"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Ok, let's issue a cert now:
 | 
			
		||||
```
 | 
			
		||||
acme.sh --issue --dns dns_ali -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `Ali_Key` and `Ali_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
 | 
			
		||||
 | 
			
		||||
## 12. Use ISPConfig 3.1 API
 | 
			
		||||
 | 
			
		||||
This only works for ISPConfig 3.1 (and newer).
 | 
			
		||||
 | 
			
		||||
Create a Remote User in the ISPConfig Control Panel. The Remote User must have access to at least `DNS zone functions` and `DNS txt functions`.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
export ISPC_User="xxx"
 | 
			
		||||
export ISPC_Password="xxx"
 | 
			
		||||
export ISPC_Api="https://ispc.domain.tld:8080/remote/json.php"
 | 
			
		||||
export ISPC_Api_Insecure=1
 | 
			
		||||
```
 | 
			
		||||
If you have installed ISPConfig on a different port, then alter the 8080 accordingly.
 | 
			
		||||
Leaver ISPC_Api_Insecure set to 1 if you have not a valid ssl cert for your installation. Change it to 0 if you have a valid ssl cert.
 | 
			
		||||
 | 
			
		||||
To issue a cert:
 | 
			
		||||
```
 | 
			
		||||
acme.sh --issue --dns dns_ispconfig -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `ISPC_User`, `ISPC_Password`, `ISPC_Api`and `ISPC_Api_Insecure` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
 | 
			
		||||
 | 
			
		||||
## 13. Use Alwaysdata domain API
 | 
			
		||||
 | 
			
		||||
First you need to login to your Alwaysdata account to get your API Key.
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
export AD_API_KEY="myalwaysdataapikey"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Ok, let's issue a cert now:
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
acme.sh --issue --dns dns_ad -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `AD_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused
 | 
			
		||||
when needed.
 | 
			
		||||
 | 
			
		||||
## 14. Use Linode domain API
 | 
			
		||||
 | 
			
		||||
First you need to login to your Linode account to get your API Key.
 | 
			
		||||
[https://manager.linode.com/profile/api](https://manager.linode.com/profile/api)
 | 
			
		||||
 | 
			
		||||
Then add an API key with label *ACME* and copy the new key.
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
export LINODE_API_KEY="..."
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Due to the reload time of any changes in the DNS records, we have to use the `dnssleep` option to wait at least 15 minutes for the changes to take effect.
 | 
			
		||||
 | 
			
		||||
Ok, let's issue a cert now:
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
acme.sh --issue --dns dns_linode --dnssleep 900 -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `LINODE_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
 | 
			
		||||
 | 
			
		||||
## 15. Use FreeDNS
 | 
			
		||||
 | 
			
		||||
FreeDNS (https://freedns.afraid.org/) does not provide an API to update DNS records (other than IPv4 and IPv6
 | 
			
		||||
dynamic DNS addresses).  The acme.sh plugin therefore retrieves and updates domain TXT records by logging
 | 
			
		||||
into the FreeDNS website to read the HTML and posting updates as HTTP.  The plugin needs to know your
 | 
			
		||||
userid and password for the FreeDNS website.
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
export FREEDNS_User="..."
 | 
			
		||||
export FREEDNS_Password="..."
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
You need only provide this the first time you run the acme.sh client with FreeDNS validation and then again
 | 
			
		||||
whenever you change your password at the FreeDNS site.  The acme.sh FreeDNS plugin does not store your userid
 | 
			
		||||
or password but rather saves an authentication token returned by FreeDNS in `~/.acme.sh/account.conf` and
 | 
			
		||||
reuses that when needed.
 | 
			
		||||
 | 
			
		||||
Now you can issue a certificate.
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
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 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
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
# Use custom API
 | 
			
		||||
 | 
			
		||||
If your API is not supported yet, you can write your own DNS API.
 | 
			
		||||
 | 
			
		||||
Let's assume you want to name it 'myapi':
 | 
			
		||||
 | 
			
		||||
1. Create a bash script named `~/.acme.sh/dns_myapi.sh`,
 | 
			
		||||
2. In the script you must have a function named `dns_myapi_add()` which will be called by acme.sh to add the DNS records.
 | 
			
		||||
3. Then you can use your API to issue cert like this:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
acme.sh --issue --dns dns_myapi -d example.com -d www.example.com
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
For more details, please check our sample script: [dns_myapi.sh](dns_myapi.sh)
 | 
			
		||||
 | 
			
		||||
# Use lexicon dns api
 | 
			
		||||
 | 
			
		||||
# Use lexicon DNS API
 | 
			
		||||
 | 
			
		||||
https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										147
									
								
								dnsapi/dns_ad.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										147
									
								
								dnsapi/dns_ad.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,147 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
#AD_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje"
 | 
			
		||||
 | 
			
		||||
#This is the Alwaysdata api wrapper for acme.sh
 | 
			
		||||
#
 | 
			
		||||
#Author: Paul Koppen
 | 
			
		||||
#Report Bugs here: https://github.com/wpk-/acme.sh
 | 
			
		||||
 | 
			
		||||
AD_API_URL="https://$AD_API_KEY:@api.alwaysdata.com/v1"
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: dns_myapi_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_ad_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  if [ -z "$AD_API_KEY" ]; then
 | 
			
		||||
    AD_API_KEY=""
 | 
			
		||||
    _err "You didn't specify the AD api key yet."
 | 
			
		||||
    _err "Please create you key and try again."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _saveaccountconf AD_API_KEY "$AD_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"
 | 
			
		||||
 | 
			
		||||
  _ad_tmpl_json="{\"domain\":$_domain_id,\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\"}"
 | 
			
		||||
 | 
			
		||||
  if _ad_rest POST "record/" "$_ad_tmpl_json" && [ -z "$response" ]; then
 | 
			
		||||
    _info "txt record updated success."
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#fulldomain txtvalue
 | 
			
		||||
dns_ad_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"
 | 
			
		||||
  _ad_rest GET "record/?domain=$_domain_id&name=$_sub_domain"
 | 
			
		||||
 | 
			
		||||
  if [ -n "$response" ]; then
 | 
			
		||||
    record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1)
 | 
			
		||||
    _debug record_id "$record_id"
 | 
			
		||||
    if [ -z "$record_id" ]; then
 | 
			
		||||
      _err "Can not get record id to remove."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    if _ad_rest DELETE "record/$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 _ad_rest GET "domain/"; then
 | 
			
		||||
    response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')"
 | 
			
		||||
    while true; do
 | 
			
		||||
      h=$(printf "%s" "$domain" | cut -d . -f $i-100)
 | 
			
		||||
      _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
 | 
			
		||||
_ad_rest() {
 | 
			
		||||
  mtd="$1"
 | 
			
		||||
  ep="$2"
 | 
			
		||||
  data="$3"
 | 
			
		||||
 | 
			
		||||
  _debug mtd "$mtd"
 | 
			
		||||
  _debug ep "$ep"
 | 
			
		||||
 | 
			
		||||
  export _H1="Accept: application/json"
 | 
			
		||||
  export _H2="Content-Type: application/json"
 | 
			
		||||
 | 
			
		||||
  if [ "$mtd" != "GET" ]; then
 | 
			
		||||
    # both POST and DELETE.
 | 
			
		||||
    _debug data "$data"
 | 
			
		||||
    response="$(_post "$data" "$AD_API_URL/$ep" "" "$mtd")"
 | 
			
		||||
  else
 | 
			
		||||
    response="$(_get "$AD_API_URL/$ep")"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "error $ep"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										187
									
								
								dnsapi/dns_ali.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										187
									
								
								dnsapi/dns_ali.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,187 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
Ali_API="https://alidns.aliyuncs.com/"
 | 
			
		||||
 | 
			
		||||
#Ali_Key="LTqIA87hOKdjevsf5"
 | 
			
		||||
#Ali_Secret="0p5EYueFNq501xnCPzKNbx6K51qPH2"
 | 
			
		||||
 | 
			
		||||
#Usage: dns_ali_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_ali_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  if [ -z "$Ali_Key" ] || [ -z "$Ali_Secret" ]; then
 | 
			
		||||
    Ali_Key=""
 | 
			
		||||
    Ali_Secret=""
 | 
			
		||||
    _err "You don't specify aliyun api key and secret yet."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  #save the api key and secret to the account conf file.
 | 
			
		||||
  _saveaccountconf Ali_Key "$Ali_Key"
 | 
			
		||||
  _saveaccountconf Ali_Secret "$Ali_Secret"
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug "Add record"
 | 
			
		||||
  _add_record_query "$_domain" "$_sub_domain" "$txtvalue" && _ali_rest "Add record"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dns_ali_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  _clean
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
 | 
			
		||||
_get_root() {
 | 
			
		||||
  domain=$1
 | 
			
		||||
  i=2
 | 
			
		||||
  p=1
 | 
			
		||||
  while true; do
 | 
			
		||||
    h=$(printf "%s" "$domain" | cut -d . -f $i-100)
 | 
			
		||||
    if [ -z "$h" ]; then
 | 
			
		||||
      #not valid
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    _describe_records_query "$h"
 | 
			
		||||
    if ! _ali_rest "Get root" "ignore"; then
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if _contains "$response" "PageNumber"; then
 | 
			
		||||
      _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
 | 
			
		||||
      _debug _sub_domain "$_sub_domain"
 | 
			
		||||
      _domain="$h"
 | 
			
		||||
      _debug _domain "$_domain"
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
    p="$i"
 | 
			
		||||
    i=$(_math "$i" + 1)
 | 
			
		||||
  done
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_ali_rest() {
 | 
			
		||||
  signature=$(printf "%s" "GET&%2F&$(_ali_urlencode "$query")" | _hmac "sha1" "$(printf "%s" "$Ali_Secret&" | _hex_dump | tr -d " ")" | _base64)
 | 
			
		||||
  signature=$(_ali_urlencode "$signature")
 | 
			
		||||
  url="$Ali_API?$query&Signature=$signature"
 | 
			
		||||
 | 
			
		||||
  if ! response="$(_get "$url")"; then
 | 
			
		||||
    _err "Error <$1>"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "$2" ]; then
 | 
			
		||||
    message="$(printf "%s" "$response" | _egrep_o "\"Message\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")"
 | 
			
		||||
    if [ -n "$message" ]; then
 | 
			
		||||
      _err "$message"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_ali_urlencode() {
 | 
			
		||||
  _str="$1"
 | 
			
		||||
  _str_len=${#_str}
 | 
			
		||||
  _u_i=1
 | 
			
		||||
  while [ "$_u_i" -le "$_str_len" ]; do
 | 
			
		||||
    _str_c="$(printf "%s" "$_str" | cut -c "$_u_i")"
 | 
			
		||||
    case $_str_c in [a-zA-Z0-9.~_-])
 | 
			
		||||
      printf "%s" "$_str_c"
 | 
			
		||||
      ;;
 | 
			
		||||
    *)
 | 
			
		||||
      printf "%%%02X" "'$_str_c"
 | 
			
		||||
      ;;
 | 
			
		||||
    esac
 | 
			
		||||
    _u_i="$(_math "$_u_i" + 1)"
 | 
			
		||||
  done
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_ali_nonce() {
 | 
			
		||||
  #_head_n 1 </dev/urandom | _digest "sha256" hex | cut -c 1-31
 | 
			
		||||
  #Not so good...
 | 
			
		||||
  date +"%s%N"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_check_exist_query() {
 | 
			
		||||
  query=''
 | 
			
		||||
  query=$query'AccessKeyId='$Ali_Key
 | 
			
		||||
  query=$query'&Action=DescribeDomainRecords'
 | 
			
		||||
  query=$query'&DomainName='$1
 | 
			
		||||
  query=$query'&Format=json'
 | 
			
		||||
  query=$query'&RRKeyWord=_acme-challenge'
 | 
			
		||||
  query=$query'&SignatureMethod=HMAC-SHA1'
 | 
			
		||||
  query=$query"&SignatureNonce=$(_ali_nonce)"
 | 
			
		||||
  query=$query'&SignatureVersion=1.0'
 | 
			
		||||
  query=$query'&Timestamp='$(_timestamp)
 | 
			
		||||
  query=$query'&TypeKeyWord=TXT'
 | 
			
		||||
  query=$query'&Version=2015-01-09'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_add_record_query() {
 | 
			
		||||
  query=''
 | 
			
		||||
  query=$query'AccessKeyId='$Ali_Key
 | 
			
		||||
  query=$query'&Action=AddDomainRecord'
 | 
			
		||||
  query=$query'&DomainName='$1
 | 
			
		||||
  query=$query'&Format=json'
 | 
			
		||||
  query=$query'&RR='$2
 | 
			
		||||
  query=$query'&SignatureMethod=HMAC-SHA1'
 | 
			
		||||
  query=$query"&SignatureNonce=$(_ali_nonce)"
 | 
			
		||||
  query=$query'&SignatureVersion=1.0'
 | 
			
		||||
  query=$query'&Timestamp='$(_timestamp)
 | 
			
		||||
  query=$query'&Type=TXT'
 | 
			
		||||
  query=$query'&Value='$3
 | 
			
		||||
  query=$query'&Version=2015-01-09'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_delete_record_query() {
 | 
			
		||||
  query=''
 | 
			
		||||
  query=$query'AccessKeyId='$Ali_Key
 | 
			
		||||
  query=$query'&Action=DeleteDomainRecord'
 | 
			
		||||
  query=$query'&Format=json'
 | 
			
		||||
  query=$query'&RecordId='$1
 | 
			
		||||
  query=$query'&SignatureMethod=HMAC-SHA1'
 | 
			
		||||
  query=$query"&SignatureNonce=$(_ali_nonce)"
 | 
			
		||||
  query=$query'&SignatureVersion=1.0'
 | 
			
		||||
  query=$query'&Timestamp='$(_timestamp)
 | 
			
		||||
  query=$query'&Version=2015-01-09'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_describe_records_query() {
 | 
			
		||||
  query=''
 | 
			
		||||
  query=$query'AccessKeyId='$Ali_Key
 | 
			
		||||
  query=$query'&Action=DescribeDomainRecords'
 | 
			
		||||
  query=$query'&DomainName='$1
 | 
			
		||||
  query=$query'&Format=json'
 | 
			
		||||
  query=$query'&SignatureMethod=HMAC-SHA1'
 | 
			
		||||
  query=$query"&SignatureNonce=$(_ali_nonce)"
 | 
			
		||||
  query=$query'&SignatureVersion=1.0'
 | 
			
		||||
  query=$query'&Timestamp='$(_timestamp)
 | 
			
		||||
  query=$query'&Version=2015-01-09'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_clean() {
 | 
			
		||||
  _check_exist_query "$_domain"
 | 
			
		||||
  if ! _ali_rest "Check exist records" "ignore"; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  records="$(echo "$response" -n | _egrep_o "\"RecordId\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")"
 | 
			
		||||
  printf "%s" "$records" \
 | 
			
		||||
    | while read -r record_id; do
 | 
			
		||||
      _delete_record_query "$record_id"
 | 
			
		||||
      _ali_rest "Delete record $record_id" "ignore"
 | 
			
		||||
    done
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_timestamp() {
 | 
			
		||||
  date -u +"%Y-%m-%dT%H%%3A%M%%3A%SZ"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										243
									
								
								dnsapi/dns_aws.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										243
									
								
								dnsapi/dns_aws.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,243 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
#AWS_ACCESS_KEY_ID="sdfsdfsdfljlbjkljlkjsdfoiwje"
 | 
			
		||||
#
 | 
			
		||||
#AWS_SECRET_ACCESS_KEY="xxxxxxx"
 | 
			
		||||
 | 
			
		||||
#This is the Amazon Route53 api wrapper for acme.sh
 | 
			
		||||
 | 
			
		||||
AWS_HOST="route53.amazonaws.com"
 | 
			
		||||
AWS_URL="https://$AWS_HOST"
 | 
			
		||||
 | 
			
		||||
AWS_WIKI="https://github.com/Neilpang/acme.sh/wiki/How-to-use-Amazon-Route53-API"
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: dns_myapi_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_aws_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then
 | 
			
		||||
    AWS_ACCESS_KEY_ID=""
 | 
			
		||||
    AWS_SECRET_ACCESS_KEY=""
 | 
			
		||||
    _err "You don't specify aws route53 api key id and and api key secret yet."
 | 
			
		||||
    _err "Please create you key and try again. see $(__green $AWS_WIKI)"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "$AWS_SESSION_TOKEN" ]; then
 | 
			
		||||
    _saveaccountconf AWS_ACCESS_KEY_ID "$AWS_ACCESS_KEY_ID"
 | 
			
		||||
    _saveaccountconf AWS_SECRET_ACCESS_KEY "$AWS_SECRET_ACCESS_KEY"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "invalid domain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug _domain_id "$_domain_id"
 | 
			
		||||
  _debug _sub_domain "$_sub_domain"
 | 
			
		||||
  _debug _domain "$_domain"
 | 
			
		||||
 | 
			
		||||
  _aws_tmpl_xml="<ChangeResourceRecordSetsRequest xmlns=\"https://route53.amazonaws.com/doc/2013-04-01/\"><ChangeBatch><Changes><Change><Action>UPSERT</Action><ResourceRecordSet><Name>$fulldomain</Name><Type>TXT</Type><TTL>300</TTL><ResourceRecords><ResourceRecord><Value>\"$txtvalue\"</Value></ResourceRecord></ResourceRecords></ResourceRecordSet></Change></Changes></ChangeBatch></ChangeResourceRecordSetsRequest>"
 | 
			
		||||
 | 
			
		||||
  if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then
 | 
			
		||||
    _info "txt record updated success."
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#fulldomain txtvalue
 | 
			
		||||
dns_aws_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"
 | 
			
		||||
 | 
			
		||||
  _aws_tmpl_xml="<ChangeResourceRecordSetsRequest xmlns=\"https://route53.amazonaws.com/doc/2013-04-01/\"><ChangeBatch><Changes><Change><Action>DELETE</Action><ResourceRecordSet><ResourceRecords><ResourceRecord><Value>\"$txtvalue\"</Value></ResourceRecord></ResourceRecords><Name>$fulldomain.</Name><Type>TXT</Type><TTL>300</TTL></ResourceRecordSet></Change></Changes></ChangeBatch></ChangeResourceRecordSetsRequest>"
 | 
			
		||||
 | 
			
		||||
  if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then
 | 
			
		||||
    _info "txt record deleted success."
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  return 1
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
 | 
			
		||||
_get_root() {
 | 
			
		||||
  domain=$1
 | 
			
		||||
  i=2
 | 
			
		||||
  p=1
 | 
			
		||||
 | 
			
		||||
  if aws_rest GET "2013-04-01/hostedzone"; then
 | 
			
		||||
    _debug "response" "$response"
 | 
			
		||||
    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>.*<PrivateZone>false<.PrivateZone>.*<.HostedZone>")"
 | 
			
		||||
        _debug hostedzone "$hostedzone"
 | 
			
		||||
        if [ -z "$hostedzone" ]; then
 | 
			
		||||
          _err "Error, can not get hostedzone."
 | 
			
		||||
          return 1
 | 
			
		||||
        fi
 | 
			
		||||
        _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "<Id>.*<.Id>" | head -n 1 | _egrep_o ">.*<" | tr -d "<>")
 | 
			
		||||
        if [ "$_domain_id" ]; then
 | 
			
		||||
          _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
 | 
			
		||||
          _domain=$h
 | 
			
		||||
          return 0
 | 
			
		||||
        fi
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
      p=$i
 | 
			
		||||
      i=$(_math "$i" + 1)
 | 
			
		||||
    done
 | 
			
		||||
  fi
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#method uri qstr data
 | 
			
		||||
aws_rest() {
 | 
			
		||||
  mtd="$1"
 | 
			
		||||
  ep="$2"
 | 
			
		||||
  qsr="$3"
 | 
			
		||||
  data="$4"
 | 
			
		||||
 | 
			
		||||
  _debug mtd "$mtd"
 | 
			
		||||
  _debug ep "$ep"
 | 
			
		||||
  _debug qsr "$qsr"
 | 
			
		||||
  _debug data "$data"
 | 
			
		||||
 | 
			
		||||
  CanonicalURI="/$ep"
 | 
			
		||||
  _debug2 CanonicalURI "$CanonicalURI"
 | 
			
		||||
 | 
			
		||||
  CanonicalQueryString="$qsr"
 | 
			
		||||
  _debug2 CanonicalQueryString "$CanonicalQueryString"
 | 
			
		||||
 | 
			
		||||
  RequestDate="$(date -u +"%Y%m%dT%H%M%SZ")"
 | 
			
		||||
  _debug2 RequestDate "$RequestDate"
 | 
			
		||||
 | 
			
		||||
  #RequestDate="20161120T141056Z" ##############
 | 
			
		||||
 | 
			
		||||
  export _H1="x-amz-date: $RequestDate"
 | 
			
		||||
 | 
			
		||||
  aws_host="$AWS_HOST"
 | 
			
		||||
  CanonicalHeaders="host:$aws_host\nx-amz-date:$RequestDate\n"
 | 
			
		||||
  SignedHeaders="host;x-amz-date"
 | 
			
		||||
  if [ -n "$AWS_SESSION_TOKEN" ]; then
 | 
			
		||||
    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
 | 
			
		||||
  _debug2 CanonicalHeaders "$CanonicalHeaders"
 | 
			
		||||
  _debug2 SignedHeaders "$SignedHeaders"
 | 
			
		||||
 | 
			
		||||
  RequestPayload="$data"
 | 
			
		||||
  _debug2 RequestPayload "$RequestPayload"
 | 
			
		||||
 | 
			
		||||
  Hash="sha256"
 | 
			
		||||
 | 
			
		||||
  CanonicalRequest="$mtd\n$CanonicalURI\n$CanonicalQueryString\n$CanonicalHeaders\n$SignedHeaders\n$(printf "%s" "$RequestPayload" | _digest "$Hash" hex)"
 | 
			
		||||
  _debug2 CanonicalRequest "$CanonicalRequest"
 | 
			
		||||
 | 
			
		||||
  HashedCanonicalRequest="$(printf "$CanonicalRequest%s" | _digest "$Hash" hex)"
 | 
			
		||||
  _debug2 HashedCanonicalRequest "$HashedCanonicalRequest"
 | 
			
		||||
 | 
			
		||||
  Algorithm="AWS4-HMAC-SHA256"
 | 
			
		||||
  _debug2 Algorithm "$Algorithm"
 | 
			
		||||
 | 
			
		||||
  RequestDateOnly="$(echo "$RequestDate" | cut -c 1-8)"
 | 
			
		||||
  _debug2 RequestDateOnly "$RequestDateOnly"
 | 
			
		||||
 | 
			
		||||
  Region="us-east-1"
 | 
			
		||||
  Service="route53"
 | 
			
		||||
 | 
			
		||||
  CredentialScope="$RequestDateOnly/$Region/$Service/aws4_request"
 | 
			
		||||
  _debug2 CredentialScope "$CredentialScope"
 | 
			
		||||
 | 
			
		||||
  StringToSign="$Algorithm\n$RequestDate\n$CredentialScope\n$HashedCanonicalRequest"
 | 
			
		||||
 | 
			
		||||
  _debug2 StringToSign "$StringToSign"
 | 
			
		||||
 | 
			
		||||
  kSecret="AWS4$AWS_SECRET_ACCESS_KEY"
 | 
			
		||||
 | 
			
		||||
  #kSecret="wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" ############################
 | 
			
		||||
 | 
			
		||||
  _secure_debug2 kSecret "$kSecret"
 | 
			
		||||
 | 
			
		||||
  kSecretH="$(printf "%s" "$kSecret" | _hex_dump | tr -d " ")"
 | 
			
		||||
  _secure_debug2 kSecretH "$kSecretH"
 | 
			
		||||
 | 
			
		||||
  kDateH="$(printf "$RequestDateOnly%s" | _hmac "$Hash" "$kSecretH" hex)"
 | 
			
		||||
  _debug2 kDateH "$kDateH"
 | 
			
		||||
 | 
			
		||||
  kRegionH="$(printf "$Region%s" | _hmac "$Hash" "$kDateH" hex)"
 | 
			
		||||
  _debug2 kRegionH "$kRegionH"
 | 
			
		||||
 | 
			
		||||
  kServiceH="$(printf "$Service%s" | _hmac "$Hash" "$kRegionH" hex)"
 | 
			
		||||
  _debug2 kServiceH "$kServiceH"
 | 
			
		||||
 | 
			
		||||
  kSigningH="$(printf "aws4_request%s" | _hmac "$Hash" "$kServiceH" hex)"
 | 
			
		||||
  _debug2 kSigningH "$kSigningH"
 | 
			
		||||
 | 
			
		||||
  signature="$(printf "$StringToSign%s" | _hmac "$Hash" "$kSigningH" hex)"
 | 
			
		||||
  _debug2 signature "$signature"
 | 
			
		||||
 | 
			
		||||
  Authorization="$Algorithm Credential=$AWS_ACCESS_KEY_ID/$CredentialScope, SignedHeaders=$SignedHeaders, Signature=$signature"
 | 
			
		||||
  _debug2 Authorization "$Authorization"
 | 
			
		||||
 | 
			
		||||
  _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")"
 | 
			
		||||
  else
 | 
			
		||||
    response="$(_post "$data" "$url")"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _ret="$?"
 | 
			
		||||
  if [ "$_ret" = "0" ]; then
 | 
			
		||||
    if _contains "$response" "<ErrorResponse"; then
 | 
			
		||||
      _err "Response error:$response"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  return "$_ret"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										163
									
								
								dnsapi/dns_cf.sh
									
									
									
									
									
								
							
							
						
						
									
										163
									
								
								dnsapi/dns_cf.sh
									
									
									
									
									
								
							@@ -1,57 +1,63 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
#CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
 | 
			
		||||
#
 | 
			
		||||
#CF_Email="xxxx@sss.com"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
CF_Api="https://api.cloudflare.com/client/v4"
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: add  _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_cf_add(){
 | 
			
		||||
dns_cf_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
  
 | 
			
		||||
  if [ -z "$CF_Key" ] || [ -z "$CF_Email" ] ; then
 | 
			
		||||
 | 
			
		||||
  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
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  if ! _contains "$CF_Email" "@"; then
 | 
			
		||||
    _err "It seems that the CF_Email=$CF_Email is not a valid email address."
 | 
			
		||||
    _err "Please check and retry."
 | 
			
		||||
    return 1
 | 
			
		||||
  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
 | 
			
		||||
  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"
 | 
			
		||||
  _cf_rest GET "zones/${_domain_id}/dns_records?type=TXT&name=$fulldomain"
 | 
			
		||||
  
 | 
			
		||||
  if ! printf "$response" | grep \"success\":true > /dev/null ; then
 | 
			
		||||
 | 
			
		||||
  if ! printf "%s" "$response" | grep \"success\":true >/dev/null; then
 | 
			
		||||
    _err "Error"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
  count=$(printf "%s\n" "$response" | _egrep_o \"count\":[^,]* | cut -d : -f 2)
 | 
			
		||||
 | 
			
		||||
  count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2)
 | 
			
		||||
  _debug count "$count"
 | 
			
		||||
  if [ "$count" = "0" ] ; then
 | 
			
		||||
  if [ "$count" = "0" ]; then
 | 
			
		||||
    _info "Adding record"
 | 
			
		||||
    if _cf_rest POST "zones/$_domain_id/dns_records"  "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then
 | 
			
		||||
      if printf -- "%s" "$response" | grep $fulldomain > /dev/null ; then
 | 
			
		||||
        _info "Added, sleeping 10 seconds"
 | 
			
		||||
        sleep 10
 | 
			
		||||
        #todo: check if the record takes effect
 | 
			
		||||
    if _cf_rest POST "zones/$_domain_id/dns_records" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then
 | 
			
		||||
      if printf -- "%s" "$response" | grep "$fulldomain" >/dev/null; then
 | 
			
		||||
        _info "Added, OK"
 | 
			
		||||
        return 0
 | 
			
		||||
      else
 | 
			
		||||
        _err "Add txt record error."
 | 
			
		||||
@@ -61,27 +67,73 @@ dns_cf_add(){
 | 
			
		||||
    _err "Add txt record error."
 | 
			
		||||
  else
 | 
			
		||||
    _info "Updating record"
 | 
			
		||||
    record_id=$(printf "%s\n" "$response" | _egrep_o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \"| head -n 1)
 | 
			
		||||
    _debug "record_id" $record_id
 | 
			
		||||
    
 | 
			
		||||
    _cf_rest PUT "zones/$_domain_id/dns_records/$record_id"  "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}"
 | 
			
		||||
    record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1)
 | 
			
		||||
    _debug "record_id" "$record_id"
 | 
			
		||||
 | 
			
		||||
    _cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}"
 | 
			
		||||
    if [ "$?" = "0" ]; then
 | 
			
		||||
      _info "Updated, sleeping 10 seconds"
 | 
			
		||||
      sleep 10
 | 
			
		||||
      #todo: check if the record takes effect
 | 
			
		||||
      return 0;
 | 
			
		||||
      _info "Updated, OK"
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
    _err "Update error"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#fulldomain txtvalue
 | 
			
		||||
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"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug _domain_id "$_domain_id"
 | 
			
		||||
  _debug _sub_domain "$_sub_domain"
 | 
			
		||||
  _debug _domain "$_domain"
 | 
			
		||||
 | 
			
		||||
  _debug "Getting txt records"
 | 
			
		||||
  _cf_rest GET "zones/${_domain_id}/dns_records?type=TXT&name=$fulldomain&content=$txtvalue"
 | 
			
		||||
 | 
			
		||||
####################  Private functions bellow ##################################
 | 
			
		||||
  if ! printf "%s" "$response" | grep \"success\":true >/dev/null; then
 | 
			
		||||
    _err "Error"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2)
 | 
			
		||||
  _debug count "$count"
 | 
			
		||||
  if [ "$count" = "0" ]; then
 | 
			
		||||
    _info "Don't need to remove."
 | 
			
		||||
  else
 | 
			
		||||
    record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1)
 | 
			
		||||
    _debug "record_id" "$record_id"
 | 
			
		||||
    if [ -z "$record_id" ]; then
 | 
			
		||||
      _err "Can not get record id to remove."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    if ! _cf_rest DELETE "zones/$_domain_id/dns_records/$record_id"; then
 | 
			
		||||
      _err "Delete record error."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    _contains "$response" '"success":true'
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
#_acme-challenge.www.domain.com
 | 
			
		||||
#returns
 | 
			
		||||
# _sub_domain=_acme-challenge.www
 | 
			
		||||
@@ -91,28 +143,29 @@ _get_root() {
 | 
			
		||||
  domain=$1
 | 
			
		||||
  i=2
 | 
			
		||||
  p=1
 | 
			
		||||
  while [ '1' ] ; do
 | 
			
		||||
    h=$(printf $domain | cut -d . -f $i-100)
 | 
			
		||||
    if [ -z "$h" ] ; then
 | 
			
		||||
  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 ! _cf_rest GET "zones?name=$h" ; then
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
    if printf $response | grep \"name\":\"$h\" >/dev/null ; then
 | 
			
		||||
      _domain_id=$(printf "%s\n" "$response" | _egrep_o \"id\":\"[^\"]*\" | head -n 1 | cut -d : -f 2 | tr -d \")
 | 
			
		||||
      if [ "$_domain_id" ] ; then
 | 
			
		||||
        _sub_domain=$(printf $domain | cut -d . -f 1-$p)
 | 
			
		||||
 | 
			
		||||
    if ! _cf_rest GET "zones?name=$h"; then
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
 | 
			
		||||
      _domain_id=$(printf "%s\n" "$response" | _egrep_o "\[.\"id\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \")
 | 
			
		||||
      if [ "$_domain_id" ]; then
 | 
			
		||||
        _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
 | 
			
		||||
        _domain=$h
 | 
			
		||||
        return 0
 | 
			
		||||
      fi
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    p=$i
 | 
			
		||||
    i=$(expr $i + 1)
 | 
			
		||||
    i=$(_math "$i" + 1)
 | 
			
		||||
  done
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
@@ -121,25 +174,23 @@ _cf_rest() {
 | 
			
		||||
  m=$1
 | 
			
		||||
  ep="$2"
 | 
			
		||||
  data="$3"
 | 
			
		||||
  _debug $ep
 | 
			
		||||
  
 | 
			
		||||
  _H1="X-Auth-Email: $CF_Email"
 | 
			
		||||
  _H2="X-Auth-Key: $CF_Key"
 | 
			
		||||
  _H3="Content-Type: application/json"
 | 
			
		||||
  
 | 
			
		||||
  if [ "$data" ] ; then
 | 
			
		||||
  _debug "$ep"
 | 
			
		||||
 | 
			
		||||
  export _H1="X-Auth-Email: $CF_Email"
 | 
			
		||||
  export _H2="X-Auth-Key: $CF_Key"
 | 
			
		||||
  export _H3="Content-Type: application/json"
 | 
			
		||||
 | 
			
		||||
  if [ "$m" != "GET" ]; then
 | 
			
		||||
    _debug data "$data"
 | 
			
		||||
    response="$(_post "$data" "$CF_Api/$ep" "" $m)"
 | 
			
		||||
    response="$(_post "$data" "$CF_Api/$ep" "" "$m")"
 | 
			
		||||
  else
 | 
			
		||||
    response="$(_get "$CF_Api/$ep")"
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
  if [ "$?" != "0" ] ; then
 | 
			
		||||
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "error $ep"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										164
									
								
								dnsapi/dns_cx.sh
									
									
									
									
									
								
							
							
						
						
									
										164
									
								
								dnsapi/dns_cx.sh
									
									
									
									
									
								
							@@ -6,10 +6,8 @@
 | 
			
		||||
#
 | 
			
		||||
#CX_Secret="sADDsdasdgdsf"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
CX_Api="https://www.cloudxns.net/api2"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#REST_API
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
@@ -17,45 +15,60 @@ CX_Api="https://www.cloudxns.net/api2"
 | 
			
		||||
dns_cx_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
  
 | 
			
		||||
  if [ -z "$CX_Key" ] || [ -z "$CX_Secret" ] ; then
 | 
			
		||||
 | 
			
		||||
  if [ -z "$CX_Key" ] || [ -z "$CX_Secret" ]; then
 | 
			
		||||
    CX_Key=""
 | 
			
		||||
    CX_Secret=""
 | 
			
		||||
    _err "You don't specify cloudxns.com  api key or secret yet."
 | 
			
		||||
    _err "Please create you key and try again."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
  REST_API=$CX_Api
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  REST_API="$CX_Api"
 | 
			
		||||
 | 
			
		||||
  #save the api key and email to the account conf file.
 | 
			
		||||
  _saveaccountconf CX_Key "$CX_Key"
 | 
			
		||||
  _saveaccountconf CX_Secret "$CX_Secret"
 | 
			
		||||
  
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root $fulldomain ; then
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "invalid domain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
  existing_records  $_domain  $_sub_domain
 | 
			
		||||
 | 
			
		||||
  existing_records "$_domain" "$_sub_domain"
 | 
			
		||||
  _debug count "$count"
 | 
			
		||||
  if [ "$?" != "0" ] ; then
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "Error get existing records."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ "$count" = "0" ] ; then
 | 
			
		||||
    add_record $_domain $_sub_domain $txtvalue
 | 
			
		||||
  if [ "$count" = "0" ]; then
 | 
			
		||||
    add_record "$_domain" "$_sub_domain" "$txtvalue"
 | 
			
		||||
  else
 | 
			
		||||
    update_record $_domain $_sub_domain $txtvalue
 | 
			
		||||
    update_record "$_domain" "$_sub_domain" "$txtvalue"
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
  if [ "$?" = "0" ] ; then
 | 
			
		||||
 | 
			
		||||
  if [ "$?" = "0" ]; then
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#fulldomain
 | 
			
		||||
dns_cx_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  REST_API="$CX_Api"
 | 
			
		||||
  if _get_root "$fulldomain"; then
 | 
			
		||||
    record_id=""
 | 
			
		||||
    existing_records "$_domain" "$_sub_domain"
 | 
			
		||||
    if ! [ "$record_id" = "" ]; then
 | 
			
		||||
      _rest DELETE "record/$record_id/$_domain_id" "{}"
 | 
			
		||||
      _info "Deleted record ${fulldomain}"
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#usage:  root  sub
 | 
			
		||||
#return if the sub record already exists.
 | 
			
		||||
#echos the existing records count.
 | 
			
		||||
@@ -64,24 +77,24 @@ existing_records() {
 | 
			
		||||
  _debug "Getting txt records"
 | 
			
		||||
  root=$1
 | 
			
		||||
  sub=$2
 | 
			
		||||
  
 | 
			
		||||
  if ! _rest GET "record/$_domain_id?:domain_id?host_id=0&offset=0&row_num=100" ; then
 | 
			
		||||
  count=0
 | 
			
		||||
  if ! _rest GET "record/$_domain_id?:domain_id?host_id=0&offset=0&row_num=100"; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  count=0
 | 
			
		||||
  seg=$(printf "%s\n" "$response" | _egrep_o "{[^\{]*host\":\"$_sub_domain\"[^\}]*\}")
 | 
			
		||||
 | 
			
		||||
  seg=$(printf "%s\n" "$response" | _egrep_o '"record_id":[^{]*host":"'"$_sub_domain"'"[^}]*\}')
 | 
			
		||||
  _debug seg "$seg"
 | 
			
		||||
  if [ -z "$seg" ] ; then
 | 
			
		||||
  if [ -z "$seg" ]; then
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if printf "$response" | grep '"type":"TXT"' > /dev/null ; then
 | 
			
		||||
  if printf "%s" "$response" | grep '"type":"TXT"' >/dev/null; then
 | 
			
		||||
    count=1
 | 
			
		||||
    record_id=$(printf "%s\n" "$seg" | _egrep_o \"record_id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \")
 | 
			
		||||
    record_id=$(printf "%s\n" "$seg" | _egrep_o '"record_id":"[^"]*"' | cut -d : -f 2 | tr -d \" | _head_n 1)
 | 
			
		||||
    _debug record_id "$record_id"
 | 
			
		||||
    return 0    
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#add the txt record.
 | 
			
		||||
@@ -90,14 +103,14 @@ add_record() {
 | 
			
		||||
  root=$1
 | 
			
		||||
  sub=$2
 | 
			
		||||
  txtvalue=$3
 | 
			
		||||
  fulldomain=$sub.$root
 | 
			
		||||
  
 | 
			
		||||
  fulldomain="$sub.$root"
 | 
			
		||||
 | 
			
		||||
  _info "Adding record"
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  if ! _rest POST "record" "{\"domain_id\": $_domain_id, \"host\":\"$_sub_domain\", \"value\":\"$txtvalue\", \"type\":\"TXT\",\"ttl\":600, \"line_id\":1}"; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -107,21 +120,18 @@ update_record() {
 | 
			
		||||
  root=$1
 | 
			
		||||
  sub=$2
 | 
			
		||||
  txtvalue=$3
 | 
			
		||||
  fulldomain=$sub.$root
 | 
			
		||||
  
 | 
			
		||||
  fulldomain="$sub.$root"
 | 
			
		||||
 | 
			
		||||
  _info "Updating record"
 | 
			
		||||
  
 | 
			
		||||
  if _rest PUT "record/$record_id" "{\"domain_id\": $_domain_id, \"host\":\"$_sub_domain\", \"value\":\"$txtvalue\", \"type\":\"TXT\",\"ttl\":600, \"line_id\":1}" ; then
 | 
			
		||||
 | 
			
		||||
  if _rest PUT "record/$record_id" "{\"domain_id\": $_domain_id, \"host\":\"$_sub_domain\", \"value\":\"$txtvalue\", \"type\":\"TXT\",\"ttl\":600, \"line_id\":1}"; then
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
####################  Private functions bellow ##################################
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
#_acme-challenge.www.domain.com
 | 
			
		||||
#returns
 | 
			
		||||
# _sub_domain=_acme-challenge.www
 | 
			
		||||
@@ -131,79 +141,75 @@ _get_root() {
 | 
			
		||||
  domain=$1
 | 
			
		||||
  i=2
 | 
			
		||||
  p=1
 | 
			
		||||
  
 | 
			
		||||
  if ! _rest GET "domain" ; then
 | 
			
		||||
 | 
			
		||||
  if ! _rest GET "domain"; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
  while [ '1' ] ; do
 | 
			
		||||
    h=$(printf $domain | cut -d . -f $i-100)
 | 
			
		||||
 | 
			
		||||
  while true; do
 | 
			
		||||
    h=$(printf "%s" "$domain" | cut -d . -f $i-100)
 | 
			
		||||
    _debug h "$h"
 | 
			
		||||
    if [ -z "$h" ] ; then
 | 
			
		||||
    if [ -z "$h" ]; then
 | 
			
		||||
      #not valid
 | 
			
		||||
      return 1;
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if printf "$response" | grep "$h." >/dev/null ; then
 | 
			
		||||
      seg=$(printf "%s" "$response" | _egrep_o "\{[^\{]*\"$h\.\"[^\}]*\}" )
 | 
			
		||||
    if _contains "$response" "$h."; then
 | 
			
		||||
      seg=$(printf "%s\n" "$response" | _egrep_o '"id":[^{]*"'"$h"'."[^}]*}')
 | 
			
		||||
      _debug seg "$seg"
 | 
			
		||||
      _domain_id=$(printf "%s" "$seg" | _egrep_o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \")
 | 
			
		||||
      _domain_id=$(printf "%s\n" "$seg" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")
 | 
			
		||||
      _debug _domain_id "$_domain_id"
 | 
			
		||||
      if [ "$_domain_id" ] ; then
 | 
			
		||||
        _sub_domain=$(printf $domain | cut -d . -f 1-$p)
 | 
			
		||||
        _debug _sub_domain $_sub_domain
 | 
			
		||||
        _domain=$h
 | 
			
		||||
        _debug _domain $_domain
 | 
			
		||||
      if [ "$_domain_id" ]; then
 | 
			
		||||
        _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
 | 
			
		||||
        _debug _sub_domain "$_sub_domain"
 | 
			
		||||
        _domain="$h"
 | 
			
		||||
        _debug _domain "$_domain"
 | 
			
		||||
        return 0
 | 
			
		||||
      fi
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    p=$i
 | 
			
		||||
    i=$(expr $i + 1)
 | 
			
		||||
    p="$i"
 | 
			
		||||
    i=$(_math "$i" + 1)
 | 
			
		||||
  done
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#Usage: method  URI  data
 | 
			
		||||
_rest() {
 | 
			
		||||
  m=$1
 | 
			
		||||
  ep="$2"
 | 
			
		||||
  _debug $ep
 | 
			
		||||
  _debug ep "$ep"
 | 
			
		||||
  url="$REST_API/$ep"
 | 
			
		||||
  _debug url "$url"
 | 
			
		||||
  
 | 
			
		||||
  cdate=$(date -u  "+%Y-%m-%d %H:%M:%S UTC")
 | 
			
		||||
 | 
			
		||||
  cdate=$(date -u "+%Y-%m-%d %H:%M:%S UTC")
 | 
			
		||||
  _debug cdate "$cdate"
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  data="$3"
 | 
			
		||||
  _debug data "$data"
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
  sec="$CX_Key$url$data$cdate$CX_Secret"
 | 
			
		||||
  _debug sec "$sec"
 | 
			
		||||
  hmac=$(printf "$sec"| openssl md5 |cut -d " " -f 2)
 | 
			
		||||
  hmac=$(printf "%s" "$sec" | _digest md5 hex)
 | 
			
		||||
  _debug hmac "$hmac"
 | 
			
		||||
  
 | 
			
		||||
  _H1="API-KEY: $CX_Key"
 | 
			
		||||
  _H2="API-REQUEST-DATE: $cdate"
 | 
			
		||||
  _H3="API-HMAC: $hmac"
 | 
			
		||||
  _H4="Content-Type: application/json"
 | 
			
		||||
 | 
			
		||||
  if [ "$data" ] ; then
 | 
			
		||||
    response="$(_post "$data" "$url" "" $m)"
 | 
			
		||||
  export _H1="API-KEY: $CX_Key"
 | 
			
		||||
  export _H2="API-REQUEST-DATE: $cdate"
 | 
			
		||||
  export _H3="API-HMAC: $hmac"
 | 
			
		||||
  export _H4="Content-Type: application/json"
 | 
			
		||||
 | 
			
		||||
  if [ "$data" ]; then
 | 
			
		||||
    response="$(_post "$data" "$url" "" "$m")"
 | 
			
		||||
  else
 | 
			
		||||
    response="$(_get "$url")"
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
  if [ "$?" != "0" ] ; then
 | 
			
		||||
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "error $ep"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
  if ! printf "$response" | grep '"message":"success"' > /dev/null ; 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'
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										181
									
								
								dnsapi/dns_dp.sh
									
									
									
									
									
								
							
							
						
						
									
										181
									
								
								dnsapi/dns_dp.sh
									
									
									
									
									
								
							@@ -6,51 +6,83 @@
 | 
			
		||||
#
 | 
			
		||||
#DP_Key="sADDsdasdgdsf"
 | 
			
		||||
 | 
			
		||||
REST_API="https://dnsapi.cn"
 | 
			
		||||
 | 
			
		||||
DP_Api="https://dnsapi.cn"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#REST_API
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: add  _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_dp_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
  
 | 
			
		||||
  if [ -z "$DP_Id" ] || [ -z "$DP_Key" ] ; then
 | 
			
		||||
 | 
			
		||||
  if [ -z "$DP_Id" ] || [ -z "$DP_Key" ]; then
 | 
			
		||||
    DP_Id=""
 | 
			
		||||
    DP_Key=""
 | 
			
		||||
    _err "You don't specify dnspod api key and key id yet."
 | 
			
		||||
    _err "Please create you key and try again."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
  REST_API=$DP_Api
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  #save the api key and email to the account conf file.
 | 
			
		||||
  _saveaccountconf DP_Id "$DP_Id"
 | 
			
		||||
  _saveaccountconf DP_Key "$DP_Key"
 | 
			
		||||
  
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root $fulldomain ; then
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "invalid domain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
  existing_records  $_domain  $_sub_domain
 | 
			
		||||
 | 
			
		||||
  existing_records "$_domain" "$_sub_domain"
 | 
			
		||||
  _debug count "$count"
 | 
			
		||||
  if [ "$?" != "0" ] ; then
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "Error get existing records."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ "$count" = "0" ] ; then
 | 
			
		||||
    add_record $_domain $_sub_domain $txtvalue
 | 
			
		||||
  if [ "$count" = "0" ]; then
 | 
			
		||||
    add_record "$_domain" "$_sub_domain" "$txtvalue"
 | 
			
		||||
  else
 | 
			
		||||
    update_record $_domain $_sub_domain $txtvalue
 | 
			
		||||
    update_record "$_domain" "$_sub_domain" "$txtvalue"
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#fulldomain txtvalue
 | 
			
		||||
dns_dp_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "invalid domain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! _rest POST "Record.List" "login_token=$DP_Id,$DP_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain"; then
 | 
			
		||||
    _err "Record.Lis error."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if _contains "$response" 'No records'; then
 | 
			
		||||
    _info "Don't need to remove."
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  record_id=$(echo "$response" | _egrep_o '{[^{]*"value":"'"$txtvalue"'"' | cut -d , -f 1 | cut -d : -f 2 | tr -d \")
 | 
			
		||||
  _debug record_id "$record_id"
 | 
			
		||||
  if [ -z "$record_id" ]; then
 | 
			
		||||
    _err "Can not get record id."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! _rest POST "Record.Remove" "login_token=$DP_Id,$DP_Key&format=json&domain_id=$_domain_id&record_id=$record_id"; then
 | 
			
		||||
    _err "Record.Remove error."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _contains "$response" "Action completed successful"
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#usage:  root  sub
 | 
			
		||||
#return if the sub record already exists.
 | 
			
		||||
#echos the existing records count.
 | 
			
		||||
@@ -59,26 +91,26 @@ existing_records() {
 | 
			
		||||
  _debug "Getting txt records"
 | 
			
		||||
  root=$1
 | 
			
		||||
  sub=$2
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  if ! _rest POST "Record.List" "login_token=$DP_Id,$DP_Key&domain_id=$_domain_id&sub_domain=$_sub_domain"; then
 | 
			
		||||
      return 1
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
  if  printf "$response" | grep 'No records' ; then
 | 
			
		||||
      count=0;
 | 
			
		||||
      return 0
 | 
			
		||||
 | 
			
		||||
  if _contains "$response" 'No records'; then
 | 
			
		||||
    count=0
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
    
 | 
			
		||||
  if printf "$response" | grep "Action completed successful" >/dev/null ; then
 | 
			
		||||
    count=$(printf "$response" | grep '<type>TXT</type>' | wc -l)
 | 
			
		||||
    record_id=$(printf "$response" | grep '^<id>' | tail -1 | cut -d '>' -f 2 | cut -d '<' -f 1)
 | 
			
		||||
    return 0    
 | 
			
		||||
 | 
			
		||||
  if _contains "$response" "Action completed successful"; then
 | 
			
		||||
    count=$(printf "%s" "$response" | grep -c '<type>TXT</type>' | tr -d ' ')
 | 
			
		||||
    record_id=$(printf "%s" "$response" | grep '^<id>' | tail -1 | cut -d '>' -f 2 | cut -d '<' -f 1)
 | 
			
		||||
    _debug record_id "$record_id"
 | 
			
		||||
    return 0
 | 
			
		||||
  else
 | 
			
		||||
    _err "get existing records error."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  count=0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -88,20 +120,19 @@ add_record() {
 | 
			
		||||
  root=$1
 | 
			
		||||
  sub=$2
 | 
			
		||||
  txtvalue=$3
 | 
			
		||||
  fulldomain=$sub.$root
 | 
			
		||||
  
 | 
			
		||||
  fulldomain="$sub.$root"
 | 
			
		||||
 | 
			
		||||
  _info "Adding record"
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  if ! _rest POST "Record.Create" "login_token=$DP_Id,$DP_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain&record_type=TXT&value=$txtvalue&record_line=默认"; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
  if printf "$response" | grep "Action completed successful" ; then
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  if _contains "$response" "Action completed successful"; then
 | 
			
		||||
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  return 1 #error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -111,26 +142,23 @@ update_record() {
 | 
			
		||||
  root=$1
 | 
			
		||||
  sub=$2
 | 
			
		||||
  txtvalue=$3
 | 
			
		||||
  fulldomain=$sub.$root
 | 
			
		||||
  
 | 
			
		||||
  fulldomain="$sub.$root"
 | 
			
		||||
 | 
			
		||||
  _info "Updating record"
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  if ! _rest POST "Record.Modify" "login_token=$DP_Id,$DP_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain&record_type=TXT&value=$txtvalue&record_line=默认&record_id=$record_id"; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
  if printf "$response" | grep "Action completed successful" ; then
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  if _contains "$response" "Action completed successful"; then
 | 
			
		||||
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  return 1 #error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
####################  Private functions bellow ##################################
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
#_acme-challenge.www.domain.com
 | 
			
		||||
#returns
 | 
			
		||||
# _sub_domain=_acme-challenge.www
 | 
			
		||||
@@ -140,59 +168,56 @@ _get_root() {
 | 
			
		||||
  domain=$1
 | 
			
		||||
  i=2
 | 
			
		||||
  p=1
 | 
			
		||||
  while [ '1' ] ; do
 | 
			
		||||
    h=$(printf $domain | cut -d . -f $i-100)
 | 
			
		||||
    if [ -z "$h" ] ; then
 | 
			
		||||
  while true; do
 | 
			
		||||
    h=$(printf "%s" "$domain" | cut -d . -f $i-100)
 | 
			
		||||
    if [ -z "$h" ]; then
 | 
			
		||||
      #not valid
 | 
			
		||||
      return 1;
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    if ! _rest POST "Domain.Info" "login_token=$DP_Id,$DP_Key&format=json&domain=$h"; then
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
    if printf "$response" | grep "Action completed successful" >/dev/null ; then
 | 
			
		||||
      _domain_id=$(printf "%s\n" "$response" | _egrep_o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \")
 | 
			
		||||
 | 
			
		||||
    if _contains "$response" "Action completed successful"; then
 | 
			
		||||
      _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")
 | 
			
		||||
      _debug _domain_id "$_domain_id"
 | 
			
		||||
      if [ "$_domain_id" ] ; then
 | 
			
		||||
        _sub_domain=$(printf $domain | cut -d . -f 1-$p)
 | 
			
		||||
        _debug _sub_domain $_sub_domain
 | 
			
		||||
        _domain=$h
 | 
			
		||||
        _debug _domain $_domain
 | 
			
		||||
      if [ "$_domain_id" ]; then
 | 
			
		||||
        _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
 | 
			
		||||
        _debug _sub_domain "$_sub_domain"
 | 
			
		||||
        _domain="$h"
 | 
			
		||||
        _debug _domain "$_domain"
 | 
			
		||||
        return 0
 | 
			
		||||
      fi
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    p=$i
 | 
			
		||||
    i=$(expr $i + 1)
 | 
			
		||||
    p="$i"
 | 
			
		||||
    i=$(_math "$i" + 1)
 | 
			
		||||
  done
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#Usage: method  URI  data
 | 
			
		||||
_rest() {
 | 
			
		||||
  m=$1
 | 
			
		||||
  m="$1"
 | 
			
		||||
  ep="$2"
 | 
			
		||||
  data="$3"
 | 
			
		||||
  _debug $ep
 | 
			
		||||
  _debug "$ep"
 | 
			
		||||
  url="$REST_API/$ep"
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  _debug url "$url"
 | 
			
		||||
  
 | 
			
		||||
  if [ "$data" ] ; then
 | 
			
		||||
    _debug2 data "$data"
 | 
			
		||||
    response="$(_post $data "$url")"
 | 
			
		||||
 | 
			
		||||
  if [ "$m" = "GET" ]; then
 | 
			
		||||
    response="$(_get "$url" | tr -d '\r')"
 | 
			
		||||
  else
 | 
			
		||||
    response="$(_get "$url")"
 | 
			
		||||
    _debug2 data "$data"
 | 
			
		||||
    response="$(_post "$data" "$url" | tr -d '\r')"
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
  if [ "$?" != "0" ] ; then
 | 
			
		||||
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "error $ep"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
  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
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										375
									
								
								dnsapi/dns_freedns.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										375
									
								
								dnsapi/dns_freedns.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,375 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#This file name is "dns_freedns.sh"
 | 
			
		||||
#So, here must be a method dns_freedns_add()
 | 
			
		||||
#Which will be called by acme.sh to add the txt record to your api system.
 | 
			
		||||
#returns 0 means success, otherwise error.
 | 
			
		||||
#
 | 
			
		||||
#Author: David Kerr
 | 
			
		||||
#Report Bugs here: https://github.com/dkerr64/acme.sh
 | 
			
		||||
#
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
# 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
 | 
			
		||||
# need to be set only when changed.
 | 
			
		||||
 | 
			
		||||
#Usage: dns_freedns_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_freedns_add() {
 | 
			
		||||
  fulldomain="$1"
 | 
			
		||||
  txtvalue="$2"
 | 
			
		||||
 | 
			
		||||
  _info "Add TXT record using FreeDNS"
 | 
			
		||||
  _debug "fulldomain: $fulldomain"
 | 
			
		||||
  _debug "txtvalue: $txtvalue"
 | 
			
		||||
 | 
			
		||||
  if [ -z "$FREEDNS_User" ] || [ -z "$FREEDNS_Password" ]; then
 | 
			
		||||
    FREEDNS_User=""
 | 
			
		||||
    FREEDNS_Password=""
 | 
			
		||||
    if [ -z "$FREEDNS_COOKIE" ]; then
 | 
			
		||||
      _err "You did not specify the FreeDNS username and password yet."
 | 
			
		||||
      _err "Please export as FREEDNS_User / FREEDNS_Password and try again."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    using_cached_cookies="true"
 | 
			
		||||
  else
 | 
			
		||||
    FREEDNS_COOKIE="$(_freedns_login "$FREEDNS_User" "$FREEDNS_Password")"
 | 
			
		||||
    if [ -z "$FREEDNS_COOKIE" ]; then
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    using_cached_cookies="false"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug "FreeDNS login cookies: $FREEDNS_COOKIE (cached = $using_cached_cookies)"
 | 
			
		||||
 | 
			
		||||
  _saveaccountconf FREEDNS_COOKIE "$FREEDNS_COOKIE"
 | 
			
		||||
 | 
			
		||||
  # split our full domain name into two parts...
 | 
			
		||||
  i="$(echo "$fulldomain" | tr '.' ' ' | wc -w)"
 | 
			
		||||
  i="$(_math "$i" - 1)"
 | 
			
		||||
  top_domain="$(echo "$fulldomain" | cut -d. -f "$i"-100)"
 | 
			
		||||
  i="$(_math "$i" - 1)"
 | 
			
		||||
  sub_domain="$(echo "$fulldomain" | cut -d. -f -"$i")"
 | 
			
		||||
 | 
			
		||||
  # 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
 | 
			
		||||
  # load the page and obtain our domain ID
 | 
			
		||||
  attempts=2
 | 
			
		||||
  while [ "$attempts" -gt "0" ]; do
 | 
			
		||||
    attempts="$(_math "$attempts" - 1)"
 | 
			
		||||
 | 
			
		||||
    htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")"
 | 
			
		||||
    if [ "$?" != "0" ]; then
 | 
			
		||||
      if [ "$using_cached_cookies" = "true" ]; then
 | 
			
		||||
        _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
 | 
			
		||||
    subdomain_csv="$(echo "$htmlpage" \
 | 
			
		||||
      | grep -i -e '</\?TABLE\|</\?TD\|</\?TR\|</\?TH' \
 | 
			
		||||
      | sed 's/^[\ \t]*//g' \
 | 
			
		||||
      | tr -d '\n' \
 | 
			
		||||
      | sed 's/<\/TR[^>]*>/\n/Ig' \
 | 
			
		||||
      | sed 's/<\/\?\(TABLE\|TR\)[^>]*>//Ig' \
 | 
			
		||||
      | sed 's/^<T[DH][^>]*>\|<\/\?T[DH][^>]*>$//Ig' \
 | 
			
		||||
      | sed 's/<\/T[DH][^>]*><T[DH][^>]*>/,/Ig' \
 | 
			
		||||
      | grep 'edit.php?' \
 | 
			
		||||
      | grep "$top_domain")"
 | 
			
		||||
    # The above beauty ends with striping out rows that do not have an
 | 
			
		||||
    # href to edit.php and do not have the top domain we are looking for.
 | 
			
		||||
    # So all we should be left with is CSV of table of subdomains we are
 | 
			
		||||
    # interested in.
 | 
			
		||||
 | 
			
		||||
    # Now we have to read through this table and extract the data we need
 | 
			
		||||
    lines="$(echo "$subdomain_csv" | wc -l)"
 | 
			
		||||
    nl='
 | 
			
		||||
'
 | 
			
		||||
    i=0
 | 
			
		||||
    found=0
 | 
			
		||||
    while [ "$i" -lt "$lines" ]; do
 | 
			
		||||
      i="$(_math "$i" + 1)"
 | 
			
		||||
      line="$(echo "$subdomain_csv" | cut -d "$nl" -f "$i")"
 | 
			
		||||
      tmp="$(echo "$line" | cut -d ',' -f 1)"
 | 
			
		||||
      if [ $found = 0 ] && _startswith "$tmp" "<td>$top_domain"; then
 | 
			
		||||
        # this line will contain DNSdomainid for the top_domain
 | 
			
		||||
        DNSdomainid="$(echo "$line" | cut -d ',' -f 2 | sed 's/^.*domain_id=//;s/>.*//')"
 | 
			
		||||
        found=1
 | 
			
		||||
      else
 | 
			
		||||
        # lines contain DNS records for all subdomains
 | 
			
		||||
        DNSname="$(echo "$line" | cut -d ',' -f 2 | sed 's/^[^>]*>//;s/<\/a>.*//')"
 | 
			
		||||
        DNStype="$(echo "$line" | cut -d ',' -f 3)"
 | 
			
		||||
        if [ "$DNSname" = "$fulldomain" ] && [ "$DNStype" = "TXT" ]; then
 | 
			
		||||
          DNSdataid="$(echo "$line" | cut -d ',' -f 2 | sed 's/^.*data_id=//;s/>.*//')"
 | 
			
		||||
          # Now get current value for the TXT record.  This method may
 | 
			
		||||
          # 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 challenge subdomain.
 | 
			
		||||
          DNSvalue="$(echo "$line" | cut -d ',' -f 4 | sed 's/^[^"]*"//;s/".*//;s/<\/td>.*//')"
 | 
			
		||||
          if [ $found != 0 ]; then
 | 
			
		||||
            break
 | 
			
		||||
            # we are breaking out of the loop at the first match of DNS name
 | 
			
		||||
            # and DNS type (if we are past finding the domainid). This assumes
 | 
			
		||||
            # that there is only ever one TXT record for the LetsEncrypt/acme
 | 
			
		||||
            # challenge subdomain.  This seems to be a reasonable assumption
 | 
			
		||||
            # as the acme client deletes the TXT record on successful validation.
 | 
			
		||||
          fi
 | 
			
		||||
        else
 | 
			
		||||
          DNSname=""
 | 
			
		||||
          DNStype=""
 | 
			
		||||
        fi
 | 
			
		||||
      fi
 | 
			
		||||
    done
 | 
			
		||||
 | 
			
		||||
    _debug "DNSname: $DNSname DNStype: $DNStype DNSdomainid: $DNSdomainid DNSdataid: $DNSdataid"
 | 
			
		||||
    _debug "DNSvalue: $DNSvalue"
 | 
			
		||||
 | 
			
		||||
    if [ -z "$DNSdomainid" ]; then
 | 
			
		||||
      # If domain ID is empty then something went wrong (top level
 | 
			
		||||
      # domain not found at FreeDNS).
 | 
			
		||||
      if [ "$attempts" = "0" ]; then
 | 
			
		||||
        # exhausted maximum retry attempts
 | 
			
		||||
        _debug "$htmlpage"
 | 
			
		||||
        _debug "$subdomain_csv"
 | 
			
		||||
        _err "Domain $top_domain not found at FreeDNS"
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
    else
 | 
			
		||||
      # break out of the 'retry' loop... we have found our domain ID
 | 
			
		||||
      break
 | 
			
		||||
    fi
 | 
			
		||||
    _info "Domain $top_domain not found at FreeDNS"
 | 
			
		||||
    _info "Retry loading subdomain page ($attempts attempts remaining)"
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  if [ -z "$DNSdataid" ]; then
 | 
			
		||||
    # If data ID is empty then specific subdomain does not exist yet, need
 | 
			
		||||
    # to create it this should always be the case as the acme client
 | 
			
		||||
    # deletes the entry after domain is validated.
 | 
			
		||||
    _freedns_add_txt_record "$FREEDNS_COOKIE" "$DNSdomainid" "$sub_domain" "$txtvalue"
 | 
			
		||||
    return $?
 | 
			
		||||
  else
 | 
			
		||||
    if [ "$txtvalue" = "$DNSvalue" ]; then
 | 
			
		||||
      # if value in TXT record matches value requested then DNS record
 | 
			
		||||
      # does not need to be updated. But...
 | 
			
		||||
      # Testing value match fails.  Website is truncating the value field.
 | 
			
		||||
      # So for now we will always go down the else path.  Though in theory
 | 
			
		||||
      # should never come here anyway as the acme client deletes
 | 
			
		||||
      # the TXT record on successful validation, so we should not even
 | 
			
		||||
      # have found a TXT record !!
 | 
			
		||||
      _info "No update necessary for $fulldomain at FreeDNS"
 | 
			
		||||
      return 0
 | 
			
		||||
    else
 | 
			
		||||
      # Delete the old TXT record (with the wrong value)
 | 
			
		||||
      _freedns_delete_txt_record "$FREEDNS_COOKIE" "$DNSdataid"
 | 
			
		||||
      if [ "$?" = "0" ]; then
 | 
			
		||||
        # And add in new TXT record with the value provided
 | 
			
		||||
        _freedns_add_txt_record "$FREEDNS_COOKIE" "$DNSdomainid" "$sub_domain" "$txtvalue"
 | 
			
		||||
      fi
 | 
			
		||||
      return $?
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#Usage: fulldomain txtvalue
 | 
			
		||||
#Remove the txt record after validation.
 | 
			
		||||
dns_freedns_rm() {
 | 
			
		||||
  fulldomain="$1"
 | 
			
		||||
  txtvalue="$2"
 | 
			
		||||
 | 
			
		||||
  _info "Delete TXT record using FreeDNS"
 | 
			
		||||
  _debug "fulldomain: $fulldomain"
 | 
			
		||||
  _debug "txtvalue: $txtvalue"
 | 
			
		||||
 | 
			
		||||
  # 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() function
 | 
			
		||||
  FREEDNS_COOKIE="$(_read_conf "$ACCOUNT_CONF_PATH" "FREEDNS_COOKIE")"
 | 
			
		||||
  _debug "FreeDNS login cookies: $FREEDNS_COOKIE"
 | 
			
		||||
 | 
			
		||||
  # 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
 | 
			
		||||
  # load the page and obtain our TXT record.
 | 
			
		||||
  attempts=2
 | 
			
		||||
  while [ "$attempts" -gt "0" ]; do
 | 
			
		||||
    attempts="$(_math "$attempts" - 1)"
 | 
			
		||||
 | 
			
		||||
    htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")"
 | 
			
		||||
    if [ "$?" != "0" ]; then
 | 
			
		||||
      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
 | 
			
		||||
    subdomain_csv="$(echo "$htmlpage" \
 | 
			
		||||
      | grep -i -e '</\?TABLE\|</\?TD\|</\?TR\|</\?TH' \
 | 
			
		||||
      | sed 's/^[\ \t]*//g' \
 | 
			
		||||
      | tr -d '\n' \
 | 
			
		||||
      | sed 's/<\/TR[^>]*>/\n/Ig' \
 | 
			
		||||
      | sed 's/<\/\?\(TABLE\|TR\)[^>]*>//Ig' \
 | 
			
		||||
      | sed 's/^<T[DH][^>]*>\|<\/\?T[DH][^>]*>$//Ig' \
 | 
			
		||||
      | sed 's/<\/T[DH][^>]*><T[DH][^>]*>/,/Ig' \
 | 
			
		||||
      | grep 'edit.php?' \
 | 
			
		||||
      | grep "$fulldomain")"
 | 
			
		||||
    # The above beauty ends with striping out rows that do not have an
 | 
			
		||||
    # href to edit.php and do not have the domain name we are looking for.
 | 
			
		||||
    # So all we should be left with is CSV of table of subdomains we are
 | 
			
		||||
    # interested in.
 | 
			
		||||
 | 
			
		||||
    # Now we have to read through this table and extract the data we need
 | 
			
		||||
    lines="$(echo "$subdomain_csv" | wc -l)"
 | 
			
		||||
    nl='
 | 
			
		||||
'
 | 
			
		||||
    i=0
 | 
			
		||||
    found=0
 | 
			
		||||
    while [ "$i" -lt "$lines" ]; do
 | 
			
		||||
      i="$(_math "$i" + 1)"
 | 
			
		||||
      line="$(echo "$subdomain_csv" | cut -d "$nl" -f "$i")"
 | 
			
		||||
      DNSname="$(echo "$line" | cut -d ',' -f 2 | sed 's/^[^>]*>//;s/<\/a>.*//')"
 | 
			
		||||
      DNStype="$(echo "$line" | cut -d ',' -f 3)"
 | 
			
		||||
      if [ "$DNSname" = "$fulldomain" ] && [ "$DNStype" = "TXT" ]; then
 | 
			
		||||
        DNSdataid="$(echo "$line" | cut -d ',' -f 2 | sed 's/^.*data_id=//;s/>.*//')"
 | 
			
		||||
        DNSvalue="$(echo "$line" | cut -d ',' -f 4 | sed 's/^[^"]*"//;s/".*//;s/<\/td>.*//')"
 | 
			
		||||
        _debug "DNSvalue: $DNSvalue"
 | 
			
		||||
        #     if [ "$DNSvalue" = "$txtvalue" ]; then
 | 
			
		||||
        # Testing value match fails.  Website is truncating the value
 | 
			
		||||
        # field. So for now we will assume that there is only one TXT
 | 
			
		||||
        # field for the sub domain and just delete it. Currently this
 | 
			
		||||
        # is a safe assumption.
 | 
			
		||||
        _freedns_delete_txt_record "$FREEDNS_COOKIE" "$DNSdataid"
 | 
			
		||||
        return $?
 | 
			
		||||
        #     fi
 | 
			
		||||
      fi
 | 
			
		||||
    done
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  # If we get this far we did not find a match (after two attempts)
 | 
			
		||||
  # Not necessarily an error, but log anyway.
 | 
			
		||||
  _debug2 "$subdomain_csv"
 | 
			
		||||
  _info "Cannot delete TXT record for $fulldomain/$txtvalue. Does not exist at FreeDNS"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
 | 
			
		||||
# usage: _freedns_login username password
 | 
			
		||||
# print string "cookie=value" etc.
 | 
			
		||||
# returns 0 success
 | 
			
		||||
_freedns_login() {
 | 
			
		||||
  export _H1="Accept-Language:en-US"
 | 
			
		||||
  username="$1"
 | 
			
		||||
  password="$2"
 | 
			
		||||
  url="https://freedns.afraid.org/zc.php?step=2"
 | 
			
		||||
 | 
			
		||||
  _debug "Login to FreeDNS as user $username"
 | 
			
		||||
 | 
			
		||||
  htmlpage="$(_post "username=$(printf '%s' "$username" | _url_encode)&password=$(printf '%s' "$password" | _url_encode)&submit=Login&action=auth" "$url")"
 | 
			
		||||
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "FreeDNS login failed for user $username bad RC from _post"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  cookies="$(grep -i '^Set-Cookie.*dns_cookie.*$' "$HTTP_HEADER" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)"
 | 
			
		||||
 | 
			
		||||
  # if cookies is not empty then logon successful
 | 
			
		||||
  if [ -z "$cookies" ]; then
 | 
			
		||||
    _debug "$htmlpage"
 | 
			
		||||
    _err "FreeDNS login failed for user $username. Check $HTTP_HEADER file"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  printf "%s" "$cookies"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# usage _freedns_retrieve_subdomain_page login_cookies
 | 
			
		||||
# echo page retrieved (html)
 | 
			
		||||
# returns 0 success
 | 
			
		||||
_freedns_retrieve_subdomain_page() {
 | 
			
		||||
  export _H1="Cookie:$1"
 | 
			
		||||
  export _H2="Accept-Language:en-US"
 | 
			
		||||
  url="https://freedns.afraid.org/subdomain/"
 | 
			
		||||
 | 
			
		||||
  _debug "Retrieve subdomain page from FreeDNS"
 | 
			
		||||
 | 
			
		||||
  htmlpage="$(_get "$url")"
 | 
			
		||||
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "FreeDNS retrieve subdomains failed bad RC from _get"
 | 
			
		||||
    return 1
 | 
			
		||||
  elif [ -z "$htmlpage" ]; then
 | 
			
		||||
    _err "FreeDNS returned empty subdomain page"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug2 "$htmlpage"
 | 
			
		||||
 | 
			
		||||
  printf "%s" "$htmlpage"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# usage _freedns_add_txt_record login_cookies domain_id subdomain value
 | 
			
		||||
# returns 0 success
 | 
			
		||||
_freedns_add_txt_record() {
 | 
			
		||||
  export _H1="Cookie:$1"
 | 
			
		||||
  export _H2="Accept-Language:en-US"
 | 
			
		||||
  domain_id="$2"
 | 
			
		||||
  subdomain="$3"
 | 
			
		||||
  value="$(printf '%s' "$4" | _url_encode)"
 | 
			
		||||
  url="http://freedns.afraid.org/subdomain/save.php?step=2"
 | 
			
		||||
 | 
			
		||||
  htmlpage="$(_post "type=TXT&domain_id=$domain_id&subdomain=$subdomain&address=%22$value%22&send=Save%21" "$url")"
 | 
			
		||||
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "FreeDNS failed to add TXT record for $subdomain bad RC from _post"
 | 
			
		||||
    return 1
 | 
			
		||||
  elif ! grep "200 OK" "$HTTP_HEADER" >/dev/null; then
 | 
			
		||||
    _debug "$htmlpage"
 | 
			
		||||
    _err "FreeDNS failed to add TXT record for $subdomain. Check $HTTP_HEADER file"
 | 
			
		||||
    return 1
 | 
			
		||||
  elif _contains "$htmlpage" "security code was incorrect"; then
 | 
			
		||||
    _debug "$htmlpage"
 | 
			
		||||
    _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
 | 
			
		||||
 | 
			
		||||
  _debug2 "$htmlpage"
 | 
			
		||||
  _info "Added acme challenge TXT record for $fulldomain at FreeDNS"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# usage _freedns_delete_txt_record login_cookies data_id
 | 
			
		||||
# returns 0 success
 | 
			
		||||
_freedns_delete_txt_record() {
 | 
			
		||||
  export _H1="Cookie:$1"
 | 
			
		||||
  export _H2="Accept-Language:en-US"
 | 
			
		||||
  data_id="$2"
 | 
			
		||||
  url="https://freedns.afraid.org/subdomain/delete2.php"
 | 
			
		||||
 | 
			
		||||
  htmlheader="$(_get "$url?data_id%5B%5D=$data_id&submit=delete+selected" "onlyheader")"
 | 
			
		||||
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "FreeDNS failed to delete TXT record for $data_id bad RC from _get"
 | 
			
		||||
    return 1
 | 
			
		||||
  elif ! _contains "$htmlheader" "200 OK"; then
 | 
			
		||||
    _debug "$htmlheader"
 | 
			
		||||
    _err "FreeDNS failed to delete TXT record $data_id"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Deleted acme challenge TXT record for $fulldomain at FreeDNS"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										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
 | 
			
		||||
}
 | 
			
		||||
@@ -6,41 +6,41 @@
 | 
			
		||||
#
 | 
			
		||||
#GD_Secret="asdfsdfsfsdfsdfdfsdf"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
GD_Api="https://api.godaddy.com/v1"
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: add  _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_gd_add(){
 | 
			
		||||
dns_gd_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
  
 | 
			
		||||
  if [ -z "$GD_Key" ] || [ -z "$GD_Secret" ] ; then
 | 
			
		||||
 | 
			
		||||
  if [ -z "$GD_Key" ] || [ -z "$GD_Secret" ]; then
 | 
			
		||||
    GD_Key=""
 | 
			
		||||
    GD_Secret=""
 | 
			
		||||
    _err "You don't specify godaddy api key and secret yet."
 | 
			
		||||
    _err "Please create you key and try again."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  #save the api key and email to the account conf file.
 | 
			
		||||
  _saveaccountconf GD_Key "$GD_Key"
 | 
			
		||||
  _saveaccountconf GD_Secret "$GD_Secret"
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root $fulldomain ; then
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "invalid domain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug _domain_id "$_domain_id"
 | 
			
		||||
 | 
			
		||||
  _debug _sub_domain "$_sub_domain"
 | 
			
		||||
  _debug _domain "$_domain"
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  _info "Adding record"
 | 
			
		||||
  if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain"  "[{\"data\":\"$txtvalue\"}]"; then
 | 
			
		||||
    if [ "$response" = "{}" ] ; then
 | 
			
		||||
  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
 | 
			
		||||
@@ -50,43 +50,44 @@ dns_gd_add(){
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
  _err "Add txt record error."
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#fulldomain
 | 
			
		||||
dns_gd_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
####################  Private functions bellow ##################################
 | 
			
		||||
####################  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
 | 
			
		||||
  while [ '1' ] ; do
 | 
			
		||||
    h=$(printf $domain | cut -d . -f $i-100)
 | 
			
		||||
    if [ -z "$h" ] ; then
 | 
			
		||||
  while true; do
 | 
			
		||||
    h=$(printf "%s" "$domain" | cut -d . -f $i-100)
 | 
			
		||||
    if [ -z "$h" ]; then
 | 
			
		||||
      #not valid
 | 
			
		||||
      return 1;
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
    if ! _gd_rest GET "domains/$h" ; then
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
    if printf "$response" | grep '"code":"NOT_FOUND"' >/dev/null ; then
 | 
			
		||||
 | 
			
		||||
    if ! _gd_rest GET "domains/$h"; then
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if _contains "$response" '"code":"NOT_FOUND"'; then
 | 
			
		||||
      _debug "$h not found"
 | 
			
		||||
    else
 | 
			
		||||
      _sub_domain=$(printf $domain | cut -d . -f 1-$p)
 | 
			
		||||
      _domain=$h
 | 
			
		||||
      _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
 | 
			
		||||
      _domain="$h"
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
    p=$i
 | 
			
		||||
    i=$(expr $i + 1)
 | 
			
		||||
    p="$i"
 | 
			
		||||
    i=$(_math "$i" + 1)
 | 
			
		||||
  done
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
@@ -95,24 +96,22 @@ _gd_rest() {
 | 
			
		||||
  m=$1
 | 
			
		||||
  ep="$2"
 | 
			
		||||
  data="$3"
 | 
			
		||||
  _debug $ep
 | 
			
		||||
  
 | 
			
		||||
  _H1="Authorization: sso-key $GD_Key:$GD_Secret"
 | 
			
		||||
  _H2="Content-Type: application/json"
 | 
			
		||||
  
 | 
			
		||||
  if [ "$data" ] ; then
 | 
			
		||||
  _debug "$ep"
 | 
			
		||||
 | 
			
		||||
  export _H1="Authorization: sso-key $GD_Key:$GD_Secret"
 | 
			
		||||
  export _H2="Content-Type: application/json"
 | 
			
		||||
 | 
			
		||||
  if [ "$data" ]; then
 | 
			
		||||
    _debug data "$data"
 | 
			
		||||
    response="$(_post "$data" "$GD_Api/$ep" "" $m)"
 | 
			
		||||
    response="$(_post "$data" "$GD_Api/$ep" "" "$m")"
 | 
			
		||||
  else
 | 
			
		||||
    response="$(_get "$GD_Api/$ep")"
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
  if [ "$?" != "0" ] ; then
 | 
			
		||||
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "error $ep"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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 "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 "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 "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 ##################################
 | 
			
		||||
							
								
								
									
										177
									
								
								dnsapi/dns_ispconfig.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										177
									
								
								dnsapi/dns_ispconfig.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,177 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
# ISPConfig 3.1 API
 | 
			
		||||
# User must provide login data and URL to the ISPConfig installation incl. port. The remote user in ISPConfig must have access to:
 | 
			
		||||
# - DNS zone Functions
 | 
			
		||||
# - DNS txt Functions
 | 
			
		||||
 | 
			
		||||
# Report bugs to https://github.com/sjau/acme.sh
 | 
			
		||||
 | 
			
		||||
# Values to export:
 | 
			
		||||
# export ISPC_User="remoteUser"
 | 
			
		||||
# export ISPC_Password="remotePassword"
 | 
			
		||||
# export ISPC_Api="https://ispc.domain.tld:8080/remote/json.php"
 | 
			
		||||
# export ISPC_Api_Insecure=1     # Set 1 for insecure and 0 for secure -> difference is whether ssl cert is checked for validity (0) or whether it is just accepted (1)
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: dns_myapi_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_ispconfig_add() {
 | 
			
		||||
  fulldomain="${1}"
 | 
			
		||||
  txtvalue="${2}"
 | 
			
		||||
  _debug "Calling: dns_ispconfig_add() '${fulldomain}' '${txtvalue}'"
 | 
			
		||||
  _ISPC_credentials && _ISPC_login && _ISPC_getZoneInfo && _ISPC_addTxt
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#Usage: dns_myapi_rm   _acme-challenge.www.domain.com
 | 
			
		||||
dns_ispconfig_rm() {
 | 
			
		||||
  fulldomain="${1}"
 | 
			
		||||
  _debug "Calling: dns_ispconfig_rm() '${fulldomain}'"
 | 
			
		||||
  _ISPC_credentials && _ISPC_login && _ISPC_rmTxt
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
 | 
			
		||||
_ISPC_credentials() {
 | 
			
		||||
  if [ -z "${ISPC_User}" ] || [ -z "$ISPC_Password" ] || [ -z "${ISPC_Api}" ] || [ -z "${ISPC_Api_Insecure}" ]; then
 | 
			
		||||
    ISPC_User=""
 | 
			
		||||
    ISPC_Password=""
 | 
			
		||||
    ISPC_Api=""
 | 
			
		||||
    ISPC_Api_Insecure=""
 | 
			
		||||
    _err "You haven't specified the ISPConfig Login data, URL and whether you want check the ISPC SSL cert. Please try again."
 | 
			
		||||
    return 1
 | 
			
		||||
  else
 | 
			
		||||
    _saveaccountconf ISPC_User "${ISPC_User}"
 | 
			
		||||
    _saveaccountconf ISPC_Password "${ISPC_Password}"
 | 
			
		||||
    _saveaccountconf ISPC_Api "${ISPC_Api}"
 | 
			
		||||
    _saveaccountconf ISPC_Api_Insecure "${ISPC_Api_Insecure}"
 | 
			
		||||
    # Set whether curl should use secure or insecure mode
 | 
			
		||||
    export HTTPS_INSECURE="${ISPC_Api_Insecure}"
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_ISPC_login() {
 | 
			
		||||
  _info "Getting Session ID"
 | 
			
		||||
  curData="{\"username\":\"${ISPC_User}\",\"password\":\"${ISPC_Password}\",\"client_login\":false}"
 | 
			
		||||
  curResult="$(_post "${curData}" "${ISPC_Api}?login")"
 | 
			
		||||
  _debug "Calling _ISPC_login: '${curData}' '${ISPC_Api}?login'"
 | 
			
		||||
  _debug "Result of _ISPC_login: '$curResult'"
 | 
			
		||||
  if _contains "${curResult}" '"code":"ok"'; then
 | 
			
		||||
    sessionID=$(echo "${curResult}" | _egrep_o "response.*" | cut -d ':' -f 2 | cut -d '"' -f 2)
 | 
			
		||||
    _info "Retrieved Session ID."
 | 
			
		||||
    _debug "Session ID: '${sessionID}'"
 | 
			
		||||
  else
 | 
			
		||||
    _err "Couldn't retrieve the Session ID."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_ISPC_getZoneInfo() {
 | 
			
		||||
  _info "Getting Zoneinfo"
 | 
			
		||||
  zoneEnd=false
 | 
			
		||||
  curZone="${fulldomain}"
 | 
			
		||||
  while [ "${zoneEnd}" = false ]; do
 | 
			
		||||
    # we can strip the first part of the fulldomain, since it's just the _acme-challenge string
 | 
			
		||||
    curZone="${curZone#*.}"
 | 
			
		||||
    # suffix . needed for zone -> domain.tld.
 | 
			
		||||
    curData="{\"session_id\":\"${sessionID}\",\"primary_id\":{\"origin\":\"${curZone}.\"}}"
 | 
			
		||||
    curResult="$(_post "${curData}" "${ISPC_Api}?dns_zone_get")"
 | 
			
		||||
    _debug "Calling _ISPC_getZoneInfo: '${curData}' '${ISPC_Api}?login'"
 | 
			
		||||
    _debug "Result of _ISPC_getZoneInfo: '$curResult'"
 | 
			
		||||
    if _contains "${curResult}" '"id":"'; then
 | 
			
		||||
      zoneFound=true
 | 
			
		||||
      zoneEnd=true
 | 
			
		||||
      _info "Retrieved zone data."
 | 
			
		||||
      _debug "Zone data: '${curResult}'"
 | 
			
		||||
    fi
 | 
			
		||||
    if [ "${curZone#*.}" != "$curZone" ]; then
 | 
			
		||||
      _debug2 "$curZone still contains a '.' - so we can check next higher level"
 | 
			
		||||
    else
 | 
			
		||||
      zoneEnd=true
 | 
			
		||||
      _err "Couldn't retrieve zone data."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
  done
 | 
			
		||||
  if [ "${zoneFound}" ]; then
 | 
			
		||||
    server_id=$(echo "${curResult}" | _egrep_o "server_id.*" | cut -d ':' -f 2 | cut -d '"' -f 2)
 | 
			
		||||
    _debug "Server ID: '${server_id}'"
 | 
			
		||||
    case "${server_id}" in
 | 
			
		||||
      '' | *[!0-9]*)
 | 
			
		||||
        _err "Server ID is not numeric."
 | 
			
		||||
        return 1
 | 
			
		||||
        ;;
 | 
			
		||||
      *) _info "Retrieved Server ID" ;;
 | 
			
		||||
    esac
 | 
			
		||||
    zone=$(echo "${curResult}" | _egrep_o "\"id.*" | cut -d ':' -f 2 | cut -d '"' -f 2)
 | 
			
		||||
    _debug "Zone: '${zone}'"
 | 
			
		||||
    case "${zone}" in
 | 
			
		||||
      '' | *[!0-9]*)
 | 
			
		||||
        _err "Zone ID is not numeric."
 | 
			
		||||
        return 1
 | 
			
		||||
        ;;
 | 
			
		||||
      *) _info "Retrieved Zone ID" ;;
 | 
			
		||||
    esac
 | 
			
		||||
    client_id=$(echo "${curResult}" | _egrep_o "sys_userid.*" | cut -d ':' -f 2 | cut -d '"' -f 2)
 | 
			
		||||
    _debug "Client ID: '${client_id}'"
 | 
			
		||||
    case "${client_id}" in
 | 
			
		||||
      '' | *[!0-9]*)
 | 
			
		||||
        _err "Client ID is not numeric."
 | 
			
		||||
        return 1
 | 
			
		||||
        ;;
 | 
			
		||||
      *) _info "Retrieved Client ID." ;;
 | 
			
		||||
    esac
 | 
			
		||||
    zoneFound=""
 | 
			
		||||
    zoneEnd=""
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_ISPC_addTxt() {
 | 
			
		||||
  curSerial="$(date +%s)"
 | 
			
		||||
  curStamp="$(date +'%F %T')"
 | 
			
		||||
  params="\"server_id\":\"${server_id}\",\"zone\":\"${zone}\",\"name\":\"${fulldomain}.\",\"type\":\"txt\",\"data\":\"${txtvalue}\",\"aux\":\"0\",\"ttl\":\"3600\",\"active\":\"y\",\"stamp\":\"${curStamp}\",\"serial\":\"${curSerial}\""
 | 
			
		||||
  curData="{\"session_id\":\"${sessionID}\",\"client_id\":\"${client_id}\",\"params\":{${params}}}"
 | 
			
		||||
  curResult="$(_post "${curData}" "${ISPC_Api}?dns_txt_add")"
 | 
			
		||||
  _debug "Calling _ISPC_addTxt: '${curData}' '${ISPC_Api}?dns_txt_add'"
 | 
			
		||||
  _debug "Result of _ISPC_addTxt: '$curResult'"
 | 
			
		||||
  record_id=$(echo "${curResult}" | _egrep_o "\"response.*" | cut -d ':' -f 2 | cut -d '"' -f 2)
 | 
			
		||||
  _debug "Record ID: '${record_id}'"
 | 
			
		||||
  case "${record_id}" in
 | 
			
		||||
    '' | *[!0-9]*)
 | 
			
		||||
      _err "Couldn't add ACME Challenge TXT record to zone."
 | 
			
		||||
      return 1
 | 
			
		||||
      ;;
 | 
			
		||||
    *) _info "Added ACME Challenge TXT record to zone." ;;
 | 
			
		||||
  esac
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_ISPC_rmTxt() {
 | 
			
		||||
  # Need to get the record ID.
 | 
			
		||||
  curData="{\"session_id\":\"${sessionID}\",\"primary_id\":{\"name\":\"${fulldomain}.\",\"type\":\"TXT\"}}"
 | 
			
		||||
  curResult="$(_post "${curData}" "${ISPC_Api}?dns_txt_get")"
 | 
			
		||||
  _debug "Calling _ISPC_rmTxt: '${curData}' '${ISPC_Api}?dns_txt_get'"
 | 
			
		||||
  _debug "Result of _ISPC_rmTxt: '$curResult'"
 | 
			
		||||
  if _contains "${curResult}" '"code":"ok"'; then
 | 
			
		||||
    record_id=$(echo "${curResult}" | _egrep_o "\"id.*" | cut -d ':' -f 2 | cut -d '"' -f 2)
 | 
			
		||||
    _debug "Record ID: '${record_id}'"
 | 
			
		||||
    case "${record_id}" in
 | 
			
		||||
      '' | *[!0-9]*)
 | 
			
		||||
        _err "Record ID is not numeric."
 | 
			
		||||
        return 1
 | 
			
		||||
        ;;
 | 
			
		||||
      *)
 | 
			
		||||
        unset IFS
 | 
			
		||||
        _info "Retrieved Record ID."
 | 
			
		||||
        curData="{\"session_id\":\"${sessionID}\",\"primary_id\":\"${record_id}\"}"
 | 
			
		||||
        curResult="$(_post "${curData}" "${ISPC_Api}?dns_txt_delete")"
 | 
			
		||||
        _debug "Calling _ISPC_rmTxt: '${curData}' '${ISPC_Api}?dns_txt_delete'"
 | 
			
		||||
        _debug "Result of _ISPC_rmTxt: '$curResult'"
 | 
			
		||||
        if _contains "${curResult}" '"code":"ok"'; then
 | 
			
		||||
          _info "Removed ACME Challenge TXT record from zone."
 | 
			
		||||
        else
 | 
			
		||||
          _err "Couldn't remove ACME Challenge TXT record from zone."
 | 
			
		||||
          return 1
 | 
			
		||||
        fi
 | 
			
		||||
        ;;
 | 
			
		||||
    esac
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										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
 | 
			
		||||
}
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
 | 
			
		||||
# dns api wrapper of lexicon for acme.sh
 | 
			
		||||
 | 
			
		||||
lexicon_url="https://github.com/AnalogJ/lexicon"
 | 
			
		||||
# https://github.com/AnalogJ/lexicon
 | 
			
		||||
lexicon_cmd="lexicon"
 | 
			
		||||
 | 
			
		||||
wiki="https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api"
 | 
			
		||||
@@ -13,15 +13,16 @@ wiki="https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api"
 | 
			
		||||
dns_lexicon_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
  
 | 
			
		||||
  domain=$(printf "$fulldomain" | cut -d . -f 2-999)
 | 
			
		||||
  
 | 
			
		||||
  if ! _exists $lexicon_cmd ; then
 | 
			
		||||
 | 
			
		||||
  domain=$(printf "%s" "$fulldomain" | cut -d . -f 2-999)
 | 
			
		||||
 | 
			
		||||
  if ! _exists "$lexicon_cmd"; then
 | 
			
		||||
    _err "Please install $lexicon_cmd first: $wiki"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
  if [ -z "$PROVIDER" ] ; then
 | 
			
		||||
 | 
			
		||||
  if [ -z "$PROVIDER" ]; then
 | 
			
		||||
    PROVIDER=""
 | 
			
		||||
    _err "Please define env PROVIDER first: $wiki"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
@@ -29,41 +30,49 @@ dns_lexicon_add() {
 | 
			
		||||
  _savedomainconf PROVIDER "$PROVIDER"
 | 
			
		||||
  export PROVIDER
 | 
			
		||||
 | 
			
		||||
  Lx_name=$(echo LEXICON_${PROVIDER}_USERNAME |  tr [a-z] [A-Z])
 | 
			
		||||
  eval Lx_name_v="\$$Lx_name"
 | 
			
		||||
  _debug "$Lx_name" "$Lx_name_v"
 | 
			
		||||
  if [ "$Lx_name_v" ] ; then
 | 
			
		||||
    _saveaccountconf $Lx_name "$Lx_name_v"
 | 
			
		||||
    export "$Lx_name"
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
  Lx_token=$(echo LEXICON_${PROVIDER}_TOKEN |  tr [a-z] [A-Z])
 | 
			
		||||
  eval Lx_token_v="\$$Lx_token"
 | 
			
		||||
  _debug "$Lx_token" "$Lx_token_v"
 | 
			
		||||
  if [ "$Lx_token_v" ] ; then
 | 
			
		||||
    _saveaccountconf $Lx_token "$Lx_token_v"
 | 
			
		||||
    export "$Lx_token"
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
  Lx_password=$(echo LEXICON_${PROVIDER}_PASSWORD |  tr [a-z] [A-Z])
 | 
			
		||||
  eval Lx_password_v="\$$Lx_password"
 | 
			
		||||
  _debug "$Lx_password" "$Lx_password_v"
 | 
			
		||||
  if [ "$Lx_password_v" ] ; then
 | 
			
		||||
    _saveaccountconf $Lx_password "$Lx_password_v"
 | 
			
		||||
    export "$Lx_password"
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
  Lx_domaintoken=$(echo LEXICON_${PROVIDER}_DOMAINTOKEN |  tr [a-z] [A-Z])
 | 
			
		||||
  eval Lx_domaintoken_v="\$$Lx_domaintoken"
 | 
			
		||||
  _debug "$Lx_domaintoken" "$Lx_domaintoken_v"
 | 
			
		||||
  if [ "$Lx_domaintoken_v" ] ; then
 | 
			
		||||
    export "$Lx_domaintoken"
 | 
			
		||||
    _saveaccountconf $Lx_domaintoken "$Lx_domaintoken_v"
 | 
			
		||||
  # e.g. busybox-ash does not know [:upper:]
 | 
			
		||||
  # shellcheck disable=SC2018,SC2019
 | 
			
		||||
  Lx_name=$(echo LEXICON_"${PROVIDER}"_USERNAME | tr 'a-z' 'A-Z')
 | 
			
		||||
  Lx_name_v=$(eval echo \$"$Lx_name")
 | 
			
		||||
  _secure_debug "$Lx_name" "$Lx_name_v"
 | 
			
		||||
  if [ "$Lx_name_v" ]; then
 | 
			
		||||
    _saveaccountconf "$Lx_name" "$Lx_name_v"
 | 
			
		||||
    eval export "$Lx_name"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  $lexicon_cmd "$PROVIDER" create ${domain} TXT --name="_acme-challenge.${domain}." --content="${txtvalue}"
 | 
			
		||||
  # shellcheck disable=SC2018,SC2019
 | 
			
		||||
  Lx_token=$(echo LEXICON_"${PROVIDER}"_TOKEN | tr 'a-z' 'A-Z')
 | 
			
		||||
  Lx_token_v=$(eval echo \$"$Lx_token")
 | 
			
		||||
  _secure_debug "$Lx_token" "$Lx_token_v"
 | 
			
		||||
  if [ "$Lx_token_v" ]; then
 | 
			
		||||
    _saveaccountconf "$Lx_token" "$Lx_token_v"
 | 
			
		||||
    eval export "$Lx_token"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # shellcheck disable=SC2018,SC2019
 | 
			
		||||
  Lx_password=$(echo LEXICON_"${PROVIDER}"_PASSWORD | tr 'a-z' 'A-Z')
 | 
			
		||||
  Lx_password_v=$(eval echo \$"$Lx_password")
 | 
			
		||||
  _secure_debug "$Lx_password" "$Lx_password_v"
 | 
			
		||||
  if [ "$Lx_password_v" ]; then
 | 
			
		||||
    _saveaccountconf "$Lx_password" "$Lx_password_v"
 | 
			
		||||
    eval export "$Lx_password"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # shellcheck disable=SC2018,SC2019
 | 
			
		||||
  Lx_domaintoken=$(echo LEXICON_"${PROVIDER}"_DOMAINTOKEN | tr 'a-z' 'A-Z')
 | 
			
		||||
  Lx_domaintoken_v=$(eval echo \$"$Lx_domaintoken")
 | 
			
		||||
  _secure_debug "$Lx_domaintoken" "$Lx_domaintoken_v"
 | 
			
		||||
  if [ "$Lx_domaintoken_v" ]; then
 | 
			
		||||
    eval export "$Lx_domaintoken"
 | 
			
		||||
    _saveaccountconf "$Lx_domaintoken" "$Lx_domaintoken_v"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  $lexicon_cmd "$PROVIDER" create "${domain}" TXT --name="_acme-challenge.${domain}." --content="${txtvalue}"
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#fulldomain
 | 
			
		||||
dns_lexicon_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										183
									
								
								dnsapi/dns_linode.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										183
									
								
								dnsapi/dns_linode.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,183 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#Author: Philipp Grosswiler <philipp.grosswiler@swiss-design.net>
 | 
			
		||||
 | 
			
		||||
LINODE_API_URL="https://api.linode.com/?api_key=$LINODE_API_KEY&api_action="
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: dns_linode_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_linode_add() {
 | 
			
		||||
  fulldomain="${1}"
 | 
			
		||||
  txtvalue="${2}"
 | 
			
		||||
 | 
			
		||||
  if ! _Linode_API; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Using Linode"
 | 
			
		||||
  _debug "Calling: dns_linode_add() '${fulldomain}' '${txtvalue}'"
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "Domain does not exist."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug _domain_id "$_domain_id"
 | 
			
		||||
  _debug _sub_domain "$_sub_domain"
 | 
			
		||||
  _debug _domain "$_domain"
 | 
			
		||||
 | 
			
		||||
  _parameters="&DomainID=$_domain_id&Type=TXT&Name=$_sub_domain&Target=$txtvalue"
 | 
			
		||||
 | 
			
		||||
  if _rest GET "domain.resource.create" "$_parameters" && [ -n "$response" ]; then
 | 
			
		||||
    _resource_id=$(printf "%s\n" "$response" | _egrep_o "\"ResourceID\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1)
 | 
			
		||||
    _debug _resource_id "$_resource_id"
 | 
			
		||||
 | 
			
		||||
    if [ -z "$_resource_id" ]; then
 | 
			
		||||
      _err "Error adding the domain resource."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    _info "Domain resource successfully added."
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#Usage: dns_linode_rm   _acme-challenge.www.domain.com
 | 
			
		||||
dns_linode_rm() {
 | 
			
		||||
  fulldomain="${1}"
 | 
			
		||||
 | 
			
		||||
  if ! _Linode_API; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Using Linode"
 | 
			
		||||
  _debug "Calling: dns_linode_rm() '${fulldomain}'"
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "Domain does not exist."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug _domain_id "$_domain_id"
 | 
			
		||||
  _debug _sub_domain "$_sub_domain"
 | 
			
		||||
  _debug _domain "$_domain"
 | 
			
		||||
 | 
			
		||||
  _parameters="&DomainID=$_domain_id"
 | 
			
		||||
 | 
			
		||||
  if _rest GET "domain.resource.list" "$_parameters" && [ -n "$response" ]; then
 | 
			
		||||
    response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')"
 | 
			
		||||
 | 
			
		||||
    resource="$(echo "$response" | _egrep_o "{.*\"NAME\":\s*\"$_sub_domain\".*}")"
 | 
			
		||||
    if [ "$resource" ]; then
 | 
			
		||||
      _resource_id=$(printf "%s\n" "$resource" | _egrep_o "\"RESOURCEID\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ )
 | 
			
		||||
      if [ "$_resource_id" ]; then
 | 
			
		||||
        _debug _resource_id "$_resource_id"
 | 
			
		||||
 | 
			
		||||
        _parameters="&DomainID=$_domain_id&ResourceID=$_resource_id"
 | 
			
		||||
 | 
			
		||||
        if _rest GET "domain.resource.delete" "$_parameters" && [ -n "$response" ]; then
 | 
			
		||||
          _resource_id=$(printf "%s\n" "$response" | _egrep_o "\"ResourceID\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1)
 | 
			
		||||
          _debug _resource_id "$_resource_id"
 | 
			
		||||
 | 
			
		||||
          if [ -z "$_resource_id" ]; then
 | 
			
		||||
            _err "Error deleting the domain resource."
 | 
			
		||||
            return 1
 | 
			
		||||
          fi
 | 
			
		||||
 | 
			
		||||
          _info "Domain resource successfully deleted."
 | 
			
		||||
          return 0
 | 
			
		||||
        fi
 | 
			
		||||
      fi
 | 
			
		||||
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
 | 
			
		||||
_Linode_API() {
 | 
			
		||||
  if [ -z "$LINODE_API_KEY" ]; then
 | 
			
		||||
    LINODE_API_KEY=""
 | 
			
		||||
 | 
			
		||||
    _err "You didn't specify the Linode API key yet."
 | 
			
		||||
    _err "Please create your key and try again."
 | 
			
		||||
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _saveaccountconf LINODE_API_KEY "$LINODE_API_KEY"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  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 _rest GET "domain.list"; 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 "{.*\"DOMAIN\":\s*\"$h\".*}")"
 | 
			
		||||
      if [ "$hostedzone" ]; then
 | 
			
		||||
        _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"DOMAINID\":\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 method action data
 | 
			
		||||
_rest() {
 | 
			
		||||
  mtd="$1"
 | 
			
		||||
  ep="$2"
 | 
			
		||||
  data="$3"
 | 
			
		||||
 | 
			
		||||
  _debug mtd "$mtd"
 | 
			
		||||
  _debug ep "$ep"
 | 
			
		||||
 | 
			
		||||
  export _H1="Accept: application/json"
 | 
			
		||||
  export _H2="Content-Type: application/json"
 | 
			
		||||
 | 
			
		||||
  if [ "$mtd" != "GET" ]; then
 | 
			
		||||
    # both POST and DELETE.
 | 
			
		||||
    _debug data "$data"
 | 
			
		||||
    response="$(_post "$data" "$LINODE_API_URL$ep" "" "$mtd")"
 | 
			
		||||
  else
 | 
			
		||||
    response="$(_get "$LINODE_API_URL$ep$data")"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "error $ep"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										174
									
								
								dnsapi/dns_lua.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										174
									
								
								dnsapi/dns_lua.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,174 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
# bug reports to dev@1e.ca
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
#LUA_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
 | 
			
		||||
#
 | 
			
		||||
#LUA_Email="user@luadns.net"
 | 
			
		||||
 | 
			
		||||
LUA_Api="https://api.luadns.com/v1"
 | 
			
		||||
LUA_auth=$(printf "%s" "$LUA_Email:$LUA_Key" | _base64)
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: add  _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_lua_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  if [ -z "$LUA_Key" ] || [ -z "$LUA_Email" ]; then
 | 
			
		||||
    LUA_Key=""
 | 
			
		||||
    LUA_Email=""
 | 
			
		||||
    _err "You don't specify luadns api key and email yet."
 | 
			
		||||
    _err "Please create you key and try again."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  #save the api key and email to the account conf file.
 | 
			
		||||
  _saveaccountconf LUA_Key "$LUA_Key"
 | 
			
		||||
  _saveaccountconf LUA_Email "$LUA_Email"
 | 
			
		||||
 | 
			
		||||
  _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"
 | 
			
		||||
 | 
			
		||||
  if ! _contains "$response" "\"id\":"; then
 | 
			
		||||
    _err "Error"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | wc -l | tr -d " ")
 | 
			
		||||
  _debug count "$count"
 | 
			
		||||
  if [ "$count" = "0" ]; then
 | 
			
		||||
    _info "Adding record"
 | 
			
		||||
    if _LUA_rest POST "zones/$_domain_id/records" "{\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"ttl\":120}"; 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 "\"id\":[^,]*,\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | _head_n 1 | cut -d: -f2 | cut -d, -f1)
 | 
			
		||||
    _debug "record_id" "$record_id"
 | 
			
		||||
 | 
			
		||||
    _LUA_rest PUT "zones/$_domain_id/records/$record_id" "{\"id\":$record_id,\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"zone_id\":$_domain_id,\"ttl\":120}"
 | 
			
		||||
    if [ "$?" = "0" ] && _contains "$response" "updated_at"; then
 | 
			
		||||
      _info "Updated!"
 | 
			
		||||
      #todo: check if the record takes effect
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
    _err "Update error"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#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 ##################################
 | 
			
		||||
#_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 ! _LUA_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" "\"name\":\"$h\""; then
 | 
			
		||||
      _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$h\"" | cut -d : -f 2 | cut -d , -f 1)
 | 
			
		||||
      _debug _domain_id "$_domain_id"
 | 
			
		||||
      if [ "$_domain_id" ]; then
 | 
			
		||||
        _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
 | 
			
		||||
        _domain="$h"
 | 
			
		||||
        return 0
 | 
			
		||||
      fi
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    p=$i
 | 
			
		||||
    i=$(_math "$i" + 1)
 | 
			
		||||
  done
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_LUA_rest() {
 | 
			
		||||
  m=$1
 | 
			
		||||
  ep="$2"
 | 
			
		||||
  data="$3"
 | 
			
		||||
  _debug "$ep"
 | 
			
		||||
 | 
			
		||||
  export _H1="Accept: application/json"
 | 
			
		||||
  export _H2="Authorization: Basic $LUA_auth"
 | 
			
		||||
  if [ "$m" != "GET" ]; then
 | 
			
		||||
    _debug data "$data"
 | 
			
		||||
    response="$(_post "$data" "$LUA_Api/$ep" "" "$m")"
 | 
			
		||||
  else
 | 
			
		||||
    response="$(_get "$LUA_Api/$ep")"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "error $ep"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										175
									
								
								dnsapi/dns_me.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								dnsapi/dns_me.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,175 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
# bug reports to dev@1e.ca
 | 
			
		||||
 | 
			
		||||
# ME_Key=qmlkdjflmkqdjf	
 | 
			
		||||
# ME_Secret=qmsdlkqmlksdvnnpae
 | 
			
		||||
 | 
			
		||||
ME_Api=https://api.dnsmadeeasy.com/V2.0/dns/managed
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: add  _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_me_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  if [ -z "$ME_Key" ] || [ -z "$ME_Secret" ]; then
 | 
			
		||||
    ME_Key=""
 | 
			
		||||
    ME_Secret=""
 | 
			
		||||
    _err "You didn't specify DNSMadeEasy api key and secret yet."
 | 
			
		||||
    _err "Please create you key and try again."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  #save the api key and email to the account conf file.
 | 
			
		||||
  _saveaccountconf ME_Key "$ME_Key"
 | 
			
		||||
  _saveaccountconf ME_Secret "$ME_Secret"
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "invalid domain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug _domain_id "$_domain_id"
 | 
			
		||||
  _debug _sub_domain "$_sub_domain"
 | 
			
		||||
  _debug _domain "$_domain"
 | 
			
		||||
 | 
			
		||||
  _debug "Getting txt records"
 | 
			
		||||
  _me_rest GET "${_domain_id}/records?recordName=$_sub_domain&type=TXT"
 | 
			
		||||
 | 
			
		||||
  if ! _contains "$response" "\"totalRecords\":"; then
 | 
			
		||||
    _err "Error"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  count=$(printf "%s\n" "$response" | _egrep_o "\"totalRecords\":[^,]*" | cut -d : -f 2)
 | 
			
		||||
  _debug count "$count"
 | 
			
		||||
  if [ "$count" = "0" ]; then
 | 
			
		||||
    _info "Adding record"
 | 
			
		||||
    if _me_rest POST "$_domain_id/records/" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}"; then
 | 
			
		||||
      if printf -- "%s" "$response" | grep \"id\": >/dev/null; 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 "\"id\":[^,]*" | cut -d : -f 2 | head -n 1)
 | 
			
		||||
    _debug "record_id" "$record_id"
 | 
			
		||||
 | 
			
		||||
    _me_rest PUT "$_domain_id/records/$record_id/" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}"
 | 
			
		||||
    if [ "$?" = "0" ]; then
 | 
			
		||||
      _info "Updated"
 | 
			
		||||
      #todo: check if the record takes effect
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
    _err "Update error"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#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 ##################################
 | 
			
		||||
#_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
 | 
			
		||||
  while true; do
 | 
			
		||||
    h=$(printf "%s" "$domain" | cut -d . -f $i-100)
 | 
			
		||||
    if [ -z "$h" ]; then
 | 
			
		||||
      #not valid
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if ! _me_rest GET "name?domainname=$h"; then
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if _contains "$response" "\"name\":\"$h\""; then
 | 
			
		||||
      _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*" | head -n 1 | cut -d : -f 2 | tr -d '}')
 | 
			
		||||
      if [ "$_domain_id" ]; then
 | 
			
		||||
        _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
 | 
			
		||||
        _domain="$h"
 | 
			
		||||
        return 0
 | 
			
		||||
      fi
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    p=$i
 | 
			
		||||
    i=$(_math "$i" + 1)
 | 
			
		||||
  done
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_me_rest() {
 | 
			
		||||
  m=$1
 | 
			
		||||
  ep="$2"
 | 
			
		||||
  data="$3"
 | 
			
		||||
  _debug "$ep"
 | 
			
		||||
 | 
			
		||||
  cdate=$(date -u +"%a, %d %b %Y %T %Z")
 | 
			
		||||
  hmac=$(printf "%s" "$cdate" | _hmac sha1 "$(printf "%s" "$ME_Secret" | _hex_dump | tr -d " ")" hex)
 | 
			
		||||
 | 
			
		||||
  export _H1="x-dnsme-apiKey: $ME_Key"
 | 
			
		||||
  export _H2="x-dnsme-requestDate: $cdate"
 | 
			
		||||
  export _H3="x-dnsme-hmac: $hmac"
 | 
			
		||||
 | 
			
		||||
  if [ "$m" != "GET" ]; then
 | 
			
		||||
    _debug data "$data"
 | 
			
		||||
    response="$(_post "$data" "$ME_Api/$ep" "" "$m")"
 | 
			
		||||
  else
 | 
			
		||||
    response="$(_get "$ME_Api/$ep")"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "error $ep"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
@@ -5,48 +5,31 @@
 | 
			
		||||
#So, here must be a method   dns_myapi_add()
 | 
			
		||||
#Which will be called by acme.sh to add the txt record to your api system.
 | 
			
		||||
#returns 0 means success, otherwise error.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
#Author: Neilpang
 | 
			
		||||
#Report Bugs here: https://github.com/Neilpang/acme.sh
 | 
			
		||||
#
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: dns_myapi_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_myapi_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
  _info "Using myapi"
 | 
			
		||||
  _debug fulldomain "$fulldomain"
 | 
			
		||||
  _debug txtvalue "$txtvalue"
 | 
			
		||||
  _err "Not implemented!"
 | 
			
		||||
  return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
####################  Private functions bellow ##################################
 | 
			
		||||
_info() {
 | 
			
		||||
  if [ -z "$2" ] ; then
 | 
			
		||||
    echo "[$(date)] $1"
 | 
			
		||||
  else
 | 
			
		||||
    echo "[$(date)] $1='$2'"
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_err() {
 | 
			
		||||
  _info "$@" >&2
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_debug() {
 | 
			
		||||
  if [ -z "$DEBUG" ] ; then
 | 
			
		||||
    return
 | 
			
		||||
  fi
 | 
			
		||||
  _err "$@"
 | 
			
		||||
  return 0
 | 
			
		||||
#Usage: fulldomain txtvalue
 | 
			
		||||
#Remove the txt record after validation.
 | 
			
		||||
dns_myapi_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
  _info "Using myapi"
 | 
			
		||||
  _debug fulldomain "$fulldomain"
 | 
			
		||||
  _debug txtvalue "$txtvalue"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_debug2() {
 | 
			
		||||
  if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then
 | 
			
		||||
    _debug "$@"
 | 
			
		||||
  fi
 | 
			
		||||
  return
 | 
			
		||||
}
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										58
									
								
								dnsapi/dns_nsupdate.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										58
									
								
								dnsapi/dns_nsupdate.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,58 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: dns_nsupdate_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_nsupdate_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
  _checkKeyFile || return 1
 | 
			
		||||
  [ -n "${NSUPDATE_SERVER}" ] || NSUPDATE_SERVER="localhost"
 | 
			
		||||
  # save the dns server and key to the account conf file.
 | 
			
		||||
  _saveaccountconf NSUPDATE_SERVER "${NSUPDATE_SERVER}"
 | 
			
		||||
  _saveaccountconf NSUPDATE_KEY "${NSUPDATE_KEY}"
 | 
			
		||||
  _info "adding ${fulldomain}. 60 in txt \"${txtvalue}\""
 | 
			
		||||
  nsupdate -k "${NSUPDATE_KEY}" <<EOF
 | 
			
		||||
server ${NSUPDATE_SERVER}
 | 
			
		||||
update add ${fulldomain}. 60 in txt "${txtvalue}"
 | 
			
		||||
send
 | 
			
		||||
EOF
 | 
			
		||||
  if [ $? -ne 0 ]; then
 | 
			
		||||
    _err "error updating domain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#Usage: dns_nsupdate_rm   _acme-challenge.www.domain.com
 | 
			
		||||
dns_nsupdate_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  _checkKeyFile || return 1
 | 
			
		||||
  [ -n "${NSUPDATE_SERVER}" ] || NSUPDATE_SERVER="localhost"
 | 
			
		||||
  _info "removing ${fulldomain}. txt"
 | 
			
		||||
  nsupdate -k "${NSUPDATE_KEY}" <<EOF
 | 
			
		||||
server ${NSUPDATE_SERVER}
 | 
			
		||||
update delete ${fulldomain}. txt
 | 
			
		||||
send
 | 
			
		||||
EOF
 | 
			
		||||
  if [ $? -ne 0 ]; then
 | 
			
		||||
    _err "error updating domain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
 | 
			
		||||
_checkKeyFile() {
 | 
			
		||||
  if [ -z "${NSUPDATE_KEY}" ]; then
 | 
			
		||||
    _err "you must specify a path to the nsupdate key file"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  if [ ! -r "${NSUPDATE_KEY}" ]; then
 | 
			
		||||
    _err "key ${NSUPDATE_KEY} is unreadable"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#Applcation Key
 | 
			
		||||
#Application Key
 | 
			
		||||
#OVH_AK="sdfsdfsdfljlbjkljlkjsdfoiwje"
 | 
			
		||||
#
 | 
			
		||||
#Application Secret
 | 
			
		||||
@@ -10,14 +9,12 @@
 | 
			
		||||
#Consumer Key
 | 
			
		||||
#OVH_CK="sdfsdfsdfsdfsdfdsf"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#OVH_END_POINT=ovh-eu
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#'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'
 | 
			
		||||
@@ -35,121 +32,118 @@ SYS_CA='https://ca.api.soyoustart.com/1.0'
 | 
			
		||||
#'runabove-ca'
 | 
			
		||||
RAV_CA='https://api.runabove.com/1.0'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
wiki="https://github.com/Neilpang/acme.sh/wiki/How-to-use-OVH-domain-api"
 | 
			
		||||
 | 
			
		||||
ovh_success="https://github.com/Neilpang/acme.sh/wiki/OVH-Success"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
_ovh_get_api() {
 | 
			
		||||
  _ogaep="$1"
 | 
			
		||||
 | 
			
		||||
  case "${_ogaep}" in
 | 
			
		||||
    
 | 
			
		||||
    ovh-eu|ovheu)
 | 
			
		||||
        printf "%s" $OVH_EU
 | 
			
		||||
        return
 | 
			
		||||
        ;;
 | 
			
		||||
    ovh-ca|ovhca)
 | 
			
		||||
        printf "%s" $OVH_CA
 | 
			
		||||
        return
 | 
			
		||||
        ;;
 | 
			
		||||
    kimsufi-eu|kimsufieu)
 | 
			
		||||
        printf "%s" $KSF_EU
 | 
			
		||||
        return
 | 
			
		||||
        ;;
 | 
			
		||||
    kimsufi-ca|kimsufica)
 | 
			
		||||
        printf "%s" $KSF_CA
 | 
			
		||||
        return
 | 
			
		||||
        ;;
 | 
			
		||||
    soyoustart-eu|soyoustarteu)
 | 
			
		||||
        printf "%s" $SYS_EU
 | 
			
		||||
        return
 | 
			
		||||
        ;;
 | 
			
		||||
    soyoustart-ca|soyoustartca)
 | 
			
		||||
        printf "%s" $SYS_CA
 | 
			
		||||
        return
 | 
			
		||||
        ;;      
 | 
			
		||||
    runabove-ca|runaboveca)
 | 
			
		||||
        printf "%s" $RAV_CA
 | 
			
		||||
        return
 | 
			
		||||
        ;;       
 | 
			
		||||
        
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
    ovh-eu | ovheu)
 | 
			
		||||
      printf "%s" $OVH_EU
 | 
			
		||||
      return
 | 
			
		||||
      ;;
 | 
			
		||||
    ovh-ca | ovhca)
 | 
			
		||||
      printf "%s" $OVH_CA
 | 
			
		||||
      return
 | 
			
		||||
      ;;
 | 
			
		||||
    kimsufi-eu | kimsufieu)
 | 
			
		||||
      printf "%s" $KSF_EU
 | 
			
		||||
      return
 | 
			
		||||
      ;;
 | 
			
		||||
    kimsufi-ca | kimsufica)
 | 
			
		||||
      printf "%s" $KSF_CA
 | 
			
		||||
      return
 | 
			
		||||
      ;;
 | 
			
		||||
    soyoustart-eu | soyoustarteu)
 | 
			
		||||
      printf "%s" $SYS_EU
 | 
			
		||||
      return
 | 
			
		||||
      ;;
 | 
			
		||||
    soyoustart-ca | soyoustartca)
 | 
			
		||||
      printf "%s" $SYS_CA
 | 
			
		||||
      return
 | 
			
		||||
      ;;
 | 
			
		||||
    runabove-ca | runaboveca)
 | 
			
		||||
      printf "%s" $RAV_CA
 | 
			
		||||
      return
 | 
			
		||||
      ;;
 | 
			
		||||
 | 
			
		||||
    *)
 | 
			
		||||
        _err "Unknown parameter : $1"
 | 
			
		||||
        return 1
 | 
			
		||||
        ;;
 | 
			
		||||
    esac
 | 
			
		||||
 | 
			
		||||
      _err "Unknown parameter : $1"
 | 
			
		||||
      return 1
 | 
			
		||||
      ;;
 | 
			
		||||
  esac
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
 | 
			
		||||
#Usage: add  _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_ovh_add(){
 | 
			
		||||
dns_ovh_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
  
 | 
			
		||||
  if [ -z "$OVH_AK" ] || [ -z "$OVH_AS" ] ; then
 | 
			
		||||
 | 
			
		||||
  if [ -z "$OVH_AK" ] || [ -z "$OVH_AS" ]; then
 | 
			
		||||
    OVH_AK=""
 | 
			
		||||
    OVH_AS=""
 | 
			
		||||
    _err "You don't specify OVH application key and application secret yet."
 | 
			
		||||
    _err "Please create you key and try again."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  #save the api key and email to the account conf file.
 | 
			
		||||
  _saveaccountconf OVH_AK "$OVH_AK"
 | 
			
		||||
  _saveaccountconf OVH_AS "$OVH_AS"
 | 
			
		||||
  
 | 
			
		||||
  
 | 
			
		||||
  if [ -z "$OVH_END_POINT" ] ; then
 | 
			
		||||
 | 
			
		||||
  if [ -z "$OVH_END_POINT" ]; then
 | 
			
		||||
    OVH_END_POINT="ovh-eu"
 | 
			
		||||
  fi
 | 
			
		||||
  _info "Using OVH endpoint: $OVH_END_POINT"
 | 
			
		||||
  if [ "$OVH_END_POINT" != "ovh-eu" ] ; then
 | 
			
		||||
  _saveaccountconf OVH_END_POINT "$OVH_END_POINT"
 | 
			
		||||
  if [ "$OVH_END_POINT" != "ovh-eu" ]; then
 | 
			
		||||
    _saveaccountconf OVH_END_POINT "$OVH_END_POINT"
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
  OVH_API="$(_ovh_get_api $OVH_END_POINT )"
 | 
			
		||||
 | 
			
		||||
  OVH_API="$(_ovh_get_api $OVH_END_POINT)"
 | 
			
		||||
  _debug OVH_API "$OVH_API"
 | 
			
		||||
 | 
			
		||||
  if [ -z "$OVH_CK" ] ; then
 | 
			
		||||
  if [ -z "$OVH_CK" ]; then
 | 
			
		||||
    _info "OVH consumer key is empty, Let's get one:"
 | 
			
		||||
    if ! _ovh_authentication ; then
 | 
			
		||||
    if ! _ovh_authentication; then
 | 
			
		||||
      _err "Can not get consumer key."
 | 
			
		||||
    fi
 | 
			
		||||
    #return and wait for retry.
 | 
			
		||||
    return 1;
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  _info "Checking authentication"
 | 
			
		||||
  
 | 
			
		||||
  response="$(_ovh_rest GET "domain/")"
 | 
			
		||||
  if _contains "$response" "INVALID_CREDENTIAL" ; then
 | 
			
		||||
 | 
			
		||||
  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."
 | 
			
		||||
    _clearaccountconf  OVH_CK
 | 
			
		||||
    _clearaccountconf OVH_CK
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _info "Consumer key is ok."
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root $fulldomain ; then
 | 
			
		||||
  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"
 | 
			
		||||
  _ovh_rest GET "domain/zone/$_domain/record?fieldType=TXT&subDomain=$_sub_domain"
 | 
			
		||||
    
 | 
			
		||||
  if  _contains "$response" '\[\]' || _contains "$response" "This service does not exist" ; then
 | 
			
		||||
 | 
			
		||||
  if _contains "$response" '\[\]' || _contains "$response" "This service does not exist"; then
 | 
			
		||||
    _info "Adding record"
 | 
			
		||||
    if _ovh_rest POST "domain/zone/$_domain/record"  "{\"fieldType\":\"TXT\",\"subDomain\":\"$_sub_domain\",\"target\":\"$txtvalue\",\"ttl\":60}"; then
 | 
			
		||||
      if _contains "$response" "$txtvalue" ; then
 | 
			
		||||
    if _ovh_rest POST "domain/zone/$_domain/record" "{\"fieldType\":\"TXT\",\"subDomain\":\"$_sub_domain\",\"target\":\"$txtvalue\",\"ttl\":60}"; then
 | 
			
		||||
      if _contains "$response" "$txtvalue"; then
 | 
			
		||||
        _ovh_rest POST "domain/zone/$_domain/refresh"
 | 
			
		||||
        _debug "Refresh:$response"
 | 
			
		||||
        _info "Added, sleeping 10 seconds"
 | 
			
		||||
@@ -161,93 +155,96 @@ dns_ovh_add(){
 | 
			
		||||
  else
 | 
			
		||||
    _info "Updating record"
 | 
			
		||||
    record_id=$(printf "%s" "$response" | tr -d "[]" | cut -d , -f 1)
 | 
			
		||||
    if [ -z "$record_id" ] ; then
 | 
			
		||||
    if [ -z "$record_id" ]; then
 | 
			
		||||
      _err "Can not get record id."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    _debug "record_id" $record_id
 | 
			
		||||
    _debug "record_id" "$record_id"
 | 
			
		||||
 | 
			
		||||
    if _ovh_rest PUT "domain/zone/$_domain/record/$record_id"  "{\"target\":\"$txtvalue\",\"subDomain\":\"$_sub_domain\",\"ttl\":60}" ; then
 | 
			
		||||
      if _contains "$response" "null" ; then
 | 
			
		||||
    if _ovh_rest PUT "domain/zone/$_domain/record/$record_id" "{\"target\":\"$txtvalue\",\"subDomain\":\"$_sub_domain\",\"ttl\":60}"; then
 | 
			
		||||
      if _contains "$response" "null"; then
 | 
			
		||||
        _ovh_rest POST "domain/zone/$_domain/refresh"
 | 
			
		||||
        _debug "Refresh:$response"
 | 
			
		||||
        _info "Updated, sleeping 10 seconds"
 | 
			
		||||
        sleep 10
 | 
			
		||||
        return 0;
 | 
			
		||||
        return 0
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
    _err "Update error"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#fulldomain
 | 
			
		||||
dns_ovh_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
 | 
			
		||||
####################  Private functions bellow ##################################
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
 | 
			
		||||
_ovh_authentication() {
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  _H1="X-Ovh-Application: $OVH_AK"
 | 
			
		||||
  _H2="Content-type: application/json"
 | 
			
		||||
  _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"
 | 
			
		||||
  validationUrl="$(echo "$response" | _egrep_o "validationUrl\":\"[^\"]*\"" | _egrep_o "http.*\"" | tr -d '"')"
 | 
			
		||||
  if [ -z "$validationUrl" ] ; then
 | 
			
		||||
  if [ -z "$validationUrl" ]; then
 | 
			
		||||
    _err "Unable to get validationUrl"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug validationUrl "$validationUrl"
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  consumerKey="$(echo "$response" | _egrep_o "consumerKey\":\"[^\"]*\"" | cut -d : -f 2 | tr -d '"')"
 | 
			
		||||
  if [ -z "$consumerKey" ] ; then
 | 
			
		||||
  if [ -z "$consumerKey" ]; then
 | 
			
		||||
    _err "Unable to get consumerKey"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug consumerKey "$consumerKey"
 | 
			
		||||
  
 | 
			
		||||
  _secure_debug consumerKey "$consumerKey"
 | 
			
		||||
 | 
			
		||||
  OVH_CK="$consumerKey"
 | 
			
		||||
  _saveaccountconf OVH_CK "$OVH_CK"
 | 
			
		||||
  
 | 
			
		||||
  _info "Please open this link to do authentication: $(__green "$validationUrl" )"
 | 
			
		||||
 | 
			
		||||
  _info "Here is a guide for you: $(__green "$wiki" )"
 | 
			
		||||
  _info "Please open this link to do authentication: $(__green "$validationUrl")"
 | 
			
		||||
 | 
			
		||||
  _info "Here is a guide for you: $(__green "$wiki")"
 | 
			
		||||
  _info "Please retry after the authentication is done."
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#_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
 | 
			
		||||
  while [ '1' ] ; do
 | 
			
		||||
    h=$(printf $domain | cut -d . -f $i-100)
 | 
			
		||||
    if [ -z "$h" ] ; then
 | 
			
		||||
  while true; do
 | 
			
		||||
    h=$(printf "%s" "$domain" | cut -d . -f $i-100)
 | 
			
		||||
    if [ -z "$h" ]; then
 | 
			
		||||
      #not valid
 | 
			
		||||
      return 1;
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
    if ! _ovh_rest GET "domain/zone/$h" ; then
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
    if ! _contains "$response" "This service does not exist" >/dev/null ; then
 | 
			
		||||
      _sub_domain=$(printf $domain | cut -d . -f 1-$p)
 | 
			
		||||
      _domain=$h
 | 
			
		||||
 | 
			
		||||
    if ! _ovh_rest GET "domain/zone/$h"; then
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
    fi
 | 
			
		||||
    p=$i
 | 
			
		||||
    i=$(expr $i + 1)
 | 
			
		||||
    i=$(_math "$i" + 1)
 | 
			
		||||
  done
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
@@ -265,38 +262,34 @@ _ovh_rest() {
 | 
			
		||||
  m=$1
 | 
			
		||||
  ep="$2"
 | 
			
		||||
  data="$3"
 | 
			
		||||
  _debug $ep
 | 
			
		||||
  
 | 
			
		||||
  
 | 
			
		||||
  _debug "$ep"
 | 
			
		||||
 | 
			
		||||
  _ovh_url="$OVH_API/$ep"
 | 
			
		||||
  _debug2 _ovh_url "$_ovh_url"
 | 
			
		||||
  _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"
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  _H1="X-Ovh-Application: $OVH_AK"
 | 
			
		||||
  _H2="X-Ovh-Signature: \$1\$$_ovh_hex"
 | 
			
		||||
  export _H1="X-Ovh-Application: $OVH_AK"
 | 
			
		||||
  export _H2="X-Ovh-Signature: \$1\$$_ovh_hex"
 | 
			
		||||
  _debug2 _H2 "$_H2"
 | 
			
		||||
  _H3="X-Ovh-Timestamp: $_ovh_t"
 | 
			
		||||
  _H4="X-Ovh-Consumer: $OVH_CK"
 | 
			
		||||
  _H5="Content-Type: application/json;charset=utf-8"
 | 
			
		||||
  if [ "$data" ] || [ "$m" = "POST" ] || [ "$m" = "PUT" ] ; then
 | 
			
		||||
  export _H3="X-Ovh-Timestamp: $_ovh_t"
 | 
			
		||||
  export _H4="X-Ovh-Consumer: $OVH_CK"
 | 
			
		||||
  export _H5="Content-Type: application/json;charset=utf-8"
 | 
			
		||||
  if [ "$data" ] || [ "$m" = "POST" ] || [ "$m" = "PUT" ]; then
 | 
			
		||||
    _debug data "$data"
 | 
			
		||||
    response="$(_post "$data" "$_ovh_url" "" $m)"
 | 
			
		||||
    response="$(_post "$data" "$_ovh_url" "" "$m")"
 | 
			
		||||
  else
 | 
			
		||||
    response="$(_get "$_ovh_url")"
 | 
			
		||||
  fi
 | 
			
		||||
  
 | 
			
		||||
  if [ "$?" != "0" ] ; then
 | 
			
		||||
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "error $ep"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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"
 | 
			
		||||
@@ -12,49 +12,72 @@ DEFAULT_PDNS_TTL=60
 | 
			
		||||
 | 
			
		||||
########  Public functions #####################
 | 
			
		||||
#Usage: add _acme-challenge.www.domain.com "123456789ABCDEF0000000000000000000000000000000000000"
 | 
			
		||||
#fulldomain
 | 
			
		||||
#txtvalue
 | 
			
		||||
dns_pdns_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  if [ -z "$PDNS_Url" ] ; then
 | 
			
		||||
  if [ -z "$PDNS_Url" ]; then
 | 
			
		||||
    PDNS_Url=""
 | 
			
		||||
    _err "You don't specify PowerDNS address."
 | 
			
		||||
    _err "Please set PDNS_Url and try again."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "$PDNS_ServerId" ] ; then
 | 
			
		||||
  if [ -z "$PDNS_ServerId" ]; then
 | 
			
		||||
    PDNS_ServerId=""
 | 
			
		||||
    _err "You don't specify PowerDNS server id."
 | 
			
		||||
    _err "Please set you PDNS_ServerId and try again."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "$PDNS_Token" ] ; then
 | 
			
		||||
  if [ -z "$PDNS_Token" ]; then
 | 
			
		||||
    PDNS_Token=""
 | 
			
		||||
    _err "You don't specify PowerDNS token."
 | 
			
		||||
    _err "Please create you PDNS_Token and try again."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ -z "$PDNS_Ttl" ] ; then
 | 
			
		||||
    PDNS_Ttl=$DEFAULT_PDNS_TTL
 | 
			
		||||
  if [ -z "$PDNS_Ttl" ]; then
 | 
			
		||||
    PDNS_Ttl="$DEFAULT_PDNS_TTL"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  #save the api addr and key to the account conf file.
 | 
			
		||||
  _saveaccountconf PDNS_Url "$PDNS_Url"
 | 
			
		||||
  _saveaccountconf PDNS_ServerId "$PDNS_ServerId"
 | 
			
		||||
  _saveaccountconf PDNS_Token "$PDNS_Token"
 | 
			
		||||
  
 | 
			
		||||
  if [ "$PDNS_Ttl" != "$DEFAULT_PDNS_TTL" ] ; then
 | 
			
		||||
 | 
			
		||||
  if [ "$PDNS_Ttl" != "$DEFAULT_PDNS_TTL" ]; then
 | 
			
		||||
    _saveaccountconf PDNS_Ttl "$PDNS_Ttl"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root $fulldomain ; then
 | 
			
		||||
  _debug "Detect root zone"
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "invalid domain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug _domain "$_domain"
 | 
			
		||||
 | 
			
		||||
  if ! set_record "$_domain" "$fulldomain" "$txtvalue" ; then
 | 
			
		||||
  if ! set_record "$_domain" "$fulldomain" "$txtvalue"; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#fulldomain
 | 
			
		||||
dns_pdns_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
 | 
			
		||||
  _debug "Detect root zone"
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    _err "invalid domain"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug _domain "$_domain"
 | 
			
		||||
 | 
			
		||||
  if ! rm_record "$_domain" "$fulldomain"; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
@@ -67,45 +90,73 @@ set_record() {
 | 
			
		||||
  full=$2
 | 
			
		||||
  txtvalue=$3
 | 
			
		||||
 | 
			
		||||
  if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root." "{\"rrsets\": [{\"name\": \"$full.\", \"changetype\": \"REPLACE\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [{\"name\": \"$full.\", \"type\": \"TXT\", \"content\": \"\\\"$txtvalue\\\"\", \"disabled\": false, \"ttl\": $PDNS_Ttl}]}]}" ; then
 | 
			
		||||
  if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root." "{\"rrsets\": [{\"changetype\": \"REPLACE\", \"name\": \"$full.\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [{\"name\": \"$full.\", \"type\": \"TXT\", \"content\": \"\\\"$txtvalue\\\"\", \"disabled\": false, \"ttl\": $PDNS_Ttl}]}]}"; then
 | 
			
		||||
    _err "Set txt record error."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  if ! _pdns_rest "PUT" "/api/v1/servers/$PDNS_ServerId/zones/$root./notify" ; then
 | 
			
		||||
    _err "Notify servers error."
 | 
			
		||||
 | 
			
		||||
  if ! notify_slaves "$root"; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions bellow ##################################
 | 
			
		||||
rm_record() {
 | 
			
		||||
  _info "Remove record"
 | 
			
		||||
  root=$1
 | 
			
		||||
  full=$2
 | 
			
		||||
 | 
			
		||||
  if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root." "{\"rrsets\": [{\"changetype\": \"DELETE\", \"name\": \"$full.\", \"type\": \"TXT\"}]}"; then
 | 
			
		||||
    _err "Delete txt record error."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! notify_slaves "$root"; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
notify_slaves() {
 | 
			
		||||
  root=$1
 | 
			
		||||
 | 
			
		||||
  if ! _pdns_rest "PUT" "/api/v1/servers/$PDNS_ServerId/zones/$root./notify"; then
 | 
			
		||||
    _err "Notify slaves error."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
#_acme-challenge.www.domain.com
 | 
			
		||||
#returns
 | 
			
		||||
# _domain=domain.com
 | 
			
		||||
_get_root() {
 | 
			
		||||
  domain=$1
 | 
			
		||||
  i=1
 | 
			
		||||
  p=1
 | 
			
		||||
 | 
			
		||||
  if _pdns_rest "GET" "/api/v1/servers/$PDNS_ServerId/zones" ; then
 | 
			
		||||
    _zones_response=$response
 | 
			
		||||
  if _pdns_rest "GET" "/api/v1/servers/$PDNS_ServerId/zones"; then
 | 
			
		||||
    _zones_response="$response"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  while [ '1' ] ; do
 | 
			
		||||
    h=$(printf $domain | cut -d . -f $i-100)
 | 
			
		||||
    if [ -z "$h" ] ; then
 | 
			
		||||
  while true; do
 | 
			
		||||
    h=$(printf "%s" "$domain" | cut -d . -f $i-100)
 | 
			
		||||
    if [ -z "$h" ]; then
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if printf "$_zones_response" | grep "\"name\": \"$h.\"" >/dev/null ; then
 | 
			
		||||
      _domain=$h
 | 
			
		||||
    if _contains "$_zones_response" "\"name\": \"$h.\""; then
 | 
			
		||||
      _domain="$h"
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    p=$i
 | 
			
		||||
    i=$(expr $i + 1)
 | 
			
		||||
    i=$(_math $i + 1)
 | 
			
		||||
  done
 | 
			
		||||
  _debug "$domain not found"
 | 
			
		||||
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -114,20 +165,20 @@ _pdns_rest() {
 | 
			
		||||
  ep=$2
 | 
			
		||||
  data=$3
 | 
			
		||||
 | 
			
		||||
  _H1="X-API-Key: $PDNS_Token"
 | 
			
		||||
  export _H1="X-API-Key: $PDNS_Token"
 | 
			
		||||
 | 
			
		||||
  if [ ! "$method" = "GET" ] ; then
 | 
			
		||||
  if [ ! "$method" = "GET" ]; then
 | 
			
		||||
    _debug data "$data"
 | 
			
		||||
    response="$(_post "$data" "$PDNS_Url$ep" "" "$method")"
 | 
			
		||||
  else
 | 
			
		||||
    response="$(_get "$PDNS_Url$ep")"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ "$?" != "0" ] ; then
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "error $ep"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user