- Added GitHub spec-kit for development workflow - Standardized file signatures to Descomplicar® format - Updated development configuration 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
751 lines
27 KiB
PHP
751 lines
27 KiB
PHP
/**
|
|
* Descomplicar® Crescimento Digital
|
|
* https://descomplicar.pt
|
|
*/
|
|
|
|
<?php
|
|
/**
|
|
* Admin interface for Care Booking Block plugin
|
|
*
|
|
* @package CareBookingBlock
|
|
*/
|
|
|
|
// Prevent direct access
|
|
if (!defined('ABSPATH')) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Admin interface class
|
|
*/
|
|
class Care_Booking_Admin_Interface
|
|
{
|
|
/**
|
|
* Database handler instance
|
|
*
|
|
* @var Care_Booking_Database_Handler
|
|
*/
|
|
private $db_handler;
|
|
|
|
/**
|
|
* Restriction model instance
|
|
*
|
|
* @var Care_Booking_Restriction_Model
|
|
*/
|
|
private $restriction_model;
|
|
|
|
/**
|
|
* Admin page slug
|
|
*/
|
|
const ADMIN_PAGE_SLUG = 'care-booking-control';
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @param Care_Booking_Database_Handler $db_handler Database handler instance
|
|
*/
|
|
public function __construct($db_handler)
|
|
{
|
|
$this->db_handler = $db_handler;
|
|
$this->restriction_model = new Care_Booking_Restriction_Model();
|
|
|
|
$this->init_hooks();
|
|
}
|
|
|
|
/**
|
|
* Initialize WordPress hooks
|
|
*/
|
|
private function init_hooks()
|
|
{
|
|
// Admin menu
|
|
add_action('admin_menu', [$this, 'add_admin_menu']);
|
|
|
|
// Admin scripts and styles
|
|
add_action('admin_enqueue_scripts', [$this, 'enqueue_admin_assets']);
|
|
|
|
// AJAX handlers
|
|
add_action('wp_ajax_care_booking_get_restrictions', [$this, 'ajax_get_restrictions']);
|
|
add_action('wp_ajax_care_booking_toggle_restriction', [$this, 'ajax_toggle_restriction']);
|
|
add_action('wp_ajax_care_booking_bulk_update', [$this, 'ajax_bulk_update']);
|
|
add_action('wp_ajax_care_booking_get_entities', [$this, 'ajax_get_entities']);
|
|
}
|
|
|
|
/**
|
|
* Add admin menu
|
|
*/
|
|
public function add_admin_menu()
|
|
{
|
|
add_management_page(
|
|
__('Care Booking Control', 'care-booking-block'),
|
|
__('Care Booking Control', 'care-booking-block'),
|
|
'manage_options',
|
|
self::ADMIN_PAGE_SLUG,
|
|
[$this, 'render_admin_page']
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Enqueue admin assets
|
|
*
|
|
* @param string $hook_suffix Current admin page
|
|
*/
|
|
public function enqueue_admin_assets($hook_suffix)
|
|
{
|
|
// Only load on our admin page
|
|
if (strpos($hook_suffix, self::ADMIN_PAGE_SLUG) === false) {
|
|
return;
|
|
}
|
|
|
|
// Enqueue CSS
|
|
wp_enqueue_style(
|
|
'care-booking-admin',
|
|
CARE_BOOKING_BLOCK_PLUGIN_URL . 'admin/css/admin-style.css',
|
|
[],
|
|
CARE_BOOKING_BLOCK_VERSION
|
|
);
|
|
|
|
// Enqueue JavaScript
|
|
wp_enqueue_script(
|
|
'care-booking-admin',
|
|
CARE_BOOKING_BLOCK_PLUGIN_URL . 'admin/js/admin-script.js',
|
|
['jquery'],
|
|
CARE_BOOKING_BLOCK_VERSION,
|
|
true
|
|
);
|
|
|
|
// Localize script
|
|
wp_localize_script('care-booking-admin', 'careBookingAjax', [
|
|
'ajaxurl' => admin_url('admin-ajax.php'),
|
|
'nonce' => wp_create_nonce('care_booking_nonce'),
|
|
'strings' => [
|
|
'loading' => __('Loading...', 'care-booking-block'),
|
|
'error' => __('An error occurred. Please try again.', 'care-booking-block'),
|
|
'confirm_bulk' => __('Are you sure you want to update all selected restrictions?', 'care-booking-block'),
|
|
'success_update' => __('Restriction updated successfully.', 'care-booking-block'),
|
|
'success_bulk' => __('Bulk update completed.', 'care-booking-block')
|
|
]
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Render admin page
|
|
*/
|
|
public function render_admin_page()
|
|
{
|
|
// Check KiviCare availability
|
|
if (!$this->is_kivicare_active()) {
|
|
$this->render_kivicare_warning();
|
|
return;
|
|
}
|
|
|
|
include CARE_BOOKING_BLOCK_PLUGIN_DIR . 'admin/partials/admin-display.php';
|
|
}
|
|
|
|
/**
|
|
* AJAX handler: Get restrictions
|
|
*/
|
|
public function ajax_get_restrictions()
|
|
{
|
|
// SECURITY: Enhanced CSRF protection with additional request validation
|
|
if (!wp_verify_nonce($_POST['nonce'] ?? '', 'care_booking_nonce')) {
|
|
wp_send_json_error(['message' => __('Security check failed', 'care-booking-block')]);
|
|
wp_die(); // Additional security measure
|
|
}
|
|
|
|
// SECURITY: Check if request is actually via AJAX
|
|
if (!wp_doing_ajax()) {
|
|
wp_send_json_error(['message' => __('Invalid request method', 'care-booking-block')]);
|
|
wp_die();
|
|
}
|
|
|
|
// SECURITY: Enhanced capability check with logging
|
|
if (!current_user_can('manage_options')) {
|
|
error_log('Care Booking Block: Unauthorized access attempt from user ID: ' . get_current_user_id());
|
|
wp_send_json_error(['message' => __('Insufficient permissions', 'care-booking-block')]);
|
|
wp_die();
|
|
}
|
|
|
|
// SECURITY: Rate limiting check
|
|
if (!$this->check_rate_limit('get_restrictions')) {
|
|
wp_send_json_error(['message' => __('Too many requests. Please wait.', 'care-booking-block')]);
|
|
wp_die();
|
|
}
|
|
|
|
// SECURITY: Enhanced input sanitization and validation
|
|
$restriction_type = sanitize_text_field($_POST['restriction_type'] ?? 'all');
|
|
$doctor_id = isset($_POST['doctor_id']) ? absint($_POST['doctor_id']) : null;
|
|
|
|
// SECURITY: Validate restriction_type against whitelist
|
|
$allowed_types = ['all', 'doctor', 'service'];
|
|
if (!in_array($restriction_type, $allowed_types, true)) {
|
|
error_log('Care Booking Block: Invalid restriction_type attempted: ' . $restriction_type);
|
|
wp_send_json_error(['message' => __('Invalid restriction type', 'care-booking-block')]);
|
|
wp_die();
|
|
}
|
|
|
|
// SECURITY: Validate doctor_id if provided
|
|
if ($doctor_id !== null && $doctor_id <= 0) {
|
|
wp_send_json_error(['message' => __('Invalid doctor ID', 'care-booking-block')]);
|
|
wp_die();
|
|
}
|
|
|
|
try {
|
|
if ($restriction_type === 'all') {
|
|
$restrictions = $this->restriction_model->get_all();
|
|
} elseif (in_array($restriction_type, ['doctor', 'service'])) {
|
|
$restrictions = $this->restriction_model->get_by_type($restriction_type);
|
|
|
|
// Filter by doctor if specified
|
|
if ($restriction_type === 'service' && $doctor_id) {
|
|
$restrictions = array_filter($restrictions, function($r) use ($doctor_id) {
|
|
return $r->doctor_id == $doctor_id;
|
|
});
|
|
}
|
|
} else {
|
|
wp_send_json_error(['message' => __('Invalid parameters', 'care-booking-block')]);
|
|
}
|
|
|
|
// SECURITY: Convert to array format with output escaping
|
|
$formatted_restrictions = [];
|
|
foreach ($restrictions as $restriction) {
|
|
$formatted_restrictions[] = [
|
|
'id' => (int) $restriction->id,
|
|
'restriction_type' => esc_html($restriction->restriction_type),
|
|
'target_id' => (int) $restriction->target_id,
|
|
'doctor_id' => $restriction->doctor_id ? (int) $restriction->doctor_id : null,
|
|
'is_blocked' => (bool) $restriction->is_blocked,
|
|
'created_at' => esc_html($restriction->created_at),
|
|
'updated_at' => esc_html($restriction->updated_at)
|
|
];
|
|
}
|
|
|
|
wp_send_json_success([
|
|
'restrictions' => $formatted_restrictions,
|
|
'total' => count($formatted_restrictions)
|
|
]);
|
|
|
|
} catch (Exception $e) {
|
|
wp_send_json_error(['message' => __('Database error occurred', 'care-booking-block')]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* AJAX handler: Toggle restriction
|
|
*/
|
|
public function ajax_toggle_restriction()
|
|
{
|
|
// SECURITY: Enhanced CSRF protection
|
|
if (!wp_verify_nonce($_POST['nonce'] ?? '', 'care_booking_nonce')) {
|
|
wp_send_json_error(['message' => __('Security check failed', 'care-booking-block')]);
|
|
wp_die();
|
|
}
|
|
|
|
// SECURITY: AJAX request validation
|
|
if (!wp_doing_ajax()) {
|
|
wp_send_json_error(['message' => __('Invalid request method', 'care-booking-block')]);
|
|
wp_die();
|
|
}
|
|
|
|
// SECURITY: Enhanced capability check with logging
|
|
if (!current_user_can('manage_options')) {
|
|
error_log('Care Booking Block: Unauthorized toggle attempt from user ID: ' . get_current_user_id());
|
|
wp_send_json_error(['message' => __('Insufficient permissions', 'care-booking-block')]);
|
|
wp_die();
|
|
}
|
|
|
|
// SECURITY: Rate limiting
|
|
if (!$this->check_rate_limit('toggle_restriction')) {
|
|
wp_send_json_error(['message' => __('Too many requests. Please wait.', 'care-booking-block')]);
|
|
wp_die();
|
|
}
|
|
|
|
// SECURITY: Enhanced parameter validation and sanitization
|
|
$restriction_type = sanitize_text_field($_POST['restriction_type'] ?? '');
|
|
$target_id = absint($_POST['target_id'] ?? 0);
|
|
$doctor_id = isset($_POST['doctor_id']) ? absint($_POST['doctor_id']) : null;
|
|
$is_blocked = isset($_POST['is_blocked']) ? (bool) $_POST['is_blocked'] : true;
|
|
|
|
// SECURITY: Validate required parameters
|
|
if (!$restriction_type || !$target_id) {
|
|
error_log('Care Booking Block: Missing parameters in toggle_restriction');
|
|
wp_send_json_error(['message' => __('Missing required parameters', 'care-booking-block')]);
|
|
wp_die();
|
|
}
|
|
|
|
// SECURITY: Whitelist validation for restriction_type
|
|
$allowed_types = ['doctor', 'service'];
|
|
if (!in_array($restriction_type, $allowed_types, true)) {
|
|
error_log('Care Booking Block: Invalid restriction_type in toggle: ' . $restriction_type);
|
|
wp_send_json_error(['message' => __('Invalid restriction type', 'care-booking-block')]);
|
|
wp_die();
|
|
}
|
|
|
|
// SECURITY: Validate target_id range
|
|
if ($target_id <= 0 || $target_id > PHP_INT_MAX) {
|
|
wp_send_json_error(['message' => __('Invalid target ID', 'care-booking-block')]);
|
|
wp_die();
|
|
}
|
|
|
|
// SECURITY: Service restriction validation
|
|
if ($restriction_type === 'service' && (!$doctor_id || $doctor_id <= 0)) {
|
|
wp_send_json_error(['message' => __('Valid doctor_id required for service restrictions', 'care-booking-block')]);
|
|
wp_die();
|
|
}
|
|
|
|
try {
|
|
// Validate target exists in KiviCare
|
|
if (!$this->validate_kivicare_target($restriction_type, $target_id, $doctor_id)) {
|
|
wp_send_json_error(['message' => __('Target not found', 'care-booking-block')]);
|
|
}
|
|
|
|
// Toggle restriction
|
|
$result = $this->restriction_model->toggle($restriction_type, $target_id, $doctor_id, $is_blocked);
|
|
|
|
if ($result) {
|
|
// Get updated/created restriction
|
|
$restriction = $this->restriction_model->find_existing($restriction_type, $target_id, $doctor_id);
|
|
|
|
if ($restriction) {
|
|
wp_send_json_success([
|
|
'message' => __('Restriction updated successfully', 'care-booking-block'),
|
|
'restriction' => [
|
|
'id' => (int) $restriction->id,
|
|
'restriction_type' => esc_html($restriction->restriction_type),
|
|
'target_id' => (int) $restriction->target_id,
|
|
'doctor_id' => $restriction->doctor_id ? (int) $restriction->doctor_id : null,
|
|
'is_blocked' => (bool) $restriction->is_blocked,
|
|
'updated_at' => esc_html($restriction->updated_at)
|
|
]
|
|
]);
|
|
}
|
|
}
|
|
|
|
wp_send_json_error(['message' => __('Failed to update restriction', 'care-booking-block')]);
|
|
|
|
} catch (Exception $e) {
|
|
wp_send_json_error(['message' => __('Database error', 'care-booking-block')]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* AJAX handler: Bulk update
|
|
*/
|
|
public function ajax_bulk_update()
|
|
{
|
|
// SECURITY: Enhanced CSRF protection
|
|
if (!wp_verify_nonce($_POST['nonce'] ?? '', 'care_booking_nonce')) {
|
|
wp_send_json_error(['message' => __('Security check failed', 'care-booking-block')]);
|
|
wp_die();
|
|
}
|
|
|
|
// SECURITY: AJAX request validation
|
|
if (!wp_doing_ajax()) {
|
|
wp_send_json_error(['message' => __('Invalid request method', 'care-booking-block')]);
|
|
wp_die();
|
|
}
|
|
|
|
// SECURITY: Enhanced capability check with logging
|
|
if (!current_user_can('manage_options')) {
|
|
error_log('Care Booking Block: Unauthorized bulk update attempt from user ID: ' . get_current_user_id());
|
|
wp_send_json_error(['message' => __('Insufficient permissions', 'care-booking-block')]);
|
|
wp_die();
|
|
}
|
|
|
|
// SECURITY: Strict rate limiting for bulk operations
|
|
if (!$this->check_rate_limit('bulk_update', 5)) { // More restrictive for bulk operations
|
|
wp_send_json_error(['message' => __('Too many bulk requests. Please wait.', 'care-booking-block')]);
|
|
wp_die();
|
|
}
|
|
|
|
// SECURITY: Enhanced parameter validation
|
|
if (!isset($_POST['restrictions'])) {
|
|
error_log('Care Booking Block: Missing restrictions parameter in bulk update');
|
|
wp_send_json_error(['message' => __('Missing restrictions parameter', 'care-booking-block')]);
|
|
wp_die();
|
|
}
|
|
|
|
$restrictions = $_POST['restrictions'];
|
|
|
|
// SECURITY: Type validation
|
|
if (!is_array($restrictions)) {
|
|
error_log('Care Booking Block: Invalid restrictions format in bulk update');
|
|
wp_send_json_error(['message' => __('Invalid restrictions format', 'care-booking-block')]);
|
|
wp_die();
|
|
}
|
|
|
|
// SECURITY: Strict bulk size limits for security
|
|
if (count($restrictions) > 50) { // Reduced from 100 for security
|
|
error_log('Care Booking Block: Bulk size limit exceeded: ' . count($restrictions));
|
|
wp_send_json_error(['message' => __('Bulk size limit exceeded (max 50)', 'care-booking-block')]);
|
|
wp_die();
|
|
}
|
|
|
|
// SECURITY: Validate each restriction item
|
|
foreach ($restrictions as $index => $restriction) {
|
|
if (!is_array($restriction)) {
|
|
error_log('Care Booking Block: Invalid restriction item at index: ' . $index);
|
|
wp_send_json_error(['message' => __('Invalid restriction data format', 'care-booking-block')]);
|
|
wp_die();
|
|
}
|
|
|
|
// Sanitize each restriction
|
|
$restrictions[$index] = [
|
|
'restriction_type' => sanitize_text_field($restriction['restriction_type'] ?? ''),
|
|
'target_id' => absint($restriction['target_id'] ?? 0),
|
|
'doctor_id' => isset($restriction['doctor_id']) ? absint($restriction['doctor_id']) : null,
|
|
'is_blocked' => isset($restriction['is_blocked']) ? (bool) $restriction['is_blocked'] : true
|
|
];
|
|
}
|
|
|
|
try {
|
|
$result = $this->restriction_model->bulk_toggle($restrictions);
|
|
|
|
if (empty($result['errors'])) {
|
|
wp_send_json_success([
|
|
'message' => __('Bulk update completed', 'care-booking-block'),
|
|
'updated' => $result['updated'],
|
|
'errors' => []
|
|
]);
|
|
} else {
|
|
// Partial failure
|
|
wp_send_json_error([
|
|
'message' => __('Partial failure in bulk update', 'care-booking-block'),
|
|
'updated' => $result['updated'],
|
|
'errors' => $result['errors']
|
|
]);
|
|
}
|
|
|
|
} catch (Exception $e) {
|
|
wp_send_json_error(['message' => __('Bulk update failed', 'care-booking-block')]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* AJAX handler: Get KiviCare entities
|
|
*/
|
|
public function ajax_get_entities()
|
|
{
|
|
// SECURITY: Enhanced CSRF protection
|
|
if (!wp_verify_nonce($_POST['nonce'] ?? '', 'care_booking_nonce')) {
|
|
wp_send_json_error(['message' => __('Security check failed', 'care-booking-block')]);
|
|
wp_die();
|
|
}
|
|
|
|
// SECURITY: AJAX request validation
|
|
if (!wp_doing_ajax()) {
|
|
wp_send_json_error(['message' => __('Invalid request method', 'care-booking-block')]);
|
|
wp_die();
|
|
}
|
|
|
|
// SECURITY: Enhanced capability check with logging
|
|
if (!current_user_can('manage_options')) {
|
|
error_log('Care Booking Block: Unauthorized entities access from user ID: ' . get_current_user_id());
|
|
wp_send_json_error(['message' => __('Insufficient permissions', 'care-booking-block')]);
|
|
wp_die();
|
|
}
|
|
|
|
// SECURITY: Rate limiting
|
|
if (!$this->check_rate_limit('get_entities')) {
|
|
wp_send_json_error(['message' => __('Too many requests. Please wait.', 'care-booking-block')]);
|
|
wp_die();
|
|
}
|
|
|
|
// SECURITY: Enhanced input validation
|
|
$entity_type = sanitize_text_field($_POST['entity_type'] ?? '');
|
|
$doctor_id = isset($_POST['doctor_id']) ? absint($_POST['doctor_id']) : null;
|
|
|
|
if (!$entity_type) {
|
|
error_log('Care Booking Block: Missing entity_type parameter');
|
|
wp_send_json_error(['message' => __('Missing entity_type parameter', 'care-booking-block')]);
|
|
wp_die();
|
|
}
|
|
|
|
// SECURITY: Whitelist validation for entity_type
|
|
$allowed_entity_types = ['doctors', 'services'];
|
|
if (!in_array($entity_type, $allowed_entity_types, true)) {
|
|
error_log('Care Booking Block: Invalid entity type: ' . $entity_type);
|
|
wp_send_json_error(['message' => __('Invalid entity type', 'care-booking-block')]);
|
|
wp_die();
|
|
}
|
|
|
|
// SECURITY: Validate doctor_id if provided
|
|
if ($doctor_id !== null && $doctor_id <= 0) {
|
|
wp_send_json_error(['message' => __('Invalid doctor ID', 'care-booking-block')]);
|
|
wp_die();
|
|
}
|
|
|
|
// Check KiviCare availability
|
|
if (!$this->is_kivicare_active()) {
|
|
wp_send_json_error(['message' => __('KiviCare plugin not available', 'care-booking-block')]);
|
|
}
|
|
|
|
try {
|
|
if ($entity_type === 'doctors') {
|
|
$entities = $this->get_kivicare_doctors();
|
|
} else {
|
|
$entities = $this->get_kivicare_services($doctor_id);
|
|
}
|
|
|
|
wp_send_json_success([
|
|
'entities' => $entities,
|
|
'total' => count($entities)
|
|
]);
|
|
|
|
} catch (Exception $e) {
|
|
wp_send_json_error(['message' => __('Database error occurred', 'care-booking-block')]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if KiviCare plugin is active
|
|
*
|
|
* @return bool True if KiviCare is active, false otherwise
|
|
*/
|
|
private function is_kivicare_active()
|
|
{
|
|
// Check if KiviCare plugin is active
|
|
if (!function_exists('is_plugin_active')) {
|
|
include_once(ABSPATH . 'wp-admin/includes/plugin.php');
|
|
}
|
|
|
|
return is_plugin_active('kivicare/kivicare.php') ||
|
|
is_plugin_active('kivicare-clinic-management-system/kivicare.php');
|
|
}
|
|
|
|
/**
|
|
* Render KiviCare warning
|
|
*/
|
|
private function render_kivicare_warning()
|
|
{
|
|
?>
|
|
<div class="wrap">
|
|
<h1><?php esc_html_e('Care Booking Control', 'care-booking-block'); ?></h1>
|
|
<div class="notice notice-error">
|
|
<p>
|
|
<?php esc_html_e('KiviCare plugin is required for Care Booking Control to work. Please install and activate KiviCare.', 'care-booking-block'); ?>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<?php
|
|
}
|
|
|
|
/**
|
|
* Get KiviCare doctors with restriction status
|
|
*
|
|
* @return array Array of doctors with restriction status
|
|
*/
|
|
private function get_kivicare_doctors()
|
|
{
|
|
global $wpdb;
|
|
|
|
// Get doctors from KiviCare (mock implementation)
|
|
// In real implementation, this would query KiviCare tables
|
|
$doctors = [];
|
|
|
|
// Get blocked doctors for status
|
|
$blocked_doctors = $this->restriction_model->get_blocked_doctors();
|
|
|
|
// SECURITY: Mock doctors for testing with output escaping
|
|
for ($i = 1; $i <= 10; $i++) {
|
|
$doctors[] = [
|
|
'id' => $i,
|
|
'name' => esc_html("Dr. Test Doctor $i"),
|
|
'email' => esc_html("doctor$i@clinic.com"),
|
|
'is_blocked' => in_array($i, $blocked_doctors)
|
|
];
|
|
}
|
|
|
|
return $doctors;
|
|
}
|
|
|
|
/**
|
|
* Get KiviCare services with restriction status
|
|
*
|
|
* @param int $doctor_id Optional doctor ID to filter services
|
|
* @return array Array of services with restriction status
|
|
*/
|
|
private function get_kivicare_services($doctor_id = null)
|
|
{
|
|
global $wpdb;
|
|
|
|
// Get services from KiviCare (mock implementation)
|
|
$services = [];
|
|
|
|
if ($doctor_id) {
|
|
// Get blocked services for this doctor
|
|
$blocked_services = $this->restriction_model->get_blocked_services($doctor_id);
|
|
|
|
// SECURITY: Mock services for testing with output escaping
|
|
for ($i = 1; $i <= 5; $i++) {
|
|
$services[] = [
|
|
'id' => $i,
|
|
'name' => esc_html("Service $i"),
|
|
'doctor_id' => $doctor_id,
|
|
'is_blocked' => in_array($i, $blocked_services)
|
|
];
|
|
}
|
|
} else {
|
|
// SECURITY: Return all services with output escaping
|
|
for ($i = 1; $i <= 20; $i++) {
|
|
$services[] = [
|
|
'id' => $i,
|
|
'name' => esc_html("Service $i"),
|
|
'doctor_id' => (($i - 1) % 10) + 1,
|
|
'is_blocked' => false
|
|
];
|
|
}
|
|
}
|
|
|
|
return $services;
|
|
}
|
|
|
|
/**
|
|
* Validate KiviCare target exists
|
|
*
|
|
* @param string $type Target type
|
|
* @param int $target_id Target ID
|
|
* @param int $doctor_id Doctor ID (for services)
|
|
* @return bool True if target exists, false otherwise
|
|
*/
|
|
private function validate_kivicare_target($type, $target_id, $doctor_id = null)
|
|
{
|
|
// SECURITY: Enhanced target validation with logging
|
|
if (!in_array($type, ['doctor', 'service'], true)) {
|
|
error_log('Care Booking Block: Invalid target type in validation: ' . $type);
|
|
return false;
|
|
}
|
|
|
|
if ($target_id <= 0) {
|
|
error_log('Care Booking Block: Invalid target_id in validation: ' . $target_id);
|
|
return false;
|
|
}
|
|
|
|
// Mock validation - always return true for testing
|
|
// In real implementation, this would check KiviCare tables with prepared statements
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* SECURITY: Rate limiting mechanism
|
|
*
|
|
* @param string $action Action being performed
|
|
* @param int $max_requests Maximum requests allowed
|
|
* @param int $time_window Time window in seconds (default: 60)
|
|
* @return bool True if within limits, false if rate limited
|
|
*/
|
|
private function check_rate_limit($action, $max_requests = 30, $time_window = 60)
|
|
{
|
|
$user_id = get_current_user_id();
|
|
$transient_key = 'care_booking_rate_limit_' . $action . '_' . $user_id;
|
|
|
|
$requests = get_transient($transient_key);
|
|
|
|
if ($requests === false) {
|
|
// First request in time window
|
|
set_transient($transient_key, 1, $time_window);
|
|
return true;
|
|
}
|
|
|
|
if ($requests >= $max_requests) {
|
|
error_log("Care Booking Block: Rate limit exceeded for action '$action' by user $user_id");
|
|
return false;
|
|
}
|
|
|
|
// Increment counter
|
|
set_transient($transient_key, $requests + 1, $time_window);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* SECURITY: Sanitize and validate admin page content
|
|
*
|
|
* @param mixed $data Data to sanitize
|
|
* @return mixed Sanitized data
|
|
*/
|
|
private function sanitize_admin_data($data)
|
|
{
|
|
if (is_string($data)) {
|
|
return sanitize_text_field($data);
|
|
}
|
|
|
|
if (is_array($data)) {
|
|
return array_map([$this, 'sanitize_admin_data'], $data);
|
|
}
|
|
|
|
if (is_int($data)) {
|
|
return absint($data);
|
|
}
|
|
|
|
if (is_bool($data)) {
|
|
return (bool) $data;
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* SECURITY: Log security events
|
|
*
|
|
* @param string $event Event description
|
|
* @param array $context Event context
|
|
*/
|
|
private function log_security_event($event, $context = [])
|
|
{
|
|
$log_entry = sprintf(
|
|
'Care Booking Block Security: %s | User ID: %d | IP: %s | Context: %s',
|
|
$event,
|
|
get_current_user_id(),
|
|
$_SERVER['REMOTE_ADDR'] ?? 'unknown',
|
|
json_encode($context)
|
|
);
|
|
|
|
error_log($log_entry);
|
|
|
|
// Trigger action for external security monitoring
|
|
do_action('care_booking_security_event', $event, $context);
|
|
}
|
|
|
|
/**
|
|
* SECURITY: Validate WordPress environment
|
|
*
|
|
* @return bool True if environment is secure
|
|
*/
|
|
private function validate_environment()
|
|
{
|
|
// Check if we're in WordPress admin
|
|
if (!is_admin()) {
|
|
$this->log_security_event('Invalid environment: not admin area');
|
|
return false;
|
|
}
|
|
|
|
// Check if user is logged in
|
|
if (!is_user_logged_in()) {
|
|
$this->log_security_event('Invalid environment: user not logged in');
|
|
return false;
|
|
}
|
|
|
|
// Check for multisite restrictions
|
|
if (is_multisite() && !is_super_admin()) {
|
|
$this->log_security_event('Invalid environment: multisite without super admin');
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* SECURITY: Enhanced error handling with security logging
|
|
*
|
|
* @param string $error_message Error message
|
|
* @param array $context Error context
|
|
*/
|
|
private function handle_security_error($error_message, $context = [])
|
|
{
|
|
$this->log_security_event('Security Error: ' . $error_message, $context);
|
|
|
|
// Don't expose sensitive information in error messages
|
|
$safe_message = __('A security error occurred. Please try again.', 'care-booking-block');
|
|
wp_send_json_error(['message' => $safe_message]);
|
|
wp_die();
|
|
}
|
|
}
|