Plugin Directory

Changeset 3400142


Ignore:
Timestamp:
11/21/2025 02:47:14 AM (4 months ago)
Author:
writetextai
Message:

hotfix

Location:
writetext-ai
Files:
258 added
8 edited

Legend:

Unmodified
Added
Removed
  • writetext-ai/trunk/CHANGELOG.md

    r3391599 r3400142  
    99The format is based on [Keep a Changelog](http://keepachangelog.com/)
    1010and this project adheres to [Semantic Versioning](http://semver.org/).
     11
     12## [3.5.10] - 2025-11-21
     13
     14### Changed
     15
     16– Update the rest endpoint rate limit expiration date and time checking.
    1117
    1218## [3.5.9] - 2025-11-07
  • writetext-ai/trunk/assets/js/admin-common.js

    r3391655 r3400142  
    1010);
    1111
    12 console.log('WriteText.ai - Version: [3.5.9] - 2025-11-07 - 3');
     12console.log('WriteText.ai - Version: [3.5.10] - 2025-11-21 - 1');
    1313
    1414jQuery( document ).ready( function( $ ){
  • writetext-ai/trunk/includes/class-wtai-product-dashboard.php

    r3391599 r3400142  
    83968396            if ( $set_welcome_banner ) {
    83978397                $current_version = wtai_get_version( true );
    8398                 // Remove the last character from the current version.
    8399                 $current_version      = substr( $current_version, 0, -2 );
     8398
     8399                $current_version_array = explode( '.', $current_version );
     8400                $current_version       = $current_version_array[0] . '.' . $current_version_array[1];
     8401
    84008402                $current_version_slug = str_replace( '.', '_', $current_version );
    84018403
  • writetext-ai/trunk/includes/class-wtai-rest.php

    r3391655 r3400142  
    218218        $do_logging = $this->is_logging_enabled();
    219219
     220        // Check rate limit.
     221        $rate_limit_check = $this->check_rate_limit();
     222        if ( is_wp_error( $rate_limit_check ) ) {
     223            return $rate_limit_check;
     224        }
     225
    220226        // Get Authorization header.
    221227        $auth_header = $request->get_header( 'Authorization' );
     
    326332        if ( ! is_ssl() && ! wtai_is_development_environment() ) {
    327333            return new WP_Error( 'wtai_https_required', 'HTTPS required for API access.', array( 'status' => 403 ) );
    328         }
    329 
    330         // Check rate limit.
    331         $rate_limit_check = $this->check_rate_limit( $consumer_key );
    332         if ( is_wp_error( $rate_limit_check ) ) {
    333             return $rate_limit_check;
    334334        }
    335335
     
    431431    /**
    432432     * Check rate limit
    433      *
    434      * @param string $consumer_key Consumer key.
    435      */
    436     private function check_rate_limit( $consumer_key ) {
     433     */
     434    private function check_rate_limit() {
    437435        $rate_limit_per_hour = apply_filters( 'wtai_rest_api_rate_limit_per_hour', 10000 ); // 10000 requests per hour by default.
    438436
    439         $transient_key = 'wtai_rest_api_rate_limit_' . md5( $consumer_key );
    440         $requests      = intval( get_transient( $transient_key ) );
    441 
    442         if ( $requests > $rate_limit_per_hour ) {
    443             return new WP_Error( 'wtai_rate_limit_exceeded', 'Rate limit exceeded.', array( 'status' => 429 ) );
    444         }
    445 
    446         set_transient( $transient_key, $requests + 1, HOUR_IN_SECONDS );
     437        // Validate the rate limit value - ensure it's a positive integer.
     438        $rate_limit_per_hour = absint( $rate_limit_per_hour );
     439        if ( $rate_limit_per_hour <= 0 ) {
     440            // Fallback to default if filter returns invalid value.
     441            $rate_limit_per_hour = 10000;
     442        }
     443
     444        // Get client IP address.
     445        $client_ip = $this->get_client_ip();
     446
     447        $transient_key = 'wtai_rest_api_rate_limit_' . md5( $client_ip );
     448
     449        // Calculate fixed expiration for current hour (prevents sliding window issue).
     450        $current_time          = time();
     451        $current_hour          = floor( $current_time / 3600 ); // Which hour are we in?
     452        $expiration_time       = ( $current_hour + 1 ) * 3600; // Expires at start of next hour.
     453        $time_until_expiration = $expiration_time - $current_time;
     454
     455        // Get current count.
     456        $requests = get_transient( $transient_key );
     457
     458        // Check if we're in a new time bucket (transient expired or different bucket).
     459        $transient_timeout_key = '_transient_timeout_' . $transient_key;
     460        $existing_expiration   = get_option( $transient_timeout_key, 0 );
     461        $existing_expiration   = intval( $existing_expiration );
     462
     463        // If expired or in a new bucket, reset counter and clear old transient.
     464        if ( false === $requests || $existing_expiration < $current_time || $existing_expiration > $expiration_time ) {
     465            // Clear the expired transient value and timeout.
     466            if ( false !== $requests || $existing_expiration > 0 ) {
     467                delete_transient( $transient_key );
     468            }
     469            $requests = 0;
     470        } else {
     471            $requests = intval( $requests );
     472        }
     473
     474        // Debug logging.
     475        if ( $this->is_logging_enabled() ) {
     476            $this->log(
     477                'Rate limit check - Key: ' . substr( $consumer_key, -7 ) . ', Requests: ' . $requests . ', Limit: ' . $rate_limit_per_hour . ', Expires in: ' . round( $time_until_expiration / 60, 1 ) . ' minutes',
     478                $this->log_file
     479            );
     480        }
     481
     482        if ( $requests >= $rate_limit_per_hour ) {
     483            return new WP_Error(
     484                'wtai_rate_limit_exceeded',
     485                'Rate limit exceeded. Rate limit per hour is set to ' . $rate_limit_per_hour . ' requests.',
     486                array( 'status' => 429 )
     487            );
     488        }
     489
     490        // Create a unique request identifier to prevent double counting.
     491        // Use URI + method + consumer key + current second (less precise but more compatible).
     492        $request_uri    = isset( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
     493        $request_method = isset( $_SERVER['REQUEST_METHOD'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_METHOD'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
     494        $request_id     = md5( $client_ip . $request_uri . $request_method . $current_time );
     495
     496        // Use static variable to track if we've already incremented for this request.
     497        static $incremented_requests = array();
     498
     499        // Only increment once per unique request (within the same second).
     500        if ( ! isset( $incremented_requests[ $request_id ] ) ) {
     501            set_transient( $transient_key, $requests + 1, $time_until_expiration );
     502            $incremented_requests[ $request_id ] = true;
     503
     504            // Clean up old entries to prevent memory buildup (keep last 1000).
     505            if ( count( $incremented_requests ) > 1000 ) {
     506                $incremented_requests = array_slice( $incremented_requests, -500, null, true );
     507            }
     508        }
    447509
    448510        return true;
     
    16821744        return $is_valid_page;
    16831745    }
     1746
     1747    /**
     1748     * Get client IP address.
     1749     */
     1750    private function get_client_ip() {
     1751        $ip = isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : '';
     1752        if ( ! empty( $_SERVER['HTTP_CLIENT_IP'] ) ) {
     1753            $ip = isset( $_SERVER['HTTP_CLIENT_IP'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_CLIENT_IP'] ) ) : '';
     1754        } elseif ( ! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
     1755            $ip = isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) : '';
     1756        }
     1757        $ips = explode( ',', $ip );
     1758
     1759        return $ips[0];
     1760    }
    16841761}
    16851762
  • writetext-ai/trunk/includes/functions.php

    r3391599 r3400142  
    89948994    }
    89958995
    8996     // Remove the last character from the current version.
    8997     $current_version = substr( $current_version, 0, -2 );
     8996    $current_version_array = explode( '.', $current_version );
     8997    $current_version       = $current_version_array[0] . '.' . $current_version_array[1];
    89988998
    89998999    $current_version_slug = str_replace( '.', '_', $current_version );
  • writetext-ai/trunk/readme.txt

    r3393313 r3400142  
    44Requires at least: 6.0
    55Tested up to: 6.8.3
    6 Stable tag: 3.5.9
     6Stable tag: 3.5.10
    77Requires PHP: 7.4
    88License: GPLv3 or later
     
    198198
    199199== Changelog ==
     200
     201= 3.5.10 2025-11-21 =
     202
     203* Update – Update the rest endpoint rate limit expiration date and time checking.
    200204
    201205= 3.5.9 2025-11-07 =
     
    489493== Upgrade Notice ==
    490494
    491 = 3.5.9 =
     495= 3.5.10 =
    492496
    493497Please upgrade, to ensure all plugin features works as expected.
  • writetext-ai/trunk/templates/admin/install.php

    r3391599 r3400142  
    3434
    3535    $current_version = wtai_get_version( true );
    36     // Remove the last character from the current version.
    37     $current_version      = substr( $current_version, 0, -2 );
     36
     37    $current_version_array = explode( '.', $current_version );
     38    $current_version       = $current_version_array[0] . '.' . $current_version_array[1];
     39
    3840    $current_version_slug = str_replace( '.', '_', $current_version );
    3941
  • writetext-ai/trunk/writetext-ai.php

    r3391599 r3400142  
    44 * Plugin URI: https://writetext.ai/woocommerce
    55 * Description: Let AI automatically generate product descriptions and other content from your product data.
    6  * Version: 3.5.9
     6 * Version: 3.5.10
    77 * Author:  1902 Software
    88 * Author URI: https://writetext.ai/
     
    5252
    5353    if ( ! defined( 'WTAI_VERSION' ) ) {
    54         define( 'WTAI_VERSION', '3.5.9' );
     54        define( 'WTAI_VERSION', '3.5.10' );
    5555    }
    5656
     
    360360        // Reset succeeding plugin flags.
    361361        $current_version = wtai_get_version( true );
    362         // Remove the last character from the current version.
    363         $current_version      = substr( $current_version, 0, -2 );
     362
     363        $current_version_array = explode( '.', $current_version );
     364        $current_version       = $current_version_array[0] . '.' . $current_version_array[1];
     365
    364366        $current_version_slug = str_replace( '.', '_', $current_version );
    365367
Note: See TracChangeset for help on using the changeset viewer.