From 6110a330bf21d7156c1e0c054ea92e79e65b5ba9 Mon Sep 17 00:00:00 2001 From: Mohammed Fahimullah A Date: Wed, 15 Oct 2025 19:13:00 +0530 Subject: [PATCH 1/4] fix: fixed lint issues --- src/combobox/stories/app-mock-query-search.component.ts | 4 ++-- src/datepicker/datepicker.component.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/combobox/stories/app-mock-query-search.component.ts b/src/combobox/stories/app-mock-query-search.component.ts index 9e2de3c824..788c1dee41 100644 --- a/src/combobox/stories/app-mock-query-search.component.ts +++ b/src/combobox/stories/app-mock-query-search.component.ts @@ -23,12 +23,12 @@ export class MockQueryCombobox { { content: `Random ${Math.random()}` }, { content: `Random ${Math.random()}` }, { content: `Random ${Math.random()}` }, - { content: `Random ${Math.random()}` }, + { content: `Random ${Math.random()}` } ]; // Include current selected in the list to avoid auto clear if (this.currentlySelected) { - array.push(this.currentlySelected) + array.push(this.currentlySelected); } this.filterItems = array; }, 1000); diff --git a/src/datepicker/datepicker.component.ts b/src/datepicker/datepicker.component.ts index e11ad1300d..95b587f0c3 100644 --- a/src/datepicker/datepicker.component.ts +++ b/src/datepicker/datepicker.component.ts @@ -510,8 +510,8 @@ export class DatePicker implements const calendarContainer = this.flatpickrInstance.calendarContainer; const dayElement = calendarContainer && calendarContainer.querySelector(".flatpickr-day[tabindex]"); - const selectedDateElem = calendarContainer && calendarContainer.querySelector('.selected'); - const todayDateElem = calendarContainer && calendarContainer.querySelector('.today'); + const selectedDateElem = calendarContainer && calendarContainer.querySelector(".selected"); + const todayDateElem = calendarContainer && calendarContainer.querySelector(".today"); if (dayElement) { (todayDateElem || selectedDateElem || dayElement).focus(); @@ -593,7 +593,7 @@ export class DatePicker implements // add day classes and special case the "today" element based on `this.value` Array.from(dayContainer).forEach(element => { - element.setAttribute('role', 'button'); + element.setAttribute("role", "button"); element.classList.add("cds--date-picker__day"); if (!this.value) { return; From 59cd0bac76375378c600b7015bba774ec64f9624 Mon Sep 17 00:00:00 2001 From: Mohammed Fahimullah A Date: Wed, 15 Oct 2025 19:14:23 +0530 Subject: [PATCH 2/4] fix: prevent XSS by separating HTML fields from plain text --- .../notification-content.interface.ts | 2 ++ src/notification/notification.component.ts | 26 ++++++++++++++++--- src/notification/notification.stories.ts | 19 ++++++++++++++ 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/src/notification/notification-content.interface.ts b/src/notification/notification-content.interface.ts index 587071091e..41409769a6 100644 --- a/src/notification/notification-content.interface.ts +++ b/src/notification/notification-content.interface.ts @@ -8,11 +8,13 @@ export interface NotificationContent { [key: string]: any; type: NotificationType; title: string; + titleHtml?: string; target?: string; duration?: number; smart?: boolean; closeLabel?: any; message?: string; + messageHtml?: string; showClose?: boolean; lowContrast?: boolean; template?: TemplateRef; diff --git a/src/notification/notification.component.ts b/src/notification/notification.component.ts index b8dc34aac8..4433cc01a5 100644 --- a/src/notification/notification.component.ts +++ b/src/notification/notification.component.ts @@ -9,6 +9,7 @@ import { I18n } from "carbon-components-angular/i18n"; import { NotificationDisplayService } from "./notification-display.service"; import { isObservable, of } from "rxjs"; import { BaseNotification } from "./base-notification.component"; +import { DomSanitizer, SafeHtml } from "@angular/platform-browser"; /** * Notification messages are displayed toward the top of the UI and do not interrupt user’s work. @@ -29,11 +30,21 @@ import { BaseNotification } from "./base-notification.component";
+ +
+
+ + {{ notificationObj.title }} +
- + + + + + {{ notificationObj.message }} +
@@ -65,6 +76,12 @@ export class Notification extends BaseNotification { obj.closeLabel = of(obj.closeLabel); } this._notificationObj = Object.assign({}, this.defaultNotificationObj, obj); + if (this._notificationObj.titleHtml) { + this.safeNotificationTitleHtml = this.sanitizer.bypassSecurityTrustHtml(this._notificationObj.titleHtml); + } + if (this._notificationObj.messageHtml) { + this.safeNotificationMessageHtml = this.sanitizer.bypassSecurityTrustHtml(this._notificationObj.messageHtml); + } } notificationID = `notification-${Notification.notificationCount++}`; @@ -79,7 +96,10 @@ export class Notification extends BaseNotification { @HostBinding("class.cds--inline-notification--low-contrast") get isLowContrast() { return this.notificationObj.lowContrast; } @HostBinding("class.cds--inline-notification--hide-close-button") get isCloseHidden() { return !this.notificationObj.showClose; } - constructor(protected notificationDisplayService: NotificationDisplayService, protected i18n: I18n) { + protected safeNotificationTitleHtml: SafeHtml; + protected safeNotificationMessageHtml: SafeHtml; + + constructor(protected notificationDisplayService: NotificationDisplayService, protected i18n: I18n, protected sanitizer: DomSanitizer) { super(notificationDisplayService, i18n); } } diff --git a/src/notification/notification.stories.ts b/src/notification/notification.stories.ts index 131c04db9d..ccb16e3106 100644 --- a/src/notification/notification.stories.ts +++ b/src/notification/notification.stories.ts @@ -243,3 +243,22 @@ export const CustomContent = CustomTemplate.bind({}); CustomContent.args = { showClose: true }; + +const HtmlTemplate = (args) => ({ + props: args, + template: ` + + + + `, +}); + +export const HtmlContent = HtmlTemplate.bind({}); +HtmlContent.args = { + showClose: true, +}; From 187935503be96ecfde6d7c2a1375f42662392bb8 Mon Sep 17 00:00:00 2001 From: Mohammed Fahimullah A Date: Wed, 15 Oct 2025 19:15:51 +0530 Subject: [PATCH 3/4] fix: prevent XSS by separating HTML fields from plain text --- src/notification/notification.component.ts | 4 ++-- src/notification/notification.stories.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/notification/notification.component.ts b/src/notification/notification.component.ts index 4433cc01a5..795e0b7900 100644 --- a/src/notification/notification.component.ts +++ b/src/notification/notification.component.ts @@ -32,7 +32,7 @@ import { DomSanitizer, SafeHtml } from "@angular/platform-browser"; *ngIf="!notificationObj.template" [id]="notificationID"> -
+
{{ notificationObj.title }} @@ -43,7 +43,7 @@ import { DomSanitizer, SafeHtml } from "@angular/platform-browser"; - {{ notificationObj.message }} + {{ notificationObj.message }} diff --git a/src/notification/notification.stories.ts b/src/notification/notification.stories.ts index ccb16e3106..5126126ff5 100644 --- a/src/notification/notification.stories.ts +++ b/src/notification/notification.stories.ts @@ -255,10 +255,10 @@ const HtmlTemplate = (args) => ({ showClose: showClose }"> - `, + ` }); export const HtmlContent = HtmlTemplate.bind({}); HtmlContent.args = { - showClose: true, + showClose: true }; From ae5a765b8792c1c3a6b7d79daec3c0e26a9aa6d3 Mon Sep 17 00:00:00 2001 From: Mohammed Fahimullah A Date: Wed, 15 Oct 2025 19:14:23 +0530 Subject: [PATCH 4/4] fix: prevent XSS by separating HTML fields from plain text fix: fixed lint issues fix: prevent XSS by separating HTML fields from plain text --- .../app-mock-query-search.component.ts | 4 +-- src/datepicker/datepicker.component.ts | 6 ++--- .../notification-content.interface.ts | 2 ++ src/notification/notification.component.ts | 26 ++++++++++++++++--- src/notification/notification.stories.ts | 19 ++++++++++++++ 5 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/combobox/stories/app-mock-query-search.component.ts b/src/combobox/stories/app-mock-query-search.component.ts index 9e2de3c824..788c1dee41 100644 --- a/src/combobox/stories/app-mock-query-search.component.ts +++ b/src/combobox/stories/app-mock-query-search.component.ts @@ -23,12 +23,12 @@ export class MockQueryCombobox { { content: `Random ${Math.random()}` }, { content: `Random ${Math.random()}` }, { content: `Random ${Math.random()}` }, - { content: `Random ${Math.random()}` }, + { content: `Random ${Math.random()}` } ]; // Include current selected in the list to avoid auto clear if (this.currentlySelected) { - array.push(this.currentlySelected) + array.push(this.currentlySelected); } this.filterItems = array; }, 1000); diff --git a/src/datepicker/datepicker.component.ts b/src/datepicker/datepicker.component.ts index e11ad1300d..95b587f0c3 100644 --- a/src/datepicker/datepicker.component.ts +++ b/src/datepicker/datepicker.component.ts @@ -510,8 +510,8 @@ export class DatePicker implements const calendarContainer = this.flatpickrInstance.calendarContainer; const dayElement = calendarContainer && calendarContainer.querySelector(".flatpickr-day[tabindex]"); - const selectedDateElem = calendarContainer && calendarContainer.querySelector('.selected'); - const todayDateElem = calendarContainer && calendarContainer.querySelector('.today'); + const selectedDateElem = calendarContainer && calendarContainer.querySelector(".selected"); + const todayDateElem = calendarContainer && calendarContainer.querySelector(".today"); if (dayElement) { (todayDateElem || selectedDateElem || dayElement).focus(); @@ -593,7 +593,7 @@ export class DatePicker implements // add day classes and special case the "today" element based on `this.value` Array.from(dayContainer).forEach(element => { - element.setAttribute('role', 'button'); + element.setAttribute("role", "button"); element.classList.add("cds--date-picker__day"); if (!this.value) { return; diff --git a/src/notification/notification-content.interface.ts b/src/notification/notification-content.interface.ts index 587071091e..41409769a6 100644 --- a/src/notification/notification-content.interface.ts +++ b/src/notification/notification-content.interface.ts @@ -8,11 +8,13 @@ export interface NotificationContent { [key: string]: any; type: NotificationType; title: string; + titleHtml?: string; target?: string; duration?: number; smart?: boolean; closeLabel?: any; message?: string; + messageHtml?: string; showClose?: boolean; lowContrast?: boolean; template?: TemplateRef; diff --git a/src/notification/notification.component.ts b/src/notification/notification.component.ts index b8dc34aac8..795e0b7900 100644 --- a/src/notification/notification.component.ts +++ b/src/notification/notification.component.ts @@ -9,6 +9,7 @@ import { I18n } from "carbon-components-angular/i18n"; import { NotificationDisplayService } from "./notification-display.service"; import { isObservable, of } from "rxjs"; import { BaseNotification } from "./base-notification.component"; +import { DomSanitizer, SafeHtml } from "@angular/platform-browser"; /** * Notification messages are displayed toward the top of the UI and do not interrupt user’s work. @@ -29,11 +30,21 @@ import { BaseNotification } from "./base-notification.component";
+ +
+
+ + {{ notificationObj.title }} +
- + + + + + {{ notificationObj.message }} +
@@ -65,6 +76,12 @@ export class Notification extends BaseNotification { obj.closeLabel = of(obj.closeLabel); } this._notificationObj = Object.assign({}, this.defaultNotificationObj, obj); + if (this._notificationObj.titleHtml) { + this.safeNotificationTitleHtml = this.sanitizer.bypassSecurityTrustHtml(this._notificationObj.titleHtml); + } + if (this._notificationObj.messageHtml) { + this.safeNotificationMessageHtml = this.sanitizer.bypassSecurityTrustHtml(this._notificationObj.messageHtml); + } } notificationID = `notification-${Notification.notificationCount++}`; @@ -79,7 +96,10 @@ export class Notification extends BaseNotification { @HostBinding("class.cds--inline-notification--low-contrast") get isLowContrast() { return this.notificationObj.lowContrast; } @HostBinding("class.cds--inline-notification--hide-close-button") get isCloseHidden() { return !this.notificationObj.showClose; } - constructor(protected notificationDisplayService: NotificationDisplayService, protected i18n: I18n) { + protected safeNotificationTitleHtml: SafeHtml; + protected safeNotificationMessageHtml: SafeHtml; + + constructor(protected notificationDisplayService: NotificationDisplayService, protected i18n: I18n, protected sanitizer: DomSanitizer) { super(notificationDisplayService, i18n); } } diff --git a/src/notification/notification.stories.ts b/src/notification/notification.stories.ts index 131c04db9d..5126126ff5 100644 --- a/src/notification/notification.stories.ts +++ b/src/notification/notification.stories.ts @@ -243,3 +243,22 @@ export const CustomContent = CustomTemplate.bind({}); CustomContent.args = { showClose: true }; + +const HtmlTemplate = (args) => ({ + props: args, + template: ` + + + + ` +}); + +export const HtmlContent = HtmlTemplate.bind({}); +HtmlContent.args = { + showClose: true +};