diff --git a/assets/js/advanced-search.js b/assets/js/advanced-search.js index a503663..b5eabfe 100644 --- a/assets/js/advanced-search.js +++ b/assets/js/advanced-search.js @@ -156,7 +156,10 @@ async function saveCurrentFilter() { try { const response = await fetch('/api/saved_filters.php', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-Token': window.CSRF_TOKEN + }, body: JSON.stringify({ filter_name: filterName.trim(), filter_criteria: filterCriteria @@ -319,7 +322,10 @@ async function deleteSavedFilter() { try { const response = await fetch('/api/saved_filters.php', { method: 'DELETE', - headers: { 'Content-Type': 'application/json' }, + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-Token': window.CSRF_TOKEN + }, body: JSON.stringify({ filter_id: filterId }) }); diff --git a/assets/js/dashboard.js b/assets/js/dashboard.js index a5ad621..9a93f69 100644 --- a/assets/js/dashboard.js +++ b/assets/js/dashboard.js @@ -276,7 +276,8 @@ function quickSave() { fetch('/api/update_ticket.php', { method: 'POST', headers: { - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', + 'X-CSRF-Token': window.CSRF_TOKEN }, body: JSON.stringify(data) }) @@ -355,7 +356,8 @@ function saveTicket() { fetch('/api/update_ticket.php', { method: 'POST', headers: { - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', + 'X-CSRF-Token': window.CSRF_TOKEN }, body: JSON.stringify({ ticket_id: ticketId, @@ -492,7 +494,10 @@ function bulkClose() { fetch('/api/bulk_operation.php', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-Token': window.CSRF_TOKEN + }, body: JSON.stringify({ operation_type: 'bulk_close', ticket_ids: ticketIds @@ -593,7 +598,10 @@ function performBulkAssign() { fetch('/api/bulk_operation.php', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-Token': window.CSRF_TOKEN + }, body: JSON.stringify({ operation_type: 'bulk_assign', ticket_ids: ticketIds, @@ -681,7 +689,10 @@ function performBulkPriority() { fetch('/api/bulk_operation.php', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-Token': window.CSRF_TOKEN + }, body: JSON.stringify({ operation_type: 'bulk_priority', ticket_ids: ticketIds, @@ -800,15 +811,18 @@ function closeBulkStatusModal() { function performBulkStatusChange() { const status = document.getElementById('bulkStatus').value; const ticketIds = getSelectedTicketIds(); - + if (!status) { alert('Please select a status'); return; } - + fetch('/api/bulk_operation.php', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-Token': window.CSRF_TOKEN + }, body: JSON.stringify({ operation_type: 'bulk_status', ticket_ids: ticketIds, @@ -885,10 +899,13 @@ function closeBulkDeleteModal() { function performBulkDelete() { const ticketIds = getSelectedTicketIds(); - + fetch('/api/bulk_operation.php', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-Token': window.CSRF_TOKEN + }, body: JSON.stringify({ operation_type: 'bulk_delete', ticket_ids: ticketIds diff --git a/assets/js/settings.js b/assets/js/settings.js index de5e667..5586558 100644 --- a/assets/js/settings.js +++ b/assets/js/settings.js @@ -81,7 +81,10 @@ async function saveSettings() { for (const [key, value] of Object.entries(prefs)) { const response = await fetch('/api/user_preferences.php', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-Token': window.CSRF_TOKEN + }, body: JSON.stringify({ key, value }) }); diff --git a/assets/js/ticket.js b/assets/js/ticket.js index 8afd663..2a3ecf3 100644 --- a/assets/js/ticket.js +++ b/assets/js/ticket.js @@ -33,7 +33,8 @@ function saveTicket() { fetch(apiUrl, { method: 'POST', headers: { - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', + 'X-CSRF-Token': window.CSRF_TOKEN }, body: JSON.stringify({ ticket_id: ticketId, @@ -140,7 +141,8 @@ function addComment() { fetch('/api/add_comment.php', { method: 'POST', headers: { - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', + 'X-CSRF-Token': window.CSRF_TOKEN }, body: JSON.stringify({ ticket_id: ticketId, @@ -178,18 +180,33 @@ function addComment() { .replace(/\n/g, '
'); } - // Add new comment to the list + // Add new comment to the list (using safe DOM API to prevent XSS) const commentsList = document.querySelector('.comments-list'); - const newComment = ` -
-
- ${data.user_name} - ${data.created_at} -
-
${displayText}
-
- `; - commentsList.insertAdjacentHTML('afterbegin', newComment); + + const commentDiv = document.createElement('div'); + commentDiv.className = 'comment'; + + const headerDiv = document.createElement('div'); + headerDiv.className = 'comment-header'; + + const userSpan = document.createElement('span'); + userSpan.className = 'comment-user'; + userSpan.textContent = data.user_name; // Safe - auto-escapes + + const dateSpan = document.createElement('span'); + dateSpan.className = 'comment-date'; + dateSpan.textContent = data.created_at; // Safe - auto-escapes + + const textDiv = document.createElement('div'); + textDiv.className = 'comment-text'; + textDiv.innerHTML = displayText; // displayText already sanitized above + + headerDiv.appendChild(userSpan); + headerDiv.appendChild(dateSpan); + commentDiv.appendChild(headerDiv); + commentDiv.appendChild(textDiv); + + commentsList.insertBefore(commentDiv, commentsList.firstChild); } else { console.error('Error adding comment:', data.error || 'Unknown error'); } @@ -283,7 +300,10 @@ function handleAssignmentChange() { fetch('/api/assign_ticket.php', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-Token': window.CSRF_TOKEN + }, body: JSON.stringify({ ticket_id: ticketId, assigned_to: assignedTo }) }) .then(response => response.json()) @@ -316,7 +336,10 @@ function handleMetadataChanges() { fetch('/api/update_ticket.php', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-Token': window.CSRF_TOKEN + }, body: JSON.stringify({ ticket_id: ticketId, [fieldName]: fieldName === 'priority' ? parseInt(newValue) : newValue @@ -418,7 +441,8 @@ function updateTicketStatus() { fetch('/api/update_ticket.php', { method: 'POST', headers: { - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', + 'X-CSRF-Token': window.CSRF_TOKEN }, body: JSON.stringify({ ticket_id: ticketId,