class Package(models.Model):
    name = models.CharField(max_length=255)
    creation_time = models.DateTimeField(auto_now_add=True)
    last_modified = models.DateTimeField(auto_now=True)
    description = models.TextField(null=True, blank=True)
    short_description = models.CharField(max_length=255, null=True, blank=True)
    namespace = models.ManyToManyField('Namespace', blank=True)
    version = models.CharField(max_length=255)
    package_id = models.CharField(max_length=255)
    source = models.CharField(max_length=255)
    produced_time = models.DateTimeField(null=True, blank=True)
    threat_actors = models.ManyToManyField('ThreatActor', blank=True)
    campaigns = models.ManyToManyField('Campaign', blank=True)
    indicators = models.ManyToManyField('Indicator', blank=True)
    observables = models.ManyToManyField('Observable', blank=True)
    ttps = models.ManyToManyField('TTP', blank=True)

    def __unicode__(self):
        return u"%s" % (self.name) class Observable(models.Model):
    name = models.CharField(max_length=255)
    creation_time = models.DateTimeField(auto_now_add=True)
    last_modified = models.DateTimeField(auto_now=True)
    description = models.TextField(null=True, blank=True)
    short_description = models.CharField(max_length=255, null=True, blank=True)
    namespace = models.ManyToManyField('Namespace', blank=True)
    indicators = models.ManyToManyField(Indicator, blank=True)
    compositions = models.ManyToManyField(ObservableComposition, blank=True)
    observable_type = models.CharField(max_length=255, null=True, blank=True)
    observable_id = models.CharField(max_length=255, unique=True)

    def __unicode__(self):
        return u"%s" % (self.name) class Related_Object(models.Model):
    relationship = models.CharField(max_length=255, default='contains')
    object_one_id = models.IntegerField()
    object_one_type = models.CharField(max_length=255)
    object_two_id = models.IntegerField()
    object_two_type = models.CharField(max_length=255)

    def __unicode__(self):
        return u"%s:%s -> %s:%s" % (self.object_one_id, self.object_one_type, self.object_two_id, self.object_two_type)

    class Meta:
        unique_together = (("relationship", "object_one_id", "object_two_id", "object_one_type", "object_two_type"),)
        index_together = (("object_one_id", "object_one_type"), ("object_two_id", "object_two_type")) class Indicator(models.Model):
    name = models.CharField(max_length=255)
    creation_time = models.DateTimeField(auto_now_add=True)
    last_modified = models.DateTimeField(auto_now=True)
    description = models.TextField(null=True, blank=True)
    short_description = models.CharField(max_length=255, null=True, blank=True)
    indicator_id = models.CharField(max_length=255)
    namespace = models.ManyToManyField('Namespace', blank=True)
    indicator_types = models.ManyToManyField(Indicator_Type, blank=True)
    confidence = models.ManyToManyField(Confidence, blank=True)
    related_indicators = models.ManyToManyField('self', blank=True)
    indicator_composition_operator = models.CharField(max_length=3, default="OR")
    ttps = models.ManyToManyField('TTP', blank=True)
    produced_time = models.DateTimeField(null=True, blank=True)
    kill_chain_phases = models.ManyToManyField(Indicator_Kill_Chain_Phase, blank=True)

    def __unicode__(self):
        return u"%s" % (self.name) class Campaign(models.Model):
    name = models.CharField(max_length=255)
    creation_time = models.DateTimeField(auto_now_add=True)
    last_modified = models.DateTimeField(auto_now=True)
    description = models.TextField(null=True, blank=True)
    short_description = models.CharField(max_length=255, null=True, blank=True)
    namespace = models.ManyToManyField('Namespace', blank=True)
    status = models.CharField(max_length=255, default='Ongoing')
    campaign_id = models.CharField(max_length=255)
    confidence = models.ManyToManyField(Confidence, blank=True)
    related_indicators = models.ManyToManyField('Indicator', blank=True)
    related_ttps = models.ManyToManyField(TTP, through='RelationCampaignTTP', symmetrical=False, related_name='ttp_related_to_campaign', blank=True)
    associated_campaigns = models.ManyToManyField('self', blank=True)

    def add_related_ttp(self, ttp, relationship):
        rel_ttp, rel_ttp_created = RelationCampaignTTP.objects.get_or_create(
            campaign=self,
            ttp=ttp,
            relationship=relationship
        )
        return rel_ttp

    def __unicode__(self):
        return u"%s" % (self.name) class ThreatActor(models.Model):
    name = models.CharField(max_length=255)
    creation_time = models.DateTimeField(auto_now_add=True)
    last_modified = models.DateTimeField(auto_now=True)
    description = models.TextField(null=True, blank=True)
    short_description = models.CharField(max_length=255, null=True, blank=True)
    namespace = models.ManyToManyField('Namespace', blank=True)
    campaigns = models.ManyToManyField(Campaign, blank=True)
    associated_threat_actors = models.ManyToManyField('self', blank=True)
    threat_actor_id = models.CharField(max_length=255)
    observed_ttps = models.ManyToManyField(TTP, through='ObservedTTP', symmetrical=False, related_name='ttp_observed_at_ta', blank=True)

    def add_observed_ttp(self, ttp, relationship):
        obs_ttp, obs_ttp_created = ObservedTTP.objects.get_or_create(
            ta=self,
            ttp=ttp,
            relationship=relationship
        )
        return obs_ttp

    def __unicode__(self):
        return u"%s" % (self.name) class TA_Types(models.Model):
    ta_type = models.CharField(max_length=255)
    actor = models.ForeignKey(ThreatActor, on_delete=models.CASCADE)

    def __unicode__(self):
        return u"%s -> %s" % (self.actor.name, self.ta_type)

    class Meta:
        unique_together = (("ta_type", "actor"),) class TA_Roles(models.Model):
    role = models.CharField(max_length=255)
    actor = models.ForeignKey(ThreatActor, on_delete=models.CASCADE)

    def __unicode__(self):
        return u"%s" % (self.role)

    class Meta:
        unique_together = (("role", "actor"),) class TA_Alias(models.Model):
    alias = models.CharField(max_length=255)
    namespace = models.ManyToManyField('Namespace', blank=True)
    actor = models.ForeignKey(ThreatActor, on_delete=models.CASCADE)
    alias_type = models.CharField(max_length=255, default='UnofficialName')

    def __unicode__(self):
        return u"%s" % (self.alias)

    class Meta:
        unique_together = (("alias", "actor"),) class TTP(models.Model):
    """ Tools, Tactics, and Procedures
    """
    name = models.CharField(max_length=255)
    creation_time = models.DateTimeField(auto_now_add=True)
    last_modified = models.DateTimeField(auto_now=True)
    description = models.TextField(null=True, blank=True)
    short_description = models.CharField(max_length=255, null=True, blank=True)
    namespace = models.ManyToManyField('Namespace', blank=True)
    ttp_id = models.CharField(max_length=255)
    related_ttps = models.ManyToManyField('self', through='RelatedTTP', symmetrical=False, related_name='ttp_related_to_ttp', blank=True)

    def add_related_ttp(self, ttp, relationship):
        rel_ttp, rel_ttp_created = RelatedTTP.objects.get_or_create(from_ttp=self, to_ttp=ttp, relationship=relationship)
        return rel_ttp

    def __unicode__(self):
        return u"%s" % (self.name) class MalwareInstance(models.Model):
    ttp_ref = models.ForeignKey(TTP, on_delete=models.CASCADE)
    name = models.CharField(max_length=255)
    creation_time = models.DateTimeField(auto_now_add=True)
    last_modified = models.DateTimeField(auto_now=True)
    description = models.TextField(null=True, blank=True)
    short_description = models.CharField(max_length=255, null=True, blank=True)

    def __unicode__(self):
        return u"%s" % (self.name) class AttackPattern(models.Model):
    ttp_ref = models.ForeignKey(TTP, on_delete=models.CASCADE)
    name = models.CharField(max_length=255)
    creation_time = models.DateTimeField(auto_now_add=True)
    last_modified = models.DateTimeField(auto_now=True)
    description = models.TextField(null=True, blank=True)
    short_description = models.CharField(max_length=255, null=True, blank=True)
    capec_id = models.CharField(max_length=255) class Namespace(models.Model):
    namespace = models.CharField(max_length=255, default='nospace', unique=True)
    description = models.TextField(null=True, blank=True)

    def __unicode__(self):
        return u"%s" % (self.namespace)

    class Meta:
        ordering = ['namespace'] class Confidence(models.Model):
    value = models.CharField(max_length=255)
    description = models.TextField(null=True, blank=True)

    def __unicode__(self):
        return u"%s" % (self.value) def get_object_for_observable(observable_type, observable_object=None, object_id=None, no_hash=True):
    """ Return the list of objects belonging to a given observable or the object for a given id.
        The optional no_hash parameter determines if also file objects without a hash should be returned.

        TODO: support all observable types that are implemented!
    """
    return_list = []
    # create filter
    if observable_object:
        q_filter = Q(observables=observable_object)
    elif object_id:
        q_filter = Q(id=object_id)
    else:
        q_filter = Q(observables=observable_object)|Q(id=object_id)
    # check observable type and query
    if observable_type == 'FileObjectType':
        for obj in File_Object.objects.filter(q_filter):
            if no_hash:
                return_list.append(obj)
            else:
                if (obj.md5_hash and obj.md5_hash != 'No MD5') or (obj.sha256_hash and obj.sha256_hash != 'No SHA256'):
                    return_list.append(obj)
    elif observable_type == 'HTTPSessionObjectType':
        for obj in HTTPSession_Object.objects.filter(q_filter):
            return_list.append(obj)
    elif observable_type == 'URIObjectType' or observable_type == 'DomainNameObjectType':
        for obj in URI_Object.objects.filter(q_filter):
            return_list.append(obj)
    elif observable_type == 'AddressObjectType':
        for obj in Address_Object.objects.filter(q_filter):
            return_list.append(obj)
    elif observable_type == 'MutexObjectType':
        for obj in Mutex_Object.objects.filter(q_filter):
            return_list.append(obj)
    elif observable_type == 'CodeObjectType':
        for obj in Code_Object.objects.filter(q_filter):
            return_list.append(obj)
    elif observable_type == 'EmailMessageObjectType':
        for obj in EmailMessage_Object.objects.filter(q_filter):
            return_list.append(obj)
    elif observable_type == 'WindowsRegistryKeyObjectType':
        for obj in Win_Registry_Object.objects.filter(q_filter):
            return_list.append(obj)
    elif observable_type == 'DNSQueryObjectType':
        for obj in DNSQuery_Object.objects.filter(q_filter):
            return_list.append(obj)
    elif observable_type == 'WindowsDriverObjectType':
        for obj in Driver_Object.objects.filter(q_filter):
            return_list.append(obj)
    elif observable_type == 'LinkObjectType':
        for obj in Link_Object.objects.filter(q_filter):
            return_list.append(obj)
    elif observable_type == 'WindowsExecutableFileObjectType':
        for obj in WindowsExecutable_Object.objects.filter(q_filter):
            return_list.append(obj)

    return return_list def get_related_objects_for_object(object_id, object_type, quick=False):
    """ Return the list of related objects for a given object and type.
        The quick parameter will kind of normalize the return values so it can be used in the quick panel.
    """
    return_list = []
    try:
        related_objects_all = Related_Object.objects.filter(
            Q(object_one_id=object_id, object_one_type=object_type)|
            Q(object_two_id=object_id, object_two_type=object_type)
        )
    except Related_Object.DoesNotExist:
        return return_list
    for object_relation in related_objects_all:
        if object_relation.object_one_id == object_id:
            related_objects = get_object_for_observable(object_relation.object_two_type, object_id=object_relation.object_two_id)
        else:
            related_objects = get_object_for_observable(object_relation.object_one_type, object_id=object_relation.object_one_id)
        return_list.append({'objects': related_objects, 'relation': object_relation.relationship})
    return return_list def get_icon_for_namespace(namespace):
    """ Return the static path to the icon associated with given namespace
    """
    try:
        if namespace.count(':')>0:
            namespace = namespace.split(':')[0]
        icon = NamespaceIcon.objects.get(namespace=namespace)
    except Exception as e:
        return static('ns_icon/octalpus.png')
    return static('ns_icon/%s' % (icon.icon)) class PackageForm(ModelForm):
    class Meta:
        model = Package
        fields = ['name', 'description', 'short_description', 'namespace', 'version', 'package_id', 'source', 'produced_time']

    def __init__(self, *args, **kwargs):
        super(PackageForm, self).__init__(*args, **kwargs)
        self.fields['name'].widget.attrs.update({'class' : 'form-control', 'id': 'packageName'})
        self.fields['namespace'].widget.attrs.update({'class' : 'form-control', 'id': 'nameSpace'})
        self.fields['produced_time'].widget.attrs.update({'class' : 'form-control', 'id': 'producedTime'})
        self.fields['version'].widget.attrs.update({'class' : 'form-control', 'id': 'version'})
        self.fields['source'].widget.attrs.update({'class' : 'form-control', 'id': 'source'})
        self.fields['description'].widget.attrs.update({'class' : 'form-control', 'id': 'description'})
        self.fields['short_description'].widget.attrs.update({'class' : 'form-control', 'id': 'shortDescription'})
        self.fields['package_id'].widget.attrs.update({'class' : 'form-control', 'id': 'packageID'})
        self.fields['namespace'].required = True class PackageCommentForm(ModelForm):
    class Meta:
        model = PackageComment
        fields = ['ctext']

    def __init__(self, *args, **kwargs):
        super(PackageCommentForm, self).__init__(*args, **kwargs)
        self.fields['ctext'].widget.attrs.update({'class' : 'form-control', 'id': 'packageComment'}) class ActorCommentForm(ModelForm):
    class Meta:
        model = ThreatActorComment
        fields = ['ctext']

    def __init__(self, *args, **kwargs):
        super(ActorCommentForm, self).__init__(*args, **kwargs)
        self.fields['ctext'].widget.attrs.update({'class' : 'form-control', 'id': 'packageComment'}) class ActorForm(ModelForm):
    class Meta:
        model = ThreatActor
        fields = ['name', 'description', 'short_description', 'namespace', 'threat_actor_id', 'associated_threat_actors']

    def __init__(self, *args, **kwargs):
        super(ActorForm, self).__init__(*args, **kwargs)
        self.fields['name'].widget.attrs.update({'class' : 'form-control', 'id': 'packageName'})
        self.fields['namespace'].widget.attrs.update({'class' : 'form-control', 'id': 'nameSpace'})
        self.fields['description'].widget.attrs.update({'class' : 'form-control', 'id': 'description'})
        self.fields['short_description'].widget.attrs.update({'class' : 'form-control', 'id': 'shortDescription'})
        self.fields['threat_actor_id'].widget.attrs.update({'class' : 'form-control', 'id': 'packageID'})
        self.fields['associated_threat_actors'].widget.attrs.update({'class' : 'form-control', 'id': 'nameSpace'})
        self.fields['namespace'].required = True class CampaignCommentForm(ModelForm):
    class Meta:
        model = CampaignComment
        fields = ['ctext']

    def __init__(self, *args, **kwargs):
        super(CampaignCommentForm, self).__init__(*args, **kwargs)
        self.fields['ctext'].widget.attrs.update({'class' : 'form-control', 'id': 'packageComment'}) class TTPCommentForm(ModelForm):
    class Meta:
        model = TTPComment
        fields = ['ctext']

    def __init__(self, *args, **kwargs):
        super(TTPCommentForm, self).__init__(*args, **kwargs)
        self.fields['ctext'].widget.attrs.update({'class' : 'form-control', 'id': 'packageComment'}) class IndicatorCommentForm(ModelForm):
    class Meta:
        model = IndicatorComment
        fields = ['ctext']

    def __init__(self, *args, **kwargs):
        super(IndicatorCommentForm, self).__init__(*args, **kwargs)
        self.fields['ctext'].widget.attrs.update({'class' : 'form-control', 'id': 'packageComment'}) class ObservableCommentForm(ModelForm):
    class Meta:
        model = ObservableComment
        fields = ['ctext']

    def __init__(self, *args, **kwargs):
        super(ObservableCommentForm, self).__init__(*args, **kwargs)
        self.fields['ctext'].widget.attrs.update({'class' : 'form-control', 'id': 'packageComment'}) class PackageComment(models.Model):
    ctext = models.TextField()
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    creation_time = models.DateTimeField(auto_now_add=True)
    package_reference = models.ForeignKey(Package, on_delete=models.CASCADE) class ThreatActorComment(models.Model):
    ctext = models.TextField()
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    creation_time = models.DateTimeField(auto_now_add=True)
    actor_reference = models.ForeignKey(ThreatActor, on_delete=models.CASCADE) class CampaignComment(models.Model):
    ctext = models.TextField()
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    creation_time = models.DateTimeField(auto_now_add=True)
    campaign_reference = models.ForeignKey(Campaign, on_delete=models.CASCADE) class TTPComment(models.Model):
    ctext = models.TextField()
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    creation_time = models.DateTimeField(auto_now_add=True)
    ttp_reference = models.ForeignKey(TTP, on_delete=models.CASCADE) class IndicatorComment(models.Model):
    ctext = models.TextField()
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    creation_time = models.DateTimeField(auto_now_add=True)
    indicator_reference = models.ForeignKey(Indicator, on_delete=models.CASCADE) class ObservableComment(models.Model):
    ctext = models.TextField()
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    creation_time = models.DateTimeField(auto_now_add=True)
    observable_reference = models.ForeignKey(Observable, on_delete=models.CASCADE)
