mirror of
https://github.com/getnamingo/registry.git
synced 2025-08-16 06:13:47 +02:00
Updates to RDAP structure
This commit is contained in:
parent
db00aaffeb
commit
2847d04942
3 changed files with 145 additions and 70 deletions
|
@ -92,25 +92,18 @@ function mapContactToVCard($contactDetails, $role, $c) {
|
||||||
'remarks' => [
|
'remarks' => [
|
||||||
[
|
[
|
||||||
"description" => [
|
"description" => [
|
||||||
"This object's data has been partially omitted for privacy.",
|
"REDACTED FOR PRIVACY",
|
||||||
"Only the registrar managing the record can view personal contact data."
|
"Visit www.icann.org/privacy for details."
|
||||||
],
|
|
||||||
"links" => [
|
|
||||||
[
|
|
||||||
"href" => "https://namingo.org",
|
|
||||||
"rel" => "alternate",
|
|
||||||
"type" => "text/html"
|
|
||||||
]
|
|
||||||
],
|
],
|
||||||
"title" => "REDACTED FOR PRIVACY",
|
"title" => "REDACTED FOR PRIVACY",
|
||||||
"type" => "Details are withheld due to privacy restrictions."
|
"type" => "object redacted due to authorization"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"description" => [
|
"description" => [
|
||||||
"To obtain contact information for the domain registrant, please refer to the Registrar of Record's RDDS service as indicated in this report."
|
"To obtain contact information for the domain registrant, please refer to the Registrar of Record's RDDS service as indicated in this report."
|
||||||
],
|
],
|
||||||
"title" => "EMAIL REDACTED FOR PRIVACY",
|
"title" => "EMAIL REDACTED FOR PRIVACY",
|
||||||
"type" => "Details are withheld due to privacy restrictions."
|
"type" => "object truncated due to authorization"
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'vcardArray' => [
|
'vcardArray' => [
|
||||||
|
@ -119,7 +112,7 @@ function mapContactToVCard($contactDetails, $role, $c) {
|
||||||
['version', new stdClass(), 'text', '4.0'],
|
['version', new stdClass(), 'text', '4.0'],
|
||||||
["fn", new stdClass(), 'text', $disclose_name ? $contactDetails['name'] : "REDACTED FOR PRIVACY"],
|
["fn", new stdClass(), 'text', $disclose_name ? $contactDetails['name'] : "REDACTED FOR PRIVACY"],
|
||||||
["org", new stdClass(), 'text', $disclose_org ? $contactDetails['org'] : "REDACTED FOR PRIVACY"],
|
["org", new stdClass(), 'text', $disclose_org ? $contactDetails['org'] : "REDACTED FOR PRIVACY"],
|
||||||
["adr", ["CC" => strtoupper($contactDetails['cc'])], 'text', [ // specify "CC" parameter for country code
|
["adr", ["cc" => strtoupper($contactDetails['cc'])], 'text', [ // specify "cc" parameter for country code
|
||||||
$disclose_addr ? $contactDetails['street1'] : "REDACTED FOR PRIVACY", // Extended address
|
$disclose_addr ? $contactDetails['street1'] : "REDACTED FOR PRIVACY", // Extended address
|
||||||
$disclose_addr ? $contactDetails['street2'] : "REDACTED FOR PRIVACY", // Street address
|
$disclose_addr ? $contactDetails['street2'] : "REDACTED FOR PRIVACY", // Street address
|
||||||
$disclose_addr ? $contactDetails['street3'] : "REDACTED FOR PRIVACY", // Additional street address
|
$disclose_addr ? $contactDetails['street3'] : "REDACTED FOR PRIVACY", // Additional street address
|
||||||
|
@ -128,8 +121,8 @@ function mapContactToVCard($contactDetails, $role, $c) {
|
||||||
$disclose_addr ? $contactDetails['pc'] : "REDACTED FOR PRIVACY", // Postal code
|
$disclose_addr ? $contactDetails['pc'] : "REDACTED FOR PRIVACY", // Postal code
|
||||||
"" // Add empty last element as required for ADR structure
|
"" // Add empty last element as required for ADR structure
|
||||||
]],
|
]],
|
||||||
["tel", ["type" => "voice"], 'uri', $disclose_voice ? "tel:" . $contactDetails['voice'] : "REDACTED FOR PRIVACY"],
|
["tel", ["type" => "voice"], $disclose_voice ? 'uri' : 'text', $disclose_voice ? "tel:" . $contactDetails['voice'] : "REDACTED FOR PRIVACY"],
|
||||||
["tel", ["type" => "fax"], 'uri', $disclose_fax ? "tel:" . $contactDetails['fax'] : "REDACTED FOR PRIVACY"],
|
["tel", ["type" => "fax"], $disclose_fax ? 'uri' : 'text', $disclose_fax ? "tel:" . $contactDetails['fax'] : "REDACTED FOR PRIVACY"],
|
||||||
["email", new stdClass(), 'text', $disclose_email ? $contactDetails['email'] : "REDACTED FOR PRIVACY"],
|
["email", new stdClass(), 'text', $disclose_email ? $contactDetails['email'] : "REDACTED FOR PRIVACY"],
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
@ -194,3 +187,43 @@ function mapStatuses(array $statuses): array {
|
||||||
return $statusMap[$status] ?? $status; // Return mapped value or original if not found
|
return $statusMap[$status] ?? $status; // Return mapped value or original if not found
|
||||||
}, $statuses);
|
}, $statuses);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isValidHostname($hostname) {
|
||||||
|
$hostname = trim($hostname);
|
||||||
|
|
||||||
|
// Convert IDN (Unicode) to ASCII if necessary
|
||||||
|
if (mb_detect_encoding($hostname, 'ASCII', true) === false) {
|
||||||
|
$hostname = idn_to_ascii($hostname, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46);
|
||||||
|
if ($hostname === false) {
|
||||||
|
return false; // Invalid IDN conversion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure there is at least **one dot** (to prevent single-segment hostnames)
|
||||||
|
if (substr_count($hostname, '.') < 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regular expression for validating a hostname
|
||||||
|
$pattern = '/^((xn--[a-zA-Z0-9-]{1,63}|[a-zA-Z0-9-]{1,63})\.)*([a-zA-Z0-9-]{1,63}|xn--[a-zA-Z0-9-]{2,63})$/';
|
||||||
|
|
||||||
|
// Ensure it matches the hostname pattern
|
||||||
|
if (!preg_match($pattern, $hostname)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure no label exceeds 63 characters
|
||||||
|
$labels = explode('.', $hostname);
|
||||||
|
foreach ($labels as $label) {
|
||||||
|
if (strlen($label) > 63) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure full hostname is not longer than 255 characters
|
||||||
|
if (strlen($hostname) > 255) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -514,12 +514,15 @@ function handleDomainQuery($request, $response, $pdo, $domainName, $c, $log) {
|
||||||
}
|
}
|
||||||
|
|
||||||
$abuseContactName = ($registrarAbuseDetails) ? $registrarAbuseDetails['first_name'] . ' ' . $registrarAbuseDetails['last_name'] : '';
|
$abuseContactName = ($registrarAbuseDetails) ? $registrarAbuseDetails['first_name'] . ' ' . $registrarAbuseDetails['last_name'] : '';
|
||||||
|
$rdapClean = rtrim(preg_replace('#^.*?//#', '', $registrarDetails['rdap_server'] ?? ''), '/');
|
||||||
|
|
||||||
// Construct the RDAP response in JSON format
|
// Construct the RDAP response in JSON format
|
||||||
$rdapResponse = [
|
$rdapResponse = [
|
||||||
'rdapConformance' => [
|
'rdapConformance' => [
|
||||||
'rdap_level_0',
|
'rdap_level_0',
|
||||||
|
'icann_rdap_response_profile_0',
|
||||||
'icann_rdap_response_profile_1',
|
'icann_rdap_response_profile_1',
|
||||||
|
'icann_rdap_technical_implementation_guide_0',
|
||||||
'icann_rdap_technical_implementation_guide_1',
|
'icann_rdap_technical_implementation_guide_1',
|
||||||
],
|
],
|
||||||
'objectClassName' => 'domain',
|
'objectClassName' => 'domain',
|
||||||
|
@ -601,8 +604,8 @@ function handleDomainQuery($request, $response, $pdo, $domainName, $c, $log) {
|
||||||
'type' => 'application/rdap+json',
|
'type' => 'application/rdap+json',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'href' => $registrarDetails['rdap_server'] . 'domain/' . $domain,
|
'href' => 'https://' . $rdapClean . '/domain/' . $domain,
|
||||||
'value' => $registrarDetails['rdap_server'] . 'domain/' . $domain,
|
'value' => 'https://' . $rdapClean . '/domain/' . $domain,
|
||||||
'rel' => 'related',
|
'rel' => 'related',
|
||||||
'type' => 'application/rdap+json',
|
'type' => 'application/rdap+json',
|
||||||
]
|
]
|
||||||
|
@ -918,7 +921,7 @@ function handleEntityQuery($request, $response, $pdo, $entityHandle, $c, $log) {
|
||||||
// Initialize an array to hold entity blocks
|
// Initialize an array to hold entity blocks
|
||||||
$entityBlocks = [];
|
$entityBlocks = [];
|
||||||
// Define an array of allowed contact types
|
// Define an array of allowed contact types
|
||||||
$allowedTypes = ['owner', 'tech', 'abuse'];
|
$allowedTypes = ['owner', 'billing', 'abuse'];
|
||||||
|
|
||||||
foreach ($contacts as $contact) {
|
foreach ($contacts as $contact) {
|
||||||
// Check if the contact type is one of the allowed types
|
// Check if the contact type is one of the allowed types
|
||||||
|
@ -929,14 +932,14 @@ function handleEntityQuery($request, $response, $pdo, $entityHandle, $c, $log) {
|
||||||
// Create an entity block for each allowed contact type
|
// Create an entity block for each allowed contact type
|
||||||
$entityBlock = [
|
$entityBlock = [
|
||||||
'objectClassName' => 'entity',
|
'objectClassName' => 'entity',
|
||||||
'roles' => [$contact['type']],
|
'roles' => [($contact['type'] === 'owner') ? 'administrative' : $contact['type']],
|
||||||
"status" => ["active"],
|
"status" => ["active"],
|
||||||
"vcardArray" => [
|
"vcardArray" => [
|
||||||
"vcard",
|
"vcard",
|
||||||
[
|
[
|
||||||
['version', new stdClass(), 'text', '4.0'],
|
['version', new stdClass(), 'text', '4.0'],
|
||||||
["fn", new stdClass(), "text", $fullName],
|
["fn", new stdClass(), "text", $fullName],
|
||||||
["tel", ["type" => ["voice"]], "uri", "tel:" . $contact['voice']],
|
["tel", ["type" => ["voice"]], $contact['voice'] ? "uri" : "text", $contact['voice'] ? "tel:" . $contact['voice'] : ""],
|
||||||
["email", new stdClass(), "text", $contact['email']]
|
["email", new stdClass(), "text", $contact['email']]
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
@ -951,7 +954,9 @@ function handleEntityQuery($request, $response, $pdo, $entityHandle, $c, $log) {
|
||||||
$rdapResponse = [
|
$rdapResponse = [
|
||||||
'rdapConformance' => [
|
'rdapConformance' => [
|
||||||
'rdap_level_0',
|
'rdap_level_0',
|
||||||
|
'icann_rdap_response_profile_0',
|
||||||
'icann_rdap_response_profile_1',
|
'icann_rdap_response_profile_1',
|
||||||
|
'icann_rdap_technical_implementation_guide_0',
|
||||||
'icann_rdap_technical_implementation_guide_1',
|
'icann_rdap_technical_implementation_guide_1',
|
||||||
],
|
],
|
||||||
'objectClassName' => 'entity',
|
'objectClassName' => 'entity',
|
||||||
|
@ -1129,11 +1134,11 @@ function handleNameserverQuery($request, $response, $pdo, $nameserverHandle, $c,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for prohibited patterns in nameserver
|
// Validate nameserver
|
||||||
if (!preg_match('/^((xn--[a-zA-Z0-9-]{1,63}|[a-zA-Z0-9-]{1,63})\.){2,}(xn--[a-zA-Z0-9-]{2,63}|[a-zA-Z]{2,63})$/', $ns)) {
|
if (!isValidHostname($ns)) {
|
||||||
$response->header('Content-Type', 'application/json');
|
$response->header('Content-Type', 'application/json');
|
||||||
$response->status(400); // Bad Request
|
$response->status(400); // Bad Request
|
||||||
$response->end(json_encode(['error' => 'Nameserver invalid format']));
|
$response->end(json_encode(['error' => 'Nameserver format is invalid. Expected a fully qualified domain name (FQDN), punycode supported (e.g., ns1.example.com)']));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1298,12 +1303,15 @@ function handleNameserverQuery($request, $response, $pdo, $nameserverHandle, $c,
|
||||||
if (!empty($associated)) {
|
if (!empty($associated)) {
|
||||||
$statuses[] = 'associated';
|
$statuses[] = 'associated';
|
||||||
}
|
}
|
||||||
|
$statuses = array_unique(array_map(fn($s) => $s === 'ok' ? 'active' : $s, $statuses));
|
||||||
|
|
||||||
// Construct the RDAP response in JSON format
|
// Construct the RDAP response in JSON format
|
||||||
$rdapResponse = [
|
$rdapResponse = [
|
||||||
'rdapConformance' => [
|
'rdapConformance' => [
|
||||||
'rdap_level_0',
|
'rdap_level_0',
|
||||||
|
'icann_rdap_response_profile_0',
|
||||||
'icann_rdap_response_profile_1',
|
'icann_rdap_response_profile_1',
|
||||||
|
'icann_rdap_technical_implementation_guide_0',
|
||||||
'icann_rdap_technical_implementation_guide_1',
|
'icann_rdap_technical_implementation_guide_1',
|
||||||
],
|
],
|
||||||
'objectClassName' => 'nameserver',
|
'objectClassName' => 'nameserver',
|
||||||
|
@ -1366,8 +1374,9 @@ function handleNameserverQuery($request, $response, $pdo, $nameserverHandle, $c,
|
||||||
'ldhName' => $hostDetails['name'],
|
'ldhName' => $hostDetails['name'],
|
||||||
'links' => [
|
'links' => [
|
||||||
[
|
[
|
||||||
'href' => $c['rdap_url'] . '/nameserver/' . $hostDetails['name'],
|
'value' => $c['rdap_url'] . '/nameserver/' . $hostDetails['name'],
|
||||||
'rel' => 'self',
|
'rel' => 'self',
|
||||||
|
'href' => $c['rdap_url'] . '/nameserver/' . $hostDetails['name'],
|
||||||
'type' => 'application/rdap+json',
|
'type' => 'application/rdap+json',
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
@ -1855,7 +1864,9 @@ function handleDomainSearchQuery($request, $response, $pdo, $searchPattern, $c,
|
||||||
$rdapResponse = [
|
$rdapResponse = [
|
||||||
'rdapConformance' => [
|
'rdapConformance' => [
|
||||||
'rdap_level_0',
|
'rdap_level_0',
|
||||||
|
'icann_rdap_response_profile_0',
|
||||||
'icann_rdap_response_profile_1',
|
'icann_rdap_response_profile_1',
|
||||||
|
'icann_rdap_technical_implementation_guide_0',
|
||||||
'icann_rdap_technical_implementation_guide_1',
|
'icann_rdap_technical_implementation_guide_1',
|
||||||
],
|
],
|
||||||
'domainSearchResults' => [
|
'domainSearchResults' => [
|
||||||
|
@ -2117,11 +2128,11 @@ function handleNameserverSearchQuery($request, $response, $pdo, $searchPattern,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for prohibited patterns in nameserver
|
// Validate nameserver
|
||||||
if (!preg_match('/^((xn--[a-zA-Z0-9-]{1,63}|[a-zA-Z0-9-]{1,63})\.){2,}(xn--[a-zA-Z0-9-]{2,63}|[a-zA-Z]{2,63})$/', $ns)) {
|
if (!isValidHostname($ns)) {
|
||||||
$response->header('Content-Type', 'application/json');
|
$response->header('Content-Type', 'application/json');
|
||||||
$response->status(400); // Bad Request
|
$response->status(400); // Bad Request
|
||||||
$response->end(json_encode(['error' => 'Nameserver invalid format']));
|
$response->end(json_encode(['error' => 'Nameserver format is invalid. Expected a fully qualified domain name (FQDN), punycode supported (e.g., ns1.example.com)']));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2339,7 +2350,9 @@ function handleNameserverSearchQuery($request, $response, $pdo, $searchPattern,
|
||||||
$rdapResponse = [
|
$rdapResponse = [
|
||||||
'rdapConformance' => [
|
'rdapConformance' => [
|
||||||
'rdap_level_0',
|
'rdap_level_0',
|
||||||
|
'icann_rdap_response_profile_0',
|
||||||
'icann_rdap_response_profile_1',
|
'icann_rdap_response_profile_1',
|
||||||
|
'icann_rdap_technical_implementation_guide_0',
|
||||||
'icann_rdap_technical_implementation_guide_1',
|
'icann_rdap_technical_implementation_guide_1',
|
||||||
],
|
],
|
||||||
'nameserverSearchResults' => $rdapResult,
|
'nameserverSearchResults' => $rdapResult,
|
||||||
|
@ -2466,7 +2479,9 @@ function handleNameserverSearchQuery($request, $response, $pdo, $searchPattern,
|
||||||
$rdapResponse = [
|
$rdapResponse = [
|
||||||
'rdapConformance' => [
|
'rdapConformance' => [
|
||||||
'rdap_level_0',
|
'rdap_level_0',
|
||||||
|
'icann_rdap_response_profile_0',
|
||||||
'icann_rdap_response_profile_1',
|
'icann_rdap_response_profile_1',
|
||||||
|
'icann_rdap_technical_implementation_guide_0',
|
||||||
'icann_rdap_technical_implementation_guide_1',
|
'icann_rdap_technical_implementation_guide_1',
|
||||||
],
|
],
|
||||||
'nameserverSearchResults' => [
|
'nameserverSearchResults' => [
|
||||||
|
@ -2815,7 +2830,7 @@ function handleEntitySearchQuery($request, $response, $pdo, $searchPattern, $c,
|
||||||
// Initialize an array to hold entity blocks
|
// Initialize an array to hold entity blocks
|
||||||
$entityBlocks = [];
|
$entityBlocks = [];
|
||||||
// Define an array of allowed contact types
|
// Define an array of allowed contact types
|
||||||
$allowedTypes = ['owner', 'tech', 'abuse'];
|
$allowedTypes = ['owner', 'billing', 'abuse'];
|
||||||
|
|
||||||
foreach ($contacts as $contact) {
|
foreach ($contacts as $contact) {
|
||||||
// Check if the contact type is one of the allowed types
|
// Check if the contact type is one of the allowed types
|
||||||
|
@ -2826,14 +2841,14 @@ function handleEntitySearchQuery($request, $response, $pdo, $searchPattern, $c,
|
||||||
// Create an entity block for each allowed contact type
|
// Create an entity block for each allowed contact type
|
||||||
$entityBlock = [
|
$entityBlock = [
|
||||||
'objectClassName' => 'entity',
|
'objectClassName' => 'entity',
|
||||||
'roles' => [$contact['type']],
|
'roles' => [($contact['type'] === 'owner') ? 'administrative' : $contact['type']],
|
||||||
"status" => ["active"],
|
"status" => ["active"],
|
||||||
"vcardArray" => [
|
"vcardArray" => [
|
||||||
"vcard",
|
"vcard",
|
||||||
[
|
[
|
||||||
['version', new stdClass(), 'text', '4.0'],
|
['version', new stdClass(), 'text', '4.0'],
|
||||||
["fn", new stdClass(), "text", $fullName],
|
["fn", new stdClass(), "text", $fullName],
|
||||||
["tel", ["type" => ["voice"]], "uri", "tel:" . $contact['voice']],
|
["tel", ["type" => ["voice"]], $contact['voice'] ? "uri" : "text", $contact['voice'] ? "tel:" . $contact['voice'] : ""],
|
||||||
["email", new stdClass(), "text", $contact['email']]
|
["email", new stdClass(), "text", $contact['email']]
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
@ -2848,7 +2863,9 @@ function handleEntitySearchQuery($request, $response, $pdo, $searchPattern, $c,
|
||||||
$rdapResponse = [
|
$rdapResponse = [
|
||||||
'rdapConformance' => [
|
'rdapConformance' => [
|
||||||
'rdap_level_0',
|
'rdap_level_0',
|
||||||
|
'icann_rdap_response_profile_0',
|
||||||
'icann_rdap_response_profile_1',
|
'icann_rdap_response_profile_1',
|
||||||
|
'icann_rdap_technical_implementation_guide_0',
|
||||||
'icann_rdap_technical_implementation_guide_1',
|
'icann_rdap_technical_implementation_guide_1',
|
||||||
],
|
],
|
||||||
'entitySearchResults' => [
|
'entitySearchResults' => [
|
||||||
|
@ -2993,9 +3010,11 @@ function handleEntitySearchQuery($request, $response, $pdo, $searchPattern, $c,
|
||||||
function handleHelpQuery($request, $response, $pdo, $c) {
|
function handleHelpQuery($request, $response, $pdo, $c) {
|
||||||
// Set the RDAP conformance levels
|
// Set the RDAP conformance levels
|
||||||
$rdapConformance = [
|
$rdapConformance = [
|
||||||
"rdap_level_0",
|
'rdap_level_0',
|
||||||
"icann_rdap_response_profile_1",
|
'icann_rdap_response_profile_0',
|
||||||
"icann_rdap_technical_implementation_guide_1"
|
'icann_rdap_response_profile_1',
|
||||||
|
'icann_rdap_technical_implementation_guide_0',
|
||||||
|
'icann_rdap_technical_implementation_guide_1',
|
||||||
];
|
];
|
||||||
|
|
||||||
// Set the descriptions and links for the help section
|
// Set the descriptions and links for the help section
|
||||||
|
@ -3015,13 +3034,15 @@ function handleHelpQuery($request, $response, $pdo, $c) {
|
||||||
],
|
],
|
||||||
'links' => [
|
'links' => [
|
||||||
[
|
[
|
||||||
'href' => $c['rdap_url'] . '/help',
|
'value' => $c['rdap_url'] . '/help',
|
||||||
'rel' => 'self',
|
'rel' => 'self',
|
||||||
|
'href' => $c['rdap_url'] . '/help',
|
||||||
'type' => 'application/rdap+json',
|
'type' => 'application/rdap+json',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'href' => 'https://namingo.org',
|
'value' => 'https://namingo.org',
|
||||||
'rel' => 'related',
|
'rel' => 'related',
|
||||||
|
'href' => 'https://namingo.org',
|
||||||
'type' => 'application/rdap+json',
|
'type' => 'application/rdap+json',
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
|
|
@ -514,12 +514,15 @@ function handleDomainQuery($request, $response, $pdo, $domainName, $c, $log) {
|
||||||
}
|
}
|
||||||
|
|
||||||
$abuseContactName = ($registrarAbuseDetails) ? $registrarAbuseDetails['first_name'] . ' ' . $registrarAbuseDetails['last_name'] : '';
|
$abuseContactName = ($registrarAbuseDetails) ? $registrarAbuseDetails['first_name'] . ' ' . $registrarAbuseDetails['last_name'] : '';
|
||||||
|
$rdapClean = rtrim(preg_replace('#^.*?//#', '', $registrarDetails['rdap_server'] ?? ''), '/');
|
||||||
|
|
||||||
// Construct the RDAP response in JSON format
|
// Construct the RDAP response in JSON format
|
||||||
$rdapResponse = [
|
$rdapResponse = [
|
||||||
'rdapConformance' => [
|
'rdapConformance' => [
|
||||||
'rdap_level_0',
|
'rdap_level_0',
|
||||||
|
'icann_rdap_response_profile_0',
|
||||||
'icann_rdap_response_profile_1',
|
'icann_rdap_response_profile_1',
|
||||||
|
'icann_rdap_technical_implementation_guide_0',
|
||||||
'icann_rdap_technical_implementation_guide_1',
|
'icann_rdap_technical_implementation_guide_1',
|
||||||
],
|
],
|
||||||
'objectClassName' => 'domain',
|
'objectClassName' => 'domain',
|
||||||
|
@ -575,20 +578,20 @@ function handleDomainQuery($request, $response, $pdo, $domainName, $c, $log) {
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
!$c['minimum_data'] ? [
|
!$c['minimum_data']
|
||||||
[
|
? array_merge(
|
||||||
mapContactToVCard($registrantDetails, 'registrant', $c)
|
[mapContactToVCard($registrantDetails, 'registrant', $c)],
|
||||||
],
|
|
||||||
array_map(function ($contact) use ($c) {
|
array_map(function ($contact) use ($c) {
|
||||||
return mapContactToVCard($contact, 'admin', $c);
|
return mapContactToVCard($contact, 'administrative', $c);
|
||||||
}, $adminDetails),
|
}, $adminDetails),
|
||||||
array_map(function ($contact) use ($c) {
|
array_map(function ($contact) use ($c) {
|
||||||
return mapContactToVCard($contact, 'tech', $c);
|
return mapContactToVCard($contact, 'technical', $c);
|
||||||
}, $techDetails),
|
}, $techDetails),
|
||||||
array_map(function ($contact) use ($c) {
|
array_map(function ($contact) use ($c) {
|
||||||
return mapContactToVCard($contact, 'billing', $c);
|
return mapContactToVCard($contact, 'billing', $c);
|
||||||
}, $billingDetails)
|
}, $billingDetails)
|
||||||
] : []
|
)
|
||||||
|
: []
|
||||||
),
|
),
|
||||||
'events' => $events,
|
'events' => $events,
|
||||||
'handle' => 'D' . $domainDetails['id'] . '-' . $c['roid'] . '',
|
'handle' => 'D' . $domainDetails['id'] . '-' . $c['roid'] . '',
|
||||||
|
@ -601,8 +604,8 @@ function handleDomainQuery($request, $response, $pdo, $domainName, $c, $log) {
|
||||||
'type' => 'application/rdap+json',
|
'type' => 'application/rdap+json',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'href' => $registrarDetails['rdap_server'] . 'domain/' . $domain,
|
'href' => 'https://' . $rdapClean . '/domain/' . $domain,
|
||||||
'value' => $registrarDetails['rdap_server'] . 'domain/' . $domain,
|
'value' => 'https://' . $rdapClean . '/domain/' . $domain,
|
||||||
'rel' => 'related',
|
'rel' => 'related',
|
||||||
'type' => 'application/rdap+json',
|
'type' => 'application/rdap+json',
|
||||||
]
|
]
|
||||||
|
@ -918,7 +921,7 @@ function handleEntityQuery($request, $response, $pdo, $entityHandle, $c, $log) {
|
||||||
// Initialize an array to hold entity blocks
|
// Initialize an array to hold entity blocks
|
||||||
$entityBlocks = [];
|
$entityBlocks = [];
|
||||||
// Define an array of allowed contact types
|
// Define an array of allowed contact types
|
||||||
$allowedTypes = ['owner', 'tech', 'abuse'];
|
$allowedTypes = ['owner', 'billing', 'abuse'];
|
||||||
|
|
||||||
foreach ($contacts as $contact) {
|
foreach ($contacts as $contact) {
|
||||||
// Check if the contact type is one of the allowed types
|
// Check if the contact type is one of the allowed types
|
||||||
|
@ -929,14 +932,14 @@ function handleEntityQuery($request, $response, $pdo, $entityHandle, $c, $log) {
|
||||||
// Create an entity block for each allowed contact type
|
// Create an entity block for each allowed contact type
|
||||||
$entityBlock = [
|
$entityBlock = [
|
||||||
'objectClassName' => 'entity',
|
'objectClassName' => 'entity',
|
||||||
'roles' => [$contact['type']],
|
'roles' => [($contact['type'] === 'owner') ? 'administrative' : $contact['type']],
|
||||||
"status" => ["active"],
|
"status" => ["active"],
|
||||||
"vcardArray" => [
|
"vcardArray" => [
|
||||||
"vcard",
|
"vcard",
|
||||||
[
|
[
|
||||||
['version', new stdClass(), 'text', '4.0'],
|
['version', new stdClass(), 'text', '4.0'],
|
||||||
["fn", new stdClass(), "text", $fullName],
|
["fn", new stdClass(), "text", $fullName],
|
||||||
["tel", ["type" => ["voice"]], "uri", "tel:" . $contact['voice']],
|
["tel", ["type" => ["voice"]], $contact['voice'] ? "uri" : "text", $contact['voice'] ? "tel:" . $contact['voice'] : ""],
|
||||||
["email", new stdClass(), "text", $contact['email']]
|
["email", new stdClass(), "text", $contact['email']]
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
@ -951,7 +954,9 @@ function handleEntityQuery($request, $response, $pdo, $entityHandle, $c, $log) {
|
||||||
$rdapResponse = [
|
$rdapResponse = [
|
||||||
'rdapConformance' => [
|
'rdapConformance' => [
|
||||||
'rdap_level_0',
|
'rdap_level_0',
|
||||||
|
'icann_rdap_response_profile_0',
|
||||||
'icann_rdap_response_profile_1',
|
'icann_rdap_response_profile_1',
|
||||||
|
'icann_rdap_technical_implementation_guide_0',
|
||||||
'icann_rdap_technical_implementation_guide_1',
|
'icann_rdap_technical_implementation_guide_1',
|
||||||
],
|
],
|
||||||
'objectClassName' => 'entity',
|
'objectClassName' => 'entity',
|
||||||
|
@ -1129,11 +1134,11 @@ function handleNameserverQuery($request, $response, $pdo, $nameserverHandle, $c,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for prohibited patterns in nameserver
|
// Validate nameserver
|
||||||
if (!preg_match('/^((xn--[a-zA-Z0-9-]{1,63}|[a-zA-Z0-9-]{1,63})\.){2,}(xn--[a-zA-Z0-9-]{2,63}|[a-zA-Z]{2,63})$/', $ns)) {
|
if (!isValidHostname($ns)) {
|
||||||
$response->header('Content-Type', 'application/json');
|
$response->header('Content-Type', 'application/json');
|
||||||
$response->status(400); // Bad Request
|
$response->status(400); // Bad Request
|
||||||
$response->end(json_encode(['error' => 'Nameserver invalid format']));
|
$response->end(json_encode(['error' => 'Nameserver format is invalid. Expected a fully qualified domain name (FQDN), punycode supported (e.g., ns1.example.com)']));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1298,12 +1303,15 @@ function handleNameserverQuery($request, $response, $pdo, $nameserverHandle, $c,
|
||||||
if (!empty($associated)) {
|
if (!empty($associated)) {
|
||||||
$statuses[] = 'associated';
|
$statuses[] = 'associated';
|
||||||
}
|
}
|
||||||
|
$statuses = array_unique(array_map(fn($s) => $s === 'ok' ? 'active' : $s, $statuses));
|
||||||
|
|
||||||
// Construct the RDAP response in JSON format
|
// Construct the RDAP response in JSON format
|
||||||
$rdapResponse = [
|
$rdapResponse = [
|
||||||
'rdapConformance' => [
|
'rdapConformance' => [
|
||||||
'rdap_level_0',
|
'rdap_level_0',
|
||||||
|
'icann_rdap_response_profile_0',
|
||||||
'icann_rdap_response_profile_1',
|
'icann_rdap_response_profile_1',
|
||||||
|
'icann_rdap_technical_implementation_guide_0',
|
||||||
'icann_rdap_technical_implementation_guide_1',
|
'icann_rdap_technical_implementation_guide_1',
|
||||||
],
|
],
|
||||||
'objectClassName' => 'nameserver',
|
'objectClassName' => 'nameserver',
|
||||||
|
@ -1366,8 +1374,9 @@ function handleNameserverQuery($request, $response, $pdo, $nameserverHandle, $c,
|
||||||
'ldhName' => $hostDetails['name'],
|
'ldhName' => $hostDetails['name'],
|
||||||
'links' => [
|
'links' => [
|
||||||
[
|
[
|
||||||
'href' => $c['rdap_url'] . '/nameserver/' . $hostDetails['name'],
|
'value' => $c['rdap_url'] . '/nameserver/' . $hostDetails['name'],
|
||||||
'rel' => 'self',
|
'rel' => 'self',
|
||||||
|
'href' => $c['rdap_url'] . '/nameserver/' . $hostDetails['name'],
|
||||||
'type' => 'application/rdap+json',
|
'type' => 'application/rdap+json',
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
@ -1855,7 +1864,9 @@ function handleDomainSearchQuery($request, $response, $pdo, $searchPattern, $c,
|
||||||
$rdapResponse = [
|
$rdapResponse = [
|
||||||
'rdapConformance' => [
|
'rdapConformance' => [
|
||||||
'rdap_level_0',
|
'rdap_level_0',
|
||||||
|
'icann_rdap_response_profile_0',
|
||||||
'icann_rdap_response_profile_1',
|
'icann_rdap_response_profile_1',
|
||||||
|
'icann_rdap_technical_implementation_guide_0',
|
||||||
'icann_rdap_technical_implementation_guide_1',
|
'icann_rdap_technical_implementation_guide_1',
|
||||||
],
|
],
|
||||||
'domainSearchResults' => [
|
'domainSearchResults' => [
|
||||||
|
@ -2117,11 +2128,11 @@ function handleNameserverSearchQuery($request, $response, $pdo, $searchPattern,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for prohibited patterns in nameserver
|
// Validate nameserver
|
||||||
if (!preg_match('/^((xn--[a-zA-Z0-9-]{1,63}|[a-zA-Z0-9-]{1,63})\.){2,}(xn--[a-zA-Z0-9-]{2,63}|[a-zA-Z]{2,63})$/', $ns)) {
|
if (!isValidHostname($ns)) {
|
||||||
$response->header('Content-Type', 'application/json');
|
$response->header('Content-Type', 'application/json');
|
||||||
$response->status(400); // Bad Request
|
$response->status(400); // Bad Request
|
||||||
$response->end(json_encode(['error' => 'Nameserver invalid format']));
|
$response->end(json_encode(['error' => 'Nameserver format is invalid. Expected a fully qualified domain name (FQDN), punycode supported (e.g., ns1.example.com)']));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2339,7 +2350,9 @@ function handleNameserverSearchQuery($request, $response, $pdo, $searchPattern,
|
||||||
$rdapResponse = [
|
$rdapResponse = [
|
||||||
'rdapConformance' => [
|
'rdapConformance' => [
|
||||||
'rdap_level_0',
|
'rdap_level_0',
|
||||||
|
'icann_rdap_response_profile_0',
|
||||||
'icann_rdap_response_profile_1',
|
'icann_rdap_response_profile_1',
|
||||||
|
'icann_rdap_technical_implementation_guide_0',
|
||||||
'icann_rdap_technical_implementation_guide_1',
|
'icann_rdap_technical_implementation_guide_1',
|
||||||
],
|
],
|
||||||
'nameserverSearchResults' => $rdapResult,
|
'nameserverSearchResults' => $rdapResult,
|
||||||
|
@ -2466,7 +2479,9 @@ function handleNameserverSearchQuery($request, $response, $pdo, $searchPattern,
|
||||||
$rdapResponse = [
|
$rdapResponse = [
|
||||||
'rdapConformance' => [
|
'rdapConformance' => [
|
||||||
'rdap_level_0',
|
'rdap_level_0',
|
||||||
|
'icann_rdap_response_profile_0',
|
||||||
'icann_rdap_response_profile_1',
|
'icann_rdap_response_profile_1',
|
||||||
|
'icann_rdap_technical_implementation_guide_0',
|
||||||
'icann_rdap_technical_implementation_guide_1',
|
'icann_rdap_technical_implementation_guide_1',
|
||||||
],
|
],
|
||||||
'nameserverSearchResults' => [
|
'nameserverSearchResults' => [
|
||||||
|
@ -2815,7 +2830,7 @@ function handleEntitySearchQuery($request, $response, $pdo, $searchPattern, $c,
|
||||||
// Initialize an array to hold entity blocks
|
// Initialize an array to hold entity blocks
|
||||||
$entityBlocks = [];
|
$entityBlocks = [];
|
||||||
// Define an array of allowed contact types
|
// Define an array of allowed contact types
|
||||||
$allowedTypes = ['owner', 'tech', 'abuse'];
|
$allowedTypes = ['owner', 'billing', 'abuse'];
|
||||||
|
|
||||||
foreach ($contacts as $contact) {
|
foreach ($contacts as $contact) {
|
||||||
// Check if the contact type is one of the allowed types
|
// Check if the contact type is one of the allowed types
|
||||||
|
@ -2826,14 +2841,14 @@ function handleEntitySearchQuery($request, $response, $pdo, $searchPattern, $c,
|
||||||
// Create an entity block for each allowed contact type
|
// Create an entity block for each allowed contact type
|
||||||
$entityBlock = [
|
$entityBlock = [
|
||||||
'objectClassName' => 'entity',
|
'objectClassName' => 'entity',
|
||||||
'roles' => [$contact['type']],
|
'roles' => [($contact['type'] === 'owner') ? 'administrative' : $contact['type']],
|
||||||
"status" => ["active"],
|
"status" => ["active"],
|
||||||
"vcardArray" => [
|
"vcardArray" => [
|
||||||
"vcard",
|
"vcard",
|
||||||
[
|
[
|
||||||
['version', new stdClass(), 'text', '4.0'],
|
['version', new stdClass(), 'text', '4.0'],
|
||||||
["fn", new stdClass(), "text", $fullName],
|
["fn", new stdClass(), "text", $fullName],
|
||||||
["tel", ["type" => ["voice"]], "uri", "tel:" . $contact['voice']],
|
["tel", ["type" => ["voice"]], $contact['voice'] ? "uri" : "text", $contact['voice'] ? "tel:" . $contact['voice'] : ""],
|
||||||
["email", new stdClass(), "text", $contact['email']]
|
["email", new stdClass(), "text", $contact['email']]
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
@ -2848,7 +2863,9 @@ function handleEntitySearchQuery($request, $response, $pdo, $searchPattern, $c,
|
||||||
$rdapResponse = [
|
$rdapResponse = [
|
||||||
'rdapConformance' => [
|
'rdapConformance' => [
|
||||||
'rdap_level_0',
|
'rdap_level_0',
|
||||||
|
'icann_rdap_response_profile_0',
|
||||||
'icann_rdap_response_profile_1',
|
'icann_rdap_response_profile_1',
|
||||||
|
'icann_rdap_technical_implementation_guide_0',
|
||||||
'icann_rdap_technical_implementation_guide_1',
|
'icann_rdap_technical_implementation_guide_1',
|
||||||
],
|
],
|
||||||
'entitySearchResults' => [
|
'entitySearchResults' => [
|
||||||
|
@ -2993,9 +3010,11 @@ function handleEntitySearchQuery($request, $response, $pdo, $searchPattern, $c,
|
||||||
function handleHelpQuery($request, $response, $pdo, $c) {
|
function handleHelpQuery($request, $response, $pdo, $c) {
|
||||||
// Set the RDAP conformance levels
|
// Set the RDAP conformance levels
|
||||||
$rdapConformance = [
|
$rdapConformance = [
|
||||||
"rdap_level_0",
|
'rdap_level_0',
|
||||||
"icann_rdap_response_profile_1",
|
'icann_rdap_response_profile_0',
|
||||||
"icann_rdap_technical_implementation_guide_1"
|
'icann_rdap_response_profile_1',
|
||||||
|
'icann_rdap_technical_implementation_guide_0',
|
||||||
|
'icann_rdap_technical_implementation_guide_1',
|
||||||
];
|
];
|
||||||
|
|
||||||
// Set the descriptions and links for the help section
|
// Set the descriptions and links for the help section
|
||||||
|
@ -3015,13 +3034,15 @@ function handleHelpQuery($request, $response, $pdo, $c) {
|
||||||
],
|
],
|
||||||
'links' => [
|
'links' => [
|
||||||
[
|
[
|
||||||
'href' => $c['rdap_url'] . '/help',
|
'value' => $c['rdap_url'] . '/help',
|
||||||
'rel' => 'self',
|
'rel' => 'self',
|
||||||
|
'href' => $c['rdap_url'] . '/help',
|
||||||
'type' => 'application/rdap+json',
|
'type' => 'application/rdap+json',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'href' => 'https://namingo.org',
|
'value' => 'https://namingo.org',
|
||||||
'rel' => 'related',
|
'rel' => 'related',
|
||||||
|
'href' => 'https://namingo.org',
|
||||||
'type' => 'application/rdap+json',
|
'type' => 'application/rdap+json',
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue