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 7 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
182 changes: 117 additions & 65 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 addon(): 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', '');

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
// Prüfen ob bereits mit richtigem Secret eingeloggt
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) {
// Prüfen ob korrektes Secret per URL oder Passwort übergeben wurde
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,45 +145,49 @@ 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 haben immer Zugriff, unabhängig von Einstellungen
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')) {
// Prüfen ob der REDAXO-Benutzer gesperrt werden soll
$block_frontend_rex_user = (bool) self::getConfig('block_frontend_rex_user', false);

// Wenn Benutzer eingeloggt ist und nicht gesperrt werden soll, dann Zugriff erlauben
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 (self::isIpAllowed()) {
return;
}

// Wenn die YRewrite installiert und Domain erlaubt ist, Anfrage nicht sperren
if (rex_addon::get('yrewrite')->isAvailable()) {
if (self::isYrewriteDomainAllowed()) {
return;
}
// Wenn YRewrite installiert und Domain erlaubt ist, Anfrage nicht sperren
if (rex_addon::get('yrewrite')->isAvailable() && self::isYrewriteDomainAllowed()) {
return;
}

// Wenn die Host erlaubt ist, Anfrage nicht sperren
// Wenn der Host erlaubt ist, Anfrage nicht sperren
if (self::isHostAllowed()) {
return;
}
Expand All @@ -171,7 +197,7 @@ public static function checkFrontend(): void
return;
}

// Wenn eingeloggte REDAXO-Benutzer erlaubt sind, oder der Benutzer Admin ist, Anfrage nicht sperren
// Wenn der Benutzer zugelassen ist (Admin oder nicht-gesperrter Redakteur), Anfrage nicht sperren
if (self::isUserAllowed()) {
return;
}
Expand All @@ -186,77 +212,103 @@ public static function checkFrontend(): void
$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 */
$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::addon()->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::addon()->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::addon()->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::addon()->getConfig($key, $default);
}

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