update
This commit is contained in:
@@ -93,10 +93,12 @@ export class SMTPServer {
|
|||||||
const cert = Buffer.from(optionsArg.cert, 'utf8');
|
const cert = Buffer.from(optionsArg.cert, 'utf8');
|
||||||
const ca = optionsArg.ca ? Buffer.from(optionsArg.ca, 'utf8') : undefined;
|
const ca = optionsArg.ca ? Buffer.from(optionsArg.ca, 'utf8') : undefined;
|
||||||
|
|
||||||
logger.log('debug', 'Creating TLS server with certificates', {
|
logger.log('warn', 'SMTP SERVER: Creating TLS server with certificates', {
|
||||||
keyBufferLength: key.length,
|
keyBufferLength: key.length,
|
||||||
certBufferLength: cert.length,
|
certBufferLength: cert.length,
|
||||||
caBufferLength: ca ? ca.length : 0
|
caBufferLength: ca ? ca.length : 0,
|
||||||
|
keyPreview: key.toString('utf8').substring(0, 50),
|
||||||
|
certPreview: cert.toString('utf8').substring(0, 50)
|
||||||
});
|
});
|
||||||
|
|
||||||
// TLS configuration for secure connections with broader compatibility
|
// TLS configuration for secure connections with broader compatibility
|
||||||
|
@@ -53,7 +53,32 @@ function normalizeCertificate(str: string | Buffer): string {
|
|||||||
// Normalize line endings (replace Windows-style \r\n with Unix-style \n)
|
// Normalize line endings (replace Windows-style \r\n with Unix-style \n)
|
||||||
normalizedStr = normalizedStr.replace(/\r\n/g, '\n');
|
normalizedStr = normalizedStr.replace(/\r\n/g, '\n');
|
||||||
|
|
||||||
// Ensure proper line breaks after header and before footer
|
// Only normalize if the certificate appears to have formatting issues
|
||||||
|
// Check if the certificate is already properly formatted
|
||||||
|
const lines = normalizedStr.split('\n');
|
||||||
|
let needsReformatting = false;
|
||||||
|
|
||||||
|
// Check for common formatting issues:
|
||||||
|
// 1. Missing line breaks after header/before footer
|
||||||
|
// 2. Lines that are too long or too short (except header/footer)
|
||||||
|
// 3. Multiple consecutive blank lines
|
||||||
|
for (let i = 0; i < lines.length; i++) {
|
||||||
|
const line = lines[i].trim();
|
||||||
|
if (line.startsWith('-----BEGIN ') || line.startsWith('-----END ')) {
|
||||||
|
continue; // Skip header/footer lines
|
||||||
|
}
|
||||||
|
if (line.length === 0) {
|
||||||
|
continue; // Skip empty lines
|
||||||
|
}
|
||||||
|
// Check if content lines are reasonable length (base64 is typically 64 chars per line)
|
||||||
|
if (line.length > 76) { // Allow some flexibility beyond standard 64
|
||||||
|
needsReformatting = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only reformat if necessary
|
||||||
|
if (needsReformatting) {
|
||||||
const beginMatch = normalizedStr.match(/^(-----BEGIN [^-]+-----)(.*)$/s);
|
const beginMatch = normalizedStr.match(/^(-----BEGIN [^-]+-----)(.*)$/s);
|
||||||
const endMatch = normalizedStr.match(/(.*)(-----END [^-]+-----)$/s);
|
const endMatch = normalizedStr.match(/(.*)(-----END [^-]+-----)$/s);
|
||||||
|
|
||||||
@@ -62,8 +87,8 @@ function normalizeCertificate(str: string | Buffer): string {
|
|||||||
const footer = endMatch[2];
|
const footer = endMatch[2];
|
||||||
let content = normalizedStr.substring(header.length, normalizedStr.length - footer.length);
|
let content = normalizedStr.substring(header.length, normalizedStr.length - footer.length);
|
||||||
|
|
||||||
// Clean up any existing line breaks or spaces in the content
|
// Clean up only line breaks and carriage returns, preserve base64 content
|
||||||
content = content.replace(/[\n\r\s]/g, '');
|
content = content.replace(/[\n\r]/g, '').trim();
|
||||||
|
|
||||||
// Add proper line breaks (every 64 characters)
|
// Add proper line breaks (every 64 characters)
|
||||||
let formattedContent = '';
|
let formattedContent = '';
|
||||||
@@ -74,6 +99,7 @@ function normalizeCertificate(str: string | Buffer): string {
|
|||||||
// Reconstruct the certificate
|
// Reconstruct the certificate
|
||||||
return header + '\n' + formattedContent + footer;
|
return header + '\n' + formattedContent + footer;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return normalizedStr;
|
return normalizedStr;
|
||||||
}
|
}
|
||||||
@@ -89,7 +115,77 @@ export function loadCertificatesFromString(options: {
|
|||||||
ca?: string | Buffer;
|
ca?: string | Buffer;
|
||||||
}): ICertificateData {
|
}): ICertificateData {
|
||||||
try {
|
try {
|
||||||
// Try to fix and normalize certificates
|
// First try to use certificates without normalization
|
||||||
|
try {
|
||||||
|
let keyStr: string;
|
||||||
|
let certStr: string;
|
||||||
|
let caStr: string | undefined;
|
||||||
|
|
||||||
|
// Convert inputs to strings without aggressive normalization
|
||||||
|
if (Buffer.isBuffer(options.key)) {
|
||||||
|
keyStr = options.key.toString('utf8');
|
||||||
|
} else {
|
||||||
|
keyStr = options.key;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Buffer.isBuffer(options.cert)) {
|
||||||
|
certStr = options.cert.toString('utf8');
|
||||||
|
} else {
|
||||||
|
certStr = options.cert;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.ca) {
|
||||||
|
if (Buffer.isBuffer(options.ca)) {
|
||||||
|
caStr = options.ca.toString('utf8');
|
||||||
|
} else {
|
||||||
|
caStr = options.ca;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple cleanup - only normalize line endings
|
||||||
|
keyStr = keyStr.trim().replace(/\r\n/g, '\n');
|
||||||
|
certStr = certStr.trim().replace(/\r\n/g, '\n');
|
||||||
|
if (caStr) {
|
||||||
|
caStr = caStr.trim().replace(/\r\n/g, '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to buffers
|
||||||
|
const keyBuffer = Buffer.from(keyStr, 'utf8');
|
||||||
|
const certBuffer = Buffer.from(certStr, 'utf8');
|
||||||
|
const caBuffer = caStr ? Buffer.from(caStr, 'utf8') : undefined;
|
||||||
|
|
||||||
|
// Test the certificates first
|
||||||
|
const secureContext = tls.createSecureContext({
|
||||||
|
key: keyBuffer,
|
||||||
|
cert: certBuffer,
|
||||||
|
ca: caBuffer
|
||||||
|
});
|
||||||
|
|
||||||
|
SmtpLogger.info('Successfully validated certificates without normalization');
|
||||||
|
|
||||||
|
return {
|
||||||
|
key: keyBuffer,
|
||||||
|
cert: certBuffer,
|
||||||
|
ca: caBuffer
|
||||||
|
};
|
||||||
|
|
||||||
|
} catch (simpleError) {
|
||||||
|
SmtpLogger.warn(`Simple certificate loading failed, trying normalization: ${simpleError instanceof Error ? simpleError.message : String(simpleError)}`);
|
||||||
|
|
||||||
|
// DEBUG: Log certificate details when simple loading fails
|
||||||
|
SmtpLogger.warn('Certificate loading failure details', {
|
||||||
|
keyType: typeof options.key,
|
||||||
|
certType: typeof options.cert,
|
||||||
|
keyIsBuffer: Buffer.isBuffer(options.key),
|
||||||
|
certIsBuffer: Buffer.isBuffer(options.cert),
|
||||||
|
keyLength: options.key ? options.key.length : 0,
|
||||||
|
certLength: options.cert ? options.cert.length : 0,
|
||||||
|
keyPreview: options.key ? (typeof options.key === 'string' ? options.key.substring(0, 50) : options.key.toString('utf8').substring(0, 50)) : 'null',
|
||||||
|
certPreview: options.cert ? (typeof options.cert === 'string' ? options.cert.substring(0, 50) : options.cert.toString('utf8').substring(0, 50)) : 'null'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: Try to fix and normalize certificates
|
||||||
try {
|
try {
|
||||||
// Normalize certificates (handles both string and Buffer inputs)
|
// Normalize certificates (handles both string and Buffer inputs)
|
||||||
const key = normalizeCertificate(options.key);
|
const key = normalizeCertificate(options.key);
|
||||||
@@ -119,7 +215,14 @@ export function loadCertificatesFromString(options: {
|
|||||||
// If createSecureContext doesn't throw, the certificates are valid
|
// If createSecureContext doesn't throw, the certificates are valid
|
||||||
SmtpLogger.info('Successfully validated certificate format');
|
SmtpLogger.info('Successfully validated certificate format');
|
||||||
} catch (validationError) {
|
} catch (validationError) {
|
||||||
|
// Log detailed error information for debugging
|
||||||
SmtpLogger.error(`Certificate validation error: ${validationError instanceof Error ? validationError.message : String(validationError)}`);
|
SmtpLogger.error(`Certificate validation error: ${validationError instanceof Error ? validationError.message : String(validationError)}`);
|
||||||
|
SmtpLogger.debug('Certificate validation details', {
|
||||||
|
keyPreview: keyBuffer.toString('utf8').substring(0, 100) + '...',
|
||||||
|
certPreview: certBuffer.toString('utf8').substring(0, 100) + '...',
|
||||||
|
keyLength: keyBuffer.length,
|
||||||
|
certLength: certBuffer.length
|
||||||
|
});
|
||||||
throw validationError;
|
throw validationError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user