address some issues in aiscanner

This commit is contained in:
usmannasir
2025-07-02 16:47:35 +05:00
parent a88abc176c
commit 9019bf1e30
4 changed files with 188 additions and 12 deletions

View File

@@ -560,6 +560,33 @@ def scan_callback(request):
scan_record.save() scan_record.save()
# Also update the ScanStatusUpdate record with final statistics
try:
from .status_models import ScanStatusUpdate
status_update, _ = ScanStatusUpdate.objects.get_or_create(scan_id=scan_id)
status_update.phase = 'completed'
status_update.progress = 100
status_update.files_discovered = summary.get('files_scanned', 0) # Use files_scanned as approximation
status_update.files_scanned = summary.get('files_scanned', 0)
status_update.files_remaining = 0
status_update.threats_found = summary.get('total_findings', 0)
# Extract critical and high threats from findings if available
critical_count = 0
high_count = 0
for finding in findings:
severity = finding.get('severity', '').lower()
if severity == 'critical':
critical_count += 1
elif severity == 'high':
high_count += 1
status_update.critical_threats = critical_count
status_update.high_threats = high_count
status_update.activity_description = f"Scan completed - {summary.get('total_findings', 0)} threats found"
status_update.save()
logging.writeToFile(f"[API] Updated ScanStatusUpdate for completed scan {scan_id}")
except Exception as e:
logging.writeToFile(f"[API] Error updating ScanStatusUpdate: {str(e)}")
# Update user balance if scan cost money # Update user balance if scan cost money
if scan_record.cost_usd > 0: if scan_record.cost_usd > 0:
try: try:

View File

