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" %}
-
+ {% 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" %}
+
+
+ {% 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):