Plugin Directory

Changeset 3490060


Ignore:
Timestamp:
03/24/2026 01:35:27 PM (12 days ago)
Author:
vinsmach
Message:

Version 1.3.0: remove sensitive data, add global rate limiting

Location:
webmcp-bridge/trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • webmcp-bridge/trunk/admin/class-admin.php

    r3489235 r3490060  
    4545            'enable_woo'    => ! empty( $input['enable_woo'] )    ? 1 : 0,
    4646            'enable_nav'    => ! empty( $input['enable_nav'] )    ? 1 : 0,
     47            'rate_limit'    => max( 10, min( 1000, (int) ( $input['rate_limit']  ?? 120 ) ) ),
     48            'rate_window'   => max( 10, min( 3600, (int) ( $input['rate_window'] ?? 60  ) ) ),
    4749        ];
    4850    }
     
    150152                            </tr>
    151153                        </table>
     154                        <!-- Rate limiting -->
     155                        <tr>
     156                            <th scope="row"><?php esc_html_e( 'Rate limit (calls)', 'webmcp-bridge' ); ?></th>
     157                            <td>
     158                                <input type="number" name="webmcp_bridge_options[rate_limit]" min="10" max="1000"
     159                                    value="<?php echo esc_attr( $options['rate_limit'] ?? 120 ); ?>" style="width:80px">
     160                                <p class="description"><?php esc_html_e( 'Max /execute calls allowed in the time window (global, not per-IP). Default: 120.', 'webmcp-bridge' ); ?></p>
     161                            </td>
     162                        </tr>
     163                        <tr>
     164                            <th scope="row"><?php esc_html_e( 'Rate window (seconds)', 'webmcp-bridge' ); ?></th>
     165                            <td>
     166                                <input type="number" name="webmcp_bridge_options[rate_window]" min="10" max="3600"
     167                                    value="<?php echo esc_attr( $options['rate_window'] ?? 60 ); ?>" style="width:80px">
     168                                <p class="description"><?php esc_html_e( 'Time window in seconds for the rate limit counter. Default: 60.', 'webmcp-bridge' ); ?></p>
     169                            </td>
     170                        </tr>
    152171                        <?php submit_button( esc_html__( 'Save Settings', 'webmcp-bridge' ), 'primary' ); ?>
    153172                    </form>
  • webmcp-bridge/trunk/includes/class-rest-api.php

    r3489235 r3490060  
    1818
    1919    /**
     20     * Global rate limit for /execute endpoint.
     21     *
     22     * Why global and not per-IP?
     23     * Per-IP limits are trivially bypassed with proxy rotation.
     24     * A global counter limits the total server load regardless of source.
     25     * The window and limit are filterable for sites with different needs.
     26     *
     27     * Defaults: 120 execute calls per 60 seconds across ALL visitors.
     28     * Adjust via filters: webmcp_bridge_rate_limit and webmcp_bridge_rate_window.
     29     */
     30    private function check_global_rate_limit(): bool {
     31        $opts   = get_option( 'webmcp_bridge_options', [] );
     32        $limit  = (int) apply_filters( 'webmcp_bridge_rate_limit',  $opts['rate_limit']  ?? 120 ); // max calls
     33        $window = (int) apply_filters( 'webmcp_bridge_rate_window', $opts['rate_window'] ?? 60  ); // seconds
     34        $key    = 'webmcp_bridge_rate_' . gmdate( 'YmdHi' ) . '_' . (int) floor( gmdate( 's' ) / $window );
     35
     36        $count = (int) get_transient( $key );
     37        if ( $count >= $limit ) {
     38            return false; // rate limit exceeded
     39        }
     40
     41        // Increment atomically via transient (best-effort — not a strict semaphore,
     42        // but sufficient to throttle aggressive automated traffic)
     43        set_transient( $key, $count + 1, $window * 2 );
     44        return true;
     45    }
     46
     47    /**
    2048     * Tools that require a logged-in user or a valid WP REST nonce to execute.
    2149     * Filterable via webmcp_bridge_protected_tools so other plugins can extend the list.
     
    108136
    109137    public function execute_tool( WP_REST_Request $request ) {
     138        // Global rate limit — checked before any processing.
     139        if ( ! $this->check_global_rate_limit() ) {
     140            return new WP_Error(
     141                'rate_limited',
     142                'Too many requests. Please slow down.',
     143                [ 'status' => 429 ]
     144            );
     145        }
     146
    110147        // Tool name is already sanitized by the 'sanitize_callback' arg above.
    111148        $tool_name = $request->get_param( 'tool' );
  • webmcp-bridge/trunk/includes/class-tools-core.php

    r3489235 r3490060  
    9191
    9292        // -------------------------------------------------------------------------
    93         // Enhanced tools — only available when Mescio for Agents plugin is active.
    94         // We check the specific classes used, not just the main class, so these
    95         // tools are safely skipped if Mescio is present but in an unexpected state.
     93        // Enhanced tools — only when Mescio for Agents plugin is active.
    9694        // -------------------------------------------------------------------------
    9795        if ( class_exists( 'Mescio_For_Agents_Markdown' ) && class_exists( 'Mescio_For_Agents_Rest' ) ) {
     
    173171            'type'    => $post->post_type,
    174172            'date'    => $post->post_date,
    175             'author'  => get_the_author_meta( 'display_name', $post->post_author ),
     173            // Note: author display_name intentionally omitted — not needed by agents
     174            // and exposes internal user information.
    176175        ];
    177176    }
     
    216215    public function tool_get_site_info( $params ) {
    217216        return [
    218             'name'        => get_bloginfo( 'name' ),
    219             'description' => get_bloginfo( 'description' ),
    220             'url'         => get_home_url(),
    221             'admin_email' => get_bloginfo( 'admin_email' ),
    222             'language'    => get_bloginfo( 'language' ),
    223             'wp_version'  => get_bloginfo( 'version' ),
     217            'name'              => get_bloginfo( 'name' ),
     218            'description'       => get_bloginfo( 'description' ),
     219            'url'               => get_home_url(),
     220            'language'          => get_bloginfo( 'language' ),
     221            'wp_version'        => get_bloginfo( 'version' ),
     222            // admin_email intentionally omitted — sensitive data, not needed by agents.
    224223            'mescio_for_agents' => class_exists( 'Mescio_For_Agents' ),
    225224        ];
     
    248247
    249248    public function tool_get_markdown_content( $params ) {
    250         // Guard on the specific Mescio classes actually used — keeps the two plugins decoupled.
    251249        if ( ! class_exists( 'Mescio_For_Agents_Markdown' ) ) {
    252250            throw new Exception( 'Mescio for Agents plugin is not active or is outdated (Mescio_For_Agents_Markdown missing).' );
     
    271269        }
    272270
    273         // Mescio_For_Agents_Markdown::post_to_markdown( WP_Post ): string
    274271        $markdown = Mescio_For_Agents_Markdown::post_to_markdown( $post );
    275272
    276         // Mescio_For_Agents_I18n::detect_post_language( WP_Post ): string — graceful fallback if missing
    277273        $language = class_exists( 'Mescio_For_Agents_I18n' )
    278274            ? Mescio_For_Agents_I18n::detect_post_language( $post )
    279275            : get_bloginfo( 'language' );
    280276
    281         // Mescio_For_Agents_Markdown::estimate_tokens( string ): int — use real estimate if available
    282277        $tokens = method_exists( 'Mescio_For_Agents_Markdown', 'estimate_tokens' )
    283278            ? Mescio_For_Agents_Markdown::estimate_tokens( $markdown )
     
    297292
    298293    public function tool_get_llms_txt( $params ) {
    299         // Guard on the specific Mescio REST class.
    300294        if ( ! class_exists( 'Mescio_For_Agents_Rest' ) ) {
    301295            throw new Exception( 'Mescio for Agents plugin is not active or is outdated (Mescio_For_Agents_Rest missing).' );
    302296        }
    303297
    304         $variant = strtolower( sanitize_key( $params['variant'] ?? 'index' ) );
    305 
    306         // Mescio_For_Agents_Rest::context_callback( WP_REST_Request ): WP_REST_Response
     298        $variant  = strtolower( sanitize_key( $params['variant'] ?? 'index' ) );
    307299        $response = Mescio_For_Agents_Rest::context_callback( new WP_REST_Request( 'GET' ) );
    308300        $context  = $response->get_data();
     
    313305            }
    314306
    315             // Mescio_For_Agents_Llms::build_full(): string — pure PHP, no HTTP loopback
    316307            $body = Mescio_For_Agents_Llms::build_full();
    317308
  • webmcp-bridge/trunk/readme.txt

    r3489247 r3490060  
    11=== WebMCP Bridge ===
    2 Contributors: vinsmach
     2Contributors: vinsmach, mescio
    33Tags: ai, mcp, webmcp, ai-agent, woocommerce
    44Requires at least: 6.0
    55Tested up to: 6.9
    6 Stable tag: 1.2.0
     6Stable tag: 1.3.0
    77Requires PHP: 8.0
    88License: GPLv2 or later
  • webmcp-bridge/trunk/webmcp-bridge.php

    r3489235 r3490060  
    44 * Plugin URI:        https://wordpress.org/plugins/webmcp-bridge/
    55 * Description:       Exposes WordPress functionality as WebMCP tools so AI agents can interact with your site natively in the browser — no backend MCP server required.
    6  * Version:           1.2.0
     6 * Version:           1.3.0
    77 * Requires at least: 6.0
    88 * Requires PHP:      8.0
     
    1717if ( ! defined( 'ABSPATH' ) ) exit;
    1818
    19 define( 'WEBMCP_BRIDGE_VERSION', '1.2.0' );
     19define( 'WEBMCP_BRIDGE_VERSION', '1.3.0' );
    2020define( 'WEBMCP_BRIDGE_DIR', plugin_dir_path( __FILE__ ) );
    2121define( 'WEBMCP_BRIDGE_URL', plugin_dir_url( __FILE__ ) );
Note: See TracChangeset for help on using the changeset viewer.