GhostManSec
Server: LiteSpeed
System: Linux premium197.web-hosting.com 4.18.0-553.54.1.lve.el8.x86_64 #1 SMP Wed Jun 4 13:01:13 UTC 2025 x86_64
User: parhudrw (1725)
PHP: 7.4.33
Disabled: NONE
Upload Files
File: //home/parhudrw/alicreates.com/wp-content/plugins/microsoft-clarity/clarity-page.php
<?php

/*******************************************************************************
 * File with Clarity page
 *******************************************************************************/

// Handle Brand Agent remove from waitlist success callback - use add_action to ensure WordPress is loaded
add_action( 'init', 'brandagent_handle_remove_from_waitlist_success_callback', 1 );
function brandagent_handle_remove_from_waitlist_success_callback() {
    if ( isset( $_GET['brandagent_remove_from_waitlist_success'] ) && $_GET['brandagent_remove_from_waitlist_success'] == '1' ) {
        brandagent_log( 'BrandAgent: Received remove from waitlist success callback' );

        // Verify HMAC signature from request headers
        $client_id = isset( $_SERVER['HTTP_X_WOOCOMMERCE_CLIENT_ID'] ) 
            ? sanitize_text_field( $_SERVER['HTTP_X_WOOCOMMERCE_CLIENT_ID'] ) 
            : '';
        $timestamp = isset( $_SERVER['HTTP_X_WOOCOMMERCE_TIMESTAMP'] ) 
            ? sanitize_text_field( $_SERVER['HTTP_X_WOOCOMMERCE_TIMESTAMP'] ) 
            : '';
        $signature = isset( $_SERVER['HTTP_X_WOOCOMMERCE_SIGNATURE'] ) 
            ? sanitize_text_field( $_SERVER['HTTP_X_WOOCOMMERCE_SIGNATURE'] ) 
            : '';

        // Validate required headers are present
        if ( empty( $client_id ) || empty( $timestamp ) || empty( $signature ) ) {
            brandagent_log( 'BrandAgent: Remove from waitlist callback missing required HMAC headers' );
            header( 'Content-Type: application/json' );
            http_response_code( 401 );
            echo json_encode( array( 'success' => false, 'error' => 'Missing authentication headers' ) );
            exit;
        }

        // Validate timestamp (5-minute window for replay attack prevention)
        $time_difference = abs( time() - intval( $timestamp ) );
        if ( $time_difference > 300 ) {
            brandagent_log( 'BrandAgent: Remove from waitlist callback timestamp too old: ' . $time_difference . ' seconds' );
            header( 'Content-Type: application/json' );
            http_response_code( 401 );
            echo json_encode( array( 'success' => false, 'error' => 'Request timestamp expired' ) );
            exit;
        }

        // Get the stored HMAC secret and verify signature
        $secret_key = brandagent_get_hmac_secret();
        if ( ! $secret_key ) {
            brandagent_log( 'BrandAgent: Remove from waitlist callback - no HMAC secret stored' );
            header( 'Content-Type: application/json' );
            http_response_code( 401 );
            echo json_encode( array( 'success' => false, 'error' => 'HMAC secret not found' ) );
            exit;
        }

        // Compute expected signature: message = clientId + timestamp
        $expected_signature = brandagent_generate_hmac_signature( $client_id, $timestamp, $secret_key );

        // Constant-time comparison to prevent timing attacks
        if ( ! hash_equals( $expected_signature, $signature ) ) {
            brandagent_log( 'BrandAgent: Remove from waitlist callback HMAC signature verification failed' );
            header( 'Content-Type: application/json' );
            http_response_code( 401 );
            echo json_encode( array( 'success' => false, 'error' => 'Invalid signature' ) );
            exit;
        }

        brandagent_log( 'BrandAgent: Remove from waitlist callback HMAC signature verified successfully' );

        delete_option( 'BAOauthSuccess' );
        delete_option( 'BAInjectFrontendScript' );
        brandagent_delete_hmac_secret();

        // Try to delete webhooks immediately if WooCommerce is available
        $deleted_immediately = false;
        if ( class_exists( 'WooCommerce' ) && class_exists( 'BrandAgent_Webhooks' ) ) {
            $deleted_count = BrandAgent_Webhooks::delete_all_brandagent_webhooks();
            brandagent_log( 'BrandAgent: Deleted ' . $deleted_count . ' webhook(s) immediately' );
            $deleted_immediately = true;
        }

        // If WooCommerce not loaded, set transient for later deletion
        if ( ! $deleted_immediately ) {
            set_transient( 'brandagent_pending_webhook_deletion', true, 3600 );
            brandagent_log( 'BrandAgent: Set pending webhook deletion transient (WooCommerce not loaded)' );
        }

        header( 'Content-Type: application/json' );
        echo json_encode( array( 'success' => true ) );
        exit;
    }
}

