139 lines
3.6 KiB
TypeScript
139 lines
3.6 KiB
TypeScript
import type { IEmailDomainConfig } from './interfaces.js';
|
|
import { logger } from '../../logger.js';
|
|
|
|
/**
|
|
* Registry for email domain configurations
|
|
* Provides fast lookups and validation for domains
|
|
*/
|
|
export class DomainRegistry {
|
|
private domains: Map<string, IEmailDomainConfig> = new Map();
|
|
private defaults: IEmailDomainConfig['dkim'] & {
|
|
dnsMode?: 'forward' | 'internal-dns' | 'external-dns';
|
|
rateLimits?: IEmailDomainConfig['rateLimits'];
|
|
};
|
|
|
|
constructor(
|
|
domainConfigs: IEmailDomainConfig[],
|
|
defaults?: {
|
|
dnsMode?: 'forward' | 'internal-dns' | 'external-dns';
|
|
dkim?: IEmailDomainConfig['dkim'];
|
|
rateLimits?: IEmailDomainConfig['rateLimits'];
|
|
}
|
|
) {
|
|
// Set defaults
|
|
this.defaults = {
|
|
dnsMode: defaults?.dnsMode || 'external-dns',
|
|
...this.getDefaultDkimConfig(),
|
|
...defaults?.dkim,
|
|
rateLimits: defaults?.rateLimits
|
|
};
|
|
|
|
// Process and store domain configurations
|
|
for (const config of domainConfigs) {
|
|
const processedConfig = this.applyDefaults(config);
|
|
this.domains.set(config.domain.toLowerCase(), processedConfig);
|
|
logger.log('info', `Registered domain: ${config.domain} with DNS mode: ${processedConfig.dnsMode}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get default DKIM configuration
|
|
*/
|
|
private getDefaultDkimConfig(): IEmailDomainConfig['dkim'] {
|
|
return {
|
|
selector: 'default',
|
|
keySize: 2048,
|
|
rotateKeys: false,
|
|
rotationInterval: 90
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Apply defaults to a domain configuration
|
|
*/
|
|
private applyDefaults(config: IEmailDomainConfig): IEmailDomainConfig {
|
|
return {
|
|
...config,
|
|
dnsMode: config.dnsMode || this.defaults.dnsMode!,
|
|
dkim: {
|
|
...this.getDefaultDkimConfig(),
|
|
...this.defaults,
|
|
...config.dkim
|
|
},
|
|
rateLimits: {
|
|
...this.defaults.rateLimits,
|
|
...config.rateLimits,
|
|
outbound: {
|
|
...this.defaults.rateLimits?.outbound,
|
|
...config.rateLimits?.outbound
|
|
},
|
|
inbound: {
|
|
...this.defaults.rateLimits?.inbound,
|
|
...config.rateLimits?.inbound
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Check if a domain is registered
|
|
*/
|
|
isDomainRegistered(domain: string): boolean {
|
|
return this.domains.has(domain.toLowerCase());
|
|
}
|
|
|
|
/**
|
|
* Check if an email address belongs to a registered domain
|
|
*/
|
|
isEmailRegistered(email: string): boolean {
|
|
const domain = this.extractDomain(email);
|
|
if (!domain) return false;
|
|
return this.isDomainRegistered(domain);
|
|
}
|
|
|
|
/**
|
|
* Get domain configuration
|
|
*/
|
|
getDomainConfig(domain: string): IEmailDomainConfig | undefined {
|
|
return this.domains.get(domain.toLowerCase());
|
|
}
|
|
|
|
/**
|
|
* Get domain configuration for an email address
|
|
*/
|
|
getEmailDomainConfig(email: string): IEmailDomainConfig | undefined {
|
|
const domain = this.extractDomain(email);
|
|
if (!domain) return undefined;
|
|
return this.getDomainConfig(domain);
|
|
}
|
|
|
|
/**
|
|
* Extract domain from email address
|
|
*/
|
|
private extractDomain(email: string): string | null {
|
|
const parts = email.toLowerCase().split('@');
|
|
if (parts.length !== 2) return null;
|
|
return parts[1];
|
|
}
|
|
|
|
/**
|
|
* Get all registered domains
|
|
*/
|
|
getAllDomains(): string[] {
|
|
return Array.from(this.domains.keys());
|
|
}
|
|
|
|
/**
|
|
* Get all domain configurations
|
|
*/
|
|
getAllConfigs(): IEmailDomainConfig[] {
|
|
return Array.from(this.domains.values());
|
|
}
|
|
|
|
/**
|
|
* Get domains by DNS mode
|
|
*/
|
|
getDomainsByMode(mode: 'forward' | 'internal-dns' | 'external-dns'): IEmailDomainConfig[] {
|
|
return Array.from(this.domains.values()).filter(config => config.dnsMode === mode);
|
|
}
|
|
} |