| @@ -120,9 +120,10 @@ | ||
| 120 | 120 | |
| 121 | 121 | $postvars = self::paypal_postvars_utf8($postvars); |
| 122 | 122 | $endpoint = ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "www.sandbox.paypal.com" : "www.paypal.com"; |
| 123 | 123 | |
| 124 | - if(!empty($_REQUEST["s2member_paypal_proxy"]) && !empty($_REQUEST["s2member_paypal_proxy_verification"]) && $_REQUEST["s2member_paypal_proxy_verification"] === c_ws_plugin__s2member_paypal_utilities::paypal_proxy_key_gen()) | |
| 124 | + //260909.0411 Normalize proxy verification input types and use the standard constant-time comparison helper. | |
| 125 | + if(!empty($_REQUEST["s2member_paypal_proxy"]) && is_string($_REQUEST["s2member_paypal_proxy"]) && !empty($_REQUEST["s2member_paypal_proxy_verification"]) && is_string($_REQUEST["s2member_paypal_proxy_verification"]) && is_string($proxy_verification_key = c_ws_plugin__s2member_paypal_utilities::paypal_proxy_key_gen()) && hash_equals($proxy_verification_key, $_REQUEST["s2member_paypal_proxy_verification"])) | |
| 125 | 126 | return apply_filters("ws_plugin__s2member_paypal_postvars", array_merge($postvars, array("proxy_verified" => $_REQUEST["s2member_paypal_proxy"])), get_defined_vars()); |
| 126 | 127 | |
| 127 | 128 | else if(empty($_POST) && !empty($_GET["s2member_paypal_proxy"]) && !empty($_GET["s2member_paypal_proxy_verification"]) && c_ws_plugin__s2member_utils_urls::s2member_sig_ok($_SERVER["REQUEST_URI"], false, false, "s2member_paypal_proxy_verification")) |
| 128 | 129 | return apply_filters("ws_plugin__s2member_paypal_postvars", array_merge($postvars, array("proxy_verified" => $_GET["s2member_paypal_proxy"])), get_defined_vars()); |
| @@ -323,10 +324,15 @@ | ||
| 323 | 324 | if(is_multisite() && !is_main_site()) |
| 324 | 325 | $key = md5(c_ws_plugin__s2member_utils_encryption::xencrypt(strtolower($current_blog->domain.$current_blog->path), false, false)); |
| 325 | 326 | |
| 326 | 327 | else { |
| 327 | - $host = ($GLOBALS['WS_PLUGIN__']['s2member']['o']['skip_ipn_domain_validation']) ? parse_url(home_url('/'), PHP_URL_HOST) : $_SERVER["HTTP_HOST"]; //250917 | |
| 328 | - $key = md5(c_ws_plugin__s2member_utils_encryption::xencrypt(preg_replace("/\:[0-9]+$/", "", strtolower((string) $host)), false, false)); | |
| 328 | + //260909.0217 Normalize host selection so proxy verification behaves consistently across different server configurations. | |
| 329 | + $site_host = preg_replace("/\:[0-9]+$/", "", strtolower((string)parse_url(home_url('/'), PHP_URL_HOST))); | |
| 330 | + $request_host = (!empty($_SERVER["HTTP_HOST"]) && is_string($_SERVER["HTTP_HOST"])) ? preg_replace("/\:[0-9]+$/", "", strtolower($_SERVER["HTTP_HOST"])) : ''; | |
| 331 | + $host = ($GLOBALS['WS_PLUGIN__']['s2member']['o']['skip_ipn_domain_validation']) ? $site_host : $request_host; | |
| 332 | + $host = strlen($host) ? $host : $site_host; | |
| 333 | + $host = strlen($host) ? $host : 's2member-paypal-proxy'; //260909.0338 Provide a stable final fallback when no usable site host is available. | |
| 334 | + $key = md5(c_ws_plugin__s2member_utils_encryption::xencrypt($host, false, false)); | |
| 329 | 335 | } |
| 330 | 336 | |
| 331 | 337 | return apply_filters("ws_plugin__s2member_paypal_proxy_key_gen", $key, get_defined_vars()); |
| 332 | 338 | } |
| @@ -1554,9 +1560,9 @@ | ||
| 1554 | 1560 | $gateway_checkout_lock = ''; |
| 1555 | 1561 | |
| 1556 | 1562 | if($gateway_checkout_id) |
| 1557 | 1563 | { |
| 1558 | - $gateway_checkout = c_ws_plugin__s2member_gateway_checkouts::get($gateway_checkout_id); | |
| 1564 | + $gateway_checkout = c_ws_plugin__s2member_gateway_checkouts::load_state($gateway_checkout_id); | |
| 1559 | 1565 | if(!$gateway_checkout || (string)$gateway_checkout['gateway'] !== 'paypal_checkout' || (string)$gateway_checkout['operation'] !== 'payment') |
| 1560 | 1566 | return array('__error' => 'gateway_checkout_invalid'); |
| 1561 | 1567 | |
| 1562 | 1568 | //260902.0635 Return an already-persisted PayPal order before another provider create; a lost browser response can therefore resume the same logical purchase. |
| @@ -1567,9 +1573,9 @@ | ||
| 1567 | 1573 | $gateway_checkout_lock = c_ws_plugin__s2member_gateway_checkouts::processing_lock($gateway_checkout_id); |
| 1568 | 1574 | if(!$gateway_checkout_lock) |
| 1569 | 1575 | return array('__error' => 'gateway_checkout_busy'); |
| 1570 | 1576 | |
| 1571 | - $gateway_checkout = c_ws_plugin__s2member_gateway_checkouts::get($gateway_checkout_id); | |
| 1577 | + $gateway_checkout = c_ws_plugin__s2member_gateway_checkouts::load_state($gateway_checkout_id); | |
| 1572 | 1578 | if(!$gateway_checkout || (string)$gateway_checkout['gateway'] !== 'paypal_checkout' || (string)$gateway_checkout['operation'] !== 'payment') |
| 1573 | 1579 | { |
| 1574 | 1580 | c_ws_plugin__s2member_gateway_checkouts::processing_unlock($gateway_checkout_id, $gateway_checkout_lock); |
| 1575 | 1581 | return array('__error' => 'gateway_checkout_invalid'); |
| @@ -1850,9 +1856,9 @@ | ||
| 1850 | 1856 | |
| 1851 | 1857 | if($gateway_checkout_id) |
| 1852 | 1858 | { |
| 1853 | 1859 | //260907.1820 For coordinator-backed captures, the order ID already persisted server-side is authoritative; never let a browser-supplied order ID rebind this logical checkout to another PayPal resource. |
| 1854 | - $gateway_checkout = c_ws_plugin__s2member_gateway_checkouts::get($gateway_checkout_id); | |
| 1860 | + $gateway_checkout = c_ws_plugin__s2member_gateway_checkouts::load_state($gateway_checkout_id); | |
| 1855 | 1861 | $expected_order_id = $gateway_checkout && !empty($gateway_checkout['gateway_ids']['order_id']) ? (string)$gateway_checkout['gateway_ids']['order_id'] : ''; |
| 1856 | 1862 | if(!$gateway_checkout || (string)$gateway_checkout['gateway'] !== 'paypal_checkout' || (string)$gateway_checkout['operation'] !== 'payment' || !$expected_order_id || !hash_equals($expected_order_id, $order_id)) |
| 1857 | 1863 | return array('__error' => 'gateway_checkout_order_mismatch'); |
| 1858 | 1864 | |
| @@ -1878,9 +1884,9 @@ | ||
| 1878 | 1884 | try |
| 1879 | 1885 | { |
| 1880 | 1886 | if($gateway_checkout_id) |
| 1881 | 1887 | { |
| 1882 | - $gateway_checkout = c_ws_plugin__s2member_gateway_checkouts::get($gateway_checkout_id); | |
| 1888 | + $gateway_checkout = c_ws_plugin__s2member_gateway_checkouts::load_state($gateway_checkout_id); | |
| 1883 | 1889 | if(!$gateway_checkout || empty($gateway_checkout['gateway_ids']['order_id']) || !hash_equals((string)$gateway_checkout['gateway_ids']['order_id'], $order_id)) |
| 1884 | 1890 | return array('__error' => 'gateway_checkout_order_mismatch'); |
| 1885 | 1891 | |
| 1886 | 1892 | $gateway_status = !empty($gateway_checkout['gateway_status']) ? strtoupper((string)$gateway_checkout['gateway_status']) : ''; |
| @@ -2030,9 +2036,9 @@ | ||
| 2030 | 2036 | } |
| 2031 | 2037 | |
| 2032 | 2038 | try |
| 2033 | 2039 | { |
| 2034 | - $gateway_checkout = c_ws_plugin__s2member_gateway_checkouts::get($gateway_checkout_id); | |
| 2040 | + $gateway_checkout = c_ws_plugin__s2member_gateway_checkouts::load_state($gateway_checkout_id); | |
| 2035 | 2041 | if(!$gateway_checkout || (string)$gateway_checkout['gateway'] !== 'paypal_checkout' || (string)$gateway_checkout['operation'] !== 'payment') |
| 2036 | 2042 | return array('handled' => FALSE, 'ok' => FALSE, 'error' => 'not_coordinator_checkout'); |
| 2037 | 2043 | |
| 2038 | 2044 | //260907.1820 Provider identities are immutable once learned: browser/webhook reconciliation may advance status only for the same PayPal order/capture and must never rebind a checkout to conflicting IDs. |
| @@ -2090,9 +2096,9 @@ | ||
| 2090 | 2096 | |
| 2091 | 2097 | if(!$gateway_checkout_id || ($completion_error = self::paypal_checkout_order_completion_error($order, $order_id, $token))) |
| 2092 | 2098 | return array('ok' => FALSE, 'error' => $completion_error ? $completion_error : 'gateway_checkout_invalid'); |
| 2093 | 2099 | |
| 2094 | - $gateway_checkout = c_ws_plugin__s2member_gateway_checkouts::get($gateway_checkout_id); | |
| 2100 | + $gateway_checkout = c_ws_plugin__s2member_gateway_checkouts::load_state($gateway_checkout_id); | |
| 2095 | 2101 | if(!$gateway_checkout || (string)$gateway_checkout['gateway'] !== 'paypal_checkout' || (string)$gateway_checkout['operation'] !== 'payment') |
| 2096 | 2102 | return array('ok' => FALSE, 'error' => 'gateway_checkout_invalid'); |
| 2097 | 2103 | |
| 2098 | 2104 | $private_context = c_ws_plugin__s2member_gateway_checkouts::private_context_get($gateway_checkout_id); |
| @@ -2282,9 +2288,9 @@ | ||
| 2282 | 2288 | |
| 2283 | 2289 | if(!$subscription_id || !c_ws_plugin__s2member_gateway_checkouts::valid_id($gateway_checkout_id)) |
| 2284 | 2290 | return array('handled' => false, 'ok' => false, 'recovered' => false, 'error' => 'not_coordinator_checkout'); |
| 2285 | 2291 | |
| 2286 | - $gateway_checkout = c_ws_plugin__s2member_gateway_checkouts::get($gateway_checkout_id); | |
| 2292 | + $gateway_checkout = c_ws_plugin__s2member_gateway_checkouts::load_state($gateway_checkout_id); | |
| 2287 | 2293 | if(!$gateway_checkout || (string)$gateway_checkout['gateway'] !== 'paypal_checkout' || (string)$gateway_checkout['operation'] !== 'subscription') |
| 2288 | 2294 | return array('handled' => false, 'ok' => false, 'recovered' => false, 'error' => 'not_coordinator_checkout'); |
| 2289 | 2295 | |
| 2290 | 2296 | $lock = c_ws_plugin__s2member_gateway_checkouts::processing_lock($gateway_checkout_id, 60); |
| @@ -2292,9 +2298,9 @@ | ||
| 2292 | 2298 | return array('handled' => true, 'ok' => false, 'recovered' => false, 'error' => 'gateway_checkout_busy', 'gateway_checkout_id' => $gateway_checkout_id); |
| 2293 | 2299 | |
| 2294 | 2300 | try |
| 2295 | 2301 | { |
| 2296 | - $gateway_checkout = c_ws_plugin__s2member_gateway_checkouts::get($gateway_checkout_id); | |
| 2302 | + $gateway_checkout = c_ws_plugin__s2member_gateway_checkouts::load_state($gateway_checkout_id); | |
| 2297 | 2303 | if(!$gateway_checkout || (string)$gateway_checkout['gateway'] !== 'paypal_checkout' || (string)$gateway_checkout['operation'] !== 'subscription') |
| 2298 | 2304 | return array('handled' => true, 'ok' => false, 'recovered' => false, 'error' => 'gateway_checkout_invalid', 'gateway_checkout_id' => $gateway_checkout_id); |
| 2299 | 2305 | |
| 2300 | 2306 | $existing_subscription_id = !empty($gateway_checkout['gateway_ids']['subscription_id']) ? (string)$gateway_checkout['gateway_ids']['subscription_id'] : ''; |
| @@ -2350,9 +2356,9 @@ | ||
| 2350 | 2356 | $gateway_checkout_lock = ''; |
| 2351 | 2357 | |
| 2352 | 2358 | if($gateway_checkout_id) |
| 2353 | 2359 | { |
| 2354 | - $gateway_checkout = c_ws_plugin__s2member_gateway_checkouts::get($gateway_checkout_id); | |
| 2360 | + $gateway_checkout = c_ws_plugin__s2member_gateway_checkouts::load_state($gateway_checkout_id); | |
| 2355 | 2361 | if(!$gateway_checkout || (string)$gateway_checkout['gateway'] !== 'paypal_checkout' || (string)$gateway_checkout['operation'] !== 'subscription') |
| 2356 | 2362 | return array('__error' => 'gateway_checkout_invalid'); |
| 2357 | 2363 | |
| 2358 | 2364 | //260901.2145 Return a previously persisted PayPal subscription before making another create request; this also recovers a browser reload after server-side creation succeeded. |
| @@ -2362,9 +2368,9 @@ | ||
| 2362 | 2368 | $gateway_checkout_lock = c_ws_plugin__s2member_gateway_checkouts::processing_lock($gateway_checkout_id); |
| 2363 | 2369 | if(!$gateway_checkout_lock) |
| 2364 | 2370 | return array('__error' => 'gateway_checkout_busy'); |
| 2365 | 2371 | |
| 2366 | - $gateway_checkout = c_ws_plugin__s2member_gateway_checkouts::get($gateway_checkout_id); | |
| 2372 | + $gateway_checkout = c_ws_plugin__s2member_gateway_checkouts::load_state($gateway_checkout_id); | |
| 2367 | 2373 | if(!$gateway_checkout || (string)$gateway_checkout['gateway'] !== 'paypal_checkout' || (string)$gateway_checkout['operation'] !== 'subscription') |
| 2368 | 2374 | { |
| 2369 | 2375 | c_ws_plugin__s2member_gateway_checkouts::processing_unlock($gateway_checkout_id, $gateway_checkout_lock); |
| 2370 | 2376 | return array('__error' => 'gateway_checkout_invalid'); |