// Handle WooCommerce OAuth return URL (browser redirect after user authorizes).
// Deferred to 'init' so that wp_remote_post() and the HTTP API are fully loaded.
add_action( 'init', 'brandagent_handle_oauth_callback', 1 );
function brandagent_handle_oauth_callback() {
    if ( ! isset($_GET['brandagent_callback']) || $_GET['brandagent_callback'] != '1' ) {
        return;
    }

    $oauth_token = isset($_GET['oauth_token']) ? sanitize_text_field($_GET['oauth_token']) : '';

    // WooCommerce adds success=1 to the return URL when the callback was successful
    $wc_success = isset($_GET['success']) && $_GET['success'] == '1';
    $success = false;

    if ($wc_success && !empty($oauth_token)) {
        // Pull the HMAC secret from Clarity server (server-to-server, secret in response body)
        if ( ! class_exists( 'BrandAgent_Config' ) ) {
            $config_path = plugin_dir_path( __FILE__ ) . 'includes/brandagent-config.php';
            if ( file_exists( $config_path ) ) {
                require_once $config_path;
            } else {
                brandagent_log( 'BrandAgent OAuth: ERROR - Config file not found at ' . $config_path );
            }
        }

        $clarity_server_url = BrandAgent_Config::get_clarity_server_url();
        $fetch_url = $clarity_server_url . '/woocommerce/fetch-secret';

        $request_body = wp_json_encode( array( 'oauth_token' => $oauth_token ) );

        $response = wp_remote_post( $fetch_url, array(
            'timeout' => 15,
            'headers' => array( 'Content-Type' => 'application/json' ),
            'body'    => $request_body,
        ) );

        if ( is_wp_error( $response ) ) {
            brandagent_log( 'BrandAgent OAuth: ERROR - wp_remote_post failed: ' . $response->get_error_message() );
        } else {
            $status_code = wp_remote_retrieve_response_code( $response );
            $response_body = wp_remote_retrieve_body( $response );

            if ( $status_code === 200 ) {
                $body = json_decode( $response_body, true );
                if ( json_last_error() !== JSON_ERROR_NONE ) {
                    brandagent_log( 'BrandAgent OAuth: ERROR - JSON parse failed: ' . json_last_error_msg() );
                } elseif ( isset( $body['success'] ) && $body['success'] === true && ! empty( $body['hmac_secret'] ) ) {
                    brandagent_store_hmac_secret( $body['hmac_secret'] );
                    update_option( 'BAOauthSuccess', true );
                    $success = true;
                    brandagent_log( 'BrandAgent OAuth: SUCCESS - HMAC secret stored, BAOauthSuccess set.' );
                } else {
                    brandagent_log( 'BrandAgent OAuth: ERROR - Unexpected response from fetch-secret' );
                }
            } else {
                brandagent_log( 'BrandAgent OAuth: ERROR - fetch-secret returned status ' . $status_code );
            }
        }
    } else {
        brandagent_log( 'BrandAgent OAuth: SKIPPED - wc_success=' . ($wc_success ? 'true' : 'false') . ', oauth_token=' . (!empty($oauth_token) ? 'present' : 'MISSING') );
    }

    ?>
    <!DOCTYPE html>
    <html>
        <body>
            <script>
                if (window.opener) {
                    <?php if ($success): ?>
                        window.opener.postMessage({
                            type: 'WOOCOMMERCE_OAUTH_SUCCESS'
                        }, '*');
                    <?php else: ?>
                        window.opener.postMessage({
                            type: 'WOOCOMMERCE_OAUTH_FAILURE'
                        }, '*');
                    <?php endif; ?>

                    setTimeout(function() {
                        window.close();
                    }, 100);
                }
            </script>
        </body>
    </html>
    <?php
    exit;
}

