error = new WP_Error( 'nexus_format_error', 'Invalid request: master request malformed' ); return; } $request = json_decode( stripslashes( $payload ), true ); if ( JSON_ERROR_NONE != json_last_error() ) { $this->error = new WP_Error( 'json_error', 'Unable to parse JSON: ' . json_last_error_msg() ); return; } array_walk_recursive( $request, function ( &$e ) { $e = str_replace( array( '
' ), "\n", $e ); // restore new lines after json_decode } ); $this->seal = $request['seal']; $this->base = rtrim( $request['base'], '/' ) . '/'; $this->get_params = $request['params']; $this->payload = $request['payload']; $this->type = $request['payload']['type']; $this->page = preg_replace( '/[^\w\-]/i', '', crb_array_get( $request, 'page' ) ); $this->tab = preg_replace( '/[^\w\-]/i', '', crb_array_get( $request, 'tab' ) ); $this->at_site = crb_array_get( $request, 'at_site' ); $this->screen = crb_array_get( $request, 'screen' ); $this->is_post = ( ! empty( $request['is_post'] ) ) ? true : false; if ( ! $this->locale = crb_array_get( $request, 'master_locale' ) ) { if ( ! $this->locale = get_site_option( 'WPLANG' ) ) { $this->locale = 'en_US'; } } $crb_assets_url = $request['assets']; $crb_ajax_loader = $crb_assets_url . 'ajax-loader.gif'; if ( $this->type == 'ajax' ) { if ( ! $this->action = crb_array_get( $request['params'], 'action' ) ) { $this->action = $this->get_post_fields( 'action' ); } $this->action = preg_replace( '/[^\w\-]/i', '', (string) $this->action ); } } /** * @param integer|string $key * @param mixed $default * @param $pattern string REGEX pattern for value validation, UTF is not supported * * @return mixed */ final function get_post_fields( $key = null, $default = false, $pattern = '' ) { if ( ! empty( $this->payload['data']['post'] ) ) { if ( $key ) { return crb_array_get( $this->payload['data']['post'], $key, $default, $pattern ); } return $this->payload['data']['post']; } if ( $key ) { return false; } return array(); } } /** * @return CRB_Master */ function nexus_request_data() { static $crb_master; if ( ! is_object( $crb_master ) ) { $crb_master = new CRB_Master(); } return $crb_master; } function nexus_slave_process() { if ( ! nexus_is_valid_request() ) { return; } @ini_set( 'display_errors', 0 ); @ignore_user_abort( true ); crb_raise_limits(); cerber_update_set( 'processing_master_request', 1, 0, false, time() + 120 ); nexus_diag_log( 'Parsing request...' ); $crb_master = nexus_request_data(); if ( is_wp_error( $crb_master->error ) ) { nexus_diag_log( 'ERROR: ' . $crb_master->error->get_error_message() ); exit; } nexus_diag_log( 'Request is parsed, generating response...' ); add_filter( 'plugin_locale', function () { return nexus_request_data()->locale; }, 9999 ); $use_eng = false; if ( nexus_request_data()->locale == 'en_US' ) { $use_eng = true; // We do not load any translation files add_filter( 'override_load_textdomain', function ( $val, $domain, $mofile ) { return true; }, 9999, 3 ); } if ( ! $use_eng ) { $r = load_plugin_textdomain( 'wp-cerber', false, 'wp-cerber/languages' ); /*if ( ! $r ) { nexus_diag_log( 'Unable to load plugin localization files ' . (string) nexus_request_data()->locale ); }*/ } require_once( ABSPATH . 'wp-admin/includes/plugin.php' ); require_once( ABSPATH . 'wp-admin/includes/template.php' ); require_once( ABSPATH . WPINC . '/pluggable.php' ); require_once( ABSPATH . WPINC . '/vars.php' ); cerber_load_admin_code(); $response = nexus_prepare_responce(); if ( is_wp_error( $response ) ) { $m = __( 'ERROR:', 'wp-cerber' ) . ' ' . $response->get_error_message(); nexus_diag_log( $m ); $error = array( $response->get_error_code(), $response->get_error_message() ); $response = array( 'error' => $error ); } nexus_diag_log( 'Now sending response to the master...' ); $result = nexus_net_send_responce( $response ); if ( is_wp_error( $result ) ) { nexus_diag_log( __( 'ERROR:', 'wp-cerber' ) . ' ' . $result->get_error_message() ); } cerber_delete_set( 'processing_master_request' ); nexus_diag_log( '=== SLAVE HAS FINISHED ===' ); exit; } /** * Avoid simultaneous requests from the master(s) * * @return bool * */ function nexus_is_processing() { return ( cerber_get_set( 'processing_master_request' ) ) ? true : false; } /* function nexus_render_admin_page_1(){ require_once( ABSPATH . 'wp-admin/includes/plugin.php' ); require_once( ABSPATH . '/wp-admin/includes/template.php' ); require_once( ABSPATH . '/wp-includes/pluggable.php' ); cerber_load_admin_code(); $page_id = 'cerber-recaptcha'; //$tab = 'captcha'; if ( empty( $tab ) ) { $tab = $page_id; } cerber_wp_settings_setup( cerber_get_setting_id( $tab ) ); // Render inner html $page = cerber_get_admin_page_config( $page_id ); call_user_func( $page['callback'], '' ); exit; }*/ function nexus_render_admin_page( $page, $tab ) { $id = ( empty( $tab ) ) ? $page : $tab; cerber_wp_settings_setup( cerber_get_setting_id( $id ) ); cerber_admin_init(); // TODO: remove, old way ob_start(); cerber_render_admin_page( $page, $tab ); // Render whole html return ob_get_clean(); } function nexus_parse_request() { $fields = nexus_get_fields(); if ( ! $payload = cerber_get_post( $fields[1] ) ) { return new WP_Error( 'nexus_format_error', 'Invalid request: master request malformed' ); } $request = json_decode( stripslashes( $payload ), true ); if ( JSON_ERROR_NONE != json_last_error() ) { return new WP_Error( 'json_error', 'Unable to parse JSON: ' . json_last_error_msg() ); } return $request; } function nexus_prepare_responce() { $master = nexus_request_data(); nexus_diag_log( 'Type: ' . $master->type ); if ( ! nexus_is_granted() ) { return new WP_Error( 'not_allowed', 'Operation is not allowed in this context' ); } $result = ''; switch ( $master->type ) { case 'get_page': CRB_Addons::load_active(); return array( 'html' => nexus_render_admin_page( $master->page, $master->tab ), //'o' => get_option( 'gmt_offset' ), //'z' => get_option( 'timezone_string' ), ); break; case 'submit': CRB_Addons::load_active(); if ( $master->get_post_fields( 'option_page' ) ) { // True WP setting page return nexus_process_wp_settings_form( $master->get_post_fields() ); } else { return cerber_admin_request( $master->is_post ); } // A new way: processing + follow up rendering in a single request //return nexus_render_admin_page( $master->page, $master->tab ); break; case 'manage': return cerber_admin_request( $master->is_post ); break; case 'hello': //case 'checkup': return array( 'numbers' => nexus_get_numbers() ); break; case 'ping': return array( 'pong' ); break; case 'sw_upgrade': $result = nexus_sw_upgrade(); $result ['numbers'] = nexus_get_numbers(); if ( ! $result['updates'] ) { //nexus_diag_log( 'No updates are available' ); } break; case 'ajax': if ( ! crb_admin_allowed_ajax( $master->action ) ) { return new WP_Error( 'unknown_ajax', 'The action ' . $master->action . ' is not supported' ); } global $nexus_doing_ajax; $nexus_doing_ajax = true; ob_start(); do_action( 'wp_ajax_' . $master->action ); $nexus_doing_ajax = false; nexus_diag_log( 'AJAX ' . $master->action . ' completed' ); return ob_get_clean(); break; default: return new WP_Error( 'unknown_request', 'This type of request is not supported' ); break; } return $result; } function nexus_sw_upgrade() { $ret = array( 'updates' => 0, 'completed' => 1, 'results' => array() ); if ( nexus_is_processing() ) { $ret['completed'] = 0; $ret['wait'] = cerber_get_remote_ip(); return $ret; } $list = crb_array_get( nexus_request_data()->payload, 'list' ); switch ( nexus_request_data()->payload['sw_type'] ) { case 'plugins': if ( empty( $list ) ) { // Upgrade all $to_update = array(); $active = get_option( 'active_plugins' ); if ( ! $plugins = get_site_transient( 'update_plugins' ) ) { wp_update_plugins(); $plugins = get_site_transient( 'update_plugins' ); } if ( isset( $plugins->response ) ) { $to_update = array_intersect( $active, array_keys( $plugins->response ) ); } nexus_diag_log( 'Total active plugins to update: ' . count( $to_update ) ); if ( $done = cerber_get_set( 'plugins_done' ) ) { // Upgraded in the current bulk operation $to_do = array_diff( $to_update, $done ); } else { $done = array(); $to_do = $to_update; } if ( ! empty( $to_do ) ) { $run_now = array_shift( $to_do ); $done[] = $run_now; $list = array( $run_now ); } if ( ! empty( $to_do ) ) { $ret['completed'] = 0; // Something left cerber_update_set( 'plugins_done', $done, 0, true, time() + 300 * count( $to_do ) ); } else { cerber_delete_set( 'plugins_done' ); } } if ( ! empty( $list ) && is_array( $list ) ) { foreach ( $list as $obj ) { $ret['results'][ $obj ] = cerber_update_plugin( $obj ); } } break; } nexus_diag_log( cerber_flat_results( $ret['results'] ) ); return $ret; } /** * Process forms generated by WP Settings API * * @param $form array WP Settings form fields * * @return string|WP_Error */ function nexus_process_wp_settings_form( $form ) { if ( ! $page = crb_array_get( $form, 'option_page' ) ) { return new WP_Error( 'unknown_option', 'Unable to identify settings page' ); } if ( ! wp_verify_nonce( crb_array_get( $form, '_wpnonce' ), $page . '-options' ) ) { return new WP_Error( 'nonce_failed', 'Nonce verification failed' ); } $wp_option = 'cerber-' . cerber_get_wp_option_id( $page ); if ( ! isset( $form[ $wp_option ] ) ) { return new WP_Error( 'no_value', 'Setting fields are not set' ); } $new_values = crb_array_get( $form, $wp_option ); nexus_diag_log( 'Updating ' . $wp_option . ' option' ); cerber_update_site_option( $wp_option, $new_values ); cerber_admin_message( __( 'Settings updated', 'wp-cerber' ) ); return ''; } /** * @param string|array $payload * * @return bool|WP_Error */ function nexus_net_send_responce( $payload ) { $ret = true; $role = nexus_get_role_data(); if ( is_array( $payload ) ) { $p = json_encode( $payload, JSON_UNESCAPED_UNICODE ); // 8.0.5 } elseif ( is_scalar( $payload ) ) { $p = (string) $payload; } else { $p = ''; $ret = new WP_Error( 'wrong_type', 'Unsupported slave data type' ); } $processing = microtime( true ) - cerber_request_time(); $hash = hash( 'sha512', $role['slave']['nx_echo'] . sha1( $p ) ); $response = json_encode( array( 'payload' => $payload, 'extra' => array( 'versions' => array( CERBER_VER, cerber_get_wp_version(), PHP_MAJOR_VERSION, PHP_MINOR_VERSION, PHP_RELEASE_VERSION, PHP_OS, lab_lab( 2 ) ) ), 'echo' => $hash, 'p_time' => $processing, 'scheme' => 2 // 8.0.5 ), JSON_UNESCAPED_UNICODE ); if ( JSON_ERROR_NONE != json_last_error() ) { $response = 'Unable to encode payload. JSON error.'; $ret = new WP_Error( 'json_error', 'Unable to encode JSON: ' . json_last_error_msg() ); } echo $response; // To master return $ret; } function nexus_is_granted( $type = null ) { $acs = crb_get_settings( 'slave_access' ); $lab = lab_lab(); if ( $acs >= 8 ) { return false; } if ( $acs == 2 ) { if ( $lab ) { return true; } } // RO mode if ( ! $type ) { $type = nexus_request_data()->type; } if ( in_array( $type, array( 'get_page', 'hello', 'ping', 'sw_upgrade' ) ) ) { return true; } if ( $type == 'submit' ) { if ( crb_get_post_fields( 'cerber_license' ) ) { return true; } return false; } if ( $type == 'ajax' ) { $action = nexus_request_data()->action; if ( ! crb_admin_allowed_ajax( $action ) ) { return false; } if ( in_array( $action, array( 'cerber_scan_control', 'cerber_view_file' ) ) ) { return true; } if ( $action == 'cerber_ajax' ) { $fields = crb_get_request_fields(); if ( empty( $fields['acl_delete'] ) ) { return true; } } } return false; } function nexus_get_numbers() { $numbers = array(); $active_plugins = get_option( 'active_plugins' ); // see wp_get_update_data(); $updates = array( 'plugins' => 0, 'themes' => 0, 'wp' => 0, 'translations' => 0 ); $pl_updates = get_site_transient( 'update_plugins' ); if ( ! $pl_updates || ( $pl_updates->last_checked < ( time() - 7200 ) ) ) { delete_site_transient( 'update_plugins' ); wp_update_plugins(); $pl_updates = get_site_transient( 'update_plugins' ); } if ( ! empty( $pl_updates->response ) ) { $updates['plugins'] = count( array_intersect( $active_plugins, array_keys( $pl_updates->response ) ) ); } include_once( ABSPATH . 'wp-admin/includes/update.php' ); if ( function_exists( 'get_core_updates' ) ) { $wp = get_core_updates( array( 'dismissed' => false ) ); if ( ! empty( $wp ) ) { $updates['wp'] = 1; } } $scan = array(); if ( ( $last_scan = cerber_get_scan() ) && $last_scan['finished'] ) { $scan['finished'] = $last_scan['finished']; $scan['numbers'] = $last_scan['numbers']; } $numbers['updates'] = $updates; $numbers['scan'] = $scan; // New $list = array(); if ( ! empty( $pl_updates->response ) ) { $list = array_map( function ( $e ) { //$ret = (array) $e; $ret = array_map( function ( $e ) { return ( is_object( $e ) ) ? (array) $e : $e; }, (array) $e ); return $ret; }, $pl_updates->response ); } $numbers['pl_updates'] = $list; $numbers['active'] = $active_plugins; $numbers['plugins'] = get_plugins(); $numbers['themes'] = crb_get_themes(); $numbers['gmt'] = get_option( 'gmt_offset' ); $numbers['tz'] = get_option( 'timezone_string' ); return $numbers; } // We have to use our own "user id" add_filter( 'nonce_user_logged_out', function ( $uid, $action ) { if ( ! nexus_is_valid_request() ) { return $uid; } return PHP_INT_MAX; }, 10, 2 );