upskill-event-manager/includes/class-hvac-security.php
ben 1032fbfe85
Some checks failed
Security Monitoring & Compliance / Static Code Security Analysis (push) Has been cancelled
Security Monitoring & Compliance / Security Compliance Validation (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Security Analysis (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Code Quality & Standards (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Unit Tests (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Integration Tests (push) Has been cancelled
Security Monitoring & Compliance / Dependency Vulnerability Scan (push) Has been cancelled
Security Monitoring & Compliance / Secrets & Credential Scan (push) Has been cancelled
Security Monitoring & Compliance / WordPress Security Analysis (push) Has been cancelled
Security Monitoring & Compliance / Security Summary Report (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Deploy to Production (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Notification (push) Has been cancelled
Security Monitoring & Compliance / Security Team Notification (push) Has been cancelled
feat: complete PHP 8+ modernization with backward compatibility
Major modernization of HVAC plugin for PHP 8+ with full backward compatibility:

CORE MODERNIZATION:
- Implement strict type declarations throughout codebase
- Modernize main plugin class with PHP 8+ features
- Convert array syntax to modern PHP format
- Add constructor property promotion where applicable
- Enhance security helpers with modern PHP patterns

COMPATIBILITY FIXES:
- Fix PHP 8.1+ enum compatibility (convert to class constants)
- Fix union type compatibility (true|WP_Error → bool|WP_Error)
- Remove mixed type declarations for PHP 8.0 compatibility
- Add default arms to match expressions preventing UnhandledMatchError
- Fix method naming inconsistency (ensureRegistrationAccess callback)
- Add null coalescing in TEC integration for strict type compliance

DEPLOYMENT STATUS:
 Successfully deployed and tested on staging
 Site functional at https://upskill-staging.measurequick.com
 Expert code review completed with GPT-5 validation
 MCP Playwright testing confirms functionality

Ready for production deployment when requested.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-31 17:44:39 -03:00

234 lines
No EOL
5.3 KiB
PHP

<?php
declare(strict_types=1);
/**
* HVAC Community Events Security Helper
*
* Provides security utilities and validation methods
*
* @package HVAC_Community_Events
* @subpackage Includes
* @since 1.1.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Class HVAC_Security
*/
class HVAC_Security {
/**
* Verify a nonce with proper error handling
*
* @param string $nonce The nonce to verify
* @param string $action The nonce action
* @param bool $die_on_fail Whether to die on failure
* @return bool
*/
public static function verify_nonce( $nonce, $action, $die_on_fail = false ) {
$is_valid = wp_verify_nonce( $nonce, $action );
if ( ! $is_valid ) {
HVAC_Logger::warning( 'Nonce verification failed', 'Security', [
'action' => $action,
'user_id' => get_current_user_id(),
] );
if ( $die_on_fail ) {
wp_die( __( 'Security check failed. Please refresh the page and try again.', 'hvac-community-events' ) );
}
}
return $is_valid;
}
/**
* Check if current user has required capability
*
* @param string $capability The capability to check
* @param bool $die_on_fail Whether to die on failure
* @return bool
*/
public static function check_capability( $capability, $die_on_fail = false ) {
$has_cap = current_user_can( $capability );
if ( ! $has_cap ) {
HVAC_Logger::warning( 'Capability check failed', 'Security', [
'capability' => $capability,
'user_id' => get_current_user_id(),
] );
if ( $die_on_fail ) {
wp_die( __( 'You do not have permission to perform this action.', 'hvac-community-events' ) );
}
}
return $has_cap;
}
/**
* Check if user is logged in with optional redirect
*
* @param string $redirect_to URL to redirect if not logged in
* @return bool
*/
public static function require_login( $redirect_to = '' ) {
if ( ! is_user_logged_in() ) {
if ( ! empty( $redirect_to ) ) {
wp_safe_redirect( $redirect_to );
exit;
}
return false;
}
return true;
}
/**
* Sanitize and validate email
*
* @param string $email Email to validate
* @return string|false Sanitized email or false if invalid
*/
public static function sanitize_email( $email ) {
$email = sanitize_email( $email );
return is_email( $email ) ? $email : false;
}
/**
* Sanitize and validate URL
*
* @param string $url URL to validate
* @return string|false Sanitized URL or false if invalid
*/
public static function sanitize_url( $url ) {
$url = esc_url_raw( $url );
return filter_var( $url, FILTER_VALIDATE_URL ) ? $url : false;
}
/**
* Sanitize array of values
*
* @param array $array Array to sanitize
* @param string $type Type of sanitization (text|email|url|int)
* @return array
*/
public static function sanitize_array( $array, $type = 'text' ) {
if ( ! is_array( $array ) ) {
return [];
}
$sanitized = [];
foreach ( $array as $key => $value ) {
switch ( $type ) {
case 'email':
$clean = self::sanitize_email( $value );
if ( $clean ) {
$sanitized[ $key ] = $clean;
}
break;
case 'url':
$clean = self::sanitize_url( $value );
if ( $clean ) {
$sanitized[ $key ] = $clean;
}
break;
case 'int':
$sanitized[ $key ] = intval( $value );
break;
default:
$sanitized[ $key ] = sanitize_text_field( $value );
}
}
return $sanitized;
}
/**
* Escape output based on context
*
* @param mixed $value Value to escape
* @param string $context Context (html|attr|url|js)
* @return string
*/
public static function escape_output( $value, $context = 'html' ) {
switch ( $context ) {
case 'attr':
return esc_attr( $value );
case 'url':
return esc_url( $value );
case 'js':
return esc_js( $value );
case 'textarea':
return esc_textarea( $value );
default:
return esc_html( $value );
}
}
/**
* Check if request is AJAX
*
* @return bool
*/
public static function is_ajax_request() {
return defined( 'DOING_AJAX' ) && DOING_AJAX;
}
/**
* Get user IP address
*
* @return string
*/
public static function get_user_ip() {
$ip = '';
if ( ! empty( $_SERVER['HTTP_CLIENT_IP'] ) ) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif ( ! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} elseif ( ! empty( $_SERVER['REMOTE_ADDR'] ) ) {
$ip = $_SERVER['REMOTE_ADDR'];
}
return sanitize_text_field( $ip );
}
/**
* Rate limiting check
*
* @param string $action Action to limit
* @param int $limit Number of attempts allowed
* @param int $window Time window in seconds
* @param string $identifier User identifier (defaults to IP)
* @return bool True if within limits, false if exceeded
*/
public static function check_rate_limit( $action, $limit = 5, $window = 300, $identifier = null ) {
if ( null === $identifier ) {
$identifier = self::get_user_ip();
}
$key = 'hvac_rate_limit_' . md5( $action . $identifier );
$attempts = get_transient( $key );
if ( false === $attempts ) {
set_transient( $key, 1, $window );
return true;
}
if ( $attempts >= $limit ) {
HVAC_Logger::warning( 'Rate limit exceeded', 'Security', [
'action' => $action,
'identifier' => $identifier,
'attempts' => $attempts,
] );
return false;
}
set_transient( $key, $attempts + 1, $window );
return true;
}
}