Skip to content

Commit

Permalink
Sanitize html (#110)
Browse files Browse the repository at this point in the history
  • Loading branch information
jfcere authored Oct 12, 2018
1 parent f291227 commit 0757442
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 7 deletions.
1 change: 1 addition & 0 deletions lib/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"peerDependencies": {
"@angular/common": "^6.0.0-rc.0 || ^6.0.0",
"@angular/core": "^6.0.0-rc.0 || ^6.0.0",
"@angular/platform-browser": "^6.0.0-rc.0 || ^6.0.0",
"core-js": "^2.5.4",
"rxjs": "^6.0.0",
"zone.js": "^0.8.26"
Expand Down
38 changes: 37 additions & 1 deletion lib/src/markdown.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { TestBed } from '@angular/core/testing';
import { BrowserModule, DomSanitizer } from '@angular/platform-browser';
import { parse } from 'marked';

import { SecurityContext } from '@angular/core';
import { MarkdownService } from './markdown.service';
import { MarkedOptions } from './marked-options';

// Prism mock
declare var Prism: any;

describe('MarkdowService', () => {
let domSanitizer: DomSanitizer;
let http: HttpTestingController;
let markdownService: MarkdownService;

beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
imports: [
BrowserModule,
HttpClientTestingModule,
],
providers: [
{ provide: MarkedOptions, useValue: {} },
MarkdownService,
Expand All @@ -23,6 +29,7 @@ describe('MarkdowService', () => {
});

beforeEach(() => {
domSanitizer = TestBed.get(DomSanitizer);
http = TestBed.get(HttpTestingController);
markdownService = TestBed.get(MarkdownService);
});
Expand Down Expand Up @@ -108,6 +115,35 @@ describe('MarkdowService', () => {
expect(markdownService.compile(mockRaw, null)).toBe(expected);
expect(markdownService.compile(mockRaw, undefined)).toBe(expected);
});

it('should sanitize when markedOptions.sanitize is true and no sanitizer function is provided', () => {

const markedOptions: MarkedOptions = { sanitize: true };
const mockRaw = '### Markdown-x';
const sanitized = domSanitizer.sanitize(SecurityContext.HTML, parse(mockRaw));
const unsanitized = parse(mockRaw);

expect(markdownService.compile(mockRaw, false, markedOptions)).toBe(sanitized);
expect(markdownService.compile(mockRaw, false, markedOptions)).not.toBe(unsanitized);
});

it('should not sanitize when markedOptions.sanitize is true but a sanitizer function is provided', () => {

const markedOptions: MarkedOptions = { sanitize: true, sanitizer: () => null };
const mockRaw = '### Markdown-x';
const expected = parse(mockRaw);

expect(markdownService.compile(mockRaw, false, markedOptions)).toBe(expected);
});

it('should not sanitize when markedOptions.sanitize is false regardless of whether a sanitizer function is provided or not', () => {

const mockRaw = '### Markdown-x';
const expected = parse(mockRaw);

expect(markdownService.compile(mockRaw, false, { sanitize: false })).toBe(expected);
expect(markdownService.compile(mockRaw, false, { sanitize: false, sanitizer: () => null })).toBe(expected);
});
});

describe('getSource', () => {
Expand Down
14 changes: 8 additions & 6 deletions lib/src/markdown.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { HttpClient } from '@angular/common/http';
import { Injectable, Optional } from '@angular/core';
import { Injectable, Optional, SecurityContext } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import { parse, Renderer } from 'marked';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
Expand All @@ -15,15 +16,14 @@ export const errorSrcWithoutHttpClient = '[ngx-markdown] When using the [src] at

@Injectable()
export class MarkdownService {
get renderer(): Renderer {
return this.options.renderer;
}
get renderer(): Renderer { return this.options.renderer; }
set renderer(value: marked.Renderer) {
this.options.renderer = value;
}

constructor(
@Optional() private http: HttpClient,
private domSanitizer: DomSanitizer,
public options: MarkedOptions,
) {
if (!this.renderer) {
Expand All @@ -33,16 +33,18 @@ export class MarkdownService {

compile(markdown: string, decodeHtml = false, markedOptions = this.options): string {
const precompiled = this.precompile(markdown);
return parse(
const compiled = parse(
decodeHtml ? this.decodeHtml(precompiled) : precompiled,
markedOptions);
return markedOptions.sanitize && !markedOptions.sanitizer
? this.domSanitizer.sanitize(SecurityContext.HTML, compiled)
: compiled;
}

getSource(src: string): Observable<string> {
if (!this.http) {
throw new Error(errorSrcWithoutHttpClient);
}

return this.http
.get(src, { responseType: 'text' })
.pipe(map(markdown => this.handleExtension(src, markdown)));
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"build:lib": "ng build lib",
"postbuild:lib": "cpx ./README.md ./dist/lib",
"link:lib": "rimraf node_modules/ngx-markdown && linklocal",
"lint": "yarn lint:lib && yarn lint:demo",
"lint:demo": "ng lint demo",
"lint:lib": "ng lint lib",
"lint:ci": "ng lint lib --format checkstyle > tslint.xml",
Expand Down

0 comments on commit 0757442

Please sign in to comment.