Skip to content
Open
80 changes: 71 additions & 9 deletions modules/registrars/openprovider/helpers/DNS.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@

use OpenProvider\WhmcsRegistrar\src\Configuration;
use OpenProvider\WhmcsRegistrar\src\OpenProvider;
use OpenProvider\WhmcsRegistrar\src\RestClient;
use WHMCS\Database\Capsule;

class DNS
{
/**
* Get the DNS URL
*
* @return bool|void
* @param int $domain_id
* @return string|null|false
*/
public static function getDnsUrlOrFail($domain_id)
{
Expand All @@ -21,24 +23,84 @@ public static function getDnsUrlOrFail($domain_id)
->first();

// Check if OpenProvider is the provider
if($domain->registrar != 'openprovider' || $domain->status != 'Active')
if ($domain->registrar != 'openprovider' || $domain->status != 'Active') {
return false;
}

// Check if we are allowed to make a redirect.
$newDnsStatus = Configuration::getOrDefault('useNewDnsManagerFeature', false);

$useNew = (bool) \OpenProvider\WhmcsRegistrar\src\Configuration::getOrDefault('useNewDnsManagerFeature', true);

if($newDnsStatus != true)
if (!$useNew) {
return false;
}

// Let's get the URL.
try {
$OpenProvider = new OpenProvider();
return $OpenProvider->api->getDnsSingleDomainTokenUrl($domain->domain)['url'];
[$username, $password] = self::getRegistrarCredentials();

if ($username === '' || $password === '') {
return null;
}

$client = new RestClient();
$client->login($username, $password);

// Create a domain token
$url = $client->createDomainToken($domain->domain, 'openprovider');

return $url;
} catch (\Exception $e) {
\logModuleCall('OpenProvider', 'Fetching generateSingleDomainTokenRequest', $domain->domain, @$response, $e->getMessage(), [htmlentities($params['Password']), $params['Password']]);
\logModuleCall('openprovider', 'Fetching generateSingleDomainTokenRequest', $domain->domain, null, $e->getMessage(), []);
return false;
}
}

}
/**
* Fetch registrar credentials directly from WHMCS DB
*
* @return array [username, password]
*/
private static function getRegistrarCredentials(): array
{
$rows = Capsule::table('tblregistrars')
->where('registrar', 'openprovider')
->whereIn('setting', ['Username', 'Password'])
->pluck('value', 'setting');

$rawUsername = (string)($rows['Username'] ?? '');
$rawPassword = (string)($rows['Password'] ?? '');

$username = self::smartDecrypt($rawUsername);
$password = self::smartDecrypt($rawPassword);

return [$username, $password];
}
private static function smartDecrypt(string $value): string
{
if ($value === '') {
return '';
}

$dec1 = $value;
try {
$tmp = \decrypt($value);
if ($tmp !== '' && $tmp !== $value) {
$dec1 = $tmp;
}
} catch (\Throwable $e) {
}

$looksEncoded = (bool)preg_match('/^[A-Za-z0-9+\/=]{16,}$/', $dec1);
if ($looksEncoded) {
try {
$tmp2 = \decrypt($dec1);
if ($tmp2 !== '' && $tmp2 !== $dec1) {
return $tmp2;
}
} catch (\Throwable $e) {
}
}

return $dec1;
}
}
15 changes: 12 additions & 3 deletions modules/registrars/openprovider/openprovider.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* @copyright Copyright (c) Openprovider 2018
*/

use \OpenProvider\WhmcsRegistrar\src\Configuration;
use OpenProvider\WhmcsRegistrar\src\Configuration;
use WHMCS\Exception\Module\InvalidConfiguration;

