PluginProbe
MainWP Dashboard: Self-hosted WordPress Management for Agencies / 6.2.2
MainWP Dashboard: Self-hosted WordPress Management for Agencies v6.2.2
6.2.2 6.2.1 6.2 6.1.8 6.1.7 6.1.6 6.1.5 6.1.4 6.1.3 6.1.2 6.1.1 6.1 6.0.12 6.0.11 4.6.0.1 5.0 5.0.1 5.0.2 5.0.3 5.0.3.1 5.0.3.2 5.1 5.1.1 5.2 5.2.1 All 155 releases
← All changes | class/class-mainwp-connect.php +85 -11 6.2 → 6.2.2 View file →
@@ -427,12 +427,15 @@
427 427 $http_user_plain = ! empty( $others['http_user_plain'] ) ? $others['http_user_plain'] : '';
428 428 $http_pass_plain = ! empty( $others['http_pass_plain'] ) ? $others['http_pass_plain'] : '';
429 429
430 430 if ( $website && '' !== $what ) {
431 + // The nonce must never repeat. The Child stores every legacy signature it accepts, forever,
432 + // and refuses a repeat as "This request has already been used"; signing is deterministic,
433 + // so the nonce is the only thing that makes two requests for the same action differ.
431 434 $data = array();
432 435 $data['user'] = $website->adminname;
433 436 $data['function'] = $what;
434 - $data['nonce'] = wp_rand( 0, 9999 );
437 + $data['nonce'] = bin2hex( random_bytes( 16 ) );
435 438 $data['mainwpver'] = MainWP_System::$version;
436 439
437 440 $params_filter = apply_filters( 'mainwp_pre_fetch_authed_data', false, $params, $what, $website, $verify_signature );
438 441 if ( is_array( $params_filter ) && ! empty( $params_filter ) ) {
@@ -512,9 +515,9 @@
512 515 'base_function' => $what,
513 516 'nonce' => $data['nonce'],
514 517 'expires' => $ts + 60,
515 518 'user' => $website->adminname,
516 - 'req_id' => wp_generate_uuid4(),
519 + 'req_id' => wp_generate_uuid4(),
517 520 );
518 521
519 522 if ( ! empty( $alt_user ) ) {
520 523 $data_sign_v2['alt_user'] = rawurlencode( $alt_user );
@@ -615,9 +618,9 @@
615 618 $compat_what = 'disconnect'; // to compatible, renew will call disconnect.
616 619 $data = array();
617 620 $data['user'] = $website->adminname;
618 621 $data['function'] = $compat_what;
619 - $data['nonce'] = wp_rand( 0, 9999 );
622 + $data['nonce'] = bin2hex( random_bytes( 16 ) );
620 623
621 624 $sign_value = $compat_what . $data['nonce']; // compatible format.
622 625
623 626 $alg = false;
@@ -660,9 +663,9 @@
660 663 'base_function' => $compat_what,
661 664 'nonce' => $data['nonce'],
662 665 'expires' => $ts + 60,
663 666 'user' => $website->adminname,
664 - 'req_id' => wp_generate_uuid4(),
667 + 'req_id' => wp_generate_uuid4(),
665 668 );
666 669 $sign_value_v2 = wp_json_encode( $data_sign_v2 );
667 670
668 671 $sign_success_v2 = null;
@@ -730,9 +733,9 @@
730 733
731 734 $sign_success = null;
732 735 $alg = false;
733 736 $use_seclib = false;
734 - $nonce = wp_rand( 0, 9999 );
737 + $nonce = bin2hex( random_bytes( 16 ) );
735 738
736 739 /**
737 740 * Current user global.
738 741 *
@@ -795,9 +798,9 @@
795 798 'where' => rawurlencode( $paramName ),
796 799 'nonce' => $nonce,
797 800 'expires' => $ts + 60,
798 801 'user' => $website->adminname,
799 - 'req_id' => wp_generate_uuid4(),
802 + 'req_id' => wp_generate_uuid4(),
800 803 );
801 804
802 805 if ( ! empty( $alt_user ) ) {
803 806 $data_sign_v2['alt_user'] = rawurlencode( $alt_user );
@@ -808,9 +811,9 @@
808 811 $sign_value_v2 = wp_json_encode( $data_sign_v2 );
809 812
810 813 if ( MainWP_Connect_Lib::is_use_fallback_sec_lib( $website ) ) {
811 814 $sign_success_v2 = MainWP_Connect_Lib::connect_sign( $sign_value_v2, $signature_v2, base64_decode( $website->privkey ), $website->id ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode used for http encoding compatible.
812 - $use_seclib = true;
815 + $use_seclib = true;
813 816 } elseif ( function_exists( 'openssl_verify' ) ) {
814 817 $alg = MainWP_System_Utility::get_connect_sign_algorithm( $website );
815 818 $sign_success_v2 = static::connect_sign( $sign_value_v2, $signature_v2, base64_decode( $website->privkey ), $alg, $website->id ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode used for http encoding compatible.
816 819 if ( false !== $alg ) {
@@ -1602,11 +1605,18 @@
1602 1605 * @since 4.5.1.1
1603 1606 */
1604 1607 do_action( 'mainwp_fetch_url_authed', $website, $information, $what, $params, $others );
1605 1608
1606 - if ( is_array( $information ) && isset( $information['sync'] ) && ! empty( $information['sync'] ) ) {
1607 - MainWP_Sync::sync_information_array( $website, $information['sync'] );
1608 - unset( $information['sync'] );
1609 + if ( is_array( $information ) ) {
1610 + if ( isset( $information['sync'] ) && ! empty( $information['sync'] ) ) {
1611 + MainWP_Sync::sync_information_array( $website, $information['sync'] );
1612 + unset( $information['sync'] );
1613 + }
1614 +
1615 + if ( isset( $information['sync_partial'] ) && is_array( $information['sync_partial'] ) && ! empty( $information['sync_partial'] ) ) {
1616 + MainWP_Sync::sync_partial_information( $website, $information['sync_partial'] );
1617 + unset( $information['sync_partial'] );
1618 + }
1609 1619 }
1610 1620
1611 1621 if ( $updating_website ) {
1612 1622 /**
@@ -1661,8 +1671,72 @@
1661 1671 $sslVersion = 0,
1662 1672 $others = array(),
1663 1673 &$output = array()
1664 1674 ) {
1675 +
1676 + /**
1677 + * Filter to mock the fetch_url_not_authed response before any HTTP request occurs.
1678 + *
1679 + * This filter fires early, before the HTTP request is performed, allowing
1680 + * tests to bypass child site communication entirely.
1681 + *
1682 + * SECURITY WARNING - TEST ONLY:
1683 + * This filter ONLY fires when ALL of the following conditions are met:
1684 + * 1. MAINWP_TESTING_MODE constant is defined and true.
1685 + * 2. A PHPUnit test harness constant is present (WP_TESTS_DOMAIN,
1686 + * PHPUNIT_COMPOSER_INSTALL, or WP_TESTS_DIR).
1687 + *
1688 + * These checks prevent malicious code from defining MAINWP_TESTING_MODE
1689 + * in production to spoof child site responses.
1690 + *
1691 + * IMPORTANT: MAINWP_TESTING_MODE must ONLY be defined in the PHPUnit bootstrap
1692 + * file (tests/bootstrap.php). Defining it in production code, wp-config.php,
1693 + * or plugin files would create a security vulnerability allowing response
1694 + * spoofing.
1695 + *
1696 + * @since 6.2.1
1697 + *
1698 + * @param mixed $pre_result Return non-false to short-circuit the request and return this value.
1699 + * @param string $url URL to fetch.
1700 + * @param string $admin Admin username or identifier.
1701 + * @param string $what Action being performed.
1702 + * @param array|null $params Request parameters.
1703 + * @param bool $pForceFetch Whether to force the fetch.
1704 + * @param bool|null $verifyCertificate Whether to verify the SSL certificate.
1705 + * @param string|null $http_user HTTP authentication username.
1706 + * @param string|null $http_pass HTTP authentication password.
1707 + * @param int $sslVersion SSL version.
1708 + * @param array $others Additional request options.
1709 + * @param array $output Output data passed by reference.
1710 + *
1711 + * @return mixed Array or other value to return early, false to proceed normally.
1712 + */
1713 + $is_phpunit_env = defined( 'WP_TESTS_DOMAIN' ) || defined( 'PHPUNIT_COMPOSER_INSTALL' ) || ( defined( 'WP_TESTS_DIR' ) && WP_TESTS_DIR );
1714 +
1715 + if ( defined( 'MAINWP_TESTING_MODE' ) && MAINWP_TESTING_MODE && $is_phpunit_env ) {
1716 + $pre_result = apply_filters_ref_array(
1717 + 'mainwp_fetch_url_not_authed_pre',
1718 + array(
1719 + false,
1720 + $url,
1721 + $admin,
1722 + $what,
1723 + $params,
1724 + $pForceFetch,
1725 + $verifyCertificate,
1726 + $http_user,
1727 + $http_pass,
1728 + $sslVersion,
1729 + $others,
1730 + &$output,
1731 + )
1732 + );
1733 +
1734 + if ( false !== $pre_result ) {
1735 + return $pre_result;
1736 + }
1737 + }
1738 +
1665 1739 unset( $pForceFetch );
1666 1740
1667 1741 if ( empty( $params ) ) {
1668 1742 $params = array();
@@ -2058,9 +2132,9 @@
2058 2132 MainWP_Logger::instance()->log_execution_time( 'fetch_url_site :: [url=' . $url . ']' );
2059 2133
2060 2134 $thr_error = null;
2061 2135
2062 - if ( in_array( $what, array( 'installplugintheme', 'upgradeplugintheme', 'upgradetranslation', 'upgrade', 'stats', 'renew', 'reconnect' ), true ) ) {
2136 + if ( in_array( $what, array( 'installplugintheme', 'upgradeplugintheme', 'upgradetranslation', 'process_premium_updates', 'upgrade', 'stats', 'renew', 'reconnect' ), true ) ) {
2063 2137 MainWP_Cache_Helper::invalidate_cache_group( MainWP_Cache_Helper::CGR_UPDATES );
2064 2138 MainWP_Cache_Warm_Helper::invalidate_pages_by_site_actions( $what );
2065 2139 }
2066 2140