| @@ -44,9 +44,10 @@ | ||
| 44 | 44 | if(session_hover_state == ''){ |
| 45 | 45 | session_hover_state = 1; |
| 46 | 46 | modal.style.display = "none"; |
| 47 | 47 | jQuery('.details_modal_body').html(''); |
| 48 | - modal.style.left = (jQuery('.session_detail_hover').width() * 2)+'px'; | |
| 48 | + modal.style.left = ''; | |
| 49 | + modal.style.top = ''; | |
| 49 | 50 | setTimeout(function() { |
| 50 | 51 | modal.style.display = "block"; |
| 51 | 52 | jQuery('.loader-mask').show(); |
| 52 | 53 | jQuery('.loader').show(); |
| @@ -61,26 +62,29 @@ | ||
| 61 | 62 | }, |
| 62 | 63 | success: function (response) { |
| 63 | 64 | jQuery('.loader').fadeOut(); |
| 64 | 65 | jQuery('.loader-mask').delay(350).fadeOut('slow'); |
| 66 | + // SECURITY FIX: Server now returns sanitized HTML (wp_kses output). | |
| 67 | + // Do NOT run htmlspecialchars_decode() on conversation data before .html(); | |
| 68 | + // that decode-then-inject pattern was the DOM XSS sink. | |
| 65 | 69 | let htmlString = response.conversation; |
| 66 | 70 | let doc = '<div class="session-details-sction-modal">' ; |
| 67 | - doc += htmlspecialchars_decode(htmlString); | |
| 71 | + doc += htmlString; | |
| 68 | 72 | doc += '</div>'; |
| 69 | 73 | if (response.email) { |
| 70 | - doc += '</div><div class="email-reply-container" style="margin-top:20px; padding:15px; border-top:1px solid #ccc; background:#f9f9f9; border-radius: 6px;">' + | |
| 71 | - '<h4 style="margin-top:0;">Reply via Email to: <strong>' + response.email + ' From: ' + (response.email_from ? response.email_from : '****') + '</strong></h4>' + | |
| 72 | - '<div class="form-group mb-2" style="margin-bottom: 10px;">' + | |
| 73 | - '<input type="text" id="reply_subject" class="form-control" style="width:100%; box-sizing:border-box;" value="Reply to your chat session">' + | |
| 74 | + doc += '<div class="email-reply-container">' + | |
| 75 | + '<p class="email-reply-meta">Reply via <strong>Email to:</strong> ' + response.email + ' <strong>From:</strong> <input type="email" id="reply_from_email" class="form-control" value="' + ( response.email_from ? '' + response.email_from : '' ) + '"></p>' + | |
| 76 | + '<div class="form-group mb-2">' + | |
| 77 | + '<input type="text" id="reply_subject" class="form-control" placeholder="Reply to your chat session">' + | |
| 74 | 78 | '</div>' + |
| 75 | - '<div class="form-group mb-2" style="margin-bottom: 10px;">' + | |
| 76 | - '<textarea id="reply_message" class="form-control" rows="4" style="width:100%; box-sizing:border-box;" placeholder="Type your reply here..."></textarea>' + | |
| 79 | + '<div class="form-group mb-2">' + | |
| 80 | + '<textarea id="reply_message" class="form-control" rows="4" placeholder="Type your reply here..."></textarea>' + | |
| 77 | 81 | '</div>' + |
| 78 | - '<button type="button" class="btn btn-primary" id="btn_send_reply_email" data-email="' + response.email + '" style="background:#0d6efd; color:#fff; border:none; padding:8px 16px; border-radius:4px; cursor:pointer;">Send Reply</button>' + | |
| 82 | + '<button type="button" class="btn btn-primary" id="btn_send_reply_email" data-email="' + response.email + '">Send Reply</button>' + | |
| 79 | 83 | '</div>'; |
| 80 | 84 | } else { |
| 81 | - doc += '<div class="email-reply-container" style="margin-top:20px; padding:15px; border-top:1px solid #ccc; background:#f9f9f9; border-radius: 6px;">' + | |
| 82 | - '<p style="margin:0; color:#d9534f; font-weight:bold;">Enable Asking for Email to get email reply option</p>' + | |
| 85 | + doc += '<div class="email-reply-container">' + | |
| 86 | + '<p class="email-reply-warning">Enable Asking for Email to get email reply option</p>' + | |
| 83 | 87 | '</div>'; |
| 84 | 88 | } |
| 85 | 89 | jQuery('.details_modal_body').html(doc); |
| 86 | 90 | session_hover_state = ''; |
| @@ -102,60 +106,82 @@ | ||
| 102 | 106 | if(session_hover_state == ''){ |
| 103 | 107 | session_hover_state = 1; |
| 104 | 108 | modal.style.display = "none"; |
| 105 | 109 | jQuery('.details_modal_body').html(''); |
| 106 | - modal.style.left = (jQuery('.session_detail_hover').width() * 2)+'px'; | |
| 107 | - setTimeout(function() { | |
| 108 | - modal.style.display = "block"; | |
| 109 | - jQuery('.loader-mask').show(); | |
| 110 | - jQuery('.loader').show(); | |
| 111 | - jQuery.ajax({ | |
| 112 | - url: ajax_object.ajax_url, | |
| 113 | - type: 'POST', | |
| 114 | - dataType: "JSON", | |
| 115 | - data: { | |
| 116 | - action : 'wpbot_session_hover_details', | |
| 117 | - security: ajax_object.ajax_nonce, | |
| 118 | - session_id: jQuery(self).attr('data-id'), | |
| 119 | - }, | |
| 120 | - success: function (response) { | |
| 121 | - jQuery('.loader').fadeOut(); | |
| 122 | - jQuery('.loader-mask').delay(350).fadeOut('slow'); | |
| 123 | - let htmlString = response.conversation; | |
| 124 | - let doc = '<div class="session-details-sction-modal">' ; | |
| 125 | - doc += htmlspecialchars_decode(htmlString); | |
| 126 | - doc += '</div>'; | |
| 127 | - if (response.email) { | |
| 128 | - doc += '</div><div class="email-reply-container" style="margin-top:20px; padding:15px; border-top:1px solid #ccc; background:#f9f9f9; border-radius: 6px;">' + | |
| 129 | - '<h4 style="margin-top:0;"> Reply via Email to: <strong>' + response.email + ( response.email_from ? ' From:' + response.email_from : '' ) + '</strong></h4>' + | |
| 130 | - '<div class="form-group mb-2" style="margin-bottom: 10px;">' + | |
| 131 | - '<input type="text" id="reply_subject" class="form-control" style="width:100%; box-sizing:border-box;" value="Reply to your chat session">' + | |
| 132 | - '</div>' + | |
| 133 | - '<div class="form-group mb-2" style="margin-bottom: 10px;">' + | |
| 134 | - '<textarea id="reply_message" class="form-control" rows="4" style="width:100%; box-sizing:border-box;" placeholder="Type your reply here..."></textarea>' + | |
| 135 | - '</div>' + | |
| 136 | - '<button type="button" class="btn btn-primary" id="btn_send_reply_email" data-email="' + response.email + '" style="background:#0d6efd; color:#fff; border:none; padding:8px 16px; border-radius:4px; cursor:pointer;">Send Reply</button>' + | |
| 137 | - '</div>'; | |
| 138 | - } else { | |
| 139 | - doc += '<div class="email-reply-container" style="margin-top:20px; padding:15px; border-top:1px solid #ccc; background:#f9f9f9; border-radius: 6px;">' + | |
| 140 | - '<p style="margin:0; color:#d9534f; font-weight:bold;">To email this user and chat session, enable Asking for Email in General Settings</p>' + | |
| 141 | - '</div></div><div class="email-reply-container" style="margin-top:20px; padding:15px; border-top:1px solid #ccc; background:#f9f9f9; border-radius: 6px;">' + | |
| 142 | - '<h4 style="margin-top:0;"> Reply via Email to: <strong>' + response.email + ( response.email_from ? ' From:' + response.email_from : '' ) + '</strong></h4>' + | |
| 143 | - '<div class="form-group mb-2" style="margin-bottom: 10px;">' + | |
| 144 | - '<input type="text" id="reply_subject" disabled class="form-control" style="width:100%; box-sizing:border-box;" value="Reply to your chat session">' + | |
| 145 | - '</div>' + | |
| 146 | - '<div class="form-group mb-2" style="margin-bottom: 10px;">' + | |
| 147 | - '<textarea id="reply_message" disabled class="form-control" rows="4" style="width:100%; box-sizing:border-box;" placeholder="Type your reply here..."></textarea>' + | |
| 148 | - '</div>' + | |
| 149 | - '<button type="button" disabled class="btn btn-primary" id="btn_send_reply_email" data-email="' + response.email + '" style="background:#0d6efd; color:#fff; border:none; padding:8px 16px; border-radius:4px; cursor:pointer;">Send Reply</button>' + | |
| 150 | - '</div'; | |
| 151 | - } | |
| 152 | - jQuery('.details_modal_body').html(doc); | |
| 153 | - session_hover_state = ''; | |
| 154 | - // location.reload(); | |
| 155 | - }, | |
| 110 | + modal.style.left = ''; | |
| 111 | + modal.style.top = ''; | |
| 112 | + | |
| 113 | + if (typeof Swal !== 'undefined') { | |
| 114 | + Swal.fire({ | |
| 115 | + html: '<div class="qcld-save-settings-spinner"></div>', | |
| 116 | + allowOutsideClick: false, | |
| 117 | + allowEscapeKey: false, | |
| 118 | + showConfirmButton: false, | |
| 119 | + background: 'transparent', | |
| 120 | + customClass: { | |
| 121 | + popup: 'qcld-swal-loading-only' | |
| 122 | + } | |
| 156 | 123 | }); |
| 157 | - }, 100); | |
| 124 | + } | |
| 125 | + | |
| 126 | + jQuery.ajax({ | |
| 127 | + url: ajax_object.ajax_url, | |
| 128 | + type: 'POST', | |
| 129 | + dataType: "JSON", | |
| 130 | + data: { | |
| 131 | + action : 'wpbot_session_hover_details', | |
| 132 | + security: ajax_object.ajax_nonce, | |
| 133 | + session_id: jQuery(self).attr('data-id'), | |
| 134 | + }, | |
| 135 | + success: function (response) { | |
| 136 | + if (typeof Swal !== 'undefined') { | |
| 137 | + Swal.close(); | |
| 138 | + } | |
| 139 | + // SECURITY FIX: Server now returns sanitized HTML (wp_kses output). | |
| 140 | + // Do NOT run htmlspecialchars_decode() on conversation data before .html(); | |
| 141 | + // that decode-then-inject pattern was the DOM XSS sink. | |
| 142 | + let htmlString = response.conversation; | |
| 143 | + let doc = '<div class="session-details-sction-modal">' ; | |
| 144 | + doc += htmlString; | |
| 145 | + doc += '</div>'; | |
| 146 | + if (response.email) { | |
| 147 | + var replyEmail = response.email || ''; | |
| 148 | + var replyEmailText = jQuery('<div>').text(replyEmail).html(); | |
| 149 | + var replyEmailLink = '<a href="mailto:' + encodeURIComponent(replyEmail) + '">' + replyEmailText + '</a>'; | |
| 150 | + doc += '<div class="email-reply-container">' + | |
| 151 | + '<p class="email-reply-meta">Reply via <strong>Email to:</strong> ' + replyEmailLink + ' <strong>From:</strong> <input type="email" id="reply_from_email" value="' + ( response.email_from ? '' + response.email_from : '' ) + '"></p>' + | |
| 152 | + '<div class="form-group mb-2">' + | |
| 153 | + '<input type="text" id="reply_subject" class="form-control" placeholder="Reply to your chat session">' + | |
| 154 | + '</div>' + | |
| 155 | + '<div class="form-group mb-2">' + | |
| 156 | + '<textarea id="reply_message" class="form-control" rows="4" placeholder="Type your reply here..."></textarea>' + | |
| 157 | + '</div>' + | |
| 158 | + '<button type="button" class="btn btn-primary" id="btn_send_reply_email" data-email="' + response.email + '">Send Reply</button>' + | |
| 159 | + '</div>'; | |
| 160 | + } else { | |
| 161 | + doc += '<div class="email-reply-container">' + | |
| 162 | + '<p class="email-reply-warning">To email this user and chat session, enable Asking for Email in General Settings</p>' + | |
| 163 | + '<p class="email-reply-meta">Reply via <strong>Email to:</strong> ' + (response.email || '') + ' <strong>From:</strong> <input type="email" id="reply_from_email" disabled value="' + ( response.email_from ? '' + response.email_from : '' ) + '"></p>' + | |
| 164 | + '<div class="form-group mb-2">' + | |
| 165 | + '<input type="text" id="reply_subject" disabled class="form-control" placeholder="Reply to your chat session">' + | |
| 166 | + '</div>' + | |
| 167 | + '<div class="form-group mb-2">' + | |
| 168 | + '<textarea id="reply_message" disabled class="form-control" rows="4" placeholder="Type your reply here..."></textarea>' + | |
| 169 | + '</div>' + | |
| 170 | + '<button type="button" disabled class="btn btn-primary" id="btn_send_reply_email" data-email="' + response.email + '">Send Reply</button>' + | |
| 171 | + '</div>'; | |
| 172 | + } | |
| 173 | + jQuery('.details_modal_body').html(doc); | |
| 174 | + modal.style.display = "block"; | |
| 175 | + session_hover_state = ''; | |
| 176 | + }, | |
| 177 | + error: function () { | |
| 178 | + if (typeof Swal !== 'undefined') { | |
| 179 | + Swal.close(); | |
| 180 | + } | |
| 181 | + session_hover_state = ''; | |
| 182 | + } | |
| 183 | + }); | |
| 158 | 184 | } |
| 159 | 185 | }); |
| 160 | 186 | jQuery('#session_details_modal').on('click','.details_session_close',function(){ |
| 161 | 187 | const modal = document.getElementById("session_details_modal"); |
| @@ -164,8 +190,9 @@ | ||
| 164 | 190 | |
| 165 | 191 | jQuery(document).on('click', '#btn_send_reply_email', function () { |
| 166 | 192 | var email = jQuery(this).attr('data-email'); |
| 167 | 193 | var container = jQuery(this).closest('.email-reply-container'); |
| 194 | + var fromEmail = container.find('#reply_from_email').val(); | |
| 168 | 195 | var subject = container.find('#reply_subject').val(); |
| 169 | 196 | var message = container.find('#reply_message').val(); |
| 170 | 197 | var btn = jQuery(this); |
| 171 | 198 | |
| @@ -183,8 +210,9 @@ | ||
| 183 | 210 | data: { |
| 184 | 211 | action: 'wpbot_send_reply_email', |
| 185 | 212 | security: ajax_object.ajax_nonce, |
| 186 | 213 | email: email, |
| 214 | + from_email: fromEmail, | |
| 187 | 215 | subject: subject, |
| 188 | 216 | message: message |
| 189 | 217 | }, |
| 190 | 218 | success: function (response) { |
| @@ -323,12 +351,10 @@ | ||
| 323 | 351 | } |
| 324 | 352 | }); |
| 325 | 353 | |
| 326 | 354 | jQuery('#chatsession-table').on('click', '.forward_session', function () { |
| 327 | - setTimeout(function() { | |
| 328 | - var detailselement = document.getElementById("wp-chatbot-messages-container"); | |
| 329 | - detailselement.remove(); | |
| 330 | - }, 500); | |
| 355 | + jQuery('.details_modal_body').html(''); | |
| 356 | + | |
| 331 | 357 | const forwardModal = document.getElementById("session_foward_modal"); |
| 332 | 358 | if (forwardModal) { |
| 333 | 359 | forwardModal.style.display = "block"; |
| 334 | 360 | jQuery('#details_session_id').val(jQuery(this).attr('data-id')); |
| @@ -393,5 +419,5 @@ | ||
| 393 | 419 | } |
| 394 | 420 | }); |
| 395 | 421 | }); |
| 396 | 422 | |
| 397 | -}); | |
| 423 | +}); | |