<?php

/**
 * Plugin Name: WTB Firewall
 * Description: WordPress firewall plugin with IP blocking, country rules, brute-force protection and proxy support to secure your site.
 * Version: 1.1.4
 * Requires at least: 6.0
 * Requires PHP: 8.1
 * Author: WTB Plugins
 * License: GPLv2 or later
 * License URI: https://www.gnu.org/licenses/gpl-2.0.html 
 */
if (!defined('ABSPATH')) {
    exit;
}

add_filter('cron_schedules', 'wtbFirewallCronSchedules');

define('WTB_FIREWALL_PATH', plugin_dir_path(__FILE__));
define('WTB_FIREWALL_VERSION', '1.1.4');
//WTB_FIREWALL_UPLOAD_PATH settes av wtbFirewallLoad() funksjonen.

register_activation_hook(__FILE__, 'wtb_firewall_install');
add_action('plugins_loaded', 'wtbFirewallLoad');

register_deactivation_hook(__FILE__, 'wtb_firewall_on_deactivate');

add_action('wtb_firewall_create_auto_rules', 'wtbFirewallCreateAutoRules');
add_action('wtb_firewall_create_country_rules', 'wtbFirewallCreateCountryRules');
add_action('wtb_firewall_daily_cleanup', 'wtbFirewallDailyCleanUp');
add_action('wtb_firewall_log_import', 'wtbFirewallLogImport');

/**
 * Sjekk om vi er i admin mode.
 */
if (is_admin()) {
    require_once WTB_FIREWALL_PATH . 'Admin/AdminMain.php';

    new \WtbFirewall\Admin\AdminMain();
}

/**
 * Inkluder delen for å håndtere automatisk beskyttelse.
 */
require_once WTB_FIREWALL_PATH . 'AutoProtect/AutoProtectMain.php';
new \WtbFirewall\AutoProtect\AutoProtectMain();

/**
 * Inkluder delen for å håndtere rate limiting og 404 monitor.
 */
require_once WTB_FIREWALL_PATH . 'RateLimit/RateLimit.php';
new \WtbFirewall\RateLimit\RateLimit();

/**
 * For WTB Firewall Pro.
 */
do_action('wtb_firewall_ready');

