Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Verbesserungen beim Wartungsmodus und Clean Code #119

Merged
merged 9 commits into from
Nov 13, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
192 changes: 122 additions & 70 deletions lib/Maintenance.php
Original file line number Diff line number Diff line change
@@ -1,15 +1,5 @@
<?php

/**
* This file is part of the maintenance package.
*
* @author (c) Friends Of REDAXO
* @author <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace FriendsOfREDAXO\Maintenance;

use rex;
Expand All @@ -30,9 +20,29 @@
use const FILTER_VALIDATE_IP;
use const FILTER_VALIDATE_URL;

/**
* Class Maintenance.
* @package FriendsOfREDAXO\Maintenance
*/
class Maintenance
{
/** @api */
private static ?rex_addon $addon = null;

/**
* Gets the addon instance.
*/
private static function getAddOn(): rex_addon
{
if (null === self::$addon) {
self::$addon = rex_addon::get('maintenance');
}
return self::$addon;
}

/**
* Checks if a URL is valid.
* @api
*/
public function checkUrl(string $url): ?bool
{
if ('' !== $url) {
Expand All @@ -44,7 +54,10 @@ public function checkUrl(string $url): ?bool
return null;
}

/** @api */
/**
* Checks if an IP address is valid.
* @api
*/
public function checkIp(string $ip): ?bool
{
if ('' !== $ip && false === filter_var($ip, FILTER_VALIDATE_IP)) {
Expand All @@ -53,12 +66,14 @@ public function checkIp(string $ip): ?bool
return true;
}

/** @api */
/**
* Checks if the current IP is allowed.
* @api
*/
public static function isIpAllowed(): bool
{
$addon = rex_addon::get('maintenance');
$ip = rex_server('REMOTE_ADDR', 'string', '');
$allowedIps = (string) $addon->getConfig('allowed_ips'); // @phpstan-ignore-line
$allowedIps = (string) self::getConfig('allowed_ips', '');

if ('' !== $allowedIps) {
$allowedIpsArray = explode(',', $allowedIps);
Expand All @@ -68,12 +83,14 @@ public static function isIpAllowed(): bool
return false;
}

/** @api */
/**
* Checks if the current host is allowed.
* @api
*/
public static function isHostAllowed(): bool
{
$addon = rex_addon::get('maintenance');
$host = rex_server('HTTP_HOST', 'string', '');
$allowedHosts = (string) $addon->getConfig('allowed_yrewrite_domains', false); // @phpstan-ignore-line
$allowedHosts = (string) self::getConfig('allowed_domains', '');
skerbis marked this conversation as resolved.
Show resolved Hide resolved

if ('' !== $allowedHosts) {
$allowedHostsArray = explode(',', $allowedHosts);
Expand All @@ -83,13 +100,15 @@ public static function isHostAllowed(): bool
return false;
}

/** @api */
/**
* Checks if the current YRewrite domain is allowed.
* @api
*/
public static function isYrewriteDomainAllowed(): bool
{
$addon = rex_addon::get('maintenance');
if ($ydomain = rex_yrewrite::getDomainByArticleId(rex_article::getCurrentId(), rex_clang::getCurrentId())) {
$yrewrite_domain = $ydomain->getHost();
$allowedDomains = (string) $addon->getConfig('allowed_yrewrite_domains'); // @phpstan-ignore-line
$allowedDomains = (string) self::getConfig('allowed_yrewrite_domains', '');

if ('' !== $allowedDomains) {
$allowedDomainsArray = explode('|', $allowedDomains);
Expand All @@ -100,21 +119,24 @@ public static function isYrewriteDomainAllowed(): bool
return false;
}

/** @api */
/**
* Checks if the maintenance secret is valid.
* @api
*/
public static function isSecretAllowed(): bool
{
$addon = rex_addon::get('maintenance');
$config_secret = (string) $addon->getConfig('maintenance_secret');
$config_secret = (string) self::getConfig('maintenance_secret', '');

// Bereits mit richtigem Secret eingeloggt
if ('' != $config_secret && rex_session('maintenance_secret', 'string', '') === $config_secret) { // @phpstan-ignore-line
// Check if already logged in with the correct secret
if ('' !== $config_secret && rex_session('maintenance_secret', 'string', '') === $config_secret) {
return true;
}

$maintenance_secret = rex_request('maintenance_secret', 'string', '');
$authentification_mode = $addon->getConfig('authentification_mode');
$authentification_mode = (string) self::getConfig('authentification_mode', '');

if (('URL' === $authentification_mode || 'password' === $authentification_mode) && '' != $config_secret && $maintenance_secret === $config_secret) {
// Check if the correct secret is passed via URL or password
if (('URL' === $authentification_mode || 'password' === $authentification_mode) && '' !== $config_secret && $maintenance_secret === $config_secret) {
rex_set_session('maintenance_secret', $maintenance_secret);
return true;
}
Expand All @@ -123,140 +145,170 @@ public static function isSecretAllowed(): bool
return false;
}

/** @api */
/**
* Checks if the current user is allowed.
* @api
*/
public static function isUserAllowed(): bool
{
$addon = rex_addon::get('maintenance');
rex_backend_login::createUser();
$user = rex::getUser();

// Admins dürfen sich immer einloggen
// Admins always have access, regardless of settings
if ($user instanceof rex_user && $user->isAdmin()) {
return true;
}

// Eingeloggte REDAXO-Benutzer dürfen sich einloggen, wenn es in den Einstellungen erlaubt ist
if ($user instanceof rex_user && (bool) $addon->getConfig('allow_logged_in_users')) {
// Check if the REDAXO user should be blocked
$block_frontend_rex_user = (bool) self::getConfig('block_frontend_rex_user', false);

// If the user is logged in and should not be blocked, allow access
if ($user instanceof rex_user && !$block_frontend_rex_user) {
return true;
}

return false;
}

/**
* Checks frontend access and shows maintenance page if necessary.
*/
public static function checkFrontend(): void
{
$addon = rex_addon::get('maintenance');

rex_login::startSession();

// Wenn die IP-Adresse erlaubt ist, Anfrage nicht sperren
// If the IP address is allowed, do not block the request
if (self::isIpAllowed()) {
return;
}

// Wenn die YRewrite installiert und Domain erlaubt ist, Anfrage nicht sperren
if (rex_addon::get('yrewrite')->isAvailable()) {
if (self::isYrewriteDomainAllowed()) {
return;
}
// If YRewrite is installed and the domain is allowed, do not block the request
if (rex_addon::get('yrewrite')->isAvailable() && self::isYrewriteDomainAllowed()) {
return;
}

// Wenn die Host erlaubt ist, Anfrage nicht sperren
// If the host is allowed, do not block the request
if (self::isHostAllowed()) {
return;
}

// Wenn das Secret / Passwort stimmt, Anfrage nicht sperren
// If the secret/password is correct, do not block the request
if (self::isSecretAllowed()) {
return;
}

// Wenn eingeloggte REDAXO-Benutzer erlaubt sind, oder der Benutzer Admin ist, Anfrage nicht sperren
// If the user is allowed (admin or non-blocked editor), do not block the request
if (self::isUserAllowed()) {
return;
}

// Wenn die Sitemap angefordert wird, Anfrage nicht sperren
// If the sitemap is requested, do not block the request
$REQUEST_URI = rex_server('REQUEST_URI', 'string', '');
if (true === str_contains($REQUEST_URI, 'sitemap.xml')) {
return;
}

// EP zum Erlauben von Medien-Dateien
// EP to allow media files
$media = rex_get('rex_media_file', 'string', '');
$media_unblock = [];
$media_unblocklist = rex_extension::registerPoint(new rex_extension_point('MAINTENANCE_MEDIA_UNBLOCK_LIST', $media_unblock));
// @phpstan-ignore-next-line
if (in_array($media, $media_unblocklist, true)) {
return;
}

// Alles, was bis hier hin nicht erlaubt wurde, blockieren wie in den Einstellungen gewählt
$redirect_url = (string) $addon->getConfig('redirect_frontend_to_url'); /** @phpstan-ignore-line */
$responsecode = (string) $addon->getConfig('http_response_code'); /** @phpstan-ignore-line */
// Block everything that has not been allowed so far as chosen in the settings
$redirect_url = (string) self::getConfig('redirect_frontend_to_url', '');
$responsecode = (int) self::getConfig('http_response_code', 503);

$mpage = new rex_fragment();
if ('' !== $redirect_url) {
rex_response::setStatus(rex_response::HTTP_MOVED_TEMPORARILY);
rex_response::sendRedirect($redirect_url);
}

header('HTTP/1.1 ' . $responsecode);
exit($mpage->parse('maintenance/frontend.php'));
}

/**
* Checks backend access and shows maintenance page if necessary.
*/
public static function checkBackend(): void
{
$addon = rex_addon::get('maintenance');

if (rex::getUser() instanceof rex_user && !rex::getUser()->isAdmin() && !rex::getImpersonator()) {
if ((string) $addon->getConfig('redirect_backend_to_url')) { // @phpstan-ignore-line
rex_response::sendRedirect((string) $addon->getConfig('redirect_backend_to_url')); // @phpstan-ignore-line
$redirect_url = (string) self::getConfig('redirect_backend_to_url', '');
if ('' !== $redirect_url) {
rex_response::sendRedirect($redirect_url);
}
$mpage = new rex_fragment();
header('HTTP/1.1 ' . (string) $addon->getConfig('http_response_code')); // @phpstan-ignore-line
$responsecode = (int) self::getConfig('http_response_code', 503);
header('HTTP/1.1 ' . $responsecode);
exit($mpage->parse('maintenance/backend.php'));
}
}

/**
* Sets maintenance mode indicators in backend.
*/
public static function setIndicators(): void
{
$addon = rex_addon::get('maintenance');
$page = $addon->getProperty('page');
$page = self::getAddOn()->getProperty('page');

if ((bool) $addon->getConfig('block_backend')) {
if (self::getBoolConfig('block_backend', false)) {
$page['title'] .= ' <span class="label label-info pull-right">B</span>';
$page['icon'] .= ' fa-toggle-on block_backend';
$addon->setProperty('page', $page);
self::getAddOn()->setProperty('page', $page);
}

if ((bool) $addon->getConfig('block_frontend')) {
if (self::getBoolConfig('block_frontend', false)) {
$page['title'] .= ' <span class="label label-danger pull-right">F</span>';
$page['icon'] .= ' fa-toggle-on block_frontend';
}

$addon->setProperty('page', $page);
self::getAddOn()->setProperty('page', $page);
}

/** @api */
/**
* Shows maintenance announcement.
* @api
*/
public static function showAnnouncement(): void
{
echo self::getAnnouncement();
}

/** @api */
/**
* Gets maintenance announcement if within announcement period.
* @api
*/
public static function getAnnouncement(): string
{
$addon = rex_addon::get('maintenance');

if ('' !== (string) $addon->getConfig('announcement_start_date')) { /** @phpstan-ignore-line */
$start = strtotime((string) $addon->getConfig('announcement_start_date')); /** @phpstan-ignore-line */
$end = strtotime((string) $addon->getConfig('announcement_end_date')); /** @phpstan-ignore-line */
$start_date = (string) self::getConfig('announcement_start_date', '');
if ('' !== $start_date) {
$start = strtotime($start_date);
$end = strtotime((string) self::getConfig('announcement_end_date', ''));
$now = time();
if ($now >= $start && $now <= $end) {
return (string) $addon->getConfig('announcement'); // @phpstan-ignore-line
if ($start && $end && $now >= $start && $now <= $end) {
return (string) self::getConfig('announcement', '');
}
}

return '';
}

/**
* Gets config value with type casting.
*/
private static function getConfig(string $key, mixed $default = null): mixed
{
return self::getAddOn()->getConfig($key, $default);
}

/**
* Gets boolean config value.
*/
private static function getBoolConfig(string $key, bool $default = false): bool
{
return (bool) self::getConfig($key, $default);
}
}
Loading