Skip to content

Commit

Permalink
added template tasks, adding of tasks, and incident contacts #14
Browse files Browse the repository at this point in the history
  • Loading branch information
zeroq committed Jun 12, 2019
1 parent a2e2fe6 commit f2f30ec
Show file tree
Hide file tree
Showing 9 changed files with 232 additions and 17 deletions.
7 changes: 6 additions & 1 deletion kraut_api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from kraut_parser.models import MalwareInstance, AttackPattern
from kraut_intel.utils import get_icon_for_namespace
from kraut_intel.models import PackageComment, NamespaceIcon, ThreatActorComment, CampaignComment, TTPComment, IndicatorComment, ObservableComment
from kraut_incident.models import Contact, Handler, Incident
from kraut_incident.models import Contact, Handler, Incident, TemplateTask
from kraut_sharing.models import TAXII_Remote_Server, TAXII_Remote_Collection

import datetime
Expand Down Expand Up @@ -319,6 +319,11 @@ class Meta:

################### INCIDENT #####################

class TemplateTaskSerializer(serializers.ModelSerializer):
class Meta:
model = TemplateTask
fields = ('id', 'name', 'description')

class IncidentSerializer(serializers.ModelSerializer):
status = serializers.StringRelatedField()
category = serializers.StringRelatedField()
Expand Down
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/tasks/$', views.template_tasks),
url(r'^incident/(?P<incident_id>[0-9]+)/handlers/$', views.handler_list_incident),
url(r'^incident/(?P<incident_id>[0-9]+)/contacts/$', views.contact_list_incident),
url(r'^incidents/$', views.incident_list),
Expand Down
51 changes: 49 additions & 2 deletions kraut_api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
# Package
from kraut_api.serializers import PackageSerializer, PackSerializer, PackageCommentSerializer
# Incident
from kraut_api.serializers import IncidentSerializer, ContactSerializer, HandlerSerializer
from kraut_api.serializers import IncidentSerializer, ContactSerializer, HandlerSerializer, TemplateTaskSerializer
# Objects
from kraut_api.serializers import AddressObjectSerializer, URIObjectSerializer, FileObjectSerializer
# TTPs
Expand All @@ -34,7 +34,7 @@
from kraut_api.serializers import CollectionSerializer, ServersSerializer
#
from kraut_parser.utils import get_object_for_observable, get_related_objects_for_object
from kraut_incident.models import Contact, Handler, Incident
from kraut_incident.models import Contact, Handler, Incident, TemplateTask
from kraut_intel.models import PackageComment, NamespaceIcon, ThreatActorComment, CampaignComment, TTPComment, IndicatorComment, ObservableComment
from kraut_sharing.models import TAXII_Remote_Server, TAXII_Remote_Collection
from kraut_sharing.forms import DiscoveryForm
Expand Down Expand Up @@ -2051,6 +2051,53 @@ def handler_list(request, format=None):
return paginator.get_paginated_response(serializer.data)
return HttpResponse(status=status.HTTP_400_BAD_REQUEST)

@api_view(['GET'])
@authentication_classes((SessionAuthentication, ))
@permission_classes((IsAuthenticated,))
def template_tasks(request, format=None):
if request.method == 'GET':
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 = 'name'
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 = 'name'
order_direction = '-'
search_value = None
# construct queryset
queryset = TemplateTask.objects.all().order_by('%s%s' % (order_direction, order_by_column))
if search_value:
queryset = queryset.filter(
Q(name__icontains=search_value)
)
handler = paginator.paginate_queryset(queryset, request)
serializer_context = {'request': request}
serializer = TemplateTaskSerializer(instance=handler, context=serializer_context, many=True)
return paginator.get_paginated_response(serializer.data)
return HttpResponse(status=status.HTTP_400_BAD_REQUEST)



################### INCIDENT CONTACTS #####################

Expand Down
4 changes: 3 additions & 1 deletion kraut_incident/admin.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4

from django.contrib import admin
from kraut_incident.models import Asset, Incident, Incident_Category, Incident_Status, Contact
from kraut_incident.models import Asset, Incident, Incident_Category, Incident_Status, Contact, Task, TemplateTask

# Register your models here.

Expand All @@ -10,3 +10,5 @@
admin.site.register(Incident_Category)
admin.site.register(Incident_Status)
admin.site.register(Contact)
admin.site.register(Task)
admin.site.register(TemplateTask)
24 changes: 24 additions & 0 deletions kraut_incident/fixtures/initial_data.json
Original file line number Diff line number Diff line change
Expand Up @@ -126,5 +126,29 @@
"name": "Phishing/Scam/Spam",
"description": "This category includes all incidents related to phishing, scam, or spam emails."
}
},
{
"model": "kraut_incident.templatetask",
"pk": 1,
"fields": {
"name": "Reinstall System(s)",
"description": "Initiate reinstallation of affected assets (e.g. because of compromise)."
}
},
{
"model": "kraut_incident.templatetask",
"pk": 2,
"fields": {
"name": "Forensic Copy",
"description": "Create forensically sound images of affected assets."
}
},
{
"model": "kraut_incident.templatetask",
"pk": 3,
"fields": {
"name": "Collect Logfiles",
"description": "Collect specific log files from affected assets."
}
}
]
6 changes: 6 additions & 0 deletions kraut_incident/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ class Contact(models.Model):
class Meta:
unique_together = (("firstname", "lastname", "email"),)

