upskill-event-manager/includes/certificates/class-certificate-security.php
bengizmo 37f4180e1c feat: Add massive missing plugin infrastructure to repository
🚨 CRITICAL: Fixed deployment blockers by adding missing core directories:

**Community System (CRITICAL)**
- includes/community/ - Login_Handler and all community classes
- templates/community/ - Community login forms

**Certificate System (CRITICAL)**
- includes/certificates/ - 8+ certificate classes and handlers
- templates/certificates/ - Certificate reports and generation templates

**Core Individual Classes (CRITICAL)**
- includes/class-hvac-event-summary.php
- includes/class-hvac-trainer-profile-manager.php
- includes/class-hvac-master-dashboard-data.php
- Plus 40+ other individual HVAC classes

**Major Feature Systems (HIGH)**
- includes/database/ - Training leads database tables
- includes/find-trainer/ - Find trainer directory and MapGeo integration
- includes/google-sheets/ - Google Sheets integration system
- includes/zoho/ - Complete Zoho CRM integration
- includes/communication/ - Communication templates system

**Template Infrastructure**
- templates/attendee/, templates/email-attendees/
- templates/event-summary/, templates/status/
- templates/template-parts/ - Shared template components

**Impact:**
- 70+ files added covering 10+ missing directories
- Resolves ALL deployment blockers and feature breakdowns
- Plugin activation should now work correctly
- Multi-machine deployment fully supported

🔧 Generated with Claude Code

Co-Authored-By: Ben Reed <ben@tealmaker.com>
2025-08-11 13:30:11 -03:00

322 lines
No EOL
10 KiB
PHP

