2022-09-16 14:59:23 +02:00
< ? php declare ( strict_types = 1 );
namespace App\Controller ;
error_reporting ( error_level : E_ALL );
define ( constant_name : 'COLOR_RED' , value : " \033 [31m " );
define ( constant_name : 'COLOR_GREEN' , value : " \033 [32m " );
define ( constant_name : 'COLOR_YELLOW' , value : " \033 [33m " );
define ( constant_name : 'COLOR_BLUE' , value : " \033 [34m " );
define ( constant_name : 'COLOR_WHITE' , value : " \033 [37m " );
define ( constant_name : 'COLOR_DEFAULT' , value : " \033 [39m " );
2022-09-27 19:13:28 +02:00
use App\Controller\Commands\Command ;
use App\Controller\Commands\CommandGroup ;
use App\Controller\Commands\CommandGroupContainer ;
use App\Entity\Apikey ;
2022-09-16 14:59:23 +02:00
use App\Entity\Domain ;
2022-09-17 18:56:20 +02:00
use App\Entity\DynDNS ;
2022-09-27 19:13:28 +02:00
use App\Entity\KeyHelp\KeyHelpDomain ;
2022-09-16 14:59:23 +02:00
use App\Entity\Nameserver ;
use App\Entity\Panel ;
use App\Repository\ApikeyRepository ;
use App\Repository\DomainRepository ;
use App\Repository\DynDNSRepository ;
use App\Repository\NameserverRepository ;
use App\Repository\PanelRepository ;
use Arubacao\TldChecker\Validator ;
2022-09-17 18:56:20 +02:00
use Exception ;
2022-09-27 19:13:28 +02:00
use JsonMapper ;
use JsonMapper_Exception ;
2022-09-16 14:59:23 +02:00
use LucidFrame\Console\ConsoleTable ;
2022-09-27 19:13:28 +02:00
use SodiumException ;
2022-09-16 14:59:23 +02:00
if ( php_sapi_name () !== 'cli' ) {
2022-09-27 19:13:28 +02:00
exit ;
2022-09-16 14:59:23 +02:00
}
/**
*
*/
class CLIController
{
2022-09-17 18:56:20 +02:00
private array $arguments ;
2022-09-27 19:13:28 +02:00
private CommandGroupContainer $commandGroupContainer ;
2022-09-16 14:59:23 +02:00
2022-09-27 19:13:28 +02:00
/**
* @ throws Exception
*/
public function __construct (
private readonly ApiController $apiController ,
private readonly ApikeyRepository $apikeyRepository ,
private readonly DomainController $domainController ,
private readonly DomainRepository $domainRepository ,
private readonly DynDNSRepository $dynDNSRepository ,
private readonly NameserverRepository $nameserverRepository ,
private readonly PanelRepository $panelRepository ,
private readonly ConfigController $configController ,
private readonly EncryptionController $encryptionController ,
private $logger )
{
2022-09-29 19:21:42 +02:00
$this -> runCheckSetup ();
2022-09-27 19:13:28 +02:00
$this -> commandGroupContainer = ( new CommandGroupContainer ())
2022-09-29 19:21:42 +02:00
-> addCommandGroup ( commandGroup : ( new CommandGroup ( name : 'check' , description : 'health checks the system can perform' ))
2022-09-27 19:13:28 +02:00
-> addCommand ( command : new Command (
name : 'permissions' ,
callback : function () {
2022-09-29 19:21:42 +02:00
$this -> checkPermissions ();
2022-09-27 19:13:28 +02:00
},
description : 'health checks the system can perform' ))
-> addCommand ( command : new Command (
name : 'panels' ,
callback : function () {
2022-09-29 19:21:42 +02:00
$this -> checkPanels ();
2022-09-27 19:13:28 +02:00
},
optionalParameters : [ 'ID' , 'fix=xes' ]))
-> addCommand ( command : new Command (
name : 'domains' ,
callback : function () {
2022-09-29 19:21:42 +02:00
$this -> checkDomains ();
}))
-> addCommand ( command : new Command (
name : 'mail' ,
callback : function () {
$this -> checkMail ();
2022-09-27 19:13:28 +02:00
}))
-> addCommand ( command : new Command (
name : 'showincludes' ,
callback : function () {
2022-09-29 19:21:42 +02:00
$this -> checkShowIncludes ();
2022-09-27 19:13:28 +02:00
},
description : 'Shows needed setting on panels' ))
-> addCommand ( command : new Command (
name : 'generatekey' ,
callback : function () {
2022-09-29 19:21:42 +02:00
$this -> checkGenerateKey ();
2022-09-27 19:13:28 +02:00
},
description : 'Generates a a new key for encryption' ))
-> addCommand ( command : new Command (
name : 'setup' ,
callback : function () {
2022-09-29 19:21:42 +02:00
$this -> checkSetup ();
2022-09-27 19:13:28 +02:00
},
mandatoryParameters : [ 'username' ],
description : 'Adapt filesystem permissions (requires elaborated permissions)' ))
-> addCommand ( command : new Command (
name : 'version' ,
callback : function () {
2022-09-29 19:21:42 +02:00
$this -> checksVersion ();
2022-09-27 19:13:28 +02:00
},
optionalParameters : [ 'major:minor:patch' ],
description : 'Read or set the bindApi version in the database' )))
2022-09-29 19:21:42 +02:00
-> addCommandGroup ( commandGroup : ( new CommandGroup ( name : 'panels' , description : 'all KeyHelp systems configured' ))
2022-09-27 19:13:28 +02:00
-> addCommand ( command : new Command (
name : 'list' ,
callback : function () {
2022-09-29 19:21:42 +02:00
$this -> panelsList ();
2022-09-27 19:13:28 +02:00
}))
-> addCommand ( command : new Command (
name : 'create' ,
callback : function () {
2022-09-29 19:21:42 +02:00
$this -> panelsCreate ();
2022-09-27 19:13:28 +02:00
},
mandatoryParameters : [ 'name' ],
optionalParameters : [ 'A=<IPv4>' , 'AAAA=<IPv6>' , 'apikey=<API-Key>' ]))
-> addCommand ( command : new Command (
name : 'update' ,
callback : function () {
2022-09-29 19:21:42 +02:00
$this -> panelsUpdate ();
2022-09-27 19:13:28 +02:00
},
mandatoryParameters : [ 'ID' ],
optionalParameters : [ 'name=<name>' , 'A=<IPv4>' , 'AAAA=<IPv6>' , 'apikey=<API-Key>' ]))
-> addCommand ( command : new Command (
name : 'delete' ,
callback : function () {
2022-09-29 19:21:42 +02:00
$this -> panelsDelete ();
2022-09-27 19:13:28 +02:00
},
mandatoryParameters : [ 'ID' ]))
-> addCommand ( command : new Command (
name : 'apiping' ,
callback : function () {
2022-09-29 19:21:42 +02:00
$this -> apiPing ( type : 'panel' );
2022-09-27 19:13:28 +02:00
},
optionalParameters : [ 'ID' ])))
2022-09-29 19:21:42 +02:00
-> addCommandGroup ( commandGroup : ( new CommandGroup ( name : 'nameservers' , description : 'available nameservers' ))
2022-09-27 19:13:28 +02:00
-> addCommand ( command : new Command (
name : 'list' ,
callback : function () {
2022-09-29 19:21:42 +02:00
$this -> nameserversList ();
2022-09-27 19:13:28 +02:00
}))
-> addCommand ( command : new Command (
name : 'create' ,
callback : function () {
2022-09-29 19:21:42 +02:00
$this -> nameserversCreate ();
2022-09-27 19:13:28 +02:00
},
mandatoryParameters : [ 'name' ],
optionalParameters : [ 'A=<IPv4>' , 'AAAA=<IPv6>' , 'apikey=<API-Key>' ]))
-> addCommand ( command : new Command (
name : 'update' ,
callback : function () {
2022-09-29 19:21:42 +02:00
$this -> nameserversUpdate ();
2022-09-27 19:13:28 +02:00
},
mandatoryParameters : [ 'ID' ],
optionalParameters : [ 'name=<name>' , 'A=<IPv4>' , 'AAAA=<IPv6>' , 'apikey=<API-Key>' ]))
-> addCommand ( command : new Command (
name : 'delete' ,
callback : function () {
2022-09-29 19:21:42 +02:00
$this -> nameserversDelete ();
2022-09-27 19:13:28 +02:00
},
mandatoryParameters : [ 'ID' ]))
-> addCommand ( command : new Command (
name : 'apiping' ,
callback : function () {
2022-09-29 19:21:42 +02:00
$this -> apiPing ( type : 'nameserver' );
2022-09-27 19:13:28 +02:00
},
optionalParameters : [ 'ID' ])))
2022-09-29 19:21:42 +02:00
-> addCommandGroup ( commandGroup : ( new CommandGroup ( name : 'domains' , description : 'configured domains' ))
2022-09-27 19:13:28 +02:00
-> addCommand ( command : new Command (
name : 'list' ,
callback : function () {
2022-09-29 19:21:42 +02:00
$this -> domainsList ();
2022-09-27 19:13:28 +02:00
}))
-> addCommand ( command : new Command (
name : 'refresh' ,
callback : function () {
2022-09-29 19:21:42 +02:00
$this -> domainsRefresh ();
2022-09-27 19:13:28 +02:00
},
mandatoryParameters : [ 'name' ],
optionalParameters : [ 'A=<IPv4>' , 'AAAA=<IPv6>' , 'apikey=<API-Key>' ])))
2022-09-29 19:21:42 +02:00
-> addCommandGroup ( commandGroup : ( new CommandGroup ( name : 'dyndns' , description : 'handle DynDNS entries' ))
2022-09-27 19:13:28 +02:00
-> addCommand ( command : new Command (
name : 'list' ,
callback : function () {
2022-09-29 19:21:42 +02:00
$this -> dynDnsList ();
2022-09-27 19:13:28 +02:00
}))
-> addCommand ( command : new Command (
name : 'create' ,
callback : function () {
2022-09-29 19:21:42 +02:00
$this -> dynDnsCreate ();
2022-09-27 19:13:28 +02:00
},
mandatoryParameters : [ 'hostname.example.com' , 'password' ],
2022-09-29 19:21:42 +02:00
optionalParameters : [ 'A=<IPv4>' , 'AAAA=<IPv6>' ],
2022-09-27 19:13:28 +02:00
description : 'FQDN within a domain where this server is master' ))
-> addCommand ( command : new Command (
name : 'update' ,
callback : function () {
2022-09-29 19:21:42 +02:00
$this -> dynDnyUpdate ();
2022-09-27 19:13:28 +02:00
},
2022-09-29 19:21:42 +02:00
mandatoryParameters : [ 'hostname.example.com' ,],
optionalParameters : [ 'password=<password>' , 'A=<IPv4>' , 'AAAA=<IPv6>' ]))
2022-09-27 19:13:28 +02:00
-> addCommand ( command : new Command (
name : 'delete' ,
callback : function () {
2022-09-29 19:21:42 +02:00
$this -> dynDnsDelete ();
},
mandatoryParameters : [ 'ID' ])))
-> addCommandGroup ( commandGroup : ( new CommandGroup ( name : 'apikeys' , description : 'API keys to access this bindAPI' ))
-> addCommand ( command : new Command (
name : 'list' ,
callback : function () {
$this -> apikeysList ();
}))
-> addCommand ( command : new Command (
name : 'create' ,
callback : function () {
$this -> apikeysCreate ();
},
optionalParameters : [ 'name=<name>' ]))
-> addCommand ( command : new Command (
name : 'update' ,
callback : function () {
$this -> apikeysUpdate ();
},
mandatoryParameters : [ 'ID' ,],
optionalParameters : [ 'name=<name>' ]))
-> addCommand ( command : new Command (
name : 'delete' ,
callback : function () {
$this -> apikeysDelete ();
},
mandatoryParameters : [ 'ID' ])))
-> addCommandGroup ( commandGroup : ( new CommandGroup ( name : 'webmail' , description : 'manage webmail setup' ))
-> addCommand ( command : new Command (
name : 'check' ,
callback : function () {
$this -> webmailCheck ();
},
mandatoryParameters : [ 'example.com' ]
))
-> addCommand ( command : new Command (
name : 'create' ,
callback : function () {
$this -> webmailCreate ();
},
mandatoryParameters : [ 'example.com' ]))
-> addCommand ( command : new Command (
name : 'delete' ,
callback : function () {
$this -> webmailDelete ();
2022-09-27 19:13:28 +02:00
},
mandatoryParameters : [ 'ID' ])));
2022-09-29 19:21:42 +02:00
2022-09-27 19:13:28 +02:00
}
2022-09-29 19:21:42 +02:00
function runCheckSetup () : void
2022-09-27 19:13:28 +02:00
{
if ( ! $this -> domainController -> checkPermissions ( disableVerbose : true )) {
echo 'You need to setup the bindAPI first.' . PHP_EOL ;
exit ( 1 );
}
$self = $this -> panelRepository -> findSelf ();
$c = count ( $self );
if ( $c != 1 ) {
if ( $c == 0 ) {
echo 'No panel marked as this server.' . PHP_EOL ;
echo 'Use ' . COLOR_YELLOW . 'panels:update <ID> self=1 ' . COLOR_DEFAULT . 'to mark this panel.' . PHP_EOL ;
} else {
echo 'Only one panel can be marked as self.' . PHP_EOL ;
echo 'Use ' . COLOR_YELLOW . 'panels:update <ID> self=0 ' . COLOR_DEFAULT . 'to remove the stale panel' . PHP_EOL ;
}
}
}
function runCommand ( array $arguments ) : void
{
2022-09-17 18:56:20 +02:00
if ( count ( $arguments ) < 1 ) {
$this -> showUsage ();
exit ( 0 );
}
2022-09-27 19:13:28 +02:00
$this -> logger -> debug ( message : " runCommand() " );
if ( str_contains ( haystack : $arguments [ 0 ], needle : ':' )) {
[ $command , $subcommand ] = explode ( separator : ':' , string : $arguments [ 0 ]);
} else {
$command = $arguments [ 0 ];
$subcommand = '' ;
}
$this -> arguments = $this -> parseArguments ( arguments : $arguments );
$this -> commandGroupContainer -> run ( command : $command , subcommand : $subcommand );
}
/**
* @ return void
*/
function showUsage () : void
{
$this -> logger -> debug ( message : " showUsage() " );
$debug = $this -> configController -> getConfig ( configKey : 'debug' );
echo 'bindAPI version: todo (env: todo) ' ;
if ( $debug ) {
echo 'true' ;
} else {
echo 'false' ;
}
echo COLOR_DEFAULT . ')' . PHP_EOL ;
echo COLOR_YELLOW . 'Usage:' . PHP_EOL ;
echo COLOR_DEFAULT . " \t ./bin/console { options} { arguments} " . PHP_EOL . PHP_EOL ;
echo COLOR_YELLOW . 'Options:' . PHP_EOL ;
echo COLOR_GREEN . " \t -v, --version \t \t " . COLOR_DEFAULT . " Display the version of the API " . PHP_EOL ;
echo COLOR_GREEN . " \t -V, --verbose \t \t " . COLOR_DEFAULT . " All :lists command are auto-verbose " . PHP_EOL . PHP_EOL ;
echo COLOR_YELLOW . 'Arguments: ' . COLOR_WHITE . '<mandatory> {optional}' . PHP_EOL ;
$this -> commandGroupContainer -> printCommands ();
echo PHP_EOL . " \033 [39me.g. ./bin/console apikeys:list " . PHP_EOL ;
}
/**
*/
2022-09-29 19:21:42 +02:00
public function checkPermissions () : void
2022-09-27 19:13:28 +02:00
{
2022-09-29 19:21:42 +02:00
$this -> logger -> debug ( message : " checkPermissions() " );
2022-09-27 19:13:28 +02:00
if ( ! $this -> domainController -> checkPermissions ()) {
if ( $this -> configController -> getConfig ( configKey : 'verbose' )) {
echo PHP_EOL . COLOR_DEFAULT ;
echo 'Missing permissions, please run ' . COLOR_YELLOW . './bin/console check:setup' . COLOR_DEFAULT . ' as root or with sudo.' . PHP_EOL ;
}
exit ( 1 );
} else {
exit ( 0 );
}
}
2022-09-29 19:21:42 +02:00
function checkSetup () : void
2022-09-27 19:13:28 +02:00
{
2022-09-29 19:21:42 +02:00
if ( empty ( $this -> arguments [ 1 ])) {
2022-09-27 19:13:28 +02:00
echo 'You need to supply a username.' . PHP_EOL ;
exit ( 1 );
}
$username = $this -> arguments [ 1 ];
$uid = posix_getuid ();
if ( $uid != 0 ) {
echo 'You need to run this as root or with sudo.' . PHP_EOL ;
exit ( 1 );
}
// deluser tracer bind
// adduser tracer bind
// add user to group bind
exec ( command : " adduser $username bind " , output : $output , result_code : $return );
if ( $return != 0 ) {
echo 'Could not add user to bind group.' . PHP_EOL ;
exit ( 1 );
}
// for /etc/bind/local.zones file
if ( ! file_exists ( filename : $this -> domainController -> localZoneFile )) {
echo 'Could not find ' . COLOR_YELLOW . $this -> domainController -> localZoneFile . COLOR_DEFAULT . '.' . PHP_EOL ;
echo 'Creating …' ;
touch ( filename : $this -> domainController -> localZoneFile );
if ( ! file_exists ( filename : $this -> domainController -> localZoneFile )) {
echo 'Could not create ' . $this -> domainController -> localZoneFile . '.' . PHP_EOL ;
exit ( 1 );
} else {
echo ' done.' . PHP_EOL ;
echo 'Setting owner …' ;
if ( chown ( filename : $this -> domainController -> localZoneFile , user : 'bind' )) {
echo " done. " . PHP_EOL ;
}
echo 'Setting permissions …' ;
if ( chmod ( filename : $this -> domainController -> localZoneFile , permissions : 0664 )) {
echo " done. " . PHP_EOL ;
}
}
}
// /etc/bind/local.zones file must be included in /etc/bind/named.conf.local
$namedConfLocal = file_get_contents ( filename : $this -> domainController -> namedConfLocalFile );
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 ;
} else {
echo 'Could not find ' . COLOR_YELLOW . $this -> domainController -> localZoneFile . COLOR_DEFAULT . ' in ' . COLOR_YELLOW . $this -> domainController -> namedConfLocalFile . COLOR_DEFAULT . '.' . PHP_EOL ;
echo 'Adding …' ;
$namedConfLocal .= PHP_EOL . 'include "' . $this -> domainController -> localZoneFile . '";' . PHP_EOL ;
file_put_contents ( filename : $this -> domainController -> namedConfLocalFile , data : $namedConfLocal );
if ( str_contains ( haystack : $namedConfLocal , needle : $this -> domainController -> localZoneFile )) {
echo ' done.' . PHP_EOL ;
} else {
echo 'Could not add ' . COLOR_YELLOW . $this -> domainController -> localZoneFile . COLOR_DEFAULT . ' to ' . COLOR_YELLOW . $this -> domainController -> namedConfLocalFile . COLOR_DEFAULT . '.' . PHP_EOL ;
exit ( 1 );
}
}
// check /etc/bind/zones exists
echo 'Check for ' . COLOR_YELLOW . $this -> domainController -> localZonesDir . COLOR_DEFAULT . ' …' ;
if ( is_dir ( filename : $this -> domainController -> localZonesDir )) {
echo " done. " . PHP_EOL ;
} else {
echo ' Could not find ' . COLOR_YELLOW . $this -> domainController -> localZonesDir . COLOR_DEFAULT . '.' . PHP_EOL ;
echo 'Creating …' ;
mkdir ( directory : $this -> domainController -> localZonesDir , permissions : 0775 , recursive : true );
echo ' done.' . PHP_EOL ;
echo 'Setting owner …' ;
if ( chown ( filename : $this -> domainController -> localZonesDir , user : 'bind' )) {
echo " done. " . PHP_EOL ;
}
echo 'Setting permissions …' ;
if ( chmod ( filename : $this -> domainController -> localZonesDir , permissions : 0774 )) {
echo " done. " . PHP_EOL ;
}
}
}
/**
*/
2022-09-29 19:21:42 +02:00
function checkPanels () : void
2022-09-27 19:13:28 +02:00
{
2022-09-29 19:21:42 +02:00
$this -> logger -> debug ( message : " checkPanels() " );
2022-09-27 19:13:28 +02:00
$id = intval ( value : $this -> arguments [ 1 ] ? ? 0 );
if ( $id != 0 ) {
if ( $panel = $this -> panelRepository -> findByID ( id : $id )) {
$this -> checkSinglePanel ( panel : $panel );
} else {
echo " Unknown panel ID $id " . PHP_EOL ;
}
} else {
echo " check all … " . PHP_EOL ;
$panels = $this -> panelRepository -> findAll ();
foreach ( $panels as $panel ) {
$this -> checkSinglePanel ( panel : $panel );
}
}
}
/**
* @ param Panel $panel
*
* @ return void
*/
2022-09-29 19:21:42 +02:00
public
function checkSinglePanel ( Panel $panel ) : void
2022-09-27 19:13:28 +02:00
{
$this -> logger -> debug ( message : " checkSinglePanel() " );
echo COLOR_DEFAULT . 'KeyHelp-Panel: ' . COLOR_YELLOW . $panel -> getName () . COLOR_DEFAULT ;
$encryptionKey = $this -> configController -> getConfig ( configKey : 'encryptionKey' );
$decryptedKey = $this -> encryptionController -> safeDecrypt ( encrypted : $panel -> getApikey (), key : $encryptionKey );
if ( $this -> configController -> getConfig ( configKey : 'verbose' )) {
if ( empty ( $panel -> getA ())) {
$panelRequest = $this -> apiController -> sendCommand (
requestType : 'GET' ,
serverName : $panel -> getName (),
versionIP : 6 ,
apiKey : $decryptedKey ,
command : '/server' ,
serverType : 'panel' );
} else {
$panelRequest = $this -> apiController -> sendCommand (
requestType : 'GET' ,
serverName : $panel -> getName (),
versionIP : 4 ,
apiKey : $decryptedKey ,
command : '/server' ,
serverType : 'panel' );
}
$panelData = json_decode ( json : $panelRequest [ 'data' ]);
if ( ! empty ( $panelData )) {
$panelVersion = $panelData -> meta -> panel_version ;
$responseTime = sprintf ( " %0.3f " , $panelRequest [ 'responseTime' ]);
} else {
$panelVersion = 'n/a' ;
$responseTime = 'n/a' ;
}
echo COLOR_DEFAULT . ' KeyHelp version: ' . $panelVersion . " ( $responseTime seconds) " . PHP_EOL ;
} else {
echo PHP_EOL ;
}
if ( empty ( $panel -> getA ())) {
$result = $this -> apiController -> sendCommand (
requestType : 'GET' ,
serverName : $panel -> getName (),
versionIP : 6 ,
apiKey : $decryptedKey ,
command : 'domains?sort=domain&subdomains=false' ,
serverType : 'panel'
);
} else {
$result = $this -> apiController -> sendCommand (
requestType : 'GET' ,
serverName : $panel -> getName (),
versionIP : 4 ,
apiKey : $decryptedKey ,
command : 'domains?sort=domain&subdomains=false' ,
serverType : 'panel' );
}
if ( ! empty ( $result [ 'error' ])) {
echo $result [ 'data' ] . PHP_EOL ;
exit ( 1 );
}
if ( ! empty ( $result [ 'data' ])) {
$domains = json_decode ( json : $result [ 'data' ]);
} else {
echo 'No domains found' . PHP_EOL ;
exit ( 1 );
}
$maxDomainNameLength = 0 ;
$tmpDomainList = [];
$mapper = new JsonMapper ();
if ( count ( $domains ) > 0 ) {
foreach ( $domains as $domain ) {
$mapper -> bExceptionOnUndefinedProperty = true ;
$mapper -> bStrictNullTypes = false ;
try {
$domainObject = $mapper -> map ( json : $domain , object : new KeyHelpDomain ());
} catch ( JsonMapper_Exception $e ) {
die ( $e -> getMessage () . PHP_EOL );
}
$tmpDomainList [] = $domainObject ;
if ( strlen ( string : $domain -> domain ) > $maxDomainNameLength ) {
$maxDomainNameLength = strlen ( string : $domain -> domain );
}
}
}
$domainCount = 0 ;
foreach ( $tmpDomainList as $domain ) {
echo COLOR_DEFAULT . " Domain: " . COLOR_YELLOW . str_pad ( string : $domain -> getDomain (), length : $maxDomainNameLength );
if ( ! $domain -> isSubdomain ()) {
$this -> checkNS ( domainName : $domain -> getDomain (), panel : $panel );
$domainCount ++ ;
}
}
if ( $domainCount == 0 ) {
echo 'No second level domains found.' . COLOR_DEFAULT . PHP_EOL ;
}
echo PHP_EOL ;
try {
sodium_memzero ( string : $decryptedKey );
} catch ( SodiumException $e ) {
die ( $e -> getMessage () . PHP_EOL );
}
}
function isSubDomain ( Domain $domain ) : bool
{
$this -> logger -> debug ( message : " isSubDomain() " );
// valid second level domain
if ( ! Validator :: endsWithTld ( value : $domain )) {
return false ;
}
$domainParts = explode ( separator : '.' , string : $domain -> getName ());
$reversedParts = array_reverse ( array : $domainParts );
$testDomain = '' ;
$foundDomain = '' ;
foreach ( $reversedParts as $part ) {
if ( $testDomain ) {
$testDomain = $part . '.' . $testDomain ;
} else {
$testDomain = $part ;
}
if ( $this -> domainRepository -> findByName ( name : $testDomain )) {
$foundDomain = $testDomain ;
echo $part . PHP_EOL ;
}
}
echo " fould domain *** " . $foundDomain . PHP_EOL ;
/*
// system domain
if ( str_contains ( haystack : $domainName , needle : $panel )) {
return false ;
}
// no second level domain
if ( substr_count ( haystack : $domainName , needle : '.' ) > 1 ) {
return false ;
}
2022-09-29 19:21:42 +02:00
*/
2022-09-27 19:13:28 +02:00
return true ;
}
function isValidSecondLevelDomain ( string $domainName , string $panel , int $parent ) : bool
{
$this -> logger -> debug ( message : " isValidSecondLevelDomain() " );
// subdomain
if ( $parent != 0 ) {
return false ;
}
// system domain
if ( str_contains ( haystack : $domainName , needle : $panel )) {
return false ;
}
// valid second level domain
if ( ! Validator :: endsWithTld ( value : $domainName )) {
return false ;
}
// no second level domain
if ( substr_count ( haystack : $domainName , needle : '.' ) > 1 ) {
return false ;
}
return true ;
}
/**
* @ param String $domainName
* @ param Panel $panel
*
* @ return void
*/
function checkNS ( string $domainName , Panel $panel ) : void
{
$this -> logger -> debug ( message : " checkNS() " );
2022-09-29 19:21:42 +02:00
$nameservers = $this -> nameserverRepository -> findAll ();
foreach ( $nameservers as $nameserver ) {
$encryptionKey = $this -> configController -> getConfig ( configKey : 'encryptionKey' );
$decryptedKey = $this -> encryptionController -> safeDecrypt ( encrypted : $nameserver -> getApikey (), key : $encryptionKey );
echo COLOR_YELLOW . ' ' . $nameserver -> getName ();
if ( ! empty ( $nameserver -> getName ())) {
2022-09-27 19:13:28 +02:00
$result = $this -> apiController -> sendCommand (
requestType : 'GET' ,
2022-09-29 19:21:42 +02:00
serverName : $nameserver -> getName (),
2022-09-27 19:13:28 +02:00
versionIP : 6 ,
2022-09-29 19:21:42 +02:00
apiKey : $decryptedKey ,
2022-09-27 19:13:28 +02:00
command : 'domains/name/' . $domainName ,
serverType : 'nameserver' );
} else {
$result = $this -> apiController -> sendCommand (
requestType : 'GET' ,
2022-09-29 19:21:42 +02:00
serverName : $nameserver -> getName (),
2022-09-27 19:13:28 +02:00
versionIP : 4 ,
2022-09-29 19:21:42 +02:00
apiKey : $decryptedKey (),
2022-09-27 19:13:28 +02:00
command : 'domains/name/' ,
serverType : 'nameserver' . $domainName );
}
switch ( $result [ 'header' ]) {
case 200 :
echo COLOR_GREEN . ' OK' ;
break ;
case 404 :
echo COLOR_RED . ' ' . $result [ 'header' ] . COLOR_DEFAULT ;
if ( ! empty ( $this -> arguments [ 'fix' ]) && $this -> arguments [ 'fix' ] == 'yes' ) {
echo ' trying to fix …' ;
$body = [
'name' => $domainName ,
'panel' => $panel -> getName (),
];
2022-09-29 19:21:42 +02:00
$encryptionKey = $this -> configController -> getConfig ( configKey : 'encryptionKey' );
$decryptedKey = $this -> encryptionController -> safeDecrypt ( encrypted : $nameserver -> getApikey (), key : $encryptionKey );
if ( ! empty ( $nameserver -> getAaaa ())) {
2022-09-27 19:13:28 +02:00
$create = $this -> apiController -> sendCommand (
requestType : 'POST' ,
2022-09-29 19:21:42 +02:00
serverName : $nameserver -> getName (),
2022-09-27 19:13:28 +02:00
versionIP : 6 ,
2022-09-29 19:21:42 +02:00
apiKey : $decryptedKey ,
2022-09-27 19:13:28 +02:00
command : 'domains' ,
serverType : 'nameserver' ,
body : $body );
} else {
$create = $this -> apiController -> sendCommand (
requestType : 'POST' ,
2022-09-29 19:21:42 +02:00
serverName : $nameserver -> getName (),
2022-09-27 19:13:28 +02:00
versionIP : 4 ,
2022-09-29 19:21:42 +02:00
apiKey : $decryptedKey (),
2022-09-27 19:13:28 +02:00
command : 'domains' ,
serverType : 'nameserver' ,
body : $body );
}
if ( $create [ 'header' ] != 201 ) {
print_r ( value : $create );
die ( " make error handling " );
} else {
echo COLOR_GREEN . 'OK' . COLOR_DEFAULT ;
}
}
break ;
default :
echo 'Server error' . PHP_EOL ;
exit ( 1 );
}
}
echo PHP_EOL ;
}
/**
* @ param array $arguments
* @ return array
*/
2022-09-29 19:21:42 +02:00
public
function parseArguments ( array $arguments ) : array
2022-09-27 19:13:28 +02:00
{
$this -> logger -> debug ( message : " parseArguments() " );
$parsedArguments = [];
$parseCount = 0 ;
foreach ( $arguments as $argument ) {
if ( str_contains ( haystack : $argument , needle : '=' )) {
[ $key , $value ] = explode ( separator : '=' , string : $argument );
$parsedArguments [ strtolower ( string : $key )] = $value ;
$parsedArguments [ $parseCount ++ ] = $value ;
} else {
$parsedArguments [ strtolower ( string : $argument )] = $argument ;
$parsedArguments [ $parseCount ++ ] = $argument ;
}
}
return $parsedArguments ;
}
/**
* @ return void
*/
2022-09-29 19:21:42 +02:00
function panelsCreate () : void
2022-09-27 19:13:28 +02:00
{
2022-09-29 19:21:42 +02:00
$this -> logger -> debug ( message : " panelsCreate() " );
2022-09-27 19:13:28 +02:00
$name = $this -> arguments [ 1 ] ? ? '' ;
if ( empty ( $name )) {
echo 'You need to supply the panel name.' . PHP_EOL ;
exit ( 1 );
}
$filteredName = filter_var ( value : $name , filter : FILTER_VALIDATE_DOMAIN , options : FILTER_FLAG_HOSTNAME );
if ( ! empty ( $filteredName ) && str_contains ( haystack : $filteredName , needle : '.' )) {
$name = $filteredName ;
} else {
echo " $name is no valid DNS domain name. " . PHP_EOL ;
exit ( 1 );
}
$a = $this -> arguments [ 'a' ] ? ? '' ;
$aaaa = $this -> arguments [ 'aaaa' ] ? ? '' ;
if ( empty ( $a ) && empty ( $aaaa )) {
echo 'At least one IP address is required.' . PHP_EOL ;
exit ( 0 );
}
$apikey = $this -> arguments [ 'apikey' ] ? ? '' ;
$self = $this -> arguments [ 'self' ] ? ? 'no' ;
if ( $this -> panelRepository -> findByName ( name : $name )) {
echo " Panel: $name already exists. " . PHP_EOL ;
exit ( 1 );
} else {
$panel = new Panel ( name : $name , a : $a , aaaa : $aaaa , passphrase : $apikey , self : $self );
$result = $this -> panelRepository -> insert ( panel : $panel );
echo " Panel $name has been created with id $result " . PHP_EOL ;
exit ( 0 );
}
}
/**
* @ return void
*/
2022-09-29 19:21:42 +02:00
function panelsList () : void
2022-09-27 19:13:28 +02:00
{
2022-09-29 19:21:42 +02:00
$this -> logger -> debug ( message : " panelsList() " );
2022-09-27 19:13:28 +02:00
$panels = $this -> panelRepository -> findAll ();
if ( ! empty ( $panels )) {
echo 'All available panels:' . PHP_EOL ;
$table = new ConsoleTable ();
$table -> setHeaders ( content : [ 'ID' , 'Name' , 'A' , 'AAAA' , 'API Key (Prefix)' , 'This Panel' ]);
foreach ( $panels as $panel ) {
$row = [];
$row [] = $panel -> getID ();
$row [] = $panel -> getName ();
$row [] = $panel -> getA ();
$row [] = $panel -> getAaaa ();
$row [] = $panel -> getApikeyPrefix ();
$row [] = ucfirst ( string : $panel -> getSelf ());
$table -> addRow ( data : $row );
}
$table -> setPadding ( value : 2 );
$table -> display ();
} else {
echo 'No panels found.' . PHP_EOL ;
exit ( 1 );
}
exit ( 0 );
}
/**
*/
2022-09-29 19:21:42 +02:00
function panelsUpdate () : void
2022-09-27 19:13:28 +02:00
{
2022-09-29 19:21:42 +02:00
$this -> logger -> debug ( message : " panelsUpdate() " );
2022-09-27 19:13:28 +02:00
$id = intval ( value : $this -> arguments [ 1 ] ? ? 0 );
$name = $this -> arguments [ 'name' ] ? ? '' ;
$a = $this -> arguments [ 'a' ] ? ? '' ;
$aaaa = $this -> arguments [ 'aaaa' ] ? ? '' ;
$apikey = $this -> arguments [ 'apikey' ] ? ? '' ;
$self = $this -> arguments [ 'self' ] ? ? '' ;
if ( $id == 0 ) {
echo 'An ID is required' . PHP_EOL ;
exit ( 1 );
}
if ( ! $this -> panelRepository -> findByID ( id : $id )) {
echo " Panel with ID : $id doesn't exist. " . PHP_EOL ;
exit ( 1 );
}
if ( $apikey ) {
$panel = new Panel ( name : $name , id : $id , a : $a , aaaa : $aaaa , passphrase : $apikey , self : $self );
} else {
$panel = new Panel ( name : $name , id : $id , a : $a , aaaa : $aaaa , self : $self );
}
if ( $this -> panelRepository -> update ( panel : $panel ) !== false ) {
echo 'Panel ' . COLOR_YELLOW . $id . COLOR_DEFAULT . ' has been updated' . PHP_EOL ;
} else {
echo 'Error while updating domain server.' . PHP_EOL ;
}
}
/**
*/
2022-09-29 19:21:42 +02:00
function panelsDelete () : void
2022-09-27 19:13:28 +02:00
{
2022-09-29 19:21:42 +02:00
$this -> logger -> debug ( message : " panelsDelete() " );
2022-09-27 19:13:28 +02:00
if ( empty ( $this -> arguments [ 1 ])) {
echo " You need to supply an ID. " . PHP_EOL ;
exit ( 1 );
}
$id = intval ( value : $this -> arguments [ 1 ]) ? ? 0 ;
if ( $id == 0 ) {
echo " Panel with ID $id not found. " . PHP_EOL ;
exit ( 1 );
}
if ( ! $this -> panelRepository -> findByID ( id : $id )) {
echo " There is no panel with ID $id . " . PHP_EOL ;
exit ( 1 );
}
$this -> panelRepository -> delete ( id : $id );
echo " The panel with ID $id has been deleted. " . PHP_EOL ;
}
/**
*/
2022-09-29 19:21:42 +02:00
function apiPing ( string $type ) : void
2022-09-27 19:13:28 +02:00
{
2022-09-29 19:21:42 +02:00
$this -> logger -> debug ( message : " apiPing() " );
2022-09-27 19:13:28 +02:00
$error = false ;
$id = $this -> getId ();
if ( $id != 0 ) {
if ( $type == 'panel' ) {
$server = $this -> panelRepository -> findByID ( id : $id );
} else {
$server = $this -> nameserverRepository -> findByID ( id : $id );
}
if ( $server ) {
if ( ! $this -> checkPing ( server : $server , type : $type )) {
$error = true ;
}
} else {
if ( ! $this -> configController -> getConfig ( configKey : 'quiet' )) {
echo " Unknown $type ID $id " . PHP_EOL ;
}
$error = true ;
}
} else {
if ( $type == 'panel' ) {
$servers = $this -> panelRepository -> findAll ();
} else {
$servers = $this -> nameserverRepository -> findAll ();
}
foreach ( $servers as $server ) {
if ( ! $this -> checkPing ( server : $server , type : $type )) {
$error = true ;
}
}
}
if ( ! $this -> configController -> getConfig ( configKey : 'quiet' )) {
echo PHP_EOL ;
}
if ( $error ) {
if ( ! $this -> configController -> getConfig ( configKey : 'verbose' )) {
echo 'There were errors, run command with -V (or -verbose) to see the errors.' . PHP_EOL ;
}
exit ( 1 );
} else {
exit ( 0 );
}
}
/**
* @ return int | void
*/
2022-09-29 19:21:42 +02:00
public
function getId ()
2022-09-27 19:13:28 +02:00
{
if ( ! empty ( $this -> arguments [ 1 ])) {
$id = intval ( value : $this -> arguments [ 1 ] ? ? 0 );
if ( $id != $this -> arguments [ 1 ]) {
echo 'ID has to be a number.' . PHP_EOL ;
exit ( 1 );
}
} else {
$id = 0 ;
}
return $id ;
}
/**
* @ param Panel | Nameserver $server
* @ param String $type
*
* @ return bool
*/
2022-09-29 19:21:42 +02:00
public
function checkPing ( Panel | Nameserver $server , string $type ) : bool
2022-09-27 19:13:28 +02:00
{
2022-09-29 19:21:42 +02:00
$this -> logger -> debug ( message : " checkPing() - server, type: " . $server -> getName () . ', ' . $type );
2022-09-27 19:13:28 +02:00
$error = false ;
if ( $type == 'nameserver' ) {
$maxName = $this -> nameserverRepository -> getLongestEntry ( field : 'name' );
$maxA = $this -> nameserverRepository -> getLongestEntry ( field : 'a' );
$maxAAAA = $this -> nameserverRepository -> getLongestEntry ( field : 'aaaa' );
} else {
$maxName = $this -> panelRepository -> getLongestEntry ( field : 'name' );
$maxA = $this -> panelRepository -> getLongestEntry ( field : 'a' );
$maxAAAA = $this -> panelRepository -> getLongestEntry ( field : 'aaaa' );
}
if ( ! $this -> configController -> getConfig ( configKey : 'quiet' )) {
echo COLOR_YELLOW . str_pad ( string : $server -> getName (), length : $maxName );
}
$encryptionKey = $this -> configController -> getConfig ( configKey : 'encryptionKey' );
$decryptedKey = $this -> encryptionController -> safeDecrypt ( encrypted : $server -> getApikey (), key : $encryptionKey );
$a = $server -> getA () ? ? '' ;
if ( ! empty ( $a )) {
$this -> logger -> debug ( " check a " );
if ( $this -> configController -> getConfig ( configKey : 'verbose' )) {
echo COLOR_DEFAULT . ' ' . str_pad ( string : $a , length : $maxA , pad_type : STR_PAD_LEFT ) . ' ' ;
}
if ( $result = $this -> apiController -> sendCommand (
requestType : 'GET' ,
serverName : $server -> getName (),
versionIP : 4 ,
apiKey : $decryptedKey ,
command : 'ping' ,
serverType : $type )) {
if ( ! $this -> configController -> getConfig ( configKey : 'quiet' )) {
if ( $result [ 'data' ] == 'pong' ) {
echo ' ' . COLOR_GREEN . $result [ 'data' ];
} else {
echo COLOR_BLUE . ' skip' . COLOR_DEFAULT ;
if ( $this -> configController -> getConfig ( configKey : 'verbose' )) {
echo ' ' . $result [ 'data' ];
}
}
}
} else {
$error = true ;
}
}
$aaaa = $server -> getAaaa () ? ? '' ;
if ( ! empty ( $aaaa )) {
$this -> logger -> debug ( " check aaaa " );
if ( $this -> configController -> getConfig ( configKey : 'verbose' )) {
echo COLOR_DEFAULT . ' ' . str_pad ( string : $aaaa , length : $maxAAAA , pad_type : STR_PAD_LEFT ) . ' ' ;
}
if ( $result = $this -> apiController -> sendCommand (
requestType : 'GET' ,
serverName : $server -> getName (),
versionIP : 6 ,
apiKey : $decryptedKey ,
command : 'ping' ,
serverType : $type )) {
if ( ! $this -> configController -> getConfig ( configKey : 'quiet' )) {
if ( $result [ 'data' ] == 'pong' ) {
echo ' ' . COLOR_GREEN . $result [ 'data' ];
} else {
echo COLOR_BLUE . ' skip' . COLOR_DEFAULT ;
if ( $this -> configController -> getConfig ( configKey : 'verbose' )) {
echo ' ' . $result [ 'data' ];
}
}
}
} else {
$error = true ;
}
}
try {
sodium_memzero ( string : $decryptedKey );
} catch ( SodiumException $e ) {
die ( $e -> getMessage () . PHP_EOL );
}
if ( ! $this -> configController -> getConfig ( configKey : 'quiet' )) {
echo COLOR_DEFAULT . PHP_EOL ;
}
return ! $error ;
}
/**
* @ return void
*/
2022-09-29 19:21:42 +02:00
function apikeysCreate () : void
2022-09-27 19:13:28 +02:00
{
$name = $this -> arguments [ 'name' ] ? ? '' ;
2022-09-16 14:59:23 +02:00
2022-09-27 19:13:28 +02:00
$apiKeyPrefix = uniqid ();
try {
$apikeyRand = bin2hex ( string : random_bytes ( length : 24 ));
} catch ( Exception $e ) {
die ( $e -> getMessage () . PHP_EOL );
}
2022-09-16 14:59:23 +02:00
2022-09-27 19:13:28 +02:00
$passphrase = password_hash ( password : $apiKeyPrefix . '.' . $apikeyRand , algo : PASSWORD_ARGON2ID );
2022-09-16 14:59:23 +02:00
2022-09-27 19:13:28 +02:00
$apikey = new Apikey ( name : $name , apikeyPrefix : $apiKeyPrefix , passphrase : $passphrase );
2022-09-17 18:56:20 +02:00
2022-09-27 19:13:28 +02:00
$result = $this -> apikeyRepository -> insert ( apikey : $apikey );
2022-09-16 14:59:23 +02:00
2022-09-27 19:13:28 +02:00
if ( $name ) {
echo 'API key ' . COLOR_YELLOW . $name . COLOR_DEFAULT ;
} else {
echo 'Unnamed API key ' ;
}
2022-09-16 14:59:23 +02:00
2022-09-27 19:13:28 +02:00
echo ' with ID ' . COLOR_YELLOW . $result . COLOR_DEFAULT . ' has been generated. Store it in a safe place, it cannot be recovered.' . PHP_EOL ;
echo COLOR_YELLOW . $apiKeyPrefix . '.' . $apikeyRand . COLOR_DEFAULT . PHP_EOL ;
exit ( 0 );
}
/**
* @ return void
*/
2022-09-29 19:21:42 +02:00
function apikeysList () : void
2022-09-27 19:13:28 +02:00
{
$keys = $this -> apikeyRepository -> findAll ();
if ( ! empty ( $keys )) {
echo 'All valid API keys:' . PHP_EOL ;
$table = new ConsoleTable ();
$table -> setHeaders ( content : [ 'ID' , 'Name' , 'API key prefix' ]);
foreach ( $keys as $key ) {
$row = [];
$row [] = $key -> getID ();
$row [] = $key -> getName ();
$row [] = $key -> getApikeyPrefix ();
$table -> addRow ( data : $row );
}
$table -> setPadding ( value : 2 );
$table -> display ();
} else {
echo 'No keys found.' . PHP_EOL ;
}
exit ( 0 );
}
/**
*/
2022-09-29 19:21:42 +02:00
function apikeysUpdate () : void
2022-09-17 17:39:47 +02:00
{
2022-09-27 19:13:28 +02:00
$id = intval ( value : $this -> arguments [ 1 ]) ? ? 0 ;
$name = $this -> arguments [ 'name' ] ? ? '' ;
if ( $id == 0 ) {
echo 'An ID is required' . PHP_EOL ;
exit ( 1 );
}
if ( ! $this -> apikeyRepository -> findByID ( id : intval ( value : $id ))) {
echo " Apikeys with ID : $id doesn't exist. " . PHP_EOL ;
exit ( 1 );
}
if ( ! $name ) {
echo 'You need tu supply a name.' . PHP_EOL ;
exit ( 1 );
}
$apikey = new Apikey ( id : $id , name : $name );
if ( $this -> apikeyRepository -> update ( apikey : $apikey ) !== false ) {
echo 'Apikey has been updated' . PHP_EOL ;
} else {
echo 'Error while updating apikey.' . PHP_EOL ;
}
2022-09-17 17:39:47 +02:00
}
2022-09-27 19:13:28 +02:00
/**
* @ return void
*/
2022-09-29 19:21:42 +02:00
function apikeysDelete () : void
2022-09-27 19:13:28 +02:00
{
$id = intval ( value : $this -> arguments [ 1 ] ? ? 0 );
if ( $id == 0 ) {
echo 'You need to add the ID of the API key.' . PHP_EOL ;
exit ( 1 );
}
if ( $this -> apikeyRepository -> findByID ( id : $id )) {
$this -> apikeyRepository -> delete ( id : $id );
echo 'API key ' . COLOR_YELLOW . $id . COLOR_DEFAULT . ' has been deleted.' . PHP_EOL ;
exit ( 0 );
} else {
echo 'Unknown ID ' . COLOR_YELLOW . $id . '.' . PHP_EOL ;
exit ( 1 );
}
}
2022-09-16 14:59:23 +02:00
2022-09-27 19:13:28 +02:00
/**
* @ return void
*/
2022-09-29 19:21:42 +02:00
function domainsList () : void
2022-09-27 19:13:28 +02:00
{
$domains = $this -> domainRepository -> findAll ();
if ( ! empty ( $domains )) {
echo 'All available domains:' . PHP_EOL ;
$table = new ConsoleTable ();
$table -> setHeaders ( content : [ 'ID' , 'Name' , 'Panel' , 'Type' ]);
/** @var Domain $domain */
foreach ( $domains as $domain ) {
$row = [];
$row [] = $domain -> getId ();
$row [] = $domain -> getName ();
$row [] = $domain -> getPanel ();
$row [] = $this -> domainController -> isMasterZone ( domain : $domain ) ? 'MASTER' : 'SLAVE' ;
$table -> addRow ( data : $row );
}
$table -> setPadding ( value : 2 );
$table -> display ();
} else {
echo 'No domains found.' . PHP_EOL ;
}
exit ( 0 );
}
/**
* @ return void
*/
2022-09-29 19:21:42 +02:00
function dynDnsList () : void
2022-09-27 19:13:28 +02:00
{
$dyndns = $this -> dynDNSRepository -> findAll ();
if ( ! empty ( $dyndns )) {
echo 'All available DynDNS hosts:' . PHP_EOL ;
$table = new ConsoleTable ();
$table -> setHeaders ( content : [ 'ID' , 'Name' , 'Panel' , 'Type' ]);
/** @var \App\Entity\DynDNS $dyndnsHost */
foreach ( $dyndns as $dyndnsHost ) {
$row = [];
$row [] = $dyndnsHost -> getId ();
$row [] = $dyndnsHost -> getName ();
$table -> addRow ( data : $row );
}
$table -> setPadding ( value : 2 );
$table -> display ();
} else {
echo 'No DynDNS hosts found.' . PHP_EOL ;
}
exit ( 0 );
}
/**
* @ return void
*/
2022-09-29 19:21:42 +02:00
function dynDnsCreate () : void
2022-09-27 19:13:28 +02:00
{
$name = $this -> arguments [ 1 ] ? ? '' ;
if ( empty ( $name )) {
echo 'You need to supply the FQDN (hostname).' . PHP_EOL ;
exit ( 1 );
}
$filteredName = filter_var ( value : $name , filter : FILTER_VALIDATE_DOMAIN , options : FILTER_FLAG_HOSTNAME );
if ( ! empty ( $filteredName ) && str_contains ( haystack : $filteredName , needle : '.' )) {
$name = $filteredName ;
} else {
echo " $name is no valid DNS domain name. " . PHP_EOL ;
exit ( 1 );
}
2022-09-16 14:59:23 +02:00
2022-09-17 18:56:20 +02:00
$password = $this -> arguments [ 2 ] ? ? '' ;
2022-09-16 14:59:23 +02:00
2022-09-17 18:56:20 +02:00
var_dump ( $this -> arguments );
die ();
2022-09-27 19:13:28 +02:00
$domainParts = explode ( separator : '.' , string : $name );
$reversedParts = array_reverse ( array : $domainParts );
$testDomain = '' ;
$foundDomain = '' ;
foreach ( $reversedParts as $part ) {
if ( $testDomain ) {
$testDomain = $part . '.' . $testDomain ;
} else {
$testDomain = $part ;
}
if ( $this -> domainRepository -> findByName ( name : $testDomain )) {
$foundDomain = $testDomain ;
echo $part . PHP_EOL ;
}
}
if ( ! $foundDomain ) {
echo 'No matching domain found for this panel.' . PHP_EOL ;
exit ( 1 );
}
2022-09-16 14:59:23 +02:00
2022-09-17 17:39:47 +02:00
if ( $this -> configController -> getConfig ( configKey : 'verbose' )) {
2022-09-17 18:56:20 +02:00
echo " Found domain: " . COLOR_YELLOW . $foundDomain . COLOR_DEFAULT . PHP_EOL ;
2022-09-17 17:39:47 +02:00
}
2022-09-16 14:59:23 +02:00
2022-09-27 19:13:28 +02:00
// get host
2022-09-16 14:59:23 +02:00
2022-09-17 18:56:20 +02:00
if ( $this -> dynDNSRepository -> findByName ( name : $name )) {
if ( $this -> configController -> getConfig ( configKey : 'verbose' )) {
2022-09-27 19:13:28 +02:00
echo " DynDNS host " . COLOR_YELLOW . $name . COLOR_DEFAULT . " already exists. " . PHP_EOL ;
2022-09-17 18:56:20 +02:00
exit ( 0 );
}
} else {
if ( $this -> configController -> getConfig ( configKey : 'verbose' )) {
2022-09-27 19:13:28 +02:00
echo " DynDNS host " . COLOR_YELLOW . $name . COLOR_DEFAULT . " will be created. " . PHP_EOL ;
2022-09-17 18:56:20 +02:00
// insert in db
2022-09-27 19:13:28 +02:00
$dyndnsHost = new DynDNS ( name : $name );
2022-09-17 18:56:20 +02:00
$dyndnsHost -> setName ( $name );
}
}
2022-09-16 14:59:23 +02:00
2022-09-27 19:13:28 +02:00
// check on NS
// => add if missing
if ( $this -> domainRepository -> findByName ( name : $name )) {
echo " Domain: $name already exists. " . PHP_EOL ;
exit ( 1 );
} else {
if ( ! $this -> panelRepository -> findByName ( name : $panel )) {
echo 'Unknown panel: ' . COLOR_YELLOW . $panel . COLOR_DEFAULT . '.' . PHP_EOL ;
exit ( 1 );
}
$domain = new Domain ( name : $name , panel : $panel );
$result = $this -> domainRepository -> insert ( domain : $domain );
echo 'Domain' . COLOR_YELLOW . $name . COLOR_DEFAULT . ' has been created with id ' . COLOR_YELLOW . $result . COLOR_DEFAULT . '.' . PHP_EOL ;
$this -> domainController -> createSlaveZoneFile ( domain : $domain );
exit ( 0 );
}
}
2022-09-29 19:21:42 +02:00
function domainsCreate () : void
2022-09-27 19:13:28 +02:00
{
// check if we're correctly setup
if ( ! $this -> domainController -> checkPermissions ()) {
echo 'You need to setup the bindAPI first.' . PHP_EOL ;
exit ( 1 );
}
$name = $this -> arguments [ 1 ] ? ? " " ;
if ( empty ( $name )) {
echo 'You need to supply the domain name.' . PHP_EOL ;
exit ( 1 );
}
$filteredName = filter_var ( value : $name , filter : FILTER_VALIDATE_DOMAIN , options : FILTER_FLAG_HOSTNAME );
if ( ! empty ( $filteredName ) && str_contains ( haystack : $filteredName , needle : '.' )) {
$name = $filteredName ;
} else {
echo " $name is no valid DNS domain name. " . PHP_EOL ;
exit ( 1 );
}
$panel = $this -> arguments [ 'panel' ] ? ? '' ;
if ( empty ( $panel )) {
echo 'You need to supply the panel name.' . PHP_EOL ;
exit ( 1 );
}
if ( $this -> domainRepository -> findByName ( name : $name )) {
echo " Domain: $name already exists. " . PHP_EOL ;
exit ( 1 );
} else {
if ( ! $this -> panelRepository -> findByName ( name : $panel )) {
echo 'Unknown panel: ' . COLOR_YELLOW . $panel . COLOR_DEFAULT . '.' . PHP_EOL ;
exit ( 1 );
}
$domain = new Domain ( name : $name , panel : $panel );
$result = $this -> domainRepository -> insert ( domain : $domain );
echo 'Domain' . COLOR_YELLOW . $name . COLOR_DEFAULT . ' has been created with id ' . COLOR_YELLOW . $result . COLOR_DEFAULT . '.' . PHP_EOL ;
$this -> domainController -> createSlaveZoneFile ( domain : $domain );
exit ( 0 );
}
}
/**
*/
2022-09-29 19:21:42 +02:00
function domainsUpdate () : void
2022-09-27 19:13:28 +02:00
{
// check if we're correctly setup
if ( ! $this -> domainController -> checkPermissions ()) {
echo 'You need to setup the bindAPI first.' . PHP_EOL ;
exit ( 1 );
}
$id = intval ( value : $this -> arguments [ 1 ] ? ? 0 );
$name = $this -> arguments [ 'name' ] ? ? '' ;
$panelName = $this -> arguments [ 'panel' ] ? ? '' ;
if ( $id == 0 ) {
echo 'An ID is required' . PHP_EOL ;
exit ( 1 );
}
if ( ! $domain = $this -> domainRepository -> findByID ( id : $id )) {
echo " Domain with ID : $id doesn't exist. " . PHP_EOL ;
exit ( 1 );
}
if ( ! empty ( $panelName )) {
$panel = $this -> panelRepository -> findByName ( name : $panelName );
}
if ( empty ( $name ) && empty ( $panel )) {
echo COLOR_DEFAULT . 'No name or panel given, just recreate the config file' . PHP_EOL ;
$this -> domainController -> updateSlaveZones ();
exit ( 1 );
}
$newDomain = new Domain ( name : $name , panel : $panelName , id : $domain -> getId ());
if ( $this -> domainRepository -> update ( domain : $newDomain ) !== false ) {
echo 'Domain server has been updated' . PHP_EOL ;
$this -> domainController -> updateSlaveZones ();
} else {
echo 'Error while updating domain server.' . PHP_EOL ;
}
}
/**
*/
2022-09-29 19:21:42 +02:00
function domainsDelete () : void
2022-09-27 19:13:28 +02:00
{
if ( empty ( $this -> arguments [ 1 ])) {
echo " You need to supply an ID. " . PHP_EOL ;
exit ( 1 );
}
$id = intval ( value : $this -> arguments [ 1 ]) ? ? 0 ;
if ( $id == 0 ) {
echo " Domain with ID $id not found. " . PHP_EOL ;
exit ( 1 );
}
if ( ! $domain = $this -> domainRepository -> findByID ( id : $id )) {
echo " There is no domain with ID $id . " . PHP_EOL ;
exit ( 1 );
}
$this -> domainRepository -> delete ( domain : $domain );
$this -> domainController -> deleteZone ( domain : $domain );
echo " The domain with ID $id has been deleted. " . PHP_EOL ;
}
/**
* @ return void
*/
2022-09-29 19:21:42 +02:00
function nameserversCreate () : void
2022-09-27 19:13:28 +02:00
{
$name = $this -> arguments [ 1 ] ? ? '' ;
if ( empty ( $name )) {
echo 'You need to supply the nameserver name.' . PHP_EOL ;
exit ( 1 );
}
$filteredName = filter_var ( value : $name , filter : FILTER_VALIDATE_DOMAIN );
if ( ! empty ( $filteredName ) && str_contains ( haystack : $filteredName , needle : '.' )) {
$name = $filteredName ;
} else {
echo " $name is no valid nameserver name. " . PHP_EOL ;
exit ( 1 );
}
$a = $this -> arguments [ 'a' ] ? ? '' ;
$aaaa = $this -> arguments [ 'aaaa' ] ? ? '' ;
if ( empty ( $a ) && empty ( $aaaa )) {
echo 'At least one IP address is required.' . PHP_EOL ;
exit ( 0 );
}
$apikey = $this -> arguments [ 'apikey' ] ? ? '' ;
if ( empty ( $apikey )) {
echo 'An API key is required.' . PHP_EOL ;
exit ( 0 );
}
if ( $this -> nameserverRepository -> findByName ( name : $name )) {
echo " Nameserver: $name already exists. " . PHP_EOL ;
exit ( 1 );
} else {
$nameserver = new Nameserver ( name : $name , a : $a , aaaa : $aaaa , passphrase : $apikey );
$result = $this -> nameserverRepository -> insert ( nameserver : $nameserver );
echo 'Nameserver ' . COLOR_YELLOW . $name . COLOR_DEFAULT . ' has been created with id ' . COLOR_YELLOW . $result . COLOR_DEFAULT . PHP_EOL ;
exit ( 0 );
}
}
/**
* @ return void
*/
2022-09-29 19:21:42 +02:00
function nameserversList () : void
2022-09-27 19:13:28 +02:00
{
$nameservers = $this -> nameserverRepository -> findAll ();
if ( ! empty ( $nameservers )) {
echo 'All available nameservers:' . PHP_EOL ;
$table = new ConsoleTable ();
$table -> setHeaders ( content : [ 'ID' , 'Name' , 'A' , 'AAAA' , 'API Key' ]);
foreach ( $nameservers as $nameserver ) {
$row = [];
$row [] = $nameserver -> getId ();
$row [] = $nameserver -> getName ();
$row [] = $nameserver -> getA ();
$row [] = $nameserver -> getAaaa ();
$row [] = $nameserver -> getApikeyPrefix ();
$table -> addRow ( data : $row );
}
$table -> setPadding ( value : 2 );
$table -> display ();
} else {
echo 'No nameservers found.' . PHP_EOL ;
exit ( 1 );
}
exit ( 0 );
}
/**
*/
2022-09-29 19:21:42 +02:00
function nameserversUpdate () : void
2022-09-27 19:13:28 +02:00
{
$id = $this -> arguments [ 1 ] ? ? 0 ;
$name = $this -> arguments [ 'name' ] ? ? '' ;
$a = $this -> arguments [ 'a' ] ? ? '' ;
$aaaa = $this -> arguments [ 'aaaa' ] ? ? '' ;
$apikey = $this -> arguments [ 'apikey' ] ? ? '' ;
if ( $id == 0 ) {
echo 'An ID is required.' . PHP_EOL ;
exit ( 1 );
}
if ( ! $this -> nameserverRepository -> findByID ( id : intval ( value : $id ))) {
echo 'Nameserver with ID ' . COLOR_YELLOW . $id . COLOR_DEFAULT . " doesn't exist. " . PHP_EOL ;
exit ( 1 );
}
if ( $apikey ) {
$nameserver = new Nameserver ( name : $name , id : intval ( value : $id ), a : $a , aaaa : $aaaa , passphrase : $apikey );
} else {
$nameserver = new Nameserver ( name : $name , id : intval ( value : $id ), a : $a , aaaa : $aaaa );
}
if ( $this -> nameserverRepository -> update ( nameserver : $nameserver ) !== false ) {
echo 'Nameserver ' . COLOR_YELLOW . $id . COLOR_DEFAULT . ' has been updated.' . PHP_EOL ;
} else {
echo 'Error while updating nameserver ' . COLOR_YELLOW . $id . '.' . PHP_EOL ;
}
}
/**
*/
2022-09-29 19:21:42 +02:00
function nameserversDelete () : void
2022-09-27 19:13:28 +02:00
{
if ( empty ( $this -> arguments [ 1 ])) {
echo " You need to supply an ID. " . PHP_EOL ;
exit ( 1 );
}
$id = intval ( value : $this -> arguments [ 1 ] ? ? 0 );
if ( $id == 0 ) {
echo 'Nameserver with ID ' . COLOR_YELLOW . $id . COLOR_DEFAULT . ' not found.' . PHP_EOL ;
exit ( 1 );
}
if ( ! $this -> nameserverRepository -> findByID ( id : $id )) {
echo 'There is no nameserver with ID ' . COLOR_YELLOW . $id . COLOR_DEFAULT . '.' . PHP_EOL ;
exit ( 1 );
}
$this -> nameserverRepository -> delete ( id : $id );
echo 'The nameserver with ID ' . COLOR_YELLOW . $id . COLOR_DEFAULT . ' has been deleted.' . PHP_EOL ;
}
/**
*/
2022-09-29 19:21:42 +02:00
function checkShowIncludes () : void
2022-09-27 19:13:28 +02:00
{
$nameservers = $this -> nameserverRepository -> findAll ();
if ( count ( $nameservers ) === 0 ) {
echo 'No nameservers found.' . PHP_EOL ;
echo 'You first need to setup the system.' . PHP_EOL ;
exit ( 1 );
}
echo COLOR_DEFAULT . 'You need to add these lines to ' . COLOR_YELLOW . '/etc/bind/local.bindapi.options' . COLOR_DEFAULT . ' on every panel and make sure' . PHP_EOL ;
echo 'that ' . COLOR_YELLOW . 'include "/etc/bind/local.bindapi.options";' . COLOR_DEFAULT . ' exists in ' . COLOR_YELLOW . '/etc/bind/named.conf.options' . COLOR_DEFAULT . '.' . PHP_EOL ;
$ip = [];
foreach ( $nameservers as $nameserver ) {
if ( ! empty ( $nameserver -> getA ())) {
$ip [] = $nameserver -> getA ();
}
if ( ! empty ( $nameserver -> getAaaa ())) {
$ip [] = $nameserver -> getAaaa ();
}
}
echo PHP_EOL . 'allow-transfer {' . PHP_EOL ;
foreach ( $ip as $currentIp )
echo " \t $currentIp ; " . PHP_EOL ;
echo '};' ;
echo PHP_EOL . 'also-notify {' . PHP_EOL ;
foreach ( $ip as $currentIp )
echo " \t $currentIp ; " . PHP_EOL ;
echo '};' . PHP_EOL ;
echo PHP_EOL . 'After the modification feel free to run ' . COLOR_YELLOW . 'named-checkconf' . COLOR_DEFAULT . ' to ensure there were no errors.' . PHP_EOL ;
echo PHP_EOL . 'Run ' . COLOR_YELLOW . 'rndc reload' . COLOR_DEFAULT . ' to activate the changes.' . PHP_EOL ;
}
/**
*/
2022-09-29 19:21:42 +02:00
function checkDomains () : void
2022-09-27 19:13:28 +02:00
{
$this -> domainController -> checkDomains ();
}
/**
*/
2022-09-29 19:21:42 +02:00
private function dynDnsPush () : void
2022-09-27 19:13:28 +02:00
{
$hostName = $this -> arguments [ 1 ] ? ? '' ;
if ( empty ( $hostName )) {
echo 'You need to supply at least the hostname' . PHP_EOL ;
exit ( 1 );
}
if ( $this -> configController -> getConfig ( configKey : 'verbose' )) {
echo " Updating DynDNS host: $hostName " . PHP_EOL ;
}
echo 'here' ;
$domain = $this -> domainRepository -> findByHost ( host : $hostName );
print_r ( value : $domain );
echo 'there' ;
// we need the panel who is master for zone
$panel = $this -> panelRepository -> findByName ( name : $domain -> getPanel ());
// which NS belongs to that panel
2022-09-29 19:21:42 +02:00
$encryptionKey = $this -> configController -> getConfig ( configKey : 'encryptionKey' );
$decryptedKey = $this -> encryptionController -> safeDecrypt ( encrypted : $panel -> getApikey (), key : $encryptionKey );
2022-09-27 19:13:28 +02:00
if ( ! empty ( $panel -> getAaaa ())) {
$result = $this -> apiController -> sendCommand (
requestType : 'POST' ,
serverName : $panel -> getName (),
versionIP : 6 ,
2022-09-29 19:21:42 +02:00
apiKey : $decryptedKey ,
2022-09-27 19:13:28 +02:00
command : 'dyndns/' . $hostName ,
serverType : 'nameserver' );
} else {
$result = $this -> apiController -> sendCommand (
requestType : 'POST' ,
serverName : $panel -> getName (),
versionIP : 4 ,
2022-09-29 19:21:42 +02:00
apiKey : $decryptedKey (),
2022-09-27 19:13:28 +02:00
command : 'dyndns/' . $hostName ,
serverType : 'nameserver' );
}
if ( $result [ 'header' ] == 200 ) {
if ( $this -> configController -> getConfig ( configKey : 'verbose' )) {
$data = $result [ 'data' ];
$decodedData = json_decode ( json : $data , associative : true );
echo $decodedData [ 'message' ] . PHP_EOL ;
}
} else {
echo 'Something went wrong:' . PHP_EOL ;
print_r ( value : $result );
exit ( 1 );
}
exit ( 0 );
}
/**
*/
2022-09-29 19:21:42 +02:00
private
function checkGenerateKey () : void
2022-09-27 19:13:28 +02:00
{
echo 'This generates a fresh encryption key.' . PHP_EOL ;
echo 'Copy it to config.json.' . PHP_EOL ;
echo 'Note: You must update all API-Keys for panels and nameservers after changing the key!' . PHP_EOL ;
try {
$key = sodium_bin2hex ( string : sodium_crypto_secretbox_keygen ());
echo 'Suggested new key : "' . COLOR_YELLOW . $key . COLOR_DEFAULT . '".' . PHP_EOL ;
echo PHP_EOL ;
exit ( 0 );
} catch ( SodiumException $e ) {
die ( $e -> getMessage () . PHP_EOL );
}
}
2022-09-29 19:21:42 +02:00
private function domainsRefresh () : void
2022-09-27 19:13:28 +02:00
{
2022-09-29 19:21:42 +02:00
$this -> logger -> debug ( message : " domainsRefresh() " );
2022-09-27 19:13:28 +02:00
$panels = $this -> panelRepository -> findAll ();
2022-09-29 19:21:42 +02:00
2022-09-27 19:13:28 +02:00
foreach ( $panels as $panel ) {
echo COLOR_DEFAULT . 'Checking panel ' . COLOR_YELLOW . $panel -> getName () . COLOR_DEFAULT . PHP_EOL ;
2022-09-29 19:21:42 +02:00
$encryptionKey = $this -> configController -> getConfig ( configKey : 'encryptionKey' );
$decryptedKey = $this -> encryptionController -> safeDecrypt ( encrypted : $panel -> getApikey (), key : $encryptionKey );
2022-09-27 19:13:28 +02:00
if ( empty ( $panel -> getA ())) {
$result = $this -> apiController -> sendCommand (
requestType : 'GET' ,
serverName : $panel -> getName (),
versionIP : 6 ,
2022-09-29 19:21:42 +02:00
apiKey : $decryptedKey ,
2022-09-27 19:13:28 +02:00
command : 'domains?sort=domain&subdomains=false' ,
serverType : 'panel'
);
} else {
$result = $this -> apiController -> sendCommand (
requestType : 'GET' ,
serverName : $panel -> getName (),
versionIP : 4 ,
2022-09-29 19:21:42 +02:00
apiKey : $decryptedKey ,
2022-09-27 19:13:28 +02:00
command : 'domains?sort=domain&subdomains=false' ,
serverType : 'panel' );
}
if ( ! empty ( $result [ 'error' ])) {
echo $result [ 'data' ] . PHP_EOL ;
exit ( 1 );
}
if ( ! empty ( $result [ 'data' ])) {
$domains = json_decode ( json : $result [ 'data' ]);
} else {
echo 'No domains found' . PHP_EOL ;
exit ( 1 );
}
$domainCount = 0 ;
if ( count ( $domains ) > 0 ) {
foreach ( $domains as $domain ) {
$domainCount ++ ;
echo COLOR_YELLOW . ' ' . $domain -> domain ;
if ( $this -> domainRepository -> findByName ( name : $domain -> domain )) {
echo COLOR_GREEN . ' OK' . COLOR_DEFAULT . PHP_EOL ;
} else {
$newDomain = new Domain ( name : $domain -> domain , panel : $panel -> getName ());
$result = $this -> domainRepository -> insert ( domain : $newDomain );
echo COLOR_DEFAULT . ' has been created with id ' . COLOR_YELLOW . $result . COLOR_DEFAULT . '.' . PHP_EOL ;
}
}
}
if ( $domainCount == 0 ) {
echo 'No second level domains found.' . COLOR_DEFAULT . PHP_EOL ;
}
}
$this -> domainController -> updateSlaveZones ();
}
2022-09-29 19:21:42 +02:00
public function webmailCheck () : void
{
$quiet = $this -> configController -> getConfig ( configKey : 'quiet' );
$verbose = $this -> configController -> getConfig ( configKey : 'verbose' );
if ( empty ( $this -> arguments [ 1 ])) {
if ( ! $quiet ) {
echo COLOR_DEFAULT . 'You need to supply a domain name.' . PHP_EOL ;
}
exit ( 1 );
} else {
$domainName = $this -> arguments [ 1 ];
}
if ( ! $quiet ) {
echo COLOR_DEFAULT . 'Checking domain ' . COLOR_YELLOW . $domainName . COLOR_DEFAULT . PHP_EOL ;
}
if ( ! $domain = $this -> domainRepository -> findByName ( name : $domainName )) {
if ( ! $quiet ) {
echo COLOR_DEFAULT . 'Domain ' . $domainName . ' not found on this server.' . PHP_EOL ;
}
exit ( 1 );
}
if ( ! $this -> domainController -> isMasterZone ( domain : $domain )) {
if ( ! $quiet ) {
echo 'This server is not responsible for ' . COLOR_YELLOW . $domainName . COLOR_DEFAULT . '.' . PHP_EOL ;
}
exit ( 1 );
}
$panel = $this -> panelRepository -> getSelf ();
$encryptionKey = $this -> configController -> getConfig ( configKey : 'encryptionKey' );
$decryptedKey = $this -> encryptionController -> safeDecrypt ( encrypted : $panel -> getApikey (), key : $encryptionKey );
$webmailDomain = 'webmail.' . $domainName ;
if ( ! empty ( $panel -> getAAAA ())) {
if ( $verbose ) {
echo 'Check using IPv6: ' . COLOR_YELLOW . $panel -> getAaaa () . COLOR_DEFAULT . PHP_EOL ;
}
$result = $this -> apiController -> sendCommand (
requestType : 'GET' ,
serverName : $panel -> getName (),
versionIP : 6 ,
apiKey : $decryptedKey ,
command : 'domains/name/' . $webmailDomain ,
serverType : 'panel' );
} else {
if ( $verbose ) {
echo 'Check using IPv4: ' . COLOR_YELLOW . $panel -> getA () . COLOR_DEFAULT . PHP_EOL ;
}
$result = $this -> apiController -> sendCommand (
requestType : 'GET' ,
serverName : $panel -> getName (),
versionIP : 4 ,
apiKey : $decryptedKey ,
command : 'domains/name/' . $webmailDomain ,
serverType : 'panel' );
}
if ( $result [ 'header' ] === 404 ) {
if ( ! $quiet ) {
echo 'The domain ' . COLOR_YELLOW . $webmailDomain . COLOR_DEFAULT . ' doesn\'t exist.' . PHP_EOL ;
}
exit ( 1 );
} else {
if ( ! $quiet ) {
echo 'Found ' . COLOR_YELLOW . $webmailDomain . COLOR_DEFAULT . '.' . PHP_EOL ;
}
}
$domainData = json_decode ( json : $result [ 'data' ]);
$apacheData = $domainData -> apache ;
$httpDirectives = $apacheData -> http_directives ;
$httpsDirectives = $apacheData -> https_directives . PHP_EOL ;
if ( ! str_contains ( haystack : $httpsDirectives , needle : '# bindAPI - webmailer' )) {
if ( ! $quiet ) {
echo 'Generated config is missing.' . PHP_EOL ;
}
exit ( 1 );
}
}
public function webmailCreate ()
{
$webmailConfig = '# bindAPI - webmailer' . PHP_EOL ;
$webmailConfig .= 'SSLProxyEngine On' . PHP_EOL ;
$webmailConfig .= 'ProxyPass /.well-known/ !' . PHP_EOL ;
$webmailConfig .= 'ProxyPass "/" "https://' . $panel -> getName () . '/webmail/"' . PHP_EOL ;
$webmailConfig .= '## bindAPI - webmailer' . PHP_EOL ;
echo $webmailConfig ;
//$httpsDirectives += $w
}
2022-09-16 14:59:23 +02:00
}