diff --git a/src/registrar/forms/__init__.py b/src/registrar/forms/__init__.py index c3aa89fed..7d2baf646 100644 --- a/src/registrar/forms/__init__.py +++ b/src/registrar/forms/__init__.py @@ -8,4 +8,6 @@ from .domain import ( DomainDnssecForm, DomainDsdataFormset, DomainDsdataForm, + DomainKeydataFormset, + DomainKeydataForm, ) diff --git a/src/registrar/forms/common.py b/src/registrar/forms/common.py new file mode 100644 index 000000000..695cb9839 --- /dev/null +++ b/src/registrar/forms/common.py @@ -0,0 +1,19 @@ +# common.py +# Q: What are the options? +ALGORITHM_CHOICES = [ + (1, "ERSA/MD5 [RSAMD5]"), + (2 , "Diffie-Hellman [DH]"), + (3 ,"DSA/SHA-1 [DSA]"), + (5 ,"RSA/SHA-1 [RSASHA1]"), +] +# Q: What are the options? +DIGEST_TYPE_CHOICES = [ + (0, "Reserved"), + (1, "SHA-256"), +] +# Flag choices +FLAG_CHOICES = [ + (0, "0"), + (256, "256"), + (257, "257"), +] diff --git a/src/registrar/forms/domain.py b/src/registrar/forms/domain.py index d7a2bba95..f74c9d345 100644 --- a/src/registrar/forms/domain.py +++ b/src/registrar/forms/domain.py @@ -1,13 +1,13 @@ """Forms for domain management.""" from django import forms -from django.core.validators import RegexValidator +from django.core.validators import MinValueValidator, MaxValueValidator, RegexValidator from django.forms import formset_factory from phonenumber_field.widgets import RegionalPhoneNumberWidget from ..models import Contact, DomainInformation - +from .common import ALGORITHM_CHOICES, DIGEST_TYPE_CHOICES, FLAG_CHOICES class DomainAddUserForm(forms.Form): @@ -149,20 +149,6 @@ class DomainDnssecForm(forms.Form): class DomainDsdataForm(forms.Form): """Form for adding or editing a security email to a domain.""" - - # Q: What are the options? - ALGORITHM_CHOICES = [ - (1, "ERSA/MD5 [RSAMD5]"), - (2 , "Diffie-Hellman [DH]"), - (3 ,"DSA/SHA-1 [DSA]"), - (5 ,"RSA/SHA-1 [RSASHA1]"), - ] - # Q: What are the options? - DIGEST_TYPE_CHOICES = [ - (0, "Reserved"), - (1, "SHA-256"), - ] - # TODO: ds key data # has_ds_key_data = forms.TypedChoiceField( # required=True, @@ -174,10 +160,8 @@ class DomainDsdataForm(forms.Form): required=True, label="Key tag", validators=[ - RegexValidator( - "^[0-9]{5}(?:-[0-9]{4})?$|^$", - message="Accepted range 0-65535.", - ) + MinValueValidator(0, "Value must be between 0 and 65535"), + MaxValueValidator(65535, "Value must be between 0 and 65535"), ], ) @@ -230,7 +214,51 @@ DomainDsdataFormset = formset_factory( ) -# TODO: -# class DomainKeyDataForm(forms.Form): +class DomainKeydataForm(forms.Form): + + """Form for adding or editing DNSSEC key data.""" + # TODO: ds key data + # has_ds_key_data = forms.TypedChoiceField( + # required=True, + # label="DS Data record type", + # choices=[(False, "DS Data"), (True, "DS Data with Key Data")], + # ) + + flag = forms.TypedChoiceField( + required=True, + label="Flag", + choices=FLAG_CHOICES, + ) + + protocol = forms.IntegerField( + max_value=3, + min_value=3, + initial=3, + required=True, + disabled=True, + ) + + algorithm = forms.TypedChoiceField( + required=True, + label="Algorithm", + choices=[(None, "--Select--")] + ALGORITHM_CHOICES, + ) -# """""" \ No newline at end of file + pub_key = forms.CharField( + required=True, + label="Pub key", + ) + + delete = forms.BooleanField( + required=False, + label="Delete", + ) + + # TODO: Conditional DS Key Data fields + + + +DomainKeydataFormset = formset_factory( + DomainKeydataForm, + extra=1, +) \ No newline at end of file diff --git a/src/registrar/templates/domain_dsdata.html b/src/registrar/templates/domain_dsdata.html index 33cb0bc49..e810be6f6 100644 --- a/src/registrar/templates/domain_dsdata.html +++ b/src/registrar/templates/domain_dsdata.html @@ -7,6 +7,16 @@

DS Data

+ {% if domain.dnssecdata is not None and domain.dnssecdata.keyData is not None %} +
+
+

Warning, you cannot add DS Data

+

+ You cannot add DS Data because you have already added Key Data. Delete your Key Data records in order to add DS Data. +

