This commit is contained in:
overcuriousity 2025-09-10 16:45:05 +02:00
parent a0caedcb1f
commit 709d3b9f3d
3 changed files with 124 additions and 21 deletions

View File

@ -194,6 +194,7 @@ class GraphManager {
<button class="graph-control-btn" id="graph-reset" title="Reset View">[RESET]</button> <button class="graph-control-btn" id="graph-reset" title="Reset View">[RESET]</button>
<button class="graph-control-btn" id="graph-physics" title="Toggle Physics">[PHYSICS]</button> <button class="graph-control-btn" id="graph-physics" title="Toggle Physics">[PHYSICS]</button>
<button class="graph-control-btn" id="graph-cluster" title="Cluster Nodes">[CLUSTER]</button> <button class="graph-control-btn" id="graph-cluster" title="Cluster Nodes">[CLUSTER]</button>
<button class="graph-control-btn" id="graph-clear" title="Clear Graph">[CLEAR]</button>
`; `;
this.container.appendChild(controlsContainer); this.container.appendChild(controlsContainer);
@ -203,6 +204,7 @@ class GraphManager {
document.getElementById('graph-reset').addEventListener('click', () => this.resetView()); document.getElementById('graph-reset').addEventListener('click', () => this.resetView());
document.getElementById('graph-physics').addEventListener('click', () => this.togglePhysics()); document.getElementById('graph-physics').addEventListener('click', () => this.togglePhysics());
document.getElementById('graph-cluster').addEventListener('click', () => this.toggleClustering()); document.getElementById('graph-cluster').addEventListener('click', () => this.toggleClustering());
document.getElementById('graph-clear').addEventListener('click', () => this.clear());
} }
/** /**

View File

@ -56,6 +56,7 @@ class DNSReconApp {
startScan: document.getElementById('start-scan'), startScan: document.getElementById('start-scan'),
stopScan: document.getElementById('stop-scan'), stopScan: document.getElementById('stop-scan'),
exportResults: document.getElementById('export-results'), exportResults: document.getElementById('export-results'),
configureApiKeys: document.getElementById('configure-api-keys'),
// Status elements // Status elements
scanStatus: document.getElementById('scan-status'), scanStatus: document.getElementById('scan-status'),
@ -69,12 +70,20 @@ class DNSReconApp {
// Provider elements // Provider elements
providerList: document.getElementById('provider-list'), providerList: document.getElementById('provider-list'),
// Modal elements // Node Modal elements
nodeModal: document.getElementById('node-modal'), nodeModal: document.getElementById('node-modal'),
modalTitle: document.getElementById('modal-title'), modalTitle: document.getElementById('modal-title'),
modalDetails: document.getElementById('modal-details'), modalDetails: document.getElementById('modal-details'),
modalClose: document.getElementById('modal-close'), modalClose: document.getElementById('modal-close'),
// API Key Modal elements
apiKeyModal: document.getElementById('api-key-modal'),
apiKeyModalClose: document.getElementById('api-key-modal-close'),
virustotalApiKey: document.getElementById('virustotal-api-key'),
shodanApiKey: document.getElementById('shodan-api-key'),
saveApiKeys: document.getElementById('save-api-keys'),
resetApiKeys: document.getElementById('reset-api-keys'),
// Other elements // Other elements
sessionId: document.getElementById('session-id'), sessionId: document.getElementById('session-id'),
connectionStatus: document.getElementById('connection-status') connectionStatus: document.getElementById('connection-status')
@ -140,6 +149,8 @@ class DNSReconApp {
this.exportResults(); this.exportResults();
}); });
this.elements.configureApiKeys.addEventListener('click', () => this.showApiKeyModal());
// Enter key support for target domain input // Enter key support for target domain input
this.elements.targetDomain.addEventListener('keypress', (e) => { this.elements.targetDomain.addEventListener('keypress', (e) => {
if (e.key === 'Enter' && !this.isScanning) { if (e.key === 'Enter' && !this.isScanning) {
@ -148,19 +159,32 @@ class DNSReconApp {
} }
}); });
// Modal interactions // Node Modal interactions
if (this.elements.modalClose) { if (this.elements.modalClose) {
this.elements.modalClose.addEventListener('click', () => this.hideModal()); this.elements.modalClose.addEventListener('click', () => this.hideModal());
} }
if (this.elements.nodeModal) { if (this.elements.nodeModal) {
this.elements.nodeModal.addEventListener('click', (e) => { this.elements.nodeModal.addEventListener('click', (e) => {
if (e.target === this.elements.nodeModal) { if (e.target === this.elements.nodeModal) this.hideModal();
this.hideModal();
}
}); });
} }
// API Key Modal interactions
if (this.elements.apiKeyModalClose) {
this.elements.apiKeyModalClose.addEventListener('click', () => this.hideApiKeyModal());
}
if (this.elements.apiKeyModal) {
this.elements.apiKeyModal.addEventListener('click', (e) => {
if (e.target === this.elements.apiKeyModal) this.hideApiKeyModal();
});
}
if (this.elements.saveApiKeys) {
this.elements.saveApiKeys.addEventListener('click', () => this.saveApiKeys());
}
if (this.elements.resetApiKeys) {
this.elements.resetApiKeys.addEventListener('click', () => this.resetApiKeys());
}
// Custom events // Custom events
document.addEventListener('nodeSelected', (e) => { document.addEventListener('nodeSelected', (e) => {
this.showNodeModal(e.detail.nodeId, e.detail.node); this.showNodeModal(e.detail.nodeId, e.detail.node);
@ -170,6 +194,7 @@ class DNSReconApp {
document.addEventListener('keydown', (e) => { document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') { if (e.key === 'Escape') {
this.hideModal(); this.hideModal();
this.hideApiKeyModal();
} }
}); });
@ -609,7 +634,6 @@ class DNSReconApp {
} }
if (this.elements.stopScan) { if (this.elements.stopScan) {
this.elements.stopScan.disabled = true; this.elements.stopScan.disabled = true;
this.elements.stopScan.classList.add('loading');
} }
if (this.elements.targetDomain) this.elements.targetDomain.disabled = false; if (this.elements.targetDomain) this.elements.targetDomain.disabled = false;
if (this.elements.maxDepth) this.elements.maxDepth.disabled = false; if (this.elements.maxDepth) this.elements.maxDepth.disabled = false;
@ -734,6 +758,62 @@ class DNSReconApp {
} }
} }
/**
* Show API Key modal
*/
showApiKeyModal() {
if (this.elements.apiKeyModal) {
this.elements.apiKeyModal.style.display = 'block';
}
}
/**
* Hide API Key modal
*/
hideApiKeyModal() {
if (this.elements.apiKeyModal) {
this.elements.apiKeyModal.style.display = 'none';
}
}
/**
* Save API Keys
*/
async saveApiKeys() {
const shodanKey = this.elements.shodanApiKey.value.trim();
const virustotalKey = this.elements.virustotalApiKey.value.trim();
const keys = {};
if (shodanKey) keys.shodan = shodanKey;
if (virustotalKey) keys.virustotal = virustotalKey;
if (Object.keys(keys).length === 0) {
this.showWarning('No API keys were entered.');
return;
}
try {
const response = await this.apiCall('/api/config/api-keys', 'POST', keys);
if (response.success) {
this.showSuccess(response.message);
this.hideApiKeyModal();
this.loadProviders(); // Refresh provider status
} else {
throw new Error(response.error || 'Failed to save API keys');
}
} catch (error) {
this.showError(`Error saving API keys: ${error.message}`);
}
}
/**
* Reset API Key fields
*/
resetApiKeys() {
this.elements.shodanApiKey.value = '';
this.elements.virustotalApiKey.value = '';
}
/** /**
* Check if graph data has changed * Check if graph data has changed
* @param {Object} graphData - New graph data * @param {Object} graphData - New graph data

View File

@ -11,7 +11,6 @@
</head> </head>
<body> <body>
<div class="container"> <div class="container">
<!-- Header -->
<header class="header"> <header class="header">
<div class="header-content"> <div class="header-content">
<div class="logo"> <div class="logo">
@ -25,9 +24,7 @@
</div> </div>
</header> </header>
<!-- Main Content -->
<main class="main-content"> <main class="main-content">
<!-- Control Panel -->
<section class="control-panel"> <section class="control-panel">
<div class="panel-header"> <div class="panel-header">
<h2>Target Configuration</h2> <h2>Target Configuration</h2>
@ -71,7 +68,6 @@
</div> </div>
</section> </section>
<!-- Status Panel -->
<section class="status-panel"> <section class="status-panel">
<div class="panel-header"> <div class="panel-header">
<h2>Reconnaissance Status</h2> <h2>Reconnaissance Status</h2>
@ -109,7 +105,6 @@
</div> </div>
</section> </section>
<!-- Visualization Panel -->
<section class="visualization-panel"> <section class="visualization-panel">
<div class="panel-header"> <div class="panel-header">
<h2>Infrastructure Map</h2> <h2>Infrastructure Map</h2>
@ -153,19 +148,16 @@
</div> </div>
</section> </section>
<!-- Provider Panel -->
<section class="provider-panel"> <section class="provider-panel">
<div class="panel-header"> <div class="panel-header">
<h2>Data Providers</h2> <h2>Data Providers</h2>
</div> </div>
<div id="provider-list" class="provider-list"> <div id="provider-list" class="provider-list">
<!-- Provider status will be populated here -->
</div> </div>
</section> </section>
</main> </main>
<!-- Footer -->
<footer class="footer"> <footer class="footer">
<div class="footer-content"> <div class="footer-content">
<span>DNSRecon v1.0 - Phase 1 Implementation</span> <span>DNSRecon v1.0 - Phase 1 Implementation</span>
@ -176,7 +168,6 @@
</div> </div>
</footer> </footer>
<!-- Node Details Modal -->
<div id="node-modal" class="modal"> <div id="node-modal" class="modal">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
@ -185,14 +176,44 @@
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div id="modal-details"> <div id="modal-details">
<!-- Node details will be populated here --> </div>
</div>
</div>
</div>
<div id="api-key-modal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h3>Configure API Keys</h3>
<button id="api-key-modal-close" class="modal-close">[×]</button>
</div>
<div class="modal-body">
<p class="modal-description">
Enter your API keys for enhanced data providers. Keys are stored in memory for the current session only and are never saved to disk.
</p>
<div class="apikey-section">
<label for="virustotal-api-key">VirusTotal API Key</label>
<input type="password" id="virustotal-api-key" placeholder="Enter VirusTotal API Key">
<p class="apikey-help">Enables passive DNS and domain reputation lookups.</p>
</div>
<div class="apikey-section">
<label for="shodan-api-key">Shodan API Key</label>
<input type="password" id="shodan-api-key" placeholder="Enter Shodan API Key">
<p class="apikey-help">Provides infrastructure context and service information.</p>
</div>
<div class="button-group" style="flex-direction: row; justify-content: flex-end;">
<button id="reset-api-keys" class="btn btn-secondary">
<span>Reset</span>
</button>
<button id="save-api-keys" class="btn btn-primary">
<span>Save Keys</span>
</button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<!-- Scripts -->
<script src="{{ url_for('static', filename='js/graph.js') }}"></script> <script src="{{ url_for('static', filename='js/graph.js') }}"></script>
<script src="{{ url_for('static', filename='js/main.js') }}"></script> <script src="{{ url_for('static', filename='js/main.js') }}"></script>
</body> </body>