BREAKING CHANGE(acme): Refactor ACME configuration and certificate provisioning by replacing legacy port80HandlerConfig with unified acme options and updating CertProvisioner event subscriptions
This commit is contained in:
		
							
								
								
									
										23
									
								
								ts/common/acmeFactory.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								ts/common/acmeFactory.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| import * as fs from 'fs'; | ||||
| import * as path from 'path'; | ||||
| import type { IAcmeOptions } from './types.js'; | ||||
| import { Port80Handler } from '../port80handler/classes.port80handler.js'; | ||||
|  | ||||
| /** | ||||
|  * Factory to create a Port80Handler with common setup. | ||||
|  * Ensures the certificate store directory exists and instantiates the handler. | ||||
|  * @param options Port80Handler configuration options | ||||
|  * @returns A new Port80Handler instance | ||||
|  */ | ||||
| export function buildPort80Handler( | ||||
|   options: IAcmeOptions | ||||
| ): Port80Handler { | ||||
|   if (options.certificateStore) { | ||||
|     const certStorePath = path.resolve(options.certificateStore); | ||||
|     if (!fs.existsSync(certStorePath)) { | ||||
|       fs.mkdirSync(certStorePath, { recursive: true }); | ||||
|       console.log(`Created certificate store directory: ${certStorePath}`); | ||||
|     } | ||||
|   } | ||||
|   return new Port80Handler(options); | ||||
| } | ||||
							
								
								
									
										34
									
								
								ts/common/eventUtils.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								ts/common/eventUtils.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| import type { Port80Handler } from '../port80handler/classes.port80handler.js'; | ||||
| import { Port80HandlerEvents } from './types.js'; | ||||
| import type { ICertificateData, ICertificateFailure, ICertificateExpiring } from './types.js'; | ||||
|  | ||||
| /** | ||||
|  * Subscribers callback definitions for Port80Handler events | ||||
|  */ | ||||
| export interface Port80HandlerSubscribers { | ||||
|   onCertificateIssued?: (data: ICertificateData) => void; | ||||
|   onCertificateRenewed?: (data: ICertificateData) => void; | ||||
|   onCertificateFailed?: (data: ICertificateFailure) => void; | ||||
|   onCertificateExpiring?: (data: ICertificateExpiring) => void; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Subscribes to Port80Handler events based on provided callbacks | ||||
|  */ | ||||
| export function subscribeToPort80Handler( | ||||
|   handler: Port80Handler, | ||||
|   subscribers: Port80HandlerSubscribers | ||||
| ): void { | ||||
|   if (subscribers.onCertificateIssued) { | ||||
|     handler.on(Port80HandlerEvents.CERTIFICATE_ISSUED, subscribers.onCertificateIssued); | ||||
|   } | ||||
|   if (subscribers.onCertificateRenewed) { | ||||
|     handler.on(Port80HandlerEvents.CERTIFICATE_RENEWED, subscribers.onCertificateRenewed); | ||||
|   } | ||||
|   if (subscribers.onCertificateFailed) { | ||||
|     handler.on(Port80HandlerEvents.CERTIFICATE_FAILED, subscribers.onCertificateFailed); | ||||
|   } | ||||
|   if (subscribers.onCertificateExpiring) { | ||||
|     handler.on(Port80HandlerEvents.CERTIFICATE_EXPIRING, subscribers.onCertificateExpiring); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										89
									
								
								ts/common/types.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								ts/common/types.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,89 @@ | ||||
| /** | ||||
|  * Shared types for certificate management and domain options | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * Domain forwarding configuration | ||||
|  */ | ||||
| export interface IForwardConfig { | ||||
|   ip: string; | ||||
|   port: number; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Domain configuration 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 | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Certificate data that can be emitted via events or set from outside | ||||
|  */ | ||||
| export interface ICertificateData { | ||||
|   domain: string; | ||||
|   certificate: string; | ||||
|   privateKey: string; | ||||
|   expiryDate: Date; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Events emitted by the Port80Handler | ||||
|  */ | ||||
| export enum Port80HandlerEvents { | ||||
|   CERTIFICATE_ISSUED = 'certificate-issued', | ||||
|   CERTIFICATE_RENEWED = 'certificate-renewed', | ||||
|   CERTIFICATE_FAILED = 'certificate-failed', | ||||
|   CERTIFICATE_EXPIRING = 'certificate-expiring', | ||||
|   MANAGER_STARTED = 'manager-started', | ||||
|   MANAGER_STOPPED = 'manager-stopped', | ||||
|   REQUEST_FORWARDED = 'request-forwarded', | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Certificate failure payload type | ||||
|  */ | ||||
| export interface ICertificateFailure { | ||||
|   domain: string; | ||||
|   error: string; | ||||
|   isRenewal: boolean; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Certificate expiry payload type | ||||
|  */ | ||||
| export interface ICertificateExpiring { | ||||
|   domain: string; | ||||
|   expiryDate: Date; | ||||
|   daysRemaining: number; | ||||
| } | ||||
| /** | ||||
|  * Forwarding configuration for specific domains in ACME setup | ||||
|  */ | ||||
| export interface IDomainForwardConfig { | ||||
|   domain: string; | ||||
|   forwardConfig?: IForwardConfig; | ||||
|   acmeForwardConfig?: IForwardConfig; | ||||
|   sslRedirect?: boolean; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Unified ACME configuration options used across proxies and handlers | ||||
|  */ | ||||
| export interface IAcmeOptions { | ||||
|   enabled?: boolean;              // Whether ACME is enabled | ||||
|   port?: number;                  // Port to listen on for ACME challenges (default: 80) | ||||
|   contactEmail?: string;          // Email for Let's Encrypt account | ||||
|   useProduction?: boolean;        // Use production environment (default: staging) | ||||
|   httpsRedirectPort?: number;     // Port to redirect HTTP requests to HTTPS (default: 443) | ||||
|   renewThresholdDays?: number;    // Days before expiry to renew certificates | ||||
|   renewCheckIntervalHours?: number; // How often to check for renewals (in hours) | ||||
|   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 | ||||
| } | ||||
		Reference in New Issue
	
	Block a user