function wtb_firewall_install() {
    global $wpdb;

    //Tabell for firewall regler.  
    $sqlRulesTable = '
    CREATE TABLE ' . $wpdb->prefix . 'wtb_firewall_ips (
      id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
      enabled TINYINT UNSIGNED NOT NULL DEFAULT 1,
      ipv4_start INT UNSIGNED DEFAULT NULL,
      ipv4_end INT UNSIGNED DEFAULT NULL,
      ipv6 VARBINARY(16) DEFAULT NULL,
      ipv6_prefix TINYINT UNSIGNED DEFAULT NULL,
      action TINYINT UNSIGNED NOT NULL,
      type TINYINT UNSIGNED NOT NULL,
      source TINYINT UNSIGNED NOT NULL,
      description VARCHAR(255) DEFAULT NULL,
      date_created DATETIME NOT NULL,
      date_expires DATETIME DEFAULT NULL,
      date_updated DATETIME DEFAULT NULL,
      created_by VARCHAR(60) NOT NULL,
      hits BIGINT UNSIGNED NOT NULL DEFAULT 0,
      date_last_hit DATETIME DEFAULT NULL,
      PRIMARY KEY  (id),
      KEY index_enabled (enabled),
      KEY index_type (type)      
    )' . $wpdb->get_charset_collate() . ';';

    $sqlLogTable = '
    CREATE TABLE ' . $wpdb->prefix . 'wtb_firewall_log (
      id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
      rule_id BIGINT UNSIGNED DEFAULT NULL,      
      event_time DATETIME NOT NULL,
      event_type TINYINT UNSIGNED NOT NULL,
      ipv4 INT UNSIGNED DEFAULT NULL,
      ipv6 VARBINARY(16) DEFAULT NULL,
      details TEXT DEFAULT NULL,      
      PRIMARY KEY  (id),
      KEY index_event_type (event_type),
      KEY index_event_time (event_time)
    )' . $wpdb->get_charset_collate() . ';';

    $sqlEventsTable = '            
    CREATE TABLE ' . $wpdb->prefix . 'wtb_firewall_events (
      id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,      
      event_time DATETIME NOT NULL,
      event_type TINYINT UNSIGNED NOT NULL,
      ipv4 INT UNSIGNED DEFAULT NULL, 
      ipv6 VARBINARY(16) DEFAULT NULL,
      PRIMARY KEY  (id),
      KEY idx_ip_type_time (ipv4, event_type, event_time)      
    )' . $wpdb->get_charset_collate() . ';';

    $sqlRateCountersTable = '            
    CREATE TABLE ' . $wpdb->prefix . 'wtb_firewall_rate_counters (
      ip VARBINARY(16) NOT NULL,
      time_window INT UNSIGNED NOT NULL,
      counter INT UNSIGNED NOT NULL DEFAULT 1,
      counter_type TINYINT UNSIGNED NOT NULL,        
      PRIMARY KEY  (ip, time_window, counter_type),
      KEY idx_time_window (time_window)      
    )' . $wpdb->get_charset_collate() . ';';
    
    $sqlTrafficLogTable = '
    CREATE TABLE ' . $wpdb->prefix . 'wtb_firewall_traffic_log (
      id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
      ip VARBINARY(16) NOT NULL,
      event_time DATETIME NOT NULL,
      method VARCHAR(10) NOT NULL DEFAULT \'\',
      path VARCHAR(512) NOT NULL DEFAULT \'\',
      path_hash BINARY(16) NOT NULL,
      status_code SMALLINT UNSIGNED NOT NULL DEFAULT 0,
      user_agent VARCHAR(512) NOT NULL DEFAULT \'\',
      user_agent_hash BINARY(16) DEFAULT NULL,
      referer VARCHAR(512) NOT NULL DEFAULT \'\',
      PRIMARY KEY  (id),
      KEY idx_event_time (event_time),
      KEY idx_ip_event_time (ip, event_time),
      KEY idx_path_hash_event_time (path_hash, event_time)      
    ) ' . $wpdb->get_charset_collate() . ';';

    require_once ABSPATH . 'wp-admin/includes/upgrade.php';
    dbDelta($sqlRulesTable);
    dbDelta($sqlLogTable);
    dbDelta($sqlEventsTable);
    dbDelta($sqlRateCountersTable);
    dbDelta($sqlTrafficLogTable);

    //Dersom firewall allerede er installert .htaccess eller .user.ini
    //installer firewall på nytt og lag regel filene på nytt.
    //Slik at de er oppdatert til nyeste versjon.
    require_once WTB_FIREWALL_PATH . 'Admin/Includes.php';
    $firewall = new \WtbFirewall\Firewall\Firewall();

    if ($firewall->isInstalled()) {
        $firewall->installFirewall();
    }

    //Legg inn daglig wp-cron vedlikehold oppgave.
    if (!wp_next_scheduled('wtb_firewall_daily_cleanup')) {
        $first_run = time() + HOUR_IN_SECONDS;
        wp_schedule_event($first_run, 'daily', 'wtb_firewall_daily_cleanup');
    }

    //Legg inn wp-cron for å importere log fil.
    if (!wp_next_scheduled('wtb_firewall_log_import')) {
        $first_run = time() + 600;
        wp_schedule_event($first_run, 'wtb_firewall_10min', 'wtb_firewall_log_import');
    }

    //Opprett  uploads/wtb-firewall folder.
    wtbFirewallCreateUploadDir();

    //Hold orden på hvilken versjon av plugin vi bruker.
    update_option('wtb_firewall_version', WTB_FIREWALL_VERSION);
}

/**
 * Kalles ved  plugins_loaded
 *  
 */
function wtbFirewallLoad() {
    //Sett WTB_FIREWALL_UPLOAD_PATH til uploads/wtb-firewall
    if (defined('WTB_FIREWALL_UPLOAD_PATH')) {
        return;
    }

    $uploads = wp_upload_dir();

    if (!empty($uploads['error']) || empty($uploads['basedir'])) {
        return;
    }

    define(
            'WTB_FIREWALL_UPLOAD_PATH',
            trailingslashit($uploads['basedir']) . 'wtb-firewall/'
    );

    //Sjekk om vi har installert ny versjon.
    $installedVer = get_option('wtb_firewall_version');

    if ($installedVer !== WTB_FIREWALL_VERSION) {
        wtb_firewall_install();
    }
}

