DomSanitizer doesn't parse text to HTML - html

I am working on an Angular project and I am taking data from a database where it has data with HTML tags. To put it in the HTML I can do that through this code:
[innerHTML]="element.texto"
What Im looking for is to use it on the ts to put the text on a pdf. Im using DomSanitizer but the output is wrong and does not transform it on the HTML. This is the exaple code im using:
import { DomSanitizer } from "#angular/platform-browser";
///
constructor(
private sanitizer:DomSanitizer
) { }
dataTransformer() {
let textoHTML = "<p>Hello <b>World</b></p>"
alert(this.sanitizer.bypassSecurityTrustHtml(textoHTML)) //It shows: SafeValue must use [property]=binding: <p>Hello <b>World</b></p> (see http://g.co/ng/security#xss)
}
In the other hand, I have used the following code for parseing the code but with a wrong solution.
this.sanitizer.bypassSecurityTrustHtml(textoHTML)['changingThisBreaksApplicationSecurity'] //It shows: <p>Hello <b>World</b></p>
What im looking for is: Hello World
Thanks!

you can use pipe
[innerHTML]="element.texto | safeHtml "
import { Pipe, PipeTransform } from '#angular/core';
import { DomSanitizer, SafeHtml } from '#angular/platform-browser';
#Pipe({
name: 'safeHtml',
pure: false
})
export class SafeHtmlPipe implements PipeTransform {
constructor(protected sanitizer: DomSanitizer) {
}
transform(value: any): SafeHtml {
return this.sanitizer.bypassSecurityTrustHtml(value);
}
}

#erfan-farhadi has given a reusable code.
Use the following as quick fix
Change your ts file to something like this
import { DomSanitizer } from "#angular/platform-browser";
sanitizedValue: undefined; // member var to hold sanitized HTML
constructor(
private sanitizer:DomSanitizer
) { }
dataTransformer() {
let textoHTML = "<p>Hello <b>World</b></p>"
this.sanitizedValue = this.sanitizer.bypassSecurityTrustHtml(textoHTML));
}
/// ...
In html template use like following
[innerHTML]="sanitizedValue"

Related

ViewEncapsulation.None not working with innertHTML

I'm actually developing an angular application and I have to put an [innerHTML] element in a div.
My code
Like that :
something.component.html
<section class="mx-auto" *ngFor="let publication of publication">
<div [innerHTML]="publication.content"></div>
</section>
So in ts :
something.component.ts
import { Component, OnInit, ViewEncapsulation } from '#angular/core';
import { Subscription } from 'rxjs';
import { ActivatedRoute } from '#angular/router';
import { Title, Meta } from '#angular/platform-browser';
import { Publication } from '../publication.model';
import { PublicationsService } from '../publication.service';
#Component({
selector: 'app-free-publication',
templateUrl: './something.component.html',
styleUrls: ['./something.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class FreePublicationComponent implements OnInit {
publication: Publication[] = [];
suggestions: Publication[] = [];
private routeSub: Subscription;
getId: any;
isLoading = false;
constructor(public publicationsService: PublicationsService, private route: ActivatedRoute, private titleService: Title, private meta: Meta) {
this.getId = this.route.url['_value'][1].path;
this.getId = + this.getId;
}
ngOnInit() {
this.isLoading = true;
// main publication
this.routeSub = this.route.params.subscribe(params => {
this.publicationsService.getPublication(params['publicationId']).then(dataPublication => {
for (let i = 0; (dataPublication.content.match(/wp-content/g) || []).length; i++) {
dataPublication.content = dataPublication.content.replace('https://aurelienbamde.com/wp-content/', 'assets/content/');
}
this.titleService.setTitle(dataPublication.title);
this.meta.addTag({ name: 'keywords', content: dataPublication.post_tag });
this.publication = [dataPublication];
});
});
}
}
And my innertHTML do not return the style of the html doc that I send.
My tests
With a console.log() at the end of ngOnInit, I can see my html with all of the styles attributs, but by inspecting the div of the innerHTML, there is no style inside.
My question
So I well implement ViewEncapsulation.None as you see, there is an action on other elements, so it works, but not on my innerHTML.
Do you have any idea, problem of version ? Or coworking with others elements ?
Thanks in advance for your time !
And I wish you success in your projects.
You must bypass the security imposed by angular for dangerous content (HTML content not generated by the app). There is a service, called DomSanitizer that enables you to declare a content as safe, preventing angular to filter potentially harm things to be used like styles, classes, tags etc. You basically need to pass your content through this sanitizer using a pipe:
<div [innerHTML]="dangerousContent | safeHtml"></div>
Your SafeHtmlPipe would be something like this:
#Pipe({name: 'safeHtml'})
export class SafeHtmlPipe implements PipeTransform {
constructor(protected sanitizer: DomSanitizer) {}
transform(value: string): SafeHtml {
return this.sanitizer.bypassSecurityTrustHtml(value)
}
}
There are other bypassSecurityTrust* methods in DomSanitizer:
bypassSecurityTrustScript
bypassSecurityTrustStyle
bypassSecurityTrustUrl
bypassSecurityTrustResourceUrl
You can find more info in Angular docs.

