aboutsummaryrefslogtreecommitdiff
path: root/rpki/gui/cacheview/models.py
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2014-04-05 22:42:12 +0000
committerRob Austein <sra@hactrn.net>2014-04-05 22:42:12 +0000
commitfe0bf509f528dbdc50c7182f81057c6a4e15e4bd (patch)
tree07c9a923d4a0ccdfea11c49cd284f6d5757c5eda /rpki/gui/cacheview/models.py
parentaa28ef54c271fbe4d52860ff8cf13cab19e2207c (diff)
Source tree reorg, phase 1. Almost everything moved, no file contents changed.
svn path=/branches/tk685/; revision=5757
Diffstat (limited to 'rpki/gui/cacheview/models.py')
-rw-r--r--rpki/gui/cacheview/models.py237
1 files changed, 237 insertions, 0 deletions
diff --git a/rpki/gui/cacheview/models.py b/rpki/gui/cacheview/models.py
new file mode 100644
index 00000000..c3ee8421
--- /dev/null
+++ b/rpki/gui/cacheview/models.py
@@ -0,0 +1,237 @@
+# 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