# 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 position: absolute; top: 0; left: 0; bottom: 0; } .markdown-body h1, .markdown-body h2, .markdown-body h3, .markdown-body h4, .markdown-body h5, .markdown-body h6 { margin: 20px 0 10px; padding: 0; font-weight: bold; -webkit-font-smoothing: antialiased; cursor: text; position: relative; } .markdown-body h1 .mini-icon-link, .markdown-body h2 .mini-icon-link, .markdown-body h3 .mini-icon-link, .markdown-body h4 .mini-icon-link, .markdown-body h5 .mini-icon-link, .markdown-body h6 .mini-icon-link { display: none; color: #000; } .markdown-body h1:hover a.anchor, .markdown-body h2:hover a.anchor, .markdown-body h3:hover a.anchor, .markdown-body h4:hover a.anchor, .markdown-body h5:hover a.anchor, .markdown-body h6:hover a.anchor { text-decoration: none; line-height: 1; padding-left: 0; margin-left: -22px; top: 15%; } .markdown-body h1:hover a.anchor .mini-icon-link, .markdown-body h2:hover a.anchor .mini-icon-link, .markdown-body h3:hover a.anchor .mini-icon-link, .markdown-body h4:hover a.anchor .mini-icon-link, .markdown-body h5:hover a.anchor .mini-icon-link, .markdown-body h6:hover a.anchor .mini-icon-link { display: inline-block; } div#cgit .markdown-body h1 a.toclink, div#cgit .markdown-body h2 a.toclink, div#cgit .markdown-body h3 a.toclink, div#cgit .markdown-body h4 a.toclink, div#cgit .markdown-body h5 a.toclink, div#cgit .markdown-body h6 a.toclink { color: black; } .markdown-body h1 tt, .markdown-body h1 code, .markdown-body h2 tt, .markdown-body h2 code, .markdown-body h3 tt, .markdown-body h3 code, .markdown-body h4 tt, .markdown-body h4 code, .markdown-body h5 tt, .markdown-body h5 code, .markdown-body h6 tt, .markdown-body h6 code { font-size: inherit; } .markdown-body h1 { font-size: 28px; color: #000; } .markdown-body h2 { font-size: 24px; border-bottom: 1px solid #ccc; color: #000; } .markdown-body h3 { font-size: 18px; } .markdown-body h4 { font-size: 16px; } .markdown-body h5 { font-size: 14px; } .markdown-body h6 { color: #777; font-size: 14px; } .markdown-body p, .markdown-body blockquote, .markdown-body ul, .markdown-body ol, .markdown-body dl, .markdown-body table, .markdown-body pre { margin: 15px 0; } .markdown-body hr { background: transparent url("/dirty-shade.png") repeat-x 0 0; border: 0 none; color: #ccc; height: 4px; padding: 0; } .markdown-body>h2:first-child, .markdown-body>h1:first-child, .markdown-body>h1:first-child+h2, .markdown-body>h3:first-child, .markdown-body>h4:first-child, .markdown-body>h5:first-child, .markdown-body>h6:first-child { margin-top: 0; padding-top: 0; } .markdown-body a:first-child h1, .markdown-body a:first-child h2, .markdown-body a:first-child h3, .markdown-body a:first-child h4, .markdown-body a:first-child h5, .markdown-body a:first-child h6 { margin-top: 0; padding-top: 0; } .markdown-body h1+p, .markdown-body h2+p, .markdown-body h3+p, .markdown-body h4+p, .markdown-body h5+p, .markdown-body h6+p { margin-top: 0; } .markdown-body li p.first { display: inline-block; } .markdown-body ul, .markdown-body ol { padding-left: 30px; } .markdown-body ul.no-list, .markdown-body ol.no-list { list-style-type: none; padding: 0; } .markdown-body ul li>:first-child, .markdown-body ul li ul:first-of-type, .markdown-body ul li ol:first-of-type, .markdown-body ol li>:first-child, .markdown-body ol li ul:first-of-type, .markdown-body ol li ol:first-of-type { margin-top: 0px; } .markdown-body ul li p:last-of-type, .markdown-body ol li p:last-of-type { margin-bottom: 0; } .markdown-body ul ul, .markdown-body ul ol, .markdown-body ol ol, .markdown-body ol ul { margin-bottom: 0; } .markdown-body dl { padding: 0; } .markdown-body dl dt { font-size: 14px; font-weight: bold; font-style: italic; padding: 0; margin: 15px 0 5px; } .markdown-body dl dt:first-child { padding: 0; } .markdown-body dl dt>:first-child { margin-top: 0px; } .markdown-body dl dt>:last-child { margin-bottom: 0px; } .markdown-body dl dd { margin: 0 0 15px; padding: 0 15px; } .markdown-body dl dd>:first-child { margin-top: 0px; } .markdown-body dl dd>:last-child { margin-bottom: 0px; } .markdown-body blockquote { border-left: 4px solid #DDD; padding: 0 15px; color: #777; } .markdown-body blockquote>:first-child { margin-top: 0px; } .markdown-body blockquote>:last-child { margin-bottom: 0px; } .markdown-body table th { font-weight: bold; } .markdown-body table th, .markdown-body table td { border: 1px solid #ccc; padding: 6px 13px; } .markdown-body table tr { border-top: 1px solid #ccc; background-color: #fff; } .markdown-body table tr:nth-child(2n) { background-color: #f8f8f8; } .markdown-body img { max-width: 100%; -moz-box-sizing: border-box; box-sizing: border-box; } .markdown-body span.frame { display: block; overflow: hidden; } .markdown-body span.frame>span { border: 1px solid #ddd; display: block; float: left; overflow: hidden; margin: 13px 0 0; padding: 7px; width: auto; } .markdown-body span.frame span img { display: block; float: left; } .markdown-body span.frame span span { clear: both; color: #333; display: block; padding: 5px 0 0; } .markdown-body span.align-center { display: block; overflow: hidden; clear: both; } .markdown-body span.align-center>span { display: block; overflow: hidden; margin: 13px auto 0; text-align: center; } .markdown-body span.align-center span img { margin: 0 auto; text-align: center; } .markdown-body span.align-right { display: block; overflow: hidden; clear: both; } .markdown-body span.align-right>span { display: block; overflow: hidden; margin: 13px 0 0; text-align: right; } .markdown-body span.align-right span img { margin: 0; text-align: right; } .markdown-body span.float-left { display: block; margin-right: 13px; overflow: hidden; float: left; } .markdown-body span.float-left span { margin: 13px 0 0; } .markdown-body span.float-right { display: block; margin-left: 13px; overflow: hidden; float: right; } .markdown-body span.float-right>span { display: block; overflow: hidden; margin: 13px auto 0; text-align: right; } .markdown-body code, .markdown-body tt { margin: 0 2px; padding: 0px 5px; border: 1px solid #eaeaea; background-color: #f8f8f8; border-radius: 3px; } .markdown-body code { white-space: nowrap; } .markdown-body pre>code { margin: 0; padding: 0; white-space: pre; border: none; background: transparent; } .markdown-body .highlight pre, .markdown-body pre { background-color: #f8f8f8; border: 1px solid #ccc; font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-radius: 3px; } .markdown-body pre code, .markdown-body pre tt { margin: 0; padding: 0; background-color: transparent; border: none; } pre { line-height: 125%; } td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } .highlight .hll { background-color: #ffffcc } .highlight { background: #ffffff; } .highlight .c { color: #888888 } /* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */