The Domain Name System (DNS) is the internet service that translates your domain name into an IP address. Before your .gov domain can be used, you'll need to connect it to your DNS hosting service and provide us with your name server information.
+
+
You can enter your name services, as well as other DNS-related information, in the following sections:
+
+ {% url 'domain-nameservers' pk=domain.id as url %}
+
DNSSEC, or DNS Security Extensions, is additional security layer to protect your website. Enabling DNSSEC ensures that when someone visits your website, they can be certain that it's connecting to the correct server, preventing potential hijacking or tampering with your domain's records. Read more about DNSSEC and why it is important.
DNSSEC, or DNS Security Extensions, is additional security layer to protect your website. Enabling DNSSEC ensures that when someone visits your website, they can be certain that it's connecting to the correct server, preventing potential hijacking or tampering with your domain's records. Read more about DNSSEC and why it is important.
+
DNSSEC, or DNS Security Extensions, is additional security layer to protect your website. Enabling DNSSEC ensures that when someone visits your website, they can be certain that it's connecting to the correct server, preventing potential hijacking or tampering with your domain's records. Read more about DNSSEC and why it is important.
+ {% csrf_token %}
+ {{ formset.management_form }}
+
+ {% for form in formset %}
+
+ {% 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):
From 0725b3c244203c75524f4ad1afe7e847ba32762e Mon Sep 17 00:00:00 2001
From: David Kennedy
Date: Tue, 3 Oct 2023 12:26:41 -0400
Subject: [PATCH 15/65] some updates to error handling, deletes, etc
---
src/registrar/templates/domain_dnssec.html | 4 +-
src/registrar/views/domain.py | 163 ++++++++-------------
2 files changed, 61 insertions(+), 106 deletions(-)
diff --git a/src/registrar/templates/domain_dnssec.html b/src/registrar/templates/domain_dnssec.html
index 675cbc087..032992014 100644
--- a/src/registrar/templates/domain_dnssec.html
+++ b/src/registrar/templates/domain_dnssec.html
@@ -27,11 +27,11 @@
In order to enable DNSSEC and add Delegation Signer (DS) records, you must first configure it with your DNS hosting service. Your configuration will determine whether you need to add DS Data or Key Data. Contact your DNS hosting provider if you are unsure which record type to add.
{% else %}
diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py
index 111e75812..5d3ca47c8 100644
--- a/src/registrar/views/domain.py
+++ b/src/registrar/views/domain.py
@@ -38,6 +38,7 @@ from ..forms import (
from epplibwrapper import (
common,
extensions,
+ RegistryError,
)
from ..utility.email import send_templated_email, EmailSendingError
@@ -252,8 +253,18 @@ class DomainDNSSECView(DomainPermissionView, FormMixin):
if 'enable_dnssec' in request.POST:
self.domain.dnssec_enabled = True
self.domain.save()
+ elif 'cancel' in request.POST:
+ self.domain.dnssec_enabled = False
+ self.domain.save()
elif 'disable_dnssec' in request.POST:
- self.domain.dnssecdata = {}
+ try:
+ self.domain.dnssecdata = {}
+ except RegistryError as err:
+ errmsg = "Error removing existing DNSSEC record(s)."
+ logger.error(errmsg + ": " + err)
+ messages.error(
+ self.request, errmsg
+ )
self.domain.dnssec_enabled = False
self.domain.save()
@@ -305,23 +316,6 @@ class DomainDsdataView(DomainPermissionView, FormMixin):
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):
@@ -332,45 +326,34 @@ class DomainDsdataView(DomainPermissionView, FormMixin):
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
- #
- #
- #
- #
-
- dsrecord = {
- "keyTag": form.cleaned_data["key_tag"],
- "alg": form.cleaned_data["algorithm"],
- "digestType": form.cleaned_data["digest_type"],
- "digest": form.cleaned_data["digest"],
- }
- dnssecdata["dsData"].append(common.DSData(**dsrecord))
+ if 'delete' in form.cleaned_data and form.cleaned_data['delete'] == True:
+ dsrecord = {
+ "keyTag": form.cleaned_data["key_tag"],
+ "alg": form.cleaned_data["algorithm"],
+ "digestType": form.cleaned_data["digest_type"],
+ "digest": form.cleaned_data["digest"],
+ }
+ dnssecdata["dsData"].append(common.DSData(**dsrecord))
except KeyError:
# no server information in this field, skip it
pass
domain = self.get_object()
- domain.dnssecdata = dnssecdata
-
- messages.success(
- self.request, "The DS Data records for this domain have been updated."
- )
-
- # superclass has the redirect
- return super().form_valid(formset)
-
+ try:
+ domain.dnssecdata = dnssecdata
+ except RegistryError as err:
+ errmsg = "Error updating DNSSEC data in the registry."
+ logger.error(f"{{ errmsg }}: {{ err }}")
+ messages.error(
+ self.request, errmsg
+ )
+ return self.form_invalid(formset)
+ else:
+ messages.success(
+ self.request, "The DS Data records for this domain have been updated."
+ )
+ # superclass has the redirect
+ return super().form_valid(formset)
+
class DomainKeydataView(DomainPermissionView, FormMixin):
@@ -418,23 +401,6 @@ class DomainKeydataView(DomainPermissionView, FormMixin):
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):
@@ -445,44 +411,33 @@ class DomainKeydataView(DomainPermissionView, FormMixin):
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))
+ if 'delete' in form.cleaned_data and form.cleaned_data['delete'] == True:
+ 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)
+ try:
+ domain.dnssecdata = dnssecdata
+ except RegistryError as err:
+ errmsg = "Error updating DNSSEC data in the registry."
+ logger.error(f"{{ errmsg }}: {{ err }}")
+ messages.error(
+ self.request, errmsg
+ )
+ return self.form_invalid(formset)
+ else:
+ 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):
From faae7693c4b45cbda0833a607abb25485765fb29 Mon Sep 17 00:00:00 2001
From: Rachid Mrad
Date: Tue, 3 Oct 2023 14:06:59 -0400
Subject: [PATCH 16/65] implemented new in domain model dnssec_ds_confirmed and
dnssec_key_confirmed to control intial blurb msg on the add pages, cleaned up
JS
---
src/registrar/assets/js/get-gov.js | 41 ++++++++++++++++++-
...034_domain_dnssec_ds_confirmed_and_more.py | 28 +++++++++++++
src/registrar/models/domain.py | 10 +++++
src/registrar/templates/domain_dnssec.html | 2 +-
src/registrar/templates/domain_dsdata.html | 10 +++++
src/registrar/templates/domain_keydata.html | 10 +++++
src/registrar/views/domain.py | 16 ++++++++
7 files changed, 115 insertions(+), 2 deletions(-)
create mode 100644 src/registrar/migrations/0034_domain_dnssec_ds_confirmed_and_more.py
diff --git a/src/registrar/assets/js/get-gov.js b/src/registrar/assets/js/get-gov.js
index 1ffdeb1c6..109d18b3d 100644
--- a/src/registrar/assets/js/get-gov.js
+++ b/src/registrar/assets/js/get-gov.js
@@ -292,7 +292,46 @@ function handleValidationClick(e) {
newForm.innerHTML = newForm.innerHTML.replace(formLabelRegex, `DS Data Record ${formNum+1}`)
// newForm.innerHTML = newForm.innerHTML.replace(formExampleRegex, `ns${formNum+1}`)
container.insertBefore(newForm, addButton)
- newForm.querySelector("input").value = ""
+
+ let inputs = newForm.querySelectorAll("input");
+
+ // Reset the values of each input to blank
+ inputs.forEach((input) => {
+ input.classList.remove("usa-input--error");
+ if (input.type === "text" || input.type === "number" || input.type === "password") {
+ input.value = ""; // Set the value to an empty string
+
+ } else if (input.type === "checkbox" || input.type === "radio") {
+ input.checked = false; // Uncheck checkboxes and radios
+ }
+ });
+
+ let selects = newForm.querySelectorAll("select");
+
+ selects.forEach((select) => {
+ select.classList.remove("usa-input--error");
+ select.selectedIndex = 0; // Set the value to an empty string
+ });
+
+
+ let labels = newForm.querySelectorAll("label");
+ labels.forEach((label) => {
+ label.classList.remove("usa-label--error");
+ });
+
+
+ let usaFormGroups = newForm.querySelectorAll(".usa-form-group");
+ usaFormGroups.forEach((usaFormGroup) => {
+ usaFormGroup.classList.remove("usa-form-group--error");
+ });
+
+ let usaErrorMessages = newForm.querySelectorAll(".usa-error-message");
+ usaErrorMessages.forEach((usaErrorMessage) => {
+ let parentDiv = usaErrorMessage.closest('div');
+ if (parentDiv) {
+ parentDiv.remove(); // Remove the parent div if it exists
+ }
+ });
totalForms.setAttribute('value', `${formNum+1}`)
}
diff --git a/src/registrar/migrations/0034_domain_dnssec_ds_confirmed_and_more.py b/src/registrar/migrations/0034_domain_dnssec_ds_confirmed_and_more.py
new file mode 100644
index 000000000..72513a401
--- /dev/null
+++ b/src/registrar/migrations/0034_domain_dnssec_ds_confirmed_and_more.py
@@ -0,0 +1,28 @@
+# Generated by Django 4.2.1 on 2023-10-03 17:34
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("registrar", "0033_domain_dnssec_enabled"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="domain",
+ name="dnssec_ds_confirmed",
+ field=models.BooleanField(
+ default=False,
+ help_text="Boolean indicating if DS record adding is confirmed",
+ ),
+ ),
+ migrations.AddField(
+ model_name="domain",
+ name="dnssec_key_confirmed",
+ field=models.BooleanField(
+ default=False,
+ help_text="Boolean indicating if Key record adding is confirmed",
+ ),
+ ),
+ ]
diff --git a/src/registrar/models/domain.py b/src/registrar/models/domain.py
index 18ac8262f..0f2436bf7 100644
--- a/src/registrar/models/domain.py
+++ b/src/registrar/models/domain.py
@@ -711,6 +711,16 @@ class Domain(TimeStampedModel, DomainHelper):
default=False,
help_text="Boolean indicating if dnssec is enabled",
)
+
+ dnssec_ds_confirmed = models.BooleanField(
+ default=False,
+ help_text="Boolean indicating if DS record adding is confirmed",
+ )
+
+ dnssec_key_confirmed = models.BooleanField(
+ default=False,
+ help_text="Boolean indicating if Key record adding is confirmed",
+ )
# ForeignKey on UserDomainRole creates a "permissions" member for
# all of the user-roles that are in place for this domain
diff --git a/src/registrar/templates/domain_dnssec.html b/src/registrar/templates/domain_dnssec.html
index 032992014..95af919d3 100644
--- a/src/registrar/templates/domain_dnssec.html
+++ b/src/registrar/templates/domain_dnssec.html
@@ -9,7 +9,7 @@
DNSSEC, or DNS Security Extensions, is additional security layer to protect your website. Enabling DNSSEC ensures that when someone visits your website, they can be certain that it's connecting to the correct server, preventing potential hijacking or tampering with your domain's records. Read more about DNSSEC and why it is important.
-
+
{% csrf_token %}
{% if not domain.dnssec_enabled %}
In order to enable DNSSEC and add DS records, you must first configure it with your DNS hosting service. Your configuration will determine whether you need to add DS Data or Key Data. Contact your DNS hosting provider if you are unsure which record type to add.
In order to enable DNSSEC and add DS records, you must first configure it with your DNS hosting service. Your configuration will determine whether you need to add DS Data or Key Data. Contact your DNS hosting provider if you are unsure which record type to add.
{% url 'domain-dns-dnssec-dsdata' pk=domain.id as url %}
diff --git a/src/registrar/templatetags/url_helpers.py b/src/registrar/templatetags/url_helpers.py
index 5b76c116f..2b983930f 100644
--- a/src/registrar/templatetags/url_helpers.py
+++ b/src/registrar/templatetags/url_helpers.py
@@ -18,6 +18,11 @@ def startswith(text, starts):
return text.startswith(starts)
return False
+@register.filter("endswith")
+def endswith(text, ends):
+ if isinstance(text, str):
+ return text.endswith(ends)
+ return False
@register.simple_tag
def public_site_url(url_path):
From 170708ecf3bdd8144b61a637dd3ece29e6c9dee3 Mon Sep 17 00:00:00 2001
From: Rachid Mrad
Date: Thu, 5 Oct 2023 16:29:19 -0400
Subject: [PATCH 31/65] modal and js toggler wip
---
src/registrar/assets/js/get-gov.js | 23 +++-
src/registrar/templates/domain_dnssec.html | 139 ++++++++++++++++----
src/registrar/templates/includes/modal.html | 42 ++++++
src/registrar/views/domain.py | 39 ++++--
4 files changed, 202 insertions(+), 41 deletions(-)
create mode 100644 src/registrar/templates/includes/modal.html
diff --git a/src/registrar/assets/js/get-gov.js b/src/registrar/assets/js/get-gov.js
index 17d4c4d6a..cfe6066e8 100644
--- a/src/registrar/assets/js/get-gov.js
+++ b/src/registrar/assets/js/get-gov.js
@@ -469,4 +469,25 @@ function prepareDeleteButtons() {
// }
// });
// }
-// })();
\ No newline at end of file
+// })();
+
+
+/**
+ *
+ *
+ */
+(function toggleDNSSECWarning() {
+ document.getElementById("toggler1").addEventListener("click", function () {
+ var element = document.getElementById("step-1");
+ var element2 = document.getElementById("step-2");
+ element.classList.toggle("display-none");
+ element2.classList.toggle("display-none");
+ });
+
+ document.getElementById("toggler2").addEventListener("click", function () {
+ var element = document.getElementById("step-1");
+ var element2 = document.getElementById("step-2");
+ element.classList.toggle("display-none");
+ element2.classList.toggle("display-none");
+ });
+})();
\ No newline at end of file
diff --git a/src/registrar/templates/domain_dnssec.html b/src/registrar/templates/domain_dnssec.html
index e21bb9458..80bcd7b50 100644
--- a/src/registrar/templates/domain_dnssec.html
+++ b/src/registrar/templates/domain_dnssec.html
@@ -11,40 +11,121 @@
{% csrf_token %}
- {% if not domain.dnssec_enabled %}
-
-
- It is strongly recommended that you do not enable this unless you fully understand DNSSEC and know how to set it up properly. If you make a mistake, it could cause your domain name to stop working.
-
In order to enable DNSSEC and add Delegation Signer (DS) records, you must first configure it with your DNS hosting service. Your configuration will determine whether you need to add DS Data or Key Data. Contact your DNS hosting provider if you are unsure which record type to add.
+ It is strongly recommended that you do not enable this unless you fully understand DNSSEC and know how to set it up properly. If you make a mistake, it could cause your domain name to stop working.
+
+
+ Enable DNSSEC
+
+
+
+
Add DS Records
+
In order to enable DNSSEC and add Delegation Signer (DS) records, you must first configure it with your DNS hosting service. Your configuration will determine whether you need to add DS Data or Key Data. Contact your DNS hosting provider if you are unsure which record type to add.
+ {% include 'includes/modal.html' with modal_heading="Are you sure you want to continue?" modal_description="Your DNSSEC records will be deleted from the registry." modal_button=modal_button|safe %}
+
+
+
+ {% comment %}
+
+
+
+ Are you sure you want to continue?
+
+
+
+ Your DNSSEC records will be deleted from the registry.
+
\ No newline at end of file
diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py
index f7483c6e0..6358bf39a 100644
--- a/src/registrar/views/domain.py
+++ b/src/registrar/views/domain.py
@@ -233,6 +233,32 @@ class DomainDNSSECView(DomainPermissionView, FormMixin):
template_name = "domain_dnssec.html"
form_class = DomainDnssecForm
+ clicked_enable_dns = False
+
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ """The initial value for the form (which is a formset here)."""
+ self.domain = self.get_object()
+
+ has_dnssec_records = self.domain.dnssecdata is not None
+
+ logger.debug(f"clicked_enable_dns {self.clicked_enable_dns}")
+
+ # if does_not_have_dnssec_records and self.clicked_enable_dns == False:
+ # logger.debug(f"clicked_enable_dns {self.clicked_enable_dns}")
+ # self.domain.dnssec_enabled = False
+ # self.domain.dnssec_ds_confirmed = False
+ # self.domain.dnssec_key_confirmed = False
+ # self.domain.save()
+
+ # Create HTML for the buttons
+ modal_button = 'Disable DNSSEC'
+
+ context['modal_button'] = modal_button
+ context['has_dnssec_records'] = has_dnssec_records
+ context['domain'] = self.domain
+
+ return context
def get_success_url(self):
"""Redirect to the DNSSEC page for the domain."""
@@ -243,16 +269,8 @@ class DomainDNSSECView(DomainPermissionView, FormMixin):
"""
self.domain = self.get_object()
form = self.get_form()
- if form.is_valid():
- if 'enable_dnssec' in request.POST:
- self.domain.dnssec_enabled = True
- self.domain.save()
- elif 'cancel' in request.POST:
- self.domain.dnssec_enabled = False
- self.domain.dnssec_ds_confirmed = False
- self.domain.dnssec_key_confirmed = False
- self.domain.save()
- elif 'disable_dnssec' in request.POST:
+ if form.is_valid():
+ if 'disable_dnssec' in request.POST:
try:
self.domain.dnssecdata = {}
except RegistryError as err:
@@ -261,7 +279,6 @@ class DomainDNSSECView(DomainPermissionView, FormMixin):
messages.error(
self.request, errmsg
)
- self.domain.dnssec_enabled = False
self.domain.dnssec_ds_confirmed = False
self.domain.dnssec_key_confirmed = False
self.domain.save()
From 13e294d0d2d5bb1eb7b648e0f1798db8c4564f71 Mon Sep 17 00:00:00 2001
From: Rachid Mrad
Date: Thu, 5 Oct 2023 16:54:01 -0400
Subject: [PATCH 32/65] clean up JS and dnssec template
---
src/registrar/assets/js/get-gov.js | 22 +++---
src/registrar/templates/domain_dnssec.html | 81 +++-------------------
src/registrar/views/domain.py | 6 +-
3 files changed, 20 insertions(+), 89 deletions(-)
diff --git a/src/registrar/assets/js/get-gov.js b/src/registrar/assets/js/get-gov.js
index cfe6066e8..36d5f257a 100644
--- a/src/registrar/assets/js/get-gov.js
+++ b/src/registrar/assets/js/get-gov.js
@@ -472,22 +472,18 @@ function prepareDeleteButtons() {
// })();
+function toggleElements() {
+ let element1 = document.getElementById("enable-dnssec");
+ let element2 = document.getElementById("add-records");
+ element1.classList.toggle("display-none");
+ element2.classList.toggle("display-none");
+}
+
/**
*
*
*/
(function toggleDNSSECWarning() {
- document.getElementById("toggler1").addEventListener("click", function () {
- var element = document.getElementById("step-1");
- var element2 = document.getElementById("step-2");
- element.classList.toggle("display-none");
- element2.classList.toggle("display-none");
- });
-
- document.getElementById("toggler2").addEventListener("click", function () {
- var element = document.getElementById("step-1");
- var element2 = document.getElementById("step-2");
- element.classList.toggle("display-none");
- element2.classList.toggle("display-none");
- });
+ document.getElementById("enable_dnssec").addEventListener("click", toggleElements);
+ document.getElementById("cancel_dnssec").addEventListener("click", toggleElements);
})();
\ No newline at end of file
diff --git a/src/registrar/templates/domain_dnssec.html b/src/registrar/templates/domain_dnssec.html
index 80bcd7b50..903020c93 100644
--- a/src/registrar/templates/domain_dnssec.html
+++ b/src/registrar/templates/domain_dnssec.html
@@ -11,7 +11,7 @@
{% csrf_token %}
- {% if domain.has_dnssec_records %}
+ {% if has_dnssec_records %}
In order to fully disable DNSSEC on your domain, you will need to work with your DNS provider to remove your DNSSEC-related records from your zone.
@@ -25,7 +25,7 @@
>Disable DNSSEC
{% else %}
-
+
It is strongly recommended that you do not enable this unless you fully understand DNSSEC and know how to set it up properly. If you make a mistake, it could cause your domain name to stop working.
@@ -35,11 +35,11 @@
type="button"
class="usa-button"
name="enable_dnssec"
- id="toggler1"
+ id="enable_dnssec"
>Enable DNSSEC
-
+
Add DS Records
In order to enable DNSSEC and add Delegation Signer (DS) records, you must first configure it with your DNS hosting service. Your configuration will determine whether you need to add DS Data or Key Data. Contact your DNS hosting provider if you are unsure which record type to add.
@@ -48,84 +48,21 @@
Cancel
-
-
-
-
-
-
{% endif %}
{% include 'includes/modal.html' with modal_heading="Are you sure you want to continue?" modal_description="Your DNSSEC records will be deleted from the registry." modal_button=modal_button|safe %}
-
- {% comment %}
-
-
-
- Are you sure you want to continue?
-
-
-
- Your DNSSEC records will be deleted from the registry.
-
-
-
-
-
-
-
-
-
-
-
{% endcomment %}
-
-
{% endblock %} {# domain_content #}
diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py
index 6358bf39a..12ce50606 100644
--- a/src/registrar/views/domain.py
+++ b/src/registrar/views/domain.py
@@ -241,9 +241,7 @@ class DomainDNSSECView(DomainPermissionView, FormMixin):
self.domain = self.get_object()
has_dnssec_records = self.domain.dnssecdata is not None
-
- logger.debug(f"clicked_enable_dns {self.clicked_enable_dns}")
-
+
# if does_not_have_dnssec_records and self.clicked_enable_dns == False:
# logger.debug(f"clicked_enable_dns {self.clicked_enable_dns}")
# self.domain.dnssec_enabled = False
@@ -256,7 +254,7 @@ class DomainDNSSECView(DomainPermissionView, FormMixin):
context['modal_button'] = modal_button
context['has_dnssec_records'] = has_dnssec_records
- context['domain'] = self.domain
+ # context['domain'] = self.domain
return context
From 3e8dc743197dcf290c251c634b8416d3de2ed58c Mon Sep 17 00:00:00 2001
From: Rachid Mrad
Date: Thu, 5 Oct 2023 17:36:43 -0400
Subject: [PATCH 33/65] cleanup
---
src/registrar/assets/js/get-gov.js | 96 +--------------------
src/registrar/templates/domain_keydata.html | 5 +-
2 files changed, 2 insertions(+), 99 deletions(-)
diff --git a/src/registrar/assets/js/get-gov.js b/src/registrar/assets/js/get-gov.js
index 36d5f257a..99c689ddf 100644
--- a/src/registrar/assets/js/get-gov.js
+++ b/src/registrar/assets/js/get-gov.js
@@ -279,17 +279,6 @@ function prepareDeleteButtons() {
let formNum2 = forms.length;
totalForms.setAttribute('value', `${formNum2}`);
- // We need to fix the indicies of every existing form otherwise
- // the frontend and backend will not match and will error on submit
- // let formNumberRegex = RegExp(`form-(\\d){1}-`,'g');
- // let formLabelRegex = RegExp(`DS Data record (\\d){1}`, 'g');
- // forms.forEach((form, index) => {
- // form.innerHTML = form.innerHTML.replace(formNumberRegex, `form-${index}-`);
- // form.innerHTML = form.innerHTML.replace(formLabelRegex, `DS Data Record ${index+1}`);
- // });
-
-
-
let formNumberRegex = RegExp(`form-(\\d){1}-`, 'g');
let formLabelRegex = RegExp(`DS Data record (\\d){1}`, 'g');
@@ -311,10 +300,6 @@ function prepareDeleteButtons() {
});
});
-
-
-
-
}
}
@@ -389,89 +374,10 @@ function prepareDeleteButtons() {
// Attach click event listener on the delete buttons of the new form
prepareDeleteButtons();
-
- // We need to fix the indicies of every existing form otherwise
- // the frontend and backend will not match and will error on submit
- // forms.forEach((form, index) => {
- // form.innerHTML = form.innerHTML.replace(formNumberRegex, `form-${index}-`);
- // form.innerHTML = form.innerHTML.replace(formLabelRegex, `DS Data Record ${index+1}`);
- // });
}
})();
-
-// (function prepareCancelButtons() {
-// const cancelButton = document.querySelector('.btn-cancel');
-
-// if (cancelButton) {
-// cancelButton.addEventListener('click', () => {
-
-// // Option 2: Redirect to another page (e.g., the homepage)
-
-// localStorage.clear(); // Clear all localStorage data
-// sessionStorage.clear(); // Clear all sessionStorage data
-
-// location.reload();
-// });
-// }
-// })();
-
-
-// /**
-// * An IIFE that attaches a click handler on form cancel buttons
-// *
-// */
-// (function prepareCancelButtons() {
-// const cancelButton = document.querySelector('.btn-cancel');
-
-// const formsetContainer = document.querySelector('#form-container');
-// const originalFormHTML = document.querySelector('.ds-record').innerHTML;
-// const numberOfFormsToReset = document.querySelectorAll('.ds-record').length;
-// const addNewRecordButton = document.querySelector('#add-ds-form');
-// const submitButton = document.querySelector('button[type="submit"]');
-
-// if (cancelButton) {
-// cancelButton.addEventListener('click', () => {
-// // Reset the form to its initial values
-// const form = document.querySelector('form');
-// resetForm(form);
-// });
-// }
-
-// function resetForm(form) {
-
-// // Remove all existing forms within the container
-// formsetContainer.innerHTML = '';
-// for (let i = 0; i < numberOfFormsToReset; i++) {
-// formsetContainer.innerHTML += originalFormHTML;
-// }
-// formsetContainer.innerHTML += addNewRecordButton
-// formsetContainer.innerHTML += submitButton
-
-// const dsRecords = form.querySelectorAll('.ds-record');
-
-// dsRecords.forEach((record) => {
-// const initialValuesField = record.querySelector('.initial-values');
-// const formFields = record.querySelectorAll('input, textarea, select');
-
-// if (initialValuesField) {
-// const initialValues = JSON.parse(initialValuesField.value);
-
-// formFields.forEach((field) => {
-// const fieldName = field.name;
-// if (fieldName in initialValues) {
-// field.value = initialValues[fieldName];
-// } else {
-// field.value = ''; // Set to empty if no initial value
-// }
-// });
-// }
-// });
-// }
-// })();
-
-
function toggleElements() {
let element1 = document.getElementById("enable-dnssec");
let element2 = document.getElementById("add-records");
@@ -480,7 +386,7 @@ function toggleElements() {
}
/**
- *
+ * An IIFE that attaches a click handler to toggle the DNSSEC warning on the DNSSEC landing page
*
*/
(function toggleDNSSECWarning() {
diff --git a/src/registrar/templates/domain_keydata.html b/src/registrar/templates/domain_keydata.html
index 1602c5d87..34ce14a4e 100644
--- a/src/registrar/templates/domain_keydata.html
+++ b/src/registrar/templates/domain_keydata.html
@@ -38,7 +38,7 @@
{% for form in formset %}
+ {% comment %} display: none is sufficient on hidden elements for accessibility (removes accessibility tree) {% endcomment %}
Add DS Records
In order to enable DNSSEC and add Delegation Signer (DS) records, you must first configure it with your DNS hosting service. Your configuration will determine whether you need to add DS Data or Key Data. Contact your DNS hosting provider if you are unsure which record type to add.
diff --git a/src/registrar/templates/domain_dsdata.html b/src/registrar/templates/domain_dsdata.html
index 0de7f4730..585b4a981 100644
--- a/src/registrar/templates/domain_dsdata.html
+++ b/src/registrar/templates/domain_dsdata.html
@@ -4,6 +4,9 @@
{% block title %}DS Data | {{ domain.name }} | {% endblock %}
{% block domain_content %}
+ {% for form in formset %}
+ {% include "includes/form_errors.html" with form=form %}
+ {% endfor %}
-
- {% comment %} {% endcomment %}
-
{% endfor %}
From b899b35285796b113aa581001b884d65909f33fa Mon Sep 17 00:00:00 2001
From: Rachid Mrad
Date: Thu, 5 Oct 2023 18:09:37 -0400
Subject: [PATCH 36/65] form error msgs on keydata form
---
src/registrar/templates/domain_keydata.html | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/registrar/templates/domain_keydata.html b/src/registrar/templates/domain_keydata.html
index 34ce14a4e..cea62e71a 100644
--- a/src/registrar/templates/domain_keydata.html
+++ b/src/registrar/templates/domain_keydata.html
@@ -4,6 +4,9 @@
{% block title %}Key Data | {{ domain.name }} | {% endblock %}
{% block domain_content %}
+ {% for form in formset %}
+ {% include "includes/form_errors.html" with form=form %}
+ {% endfor %}
Key Data
From a6cfd343e8ea805cabba49eff5ee571940d64788 Mon Sep 17 00:00:00 2001
From: David Kennedy
Date: Fri, 6 Oct 2023 07:05:45 -0400
Subject: [PATCH 37/65] removed js for hide and show on dnssec main page;
handling flags in app with session variables rather than model attributes
---
src/registrar/assets/js/get-gov.js | 20 --------
src/registrar/templates/domain_dnssec.html | 37 +++++++--------
src/registrar/templates/domain_dsdata.html | 2 +-
src/registrar/templates/domain_keydata.html | 2 +-
src/registrar/views/domain.py | 52 ++++++++++++++-------
5 files changed, 54 insertions(+), 59 deletions(-)
diff --git a/src/registrar/assets/js/get-gov.js b/src/registrar/assets/js/get-gov.js
index 3a7d81ba5..4b5ff5e31 100644
--- a/src/registrar/assets/js/get-gov.js
+++ b/src/registrar/assets/js/get-gov.js
@@ -376,23 +376,3 @@ function prepareDeleteButtons() {
}
})();
-
-function toggleElements() {
- let element1 = document.getElementById("enable-dnssec");
- let element2 = document.getElementById("add-records");
- element1.classList.toggle("display-none");
- element2.classList.toggle("display-none");
-}
-
-/**
- * An IIFE that attaches a click handler to toggle the DNSSEC warning on the DNSSEC landing page
- *
- */
-(function toggleDNSSECWarning() {
- let toggle1 = document.getElementById("enable_dnssec");
- if (toggle1)
- toggle1.addEventListener("click", toggleElements);
- let toggle2 = document.getElementById("cancel_dnssec");
- if (toggle2)
- toggle2.addEventListener("click", toggleElements);
-})();
\ No newline at end of file
diff --git a/src/registrar/templates/domain_dnssec.html b/src/registrar/templates/domain_dnssec.html
index c87fc9152..4763ff3c1 100644
--- a/src/registrar/templates/domain_dnssec.html
+++ b/src/registrar/templates/domain_dnssec.html
@@ -5,9 +5,9 @@
{% block domain_content %}
-
DNSSEC
+
{% if dnssec_enabled %}Set up {% endif %}DNSSEC
-
DNSSEC, or DNS Security Extensions, is additional security layer to protect your website. Enabling DNSSEC ensures that when someone visits your website, they can be certain that it's connecting to the correct server, preventing potential hijacking or tampering with your domain's records. Read more about DNSSEC and why it is important.
+
DNSSEC, or DNS Security Extensions, is additional security layer to protect your website. Enabling DNSSEC ensures that when someone visits your website, they can be certain that it's connecting to the correct server, preventing potential hijacking or tampering with your domain's records.
In order to enable DNSSEC and add Delegation Signer (DS) records, you must first configure it with your DNS hosting service. Your configuration will determine whether you need to add DS Data or Key Data. Contact your DNS hosting provider if you are unsure which record type to add.
-
- {% comment %} display: none is sufficient on hidden elements for accessibility (removes accessibility tree) {% endcomment %}
-
-
Add DS Records
-
In order to enable DNSSEC and add Delegation Signer (DS) records, you must first configure it with your DNS hosting service. Your configuration will determine whether you need to add DS Data or Key Data. Contact your DNS hosting provider if you are unsure which record type to add.
- {% elif not domain.dnssec_ds_confirmed %}
+ {% elif not dnssec_ds_confirmed %}
In order to enable DNSSEC and add DS records, you must first configure it with your DNS hosting service. Your configuration will determine whether you need to add DS Data or Key Data. Contact your DNS hosting provider if you are unsure which record type to add.
- {% elif not domain.dnssec_key_confirmed %}
+ {% elif not dnssec_key_confirmed %}
In order to enable DNSSEC and add DS records, you must first configure it with your DNS hosting service. Your configuration will determine whether you need to add DS Data or Key Data. Contact your DNS hosting provider if you are unsure which record type to add.
{% csrf_token %}
diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py
index 105691c37..fd5d22651 100644
--- a/src/registrar/views/domain.py
+++ b/src/registrar/views/domain.py
@@ -233,7 +233,6 @@ class DomainDNSSECView(DomainPermissionView, FormMixin):
template_name = "domain_dnssec.html"
form_class = DomainDnssecForm
- clicked_enable_dns = False
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
@@ -242,20 +241,13 @@ class DomainDNSSECView(DomainPermissionView, FormMixin):
has_dnssec_records = self.domain.dnssecdata is not None
- # if does_not_have_dnssec_records and self.clicked_enable_dns == False:
- # logger.debug(f"clicked_enable_dns {self.clicked_enable_dns}")
- # self.domain.dnssec_enabled = False
- # self.domain.dnssec_ds_confirmed = False
- # self.domain.dnssec_key_confirmed = False
- # self.domain.save()
-
# Create HTML for the buttons
modal_button = 'Disable DNSSEC'
context['modal_button'] = modal_button
context['has_dnssec_records'] = has_dnssec_records
- # context['domain'] = self.domain
-
+ context['dnssec_enabled'] = self.request.session.pop('dnssec_enabled', False)
+
return context
def get_success_url(self):
@@ -277,9 +269,12 @@ class DomainDNSSECView(DomainPermissionView, FormMixin):
messages.error(
self.request, errmsg
)
- self.domain.dnssec_ds_confirmed = False
- self.domain.dnssec_key_confirmed = False
- self.domain.save()
+ request.session['dnssec_ds_confirmed'] = False
+ request.session['dnssec_key_confirmed'] = False
+ elif 'enable_dnssec' in request.POST:
+ request.session['dnssec_enabled'] = True
+ request.session['dnssec_ds_confirmed'] = False
+ request.session['dnssec_key_confirmed'] = False
return self.form_valid(form)
@@ -323,6 +318,17 @@ class DomainDsdataView(DomainPermissionView, FormMixin):
context = super().get_context_data(**kwargs)
# use "formset" instead of "form" for the key
context["formset"] = context.pop("form")
+
+ # set the dnssec_ds_confirmed flag in the context for this view
+ # based either on the existence of DS Data in the domain,
+ # or on the flag stored in the session
+ domain = self.get_object()
+ dnssecdata: extensions.DNSSECExtension = domain.dnssecdata
+
+ if dnssecdata is not None and dnssecdata.dsData is not None:
+ self.request.session['dnssec_ds_confirmed'] = True
+
+ context['dnssec_ds_confirmed'] = self.request.session.get('dnssec_ds_confirmed', False)
return context
def post(self, request, *args, **kwargs):
@@ -331,9 +337,8 @@ class DomainDsdataView(DomainPermissionView, FormMixin):
formset = self.get_form()
if 'confirm-ds' in request.POST:
- self.object.dnssec_ds_confirmed = True
- self.object.dnssec_key_confirmed = False
- self.object.save()
+ request.session['dnssec_ds_confirmed'] = True
+ request.session['dnssec_key_confirmed'] = False
return super().form_valid(formset)
if 'btn-cancel-click' in request.POST:
@@ -425,6 +430,17 @@ class DomainKeydataView(DomainPermissionView, FormMixin):
context = super().get_context_data(**kwargs)
# use "formset" instead of "form" for the key
context["formset"] = context.pop("form")
+
+ # set the dnssec_key_confirmed flag in the context for this view
+ # based either on the existence of Key Data in the domain,
+ # or on the flag stored in the session
+ domain = self.get_object()
+ dnssecdata: extensions.DNSSECExtension = domain.dnssecdata
+
+ if dnssecdata is not None and dnssecdata.keyData is not None:
+ self.request.session['dnssec_key_confirmed'] = True
+
+ context['dnssec_key_confirmed'] = self.request.session.get('dnssec_key_confirmed', False)
return context
def post(self, request, *args, **kwargs):
@@ -433,8 +449,8 @@ class DomainKeydataView(DomainPermissionView, FormMixin):
formset = self.get_form()
if 'confirm-key' in request.POST:
- self.object.dnssec_key_confirmed = True
- self.object.dnssec_ds_confirmed = False
+ request.session['dnssec_key_confirmed'] = True
+ request.session['dnssec_ds_confirmed'] = False
self.object.save()
return super().form_valid(formset)
From ba8901bf272822427aa622f9d9d56542da4c552c Mon Sep 17 00:00:00 2001
From: David Kennedy
Date: Fri, 6 Oct 2023 07:56:44 -0400
Subject: [PATCH 38/65] removing unnecessary domain attributes
---
...ove_domain_dnssec_ds_confirmed_and_more.py | 24 +++++++++++++++++++
src/registrar/models/domain.py | 15 ------------
2 files changed, 24 insertions(+), 15 deletions(-)
create mode 100644 src/registrar/migrations/0035_remove_domain_dnssec_ds_confirmed_and_more.py
diff --git a/src/registrar/migrations/0035_remove_domain_dnssec_ds_confirmed_and_more.py b/src/registrar/migrations/0035_remove_domain_dnssec_ds_confirmed_and_more.py
new file mode 100644
index 000000000..8b7b7566e
--- /dev/null
+++ b/src/registrar/migrations/0035_remove_domain_dnssec_ds_confirmed_and_more.py
@@ -0,0 +1,24 @@
+# Generated by Django 4.2.1 on 2023-10-06 11:50
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("registrar", "0034_domain_dnssec_ds_confirmed_and_more"),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name="domain",
+ name="dnssec_ds_confirmed",
+ ),
+ migrations.RemoveField(
+ model_name="domain",
+ name="dnssec_enabled",
+ ),
+ migrations.RemoveField(
+ model_name="domain",
+ name="dnssec_key_confirmed",
+ ),
+ ]
diff --git a/src/registrar/models/domain.py b/src/registrar/models/domain.py
index 56a1a53cb..7a890632c 100644
--- a/src/registrar/models/domain.py
+++ b/src/registrar/models/domain.py
@@ -702,21 +702,6 @@ class Domain(TimeStampedModel, DomainHelper):
help_text="Very basic info about the lifecycle of this domain object",
)
- dnssec_enabled = models.BooleanField(
- default=False,
- help_text="Boolean indicating if dnssec is enabled",
- )
-
- dnssec_ds_confirmed = models.BooleanField(
- default=False,
- help_text="Boolean indicating if DS record adding is confirmed",
- )
-
- dnssec_key_confirmed = models.BooleanField(
- default=False,
- help_text="Boolean indicating if Key record adding is confirmed",
- )
-
# ForeignKey on UserDomainRole creates a "permissions" member for
# all of the user-roles that are in place for this domain
From 88bcb1eedcccae3b8f997324890923111da90a92 Mon Sep 17 00:00:00 2001
From: Rachid Mrad
Date: Fri, 6 Oct 2023 10:12:10 -0400
Subject: [PATCH 39/65] fix modal ui
---
src/registrar/assets/sass/_theme/_buttons.scss | 8 ++++++++
src/registrar/templates/domain_dnssec.html | 4 ++--
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/src/registrar/assets/sass/_theme/_buttons.scss b/src/registrar/assets/sass/_theme/_buttons.scss
index 45ea6620c..f4c72f4fa 100644
--- a/src/registrar/assets/sass/_theme/_buttons.scss
+++ b/src/registrar/assets/sass/_theme/_buttons.scss
@@ -24,6 +24,14 @@ a.breadcrumb__back {
a.usa-button {
text-decoration: none;
+ color: color('white');
+}
+
+a.usa-button:visited,
+a.usa-button:hover,
+a.usa-button:focus,
+a.usa-button:active {
+ color: color('white');
}
a.usa-button--outline,
diff --git a/src/registrar/templates/domain_dnssec.html b/src/registrar/templates/domain_dnssec.html
index 4763ff3c1..6a0a15389 100644
--- a/src/registrar/templates/domain_dnssec.html
+++ b/src/registrar/templates/domain_dnssec.html
@@ -18,9 +18,9 @@
Disable DNSSEC
From a0f7cd5e1dda8d8320d99af921a6bff16c82b88f Mon Sep 17 00:00:00 2001
From: David Kennedy
Date: Fri, 6 Oct 2023 12:04:56 -0400
Subject: [PATCH 40/65] shared mock data for dnssec unit tests
---
src/registrar/tests/common.py | 63 +++++++-
src/registrar/tests/test_models_domain.py | 168 +++++-----------------
2 files changed, 94 insertions(+), 137 deletions(-)
diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py
index 10c387099..9291aa271 100644
--- a/src/registrar/tests/common.py
+++ b/src/registrar/tests/common.py
@@ -7,7 +7,7 @@ import random
from string import ascii_uppercase
from django.test import TestCase
from unittest.mock import MagicMock, Mock, patch
-from typing import List, Dict
+from typing import List, Dict, Mapping, Any
from django.conf import settings
from django.contrib.auth import get_user_model, login
@@ -26,6 +26,7 @@ from registrar.models import (
from epplibwrapper import (
commands,
common,
+ extensions,
RegistryError,
ErrorCode,
)
@@ -584,6 +585,37 @@ class MockEppLib(TestCase):
mockDataInfoHosts = fakedEppObject(
"lastPw", cr_date=datetime.datetime(2023, 8, 25, 19, 45, 35)
)
+ addDsData1 = {
+ "keyTag": 1234,
+ "alg": 3,
+ "digestType": 1,
+ "digest": "ec0bdd990b39feead889f0ba613db4adec0bdd99",
+ }
+ addDsData2 = {
+ "keyTag": 2345,
+ "alg": 3,
+ "digestType": 1,
+ "digest": "ec0bdd990b39feead889f0ba613db4adecb4adec",
+ }
+ keyDataDict = {
+ "flags": 257,
+ "protocol": 3,
+ "alg": 1,
+ "pubKey": "AQPJ////4Q==",
+ }
+ dnssecExtensionWithDsData: Mapping[str, Any] = {
+ "dsData": [common.DSData(**addDsData1)]
+ }
+ dnssecExtensionWithMultDsData: Mapping[str, Any] = {
+ "dsData": [
+ common.DSData(**addDsData1),
+ common.DSData(**addDsData2),
+ ],
+ }
+ dnssecExtensionWithKeyData: Mapping[str, Any] = {
+ "maxSigLife": 3215,
+ "keyData": [common.DNSSECKeyData(**keyDataDict)],
+ }
def mockSend(self, _request, cleaned):
"""Mocks the registry.send function used inside of domain.py
@@ -593,6 +625,30 @@ class MockEppLib(TestCase):
if isinstance(_request, commands.InfoDomain):
if getattr(_request, "name", None) == "security.gov":
return MagicMock(res_data=[self.infoDomainNoContact])
+ elif getattr(_request, "name", None) == "dnssec-dsdata.gov":
+ return MagicMock(
+ res_data=[self.mockDataInfoDomain],
+ extensions=[
+ extensions.DNSSECExtension(**self.dnssecExtensionWithDsData)
+ ],
+ )
+ elif getattr(_request, "name", None) == "dnssec-multdsdata.gov":
+ return MagicMock(
+ res_data=[self.mockDataInfoDomain],
+ extensions=[
+ extensions.DNSSECExtension(**self.dnssecExtensionWithMultDsData)
+ ],
+ )
+ elif getattr(_request, "name", None) == "dnssec-keydata.gov":
+ return MagicMock(
+ res_data=[self.mockDataInfoDomain],
+ extensions=[
+ extensions.DNSSECExtension(**self.dnssecExtensionWithKeyData)
+ ],
+ )
+ elif getattr(_request, "name", None) == "dnssec-none.gov":
+ # this case is not necessary, but helps improve readability
+ return MagicMock(res_data=[self.mockDataInfoDomain])
return MagicMock(res_data=[self.mockDataInfoDomain])
elif isinstance(_request, commands.InfoContact):
return MagicMock(res_data=[self.mockDataInfoContact])
@@ -614,6 +670,11 @@ class MockEppLib(TestCase):
raise RegistryError(
code=ErrorCode.OBJECT_ASSOCIATION_PROHIBITS_OPERATION
)
+ elif (
+ isinstance(_request, commands.UpdateDomain)
+ and getattr(_request, "name", None) == "dnssec-invalid.gov"
+ ):
+ raise RegistryError(code=ErrorCode.PARAMETER_VALUE_RANGE_ERROR)
return MagicMock(res_data=[self.mockDataInfoHosts])
def setUp(self):
diff --git a/src/registrar/tests/test_models_domain.py b/src/registrar/tests/test_models_domain.py
index 16dd30017..6f164d1f4 100644
--- a/src/registrar/tests/test_models_domain.py
+++ b/src/registrar/tests/test_models_domain.py
@@ -3,7 +3,6 @@ Feature being tested: Registry Integration
This file tests the various ways in which the registrar interacts with the registry.
"""
-from typing import Mapping, Any
from django.test import TestCase
from django.db.utils import IntegrityError
from unittest.mock import MagicMock, patch, call
@@ -803,37 +802,7 @@ class TestRegistrantDNSSEC(MockEppLib):
super().setUp()
# for the tests, need a domain in the unknown state
self.domain, _ = Domain.objects.get_or_create(name="fake.gov")
- self.addDsData1 = {
- "keyTag": 1234,
- "alg": 3,
- "digestType": 1,
- "digest": "ec0bdd990b39feead889f0ba613db4adec0bdd99",
- }
- self.addDsData2 = {
- "keyTag": 2345,
- "alg": 3,
- "digestType": 1,
- "digest": "ec0bdd990b39feead889f0ba613db4adecb4adec",
- }
- self.keyDataDict = {
- "flags": 257,
- "protocol": 3,
- "alg": 1,
- "pubKey": "AQPJ////4Q==",
- }
- self.dnssecExtensionWithDsData: Mapping[str, Any] = {
- "dsData": [common.DSData(**self.addDsData1)]
- }
- self.dnssecExtensionWithMultDsData: Mapping[str, Any] = {
- "dsData": [
- common.DSData(**self.addDsData1),
- common.DSData(**self.addDsData2),
- ],
- }
- self.dnssecExtensionWithKeyData: Mapping[str, Any] = {
- "maxSigLife": 3215,
- "keyData": [common.DNSSECKeyData(**self.keyDataDict)],
- }
+
def tearDown(self):
Domain.objects.all().delete()
@@ -852,26 +821,13 @@ class TestRegistrantDNSSEC(MockEppLib):
"""
- # make sure to stop any other patcher so there are no conflicts
- self.mockSendPatch.stop()
+ domain, _ = Domain.objects.get_or_create(name="dnssec-dsdata.gov")
- def side_effect(_request, cleaned):
- return MagicMock(
- res_data=[self.mockDataInfoDomain],
- extensions=[
- extensions.DNSSECExtension(**self.dnssecExtensionWithDsData)
- ],
- )
-
- patcher = patch("registrar.models.domain.registry.send")
- mocked_send = patcher.start()
- mocked_send.side_effect = side_effect
-
- self.domain.dnssecdata = self.dnssecExtensionWithDsData
+ domain.dnssecdata = self.dnssecExtensionWithDsData
# get the DNS SEC extension added to the UpdateDomain command and
# verify that it is properly sent
# args[0] is the _request sent to registry
- args, _ = mocked_send.call_args
+ args, _ = self.mockedSendFunction.call_args
# assert that the extension matches
self.assertEquals(
args[0].extensions[0],
@@ -880,12 +836,12 @@ class TestRegistrantDNSSEC(MockEppLib):
),
)
# test that the dnssecdata getter is functioning properly
- dnssecdata_get = self.domain.dnssecdata
- mocked_send.assert_has_calls(
+ dnssecdata_get = domain.dnssecdata
+ self.mockedSendFunction.assert_has_calls(
[
call(
commands.UpdateDomain(
- name="fake.gov",
+ name="dnssec-dsdata.gov",
nsset=None,
keyset=None,
registrant=None,
@@ -895,7 +851,7 @@ class TestRegistrantDNSSEC(MockEppLib):
),
call(
commands.InfoDomain(
- name="fake.gov",
+ name="dnssec-dsdata.gov",
),
cleaned=True,
),
@@ -906,8 +862,6 @@ class TestRegistrantDNSSEC(MockEppLib):
dnssecdata_get.dsData, self.dnssecExtensionWithDsData["dsData"]
)
- patcher.stop()
-
def test_dnssec_is_idempotent(self):
"""
Scenario: Registrant adds DNS data twice, due to a UI glitch
@@ -923,32 +877,19 @@ class TestRegistrantDNSSEC(MockEppLib):
"""
- # make sure to stop any other patcher so there are no conflicts
- self.mockSendPatch.stop()
-
- def side_effect(_request, cleaned):
- return MagicMock(
- res_data=[self.mockDataInfoDomain],
- extensions=[
- extensions.DNSSECExtension(**self.dnssecExtensionWithDsData)
- ],
- )
-
- patcher = patch("registrar.models.domain.registry.send")
- mocked_send = patcher.start()
- mocked_send.side_effect = side_effect
+ domain, _ = Domain.objects.get_or_create(name="dnssec-dsdata.gov")
# set the dnssecdata once
- self.domain.dnssecdata = self.dnssecExtensionWithDsData
+ domain.dnssecdata = self.dnssecExtensionWithDsData
# set the dnssecdata again
- self.domain.dnssecdata = self.dnssecExtensionWithDsData
+ domain.dnssecdata = self.dnssecExtensionWithDsData
# test that the dnssecdata getter is functioning properly
- dnssecdata_get = self.domain.dnssecdata
- mocked_send.assert_has_calls(
+ dnssecdata_get = domain.dnssecdata
+ self.mockedSendFunction.assert_has_calls(
[
call(
commands.UpdateDomain(
- name="fake.gov",
+ name="dnssec-dsdata.gov",
nsset=None,
keyset=None,
registrant=None,
@@ -958,7 +899,7 @@ class TestRegistrantDNSSEC(MockEppLib):
),
call(
commands.UpdateDomain(
- name="fake.gov",
+ name="dnssec-dsdata.gov",
nsset=None,
keyset=None,
registrant=None,
@@ -968,7 +909,7 @@ class TestRegistrantDNSSEC(MockEppLib):
),
call(
commands.InfoDomain(
- name="fake.gov",
+ name="dnssec-dsdata.gov",
),
cleaned=True,
),
@@ -979,8 +920,6 @@ class TestRegistrantDNSSEC(MockEppLib):
dnssecdata_get.dsData, self.dnssecExtensionWithDsData["dsData"]
)
- patcher.stop()
-
def test_user_adds_dnssec_data_multiple_dsdata(self):
"""
Scenario: Registrant adds DNSSEC data with multiple DSData.
@@ -994,26 +933,13 @@ class TestRegistrantDNSSEC(MockEppLib):
"""
- # make sure to stop any other patcher so there are no conflicts
- self.mockSendPatch.stop()
+ domain, _ = Domain.objects.get_or_create(name="dnssec-multdsdata.gov")
- def side_effect(_request, cleaned):
- return MagicMock(
- res_data=[self.mockDataInfoDomain],
- extensions=[
- extensions.DNSSECExtension(**self.dnssecExtensionWithMultDsData)
- ],
- )
-
- patcher = patch("registrar.models.domain.registry.send")
- mocked_send = patcher.start()
- mocked_send.side_effect = side_effect
-
- self.domain.dnssecdata = self.dnssecExtensionWithMultDsData
+ domain.dnssecdata = self.dnssecExtensionWithMultDsData
# get the DNS SEC extension added to the UpdateDomain command
# and verify that it is properly sent
# args[0] is the _request sent to registry
- args, _ = mocked_send.call_args
+ args, _ = self.mockedSendFunction.call_args
# assert that the extension matches
self.assertEquals(
args[0].extensions[0],
@@ -1022,12 +948,12 @@ class TestRegistrantDNSSEC(MockEppLib):
),
)
# test that the dnssecdata getter is functioning properly
- dnssecdata_get = self.domain.dnssecdata
- mocked_send.assert_has_calls(
+ dnssecdata_get = domain.dnssecdata
+ self.mockedSendFunction.assert_has_calls(
[
call(
commands.UpdateDomain(
- name="fake.gov",
+ name="dnssec-multdsdata.gov",
nsset=None,
keyset=None,
registrant=None,
@@ -1037,7 +963,7 @@ class TestRegistrantDNSSEC(MockEppLib):
),
call(
commands.InfoDomain(
- name="fake.gov",
+ name="dnssec-multdsdata.gov",
),
cleaned=True,
),
@@ -1048,8 +974,6 @@ class TestRegistrantDNSSEC(MockEppLib):
dnssecdata_get.dsData, self.dnssecExtensionWithMultDsData["dsData"]
)
- patcher.stop()
-
def test_user_adds_dnssec_keydata(self):
"""
Scenario: Registrant adds DNSSEC data.
@@ -1063,26 +987,13 @@ class TestRegistrantDNSSEC(MockEppLib):
"""
- # make sure to stop any other patcher so there are no conflicts
- self.mockSendPatch.stop()
+ domain, _ = Domain.objects.get_or_create(name="dnssec-keydata.gov")
- def side_effect(_request, cleaned):
- return MagicMock(
- res_data=[self.mockDataInfoDomain],
- extensions=[
- extensions.DNSSECExtension(**self.dnssecExtensionWithKeyData)
- ],
- )
-
- patcher = patch("registrar.models.domain.registry.send")
- mocked_send = patcher.start()
- mocked_send.side_effect = side_effect
-
- self.domain.dnssecdata = self.dnssecExtensionWithKeyData
+ domain.dnssecdata = self.dnssecExtensionWithKeyData
# get the DNS SEC extension added to the UpdateDomain command
# and verify that it is properly sent
# args[0] is the _request sent to registry
- args, _ = mocked_send.call_args
+ args, _ = self.mockedSendFunction.call_args
# assert that the extension matches
self.assertEquals(
args[0].extensions[0],
@@ -1091,12 +1002,12 @@ class TestRegistrantDNSSEC(MockEppLib):
),
)
# test that the dnssecdata getter is functioning properly
- dnssecdata_get = self.domain.dnssecdata
- mocked_send.assert_has_calls(
+ dnssecdata_get = domain.dnssecdata
+ self.mockedSendFunction.assert_has_calls(
[
call(
commands.UpdateDomain(
- name="fake.gov",
+ name="dnssec-keydata.gov",
nsset=None,
keyset=None,
registrant=None,
@@ -1106,7 +1017,7 @@ class TestRegistrantDNSSEC(MockEppLib):
),
call(
commands.InfoDomain(
- name="fake.gov",
+ name="dnssec-keydata.gov",
),
cleaned=True,
),
@@ -1117,8 +1028,6 @@ class TestRegistrantDNSSEC(MockEppLib):
dnssecdata_get.keyData, self.dnssecExtensionWithKeyData["keyData"]
)
- patcher.stop()
-
def test_update_is_unsuccessful(self):
"""
Scenario: An update to the dns data is unsuccessful
@@ -1126,27 +1035,14 @@ class TestRegistrantDNSSEC(MockEppLib):
Then a user-friendly error message is returned for displaying on the web
"""
- # make sure to stop any other patcher so there are no conflicts
- self.mockSendPatch.stop()
+ domain, _ = Domain.objects.get_or_create(name="dnssec-invalid.gov")
- def side_effect(_request, cleaned):
- raise RegistryError(code=ErrorCode.PARAMETER_VALUE_RANGE_ERROR)
-
- patcher = patch("registrar.models.domain.registry.send")
- mocked_send = patcher.start()
- mocked_send.side_effect = side_effect
-
- # if RegistryError is raised, view formats user-friendly
- # error message if error is_client_error, is_session_error, or
- # is_server_error; so test for those conditions
with self.assertRaises(RegistryError) as err:
- self.domain.dnssecdata = self.dnssecExtensionWithDsData
+ domain.dnssecdata = self.dnssecExtensionWithDsData
self.assertTrue(
err.is_client_error() or err.is_session_error() or err.is_server_error()
)
- patcher.stop()
-
class TestAnalystClientHold(MockEppLib):
"""Rule: Analysts may suspend or restore a domain by using client hold"""
From 136db5bab2022c34482f35fb9b8f5f31fa5bd948 Mon Sep 17 00:00:00 2001
From: David Kennedy
Date: Fri, 6 Oct 2023 12:12:43 -0400
Subject: [PATCH 41/65] initial breakdown of test_views
---
src/registrar/tests/test_views.py | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/src/registrar/tests/test_views.py b/src/registrar/tests/test_views.py
index c49ec8f3f..83e9a8749 100644
--- a/src/registrar/tests/test_views.py
+++ b/src/registrar/tests/test_views.py
@@ -1133,7 +1133,7 @@ class TestDomainPermissions(TestWithDomainPermissions):
self.assertEqual(response.status_code, 403)
-class TestDomainDetail(TestWithDomainPermissions, WebTest):
+class TestDomainOverview(TestWithDomainPermissions, WebTest):
def setUp(self):
super().setUp()
self.app.set_user(self.user.username)
@@ -1147,6 +1147,13 @@ class TestDomainDetail(TestWithDomainPermissions, WebTest):
self.assertContains(detail_page, "igorville.gov")
self.assertContains(detail_page, "Status")
+
+class TestDomainUserManagement(TestWithDomainPermissions, WebTest):
+ def setUp(self):
+ super().setUp()
+ self.app.set_user(self.user.username)
+ self.client.force_login(self.user)
+
def test_domain_user_management(self):
response = self.client.get(
reverse("domain-users", kwargs={"pk": self.domain.id})
From bb61ce9f642eb853a8bb0d0b599f9494bff2b09d Mon Sep 17 00:00:00 2001
From: Rachid Mrad
Date: Fri, 6 Oct 2023 13:26:07 -0400
Subject: [PATCH 42/65] 50% coverage on DNSSEC code (testing for statuses and
flows)
---
src/registrar/tests/test_views.py | 181 ++++++++++++++++++++++++++----
1 file changed, 160 insertions(+), 21 deletions(-)
diff --git a/src/registrar/tests/test_views.py b/src/registrar/tests/test_views.py
index 83e9a8749..8e984be85 100644
--- a/src/registrar/tests/test_views.py
+++ b/src/registrar/tests/test_views.py
@@ -1071,21 +1071,51 @@ class TestWithDomainPermissions(TestWithUser):
def setUp(self):
super().setUp()
self.domain, _ = Domain.objects.get_or_create(name="igorville.gov")
+ self.domain_dsdata, _ = Domain.objects.get_or_create(name="dnssec-dsdata.gov")
+ self.domain_multdsdata, _ = Domain.objects.get_or_create(name="dnssec-multdsdata.gov")
+ self.domain_keydata, _ = Domain.objects.get_or_create(name="dnssec-keydata.gov")
+ # We could simply use domain (igoreville) but this will be more readable in tests
+ # that inherit this setUp
+ self.domain_dnssec_none, _ = Domain.objects.get_or_create(name="dnssec-none.gov")
self.domain_information, _ = DomainInformation.objects.get_or_create(
creator=self.user, domain=self.domain
)
+ DomainInformation.objects.get_or_create(
+ creator=self.user, domain=self.domain_dsdata
+ )
+ DomainInformation.objects.get_or_create(
+ creator=self.user, domain=self.domain_multdsdata
+ )
+ DomainInformation.objects.get_or_create(
+ creator=self.user, domain=self.domain_keydata
+ )
+ DomainInformation.objects.get_or_create(
+ creator=self.user, domain=self.domain_dnssec_none
+ )
self.role, _ = UserDomainRole.objects.get_or_create(
user=self.user, domain=self.domain, role=UserDomainRole.Roles.ADMIN
)
+ UserDomainRole.objects.get_or_create(
+ user=self.user, domain=self.domain_dsdata, role=UserDomainRole.Roles.ADMIN
+ )
+ UserDomainRole.objects.get_or_create(
+ user=self.user, domain=self.domain_multdsdata, role=UserDomainRole.Roles.ADMIN
+ )
+ UserDomainRole.objects.get_or_create(
+ user=self.user, domain=self.domain_keydata, role=UserDomainRole.Roles.ADMIN
+ )
+ UserDomainRole.objects.get_or_create(
+ user=self.user, domain=self.domain_dnssec_none, role=UserDomainRole.Roles.ADMIN
+ )
def tearDown(self):
try:
- self.domain_information.delete()
+ UserDomainRole.objects.all().delete()
if hasattr(self.domain, "contacts"):
self.domain.contacts.all().delete()
DomainApplication.objects.all().delete()
- self.domain.delete()
- self.role.delete()
+ Domain.objects.all().delete()
+ UserDomainRole.objects.all().delete()
except ValueError: # pass if already deleted
pass
super().tearDown()
@@ -1143,17 +1173,25 @@ class TestDomainOverview(TestWithDomainPermissions, WebTest):
home_page = self.app.get("/")
self.assertContains(home_page, "igorville.gov")
# click the "Edit" link
- detail_page = home_page.click("Manage")
+ detail_page = home_page.click("Manage", index=0)
self.assertContains(detail_page, "igorville.gov")
self.assertContains(detail_page, "Status")
+
+ def test_domain_overview_blocked_for_ineligible_user(self):
+ """We could easily duplicate this test for all domain management
+ views, but a single url test should be solid enough since all domain
+ management pages share the same permissions class"""
+ self.user.status = User.RESTRICTED
+ self.user.save()
+ home_page = self.app.get("/")
+ self.assertContains(home_page, "igorville.gov")
+ with less_console_noise():
+ response = self.client.get(reverse("domain", kwargs={"pk": self.domain.id}))
+ self.assertEqual(response.status_code, 403)
-class TestDomainUserManagement(TestWithDomainPermissions, WebTest):
- def setUp(self):
- super().setUp()
- self.app.set_user(self.user.username)
- self.client.force_login(self.user)
-
+class TestDomainUserManagement(TestDomainOverview):
+
def test_domain_user_management(self):
response = self.client.get(
reverse("domain-users", kwargs={"pk": self.domain.id})
@@ -1311,6 +1349,8 @@ class TestDomainUserManagement(TestWithDomainPermissions, WebTest):
# Now load the home page and make sure our domain appears there
home_page = self.app.get(reverse("home"))
self.assertContains(home_page, self.domain.name)
+
+class TestDomainNameservers(TestDomainOverview):
def test_domain_nameservers(self):
"""Can load domain's nameservers page."""
@@ -1362,6 +1402,8 @@ class TestDomainUserManagement(TestWithDomainPermissions, WebTest):
# error text appears twice, once at the top of the page, once around
# the field.
self.assertContains(result, "This field is required", count=2, status_code=200)
+
+class TestDomainAuthorizingOfficial(TestDomainOverview):
def test_domain_authorizing_official(self):
"""Can load domain's authorizing official page."""
@@ -1380,6 +1422,8 @@ class TestDomainUserManagement(TestWithDomainPermissions, WebTest):
reverse("domain-authorizing-official", kwargs={"pk": self.domain.id})
)
self.assertContains(page, "Testy")
+
+class TestDomainOrganization(TestDomainOverview):
def test_domain_org_name_address(self):
"""Can load domain's org name and mailing address page."""
@@ -1416,6 +1460,8 @@ class TestDomainUserManagement(TestWithDomainPermissions, WebTest):
self.assertContains(success_result_page, "Not igorville")
self.assertContains(success_result_page, "Faketown")
+
+class TestDomainContactInformation(TestDomainOverview):
def test_domain_your_contact_information(self):
"""Can load domain's your contact information page."""
@@ -1432,6 +1478,8 @@ class TestDomainUserManagement(TestWithDomainPermissions, WebTest):
reverse("domain-your-contact-information", kwargs={"pk": self.domain.id})
)
self.assertContains(page, "Testy")
+
+class TestDomainSecurityEmail(TestDomainOverview):
def test_domain_security_email(self):
"""Can load domain's security email page."""
@@ -1465,18 +1513,109 @@ class TestDomainUserManagement(TestWithDomainPermissions, WebTest):
self.assertContains(
success_page, "The security email for this domain have been updated"
)
+
+
+class TestDomainDNSSEC(TestDomainOverview):
+
+ """MockEPPLib is already inherited."""
+
+ def test_dnssec_page_refreshes_enable_button(self):
+ """DNSSEC overview page loads when domain has no DNSSEC data
+ and shows a 'Enable DNSSEC' button. When button is clicked the template
+ updates. When user navigates away then comes back to the page, the
+ 'Enable DNSSEC' button is shown again."""
+ # home_page = self.app.get("/")
+
+ page = self.client.get(
+ reverse("domain-dns-dnssec", kwargs={"pk": self.domain.id})
+ )
+ self.assertContains(page, "Enable DNSSEC")
+
+ # Prepare the data for the POST request
+ post_data = {
+ 'enable_dnssec': 'Enable DNSSEC', # Replace with the actual form field and value
+ # Add other form fields as needed
+ }
+ updated_page = self.client.post(reverse("domain-dns-dnssec", kwargs={"pk": self.domain.id}), post_data, follow=True)
+
+ self.assertEqual(updated_page.status_code, 200)
+
+ self.assertContains(updated_page, "Add DS Data")
+ self.assertContains(updated_page, "Add Key Data")
+
+ self.app.get("/")
+
+ back_to_page = self.client.get(
+ reverse("domain-dns-dnssec", kwargs={"pk": self.domain.id})
+ )
+ self.assertContains(back_to_page, "Enable DNSSEC")
+
+
+ def test_dnssec_page_loads_with_data_in_domain(self):
+ """DNSSEC overview page loads when domain has DNSSEC data
+ and the template contains a button to disable DNSSEC."""
+
+ page = self.client.get(
+ reverse("domain-dns-dnssec", kwargs={"pk": self.domain_multdsdata.id})
+ )
+ self.assertContains(page, "Disable DNSSEC")
+
+ def test_ds_form_loads_with_no_domain_data(self):
+ """DNSSEC Add DS Data page loads when there is no
+ domain DNSSEC data and shows a button to Add DS Data record"""
+
+ page = self.client.get(
+ reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dnssec_none.id})
+ )
+ self.assertContains(page, "Add DS Data record")
+
+ def test_ds_form_loads_with_ds_data(self):
+ """DNSSEC Add DS Data page loads when there is
+ domain DNSSEC DS data and shows the data"""
+
+ page = self.client.get(
+ reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id})
+ )
+ self.assertContains(page, "DS Data record 1")
+
+ def test_ds_form_loads_with_key_data(self):
+ """DNSSEC Add DS Data page loads when there is
+ domain DNSSEC KEY data and shows an alert"""
+
+ page = self.client.get(
+ reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_keydata.id})
+ )
+ self.assertContains(page, "Warning, you cannot add DS Data")
+
+ def test_key_form_loads_with_no_domain_data(self):
+ """DNSSEC Add Key Data page loads when there is no
+ domain DNSSEC data and shows a button to Add DS Key record"""
+
+ page = self.client.get(
+ reverse("domain-dns-dnssec-keydata", kwargs={"pk": self.domain_dnssec_none.id})
+ )
+ self.assertContains(page, "Add DS Key record")
+
+ def test_key_form_loads_with_key_data(self):
+ """DNSSEC Add Key Data page loads when there is
+ domain DNSSEC Key data and shows the data"""
+
+ page = self.client.get(
+ reverse("domain-dns-dnssec-keydata", kwargs={"pk": self.domain_keydata.id})
+ )
+ self.assertContains(page, "DS Data record 1")
+
+ def test_key_form_loads_with_ds_data(self):
+ """DNSSEC Add Key Data page loads when there is
+ domain DNSSEC DS data and shows an alert"""
+
+ page = self.client.get(
+ reverse("domain-dns-dnssec-keydata", kwargs={"pk": self.domain_dsdata.id})
+ )
+ self.assertContains(page, "Warning, you cannot add Key Data")
- def test_domain_overview_blocked_for_ineligible_user(self):
- """We could easily duplicate this test for all domain management
- views, but a single url test should be solid enough since all domain
- management pages share the same permissions class"""
- self.user.status = User.RESTRICTED
- self.user.save()
- home_page = self.app.get("/")
- self.assertContains(home_page, "igorville.gov")
- with less_console_noise():
- response = self.client.get(reverse("domain", kwargs={"pk": self.domain.id}))
- self.assertEqual(response.status_code, 403)
+
+
class TestApplicationStatus(TestWithUser, WebTest):
From a6f4c2f000c18ba6b04fc2cb6c018c2f160976d4 Mon Sep 17 00:00:00 2001
From: David Kennedy
Date: Fri, 6 Oct 2023 13:59:20 -0400
Subject: [PATCH 43/65] unit tests on ds data form and disable dnssec
---
src/registrar/tests/test_views.py | 52 ++++++++++++++++++++++++++++++-
1 file changed, 51 insertions(+), 1 deletion(-)
diff --git a/src/registrar/tests/test_views.py b/src/registrar/tests/test_views.py
index 8e984be85..5c24b33f4 100644
--- a/src/registrar/tests/test_views.py
+++ b/src/registrar/tests/test_views.py
@@ -1550,7 +1550,6 @@ class TestDomainDNSSEC(TestDomainOverview):
)
self.assertContains(back_to_page, "Enable DNSSEC")
-
def test_dnssec_page_loads_with_data_in_domain(self):
"""DNSSEC overview page loads when domain has DNSSEC data
and the template contains a button to disable DNSSEC."""
@@ -1559,6 +1558,16 @@ class TestDomainDNSSEC(TestDomainOverview):
reverse("domain-dns-dnssec", kwargs={"pk": self.domain_multdsdata.id})
)
self.assertContains(page, "Disable DNSSEC")
+
+ # Prepare the data for the POST request
+ post_data = {
+ 'disable_dnssec': 'Disable DNSSEC', # Replace with the actual form field and value
+ }
+ updated_page = self.client.post(reverse("domain-dns-dnssec", kwargs={"pk": self.domain.id}), post_data, follow=True)
+
+ self.assertEqual(updated_page.status_code, 200)
+
+ self.assertContains(updated_page, "Enable DNSSEC")
def test_ds_form_loads_with_no_domain_data(self):
"""DNSSEC Add DS Data page loads when there is no
@@ -1614,6 +1623,47 @@ class TestDomainDNSSEC(TestDomainOverview):
)
self.assertContains(page, "Warning, you cannot add Key Data")
+ def test_ds_data_form_submits(self):
+ """DS Data form submits successfully
+
+ Uses self.app WebTest because we need to interact with forms.
+ """
+ add_data_page = self.app.get(
+ reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id})
+ )
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ with less_console_noise(): # swallow log warning message
+ result = add_data_page.forms[0].submit()
+ # form submission was a post, response should be a redirect
+ self.assertEqual(result.status_code, 302)
+ self.assertEqual(
+ result["Location"],
+ reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id}),
+ )
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ page = result.follow()
+ self.assertContains(page, "The DS Data records for this domain have been updated.")
+
+ def test_domain_nameservers_form_invalid(self):
+ """DS Data form errors with invalid data
+
+ Uses self.app WebTest because we need to interact with forms.
+ """
+ add_data_page = self.app.get(
+ reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id})
+ )
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # first two nameservers are required, so if we empty one out we should
+ # get a form error
+ add_data_page.forms[0]["form-0-key_tag"] = ""
+ with less_console_noise(): # swallow logged warning message
+ result = add_data_page.forms[0].submit()
+ # form submission was a post with an error, response should be a 200
+ # error text appears twice, once at the top of the page, once around
+ # the field.
+ self.assertContains(result, "Key tag is required", count=2, status_code=200)
From c39384df8c8842076d818659fd977e1b2945d111 Mon Sep 17 00:00:00 2001
From: David Kennedy
Date: Fri, 6 Oct 2023 14:04:37 -0400
Subject: [PATCH 44/65] unit tests completed
---
src/registrar/tests/test_views.py | 46 +++++++++++++++++++++++++++++--
1 file changed, 43 insertions(+), 3 deletions(-)
diff --git a/src/registrar/tests/test_views.py b/src/registrar/tests/test_views.py
index 5c24b33f4..cff7d1614 100644
--- a/src/registrar/tests/test_views.py
+++ b/src/registrar/tests/test_views.py
@@ -1645,7 +1645,7 @@ class TestDomainDNSSEC(TestDomainOverview):
page = result.follow()
self.assertContains(page, "The DS Data records for this domain have been updated.")
- def test_domain_nameservers_form_invalid(self):
+ def test_ds_data_form_invalid(self):
"""DS Data form errors with invalid data
Uses self.app WebTest because we need to interact with forms.
@@ -1665,9 +1665,49 @@ class TestDomainDNSSEC(TestDomainOverview):
# the field.
self.assertContains(result, "Key tag is required", count=2, status_code=200)
+ def test_key_data_form_submits(self):
+ """Key Data form submits successfully
+
+ Uses self.app WebTest because we need to interact with forms.
+ """
+ add_data_page = self.app.get(
+ reverse("domain-dns-dnssec-keydata", kwargs={"pk": self.domain_keydata.id})
+ )
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ with less_console_noise(): # swallow log warning message
+ result = add_data_page.forms[0].submit()
+ # form submission was a post, response should be a redirect
+ self.assertEqual(result.status_code, 302)
+ self.assertEqual(
+ result["Location"],
+ reverse("domain-dns-dnssec-keydata", kwargs={"pk": self.domain_keydata.id}),
+ )
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ page = result.follow()
+ self.assertContains(page, "The Key Data records for this domain have been updated.")
+
+ def test_key_data_form_invalid(self):
+ """Key Data form errors with invalid data
+
+ Uses self.app WebTest because we need to interact with forms.
+ """
+ add_data_page = self.app.get(
+ reverse("domain-dns-dnssec-keydata", kwargs={"pk": self.domain_keydata.id})
+ )
+ session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
+ self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
+ # first two nameservers are required, so if we empty one out we should
+ # get a form error
+ add_data_page.forms[0]["form-0-pub_key"] = ""
+ with less_console_noise(): # swallow logged warning message
+ result = add_data_page.forms[0].submit()
+ # form submission was a post with an error, response should be a 200
+ # error text appears twice, once at the top of the page, once around
+ # the field.
+ self.assertContains(result, "Pub key is required", count=2, status_code=200)
+
-
-
class TestApplicationStatus(TestWithUser, WebTest):
def setUp(self):
super().setUp()
From 6ece85796c6ae4ccf834ae24799546cc820b7ea9 Mon Sep 17 00:00:00 2001
From: David Kennedy
Date: Fri, 6 Oct 2023 15:22:03 -0400
Subject: [PATCH 45/65] removing old migrations
---
.../migrations/0033_domain_dnssec_enabled.py | 19 -------------
...034_domain_dnssec_ds_confirmed_and_more.py | 28 -------------------
...ove_domain_dnssec_ds_confirmed_and_more.py | 24 ----------------
3 files changed, 71 deletions(-)
delete mode 100644 src/registrar/migrations/0033_domain_dnssec_enabled.py
delete mode 100644 src/registrar/migrations/0034_domain_dnssec_ds_confirmed_and_more.py
delete mode 100644 src/registrar/migrations/0035_remove_domain_dnssec_ds_confirmed_and_more.py
diff --git a/src/registrar/migrations/0033_domain_dnssec_enabled.py b/src/registrar/migrations/0033_domain_dnssec_enabled.py
deleted file mode 100644
index a4695a02b..000000000
--- a/src/registrar/migrations/0033_domain_dnssec_enabled.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# Generated by Django 4.2.1 on 2023-10-03 06:36
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
- dependencies = [
- ("registrar", "0032_alter_transitiondomain_status"),
- ]
-
- operations = [
- migrations.AddField(
- model_name="domain",
- name="dnssec_enabled",
- field=models.BooleanField(
- default=False, help_text="Boolean indicating if dnssec is enabled"
- ),
- ),
- ]
diff --git a/src/registrar/migrations/0034_domain_dnssec_ds_confirmed_and_more.py b/src/registrar/migrations/0034_domain_dnssec_ds_confirmed_and_more.py
deleted file mode 100644
index 72513a401..000000000
--- a/src/registrar/migrations/0034_domain_dnssec_ds_confirmed_and_more.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# Generated by Django 4.2.1 on 2023-10-03 17:34
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
- dependencies = [
- ("registrar", "0033_domain_dnssec_enabled"),
- ]
-
- operations = [
- migrations.AddField(
- model_name="domain",
- name="dnssec_ds_confirmed",
- field=models.BooleanField(
- default=False,
- help_text="Boolean indicating if DS record adding is confirmed",
- ),
- ),
- migrations.AddField(
- model_name="domain",
- name="dnssec_key_confirmed",
- field=models.BooleanField(
- default=False,
- help_text="Boolean indicating if Key record adding is confirmed",
- ),
- ),
- ]
diff --git a/src/registrar/migrations/0035_remove_domain_dnssec_ds_confirmed_and_more.py b/src/registrar/migrations/0035_remove_domain_dnssec_ds_confirmed_and_more.py
deleted file mode 100644
index 8b7b7566e..000000000
--- a/src/registrar/migrations/0035_remove_domain_dnssec_ds_confirmed_and_more.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Generated by Django 4.2.1 on 2023-10-06 11:50
-
-from django.db import migrations
-
-
-class Migration(migrations.Migration):
- dependencies = [
- ("registrar", "0034_domain_dnssec_ds_confirmed_and_more"),
- ]
-
- operations = [
- migrations.RemoveField(
- model_name="domain",
- name="dnssec_ds_confirmed",
- ),
- migrations.RemoveField(
- model_name="domain",
- name="dnssec_enabled",
- ),
- migrations.RemoveField(
- model_name="domain",
- name="dnssec_key_confirmed",
- ),
- ]
From a9d57cda079bf91a532f202ed4b5bad131a16334 Mon Sep 17 00:00:00 2001
From: David Kennedy
Date: Fri, 6 Oct 2023 15:38:50 -0400
Subject: [PATCH 46/65] fixed unit tests
---
src/registrar/tests/test_views.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/registrar/tests/test_views.py b/src/registrar/tests/test_views.py
index 3f583ea77..da4d2dce8 100644
--- a/src/registrar/tests/test_views.py
+++ b/src/registrar/tests/test_views.py
@@ -18,6 +18,7 @@ from registrar.models import (
DraftDomain,
DomainInvitation,
Contact,
+ PublicContact,
Website,
UserDomainRole,
User,
@@ -1113,6 +1114,7 @@ class TestWithDomainPermissions(TestWithUser):
if hasattr(self.domain, "contacts"):
self.domain.contacts.all().delete()
DomainApplication.objects.all().delete()
+ PublicContact.objects.all().delete()
Domain.objects.all().delete()
UserDomainRole.objects.all().delete()
except ValueError: # pass if already deleted
From 93d8b8227e046f4dbdd2eb043f03bb59b973c86d Mon Sep 17 00:00:00 2001
From: David Kennedy
Date: Fri, 6 Oct 2023 16:18:59 -0400
Subject: [PATCH 47/65] refactored complicated test code in common, satisfied
the linter
---
src/registrar/forms/common.py | 5 +-
src/registrar/forms/domain.py | 52 ++++----
src/registrar/templatetags/url_helpers.py | 2 +
src/registrar/tests/common.py | 110 ++++++++--------
src/registrar/tests/test_models_domain.py | 1 -
src/registrar/tests/test_views.py | 130 +++++++++++--------
src/registrar/views/domain.py | 146 ++++++++++++----------
7 files changed, 241 insertions(+), 205 deletions(-)
diff --git a/src/registrar/forms/common.py b/src/registrar/forms/common.py
index 377f59797..159113488 100644
--- a/src/registrar/forms/common.py
+++ b/src/registrar/forms/common.py
@@ -1,7 +1,8 @@
# common.py
-#
+#
# ALGORITHM_CHOICES are options for alg attribute in DS Data and Key Data
-# reference: https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml
+# reference:
+# https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml
ALGORITHM_CHOICES = [
(1, "(1) ERSA/MD5 [RSAMD5]"),
(2, "(2) Diffie-Hellman [DH]"),
diff --git a/src/registrar/forms/domain.py b/src/registrar/forms/domain.py
index a9c736175..4ee17a72d 100644
--- a/src/registrar/forms/domain.py
+++ b/src/registrar/forms/domain.py
@@ -7,7 +7,13 @@ 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, PROTOCOL_CHOICES
+from .common import (
+ ALGORITHM_CHOICES,
+ DIGEST_TYPE_CHOICES,
+ FLAG_CHOICES,
+ PROTOCOL_CHOICES,
+)
+
class DomainAddUserForm(forms.Form):
@@ -157,35 +163,27 @@ class DomainDsdataForm(forms.Form):
MinValueValidator(0, message="Value must be between 0 and 65535"),
MaxValueValidator(65535, message="Value must be between 0 and 65535"),
],
- error_messages={
- "required": ("Key tag is required.")
- },
+ error_messages={"required": ("Key tag is required.")},
)
-
+
algorithm = forms.TypedChoiceField(
required=True,
label="Algorithm",
- choices=[(None, "--Select--")] + ALGORITHM_CHOICES,
- error_messages={
- "required": ("Algorithm is required.")
- },
+ choices=[(None, "--Select--")] + ALGORITHM_CHOICES, # type: ignore
+ error_messages={"required": ("Algorithm is required.")},
)
digest_type = forms.TypedChoiceField(
required=True,
label="Digest Type",
- choices=[(None, "--Select--")] + DIGEST_TYPE_CHOICES,
- error_messages={
- "required": ("Digest Type is required.")
- },
+ choices=[(None, "--Select--")] + DIGEST_TYPE_CHOICES, # type: ignore
+ error_messages={"required": ("Digest Type is required.")},
)
digest = forms.CharField(
required=True,
label="Digest",
- error_messages={
- "required": ("Digest is required.")
- },
+ error_messages={"required": ("Digest is required.")},
)
@@ -204,35 +202,27 @@ class DomainKeydataForm(forms.Form):
required=True,
label="Flag",
choices=FLAG_CHOICES,
- error_messages={
- "required": ("Flag is required.")
- },
+ error_messages={"required": ("Flag is required.")},
)
protocol = forms.TypedChoiceField(
required=True,
label="Protocol",
choices=PROTOCOL_CHOICES,
- error_messages={
- "required": ("Protocol is required.")
- },
+ error_messages={"required": ("Protocol is required.")},
)
algorithm = forms.TypedChoiceField(
required=True,
label="Algorithm",
- choices=[(None, "--Select--")] + ALGORITHM_CHOICES,
- error_messages={
- "required": ("Algorithm is required.")
- },
+ choices=[(None, "--Select--")] + ALGORITHM_CHOICES, # type: ignore
+ error_messages={"required": ("Algorithm is required.")},
)
-
+
pub_key = forms.CharField(
required=True,
label="Pub key",
- error_messages={
- "required": ("Pub key is required.")
- },
+ error_messages={"required": ("Pub key is required.")},
)
@@ -240,4 +230,4 @@ DomainKeydataFormset = formset_factory(
DomainKeydataForm,
extra=0,
can_delete=True,
-)
\ No newline at end of file
+)
diff --git a/src/registrar/templatetags/url_helpers.py b/src/registrar/templatetags/url_helpers.py
index 2b983930f..931eedc92 100644
--- a/src/registrar/templatetags/url_helpers.py
+++ b/src/registrar/templatetags/url_helpers.py
@@ -18,12 +18,14 @@ def startswith(text, starts):
return text.startswith(starts)
return False
+
@register.filter("endswith")
def endswith(text, ends):
if isinstance(text, str):
return text.endswith(ends)
return False
+
@register.simple_tag
def public_site_url(url_path):
"""Make a full URL for this path at our public site.
diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py
index b44e21d01..70d0cd1c9 100644
--- a/src/registrar/tests/common.py
+++ b/src/registrar/tests/common.py
@@ -689,18 +689,18 @@ class MockEppLib(TestCase):
"alg": 1,
"pubKey": "AQPJ////4Q==",
}
- dnssecExtensionWithDsData: Mapping[str, Any] = {
- "dsData": [common.DSData(**addDsData1)]
+ dnssecExtensionWithDsData: Mapping[Any, Any] = {
+ "dsData": [common.DSData(**addDsData1)] # type: ignore
}
dnssecExtensionWithMultDsData: Mapping[str, Any] = {
"dsData": [
- common.DSData(**addDsData1),
- common.DSData(**addDsData2),
+ common.DSData(**addDsData1), # type: ignore
+ common.DSData(**addDsData2), # type: ignore
],
}
dnssecExtensionWithKeyData: Mapping[str, Any] = {
"maxSigLife": 3215,
- "keyData": [common.DNSSECKeyData(**keyDataDict)],
+ "keyData": [common.DNSSECKeyData(**keyDataDict)], # type: ignore
}
def mockSend(self, _request, cleaned):
@@ -709,54 +709,9 @@ class MockEppLib(TestCase):
returns objects that simulate what would be in a epp response
but only relevant pieces for tests"""
if isinstance(_request, commands.InfoDomain):
- if getattr(_request, "name", None) == "security.gov":
- return MagicMock(res_data=[self.infoDomainNoContact])
- elif getattr(_request, "name", None) == "dnssec-dsdata.gov":
- return MagicMock(
- res_data=[self.mockDataInfoDomain],
- extensions=[
- extensions.DNSSECExtension(**self.dnssecExtensionWithDsData)
- ],
- )
- elif getattr(_request, "name", None) == "dnssec-multdsdata.gov":
- return MagicMock(
- res_data=[self.mockDataInfoDomain],
- extensions=[
- extensions.DNSSECExtension(**self.dnssecExtensionWithMultDsData)
- ],
- )
- elif getattr(_request, "name", None) == "dnssec-keydata.gov":
- return MagicMock(
- res_data=[self.mockDataInfoDomain],
- extensions=[
- extensions.DNSSECExtension(**self.dnssecExtensionWithKeyData)
- ],
- )
- elif getattr(_request, "name", None) == "dnssec-none.gov":
- # this case is not necessary, but helps improve readability
- return MagicMock(res_data=[self.mockDataInfoDomain])
- elif getattr(_request, "name", None) == "freeman.gov":
- return MagicMock(res_data=[self.InfoDomainWithContacts])
- else:
- return MagicMock(res_data=[self.mockDataInfoDomain])
+ return self.mockInfoDomainCommands(_request, cleaned)
elif isinstance(_request, commands.InfoContact):
- mocked_result: info.InfoContactResultData
-
- # For testing contact types
- match getattr(_request, "id", None):
- case "securityContact":
- mocked_result = self.mockSecurityContact
- case "technicalContact":
- mocked_result = self.mockTechnicalContact
- case "adminContact":
- mocked_result = self.mockAdministrativeContact
- case "regContact":
- mocked_result = self.mockRegistrantContact
- case _:
- # Default contact return
- mocked_result = self.mockDataInfoContact
-
- return MagicMock(res_data=[mocked_result])
+ return self.mockInfoContactCommands(_request, cleaned)
elif (
isinstance(_request, commands.CreateContact)
and getattr(_request, "id", None) == "fail"
@@ -782,6 +737,57 @@ class MockEppLib(TestCase):
raise RegistryError(code=ErrorCode.PARAMETER_VALUE_RANGE_ERROR)
return MagicMock(res_data=[self.mockDataInfoHosts])
+ def mockInfoDomainCommands(self, _request, cleaned):
+ if getattr(_request, "name", None) == "security.gov":
+ return MagicMock(res_data=[self.infoDomainNoContact])
+ elif getattr(_request, "name", None) == "dnssec-dsdata.gov":
+ return MagicMock(
+ res_data=[self.mockDataInfoDomain],
+ extensions=[
+ extensions.DNSSECExtension(**self.dnssecExtensionWithDsData)
+ ],
+ )
+ elif getattr(_request, "name", None) == "dnssec-multdsdata.gov":
+ return MagicMock(
+ res_data=[self.mockDataInfoDomain],
+ extensions=[
+ extensions.DNSSECExtension(**self.dnssecExtensionWithMultDsData)
+ ],
+ )
+ elif getattr(_request, "name", None) == "dnssec-keydata.gov":
+ return MagicMock(
+ res_data=[self.mockDataInfoDomain],
+ extensions=[
+ extensions.DNSSECExtension(**self.dnssecExtensionWithKeyData)
+ ],
+ )
+ elif getattr(_request, "name", None) == "dnssec-none.gov":
+ # this case is not necessary, but helps improve readability
+ return MagicMock(res_data=[self.mockDataInfoDomain])
+ elif getattr(_request, "name", None) == "freeman.gov":
+ return MagicMock(res_data=[self.InfoDomainWithContacts])
+ else:
+ return MagicMock(res_data=[self.mockDataInfoDomain])
+
+ def mockInfoContactCommands(self, _request, cleaned):
+ mocked_result: info.InfoContactResultData
+
+ # For testing contact types
+ match getattr(_request, "id", None):
+ case "securityContact":
+ mocked_result = self.mockSecurityContact
+ case "technicalContact":
+ mocked_result = self.mockTechnicalContact
+ case "adminContact":
+ mocked_result = self.mockAdministrativeContact
+ case "regContact":
+ mocked_result = self.mockRegistrantContact
+ case _:
+ # Default contact return
+ mocked_result = self.mockDataInfoContact
+
+ return MagicMock(res_data=[mocked_result])
+
def setUp(self):
"""mock epp send function as this will fail locally"""
self.mockSendPatch = patch("registrar.models.domain.registry.send")
diff --git a/src/registrar/tests/test_models_domain.py b/src/registrar/tests/test_models_domain.py
index 5b299c112..d0718b4ba 100644
--- a/src/registrar/tests/test_models_domain.py
+++ b/src/registrar/tests/test_models_domain.py
@@ -1003,7 +1003,6 @@ class TestRegistrantDNSSEC(MockEppLib):
super().setUp()
# for the tests, need a domain in the unknown state
self.domain, _ = Domain.objects.get_or_create(name="fake.gov")
-
def tearDown(self):
Domain.objects.all().delete()
diff --git a/src/registrar/tests/test_views.py b/src/registrar/tests/test_views.py
index da4d2dce8..553b45135 100644
--- a/src/registrar/tests/test_views.py
+++ b/src/registrar/tests/test_views.py
@@ -1072,11 +1072,15 @@ class TestWithDomainPermissions(TestWithUser):
super().setUp()
self.domain, _ = Domain.objects.get_or_create(name="igorville.gov")
self.domain_dsdata, _ = Domain.objects.get_or_create(name="dnssec-dsdata.gov")
- self.domain_multdsdata, _ = Domain.objects.get_or_create(name="dnssec-multdsdata.gov")
+ self.domain_multdsdata, _ = Domain.objects.get_or_create(
+ name="dnssec-multdsdata.gov"
+ )
self.domain_keydata, _ = Domain.objects.get_or_create(name="dnssec-keydata.gov")
- # We could simply use domain (igoreville) but this will be more readable in tests
+ # We could simply use domain (igorville) but this will be more readable in tests
# that inherit this setUp
- self.domain_dnssec_none, _ = Domain.objects.get_or_create(name="dnssec-none.gov")
+ self.domain_dnssec_none, _ = Domain.objects.get_or_create(
+ name="dnssec-none.gov"
+ )
self.domain_information, _ = DomainInformation.objects.get_or_create(
creator=self.user, domain=self.domain
)
@@ -1099,13 +1103,17 @@ class TestWithDomainPermissions(TestWithUser):
user=self.user, domain=self.domain_dsdata, role=UserDomainRole.Roles.ADMIN
)
UserDomainRole.objects.get_or_create(
- user=self.user, domain=self.domain_multdsdata, role=UserDomainRole.Roles.ADMIN
+ user=self.user,
+ domain=self.domain_multdsdata,
+ role=UserDomainRole.Roles.ADMIN,
)
UserDomainRole.objects.get_or_create(
user=self.user, domain=self.domain_keydata, role=UserDomainRole.Roles.ADMIN
)
UserDomainRole.objects.get_or_create(
- user=self.user, domain=self.domain_dnssec_none, role=UserDomainRole.Roles.ADMIN
+ user=self.user,
+ domain=self.domain_dnssec_none,
+ role=UserDomainRole.Roles.ADMIN,
)
def tearDown(self):
@@ -1177,7 +1185,7 @@ class TestDomainOverview(TestWithDomainPermissions, WebTest):
detail_page = home_page.click("Manage", index=0)
self.assertContains(detail_page, "igorville.gov")
self.assertContains(detail_page, "Status")
-
+
def test_domain_overview_blocked_for_ineligible_user(self):
"""We could easily duplicate this test for all domain management
views, but a single url test should be solid enough since all domain
@@ -1192,7 +1200,6 @@ class TestDomainOverview(TestWithDomainPermissions, WebTest):
class TestDomainUserManagement(TestDomainOverview):
-
def test_domain_user_management(self):
response = self.client.get(
reverse("domain-users", kwargs={"pk": self.domain.id})
@@ -1350,9 +1357,9 @@ class TestDomainUserManagement(TestDomainOverview):
# Now load the home page and make sure our domain appears there
home_page = self.app.get(reverse("home"))
self.assertContains(home_page, self.domain.name)
-
-class TestDomainNameservers(TestDomainOverview):
+
+class TestDomainNameservers(TestDomainOverview):
def test_domain_nameservers(self):
"""Can load domain's nameservers page."""
page = self.client.get(
@@ -1403,9 +1410,9 @@ class TestDomainNameservers(TestDomainOverview):
# error text appears twice, once at the top of the page, once around
# the field.
self.assertContains(result, "This field is required", count=2, status_code=200)
-
-class TestDomainAuthorizingOfficial(TestDomainOverview):
+
+class TestDomainAuthorizingOfficial(TestDomainOverview):
def test_domain_authorizing_official(self):
"""Can load domain's authorizing official page."""
page = self.client.get(
@@ -1423,9 +1430,9 @@ class TestDomainAuthorizingOfficial(TestDomainOverview):
reverse("domain-authorizing-official", kwargs={"pk": self.domain.id})
)
self.assertContains(page, "Testy")
-
-class TestDomainOrganization(TestDomainOverview):
+
+class TestDomainOrganization(TestDomainOverview):
def test_domain_org_name_address(self):
"""Can load domain's org name and mailing address page."""
page = self.client.get(
@@ -1461,9 +1468,9 @@ class TestDomainOrganization(TestDomainOverview):
self.assertContains(success_result_page, "Not igorville")
self.assertContains(success_result_page, "Faketown")
-
-class TestDomainContactInformation(TestDomainOverview):
+
+class TestDomainContactInformation(TestDomainOverview):
def test_domain_your_contact_information(self):
"""Can load domain's your contact information page."""
page = self.client.get(
@@ -1479,9 +1486,9 @@ class TestDomainContactInformation(TestDomainOverview):
reverse("domain-your-contact-information", kwargs={"pk": self.domain.id})
)
self.assertContains(page, "Testy")
-
-class TestDomainSecurityEmail(TestDomainOverview):
+
+class TestDomainSecurityEmail(TestDomainOverview):
def test_domain_security_email_existing_security_contact(self):
"""Can load domain's security email page."""
self.mockSendPatch = patch("registrar.models.domain.registry.send")
@@ -1546,47 +1553,50 @@ class TestDomainSecurityEmail(TestDomainOverview):
self.assertContains(
success_page, "The security email for this domain has been updated"
)
-
-
+
+
class TestDomainDNSSEC(TestDomainOverview):
-
+
"""MockEPPLib is already inherited."""
-
+
def test_dnssec_page_refreshes_enable_button(self):
"""DNSSEC overview page loads when domain has no DNSSEC data
and shows a 'Enable DNSSEC' button. When button is clicked the template
updates. When user navigates away then comes back to the page, the
'Enable DNSSEC' button is shown again."""
# home_page = self.app.get("/")
-
+
page = self.client.get(
reverse("domain-dns-dnssec", kwargs={"pk": self.domain.id})
)
self.assertContains(page, "Enable DNSSEC")
-
+
# Prepare the data for the POST request
post_data = {
- 'enable_dnssec': 'Enable DNSSEC', # Replace with the actual form field and value
- # Add other form fields as needed
+ "enable_dnssec": "Enable DNSSEC",
}
- updated_page = self.client.post(reverse("domain-dns-dnssec", kwargs={"pk": self.domain.id}), post_data, follow=True)
-
+ updated_page = self.client.post(
+ reverse("domain-dns-dnssec", kwargs={"pk": self.domain.id}),
+ post_data,
+ follow=True,
+ )
+
self.assertEqual(updated_page.status_code, 200)
-
+
self.assertContains(updated_page, "Add DS Data")
self.assertContains(updated_page, "Add Key Data")
-
+
self.app.get("/")
-
+
back_to_page = self.client.get(
reverse("domain-dns-dnssec", kwargs={"pk": self.domain.id})
)
self.assertContains(back_to_page, "Enable DNSSEC")
-
+
def test_dnssec_page_loads_with_data_in_domain(self):
"""DNSSEC overview page loads when domain has DNSSEC data
and the template contains a button to disable DNSSEC."""
-
+
page = self.client.get(
reverse("domain-dns-dnssec", kwargs={"pk": self.domain_multdsdata.id})
)
@@ -1594,63 +1604,71 @@ class TestDomainDNSSEC(TestDomainOverview):
# Prepare the data for the POST request
post_data = {
- 'disable_dnssec': 'Disable DNSSEC', # Replace with the actual form field and value
+ "disable_dnssec": "Disable DNSSEC",
}
- updated_page = self.client.post(reverse("domain-dns-dnssec", kwargs={"pk": self.domain.id}), post_data, follow=True)
-
+ updated_page = self.client.post(
+ reverse("domain-dns-dnssec", kwargs={"pk": self.domain.id}),
+ post_data,
+ follow=True,
+ )
+
self.assertEqual(updated_page.status_code, 200)
-
+
self.assertContains(updated_page, "Enable DNSSEC")
-
+
def test_ds_form_loads_with_no_domain_data(self):
"""DNSSEC Add DS Data page loads when there is no
domain DNSSEC data and shows a button to Add DS Data record"""
-
+
page = self.client.get(
- reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dnssec_none.id})
+ reverse(
+ "domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dnssec_none.id}
+ )
)
self.assertContains(page, "Add DS Data record")
-
+
def test_ds_form_loads_with_ds_data(self):
"""DNSSEC Add DS Data page loads when there is
domain DNSSEC DS data and shows the data"""
-
+
page = self.client.get(
reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dsdata.id})
)
self.assertContains(page, "DS Data record 1")
-
+
def test_ds_form_loads_with_key_data(self):
"""DNSSEC Add DS Data page loads when there is
domain DNSSEC KEY data and shows an alert"""
-
+
page = self.client.get(
reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_keydata.id})
)
self.assertContains(page, "Warning, you cannot add DS Data")
-
+
def test_key_form_loads_with_no_domain_data(self):
"""DNSSEC Add Key Data page loads when there is no
domain DNSSEC data and shows a button to Add DS Key record"""
-
+
page = self.client.get(
- reverse("domain-dns-dnssec-keydata", kwargs={"pk": self.domain_dnssec_none.id})
+ reverse(
+ "domain-dns-dnssec-keydata", kwargs={"pk": self.domain_dnssec_none.id}
+ )
)
self.assertContains(page, "Add DS Key record")
-
+
def test_key_form_loads_with_key_data(self):
"""DNSSEC Add Key Data page loads when there is
domain DNSSEC Key data and shows the data"""
-
+
page = self.client.get(
reverse("domain-dns-dnssec-keydata", kwargs={"pk": self.domain_keydata.id})
)
self.assertContains(page, "DS Data record 1")
-
+
def test_key_form_loads_with_ds_data(self):
"""DNSSEC Add Key Data page loads when there is
domain DNSSEC DS data and shows an alert"""
-
+
page = self.client.get(
reverse("domain-dns-dnssec-keydata", kwargs={"pk": self.domain_dsdata.id})
)
@@ -1676,7 +1694,9 @@ class TestDomainDNSSEC(TestDomainOverview):
)
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
page = result.follow()
- self.assertContains(page, "The DS Data records for this domain have been updated.")
+ self.assertContains(
+ page, "The DS Data records for this domain have been updated."
+ )
def test_ds_data_form_invalid(self):
"""DS Data form errors with invalid data
@@ -1718,7 +1738,9 @@ class TestDomainDNSSEC(TestDomainOverview):
)
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
page = result.follow()
- self.assertContains(page, "The Key Data records for this domain have been updated.")
+ self.assertContains(
+ page, "The Key Data records for this domain have been updated."
+ )
def test_key_data_form_invalid(self):
"""Key Data form errors with invalid data
@@ -1739,8 +1761,8 @@ class TestDomainDNSSEC(TestDomainOverview):
# error text appears twice, once at the top of the page, once around
# the field.
self.assertContains(result, "Pub key is required", count=2, status_code=200)
-
-
+
+
class TestApplicationStatus(TestWithUser, WebTest):
def setUp(self):
super().setUp()
diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py
index 9334700ef..e51395ba3 100644
--- a/src/registrar/views/domain.py
+++ b/src/registrar/views/domain.py
@@ -233,20 +233,24 @@ class DomainDNSSECView(DomainPermissionView, FormMixin):
template_name = "domain_dnssec.html"
form_class = DomainDnssecForm
-
+
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
"""The initial value for the form (which is a formset here)."""
self.domain = self.get_object()
-
- has_dnssec_records = self.domain.dnssecdata is not None
-
- # Create HTML for the buttons
- modal_button = 'Disable DNSSEC'
- context['modal_button'] = modal_button
- context['has_dnssec_records'] = has_dnssec_records
- context['dnssec_enabled'] = self.request.session.pop('dnssec_enabled', False)
+ has_dnssec_records = self.domain.dnssecdata is not None
+
+ # Create HTML for the buttons
+ modal_button = (
+ 'Disable DNSSEC'
+ )
+
+ context["modal_button"] = modal_button
+ context["has_dnssec_records"] = has_dnssec_records
+ context["dnssec_enabled"] = self.request.session.pop("dnssec_enabled", False)
return context
@@ -255,27 +259,24 @@ class DomainDNSSECView(DomainPermissionView, FormMixin):
return reverse("domain-dns-dnssec", kwargs={"pk": self.domain.pk})
def post(self, request, *args, **kwargs):
- """Form submission posts to this view.
- """
+ """Form submission posts to this view."""
self.domain = self.get_object()
form = self.get_form()
- if form.is_valid():
- if 'disable_dnssec' in request.POST:
+ if form.is_valid():
+ if "disable_dnssec" in request.POST:
try:
self.domain.dnssecdata = {}
except RegistryError as err:
errmsg = "Error removing existing DNSSEC record(s)."
logger.error(errmsg + ": " + err)
- messages.error(
- self.request, errmsg
- )
- request.session['dnssec_ds_confirmed'] = False
- request.session['dnssec_key_confirmed'] = False
- elif 'enable_dnssec' in request.POST:
- request.session['dnssec_enabled'] = True
- request.session['dnssec_ds_confirmed'] = False
- request.session['dnssec_key_confirmed'] = False
-
+ messages.error(self.request, errmsg)
+ request.session["dnssec_ds_confirmed"] = False
+ request.session["dnssec_key_confirmed"] = False
+ elif "enable_dnssec" in request.POST:
+ request.session["dnssec_enabled"] = True
+ request.session["dnssec_ds_confirmed"] = False
+ request.session["dnssec_key_confirmed"] = False
+
return self.form_valid(form)
@@ -292,21 +293,28 @@ class DomainDsdataView(DomainPermissionView, FormMixin):
domain = self.get_object()
dnssecdata: extensions.DNSSECExtension = domain.dnssecdata
initial_data = []
-
- if dnssecdata is not None:
+ if dnssecdata is not None:
if dnssecdata.keyData is not None:
# TODO: Throw an error
pass
if dnssecdata.dsData is not None:
# Add existing nameservers as initial data
- initial_data.extend({"key_tag": record.keyTag, "algorithm": record.alg, "digest_type": record.digestType, "digest": record.digest} for record in dnssecdata.dsData)
-
+ initial_data.extend(
+ {
+ "key_tag": record.keyTag,
+ "algorithm": record.alg,
+ "digest_type": record.digestType,
+ "digest": record.digest,
+ }
+ for record in dnssecdata.dsData
+ )
+
# Ensure at least 3 fields, filled or empty
while len(initial_data) == 0:
initial_data.append({})
-
+
return initial_data
def get_success_url(self):
@@ -319,16 +327,18 @@ class DomainDsdataView(DomainPermissionView, FormMixin):
# use "formset" instead of "form" for the key
context["formset"] = context.pop("form")
- # set the dnssec_ds_confirmed flag in the context for this view
+ # set the dnssec_ds_confirmed flag in the context for this view
# based either on the existence of DS Data in the domain,
# or on the flag stored in the session
domain = self.get_object()
dnssecdata: extensions.DNSSECExtension = domain.dnssecdata
if dnssecdata is not None and dnssecdata.dsData is not None:
- self.request.session['dnssec_ds_confirmed'] = True
+ self.request.session["dnssec_ds_confirmed"] = True
- context['dnssec_ds_confirmed'] = self.request.session.get('dnssec_ds_confirmed', False)
+ context["dnssec_ds_confirmed"] = self.request.session.get(
+ "dnssec_ds_confirmed", False
+ )
return context
def post(self, request, *args, **kwargs):
@@ -336,14 +346,14 @@ class DomainDsdataView(DomainPermissionView, FormMixin):
self.object = self.get_object()
formset = self.get_form()
- if 'confirm-ds' in request.POST:
- request.session['dnssec_ds_confirmed'] = True
- request.session['dnssec_key_confirmed'] = False
+ if "confirm-ds" in request.POST:
+ request.session["dnssec_ds_confirmed"] = True
+ request.session["dnssec_key_confirmed"] = False
return super().form_valid(formset)
-
- if 'btn-cancel-click' in request.POST:
- return redirect('/', {'formset': formset},RequestContext(request))
-
+
+ if "btn-cancel-click" in request.POST:
+ return redirect("/", {"formset": formset}, RequestContext(request))
+
if formset.is_valid():
return self.form_valid(formset)
else:
@@ -353,11 +363,12 @@ class DomainDsdataView(DomainPermissionView, FormMixin):
"""The formset is valid, perform something with it."""
# Set the nameservers from the formset
- dnssecdata = {"dsData":[]}
+ dnssecdata = {"dsData": []}
for form in formset:
try:
- # if 'delete' not in form.cleaned_data or form.cleaned_data['delete'] == False:
+ # if 'delete' not in form.cleaned_data
+ # or form.cleaned_data['delete'] == False:
dsrecord = {
"keyTag": form.cleaned_data["key_tag"],
"alg": form.cleaned_data["algorithm"],
@@ -378,9 +389,7 @@ class DomainDsdataView(DomainPermissionView, FormMixin):
errmsg = "Error updating DNSSEC data in the registry."
logger.error(errmsg)
logger.error(err)
- messages.error(
- self.request, errmsg
- )
+ messages.error(self.request, errmsg)
return self.form_invalid(formset)
else:
messages.success(
@@ -388,7 +397,6 @@ class DomainDsdataView(DomainPermissionView, FormMixin):
)
# superclass has the redirect
return super().form_valid(formset)
-
class DomainKeydataView(DomainPermissionView, FormMixin):
@@ -404,21 +412,28 @@ class DomainKeydataView(DomainPermissionView, FormMixin):
domain = self.get_object()
dnssecdata: extensions.DNSSECExtension = domain.dnssecdata
initial_data = []
-
- if dnssecdata is not None:
+ 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)
-
+ initial_data.extend(
+ {
+ "flag": record.flags,
+ "protocol": record.protocol,
+ "algorithm": record.alg,
+ "pub_key": record.pubKey,
+ }
+ for record in dnssecdata.keyData
+ )
+
# Ensure at least 3 fields, filled or empty
while len(initial_data) == 0:
initial_data.append({})
-
+
return initial_data
def get_success_url(self):
@@ -431,32 +446,34 @@ class DomainKeydataView(DomainPermissionView, FormMixin):
# use "formset" instead of "form" for the key
context["formset"] = context.pop("form")
- # set the dnssec_key_confirmed flag in the context for this view
+ # set the dnssec_key_confirmed flag in the context for this view
# based either on the existence of Key Data in the domain,
# or on the flag stored in the session
domain = self.get_object()
dnssecdata: extensions.DNSSECExtension = domain.dnssecdata
if dnssecdata is not None and dnssecdata.keyData is not None:
- self.request.session['dnssec_key_confirmed'] = True
+ self.request.session["dnssec_key_confirmed"] = True
- context['dnssec_key_confirmed'] = self.request.session.get('dnssec_key_confirmed', False)
+ context["dnssec_key_confirmed"] = self.request.session.get(
+ "dnssec_key_confirmed", False
+ )
return context
def post(self, request, *args, **kwargs):
"""Formset submission posts to this view."""
self.object = self.get_object()
formset = self.get_form()
-
- if 'confirm-key' in request.POST:
- request.session['dnssec_key_confirmed'] = True
- request.session['dnssec_ds_confirmed'] = False
+
+ if "confirm-key" in request.POST:
+ request.session["dnssec_key_confirmed"] = True
+ request.session["dnssec_ds_confirmed"] = False
self.object.save()
return super().form_valid(formset)
-
- if 'btn-cancel-click' in request.POST:
- return redirect('/', {'formset': formset},RequestContext(request))
-
+
+ if "btn-cancel-click" in request.POST:
+ return redirect("/", {"formset": formset}, RequestContext(request))
+
if formset.is_valid():
return self.form_valid(formset)
else:
@@ -466,11 +483,12 @@ class DomainKeydataView(DomainPermissionView, FormMixin):
"""The formset is valid, perform something with it."""
# Set the nameservers from the formset
- dnssecdata = {"keyData":[]}
+ dnssecdata = {"keyData": []}
for form in formset:
try:
- # if 'delete' not in form.cleaned_data or form.cleaned_data['delete'] == False:
+ # if 'delete' not in form.cleaned_data
+ # or form.cleaned_data['delete'] == False:
keyrecord = {
"flags": form.cleaned_data["flag"],
"protocol": form.cleaned_data["protocol"],
@@ -490,9 +508,7 @@ class DomainKeydataView(DomainPermissionView, FormMixin):
errmsg = "Error updating DNSSEC data in the registry."
logger.error(errmsg)
logger.error(err)
- messages.error(
- self.request, errmsg
- )
+ messages.error(self.request, errmsg)
return self.form_invalid(formset)
else:
messages.success(
From 93696c31c6822fb36d49aa808a52453cc0f5aa38 Mon Sep 17 00:00:00 2001
From: David Kennedy
Date: Mon, 9 Oct 2023 16:30:04 -0400
Subject: [PATCH 48/65] first pass at dnssec rewrite
---
src/registrar/models/domain.py | 73 ++++++++++++++++++++++++++++++----
1 file changed, 66 insertions(+), 7 deletions(-)
diff --git a/src/registrar/models/domain.py b/src/registrar/models/domain.py
index 0268cc4a4..90a0168c4 100644
--- a/src/registrar/models/domain.py
+++ b/src/registrar/models/domain.py
@@ -292,21 +292,80 @@ class Domain(TimeStampedModel, DomainHelper):
logger.info("Domain does not have dnssec data defined %s" % err)
return None
+ def getDnssecdataChanges(
+ self, _dnssecdata: dict
+ ) -> tuple[dict, dict]:
+ """
+ calls self.dnssecdata, it should pull from cache but may result
+ in an epp call
+ returns tuple of 2 values as follows:
+ addExtension: dict
+ remExtension: dict
+
+ addExtension includes all dsData or keyData to be added
+ remExtension includes all dsData or keyData to be removed
+
+ method operates on dsData OR keyData, never a mix of the two;
+ operates based on which is present in _dnssecdata;
+ if neither is present, addExtension will be empty dict, and
+ remExtension will be all existing dnssecdata to be deleted
+ """
+
+ oldDnssecdata = self.dnssecdata
+ addDnssecdata = {}
+ remDnssecdata = {}
+
+ if len(_dnssecdata["dsData"]) > 0:
+ # initialize addDnssecdata and remDnssecdata for dsData
+ addDnssecdata["dsData"] = []
+ remDnssecdata["dsData"] = []
+
+ # if existing dsData not in new dsData, mark for removal
+ remDnssecdata["dsData"] = [dsData for dsData in oldDnssecdata["dsData"] if dsData not in _dnssecdata["dsData"]]
+
+ # if new dsData not in existing dsData, mark for add
+ addDnssecdata["dsData"] = [dsData for dsData in _dnssecdata["dsData"] if dsData not in oldDnssecdata["dsData"]]
+ elif len(_dnssecdata["keyData"]) > 0:
+ # initialize addDnssecdata and remDnssecdata for keyData
+ addDnssecdata["keyData"] = []
+ remDnssecdata["keyData"] = []
+
+ # if existing keyData not in new keyData, mark for removal
+ remDnssecdata["keyData"] = [keyData for keyData in oldDnssecdata["keyData"] if keyData not in _dnssecdata["keyData"]]
+
+ # if new keyData not in existing keyData, mark for add
+ addDnssecdata["keyData"] = [keyData for keyData in _dnssecdata["keyData"] if keyData not in oldDnssecdata["keyData"]]
+ else:
+ # there are no new dsData or keyData, remove all
+ remDnssecdata["dsData"] = oldDnssecdata["dsData"]
+ remDnssecdata["keyData"] = oldDnssecdata["keyData"]
+
+ return addDnssecdata, remDnssecdata
+
@dnssecdata.setter # type: ignore
def dnssecdata(self, _dnssecdata: dict):
- updateParams = {
+ _addDnssecdata, _remDnssecdata = self.getDnssecdataChanges(_dnssecdata)
+ addParams = {
"maxSigLife": _dnssecdata.get("maxSigLife", None),
"dsData": _dnssecdata.get("dsData", None),
"keyData": _dnssecdata.get("keyData", None),
- "remAllDsKeyData": True,
}
- request = commands.UpdateDomain(name=self.name)
- extension = commands.UpdateDomainDNSSECExtension(**updateParams)
- request.add_extension(extension)
+ remParams = {
+ "maxSigLife": _dnssecdata.get("maxSigLife", None),
+ "dsData": _dnssecdata.get("dsData", None),
+ "keyData": _dnssecdata.get("keyData", None),
+ }
+ addRequest = commands.UpdateDomain(name=self.name)
+ addExtension = commands.UpdateDomainDNSSECExtension(**addParams)
+ addRequest.add_extension(addExtension)
+ remRequest = commands.UpdateDomain(name=self.name)
+ remExtension = commands.UpdateDomainDNSSECExtension(**remParams)
+ remRequest.add_extension(remExtension)
try:
- registry.send(request, cleaned=True)
+ registry.send(addRequest, cleaned=True)
+ registry.send(remRequest, cleaned=True)
except RegistryError as e:
- logger.error("Error adding DNSSEC, code was %s error was %s" % (e.code, e))
+ logger.error("Error updating DNSSEC, code was %s error was %s" % (e.code, e))
raise e
@nameservers.setter # type: ignore
From 6bd93d56e21357cf57c80ac9b8dbbbaf3eac34d3 Mon Sep 17 00:00:00 2001
From: David Kennedy
Date: Mon, 9 Oct 2023 19:45:44 -0400
Subject: [PATCH 49/65] updated logic for setter of dnssec
---
src/registrar/forms/domain.py | 5 +++
src/registrar/models/domain.py | 56 +++++++++++++++++++---------------
src/registrar/views/domain.py | 10 +++---
3 files changed, 41 insertions(+), 30 deletions(-)
diff --git a/src/registrar/forms/domain.py b/src/registrar/forms/domain.py
index 4ee17a72d..41b15e688 100644
--- a/src/registrar/forms/domain.py
+++ b/src/registrar/forms/domain.py
@@ -169,6 +169,7 @@ class DomainDsdataForm(forms.Form):
algorithm = forms.TypedChoiceField(
required=True,
label="Algorithm",
+ coerce=int, # need to coerce into int so dsData objects can be compared
choices=[(None, "--Select--")] + ALGORITHM_CHOICES, # type: ignore
error_messages={"required": ("Algorithm is required.")},
)
@@ -176,6 +177,7 @@ class DomainDsdataForm(forms.Form):
digest_type = forms.TypedChoiceField(
required=True,
label="Digest Type",
+ coerce=int, # need to coerce into int so dsData objects can be compared
choices=[(None, "--Select--")] + DIGEST_TYPE_CHOICES, # type: ignore
error_messages={"required": ("Digest Type is required.")},
)
@@ -201,6 +203,7 @@ class DomainKeydataForm(forms.Form):
flag = forms.TypedChoiceField(
required=True,
label="Flag",
+ coerce=int,
choices=FLAG_CHOICES,
error_messages={"required": ("Flag is required.")},
)
@@ -208,6 +211,7 @@ class DomainKeydataForm(forms.Form):
protocol = forms.TypedChoiceField(
required=True,
label="Protocol",
+ coerce=int,
choices=PROTOCOL_CHOICES,
error_messages={"required": ("Protocol is required.")},
)
@@ -215,6 +219,7 @@ class DomainKeydataForm(forms.Form):
algorithm = forms.TypedChoiceField(
required=True,
label="Algorithm",
+ coerce=int,
choices=[(None, "--Select--")] + ALGORITHM_CHOICES, # type: ignore
error_messages={"required": ("Algorithm is required.")},
)
diff --git a/src/registrar/models/domain.py b/src/registrar/models/domain.py
index 90a0168c4..2188a1764 100644
--- a/src/registrar/models/domain.py
+++ b/src/registrar/models/domain.py
@@ -291,7 +291,7 @@ class Domain(TimeStampedModel, DomainHelper):
# TODO - 433 error handling ticket should address this
logger.info("Domain does not have dnssec data defined %s" % err)
return None
-
+
def getDnssecdataChanges(
self, _dnssecdata: dict
) -> tuple[dict, dict]:
@@ -312,33 +312,37 @@ class Domain(TimeStampedModel, DomainHelper):
"""
oldDnssecdata = self.dnssecdata
- addDnssecdata = {}
- remDnssecdata = {}
+ addDnssecdata = {"dsData": [], "keyData": [],}
+ remDnssecdata = {"dsData": [], "keyData": [],}
+
+ if _dnssecdata and len(_dnssecdata["dsData"]) > 0:
- if len(_dnssecdata["dsData"]) > 0:
# initialize addDnssecdata and remDnssecdata for dsData
- addDnssecdata["dsData"] = []
+ addDnssecdata["dsData"] = _dnssecdata["dsData"]
remDnssecdata["dsData"] = []
- # if existing dsData not in new dsData, mark for removal
- remDnssecdata["dsData"] = [dsData for dsData in oldDnssecdata["dsData"] if dsData not in _dnssecdata["dsData"]]
+ if oldDnssecdata and len(oldDnssecdata.dsData) > 0:
+ # if existing dsData not in new dsData, mark for removal
+ remDnssecdata["dsData"] = [dsData for dsData in oldDnssecdata.dsData if dsData not in _dnssecdata["dsData"]]
- # if new dsData not in existing dsData, mark for add
- addDnssecdata["dsData"] = [dsData for dsData in _dnssecdata["dsData"] if dsData not in oldDnssecdata["dsData"]]
- elif len(_dnssecdata["keyData"]) > 0:
+ # if new dsData not in existing dsData, mark for add
+ addDnssecdata["dsData"] = [dsData for dsData in _dnssecdata["dsData"] if dsData not in oldDnssecdata.dsData]
+
+ elif _dnssecdata and len(_dnssecdata["keyData"]) > 0:
# initialize addDnssecdata and remDnssecdata for keyData
- addDnssecdata["keyData"] = []
+ addDnssecdata["keyData"] = _dnssecdata["keyData"]
remDnssecdata["keyData"] = []
- # if existing keyData not in new keyData, mark for removal
- remDnssecdata["keyData"] = [keyData for keyData in oldDnssecdata["keyData"] if keyData not in _dnssecdata["keyData"]]
+ if oldDnssecdata and len(oldDnssecdata.keyData) > 0:
+ # if existing keyData not in new keyData, mark for removal
+ remDnssecdata["keyData"] = [keyData for keyData in oldDnssecdata.keyData if keyData not in _dnssecdata["keyData"]]
- # if new keyData not in existing keyData, mark for add
- addDnssecdata["keyData"] = [keyData for keyData in _dnssecdata["keyData"] if keyData not in oldDnssecdata["keyData"]]
+ # if new keyData not in existing keyData, mark for add
+ addDnssecdata["keyData"] = [keyData for keyData in _dnssecdata["keyData"] if keyData not in oldDnssecdata.keyData]
else:
# there are no new dsData or keyData, remove all
- remDnssecdata["dsData"] = oldDnssecdata["dsData"]
- remDnssecdata["keyData"] = oldDnssecdata["keyData"]
+ remDnssecdata["dsData"] = getattr(oldDnssecdata, "dsData", None)
+ remDnssecdata["keyData"] = getattr(oldDnssecdata, "keyData", None)
return addDnssecdata, remDnssecdata
@@ -346,14 +350,14 @@ class Domain(TimeStampedModel, DomainHelper):
def dnssecdata(self, _dnssecdata: dict):
_addDnssecdata, _remDnssecdata = self.getDnssecdataChanges(_dnssecdata)
addParams = {
- "maxSigLife": _dnssecdata.get("maxSigLife", None),
- "dsData": _dnssecdata.get("dsData", None),
- "keyData": _dnssecdata.get("keyData", None),
+ "maxSigLife": _addDnssecdata.get("maxSigLife", None),
+ "dsData": _addDnssecdata.get("dsData", None),
+ "keyData": _addDnssecdata.get("keyData", None),
}
remParams = {
- "maxSigLife": _dnssecdata.get("maxSigLife", None),
- "dsData": _dnssecdata.get("dsData", None),
- "keyData": _dnssecdata.get("keyData", None),
+ "maxSigLife": _remDnssecdata.get("maxSigLife", None),
+ "remDsData": _remDnssecdata.get("dsData", None),
+ "remKeyData": _remDnssecdata.get("keyData", None),
}
addRequest = commands.UpdateDomain(name=self.name)
addExtension = commands.UpdateDomainDNSSECExtension(**addParams)
@@ -362,8 +366,10 @@ class Domain(TimeStampedModel, DomainHelper):
remExtension = commands.UpdateDomainDNSSECExtension(**remParams)
remRequest.add_extension(remExtension)
try:
- registry.send(addRequest, cleaned=True)
- registry.send(remRequest, cleaned=True)
+ if len(_addDnssecdata.get("dsData", [])) > 0 or len(_addDnssecdata.get("keyData",[])) > 0:
+ registry.send(addRequest, cleaned=True)
+ if len(_remDnssecdata.get("dsData", [])) > 0 or len(_remDnssecdata.get("keyData", [])) > 0:
+ registry.send(remRequest, cleaned=True)
except RegistryError as e:
logger.error("Error updating DNSSEC, code was %s error was %s" % (e.code, e))
raise e
diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py
index e51395ba3..b4509b162 100644
--- a/src/registrar/views/domain.py
+++ b/src/registrar/views/domain.py
@@ -371,8 +371,8 @@ class DomainDsdataView(DomainPermissionView, FormMixin):
# or form.cleaned_data['delete'] == False:
dsrecord = {
"keyTag": form.cleaned_data["key_tag"],
- "alg": form.cleaned_data["algorithm"],
- "digestType": form.cleaned_data["digest_type"],
+ "alg": int(form.cleaned_data["algorithm"]),
+ "digestType": int(form.cleaned_data["digest_type"]),
"digest": form.cleaned_data["digest"],
}
dnssecdata["dsData"].append(common.DSData(**dsrecord))
@@ -490,9 +490,9 @@ class DomainKeydataView(DomainPermissionView, FormMixin):
# if 'delete' not in form.cleaned_data
# or form.cleaned_data['delete'] == False:
keyrecord = {
- "flags": form.cleaned_data["flag"],
- "protocol": form.cleaned_data["protocol"],
- "alg": form.cleaned_data["algorithm"],
+ "flags": int(form.cleaned_data["flag"]),
+ "protocol": int(form.cleaned_data["protocol"]),
+ "alg": int(form.cleaned_data["algorithm"]),
"pubKey": form.cleaned_data["pub_key"],
}
dnssecdata["keyData"].append(common.DNSSECKeyData(**keyrecord))
From 95b1a02789c9fb80222740c2a369c259708db5df Mon Sep 17 00:00:00 2001
From: David Kennedy
Date: Tue, 10 Oct 2023 05:25:15 -0400
Subject: [PATCH 50/65] modified unit tests
---
src/registrar/tests/common.py | 55 ++++++----
src/registrar/tests/test_models_domain.py | 126 +++++++++++++++++-----
2 files changed, 136 insertions(+), 45 deletions(-)
diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py
index 60a23b3b4..6ede8965b 100644
--- a/src/registrar/tests/common.py
+++ b/src/registrar/tests/common.py
@@ -705,17 +705,23 @@ class MockEppLib(TestCase):
"pubKey": "AQPJ////4Q==",
}
dnssecExtensionWithDsData: Mapping[Any, Any] = {
- "dsData": [common.DSData(**addDsData1)] # type: ignore
+ "dsData": [common.DSData(**addDsData1)], # type: ignore
+ "keyData": [],
}
dnssecExtensionWithMultDsData: Mapping[str, Any] = {
"dsData": [
common.DSData(**addDsData1), # type: ignore
common.DSData(**addDsData2), # type: ignore
],
+ "keyData": [],
}
dnssecExtensionWithKeyData: Mapping[str, Any] = {
- "maxSigLife": 3215,
"keyData": [common.DNSSECKeyData(**keyDataDict)], # type: ignore
+ "dsData": [],
+ }
+ dnssecExtensionRemovingDsData: Mapping[Any, Any] = {
+ "dsData": [],
+ "keyData": [],
}
def mockSend(self, _request, cleaned):
@@ -756,26 +762,35 @@ class MockEppLib(TestCase):
if getattr(_request, "name", None) == "security.gov":
return MagicMock(res_data=[self.infoDomainNoContact])
elif getattr(_request, "name", None) == "dnssec-dsdata.gov":
- return MagicMock(
- res_data=[self.mockDataInfoDomain],
- extensions=[
- extensions.DNSSECExtension(**self.dnssecExtensionWithDsData)
- ],
- )
+ if self.mockedSendFunction.call_count == 1:
+ return MagicMock(res_data=[self.mockDataInfoDomain])
+ else:
+ return MagicMock(
+ res_data=[self.mockDataInfoDomain],
+ extensions=[
+ extensions.DNSSECExtension(**self.dnssecExtensionWithDsData)
+ ],
+ )
elif getattr(_request, "name", None) == "dnssec-multdsdata.gov":
- return MagicMock(
- res_data=[self.mockDataInfoDomain],
- extensions=[
- extensions.DNSSECExtension(**self.dnssecExtensionWithMultDsData)
- ],
- )
+ if self.mockedSendFunction.call_count == 1:
+ return MagicMock(res_data=[self.mockDataInfoDomain])
+ else:
+ return MagicMock(
+ res_data=[self.mockDataInfoDomain],
+ extensions=[
+ extensions.DNSSECExtension(**self.dnssecExtensionWithMultDsData)
+ ],
+ )
elif getattr(_request, "name", None) == "dnssec-keydata.gov":
- return MagicMock(
- res_data=[self.mockDataInfoDomain],
- extensions=[
- extensions.DNSSECExtension(**self.dnssecExtensionWithKeyData)
- ],
- )
+ if self.mockedSendFunction.call_count == 1:
+ return MagicMock(res_data=[self.mockDataInfoDomain])
+ else:
+ return MagicMock(
+ res_data=[self.mockDataInfoDomain],
+ extensions=[
+ extensions.DNSSECExtension(**self.dnssecExtensionWithKeyData)
+ ],
+ )
elif getattr(_request, "name", None) == "dnssec-none.gov":
# this case is not necessary, but helps improve readability
return MagicMock(res_data=[self.mockDataInfoDomain])
diff --git a/src/registrar/tests/test_models_domain.py b/src/registrar/tests/test_models_domain.py
index d0718b4ba..b8d648e45 100644
--- a/src/registrar/tests/test_models_domain.py
+++ b/src/registrar/tests/test_models_domain.py
@@ -984,15 +984,25 @@ class TestRegistrantDNSSEC(MockEppLib):
"""Rule: Registrants may modify their secure DNS data"""
# helper function to create UpdateDomainDNSSECExtention object for verification
- def createUpdateExtension(self, dnssecdata: extensions.DNSSECExtension):
- return commands.UpdateDomainDNSSECExtension(
- maxSigLife=dnssecdata.maxSigLife,
- dsData=dnssecdata.dsData,
- keyData=dnssecdata.keyData,
- remDsData=None,
- remKeyData=None,
- remAllDsKeyData=True,
- )
+ def createUpdateExtension(self, dnssecdata: extensions.DNSSECExtension, remove=False):
+ if not remove:
+ return commands.UpdateDomainDNSSECExtension(
+ maxSigLife=dnssecdata.maxSigLife,
+ dsData=dnssecdata.dsData,
+ keyData=dnssecdata.keyData,
+ remDsData=None,
+ remKeyData=None,
+ remAllDsKeyData=False,
+ )
+ else:
+ return commands.UpdateDomainDNSSECExtension(
+ maxSigLife=dnssecdata.maxSigLife,
+ dsData=None,
+ keyData=None,
+ remDsData=dnssecdata.dsData,
+ remKeyData=dnssecdata.keyData,
+ remAllDsKeyData=False,
+ )
def setUp(self):
"""
@@ -1010,25 +1020,25 @@ class TestRegistrantDNSSEC(MockEppLib):
def test_user_adds_dnssec_data(self):
"""
- Scenario: Registrant adds DNSSEC data.
+ Scenario: Registrant adds DNSSEC ds data.
Verify that both the setter and getter are functioning properly
This test verifies:
- 1 - setter calls UpdateDomain command
- 2 - setter adds the UpdateDNSSECExtension extension to the command
- 3 - setter causes the getter to call info domain on next get from cache
- 4 - getter properly parses dnssecdata from InfoDomain response and sets to cache
+ 1 - setter initially calls InfoDomain command
+ 2 - setter then calls UpdateDomain command
+ 3 - setter adds the UpdateDNSSECExtension extension to the command
+ 4 - setter causes the getter to call info domain on next get from cache
+ 5 - getter properly parses dnssecdata from InfoDomain response and sets to cache
"""
domain, _ = Domain.objects.get_or_create(name="dnssec-dsdata.gov")
-
domain.dnssecdata = self.dnssecExtensionWithDsData
# get the DNS SEC extension added to the UpdateDomain command and
# verify that it is properly sent
# args[0] is the _request sent to registry
args, _ = self.mockedSendFunction.call_args
- # assert that the extension matches
+ # assert that the extension on the update matches
self.assertEquals(
args[0].extensions[0],
self.createUpdateExtension(
@@ -1039,6 +1049,12 @@ class TestRegistrantDNSSEC(MockEppLib):
dnssecdata_get = domain.dnssecdata
self.mockedSendFunction.assert_has_calls(
[
+ call(
+ commands.InfoDomain(
+ name="dnssec-dsdata.gov",
+ ),
+ cleaned=True,
+ ),
call(
commands.UpdateDomain(
name="dnssec-dsdata.gov",
@@ -1071,9 +1087,11 @@ class TestRegistrantDNSSEC(MockEppLib):
# registry normally sends in this case
This test verifies:
- 1 - UpdateDomain command called twice
- 2 - setter causes the getter to call info domain on next get from cache
- 3 - getter properly parses dnssecdata from InfoDomain response and sets to cache
+ 1 - InfoDomain command is called first
+ 2 - UpdateDomain command called on the initial setter
+ 3 - setter causes the getter to call info domain on next get from cache
+ 4 - UpdateDomain command is not called on second setter (no change)
+ 5 - getter properly parses dnssecdata from InfoDomain response and sets to cache
"""
@@ -1088,12 +1106,8 @@ class TestRegistrantDNSSEC(MockEppLib):
self.mockedSendFunction.assert_has_calls(
[
call(
- commands.UpdateDomain(
+ commands.InfoDomain(
name="dnssec-dsdata.gov",
- nsset=None,
- keyset=None,
- registrant=None,
- auth_info=None,
),
cleaned=True,
),
@@ -1113,6 +1127,12 @@ class TestRegistrantDNSSEC(MockEppLib):
),
cleaned=True,
),
+ call(
+ commands.InfoDomain(
+ name="dnssec-dsdata.gov",
+ ),
+ cleaned=True,
+ ),
]
)
@@ -1174,9 +1194,65 @@ class TestRegistrantDNSSEC(MockEppLib):
dnssecdata_get.dsData, self.dnssecExtensionWithMultDsData["dsData"]
)
+ def test_user_removes_dnssec_data(self):
+ """
+ Scenario: Registrant removes DNSSEC ds data.
+ Verify that both the setter and getter are functioning properly
+
+ This test verifies:
+ 1 - setter initially calls InfoDomain command
+ 2 - invalidate cache forces second InfoDomain command (to match mocks)
+ 3 - setter then calls UpdateDomain command
+ 4 - setter adds the UpdateDNSSECExtension extension to the command with rem
+
+ """
+
+ domain, _ = Domain.objects.get_or_create(name="dnssec-dsdata.gov")
+ dnssecdata_get_initial = domain.dnssecdata # call to force initial mock
+ domain._invalidate_cache()
+ domain.dnssecdata = self.dnssecExtensionRemovingDsData
+ # get the DNS SEC extension added to the UpdateDomain command and
+ # verify that it is properly sent
+ # args[0] is the _request sent to registry
+ args, _ = self.mockedSendFunction.call_args
+ # assert that the extension on the update matches
+ self.assertEquals(
+ args[0].extensions[0],
+ self.createUpdateExtension(
+ extensions.DNSSECExtension(**self.dnssecExtensionWithDsData),
+ remove=True
+ ),
+ )
+ self.mockedSendFunction.assert_has_calls(
+ [
+ call(
+ commands.InfoDomain(
+ name="dnssec-dsdata.gov",
+ ),
+ cleaned=True,
+ ),
+ call(
+ commands.InfoDomain(
+ name="dnssec-dsdata.gov",
+ ),
+ cleaned=True,
+ ),
+ call(
+ commands.UpdateDomain(
+ name="dnssec-dsdata.gov",
+ nsset=None,
+ keyset=None,
+ registrant=None,
+ auth_info=None,
+ ),
+ cleaned=True,
+ ),
+ ]
+ )
+
def test_user_adds_dnssec_keydata(self):
"""
- Scenario: Registrant adds DNSSEC data.
+ Scenario: Registrant adds DNSSEC key data.
Verify that both the setter and getter are functioning properly
This test verifies:
From 9e8aa2dee33266cf1291cb830151ac4e3da71970 Mon Sep 17 00:00:00 2001
From: David Kennedy
Date: Tue, 10 Oct 2023 08:08:16 -0400
Subject: [PATCH 51/65] properly typed extensions.DNSSECExtension
---
src/registrar/models/domain.py | 104 +++++++++++++++++-----
src/registrar/tests/common.py | 7 +-
src/registrar/tests/test_models_domain.py | 42 ++++++---
src/registrar/views/domain.py | 16 ++--
4 files changed, 120 insertions(+), 49 deletions(-)
diff --git a/src/registrar/models/domain.py b/src/registrar/models/domain.py
index 2188a1764..c539838e0 100644
--- a/src/registrar/models/domain.py
+++ b/src/registrar/models/domain.py
@@ -2,6 +2,7 @@ from itertools import zip_longest
import logging
from datetime import date
from string import digits
+from typing import Optional
from django_fsm import FSMField, transition, TransitionNotAllowed # type: ignore
from django.db import models
@@ -283,7 +284,7 @@ class Domain(TimeStampedModel, DomainHelper):
return e.code
@Cache
- def dnssecdata(self) -> extensions.DNSSECExtension:
+ def dnssecdata(self) -> Optional[extensions.DNSSECExtension]:
try:
return self._get_property("dnssecdata")
except Exception as err:
@@ -291,17 +292,18 @@ class Domain(TimeStampedModel, DomainHelper):
# TODO - 433 error handling ticket should address this
logger.info("Domain does not have dnssec data defined %s" % err)
return None
-
+
def getDnssecdataChanges(
- self, _dnssecdata: dict
- ) -> tuple[dict, dict]:
+ self,
+ _dnssecdata: Optional[extensions.DNSSECExtension]
+ ) -> tuple[dict, dict]:
"""
calls self.dnssecdata, it should pull from cache but may result
in an epp call
returns tuple of 2 values as follows:
addExtension: dict
remExtension: dict
-
+
addExtension includes all dsData or keyData to be added
remExtension includes all dsData or keyData to be removed
@@ -311,34 +313,76 @@ class Domain(TimeStampedModel, DomainHelper):
remExtension will be all existing dnssecdata to be deleted
"""
+ if isinstance(_dnssecdata, extensions.DNSSECExtension):
+ logger.info("extension is properly typed")
+ else:
+ logger.info("extension is NOT properly typed")
+
oldDnssecdata = self.dnssecdata
- addDnssecdata = {"dsData": [], "keyData": [],}
- remDnssecdata = {"dsData": [], "keyData": [],}
-
- if _dnssecdata and len(_dnssecdata["dsData"]) > 0:
+ addDnssecdata: dict = {}
+ # "dsData": [],
+ # "keyData": [],
+ # }
+ remDnssecdata: dict = {}
+ # "dsData": [],
+ # "keyData": [],
+ # }
+ if _dnssecdata and _dnssecdata.dsData is not None:
+ logger.info("there is submitted dsdata for comparison")
+ logger.info("there is %s submitted records", len(_dnssecdata.dsData))
# initialize addDnssecdata and remDnssecdata for dsData
- addDnssecdata["dsData"] = _dnssecdata["dsData"]
- remDnssecdata["dsData"] = []
+ addDnssecdata["dsData"] = _dnssecdata.dsData
+ # remDnssecdata["dsData"] = []
if oldDnssecdata and len(oldDnssecdata.dsData) > 0:
+ logger.info("there is existing ds data for comparison")
+ logger.info("there is %s existing records for compare", len(oldDnssecdata.dsData))
# if existing dsData not in new dsData, mark for removal
- remDnssecdata["dsData"] = [dsData for dsData in oldDnssecdata.dsData if dsData not in _dnssecdata["dsData"]]
+ dsDataForRemoval = [
+ dsData
+ for dsData in oldDnssecdata.dsData
+ if dsData not in _dnssecdata.dsData
+ ]
+ if len(dsDataForRemoval) > 0:
+ logger.info("ds data marked for removal")
+ remDnssecdata["dsData"] = dsDataForRemoval
# if new dsData not in existing dsData, mark for add
- addDnssecdata["dsData"] = [dsData for dsData in _dnssecdata["dsData"] if dsData not in oldDnssecdata.dsData]
-
- elif _dnssecdata and len(_dnssecdata["keyData"]) > 0:
+ dsDataForAdd = [
+ dsData
+ for dsData in _dnssecdata.dsData
+ if dsData not in oldDnssecdata.dsData
+ ]
+ if len(dsDataForAdd) > 0:
+ logger.info("ds data marked for add")
+ addDnssecdata["dsData"] = dsDataForAdd
+ else:
+ addDnssecdata["dsData"] = None
+
+ elif _dnssecdata and _dnssecdata.keyData is not None:
# initialize addDnssecdata and remDnssecdata for keyData
- addDnssecdata["keyData"] = _dnssecdata["keyData"]
- remDnssecdata["keyData"] = []
+ addDnssecdata["keyData"] = _dnssecdata.keyData
+ # remDnssecdata["keyData"] = []
if oldDnssecdata and len(oldDnssecdata.keyData) > 0:
# if existing keyData not in new keyData, mark for removal
- remDnssecdata["keyData"] = [keyData for keyData in oldDnssecdata.keyData if keyData not in _dnssecdata["keyData"]]
+ keyDataForRemoval = [
+ keyData
+ for keyData in oldDnssecdata.keyData
+ if keyData not in _dnssecdata.keyData
+ ]
+ if len(keyDataForRemoval) > 0:
+ remDnssecdata["keyData"] = keyDataForRemoval
# if new keyData not in existing keyData, mark for add
- addDnssecdata["keyData"] = [keyData for keyData in _dnssecdata["keyData"] if keyData not in oldDnssecdata.keyData]
+ keyDataForAdd = [
+ keyData
+ for keyData in _dnssecdata.keyData
+ if keyData not in oldDnssecdata.keyData
+ ]
+ if len(keyDataForAdd) > 0:
+ addDnssecdata["keyData"] = keyDataForAdd
else:
# there are no new dsData or keyData, remove all
remDnssecdata["dsData"] = getattr(oldDnssecdata, "dsData", None)
@@ -347,7 +391,7 @@ class Domain(TimeStampedModel, DomainHelper):
return addDnssecdata, remDnssecdata
@dnssecdata.setter # type: ignore
- def dnssecdata(self, _dnssecdata: dict):
+ def dnssecdata(self, _dnssecdata: Optional[extensions.DNSSECExtension]):
_addDnssecdata, _remDnssecdata = self.getDnssecdataChanges(_dnssecdata)
addParams = {
"maxSigLife": _addDnssecdata.get("maxSigLife", None),
@@ -366,12 +410,26 @@ class Domain(TimeStampedModel, DomainHelper):
remExtension = commands.UpdateDomainDNSSECExtension(**remParams)
remRequest.add_extension(remExtension)
try:
- if len(_addDnssecdata.get("dsData", [])) > 0 or len(_addDnssecdata.get("keyData",[])) > 0:
+ if (
+ "dsData" in _addDnssecdata and
+ _addDnssecdata["dsData"] is not None
+ or "keyData" in _addDnssecdata and
+ _addDnssecdata["keyData"] is not None
+ ):
+ logger.info("sending addition")
registry.send(addRequest, cleaned=True)
- if len(_remDnssecdata.get("dsData", [])) > 0 or len(_remDnssecdata.get("keyData", [])) > 0:
+ if (
+ "dsData" in _remDnssecdata and
+ _remDnssecdata["dsData"] is not None
+ or "keyData" in _remDnssecdata and
+ _remDnssecdata["keyData"] is not None
+ ):
+ logger.info("sending removal")
registry.send(remRequest, cleaned=True)
except RegistryError as e:
- logger.error("Error updating DNSSEC, code was %s error was %s" % (e.code, e))
+ logger.error(
+ "Error updating DNSSEC, code was %s error was %s" % (e.code, e)
+ )
raise e
@nameservers.setter # type: ignore
diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py
index 6ede8965b..4d399fd29 100644
--- a/src/registrar/tests/common.py
+++ b/src/registrar/tests/common.py
@@ -706,22 +706,19 @@ class MockEppLib(TestCase):
}
dnssecExtensionWithDsData: Mapping[Any, Any] = {
"dsData": [common.DSData(**addDsData1)], # type: ignore
- "keyData": [],
}
dnssecExtensionWithMultDsData: Mapping[str, Any] = {
"dsData": [
common.DSData(**addDsData1), # type: ignore
common.DSData(**addDsData2), # type: ignore
],
- "keyData": [],
}
dnssecExtensionWithKeyData: Mapping[str, Any] = {
"keyData": [common.DNSSECKeyData(**keyDataDict)], # type: ignore
- "dsData": [],
}
dnssecExtensionRemovingDsData: Mapping[Any, Any] = {
- "dsData": [],
- "keyData": [],
+ "dsData": None,
+ "keyData": None,
}
def mockSend(self, _request, cleaned):
diff --git a/src/registrar/tests/test_models_domain.py b/src/registrar/tests/test_models_domain.py
index b8d648e45..2a0a820ec 100644
--- a/src/registrar/tests/test_models_domain.py
+++ b/src/registrar/tests/test_models_domain.py
@@ -984,7 +984,9 @@ class TestRegistrantDNSSEC(MockEppLib):
"""Rule: Registrants may modify their secure DNS data"""
# helper function to create UpdateDomainDNSSECExtention object for verification
- def createUpdateExtension(self, dnssecdata: extensions.DNSSECExtension, remove=False):
+ def createUpdateExtension(
+ self, dnssecdata: extensions.DNSSECExtension, remove=False
+ ):
if not remove:
return commands.UpdateDomainDNSSECExtension(
maxSigLife=dnssecdata.maxSigLife,
@@ -1033,7 +1035,9 @@ class TestRegistrantDNSSEC(MockEppLib):
"""
domain, _ = Domain.objects.get_or_create(name="dnssec-dsdata.gov")
- domain.dnssecdata = self.dnssecExtensionWithDsData
+ domain.dnssecdata = extensions.DNSSECExtension(
+ **self.dnssecExtensionWithDsData
+ )
# get the DNS SEC extension added to the UpdateDomain command and
# verify that it is properly sent
# args[0] is the _request sent to registry
@@ -1098,9 +1102,9 @@ class TestRegistrantDNSSEC(MockEppLib):
domain, _ = Domain.objects.get_or_create(name="dnssec-dsdata.gov")
# set the dnssecdata once
- domain.dnssecdata = self.dnssecExtensionWithDsData
+ domain.dnssecdata = extensions.DNSSECExtension(**self.dnssecExtensionWithDsData)
# set the dnssecdata again
- domain.dnssecdata = self.dnssecExtensionWithDsData
+ domain.dnssecdata = extensions.DNSSECExtension(**self.dnssecExtensionWithDsData)
# test that the dnssecdata getter is functioning properly
dnssecdata_get = domain.dnssecdata
self.mockedSendFunction.assert_has_calls(
@@ -1155,7 +1159,7 @@ class TestRegistrantDNSSEC(MockEppLib):
domain, _ = Domain.objects.get_or_create(name="dnssec-multdsdata.gov")
- domain.dnssecdata = self.dnssecExtensionWithMultDsData
+ domain.dnssecdata = extensions.DNSSECExtension(**self.dnssecExtensionWithMultDsData)
# get the DNS SEC extension added to the UpdateDomain command
# and verify that it is properly sent
# args[0] is the _request sent to registry
@@ -1201,16 +1205,18 @@ class TestRegistrantDNSSEC(MockEppLib):
This test verifies:
1 - setter initially calls InfoDomain command
- 2 - invalidate cache forces second InfoDomain command (to match mocks)
+ 2 - first setter calls UpdateDomain command
+ 3 - second setter calls InfoDomain command again
3 - setter then calls UpdateDomain command
4 - setter adds the UpdateDNSSECExtension extension to the command with rem
"""
domain, _ = Domain.objects.get_or_create(name="dnssec-dsdata.gov")
- dnssecdata_get_initial = domain.dnssecdata # call to force initial mock
- domain._invalidate_cache()
- domain.dnssecdata = self.dnssecExtensionRemovingDsData
+ # dnssecdata_get_initial = domain.dnssecdata # call to force initial mock
+ # domain._invalidate_cache()
+ domain.dnssecdata = extensions.DNSSECExtension(**self.dnssecExtensionWithDsData)
+ domain.dnssecdata = extensions.DNSSECExtension(**self.dnssecExtensionRemovingDsData)
# get the DNS SEC extension added to the UpdateDomain command and
# verify that it is properly sent
# args[0] is the _request sent to registry
@@ -1220,7 +1226,7 @@ class TestRegistrantDNSSEC(MockEppLib):
args[0].extensions[0],
self.createUpdateExtension(
extensions.DNSSECExtension(**self.dnssecExtensionWithDsData),
- remove=True
+ remove=True,
),
)
self.mockedSendFunction.assert_has_calls(
@@ -1231,6 +1237,16 @@ class TestRegistrantDNSSEC(MockEppLib):
),
cleaned=True,
),
+ call(
+ commands.UpdateDomain(
+ name="dnssec-dsdata.gov",
+ nsset=None,
+ keyset=None,
+ registrant=None,
+ auth_info=None,
+ ),
+ cleaned=True,
+ ),
call(
commands.InfoDomain(
name="dnssec-dsdata.gov",
@@ -1246,7 +1262,7 @@ class TestRegistrantDNSSEC(MockEppLib):
auth_info=None,
),
cleaned=True,
- ),
+ ),
]
)
@@ -1265,7 +1281,7 @@ class TestRegistrantDNSSEC(MockEppLib):
domain, _ = Domain.objects.get_or_create(name="dnssec-keydata.gov")
- domain.dnssecdata = self.dnssecExtensionWithKeyData
+ domain.dnssecdata = extensions.DNSSECExtension(**self.dnssecExtensionWithKeyData)
# get the DNS SEC extension added to the UpdateDomain command
# and verify that it is properly sent
# args[0] is the _request sent to registry
@@ -1314,7 +1330,7 @@ class TestRegistrantDNSSEC(MockEppLib):
domain, _ = Domain.objects.get_or_create(name="dnssec-invalid.gov")
with self.assertRaises(RegistryError) as err:
- domain.dnssecdata = self.dnssecExtensionWithDsData
+ domain.dnssecdata = extensions.DNSSECExtension(**self.dnssecExtensionWithDsData)
self.assertTrue(
err.is_client_error() or err.is_session_error() or err.is_server_error()
)
diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py
index b4509b162..6cc89682e 100644
--- a/src/registrar/views/domain.py
+++ b/src/registrar/views/domain.py
@@ -362,8 +362,8 @@ class DomainDsdataView(DomainPermissionView, FormMixin):
def form_valid(self, formset):
"""The formset is valid, perform something with it."""
- # Set the nameservers from the formset
- dnssecdata = {"dsData": []}
+ # Set the dnssecdata from the formset
+ dnssecdata = extensions.DNSSECExtension()
for form in formset:
try:
@@ -375,13 +375,13 @@ class DomainDsdataView(DomainPermissionView, FormMixin):
"digestType": int(form.cleaned_data["digest_type"]),
"digest": form.cleaned_data["digest"],
}
- dnssecdata["dsData"].append(common.DSData(**dsrecord))
+ if dnssecdata.dsData is None:
+ dnssecdata.dsData = []
+ dnssecdata.dsData.append(common.DSData(**dsrecord))
except KeyError:
# no server information in this field, skip it
pass
domain = self.get_object()
- if len(dnssecdata["dsData"]) == 0:
- dnssecdata = {}
try:
domain.dnssecdata = dnssecdata
except RegistryError as err:
@@ -483,7 +483,7 @@ class DomainKeydataView(DomainPermissionView, FormMixin):
"""The formset is valid, perform something with it."""
# Set the nameservers from the formset
- dnssecdata = {"keyData": []}
+ dnssecdata = extensions.DNSSECExtension()
for form in formset:
try:
@@ -495,13 +495,13 @@ class DomainKeydataView(DomainPermissionView, FormMixin):
"alg": int(form.cleaned_data["algorithm"]),
"pubKey": form.cleaned_data["pub_key"],
}
+ if dnssecdata.keyData is None:
+ dnssecdata.keyData = []
dnssecdata["keyData"].append(common.DNSSECKeyData(**keyrecord))
except KeyError:
# no server information in this field, skip it
pass
domain = self.get_object()
- if len(dnssecdata["keyData"]) == 0:
- dnssecdata = {}
try:
domain.dnssecdata = dnssecdata
except RegistryError as err:
From cb15b7d0296315190cb29adac71391731f5eba4d Mon Sep 17 00:00:00 2001
From: David Kennedy
Date: Tue, 10 Oct 2023 08:43:36 -0400
Subject: [PATCH 52/65] cleaned up tests
---
src/registrar/tests/common.py | 25 +++++++--------
src/registrar/tests/test_models_domain.py | 37 +++++++++++------------
2 files changed, 29 insertions(+), 33 deletions(-)
diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py
index 4d399fd29..d28171155 100644
--- a/src/registrar/tests/common.py
+++ b/src/registrar/tests/common.py
@@ -704,22 +704,19 @@ class MockEppLib(TestCase):
"alg": 1,
"pubKey": "AQPJ////4Q==",
}
- dnssecExtensionWithDsData: Mapping[Any, Any] = {
- "dsData": [common.DSData(**addDsData1)], # type: ignore
- }
- dnssecExtensionWithMultDsData: Mapping[str, Any] = {
+ dnssecExtensionWithDsData = extensions.DNSSECExtension(**{
+ "dsData": [common.DSData(**addDsData1)],
+ })
+ dnssecExtensionWithMultDsData = extensions.DNSSECExtension(**{
"dsData": [
common.DSData(**addDsData1), # type: ignore
common.DSData(**addDsData2), # type: ignore
],
- }
- dnssecExtensionWithKeyData: Mapping[str, Any] = {
+ })
+ dnssecExtensionWithKeyData = extensions.DNSSECExtension(**{
"keyData": [common.DNSSECKeyData(**keyDataDict)], # type: ignore
- }
- dnssecExtensionRemovingDsData: Mapping[Any, Any] = {
- "dsData": None,
- "keyData": None,
- }
+ })
+ dnssecExtensionRemovingDsData = extensions.DNSSECExtension()
def mockSend(self, _request, cleaned):
"""Mocks the registry.send function used inside of domain.py
@@ -765,7 +762,7 @@ class MockEppLib(TestCase):
return MagicMock(
res_data=[self.mockDataInfoDomain],
extensions=[
- extensions.DNSSECExtension(**self.dnssecExtensionWithDsData)
+ self.dnssecExtensionWithDsData
],
)
elif getattr(_request, "name", None) == "dnssec-multdsdata.gov":
@@ -775,7 +772,7 @@ class MockEppLib(TestCase):
return MagicMock(
res_data=[self.mockDataInfoDomain],
extensions=[
- extensions.DNSSECExtension(**self.dnssecExtensionWithMultDsData)
+ self.dnssecExtensionWithMultDsData
],
)
elif getattr(_request, "name", None) == "dnssec-keydata.gov":
@@ -785,7 +782,7 @@ class MockEppLib(TestCase):
return MagicMock(
res_data=[self.mockDataInfoDomain],
extensions=[
- extensions.DNSSECExtension(**self.dnssecExtensionWithKeyData)
+ self.dnssecExtensionWithKeyData
],
)
elif getattr(_request, "name", None) == "dnssec-none.gov":
diff --git a/src/registrar/tests/test_models_domain.py b/src/registrar/tests/test_models_domain.py
index 2a0a820ec..05f56e0f4 100644
--- a/src/registrar/tests/test_models_domain.py
+++ b/src/registrar/tests/test_models_domain.py
@@ -1035,9 +1035,8 @@ class TestRegistrantDNSSEC(MockEppLib):
"""
domain, _ = Domain.objects.get_or_create(name="dnssec-dsdata.gov")
- domain.dnssecdata = extensions.DNSSECExtension(
- **self.dnssecExtensionWithDsData
- )
+ domain.dnssecdata = self.dnssecExtensionWithDsData
+
# get the DNS SEC extension added to the UpdateDomain command and
# verify that it is properly sent
# args[0] is the _request sent to registry
@@ -1046,7 +1045,7 @@ class TestRegistrantDNSSEC(MockEppLib):
self.assertEquals(
args[0].extensions[0],
self.createUpdateExtension(
- extensions.DNSSECExtension(**self.dnssecExtensionWithDsData)
+ self.dnssecExtensionWithDsData
),
)
# test that the dnssecdata getter is functioning properly
@@ -1079,7 +1078,7 @@ class TestRegistrantDNSSEC(MockEppLib):
)
self.assertEquals(
- dnssecdata_get.dsData, self.dnssecExtensionWithDsData["dsData"]
+ dnssecdata_get.dsData, self.dnssecExtensionWithDsData.dsData
)
def test_dnssec_is_idempotent(self):
@@ -1096,15 +1095,15 @@ class TestRegistrantDNSSEC(MockEppLib):
3 - setter causes the getter to call info domain on next get from cache
4 - UpdateDomain command is not called on second setter (no change)
5 - getter properly parses dnssecdata from InfoDomain response and sets to cache
-
+
"""
domain, _ = Domain.objects.get_or_create(name="dnssec-dsdata.gov")
# set the dnssecdata once
- domain.dnssecdata = extensions.DNSSECExtension(**self.dnssecExtensionWithDsData)
+ domain.dnssecdata = self.dnssecExtensionWithDsData
# set the dnssecdata again
- domain.dnssecdata = extensions.DNSSECExtension(**self.dnssecExtensionWithDsData)
+ domain.dnssecdata = self.dnssecExtensionWithDsData
# test that the dnssecdata getter is functioning properly
dnssecdata_get = domain.dnssecdata
self.mockedSendFunction.assert_has_calls(
@@ -1141,7 +1140,7 @@ class TestRegistrantDNSSEC(MockEppLib):
)
self.assertEquals(
- dnssecdata_get.dsData, self.dnssecExtensionWithDsData["dsData"]
+ dnssecdata_get.dsData, self.dnssecExtensionWithDsData.dsData
)
def test_user_adds_dnssec_data_multiple_dsdata(self):
@@ -1159,7 +1158,7 @@ class TestRegistrantDNSSEC(MockEppLib):
domain, _ = Domain.objects.get_or_create(name="dnssec-multdsdata.gov")
- domain.dnssecdata = extensions.DNSSECExtension(**self.dnssecExtensionWithMultDsData)
+ domain.dnssecdata = self.dnssecExtensionWithMultDsData
# get the DNS SEC extension added to the UpdateDomain command
# and verify that it is properly sent
# args[0] is the _request sent to registry
@@ -1168,7 +1167,7 @@ class TestRegistrantDNSSEC(MockEppLib):
self.assertEquals(
args[0].extensions[0],
self.createUpdateExtension(
- extensions.DNSSECExtension(**self.dnssecExtensionWithMultDsData)
+ self.dnssecExtensionWithMultDsData
),
)
# test that the dnssecdata getter is functioning properly
@@ -1195,7 +1194,7 @@ class TestRegistrantDNSSEC(MockEppLib):
)
self.assertEquals(
- dnssecdata_get.dsData, self.dnssecExtensionWithMultDsData["dsData"]
+ dnssecdata_get.dsData, self.dnssecExtensionWithMultDsData.dsData
)
def test_user_removes_dnssec_data(self):
@@ -1215,8 +1214,8 @@ class TestRegistrantDNSSEC(MockEppLib):
domain, _ = Domain.objects.get_or_create(name="dnssec-dsdata.gov")
# dnssecdata_get_initial = domain.dnssecdata # call to force initial mock
# domain._invalidate_cache()
- domain.dnssecdata = extensions.DNSSECExtension(**self.dnssecExtensionWithDsData)
- domain.dnssecdata = extensions.DNSSECExtension(**self.dnssecExtensionRemovingDsData)
+ domain.dnssecdata = self.dnssecExtensionWithDsData
+ domain.dnssecdata = self.dnssecExtensionRemovingDsData
# get the DNS SEC extension added to the UpdateDomain command and
# verify that it is properly sent
# args[0] is the _request sent to registry
@@ -1225,7 +1224,7 @@ class TestRegistrantDNSSEC(MockEppLib):
self.assertEquals(
args[0].extensions[0],
self.createUpdateExtension(
- extensions.DNSSECExtension(**self.dnssecExtensionWithDsData),
+ self.dnssecExtensionWithDsData,
remove=True,
),
)
@@ -1281,7 +1280,7 @@ class TestRegistrantDNSSEC(MockEppLib):
domain, _ = Domain.objects.get_or_create(name="dnssec-keydata.gov")
- domain.dnssecdata = extensions.DNSSECExtension(**self.dnssecExtensionWithKeyData)
+ domain.dnssecdata = self.dnssecExtensionWithKeyData
# get the DNS SEC extension added to the UpdateDomain command
# and verify that it is properly sent
# args[0] is the _request sent to registry
@@ -1290,7 +1289,7 @@ class TestRegistrantDNSSEC(MockEppLib):
self.assertEquals(
args[0].extensions[0],
self.createUpdateExtension(
- extensions.DNSSECExtension(**self.dnssecExtensionWithKeyData)
+ self.dnssecExtensionWithKeyData
),
)
# test that the dnssecdata getter is functioning properly
@@ -1317,7 +1316,7 @@ class TestRegistrantDNSSEC(MockEppLib):
)
self.assertEquals(
- dnssecdata_get.keyData, self.dnssecExtensionWithKeyData["keyData"]
+ dnssecdata_get.keyData, self.dnssecExtensionWithKeyData.keyData
)
def test_update_is_unsuccessful(self):
@@ -1330,7 +1329,7 @@ class TestRegistrantDNSSEC(MockEppLib):
domain, _ = Domain.objects.get_or_create(name="dnssec-invalid.gov")
with self.assertRaises(RegistryError) as err:
- domain.dnssecdata = extensions.DNSSECExtension(**self.dnssecExtensionWithDsData)
+ domain.dnssecdata = self.dnssecExtensionWithDsData
self.assertTrue(
err.is_client_error() or err.is_session_error() or err.is_server_error()
)
From 950014ea4780d67318692877fb95b12c740e1820 Mon Sep 17 00:00:00 2001
From: David Kennedy
Date: Tue, 10 Oct 2023 08:48:14 -0400
Subject: [PATCH 53/65] removed some comments and debug statements
---
src/registrar/models/domain.py | 21 ---------------------
1 file changed, 21 deletions(-)
diff --git a/src/registrar/models/domain.py b/src/registrar/models/domain.py
index c539838e0..4226e6ac9 100644
--- a/src/registrar/models/domain.py
+++ b/src/registrar/models/domain.py
@@ -313,31 +313,15 @@ class Domain(TimeStampedModel, DomainHelper):
remExtension will be all existing dnssecdata to be deleted
"""
- if isinstance(_dnssecdata, extensions.DNSSECExtension):
- logger.info("extension is properly typed")
- else:
- logger.info("extension is NOT properly typed")
-
oldDnssecdata = self.dnssecdata
addDnssecdata: dict = {}
- # "dsData": [],
- # "keyData": [],
- # }
remDnssecdata: dict = {}
- # "dsData": [],
- # "keyData": [],
- # }
if _dnssecdata and _dnssecdata.dsData is not None:
- logger.info("there is submitted dsdata for comparison")
- logger.info("there is %s submitted records", len(_dnssecdata.dsData))
# initialize addDnssecdata and remDnssecdata for dsData
addDnssecdata["dsData"] = _dnssecdata.dsData
- # remDnssecdata["dsData"] = []
if oldDnssecdata and len(oldDnssecdata.dsData) > 0:
- logger.info("there is existing ds data for comparison")
- logger.info("there is %s existing records for compare", len(oldDnssecdata.dsData))
# if existing dsData not in new dsData, mark for removal
dsDataForRemoval = [
dsData
@@ -345,7 +329,6 @@ class Domain(TimeStampedModel, DomainHelper):
if dsData not in _dnssecdata.dsData
]
if len(dsDataForRemoval) > 0:
- logger.info("ds data marked for removal")
remDnssecdata["dsData"] = dsDataForRemoval
# if new dsData not in existing dsData, mark for add
@@ -355,7 +338,6 @@ class Domain(TimeStampedModel, DomainHelper):
if dsData not in oldDnssecdata.dsData
]
if len(dsDataForAdd) > 0:
- logger.info("ds data marked for add")
addDnssecdata["dsData"] = dsDataForAdd
else:
addDnssecdata["dsData"] = None
@@ -363,7 +345,6 @@ class Domain(TimeStampedModel, DomainHelper):
elif _dnssecdata and _dnssecdata.keyData is not None:
# initialize addDnssecdata and remDnssecdata for keyData
addDnssecdata["keyData"] = _dnssecdata.keyData
- # remDnssecdata["keyData"] = []
if oldDnssecdata and len(oldDnssecdata.keyData) > 0:
# if existing keyData not in new keyData, mark for removal
@@ -416,7 +397,6 @@ class Domain(TimeStampedModel, DomainHelper):
or "keyData" in _addDnssecdata and
_addDnssecdata["keyData"] is not None
):
- logger.info("sending addition")
registry.send(addRequest, cleaned=True)
if (
"dsData" in _remDnssecdata and
@@ -424,7 +404,6 @@ class Domain(TimeStampedModel, DomainHelper):
or "keyData" in _remDnssecdata and
_remDnssecdata["keyData"] is not None
):
- logger.info("sending removal")
registry.send(remRequest, cleaned=True)
except RegistryError as e:
logger.error(
From f447df6d6468f0d21b250eb22851292c25df0be7 Mon Sep 17 00:00:00 2001
From: David Kennedy
Date: Tue, 10 Oct 2023 10:50:24 -0400
Subject: [PATCH 54/65] tests cleanup and formatting for linter
---
src/registrar/models/domain.py | 21 ++--
src/registrar/tests/common.py | 73 +++++------
src/registrar/tests/test_models_domain.py | 147 ++++++++++++++++++----
src/registrar/views/domain.py | 2 +-
4 files changed, 165 insertions(+), 78 deletions(-)
diff --git a/src/registrar/models/domain.py b/src/registrar/models/domain.py
index 4226e6ac9..f5e229b0a 100644
--- a/src/registrar/models/domain.py
+++ b/src/registrar/models/domain.py
@@ -294,9 +294,8 @@ class Domain(TimeStampedModel, DomainHelper):
return None
def getDnssecdataChanges(
- self,
- _dnssecdata: Optional[extensions.DNSSECExtension]
- ) -> tuple[dict, dict]:
+ self, _dnssecdata: Optional[extensions.DNSSECExtension]
+ ) -> tuple[dict, dict]:
"""
calls self.dnssecdata, it should pull from cache but may result
in an epp call
@@ -392,17 +391,17 @@ class Domain(TimeStampedModel, DomainHelper):
remRequest.add_extension(remExtension)
try:
if (
- "dsData" in _addDnssecdata and
- _addDnssecdata["dsData"] is not None
- or "keyData" in _addDnssecdata and
- _addDnssecdata["keyData"] is not None
+ "dsData" in _addDnssecdata
+ and _addDnssecdata["dsData"] is not None
+ or "keyData" in _addDnssecdata
+ and _addDnssecdata["keyData"] is not None
):
registry.send(addRequest, cleaned=True)
if (
- "dsData" in _remDnssecdata and
- _remDnssecdata["dsData"] is not None
- or "keyData" in _remDnssecdata and
- _remDnssecdata["keyData"] is not None
+ "dsData" in _remDnssecdata
+ and _remDnssecdata["dsData"] is not None
+ or "keyData" in _remDnssecdata
+ and _remDnssecdata["keyData"] is not None
):
registry.send(remRequest, cleaned=True)
except RegistryError as e:
diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py
index d28171155..f27713454 100644
--- a/src/registrar/tests/common.py
+++ b/src/registrar/tests/common.py
@@ -7,7 +7,7 @@ import random
from string import ascii_uppercase
from django.test import TestCase
from unittest.mock import MagicMock, Mock, patch
-from typing import List, Dict, Mapping, Any
+from typing import List, Dict
from django.conf import settings
from django.contrib.auth import get_user_model, login
@@ -704,18 +704,26 @@ class MockEppLib(TestCase):
"alg": 1,
"pubKey": "AQPJ////4Q==",
}
- dnssecExtensionWithDsData = extensions.DNSSECExtension(**{
- "dsData": [common.DSData(**addDsData1)],
- })
- dnssecExtensionWithMultDsData = extensions.DNSSECExtension(**{
- "dsData": [
- common.DSData(**addDsData1), # type: ignore
- common.DSData(**addDsData2), # type: ignore
- ],
- })
- dnssecExtensionWithKeyData = extensions.DNSSECExtension(**{
- "keyData": [common.DNSSECKeyData(**keyDataDict)], # type: ignore
- })
+ dnssecExtensionWithDsData = extensions.DNSSECExtension(
+ **{
+ "dsData": [
+ common.DSData(**addDsData1) # type: ignore
+ ], # type: ignore
+ }
+ )
+ dnssecExtensionWithMultDsData = extensions.DNSSECExtension(
+ **{
+ "dsData": [
+ common.DSData(**addDsData1), # type: ignore
+ common.DSData(**addDsData2), # type: ignore
+ ], # type: ignore
+ }
+ )
+ dnssecExtensionWithKeyData = extensions.DNSSECExtension(
+ **{
+ "keyData": [common.DNSSECKeyData(**keyDataDict)], # type: ignore
+ }
+ )
dnssecExtensionRemovingDsData = extensions.DNSSECExtension()
def mockSend(self, _request, cleaned):
@@ -756,35 +764,20 @@ class MockEppLib(TestCase):
if getattr(_request, "name", None) == "security.gov":
return MagicMock(res_data=[self.infoDomainNoContact])
elif getattr(_request, "name", None) == "dnssec-dsdata.gov":
- if self.mockedSendFunction.call_count == 1:
- return MagicMock(res_data=[self.mockDataInfoDomain])
- else:
- return MagicMock(
- res_data=[self.mockDataInfoDomain],
- extensions=[
- self.dnssecExtensionWithDsData
- ],
- )
+ return MagicMock(
+ res_data=[self.mockDataInfoDomain],
+ extensions=[self.dnssecExtensionWithDsData],
+ )
elif getattr(_request, "name", None) == "dnssec-multdsdata.gov":
- if self.mockedSendFunction.call_count == 1:
- return MagicMock(res_data=[self.mockDataInfoDomain])
- else:
- return MagicMock(
- res_data=[self.mockDataInfoDomain],
- extensions=[
- self.dnssecExtensionWithMultDsData
- ],
- )
+ return MagicMock(
+ res_data=[self.mockDataInfoDomain],
+ extensions=[self.dnssecExtensionWithMultDsData],
+ )
elif getattr(_request, "name", None) == "dnssec-keydata.gov":
- if self.mockedSendFunction.call_count == 1:
- return MagicMock(res_data=[self.mockDataInfoDomain])
- else:
- return MagicMock(
- res_data=[self.mockDataInfoDomain],
- extensions=[
- self.dnssecExtensionWithKeyData
- ],
- )
+ return MagicMock(
+ res_data=[self.mockDataInfoDomain],
+ extensions=[self.dnssecExtensionWithKeyData],
+ )
elif getattr(_request, "name", None) == "dnssec-none.gov":
# this case is not necessary, but helps improve readability
return MagicMock(res_data=[self.mockDataInfoDomain])
diff --git a/src/registrar/tests/test_models_domain.py b/src/registrar/tests/test_models_domain.py
index 05f56e0f4..cf2d002f5 100644
--- a/src/registrar/tests/test_models_domain.py
+++ b/src/registrar/tests/test_models_domain.py
@@ -1034,23 +1034,40 @@ class TestRegistrantDNSSEC(MockEppLib):
"""
+ # need to use a separate patcher and side_effect for this test, as
+ # response from InfoDomain must be different for different iterations
+ # of the same command
+ def side_effect(_request, cleaned):
+ if isinstance(_request, commands.InfoDomain):
+ if mocked_send.call_count == 1:
+ return MagicMock(res_data=[self.mockDataInfoDomain])
+ else:
+ return MagicMock(
+ res_data=[self.mockDataInfoDomain],
+ extensions=[self.dnssecExtensionWithDsData],
+ )
+ else:
+ return MagicMock(res_data=[self.mockDataInfoHosts])
+
+ patcher = patch("registrar.models.domain.registry.send")
+ mocked_send = patcher.start()
+ mocked_send.side_effect = side_effect
+
domain, _ = Domain.objects.get_or_create(name="dnssec-dsdata.gov")
domain.dnssecdata = self.dnssecExtensionWithDsData
-
+
# get the DNS SEC extension added to the UpdateDomain command and
# verify that it is properly sent
# args[0] is the _request sent to registry
- args, _ = self.mockedSendFunction.call_args
+ args, _ = mocked_send.call_args
# assert that the extension on the update matches
self.assertEquals(
args[0].extensions[0],
- self.createUpdateExtension(
- self.dnssecExtensionWithDsData
- ),
+ self.createUpdateExtension(self.dnssecExtensionWithDsData),
)
# test that the dnssecdata getter is functioning properly
dnssecdata_get = domain.dnssecdata
- self.mockedSendFunction.assert_has_calls(
+ mocked_send.assert_has_calls(
[
call(
commands.InfoDomain(
@@ -1077,9 +1094,9 @@ class TestRegistrantDNSSEC(MockEppLib):
]
)
- self.assertEquals(
- dnssecdata_get.dsData, self.dnssecExtensionWithDsData.dsData
- )
+ self.assertEquals(dnssecdata_get.dsData, self.dnssecExtensionWithDsData.dsData)
+
+ patcher.stop()
def test_dnssec_is_idempotent(self):
"""
@@ -1095,9 +1112,28 @@ class TestRegistrantDNSSEC(MockEppLib):
3 - setter causes the getter to call info domain on next get from cache
4 - UpdateDomain command is not called on second setter (no change)
5 - getter properly parses dnssecdata from InfoDomain response and sets to cache
-
+
"""
+ # need to use a separate patcher and side_effect for this test, as
+ # response from InfoDomain must be different for different iterations
+ # of the same command
+ def side_effect(_request, cleaned):
+ if isinstance(_request, commands.InfoDomain):
+ if mocked_send.call_count == 1:
+ return MagicMock(res_data=[self.mockDataInfoDomain])
+ else:
+ return MagicMock(
+ res_data=[self.mockDataInfoDomain],
+ extensions=[self.dnssecExtensionWithDsData],
+ )
+ else:
+ return MagicMock(res_data=[self.mockDataInfoHosts])
+
+ patcher = patch("registrar.models.domain.registry.send")
+ mocked_send = patcher.start()
+ mocked_send.side_effect = side_effect
+
domain, _ = Domain.objects.get_or_create(name="dnssec-dsdata.gov")
# set the dnssecdata once
@@ -1106,7 +1142,7 @@ class TestRegistrantDNSSEC(MockEppLib):
domain.dnssecdata = self.dnssecExtensionWithDsData
# test that the dnssecdata getter is functioning properly
dnssecdata_get = domain.dnssecdata
- self.mockedSendFunction.assert_has_calls(
+ mocked_send.assert_has_calls(
[
call(
commands.InfoDomain(
@@ -1139,9 +1175,9 @@ class TestRegistrantDNSSEC(MockEppLib):
]
)
- self.assertEquals(
- dnssecdata_get.dsData, self.dnssecExtensionWithDsData.dsData
- )
+ self.assertEquals(dnssecdata_get.dsData, self.dnssecExtensionWithDsData.dsData)
+
+ patcher.stop()
def test_user_adds_dnssec_data_multiple_dsdata(self):
"""
@@ -1156,23 +1192,40 @@ class TestRegistrantDNSSEC(MockEppLib):
"""
+ # need to use a separate patcher and side_effect for this test, as
+ # response from InfoDomain must be different for different iterations
+ # of the same command
+ def side_effect(_request, cleaned):
+ if isinstance(_request, commands.InfoDomain):
+ if mocked_send.call_count == 1:
+ return MagicMock(res_data=[self.mockDataInfoDomain])
+ else:
+ return MagicMock(
+ res_data=[self.mockDataInfoDomain],
+ extensions=[self.dnssecExtensionWithMultDsData],
+ )
+ else:
+ return MagicMock(res_data=[self.mockDataInfoHosts])
+
+ patcher = patch("registrar.models.domain.registry.send")
+ mocked_send = patcher.start()
+ mocked_send.side_effect = side_effect
+
domain, _ = Domain.objects.get_or_create(name="dnssec-multdsdata.gov")
domain.dnssecdata = self.dnssecExtensionWithMultDsData
# get the DNS SEC extension added to the UpdateDomain command
# and verify that it is properly sent
# args[0] is the _request sent to registry
- args, _ = self.mockedSendFunction.call_args
+ args, _ = mocked_send.call_args
# assert that the extension matches
self.assertEquals(
args[0].extensions[0],
- self.createUpdateExtension(
- self.dnssecExtensionWithMultDsData
- ),
+ self.createUpdateExtension(self.dnssecExtensionWithMultDsData),
)
# test that the dnssecdata getter is functioning properly
dnssecdata_get = domain.dnssecdata
- self.mockedSendFunction.assert_has_calls(
+ mocked_send.assert_has_calls(
[
call(
commands.UpdateDomain(
@@ -1197,6 +1250,8 @@ class TestRegistrantDNSSEC(MockEppLib):
dnssecdata_get.dsData, self.dnssecExtensionWithMultDsData.dsData
)
+ patcher.stop()
+
def test_user_removes_dnssec_data(self):
"""
Scenario: Registrant removes DNSSEC ds data.
@@ -1211,6 +1266,25 @@ class TestRegistrantDNSSEC(MockEppLib):
"""
+ # need to use a separate patcher and side_effect for this test, as
+ # response from InfoDomain must be different for different iterations
+ # of the same command
+ def side_effect(_request, cleaned):
+ if isinstance(_request, commands.InfoDomain):
+ if mocked_send.call_count == 1:
+ return MagicMock(res_data=[self.mockDataInfoDomain])
+ else:
+ return MagicMock(
+ res_data=[self.mockDataInfoDomain],
+ extensions=[self.dnssecExtensionWithDsData],
+ )
+ else:
+ return MagicMock(res_data=[self.mockDataInfoHosts])
+
+ patcher = patch("registrar.models.domain.registry.send")
+ mocked_send = patcher.start()
+ mocked_send.side_effect = side_effect
+
domain, _ = Domain.objects.get_or_create(name="dnssec-dsdata.gov")
# dnssecdata_get_initial = domain.dnssecdata # call to force initial mock
# domain._invalidate_cache()
@@ -1219,7 +1293,7 @@ class TestRegistrantDNSSEC(MockEppLib):
# get the DNS SEC extension added to the UpdateDomain command and
# verify that it is properly sent
# args[0] is the _request sent to registry
- args, _ = self.mockedSendFunction.call_args
+ args, _ = mocked_send.call_args
# assert that the extension on the update matches
self.assertEquals(
args[0].extensions[0],
@@ -1228,7 +1302,7 @@ class TestRegistrantDNSSEC(MockEppLib):
remove=True,
),
)
- self.mockedSendFunction.assert_has_calls(
+ mocked_send.assert_has_calls(
[
call(
commands.InfoDomain(
@@ -1265,6 +1339,8 @@ class TestRegistrantDNSSEC(MockEppLib):
]
)
+ patcher.stop()
+
def test_user_adds_dnssec_keydata(self):
"""
Scenario: Registrant adds DNSSEC key data.
@@ -1278,23 +1354,40 @@ class TestRegistrantDNSSEC(MockEppLib):
"""
+ # need to use a separate patcher and side_effect for this test, as
+ # response from InfoDomain must be different for different iterations
+ # of the same command
+ def side_effect(_request, cleaned):
+ if isinstance(_request, commands.InfoDomain):
+ if mocked_send.call_count == 1:
+ return MagicMock(res_data=[self.mockDataInfoDomain])
+ else:
+ return MagicMock(
+ res_data=[self.mockDataInfoDomain],
+ extensions=[self.dnssecExtensionWithKeyData],
+ )
+ else:
+ return MagicMock(res_data=[self.mockDataInfoHosts])
+
+ patcher = patch("registrar.models.domain.registry.send")
+ mocked_send = patcher.start()
+ mocked_send.side_effect = side_effect
+
domain, _ = Domain.objects.get_or_create(name="dnssec-keydata.gov")
domain.dnssecdata = self.dnssecExtensionWithKeyData
# get the DNS SEC extension added to the UpdateDomain command
# and verify that it is properly sent
# args[0] is the _request sent to registry
- args, _ = self.mockedSendFunction.call_args
+ args, _ = mocked_send.call_args
# assert that the extension matches
self.assertEquals(
args[0].extensions[0],
- self.createUpdateExtension(
- self.dnssecExtensionWithKeyData
- ),
+ self.createUpdateExtension(self.dnssecExtensionWithKeyData),
)
# test that the dnssecdata getter is functioning properly
dnssecdata_get = domain.dnssecdata
- self.mockedSendFunction.assert_has_calls(
+ mocked_send.assert_has_calls(
[
call(
commands.UpdateDomain(
@@ -1319,6 +1412,8 @@ class TestRegistrantDNSSEC(MockEppLib):
dnssecdata_get.keyData, self.dnssecExtensionWithKeyData.keyData
)
+ patcher.stop()
+
def test_update_is_unsuccessful(self):
"""
Scenario: An update to the dns data is unsuccessful
diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py
index 6cc89682e..2781be038 100644
--- a/src/registrar/views/domain.py
+++ b/src/registrar/views/domain.py
@@ -497,7 +497,7 @@ class DomainKeydataView(DomainPermissionView, FormMixin):
}
if dnssecdata.keyData is None:
dnssecdata.keyData = []
- dnssecdata["keyData"].append(common.DNSSECKeyData(**keyrecord))
+ dnssecdata.keyData.append(common.DNSSECKeyData(**keyrecord))
except KeyError:
# no server information in this field, skip it
pass
From 4dc94a5410ac4946fce57e3ef6f76644a64aa111 Mon Sep 17 00:00:00 2001
From: David Kennedy
Date: Tue, 10 Oct 2023 11:47:07 -0400
Subject: [PATCH 55/65] copy changes
---
src/registrar/templates/domain_dns.html | 2 +-
src/registrar/templates/domain_dnssec.html | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/registrar/templates/domain_dns.html b/src/registrar/templates/domain_dns.html
index 0133a8b07..b16c1cb8b 100644
--- a/src/registrar/templates/domain_dns.html
+++ b/src/registrar/templates/domain_dns.html
@@ -9,7 +9,7 @@
The Domain Name System (DNS) is the internet service that translates your domain name into an IP address. Before your .gov domain can be used, you'll need to connect it to your DNS hosting service and provide us with your name server information.
-
You can enter your name services, as well as other DNS-related information, in the following sections:
+
You can enter your name servers, as well as other DNS-related information, in the following sections:
{% url 'domain-dns-nameservers' pk=domain.id as url %}
DNSSEC, or DNS Security Extensions, is additional security layer to protect your website. Enabling DNSSEC ensures that when someone visits your website, they can be certain that it's connecting to the correct server, preventing potential hijacking or tampering with your domain's records.
+
DNSSEC, or DNS Security Extensions, is additional security layer to protect your domain. Enabling DNSSEC ensures that when someone visits your domain, they can be certain that it's connecting to the correct server, preventing potential hijacking or tampering with your domain's records.
{% csrf_token %}
@@ -43,7 +43,7 @@
- It is strongly recommended that you do not enable this unless you fully understand DNSSEC and know how to set it up properly. If you make a mistake, it could cause your domain name to stop working.
+ It is strongly recommended that you only enable DNSSEC if you know how to set it up properly at your hosting service. If you make a mistake, it could cause your domain name to stop working.
Date: Tue, 10 Oct 2023 19:54:43 -0400
Subject: [PATCH 56/65] trailing lines and some cleanup
---
src/registrar/assets/sass/_theme/_admin.scss | 2 +-
src/registrar/assets/sass/_theme/_alerts.scss | 2 +-
src/registrar/assets/sass/_theme/_base.scss | 2 +-
src/registrar/assets/sass/_theme/_buttons.scss | 2 +-
src/registrar/assets/sass/_theme/_fieldsets.scss | 2 +-
src/registrar/assets/sass/_theme/_forms.scss | 2 +-
src/registrar/assets/sass/_theme/_register-form.scss | 2 +-
src/registrar/assets/sass/_theme/_sidenav.scss | 2 +-
src/registrar/assets/sass/_theme/_tables.scss | 2 +-
src/registrar/assets/sass/_theme/_typography.scss | 2 +-
src/registrar/templates/includes/modal.html | 2 +-
src/registrar/views/domain.py | 2 +-
12 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/src/registrar/assets/sass/_theme/_admin.scss b/src/registrar/assets/sass/_theme/_admin.scss
index a2e32bd21..35d089cbd 100644
--- a/src/registrar/assets/sass/_theme/_admin.scss
+++ b/src/registrar/assets/sass/_theme/_admin.scss
@@ -179,4 +179,4 @@ h1, h2, h3 {
text-align: left;
background: var(--primary);
color: var(--header-link-color);
-}
\ No newline at end of file
+}
diff --git a/src/registrar/assets/sass/_theme/_alerts.scss b/src/registrar/assets/sass/_theme/_alerts.scss
index 077708990..dd51734ed 100644
--- a/src/registrar/assets/sass/_theme/_alerts.scss
+++ b/src/registrar/assets/sass/_theme/_alerts.scss
@@ -14,4 +14,4 @@
left: 1rem !important;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/registrar/assets/sass/_theme/_base.scss b/src/registrar/assets/sass/_theme/_base.scss
index 729049444..668a6ace6 100644
--- a/src/registrar/assets/sass/_theme/_base.scss
+++ b/src/registrar/assets/sass/_theme/_base.scss
@@ -124,4 +124,4 @@ abbr[title] {
.flex-end {
align-items: flex-end;
-}
\ No newline at end of file
+}
diff --git a/src/registrar/assets/sass/_theme/_buttons.scss b/src/registrar/assets/sass/_theme/_buttons.scss
index f4c72f4fa..4815ff82e 100644
--- a/src/registrar/assets/sass/_theme/_buttons.scss
+++ b/src/registrar/assets/sass/_theme/_buttons.scss
@@ -106,4 +106,4 @@ a.usa-button--unstyled:visited {
position: relative;
top: -39.2px;
left: 88px;
-}
\ No newline at end of file
+}
diff --git a/src/registrar/assets/sass/_theme/_fieldsets.scss b/src/registrar/assets/sass/_theme/_fieldsets.scss
index e7da538e3..c60080cb9 100644
--- a/src/registrar/assets/sass/_theme/_fieldsets.scss
+++ b/src/registrar/assets/sass/_theme/_fieldsets.scss
@@ -7,4 +7,4 @@ fieldset {
fieldset:not(:first-child) {
margin-top: units(2);
-}
\ No newline at end of file
+}
diff --git a/src/registrar/assets/sass/_theme/_forms.scss b/src/registrar/assets/sass/_theme/_forms.scss
index 13e1a7a61..cdb2889c5 100644
--- a/src/registrar/assets/sass/_theme/_forms.scss
+++ b/src/registrar/assets/sass/_theme/_forms.scss
@@ -18,4 +18,4 @@
margin-left: 0;
padding-left: 0;
border-left: none;
-}
\ No newline at end of file
+}
diff --git a/src/registrar/assets/sass/_theme/_register-form.scss b/src/registrar/assets/sass/_theme/_register-form.scss
index 7bf4eebf3..d0405a3c3 100644
--- a/src/registrar/assets/sass/_theme/_register-form.scss
+++ b/src/registrar/assets/sass/_theme/_register-form.scss
@@ -77,4 +77,4 @@
color: color('primary-dark');
font-weight: font-weight('semibold');
margin-bottom: units(0.5);
-}
\ No newline at end of file
+}
diff --git a/src/registrar/assets/sass/_theme/_sidenav.scss b/src/registrar/assets/sass/_theme/_sidenav.scss
index c1be03a00..caafa7dd4 100644
--- a/src/registrar/assets/sass/_theme/_sidenav.scss
+++ b/src/registrar/assets/sass/_theme/_sidenav.scss
@@ -27,4 +27,4 @@
.stepnav {
margin-top: units(2);
-}
\ No newline at end of file
+}
diff --git a/src/registrar/assets/sass/_theme/_tables.scss b/src/registrar/assets/sass/_theme/_tables.scss
index 947c75005..6dcc6f3bc 100644
--- a/src/registrar/assets/sass/_theme/_tables.scss
+++ b/src/registrar/assets/sass/_theme/_tables.scss
@@ -90,4 +90,4 @@
border-top: none;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/registrar/assets/sass/_theme/_typography.scss b/src/registrar/assets/sass/_theme/_typography.scss
index e13e9ee3b..4fc2bb819 100644
--- a/src/registrar/assets/sass/_theme/_typography.scss
+++ b/src/registrar/assets/sass/_theme/_typography.scss
@@ -21,4 +21,4 @@ h2 {
line-height: line-height('heading', 3);
margin: units(4) 0 units(1);
color: color('primary-darker');
-}
\ No newline at end of file
+}
diff --git a/src/registrar/templates/includes/modal.html b/src/registrar/templates/includes/modal.html
index b456a59e1..996759576 100644
--- a/src/registrar/templates/includes/modal.html
+++ b/src/registrar/templates/includes/modal.html
@@ -39,4 +39,4 @@
-
\ No newline at end of file
+
diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py
index 9334700ef..c0e121fee 100644
--- a/src/registrar/views/domain.py
+++ b/src/registrar/views/domain.py
@@ -241,7 +241,7 @@ class DomainDNSSECView(DomainPermissionView, FormMixin):
has_dnssec_records = self.domain.dnssecdata is not None
- # Create HTML for the buttons
+ # Create HTML for the modal button
modal_button = 'Disable DNSSEC'
context['modal_button'] = modal_button
From 4c2eaac59f9d8800fe21146b100f8c262211203f Mon Sep 17 00:00:00 2001
From: Rachid Mrad
Date: Tue, 10 Oct 2023 20:02:02 -0400
Subject: [PATCH 57/65] comments clean up
---
src/registrar/views/domain.py | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py
index 2cf5ca3c2..24a704d94 100644
--- a/src/registrar/views/domain.py
+++ b/src/registrar/views/domain.py
@@ -297,6 +297,8 @@ class DomainDsdataView(DomainPermissionView, FormMixin):
if dnssecdata is not None:
if dnssecdata.keyData is not None:
# TODO: Throw an error
+ # Note: This is moot if we're
+ # removing key data
pass
if dnssecdata.dsData is not None:
@@ -311,7 +313,7 @@ class DomainDsdataView(DomainPermissionView, FormMixin):
for record in dnssecdata.dsData
)
- # Ensure at least 3 fields, filled or empty
+ # Ensure at least 1 record, filled or empty
while len(initial_data) == 0:
initial_data.append({})
@@ -385,7 +387,6 @@ class DomainDsdataView(DomainPermissionView, FormMixin):
try:
domain.dnssecdata = dnssecdata
except RegistryError as err:
- # Alysia: Check client hold error handling and duplicate this here
errmsg = "Error updating DNSSEC data in the registry."
logger.error(errmsg)
logger.error(err)
@@ -415,7 +416,9 @@ class DomainKeydataView(DomainPermissionView, FormMixin):
if dnssecdata is not None:
if dnssecdata.dsData is not None:
- # TODO: Throw an error
+ # TODO: Throw an error?
+ # Note: this is moot if we're
+ # removing Key data
pass
if dnssecdata.keyData is not None:
@@ -430,7 +433,7 @@ class DomainKeydataView(DomainPermissionView, FormMixin):
for record in dnssecdata.keyData
)
- # Ensure at least 3 fields, filled or empty
+ # Ensure at least 1 record, filled or empty
while len(initial_data) == 0:
initial_data.append({})
From bddf791489c1e82f2266b5e66568d12ac4439982 Mon Sep 17 00:00:00 2001
From: David Kennedy
Date: Wed, 11 Oct 2023 18:42:13 -0400
Subject: [PATCH 58/65] some content updates
---
src/registrar/templates/domain_dnssec.html | 2 +-
src/registrar/templates/domain_dsdata.html | 17 +++++++++++------
src/registrar/templates/domain_sidebar.html | 2 +-
3 files changed, 13 insertions(+), 8 deletions(-)
diff --git a/src/registrar/templates/domain_dnssec.html b/src/registrar/templates/domain_dnssec.html
index 91d8bb7b8..9913b041c 100644
--- a/src/registrar/templates/domain_dnssec.html
+++ b/src/registrar/templates/domain_dnssec.html
@@ -5,7 +5,7 @@
{% block domain_content %}
-
{% if dnssec_enabled %}Set up {% endif %}DNSSEC
+
DNSSEC
DNSSEC, or DNS Security Extensions, is additional security layer to protect your domain. Enabling DNSSEC ensures that when someone visits your domain, they can be certain that it's connecting to the correct server, preventing potential hijacking or tampering with your domain's records.
In order to enable DNSSEC and add DS records, you must first configure it with your DNS hosting service. Your configuration will determine whether you need to add DS Data or Key Data. Contact your DNS hosting provider if you are unsure which record type to add.
+
In order to enable DNSSEC, you must first configure it with your DNS hosting service.
+
Enter the values given by your DNS provider for DS Data.
+
Required fields are marked with an asterisk (*).
{% csrf_token %}
- Add DS Data record
+
+ Add new record
+
{% else %}
diff --git a/src/registrar/templates/domain_sidebar.html b/src/registrar/templates/domain_sidebar.html
index aff9f5dab..1acd87eeb 100644
--- a/src/registrar/templates/domain_sidebar.html
+++ b/src/registrar/templates/domain_sidebar.html
@@ -23,7 +23,7 @@
- DNS name servers
+ Name servers
From c7c50fb3d5b19a1d836368e483900e15da225f84 Mon Sep 17 00:00:00 2001
From: David Kennedy
Date: Wed, 11 Oct 2023 18:48:24 -0400
Subject: [PATCH 59/65] minor js update
---
src/registrar/assets/js/get-gov.js | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/registrar/assets/js/get-gov.js b/src/registrar/assets/js/get-gov.js
index 4b5ff5e31..f5dffba12 100644
--- a/src/registrar/assets/js/get-gov.js
+++ b/src/registrar/assets/js/get-gov.js
@@ -276,8 +276,7 @@ function prepareDeleteButtons() {
let formToRemove = e.target.closest(".ds-record");
formToRemove.remove();
let forms = document.querySelectorAll(".ds-record");
- let formNum2 = forms.length;
- totalForms.setAttribute('value', `${formNum2}`);
+ totalForms.setAttribute('value', `${forms.length}`);
let formNumberRegex = RegExp(`form-(\\d){1}-`, 'g');
let formLabelRegex = RegExp(`DS Data record (\\d){1}`, 'g');
From bac08277b2fe2e8bd811c0857c3bdca58d052131 Mon Sep 17 00:00:00 2001
From: David Kennedy
Date: Wed, 11 Oct 2023 19:04:10 -0400
Subject: [PATCH 60/65] updated copy and fixed failing test
---
src/registrar/templates/domain_dsdata.html | 8 ++++++++
src/registrar/tests/test_views.py | 5 +++--
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/src/registrar/templates/domain_dsdata.html b/src/registrar/templates/domain_dsdata.html
index eb0e73e49..c068a3752 100644
--- a/src/registrar/templates/domain_dsdata.html
+++ b/src/registrar/templates/domain_dsdata.html
@@ -8,6 +8,14 @@
{% include "includes/form_errors.html" with form=form %}
{% endfor %}
+ {% if domain.dnssecdata is None and not dnssec_ds_confirmed %}
+
+
+ You have no DS Data added. Enable DNSSEC by adding DS Data or return to the DNSSEC page and click 'enable.'
+
+
+ {% endif %}
+
DS Data
{% if domain.dnssecdata is not None and domain.dnssecdata.keyData is not None %}
diff --git a/src/registrar/tests/test_views.py b/src/registrar/tests/test_views.py
index af44cdeaa..06fddfde7 100644
--- a/src/registrar/tests/test_views.py
+++ b/src/registrar/tests/test_views.py
@@ -1618,14 +1618,15 @@ class TestDomainDNSSEC(TestDomainOverview):
def test_ds_form_loads_with_no_domain_data(self):
"""DNSSEC Add DS Data page loads when there is no
- domain DNSSEC data and shows a button to Add DS Data record"""
+ domain DNSSEC data and shows a button to Add new record"""
page = self.client.get(
reverse(
"domain-dns-dnssec-dsdata", kwargs={"pk": self.domain_dnssec_none.id}
)
)
- self.assertContains(page, "Add DS Data record")
+ self.assertContains(page, "You have no DS Data added")
+ self.assertContains(page, "Add new record")
def test_ds_form_loads_with_ds_data(self):
"""DNSSEC Add DS Data page loads when there is
From 46ad6002cd0213fd0b46d1efe86ab1f5be2bf5c1 Mon Sep 17 00:00:00 2001
From: Rachid Mrad
Date: Fri, 13 Oct 2023 12:07:35 -0400
Subject: [PATCH 61/65] CSS tweaks
---
src/registrar/assets/sass/_theme/_forms.scss | 4 ++++
src/registrar/forms/domain.py | 2 +-
src/registrar/templates/domain_dnssec.html | 8 ++++----
src/registrar/templates/domain_dsdata.html | 2 +-
src/registrar/templates/domain_keydata.html | 2 +-
5 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/src/registrar/assets/sass/_theme/_forms.scss b/src/registrar/assets/sass/_theme/_forms.scss
index cdb2889c5..ed118bb94 100644
--- a/src/registrar/assets/sass/_theme/_forms.scss
+++ b/src/registrar/assets/sass/_theme/_forms.scss
@@ -8,6 +8,10 @@
max-width: none;
}
+.usa-form--text-width {
+ max-width: measure(5);
+}
+
.usa-textarea {
@include at-media('tablet') {
height: units('mobile');
diff --git a/src/registrar/forms/domain.py b/src/registrar/forms/domain.py
index 73a40bfa1..b28c9f6a4 100644
--- a/src/registrar/forms/domain.py
+++ b/src/registrar/forms/domain.py
@@ -176,7 +176,7 @@ class DomainDsdataForm(forms.Form):
digest_type = forms.TypedChoiceField(
required=True,
- label="Digest Type",
+ label="Digest type",
coerce=int, # need to coerce into int so dsData objects can be compared
choices=[(None, "--Select--")] + DIGEST_TYPE_CHOICES, # type: ignore
error_messages={"required": ("Digest Type is required.")},
diff --git a/src/registrar/templates/domain_dnssec.html b/src/registrar/templates/domain_dnssec.html
index 9913b041c..4fa43bb4c 100644
--- a/src/registrar/templates/domain_dnssec.html
+++ b/src/registrar/templates/domain_dnssec.html
@@ -9,10 +9,10 @@
DNSSEC, or DNS Security Extensions, is additional security layer to protect your domain. Enabling DNSSEC ensures that when someone visits your domain, they can be certain that it's connecting to the correct server, preventing potential hijacking or tampering with your domain's records.
-
+
{% csrf_token %}
{% if has_dnssec_records %}
-
+
In order to fully disable DNSSEC on your domain, you will need to work with your DNS provider to remove your DNSSEC-related records from your zone.
It is strongly recommended that you only enable DNSSEC if you know how to set it up properly at your hosting service. If you make a mistake, it could cause your domain name to stop working.
diff --git a/src/registrar/templates/domain_dsdata.html b/src/registrar/templates/domain_dsdata.html
index c068a3752..ca4dce783 100644
--- a/src/registrar/templates/domain_dsdata.html
+++ b/src/registrar/templates/domain_dsdata.html
@@ -97,7 +97,7 @@
{% endfor %}
-
+ Add new record
diff --git a/src/registrar/templates/domain_keydata.html b/src/registrar/templates/domain_keydata.html
index a5d2f610c..167d86370 100644
--- a/src/registrar/templates/domain_keydata.html
+++ b/src/registrar/templates/domain_keydata.html
@@ -84,7 +84,7 @@
{% endfor %}
-
+ Add new record
From 5a5aa5e97a2e26e340436dd225cb105ae49cb9b4 Mon Sep 17 00:00:00 2001
From: Rachid Mrad
Date: Fri, 13 Oct 2023 12:54:56 -0400
Subject: [PATCH 62/65] tweak cancel buttons
---
src/registrar/assets/sass/_theme/_buttons.scss | 18 +++++++++++++++++-
src/registrar/templates/domain_dnssec.html | 2 +-
2 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/src/registrar/assets/sass/_theme/_buttons.scss b/src/registrar/assets/sass/_theme/_buttons.scss
index 4815ff82e..718bd5792 100644
--- a/src/registrar/assets/sass/_theme/_buttons.scss
+++ b/src/registrar/assets/sass/_theme/_buttons.scss
@@ -101,7 +101,23 @@ a.usa-button--unstyled:visited {
}
}
-// WARNING: crazy hack ahead
+// Cancel button used on the
+// DNSSEC main page
+// We want to center this button on mobile
+// and add some extra left margin on tablet+
+.usa-button--cancel {
+ text-align: center;
+ @include at-media('tablet') {
+ margin-left: units(2);
+ }
+}
+
+
+// WARNING: crazy hack ahead:
+// Cancel button(s) on the DNSSEC form pages
+// We want to position the cancel button on the
+// dnssec forms next to the submit button
+// This button's markup is in its own form
.btn-cancel {
position: relative;
top: -39.2px;
diff --git a/src/registrar/templates/domain_dnssec.html b/src/registrar/templates/domain_dnssec.html
index 4fa43bb4c..5eedb2184 100644
--- a/src/registrar/templates/domain_dnssec.html
+++ b/src/registrar/templates/domain_dnssec.html
@@ -33,7 +33,7 @@
Add Key DataCancel
From c6abca99cad675ff8616e18e4f9dfba29cbfca80 Mon Sep 17 00:00:00 2001
From: David Kennedy
Date: Fri, 13 Oct 2023 15:32:30 -0400
Subject: [PATCH 63/65] updates to tests
---
src/registrar/tests/common.py | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py
index d1021f45c..5df54de76 100644
--- a/src/registrar/tests/common.py
+++ b/src/registrar/tests/common.py
@@ -791,6 +791,8 @@ class MockEppLib(TestCase):
return self.mockInfoDomainCommands(_request, cleaned)
elif isinstance(_request, commands.InfoContact):
return self.mockInfoContactCommands(_request, cleaned)
+ elif isinstance(_request, commands.UpdateDomain):
+ return self.mockUpdateDomainCommands(_request, cleaned)
elif (
isinstance(_request, commands.CreateContact)
and getattr(_request, "id", None) == "fail"
@@ -809,16 +811,6 @@ class MockEppLib(TestCase):
res_data=[self.mockDataHostChange],
code=ErrorCode.COMMAND_COMPLETED_SUCCESSFULLY,
)
- elif (
- isinstance(_request, commands.UpdateDomain)
- and getattr(_request, "name", None) == "dnssec-invalid.gov"
- ):
- raise RegistryError(code=ErrorCode.PARAMETER_VALUE_RANGE_ERROR)
- elif isinstance(_request, commands.UpdateDomain):
- return MagicMock(
- res_data=[self.mockDataHostChange],
- code=ErrorCode.COMMAND_COMPLETED_SUCCESSFULLY,
- )
elif isinstance(_request, commands.DeleteHost):
return MagicMock(
res_data=[self.mockDataHostChange],
@@ -836,6 +828,15 @@ class MockEppLib(TestCase):
)
return MagicMock(res_data=[self.mockDataInfoHosts])
+ def mockUpdateDomainCommands(self, _request, cleaned):
+ if getattr(_request, "name", None) == "dnssec-invalid.gov":
+ raise RegistryError(code=ErrorCode.PARAMETER_VALUE_RANGE_ERROR)
+ else:
+ return MagicMock(
+ res_data=[self.mockDataHostChange],
+ code=ErrorCode.COMMAND_COMPLETED_SUCCESSFULLY,
+ )
+
def mockInfoDomainCommands(self, _request, cleaned):
if getattr(_request, "name", None) == "security.gov":
return MagicMock(res_data=[self.infoDomainNoContact])
From f94363a836a59b34291261f21cdb3296593b9adf Mon Sep 17 00:00:00 2001
From: Rachid Mrad
Date: Fri, 13 Oct 2023 15:43:24 -0400
Subject: [PATCH 64/65] refactor epp mockInfoDomainCommands function
---
src/registrar/tests/common.py | 74 ++++++++++++++++++-----------------
1 file changed, 39 insertions(+), 35 deletions(-)
diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py
index 5df54de76..7ae107006 100644
--- a/src/registrar/tests/common.py
+++ b/src/registrar/tests/common.py
@@ -838,41 +838,45 @@ class MockEppLib(TestCase):
)
def mockInfoDomainCommands(self, _request, cleaned):
- if getattr(_request, "name", None) == "security.gov":
- return MagicMock(res_data=[self.infoDomainNoContact])
- elif getattr(_request, "name", None) == "dnssec-dsdata.gov":
- return MagicMock(
- res_data=[self.mockDataInfoDomain],
- extensions=[self.dnssecExtensionWithDsData],
- )
- elif getattr(_request, "name", None) == "dnssec-multdsdata.gov":
- return MagicMock(
- res_data=[self.mockDataInfoDomain],
- extensions=[self.dnssecExtensionWithMultDsData],
- )
- elif getattr(_request, "name", None) == "dnssec-keydata.gov":
- return MagicMock(
- res_data=[self.mockDataInfoDomain],
- extensions=[self.dnssecExtensionWithKeyData],
- )
- elif getattr(_request, "name", None) == "dnssec-none.gov":
- # this case is not necessary, but helps improve readability
- return MagicMock(res_data=[self.mockDataInfoDomain])
- elif getattr(_request, "name", None) == "my-nameserver.gov":
- if self.mockedSendFunction.call_count == 5:
- return MagicMock(res_data=[self.infoDomainTwoHosts])
- else:
- return MagicMock(res_data=[self.infoDomainNoHost])
- elif getattr(_request, "name", None) == "nameserverwithip.gov":
- return MagicMock(res_data=[self.infoDomainHasIP])
- elif getattr(_request, "name", None) == "namerserversubdomain.gov":
- return MagicMock(res_data=[self.infoDomainCheckHostIPCombo])
- elif getattr(_request, "name", None) == "freeman.gov":
- return MagicMock(res_data=[self.InfoDomainWithContacts])
- elif getattr(_request, "name", None) == "threenameserversDomain.gov":
- return MagicMock(res_data=[self.infoDomainThreeHosts])
- else:
- return MagicMock(res_data=[self.mockDataInfoDomain])
+ request_name = getattr(_request, "name", None)
+
+ # Define a dictionary to map request names to data and extension values
+ request_mappings = {
+ "security.gov": (self.infoDomainNoContact, None),
+ "dnssec-dsdata.gov": (
+ self.mockDataInfoDomain,
+ self.dnssecExtensionWithDsData,
+ ),
+ "dnssec-multdsdata.gov": (
+ self.mockDataInfoDomain,
+ self.dnssecExtensionWithMultDsData,
+ ),
+ "dnssec-keydata.gov": (
+ self.mockDataInfoDomain,
+ self.dnssecExtensionWithKeyData,
+ ),
+ "dnssec-none.gov": (self.mockDataInfoDomain, None),
+ "my-nameserver.gov": (
+ self.infoDomainTwoHosts
+ if self.mockedSendFunction.call_count == 5
+ else self.infoDomainNoHost,
+ None,
+ ),
+ "nameserverwithip.gov": (self.infoDomainHasIP, None),
+ "namerserversubdomain.gov": (self.infoDomainCheckHostIPCombo, None),
+ "freeman.gov": (self.InfoDomainWithContacts, None),
+ "threenameserversDomain.gov": (self.infoDomainThreeHosts, None),
+ }
+
+ # Retrieve the corresponding values from the dictionary
+ res_data, extensions = request_mappings.get(
+ request_name, (self.mockDataInfoDomain, None)
+ )
+
+ return MagicMock(
+ res_data=[res_data],
+ extensions=[extensions] if extensions is not None else [],
+ )
def mockInfoContactCommands(self, _request, cleaned):
mocked_result: info.InfoContactResultData
From 181cfccfc5463ef1984563b4d4211107d13b3a32 Mon Sep 17 00:00:00 2001
From: David Kennedy
Date: Tue, 17 Oct 2023 13:20:48 -0400
Subject: [PATCH 65/65] added comments, removed empty lines, and renamed
methods for code legibility
---
src/registrar/assets/js/get-gov.js | 8 ++++++++
src/registrar/config/urls.py | 4 ++--
src/registrar/forms/domain.py | 8 --------
src/registrar/models/domain.py | 12 +++++++++++-
src/registrar/views/__init__.py | 4 ++--
src/registrar/views/domain.py | 22 +++++++---------------
6 files changed, 30 insertions(+), 28 deletions(-)
diff --git a/src/registrar/assets/js/get-gov.js b/src/registrar/assets/js/get-gov.js
index f5dffba12..c21060382 100644
--- a/src/registrar/assets/js/get-gov.js
+++ b/src/registrar/assets/js/get-gov.js
@@ -315,9 +315,17 @@ function prepareDeleteButtons() {
// Attach click event listener on the delete buttons of the existing forms
prepareDeleteButtons();
+ // Attack click event listener on the add button
if (addButton)
addButton.addEventListener('click', addForm);
+ /*
+ * Add a formset to the end of the form.
+ * For each element in the added formset, name the elements with the prefix,
+ * form-{#}-{element_name} where # is the index of the formset and element_name
+ * is the element's name.
+ * Additionally, update the form element's metadata, including totalForms' value.
+ */
function addForm(e){
let forms = document.querySelectorAll(".ds-record");
let formNum = forms.length;
diff --git a/src/registrar/config/urls.py b/src/registrar/config/urls.py
index 7caa64e5c..bd2215620 100644
--- a/src/registrar/config/urls.py
+++ b/src/registrar/config/urls.py
@@ -97,12 +97,12 @@ urlpatterns = [
),
path(
"domain//dns/dnssec/dsdata",
- views.DomainDsdataView.as_view(),
+ views.DomainDsDataView.as_view(),
name="domain-dns-dnssec-dsdata",
),
path(
"domain//dns/dnssec/keydata",
- views.DomainKeydataView.as_view(),
+ views.DomainKeyDataView.as_view(),
name="domain-dns-dnssec-keydata",
),
path(
diff --git a/src/registrar/forms/domain.py b/src/registrar/forms/domain.py
index 3878c1f43..8abc7e14a 100644
--- a/src/registrar/forms/domain.py
+++ b/src/registrar/forms/domain.py
@@ -16,14 +16,12 @@ from .common import (
class DomainAddUserForm(forms.Form):
-
"""Form for adding a user to a domain."""
email = forms.EmailField(label="Email")
class DomainNameserverForm(forms.Form):
-
"""Form for changing nameservers."""
server = forms.CharField(label="Name server", strip=True)
@@ -37,7 +35,6 @@ NameserverFormset = formset_factory(
class ContactForm(forms.ModelForm):
-
"""Form for updating contacts."""
class Meta:
@@ -68,14 +65,12 @@ class ContactForm(forms.ModelForm):
class DomainSecurityEmailForm(forms.Form):
-
"""Form for adding or editing a security email to a domain."""
security_email = forms.EmailField(label="Security email", required=False)
class DomainOrgNameAddressForm(forms.ModelForm):
-
"""Form for updating the organization name and mailing address."""
zipcode = forms.CharField(
@@ -149,12 +144,10 @@ class DomainOrgNameAddressForm(forms.ModelForm):
class DomainDnssecForm(forms.Form):
-
"""Form for enabling and disabling dnssec"""
class DomainDsdataForm(forms.Form):
-
"""Form for adding or editing DNSSEC DS Data to a domain."""
key_tag = forms.IntegerField(
@@ -198,7 +191,6 @@ DomainDsdataFormset = formset_factory(
class DomainKeydataForm(forms.Form):
-
"""Form for adding or editing DNSSEC Key Data to a domain."""
flag = forms.TypedChoiceField(
diff --git a/src/registrar/models/domain.py b/src/registrar/models/domain.py
index c5ba4356b..0b107907e 100644
--- a/src/registrar/models/domain.py
+++ b/src/registrar/models/domain.py
@@ -458,11 +458,21 @@ class Domain(TimeStampedModel, DomainHelper):
@Cache
def dnssecdata(self) -> Optional[extensions.DNSSECExtension]:
+ """
+ Get a complete list of dnssecdata extensions for this domain.
+
+ dnssecdata are provided as a list of DNSSECExtension objects.
+
+ A DNSSECExtension object includes:
+ maxSigLife: Optional[int]
+ dsData: Optional[Sequence[DSData]]
+ keyData: Optional[Sequence[DNSSECKeyData]]
+
+ """
try:
return self._get_property("dnssecdata")
except Exception as err:
# Don't throw error as this is normal for a new domain
- # TODO - 433 error handling ticket should address this
logger.info("Domain does not have dnssec data defined %s" % err)
return None
diff --git a/src/registrar/views/__init__.py b/src/registrar/views/__init__.py
index 5bca4e1d5..5fd81df8c 100644
--- a/src/registrar/views/__init__.py
+++ b/src/registrar/views/__init__.py
@@ -6,8 +6,8 @@ from .domain import (
DomainDNSView,
DomainNameserversView,
DomainDNSSECView,
- DomainDsdataView,
- DomainKeydataView,
+ DomainDsDataView,
+ DomainKeyDataView,
DomainYourContactInformationView,
DomainSecurityEmailView,
DomainUsersView,
diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py
index 68d193e86..36b7a9445 100644
--- a/src/registrar/views/domain.py
+++ b/src/registrar/views/domain.py
@@ -51,7 +51,6 @@ logger = logging.getLogger(__name__)
class DomainView(DomainPermissionView):
-
"""Domain detail overview page."""
template_name = "domain_detail.html"
@@ -113,7 +112,6 @@ class DomainOrgNameAddressView(DomainPermissionView, FormMixin):
class DomainAuthorizingOfficialView(DomainPermissionView, FormMixin):
-
"""Domain authorizing official editing view."""
model = Domain
@@ -156,14 +154,12 @@ class DomainAuthorizingOfficialView(DomainPermissionView, FormMixin):
class DomainDNSView(DomainPermissionView):
-
"""DNS Information View."""
template_name = "domain_dns.html"
class DomainNameserversView(DomainPermissionView, FormMixin):
-
"""Domain nameserver editing view."""
template_name = "domain_nameservers.html"
@@ -242,15 +238,15 @@ class DomainNameserversView(DomainPermissionView, FormMixin):
class DomainDNSSECView(DomainPermissionView, FormMixin):
-
"""Domain DNSSEC editing view."""
template_name = "domain_dnssec.html"
form_class = DomainDnssecForm
def get_context_data(self, **kwargs):
- context = super().get_context_data(**kwargs)
"""The initial value for the form (which is a formset here)."""
+ context = super().get_context_data(**kwargs)
+
self.domain = self.get_object()
has_dnssec_records = self.domain.dnssecdata is not None
@@ -294,8 +290,7 @@ class DomainDNSSECView(DomainPermissionView, FormMixin):
return self.form_valid(form)
-class DomainDsdataView(DomainPermissionView, FormMixin):
-
+class DomainDsDataView(DomainPermissionView, FormMixin):
"""Domain DNSSEC ds data editing view."""
template_name = "domain_dsdata.html"
@@ -395,7 +390,9 @@ class DomainDsdataView(DomainPermissionView, FormMixin):
dnssecdata.dsData = []
dnssecdata.dsData.append(common.DSData(**dsrecord))
except KeyError:
- # no server information in this field, skip it
+ # no cleaned_data provided for this form, but passed
+ # as valid; this can happen if form has been added but
+ # not been interacted with; in that case, want to ignore
pass
domain = self.get_object()
try:
@@ -414,8 +411,7 @@ class DomainDsdataView(DomainPermissionView, FormMixin):
return super().form_valid(formset)
-class DomainKeydataView(DomainPermissionView, FormMixin):
-
+class DomainKeyDataView(DomainPermissionView, FormMixin):
"""Domain DNSSEC key data editing view."""
template_name = "domain_keydata.html"
@@ -536,7 +532,6 @@ class DomainKeydataView(DomainPermissionView, FormMixin):
class DomainYourContactInformationView(DomainPermissionView, FormMixin):
-
"""Domain your contact information editing view."""
template_name = "domain_your_contact_information.html"
@@ -577,7 +572,6 @@ class DomainYourContactInformationView(DomainPermissionView, FormMixin):
class DomainSecurityEmailView(DomainPermissionView, FormMixin):
-
"""Domain security email editing view."""
template_name = "domain_security_email.html"
@@ -639,14 +633,12 @@ class DomainSecurityEmailView(DomainPermissionView, FormMixin):
class DomainUsersView(DomainPermissionView):
-
"""User management page in the domain details."""
template_name = "domain_users.html"
class DomainAddUserView(DomainPermissionView, FormMixin):
-
"""Inside of a domain's user management, a form for adding users.
Multiple inheritance is used here for permissions, form handling, and