Files
url_tracker_tool/apps/api/dist/services/ssl-analyzer.service.js
Andrei 58f8093689 Rebrand from 'Redirect Intelligence v2' to 'URL Tracker Tool V2' throughout UI
- Updated all component headers and documentation
- Changed navbar and footer branding
- Updated homepage hero badge
- Modified page title in index.html
- Simplified footer text to 'Built with ❤️'
- Consistent V2 capitalization across all references
2025-08-19 19:12:23 +00:00

219 lines
8.9 KiB
JavaScript

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SSLAnalyzerService = void 0;
const tls_1 = __importDefault(require("tls"));
const url_1 = require("url");
const logger_1 = require("../lib/logger");
class SSLAnalyzerService {
async analyzeSSL(url) {
const parsedUrl = new url_1.URL(url);
const host = parsedUrl.hostname;
const port = parsedUrl.port ? parseInt(parsedUrl.port) : 443;
logger_1.logger.info(`Starting SSL analysis for: ${host}:${port}`);
const result = {
host,
port,
warnings: [],
errors: [],
securityScore: 0,
recommendations: [],
};
if (parsedUrl.protocol !== 'https:') {
result.errors.push('URL is not HTTPS');
result.recommendations.push('Use HTTPS to secure communications');
return result;
}
try {
const certificate = await this.getCertificateInfo(host, port);
result.certificate = certificate;
this.analyzeCertificateSecurity(result);
logger_1.logger.info(`SSL analysis completed for: ${host}:${port}`, {
valid: certificate.valid,
daysToExpiry: certificate.daysToExpiry,
securityScore: result.securityScore
});
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown SSL error';
result.errors.push(`SSL analysis failed: ${errorMessage}`);
logger_1.logger.error(`SSL analysis failed for ${host}:${port}:`, error);
}
return result;
}
async getCertificateInfo(host, port) {
return new Promise((resolve, reject) => {
const options = {
host,
port,
servername: host,
rejectUnauthorized: false,
timeout: 10000,
};
const socket = tls_1.default.connect(options, () => {
try {
const cert = socket.getPeerCertificate(true);
const cipher = socket.getCipher();
const protocol = socket.getProtocol();
if (!cert || Object.keys(cert).length === 0) {
socket.end();
reject(new Error('No certificate found'));
return;
}
const now = new Date();
const validFrom = new Date(cert.valid_from);
const validTo = new Date(cert.valid_to);
const daysToExpiry = Math.floor((validTo.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
const certificateInfo = {
valid: socket.authorized,
subject: this.parseCertificateField(cert.subject),
issuer: this.parseCertificateField(cert.issuer),
validFrom: validFrom.toISOString(),
validTo: validTo.toISOString(),
daysToExpiry,
serialNumber: cert.serialNumber,
fingerprint: cert.fingerprint,
signatureAlgorithm: cert.signatureAlgorithm,
keySize: cert.bits,
protocol,
cipher: cipher ? {
name: cipher.name,
version: cipher.version,
} : undefined,
};
socket.end();
resolve(certificateInfo);
}
catch (error) {
socket.end();
reject(error);
}
});
socket.on('error', (error) => {
reject(error);
});
socket.on('timeout', () => {
socket.destroy();
reject(new Error('SSL connection timeout'));
});
socket.setTimeout(10000);
});
}
parseCertificateField(field) {
if (!field)
return {};
return {
commonName: field.CN,
organization: field.O,
organizationalUnit: field.OU,
locality: field.L,
state: field.ST,
country: field.C,
};
}
analyzeCertificateSecurity(result) {
const cert = result.certificate;
if (!cert)
return;
let score = 100;
if (!cert.valid) {
result.warnings.push('Certificate is not valid or trusted');
result.recommendations.push('Install a valid SSL certificate from a trusted CA');
score -= 30;
}
if (cert.daysToExpiry < 0) {
result.errors.push('Certificate has expired');
result.recommendations.push('Renew the SSL certificate immediately');
score -= 40;
}
else if (cert.daysToExpiry < 30) {
result.warnings.push(`Certificate expires in ${cert.daysToExpiry} days`);
result.recommendations.push('Renew the SSL certificate soon');
score -= 10;
}
else if (cert.daysToExpiry < 90) {
result.warnings.push(`Certificate expires in ${cert.daysToExpiry} days`);
score -= 5;
}
if (cert.keySize && cert.keySize < 2048) {
result.warnings.push(`Weak key size: ${cert.keySize} bits`);
result.recommendations.push('Use at least 2048-bit RSA keys or 256-bit ECC keys');
score -= 20;
}
if (cert.signatureAlgorithm) {
if (cert.signatureAlgorithm.toLowerCase().includes('sha1')) {
result.warnings.push('Using deprecated SHA-1 signature algorithm');
result.recommendations.push('Upgrade to SHA-256 or better signature algorithm');
score -= 15;
}
else if (cert.signatureAlgorithm.toLowerCase().includes('md5')) {
result.errors.push('Using insecure MD5 signature algorithm');
result.recommendations.push('Immediately upgrade to SHA-256 or better');
score -= 30;
}
}
if (cert.protocol) {
if (cert.protocol.includes('TLSv1.0') || cert.protocol.includes('TLSv1.1')) {
result.warnings.push(`Using deprecated protocol: ${cert.protocol}`);
result.recommendations.push('Upgrade to TLS 1.2 or TLS 1.3');
score -= 15;
}
else if (cert.protocol.includes('SSLv')) {
result.errors.push(`Using insecure protocol: ${cert.protocol}`);
result.recommendations.push('Immediately upgrade to TLS 1.2 or TLS 1.3');
score -= 35;
}
}
if (cert.cipher?.name) {
const cipherName = cert.cipher.name.toLowerCase();
if (cipherName.includes('rc4') || cipherName.includes('des')) {
result.errors.push(`Weak cipher suite: ${cert.cipher.name}`);
result.recommendations.push('Use strong cipher suites like AES-GCM');
score -= 25;
}
else if (cipherName.includes('cbc')) {
result.warnings.push(`CBC cipher mode detected: ${cert.cipher.name}`);
result.recommendations.push('Prefer GCM or ChaCha20-Poly1305 cipher modes');
score -= 5;
}
}
if (!cert.subject.commonName) {
result.warnings.push('Certificate missing Common Name');
score -= 5;
}
result.securityScore = Math.max(0, score);
if (result.securityScore >= 90) {
result.recommendations.push('SSL configuration looks excellent!');
}
else if (result.securityScore >= 70) {
result.recommendations.push('SSL configuration is good with minor improvements possible');
}
else if (result.securityScore >= 50) {
result.recommendations.push('SSL configuration needs improvement for better security');
}
else {
result.recommendations.push('SSL configuration requires immediate attention');
}
}
async quickSSLCheck(url) {
try {
const analysis = await this.analyzeSSL(url);
return {
valid: analysis.certificate?.valid ?? false,
daysToExpiry: analysis.certificate?.daysToExpiry,
warnings: analysis.warnings,
};
}
catch (error) {
logger_1.logger.warn(`Quick SSL check failed for ${url}:`, error);
return {
valid: false,
warnings: ['SSL check failed'],
};
}
}
}
exports.SSLAnalyzerService = SSLAnalyzerService;
//# sourceMappingURL=ssl-analyzer.service.js.map