HEX
Server: nginx
System: Linux pool195-106-36.bur.atomicsites.net 6.12.57+deb12-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.12.57-1~bpo12+1 (2025-11-17) x86_64
User: (0)
PHP: 8.3.32
Disabled: pcntl_fork
Upload Files
File: /wordpress/plugins/wp-cloud-client/beta/src/Access/LoginPageGuard.php
<?php

declare(strict_types=1);

namespace VPlugins\WPCloudClient\Access;

use VPlugins\WPCloudClient\Settings\SettingsRepository;

class LoginPageGuard {

	/**
	 * Login-page actions that must always reach native handling, even when the
	 * login page is hidden (logout, lost-password and reset-password flows).
	 *
	 * @var string[]
	 */
	private const ALLOWED_ACTIONS = [ 'logout', 'lostpassword', 'rp', 'resetpass' ];

	/**
	 * Construct the login page guard.
	 *
	 * @param SettingsRepository $settings Settings repository.
	 */
	public function __construct(
		private readonly SettingsRepository $settings,
	) {}

	/**
	 * Hooked to `init` and `login_init`. Redirects unauthenticated visitors
	 * away from wp-login.php when the login page is hidden.
	 *
	 * For production sites the redirect is governed by the manager's
	 * expose_login flag (set via set_login_visibility). Staging sites always
	 * redirect — they never receive a set_login_visibility call — using the
	 * stored login_redirect_url when available, or a URL built from the manager
	 * base URL + Vendasta site ID as a fallback. One-click login, logout and
	 * password-reset flows are always allowed through.
	 *
	 * @return void
	 */
	public function handle(): void {
		$pagenow = $GLOBALS['pagenow'] ?? basename( $_SERVER['PHP_SELF'] ?? '' );
		if ( 'wp-login.php' !== $pagenow ) {
			return;
		}

		// Authenticated users keep full access to the login page.
		if ( is_user_logged_in() ) {
			return;
		}

		$is_staging = $this->settings->isStaging();

		// For non-staging sites, respect the manager's expose_login flag.
		// Staging sites always redirect regardless of expose_login because
		// set_login_visibility is never called during staging site creation.
		if ( ! $is_staging && $this->settings->isLoginExposed() ) {
			return;
		}

		// One-click login (handled by LoginInterceptor on the same hook).
		if ( isset( $_GET['wpcc_login_token'] ) ) {
			return;
		}

		// Logout and password-reset flows must continue to work.
		$action = isset( $_REQUEST['action'] )
			? sanitize_key( wp_unslash( $_REQUEST['action'] ) )
			: '';
		if ( in_array( $action, self::ALLOWED_ACTIONS, true ) ) {
			return;
		}

		// Staging: derive portal URL directly from WSP_SITE_ENVIRONMENT + WSP_SITE_ID —
		// login_redirect_url is never stored in the DB for staging sites.
		// Non-staging: use the URL written by set_login_visibility, falling back to home.
		if ( $is_staging ) {
			$site_id = $this->settings->getVendastaSiteId();
			// Portal base URLs per environment — no WSP_PORTAL_URL constant is
			// available to the plugin for staging sites. These mirror
			// config.Env.WSPPortalURL on the manager side; update both if the
			// portal domain ever changes.
			$base   = 'DEMO' === $this->settings->getEnvironment()
				? 'https://websiteprodashboard-demo.com'
				: 'https://www.websiteprodashboard.com';
			$target = null !== $site_id
				? $base . '/redirect/wp-login/' . $site_id
				: home_url();
		} else {
			$target = $this->settings->getLoginRedirectUrl();
			if ( '' === $target ) {
				return;
			}
		}

		// External host, so wp_redirect (not wp_safe_redirect), matching the
		// bootstrapper's redirect to the Portal. esc_url_raw() guards against a
		// malformed or javascript:-scheme URL supplied by the manager.
		wp_redirect( esc_url_raw( $target ) );
		exit;
	}
}