ist( 'allowlist' ) ); $blocklist_regex_pattern = '#' . implode( '|', $blocklist ) . '#i'; $allowlist_regex_pattern = '#' . implode( '|', $allowlist ) . '#i'; $blocklist_match = preg_match( $blocklist_regex_pattern, $ua ); $allowlist_match = preg_match( $allowlist_regex_pattern, $ua ); if ( empty( $blocklist_match ) && empty( $allowlist_match ) ) { return array( 'na' ); } $result = array(); if ( ! empty( $blocklist_match ) && empty( $allowlist_match ) ) { $result[] = 'banned'; } if ( ! empty( $allowlist_match ) ) { $result[] = 'allowlist'; } return $result; } /** * Checks if a user agent is present in a given list. * * @param string $ua The user agent to check. * @param string $collection The type of list to check against ('blocklist' or 'allowlist'). * * @return bool Returns true if the user agent is in the list, false otherwise. */ public function is_ua_in_list( $ua, $collection ): bool { $arr = str_replace( '#', '\#', $this->get_lockout_list( $collection ) ); $list_regex_pattern = '#' . implode( '|', $arr ) . '#i'; $list_match = preg_match( $list_regex_pattern, $ua ); return ! empty( $list_match ); } /** * Remove User Agent from a list. * * @param string $ua The user agent to remove. * @param string $collection blocklist|allowlist. * * @return void */ public function remove_from_list( $ua, $collection ) { $arr = $this->get_lockout_list( $collection ); // Array can contain uppercase. $orig_arr = str_replace( '#', '\#', $this->get_lockout_list( $collection, false ) ); $list_regex_pattern = '#' . implode( '|', $arr ) . '#i'; $list_match = preg_match( $list_regex_pattern, $ua ); if ( false !== $list_match ) { // Plain string match. For e.g. r.n regex matches ran & run but we can add/block UA string name if user send the useragent name as run then we include that in allowlist so run won't be blocked but ran will be blocked. $key = array_search( $ua, $arr, true ); if ( false !== $key && isset( $orig_arr[ $key ] ) ) { unset( $orig_arr[ $key ] ); $is_string_match = true; } else { // If plain string not matched then add the user agent in opposite list if unban is clicked then add that string to allow list, else if ban user agent clicked then add that string to blocklist though allow list take higher priority i.e. in allow list r.n present then adding r.n or run or ran in blocklist won't block the user agent because of priority. $is_string_match = false; } if ( 'blocklist' === $collection ) { $this->blacklist = implode( PHP_EOL, $orig_arr ); if ( false === $is_string_match ) { $this->whitelist = $this->push_ua_to_list( $ua, 'allowlist' ); } } elseif ( 'allowlist' === $collection ) { $this->whitelist = implode( PHP_EOL, $orig_arr ); if ( false === $is_string_match ) { $this->blacklist = $this->push_ua_to_list( $ua, 'blocklist' ); } } $this->save(); } } /** * Add an UA to the list. * * @param string $ua User agent name. * @param string $collection blocklist|allowlist. * * @return void */ public function add_to_list( $ua, $collection ) { if ( 'blocklist' === $collection ) { $this->blacklist = $this->push_ua_to_list( $ua, $collection ); } elseif ( 'allowlist' === $collection ) { $this->whitelist = $this->push_ua_to_list( $ua, $collection ); } $this->save(); } /** * Push the UA to either blocklist or allowlist * * @param string $ua User agent name. * @param string $collection List type i.e. blocklist or allowlist. * * @return string List as string format with UA delimited with newline character. */ private function push_ua_to_list( string $ua, string $collection ): string { $arr = $this->get_lockout_list( $collection, false ); $arr[] = trim( $ua ); $arr = array_unique( $arr ); return implode( PHP_EOL, $arr ); } /** * Get the module name. * * @return string */ public static function get_module_name(): string { return esc_html__( 'User Agent Banning', 'defender-security' ); } /** * Get the module state. * * @param bool $flag Module state. * * @return string */ public static function get_module_state( $flag ): string { return $flag ? esc_html__( 'active', 'defender-security' ) : esc_html__( 'inactive', 'defender-security' ); } }