Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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><a href="http://www.google.com">google</a></p>
        </div>
    </div>
</div>

and the google link is not clickable.

like image 798
user2845798 Avatar asked Dec 13 '17 08:12

user2845798


Video Answer


2 Answers

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...

like image 182
TimTheEnchanter Avatar answered Sep 20 '22 12:09

TimTheEnchanter


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

like image 39
Sahil Ralkar Avatar answered Sep 17 '22 12:09

Sahil Ralkar