add template, implement auth and zones
This commit is contained in:
		
							parent
							
								
									3e67322d69
								
							
						
					
					
						commit
						22c1e761e0
					
				
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1,3 +1,7 @@ | ||||
| *.json | ||||
| service_account.json | ||||
| credentials.json | ||||
| 
 | ||||
| # ---> Node | ||||
| # Logs | ||||
| logs | ||||
|  | ||||
							
								
								
									
										28
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								README.md
									
									
									
									
									
								
							| @ -1,3 +1,29 @@ | ||||
| # acme-dns-01-googlecloud.js | ||||
| 
 | ||||
| Google Cloud DNS for Let's Encrypt / ACME dns-01 challenges with ACME.js and Greenlock.js | ||||
| Google Domains + Let's Encrypt for Node.js - ACME dns-01 challenges w/ ACME.js and Greenlock.js | ||||
| 
 | ||||
| In Progress. Would love help. Please contact @coolaj86 on Keybase. | ||||
| 
 | ||||
| -   [x] zones | ||||
| -   [ ] set | ||||
| -   [ ] get | ||||
| -   [ ] remove | ||||
| 
 | ||||
| Implementation Details | ||||
| 
 | ||||
| -   https://cloud.google.com/dns/docs/reference/v1/ | ||||
| -   https://cloud.google.com/service-usage/docs/getting-started#api | ||||
| -   https://github.com/google/oauth2l | ||||
| 
 | ||||
| # Usage | ||||
| 
 | ||||
| First you create an instance with your credentials: | ||||
| 
 | ||||
| ```js | ||||
| var dns01 = require('acme-dns-01-googlecloud').create({ | ||||
| 	baseUrl: 'https://www.googleapis.com/dns/v1/', // default | ||||
| 
 | ||||
|   // contains private_key, private_key_id, project_id, and client_email | ||||
| 	serviceAccountPath: __dirname + '/service_account.json' | ||||
| }); | ||||
| ``` | ||||
|  | ||||
							
								
								
									
										3
									
								
								example.env
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								example.env
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| # NOT credentials.json | ||||
| GOOGLE_APPLICATION_CREDENTIALS=/Users/me/service_account.json | ||||
| ZONE=example.co.uk | ||||
							
								
								
									
										3
									
								
								index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								index.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| 'use strict'; | ||||
| 
 | ||||
| module.exports = require('./lib/index.js'); | ||||
							
								
								
									
										36
									
								
								lib/auth.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								lib/auth.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | ||||
| 'use strict'; | ||||
| 
 | ||||
| var Keypairs = require('keypairs'); | ||||
| 
 | ||||
| module.exports.getToken = function(serviceAccount) { | ||||
| 	var jwt = ''; | ||||
| 	var exp = 0; | ||||
| 
 | ||||
| 	if (exp - Date.now() > 0) { | ||||
| 		return Promise.resolve(jwt); | ||||
| 	} | ||||
| 
 | ||||
| 	return module.exports.generateToken(serviceAccount).then(function(_jwt) { | ||||
| 		jwt = _jwt; | ||||
| 		exp = Math.round(Date.now()) - 15 * 60 * 60 * 1000; | ||||
| 		return jwt; | ||||
| 	}); | ||||
| }; | ||||
| 
 | ||||
| module.exports.generateToken = function(serviceAccount) { | ||||
| 	var sa = serviceAccount; | ||||
| 	return Keypairs.import({ pem: sa.private_key }).then(function(key) { | ||||
| 		return Keypairs.signJwt({ | ||||
| 			jwk: key, | ||||
| 			iss: sa.client_email, | ||||
| 			exp: '1h', | ||||
| 			header: { | ||||
| 				kid: sa.private_key_id | ||||
| 			}, | ||||
| 			claims: { | ||||
| 				aud: 'ndev.clouddns.readwrite', | ||||
| 				sub: sa.client_email | ||||
| 			} | ||||
| 		}); | ||||
| 	}); | ||||
| }; | ||||
							
								
								
									
										74
									
								
								lib/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								lib/index.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,74 @@ | ||||
| 'use strict'; | ||||
| 
 | ||||
| var auth = require('./auth.js'); | ||||
| var defaults = { | ||||
| 	baseUrl: 'https://www.googleapis.com/dns/v1/' | ||||
| }; | ||||
| 
 | ||||
