Skip to content

Commit

Permalink
made safeHtml standalone and used in all [innerHTML] bindings to stop…
Browse files Browse the repository at this point in the history
… injection
  • Loading branch information
codizen-dev committed Aug 11, 2024
1 parent 2929519 commit a4116bd
Show file tree
Hide file tree
Showing 15 changed files with 79 additions and 61 deletions.
11 changes: 6 additions & 5 deletions src/app/components/breadcrumb/breadcrumb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { ChevronRightIcon } from 'primeng/icons/chevronright';
import { HomeIcon } from 'primeng/icons/home';
import { TooltipModule } from 'primeng/tooltip';
import { BreadcrumbItemClickEvent } from './breadcrumb.interface';
import { SafeHtmlPipe } from '../dom/safeHtmlPipe';
/**
* Breadcrumb provides contextual information about page hierarchy.
* @group Components
Expand Down Expand Up @@ -41,7 +42,7 @@ import { BreadcrumbItemClickEvent } from './breadcrumb.interface';
<HomeIcon *ngIf="!home.icon" [styleClass]="'p-menuitem-icon'" />
<ng-container *ngIf="home.label">
<span *ngIf="home.escape !== false; else htmlHomeLabel" class="p-menuitem-text">{{ home.label }}</span>
<ng-template #htmlHomeLabel><span class="p-menuitem-text" [innerHTML]="home.label"></span></ng-template>
<ng-template #htmlHomeLabel><span class="p-menuitem-text" [innerHTML]="home.label | safeHtml"></span></ng-template>
</ng-container>
</a>
<a
Expand All @@ -68,7 +69,7 @@ import { BreadcrumbItemClickEvent } from './breadcrumb.interface';
<HomeIcon *ngIf="!home.icon" [styleClass]="'p-menuitem-icon'" />
<ng-container *ngIf="home.label">
<span *ngIf="home.escape !== false; else htmlHomeRouteLabel" class="p-menuitem-text">{{ home.label }}</span>
<ng-template #htmlHomeRouteLabel><span class="p-menuitem-text" [innerHTML]="home.label"></span></ng-template>
<ng-template #htmlHomeRouteLabel><span class="p-menuitem-text" [innerHTML]="home.label | safeHtml"></span></ng-template>
</ng-container>
</a>
</li>
Expand Down Expand Up @@ -101,7 +102,7 @@ import { BreadcrumbItemClickEvent } from './breadcrumb.interface';
<span *ngIf="item.icon" class="p-menuitem-icon" [ngClass]="item.icon" [ngStyle]="item.iconStyle"></span>
<ng-container *ngIf="item.label">
<span *ngIf="item.escape !== false; else htmlLabel" class="p-menuitem-text">{{ item.label }}</span>
<ng-template #htmlLabel><span class="p-menuitem-text" [innerHTML]="item.label"></span></ng-template>
<ng-template #htmlLabel><span class="p-menuitem-text" [innerHTML]="item.label | safeHtml"></span></ng-template>
</ng-container>
</ng-container>
<ng-container *ngIf="itemTemplate">
Expand Down Expand Up @@ -131,7 +132,7 @@ import { BreadcrumbItemClickEvent } from './breadcrumb.interface';
<span *ngIf="item.icon" class="p-menuitem-icon" [ngClass]="item.icon" [ngStyle]="item.iconStyle"></span>
<ng-container *ngIf="item.label">
<span *ngIf="item.escape !== false; else htmlRouteLabel" class="p-menuitem-text">{{ item.label }}</span>
<ng-template #htmlRouteLabel><span class="p-menuitem-text" [innerHTML]="item.label"></span></ng-template>
<ng-template #htmlRouteLabel><span class="p-menuitem-text" [innerHTML]="item.label | safeHtml"></span></ng-template>
</ng-container>
</ng-container>
<ng-container *ngIf="itemTemplate">
Expand Down Expand Up @@ -251,7 +252,7 @@ export class Breadcrumb implements AfterContentInit {
}

@NgModule({
imports: [CommonModule, RouterModule, TooltipModule, ChevronRightIcon, HomeIcon, SharedModule],
imports: [CommonModule, RouterModule, TooltipModule, ChevronRightIcon, HomeIcon, SharedModule, SafeHtmlPipe],
exports: [Breadcrumb, RouterModule, TooltipModule, SharedModule],
declarations: [Breadcrumb]
})
Expand Down
5 changes: 3 additions & 2 deletions src/app/components/confirmdialog/confirmdialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { RippleModule } from 'primeng/ripple';
import { Nullable } from 'primeng/ts-helpers';
import { UniqueComponentId, ZIndexUtils } from 'primeng/utils';
import { Subscription } from 'rxjs';
import { SafeHtmlPipe } from '../dom/safeHtmlPipe';

const showAnimation = animation([style({ transform: '{{transform}}', opacity: 0 }), animate('{{transition}}', style({ transform: 'none', opacity: 1 }))]);

Expand Down Expand Up @@ -78,7 +79,7 @@ const hideAnimation = animation([animate('{{transition}}', style({ transform: '{
<ng-container *ngIf="iconTemplate">
<ng-template *ngTemplateOutlet="iconTemplate"></ng-template>
</ng-container>
<span class="p-confirm-dialog-message" *ngIf="!messageTemplate" [innerHTML]="option('message')"></span>
<span class="p-confirm-dialog-message" *ngIf="!messageTemplate" [innerHTML]="option('message') | safeHtml"></span>
<ng-container *ngIf="messageTemplate">
<ng-template *ngTemplateOutlet="messageTemplate; context: { $implicit: confirmation }"></ng-template>
</ng-container>
Expand Down Expand Up @@ -761,7 +762,7 @@ export class ConfirmDialog implements AfterContentInit, OnInit, OnDestroy {
}

@NgModule({
imports: [CommonModule, ButtonModule, RippleModule, TimesIcon, CheckIcon],
imports: [CommonModule, ButtonModule, RippleModule, TimesIcon, CheckIcon, SafeHtmlPipe],
exports: [ConfirmDialog, ButtonModule, SharedModule],
declarations: [ConfirmDialog]
})
Expand Down
7 changes: 4 additions & 3 deletions src/app/components/contextmenu/contextmenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { RippleModule } from 'primeng/ripple';
import { TooltipModule } from 'primeng/tooltip';
import { Nullable, VoidListener } from 'primeng/ts-helpers';
import { ObjectUtils, UniqueComponentId, ZIndexUtils } from 'primeng/utils';
import { SafeHtmlPipe } from '../dom/safeHtmlPipe';

@Component({
selector: 'p-contextMenuSub',
Expand Down Expand Up @@ -116,7 +117,7 @@ import { ObjectUtils, UniqueComponentId, ZIndexUtils } from 'primeng/utils';
{{ getItemLabel(processedItem) }}
</span>
<ng-template #htmlLabel>
<span class="p-menuitem-text" [innerHTML]="getItemLabel(processedItem)" [attr.data-pc-section]="'label'"></span>
<span class="p-menuitem-text" [innerHTML]="getItemLabel(processedItem) | safeHtml" [attr.data-pc-section]="'label'"></span>
</ng-template>
<span class="p-menuitem-badge" *ngIf="getItemProp(processedItem, 'badge')" [ngClass]="getItemProp(processedItem, 'badgeStyleClass')">{{ getItemProp(processedItem, 'badge') }}</span>
Expand Down Expand Up @@ -159,7 +160,7 @@ import { ObjectUtils, UniqueComponentId, ZIndexUtils } from 'primeng/utils';
{{ getItemLabel(processedItem) }}
</span>
<ng-template #htmlLabel>
<span class="p-menuitem-text" [innerHTML]="getItemLabel(processedItem)" [attr.data-pc-section]="'label'"></span>
<span class="p-menuitem-text" [innerHTML]="getItemLabel(processedItem) | safeHtml" [attr.data-pc-section]="'label'"></span>
</ng-template>
<span class="p-menuitem-badge" *ngIf="getItemProp(processedItem, 'badge')" [ngClass]="getItemProp(processedItem, 'badgeStyleClass')">{{ getItemProp(processedItem, 'badge') }}</span>
Expand Down Expand Up @@ -1201,7 +1202,7 @@ export class ContextMenu implements OnInit, AfterContentInit, OnDestroy {
}

@NgModule({
imports: [CommonModule, RouterModule, RippleModule, TooltipModule, AngleRightIcon, SharedModule],
imports: [CommonModule, RouterModule, RippleModule, TooltipModule, AngleRightIcon, SharedModule, SafeHtmlPipe],
exports: [ContextMenu, RouterModule, TooltipModule, SharedModule],
declarations: [ContextMenu, ContextMenuSub]
})
Expand Down
26 changes: 26 additions & 0 deletions src/app/components/dom/safeHtmlPipe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { isPlatformBrowser } from '@angular/common';
import {
Inject, PLATFORM_ID,
Pipe,
PipeTransform,
SecurityContext
} from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';


@Pipe({
name: 'safeHtml',
standalone: true
})
export class SafeHtmlPipe implements PipeTransform {
constructor(@Inject(PLATFORM_ID) private readonly platformId: any, private readonly domSanitizer: DomSanitizer) { }

public transform(value: string): SafeHtml {
if (!value || !isPlatformBrowser(this.platformId)) {
return value;
}

const sanitizedValue = this.domSanitizer.sanitize(SecurityContext.HTML ,value);
return this.domSanitizer.bypassSecurityTrustHtml(sanitizedValue);
}
}
7 changes: 4 additions & 3 deletions src/app/components/megamenu/megamenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { RippleModule } from 'primeng/ripple';
import { TooltipModule } from 'primeng/tooltip';
import { VoidListener } from 'primeng/ts-helpers';
import { ObjectUtils, UniqueComponentId } from 'primeng/utils';
import { SafeHtmlPipe } from '../dom/safeHtmlPipe';

@Component({
selector: 'p-megaMenuSub',
Expand Down Expand Up @@ -111,7 +112,7 @@ import { ObjectUtils, UniqueComponentId } from 'primeng/utils';
{{ getItemLabel(processedItem) }}
</span>
<ng-template #htmlLabel>
<span class="p-menuitem-text" [innerHTML]="getItemLabel(processedItem)" [attr.data-pc-section]="'label'"></span>
<span class="p-menuitem-text" [innerHTML]="getItemLabel(processedItem) | safeHtml" [attr.data-pc-section]="'label'"></span>
</ng-template>
<span class="p-menuitem-badge" *ngIf="getItemProp(processedItem, 'badge')" [ngClass]="getItemProp(processedItem, 'badgeStyleClass')">{{ getItemProp(processedItem, 'badge') }}</span>
Expand Down Expand Up @@ -153,7 +154,7 @@ import { ObjectUtils, UniqueComponentId } from 'primeng/utils';
[attr.tabindex]="-1"
></span>
<span class="p-menuitem-text" *ngIf="getItemProp(processedItem, 'escape'); else htmlRouteLabel">{{ getItemLabel(processedItem) }}</span>
<ng-template #htmlRouteLabel><span class="p-menuitem-text" [innerHTML]="getItemLabel(processedItem)" [attr.data-pc-section]="'label'"></span></ng-template>
<ng-template #htmlRouteLabel><span class="p-menuitem-text" [innerHTML]="getItemLabel(processedItem) | safeHtml" [attr.data-pc-section]="'label'"></span></ng-template>
<span class="p-menuitem-badge" *ngIf="getItemProp(processedItem, 'badge')" [ngClass]="getItemProp(processedItem, 'badgeStyleClass')">{{ getItemProp(processedItem, 'badge') }}</span>
<ng-container *ngIf="isItemGroup(processedItem)">
<ng-container *ngIf="!megaMenu.submenuIconTemplate">
Expand Down Expand Up @@ -1077,7 +1078,7 @@ export class MegaMenu implements AfterContentInit, OnDestroy, OnInit {
}

@NgModule({
imports: [CommonModule, RouterModule, RippleModule, TooltipModule, SharedModule, AngleDownIcon, AngleRightIcon],
imports: [CommonModule, RouterModule, RippleModule, TooltipModule, SharedModule, AngleDownIcon, AngleRightIcon, SafeHtmlPipe],
exports: [MegaMenu, RouterModule, TooltipModule, SharedModule],
declarations: [MegaMenu, MegaMenuSub]
})
Expand Down
23 changes: 2 additions & 21 deletions src/app/components/menu/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,44 +13,25 @@ import {
OnDestroy,
Output,
PLATFORM_ID,
Pipe,
PipeTransform,
QueryList,
Renderer2,
TemplateRef,
ViewChild,
ViewEncapsulation,
ViewRef,
booleanAttribute,
computed,
effect,
forwardRef,
numberAttribute,
signal
} from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { RouterModule } from '@angular/router';
import { MenuItem, OverlayService, PrimeNGConfig, PrimeTemplate, SharedModule } from 'primeng/api';
import { ConnectedOverlayScrollHandler, DomHandler } from 'primeng/dom';
import { RippleModule } from 'primeng/ripple';
import { TooltipModule } from 'primeng/tooltip';
import { Nullable, VoidListener } from 'primeng/ts-helpers';
import { UniqueComponentId, ZIndexUtils } from 'primeng/utils';

@Pipe({
name: 'safeHtml'
})
export class SafeHtmlPipe implements PipeTransform {
constructor(@Inject(PLATFORM_ID) private readonly platformId: any, private readonly sanitizer: DomSanitizer) {}

public transform(value: string): SafeHtml {
if (!value || !isPlatformBrowser(this.platformId)) {
return value;
}

return this.sanitizer.bypassSecurityTrustHtml(value);
}
}
import { SafeHtmlPipe } from '../dom/safeHtmlPipe';

@Component({
selector: '[pMenuItemContent]',
Expand Down Expand Up @@ -824,6 +805,6 @@ export class Menu implements OnDestroy {
@NgModule({
imports: [CommonModule, RouterModule, RippleModule, TooltipModule, SharedModule],
exports: [Menu, RouterModule, TooltipModule, SharedModule],
declarations: [Menu, MenuItemContent, SafeHtmlPipe]
declarations: [Menu, MenuItemContent]
})
export class MenuModule {}
7 changes: 4 additions & 3 deletions src/app/components/menubar/menubar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import { VoidListener } from 'primeng/ts-helpers';
import { ObjectUtils, UniqueComponentId, ZIndexUtils } from 'primeng/utils';
import { Subject, Subscription, interval } from 'rxjs';
import { debounce, filter } from 'rxjs/operators';
import { SafeHtmlPipe } from '../dom/safeHtmlPipe';

@Injectable()
export class MenubarService {
Expand Down Expand Up @@ -125,7 +126,7 @@ export class MenubarService {
{{ getItemLabel(processedItem) }}
</span>
<ng-template #htmlLabel>
<span class="p-menuitem-text" [innerHTML]="getItemLabel(processedItem)" [attr.data-pc-section]="'label'" [id]="getItemLabelId(processedItem)"></span>
<span class="p-menuitem-text" [innerHTML]="getItemLabel(processedItem) | safeHtml" [attr.data-pc-section]="'label'" [id]="getItemLabelId(processedItem)"></span>
</ng-template>
<span class="p-menuitem-badge" *ngIf="getItemProp(processedItem, 'badge')" [ngClass]="getItemProp(processedItem, 'badgeStyleClass')">{{ getItemProp(processedItem, 'badge') }}</span>
Expand Down Expand Up @@ -165,7 +166,7 @@ export class MenubarService {
[attr.tabindex]="-1"
></span>
<span class="p-menuitem-text" *ngIf="getItemProp(processedItem, 'escape'); else htmlRouteLabel">{{ getItemLabel(processedItem) }}</span>
<ng-template #htmlRouteLabel><span class="p-menuitem-text" [innerHTML]="getItemLabel(processedItem)" [attr.data-pc-section]="'label'"></span></ng-template>
<ng-template #htmlRouteLabel><span class="p-menuitem-text" [innerHTML]="getItemLabel(processedItem) | safeHtml" [attr.data-pc-section]="'label'"></span></ng-template>
<span class="p-menuitem-badge" *ngIf="getItemProp(processedItem, 'badge')" [ngClass]="getItemProp(processedItem, 'badgeStyleClass')">{{ getItemProp(processedItem, 'badge') }}</span>
<ng-container *ngIf="isItemGroup(processedItem)">
<ng-container *ngIf="!menubar.submenuIconTemplate">
Expand Down Expand Up @@ -1124,7 +1125,7 @@ export class Menubar implements AfterContentInit, OnDestroy, OnInit {
}

@NgModule({
imports: [CommonModule, RouterModule, RippleModule, TooltipModule, SharedModule, BarsIcon, AngleDownIcon, AngleRightIcon],
imports: [CommonModule, RouterModule, RippleModule, TooltipModule, SharedModule, BarsIcon, AngleDownIcon, AngleRightIcon, SafeHtmlPipe],
exports: [Menubar, RouterModule, TooltipModule, SharedModule],
declarations: [Menubar, MenubarSub]
})
Expand Down
5 changes: 3 additions & 2 deletions src/app/components/message/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { CheckIcon } from 'primeng/icons/check';
import { ExclamationTriangleIcon } from 'primeng/icons/exclamationtriangle';
import { InfoCircleIcon } from 'primeng/icons/infocircle';
import { TimesCircleIcon } from 'primeng/icons/timescircle';
import { SafeHtmlPipe } from '../dom/safeHtmlPipe';
/**
* Message groups a collection of contents in tabs.
* @group Components
Expand All @@ -17,7 +18,7 @@ import { TimesCircleIcon } from 'primeng/icons/timescircle';
<TimesCircleIcon *ngIf="icon === 'error'" [styleClass]="'p-inline-message-icon'" />
<ExclamationTriangleIcon *ngIf="icon === 'warn'" [styleClass]="'p-inline-message-icon'" />
<div *ngIf="!escape; else escapeOut">
<span *ngIf="!escape" class="p-inline-message-text" [innerHTML]="text"></span>
<span *ngIf="!escape" class="p-inline-message-text" [innerHTML]="text | safeHtml"></span>
</div>
<ng-template #escapeOut>
<span *ngIf="escape" class="p-inline-message-text">{{ text }}</span>
Expand Down Expand Up @@ -75,7 +76,7 @@ export class UIMessage {
}

@NgModule({
imports: [CommonModule, CheckIcon, InfoCircleIcon, TimesCircleIcon, ExclamationTriangleIcon],
imports: [CommonModule, CheckIcon, InfoCircleIcon, TimesCircleIcon, ExclamationTriangleIcon, SafeHtmlPipe],
exports: [UIMessage],
declarations: [UIMessage]
})
Expand Down
7 changes: 4 additions & 3 deletions src/app/components/messages/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { TimesIcon } from 'primeng/icons/times';
import { TimesCircleIcon } from 'primeng/icons/timescircle';
import { RippleModule } from 'primeng/ripple';
import { Subscription, timer } from 'rxjs';
import { SafeHtmlPipe } from '../dom/safeHtmlPipe';
/**
* Messages is used to display alerts inline.
* @group Components
Expand All @@ -53,8 +54,8 @@ import { Subscription, timer } from 'rxjs';
</ng-container>
</span>
<ng-container *ngIf="!escape; else escapeOut">
<span *ngIf="msg.summary" class="p-message-summary" [innerHTML]="msg.summary" [attr.data-pc-section]="'summary'"></span>
<span *ngIf="msg.detail" class="p-message-detail" [innerHTML]="msg.detail" [attr.data-pc-section]="'detail'"></span>
<span *ngIf="msg.summary" class="p-message-summary" [innerHTML]="msg.summary | safeHtml" [attr.data-pc-section]="'summary'"></span>
<span *ngIf="msg.detail" class="p-message-detail" [innerHTML]="msg.detail | safeHtml" [attr.data-pc-section]="'detail'"></span>
</ng-container>
<ng-template #escapeOut>
<span *ngIf="msg.summary" class="p-message-summary" [attr.data-pc-section]="'summary'">{{ msg.summary }}</span>
Expand Down Expand Up @@ -287,7 +288,7 @@ export class Messages implements AfterContentInit, OnDestroy {
}

@NgModule({
imports: [CommonModule, RippleModule, CheckIcon, InfoCircleIcon, TimesCircleIcon, ExclamationTriangleIcon, TimesIcon],
imports: [CommonModule, RippleModule, CheckIcon, InfoCircleIcon, TimesCircleIcon, ExclamationTriangleIcon, TimesIcon, SafeHtmlPipe],
exports: [Messages],
declarations: [Messages]
})
Expand Down
Loading

0 comments on commit a4116bd

Please sign in to comment.