From f3e17576ba1d6fbef14b120019fd4be902fe508f Mon Sep 17 00:00:00 2001 From: Nam Mai <117440763+mnhnam-axonivy@users.noreply.github.com> Date: Mon, 16 Dec 2024 17:00:59 +0700 Subject: [PATCH 1/2] IVYPORTAL-18029: Security findings- Client-side cross-site scripting (#1310) * feature/IVYPORTAL-18028-High-Failure-to-use-HTTPS-or-SFTP-URL-in-Maven-artifact-upload-download-Two-occurrences-12 (#1305) * IVYPORTAL-18029 High - Client-side cross-site scripting - Apply new approach to load taskUrl from server --- .../generic/bean/IFrameTaskTemplateBean.java | 7 +++ .../restricted/IFrameTaskTemplate.xhtml | 49 ++++++++++++------- .../resources/js/iframe-task-template.js | 11 ----- 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/IFrameTaskTemplateBean.java b/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/IFrameTaskTemplateBean.java index c7b6b99bcd2..af864d25651 100644 --- a/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/IFrameTaskTemplateBean.java +++ b/AxonIvyPortal/portal/src/ch/ivy/addon/portal/generic/bean/IFrameTaskTemplateBean.java @@ -54,6 +54,7 @@ public class IFrameTaskTemplateBean extends AbstractTaskTemplateBean implements public static final String PORTAL_GROWL_MESSGE_PARAM = "portalGrowlMessage"; private static final String DEFAULT_TASK_ICON = "si si-task-list-edit"; private static final String TASK_ICON = "taskIcon"; + private static final String TASK_URL = "taskUrl"; private int currentProcessStep; private List processSteps; @@ -74,6 +75,12 @@ public class IFrameTaskTemplateBean extends AbstractTaskTemplateBean implements private Long caseId = null; + public String getTaskUrl() { + return Optional.ofNullable(FacesContext.getCurrentInstance() + .getExternalContext().getRequestParameterMap().get(TASK_URL)) + .orElse(StringUtils.EMPTY); + } + public void useTaskInIFrame() { keepOverridePortalGrowl(); Map requestParamMap = getRequestParameterMap(); diff --git a/AxonIvyPortal/portal/webContent/layouts/restricted/IFrameTaskTemplate.xhtml b/AxonIvyPortal/portal/webContent/layouts/restricted/IFrameTaskTemplate.xhtml index c9cda06739d..7b521bc862c 100644 --- a/AxonIvyPortal/portal/webContent/layouts/restricted/IFrameTaskTemplate.xhtml +++ b/AxonIvyPortal/portal/webContent/layouts/restricted/IFrameTaskTemplate.xhtml @@ -70,24 +70,24 @@ **2. JavaScript-Based Configuration:** Example: + window.taskName = "Approve Investment"; + window.taskIcon = "si si-bulb"; + window.isHideTaskName = false; + window.caseId = "123456"; + window.isHideCaseInfo = false; + window.currentProcessStep = 0; + window.processSteps = ["Create Investment Request", "Approve Investment Request"]; + // Convert Java List of steps to JSON format if needed: + window.processSteps = #{portalComponentUtilsBean.convertToJSON(data.steps)}; + window.isShowAllSteps = true; + window.processChainDirection = "VERTICAL"; + window.processChainShape = "LINE"; + window.isHideTaskAction = false; + window.isWorkingOnATask = false; + window.announcementInvisible = false; + window.isCardFrame = true; + window.viewName = "TASK_DETAIL"; + --> @@ -113,6 +113,19 @@ + diff --git a/AxonIvyPortal/portal/webContent/resources/js/iframe-task-template.js b/AxonIvyPortal/portal/webContent/resources/js/iframe-task-template.js index 7e32a706de4..46a55531bc3 100644 --- a/AxonIvyPortal/portal/webContent/resources/js/iframe-task-template.js +++ b/AxonIvyPortal/portal/webContent/resources/js/iframe-task-template.js @@ -1,16 +1,5 @@ var invalidIFrameSrcPath = false; -let taskUrl = new URLSearchParams(window.location.search).get("taskUrl"); -let updateIframeSrc = (newSrc) => { - getPortalIframe().src = newSrc; -} -if (taskUrl){ - if(taskUrl.endsWith('blank')){ - window.history.back(document.referrer); - } - updateIframeSrc(taskUrl) -} -loadIframe(false); var recheckFrameTimer; function loadIframe(recheckIndicator) { var iframe = getPortalIframe(); From c770f8c666c636c728627fbf42327d03f544afb0 Mon Sep 17 00:00:00 2001 From: "Nam.Chu" Date: Tue, 17 Dec 2024 09:53:17 +0700 Subject: [PATCH 2/2] IVYPORTAL-18031 Medium - DOM text reinterpreted as HTML - Implement --- AxonIvyPortal/portal/webContent/resources/js/chat.js | 11 ++++++++++- .../portal/webContent/resources/js/welcome-widget.js | 11 +++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/AxonIvyPortal/portal/webContent/resources/js/chat.js b/AxonIvyPortal/portal/webContent/resources/js/chat.js index 24291ab046c..020e46607f9 100644 --- a/AxonIvyPortal/portal/webContent/resources/js/chat.js +++ b/AxonIvyPortal/portal/webContent/resources/js/chat.js @@ -733,7 +733,7 @@ function View(uri) } } else { var userDom = document.createElement('li'); - userDom.innerHTML = $('.js-no-users-of-role').val(); + userDom.innerHTML = escapeHtml($('.js-no-users-of-role').val()); userList.appendChild(userDom); } roleGroupDom.appendChild(userList) @@ -742,6 +742,15 @@ function View(uri) } PF('participants-list-dialog').initPosition(); } + + function escapeHtml(unsafe){ + return unsafe + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); + } function initCloneGroup(groupTemplate, groupId) { var cloneGroup = groupTemplate.cloneNode(true); diff --git a/AxonIvyPortal/portal/webContent/resources/js/welcome-widget.js b/AxonIvyPortal/portal/webContent/resources/js/welcome-widget.js index f8d858969a0..a3090dc29e7 100644 --- a/AxonIvyPortal/portal/webContent/resources/js/welcome-widget.js +++ b/AxonIvyPortal/portal/webContent/resources/js/welcome-widget.js @@ -1,3 +1,11 @@ +function escapeHtml(unsafe){ + return unsafe + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); +} WelcomeWidgetConfiguration = { oldImageStyleClass : '', @@ -11,7 +19,6 @@ WelcomeWidgetConfiguration = { this.updateStyleClasses(); this.updatePreviewImageFit(); }, - updatePreviewText : function(isGreeting) { var previewDialog = $('#new-widget-configuration-dialog'); var welcomeText = previewDialog.find('.js-welcome-text-input.language-to-preview').get(0).value; @@ -19,7 +26,7 @@ WelcomeWidgetConfiguration = { if (isGreeting == 'true' || (isGreeting == undefined && $('.js-greeting-text').length != 0)) { welcomeText = previewDialog.find('.js-greeting-text.language-to-preview').get(0).innerHTML + welcomeText; } - $('#new-widget-configuration-dialog').find('.js-preview-text').get(0).innerHTML = welcomeText; + $('#new-widget-configuration-dialog').find('.js-preview-text').get(0).innerHTML = escapeHtml(welcomeText); }, updatePreviewTextPosition : function() {