from django.http import HttpResponseRedirect
from django.db.models import Prefetch, Q
from django.contrib import messages
from django.shortcuts import render
from django.urls import reverse
from django.template import RequestContext
from django.utils.html import strip_tags
from django.contrib.auth.decorators import login_required
from kraut_parser.models import Package, Observable, Related_Object, Indicator, Campaign, ThreatActor, TA_Types, TA_Roles, TA_Alias, TTP, MalwareInstance
from kraut_parser.models import AttackPattern, Namespace, Confidence
from kraut_parser.utils import get_object_for_observable, get_related_objects_for_object
from kraut_intel.utils import get_icon_for_namespace
from kraut_intel.forms import PackageForm, PackageCommentForm, ActorCommentForm, ActorForm, CampaignCommentForm, TTPCommentForm, IndicatorCommentForm, ObservableCommentForm
from kraut_intel.models import PackageComment, ThreatActorComment, CampaignComment, TTPComment, IndicatorComment, ObservableComment
import datetime, uuid, argparse
# MALWARE INSTANCE VIEWS #
##########################

@login_required
def malware_instances(request):
    """ list all malware instance items
    """
    context = {}
    if hasattr(request.user.userextension, 'namespaces'):
        context['usernamespace'] = request.user.userextension.namespaces.last().namespace.split(':')[0]
        context['namespaceicon'] = get_icon_for_namespace(request.user.userextension.namespaces.last().namespace)
    else:
        context['usernamespace'] = 'nospace'
        context['namespaceicon'] = static('ns_icon/octalpus.png')
    return render(request, 'kraut_intel/mwinstances.html', context)

