Skip to content

Commit

Permalink
Created ACME service to phase out other services
Browse files Browse the repository at this point in the history
  • Loading branch information
FLYBYME authored Sep 2, 2023
1 parent 2743086 commit b1172ce
Show file tree
Hide file tree
Showing 3 changed files with 825 additions and 0 deletions.
237 changes: 237 additions & 0 deletions services/certificates.account-keys.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
"use strict";

const acme = require('acme-client');
const DbService = require("db-mixin");
const ConfigLoader = require("config-mixin");
const { MoleculerClientError } = require("moleculer").Errors;


/**
* service for managing acme account keys for Let's Encrypt and other ACME providers
*
* @name v1.certificates.account-keys
* @version 1.0.0
* @fires "v1.certificates.account-keys.created"
* @fires "v1.certificates.account-keys.updated"
* @fires "v1.certificates.account-keys.removed"
* @mixin DbService ConfigLoader
*/

module.exports = {
// name of service
name: "certificates.account-keys",
// version of service
version: 1,

/**
* Service Mixins
*
* @type {Array}
* @property {DbService} DbService - Database mixin
* @property {ConfigLoader} ConfigLoader - Config loader mixin
*/
mixins: [
DbService({}),
ConfigLoader(['certificates.**']),
],

/**
* Service dependencies
*/
dependencies: [],

/**
* Service settings
*
* @type {Object}
*/
settings: {
rest: true,

fields: {
privkey: {
type: "string",
required: true,
trim: true,
empty: false,
secure: true,
},
chain: {
type: "string",
required: true,
trim: true,
empty: false,
secure: true,
},
cert: {
type: "string",
required: true,
trim: true,
empty: false,
secure: true,
},
environment: {
type: "enum",
default: "production",
values: ["production", "staging"]
},
provider: {
type: "enum",
default: "letsencrypt",
values: ["letsencrypt"]
},
email: {
type: "string",
required: true,
trim: true,
empty: false,
},


...DbService.FIELDS,// inject dbservice fields
},

// default database populates
defaultPopulates: [],

// database scopes
scopes: {
...DbService.SCOPE,// inject dbservice scope
},

// default database scope
defaultScopes: [...DbService.DSCOPE],// inject dbservice dscope

// default init config settings
config: {

}
},

/**
* service actions
*/
actions: {
// create a new account keys for a given email address
// this will be used to create new certificates
// then save the account key to the database
createPrivateKey: {
params: {
email: { type: "string" },
environment: {
type: "enum",
default: "production",
values: ["production", "staging"]
},
provider: {
type: "enum",
default: "letsencrypt",
values: ["letsencrypt"]
}
},
async handler(ctx) {
// get the email address
const { email, environment, provider } = ctx.params;

// lookup email environment and provider in database
const found = await this.findByEmail(ctx, email, environment, provider);

// if found return the account key record
if (found)
throw new MoleculerClientError("Account key already exists", 409, "ACCOUNT_KEY_EXISTS", { email, environment, provider });

// get the provider config from acme module
const environmentConfig = acme[provider][environment];

// create the acme client
const client = new acme.Client({
directoryUrl: environmentConfig.directoryUrl,
accountKey: await acme.forge.createPrivateKey(),
});

// create the account key
const accountKey = await client.createAccount({
termsOfServiceAgreed: true,
contact: [`mailto:${email}`],
});

// get the account key details
const accountKeyDetails = await client.getAccountKey();

// create the account key object
const accountKeyObject = {
privkey: accountKey.privateKeyPem,
chain: accountKeyDetails.chain,
cert: accountKeyDetails.certificate,
environment: environment,
provider: provider,
email: email,
};

// save the account key to the database
const accountKeyRecord = await this.createEntity(ctx, accountKeyObject);

// return the account key record
return accountKeyRecord;
}
},
// retrieve the account key for a given email address, environment and provider
getPrivateKey: {
params: {
email: { type: "string" },
environment: {
type: "enum",
default: "production",
values: ["production", "staging"]
},
provider: {
type: "enum",
default: "letsencrypt",
values: ["letsencrypt"]
}
},
async handler(ctx) {
// get the email address
const { email, environment, provider } = ctx.params;

// lookup email environment and provider in database
const found = await this.findByEmail(ctx, email, environment, provider);

// if found return the account key record
if (found)
return found;

// if not found throw error
throw new MoleculerClientError("Account key not found", 404, "ACCOUNT_KEY_NOT_FOUND", { email, environment, provider });
}
},
},

/**
* service events
*/
events: {

},

/**
* service methods
*/
methods: {
findByEmail(ctx, email, environment, provider) {
// find the account key record by email address
return this.findEntity(null, {
query: {
email: email,
environment: environment,
provider: provider,
},
});
},
}

}




Loading

0 comments on commit b1172ce

Please sign in to comment.