layout_tools(); if ( ! $layout_tools instanceof Divi_Powers_Layout_Tools ) { return false; } define( 'DIVI_POWERS_CONNECTION_NATIVE', true ); define( 'FIVED_SITE_BRIDGE_VERSION', DIVI_POWERS_VERSION ); define( 'FIVED_SITE_BRIDGE_FILE', DIVI_POWERS_FILE ); define( 'FIVED_SITE_BRIDGE_DIR', DIVI_POWERS_PATH . 'includes/connection/' ); define( 'FIVED_SITE_BRIDGE_BASENAME', plugin_basename( DIVI_POWERS_FILE ) ); foreach ( array( 'class-fived-site-bridge-db.php', 'class-fived-site-bridge-settings.php', 'class-fived-site-bridge-oauth.php', 'class-fived-site-bridge-transport.php', 'class-fived-site-bridge.php', 'class-divi-powers-free-remote-connector.php', ) as $file ) { require_once FIVED_SITE_BRIDGE_DIR . $file; } FiveD_Site_Bridge_Settings::install_defaults(); ( new Divi_Powers_Free_Remote_Connector( $plugin, $layout_tools ) )->register(); FiveD_Site_Bridge::instance(); self::$owner = true; update_option( 'divi_powers_connection_owner', 'free', false ); return true; } /** Restore a previously approved bearer identity before user-bound hooks. */ public static function authenticate_mcp_before_init() { if ( ! self::$owner || ! self::is_mcp_http_request() ) { return; } $settings = get_option( FiveD_Site_Bridge_Settings::OPTION, array() ); if ( ! is_array( $settings ) || empty( $settings['customer_connection_enabled'] ) || 'standalone' !== ( $settings['transport_mode'] ?? '' ) ) { return; } $header = isset( $_SERVER['HTTP_AUTHORIZATION'] ) ? (string) $_SERVER['HTTP_AUTHORIZATION'] : (string) ( $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ?? '' ); if ( ! preg_match( '/^Bearer\s+(.+)$/i', $header, $matches ) ) { return; } $token = trim( $matches[1] ); if ( '' === $token ) { return; } $grant = self::validate_compatible_oauth_token( $token ); if ( ! $grant ) { return; } $request = new WP_REST_Request( isset( $_SERVER['REQUEST_METHOD'] ) ? (string) $_SERVER['REQUEST_METHOD'] : 'POST', '/mcp/v1/http' ); $request->set_header( 'authorization', $header ); $allowed = (bool) apply_filters( 'fived_mcp_oauth_grant_can_access', user_can( $grant['user_id'], 'manage_options' ), $grant, $request ); if ( $allowed ) { wp_set_current_user( $grant['user_id'] ); } } /** @return bool */ private static function is_mcp_http_request() { if ( 'POST' !== strtoupper( (string) ( $_SERVER['REQUEST_METHOD'] ?? '' ) ) ) { return false; } if ( isset( $_GET['rest_route'] ) ) { return '/mcp/v1/http' === '/' . trim( (string) wp_unslash( $_GET['rest_route'] ), '/' ); } $request_path = isset( $_SERVER['REQUEST_URI'] ) ? wp_parse_url( (string) $_SERVER['REQUEST_URI'], PHP_URL_PATH ) : ''; $endpoint_path = wp_parse_url( rest_url( 'mcp/v1/http' ), PHP_URL_PATH ); return is_string( $request_path ) && is_string( $endpoint_path ) && untrailingslashit( $request_path ) === untrailingslashit( $endpoint_path ); } /** Read an existing approved token without changing the grant. */ private static function validate_compatible_oauth_token( $token ) { global $wpdb; $hash = hash( 'sha256', (string) $token ); foreach ( array( 'fived_mcp_oauth_tokens', 'mwai_mcp_oauth_tokens' ) as $suffix ) { $table = $wpdb->prefix . $suffix; if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) ) !== $table ) { continue; } $row = $wpdb->get_row( $wpdb->prepare( 'SELECT id, user_id, client_id, access_expires, revoked FROM %i WHERE access_token_hash = %s AND revoked <> 1 LIMIT 1', $table, $hash ), ARRAY_A ); if ( ! $row ) { continue; } $expires = strtotime( $row['access_expires'] . ' UTC' ); if ( false === $expires || $expires < time() ) { return null; } return array( 'user_id' => (int) $row['user_id'], 'client_id' => (string) $row['client_id'] ); } return null; } /** Tell admins how to finish the legacy one-plugin migration. */ public static function legacy_connector_notice() { if ( current_user_can( 'activate_plugins' ) ) { echo '

' . esc_html__( 'The ChatGPT site connection is now included in 5D Powers for Divi. The separate AI Connector currently owns this connection; deactivate it when ready to let Free take over on the next request. Saved settings and approved connections will remain.', '5d-powers-for-divi' ) . '

'; } } /** Avoid loading competing classes while the rollback bridge is activated. */ private static function is_rollback_activation_request() { if ( ! is_admin() ) { return false; } $action = isset( $_REQUEST['action'] ) ? sanitize_key( wp_unslash( $_REQUEST['action'] ) ) : ''; $rollback = '5d-site-bridge/5d-site-bridge.php'; if ( 'activate' === $action ) { $plugin = isset( $_REQUEST['plugin'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['plugin'] ) ) : ''; return $rollback === $plugin; } if ( 'activate-selected' !== $action || empty( $_REQUEST['checked'] ) || ! is_array( $_REQUEST['checked'] ) ) { return false; } return in_array( $rollback, array_map( 'sanitize_text_field', wp_unslash( $_REQUEST['checked'] ) ), true ); } }