PageRenderTime 41ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-content/plugins/ithemes-security-pro/core/modules/ipcheck/class-itsec-ipcheck.php

https://bitbucket.org/Pandababe/boho
PHP | 261 lines | 142 code | 58 blank | 61 comment | 29 complexity | 082ac6c8a73987fedc46f85ab570d61e MD5 | raw file
Possible License(s): GPL-3.0
  1. <?php
  2. /**
  3. * iThemes IPCheck API Wrapper.
  4. *
  5. * Provides static calls to the iThemes IPCheck API
  6. *
  7. * @package iThemes_Security
  8. *
  9. * @since 4.5
  10. *
  11. */
  12. class ITSEC_IPCheck {
  13. private $endpoint = 'http://ipcheck-api.ithemes.com/?action=';
  14. private $settings;
  15. public function run() {
  16. add_action( 'wp_login', array( $this, 'wp_login' ), 10, 2 );
  17. add_action( 'itsec-handle-failed-login', array( $this, 'handle_failed_login' ), 10, 2 );
  18. add_filter( 'itsec_logger_modules', array( $this, 'itsec_logger_modules' ) );
  19. }
  20. private function load_settings() {
  21. if ( ! isset( $this->settings ) ) {
  22. $this->settings = ITSEC_Modules::get_settings( 'network-brute-force' );
  23. }
  24. }
  25. private function set_cache( $ip, $response ) {
  26. $cache = $this->get_cache( $ip );
  27. $time = ITSEC_Core::get_current_time_gmt();
  28. if ( isset( $response['block'] ) ) {
  29. $cache['block'] = (boolean) $response['block'];
  30. }
  31. if ( isset( $response['cache_ttl'] ) ) {
  32. $cache['cache_ttl'] = intval( $response['cache_ttl'] ) + $time;
  33. } else if ( 0 === $cache['cache_ttl'] ) {
  34. $cache['cache_ttl'] = $time + HOUR_IN_SECONDS;
  35. }
  36. if ( isset( $response['report_ttl'] ) ) {
  37. $cache['report_ttl'] = intval( $response['report_ttl'] ) + $time;
  38. }
  39. $transient_time = max( $cache['cache_ttl'], $cache['report_ttl'] ) - $time;
  40. set_site_transient( "itsec_ipcheck_$ip", $cache, $transient_time );
  41. }
  42. private function get_cache( $ip ) {
  43. $cache = get_site_transient( "itsec_ipcheck_$ip" );
  44. $defaults = array(
  45. 'block' => false,
  46. 'cache_ttl' => 0,
  47. 'report_ttl' => 0,
  48. );
  49. if ( ! is_array( $cache ) ) {
  50. return $defaults;
  51. }
  52. return array_merge( $defaults, $cache );
  53. }
  54. /**
  55. * Check visitor IP to see if it is banned by IPCheck.
  56. *
  57. * @since 3.0.0
  58. *
  59. * @return bool true if banned, false otherwise.
  60. */
  61. private function is_ip_banned( $ip = false ) {
  62. return $this->get_server_response( 'check-ip', $ip );
  63. }
  64. /**
  65. * Report visitor IP for blacklistable-offense to IPCheck.
  66. *
  67. * @since 3.0.0
  68. *
  69. * @return bool true if banned, false otherwise.
  70. */
  71. private function report_ip( $ip = false ) {
  72. return $this->get_server_response( 'report-ip', $ip );
  73. }
  74. private function get_server_response( $action, $ip = false ) {
  75. global $itsec_logger;
  76. $this->load_settings();
  77. if ( empty( $this->settings['api_key'] ) || empty( $this->settings['api_secret'] ) ) {
  78. return false;
  79. }
  80. if ( false === $ip ) {
  81. $ip = ITSEC_Lib::get_ip();
  82. }
  83. require_once( ITSEC_Core::get_core_dir() . '/lib/class-itsec-lib-ip-tools.php' );
  84. if ( ! ITSEC_Lib_IP_Tools::validate( $ip ) || ITSEC_Lib::is_ip_whitelisted( $ip ) ) {
  85. return false;
  86. }
  87. $cache = $this->get_cache( $ip );
  88. if ( 'check-ip' === $action ) {
  89. if ( $cache['cache_ttl'] >= ITSEC_Core::get_current_time_gmt() ) {
  90. return $cache['block'];
  91. }
  92. } else if ( 'report-ip' === $action ) {
  93. if ( $cache['report_ttl'] >= ITSEC_Core::get_current_time_gmt() ) {
  94. return $cache['block'];
  95. }
  96. }
  97. $args = json_encode(
  98. array(
  99. 'apikey' => $this->settings['api_key'],
  100. 'behavior' => 'brute-force-login',
  101. 'ip' => $ip,
  102. 'site' => home_url( '', 'http' ),
  103. 'timestamp' => ITSEC_Core::get_current_time_gmt(),
  104. )
  105. );
  106. $request = array(
  107. 'body' => array(
  108. 'request' => $args,
  109. 'signature' => $this->hmac_sha1( $this->settings['api_secret'], $action . $args ),
  110. ),
  111. );
  112. $response = wp_remote_post( $this->endpoint . $action, $request );
  113. if ( is_wp_error( $response ) || ! isset( $response['body'] ) ) {
  114. return false;
  115. }
  116. $response = json_decode( $response['body'], true );
  117. if ( ! is_array( $response ) || ! isset( $response['success'] ) || ! $response['success'] ) {
  118. return false;
  119. }
  120. $this->set_cache( $ip, $response );
  121. $cache_seconds = isset( $response['cache_ttl'] ) ? absint( $response['cache_ttl'] ) : 3600;
  122. if ( isset( $response['block'] ) && $response['block'] ) {
  123. $data = array(
  124. 'expires' => date( 'Y-m-d H:i:s', ITSEC_Core::get_current_time() + $cache_seconds ),
  125. 'expires_gmt' => date( 'Y-m-d H:i:s', ITSEC_Core::get_current_time_gmt() + $cache_seconds ),
  126. 'type' => 'host',
  127. );
  128. $itsec_logger->log_event( 'lockout', 10, $data, $ip );
  129. return true;
  130. }
  131. return false;
  132. }
  133. /**
  134. * Calculates the HMAC of a string using SHA1.
  135. *
  136. * there is a native PHP hmac function, but we use this one for
  137. * the widest compatibility with older PHP versions
  138. *
  139. * @param string $key the shared secret key used to generate the mac
  140. * @param string $data data to be signed
  141. *
  142. *
  143. * @return string base64 encoded hmac
  144. */
  145. private function hmac_sha1( $key, $data ) {
  146. if ( strlen( $key ) > 64 ) {
  147. $key = pack( 'H*', sha1( $key ) );
  148. }
  149. $key = str_pad( $key, 64, chr( 0x00 ) );
  150. $ipad = str_repeat( chr( 0x36 ), 64 );
  151. $opad = str_repeat( chr( 0x5c ), 64 );
  152. $hmac = pack( 'H*', sha1( ( $key ^ $opad ) . pack( 'H*', sha1( ( $key ^ $ipad ) . $data ) ) ) );
  153. return base64_encode( $hmac );
  154. }
  155. /**
  156. * Register IPCheck for logger
  157. *
  158. * @since 4.5
  159. *
  160. * @param array $logger_modules array of logger modules
  161. *
  162. * @return array array of logger modules
  163. */
  164. public function itsec_logger_modules( $logger_modules ) {
  165. $logger_modules['ipcheck'] = array(
  166. 'type' => 'ipcheck',
  167. 'function' => __( 'IP Flagged by Network Brute Force Protection', 'it-l10n-ithemes-security-pro' ),
  168. );
  169. return $logger_modules;
  170. }
  171. /**
  172. * Make sure user isn't already locked out even on successful form submission
  173. *
  174. * @since 4.5
  175. *
  176. * @return void
  177. */
  178. public function wp_login() {
  179. /** @var ITSEC_Lockout $itsec_lockout */
  180. global $itsec_logger, $itsec_lockout;
  181. $this->load_settings();
  182. if ( $this->settings['enable_ban'] && $this->is_ip_banned() ) {
  183. $itsec_logger->log_event( 'ipcheck', 10, array(), ITSEC_Lib::get_ip() );
  184. $itsec_lockout->execute_lock( array( 'network_lock' => true ) );
  185. }
  186. }
  187. /**
  188. * Sends to lockout class when username and password are filled out and wrong
  189. *
  190. * @since 4.5
  191. *
  192. * @return void
  193. */
  194. public function handle_failed_login( $username, $details ) {
  195. /** @var ITSEC_Lockout $itsec_lockout */
  196. global $itsec_logger, $itsec_lockout;
  197. $this->load_settings();
  198. if ( $this->settings['enable_ban'] && $this->report_ip() ) {
  199. $itsec_logger->log_event( 'ipcheck', 10, array(), ITSEC_Lib::get_ip() );
  200. $itsec_lockout->execute_lock( array( 'network_lock' => true ) );
  201. }
  202. }
  203. }