bugfixed on setup

This commit is contained in:
tracer 2024-04-05 17:17:33 +02:00
parent 3571e7888f
commit 192a5a2234
12 changed files with 463 additions and 520 deletions

View File

@ -100,6 +100,7 @@
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-grapheme" /> <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-grapheme" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/property-info" /> <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/property-info" />
<excludeFolder url="file://$MODULE_DIR$/vendor/netresearch/jsonmapper" /> <excludeFolder url="file://$MODULE_DIR$/vendor/netresearch/jsonmapper" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/deprecation-contracts" />
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />

View File

@ -22,7 +22,6 @@
<option name="CUSTOM_RULESET_PATH" value="$PROJECT_DIR$/phpcs.xml.dist" /> <option name="CUSTOM_RULESET_PATH" value="$PROJECT_DIR$/phpcs.xml.dist" />
<option name="USE_INSTALLED_PATHS" value="true" /> <option name="USE_INSTALLED_PATHS" value="true" />
<option name="INSTALLED_PATHS" value="$PROJECT_DIR$/vendor/doctrine/coding-standard/lib/Doctrine" /> <option name="INSTALLED_PATHS" value="$PROJECT_DIR$/vendor/doctrine/coding-standard/lib/Doctrine" />
<option name="EXTENSIONS" value="php,js,css,inc" />
</inspection_tool> </inspection_tool>
<inspection_tool class="PhpCastIsUnnecessaryInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" /> <inspection_tool class="PhpCastIsUnnecessaryInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="PhpClassNamingConventionInspection" enabled="true" level="WARNING" enabled_by_default="true"> <inspection_tool class="PhpClassNamingConventionInspection" enabled="true" level="WARNING" enabled_by_default="true">
@ -39,7 +38,7 @@
<option name="m_minLength" value="2" /> <option name="m_minLength" value="2" />
<option name="m_maxLength" value="48" /> <option name="m_maxLength" value="48" />
</inspection_tool> </inspection_tool>
<inspection_tool class="PhpMissingDocCommentInspection" enabled="true" level="WARNING" enabled_by_default="true" /> <inspection_tool class="PhpMissingDocCommentInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="PhpNamedArgumentUsageInspection" enabled="false" level="WARNING" enabled_by_default="false" /> <inspection_tool class="PhpNamedArgumentUsageInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="PhpNamedArgumentsWithChangedOrderInspection" enabled="true" level="WARNING" enabled_by_default="true" editorAttributes="WARNING_ATTRIBUTES" /> <inspection_tool class="PhpNamedArgumentsWithChangedOrderInspection" enabled="true" level="WARNING" enabled_by_default="true" editorAttributes="WARNING_ATTRIBUTES" />
<inspection_tool class="PhpNoReturnAttributeCanBeAddedInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" /> <inspection_tool class="PhpNoReturnAttributeCanBeAddedInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />

View File

@ -81,6 +81,7 @@
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-grapheme" /> <path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-grapheme" />
<path value="$PROJECT_DIR$/vendor/symfony/property-info" /> <path value="$PROJECT_DIR$/vendor/symfony/property-info" />
<path value="$PROJECT_DIR$/vendor/netresearch/jsonmapper" /> <path value="$PROJECT_DIR$/vendor/netresearch/jsonmapper" />
<path value="$PROJECT_DIR$/vendor/symfony/deprecation-contracts" />
</include_path> </include_path>
</component> </component>
<component name="PhpProjectSharedConfiguration" php_language_level="8.1"> <component name="PhpProjectSharedConfiguration" php_language_level="8.1">

View File

