it
This commit is contained in:
@@ -233,7 +233,6 @@ class GraphManager {
|
||||
const nodeId = params.node;
|
||||
const node = this.nodes.get(nodeId);
|
||||
if (node) {
|
||||
this.showNodeInfoPopup(params.pointer.DOM, node);
|
||||
this.highlightConnectedNodes(nodeId, true);
|
||||
}
|
||||
});
|
||||
@@ -243,19 +242,6 @@ class GraphManager {
|
||||
this.clearHoverHighlights();
|
||||
});
|
||||
|
||||
// Edge hover events
|
||||
this.network.on('hoverEdge', (params) => {
|
||||
const edgeId = params.edge;
|
||||
const edge = this.edges.get(edgeId);
|
||||
if (edge) {
|
||||
this.showEdgeInfo(params.pointer.DOM, edge);
|
||||
}
|
||||
});
|
||||
|
||||
this.network.on('blurEdge', () => {
|
||||
this.hideNodeInfoPopup();
|
||||
});
|
||||
|
||||
// Double-click to focus on node
|
||||
this.network.on('doubleClick', (params) => {
|
||||
if (params.nodes.length > 0) {
|
||||
@@ -347,7 +333,6 @@ class GraphManager {
|
||||
const processedNode = {
|
||||
id: node.id,
|
||||
label: this.formatNodeLabel(node.id, node.type),
|
||||
title: this.createNodeTooltip(node),
|
||||
color: this.getNodeColor(node.type),
|
||||
size: this.getNodeSize(node.type),
|
||||
borderColor: this.getNodeBorderColor(node.type),
|
||||
@@ -373,11 +358,14 @@ class GraphManager {
|
||||
}
|
||||
|
||||
// Style based on certificate validity
|
||||
if (node.has_valid_cert === true) {
|
||||
processedNode.borderColor = '#00ff41'; // Green for valid cert
|
||||
} else if (node.has_valid_cert === false) {
|
||||
processedNode.borderColor = '#ff9900'; // Amber for expired/no cert
|
||||
processedNode.borderDashes = [5, 5];
|
||||
if (node.type === 'domain') {
|
||||
if (node.metadata && node.metadata.has_valid_cert === true) {
|
||||
processedNode.color = '#00ff41'; // Bright green for valid cert
|
||||
processedNode.borderColor = '#00aa2e';
|
||||
} else if (node.metadata && node.metadata.has_valid_cert === false) {
|
||||
processedNode.color = '#888888'; // Muted grey color
|
||||
processedNode.borderColor = '#666666'; // Darker grey border
|
||||
}
|
||||
}
|
||||
|
||||
return processedNode;
|
||||
@@ -457,9 +445,9 @@ class GraphManager {
|
||||
const colors = {
|
||||
'domain': '#00ff41', // Green
|
||||
'ip': '#ff9900', // Amber
|
||||
'certificate': '#c7c7c7', // Gray
|
||||
'asn': '#00aaff', // Blue
|
||||
'large_entity': '#ff6b6b' // Red for large entities
|
||||
'large_entity': '#ff6b6b', // Red for large entities
|
||||
'dns_record': '#999999'
|
||||
};
|
||||
return colors[nodeType] || '#ffffff';
|
||||
}
|
||||
@@ -474,8 +462,8 @@ class GraphManager {
|
||||
const borderColors = {
|
||||
'domain': '#00aa2e',
|
||||
'ip': '#cc7700',
|
||||
'certificate': '#999999',
|
||||
'asn': '#0088cc'
|
||||
'asn': '#0088cc',
|
||||
'dns_record': '#999999'
|
||||
};
|
||||
return borderColors[nodeType] || '#666666';
|
||||
}
|
||||
@@ -489,8 +477,8 @@ class GraphManager {
|
||||
const sizes = {
|
||||
'domain': 12,
|
||||
'ip': 14,
|
||||
'certificate': 10,
|
||||
'asn': 16
|
||||
'asn': 16,
|
||||
'dns_record': 8
|
||||
};
|
||||
return sizes[nodeType] || 12;
|
||||
}
|
||||
@@ -504,8 +492,8 @@ class GraphManager {
|
||||
const shapes = {
|
||||
'domain': 'dot',
|
||||
'ip': 'square',
|
||||
'certificate': 'diamond',
|
||||
'asn': 'triangle'
|
||||
'asn': 'triangle',
|
||||
'dns_record': 'hexagon'
|
||||
};
|
||||
return shapes[nodeType] || 'dot';
|
||||
}
|
||||
@@ -541,26 +529,7 @@ class GraphManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create node tooltip
|
||||
* @param {Object} node - Node data
|
||||
* @returns {string} HTML tooltip content
|
||||
*/
|
||||
createNodeTooltip(node) {
|
||||
let tooltip = `<div style="font-family: 'Roboto Mono', monospace; font-size: 11px;">`;
|
||||
tooltip += `<div style="color: #00ff41; font-weight: bold; margin-bottom: 4px;">${node.id}</div>`;
|
||||
tooltip += `<div style="color: #999; margin-bottom: 2px;">Type: ${node.type}</div>`;
|
||||
|
||||
if (node.metadata && Object.keys(node.metadata).length > 0) {
|
||||
tooltip += `<div style="color: #999; margin-top: 4px; border-top: 1px solid #444; padding-top: 4px;">`;
|
||||
tooltip += `Click for details</div>`;
|
||||
}
|
||||
|
||||
tooltip += `</div>`;
|
||||
return tooltip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create edge tooltip
|
||||
* Create edge tooltip with correct provider information
|
||||
* @param {Object} edge - Edge data
|
||||
* @returns {string} HTML tooltip content
|
||||
*/
|
||||
@@ -570,7 +539,7 @@ class GraphManager {
|
||||
tooltip += `<div style="color: #999; margin-bottom: 2px;">Confidence: ${(edge.confidence_score * 100).toFixed(1)}%</div>`;
|
||||
|
||||
if (edge.source_provider) {
|
||||
tooltip += `<div style="color: #999; margin-bottom: 2px;">Source: ${edge.source_provider}</div>`;
|
||||
tooltip += `<div style="color: #999; margin-bottom: 2px;">Provider: ${edge.source_provider}</div>`;
|
||||
}
|
||||
|
||||
if (edge.discovery_timestamp) {
|
||||
@@ -610,69 +579,6 @@ class GraphManager {
|
||||
document.dispatchEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show enhanced node info popup
|
||||
* @param {Object} position - Mouse position
|
||||
* @param {Object} node - Node data
|
||||
*/
|
||||
showNodeInfoPopup(position, node) {
|
||||
if (!this.nodeInfoPopup) return;
|
||||
|
||||
const html = `
|
||||
<div class="node-info-title">${node.id}</div>
|
||||
<div class="node-info-detail">
|
||||
<span class="node-info-label">Type:</span>
|
||||
<span class="node-info-value">${node.type || 'Unknown'}</span>
|
||||
</div>
|
||||
${node.metadata && Object.keys(node.metadata).length > 0 ?
|
||||
'<div class="node-info-detail"><span class="node-info-label">Details:</span><span class="node-info-value">Click for more</span></div>' :
|
||||
''}
|
||||
`;
|
||||
|
||||
this.nodeInfoPopup.innerHTML = html;
|
||||
this.nodeInfoPopup.style.display = 'block';
|
||||
this.nodeInfoPopup.style.left = position.x + 15 + 'px';
|
||||
this.nodeInfoPopup.style.top = position.y - 10 + 'px';
|
||||
|
||||
// Ensure popup stays in viewport
|
||||
const rect = this.nodeInfoPopup.getBoundingClientRect();
|
||||
if (rect.right > window.innerWidth) {
|
||||
this.nodeInfoPopup.style.left = position.x - rect.width - 15 + 'px';
|
||||
}
|
||||
if (rect.bottom > window.innerHeight) {
|
||||
this.nodeInfoPopup.style.top = position.y - rect.height + 10 + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show edge information tooltip
|
||||
* @param {Object} position - Mouse position
|
||||
* @param {Object} edge - Edge data
|
||||
*/
|
||||
showEdgeInfo(position, edge) {
|
||||
if (!this.nodeInfoPopup) return;
|
||||
|
||||
const confidence = edge.metadata ? edge.metadata.confidence_score : 0;
|
||||
const provider = edge.metadata ? edge.metadata.source_provider : 'Unknown';
|
||||
|
||||
const html = `
|
||||
<div class="node-info-title">${edge.metadata ? edge.metadata.relationship_type : 'Relationship'}</div>
|
||||
<div class="node-info-detail">
|
||||
<span class="node-info-label">Confidence:</span>
|
||||
<span class="node-info-value">${(confidence * 100).toFixed(1)}%</span>
|
||||
</div>
|
||||
<div class="node-info-detail">
|
||||
<span class="node-info-label">Provider:</span>
|
||||
<span class="node-info-value">${provider}</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
this.nodeInfoPopup.innerHTML = html;
|
||||
this.nodeInfoPopup.style.display = 'block';
|
||||
this.nodeInfoPopup.style.left = position.x + 15 + 'px';
|
||||
this.nodeInfoPopup.style.top = position.y - 10 + 'px';
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide node info popup
|
||||
*/
|
||||
|
||||
@@ -511,9 +511,18 @@ class DNSReconApp {
|
||||
}
|
||||
}
|
||||
|
||||
// Update session ID
|
||||
if (this.currentSessionId && this.elements.sessionId) {
|
||||
this.elements.sessionId.textContent = `Session: ${this.currentSessionId}`;
|
||||
// Update session ID display with user session info
|
||||
if (this.elements.sessionId) {
|
||||
const scanSessionId = this.currentSessionId;
|
||||
const userSessionId = status.user_session_id;
|
||||
|
||||
if (scanSessionId && userSessionId) {
|
||||
this.elements.sessionId.textContent = `Session: ${userSessionId.substring(0, 8)}... | Scan: ${scanSessionId}`;
|
||||
} else if (userSessionId) {
|
||||
this.elements.sessionId.textContent = `User Session: ${userSessionId.substring(0, 8)}...`;
|
||||
} else {
|
||||
this.elements.sessionId.textContent = 'Session: Loading...';
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Status display updated successfully');
|
||||
@@ -730,11 +739,13 @@ class DNSReconApp {
|
||||
}
|
||||
|
||||
let detailsHtml = '';
|
||||
const createDetailRow = (label, value) => {
|
||||
const createDetailRow = (label, value, statusIcon = '') => {
|
||||
const baseId = `detail-${label.replace(/[^a-zA-Z0-9]/g, '-')}`;
|
||||
|
||||
// Handle empty or undefined values by showing N/A
|
||||
if (value === null || value === undefined || (Array.isArray(value) && value.length === 0)) {
|
||||
// Handle empty or undefined values
|
||||
if (value === null || value === undefined ||
|
||||
(Array.isArray(value) && value.length === 0) ||
|
||||
(typeof value === 'object' && Object.keys(value).length === 0)) {
|
||||
return `
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">${label} <span class="status-icon text-warning">✗</span></span>
|
||||
@@ -743,12 +754,11 @@ class DNSReconApp {
|
||||
`;
|
||||
}
|
||||
|
||||
// If value is an array, create a row for each item
|
||||
// Handle arrays
|
||||
if (Array.isArray(value)) {
|
||||
return value.map((item, index) => {
|
||||
const itemId = `${baseId}-${index}`;
|
||||
// Only show the label for the first item in the list
|
||||
const itemLabel = index === 0 ? label : '';
|
||||
const itemLabel = index === 0 ? `${label} <span class="status-icon text-success">✓</span>` : '';
|
||||
return `
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">${itemLabel}</span>
|
||||
@@ -758,12 +768,13 @@ class DNSReconApp {
|
||||
`;
|
||||
}).join('');
|
||||
}
|
||||
// Handle objects and other primitive values in a single row
|
||||
// Handle objects and primitives
|
||||
else {
|
||||
const valueId = `${baseId}-0`;
|
||||
const icon = statusIcon || '<span class="status-icon text-success">✓</span>';
|
||||
return `
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">${label} <span class="status-icon text-success">✓</span></span>
|
||||
<span class="detail-label">${label} ${icon}</span>
|
||||
<span class="detail-value" id="${valueId}">${this.formatValue(value)}</span>
|
||||
<button class="copy-btn" onclick="copyToClipboard('${valueId}')" title="Copy">📋</button>
|
||||
</div>
|
||||
@@ -773,33 +784,44 @@ class DNSReconApp {
|
||||
|
||||
const metadata = node.metadata || {};
|
||||
|
||||
// Display data based on node type
|
||||
switch (node.type) {
|
||||
case 'domain':
|
||||
detailsHtml += createDetailRow('DNS Records', metadata.dns_records);
|
||||
detailsHtml += createDetailRow('Related Domains (SAN)', metadata.related_domains_san);
|
||||
detailsHtml += createDetailRow('Certificate Data', metadata.certificate_data);
|
||||
detailsHtml += createDetailRow('Passive DNS', metadata.passive_dns);
|
||||
detailsHtml += createDetailRow('Shodan Data', metadata.shodan);
|
||||
detailsHtml += createDetailRow('VirusTotal Data', metadata.virustotal);
|
||||
detailsHtml += createDetailRow('ASN Information', metadata.asn_data);
|
||||
break;
|
||||
case 'ip':
|
||||
detailsHtml += createDetailRow('DNS Records', metadata.dns_records);
|
||||
detailsHtml += createDetailRow('Passive DNS', metadata.passive_dns);
|
||||
detailsHtml += createDetailRow('Shodan Data', metadata.shodan);
|
||||
detailsHtml += createDetailRow('VirusTotal Data', metadata.virustotal);
|
||||
break;
|
||||
case 'certificate':
|
||||
detailsHtml += createDetailRow('Certificate Hash', metadata.hash);
|
||||
detailsHtml += createDetailRow('SANs', metadata.sans);
|
||||
detailsHtml += createDetailRow('Issuer', metadata.issuer);
|
||||
detailsHtml += createDetailRow('Validity', `From: ${metadata.not_before || 'N/A'} To: ${metadata.not_after || 'N/A'}`);
|
||||
detailsHtml += createDetailRow('ASN Information', metadata.asn_data);
|
||||
break;
|
||||
case 'asn':
|
||||
detailsHtml += createDetailRow('ASN', metadata.asn);
|
||||
detailsHtml += createDetailRow('Description', metadata.description);
|
||||
detailsHtml += createDetailRow('ASN Information', metadata.asn_data);
|
||||
detailsHtml += createDetailRow('Related IPs', metadata.passive_dns);
|
||||
break;
|
||||
case 'large_entity':
|
||||
detailsHtml += createDetailRow('Entity Type', metadata.entity_type || 'Large Collection');
|
||||
detailsHtml += createDetailRow('Item Count', metadata.count);
|
||||
detailsHtml += createDetailRow('Discovered Domains', metadata.domains);
|
||||
break;
|
||||
}
|
||||
|
||||
// Add any additional metadata not covered above
|
||||
for (const [key, value] of Object.entries(metadata)) {
|
||||
if (!['dns_records', 'related_domains_san', 'certificate_data', 'passive_dns',
|
||||
'shodan', 'virustotal', 'asn_data', 'hash', 'sans', 'issuer',
|
||||
'not_before', 'not_after', 'entity_type', 'count', 'domains'].includes(key)) {
|
||||
detailsHtml += createDetailRow(this.formatLabel(key), value);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.elements.modalDetails) {
|
||||
this.elements.modalDetails.innerHTML = detailsHtml;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user