fix(port80handler): refactor ACME challenge handling to use dedicated Http01MemoryHandler, remove obsolete readme.plan.md, and update version to 10.0.12
This commit is contained in:
		| @@ -3,6 +3,6 @@ | ||||
|  */ | ||||
| export const commitinfo = { | ||||
|   name: '@push.rocks/smartproxy', | ||||
|   version: '10.0.11', | ||||
|   version: '10.0.12', | ||||
|   description: 'A powerful proxy package that effectively handles high traffic, with features such as SSL/TLS support, port proxying, WebSocket handling, dynamic routing with authentication options, and automatic ACME certificate management.' | ||||
| } | ||||
|   | ||||
| @@ -65,11 +65,11 @@ interface IDomainCertificate { | ||||
|  */ | ||||
| export class Port80Handler extends plugins.EventEmitter { | ||||
|   private domainCertificates: Map<string, IDomainCertificate>; | ||||
|   // In-memory storage for ACME HTTP-01 challenge tokens | ||||
|   private acmeHttp01Storage: Map<string, string> = new Map(); | ||||
|   // SmartAcme instance for certificate management | ||||
|   private smartAcme: plugins.smartacme.SmartAcme | null = null; | ||||
|   private smartAcmeHttp01Handler!: plugins.smartacme.handlers.Http01MemoryHandler; | ||||
|   private server: plugins.http.Server | null = null; | ||||
|    | ||||
|   // Renewal scheduling is handled externally by SmartProxy | ||||
|   // (Removed internal renewal timer) | ||||
|   private isShuttingDown: boolean = false; | ||||
| @@ -116,13 +116,14 @@ export class Port80Handler extends plugins.EventEmitter { | ||||
|       console.log('Port80Handler is disabled, skipping start'); | ||||
|       return; | ||||
|     } | ||||
|     // Initialize SmartAcme for ACME challenge management (diskless HTTP handler) | ||||
|     // Initialize SmartAcme with in-memory HTTP-01 challenge handler | ||||
|     if (this.options.enabled) { | ||||
|       this.smartAcmeHttp01Handler = new plugins.smartacme.handlers.Http01MemoryHandler(); | ||||
|       this.smartAcme = new plugins.smartacme.SmartAcme({ | ||||
|         accountEmail: this.options.accountEmail, | ||||
|         certManager: new plugins.smartacme.certmanagers.MemoryCertManager(), | ||||
|         environment: this.options.useProduction ? 'production' : 'integration', | ||||
|         challengeHandlers: [ new plugins.smartacme.handlers.Http01MemoryHandler() ], | ||||
|         challengeHandlers: [ this.smartAcmeHttp01Handler ], | ||||
|         challengePriority: ['http-01'], | ||||
|       }); | ||||
|       await this.smartAcme.start(); | ||||
| @@ -433,17 +434,12 @@ export class Port80Handler extends plugins.EventEmitter { | ||||
|         res.end('Not found'); | ||||
|         return; | ||||
|       } | ||||
|       // Serve challenge response from in-memory storage | ||||
|       const token = req.url.split('/').pop() || ''; | ||||
|       const keyAuth = this.acmeHttp01Storage.get(token); | ||||
|       if (keyAuth) { | ||||
|         res.statusCode = 200; | ||||
|         res.setHeader('Content-Type', 'text/plain'); | ||||
|         res.end(keyAuth); | ||||
|         console.log(`Served ACME challenge response for ${domain}`); | ||||
|       // Delegate to Http01MemoryHandler | ||||
|       if (this.smartAcmeHttp01Handler) { | ||||
|         this.smartAcmeHttp01Handler.handleRequest(req, res); | ||||
|       } else { | ||||
|         res.statusCode = 404; | ||||
|         res.end('Challenge token not found'); | ||||
|         res.statusCode = 500; | ||||
|         res.end('ACME HTTP-01 handler not initialized'); | ||||
|       } | ||||
|       return; | ||||
|     } | ||||
|   | ||||
| @@ -81,8 +81,7 @@ export class CertProvisioner extends plugins.EventEmitter { | ||||
|     // Initial provisioning for all domains | ||||
|     const domains = this.domainConfigs.flatMap(cfg => cfg.domains); | ||||
|     for (const domain of domains) { | ||||
|       // Skip wildcard domains | ||||
|       if (domain.includes('*')) continue; | ||||
|       const isWildcard = domain.includes('*'); | ||||
|       let provision: ISmartProxyCertProvisionObject | 'http01' = 'http01'; | ||||
|       if (this.certProvider) { | ||||
|         try { | ||||
| @@ -90,11 +89,20 @@ export class CertProvisioner extends plugins.EventEmitter { | ||||
|         } catch (err) { | ||||
|           console.error(`certProvider error for ${domain}:`, err); | ||||
|         } | ||||
|       } else if (isWildcard) { | ||||
|         // No certProvider: cannot handle wildcard without DNS-01 support | ||||
|         console.warn(`Skipping wildcard domain without certProvisionFunction: ${domain}`); | ||||
|         continue; | ||||
|       } | ||||
|       if (provision === 'http01') { | ||||
|         if (isWildcard) { | ||||
|           console.warn(`Skipping HTTP-01 for wildcard domain: ${domain}`); | ||||
|           continue; | ||||
|         } | ||||
|         this.provisionMap.set(domain, 'http01'); | ||||
|         this.port80Handler.addDomain({ domainName: domain, sslRedirect: true, acmeMaintenance: true }); | ||||
|       } else { | ||||
|         // Static certificate (e.g., DNS-01 provisioned or user-provided) supports wildcard domains | ||||
|         this.provisionMap.set(domain, 'static'); | ||||
|         const certObj = provision as plugins.tsclass.network.ICert; | ||||
|         const certData: ICertificateData = { | ||||
| @@ -162,18 +170,22 @@ export class CertProvisioner extends plugins.EventEmitter { | ||||
|    * @param domain Domain name to provision | ||||
|    */ | ||||
|   public async requestCertificate(domain: string): Promise<void> { | ||||
|     // Skip wildcard domains | ||||
|     if (domain.includes('*')) { | ||||
|       throw new Error(`Cannot request certificate for wildcard domain: ${domain}`); | ||||
|     } | ||||
|     const isWildcard = domain.includes('*'); | ||||
|     // Determine provisioning method | ||||
|     let provision: ISmartProxyCertProvisionObject | 'http01' = 'http01'; | ||||
|     if (this.certProvider) { | ||||
|       provision = await this.certProvider(domain); | ||||
|     } else if (isWildcard) { | ||||
|       // Cannot perform HTTP-01 on wildcard without certProvider | ||||
|       throw new Error(`Cannot request certificate for wildcard domain without certProvisionFunction: ${domain}`); | ||||
|     } | ||||
|     if (provision === 'http01') { | ||||
|       if (isWildcard) { | ||||
|         throw new Error(`Cannot request HTTP-01 certificate for wildcard domain: ${domain}`); | ||||
|       } | ||||
|       await this.port80Handler.renewCertificate(domain); | ||||
|     } else { | ||||
|       // Static certificate (e.g., DNS-01 provisioned) supports wildcards | ||||
|       const certObj = provision as plugins.tsclass.network.ICert; | ||||
|       const certData: ICertificateData = { | ||||
|         domain: certObj.domainName, | ||||
|   | ||||
| @@ -391,16 +391,23 @@ export class SmartProxy extends plugins.EventEmitter { | ||||
|     if (this.port80Handler && this.settings.acme?.enabled) { | ||||
|       for (const domainConfig of newDomainConfigs) { | ||||
|         for (const domain of domainConfig.domains) { | ||||
|           if (domain.includes('*')) continue; | ||||
|           let provision = 'http01' as string | plugins.tsclass.network.ICert; | ||||
|           const isWildcard = domain.includes('*'); | ||||
|           let provision: string | plugins.tsclass.network.ICert = 'http01'; | ||||
|           if (this.settings.certProvisionFunction) { | ||||
|             try { | ||||
|               provision = await this.settings.certProvisionFunction(domain); | ||||
|             } catch (err) { | ||||
|               console.log(`certProvider error for ${domain}: ${err}`); | ||||
|             } | ||||
|           } else if (isWildcard) { | ||||
|             console.warn(`Skipping wildcard domain without certProvisionFunction: ${domain}`); | ||||
|             continue; | ||||
|           } | ||||
|           if (provision === 'http01') { | ||||
|             if (isWildcard) { | ||||
|               console.warn(`Skipping HTTP-01 for wildcard domain: ${domain}`); | ||||
|               continue; | ||||
|             } | ||||
|             this.port80Handler.addDomain({ | ||||
|               domainName: domain, | ||||
|               sslRedirect: true, | ||||
| @@ -408,6 +415,7 @@ export class SmartProxy extends plugins.EventEmitter { | ||||
|             }); | ||||
|             console.log(`Registered domain ${domain} with Port80Handler for HTTP-01`); | ||||
|           } else { | ||||
|             // Static certificate (e.g., DNS-01 provisioned) supports wildcards | ||||
|             const certObj = provision as plugins.tsclass.network.ICert; | ||||
|             const certData: ICertificateData = { | ||||
|               domain: certObj.domainName, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user