PluginProbe
RSFirewall! / trunk
RSFirewall! vtrunk
rsfirewall / models / configuration.php

configuration.php in RSFirewall! trunk, at models/configuration.php

772 lines 23.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package RSFirewall!
4 * @copyright (c) 2018 RSJoomla!
5 * @link https://www.rsjoomla.com
6 * @license GNU General Public License http://www.gnu.org/licenses/gpl-3.0.en.html
7 */
8
9 if ( ! defined( 'WPINC' ) ) {
10 die;
11 }
12
13 class RSFirewall_Model_Configuration extends RSFirewall_Model {
14
15 public function __construct() {
16 /**
17 * Need to construct the parent here to initiate $this->form
18 */
19 parent::__construct();
20
21 /**
22 * Hook into admin_init to add our settings page
23 */
24 add_action( 'admin_init', array( $this, 'init_config' ) );
25
26 /*
27 * We need to add json file type to the mime_types filter, because the .json is not present by default
28 */
29 add_filter('mime_types', array($this, 'mime_types'));
30 }
31
32 public function mime_types($types) {
33 if (!isset($types['json'])) {
34 $types['json'] = 'application/json';
35 }
36
37 return $types;
38 }
39
40 public function init_config() {
41 foreach ( $this->form->sections as $section ) {
42 // Add the calback for this section if specified
43 $callback = isset($section['callback']) ? array($this, $section['callback']) : array();
44 // Determine if the label is hidden or not
45 $section_label = (isset($section['hide_label']) && $section['hide_label']) ? '&shy;' : $section['label'];
46
47 add_settings_section(
48 $section['name'],
49 $section_label,
50 $callback,
51 $section['name']
52 );
53
54 /** Load values from the database or use defaults from XML form */
55 $options = get_option( $section['name'] );
56 $must_update = false;
57 if ( $options === false ) {
58 $must_update = true;
59 $options = array();
60 }
61
62 foreach ( $section['fields'] as $field ) {
63 $value = NULL;
64 if ( isset( $options[ $field['name'] ] ) ) {
65 $value = $options[ $field['name'] ];
66 } else {
67 if ( $default = (string) $field['field']->attributes()->default ) {
68 if ($field['name'] == 'dot_files') {
69 $default = str_replace('\n', "\n", $default);
70 }
71
72 $value = $default;
73 $options[ $field['name'] ] = $default;
74 }
75 }
76
77 // For the "ignore_files_or_folders" option we need to take in consideration the values added by the System Check
78 if ($field['name'] == 'ignore_files_or_folders' && $field['type'] != 'only_pro_field') {
79
80 // get the ignored files and folders from the database, so that they can be present in the textarea
81 $check_model = RSFirewall_Helper::call_user_func_pro(array('RSFirewall_Model_Check', 'get_instance'));
82 // build the ignore variable
83 $check_model->_get_ignored();
84
85 $ignored = $check_model->ignored;
86 if(!empty($ignored)) {
87 // what is already ignored in the database
88 $already_ignored = array();
89 foreach ($ignored as $type => $paths) {
90 if (!empty($paths)) {
91 $already_ignored = array_merge ($already_ignored, $paths);
92 }
93 }
94
95 if (!empty($already_ignored)) {
96 // break the current value stored in the options
97 $value_options = RSFirewall_Helper::explode($value);
98
99 // merge the two arrays
100 $value = array_merge($already_ignored, $value_options);
101
102 // filter the values to remove duplicates
103 $value = array_unique($value);
104 // rebuild as text value
105 $value = implode("\n", $value);
106 }
107 }
108 }
109
110 // remove the disabled attribute from the continents/check_all/country blocking if there is a GeoIp support
111 if (in_array($field['name'], array('blocked_continents', 'blocked_countries', 'blocked_countries_checkall')) && $field['field']->attributes()->disabled && (isset($this->geoIp_support) && $this->geoIp_support->works)) {
112 $field['field']->attributes()->disabled = '';
113 }
114
115 add_settings_field(
116 $field['name'],
117 RSFirewall_Helper::call_user_func_pro_args(array('RSFirewall_Helper_Fields', 'label_for', $field['field'])),
118 RSFirewall_Helper::buildWPCallback(array( 'RSFirewall_Helper_Fields', $field['type'] )),
119 $section['name'],
120 $section['name'],
121 array(
122 'section' => $section['name'],
123 'field' => $field['field'],
124 'value' => $value,
125 )
126 );
127 }
128 /**
129 * Update only if necessary
130 */
131 if ( $must_update ) {
132 update_option( $section['name'], $options );
133 }
134
135 // Register the settings with the sanitize_callback function
136 register_setting(
137 $section['name'],
138 $section['name'],
139 array($this, 'validate')
140 );
141 }
142
143 // Show the current ip when adding
144 add_action( 'admin_notices', array($this, 'admin_notice') );
145 }
146
147 protected function delete_file($file) {
148 if ( function_exists( 'wp_delete_file' ) ) {
149 wp_delete_file($file);
150 }
151
152 $delete = apply_filters( 'wp_delete_file', $file );
153 if ( ! empty( $delete ) ) {
154 @unlink( $delete );
155 }
156 }
157
158 protected function strip_ext($file)
159 {
160 return preg_replace('#\.[^.]*$#', '', $file);
161 }
162
163
164 protected function get_extension($filename) {
165 $parts = explode('.', $filename, 2);
166 $ext = '';
167 if (count($parts) == 2) {
168 $file = $parts[0];
169 $ext = $parts[1];
170 // check for multiple extensions
171 if (strpos($file, '.') !== false) {
172 $parts = explode('.', $file);
173 $last = end($parts);
174 if (strlen($last) <= 4) {
175 $ext = $last.'.'.$ext;
176 }
177 }
178 }
179
180 return strtolower($ext);
181 }
182
183 protected function process_import_cfg_file($filename, $tmp_file) {
184 global $wpdb;
185 // Check extension is .json
186 $ext = wp_check_filetype($filename);
187
188 // Not a valid extension
189 if ($ext['ext'] != 'json')
190 {
191 throw new Exception(__('Please upload only .json files!', 'rsfirewall'));
192 }
193
194 // Check if the temporary file is readable
195 if (!is_readable($tmp_file))
196 {
197 throw new Exception(sprintf(__('Uploaded file is not readable in server\'s temp directory: %s','rsfirewall'), $tmp_file));
198 }
199
200 // Get the contents of the json file and check if it's not empty
201 $contents = file_get_contents($tmp_file);
202 if (!$contents)
203 {
204 throw new Exception(__('No contents found in uploaded file.', 'rsfirewall'));
205 }
206
207 // Process the json found in the contents
208 $contents = json_decode($contents, true);
209 if ($contents === null)
210 {
211 throw new Exception(__('Could not decode JSON data from uploaded file.', 'rsfirewall'));
212 }
213
214 // Update paths
215 if (isset($contents['root']))
216 {
217 if (!empty($contents['rsfirewall_system_check']['ignore_files_or_folders']))
218 {
219 $contents['rsfirewall_system_check']['ignore_files_or_folders'] = str_replace($contents['root'], ABSPATH, $contents['rsfirewall_system_check']['ignore_files_or_folders']);
220 }
221 if (!empty($contents['rsfirewall_active_scanner']['monitor_files']))
222 {
223 $contents['rsfirewall_active_scanner']['monitor_files'] = str_replace($contents['root'], ABSPATH, $contents['rsfirewall_active_scanner']['monitor_files']);
224 }
225 }
226
227
228 foreach ($contents as $section => $data) {
229 if ($section == 'root') {
230 continue;
231 }
232 // We can not use update_option function, there is a problem with the sanitize_option function inside it (don't know why)
233
234 // Check if the option is in the database
235 $row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s", $section ) );
236 $new_value = maybe_serialize($data);
237 if ( is_null( $row ) ) {
238 $result = $wpdb->query( $wpdb->prepare( "INSERT INTO `$wpdb->options` (`option_name`, `option_value`, `autoload`) VALUES (%s, %s, %s)", $section,$new_value, 'yes' ) );
239 } else {
240 $old_value = $row->option_value;
241 if ($old_value == $new_value) {
242 $result = true;
243 } else {
244 // Skip the license code of the configuration if the option is not selected
245 if ($section == 'rsfirewall_updates' && (int) $_POST['rsfirewall_import']['upload_license'] == 0) {
246 $result = true;
247 } // This option (update license code) do not import because the old value the desired value
248 else if($section == 'rsfirewall_import'){
249 $result = true;
250 } else {
251 $result = $wpdb->update($wpdb->options, array('option_value' => maybe_serialize($data)), array('option_name' => $section));
252 }
253 }
254 }
255
256 if (!$result) {
257 throw new Exception(sprintf(__('Could not import the settings for the section: %s', 'rsfirewall'), $section));
258 break;
259 }
260 }
261 }
262
263 public function validate( $section ) {
264 global $wpdb;
265
266 $blog_id = is_multisite() ? 'rsf_'.get_current_blog_id() : 'rsf_';
267 $blog_id = md5($blog_id);
268
269 if (isset($section['code']))
270 {
271 $current_code = get_option('rsfirewall_updates');
272
273 // if the code has changed, delete the update_plugins transient so that the update is checked again
274 if ($current_code['code'] != $section['code'])
275 {
276 // get existing transient
277 $transient = get_site_transient('update_plugins');
278
279 // make sure it exists
280 if ($transient) {
281 // remake
282 $transient = RSFirewall_Version::get_instance()->activate_updates(true, $section['code'])->check_update($transient);
283
284 //set the transient
285 set_site_transient('update_plugins', $transient);
286 }
287 }
288 }
289
290 if ( ! empty( $section['enable_backend'] ) ) {
291 try {
292 // verify that a password hasn't been set
293 $backend_pass_options = get_option( 'rsfirewall_backend_password' );
294 $stop_checks = false;
295
296 if (isset($backend_pass_options['type_password']) && !empty($backend_pass_options['type_password']) && (!strlen($section['type_password']) || !strlen($section['confirm_password']))) {
297 $stop_checks = true;
298 }
299
300 if(!$stop_checks) {
301 if (!strlen($section['type_password'])) {
302 throw new Exception(esc_html__('Please provide a password.', 'rsfirewall'));
303 }
304
305 if (strlen($section['type_password']) < 6) {
306 throw new Exception(esc_html__('Please provide a password containing at least 6 characters.', 'rsfirewall'));
307 }
308
309 if ($section['type_password'] !== $section['confirm_password']) {
310 throw new Exception(esc_html__('Passwords do not match.', 'rsfirewall'));
311 }
312
313 // save them encrypted
314 $encrypt = md5($section['type_password']);
315 $section['type_password'] = $section['confirm_password'] = $encrypt;
316 } else {
317 // keep the current password already saved
318 $section['type_password'] = $backend_pass_options['type_password'];
319 $section['confirm_password'] = $backend_pass_options['confirm_password'];
320 }
321
322 } catch ( Exception $e ) {
323 $section['enable_backend'] = 0;
324 add_settings_error( 'rsfirewall', 'password', $e->getMessage(), 'error' );
325 }
326 } else if (isset($section['enable_backend']) && $section['enable_backend'] === '0' && isset($_COOKIE['rsf_backend_login'.$blog_id])) {
327 $backend_pass = RSFirewall_Core_Backend_Password::get_instance();
328 $backend_pass->delete_login_cookie();
329 }
330
331 // this is a clean of the logout link independent of the enable backend password option
332 if (isset($section['logout_redirect']) && strlen($section['logout_redirect']) > 0) {
333 if(!wp_http_validate_url($section['logout_redirect'])) {
334 $section['logout_redirect'] = '';
335 add_settings_error( 'rsfirewall', 'password', sprintf(esc_html__('Please provide a full schema link for the logout redirect! (ex: %s)', 'rsfirewall'), get_site_url()), 'error' );
336 }
337 }
338
339 if (isset($section['enable_admin_slug']) && !empty($section['enable_admin_slug']) && isset($section['admin_slug_text'])) {
340 // clean a bit the slug
341 $section['admin_slug_text'] = trim($section['admin_slug_text']);
342 if (strlen($section['admin_slug_text']) == 0) {
343 $section['enable_admin_slug'] = 0;
344 add_settings_error( 'rsfirewall', 'slug', esc_html__('Please provide a text for the slug to enable it!'), 'error' );
345 }
346 }
347
348 // Handle the hardening options
349 if (isset($section['harden_uploads'])) {
350
351 // Find all the hardening options and values
352 $hardening_options = array();
353 $hardening_defaults = get_option('rsfirewall_hardening');
354 foreach ($section as $option => $option_value ) {
355 if (strpos($option, 'harden_') == 0) {
356 $hardening_options[] = $option;
357 }
358 }
359
360 if (!empty($hardening_options)) {
361 try {
362 foreach ($hardening_options as $option) {
363 if (method_exists($this, $option)) {
364 call_user_func_array(array($this, $option), array(&$section[$option]));
365 } else {
366 // restore to the last saved value
367 $section[$option] = isset($hardening_defaults[$option]) ? $hardening_defaults[$option] : 0;
368 }
369 }
370 } catch (Exception $e) {
371 $trace = $e->getTrace();
372 $stuck_at = $trace[0]['function'];
373
374 $change = false;
375 foreach ($hardening_options as $option) {
376 if ($option == $stuck_at) {
377 $change = true;
378 }
379
380 if ($change) {
381 $section[$option] = isset($hardening_defaults[$option]) ? $hardening_defaults[$option] : 0;
382 }
383 }
384 add_settings_error('rsfirewall', 'hardening', $e->getMessage(), 'error');
385 }
386 }
387 }
388
389 if (isset($section['monitor_files'])) {
390 $table = $wpdb->prefix . 'rsfirewall_hashes';
391
392 $already_monitored = RSFirewall_Config::get( 'monitor_files' );
393 if ($already_monitored != $section['monitor_files']) {
394 /** Cleanup the table */
395 $wpdb->delete( $table, array( 'type' => 'protect' ) );
396
397 $values = RSFirewall_Helper::explode($section['monitor_files']);
398 // Remove Duplicates
399 $values = array_unique($values);
400
401 foreach ($values as $i => $value)
402 {
403 $value = trim($value);
404 if (!file_exists($value) || !is_readable($value))
405 {
406 unset($values[$i]);
407 continue;
408 }
409
410 $wpdb->insert(
411 $table,
412 array(
413 'file' => $value,
414 'hash' => md5_file($value),
415 'type' => 'protect',
416 'flag' => '',
417 'date' => current_time('mysql')
418 )
419 );
420 }
421
422 // Override the section value so that is saved without the duplicates
423 $section['monitor_files'] = !empty($values) ? implode("\n", $values) : '';
424 }
425 }
426
427 // When we disable the creation of new admin users, we need to remember which are the default ones
428 if (!empty($section['disable_admin_creation'])) {
429 $admin_users = RSFirewall_Helper_Users::getAdminUsers();
430
431 update_option('rsfirewall_admin_users', $admin_users);
432 }
433
434
435 // Parse all the uploaded files
436 try {
437 $this->handle_uploads();
438 } catch ( Exception $e ) {
439 add_settings_error( 'rsfirewall', 'country_blocking', $e->getMessage(), 'error' );
440 }
441
442 if (get_class($this) != 'RSFirewall_Model_ConfigurationPro') {
443 return apply_filters( 'validate_inputs', $section );
444 } else {
445 return $section;
446 }
447 }
448
449 /**
450 * Callback function to harden uploads directory
451 *
452 * @param $section_value
453 * @throws Exception in case something goes wrong
454 */
455 protected function harden_uploads($section_value) {
456 $upload_path = RSFirewall_Helper::get_uploads_path();
457
458 if (!empty($section_value)) {
459 RSFirewall_Helper_Harden::harden_directory($upload_path);
460 } else {
461 RSFirewall_Helper_Harden::unharden_directory($upload_path);
462 }
463 }
464
465 /**
466 * Callback function to harden wp-content directory
467 *
468 * @param $section_value
469 * @throws Exception in case something goes wrong
470 */
471 protected function harden_wp_content($section_value) {
472
473 if (!empty($section_value)) {
474 RSFirewall_Helper_Harden::harden_directory(WP_CONTENT_DIR);
475 } else {
476 RSFirewall_Helper_Harden::unharden_directory(WP_CONTENT_DIR);
477 }
478 }
479
480 /**
481 * Callback function to harden wp-includes directory
482 *
483 * @param $section_value
484 * @throws Exception in case something goes wrong
485 */
486 protected function harden_wp_includes($section_value) {
487
488 if (!empty($section_value)) {
489 RSFirewall_Helper_Harden::harden_directory(ABSPATH . '/wp-includes');
490 } else {
491 RSFirewall_Helper_Harden::unharden_directory(ABSPATH . '/wp-includes');
492 }
493 }
494
495 /**
496 * Callback function to enable/disable file editors
497 *
498 * @param $section_value
499 * @throws Exception in case something goes wrong
500 */
501 protected function harden_editors($section_value) {
502 $is_disabled = (defined('DISALLOW_FILE_EDIT') && DISALLOW_FILE_EDIT);
503
504 // if the editors are already disabled / enabled (in case of unharden) then skip this process
505 if (($section_value == 1 && $is_disabled) || ($section_value == 0 && !$is_disabled)) {
506 return;
507 }
508
509 $config_file = RSFirewall_Helper::get_config_path();
510
511 if (!$config_file) {
512 throw new Exception(esc_html__('The configuration file could not be located!', 'rsfirewall'));
513 }
514
515 if (!is_writable($config_file)) {
516 throw new Exception(esc_html__('The configuration file is not writable!', 'rsfirewall'));
517 }
518
519 if (!is_readable($config_file)) {
520 throw new Exception(esc_html__('The configuration file is not readable!', 'rsfirewall'));
521 }
522
523 $file_content = (string) file_get_contents($config_file);
524 $lines = explode("\n", $file_content);
525 $newlines = array();
526
527 $has_constant = (strpos($file_content, 'DISALLOW_FILE_EDIT') !== false);
528
529 foreach ($lines as $line) {
530 if ($section_value == 1) {
531 /** if the constant is not defined add it */
532 if (strpos($line, 'DB_COLLATE') !== false && !$has_constant) {
533 $newlines[] = $line; // keep the DB_COLLATE line
534 $newlines[] = '';
535 $newlines[] = '/** Disable / Enable file edit using plugins / themes editors. */';
536 $newlines[] = "define('DISALLOW_FILE_EDIT', true);";
537 } else if (strpos($line, 'DISALLOW_FILE_EDIT') !== false){
538 /** if the constant is defined modify it */
539 $newlines[] = "define('DISALLOW_FILE_EDIT', true);";
540 } else {
541 $newlines[] = $line; // keep everything else
542 }
543 } else if (empty($section_value)) {
544 if (strpos($line, 'DISALLOW_FILE_EDIT') !== false) {
545 $newlines[] = "define('DISALLOW_FILE_EDIT', false);";
546 } else {
547 $newlines[] = $line; // keep everything else
548 }
549 }
550 }
551
552 // Change the file only if the content is built
553 if (!empty($newlines)) {
554 $file_content = implode("\n", $newlines);
555 file_put_contents($config_file, $file_content, LOCK_EX);
556 }
557 }
558
559 protected function handle_uploads() {
560 //Redefine files in a more beautiful way
561 $handler = RSFirewall_Helper_Files::get_instance();
562
563 // handle json configuration file
564 $config_file = $handler->get('rsfirewall_import');
565
566 // if no country blocking files / configuration files are loaded then skip
567 if (is_null($config_file)) {
568 return false;
569 }
570
571 // Process the configuration file
572 if (!empty($config_file) && strlen($config_file[0]['tmp_name'])) {
573 $config_file = $config_file[0];
574
575 // handle the file upload errors
576 $this->handle_upload_file_errors($config_file);
577
578 // Parse and check the uploaded json file
579 $this->process_import_cfg_file($config_file['name'], $config_file['tmp_name']);
580
581 }
582
583 return true;
584 }
585
586 protected function handle_upload_file_errors($file = null) {
587 if (is_null($file)) {
588 return false;
589 }
590
591 if ($file['error']) {
592 if ($file['error'] == UPLOAD_ERR_INI_SIZE)
593 {
594 throw new Exception( esc_html__( 'The uploaded file exceeds the upload_max_filesize directive in php.ini.', 'rsfirewall' ) );
595 }
596 elseif ($file['error'] == UPLOAD_ERR_FORM_SIZE)
597 {
598 throw new Exception( esc_html__( 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.', 'rsfirewall' ) );
599 }
600 elseif ($file['error'] == UPLOAD_ERR_PARTIAL)
601 {
602 throw new Exception( esc_html__( 'The uploaded file was only partially uploaded.', 'rsfirewall' ) );
603 }
604 elseif ($file['error'] == UPLOAD_ERR_NO_TMP_DIR)
605 {
606 throw new Exception( esc_html__( 'Missing a temporary folder.', 'rsfirewall' ) );
607 }
608 elseif ($file['error'] == UPLOAD_ERR_CANT_WRITE)
609 {
610 throw new Exception( esc_html__( 'Failed to write file to disk.', 'rsfirewall' ) );
611 }
612 elseif ($file['error'] == UPLOAD_ERR_EXTENSION)
613 {
614 throw new Exception( esc_html__( 'A PHP extension stopped the file upload.', 'rsfirewall' ) );
615 }
616 }
617
618 return true;
619 }
620
621 public function get_administrator_users() {
622 $results = array();
623
624 if ( $users = get_users( array( 'role' => 'administrator', 'orderby' => 'nicename' ) ) ) {
625 foreach ( $users as $user ) {
626 $results[] = (object) array(
627 'label' => $user->display_name,
628 'value' => $user->ID,
629 'checked' => false
630 );
631 }
632 }
633
634 return $results;
635 }
636
637 public function get_users_roles() {
638 global $wp_roles;
639 $all_roles = $wp_roles->roles;
640
641 $results = array();
642
643 foreach ($all_roles as $role => $details) {
644 $results[] = (object) array(
645 'label' => translate_user_role($details['name']),
646 'value' => esc_attr($role),
647 'checked' => false
648 );
649 }
650 return $results;
651 }
652
653 /**
654 * Callback function for the country blocking section and 2FA
655 */
656 public function only_pro_version() {
657 $html = '<div id="country_block">';
658
659 $html .= '<div class="alert alert-info">';
660 $html .= ' <h4>' . __('This feature is not available in the free version of RSFirewall!', 'rsfirewall') . '</h4>';
661 $html .= ' <p>' . esc_attr__('If you wish to use this feature please consider purchasing the full version of RSFirewall!', 'rsfirewall') . '</p>';
662 $html .= ' <p><a href="https://www.rsjoomla.com/wordpress-plugins/wordpress-security-plugin.html" class="button-primary">' . __('Purchase the full version of RSFirewall!', 'rsfirewall') . '</a></p>';
663 $html .= '</div>';
664
665 $html .= '</div>';
666
667 echo $html;
668 }
669
670 public function export_configuration() {
671 $values = array();
672 foreach ($this->form->get_sections() as $section) {
673 if (!isset($values[$section])) {
674 $values[$section] = array();
675 }
676
677 $options = get_option($section);
678 if (is_array($options))
679 {
680 $values[$section] = array_merge($values[$section], $options);
681 }
682 }
683
684 $values['root'] = ABSPATH;
685
686 return json_encode($values);
687 }
688
689 public function remove_whitelisted($files = array()) {
690 foreach ($files as $file) {
691 if (!RSFirewall_Helper_Harden::remove_file_from_whitelist($file['file'], ABSPATH.'/'.$file['folder'])) {
692 throw new Exception(sprintf(__('The .htaccess from %s could not be written!','rsfirewall'), $file['folder']));
693 }
694 }
695
696 return true;
697 }
698
699 public function add_whitelisted($file = '', $folder = '') {
700 /**
701 * Filename checks
702 */
703
704 // check the file to not be empty
705 if (trim($file) == '') {
706 throw new Exception(esc_html__('Please enter a filename!','rsfirewall'));
707 }
708
709 // do not include a full path (ex: folder1/folder2/file.php)
710 if (strpos($file, '/') !== false) {
711 throw new Exception(esc_html__('Please specify only the filename, not the full path!','rsfirewall'));
712 }
713
714 // alphanumeric and ".", "_", '-' characters accepted
715 preg_match_all('#([^a-zA-Z\d-\.\-])+#', $file, $matches);
716
717 if (!empty($matches[0])) {
718 throw new Exception(esc_html__('The filename must contain only alphanumeric and ".", "_", "-" as strings!','rsfirewall'));
719 }
720
721 // check if file extension is specified
722 $file_parts = explode('.', $file);
723 if (count($file_parts) <= 1) {
724 throw new Exception(esc_html__('No extension has been provided for the filename!','rsfirewall'));
725 }
726
727 // check if the extension is php
728 $extension = array_pop($file_parts);
729 if ($extension != 'php') {
730 throw new Exception(esc_html__('Only PHP files are accepted!','rsfirewall'));
731 }
732
733 /**
734 * Folder checks
735 */
736
737 $accepted_folders = array(
738 'uploads' => WP_CONTENT_DIR . '/uploads',
739 'wp-content' => WP_CONTENT_DIR,
740 'wp-includes' => ABSPATH . '/wp-includes',
741 );
742
743 // in case somehow is empty
744
745 if (trim($folder) == '') {
746 throw new Exception(esc_html__('The folder is not selected!','rsfirewall'));
747 }
748
749 if (!isset($accepted_folders[$folder])) {
750 throw new Exception(esc_html__('The folder must be one of the select options!','rsfirewall'));
751 }
752
753 if (!RSFirewall_Helper_Harden::add_file_to_whitelist($file, $accepted_folders[$folder])) {
754 throw new Exception(sprintf(__('The .htaccess from %s could not be written!','rsfirewall'), $file['folder']));
755 }
756 }
757
758 /**
759 * Function to display notices
760 */
761 public function admin_notice() {
762 $screen_id = RSFirewall_Helper::get_current_screen();
763
764 if ($screen_id =='rsfirewall_page_rsfirewall_configuration') {
765 ?>
766 <div class="notice notice-warning is-dismissible">
767 <p><?php echo wp_kses_post(__('Your IP address is currently detected as '.RSFirewall_Helper::get_ip().'.', 'rsfirewall')); ?></p>
768 </div>
769 <?php
770 }
771 }
772 }