@ -3,11 +3,6 @@
namespace App\Controller; namespace App\Controller;
// & ~E_DEPRECATED is needed because of a bug in PhpStorm
use DI\DependencyException;
use DI\NotFoundException;
use Exception;
if (php_sapi_name() !== 'cli') { if (php_sapi_name() !== 'cli') {
echo 'This application must be run on the command line.' . PHP_EOL; echo 'This application must be run on the command line.' . PHP_EOL;
exit; exit;

View File

@ -2,7 +2,7 @@
"name": "24unix/bindapi", "name": "24unix/bindapi",
"description": "manage Bind9 DNS server via REST API", "description": "manage Bind9 DNS server via REST API",
"version": "2023.0.1", "version": "2023.0.1",
"build_number": "324", "build_number": "325",
"authors": [ "authors": [
{ {
"name": "Micha Espey", "name": "Micha Espey",

829
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -57,7 +57,7 @@ class CLIController
private readonly EncryptionController $encryptionController, private readonly EncryptionController $encryptionController,
private $logger) private $logger)
{ {
$this->runCheckSetup(); // FIXME needs to be elsewhere $this->runCheckSetup();
$this->commandGroupContainer = (new CommandGroupContainer()) $this->commandGroupContainer = (new CommandGroupContainer())
->addCommandGroup(commandGroup: (new CommandGroup(name: 'check', description: 'health checks the system can perform')) ->addCommandGroup(commandGroup: (new CommandGroup(name: 'check', description: 'health checks the system can perform'))
@ -264,7 +264,8 @@ class CLIController
function runCheckSetup(): void function runCheckSetup(): void
{ {
if (!$this->domainController->checkPermissions(quiet: true)) { if (!$this->domainController->checkPermissions(quiet: true)) {
echo COLOR_RED . 'You need to setup the bindAPI first.' . COLOR_DEFAULT .PHP_EOL; echo COLOR_RED . 'You need to setup the bindAPI permission first.' . COLOR_DEFAULT .PHP_EOL;
echo 'Run ' . COLOR_YELLOW . './bin/console check:setup' . COLOR_DEFAULT . ' as root or with sudo.' . PHP_EOL;
} }
$self = $this->panelRepository->findSelf(); $self = $this->panelRepository->findSelf();
@ -355,15 +356,17 @@ class CLIController
echo 'You need to supply a username.' . PHP_EOL; echo 'You need to supply a username.' . PHP_EOL;
exit(1); exit(1);
} }
$username = $this->arguments[1];
$uid = posix_getuid(); $uid = posix_getuid();
if ($uid != 0) { if ($uid != 0) {
echo 'You need to run this as root or with sudo.' . PHP_EOL; echo 'You need to run this as root or with sudo.' . PHP_EOL;
exit(1); exit(1);
} }
$username = $this->arguments[1];
// deluser tracer bind if (!$impersonatedUser = posix_getpwnam(username: $username)) {
// adduser tracer bind echo 'Cannot find user: ' . $username . PHP_EOL;
exit(1);
}
$impersonatedUserId = $impersonatedUser['uid'];
// add user to group bind // add user to group bind
exec(command: "adduser $username bind", output: $output, result_code: $return); exec(command: "adduser $username bind", output: $output, result_code: $return);
@ -391,12 +394,20 @@ class CLIController
echo " done." . PHP_EOL; echo " done." . PHP_EOL;
} }
} }
} else {
// check /etc/bind/local.zones permissions
echo 'Found ' . COLOR_YELLOW . $this->domainController->localZoneFile . COLOR_DEFAULT . '.' . PHP_EOL;
echo 'Check permissions for ' . COLOR_YELLOW . $this->domainController->localZoneFile . COLOR_DEFAULT . ' …' ;
// dont repeat yourself, use check from DomainController FIXME
$this->domainController->checkPermissions(impersonatedUserId: $impersonatedUserId);
} }
// /etc/bind/local.zones file must be included in /etc/bind/named.conf.local // /etc/bind/local.zones file must be included in /etc/bind/named.conf.local
$namedConfLocal = file_get_contents(filename: $this->domainController->namedConfLocalFile); $namedConfLocal = file_get_contents(filename: $this->domainController->namedConfLocalFile);
if (str_contains(haystack: $namedConfLocal, needle: $this->domainController->localZoneFile)) { if (str_contains(haystack: $namedConfLocal, needle: $this->domainController->localZoneFile)) {
echo 'Found ' . COLOR_YELLOW . $this->domainController->localZoneFile . COLOR_DEFAULT . ' in ' . COLOR_YELLOW . $this->domainController->namedConfLocalFile . COLOR_DEFAULT . '.' . PHP_EOL; echo 'Found ' . COLOR_YELLOW . $this->domainController->localZoneFile . COLOR_DEFAULT . ' included ' . COLOR_YELLOW . $this->domainController->namedConfLocalFile . COLOR_DEFAULT . '.' . PHP_EOL;
} else { } else {
echo 'Could not find ' . COLOR_YELLOW . $this->domainController->localZoneFile . COLOR_DEFAULT . ' in ' . COLOR_YELLOW . $this->domainController->namedConfLocalFile . COLOR_DEFAULT . '.' . PHP_EOL; echo 'Could not find ' . COLOR_YELLOW . $this->domainController->localZoneFile . COLOR_DEFAULT . ' in ' . COLOR_YELLOW . $this->domainController->namedConfLocalFile . COLOR_DEFAULT . '.' . PHP_EOL;
echo 'Adding …'; echo 'Adding …';
@ -413,7 +424,7 @@ class CLIController
// check /etc/bind/zones exists // check /etc/bind/zones exists
echo 'Check for ' . COLOR_YELLOW . $this->domainController->localZonesDir . COLOR_DEFAULT . ' …'; echo 'Check for ' . COLOR_YELLOW . $this->domainController->localZonesDir . COLOR_DEFAULT . ' …';
if (is_dir(filename: $this->domainController->localZonesDir)) { if (is_dir(filename: $this->domainController->localZonesDir)) {
echo " done." . PHP_EOL; echo " exists." . PHP_EOL;
} else { } else {
echo ' Could not find ' . COLOR_YELLOW . $this->domainController->localZonesDir . COLOR_DEFAULT . '.' . PHP_EOL; echo ' Could not find ' . COLOR_YELLOW . $this->domainController->localZonesDir . COLOR_DEFAULT . '.' . PHP_EOL;
echo 'Creating …'; echo 'Creating …';
@ -428,6 +439,7 @@ class CLIController
echo " done." . PHP_EOL; echo " done." . PHP_EOL;
} }
} }
} }

