diff options
Diffstat (limited to 'rpki/gui/cacheview')
18 files changed, 0 insertions, 1318 deletions
diff --git a/rpki/gui/cacheview/__init__.py b/rpki/gui/cacheview/__init__.py deleted file mode 100644 index e69de29b..00000000 --- a/rpki/gui/cacheview/__init__.py +++ /dev/null diff --git a/rpki/gui/cacheview/forms.py b/rpki/gui/cacheview/forms.py deleted file mode 100644 index 7ae3601f..00000000 --- a/rpki/gui/cacheview/forms.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright (C) 2011 SPARTA, Inc. dba Cobham Analytic Solutions -# Copyright (C) 2013 SPARTA, Inc. a Parsons Company -# -# Permission to use, copy, modify, and distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND SPARTA DISCLAIMS ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -# AND FITNESS. IN NO EVENT SHALL SPARTA BE LIABLE FOR ANY SPECIAL, DIRECT, -# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE -# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -# PERFORMANCE OF THIS SOFTWARE. - -__version__ = '$Id$' - -from django import forms - -from rpki.gui.cacheview.misc import parse_ipaddr -from rpki.exceptions import BadIPResource -from rpki.resource_set import resource_range_as - - -class SearchForm(forms.Form): - asn = forms.CharField(required=False, help_text='AS or range', label='AS') - addr = forms.CharField(required=False, max_length=40, help_text='range/CIDR', label='IP Address') - - def clean(self): - asn = self.cleaned_data.get('asn') - addr = self.cleaned_data.get('addr') - if (asn and addr) or ((not asn) and (not addr)): - raise forms.ValidationError('Please specify either an AS or IP range, not both') - - if asn: - try: - resource_range_as.parse_str(asn) - except ValueError: - raise forms.ValidationError('invalid AS range') - - if addr: - #try: - parse_ipaddr(addr) - #except BadIPResource: - # raise forms.ValidationError('invalid IP address range/prefix') - - return self.cleaned_data - - -class SearchForm2(forms.Form): - resource = forms.CharField(required=True) diff --git a/rpki/gui/cacheview/misc.py b/rpki/gui/cacheview/misc.py deleted file mode 100644 index 54431224..00000000 --- a/rpki/gui/cacheview/misc.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (C) 2011 SPARTA, Inc. dba Cobham Analytic Solutions -# -# Permission to use, copy, modify, and distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND SPARTA DISCLAIMS ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -# AND FITNESS. IN NO EVENT SHALL SPARTA BE LIABLE FOR ANY SPECIAL, DIRECT, -# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE -# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -# PERFORMANCE OF THIS SOFTWARE. - -from rpki.resource_set import resource_range_ipv4, resource_range_ipv6 -from rpki.exceptions import BadIPResource - -def parse_ipaddr(s): - # resource_set functions only accept str - if isinstance(s, unicode): - s = s.encode() - s = s.strip() - r = resource_range_ipv4.parse_str(s) - try: - r = resource_range_ipv4.parse_str(s) - return 4, r - except BadIPResource: - r = resource_range_ipv6.parse_str(s) - return 6, r - -# vim:sw=4 ts=8 expandtab diff --git a/rpki/gui/cacheview/models.py b/rpki/gui/cacheview/models.py deleted file mode 100644 index 08acfa2d..00000000 --- a/rpki/gui/cacheview/models.py +++ /dev/null @@ -1,245 +0,0 @@ -# Copyright (C) 2011 SPARTA, Inc. dba Cobham Analytic Solutions -# Copyright (C) 2012 SPARTA, Inc. a Parsons Company -# -# Permission to use, copy, modify, and distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND SPARTA DISCLAIMS ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -# AND FITNESS. IN NO EVENT SHALL SPARTA BE LIABLE FOR ANY SPECIAL, DIRECT, -# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE -# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -# PERFORMANCE OF THIS SOFTWARE. - -__version__ = '$Id$' - -from datetime import datetime -import time - -from django.db import models -from django.core.urlresolvers import reverse - -import rpki.resource_set -import rpki.gui.models - - -class TelephoneField(models.CharField): - def __init__(self, *args, **kwargs): - kwargs['max_length'] = 255 - models.CharField.__init__(self, *args, **kwargs) - - -class AddressRange(rpki.gui.models.PrefixV4): - @models.permalink - def get_absolute_url(self): - return ('rpki.gui.cacheview.views.addressrange_detail', [str(self.pk)]) - - -class AddressRangeV6(rpki.gui.models.PrefixV6): - @models.permalink - def get_absolute_url(self): - return ('rpki.gui.cacheview.views.addressrange_detail_v6', - [str(self.pk)]) - - -class ASRange(rpki.gui.models.ASN): - @models.permalink - def get_absolute_url(self): - return ('rpki.gui.cacheview.views.asrange_detail', [str(self.pk)]) - -kinds = list(enumerate(('good', 'warn', 'bad'))) -kinds_dict = dict((v, k) for k, v in kinds) - - -class ValidationLabel(models.Model): - """ - Represents a specific error condition defined in the rcynic XML - output file. - """ - - label = models.CharField(max_length=79, db_index=True, unique=True) - status = models.CharField(max_length=255) - kind = models.PositiveSmallIntegerField(choices=kinds) - - def __unicode__(self): - return self.label - - -class RepositoryObject(models.Model): - """ - Represents a globally unique RPKI repository object, specified by its URI. - """ - - uri = models.URLField(unique=True, db_index=True) - -generations = list(enumerate(('current', 'backup'))) -generations_dict = dict((val, key) for (key, val) in generations) - - -class ValidationStatus(models.Model): - timestamp = models.DateTimeField() - generation = models.PositiveSmallIntegerField(choices=generations, null=True) - status = models.ForeignKey(ValidationLabel) - repo = models.ForeignKey(RepositoryObject, related_name='statuses') - - -class SignedObject(models.Model): - """ - Abstract class to hold common metadata for all signed objects. - The signing certificate is ommitted here in order to give a proper - value for the 'related_name' attribute. - """ - - repo = models.ForeignKey(RepositoryObject, related_name='cert', unique=True) - - # on-disk file modification time - mtime = models.PositiveIntegerField(default=0) - - # SubjectName - name = models.CharField(max_length=255) - - # value from the SKI extension - keyid = models.CharField(max_length=60, db_index=True) - - # validity period from EE cert which signed object - not_before = models.DateTimeField() - not_after = models.DateTimeField() - - def mtime_as_datetime(self): - """ - convert the local timestamp to UTC and convert to a datetime object - """ - - return datetime.utcfromtimestamp(self.mtime + time.timezone) - - def status_id(self): - """ - Returns a HTML class selector for the current object based on its validation status. - The selector is chosen based on the current generation only. If there is any bad status, - return bad, else if there are any warn status, return warn, else return good. - """ - - for x in reversed(kinds): - if self.repo.statuses.filter(generation=generations_dict['current'], status__kind=x[0]): - return x[1] - return None # should not happen - - def __unicode__(self): - return u'%s' % self.name - - -class Cert(SignedObject): - """ - Object representing a resource certificate. - """ - - addresses = models.ManyToManyField(AddressRange, related_name='certs') - addresses_v6 = models.ManyToManyField(AddressRangeV6, related_name='certs') - asns = models.ManyToManyField(ASRange, related_name='certs') - issuer = models.ForeignKey('self', related_name='children', null=True) - sia = models.CharField(max_length=255) - - def get_absolute_url(self): - return reverse('cert-detail', args=[str(self.pk)]) - - def get_cert_chain(self): - """Return a list containing the complete certificate chain for this - certificate.""" - - cert = self - x = [cert] - while cert != cert.issuer: - cert = cert.issuer - x.append(cert) - x.reverse() - return x - cert_chain = property(get_cert_chain) - - -class ROAPrefix(models.Model): - "Abstract base class for ROA mixin." - - max_length = models.PositiveSmallIntegerField() - - class Meta: - abstract = True - - def as_roa_prefix(self): - "Return value as a rpki.resource_set.roa_prefix_ip object." - rng = self.as_resource_range() - return self.roa_cls(rng.min, rng.prefixlen(), self.max_length) - - def __unicode__(self): - p = self.as_resource_range() - if p.prefixlen() == self.max_length: - return str(p) - return '%s-%s' % (str(p), self.max_length) - - -# ROAPrefix is declared first, so subclass picks up __unicode__ from it. -class ROAPrefixV4(ROAPrefix, rpki.gui.models.PrefixV4): - "One v4 prefix in a ROA." - - roa_cls = rpki.resource_set.roa_prefix_ipv4 - - @property - def routes(self): - """return all routes covered by this roa prefix""" - - return RouteOrigin.objects.filter(prefix_min__gte=self.prefix_min, - prefix_max__lte=self.prefix_max) - - class Meta: - ordering = ('prefix_min',) - - -# ROAPrefix is declared first, so subclass picks up __unicode__ from it. -class ROAPrefixV6(ROAPrefix, rpki.gui.models.PrefixV6): - "One v6 prefix in a ROA." - - roa_cls = rpki.resource_set.roa_prefix_ipv6 - - class Meta: - ordering = ('prefix_min',) - - -class ROA(SignedObject): - asid = models.PositiveIntegerField() - prefixes = models.ManyToManyField(ROAPrefixV4, related_name='roas') - prefixes_v6 = models.ManyToManyField(ROAPrefixV6, related_name='roas') - issuer = models.ForeignKey('Cert', related_name='roas') - - def get_absolute_url(self): - return reverse('roa-detail', args=[str(self.pk)]) - - class Meta: - ordering = ('asid',) - - def __unicode__(self): - return u'ROA for AS%d' % self.asid - - -class Ghostbuster(SignedObject): - full_name = models.CharField(max_length=40) - email_address = models.EmailField(blank=True, null=True) - organization = models.CharField(blank=True, null=True, max_length=255) - telephone = TelephoneField(blank=True, null=True) - issuer = models.ForeignKey('Cert', related_name='ghostbusters') - - def get_absolute_url(self): - # note that ghostbuster-detail is different from gbr-detail! sigh - return reverse('ghostbuster-detail', args=[str(self.pk)]) - - def __unicode__(self): - if self.full_name: - return self.full_name - if self.organization: - return self.organization - if self.email_address: - return self.email_address - return self.telephone - - -from rpki.gui.routeview.models import RouteOrigin diff --git a/rpki/gui/cacheview/templates/cacheview/addressrange_detail.html b/rpki/gui/cacheview/templates/cacheview/addressrange_detail.html deleted file mode 100644 index 76edc1ba..00000000 --- a/rpki/gui/cacheview/templates/cacheview/addressrange_detail.html +++ /dev/null @@ -1,18 +0,0 @@ -{% extends "cacheview/cacheview_base.html" %} - -{% block content %} -<h1>{% block title %}IP Range Detail{% endblock %}</h1> - -<p> -IP Range: {{ object }} -</p> - -<p>Covered by the following resource certs:</p> - -<ul> -{% for cert in object.certs.all %} -<li><a href="{{ cert.get_absolute_url }}">{{ cert }}</a></li> -{% endfor %} -</ul> - -{% endblock %} diff --git a/rpki/gui/cacheview/templates/cacheview/cacheview_base.html b/rpki/gui/cacheview/templates/cacheview/cacheview_base.html deleted file mode 100644 index ec71d740..00000000 --- a/rpki/gui/cacheview/templates/cacheview/cacheview_base.html +++ /dev/null @@ -1,10 +0,0 @@ -{% extends "base.html" %} -{% load url from future %} - -{% block sidebar %} -<form method='post' action='{% url 'res-search' %}'> - {% csrf_token %} - <input type='text' id='id_resource' name='resource' placeholder='prefix or AS'> - <button type='submit'>Search</button> -</form> -{% endblock %} diff --git a/rpki/gui/cacheview/templates/cacheview/cert_detail.html b/rpki/gui/cacheview/templates/cacheview/cert_detail.html deleted file mode 100644 index 256e7780..00000000 --- a/rpki/gui/cacheview/templates/cacheview/cert_detail.html +++ /dev/null @@ -1,105 +0,0 @@ -{% extends "cacheview/signedobject_detail.html" %} - -{% block title %} -Resource Certificate Detail -{% endblock %} - -{% block detail %} - -<h2>RFC3779 Resources</h2> - -<table class='table table-striped'> - <thead> - <tr><th>AS Ranges</th><th>IP Ranges</th></tr> - </thead> - <tbody> - <tr> - <td style='text-align:left;vertical-align:top'> - <ul class='compact'> - {% for asn in object.asns.all %} - <li><a href="{{ asn.get_absolute_url }}">{{ asn }}</a></li> - {% endfor %} - </ul> - </td> - <td style='text-align:left;vertical-align:top'> - <ul class='compact'> - {% for rng in object.addresses.all %} - <li><a href="{{ rng.get_absolute_url }}">{{ rng }}</a></li> - {% endfor %} - </ul> - </td> - </tr> - </tbody> -</table> - -<div class='section'> -<h2>Issued Objects</h2> -<ul> - -{% if object.ghostbusters.all %} - <li> -<h3>Ghostbusters</h3> - -<table class='table table-striped'> - <thead> - <tr><th>Name</th><th>Expires</th></tr> - </thead> - <tbody> - -{% for g in object.ghostbusters.all %} - <tr class='{{ g.status_id }}'> - <td><a href="{{ g.get_absolute_url }}">{{ g }}</a></td> - <td>{{ g.not_after }}</td> - </tr> - </tbody> -{% endfor %} - -</table> -{% endif %} - -{% if object.roas.all %} - <li> -<h3>ROAs</h3> -<table class='table table-striped'> - <thead> - <tr><th>#</th><th>Prefix</th><th>AS</th><th>Expires</th></tr> - </thead> - <tbody> - {% for roa in object.roas.all %} - {% for pfx in roa.prefixes.all %} - <tr class='{{ roa.status_id }}'> - <td><a href="{{ roa.get_absolute_url }}">#</a></td> - <td>{{ pfx }}</td> - <td>{{ roa.asid }}</td> - <td>{{ roa.not_after }}</td> - </tr> - {% endfor %} - {% endfor %} - </tbody> -</table> -{% endif %} - -{% if object.children.all %} -<li> -<h3>Children</h3> -<table class='table table-striped'> - <thead> - <tr><th>Name</th><th>Expires</th></tr> - </thead> - <tbody> - - {% for child in object.children.all %} - <tr class='{{ child.status_id }}'> - <td><a href="{{ child.get_absolute_url }}">{{ child.name }}</a></td> - <td>{{ child.not_after }}</td> - </tr> - {% endfor %} - </tbody> -</table> -{% endif %} - -</ul> - -</div><!--issued objects--> - -{% endblock %} diff --git a/rpki/gui/cacheview/templates/cacheview/ghostbuster_detail.html b/rpki/gui/cacheview/templates/cacheview/ghostbuster_detail.html deleted file mode 100644 index 4215f757..00000000 --- a/rpki/gui/cacheview/templates/cacheview/ghostbuster_detail.html +++ /dev/null @@ -1,13 +0,0 @@ -{% extends "cacheview/signedobject_detail.html" %} - -{% block title %}Ghostbuster Detail{% endblock %} - -{% block detail %} -<p> -<table class='table'> - <tr><td>Full Name</td><td>{{ object.full_name }}</td></tr> - <tr><td>Organization</td><td>{{ object.organization }}</td></tr> - <tr><td>Email</td><td>{{ object.email_address }}</td></tr> - <tr><td>Telephone</td><td>{{ object.telephone }}</td></tr> -</table> -{% endblock %} diff --git a/rpki/gui/cacheview/templates/cacheview/global_summary.html b/rpki/gui/cacheview/templates/cacheview/global_summary.html deleted file mode 100644 index 0dbd0ffc..00000000 --- a/rpki/gui/cacheview/templates/cacheview/global_summary.html +++ /dev/null @@ -1,26 +0,0 @@ -{% extends "cacheview/cacheview_base.html" %} - -{% block content %} -<div class='page-header'> - <h1>Browse Global RPKI</h1> -</div> - -<table class="table table-striped"> - <thead> - <tr> - <th>Name</th> - <th>Expires</th> - <th>URI</th> - </tr> - </thead> - <tbody> - {% for r in roots %} - <tr> - <td><a href="{{ r.get_absolute_url }}">{{ r.name }}</a></td> - <td>{{ r.not_after }}</td> - <td>{{ r.repo.uri }}</td> - </tr> - {% endfor %} - </tbody> -</table> -{% endblock content %} diff --git a/rpki/gui/cacheview/templates/cacheview/query_result.html b/rpki/gui/cacheview/templates/cacheview/query_result.html deleted file mode 100644 index 0694c531..00000000 --- a/rpki/gui/cacheview/templates/cacheview/query_result.html +++ /dev/null @@ -1,21 +0,0 @@ -{% extends "cacheview/cacheview_base.html" %} - -{% block content %} - -<h1>{% block title %}Query Results{% endblock %}</h1> - -<table> - <tr><th>Prefix</th><th>AS</th><th>Valid</th><th>Until</th></tr> - {% for object in object_list %} - <tr class='{{ object.1.status.kind_as_str }}'> - <td>{{ object.0 }}</td> - <td>{{ object.1.asid }}</td> - <td><a href="{{ object.1.get_absolute_url }}">{{ object.1.ok }}</a></td> - <td>{{ object.1.not_after }}</td> - </tr> - {% endfor %} -</table> - -<p><a href="{% url rpki.gui.cacheview.views.query_view %}">new query</a></p> - -{% endblock %} diff --git a/rpki/gui/cacheview/templates/cacheview/roa_detail.html b/rpki/gui/cacheview/templates/cacheview/roa_detail.html deleted file mode 100644 index 39cc547b..00000000 --- a/rpki/gui/cacheview/templates/cacheview/roa_detail.html +++ /dev/null @@ -1,18 +0,0 @@ -{% extends "cacheview/signedobject_detail.html" %} - -{% block title %}ROA Detail{% endblock %} - -{% block detail %} -<p> -<table> - <tr><td>AS</td><td>{{ object.asid }}</td></tr> -</table> - -<h2>Prefixes</h2> - -<ul> -{% for pfx in object.prefixes.all %} -<li>{{ pfx }} -{% endfor %} -</ul> -{% endblock %} diff --git a/rpki/gui/cacheview/templates/cacheview/search_form.html b/rpki/gui/cacheview/templates/cacheview/search_form.html deleted file mode 100644 index 1141615d..00000000 --- a/rpki/gui/cacheview/templates/cacheview/search_form.html +++ /dev/null @@ -1,17 +0,0 @@ -{% extends "cacheview/cacheview_base.html" %} - -{% block title %} -{{ search_type }} Search -{% endblock %} - -{% block content %} - -<h1>{{search_type}} Search</h1> - -<form method='post' action='{{ request.url }}'> - {% csrf_token %} - {{ form.as_p }} - <input type='submit' name='Search'> -</form> - -{% endblock %} diff --git a/rpki/gui/cacheview/templates/cacheview/search_result.html b/rpki/gui/cacheview/templates/cacheview/search_result.html deleted file mode 100644 index 7cbf852e..00000000 --- a/rpki/gui/cacheview/templates/cacheview/search_result.html +++ /dev/null @@ -1,42 +0,0 @@ -{% extends "cacheview/cacheview_base.html" %} - -{% block content %} - -<div class='page-header'> - <h1>Search Results <small>{{ resource }}</small></h1> -</div> - -<h2>Matching Resource Certificates</h2> -{% if certs %} -<ul> -{% for cert in certs %} -<li><a href="{{ cert.get_absolute_url }}">{{ cert }}</a> -{% endfor %} -</ul> -{% else %} -<p>none</p> -{% endif %} - -<h2>Matching ROAs</h2> -{% if roas %} -<table class='table table-striped'> - <thead> - <tr> - <th>#</th><th>Prefix</th><th>AS</th> - </tr> - </thead> - <tbody> -{% for roa in roas %} -<tr> - <td><a href="{{ roa.get_absolute_url }}">#</a></td> - <td>{{ roa.prefixes.all.0 }}</td> - <td>{{ roa.asid }}</td> -</tr> -{% endfor %} -</tbody> -</table> -{% else %} -<p>none</p> -{% endif %} - -{% endblock %} diff --git a/rpki/gui/cacheview/templates/cacheview/signedobject_detail.html b/rpki/gui/cacheview/templates/cacheview/signedobject_detail.html deleted file mode 100644 index 22ae3d27..00000000 --- a/rpki/gui/cacheview/templates/cacheview/signedobject_detail.html +++ /dev/null @@ -1,58 +0,0 @@ -{% extends "cacheview/cacheview_base.html" %} - -{% block content %} -<div class='page-header'> -<h1>{% block title %}Signed Object Detail{% endblock %}</h1> -</div> - -<h2>Cert Info</h2> -<table class='table table-striped'> - <tr><td>Subject Name</td><td>{{ object.name }}</td></tr> - <tr><td>SKI</td><td>{{ object.keyid }}</td></tr> - {% if object.sia %} - <tr><td>SIA</td><td>{{ object.sia }}</td></tr> - {% endif %} - <tr><td>Not Before</td><td>{{ object.not_before }}</td></tr> - <tr><td>Not After</td><td>{{ object.not_after }}</td></tr> -</table> - -<h2>Metadata</h2> - -<table class='table table-striped'> - <tr><td>URI</td><td>{{ object.repo.uri }}</td></tr> - <tr><td>Last Modified</td><td>{{ object.mtime_as_datetime|date:"DATETIME_FORMAT" }}</td></tr> -</table> - -<h2>Validation Status</h2> -<table class='table table-striped'> - <thead> - <tr><th>Timestamp</th><th>Generation</th><th>Status</th></tr> - </thead> - <tbody> - {% for status in object.repo.statuses.all %} - <tr class="{{ status.status.get_kind_display }}"><td>{{ status.timestamp }}</td><td>{{ status.get_generation_display }}</td><td>{{ status.status.status }}</td></tr> - {% endfor %} - </tbody> -</table> - -<h2>X.509 Certificate Chain</h2> - -<table class='table table-striped'> - <thead> - <tr><th>Depth</th><th>Name</th></tr> - </thead> - <tbody> - -{% for cert in chain %} -<tr class='{{ cert.1.status_id }}'> - <td>{{ cert.0 }}</td> - <td><a href="{{ cert.1.get_absolute_url }}">{{ cert.1.name }}</a></td> -</tr> -{% endfor %} -</tbody> - -</table> - -{% block detail %}{% endblock %} - -{% endblock %} diff --git a/rpki/gui/cacheview/tests.py b/rpki/gui/cacheview/tests.py deleted file mode 100644 index c2958c72..00000000 --- a/rpki/gui/cacheview/tests.py +++ /dev/null @@ -1,23 +0,0 @@ -""" -This file demonstrates two different styles of tests (one doctest and one -unittest). These will both pass when you run "manage.py test". - -Replace these with more appropriate tests for your application. -""" - -from django.test import TestCase - -class SimpleTest(TestCase): - def test_basic_addition(self): - """ - Tests that 1 + 1 always equals 2. - """ - - self.failUnlessEqual(1 + 1, 2) - -__test__ = {"doctest": """ -Another way to test that 1 + 1 is equal to 2. - ->>> 1 + 1 == 2 -True -"""} diff --git a/rpki/gui/cacheview/urls.py b/rpki/gui/cacheview/urls.py deleted file mode 100644 index cc03a587..00000000 --- a/rpki/gui/cacheview/urls.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (C) 2011 SPARTA, Inc. dba Cobham Analytic Solutions -# Copyright (C) 2013 SPARTA, Inc. a Parsons Company -# -# Permission to use, copy, modify, and distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND SPARTA DISCLAIMS ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -# AND FITNESS. IN NO EVENT SHALL SPARTA BE LIABLE FOR ANY SPECIAL, DIRECT, -# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE -# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -# PERFORMANCE OF THIS SOFTWARE. - -__version__ = '$Id$' - -from django.conf.urls import patterns, url -from rpki.gui.cacheview.views import (CertDetailView, RoaDetailView, - GhostbusterDetailView) - -urlpatterns = patterns('', - url(r'^search$', 'rpki.gui.cacheview.views.search_view', - name='res-search'), - url(r'^cert/(?P<pk>[^/]+)$', CertDetailView.as_view(), name='cert-detail'), - url(r'^gbr/(?P<pk>[^/]+)$', GhostbusterDetailView.as_view(), - name='ghostbuster-detail'), - url(r'^roa/(?P<pk>[^/]+)$', RoaDetailView.as_view(), name='roa-detail'), - (r'^$', 'rpki.gui.cacheview.views.global_summary'), -) - -# vim:sw=4 ts=8 expandtab diff --git a/rpki/gui/cacheview/util.py b/rpki/gui/cacheview/util.py deleted file mode 100644 index 00298b2c..00000000 --- a/rpki/gui/cacheview/util.py +++ /dev/null @@ -1,435 +0,0 @@ -# Copyright (C) 2011 SPARTA, Inc. dba Cobham -# Copyright (C) 2012, 2013 SPARTA, Inc. a Parsons Company -# -# Permission to use, copy, modify, and distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND SPARTA DISCLAIMS ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -# AND FITNESS. IN NO EVENT SHALL SPARTA BE LIABLE FOR ANY SPECIAL, DIRECT, -# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE -# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -# PERFORMANCE OF THIS SOFTWARE. - -__version__ = '$Id$' -__all__ = ('import_rcynic_xml') - -default_logfile = '/var/rcynic/data/rcynic.xml' -default_root = '/var/rcynic/data' -object_accepted = None # set by import_rcynic_xml() - -import time -import vobject -import logging -import os -import stat -from socket import getfqdn -from cStringIO import StringIO - -from django.db import transaction -import django.db.models - -import rpki -import rpki.left_right -import rpki.gui.app.timestamp -from rpki.gui.app.models import Conf, Alert -from rpki.gui.cacheview import models -from rpki.rcynic import rcynic_xml_iterator, label_iterator -from rpki.sundial import datetime -from rpki.irdb.zookeeper import Zookeeper - -from lxml.etree import Element, SubElement - -logger = logging.getLogger(__name__) - - -def rcynic_cert(cert, obj): - obj.sia = cert.sia_directory_uri - - # object must be saved for the related manager methods below to work - obj.save() - - # for the root cert, we can't set inst.issuer = inst until - # after inst.save() has been called. - if obj.issuer is None: - obj.issuer = obj - obj.save() - - # resources can change when a cert is updated - obj.asns.clear() - obj.addresses.clear() - - if cert.resources.asn.inherit: - # FIXME: what happens when the parent's resources change and the child - # cert is not reissued? - obj.asns.add(*obj.issuer.asns.all()) - else: - for asr in cert.resources.asn: - logger.debug('processing %s', asr) - - attrs = {'min': asr.min, 'max': asr.max} - q = models.ASRange.objects.filter(**attrs) - if not q: - obj.asns.create(**attrs) - else: - obj.asns.add(q[0]) - - # obj.issuer is None the first time we process the root cert in the - # hierarchy, so we need to guard against dereference - for cls, addr_obj, addrset, parentset in ( - models.AddressRange, obj.addresses, cert.resources.v4, - obj.issuer.addresses.all() if obj.issuer else [] - ), ( - models.AddressRangeV6, obj.addresses_v6, cert.resources.v6, - obj.issuer.addresses_v6.all() if obj.issuer else [] - ): - if addrset.inherit: - addr_obj.add(*parentset) - else: - for rng in addrset: - logger.debug('processing %s', rng) - - attrs = {'prefix_min': rng.min, 'prefix_max': rng.max} - q = cls.objects.filter(**attrs) - if not q: - addr_obj.create(**attrs) - else: - addr_obj.add(q[0]) - - -def rcynic_roa(roa, obj): - obj.asid = roa.asID - # object must be saved for the related manager methods below to work - obj.save() - obj.prefixes.clear() - obj.prefixes_v6.clear() - for pfxset in roa.prefix_sets: - if pfxset.__class__.__name__ == 'roa_prefix_set_ipv6': - roa_cls = models.ROAPrefixV6 - prefix_obj = obj.prefixes_v6 - else: - roa_cls = models.ROAPrefixV4 - prefix_obj = obj.prefixes - - for pfx in pfxset: - attrs = {'prefix_min': pfx.min(), - 'prefix_max': pfx.max(), - 'max_length': pfx.max_prefixlen} - q = roa_cls.objects.filter(**attrs) - if not q: - prefix_obj.create(**attrs) - else: - prefix_obj.add(q[0]) - - -def rcynic_gbr(gbr, obj): - vcard = vobject.readOne(gbr.vcard) - obj.full_name = vcard.fn.value if hasattr(vcard, 'fn') else None - obj.email_address = vcard.email.value if hasattr(vcard, 'email') else None - obj.telephone = vcard.tel.value if hasattr(vcard, 'tel') else None - obj.organization = vcard.org.value[0] if hasattr(vcard, 'org') else None - obj.save() - -LABEL_CACHE = {} - -# dict keeping mapping of uri to (handle, old status, new status) for objects -# published by the local rpkid -uris = {} - -dispatch = { - 'rcynic_certificate': rcynic_cert, - 'rcynic_roa': rcynic_roa, - 'rcynic_ghostbuster': rcynic_gbr -} - -model_class = { - 'rcynic_certificate': models.Cert, - 'rcynic_roa': models.ROA, - 'rcynic_ghostbuster': models.Ghostbuster -} - - -def save_status(repo, vs): - timestamp = datetime.fromXMLtime(vs.timestamp).to_sql() - status = LABEL_CACHE[vs.status] - g = models.generations_dict.get(vs.generation) - repo.statuses.create(generation=g, timestamp=timestamp, status=status) - - # if this object is in our interest set, update with the current validation - # status - if repo.uri in uris: - x, y, z, q = uris[repo.uri] - valid = z or (status is object_accepted) # don't clobber previous True value - uris[repo.uri] = x, y, valid, repo - - if status is not object_accepted: - return - - cls = model_class[vs.file_class.__name__] - # find the instance of the signedobject subclass that is associated with - # this repo instance (may be empty when not accepted) - inst_qs = cls.objects.filter(repo=repo) - - logger.debug('processing %s', vs.filename) - - if not inst_qs: - inst = cls(repo=repo) - logger.debug('object not found in db, creating new object cls=%s id=%s', - cls, id(inst)) - else: - inst = inst_qs[0] - - try: - # determine if the object is changed/new - mtime = os.stat(vs.filename)[stat.ST_MTIME] - except OSError as e: - logger.error('unable to stat %s: %s %s', - vs.filename, type(e), e) - # treat as if missing from rcynic.xml - # use inst_qs rather than deleting inst so that we don't raise an - # exception for newly created objects (inst_qs will be empty) - inst_qs.delete() - return - - if mtime != inst.mtime: - inst.mtime = mtime - try: - obj = vs.obj # causes object to be lazily loaded - except Exception, e: - logger.warning('Caught %s while processing %s: %s', - type(e), vs.filename, e) - return - - inst.not_before = obj.notBefore.to_sql() - inst.not_after = obj.notAfter.to_sql() - inst.name = obj.subject - inst.keyid = obj.ski - - # look up signing cert - if obj.issuer == obj.subject: - # self-signed cert (TA) - assert isinstance(inst, models.Cert) - inst.issuer = None - else: - # if an object has moved in the repository, the entry for - # the old location will still be in the database, but - # without any object_accepted in its validtion status - qs = models.Cert.objects.filter( - keyid=obj.aki, - name=obj.issuer, - repo__statuses__status=object_accepted - ) - ncerts = len(qs) - if ncerts == 0: - logger.warning('unable to find signing cert with ski=%s (%s)', obj.aki, obj.issuer) - return - else: - if ncerts > 1: - # multiple matching certs, all of which are valid - logger.warning('Found multiple certs matching ski=%s sn=%s', obj.aki, obj.issuer) - for c in qs: - logger.warning(c.repo.uri) - # just use the first match - inst.issuer = qs[0] - - try: - # do object-specific tasks - dispatch[vs.file_class.__name__](obj, inst) - except: - logger.error('caught exception while processing rcynic_object:\n' - 'vs=' + repr(vs) + '\nobj=' + repr(obj)) - # .show() writes to stdout - obj.show() - raise - - logger.debug('object saved id=%s', id(inst)) - else: - logger.debug('object is unchanged') - - -@transaction.atomic -def process_cache(root, xml_file): - - last_uri = None - repo = None - - logger.info('clearing validation statuses') - models.ValidationStatus.objects.all().delete() - - logger.info('updating validation status') - for vs in rcynic_xml_iterator(root, xml_file): - if vs.uri != last_uri: - repo, created = models.RepositoryObject.objects.get_or_create(uri=vs.uri) - last_uri = vs.uri - save_status(repo, vs) - - # garbage collection - # remove all objects which have no ValidationStatus references, which - # means they did not appear in the last XML output - logger.info('performing garbage collection') - - # Delete all objects that have zero validation status elements. - models.RepositoryObject.objects.annotate(num_statuses=django.db.models.Count('statuses')).filter(num_statuses=0).delete() - - # Delete all SignedObject instances that were not accepted. There may - # exist rows for objects that were previously accepted. - # See https://trac.rpki.net/ticket/588#comment:30 - # - # We have to do this here rather than in save_status() because the - # <validation_status/> elements are not guaranteed to be consecutive for a - # given URI. see https://trac.rpki.net/ticket/625#comment:5 - models.SignedObject.objects.exclude(repo__statuses__status=object_accepted).delete() - - # ROAPrefixV* objects are M2M so they are not automatically deleted when - # their ROA object disappears - models.ROAPrefixV4.objects.annotate(num_roas=django.db.models.Count('roas')).filter(num_roas=0).delete() - models.ROAPrefixV6.objects.annotate(num_roas=django.db.models.Count('roas')).filter(num_roas=0).delete() - logger.info('done with garbage collection') - - -@transaction.atomic -def process_labels(xml_file): - logger.info('updating labels...') - - for label, kind, desc in label_iterator(xml_file): - logger.debug('label=%s kind=%s desc=%s', label, kind, desc) - if kind: - q = models.ValidationLabel.objects.filter(label=label) - if not q: - obj = models.ValidationLabel(label=label) - else: - obj = q[0] - - obj.kind = models.kinds_dict[kind] - obj.status = desc - obj.save() - - LABEL_CACHE[label] = obj - - -def fetch_published_objects(): - """Query rpkid for all objects published by local users, and look up the - current validation status of each object. The validation status is used - later to send alerts for objects which have transitioned to invalid. - """ - - logger.info('querying for published objects') - - handles = [conf.handle for conf in Conf.objects.all()] - q_msg = Element(rpki.left_right.tag_msg, nsmap = rpki.left_right.nsmap, - type = "query", version = rpki.left_right.version) - for h in handles: - SubElement(q_msg, rpki.left_right.tag_list_published_objects, action="list", tenant_handle=h, tag=h) - z = Zookeeper() - r_msg = z.call_rpkid(q_msg) - for r_pdu in r_msg: - if r_pdu.tag == rpki.left_right.tag_list_published_objects: - # Look up the object in the rcynic cache - qs = models.RepositoryObject.objects.filter(uri=r_pdu.get("uri")) - if qs: - # get the current validity state - valid = qs[0].statuses.filter(status=object_accepted).exists() - uris[r_pdu.get("uri")] = (r_pdu.get("tenant_handle"), valid, False, None) - logger.debug('adding %s', r_pdu.get("uri")) - else: - # this object is not in the cache. it was either published - # recently, or disappared previously. if it disappeared - # previously, it has already been alerted. in either case, we - # omit the uri from the list since we are interested only in - # objects which were valid and are no longer valid - pass - elif r_pdu.tag == rpki.left_right.tag_report_error: - logging.error('rpkid reported an error: %s', r_pdu.get("error_code")) - - -class Handle(object): - def __init__(self): - self.invalid = [] - self.missing = [] - - def add_invalid(self, v): - self.invalid.append(v) - - def add_missing(self, v): - self.missing.append(v) - - -def notify_invalid(): - """Send email alerts to the addresses registered in ghostbuster records for - any invalid objects that were published by users of this system. - """ - - logger.info('sending notifications for invalid objects') - - # group invalid objects by user - notify = {} - for uri, v in uris.iteritems(): - handle, old_status, new_status, obj = v - - if obj is None: - # object went missing - n = notify.get(handle, Handle()) - n.add_missing(uri) - # only select valid->invalid - elif old_status and not new_status: - n = notify.get(handle, Handle()) - n.add_invalid(obj) - - for handle, v in notify.iteritems(): - conf = Conf.objects.get(handle) - - msg = StringIO() - msg.write('This is an alert about problems with objects published by ' - 'the resource handle %s.\n\n' % handle) - - if v.invalid: - msg.write('The following objects were previously valid, but are ' - 'now invalid:\n') - - for o in v.invalid: - msg.write('\n') - msg.write(o.repo.uri) - msg.write('\n') - for s in o.statuses.all(): - msg.write('\t') - msg.write(s.status.label) - msg.write(': ') - msg.write(s.status.status) - msg.write('\n') - - if v.missing: - msg.write('The following objects were previously valid but are no ' - 'longer in the cache:\n') - - for o in v.missing: - msg.write(o) - msg.write('\n') - - msg.write("""-- -You are receiving this email because your address is published in a Ghostbuster -record, or is the default email address for this resource holder account on -%s.""" % getfqdn()) - - from_email = 'root@' + getfqdn() - subj = 'invalid RPKI object alert for resource handle %s' % conf.handle - conf.send_alert(subj, msg.getvalue(), from_email, severity=Alert.ERROR) - - -def import_rcynic_xml(root=default_root, logfile=default_logfile): - """Load the contents of rcynic.xml into the rpki.gui.cacheview database.""" - - global object_accepted - - start = time.time() - process_labels(logfile) - object_accepted = LABEL_CACHE['OBJECT_ACCEPTED'] - fetch_published_objects() - process_cache(root, logfile) - notify_invalid() - - rpki.gui.app.timestamp.update('rcynic_import') - - stop = time.time() - logger.info('elapsed time %d seconds.', (stop - start)) diff --git a/rpki/gui/cacheview/views.py b/rpki/gui/cacheview/views.py deleted file mode 100644 index 451c0d1e..00000000 --- a/rpki/gui/cacheview/views.py +++ /dev/null @@ -1,173 +0,0 @@ -# Copyright (C) 2011 SPARTA, Inc. dba Cobham Analytic Solutions -# Copyright (C) 2013 SPARTA, Inc. a Parsons Company -# -# Permission to use, copy, modify, and distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND SPARTA DISCLAIMS ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -# AND FITNESS. IN NO EVENT SHALL SPARTA BE LIABLE FOR ANY SPECIAL, DIRECT, -# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE -# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -# PERFORMANCE OF THIS SOFTWARE. - -__version__ = '$Id$' - -from django.views.generic import DetailView -from django.shortcuts import render -from django.db.models import F - -from rpki.gui.cacheview import models, forms, misc -from rpki.resource_set import resource_range_as, resource_range_ip -from rpki.POW import IPAddress -from rpki.exceptions import BadIPResource - - -def cert_chain(obj): - """ - returns an iterator covering all certs from the root cert down to the EE. - """ - - chain = [obj] - while obj != obj.issuer: - obj = obj.issuer - chain.append(obj) - return zip(range(len(chain)), reversed(chain)) - - -class SignedObjectDetailView(DetailView): - def get_context_data(self, **kwargs): - context = super(SignedObjectDetailView, - self).get_context_data(**kwargs) - context['chain'] = cert_chain(self.object) - return context - - -class RoaDetailView(SignedObjectDetailView): - model = models.ROA - - -class CertDetailView(SignedObjectDetailView): - model = models.Cert - - -class GhostbusterDetailView(SignedObjectDetailView): - model = models.Ghostbuster - - -def search_view(request): - certs = None - roas = None - - if request.method == 'POST': - form = forms.SearchForm2(request.POST, request.FILES) - if form.is_valid(): - resource = form.cleaned_data.get('resource') - # try to determine the type of input given - try: - r = resource_range_as.parse_str(resource) - certs = models.Cert.objects.filter(asns__min__gte=r.min, - asns__max__lte=r.max) - roas = models.ROA.objects.filter(asid__gte=r.min, - asid__lte=r.max) - except: - try: - r = resource_range_ip.parse_str(resource) - if r.version == 4: - certs = models.Cert.objects.filter( - addresses__prefix_min__lte=r.min, - addresses__prefix_max__gte=r.max) - roas = models.ROA.objects.filter( - prefixes__prefix_min__lte=r.min, - prefixes__prefix_max__gte=r.max) - else: - certs = models.Cert.objects.filter( - addresses_v6__prefix_min__lte=r.min, - addresses_v6__prefix_max__gte=r.max) - roas = models.ROA.objects.filter( - prefixes_v6__prefix_min__lte=r.min, - prefixes_v6__prefix_max__gte=r.max) - except BadIPResource: - pass - - return render(request, 'cacheview/search_result.html', - {'resource': resource, 'certs': certs, 'roas': roas}) - - -def cmp_prefix(x, y): - r = cmp(x[0].family, y[0].family) - if r == 0: - r = cmp(x[2], y[2]) # integer address - if r == 0: - r = cmp(x[0].bits, y[0].bits) - if r == 0: - r = cmp(x[0].max_length, y[0].max_length) - if r == 0: - r = cmp(x[1].asid, y[1].asid) - return r - - -#def cmp_prefix(x,y): -# for attr in ('family', 'prefix', 'bits', 'max_length'): -# r = cmp(getattr(x[0], attr), getattr(y[0], attr)) -# if r: -# return r -# return cmp(x[1].asid, y[1].asid) - - -def query_view(request): - """ - Allow the user to search for an AS or prefix, and show all published ROA - information. - """ - - if request.method == 'POST': - form = forms.SearchForm(request.POST, request.FILES) - if form.is_valid(): - certs = None - roas = None - - addr = form.cleaned_data.get('addr') - asn = form.cleaned_data.get('asn') - - if addr: - family, r = misc.parse_ipaddr(addr) - prefixes = models.ROAPrefix.objects.filter(family=family, prefix=str(r.min)) - - prefix_list = [] - for pfx in prefixes: - for roa in pfx.roas.all(): - prefix_list.append((pfx, roa)) - elif asn: - r = resource_range_as.parse_str(asn) - roas = models.ROA.objects.filter(asid__gte=r.min, asid__lte=r.max) - - # display the results sorted by prefix - prefix_list = [] - for roa in roas: - for pfx in roa.prefixes.all(): - addr = IPAddress(pfx.prefix.encode()) - prefix_list.append((pfx, roa, addr)) - prefix_list.sort(cmp=cmp_prefix) - - return render('cacheview/query_result.html', - {'object_list': prefix_list}, request) - else: - form = forms.SearchForm() - - return render('cacheview/search_form.html', { - 'form': form, 'search_type': 'ROA '}, request) - - -def global_summary(request): - """Display a table summarizing the state of the global RPKI.""" - - roots = models.Cert.objects.filter(issuer=F('pk')) # self-signed - - return render(request, 'cacheview/global_summary.html', { - 'roots': roots - }) - -# vim:sw=4 ts=8 expandtab |