@login_required
def delete_malware_instance(request, mwi_id):
    """ delete a malware instance object
    """
    try:
        mwi = MalwareInstance.objects.get(pk=int(mwi_id))
    except MalwareInstance.DoesNotExist:
        messages.error(request, 'The requested Malware Instance object does not exist')
        return HttpResponseRedirect(reverse('intel:malware_instances'))
    mwi.delete()
    messages.info(request, 'The malware instance was deleted successfully!')
    return HttpResponseRedirect(reverse('intel:malware_instances'))

@login_required
def malware_instance(request, mwi_id="1"):
    """ details of a single malware instance
    """
    context = {'mwi_id': mwi_id, 'mwi': None, 'related_ttps': []}
    try:
        mwi = MalwareInstance.objects.get(pk=int(mwi_id))
    except MalwareInstance.DoesNotExist:
        messages.error(request, 'The requested Malware Instance object does not exist')
        return HttpResponseRedirect(reverse('intel:packages'))
    context['mwi'] = mwi
    context['namespace_icon'] = get_icon_for_namespace(mwi.ttp_ref.namespace.last().namespace)
    context['description'] = ' '.join(strip_tags(mwi.description).replace('\n', ' ').replace('\r', '').replace('\t', ' ').strip().split())
    return render(request, 'kraut_intel/mwinstance_details.html', context)

