%PDF- %PDF-
Direktori : /home/kfvehpdt/safsu.fr/wp-content/plugins/sucuri-scanner/src/ |
Current File : /home/kfvehpdt/safsu.fr/wp-content/plugins/sucuri-scanner/src/option.lib.php |
<?php /** * Code related to the option.lib.php interface. * * PHP version 5 * * @category Library * @package Sucuri * @subpackage SucuriScanner * @author Daniel Cid <dcid@sucuri.net> * @copyright 2010-2018 Sucuri Inc. * @license https://www.gnu.org/licenses/gpl-2.0.txt GPL2 * @link https://wordpress.org/plugins/sucuri-scanner */ if (!defined('SUCURISCAN_INIT') || SUCURISCAN_INIT !== true) { if (!headers_sent()) { /* Report invalid access if possible. */ header('HTTP/1.1 403 Forbidden'); } exit(1); } /** * Plugin options handler. * * Options are pieces of data that WordPress uses to store various preferences * and configuration settings. Listed below are the options, along with some of * the default values from the current WordPress install. By using the * appropriate function, options can be added, changed, removed, and retrieved, * from the wp_options table. * * The Options API is a simple and standardized way of storing data in the * database. The API makes it easy to create, access, update, and delete * options. All the data is stored in the wp_options table under a given custom * name. This page contains the technical documentation needed to use the * Options API. A list of default options can be found in the Option Reference. * * Note that the _site_ methods are essentially the same as their * counterparts. The only differences occur for WP Multisite, when the options * apply network-wide and the data is stored in the wp_sitemeta table under the * given custom name. * * @category Library * @package Sucuri * @subpackage SucuriScanner * @author Daniel Cid <dcid@sucuri.net> * @copyright 2010-2018 Sucuri Inc. * @license https://www.gnu.org/licenses/gpl-2.0.txt GPL2 * @link https://wordpress.org/plugins/sucuri-scanner * @see https://codex.wordpress.org/Option_Reference * @see https://codex.wordpress.org/Options_API */ class SucuriScanOption extends SucuriScanRequest { /** * Default values for all the plugin's options. * * @return array Default values for all the plugin's options. */ private static function getDefaultOptionValues() { $defaults = array( 'sucuriscan_account' => '', 'sucuriscan_addr_header' => 'HTTP_X_SUCURI_CLIENTIP', 'sucuriscan_api_key' => false, 'sucuriscan_api_protocol' => 'https', 'sucuriscan_api_service' => 'disabled', 'sucuriscan_auto_clear_cache' => 'disabled', 'sucuriscan_checksum_api' => '', 'sucuriscan_cloudproxy_apikey' => '', 'sucuriscan_diff_utility' => 'disabled', 'sucuriscan_dns_lookups' => 'enabled', 'sucuriscan_email_subject' => '', 'sucuriscan_emails_per_hour' => 5, 'sucuriscan_emails_sent' => 0, 'sucuriscan_ignored_events' => '', 'sucuriscan_last_email_at' => time(), 'sucuriscan_lastlogin_redirection' => 'enabled', 'sucuriscan_maximum_failed_logins' => 30, 'sucuriscan_notify_available_updates' => 'disabled', 'sucuriscan_notify_bruteforce_attack' => 'disabled', 'sucuriscan_notify_failed_login' => 'disabled', 'sucuriscan_notify_plugin_activated' => 'enabled', 'sucuriscan_notify_plugin_change' => 'enabled', 'sucuriscan_notify_plugin_deactivated' => 'disabled', 'sucuriscan_notify_plugin_deleted' => 'disabled', 'sucuriscan_notify_plugin_installed' => 'disabled', 'sucuriscan_notify_plugin_updated' => 'disabled', 'sucuriscan_notify_post_publication' => 'enabled', 'sucuriscan_notify_scan_checksums' => 'disabled', 'sucuriscan_notify_settings_updated' => 'enabled', 'sucuriscan_notify_success_login' => 'disabled', 'sucuriscan_notify_theme_activated' => 'enabled', 'sucuriscan_notify_theme_deleted' => 'disabled', 'sucuriscan_notify_theme_editor' => 'enabled', 'sucuriscan_notify_theme_installed' => 'disabled', 'sucuriscan_notify_theme_updated' => 'disabled', 'sucuriscan_notify_to' => '', 'sucuriscan_notify_user_registration' => 'disabled', 'sucuriscan_notify_website_updated' => 'disabled', 'sucuriscan_notify_widget_added' => 'disabled', 'sucuriscan_notify_widget_deleted' => 'disabled', 'sucuriscan_plugin_version' => '0.0', 'sucuriscan_prettify_mails' => 'disabled', 'sucuriscan_revproxy' => 'disabled', 'sucuriscan_runtime' => 0, 'sucuriscan_selfhosting_fpath' => '', 'sucuriscan_selfhosting_monitor' => 'disabled', 'sucuriscan_site_version' => '0.0', 'sucuriscan_sitecheck_target' => '', 'sucuriscan_timezone' => 'UTC+00.00', 'sucuriscan_use_wpmail' => 'enabled', 'sucuriscan_headers_cache_control' => 'disabled', 'sucuriscan_headers_cache_control_options' => array( 'front_page' => array( 'id' => 'front_page', 'title' => __('Front Page', 'sucuri-scanner'), 'max_age' => 21600, 's_maxage' => 0, 'stale_if_error' => 0, 'stale_while_revalidate' => 0, 'pagination_factor' => 'unavailable', 'old_age_multiplier' => 'unavailable', ), 'posts' => array( 'id' => 'posts', 'title' => __('Posts', 'sucuri-scanner'), 'max_age' => 43200, 's_maxage' => 0, 'stale_if_error' => 0, 'stale_while_revalidate' => 0, 'pagination_factor' => 'unavailable', 'old_age_multiplier' => true, ), 'pages' => array( 'id' => 'pages', 'title' => __('Pages', 'sucuri-scanner'), 'max_age' => 86400, 's_maxage' => 0, 'stale_if_error' => 0, 'stale_while_revalidate' => 0, 'pagination_factor' => 'unavailable', 'old_age_multiplier' => 'unavailable', ), 'main_index' => array( 'id' => 'main_index', 'title' => __('Main Index', 'sucuri-scanner'), 'max_age' => 21600, 's_maxage' => 0, 'stale_if_error' => 0, 'stale_while_revalidate' => 0, 'pagination_factor' => 5, 'old_age_multiplier' => 'unavailable', ), 'categories' => array( 'id' => 'categories', 'title' => __('Categories', 'sucuri-scanner'), 'max_age' => 86400, 's_maxage' => 0, 'stale_if_error' => 0, 'stale_while_revalidate' => 0, 'pagination_factor' => 8, 'old_age_multiplier' => 'unavailable', ), 'tags' => array( 'id' => 'tags', 'title' => __('Tags', 'sucuri-scanner'), 'max_age' => 86400, 's_maxage' => 0, 'stale_if_error' => 0, 'stale_while_revalidate' => 0, 'pagination_factor' => 10, 'old_age_multiplier' => 'unavailable', ), 'authors' => array( 'id' => 'authors', 'title' => __('Authors', 'sucuri-scanner'), 'max_age' => 86400, 's_maxage' => 0, 'stale_if_error' => 0, 'stale_while_revalidate' => 0, 'pagination_factor' => 10, 'old_age_multiplier' => 'unavailable', ), 'archives' => array( 'id' => 'archives', 'title' => __('Archives', 'sucuri-scanner'), 'max_age' => 86400, 's_maxage' => 0, 'stale_if_error' => 0, 'stale_while_revalidate' => 0, 'pagination_factor' => 'unavailable', 'old_age_multiplier' => 'unavailable', ), 'feeds' => array( 'id' => 'feeds', 'title' => __('Feeds', 'sucuri-scanner'), 'max_age' => 21600, 's_maxage' => 0, 'stale_if_error' => 0, 'stale_while_revalidate' => 0, 'pagination_factor' => 'unavailable', 'old_age_multiplier' => 'unavailable', ), 'attachment_pages' => array( 'id' => 'attachment_pages', 'title' => __('Attachment Pages', 'sucuri-scanner'), 'max_age' => 86400, 's_maxage' => 0, 'stale_if_error' => 0, 'stale_while_revalidate' => 0, 'pagination_factor' => 'unavailable', 'old_age_multiplier' => 'unavailable', ), 'search_results' => array( 'id' => 'search_results', 'title' => __('Search Results', 'sucuri-scanner'), 'max_age' => 86400, 's_maxage' => 0, 'stale_if_error' => 0, 'stale_while_revalidate' => 0, 'pagination_factor' => 'unavailable', 'old_age_multiplier' => 'unavailable', ), '404_not_found' => array( 'id' => '404_not_found', 'title' => __('404 Not Found', 'sucuri-scanner'), 'max_age' => 86400, 's_maxage' => 0, 'stale_if_error' => 0, 'stale_while_revalidate' => 0, 'pagination_factor' => 'unavailable', 'old_age_multiplier' => 'unavailable', ), 'redirects' => array( 'id' => 'attachment', 'title' => __('Redirects', 'sucuri-scanner'), 'max_age' => 86400, 's_maxage' => 0, 'stale_if_error' => 0, 'stale_while_revalidate' => 0, 'pagination_factor' => 'unavailable', 'old_age_multiplier' => 'unavailable', ), 'woocommerce_products' => array( 'id' => 'woocommerce_products', 'title' => __('Woocommerce Products', 'sucuri-scanner'), 'max_age' => 86400, 's_maxage' => 0, 'stale_if_error' => 0, 'stale_while_revalidate' => 0, 'pagination_factor' => 'unavailable', 'old_age_multiplier' => 'unavailable', ), 'woocommerce_categories' => array( 'id' => 'woocommerce_categories', 'title' => __('Woocommerce Categories', 'sucuri-scanner'), 'max_age' => 86400, 's_maxage' => 0, 'stale_if_error' => 0, 'stale_while_revalidate' => 0, 'pagination_factor' => 'unavailable', 'old_age_multiplier' => 'unavailable', ), ) ); return (array)apply_filters('sucuriscan_option_defaults', $defaults); } /** * Name of all valid plugin's options. * * @return array Name of all valid plugin's options. */ public static function getDefaultOptionNames() { $options = self::getDefaultOptionValues(); $names = array_keys($options); return $names; } /** * Retrieve the default values for some specific options. * * @param string $option List of options, or single option name. * @return mixed The default values for the specified options. */ private static function getDefaultOptions($option = '') { $default = self::getDefaultOptionValues(); // Use framework built-in function. if (function_exists('get_option')) { $admin_email = get_option('admin_email'); $default['sucuriscan_account'] = $admin_email; $default['sucuriscan_notify_to'] = $admin_email; $default['sucuriscan_email_subject'] = sprintf(__('Sucuri Alert, %s, %s, %s', 'sucuri-scanner'), ':domain', ':event', ':remoteaddr'); } return @$default[$option]; } /** * Returns path of the options storage. * * Returns the absolute path of the file that will store the options * associated to the plugin. This must be a PHP file without public access, * for which reason it will contain a header with an exit point to prevent * malicious people to read the its content. The rest of the file will * content a JSON encoded array. * * @return string File path of the options storage. */ public static function optionsFilePath() { return self::dataStorePath('sucuri-settings.php'); } /** * Returns an array with all the plugin options. * * NOTE: There is a maximum number of lines for this file, one is for the * exit point and the other one is for a single line JSON encoded string. * We will discard any other content that exceeds this limit. * * @return array Array with all the plugin options. */ public static function getAllOptions() { $options = wp_cache_get('alloptions', SUCURISCAN); if ($options && is_array($options)) { return $options; } $options = array(); $fpath = self::optionsFilePath(); /* Use this over SucuriScanCache to prevent nested method calls */ $content = SucuriScanFileInfo::fileContent($fpath); if ($content !== false) { // Refer to self::optionsFilePath to know why the number two. $lines = explode("\n", $content, 2); if (count($lines) >= 2) { $jsonData = json_decode($lines[1], true); if (is_array($jsonData) && !empty($jsonData)) { $options = $jsonData; } } } wp_cache_set('alloptions', $options, SUCURISCAN); return $options; } /** * Write new options into the external options file. * * @param array $options Array with plugins options. * @return bool True if the new options were saved, false otherwise. */ public static function writeNewOptions($options = array()) { wp_cache_delete('alloptions', SUCURISCAN); $fpath = self::optionsFilePath(); $content = "<?php exit(0); ?>\n"; $content .= @json_encode($options) . "\n"; return (bool)@file_put_contents($fpath, $content); } /** * Returns data from the settings file or the database. * * To facilitate the development, you can prefix the name of the key in the * request (when accessing it) with a single colon, this method will automa- * tically replace that character with the unique identifier of the plugin. * * NOTE: The SucuriScanCache library is a better interface to read the * content of a configuration file following the same standard in the other * files associated to the plugin. However, this library makes use of this * method to retrieve the directory where the files are stored, if we use * this library for this specific task we will end up provoking a maximum * nesting method call warning. * * @see https://developer.wordpress.org/reference/functions/get_option/ * * @param string $option Name of the option. * @return mixed Value associated to the option. */ public static function getOption($option = '') { $options = self::getAllOptions(); $option = self::varPrefix($option); if (array_key_exists($option, $options)) { return $options[$option]; } /** * Fallback to the default values. * * If the option is not set in the external options file then we must * search in the database for older data, this to provide backward * compatibility with older installations of the plugin. If the option * is found in the database we must insert it in the external file and * delete it from the database before the value is returned to the user. * * If the option is not in the external file nor in the database, and * the name starts with the same prefix used by the plugin then we must * return the default value defined by the author. * * Note that if the plain text file is not writable the method should * not delete the option from the database to keep backward compatibility * with previous installations of the plugin. */ if (function_exists('get_option')) { $value = get_option($option); if ($value !== false) { if (strpos($option, SUCURISCAN . '_') === 0) { $written = self::updateOption($option, $value); if ($written === true) { delete_option($option); } } return $value; } } /** * Cache default value to stop querying the database. * * The option was not found in the database either, we will return the * data from the array of default values hardcoded in the source code, * then will attempt to write the default value into the flat settings * file to stop querying the database in subsequent requests. */ if (strpos($option, SUCURISCAN . '_') === 0) { $value = self::getDefaultOptions($option); self::updateOption($option, $value); return $value; } return false; } /** * Update the value of an database' option. * * Use the method to update a named option/value pair to the options database * table. The option name value is escaped with a special database method before * the insert SQL statement but not the option value, this value should always * be properly sanitized. * * @see https://developer.wordpress.org/reference/functions/update_option/ * * @param string $option Name of the option. * @param mixed $value New value for the option. * @return bool True if option has been updated, false otherwise. */ public static function updateOption($option = '', $value = '') { if (strpos($option, ':') === 0 || strpos($option, SUCURISCAN) === 0) { $options = self::getAllOptions(); $option = self::varPrefix($option); $options[$option] = $value; return self::writeNewOptions($options); } return update_option($option, $value); } /** * Remove an option from the database. * * A safe way of removing a named option/value pair from the options database table. * * @see https://developer.wordpress.org/reference/functions/delete_option/ * * @param string $option Name of the option to be deleted. * @return bool True if option is successfully deleted, false otherwise. */ public static function deleteOption($option = '') { if (strpos($option, ':') === 0 || strpos($option, SUCURISCAN) === 0) { $options = self::getAllOptions(); $option = self::varPrefix($option); // Create/Modify option's value. if (array_key_exists($option, $options)) { unset($options[$option]); return self::writeNewOptions($options); } } return delete_option($option); } /** * Check whether a setting is enabled or not. * * @param string $option Name of the option to be deleted. * @return bool True if the option is enabled, false otherwise. */ public static function isEnabled($option = '') { return (bool)(self::getOption($option) === 'enabled'); } /** * Check whether a setting is disabled or not. * * @param string $option Name of the option to be deleted. * @return bool True if the option is disabled, false otherwise. */ public static function isDisabled($option = '') { return (bool)(self::getOption($option) === 'disabled'); } /** * Retrieve all the options stored by Wordpress in the database. The options * containing the word "transient" are excluded from the results, this method * compatible with multisite instances. * * @return array All the options stored by Wordpress in the database. */ private static function getSiteOptions() { $settings = array(); if (array_key_exists('wpdb', $GLOBALS)) { $results = $GLOBALS['wpdb']->get_results( 'SELECT * FROM ' . $GLOBALS['wpdb']->options . ' WHERE opti' . 'on_name NOT LIKE "%_transient_%" ORDER BY option_id ASC' ); foreach ($results as $row) { $settings[$row->option_name] = $row->option_value; } } $external = self::getAllOptions(); foreach ($external as $option => $value) { $settings[$option] = $value; } return $settings; } /** * Check what Wordpress options were changed comparing the values in the database * with the values sent through a simple request using a GET or POST method. * * @param array $request The content of the global variable GET or POST considering SERVER[REQUEST_METHOD]. * @return array A list of all the options that were changes through this request. */ public static function whatOptionsWereChanged($request = array()) { $options_changed = array( 'original' => array(), 'changed' => array() ); $site_options = self::getSiteOptions(); foreach ($request as $req_name => $req_value) { if (array_key_exists($req_name, $site_options) && $site_options[$req_name] != $req_value ) { $options_changed['original'][$req_name] = $site_options[$req_name]; $options_changed['changed'][$req_name] = $req_value; } } return $options_changed; } /** * Check the nonce comming from any of the settings pages. * * @return bool True if the nonce is valid, false otherwise. */ public static function checkOptionsNonce() { // Create the option_page value if permalink submission. if (!isset($_POST['option_page']) && isset($_POST['permalink_structure'])) { $_POST['option_page'] = 'permalink'; } /* check if the option_page has an allowed value */ $option_page = SucuriScanRequest::post('option_page'); if (!$option_page) { return false; } $action = ''; $nonce = '_wpnonce'; switch ($option_page) { case 'general': /* no_break */ case 'writing': /* no_break */ case 'reading': /* no_break */ case 'discussion': /* no_break */ case 'media': /* no_break */ case 'options': /* no_break */ $action = $option_page . '-options'; break; case 'permalink': $action = 'update-permalink'; break; } /* check the nonce validity */ return (bool)( !empty($action) && isset($_REQUEST[$nonce]) && wp_verify_nonce($_REQUEST[$nonce], $action) ); } /** * Returns a list of post-types. * * The list of post-types includes objects such as Post and Page but also * the transitions between each post type, for example, if there are posts * of type Draft and they change to Trash, this function will include a new * post type called "from_draft_to_trash" and so on. * * @return array List of post-types with transitions. */ public static function getPostTypes() { $postTypes = get_post_types(); $transitions = array( 'new', 'publish', 'pending', 'draft', 'auto-draft', 'future', 'private', 'inherit', 'trash', ); /* include post-type transitions */ foreach ($transitions as $from) { foreach ($transitions as $to) { if ($from === $to) { continue; } $event = sprintf('from_%s_to_%s', $from, $to); if (!array_key_exists($event, $postTypes)) { $postTypes[$event] = $event; } } } /* include custom non-registered post-types */ $ignoredEvents = SucuriScanOption::getIgnoredEvents(); foreach ($ignoredEvents as $event => $time) { if (!array_key_exists($event, $postTypes)) { $postTypes[$event] = $event; } } return $postTypes; } /** * Check whether an event is being ignored to send alerts or not. * * @param string $event Unique post-type name. * @return bool Whether an event is being ignored or not. */ public static function isIgnoredEvent($event = '') { $event = strtolower($event); $ignored = self::getIgnoredEvents(); return array_key_exists($event, $ignored); } /** * Get a list of the post types ignored to receive email alerts when the * "new site content" hook is triggered. * * @return array List of ignored posts-types to send alerts. */ public static function getIgnoredEvents() { $post_types = self::getOption(':ignored_events'); if (is_string($post_types)) { $post_types = @json_decode($post_types, true); } return (array)$post_types; } /** * Retrieve a list of basic security keys and check whether their values were * randomized correctly. * * @return array Array with three keys: good, missing, bad. */ public static function getSecurityKeys() { $response = array( 'good' => array(), 'missing' => array(), 'bad' => array(), ); $key_names = array( 'AUTH_KEY', 'AUTH_SALT', 'LOGGED_IN_KEY', 'LOGGED_IN_SALT', 'NONCE_KEY', 'NONCE_SALT', 'SECURE_AUTH_KEY', 'SECURE_AUTH_SALT', ); foreach ($key_names as $key_name) { if (defined($key_name)) { $key_value = constant($key_name); if (stripos($key_value, 'unique phrase') !== false) { $response['bad'][$key_name] = $key_value; } else { $response['good'][$key_name] = $key_value; } } else { $response['missing'][$key_name] = false; } } return $response; } /** * Change the reverse proxy setting. * * When enabled this option forces the plugin to override the value of the * global IP address variable from the HTTP header selected by the user from * the settings. Note that this may also be automatically enabled when the * firewall page is activated as it assumes that the proxy is creating a * custom HTTP header for the real IP. * * @param string $action Enable or disable the reverse proxy. * @param bool $silent Hide admin notices on success. * @return void */ public static function setRevProxy($action = 'disable', $silent = false) { if ($action !== 'enable' && $action !== 'disable') { return self::deleteOption(':revproxy'); } $action_d = $action . 'd'; $message = 'Reverse proxy support was <code>' . $action_d . '</code>'; self::updateOption(':revproxy', $action_d); SucuriScanEvent::reportInfoEvent($message); SucuriScanEvent::notifyEvent('plugin_change', $message); if ($silent) { return true; } return SucuriScanInterface::info( sprintf( 'Reverse proxy support was set to <b>%s</b>', $action_d /* either enabled or disabled */ ) ); } /** * Change the HTTP header to retrieve the real IP address. * * @param string $header Valid HTTP header name. * @param bool $silent Hide admin notices on success. * @return void */ public static function setAddrHeader($header = 'REMOTE_ADDR', $silent = false) { $header = strtoupper($header); $allowed = SucuriScan::allowedHttpHeaders(true); if (!array_key_exists($header, $allowed)) { return SucuriScanInterface::error('HTTP header is not allowed'); } $message = sprintf('HTTP header was set to %s', $header); self::updateOption(':addr_header', $header); SucuriScanEvent::reportInfoEvent($message); SucuriScanEvent::notifyEvent('plugin_change', $message); if ($silent) { return true; } return SucuriScanInterface::info( sprintf( 'HTTP header was set to <code>%s</code>', $header /* one of the allowed HTTP headers */ ) ); } }