aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Elkins <melkins@tislabs.com>2012-01-21 00:51:23 +0000
committerMichael Elkins <melkins@tislabs.com>2012-01-21 00:51:23 +0000
commitf25bac0b0473490d84198e6a28185182530550c5 (patch)
tree30f829e8242a9b3f5bbb43aaf1498b3c7293245d
parentaeee0dc92a2862ea778b1efe6d8628f775c2239d (diff)
add form for creating ROA requests
svn path=/branches/tk161/; revision=4253
-rw-r--r--rpkid/rpki/gui/app/forms.py93
-rw-r--r--rpkid/rpki/gui/app/views.py29
2 files changed, 88 insertions, 34 deletions
diff --git a/rpkid/rpki/gui/app/forms.py b/rpkid/rpki/gui/app/forms.py
index 60e2fc8e..375e8e67 100644
--- a/rpkid/rpki/gui/app/forms.py
+++ b/rpkid/rpki/gui/app/forms.py
@@ -18,9 +18,10 @@ PERFORMANCE OF THIS SOFTWARE.
from django import forms
-import rpki.ipaddrs
-
+from rpki import resource_set
from rpki.gui.app import models
+from rpki.exceptions import BadIPResource
+
class AddConfForm(forms.Form):
handle = forms.CharField(required=True,
@@ -44,18 +45,22 @@ class AddConfForm(forms.Form):
label='Pubd contact',
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')
+ 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
resource handle.
"""
# override default form field
- parent = forms.ModelChoiceField(queryset=None, required=False, help_text='Specify specific parent, or none for all parents')
+ parent = forms.ModelChoiceField(queryset=None, required=False,
+ help_text='Specify specific parent, or none for all parents')
# override full_name. it is required in the db schema, but we allow the
# user to skip it and default from family+given name
@@ -89,14 +94,6 @@ class GhostbusterRequestForm(forms.ModelForm):
return self.cleaned_data
-class ChildForm(forms.ModelForm):
- """
- Subclass for editing rpki.gui.app.models.Child objects.
- """
-
- class Meta:
- model = models.Child
- exclude = [ 'conf', 'handle' ]
def ImportChildForm(parent_conf, *args, **kwargs):
class wrapped(forms.Form):
@@ -110,6 +107,7 @@ def ImportChildForm(parent_conf, *args, **kwargs):
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)
@@ -123,13 +121,16 @@ def ImportParentForm(conf, *args, **kwargs):
return wrapped(*args, **kwargs)
+
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')
+
class ImportPubClientForm(forms.Form):
xml = forms.FileField(help_text='xml file from publication client')
+
def ChildWizardForm(parent, *args, **kwargs):
class wrapped(forms.Form):
handle = forms.CharField(max_length=30, help_text='handle for new child')
@@ -144,34 +145,60 @@ def ChildWizardForm(parent, *args, **kwargs):
return wrapped(*args, **kwargs)
-class AddASNForm(forms.Form):
- as_range = forms.CharField(max_length=30, required=True, help_text='single AS or range')
- def clean_as_range(self):
+class ROARequest(forms.Form):
+ """Form for entering a ROA request.
+
+ Handles both IPv4 and IPv6."""
+
+ asn = forms.IntegerField()
+ prefix = forms.CharField(max_length=50)
+ max_prefixlen = forms.CharField(required=False)
+
+ def _as_resource_range(self):
+ prefix = self.cleaned_data.get('prefix')
try:
- r = resource_set.resource_range_as.parse_str(self.cleaned_data['asrange'])
- except:
- raise forms.ValidationError, 'invalid AS or range'
- return str(r)
+ r = resource_set.resource_range_ipv4.parse_str(prefix)
+ except BadIPResource:
+ r = resource_set.resource_range_ipv6.parse_str(prefix)
+ return r
-class AddAddressForm(forms.Form):
- prefix = forms.CharField(max_length=70, required=True, help_text='single IP address, CIDR or range')
+ def clean_asn(self):
+ value = self.cleaned_data.get('asn')
+ if value < 0:
+ raise forms.ValidationError, 'AS must be a positive value or 0'
+ return value
def clean_prefix(self):
- v = self.cleaned_data['prefix']
try:
- r = resource_set.resource_range_ipv4.parse_str(v)
- except rpki.exceptions.BadIPResource:
- try:
- r = resource_set.resource_range_ipv6.parse_str(v)
- except:
- raise forms.ValidationError, 'bad IP address, CIDR or range'
+ r = self._as_resource_range()
+ except:
+ raise forms.ValidationError, 'invalid IP address'
return str(r)
-class GenericConfirmationForm(forms.Form):
- """
- stub form used for doing confirmations.
- """
- pass
+ def clean_max_prefixlen(self):
+ v = self.cleaned_data.get('max_prefixlen')
+ if v:
+ if v[0] == '/':
+ v = v[1:] # allow user to specify /24
+ if int(v) < 0:
+ raise forms.ValidationError, \
+ 'max prefix length must be positive or 0'
+ return v
+
+ def clean(self):
+ if 'prefix' in self.cleaned_data:
+ r = self._as_resource_range()
+ max_prefixlen = self.cleaned_data.get('max_prefixlen')
+ max_prefixlen = int(max_prefixlen) if max_prefixlen else r.prefixlen()
+ if max_prefixlen < r.prefixlen():
+ raise (forms.ValidationError,
+ 'max prefix length must be greater than or equal to the prefix length')
+ if max_prefixlen > r.datum_type.bits:
+ raise forms.ValidationError, \
+ 'max prefix length (%d) is out of range for IP version (%d)' % (max_prefixlen, r.datum_type.bits)
+ self.cleaned_data['max_prefixlen'] = str(max_prefixlen)
+
+ return self.cleaned_data
# vim:sw=4 ts=8 expandtab
diff --git a/rpkid/rpki/gui/app/views.py b/rpkid/rpki/gui/app/views.py
index a35b4373..70696eea 100644
--- a/rpkid/rpki/gui/app/views.py
+++ b/rpkid/rpki/gui/app/views.py
@@ -424,7 +424,34 @@ def login(request):
@handle_required
def roa_create(request):
- conf = request.session['handle']
+ """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."""
+
+ if request.method == 'POST':
+ form = forms.ROARequest(request.POST, request.FILES)
+ if form.is_valid():
+ asn = form.cleaned_data.get('asn')
+ conf = request.session['handle']
+ 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.
+ roa = roarequests[0]
+ else:
+ roa = models.ROARequest.objects.create(issuer=conf, asn=asn)
+ rng = form._as_resource_range() # FIXME calling "private" method
+ max_prefixlen = int(form.cleaned_data.get('max_prefixlen'))
+ version = 'IPv4' if isinstance(rng,
+ resource_set.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))
+ else:
+ form = forms.ROARequest()
+ return render('app/roarequest_form.html', {'form': form}, request)
@handle_required