// Handle Brand Agent refresh credentials callback
add_action( 'init', 'brandagent_handle_refresh_credentials_callback', 1 );
function brandagent_handle_refresh_credentials_callback() {
    if ( ! isset( $_GET['brandagent_refresh_credentials'] ) || $_GET['brandagent_refresh_credentials'] != '1' ) {
        return;
    }

    $oauth_token = isset( $_GET['oauth_token'] ) ? sanitize_text_field( $_GET['oauth_token'] ) : '';
    $success = false;

    if ( ! empty( $oauth_token ) ) {
        // Ensure BrandAgent_Config is loaded
        if ( ! class_exists( 'BrandAgent_Config' ) ) {
            $config_path = plugin_dir_path( __FILE__ ) . 'includes/brandagent-config.php';
            if ( file_exists( $config_path ) ) {
                require_once $config_path;
            } else {
                brandagent_log( 'BrandAgent Refresh: ERROR - Config file not found at ' . $config_path );
            }
        }

        // Fetch the new HMAC secret from Clarity server using the opaque token
        $clarity_server_url = BrandAgent_Config::get_clarity_server_url();
        $fetch_url = $clarity_server_url . '/woocommerce/fetch-secret';

        $request_body = wp_json_encode( array( 'oauth_token' => $oauth_token ) );

        $response = wp_remote_post( $fetch_url, array(
            'timeout' => 15,
            'headers' => array( 'Content-Type' => 'application/json' ),
            'body'    => $request_body,
        ) );

        if ( is_wp_error( $response ) ) {
            brandagent_log( 'BrandAgent Refresh: ERROR - wp_remote_post failed: ' . $response->get_error_message() );
        } else {
            $status_code = wp_remote_retrieve_response_code( $response );
            $response_body = wp_remote_retrieve_body( $response );

            if ( $status_code === 200 ) {
                $body = json_decode( $response_body, true );
                if ( json_last_error() !== JSON_ERROR_NONE ) {
                    brandagent_log( 'BrandAgent Refresh: ERROR - JSON parse failed: ' . json_last_error_msg() );
                } elseif ( isset( $body['success'] ) && $body['success'] === true && ! empty( $body['hmac_secret'] ) ) {
                    brandagent_store_hmac_secret( $body['hmac_secret'] );
                    $success = true;
                    brandagent_log( 'BrandAgent Refresh: SUCCESS - New HMAC secret stored.' );
                } else {
                    brandagent_log( 'BrandAgent Refresh: ERROR - Unexpected response from fetch-secret' );
                }
            } else {
                brandagent_log( 'BrandAgent Refresh: ERROR - fetch-secret returned status ' . $status_code );
            }
        }
    } else {
        brandagent_log( 'BrandAgent Refresh: ERROR - Missing oauth_token parameter' );
    }

    header( 'Content-Type: application/json' );
    if ( $success ) {
        echo json_encode( array( 'success' => true ) );
    } else {
        http_response_code( 500 );
        echo json_encode( array( 'success' => false, 'error' => 'Failed to refresh credentials' ) );
    }
    exit;
}

function generate_wordpress_id_option_if_empty()
{
    $clarity_wp_site = get_option('clarity_wordpress_site_id');
    if (empty($clarity_wp_site)) {
        update_option('clarity_wordpress_site_id', wp_generate_uuid4());
    };
}

/**
 * generate a guid identifier for this wordpress site
 * runs in the callback of register_activation_hook, rerunning here for existing plugin which updated 
 **/
function refresh_wordpress_id_option()
{
    update_option('clarity_wordpress_site_id', wp_generate_uuid4());
}

