Files
KeyHelp-Manager-for-WHMCS/modules/servers/keyhelpmanager/keyhelpmanager.php
Kevin Feiler 8259ec4621 commit update
2025-10-15 22:40:34 +02:00

651 lines
18 KiB
PHP

<?php
/**
* KeyHelp Manager - WHMCS Provisioning Module
*
* @author Kevin Feiler <info@avvgo.de>
* @copyright Copyright (c) 2024 Kevin Feiler / AVVGO
* @license MIT License
* @link https://avvgo.de
* @version 1.0.0
*/
if (!defined("WHMCS")) {
die("This file cannot be accessed directly");
}
use WHMCS\Database\Capsule;
function keyhelpmanager_MetaData()
{
return [
"DisplayName" => "KeyHelp Manager",
"APIVersion" => "1.1",
"RequiresServer" => true,
"DefaultNonSSLPort" => "80",
"DefaultSSLPort" => "443",
"ServiceSingleSignOnLabel" => "Login to KeyHelp",
"AdminSingleSignOnLabel" => "Login as Admin",
];
}
function keyhelpmanager_ConfigOptions()
{
return [
"hostname" => [
"FriendlyName" => "Hostname (IP or FQDN)",
"Type" => "text",
"Size" => "25",
"Description" =>
"KeyHelp server hostname or IP address (without http://)",
"Required" => true,
],
"apikey" => [
"FriendlyName" => "API Key",
"Type" => "password",
"Size" => "50",
"Description" => "KeyHelp API Key from Settings → API",
"Required" => true,
],
"usessl" => [
"FriendlyName" => "Use SSL",
"Type" => "yesno",
"Default" => "on",
"Description" => "Use SSL for API connection (recommended)",
],
"verify_ssl" => [
"FriendlyName" => "Verify SSL Certificate",
"Type" => "yesno",
"Default" => "on",
"Description" => "Verify SSL certificate (disable for self-signed)",
],
];
}
function _keyhelpmanager_APIRequest(
array $params,
string $endpoint,
string $method = "GET",
array $data = [],
) {
try {
$hostname =
$params["serverhostname"] ?? ($params["configoption1"] ?? "");
$apiKey = $params["serverpassword"] ?? ($params["configoption2"] ?? "");
$useSSL = $params["configoption3"] ?? "on";
$verifySSL = $params["configoption4"] ?? "on";
if (empty($hostname) || empty($apiKey)) {
return [
"success" => false,
"error" => "KeyHelp server not configured",
];
}
$protocol = $useSSL === "on" ? "https" : "http";
$url = sprintf("%s://%s/api/v2%s", $protocol, $hostname, $endpoint);
$client = new \GuzzleHttp\Client([
"verify" => $verifySSL === "on",
"timeout" => 30,
"http_errors" => false,
]);
$options = [
"headers" => [
"X-API-Key" => $apiKey,
"Content-Type" => "application/json",
"Accept" => "application/json",
],
];
if (!empty($data) && in_array($method, ["POST", "PUT", "PATCH"])) {
$options["json"] = $data;
}
$response = $client->request($method, $url, $options);
$statusCode = $response->getStatusCode();
$body = (string) $response->getBody();
$responseData = json_decode($body, true);
logModuleCall(
"keyhelpmanager",
$method . " " . $endpoint,
$data,
$statusCode . " - " . $body,
$responseData,
[$apiKey],
);
if ($statusCode >= 200 && $statusCode < 300) {
return [
"success" => true,
"data" => $responseData,
"status_code" => $statusCode,
];
}
$errorMessage =
$responseData["message"] ??
($responseData["error"] ??
sprintf("HTTP %d - %s", $statusCode, $body));
return [
"success" => false,
"error" => "KeyHelp API Error: " . $errorMessage,
"status_code" => $statusCode,
];
} catch (\GuzzleHttp\Exception\ConnectException $e) {
return [
"success" => false,
"error" => "Connection failed: " . $e->getMessage(),
];
} catch (\Exception $e) {
return [
'
success' => false,
"error" => "Unexpected error: " . $e->getMessage(),
];
}
}
function keyhelpmanager_CreateAccount(array $params)
{
try {
$domain = $params["domain"] ?? "";
$username =
$params["username"] ?? _keyhelpmanager_GenerateUsername($domain);
$password = $params["password"] ?? _keyhelpmanager_GeneratePassword();
$clientEmail = $params["clientsdetails"]["email"] ?? "";
$clientName = trim(
($params["clientsdetails"]["firstname"] ?? "") .
" " .
($params["clientsdetails"]["lastname"] ?? ""),
);
if (empty($domain)) {
return "Domain is required";
}
$accountData = [
"login_name" => $username,
"password" => $password,
"email" => $clientEmail,
"display_name" => $clientName,
];
if (!empty($params["configoptions"]["KeyHelp Plan"])) {
$accountData["plan"] = $params["configoptions"]["KeyHelp Plan"];
}
$result = _keyhelpmanager_APIRequest(
$params,
"/users",
"POST",
$accountData,
);
if (!$result["success"]) {
return $result["error"];
}
$userId = $result["data"]["id"] ?? null;
if (empty($userId)) {
return "User created but no ID returned";
}
$domainData = ["domain_name" => $domain, "user_id" => $userId];
$domainResult = _keyhelpmanager_APIRequest(
$params,
"/domains",
"POST",
$domainData,
);
if (!$domainResult["success"]) {
_keyhelpmanager_APIRequest($params, "/users/" . $userId, "DELETE");
return "Domain creation failed: " . $domainResult["error"];
}
_keyhelpmanager_SaveAccountDetails($params["serviceid"], [
"username" => $username,
"password" => $password,
"userid" => $userId,
]);
return "success";
} catch (\Exception $e) {
return "Account creation failed: " . $e->getMessage();
}
}
function keyhelpmanager_SuspendAccount(array $params)
{
try {
$userId = _keyhelpmanager_GetUserId($params);
if (empty($userId)) {
return "User ID not found";
}
$result = _keyhelpmanager_APIRequest(
$params,
"/users/" . $userId,
"PUT",
["is_locked" => true],
);
return $result["success"] ? "success" : $result["error"];
} catch (\Exception $e) {
return "Suspend failed: " . $e->getMessage();
}
}
function keyhelpmanager_UnsuspendAccount(array $params)
{
try {
$userId = _keyhelpmanager_GetUserId($params);
if (empty($userId)) {
return "User ID not found";
}
$result = _keyhelpmanager_APIRequest(
$params,
"/users/" . $userId,
"PUT",
["is_locked" => false],
);
return $result["success"] ? "success" : $result["error"];
} catch (\Exception $e) {
return "Unsuspend failed: " . $e->getMessage();
}
}
function keyhelpmanager_TerminateAccount(array $params)
{
try {
$userId = _keyhelpmanager_GetUserId($params);
if (empty($userId)) {
return "User ID not found";
}
$result = _keyhelpmanager_APIRequest(
$params,
"/users/" . $userId,
"DELETE",
);
if ($result["success"]) {
_keyhelpmanager_DeleteAccountDetails($params["serviceid"]);
return "success";
}
return $result["error"];
} catch (\Exception $e) {
return "Termination failed: " . $e->getMessage();
}
}
function keyhelpmanager_ClientArea(array $params)
{
try {
$accountDetails = _keyhelpmanager_GetAccountDetails(
$params["serviceid"],
);
$userId = $accountDetails["userid"] ?? null;
$hostname =
$params["serverhostname"] ?? ($params["configoption1"] ?? "");
$useSSL = $params["configoption3"] ?? "on";
$protocol = $useSSL === "on" ? "https" : "http";
$loginUrl = sprintf("%s://%s", $protocol, $hostname);
$templateVars = [
"login_url" => $loginUrl,
"username" =>
$accountDetails["username"] ?? ($params["username"] ?? "N/A"),
"password" =>
$accountDetails["password"] ??
($params["password"] ?? "••••••••"),
"domain" => $params["domain"] ?? "N/A",
"stats" => null,
"error" => null,
];
if (!empty($userId)) {
$statsResult = _keyhelpmanager_APIRequest(
$params,
"/users/" . $userId . "/statistics",
"GET",
);
if ($statsResult["success"] && isset($statsResult["data"])) {
$stats = $statsResult["data"];
$templateVars["stats"] = [
"disk_used" => $stats["disk_usage"] ?? 0,
"disk_limit" => $stats["disk_limit"] ?? 0,
"disk_used_formatted" => _keyhelpmanager_FormatBytes(
$stats["disk_usage"] ?? 0,
),
"disk_limit_formatted" => _keyhelpmanager_FormatBytes(
$stats["disk_limit"] ?? 0,
),
"disk_percent" => _keyhelpmanager_CalculatePercent(
$stats["disk_usage"] ?? 0,
$stats["disk_limit"] ?? 0,
),
"bandwidth_used" => $stats["traffic_usage"] ?? 0,
"bandwidth_limit" => $stats["traffic_limit"] ?? 0,
"bandwidth_used_formatted" => _keyhelpmanager_FormatBytes(
$stats["traffic_usage"] ?? 0,
),
"bandwidth_limit_formatted" => _keyhelpmanager_FormatBytes(
$stats["traffic_limit"] ?? 0,
),
"bandwidth_percent" => _keyhelpmanager_CalculatePercent(
$stats["traffic_usage"] ?? 0,
$stats["traffic_limit"] ?? 0,
),
"domains" => $stats["domains_count"] ?? 0,
"databases" => $stats["databases_count"] ?? 0,
"email_accounts" => $stats["email_accounts_count"] ?? 0,
];
}
}
return ["templatefile" => "clientarea", "vars" => $templateVars];
} catch (\Exception $e) {
return [
"templatefile" => "clientarea",
"vars" => [
"error" =>
"Failed to load account information: " . $e->getMessage(),
],
];
}
}
function keyhelpmanager_LoginLink(array $params)
{
try {
$accountDetails = _keyhelpmanager_GetAccountDetails(
$params["serviceid"],
);
$userId = $accountDetails["userid"] ?? null;
if (empty($userId)) {
return ["success" => false, "errorMsg" => "User ID not found"];
}
$sessionData = ["user_id" => $userId, "lifetime" => 300];
$result = _keyhelpmanager_APIRequest(
$params,
"/sessions",
"POST",
$sessionData,
);
if (!$result["success"]) {
return [
"success" => false,
"errorMsg" => "Session creation failed: " . $result["error"],
];
}
$sessionToken = $result["data"]["token"] ?? null;
if (empty($sessionToken)) {
return [
"success" => false,
"errorMsg" => "No session token received",
];
}
$hostname =
$params["serverhostname"] ?? ($params["configoption1"] ?? "");
$useSSL = $params["configoption3"] ?? "on";
$protocol = $useSSL === "on" ? "https" : "http";
$loginUrl = sprintf(
"%s://%s/login?token=%s",
$protocol,
$hostname,
$sessionToken,
);
return ["success" => true, "redirectTo" => $loginUrl];
} catch (\Exception $e) {
return [
"success" => false,
"errorMsg" => "Login link creation failed: " . $e->getMessage(),
];
}
}
function keyhelpmanager_ChangePassword(array $params)
{
try {
$userId = _keyhelpmanager_GetUserId($params);
$newPassword = $params["password"] ?? "";
if (empty($userId)) {
return "User ID not found";
}
if (empty($newPassword)) {
return "New password is required";
}
$result = _keyhelpmanager_APIRequest(
$params,
"/users/" . $userId,
"PUT",
["password" => $newPassword],
);
if ($result["success"]) {
_keyhelpmanager_UpdateAccountDetail(
$params["serviceid"],
"password",
$newPassword,
);
return "success";
}
return $result["error"];
} catch (\Exception $e) {
return "Password change failed: " . $e->getMessage();
}
}
function keyhelpmanager_TestConnection(array $params)
{
try {
$result = _keyhelpmanager_APIRequest($params, "/server/version", "GET");
if (!$result["success"]) {
return ["success" => false, "error" => $result["error"]];
}
$version = $result["data"]["version"] ?? "Unknown";
return [
"success" => true,
"message" => sprintf(
"Connection successful! KeyHelp Version: %s",
$version,
),
];
} catch (\Exception $e) {
return ["success" => false, "error" => $e->getMessage()];
}
}
// Helper Functions
function _keyhelpmanager_GenerateUsername(string $domain): string
{
$username = preg_replace('/\.[^.]+$/', "", $domain);
$username = preg_replace("/[^a-z0-9]/i", "", $username);
$username = strtolower(substr($username, 0, 16));
if (strlen($username) < 6) {
$username .= rand(1000, 9999);
}
return $username;
}
function _keyhelpmanager_GeneratePassword(int $length = 16): string
{
$chars =
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_=+';
$password = "";
$charsLength = strlen($chars);
for ($i = 0; $i < $length; $i++) {
$password .= $chars[random_int(0, $charsLength - 1)];
}
return $password;
}
function _keyhelpmanager_SaveAccountDetails(
int $serviceId,
array $details,
): void {
try {
foreach ($details as $key => $value) {
if ($key === "username" || $key === "password") {
Capsule::table("tblhosting")
->where("id", $serviceId)
->update([$key => $value]);
}
}
if (isset($details["userid"])) {
Capsule::table("tblcustomfieldsvalues")->updateOrInsert(
[
"relid" => $serviceId,
"fieldid" => _keyhelpmanager_GetCustomFieldId(
"KeyHelp User ID",
),
],
["value" => $details["userid"]],
);
}
} catch (\Exception $e) {
logActivity(
"KeyHelpManager: Save account details failed - " . $e->getMessage(),
);
}
}
function _keyhelpmanager_GetAccountDetails(int $serviceId): array
{
try {
$service = Capsule::table("tblhosting")
->where("id", $serviceId)
->first();
$userid = Capsule::table("tblcustomfieldsvalues")
->where("relid", $serviceId)
->where(
"fieldid",
_keyhelpmanager_GetCustomFieldId("KeyHelp User ID"),
)
->value("value");
return [
"username" => $service->username ?? "",
"password" => decrypt($service->password ?? ""),
"userid" => $userid ?? null,
];
} catch (\Exception $e) {
logActivity(
"KeyHelpManager: Get account details failed - " . $e->getMessage(),
);
return [];
}
}
function _keyhelpmanager_GetUserId(array $params): ?int
{
$accountDetails = _keyhelpmanager_GetAccountDetails($params["serviceid"]);
return $accountDetails["userid"] ?? null;
}
function _keyhelpmanager_UpdateAccountDetail(
int $serviceId,
string $field,
string $value,
): void {
try {
if ($field === "username" || $field === "password") {
Capsule::table("tblhosting")
->where("id", $serviceId)
->update([$field => $value]);
}
} catch (\Exception $e) {
logActivity(
"KeyHelpManager: Update account detail failed - " .
$e->getMessage(),
);
}
}
function _keyhelpmanager_DeleteAccountDetails(int $serviceId): void
{
try {
Capsule::table("tblcustomfieldsvalues")
->where("relid", $serviceId)
->delete();
} catch (\Exception $e) {
logActivity(
"KeyHelpManager: Delete account details failed - " .
$e->getMessage(),
);
}
}
function _keyhelpmanager_GetCustomFieldId(string $fieldName): int
{
try {
$field = Capsule::table("tblcustomfields")
->where("fieldname", $fieldName)
->where("type", "product")
->first();
if (!$field) {
return Capsule::table("tblcustomfields")->insertGetId([
"type" => "product",
"fieldname" => $fieldName,
"fieldtype" => "text",
"description" => "",
"adminonly" => "on",
]);
}
return $field->id;
} catch (\Exception $e) {
logActivity(
"KeyHelpManager: Get custom field ID failed - " . $e->getMessage(),
);
return 0;
}
}
function _keyhelpmanager_FormatBytes(int $bytes): string
{
$units = ["B", "KB", "MB", "GB", "TB"];
$power = $bytes > 0 ? floor(log($bytes, 1024)) : 0;
return number_format($bytes / pow(1024, $power), 2, ".", ",") .
" " .
$units[$power];
}
function _keyhelpmanager_CalculatePercent(int $used, int $limit): float
{
return $limit > 0 ? round(($used / $limit) * 100, 2) : 0;
}