Skip to content
This repository has been archived by the owner on Sep 16, 2022. It is now read-only.

Commit

Permalink
Merge pull request #617 from GreatFruitOmsk/543-cve-page
Browse files Browse the repository at this point in the history
CVE page
  • Loading branch information
vpetersson authored Jan 17, 2020
2 parents 70ca7c3 + b66031b commit 430d928
Show file tree
Hide file tree
Showing 10 changed files with 432 additions and 75 deletions.
2 changes: 2 additions & 0 deletions backend/device_registry/celery_tasks/ubuntu_cve.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from django.conf import settings

import dateutil.parser
import redis
from git import Repo

Expand Down Expand Up @@ -291,6 +292,7 @@ def fetch_vulnerabilities():
'medium': Vulnerability.Urgency.MEDIUM,
'high': Vulnerability.Urgency.HIGH,
}.get(header['Priority'], Vulnerability.Urgency.NONE),
pub_date=dateutil.parser.parse(header['PublicDate']),
remote=None,
fix_available=(status == 'fixed'),
os_release_codename=codename
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class Migration(migrations.Migration):
('is_binary', models.BooleanField()),
('unstable_version', models.CharField(blank=True, max_length=64)),
('other_versions', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=64), blank=True, size=None)),
('urgency', models.CharField(choices=[(device_registry.models.Vulnerability.Urgency(' '), ' '), (device_registry.models.Vulnerability.Urgency('L'), 'L'), (device_registry.models.Vulnerability.Urgency('M'), 'M'), (device_registry.models.Vulnerability.Urgency('H'), 'H')], max_length=64)),
('urgency', models.CharField(max_length=64)),
('remote', models.BooleanField(null=True)),
('fix_available', models.BooleanField()),
],
Expand Down
44 changes: 44 additions & 0 deletions backend/device_registry/migrations/0079_vulnerability.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Generated by Django 2.2.6 on 2020-01-09 11:37

import device_registry.models
from django.db import migrations, models
from django.db.models import Case, CharField, Value, When


def convert_urgencies(apps, schema_editor):
urgencies = {
'Urgency.NONE': 0,
'Urgency.LOW': 1,
'Urgency.MEDIUM': 2,
'Urgency.HIGH': 3,
}
Vulnerability = apps.get_model('device_registry', 'Vulnerability')
Vulnerability.objects.update(urgency=Case(
*[When(urgency=k, then=Value(v)) for k, v in urgencies.items()],
default=Value(0)
))


class Migration(migrations.Migration):

dependencies = [
('device_registry', '0078_merge_20200107_1719'),
]

operations = [
migrations.RunPython(convert_urgencies),
migrations.AlterField(
model_name='vulnerability',
name='urgency',
field=models.PositiveSmallIntegerField(choices=[(device_registry.models.Vulnerability.Urgency(0), 0), (device_registry.models.Vulnerability.Urgency(1), 1), (device_registry.models.Vulnerability.Urgency(2), 2), (device_registry.models.Vulnerability.Urgency(3), 3)]),
),
migrations.AddField(
model_name='vulnerability',
name='pub_date',
field=models.DateField(null=True),
),
migrations.AlterUniqueTogether(
name='vulnerability',
unique_together={('os_release_codename', 'name', 'package')},
)
]
40 changes: 32 additions & 8 deletions backend/device_registry/models.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
from enum import Enum, IntEnum
import datetime
from statistics import mean
import json
import uuid
from typing import NamedTuple

from django.conf import settings
from django.db import models, transaction
from django.db.models import Q, Avg
from django.db.models import Q
from django.utils import timezone
from django.contrib.postgres.fields import ArrayField, JSONField
from django.core.exceptions import ObjectDoesNotExist
Expand Down Expand Up @@ -473,6 +472,27 @@ def vulnerable_packages(self):
self.os_release.get('codename') in DEBIAN_SUITES + UBUNTU_SUITES:
return self.deb_packages.filter(vulnerabilities__isnull=False).distinct().order_by('name')

@property
def cve_count(self):
"""
Count the number of high, medium and low severity CVEs for the device.
:return: A dict of {'high': N1, 'med': N2, 'low': N3} or None if no deb packages or unsupported OS.
"""

# We have no vulnerability data for OS other than Debian and Ubuntu flavors.
if not(self.deb_packages_hash and self.deb_packages.exists() and self.os_release
and self.os_release.get('codename') in DEBIAN_SUITES + UBUNTU_SUITES):
return
vuln_qs = Vulnerability.objects.filter(urgency__gte=Vulnerability.Urgency.LOW, debpackage__device=self,
fix_available=True)
severities = {
Vulnerability.Urgency.HIGH: 'high',
Vulnerability.Urgency.MEDIUM: 'med',
Vulnerability.Urgency.LOW: 'low'
}
return {severities[urgency]: vuln_qs.filter(urgency=urgency).values('name').distinct().count()
for urgency in severities}

