aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Elkins <melkins@tislabs.com>2012-01-30 19:13:35 +0000
committerMichael Elkins <melkins@tislabs.com>2012-01-30 19:13:35 +0000
commit8867b8d0d247ae898e749d06a16f4fb593fe90be (patch)
treecc232520763f186401e4378161e66bcc2ea9aa57
parentcb3e16840ce29c8e46789abd083803f4f9cfd2b5 (diff)
remove dead code that is deprecated by the changes in tk100.
reformat code according to pep8 move copyright notices into comments out of docstrings svn path=/branches/tk161/; revision=4271
-rw-r--r--rpkid/rpki/gui/app/forms.py85
-rw-r--r--rpkid/rpki/gui/app/glue.py357
-rwxr-xr-xrpkid/rpki/gui/app/range_list.py16
-rw-r--r--rpkid/rpki/gui/app/templates/app/bootstrap_form.html2
-rw-r--r--rpkid/rpki/gui/app/templates/app/child_import_form.html (renamed from rpkid/rpki/gui/app/templates/app/import_child_form.html)0
-rw-r--r--rpkid/rpki/gui/app/templates/app/client_import_form.html (renamed from rpkid/rpki/gui/app/templates/app/import_pubclient_form.html)0
-rw-r--r--rpkid/rpki/gui/app/templates/app/parent_import_form.html (renamed from rpkid/rpki/gui/app/templates/app/import_parent_form.html)0
-rw-r--r--rpkid/rpki/gui/app/templates/app/respository_import_form.html (renamed from rpkid/rpki/gui/app/templates/app/import_repository_form.html)0
-rw-r--r--rpkid/rpki/gui/app/views.py495
9 files changed, 354 insertions, 601 deletions
diff --git a/rpkid/rpki/gui/app/forms.py b/rpkid/rpki/gui/app/forms.py
index 69d4b335..0755b6a0 100644
--- a/rpkid/rpki/gui/app/forms.py
+++ b/rpkid/rpki/gui/app/forms.py
@@ -1,20 +1,19 @@
-# $Id$
-"""
-Copyright (C) 2010, 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.
-"""
+# Copyright (C) 2010, 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 django import forms
@@ -46,13 +45,6 @@ class AddConfForm(forms.Form):
help_text='email address for the operator of your pubd instance')
-class ImportForm(forms.Form):
- '''Form used for uploading parent/child identity xml files'''
- handle = forms.CharField(max_length=30,
- help_text='your name for this entity')
- xml = forms.FileField(help_text='xml filename')
-
-
class GhostbusterRequestForm(forms.ModelForm):
"""
Generate a ModelForm with the subset of parents for the current
@@ -95,40 +87,27 @@ class GhostbusterRequestForm(forms.ModelForm):
return self.cleaned_data
-def ImportChildForm(parent_conf, *args, **kwargs):
- class wrapped(forms.Form):
- handle = forms.CharField(max_length=30, help_text="Child's RPKI handle")
- xml = forms.FileField(help_text="Child's identity.xml file")
-
- def clean_handle(self):
- if parent_conf.children.filter(handle=self.cleaned_data['handle']):
- raise forms.ValidationError, "a child with that handle already exists"
- return self.cleaned_data['handle']
-
- return wrapped(*args, **kwargs)
-
-
-def ImportParentForm(conf, *args, **kwargs):
- class wrapped(forms.Form):
- handle = forms.CharField(max_length=30, help_text="Parent's RPKI handle", required=True)
- xml = forms.FileField(help_text="XML response from parent", required=True,
- widget=forms.FileInput(attrs={'class': 'xlarge'}))
-
- def clean_handle(self):
- if conf.parents.filter(handle=self.cleaned_data['handle']):
- raise forms.ValidationError, "a parent with that handle already exists"
- return self.cleaned_data['handle']
-
- return wrapped(*args, **kwargs)
+class ImportForm(forms.Form):
+ """Form used for uploading parent/child identity xml files."""
+ handle = forms.CharField(required=False,
+ widget=forms.TextInput(attrs={'class': 'xlarge'}),
+ help_text='Optional. Your name for this entity, or blank to accept name in XML')
+ xml = forms.FileField(label='XML file',
+ widget=forms.FileInput(attrs={'class': 'input-file'}))
class ImportRepositoryForm(forms.Form):
- parent_handle = forms.CharField(max_length=30, required=False, help_text='(optional)')
- xml = forms.FileField(help_text='xml file from repository operator')
+ handle = forms.CharField(max_length=30, required=False,
+ label='Parent Handle',
+ help_text='Optional. Must be specified if you use a different name for this parent')
+ xml = forms.FileField(label='XML file',
+ widget=forms.FileInput(attrs={'class': 'input-file'}))
-class ImportPubClientForm(forms.Form):
- xml = forms.FileField(help_text='xml file from publication client')
+class ImportClientForm(forms.Form):
+ """Form used for importing publication client requests."""
+ xml = forms.FileField(label='XML file',
+ widget=forms.FileInput(attrs={'class': 'input-file'}))
def ChildWizardForm(parent, *args, **kwargs):
diff --git a/rpkid/rpki/gui/app/glue.py b/rpkid/rpki/gui/app/glue.py
index 99086ae6..2cc3733f 100644
--- a/rpkid/rpki/gui/app/glue.py
+++ b/rpkid/rpki/gui/app/glue.py
@@ -1,93 +1,47 @@
-# $Id$
-"""
-Copyright (C) 2010, 2011 SPARTA, Inc. dba Cobham Analytic Solutions
-Copyright (C) 2012 SPARTA, Inc. a Parsons Company
+# Copyright (C) 2010, 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.
-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.
+"""
+This file contains code that interfaces between the django views implementing
+the portal gui and the rpki.* modules.
-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 __future__ import with_statement
-import os, os.path, csv, stat, sys
-from datetime import datetime, timedelta
+__version__ = '$Id$'
-from django.db.models import F
+from datetime import datetime
-import rpki
-import rpki.left_right
-import rpki.publication
+from rpki.resource_set import (resource_set_as, resource_set_ipv4,
+ resource_set_ipv6)
+from rpki.left_right import list_received_resources_elt
from rpki.irdb.zookeeper import Zookeeper
from rpki.gui.app import models, settings
-def confpath(*handle):
- """
- Return the absolute pathname to the configuration directory for the
- given resource handle. If additional arguments are given, they are
- taken to mean files/subdirectories relative to the configuration
- directory.
-
- """
- argv = [ settings.CONFDIR ]
- argv.extend(handle)
- return os.path.join(*argv)
-
-def read_file_from_handle(handle, fname):
- """
- read a filename relative to the directory for the given resource
- handle. returns a tuple of (content, mtime)
-
- """
- with open(confpath(handle, fname), 'r') as fp:
- data = fp.read()
- mtime = os.fstat(fp.fileno())[stat.ST_MTIME]
- return data, mtime
-
-read_identity = lambda h: read_file_from_handle(h, 'entitydb/identity.xml')[0]
-
-def output_asns(path, handle):
- """Write out csv file containing asns delegated to my children."""
- qs = models.Asn.objects.filter(lo=F('hi'), allocated__in=handle.children.all())
- w = rpki.myrpki.csv_writer(path)
- w.writerows([asn.allocated.handle, asn.lo] for asn in qs)
- w.close()
-
-def output_prefixes(path, handle):
- """Write out csv file containing prefixes delegated to my children."""
- qs = models.AddressRange.objects.filter(allocated__in=handle.children.all())
- w = rpki.myrpki.csv_writer(path)
- w.writerows([p.allocated.handle, p.as_resource_range()] for p in qs)
- w.close()
-
-def output_roas(path, handle):
- """Write out csv file containing my roas."""
- qs = models.RoaRequest.objects.filter(roa__in=handle.roas.all())
- w = rpki.myrpki.csv_writer(path)
- w.writerows([req.as_roa_prefix(), req.roa.asn,
- '%s-group-%d' % (handle.handle, req.roa.pk)] for req in qs)
- w.close()
-
-def qualify_path(pfx, fname):
- """Ensure 'path' is an absolute filename."""
- return fname if fname.startswith('/') else os.path.join(pfx, fname)
def ghostbuster_to_vcard(gbr):
"""Convert a GhostbusterRequest object into a vCard object."""
import vobject
vcard = vobject.vCard()
- vcard.add('N').value = vobject.vcard.Name(family=gbr.family_name, given=gbr.given_name)
+ vcard.add('N').value = vobject.vcard.Name(family=gbr.family_name,
+ given=gbr.given_name)
- adr_fields = [ 'box', 'extended', 'street', 'city', 'region', 'code', 'country' ]
+ adr_fields = ['box', 'extended', 'street', 'city', 'region', 'code',
+ 'country']
adr_dict = dict((f, getattr(gbr, f, '')) for f in adr_fields)
if any(adr_dict.itervalues()):
vcard.add('ADR').value = vobject.vcard.Address(**adr_dict)
@@ -96,100 +50,36 @@ def ghostbuster_to_vcard(gbr):
# the ORG type is a sequence of organization unit names, so
# transform the org name into a tuple before stuffing into the
# vCard object
- attrs = [ ('FN', 'full_name', None),
- ('TEL', 'telephone', None),
- ('ORG', 'organization', lambda x: (x,)),
- ('EMAIL', 'email_address', None) ]
+ attrs = [('FN', 'full_name', None),
+ ('TEL', 'telephone', None),
+ ('ORG', 'organization', lambda x: (x,)),
+ ('EMAIL', 'email_address', None)]
for vtype, field, transform in attrs:
v = getattr(gbr, field)
if v:
vcard.add(vtype).value = transform(v) if transform else v
return vcard.serialize()
-def qualify_path(pfx, fname):
- """Ensure 'path' is an absolute filename."""
- return fname if fname.startswith('/') else os.path.join(pfx, fname)
-def configure_resources(log, handle):
+def list_received_resources(log, conf):
"""
- This function should be called when resources for this resource
- holder have changed. It updates IRDB and notifies rpkid to
- immediately process the changes, rather than waiting for the cron
- job to run.
+ Query rpkid for this resource handle's received resources.
- For backwards compatability (and backups), it also writes the csv
- files for use with the myrpki.py command line script.
+ The semantics are to clear the entire table and populate with the list of
+ certs received. Other models should not reference the table directly with
+ foreign keys.
"""
- path = confpath(handle.handle)
-
- # Read rpki.conf to determine the paths for the csv files.
- if handle.host:
- cfg = rpki.config.parser(os.path.join(path, 'rpki.conf'), section='myrpki')
- else:
- # Use the system rpki.conf for the self-hosted handle.
- cfg = get_system_config()
-
- output_asns(qualify_path(path, cfg.get('asn_csv')), handle)
- output_prefixes(qualify_path(path, cfg.get('prefix_csv')), handle)
- output_roas(qualify_path(path, cfg.get('roa_csv')), handle)
-
- roa_requests = []
- for roa in handle.roas.all():
- v4 = rpki.resource_set.roa_prefix_set_ipv4()
- v6 = rpki.resource_set.roa_prefix_set_ipv6()
- for req in roa.from_roa_request.all():
- pfx = req.as_roa_prefix()
- if isinstance(pfx, rpki.resource_set.roa_prefix_ipv4):
- v4.append(pfx)
- else:
- v6.append(pfx)
- roa_requests.append((roa.asn, v4, v6))
-
- children = []
- for child in handle.children.all():
- asns = rpki.resource_set.resource_set_as([a.as_resource_range() for a in child.asn.all()])
-
- v4 = rpki.resource_set.resource_set_ipv4()
- v6 = rpki.resource_set.resource_set_ipv6()
- for pfx in child.address_range.all():
- rng = pfx.as_resource_range()
- if isinstance(rng, rpki.resource_set.resource_range_ipv4):
- v4.append(rng)
- else:
- v6.append(rng)
-
- # Convert from datetime.datetime to rpki.sundial.datetime
- valid_until = rpki.sundial.datetime.fromdatetime(child.valid_until)
- children.append((child.handle, asns, v4, v6, valid_until))
-
- ghostbusters = []
- for gbr in handle.ghostbusters.all():
- vcard = ghostbuster_to_vcard(gbr)
- parent_set = gbr.parent.all()
- if parent_set:
- for p in parent_set:
- ghostbusters.append((p, vcard))
- else:
- ghostbusters.append((None, vcard))
-
- z.synchronize([handle])
-
-def list_received_resources(log, conf):
- """Query rpkid for this resource handle's received resources.
-
- The semantics are to clear the entire table and populate with the
- list of certs received. Other models should not reference the
- table directly with foreign keys."""
z = Zookeeper(handle=conf.handle)
- pdus = z.call_rpkid(rpki.left_right.list_received_resources_elt.make_pdu(self_handle=conf.handle))
+ pdus = z.call_rpkid(list_received_resources_elt.make_pdu(self_handle=conf.handle))
models.ResourceCert.objects.filter(parent__issuer=conf).delete()
for pdu in pdus:
- if isinstance(pdu, rpki.left_right.list_received_resources_elt):
- parent = models.Parent.objects.get(issuer=conf, handle=pdu.parent_handle)
+ if isinstance(pdu, list_received_resources_elt):
+ parent = models.Parent.objects.get(issuer=conf,
+ handle=pdu.parent_handle)
not_before = datetime.strptime(pdu.notBefore, "%Y-%m-%dT%H:%M:%SZ")
not_after = datetime.strptime(pdu.notAfter, "%Y-%m-%dT%H:%M:%SZ")
@@ -198,23 +88,25 @@ def list_received_resources(log, conf):
not_before=not_before, not_after=not_after,
uri=pdu.uri)
- for asn in rpki.resource_set.resource_set_as(pdu.asn):
+ for asn in resource_set_as(pdu.asn):
cert.asn_ranges.create(min=asn.min, max=asn.max)
- for rng in rpki.resource_set.resource_set_ipv4(pdu.ipv4):
+ for rng in resource_set_ipv4(pdu.ipv4):
print >>log, 'adding v4 address range: %s' % rng
- cert.address_ranges.create(prefix_min=rng.min, prefix_max=rng.max)
+ cert.address_ranges.create(prefix_min=rng.min,
+ prefix_max=rng.max)
- for rng in rpki.resource_set.resource_set_ipv6(pdu.ipv6):
- cert.address_ranges_v6.create(prefix_min=rng.min, prefix_max=rng.max)
+ for rng in resource_set_ipv6(pdu.ipv6):
+ cert.address_ranges_v6.create(prefix_min=rng.min,
+ prefix_max=rng.max)
else:
print >>log, "error: unexpected pdu from rpkid type=%s" % type(pdu)
+
def config_from_template(dest, a):
"""
- Create a new rpki.conf file from a generic template. Go line by
- line through the template and substitute directives from the
- dictionary 'a'.
+ Create a new rpki.conf file from a generic template. Go line by line
+ through the template and substitute directives from the dictionary 'a'.
"""
with open(dest, 'w') as f:
@@ -228,154 +120,3 @@ def config_from_template(dest, a):
print >>f, r,
else:
print >>f, r,
-
-def initialize_handle(log, handle, host, owner=None, commit=True):
- """Create a new Conf object for this user."""
- print >>log, "initializing new resource handle %s" % handle
-
- qs = models.Conf.objects.filter(handle=handle)
- if not qs:
- conf = models.Conf(handle=handle, host=host)
- conf.save()
- if owner:
- conf.owner.add(owner)
- else:
- conf = qs[0]
-
- # Create the config directory if it doesn't already exist
- top = confpath(conf.handle)
- if not os.path.exists(top):
- os.makedirs(top)
-
- # Create rpki.conf file if it doesn't exist
-# if not os.path.exists(cfg_file):
-# print >>log, "generating rpki.conf for %s" % conf.handle
-# config_from_template(cfg_file,
-# {
-# 'handle' : conf.handle,
-# 'configuration_directory': top,
-# 'run_rpkid' : 'false',
-# 'run_pubd' : 'false',
-# 'run_rootd' : 'false',
-# 'openssl' : get_system_config().get('openssl')
-# })
-
- # Load configuration for self
- z = Zookeeper(handle=conf.handle)
- identity_xml = z.initialize()
-
- if commit:
- m.synchronize([conf.handle])
-
-### CHILD ###
-
-def import_child(log, conf, child_handle, xml_file):
- """Import a child's identity.xml."""
- z = Zookeeper(handle=conf.handle)
- wrapper, handle = z.configure_child(xml_file)
- z.synchronize([conf.handle])
-
-def delete_child(log, conf, child_handle):
- z = Zookeeper(handle=conf.handle)
- z.delete_child(child_handle)
- z.synchronize([conf.handle])
-
-### PARENT ###
-
-def import_parent(log, conf, parent_handle, xml_file):
- z = Zookeeper(handle=conf.handle)
- wrapper, handle = z.configure_parent(xml_file)
- z.synchronize([conf.handle])
-
-def delete_parent(log, conf, parent_handle):
- z = Zookeeper(handle=conf.handle)
- z.delete_parent(parent_handle)
- z.synchronize([conf.handle])
-
-### PUBCLIENT ###
-
-def import_pubclient(log, conf, xml_file):
- z = Zookeeper(handle=conf.handle)
- wrapper, client_handle = z.configure_publication_client(xml_file)
- z.synchronize([conf.handle])
-
-def delete_publication_client(log, conf, client_handle):
- z = Zookeeper(handle=conf.handle)
- z.delete_publication_client(client_handle)
- z.synchronize([conf.handle])
-
-### REPO ###
-
-def import_repository(log, conf, xml_file):
- z = Zookeeper(handle=conf.handle)
- z.configure_repository(xml_file)
- z.synchronize([conf.handle])
-
-def delete_repository(log, conf, repository_handle):
- z = Zookeeper(handle=conf.handle)
- z.delete_publication_client(repository_handle)
- z.synchronize([conf.handle])
-
-def create_child(log, parent_conf, child_handle):
- """
- Implements the child create wizard to create a new locally hosted child
-
- """
- child_conf, child = initialize_handle(log, handle=child_handle, host=parent_conf, commit=False)
-
- parent_handle = parent_conf.handle
-
- parent = get_myrpki(parent_conf)
-
- child_identity_xml = os.path.join(child.cfg.get("entitydb_dir"), 'identity.xml')
- parent_response_xml = os.path.join(parent.cfg.get("entitydb_dir"), 'children', child_handle + '.xml')
- repo_req_xml = os.path.join(child.cfg.get('entitydb_dir'), 'repositories', parent_handle + '.xml')
- # XXX for now we assume the child is hosted by parent's pubd
- repo_resp_xml = os.path.join(parent.cfg.get('entitydb_dir'), 'pubclients', '%s.%s.xml' % (parent_handle, child_handle))
-
- parent.do_configure_child(child_identity_xml)
-
- child.do_configure_parent(parent_response_xml)
-
- parent.do_configure_publication_client(repo_req_xml)
-
- child.do_configure_repository(repo_resp_xml)
-
- # run twice the first time to get bsc cert issued
- sys.stdout = sys.stderr
- configure_daemons(log, child_conf, child)
- configure_daemons(log, child_conf, child)
-
-def destroy_handle(log, handle):
- conf = models.Conf.objects.get(handle=handle)
-
- z = Zookeeper(handle=conf.host.handle)
- z.delete_child(conf.handle)
- z.delete_self(handle=conf.handle)
- z.delete_publication_client(client_handle=conf.handle)
- z.synchronize([conf.host.handle])
-
- conf.delete()
-
-def read_child_response(log, conf, child_handle):
- m = get_myrpki(conf)
- bname = child_handle + '.xml'
- return open(os.path.join(m.cfg.get('entitydb_dir'), 'children', bname)).read()
-
-def read_child_repo_response(log, conf, child_handle):
- """
- Return the XML file for the configure_publication_client response to the
- child.
-
- Note: the current model assumes the publication client is a child of this
- handle.
-
- """
- m = get_myrpki(conf)
- return open(os.path.join(m.cfg.get('entitydb_dir'), 'pubclients', '%s.%s.xml' % (conf.handle, child_handle))).read()
-
-def update_bpki(log, conf):
- z = Zookeeper(handle=conf.handle)
- z.update_bpki()
-
-# vim:sw=4 ts=8 expandtab
diff --git a/rpkid/rpki/gui/app/range_list.py b/rpkid/rpki/gui/app/range_list.py
index 76547555..5fa36891 100755
--- a/rpkid/rpki/gui/app/range_list.py
+++ b/rpkid/rpki/gui/app/range_list.py
@@ -1,3 +1,19 @@
+# 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$'
+
import bisect
import unittest
diff --git a/rpkid/rpki/gui/app/templates/app/bootstrap_form.html b/rpkid/rpki/gui/app/templates/app/bootstrap_form.html
index df9620fe..f30cb4ad 100644
--- a/rpkid/rpki/gui/app/templates/app/bootstrap_form.html
+++ b/rpkid/rpki/gui/app/templates/app/bootstrap_form.html
@@ -11,7 +11,7 @@
{% else %}
<div class='clearfix {% if field.errors %}error{% endif %}'>
{{ field.label_tag }}
- {% if field.required %}<span class='required-field'>*</span>{% endif %}
+ {% if field.required %}*{% endif %}
<div class='input'>
{{ field }}
{% if field.help_text %}
diff --git a/rpkid/rpki/gui/app/templates/app/import_child_form.html b/rpkid/rpki/gui/app/templates/app/child_import_form.html
index 4b0cf9d2..4b0cf9d2 100644
--- a/rpkid/rpki/gui/app/templates/app/import_child_form.html
+++ b/rpkid/rpki/gui/app/templates/app/child_import_form.html
diff --git a/rpkid/rpki/gui/app/templates/app/import_pubclient_form.html b/rpkid/rpki/gui/app/templates/app/client_import_form.html
index acd6bf61..acd6bf61 100644
--- a/rpkid/rpki/gui/app/templates/app/import_pubclient_form.html
+++ b/rpkid/rpki/gui/app/templates/app/client_import_form.html
diff --git a/rpkid/rpki/gui/app/templates/app/import_parent_form.html b/rpkid/rpki/gui/app/templates/app/parent_import_form.html
index c192a4a4..c192a4a4 100644
--- a/rpkid/rpki/gui/app/templates/app/import_parent_form.html
+++ b/rpkid/rpki/gui/app/templates/app/parent_import_form.html
diff --git a/rpkid/rpki/gui/app/templates/app/import_repository_form.html b/rpkid/rpki/gui/app/templates/app/respository_import_form.html
index acd6bf61..acd6bf61 100644
--- a/rpkid/rpki/gui/app/templates/app/import_repository_form.html
+++ b/rpkid/rpki/gui/app/templates/app/respository_import_form.html
diff --git a/rpkid/rpki/gui/app/views.py b/rpkid/rpki/gui/app/views.py
index 9f7e6df3..0d007706 100644
--- a/rpkid/rpki/gui/app/views.py
+++ b/rpkid/rpki/gui/app/views.py
@@ -1,29 +1,29 @@
-# $Id$
+# Copyright (C) 2010, 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.
"""
-Copyright (C) 2010, 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.
+This module contains the view functions implementing the web portal
+interface.
+
"""
-from __future__ import with_statement
+__version__ = '$Id$'
-import email.message
-import email.utils
import os
import os.path
-import tempfile
+from tempfile import NamedTemporaryFile
from django.contrib.auth.decorators import login_required
from django.contrib import auth
@@ -32,30 +32,29 @@ from django.utils.http import urlquote
from django.template import RequestContext
from django import http
from django.views.generic.list_detail import object_list, object_detail
-from django.views.generic.create_update import (delete_object, update_object,
- create_object)
+from django.views.generic.create_update import delete_object
from django.core.urlresolvers import reverse
+from rpki.irdb import Zookeeper, ChildASN, ChildNet
from rpki.gui.app import models, forms, glue, range_list
-from rpki import resource_set
-import rpki.irdb
-import rpki.exceptions
+from rpki.resource_set import (resource_range_as, resource_range_ipv4,
+ resource_range_ipv6, roa_prefix_ipv4)
+from rpki.exceptions import BadIPResource
import rpki.gui.cacheview.models
import rpki.gui.routeview.models
-debug = False
-
def my_login_required(f):
"""
- A version of django.contrib.auth.decorators.login_required
- that will fail instead of redirecting to the login page when
- the user is not logged in.
+ A version of django.contrib.auth.decorators.login_required that will
+ fail instead of redirecting to the login page when the user is not
+ logged in.
For use with the rpkidemo service URLs where we want to detect
- failure to log in. Otherwise django will return code 200 with
- the login form, and fools rpkidemo.
+ failure to log in. Otherwise django will return code 200 with the
+ login form, and fools rpkidemo.
+
"""
def wrapped(request, *args, **kwargs):
if not request.user.is_authenticated():
@@ -66,9 +65,10 @@ def my_login_required(f):
def superuser_required(f):
- """Decorator which returns HttpResponseForbidden if the user does not have
- superuser permissions."""
+ """Decorator which returns HttpResponseForbidden if the user does
+ not have superuser permissions.
+ """
@login_required
def _wrapped(request, *args, **kwargs):
if not request.user.is_superuser:
@@ -76,12 +76,23 @@ def superuser_required(f):
return f(request, *args, **kwargs)
return _wrapped
-# For each type of object, we have a detail view, a create view and
-# an update view. We heavily leverage the generic views, only
-# adding our own idea of authorization.
+
+# FIXME This method is included in Django 1.3 and can be removed when Django
+# 1.2 is out of its support window.
+def render(request, template, context):
+ """
+ https://docs.djangoproject.com/en/1.3/topics/http/shortcuts/#render
+
+ """
+ return render_to_response(template, context,
+ context_instance=RequestContext(request))
def handle_required(f):
+ """Decorator for view functions which require the user to be logged in and
+ a resource handle selected for the session.
+
+ """
@login_required
def wrapped_fn(request, *args, **kwargs):
if 'handle' not in request.session:
@@ -93,7 +104,7 @@ def handle_required(f):
if conf.count() == 1:
request.session['handle'] = conf[0]
elif conf.count() == 0:
- return render('app/conf_empty.html', {}, request)
+ return render(request, 'app/conf_empty.html', {})
else:
# Should reverse the view for this instead of hardcoding
# the URL.
@@ -105,9 +116,62 @@ def handle_required(f):
return wrapped_fn
-def render(template, context, request):
- return render_to_response(template, context,
- context_instance=RequestContext(request))
+@handle_required
+def generic_import(request, queryset, configure, form_class=None,
+ template_name=None, post_import_redirect=None):
+ """
+ Generic view function for importing XML files used in the setup
+ process.
+
+ queryset
+ queryset containing all objects of the type being imported
+
+ configure
+ method on Zookeeper to invoke with the imported XML file
+
+ form_class
+ specifies the form to use for import. If None, uses the generic
+ forms.ImportForm.
+
+ template_name
+ path to the html template to use to render the form. If None, defaults
+ to "app/<model>_import_form.html", where <model> is introspected from
+ the "queryset" argument.
+
+ post_import_redirect
+ if None (default), the user will be redirected to the detail page for
+ the imported object. Otherwise, the user will be redirected to the
+ specified URL.
+
+ """
+ conf = request.session['handle']
+ if template_name is None:
+ template_name = 'app/%s_import_form.html' % queryset.model.__name__.lower()
+ if form_class is None:
+ form_class = forms.ImportForm
+ if request.method == 'POST':
+ form = form_class(request.POST, request.FILES)
+ if form.is_valid():
+ tmpf = NamedTemporaryFile(prefix='import', suffix='.xml',
+ delete=False)
+ tmpf.write(form.cleaned_data['xml'].read())
+ tmpf.close()
+ z = Zookeeper(handle=conf.handle)
+ # configure_repository returns None, so can't use tuple expansion
+ # here. Unpack the tuple below if post_import_redirect is None.
+ r = configure(z, tmpf.name, form.cleaned_data.get('handle'))
+ os.remove(tmpf.name)
+ if post_import_redirect:
+ url = post_import_redirect
+ else:
+ _, handle = r
+ url = queryset.get(issuer=conf,
+ handle=handle).get_absolute_url()
+ return http.HttpResponseRedirect(url)
+ else:
+ form = form_class()
+
+ return render(request, template_name, {'form': form})
@handle_required
@@ -120,15 +184,15 @@ def dashboard(request):
# asns used in my roas
qs = models.ROARequest.objects.filter(issuer=conf)
roa_asns = set((obj.asn for obj in qs))
- used_asns.extend((resource_set.resource_range_as(asn, asn) for asn in roa_asns))
+ used_asns.extend((resource_range_as(asn, asn) for asn in roa_asns))
# asns given to my children
- child_asns = rpki.irdb.models.ChildASN.objects.filter(child__in=conf.children.all())
- used_asns.extend((resource_set.resource_range_as(obj.start_as, obj.end_as) for obj in child_asns))
+ child_asns = ChildASN.objects.filter(child__in=conf.children.all())
+ used_asns.extend((resource_range_as(obj.start_as, obj.end_as) for obj in child_asns))
# my received asns
asns = models.ResourceRangeAS.objects.filter(cert__parent__issuer=conf)
- my_asns = range_list.RangeList([resource_set.resource_range_as(obj.min, obj.max) for obj in asns])
+ my_asns = range_list.RangeList([resource_range_as(obj.min, obj.max) for obj in asns])
unused_asns = my_asns.difference(used_asns)
@@ -136,17 +200,21 @@ def dashboard(request):
used_prefixes_v6 = range_list.RangeList()
# prefixes used in my roas
- for obj in models.ROARequestPrefix.objects.filter(roa_request__issuer=conf, version='IPv4'):
+ for obj in models.ROARequestPrefix.objects.filter(roa_request__issuer=conf,
+ version='IPv4'):
used_prefixes.append(obj.as_resource_range())
- for obj in models.ROARequestPrefix.objects.filter(roa_request__issuer=conf, version='IPv6'):
+ for obj in models.ROARequestPrefix.objects.filter(roa_request__issuer=conf,
+ version='IPv6'):
used_prefixes_v6.append(obj.as_resource_range())
# prefixes given to my children
- for obj in rpki.irdb.models.ChildNet.objects.filter(child__in=conf.children.all(), version='IPv4'):
+ for obj in ChildNet.objects.filter(child__in=conf.children.all(),
+ version='IPv4'):
used_prefixes.append(obj.as_resource_range())
- for obj in rpki.irdb.models.ChildNet.objects.filter(child__in=conf.children.all(), version='IPv6'):
+ for obj in ChildNet.objects.filter(child__in=conf.children.all(),
+ version='IPv6'):
used_prefixes_v6.append(obj.as_resource_range())
# my received prefixes
@@ -158,19 +226,21 @@ def dashboard(request):
unused_prefixes = my_prefixes.difference(used_prefixes)
unused_prefixes_v6 = my_prefixes_v6.difference(used_prefixes_v6)
- return render('app/dashboard.html', {
+ return render(request, 'app/dashboard.html', {
'conf': conf,
'unused_asns': unused_asns,
'unused_prefixes': unused_prefixes,
'unused_prefixes_v6': unused_prefixes_v6,
'asns': asns,
'prefixes': prefixes,
- 'prefixes_v6': prefixes}, request)
+ 'prefixes_v6': prefixes})
@superuser_required
def conf_list(request):
- """Allow the user to select a handle."""
+ """Allow the user to select a handle.
+
+ """
queryset = models.Conf.objects.all()
return object_list(request, queryset,
template_name='app/conf_list.html', template_object_name='conf',
@@ -179,7 +249,9 @@ def conf_list(request):
@superuser_required
def conf_select(request):
- '''Change the handle for the current session.'''
+ """Change the handle for the current session.
+
+ """
if not 'handle' in request.GET:
return http.HttpResponseRedirect('/myrpki/conf/select')
handle = request.GET['handle']
@@ -198,7 +270,9 @@ def serve_xml(content, basename):
@handle_required
def conf_export(request):
- """Return the identity.xml for the current handle."""
+ """Return the identity.xml for the current handle.
+
+ """
handle = request.session['handle']
return serve_xml(glue.read_identity(handle.handle), 'identity')
@@ -206,25 +280,8 @@ def conf_export(request):
@handle_required
def parent_import(request):
conf = request.session['handle']
- log = request.META['wsgi.errors']
-
- if request.method == 'POST':
- form = forms.ImportParentForm(conf, request.POST, request.FILES)
- if form.is_valid():
- tmpf = tempfile.NamedTemporaryFile(prefix='parent', suffix='.xml', delete=False)
- f = tmpf.name
- tmpf.write(form.cleaned_data['xml'].read())
- tmpf.close()
-
- glue.import_parent(log, conf, form.cleaned_data['handle'], f)
-
- os.remove(tmpf.name)
-
- return http.HttpResponseRedirect(reverse(dashboard))
- else:
- form = forms.ImportParentForm(conf)
-
- return render('app/import_parent_form.html', {'form': form}, request)
+ return generic_import(request, conf.parents,
+ Zookeeper.configure_parent)
@handle_required
@@ -257,29 +314,9 @@ def parent_delete(request, pk):
@handle_required
def child_import(request):
- """
- Import a repository response.
- """
conf = request.session['handle']
- log = request.META['wsgi.errors']
-
- if request.method == 'POST':
- form = forms.ImportChildForm(conf, request.POST, request.FILES)
- if form.is_valid():
- tmpf = tempfile.NamedTemporaryFile(prefix='identity', suffix='.xml', delete=False)
- f = tmpf.name
- tmpf.write(form.cleaned_data['xml'].read())
- tmpf.close()
-
- glue.import_child(log, conf, form.cleaned_data['handle'], f)
-
- os.remove(tmpf.name)
-
- return http.HttpResponseRedirect(reverse(dashboard))
- else:
- form = forms.ImportChildForm(conf)
-
- return render('app/import_child_form.html', {'form': form}, request)
+ return generic_import(request, conf.children, Zookeeper.configure_child,
+ post_import_redirect=reverse(child_list))
@handle_required
@@ -294,7 +331,8 @@ def child_list(request):
@handle_required
-def child_add_resource(request, pk, form_class, unused_list, callback, template_name='app/child_add_resource_form.html'):
+def child_add_resource(request, pk, form_class, unused_list, callback,
+ template_name='app/child_add_resource_form.html'):
conf = request.session['handle']
child = models.Child.objects.filter(issuer=conf, pk=pk)
if request.method == 'POST':
@@ -305,12 +343,12 @@ def child_add_resource(request, pk, form_class, unused_list, callback, template_
else:
form = form_class()
- return render(template_name, {'object': child, 'form': form,
- 'unused': unused_list}, request)
+ return render(request, template_name, {'object': child, 'form': form,
+ 'unused': unused_list})
def add_asn_callback(child, form):
- r = resource_set.resource_range_as.parse_str(form.as_range)
+ r = resource_range_as.parse_str(form.as_range)
child.asns.create(min=r.min, max=r.max)
@@ -321,10 +359,10 @@ def child_add_asn(request, pk):
def add_address_callback(child, form):
try:
- r = resource_set.resource_range_ipv4.parse_str(form.prefix)
+ r = resource_range_ipv4.parse_str(form.prefix)
family = 4
- except rpki.exceptions.BadIPResource:
- r = resource_set.resource_range_ipv6.parse_str(form.prefix)
+ except BadIPResource:
+ r = resource_range_ipv6.parse_str(form.prefix)
family = 6
child.address_ranges.create(min=str(r.min), max=str(r.max), family=family)
@@ -339,7 +377,7 @@ def child_view(request, pk):
'''Detail view of child for the currently selected handle.'''
handle = request.session['handle']
child = get_object_or_404(handle.children.all(), pk=pk)
- return render('app/child_view.html', {'child': child}, request)
+ return render(request, 'app/child_view.html', {'child': child})
@handle_required
@@ -357,45 +395,8 @@ def child_edit(request, pk):
else:
form = forms.ChildForm(instance=child)
- return render('app/child_form.html', {'child': child, 'form': form}, request)
-
-
-# this is similar to handle_required, except that the handle is given in URL
-def handle_or_404(request, handle):
- "ensure the requested handle is available to this user"
- if request.user.is_superuser:
- conf_set = models.Conf.objects.filter(handle=handle)
- else:
- conf_set = models.Conf.objects.filter(owner=request.user, handle=handle)
- if not conf_set:
- raise http.Http404, 'resource handle not found'
- return conf_set[0]
-
-
-def serve_file(handle, fname, content_type, error_code=404):
- content, mtime = glue.read_file_from_handle(handle, fname)
- resp = http.HttpResponse(content, mimetype=content_type)
- resp['Content-Disposition'] = 'attachment; filename=%s' % (os.path.basename(fname), )
- resp['Last-Modified'] = email.utils.formatdate(mtime, usegmt=True)
- return resp
-
-
-@my_login_required
-def download_csv(request, self_handle, fname):
- conf = handle_or_404(request, self_handle)
- return serve_file(conf.handle, fname + '.csv', 'text/csv')
-
-
-def download_asns(request, self_handle):
- return download_csv(request, self_handle, 'asns')
-
-
-def download_roas(request, self_handle):
- return download_csv(request, self_handle, 'roas')
-
-
-def download_prefixes(request, self_handle):
- return download_csv(request, self_handle, 'prefixes')
+ return render(request, 'app/child_form.html',
+ {'child': child, 'form': form})
def login(request):
@@ -405,6 +406,7 @@ def login(request):
use with rpkidemo to properly detect errors. The django login
view will return 200 with the login page when the login fails,
which is not desirable when using rpkidemo.
+
"""
log = request.META['wsgi.errors']
@@ -426,8 +428,10 @@ def login(request):
def roa_create(request):
"""Present the user with a form to create a ROA.
- Doesn't use the generic create_object() form because we need to create both
- the ROARequest and ROARequestPrefix objects."""
+ Doesn't use the generic create_object() form because we need to
+ create both the ROARequest and ROARequestPrefix objects.
+
+ """
routes = []
if request.method == 'POST':
@@ -439,16 +443,18 @@ def roa_create(request):
max_prefixlen = int(form.cleaned_data.get('max_prefixlen'))
if form.cleaned_data.get('confirmed'):
- roarequests = models.ROARequest.objects.filter(issuer=conf, asn=asn)
+ roarequests = models.ROARequest.objects.filter(issuer=conf,
+ asn=asn)
if roarequests:
- # FIXME need to handle the case where there are multiple ROAs
- # for the same AS due to prefixes delegated from different
- # resource certs.
+ # FIXME need to handle the case where there are
+ # multiple ROAs for the same AS due to prefixes
+ # delegated from different resource certs.
roa = roarequests[0]
else:
- roa = models.ROARequest.objects.create(issuer=conf, asn=asn)
+ roa = models.ROARequest.objects.create(issuer=conf,
+ asn=asn)
version = 'IPv4' if isinstance(rng,
- resource_set.resource_range_ipv4) else 'IPv6'
+ resource_range_ipv4) else 'IPv6'
roa.prefixes.create(version=version, prefix=str(rng.min),
prefixlen=rng.prefixlen(), max_prefixlen=max_prefixlen)
return http.HttpResponseRedirect(reverse(roa_list))
@@ -467,13 +473,18 @@ def roa_create(request):
else:
form = forms.ROARequest()
- return render('app/roarequest_form.html', {'form': form, 'routes': routes},
- request)
+ return render(request, 'app/roarequest_form.html',
+ {'form': form, 'routes': routes})
@handle_required
def roa_list(request):
- "Displays a list of ROARequestPrefix objects for the current resource handle."
+ """
+ Display a list of ROARequestPrefix objects for the current resource
+ handle.
+
+ """
+
conf = request.session['handle']
qs = models.ROARequestPrefix.objects.filter(roa_request__issuer=conf)
return object_list(request, queryset=qs,
@@ -483,8 +494,13 @@ def roa_list(request):
@handle_required
def roa_detail(request, pk):
- """Not implemented. This is a placeholder so that models.ROARequestPrefix.get_absolute_url
- works. The only reason it exist is so that the /delete URL works."""
+ """Not implemented.
+
+ This is a placeholder so that
+ models.ROARequestPrefix.get_absolute_url works. The only reason it
+ exist is so that the /delete URL works.
+
+ """
pass
@@ -493,10 +509,13 @@ def roa_delete(request, pk):
"""Handles deletion of a single ROARequestPrefix object.
Uses a form for double confirmation, displaying how the route
- validation status may change as a result."""
+ validation status may change as a result.
+
+ """
conf = request.session['handle']
- obj = get_object_or_404(models.ROARequestPrefix.objects, roa_request__issuer=conf, pk=pk)
+ obj = get_object_or_404(models.ROARequestPrefix.objects, roa_request__issuer=conf,
+ pk=pk)
if request.method == 'POST':
roa = obj.roa_request
@@ -512,7 +531,7 @@ def roa_delete(request, pk):
roa_pfx = obj.as_roa_prefix()
- pfx = 'prefixes' if isinstance(roa_pfx, resource_set.roa_prefix_ipv4) else 'prefixes_v6'
+ pfx = 'prefixes' if isinstance(roa_pfx, roa_prefix_ipv4) else 'prefixes_v6'
args = {'%s__prefix_min' % pfx: roa_pfx.min(),
'%s__prefix_max' % pfx: roa_pfx.max(),
'%s__max_length' % pfx: roa_pfx.max_prefixlen}
@@ -524,14 +543,15 @@ def roa_delete(request, pk):
validate_route(route, qs)
routes.append(route)
- return render('app/roa_request_confirm_delete.html', {'object': obj,
- 'routes': routes}, request)
+ return render(request, 'app/roa_request_confirm_delete.html',
+ {'object': obj, 'routes': routes})
@handle_required
def ghostbuster_list(request):
"""
Display a list of all ghostbuster requests for the current Conf.
+
"""
conf = request.session['handle']
qs = models.GhostbusterRequest.objects.filter(issuer=conf)
@@ -542,6 +562,7 @@ def ghostbuster_list(request):
def ghostbuster_view(request, pk):
"""
Display an individual ghostbuster request.
+
"""
conf = request.session['handle']
qs = models.GhostbusterRequest.objects.filter(issuer=conf)
@@ -551,17 +572,26 @@ def ghostbuster_view(request, pk):
@handle_required
def ghostbuster_delete(request, pk):
+ """
+ Handle deletion of a GhostbusterRequest object.
+
+ """
conf = request.session['handle']
- get_object_or_404(models.GhostbusterRequest, issuer=conf, pk=pk) # permission check
- return delete_object(request, model=models.GhostbusterRequest, object_id=pk,
- post_delete_redirect=reverse(ghostbuster_list),
- template_name='app/ghostbusterrequest_detail.html',
- extra_context={'confirm_delete': True})
+
+ # Ensure the GhosbusterRequest object belongs to the current user.
+ get_object_or_404(models.GhostbusterRequest, issuer=conf, pk=pk)
+
+ return delete_object(request, model=models.GhostbusterRequest,
+ object_id=pk,
+ post_delete_redirect=reverse(ghostbuster_list),
+ template_name='app/ghostbusterrequest_detail.html',
+ extra_context={'confirm_delete': True})
def _ghostbuster_edit(request, obj=None):
"""
Common code for create/edit.
+
"""
conf = request.session['handle']
form_class = forms.GhostbusterRequestForm
@@ -578,8 +608,8 @@ def _ghostbuster_edit(request, obj=None):
return http.HttpResponseRedirect(obj.get_absolute_url())
else:
form = form_class(conf, instance=obj)
- return render('app/ghostbuster_form.html', {'form': form, 'object': obj},
- request)
+ return render(request, 'app/ghostbuster_form.html',
+ {'form': form, 'object': obj})
@handle_required
@@ -599,8 +629,12 @@ def ghostbuster_create(request):
@handle_required
def refresh(request):
- "Query rpkid, update the db, and redirect back to the dashboard."
- glue.list_received_resources(request.META['wsgi.errors'], request.session['handle'])
+ """
+ Query rpkid, update the db, and redirect back to the dashboard.
+
+ """
+ glue.list_received_resources(request.META['wsgi.errors'],
+ request.session['handle'])
return http.HttpResponseRedirect(reverse(dashboard))
@@ -608,6 +642,7 @@ def refresh(request):
def initialize(request):
"""
Initialize a new user account.
+
"""
if request.method == 'POST':
form = forms.GenericConfirmationForm(request.POST)
@@ -618,13 +653,14 @@ def initialize(request):
else:
form = forms.GenericConfirmationForm()
- return render('app/initialize_form.html', {'form': form}, request)
+ return render(request, 'app/initialize_form.html', {'form': form})
@handle_required
def child_wizard(request):
"""
Wizard mode to create a new locally hosted child.
+
"""
conf = request.session['handle']
log = request.META['wsgi.errors']
@@ -639,7 +675,7 @@ def child_wizard(request):
else:
form = forms.ChildWizardForm(conf)
- return render('app/child_wizard_form.html', {'form': form}, request)
+ return render(request, 'app/child_wizard_form.html', {'form': form})
@handle_required
@@ -647,10 +683,12 @@ def export_child_response(request, child_handle):
"""
Export the XML file containing the output of the configure_child
to send back to the client.
+
"""
conf = request.session['handle']
log = request.META['wsgi.errors']
- return serve_xml(glue.read_child_response(log, conf, child_handle), child_handle)
+ return serve_xml(glue.read_child_response(log, conf, child_handle),
+ child_handle)
@handle_required
@@ -658,26 +696,27 @@ def export_child_repo_response(request, child_handle):
"""
Export the XML file containing the output of the configure_child
to send back to the client.
+
"""
conf = request.session['handle']
log = request.META['wsgi.errors']
- return serve_xml(glue.read_child_repo_response(log, conf, child_handle), child_handle)
+ return serve_xml(glue.read_child_repo_response(log, conf, child_handle),
+ child_handle)
@handle_required
def update_bpki(request):
conf = request.session['handle']
- log = request.META['wsgi.errors']
if request.method == 'POST':
form = forms.GenericConfirmationForm(request.POST, request.FILES)
if form.is_valid():
- glue.update_bpki(log, conf)
+ Zookeeper(handle=conf.handle).update_bpki()
return http.HttpResponseRedirect(reverse(dashboard))
else:
form = forms.GenericConfirmationForm()
- return render('app/update_bpki_form.html', {'form': form}, request)
+ return render(request, 'app/update_bpki_form.html', {'form': form})
@handle_required
@@ -693,41 +732,45 @@ def child_delete(request, pk):
else:
form = forms.GenericConfirmationForm()
- return render('app/child_delete_form.html', {'form': form, 'object': child}, request)
+ return render(request, 'app/child_delete_form.html',
+ {'form': form, 'object': child})
@login_required
def destroy_handle(request, handle):
"""
Completely remove a hosted resource handle.
- """
+ """
log = request.META['wsgi.errors']
if not request.user.is_superuser:
return http.HttpResponseForbidden()
- conf = get_object_or_404(models.Conf, handle=handle)
+ get_object_or_404(models.Conf, handle=handle)
if request.method == 'POST':
form = forms.GenericConfirmationForm(request.POST, request.FILES)
if form.is_valid():
glue.destroy_handle(log, handle)
- return render('app/generic_result.html',
+ return render(request, 'app/generic_result.html',
{'operation': 'Destroy ' + handle,
- 'result': 'Succeeded'}, request)
+ 'result': 'Succeeded'})
else:
form = forms.GenericConfirmationForm()
- return render('app/destroy_handle_form.html', {'form': form,
- 'handle': handle}, request)
+ return render(request, 'app/destroy_handle_form.html',
+ {'form': form, 'handle': handle})
def roa_match(rng):
- "Return a list of tuples of matching routes and roas."
+ """
+ Return a list of tuples of matching routes and roas.
+
+ """
object_accepted = rpki.gui.cacheview.models.ValidationLabel.objects.get(label='object_accepted')
- if isinstance(rng, rpki.resource_set.resource_range_ipv6):
+ if isinstance(rng, resource_range_ipv6):
route_manager = rpki.gui.routeview.models.RouteOriginV6.objects
pfx = 'prefixes_v6'
else:
@@ -751,7 +794,9 @@ def roa_match(rng):
def validate_route(route, roas):
"""Annotate the route object with its validation status.
- `roas` is a queryset containing ROAs which cover `route`. """
+ `roas` is a queryset containing ROAs which cover `route`.
+
+ """
pfx = 'prefixes' if isinstance(route, rpki.gui.routeview.models.RouteOrigin) else 'prefixes_v6'
args = {'asid': route.asn,
'%s__prefix_min__lte' % pfx: route.prefix_min,
@@ -762,7 +807,8 @@ def validate_route(route, roas):
if not roas.exists():
route.status = 'unknown'
route.status_label = 'warning'
- # 3. if any candidate roa matches the origin AS and max_length, end with valid
+ # 3. if any candidate roa matches the origin AS and max_length, end with
+ # valid
#
# AS0 is always invalid.
elif route.asn != 0 and roas.filter(**args).exists():
@@ -779,10 +825,10 @@ def validate_route(route, roas):
@handle_required
def route_view(request):
"""
- Display a list of global routing table entries which match resources listed
- in received certificates.
- """
+ Display a list of global routing table entries which match resources
+ listed in received certificates.
+ """
conf = request.session['handle']
log = request.META['wsgi.errors']
@@ -797,58 +843,47 @@ def route_view(request):
routes.extend([validate_route(*x) for x in roa_match(r)])
ts = dict((attr['name'], attr['ts']) for attr in models.Timestamp.objects.values())
- return render('app/routes_view.html', {'routes': routes, 'timestamp': ts}, request)
+ return render(request, 'app/routes_view.html',
+ {'routes': routes, 'timestamp': ts})
@handle_required
def repository_list(request):
conf = request.session['handle']
qs = models.Repository.objects.filter(issuer=conf)
- return object_list(request, queryset=qs, template_name='app/repository_list.html',
- extra_context={
- 'create_url': reverse(repository_import),
- 'create_label': u'Import'})
+ return object_list(request, queryset=qs,
+ template_name='app/repository_list.html',
+ extra_context={
+ 'create_url': reverse(repository_import),
+ 'create_label': u'Import'})
@handle_required
def repository_detail(request, pk):
conf = request.session['handle']
qs = models.Repository.objects.filter(issuer=conf)
- return object_detail(request, queryset=qs, object_id=pk, template_name='app/repository_detail.html')
+ return object_detail(request, queryset=qs, object_id=pk,
+ template_name='app/repository_detail.html')
@handle_required
def repository_delete(request, pk):
conf = request.session['handle']
- get_object_or_404(models.Repository, issuer=conf, pk=pk) # permission check
+ # Ensure the repository being deleted belongs to the current user.
+ get_object_or_404(models.Repository, issuer=conf, pk=pk)
return delete_object(request, model=models.Repository, object_id=pk,
post_delete_redirect=reverse(repository_list),
template_name='app/repository_detail.html',
extra_context={'confirm_delete': True})
-@handle_required
+@superuser_required
def repository_import(request):
- conf = request.session['handle']
- log = request.META['wsgi.errors']
-
- if request.method == 'POST':
- form = forms.ImportRepositoryForm(request.POST, request.FILES)
- if form.is_valid():
- tmpf = tempfile.NamedTemporaryFile(prefix='repository', suffix='.xml', delete=False)
- f = tmpf.name
- tmpf.write(form.cleaned_data['xml'].read())
- tmpf.close()
-
- glue.import_repository(log, conf, f)
-
- os.remove(tmpf.name)
-
- return http.HttpResponseRedirect(reverse(dashboard))
- else:
- form = forms.ImportRepositoryForm()
-
- return render('app/import_repository_form.html', {'form': form}, request)
+ return generic_import(request,
+ models.Repository.objects,
+ Zookeeper.configure_repository,
+ form_class=forms.ImportClientForm,
+ post_import_redirect=reverse(repository_list))
@superuser_required
@@ -872,25 +907,7 @@ def client_delete(request, pk):
@superuser_required
def client_import(request):
- conf = request.session['handle']
- log = request.META['wsgi.errors']
-
- if request.method == 'POST':
- form = forms.ImportPubClientForm(request.POST, request.FILES)
- if form.is_valid():
- tmpf = tempfile.NamedTemporaryFile(prefix='pubclient', suffix='.xml', delete=False)
- f = tmpf.name
- tmpf.write(form.cleaned_data['xml'].read())
- tmpf.close()
-
- glue.import_pubclient(log, conf, f)
-
- os.remove(tmpf.name)
-
- return http.HttpResponseRedirect(reverse(dashboard))
- else:
- form = forms.ImportPubClientForm()
-
- return render('app/import_pubclient_form.html', {'form': form}, request)
-
-# vim:sw=4 ts=8 expandtab
+ return generic_import(request, models.Client.objects,
+ Zookeeper.configure_publication_client,
+ form_class=forms.ImportClientForm,
+ post_import_redirect=reverse(client_list))