certd/packages/core/acme-client/examples/api.js

154 lines
4.3 KiB
JavaScript

/**
* Example of acme.Client API
*/
const acme = require('./../');
function log(m) {
process.stdout.write(`${m}\n`);
}
/**
* Function used to satisfy an ACME challenge
*
* @param {object} authz Authorization object
* @param {object} challenge Selected challenge
* @param {string} keyAuthorization Authorization key
* @returns {Promise}
*/
async function challengeCreateFn(authz, challenge, keyAuthorization) {
/* Do something here */
log(JSON.stringify(authz));
log(JSON.stringify(challenge));
log(keyAuthorization);
}
/**
* Function used to remove an ACME challenge response
*
* @param {object} authz Authorization object
* @param {object} challenge Selected challenge
* @returns {Promise}
*/
async function challengeRemoveFn(authz, challenge, keyAuthorization) {
/* Do something here */
log(JSON.stringify(authz));
log(JSON.stringify(challenge));
log(keyAuthorization);
}
/**
* Main
*/
module.exports = async function() {
/* Init client */
const client = new acme.Client({
directoryUrl: acme.directory.letsencrypt.staging,
accountKey: await acme.crypto.createPrivateKey()
});
/* Register account */
await client.createAccount({
termsOfServiceAgreed: true,
contact: ['mailto:test@example.com']
});
/* Place new order */
const order = await client.createOrder({
identifiers: [
{ type: 'dns', value: 'example.com' },
{ type: 'dns', value: '*.example.com' }
]
});
/**
* authorizations / client.getAuthorizations(order);
* An array with one item per DNS name in the certificate order.
* All items require at least one satisfied challenge before order can be completed.
*/
const authorizations = await client.getAuthorizations(order);
const promises = authorizations.map(async (authz) => {
let challengeCompleted = false;
try {
/**
* challenges / authz.challenges
* An array of all available challenge types for a single DNS name.
* One of these challenges needs to be satisfied.
*/
const { challenges } = authz;
/* Just select any challenge */
const challenge = challenges.pop();
const keyAuthorization = await client.getChallengeKeyAuthorization(challenge);
try {
/* Satisfy challenge */
await challengeCreateFn(authz, challenge, keyAuthorization);
/* Verify that challenge is satisfied */
await client.verifyChallenge(authz, challenge);
/* Notify ACME provider that challenge is satisfied */
await client.completeChallenge(challenge);
challengeCompleted = true;
/* Wait for ACME provider to respond with valid status */
await client.waitForValidStatus(challenge);
}
finally {
/* Clean up challenge response */
try {
await challengeRemoveFn(authz, challenge, keyAuthorization);
}
catch (e) {
/**
* Catch errors thrown by challengeRemoveFn() so the order can
* be finalized, even though something went wrong during cleanup
*/
}
}
}
catch (e) {
/* Deactivate pending authz when unable to complete challenge */
if (!challengeCompleted) {
try {
await client.deactivateAuthorization(authz);
}
catch (f) {
/* Catch and suppress deactivateAuthorization() errors */
}
}
throw e;
}
});
/* Wait for challenges to complete */
await Promise.all(promises);
/* Finalize order */
const [key, csr] = await acme.crypto.createCsr({
commonName: '*.example.com',
altNames: ['example.com']
});
const finalized = await client.finalizeOrder(order, csr);
const cert = await client.getCertificate(finalized);
/* Done */
log(`CSR:\n${csr.toString()}`);
log(`Private key:\n${key.toString()}`);
log(`Certificate:\n${cert.toString()}`);
};