def generate_recommended_actions(self, classes=None):
"""
Generate RAs for this device and store them as RecommendedAction objects in database.
Expand Down Expand Up @@ -806,6 +826,9 @@ class Meta:


class Vulnerability(models.Model):
class Meta:
unique_together = ['os_release_codename', 'name', 'package']

class Version:
"""Version class which uses the original APT comparison algorithm."""

Expand All @@ -826,21 +849,22 @@ def __lt__(self, other):
def __eq__(self, other):
return apt_pkg.version_compare(self.__asString, other.__asString) == 0

class Urgency(Enum):
NONE = ' '
LOW = 'L'
MEDIUM = 'M'
HIGH = 'H'
class Urgency(IntEnum):
NONE = 0
LOW = 1
MEDIUM = 2
HIGH = 3

os_release_codename = models.CharField(max_length=64, db_index=True)
name = models.CharField(max_length=64)
package = models.CharField(max_length=64, db_index=True)
is_binary = models.BooleanField()
unstable_version = models.CharField(max_length=64, blank=True)
other_versions = ArrayField(models.CharField(max_length=64), blank=True)
urgency = models.CharField(max_length=64, choices=[(tag, tag.value) for tag in Urgency])
urgency = models.PositiveSmallIntegerField(choices=[(tag, tag.value) for tag in Urgency])
remote = models.BooleanField(null=True)
fix_available = models.BooleanField()
pub_date = models.DateField(null=True)

def is_vulnerable(self, src_ver):
if self.unstable_version:
Expand Down
92 changes: 92 additions & 0 deletions backend/device_registry/templates/cve.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
{% extends "admin_base.html" %}

{% block title %}WoTT - CVE list{% endblock title %}

{% block dashboard_title %}
<h1 style="margin-bottom: 0">CVE list{% if device_name %} for {{ device_name }}{% endif %}</h1>
{% endblock dashboard_title %}

{% block admin_content %}
<!-- cve.html -->
<div class="container-fluid p-0">
<div class="card">
<div class="card-body">
<table class="table table-striped table-responsive-xs" >
<thead>
<th>CVE</th>
<th>Date</th>
<th>Severity</th>
<th>Packages Affected</th>
{% if not device_name %}
<th>Nodes Affected</th>
{% endif %}
<th>Solve</th>
</thead>
<tbody>
{% for row in table_rows %}
<tr>
<td>
<a href="{{ row.cve_link.href }}">{{ row.cve_link.text }}</a>
</td>
<td>{{ row.cve_date|date:"Y-m-d"|default:"N/A" }}</td>
<td>{{ row.severity }}</td>
<td>
{% for p in row.packages %}
{{ p.name }}
<br>
{% endfor %}
</td>
{% if not device_name %}
<td>
{% for p in row.packages %}
<a href="#" class="wott-popover">
{{ p.device_urls|length }}
<template>
{% for du in p.device_urls %}
<a href="{{ du.href }}">{{ du.text }}</a><br>
{% endfor %}
</template>
</a>
<br>
{% endfor %}
</td>
{% endif %}
<td>
{% for p in row.packages %}
<a href="#" class="wott-popover">
Instructions
<template>
Run the following command:
<pre>{{ p.upgrade_command }}</pre>
</template>
</a>
<br>
{% endfor %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock admin_content %}

{% block scripts %}
{{ block.super }}

<script>
$(function () {
$('[data-toggle="popover"]').popover()
});

$('.wott-popover').popover({
html: true,
trigger: 'click',
title: 'Details',
content: function() {
return $(this).children('template').html();
}
})
</script>
{% endblock scripts %}
18 changes: 6 additions & 12 deletions backend/device_registry/templates/device_info_security.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,16 @@ <h4 class="tab-title">Security</h4>
<tr>
<th scope="row">Vulnerable Packages</th>
<td>
{% with object.vulnerable_packages as vulnerable_packages %}
{% if vulnerable_packages is None %}
{% with object.cve_count as cve_count %}
{% if cve_count is None %}
N/A
{% elif vulnerable_packages.exists %}
<ul>
{% for package in vulnerable_packages %}
<li>{{ package.name }} / {{ package.version }}
({% for v in package.vulnerabilities.all %}<a href="https://security-tracker.debian.org/tracker/{{ v.name }}"
target="_blank">{{ v.name }}</a>{% if not forloop.last %}, {% endif %}{% endfor %})
</li>
{% endfor %}
</ul>
{% else %}
{% include "badge.html" with icon="check" color="success" %}
High: {{ cve_count.high }}<br>
Medium: {{ cve_count.med }}<br>
Low: {{ cve_count.low }}<br>
{% endif %}
{% endwith %}
<a href="{% url 'device_cve' object.pk %}">Detailed View</a>
</td>
</tr>
{% with object.heartbleed_vulnerable as heartbleed_vulnerable %}
Expand Down
Loading

0 comments on commit 430d928

Please sign in to comment.