관리-도구
편집 파일: security.php
<?php class Meow_MWAI_Modules_Security { public $core = null; public $banned_ips = []; public $banned_words = []; public function __construct( $core ) { $this->core = $core; $this->banned_ips = $this->core->get_option( 'banned_ips' ); $this->banned_words = $this->core->get_option( 'banned_words' ); if ( !empty( $this->banned_ips ) ) { add_filter( 'mwai_ai_allowed', [ $this, 'check_banned_ips' ], 5, 3 ); } if ( !empty( $this->banned_words ) ) { add_filter( 'mwai_ai_allowed', [ $this, 'check_banned_words' ], 5, 3 ); } } public function check_banned_ips( $ok, $query, $limits ) { if ( $ok !== true || empty( $this->banned_ips ) ) { return $ok; } if ( is_a( $query, 'Meow_MWAI_Query_Embed' ) ) { if ( $this->core->can_access_settings() ) { return $ok; } } $ip = $this->core->get_ip_address( true ); if ( $this->is_blocked_ip( $ip, $this->banned_ips ) ) { Meow_MWAI_Logging::warn( "Blocked IP: $ip", '🔒' ); throw new Exception( 'Your query has been rejected.' ); } return $ok; } public function check_banned_words( $ok, $query, $limits ) { if ( $ok !== true || empty( $this->banned_words ) ) { return $ok; } if ( is_a( $query, 'Meow_MWAI_Query_Embed' ) ) { if ( $this->core->can_access_settings() ) { return $ok; } } $text = $query->get_message(); $is_substring_match = $this->core->get_option( 'ignore_word_boundaries' ); foreach ( $this->banned_words as $word ) { // Use preg_quote to escape any special characters in the word // This is necessary to safely include $word in the regex pattern // Add the 'u' modifier to enable Unicode support if ( $is_substring_match ) { $pattern = '/' . preg_quote( $word, '/' ) . '/iu'; // no \b } else { $pattern = '/\b' . preg_quote( $word, '/' ) . '\b/iu'; } if ( preg_match( $pattern, $text ) ) { Meow_MWAI_Logging::warn( "Blocked word: $word", '🔒' ); throw new Exception( 'Your query has been rejected.' ); } } return $ok; } public function ip_in_range( $ip, $range ) { if ( strpos( $range, '/' ) === false ) { $range .= '/32'; // Convert single IP to CIDR notation } list( $range_ip, $subnet ) = explode( '/', $range, 2 ); if ( filter_var( $range_ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) ) { $ip_bin = ip2long( $ip ); $range_ip_bin = ip2long( $range_ip ); $subnet_mask = 0xFFFFFFFF << ( 32 - $subnet ); return ( $ip_bin & $subnet_mask ) == ( $range_ip_bin & $subnet_mask ); } elseif ( filter_var( $range_ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) ) { $ip_bin = inet_pton( $ip ); $range_ip_bin = inet_pton( $range_ip ); $subnet_mask = str_repeat( "\xFF", $subnet >> 3 ) . str_repeat( "\x00", 16 - ( $subnet >> 3 ) ); $subnet_mask[( $subnet >> 3 )] = chr( 0xFF << ( 8 - ( $subnet & 7 ) ) ); return ( $ip_bin & $subnet_mask ) == ( $range_ip_bin & $subnet_mask ); } return false; } public function is_blocked_ip( $ip, $blocked_ips ) { foreach ( $blocked_ips as $range ) { if ( $this->ip_in_range( $ip, $range ) ) { return true; } } return false; } }