2019-01-06 19:41:21 +00:00
|
|
|
import * as plugins from './smartacme.plugins';
|
2017-01-14 13:14:50 +00:00
|
|
|
|
2019-01-06 19:41:21 +00:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
export interface ISmartAcmeStorage {}
|
2017-01-01 23:18:51 +00:00
|
|
|
|
2019-01-06 19:41:21 +00:00
|
|
|
export class SmartAcme {
|
|
|
|
// the acme client
|
|
|
|
private client: any;
|
2016-11-01 19:16:43 +00:00
|
|
|
|
2019-01-06 19:41:21 +00:00
|
|
|
// the account private key
|
|
|
|
private privateKey: string;
|
2016-11-07 17:41:52 +00:00
|
|
|
|
2019-01-06 19:41:21 +00:00
|
|
|
// challenge fullfillment
|
|
|
|
private setChallenge: (authz, challenge, keyAuthorization) => Promise<any>;
|
|
|
|
private removeChallenge: (authz, challenge, keyAuthorization) => Promise<any>;
|
2016-11-01 19:16:43 +00:00
|
|
|
|
2019-01-06 19:41:21 +00:00
|
|
|
public async init(optionsArg: {
|
|
|
|
accountPrivateKey?: string;
|
|
|
|
accountEmail: string;
|
|
|
|
setChallenge: (authz, challenge, keyAuthorization) => Promise<any>;
|
|
|
|
removeChallenge: (authz, challenge, keyAuthorization) => Promise<any>;
|
|
|
|
}) {
|
|
|
|
this.privateKey = optionsArg.accountPrivateKey || (await plugins.acme.forge.createPrivateKey());
|
|
|
|
this.setChallenge = optionsArg.setChallenge;
|
|
|
|
this.removeChallenge = optionsArg.removeChallenge;
|
|
|
|
this.client = new plugins.acme.Client({
|
|
|
|
directoryUrl: plugins.acme.directory.letsencrypt.staging,
|
|
|
|
accountKey: this.privateKey
|
|
|
|
});
|
|
|
|
|
|
|
|
/* Register account */
|
|
|
|
await this.client.createAccount({
|
|
|
|
termsOfServiceAgreed: true,
|
|
|
|
contact: [`mailto:${optionsArg.accountEmail}`]
|
|
|
|
});
|
2018-08-11 23:35:14 +00:00
|
|
|
}
|
|
|
|
|
2019-01-06 19:41:21 +00:00
|
|
|
public async getCertificateForDomain(domainArg: string) {
|
|
|
|
const domain = domainArg;
|
|
|
|
|
|
|
|
/* Place new order */
|
|
|
|
const order = await this.client.createOrder({
|
|
|
|
identifiers: [{ type: 'dns', value: domain }, { type: 'dns', value: `*.${domain}` }]
|
|
|
|
});
|
|
|
|
|
|
|
|
/* Get authorizations and select challenges */
|
|
|
|
const authorizations = await this.client.getAuthorizations(order);
|
|
|
|
|
|
|
|
const promises = authorizations.map(async authz => {
|
|
|
|
const challenge = authz.challenges.pop();
|
|
|
|
const keyAuthorization = await this.client.getChallengeKeyAuthorization(challenge);
|
|
|
|
|
|
|
|
try {
|
|
|
|
/* Satisfy challenge */
|
|
|
|
await this.setChallenge(authz, challenge, keyAuthorization);
|
|
|
|
|
|
|
|
/* Verify that challenge is satisfied */
|
|
|
|
await this.client.verifyChallenge(authz, challenge);
|
|
|
|
|
|
|
|
/* Notify ACME provider that challenge is satisfied */
|
|
|
|
await this.client.completeChallenge(challenge);
|
|
|
|
|
|
|
|
/* Wait for ACME provider to respond with valid status */
|
|
|
|
await this.client.waitForValidStatus(challenge);
|
|
|
|
} finally {
|
|
|
|
/* Clean up challenge response */
|
|
|
|
try {
|
|
|
|
await this.removeChallenge(authz, challenge, keyAuthorization);
|
|
|
|
} catch (e) {
|
|
|
|
console.log(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
/* Wait for challenges to complete */
|
|
|
|
await Promise.all(promises);
|
|
|
|
|
|
|
|
/* Finalize order */
|
|
|
|
const [key, csr] = await plugins.acme.forge.createCsr({
|
|
|
|
commonName: `*.${domain}`,
|
|
|
|
altNames: [domain]
|
|
|
|
});
|
|
|
|
|
|
|
|
await this.client.finalizeOrder(order, csr);
|
|
|
|
const cert = await this.client.getCertificate(order);
|
|
|
|
|
|
|
|
/* Done */
|
|
|
|
console.log(`CSR:\n${csr.toString()}`);
|
|
|
|
console.log(`Private key:\n${key.toString()}`);
|
|
|
|
console.log(`Certificate:\n${cert.toString()}`);
|
2017-04-28 16:56:55 +00:00
|
|
|
}
|
2019-01-06 19:41:21 +00:00
|
|
|
|
|
|
|
toStorageObject () {};
|
2016-11-01 17:27:57 +00:00
|
|
|
}
|