new data model refinement
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Graph visualization module for DNSRecon
|
||||
* Handles network graph rendering using vis.js with proper large entity node hiding
|
||||
* UPDATED: Now compatible with unified data model (StandardAttribute objects)
|
||||
* UPDATED: Now compatible with a strictly flat, unified data model for attributes.
|
||||
*/
|
||||
const contextMenuCSS = `
|
||||
.graph-context-menu {
|
||||
@@ -484,7 +484,7 @@ class GraphManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* UPDATED: Process node data with styling and metadata for unified data model
|
||||
* UPDATED: Process node data with styling and metadata for the flat data model
|
||||
* @param {Object} node - Raw node data with standardized attributes
|
||||
* @returns {Object} Processed node data
|
||||
*/
|
||||
@@ -508,14 +508,6 @@ class GraphManager {
|
||||
if (node.confidence) {
|
||||
processedNode.borderWidth = Math.max(2, Math.floor(node.confidence * 5));
|
||||
}
|
||||
|
||||
// UPDATED: Style based on certificate validity using unified data model
|
||||
if (node.type === 'domain') {
|
||||
const certificatesAttr = this.findAttributeByName(node.attributes, 'certificates');
|
||||
if (certificatesAttr && certificatesAttr.value && certificatesAttr.value.has_valid_cert === false) {
|
||||
processedNode.color = { background: '#888888', border: '#666666' };
|
||||
}
|
||||
}
|
||||
|
||||
// Handle merged correlation objects (similar to large entities)
|
||||
if (node.type === 'correlation_object') {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Main application logic for DNSRecon web interface
|
||||
* Handles UI interactions, API communication, and data flow
|
||||
* UPDATED: Now compatible with unified data model (StandardAttribute objects)
|
||||
* UPDATED: Now compatible with a strictly flat, unified data model for attributes.
|
||||
*/
|
||||
|
||||
class DNSReconApp {
|
||||
@@ -879,21 +879,9 @@ class DNSReconApp {
|
||||
// Relationships sections
|
||||
html += this.generateRelationshipsSection(node);
|
||||
|
||||
// UPDATED: Enhanced attributes section with special certificate handling for unified model
|
||||
// UPDATED: Simplified attributes section for the flat model
|
||||
if (node.attributes && Array.isArray(node.attributes) && node.attributes.length > 0) {
|
||||
// Find certificate attribute separately
|
||||
const certificatesAttr = this.findAttributeByName(node.attributes, 'certificates');
|
||||
|
||||
// Handle certificates separately with enhanced display
|
||||
if (certificatesAttr) {
|
||||
html += this.generateCertificateSection(certificatesAttr);
|
||||
}
|
||||
|
||||
// Handle other attributes normally (excluding certificates to avoid duplication)
|
||||
const otherAttributes = node.attributes.filter(attr => attr.name !== 'certificates');
|
||||
if (otherAttributes.length > 0) {
|
||||
html += this.generateAttributesSection(otherAttributes);
|
||||
}
|
||||
html += this.generateAttributesSection(node.attributes);
|
||||
}
|
||||
|
||||
// Description section
|
||||
@@ -905,213 +893,6 @@ class DNSReconApp {
|
||||
return html;
|
||||
}
|
||||
|
||||
/**
|
||||
* UPDATED: Enhanced certificate section generation for unified data model
|
||||
*/
|
||||
generateCertificateSection(certificatesAttr) {
|
||||
const certificates = certificatesAttr.value;
|
||||
if (!certificates || typeof certificates !== 'object') {
|
||||
return '';
|
||||
}
|
||||
|
||||
let html = `
|
||||
<div class="modal-section">
|
||||
<details>
|
||||
<summary>🔒 SSL/TLS Certificates</summary>
|
||||
<div class="modal-section-content">
|
||||
`;
|
||||
|
||||
// Certificate summary using existing grid pattern
|
||||
html += this.generateCertificateSummary(certificates);
|
||||
|
||||
// Latest certificate info using existing attribute display
|
||||
if (certificates.latest_certificate) {
|
||||
html += this.generateLatestCertificateInfo(certificates.latest_certificate);
|
||||
}
|
||||
|
||||
// Detailed certificate list if available
|
||||
if (certificates.certificate_details && Array.isArray(certificates.certificate_details)) {
|
||||
html += this.generateCertificateList(certificates.certificate_details);
|
||||
}
|
||||
|
||||
html += '</div></details></div>';
|
||||
return html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate latest certificate info using existing attribute list
|
||||
*/
|
||||
generateLatestCertificateInfo(latest) {
|
||||
const isValid = latest.is_currently_valid;
|
||||
const statusText = isValid ? 'Valid' : 'Invalid/Expired';
|
||||
const statusColor = isValid ? '#00ff41' : '#ff6b6b';
|
||||
|
||||
let html = `
|
||||
<div style="margin-bottom: 1rem; padding: 0.75rem; background: rgba(255, 255, 255, 0.02); border-radius: 4px; border: 1px solid #333;">
|
||||
<h5 style="margin: 0 0 0.5rem 0; color: #00ff41; font-size: 0.9rem;">Most Recent Certificate</h5>
|
||||
<div class="attribute-list">
|
||||
<div class="attribute-item-compact">
|
||||
<span class="attribute-key-compact">Status:</span>
|
||||
<span class="attribute-value-compact" style="color: ${statusColor}; font-weight: 600;">${statusText}</span>
|
||||
</div>
|
||||
<div class="attribute-item-compact">
|
||||
<span class="attribute-key-compact">Issued:</span>
|
||||
<span class="attribute-value-compact">${latest.not_before || 'Unknown'}</span>
|
||||
</div>
|
||||
<div class="attribute-item-compact">
|
||||
<span class="attribute-key-compact">Expires:</span>
|
||||
<span class="attribute-value-compact">${latest.not_after || 'Unknown'}</span>
|
||||
</div>
|
||||
<div class="attribute-item-compact">
|
||||
<span class="attribute-key-compact">Issuer:</span>
|
||||
<span class="attribute-value-compact">${this.escapeHtml(latest.issuer_name || 'Unknown')}</span>
|
||||
</div>
|
||||
${latest.certificate_id ? `
|
||||
<div class="attribute-item-compact">
|
||||
<span class="attribute-key-compact">Certificate:</span>
|
||||
<span class="attribute-value-compact">
|
||||
<a href="https://crt.sh/?id=${latest.certificate_id}" target="_blank" class="cert-link">
|
||||
View on crt.sh ↗
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
` : ''}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate certificate list using existing collapsible structure
|
||||
*/
|
||||
generateCertificateList(certificateDetails) {
|
||||
if (!certificateDetails || certificateDetails.length === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Limit display to prevent overwhelming the UI
|
||||
const maxDisplay = 8;
|
||||
const certificates = certificateDetails.slice(0, maxDisplay);
|
||||
const remaining = certificateDetails.length - maxDisplay;
|
||||
|
||||
let html = `
|
||||
<details style="margin-top: 1rem;">
|
||||
<summary>📋 Certificate Details (${certificates.length}${remaining > 0 ? ` of ${certificateDetails.length}` : ''})</summary>
|
||||
<div style="margin-top: 0.75rem;">
|
||||
`;
|
||||
|
||||
certificates.forEach((cert, index) => {
|
||||
const isValid = cert.is_currently_valid;
|
||||
let statusText = isValid ? '✅ Valid' : '❌ Invalid/Expired';
|
||||
let statusColor = isValid ? '#00ff41' : '#ff6b6b';
|
||||
|
||||
if (cert.expires_soon && isValid) {
|
||||
statusText = '⚠️ Valid (Expiring Soon)';
|
||||
statusColor = '#ff9900';
|
||||
}
|
||||
|
||||
html += `
|
||||
<div style="margin-bottom: 0.75rem; padding: 0.75rem; background: rgba(255, 255, 255, 0.02); border: 1px solid #333; border-radius: 4px;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5rem; border-bottom: 1px solid #333; padding-bottom: 0.5rem;">
|
||||
<span style="font-weight: 600; color: #999;">#${index + 1}</span>
|
||||
<span style="color: ${statusColor}; font-size: 0.85rem; font-weight: 500;">${statusText}</span>
|
||||
${cert.certificate_id ? `
|
||||
<a href="https://crt.sh/?id=${cert.certificate_id}" target="_blank" class="cert-link">crt.sh ↗</a>
|
||||
` : ''}
|
||||
</div>
|
||||
<div class="attribute-list">
|
||||
<div class="attribute-item-compact">
|
||||
<span class="attribute-key-compact">Common Name:</span>
|
||||
<span class="attribute-value-compact">${this.escapeHtml(cert.common_name || 'N/A')}</span>
|
||||
</div>
|
||||
<div class="attribute-item-compact">
|
||||
<span class="attribute-key-compact">Issuer:</span>
|
||||
<span class="attribute-value-compact">${this.escapeHtml(cert.issuer_name || 'Unknown')}</span>
|
||||
</div>
|
||||
<div class="attribute-item-compact">
|
||||
<span class="attribute-key-compact">Valid From:</span>
|
||||
<span class="attribute-value-compact">${cert.not_before || 'Unknown'}</span>
|
||||
</div>
|
||||
<div class="attribute-item-compact">
|
||||
<span class="attribute-key-compact">Valid Until:</span>
|
||||
<span class="attribute-value-compact">${cert.not_after || 'Unknown'}</span>
|
||||
</div>
|
||||
${cert.validity_period_days ? `
|
||||
<div class="attribute-item-compact">
|
||||
<span class="attribute-key-compact">Period:</span>
|
||||
<span class="attribute-value-compact">${cert.validity_period_days} days</span>
|
||||
</div>
|
||||
` : ''}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
|
||||
if (remaining > 0) {
|
||||
html += `
|
||||
<div style="text-align: center; padding: 1rem; color: #ff9900; background: rgba(255, 153, 0, 0.1); border: 1px solid #ff9900; border-radius: 4px;">
|
||||
📋 ${remaining} additional certificate${remaining > 1 ? 's' : ''} not shown.<br>
|
||||
<small style="color: #999;">Use the export function to see all certificates.</small>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
html += '</div></details>';
|
||||
return html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate certificate summary using minimal new CSS
|
||||
*/
|
||||
generateCertificateSummary(certificates) {
|
||||
const total = certificates.total_certificates || 0;
|
||||
const valid = certificates.valid_certificates || 0;
|
||||
const expired = certificates.expired_certificates || 0;
|
||||
const expiringSoon = certificates.expires_soon_count || 0;
|
||||
const issuers = certificates.unique_issuers || [];
|
||||
|
||||
let html = `
|
||||
<div class="cert-summary-grid">
|
||||
<div class="cert-stat-item">
|
||||
<div class="cert-stat-value">${total}</div>
|
||||
<div class="cert-stat-label">Total</div>
|
||||
</div>
|
||||
<div class="cert-stat-item">
|
||||
<div class="cert-stat-value" style="color: #00ff41">${valid}</div>
|
||||
<div class="cert-stat-label">Valid</div>
|
||||
</div>
|
||||
<div class="cert-stat-item">
|
||||
<div class="cert-stat-value" style="color: #ff6b6b">${expired}</div>
|
||||
<div class="cert-stat-label">Expired</div>
|
||||
</div>
|
||||
<div class="cert-stat-item">
|
||||
<div class="cert-stat-value" style="color: #ff9900">${expiringSoon}</div>
|
||||
<div class="cert-stat-label">Expiring Soon</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Certificate authorities using existing array display
|
||||
if (issuers.length > 0) {
|
||||
html += `
|
||||
<div class="attribute-item-compact" style="margin-bottom: 1rem;">
|
||||
<span class="attribute-key-compact">Certificate Authorities:</span>
|
||||
<span class="attribute-value-compact">
|
||||
<div class="array-display">
|
||||
`;
|
||||
|
||||
issuers.forEach(issuer => {
|
||||
html += `<div class="array-display-item">${this.escapeHtml(issuer)}</div>`;
|
||||
});
|
||||
|
||||
html += '</div></span></div>';
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
/**
|
||||
* UPDATED: Generate large entity details using unified data model
|
||||
*/
|
||||
@@ -1356,71 +1137,32 @@ class DNSReconApp {
|
||||
}
|
||||
|
||||
/**
|
||||
* UPDATED: Generate attributes section for unified data model
|
||||
* Now processes StandardAttribute objects instead of key-value pairs
|
||||
* UPDATED: Generate attributes section for the new flat data model
|
||||
*/
|
||||
generateAttributesSection(attributes) {
|
||||
if (!Array.isArray(attributes) || attributes.length === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const categorized = this.categorizeStandardAttributes(attributes);
|
||||
let html = '';
|
||||
|
||||
Object.entries(categorized).forEach(([category, attrs]) => {
|
||||
if (attrs.length === 0) return;
|
||||
|
||||
html += `
|
||||
<div class="modal-section">
|
||||
<details>
|
||||
<summary>📊 ${category}</summary>
|
||||
<div class="modal-section-content">
|
||||
`;
|
||||
|
||||
html += '<div class="attribute-list">';
|
||||
attrs.forEach(attr => {
|
||||
html += `
|
||||
<div class="attribute-item-compact">
|
||||
<span class="attribute-key-compact">${this.formatLabel(attr.name)}</span>
|
||||
<span class="attribute-value-compact">${this.formatStandardAttributeValue(attr)}</span>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
html += '</div>';
|
||||
|
||||
html += '</div></details></div>';
|
||||
});
|
||||
|
||||
return html;
|
||||
}
|
||||
let html = `
|
||||
<div class="modal-section">
|
||||
<details open>
|
||||
<summary>📊 Attributes (${attributes.length})</summary>
|
||||
<div class="modal-section-content">
|
||||
<div class="attribute-list">
|
||||
`;
|
||||
|
||||
/**
|
||||
* UPDATED: Categorize StandardAttribute objects by type and content
|
||||
*/
|
||||
categorizeStandardAttributes(attributes) {
|
||||
const categories = {
|
||||
'DNS Records': [],
|
||||
'Network Info': [],
|
||||
'Provider Data': [],
|
||||
'Other': []
|
||||
};
|
||||
|
||||
attributes.forEach(attr => {
|
||||
const lowerName = attr.name.toLowerCase();
|
||||
const attrType = attr.type ? attr.type.toLowerCase() : '';
|
||||
|
||||
if (lowerName.includes('dns') || lowerName.includes('record') || attrType.includes('dns')) {
|
||||
categories['DNS Records'].push(attr);
|
||||
} else if (lowerName.includes('ip') || lowerName.includes('asn') || lowerName.includes('network') || attrType.includes('network')) {
|
||||
categories['Network Info'].push(attr);
|
||||
} else if (lowerName.includes('shodan') || lowerName.includes('crtsh') || lowerName.includes('provider') || attrType.includes('provider')) {
|
||||
categories['Provider Data'].push(attr);
|
||||
} else {
|
||||
categories['Other'].push(attr);
|
||||
}
|
||||
html += `
|
||||
<div class="attribute-item-compact">
|
||||
<span class="attribute-key-compact">${this.formatLabel(attr.name)}</span>
|
||||
<span class="attribute-value-compact">${this.formatStandardAttributeValue(attr)}</span>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
|
||||
return categories;
|
||||
|
||||
html += '</div></div></details></div>';
|
||||
return html;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user