Skip to content

Commit

Permalink
Merge pull request #1321 from yogeshojha/1270-stop-all-scans-killswitch
Browse files Browse the repository at this point in the history
Feature: Introduce stop multiple scans #1270
  • Loading branch information
yogeshojha authored Jul 31, 2024
2 parents 4fe2a5c + ded8c16 commit db0348c
Show file tree
Hide file tree
Showing 7 changed files with 311 additions and 61 deletions.
116 changes: 74 additions & 42 deletions web/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -774,63 +774,95 @@ class StopScan(APIView):
def post(self, request):
req = self.request
data = req.data
scan_id = data.get('scan_id')
subscan_id = data.get('subscan_id')
response = {}
task_ids = []
scan = None
subscan = None
if subscan_id:
try:
subscan = get_object_or_404(SubScan, id=subscan_id)
scan = subscan.scan_history
task_ids = subscan.celery_ids
subscan.status = ABORTED_TASK
subscan.stop_scan_date = timezone.now()
subscan.save()
create_scan_activity(
subscan.scan_history.id,
f'Subscan {subscan_id} aborted',
SUCCESS_TASK)
response['status'] = True
except Exception as e:
logging.error(e)
response = {'status': False, 'message': str(e)}
elif scan_id:
scan_ids = data.get('scan_ids', [])
subscan_ids = data.get('subscan_ids', [])

scan_ids = [int(id) for id in scan_ids]
subscan_ids = [int(id) for id in subscan_ids]

response = {'status': False}

def abort_scan(scan):
response = {}
logger.info(f'Aborting scan History')
try:
scan = get_object_or_404(ScanHistory, id=scan_id)
logger.info(f"Setting scan {scan} status to ABORTED_TASK")
task_ids = scan.celery_ids
scan.scan_status = ABORTED_TASK
scan.stop_scan_date = timezone.now()
scan.aborted_by = request.user
scan.save()
for task_id in task_ids:
app.control.revoke(task_id, terminate=True, signal='SIGKILL')

tasks = (
ScanActivity.objects
.filter(scan_of=scan)
.filter(status=RUNNING_TASK)
.order_by('-pk')
)
for task in tasks:
task.status = ABORTED_TASK
task.time = timezone.now()
task.save()

create_scan_activity(
scan.id,
"Scan aborted",
SUCCESS_TASK)
ABORTED_TASK
)
response['status'] = True
except Exception as e:
logging.error(e)
logger.error(e)
response = {'status': False, 'message': str(e)}

logger.warning(f'Revoking tasks {task_ids}')
for task_id in task_ids:
app.control.revoke(task_id, terminate=True, signal='SIGKILL')
return response

# Abort running tasks
tasks = (
ScanActivity.objects
.filter(scan_of=scan)
.filter(status=RUNNING_TASK)
.order_by('-pk')
)
if tasks.exists():
for task in tasks:
if subscan_id and task.id not in subscan.celery_ids:
def abort_subscan(subscan):
response = {}
logger.info(f'Aborting subscan')
try:
logger.info(f"Setting scan {subscan} status to ABORTED_TASK")
task_ids = subscan.celery_ids

for task_id in task_ids:
app.control.revoke(task_id, terminate=True, signal='SIGKILL')

subscan.status = ABORTED_TASK
subscan.stop_scan_date = timezone.now()
subscan.save()
create_scan_activity(
subscan.scan_history.id,
f'Subscan aborted',
ABORTED_TASK
)
response['status'] = True
except Exception as e:
logger.error(e)
response = {'status': False, 'message': str(e)}

return response

for scan_id in scan_ids:
try:
scan = ScanHistory.objects.get(id=scan_id)
# if scan is already successful or aborted then do nothing
if scan.scan_status == SUCCESS_TASK or scan.scan_status == ABORTED_TASK:
continue
task.status = ABORTED_TASK
task.time = timezone.now()
task.save()
response = abort_scan(scan)
except Exception as e:
logger.error(e)
response = {'status': False, 'message': str(e)}

for subscan_id in subscan_ids:
try:
subscan = SubScan.objects.get(id=subscan_id)
if subscan.scan_status == SUCCESS_TASK or subscan.scan_status == ABORTED_TASK:
continue
response = abort_subscan(subscan)
except Exception as e:
logger.error(e)
response = {'status': False, 'message': str(e)}

