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