BREAKING CHANGE(smartproxy/configuration): Migrate SmartProxy to a fully unified route‐based configuration by removing legacy domain-based settings and conversion code. CertProvisioner, NetworkProxyBridge, and RouteManager now use IRouteConfig exclusively, and related legacy interfaces and files have been removed.

This commit is contained in:
2025-05-10 07:56:21 +00:00
parent 455858af0d
commit a2eb0741e9
11 changed files with 331 additions and 499 deletions

View File

@ -54,8 +54,30 @@ export function createCertificateProvisioner(
} = acmeOptions;
// Create and return the certificate provisioner
// Convert domain configs to route configs for the new CertProvisioner
const routeConfigs = domainConfigs.map(config => {
// Create a basic route config with the minimum required properties
return {
match: {
ports: 443,
domains: config.domains
},
action: {
type: 'forward' as const,
target: config.forwarding.target,
tls: {
mode: config.forwarding.type === 'https-terminate-to-https' ?
'terminate-and-reencrypt' as const :
'terminate' as const,
certificate: 'auto' as 'auto'
},
security: config.forwarding.security
}
};
});
return new CertProvisioner(
domainConfigs,
routeConfigs,
port80Handler,
networkProxyBridge,
certProvider,

View File

@ -1,4 +1,5 @@
import * as plugins from '../../plugins.js';
import type { IRouteConfig } from '../../proxies/smart-proxy/models/route-types.js';
/**
* Certificate data structure containing all necessary information
@ -12,6 +13,11 @@ export interface ICertificateData {
// Optional source and renewal information for event emissions
source?: 'static' | 'http01' | 'dns01';
isRenewal?: boolean;
// Reference to the route that requested this certificate (if available)
routeReference?: {
routeId?: string;
routeName?: string;
};
}
/**
@ -29,6 +35,10 @@ export interface ICertificateFailure {
domain: string;
error: string;
isRenewal: boolean;
routeReference?: {
routeId?: string;
routeName?: string;
};
}
/**
@ -38,35 +48,46 @@ export interface ICertificateExpiring {
domain: string;
expiryDate: Date;
daysRemaining: number;
routeReference?: {
routeId?: string;
routeName?: string;
};
}
/**
* Domain forwarding configuration
* Route-specific forwarding configuration for ACME challenges
*/
export interface IForwardConfig {
ip: string;
port: number;
}
/**
* Domain-specific forwarding configuration for ACME challenges
*/
export interface IDomainForwardConfig {
export interface IRouteForwardConfig {
domain: string;
forwardConfig?: IForwardConfig;
acmeForwardConfig?: IForwardConfig;
target: {
host: string;
port: number;
};
sslRedirect?: boolean;
}
/**
* Domain configuration options
* Domain configuration options for Port80Handler
*
* This is used internally by the Port80Handler to manage domains
* but will eventually be replaced with route-based options.
*/
export interface IDomainOptions {
domainName: string;
sslRedirect: boolean; // if true redirects the request to port 443
acmeMaintenance: boolean; // tries to always have a valid cert for this domain
forward?: IForwardConfig; // forwards all http requests to that target
acmeForward?: IForwardConfig; // forwards letsencrypt requests to this config
forward?: {
ip: string;
port: number;
}; // forwards all http requests to that target
acmeForward?: {
ip: string;
port: number;
}; // forwards letsencrypt requests to this config
routeReference?: {
routeId?: string;
routeName?: string;
};
}
/**
@ -83,6 +104,6 @@ export interface IAcmeOptions {
autoRenew?: boolean; // Whether to automatically renew certificates
certificateStore?: string; // Directory to store certificates
skipConfiguredCerts?: boolean; // Skip domains with existing certificates
domainForwards?: IDomainForwardConfig[]; // Domain-specific forwarding configs
routeForwards?: IRouteForwardConfig[]; // Route-specific forwarding configs
}

View File

@ -1,5 +1,6 @@
import * as plugins from '../../plugins.js';
import type { IDomainConfig } from '../../forwarding/config/domain-config.js';
import type { IRouteConfig } from '../../proxies/smart-proxy/models/route-types.js';
import type { ICertificateData, IDomainForwardConfig, IDomainOptions } from '../models/certificate-types.js';
import { Port80HandlerEvents, CertProvisionerEvents } from '../events/certificate-events.js';
import { Port80Handler } from '../../http/port80/port80-handler.js';
@ -28,6 +29,45 @@ export class CertProvisioner extends plugins.EventEmitter {
private port80Handler: Port80Handler;
private networkProxyBridge: INetworkProxyBridge;
private certProvisionFunction?: (domain: string) => Promise<TCertProvisionObject>;
/**
* Extract domains from route configurations for certificate management
* @param routes Route configurations
*/
private extractDomainsFromRoutes(routes: IRouteConfig[]): void {
// Process all HTTPS routes that need certificates
for (const route of routes) {
// Only process routes with TLS termination that need certificates
if (route.action.type === 'forward' &&
route.action.tls &&
(route.action.tls.mode === 'terminate' || route.action.tls.mode === 'terminate-and-reencrypt') &&
route.match.domains) {
// Extract domains from the route
const domains = Array.isArray(route.match.domains)
? route.match.domains
: [route.match.domains];
// Skip wildcard domains that can't use ACME
const eligibleDomains = domains.filter(d => !d.includes('*'));
if (eligibleDomains.length > 0) {
// Create a domain config object for certificate provisioning
const domainConfig: IDomainConfig = {
domains: eligibleDomains,
forwarding: {
type: route.action.tls.mode === 'terminate' ? 'https-terminate-to-http' : 'https-terminate-to-https',
target: route.action.target || { host: 'localhost', port: 80 },
// Add any other required properties from the legacy format
security: route.action.security || {}
}
};
this.domainConfigs.push(domainConfig);
}
}
}
};
private forwardConfigs: IDomainForwardConfig[];
private renewThresholdDays: number;
private renewCheckIntervalHours: number;
@ -47,7 +87,7 @@ export class CertProvisioner extends plugins.EventEmitter {
* @param forwardConfigs Domain forwarding configurations for ACME challenges
*/
constructor(
domainConfigs: IDomainConfig[],
routeConfigs: IRouteConfig[],
port80Handler: Port80Handler,
networkProxyBridge: INetworkProxyBridge,
certProvider?: (domain: string) => Promise<TCertProvisionObject>,
@ -57,7 +97,8 @@ export class CertProvisioner extends plugins.EventEmitter {
forwardConfigs: IDomainForwardConfig[] = []
) {
super();
this.domainConfigs = domainConfigs;
this.domainConfigs = [];
this.extractDomainsFromRoutes(routeConfigs);
this.port80Handler = port80Handler;
this.networkProxyBridge = networkProxyBridge;
this.certProvisionFunction = certProvider;