import * as plugins from '../../plugins.js'; import * as fs from 'fs'; import * as path from 'path'; import { fileURLToPath } from 'url'; import { AsyncFileSystem } from '../../core/utils/fs-utils.js'; import { type IHttpProxyOptions, type ICertificateEntry, type ILogger, createLogger } from './models/types.js'; import type { IRouteConfig } from '../smart-proxy/models/route-types.js'; /** * @deprecated This class is deprecated. Use SmartCertManager instead. * * This is a stub implementation that maintains backward compatibility * while the functionality has been moved to SmartCertManager. */ export class CertificateManager { private defaultCertificates: { key: string; cert: string }; private certificateCache: Map = new Map(); private certificateStoreDir: string; private logger: ILogger; private httpsServer: plugins.https.Server | null = null; private initialized = false; constructor(private options: IHttpProxyOptions) { this.certificateStoreDir = path.resolve(options.acme?.certificateStore || './certs'); this.logger = createLogger(options.logLevel || 'info'); this.logger.warn('CertificateManager is deprecated - use SmartCertManager instead'); // Initialize synchronously for backward compatibility but log warning this.initializeSync(); } /** * Synchronous initialization for backward compatibility * @deprecated This uses sync filesystem operations which block the event loop */ private initializeSync(): void { // Ensure certificate store directory exists try { if (!fs.existsSync(this.certificateStoreDir)) { fs.mkdirSync(this.certificateStoreDir, { recursive: true }); this.logger.info(`Created certificate store directory: ${this.certificateStoreDir}`); } } catch (error) { this.logger.warn(`Failed to create certificate store directory: ${error}`); } this.loadDefaultCertificates(); } /** * Async initialization - preferred method */ public async initialize(): Promise { if (this.initialized) return; // Ensure certificate store directory exists try { await AsyncFileSystem.ensureDir(this.certificateStoreDir); this.logger.info(`Ensured certificate store directory: ${this.certificateStoreDir}`); } catch (error) { this.logger.warn(`Failed to create certificate store directory: ${error}`); } await this.loadDefaultCertificatesAsync(); this.initialized = true; } /** * Loads default certificates from the filesystem * @deprecated This uses sync filesystem operations which block the event loop */ public loadDefaultCertificates(): void { const __dirname = path.dirname(fileURLToPath(import.meta.url)); const certPath = path.join(__dirname, '..', '..', '..', 'assets', 'certs'); try { this.defaultCertificates = { key: fs.readFileSync(path.join(certPath, 'key.pem'), 'utf8'), cert: fs.readFileSync(path.join(certPath, 'cert.pem'), 'utf8') }; this.logger.info('Loaded default certificates from filesystem (sync - deprecated)'); } catch (error) { this.logger.error(`Failed to load default certificates: ${error}`); this.generateSelfSignedCertificate(); } } /** * Loads default certificates from the filesystem asynchronously */ public async loadDefaultCertificatesAsync(): Promise { const __dirname = path.dirname(fileURLToPath(import.meta.url)); const certPath = path.join(__dirname, '..', '..', '..', 'assets', 'certs'); try { const [key, cert] = await Promise.all([ AsyncFileSystem.readFile(path.join(certPath, 'key.pem')), AsyncFileSystem.readFile(path.join(certPath, 'cert.pem')) ]); this.defaultCertificates = { key, cert }; this.logger.info('Loaded default certificates from filesystem (async)'); } catch (error) { this.logger.error(`Failed to load default certificates: ${error}`); this.generateSelfSignedCertificate(); } } /** * Generates self-signed certificates as fallback */ private generateSelfSignedCertificate(): void { // Generate a self-signed certificate using forge or similar // For now, just use a placeholder const selfSignedCert = `-----BEGIN CERTIFICATE----- MIIBkTCB+wIJAKHHIgIIA0/cMA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNVBAYTAlVT MB4XDTE0MDEwMTAwMDAwMFoXDTI0MDEwMTAwMDAwMFowDTELMAkGA1UEBhMCVVMw gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMRiH0VwnOH3jCV7c6JFZWYrvuqy -----END CERTIFICATE-----`; const selfSignedKey = `-----BEGIN PRIVATE KEY----- MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMRiH0VwnOH3jCV7 c6JFZWYrvuqyALCLXj0pcr1iqNdHjegNXnkl5zjdaUjq4edNOKl7M1AlFiYjG2xk -----END PRIVATE KEY-----`; this.defaultCertificates = { key: selfSignedKey, cert: selfSignedCert }; this.logger.warn('Using self-signed certificate as fallback'); } /** * Gets the default certificates */ public getDefaultCertificates(): { key: string; cert: string } { return this.defaultCertificates; } /** * @deprecated Use SmartCertManager instead */ public setExternalPort80Handler(handler: any): void { this.logger.warn('setExternalPort80Handler is deprecated - use SmartCertManager instead'); } /** * @deprecated Use SmartCertManager instead */ public async updateRoutes(routes: IRouteConfig[]): Promise { this.logger.warn('updateRoutes is deprecated - use SmartCertManager instead'); } /** * Handles SNI callback to provide appropriate certificate */ public handleSNI(domain: string, cb: (err: Error | null, ctx: plugins.tls.SecureContext) => void): void { const certificate = this.getCachedCertificate(domain); if (certificate) { const context = plugins.tls.createSecureContext({ key: certificate.key, cert: certificate.cert }); cb(null, context); return; } // Use default certificate if no domain-specific certificate found const defaultContext = plugins.tls.createSecureContext({ key: this.defaultCertificates.key, cert: this.defaultCertificates.cert }); cb(null, defaultContext); } /** * Updates a certificate in the cache */ public updateCertificate(domain: string, cert: string, key: string): void { this.certificateCache.set(domain, { cert, key, expires: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000) // 90 days }); this.logger.info(`Certificate updated for ${domain}`); } /** * Gets a cached certificate */ private getCachedCertificate(domain: string): ICertificateEntry | null { return this.certificateCache.get(domain) || null; } /** * @deprecated Use SmartCertManager instead */ public async initializePort80Handler(): Promise { this.logger.warn('initializePort80Handler is deprecated - use SmartCertManager instead'); return null; } /** * @deprecated Use SmartCertManager instead */ public async stopPort80Handler(): Promise { this.logger.warn('stopPort80Handler is deprecated - use SmartCertManager instead'); } /** * @deprecated Use SmartCertManager instead */ public registerDomainsWithPort80Handler(domains: string[]): void { this.logger.warn('registerDomainsWithPort80Handler is deprecated - use SmartCertManager instead'); } /** * @deprecated Use SmartCertManager instead */ public registerRoutesWithPort80Handler(routes: IRouteConfig[]): void { this.logger.warn('registerRoutesWithPort80Handler is deprecated - use SmartCertManager instead'); } /** * Sets the HTTPS server for certificate updates */ public setHttpsServer(server: plugins.https.Server): void { this.httpsServer = server; } /** * Gets statistics for metrics */ public getStats() { return { cachedCertificates: this.certificateCache.size, defaultCertEnabled: true }; } }