| module.exports.create = function(config) { | ||||
| 	var request; | ||||
| 	var baseUrl = (config.baseUrl || defaults.baseUrl).replace(/\/$/, ''); | ||||
| 	var sa = getServiceAccount(config); | ||||
| 
 | ||||
| 	return { | ||||
| 		init: function(opts) { | ||||
| 			request = opts.request; | ||||
| 			return null; | ||||
| 		}, | ||||
| 		zones: function(data) { | ||||
| 			//console.info('List Zones', data);
 | ||||
| 			return api({ | ||||
| 				url: baseUrl + '/projects/' + sa.project_id + '/managedZones', | ||||
| 				json: true | ||||
| 			}).then(function(resp) { | ||||
| 				return resp.body.managedZones.map(function(zone) { | ||||
| 					// slice out the leading and trailing single quotes, and the trailing dot
 | ||||
| 					// (assuming that all 'dnsName's probably look the same)
 | ||||
| 					return zone.dnsName.slice(1, zone.dnsName.length - 2); | ||||
| 				}); | ||||
| 			}); | ||||
| 		}, | ||||
| 		set: function(data) { | ||||
| 			// console.info('Add TXT', data);
 | ||||
| 			throw Error('setting TXT not implemented'); | ||||
| 		}, | ||||
| 		remove: function(data) { | ||||
| 			// console.info('Remove TXT', data);
 | ||||
| 			throw Error('removing TXT not implemented'); | ||||
| 		}, | ||||
| 		get: function(data) { | ||||
| 			// console.info('List TXT', data);
 | ||||
| 			throw Error('listing TXTs not implemented'); | ||||
| 		} | ||||
| 	}; | ||||
| 
 | ||||
| 	function api(opts) { | ||||
| 		return auth.getToken(sa).then(function(token) { | ||||
| 			opts.headers = opts.headers || {}; | ||||
| 			opts.headers.Authorization = 'Bearer ' + token; | ||||
| 			return request(opts); | ||||
| 		}); | ||||
| 	} | ||||
| 
 | ||||
| 	function getServiceAccount(config) { | ||||
| 		var saPath = | ||||
| 			config.serviceAccountPath || | ||||
| 			process.env.GOOGLE_APPLICATION_CREDENTIALS; | ||||
| 		var sa = config.serviceAccount || require(saPath); | ||||
| 
 | ||||
| 		if ( | ||||
| 			!sa || | ||||
| 			!( | ||||
| 				sa.private_key && | ||||
| 				sa.private_key_id && | ||||
| 				sa.client_email && | ||||
| 				sa.project_id | ||||
| 			) | ||||
| 		) { | ||||
| 			throw new Error( | ||||
| 				'missing or incomplete service_account.json: set serviceAccount serviceAccountPath' | ||||
| 			); | ||||
| 		} | ||||
| 		return sa; | ||||
| 	} | ||||
| }; | ||||
							
								
								
									
										37
									
								
								test.js
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										37
									
								
								test.js
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,37 @@ | ||||
| #!/usr/bin/env node
 | ||||
| 'use strict'; | ||||
| 
 | ||||
| // See https://git.coolaj86.com/coolaj86/acme-challenge-test.js
 | ||||
| var tester = require('acme-challenge-test'); | ||||
| require('dotenv').config(); | ||||
| 
 | ||||
| // Usage: node ./test.js example.com xxxxxxxxx
 | ||||
| var zone = process.argv[2] || process.env.ZONE; | ||||
| var config = { | ||||
| 	serviceAccountPath: | ||||
| 		process.argv[3] || process.env.GOOGLE_APPLICATION_CREDENTIALS | ||||
| }; | ||||
| var challenger = require('./index.js').create(config); | ||||
| 
 | ||||
| // Google has its own special authentication
 | ||||
| var sa = require(config.serviceAccountPath); | ||||
| require('./lib/auth.js') | ||||
| 	.getToken(sa) | ||||
| 	.then(function(jwt) { | ||||
| 		console.info('\nAuthorization: Bearer ' + jwt + '\n'); | ||||
| 
 | ||||
| 		// The dry-run tests can pass on, literally, 'example.com'
 | ||||
| 		// but the integration tests require that you have control over the domain
 | ||||
| 		return tester | ||||
| 			.testZone('dns-01', zone, challenger) | ||||
| 			.then(function() { | ||||
| 				console.info('PASS', zone); | ||||
| 			}) | ||||
| 			.catch(function(e) { | ||||
| 				console.error(e.message); | ||||
| 				console.error(e.stack); | ||||
| 			}); | ||||
| 	}) | ||||
| 	.catch(function(err) { | ||||
| 		console.error(err.stack); | ||||
| 	}); | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user