return Response(response)

Check warning

Code scanning / CodeQL

Information exposure through an exception Medium

Stack trace information
flows to this location and may be exposed to an external user.
Stack trace information
flows to this location and may be exposed to an external user.
Stack trace information
flows to this location and may be exposed to an external user.
Stack trace information
flows to this location and may be exposed to an external user.

Expand Down
5 changes: 5 additions & 0 deletions web/reNgine/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,11 @@
'handlers': ['task'],
'level': 'DEBUG' if DEBUG else 'INFO',
'propagate': False
},
'api.views': {
'handlers': ['console'],
'level': 'DEBUG' if DEBUG else 'INFO',
'propagate': False
}
},
}
86 changes: 84 additions & 2 deletions web/startScan/templates/startScan/history.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,12 @@ <h4 class="headline-title">Filters</h4>
<a href="#" class="dropdown-ite text-primary float-end" id="resetFilters">Reset Filters</a>
</div>
</div>
{% if user|can:'initiate_scans_subscans' %}
<div class="col-xl-6 col-lg-6 col-md-6 col-sm-12 col-12">
<a class="btn btn-soft-danger float-end disabled ms-1" href="#" onclick="deleteMultipleScan()" id="delete_multiple_button">Delete Multiple Scans</a>
<a class="btn btn-soft-danger float-end disabled ms-1 mt-1" href="#" onclick="deleteMultipleScan()" id="delete_multiple_button">Delete Multiple Scans</a>
<a class="btn btn-soft-danger float-end disabled ms-1 mt-1" href="#" onclick="stopMultipleScan()" id="stop_multiple_button">Stop Multiple Scans</a>
</div>
{% endif %}
</div>
</div>
</div>
Expand Down Expand Up @@ -435,17 +438,21 @@ <h4 class="modal-title" id="myCenterModalLabel">Download Report</h4>
function toggleMultipleTargetButton() {
if (checkedCount() > 0) {
$("#delete_multiple_button").removeClass("disabled");
$("#stop_multiple_button").removeClass("disabled");
} else {
$("#delete_multiple_button").addClass("disabled");
$("#stop_multiple_button").addClass("disabled");
}
}

function mainCheckBoxSelected(checkbox) {
if (checkbox.checked) {
$("#delete_multiple_button").removeClass("disabled");
$("#stop_multiple_button").removeClass("disabled");
$(".targets_checkbox").prop('checked', true);
} else {
$("#delete_multiple_button").addClass("disabled");
$("#stop_multiple_button").addClass("disabled");
$(".targets_checkbox").prop('checked', false);
}
}
Expand All @@ -454,7 +461,7 @@ <h4 class="modal-title" id="myCenterModalLabel">Download Report</h4>
if (!checkedCount()) {
swal({
title: '',
text: "Oops! No targets has been selected!",
text: "Oops! You haven't selected any scan to delete.",
type: 'error',
padding: '2em'
})
Expand All @@ -477,6 +484,81 @@ <h4 class="modal-title" id="myCenterModalLabel">Download Report</h4>
}
}

function stopMultipleScan() {
if (!checkedCount()) {
swal({
title: '',
text: "Oops! You haven't selected any scans to stop.",
type: 'error',
padding: '2em'
})
} else {
// atleast one target is selected
Swal.fire({
title: 'Are you sure you want to stop ' + checkedCount() + ' Scans?',
text: "This action is irreversible.\nThis will stop all the selected scans if they are running.",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#d33',
cancelButtonColor: '#3085d6',
confirmButtonText: 'Stop',
cancelButtonText: 'Cancel',
showLoaderOnConfirm: true,
preConfirm: function() {
var selected_scan_ids = [];
$('.targets_checkbox:checked').each(function() {
selected_scan_ids.push($(this).val());
});
data = {
'scan_ids': selected_scan_ids
}
fetch('/api/action/stop/scan/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': getCookie('csrftoken')
},
body: JSON.stringify(data)
}).then(function(response) {
if (response.ok) {
return response.json();
}
throw new Error('Network response was not ok.');
}).then(function(data) {
if (data['status']) {
Swal.fire({
title: 'Success',
text: data['message'],
icon: 'success',
showConfirmButton: false,
timer: 1500
});
setTimeout(function() {
location.reload();
}, 1500);
} else {
Swal.fire({
title: 'Error',
text: data['message'],
icon: 'error',
showConfirmButton: false,
timer: 1500
});
}
}).catch(function(error) {
Swal.fire({
title: 'Error',
text: 'An error occurred while stopping the scans',
icon: 'error',
showConfirmButton: false,
timer: 1500
});
});
}
});
}
}

