fix
This commit is contained in:
parent
3596d35f45
commit
529857220d
@ -13,64 +13,17 @@ export type TSmartProxyCertProvisionObject = plugins.tsclass.network.ICert | 'ht
|
|||||||
*/
|
*/
|
||||||
export type IRoutedSmartProxyOptions = ISmartProxyOptions;
|
export type IRoutedSmartProxyOptions = ISmartProxyOptions;
|
||||||
|
|
||||||
/**
|
|
||||||
* Legacy domain configuration interface for backward compatibility
|
|
||||||
*/
|
|
||||||
export interface IDomainConfig {
|
|
||||||
domains: string[];
|
|
||||||
forwarding: {
|
|
||||||
type: TForwardingType;
|
|
||||||
target: {
|
|
||||||
host: string | string[];
|
|
||||||
port: number;
|
|
||||||
};
|
|
||||||
acme?: {
|
|
||||||
enabled?: boolean;
|
|
||||||
maintenance?: boolean;
|
|
||||||
production?: boolean;
|
|
||||||
forwardChallenges?: {
|
|
||||||
host: string;
|
|
||||||
port: number;
|
|
||||||
useTls?: boolean;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
http?: {
|
|
||||||
enabled?: boolean;
|
|
||||||
redirectToHttps?: boolean;
|
|
||||||
headers?: Record<string, string>;
|
|
||||||
};
|
|
||||||
https?: {
|
|
||||||
customCert?: {
|
|
||||||
key: string;
|
|
||||||
cert: string;
|
|
||||||
};
|
|
||||||
forwardSni?: boolean;
|
|
||||||
};
|
|
||||||
security?: {
|
|
||||||
allowedIps?: string[];
|
|
||||||
blockedIps?: string[];
|
|
||||||
maxConnections?: number;
|
|
||||||
};
|
|
||||||
advanced?: {
|
|
||||||
portRanges?: Array<{ from: number; to: number }>;
|
|
||||||
networkProxyPort?: number;
|
|
||||||
keepAlive?: boolean;
|
|
||||||
timeout?: number;
|
|
||||||
headers?: Record<string, string>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper functions for type checking configuration types
|
* Helper functions for type checking configuration types
|
||||||
*/
|
*/
|
||||||
export function isLegacyOptions(options: any): boolean {
|
export function isLegacyOptions(options: any): boolean {
|
||||||
return !!(options.domainConfigs && options.domainConfigs.length > 0 &&
|
// Legacy options are no longer supported
|
||||||
(!options.routes || options.routes.length === 0));
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isRoutedOptions(options: any): boolean {
|
export function isRoutedOptions(options: any): boolean {
|
||||||
return !!(options.routes && options.routes.length > 0);
|
// All configurations are now route-based
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -80,14 +33,7 @@ export interface ISmartProxyOptions {
|
|||||||
// The unified configuration array (required)
|
// The unified configuration array (required)
|
||||||
routes: IRouteConfig[];
|
routes: IRouteConfig[];
|
||||||
|
|
||||||
// Legacy options for backward compatibility
|
// Port range configuration
|
||||||
fromPort?: number;
|
|
||||||
toPort?: number;
|
|
||||||
sniEnabled?: boolean;
|
|
||||||
domainConfigs?: IDomainConfig[];
|
|
||||||
targetIP?: string;
|
|
||||||
defaultAllowedIPs?: string[];
|
|
||||||
defaultBlockedIPs?: string[];
|
|
||||||
globalPortRanges?: Array<{ from: number; to: number }>;
|
globalPortRanges?: Array<{ from: number; to: number }>;
|
||||||
forwardAllGlobalRanges?: boolean;
|
forwardAllGlobalRanges?: boolean;
|
||||||
preserveSourceIP?: boolean;
|
preserveSourceIP?: boolean;
|
||||||
@ -99,8 +45,8 @@ export interface ISmartProxyOptions {
|
|||||||
port: number; // Default port to use when not specified in routes
|
port: number; // Default port to use when not specified in routes
|
||||||
};
|
};
|
||||||
security?: {
|
security?: {
|
||||||
allowedIPs?: string[]; // Default allowed IPs
|
allowedIps?: string[]; // Default allowed IPs
|
||||||
blockedIPs?: string[]; // Default blocked IPs
|
blockedIps?: string[]; // Default blocked IPs
|
||||||
maxConnections?: number; // Default max connections
|
maxConnections?: number; // Default max connections
|
||||||
};
|
};
|
||||||
preserveSourceIP?: boolean; // Default source IP preservation
|
preserveSourceIP?: boolean; // Default source IP preservation
|
||||||
@ -184,9 +130,6 @@ export interface IConnectionRecord {
|
|||||||
pendingData: Buffer[]; // Buffer to hold data during connection setup
|
pendingData: Buffer[]; // Buffer to hold data during connection setup
|
||||||
pendingDataSize: number; // Track total size of pending data
|
pendingDataSize: number; // Track total size of pending data
|
||||||
|
|
||||||
// Legacy property for backward compatibility
|
|
||||||
domainConfig?: IDomainConfig;
|
|
||||||
|
|
||||||
// Enhanced tracking fields
|
// Enhanced tracking fields
|
||||||
bytesReceived: number; // Total bytes received
|
bytesReceived: number; // Total bytes received
|
||||||
bytesSent: number; // Total bytes sent
|
bytesSent: number; // Total bytes sent
|
||||||
|
@ -4,10 +4,19 @@ import { Port80Handler } from '../../http/port80/port80-handler.js';
|
|||||||
import { Port80HandlerEvents } from '../../core/models/common-types.js';
|
import { Port80HandlerEvents } from '../../core/models/common-types.js';
|
||||||
import { subscribeToPort80Handler } from '../../core/utils/event-utils.js';
|
import { subscribeToPort80Handler } from '../../core/utils/event-utils.js';
|
||||||
import type { ICertificateData } from '../../certificate/models/certificate-types.js';
|
import type { ICertificateData } from '../../certificate/models/certificate-types.js';
|
||||||
import type { IConnectionRecord, ISmartProxyOptions, IDomainConfig } from './models/interfaces.js';
|
import type { IConnectionRecord, ISmartProxyOptions } from './models/interfaces.js';
|
||||||
|
import type { IRouteConfig } from './models/route-types.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages NetworkProxy integration for TLS termination
|
* Manages NetworkProxy integration for TLS termination
|
||||||
|
*
|
||||||
|
* NetworkProxyBridge connects SmartProxy with NetworkProxy to handle TLS termination.
|
||||||
|
* It converts route configurations to NetworkProxy configuration format and manages
|
||||||
|
* certificate provisioning through Port80Handler when ACME is enabled.
|
||||||
|
*
|
||||||
|
* It is used by SmartProxy for routes that have:
|
||||||
|
* - TLS mode of 'terminate' or 'terminate-and-reencrypt'
|
||||||
|
* - Certificate set to 'auto' or custom certificate
|
||||||
*/
|
*/
|
||||||
export class NetworkProxyBridge {
|
export class NetworkProxyBridge {
|
||||||
private networkProxy: NetworkProxy | null = null;
|
private networkProxy: NetworkProxy | null = null;
|
||||||
@ -58,8 +67,8 @@ export class NetworkProxyBridge {
|
|||||||
this.networkProxy.setExternalPort80Handler(this.port80Handler);
|
this.networkProxy.setExternalPort80Handler(this.port80Handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert and apply domain configurations to NetworkProxy
|
// Apply route configurations to NetworkProxy
|
||||||
await this.syncDomainConfigsToNetworkProxy();
|
await this.syncRoutesToNetworkProxy(this.settings.routes || []);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,9 +258,19 @@ export class NetworkProxyBridge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Synchronizes domain configurations to NetworkProxy
|
* Synchronizes routes to NetworkProxy
|
||||||
|
*
|
||||||
|
* This method converts route configurations to NetworkProxy format and updates
|
||||||
|
* the NetworkProxy with the converted configurations. It handles:
|
||||||
|
*
|
||||||
|
* - Extracting domain, target, and certificate information from routes
|
||||||
|
* - Converting TLS mode settings to NetworkProxy configuration
|
||||||
|
* - Applying security and advanced settings
|
||||||
|
* - Registering domains for ACME certificate provisioning when needed
|
||||||
|
*
|
||||||
|
* @param routes The route configurations to sync to NetworkProxy
|
||||||
*/
|
*/
|
||||||
public async syncDomainConfigsToNetworkProxy(): Promise<void> {
|
public async syncRoutesToNetworkProxy(routes: IRouteConfig[]): Promise<void> {
|
||||||
if (!this.networkProxy) {
|
if (!this.networkProxy) {
|
||||||
console.log('Cannot sync configurations - NetworkProxy not initialized');
|
console.log('Cannot sync configurations - NetworkProxy not initialized');
|
||||||
return;
|
return;
|
||||||
@ -282,39 +301,113 @@ export class NetworkProxyBridge {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert domain configs to NetworkProxy configs
|
// Convert routes to NetworkProxy configs
|
||||||
const proxyConfigs = this.networkProxy.convertSmartProxyConfigs(
|
const proxyConfigs = this.convertRoutesToNetworkProxyConfigs(routes, certPair);
|
||||||
this.settings.domainConfigs,
|
|
||||||
certPair
|
|
||||||
);
|
|
||||||
|
|
||||||
// Log ACME-eligible domains
|
// Update the proxy configs
|
||||||
const acmeEnabled = !!this.settings.acme?.enabled;
|
|
||||||
if (acmeEnabled) {
|
|
||||||
const acmeEligibleDomains = proxyConfigs
|
|
||||||
.filter((config) => !config.hostName.includes('*')) // Exclude wildcards
|
|
||||||
.map((config) => config.hostName);
|
|
||||||
|
|
||||||
if (acmeEligibleDomains.length > 0) {
|
|
||||||
console.log(`Domains eligible for ACME certificates: ${acmeEligibleDomains.join(', ')}`);
|
|
||||||
|
|
||||||
// Register these domains with Port80Handler if available
|
|
||||||
if (this.port80Handler) {
|
|
||||||
this.registerDomainsWithPort80Handler(acmeEligibleDomains);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.log('No domains eligible for ACME certificates found in configuration');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update NetworkProxy with the converted configs
|
|
||||||
await this.networkProxy.updateProxyConfigs(proxyConfigs);
|
await this.networkProxy.updateProxyConfigs(proxyConfigs);
|
||||||
console.log(`Successfully synchronized ${proxyConfigs.length} domain configurations to NetworkProxy`);
|
console.log(`Synced ${proxyConfigs.length} configurations to NetworkProxy`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(`Failed to sync configurations: ${err}`);
|
console.log(`Error syncing routes to NetworkProxy: ${err}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert routes to NetworkProxy configuration format
|
||||||
|
*
|
||||||
|
* This method transforms route-based configuration to NetworkProxy's configuration format.
|
||||||
|
* It processes each route and creates appropriate NetworkProxy configs for domains
|
||||||
|
* that require TLS termination.
|
||||||
|
*
|
||||||
|
* @param routes Array of route configurations to convert
|
||||||
|
* @param defaultCertPair Default certificate to use if no custom certificate is specified
|
||||||
|
* @returns Array of NetworkProxy configurations
|
||||||
|
*/
|
||||||
|
public convertRoutesToNetworkProxyConfigs(
|
||||||
|
routes: IRouteConfig[],
|
||||||
|
defaultCertPair: { key: string; cert: string }
|
||||||
|
): plugins.tsclass.network.IReverseProxyConfig[] {
|
||||||
|
const configs: plugins.tsclass.network.IReverseProxyConfig[] = [];
|
||||||
|
|
||||||
|
for (const route of routes) {
|
||||||
|
// Skip routes without domains
|
||||||
|
if (!route.match.domains) continue;
|
||||||
|
|
||||||
|
// Skip non-forward routes
|
||||||
|
if (route.action.type !== 'forward') continue;
|
||||||
|
|
||||||
|
// Skip routes without TLS configuration
|
||||||
|
if (!route.action.tls || !route.action.target) continue;
|
||||||
|
|
||||||
|
// Get domains from route
|
||||||
|
const domains = Array.isArray(route.match.domains)
|
||||||
|
? route.match.domains
|
||||||
|
: [route.match.domains];
|
||||||
|
|
||||||
|
// Create a config for each domain
|
||||||
|
for (const domain of domains) {
|
||||||
|
// Determine if this route requires TLS termination
|
||||||
|
const needsTermination = route.action.tls.mode === 'terminate' ||
|
||||||
|
route.action.tls.mode === 'terminate-and-reencrypt';
|
||||||
|
|
||||||
|
// Skip passthrough domains for NetworkProxy
|
||||||
|
if (route.action.tls.mode === 'passthrough') continue;
|
||||||
|
|
||||||
|
// Get certificate
|
||||||
|
let certKey = defaultCertPair.key;
|
||||||
|
let certCert = defaultCertPair.cert;
|
||||||
|
|
||||||
|
// Use custom certificate if specified
|
||||||
|
if (route.action.tls.certificate !== 'auto' && typeof route.action.tls.certificate === 'object') {
|
||||||
|
certKey = route.action.tls.certificate.key;
|
||||||
|
certCert = route.action.tls.certificate.cert;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine target hosts and ports
|
||||||
|
const targetHosts = Array.isArray(route.action.target.host)
|
||||||
|
? route.action.target.host
|
||||||
|
: [route.action.target.host];
|
||||||
|
|
||||||
|
const targetPort = route.action.target.port;
|
||||||
|
|
||||||
|
// Create NetworkProxy config
|
||||||
|
const config: plugins.tsclass.network.IReverseProxyConfig = {
|
||||||
|
hostName: domain,
|
||||||
|
privateKey: certKey,
|
||||||
|
publicKey: certCert,
|
||||||
|
destinationIps: targetHosts,
|
||||||
|
destinationPorts: [targetPort],
|
||||||
|
proxyConfig: {
|
||||||
|
targetIsTls: route.action.tls.mode === 'terminate-and-reencrypt',
|
||||||
|
allowHTTP1: true,
|
||||||
|
// Apply any other NetworkProxy-specific settings
|
||||||
|
...(route.action.advanced ? {
|
||||||
|
preserveHost: true,
|
||||||
|
timeout: route.action.advanced.timeout,
|
||||||
|
headers: route.action.advanced.headers
|
||||||
|
} : {})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
configs.push(config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return configs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated This method is deprecated and will be removed in a future version.
|
||||||
|
* Use syncRoutesToNetworkProxy() instead.
|
||||||
|
*
|
||||||
|
* This legacy method exists only for backward compatibility and
|
||||||
|
* simply forwards to syncRoutesToNetworkProxy().
|
||||||
|
*/
|
||||||
|
public async syncDomainConfigsToNetworkProxy(): Promise<void> {
|
||||||
|
console.log('Method syncDomainConfigsToNetworkProxy is deprecated. Use syncRoutesToNetworkProxy instead.');
|
||||||
|
await this.syncRoutesToNetworkProxy(this.settings.routes || []);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request a certificate for a specific domain
|
* Request a certificate for a specific domain
|
||||||
*/
|
*/
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import * as plugins from '../../plugins.js';
|
import * as plugins from '../../plugins.js';
|
||||||
import type {
|
import type {
|
||||||
IConnectionRecord,
|
IConnectionRecord,
|
||||||
IDomainConfig,
|
|
||||||
ISmartProxyOptions
|
ISmartProxyOptions
|
||||||
} from './models/interfaces.js';
|
} from './models/interfaces.js';
|
||||||
import {
|
import {
|
||||||
isRoutedOptions,
|
isRoutedOptions
|
||||||
isLegacyOptions
|
|
||||||
} from './models/interfaces.js';
|
} from './models/interfaces.js';
|
||||||
import type {
|
import type {
|
||||||
IRouteConfig,
|
IRouteConfig,
|
||||||
@ -14,13 +12,11 @@ import type {
|
|||||||
} from './models/route-types.js';
|
} from './models/route-types.js';
|
||||||
import { ConnectionManager } from './connection-manager.js';
|
import { ConnectionManager } from './connection-manager.js';
|
||||||
import { SecurityManager } from './security-manager.js';
|
import { SecurityManager } from './security-manager.js';
|
||||||
import { DomainConfigManager } from './domain-config-manager.js';
|
|
||||||
import { TlsManager } from './tls-manager.js';
|
import { TlsManager } from './tls-manager.js';
|
||||||
import { NetworkProxyBridge } from './network-proxy-bridge.js';
|
import { NetworkProxyBridge } from './network-proxy-bridge.js';
|
||||||
import { TimeoutManager } from './timeout-manager.js';
|
import { TimeoutManager } from './timeout-manager.js';
|
||||||
import { RouteManager } from './route-manager.js';
|
import { RouteManager } from './route-manager.js';
|
||||||
import type { ForwardingHandler } from '../../forwarding/handlers/base-handler.js';
|
import type { ForwardingHandler } from '../../forwarding/handlers/base-handler.js';
|
||||||
import type { TForwardingType } from '../../forwarding/config/forwarding-types.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles new connection processing and setup logic with support for route-based configuration
|
* Handles new connection processing and setup logic with support for route-based configuration
|
||||||
@ -32,7 +28,6 @@ export class RouteConnectionHandler {
|
|||||||
settings: ISmartProxyOptions,
|
settings: ISmartProxyOptions,
|
||||||
private connectionManager: ConnectionManager,
|
private connectionManager: ConnectionManager,
|
||||||
private securityManager: SecurityManager,
|
private securityManager: SecurityManager,
|
||||||
private domainConfigManager: DomainConfigManager,
|
|
||||||
private tlsManager: TlsManager,
|
private tlsManager: TlsManager,
|
||||||
private networkProxyBridge: NetworkProxyBridge,
|
private networkProxyBridge: NetworkProxyBridge,
|
||||||
private timeoutManager: TimeoutManager,
|
private timeoutManager: TimeoutManager,
|
||||||
@ -245,34 +240,17 @@ export class RouteConnectionHandler {
|
|||||||
if (!routeMatch) {
|
if (!routeMatch) {
|
||||||
console.log(`[${connectionId}] No route found for ${serverName || 'connection'} on port ${localPort}`);
|
console.log(`[${connectionId}] No route found for ${serverName || 'connection'} on port ${localPort}`);
|
||||||
|
|
||||||
// Fall back to legacy matching if we're using a hybrid configuration
|
// No matching route, use default/fallback handling
|
||||||
const domainConfig = serverName
|
|
||||||
? this.domainConfigManager.findDomainConfig(serverName)
|
|
||||||
: this.domainConfigManager.findDomainConfigForPort(localPort);
|
|
||||||
|
|
||||||
if (domainConfig) {
|
|
||||||
if (this.settings.enableDetailedLogging) {
|
|
||||||
console.log(`[${connectionId}] Using legacy domain configuration for ${serverName || 'port ' + localPort}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Associate this domain config with the connection
|
|
||||||
record.domainConfig = domainConfig;
|
|
||||||
|
|
||||||
// Handle the connection using the legacy setup
|
|
||||||
return this.handleLegacyConnection(socket, record, serverName, domainConfig, initialChunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
// No matching route or domain config, use default/fallback handling
|
|
||||||
console.log(`[${connectionId}] Using default route handling for connection`);
|
console.log(`[${connectionId}] Using default route handling for connection`);
|
||||||
|
|
||||||
// Check default security settings
|
// Check default security settings
|
||||||
const defaultSecuritySettings = this.settings.defaults?.security;
|
const defaultSecuritySettings = this.settings.defaults?.security;
|
||||||
if (defaultSecuritySettings) {
|
if (defaultSecuritySettings) {
|
||||||
if (defaultSecuritySettings.allowedIPs && defaultSecuritySettings.allowedIPs.length > 0) {
|
if (defaultSecuritySettings.allowedIps && defaultSecuritySettings.allowedIps.length > 0) {
|
||||||
const isAllowed = this.securityManager.isIPAuthorized(
|
const isAllowed = this.securityManager.isIPAuthorized(
|
||||||
remoteIP,
|
remoteIP,
|
||||||
defaultSecuritySettings.allowedIPs,
|
defaultSecuritySettings.allowedIps,
|
||||||
defaultSecuritySettings.blockedIPs || []
|
defaultSecuritySettings.blockedIps || []
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!isAllowed) {
|
if (!isAllowed) {
|
||||||
@ -282,41 +260,13 @@ export class RouteConnectionHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (this.settings.defaultAllowedIPs && this.settings.defaultAllowedIPs.length > 0) {
|
|
||||||
// Legacy default IP restrictions
|
|
||||||
const isAllowed = this.securityManager.isIPAuthorized(
|
|
||||||
remoteIP,
|
|
||||||
this.settings.defaultAllowedIPs,
|
|
||||||
this.settings.defaultBlockedIPs || []
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!isAllowed) {
|
|
||||||
console.log(`[${connectionId}] IP ${remoteIP} not in default allowed list`);
|
|
||||||
socket.end();
|
|
||||||
this.connectionManager.cleanupConnection(record, 'ip_blocked');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup direct connection with default settings
|
// Setup direct connection with default settings
|
||||||
let targetHost: string;
|
if (this.settings.defaults?.target) {
|
||||||
let targetPort: number;
|
// Use defaults from configuration
|
||||||
|
const targetHost = this.settings.defaults.target.host;
|
||||||
if (isRoutedOptions(this.settings) && this.settings.defaults?.target) {
|
const targetPort = this.settings.defaults.target.port;
|
||||||
// Use defaults from routed configuration
|
|
||||||
targetHost = this.settings.defaults.target.host;
|
|
||||||
targetPort = this.settings.defaults.target.port;
|
|
||||||
} else if (this.settings.targetIP && this.settings.toPort) {
|
|
||||||
// Fall back to legacy settings
|
|
||||||
targetHost = this.settings.targetIP;
|
|
||||||
targetPort = this.settings.toPort;
|
|
||||||
} else {
|
|
||||||
// No default target available, terminate the connection
|
|
||||||
console.log(`[${connectionId}] No default target configured. Closing connection.`);
|
|
||||||
socket.end();
|
|
||||||
this.connectionManager.cleanupConnection(record, 'no_default_target');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.setupDirectConnection(
|
return this.setupDirectConnection(
|
||||||
socket,
|
socket,
|
||||||
@ -328,6 +278,13 @@ export class RouteConnectionHandler {
|
|||||||
targetHost,
|
targetHost,
|
||||||
targetPort
|
targetPort
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
// No default target available, terminate the connection
|
||||||
|
console.log(`[${connectionId}] No default target configured. Closing connection.`);
|
||||||
|
socket.end();
|
||||||
|
this.connectionManager.cleanupConnection(record, 'no_default_target');
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A matching route was found
|
// A matching route was found
|
||||||
@ -575,114 +532,8 @@ export class RouteConnectionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a connection using legacy domain configuration
|
* Legacy connection handling has been removed in favor of pure route-based approach
|
||||||
*/
|
*/
|
||||||
private handleLegacyConnection(
|
|
||||||
socket: plugins.net.Socket,
|
|
||||||
record: IConnectionRecord,
|
|
||||||
serverName: string,
|
|
||||||
domainConfig: IDomainConfig,
|
|
||||||
initialChunk?: Buffer
|
|
||||||
): void {
|
|
||||||
const connectionId = record.id;
|
|
||||||
|
|
||||||
// Get the forwarding type for this domain
|
|
||||||
const forwardingType = this.domainConfigManager.getForwardingType(domainConfig);
|
|
||||||
|
|
||||||
// IP validation
|
|
||||||
const ipRules = this.domainConfigManager.getEffectiveIPRules(domainConfig);
|
|
||||||
|
|
||||||
if (!this.securityManager.isIPAuthorized(record.remoteIP, ipRules.allowedIPs, ipRules.blockedIPs)) {
|
|
||||||
console.log(
|
|
||||||
`[${connectionId}] Connection rejected: IP ${record.remoteIP} not allowed for domain ${domainConfig.domains.join(', ')}`
|
|
||||||
);
|
|
||||||
socket.end();
|
|
||||||
this.connectionManager.initiateCleanupOnce(record, 'ip_blocked');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle based on forwarding type
|
|
||||||
switch (forwardingType) {
|
|
||||||
case 'http-only':
|
|
||||||
// For HTTP-only configs with TLS traffic
|
|
||||||
if (record.isTLS) {
|
|
||||||
console.log(`[${connectionId}] Received TLS connection for HTTP-only domain ${serverName}`);
|
|
||||||
socket.end();
|
|
||||||
this.connectionManager.initiateCleanupOnce(record, 'wrong_protocol');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'https-passthrough':
|
|
||||||
// For TLS passthrough with TLS traffic
|
|
||||||
if (record.isTLS) {
|
|
||||||
try {
|
|
||||||
const handler = this.domainConfigManager.getForwardingHandler(domainConfig);
|
|
||||||
|
|
||||||
if (this.settings.enableDetailedLogging) {
|
|
||||||
console.log(`[${connectionId}] Using forwarding handler for SNI passthrough to ${serverName}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle the connection using the handler
|
|
||||||
return handler.handleConnection(socket);
|
|
||||||
} catch (err) {
|
|
||||||
console.log(`[${connectionId}] Error using forwarding handler: ${err}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'https-terminate-to-http':
|
|
||||||
case 'https-terminate-to-https':
|
|
||||||
// For TLS termination with TLS traffic
|
|
||||||
if (record.isTLS) {
|
|
||||||
const networkProxyPort = this.domainConfigManager.getNetworkProxyPort(domainConfig);
|
|
||||||
|
|
||||||
if (this.settings.enableDetailedLogging) {
|
|
||||||
console.log(`[${connectionId}] Using TLS termination (${forwardingType}) for ${serverName} on port ${networkProxyPort}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forward to NetworkProxy with domain-specific port
|
|
||||||
return this.networkProxyBridge.forwardToNetworkProxy(
|
|
||||||
connectionId,
|
|
||||||
socket,
|
|
||||||
record,
|
|
||||||
initialChunk!,
|
|
||||||
networkProxyPort,
|
|
||||||
(reason) => this.connectionManager.initiateCleanupOnce(record, reason)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we're still here, use the forwarding handler if available
|
|
||||||
try {
|
|
||||||
const handler = this.domainConfigManager.getForwardingHandler(domainConfig);
|
|
||||||
|
|
||||||
if (this.settings.enableDetailedLogging) {
|
|
||||||
console.log(`[${connectionId}] Using general forwarding handler for domain ${serverName || 'unknown'}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle the connection using the handler
|
|
||||||
return handler.handleConnection(socket);
|
|
||||||
} catch (err) {
|
|
||||||
console.log(`[${connectionId}] Error using forwarding handler: ${err}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback: set up direct connection
|
|
||||||
const targetIp = this.domainConfigManager.getTargetIP(domainConfig);
|
|
||||||
const targetPort = this.domainConfigManager.getTargetPort(domainConfig, this.settings.toPort);
|
|
||||||
|
|
||||||
return this.setupDirectConnection(
|
|
||||||
socket,
|
|
||||||
record,
|
|
||||||
domainConfig,
|
|
||||||
serverName,
|
|
||||||
initialChunk,
|
|
||||||
undefined,
|
|
||||||
targetIp,
|
|
||||||
targetPort
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up a direct connection to the target
|
* Sets up a direct connection to the target
|
||||||
@ -690,7 +541,7 @@ export class RouteConnectionHandler {
|
|||||||
private setupDirectConnection(
|
private setupDirectConnection(
|
||||||
socket: plugins.net.Socket,
|
socket: plugins.net.Socket,
|
||||||
record: IConnectionRecord,
|
record: IConnectionRecord,
|
||||||
domainConfig?: IDomainConfig,
|
_unused?: any, // kept for backward compatibility
|
||||||
serverName?: string,
|
serverName?: string,
|
||||||
initialChunk?: Buffer,
|
initialChunk?: Buffer,
|
||||||
overridePort?: number,
|
overridePort?: number,
|
||||||
@ -700,20 +551,13 @@ export class RouteConnectionHandler {
|
|||||||
const connectionId = record.id;
|
const connectionId = record.id;
|
||||||
|
|
||||||
// Determine target host and port if not provided
|
// Determine target host and port if not provided
|
||||||
const finalTargetHost = targetHost || (domainConfig
|
const finalTargetHost = targetHost ||
|
||||||
? this.domainConfigManager.getTargetIP(domainConfig)
|
(this.settings.defaults?.target?.host || 'localhost');
|
||||||
: this.settings.defaults?.target?.host
|
|
||||||
? this.settings.defaults.target.host
|
|
||||||
: this.settings.targetIP!);
|
|
||||||
|
|
||||||
// Determine target port - first try explicit port, then forwarding config, then fallback
|
// Determine target port
|
||||||
const finalTargetPort = targetPort || (overridePort !== undefined
|
const finalTargetPort = targetPort ||
|
||||||
? overridePort
|
(overridePort !== undefined ? overridePort :
|
||||||
: domainConfig
|
(this.settings.defaults?.target?.port || 443));
|
||||||
? this.domainConfigManager.getTargetPort(domainConfig, this.settings.toPort)
|
|
||||||
: this.settings.defaults?.target?.port
|
|
||||||
? this.settings.defaults.target.port
|
|
||||||
: this.settings.toPort);
|
|
||||||
|
|
||||||
// Setup connection options
|
// Setup connection options
|
||||||
const connectionOptions: plugins.net.NetConnectOpts = {
|
const connectionOptions: plugins.net.NetConnectOpts = {
|
||||||
|
@ -3,7 +3,6 @@ import * as plugins from '../../plugins.js';
|
|||||||
// Importing required components
|
// Importing required components
|
||||||
import { ConnectionManager } from './connection-manager.js';
|
import { ConnectionManager } from './connection-manager.js';
|
||||||
import { SecurityManager } from './security-manager.js';
|
import { SecurityManager } from './security-manager.js';
|
||||||
import { DomainConfigManager } from './domain-config-manager.js';
|
|
||||||
import { TlsManager } from './tls-manager.js';
|
import { TlsManager } from './tls-manager.js';
|
||||||
import { NetworkProxyBridge } from './network-proxy-bridge.js';
|
import { NetworkProxyBridge } from './network-proxy-bridge.js';
|
||||||
import { TimeoutManager } from './timeout-manager.js';
|
import { TimeoutManager } from './timeout-manager.js';
|
||||||
@ -21,14 +20,23 @@ import { createPort80HandlerOptions } from '../../common/port80-adapter.js';
|
|||||||
// Import types and utilities
|
// Import types and utilities
|
||||||
import type {
|
import type {
|
||||||
ISmartProxyOptions,
|
ISmartProxyOptions,
|
||||||
IRoutedSmartProxyOptions,
|
IRoutedSmartProxyOptions
|
||||||
IDomainConfig
|
|
||||||
} from './models/interfaces.js';
|
} from './models/interfaces.js';
|
||||||
import { isRoutedOptions, isLegacyOptions } from './models/interfaces.js';
|
import { isRoutedOptions } from './models/interfaces.js';
|
||||||
import type { IRouteConfig } from './models/route-types.js';
|
import type { IRouteConfig } from './models/route-types.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SmartProxy - Unified route-based API
|
* SmartProxy - Pure route-based API
|
||||||
|
*
|
||||||
|
* SmartProxy is a unified proxy system that works with routes to define connection handling behavior.
|
||||||
|
* Each route contains matching criteria (ports, domains, etc.) and an action to take (forward, redirect, block).
|
||||||
|
*
|
||||||
|
* Configuration is provided through a set of routes, with each route defining:
|
||||||
|
* - What to match (ports, domains, paths, client IPs)
|
||||||
|
* - What to do with matching traffic (forward, redirect, block)
|
||||||
|
* - How to handle TLS (passthrough, terminate, terminate-and-reencrypt)
|
||||||
|
* - Security settings (IP restrictions, connection limits)
|
||||||
|
* - Advanced options (timeout, headers, etc.)
|
||||||
*/
|
*/
|
||||||
export class SmartProxy extends plugins.EventEmitter {
|
export class SmartProxy extends plugins.EventEmitter {
|
||||||
private netServers: plugins.net.Server[] = [];
|
private netServers: plugins.net.Server[] = [];
|
||||||
@ -38,7 +46,6 @@ export class SmartProxy extends plugins.EventEmitter {
|
|||||||
// Component managers
|
// Component managers
|
||||||
private connectionManager: ConnectionManager;
|
private connectionManager: ConnectionManager;
|
||||||
private securityManager: SecurityManager;
|
private securityManager: SecurityManager;
|
||||||
private domainConfigManager: DomainConfigManager;
|
|
||||||
private tlsManager: TlsManager;
|
private tlsManager: TlsManager;
|
||||||
private networkProxyBridge: NetworkProxyBridge;
|
private networkProxyBridge: NetworkProxyBridge;
|
||||||
private timeoutManager: TimeoutManager;
|
private timeoutManager: TimeoutManager;
|
||||||
@ -52,7 +59,35 @@ export class SmartProxy extends plugins.EventEmitter {
|
|||||||
private certProvisioner?: CertProvisioner;
|
private certProvisioner?: CertProvisioner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor that supports both legacy and route-based configuration
|
* Constructor for SmartProxy
|
||||||
|
*
|
||||||
|
* @param settingsArg Configuration options containing routes and other settings
|
||||||
|
* Routes define how traffic is matched and handled, with each route having:
|
||||||
|
* - match: criteria for matching traffic (ports, domains, paths, IPs)
|
||||||
|
* - action: what to do with matched traffic (forward, redirect, block)
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* ```ts
|
||||||
|
* const proxy = new SmartProxy({
|
||||||
|
* routes: [
|
||||||
|
* {
|
||||||
|
* match: {
|
||||||
|
* ports: 443,
|
||||||
|
* domains: ['example.com', '*.example.com']
|
||||||
|
* },
|
||||||
|
* action: {
|
||||||
|
* type: 'forward',
|
||||||
|
* target: { host: '10.0.0.1', port: 8443 },
|
||||||
|
* tls: { mode: 'passthrough' }
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* ],
|
||||||
|
* defaults: {
|
||||||
|
* target: { host: 'localhost', port: 8080 },
|
||||||
|
* security: { allowedIps: ['*'] }
|
||||||
|
* }
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
*/
|
*/
|
||||||
constructor(settingsArg: ISmartProxyOptions) {
|
constructor(settingsArg: ISmartProxyOptions) {
|
||||||
super();
|
super();
|
||||||
@ -113,17 +148,10 @@ export class SmartProxy extends plugins.EventEmitter {
|
|||||||
this.timeoutManager
|
this.timeoutManager
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create the new route manager first
|
// Create the route manager
|
||||||
this.routeManager = new RouteManager(this.settings);
|
this.routeManager = new RouteManager(this.settings);
|
||||||
|
|
||||||
// Create domain config manager and port range manager
|
// Create port range manager
|
||||||
this.domainConfigManager = new DomainConfigManager(this.settings);
|
|
||||||
|
|
||||||
// Share the route manager with the domain config manager
|
|
||||||
if (typeof this.domainConfigManager.setRouteManager === 'function') {
|
|
||||||
this.domainConfigManager.setRouteManager(this.routeManager);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.portRangeManager = new PortRangeManager(this.settings);
|
this.portRangeManager = new PortRangeManager(this.settings);
|
||||||
|
|
||||||
// Create other required components
|
// Create other required components
|
||||||
@ -135,7 +163,6 @@ export class SmartProxy extends plugins.EventEmitter {
|
|||||||
this.settings,
|
this.settings,
|
||||||
this.connectionManager,
|
this.connectionManager,
|
||||||
this.securityManager,
|
this.securityManager,
|
||||||
this.domainConfigManager,
|
|
||||||
this.tlsManager,
|
this.tlsManager,
|
||||||
this.networkProxyBridge,
|
this.networkProxyBridge,
|
||||||
this.timeoutManager,
|
this.timeoutManager,
|
||||||
@ -162,7 +189,7 @@ export class SmartProxy extends plugins.EventEmitter {
|
|||||||
// Build and start the Port80Handler
|
// Build and start the Port80Handler
|
||||||
this.port80Handler = buildPort80Handler({
|
this.port80Handler = buildPort80Handler({
|
||||||
...config,
|
...config,
|
||||||
httpsRedirectPort: config.httpsRedirectPort || (isLegacyOptions(this.settings) ? this.settings.fromPort : 443)
|
httpsRedirectPort: config.httpsRedirectPort || 443
|
||||||
});
|
});
|
||||||
|
|
||||||
// Share Port80Handler with NetworkProxyBridge before start
|
// Share Port80Handler with NetworkProxyBridge before start
|
||||||
@ -184,17 +211,7 @@ export class SmartProxy extends plugins.EventEmitter {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize domain config based on configuration type
|
// Pure route-based configuration - no domain configs needed
|
||||||
if (isLegacyOptions(this.settings)) {
|
|
||||||
// Initialize domain config manager with the legacy domain configs
|
|
||||||
this.domainConfigManager.updateDomainConfigs(this.settings.domainConfigs || []);
|
|
||||||
} else if (isRoutedOptions(this.settings)) {
|
|
||||||
// For pure route-based configuration, the domain config is already initialized
|
|
||||||
// in the constructor, but we might need to regenerate it
|
|
||||||
if (typeof this.domainConfigManager.generateDomainConfigsFromRoutes === 'function') {
|
|
||||||
this.domainConfigManager.generateDomainConfigsFromRoutes();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize Port80Handler if enabled
|
// Initialize Port80Handler if enabled
|
||||||
await this.initializePort80Handler();
|
await this.initializePort80Handler();
|
||||||
@ -248,9 +265,10 @@ export class SmartProxy extends plugins.EventEmitter {
|
|||||||
}) || [];
|
}) || [];
|
||||||
|
|
||||||
// Create CertProvisioner with appropriate parameters
|
// Create CertProvisioner with appropriate parameters
|
||||||
if (isLegacyOptions(this.settings)) {
|
// No longer need to support multiple configuration types
|
||||||
|
// Just pass the routes directly
|
||||||
this.certProvisioner = new CertProvisioner(
|
this.certProvisioner = new CertProvisioner(
|
||||||
this.settings.domainConfigs,
|
this.settings.routes,
|
||||||
this.port80Handler,
|
this.port80Handler,
|
||||||
this.networkProxyBridge,
|
this.networkProxyBridge,
|
||||||
this.settings.certProvisionFunction,
|
this.settings.certProvisionFunction,
|
||||||
@ -259,24 +277,6 @@ export class SmartProxy extends plugins.EventEmitter {
|
|||||||
acme.autoRenew!,
|
acme.autoRenew!,
|
||||||
domainForwards
|
domainForwards
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
// For route-based configuration, we need to adapt the interface
|
|
||||||
// Convert routes to domain configs for CertProvisioner
|
|
||||||
const domainConfigs: IDomainConfig[] = this.extractDomainConfigsFromRoutes(
|
|
||||||
(this.settings as IRoutedSmartProxyOptions).routes
|
|
||||||
);
|
|
||||||
|
|
||||||
this.certProvisioner = new CertProvisioner(
|
|
||||||
domainConfigs,
|
|
||||||
this.port80Handler,
|
|
||||||
this.networkProxyBridge,
|
|
||||||
this.settings.certProvisionFunction,
|
|
||||||
acme.renewThresholdDays!,
|
|
||||||
acme.renewCheckIntervalHours!,
|
|
||||||
acme.autoRenew!,
|
|
||||||
domainForwards
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register certificate event handler
|
// Register certificate event handler
|
||||||
this.certProvisioner.on('certificate', (certData) => {
|
this.certProvisioner.on('certificate', (certData) => {
|
||||||
@ -416,60 +416,9 @@ export class SmartProxy extends plugins.EventEmitter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract domain configurations from routes for certificate provisioning
|
* Extract domain configurations from routes for certificate provisioning
|
||||||
|
*
|
||||||
|
* Note: This method has been removed as we now work directly with routes
|
||||||
*/
|
*/
|
||||||
private extractDomainConfigsFromRoutes(routes: IRouteConfig[]): IDomainConfig[] {
|
|
||||||
const domainConfigs: IDomainConfig[] = [];
|
|
||||||
|
|
||||||
for (const route of routes) {
|
|
||||||
// Skip routes without domain specs
|
|
||||||
if (!route.match.domains) continue;
|
|
||||||
|
|
||||||
// Skip non-forward routes
|
|
||||||
if (route.action.type !== 'forward') continue;
|
|
||||||
|
|
||||||
// Only process routes that need TLS termination (those with certificates)
|
|
||||||
if (!route.action.tls ||
|
|
||||||
route.action.tls.mode === 'passthrough' ||
|
|
||||||
!route.action.target) continue;
|
|
||||||
|
|
||||||
const domains = Array.isArray(route.match.domains)
|
|
||||||
? route.match.domains
|
|
||||||
: [route.match.domains];
|
|
||||||
|
|
||||||
// Determine forwarding type based on TLS mode
|
|
||||||
const forwardingType = route.action.tls.mode === 'terminate'
|
|
||||||
? 'https-terminate-to-http'
|
|
||||||
: 'https-terminate-to-https';
|
|
||||||
|
|
||||||
// Create a forwarding config
|
|
||||||
const forwarding = {
|
|
||||||
type: forwardingType as any,
|
|
||||||
target: {
|
|
||||||
host: Array.isArray(route.action.target.host)
|
|
||||||
? route.action.target.host[0]
|
|
||||||
: route.action.target.host,
|
|
||||||
port: route.action.target.port
|
|
||||||
},
|
|
||||||
// Add TLS settings
|
|
||||||
https: {
|
|
||||||
customCert: route.action.tls.certificate !== 'auto'
|
|
||||||
? route.action.tls.certificate
|
|
||||||
: undefined
|
|
||||||
},
|
|
||||||
// Add security settings if present
|
|
||||||
security: route.action.security,
|
|
||||||
// Add advanced settings if present
|
|
||||||
advanced: route.action.advanced
|
|
||||||
};
|
|
||||||
|
|
||||||
domainConfigs.push({
|
|
||||||
domains,
|
|
||||||
forwarding
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return domainConfigs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop the proxy server
|
* Stop the proxy server
|
||||||
@ -535,90 +484,37 @@ export class SmartProxy extends plugins.EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the domain configurations for the proxy (legacy support)
|
* Updates the domain configurations for the proxy
|
||||||
|
*
|
||||||
|
* Note: This legacy method has been removed. Use updateRoutes instead.
|
||||||
*/
|
*/
|
||||||
public async updateDomainConfigs(newDomainConfigs: IDomainConfig[]): Promise<void> {
|
public async updateDomainConfigs(): Promise<void> {
|
||||||
console.log(`Updating domain configurations (${newDomainConfigs.length} configs)`);
|
console.warn('Method updateDomainConfigs() is deprecated. Use updateRoutes() instead.');
|
||||||
|
throw new Error('updateDomainConfigs() is deprecated - use updateRoutes() instead');
|
||||||
// Update domain configs in DomainConfigManager (legacy)
|
|
||||||
this.domainConfigManager.updateDomainConfigs(newDomainConfigs);
|
|
||||||
|
|
||||||
// Also update the RouteManager with these domain configs
|
|
||||||
this.routeManager.updateFromDomainConfigs(newDomainConfigs);
|
|
||||||
|
|
||||||
// If NetworkProxy is initialized, resync the configurations
|
|
||||||
if (this.networkProxyBridge.getNetworkProxy()) {
|
|
||||||
await this.networkProxyBridge.syncDomainConfigsToNetworkProxy();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If Port80Handler is running, provision certificates based on forwarding type
|
|
||||||
if (this.port80Handler && this.settings.acme?.enabled) {
|
|
||||||
for (const domainConfig of newDomainConfigs) {
|
|
||||||
// Skip certificate provisioning for http-only or passthrough configs that don't need certs
|
|
||||||
const forwardingType = this.domainConfigManager.getForwardingType(domainConfig);
|
|
||||||
const needsCertificate =
|
|
||||||
forwardingType === 'https-terminate-to-http' ||
|
|
||||||
forwardingType === 'https-terminate-to-https';
|
|
||||||
|
|
||||||
// Skip certificate provisioning if ACME is explicitly disabled for this domain
|
|
||||||
const acmeDisabled = domainConfig.forwarding.acme?.enabled === false;
|
|
||||||
|
|
||||||
if (!needsCertificate || acmeDisabled) {
|
|
||||||
if (this.settings.enableDetailedLogging) {
|
|
||||||
console.log(`Skipping certificate provisioning for ${domainConfig.domains.join(', ')} (${forwardingType})`);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const domain of domainConfig.domains) {
|
|
||||||
const isWildcard = domain.includes('*');
|
|
||||||
let provision: string | plugins.tsclass.network.ICert = 'http01';
|
|
||||||
|
|
||||||
// Check for ACME forwarding configuration in the domain
|
|
||||||
const forwardAcmeChallenges = domainConfig.forwarding.acme?.forwardChallenges;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create Port80Handler options from the forwarding configuration
|
|
||||||
const port80Config = createPort80HandlerOptions(domain, domainConfig.forwarding);
|
|
||||||
|
|
||||||
this.port80Handler.addDomain(port80Config);
|
|
||||||
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,
|
|
||||||
certificate: certObj.publicKey,
|
|
||||||
privateKey: certObj.privateKey,
|
|
||||||
expiryDate: new Date(certObj.validUntil)
|
|
||||||
};
|
|
||||||
this.networkProxyBridge.applyExternalCertificate(certData);
|
|
||||||
console.log(`Applied static certificate for ${domain} from certProvider`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.log('Provisioned certificates for new domains');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update routes with new configuration (new API)
|
* Update routes with new configuration
|
||||||
|
*
|
||||||
|
* This method replaces the current route configuration with the provided routes.
|
||||||
|
* It also provisions certificates for routes that require TLS termination and have
|
||||||
|
* `certificate: 'auto'` set in their TLS configuration.
|
||||||
|
*
|
||||||
|
* @param newRoutes Array of route configurations to use
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* ```ts
|
||||||
|
* proxy.updateRoutes([
|
||||||
|
* {
|
||||||
|
* match: { ports: 443, domains: 'secure.example.com' },
|
||||||
|
* action: {
|
||||||
|
* type: 'forward',
|
||||||
|
* target: { host: '10.0.0.1', port: 8443 },
|
||||||
|
* tls: { mode: 'terminate', certificate: 'auto' }
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* ]);
|
||||||
|
* ```
|
||||||
*/
|
*/
|
||||||
public async updateRoutes(newRoutes: IRouteConfig[]): Promise<void> {
|
public async updateRoutes(newRoutes: IRouteConfig[]): Promise<void> {
|
||||||
console.log(`Updating routes (${newRoutes.length} routes)`);
|
console.log(`Updating routes (${newRoutes.length} routes)`);
|
||||||
@ -628,14 +524,7 @@ export class SmartProxy extends plugins.EventEmitter {
|
|||||||
|
|
||||||
// If NetworkProxy is initialized, resync the configurations
|
// If NetworkProxy is initialized, resync the configurations
|
||||||
if (this.networkProxyBridge.getNetworkProxy()) {
|
if (this.networkProxyBridge.getNetworkProxy()) {
|
||||||
// Create equivalent domain configs for NetworkProxy
|
await this.networkProxyBridge.syncRoutesToNetworkProxy(newRoutes);
|
||||||
const domainConfigs = this.extractDomainConfigsFromRoutes(newRoutes);
|
|
||||||
|
|
||||||
// Update domain configs in DomainConfigManager for sync
|
|
||||||
this.domainConfigManager.updateDomainConfigs(domainConfigs);
|
|
||||||
|
|
||||||
// Sync with NetworkProxy
|
|
||||||
await this.networkProxyBridge.syncDomainConfigsToNetworkProxy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If Port80Handler is running, provision certificates based on routes
|
// If Port80Handler is running, provision certificates based on routes
|
||||||
|
Loading…
x
Reference in New Issue
Block a user