Jetpack_Signature

The Jetpack by WordPress.com Jetpack Signature class.

Defined (1)

The class is defined in the following location(s).

/class.jetpack-signature.php  
  1. class Jetpack_Signature { 
  2. public $token; 
  3. public $secret; 
  4.  
  5. function __construct( $access_token, $time_diff = 0 ) { 
  6. $secret = explode( '.', $access_token ); 
  7. if ( 2 != count( $secret ) ) 
  8. return; 
  9.  
  10. $this->token = $secret[0]; 
  11. $this->secret = $secret[1]; 
  12. $this->time_diff = $time_diff; 
  13.  
  14. function sign_current_request( $override = array() ) { 
  15. if ( isset( $override['scheme'] ) ) { 
  16. $scheme = $override['scheme']; 
  17. if ( !in_array( $scheme, array( 'http', 'https' ) ) ) { 
  18. return new Jetpack_Error( 'invalid_sheme', 'Invalid URL scheme' ); 
  19. } else { 
  20. if ( is_ssl() ) { 
  21. $scheme = 'https'; 
  22. } else { 
  23. $scheme = 'http'; 
  24.  
  25. if ( is_ssl() ) { 
  26. $port = JETPACK_SIGNATURE__HTTPS_PORT == $_SERVER['SERVER_PORT'] ? '' : $_SERVER['SERVER_PORT']; 
  27. } else { 
  28. $port = JETPACK_SIGNATURE__HTTP_PORT == $_SERVER['SERVER_PORT'] ? '' : $_SERVER['SERVER_PORT']; 
  29.  
  30. $url = "{$scheme}://{$_SERVER['HTTP_HOST']}:{$port}" . stripslashes( $_SERVER['REQUEST_URI'] ); 
  31.  
  32. if ( array_key_exists( 'body', $override ) && !is_null( $override['body'] ) ) { 
  33. $body = $override['body']; 
  34. } else if ( 'POST' == strtoupper( $_SERVER['REQUEST_METHOD'] ) ) { 
  35. $body = isset( $GLOBALS['HTTP_RAW_POST_DATA'] ) ? $GLOBALS['HTTP_RAW_POST_DATA'] : null; 
  36. } else { 
  37. $body = null; 
  38.  
  39. $a = array(); 
  40. foreach ( array( 'token', 'timestamp', 'nonce', 'body-hash' ) as $parameter ) { 
  41. if ( isset( $override[$parameter] ) ) { 
  42. $a[$parameter] = $override[$parameter]; 
  43. } else { 
  44. $a[$parameter] = isset( $_GET[$parameter] ) ? stripslashes( $_GET[$parameter] ) : ''; 
  45.  
  46. $method = isset( $override['method'] ) ? $override['method'] : $_SERVER['REQUEST_METHOD']; 
  47. return $this->sign_request( $a['token'], $a['timestamp'], $a['nonce'], $a['body-hash'], $method, $url, $body, true ); 
  48.  
  49. // body_hash v. body-hash is annoying. Refactor to accept an array? 
  50. function sign_request( $token = '', $timestamp = 0, $nonce = '', $body_hash = '', $method = '', $url = '', $body = null, $verify_body_hash = true ) { 
  51. if ( !$this->secret ) { 
  52. return new Jetpack_Error( 'invalid_secret', 'Invalid secret' ); 
  53.  
  54. if ( !$this->token ) { 
  55. return new Jetpack_Error( 'invalid_token', 'Invalid token' ); 
  56.  
  57. list( $token ) = explode( '.', $token ); 
  58.  
  59. if ( 0 !== strpos( $token, "$this->token:" ) ) { 
  60. return new Jetpack_Error( 'token_mismatch', 'Incorrect token' ); 
  61.  
  62. $required_parameters = array( 'token', 'timestamp', 'nonce', 'method', 'url' ); 
  63. if ( !is_null( $body ) ) { 
  64. $required_parameters[] = 'body_hash'; 
  65. if ( !is_string( $body ) ) { 
  66. return new Jetpack_Error( 'invalid_body', 'Body is malformed.' ); 
  67.  
  68. foreach ( $required_parameters as $required ) { 
  69. if ( !is_scalar( $$required ) ) { 
  70. return new Jetpack_Error( 'invalid_signature', sprintf( 'The required "%s" parameter is malformed.', str_replace( '_', '-', $required ) ) ); 
  71.  
  72. if ( !strlen( $$required ) ) { 
  73. return new Jetpack_Error( 'invalid_signature', sprintf( 'The required "%s" parameter is missing.', str_replace( '_', '-', $required ) ) ); 
  74.  
  75. if ( is_null( $body ) ) { 
  76. if ( $body_hash ) { 
  77. return new Jetpack_Error( 'invalid_body_hash', 'The body hash does not match.' ); 
  78. } else { 
  79. if ( $verify_body_hash && jetpack_sha1_base64( $body ) !== $body_hash ) { 
  80. return new Jetpack_Error( 'invalid_body_hash', 'The body hash does not match.' ); 
  81.  
  82. $parsed = parse_url( $url ); 
  83. if ( !isset( $parsed['host'] ) ) { 
  84. return new Jetpack_Error( 'invalid_signature', sprintf( 'The required "%s" parameter is malformed.', 'url' ) ); 
  85.  
  86. if ( !empty( $parsed['port'] ) ) { 
  87. $port = $parsed['port']; 
  88. } else { 
  89. if ( 'http' == $parsed['scheme'] ) { 
  90. $port = 80; 
  91. } else if ( 'https' == $parsed['scheme'] ) { 
  92. $port = 443; 
  93. } else { 
  94. return new Jetpack_Error( 'unknown_scheme_port', "The scheme's port is unknown" ); 
  95.  
  96. if ( !ctype_digit( "$timestamp" ) || 10 < strlen( $timestamp ) ) { // If Jetpack is around in 275 years, you can blame mdawaffe for the bug. 
  97. return new Jetpack_Error( 'invalid_signature', sprintf( 'The required "%s" parameter is malformed.', 'timestamp' ) ); 
  98.  
  99. $local_time = $timestamp - $this->time_diff; 
  100. if ( $local_time < time() - 600 || $local_time > time() + 300 ) { 
  101. return new Jetpack_Error( 'invalid_signature', 'The timestamp is too old.' ); 
  102.  
  103. if ( 12 < strlen( $nonce ) || preg_match( '/[^a-zA-Z0-9]/', $nonce ) ) { 
  104. return new Jetpack_Error( 'invalid_signature', sprintf( 'The required "%s" parameter is malformed.', 'nonce' ) ); 
  105.  
  106. $normalized_request_pieces = array( 
  107. $token,  
  108. $timestamp,  
  109. $nonce,  
  110. $body_hash,  
  111. strtoupper( $method ),  
  112. strtolower( $parsed['host'] ),  
  113. $port,  
  114. $parsed['path'],  
  115. // Normalized Query String 
  116. ); 
  117.  
  118. $normalized_request_pieces = array_merge( $normalized_request_pieces, $this->normalized_query_parameters( isset( $parsed['query'] ) ? $parsed['query'] : '' ) ); 
  119.  
  120. $normalized_request_string = join( "\n", $normalized_request_pieces ) . "\n"; 
  121.  
  122. return base64_encode( hash_hmac( 'sha1', $normalized_request_string, $this->secret, true ) ); 
  123.  
  124. function normalized_query_parameters( $query_string ) { 
  125. parse_str( $query_string, $array ); 
  126. if ( get_magic_quotes_gpc() ) 
  127. $array = stripslashes_deep( $array ); 
  128.  
  129. unset( $array['signature'] ); 
  130.  
  131. $names = array_keys( $array ); 
  132. $values = array_values( $array ); 
  133.  
  134. $names = array_map( array( $this, 'encode_3986' ), $names ); 
  135. $values = array_map( array( $this, 'encode_3986' ), $values ); 
  136.  
  137. $pairs = array_map( array( $this, 'join_with_equal_sign' ), $names, $values ); 
  138.  
  139. sort( $pairs ); 
  140.  
  141. return $pairs; 
  142.  
  143. function encode_3986( $string ) { 
  144. $string = rawurlencode( $string ); 
  145. return str_replace( '%7E', '~', $string ); // prior to PHP 5.3, rawurlencode was RFC 1738 
  146.  
  147. function join_with_equal_sign( $name, $value ) { 
  148. return "{$name}={$value}";