PluginProbe
The WP Remote WordPress Plugin / 6.76
The WP Remote WordPress Plugin v6.76
6.76 6.72 6.69 6.65 6.62 6.48 6.47 4.87 4.97 5.05 5.09 5.16 5.22 5.24 5.25 5.38 5.41 5.42 5.45 5.47 5.53 5.56 5.65 5.68 5.72 All 54 releases
wpremote / protect / fw / rule / engine.php

engine.php in The WP Remote WordPress Plugin 6.76, at protect/fw/rule/engine.php

349 lines 8.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // phpcs:disable WordPress.Security.EscapeOutput.ExceptionNotEscaped
3 if (!defined('ABSPATH') && !defined('MCDATAPATH')) exit;
4
5 if (!class_exists('WPRProtectFWRuleEngine_V676')) :
6 require_once dirname( __FILE__ ) . '/functions.php';
7
8 class WPRProtectFWRuleEngine_V676 {
9 use WPRProtectFWRuleStringFunc_V676;
10 use WPRProtectFWRuleArrayFunc_V676;
11 use WPRProtectFWRuleMiscFunc_V676;
12 use WPRProtectFWRuleRequestFunc_V676;
13 use WPRProtectFWRuleWPFunc_V676;
14
15 private $request;
16 private $variables;
17
18 private $error;
19 private $ex_stack = array();
20 private $ex_stack_inx = -1;
21
22 const VERSION = 1.4;
23
24 const MAX_DEPTH_TO_ALLOWED_TYPE_FUNC = 8;
25 const MAX_ARRAY_KEYS_TO_TRAVERSE = 10000;
26 const WILDCARD_KEY = '*';
27 const FUNC_NAME_PREFIX = '_rf_';
28 const CONST_NAME_PREFIX = 'WPRProtectFWRule_V676::';
29 const ALLOWED_EXT_CONSTANTS = [
30 'DOING_CRON'
31 ];
32
33 public function __construct($request = null, $variables = array()) {
34 $this->request = $request;
35 $this->variables = $variables;
36 }
37
38 public static function normalizeVariables($variables) {
39 return self::toAllowedType($variables);
40 }
41
42 public function hasError() {
43 return isset($this->error);
44 }
45
46 public function getErrorMessage() {
47 if (isset($this->error)) {
48 return $this->error->getMessage();
49 }
50 }
51
52 public function evaluate($rule) {
53 try {
54 return $this->executeStmt($rule->logic);
55 } catch (WPRProtectRuleError_V676 $e) {
56 $this->error = $e;
57 }
58 }
59
60 private static function toAllowedType($value, $depth = 1) {
61 if ($depth > self::MAX_DEPTH_TO_ALLOWED_TYPE_FUNC) {
62 return null;
63 }
64 switch (gettype($value)) {
65 case 'NULL':
66 case 'boolean':
67 case 'integer':
68 case 'double':
69 case 'string':
70 return $value;
71 case 'array':
72 $array_value = [];
73
74 foreach ($value as $key => $val) {
75 $array_value[$key] = self::toAllowedType($val, $depth + 1);
76 }
77
78 return $array_value;
79 case 'object':
80 $object_vars = [];
81
82 foreach (get_object_vars($value) as $key => $val) {
83 $object_vars[$key] = self::toAllowedType($val, $depth + 1);
84 }
85
86 return $object_vars;
87 default:
88 return null;
89 }
90 }
91
92 private function pushExStack() {
93 array_push($this->ex_stack, array('cur_op' => '-', 'op_cnt' => 0));
94 $this->ex_stack_inx += 1;
95 }
96
97 private function popExStack() {
98 array_pop($this->ex_stack);
99 $this->ex_stack_inx -= 1;
100 }
101
102 private function updateCurOp($cur_op) {
103 if (!empty($this->ex_stack[$this->ex_stack_inx])) {
104 $this->ex_stack[$this->ex_stack_inx]['cur_op'] = $cur_op;
105 }
106 }
107
108 private function incrOpCnt() {
109 if (!empty($this->ex_stack[$this->ex_stack_inx])) {
110 $this->ex_stack[$this->ex_stack_inx]['op_cnt'] += 1;
111 }
112 }
113
114 private function addExState($msg) {
115 if (!empty($this->ex_stack[$this->ex_stack_inx])) {
116 $msg .= " on " . $this->ex_stack[$this->ex_stack_inx]['cur_op'];
117 $msg .= " at (" . $this->ex_stack_inx . ":" .
118 $this->ex_stack[$this->ex_stack_inx]['op_cnt'] . ").";
119 }
120
121 return $msg;
122 }
123
124 private function getValue($stmt) {
125 if (!is_array($stmt) || empty($stmt["type"])) {
126 throw new WPRProtectRuleError_V676(
127 $this->addExState("InvalidStatementError: Malformed value statement"));
128 }
129
130 $this->incrOpCnt();
131
132 switch ($stmt["type"]) {
133 case "NUMBER":
134 if (!isset($stmt["value"]) || !is_int($stmt["value"])) {
135 throw new WPRProtectRuleError_V676(
136 $this->addExState("TypeError: Value is not a number")
137 );
138 }
139
140 return $stmt["value"];
141 case "STRING":
142 if (!isset($stmt["value"]) || !is_string($stmt["value"])) {
143 throw new WPRProtectRuleError_V676(
144 $this->addExState("TypeError: Value is not a string")
145 );
146 }
147
148 return $stmt["value"];
149 case "BOOL":
150 if (!isset($stmt["value"]) || !is_bool($stmt["value"])) {
151 throw new WPRProtectRuleError_V676(
152 $this->addExState("TypeError: Value is not a boolean")
153 );
154 }
155
156 return $stmt["value"];
157 case "CONST":
158 if (!isset($stmt["value"]) || !is_string($stmt["value"])) {
159 throw new WPRProtectRuleError_V676(
160 $this->addExState("TypeError: Invalid constant name")
161 );
162 }
163
164 //For backward compatibility.
165 $name = str_replace('BVFW::', '', $stmt["value"]);
166 if (!in_array($name, self::ALLOWED_EXT_CONSTANTS, true)) {
167 $name = self::CONST_NAME_PREFIX . $name;
168 }
169
170 if (!defined($name)) {
171 throw new WPRProtectRuleError_V676(
172 $this->addExState("TypeError: Undefined constant" . $stmt["value"])
173 );
174 }
175
176 return constant($name);
177 case "ARRAY":
178 if (!isset($stmt["value"]) || !is_array($stmt["value"])) {
179 throw new WPRProtectRuleError_V676(
180 $this->addExState("TypeError: Value is not a array")
181 );
182 }
183
184 $arr = array();
185 foreach ($stmt["value"] as $element) {
186 $arr[] = $this->getValue($element);
187 }
188
189 return $arr;
190 case "HASH_MAP":
191 if (!isset($stmt["value"]) || !is_array($stmt["value"])) {
192 throw new MCProtectRuleError(
193 $this->addExState("TypeError: Value is not a hash map")
194 );
195 }
196
197 $hash_map = array();
198 foreach($stmt["value"] as $key => $value) {
199 $hash_map[$key] = $this->getValue($value);
200 }
201
202 return $hash_map;
203 default:
204 return $this->executeStmt($stmt);
205 }
206 }
207
208 private function executeStmt($stmt) {
209 if (!is_array($stmt) || empty($stmt["type"])) {
210 throw new WPRProtectRuleError_V676(
211 $this->addExState("InvalidStatementError: Malformed logic statement")
212 );
213 }
214
215 $this->pushExStack();
216 $this->updateCurOp($stmt["type"]);
217 $return_val = null;
218
219 switch ($stmt["type"]) {
220 case "AND":
221 if (empty($stmt["left_operand"]) || empty($stmt["right_operand"])) {
222 throw new WPRProtectRuleError_V676(
223 $this->addExState("InvalidOperandError: Malformed operand(s)")
224 );
225 }
226
227 $return_val = $this->getValue($stmt["left_operand"]) && $this->getValue($stmt["right_operand"]);
228 break;
229 case "OR":
230 if (empty($stmt["left_operand"]) || empty($stmt["right_operand"])) {
231 throw new WPRProtectRuleError_V676(
232 $this->addExState("InvalidOperandError: Malformed operand(s)")
233 );
234 }
235
236 $return_val = $this->getValue($stmt["left_operand"]) || $this->getValue($stmt["right_operand"]);
237 break;
238 case "NOT":
239 if (empty($stmt["value"])) {
240 throw new WPRProtectRuleError_V676(
241 $this->addExState("InvalidOperandError: Malformed operand")
242 );
243 }
244
245 $return_val = !$this->getValue($stmt["value"]);
246 break;
247 case "FUNCTION":
248 if (empty($stmt["name"]) || !is_string($stmt["name"])) {
249 throw new WPRProtectRuleError_V676(
250 $this->addExState("InvalidFunctionName: Malformed name")
251 );
252 }
253
254 $name = self::FUNC_NAME_PREFIX . $stmt["name"];
255 $handler = array($this, $name);
256
257 if (!is_callable($handler)) {
258 throw new WPRProtectRuleError_V676(
259 $this->addExState("UndefinedFunctionCall: " . $stmt["name"])
260 );
261 }
262
263 if (!array_key_exists('args', $stmt) || !is_array($stmt['args'])) {
264 throw new WPRProtectRuleError_V676(
265 $this->addExState("InvalidArguments: Malformed args")
266 );
267 }
268
269 $args = array();
270 foreach ($stmt['args'] as $arg_stmt) {
271 array_push($args, $this->getValue($arg_stmt));
272 }
273
274 $return_val = self::toAllowedType(call_user_func_array($handler, $args));
275 break;
276 default:
277 throw new WPRProtectRuleError_V676(
278 $this->addExState("UnknownOperation: -")
279 );
280 }
281
282 $this->popExStack();
283 return $return_val;
284 }
285
286 private function processRuleFunctionParams($func_name, $args_cnt, $args, $required_params = 0, $param_types = array()) {
287 if (($args_cnt < $required_params)) {
288 throw new WPRProtectRuleError_V676(
289 $this->addExState("ArgumentCountError: Too few arguments for " . $func_name)
290 );
291 }
292
293 foreach ($param_types as $pos => $type) {
294 if (!is_int($pos)) {
295 throw new WPRProtectRuleError_V676(
296 $this->addExState("InvalidParamType: " . $pos)
297 );
298 }
299
300 switch ($type) {
301 case "string":
302 if (!isset($args[$pos]) || !is_string($args[$pos])) {
303 throw new WPRProtectRuleError_V676(
304 $this->addExState("TypeError: " . $func_name . " param at " . $pos . " is not a string.")
305 );
306 }
307 break;
308 case 'integer':
309 if (!isset($args[$pos]) || !is_int($args[$pos])) {
310 throw new WPRProtectRuleError_V676(
311 $this->addExState("TypeError: " . $func_name . " param at " . $pos . " is not a integer.")
312 );
313 }
314 break;
315 case 'double':
316 if (!isset($args[$pos]) || !is_double($args[$pos])) {
317 throw new WPRProtectRuleError_V676(
318 $this->addExState("TypeError: " . $func_name . " param at " . $pos . " is not a double.")
319 );
320 }
321 break;
322 case 'boolean':
323 if (!isset($args[$pos]) || !is_bool($args[$pos])) {
324 throw new WPRProtectRuleError_V676(
325 $this->addExState("TypeError: " . $func_name . " param at " . $pos . " is not a boolean.")
326 );
327 }
328 break;
329 case 'array':
330 if (!isset($args[$pos]) || !is_array($args[$pos])) {
331 throw new WPRProtectRuleError_V676(
332 $this->addExState("TypeError: " . $func_name . " param at " . $pos . " is not an array.")
333 );
334 }
335 break;
336 case 'mixed':
337 break;
338 default:
339 throw new WPRProtectRuleError_V676(
340 $this->addExState("InvalidParamTypeError: Invalid type at " . $pos . " for " . $func_name)
341 );
342 }
343 }
344
345 return $args;
346 }
347 }
348 endif;
349