mirror of
				https://github.com/therootcompany/acme.js.git
				synced 2024-11-16 17:29:00 +00:00 
			
		
		
		
	
		
			
	
	
		
			152 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			152 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | async function main() { | ||
|  | 	'use strict'; | ||
|  | 
 | ||
|  | 	require('dotenv').config(); | ||
|  | 
 | ||
|  | 	var fs = require('fs'); | ||
|  | 	// just to trigger the warning message out of the way
 | ||
|  | 	await fs.promises.readFile().catch(function() {}); | ||
|  | 	console.warn('\n'); | ||
|  | 	var MY_DOMAINS = process.env.DOMAINS.split(/[,\s]+/); | ||
|  | 
 | ||
|  | 	// In many cases all three of these are the same (your email)
 | ||
|  | 	// However, this is what they may look like when different:
 | ||
|  | 
 | ||
|  | 	var maintainerEmail = process.env.MAINTAINER_EMAIL; | ||
|  | 	var subscriberEmail = process.env.SUBSCRIBER_EMAIL; | ||
|  | 	//var customerEmail = 'jane.doe@gmail.com';
 | ||
|  | 
 | ||
|  | 	var pkg = require('../package.json'); | ||
|  | 	var packageAgent = 'test-' + pkg.name + '/' + pkg.version; | ||
|  | 
 | ||
|  | 	// Choose either the production or staging URL
 | ||
|  | 
 | ||
|  | 	var directoryUrl = 'https://acme-staging-v02.api.letsencrypt.org/directory'; | ||
|  | 	//var directoryUrl = 'https://acme-v02.api.letsencrypt.org/directory'
 | ||
|  | 
 | ||
|  | 	// This is intended to get at important messages without
 | ||
|  | 	// having to use even lower-level APIs in the code
 | ||
|  | 
 | ||
|  | 	var errors = []; | ||
|  | 	function notify(ev, msg) { | ||
|  | 		if ('error' === ev || 'warning' === ev) { | ||
|  | 			errors.push(ev.toUpperCase() + ' ' + msg.message); | ||
|  | 			return; | ||
|  | 		} | ||
|  | 		// ignore all for now
 | ||
|  | 		console.log(ev, msg.altname || '', msg.status || ''); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	var Keypairs = require('@root/keypairs'); | ||
|  | 
 | ||
|  | 	var ACME = require('../'); | ||
|  | 	var acme = ACME.create({ maintainerEmail, packageAgent, notify }); | ||
|  | 	await acme.init(directoryUrl); | ||
|  | 
 | ||
|  | 	// You only need ONE account key, ever, in most cases
 | ||
|  | 	// save this and keep it safe. ECDSA is preferred.
 | ||
|  | 
 | ||
|  | 	var accountKeypair = await Keypairs.generate({ kty: 'EC', format: 'jwk' }); | ||
|  | 	var accountKey = accountKeypair.private; | ||
|  | 
 | ||
|  | 	// This can be `true` or an async function which presents the terms of use
 | ||
|  | 
 | ||
|  | 	var agreeToTerms = true; | ||
|  | 
 | ||
|  | 	// If you are multi-tenanted or white-labled and need to present the terms of
 | ||
|  | 	// use to the Subscriber running the service, you can do so with a function.
 | ||
|  | 	var agreeToTerms = async function() { | ||
|  | 		return true; | ||
|  | 	}; | ||
|  | 
 | ||
|  | 	console.info('registering new ACME account...'); | ||
|  | 	var account = await acme.accounts.create({ | ||
|  | 		subscriberEmail, | ||
|  | 		agreeToTerms, | ||
|  | 		accountKey | ||
|  | 	}); | ||
|  | 	console.info('created account with id', account.key.kid); | ||
|  | 
 | ||
|  | 	// This is the key used by your WEBSERVER, typically named `privkey.pem`,
 | ||
|  | 	// `key.crt`, or `bundle.pem`. RSA may be preferrable for legacy compatibility.
 | ||
|  | 
 | ||
|  | 	// You can generate it fresh
 | ||
|  | 	var serverKeypair = await Keypairs.generate({ kty: 'RSA', format: 'jwk' }); | ||
|  | 	var serverKey = serverKeypair.private; | ||
|  | 	var serverPem = await Keypairs.export({ jwk: serverKey }); | ||
|  | 	await fs.promises.writeFile('./privkey.pem', serverPem, 'ascii'); | ||
|  | 	console.info('wrote ./privkey.pem'); | ||
|  | 
 | ||
|  | 	// Or you can load it from a file
 | ||
|  | 	var serverPem = await fs.promises.readFile('./privkey.pem', 'ascii'); | ||
|  | 
 | ||
|  | 	var serverKey = await Keypairs.import({ pem: serverPem }); | ||
|  | 
 | ||
|  | 	var CSR = require('@root/csr'); | ||
|  | 	var PEM = require('@root/pem'); | ||
|  | 	var Enc = require('@root/encoding/base64'); | ||
|  | 
 | ||
|  | 	var encoding = 'der'; | ||
|  | 	var typ = 'CERTIFICATE REQUEST'; | ||
|  | 
 | ||
|  | 	var domains = MY_DOMAINS; | ||
|  | 	var csrDer = await CSR.csr({ jwk: serverKey, domains, encoding }); | ||
|  | 	//var csr64 = Enc.bufToBase64(csrDer);
 | ||
|  | 	var csr = PEM.packBlock({ type: typ, bytes: csrDer }); | ||
|  | 
 | ||
|  | 	// You can pick from existing challenge modules
 | ||
|  | 	// which integrate with a variety of popular services
 | ||
|  | 	// or you can create your own.
 | ||
|  | 	//
 | ||
|  | 	// The order of priority will be http-01, tls-alpn-01, dns-01
 | ||
|  | 	// dns-01 will always be used for wildcards
 | ||
|  | 	// dns-01 should be the only option given for local/private domains
 | ||
|  | 
 | ||
|  | 	var challenges = { | ||
|  | 		'dns-01': loadDns01() | ||
|  | 	}; | ||
|  | 
 | ||
|  | 	console.info('validating domain authorization for ' + domains.join(' ')); | ||
|  | 	var pems = await acme.certificates.create({ | ||
|  | 		account, | ||
|  | 		accountKey, | ||
|  | 		csr, | ||
|  | 		domains, | ||
|  | 		challenges | ||
|  | 	}); | ||
|  | 	var fullchain = pems.cert + '\n' + pems.chain + '\n'; | ||
|  | 
 | ||
|  | 	await fs.promises.writeFile('fullchain.pem', fullchain, 'ascii'); | ||
|  | 	console.info('wrote ./fullchain.pem'); | ||
|  | 	if (errors.length) { | ||
|  | 		console.warn(); | ||
|  | 		console.warn('[Warning]'); | ||
|  | 		console.warn('The following warnings and/or errors were encountered:'); | ||
|  | 		console.warn(errors.join('\n')); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | main().catch(function(e) { | ||
|  | 	console.error(e.stack); | ||
|  | }); | ||
|  | 
 | ||
|  | function loadDns01() { | ||
|  | 	var pluginName = process.env.CHALLENGE_PLUGIN; | ||
|  | 	var pluginOptions = process.env.CHALLENGE_OPTIONS; | ||
|  | 	var plugin; | ||
|  | 	if (!pluginOptions) { | ||
|  | 		console.error( | ||
|  | 			'Please create a .env in the format of examples/example.env to run the tests' | ||
|  | 		); | ||
|  | 		process.exit(1); | ||
|  | 	} | ||
|  | 	try { | ||
|  | 		plugin = require(pluginName); | ||
|  | 	} catch (err) { | ||
|  | 		console.error("Couldn't find '" + pluginName + "'. Is it installed?"); | ||
|  | 		console.error("\tnpm install --save-dev '" + pluginName + "'"); | ||
|  | 		process.exit(1); | ||
|  | 	} | ||
|  | 	return plugin.create(JSON.parse(pluginOptions)); | ||
|  | } |