Skip to content

Commit

Permalink
add/remove incident handlers #14
Browse files Browse the repository at this point in the history
  • Loading branch information
zeroq committed May 5, 2019
1 parent a571aea commit 22abb4c
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 17 deletions.
1 change: 1 addition & 0 deletions kraut_api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
# incident
url(r'^incident/contacts/$', views.contact_list),
url(r'^incident/handlers/$', views.handler_list),
url(r'^incident/(?P<incident_id>[0-9]+)/handlers/$', views.handler_list_incident),
url(r'^incidents/$', views.incident_list),
# ttp
url(r'^ttps/$', views.ttp_list),
Expand Down
62 changes: 57 additions & 5 deletions kraut_api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1953,6 +1953,58 @@ def object_domain_list(request, format=None):

################### INCIDENT HANDLER #####################

@api_view(['GET'])
@authentication_classes((SessionAuthentication, ))
@permission_classes((IsAuthenticated,))
def handler_list_incident(request, incident_id, format=None):
if request.method == 'GET':
try:
inc = Incident.objects.get(id=incident_id)
except Exception as e:
print(e)
return HttpResponse(status=status.HTTP_400_BAD_REQUEST)
paginator = CustomPaginator()
max_items = 10
page = request.query_params.get('page')
if request.query_params:
# number of items to retrieve
if 'length' in request.query_params:
max_items = int(request.query_params['length'])
# page to show
if 'start' in request.query_params:
page = int(int(request.query_params['start'])/int(max_items))+1
# order
if 'order[0][column]' in request.query_params and 'order[0][dir]' in request.query_params:
order_by_column = request.query_params['columns['+str(request.query_params['order[0][column]'])+'][data]']
if request.query_params['order[0][dir]'] == 'desc':
order_direction = '-'
else:
order_direction = ''
else:
order_by_column = 'lastname'
order_direction = '-'
# search
if 'search[value]' in request.query_params:
search_value = request.query_params['search[value]']
else:
search_value = None
else:
order_by_column = 'lastname'
order_direction = '-'
search_value = None
# construct queryset
queryset = Handler.objects.exclude(id__in=inc.incident_handler.all()).order_by('%s%s' % (order_direction, order_by_column))
if search_value:
queryset = queryset.filter(
Q(firstname__istartswith=search_value)|
Q(lastname__istartswith=search_value)
)
handler = paginator.paginate_queryset(queryset, request)
serializer_context = {'request': request}
serializer = HandlerSerializer(instance=handler, context=serializer_context, many=True)
return paginator.get_paginated_response(serializer.data)
return HttpResponse(status=status.HTTP_400_BAD_REQUEST)

@api_view(['GET'])
@authentication_classes((SessionAuthentication, ))
@permission_classes((IsAuthenticated,))
Expand Down Expand Up @@ -1998,7 +2050,7 @@ def handler_list(request, format=None):
serializer_context = {'request': request}
serializer = HandlerSerializer(instance=handler, context=serializer_context, many=True)
return paginator.get_paginated_response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
return HttpResponse(status=status.HTTP_400_BAD_REQUEST)


################### INCIDENT CONTACTS #####################
Expand Down Expand Up @@ -2048,7 +2100,7 @@ def contact_list(request, format=None):
serializer_context = {'request': request}
serializer = ContactSerializer(instance=handler, context=serializer_context, many=True)
return paginator.get_paginated_response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
return HttpResponse(status=status.HTTP_400_BAD_REQUEST)

################### INCIDENTS #####################

Expand Down Expand Up @@ -2099,7 +2151,7 @@ def incident_list(request, format=None):
serializer_context = {'request': request}
serializer = IncidentSerializer(instance=incident, context=serializer_context, many=True)
return paginator.get_paginated_response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
return HttpResponse(status=status.HTTP_400_BAD_REQUEST)

################### SHARING #####################

Expand Down Expand Up @@ -2141,7 +2193,7 @@ def taxii_server_list(request, format=None):
serializer_context = {'request': request}
serializer = ServersSerializer(instance=servers, context=serializer_context, many=True)
return paginator.get_paginated_response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
return HttpResponse(status=status.HTTP_400_BAD_REQUEST)

@api_view(['GET'])
@authentication_classes((SessionAuthentication, ))
Expand Down Expand Up @@ -2180,7 +2232,7 @@ def taxii_collection_list(request, format=None):
serializer_context = {'request': request}
serializer = CollectionSerializer(instance=collections, context=serializer_context, many=True)
return paginator.get_paginated_response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
return HttpResponse(status=status.HTTP_400_BAD_REQUEST)


