wizard: block Next if external service cannot be verified
Unit Tests / test (push) Successful in 15m44s

For pic_ngo: name must be confirmed available (not just format-valid).
For cloudflare/duckdns: token is auto-verified on Next if not already
done — invalid or unreachable service blocks proceeding. Only lan and
http01 (no external dependency) allow Next without a live check.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-26 08:09:06 -04:00
parent 99dcb1332a
commit 55d36eb410
+28 -7
View File
@@ -301,16 +301,20 @@ function Step2Domain({
setCfStatus('checking');
try {
const res = await setupAPI.validate('cloudflare_token', { token: cloudflareToken });
setCfStatus(res.data?.valid ? 'valid' : 'invalid');
} catch { setCfStatus('invalid'); }
const result = res.data?.valid ? 'valid' : 'invalid';
setCfStatus(result);
return result;
} catch { setCfStatus('invalid'); return 'invalid'; }
};
const verifyDns = async () => {
setDnsStatus('checking');
try {
const res = await setupAPI.validate('duckdns_token', { subdomain: duckSub, token: duckdnsToken });
setDnsStatus(res.data?.valid ? 'valid' : 'invalid');
} catch { setDnsStatus('invalid'); }
const result = res.data?.valid ? 'valid' : 'invalid';
setDnsStatus(result);
return result;
} catch { setDnsStatus('invalid'); return 'invalid'; }
};
const handleNext = async () => {
@@ -324,14 +328,31 @@ function Step2Domain({
setNextLoading(true);
const result = await checkPicAvail(picName);
setNextLoading(false);
if (result === 'taken') e.name = 'This subdomain is already taken. Choose another.';
if (result === 'taken')
e.name = 'This subdomain is already taken. Choose another.';
else if (result !== 'available')
e.name = 'Could not reach the DDNS service. Check your connection or choose a different domain option.';
}
} else if (domainType === 'cloudflare') {
if (!customDomain || !DOMAIN_RE.test(customDomain)) e.domain = 'Enter a valid domain (e.g. home.example.com).';
if (!cloudflareToken.trim()) e.token = 'Cloudflare API token is required.';
if (!cloudflareToken.trim()) {
e.token = 'Cloudflare API token is required.';
} else if (cfStatus !== 'valid') {
setNextLoading(true);
const result = await verifyCf();
setNextLoading(false);
if (result !== 'valid') e.token = 'Cloudflare token is invalid or could not be verified.';
}
} else if (domainType === 'duckdns') {
if (!duckSub) e.name = 'DuckDNS subdomain is required.';
if (!duckdnsToken.trim()) e.token = 'DuckDNS token is required.';
if (!duckdnsToken.trim()) {
e.token = 'DuckDNS token is required.';
} else if (dnsStatus !== 'valid') {
setNextLoading(true);
const result = await verifyDns();
setNextLoading(false);
if (result !== 'valid') e.token = 'DuckDNS token is invalid or could not be verified.';
}
} else if (domainType === 'http01') {
if (!customDomain || !DOMAIN_RE.test(customDomain)) e.domain = 'Enter a valid domain (e.g. home.example.com).';
}