mirror of
https://github.com/FOSSBilling/FOSSBilling.git
synced 2026-11-05 11:37:31 +09:00
* Fix WHM reseller accounts always getting an empty ACL list Server_Manager_Whm::createAccount() called $package->getAcllist(), but Server_Package has never had that method. Its __call() silently swallows calls to undefined methods and returns '', so every reseller account created via WHM had setacls called with an empty acllist - wiping out the initial privileges WHM had just granted via setupreseller. Wire the ACL list through the existing custom-value mechanism instead (same pattern already used for cgi, cpmod, maxlst, hasshell), and skip the setacls call entirely when the hosting plan defines no 'acl' custom value, so the reseller keeps WHM's default privileges instead of having them stripped. Fixes #4173 * Whitelist WHM API action names for cspell src/library/Server/Manager/** is excluded from spellcheck entirely, so Whm.php's own use of these WHM API1 action/field names never tripped the checker. tests/Unit/Server/Manager/WhmTest.php isn't under that exclusion, so add the same words DirectAdmin's custom-value keys already use this pattern for (listpkgs, addpkg, createacct, setupreseller, setacls, acllist) to cspell.json's ignoreWords.
103 lines
3.8 KiB
PHP
103 lines
3.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use Symfony\Component\HttpClient\MockHttpClient;
|
|
use Symfony\Component\HttpClient\Response\MockResponse;
|
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
|
|
|
function createWhmManager(HttpClientInterface $httpClient): Server_Manager_Whm
|
|
{
|
|
return new class(['host' => 'whm.example.com', 'username' => 'admin', 'password' => 'secret'], $httpClient) extends Server_Manager_Whm {
|
|
public function __construct(array $options, private readonly HttpClientInterface $httpClient)
|
|
{
|
|
parent::__construct($options);
|
|
}
|
|
|
|
public function getHttpClient(): HttpClientInterface
|
|
{
|
|
return $this->httpClient;
|
|
}
|
|
};
|
|
}
|
|
|
|
function createWhmAccount(Server_Package $package, bool $reseller): Server_Account
|
|
{
|
|
return (new Server_Account())
|
|
->setUsername('example')
|
|
->setDomain('example.com')
|
|
->setPassword('secret')
|
|
->setClient((new Server_Client())->setEmail('client@example.com'))
|
|
->setPackage($package)
|
|
->setReseller($reseller);
|
|
}
|
|
|
|
function actionOf(array $request): string
|
|
{
|
|
return basename((string) parse_url($request['url'], PHP_URL_PATH));
|
|
}
|
|
|
|
function createWhmAccountCreationClient(array &$requests): MockHttpClient
|
|
{
|
|
return new MockHttpClient(function (string $method, string $url, array $options) use (&$requests): MockResponse {
|
|
$requests[] = ['method' => $method, 'url' => $url, 'options' => $options];
|
|
|
|
if (str_contains($url, 'listpkgs')) {
|
|
return new MockResponse(json_encode(['package' => []]));
|
|
}
|
|
|
|
if (str_contains($url, 'createacct')) {
|
|
return new MockResponse(json_encode(['result' => [['status' => 1]]]));
|
|
}
|
|
|
|
return new MockResponse(json_encode(['status' => 1]));
|
|
});
|
|
}
|
|
|
|
test('createAccount sets up the reseller but does not touch the ACL list when the plan has no acl custom value', function (): void {
|
|
$requests = [];
|
|
$manager = createWhmManager(createWhmAccountCreationClient($requests));
|
|
$account = createWhmAccount(new Server_Package(), true);
|
|
|
|
expect($manager->createAccount($account))->toBeTrue();
|
|
|
|
$actions = array_map(actionOf(...), $requests);
|
|
|
|
// Calling "setacls" with an empty acllist would strip the initial privileges "setupreseller"
|
|
// just granted, so it must be skipped when the plan has no 'acl' custom value.
|
|
expect($actions)->toBe(['listpkgs', 'addpkg', 'createacct', 'setupreseller'])
|
|
->and($actions)->not->toContain('setacls');
|
|
});
|
|
|
|
test('createAccount assigns the plan\'s acl custom value to the reseller via setacls', function (): void {
|
|
$requests = [];
|
|
$manager = createWhmManager(createWhmAccountCreationClient($requests));
|
|
$package = (new Server_Package())->setCustomValues(['acl' => 'reseller_basic']);
|
|
$account = createWhmAccount($package, true);
|
|
|
|
expect($manager->createAccount($account))->toBeTrue();
|
|
|
|
$actions = array_map(actionOf(...), $requests);
|
|
expect($actions)->toBe(['listpkgs', 'addpkg', 'createacct', 'setupreseller', 'setacls']);
|
|
|
|
$setaclsRequest = $requests[array_search('setacls', $actions, true)];
|
|
parse_str((string) $setaclsRequest['options']['body'], $fields);
|
|
|
|
expect($fields)->toMatchArray([
|
|
'reseller' => 'example',
|
|
'acllist' => 'reseller_basic',
|
|
]);
|
|
});
|
|
|
|
test('createAccount never calls setupreseller or setacls for a non-reseller account', function (): void {
|
|
$requests = [];
|
|
$manager = createWhmManager(createWhmAccountCreationClient($requests));
|
|
$package = (new Server_Package())->setCustomValues(['acl' => 'reseller_basic']);
|
|
$account = createWhmAccount($package, false);
|
|
|
|
expect($manager->createAccount($account))->toBeTrue();
|
|
|
|
$actions = array_map(actionOf(...), $requests);
|
|
expect($actions)->toBe(['listpkgs', 'addpkg', 'createacct']);
|
|
});
|