diff options
-rw-r--r-- | pgweb/security/migrations/0003_add_security_patch_details.py | 20 | ||||
-rw-r--r-- | pgweb/security/models.py | 5 | ||||
-rw-r--r-- | pgweb/security/struct.py | 9 | ||||
-rw-r--r-- | pgweb/security/views.py | 33 | ||||
-rw-r--r-- | pgweb/urls.py | 1 | ||||
-rw-r--r-- | templates/security/details.html | 95 | ||||
-rw-r--r-- | templates/security/security.html | 4 |
7 files changed, 162 insertions, 5 deletions
diff --git a/pgweb/security/migrations/0003_add_security_patch_details.py b/pgweb/security/migrations/0003_add_security_patch_details.py new file mode 100644 index 00000000..23acb72b --- /dev/null +++ b/pgweb/security/migrations/0003_add_security_patch_details.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.13 on 2018-11-12 16:37 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('security', '0002_cve_visible'), + ] + + operations = [ + migrations.AddField( + model_name='securitypatch', + name='details', + field=models.TextField(blank=True, help_text='Additional details about the security patch', null=True), + ), + ] diff --git a/pgweb/security/models.py b/pgweb/security/models.py index e82c7d4f..208a9de7 100644 --- a/pgweb/security/models.py +++ b/pgweb/security/models.py @@ -70,6 +70,7 @@ class SecurityPatch(models.Model): cvenumber = models.IntegerField(null=False, blank=False, db_index=True) detailslink = models.URLField(null=False, blank=True) description = models.TextField(null=False, blank=False) + details = models.TextField(blank=True, null=True, help_text="Additional details about the security patch") component = models.CharField(max_length=32, null=False, blank=False, help_text="If multiple components, choose the most critical one", choices=component_choices) versions = models.ManyToManyField(Version, through='SecurityPatchVersion') @@ -84,7 +85,9 @@ class SecurityPatch(models.Model): vector_a = models.CharField(max_length=1, null=False, blank=True, verbose_name="Availability Impact", choices=vector_choices['A']) legacyscore = models.CharField(max_length=1, null=False, blank=True, verbose_name='Legacy score', choices=(('A', 'A'), ('B', 'B'), ('C', 'C'), ('D', 'D'))) - purge_urls = ('/support/security/', ) + def purge_urls(self): + yield '/support/security/CVE-%s/' % self.cve + yield '/support/security/' def save(self, force_insert=False, force_update=False): # Calculate a number from the CVE, that we can use to sort by. We need to diff --git a/pgweb/security/struct.py b/pgweb/security/struct.py new file mode 100644 index 00000000..fd5a713b --- /dev/null +++ b/pgweb/security/struct.py @@ -0,0 +1,9 @@ +from datetime import date, timedelta +from .models import SecurityPatch + + +def get_struct(): + """create sitemap entries for each CVE entry and the top level CVE URL""" + yield ('support/security/', None) + for s in SecurityPatch.objects.filter(public=True).order_by('-cvenumber'): + yield ('support/security/CVE-{}'.format(s.cve), None) diff --git a/pgweb/security/views.py b/pgweb/security/views.py index 0a7f2041..b36fcc04 100644 --- a/pgweb/security/views.py +++ b/pgweb/security/views.py @@ -1,9 +1,11 @@ -from django.shortcuts import get_object_or_404 +from django.core.validators import ValidationError +from django.http import Http404 +from django.shortcuts import get_object_or_404, redirect from pgweb.util.contexts import render_pgweb from pgweb.core.models import Version -from .models import SecurityPatch +from .models import SecurityPatch, make_cvenumber def GetPatchesList(filt): @@ -22,6 +24,33 @@ def _list_patches(request, filt): }) +def details(request, cve_prefix, cve): + """Provides additional details about a specific CVE""" + # First determine if the entrypoint of the URL is a lowercase "cve". If it + # is, redirect to the uppercase + if cve_prefix != "CVE": + return redirect('/support/security/CVE-{}/'.format(cve), permanent=True) + # Get the CVE number from the CVE ID string so we can look it up + # against the database. This shouldn't fail due to an ill-formatted CVE, + # as both use the same validation check, but we will wrap it just in case. + # + # However, we do need to ensure that the CVE does both exist and + # is published. + try: + security_patch = get_object_or_404( + SecurityPatch, + cvenumber=make_cvenumber(cve), + public=True, + ) + except ValidationError: + raise Http404() + + return render_pgweb(request, 'support', 'security/details.html', { + 'security_patch': security_patch, + 'versions': security_patch.securitypatchversion_set.select_related('version').order_by('-version__tree').all(), + }) + + def index(request): # Show all supported versions return _list_patches(request, "v.supported") diff --git a/pgweb/urls.py b/pgweb/urls.py index 64fb616b..cc29aaba 100644 --- a/pgweb/urls.py +++ b/pgweb/urls.py @@ -81,6 +81,7 @@ urlpatterns = [ url(r'^support/security/$', pgweb.security.views.index), url(r'^support/security/(\d\.\d|\d{2})/$', pgweb.security.views.version), + url(r'^support/security/(?P<cve_prefix>CVE|cve)-(?P<cve>\d{4}-\d{4,7})/$', pgweb.security.views.details), url(r'^support/security_archive/$', RedirectView.as_view(url='/support/security/', permanent=True)), url(r'^support/professional_(support|hosting)/$', pgweb.profserv.views.root), diff --git a/templates/security/details.html b/templates/security/details.html new file mode 100644 index 00000000..0e894c5a --- /dev/null +++ b/templates/security/details.html @@ -0,0 +1,95 @@ +{%extends "base/page.html"%} +{%block title%}CVE-{{ security_patch.cve }}: {{ security_patch.description }}{%endblock%} +{%block contents%} + +<h1>CVE-{{ security_patch.cve }} <i class="fas fa-lock"></i></h1> +<h3>{{ security_patch.description }}</h3> + +{% if security_patch.details %} +<p>{{ security_patch.details }}</p> +{% endif %} + +<h2>Version Information</h2> + +<table class="table"> + <thead> + <tr> + <th>Affected Version</th> + <th>Fixed In</th> + {% if security_patch.newspost %} + <th>Fix Published</th> + {% endif %} + </thead> + <tbody> + {% for version in versions %} + <tr> + <td> + {% if version.version.tree >= 10 %} + {{ version.version.tree|floatformat:"0" }} + {% else %} + {{ version.version.tree }} + {% endif %} + </td> + <td> + <a href="/docs/release/{% if version.version.tree >= 10 %}{{ version.version.tree|floatformat:"0" }}.{{ version.fixed_minor }}{% else %}{{ version.version.tree }}.{{ version.fixed_minor }}{% endif %}"> + {% if version.version.tree >= 10 %} + {{ version.version.tree|floatformat:"0" }}.{{ version.fixed_minor }} + {% else %} + {{ version.version.tree }}.{{ version.fixed_minor }} + {% endif %} + </a> + </td> + {% if security_patch.newspost %} + <td> + <a href="/about/news/{{ security_patch.newspost.title|slugify }}-{{ security_patch.newspost.id }}/"> + {{ security_patch.newspost.date }} + </a> + </td> + {% endif %} + </tr> + {% endfor %} + </tbody> +</table> + +<p> + For more information about <a href="/support/versioning/">PostgreSQL versioning</a>, + please visit the <a href="/support/versioning/">versioning page</a>. +</p> + +{% if security_patch.cvssscore >= 0 %} +<h2>CVSS 3.0</h2> + +<table class="table"> + <tbody> + <tr> + <th>Overall Score</th> + <td><strong>{{ security_patch.cvssscore }}</strong></td> + </tr> + <tr> + <th>Component</th> + <td>{{ security_patch.component }}</td> + </tr> + <tr> + <th>Vector</th> + <td> + <a href="https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?vector={{ security_patch.cvssvector }}&version=3.0" target="_blank" rel="noopener noreferer"> + {{ security_patch.cvssvector }} + </a> + </td> + </tr> + </tbody> +</table> +{% endif %} + +<h2>Reporting Security Vulnerabilities</h2> + +<p> + If you wish to report a new security vulnerability in PostgreSQL, please + send an email to + <a href="mailto:security@postgresql.org">security@postgresql.org</a>. +</p> + +<p> + For reporting non-security bugs, please see the <a href="/account/submitbug/">Report a Bug</a> page. +</p> +{%endblock%} diff --git a/templates/security/security.html b/templates/security/security.html index a6e0a6fc..13fcc169 100644 --- a/templates/security/security.html +++ b/templates/security/security.html @@ -75,7 +75,7 @@ You can filter the view of patches to show just patches for version:<br/> {%for p in patches%} <tr> <td> - {%if p.cve%}<nobr>{%if p.cve_visible%}<a href="{{p.cvelink}}">CVE-{{p.cve}}</a>{%else%}CVE-{{p.cve}}{%endif%}</nobr><br/>{%endif%} + {%if p.cve%}<nobr><a href="/support/security/CVE-{{ p.cve }}/">CVE-{{p.cve}}</a></nobr><br/>{%endif%} {%if p.newspost%}<a href="/about/news/{{p.newspost.title|slugify}}-{{p.newspost.id}}/">Announcement</a><br/>{%endif%} </td> <td>{{p.affected|join:", "}}</td> @@ -83,7 +83,7 @@ You can filter the view of patches to show just patches for version:<br/> <td>{{p.component}}<br/> {%if p.cvssscore >= 0%}<a href="https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?vector={{p.cvssvector}}">{{p.cvssscore}}</a><br/><span class="cvssvector">{{p.cvssvector}}</span> {%else%}Legacy: {{p.legacyscore}}{%endif%}</td> - <td>{{p.description}}{%if p.detailslink%}<br/><br/><a href="{{p.detailslink}}">more details</a>{%endif%}</td> + <td>{{p.description}}<br/><br/><a href="/support/security/CVE-{{ p.cve }}/">more details</a></td> </tr> {% endfor %} </tbody> |