/**
 * Når plugin deaktiveres, fjerner firewall og alle relaterte filer.
 */
function wtb_firewall_on_deactivate() {
    $firewall = new \WtbFirewall\Firewall\Firewall();

    if ($firewall->isInstalled()) {
        $firewall->removeFirewall();
    }

    //Fjern wp-cron jobb for daglig vedlikehold.    
    wp_clear_scheduled_hook('wtb_firewall_daily_cleanup');

    //Fjern wp-cron jobb for å importere log fil.
    wp_clear_scheduled_hook('wtb_firewall_log_import');
}

/**
 * Kalles fra wp-cron for å lage filen for automatiske firewall regler.
 */
function wtbFirewallCreateAutoRules() {
    require_once WTB_FIREWALL_PATH . 'Admin/Includes.php';

    $firewall = new \WtbFirewall\Firewall\Firewall();
    $firewall->writeAutoRulesToFile();
}

/**
 * Kalles fra wp-cron for å lage firewall regel filene for land.
 */
function wtbFirewallCreateCountryRules() {
    require_once WTB_FIREWALL_PATH . 'Admin/Includes.php';

    $firewall = new \WtbFirewall\Firewall\Firewall();
    $firewall->writeCountryRulesToFile();
}

/**
 * Kalles fra wp-cron daglig for å utføre vedlikehold.
 */
function wtbFirewallDailyCleanUp() {
    require_once WTB_FIREWALL_PATH . 'Admin/Includes.php';
    require_once WTB_FIREWALL_PATH . 'AutoProtect/Includes.php';
    require_once WTB_FIREWALL_PATH . 'RateLimit/Includes.php';

    \WtbFirewall\Config\FirewallConfig::loadOptions();

    //Tøm logger.
    $log = new \WtbFirewall\Firewall\Log();
    $log->deleteLogEntries(\WtbFirewall\Config\FirewallConfig::$logDays);

    $autoProtectLog = new \WtbFirewall\AutoProtect\AutoProtectLog();
    $autoProtectLog->authenticateClearLog();
    
    $rateLimitLog = new \WtbFirewall\RateLimit\RateLimitLog();
    $rateLimitLog->rateLimitClearLog();

    //Slett automatiske regler utgått på dato.
    $firewall = new \WtbFirewall\Firewall\Firewall();
    $firewall->autoRulesCleanup();

    //Fjern eventuelle manuellle regler utgått på dato.
    $firewall->checkTemporaryRules();
}

/**
 * Kalles fra wp-cron for å importere log fil fra prepend scriptet.
 */
function wtbFirewallLogImport() {
    require_once WTB_FIREWALL_PATH . 'Admin/Includes.php';

    \WtbFirewall\Config\FirewallConfig::loadOptions();

    $log = new \WtbFirewall\Firewall\Log();
    $log->importLogFile(WTB_FIREWALL_UPLOAD_PATH . 'firewall_blocked.log');
}

/**
 * Oppretter uploads/wtb-firewall
 * Samt legger inn .htaccess og index.php for å hindre visning av innholdet.
 *
 * @return bool True hvis OK, False hvis feil.
 */
function wtbFirewallCreateUploadDir() {

    $uploads = wp_upload_dir();

    if (!empty($uploads['error']) || empty($uploads['basedir'])) {
        return false;
    }

    $dir = trailingslashit($uploads['basedir']) . 'wtb-firewall/';

    if (!is_dir($dir)) {
        if (!wp_mkdir_p($dir)) {
            return false;
        }
    }

    $index_file = $dir . 'index.php';
    $htaccess_file = $dir . '.htaccess';

    if (!file_exists($index_file)) {
        $result = file_put_contents(
                $index_file,
                "<?php\n// Silence is golden.\n",
                LOCK_EX
        );

        if (false === $result) {
            return false;
        }
    }

    if (!file_exists($htaccess_file)) {
        $result = file_put_contents(
                $htaccess_file,
                "Require all denied\n",
                LOCK_EX
        );

        if (false === $result) {
            return false;
        }
    }

    return true;
}

/**
 * Registrerer wp-cron intervaller brukt at WTB Firewall.
 */
function wtbFirewallCronSchedules($schedules) {

    $schedules['wtb_firewall_10min'] = [
        'interval' => 600,
        'display' => __('Every 10 Minutes', 'wtb-firewall')
    ];

    return $schedules;
}
