<?php
if (!defined('ABSPATH')) {
	exit;//Exit if accessed directly
}

class AIOWPSecurity_Process_Renamed_Login_Page {

	public function __construct() {
		add_action('login_init', array($this, 'aiowps_login_init'));
		add_filter('site_url', array($this, 'aiowps_site_url'), 10, 2);
		add_filter('network_site_url', array($this, 'aiowps_site_url'), 10, 2);
		add_filter('wp_redirect', array($this, 'aiowps_wp_redirect'), 10, 2);
		add_filter('register', array($this, 'register_link'));
		add_filter('user_request_action_email_content', array($this, 'aiowps_user_request_email_content'), 10, 2);
		remove_action('template_redirect', 'wp_redirect_admin_locations', 1000); //To prevent redirect to login page when people type "login" at end of home URL

	}

	public function aiowps_login_init() {
		$parsed_request = isset($_SERVER['REQUEST_URI']) ? wp_parse_url(sanitize_url(wp_unslash($_SERVER['REQUEST_URI']))) : '';
		if ($parsed_request && preg_match('/wp-login\.php$/', $parsed_request['path'])) {
			AIOWPSecurity_Process_Renamed_Login_Page::aiowps_set_404();
		}
	}

	public function aiowps_site_url($url) {
		return $this->aiowps_filter_wp_login_file($url);
	}

	public function aiowps_wp_redirect($location) {
		return $this->aiowps_filter_wp_login_file($location);
	}

	/**
	 * Filter register link on the login page
	 *
	 * @param string $registration_url
	 * @return string
	 */
	public function register_link($registration_url) {
		return $this->aiowps_filter_wp_login_file($registration_url);
	}

	/**
	 * Filter confirm link so we hide the secret login slug in the export_personal_data email
	 *
	 * @param string $email_text
	 * @param string $email_data
	 * @return string
	 */
	public function aiowps_user_request_email_content($email_text, $email_data) {
		global $aio_wp_security;
		if (isset($email_data['request']) && isset($email_data['request']->action_name)) {
			if ('export_personal_data' == $email_data['request']->action_name) {
				$confirm_url = $email_data['confirm_url'];
				$login_slug = $aio_wp_security->configs->get_value('aiowps_login_page_slug');
				if (get_option('permalink_structure')) {
					$new_confirm_url = str_replace($login_slug, 'wp-login.php', $confirm_url);
				} else {
					$search_pattern = '?'.$login_slug.'&action';
					$new_confirm_url = str_replace($search_pattern, '/wp-login.php/?action', $confirm_url);
				}

				$email_text_modified = str_replace('###CONFIRM_URL###', esc_url_raw($new_confirm_url), $email_text);
				return $email_text_modified;
			}
		}
		return $email_text;
	}

	/**
	 * Filter all login url strings on the login page
	 *
	 * @param string $url
	 * @return string
	 */
	public function aiowps_filter_wp_login_file($url) {
		if (strpos($url, 'wp-login.php') !== false) {
			$args = explode('?', $url);
			if (isset($args[1])) {
				if (strpos($args[1], 'action=postpass') !== false) {
					return $url; //Don't reveal the secret URL in the post password action url
				}
				parse_str($args[1], $args);
				$url = esc_url(add_query_arg($args, AIOWPSecurity_Process_Renamed_Login_Page::new_login_url()));
				$url = html_entity_decode($url);
			} elseif (isset($_SERVER['REQUEST_URI']) && stripos(urldecode(sanitize_url(wp_unslash($_SERVER['REQUEST_URI']))), 'wp-admin/install.php')) {
				return $url;
			} else {
				$url = AIOWPSecurity_Process_Renamed_Login_Page::new_login_url();
			}
		}
		return $url;
	}

