<?php

/**
 * The public-facing functionality of the plugin.
 *
 * @link       https://wpiron.com
 * @since      1.0.0
 *
 * @package    iron-security
 * @subpackage iron-security/public
 */

/**
 * The public-facing functionality of the plugin.
 *
 * Defines the plugin name, version, and two examples hooks for how to
 * enqueue the public-facing stylesheet and JavaScript.
 *
 * @package    iron-security
 * @subpackage iron-security/public
 * @author     WPIron <info@wpiron.com>
 */
class iron_securi_Public {

	private $plugin_name;
	private $version;

	public function __construct( $plugin_name, $version ) {
		$this->plugin_name = $plugin_name;
		$this->version     = $version;
	}

	public function wpironis_init() {
		$options = get_option( 'wpironis_options', array() );

		$xmlrcapi = $options['wpironis_disable_xmlrpc'] ?? null;

		if ( isset( $xmlrcapi ) && $xmlrcapi === 1 && defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {
			wp_die( 'XML-RPC is disabled.', 'XML-RPC Disabled', [ 'response' => 403 ] );
		}

		if ( isset( $options['wpironis_hide_wp_version'] ) && $options['wpironis_hide_wp_version'] === 1 ) {
			$this->wpironis_hide_wp_version();
		}

		$this->wpironis_add_security_headers();
	}

	public function wpironis_hide_wp_version() {
		remove_action( 'wp_head', 'wp_generator' );
		add_filter( 'the_generator', '__return_empty_string' );
		add_filter( 'style_loader_src', array( $this, 'wpironis_remove_version_from_source' ), 9999 );
		add_filter( 'script_loader_src', array( $this, 'wpironis_remove_version_from_source' ), 9999 );
	}

	public function wpironis_remove_version_from_source( $src ) {
		if ( strpos( $src, 'ver=' ) ) {
			$src = remove_query_arg( 'ver', $src );
		}

		return $src;
	}

	public function disable_xmlrpc() {
		return false;
	}

	public function wpironis_enqueue_styles() {
		wp_enqueue_style( $this->plugin_name,
			plugin_dir_url( __FILE__ ) . 'css/iron-security-public.css',
			array(),
			$this->version,
			'all' );
	}

	public function wpironis_enqueue_scripts() {
		wp_enqueue_script( $this->plugin_name,
			plugin_dir_url( __FILE__ ) . 'js/iron-security-public.js',
			array( 'jquery' ),
			$this->version,
			false );
	}

	public function wpironis_xmlrpc_enabled() {
		$options = get_option( 'wpironis_options', array() );

		if ( isset( $options['wpironis_disable_xmlrpc'] ) || $options['wpironis_disable_xmlrpc'] === 1 ) {
			return true;
		}

		return false;
	}

	public function wpironis_add_security_headers() {
		if ( headers_sent() ) {
			return;
		}

		$options = get_option( 'wpironis_options', array() );

		if ( isset( $options['wpironis_security_header_content_type_options'] ) && $options['wpironis_security_header_content_type_options'] === 1 ) {
			header( 'X-Content-Type-Options: nosniff' );
		}

		if ( isset( $options['wpironis_security_header_frame_options'] ) && $options['wpironis_security_header_frame_options'] === 1 ) {
			header( 'X-Frame-Options: SAMEORIGIN' );
		}

		if ( isset( $options['wpironis_security_header_xss_protection'] ) && $options['wpironis_security_header_xss_protection'] === 1 ) {
			header( 'X-XSS-Protection: 1; mode=block' );
		}

		if ( isset( $options['wpironis_security_header_strict_transport_security'] ) && $options['wpironis_security_header_strict_transport_security'] === 1 ) {
			header( 'Strict-Transport-Security: max-age=31536000; includeSubDomains' );
		}

		if ( isset( $options['wpironis_security_header_referrer_policy'] ) && $options['wpironis_security_header_referrer_policy'] === 1 ) {
			header( 'Referrer-Policy: strict-origin-when-cross-origin' );
		}

		if ( isset( $options['wpironis_security_header_content_security_policy'] ) && $options['wpironis_security_header_content_security_policy'] === 1 ) {
			$csp = "default-src 'self'; " .
			       "script-src 'self' 'unsafe-inline' 'unsafe-eval' *.wordpress.org *.wp.com *.googletagmanager.com *.google-analytics.com cdnjs.cloudflare.com cdn.jsdelivr.net; " .
			       "style-src 'self' 'unsafe-inline' *.wp.com fonts.googleapis.com cdn.jsdelivr.net; " .
			       "img-src 'self' data: *.wp.com *.wordpress.org *.gravatar.com *.google-analytics.com; " .
			       "font-src 'self' fonts.gstatic.com cdn.jsdelivr.net; " .
			       "frame-src 'self' www.youtube.com player.vimeo.com www.google.com;";
			header( "Content-Security-Policy: " . $csp );
		}

		if ( isset( $options['wpironis_security_header_permissions_policy'] ) && $options['wpironis_security_header_permissions_policy'] === 1 ) {
			header( 'Permissions-Policy: geolocation=(), microphone=(), camera=()' );
		}
	}

	public function wpironis_restrict_rest_api( $access ) {
		$options = get_option( 'wpironis_options', array() );

		if (
			! empty( $options['wpironis_disable_rest_api'] ) &&
			$options['wpironis_disable_rest_api'] === 1 &&
			! is_user_logged_in()
		) {
			$current_route = $GLOBALS['wp']->query_vars['rest_route'] ?? '';

			$allowed_routes = apply_filters( 'wpironis_rest_allowed_routes', array(
				'jwt-auth',
				'contact-form-7',
				'wc-analytics',
				'wc/store',
//				'/wp/v2/categories',
//				'/wp/v2/tags',
			) );

			foreach ( $allowed_routes as $allowed ) {
				if ( strpos( $current_route, $allowed ) !== false ) {
					return $access;
				}
			}

			$sensitive_routes = apply_filters( 'wpironis_rest_sensitive_routes', array(
				'/wp/v2/users',
				'/wp/v2/users/me',
				'/wp/v2/settings',
				'/wp/v2/plugins',
				'/wp/v2/themes',
				'/wp/v2/media',
				'/wp/v2/posts'    => array( 'methods' => array( 'POST', 'GET', 'PUT', 'PATCH', 'DELETE' ) ),
				'/wp/v2/pages'    => array( 'methods' => array( 'POST', 'GET', 'PUT', 'PATCH', 'DELETE' ) ),
				'/wp/v2/comments' => array( 'methods' => array( 'POST', 'GET', 'PUT', 'PATCH', 'DELETE' ) )
			) );

			if ( isset( $sensitive_routes[ $current_route ] ) ) {
				$route_config = $sensitive_routes[ $current_route ];

				if ( is_array( $route_config ) && isset( $route_config['methods'] ) ) {
					$current_method = $_SERVER['REQUEST_METHOD'];
					if ( in_array( $current_method, $route_config['methods'] ) ) {
						return $this->api_access_denied();
					}

					return $access;
				}

				return $this->api_access_denied();
			}

			foreach ( $sensitive_routes as $restricted => $config ) {
				if ( is_array( $config ) ) {
					continue;
				}

				if ( strpos( $current_route, $restricted ) === 0 ) {
					return $this->api_access_denied();
				}
			}
		}

		return $access;
	}

	private function api_access_denied() {
		return new WP_Error(
			'rest_api_restricted',
			__( 'Access to this REST API endpoint is restricted.', 'iron-security' ),
			array( 'status' => rest_authorization_required_code() )
		);
	}

	public function wpironis_disable_rest_endpoints( $endpoints ) {
		$options = get_option( 'wpironis_options', array() );

		if (
			! empty( $options['wpironis_disable_rest_api'] ) &&
			$options['wpironis_disable_rest_api'] === 1 && ! is_user_logged_in()
		) {
			$sensitive_endpoints = apply_filters( 'wpironis_hidden_rest_endpoints', array(
				'/wp/v2/users',
				'/wp/v2/users/(?P<id>[\d]+)',
				'/wp/v2/plugins',
				'/wp/v2/themes',
			) );

			foreach ( $sensitive_endpoints as $endpoint ) {
				if ( isset( $endpoints[ $endpoint ] ) ) {
					unset( $endpoints[ $endpoint ] );
				}
			}
		}

		return $endpoints;
	}

}