<?php
/**
* Certificate Security Class
*
* Handles security aspects of certificate generation and storage.
*
* @package HVAC_Community_Events
* @subpackage Certificates
*/
// Exit if accessed directly
if (!defined('ABSPATH')) {
exit;
}
/**
* Certificate Security class.
*
* Provides security functions for certificates.
*
* @since 1.0.0
*/
class HVAC_Certificate_Security {
/**
* The single instance of the class.
*
* @var HVAC_Certificate_Security
*/
protected static $_instance = null;
/**
* Main HVAC_Certificate_Security Instance.
*
* Ensures only one instance of HVAC_Certificate_Security is loaded or can be loaded.
*
* @return HVAC_Certificate_Security - Main instance.
*/
public static function instance() {
if (is_null(self::$_instance)) {
self::$_instance = new self();
}
return self::$_instance;
}
/**
* Constructor.
*/
public function __construct() {
// Initialize hooks
add_action('init', array($this, 'init_secure_download'), 1); // Early priority
// Add admin action to manually flush rewrite rules
add_action('admin_init', array($this, 'maybe_flush_rewrite_rules'));
// Alternative URL handling without rewrite rules
add_action('parse_request', array($this, 'parse_certificate_request'), 1);
}
/**
* Initialize the secure download endpoint.
*/
public function init_secure_download() {
// Add rewrite rule for certificate downloads
add_rewrite_rule(
'hvac-certificate/([^/]+)/?$',
'index.php?certificate_token=$matches[1]',
'top'
);
// Add query var
add_filter('query_vars', array($this, 'add_query_vars'));
// Handle certificate download requests
add_action('template_redirect', array($this, 'handle_certificate_download'));
}
/**
* Add custom query variables.
*
* @param array $vars Query variables.
*
* @return array Modified query variables.
*/
public function add_query_vars($vars) {
$vars[] = 'certificate_token';
return $vars;
}
/**
* Handle certificate download requests.
*/
public function handle_certificate_download() {
$certificate_token = get_query_var('certificate_token');
if (empty($certificate_token)) {
return;
}
// Validate the token
$certificate_data = $this->validate_download_token($certificate_token);
if (!$certificate_data) {
wp_die(__('Invalid or expired certificate download link.', 'hvac-community-events'));
}
// Get file path
$file_path = $this->get_certificate_file_path($certificate_data);
if (!$file_path || !file_exists($file_path)) {
wp_die(__('Certificate file not found.', 'hvac-community-events'));
}
// Serve the file
$this->serve_certificate_file($file_path, $certificate_data);
exit;
}
/**
* Parse certificate requests directly without relying on rewrite rules.
* This is a fallback method that works even if rewrite rules fail.
*/
public function parse_certificate_request($wp) {
// Only process if we haven't already handled via template_redirect
if (did_action('template_redirect')) {
return;
}
$request_uri = $_SERVER['REQUEST_URI'];
// Only match exact certificate download URLs - be very specific
if (preg_match('#^/hvac-certificate/([a-zA-Z0-9]{32})/?$#', $request_uri, $matches)) {
$certificate_token = $matches[1];
// Validate the token exists (don't delete it yet - let the normal handler do that)
$certificate_data = get_transient('hvac_certificate_token_' . $certificate_token);
if (!$certificate_data) {
// Return 404 instead of wp_die to avoid interfering with other pages
status_header(404);
return;
}
// If we have valid certificate data, let the normal template_redirect handler take over
// Set the query var so the normal handler can pick it up
set_query_var('certificate_token', $certificate_token);
return;
}
}
/**
* Validate a certificate download token.
*
* @param string $token The token to validate.
*
* @return array|false Certificate data if valid, false otherwise.
*/
protected function validate_download_token($token) {
// Check if token exists in transients
$certificate_data = get_transient('hvac_certificate_token_' . $token);
if (!$certificate_data) {
return false;
}
// Delete the transient to prevent reuse
delete_transient('hvac_certificate_token_' . $token);
return $certificate_data;
}
/**
* Get the full file path for a certificate.
*
* @param array $certificate_data Certificate data.
*
* @return string|false Full file path or false if not found.
*/
protected function get_certificate_file_path($certificate_data) {
if (empty($certificate_data['file_path'])) {
return false;
}
$upload_dir = wp_upload_dir();
$file_path = $upload_dir['basedir'] . '/' . $certificate_data['file_path'];
if (file_exists($file_path)) {
return $file_path;
}
return false;
}
/**
* Serve a certificate file for download.
*
* @param string $file_path Full path to certificate file.
* @param array $certificate_data Certificate data.
*/
protected function serve_certificate_file($file_path, $certificate_data) {
// Get file information
$file_name = basename($file_path);
$file_size = filesize($file_path);
$file_ext = pathinfo($file_path, PATHINFO_EXTENSION);
// Set download filename
$event_name = sanitize_title($certificate_data['event_name'] ?? 'event');
$attendee_name = sanitize_title($certificate_data['attendee_name'] ?? 'attendee');
$download_filename = "certificate-{$event_name}-{$attendee_name}.{$file_ext}";
// Send headers
nocache_headers();
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="' . $download_filename . '"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . $file_size);
// Disable output buffering
if (ob_get_level()) {
ob_end_clean();
}
// Output the file
readfile($file_path);
}
/**
* Generate a secure download token for a certificate.
*
* @param int $certificate_id The certificate ID.
* @param array $certificate_data Additional certificate data.
* @param int $expiry Token expiry time in seconds (default 1 hour).
*
* @return string|false The download URL or false on failure.
*/
public function generate_download_token($certificate_id, $certificate_data, $expiry = 3600) {
if (!$certificate_id || empty($certificate_data['file_path'])) {
return false;
}
// Generate a unique token
$token = wp_generate_password(32, false);
// Store in transient
set_transient('hvac_certificate_token_' . $token, $certificate_data, $expiry);
// Generate URL
return home_url('hvac-certificate/' . $token);
}
/**
* Create a secure storage directory for certificates.
*
* @param string $dir_path The directory path to secure.
*
* @return bool True if successful, false otherwise.
*/
public function create_secure_directory($dir_path) {
// Check if directory exists
if (!file_exists($dir_path)) {
// Create directory
if (!wp_mkdir_p($dir_path)) {
return false;
}
}
// Create/update .htaccess file
$htaccess_content = "# Prevent direct access to files\n";
$htaccess_content .= "<Files ~ \".*\">\n";
$htaccess_content .= " Order Allow,Deny\n";
$htaccess_content .= " Deny from all\n";
$htaccess_content .= "</Files>\n";
$htaccess_content .= "# Prevent directory listing\n";
$htaccess_content .= "Options -Indexes\n";
$htaccess_file = $dir_path . '/.htaccess';
if (!@file_put_contents($htaccess_file, $htaccess_content)) {
return false;
}
// Create empty index.php
$index_content = "<?php\n// Silence is golden.";
$index_file = $dir_path . '/index.php';
if (!@file_put_contents($index_file, $index_content)) {
return false;
}
return true;
}
/**
* Check if we need to flush rewrite rules.
* This provides a way to manually trigger a flush via URL parameter.
*/
public function maybe_flush_rewrite_rules() {
// Only allow admins to flush rewrite rules
if (!current_user_can('manage_options')) {
return;
}
// Check for flush parameter
if (isset($_GET['hvac_flush_rewrite_rules']) && $_GET['hvac_flush_rewrite_rules'] === '1') {
// Re-register our rewrite rule
$this->init_secure_download();
// Flush the rules
flush_rewrite_rules();
// Log the action
if (class_exists('HVAC_Logger')) {
HVAC_Logger::info('Rewrite rules flushed manually via admin parameter', 'Certificate Security');
}
// Redirect to remove the parameter
wp_redirect(remove_query_arg('hvac_flush_rewrite_rules'));
exit;
}
}
}