From e27cab719d6e1152e0020af3c8e52523444f95bd Mon Sep 17 00:00:00 2001 From: MaKyOtOx <nicolas.mattiocco@patrowl.io> Date: Wed, 12 Jan 2022 10:36:23 +0100 Subject: [PATCH] minor refactoring --- backend_app/requirements.txt | 2 +- backend_app/vpratings/apis.py | 43 ++++++++-------- backend_app/vulns/apis.py | 6 ++- backend_app/vulns/models.py | 11 ++-- backend_app/vulns/serializers.py | 50 +++++++++--------- frontend/src/components/pages/Vuln.vue | 51 +++++++++---------- .../CardHeaderVulnerability.vue | 28 +++++----- 7 files changed, 94 insertions(+), 97 deletions(-) diff --git a/backend_app/requirements.txt b/backend_app/requirements.txt index 53cf16da..ce32505c 100644 --- a/backend_app/requirements.txt +++ b/backend_app/requirements.txt @@ -46,7 +46,7 @@ oauthlib==3.1.0 openapi-codec==1.3.2 ordered-set==3.1.1 packaging==20.3 -psycopg2==2.8.4 +psycopg2==2.9.0 PyJWT==1.7.1 pymongo==3.10.1 pyparsing==2.4.6 diff --git a/backend_app/vpratings/apis.py b/backend_app/vpratings/apis.py index e67023ec..9093db0c 100644 --- a/backend_app/vpratings/apis.py +++ b/backend_app/vpratings/apis.py @@ -27,29 +27,28 @@ def get_vprating_metrics(self): @api_view(['GET']) @permission_classes([IsAuthenticated]) -def get_vuln_vector(self, vuln_id): - +def get_vuln_vector(self, vuln_id): + vuln = get_object_or_404(Vuln, id=vuln_id) try: org_id = self.session.get('org_id', None) org = organization.get_current_organization(user=self.user, org_id=org_id) except Exception: return JsonResponse("error: unable to get the organization", safe=False, status=500) - - vector = "" + today_date = date.today() - # Vulnerability - vector = vector + vuln.cvss_vector - + # Vulnerability + vector = "" + vuln.cvss_vector + if vuln.is_confirmed is True: vector += "/CL:Y" - - if type(vuln.published) is datetime: + + if type(vuln.published) is datetime: published_date = vuln.published.date() delta = today_date - published_date vector += "/VX:" + str(delta.days) - + ea_metrics = ['unknown', 'private', 'public'] em_metrics = ['unknown', 'unproven', 'poc', 'functional'] et_metrics = ['unknown', 'low', 'medium', 'high', 'trusted'] @@ -57,7 +56,7 @@ def get_vuln_vector(self, vuln_id): em_idx = em_max_idx = 0 et_idx = et_max_idx = 0 ex_max_days = 0 - + exploits = list( chain( vuln.exploitmetadata_set.all(), @@ -67,40 +66,40 @@ def get_vuln_vector(self, vuln_id): for exploit in exploits: e = model_to_dict(exploit) - + ea_idx = ea_metrics.index(e['availability']) if ea_idx > ea_max_idx: ea_max_idx = ea_idx - + em_idx = em_metrics.index(e['maturity']) if em_idx > em_max_idx: em_max_idx = em_idx - + et_idx = et_metrics.index(e['trust_level']) if et_idx > et_max_idx: et_max_idx = et_idx - + if type(e['published']) is datetime: published_date = e['published'].date() delta_published_date = today_date - published_date - if delta_published_date.days > ex_max_days: + if delta_published_date.days > ex_max_days: ex_max_days = delta_published_date.days ea_vectors = ['X', 'R', 'U'] em_vectors = ['X', 'U', 'P', 'F'] et_vectors = ['X', 'L', 'M', 'H', 'H'] - + vector += "/EA:" + str(ea_vectors[ea_max_idx]) vector += "/EM:" + str(em_vectors[em_max_idx]) vector += "/ET:" + str(et_vectors[et_max_idx]) vector += "/EX:" + str(ex_max_days) - - if vuln.is_in_the_news: + + if vuln.is_in_the_news: vector += "/N:Y" - - if vuln.is_in_the_wild: + + if vuln.is_in_the_wild: vector += "/W:Y" - + return JsonResponse(vector, safe=False) diff --git a/backend_app/vulns/apis.py b/backend_app/vulns/apis.py index b5a25090..64425131 100644 --- a/backend_app/vulns/apis.py +++ b/backend_app/vulns/apis.py @@ -755,7 +755,8 @@ def get_org_vuln_metadata(self, vuln_id): @api_view(['GET']) @permission_classes([AllowManageMetadata]) def get_org_vuln_comment(self, vuln_id): - """Return comment linked to a vulnerability and an organization + """Return comments linked to a vulnerability and an organization. + Args: vuln_id (str): The vuln id Returns: @@ -784,7 +785,8 @@ def get_org_vuln_comment(self, vuln_id): @api_view(['POST']) @permission_classes([AllowManageMetadata]) def edit_org_vuln_comment(self, vuln_id): - """ Modify the comment linked to a vulnerability and an organization + """Update the comments linked to a vulnerability and an organization. + Args: vuln_id (str): The vuln id Returns: diff --git a/backend_app/vulns/models.py b/backend_app/vulns/models.py index 13db3480..bbdabdb8 100644 --- a/backend_app/vulns/models.py +++ b/backend_app/vulns/models.py @@ -16,7 +16,7 @@ TRUST_LEVELS, TLP_LEVELS, EXPLOIT_RELEVANCY_RATES ) -from common.utils import _json_serial, organization +from common.utils import _json_serial from cpe import CPE as _CPE import json @@ -252,18 +252,15 @@ class Meta: class OrgVulnMetadata(models.Model): - """Models for data about one vulnerability linked to an organisation. The class inherit from vulnerabiltiy class. - Args: - VulnBase (class): The class of vulnerability - """ - + """Model for vulnerability context data linked to an organization.""" + STATUS_CHOICES = [ ('undefined', 'Undefined'), ('fixed', 'Fixed'), ('not_interesting', 'Not Interesting'), ("in_progress", "In Progress") ] - + organization = models.ForeignKey(Organization, on_delete=models.CASCADE, related_name='org_vulns_metadata') vuln = models.ForeignKey(Vuln, on_delete=models.CASCADE, related_name='org_vulns_metadata') comment = models.TextField(default="", blank=False) diff --git a/backend_app/vulns/serializers.py b/backend_app/vulns/serializers.py index e5a86d01..8c442790 100644 --- a/backend_app/vulns/serializers.py +++ b/backend_app/vulns/serializers.py @@ -135,23 +135,23 @@ class VulnFilter(FilterSet): impact_availability = CharFilter(method='filter_impact_availability', field_name='impact_availability') impact_confidentiality = CharFilter(method='filter_impact_confidentiality', field_name='impact_confidentiality') - def filter_exploit_count__gt(self, queryset, name, value): + def filter_exploit_count__gt(self, queryset, name, value): queryset = queryset.annotate(exploit_count=Count('exploitmetadata')).filter(exploit_count__gte=value) - def filter_exploit_count__gte(self, queryset, name, value): + def filter_exploit_count__gte(self, queryset, name, value): queryset = queryset.annotate(exploit_count=Count('exploitmetadata')) return queryset.filter(exploit_count__gt=value) - def filter_exploit_count__lt(self, queryset, name, value): + def filter_exploit_count__lt(self, queryset, name, value): queryset = queryset.annotate(exploit_count=Count('exploitmetadata')).filter(exploit_count__lt=value) - def filter_exploit_count__lte(self, queryset, name, value): + def filter_exploit_count__lte(self, queryset, name, value): return queryset.annotate(exploit_count=Count('exploitmetadata')).filter(exploit_count__lte=value) - def filter_cwe_id(self, queryset, name, value): + def filter_cwe_id(self, queryset, name, value): return queryset.filter(cwe__cwe_id__icontains=value) - def filter_cpe(self, queryset, name, value): + def filter_cpe(self, queryset, name, value): try: c = value.split(':') vendor = c[3] @@ -167,7 +167,7 @@ def filter_cpe(self, queryset, name, value): pass return queryset.filter(vulnerable_products__icontains=value) - def filter_search(self, queryset, name, value): + def filter_search(self, queryset, name, value): if type(value) == str: value = value.lower() @@ -180,23 +180,23 @@ def filter_search(self, queryset, name, value): Q(products__name__contains=value) ).distinct() - def filter_vendor(self, queryset, name, value): + def filter_vendor(self, queryset, name, value): return queryset.filter(products__vendor__in=[value]) - def filter_vendor_name(self, queryset, name, value): + def filter_vendor_name(self, queryset, name, value): if type(value) == str: value = value.lower().replace(" ", "_") return queryset.filter(products__vendor__name__contains=value) - def filter_product(self, queryset, name, value): + def filter_product(self, queryset, name, value): return queryset.filter(products__in=[value]) - def filter_product_name(self, queryset, name, value): + def filter_product_name(self, queryset, name, value): if type(value) == str: value = value.lower().replace(" ", "_") return queryset.filter(products__name__contains=value) - def filter_product_version(self, queryset, name, value): + def filter_product_version(self, queryset, name, value): if type(value) == str: value = value.lower() # print(value) @@ -209,35 +209,35 @@ def filter_product_version(self, queryset, name, value): return queryset.filter(vulnerable_product_versions__all__contains=value).distinct() - def filter_package(self, queryset, name, value): + def filter_package(self, queryset, name, value): return queryset.filter(packages__in=[value]) - def filter_package_name(self, queryset, name, value): + def filter_package_name(self, queryset, name, value): if type(value) == str: value = value.lower().replace(" ", "_") return queryset.filter(packages__name__contains=value) - def filter_monitored(self, queryset, name, value): + def filter_monitored(self, queryset, name, value): return queryset.filter(monitored=value) # Access - def filter_access_vector(self, queryset, name, value): + def filter_access_vector(self, queryset, name, value): return queryset.filter(access__vector=value) - def filter_access_complexity(self, queryset, name, value): + def filter_access_complexity(self, queryset, name, value): return queryset.filter(access__complexity=value) - def filter_access_authentication(self, queryset, name, value): + def filter_access_authentication(self, queryset, name, value): return queryset.filter(access__authentication=value) # Impact - def filter_impact_integrity(self, queryset, name, value): + def filter_impact_integrity(self, queryset, name, value): return queryset.filter(impact__integrity=value) - def filter_impact_availability(self, queryset, name, value): + def filter_impact_availability(self, queryset, name, value): return queryset.filter(impact__availability=value) - def filter_impact_confidentiality(self, queryset, name, value): + def filter_impact_confidentiality(self, queryset, name, value): return queryset.filter(impact__confidentiality=value) @@ -330,14 +330,14 @@ class ExploitMetadataFilter(FilterSet): search = CharFilter(method='filter_search', field_name='search') cveid = CharFilter(method='filter_cveid', field_name='cveid') - def filter_search(self, queryset, name, value): + def filter_search(self, queryset, name, value): return queryset.filter( Q(link__icontains=value) | Q(notes__icontains=value) | Q(vuln__cveid__icontains=value) ) - def filter_cveid(self, queryset, name, value): + def filter_cveid(self, queryset, name, value): return queryset.filter(vuln__cveid=value) sorted_by = OrderingFilter( @@ -439,14 +439,14 @@ class ThreatMetadataFilter(FilterSet): search = CharFilter(method='filter_search', field_name='search') cveid = CharFilter(method='filter_cveid', field_name='cveid') - def filter_search(self, queryset, name, value): + def filter_search(self, queryset, name, value): return queryset.filter( Q(link__icontains=value) | Q(notes__icontains=value) | Q(vuln__cveid__icontains=value) ) - def filter_cveid(self, queryset, name, value): + def filter_cveid(self, queryset, name, value): return queryset.filter(vuln__cveid=value) sorted_by = OrderingFilter( diff --git a/frontend/src/components/pages/Vuln.vue b/frontend/src/components/pages/Vuln.vue index 35da6315..dc9453d9 100644 --- a/frontend/src/components/pages/Vuln.vue +++ b/frontend/src/components/pages/Vuln.vue @@ -10,7 +10,7 @@ <v-tab>Summary</v-tab> <v-tab> <v-badge - :color = getNumberColor(this.counter.count_exploit) + :color='getNumberColor(this.counter.count_exploit)' :content='this.count_exploit' > Exploits @@ -18,53 +18,52 @@ </v-tab> <v-tab> <v-badge - :color = getNumberColor(this.counter.count_threat) + :color='getNumberColor(this.counter.count_threat)' :content='this.count_threat' > Threat activities </v-badge> </v-tab> - <v-tab>Comment</v-tab> - + <v-tab>Comments</v-tab> + - <!-- Information Vulnerability --> - <v-tab-item> + <!-- Information Vulnerability --> + <v-tab-item> <VulnDetails - :vuln_id = this.vuln_id - @OpenSnackBar = this.modifySnackBar + :vuln_id='this.vuln_id' + @OpenSnackBar='this.modifySnackBar' /> </v-tab-item> - <!-- Exploits --> + <!-- Exploits --> <v-tab-item> - <VulnerabilityExploit - :vuln_id = this.vuln_id - @OpenSnackBar = this.modifySnackBar - @UpdateCounter = this.getCountThreatsExploits + <VulnerabilityExploit + :vuln_id='this.vuln_id' + @OpenSnackBar='this.modifySnackBar' + @UpdateCounter='this.getCountThreatsExploits' /> </v-tab-item> - <!-- Threat --> + <!-- Threat --> <v-tab-item> - <VulnerabilityThreat - :vuln_id = this.vuln_id - @OpenSnackBar = this.modifySnackBar - @UpdateCounter = this.getCountThreatsExploits + <VulnerabilityThreat + :vuln_id='this.vuln_id' + @OpenSnackBar='this.modifySnackBar' + @UpdateCounter='this.getCountThreatsExploits' /> </v-tab-item> - <!-- Comment --> + <!-- Comment --> <v-tab-item> <VulnerabilityComment - :vuln_id = this.vuln_id - @OpenSnackBar = this.modifySnackBar + :vuln_id='this.vuln_id' + @OpenSnackBar='this.modifySnackBar' /> </v-tab-item> - </v-tabs> - <SnackBar - :snack = snack + <SnackBar + :snack='snack' /> </div> </template> @@ -155,10 +154,10 @@ export default { this.loading = false; } } - + } </script> <style> -</style> \ No newline at end of file +</style> diff --git a/frontend/src/components/vulnerability/vulnerabilityDetails/cardVulnerability/CardHeaderVulnerability.vue b/frontend/src/components/vulnerability/vulnerabilityDetails/cardVulnerability/CardHeaderVulnerability.vue index d9668334..5065842f 100644 --- a/frontend/src/components/vulnerability/vulnerabilityDetails/cardVulnerability/CardHeaderVulnerability.vue +++ b/frontend/src/components/vulnerability/vulnerabilityDetails/cardVulnerability/CardHeaderVulnerability.vue @@ -1,7 +1,7 @@ <template> <v-card-title primary class="title"> <v-container class="grey lighten-5"> - <v-row no-gutters> + <v-row no-gutters> <v-col class="pa-2" md="auto"> Vuln ID: PH-{{ this.vuln.id }} @@ -27,25 +27,25 @@ <v-col class="pa-2"> <v-chip - small label outlined + small label outlined :color="this.getColorChipMonitored" @click="toggleMonitored" >{{this.getTextChipMonitored}}</v-chip> </v-col> - <v-col + <v-col class="pa-2" md="auto" v-if="this.vuln.monitored" > <v-select - :items="vuln_status" + :items="vuln_status" item-text="label" item-value="value" label="Status" v-model="status" dense - solo + @change="editStatusVunerability()" /> </v-col> @@ -53,12 +53,12 @@ </v-row> </v-container> - <v-dialog + <v-dialog v-model="dialog_edit_vuln" - max-width="600px" + max-width="600px" v-if="this.showManageMetadataButtons()" > - <DialogVulnAddEdit + <DialogVulnAddEdit :vuln="this.vuln" action="edit" /> @@ -66,9 +66,9 @@ <v-dialog v-model="dialog_send_mail" - max-width="600px" + max-width="600px" > - <DialogSendEmail + <DialogSendEmail :vuln_id="this.vuln.id" v-on="$listeners" @CloseDialog="toggleDialogEmail" @@ -117,7 +117,7 @@ export default { }, mounted(){ this.getDataFromApi(); - + }, methods: { getDataFromApi() { @@ -181,7 +181,7 @@ export default { this.getDataFromApi() } else { const snack = { - open: true, + open: true, color: 'error', text: 'Unable to change the vulnerability monitoring status' } @@ -223,7 +223,7 @@ export default { this.loading = false; }, editStatusVunerability() { - // Edit the the status + // Edit the the status this.$api.post('/api/vulns/'+this.vuln.id+'/status/edit', {"status": this.status}).then(res => { if (res && res.status === 200) { var snack = { @@ -254,4 +254,4 @@ export default { } } } -</script> \ No newline at end of file +</script>