@@ -718,9 +718,16 @@ AI Security Scanner - CyberPanel
{% endif %} {% endif %}
</td> </td>
<td> <td>
<button class="btn-default btn-xs" onclick="viewScanDetails('{{ scan.scan_id }}')"> <div style="display: flex; gap: 5px;">
<i class="fas fa-eye"></i> View <button class="btn-default btn-xs" onclick="viewScanDetails('{{ scan.scan_id }}')">
</button> <i class="fas fa-eye"></i> View
</button>
{% if scan.status == 'completed' %}
<button class="btn-primary btn-xs" onclick="viewOnPlatform('{{ scan.scan_id }}')" title="View detailed AI analysis on platform">
<i class="fas fa-external-link-alt"></i> AI Analysis
</button>
{% endif %}
</div>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
@@ -953,9 +960,16 @@ function updateScanHistoryTable(scans) {
`<span style="color: #ef4444; font-weight: 700;">${scan.issues_found}</span>` : `<span style="color: #ef4444; font-weight: 700;">${scan.issues_found}</span>` :
`<span style="color: #10b981;">${scan.issues_found}</span>`; `<span style="color: #10b981;">${scan.issues_found}</span>`;
const actionsHtml = `<button class="btn-default btn-xs" onclick="viewScanDetails('${scan.scan_id}')"> const actionsHtml = `<div style="display: flex; gap: 5px;">
<i class="fas fa-eye"></i> View <button class="btn-default btn-xs" onclick="viewScanDetails('${scan.scan_id}')">
</button>`; <i class="fas fa-eye"></i> View
</button>
${scan.status === 'completed' ? `
<button class="btn-primary btn-xs" onclick="viewOnPlatform('${scan.scan_id}')" title="View detailed AI analysis on platform">
<i class="fas fa-external-link-alt"></i> AI Analysis
</button>
` : ''}
</div>`;
const progressHtml = (scan.status === 'running' || scan.status === 'pending') ? const progressHtml = (scan.status === 'running' || scan.status === 'pending') ?
`<div class="progress" style="height: 20px;"> `<div class="progress" style="height: 20px;">
@@ -1011,6 +1025,24 @@ function viewScanDetails(scanId) {
fetchLiveProgress(scanId); fetchLiveProgress(scanId);
} }
function viewOnPlatform(scanId) {
// Fetch the platform monitor URL
fetch(`/aiscanner/platform-monitor-url/${scanId}/`)
.then(response => response.json())
.then(data => {
if (data.success && data.monitor_url) {
// Open in new tab
window.open(data.monitor_url, '_blank');
} else {
alert('Error: ' + (data.error || 'Could not get platform URL'));
}
})
.catch(error => {
console.error('Error:', error);
alert('Failed to get platform URL. Please try again.');
});
}
function fetchLiveProgress(scanId) { function fetchLiveProgress(scanId) {
console.log(`[AI Scanner] Fetching live progress for scan: ${scanId}`); console.log(`[AI Scanner] Fetching live progress for scan: ${scanId}`);
fetch(`/api/ai-scanner/scan/${scanId}/live-progress`) fetch(`/api/ai-scanner/scan/${scanId}/live-progress`)
@@ -1207,21 +1239,29 @@ function displayCompletedScanDetails(scan) {
</div>`; </div>`;
} }
// Use enhanced scan data from ScanStatusUpdate if available
const filesScanned = scan.files_scanned || 0;
const filesDiscovered = scan.files_discovered || scan.files_scanned || 0;
const threatsFound = scan.threats_found !== undefined ? scan.threats_found : (scan.issues_found || 0);
const criticalThreats = scan.critical_threats || 0;
const highThreats = scan.high_threats || 0;
document.getElementById('completedSection').innerHTML = ` document.getElementById('completedSection').innerHTML = `
<div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 15px; margin-bottom: 20px;"> <div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 15px; margin-bottom: 20px;">
<div class="stat-card" style="padding: 20px;"> <div class="stat-card" style="padding: 20px;">
<div class="stat-card-icon info" style="width: 40px; height: 40px; font-size: 18px; margin-bottom: 10px;"> <div class="stat-card-icon info" style="width: 40px; height: 40px; font-size: 18px; margin-bottom: 10px;">
<i class="fas fa-file"></i> <i class="fas fa-file"></i>
</div> </div>
<h4 style="margin: 0; font-size: 24px; font-weight: 700;">${scan.files_scanned || 0}</h4> <h4 style="margin: 0; font-size: 24px; font-weight: 700;">${filesScanned}${filesDiscovered > filesScanned ? `/${filesDiscovered}` : ''}</h4>
<p style="margin: 5px 0 0 0; font-size: 13px;">Files Scanned</p> <p style="margin: 5px 0 0 0; font-size: 13px;">Files Scanned</p>
</div> </div>
<div class="stat-card" style="padding: 20px;"> <div class="stat-card" style="padding: 20px;">
<div class="stat-card-icon ${scan.issues_found > 0 ? 'danger' : 'success'}" style="width: 40px; height: 40px; font-size: 18px; margin-bottom: 10px;"> <div class="stat-card-icon ${threatsFound > 0 ? 'danger' : 'success'}" style="width: 40px; height: 40px; font-size: 18px; margin-bottom: 10px;">
<i class="fas ${scan.issues_found > 0 ? 'fa-exclamation-triangle' : 'fa-check'}"></i> <i class="fas ${threatsFound > 0 ? 'fa-exclamation-triangle' : 'fa-check'}"></i>
</div> </div>
<h4 style="margin: 0; font-size: 24px; font-weight: 700;">${scan.issues_found || 0}</h4> <h4 style="margin: 0; font-size: 24px; font-weight: 700;">${threatsFound}</h4>
<p style="margin: 5px 0 0 0; font-size: 13px;">Issues Found</p> <p style="margin: 5px 0 0 0; font-size: 13px;">Threats Found</p>
${(criticalThreats > 0 || highThreats > 0) ? `<small style="color: #ef4444; font-size: 11px;">${criticalThreats > 0 ? `${criticalThreats} Critical` : ''}${criticalThreats > 0 && highThreats > 0 ? ', ' : ''}${highThreats > 0 ? `${highThreats} High` : ''}</small>` : ''}
</div> </div>
<div class="stat-card" style="padding: 20px;"> <div class="stat-card" style="padding: 20px;">
<div class="stat-card-icon info" style="width: 40px; height: 40px; font-size: 18px; margin-bottom: 10px;"> <div class="stat-card-icon info" style="width: 40px; height: 40px; font-size: 18px; margin-bottom: 10px;">
@@ -1239,6 +1279,11 @@ function displayCompletedScanDetails(scan) {
</div> </div>
</div> </div>
${findingsHtml} ${findingsHtml}
<div style="margin-top: 20px; text-align: center;">
<button class="btn-primary" onclick="viewOnPlatform('${scan.scan_id}')" style="padding: 0.75rem 2rem;">
<i class="fas fa-external-link-alt"></i> View Full AI Analysis on Platform
</button>
</div>
`; `;
} }

