user-definable verificationCode and more business-level-validation-tests #100

Merged
hsh-michaelhoennig merged 8 commits from user-definable-verificationCode-and-bi-validation-tests into master 2024-09-12 10:52:45 +02:00
Showing only changes of commit 667b3908fd - Show all commits

View File

@ -2,9 +2,9 @@ package net.hostsharing.hsadminng.hs.hosting.asset.validators;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAsset; import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAsset;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.function.Supplier;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_SETUP; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_SETUP;
@ -33,14 +33,49 @@ class HsDomainSetupHostingAssetValidator extends HostingAssetEntityValidator {
return violations; return violations;
} }
final var domainName = assetEntity.getIdentifier(); final var dnsResult = new Dns(assetEntity.getIdentifier()).fetchRecordsOfType("TXT");
final var dnsResult = new Dns(domainName).fetchRecordsOfType("TXT");
final Supplier<String> getCode = () -> assetEntity.getBookingItem().getDirectValue("verificationCode", String.class);
switch (dnsResult.status()) { switch (dnsResult.status()) {
case Dns.Status.SUCCESS: { case Dns.Status.SUCCESS:
final var expectedTxtRecordValue = "Hostsharing-domain-setup-verification-code=" + getCode.get(); violations.addAll(handleDomainNameFound(assetEntity, dnsResult));
break;
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
violations.add("[DNS] invalid domain name '" + assetEntity.getIdentifier() + "'");
break;
case Dns.Status.SERVICE_UNAVAILABLE:
case Dns.Status.UNKNOWN_FAILURE:
violations.add("[DNS] lookup failed for domain name '" + assetEntity.getIdentifier() + "': " + dnsResult.exception());
break;
}
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) {
final var bookingItemDomainName = assetEntity.getBookingItem()
.getDirectValue(DOMAIN_NAME_PROPERTY_NAME, String.class);
return Pattern.compile(bookingItemDomainName, Pattern.CASE_INSENSITIVE | Pattern.LITERAL);
}
final var parentDomainName = assetEntity.getParentAsset().getIdentifier();
return Pattern.compile(SUBDOMAIN_NAME_REGEX + "\\." + parentDomainName.replace(".", "\\."), Pattern.CASE_INSENSITIVE);
}
private static List<String> handleDomainNameFound(final HsHostingAsset assetEntity, final Dns.Result dnsResult) {
final var violations = new ArrayList<String>();
final var expectedTxtRecordValue = "Hostsharing-domain-setup-verification-code=" + verificationCode(assetEntity);
final var verificationFound = findTxtRecord(dnsResult, expectedTxtRecordValue) final var verificationFound = findTxtRecord(dnsResult, expectedTxtRecordValue)
.or(() -> superDomain(domainName) .or(() -> superDomain(assetEntity.getIdentifier())
.flatMap(superDomainName -> findTxtRecord( .flatMap(superDomainName -> findTxtRecord(
new Dns(superDomainName).fetchRecordsOfType("TXT"), new Dns(superDomainName).fetchRecordsOfType("TXT"),
expectedTxtRecordValue)) expectedTxtRecordValue))
@ -48,15 +83,16 @@ class HsDomainSetupHostingAssetValidator extends HostingAssetEntityValidator {
if (verificationFound.isEmpty()) { if (verificationFound.isEmpty()) {
violations.add( violations.add(
"[DNS] no TXT record '" + expectedTxtRecordValue + "[DNS] no TXT record '" + expectedTxtRecordValue +
"' found for domain name '" + domainName + "' (nor in its super-domain)"); "' found for domain name '" + assetEntity.getIdentifier() + "' (nor in its super-domain)");
} }
break; return violations;
} }
case Dns.Status.NAME_NOT_FOUND: { private static List<String> handleDomainNameNotFoundError(final HsHostingAsset assetEntity, final Dns.Result dnsResult) {
final var violations = new ArrayList<String>();
if (isDnsVerificationRequiredForUnregisteredDomain(assetEntity)) { if (isDnsVerificationRequiredForUnregisteredDomain(assetEntity)) {
final var superDomain = superDomain(domainName); final var superDomain = superDomain(assetEntity.getIdentifier());
final var expectedTxtRecordValue = "Hostsharing-domain-setup-verification-code=" + getCode.get(); final var expectedTxtRecordValue = "Hostsharing-domain-setup-verification-code=" + verificationCode(assetEntity);
final var verificationFoundInSuperDomain = superDomain.map(superDomainName -> final var verificationFoundInSuperDomain = superDomain.map(superDomainName ->
{ {
final Dns.Result superDomainDnsResult = new Dns(superDomainName).fetchRecordsOfType("TXT"); final Dns.Result superDomainDnsResult = new Dns(superDomainName).fetchRecordsOfType("TXT");
@ -72,35 +108,12 @@ class HsDomainSetupHostingAssetValidator extends HostingAssetEntityValidator {
"[DNS] no TXT record '" + expectedTxtRecordValue + "[DNS] no TXT record '" + expectedTxtRecordValue +
"' found for domain name '" + superDomain.orElseThrow() + "'"); "' found for domain name '" + superDomain.orElseThrow() + "'");
} }
} } else {
// otherwise no DNS verification to be able to setup DNS for domains to register // otherwise no DNS verification to be able to setup DNS for domains to register
break;
}
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;
case Dns.Status.SERVICE_UNAVAILABLE:
case Dns.Status.UNKNOWN_FAILURE:
violations.add("[DNS] lookup failed for domain name '" + assetEntity.getIdentifier() + "': " + dnsResult.exception());
break;
} }
return violations; return violations;
} }
@Override
protected Pattern identifierPattern(final HsHostingAsset assetEntity) {
if (assetEntity.getBookingItem() != null) {
final var bookingItemDomainName = assetEntity.getBookingItem()
.getDirectValue(DOMAIN_NAME_PROPERTY_NAME, String.class);
return Pattern.compile(bookingItemDomainName, Pattern.CASE_INSENSITIVE | Pattern.LITERAL);
}
final var parentDomainName = assetEntity.getParentAsset().getIdentifier();
return Pattern.compile(SUBDOMAIN_NAME_REGEX + "\\." + parentDomainName.replace(".", "\\."), Pattern.CASE_INSENSITIVE);
}
private static boolean isDnsVerificationRequiredForUnregisteredDomain(final HsHostingAsset assetEntity) { private static boolean isDnsVerificationRequiredForUnregisteredDomain(final HsHostingAsset assetEntity) {
return !Dns.isRegistrableDomain(assetEntity.getIdentifier()) return !Dns.isRegistrableDomain(assetEntity.getIdentifier())
&& assetEntity.getParentAsset() == null; && assetEntity.getParentAsset() == null;