Angular Inject custom tag in innerHTML

Text with custom tag to inject inside innerHtml:
const test = '<FREEZE> the image. Then try again.'
<td [innerHtml]="test | htmlEscape"></td>
I am using a custom pipe to disable Angular's built-in sanitization for the provided value.
custom-pipe.ts
#Pipe({
name: 'htmlEscape'
})
export class HtmlEscapePipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) {
}
transform(content: string): SafeHtml {
if (!content) {
return null;
}
const t = this.sanitizer.bypassSecurityTrustHtml(content);
return t;
}
}
Unfortunately <FREEZE> tag inside the string is stripped out. Any suggestions would be appreciate it.

How do i write a function that detects and replaces urls in a loaded JSON?

Im trying to write a function that replaces all urls in a Json with a button that leads to another function. The loaded Json with the buttons is shown on my website then.
In my component.ts the part where a Json is detected looks like that:
} else {
this.downloading = false;
this.container = <aContainer>json;
this.loadedJson = JSON.stringify(json, null, 2);
And in the component.html the JSON gets shown on my website:
h3>Unrecognized JSON data:</h3>
<pre>{{loadedJson}}</pre>
I wanted to try it with a regExp like that to replace everything with the string: url://
let regExp = /url:\/\//
Does anybody know how i can implement code that recognizes the urls and than replaces them with a button that leads to antoher function?
Thank You!
You can create a pipe to transform the loadedJSON like below and [innerHTML] property binding
import { PipeTransform, Pipe } from "#angular/core";
import { DomSanitizer } from "#angular/platform-browser";
#Pipe({
name: "transformURL",
pure: false
})
export class TransformURLPipe implements PipeTransform {
constructor(protected sanitizer: DomSanitizer) { }
transform(value: any): any {
if (value.length === 0) {
return value;
}
return this.sanitizer.bypassSecurityTrustHtml(
value.replace(/url:\/\//g, "<button type='button'>Test</button>")
);
}
}
HTML
<p [innerHTML]=" loadedJSON | transformURL"></p>

Display view from external HTML

I would like to display a view on page from HTML from external database using Angular 2.
For example I have a html string in component.ts like below:
htmlString = '<div style="color: red">Hello world!</div>';
And this is my html file:
<div [innerHTML]="htmlString"></div>
Instead to get red font "Hello word!" sentence it returns me only tags on my page. How can I fix this issue?
i think you also need to put a pipe to allow html in string (safe html) ..
something like:
import { Pipe, PipeTransform } from '#angular/core';
import { DomSanitizer } from '#angular/platform-browser';
#Pipe({
name: 'safeHtml'
})
export class SafeHtmlPipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) { }
transform(value: any, args?: any): any {
return this.sanitizer.bypassSecurityTrustHtml(value);
}
}
and use like this:
<div [innerHTML]="htmlString | safeHtml"></div>

Angular 5 DomSanitizer with Hyperlinks