View File

@ -55,14 +55,28 @@ class CommandGroup
return null; return null;
} }
private function findCommandGroupByName(string $command)
{
echo 'in check';
foreach ($this->commands as $currentCommand) {
print_r($currentCommand->getName());
if ($currentCommand instanceof CommandGroup) {
if ($command === $currentCommand->getName()) {
return $currentCommand;
}
}
}
return false;
}
public function exec(string $subcommand): void public function exec(string $subcommand): bool
{ {
if ($command = $this->findCommandByName(command: $subcommand)) { if ($command = $this->findCommandByName(command: $subcommand)) {
$command->exec(); $command->exec();
return true;
} else { } else {
echo COLOR_DEFAULT . 'Command ' . COLOR_YELLOW . $this->name . ':' . $subcommand . COLOR_DEFAULT . ' not found.' . PHP_EOL; return false;
exit(1);
} }
} }
} }

View File

@ -63,11 +63,25 @@ class CommandGroupContainer
public function run(string $command, string $subcommand): void public function run(string $command, string $subcommand): void
{ {
if ($subcommand !== '') {
if ($group = $this->findGroupByName(command: $command)) { if ($group = $this->findGroupByName(command: $command)) {
$group->exec(subcommand: $subcommand); if ($group->exec(subcommand: $subcommand)) {
exit(0);
}
} else { } else {
echo COLOR_DEFAULT . 'Unknown subcommand ' . COLOR_YELLOW . $command . ' for ' . $command . COLOR_DEFAULT . '.' . PHP_EOL;
}
} else {
// check for command group and print available commands
foreach ($this->commandGroups as $group) {
echo 'Available subcommands for : ' . COLOR_YELLOW . $group->getName() . COLOR_DEFAULT . ':' . PHP_EOL;
if ($group->getName() === $command) {
$group->printCommands(strlen(string: $group->getName()));
exit(0);
}
}
}
echo COLOR_DEFAULT . 'Unknown command ' . COLOR_YELLOW . $command . COLOR_DEFAULT . '.' . PHP_EOL; echo COLOR_DEFAULT . 'Unknown command ' . COLOR_YELLOW . $command . COLOR_DEFAULT . '.' . PHP_EOL;
exit(1);
}
} }
} }

View File