if (!defined("WHMCS")) {
Expand Down Expand Up @@ -64,6 +64,7 @@ function openprovider_AdminCustomButtonArray()
$buttonarray = array(
"Auto-renew Sync" => "AutoRenewSync",
"Sync" => "Sync",
'Manage DNS Zone' => 'AdminManageDnsZone',
);

return $buttonarray;
Expand Down Expand Up @@ -282,7 +283,7 @@ function openprovider_AutoRenewSync($params)
* @return array
*/
function openprovider_Sync($paramsArray)
{
{
return openprovider_registrar_launch_decorator('domainSync', $paramsArray);
}

Expand Down Expand Up @@ -342,6 +343,13 @@ function openprovider_ResendIRTPVerificationEmail(array $params)
return openprovider_registrar_launch_decorator('resendIRTPVerificationEmail', $params);
}

function openprovider_AdminManageDnsZone($params)
{
$controller = new \OpenProvider\WhmcsRegistrar\Controllers\Hooks\DnsAuthController();
$ok = $controller->redirectDnsManagementPage($params);

return ['error' => 'Could not redirect to DNS panel'];
}

function openprovider_config_validate($params)
{
Expand All @@ -358,7 +366,7 @@ function openprovider_config_validate($params)
$baseUrl = Configuration::get('restapi_url_sandbox');
}

$url = "{$baseUrl}{$resourcePath}";
$url = "{$baseUrl}{$resourcePath}";

$data = array(
"username" => $username,
Expand All @@ -375,6 +383,7 @@ function openprovider_config_validate($params)
curl_setopt($curl, CURLOPT_POSTFIELDS, $encodedData);
$result = curl_exec($curl);
curl_close($curl);

$response = json_decode($result);
if (!$response->data->token || !$response->data->reseller_id) {
throw new InvalidConfiguration("Credentials are Invalid for $env Environment");
Expand Down
114 changes: 114 additions & 0 deletions modules/registrars/openprovider/src/RestClient.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<?php

namespace OpenProvider\WhmcsRegistrar\src;

class RestClient
{
private string $baseUrl;
private bool $isSandbox;
private ?string $bearer = null;

public function __construct()
{
$this->isSandbox = ((string) Configuration::get('test_mode') === 'on');
$this->baseUrl = $this->isSandbox
? (string) Configuration::get('restapi_url_sandbox')
: (string) Configuration::get('api_url');
}

public function login(string $username, string $password): void
{
$url = rtrim($this->baseUrl, '/') . '/v1beta/auth/login';
$payload = [
'username' => $username,
'password' => $password,
'ip' => '0.0.0.0',
];

[$http, $json, $raw] = $this->curl('POST', $url, $payload);


if ($http !== 200 || empty($json->data->token)) {
\logModuleCall(
'openprovider',
'rest:/v1beta/auth/login:fail',
$this->safeLogBody($payload),
null,
['httpcode' => $http, 'json' => $json],
[]
);
throw new \RuntimeException($json->desc ?? 'Login failed', $http);
}

$this->bearer = $json->data->token;
}

public function createDomainToken(string $fqdn, string $zoneProvider = 'openprovider'): string
{
if (!$this->bearer) {
throw new \LogicException('Not authenticated');
}

$url = rtrim($this->baseUrl, '/') . '/v1beta/dns/domain-token';

[$http, $json] = $this->curl('POST', $url, [
'domain' => $fqdn,
'zone_provider' => $zoneProvider,
], [
'Authorization: Bearer ' . $this->bearer,
]);

if ($http !== 200 || empty($json->data->token)) {
throw new \RuntimeException($json->desc ?? 'domain-token failed', $http);
}

return $json->data->url ?? null;
}

/** ------------ Helpers ------------ */
private function curl(string $method, string $url, array $body = [], array $headers = []): array
{
$ch = curl_init();
$headers = array_merge(['Content-Type: application/json'], $headers);

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($method));

if (in_array($method, ['POST','PUT','DELETE'], true)) {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
}

$response = curl_exec($ch);
$httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);

if (curl_errno($ch)) {
$err = curl_error($ch);
curl_close($ch);
throw new \RuntimeException($err);
}

curl_close($ch);
$json = json_decode((string) $response);

\logModuleCall(
'openprovider',
'rest:' . parse_url($url, PHP_URL_PATH),
$this->safeLogBody($body),
(string) $response,
['httpcode' => $httpCode, 'json' => $json],
[]
);

return [$httpCode, $json, (string) $response];
}

private function safeLogBody(array $body): array
{
if (isset($body['password'])) {
$body['password'] = '********';
}
return $body;
}
}