class TemplateTask(models.Model):
"""Describe a template for a task to attach to an incident
"""
name = models.CharField(max_length=255, default="Template Task")
description = models.TextField(null=True, blank=True, default="Task Description")

class Task(models.Model):
"""Describe a task to be performed
"""
Expand Down
101 changes: 95 additions & 6 deletions kraut_incident/templates/kraut_incident/incident_details.html
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,9 @@ <h3 class="panel-title">{{ incident.title }}<i id="toggle-commentsidebar" class=
<a class="btn btn-primary btn-sm" el="tooltip" data-placement="top" data-original-title="View" href="#" data-toggle="modal" data-target="#addCOModal" data-objectid="{{ 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" el="tooltip" data-placement="top" data-original-title="View" href="#" data-toggle="modal" data-target="#addtaskModal" data-objectid="{{ 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/>

Expand Down Expand Up @@ -227,13 +229,16 @@ <h3 class="panel-title">Incident Information
<br/>
<table id="task_table" class="table table-condensed" style="font-size: 0.9em;">
<thead>
<tr><th>Name</th><th>Short Description</th></tr>
<tr><th>Name</th><th>Status</th><th>Short Description</th></tr>
</thead>
<tbody>
{% for t in incident.tasks.all %}
<tr>
<td></td>
<td></td>
<td>{{ t.name }}</td>
<td>{{ t.get_status_display }}</td>
<td>{{ t.description }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
Expand Down Expand Up @@ -303,9 +308,11 @@ <h4 class="modal-title" id="addIHLabel">Add Incident Handler</h4>
<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="addCALabel">Add Incident Contact</h4>
<h4 class="modal-title" id="addCOLabel">Add Incident Contact</h4>
</div>
<form method="post" action="{% url 'incidents:add_contact_incident' incident_id=incident_id %}" id="post-contact">
<div class="modal-body">
{% csrf_token %}
<table id="co_table" class="table table-condensed table-striped table-bordered" style="font-size: 0.9em;">
<thead>
<tr>
Expand All @@ -318,6 +325,34 @@ <h4 class="modal-title" id="addCALabel">Add Incident Contact</h4>
<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>
<!-- Modal to add a task to the incident -->
<div class="modal bs-example-modal-lg" id="addtaskModal" tabindex="-1" role="dialog" aria-labelledby="addtaskLabel" 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="addtaskLabel">Add Incident Task</h4>
</div>
<form method="post" action="{% url 'incidents:add_task' incident_id=incident_id %}" id="post-task">
<div class="modal-body">
{% csrf_token %}
<table id="ttask_table" class="table table-condensed table-striped table-bordered" style="font-size: 0.9em;">
<thead>
<tr>
<th>Add</th><th>Name</th><th>Description</th>
</tr>
</thead>
</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 @@ -448,6 +483,39 @@ <h4 class="modal-title" id="addOBLabel">Add Observable</h4>
});
});

$(document).ready( function () {
var ttTable = $('#ttask_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/tasks/",
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="TaskCheckBox_'+data+'" form="post-task" value="'+data+'"></div>'
}
},
{'data': 'name', 'sName': 'Name', 'aTargets': [ 2 ]},
{'data': 'description', 'sName': 'Description', 'aTargets': [ 3 ]},
],
});
});

$(document).ready( function () {
var cTable = $('#co_table').DataTable({
processing: true,
Expand All @@ -472,7 +540,7 @@ <h4 class="modal-title" id="addOBLabel">Add Observable</h4>
'bSortable': false,
'aTargets': [ 1 ],
"mRender": function (data, type, full) {
return '<div class="checkbox"><input type="checkbox" id="ContactCheckBox_'+data+'" form="post-incident" value="'+data+'"></div>'
return '<div class="checkbox"><input type="checkbox" id="ContactCheckBox_'+data+'" form="post-contact" value="'+data+'"></div>'
}
},
{'data': 'lastname', 'sName': 'lastname', 'aTargets': [ 2 ]},
Expand Down Expand Up @@ -530,5 +598,26 @@ <h4 class="modal-title" id="addOBLabel">Add Observable</h4>
});
});

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

$('#post-contact').submit(function(){
$('input[type=checkbox]').each(function () {
if (this.checked) {
$('<input />').attr('type', 'hidden')
.attr('name', this.id)
.attr('value', this.value)
.appendTo('#post-contact');
}
});
});
</script>
{% endblock%}
1 change: 1 addition & 0 deletions kraut_incident/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
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+)/add/contact/$', views.add_contact_incident, name='add_contact_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+)/remove/contact/(?P<contact_id>\d+)/$', views.remove_contact_incident, name='remove_contact_incident'),
url(r'^incident/(?P<incident_id>\d+)/add/comment/$', views.comment_incident, name='comment_incident'),
Expand Down
Loading

0 comments on commit f2f30ec

Please sign in to comment.