Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(dashmate): cleanup zerossl certs command #2298

Merged
merged 3 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions packages/dashmate/src/commands/ssl/cleanup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Listr } from 'listr2';
import { Flags } from '@oclif/core';
import ConfigBaseCommand from '../../oclif/command/ConfigBaseCommand.js';
import MuteOneLineError from '../../oclif/errors/MuteOneLineError.js';

export default class CleanupCommand extends ConfigBaseCommand {
static description = `Cleanup Zero SSL certificate

Cancel all drafted or pending validation certificates on ZeroSSL
`;

static flags = {
...ConfigBaseCommand.flags,
verbose: Flags.boolean({ char: 'v', description: 'use verbose mode for output', default: false }),
};

/**
* @param {Object} args
* @param {Object} flags
* @param {boolean} flags.verbose
* @param {Config} config
* @param {cleanupZeroSSLCertificatesTask} cleanupZeroSSLCertificatesTask
* @return {Promise<void>}
*/
async runWithDependencies(
args,
{
verbose: isVerbose,
},
config,
cleanupZeroSSLCertificatesTask,
) {
const tasks = new Listr(
[
{
title: 'Cleanup ZeroSSL certificate',
task: () => cleanupZeroSSLCertificatesTask(config),
},
],
{
renderer: isVerbose ? 'verbose' : 'default',
rendererOptions: {
showTimer: isVerbose,
clearOutput: false,
collapse: false,
showSubtasks: true,
removeEmptyLines: false,
},
},
);

try {
await tasks.run();
} catch (e) {
throw new MuteOneLineError(e);
}
}
}
2 changes: 1 addition & 1 deletion packages/dashmate/src/commands/ssl/obtain.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Certificate will be renewed if it is about to expire (see 'expiration-days' flag
[
{
title: 'Obtain ZeroSSL certificate',
task: async () => obtainZeroSSLCertificateTask(config),
task: () => obtainZeroSSLCertificateTask(config),
},
],
{
Expand Down
5 changes: 5 additions & 0 deletions packages/dashmate/src/createDIContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ import analyseSystemResourcesFactory from './doctor/analyse/analyseSystemResourc
import analyseSamplesFactory from './doctor/analyseSamplesFactory.js';
import archiveSamples from './doctor/archiveSamples.js';
import unarchiveSamplesFactory from './doctor/unarchiveSamplesFactory.js';
import cleanupZeroSSLCertificatesTaskFactory
from './listr/tasks/ssl/zerossl/cleanupZeroSSLCertificatesTaskFactory.js';
import cancelCertificate from './ssl/zerossl/cancelCertificate.js';

import renderTemplateFactory from './templates/renderTemplateFactory.js';
import renderServiceTemplatesFactory from './templates/renderServiceTemplatesFactory.js';
Expand Down Expand Up @@ -206,6 +209,7 @@ export default async function createDIContainer(options = {}) {
downloadCertificate: asValue(downloadCertificate),
getCertificate: asValue(getCertificate),
listCertificates: asValue(listCertificates),
cancelCertificate: asValue(cancelCertificate),
createSelfSignedCertificate: asValue(createSelfSignedCertificate),
verificationServer: asClass(VerificationServer).singleton(),
});
Expand Down Expand Up @@ -299,6 +303,7 @@ export default async function createDIContainer(options = {}) {
enableCoreQuorumsTask: asFunction(enableCoreQuorumsTaskFactory).singleton(),
registerMasternodeGuideTask: asFunction(registerMasternodeGuideTaskFactory).singleton(),
obtainZeroSSLCertificateTask: asFunction(obtainZeroSSLCertificateTaskFactory).singleton(),
cleanupZeroSSLCertificatesTask: asFunction(cleanupZeroSSLCertificatesTaskFactory).singleton(),
obtainSelfSignedCertificateTask: asFunction(obtainSelfSignedCertificateTaskFactory).singleton(),
saveCertificateTask: asFunction(saveCertificateTaskFactory),
reindexNodeTask: asFunction(reindexNodeTaskFactory).singleton(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export default function scheduleRenewZeroSslCertificateFactory(
}

const job = new CronJob(expiresAt, async () => {
const tasks = await obtainZeroSSLCertificateTask(config);
const tasks = obtainZeroSSLCertificateTask(config);

await tasks.run({
expirationDays: Certificate.EXPIRATION_LIMIT_DAYS,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import chalk from 'chalk';
import { Listr } from 'listr2';
import { Observable } from 'rxjs';
import wait from '../../../../util/wait.js';

/**
* @param {listCertificates} listCertificates
* @param {cancelCertificate} cancelCertificate
* @return {cleanupZeroSSLCertificatesTask}
*/
export default function cleanupZeroSSLCertificatesTaskFactory(
listCertificates,
cancelCertificate,
) {
/**
* @typedef {cleanupZeroSSLCertificatesTask}
* @param {Config} config
* @return {Listr}
*/
function cleanupZeroSSLCertificatesTask(config) {
const apiKey = config.get('platform.gateway.ssl.providerConfigs.zerossl.apiKey', true);

return new Listr([
{
title: 'Collect drafted and pending validation certificates',
// Skips the check if force flag is set
task: async (ctx, task) => {
ctx.certificates = [];

let certificatesPerRequest = [];
let page = 1;

// Fetch all certificates in draft or pending validation status
// with pagination
do {
certificatesPerRequest = await listCertificates(apiKey, ['draft', 'pending_validation'], page);

ctx.certificates = ctx.certificates.concat(certificatesPerRequest);

page += 1;

// eslint-disable-next-line no-param-reassign
task.output = `Found ${ctx.certificates.length} certificates`;
} while (certificatesPerRequest.length === 1000);

ctx.total = ctx.certificates.length;
},
},
shumkov marked this conversation as resolved.
Show resolved Hide resolved
{
title: 'Cancel certificates',
skip: (ctx) => ctx.certificates.length === 0,
task: async (ctx, task) => {
// eslint-disable-next-line no-param-reassign
task.title = `Cancel ${ctx.certificates.length} certificates`;
ctx.canceled = 0;
ctx.errored = 0;
return new Observable(async (observer) => {
for (const certificate of ctx.certificates) {
try {
await cancelCertificate(apiKey, certificate.id);

ctx.canceled += 1;
} catch (e) {
ctx.errored += 1;

if (process.env.DEBUG) {
// eslint-disable-next-line no-console
console.warn(e);
}
shumkov marked this conversation as resolved.
Show resolved Hide resolved
}

observer.next(chalk`{green ${ctx.canceled}} / {red ${ctx.errored}} / ${ctx.total}`);

await wait(100);
shumkov marked this conversation as resolved.
Show resolved Hide resolved
}

if (ctx.errored > 0) {
observer.error(new Error('Some certificates were not canceled. Please try again.'));
} else {
observer.complete();
}
shumkov marked this conversation as resolved.
Show resolved Hide resolved

return this;
});
},
options: {
persistentOutput: true,
},
},
], {
rendererOptions: {
showErrorMessage: true,
},
});
}

return cleanupZeroSSLCertificatesTask;
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ export default function obtainZeroSSLCertificateTaskFactory(
/**
* @typedef {obtainZeroSSLCertificateTask}
* @param {Config} config
* @return {Promise<Listr>}
* @return {Listr}
*/
async function obtainZeroSSLCertificateTask(config) {
function obtainZeroSSLCertificateTask(config) {
return new Listr([
{
title: 'Check if certificate already exists and not expiring soon',
Expand Down
2 changes: 1 addition & 1 deletion packages/dashmate/src/ssl/zerossl/cancelCertificate.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import requestApi from './requestApi';
import requestApi from './requestApi.js';

/**
* Get ZeroSSL certificate
Expand Down
10 changes: 8 additions & 2 deletions packages/dashmate/src/ssl/zerossl/listCertificates.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,18 @@ import Certificate from './Certificate.js';
* @param {string} apiKey
* @param {String[]} [statuses] - possible values: draft, pending_validation, issued, cancelled,
* revoked, expired.
* @param {number} [page]
* @param {string} [search]
* @return {Promise<Certificate[]>}
*/

export default async function listCertificates(apiKey, statuses = [], search = undefined) {
let url = `https://api.zerossl.com/certificates?access_key=${apiKey}&limit=1000`;
export default async function listCertificates(
apiKey,
statuses = [],
page = 1,
search = undefined,
) {
let url = `https://api.zerossl.com/certificates?access_key=${apiKey}&limit=1000&page=${page}`;

if (statuses.length > 0) {
url += `&statuses=${statuses.join(',')}`;
Expand Down
Loading