def update_mwinstance_header(request, mwi_id):
    """ update malware instance meta information
    """
    try:
        mwi = MalwareInstance.objects.get(pk=int(mwi_id))
    except MalwareInstance.DoesNotExist:
        messages.error(request, 'The requested Malware Instance object does not exist')
        return HttpResponseRedirect(reverse('intel:packages'))
    if request.method == "POST":
        mwi_name = request.POST.get('mwi_name', None)
        mwi_description = request.POST.get('mwi_description', None)
        if mwi_name:
            mwi.name = mwi_name
        if mwi_description:
            mwi.description = mwi_description
        mwi.save()
    return HttpResponseRedirect(reverse("intel:malware_instance", kwargs={'mwi_id': mwi_id}))


########################
# ATTACK PATTERN VIEWS #
########################

@login_required
def attack_patterns(request):
    """ list all attack pattern items
    """
    context = {}
    if hasattr(request.user.userextension, 'namespaces'):
        context['usernamespace'] = request.user.userextension.namespaces.last().namespace.split(':')[0]
        context['namespaceicon'] = get_icon_for_namespace(request.user.userextension.namespaces.last().namespace)
    else:
        context['usernamespace'] = 'nospace'
        context['namespaceicon'] = static('ns_icon/octalpus.png')
    return render(request, 'kraut_intel/attack_patterns.html', context)

