Compare commits

...

2 Commits

Author SHA1 Message Date
a77ec6884a v12.8.0
Some checks failed
Docker (tags) / security (push) Failing after 2s
Docker (tags) / test (push) Has been skipped
Docker (tags) / release (push) Has been skipped
Docker (tags) / metadata (push) Has been skipped
2026-04-03 19:08:46 +00:00
6112e4e884 feat(certificates): add force renew option for domain certificate reprovisioning 2026-04-03 19:08:46 +00:00
9 changed files with 31 additions and 20 deletions

View File

@@ -1,5 +1,12 @@
# Changelog
## 2026-04-03 - 12.8.0 - feat(certificates)
add force renew option for domain certificate reprovisioning
- pass an optional forceRenew flag through certificate reprovision requests from the UI to the ops handler
- use smartacme forceRenew support and return renewal-specific success messages
- update the SmartAcme dependency to version ^9.4.0
## 2026-04-03 - 12.7.0 - feat(opsserver)
add RADIUS and VPN metrics to combined ops stats and overview dashboards, and stream live log buffer entries in follow mode

View File

@@ -1,7 +1,7 @@
{
"name": "@serve.zone/dcrouter",
"private": false,
"version": "12.7.0",
"version": "12.8.0",
"description": "A multifaceted routing service handling mail and SMS delivery functions.",
"type": "module",
"exports": {
@@ -40,7 +40,7 @@
"@push.rocks/lik": "^6.4.0",
"@push.rocks/projectinfo": "^5.1.0",
"@push.rocks/qenv": "^6.1.3",
"@push.rocks/smartacme": "^9.3.1",
"@push.rocks/smartacme": "^9.4.0",
"@push.rocks/smartdata": "^7.1.3",
"@push.rocks/smartdb": "^2.1.1",
"@push.rocks/smartdns": "^7.9.0",

10
pnpm-lock.yaml generated
View File

@@ -39,8 +39,8 @@ importers:
specifier: ^6.1.3
version: 6.1.3
'@push.rocks/smartacme':
specifier: ^9.3.1
version: 9.3.1(socks@2.8.7)
specifier: ^9.4.0
version: 9.4.0(socks@2.8.7)
'@push.rocks/smartdata':
specifier: ^7.1.3
version: 7.1.3(socks@2.8.7)
@@ -1108,8 +1108,8 @@ packages:
'@push.rocks/qenv@6.1.3':
resolution: {integrity: sha512-+z2hsAU/7CIgpYLFqvda8cn9rUBMHqLdQLjsFfRn5jPoD7dJ5rFlpkbhfM4Ws8mHMniwWaxGKo+q/YBhtzRBLg==}
'@push.rocks/smartacme@9.3.1':
resolution: {integrity: sha512-Cl1DVQ+rfpaYkk6VVm/KYVeUYzWfXzSfTXybHfCZ5SuiACuTVHZ6jK8TouELaV1RgrdYnIp0MrbiY2Kqi8ayAw==}
'@push.rocks/smartacme@9.4.0':
resolution: {integrity: sha512-mSqsI859mHI9fCZxLfayzPf/WvukDFzVHOh02vXq3ujxbb5M+ArMnXe0MmC2egR9GeXmQTm3DTENaETX5ffMtw==}
'@push.rocks/smartarchive@4.2.4':
resolution: {integrity: sha512-uiqVAXPxmr8G5rv3uZvZFMOCt8l7cZC3nzvsy4YQqKf/VkPhKIEX+b7LkAeNlxPSYUiBQUkNRoawg9+5BaMcHg==}
@@ -5960,7 +5960,7 @@ snapshots:
'@push.rocks/smartlog': 3.2.1
'@push.rocks/smartpath': 6.0.0
'@push.rocks/smartacme@9.3.1(socks@2.8.7)':
'@push.rocks/smartacme@9.4.0(socks@2.8.7)':
dependencies:
'@apiclient.xyz/cloudflare': 7.1.0
'@peculiar/x509': 2.0.0

View File

@@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@serve.zone/dcrouter',
version: '12.7.0',
version: '12.8.0',
description: 'A multifaceted routing service handling mail and SMS delivery functions.'
}

View File

@@ -43,7 +43,7 @@ export class CertificateHandler {
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_ReprovisionCertificateDomain>(
'reprovisionCertificateDomain',
async (dataArg) => {
return this.reprovisionCertificateDomain(dataArg.domain);
return this.reprovisionCertificateDomain(dataArg.domain, dataArg.forceRenew);
}
)
);
@@ -318,7 +318,7 @@ export class CertificateHandler {
/**
* Domain-based reprovisioning — clears backoff first, then triggers provision
*/
private async reprovisionCertificateDomain(domain: string): Promise<{ success: boolean; message?: string }> {
private async reprovisionCertificateDomain(domain: string, forceRenew?: boolean): Promise<{ success: boolean; message?: string }> {
const dcRouter = this.opsServerRef.dcRouterRef;
const smartProxy = dcRouter.smartProxy;
@@ -337,8 +337,8 @@ export class CertificateHandler {
// Try to provision via SmartAcme directly
if (dcRouter.smartAcme) {
try {
await dcRouter.smartAcme.getCertificateForDomain(domain);
return { success: true, message: `Certificate reprovisioning triggered for domain '${domain}'` };
await dcRouter.smartAcme.getCertificateForDomain(domain, { forceRenew: forceRenew ?? false });
return { success: true, message: forceRenew ? `Certificate force-renewed for domain '${domain}'` : `Certificate reprovisioning triggered for domain '${domain}'` };
} catch (err: unknown) {
return { success: false, message: (err as Error).message || `Failed to reprovision certificate for ${domain}` };
}

View File

@@ -68,6 +68,7 @@ export interface IReq_ReprovisionCertificateDomain extends plugins.typedrequestI
request: {
identity: authInterfaces.IIdentity;
domain: string;
forceRenew?: boolean;
};
response: {
success: boolean;

View File

@@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@serve.zone/dcrouter',
version: '12.7.0',
version: '12.8.0',
description: 'A multifaceted routing service handling mail and SMS delivery functions.'
}

View File

@@ -605,8 +605,8 @@ export const fetchCertificateOverviewAction = certificateStatePart.createAction(
}
});
export const reprovisionCertificateAction = certificateStatePart.createAction<string>(
async (statePartArg, domain, actionContext): Promise<ICertificateState> => {
export const reprovisionCertificateAction = certificateStatePart.createAction<{ domain: string; forceRenew?: boolean }>(
async (statePartArg, dataArg, actionContext): Promise<ICertificateState> => {
const context = getActionContext();
const currentState = statePartArg.getState()!;
@@ -617,7 +617,8 @@ export const reprovisionCertificateAction = certificateStatePart.createAction<st
await request.fire({
identity: context.identity!,
domain,
domain: dataArg.domain,
forceRenew: dataArg.forceRenew,
});
// Re-fetch overview after reprovisioning

View File

@@ -312,14 +312,16 @@ export class OpsViewCertificates extends DeesElement {
return;
}
const doReprovision = async () => {
const doReprovision = async (forceRenew = false) => {
await appstate.certificateStatePart.dispatchAction(
appstate.reprovisionCertificateAction,
cert.domain,
{ domain: cert.domain, forceRenew },
);
const { DeesToast } = await import('@design.estate/dees-catalog');
DeesToast.show({
message: `Reprovisioning triggered for ${cert.domain}`,
message: forceRenew
? `Force renewal triggered for ${cert.domain}`
: `Reprovisioning triggered for ${cert.domain}`,
type: 'success',
duration: 3000,
});
@@ -336,7 +338,7 @@ export class OpsViewCertificates extends DeesElement {
name: 'Force Renew',
action: async (modalArg: any) => {
await modalArg.destroy();
await doReprovision();
await doReprovision(true);
},
},
],