@api_view(['POST'])
Expand Down
78 changes: 66 additions & 12 deletions kraut_incident/templates/kraut_incident/incident_details.html
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,15 @@ <h3 class="panel-title">{{ incident.title }}<i id="toggle-commentsidebar" class=
</div>
{% endspaceless %}

<div class="pull-right">
<a class="btn btn-primary btn-sm" el="tooltip" data-placement="top" data-original-title="View" href="#" data-toggle="modal" data-target="#addIHModal" data-objectid="{{ incident.id }}">
<i class="fa fa-plus-circle fa-sm"></i> Add Incident Handler
</a>
<a class="btn btn-primary btn-sm" href="{% url 'incidents:add_task' incident_id=incident.id %}"><i class="fa fa-plus-circle fa-sm"></i> Add Incident Contact</a>
<a class="btn btn-primary btn-sm" href="{% url 'incidents:add_task' incident_id=incident.id %}"><i class="fa fa-plus-circle fa-sm"></i> Add Task</a>
<a class="btn btn-primary btn-sm" href="{% url 'incidents:add_task' incident_id=incident.id %}"><i class="fa fa-plus-circle fa-sm"></i> Add Asset</a>
</div><br/><br/>

<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">Incident Information
Expand Down Expand Up @@ -178,14 +187,15 @@ <h3 class="panel-title">Incident Information
<br/>
<table id="handler_table" class="table table-condensed" style="font-size: 0.9em;">
<thead>
<tr><th>Name</th><th>E-Mail</th><th>Phone</th></tr>
<tr><th>Name</th><th>E-Mail</th><th>Phone</th><th></th></tr>
</thead>
<tbody>
{% for ha in incident.incident_handler.all %}
<tr>
<td>{{ ha.firstname }} {{ ha.lastname }}</td>
<td>{{ ha.email }}</td>
<td>{{ ha.phone }}</td>
<td><a href="{% url 'incidents:remove_handler_incident' incident_id=incident_id handler_id=ha.id %}"><i data-toggle="tooltip" data-placement="left" data-original-title="remove incident handler" class="fa fa-remove pull-right"></i></a></td>
</tr>
{% endfor %}
</tbody>
Expand All @@ -196,14 +206,15 @@ <h3 class="panel-title">Incident Information
<br/>
<table id="contact_table" class="table table-condensed" style="font-size: 0.9em;">
<thead>
<tr><th>Name</th><th>E-Mail</th><th>Phone</th></tr>
<tr><th>Name</th><th>E-Mail</th><th>Phone</th><th></th></tr>
</thead>
<tbody>
{% for co in incident.contacts.all %}
<tr>
<td>{{ co.firstname }} {{ co.lastname }}</td>
<td>{{ co.email }}</td>
<td>{{ co.phone }}</td>
<td><a href="#"><i data-toggle="tooltip" data-placement="left" data-original-title="remove incident contact" class="fa fa-remove pull-right"></i></a></td>
</tr>
{% endfor %}
</tbody>
Expand Down Expand Up @@ -257,32 +268,30 @@ <h3 class="panel-title"><i class="fa fa-comment-o"></i>&nbsp;Comments</h3>
</div>
{% endif %}

<!-- Modal to add an existing threat actor to the package -->
<div class="modal bs-example-modal-lg" id="addTAModal" tabindex="-1" role="dialog" aria-labelledby="addTALabel" aria-hidden="true">
<!-- Modal to add an existing incident handler to the incident -->
<div class="modal bs-example-modal-lg" id="addIHModal" tabindex="-1" role="dialog" aria-labelledby="addIHLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="addTALabel">Add Threat Actor</h4>
<h4 class="modal-title" id="addIHLabel">Add Incident Handler</h4>
</div>
<form method="post" action="{% url 'incidents:add_handler_incident' incident_id=incident_id %}" id="post-handler">
<div class="modal-body">
<table id="ta_table" class="table table-condensed table-striped table-bordered" style="font-size: 0.9em;">
{% csrf_token %}
<table id="ih_table" class="table table-condensed table-striped table-bordered" style="font-size: 0.9em;">
<thead>
<tr>
<th>Name</th>
<th>Add</th><th>Lastname</th><th>Firstname</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
</tr>
</tbody>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary">Save</button>
</div>
</form>
</div>
</div>
</div>
Expand Down Expand Up @@ -409,6 +418,39 @@ <h4 class="modal-title" id="addOBLabel">Add Observable</h4>

