modularize, shodan qs

This commit is contained in:
overcuriousity
2025-09-13 17:14:16 +02:00
parent 2925512a4d
commit 930fdca500
10 changed files with 275 additions and 147 deletions

View File

@@ -13,7 +13,6 @@ class GraphManager {
this.currentLayout = 'physics';
this.nodeInfoPopup = null;
// Enhanced graph options for Phase 2
this.options = {
nodes: {
shape: 'dot',
@@ -214,20 +213,7 @@ class GraphManager {
}
});
this.network.on('blurNode', (params) => {
this.hideNodeInfoPopup();
this.clearHoverHighlights();
});
// Double-click to focus on node
this.network.on('doubleClick', (params) => {
if (params.nodes.length > 0) {
const nodeId = params.nodes[0];
this.focusOnNode(nodeId);
}
});
// Context menu (right-click)
// TODO Context menu (right-click)
this.network.on('oncontext', (params) => {
params.event.preventDefault();
if (params.nodes.length > 0) {

View File

@@ -12,10 +12,8 @@ class DNSReconApp {
this.pollInterval = null;
this.currentSessionId = null;
// UI Elements
this.elements = {};
// Application state
this.isScanning = false;
this.lastGraphUpdate = null;
@@ -80,7 +78,7 @@ class DNSReconApp {
// API Key Modal elements
apiKeyModal: document.getElementById('api-key-modal'),
apiKeyModalClose: document.getElementById('api-key-modal-close'),
shodanApiKey: document.getElementById('shodan-api-key'),
apiKeyInputs: document.getElementById('api-key-inputs'),
saveApiKeys: document.getElementById('save-api-keys'),
resetApiKeys: document.getElementById('reset-api-keys'),
@@ -732,6 +730,7 @@ class DNSReconApp {
if (response.success) {
this.updateProviderDisplay(response.providers);
this.buildApiKeyModal(response.providers);
console.log('Providers loaded successfully');
}
@@ -766,7 +765,7 @@ class DNSReconApp {
providerItem.innerHTML = `
<div class="provider-header">
<div class="provider-name">${name.toUpperCase()}</div>
<div class="provider-name">${info.display_name}</div>
<div class="provider-status ${statusClass}">${statusText}</div>
</div>
<div class="provider-stats">
@@ -970,10 +969,15 @@ class DNSReconApp {
* Save API Keys
*/
async saveApiKeys() {
const shodanKey = this.elements.shodanApiKey.value.trim();
const inputs = this.elements.apiKeyInputs.querySelectorAll('input');
const keys = {};
if (shodanKey) keys.shodan = shodanKey;
inputs.forEach(input => {
const provider = input.dataset.provider;
const value = input.value.trim();
if (provider && value) {
keys[provider] = value;
}
});
if (Object.keys(keys).length === 0) {
this.showWarning('No API keys were entered.');
@@ -998,7 +1002,10 @@ class DNSReconApp {
* Reset API Key fields
*/
resetApiKeys() {
this.elements.shodanApiKey.value = '';
const inputs = this.elements.apiKeyInputs.querySelectorAll('input');
inputs.forEach(input => {
input.value = '';
});
}
/**
@@ -1295,6 +1302,74 @@ class DNSReconApp {
};
return colors[type] || colors.info;
}
/**
* Build the API key modal dynamically
* @param {Object} providers - Provider information
*/
buildApiKeyModal(providers) {
if (!this.elements.apiKeyInputs) return;
this.elements.apiKeyInputs.innerHTML = ''; // Clear existing inputs
let hasApiKeyProviders = false;
for (const [name, info] of Object.entries(providers)) {
if (info.requires_api_key) {
hasApiKeyProviders = true;
const inputGroup = document.createElement('div');
inputGroup.className = 'apikey-section';
if (info.enabled) {
// If the API key is set and the provider is enabled
inputGroup.innerHTML = `
<label for="${name}-api-key">${info.display_name} API Key</label>
<div class="api-key-set-message">
<span class="api-key-set-text">API Key is set</span>
<button class="clear-api-key-btn" data-provider="${name}">Clear</button>
</div>
<p class="apikey-help">Provides infrastructure context and service information.</p>
`;
} else {
// If the API key is not set
inputGroup.innerHTML = `
<label for="${name}-api-key">${info.display_name} API Key</label>
<input type="password" id="${name}-api-key" data-provider="${name}" placeholder="Enter ${info.display_name} API Key">
<p class="apikey-help">Provides infrastructure context and service information.</p>
`;
}
this.elements.apiKeyInputs.appendChild(inputGroup);
}
}
// Add event listeners for the new clear buttons
this.elements.apiKeyInputs.querySelectorAll('.clear-api-key-btn').forEach(button => {
button.addEventListener('click', (e) => {
const provider = e.target.dataset.provider;
this.clearApiKey(provider);
});
});
if (!hasApiKeyProviders) {
this.elements.apiKeyInputs.innerHTML = '<p>No providers require API keys.</p>';
}
}
/**
* Clear an API key for a specific provider
* @param {string} provider The name of the provider to clear the API key for
*/
async clearApiKey(provider) {
try {
const response = await this.apiCall('/api/config/api-keys', 'POST', { [provider]: '' });
if (response.success) {
this.showSuccess(`API key for ${provider} has been cleared.`);
this.loadProviders(); // This will rebuild the modal with the updated state
} else {
throw new Error(response.error || 'Failed to clear API key');
}
} catch (error) {
this.showError(`Error clearing API key: ${error.message}`);
}
}
}
// Add CSS animations for message toasts