/**
 * Detects whether this site is hosted on WordPress.com.
 **/
function clarity_is_wordpress_com_hosted()
{
    return defined('IS_WPCOM') && IS_WPCOM;
}

/**
 * Displays the embedded iframe in Clarity settings
 **/
function clarity_section_iframe_callback()
{
    $nonce = wp_create_nonce('wp_ajax_edit_clarity_project_id');

    $clarity_project_id_option = get_option(
        'clarity_project_id', /* option */
        clarity_project_id_default_value() /* default */
    );
    $clarity_wp_site = get_option(
        'clarity_wordpress_site_id' /* option */
        /* default */
    );

    $site_url = home_url();
    $hosting_type = clarity_is_wordpress_com_hosted() ? 'wpcom' : 'selfhosted';

    $clarity_domain = "https://clarity.microsoft.com/embed";

    $query_params = "?nonce=$nonce&integration=Wordpress&wpsite=$clarity_wp_site&siteurl=$site_url&hostingtype=$hosting_type";

    // set a QP if user is admin
    if (current_user_can('manage_options')) {
        $query_params = $query_params . "&WPAdmin=1";
    }

    // set a QP if user is WooCommerce plugin is active
    if (class_exists('woocommerce')) {
        $query_params = $query_params . "&WooCommerce=1";
    }

    // set a QP if permalink structure is plain (required for Brand Agent rewrite rules)
    if (get_option('permalink_structure') === '') {
        $query_params = $query_params . "&PlainPermalink=1";
    }

    // Add flag to indicate Brand Agent integration is supported (0.10.21+)
    // If this flag is missing, iframe knows user is on an older version
    $query_params = $query_params . "&BrandAgentSupported=1";

    // initially set iframe src to the new users path
    $iframe_src = $clarity_domain . $query_params;

    // clarity project exist
    if (!empty($clarity_project_id_option)) {
        $iframe_src = $iframe_src . "&project=" . $clarity_project_id_option;
    }

    // Support deep-linking to specific pages in the embedded Clarity dashboard
    if (isset($_GET['iframeRedirect']) && !empty($_GET['iframeRedirect'])) {
        $iframe_redirect = sanitize_text_field($_GET['iframeRedirect']);
        $iframe_src = $iframe_src . "&iframeRedirect=" . rawurlencode($iframe_redirect);
    }

?>
    <div style="width:100%;height:100vh;padding-right:15px;margin-top:0px;box-sizing:border-box;">
        <iframe sandbox="allow-modals allow-forms allow-scripts allow-same-origin allow-popups allow-storage-access-by-user-activation" src="<?php echo $iframe_src ?>" width="100%" height="100%" title="Microsoft Clarity" />
    </div>
<?php
}

/**
 * clarity project id default value is empty string
 **/
function clarity_project_id_default_value()
{
    return '';
}

/**
 * Generates a menu page
 **/

add_action('admin_menu', 'clarity_page_generation');
function clarity_page_generation()
{
    add_menu_page(
        'microsoft-clarity', /* $page_title */
        'Clarity', /* menu_title */
        'edit_posts', /* capability */
        'microsoft-clarity', /* menu_slug */
        'clarity_section_iframe_callback', /* callback */
        'https://claritystatic.blob.core.windows.net/images/logo.svg', /* icon_url */
        99 /* position */
    );
}

/**
 * Register Plugin settings
 * clarity_project_id: option for currently integrated Clarity project id
 * clarity_wordpress_site_id: a guid generated by the Clarity plugin to uniquely identify this wordpress site
 * clarity_section_iframe_callback: part of the settings page in which the iframe is embedded
 * BAOauthSuccess: option for checking if brand agent oauth was successful
 **/
add_action('admin_init', 'clarity_register_settings');
function clarity_register_settings()
{
    register_setting(
        'clarity_settings_fields', /* $option_group */
        'clarity_project_id' /* option_name */
        /* args */
    );
    register_setting(
        'general', /* $option_group */
        'clarity_wordpress_site_id' /* option_name */
        /* args */
    );
    register_setting(
        'general', /* $option_group */
        'BAOauthSuccess' /* option_name */
        /* args */
    );
}

