mirror of
https://github.com/stefanpejcic/openpanel
synced 2025-06-26 18:28:26 +00:00
539 lines
17 KiB
PHP
539 lines
17 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Copyright 2022-2024 FOSSBilling
|
|
* Copyright 2011-2021 BoxBilling, Inc.
|
|
* SPDX-License-Identifier: Apache-2.0.
|
|
*
|
|
* @copyright FOSSBilling (https://www.fossbilling.org)
|
|
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache-2.0
|
|
*/
|
|
|
|
use Random\RandomException;
|
|
use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface;
|
|
|
|
/**
|
|
* OpenPanel API.
|
|
*
|
|
* @see https://dev.openpanel.co/api/
|
|
*/
|
|
class Server_Manager_Openpanel extends Server_Manager
|
|
{
|
|
/**
|
|
* Returns the form configuration for the OpenPanel server manager.
|
|
*
|
|
* @return array the form configuration as an associative array
|
|
*/
|
|
public static function getForm(): array
|
|
{
|
|
return [
|
|
'label' => 'OpenPanel',
|
|
'form' => [
|
|
'credentials' => [
|
|
'fields' => [
|
|
[
|
|
'name' => 'username',
|
|
'type' => 'text',
|
|
'label' => 'Username',
|
|
'placeholder' => 'Username used to connect to the server',
|
|
'required' => true,
|
|
],
|
|
[
|
|
'name' => 'password',
|
|
'type' => 'text',
|
|
'label' => 'Password / Login Key',
|
|
'placeholder' => 'Password or login key used to connect to the server',
|
|
'required' => true,
|
|
],
|
|
],
|
|
],
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Initializes the OpenPanel server manager.
|
|
* Checks if the necessary configuration options are set and throws an exception if any are missing.
|
|
*
|
|
* @throws Server_Exception if any necessary configuration options are missing
|
|
*/
|
|
public function init(): void
|
|
{
|
|
if (empty($this->_config['host'])) {
|
|
throw new Server_Exception('The ":server_manager" server manager is not fully configured. Please configure the :missing', [':server_manager' => 'OpenPanel', ':missing' => 'hostname'], 2001);
|
|
}
|
|
|
|
if (empty($this->_config['username'])) {
|
|
throw new Server_Exception('The ":server_manager" server manager is not fully configured. Please configure the :missing', [':server_manager' => 'OpenPanel', ':missing' => 'username'], 2001);
|
|
}
|
|
|
|
if (empty($this->_config['password']) && empty($this->_config['accesshash'])) {
|
|
throw new Server_Exception('The ":server_manager" server manager is not fully configured. Please configure the :missing', [':server_manager' => 'OpenPanel', ':missing' => 'authentication credentials'], 2001);
|
|
}
|
|
|
|
// If port not set, use OpenPanel default.
|
|
$this->_config['port'] = empty($this->_config['port']) ? '2087' : $this->_config['port'];
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function getAuthToken() {
|
|
$apiProtocol = $this->_config['secure'] ? 'https://' : 'http://';
|
|
$host = $this->_config['host'];
|
|
$username = $this->_config['username'];
|
|
$password = $this->_config['password'];
|
|
$authEndpoint = $apiProtocol . $host . ':' . $this->getPort() . '/api/';
|
|
|
|
// Prepare cURL request to authenticate
|
|
$curl = curl_init();
|
|
curl_setopt_array($curl, array(
|
|
CURLOPT_URL => $authEndpoint,
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_POST => true,
|
|
CURLOPT_POSTFIELDS => json_encode(array(
|
|
'username' => $username,
|
|
'password' => $password
|
|
)),
|
|
CURLOPT_HTTPHEADER => array(
|
|
"Content-Type: application/json"
|
|
),
|
|
));
|
|
|
|
// Execute cURL request to authenticate
|
|
$response = curl_exec($curl);
|
|
|
|
// Check for errors
|
|
if (curl_errno($curl)) {
|
|
$token = false;
|
|
$error = "cURL Error: " . curl_error($curl);
|
|
} else {
|
|
// Decode the response JSON to get the token
|
|
$responseData = json_decode($response, true);
|
|
$token = isset($responseData['access_token']) ? $responseData['access_token'] : false;
|
|
$error = $token ? null : "Token not found in response";
|
|
}
|
|
|
|
// Close cURL session
|
|
curl_close($curl);
|
|
|
|
return $token;
|
|
}
|
|
|
|
function makeApiRequest($endpoint, $data = null, $method = 'GET') {
|
|
$apiProtocol = $this->_config['secure'] ? 'https://' : 'http://';
|
|
$host = $this->_config['host'];
|
|
$baseUrl = $apiProtocol . $host . ':' . $this->getPort() . '/api/';
|
|
|
|
|
|
|
|
$url = $baseUrl . $endpoint;
|
|
|
|
$token = $this->getAuthToken();
|
|
|
|
if (!$token) {
|
|
error_log("Failed to retrieve auth token");
|
|
return false;
|
|
}
|
|
|
|
$curl = curl_init();
|
|
|
|
curl_setopt_array($curl, array(
|
|
CURLOPT_URL => $url,
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_ENCODING => '',
|
|
CURLOPT_MAXREDIRS => 10,
|
|
CURLOPT_TIMEOUT => 0,
|
|
CURLOPT_FOLLOWLOCATION => true,
|
|
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
|
|
CURLOPT_CUSTOMREQUEST => $method,
|
|
CURLOPT_POSTFIELDS => $data,
|
|
CURLOPT_HTTPHEADER => array(
|
|
'Content-Type: application/json',
|
|
'Authorization: Bearer ' . $token
|
|
),
|
|
));
|
|
|
|
|
|
|
|
$response = curl_exec($curl);
|
|
|
|
curl_close($curl);
|
|
|
|
return $response;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
* Returns the login URL for a OpenPanel account.
|
|
*
|
|
* @param Server_Account|null $account The account for which to get the login URL. This parameter is currently not used.
|
|
*
|
|
* @return string the login URL
|
|
*/
|
|
public function getLoginUrl(Server_Account $account = null): string
|
|
{
|
|
$host = $this->_config['host'];
|
|
$protocol = $this->_config['secure'] ? 'https://' : 'http://';
|
|
|
|
return $protocol . $host . ':2083';
|
|
}
|
|
|
|
/**
|
|
* Returns the login URL for a OpenAdmin reseller account.
|
|
*
|
|
* @param Server_Account|null $account The account for which to get the login URL. This parameter is currently not used.
|
|
*
|
|
* @return string the login URL
|
|
*/
|
|
public function getResellerLoginUrl(Server_Account $account = null): string
|
|
{
|
|
$host = $this->_config['host'];
|
|
$protocol = $this->_config['secure'] ? 'https://' : 'http://';
|
|
$url = $protocol . $this->_config['host'] . ':' . $this->getPort() . '/api/';
|
|
|
|
return $protocol . $host . ':2087';
|
|
}
|
|
|
|
# OpenAdmin can use custom port
|
|
public function getPort(): int|string
|
|
{
|
|
$port = $this->_config['port'];
|
|
|
|
if (filter_var($port, FILTER_VALIDATE_INT) !== false && $port >= 0 && $port <= 65535) {
|
|
return $this->_config['port'];
|
|
} else {
|
|
return 2087;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
* Tests the connection to the OpenPanel server.
|
|
* Sends a request to the OpenPanel server to get its version.
|
|
*
|
|
* @return true if the connection was successful
|
|
*
|
|
* @throws Server_Exception if an error occurs during the request
|
|
*/
|
|
public function testConnection(): bool
|
|
{
|
|
|
|
|
|
$response = $this->makeApiRequest(null);
|
|
$response = json_decode($response);
|
|
|
|
if($response->message === "API is working!") {
|
|
return true;
|
|
}
|
|
throw new Server_Exception('Can\'t connect to the server');
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Generates a username for a new account on the OpenPanel server.
|
|
* The username is generated based on the domain name, with some modifications to comply with OpenPanel's username restrictions.
|
|
*
|
|
* @param string $domain the domain name for which to generate a username
|
|
*
|
|
* @return string the generated username
|
|
*
|
|
* @throws RandomException if an error occurs during the generation of a random number
|
|
*/
|
|
public function generateUsername(string $domain): string
|
|
{
|
|
$processedDomain = strtolower(preg_replace('/[^A-Za-z0-9]/', '', $domain));
|
|
$username = substr($processedDomain, 0, 7) . random_int(0, 9);
|
|
|
|
// OpenPanel doesn't allow usernames to start with "test", so replace it with a random string if it does (test3456 would then become something like a62f93456).
|
|
if (str_starts_with($username, 'test')) {
|
|
$username = substr_replace($username, 'a' . bin2hex(random_bytes(2)), 0, 5);
|
|
}
|
|
|
|
return $username;
|
|
}
|
|
|
|
/**
|
|
* Synchronizes an account with the OpenPanel server.
|
|
* Sends a request to the OpenPanel server to get the account's details and updates the Server_Account object accordingly.
|
|
*
|
|
* @param Server_Account $account the account to be synchronized
|
|
*
|
|
* @return Server_Account the updated account
|
|
*
|
|
* @throws Server_Exception if an error occurs during the request, or if the account does not exist on the OpenPanel server
|
|
*/
|
|
public function synchronizeAccount(Server_Account $account)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Creates a new account on the OpenPanel server.
|
|
* Sends a request to the OpenPanel server to create a new account with the details provided in the Server_Account object.
|
|
* If the account is a reseller account, it also sets up the reseller and assigns the appropriate ACL list.
|
|
*
|
|
* @param Server_Account $account The account to be created. This object should contain all the necessary details for the new account.
|
|
*
|
|
* @return bool returns true if the account was successfully created, false otherwise
|
|
*
|
|
* @throws Server_Exception if an error occurs during the request, or if the response from the OpenPanel server indicates an error
|
|
*/
|
|
public function createAccount(Server_Account $account)
|
|
{
|
|
$client = $account->getClient();
|
|
$package = $account->getPackage();
|
|
$this->getLog()->info('Creating account ' . $client->getUsername());
|
|
$data = json_encode(array(
|
|
"email" => $client->getEmail(),
|
|
'username' => $account->getUsername(),
|
|
'password' => $account->getPassword(),
|
|
"plan_name" => $package->getName()
|
|
|
|
));
|
|
|
|
$response = $this->makeApiRequest("users" , $data, 'POST');
|
|
$response = json_decode($response);
|
|
|
|
|
|
if (!empty($response->success)) {
|
|
return true;
|
|
|
|
}
|
|
|
|
throw new Server_Exception('Error when creating ' . $client->getUsername() . ': ' . $response->error);
|
|
|
|
}
|
|
|
|
/**
|
|
* Suspends an account on the OpenPanel server.
|
|
*
|
|
* @param Server_Account $account the account to be suspended
|
|
*
|
|
* @return bool returns true if the account was successfully suspended
|
|
*
|
|
* @throws Server_Exception if an error occurs during the request
|
|
*/
|
|
public function suspendAccount(Server_Account $account): bool
|
|
{
|
|
// Log the suspension
|
|
$this->getLog()->info('Suspending account ' . $account->getUsername());
|
|
|
|
$client = $account->getClient();
|
|
|
|
$data = json_encode(array("action" => "suspend"));
|
|
$response = $this->makeApiRequest("users/" . $account->getUsername() , $data, 'PATCH');
|
|
$response = json_decode($response);
|
|
|
|
if ($response->success == 1 || $response->success == true ) {
|
|
return true;
|
|
|
|
}
|
|
|
|
throw new Server_Exception('Error when suspending ' . $client->getUsername() . ': ' . json_encode($response));
|
|
|
|
}
|
|
|
|
/**
|
|
* Unsuspends an account on the OpenPanel server.
|
|
*
|
|
* @param Server_Account $account the account to be unsuspended
|
|
*
|
|
* @return bool returns true if the account was successfully unsuspended
|
|
*
|
|
* @throws Server_Exception if an error occurs during the request
|
|
*/
|
|
public function unsuspendAccount(Server_Account $account): bool
|
|
{
|
|
// Log the unsuspension
|
|
$this->getLog()->info('Activating account ' . $account->getUsername());
|
|
|
|
$client = $account->getClient();
|
|
|
|
$data = json_encode(array("action" => "unsuspend"));
|
|
$response = $this->makeApiRequest("users/". $account->getUsername() , $data, 'PATCH');
|
|
$response = json_decode($response);
|
|
|
|
if ($response->success == 1 || $response->success == true ) {
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
throw new Server_Exception('Failed to unsuspend ' . $client->getUsername() . ': ' . $response->error);
|
|
|
|
}
|
|
|
|
/**
|
|
* Cancels an account on the OpenPanel server.
|
|
*
|
|
* @param Server_Account $account the account to be cancelled
|
|
*
|
|
* @return bool returns true if the account was successfully cancelled
|
|
*
|
|
* @throws Server_Exception if an error occurs during the request
|
|
*/
|
|
public function cancelAccount(Server_Account $account): bool
|
|
{
|
|
// Log the cancellation
|
|
$this->getLog()->info('Canceling account ' . $account->getUsername());
|
|
|
|
$response = $this->makeApiRequest(endpoint: "users/". $account->getUsername(), method: 'DELETE');
|
|
$response = json_decode($response);
|
|
|
|
if ($response->success) {
|
|
return true;
|
|
|
|
}
|
|
$client = $account->getClient();
|
|
|
|
|
|
throw new Server_Exception('Failed to canceling ' . $client->getUsername() . ': ' . $response->error);
|
|
|
|
}
|
|
|
|
/**
|
|
* Changes the package of an account on the OpenPanel server.
|
|
*
|
|
* @param Server_Account $account the account for which to change the package
|
|
* @param Server_Package $package the new package
|
|
*
|
|
* @return bool returns true if the package was successfully changed
|
|
*
|
|
* @throws Server_Exception if an error occurs during the request
|
|
*/
|
|
public function changeAccountPackage(Server_Account $account, Server_Package $package)
|
|
{
|
|
|
|
// Log the package change
|
|
$this->getLog()->info('Changing account ' . $account->getUsername() . ' package');
|
|
$data = json_encode(array("plan_name" => $package->getName()));
|
|
|
|
$response = $this->makeApiRequest("users/". $account->getUsername(),$data , 'PUT');
|
|
$response = json_decode($response);
|
|
|
|
if ($response->success) {
|
|
return true;
|
|
|
|
}
|
|
$client = $account->getClient();
|
|
|
|
|
|
throw new Server_Exception('Failed to change package for user ' . $client->getUsername() . ' | Error: ' . $response->error);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
/**
|
|
* Changes the password of an account on the OpenPanel server.
|
|
*
|
|
* @param Server_Account $account the account for which to change the password
|
|
* @param string $newPassword the new password
|
|
*
|
|
* @return bool returns true if the password was successfully changed
|
|
*
|
|
* @throws Server_Exception if an error occurs during the request
|
|
*/
|
|
public function changeAccountPassword(Server_Account $account, string $newPassword)
|
|
{
|
|
// Log the password change
|
|
$this->getLog()->info('Changing account ' . $account->getUsername() . ' password');
|
|
|
|
$data = json_encode(array("password" => $newPassword));
|
|
|
|
$response = $this->makeApiRequest("users/". $account->getUsername(),$data , 'PATCH');
|
|
$response = json_decode($response);
|
|
|
|
if ($response->success) {
|
|
return true;
|
|
|
|
}
|
|
$client = $account->getClient();
|
|
|
|
|
|
throw new Server_Exception('Failed to change package for user ' . $client->getUsername() . ' | Error: ' . $response->error);
|
|
}
|
|
|
|
/**
|
|
* Changes the username of an account on the OpenPanel server.
|
|
*
|
|
* @param Server_Account $account the account for which to change the username
|
|
* @param string $newUsername the new username
|
|
*
|
|
* @return bool returns true if the username was successfully changed
|
|
*
|
|
* @throws Server_Exception if an error occurs during the request
|
|
*/
|
|
public function changeAccountUsername(Server_Account $account, string $newUsername): bool
|
|
{
|
|
throw new Server_Exception('OpenPanel does not supporting changing username');
|
|
}
|
|
|
|
/**
|
|
* Changes the domain of an account on the OpenPanel server.
|
|
*
|
|
* @param Server_Account $account the account for which to change the domain
|
|
* @param string $newDomain the new domain
|
|
*
|
|
* @return bool returns true if the domain was successfully changed
|
|
*
|
|
* @throws Server_Exception if an error occurs during the request
|
|
*/
|
|
public function changeAccountDomain(Server_Account $account, string $newDomain): bool
|
|
{
|
|
throw new Server_Exception('OpenPanel does not supporting account domain');
|
|
|
|
}
|
|
|
|
/**
|
|
* Changes the IP of an account on the OpenPanel server.
|
|
*
|
|
* @param Server_Account $account the account for which to change the IP
|
|
* @param string $newIp the new IP
|
|
*
|
|
* @return bool returns true if the IP was successfully changed
|
|
*
|
|
* @throws Server_Exception if an error occurs during the request
|
|
*/
|
|
public function changeAccountIp(Server_Account $account, string $newIp): bool
|
|
{
|
|
throw new Server_Exception('OpenPanel does not supporting change account IP');
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|