merge branch '0.11-dev' of https://github.com/Froxlor/Froxlor into 0.11-dev
This commit is contained in:
@@ -233,7 +233,7 @@ return array(
|
||||
'save_method' => 'storeSettingField',
|
||||
'advanced_mode' => true
|
||||
),
|
||||
'system_disable_le_selfcheck' => array(
|
||||
'system_le_domain_dnscheck' => array(
|
||||
'label' => $lng['serversettings']['le_domain_dnscheck'],
|
||||
'settinggroup' => 'system',
|
||||
'varname' => 'le_domain_dnscheck',
|
||||
|
||||
@@ -29,20 +29,30 @@ define('UPDATE_URI', "https://version.froxlor.org/Froxlor/api/" . \Froxlor\Froxl
|
||||
define('RELEASE_URI', "https://autoupdate.froxlor.org/froxlor-{version}.zip");
|
||||
define('CHECKSUM_URI', "https://autoupdate.froxlor.org/froxlor-{version}.zip.sha256");
|
||||
|
||||
// check for archive-stuff
|
||||
if (!extension_loaded('zip')) {
|
||||
\Froxlor\UI\Response::redirectTo($filename, array(
|
||||
'page' => 'error',
|
||||
'errno' => 2
|
||||
));
|
||||
}
|
||||
if ($page != 'error') {
|
||||
// check for archive-stuff
|
||||
if (!extension_loaded('zip')) {
|
||||
\Froxlor\UI\Response::redirectTo($filename, array(
|
||||
'page' => 'error',
|
||||
'errno' => 2
|
||||
));
|
||||
}
|
||||
|
||||
// 0.11.x requires 7.4 at least
|
||||
if (version_compare("7.4.0", PHP_VERSION, ">=")) {
|
||||
\Froxlor\UI\Response::redirectTo($filename, array(
|
||||
'page' => 'error',
|
||||
'errno' => 10
|
||||
));
|
||||
// 0.11.x requires 7.4 at least
|
||||
if (version_compare("7.4.0", PHP_VERSION, ">=")) {
|
||||
\Froxlor\UI\Response::redirectTo($filename, array(
|
||||
'page' => 'error',
|
||||
'errno' => 10
|
||||
));
|
||||
}
|
||||
|
||||
// check for webupdate to be enabled
|
||||
if (\Froxlor\Settings::Config('enable_webupdate') != true) {
|
||||
\Froxlor\UI\Response::redirectTo($filename, array(
|
||||
'page' => 'error',
|
||||
'errno' => 11
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// display initial version check
|
||||
@@ -281,5 +291,6 @@ elseif ($page == 'error') {
|
||||
// 8 = could not extract archive
|
||||
// 9 = checksum mismatch
|
||||
// 10 = <php-7.4
|
||||
// 11 = enable_webupdate = false
|
||||
\Froxlor\UI\Response::standard_error('autoupdate_' . $errno);
|
||||
}
|
||||
|
||||
2
api.php
2
api.php
@@ -23,7 +23,7 @@ require __DIR__ . '/lib/tables.inc.php';
|
||||
|
||||
// Return response
|
||||
try {
|
||||
echo (new Api)->handle(@file_get_contents('php://input'));
|
||||
echo (new Api)->formatMiddleware(@file_get_contents('php://input'))->handle();
|
||||
} catch (Exception $e) {
|
||||
echo \Froxlor\Api\Response::jsonErrorResponse($e->getMessage(), $e->getCode());
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Froxlor\Api;
|
||||
|
||||
use Exception;
|
||||
@@ -21,55 +22,77 @@ use voku\helper\AntiXSS;
|
||||
*/
|
||||
class Api
|
||||
{
|
||||
protected array $headers;
|
||||
protected array $headers;
|
||||
|
||||
/**
|
||||
* Api constructor.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->headers = getallheaders();
|
||||
protected $request = null;
|
||||
|
||||
// set header for the response
|
||||
header("Accept: application/json");
|
||||
header("Content-Type: application/json");
|
||||
/**
|
||||
* Api constructor.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->headers = getallheaders();
|
||||
|
||||
// check whether API interface is enabled after all
|
||||
if (\Froxlor\Settings::Get('api.enabled') != 1) {
|
||||
throw new Exception('API is not enabled. Please contact the administrator if you think this is wrong.', 400);
|
||||
}
|
||||
}
|
||||
// set header for the response
|
||||
header("Accept: application/json");
|
||||
header("Content-Type: application/json");
|
||||
|
||||
/**
|
||||
* Handle incoming api request to our backend.
|
||||
*
|
||||
* @param mixed $request
|
||||
* @throws Exception
|
||||
*/
|
||||
public function handle($request)
|
||||
{
|
||||
// validate content
|
||||
$request = \Froxlor\Api\FroxlorRPC::validateRequest($request);
|
||||
$request = (new AntiXSS())->xss_clean(
|
||||
$this->stripcslashesDeep($request)
|
||||
);
|
||||
// check whether API interface is enabled after all
|
||||
if (\Froxlor\Settings::Get('api.enabled') != 1) {
|
||||
throw new Exception('API is not enabled. Please contact the administrator if you think this is wrong.', 400);
|
||||
}
|
||||
}
|
||||
|
||||
// now actually do it
|
||||
$cls = "\\Froxlor\\Api\\Commands\\" . $request['command']['class'];
|
||||
$method = $request['command']['method'];
|
||||
$apiObj = new $cls([
|
||||
'apikey' => $_SERVER['PHP_AUTH_USER'],
|
||||
'secret' => $_SERVER['PHP_AUTH_PW']
|
||||
], $request['params']);
|
||||
/**
|
||||
* @param mixed $request
|
||||
*
|
||||
* @return Api
|
||||
*/
|
||||
public function formatMiddleware($request): Api
|
||||
{
|
||||
// check auf RESTful api call
|
||||
$this->request = $request;
|
||||
|
||||
// call the method with the params if any
|
||||
return $apiObj->$method();
|
||||
}
|
||||
$uri = parse_url($_SERVER["REQUEST_URI"], PHP_URL_QUERY);
|
||||
// map /module/command to internal request array if match
|
||||
if (!empty($uri) && preg_match("/^\/([a-z]+)\/([a-z]+)\/?/", $uri, $matches)) {
|
||||
$request = [];
|
||||
$request['command'] = ucfirst($matches[1]) . '.' . $matches[2];
|
||||
$request['params'] = !empty($this->request) ? json_decode($this->request, true) : null;
|
||||
$this->request = json_encode($request);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* Handle incoming api request to our backend.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$request = $this->request;
|
||||
// validate content
|
||||
$request = \Froxlor\Api\FroxlorRPC::validateRequest($request);
|
||||
$request = (new AntiXSS())->xss_clean(
|
||||
$this->stripcslashesDeep($request)
|
||||
);
|
||||
|
||||
private function stripcslashesDeep($value)
|
||||
{
|
||||
return is_array($value) ? array_map([$this, 'stripcslashesDeep'], $value) : stripcslashes($value);
|
||||
}
|
||||
// now actually do it
|
||||
$cls = "\\Froxlor\\Api\\Commands\\" . $request['command']['class'];
|
||||
$method = $request['command']['method'];
|
||||
$apiObj = new $cls([
|
||||
'apikey' => $_SERVER['PHP_AUTH_USER'],
|
||||
'secret' => $_SERVER['PHP_AUTH_PW']
|
||||
], $request['params']);
|
||||
|
||||
// call the method with the params if any
|
||||
return $apiObj->$method();
|
||||
}
|
||||
|
||||
private function stripcslashesDeep($value)
|
||||
{
|
||||
return is_array($value) ? array_map([$this, 'stripcslashesDeep'], $value) : stripcslashes($value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -760,6 +760,7 @@ class Lighttpd extends HttpConfigBase
|
||||
'customerid' => $domain['customerid']
|
||||
));
|
||||
|
||||
$diroption_text = '';
|
||||
while ($row_htpasswds = $result_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
if ($this->auth_backend_loaded[$domain['ipandport']] != 'yes' && $this->auth_backend_loaded[$domain['ssl_ipandport']] != 'yes') {
|
||||
$filename = $domain['customerid'] . '.htpasswd';
|
||||
@@ -836,6 +837,7 @@ class Lighttpd extends HttpConfigBase
|
||||
}
|
||||
}
|
||||
|
||||
$servernames_text = '';
|
||||
for ($i = 0; $i < sizeof($server_string); $i ++) {
|
||||
$data = $server_string[$i];
|
||||
|
||||
|
||||
@@ -324,8 +324,8 @@ class TasksCron extends \Froxlor\Cron\FroxlorCron
|
||||
|
||||
if (file_exists($logsdir) && $logsdir != '/' && $logsdir != \Froxlor\FileDir::makeCorrectDir(Settings::Get('system.logfiles_directory')) && substr($logsdir, 0, strlen(Settings::Get('system.logfiles_directory'))) == Settings::Get('system.logfiles_directory')) {
|
||||
// build up wildcard for webX-{access,error}.log{*}
|
||||
$logfiles .= '-*';
|
||||
\Froxlor\FileDir::safe_exec('rm -f ' . escapeshellarg($logfiles));
|
||||
$logsdir .= '-*';
|
||||
\Froxlor\FileDir::safe_exec('rm -f ' . escapeshellarg($logsdir));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -496,7 +496,7 @@ class FileDir
|
||||
};
|
||||
|
||||
// create RecursiveIteratorIterator
|
||||
$its = new \RecursiveIteratorIterator(new \RecursiveCallbackFilterIterator(new System\IgnorantRecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS), $filter));
|
||||
$its = new \RecursiveIteratorIterator(new \RecursiveCallbackFilterIterator(new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS), $filter));
|
||||
// we can limit the recursion-depth, but will it be helpful or
|
||||
// will people start asking "why do I only see 2 subdirectories, i want to use /a/b/c"
|
||||
// let's keep this in mind and see whether it will be useful
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Froxlor;
|
||||
|
||||
use Froxlor\Database\Database;
|
||||
@@ -43,6 +44,13 @@ class Settings
|
||||
*/
|
||||
private static $data = null;
|
||||
|
||||
/**
|
||||
* local config overrides
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $conf = null;
|
||||
|
||||
/**
|
||||
* changed and unsaved settings data
|
||||
*
|
||||
@@ -65,6 +73,7 @@ class Settings
|
||||
{
|
||||
if (empty(self::$data)) {
|
||||
self::readSettings();
|
||||
self::readConfig();
|
||||
self::$updatedata = array();
|
||||
|
||||
// prepare statement
|
||||
@@ -92,6 +101,24 @@ class Settings
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read in all config overrides from
|
||||
* config/config.inc.php
|
||||
*/
|
||||
private static function readConfig()
|
||||
{
|
||||
// set defaults
|
||||
self::$conf = [
|
||||
'enable_webupdate' => false
|
||||
];
|
||||
|
||||
$configfile = Froxlor::getInstallDir() . '/lib/config.inc.php';
|
||||
if (@file_exists($configfile) && is_readable($configfile)) {
|
||||
self::$conf = include $configfile;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* update a value in the database
|
||||
*
|
||||
@@ -122,7 +149,7 @@ class Settings
|
||||
self::init();
|
||||
$sstr = explode(".", $setting);
|
||||
// no separator - do'h
|
||||
if (! isset($sstr[1])) {
|
||||
if (!isset($sstr[1])) {
|
||||
return null;
|
||||
}
|
||||
$result = null;
|
||||
@@ -170,7 +197,7 @@ class Settings
|
||||
if (self::Get($setting) !== null) {
|
||||
// set new value in array
|
||||
$sstr = explode(".", $setting);
|
||||
if (! isset($sstr[1])) {
|
||||
if (!isset($sstr[1])) {
|
||||
return false;
|
||||
}
|
||||
self::$data[$sstr[0]][$sstr[1]] = $value;
|
||||
@@ -179,12 +206,12 @@ class Settings
|
||||
self::storeSetting($sstr[0], $sstr[1], $value);
|
||||
} else {
|
||||
// set temporary data for usage
|
||||
if (! isset(self::$data[$sstr[0]]) || ! is_array(self::$data[$sstr[0]])) {
|
||||
if (!isset(self::$data[$sstr[0]]) || !is_array(self::$data[$sstr[0]])) {
|
||||
self::$data[$sstr[0]] = array();
|
||||
}
|
||||
self::$data[$sstr[0]][$sstr[1]] = $value;
|
||||
// set update-data when invoking Flush()
|
||||
if (! isset(self::$updatedata[$sstr[0]]) || ! is_array(self::$updatedata[$sstr[0]])) {
|
||||
if (!isset(self::$updatedata[$sstr[0]]) || !is_array(self::$updatedata[$sstr[0]])) {
|
||||
self::$updatedata[$sstr[0]] = array();
|
||||
}
|
||||
self::$updatedata[$sstr[0]][$sstr[1]] = $value;
|
||||
@@ -210,7 +237,7 @@ class Settings
|
||||
if (self::Get($setting) === null) {
|
||||
// validate parameter
|
||||
$sstr = explode(".", $setting);
|
||||
if (! isset($sstr[1])) {
|
||||
if (!isset($sstr[1])) {
|
||||
return false;
|
||||
}
|
||||
// prepare statement
|
||||
@@ -291,7 +318,7 @@ class Settings
|
||||
'varname' => $field_details['varname']
|
||||
));
|
||||
|
||||
if (! empty($row)) {
|
||||
if (!empty($row)) {
|
||||
$varvalue = $row['value'];
|
||||
} else {
|
||||
$varvalue = $field_details['default'];
|
||||
@@ -306,4 +333,19 @@ class Settings
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get value from config by identifier
|
||||
*/
|
||||
public static function Config(string $config)
|
||||
{
|
||||
self::init();
|
||||
$sstr = explode(".", $config);
|
||||
$result = self::$conf;
|
||||
foreach ($sstr as $key) {
|
||||
$result = $result[$key] ?? null;
|
||||
if (empty($result)) break;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
<?php
|
||||
namespace Froxlor\System;
|
||||
|
||||
/**
|
||||
* If you use RecursiveDirectoryIterator with RecursiveIteratorIterator and run
|
||||
* into UnexpectedValueException you may use this little hack to ignore those
|
||||
* directories, such as lost+found on linux.
|
||||
* (User "antennen" @ http://php.net/manual/en/class.recursivedirectoryiterator.php#101654)
|
||||
*/
|
||||
class IgnorantRecursiveDirectoryIterator extends \RecursiveDirectoryIterator
|
||||
{
|
||||
|
||||
public function getChildren()
|
||||
{
|
||||
try {
|
||||
return new IgnorantRecursiveDirectoryIterator($this->getPathname());
|
||||
} catch (\UnexpectedValueException $e) {
|
||||
return new \RecursiveArrayIterator(array());
|
||||
}
|
||||
}
|
||||
}
|
||||
8
lib/config.inc.php
Normal file
8
lib/config.inc.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* change the options below to either true or false
|
||||
*/
|
||||
return [
|
||||
'enable_webupdate' => false
|
||||
];
|
||||
@@ -119,7 +119,6 @@ return array(
|
||||
'image' => 'icons/domain_add.png',
|
||||
'fields' => array(
|
||||
'documentroot' => array(
|
||||
'visible' => $userinfo['change_serversettings'] == '1',
|
||||
'label' => 'DocumentRoot',
|
||||
'desc' => $lng['panel']['emptyfordefault'],
|
||||
'type' => 'text'
|
||||
|
||||
@@ -129,7 +129,6 @@ return array(
|
||||
'image' => 'icons/domain_edit.png',
|
||||
'fields' => array(
|
||||
'documentroot' => array(
|
||||
'visible' => $userinfo['change_serversettings'] == '1',
|
||||
'label' => 'DocumentRoot',
|
||||
'desc' => $lng['panel']['emptyfordefault'],
|
||||
'type' => 'text',
|
||||
|
||||
@@ -228,7 +228,7 @@ return array(
|
||||
'url' => 'admin_autoupdate.php?page=overview',
|
||||
'label' => $lng['admin']['autoupdate'],
|
||||
'required_resources' => 'change_serversettings',
|
||||
'show_element' => extension_loaded('zip')
|
||||
'show_element' => extension_loaded('zip') && \Froxlor\Settings::Config('enable_webupdate')
|
||||
),
|
||||
array(
|
||||
'url' => 'admin_settings.php?page=wipecleartextmailpws',
|
||||
|
||||
@@ -898,7 +898,7 @@ $lng['serversettings']['session_allow_multiple_login']['description'] = 'If acti
|
||||
$lng['serversettings']['panel_allow_domain_change_admin']['title'] = 'Allow moving domains between admins';
|
||||
$lng['serversettings']['panel_allow_domain_change_admin']['description'] = 'If activated you can change the admin of a domain at domainsettings.<br /><b>Attention:</b> If a customer isn\'t assigned to the same admin as the domain, the admin can see every other domain of that customer!';
|
||||
$lng['serversettings']['panel_allow_domain_change_customer']['title'] = 'Allow moving domains between customers';
|
||||
$lng['serversettings']['panel_allow_domain_change_customer']['description'] = 'If activated you can change the customer of a domain at domainsettings.<br /><b>Attention:</b> Froxlor won\'t change any paths. This could render a domain unusable!';
|
||||
$lng['serversettings']['panel_allow_domain_change_customer']['description'] = 'If activated you can change the customer of a domain at domainsettings.<br /><b>Attention:</b> Froxlor changes the documentroot to the new customer\'s default homedir (+ domain-folder if activated)';
|
||||
$lng['domains']['associated_with_domain'] = 'Associated';
|
||||
$lng['domains']['aliasdomains'] = 'Alias domains';
|
||||
$lng['error']['ipportdoesntexist'] = 'The ip/port combination you have chosen doesn\'t exist.';
|
||||
@@ -1878,6 +1878,7 @@ $lng['error']['autoupdate_7'] = 'The downloaded archive could not be found :(';
|
||||
$lng['error']['autoupdate_8'] = 'The archive could not be extracted :(';
|
||||
$lng['error']['autoupdate_9'] = 'The downloaded file did not pass the integrity check. Please try to update again.';
|
||||
$lng['error']['autoupdate_10'] = 'Minimum supported version of PHP is 7.4.0';
|
||||
$lng['error']['autoupdate_11'] = 'Webupdate is disabled';
|
||||
|
||||
$lng['admin']['server_php'] = 'PHP';
|
||||
$lng['domains']['termination_date'] = 'Date of termination';
|
||||
|
||||
@@ -892,7 +892,7 @@ $lng['serversettings']['session_allow_multiple_login']['description'] = 'Wenn di
|
||||
$lng['serversettings']['panel_allow_domain_change_admin']['title'] = 'Erlaube Verschieben von Domains unter Admins';
|
||||
$lng['serversettings']['panel_allow_domain_change_admin']['description'] = 'Wenn diese Option aktiviert ist, kann unter Domaineinstellungen die Domain einem anderen Admin zugewiesen werden.<br /><b>Achtung:</b> Wenn der Kunde einer Domain nicht dem gleichen Admin zugeordnet ist wie die Domain selbst, kann dieser Admin alle anderen Domains des Kunden sehen!';
|
||||
$lng['serversettings']['panel_allow_domain_change_customer']['title'] = 'Erlaube Verschieben von Domains unter Kunden';
|
||||
$lng['serversettings']['panel_allow_domain_change_customer']['description'] = 'Wenn diese Option aktiviert ist, kann unter Domaineinstellungen die Domain einem anderen Kunden zugewiesen werden.<br /><b>Achtung:</b> Es werden keine Pfade bei dieser Aktion angepasst. Das kann dazu führen, dass die Domain nach dem Verschieben nicht mehr richtig funktioniert!';
|
||||
$lng['serversettings']['panel_allow_domain_change_customer']['description'] = 'Wenn diese Option aktiviert ist, kann unter Domaineinstellungen die Domain einem anderen Kunden zugewiesen werden.<br /><b>Achtung:</b> Der Dokumenten-Pfad der Domain wird auf den Heimatpfad (+ Domain-Ordner, sofern aktiviert) des neuen Kunden gesetzt.';
|
||||
$lng['domains']['associated_with_domain'] = 'Verbunden mit';
|
||||
$lng['domains']['aliasdomains'] = 'Aliasdomains';
|
||||
$lng['error']['ipportdoesntexist'] = 'Die gewählte IP/Port-Kombination existiert nicht.';
|
||||
@@ -1525,6 +1525,7 @@ $lng['error']['autoupdate_7'] = 'Das heruntergeladene Archiv konnte nicht gefund
|
||||
$lng['error']['autoupdate_8'] = 'Das Archiv konnte nicht entpackt werden :(';
|
||||
$lng['error']['autoupdate_9'] = 'Die heruntergeladene Datei konnte nicht verifiziert werden. Bitte erneut versuchen zu aktualisieren.';
|
||||
$lng['error']['autoupdate_10'] = 'Minimum unterstützte Version von PHP ist 7.4.0';
|
||||
$lng['error']['autoupdate_11'] = 'Webupdate ist deaktiviert';
|
||||
|
||||
$lng['domains']['termination_date'] = 'Kündigungsdatum';
|
||||
$lng['domains']['termination_date_overview'] = 'gekündigt zum ';
|
||||
|
||||
Reference in New Issue
Block a user