	/**
	 * Login page renamed related tasks, do not allow access if not logged with rename login page.
	 *
	 * @return void
	 */
	public static function renamed_login_init_tasks() {
		// Bail if the host cron job is running by running the command "php wp-cron.php"
		// The $_SERVER['REQUEST_URI'] is undefined when running a PHP file from the command line.
		// for `wp plugin list` it will be empty so showing Not available instead plugin list.
		if (empty($_SERVER['REQUEST_URI']) || defined('WP_CLI') || 'cli' == PHP_SAPI || wp_doing_cron() || wp_doing_ajax()) {
			return;
		}

		global $aio_wp_security;

		//The following will process the native wordpress post password protection form
		//Normally this is done by wp-login.php file but we cannot use that since the login page has been renamed
		
		// Bots with URLs like: /index.php?action[]=aaaa will return an array here. It needs to be a string.
		$action = (isset($_GET['action']) && is_string($_GET['action'])) ? sanitize_text_field(wp_unslash($_GET['action'])) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No nonce available.
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing -- No nonce available.
		if (isset($_POST['post_password']) && 'postpass' == $action) {

			// Check if the captcha is enabled for the password protected pages and process validation if the login page was renamed
			if ('1' == $aio_wp_security->configs->get_value('aiowps_enable_password_protected_captcha')) {
				$aio_wp_security->captcha_obj->validate_password_protected_password_form_with_captcha();
			}

			require_once ABSPATH . 'wp-includes/class-phpass.php';
			$hasher = new PasswordHash(8, true);

			/**
			 * Filter the life span of the post password cookie.
			 *
			 * By default, the cookie expires 10 days from creation. To turn this
			 * into a session cookie, return 0.
			 *
			 * @since 3.7.0
			 *
			 * @param int $expires The expiry time, as passed to setcookie().
			 */
			$expire = apply_filters('post_password_expires', time() + 10 * DAY_IN_SECONDS);
			// phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- No nonce available, not recommended to sanitize passwords.
			setcookie('wp-postpass_' . COOKIEHASH, $hasher->HashPassword(wp_unslash($_POST['post_password'])), $expire, COOKIEPATH, COOKIE_DOMAIN, is_ssl(), true);

			wp_safe_redirect(wp_get_referer());
			exit();
		}

		//case where someone attempting to reach wp-admin
		if (is_admin() && !is_user_logged_in() && (isset($_SERVER["SCRIPT_FILENAME"]) ? basename(sanitize_text_field(wp_unslash($_SERVER["SCRIPT_FILENAME"]))) : '') !== 'admin-post.php') {
			//Fix to prevent fatal error caused by some themes and Yoast SEO
			do_action('aiowps_before_wp_die_renamed_login');
			wp_die(esc_html__('You do not have permission to access this page.', 'all-in-one-wp-security-and-firewall') .  ' ' . esc_html__('Please log in and try again.', 'all-in-one-wp-security-and-firewall'), 403);
		}

		//case where someone attempting to reach wp-login
		if (isset($_SERVER['REQUEST_URI']) && stripos(urldecode(sanitize_url(wp_unslash($_SERVER['REQUEST_URI']))), 'wp-login.php') && !is_user_logged_in()) {

			// Handle export personal data request for rename login case
			if (isset($_GET['request_id'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce available.
				$request_id = (int) sanitize_text_field(wp_unslash($_GET['request_id'])); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce available.
				$result = '';
				if (isset($_GET['confirm_key'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce available.
					$key = sanitize_text_field(wp_unslash($_GET['confirm_key'])); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce available.
					$result = wp_validate_user_request_key($request_id, $key);
				} else {
					$result = new WP_Error('invalid_key', esc_html__('Invalid key', 'all-in-one-wp-security-and-firewall'));
				}

				if (is_wp_error($result)) {
					// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- PCP error. $result is WPError object with sanitized strings.
					wp_die($result);
				} elseif (!empty($result)) {
					_wp_privacy_account_request_confirmed($request_id);
					$message = _wp_privacy_account_request_confirmed_message($request_id);
					login_header(__('User action confirmed.', 'all-in-one-wp-security-and-firewall'), $message);
					login_footer();
					exit;
				}
			}

			//Check if the maintenance (lockout) mode is active - if so prevent access to site by not displaying 404 page!
			if ($aio_wp_security->configs->get_value('aiowps_site_lockout') == '1') {
				AIOWPSecurity_WP_Loaded_Tasks::site_lockout_tasks();
			} else {
				AIOWPSecurity_Process_Renamed_Login_Page::aiowps_set_404();
			}
		}

		//case where someone attempting to reach the standard register or signup pages
		$request_uri = urldecode(sanitize_url(wp_unslash($_SERVER['REQUEST_URI'])));
		if ('' !== $request_uri && stripos($request_uri, 'wp-register.php') || '' !== $request_uri && stripos($request_uri, 'wp-signup.php')) {
			//Check if the maintenance (lockout) mode is active - if so prevent access to site by not displaying 404 page!
			if ('1' == $aio_wp_security->configs->get_value('aiowps_site_lockout')) {
				AIOWPSecurity_WP_Loaded_Tasks::site_lockout_tasks();
			} else {
				AIOWPSecurity_Process_Renamed_Login_Page::aiowps_set_404();
			}
		}

		$login_slug = $aio_wp_security->configs->get_value('aiowps_login_page_slug');

		if (self::is_renamed_login_page_requested($login_slug)) {
			if (empty($action) && is_user_logged_in()) {
				//if user is already logged in but tries to access the renamed login page, send them to the dashboard
				// or to requested redirect-page, filtered in 'login_redirect'.
				if (isset($_REQUEST['redirect_to'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce available.
					$redirect_to = wp_sanitize_redirect(wp_unslash($_REQUEST['redirect_to'])); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce available.
					$redirect_to = wp_validate_redirect($redirect_to, apply_filters('wp_safe_redirect_fallback', admin_url(), 302));
					$requested_redirect_to = $redirect_to;
				} else {
					$redirect_to = admin_url();
					$requested_redirect_to = '';
				}
				$redirect_to = apply_filters('login_redirect', $redirect_to, $requested_redirect_to, wp_get_current_user());
				AIOWPSecurity_Utility::redirect_to_url($redirect_to);
			} else {
				global $wp_version;
				do_action('aiowps_rename_login_load');
				// logout action called by WooCommerce does not apply the login whitelist which shows a 403 error for the customer
				if (!(isset($_GET['action']) && 'logout' == $_GET['action'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce available.
					AIOWPSecurity_Utility_IP::check_login_whitelist_and_forbid();
				}

				status_header(200);
				if (version_compare($wp_version, '6.6', '>=')) {
					require_once(AIO_WP_SECURITY_PATH . '/other-includes/wp-security-rename-login-feature.php');
				} elseif (version_compare($wp_version, '5.7', '>=')) {
					require_once(AIO_WP_SECURITY_PATH . '/other-includes/wp-security-rename-login-feature-pre-6-6.php');
				} elseif (version_compare($wp_version, '5.2', '>=')) {
					require_once(AIO_WP_SECURITY_PATH . '/other-includes/wp-security-rename-login-feature-pre-5-7.php');
				} else {
					require_once(AIO_WP_SECURITY_PATH . '/other-includes/wp-security-rename-login-feature-pre-5-2.php');
				}

				die;
			}
		}
	}

	public static function new_login_url() {
		global $aio_wp_security;
		$login_slug = $aio_wp_security->configs->get_value('aiowps_login_page_slug');
		if (get_option('permalink_structure')) {
			return trailingslashit(trailingslashit(home_url()) . $login_slug);
		} else {
			return trailingslashit(site_url()) . '?' . $login_slug;
		}
	}

	public static function aiowps_set_404() {
		global $wp_query;
		do_action('aiowps_before_set_404'); // This hook is for themes which produce a fatal error when the rename login feature is enabled and someone visits "wp-admin" slug directly

		status_header(404);
		$wp_query->set_404();
		do_action('template_redirect'); // Trigger 'template_redirect' to allow third-party plugins to intercept and inject custom logic before rendering the fallback template.

		$template = get_404_template();
		if (empty($template)) $template = get_index_template();
		$template = apply_filters('template_include', $template);
		if ($template) include($template);
		die;
	}
	
	/**
	 * Check renamed login page is requested
	 *
	 * @param string $login_slug Renamed loginpage slug
	 *
	 * @return boolean
	 */
	public static function is_renamed_login_page_requested($login_slug) {
		
		if (empty($_SERVER['REQUEST_URI'])) return false;
	
		$parsed_url_path = isset($_SERVER['REQUEST_URI']) ? wp_parse_url(sanitize_url(wp_unslash($_SERVER['REQUEST_URI'])), PHP_URL_PATH) : '';
		
		if (empty($parsed_url_path)) return false;
		
		$home_url_with_slug = home_url($login_slug, 'relative');

		/*
		 * Compatibility fix for WPML, TranslatePress plugin
		 */
		if (function_exists('wpml_object_id') || function_exists('trp_enable_translatepress')) {
			$home_url_with_slug = home_url($login_slug);
			$parsed_home_url_with_slug = wp_parse_url($home_url_with_slug);
			$home_url_with_slug = $parsed_home_url_with_slug['path']; //this will return just the path minus the protocol and host
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- PCP warning. No nonce available.
		if (untrailingslashit($parsed_url_path) === $home_url_with_slug || (!get_option('permalink_structure') && isset($_GET[$login_slug]))) {
			return true;
		}
		
		return false;
	}

}