I am using a WYSIWYG editor (CKEditor) and trying to render the content with Angular 5.
What I am trying to figure out is the proper way to use DomSanitizer in Angular 5. The problem I am facing is that Hyperlinks are not working (are not "clickable") in the resulting sanitized HTML.
I am using the following Typescript code to return a safeHtml content:
public getSafeContent(): SafeHtml {
return this.sanitizer.bypassSecurityTrustHtml(this.page.content);
}
and using it in my template this way:
<div [innerHTML]="getSafeContent()"></div>
This will render the HTML with all inline styles intact, but hyperlinks won't work.
I tried doing this instead:
public getSafeContent(): SafeHtml {
return this.sanitizer.sanitize(SecurityContext.HTML, this.page.content);
}
Which results in that Hyperlinks actually works, but inlines styles are not.
Is there a way to get both styles and hyperlinks to work with sanitized content?
Update
This is what the page looks like in Chrome dev tools:
<div _ngcontent-c22="" class="row">
<div _ngcontent-c22="" class="col-lg-12">
<div _ngcontent-c22="">
<p>google</p>
</div>
</div>
</div>
and the google link is not clickable.
bypassSecurityTrustHtml allows <script> tags in the content. For URLs you need bypassSecurityTrustUrl. See here: https://angular.io/api/platform-browser/DomSanitizer#bypassSecurityTrustUrl.
I've never tried stacking the bypassXXX methods, so I don't know if you can do something like this bypassSecurityTrustUrl(bypassSecurityTrustHtml(myContent)) but I would guess probably not since each method takes a string but returns an object (of type SafeHtml/SafeUrl), so it can't be used as the input to the stacked function call which expects a string.
So, you may need to parse the contents, pass each URL into the bypassSecurityTrustUrl and then combine everything back together again.
Update
I just looked at the sanitize method. I haven't tried this, but something like this might work:
this.sanitizer.sanitize(SecurityContext.HTML, this.sanitizer.bypassSecurityTrustUrl(myContent));
since sanitize can take a SafeValue as an input. The inner bypassSecurityTrustUrl sanitizes the URLs and returns a SafeUrl, which is unwrapped by the outer sanitize and used as input to make it HTML safe. Like I said, I haven't tried it, but it looks good in theory...
in .ts pipe for 'URL' sanitizer
import { Component, Pipe, PipeTransform } from '#angular/core';
import { DomSanitizer } from '#angular/platform-browser';
#Pipe({ name: 'sanitizeUrl' })
export class SafeUrlPipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) {}
transform(url) {
return this.sanitizer.bypassSecurityTrustResourceUrl(url);
}
}
in .html
<div [innerHTML]="Content | sanitizeUrl| sanitizeHtml">
</div>
pipe for 'HTML' sanitizer
import { Component, Pipe, PipeTransform } from '#angular/core';
import { DomSanitizer } from '#angular/platform-browser';
#Pipe({
name: 'sanitizeHtml'
})
export class SafeHtmlPipe implements PipeTransform {
constructor(private sanitized: DomSanitizer) {}
transform(value) {
return this.sanitized.bypassSecurityTrustHtml(value);
}
}
Please consider the above solution. this will apply both pipes without disturbing any style and link click event at same time
I used DOMPurify library to sanitize the DOM. DOMPurify is a DOM-only, super-fast, uber-tolerant XSS sanitizer for HTML, MathML and SVG.
I created angular PureTextPipe pipe to sanitize the raw content
import { Pipe, PipeTransform } from '#angular/core';
import DOMPurify from 'dompurify';
#Pipe({
name: 'pureText',
pure: true
})
export class PureTextPipe implements PipeTransform {
transform(str: any): any {
let res = str;
if (str === null || str === undefined || str === '' || str === 0) {
res = '--';
}
return DOMPurify.sanitize(res);
}
}
Now to use this pipe you just need to add it to HTML like:
<div [innerHTML]="yourRawData | pureText"></div>
Documentation of DOMPurify at
https://www.npmjs.com/package/dompurify
import DOMPurify from 'dompurify';
var clean = DOMPurify.sanitize(dirty);
I have found a working solution to this. With this both the URL and the style would work. It is again with the use of "bypassSecurityTrustHtml". It's surprising how using this in html or TS does not make the link work, but using this in a seperate file as a pipe makes this work like a charm.
Here is what I did
Create a Custom Pipe
.safe.dom.pipe
import { Component, Pipe, PipeTransform } from '#angular/core';
import { DomSanitizer, SafeHtml, SafeResourceUrl, SafeScript, SafeStyle, SafeUrl } from '#angular/platform-browser';
#Pipe({
name: 'safeDom'
})
export class SafeDomPipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) {}
public transform(value: any, type: string): SafeHtml | SafeStyle | SafeScript | SafeUrl | SafeResourceUrl {
switch (type) {
case 'html': return this.sanitizer.bypassSecurityTrustHtml(value);
case 'style': return this.sanitizer.bypassSecurityTrustStyle(value);
case 'script': return this.sanitizer.bypassSecurityTrustScript(value);
case 'url': return this.sanitizer.bypassSecurityTrustUrl(value);
case 'resourceUrl': return this.sanitizer.bypassSecurityTrustResourceUrl(value);
default: throw new Error(`Invalid safe type specified: ${type}`);
}
}
}`
In Case you have a common module in your project that is included where you require to implement it, you can declare and export this package from there. Else just declare this pipe in the module you want to implement this.
import { SafeDomPipe } from './pipes/safe.dom.pipe';
#NgModule({
imports: [
.....
],
exports: [
....
SafeDomPipe
....
],
declarations: [
....
SafeDomPipe
....
])
Now in Html you can directly use this pipe.
<div [innerHtml]="data | safeDom: 'html' "> </div>
This would allow both link and style.
If you're data content is consisting of HTML with Hyperlinks. But we want to sanitize with hyperlink working. This worked for me:
HTML
<div [innerHTML]="getSafeContent()"></div>
TS:
public getSafeContent(): SafeHtml {
return this.sanitizer.sanitize(SecurityContext.HTML, this.page.content);
}
This works for me:
Component:
content = '<b>Hello World</b><p style=\'font-size:14pt\'>
<a href=\'http://www.google.com\'>Go to Google</a></p>Test123';
public getSafeContent(): SafeHtml {
return this.sanitizer.bypassSecurityTrustHtml(this.content);
}
HTML:
<div [innerHTML]="getSafeContent()"></div>
Link works and inline styles are intact