before refactor

This commit is contained in:
2025-05-01 11:48:04 +00:00
parent a30571dae2
commit e6a138279d
6 changed files with 475 additions and 47 deletions

View File

@ -12,6 +12,10 @@ import { Port80Handler } from '../port80handler/classes.port80handler.js';
* automatic certificate management, and high-performance connection pooling.
*/
export class NetworkProxy implements IMetricsTracker {
// Provide a minimal JSON representation to avoid circular references during deep equality checks
public toJSON(): any {
return {};
}
// Configuration
public options: INetworkProxyOptions;
public proxyConfigs: IReverseProxyConfig[] = [];

View File

@ -22,13 +22,15 @@ import * as smartpromise from '@push.rocks/smartpromise';
import * as smartrequest from '@push.rocks/smartrequest';
import * as smartstring from '@push.rocks/smartstring';
export { lik, smartdelay, smartrequest, smartpromise, smartstring };
import * as smartacme from '@push.rocks/smartacme';
import * as smartacmePlugins from '@push.rocks/smartacme/dist_ts/smartacme.plugins.js';
import * as smartacmeHandlers from '@push.rocks/smartacme/dist_ts/handlers/index.js';
export { lik, smartdelay, smartrequest, smartpromise, smartstring, smartacme, smartacmePlugins, smartacmeHandlers };
// third party scope
import * as acme from 'acme-client';
import prettyMs from 'pretty-ms';
import * as ws from 'ws';
import wsDefault from 'ws';
import { minimatch } from 'minimatch';
export { acme, prettyMs, ws, wsDefault, minimatch };
export { prettyMs, ws, wsDefault, minimatch };

View File

@ -2,6 +2,21 @@ import * as plugins from '../plugins.js';
import { IncomingMessage, ServerResponse } from 'http';
import * as fs from 'fs';
import * as path from 'path';
// ACME HTTP-01 challenge handler storing tokens in memory (diskless)
class DisklessHttp01Handler {
private storage: Map<string, string>;
constructor(storage: Map<string, string>) { this.storage = storage; }
public getSupportedTypes(): string[] { return ['http-01']; }
public async prepare(ch: any): Promise<void> {
this.storage.set(ch.token, ch.keyAuthorization);
}
public async verify(ch: any): Promise<void> {
return;
}
public async cleanup(ch: any): Promise<void> {
this.storage.delete(ch.token);
}
}
/**
* Custom error classes for better error handling
@ -79,6 +94,7 @@ interface IPort80HandlerOptions {
autoRenew?: boolean; // Whether to automatically renew certificates
certificateStore?: string; // Directory to store certificates
skipConfiguredCerts?: boolean; // Skip domains that already have certificates
mongoDescriptor?: plugins.smartdata.IMongoDescriptor; // MongoDB config for SmartAcme
}
/**
@ -128,6 +144,10 @@ export interface ICertificateExpiring {
*/
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 server: plugins.http.Server | null = null;
private acmeClient: plugins.acme.Client | null = null;
private accountKey: string | null = null;
@ -175,6 +195,20 @@ export class Port80Handler extends plugins.EventEmitter {
console.log('Port80Handler is disabled, skipping start');
return;
}
// Initialize SmartAcme for ACME challenge management (diskless HTTP handler)
if (this.options.enabled) {
if (!this.options.mongoDescriptor) {
throw new ServerError('MongoDB descriptor is required for SmartAcme');
}
this.smartAcme = new plugins.smartacme.SmartAcme({
accountEmail: this.options.contactEmail,
environment: this.options.useProduction ? 'production' : 'integration',
mongoDescriptor: this.options.mongoDescriptor,
challengeHandlers: [ new DisklessHttp01Handler(this.acmeHttp01Storage) ],
challengePriority: ['http-01'],
});
await this.smartAcme.start();
}
return new Promise((resolve, reject) => {
try {
@ -640,19 +674,26 @@ export class Port80Handler extends plugins.EventEmitter {
const { domainInfo, pattern } = domainMatch;
const options = domainInfo.options;
// If the request is for an ACME HTTP-01 challenge, handle it
if (req.url && req.url.startsWith('/.well-known/acme-challenge/') && (options.acmeMaintenance || options.acmeForward)) {
// Check if we should forward ACME requests
// Serve or forward ACME HTTP-01 challenge requests
if (req.url && req.url.startsWith('/.well-known/acme-challenge/') && options.acmeMaintenance) {
// Forward ACME requests if configured
if (options.acmeForward) {
this.forwardRequest(req, res, options.acmeForward, 'ACME challenge');
return;
}
// Only handle ACME challenges for non-glob patterns
if (!this.isGlobPattern(pattern)) {
this.handleAcmeChallenge(req, res, domain);
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}`);
} else {
res.statusCode = 404;
res.end('Challenge token not found');
}
return;
}
// Check if we should forward non-ACME requests