initial
This commit is contained in:
@@ -0,0 +1,414 @@
|
||||
<?php
|
||||
/**
|
||||
* API wrapper for the Recaptcha service.
|
||||
*
|
||||
* @since 1.0
|
||||
* @package Gravity_Forms\Gravity_Forms_RECAPTCHA
|
||||
*/
|
||||
|
||||
namespace Gravity_Forms\Gravity_Forms_RECAPTCHA;
|
||||
|
||||
use WP_Error;
|
||||
|
||||
/**
|
||||
* Class RECAPTCHA_API
|
||||
*
|
||||
* @package Gravity_Forms\Gravity_Forms_RECAPTCHA
|
||||
*/
|
||||
class RECAPTCHA_API {
|
||||
/**
|
||||
* Google Recaptcha token verification URL.
|
||||
*
|
||||
* @since 1.0
|
||||
* @var string
|
||||
*/
|
||||
private $verification_url = 'https://www.google.com/recaptcha/api/siteverify';
|
||||
|
||||
/**
|
||||
* OAuth Access Token.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $access_token;
|
||||
|
||||
/**
|
||||
* OAuth Refresh Token.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $refresh_token;
|
||||
|
||||
/**
|
||||
* The GF_RECAPTCHA instance.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*
|
||||
* @var GF_RECAPTCHA|null The GF_RECAPTCHA instance.
|
||||
*/
|
||||
protected $addon;
|
||||
|
||||
/**
|
||||
* The Google Cloud Project ID.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $project_id;
|
||||
|
||||
/**
|
||||
* Constructor for RECAPTCHA_API
|
||||
*
|
||||
* @param string $auth_data The array of auth data.
|
||||
* @param GF_RECAPTCHA $addon The GF_RECAPTCHA instance.
|
||||
*/
|
||||
public function __construct( $auth_data = null, $addon = null ) {
|
||||
$this->addon = $addon;
|
||||
$this->refresh_token = rgar( $auth_data, 'refresh_token' );
|
||||
$this->access_token = rgar( $auth_data, 'access_token' );
|
||||
$this->project_id = rgar( $auth_data, 'project_id' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Gravity API URL for path.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*
|
||||
* @param string $path Endpoint path.
|
||||
*
|
||||
* @return string URL for Gravity API endpoint.
|
||||
*/
|
||||
public static function get_gravity_api_url( $path = '' ) {
|
||||
|
||||
if ( '/' !== substr( $path, 0, 1 ) ) {
|
||||
$path = '/' . $path;
|
||||
}
|
||||
|
||||
return defined( 'GRAVITY_API_URL' ) ? GRAVITY_API_URL . '/auth/googlerecaptcha' . $path : self::$gravity_api_url . '/auth/googlerecaptcha' . $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base URL for the Recaptcha API.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*
|
||||
* @param string $base_path The base path.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_base_url( $base_path = null ) {
|
||||
if ( $base_path ) {
|
||||
return $base_path;
|
||||
}
|
||||
|
||||
return 'https://recaptchaenterprise.googleapis.com/v1/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a request to the reCAPTCHA API.
|
||||
*
|
||||
* @param string $path The relative request path.
|
||||
* @param array $body The request body.
|
||||
* @param array $headers The request headers.
|
||||
* @param string $method The request method.
|
||||
* @param string $base_path The base API path.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*
|
||||
* @return array|string|WP_Error
|
||||
*/
|
||||
private function make_request( $path = '', $body = array(), $headers = array(), $method = 'GET', $base_path = null ) {
|
||||
|
||||
gf_recaptcha()->log_debug( __METHOD__ . '(): Making request to: ' . $path );
|
||||
|
||||
// Build request URL.
|
||||
$request_url = $this->get_base_url( $base_path ) . $path;
|
||||
|
||||
$args = array(
|
||||
'method' => $method,
|
||||
/**
|
||||
* Filters if SSL verification should occur.
|
||||
*
|
||||
* @param bool $ssl_verify If the SSL certificate should be verified. Defaults to false.
|
||||
* @param string $request_url The request URL.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
'sslverify' => apply_filters( 'https_local_ssl_verify', false, $request_url ),
|
||||
/**
|
||||
* Sets the HTTP timeout, in seconds, for the request.
|
||||
*
|
||||
* @param int $timeout_value The timeout limit, in seconds. Defaults to 30.
|
||||
* @param string $request_url The request URL.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
'timeout' => apply_filters( 'http_request_timeout', 30, $request_url ),
|
||||
);
|
||||
|
||||
$args['headers'] = $headers;
|
||||
|
||||
if ( 'GET' === $method || 'POST' === $method ) {
|
||||
$args['body'] = empty( $body ) ? '' : $body;
|
||||
}
|
||||
|
||||
if ( 'POST' === $method ) {
|
||||
$args['body'] = wp_json_encode( $body );
|
||||
}
|
||||
|
||||
// Execute request.
|
||||
$response = wp_remote_request(
|
||||
$request_url,
|
||||
$args
|
||||
);
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$response_body = wp_remote_retrieve_body( $response );
|
||||
$retrieved_response_code = wp_remote_retrieve_response_code( $response );
|
||||
|
||||
if ( 200 !== $retrieved_response_code ) {
|
||||
$error_message = rgars( $response_body, 'error/message', "Expected response code: 200. Returned response code: {$retrieved_response_code}." );
|
||||
$error_code = rgars( $response_body, 'error/errors/reason', 'google_recaptcha_api_error' );
|
||||
|
||||
gf_recaptcha()->log_error( __METHOD__ . '(): Unable to validate with the Google Cloud API: ' . $error_message );
|
||||
|
||||
return new WP_Error( $error_code, $error_message, $retrieved_response_code );
|
||||
}
|
||||
|
||||
return $response_body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the result of token verification from the Recaptcha API.
|
||||
*
|
||||
* @param string $token The token to verify.
|
||||
* @param string $secret The site's secret key.
|
||||
*
|
||||
* @return array|\WP_Error
|
||||
*/
|
||||
public function verify_token( $token, $secret ) {
|
||||
return wp_remote_post(
|
||||
$this->verification_url,
|
||||
array(
|
||||
'body' => array(
|
||||
'secret' => $secret,
|
||||
'response' => $token,
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the reCAPTCHA enterprise assessment.
|
||||
*
|
||||
* @param string $access_token The OAuth access token.
|
||||
* @param string $project_id The Google Cloud Project ID.
|
||||
* @param string $token The reCAPTCHA token from the submission.
|
||||
* @param string $site_key The reCAPTCHA site key.
|
||||
* @param string $action Teh reCATPCHA action.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*
|
||||
* @return array|mixed|WP_Error
|
||||
*/
|
||||
public function create_recaptcha_assessment( $access_token, $project_id, $token, $site_key, $action ) {
|
||||
|
||||
$url = 'https://recaptchaenterprise.googleapis.com/v1/projects/' . $project_id . '/assessments';
|
||||
|
||||
$payload = wp_json_encode(
|
||||
array(
|
||||
'event' => array(
|
||||
'token' => $token,
|
||||
'siteKey' => $site_key,
|
||||
'expectedAction' => $action,
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
$response = wp_remote_post(
|
||||
$url,
|
||||
array(
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $access_token,
|
||||
'Content-Type' => 'application/json',
|
||||
),
|
||||
'body' => $payload,
|
||||
)
|
||||
);
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$body = json_decode( wp_remote_retrieve_body( $response ), true );
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Annotates the assessment; informing Google that the submission was spam or ham.
|
||||
*
|
||||
* @since 2.0
|
||||
*
|
||||
* @param string $assessment_id The assessment ID
|
||||
* @param string $annotation The annotation to added to the assessment. Possible values: LEGITIMATE or FRAUDULENT.
|
||||
*
|
||||
* @return array|mixed|WP_Error
|
||||
*/
|
||||
public function annotate_assessment( $assessment_id, $annotation ) {
|
||||
$body = array(
|
||||
'annotation' => $annotation,
|
||||
);
|
||||
|
||||
$response = wp_remote_post(
|
||||
sprintf( 'https://recaptchaenterprise.googleapis.com/v1/%s:annotate', $assessment_id ),
|
||||
array(
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $this->access_token,
|
||||
'Content-Type' => 'application/json',
|
||||
),
|
||||
'body' => wp_json_encode( $body ),
|
||||
)
|
||||
);
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body( $response );
|
||||
|
||||
return $body ? json_decode( $body, true ) : $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the reCAPTCHA access token.
|
||||
*
|
||||
* @param string $refresh_token The refresh token.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*
|
||||
* @return array|WP_Error
|
||||
*/
|
||||
public function refresh_token( $refresh_token ) {
|
||||
// Connect to Gravity Form's API.
|
||||
$response = wp_remote_post(
|
||||
$this->get_gravity_api_url( 'refresh' ),
|
||||
array(
|
||||
'body' => array(
|
||||
'refresh_token' => rawurlencode( $refresh_token ),
|
||||
),
|
||||
)
|
||||
);
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$retrieved_response_code = wp_remote_retrieve_response_code( $response );
|
||||
if ( 200 !== $retrieved_response_code ) {
|
||||
$error_message = "Expected response code: 200. Returned response code: {$retrieved_response_code}.";
|
||||
|
||||
return new WP_Error( 'google_recaptcha_api_error', $error_message, $retrieved_response_code );
|
||||
}
|
||||
|
||||
$response_body = gf_recaptcha()->maybe_decode_json( wp_remote_retrieve_body( $response ) );
|
||||
|
||||
if ( array_key_exists( 'auth_error', $response_body ) ) {
|
||||
if ( empty( $response_body['auth_error'] ) ) {
|
||||
$error_message = 'Google returned an empty response.';
|
||||
} else {
|
||||
$error_message = 'Google response: ' . print_r( $response_body['auth_error'], true );
|
||||
}
|
||||
|
||||
return new WP_Error( 'google_recaptcha_api_error', $error_message );
|
||||
}
|
||||
|
||||
return $response_body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of Google Cloud projects.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*
|
||||
* @return array|mixed
|
||||
*/
|
||||
public function get_recaptcha_projects() {
|
||||
|
||||
$request_path = 'projects';
|
||||
|
||||
$headers = array(
|
||||
'Authorization' => 'Bearer ' . $this->access_token,
|
||||
'Accept' => 'application/json',
|
||||
);
|
||||
|
||||
$response = $this->make_request( $request_path, array(), $headers, 'GET', 'https://cloudresourcemanager.googleapis.com/v1/' );
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$data = json_decode( $response, true );
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of enterprise site keys associates with the chosen project.
|
||||
*
|
||||
* @param string $project The Google Cloud Project ID.
|
||||
*
|
||||
* @since 1.7.0
|
||||
* @since 1.8.0 Increased the default page size to 100 and added pagination to retrieve all keys.
|
||||
*
|
||||
* @return array|mixed
|
||||
*/
|
||||
public function get_enterprise_site_keys( $project ) {
|
||||
$request_path_base = 'projects/' . $project . '/keys';
|
||||
|
||||
$headers = array(
|
||||
'Authorization' => 'Bearer ' . $this->access_token,
|
||||
'Accept' => 'application/json',
|
||||
);
|
||||
|
||||
$all_keys = array(
|
||||
'keys' => array(),
|
||||
);
|
||||
$page_token = null;
|
||||
$page_size = apply_filters( 'gform_recaptcha_enterprise_keys_page_size', 100 );
|
||||
|
||||
$query_params = array(
|
||||
'pageSize' => $page_size,
|
||||
);
|
||||
|
||||
do {
|
||||
if ( $page_token ) {
|
||||
$query_params['pageToken'] = $page_token;
|
||||
}
|
||||
|
||||
$request_path = $request_path_base . '?' . http_build_query( $query_params );
|
||||
|
||||
$response = $this->make_request( $request_path, array(), $headers );
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
$this->addon->log_error( __METHOD__ . '(): Unable to retrieve site keys: ' . $response->get_error_message() );
|
||||
break;
|
||||
}
|
||||
|
||||
$data = json_decode( $response, true );
|
||||
|
||||
if ( isset( $data['keys'] ) && is_array( $data['keys'] ) ) {
|
||||
$all_keys['keys'] = array_merge( $all_keys['keys'], $data['keys'] );
|
||||
}
|
||||
|
||||
$page_token = rgar( $data, 'nextPageToken' ) ? $data['nextPageToken'] : null;
|
||||
} while ( $page_token );
|
||||
|
||||
return $all_keys;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user