- Renamed port proxy and SNI handler source files to classes.pp.portproxy.js and classes.pp.snihandler.js respectively - Updated import paths in index.ts and test files (e.g. in test.ts and test.router.ts) to reference the new file names - This refactor improves code organization but breaks direct imports from the old paths
149 lines
4.6 KiB
TypeScript
149 lines
4.6 KiB
TypeScript
import type { IPortProxySettings } from './classes.pp.interfaces.js';
|
|
import { NetworkProxyBridge } from './classes.pp.networkproxybridge.js';
|
|
|
|
/**
|
|
* Manages ACME certificate operations
|
|
*/
|
|
export class AcmeManager {
|
|
constructor(
|
|
private settings: IPortProxySettings,
|
|
private networkProxyBridge: NetworkProxyBridge
|
|
) {}
|
|
|
|
/**
|
|
* Get current ACME settings
|
|
*/
|
|
public getAcmeSettings(): IPortProxySettings['acme'] {
|
|
return this.settings.acme;
|
|
}
|
|
|
|
/**
|
|
* Check if ACME is enabled
|
|
*/
|
|
public isAcmeEnabled(): boolean {
|
|
return !!this.settings.acme?.enabled;
|
|
}
|
|
|
|
/**
|
|
* Update ACME certificate settings
|
|
*/
|
|
public async updateAcmeSettings(acmeSettings: IPortProxySettings['acme']): Promise<void> {
|
|
console.log('Updating ACME certificate settings');
|
|
|
|
// Check if enabled state is changing
|
|
const enabledChanging = this.settings.acme?.enabled !== acmeSettings.enabled;
|
|
|
|
// Update settings
|
|
this.settings.acme = {
|
|
...this.settings.acme,
|
|
...acmeSettings,
|
|
};
|
|
|
|
// Get NetworkProxy instance
|
|
const networkProxy = this.networkProxyBridge.getNetworkProxy();
|
|
|
|
if (!networkProxy) {
|
|
console.log('Cannot update ACME settings - NetworkProxy not initialized');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// If enabled state changed, we need to restart NetworkProxy
|
|
if (enabledChanging) {
|
|
console.log(`ACME enabled state changed to: ${acmeSettings.enabled}`);
|
|
|
|
// Stop the current NetworkProxy
|
|
await this.networkProxyBridge.stop();
|
|
|
|
// Reinitialize with new settings
|
|
await this.networkProxyBridge.initialize();
|
|
|
|
// Start NetworkProxy with new settings
|
|
await this.networkProxyBridge.start();
|
|
} else {
|
|
// Just update the settings in the existing NetworkProxy
|
|
console.log('Updating ACME settings in NetworkProxy without restart');
|
|
|
|
// Update settings in NetworkProxy
|
|
if (networkProxy.options && networkProxy.options.acme) {
|
|
networkProxy.options.acme = { ...this.settings.acme };
|
|
|
|
// For certificate renewals, we might want to trigger checks with the new settings
|
|
if (acmeSettings.renewThresholdDays !== undefined) {
|
|
console.log(`Setting new renewal threshold to ${acmeSettings.renewThresholdDays} days`);
|
|
networkProxy.options.acme.renewThresholdDays = acmeSettings.renewThresholdDays;
|
|
}
|
|
|
|
// Update other settings that might affect certificate operations
|
|
if (acmeSettings.useProduction !== undefined) {
|
|
console.log(`Setting ACME to ${acmeSettings.useProduction ? 'production' : 'staging'} mode`);
|
|
}
|
|
|
|
if (acmeSettings.autoRenew !== undefined) {
|
|
console.log(`Setting auto-renewal to ${acmeSettings.autoRenew ? 'enabled' : 'disabled'}`);
|
|
}
|
|
}
|
|
}
|
|
} catch (err) {
|
|
console.log(`Error updating ACME settings: ${err}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Request a certificate for a specific domain
|
|
*/
|
|
public async requestCertificate(domain: string): Promise<boolean> {
|
|
// Validate domain format
|
|
if (!this.isValidDomain(domain)) {
|
|
console.log(`Invalid domain format: ${domain}`);
|
|
return false;
|
|
}
|
|
|
|
// Delegate to NetworkProxyManager
|
|
return this.networkProxyBridge.requestCertificate(domain);
|
|
}
|
|
|
|
/**
|
|
* Basic domain validation
|
|
*/
|
|
private isValidDomain(domain: string): boolean {
|
|
// Very basic domain validation
|
|
if (!domain || domain.length === 0) {
|
|
return false;
|
|
}
|
|
|
|
// Check for wildcard domains (they can't get ACME certs)
|
|
if (domain.includes('*')) {
|
|
console.log(`Wildcard domains like "${domain}" are not supported for ACME certificates`);
|
|
return false;
|
|
}
|
|
|
|
// Check if domain has at least one dot and no invalid characters
|
|
const validDomainRegex = /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
|
|
if (!validDomainRegex.test(domain)) {
|
|
console.log(`Domain "${domain}" has invalid format`);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get eligible domains for ACME certificates
|
|
*/
|
|
public getEligibleDomains(): string[] {
|
|
// Collect all eligible domains from domain configs
|
|
const domains: string[] = [];
|
|
|
|
for (const config of this.settings.domainConfigs) {
|
|
// Skip domains that can't be used with ACME
|
|
const eligibleDomains = config.domains.filter(domain =>
|
|
!domain.includes('*') && this.isValidDomain(domain)
|
|
);
|
|
|
|
domains.push(...eligibleDomains);
|
|
}
|
|
|
|
return domains;
|
|
}
|
|
} |