Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions webplugin/js/app/mck-sidebox-1.0.js
Original file line number Diff line number Diff line change
Expand Up @@ -4363,7 +4363,10 @@ const firstVisibleMsg = {
var mck_text_box = document.getElementById('mck-text-box');
mck_text_box.addEventListener('paste', function (e) {
e.preventDefault();
const text = (e.clipboardData || window.clipboardData).getData('text');
const text = (e.clipboardData || window.clipboardData)
.getData('text')
.replace(/\r\n/g, '\n')
.replace(/\n+$/, '');
Comment on lines +4366 to +4369
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard clipboard access before calling getData()

Line 4366 can throw when clipboard APIs are unavailable, which breaks paste handling entirely in affected environments. Add a safe fallback before .replace(...).

Proposed fix
-                    const text = (e.clipboardData || window.clipboardData)
-                        .getData('text')
-                        .replace(/\r\n/g, '\n')
-                        .replace(/\n+$/, '');
+                    var clipboard = e.clipboardData || window.clipboardData;
+                    var rawText =
+                        clipboard && typeof clipboard.getData === 'function'
+                            ? clipboard.getData('text') || clipboard.getData('Text') || ''
+                            : '';
+                    const text = String(rawText).replace(/\r\n/g, '\n').replace(/\n+$/, '');
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const text = (e.clipboardData || window.clipboardData)
.getData('text')
.replace(/\r\n/g, '\n')
.replace(/\n+$/, '');
var clipboard = e.clipboardData || window.clipboardData;
var rawText =
clipboard && typeof clipboard.getData === 'function'
? clipboard.getData('text') || clipboard.getData('Text') || ''
: '';
const text = String(rawText).replace(/\r\n/g, '\n').replace(/\n+$/, '');
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@webplugin/js/app/mck-sidebox-1.0.js` around lines 4366 - 4369, The current
assignment to text calls (e.clipboardData ||
window.clipboardData).getData('text') directly which can throw when clipboard
APIs are absent; change it to first capture the data source (e.clipboardData ||
window.clipboardData), check that it's truthy, call getData('text') only when
present, and then run the .replace(...) on a safe string (e.g., raw || '') so
that e.clipboardData/window.clipboardData and getData are guarded; update the
assignment where text is computed (the const text = ... line) to use this safe
pattern referencing e.clipboardData, window.clipboardData and getData.

document.execCommand('insertText', false, text);
});

Expand Down Expand Up @@ -7505,6 +7508,19 @@ const firstVisibleMsg = {
}
};

_this.sortMessagesByCreatedAt = function (messages, descending) {
if (!Array.isArray(messages)) {
return messages;
}
return messages.slice().sort(function (firstMessage, secondMessage) {
var firstCreatedAt = Number(firstMessage && firstMessage.createdAtTime) || 0;
var secondCreatedAt = Number(secondMessage && secondMessage.createdAtTime) || 0;
return descending
? secondCreatedAt - firstCreatedAt
: firstCreatedAt - secondCreatedAt;
});
};

_this.processMessageList = function (data, scroll, isValidated, append, allowReload) {
// allowReload parameter is using to reload chat widget when the socket connect
var showMoreDateTime;
Expand All @@ -7522,14 +7538,19 @@ const firstVisibleMsg = {
var contact = isGroup
? mckGroupUtils.getGroup(tabId)
: mckMessageLayout.fetchContact(tabId);
if (data && Array.isArray(data.message)) {
data.message = _this.sortMessagesByCreatedAt(data.message, !append);
}
scroll &&
$mck_msg_inner.data(
'last-message-received-time',
data.message[0].createdAtTime
);
if (allowReload) {
scroll = false;
data && data.message && (data.message = data.message.reverse());
data &&
data.message &&
(data.message = _this.sortMessagesByCreatedAt(data.message, false));
}
if (typeof data.message.length === 'undefined') {
var messageArray = [];
Expand Down
131 changes: 121 additions & 10 deletions webplugin/js/app/prechat/km-prechat.js
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,44 @@ var KMPreChat = (function () {
}
}

var getCustomValidation = function (preLeadCollection) {
var validation = preLeadCollection && preLeadCollection.validation;
if (!validation || !validation.regex) {
return null;
}
var regex = validation.regex;
var flags = '';
if (regex instanceof RegExp) {
flags = regex.flags;
regex = regex.source;
Comment on lines +369 to +371
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve validation regex flags

When a widget config passes validation.regex as a RegExp with flags, such as /^[a-z]+$/i for a case-insensitive field, converting it to regex.source drops the flags before both the pattern attribute and data-km-validation-regex are populated. Those fields then become case-sensitive and reject values that the configured validator was meant to accept, so either preserve the flags for the JS check or avoid accepting RegExp objects without flag handling.

Useful? React with 👍 / 👎.

}
if (typeof regex !== 'string') {
return null;
}
return {
regex: regex,
flags: flags,
errorText:
validation.errorText || getLeadCollectionLabel('commonErrorMsg', ''),
};
};

var setValidationAttributes = function (input, validation) {
if (!input || !validation || !validation.regex) {
return;
}
input.setAttribute('pattern', validation.regex);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve flags in native validation

Although the new data attribute now preserves RegExp flags for the JS check, this line still installs only the regex source as the HTML pattern. For a configured validator like /^[a-z]+$/i, entering ABC passes handleCustomValidation() but the browser’s native pattern check is case-sensitive and prevents the form submit before the submit listener can proceed, so values accepted by the supplied validator remain blocked.

Useful? React with 👍 / 👎.

input.setAttribute('title', validation.errorText || '');
input.setAttribute('data-km-validation-regex', validation.regex);
input.setAttribute('data-km-validation-flags', validation.flags || '');
input.setAttribute('data-km-validation-error', validation.errorText || '');
input.setAttribute(
'oninvalid',
"setCustomValidity(this.getAttribute('data-km-validation-error') || '')"
);
input.setAttribute('oninput', "setCustomValidity('')");
};

target.createInputField = function (preLeadCollection) {
var rawField = (preLeadCollection.field || '').toString();
var normalizedField = rawField.toLowerCase().replace(/\s+/g, '');
Expand Down Expand Up @@ -427,7 +465,10 @@ var KMPreChat = (function () {
kmChatInput.setAttribute('type', preLeadCollection.type || 'text');
kmChatInput.setAttribute('placeholder', preLeadCollection.placeholder || '');
kmChatInput.setAttribute('aria-label', preLeadCollection.field);
if (preLeadCollection.type === 'email') {
var customValidation = getCustomValidation(preLeadCollection);
if (customValidation) {
setValidationAttributes(kmChatInput, customValidation);
} else if (preLeadCollection.type === 'email') {
kmChatInput.setAttribute('pattern', '^[^\\s@]+@[^\\s@]+\\.[^\\s@]{2,}$');
kmChatInput.setAttribute('title', '');
kmChatInput.setAttribute(
Expand Down Expand Up @@ -645,6 +686,10 @@ var KMPreChat = (function () {
var emailField = document.getElementById('km-email');
var phoneField = document.getElementById('km-phone');
var submitBtn = document.getElementById('km-submit-chat-login');
var chatLoginForm = document.getElementById('km-form-chat-login');
var customValidationFields = Array.prototype.slice.call(
document.querySelectorAll('[data-km-validation-regex]')
);
var formSubmitted = false;

var setError = function (message) {
Expand All @@ -660,24 +705,73 @@ var KMPreChat = (function () {
}
};

var validateCustomField = function (field) {
var regexText = field.getAttribute('data-km-validation-regex');
var regexFlags = field.getAttribute('data-km-validation-flags') || '';
var errorText =
field.getAttribute('data-km-validation-error') ||
getLeadCollectionLabel('commonErrorMsg', '');
if (!regexText) {
return true;
}
var value = field.value || '';
if (!value && !field.hasAttribute('required')) {
return true;
}
try {
if (!new RegExp(regexText, regexFlags).test(value)) {
setError(errorText);
return false;
}
} catch (error) {
console.error('Invalid pre-chat validation regex', error);
setError(errorText);
return false;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
return true;
};

var handleCustomValidation = function () {
if (!formSubmitted) {
return true;
}
for (var i = 0; i < customValidationFields.length; i++) {
if (!validateCustomField(customValidationFields[i])) {
return false;
}
}
return true;
};

customValidationFields.forEach(function (field) {
field.addEventListener('input', function () {
handleCustomValidation();
});
field.addEventListener('blur', function () {
handleCustomValidation();
});
});

if (emailField) {
var isValidEmail = function (value) {
return KommunicateUI.isValidEmail(value);
};
var handleEmailValidation = function () {
if (!formSubmitted) {
return;
return true;
}
var value = (emailField.value || '').toLowerCase();
if (!value) {
setError('');
return;
return true;
}
if (!isValidEmail(value)) {
setError(getLeadCollectionLabel('errorEmail', ''));
return false;
} else {
setError('');
}
return true;
};
emailField.addEventListener('input', function () {
handleEmailValidation();
Expand All @@ -690,12 +784,12 @@ var KMPreChat = (function () {
if (phoneField) {
var handlePhoneValidation = function () {
if (!formSubmitted) {
return;
return true;
}
var value = phoneField.value || '';
if (!value) {
setError('');
return;
return true;
}
var isValid = true;
var intlInstance = deps.getIntlTelInstance();
Expand All @@ -707,9 +801,11 @@ var KMPreChat = (function () {
}
if (!isValid) {
setError(getLeadCollectionLabel('commonErrorMsg', ''));
return false;
} else {
setError('');
}
return true;
};
phoneField.addEventListener('input', function () {
handlePhoneValidation();
Expand All @@ -719,12 +815,27 @@ var KMPreChat = (function () {
});
}

var handleSubmitValidation = function (event) {
formSubmitted = true;
if (
!handleCustomValidation() ||
(handleEmailValidation && !handleEmailValidation()) ||
(handlePhoneValidation && !handlePhoneValidation())
) {
if (event && typeof event.preventDefault === 'function') {
event.preventDefault();
}
return false;
}
setError('');
return true;
};

if (submitBtn) {
submitBtn.addEventListener('click', function () {
formSubmitted = true;
handleEmailValidation && handleEmailValidation();
handlePhoneValidation && handlePhoneValidation();
});
submitBtn.addEventListener('click', handleSubmitValidation);
}
if (chatLoginForm) {
chatLoginForm.addEventListener('submit', handleSubmitValidation);
}
};

Expand Down
Loading