Jetpack_Signature::sign_request PHP Method

sign_request() public method

body_hash v. body-hash is annoying. Refactor to accept an array?
public sign_request ( $token = '', $timestamp, $nonce = '', $body_hash = '', $method = '', $url = '', $body = null, $verify_body_hash = true )
    function sign_request($token = '', $timestamp = 0, $nonce = '', $body_hash = '', $method = '', $url = '', $body = null, $verify_body_hash = true)
    {
        if (!$this->secret) {
            return new Jetpack_Error('invalid_secret', 'Invalid secret');
        }
        if (!$this->token) {
            return new Jetpack_Error('invalid_token', 'Invalid token');
        }
        list($token) = explode('.', $token);
        if (0 !== strpos($token, "{$this->token}:")) {
            return new Jetpack_Error('token_mismatch', 'Incorrect token');
        }
        // If we got an array at this point, let's encode it, so we can see what it looks like as a string.
        if (is_array($body)) {
            if (count($body) > 0) {
                $body = json_encode($body);
            } else {
                $body = '';
            }
        }
        $required_parameters = array('token', 'timestamp', 'nonce', 'method', 'url');
        if (!is_null($body)) {
            $required_parameters[] = 'body_hash';
            if (!is_string($body)) {
                return new Jetpack_Error('invalid_body', 'Body is malformed.');
            }
        }
        foreach ($required_parameters as $required) {
            if (!is_scalar(${$required})) {
                return new Jetpack_Error('invalid_signature', sprintf('The required "%s" parameter is malformed.', str_replace('_', '-', $required)));
            }
            if (!strlen(${$required})) {
                return new Jetpack_Error('invalid_signature', sprintf('The required "%s" parameter is missing.', str_replace('_', '-', $required)));
            }
        }
        if (empty($body)) {
            if ($body_hash) {
                return new Jetpack_Error('invalid_body_hash', 'The body hash does not match.');
            }
        } else {
            if ($verify_body_hash && jetpack_sha1_base64($body) !== $body_hash) {
                return new Jetpack_Error('invalid_body_hash', 'The body hash does not match.');
            }
        }
        $parsed = parse_url($url);
        if (!isset($parsed['host'])) {
            return new Jetpack_Error('invalid_signature', sprintf('The required "%s" parameter is malformed.', 'url'));
        }
        if ($parsed['host'] === JETPACK__WPCOM_JSON_API_HOST) {
            $parsed['host'] = 'public-api.wordpress.com';
        }
        if (!empty($parsed['port'])) {
            $port = $parsed['port'];
        } else {
            if ('http' == $parsed['scheme']) {
                $port = 80;
            } else {
                if ('https' == $parsed['scheme']) {
                    $port = 443;
                } else {
                    return new Jetpack_Error('unknown_scheme_port', "The scheme's port is unknown");
                }
            }
        }
        if (!ctype_digit("{$timestamp}") || 10 < strlen($timestamp)) {
            // If Jetpack is around in 275 years, you can blame mdawaffe for the bug.
            return new Jetpack_Error('invalid_signature', sprintf('The required "%s" parameter is malformed.', 'timestamp'));
        }
        $local_time = $timestamp - $this->time_diff;
        if ($local_time < time() - 600 || $local_time > time() + 300) {
            return new Jetpack_Error('invalid_signature', 'The timestamp is too old.');
        }
        if (12 < strlen($nonce) || preg_match('/[^a-zA-Z0-9]/', $nonce)) {
            return new Jetpack_Error('invalid_signature', sprintf('The required "%s" parameter is malformed.', 'nonce'));
        }
        $normalized_request_pieces = array($token, $timestamp, $nonce, $body_hash, strtoupper($method), strtolower($parsed['host']), $port, $parsed['path']);
        $normalized_request_pieces = array_merge($normalized_request_pieces, $this->normalized_query_parameters(isset($parsed['query']) ? $parsed['query'] : ''));
        $normalized_request_string = join("\n", $normalized_request_pieces) . "\n";
        return base64_encode(hash_hmac('sha1', $normalized_request_string, $this->secret, true));
    }

Usage Example

 /**
  * Makes an authorized remote request using Jetpack_Signature
  *
  * @return array|WP_Error WP HTTP response on success
  */
 public static function remote_request($args, $body = null)
 {
     $defaults = array('url' => '', 'user_id' => 0, 'blog_id' => 0, 'auth_location' => JETPACK_CLIENT__AUTH_LOCATION, 'method' => 'POST', 'timeout' => 10, 'redirection' => 0);
     $args = wp_parse_args($args, $defaults);
     $args['blog_id'] = (int) $args['blog_id'];
     if ('header' != $args['auth_location']) {
         $args['auth_location'] = 'query_string';
     }
     $token = Jetpack_Data::get_access_token($args['user_id']);
     if (!$token) {
         return new Jetpack_Error('missing_token');
     }
     $method = strtoupper($args['method']);
     $timeout = intval($args['timeout']);
     $redirection = $args['redirection'];
     $request = compact('method', 'body', 'timeout', 'redirection');
     @(list($token_key, $secret) = explode('.', $token->secret));
     if (empty($token) || empty($secret)) {
         return new Jetpack_Error('malformed_token');
     }
     $token_key = sprintf('%s:%d:%d', $token_key, JETPACK__API_VERSION, $token->external_user_id);
     require_once dirname(__FILE__) . '/class.jetpack-signature.php';
     $time_diff = (int) Jetpack_Options::get_option('time_diff');
     $jetpack_signature = new Jetpack_Signature($token->secret, $time_diff);
     $timestamp = time() + $time_diff;
     $nonce = wp_generate_password(10, false);
     // Kind of annoying.  Maybe refactor Jetpack_Signature to handle body-hashing
     if (is_null($body)) {
         $body_hash = '';
     } else {
         if (!is_string($body)) {
             return new Jetpack_Error('invalid_body', 'Body is malformed.');
         }
         $body_hash = jetpack_sha1_base64($body);
     }
     $auth = array('token' => $token_key, 'timestamp' => $timestamp, 'nonce' => $nonce, 'body-hash' => $body_hash);
     if (false !== strpos($args['url'], 'xmlrpc.php')) {
         $url_args = array('for' => 'jetpack', 'wpcom_blog_id' => Jetpack_Options::get_option('id'));
     } else {
         $url_args = array();
     }
     if ('header' != $args['auth_location']) {
         $url_args += $auth;
     }
     $url = add_query_arg(urlencode_deep($url_args), $args['url']);
     $url = Jetpack::fix_url_for_bad_hosts($url);
     $signature = $jetpack_signature->sign_request($token_key, $timestamp, $nonce, $body_hash, $method, $url, $body, false);
     if (!$signature || is_wp_error($signature)) {
         return $signature;
     }
     // Send an Authorization header so various caches/proxies do the right thing
     $auth['signature'] = $signature;
     $auth['version'] = JETPACK__VERSION;
     $header_pieces = array();
     foreach ($auth as $key => $value) {
         $header_pieces[] = sprintf('%s="%s"', $key, $value);
     }
     $request['headers'] = array('Authorization' => "X_JETPACK " . join(' ', $header_pieces));
     if ('header' != $args['auth_location']) {
         $url = add_query_arg('signature', urlencode($signature), $url);
     }
     return Jetpack_Client::_wp_remote_request($url, $request);
 }
All Usage Examples Of Jetpack_Signature::sign_request