diff --git a/projects/packages/waf/src/class-waf-blocklog-manager.php b/projects/packages/waf/src/class-waf-blocklog-manager.php index 2d891f789c9ec..f5ff9652cfe9e 100644 --- a/projects/packages/waf/src/class-waf-blocklog-manager.php +++ b/projects/packages/waf/src/class-waf-blocklog-manager.php @@ -22,6 +22,15 @@ class Waf_Blocklog_Manager { */ private static $db_connection = null; + /** + * Gets the path to the waf-blocklog file. + * + * @return string The waf-blocklog file path. + */ + public static function get_blocklog_file_path() { + return trailingslashit( JETPACK_WAF_DIR ) . 'waf-blocklog'; + } + /** * Connect to WordPress database. * @@ -33,7 +42,7 @@ private static function connect_to_wordpress_db() { } if ( ! file_exists( JETPACK_WAF_WPCONFIG ) ) { - return; + return null; } require_once JETPACK_WAF_WPCONFIG; @@ -54,7 +63,7 @@ private static function connect_to_wordpress_db() { * * @return void */ - public static function close_db_connection() { + private static function close_db_connection() { if ( self::$db_connection ) { self::$db_connection->close(); self::$db_connection = null; @@ -109,6 +118,8 @@ public static function create_blocklog_table() { * Write block logs to database. * * @param array $log_data Log data. + * + * @return void */ private static function write_blocklog_row( $log_data ) { $conn = self::connect_to_wordpress_db(); @@ -162,6 +173,7 @@ private static function get_daily_summary() { * Increments the current date's daily summary stat. * * @param array $current_value The current value of the daily summary. + * * @return array The updated daily summary. */ public static function increment_daily_summary( array $current_value ) { @@ -176,9 +188,10 @@ public static function increment_daily_summary( array $current_value ) { * Update the daily summary option in the database. * * @param array $value The value to update. + * * @return void */ - private static function update_daily_summary( array $value ) { + private static function write_daily_summary_row( array $value ) { global $table_prefix; $option_name = self::BLOCKLOG_OPTION_NAME_DAILY_SUMMARY; @@ -201,12 +214,12 @@ private static function update_daily_summary( array $value ) { * * @return void */ - private static function write_daily_summary_row() { + private static function write_daily_summary() { $stats = self::get_daily_summary(); $stats = self::increment_daily_summary( $stats ); $stats = self::filter_last_30_days( $stats ); - self::update_daily_summary( $stats ); + self::write_daily_summary_row( $stats ); } /** @@ -243,8 +256,10 @@ private static function get_all_time_block_count_value() { * @param int $value The value to update. * @return void */ - private static function update_all_time_block_count( int $value ) { + private static function write_all_time_block_count_row( int $value ) { global $table_prefix; + $option_name = self::BLOCKLOG_OPTION_NAME_ALL_TIME_BLOCK_COUNT; + $db_connection = self::connect_to_wordpress_db(); if ( ! $db_connection ) { return; @@ -262,24 +277,26 @@ private static function update_all_time_block_count( int $value ) { * * @return void */ - public static function write_all_time_block_count_row() { + private static function write_all_time_block_count() { $block_count = self::get_all_time_block_count_value() ?? self::get_default_all_time_stat_value(); - self::update_all_time_block_count( $block_count + 1 ); + self::write_all_time_block_count_row( $block_count + 1 ); } /** * Filters the stats to retain only data for the last 30 days. * * @param array $stats The array of stats to prune. + * * @return array Pruned stats array. */ public static function filter_last_30_days( array $stats ) { + $today = gmdate( 'Y-m-d' ); $one_month_ago = gmdate( 'Y-m-d', strtotime( '-30 days' ) ); return array_filter( $stats, - function ( $date ) use ( $one_month_ago ) { - return $date >= $one_month_ago; + function ( $date ) use ( $one_month_ago, $today ) { + return $date >= $one_month_ago && $date <= $today; }, ARRAY_FILTER_USE_KEY ); @@ -330,6 +347,8 @@ public static function get_all_time_block_count() { /** * Compute the initial all-time stats value. + * + * @return int The initial all-time stats value. */ private static function get_default_all_time_stat_value() { $conn = self::connect_to_wordpress_db(); @@ -355,6 +374,8 @@ private static function get_default_all_time_stat_value() { /** * Get the headers for logging purposes. + * + * @return array The headers. */ public static function get_request_headers() { $all_headers = getallheaders(); @@ -408,18 +429,9 @@ public static function write_blocklog( $rule_id, $reason ) { } } - self::write_daily_summary_row(); - self::write_all_time_block_count_row(); + self::write_daily_summary(); + self::write_all_time_block_count(); self::write_blocklog_row( $log_data ); self::close_db_connection(); } - - /** - * Gets the path to the waf-blocklog file. - * - * @return string The waf-blocklog file path. - */ - public static function get_blocklog_file_path() { - return trailingslashit( JETPACK_WAF_DIR ) . 'waf-blocklog'; - } } diff --git a/projects/packages/waf/src/functions.php b/projects/packages/waf/src/functions.php index 7d60cd28f88fe..69880fbc7f3e7 100644 --- a/projects/packages/waf/src/functions.php +++ b/projects/packages/waf/src/functions.php @@ -70,3 +70,51 @@ function flatten_array( $array, $key_prefix = '', $dot_notation = null ) { } return $return; } + +/** + * Polyfill for getallheaders, which is not available in all PHP environments. + * + * @link https://github.com/ralouphie/getallheaders + */ +if ( ! function_exists( 'getallheaders' ) ) { + /** + * Get all HTTP header key/values as an associative array for the current request. + * + * @return string[string] The HTTP header key/value pairs. + */ + function getallheaders() { + // phpcs:disable WordPress.Security.ValidatedSanitizedInput + $headers = array(); + + $copy_server = array( + 'CONTENT_TYPE' => 'Content-Type', + 'CONTENT_LENGTH' => 'Content-Length', + 'CONTENT_MD5' => 'Content-Md5', + ); + + foreach ( $_SERVER as $key => $value ) { + if ( substr( $key, 0, 5 ) === 'HTTP_' ) { + $key = substr( $key, 5 ); + if ( ! isset( $copy_server[ $key ] ) || ! isset( $_SERVER[ $key ] ) ) { + $key = str_replace( ' ', '-', ucwords( strtolower( str_replace( '_', ' ', $key ) ) ) ); + $headers[ $key ] = $value; + } + } elseif ( isset( $copy_server[ $key ] ) ) { + $headers[ $copy_server[ $key ] ] = $value; + } + } + + if ( ! isset( $headers['Authorization'] ) ) { + if ( isset( $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ) ) { + $headers['Authorization'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; + } elseif ( isset( $_SERVER['PHP_AUTH_USER'] ) ) { + $basic_pass = isset( $_SERVER['PHP_AUTH_PW'] ) ? $_SERVER['PHP_AUTH_PW'] : ''; + $headers['Authorization'] = 'Basic ' . base64_encode( $_SERVER['PHP_AUTH_USER'] . ':' . $basic_pass ); + } elseif ( isset( $_SERVER['PHP_AUTH_DIGEST'] ) ) { + $headers['Authorization'] = $_SERVER['PHP_AUTH_DIGEST']; + } + } + + return $headers; + } +} diff --git a/projects/packages/waf/tests/php/unit/test-waf-blocklog-manager.php b/projects/packages/waf/tests/php/unit/test-waf-blocklog-manager.php index 3d39b67724f23..e1835501adee3 100644 --- a/projects/packages/waf/tests/php/unit/test-waf-blocklog-manager.php +++ b/projects/packages/waf/tests/php/unit/test-waf-blocklog-manager.php @@ -51,4 +51,26 @@ public function testIncrementDailySummary() { $result = Waf_Blocklog_Manager::increment_daily_summary( $value ); $this->assertEquals( 2, $result[ $today ] ); } + + /** + * Test filtering of the daily summary stats. + */ + public function testFilterLast30Days() { + // Generate stats data with dates from 35 days ago to 5 days in the future + $stats = array(); + for ( $i = -35; $i <= 5; $i++ ) { + $date = gmdate( 'Y-m-d', strtotime( "$i days" ) ); + $stats[ $date ] = "data for $date"; + } + + // Generate expected data with dates from 30 days ago to today + $expected_stats = array(); + for ( $i = -30; $i <= 0; $i++ ) { + $date = gmdate( 'Y-m-d', strtotime( "$i days" ) ); + $expected_stats[ $date ] = "data for $date"; + } + + $filtered_stats = Waf_Blocklog_Manager::filter_last_30_days( $stats ); + $this->assertEquals( $expected_stats, $filtered_stats ); + } }