<?php

namespace CleantalkSP\SpbctWP\Firewall;

/*
 * The abstract class for any FireWall modules.
 * Compatible with any CMS.
 *
 * @version       1.0
 * @author        Cleantalk team (welcome@cleantalk.org)
 * @copyright (C) 2014 CleanTalk team (http://cleantalk.org)
 * @license       GNU/GPL: http://www.gnu.org/copyleft/gpl.html
 * @since 2.49
 */

use CleantalkSP\SpbctWP\Escape;
use CleantalkSP\Variables\Get;
use CleantalkSP\Variables\Server;
use CleantalkSP\Security\Firewall\Result;

class FirewallModule extends \CleantalkSP\Security\Firewall\FirewallModule
{
    public $result;

    /**
     * Real IP address (user's actual IP, not test IP)
     * @var string|null
     */
    public $real_ip;

    /**
     * FireWall_module constructor.
     * Use this method to prepare any data for the module working.
     *
     * @param array $params
     */
    public function __construct($params = array())
    {
        $this->die_page__file = file_exists(
            __DIR__ . DIRECTORY_SEPARATOR . 'die_page_' . strtolower($this->module_name) . '.html'
        )
            ? __DIR__ . DIRECTORY_SEPARATOR . 'die_page_' . strtolower($this->module_name) . '.html'
            : null;

        parent::__construct($params);
    }

    /**
     * Shows DIE page.
     * Stops script executing.
     *
     * @param Result $result
     */
    public function _die(Result $result) // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore
    {
        global $spbc;

        // Common actions for all modules
        parent::_die($result);

        /**
         * Use something like that to set a cookie before die (useful for cache 403 errors).
         *
         * add_action('spbct_firewall_before_die', function ($_result){
         *  if ( ! headers_sent() ) {
         *    $cookie_name = 'spbc_firewall_die';
         *    $cookie_value = '1';
         *    $cookie_expiration = time() + 3600; // 1 hour
         *    $cookie_path = '/';
         *    setcookie($cookie_name, $cookie_value, $cookie_expiration, $cookie_path);
         *  }
         * });
         */
        do_action('spbct_firewall_before_die', $result);

        // Adding block reason
        switch ( $result->status ) {
            case 'DENY':
                $reason = __('Blacklisted', 'security-malware-firewall');
                break;
            case 'DENY_BY_NETWORK':
                $reason = __('Hazardous network', 'security-malware-firewall');
                break;
            case 'DENY_BY_DOS':
                $reason = __('Blocked by Traffic Control', 'security-malware-firewall');
                break;
            case 'DENY_BY_WAF_XSS':
                $reason = __('Blocked by Web Application Firewall: XSS attack detected.', 'security-malware-firewall');
                break;
            case 'DENY_BY_WAF_SQL':
                $reason = __(
                    'Blocked by Web Application Firewall: SQL-injection detected.',
                    'security-malware-firewall'
                );
                break;
            case 'DENY_BY_WAF_EXPLOIT':
                $reason = __('Blocked by Web Application Firewall: Exploit detected.', 'security-malware-firewall');
                break;
            case 'DENY_BY_WAF_FILE':
                $reason = __(
                    'Blocked by Upload Checker module: Malicious files upload: ',
                    'security-malware-firewall'
                );
                $reason .= isset($result->pattern['file_path']) ? $result->pattern['file_path'] : '';
                break;
            case 'DENY_BY_BFP':
                $reason = __('Blocked by BruteForce Protection: Too many invalid logins.', 'security-malware-firewall');
                break;
            case 'DENY_BY_WAF_BLOCKER':
                $reason = __('Blocked for 24 hours by Web Application Firewall: several attacks detected in a row', 'security-malware-firewall');
                break;
            case 'PASS_BY_TRUSTED_NETWORK':
                $reason = __('Pass by trusted network', 'security-malware-firewall');
                break;
            case 'PASS_BY_WHITELIST':
                $reason = __('Pass by whitelisted', 'security-malware-firewall');
                break;
            case 'PASS_AS_SKIPPED_NETWORK':
                $reason = __('Pass by skipped network', 'security-malware-firewall');
                break;
            case 'PASS':
                $reason = __('Passed by common lists', 'security-malware-firewall');
                break;
            default:
                $reason = __('Blacklisted', 'security-malware-firewall');
                break;
        }

        if ( $result->is_personal ) {
            $reason .= ' ' . esc_html__('by Personal Lists', 'security-malware-firewall');
        }

        if ( $this->die_page__file ) {
            $die_page_template = file_get_contents($this->die_page__file);

            $allowed_html = array(
                'h1' => array(),
                'h2' => array(),
                'h3' => array(),
                'h4' => array(),
                'h5' => array(),
                'p' => array(),
                'br' => array(),
                'a' => array(
                    'href'  => true,
                )
            );

            // Check if this is test mode
            $is_test_mode = (bool) Get::getString('spbct_test');
            $test_ip = esc_html(Get::getString('spbct_test_ip'));

            // Translation
            $replaces = array(
                '{TITLE}'                  => __('Blocked: ' . $spbc->data["wl_brandname"], 'security-malware-firewall'),
                '{CUSTOM_MESSAGE}'         => isset($this->state->settings['fw__custom_message']) ? Escape::escKses(
                    $this->state->settings['fw__custom_message'],
                    $allowed_html
                ) : '',
                '{TEST_TITLE}'             => Get::getString('spbct_test')
                    ? __('This is the testing page for Security FireWall', 'security-malware-firewall')
                    : '',
                '{TEST_INFO_DISPLAY}'      => $is_test_mode ? 'block' : 'none',
                '{REAL_IP}'                => $this->real_ip ?: __('Unknown', 'security-malware-firewall'),
                '{TEST_IP}'                => $test_ip ?: __('Not specified', 'security-malware-firewall'),
                '{REASON}'                 => $reason,
                '{GENERATED_TIMESTAMP}'    => time(),
                '{FALSE_POSITIVE_WARNING}' => __(
                    'Maybe you\'ve been blocked by a mistake. Please refresh the page (press CTRL + F5) or try again later.',
                    'security-malware-firewall'
                ),

                '{REMOTE_ADDRESS}' => $is_test_mode && $test_ip ? $test_ip : $result->ip,
                '{SERVICE_ID}'     => isset($this->state->data['service_id']) ? $this->state->data['service_id'] : '',
                '{HOST}'           => Server::getString('HTTP_HOST'),
                '{GENERATED}'      => sprintf(
                    '<h2 class="second">%s %s (%s)</h2>',
                    __('The page was generated on', 'security-malware-firewall'),
                    esc_html(date("l, F j, Y H:i:s")),
                    esc_html(spbc_wp_timezone_string())
                ),
                '{BRANDNAME}'      => $spbc->data["wl_brandname"],
                '{CLEANTALK_URL}'  => esc_url($spbc->data['wl_url']),
            );

            foreach ( $replaces as $place_holder => $replace ) {
                $die_page_template = str_replace($place_holder, $replace, $die_page_template);
            }
            if ( ! headers_sent() ) {
                http_response_code(403);
            }
            die($die_page_template);
        }

        if ( ! headers_sent() ) {
            http_response_code(403);
        }
        die("IP BLACKLISTED. Blocked by Security Firewall " . $result->ip);
    }
}
