query( $wpdb->prepare( "INSERT INTO {$wpdb->prefix}wc_rate_limits (`rate_limit_key`, `rate_limit_expiry`, `rate_limit_remaining`) VALUES (%s, %d, %d) ON DUPLICATE KEY UPDATE `rate_limit_id` = IF( `rate_limit_expiry` < %d OR `rate_limit_remaining` > 0, LAST_INSERT_ID(`rate_limit_id`), LAST_INSERT_ID(0) + `rate_limit_id` ), `rate_limit_remaining` = IF( `rate_limit_expiry` < %d, VALUES(`rate_limit_remaining`), IF(`rate_limit_remaining` > 0, `rate_limit_remaining` - 1, 0) ), `rate_limit_expiry` = IF(`rate_limit_expiry` < %d, VALUES(`rate_limit_expiry`), `rate_limit_expiry`); ", $action_id, $rate_limit_expiry, $limit - 1, $time, $time, $time ) ); if ( false === $result ) { return false; } return (int) $wpdb->get_var( 'SELECT LAST_INSERT_ID()' ) > 0; } /** * Get bucket options. * * @param string $bucket Bucket name. * @return array{limit:int, seconds:int}|null */ private static function get_bucket_options( string $bucket ): ?array { switch ( $bucket ) { case self::BUCKET_GENERATION: return array( 'limit' => MobileAppQRLogin::MAX_TOKENS_PER_WINDOW, 'seconds' => 15 * MINUTE_IN_SECONDS, ); case self::BUCKET_EXCHANGE_IP: return array( 'limit' => MobileAppQRLogin::MAX_EXCHANGE_IP_ATTEMPTS, 'seconds' => 15 * MINUTE_IN_SECONDS, ); case self::BUCKET_INVALID_EXCHANGE: return array( 'limit' => MobileAppQRLogin::MAX_INVALID_EXCHANGE_ATTEMPTS, 'seconds' => 15 * MINUTE_IN_SECONDS, ); case self::BUCKET_INVALID_SCAN: return array( 'limit' => MobileAppQRLogin::MAX_INVALID_SCAN_ATTEMPTS, 'seconds' => 15 * MINUTE_IN_SECONDS, ); case self::BUCKET_VALID_EXCHANGE: return array( 'limit' => MobileAppQRLogin::MAX_EXCHANGE_ATTEMPTS, 'seconds' => 15 * MINUTE_IN_SECONDS, ); case self::BUCKET_STATUS: return array( 'limit' => MobileAppQRLogin::MAX_STATUS_CHECKS_PER_WINDOW, 'seconds' => 15 * MINUTE_IN_SECONDS, ); case self::BUCKET_REVOKE: return array( 'limit' => MobileAppQRLogin::MAX_REVOKE_ATTEMPTS, 'seconds' => 15 * MINUTE_IN_SECONDS, ); case self::BUCKET_SCAN: return array( 'limit' => MobileAppQRLogin::MAX_SCAN_PER_WINDOW, 'seconds' => 15 * MINUTE_IN_SECONDS, ); case self::BUCKET_APPROVE: return array( 'limit' => MobileAppQRLogin::MAX_APPROVE_PER_WINDOW, 'seconds' => 15 * MINUTE_IN_SECONDS, ); case self::BUCKET_SESSION_STATUS: return array( 'limit' => MobileAppQRLogin::MAX_SESSION_STATUS_PER_WINDOW, 'seconds' => 15 * MINUTE_IN_SECONDS, ); } return null; } }