Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/affiliatex/affiliatex.php
+++ b/affiliatex/affiliatex.php
@@ -8,7 +8,7 @@
* Author URI: https://affiliatexblocks.com
* Text Domain: affiliatex
* Domain Path: /languages
- * Version: 2.3.5
+ * Version: 2.3.6
* Requires at least: 5.8
* Requires PHP: 7.4
* License: GPL-2.0-or-later
@@ -71,7 +71,7 @@
define( 'AFFILIATEX_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
}
if ( !defined( 'AFFILIATEX_VERSION' ) ) {
- define( 'AFFILIATEX_VERSION', '2.3.5' );
+ define( 'AFFILIATEX_VERSION', '2.3.6' );
}
if ( !defined( 'AFFILIATEX_EXTERNAL_API_ENDPOINT' ) ) {
define( 'AFFILIATEX_EXTERNAL_API_ENDPOINT', 'https://affiliatexblocks.com' );
--- a/affiliatex/build/adminJS.asset.php
+++ b/affiliatex/build/adminJS.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('jquery', 'react', 'react-dom', 'react-jsx-runtime', 'wp-api-fetch', 'wp-components', 'wp-data', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => '78a4b8b58119870c4c84');
+<?php return array('dependencies' => array('jquery', 'react', 'react-dom', 'react-jsx-runtime', 'wp-api-fetch', 'wp-components', 'wp-data', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => '031574ca8a53c2f84098');
--- a/affiliatex/build/dashboard.asset.php
+++ b/affiliatex/build/dashboard.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array(), 'version' => '9287d8d26519fa71c300');
+<?php return array('dependencies' => array(), 'version' => '84b30ec443a98146a24c');
--- a/affiliatex/includes/broken-links/BrokenLinkScanner.php
+++ b/affiliatex/includes/broken-links/BrokenLinkScanner.php
@@ -152,21 +152,49 @@
);
$parsed = wp_parse_url( $url );
+ $scheme = isset( $parsed['scheme'] ) ? strtolower( $parsed['scheme'] ) : '';
+ $port = isset( $parsed['port'] ) ? (int) $parsed['port'] : 0;
- if ( empty( $parsed['host'] ) || ! preg_match( '/^[a-z0-9]([a-z0-9-]*[a-z0-9])?(.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i', $parsed['host'] ) ) {
+ if ( empty( $parsed['host'] )
+ || ! in_array( $scheme, array( 'http', 'https' ), true )
+ || isset( $parsed['user'] ) || isset( $parsed['pass'] )
+ || ( $port && ! in_array( $port, array( 80, 443 ), true ) )
+ || ! preg_match( '/^[a-z0-9]([a-z0-9-]*[a-z0-9])?(.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i', $parsed['host'] )
+ ) {
$result['status'] = 'broken';
$result['status_label'] = 'Invalid URL';
$result['error_message'] = 'URL has no valid hostname.';
return $result;
}
+ // Tracked URLs come from a public endpoint, so resolve before requesting.
+ $host = trim( $parsed['host'], '.' );
+ $ips = filter_var( $host, FILTER_VALIDATE_IP ) ? array( $host ) : gethostbynamel( $host );
+
+ if ( empty( $ips ) ) {
+ $result['status'] = 'broken';
+ $result['status_label'] = 'Domain Not Found';
+ $result['error_message'] = 'Could not resolve the hostname.';
+ return $result;
+ }
+
+ foreach ( $ips as $ip ) {
+ if ( ! filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) ) {
+ $result['status'] = 'broken';
+ $result['status_label'] = 'Invalid URL';
+ $result['error_message'] = 'URL points to a private or reserved network address.';
+ return $result;
+ }
+ }
+
$browser_ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36';
$request_args = array(
- 'timeout' => 15,
- 'redirection' => 0,
- 'sslverify' => false,
- 'user-agent' => $browser_ua,
- 'headers' => array(
+ 'timeout' => 15,
+ 'redirection' => 0,
+ 'sslverify' => false,
+ 'reject_unsafe_urls' => true,
+ 'user-agent' => $browser_ua,
+ 'headers' => array(
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language' => 'en-US,en;q=0.5',
),
--- a/affiliatex/vendor/composer/installed.php
+++ b/affiliatex/vendor/composer/installed.php
@@ -1,9 +1,9 @@
<?php return array(
'root' => array(
'name' => 'wpcenter/affiliatex',
- 'pretty_version' => '2.3.5',
- 'version' => '2.3.5.0',
- 'reference' => '3d28686d400b99ed51feef971915b8cb740a5a2a',
+ 'pretty_version' => '2.3.6',
+ 'version' => '2.3.6.0',
+ 'reference' => '71f33b24f25a67cc90ad9a2ca159de2f5c05a42c',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -11,9 +11,9 @@
),
'versions' => array(
'freemius/wordpress-sdk' => array(
- 'pretty_version' => '2.13.1',
- 'version' => '2.13.1.0',
- 'reference' => '7376c0eca1ae7f92aaba9d3b550bd10affe797ff',
+ 'pretty_version' => '2.13.4',
+ 'version' => '2.13.4.0',
+ 'reference' => 'fa43eb92ae9dffa0d9f5ae11b5a1739bd7222308',
'type' => 'library',
'install_path' => __DIR__ . '/../freemius/wordpress-sdk',
'aliases' => array(),
@@ -29,9 +29,9 @@
'dev_requirement' => false,
),
'wpcenter/affiliatex' => array(
- 'pretty_version' => '2.3.5',
- 'version' => '2.3.5.0',
- 'reference' => '3d28686d400b99ed51feef971915b8cb740a5a2a',
+ 'pretty_version' => '2.3.6',
+ 'version' => '2.3.6.0',
+ 'reference' => '71f33b24f25a67cc90ad9a2ca159de2f5c05a42c',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
--- a/affiliatex/vendor/freemius/wordpress-sdk/config.php
+++ b/affiliatex/vendor/freemius/wordpress-sdk/config.php
@@ -210,6 +210,10 @@
define( 'WP_FS__API_SANDBOX_ADDRESS_LOCALHOST', 'http://sandbox-api.freemius:8080' );
}
+ if ( ! defined( 'WP_FS__API_TIMEOUT' ) ) {
+ define( 'WP_FS__API_TIMEOUT', 30 );
+ }
+
// Set API address for local testing.
if ( ! WP_FS__IS_PRODUCTION_MODE ) {
if ( ! defined( 'FS_API__ADDRESS' ) ) {
--- a/affiliatex/vendor/freemius/wordpress-sdk/includes/class-freemius.php
+++ b/affiliatex/vendor/freemius/wordpress-sdk/includes/class-freemius.php
@@ -3946,7 +3946,7 @@
$this->_storage->connectivity_test = array(
'is_connected' => $is_connected,
- 'host' => $_SERVER['HTTP_HOST'],
+ 'host' => isset( $_SERVER['HTTP_HOST'] ) ? $_SERVER['HTTP_HOST'] : '',
'server_ip' => WP_FS__REMOTE_ADDR,
'is_active' => $is_active,
'timestamp' => WP_FS__SCRIPT_START_TIME,
@@ -17653,6 +17653,31 @@
/**
* Install plugin with new user.
*
+ * You can use this method to sync activation with the Freemius WP SDK where the activation happened outside of the regular opt-in flow, for example if you're using an external licensing server with our api:
+ *
+ * https://docs.freemius.com/api/licenses/activate
+ *
+ * In that case you can call this method like following:
+ *
+ * ```
+ *
+ * my_fs()->install_with_new_user(
+ * $result['user_id'],
+ * $result['user_public_key'],
+ * $result['user_secret_key'],
+ * $result['is_marketing_allowed'],
+ * null,
+ * true,
+ * $result['install_id'],
+ * $result['install_public_key'],
+ * $result['install_secret_key'],
+ * false
+ * );
+ *
+ * ```
+ *
+ * Here `$result` represents the object returned by the API endpoint.
+ *
* @author Vova Feldman (@svovaf)
* @since 1.1.7.4
*
@@ -17670,7 +17695,7 @@
*
* @return string If redirect is `false`, returns the next page the user should be redirected to.
*/
- private function install_with_new_user(
+ public function install_with_new_user(
$user_id,
$user_public_key,
$user_secret_key,
--- a/affiliatex/vendor/freemius/wordpress-sdk/includes/entities/class-fs-payment.php
+++ b/affiliatex/vendor/freemius/wordpress-sdk/includes/entities/class-fs-payment.php
@@ -80,11 +80,22 @@
*/
public $source = 0;
+ /**
+ * Presentment payment information for customer-facing currency display.
+ *
+ * @var object|null
+ */
+ public $presentment;
+
#endregion Properties
const CURRENCY_USD = 'usd';
const CURRENCY_GBP = 'gbp';
const CURRENCY_EUR = 'eur';
+ const CURRENCY_ILS = 'ils';
+ const CURRENCY_CAD = 'cad';
+ const CURRENCY_AUD = 'aud';
+ const CURRENCY_PLN = 'pln';
/**
* @param object|bool $payment
@@ -120,6 +131,44 @@
}
/**
+ * @return bool
+ */
+ private function has_presentment()
+ {
+ return is_object( $this->presentment );
+ }
+
+ /**
+ * @return float
+ */
+ private function get_display_gross()
+ {
+ return $this->has_presentment() ?
+ (float) $this->presentment->gross :
+ (float) $this->gross;
+ }
+
+ /**
+ * @return float
+ */
+ private function get_display_vat()
+ {
+ return $this->has_presentment() ?
+ (float) $this->presentment->vat :
+ (float) $this->vat;
+ }
+
+ /**
+ * @return string
+ */
+ private function get_display_currency()
+ {
+ return $this->has_presentment() ?
+ $this->presentment->currency :
+ $this->currency;
+ }
+
+ /**
* Returns the gross in this format:
* `{symbol}{amount | 2 decimal digits} {currency | uppercase}`
*
@@ -132,12 +181,13 @@
*/
function formatted_gross()
{
- $price = $this->gross + $this->vat;
+ $price = $this->get_display_gross() + $this->get_display_vat();
+
return (
( $price < 0 ? '-' : '' ) .
$this->get_symbol() .
number_format( abs( $price ), 2, '.', ',' ) . ' ' .
- strtoupper( $this->currency )
+ strtoupper( $this->get_display_currency() )
);
}
@@ -161,9 +211,17 @@
self::CURRENCY_USD => '$',
self::CURRENCY_GBP => '£',
self::CURRENCY_EUR => '€',
+ self::CURRENCY_ILS => '₪',
+ self::CURRENCY_CAD => '$',
+ self::CURRENCY_AUD => '$',
+ self::CURRENCY_PLN => 'zł',
);
}
- return self::$CURRENCY_2_SYMBOL[ $this->currency ];
+ $currency = $this->get_display_currency();
+
+ return isset( self::$CURRENCY_2_SYMBOL[ $currency ] )
+ ? self::$CURRENCY_2_SYMBOL[ $currency ]
+ : strtoupper( $currency ) . ' ';
}
- }
No newline at end of file
+ }
--- a/affiliatex/vendor/freemius/wordpress-sdk/includes/managers/class-fs-checkout-manager.php
+++ b/affiliatex/vendor/freemius/wordpress-sdk/includes/managers/class-fs-checkout-manager.php
@@ -110,6 +110,15 @@
// If add-on isn't activated assume the premium version isn't installed.
$is_premium = false;
}
+
+ // Override the checkout context with the add-on's purchase details so the checkout flow is initialized for the selected add-on instead of the parent product.
+ $context_params['plugin_id'] = $plugin_id;
+
+ foreach ( array( 'plan_id', 'pricing_id', 'billing_cycle', 'is_trial' ) as $param ) {
+ if ( fs_request_has( $param ) ) {
+ $context_params[ $param ] = fs_request_get( $param );
+ }
+ }
}
// Get site context secure params.
@@ -187,7 +196,7 @@
// Allowlist only allowed query params.
$filtered_params = array_intersect_key($filtered_params, $this->_allowed_custom_params);
- return array_merge( $context_params, $filtered_params, $_GET, array(
+ return array_merge( $_GET, $context_params, $filtered_params, array(
// Current plugin version.
'plugin_version' => $fs->get_plugin_version(),
'sdk_version' => WP_FS__SDK_VERSION,
--- a/affiliatex/vendor/freemius/wordpress-sdk/includes/managers/class-fs-contact-form-manager.php
+++ b/affiliatex/vendor/freemius/wordpress-sdk/includes/managers/class-fs-contact-form-manager.php
@@ -77,8 +77,9 @@
$query_params = $this->get_query_params( $fs );
$query_params['is_standalone'] = 'true';
+ // Intentionally using add_query_arg( '', '' ) to preserve the legacy behavior of resolving the current admin URL.
$query_params['parent_url'] = admin_url( add_query_arg( '', '' ) );
return WP_FS__ADDRESS . '/contact/?' . http_build_query( $query_params );
}
- }
No newline at end of file
+ }
--- a/affiliatex/vendor/freemius/wordpress-sdk/includes/sdk/FreemiusWordPress.php
+++ b/affiliatex/vendor/freemius/wordpress-sdk/includes/sdk/FreemiusWordPress.php
@@ -408,7 +408,7 @@
$pWPRemoteArgs = array(
'method' => strtoupper( $pMethod ),
'connect_timeout' => 10,
- 'timeout' => 60,
+ 'timeout' => WP_FS__API_TIMEOUT,
'follow_redirects' => true,
'redirection' => 5,
'user-agent' => $user_agent,
--- a/affiliatex/vendor/freemius/wordpress-sdk/start.php
+++ b/affiliatex/vendor/freemius/wordpress-sdk/start.php
@@ -15,7 +15,7 @@
*
* @var string
*/
- $this_sdk_version = '2.13.1';
+ $this_sdk_version = '2.13.4';
#region SDK Selection Logic --------------------------------------------------------------------