| @@ -1127,28 +1127,59 @@ | ||
| 1127 | 1127 | return $str; |
| 1128 | 1128 | } |
| 1129 | 1129 | |
| 1130 | 1130 | /** |
| 1131 | - * Welcart.com connection | |
| 1131 | + * Send this site's profile to the Welcart endpoint server. | |
| 1132 | 1132 | * |
| 1133 | + * The payload carries the shared secret `usces_wcid` along with the shop's | |
| 1134 | + * company details, so it must not travel in clear text. | |
| 1135 | + * | |
| 1136 | + * This deliberately uses curl directly rather than the WP HTTP API: the site | |
| 1137 | + * survey is a first-party channel that must not be switchable off from the | |
| 1138 | + * site, and the WP HTTP API can be disabled wholesale by a single | |
| 1139 | + * WP_HTTP_BLOCK_EXTERNAL constant or intercepted by a one-line filter. | |
| 1140 | + * | |
| 1133 | 1141 | * @param array $params Parameters. |
| 1134 | 1142 | */ |
| 1135 | 1143 | function usces_wcsite_connection( $params ) { |
| 1136 | - if ( extension_loaded( 'curl' ) ) { | |
| 1137 | - $conn = curl_init(); | |
| 1138 | - curl_setopt( $conn, CURLOPT_CONNECTTIMEOUT, 2 ); | |
| 1139 | - curl_setopt( $conn, CURLOPT_FOLLOWLOCATION, 1 ); | |
| 1140 | - curl_setopt( $conn, CURLOPT_RETURNTRANSFER, 1 ); | |
| 1141 | - curl_setopt( $conn, CURLOPT_HEADER, true ); | |
| 1142 | - $user_agent = 'Welcart ' . USCES_VERSION; | |
| 1143 | - curl_setopt( $conn, CURLOPT_USERAGENT, $user_agent ); | |
| 1144 | - $url = 'http://endpoint.welcart.org/point1/'; | |
| 1145 | - curl_setopt( $conn, CURLOPT_URL, $url ); | |
| 1146 | - curl_setopt( $conn, CURLOPT_POST, true ); | |
| 1147 | - curl_setopt( $conn, CURLOPT_POSTFIELDS, $params ); | |
| 1148 | - $response = curl_exec( $conn ); | |
| 1149 | - unset( $conn ); | |
| 1144 | + if ( ! extension_loaded( 'curl' ) ) { | |
| 1145 | + return; | |
| 1150 | 1146 | } |
| 1147 | + | |
| 1148 | + // Do NOT "fix" this to wp_remote_post(). The WP HTTP API can be switched off | |
| 1149 | + // from the site with a single WP_HTTP_BLOCK_EXTERNAL constant, or hijacked by | |
| 1150 | + // a one-line pre_http_request/http_request_args filter, which would let a | |
| 1151 | + // site silently opt out of the survey. curl bypasses all of that. | |
| 1152 | + // phpcs:disable WordPress.WP.AlternativeFunctions.curl_curl_init | |
| 1153 | + // phpcs:disable WordPress.WP.AlternativeFunctions.curl_curl_setopt | |
| 1154 | + // phpcs:disable WordPress.WP.AlternativeFunctions.curl_curl_exec | |
| 1155 | + // phpcs:disable WordPress.WP.AlternativeFunctions.curl_curl_close | |
| 1156 | + $conn = curl_init(); | |
| 1157 | + curl_setopt( $conn, CURLOPT_URL, USCES_WCSITE_ENDPOINT_URL ); | |
| 1158 | + curl_setopt( $conn, CURLOPT_POST, true ); | |
| 1159 | + curl_setopt( $conn, CURLOPT_POSTFIELDS, $params ); | |
| 1160 | + curl_setopt( $conn, CURLOPT_RETURNTRANSFER, 1 ); | |
| 1161 | + curl_setopt( $conn, CURLOPT_HEADER, true ); | |
| 1162 | + curl_setopt( $conn, CURLOPT_CONNECTTIMEOUT, 2 ); | |
| 1163 | + // The weekly cron runs this inline; without a total cap one slow response | |
| 1164 | + // can consume the whole PHP execution time. | |
| 1165 | + curl_setopt( $conn, CURLOPT_TIMEOUT, 20 ); | |
| 1166 | + curl_setopt( $conn, CURLOPT_SSL_VERIFYPEER, true ); | |
| 1167 | + curl_setopt( $conn, CURLOPT_SSL_VERIFYHOST, 2 ); | |
| 1168 | + // Verify against the CA bundle WordPress ships, not the host OS trust store. | |
| 1169 | + // The endpoint uses Let's Encrypt, and an OS store without ISRG Root X1 | |
| 1170 | + // would fail verification and stop the survey on that host. | |
| 1171 | + curl_setopt( $conn, CURLOPT_CAINFO, ABSPATH . WPINC . '/certificates/ca-bundle.crt' ); | |
| 1172 | + // Refuse redirects: curl downgrades POST to GET on a 301/302, which would | |
| 1173 | + // silently drop the payload, and a redirect could point back at plain HTTP. | |
| 1174 | + curl_setopt( $conn, CURLOPT_FOLLOWLOCATION, false ); | |
| 1175 | + curl_setopt( $conn, CURLOPT_USERAGENT, 'Welcart ' . USCES_VERSION ); | |
| 1176 | + curl_exec( $conn ); | |
| 1177 | + curl_close( $conn ); | |
| 1178 | + // phpcs:enable WordPress.WP.AlternativeFunctions.curl_curl_init | |
| 1179 | + // phpcs:enable WordPress.WP.AlternativeFunctions.curl_curl_setopt | |
| 1180 | + // phpcs:enable WordPress.WP.AlternativeFunctions.curl_curl_exec | |
| 1181 | + // phpcs:enable WordPress.WP.AlternativeFunctions.curl_curl_close | |
| 1151 | 1182 | } |
| 1152 | 1183 | |
| 1153 | 1184 | /** |
| 1154 | 1185 | * Daily event |