' .
__('Admin Notes Widget By Website14', 'admin-notes-widget-by-website14'),
array($this, 'dashboard_widget_content')
);
}
/**
* Renders the dashboard widget content HTML
*
* Outputs the complete HTML structure for the notes widget, including:
* - Notes list container for displaying existing notes
* - Rich text editor with formatting toolbar
* - Form controls for note creation and management
* - Modal for sending notes to other administrators
* - Support section with links to WordPress.org support
*
* @since 1.0.0
* @access public
*
* @uses esc_attr_e() WordPress function for internationalized and escaped attributes
* @uses esc_html_e() WordPress function for internationalized and escaped HTML
*
* @return void
*/
public function dashboard_widget_content() {
?>
esc_url(admin_url('admin-ajax.php')),
'nonce' => wp_create_nonce('qanw_nonce'),
'strings' => array(
'confirm_delete' => esc_html__('Are you sure you want to delete this note?', 'admin-notes-widget-by-website14'),
'note_added' => esc_html__('Note added successfully!', 'admin-notes-widget-by-website14'),
'note_deleted' => esc_html__('Note deleted successfully!', 'admin-notes-widget-by-website14'),
'error' => esc_html__('An error occurred. Please try again.', 'admin-notes-widget-by-website14'),
'please_enter_note' => esc_html__('Please enter a note.', 'admin-notes-widget-by-website14'),
'enter_url' => esc_html__('Enter URL:', 'admin-notes-widget-by-website14'),
'please_enter_note_before_sending' => esc_html__('Please enter a note before sending.', 'admin-notes-widget-by-website14'),
'please_select_admin_user' => esc_html__('Please select at least one admin user.', 'admin-notes-widget-by-website14'),
'security_check_failed' => esc_html__('Security check failed. Please refresh the page and try again.', 'admin-notes-widget-by-website14'),
'session_expired' => esc_html__('Session expired. Please log in again.', 'admin-notes-widget-by-website14'),
'too_many_requests' => esc_html__('Too many requests. Please wait a moment before trying again.', 'admin-notes-widget-by-website14'),
'authentication_required' => esc_html__('Authentication required.', 'admin-notes-widget-by-website14'),
'list_item' => esc_html__('List item', 'admin-notes-widget-by-website14'),
'link_text' => esc_html__('link', 'admin-notes-widget-by-website14'),
'bold_text' => esc_html__('bold', 'admin-notes-widget-by-website14'),
'italic_text' => esc_html__('italic', 'admin-notes-widget-by-website14'),
'underline_text' => esc_html__('underline', 'admin-notes-widget-by-website14')
)
));
}
/**
* Performs comprehensive security validation for AJAX requests
*
* Implements a multi-layered security approach including:
* - User authentication verification
* - Nonce validation to prevent CSRF attacks
* - Session validation to prevent session hijacking
* - Rate limiting to prevent brute force attacks
*
* @since 1.0.0
* @access private
*
* @param string $action The nonce action name (default: 'qanw_nonce')
*
* @uses is_user_logged_in() WordPress function to check user authentication
* @uses check_ajax_referer() WordPress function to verify nonce
* @uses wp_verify_auth_cookie() WordPress function to validate session
* @uses get_current_user_id() WordPress function to get current user ID
* @uses get_transient() WordPress function to get rate limit data
* @uses set_transient() WordPress function to set rate limit data
* @uses wp_send_json_error() WordPress function to send error response
* @uses esc_html__() WordPress function for internationalized error messages
*
* @return bool|void Returns true on success, sends JSON error response on failure
*
* @throws wp_send_json_error() Sends HTTP 401 for authentication failures
* @throws wp_send_json_error() Sends HTTP 403 for security check failures
* @throws wp_send_json_error() Sends HTTP 429 for rate limit violations
*/
private function enhanced_security_check($action = 'qanw_nonce') {
// Check if user is logged in
if (!is_user_logged_in()) {
wp_send_json_error(esc_html__('Error: Authentication required. You must be logged in to perform this action. Please log in and try again.', 'admin-notes-widget-by-website14'), 401);
}
// Check nonce with proper error handling
if (!check_ajax_referer($action, 'nonce', false)) {
wp_send_json_error(esc_html__('Error: Security check failed. This usually happens when the page has been open for too long. Please refresh the page and try again.', 'admin-notes-widget-by-website14'), 403);
}
// Check if user session is still valid (reliable method for all contexts)
if (!wp_get_current_user() || !wp_get_current_user()->exists()) {
wp_send_json_error(esc_html__('Error: Session expired. Your login session has timed out. Please log in again to continue.', 'admin-notes-widget-by-website14'), 401);
}
// Rate limiting check
$user_id = get_current_user_id();
$rate_limit_key = 'qanw_rate_limit_' . $user_id;
$rate_limit = get_transient($rate_limit_key);
if ($rate_limit && $rate_limit > 10) { // Max 10 requests per minute
$remaining_time = 60 - (time() - get_option('_transient_timeout_' . $rate_limit_key, 0));
wp_send_json_error(esc_html(sprintf(__('Error: Rate limit exceeded. You have made too many requests. Please wait %d seconds before trying again.', 'admin-notes-widget-by-website14'), $remaining_time)), 429);
}
// Update rate limit
if ($rate_limit) {
set_transient($rate_limit_key, $rate_limit + 1, 60);
} else {
set_transient($rate_limit_key, 1, 60);
}
return true;
}
/**
* Generates a new security nonce for continued AJAX operations
*
* Creates a fresh nonce after successful operations to maintain security
* and prevent nonce reuse attacks. This is called after each successful
* AJAX request to ensure continued security.
*
* @since 1.0.0
* @access private
*
* @uses wp_create_nonce() WordPress function to create security nonce
*
* @return string The newly generated nonce string
*/
private function refresh_nonce() {
return wp_create_nonce('qanw_nonce');
}
/**
* Validates and sanitizes note color input
*
* Ensures that only predefined, safe color values are accepted.
* This prevents XSS attacks and ensures consistent styling across the plugin.
*
* @since 1.0.0
* @access private
*
* @param string $color The color value to validate
*
* @uses sanitize_text_field() WordPress function to sanitize input
*
* @return string The validated and sanitized color value, or 'yellow' as default
*/
private function validate_note_color($color) {
$allowed_colors = array('yellow', 'blue', 'green', 'red');
$sanitized_color = sanitize_text_field($color);
if (!in_array($sanitized_color, $allowed_colors)) {
return 'yellow'; // Default fallback
}
return $sanitized_color;
}
/**
* Handles AJAX request to save a new note
*
* Processes note creation requests with comprehensive security measures:
* - Enhanced security validation (authentication, nonce, rate limiting)
* - User capability verification
* - HTML content sanitization and validation
* - XSS protection through content filtering
* - Input length validation
* - Color validation and sanitization
*
* @since 1.0.0
* @access public
*
* @uses enhanced_security_check() Internal method for security validation
* @uses current_user_can() WordPress function to check user capabilities
* @uses wp_kses() WordPress function to sanitize HTML content
* @uses wp_die() WordPress function to terminate execution on permission failure
* @uses validate_note_color() Internal method to validate note color
* @uses get_notes_data() Internal method to retrieve existing notes
* @uses save_notes_data() Internal method to save notes
* @uses wp_send_json_success() WordPress function to send success response
* @uses wp_send_json_error() WordPress function to send error response
* @uses esc_html__() WordPress function for internationalized messages
* @uses refresh_nonce() Internal method to generate new nonce
*
* @return void Sends JSON response via wp_send_json_success() or wp_send_json_error()
*
* @throws wp_die() Terminates execution if user lacks required capabilities
* @throws wp_send_json_error() Sends error response for validation failures
*/
public function save_note() {
// Enhanced security check
$this->enhanced_security_check();
if (!current_user_can('read')) {
wp_die(esc_html__('Permission denied: You need at least "read" capability to create notes. Please contact your administrator if you believe this is an error.', 'admin-notes-widget-by-website14'));
}
// Check if note text was provided
if (!isset($_POST['note_text']) || empty($_POST['note_text'])) {
wp_send_json_error(esc_html__('Error: Note content is required. Please enter some text before saving.', 'admin-notes-widget-by-website14'));
}
$note_text = wp_kses($_POST['note_text'], array(
'b' => array(),
'strong' => array(),
'i' => array(),
'em' => array(),
'u' => array(),
'ul' => array(),
'ol' => array(),
'li' => array(),
'a' => array(
'href' => array(),
'target' => array()
),
'code' => array(),
'br' => array(),
'p' => array(),
'div' => array(),
'span' => array()
));
// Additional security: Remove any potentially dangerous content
$note_text = preg_replace('/