177 lines
5.7 KiB
TypeScript
177 lines
5.7 KiB
TypeScript
import * as plugins from '../../plugins.js';
|
|
import type { IDomainOptions, IAcmeOptions } from '../models/common-types.js';
|
|
|
|
/**
|
|
* Collection of validation utilities for configuration and domain options
|
|
*/
|
|
export class ValidationUtils {
|
|
/**
|
|
* Validates domain configuration options
|
|
*
|
|
* @param domainOptions The domain options to validate
|
|
* @returns An object with validation result and error message if invalid
|
|
*/
|
|
public static validateDomainOptions(domainOptions: IDomainOptions): { isValid: boolean; error?: string } {
|
|
if (!domainOptions) {
|
|
return { isValid: false, error: 'Domain options cannot be null or undefined' };
|
|
}
|
|
|
|
if (!domainOptions.domainName) {
|
|
return { isValid: false, error: 'Domain name is required' };
|
|
}
|
|
|
|
// Check domain pattern
|
|
if (!this.isValidDomainName(domainOptions.domainName)) {
|
|
return { isValid: false, error: `Invalid domain name: ${domainOptions.domainName}` };
|
|
}
|
|
|
|
// Validate forward config if provided
|
|
if (domainOptions.forward) {
|
|
if (!domainOptions.forward.ip) {
|
|
return { isValid: false, error: 'Forward IP is required when forward is specified' };
|
|
}
|
|
|
|
if (!domainOptions.forward.port) {
|
|
return { isValid: false, error: 'Forward port is required when forward is specified' };
|
|
}
|
|
|
|
if (!this.isValidPort(domainOptions.forward.port)) {
|
|
return { isValid: false, error: `Invalid forward port: ${domainOptions.forward.port}` };
|
|
}
|
|
}
|
|
|
|
// Validate ACME forward config if provided
|
|
if (domainOptions.acmeForward) {
|
|
if (!domainOptions.acmeForward.ip) {
|
|
return { isValid: false, error: 'ACME forward IP is required when acmeForward is specified' };
|
|
}
|
|
|
|
if (!domainOptions.acmeForward.port) {
|
|
return { isValid: false, error: 'ACME forward port is required when acmeForward is specified' };
|
|
}
|
|
|
|
if (!this.isValidPort(domainOptions.acmeForward.port)) {
|
|
return { isValid: false, error: `Invalid ACME forward port: ${domainOptions.acmeForward.port}` };
|
|
}
|
|
}
|
|
|
|
return { isValid: true };
|
|
}
|
|
|
|
/**
|
|
* Validates ACME configuration options
|
|
*
|
|
* @param acmeOptions The ACME options to validate
|
|
* @returns An object with validation result and error message if invalid
|
|
*/
|
|
public static validateAcmeOptions(acmeOptions: IAcmeOptions): { isValid: boolean; error?: string } {
|
|
if (!acmeOptions) {
|
|
return { isValid: false, error: 'ACME options cannot be null or undefined' };
|
|
}
|
|
|
|
if (acmeOptions.enabled) {
|
|
if (!acmeOptions.accountEmail) {
|
|
return { isValid: false, error: 'Account email is required when ACME is enabled' };
|
|
}
|
|
|
|
if (!this.isValidEmail(acmeOptions.accountEmail)) {
|
|
return { isValid: false, error: `Invalid email: ${acmeOptions.accountEmail}` };
|
|
}
|
|
|
|
if (acmeOptions.port && !this.isValidPort(acmeOptions.port)) {
|
|
return { isValid: false, error: `Invalid ACME port: ${acmeOptions.port}` };
|
|
}
|
|
|
|
if (acmeOptions.httpsRedirectPort && !this.isValidPort(acmeOptions.httpsRedirectPort)) {
|
|
return { isValid: false, error: `Invalid HTTPS redirect port: ${acmeOptions.httpsRedirectPort}` };
|
|
}
|
|
|
|
if (acmeOptions.renewThresholdDays && acmeOptions.renewThresholdDays < 1) {
|
|
return { isValid: false, error: 'Renew threshold days must be greater than 0' };
|
|
}
|
|
|
|
if (acmeOptions.renewCheckIntervalHours && acmeOptions.renewCheckIntervalHours < 1) {
|
|
return { isValid: false, error: 'Renew check interval hours must be greater than 0' };
|
|
}
|
|
}
|
|
|
|
return { isValid: true };
|
|
}
|
|
|
|
/**
|
|
* Validates a port number
|
|
*
|
|
* @param port The port to validate
|
|
* @returns true if the port is valid, false otherwise
|
|
*/
|
|
public static isValidPort(port: number): boolean {
|
|
return typeof port === 'number' && port > 0 && port <= 65535 && Number.isInteger(port);
|
|
}
|
|
|
|
/**
|
|
* Validates a domain name
|
|
*
|
|
* @param domain The domain name to validate
|
|
* @returns true if the domain name is valid, false otherwise
|
|
*/
|
|
public static isValidDomainName(domain: string): boolean {
|
|
if (!domain || typeof domain !== 'string') {
|
|
return false;
|
|
}
|
|
|
|
// Wildcard domain check (*.example.com)
|
|
if (domain.startsWith('*.')) {
|
|
domain = domain.substring(2);
|
|
}
|
|
|
|
// Simple domain validation pattern
|
|
const domainPattern = /^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/;
|
|
return domainPattern.test(domain);
|
|
}
|
|
|
|
/**
|
|
* Validates an email address
|
|
*
|
|
* @param email The email to validate
|
|
* @returns true if the email is valid, false otherwise
|
|
*/
|
|
public static isValidEmail(email: string): boolean {
|
|
if (!email || typeof email !== 'string') {
|
|
return false;
|
|
}
|
|
|
|
// Basic email validation pattern
|
|
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
return emailPattern.test(email);
|
|
}
|
|
|
|
/**
|
|
* Validates a certificate format (PEM)
|
|
*
|
|
* @param cert The certificate content to validate
|
|
* @returns true if the certificate appears to be in PEM format, false otherwise
|
|
*/
|
|
public static isValidCertificate(cert: string): boolean {
|
|
if (!cert || typeof cert !== 'string') {
|
|
return false;
|
|
}
|
|
|
|
return cert.includes('-----BEGIN CERTIFICATE-----') &&
|
|
cert.includes('-----END CERTIFICATE-----');
|
|
}
|
|
|
|
/**
|
|
* Validates a private key format (PEM)
|
|
*
|
|
* @param key The private key content to validate
|
|
* @returns true if the key appears to be in PEM format, false otherwise
|
|
*/
|
|
public static isValidPrivateKey(key: string): boolean {
|
|
if (!key || typeof key !== 'string') {
|
|
return false;
|
|
}
|
|
|
|
return key.includes('-----BEGIN PRIVATE KEY-----') &&
|
|
key.includes('-----END PRIVATE KEY-----');
|
|
}
|
|
} |