+
+
+ {% else %} {% include "includes/required_fields.html" %}
@@ -67,5 +77,5 @@ >Save
- + {% endif %} {% endblock %} {# domain_content #} diff --git a/src/registrar/templates/domain_keydata.html b/src/registrar/templates/domain_keydata.html index 6433d0c80..12c6f9082 100644 --- a/src/registrar/templates/domain_keydata.html +++ b/src/registrar/templates/domain_keydata.html @@ -7,4 +7,75 @@

Key Data

+ {% if domain.dnssecdata is not None and domain.dnssecdata.dsData is not None %} +
+
+

Warning, you cannot add Key Data

+

+ You cannot add Key Data because you have already added DS Data. Delete your DS Data records in order to add Key Data. +

+
+
+ {% else %} + {% include "includes/required_fields.html" %} + +
+ {% csrf_token %} + {{ formset.management_form }} + + {% for form in formset %} +
+ + Key Data record {{forloop.counter}} + +
+
+ {% with attr_required=True %} + {% input_with_errors form.flag %} + {% endwith %} +
+
+ {% with attr_required=True %} + {% input_with_errors form.protocol %} + {% endwith %} +
+
+ {% with attr_required=True %} + {% input_with_errors form.algorithm %} + {% endwith %} +
+
+ +
+
+ {% with attr_required=True %} + {% input_with_errors form.pub_key %} + {% endwith %} +
+
+ +
+
+ {% with add_group_class="float-right-tablet" %} + {% input_with_errors form.delete %} + {% endwith %} +
+
+ +
+ {% endfor %} + + + + +
+ {% endif %} {% endblock %} {# domain_content #} diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py index 5094c2bed..111e75812 100644 --- a/src/registrar/views/domain.py +++ b/src/registrar/views/domain.py @@ -31,6 +31,8 @@ from ..forms import ( DomainDnssecForm, DomainDsdataFormset, DomainDsdataForm, + DomainKeydataFormset, + DomainKeydataForm, ) from epplibwrapper import ( @@ -371,11 +373,116 @@ class DomainDsdataView(DomainPermissionView, FormMixin): -class DomainKeydataView(DomainPermissionView): +class DomainKeydataView(DomainPermissionView, FormMixin): """Domain DNSSEC key data editing view.""" template_name = "domain_keydata.html" + form_class = DomainKeydataFormset + form = DomainKeydataForm + + def get_initial(self): + """The initial value for the form (which is a formset here).""" + domain = self.get_object() + dnssecdata: extensions.DNSSECExtension = domain.dnssecdata + initial_data = [] + + if dnssecdata is not None: + + if dnssecdata.dsData is not None: + # TODO: Throw an error + pass + + if dnssecdata.keyData is not None: + # Add existing keydata as initial data + initial_data.extend({"flag": record.flags, "protocol": record.protocol, "algorithm": record.alg, "pub_key": record.pubKey} for record in dnssecdata.keyData) + + return initial_data + + def get_success_url(self): + """Redirect to the Key Data page for the domain.""" + return reverse("domain-dns-dnssec-keydata", kwargs={"pk": self.object.pk}) + + def get_context_data(self, **kwargs): + """Adjust context from FormMixin for formsets.""" + context = super().get_context_data(**kwargs) + # use "formset" instead of "form" for the key + context["formset"] = context.pop("form") + return context + + def post(self, request, *args, **kwargs): + """Formset submission posts to this view.""" + self.object = self.get_object() + formset = self.get_form() + + if formset.is_valid(): + return self.form_valid(formset) + else: + # + # + # + # testing delete + try: + for form in formset: + if 'delete' in form.cleaned_data: + logger.debug(f"delete: {form.cleaned_data['delete']}") + else: + logger.debug(f"delete key does not exist, harcoding false") + except KeyError: + logger.debug(f"KeyError: {KeyError}") + # + # + # + # + + return self.form_invalid(formset) + + def form_valid(self, formset): + """The formset is valid, perform something with it.""" + + # Set the nameservers from the formset + dnssecdata = {"keyData":[]} + + for form in formset: + try: + # + # + # + # untested + if 'delete' in form.cleaned_data: + if form.cleaned_data['delete'] == False: + pass + else: + # delete key exists and is true, delete this record + logger.debug(f"delete: {form.cleaned_data['delete']}") + + else: + logger.debug(f"delete key does not exist, pass") + pass + # + # + # + # + + keyrecord = { + "flags": form.cleaned_data["flag"], + "protocol": form.cleaned_data["protocol"], + "alg": form.cleaned_data["algorithm"], + "pubKey": form.cleaned_data["pub_key"], + } + dnssecdata["keyData"].append(common.DNSSECKeyData(**keyrecord)) + except KeyError: + # no server information in this field, skip it + pass + domain = self.get_object() + domain.dnssecdata = dnssecdata + + messages.success( + self.request, "The Key Data records for this domain have been updated." + ) + + # superclass has the redirect + return super().form_valid(formset) class DomainYourContactInformationView(DomainPermissionView, FormMixin):