Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2 - Expected safevalue must use [property] = binding

I am writing a test for a SafePipe. The method uses bypassSecurityTrustResourceUrl() . I searched the available solutions and tried them but unfortunately, it didn't help me. The error is

Expected SafeValue must use [property]=binding: Cross (see http://g.co/ng/security#xss) to be 'Cross site Request'.

What's wrong I am doing here?

import {Pipe, PipeTransform} from "@angular/core";
import {DomSanitizer} from "@angular/platform-browser";

@Pipe({name: 'safe'})
 export class SafePipe implements PipeTransform {
  constructor(private sanitizer: DomSanitizer) {
 }

 public transform(url: string): any {
   return this.sanitizer.bypassSecurityTrustResourceUrl(url);
 }
}

Test is:

import {SafePipe} from './safe.pipe';
import {DomSanitizer} from "@angular/platform-browser";
import {DomSanitizerImpl} from "@angular/platform-browse/src/security/dom_sanitization_service";

fdescribe('SafePipe', () => {
  let pipe: SafePipe;
  let sanitizer: DomSanitizer = new DomSanitizerImpl();
  beforeEach(() => {
    pipe = new SafePipe(sanitizer);
  });

  it('should transform', () => {
    expect(pipe.transform("Cross <script>alert('Hello')</script>")).toBe("Cross alert('Hello')");
  });
});
like image 354
user3520629 Avatar asked Jul 26 '17 05:07

user3520629


2 Answers

sanitizer.bypassSecurityTrustResourceUrl method returns SafeResourceUrlImpl class and you can't convert it to string (jasmine is trying to convert it internally).

abstract class SafeValueImpl implements SafeValue {
  constructor(public changingThisBreaksApplicationSecurity: string) {
    // empty
  }

  abstract getTypeName(): string;

  toString() {
    return `SafeValue must use [property]=binding: ${this.changingThisBreaksApplicationSecurity}` +
        ` (see http://g.co/ng/security#xss)`;
  }
}

You should use DomSanitizer.sanitize method instead (Angular uses it when applies property like [url]="value | safe")

it('should transform', () => {
  const safeResourceUrl = pipe.transform("Cross <script>alert('Hello')</script>");
  const sanitizedValue = sanitizer.sanitize(SecurityContext.RESOURCE_URL, safeResourceUrl);

  expect(sanitizedValue).toBe("Cross <script>alert('Hello')</script>");
});

PS. Here I assume you have typo in toBe statement, and that you are expecting string will save script tags.

Complete example you can find in Plunker

like image 152
yurzui Avatar answered Oct 16 '22 13:10

yurzui


A slight variation on the accepted answer: compare the SafeValue output of your pipe to the sanitised expected value:

import { RichtextPipe } from './richtext.pipe';
import {BrowserModule, DomSanitizer} from "@angular/platform-browser";
import {TestBed} from "@angular/core/testing";

describe('RichtextPipe', () => {
  let domSanitizer: DomSanitizer;
  let pipe: RichtextPipe;

  beforeEach(() => {
    TestBed
      .configureTestingModule({
        imports: [
          BrowserModule
        ]
      });
    domSanitizer = TestBed.get(DomSanitizer);
    pipe = new RichtextPipe(domSanitizer);
  });

  it('should convert EventPage page link', () => {
    // Setup
    const html = '<a id="1" linktype="page" pagetype="EventPage">foo</a>';

    // Test
    const result = pipe.transform(html); 

    // Assert
    const expected = domSanitizer.bypassSecurityTrustHtml('<a routerLink="/events/1">foo</a>');
    expect(result).toEqual(expected);
  });


});

In this example, the RichtextPipe uses bypassSecurityTrustHtml to transform the output. If your pipe uses a different bypass method then you probably should use the same method on the expected value.

like image 2
Greg Brown Avatar answered Oct 16 '22 14:10

Greg Brown