-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
373 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,23 @@ | ||
# whmcs-whois | ||
# WHOIS & RDAP Client | ||
Provides WHOIS and RDAP query capabilities to retrieve domain registration details and status information | ||
|
||
## Installation | ||
|
||
```bash | ||
git clone https://github.com/getnamingo/whmcs-whois | ||
mv whmcs-whois/whois /var/www/html/whmcs/modules/addons | ||
chown -R www-data:www-data /var/www/html/whmcs/modules/addons/whois | ||
chmod -R 755 /var/www/html/whmcs/modules/addons/whois | ||
``` | ||
|
||
- Go to Settings > Apps & Integrations in the admin panel, search for "WHOIS & RDAP Client" and then activate "WHOIS & RDAP Client". | ||
|
||
Edit the `/var/www/html/whmcs/modules/addons/whois/check.php` file and set your WHOIS and RDAP server URLs by replacing the placeholder values with your actual server addresses. | ||
|
||
## Usage Instructions | ||
|
||
The detailed usage instructions for this module are currently being written and will be available soon. This module is specifically designed to work with the Namingo Registrar project, ensuring WHOIS and RDAP client is provided to your customers. Please check back later for full documentation and guidance on using this module with your Namingo Registrar setup. | ||
|
||
## License | ||
|
||
Apache License 2.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
<?php | ||
// ========================================== | ||
// Start editing below: Add your WHOIS and RDAP server hostnames here | ||
// ========================================== | ||
|
||
// WHOIS server | ||
$whoisServer = 'whois.example.com'; | ||
|
||
// RDAP server | ||
$rdap_url = 'rdap.example.com'; | ||
|
||
// ========================================== | ||
// Stop editing above: No further modifications are necessary | ||
// ========================================== | ||
|
||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') { | ||
echo json_encode(['error' => 'Invalid request method.']); | ||
exit; | ||
} | ||
|
||
$domain = $_POST['domain']; | ||
$type = $_POST['type']; | ||
$rdapServer = 'https://' . $rdap_url . '/domain/'; | ||
|
||
$sanitized_domain = filter_var($domain, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME); | ||
|
||
// Check if the domain is in Unicode and convert it to Punycode | ||
if (mb_check_encoding($domain, 'UTF-8') && !filter_var($domain, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME)) { | ||
$punycodeDomain = idn_to_ascii($domain, IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46); | ||
|
||
if ($punycodeDomain !== false) { | ||
$domain = $punycodeDomain; | ||
} else { | ||
echo json_encode(['error' => 'Invalid domain.']); | ||
exit; | ||
} | ||
} | ||
|
||
$sanitized_domain = filter_var($domain, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME); | ||
|
||
if ($sanitized_domain) { | ||
$domain = $sanitized_domain; | ||
} else { | ||
echo json_encode(['error' => 'Invalid domain.']); | ||
exit; | ||
} | ||
|
||
$sanitized_type = filter_var($type, FILTER_SANITIZE_STRING); | ||
|
||
if ($sanitized_type === 'whois' || $sanitized_type === 'rdap') { | ||
$type = $sanitized_type; | ||
} else { | ||
echo json_encode(['error' => 'Invalid input.']); | ||
exit; | ||
} | ||
|
||
if ($type === 'whois') { | ||
$output = ''; | ||
$socket = fsockopen($whoisServer, 43, $errno, $errstr, 30); | ||
|
||
if (!$socket) { | ||
echo json_encode(['error' => "Error fetching WHOIS data."]); | ||
exit; | ||
} | ||
|
||
fwrite($socket, $domain . "\r\n"); | ||
while (!feof($socket)) { | ||
$output .= fgets($socket); | ||
} | ||
fclose($socket); | ||
} elseif ($type === 'rdap') { | ||
$ch = curl_init(); | ||
curl_setopt($ch, CURLOPT_URL, $rdapServer . $domain); | ||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | ||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); | ||
|
||
$output = curl_exec($ch); | ||
|
||
if (curl_errno($ch)) { | ||
echo json_encode(['error' => 'cURL error: ' . curl_error($ch)]); | ||
curl_close($ch); | ||
exit; | ||
} | ||
|
||
curl_close($ch); | ||
|
||
if (!$output) { | ||
echo json_encode(['error' => 'Error fetching RDAP data.']); | ||
exit; | ||
} | ||
} | ||
header('Content-Type: application/json'); | ||
echo $output; | ||
exit; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
{block name="head"} | ||
<style> | ||
#bottom { | ||
display: none; | ||
} | ||
#result { | ||
white-space: pre-wrap; | ||
word-wrap: break-word; | ||
} | ||
</style> | ||
{/block} | ||
|
||
<h1 class="mb-4">Domain Lookup</h1> | ||
|
||
{block name="page-content"} | ||
<div class="container"> | ||
<div class="row"> | ||
<div class="col-md-12"> | ||
<div class="card mb-4"> | ||
<div class="card-body"> | ||
<form id="lookupForm"> | ||
<div class="row mb-3"> | ||
<div class="col-12 col-md-8"> | ||
<input type="text" class="form-control form-control-lg" id="domainInput" placeholder="Enter Domain Name" autocapitalize="none"> | ||
</div> | ||
<div class="col-12 col-md-4 mt-3 mt-md-0 d-flex flex-column flex-md-row justify-content-center justify-content-md-end text-center"> | ||
<button type="button" class="btn btn-info btn-lg mb-2 mb-md-0 w-100 w-md-auto me-md-2" id="whoisButton">WHOIS</button> | ||
<button type="button" class="btn btn-info btn-lg mb-2 mb-md-0 w-100 w-md-auto" id="rdapButton">RDAP</button> | ||
</div> | ||
</div> | ||
</form> | ||
<div class="row" id="bottom"> | ||
<div class="col-lg-12"> | ||
<pre><code><div id="result"></div></code></pre> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
{literal} | ||
<script> | ||
document.addEventListener('DOMContentLoaded', function() { | ||
document.getElementById('domainInput').addEventListener('keypress', function(event) { | ||
if (event.key === 'Enter') { | ||
event.preventDefault(); | ||
document.getElementById('whoisButton').click(); | ||
} | ||
}); | ||
|
||
document.getElementById('whoisButton').addEventListener('click', function() { | ||
var domain = document.getElementById('domainInput').value.trim(); | ||
if (!domain) { | ||
alert('Please enter a domain name.'); | ||
return; | ||
} | ||
var captcha = ''; | ||
|
||
fetch('/modules/addons/whois/check.php', { | ||
method: 'POST', | ||
headers: { | ||
'Content-Type': 'application/x-www-form-urlencoded', | ||
}, | ||
body: 'domain=' + encodeURIComponent(domain) + '&captcha=' + encodeURIComponent(captcha) + '&type=whois' | ||
}) | ||
.then(response => response.text()) | ||
.then(data => { | ||
document.getElementById('result').innerText = data; | ||
document.getElementById('bottom').style.display = 'block'; | ||
}) | ||
.catch(error => console.error('Error:', error)); | ||
}); | ||
|
||
document.getElementById('rdapButton').addEventListener('click', function() { | ||
var domain = document.getElementById('domainInput').value.trim(); | ||
if (!domain) { | ||
alert('Please enter a domain name.'); | ||
return; | ||
} | ||
var captcha = ''; | ||
|
||
fetch('/modules/addons/whois/check.php', { | ||
method: 'POST', | ||
headers: { | ||
'Content-Type': 'application/x-www-form-urlencoded', | ||
}, | ||
body: 'domain=' + encodeURIComponent(domain) + '&captcha=' + encodeURIComponent(captcha) + '&type=rdap' | ||
}) | ||
.then(response => response.json()) | ||
.then(data => { | ||
if (data.error) { | ||
console.error('Error:', data.error); | ||
document.getElementById('result').innerText = 'Error: ' + data.error; | ||
} else { | ||
let output = parseRdapResponse(data); | ||
document.getElementById('result').innerText = output; | ||
document.getElementById('bottom').style.display = 'block'; | ||
} | ||
}) | ||
.catch(error => console.error('Error:', error)); | ||
}); | ||
}); | ||
|
||
function parseRdapResponse(data) { | ||
let output = ''; | ||
// Domain Name and Status | ||
output += 'Domain Name: ' + (data.ldhName || 'N/A') + '\n'; | ||
output += 'Status: ' + (data.status ? data.status.join(', ') : 'N/A') + '\n\n'; | ||
// Parsing entities for specific roles like registrar and registrant | ||
if (data.entities && data.entities.length > 0) { | ||
data.entities.forEach(entity => { | ||
if (entity.roles) { | ||
output += entity.roles.join(', ').toUpperCase() + ' Contact:\n'; | ||
if (entity.vcardArray && entity.vcardArray.length > 1) { | ||
output += parseVcard(entity.vcardArray[1]); | ||
} | ||
if (entity.roles.includes('registrar') && entity.publicIds) { | ||
output += ' IANA ID: ' + entity.publicIds.map(id => id.identifier).join(', ') + '\n'; | ||
} | ||
output += '\n'; | ||
} | ||
}); | ||
} | ||
|
||
// Nameservers | ||
if (data.nameservers && data.nameservers.length > 0) { | ||
output += 'Nameservers:\n'; | ||
data.nameservers.forEach(ns => { | ||
output += ' - ' + ns.ldhName + '\n'; | ||
}); | ||
output += '\n'; | ||
} | ||
|
||
// SecureDNS Details | ||
if (data.secureDNS) { | ||
output += 'SecureDNS:\n'; | ||
output += ' - Delegation Signed: ' + (data.secureDNS.delegationSigned ? 'Yes' : 'No') + '\n'; | ||
output += ' - Zone Signed: ' + (data.secureDNS.zoneSigned ? 'Yes' : 'No') + '\n\n'; | ||
} | ||
|
||
// Events (like registration, expiration dates) | ||
if (data.events && data.events.length > 0) { | ||
output += 'Events:\n'; | ||
data.events.forEach(event => { | ||
output += ' - ' + event.eventAction + ': ' + new Date(event.eventDate).toLocaleString() + '\n'; | ||
}); | ||
output += '\n'; | ||
} | ||
|
||
// Notices | ||
if (data.notices && data.notices.length > 0) { | ||
output += 'Notices:\n'; | ||
data.notices.forEach(notice => { | ||
output += ' - ' + (notice.title || 'Notice') + ': ' + notice.description.join(' ') + '\n'; | ||
}); | ||
} | ||
|
||
return output; | ||
} | ||
|
||
function parseVcard(vcard) { | ||
let vcardOutput = ''; | ||
vcard.forEach(entry => { | ||
switch (entry[0]) { | ||
case 'fn': | ||
vcardOutput += ' Name: ' + entry[3] + '\n'; | ||
break; | ||
case 'adr': | ||
if (Array.isArray(entry[3]) && entry[3].length > 0) { | ||
const addressParts = entry[3]; | ||
vcardOutput += ' Address: ' + addressParts.join(', ') + '\n'; | ||
} | ||
break; | ||
case 'email': | ||
vcardOutput += ' Email: ' + entry[3] + '\n'; | ||
break; | ||
case 'tel': | ||
vcardOutput += ' Phone: ' + entry[3] + '\n'; | ||
break; | ||
} | ||
}); | ||
return vcardOutput; | ||
} | ||
</script> | ||
{/literal} | ||
</div> | ||
{/block} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"schema": "1.0", | ||
"type": "whmcs-addons", | ||
"name": "whois", | ||
"version": "1.0", | ||
"license": "MIT", | ||
"category": "utilities", | ||
"description": { | ||
"name": "WHOIS & RDAP Client", | ||
"tagline": "Provides WHOIS and RDAP query capabilities to retrieve domain registration details and status information" | ||
}, | ||
"authors": [ | ||
{ | ||
"name": "Namingo", | ||
"homepage": "https:\/\/namingo.org\/" | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
<?php | ||
if (!defined("WHMCS")) { | ||
die("This file cannot be accessed directly"); | ||
} | ||
|
||
function whois_config() | ||
{ | ||
return [ | ||
'name' => 'WHOIS & RDAP Client', | ||
'description' => 'Provides WHOIS and RDAP query capabilities to retrieve domain registration details and status information', | ||
'version' => '1.0', | ||
'author' => 'Namingo', | ||
'fields' => [], | ||
]; | ||
} | ||
|
||
function whois_activate() | ||
{ | ||
return [ | ||
'status' => 'success', | ||
'description' => 'WHOIS & RDAP Client activated successfully.', | ||
]; | ||
} | ||
|
||
function whois_deactivate() | ||
{ | ||
return [ | ||
'status' => 'success', | ||
'description' => 'WHOIS & RDAP Client deactivated successfully.', | ||
]; | ||
} | ||
|
||
function whois_clientarea($vars) | ||
{ | ||
$templateFile = 'clientarea'; | ||
$modulelink = $vars['modulelink']; | ||
$systemUrl = $vars['systemurl']; | ||
|
||
return [ | ||
'pagetitle' => 'Domain Lookup', | ||
'breadcrumb' => ['index.php?m=whois' => 'Domain Lookup'], | ||
'templatefile' => $templateFile, | ||
'requirelogin' => false, | ||
'vars' => [ | ||
'modulelink' => $modulelink, | ||
'systemurl' => $systemUrl, | ||
], | ||
]; | ||
} |