{% block javascript%}
<script type="text/javascript" language="javascript" class="init">
$(document).ready( function () {
var cTable = $('#ih_table').DataTable({
processing: true,
info: false,
bLengthChange: false,
serverSide: true,
oLanguage: {
sProcessing: "<img src='{% static 'images/loading.gif' %}'>",
},
order: [[ 1, "desc" ]],
ajax: {
processing: true,
url: "/api/incident/{{ incident.id }}/handlers/",
dataSrc: "results",
type: "GET",
dataType: "json"
},
columns: [
{
"data": 'id',
'sName': 'operations',
'bSortable': false,
'aTargets': [ 1 ],
"mRender": function (data, type, full) {
return '<div class="checkbox"><input type="checkbox" id="HandlerCheckBox_'+data+'" form="post-handler" value="'+data+'"></div>'
}
},
{'data': 'lastname', 'sName': 'lastname', 'aTargets': [ 2 ]},
{'data': 'firstname', 'sName': 'firstname', 'aTargets': [ 3 ]},
],
});
});


$(function () {
$('[data-toggle="popover"]').popover()
Expand Down Expand Up @@ -447,5 +489,17 @@ <h4 class="modal-title" id="addOBLabel">Add Observable</h4>
}
});
});

$('#post-handler').submit(function(){
$('input[type=checkbox]').each(function () {
if (this.checked) {
$('<input />').attr('type', 'hidden')
.attr('name', this.id)
.attr('value', this.value)
.appendTo('#post-handler');
}
});
});

</script>
{% endblock%}
3 changes: 3 additions & 0 deletions kraut_incident/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
url(r'^incident/(?P<incident_id>\d+)/delete/$', views.delete_incident, name='delete_incident'),
url(r'^incident/(?P<incident_id>\d+)/view/$', views.view_incident, name='view_incident'),
url(r'^incident/(?P<incident_id>\d+)/update/header/$', views.update_incident_header, name='update_incident_header'),
url(r'^incident/(?P<incident_id>\d+)/add/task/$', views.add_task, name='add_task'),
url(r'^incident/(?P<incident_id>\d+)/add/handler/$', views.add_handler_incident, name='add_handler_incident'),
url(r'^incident/(?P<incident_id>\d+)/remove/handler/(?P<handler_id>\d+)/$', views.remove_handler_incident, name='remove_handler_incident'),
url(r'^incident/(?P<incident_id>\d+)/add/comment/$', views.comment_incident, name='comment_incident'),
url(r'^incident/(?P<incident_id>\d+)/del/comment/(?P<comment_id>\d+)/$', views.delete_comment_incident, name='delete_comment_incident'),
url(r'^create_contact/$', views.create_contact, name='create_contact'),
Expand Down
47 changes: 47 additions & 0 deletions kraut_incident/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,53 @@ def list_incidents(request):
context = {}
return render(request, 'kraut_incident/incident_list.html', context)

@login_required
def remove_handler_incident(request, incident_id, handler_id):
"""remove handler from incident
"""
context = {}
try:
inc = Incident.objects.get(id=incident_id)
except Incident.DoesNotExist:
messages.error(request, 'The requested incident does not exist!')
return render(request, 'kraut_incident/incident_list.html', context)
try:
handler = Handler.objects.get(id=handler_id)
except Handler.DoesNotExist:
messages.error(request, 'The requested incident handler does not exist!')
return render(request, 'kraut_incident/incident_list.html', context)
inc.incident_handler.remove(handler)
inc.save()
return HttpResponseRedirect(reverse("incidents:view_incident", kwargs={'incident_id': incident_id}))

@login_required
def add_handler_incident(request, incident_id):
"""add incident handler to incident
"""
if request.method == 'POST':
try:
inc = Incident.objects.get(id=incident_id)
except Incident.DoesNotExist:
messages.error(request, 'The requested incident does not exist!')
return render(request, 'kraut_incident/incident_list.html', context)
handler_dict = slicedict(request.POST, 'HandlerCheckBox')
for key in handler_dict:
handler_id = int(handler_dict[key])
try:
ih = Handler.objects.get(id=handler_id)
inc.incident_handler.add(ih)
except Handler.DoesNotExist:
messages.error(request, 'Failed getting incident handler with ID: %s' % (handler_id))
return HttpResponseRedirect(reverse("incidents:view_incident", kwargs={'incident_id': incident_id}))
inc.save()
return HttpResponseRedirect(reverse("incidents:view_incident", kwargs={'incident_id': incident_id}))

@login_required
def add_task(request, incident_id):
"""add task to incident
"""
return HttpResponseRedirect(reverse("incidents:view_incident", kwargs={'incident_id': incident_id}))

@login_required
def update_incident_header(request, incident_id):
"""Update incident header information
Expand Down

0 comments on commit 22abb4c

Please sign in to comment.