Add bootstrap file load check, use registry URL lookup properly, getAndParse

- Clear error before returning submit
- ParsedGeneric types
This commit is contained in:
Xevion
2023-02-20 00:06:06 -06:00
parent 3c8e1ce716
commit a535c43bf8

View File

@@ -6,6 +6,7 @@ import axios from "axios";
import {AutonomousNumberSchema, DomainSchema, IpNetworkSchema, RegisterSchema, RootRegistryEnum} from "@/schema"; import {AutonomousNumberSchema, DomainSchema, IpNetworkSchema, RegisterSchema, RootRegistryEnum} from "@/schema";
import {truncated} from "@/helpers"; import {truncated} from "@/helpers";
import {ZodSchema} from "zod"; import {ZodSchema} from "zod";
import {ParsedGeneric} from "@/components/Generic";
export type WarningHandler = (warning: { message: string }) => void; export type WarningHandler = (warning: { message: string }) => void;
type BootstrapMatcher = (value: string) => boolean; type BootstrapMatcher = (value: string) => boolean;
@@ -20,7 +21,11 @@ const useLookup = (warningHandler?: WarningHandler) => {
}, [target]); }, [target]);
// Fetch & load a specific registry's data into memory. // Fetch & load a specific registry's data into memory.
async function loadBootstrap(type: RootRegistryType) { async function loadBootstrap(type: RootRegistryType, force = false) {
// Early preload exit condition
if (registryData[type] != null && !force)
return;
// Fetch the bootstrapping file from the registry // Fetch the bootstrapping file from the registry
const response = await axios.get(registryURLs[type]); const response = await axios.get(registryURLs[type]);
if (response.status != 200) if (response.status != 200)
@@ -38,32 +43,37 @@ const useLookup = (warningHandler?: WarningHandler) => {
})); }));
} }
function getURL(type: RootRegistryType, lookupTarget: string): string { function getRegistryURL(type: RootRegistryType, lookupTarget: string): string {
const bootstrap = registryData[type]; const bootstrap = registryData[type];
if (bootstrap == null) throw new Error(`Cannot acquire RDAP URL without bootstrap data for ${type} lookup.`) if (bootstrap == null) throw new Error(`Cannot acquire RDAP URL without bootstrap data for ${type} lookup.`)
let url: string | null = null;
typeSwitch:
switch (type) { switch (type) {
case "domain": case "domain":
for (const bootstrapItem of bootstrap.services) { for (const bootstrapItem of bootstrap.services) {
if (bootstrapItem[0].some(domainMatchPredicate)) if (bootstrapItem[0].some(domainMatchPredicate(lookupTarget))) {
return getBestURL(bootstrapItem[1]); url = getBestURL(bootstrapItem[1]);
break typeSwitch;
}
} }
throw new Error(`No matching domain found.`) throw new Error(`No matching domain found.`)
case "ip4": case "ip4":
throw new Error(`No matching ip4 found.`) throw new Error(`No matching ip4 found.`)
break;
case "ip6": case "ip6":
throw new Error(`No matching ip6 found.`) throw new Error(`No matching ip6 found.`)
break;
case "entity": case "entity":
throw new Error(`No matching entity found.`) throw new Error(`No matching entity found.`)
break;
case "autnum": case "autnum":
throw new Error(`No matching autnum found.`) throw new Error(`No matching autnum found.`)
break;
default: default:
throw new Error("") throw new Error("Invalid lookup target provided.")
} }
if (url == null) throw new Error('No lookup target was resolved.')
return `${url}${type}/${lookupTarget}`;
} }
useEffect(() => { useEffect(() => {
@@ -95,7 +105,7 @@ const useLookup = (warningHandler?: WarningHandler) => {
return schema.parse(response.data) as T return schema.parse(response.data) as T
} }
async function submitInternal() { async function submitInternal(): Promise<ParsedGeneric | undefined> {
if (target == null) if (target == null)
throw new Error("A target must be given in order to execute a lookup.") throw new Error("A target must be given in order to execute a lookup.")
@@ -105,23 +115,23 @@ const useLookup = (warningHandler?: WarningHandler) => {
// Block scoped case to allow url const reuse // Block scoped case to allow url const reuse
case "ip4": { case "ip4": {
await loadBootstrap("ip4"); await loadBootstrap("ip4");
const url = getURL(targetType, target); const url = getRegistryURL(targetType, target);
return getAndParse<IpNetwork>(url, IpNetworkSchema) return await getAndParse<IpNetwork>(url, IpNetworkSchema)
} }
case "ip6": { case "ip6": {
await loadBootstrap("ip6"); await loadBootstrap("ip6");
const url = getURL(targetType, target); const url = getRegistryURL(targetType, target);
return getAndParse<IpNetwork>(url, IpNetworkSchema); return await getAndParse<IpNetwork>(url, IpNetworkSchema);
} }
case "domain": { case "domain": {
await loadBootstrap("domain"); await loadBootstrap("domain");
const url = getURL(targetType, target); const url = getRegistryURL(targetType, target);
return getAndParse<Domain>(url, DomainSchema); return await getAndParse<Domain>(url, DomainSchema);
} }
case "autnum": { case "autnum": {
await loadBootstrap("autnum"); await loadBootstrap("autnum");
const url = getURL(targetType, target); const url = getRegistryURL(targetType, target);
return getAndParse<AutonomousNumber>(url, AutonomousNumberSchema); return await getAndParse<AutonomousNumber>(url, AutonomousNumberSchema);
} }
case null: case null:
throw new Error("The type could not be detected given the target.") throw new Error("The type could not be detected given the target.")
@@ -134,13 +144,18 @@ const useLookup = (warningHandler?: WarningHandler) => {
} }
} }
async function submit() { async function submit(): Promise<ParsedGeneric | undefined> {
try { try {
const data = await submitInternal(); const response = await submitInternal();
if (response == undefined)
throw new Error("Internal submission failed to yield any data.")
setError(null);
return response;
} catch (e) { } catch (e) {
if (!(e instanceof Error)) if (!(e instanceof Error))
return setError("An unknown, unprocessable error has occurred."); setError("An unknown, unprocessable error has occurred.");
return setError(e.message); setError((e as Error).message);
} }
} }