From cf461047664706057e755c7baf096bf1e0909f77 Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Wed, 11 Sep 2024 19:56:54 +0200 Subject: [PATCH 1/8] user definable verificationCode --- .../HsDomainSetupBookingItemValidator.java | 5 ++-- .../hs/validation/ValidatableProperty.java | 2 +- ...mainSetupBookingItemValidatorUnitTest.java | 24 +++++++++++++++++-- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsDomainSetupBookingItemValidator.java b/src/main/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsDomainSetupBookingItemValidator.java index 3d62b765..c9fd731a 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsDomainSetupBookingItemValidator.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsDomainSetupBookingItemValidator.java @@ -25,8 +25,9 @@ class HsDomainSetupBookingItemValidator extends HsBookingItemEntityValidator { .notMatchesRegEx(REGISTRAR_LEVEL_DOMAINS).describedAs("is a forbidden registrar-level domain name") .required(), stringProperty(VERIFICATION_CODE_PROPERTY_NAME) - .readOnly().initializedBy(HsDomainSetupBookingItemValidator::generateVerificationCode) - + .minLength(12) + .maxLength(64) + .initializedBy(HsDomainSetupBookingItemValidator::generateVerificationCode) ); } diff --git a/src/main/java/net/hostsharing/hsadminng/hs/validation/ValidatableProperty.java b/src/main/java/net/hostsharing/hsadminng/hs/validation/ValidatableProperty.java index d0966a5e..fb51e7fe 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/validation/ValidatableProperty.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/validation/ValidatableProperty.java @@ -266,7 +266,7 @@ public abstract class ValidatableProperty

