'handleTicketView' ]; if (isset($methodMaps[$route])) { $this->{$methodMaps[$route]}(); } } public function handleTicketView() { if (!Helper::isPublicSignedTicketEnabled()) { $this->handleInvalidTicket(); } else { $this->handleValidTicket(); } } /** * Display the attachment. * * Uses the new rewrite endpoint to get an attachment ID * and display the attachment if the currently logged in user * has the authorization to. * * @return void * @since 3.2.0 */ public function view_attachment() { // First verify nonce for security if (!isset($_REQUEST['_wpnonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_REQUEST['_wpnonce'])), 'fluent-support')) { wp_die(esc_html__('Security check failed. Please try again.', 'fluent-support'), 403); return; } // Then check permissions if user is logged in if (!get_current_user_id()) { wp_die(esc_html__('You do not have permission to access this file.', 'fluent-support'), 403); return; } $attachmentHash = sanitize_text_field($_REQUEST['fst_file']); if (empty($attachmentHash)) { die('Invalid Attachment Hash'); } $attachment = $this->getAttachmentByHash($attachmentHash); if (!$attachment) { die('Invalid Attachment Hash'); } // check signature hash if (!$this->validateAttachmentSignature($attachment)) { $dieMessage = esc_html__('Sorry, Your secure sign is invalid, Please reload the previous page and get new signed url', 'fluent-support'); die(esc_html($dieMessage)); // Escaping the die message again for safety } //If external file if ('local' !== $attachment->driver) { if(!empty($attachment->full_url)){ $this->redirectToExternalAttachment($attachment->full_url); }else{ die('File could not be found'); } } //Handle Local file if (!file_exists($attachment->file_path)) { die('File could not be found'); } $this->serveLocalAttachment($attachment); } private function getAttachmentByHash($attachmentHash) { return Attachment::where('file_hash', $attachmentHash)->first(); } private function validateAttachmentSignature($attachment) { // Sanitize and validate secure_sign input - don't trust any input if (!isset($_REQUEST['secure_sign'])) { return false; } $secureSign = sanitize_text_field(wp_unslash($_REQUEST['secure_sign'])); $sign = md5($attachment->id . date('YmdH')); return $sign === $_REQUEST['secure_sign']; // return hash_equals($sign, $secureSign); } private function handleInvalidTicket() { // Nonce already verified in route() method // Validate and sanitize input - don't trust any input $ticketId = absint(Arr::get($_REQUEST, 'ticket_id', 0)); if (!$ticketId) { $this->showInvalidPortalMessage(); return; } $ticket = Ticket::where('id', $ticketId)->first(); if (!$ticket) { $this->showInvalidPortalMessage(); } else { // Check permissions if user is logged in if (!get_current_user_id()) { wp_die(esc_html__('You do not have permission to access this ticket.', 'fluent-support'), 403); return; } $this->redirectToTicketView($ticket); } } private function handleValidTicket() { // Nonce already verified in route() method // Validate and sanitize inputs - don't trust any input $ticketHash = sanitize_text_field(Arr::get($_REQUEST, 'support_hash', '')); $ticketId = absint(Arr::get($_REQUEST, 'ticket_id', 0)); if (empty($ticketHash) || !$ticketId) { $this->showInvalidPortalMessage(); return; } $ticket = Ticket::where('hash', $ticketHash)->where('id', $ticketId)->first(); if (!$ticket) { $this->showInvalidPortalMessage(); } elseif (get_current_user_id()) { $this->redirectToTicketView($ticket); } } private function showInvalidPortalMessage() { echo '

' . esc_html__('Invalid Support Portal URL', 'fluent-support') . '

'; die(); } private function redirectToTicketView($ticket) { $redirectUrl = Helper::getTicketViewUrl($ticket); $this->redirectToExternalAttachment($redirectUrl); } private function redirectToExternalAttachment($redirectUrl) { wp_redirect($redirectUrl, 307); exit(); } // Helper method to serve an attachment private function serveLocalAttachment($attachment) { $file_path = realpath($attachment->file_path); $uploads = wp_upload_dir(); $uploads_dir = realpath($uploads['basedir']); // Ensures both paths are absolute if (!$file_path || !$uploads_dir || strpos($file_path, $uploads_dir) !== 0 || !file_exists($file_path)) { wp_die(esc_html__('File not found or access denied', 'fluent-support'), 403); return; } ob_get_clean(); $original_user_agent = ini_get('user_agent'); ini_set('user_agent', 'Fluent Support/' . FLUENT_SUPPORT_VERSION . '; ' . esc_url(get_bloginfo('url'))); header("Content-Type: " . esc_attr($attachment->file_type)); header("Content-Disposition: inline; filename=\"" . esc_attr($attachment->title) . "\""); readfile($file_path); ini_set('user_agent', $original_user_agent); die(); } }