This repository has been archived on 2022-06-23. You can view files and clone it, but cannot push or open issues or pull requests.
divi/core/components/api/OAuthHelper.php

296 lines
8.6 KiB
PHP

<?php
/**
* Wrapper for the ET_Core_OAuth library.
*
* @since 1.1.0
* @package ET\Core\API
*
* @property string consumer_key
* @property string consumer_secret
* @property string access_token
* @property string access_token_secret
*/
class ET_Core_API_OAuthHelper {
/**
* URL for access token requests.
*
* @since 1.1.0
* @var string
*/
public $ACCESS_TOKEN_URL;
/**
* URL for authorizing applications.
*
* @since 1.1.0
* @var string
*/
public $AUTHORIZATION_URL;
/**
* URL for request token requests.
*
* @since 1.1.0
* @var string
*/
public $REQUEST_TOKEN_URL;
/**
* Instance URL, used by Salesforce.
*
* @since 4.9.0
* @var string
*/
public $INSTANCE_URL; // @phpcs:ignore ET.Sniffs.ValidVariableName.PropertyNotSnakeCase -- Use uppercase to be consistent with existing code.
/**
* The OAuth2 bearer for this instance. This is used as the value of the HTTP
* `Authorization` header. The format is: `Bearer {$access_token}`.
*
* @since 1.1.0
* @var string
*/
private $bearer = null;
/**
* The OAuth Consumer object for this instance.
*
* @since 1.1.0
* @var ET_Core_LIB_OAuthConsumer
*/
public $consumer = null;
/**
* The OAuth Token object for this instance.
*
* @since 1.1.0
* @var ET_Core_LIB_OAuthToken
*/
public $token = null;
/**
* ET_Core_API_OAuth_Helper constructor.
*
* @since 1.1.0
*
* @param array $data {
* The consumer key/secret and access token/secret.
*
* @type string $consumer_key Consumer key. Required.
* @type string $consumer_secret Consumer secret. Required.
* @type string $access_token Previously obtained access token. Optional.
* @type string $access_secret Previously obtained access secret. Optional.
* }
* @param array $urls {
* The service's OAuth endpoints.
*
* @type string $request_token_url URL for request tokens. Required.
* @type string $authorization_url URL for authorizations. Optional.
* @type string $access_token_url URL for access tokens. Required.
* }
*/
public function __construct( array $data, array $urls, $owner ) {
$this->_initialize( $data, $urls );
$this->sha1_method = new ET_Core_LIB_OAuthHMACSHA1();
$this->consumer = new ET_Core_LIB_OAuthConsumer( $this->consumer_key, $this->consumer_secret );
if ( '' !== $this->access_token && '' !== $this->access_token_secret ) {
$this->token = new ET_Core_LIB_OAuthToken( $this->access_token, $this->access_token_secret );
} else if ( empty( $this->access_token ) && ! empty( $this->access_token_secret ) ) {
$this->bearer = "Bearer {$this->access_token_secret}";
}
}
/**
* @internal
*
* @param array $data {@see self::__construct()}
* @param array $urls {@see self::__construct()}
*/
private function _initialize( $data, $urls ) {
$this->consumer_key = isset( $data['consumer_key'] ) ? $data['consumer_key'] : '';
$this->consumer_secret = isset( $data['consumer_secret'] ) ? $data['consumer_secret'] : '';
$this->access_token = isset( $data['access_key'] ) ? $data['access_key'] : '';
$this->access_token_secret = isset( $data['access_secret'] ) ? $data['access_secret'] : '';
$this->REQUEST_TOKEN_URL = $urls['request_token_url'];
$this->AUTHORIZATION_URL = $urls['authorization_url'];
$this->ACCESS_TOKEN_URL = $urls['access_token_url'];
$this->REDIRECT_URL = isset( $urls['redirect_url'] ) ? $urls['redirect_url'] : '';
}
protected function _get_oauth2_parameters( $args ) {
et_core_nonce_verified_previously();
return wp_parse_args( $args, array(
'grant_type' => 'authorization_code',
'code' => sanitize_text_field( $_GET['code'] ),
'client_id' => $this->consumer_key,
'client_secret' => $this->consumer_secret,
'redirect_uri' => $this->REDIRECT_URL,
) );
}
/**
* @param \ET_Core_HTTPRequest $request
*
* @return \ET_Core_HTTPRequest
*/
protected function _prepare_oauth_request( $request ) {
$parameters = array();
if ( is_array( $request->BODY ) && $request->BODY && ! $request->JSON_BODY ) {
$parameters = $request->BODY;
}
$oauth_request = ET_Core_LIB_OAuthRequest::from_consumer_and_token(
$this->consumer,
$this->token,
$request->METHOD,
$request->URL,
$parameters
);
$oauth_request->sign_request( $this->sha1_method, $this->consumer, $this->token );
if ( 'GET' === $request->METHOD ) {
$request->URL = $oauth_request->to_url();
} else if ( 'POST' === $request->METHOD ) {
$request->URL = $request->JSON_BODY ? $oauth_request->to_url() : $oauth_request->get_normalized_http_url();
$request->BODY = $request->JSON_BODY ? json_encode( $request->BODY ) : $oauth_request->to_post_data();
}
return $request;
}
/**
* @param \ET_Core_HTTPRequest $request
*
* @return \ET_Core_HTTPRequest
*/
protected function _prepare_oauth2_request( $request ) {
if ( null !== $this->bearer ) {
$request->HEADERS['Authorization'] = $this->bearer;
}
if ( $request->JSON_BODY ) {
return $request;
}
if ( is_array( $request->BODY ) && ! array_key_exists( 'code', $request->BODY ) ) {
$request->URL = add_query_arg( $request->BODY, $request->URL );
$request->BODY = null;
}
return $request;
}
/**
* Finish the OAuth2 authorization process if needed.
*/
public static function finish_oauth2_authorization() {
et_core_nonce_verified_previously();
if ( ! isset( $_GET['state'] ) || 0 !== strpos( $_GET['state'], 'ET_Core' ) ) {
return;
}
list( $_, $name, $account, $nonce ) = explode( '|', sanitize_text_field( rawurldecode( $_GET['state'] ) ) );
if ( ! $name || ! $account || ! $nonce ) {
return;
}
$_GET['nonce'] = $nonce;
et_core_security_check( 'manage_options', 'et_core_api_service_oauth2', 'nonce', '_GET' );
$providers = et_core_api_email_providers();
if ( ! $providers->account_exists( $name, $account ) ) {
et_core_die();
}
if ( ! $provider = $providers->get( $name, $account, 'ET_Core' ) ) {
et_core_die();
}
$result = $provider->fetch_subscriber_lists();
// Display the authorization results
echo et_core_esc_previously( ET_Bloom::generate_modal_warning( $result ) );
}
/**
* Prepare a request for an access token.
*
* @param array $args {
* For OAuth 1.0 & 1.0a:
*
* @type string $verifier OAuth verifier token. Optional.
*
* For OAuth 2.0:
*
* @type string $code The code returned when the user was redirected back to their dashboard.
* @type string $grant_type The desired grant type, as per the OAuth 2.0 spec.
* @type string $redirect_uri The redirect URL from the original authorization request.
* }
*
* @return ET_Core_HTTPRequest
*/
public function prepare_access_token_request( $args = array() ) {
et_core_nonce_verified_previously();
$oauth2 = ! empty( $_GET['code'] );
$request = new ET_Core_HTTPRequest( $this->ACCESS_TOKEN_URL, 'POST', '', true );
$request->BODY = $oauth2 ? $this->_get_oauth2_parameters( $args ) : $args;
return $this->prepare_oauth_request( $request, $oauth2 );
}
/**
* Prepare an OAuth 1.0a or 2.0 request.
*
* @param ET_Core_HTTPRequest $request
* @param bool $oauth2
*
* @return \ET_Core_HTTPRequest
*/
function prepare_oauth_request( $request, $oauth2 = false ) {
return $oauth2 ? $this->_prepare_oauth2_request( $request ) : $this->_prepare_oauth_request( $request );
}
/**
* Process a response to an OAuth access token request and retrieve the access token if auth was successful.
*
* @param \ET_Core_HTTPResponse $response
*/
public function process_authentication_response( $response, $json = true ) {
if ( $response->ERROR ) {
return;
}
$response = $json ? $response->DATA : wp_parse_args( $response->DATA );
// Salesforce returns an `instance_url` data in the auth response.
if ( isset( $response['instance_url'] ) ) {
$this->INSTANCE_URL = esc_url( $response['instance_url'] ); // @phpcs:ignore ET.Sniffs.ValidVariableName.UsedPropertyNotSnakeCase -- Use uppercase to be consistent with existing code.
}
if ( isset( $response['oauth_token'], $response['oauth_token_secret'] ) ) {
// OAuth 1.0a
$token = sanitize_text_field( $response['oauth_token'] );
$secret = sanitize_text_field( $response['oauth_token_secret'] );
$this->token = new ET_Core_LIB_OAuthToken( $token, $secret );
} elseif ( isset( $response['access_token'] ) ) {
// OAuth 2.0
$this->token = new ET_Core_LIB_OAuthToken( '', sanitize_text_field( $response['access_token'] ) );
if ( isset( $response['refresh_token'] ) ) {
$this->token->refresh_token = sanitize_text_field( $response['refresh_token'] );
}
}
}
}