Changeset 3005252
- Timestamp:
- 12/04/2023 06:25:01 PM (16 months ago)
- Location:
- unbounce
- Files:
-
- 22 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
unbounce/tags/1.1.1/UBConfig.php
r2953445 r3005252 3 3 class UBConfig 4 4 { 5 const DYNAMIC_CONFIG_DEFAULT_TIMEOUT = 86400; 6 const DYNAMIC_CONFIG_FAILURE_TIMEOUT = 1200; 5 7 6 8 const UB_PLUGIN_NAME = 'ub-wordpress'; 7 9 const UB_CACHE_TIMEOUT_ENV_KEY = 'UB_WP_ROUTES_CACHE_EXP'; 8 const UB_USER_AGENT = 'Unbounce WP Plugin 1.1. 0';9 const UB_VERSION = '1.1. 0';10 const UB_USER_AGENT = 'Unbounce WP Plugin 1.1.1'; 11 const UB_VERSION = '1.1.1'; 10 12 11 13 // WP Admin Pages … … 15 17 16 18 // Option keys 19 const UB_DYNAMIC_CONFIG_CACHE_KEY = 'ub-dynamic-config-cache'; 17 20 const UB_ROUTES_CACHE_KEY = 'ub-route-cache'; 18 21 const UB_PAGE_SERVER_DOMAIN_KEY = 'ub-page-server-domain'; 22 const UB_DYNAMIC_CONFIG_DOMAIN_KEY = 'ub-dynamic-config-domain'; 19 23 const UB_API_URL_KEY = 'ub-api-url'; 20 24 const UB_API_CLIENT_ID_KEY = 'ub-api-client-id'; … … 23 27 const UB_USER_ID_KEY = 'ub-user-id'; 24 28 const UB_DOMAIN_ID_KEY = 'ub-domain-id'; 29 const UB_DOMAIN_UUID_KEY = 'ub-domain-uuid'; 25 30 const UB_CLIENT_ID_KEY = 'ub-client-id'; 26 31 const UB_PROXY_ERROR_MESSAGE_KEY = 'ub-proxy-error-message'; … … 33 38 const UB_RESPONSE_HEADERS_FORWARDED_KEY = 'ub-response-headers-forwarded'; 34 39 40 const UB_DEFAULT_REQUEST_HEADER_ALLOW = '/^(?:Accept|Content-Type|Referer|User-Agent|If-None-Match|Host|X-Forwarded-.+|X-Proxied-For|X-Ub-Wordpress-.+|Cookie|Accept-Language|Origin|Access-Control-Request-Headers|Access-Control-Request-Method)$/i'; 41 const UB_DEFAULT_REQUEST_HEADER_ADD = array(); 42 const UB_DEFAULT_REQUEST_COOKIE_ALLOW = array('ubvs', 'ubpv', 'ubvt', 'hubspotutk'); 43 const UB_DEFAULT_RESPONSE_HEADER_ALLOW = array( 44 'content-length', 45 'content-location', 46 'content-type', 47 'location', 48 'link', 49 'set-cookie', 50 'cf-ray', 51 'cf-cache-status', 52 'access-control-allow-origin', 53 'access-control-allow-credentials', 54 'access-control-allow-headers', 55 'access-control-max-age' 56 ); 57 35 58 public static function ub_option_defaults() 36 59 { … … 38 61 // Arrays are not allowed in class constants, so use a function 39 62 return array( 63 UBConfig::UB_DYNAMIC_CONFIG_CACHE_KEY => array( 64 'request_header_allow' => UBConfig::UB_DEFAULT_REQUEST_HEADER_ALLOW, 65 'request_header_add' => UBConfig::UB_DEFAULT_REQUEST_HEADER_ADD, 66 'request_cookie_allow' => UBConfig::UB_DEFAULT_REQUEST_COOKIE_ALLOW, 67 'response_header_allow' => UBConfig::UB_DEFAULT_RESPONSE_HEADER_ALLOW 68 ), 40 69 UBConfig::UB_ROUTES_CACHE_KEY => array(), 41 70 UBConfig::UB_PAGE_SERVER_DOMAIN_KEY => UBConfig::default_page_server_domain(), 71 UBConfig::UB_DYNAMIC_CONFIG_DOMAIN_KEY => UBConfig::default_dynamic_config_retrieval_domain(), 42 72 UBConfig::UB_API_URL_KEY => UBConfig::default_api_url(), 43 73 UBConfig::UB_API_CLIENT_ID_KEY => UBConfig::default_api_client_id(), … … 46 76 UBConfig::UB_USER_ID_KEY => '', 47 77 UBConfig::UB_DOMAIN_ID_KEY => '', 78 UBConfig::UB_DOMAIN_UUID_KEY => '', 48 79 UBConfig::UB_CLIENT_ID_KEY => '', 49 80 UBConfig::UB_PROXY_ERROR_MESSAGE_KEY => '', … … 76 107 } 77 108 109 public static function default_dynamic_config_retrieval_domain() 110 { 111 $domain = getenv('UB_DYNAMIC_CONFIG_DOMAIN'); 112 return $domain ? $domain : 'wp-config.unbouncepages.com'; 113 } 114 78 115 public static function default_api_url() 79 116 { … … 96 133 public static function page_server_domain() 97 134 { 98 return get_option(UBConfig::UB_PAGE_SERVER_DOMAIN_KEY, UBConfig::default_page_server_domain()); 135 $domain = get_option(UBConfig::UB_PAGE_SERVER_DOMAIN_KEY, UBConfig::default_page_server_domain()); 136 137 return UBConfig::add_domain_uuid_subdomain($domain); 138 } 139 140 public static function dynamic_config_retrieval_domain() 141 { 142 $domain = get_option(UBConfig::UB_DYNAMIC_CONFIG_DOMAIN_KEY, UBConfig::default_dynamic_config_retrieval_domain()); 143 144 return UBConfig::add_domain_uuid_subdomain($domain); 145 } 146 147 private static function add_domain_uuid_subdomain($domain) 148 { 149 $subdomain = get_option(UBConfig::UB_DOMAIN_UUID_KEY); 150 151 if ($subdomain) { 152 $domain = $subdomain . '.' . $domain; 153 } 154 155 return $domain; 99 156 } 100 157 … … 131 188 public static function create_none_response() 132 189 { 133 return array(array('status' => 'NONE') , null, null, null);190 return array(array('status' => 'NONE')); 134 191 } 135 192 136 193 public static function create_same_response($etag, $max_age) 137 194 { 138 return array(array('status' => 'SAME'), $etag, $max_age , null);139 } 140 141 public static function create_new_response ($etag, $max_age, $proxyable_url_set)195 return array(array('status' => 'SAME'), $etag, $max_age); 196 } 197 198 public static function create_new_response_proxyable_url_set($etag, $max_age, $proxyable_url_set) 142 199 { 143 200 return array(array('status' => 'NEW'), $etag, $max_age, $proxyable_url_set); 144 201 } 145 202 203 public static function create_new_response_dynamic_config($etag, $max_age, $request_header_allow, $request_header_add, $request_cookie_allow, $response_header_allow) 204 { 205 return array(array('status' => 'NEW'), $etag, $max_age, $request_header_allow, $request_header_add, $request_cookie_allow, $response_header_allow); 206 } 207 146 208 public static function create_failure_response($failure_message) 147 209 { 148 210 return array(array('status' => 'FAILURE', 149 'failure_message' => $failure_message), 150 null, null, null); 211 'failure_message' => $failure_message)); 151 212 } 152 213 … … 187 248 try { 188 249 $url = 'https://' . $ps_domain . '/sitemap.xml'; 189 $curl = curl_init(); 190 $curl_options = array( 191 CURLOPT_URL => $url, 192 CURLOPT_CUSTOMREQUEST => "GET", 193 CURLOPT_HEADER => true, 194 CURLOPT_USERAGENT => UBConfig::UB_USER_AGENT, 195 CURLOPT_HTTPHEADER => UBHTTP::convert_headers_to_curl( 196 array( 197 'x-forwarded-host' => $domain, 198 'if-none-match' => $etag 199 ) 200 ), 201 CURLOPT_RETURNTRANSFER => true, 202 CURLOPT_FOLLOWLOCATION => false, 203 CURLOPT_TIMEOUT => 5 204 ); 205 250 206 251 UBLogger::debug("Retrieving routes from '$url', etag: '$etag', host: '$domain'"); 207 252 208 curl_setopt_array($curl, $curl_options); 209 $data = curl_exec($curl); 210 $http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE); 211 $header_size = strlen($data) - curl_getinfo($curl, CURLINFO_SIZE_DOWNLOAD); 212 $curl_error = null; 213 $etag = null; 214 $max_age = null; 215 216 // when having an CURL error, http_code is 0 217 if ($http_code == 0) { 218 $curl_error = curl_error($curl); 219 } 220 221 curl_close($curl); 222 223 $headers = substr($data, 0, $header_size); 224 225 $matches = array(); 226 $does_match = preg_match('/ETag: (\S+)/is', $headers, $matches); 227 if ($does_match) { 228 $etag = $matches[1]; 229 } 230 231 $matches = array(); 232 $does_match = preg_match('/Cache-Control: max-age=(\S+)/is', $headers, $matches); 233 if ($does_match) { 234 $max_age = $matches[1]; 235 } 253 list($data, $http_code, $header_size, $curl_error) = UBConfig::make_curl_request($url, $domain, $etag); 254 list($etag, $max_age) = UBConfig::process_headers($data, $header_size); 236 255 237 256 if ($http_code == 200) { … … 241 260 if ($success) { 242 261 UBLogger::debug("Retrieved new routes, HTTP code: '$http_code'"); 243 return UBConfig::create_new_response ($etag, $max_age, $result);262 return UBConfig::create_new_response_proxyable_url_set($etag, $max_age, $result); 244 263 } else { 245 264 $errors = join(', ', $result); … … 249 268 } 250 269 } 251 if ($http_code == 304) { 252 UBLogger::debug("Routes have not changed, HTTP code: '$http_code'"); 253 return UBConfig::create_same_response($etag, $max_age); 254 } 255 if ($http_code == 404) { 256 UBLogger::debug("No routes to retrieve, HTTP code: '$http_code'"); 257 return UBConfig::create_none_response(); 258 } else { 259 $failure_message = "An error occurred while retrieving routes; 260 HTTP code: '$http_code'; 261 Error: " . $curl_error; 262 UBLogger::warning($failure_message); 263 return UBConfig::create_failure_response($failure_message); 264 } 270 271 return UBConfig::handle_non_200_http_response($http_code, $etag, $max_age, $curl_error, 'routes'); 265 272 } catch (Exception $e) { 266 273 $failure_message = "An error occurred while retrieving routes; Error: " . $e; … … 323 330 $cache_max_time_default = 10; 324 331 325 $ps_domain = get_option(UBConfig::UB_PAGE_SERVER_DOMAIN_KEY, UBConfig::default_page_server_domain()); 332 $ps_domain = UBConfig::page_server_domain(); 333 326 334 $domains_info = get_option(UBConfig::UB_ROUTES_CACHE_KEY, array()); 327 335 … … 396 404 } 397 405 406 // We are using a fetched dynamic config to retrieve information 407 // such that we decide what request headers to allow and add, 408 // as well as what response headers and request cookies to allow. 409 public static function read_unbounce_dynamic_config($domain) 410 { 411 // Check if curl is installed to prevent fatal error 412 if (!UBDiagnostics::is_curl_installed()) { 413 return array(); 414 } 415 416 $cache_max_time_default = UBConfig::DYNAMIC_CONFIG_DEFAULT_TIMEOUT; 417 $dynamic_config = get_option(UBConfig::UB_DYNAMIC_CONFIG_CACHE_KEY, array()); 418 419 if (!is_array($dynamic_config)) { 420 $dynamic_config = array(); 421 } 422 423 $dynamic_config_fetched_at = UBUtil::array_fetch($dynamic_config, 'fetched_at'); 424 $dynamic_config_cache_timeout = UBUtil::array_fetch($dynamic_config, 'cache_timeout'); 425 $dynamic_config_etag = UBUtil::array_fetch($dynamic_config, 'etag'); 426 427 $cache_max_time = is_null($dynamic_config_cache_timeout) ? $cache_max_time_default : $dynamic_config_cache_timeout; 428 429 // regardless of dynamic_config_cache_timeout being set, if the last fetch failed or returned a 404, we want to try again in 20 minutes 430 if ($dynamic_config['last_status'] === 'FAILURE' || $dynamic_config['last_status'] === 'NONE') { 431 $cache_max_time = UBConfig::DYNAMIC_CONFIG_FAILURE_TIMEOUT; 432 } 433 434 $current_time = time(); 435 436 if (is_null($dynamic_config_fetched_at) || 437 ($current_time - $dynamic_config_fetched_at > $cache_max_time)) { 438 try { 439 $can_fetch = UBUtil::get_lock(); 440 UBLogger::debug('Locking: ' . $can_fetch); 441 442 if ($can_fetch) { 443 $result_array = UBConfig::fetch_dynamic_config($domain, $dynamic_config_etag); 444 list($routes_status, $etag, $max_age, $request_header_allow_new, $request_header_add_new, $request_cookie_allow_new, $response_header_allow_new) = $result_array; 445 446 if ($routes_status['status'] === 'NEW') { 447 $dynamic_config['request_header_allow'] = $request_header_allow_new; 448 $dynamic_config['request_header_add'] = $request_header_add_new; 449 $dynamic_config['request_cookie_allow'] = $request_cookie_allow_new; 450 $dynamic_config['response_header_allow'] = $response_header_allow_new; 451 $dynamic_config['etag'] = $etag; 452 $dynamic_config['cache_timeout'] = $max_age; 453 } elseif ($routes_status['status'] === 'SAME') { 454 // Just extend the cache 455 $dynamic_config['cache_timeout'] = $max_age; 456 } elseif ($routes_status['status'] === 'FAILURE' || $routes_status['status'] === 'NONE') { 457 UBLogger::warning('Not updating the dynamic config: Fetching failed or 404 was returned'); 458 } else { 459 UBLogger::warning("Unknown response from dynamic config fetcher: '$routes_status'"); 460 } 461 462 $dynamic_config['fetched_at'] = $current_time; 463 $dynamic_config['last_status'] = $routes_status['status']; 464 465 if ($routes_status['status'] === 'FAILURE') { 466 $dynamic_config['failure_message'] = $routes_status['failure_message']; 467 } 468 469 update_option(UBConfig::UB_DYNAMIC_CONFIG_CACHE_KEY, $dynamic_config, false); 470 } 471 } catch (Exception $e) { 472 UBLogger::warning('Could not update dynamic config: ' . $e); 473 $dynamic_config['last_status'] = 'FAILURE'; 474 $dynamic_config['failure_message'] = $e->getMessage(); 475 update_option(UBConfig::UB_DYNAMIC_CONFIG_CACHE_KEY, $dynamic_config, false); 476 } 477 478 $release_result = UBUtil::release_lock(); 479 UBLogger::debug('Unlocking: ' . $release_result); 480 } 481 482 return UBUtil::array_select_by_key( 483 $dynamic_config, 484 array('request_header_allow', 'request_header_add', 'request_cookie_allow', 'response_header_allow') 485 ); 486 } 487 488 private static function make_curl_request($url, $domain, $etag) 489 { 490 $curl = curl_init(); 491 $curl_options = array( 492 CURLOPT_URL => $url, 493 CURLOPT_CUSTOMREQUEST => "GET", 494 CURLOPT_HEADER => true, 495 CURLOPT_USERAGENT => UBConfig::UB_USER_AGENT, 496 CURLOPT_HTTPHEADER => UBHTTP::convert_headers_to_curl( 497 array( 498 'x-forwarded-host' => $domain, 499 'if-none-match' => $etag 500 ) 501 ), 502 CURLOPT_RETURNTRANSFER => true, 503 CURLOPT_FOLLOWLOCATION => false, 504 CURLOPT_TIMEOUT => 5 505 ); 506 curl_setopt_array($curl, $curl_options); 507 508 $data = curl_exec($curl); 509 $http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE); 510 $header_size = strlen($data) - curl_getinfo($curl, CURLINFO_SIZE_DOWNLOAD); 511 $curl_error = $http_code == 0 ? curl_error($curl) : null; 512 513 curl_close($curl); 514 515 return array($data, $http_code, $header_size, $curl_error); 516 } 517 518 private static function process_headers($data, $header_size) 519 { 520 $headers = substr($data, 0, $header_size); 521 $etag = null; 522 $max_age = null; 523 524 $matches = array(); 525 $does_match = preg_match('/ETag: (\S+)/is', $headers, $matches); 526 if ($does_match) { 527 $etag = $matches[1]; 528 } 529 530 $matches = array(); 531 $does_match = preg_match('/Cache-Control: max-age=(\S+)/is', $headers, $matches); 532 if ($does_match) { 533 $max_age = $matches[1]; 534 } 535 536 // Make sure Cache-Control header is numeric to avoid errors later on when it is used for comparison 537 if (is_numeric($max_age)) { 538 $max_age = (int) $max_age; 539 } else { 540 $max_age = null; 541 } 542 543 return array($etag, $max_age); 544 } 545 546 547 548 public static function fetch_dynamic_config($domain, $etag) 549 { 550 if (!$domain) { 551 $failure_message = 'Domain not provided, not fetching dynamic config'; 552 UBLogger::warning($failure_message); 553 return UBConfig::create_failure_response($failure_message); 554 } 555 556 try { 557 $url = 'https://' . UBConfig::dynamic_config_retrieval_domain() . '/v' . UBConfig::UB_VERSION; 558 UBLogger::debug("Retrieving dynamic config from '$url', etag: '$etag', host: '$domain'"); 559 560 list($data, $http_code, $header_size, $curl_error) = UBConfig::make_curl_request($url, $domain, $etag); 561 list($etag, $max_age) = UBConfig::process_headers($data, $header_size); 562 563 if ($http_code == 200) { 564 $body = substr($data, $header_size); 565 $decoded_body = json_decode($body, true); 566 567 if (json_last_error() == JSON_ERROR_NONE) { 568 UBLogger::debug("Retrieved new dynamic config, HTTP code: '$http_code'"); 569 return UBConfig::create_new_response_dynamic_config($etag, $max_age, $decoded_body['request_header_allow'], $decoded_body['request_header_add'], $decoded_body['request_cookie_allow'], $decoded_body['response_header_allow']); 570 } else { 571 $failure_message = "An error occurred while processing dynamic config, JSON errors: " . json_last_error_msg(); 572 UBLogger::warning($failure_message); 573 return UBConfig::create_failure_response($failure_message); 574 } 575 } 576 577 return UBConfig::handle_non_200_http_response($http_code, $etag, $max_age, $curl_error, 'dynamic config'); 578 } catch (Exception $e) { 579 $failure_message = "An error occurred while retrieving dynamic config; Error: " . $e->getMessage(); 580 UBLogger::warning($failure_message); 581 return UBConfig::create_failure_response($failure_message); 582 } 583 } 584 585 public static function handle_non_200_http_response($http_code, $etag, $max_age, $curl_error, $context) 586 { 587 if ($http_code == 304) { 588 UBLogger::debug("$context have not changed, HTTP code: '$http_code'"); 589 return UBConfig::create_same_response($etag, $max_age); 590 } 591 592 if ($http_code == 404) { 593 UBLogger::debug("No $context to retrieve, HTTP code: '$http_code'"); 594 return UBConfig::create_none_response(); 595 } 596 597 $failure_message = "An error occurred while retrieving $context;HTTP code: '$http_code'; 598 Error: " . $curl_error; 599 UBLogger::warning($failure_message); 600 return UBConfig::create_failure_response($failure_message); 601 } 602 398 603 public static function is_authorized_domain($domain0) 399 604 { … … 407 612 update_option(UBConfig::UB_USER_ID_KEY, $data['user_id']); 408 613 update_option(UBConfig::UB_DOMAIN_ID_KEY, $data['domain_id']); 614 update_option(UBConfig::UB_DOMAIN_UUID_KEY, $data['domain_uuid']); 409 615 update_option(UBConfig::UB_CLIENT_ID_KEY, $data['client_id']); 410 616 update_option(UBConfig::UB_AUTHORIZED_DOMAINS_KEY, $domains); -
unbounce/tags/1.1.1/UBDiagnostics.php
r2953445 r3005252 13 13 public static function domain_checks($domain, $domain_info) 14 14 { 15 return array( 16 'Domain is Authorized' => UBConfig::is_authorized_domain($domain), 17 'Can Fetch Page Listing' => UBDiagnostics::last_status_success($domain_info), 18 ); 15 $dynamic_config = get_option(UBConfig::UB_DYNAMIC_CONFIG_CACHE_KEY, array()); 16 $uuid = get_option(UBConfig::UB_DOMAIN_UUID_KEY, ''); 17 18 $result = array( 19 'Domain is Authorized' => UBConfig::is_authorized_domain($domain), 20 'Can Fetch Page Listing' => UBDiagnostics::last_status_success($domain_info) 21 ); 22 23 if (UBConfig::has_authorized()) { 24 $result['Domain UUID'] = $uuid !== ''; 25 } 26 27 if (isset($dynamic_config['last_status'])) { 28 $result['Dynamic Config Retrieval'] = $dynamic_config['last_status'] !== 'FAILURE'; 29 } 30 31 return $result; 19 32 } 20 33 … … 101 114 'PHP Version' => phpversion(), 102 115 'WordPress Version' => UBDiagnostics::wordpress_version(), 103 'Unbounce Plugin Version' => '1.1. 0',116 'Unbounce Plugin Version' => '1.1.1', 104 117 'Checks' => self::pp(UBDiagnostics::checks($domain, $domain_info)), 105 118 'Options' => self::pp(UBDiagnostics::ub_options()), … … 179 192 'php' => phpversion(), 180 193 'wordpress' => UBDiagnostics::wordpress_version(), 181 'plugin_version' => '1.1. 0',194 'plugin_version' => '1.1.1', 182 195 'curl_installed' => self::is_curl_installed(), 183 196 'xml_installed' => self::is_xml_installed(), -
unbounce/tags/1.1.1/UBHTTP.php
r2953445 r3005252 7 7 public static $variant_url_regex = '/(.+)\/[a-z]+\.html/i'; 8 8 public static $pie_htc_url = '/PIE.htc'; 9 public static $request_header_blocklist = '/^(?:Accept-Encoding|Host|Forwarded)$/i';10 9 public static $location_header_regex = '/^(?:Location):/i'; 11 public static $cookie_allowlist = array('ubvs', 'ubpv', 'ubvt', 'hubspotutk');12 public static $response_headers_always_forwarded = array(13 'content-length',14 'content-location',15 'content-type',16 'location',17 'link',18 'set-cookie',19 'cf-ray',20 'cf-cache-status'21 );22 10 23 11 public static function is_public_ip_address($ip_address) … … 126 114 } 127 115 128 public static function stream_headers_function( )129 { 130 $header_filter = UBHTTP::create_curl_response_header_filter( );116 public static function stream_headers_function($dynamic_config) 117 { 118 $header_filter = UBHTTP::create_curl_response_header_filter($dynamic_config); 131 119 132 120 return function ($curl, $header_line) use ($header_filter) { … … 242 230 // Always add this header to responses to show it comes from our plugin. 243 231 header("X-Unbounce-Plugin: 1", false); 232 $dynamic_config = UBConfig::read_unbounce_dynamic_config($domain); 233 244 234 if (UBConfig::use_curl()) { 245 235 return UBHTTP::stream_request_curl( … … 249 239 $current_headers, 250 240 $current_protocol, 251 $domain 241 $domain, 242 $dynamic_config 252 243 ); 253 244 } else { … … 258 249 $current_headers, 259 250 $current_protocol, 260 $domain 251 $domain, 252 $dynamic_config 261 253 ); 262 254 } … … 269 261 $current_headers, 270 262 $current_protocol, 271 $domain 263 $domain, 264 $dynamic_config 272 265 ) { 273 266 $args = array( … … 277 270 'timeout' => 30, 278 271 'headers' => array_merge( 279 UBHTTP::prepare_request_headers($current_headers, $current_protocol, $domain ),272 UBHTTP::prepare_request_headers($current_headers, $current_protocol, $domain, $dynamic_config), 280 273 array( 281 274 'x-ub-wordpress-remote-request' => '1', … … 297 290 http_response_code($resp['response']['code']); 298 291 $response_headers = $resp['headers']; 299 UBHTTP::set_response_headers($response_headers );292 UBHTTP::set_response_headers($response_headers, $dynamic_config); 300 293 echo $resp['body']; 301 294 return array(true, null); … … 303 296 } 304 297 305 public static function prepare_request_headers($current_headers, $current_protocol, $domain) 306 { 307 $target_headers = array(); 308 array_walk($current_headers, function ($v, $k) use (&$target_headers) { 309 if (!preg_match(UBHTTP::$request_header_blocklist, $k)) { 310 $target_headers[$k] = $v; 311 } 312 }); 298 public static function prepare_request_headers($current_headers, $current_protocol, $domain, $dynamic_config) 299 { 300 301 $request_header_allow = UBUtil::array_fetch($dynamic_config, 'request_header_allow', UBConfig::UB_DEFAULT_REQUEST_HEADER_ALLOW); 302 $request_header_add = UBUtil::array_fetch($dynamic_config, 'request_header_add', UBConfig::UB_DEFAULT_REQUEST_HEADER_ADD); 303 $request_cookie_allow = UBUtil::array_fetch($dynamic_config, 'request_cookie_allow', UBConfig::UB_DEFAULT_REQUEST_COOKIE_ALLOW); 313 304 314 305 $current_forwarded_for = UBUtil::array_fetch($current_headers, 'x-forwarded-for'); … … 316 307 $current_remote_ip = UBUtil::array_fetch($_SERVER, 'REMOTE_ADDR'); 317 308 318 return array_merge( 319 UBHTTP::sanitize_cookies($target_headers), 309 // remove current host header as we will be setting it to the target domain 310 unset($current_headers['host']); 311 312 $merged_headers = array_merge( 313 UBHTTP::sanitize_cookies($current_headers, $request_cookie_allow), 320 314 UBHTTP::get_forwarded_headers( 321 315 $domain, … … 327 321 UBHTTP::get_common_headers() 328 322 ); 323 324 $target_headers = array(); 325 array_walk($merged_headers, function ($v, $k) use (&$target_headers, $request_header_allow) { 326 if (preg_match($request_header_allow, $k)) { 327 $target_headers[$k] = $v; 328 } 329 }); 330 331 foreach ($request_header_add as $key => $value) { 332 $target_headers[$key] = $value; 333 } 334 return $target_headers; 329 335 } 330 336 … … 333 339 $headers = array( 334 340 'host' => UBConfig::page_server_domain(), 335 'x-ub-wordpress-plugin-version' => '1.1. 0'341 'x-ub-wordpress-plugin-version' => '1.1.1' 336 342 ); 337 343 … … 364 370 } 365 371 366 public static function sanitize_cookies($headers )372 public static function sanitize_cookies($headers, $request_cookie_allow) 367 373 { 368 374 $cookie_key = "Cookie"; … … 376 382 $cookies_to_forward = UBUtil::array_select_by_key( 377 383 UBHTTP::cookie_array_from_string($headers[$cookie_key]), 378 UBHTTP::$cookie_allowlist 379 ); 380 if (sizeof($cookies_to_forward) > 0) { 381 $headers[$cookie_key] = UBHTTP::cookie_string_from_array($cookies_to_forward); 382 } 384 $request_cookie_allow 385 ); 386 387 $headers[$cookie_key] = UBHTTP::cookie_string_from_array($cookies_to_forward); 383 388 return $headers; 384 389 } … … 395 400 } 396 401 397 public static function set_response_headers($headers )398 { 399 $header_filter = UBHTTP::create_response_header_filter( );402 public static function set_response_headers($headers, $dynamic_config) 403 { 404 $header_filter = UBHTTP::create_response_header_filter($dynamic_config); 400 405 401 406 foreach ($headers as $h_key => $h_value) { … … 418 423 $current_headers, 419 424 $current_protocol, 420 $domain 425 $domain, 426 $dynamic_config 421 427 ) { 422 428 $base_response_headers = headers_list(); 423 429 424 $target_headers = UBHTTP::prepare_request_headers($current_headers, $current_protocol, $domain );430 $target_headers = UBHTTP::prepare_request_headers($current_headers, $current_protocol, $domain, $dynamic_config); 425 431 $target_headers = UBHTTP::convert_headers_to_curl($target_headers); 426 432 … … 429 435 UBLogger::debug_var('target_headers', print_r($target_headers, true)); 430 436 431 $stream_headers = UBHTTP::stream_headers_function( );437 $stream_headers = UBHTTP::stream_headers_function($dynamic_config); 432 438 $stream_body = UBHTTP::stream_response_function(); 433 439 $curl = curl_init(); … … 574 580 } 575 581 576 private static function create_curl_response_header_filter( )582 private static function create_curl_response_header_filter($dynamic_config) 577 583 { 578 584 $blocklist_regex = '/^connection:/i'; … … 585 591 } 586 592 587 $allowlist = array_merge($config_headers_forwarded, UB HTTP::$response_headers_always_forwarded);593 $allowlist = array_merge($config_headers_forwarded, UBUtil::array_fetch($dynamic_config, 'response_header_allow', array())); 588 594 $allowlist_regex = '/^('.implode('|', $allowlist).'):/i'; 589 595 return function ($header) use ($blocklist_regex, $allowlist_regex) { … … 592 598 } 593 599 594 private static function create_response_header_filter( )600 private static function create_response_header_filter($dynamic_config) 595 601 { 596 602 $config_headers_forwarded = UBConfig::response_headers_forwarded(); … … 602 608 } 603 609 604 $allowlist = array_merge($config_headers_forwarded, UB HTTP::$response_headers_always_forwarded);610 $allowlist = array_merge($config_headers_forwarded, UBUtil::array_fetch($dynamic_config, 'response_header_allow', array())); 605 611 606 612 return function ($header) use ($allowlist) { -
unbounce/tags/1.1.1/Unbounce-Page.php
r2953445 r3005252 4 4 Plugin URI: http://unbounce.com 5 5 Description: Unbounce is the most powerful standalone landing page builder available. 6 Version: 1.1. 06 Version: 1.1.1 7 7 Author: Unbounce 8 8 Author URI: http://unbounce.com … … 148 148 add_action('admin_init', function () { 149 149 $current_version = UBConfig::UB_VERSION; 150 151 if (get_option(UBConfig::UB_PLUGIN_VERSION_KEY) != $current_version) { 150 $saved_version = get_option(UBConfig::UB_PLUGIN_VERSION_KEY); 151 152 if ($saved_version != $current_version) { 152 153 UBConfig::set_options_if_not_exist(); 153 154 update_option(UBConfig::UB_PLUGIN_VERSION_KEY, $current_version); 154 155 155 // When upgrading to 1.1.0, override all previous ub-page-server-domain values to new default 156 // TODO: Remove this in subsequent plugin versions 157 update_option(UBConfig::UB_PAGE_SERVER_DOMAIN_KEY, UBConfig::default_page_server_domain()); 156 // When upgrading to 1.1.x from a 1.0.x version, override all previous ub-page-server-domain values to new default 157 if (version_compare($saved_version, '1.1.0', '<')) { 158 update_option(UBConfig::UB_PAGE_SERVER_DOMAIN_KEY, UBConfig::default_page_server_domain()); 159 } 158 160 } 159 161 … … 175 177 'set-unbounce-domains-js', 176 178 plugins_url('js/set-unbounce-domains.js', __FILE__), 177 array('jquery', 'ub-rx') 179 array('jquery', 'ub-rx'), 180 "1.1.1" 178 181 ); 179 182 wp_enqueue_script( … … 319 322 'client_id' => UBUtil::array_fetch($_POST, 'client_id', ''), 320 323 'domain_id' => UBUtil::array_fetch($_POST, 'domain_id', ''), 324 'domain_uuid' => UBUtil::array_fetch($_POST, 'domain_uuid', ''), 321 325 ); 322 326 -
unbounce/tags/1.1.1/js/set-unbounce-domains.js
r1266757 r3005252 23 23 clientId: subAccount.id, 24 24 domainId: domain.id, 25 name: domain.name 25 name: domain.name, 26 domainUUID: domain.uuid 26 27 }; 27 28 } else { … … 55 56 $form.find('[name="domain_id"]').val(wordpressDomain.domainId); 56 57 $form.find('[name="client_id"]').val(wordpressDomain.clientId); 58 $form.find('[name="domain_uuid"]').val(wordpressDomain.domainUUID); 57 59 } 58 60 -
unbounce/tags/1.1.1/readme.txt
r2953445 r3005252 3 3 Tags: Unbounce, AB testing, A/B testing, split testing, CRO, conversion optimization, wordpress landing page, wp landing pages, splash pages, landing pages, squeeze pages, lead gen, lead generation, email list, responsive landing pages, templates, inbound marketing, ppc, analytics 4 4 Requires at least: 4.1.5 5 Tested up to: 6. 36 Stable tag: 1.1. 05 Tested up to: 6.4 6 Stable tag: 1.1.1 7 7 Requires PHP: 7.2 8 8 License: GPLv2 or later … … 104 104 == Changelog == 105 105 106 = 1.1.1 = 107 * Changes to the way the plugin filters headers and cookies using a dynamic configuration. 108 * Tested with WP 6.4 109 106 110 = 1.1.0 = 107 111 * Changes the method used to communicate with Unbounce servers, which will improve the resilience of -
unbounce/tags/1.1.1/templates/authorize_button.php
r2823212 r3005252 3 3 <input type="hidden" name="user_id" /> 4 4 <input type="hidden" name="domain_id" /> 5 <input type="hidden" name="domain_uuid" /> 5 6 <input type="hidden" name="client_id" /> 6 7 <?php if (isset($outer_text)) { ?> -
unbounce/tags/1.1.1/templates/diagnostics.php
r2953445 r3005252 37 37 $sni_support = 'The Unbounce Plugin communicates with the Unbounce servers using a TLS 1.2 connection, this requires SNI support in order to function. Our diagnostics indicate that your server does not currently have SNI support.'; 38 38 39 $dynamic_config_retrieval = 'The Unbounce Plugin is unable to retrieve the dynamic configuration from Unbounce. This is required in order to make sure we are able to serve your Unbounce pages the correct way and prevent any errors. Please contact support if you continue to see this error for more than a few days.'; 40 41 $domain_uuid = 'Plugin requests are not sent to Unbounce servers with the uuid added as a subdomain, which compromises security. Please update wordpress enabled domains on the pages section.'; 42 39 43 $diagnostic_descriptions = array( 40 44 'Curl Support' => $curl_support, … … 45 49 'Supported PHP Version' => $supported_php_version, 46 50 'Supported Wordpress Version' => $supported_wordpress_version, 47 'SNI Support' => $sni_support 51 'SNI Support' => $sni_support, 52 'Dynamic Config Retrieval' => $dynamic_config_retrieval, 53 "Domain UUID" => $domain_uuid, 48 54 ); 49 55 -
unbounce/tags/1.1.1/templates/main_authorized_footer.php
r2953445 r3005252 22 22 Click here for troubleshooting and plugin diagnostics 23 23 </a> 24 <p class="ub-version">Unbounce Version 1.1. 0</p>24 <p class="ub-version">Unbounce Version 1.1.1</p> -
unbounce/tags/1.1.1/templates/main_unauthorized_footer.php
r2953445 r3005252 5 5 Click here for troubleshooting and plugin diagnostics 6 6 </a> 7 <p class="ub-version">Unbounce Version 1.1. 0</p>7 <p class="ub-version">Unbounce Version 1.1.1</p> -
unbounce/tags/1.1.1/templates/settings_response_headers_forwarded.php
r2823212 r3005252 11 11 $headers = array_map(function ($header) { 12 12 return '<code>'.$header.'</code>'; 13 }, UBHTTP::$response_headers_always_forwarded);13 }, get_option(UBConfig::UB_DYNAMIC_CONFIG_CACHE_KEY, array())['response_header_allow']); 14 14 echo implode(',', array_slice($headers, 0, -1)).' and '.end($headers); 15 15 ?> -
unbounce/trunk/UBConfig.php
r2953445 r3005252 3 3 class UBConfig 4 4 { 5 const DYNAMIC_CONFIG_DEFAULT_TIMEOUT = 86400; 6 const DYNAMIC_CONFIG_FAILURE_TIMEOUT = 1200; 5 7 6 8 const UB_PLUGIN_NAME = 'ub-wordpress'; 7 9 const UB_CACHE_TIMEOUT_ENV_KEY = 'UB_WP_ROUTES_CACHE_EXP'; 8 const UB_USER_AGENT = 'Unbounce WP Plugin 1.1. 0';9 const UB_VERSION = '1.1. 0';10 const UB_USER_AGENT = 'Unbounce WP Plugin 1.1.1'; 11 const UB_VERSION = '1.1.1'; 10 12 11 13 // WP Admin Pages … … 15 17 16 18 // Option keys 19 const UB_DYNAMIC_CONFIG_CACHE_KEY = 'ub-dynamic-config-cache'; 17 20 const UB_ROUTES_CACHE_KEY = 'ub-route-cache'; 18 21 const UB_PAGE_SERVER_DOMAIN_KEY = 'ub-page-server-domain'; 22 const UB_DYNAMIC_CONFIG_DOMAIN_KEY = 'ub-dynamic-config-domain'; 19 23 const UB_API_URL_KEY = 'ub-api-url'; 20 24 const UB_API_CLIENT_ID_KEY = 'ub-api-client-id'; … … 23 27 const UB_USER_ID_KEY = 'ub-user-id'; 24 28 const UB_DOMAIN_ID_KEY = 'ub-domain-id'; 29 const UB_DOMAIN_UUID_KEY = 'ub-domain-uuid'; 25 30 const UB_CLIENT_ID_KEY = 'ub-client-id'; 26 31 const UB_PROXY_ERROR_MESSAGE_KEY = 'ub-proxy-error-message'; … … 33 38 const UB_RESPONSE_HEADERS_FORWARDED_KEY = 'ub-response-headers-forwarded'; 34 39 40 const UB_DEFAULT_REQUEST_HEADER_ALLOW = '/^(?:Accept|Content-Type|Referer|User-Agent|If-None-Match|Host|X-Forwarded-.+|X-Proxied-For|X-Ub-Wordpress-.+|Cookie|Accept-Language|Origin|Access-Control-Request-Headers|Access-Control-Request-Method)$/i'; 41 const UB_DEFAULT_REQUEST_HEADER_ADD = array(); 42 const UB_DEFAULT_REQUEST_COOKIE_ALLOW = array('ubvs', 'ubpv', 'ubvt', 'hubspotutk'); 43 const UB_DEFAULT_RESPONSE_HEADER_ALLOW = array( 44 'content-length', 45 'content-location', 46 'content-type', 47 'location', 48 'link', 49 'set-cookie', 50 'cf-ray', 51 'cf-cache-status', 52 'access-control-allow-origin', 53 'access-control-allow-credentials', 54 'access-control-allow-headers', 55 'access-control-max-age' 56 ); 57 35 58 public static function ub_option_defaults() 36 59 { … … 38 61 // Arrays are not allowed in class constants, so use a function 39 62 return array( 63 UBConfig::UB_DYNAMIC_CONFIG_CACHE_KEY => array( 64 'request_header_allow' => UBConfig::UB_DEFAULT_REQUEST_HEADER_ALLOW, 65 'request_header_add' => UBConfig::UB_DEFAULT_REQUEST_HEADER_ADD, 66 'request_cookie_allow' => UBConfig::UB_DEFAULT_REQUEST_COOKIE_ALLOW, 67 'response_header_allow' => UBConfig::UB_DEFAULT_RESPONSE_HEADER_ALLOW 68 ), 40 69 UBConfig::UB_ROUTES_CACHE_KEY => array(), 41 70 UBConfig::UB_PAGE_SERVER_DOMAIN_KEY => UBConfig::default_page_server_domain(), 71 UBConfig::UB_DYNAMIC_CONFIG_DOMAIN_KEY => UBConfig::default_dynamic_config_retrieval_domain(), 42 72 UBConfig::UB_API_URL_KEY => UBConfig::default_api_url(), 43 73 UBConfig::UB_API_CLIENT_ID_KEY => UBConfig::default_api_client_id(), … … 46 76 UBConfig::UB_USER_ID_KEY => '', 47 77 UBConfig::UB_DOMAIN_ID_KEY => '', 78 UBConfig::UB_DOMAIN_UUID_KEY => '', 48 79 UBConfig::UB_CLIENT_ID_KEY => '', 49 80 UBConfig::UB_PROXY_ERROR_MESSAGE_KEY => '', … … 76 107 } 77 108 109 public static function default_dynamic_config_retrieval_domain() 110 { 111 $domain = getenv('UB_DYNAMIC_CONFIG_DOMAIN'); 112 return $domain ? $domain : 'wp-config.unbouncepages.com'; 113 } 114 78 115 public static function default_api_url() 79 116 { … … 96 133 public static function page_server_domain() 97 134 { 98 return get_option(UBConfig::UB_PAGE_SERVER_DOMAIN_KEY, UBConfig::default_page_server_domain()); 135 $domain = get_option(UBConfig::UB_PAGE_SERVER_DOMAIN_KEY, UBConfig::default_page_server_domain()); 136 137 return UBConfig::add_domain_uuid_subdomain($domain); 138 } 139 140 public static function dynamic_config_retrieval_domain() 141 { 142 $domain = get_option(UBConfig::UB_DYNAMIC_CONFIG_DOMAIN_KEY, UBConfig::default_dynamic_config_retrieval_domain()); 143 144 return UBConfig::add_domain_uuid_subdomain($domain); 145 } 146 147 private static function add_domain_uuid_subdomain($domain) 148 { 149 $subdomain = get_option(UBConfig::UB_DOMAIN_UUID_KEY); 150 151 if ($subdomain) { 152 $domain = $subdomain . '.' . $domain; 153 } 154 155 return $domain; 99 156 } 100 157 … … 131 188 public static function create_none_response() 132 189 { 133 return array(array('status' => 'NONE') , null, null, null);190 return array(array('status' => 'NONE')); 134 191 } 135 192 136 193 public static function create_same_response($etag, $max_age) 137 194 { 138 return array(array('status' => 'SAME'), $etag, $max_age , null);139 } 140 141 public static function create_new_response ($etag, $max_age, $proxyable_url_set)195 return array(array('status' => 'SAME'), $etag, $max_age); 196 } 197 198 public static function create_new_response_proxyable_url_set($etag, $max_age, $proxyable_url_set) 142 199 { 143 200 return array(array('status' => 'NEW'), $etag, $max_age, $proxyable_url_set); 144 201 } 145 202 203 public static function create_new_response_dynamic_config($etag, $max_age, $request_header_allow, $request_header_add, $request_cookie_allow, $response_header_allow) 204 { 205 return array(array('status' => 'NEW'), $etag, $max_age, $request_header_allow, $request_header_add, $request_cookie_allow, $response_header_allow); 206 } 207 146 208 public static function create_failure_response($failure_message) 147 209 { 148 210 return array(array('status' => 'FAILURE', 149 'failure_message' => $failure_message), 150 null, null, null); 211 'failure_message' => $failure_message)); 151 212 } 152 213 … … 187 248 try { 188 249 $url = 'https://' . $ps_domain . '/sitemap.xml'; 189 $curl = curl_init(); 190 $curl_options = array( 191 CURLOPT_URL => $url, 192 CURLOPT_CUSTOMREQUEST => "GET", 193 CURLOPT_HEADER => true, 194 CURLOPT_USERAGENT => UBConfig::UB_USER_AGENT, 195 CURLOPT_HTTPHEADER => UBHTTP::convert_headers_to_curl( 196 array( 197 'x-forwarded-host' => $domain, 198 'if-none-match' => $etag 199 ) 200 ), 201 CURLOPT_RETURNTRANSFER => true, 202 CURLOPT_FOLLOWLOCATION => false, 203 CURLOPT_TIMEOUT => 5 204 ); 205 250 206 251 UBLogger::debug("Retrieving routes from '$url', etag: '$etag', host: '$domain'"); 207 252 208 curl_setopt_array($curl, $curl_options); 209 $data = curl_exec($curl); 210 $http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE); 211 $header_size = strlen($data) - curl_getinfo($curl, CURLINFO_SIZE_DOWNLOAD); 212 $curl_error = null; 213 $etag = null; 214 $max_age = null; 215 216 // when having an CURL error, http_code is 0 217 if ($http_code == 0) { 218 $curl_error = curl_error($curl); 219 } 220 221 curl_close($curl); 222 223 $headers = substr($data, 0, $header_size); 224 225 $matches = array(); 226 $does_match = preg_match('/ETag: (\S+)/is', $headers, $matches); 227 if ($does_match) { 228 $etag = $matches[1]; 229 } 230 231 $matches = array(); 232 $does_match = preg_match('/Cache-Control: max-age=(\S+)/is', $headers, $matches); 233 if ($does_match) { 234 $max_age = $matches[1]; 235 } 253 list($data, $http_code, $header_size, $curl_error) = UBConfig::make_curl_request($url, $domain, $etag); 254 list($etag, $max_age) = UBConfig::process_headers($data, $header_size); 236 255 237 256 if ($http_code == 200) { … … 241 260 if ($success) { 242 261 UBLogger::debug("Retrieved new routes, HTTP code: '$http_code'"); 243 return UBConfig::create_new_response ($etag, $max_age, $result);262 return UBConfig::create_new_response_proxyable_url_set($etag, $max_age, $result); 244 263 } else { 245 264 $errors = join(', ', $result); … … 249 268 } 250 269 } 251 if ($http_code == 304) { 252 UBLogger::debug("Routes have not changed, HTTP code: '$http_code'"); 253 return UBConfig::create_same_response($etag, $max_age); 254 } 255 if ($http_code == 404) { 256 UBLogger::debug("No routes to retrieve, HTTP code: '$http_code'"); 257 return UBConfig::create_none_response(); 258 } else { 259 $failure_message = "An error occurred while retrieving routes; 260 HTTP code: '$http_code'; 261 Error: " . $curl_error; 262 UBLogger::warning($failure_message); 263 return UBConfig::create_failure_response($failure_message); 264 } 270 271 return UBConfig::handle_non_200_http_response($http_code, $etag, $max_age, $curl_error, 'routes'); 265 272 } catch (Exception $e) { 266 273 $failure_message = "An error occurred while retrieving routes; Error: " . $e; … … 323 330 $cache_max_time_default = 10; 324 331 325 $ps_domain = get_option(UBConfig::UB_PAGE_SERVER_DOMAIN_KEY, UBConfig::default_page_server_domain()); 332 $ps_domain = UBConfig::page_server_domain(); 333 326 334 $domains_info = get_option(UBConfig::UB_ROUTES_CACHE_KEY, array()); 327 335 … … 396 404 } 397 405 406 // We are using a fetched dynamic config to retrieve information 407 // such that we decide what request headers to allow and add, 408 // as well as what response headers and request cookies to allow. 409 public static function read_unbounce_dynamic_config($domain) 410 { 411 // Check if curl is installed to prevent fatal error 412 if (!UBDiagnostics::is_curl_installed()) { 413 return array(); 414 } 415 416 $cache_max_time_default = UBConfig::DYNAMIC_CONFIG_DEFAULT_TIMEOUT; 417 $dynamic_config = get_option(UBConfig::UB_DYNAMIC_CONFIG_CACHE_KEY, array()); 418 419 if (!is_array($dynamic_config)) { 420 $dynamic_config = array(); 421 } 422 423 $dynamic_config_fetched_at = UBUtil::array_fetch($dynamic_config, 'fetched_at'); 424 $dynamic_config_cache_timeout = UBUtil::array_fetch($dynamic_config, 'cache_timeout'); 425 $dynamic_config_etag = UBUtil::array_fetch($dynamic_config, 'etag'); 426 427 $cache_max_time = is_null($dynamic_config_cache_timeout) ? $cache_max_time_default : $dynamic_config_cache_timeout; 428 429 // regardless of dynamic_config_cache_timeout being set, if the last fetch failed or returned a 404, we want to try again in 20 minutes 430 if ($dynamic_config['last_status'] === 'FAILURE' || $dynamic_config['last_status'] === 'NONE') { 431 $cache_max_time = UBConfig::DYNAMIC_CONFIG_FAILURE_TIMEOUT; 432 } 433 434 $current_time = time(); 435 436 if (is_null($dynamic_config_fetched_at) || 437 ($current_time - $dynamic_config_fetched_at > $cache_max_time)) { 438 try { 439 $can_fetch = UBUtil::get_lock(); 440 UBLogger::debug('Locking: ' . $can_fetch); 441 442 if ($can_fetch) { 443 $result_array = UBConfig::fetch_dynamic_config($domain, $dynamic_config_etag); 444 list($routes_status, $etag, $max_age, $request_header_allow_new, $request_header_add_new, $request_cookie_allow_new, $response_header_allow_new) = $result_array; 445 446 if ($routes_status['status'] === 'NEW') { 447 $dynamic_config['request_header_allow'] = $request_header_allow_new; 448 $dynamic_config['request_header_add'] = $request_header_add_new; 449 $dynamic_config['request_cookie_allow'] = $request_cookie_allow_new; 450 $dynamic_config['response_header_allow'] = $response_header_allow_new; 451 $dynamic_config['etag'] = $etag; 452 $dynamic_config['cache_timeout'] = $max_age; 453 } elseif ($routes_status['status'] === 'SAME') { 454 // Just extend the cache 455 $dynamic_config['cache_timeout'] = $max_age; 456 } elseif ($routes_status['status'] === 'FAILURE' || $routes_status['status'] === 'NONE') { 457 UBLogger::warning('Not updating the dynamic config: Fetching failed or 404 was returned'); 458 } else { 459 UBLogger::warning("Unknown response from dynamic config fetcher: '$routes_status'"); 460 } 461 462 $dynamic_config['fetched_at'] = $current_time; 463 $dynamic_config['last_status'] = $routes_status['status']; 464 465 if ($routes_status['status'] === 'FAILURE') { 466 $dynamic_config['failure_message'] = $routes_status['failure_message']; 467 } 468 469 update_option(UBConfig::UB_DYNAMIC_CONFIG_CACHE_KEY, $dynamic_config, false); 470 } 471 } catch (Exception $e) { 472 UBLogger::warning('Could not update dynamic config: ' . $e); 473 $dynamic_config['last_status'] = 'FAILURE'; 474 $dynamic_config['failure_message'] = $e->getMessage(); 475 update_option(UBConfig::UB_DYNAMIC_CONFIG_CACHE_KEY, $dynamic_config, false); 476 } 477 478 $release_result = UBUtil::release_lock(); 479 UBLogger::debug('Unlocking: ' . $release_result); 480 } 481 482 return UBUtil::array_select_by_key( 483 $dynamic_config, 484 array('request_header_allow', 'request_header_add', 'request_cookie_allow', 'response_header_allow') 485 ); 486 } 487 488 private static function make_curl_request($url, $domain, $etag) 489 { 490 $curl = curl_init(); 491 $curl_options = array( 492 CURLOPT_URL => $url, 493 CURLOPT_CUSTOMREQUEST => "GET", 494 CURLOPT_HEADER => true, 495 CURLOPT_USERAGENT => UBConfig::UB_USER_AGENT, 496 CURLOPT_HTTPHEADER => UBHTTP::convert_headers_to_curl( 497 array( 498 'x-forwarded-host' => $domain, 499 'if-none-match' => $etag 500 ) 501 ), 502 CURLOPT_RETURNTRANSFER => true, 503 CURLOPT_FOLLOWLOCATION => false, 504 CURLOPT_TIMEOUT => 5 505 ); 506 curl_setopt_array($curl, $curl_options); 507 508 $data = curl_exec($curl); 509 $http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE); 510 $header_size = strlen($data) - curl_getinfo($curl, CURLINFO_SIZE_DOWNLOAD); 511 $curl_error = $http_code == 0 ? curl_error($curl) : null; 512 513 curl_close($curl); 514 515 return array($data, $http_code, $header_size, $curl_error); 516 } 517 518 private static function process_headers($data, $header_size) 519 { 520 $headers = substr($data, 0, $header_size); 521 $etag = null; 522 $max_age = null; 523 524 $matches = array(); 525 $does_match = preg_match('/ETag: (\S+)/is', $headers, $matches); 526 if ($does_match) { 527 $etag = $matches[1]; 528 } 529 530 $matches = array(); 531 $does_match = preg_match('/Cache-Control: max-age=(\S+)/is', $headers, $matches); 532 if ($does_match) { 533 $max_age = $matches[1]; 534 } 535 536 // Make sure Cache-Control header is numeric to avoid errors later on when it is used for comparison 537 if (is_numeric($max_age)) { 538 $max_age = (int) $max_age; 539 } else { 540 $max_age = null; 541 } 542 543 return array($etag, $max_age); 544 } 545 546 547 548 public static function fetch_dynamic_config($domain, $etag) 549 { 550 if (!$domain) { 551 $failure_message = 'Domain not provided, not fetching dynamic config'; 552 UBLogger::warning($failure_message); 553 return UBConfig::create_failure_response($failure_message); 554 } 555 556 try { 557 $url = 'https://' . UBConfig::dynamic_config_retrieval_domain() . '/v' . UBConfig::UB_VERSION; 558 UBLogger::debug("Retrieving dynamic config from '$url', etag: '$etag', host: '$domain'"); 559 560 list($data, $http_code, $header_size, $curl_error) = UBConfig::make_curl_request($url, $domain, $etag); 561 list($etag, $max_age) = UBConfig::process_headers($data, $header_size); 562 563 if ($http_code == 200) { 564 $body = substr($data, $header_size); 565 $decoded_body = json_decode($body, true); 566 567 if (json_last_error() == JSON_ERROR_NONE) { 568 UBLogger::debug("Retrieved new dynamic config, HTTP code: '$http_code'"); 569 return UBConfig::create_new_response_dynamic_config($etag, $max_age, $decoded_body['request_header_allow'], $decoded_body['request_header_add'], $decoded_body['request_cookie_allow'], $decoded_body['response_header_allow']); 570 } else { 571 $failure_message = "An error occurred while processing dynamic config, JSON errors: " . json_last_error_msg(); 572 UBLogger::warning($failure_message); 573 return UBConfig::create_failure_response($failure_message); 574 } 575 } 576 577 return UBConfig::handle_non_200_http_response($http_code, $etag, $max_age, $curl_error, 'dynamic config'); 578 } catch (Exception $e) { 579 $failure_message = "An error occurred while retrieving dynamic config; Error: " . $e->getMessage(); 580 UBLogger::warning($failure_message); 581 return UBConfig::create_failure_response($failure_message); 582 } 583 } 584 585 public static function handle_non_200_http_response($http_code, $etag, $max_age, $curl_error, $context) 586 { 587 if ($http_code == 304) { 588 UBLogger::debug("$context have not changed, HTTP code: '$http_code'"); 589 return UBConfig::create_same_response($etag, $max_age); 590 } 591 592 if ($http_code == 404) { 593 UBLogger::debug("No $context to retrieve, HTTP code: '$http_code'"); 594 return UBConfig::create_none_response(); 595 } 596 597 $failure_message = "An error occurred while retrieving $context;HTTP code: '$http_code'; 598 Error: " . $curl_error; 599 UBLogger::warning($failure_message); 600 return UBConfig::create_failure_response($failure_message); 601 } 602 398 603 public static function is_authorized_domain($domain0) 399 604 { … … 407 612 update_option(UBConfig::UB_USER_ID_KEY, $data['user_id']); 408 613 update_option(UBConfig::UB_DOMAIN_ID_KEY, $data['domain_id']); 614 update_option(UBConfig::UB_DOMAIN_UUID_KEY, $data['domain_uuid']); 409 615 update_option(UBConfig::UB_CLIENT_ID_KEY, $data['client_id']); 410 616 update_option(UBConfig::UB_AUTHORIZED_DOMAINS_KEY, $domains); -
unbounce/trunk/UBDiagnostics.php
r2953445 r3005252 13 13 public static function domain_checks($domain, $domain_info) 14 14 { 15 return array( 16 'Domain is Authorized' => UBConfig::is_authorized_domain($domain), 17 'Can Fetch Page Listing' => UBDiagnostics::last_status_success($domain_info), 18 ); 15 $dynamic_config = get_option(UBConfig::UB_DYNAMIC_CONFIG_CACHE_KEY, array()); 16 $uuid = get_option(UBConfig::UB_DOMAIN_UUID_KEY, ''); 17 18 $result = array( 19 'Domain is Authorized' => UBConfig::is_authorized_domain($domain), 20 'Can Fetch Page Listing' => UBDiagnostics::last_status_success($domain_info) 21 ); 22 23 if (UBConfig::has_authorized()) { 24 $result['Domain UUID'] = $uuid !== ''; 25 } 26 27 if (isset($dynamic_config['last_status'])) { 28 $result['Dynamic Config Retrieval'] = $dynamic_config['last_status'] !== 'FAILURE'; 29 } 30 31 return $result; 19 32 } 20 33 … … 101 114 'PHP Version' => phpversion(), 102 115 'WordPress Version' => UBDiagnostics::wordpress_version(), 103 'Unbounce Plugin Version' => '1.1. 0',116 'Unbounce Plugin Version' => '1.1.1', 104 117 'Checks' => self::pp(UBDiagnostics::checks($domain, $domain_info)), 105 118 'Options' => self::pp(UBDiagnostics::ub_options()), … … 179 192 'php' => phpversion(), 180 193 'wordpress' => UBDiagnostics::wordpress_version(), 181 'plugin_version' => '1.1. 0',194 'plugin_version' => '1.1.1', 182 195 'curl_installed' => self::is_curl_installed(), 183 196 'xml_installed' => self::is_xml_installed(), -
unbounce/trunk/UBHTTP.php
r2953445 r3005252 7 7 public static $variant_url_regex = '/(.+)\/[a-z]+\.html/i'; 8 8 public static $pie_htc_url = '/PIE.htc'; 9 public static $request_header_blocklist = '/^(?:Accept-Encoding|Host|Forwarded)$/i';10 9 public static $location_header_regex = '/^(?:Location):/i'; 11 public static $cookie_allowlist = array('ubvs', 'ubpv', 'ubvt', 'hubspotutk');12 public static $response_headers_always_forwarded = array(13 'content-length',14 'content-location',15 'content-type',16 'location',17 'link',18 'set-cookie',19 'cf-ray',20 'cf-cache-status'21 );22 10 23 11 public static function is_public_ip_address($ip_address) … … 126 114 } 127 115 128 public static function stream_headers_function( )129 { 130 $header_filter = UBHTTP::create_curl_response_header_filter( );116 public static function stream_headers_function($dynamic_config) 117 { 118 $header_filter = UBHTTP::create_curl_response_header_filter($dynamic_config); 131 119 132 120 return function ($curl, $header_line) use ($header_filter) { … … 242 230 // Always add this header to responses to show it comes from our plugin. 243 231 header("X-Unbounce-Plugin: 1", false); 232 $dynamic_config = UBConfig::read_unbounce_dynamic_config($domain); 233 244 234 if (UBConfig::use_curl()) { 245 235 return UBHTTP::stream_request_curl( … … 249 239 $current_headers, 250 240 $current_protocol, 251 $domain 241 $domain, 242 $dynamic_config 252 243 ); 253 244 } else { … … 258 249 $current_headers, 259 250 $current_protocol, 260 $domain 251 $domain, 252 $dynamic_config 261 253 ); 262 254 } … … 269 261 $current_headers, 270 262 $current_protocol, 271 $domain 263 $domain, 264 $dynamic_config 272 265 ) { 273 266 $args = array( … … 277 270 'timeout' => 30, 278 271 'headers' => array_merge( 279 UBHTTP::prepare_request_headers($current_headers, $current_protocol, $domain ),272 UBHTTP::prepare_request_headers($current_headers, $current_protocol, $domain, $dynamic_config), 280 273 array( 281 274 'x-ub-wordpress-remote-request' => '1', … … 297 290 http_response_code($resp['response']['code']); 298 291 $response_headers = $resp['headers']; 299 UBHTTP::set_response_headers($response_headers );292 UBHTTP::set_response_headers($response_headers, $dynamic_config); 300 293 echo $resp['body']; 301 294 return array(true, null); … … 303 296 } 304 297 305 public static function prepare_request_headers($current_headers, $current_protocol, $domain) 306 { 307 $target_headers = array(); 308 array_walk($current_headers, function ($v, $k) use (&$target_headers) { 309 if (!preg_match(UBHTTP::$request_header_blocklist, $k)) { 310 $target_headers[$k] = $v; 311 } 312 }); 298 public static function prepare_request_headers($current_headers, $current_protocol, $domain, $dynamic_config) 299 { 300 301 $request_header_allow = UBUtil::array_fetch($dynamic_config, 'request_header_allow', UBConfig::UB_DEFAULT_REQUEST_HEADER_ALLOW); 302 $request_header_add = UBUtil::array_fetch($dynamic_config, 'request_header_add', UBConfig::UB_DEFAULT_REQUEST_HEADER_ADD); 303 $request_cookie_allow = UBUtil::array_fetch($dynamic_config, 'request_cookie_allow', UBConfig::UB_DEFAULT_REQUEST_COOKIE_ALLOW); 313 304 314 305 $current_forwarded_for = UBUtil::array_fetch($current_headers, 'x-forwarded-for'); … … 316 307 $current_remote_ip = UBUtil::array_fetch($_SERVER, 'REMOTE_ADDR'); 317 308 318 return array_merge( 319 UBHTTP::sanitize_cookies($target_headers), 309 // remove current host header as we will be setting it to the target domain 310 unset($current_headers['host']); 311 312 $merged_headers = array_merge( 313 UBHTTP::sanitize_cookies($current_headers, $request_cookie_allow), 320 314 UBHTTP::get_forwarded_headers( 321 315 $domain, … … 327 321 UBHTTP::get_common_headers() 328 322 ); 323 324 $target_headers = array(); 325 array_walk($merged_headers, function ($v, $k) use (&$target_headers, $request_header_allow) { 326 if (preg_match($request_header_allow, $k)) { 327 $target_headers[$k] = $v; 328 } 329 }); 330 331 foreach ($request_header_add as $key => $value) { 332 $target_headers[$key] = $value; 333 } 334 return $target_headers; 329 335 } 330 336 … … 333 339 $headers = array( 334 340 'host' => UBConfig::page_server_domain(), 335 'x-ub-wordpress-plugin-version' => '1.1. 0'341 'x-ub-wordpress-plugin-version' => '1.1.1' 336 342 ); 337 343 … … 364 370 } 365 371 366 public static function sanitize_cookies($headers )372 public static function sanitize_cookies($headers, $request_cookie_allow) 367 373 { 368 374 $cookie_key = "Cookie"; … … 376 382 $cookies_to_forward = UBUtil::array_select_by_key( 377 383 UBHTTP::cookie_array_from_string($headers[$cookie_key]), 378 UBHTTP::$cookie_allowlist 379 ); 380 if (sizeof($cookies_to_forward) > 0) { 381 $headers[$cookie_key] = UBHTTP::cookie_string_from_array($cookies_to_forward); 382 } 384 $request_cookie_allow 385 ); 386 387 $headers[$cookie_key] = UBHTTP::cookie_string_from_array($cookies_to_forward); 383 388 return $headers; 384 389 } … … 395 400 } 396 401 397 public static function set_response_headers($headers )398 { 399 $header_filter = UBHTTP::create_response_header_filter( );402 public static function set_response_headers($headers, $dynamic_config) 403 { 404 $header_filter = UBHTTP::create_response_header_filter($dynamic_config); 400 405 401 406 foreach ($headers as $h_key => $h_value) { … … 418 423 $current_headers, 419 424 $current_protocol, 420 $domain 425 $domain, 426 $dynamic_config 421 427 ) { 422 428 $base_response_headers = headers_list(); 423 429 424 $target_headers = UBHTTP::prepare_request_headers($current_headers, $current_protocol, $domain );430 $target_headers = UBHTTP::prepare_request_headers($current_headers, $current_protocol, $domain, $dynamic_config); 425 431 $target_headers = UBHTTP::convert_headers_to_curl($target_headers); 426 432 … … 429 435 UBLogger::debug_var('target_headers', print_r($target_headers, true)); 430 436 431 $stream_headers = UBHTTP::stream_headers_function( );437 $stream_headers = UBHTTP::stream_headers_function($dynamic_config); 432 438 $stream_body = UBHTTP::stream_response_function(); 433 439 $curl = curl_init(); … … 574 580 } 575 581 576 private static function create_curl_response_header_filter( )582 private static function create_curl_response_header_filter($dynamic_config) 577 583 { 578 584 $blocklist_regex = '/^connection:/i'; … … 585 591 } 586 592 587 $allowlist = array_merge($config_headers_forwarded, UB HTTP::$response_headers_always_forwarded);593 $allowlist = array_merge($config_headers_forwarded, UBUtil::array_fetch($dynamic_config, 'response_header_allow', array())); 588 594 $allowlist_regex = '/^('.implode('|', $allowlist).'):/i'; 589 595 return function ($header) use ($blocklist_regex, $allowlist_regex) { … … 592 598 } 593 599 594 private static function create_response_header_filter( )600 private static function create_response_header_filter($dynamic_config) 595 601 { 596 602 $config_headers_forwarded = UBConfig::response_headers_forwarded(); … … 602 608 } 603 609 604 $allowlist = array_merge($config_headers_forwarded, UB HTTP::$response_headers_always_forwarded);610 $allowlist = array_merge($config_headers_forwarded, UBUtil::array_fetch($dynamic_config, 'response_header_allow', array())); 605 611 606 612 return function ($header) use ($allowlist) { -
unbounce/trunk/Unbounce-Page.php
r2953445 r3005252 4 4 Plugin URI: http://unbounce.com 5 5 Description: Unbounce is the most powerful standalone landing page builder available. 6 Version: 1.1. 06 Version: 1.1.1 7 7 Author: Unbounce 8 8 Author URI: http://unbounce.com … … 148 148 add_action('admin_init', function () { 149 149 $current_version = UBConfig::UB_VERSION; 150 151 if (get_option(UBConfig::UB_PLUGIN_VERSION_KEY) != $current_version) { 150 $saved_version = get_option(UBConfig::UB_PLUGIN_VERSION_KEY); 151 152 if ($saved_version != $current_version) { 152 153 UBConfig::set_options_if_not_exist(); 153 154 update_option(UBConfig::UB_PLUGIN_VERSION_KEY, $current_version); 154 155 155 // When upgrading to 1.1.0, override all previous ub-page-server-domain values to new default 156 // TODO: Remove this in subsequent plugin versions 157 update_option(UBConfig::UB_PAGE_SERVER_DOMAIN_KEY, UBConfig::default_page_server_domain()); 156 // When upgrading to 1.1.x from a 1.0.x version, override all previous ub-page-server-domain values to new default 157 if (version_compare($saved_version, '1.1.0', '<')) { 158 update_option(UBConfig::UB_PAGE_SERVER_DOMAIN_KEY, UBConfig::default_page_server_domain()); 159 } 158 160 } 159 161 … … 175 177 'set-unbounce-domains-js', 176 178 plugins_url('js/set-unbounce-domains.js', __FILE__), 177 array('jquery', 'ub-rx') 179 array('jquery', 'ub-rx'), 180 "1.1.1" 178 181 ); 179 182 wp_enqueue_script( … … 319 322 'client_id' => UBUtil::array_fetch($_POST, 'client_id', ''), 320 323 'domain_id' => UBUtil::array_fetch($_POST, 'domain_id', ''), 324 'domain_uuid' => UBUtil::array_fetch($_POST, 'domain_uuid', ''), 321 325 ); 322 326 -
unbounce/trunk/js/set-unbounce-domains.js
r1266757 r3005252 23 23 clientId: subAccount.id, 24 24 domainId: domain.id, 25 name: domain.name 25 name: domain.name, 26 domainUUID: domain.uuid 26 27 }; 27 28 } else { … … 55 56 $form.find('[name="domain_id"]').val(wordpressDomain.domainId); 56 57 $form.find('[name="client_id"]').val(wordpressDomain.clientId); 58 $form.find('[name="domain_uuid"]').val(wordpressDomain.domainUUID); 57 59 } 58 60 -
unbounce/trunk/readme.txt
r2953445 r3005252 3 3 Tags: Unbounce, AB testing, A/B testing, split testing, CRO, conversion optimization, wordpress landing page, wp landing pages, splash pages, landing pages, squeeze pages, lead gen, lead generation, email list, responsive landing pages, templates, inbound marketing, ppc, analytics 4 4 Requires at least: 4.1.5 5 Tested up to: 6. 36 Stable tag: 1.1. 05 Tested up to: 6.4 6 Stable tag: 1.1.1 7 7 Requires PHP: 7.2 8 8 License: GPLv2 or later … … 104 104 == Changelog == 105 105 106 = 1.1.1 = 107 * Changes to the way the plugin filters headers and cookies using a dynamic configuration. 108 * Tested with WP 6.4 109 106 110 = 1.1.0 = 107 111 * Changes the method used to communicate with Unbounce servers, which will improve the resilience of -
unbounce/trunk/templates/authorize_button.php
r2823212 r3005252 3 3 <input type="hidden" name="user_id" /> 4 4 <input type="hidden" name="domain_id" /> 5 <input type="hidden" name="domain_uuid" /> 5 6 <input type="hidden" name="client_id" /> 6 7 <?php if (isset($outer_text)) { ?> -
unbounce/trunk/templates/diagnostics.php
r2953445 r3005252 37 37 $sni_support = 'The Unbounce Plugin communicates with the Unbounce servers using a TLS 1.2 connection, this requires SNI support in order to function. Our diagnostics indicate that your server does not currently have SNI support.'; 38 38 39 $dynamic_config_retrieval = 'The Unbounce Plugin is unable to retrieve the dynamic configuration from Unbounce. This is required in order to make sure we are able to serve your Unbounce pages the correct way and prevent any errors. Please contact support if you continue to see this error for more than a few days.'; 40 41 $domain_uuid = 'Plugin requests are not sent to Unbounce servers with the uuid added as a subdomain, which compromises security. Please update wordpress enabled domains on the pages section.'; 42 39 43 $diagnostic_descriptions = array( 40 44 'Curl Support' => $curl_support, … … 45 49 'Supported PHP Version' => $supported_php_version, 46 50 'Supported Wordpress Version' => $supported_wordpress_version, 47 'SNI Support' => $sni_support 51 'SNI Support' => $sni_support, 52 'Dynamic Config Retrieval' => $dynamic_config_retrieval, 53 "Domain UUID" => $domain_uuid, 48 54 ); 49 55 -
unbounce/trunk/templates/main_authorized_footer.php
r2953445 r3005252 22 22 Click here for troubleshooting and plugin diagnostics 23 23 </a> 24 <p class="ub-version">Unbounce Version 1.1. 0</p>24 <p class="ub-version">Unbounce Version 1.1.1</p> -
unbounce/trunk/templates/main_unauthorized_footer.php
r2953445 r3005252 5 5 Click here for troubleshooting and plugin diagnostics 6 6 </a> 7 <p class="ub-version">Unbounce Version 1.1. 0</p>7 <p class="ub-version">Unbounce Version 1.1.1</p> -
unbounce/trunk/templates/settings_response_headers_forwarded.php
r2823212 r3005252 11 11 $headers = array_map(function ($header) { 12 12 return '<code>'.$header.'</code>'; 13 }, UBHTTP::$response_headers_always_forwarded);13 }, get_option(UBConfig::UB_DYNAMIC_CONFIG_CACHE_KEY, array())['response_header_allow']); 14 14 echo implode(',', array_slice($headers, 0, -1)).' and '.end($headers); 15 15 ?>
Note: See TracChangeset
for help on using the changeset viewer.