Skip to content

Commit

Permalink
Initial upload
Browse files Browse the repository at this point in the history
  • Loading branch information
getpinga committed Sep 18, 2024
1 parent c912508 commit 705eab9
Show file tree
Hide file tree
Showing 5 changed files with 373 additions and 1 deletion.
23 changes: 22 additions & 1 deletion README.md
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
94 changes: 94 additions & 0 deletions whois/check.php
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;
190 changes: 190 additions & 0 deletions whois/templates/clientarea.tpl
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}
18 changes: 18 additions & 0 deletions whois/whmcs.json
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\/"
}
]
}
49 changes: 49 additions & 0 deletions whois/whois.php
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,
],
];
}

0 comments on commit 705eab9

Please sign in to comment.