/** 
 * Notice for when wordpress admins did not finish intalling Clarity
 * did not integrate a project
 */
add_action('admin_notices', 'setup_clarity_notice__info');
function setup_clarity_notice__info()
{
    global $pagenow;
    $url = get_admin_url() . 'admin.php?page=microsoft-clarity';

    $learnMoreUrl = 'https://wordpress.org/plugins/microsoft-clarity/';

    $clarity_project_id_option = get_option(
        'clarity_project_id', /* option */
        clarity_project_id_default_value() /* default */
    );
    $pageQPExists = isset($_GET['page']);
    if ($pageQPExists) {
        $pageQP =  $_GET['page'];
    } else {
        $pageQP = "";
    }


    if (empty($clarity_project_id_option) && $pageQP !== "microsoft-clarity" && current_user_can("manage_options")) {
        echo
        '<div class="notice notice-info is-dismissible">
            <p style="font-weight:700">
                Unlock User Insights with Microsoft Clarity!
            </p>
            <p style="font-weight:500">
                Almost there! Start tracking user behavior on your site with Microsoft Clarity. See exactly where on your site users click, scroll, and get stuck. It takes just a few moments to set up.
            </p>
            <p>
                <a class="button-primary" href="' . $url . '">
                    Setup Clarity
                </a>
                <a class="button-primary" style="margin-left:10px" href="' . $learnMoreUrl . '">
                    Learn more
                </a>
            </p>
        </div>';
    }
}

/**
 * Add js function to listen to message on all admin pages
 * These message contain changes to integrated Clarity project
 * remove - change - add new
 */
add_action('admin_enqueue_scripts', 'add_event_listeners');
function add_event_listeners($hook)
{
    $pageQPExists = isset($_GET['page']);
    if ($pageQPExists) {
        $pageQP =  $_GET['page'];
    } else {
        $pageQP = "";
    }

    if ($pageQP !== "microsoft-clarity") {
        return;
    }

    if (!current_user_can("edit_posts")) {
        return;
    }

    wp_register_script(
        'window_listeners_js', /* handle */
        plugins_url('js\add_window_listeners.js', __FILE__), /* src */
        array(), /* deps  */
        false, /* ver  */
        false /* in_footer */
    );
    wp_enqueue_script(
        'window_listeners_js' /* handle */
        /* src */
        /* deps  */
        /* ver  */
        /* in_footer */
    );
}

/**
 * Add callback triggered when a new message is received
 * Edits the clarity project id option respectively
 */
add_action('wp_ajax_edit_clarity_project_id', "edit_clarity_project_id");
function edit_clarity_project_id()
{
    $new_value = $_POST['new_value'];
    $nonce = $_POST['nonce'];
    if (!wp_verify_nonce($nonce, "wp_ajax_edit_clarity_project_id")) {
        die(json_encode(
                array(
                    'success' => false,
                    'message' => 'Invalid nonce.',
                )
            ));
    }
    // only admins are allowed to edit the Clarity project id
    if (!current_user_can('manage_options')) {
        die(json_encode(
                array(
                    'success' => false,
                    'message' => 'User must be WordPress admin.'
                )
            ));
    } else {
        update_option(
            'clarity_project_id', /* option */
            $new_value /* value */
            /* autoload */
        );
        die(json_encode(
                array(
                    'success' => true,
                    'message' => 'Clarity project updated successfully.'
                )
            ));
    }
}

/**
 * Add callback triggered when a new message is received
 * Edits the agent enabled status option respectively
 */
add_action('wp_ajax_edit_agent_enabled_status', "edit_agent_enabled_status");
function edit_agent_enabled_status()
{
    $new_value = $_POST['new_value'];
    $nonce = $_POST['nonce'];
    if (!wp_verify_nonce($nonce, "wp_ajax_edit_clarity_project_id")) {
        die(json_encode(
                array(
                    'success' => false,
                    'message' => 'Invalid nonce.',
                )
            ));
    }
    // only admins are allowed to edit the Clarity project id
    if (!current_user_can('manage_options')) {
        die(json_encode(
                array(
                    'success' => false,
                    'message' => 'User must be WordPress admin.'
                )
            ));
    } else {
        update_option(
            'BAOauthSuccess', /* option */
            $new_value /* value */
            /* autoload */
        );
        die(json_encode(
                array(
                    'success' => true,
                    'message' => 'Agent enabled status updated successfully.'
                )
            ));
    }
}

