refactor DNS lookup result handling

This commit is contained in:
Michael Hoennig 2024-09-12 07:43:26 +02:00
parent 4f49793817
commit 667b3908fd

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,49 +33,15 @@ 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));
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)");
}
break; break;
}
case Dns.Status.NAME_NOT_FOUND: { case Dns.Status.NAME_NOT_FOUND:
if (isDnsVerificationRequiredForUnregisteredDomain(assetEntity)) { violations.addAll(handleDomainNameNotFoundError(assetEntity, dnsResult));
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
break; break;
}
case Dns.Status.INVALID_NAME: case Dns.Status.INVALID_NAME:
// should not happen because we validate the domain name at booking item level // should not happen because we validate the domain name at booking item level
@ -90,6 +56,10 @@ class HsDomainSetupHostingAssetValidator extends HostingAssetEntityValidator {
return violations; return violations;
} }
private static String verificationCode(final HsHostingAsset assetEntity) {
return assetEntity.getBookingItem().getDirectValue("verificationCode", String.class);
}
@Override @Override
protected Pattern identifierPattern(final HsHostingAsset assetEntity) { protected Pattern identifierPattern(final HsHostingAsset assetEntity) {
if (assetEntity.getBookingItem() != null) { if (assetEntity.getBookingItem() != null) {
@ -101,6 +71,49 @@ class HsDomainSetupHostingAssetValidator extends HostingAssetEntityValidator {
return Pattern.compile(SUBDOMAIN_NAME_REGEX + "\\." + parentDomainName.replace(".", "\\."), Pattern.CASE_INSENSITIVE); 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)
.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<String> handleDomainNameNotFoundError(final HsHostingAsset assetEntity, final Dns.Result dnsResult) {
final var violations = new ArrayList<String>();
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) { private static boolean isDnsVerificationRequiredForUnregisteredDomain(final HsHostingAsset assetEntity) {
return !Dns.isRegistrableDomain(assetEntity.getIdentifier()) return !Dns.isRegistrableDomain(assetEntity.getIdentifier())
&& assetEntity.getParentAsset() == null; && assetEntity.getParentAsset() == null;