Compare commits

..

30 Commits

Author SHA1 Message Date
Michael Kaufmann
5615decd96 set version to 2.1.1 for bugfix release (dns and install)
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-12-10 08:20:12 +01:00
Michael Kaufmann
0348b1ec7e fix wrong result in Domain::getMainSubdomainIds(); fixes #1202
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-12-09 14:25:58 +01:00
Michael Kaufmann
1467dab58f set version to 2.1.0 for upcoming stable release
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-12-08 11:48:32 +01:00
Michael Kaufmann
3a8f48de35 check subclass for cli commands to be \Symfony\Component\Console\Command\Command as the installcommand does not use \Froxlor\Cli\CliCommand
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-12-07 11:16:53 +01:00
Michael Kaufmann
46391c06ec Merge branch 'main' of github.com:Froxlor/Froxlor 2023-12-06 08:11:17 +01:00
dependabot[bot]
7103f7dd51 Bump vite from 4.4.11 to 4.4.12 (#1201)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 4.4.11 to 4.4.12.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v4.4.12/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v4.4.12/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-06 08:11:01 +01:00
Michael Kaufmann
9fc1dfee41 better check for invalid cli classes
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-12-05 12:50:57 +01:00
Michael Kaufmann
82dc76fdc6 fix wrong escaping of backslash in class-names when updating cronjobs_run table; add missing validateFormField-method for type 'image' (needs to be present but image-validation is handled elsewhere
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-12-05 11:16:41 +01:00
Michael Kaufmann
02ae52e3df remove old files in updater; avoid including old cli files in froxlor-cli; fix css for card list-groups
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-12-05 10:22:12 +01:00
Michael Kaufmann
5c06683e27 set version to 2.1.0-rc3
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-12-01 21:41:21 +01:00
Michael Kaufmann
2684372156 little work on installation; replace hardcoded strings with variables/constants; update dependencies
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-11-30 11:41:20 +01:00
Michael Kaufmann
d80c6d5714 dynamically read in CLI commands for froxlor-bin
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-11-28 09:07:30 +01:00
Michael Kaufmann
1ae5311b81 disable default php-fpm config for apache as for some users, it is enabled and used prior to froxlor generated virtual-host configs resulting in no php-rendering
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-11-27 16:43:13 +01:00
Michael Kaufmann
e1e7555cce minor textual adjustments; add non-session-based csrf-token for js/axios as it is configured to append it to the http-request
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-11-27 16:42:15 +01:00
Michael Kaufmann
4f79d7cf4b check php-extension requirements not only on installation (e.g. when php version was changed)
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-11-26 22:22:39 +01:00
Michael Kaufmann
b13b1e8ac7 correctly handle empty logger.logfile setting if 'file' is in the activated log-types and no file name was given, thx to Oops
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-11-26 17:56:30 +01:00
Michael Kaufmann
6a1e7cc539 actually create notice file for 'unconfigured/unmanaged domain' and redirect it for potential dynamic contents (e.g. file extension php) to work properly
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-11-26 15:19:49 +01:00
Michael Kaufmann
2e87633ef7 table-adjustments for panel_templates #2
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-11-26 10:58:19 +01:00
Michael Kaufmann
8a23d0b72c table-adjustments for panel_templates
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-11-26 10:55:24 +01:00
Michael Kaufmann
735ef85088 make unconfigured/unknown domain page a file-template
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-11-26 10:53:41 +01:00
Michael Kaufmann
75cf44a6d2 respect custom-theme variants in UI::getTheme(); add margin to customer-services dashboard-badges
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-11-26 09:24:44 +01:00
Michael Kaufmann
7e0073f4a3 on building nightly, of course also install composer dependencies
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-11-15 22:53:23 +01:00
Michael Kaufmann
c9291df345 rename validateFormFieldHiddenString to validateFormFieldPassword
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-11-15 22:37:25 +01:00
Michael Kaufmann
fd5e97d48c introduce nightly builds and nightly-update-channel
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-11-15 22:16:29 +01:00
Michael Kaufmann
64a9fb163a remove duplicated code-line
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-11-15 10:34:31 +01:00
Michael Kaufmann
b0256ffb7d add REBUILD_VHOST task if only openbasedir-path value changes; fixes #1200
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-11-15 08:08:48 +01:00
Michael Kaufmann
e606bdc97f Merge branch 'main' of github.com:Froxlor/Froxlor 2023-11-12 13:09:07 +01:00
Michael Kaufmann
b53b3a924a fix wrong database-update procedure in update-command, fix distribution guessing on installation
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-11-12 13:08:40 +01:00
Michael Kaufmann
539ea7c8fc corrected passing of ref-variable to workflow 2023-11-11 22:02:11 +01:00
Michael Kaufmann
5e8763e160 Update build-docs.yml 2023-11-11 21:55:22 +01:00
43 changed files with 553 additions and 352 deletions

View File

@@ -2,7 +2,8 @@ name: build-documentation
on: on:
release: release:
types: [published] # only run for stable releases
types: [released]
jobs: jobs:
build_docs: build_docs:
@@ -11,4 +12,4 @@ jobs:
- env: - env:
GITHUB_TOKEN: ${{ secrets.ORG_GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.ORG_GITHUB_TOKEN }}
run: | run: |
gh workflow run --repo Froxlor/Documentation build-and-deploy.yml -f type=tags ref=${{github.ref_name}} gh workflow run --repo Froxlor/Documentation build-and-deploy.yml -f type=tags -f ref=${{github.ref_name}}

View File

@@ -1,5 +1,5 @@
name: Froxlor-CI-MariaDB name: Froxlor-CI-MariaDB
on: ['push', 'pull_request', 'create'] on: [ 'push', 'pull_request', 'create' ]
jobs: jobs:
froxlor: froxlor:
@@ -8,8 +8,8 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
php-versions: ['7.4', '8.2'] php-versions: [ '7.4', '8.2' ]
mariadb-version: [10.11, 10.5] mariadb-version: [ 10.11, 10.5 ]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
@@ -49,33 +49,81 @@ jobs:
- name: Run testing - name: Run testing
run: ant quick-build run: ant quick-build
# - name: irc push nightly:
# uses: rectalogic/notify-irc@v1 name: Create nightly/testing tarball
# if: github.event_name == 'push' runs-on: ubuntu-latest
# with: needs: froxlor
# channel: "#froxlor" if: ${{ github.event_name == 'push' }}
# server: "irc.libera.chat"
# nickname: froxlor-ci
# message: |
# ${{ github.actor }} pushed ${{ github.event.ref }} ${{ github.event.compare }}
# ${{ join(github.event.commits.*.message) }}
# - name: irc pull request steps:
# uses: rectalogic/notify-irc@v1 - name: Checkout
# if: github.event_name == 'pull_request' uses: actions/checkout@v3
# with:
# channel: "#froxlor"
# server: "irc.libera.chat"
# nickname: froxlor-ci
# message: |
# ${{ github.actor }} opened PR ${{ github.event.pull_request.html_url }}
# - name: irc tag created - name: Setup PHP with PECL extension
# uses: rectalogic/notify-irc@v1 uses: shivammathur/setup-php@v2
# if: github.event_name == 'create' && github.event.ref_type == 'tag' with:
# with: php-version: '7.4'
# channel: "#froxlor" tools: composer:v2
# server: "irc.libera.chat" extensions: mbstring, xml, ctype, pdo_mysql, mysql, curl, json, zip, session, filter, posix, openssl, fileinfo, bcmath, gmp, gnupg
# nickname: froxlor-ci
# message: | - name: Install composer dependencies
# ${{ github.actor }} tagged ${{ github.repository }} ${{ github.event.ref }} run: composer install --no-dev
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: '20.x'
- name: Install npm dependencies
run: npm install
- name: Build assets
run: npm run build
working-directory: .
- name: Setting file/directory permissions
run: |
find -exec chmod ugo+r,u+w,go-w {} \;
find -type f -exec chmod ugo-x {} \;
find -type d -exec chmod ugo+x {} \;
chmod 0755 bin/froxlor-cli
- name: Remove vcs and unneeded files
run: |
rm .gitignore
rm .editorconfig
rm -rf node_modules
rm composer.json
rm composer.lock
rm package.json
rm package-lock.json
rm *.xml
rm vite.config.js
- name: Create empty index.html in built assets directory
run: |
touch templates/Froxlor/build/index.html
touch templates/Froxlor/build/assets/index.html
- name: Set outputs
id: vars
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Set nightly branding
run: |
sed -i "s/const BRANDING = '';/const BRANDING = '+nightly.${{steps.vars.outputs.sha_short}}';/" lib/Froxlor/Froxlor.php
zip -r froxlor-nightly.${{steps.vars.outputs.sha_short}}.zip . -x "*.git*"
sha256sum froxlor-nightly.${{steps.vars.outputs.sha_short}}.zip > froxlor-nightly.${{steps.vars.outputs.sha_short}}.zip.sha256
mkdir dist
mv froxlor-nightly.${{steps.vars.outputs.sha_short}}.zip dist/
mv froxlor-nightly.${{steps.vars.outputs.sha_short}}.zip.sha256 dist/
- name: Deploy nightly to server
uses: easingthemes/ssh-deploy@v3.4.3
env:
ARGS: "-rltDzvO --chown=${{ secrets.WEB_USER }}:${{ secrets.WEB_USER }}"
SOURCE: "dist/"
SSH_PRIVATE_KEY: ${{ secrets.SERVER_SSH_KEY }}
REMOTE_HOST: ${{ secrets.REMOTE_HOST }}
REMOTE_USER: ${{ secrets.REMOTE_USER }}
TARGET: "${{ secrets.REMOTE_TARGET }}"

View File

@@ -130,7 +130,8 @@ return [
'default' => 'stable', 'default' => 'stable',
'select_var' => [ 'select_var' => [
'stable' => lng('serversettings.uc_stable'), 'stable' => lng('serversettings.uc_stable'),
'testing' => lng('serversettings.uc_testing') 'testing' => lng('serversettings.uc_testing'),
'nightly' => lng('serversettings.uc_nightly')
], ],
'save_method' => 'storeSettingField', 'save_method' => 'storeSettingField',
'advanced_mode' => true 'advanced_mode' => true
@@ -171,16 +172,6 @@ return [
'default' => false, 'default' => false,
'save_method' => 'storeSettingField' 'save_method' => 'storeSettingField'
], ],
'system_index_file_extension' => [
'label' => lng('serversettings.index_file_extension'),
'settinggroup' => 'system',
'varname' => 'index_file_extension',
'type' => 'text',
'string_regexp' => '/^[a-zA-Z0-9]{1,6}$/',
'default' => 'html',
'save_method' => 'storeSettingField',
'advanced_mode' => true
],
'system_store_index_file_subs' => [ 'system_store_index_file_subs' => [
'label' => lng('serversettings.system_store_index_file_subs'), 'label' => lng('serversettings.system_store_index_file_subs'),
'settinggroup' => 'system', 'settinggroup' => 'system',

View File

@@ -60,7 +60,8 @@ if (Settings::Get('panel.sendalternativemail') == 1) {
} }
$file_templates = [ $file_templates = [
'index_html' 'index_html',
'unconfigured_html'
]; ];
$languages = Language::getLanguages(); $languages = Language::getLanguages();

View File

@@ -24,20 +24,8 @@
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2 * @license https://files.froxlor.org/misc/COPYING.txt GPLv2
*/ */
declare(strict_types=1);
use Froxlor\Cli\ConfigDiff;
use Symfony\Component\Console\Application;
use Froxlor\Cli\RunApiCommand;
use Froxlor\Cli\ConfigServices;
use Froxlor\Cli\PhpSessionclean;
use Froxlor\Cli\SwitchServerIp;
use Froxlor\Cli\UpdateCommand;
use Froxlor\Cli\InstallCommand;
use Froxlor\Cli\MasterCron;
use Froxlor\Cli\UserCommand;
use Froxlor\Cli\ValidateAcmeWebroot;
use Froxlor\Froxlor; use Froxlor\Froxlor;
use Symfony\Component\Console\Application;
// validate correct php version // validate correct php version
if (version_compare("7.4.0", PHP_VERSION, ">=")) { if (version_compare("7.4.0", PHP_VERSION, ">=")) {
@@ -53,14 +41,31 @@ require dirname(__DIR__) . '/vendor/autoload.php';
require dirname(__DIR__) . '/lib/tables.inc.php'; require dirname(__DIR__) . '/lib/tables.inc.php';
$application = new Application('froxlor-cli', Froxlor::getFullVersion()); $application = new Application('froxlor-cli', Froxlor::getFullVersion());
$application->add(new RunApiCommand());
$application->add(new ConfigServices()); // files that are no commands
$application->add(new PhpSessionclean()); $fileIgnoreList = [
$application->add(new SwitchServerIp()); // Current non-command files
$application->add(new UpdateCommand()); 'CliCommand.php',
$application->add(new InstallCommand()); 'index.html',
$application->add(new MasterCron()); 'install.functions.php',
$application->add(new UserCommand()); ];
$application->add(new ValidateAcmeWebroot()); // directory of commands to include
$application->add(new ConfigDiff()); $cmd_files = glob(Froxlor::getInstallDir() . '/lib/Froxlor/Cli/*.php');
// include and add commands
foreach ($cmd_files as $cmdFile) {
// check ignore-list
if (!in_array(basename($cmdFile), $fileIgnoreList)) {
// include class-file
require $cmdFile;
// create class-name including namespace
$cmdClass = "\\Froxlor\\Cli\\" . substr(basename($cmdFile), 0, -4);
// check whether it exists
if (class_exists($cmdClass) && is_subclass_of($cmdClass, '\Symfony\Component\Console\Command\Command')) {
// add to cli application
$application->add(new $cmdClass());
}
}
}
$application->run(); $application->run();

144
composer.lock generated
View File

@@ -8,16 +8,16 @@
"packages": [ "packages": [
{ {
"name": "amnuts/opcache-gui", "name": "amnuts/opcache-gui",
"version": "3.5.2", "version": "3.5.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/amnuts/opcache-gui.git", "url": "https://github.com/amnuts/opcache-gui.git",
"reference": "db9df06889067f99d95bb9f226ec99e663aed196" "reference": "f3a8fe44c0a4c69dd69b9999d68f9097ee362946"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/amnuts/opcache-gui/zipball/db9df06889067f99d95bb9f226ec99e663aed196", "url": "https://api.github.com/repos/amnuts/opcache-gui/zipball/f3a8fe44c0a4c69dd69b9999d68f9097ee362946",
"reference": "db9df06889067f99d95bb9f226ec99e663aed196", "reference": "f3a8fe44c0a4c69dd69b9999d68f9097ee362946",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -58,7 +58,7 @@
"support": { "support": {
"email": "andy@amnuts.com", "email": "andy@amnuts.com",
"issues": "https://github.com/amnuts/opcache-gui/issues", "issues": "https://github.com/amnuts/opcache-gui/issues",
"source": "https://github.com/amnuts/opcache-gui/tree/3.5.2" "source": "https://github.com/amnuts/opcache-gui/tree/3.5.4"
}, },
"funding": [ "funding": [
{ {
@@ -66,7 +66,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-10-02T10:23:26+00:00" "time": "2023-10-25T19:09:56+00:00"
}, },
{ {
"name": "dflydev/dot-access-data", "name": "dflydev/dot-access-data",
@@ -674,16 +674,16 @@
}, },
{ {
"name": "phpmailer/phpmailer", "name": "phpmailer/phpmailer",
"version": "v6.8.1", "version": "v6.9.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git", "url": "https://github.com/PHPMailer/PHPMailer.git",
"reference": "e88da8d679acc3824ff231fdc553565b802ac016" "reference": "039de174cd9c17a8389754d3b877a2ed22743e18"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/e88da8d679acc3824ff231fdc553565b802ac016", "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/039de174cd9c17a8389754d3b877a2ed22743e18",
"reference": "e88da8d679acc3824ff231fdc553565b802ac016", "reference": "039de174cd9c17a8389754d3b877a2ed22743e18",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -703,6 +703,7 @@
"yoast/phpunit-polyfills": "^1.0.4" "yoast/phpunit-polyfills": "^1.0.4"
}, },
"suggest": { "suggest": {
"decomplexity/SendOauth2": "Adapter for using XOAUTH2 authentication",
"ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses", "ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses",
"ext-openssl": "Needed for secure SMTP sending and DKIM signing", "ext-openssl": "Needed for secure SMTP sending and DKIM signing",
"greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication", "greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication",
@@ -742,7 +743,7 @@
"description": "PHPMailer is a full-featured email creation and transfer class for PHP", "description": "PHPMailer is a full-featured email creation and transfer class for PHP",
"support": { "support": {
"issues": "https://github.com/PHPMailer/PHPMailer/issues", "issues": "https://github.com/PHPMailer/PHPMailer/issues",
"source": "https://github.com/PHPMailer/PHPMailer/tree/v6.8.1" "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.9.1"
}, },
"funding": [ "funding": [
{ {
@@ -750,7 +751,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-08-29T08:26:30+00:00" "time": "2023-11-25T22:23:28+00:00"
}, },
{ {
"name": "psr/container", "name": "psr/container",
@@ -972,16 +973,16 @@
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v5.4.28", "version": "v5.4.32",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/console.git", "url": "https://github.com/symfony/console.git",
"reference": "f4f71842f24c2023b91237c72a365306f3c58827" "reference": "c70df1ffaf23a8d340bded3cfab1b86752ad6ed7"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/f4f71842f24c2023b91237c72a365306f3c58827", "url": "https://api.github.com/repos/symfony/console/zipball/c70df1ffaf23a8d340bded3cfab1b86752ad6ed7",
"reference": "f4f71842f24c2023b91237c72a365306f3c58827", "reference": "c70df1ffaf23a8d340bded3cfab1b86752ad6ed7",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1051,7 +1052,7 @@
"terminal" "terminal"
], ],
"support": { "support": {
"source": "https://github.com/symfony/console/tree/v5.4.28" "source": "https://github.com/symfony/console/tree/v5.4.32"
}, },
"funding": [ "funding": [
{ {
@@ -1067,7 +1068,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-08-07T06:12:30+00:00" "time": "2023-11-18T18:23:04+00:00"
}, },
{ {
"name": "symfony/deprecation-contracts", "name": "symfony/deprecation-contracts",
@@ -1872,16 +1873,16 @@
}, },
{ {
"name": "symfony/string", "name": "symfony/string",
"version": "v5.4.29", "version": "v5.4.32",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/string.git", "url": "https://github.com/symfony/string.git",
"reference": "e41bdc93def20eaf3bfc1537c4e0a2b0680a152d" "reference": "91bf4453d65d8231688a04376c3a40efe0770f04"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/e41bdc93def20eaf3bfc1537c4e0a2b0680a152d", "url": "https://api.github.com/repos/symfony/string/zipball/91bf4453d65d8231688a04376c3a40efe0770f04",
"reference": "e41bdc93def20eaf3bfc1537c4e0a2b0680a152d", "reference": "91bf4453d65d8231688a04376c3a40efe0770f04",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1938,7 +1939,7 @@
"utf8" "utf8"
], ],
"support": { "support": {
"source": "https://github.com/symfony/string/tree/v5.4.29" "source": "https://github.com/symfony/string/tree/v5.4.32"
}, },
"funding": [ "funding": [
{ {
@@ -1954,30 +1955,31 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-09-13T11:47:41+00:00" "time": "2023-11-26T13:43:46+00:00"
}, },
{ {
"name": "twig/twig", "name": "twig/twig",
"version": "v3.7.1", "version": "v3.8.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/twigphp/Twig.git", "url": "https://github.com/twigphp/Twig.git",
"reference": "a0ce373a0ca3bf6c64b9e3e2124aca502ba39554" "reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/a0ce373a0ca3bf6c64b9e3e2124aca502ba39554", "url": "https://api.github.com/repos/twigphp/Twig/zipball/9d15f0ac07f44dc4217883ec6ae02fd555c6f71d",
"reference": "a0ce373a0ca3bf6c64b9e3e2124aca502ba39554", "reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=7.2.5", "php": ">=7.2.5",
"symfony/polyfill-ctype": "^1.8", "symfony/polyfill-ctype": "^1.8",
"symfony/polyfill-mbstring": "^1.3" "symfony/polyfill-mbstring": "^1.3",
"symfony/polyfill-php80": "^1.22"
}, },
"require-dev": { "require-dev": {
"psr/container": "^1.0|^2.0", "psr/container": "^1.0|^2.0",
"symfony/phpunit-bridge": "^5.4.9|^6.3" "symfony/phpunit-bridge": "^5.4.9|^6.3|^7.0"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@@ -2013,7 +2015,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/twigphp/Twig/issues", "issues": "https://github.com/twigphp/Twig/issues",
"source": "https://github.com/twigphp/Twig/tree/v3.7.1" "source": "https://github.com/twigphp/Twig/tree/v3.8.0"
}, },
"funding": [ "funding": [
{ {
@@ -2025,7 +2027,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-08-28T11:09:02+00:00" "time": "2023-11-21T18:54:41+00:00"
}, },
{ {
"name": "voku/anti-xss", "name": "voku/anti-xss",
@@ -2291,16 +2293,16 @@
"packages-dev": [ "packages-dev": [
{ {
"name": "composer/pcre", "name": "composer/pcre",
"version": "3.1.0", "version": "3.1.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/composer/pcre.git", "url": "https://github.com/composer/pcre.git",
"reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2" "reference": "00104306927c7a0919b4ced2aaa6782c1e61a3c9"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/composer/pcre/zipball/4bff79ddd77851fe3cdd11616ed3f92841ba5bd2", "url": "https://api.github.com/repos/composer/pcre/zipball/00104306927c7a0919b4ced2aaa6782c1e61a3c9",
"reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2", "reference": "00104306927c7a0919b4ced2aaa6782c1e61a3c9",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2342,7 +2344,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/composer/pcre/issues", "issues": "https://github.com/composer/pcre/issues",
"source": "https://github.com/composer/pcre/tree/3.1.0" "source": "https://github.com/composer/pcre/tree/3.1.1"
}, },
"funding": [ "funding": [
{ {
@@ -2358,7 +2360,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-11-17T09:50:14+00:00" "time": "2023-10-11T07:11:09+00:00"
}, },
{ {
"name": "composer/xdebug-handler", "name": "composer/xdebug-handler",
@@ -2613,23 +2615,24 @@
}, },
{ {
"name": "pdepend/pdepend", "name": "pdepend/pdepend",
"version": "2.15.1", "version": "2.16.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/pdepend/pdepend.git", "url": "https://github.com/pdepend/pdepend.git",
"reference": "d12f25bcdfb7754bea458a4a5cb159d55e9950d0" "reference": "8dfc0c46529e2073fa97986552f80646eedac562"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/pdepend/pdepend/zipball/d12f25bcdfb7754bea458a4a5cb159d55e9950d0", "url": "https://api.github.com/repos/pdepend/pdepend/zipball/8dfc0c46529e2073fa97986552f80646eedac562",
"reference": "d12f25bcdfb7754bea458a4a5cb159d55e9950d0", "reference": "8dfc0c46529e2073fa97986552f80646eedac562",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.7", "php": ">=5.3.7",
"symfony/config": "^2.3.0|^3|^4|^5|^6.0", "symfony/config": "^2.3.0|^3|^4|^5|^6.0|^7.0",
"symfony/dependency-injection": "^2.3.0|^3|^4|^5|^6.0", "symfony/dependency-injection": "^2.3.0|^3|^4|^5|^6.0|^7.0",
"symfony/filesystem": "^2.3.0|^3|^4|^5|^6.0" "symfony/filesystem": "^2.3.0|^3|^4|^5|^6.0|^7.0",
"symfony/polyfill-mbstring": "^1.19"
}, },
"require-dev": { "require-dev": {
"easy-doc/easy-doc": "0.0.0|^1.2.3", "easy-doc/easy-doc": "0.0.0|^1.2.3",
@@ -2664,7 +2667,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/pdepend/pdepend/issues", "issues": "https://github.com/pdepend/pdepend/issues",
"source": "https://github.com/pdepend/pdepend/tree/2.15.1" "source": "https://github.com/pdepend/pdepend/tree/2.16.0"
}, },
"funding": [ "funding": [
{ {
@@ -2672,7 +2675,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-09-28T12:00:56+00:00" "time": "2023-11-29T08:52:35+00:00"
}, },
{ {
"name": "phar-io/manifest", "name": "phar-io/manifest",
@@ -2906,7 +2909,6 @@
"type": "github" "type": "github"
} }
], ],
"abandoned": true,
"time": "2020-12-07T05:51:20+00:00" "time": "2020-12-07T05:51:20+00:00"
}, },
{ {
@@ -2995,16 +2997,16 @@
}, },
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
"version": "1.10.38", "version": "1.10.46",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan.git", "url": "https://github.com/phpstan/phpstan.git",
"reference": "5302bb402c57f00fb3c2c015bac86e0827e4b691" "reference": "90d3d25c5b98b8068916bbf08ce42d5cb6c54e70"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/5302bb402c57f00fb3c2c015bac86e0827e4b691", "url": "https://api.github.com/repos/phpstan/phpstan/zipball/90d3d25c5b98b8068916bbf08ce42d5cb6c54e70",
"reference": "5302bb402c57f00fb3c2c015bac86e0827e4b691", "reference": "90d3d25c5b98b8068916bbf08ce42d5cb6c54e70",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -3053,7 +3055,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-10-06T14:19:14+00:00" "time": "2023-11-28T14:57:26+00:00"
}, },
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",
@@ -4562,16 +4564,16 @@
}, },
{ {
"name": "symfony/config", "name": "symfony/config",
"version": "v5.4.26", "version": "v5.4.31",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/config.git", "url": "https://github.com/symfony/config.git",
"reference": "8109892f27beed9252bd1f1c1880aeb4ad842650" "reference": "dd5ea39de228813aba0c23c3a4153da2a4cf3cd9"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/config/zipball/8109892f27beed9252bd1f1c1880aeb4ad842650", "url": "https://api.github.com/repos/symfony/config/zipball/dd5ea39de228813aba0c23c3a4153da2a4cf3cd9",
"reference": "8109892f27beed9252bd1f1c1880aeb4ad842650", "reference": "dd5ea39de228813aba0c23c3a4153da2a4cf3cd9",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -4621,7 +4623,7 @@
"description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "description": "Helps you find, load, combine, autofill and validate configuration values of any kind",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/config/tree/v5.4.26" "source": "https://github.com/symfony/config/tree/v5.4.31"
}, },
"funding": [ "funding": [
{ {
@@ -4637,20 +4639,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-07-19T20:21:11+00:00" "time": "2023-11-09T08:22:43+00:00"
}, },
{ {
"name": "symfony/dependency-injection", "name": "symfony/dependency-injection",
"version": "v5.4.29", "version": "v5.4.32",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/dependency-injection.git", "url": "https://github.com/symfony/dependency-injection.git",
"reference": "338638ed8c9d5c7fcb136a73f5c7043465ae2f05" "reference": "d5d48f215ed73f7973d01256b9a2fac729bef759"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/338638ed8c9d5c7fcb136a73f5c7043465ae2f05", "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/d5d48f215ed73f7973d01256b9a2fac729bef759",
"reference": "338638ed8c9d5c7fcb136a73f5c7043465ae2f05", "reference": "d5d48f215ed73f7973d01256b9a2fac729bef759",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -4710,7 +4712,7 @@
"description": "Allows you to standardize and centralize the way objects are constructed in your application", "description": "Allows you to standardize and centralize the way objects are constructed in your application",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/dependency-injection/tree/v5.4.29" "source": "https://github.com/symfony/dependency-injection/tree/v5.4.32"
}, },
"funding": [ "funding": [
{ {
@@ -4726,7 +4728,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-09-20T06:23:43+00:00" "time": "2023-11-29T06:58:28+00:00"
}, },
{ {
"name": "symfony/filesystem", "name": "symfony/filesystem",
@@ -4873,16 +4875,16 @@
}, },
{ {
"name": "theseer/tokenizer", "name": "theseer/tokenizer",
"version": "1.2.1", "version": "1.2.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/theseer/tokenizer.git", "url": "https://github.com/theseer/tokenizer.git",
"reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
"reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -4911,7 +4913,7 @@
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
"support": { "support": {
"issues": "https://github.com/theseer/tokenizer/issues", "issues": "https://github.com/theseer/tokenizer/issues",
"source": "https://github.com/theseer/tokenizer/tree/1.2.1" "source": "https://github.com/theseer/tokenizer/tree/1.2.2"
}, },
"funding": [ "funding": [
{ {
@@ -4919,7 +4921,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2021-07-28T10:34:58+00:00" "time": "2023-11-20T00:12:19+00:00"
} }
], ],
"aliases": [], "aliases": [],

View File

@@ -72,7 +72,7 @@ if ($page == 'overview' || $page == 'domains') {
} }
$actions_links[] = [ $actions_links[] = [
'href' => 'https://docs.froxlor.org/v2/user-guide/domains/', 'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/domains/',
'target' => '_blank', 'target' => '_blank',
'icon' => 'fa-solid fa-circle-info', 'icon' => 'fa-solid fa-circle-info',
'class' => 'btn-outline-secondary' 'class' => 'btn-outline-secondary'

View File

@@ -76,7 +76,7 @@ if ($page == 'overview' || $page == 'emails') {
} }
$actions_links[] = [ $actions_links[] = [
'href' => 'https://docs.froxlor.org/v2/user-guide/emails/', 'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/emails/',
'target' => '_blank', 'target' => '_blank',
'icon' => 'fa-solid fa-circle-info', 'icon' => 'fa-solid fa-circle-info',
'class' => 'btn-outline-secondary' 'class' => 'btn-outline-secondary'
@@ -138,7 +138,7 @@ if ($page == 'email_domain') {
]; ];
} }
$actions_links[] = [ $actions_links[] = [
'href' => 'https://docs.froxlor.org/v2/user-guide/emails/', 'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/emails/',
'target' => '_blank', 'target' => '_blank',
'icon' => 'fa-solid fa-circle-info', 'icon' => 'fa-solid fa-circle-info',
'class' => 'btn-outline-secondary' 'class' => 'btn-outline-secondary'

View File

@@ -75,7 +75,7 @@ if ($page == 'overview' || $page == 'htpasswds') {
]; ];
$actions_links[] = [ $actions_links[] = [
'href' => 'https://docs.froxlor.org/v2/user-guide/extras/', 'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/extras/',
'target' => '_blank', 'target' => '_blank',
'icon' => 'fa-solid fa-circle-info', 'icon' => 'fa-solid fa-circle-info',
'class' => 'btn-outline-secondary' 'class' => 'btn-outline-secondary'
@@ -200,7 +200,7 @@ if ($page == 'overview' || $page == 'htpasswds') {
]; ];
$actions_links[] = [ $actions_links[] = [
'href' => 'https://docs.froxlor.org/v2/user-guide/extras/', 'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/extras/',
'target' => '_blank', 'target' => '_blank',
'icon' => 'fa-solid fa-circle-info', 'icon' => 'fa-solid fa-circle-info',
'class' => 'btn-outline-secondary' 'class' => 'btn-outline-secondary'
@@ -349,7 +349,7 @@ if ($page == 'overview' || $page == 'htpasswds') {
$actions_links = [ $actions_links = [
[ [
'href' => 'https://docs.froxlor.org/v2/user-guide/extras/', 'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/extras/',
'target' => '_blank', 'target' => '_blank',
'icon' => 'fa-solid fa-circle-info', 'icon' => 'fa-solid fa-circle-info',
'class' => 'btn-outline-secondary' 'class' => 'btn-outline-secondary'

View File

@@ -65,7 +65,7 @@ if ($page == 'overview' || $page == 'accounts') {
]; ];
} }
$actions_links[] = [ $actions_links[] = [
'href' => 'https://docs.froxlor.org/v2/user-guide/ftp-accounts/', 'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/ftp-accounts/',
'target' => '_blank', 'target' => '_blank',
'icon' => 'fa-solid fa-circle-info', 'icon' => 'fa-solid fa-circle-info',
'class' => 'btn-outline-secondary' 'class' => 'btn-outline-secondary'

View File

@@ -75,7 +75,7 @@ if ($page == 'overview' || $page == 'mysqls') {
} }
$actions_links[] = [ $actions_links[] = [
'href' => 'https://docs.froxlor.org/v2/user-guide/databases/', 'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/databases/',
'target' => '_blank', 'target' => '_blank',
'icon' => 'fa-solid fa-circle-info', 'icon' => 'fa-solid fa-circle-info',
'class' => 'btn-outline-secondary' 'class' => 'btn-outline-secondary'

View File

@@ -562,7 +562,6 @@ opcache.validate_timestamps'),
('system', 'mod_fcgid_wrapper', '1'), ('system', 'mod_fcgid_wrapper', '1'),
('system', 'mod_fcgid_starter', '0'), ('system', 'mod_fcgid_starter', '0'),
('system', 'mod_fcgid_peardir', '/usr/share/php/:/usr/share/php5/'), ('system', 'mod_fcgid_peardir', '/usr/share/php/:/usr/share/php5/'),
('system', 'index_file_extension', 'html'),
('system', 'mod_fcgid_maxrequests', '250'), ('system', 'mod_fcgid_maxrequests', '250'),
('system', 'ssl_key_file','/etc/ssl/froxlor_selfsigned.key'), ('system', 'ssl_key_file','/etc/ssl/froxlor_selfsigned.key'),
('system', 'ssl_ca_file', ''), ('system', 'ssl_ca_file', ''),
@@ -679,7 +678,7 @@ opcache.validate_timestamps'),
('system', 'distribution', ''), ('system', 'distribution', ''),
('system', 'update_channel', 'stable'), ('system', 'update_channel', 'stable'),
('system', 'updatecheck_data', ''), ('system', 'updatecheck_data', ''),
('system', 'update_notify_last', '2.1.0-rc2'), ('system', 'update_notify_last', '2.1.1'),
('system', 'traffictool', 'goaccess'), ('system', 'traffictool', 'goaccess'),
('system', 'req_limit_per_interval', 60), ('system', 'req_limit_per_interval', 60),
('system', 'req_limit_interval', 60), ('system', 'req_limit_interval', 60),
@@ -727,8 +726,8 @@ opcache.validate_timestamps'),
('panel', 'logo_overridecustom', '0'), ('panel', 'logo_overridecustom', '0'),
('panel', 'settings_mode', '0'), ('panel', 'settings_mode', '0'),
('panel', 'menu_collapsed', '1'), ('panel', 'menu_collapsed', '1'),
('panel', 'version', '2.1.0-rc2'), ('panel', 'version', '2.1.1'),
('panel', 'db_version', '202305240'); ('panel', 'db_version', '202312050');
DROP TABLE IF EXISTS `panel_tasks`; DROP TABLE IF EXISTS `panel_tasks`;
@@ -751,6 +750,7 @@ CREATE TABLE `panel_templates` (
`templategroup` varchar(255) NOT NULL default '', `templategroup` varchar(255) NOT NULL default '',
`varname` varchar(255) NOT NULL default '', `varname` varchar(255) NOT NULL default '',
`value` longtext NOT NULL, `value` longtext NOT NULL,
`file_extension` varchar(50) NOT NULL default 'html',
PRIMARY KEY (id), PRIMARY KEY (id),
KEY adminid (adminid) KEY adminid (adminid)
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci; ) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;

View File

@@ -67,15 +67,18 @@ if (Froxlor::isFroxlorVersion('2.0.24')) {
} }
Update::showUpdateStep("Adjusting cronjobs"); Update::showUpdateStep("Adjusting cronjobs");
Database::query(" $cfupd_stmt = Database::prepare("
UPDATE `" . TABLE_PANEL_CRONRUNS . "` SET UPDATE `" . TABLE_PANEL_CRONRUNS . "` SET
`module`= 'froxlor/export', `module`= 'froxlor/export',
`cronfile` = 'export', `cronfile` = 'export',
`cronclass` = '\\Froxlor\\Cron\\System\\ExportCron', `cronclass` = :cc,
`interval` = '1 HOUR', `interval` = '1 HOUR',
`desc_lng_key` = 'cron_export' `desc_lng_key` = 'cron_export'
WHERE `module` = 'froxlor/backup' WHERE `module` = 'froxlor/backup'
"); ");
Database::pexecute($cfupd_stmt, [
'cc' => '\\Froxlor\\Cron\\System\\ExportCron'
]);
Update::lastStepStatus(0); Update::lastStepStatus(0);
Update::showUpdateStep("Adjusting system for data-export function"); Update::showUpdateStep("Adjusting system for data-export function");
@@ -123,3 +126,90 @@ if (Froxlor::isFroxlorVersion('2.1.0-rc1')) {
Froxlor::updateToVersion('2.1.0-rc2'); Froxlor::updateToVersion('2.1.0-rc2');
} }
if (Froxlor::isDatabaseVersion('202305240')) {
Update::showUpdateStep("Adjusting file-template file extension setttings");
$current_fileextension = Settings::Get('system.index_file_extension');
Database::query("DELETE FROM `" . TABLE_PANEL_SETTINGS . "` WHERE `settinggroup`= 'system' AND `varname`= 'index_file_extension'");
Database::query("ALTER TABLE `" . TABLE_PANEL_TEMPLATES . "` ADD `file_extension` varchar(50) NOT NULL default 'html';");
if (!empty(trim($current_fileextension)) && strtolower(trim($current_fileextension)) != 'html') {
$stmt = Database::prepare("UPDATE `" . TABLE_PANEL_TEMPLATES . "` SET `file_extension` = :ext WHERE `templategroup` = 'files'");
Database::pexecute($stmt, ['ext' => strtolower(trim($current_fileextension))]);
}
Update::lastStepStatus(0);
Froxlor::updateToDbVersion('202311260');
}
if (Froxlor::isFroxlorVersion('2.1.0-rc2')) {
Update::showUpdateStep("Updating from 2.1.0-rc2 to 2.1.0-rc3", false);
Froxlor::updateToVersion('2.1.0-rc3');
}
if (Froxlor::isDatabaseVersion('202311260')) {
Update::showUpdateStep("Cleaning up old files");
$to_clean = array(
"install/updates/froxlor/update_2.x.inc.php",
"install/updates/preconfig/preconfig_2.x.inc.php",
"lib/Froxlor/Api/Commands/CustomerBackups.php",
"lib/Froxlor/Cli/Action",
"lib/Froxlor/Cli/Action.php",
"lib/Froxlor/Cli/CmdLineHandler.php",
"lib/Froxlor/Cli/ConfigServicesCmd.php",
"lib/Froxlor/Cli/PhpSessioncleanCmd.php",
"lib/Froxlor/Cli/SwitchServerIpCmd.php",
"lib/Froxlor/Cli/UpdateCliCmd.php",
"lib/Froxlor/Cron/System/BackupCron.php",
"lib/formfields/customer/extras/formfield.backup.php",
"lib/tablelisting/customer/tablelisting.backups.php",
"templates/Froxlor/assets/mix-manifest.json",
"templates/Froxlor/assets/css",
"templates/Froxlor/assets/webfonts",
"templates/Froxlor/assets/js/main.js",
"templates/Froxlor/assets/js/main.js.LICENSE.txt",
"templates/Froxlor/src",
"templates/Froxlor/user/change_language.html.twig",
"templates/Froxlor/user/change_password.html.twig",
"templates/Froxlor/user/change_theme.html.twig",
"tests/Backup/CustomerBackupsTest.php"
);
$disabled = explode(',', ini_get('disable_functions'));
$exec_allowed = !in_array('exec', $disabled);
$del_list = "";
foreach ($to_clean as $filedir) {
$complete_filedir = Froxlor::getInstallDir() . $filedir;
if (file_exists($complete_filedir)) {
if ($exec_allowed) {
FileDir::safe_exec("rm -rf " . escapeshellarg($complete_filedir));
} else {
$del_list .= "rm -rf " . escapeshellarg($complete_filedir) . PHP_EOL;
}
}
}
if ($exec_allowed) {
Update::lastStepStatus(0);
} else {
if (empty($del_list)) {
// none of the files existed
Update::lastStepStatus(0);
} else {
Update::lastStepStatus(
1,
'manual commands needed',
'Please run the following commands manually:<br><pre>' . $del_list . '</pre>'
);
}
}
Froxlor::updateToDbVersion('202312050');
}
if (Froxlor::isFroxlorVersion('2.1.0-rc3')) {
Update::showUpdateStep("Updating from 2.1.0-rc3 to 2.1.0 stable", false);
Froxlor::updateToVersion('2.1.0');
}
if (Froxlor::isFroxlorVersion('2.1.0')) {
Update::showUpdateStep("Updating from 2.1.0 to 2.1.1", false);
Froxlor::updateToVersion('2.1.1');
}

View File

@@ -1652,6 +1652,7 @@ class Domains extends ApiCommand implements ResourceEntity
|| $iswildcarddomain != $result['iswildcarddomain'] || $iswildcarddomain != $result['iswildcarddomain']
|| $phpenabled != $result['phpenabled'] || $phpenabled != $result['phpenabled']
|| $openbasedir != $result['openbasedir'] || $openbasedir != $result['openbasedir']
|| $openbasedir_path != $result['openbasedir_path']
|| $phpsettingid != $result['phpsettingid'] || $phpsettingid != $result['phpsettingid']
|| $mod_fcgid_starter != $result['mod_fcgid_starter'] || $mod_fcgid_starter != $result['mod_fcgid_starter']
|| $mod_fcgid_maxrequests != $result['mod_fcgid_maxrequests'] || $mod_fcgid_maxrequests != $result['mod_fcgid_maxrequests']

View File

@@ -82,7 +82,7 @@ class Froxlor extends ApiCommand
if ($aucheck == 1) { if ($aucheck == 1) {
// anzeige über version-status mit ggfls. formular // anzeige über version-status mit ggfls. formular
// zum update schritt #1 -> download // zum update schritt #1 -> download
$text = lng('update.uc_newinfo', [(Settings::Get('system.update_channel') == 'testing' ? 'testing ' : ''), AutoUpdate::getFromResult('version'), $this->version]); $text = lng('update.uc_newinfo', [(Settings::Get('system.update_channel') != 'stable' ? Settings::Get('system.update_channel').' ' : ''), AutoUpdate::getFromResult('version'), $this->version]);
$response = [ $response = [
'isnewerversion' => (int) !AutoUpdate::getFromResult('has_latest'), 'isnewerversion' => (int) !AutoUpdate::getFromResult('has_latest'),
'version' => $this->version, 'version' => $this->version,
@@ -91,7 +91,7 @@ class Froxlor extends ApiCommand
'additional_info' => AutoUpdate::getFromResult('info'), 'additional_info' => AutoUpdate::getFromResult('info'),
'aucheck' => $aucheck 'aucheck' => $aucheck
]; ];
} else if ($aucheck < 0 || $aucheck > 1) { } elseif ($aucheck < 0 || $aucheck > 1) {
// errors // errors
if ($aucheck < 0) { if ($aucheck < 0) {
$errmsg = AutoUpdate::getLastError(); $errmsg = AutoUpdate::getLastError();

View File

@@ -100,7 +100,7 @@ final class UpdateCommand extends CliCommand
} }
// there is a new version // there is a new version
if ($input->getOption('check-only')) { if ($input->getOption('check-only')) {
$text = lng('update.uc_newinfo', [(Settings::Get('system.update_channel') == 'testing' ? 'testing ' : ''), AutoUpdate::getFromResult('version'), Froxlor::VERSION]); $text = lng('update.uc_newinfo', [(Settings::Get('system.update_channel') != 'stable' ? Settings::Get('system.update_channel').' ' : ''), AutoUpdate::getFromResult('version'), Froxlor::VERSION]);
} else { } else {
$text = lng('admin.newerversionavailable') . ' ' . lng('admin.newerversiondetails', [AutoUpdate::getFromResult('version'), Froxlor::VERSION]); $text = lng('admin.newerversionavailable') . ' ' . lng('admin.newerversiondetails', [AutoUpdate::getFromResult('version'), Froxlor::VERSION]);
} }
@@ -175,7 +175,7 @@ final class UpdateCommand extends CliCommand
$result = self::SUCCESS; $result = self::SUCCESS;
$question = new ConfirmationQuestion('Update database? [no] ', false, '/^(y|j)/i'); $question = new ConfirmationQuestion('Update database? [no] ', false, '/^(y|j)/i');
if ($yestoall || $helper->ask($input, $output, $question)) { if ($yestoall || $helper->ask($input, $output, $question)) {
$result = $this->updateDatabase(); $result = $this->runUpdate($output, true);
} }
} else { } else {
$errmsg = 'error.autoupdate_' . $auex; $errmsg = 'error.autoupdate_' . $auex;
@@ -199,7 +199,7 @@ final class UpdateCommand extends CliCommand
if ($input->getOption('mail-notify')) { if ($input->getOption('mail-notify')) {
$last_check_version = Settings::Get('system.update_notify_last'); $last_check_version = Settings::Get('system.update_notify_last');
if (Update::versionInUpdate($last_check_version, AutoUpdate::getFromResult('version'))) { if (Update::versionInUpdate($last_check_version, AutoUpdate::getFromResult('version'))) {
$text = lng('update.uc_newinfo', [(Settings::Get('system.update_channel') == 'testing' ? 'testing ' : ''), AutoUpdate::getFromResult('version'), Froxlor::VERSION]); $text = lng('update.uc_newinfo', [(Settings::Get('system.update_channel') != 'stable' ? Settings::Get('system.update_channel').' ' : ''), AutoUpdate::getFromResult('version'), Froxlor::VERSION]);
$mail = new Mailer(true); $mail = new Mailer(true);
$mail->Body = $text; $mail->Body = $text;
$mail->Subject = "[froxlor] " . lng('update.notify_subject'); $mail->Subject = "[froxlor] " . lng('update.notify_subject');

View File

@@ -26,6 +26,7 @@
namespace Froxlor\Cron\Http\LetsEncrypt; namespace Froxlor\Cron\Http\LetsEncrypt;
use Froxlor\Cron\FroxlorCron; use Froxlor\Cron\FroxlorCron;
use Froxlor\Cron\TaskId;
use Froxlor\Database\Database; use Froxlor\Database\Database;
use Froxlor\Domain\Domain; use Froxlor\Domain\Domain;
use Froxlor\FileDir; use Froxlor\FileDir;
@@ -83,7 +84,7 @@ class AcmeSh extends FroxlorCron
$renew_domains = self::renewDomains(true); $renew_domains = self::renewDomains(true);
if ($issue_froxlor || !empty($issue_domains) || !empty($renew_froxlor) || $renew_domains) { if ($issue_froxlor || !empty($issue_domains) || !empty($renew_froxlor) || $renew_domains) {
// insert task to generate certificates and vhost-configs // insert task to generate certificates and vhost-configs
Cronjob::inserttask(1); Cronjob::inserttask(TaskId::REBUILD_VHOST);
} }
return 0; return 0;
} }
@@ -203,7 +204,7 @@ class AcmeSh extends FroxlorCron
// This is easiest done by just creating a new task ;) // This is easiest done by just creating a new task ;)
if ($changedetected) { if ($changedetected) {
if (self::$no_inserttask == false) { if (self::$no_inserttask == false) {
Cronjob::inserttask(1); Cronjob::inserttask(TaskId::REBUILD_VHOST);
} }
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Let's Encrypt certificates have been updated"); FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Let's Encrypt certificates have been updated");
} else { } else {

View File

@@ -256,7 +256,7 @@ class Domain
]); ]);
$result = []; $result = [];
while ($entry = $result_stmt->fetch(PDO::FETCH_ASSOC)) { while ($entry = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
$result = $entry['id']; $result[] = $entry['id'];
} }
return $result; return $result;
} }

View File

@@ -257,6 +257,41 @@ class FileDir
return $return; return $return;
} }
/**
* Read unconfigured-domain template from database if exists or fallback to default
*
* @param string $servername
*
* @return string
* @throws Exception
*/
public static function getUnknownDomainTemplate(string $servername = "")
{
$result_stmt = Database::prepare("
SELECT * FROM `" . TABLE_PANEL_TEMPLATES . "` WHERE `templategroup` = 'files' AND `varname` = 'unconfigured_html'
");
Database::pexecute($result_stmt);
if (Database::num_rows() > 0) {
$template = $result_stmt->fetch(PDO::FETCH_ASSOC);
$replace_arr = [
'SERVERNAME' => $servername,
];
$tpl_content = PhpHelper::replaceVariables($template['value'], $replace_arr);
$tpl_ext = $template['file_extension'];
} else {
$tpl_ext = 'html';
$unconfiguredPath = FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/templates/misc/unconfigured/index.html');
if (file_exists($unconfiguredPath)) {
$tpl_content = file_get_contents($unconfiguredPath);
} else {
$tpl_content = lng('admin.templates.unconfigured_content_fallback');
}
}
$redirect_file = FileDir::makeCorrectFile(Froxlor::getInstallDir().'/notice.'.$tpl_ext);
file_put_contents($redirect_file, $tpl_content);
return basename($redirect_file);
}
/** /**
* store the default index-file in a given destination folder * store the default index-file in a given destination folder
* *
@@ -277,7 +312,7 @@ class FileDir
{ {
if ($force || (int)Settings::Get('system.store_index_file_subs') == 1) { if ($force || (int)Settings::Get('system.store_index_file_subs') == 1) {
$result_stmt = Database::prepare(" $result_stmt = Database::prepare("
SELECT `t`.`value`, `c`.`email` AS `customer_email`, `a`.`email` AS `admin_email`, `c`.`loginname` AS `customer_login`, `a`.`loginname` AS `admin_login` SELECT `t`.`value`, `t`.`file_extension`, `c`.`email` AS `customer_email`, `a`.`email` AS `admin_email`, `c`.`loginname` AS `customer_login`, `a`.`loginname` AS `admin_login`
FROM `" . TABLE_PANEL_CUSTOMERS . "` AS `c` INNER JOIN `" . TABLE_PANEL_ADMINS . "` AS `a` FROM `" . TABLE_PANEL_CUSTOMERS . "` AS `c` INNER JOIN `" . TABLE_PANEL_ADMINS . "` AS `a`
ON `c`.`adminid` = `a`.`adminid` ON `c`.`adminid` = `a`.`adminid`
INNER JOIN `" . TABLE_PANEL_TEMPLATES . "` AS `t` INNER JOIN `" . TABLE_PANEL_TEMPLATES . "` AS `t`
@@ -300,7 +335,7 @@ class FileDir
// replaceVariables // replaceVariables
$htmlcontent = PhpHelper::replaceVariables($template['value'], $replace_arr); $htmlcontent = PhpHelper::replaceVariables($template['value'], $replace_arr);
$indexhtmlpath = self::makeCorrectFile($destination . '/index.' . Settings::Get('system.index_file_extension')); $indexhtmlpath = self::makeCorrectFile($destination . '/index.' . $template['file_extension']);
$index_html_handler = fopen($indexhtmlpath, 'w'); $index_html_handler = fopen($indexhtmlpath, 'w');
fwrite($index_html_handler, $htmlcontent); fwrite($index_html_handler, $htmlcontent);
fclose($index_html_handler); fclose($index_html_handler);
@@ -308,7 +343,7 @@ class FileDir
$logger->logAction( $logger->logAction(
FroxlorLogger::CRON_ACTION, FroxlorLogger::CRON_ACTION,
LOG_NOTICE, LOG_NOTICE,
'Creating \'index.' . Settings::Get('system.index_file_extension') . '\' for Customer \'' . $template['customer_login'] . '\' based on template in directory ' . escapeshellarg($indexhtmlpath) 'Creating \'index.' . $template['file_extension'] . '\' for Customer \'' . $template['customer_login'] . '\' based on template in directory ' . escapeshellarg($indexhtmlpath)
); );
} }
} else { } else {

View File

@@ -31,14 +31,16 @@ final class Froxlor
{ {
// Main version variable // Main version variable
const VERSION = '2.1.0-rc2'; const VERSION = '2.1.1';
// Database version (YYYYMMDDC where C is a daily counter) // Database version (YYYYMMDDC where C is a daily counter)
const DBVERSION = '202305240'; const DBVERSION = '202312050';
// Distribution branding-tag (used for Debian etc.) // Distribution branding-tag (used for Debian etc.)
const BRANDING = ''; const BRANDING = '';
const DOCS_URL = 'https://docs.froxlor.org/v2.1/';
/** /**
* return path to where froxlor is installed, e.g. * return path to where froxlor is installed, e.g.
* /var/www/froxlor/ * /var/www/froxlor/

View File

@@ -104,17 +104,15 @@ class FroxlorLogger
self::$ml->pushHandler(new SyslogHandler('froxlor', LOG_USER, Logger::DEBUG)); self::$ml->pushHandler(new SyslogHandler('froxlor', LOG_USER, Logger::DEBUG));
break; break;
case 'file': case 'file':
$setings_logfile = Settings::Get('logger.logfile');
if (empty($setings_logfile)) {
Settings::Set('logger.logfile', 'froxlor.log');
}
$logger_logfile = FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/logs/' . Settings::Get('logger.logfile')); $logger_logfile = FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/logs/' . Settings::Get('logger.logfile'));
// is_writable needs an existing file to check if it's actually writable // is_writable needs an existing file to check if it's actually writable
@touch($logger_logfile); if (!@touch($logger_logfile) || !is_writable($logger_logfile)) {
if (empty($logger_logfile) || !is_writable($logger_logfile)) { // not writable in our own directory? Skip
Settings::Set('logger.logfile', 'froxlor.log'); break;
$logger_logfile = FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/logs/froxlor.log');
@touch($logger_logfile);
if (empty($logger_logfile) || !is_writable($logger_logfile)) {
// not writable in our own directory? Skip
break;
}
} }
self::$ml->pushHandler(new StreamHandler($logger_logfile, Logger::DEBUG)); self::$ml->pushHandler(new StreamHandler($logger_logfile, Logger::DEBUG));
break; break;

View File

@@ -51,13 +51,13 @@ class AutoUpdate
/** /**
* returns status about whether there is a newer version * returns status about whether there is a newer version
* *
* 0 = no new version available * 0 = no new version available
* 1 = new version available * 1 = new version available
* -1 = remote error message * -1 = remote error message
* >1 = local error message * >1 = local error message
* *
* @return int * @return int
*/ */
public static function checkVersion(): int public static function checkVersion(): int
{ {
@@ -68,6 +68,12 @@ class AutoUpdate
$channel = ''; $channel = '';
if (Settings::Get('system.update_channel') == 'testing') { if (Settings::Get('system.update_channel') == 'testing') {
$channel = '/testing'; $channel = '/testing';
} elseif (Settings::Get('system.update_channel') == 'nightly') {
if (empty(Froxlor::BRANDING)) {
$channel = '/nightly.0000000';
} else {
$channel = '/' . substr(Froxlor::BRANDING, 1);
}
} }
$latestversion = HttpClient::urlGet(self::UPDATE_URI . Froxlor::VERSION . $channel, true, 3); $latestversion = HttpClient::urlGet(self::UPDATE_URI . Froxlor::VERSION . $channel, true, 3);
} catch (Exception $e) { } catch (Exception $e) {
@@ -81,7 +87,7 @@ class AutoUpdate
if (!empty(self::$latestversion['error']) && self::$latestversion['error']) { if (!empty(self::$latestversion['error']) && self::$latestversion['error']) {
$result = -1; $result = -1;
self::$lasterror = self::$latestversion['message']; self::$lasterror = self::$latestversion['message'];
} else if (isset(self::$latestversion['has_latest']) && self::$latestversion['has_latest'] == false) { } elseif (isset(self::$latestversion['has_latest']) && self::$latestversion['has_latest'] == false) {
$result = 1; $result = 1;
} }
} }

View File

@@ -26,13 +26,14 @@
namespace Froxlor\Install; namespace Froxlor\Install;
use Exception; use Exception;
use PDO; use Froxlor\Config\ConfigParser;
use Froxlor\Froxlor;
use Froxlor\Install\Install\Core; use Froxlor\Install\Install\Core;
use Froxlor\System\IPTools;
use Froxlor\UI\Panel\UI; use Froxlor\UI\Panel\UI;
use Froxlor\UI\Request; use Froxlor\UI\Request;
use Froxlor\Config\ConfigParser;
use Froxlor\Validate\Validate; use Froxlor\Validate\Validate;
use Froxlor\System\IPTools; use PDO;
class Install class Install
{ {
@@ -41,34 +42,37 @@ class Install
public $maxSteps; public $maxSteps;
public $phpVersion; public $phpVersion;
public $formfield; public $formfield;
public string $requiredVersion = '7.4.0';
public array $requiredExtensions = ['session', 'ctype', 'xml', 'filter', 'posix', 'mbstring', 'curl', 'gmp', 'json', 'gd'];
public array $suggestedExtensions = ['bcmath', 'zip', 'gnupg'];
public array $suggestions = []; public array $suggestions = [];
public array $criticals = []; public array $criticals = [];
public array $loadedExtensions; public array $loadedExtensions;
public array $supportedOS = []; public array $supportedOS = [];
public array $webserverBackend = [ public array $webserverBackend = [
'php-fpm' => 'PHP-FPM', 'php-fpm' => 'PHP-FPM',
'fcgid' => 'FCGID', 'fcgid' => 'FCGID (apache2 only)',
'mod_php' => 'mod_php (not recommended)', 'mod_php' => 'mod_php (not recommended)',
]; ];
public function __construct(array $cliData = []) public function __construct(array $cliData = [])
{ {
// set actual php version and extensions
$this->phpVersion = phpversion();
$this->loadedExtensions = get_loaded_extensions();
// get all supported OS // get all supported OS
// show list of available distro's // show list of available distro's
$distros = glob(dirname(__DIR__, 3) . '/lib/configfiles/*.xml'); $distros = glob(dirname(__DIR__, 3) . '/lib/configfiles/*.xml');
$distributions_select[''] = '-'; $distributions_select[''] = '-';
// read in all the distros if (in_array('xml', $this->loadedExtensions)) {
foreach ($distros as $distribution) { // read in all the distros
// get configparser object foreach ($distros as $distribution) {
$dist = new ConfigParser($distribution); // get configparser object
// store in tmp array $dist = new ConfigParser($distribution);
$this->supportedOS[str_replace(".xml", "", strtolower(basename($distribution)))] = $dist->getCompleteDistroName(); // store in tmp array
$this->supportedOS[str_replace(".xml", "", strtolower(basename($distribution)))] = $dist->getCompleteDistroName();
}
// sort by distribution name
asort($this->supportedOS);
} }
// sort by distribution name
asort($this->supportedOS);
// guess distribution and webserver to preselect in formfield // guess distribution and webserver to preselect in formfield
$webserverBackend = $this->webserverBackend; $webserverBackend = $this->webserverBackend;
@@ -84,10 +88,6 @@ class Install
$this->extendedView = $cliData['extended'] ?? Request::any('extended', 0); $this->extendedView = $cliData['extended'] ?? Request::any('extended', 0);
$this->maxSteps = count($this->formfield['install']['sections']); $this->maxSteps = count($this->formfield['install']['sections']);
// set actual php version and extensions
$this->phpVersion = phpversion();
$this->loadedExtensions = get_loaded_extensions();
if (empty($cliData)) { if (empty($cliData)) {
// set global variables // set global variables
UI::twig()->addGlobal('install_mode', true); UI::twig()->addGlobal('install_mode', true);
@@ -99,7 +99,7 @@ class Install
} }
// check for url manipulation or wrong step // check for url manipulation or wrong step
if ((isset($_SESSION['installation']['stepCompleted']) && ($this->currentStep + 1) > ($_SESSION['installation']['stepCompleted'] ?? 0)) if ((isset($_SESSION['installation']['stepCompleted']) && ($this->currentStep + 1) > $_SESSION['installation']['stepCompleted'])
|| (!isset($_SESSION['installation']['stepCompleted']) && $this->currentStep > 0) || (!isset($_SESSION['installation']['stepCompleted']) && $this->currentStep > 0)
) { ) {
$this->currentStep = isset($_SESSION['installation']['stepCompleted']) ? $_SESSION['installation']['stepCompleted'] + 1 : 1; $this->currentStep = isset($_SESSION['installation']['stepCompleted']) ? $_SESSION['installation']['stepCompleted'] + 1 : 1;
@@ -136,6 +136,7 @@ class Install
'section' => $this->formfield['install']['sections']['step' . $this->currentStep] ?? [], 'section' => $this->formfield['install']['sections']['step' . $this->currentStep] ?? [],
'error' => $error ?? null, 'error' => $error ?? null,
'extended' => $this->extendedView, 'extended' => $this->extendedView,
'csrf_token' => Froxlor::genSessionId(20),
]); ]);
// output view // output view
@@ -151,16 +152,14 @@ class Install
if ($this->currentStep <= $this->maxSteps) { if ($this->currentStep <= $this->maxSteps) {
// Validate user data // Validate user data
$validatedData = $this->validateRequest($formfield['sections']['step' . $this->currentStep]['fields']); $validatedData = $this->validateRequest($formfield['sections']['step' . $this->currentStep]['fields']);
// Check database connection (
if ($this->currentStep == 1) { if ($this->currentStep == 1) {
// Check database connection
$this->checkDatabase($validatedData); $this->checkDatabase($validatedData);
} } elseif ($this->currentStep == 2) {
// Check validity of admin user data // Check validity of admin user data
elseif ($this->currentStep == 2) {
$this->checkAdminUser($validatedData); $this->checkAdminUser($validatedData);
} } elseif ($this->currentStep == 3) {
// Check validity of system data // Check validity of system data
elseif ($this->currentStep == 3) {
$this->checkSystem($validatedData); $this->checkSystem($validatedData);
} }
$validatedData['stepCompleted'] = ($this->currentStep < $this->maxSteps) ? $this->currentStep : ($this->maxSteps - 1); $validatedData['stepCompleted'] = ($this->currentStep < $this->maxSteps) ? $this->currentStep : ($this->maxSteps - 1);
@@ -192,7 +191,7 @@ class Install
private function checkInstallStateFinished(): bool private function checkInstallStateFinished(): bool
{ {
$core = new Core($_SESSION['installation']); $core = new Core($_SESSION['installation']);
if (isset($_SESSION['installation']['manual_config']) && (int) $_SESSION['installation']['manual_config'] == 1) { if (isset($_SESSION['installation']['manual_config']) && (int)$_SESSION['installation']['manual_config'] == 1) {
$core->createUserdataConf(); $core->createUserdataConf();
return true; return true;
} }
@@ -200,7 +199,7 @@ class Install
$stmt = $pdo->prepare("SELECT `value` FROM `panel_settings` WHERE `settinggroup` = 'panel' AND `varname` = 'is_configured'"); $stmt = $pdo->prepare("SELECT `value` FROM `panel_settings` WHERE `settinggroup` = 'panel' AND `varname` = 'is_configured'");
$stmt->execute(); $stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC); $result = $stmt->fetch(PDO::FETCH_ASSOC);
if ($result && (int) $result['value'] == 1) { if ($result && (int)$result['value'] == 1) {
$core->createUserdataConf(); $core->createUserdataConf();
return true; return true;
} }
@@ -223,7 +222,7 @@ class Install
} }
// check for required extensions // check for required extensions
foreach ($this->requiredExtensions as $requiredExtension) { foreach (Requirements::REQUIRED_EXTENSIONS as $requiredExtension) {
if (in_array($requiredExtension, $this->loadedExtensions)) { if (in_array($requiredExtension, $this->loadedExtensions)) {
continue; continue;
} }
@@ -231,7 +230,7 @@ class Install
} }
// check for suggested extensions // check for suggested extensions
foreach ($this->suggestedExtensions as $suggestedExtension) { foreach (Requirements::SUGGESTED_EXTENSIONS as $suggestedExtension) {
if (in_array($suggestedExtension, $this->loadedExtensions)) { if (in_array($suggestedExtension, $this->loadedExtensions)) {
continue; continue;
} }
@@ -250,11 +249,11 @@ class Install
*/ */
private function getInformationText(): string private function getInformationText(): string
{ {
if (version_compare($this->requiredVersion, PHP_VERSION, "<")) { if (version_compare(Requirements::REQUIRED_VERSION, PHP_VERSION, "<")) {
$text = lng('install.phpinfosuccess', [$this->phpVersion]); $text = lng('install.phpinfosuccess', [$this->phpVersion]);
} else { } else {
$text = lng('install.phpinfowarn', [$this->requiredVersion]); $text = lng('install.phpinfowarn', [Requirements::REQUIRED_VERSION]);
$this->criticals[] = lng('install.phpinfoupdate', [$this->phpVersion, $this->requiredVersion]); $this->criticals[] = lng('install.phpinfoupdate', [$this->phpVersion, Requirements::REQUIRED_VERSION]);
} }
return $text; return $text;
} }
@@ -302,7 +301,7 @@ class Install
throw new Exception(lng('install.errors.nov4andnov6ip')); throw new Exception(lng('install.errors.nov4andnov6ip'));
} elseif (!empty($serveripv4) && (!Validate::validate_ip2($serveripv4, true, '', false, true) || IPTools::is_ipv6($serveripv4))) { } elseif (!empty($serveripv4) && (!Validate::validate_ip2($serveripv4, true, '', false, true) || IPTools::is_ipv6($serveripv4))) {
throw new Exception(lng('error.invalidip', [$serveripv4])); throw new Exception(lng('error.invalidip', [$serveripv4]));
} elseif (!empty($serveripv6) && (!Validate::validate_ip2($serveripv6, true, '', false, true) || IPTools::is_ipv6($serveripv6) == false)) { } elseif (!empty($serveripv6) && (!Validate::validate_ip2($serveripv6, true, '', false, true) || !IPTools::is_ipv6($serveripv6))) {
throw new Exception(lng('error.invalidip', [$serveripv6])); throw new Exception(lng('error.invalidip', [$serveripv6]));
} elseif (!Validate::validateDomain($servername)) { } elseif (!Validate::validateDomain($servername)) {
throw new Exception(lng('install.errors.servernameneedstobevalid')); throw new Exception(lng('install.errors.servernameneedstobevalid'));
@@ -410,7 +409,7 @@ class Install
} else { } else {
$osrf = explode("\n", file_get_contents('/etc/os-release')); $osrf = explode("\n", file_get_contents('/etc/os-release'));
foreach ($osrf as $line) { foreach ($osrf as $line) {
$osrfline = explode("\n", $line); $osrfline = explode("=", $line);
if ($osrfline[0] == 'VERSION_CODENAME') { if ($osrfline[0] == 'VERSION_CODENAME') {
$os_dist['VERSION_CODENAME'] = $osrfline[1]; $os_dist['VERSION_CODENAME'] = $osrfline[1];
} else if ($osrfline[0] == 'ID') { } else if ($osrfline[0] == 'ID') {

View File

@@ -0,0 +1,10 @@
<?php
namespace Froxlor\Install;
class Requirements
{
const REQUIRED_VERSION = '7.4.0';
const REQUIRED_EXTENSIONS = ['session', 'ctype', 'xml', 'filter', 'posix', 'mbstring', 'pdo_mysql', 'curl', 'gmp', 'json', 'gd'];
const SUGGESTED_EXTENSIONS = ['bcmath', 'zip', 'gnupg'];
}

View File

@@ -321,6 +321,10 @@ class UI
} }
} }
} }
// check for template-variant
if (preg_match("/([a-z0-9.\-]+)_([a-z0-9.\-]+)/i", $theme, $matches)) {
$theme = $matches[1];
}
if (!file_exists(Froxlor::getInstallDir() . '/templates/' . $theme)) { if (!file_exists(Froxlor::getInstallDir() . '/templates/' . $theme)) {
PhpHelper::phpErrHandler(E_USER_WARNING, "Theme '" . $theme . "' could not be found.", __FILE__, __LINE__); PhpHelper::phpErrHandler(E_USER_WARNING, "Theme '" . $theme . "' could not be found.", __FILE__, __LINE__);
$theme = self::$default_theme; $theme = self::$default_theme;

View File

@@ -35,6 +35,11 @@ class Data
return self::validateFormFieldString($fieldname, $fielddata, $newfieldvalue); return self::validateFormFieldString($fieldname, $fielddata, $newfieldvalue);
} }
public static function validateFormFieldPassword($fieldname, $fielddata, $newfieldvalue)
{
return self::validateFormFieldString($fieldname, $fielddata, $newfieldvalue);
}
public static function validateFormFieldString($fieldname, $fielddata, $newfieldvalue) public static function validateFormFieldString($fieldname, $fielddata, $newfieldvalue)
{ {
if (isset($fielddata['string_delimiter']) && $fielddata['string_delimiter'] != '') { if (isset($fielddata['string_delimiter']) && $fielddata['string_delimiter'] != '') {
@@ -210,75 +215,6 @@ class Data
} }
} }
public static function validateFormFieldHiddenString($fieldname, $fielddata, $newfieldvalue)
{
if (isset($fielddata['string_delimiter']) && $fielddata['string_delimiter'] != '') {
$newfieldvalues = explode($fielddata['string_delimiter'], $newfieldvalue);
unset($fielddata['string_delimiter']);
$returnvalue = true;
foreach ($newfieldvalues as $single_newfieldvalue) {
/**
* don't use tabs in value-fields, #81
*/
$single_newfieldvalue = str_replace("\t", " ", $single_newfieldvalue);
$single_returnvalue = Data::validateFormFieldString($fieldname, $fielddata, $single_newfieldvalue);
if ($single_returnvalue !== true) {
$returnvalue = $single_returnvalue;
break;
}
}
} else {
$returnvalue = false;
/**
* don't use tabs in value-fields, #81
*/
$newfieldvalue = str_replace("\t", " ", $newfieldvalue);
if (isset($fielddata['string_type']) && $fielddata['string_type'] == 'mail') {
$returnvalue = Validate::validateEmail($newfieldvalue);
} elseif (isset($fielddata['string_type']) && $fielddata['string_type'] == 'url') {
$returnvalue = Validate::validateUrl($newfieldvalue);
} elseif (isset($fielddata['string_type']) && $fielddata['string_type'] == 'dir') {
// add trailing slash to validate path if needed
// refs #331
if (substr($newfieldvalue, -1) != '/') {
$newfieldvalue .= '/';
}
$returnvalue = ($newfieldvalue == FileDir::makeCorrectDir($newfieldvalue));
} elseif (isset($fielddata['string_type']) && $fielddata['string_type'] == 'file') {
$returnvalue = ($newfieldvalue == FileDir::makeCorrectFile($newfieldvalue));
} elseif (isset($fielddata['string_type']) && $fielddata['string_type'] == 'filedir') {
$returnvalue = (($newfieldvalue == FileDir::makeCorrectDir($newfieldvalue)) || ($newfieldvalue == FileDir::makeCorrectFile($newfieldvalue)));
} elseif (preg_match('/^[^\r\n\t\f\0]*$/D', $newfieldvalue)) {
$returnvalue = true;
}
if (isset($fielddata['string_regexp']) && $fielddata['string_regexp'] != '') {
if (preg_match($fielddata['string_regexp'], $newfieldvalue)) {
$returnvalue = true;
} else {
$returnvalue = false;
}
}
if (isset($fielddata['string_emptyallowed']) && $fielddata['string_emptyallowed'] === true && $newfieldvalue === '') {
$returnvalue = true;
} elseif (isset($fielddata['string_emptyallowed']) && $fielddata['string_emptyallowed'] === false && $newfieldvalue === '') {
$returnvalue = 'stringmustntbeempty';
}
}
if ($returnvalue === true) {
return true;
} elseif ($returnvalue === false) {
return 'stringformaterror';
} else {
return $returnvalue;
}
}
public static function validateFormFieldNumber($fieldname, $fielddata, $newfieldvalue) public static function validateFormFieldNumber($fieldname, $fielddata, $newfieldvalue)
{ {
if (isset($fielddata['min']) && (int)$newfieldvalue < (int)$fielddata['min']) { if (isset($fielddata['min']) && (int)$newfieldvalue < (int)$fielddata['min']) {
@@ -323,10 +259,16 @@ class Data
if (preg_match($fielddata['string_regexp'], $newfieldvalue)) { if (preg_match($fielddata['string_regexp'], $newfieldvalue)) {
$returnvalue = true; $returnvalue = true;
} }
} else if (preg_match('/^[^\0]*$/', $newfieldvalue)) { } elseif (preg_match('/^[^\0]*$/', $newfieldvalue)) {
$returnvalue = true; $returnvalue = true;
} }
return $returnvalue; return $returnvalue;
} }
public static function validateFormFieldImage($fieldname, $fielddata, $newfieldvalue)
{
// validation is handled in \Froxlor\Settings\Store::storeSettingImage()
return true;
}
} }

View File

@@ -3383,6 +3383,11 @@ aliases: files
</visibility> </visibility>
<command><![CDATA[a2dismod php8.2]]></command> <command><![CDATA[a2dismod php8.2]]></command>
</commands> </commands>
<commands index="5">
<visibility mode="equals" value="apache2">{{settings.system.webserver}}
</visibility>
<command><![CDATA[a2disconf php8.2-fpm]]></command>
</commands>
<!-- instead of just restarting apache, we let the cronjob do all the <!-- instead of just restarting apache, we let the cronjob do all the
dirty work --> dirty work -->
<command><![CDATA[php {{const.install_dir}}bin/froxlor-cli froxlor:cron --force]]></command> <command><![CDATA[php {{const.install_dir}}bin/froxlor-cli froxlor:cron --force]]></command>

View File

@@ -4172,6 +4172,11 @@ aliases: files
</visibility> </visibility>
<command><![CDATA[a2dismod php8.1]]></command> <command><![CDATA[a2dismod php8.1]]></command>
</commands> </commands>
<commands index="5">
<visibility mode="equals" value="apache2">{{settings.system.webserver}}
</visibility>
<command><![CDATA[a2disconf php8.1-fpm]]></command>
</commands>
<!-- instead of just restarting apache, we let the cronjob do all the <!-- instead of just restarting apache, we let the cronjob do all the
dirty work --> dirty work -->
<command><![CDATA[php {{const.install_dir}}bin/froxlor-cli froxlor:cron --force]]></command> <command><![CDATA[php {{const.install_dir}}bin/froxlor-cli froxlor:cron --force]]></command>

View File

@@ -38,11 +38,20 @@ return [
'type' => 'select', 'type' => 'select',
'select_var' => $free_templates 'select_var' => $free_templates
], ],
'file_extension' => [
'label' => lng('admin.templates.file_extension'),
'type' => 'text',
'string_regexp' => '/^[a-zA-Z0-9]{1,6}$/',
'default' => 'html',
'value' => 'html',
'mandatory' => true
],
'filecontent' => [ 'filecontent' => [
'label' => lng('admin.templates.filecontent'), 'label' => lng('admin.templates.filecontent'),
'type' => 'textarea', 'type' => 'textarea',
'cols' => 60, 'cols' => 60,
'rows' => 12 'rows' => 12,
'mandatory' => true
], ],
'filesend' => [ 'filesend' => [
'type' => 'hidden', 'type' => 'hidden',

View File

@@ -39,12 +39,21 @@ return [
'value' => lng('admin.templates.' . $row['varname']), 'value' => lng('admin.templates.' . $row['varname']),
'display' => lng('admin.templates.' . $row['varname']) 'display' => lng('admin.templates.' . $row['varname'])
], ],
'file_extension' => [
'label' => lng('admin.templates.file_extension'),
'type' => 'text',
'string_regexp' => '/^[a-zA-Z0-9]{1,6}$/',
'value' => $row['file_extension'],
'default' => 'html',
'mandatory' => true
],
'filecontent' => [ 'filecontent' => [
'label' => lng('admin.templates.filecontent'), 'label' => lng('admin.templates.filecontent'),
'type' => 'textarea', 'type' => 'textarea',
'cols' => 60, 'cols' => 60,
'rows' => 12, 'rows' => 12,
'value' => $row['value'] 'value' => $row['value'],
'mandatory' => true
], ],
'filesend' => [ 'filesend' => [
'type' => 'hidden', 'type' => 'hidden',

View File

@@ -65,6 +65,7 @@ use Froxlor\UI\Linker;
use Froxlor\UI\Panel\UI; use Froxlor\UI\Panel\UI;
use Froxlor\UI\Request; use Froxlor\UI\Request;
use Froxlor\UI\Response; use Froxlor\UI\Response;
use Froxlor\Install\Requirements;
// include MySQL-tabledefinitions // include MySQL-tabledefinitions
require Froxlor::getInstallDir() . '/lib/tables.inc.php'; require Froxlor::getInstallDir() . '/lib/tables.inc.php';
@@ -114,18 +115,34 @@ if (!isset($sql) || !is_array($sql)) {
/** /**
* Show nice note if requested domain is "unknown" to froxlor and thus is being lead to its vhost * Show nice note if requested domain is "unknown" to froxlor and thus is being lead to its vhost
*/ */
if ($_SERVER['SERVER_NAME'] != Settings::Get('system.hostname') && $req_host = UI::getCookieHost();
!filter_var($_SERVER['SERVER_NAME'], FILTER_VALIDATE_IP) && ( if ($req_host != Settings::Get('system.hostname') &&
Settings::Get('panel.is_configured') == 1 &&
!filter_var($req_host, FILTER_VALIDATE_IP) && (
empty(Settings::Get('system.froxloraliases')) || empty(Settings::Get('system.froxloraliases')) ||
(!empty(Settings::Get('system.froxloraliases')) && !in_array($_SERVER['SERVER_NAME'], array_map('trim', explode(',', Settings::Get('system.froxloraliases'))))) (!empty(Settings::Get('system.froxloraliases')) && !in_array($req_host, array_map('trim', explode(',', Settings::Get('system.froxloraliases')))))
)) { )) {
// not the froxlor system-hostname, show info page for domains not configured in froxlor // not the froxlor system-hostname, show info page for domains not configured in froxlor
$unconfiguredPath = FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/templates/misc/unconfigured/index.html'); $redirect_file = FileDir::getUnknownDomainTemplate($req_host);
if (file_exists($unconfiguredPath)) { header('Location: '.$redirect_file);
echo file_get_contents($unconfiguredPath); die();
} else { }
echo "This domain requires configuration via the froxlor server management panel, as it is currently not assigned to any customer.";
// validate php-extensions requirements
$loadedExtensions = get_loaded_extensions();
$missingExtensions = [];
foreach (Requirements::REQUIRED_EXTENSIONS as $requiredExtension) {
if (in_array($requiredExtension, $loadedExtensions)) {
continue;
} }
$missingExtensions[] = $requiredExtension;
}
if (!empty($missingExtensions)) {
UI::twig()->addGlobal('install_mode', '1');
echo UI::twig()->render($_deftheme . '/misc/missingextensionhint.html.twig', [
'phpversion' => phpversion(),
'missing_extensions' => implode(", ", $missingExtensions),
]);
die(); die();
} }
@@ -187,7 +204,7 @@ if (Update::versionInUpdate(Settings::Get('panel.version'), '2.0.0-beta1')) {
// Check if a different variant of the theme is used // Check if a different variant of the theme is used
$themevariant = "default"; $themevariant = "default";
if (preg_match("/([a-z0-9\.\-]+)_([a-z0-9\.\-]+)/i", $theme, $matches)) { if (preg_match("/([a-z0-9.\-]+)_([a-z0-9.\-]+)/i", $theme, $matches)) {
$theme = $matches[1]; $theme = $matches[1];
$themevariant = $matches[2]; $themevariant = $matches[2];
} }
@@ -360,4 +377,6 @@ if (CurrentUser::hasSession()) {
'samesite' => 'Strict' 'samesite' => 'Strict'
]; ];
setcookie(session_name(), $_COOKIE[session_name()], $cookie_params); setcookie(session_name(), $_COOKIE[session_name()], $cookie_params);
} else {
UI::twig()->addGlobal('csrf_token', Froxlor::genSessionId(20));
} }

View File

@@ -161,13 +161,13 @@ return [
'show_element' => (!Settings::IsInList('panel.customer_hide_options', 'misc.documentation')), 'show_element' => (!Settings::IsInList('panel.customer_hide_options', 'misc.documentation')),
'elements' => [ 'elements' => [
[ [
'url' => 'https://docs.froxlor.org/v2/user-guide/', 'url' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/',
'label' => lng('admin.userguide'), 'label' => lng('admin.userguide'),
'new_window' => true, 'new_window' => true,
'is_external' => true, 'is_external' => true,
], ],
[ [
'url' => 'https://docs.froxlor.org/v2/api-guide/', 'url' => \Froxlor\Froxlor::DOCS_URL . 'api-guide/',
'label' => lng('admin.apiguide'), 'label' => lng('admin.apiguide'),
'new_window' => true, 'new_window' => true,
'show_element' => Settings::Get('api.enabled') == 1 && CurrentUser::getField('api_allowed') == 1, 'show_element' => Settings::Get('api.enabled') == 1 && CurrentUser::getField('api_allowed') == 1,
@@ -348,13 +348,13 @@ return [
'icon' => 'fa-solid fa-circle-info', 'icon' => 'fa-solid fa-circle-info',
'elements' => [ 'elements' => [
[ [
'url' => 'https://docs.froxlor.org/v2/admin-guide/', 'url' => \Froxlor\Froxlor::DOCS_URL . 'admin-guide/',
'label' => lng('admin.adminguide'), 'label' => lng('admin.adminguide'),
'new_window' => true, 'new_window' => true,
'is_external' => true, 'is_external' => true,
], ],
[ [
'url' => 'https://docs.froxlor.org/v2/api-guide/', 'url' => \Froxlor\Froxlor::DOCS_URL . 'api-guide/',
'label' => lng('admin.apiguide'), 'label' => lng('admin.apiguide'),
'new_window' => true, 'new_window' => true,
'show_element' => Settings::Get('api.enabled') == 1, 'show_element' => Settings::Get('api.enabled') == 1,

View File

@@ -140,12 +140,18 @@ return [
'TRAFFICUSED' => 'Wird mit Traffic, der vom Kunden bereits verbraucht wurde, ersetzt.', 'TRAFFICUSED' => 'Wird mit Traffic, der vom Kunden bereits verbraucht wurde, ersetzt.',
'pop_success_alternative' => 'Willkommensmail für neue E-Mail-Konten für die alternative E-Mail-Adresse', 'pop_success_alternative' => 'Willkommensmail für neue E-Mail-Konten für die alternative E-Mail-Adresse',
'EMAIL_PASSWORD' => 'Wird mit dem Passwort des neuen POP3/IMAP Kontos ersetzt.', 'EMAIL_PASSWORD' => 'Wird mit dem Passwort des neuen POP3/IMAP Kontos ersetzt.',
'index_html' => 'index.html Datei für neu erzeugte Kundenverzeichnisse', 'index_html' => 'index Datei für neu erzeugte Kundenverzeichnisse',
'unconfigured_html' => 'index Datei für unkonfigurierte/unbekannte Domains',
'unconfigured_content_fallback' => 'Diese Domain muss über das Froxlor-Serververwaltungspanel konfiguriert werden, da sie derzeit keinem Kunden zugewiesen ist.',
'file_extension' => [
'description' => 'Die Dateiendung für die index Datei muss zwischen 1 und 6 Zeichen lang sein und darf nur aus den Zeichen a-z, A-Z und 0-9 bestehen<br><br>Standard: html',
'title' => 'Dateiendung für Datei Vorlage',
],
'SERVERNAME' => 'Wird mit dem Servernamen ersetzt.', 'SERVERNAME' => 'Wird mit dem Servernamen ersetzt.',
'CUSTOMER' => 'Wird mit dem Loginnamen des Kunden ersetzt.', 'CUSTOMER' => 'Wird mit dem Loginnamen des Kunden ersetzt. Nur für "index Datei für neu erzeugte Kundenverzeichnisse".',
'ADMIN' => 'Wird mit dem Loginnamen des Admins ersetzt.', 'ADMIN' => 'Wird mit dem Loginnamen des Admins ersetzt. Nur für "index Datei für neu erzeugte Kundenverzeichnisse".',
'CUSTOMER_EMAIL' => 'Wird mit der E-Mail-Adresse des Kunden ersetzt.', 'CUSTOMER_EMAIL' => 'Wird mit der E-Mail-Adresse des Kunden ersetzt. Nur für "index Datei für neu erzeugte Kundenverzeichnisse".',
'ADMIN_EMAIL' => 'Wird mit der E-Mail-Adresse des Admin ersetzt.', 'ADMIN_EMAIL' => 'Wird mit der E-Mail-Adresse des Admin ersetzt. Nur für "index Datei für neu erzeugte Kundenverzeichnisse".',
'filetemplates' => 'Dateivorlagen', 'filetemplates' => 'Dateivorlagen',
'filecontent' => 'Dateiinhalt', 'filecontent' => 'Dateiinhalt',
'new_database_by_customer' => 'Kunden-Benachrichtigungs nach Erstellung einer neuen Datenbank', 'new_database_by_customer' => 'Kunden-Benachrichtigungs nach Erstellung einer neuen Datenbank',
@@ -831,7 +837,6 @@ return [
'descriptioninvalid' => 'Der Beschreibungstext ist zu kurz, zu lang oder enthält ungültige Zeichen', 'descriptioninvalid' => 'Der Beschreibungstext ist zu kurz, zu lang oder enthält ungültige Zeichen',
'info' => 'Info', 'info' => 'Info',
'filecontentnotset' => 'Diese Datei darf nicht leer sein!', 'filecontentnotset' => 'Diese Datei darf nicht leer sein!',
'index_file_extension' => 'Die Dateiendung für die index Datei muss zwischen 1 und 6 Zeichen lang sein und darf nur aus den Zeichen a-z, A-Z und 0-9 bestehen',
'customerdoesntexist' => 'Der ausgewählte Kunde existiert nicht.', 'customerdoesntexist' => 'Der ausgewählte Kunde existiert nicht.',
'admindoesntexist' => 'Der ausgewählte Admin existiert nicht.', 'admindoesntexist' => 'Der ausgewählte Admin existiert nicht.',
'ipportdoesntexist' => 'Die gewählte IP/Port-Kombination existiert nicht.', 'ipportdoesntexist' => 'Die gewählte IP/Port-Kombination existiert nicht.',
@@ -1610,10 +1615,6 @@ Vielen Dank, Ihr Administrator',
'removelink' => 'Hier klicken, um alle E-Mail-Kontingente zu entfernen', 'removelink' => 'Hier klicken, um alle E-Mail-Kontingente zu entfernen',
'enforcelink' => 'Hier klicken, um allen Benutzern das Standard-Kontingent zu zuweisen.', 'enforcelink' => 'Hier klicken, um allen Benutzern das Standard-Kontingent zu zuweisen.',
], ],
'index_file_extension' => [
'description' => 'Welche Dateiendung soll die index Datei in neu erstellten Kundenverzeichnissen haben? Diese Dateiendung wird dann verwendet, wenn Sie bzw. einer Ihrer Admins eigene index Dateivorlagen erstellt haben.',
'title' => 'Dateiendung für index Datei in neu erstellen Kundenverzeichnissen',
],
'session_allow_multiple_login' => [ 'session_allow_multiple_login' => [
'title' => 'Erlaube gleichzeitigen Login', 'title' => 'Erlaube gleichzeitigen Login',
'description' => 'Wenn diese Option aktiviert ist, können sich Nutzer mehrmals gleichzeitig anmelden.', 'description' => 'Wenn diese Option aktiviert ist, können sich Nutzer mehrmals gleichzeitig anmelden.',
@@ -2242,7 +2243,7 @@ Vielen Dank, Ihr Administrator',
'database' => [ 'database' => [
'top' => 'Datenbank', 'top' => 'Datenbank',
'title' => 'Datenbank und Benutzer erstellen', 'title' => 'Datenbank und Benutzer erstellen',
'description' => 'Froxlor benötigt eine Datenbank und zusätzlich einen Benutzer mit privilegierten Rechten, welcher Benutzer und Datenbanken erstellen darf (GRANT Option). Die angegebene Datenbank und der unprivilegierte Benutzer werden automatisch in diesem Prozess erstellt. Der privilegierte Benutzer muss existieren.', 'description' => 'Froxlor benötigt eine Datenbank und zusätzlich <a href="https://docs.froxlor.org/latest/general/installation/tarball.html#_3-create-privileged-database-user" target="_blank">einen Benutzer mit privilegierten Rechten</a>, welcher Benutzer und Datenbanken erstellen darf (GRANT Option). Die angegebene Datenbank und der unprivilegierte Benutzer werden automatisch in diesem Prozess erstellt. Der privilegierte Benutzer muss existieren.',
'user' => 'Unprivilegierter Datenbank Benutzer', 'user' => 'Unprivilegierter Datenbank Benutzer',
'dbname' => 'Datenbank Name', 'dbname' => 'Datenbank Name',
'force_create' => 'Sichern und überschreiben, sofern Datenbank existiert?', 'force_create' => 'Sichern und überschreiben, sofern Datenbank existiert?',

View File

@@ -144,11 +144,17 @@ return [
'pop_success_alternative' => 'Welcome mail for new email accounts sent to alternative address', 'pop_success_alternative' => 'Welcome mail for new email accounts sent to alternative address',
'EMAIL_PASSWORD' => 'Replaced with the POP3/IMAP account password.', 'EMAIL_PASSWORD' => 'Replaced with the POP3/IMAP account password.',
'index_html' => 'index file for newly created customer directories', 'index_html' => 'index file for newly created customer directories',
'unconfigured_html' => 'index file for unconfigured/unknown domains',
'unconfigured_content_fallback' => 'This domain requires configuration via the froxlor server management panel, as it is currently not assigned to any customer.',
'file_extension' => [
'description' => 'The file extension for the index file must be between 1 and 6 characters long. The extension can only contain characters like a-z, A-Z and 0-9<br><br>Default: html',
'title' => 'File extension for the file template',
],
'SERVERNAME' => 'Replaced with the servername.', 'SERVERNAME' => 'Replaced with the servername.',
'CUSTOMER' => 'Replaced with the loginname of the customer.', 'CUSTOMER' => 'Replaced with the loginname of the customer. Only for "index file for newly created customer directories"',
'ADMIN' => 'Replaced with the loginname of the admin.', 'ADMIN' => 'Replaced with the loginname of the admin. Only for "index file for newly created customer directories"',
'CUSTOMER_EMAIL' => 'Replaced with the e-mail address of the customer.', 'CUSTOMER_EMAIL' => 'Replaced with the e-mail address of the customer. Only for "index file for newly created customer directories"',
'ADMIN_EMAIL' => 'Replaced with the e-mail address of the admin.', 'ADMIN_EMAIL' => 'Replaced with the e-mail address of the admin. Only for "index file for newly created customer directories"',
'filetemplates' => 'File templates', 'filetemplates' => 'File templates',
'filecontent' => 'File content', 'filecontent' => 'File content',
'new_database_by_customer' => 'Customer-notification when a database has been created', 'new_database_by_customer' => 'Customer-notification when a database has been created',
@@ -903,7 +909,6 @@ return [
'descriptioninvalid' => 'The description is too short, too long or contains illegal characters.', 'descriptioninvalid' => 'The description is too short, too long or contains illegal characters.',
'info' => 'Info', 'info' => 'Info',
'filecontentnotset' => 'The file cannot be empty!', 'filecontentnotset' => 'The file cannot be empty!',
'index_file_extension' => 'The file extension for the index file must be between 1 and 6 characters long. The extension can only contain characters like a-z, A-Z and 0-9',
'customerdoesntexist' => 'The customer you have chosen doesn\'t exist.', 'customerdoesntexist' => 'The customer you have chosen doesn\'t exist.',
'admindoesntexist' => 'The admin you have chosen doesn\'t exist.', 'admindoesntexist' => 'The admin you have chosen doesn\'t exist.',
'ipportdoesntexist' => 'The ip/port combination you have chosen doesn\'t exist.', 'ipportdoesntexist' => 'The ip/port combination you have chosen doesn\'t exist.',
@@ -1732,10 +1737,6 @@ Yours sincerely, your administrator',
'removelink' => 'Click here to wipe all quotas for mail accounts.', 'removelink' => 'Click here to wipe all quotas for mail accounts.',
'enforcelink' => 'Click here to enforce default quota to all User mail accounts.', 'enforcelink' => 'Click here to enforce default quota to all User mail accounts.',
], ],
'index_file_extension' => [
'description' => 'Which file extension should be used for the index file in newly created customer directories? This file extension will be used, if you or one of your admins has created its own index file template.',
'title' => 'File extension for index file in newly created customer directories',
],
'session_allow_multiple_login' => [ 'session_allow_multiple_login' => [
'title' => 'Allow multiple login', 'title' => 'Allow multiple login',
'description' => 'If activated a user could login multiple times.', 'description' => 'If activated a user could login multiple times.',
@@ -2210,6 +2211,7 @@ Yours sincerely, your administrator',
], ],
'uc_stable' => 'stable', 'uc_stable' => 'stable',
'uc_testing' => 'testing', 'uc_testing' => 'testing',
'uc_nightly' => 'nightly',
'traffictool' => [ 'traffictool' => [
'toolselect' => 'Traffic analyzer', 'toolselect' => 'Traffic analyzer',
'webalizer' => 'Webalizer', 'webalizer' => 'Webalizer',
@@ -2377,7 +2379,7 @@ Yours sincerely, your administrator',
'database' => [ 'database' => [
'top' => 'Database', 'top' => 'Database',
'title' => 'Create database and user', 'title' => 'Create database and user',
'description' => 'Froxlor requires a database and additionally a privileged user to be able to create users and databases (GRANT option). The given database and unprivileged database-user will be created in this process. The privileged user must exist.', 'description' => 'Froxlor requires a database and additionally <a href="https://docs.froxlor.org/latest/general/installation/tarball.html#_3-create-privileged-database-user" target="_blank">a privileged user</a> to be able to create users and databases (GRANT option). The given database and unprivileged database-user will be created in this process. The privileged user must exist.',
'user' => 'Unprivileged database user', 'user' => 'Unprivileged database user',
'dbname' => 'Database name', 'dbname' => 'Database name',
'force_create' => 'Backup and overwrite database if exists?', 'force_create' => 'Backup and overwrite database if exists?',

8
package-lock.json generated
View File

@@ -19,7 +19,7 @@
"postcss": "^8.1.14", "postcss": "^8.1.14",
"resolve-url-loader": "^5.0.0", "resolve-url-loader": "^5.0.0",
"sass": "^1.69.3", "sass": "^1.69.3",
"vite": "^4.0.0", "vite": "^4.4.12",
"vue": "^3.2.37" "vue": "^3.2.37"
}, },
"engines": { "engines": {
@@ -1156,9 +1156,9 @@
} }
}, },
"node_modules/vite": { "node_modules/vite": {
"version": "4.4.11", "version": "4.4.12",
"resolved": "https://registry.npmjs.org/vite/-/vite-4.4.11.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.12.tgz",
"integrity": "sha512-ksNZJlkcU9b0lBwAGZGGaZHCMqHsc8OpgtoYhsQ4/I2v5cnpmmmqe5pM4nv/4Hn6G/2GhTdj0DhZh2e+Er1q5A==", "integrity": "sha512-KtPlUbWfxzGVul8Nut8Gw2Qe8sBzWY+8QVc5SL8iRFnpnrcoCaNlzO40c1R6hPmcdTwIPEDkq0Y9+27a5tVbdQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"esbuild": "^0.18.10", "esbuild": "^0.18.10",

View File

@@ -19,7 +19,7 @@
"postcss": "^8.1.14", "postcss": "^8.1.14",
"resolve-url-loader": "^5.0.0", "resolve-url-loader": "^5.0.0",
"sass": "^1.69.3", "sass": "^1.69.3",
"vite": "^4.0.0", "vite": "^4.4.12",
"vue": "^3.2.37" "vue": "^3.2.37"
}, },
"engines": { "engines": {

View File

@@ -22,6 +22,9 @@
} }
} }
} }
.list-group-item {
background: $white;
}
@include color-mode(dark) { @include color-mode(dark) {
.card, .list-group-item { .card, .list-group-item {

View File

@@ -8,7 +8,7 @@
{{ call_static('\\Froxlor\\Froxlor', 'getFullVersion') }} {{ call_static('\\Froxlor\\Froxlor', 'getFullVersion') }}
{% endif %} {% endif %}
{% endif %} {% endif %}
&copy; 2009-{{ "now"|date("Y") }} by <a href="https://www.froxlor.org/" rel="external" target="_blank">the Froxlor Team</a><br> &copy; 2009-{{ "now"|date("Y") }} by <a href="https://www.froxlor.org/" rel="external" target="_blank">the froxlor team</a><br>
{% if install_mode is not defined %} {% if install_mode is not defined %}
{% if (get_setting('panel.imprint_url') != '') %}<a href="{{ get_setting('panel.imprint_url') }}" target="_blank" class="footer-link">{{ lng('imprint') }}</a>{% endif %} {% if (get_setting('panel.imprint_url') != '') %}<a href="{{ get_setting('panel.imprint_url') }}" target="_blank" class="footer-link">{{ lng('imprint') }}</a>{% endif %}
{% if (get_setting('panel.terms_url') != '') %}<a href="{{ get_setting('panel.terms_url') }}" target="_blank" class="footer-link">{{ lng('terms') }}</a>{% endif %} {% if (get_setting('panel.terms_url') != '') %}<a href="{{ get_setting('panel.terms_url') }}" target="_blank" class="footer-link">{{ lng('terms') }}</a>{% endif %}

View File

@@ -6,8 +6,8 @@
<div class="row gx-0 rounded shadow bg-primary text-white mt-5"> <div class="row gx-0 rounded shadow bg-primary text-white mt-5">
<div class="col p-5 rounded-start"> <div class="col p-5 rounded-start">
<h2 class="card-title">Welcome to Froxlor</h2> <h2 class="card-title">Welcome to froxlor</h2>
<p class="lead mt-5">It seems that Froxlor has not been installed yet.</p> <p class="lead mt-5">It seems that froxlor has not been installed yet.</p>
<p class="lead">Click on the button below to start the installation.</p> <p class="lead">Click on the button below to start the installation.</p>
</div> </div>

View File

@@ -0,0 +1,18 @@
{% extends "Froxlor/base.html.twig" %}
{% block content %}
<div class="container my-auto">
<div class="alert alert-warning fade show" role="alert">
<h4 class="alert-heading">
Whoops!
</h4>
<p>It looks like you are missing some of the required php requirements.</p>
<p>Please ensure that the following extension for the currently used php version ({{ phpversion }}) are installed:</p>
<pre>{{ missing_extensions }}</pre>
<hr>
<p class="mt-1 text-center">
<a href="" class="btn btn-primary" title="Reload page">Reload</a>
</p>
</div>
</div>
{% endblock %}

View File

@@ -35,7 +35,7 @@
<footer class="pý-5 text-center"> <footer class="pý-5 text-center">
<span> <span>
<img src="{{ basehref }}templates/Froxlor/assets/img/logo_grey.png" alt="Froxlor" /> <img src="{{ basehref }}templates/Froxlor/assets/img/logo_grey.png" alt="Froxlor" />
&copy; 2009-{{ current_year }} by <a href="https://www.froxlor.org/" rel="external">the Froxlor Team</a> &copy; 2009-{{ current_year }} by <a href="https://www.froxlor.org/" rel="external">the froxlor team</a>
</span> </span>
</footer> </footer>
</div> </div>

View File

@@ -35,7 +35,7 @@
<footer class="py-5 text-center"> <footer class="py-5 text-center">
<span> <span>
<img src="{{ basehref }}templates/Froxlor/assets/img/logo_grey.png" alt="Froxlor" /> <img src="{{ basehref }}templates/Froxlor/assets/img/logo_grey.png" alt="Froxlor" />
&copy; 2009-{{ current_year }} by <a href="https://www.froxlor.org/" rel="external">the Froxlor Team</a> &copy; 2009-{{ current_year }} by <a href="https://www.froxlor.org/" rel="external">the froxlor team</a>
</span> </span>
</footer> </footer>
</div> </div>

View File

@@ -51,8 +51,16 @@
<div class="row"> <div class="row">
{% if userinfo.adminsession == 1 %} {% if userinfo.adminsession == 1 %}
<div <div class="col-12 col-lg-6">
class="col-12 col-lg-6">
{% if userinfo.custom_notes|markdown is not empty and userinfo.custom_notes_show == 1 %}
<div class="card mb-3">
<div class="card-body">
{{ userinfo.custom_notes|markdown|raw }}
</div>
</div>
{% endif %}
{# system infos #} {# system infos #}
<div class="card mb-3"> <div class="card mb-3">
<div class="card-header"> <div class="card-header">
@@ -135,22 +143,9 @@
{% endif %} {% endif %}
</ul> </ul>
</div> </div>
{% if userinfo.custom_notes|markdown is not empty and userinfo.custom_notes_show == 1 %}
<div class="card mb-3">
<ul class="list-group list-group-flush">
<li class="list-group-item list-group-item-info d-flex justify-content-between align-items-start">
<div class="ms-2 me-auto">
{{ userinfo.custom_notes|markdown|raw }}
</div>
</li>
</ul>
</div>
{% endif %}
</div> </div>
{% else %} {% else %}
<div <div class="col-12 col-md-6 col-lg-4">
class="col-12 col-md-6 col-lg-4">
{# account info #} {# account info #}
<div class="card mb-3"> <div class="card mb-3">
<div class="card-header"> <div class="card-header">
@@ -174,16 +169,16 @@
<div class="ms-2 me-auto"> <div class="ms-2 me-auto">
<div class="fw-bold">{{ lng('customer.services') }}</div> <div class="fw-bold">{{ lng('customer.services') }}</div>
{% if userinfo.imap == 1 %} {% if userinfo.imap == 1 %}
<span class="badge bg-success">IMAP</span> <span class="badge bg-success me-1">IMAP</span>
{% endif %} {% endif %}
{% if userinfo.pop3 == 1 %} {% if userinfo.pop3 == 1 %}
<span class="badge bg-success">POP3</span> <span class="badge bg-success me-1">POP3</span>
{% endif %} {% endif %}
{% if userinfo.phpenabled == 1 %} {% if userinfo.phpenabled == 1 %}
<span class="badge bg-success">PHP</span> <span class="badge bg-success me-1">PHP</span>
{% endif %} {% endif %}
{% if userinfo.perlenabled == 1 %} {% if userinfo.perlenabled == 1 %}
<span class="badge bg-success">Perl/CGI</span> <span class="badge bg-success me-1">Perl/CGI</span>
{% endif %} {% endif %}
{% if userinfo.api_allowed == 1 %} {% if userinfo.api_allowed == 1 %}
<a href="{{ linker({'section':'index','page':'apikeys'}) }}"> <a href="{{ linker({'section':'index','page':'apikeys'}) }}">
@@ -212,8 +207,7 @@
</ul> </ul>
</div> </div>
</div> </div>
<div <div class="col-12 col-md-6 col-lg-4">
class="col-12 col-md-6 col-lg-4">
{# customer details #} {# customer details #}
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">