* @license GPL-3.0 * @link https://www.ipgeoblock.com/ * @copyright 2013-2019 tokkonopapa */ class IP_Geo_Block_Admin { /** * Constants for admin class * */ const INTERVAL_LIVE_UPDATE = 5; // interval for live update [sec] const TIMEOUT_LIVE_UPDATE = 60; // timeout of pausing live update [sec] /** * Globals in this class * */ private static $instance = NULL; private $is_network_admin = FALSE; private $admin_tab = 0; /** * Initialize the plugin by loading admin scripts & styles * and adding a settings page and menu. */ private function __construct() { // Setup the tab number. $this->admin_tab = isset( $_GET['tab'] ) ? (int)$_GET['tab'] : 0; $this->admin_tab = min( 5, max( 0, $this->admin_tab ) ); // Load plugin text domain and add body class add_action( 'init', array( $this, 'admin_init' ) ); // Add suggest text for inclusion in the site's privacy policy. @since 4.9.6 // add_action( 'admin_init', array( $this, 'add_privacy_policy' ) ); // Setup a nonce to validate authentication. add_filter( 'wp_redirect', array( $this, 'add_redirect_nonce' ), 10, 2 ); // @since 2.1.0 } /** * Return an instance of this class. * */ public static function get_instance() { return self::$instance ? self::$instance : ( self::$instance = new self ); } /** * Load the plugin text domain for translation and add body class. * */ public function admin_init() { // include drop in for admin if it exists $settings = IP_Geo_Block::get_option(); file_exists( $file = IP_Geo_Block_Util::unslashit( $settings['api_dir'] ) . '/drop-in-admin.php' ) and include( $file ); // Add the options page and menu item. add_action( 'admin_menu', array( $this, 'setup_admin_page' ) ); // @since: 2.5.0 add_action( 'admin_post_ip_geo_block', array( $this, 'admin_ajax_callback' ) ); // @since: 2.6.0 add_action( 'wp_ajax_ip_geo_block', array( $this, 'admin_ajax_callback' ) ); // @since: 2.1.0 add_filter( 'wp_prepare_revision_for_js', array( $this, 'add_revision_nonce' ), 10, 3 ); if ( IP_Geo_Block_Util::is_user_logged_in() ) add_filter( IP_Geo_Block::PLUGIN_NAME . '-bypass-admins', array( $this, 'verify_request' ), 10, 2 ); if ( is_multisite() && is_plugin_active_for_network( IP_GEO_BLOCK_BASE ) ) { // @since: 3.0.0 $this->is_network_admin = current_user_can( 'manage_network_options' ); add_action( 'network_admin_menu', array( $this, 'setup_admin_page' ) ); // @since: 2.5 add_action( 'wpmu_new_blog', array( $this, 'create_blog' ), 10, 6 ); // on creating a new blog @since MU add_action( 'delete_blog', array( $this, 'delete_blog' ), 10, 2 ); // on deleting an old blog @since 3.0.0 } // loads a plugin’s translated strings. load_plugin_textdomain( IP_Geo_Block::PLUGIN_NAME, FALSE, dirname( IP_GEO_BLOCK_BASE ) . '/languages/' ); // add webview class into body tag. // https://stackoverflow.com/questions/37591279/detect-if-user-is-using-webview-for-android-ios-or-a-regular-browser if ( isset( $_SERVER['HTTP_USER_AGENT'] ) && ( strpos( $_SERVER['HTTP_USER_AGENT'], 'Mobile/' ) !== FALSE ) && ( strpos( $_SERVER['HTTP_USER_AGENT'], 'Safari/' ) === FALSE ) ) { add_filter( 'admin_body_class', array( $this, 'add_webview_class' ) ); } // for Android elseif ( isset( $_SERVER['HTTP_X_REQUESTED_WITH'] ) && $_SERVER['HTTP_X_REQUESTED_WITH'] === "com.company.app" ) { add_filter( 'admin_body_class', array( $this, 'add_webview_class' ) ); } } /** * Whether this plugin activated by network or not. * */ public function is_network_admin() { return $this->is_network_admin; } /** * Add webview class into the body. * */ public function add_webview_class( $classes ) { return $classes . ($classes ? ' ' : '') . 'webview'; } /** * Add nonce when redirect into wp-admin area. * */ public function add_redirect_nonce( $location, $status ) { $status = TRUE; // default is `retrieve` a nonce $urls = array( wp_login_url() ); // avoid multiple redirection caused by WP hide 1.4.9.1 if ( is_plugin_active( 'wp-hide-security-enhancer/wp-hide.php' ) ) $urls[] = 'options-permalink.php'; foreach ( $urls as $url ) { if ( FALSE !== strpos( $location, $url ) ) { $status = FALSE; // do not `retieve` a nonce break; } } return IP_Geo_Block_Util::rebuild_nonce( $location, $status ); } /** * Add nonce to revision @since 4.4.0 * */ public function add_revision_nonce( $revisions_data, $revision, $post ) { $revisions_data['restoreUrl'] = add_query_arg( $nonce = IP_Geo_Block::get_auth_key(), IP_Geo_Block_Util::create_nonce( $nonce ), $revisions_data['restoreUrl'] ); return $revisions_data; } /** * Verify admin screen without action instead of validating nonce. * */ public function verify_request( $queries, $settings ) { // the request that is intended to show the page without any action follows authentication of core. if ( 'GET' === $_SERVER['REQUEST_METHOD'] && isset( $_GET['page'] ) ) { foreach ( array( 'action', 'task') as $key ) { if ( ! empty( $_GET[ $key ] ) ) return $queries; } $queries[] = $_GET['page']; } return $queries; } /** * Do some procedures when a blog is created or deleted. * */ public function create_blog( $blog_id, $user_id, $domain, $path, $site_id, $meta ) { defined( 'IP_GEO_BLOCK_DEBUG' ) and IP_GEO_BLOCK_DEBUG and assert( is_main_site(), 'Not main blog.' ); require_once IP_GEO_BLOCK_PATH . 'classes/class-ip-geo-block-actv.php'; // get options on main blog $settings = IP_Geo_Block::get_option(); // Switch to the new blog and initialize. switch_to_blog( $blog_id ); IP_Geo_Block_Activate::activate_blog(); // Copy option from main blog. if ( $this->is_network_admin && $settings['network_wide'] ) IP_Geo_Block::update_option( $settings, FALSE ); // Restore the main blog. restore_current_blog(); } public function delete_blog( $blog_id, $drop ) { // blog is already switched to the target in wpmu_delete_blog() $drop and IP_Geo_Block_Logs::delete_tables(); } /** * Get the action name of ajax for nonce * */ private function get_ajax_action() { return IP_Geo_Block::PLUGIN_NAME . '-ajax-action'; } /** * Register and enqueue plugin-specific style sheet and JavaScript. * * @see https://developers.google.com/maps/faq#china_ws_access */ public function enqueue_admin_assets() { $release = ( ! defined( 'IP_GEO_BLOCK_DEBUG' ) || ! IP_GEO_BLOCK_DEBUG ); $footer = TRUE; $dependency = array( 'jquery' ); $version = $release ? IP_Geo_Block::VERSION : max( filemtime( plugin_dir_path( __FILE__ ) . 'css/admin.css' ), filemtime( plugin_dir_path( __FILE__ ) . 'js/admin.js' ) ); switch ( $this->admin_tab ) { case 1: /* Statistics */ case 4: /* Logs */ // css and js for DataTables wp_enqueue_style( IP_Geo_Block::PLUGIN_NAME . '-datatables-css', plugins_url( 'datatables/css/datatables-all.min.css', __FILE__ ), array(), IP_Geo_Block::VERSION ); wp_enqueue_script( IP_Geo_Block::PLUGIN_NAME . '-datatables-js', plugins_url( 'datatables/js/datatables-all.min.js', __FILE__ ), $dependency, IP_Geo_Block::VERSION, $footer ); if ( 4 === $this->admin_tab ) break; case 5: /* Sites list */ // js for google charts wp_register_script( $addon = IP_Geo_Block::PLUGIN_NAME . '-google-chart', apply_filters( 'google-charts', 'https://www.gstatic.com/charts/loader.js' ), array(), NULL, $footer ); wp_enqueue_script( $addon ); break; case 2: /* Search */ // Google Map in China $geo = IP_Geo_Block::get_geolocation(); if ( isset( $geo['code'] ) && 'CN' === $geo['code'] ) { add_filter( 'google-charts', array( $this, 'google_charts_cn' ) ); add_filter( 'google-maps', array( $this, 'google_maps_cn' ) ); add_filter( 'google-maps-nokey', array( $this, 'google_maps_nokey_cn' ) ); } // js for google map $settings = IP_Geo_Block::get_option(); if ( $key = $settings['api_key']['GoogleMap'] ) { wp_enqueue_script( IP_Geo_Block::PLUGIN_NAME . '-gmap-js', plugins_url( $release ? 'js/gmap.min.js' : 'js/gmap.js', __FILE__ ), $dependency, IP_Geo_Block::VERSION, $footer ); wp_enqueue_script( IP_Geo_Block::PLUGIN_NAME . '-google-map', apply_filters( 'google-maps', '//maps.googleapis.com/maps/api/js' ) . ( 'default' !== $key ? "?key=$key" : '' ), $dependency, IP_Geo_Block::VERSION, $footer ); } wp_enqueue_script( IP_Geo_Block::PLUGIN_NAME . '-whois-js', plugins_url( $release ? 'js/whois.min.js' : 'js/whois.js', __FILE__ ), $dependency, IP_Geo_Block::VERSION, $footer ); break; } // css for option page wp_enqueue_style( IP_Geo_Block::PLUGIN_NAME . '-admin-icons', plugins_url( $release ? 'css/admin-icons.min.css' : 'css/admin-icons.css', __FILE__ ), array(), IP_Geo_Block::VERSION ); wp_enqueue_style( IP_Geo_Block::PLUGIN_NAME . '-admin-styles', plugins_url( $release ? 'css/admin.min.css' : 'css/admin.css', __FILE__ ), array(), $version ); // js for IP Geo Block admin page wp_register_script( $handle = IP_Geo_Block::PLUGIN_NAME . '-admin-script', plugins_url( $release ? 'js/admin.min.js' : 'js/admin.js', __FILE__ ), $dependency + ( isset( $addon ) ? array( $addon ) : array() ), $version, $footer ); wp_localize_script( $handle, 'IP_GEO_BLOCK', array( 'action' => 'ip_geo_block', 'tab' => $this->admin_tab, 'url' => admin_url( 'admin-ajax.php' ), 'nonce' => IP_Geo_Block_Util::create_nonce( $this->get_ajax_action() ), 'msg' => array( /* [ 0] */ __( 'Are you sure ?', 'ip-geo-block' ), /* [ 1] */ __( 'Open a new window', 'ip-geo-block' ), /* [ 2] */ __( 'Generate new link', 'ip-geo-block' ), /* [ 3] */ __( 'Delete current link', 'ip-geo-block' ), /* [ 4] */ __( 'Please add the following link to favorites / bookmarks in your browser : ', 'ip-geo-block' ), /* [ 5] */ __( 'ajax for logged-in user', 'ip-geo-block' ), /* [ 6] */ __( 'ajax for non logged-in user', 'ip-geo-block' ), /* [ 7] */ __( '[Found: %d]', 'ip-geo-block' ), /* [ 8] */ __( 'Find and verify `%s` on “Logs” tab.', 'ip-geo-block' ), /* [ 9] */ __( 'This feature is available with HTML5 compliant browsers.', 'ip-geo-block' ), /* [10] */ __( 'The selected row cannot be found in the table.', 'ip-geo-block' ), /* [11] */ __( 'An error occurred while executing the ajax command `%s`.', 'ip-geo-block' ), ), 'i18n' => array( /* [ 0] */ '
', /* [ 1] */ __( 'No data available in table', 'ip-geo-block' ), /* [ 2] */ __( 'No matching records found', 'ip-geo-block' ), /* [ 3] */ __( 'IP address', 'ip-geo-block' ), /* [ 4] */ __( 'Code', 'ip-geo-block' ), /* [ 5] */ __( 'ASN', 'ip-geo-block' ), /* [ 6] */ __( 'Host name', 'ip-geo-block' ), /* [ 7] */ __( 'Target', 'ip-geo-block' ), /* [ 8] */ __( 'Failure / Total', 'ip-geo-block' ), /* [ 9] */ __( 'Elapsed[sec]', 'ip-geo-block' ), /* [10] */ __( 'Time', 'ip-geo-block' ), /* [11] */ __( 'Result', 'ip-geo-block' ), /* [12] */ __( 'Request', 'ip-geo-block' ), /* [13] */ __( 'User agent', 'ip-geo-block' ), /* [14] */ __( 'HTTP headers', 'ip-geo-block' ), /* [15] */ __( '$_POST data', 'ip-geo-block' ), ), 'interval' => self::INTERVAL_LIVE_UPDATE, // interval for live update [sec] 'timeout' => self::TIMEOUT_LIVE_UPDATE, // timeout of pausing live update [sec] 'altgmap' => apply_filters( 'google-maps-nokey', 'https://www.google.com/maps/embed' ), ) ); wp_enqueue_script( $handle ); } /** * Google Map in China * */ public function google_charts_cn ( $url ) { return 'https://www.gstatic.cn/charts/loader.js'; } public function google_maps_cn ( $url ) { return '//maps.google.cn/maps/api/js'; } public function google_maps_nokey_cn( $url ) { return '//maps.google.cn/maps'; } /** * Add plugin meta links * */ public function add_plugin_meta_links( $links, $file ) { if ( $file === IP_GEO_BLOCK_BASE ) { array_push( $links, '' . __( 'Contribute on GitHub', 'ip-geo-block' ) . '' ); } return $links; } /** * Add settings action link to the plugins page. * */ public function add_action_links( $links ) { $settings = IP_Geo_Block::get_option(); return array_merge( array( 'settings' => '' . __( 'Settings' ) . '' ), $links ); } /** * Add suggest text for inclusion in the site's privacy policy. @since 4.9.6 * * /wp-admin/tools.php?wp-privacy-policy-guide * https://developer.wordpress.org/plugins/privacy/privacy-related-options-hooks-and-capabilities/ */ public function add_privacy_policy() { if ( function_exists( 'wp_add_privacy_policy_content' ) ) wp_add_privacy_policy_content( 'IP Geo Block', __( 'suggested text.', 'ip-geo-block' ) ); } /** * Show global notice. * */ public function show_admin_notices() { $key = IP_Geo_Block::PLUGIN_NAME . '-notice'; if ( FALSE !== ( $notices = get_transient( $key ) ) ) { foreach ( $notices as $msg => $type ) { echo "\n", ''; if ( 'updated' === $type ) echo '', IP_Geo_Block_Util::kses( $msg ), ''; else echo 'IP Geo Block: ', IP_Geo_Block_Util::kses( $msg ); echo '
%s. It seems to have failed downloading ZIP file from WordPress-IP-Geo-API. Try to deactivate IP Geo Block once and activate it again, or install ip-geo-api with write permission according to this instruction.', 'ip-geo-block' ),
apply_filters( 'ip-geo-block-api-dir', $settings['api_dir'] ? $settings['api_dir'] : basename( WP_CONTENT_DIR ) )
) );
}
else {
$providers = IP_Geo_Block_Provider::get_valid_providers( $settings, FALSE, FALSE, TRUE );
if ( empty( $providers ) ) {
$this->add_admin_notice( 'error', sprintf(
__( 'You should select at least one API at Geolocation API settings. Otherwise you\'ll be blocked after the cache expires.', 'ip-geo-block' ),
esc_url( add_query_arg( array( 'page' => IP_Geo_Block::PLUGIN_NAME, 'tab' => 0, 'sec' => 4 ), $network ) ) . '#' . IP_Geo_Block::PLUGIN_NAME . '-section-4'
) );
}
else {
$providers = IP_Geo_Block_Provider::get_addons( $settings['providers'] );
if ( empty( $providers ) ) {
$this->add_admin_notice( 'error', sprintf(
__( 'You should select at least one API for local database at Geolocation API settings. Otherwise access to the external API may slow down the site.', 'ip-geo-block' ),
esc_url( add_query_arg( array( 'page' => IP_Geo_Block::PLUGIN_NAME, 'tab' => 0, 'sec' => 4 ), $network ) ) . '#' . IP_Geo_Block::PLUGIN_NAME . '-section-4'
) );
}
}
}
// Check consistency of matching rule
if ( -1 === (int)$settings['matching_rule'] ) {
if ( FALSE !== $updating ) {
self::add_admin_notice( 'notice-warning', sprintf(
__( 'Now downloading geolocation databases in background. After a little while, please check your country code and “Matching rule” at Validation rules and behavior.', 'ip-geo-block' ),
esc_url( add_query_arg( array( 'page' => IP_Geo_Block::PLUGIN_NAME ), $network ) )
) );
}
else {
self::add_admin_notice( 'error', sprintf(
__( 'The “Matching rule” is not set properly. Please confirm it at Validation rules and behavior.', 'ip-geo-block' ),
esc_url( add_query_arg( array( 'page' => IP_Geo_Block::PLUGIN_NAME ), $network ) )
) );
}
}
// Check to finish updating matching rule
elseif ( 'done' === $updating ) {
delete_transient( IP_Geo_Block::CRON_NAME );
self::add_admin_notice( 'updated ', __( 'Local database and matching rule have been updated.', 'ip-geo-block' ) );
}
// Check self blocking (skip during updating)
if ( FALSE === $updating && 1 === (int)$settings['validation']['login'] ) {
$instance = IP_Geo_Block::get_instance();
$validate = $instance->validate_ip( 'login', $settings, TRUE, FALSE ); // skip authentication check
switch( $validate['result'] ) {
case 'limited':
self::add_admin_notice( 'error',
__( 'Once you logout, you will be unable to login again because the number of login attempts reaches the limit.', 'ip-geo-block' ) . ' ' .
sprintf(
__( 'Please remove your IP address in “%1$sStatistics in IP address cache%2$s” on “%3$sStatistics%4$s” tab to prevent locking yourself out.', 'ip-geo-block' ),
'', '',
'', ''
)
);
break;
case 'blocked':
case 'extra':
self::add_admin_notice( 'error',
( $settings['matching_rule'] ?
__( 'Once you logout, you will be unable to login again because your country code or IP address is in the blacklist.', 'ip-geo-block' ) :
__( 'Once you logout, you will be unable to login again because your country code or IP address is not in the whitelist.', 'ip-geo-block' )
) . ' ' .
( 'ZZ' !== $validate['code'] ?
sprintf(
__( 'Please check your “%sValidation rules and behavior%s”.', 'ip-geo-block' ),
'', ''
) :
sprintf(
__( 'Please confirm your local geolocation database files exist at “%sLocal database settings%s” section, or remove your IP address in cache at “%sStatistics in cache%s” section.', 'ip-geo-block' ),
'', '',
'', ''
)
)
);
break;
}
}
// Check consistency of emergency login link
if ( isset( $settings['login_link'] ) && $settings['login_link']['link'] && ! IP_Geo_Block_Util::verify_link( $settings['login_link']['link'], $settings['login_link']['hash'] ) ) {
self::add_admin_notice( 'error',
sprintf(
__( 'Emergency login link is outdated. Please delete it once and generate again at “%sPlugin settings%s” section. Also do not forget to update favorites / bookmarks in your browser.', 'ip-geo-block' ),
'', ''
)
);
}
// Check activation of IP Geo Allow
if ( $settings['validation']['timing'] && is_plugin_active( 'ip-geo-allow/index.php' ) ) {
self::add_admin_notice( 'error',
__( '“mu-plugins” (ip-geo-block-mu.php) at “Validation timing” is imcompatible with IP Geo Allow. Please select “init” action hook.', 'ip-geo-block' )
);
}
}
/**
* Setup menu and option page for this plugin
*
*/
public function setup_admin_page() {
$settings = IP_Geo_Block::get_option();
// Register the administration menu.
$this->add_plugin_admin_menu( $settings );
// Avoid multiple validation.
if ( 'GET' === $_SERVER['REQUEST_METHOD'] )
$this->diagnose_admin_screen( $settings );
// Register settings page only if it is needed.
if ( ( isset( $_GET ['page' ] ) && IP_Geo_Block::PLUGIN_NAME === $_GET ['page' ] ) ||
( isset( $_POST['option_page'] ) && IP_Geo_Block::PLUGIN_NAME === $_POST['option_page'] ) ) {
$this->register_settings_tab();
}
// Add an action link pointing to the options page. @since 2.7
else {
add_filter( 'plugin_row_meta', array( $this, 'add_plugin_meta_links' ), 10, 2 );
add_filter( 'plugin_action_links_' . IP_GEO_BLOCK_BASE, array( $this, 'add_action_links' ), 10, 1 );
}
// Register scripts for admin.
add_action( 'admin_enqueue_scripts', array( 'IP_Geo_Block', 'enqueue_nonce' ), 0 );
// Show admin notices at the place where it should be. @since 2.5.0
add_action( 'admin_notices', array( $this, 'show_admin_notices' ) );
add_action( 'network_admin_notices', array( $this, 'show_admin_notices' ) );
}
/**
* Get cookie that indicates open/close section
*
*/
public function get_cookie() {
static $cookie = array();
if ( empty( $cookie ) && ! empty( $_COOKIE[ IP_Geo_Block::PLUGIN_NAME ] ) ) {
foreach ( explode( '&', $_COOKIE[ IP_Geo_Block::PLUGIN_NAME ] ) as $i => $v ) {
list( $i, $v ) = explode( '=', $v );
$cookie[ $i ] = str_split( $v );
}
}
return $cookie;
}
/**
* Prints out all settings sections added to a particular settings page
*
* wp-admin/includes/template.php @since 2.7.0
*/
private function do_settings_sections( $page, $tab ) {
global $wp_settings_sections, $wp_settings_fields;
// target section to be opened
$target = isset( $_GET['sec'] ) ? (int)$_GET['sec'] : -1;
if ( isset( $wp_settings_sections[ $page ] ) ) {
$index = 0; // index of fieldset
$cookie = $this->get_cookie();
foreach ( (array) $wp_settings_sections[ $page ] as $section ) {
// TRUE if open ('o') or FALSE if close ('x')
$stat = empty( $cookie[ $tab ][ $index ] ) || 'x' !== $cookie[ $tab ][ $index ] || $index === $target;
echo "\n", '\n";
++$index;
}
}
}
/**
* Render the settings page for this plugin.
*
*/
public function display_plugin_admin_page() {
$tab = $this->admin_tab;
$tabs = array(
5 => __( 'Sites list', 'ip-geo-block' ),
0 => __( 'Settings', 'ip-geo-block' ),
1 => __( 'Statistics', 'ip-geo-block' ),
4 => __( 'Logs', 'ip-geo-block' ),
2 => __( 'Search', 'ip-geo-block' ),
3 => __( 'Attribution', 'ip-geo-block' ),
);
$settings = IP_Geo_Block::get_option();
$cookie = $this->get_cookie();
$title = esc_html( get_admin_page_title() );
// Target page that depends on the network multisite or not.
if ( 'options-general.php' === $GLOBALS['pagenow'] ) {
$action = 'options.php';
unset( $tabs[5] ); // Sites list
if ( $this->is_network_admin ) {
$title .= ' ';
}
}
// '/wp-admin/network/admin.php'
else {
// `edit.php` is an action handler for Multisite administration dashboard.
// `edit.php` ==> do action `network_admin_edit_ip-geo-block` ==> `validate_network_settings()`
$action = 'edit.php?action=' . IP_Geo_Block::PLUGIN_NAME;
if ( $this->is_network_admin ) {
unset( $tabs[1], $tabs[4], $tabs[2], $tabs[3] ); // Statistics, Logs, Search, Attribution
$title .= ' ';
}
}
?>
', implode( '
', $tab ), "
', __( 'Thanks for providing these great services for free.', 'ip-geo-block' ), "
\n";
echo __( '(Most browsers will redirect you to each site without referrer when you click the link.)', 'ip-geo-block' ), "
', $desc, "
\n"; if ( 'select' === $args['type'] ) break; echo "%s. Please check the permission.', 'ip-geo-block' ), '' . $file . ''
) );
}
// Force to finish update matching rule
delete_transient( IP_Geo_Block::CRON_NAME );
// start to update databases immediately
do_action( IP_Geo_Block::PLUGIN_NAME . '-settings-updated', $options, TRUE );
return $options;
}
/**
* Validate settings and configure some features for network multisite.
*
* @see https://vedovini.net/2015/10/using-the-wordpress-settings-api-with-network-admin-pages/
*/
public function validate_network_settings() {
// Must check that the user has the required capability
$this->check_admin_post( FALSE );
// The list of registered options (IP_Geo_Block::OPTION_NAME).
global $new_whitelist_options;
$options = $new_whitelist_options[ IP_Geo_Block::PLUGIN_NAME ];
// Go through the posted data and save the targetted options.
foreach ( $options as $option ) {
if ( isset( $_POST[ $option ] ) ) {
$this->update_multisite_settings( $_POST[ $option ] );
}
}
// Register a settings error to be displayed to the user
self::add_admin_notice( 'updated', __( 'Settings saved.' ) );
// Redirect in order to back to the settings page.
wp_redirect( esc_url_raw(
add_query_arg(
array( 'page' => IP_Geo_Block::PLUGIN_NAME ),
$this->dashboard_url( ! empty( $_POST[ $option ]['network_wide'] ) )
)
) );
exit;
}
/**
* Update option in all blogs.
*
* @note: This function triggers `validate_settings()` on register_setting() in wp-include/option.php.
*/
public function update_multisite_settings( $settings ) {
global $wpdb;
$blog_ids = $wpdb->get_col( "SELECT `blog_id` FROM `$wpdb->blogs`" );
$ret = TRUE;
foreach ( $blog_ids as $id ) {
switch_to_blog( $id );
$map = IP_Geo_Block::get_option( FALSE );
$settings['api_key']['GoogleMap'] = $map['api_key']['GoogleMap'];
$ret &= IP_Geo_Block::update_option( $settings, FALSE );
restore_current_blog();
}
return $ret;
}
/**
* Analyze entries in "Validation logs"
*
* @param array $logs An array including each entry where:
* Array (
* [0 DB row number] => 154
* [1 Target ] => comment
* [2 Time ] => 1534580897
* [3 IP address ] => 102.177.147.***
* [4 Country code ] => ZA
* [5 Result ] => blocked
* [6 AS number ] => AS328239
* [7 Request ] => POST[80]:/wp-comments-post.php
* [8 User agent ] => Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) ...
* [9 HTTP headers ] => HTTP_ORIGIN=http://localhost,HTTP_X_FORWARDED_FOR=102.177.147.***
* [10 $_POST data ] => comment=Hello.,author,email,url,comment_post_ID,comment_parent
* )
* And put a mark at "Target"
* ¹¹: Passed in Whitelist
* ¹²: Passed in Blacklist
* ¹³: Passed not in list
* ²¹: Blocked in Whitelist
* ²²: Blocked in Blacklist
* ²³: Blocked not in list
*/
public function filter_logs( $logs ) {
$settings = IP_Geo_Block::get_option();
// White/Black list for back-end
$white_backend = $settings['white_list'];
$black_backend = $settings['black_list'];
// White/Black list for front-end
if ( $settings['public']['matching_rule'] < 0 ) {
// Follow "Validation rule settings"
$white_frontend = $white_backend;
$black_frontend = $black_backend;
} else {
// Whitelist or Blacklist for "Public facing pages"
$white_frontend = $settings['public']['white_list'];
$black_frontend = $settings['public']['black_list'];
}
foreach ( $logs as $key => $log ) {
// Passed or Blocked
$mark = IP_Geo_Block::is_passed( $log[5] ) ? '¹' : '²';
// Whitelisted, Blacklisted or N/A
if ( 'public' === $log[1] ) {
$mark .= IP_Geo_Block::is_listed( $log[4], $white_frontend ) ? '¹' : (
IP_Geo_Block::is_listed( $log[4], $black_frontend ) ? '²' : '³' );
} else {
$mark .= IP_Geo_Block::is_listed( $log[4], $white_backend ) ? '¹' : (
IP_Geo_Block::is_listed( $log[4], $black_backend ) ? '²' : '³' );
}
// Put a mark at "Target"
$logs[ $key ][1] .= $mark;
}
return $logs;
}
/**
* Register UI "Preset filters" at "Search in logs"
*
* @param array $filters An empty array by default.
* @return array $filters The array of paired with 'title' and 'value'.
*/
public function preset_filters( $filters = array() ) {
return array(
array( 'title' => '' . __( 'Passed in Whitelist', 'ip-geo-block' ), 'value' => '¹¹' ),
array( 'title' => '' . __( 'Passed in Blacklist', 'ip-geo-block' ), 'value' => '¹²' ),
array( 'title' => '' . __( 'Passed not in List', 'ip-geo-block' ), 'value' => '¹³' ),
array( 'title' => '' . __( 'Blocked in Whitelist', 'ip-geo-block' ), 'value' => '²¹' ),
array( 'title' => '' . __( 'Blocked in Blacklist', 'ip-geo-block' ), 'value' => '²²' ),
array( 'title' => '' . __( 'Blocked not in List', 'ip-geo-block' ), 'value' => '²³' ),
);
}
/**
* Ajax callback function
*
* @link https://codex.wordpress.org/AJAX_in_Plugins
* @link https://codex.wordpress.org/Function_Reference/check_ajax_referer
* @link https://core.trac.wordpress.org/browser/trunk/wp-admin/admin-ajax.php
*/
public function admin_ajax_callback() {
require_once IP_GEO_BLOCK_PATH . 'admin/includes/class-admin-ajax.php';
// Check request origin, nonce, capability.
$this->check_admin_post( TRUE );
// `$which` and `$cmd` should be restricted by whitelist in each function
$settings = IP_Geo_Block::get_option();
$which = isset( $_POST['which'] ) ? $_POST['which'] : NULL;
$cmd = isset( $_POST['cmd' ] ) ? $_POST['cmd' ] : NULL;
switch ( $cmd ) {
case 'download':
$res = IP_Geo_Block::get_instance();
$res = $res->exec_update_db();
break;
case 'search': // Get geolocation by IP
$res = array();
foreach ( (array)$which as $cmd ) {
$res[ $cmd ] = IP_Geo_Block_Admin_Ajax::search_ip( $cmd );
}
break;
case 'scan-code': // Fetch providers to get country code
$res = IP_Geo_Block_Admin_Ajax::scan_country( $which );
break;
case 'clear-statistics': // Set default values
IP_Geo_Block_Logs::clear_stat();
$res = array(
'page' => 'options-general.php?page=' . IP_Geo_Block::PLUGIN_NAME,
'tab' => 'tab=1'
);
break;
case 'clear-cache': // Delete cache of IP address
IP_Geo_Block_API_Cache::clear_cache();
$res = array(
'page' => 'options-general.php?page=' . IP_Geo_Block::PLUGIN_NAME,
'tab' => 'tab=1'
);
break;
case 'clear-logs': // Delete logs in MySQL DB
IP_Geo_Block_Logs::clear_logs( $which );
$res = array(
'page' => 'options-general.php?page=' . IP_Geo_Block::PLUGIN_NAME,
'tab' => 'tab=4'
);
break;
case 'export-logs':// Export logs from MySQL DB
IP_Geo_Block_Admin_Ajax::export_logs( $which );
break;
case 'restore-logs': // Get logs from MySQL DB
has_filter( $cmd = IP_Geo_Block::PLUGIN_NAME . '-logs' ) or add_filter( $cmd, array( $this, 'filter_logs' ) );
$res = IP_Geo_Block_Admin_Ajax::restore_logs( $which );
break;
case 'live-start': // Restore live log
has_filter( $cmd = IP_Geo_Block::PLUGIN_NAME . '-logs' ) or add_filter( $cmd, array( $this, 'filter_logs' ) );
if ( is_wp_error( $res = IP_Geo_Block_Admin_Ajax::restore_live_log( $which, $settings ) ) )
$res = array( 'error' => $res->get_error_message() );
break;
case 'live-pause': // Pause live log
if ( ! is_wp_error( $res = IP_Geo_Block_Admin_Ajax::catch_live_log() ) )
$res = array( 'data' => array() );
else
$res = array( 'error' => $res->get_error_message() );
break;
case 'live-stop': // Stop live log
if ( ! is_wp_error( $res = IP_Geo_Block_Admin_Ajax::release_live_log() ) )
$res = array( 'data' => array() );
else
$res = array( 'error' => $res->get_error_message() );
break;
case 'reset-live': // Reset data source of live log
$res = IP_Geo_Block_Admin_Ajax::reset_live_log();
break;
case 'validate': // Validate settings
IP_Geo_Block_Admin_Ajax::validate_settings( $this );
break;
case 'import-default': // Import initial settings
$res = IP_Geo_Block_Admin_Ajax::settings_to_json( IP_Geo_Block::get_default() );
break;
case 'import-preferred': // Import preference
$res = IP_Geo_Block_Admin_Ajax::preferred_to_json();
break;
case 'gmap-error': // Reset Google Maps API key
if ( $settings['api_key']['GoogleMap'] === 'default' ) {
$settings['api_key']['GoogleMap'] = NULL;
IP_Geo_Block::update_option( $settings );
$res = array(
'page' => 'options-general.php?page=' . IP_Geo_Block::PLUGIN_NAME,
'tab' => 'tab=2'
);
}
break;
case 'generate-link': // Generate new link
$res = array( 'link' => IP_Geo_Block_Util::generate_link( $this ) );
break;
case 'delete-link': // Delete existing link
IP_Geo_Block_Util::delete_link( $this );
break;
case 'show-info': // Show system and debug information
$res = IP_Geo_Block_Admin_Ajax::get_wp_info();
break;
case 'get-actions': // Get all the ajax/post actions
$res = IP_Geo_Block_Util::get_registered_actions( TRUE );
break;
case 'export-cache': // Restore cache from database and format for DataTables
IP_Geo_Block_Admin_Ajax::export_cache( $settings['anonymize'] );
break;
case 'restore-cache': // Restore cache from database and format for DataTables
$res = IP_Geo_Block_Admin_Ajax::restore_cache( $settings['anonymize'] );
break;
case 'bulk-action-remove': // Delete specified IP addresses from cache
$res = IP_Geo_Block_Logs::delete_cache_entry( $which['IP'] );
break;
case 'bulk-action-ip-erase':
$res = IP_Geo_Block_Logs::delete_logs_entry( $which['IP'] );
break;
case 'bulk-action-ip-white':
case 'bulk-action-ip-black':
case 'bulk-action-as-white':
case 'bulk-action-as-black':
// Bulk actions for registration of settings
$src = ( FALSE !== strpos( $cmd, '-ip-' ) ? 'IP' : 'AS' );
$dst = ( FALSE !== strpos( $cmd, '-white' ) ? 'white_list' : 'black_list' );
if ( empty( $which[ $src ] ) ) {
$res = array( 'error' => sprintf( __( 'An error occurred while executing the ajax command `%s`.', 'ip-geo-block' ), $cmd ) );
break;
}
foreach ( array_unique( (array)$which[ $src ] ) as $val ) {
// replace anonymized IP address with CIDR (IPv4:256, IPv6:4096)
$val = preg_replace(
array( '/\.\*\*\*$/', '/:\w*\*\*\*$/', '/(::.*)::\/116$/' ),
array( '.0/24', '::/116', '$1/116' ),
trim( $val )
);
if ( ( filter_var( preg_replace( '/\/\d+$/', '', $val ), FILTER_VALIDATE_IP ) || preg_match( '/^AS\d+$/', $val ) ) &&
( FALSE === strpos( $settings['extra_ips'][ $dst ], $val ) ) ) {
$settings['extra_ips'][ $dst ] .= "\n" . $val;
}
}
if ( $this->is_network_admin && $settings['network_wide'] )
$this->update_multisite_settings( $settings );
else
IP_Geo_Block::update_option( $settings );
$res = array( 'page' => 'options-general.php?page=' . IP_Geo_Block::PLUGIN_NAME );
break;
case 'restore-network': // Restore blocked per target in logs
$res = IP_Geo_Block_Admin_Ajax::restore_network( $which, (int)$_POST['offset'], (int)$_POST['length'], FALSE );
break;
case 'find-admin':
case 'find-plugins':
case 'find-themes':
// Get slug in blocked requests for exceptions
$res = IP_Geo_Block_Admin_Ajax::find_exceptions( $cmd );
break;
case 'diag-tables': // Check database tables
IP_Geo_Block_Logs::diag_tables() or IP_Geo_Block_Logs::create_tables();
$res = array( 'page' => 'options-general.php?page=' . IP_Geo_Block::PLUGIN_NAME );
break;
}
if ( isset( $res ) ) // wp_send_json_{success,error}() @since 3.5.0
wp_send_json( $res ); // @since 3.5.0
die(); // End of ajax
}
}