, T private boolean isSpecPotentiallyComplete() { return required == null && requiresAtLeastOneOf == null && requiresAtMaxOneOf == null && !readOnly && !writeOnly - && defaultValue == null; + && defaultValue == null && computedBy == null; } @SuppressWarnings("unchecked") diff --git a/src/test/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsDomainSetupBookingItemValidatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsDomainSetupBookingItemValidatorUnitTest.java index 9fbdac45..643c5e54 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsDomainSetupBookingItemValidatorUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsDomainSetupBookingItemValidatorUnitTest.java @@ -28,7 +28,7 @@ class HsDomainSetupBookingItemValidatorUnitTest { private EntityManager em; @Test - void acceptsRegisterableDomain() { + void acceptsRegisterableDomainWithGeneratedVerificationCode() { // given final var domainSetupBookingItemEntity = HsBookingItemRealEntity.builder() .type(DOMAIN_SETUP) @@ -46,6 +46,26 @@ class HsDomainSetupBookingItemValidatorUnitTest { assertThat(result).isEmpty(); } + @Test + void acceptsRegisterableDomainWithExplicitVerifiactionCode() { + // given + final var domainSetupBookingItemEntity = HsBookingItemRealEntity.builder() + .type(DOMAIN_SETUP) + .project(project) + .caption("Test-Domain") + .resources(Map.ofEntries( + entry("domainName", "example.org"), + entry("verificationCode", "1234-5678-9100") + )) + .build(); + + // when + final var result = HsBookingItemEntityValidatorRegistry.doValidate(em, domainSetupBookingItemEntity); + + // then + assertThat(result).isEmpty(); + } + @Test void acceptsMaximumDomainNameLength() { final var domainSetupBookingItemEntity = HsBookingItemRealEntity.builder() @@ -150,6 +170,6 @@ class HsDomainSetupBookingItemValidatorUnitTest { // then assertThat(validator.properties()).map(Map::toString).containsExactlyInAnyOrder( "{type=string, propertyName=domainName, matchesRegEx=[^((?!-)[A-Za-z0-9-]{1,63}(? Date: Wed, 11 Sep 2024 19:57:28 +0200 Subject: [PATCH 2/8] bi-validation in domain-setup business-rules-test --- ...ainSetupHostingAssetValidatorUnitTest.java | 65 +++++++++++++++---- 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidatorUnitTest.java index 8b96ea76..d051ce1e 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidatorUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidatorUnitTest.java @@ -3,6 +3,7 @@ package net.hostsharing.hsadminng.hs.hosting.asset.validators; import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemRealEntity; import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType; import net.hostsharing.hsadminng.hs.booking.item.validators.HsBookingItemEntityValidatorRegistry; +import net.hostsharing.hsadminng.hs.booking.project.HsBookingProjectRealEntity; import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetRbacEntity; import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetRealEntity; import org.junit.jupiter.api.AfterEach; @@ -35,8 +36,10 @@ class HsDomainSetupHostingAssetValidatorUnitTest { static HsHostingAssetRbacEntity.HsHostingAssetRbacEntityBuilder validEntityBuilder( final String domainName, final Function, HsBookingItemRealEntity> buildBookingItem) { - final HsBookingItemRealEntity bookingItem = buildBookingItem.apply( + final var project = HsBookingProjectRealEntity.builder().build(); + final var bookingItem = buildBookingItem.apply( HsBookingItemRealEntity.builder() + .project(project) .type(HsBookingItemType.DOMAIN_SETUP) .resources(new HashMap<>(ofEntries( entry("domainName", domainName) @@ -90,7 +93,8 @@ class HsDomainSetupHostingAssetValidatorUnitTest { // then assertThat(result).contains( - "'identifier' expected to match '(\\*|(?!-)[A-Za-z0-9-]{1,63}(? bib.type(HsBookingItemType.CLOUD_SERVER).build()) + final var domainSetupHostingAssetEntity = validEntityBuilder( + "example.org", + bib -> bib.type(HsBookingItemType.CLOUD_SERVER).build()) .parentAsset(HsHostingAssetRealEntity.builder().type(CLOUD_SERVER).build()) .assignedToAsset(HsHostingAssetRealEntity.builder().type(MANAGED_SERVER).build()) .build(); @@ -161,11 +166,12 @@ class HsDomainSetupHostingAssetValidatorUnitTest { @Test void rejectsDomainNameNotMatchingBookingItemDomainName() { // given - final var domainSetupHostingAssetEntity = validEntityBuilder("not-matching-booking-item-domain-name.org", - bib -> bib.resources(new HashMap<>(ofEntries( - entry("domainName", "example.org") - ))).build() - ).build(); + final var domainSetupHostingAssetEntity = validEntityBuilder( + "not-matching-booking-item-domain-name.org", + bib -> bib.resources(new HashMap<>(ofEntries( + entry("domainName", "example.org") + ))).build() + ).build(); final var validator = HostingAssetEntityValidatorRegistry.forType(domainSetupHostingAssetEntity.getType()); // when @@ -262,6 +268,24 @@ class HsDomainSetupHostingAssetValidatorUnitTest { //===================================================================================================================== + @Test + void rejectsSetupOfRegistrar1stLevelDomain() { + domainSetupFor("org").notRegistered() + .isRejectedWithCauseForbidden("registrar-level domain name"); + } + + @Test + void rejectsSetupOfRegistrar2ndLevelDomain() { + domainSetupFor("co.uk").notRegistered() + .isRejectedWithCauseForbidden("registrar-level domain name"); + } + + @Test + void rejectsSetupOfHostsharingDmain() { + domainSetupFor("hostsharing.net").notRegistered() + .isRejectedWithCauseForbidden("Hostsharing domain name"); + } + @Test void allowSetupOfAvailableRegistrableDomain() { domainSetupFor("example.com").notRegistered() @@ -416,13 +440,27 @@ class HsDomainSetupHostingAssetValidatorUnitTest { + "' found for domain name '" + domainName + "'"); } + void isRejectedWithCauseForbidden(final String type) { + assertThat(validate()).contains( + "'D-???????:null:null.resources.domainName' = '" + domainAsset.getIdentifier() + "' is a forbidden " + type + ); + } + void isAccepted() { assertThat(validate()).isEmpty(); } private List validate() { - final var validator = HostingAssetEntityValidatorRegistry.forType(DOMAIN_SETUP); - return validator.validateEntity(domainAsset); + if ( domainAsset.getBookingItem() != null ) { + final var biValidation = HsBookingItemEntityValidatorRegistry.forType(HsBookingItemType.DOMAIN_SETUP) + .validateEntity(domainAsset.getBookingItem()); + if (!biValidation.isEmpty()) { + return biValidation; + } + } + + return HostingAssetEntityValidatorRegistry.forType(DOMAIN_SETUP) + .validateEntity(domainAsset); } } @@ -432,7 +470,10 @@ class HsDomainSetupHostingAssetValidatorUnitTest { private DomainSetupBuilder domainSetupWithParentAssetFor(final String domainName) { return new DomainSetupBuilder( - HsHostingAssetRealEntity.builder().type(DOMAIN_SETUP).identifier(Dns.superDomain(domainName).orElseThrow()).build(), + HsHostingAssetRealEntity.builder() + .type(DOMAIN_SETUP) + .identifier(Dns.superDomain(domainName).orElseThrow()) + .build(), domainName); } } -- 2.39.5 From ca10f7a99886cce68aa2555faa30b31b702687f1 Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Wed, 11 Sep 2024 19:57:33 +0200 Subject: [PATCH 3/8] cleanup --- .../asset/validators/HsDomainSetupHostingAssetValidator.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidator.java b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidator.java index 20fcbf69..9583e870 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidator.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidator.java @@ -13,7 +13,6 @@ import static net.hostsharing.hsadminng.hs.hosting.asset.validators.HsDomainHttp class HsDomainSetupHostingAssetValidator extends HostingAssetEntityValidator { - public static final String FQDN_REGEX = "^((?!-)[A-Za-z0-9-]{1,63}(? Date: Thu, 12 Sep 2024 07:00:48 +0200 Subject: [PATCH 4/8] add tests with user defined verification cod --- ...ainSetupHostingAssetValidatorUnitTest.java | 46 +++++++++++++++---- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidatorUnitTest.java index d051ce1e..f7c09092 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidatorUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidatorUnitTest.java @@ -365,6 +365,20 @@ class HsDomainSetupHostingAssetValidatorUnitTest { .isRejectedWithCauseMissingVerificationIn("sub.example.org"); } + @Test + void allowSetupOfRegistrableDomainWithUserDefinedVerificationCode() { + domainSetupFor("example.edu.it").notRegistered().withUserDefinedVerificationCode("ABCD-EFGH-IJKL-MNOP") + .withVerificationIn("example.edu.it") + .isAccepted(); + } + + @Test + void rejectSetupOfRegistrableDomainWithInvalidUserDefinedVerificationCode() { + domainSetupFor("example.edu.it").notRegistered().withUserDefinedVerificationCode("ABCD-EFGH-IJKL-MNOP") + .withVerificationIn("example.edu.it", "SOME-OTHER-CODE") + .isRejectedWithCauseMissingVerificationIn("example.edu.it"); + } + //==================================================================================================================== private static HsHostingAssetRealEntity createValidParentDomainSetupAsset(final String parentDomainName) { @@ -384,11 +398,9 @@ class HsDomainSetupHostingAssetValidatorUnitTest { class DomainSetupBuilder { private final HsHostingAssetRbacEntity domainAsset; - private final String expectedHash; public DomainSetupBuilder(final String domainName) { domainAsset = validEntityBuilder(domainName).build(); - expectedHash = domainAsset.getBookingItem().getDirectValue("verificationCode", String.class); } public DomainSetupBuilder(final HsHostingAssetRealEntity parentAsset, final String domainName) { @@ -396,7 +408,6 @@ class HsDomainSetupHostingAssetValidatorUnitTest { .bookingItem(null) .parentAsset(parentAsset) .build(); - expectedHash = null; } DomainSetupBuilder notRegistered() { @@ -423,20 +434,33 @@ class HsDomainSetupHostingAssetValidatorUnitTest { return this; } - DomainSetupBuilder withVerificationIn(final String domainName) { - assertThat(expectedHash).as("no expectedHash available").isNotNull(); + DomainSetupBuilder withUserDefinedVerificationCode(final String verificationCode) { + domainAsset.getBookingItem().getResources().put("verificationCode", verificationCode); + return this; + } + + DomainSetupBuilder withVerificationIn(final String domainName, final String verificationCode) { + assertThat(verificationCode).as("explicit verificationCode must not be null").isNotNull(); Dns.fakeResultForDomain( domainName, - Dns.Result.fromRecords("Hostsharing-domain-setup-verification-code=" + expectedHash)); + Dns.Result.fromRecords("Hostsharing-domain-setup-verification-code=" + verificationCode)); + return this; + } + + DomainSetupBuilder withVerificationIn(final String domainName) { + assertThat(expectedVerificationCode()).as("no expectedHash available").isNotNull(); + Dns.fakeResultForDomain( + domainName, + Dns.Result.fromRecords("Hostsharing-domain-setup-verification-code=" + expectedVerificationCode())); return this; } void isRejectedWithCauseMissingVerificationIn(final String domainName) { - assertThat(expectedHash).as("no expectedHash available").isNotNull(); + assertThat(expectedVerificationCode()).as("no expectedHash available").isNotNull(); assertThat(validate()).containsAnyOf( - "[DNS] no TXT record 'Hostsharing-domain-setup-verification-code=" + expectedHash + "[DNS] no TXT record 'Hostsharing-domain-setup-verification-code=" + expectedVerificationCode() + "' found for domain name '" + domainName + "' (nor in its super-domain)", - "[DNS] no TXT record 'Hostsharing-domain-setup-verification-code=" + expectedHash + "[DNS] no TXT record 'Hostsharing-domain-setup-verification-code=" + expectedVerificationCode() + "' found for domain name '" + domainName + "'"); } @@ -450,6 +474,10 @@ class HsDomainSetupHostingAssetValidatorUnitTest { assertThat(validate()).isEmpty(); } + private String expectedVerificationCode() { + return domainAsset.getBookingItem().getDirectValue("verificationCode", String.class); + } + private List validate() { if ( domainAsset.getBookingItem() != null ) { final var biValidation = HsBookingItemEntityValidatorRegistry.forType(HsBookingItemType.DOMAIN_SETUP) -- 2.39.5 From 8d69f2ed39250e3efb2d48c23465b5ce5895d90e Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Thu, 12 Sep 2024 07:13:15 +0200 Subject: [PATCH 5/8] add business-level tests with parent asset --- ...ainSetupHostingAssetValidatorUnitTest.java | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidatorUnitTest.java index f7c09092..36cb2504 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidatorUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidatorUnitTest.java @@ -281,7 +281,7 @@ class HsDomainSetupHostingAssetValidatorUnitTest { } @Test - void rejectsSetupOfHostsharingDmain() { + void rejectsSetupOfHostsharingDomain() { domainSetupFor("hostsharing.net").notRegistered() .isRejectedWithCauseForbidden("Hostsharing domain name"); } @@ -322,6 +322,18 @@ class HsDomainSetupHostingAssetValidatorUnitTest { .isAccepted(); } + @Test + void allowSetupOfUnregisteredSubdomainIfSuperDomainParentAssetIsSpecified() { + domainSetupFor("sub.example.org").notRegistered().withParentAsset("example.org") + .isAccepted(); + } + + @Test + void rejectSetupOfUnregisteredSubdomainIfWrongParentAssetIsSpecified() { + domainSetupFor("sub.example.org").notRegistered().withParentAsset("example.net") + .isRejectedDueToInvalidIdentifier(); + } + @Test void allowSetupOfUnregisteredSubdomainWithValidDnsVerificationInSuperDomain() { domainSetupFor("sub.example.org").notRegistered().withVerificationIn("example.org") @@ -470,6 +482,12 @@ class HsDomainSetupHostingAssetValidatorUnitTest { ); } + void isRejectedDueToInvalidIdentifier() { + assertThat(validate()).contains( + "'identifier' expected to match '(\\*|(?!-)[A-Za-z0-9-]{1,63}(? Date: Thu, 12 Sep 2024 07:31:31 +0200 Subject: [PATCH 6/8] test for setup of subdomain of non-existing superdomain and improved error message for this case --- .../HsDomainSetupHostingAssetValidator.java | 14 +++++++++++--- ...HsDomainSetupHostingAssetValidatorUnitTest.java | 12 ++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidator.java b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidator.java index 9583e870..785424ad 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidator.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidator.java @@ -57,9 +57,16 @@ class HsDomainSetupHostingAssetValidator extends HostingAssetEntityValidator { if (isDnsVerificationRequiredForUnregisteredDomain(assetEntity)) { final var superDomain = superDomain(domainName); final var expectedTxtRecordValue = "Hostsharing-domain-setup-verification-code=" + getCode.get(); - final var verificationFoundInSuperDomain = superDomain.flatMap(superDomainName -> findTxtRecord( - new Dns(superDomainName).fetchRecordsOfType("TXT"), - expectedTxtRecordValue)); + final var verificationFoundInSuperDomain = superDomain.map(superDomainName -> + { + final Dns.Result superDomainDnsResult = new Dns(superDomainName).fetchRecordsOfType("TXT"); + if (superDomainDnsResult.status() != Dns.Status.SUCCESS) { + violations.add("[DNS] lookup failed for domain name '" + superDomainName + "': " + dnsResult.exception()); + } + return superDomainDnsResult; + } + ) + .flatMap(records -> findTxtRecord(records, expectedTxtRecordValue)); if (verificationFoundInSuperDomain.isEmpty()) { violations.add( "[DNS] no TXT record '" + expectedTxtRecordValue + @@ -71,6 +78,7 @@ class HsDomainSetupHostingAssetValidator extends HostingAssetEntityValidator { } case Dns.Status.INVALID_NAME: + // should not happen because we validate the domain name at booking item level violations.add("[DNS] invalid domain name '" + assetEntity.getIdentifier() + "'"); break; diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidatorUnitTest.java index 36cb2504..8acca8d9 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidatorUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidatorUnitTest.java @@ -358,6 +358,12 @@ class HsDomainSetupHostingAssetValidatorUnitTest { .isRejectedWithCauseMissingVerificationIn("example.org"); } + @Test + void rejectSetupOfUnregisteredSubdomainOfUnregisteredSuperDomain() { + domainSetupFor("sub.sub.example.org").notRegistered() + .isRejectedWithCauseDomainNameNotFound("sub.example.org"); + } + @Test void acceptSetupOfUnregisteredSubdomainWithParentAssetEvenWithoutDnsVerificationInSuperDomain() { domainSetupWithParentAssetFor("sub.example.org").notRegistered() @@ -488,6 +494,12 @@ class HsDomainSetupHostingAssetValidatorUnitTest { ); } + void isRejectedWithCauseDomainNameNotFound(final String domainName) { + assertThat(validate()).contains( + "[DNS] lookup failed for domain name '" + domainName + "': javax.naming.NameNotFoundException: domain not registered" + ); + } + void isAccepted() { assertThat(validate()).isEmpty(); } -- 2.39.5 From 667b3908fdeca23ddf46d183f81117f23fa5836d Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Thu, 12 Sep 2024 07:43:26 +0200 Subject: [PATCH 7/8] refactor DNS lookup result handling --- .../HsDomainSetupHostingAssetValidator.java | 93 +++++++++++-------- 1 file changed, 53 insertions(+), 40 deletions(-) diff --git a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidator.java b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidator.java index 785424ad..a4ad06a4 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidator.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidator.java @@ -2,9 +2,9 @@ package net.hostsharing.hsadminng.hs.hosting.asset.validators; import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAsset; +import java.util.ArrayList; import java.util.List; import java.util.Optional; -import java.util.function.Supplier; import java.util.regex.Pattern; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_SETUP; @@ -33,49 +33,15 @@ class HsDomainSetupHostingAssetValidator extends HostingAssetEntityValidator { return violations; } - final var domainName = assetEntity.getIdentifier(); - final var dnsResult = new Dns(domainName).fetchRecordsOfType("TXT"); - final Supplier getCode = () -> assetEntity.getBookingItem().getDirectValue("verificationCode", String.class); + final var dnsResult = new Dns(assetEntity.getIdentifier()).fetchRecordsOfType("TXT"); switch (dnsResult.status()) { - case Dns.Status.SUCCESS: { - final var expectedTxtRecordValue = "Hostsharing-domain-setup-verification-code=" + getCode.get(); - final var verificationFound = findTxtRecord(dnsResult, expectedTxtRecordValue) - .or(() -> superDomain(domainName) - .flatMap(superDomainName -> findTxtRecord( - new Dns(superDomainName).fetchRecordsOfType("TXT"), - expectedTxtRecordValue)) - ); - if (verificationFound.isEmpty()) { - violations.add( - "[DNS] no TXT record '" + expectedTxtRecordValue + - "' found for domain name '" + domainName + "' (nor in its super-domain)"); - } + case Dns.Status.SUCCESS: + violations.addAll(handleDomainNameFound(assetEntity, dnsResult)); break; - } - case Dns.Status.NAME_NOT_FOUND: { - if (isDnsVerificationRequiredForUnregisteredDomain(assetEntity)) { - final var superDomain = superDomain(domainName); - final var expectedTxtRecordValue = "Hostsharing-domain-setup-verification-code=" + getCode.get(); - final var verificationFoundInSuperDomain = superDomain.map(superDomainName -> - { - final Dns.Result superDomainDnsResult = new Dns(superDomainName).fetchRecordsOfType("TXT"); - if (superDomainDnsResult.status() != Dns.Status.SUCCESS) { - violations.add("[DNS] lookup failed for domain name '" + superDomainName + "': " + dnsResult.exception()); - } - return superDomainDnsResult; - } - ) - .flatMap(records -> findTxtRecord(records, expectedTxtRecordValue)); - if (verificationFoundInSuperDomain.isEmpty()) { - violations.add( - "[DNS] no TXT record '" + expectedTxtRecordValue + - "' found for domain name '" + superDomain.orElseThrow() + "'"); - } - } - // otherwise no DNS verification to be able to setup DNS for domains to register + case Dns.Status.NAME_NOT_FOUND: + violations.addAll(handleDomainNameNotFoundError(assetEntity, dnsResult)); break; - } case Dns.Status.INVALID_NAME: // should not happen because we validate the domain name at booking item level @@ -90,6 +56,10 @@ class HsDomainSetupHostingAssetValidator extends HostingAssetEntityValidator { return violations; } + private static String verificationCode(final HsHostingAsset assetEntity) { + return assetEntity.getBookingItem().getDirectValue("verificationCode", String.class); + } + @Override protected Pattern identifierPattern(final HsHostingAsset assetEntity) { if (assetEntity.getBookingItem() != null) { @@ -101,6 +71,49 @@ class HsDomainSetupHostingAssetValidator extends HostingAssetEntityValidator { return Pattern.compile(SUBDOMAIN_NAME_REGEX + "\\." + parentDomainName.replace(".", "\\."), Pattern.CASE_INSENSITIVE); } + private static List handleDomainNameFound(final HsHostingAsset assetEntity, final Dns.Result dnsResult) { + final var violations = new ArrayList(); + final var expectedTxtRecordValue = "Hostsharing-domain-setup-verification-code=" + verificationCode(assetEntity); + final var verificationFound = findTxtRecord(dnsResult, expectedTxtRecordValue) + .or(() -> superDomain(assetEntity.getIdentifier()) + .flatMap(superDomainName -> findTxtRecord( + new Dns(superDomainName).fetchRecordsOfType("TXT"), + expectedTxtRecordValue)) + ); + if (verificationFound.isEmpty()) { + violations.add( + "[DNS] no TXT record '" + expectedTxtRecordValue + + "' found for domain name '" + assetEntity.getIdentifier() + "' (nor in its super-domain)"); + } + return violations; + } + + private static List handleDomainNameNotFoundError(final HsHostingAsset assetEntity, final Dns.Result dnsResult) { + final var violations = new ArrayList(); + if (isDnsVerificationRequiredForUnregisteredDomain(assetEntity)) { + final var superDomain = superDomain(assetEntity.getIdentifier()); + final var expectedTxtRecordValue = "Hostsharing-domain-setup-verification-code=" + verificationCode(assetEntity); + final var verificationFoundInSuperDomain = superDomain.map(superDomainName -> + { + final Dns.Result superDomainDnsResult = new Dns(superDomainName).fetchRecordsOfType("TXT"); + if (superDomainDnsResult.status() != Dns.Status.SUCCESS) { + violations.add("[DNS] lookup failed for domain name '" + superDomainName + "': " + dnsResult.exception()); + } + return superDomainDnsResult; + } + ) + .flatMap(records -> findTxtRecord(records, expectedTxtRecordValue)); + if (verificationFoundInSuperDomain.isEmpty()) { + violations.add( + "[DNS] no TXT record '" + expectedTxtRecordValue + + "' found for domain name '" + superDomain.orElseThrow() + "'"); + } + } else { + // otherwise no DNS verification to be able to setup DNS for domains to register + } + return violations; + } + private static boolean isDnsVerificationRequiredForUnregisteredDomain(final HsHostingAsset assetEntity) { return !Dns.isRegistrableDomain(assetEntity.getIdentifier()) && assetEntity.getParentAsset() == null; -- 2.39.5 From f2bd1cd011158c50c93495e225503e33878dea33 Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Thu, 12 Sep 2024 10:52:16 +0200 Subject: [PATCH 8/8] fix typo --- .../validators/HsDomainSetupBookingItemValidatorUnitTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsDomainSetupBookingItemValidatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsDomainSetupBookingItemValidatorUnitTest.java index 643c5e54..60356401 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsDomainSetupBookingItemValidatorUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsDomainSetupBookingItemValidatorUnitTest.java @@ -47,7 +47,7 @@ class HsDomainSetupBookingItemValidatorUnitTest { } @Test - void acceptsRegisterableDomainWithExplicitVerifiactionCode() { + void acceptsRegisterableDomainWithExplicitVerificationCode() { // given final var domainSetupBookingItemEntity = HsBookingItemRealEntity.builder() .type(DOMAIN_SETUP) -- 2.39.5