_username = $username; $this->_password = $password; $this->_certificate = $certificate; $this->_subject = $subject; } /** * {@inheritdoc} */ public function get_endpoint_subdomain() { return 'api'; } /** * Get certificate. * * @return string */ public function get_certificate() { return $this->_certificate; } /** * Allow certificate-based credential to configure cURL, especially * to set CURLOPT_SSLCERT and CURLOPT_SSLCERTPASSWD. * * @throws Exception * * @param resource &$handle The cURL handle returned by curl_init(). * @param array $r The HTTP request arguments. * @param string $url The request URL. * * @return void */ public function configure_curl( $handle, $r, $url ) { parent::configure_curl( $handle, $r, $url ); $password = uniqid(); $certificate_file = $this->_maybe_create_certificate_file( $password ); if ( false === curl_setopt( $handle, CURLOPT_SSLCERT, $certificate_file ) ) { // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_setopt throw new Exception( __( 'Unable to accept certificate during cURL configuration', 'woocommerce-gateway-paypal-express-checkout' ), WC_Gateway_PPEC_Client::INVALID_ENVIRONMENT_ERROR ); } if ( $this->_use_secure_transport() && false === curl_setopt( $handle, CURLOPT_SSLCERTPASSWD, $password ) ) { // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_setopt throw new Exception( __( 'Unable to accept certificate password during cURL configuration', 'woocommerce-gateway-paypal-express-checkout' ), WC_Gateway_PPEC_Client::INVALID_ENVIRONMENT_ERROR ); } } /** * Dump the certificate out to a temporary file, because cURL can't accept * it any other way. * * @throws Exception * * @param string $password Password for certificate when using secure transport * * @return string Filepath of certificate file */ protected function _maybe_create_certificate_file( $password ) { $temp_file = tempnam( sys_get_temp_dir(), 'pptmp_' ); if ( ! $temp_file ) { // Translators: %s is a filepath. throw new Exception( sprintf( __( 'Unable to write certificate file %s during cURL configuration', 'woocommerce-gateway-paypal-express-checkout' ), $temp_file ), WC_Gateway_PPEC_Client::INVALID_ENVIRONMENT_ERROR ); } if ( $this->_use_secure_transport() ) { $this->_maybe_create_secure_certificate_file( $temp_file, $password ); } else { $this->_maybe_create_non_secure_certificate_file( $temp_file ); } return $temp_file; } /** * If we're using SecureTransport, we have to translate the certificate to * PKCS12 before passing it to cURL. * * @throws Exception * * @param string $temp_file Filepath to temporary certificate file * * @return void */ protected function _maybe_create_secure_certificate_file( $temp_file, $password ) { $private_key = openssl_pkey_get_private( $this->_certificate ); if ( false === $private_key ) { throw new Exception( __( 'Failed to retrieve private key during cURL configuration', 'woocommerce-gateway-paypal-express-checkout' ), WC_Gateway_PPEC_Client::INVALID_ENVIRONMENT_ERROR ); } if ( ! openssl_pkcs12_export_to_file( $this->_certificate, $temp_file, $private_key, $password ) ) { throw new Exception( __( 'Failed to export PKCS12 file during cURL configuration', 'woocommerce-gateway-paypal-express-checkout' ), WC_Gateway_PPEC_Client::INVALID_ENVIRONMENT_ERROR ); } } /** * Create non-password certificate file. Basically just dump the certificate * string to temporary file. * * @throws Exception * * @param string $temp_file Filepath to temporary certificate file * * @return void */ protected function _maybe_create_non_secure_certificate_file( $temp_file ) { if ( false === file_put_contents( $temp_file, $this->_certificate ) ) { // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_file_put_contents // Translators: %s is a filepath. throw new Exception( sprintf( __( 'Unable to write certificate file %s during cURL configuration', 'woocommerce-gateway-paypal-express-checkout' ), $temp_file ), WC_Gateway_PPEC_Client::INVALID_ENVIRONMENT_ERROR ); } } /** * Returns true if secure transport is available in current cURL. * * @return bool */ protected function _use_secure_transport() { $curl_version = curl_version(); return false !== strpos( $curl_version['ssl_version'], 'SecureTransport' ); } }