@ -7,6 +7,7 @@ namespace App\Controller;
use PDO; use PDO;
use PDOException; use PDOException;
use PHPUnit\Exception;
/** /**
* *
@ -30,11 +31,17 @@ class DatabaseConnection
$dbUser = $this->configController->getConfig(configKey: 'dbUser'); $dbUser = $this->configController->getConfig(configKey: 'dbUser');
$dbPassword = $this->configController->getConfig(configKey: 'dbPassword'); $dbPassword = $this->configController->getConfig(configKey: 'dbPassword');
try {
$this->dbConnection = new PDO( $this->dbConnection = new PDO(
dsn: "mysql:host=$dbHost;port=$dbPort;charset=utf8mb4;dbname=$dbDatabase", dsn: "mysql:host=$dbHost;port=$dbPort;charset=utf8mb4;dbname=$dbDatabase",
username: $dbUser, username: $dbUser,
password: $dbPassword password: $dbPassword
); );
} catch (Exception $e) {
echo $e->getMessage() . PHP_EOL;
echo 'Did you create the database and adjust the config file?' . PHP_EOL;
exit(1);
}
if (!$this->configController->getConfig(configKey: 'test')) { if (!$this->configController->getConfig(configKey: 'test')) {
// TODO create config => encryption key // TODO create config => encryption key
@ -110,7 +117,6 @@ class DatabaseConnection
} }
exit(1); exit(1);
} }
} catch (PDOException $exception) { } catch (PDOException $exception) {
echo $exception->getMessage() . PHP_EOL; echo $exception->getMessage() . PHP_EOL;
echo 'Did you create the database and adjust the config file?' . PHP_EOL; echo 'Did you create the database and adjust the config file?' . PHP_EOL;

View File

@ -138,10 +138,7 @@ class DomainController
} }
/** function checkPermissions(bool $verbose = false, bool $quiet = false, $impersonatedUserId = null): bool
* @return bool
*/
function checkPermissions(bool $verbose = false, bool $quiet = false): bool
{ {
$this->logger->debug(message: "checkPermissions()"); $this->logger->debug(message: "checkPermissions()");
$setupIsValid = true; $setupIsValid = true;
@ -160,7 +157,11 @@ class DomainController
if ($verbose && !$quiet) { if ($verbose && !$quiet) {
echo 'Checking permissions...' . PHP_EOL; echo 'Checking permissions...' . PHP_EOL;
} }
if ($impersonatedUserId) {
$uid = $impersonatedUserId;
} else {
$uid = posix_geteuid(); $uid = posix_geteuid();
}
if ($verbose && !$quiet) { if ($verbose && !$quiet) {
echo "UID:\t" . COLOR_YELLOW . $uid . PHP_EOL; echo "UID:\t" . COLOR_YELLOW . $uid . PHP_EOL;
} }
@ -170,8 +171,10 @@ class DomainController
echo COLOR_DEFAULT . "Name:\t" . COLOR_YELLOW . $name . PHP_EOL; echo COLOR_DEFAULT . "Name:\t" . COLOR_YELLOW . $name . PHP_EOL;
} }
$bindGroup = posix_getgrnam(name: 'bind'); if (!$bindGroup = posix_getgrnam(name: 'bind')) {
$members = $bindGroup['members']; $bindGroup = [];
}
$members = $bindGroup['members'] ?? [];
if (in_array(needle: $name, haystack: $members)) { if (in_array(needle: $name, haystack: $members)) {
if ($verbose && !$quiet) { if ($verbose && !$quiet) {
echo "\t$name" . COLOR_DEFAULT . ' is in group ' . COLOR_YELLOW . 'bind' . PHP_EOL; echo "\t$name" . COLOR_DEFAULT . ' is in group ' . COLOR_YELLOW . 'bind' . PHP_EOL;
@ -199,7 +202,7 @@ class DomainController
if ($verbose && !$quiet) { if ($verbose && !$quiet) {
echo 'Checking ' . COLOR_YELLOW . $this->namedConfLocalFile . PHP_EOL; echo 'Checking ' . COLOR_YELLOW . $this->namedConfLocalFile . PHP_EOL;
} }
if ($namedConfLocal = file_get_contents(filename: $this->namedConfLocalFile)) { if (file_exists(filename: $this->namedConfLocalFile) && $namedConfLocal = file_get_contents(filename: $this->namedConfLocalFile)) {
if (!str_contains(haystack: $namedConfLocal, needle: $this->localZoneFile)) { if (!str_contains(haystack: $namedConfLocal, needle: $this->localZoneFile)) {
$setupIsValid = false; $setupIsValid = false;
if ($verbose && !$quiet) { if ($verbose && !$quiet) {
@ -248,7 +251,7 @@ class DomainController
$domains = $this->domainRepository->findAll(); $domains = $this->domainRepository->findAll();
foreach ($domains as $domain) { foreach ($domains as $domain) {
$idString = '(' . strval(value: $domain->getId()) . ') '; $idString = '(' . $domain->getId() . ') ';
echo COLOR_YELLOW . echo COLOR_YELLOW .
str_pad(string: $domain->getName(), length: $maxNameLength + 1) str_pad(string: $domain->getName(), length: $maxNameLength + 1)
. COLOR_DEFAULT . COLOR_DEFAULT

View File

@ -1,16 +1,14 @@
<?php <?php
use App\Controller\BindAPI; use App\Controller\BindAPI;
use DI\DependencyException;
use DI\NotFoundException;
error_reporting(error_level: E_ALL & ~E_DEPRECATED); error_reporting(error_level: E_ALL & ~E_DEPRECATED);
if (!is_file(filename: dirname(path: __DIR__).'/vendor/autoload.php')) { if (!is_file(filename: dirname(path: __DIR__, levels: 2) . '/vendor/autoload.php')) {
die('Required runtime components are missing. Try running "composer install".' . PHP_EOL); die('Required runtime components are missing. Try running "composer install".' . PHP_EOL);
} }
require dirname(path: __DIR__) . '/vendor/autoload.php'; require dirname(path: __DIR__, levels: 2) . '/vendor/autoload.php';
$shortOpts = 'v::'; // version $shortOpts = 'v::'; // version
@ -32,7 +30,7 @@ $arguments = array_slice(array: $argv, offset: $restIndex);
if (array_key_exists(key: 'v', array: $options) || array_key_exists(key: 'version', array: $options)) { if (array_key_exists(key: 'v', array: $options) || array_key_exists(key: 'version', array: $options)) {
$arguments = 'showVersion'; $arguments = 'showVersion';
$composerJson = json_decode(json: file_get_contents(filename: dirname(path: __DIR__) . '/composer.json'), associative: true); $composerJson = json_decode(json: file_get_contents(filename: dirname(path: __DIR__, levels: 2) . '/composer.json'), associative: true);
$name = $composerJson['name']; $name = $composerJson['name'];
$description = $composerJson['description']; $description = $composerJson['description'];
$version = $composerJson['version']; $version = $composerJson['version'];
@ -68,14 +66,27 @@ if (array_key_exists(key: 'V', array: $options) || array_key_exists(key: 'verbos
try { try {
$app = new BindAPI(verbose: $verbose, quiet: $quiet); $app = new BindAPI(verbose: $verbose, quiet: $quiet);
$app->runCommand(arguments: $arguments); } catch (Exception $e) {
echo 'Could not initialize the application: ' . $e->getMessage() . PHP_EOL;
} catch (DependencyException|NotFoundException|Exception $e) {
echo $e->getMessage() . PHP_EOL;
exit(1); exit(1);
} }
try {
$app->runCommand(arguments: $arguments);
} catch (Exception $e) {
$exceptionMessage = $e->getMessage();
preg_match(pattern: '/\[1045\]/', subject: $exceptionMessage, matches: $matches);
if (!empty($matches)) {
echo 'Access was denied for a user when trying to access the database.' . PHP_EOL;
} else {
echo 'The error message could not be parsed.';
echo $exceptionMessage . PHP_EOL;
exit(1);
}
}
function confirm(string $message = 'Are you sure? ', array $options = ['y', 'n'], string $default = 'n'): bool function confirm(string $message = 'Are you sure? ', array $options = ['y', 'n'], string $default = 'n'): bool
{ {
// first $options means true, any other false // first $options means true, any other false