def delete_attack_pattern(request, ap_id):
    """ delete attacker pattern
    """
    try:
        ap = AttackPattern.objects.get(pk=int(ap_id))
    except AttackPattern.DoesNotExist:
        messages.error(request, 'The requested Malware Instance object does not exist')
        return HttpResponseRedirect(reverse('intel:attack_patterns'))
    ap.delete()
    messages.info(request, 'The attack pattern was deleted successfully!')
    return HttpResponseRedirect(reverse('intel:attack_patterns'))

@login_required
def update_attpattern_header(request, ap_id):
    """ update attack pattern meta information
    """
    try:
        ap = AttackPattern.objects.get(pk=int(ap_id))
    except AttackPattern.DoesNotExist:
        messages.error(request, 'The requested Malware Instance object does not exist')
        return render(request, 'kraut_intel/attpattern_details.html', context)
    if request.method == "POST":
        ap_name = request.POST.get('ap_name', None)
        ap_description = request.POST.get('ap_description', None)
        ap_capec_id = request.POST.get('ap_capec_id', None)
        if ap_name:
            ap.name = ap_name
        if ap_description:
            ap.description = ap_description
        if ap_capec_id:
            ap.capec_id = ap_capec_id
        ap.save()
    return HttpResponseRedirect(reverse("intel:attack_pattern", kwargs={'ap_id': ap_id}))

@login_required
def attack_pattern(request, ap_id="1"):
    """ details of a single attack pattern
    """
    context = {'ap_id': ap_id, 'ap': None, 'related_ttps': []}
    try:

        ap = AttackPattern.objects.get(pk=int(ap_id))