// select option listener for report_type_select
var report_type = document.getElementById("report_type_select");
report_type.addEventListener("change", function() {
Expand Down
84 changes: 83 additions & 1 deletion web/startScan/templates/startScan/subscan_history.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,10 @@ <h4 class="headline-title">Filters</h4>
<a href="#" class="dropdown-ite text-primary float-end" id="resetFilters">Reset Filters</a>
</div>
</div>
{% if user|can:'modify_scan_results' %}
{% if user|can:'initiate_scans_subscans' %}
<div class="col-xl-6 col-lg-6 col-md-6 col-sm-12 col-12">
<a class="btn btn-soft-danger float-end disabled ms-1" href="#" onclick="deleteMultipleSubScan()" id="delete_multiple_button">Delete Multiple SubScans</a>
<a class="btn btn-soft-danger float-end disabled ms-1" href="#" onclick="stopMultipleSubScan()" id="stop_multiple_button">Stop Multiple SubScans</a>
</div>
{% endif %}
</div>
Expand Down Expand Up @@ -353,17 +354,21 @@ <h4 class="headline-title">Filters</h4>
function toggleMultipleTargetButton() {
if (checkedCount() > 0) {
$("#delete_multiple_button").removeClass("disabled");
$("#stop_multiple_button").removeClass("disabled");
} else {
$("#delete_multiple_button").addClass("disabled");
$("#stop_multiple_button").addClass("disabled");
}
}

function mainCheckBoxSelected(checkbox) {
if (checkbox.checked) {
$("#delete_multiple_button").removeClass("disabled");
$("#stop_multiple_button").removeClass("disabled");
$(".targets_checkbox").prop('checked', true);
} else {
$("#delete_multiple_button").addClass("disabled");
$("#stop_multiple_button").addClass("disabled");
$(".targets_checkbox").prop('checked', false);
}
}
Expand Down Expand Up @@ -423,5 +428,82 @@ <h4 class="headline-title">Filters</h4>
}])
}
}


function stopMultipleSubScan() {
if (!checkedCount()) {
swal({
title: '',
text: "Oops! You haven't selected any subscans to stop.",
type: 'error',
padding: '2em'
})
} else {
// atleast one target is selected
Swal.fire({
title: 'Are you sure you want to stop ' + checkedCount() + ' SubScans?',
text: "This action is irreversible.\nThis will stop all the selected subscans if they are running.",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#d33',
cancelButtonColor: '#3085d6',
confirmButtonText: 'Stop',
cancelButtonText: 'Cancel',
showLoaderOnConfirm: true,
preConfirm: function() {
var selected_subscan_ids = [];
$('.targets_checkbox:checked').each(function() {
selected_subscan_ids.push($(this).val());
});
data = {
'subscan_ids': selected_subscan_ids
}
fetch('/api/action/stop/scan/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': getCookie('csrftoken')
},
body: JSON.stringify(data)
}).then(function(response) {
if (response.ok) {
return response.json();
}
throw new Error('Network response was not ok.');
}).then(function(data) {
if (data['status']) {
Swal.fire({
title: 'Success',
text: data['message'],
icon: 'success',
showConfirmButton: false,
timer: 1500
});
setTimeout(function() {
location.reload();
}, 1500);
} else {
Swal.fire({
title: 'Error',
text: data['message'],
icon: 'error',
showConfirmButton: false,
timer: 1500
});
}
}).catch(function(error) {
Swal.fire({
title: 'Error',
text: 'An error occurred while stopping the subscans',
icon: 'error',
showConfirmButton: false,
timer: 1500
});
});
}
});
}
}

</script>
{% endblock page_level_script %}
Loading

0 comments on commit db0348c

Please sign in to comment.