View File

@@ -15,6 +15,7 @@ urlpatterns = [
# Scan management # Scan management
path('scan-history/', views.getScanHistory, name='aiScannerHistory'), path('scan-history/', views.getScanHistory, name='aiScannerHistory'),
path('scan-details/<str:scan_id>/', views.getScanDetails, name='aiScannerDetails'), path('scan-details/<str:scan_id>/', views.getScanDetails, name='aiScannerDetails'),
path('platform-monitor-url/<str:scan_id>/', views.getPlatformMonitorUrl, name='aiScannerPlatformMonitorUrl'),
path('platform-status/<str:scan_id>/', views.getPlatformScanStatus, name='aiScannerPlatformStatus'), path('platform-status/<str:scan_id>/', views.getPlatformScanStatus, name='aiScannerPlatformStatus'),
# Note: RESTful API endpoints are in /api/urls.py for external access # Note: RESTful API endpoints are in /api/urls.py for external access

View File

@@ -129,12 +129,14 @@ def getScanHistory(request):
return JsonResponse({'success': False, 'error': str(e)}) return JsonResponse({'success': False, 'error': str(e)})
@require_http_methods(['GET'])
def getScanDetails(request, scan_id): def getScanDetails(request, scan_id):
"""Get detailed scan results""" """Get detailed scan results"""
try: try:
userID = request.session['userID'] userID = request.session['userID']
from loginSystem.models import Administrator from loginSystem.models import Administrator
from .models import ScanHistory from .models import ScanHistory
from .status_models import ScanStatusUpdate
from plogical.acl import ACLManager from plogical.acl import ACLManager
admin = Administrator.objects.get(pk=userID) admin = Administrator.objects.get(pk=userID)
@@ -153,6 +155,23 @@ def getScanDetails(request, scan_id):
except ScanHistory.DoesNotExist: except ScanHistory.DoesNotExist:
return JsonResponse({'success': False, 'error': 'Scan not found'}) return JsonResponse({'success': False, 'error': 'Scan not found'})
# Get the status update for more detailed information
try:
status_update = ScanStatusUpdate.objects.get(scan_id=scan_id)
# Use detailed information from status update if available
files_scanned = status_update.files_scanned if status_update.files_scanned > 0 else scan.files_scanned
files_discovered = status_update.files_discovered
threats_found = status_update.threats_found
critical_threats = status_update.critical_threats
high_threats = status_update.high_threats
except ScanStatusUpdate.DoesNotExist:
# Fall back to basic information from scan history
files_scanned = scan.files_scanned
files_discovered = scan.files_scanned # Approximate
threats_found = scan.issues_found
critical_threats = 0
high_threats = 0
scan_data = { scan_data = {
'scan_id': scan.scan_id, 'scan_id': scan.scan_id,
'domain': scan.domain, 'domain': scan.domain,
@@ -161,8 +180,12 @@ def getScanDetails(request, scan_id):
'started_at': scan.started_at.strftime('%Y-%m-%d %H:%M:%S'), 'started_at': scan.started_at.strftime('%Y-%m-%d %H:%M:%S'),
'completed_at': scan.completed_at.strftime('%Y-%m-%d %H:%M:%S') if scan.completed_at else None, 'completed_at': scan.completed_at.strftime('%Y-%m-%d %H:%M:%S') if scan.completed_at else None,
'cost_usd': float(scan.cost_usd) if scan.cost_usd else 0, 'cost_usd': float(scan.cost_usd) if scan.cost_usd else 0,
'files_scanned': scan.files_scanned, 'files_scanned': files_scanned,
'files_discovered': files_discovered,
'issues_found': scan.issues_found, 'issues_found': scan.issues_found,
'threats_found': threats_found,
'critical_threats': critical_threats,
'high_threats': high_threats,
'findings': scan.findings, 'findings': scan.findings,
'summary': scan.summary, 'summary': scan.summary,
'error_message': scan.error_message 'error_message': scan.error_message
@@ -178,6 +201,86 @@ def getScanDetails(request, scan_id):
return JsonResponse({'success': False, 'error': str(e)}) return JsonResponse({'success': False, 'error': str(e)})
@require_http_methods(['GET'])
def getPlatformMonitorUrl(request, scan_id):
"""Get the platform monitor URL for a scan"""
try:
userID = request.session['userID']
from loginSystem.models import Administrator
from .models import ScanHistory, AIScannerSettings
from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging
import requests
# Get scan to verify ownership
try:
scan = ScanHistory.objects.get(scan_id=scan_id)
admin = Administrator.objects.get(pk=userID)
# Verify access
from plogical.acl import ACLManager
currentACL = ACLManager.loadedACL(userID)
if currentACL['admin'] != 1:
user_admins = ACLManager.loadUserObjects(userID)
if scan.admin not in user_admins:
return JsonResponse({'success': False, 'error': 'Access denied'})
except ScanHistory.DoesNotExist:
return JsonResponse({'success': False, 'error': 'Scan not found'})
# Get API key for the scan owner
try:
scanner_settings = scan.admin.ai_scanner_settings
if not scanner_settings.api_key:
return JsonResponse({'success': False, 'error': 'API key not configured'})
api_key = scanner_settings.api_key
except:
return JsonResponse({'success': False, 'error': 'Scanner not configured'})
# Call platform API to get monitor URL
try:
url = f"https://platform.cyberpersons.com/ai-scanner/api/ai-scanner/scan/{scan_id}/monitor-url/"
headers = {
'Authorization': f'Bearer {api_key}',
'Content-Type': 'application/json'
}
logging.writeToFile(f"[AI Scanner] Fetching platform monitor URL for scan {scan_id}")
response = requests.get(url, headers=headers, timeout=10)
data = response.json()
if response.status_code == 200 and data.get('success'):
logging.writeToFile(f"[AI Scanner] Got monitor URL: {data.get('monitor_url')}")
return JsonResponse({
'success': True,
'monitor_url': data.get('monitor_url'),
'platform_scan_id': data.get('platform_scan_id')
})
else:
error_msg = data.get('error', 'Failed to get monitor URL')
logging.writeToFile(f"[AI Scanner] Failed to get monitor URL: {error_msg}")
return JsonResponse({
'success': False,
'error': error_msg,
'scan_exists': data.get('scan_exists', False)
})
except requests.exceptions.Timeout:
logging.writeToFile(f"[AI Scanner] Platform request timeout for scan {scan_id}")
return JsonResponse({'success': False, 'error': 'Platform request timeout'})
except requests.exceptions.RequestException as e:
logging.writeToFile(f"[AI Scanner] Platform request error: {str(e)}")
return JsonResponse({'success': False, 'error': f'Platform error: {str(e)}'})
except Exception as e:
logging.writeToFile(f"[AI Scanner] Unexpected error: {str(e)}")
return JsonResponse({'success': False, 'error': f'Error: {str(e)}'})
except KeyError:
return JsonResponse({'success': False, 'error': 'Not authenticated'})
except Exception as e:
logging.writeToFile(f"[AI Scanner] getPlatformMonitorUrl error: {str(e)}")
return JsonResponse({'success': False, 'error': str(e)})
def getPlatformScanStatus(request, scan_id): def getPlatformScanStatus(request, scan_id):
"""Get real-time scan status from AI Scanner platform""" """Get real-time scan status from AI Scanner platform"""
try: try: