improving the display

This commit is contained in:
overcuriousity
2025-09-16 22:25:46 +02:00
parent 733e1da640
commit 229746e1ec
2 changed files with 372 additions and 33 deletions

View File

@@ -822,8 +822,8 @@ class DNSReconApp {
}
/**
* UPDATED: Enhanced node details HTML generation for unified data model
* Now processes StandardAttribute objects instead of simple key-value pairs
* Node details HTML generation for unified data model
* processes StandardAttribute objects
*/
generateNodeDetailsHtml(node) {
if (!node) return '<div class="detail-row"><span class="detail-value">Details not available.</span></div>';
@@ -871,7 +871,7 @@ class DNSReconApp {
}
/**
* UPDATED: Generate details for standard nodes using unified data model
* Generate details for standard nodes using unified data model
*/
generateStandardNodeDetails(node) {
let html = '';
@@ -879,9 +879,9 @@ class DNSReconApp {
// Relationships sections
html += this.generateRelationshipsSection(node);
// UPDATED: Simplified attributes section for the flat model
// Attributes section with grouping
if (node.attributes && Array.isArray(node.attributes) && node.attributes.length > 0) {
html += this.generateAttributesSection(node.attributes);
html += this.generateEnhancedAttributesSection(node.attributes, node.type);
}
// Description section
@@ -893,6 +893,242 @@ class DNSReconApp {
return html;
}
generateEnhancedAttributesSection(attributes, nodeType) {
if (!Array.isArray(attributes) || attributes.length === 0) {
return '';
}
// Group attributes by provider and type for better organization
const groupedAttributes = this.groupAttributesIntelligently(attributes, nodeType);
let html = '';
for (const [groupName, groupData] of Object.entries(groupedAttributes)) {
const isDefaultOpen = groupData.priority === 'high';
html += `
<div class="modal-section">
<details ${isDefaultOpen ? 'open' : ''}>
<summary>
<span>${groupData.icon} ${groupName}</span>
<span class="count-badge">${groupData.attributes.length}</span>
</summary>
<div class="modal-section-content">
<div class="attribute-list">
`;
groupData.attributes.forEach(attr => {
html += `
<div class="attribute-item-compact">
<span class="attribute-key-compact">${this.formatAttributeLabel(attr.name)}</span>
<span class="attribute-value-compact">${this.formatAttributeValueEnhanced(attr)}</span>
</div>
`;
});
html += '</div></div></details></div>';
}
return html;
}
formatAttributeValueEnhanced(attr) {
const value = attr.value;
if (value === null || value === undefined) {
return '<em>None</em>';
}
if (Array.isArray(value)) {
if (value.length === 0) return '<em>None</em>';
if (value.length === 1) return this.escapeHtml(String(value[0]));
// Complex array - make it collapsible
const previewItems = value.slice(0, 2);
const hasMore = value.length > 2;
let html = '<div class="expandable-array">';
html += `<div class="array-preview">`;
previewItems.forEach(item => {
html += `<div class="array-item-preview">${this.escapeHtml(String(item))}</div>`;
});
if (hasMore) {
html += `
<button class="expand-array-btn" onclick="this.parentElement.style.display='none'; this.parentElement.nextElementSibling.style.display='block';">
+${value.length - 2} more...
</button>
`;
}
html += '</div>';
if (hasMore) {
html += `<div class="array-full" style="display: none;">`;
value.forEach(item => {
html += `<div class="array-item-full">${this.escapeHtml(String(item))}</div>`;
});
html += `
<button class="collapse-array-btn" onclick="this.parentElement.style.display='none'; this.parentElement.previousElementSibling.style.display='block';">
Show less
</button>
`;
html += '</div>';
}
html += '</div>';
return html;
}
if (typeof value === 'object' && value !== null) {
return this.formatObjectExpandable(value);
}
return this.escapeHtml(String(value));
}
/**
* NEW: Format objects as expandable content
*/
formatObjectExpandable(obj) {
if (!obj || typeof obj !== 'object') return '';
const entries = Object.entries(obj);
if (entries.length === 0) return '<em>Empty</em>';
if (entries.length <= 3) {
// Simple inline display for small objects
let html = '<div class="simple-object">';
entries.forEach(([key, value]) => {
html += `<div><strong>${key}:</strong> ${this.escapeHtml(String(value))}</div>`;
});
html += '</div>';
return html;
}
// Expandable display for complex objects
let html = '<div class="expandable-object">';
html += `
<div class="object-preview">
<strong>${entries[0][0]}:</strong> ${this.escapeHtml(String(entries[0][1]))}
<button class="expand-object-btn" onclick="this.parentElement.style.display='none'; this.parentElement.nextElementSibling.style.display='block';">
+${entries.length - 1} more properties...
</button>
</div>
<div class="object-full" style="display: none;">
`;
entries.forEach(([key, value]) => {
html += `<div class="object-property"><strong>${key}:</strong> ${this.escapeHtml(String(value))}</div>`;
});
html += `
<button class="collapse-object-btn" onclick="this.parentElement.style.display='none'; this.parentElement.previousElementSibling.style.display='block';">
Show less
</button>
</div>
</div>
`;
return html;
}
formatAttributeLabel(name) {
// Handle provider prefixed attributes
if (name.includes('_')) {
const parts = name.split('_');
if (parts.length >= 2) {
const provider = parts[0];
const attribute = parts.slice(1).join('_');
return `${this.provider}: ${this.formatLabel(attribute)}`;
}
}
return this.formatLabel(name);
}
groupAttributesIntelligently(attributes, nodeType) {
const groups = {};
// Define group configurations
const groupConfigs = {
'DNS Records': {
icon: '🔍',
priority: 'high',
keywords: ['dns', 'record', 'a_record', 'cname', 'mx', 'ns', 'txt', 'ptr'],
providers: ['dns']
},
'Certificate Information': {
icon: '🔒',
priority: 'high',
keywords: ['cert', 'certificate', 'ssl', 'tls', 'issuer', 'validity', 'san'],
providers: ['crtsh']
},
'Network Information': {
icon: '🌐',
priority: 'high',
keywords: ['port', 'service', 'banner', 'asn', 'organization', 'country', 'city'],
providers: ['shodan']
},
'Correlation Data': {
icon: '🔗',
priority: 'medium',
keywords: ['correlation', 'shared', 'common'],
providers: []
}
};
// Initialize groups
Object.entries(groupConfigs).forEach(([name, config]) => {
groups[name] = {
...config,
attributes: []
};
});
// Add a catch-all group
groups['Other Information'] = {
icon: '📋',
priority: 'low',
attributes: []
};
// Classify attributes into groups
attributes.forEach(attr => {
let assigned = false;
// Try to assign to a specific group based on provider or keywords
for (const [groupName, config] of Object.entries(groupConfigs)) {
const matchesProvider = config.providers.includes(attr.provider);
const matchesKeyword = config.keywords.some(keyword =>
attr.name.toLowerCase().includes(keyword) ||
attr.type.toLowerCase().includes(keyword)
);
if (matchesProvider || matchesKeyword) {
groups[groupName].attributes.push(attr);
assigned = true;
break;
}
}
// If not assigned to any specific group, put in "Other"
if (!assigned) {
groups['Other Information'].attributes.push(attr);
}
});
// Remove empty groups
Object.keys(groups).forEach(groupName => {
if (groups[groupName].attributes.length === 0) {
delete groups[groupName];
}
});
return groups;
}
/**
* UPDATED: Generate large entity details using unified data model
*/