/**
 * Displays an admin notice if the plugin version installed is not the latest
 */
add_action('admin_notices', 'plugin_update_notice');
function plugin_update_notice()
{
    // Only show the notice to users who can update plugins
    if (! current_user_can('update_plugins')) {
        return;
    }

    $is_latest_version = get_transient('clarity_is_latest_plugin_version');
    if ($is_latest_version !== '0') {
        return;
    }

    $plugin_slug = 'microsoft-clarity/clarity.php';
    $update_url = wp_nonce_url(
        add_query_arg(
            array(
                'action'       => 'trigger_plugin_update',
                'plugin'       => urlencode($plugin_slug),
            ),
            admin_url('admin.php')
        ),
        'plugin_update_nonce'
    );

?>
    <div class="notice notice-warning is-dismissible">
        <p style="font-weight:700">
            <?php _e('A new version of Microsoft Clarity is available.', 'text-domain'); ?>
        </p>
        <p>
            <a href="<?php echo esc_url($update_url); ?>" class="button button-primary">
                <?php _e('Update Now', 'text-domain'); ?>
            </a>
        </p>
    </div>
<?php
}

/**
 * Updates the plugin to the latest version programmatically
 * The upgrade function deactives the plugin by default before the upgrade, hence the need to reactivate it
 */
add_action('admin_action_trigger_plugin_update', 'plugin_perform_update');
function plugin_perform_update()
{
    if (! current_user_can('update_plugins')) {
        wp_die(__('You do not have sufficient permissions to update plugins.', 'text-domain'));
    }

    if (! isset($_GET['plugin']) || ! isset($_GET['_wpnonce'])) {
        return;
    }

    $plugin_slug = sanitize_text_field(urldecode($_GET['plugin']));

    if (! wp_verify_nonce($_GET['_wpnonce'], 'plugin_update_nonce')) {
        wp_die(__('Nonce verification failed.', 'text-domain'));
    }

    include_once(ABSPATH . 'wp-admin/includes/class-wp-upgrader.php');
    include_once(ABSPATH . 'wp-admin/includes/plugin.php');

    // Create a custom skin to handle output and redirection
    $upgrader_skin = new Automatic_Upgrader_Skin();
    $upgrader      = new Plugin_Upgrader($upgrader_skin);

    // Perform the update
    $updated = $upgrader->upgrade($plugin_slug);

    if (is_wp_error($updated) || ! $updated) {
        // Handle error: redirect back to admin page with an error notice 
        $redirect_url = add_query_arg('plugin_update_error', '1', admin_url('plugins.php'));
        wp_redirect(esc_url($redirect_url));
        exit;
    } else {
        // Success: redirect back to the plugin page with a success notice
        activate_plugin($plugin_slug);
        $redirect_url = add_query_arg('plugin_updated', '1', admin_url('admin.php?page=microsoft-clarity'));
        wp_redirect(esc_url($redirect_url));
        exit;
    }
}

/**
 * Display an admin notice with the status of the plugin update
 */
add_action('admin_notices', 'plugin_admin_notices');
function plugin_admin_notices()
{
    if (isset($_GET['plugin_updated']) && '1' === $_GET['plugin_updated']) {
        echo
        '<div class="notice notice-success is-dismissible">
            <p><strong>Microsoft Clarity plugin has been updated successfully.</strong></p>
        </div>';
    } else if (isset($_GET['plugin_update_error']) && '1' === $_GET['plugin_update_error']) {
        echo
        '<div class="notice notice-error is-dismissible">
            <p><strong>Microsoft Clarity plugin update failed.</strong></p>
        </div>';
    }
}