Skip to content

Commit 88228a4

Browse files
committed
rate limiter for export downloads
Signed-off-by: Kev Provance <kevin.provance@gmail.com>
1 parent 8e54f7c commit 88228a4

4 files changed

Lines changed: 104 additions & 7 deletions

File tree

redux-core/class-redux-core.php

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -235,11 +235,12 @@ public static function plugins_loaded() {}
235235
*/
236236
private function init() {
237237
self::$server = array(
238-
'SERVER_SOFTWARE' => '',
239-
'REMOTE_ADDR' => Redux_Helpers::is_local_host() ? '127.0.0.1' : '',
240-
'HTTP_USER_AGENT' => '',
241-
'HTTP_HOST' => '',
242-
'REQUEST_URI' => '',
238+
'SERVER_SOFTWARE' => '',
239+
'REMOTE_ADDR' => Redux_Helpers::is_local_host() ? '127.0.0.1' : '',
240+
'HTTP_USER_AGENT' => '',
241+
'HTTP_HOST' => '',
242+
'REQUEST_URI' => '',
243+
'HTTP_X_FORWARDED_FOR' => '',
243244
);
244245

245246
// phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
@@ -258,7 +259,9 @@ private function init() {
258259
if ( ! empty( $_SERVER['REQUEST_URI'] ) ) {
259260
self::$server['REQUEST_URI'] = sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) );
260261
}
261-
262+
if ( ! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
263+
self::$server['HTTP_X_FORWARDED_FOR'] = sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_FORWARDED_FOR'] ) );
264+
}
262265
// phpcs:enable
263266

264267
self::$dir = trailingslashit( wp_normalize_path( dirname( realpath( __FILE__ ) ) ) );
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?php // phpcs:ignore WordPress.Files.FileName
2+
3+
/**
4+
* Redux Rate Limiter Class
5+
*
6+
* @class Secure Token
7+
* @version 4.5.10
8+
* @package Redux Framework/Classes
9+
*/
10+
11+
defined( 'ABSPATH' ) || exit;
12+
13+
if ( ! class_exists( 'Redux_Rate_Limiter', false ) ) {
14+
15+
/**
16+
* Redux_Rate_Limiter.
17+
*
18+
* @since 4.5.10
19+
*/
20+
class Redux_Rate_Limiter {
21+
22+
/**
23+
* Limits for functions that require them.
24+
*
25+
* @var array[]
26+
*/
27+
private static array $limits = array(
28+
'download_options' => array(
29+
'max' => 5,
30+
'window' => 300,
31+
), // 5 per 5 minutes.
32+
'color_schemes' => array(
33+
'max' => 5,
34+
'window' => 300,
35+
), // 5 per 5 minutes.
36+
);
37+
38+
/**
39+
* Check for the rate limit.
40+
*
41+
* @param string $action Function to check.
42+
*
43+
* @return bool
44+
*/
45+
public static function check( string $action ): bool {
46+
if ( ! isset( self::$limits[ $action ] ) ) {
47+
return true;
48+
}
49+
50+
$limit = self::$limits[ $action ];
51+
52+
$ip = self::get_client_ip();
53+
$key = 'redux_rate_' . md5( $action . $ip );
54+
55+
$current = get_transient( $key );
56+
57+
if ( false === $current ) {
58+
set_transient( $key, 1, $limit['window'] );
59+
return true;
60+
}
61+
62+
if ( $current >= $limit['max'] ) {
63+
return false; // Rate limited.
64+
}
65+
66+
set_transient( $key, $current + 1, $limit['window'] );
67+
return true;
68+
}
69+
70+
/**
71+
* Get the client's IP address.
72+
*
73+
* @return mixed|string
74+
*/
75+
private static function get_client_ip() {
76+
$ip = Redux_Core::$server['REMOTE_ADDR'];
77+
78+
if ( ! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
79+
$ips = explode( ',', Redux_Core::$server['HTTP_X_FORWARDED_FOR'] );
80+
$ip = trim( $ips[0] );
81+
}
82+
83+
return filter_var( $ip, FILTER_VALIDATE_IP ) ?? '0.0.0.0';
84+
}
85+
}
86+
}

redux-core/inc/extensions/color_scheme/class-redux-extension-color-scheme.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -555,10 +555,14 @@ private function import_schemes() {
555555
* @return void
556556
*/
557557
private function download_schemes() {
558+
if ( ! Redux_Rate_Limiter::check( 'color_schemes' ) ) {
559+
wp_die( 'Rate limit exceeded. Please try again later.' );
560+
}
561+
558562
Redux_Color_Scheme_Functions::$parent = $this->parent;
559563
Redux_Color_Scheme_Functions::$field_id = $this->field_id;
560564

561-
// Read contents of scheme file.
565+
// Read the contents of the scheme file.
562566
$content = Redux_Color_Scheme_Functions::read_scheme_file();
563567
$content = wp_json_encode( $content );
564568

redux-core/inc/extensions/import_export/class-redux-extension-import-export.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ public function download_options() {
108108
wp_die( 'Invalid secret for options use.' );
109109
}
110110

111+
if ( ! Redux_Rate_Limiter::check( 'download_options' ) ) {
112+
wp_die( 'Rate limit exceeded. Please try again later.' );
113+
}
114+
111115
$this->parent->options_class->get();
112116
$backup_options = $this->parent->options;
113117
$backup_options['redux-backup'] = 1;

0 commit comments

Comments
 (0)