diff options
author | Michael Elkins <melkins@tislabs.com> | 2012-01-21 00:51:23 +0000 |
---|---|---|
committer | Michael Elkins <melkins@tislabs.com> | 2012-01-21 00:51:23 +0000 |
commit | f25bac0b0473490d84198e6a28185182530550c5 (patch) | |
tree | 30f829e8242a9b3f5bbb43aaf1498b3c7293245d | |
parent | aeee0dc92a2862ea778b1efe6d8628f775c2239d (diff) |
add form for creating ROA requests
svn path=/branches/tk161/; revision=4253
-rw-r--r-- | rpkid/rpki/gui/app/forms.py | 93 | ||||
-rw-r--r-- | rpkid/rpki/gui/app/views.py | 29 |
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 |