PluginProbe
The WP Remote WordPress Plugin / 6.36
The WP Remote WordPress Plugin v6.36
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 5.73 All 53 releases
wpremote / protect / fw / rule / engine.php

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

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