Parcourir la source

Use sanitize-html, create a Sanitizer class and a defaultSanitizer instance with Jupyter defaults.

A. Darian il y a 8 ans
Parent
commit
d04d2a634d

+ 1 - 1
package.json

@@ -33,7 +33,7 @@
     "phosphor-signaling": "^1.2.0",
     "phosphor-tabs": "^1.0.0-rc.2",
     "phosphor-widget": "^1.0.0-rc.1",
-    "sanitizer": "^0.1.3",
+    "sanitize-html": "^1.12.0",
     "simulate-event": "^1.2.0",
     "xterm": "^0.33.0"
   },

+ 15 - 8
src/notebook/output-area/widget.ts

@@ -25,10 +25,6 @@ import {
   Widget
 } from 'phosphor-widget';
 
-import {
-  sanitize
-} from 'sanitizer';
-
 import {
   nbformat
 } from '../notebook/nbformat';
@@ -37,6 +33,10 @@ import {
   OutputAreaModel
 } from './model';
 
+import {
+  defaultSanitizer
+} from '../../sanitizer';
+
 
 /**
  * The class name added to an output area widget.
@@ -589,12 +589,17 @@ class OutputWidget extends Widget {
       bundle = (output as nbformat.IDisplayData).data;
       break;
     case 'stream':
-      bundle = {'application/vnd.jupyter.console-text': (output as nbformat.IStream).text};
+      bundle = {
+        'application/vnd.jupyter.console-text': (output as nbformat.IStream).text
+      };
       break;
     case 'error':
       let out: nbformat.IError = output as nbformat.IError;
       let traceback = out.traceback.join('\n');
-      bundle = {'application/vnd.jupyter.console-text': traceback || `${out.ename}: ${out.evalue}`};
+      bundle = {
+        'application/vnd.jupyter.console-text': traceback ||
+          `${out.ename}: ${out.evalue}`
+      };
       break;
     default:
       console.error(`Unrecognized output type: ${output.output_type}`);
@@ -632,9 +637,11 @@ class OutputWidget extends Widget {
       } else if (sanitizable.indexOf(key) !== -1) {
         let out = map[key];
         if (typeof out === 'string') {
-          map[key] = sanitize(out);
+          map[key] = defaultSanitizer.sanitize(out);
         } else {
-          console.log('Ignoring unsanitized ' + key + ' output; could not sanitize because output is not a string.');
+          let message = 'Ignoring unsanitized ' + key +
+            ' output; could not sanitize because output is not a string.';
+          console.log(message);
           delete map[key];
         }
       } else {

+ 1 - 1
src/notebook/typings.d.ts

@@ -1,5 +1,5 @@
 /// <reference path="../../typings/es6-promise/es6-promise.d.ts"/>
-/// <reference path="../../typings/sanitizer/sanitizer.d.ts"/>
+/// <reference path="../../typings/sanitize-html/sanitize-html.d.ts"/>
 /// <reference path="../../typings/codemirror/codemirror.d.ts"/>
 /// <reference path="../../typings/diff-match-patch/diff-match-patch.d.ts"/>
 /// <reference path="../../typings/mathjax/mathjax.d.ts"/>

+ 9 - 22
src/renderers/index.ts

@@ -20,31 +20,17 @@ import {
   Message
 } from 'phosphor-messaging';
 
-import {
-  sanitize
-} from 'sanitizer';
-
 import {
   typeset, removeMath, replaceMath
 } from './latex';
 
-class MarkedRenderer extends marked.Renderer {
-  link(href: string, title: string, text: string): string {
-    let output = super.link(href, title, text);
-    if (!output) {
-      return output;
-    }
-    if (0 === href.indexOf('//') || href.indexOf(':') > -1) {
-      return output.replace('href=', 'rel="nofollow" href=');
-    }
-    return output;
-  }
-}
+import {
+  defaultSanitizer
+} from '../sanitizer';
+
 
-marked.setOptions({
-  renderer: new MarkedRenderer(),
-  sanitize: true
-});
+// Support GitHub flavored Markdown, leave sanitizing to external library.
+marked.setOptions({ gfm: true, sanitize: false });
 
 
 /**
@@ -192,7 +178,7 @@ class PDFRenderer implements IRenderer<Widget> {
     let w = new Widget();
     let a = document.createElement('a');
     a.target = '_blank';
-    a.textContent = "View PDF";
+    a.textContent = 'View PDF';
     a.href = 'data:application/pdf;base64,' + data;
     w.node.appendChild(a);
     return w;
@@ -223,6 +209,7 @@ class MarkdownRenderer implements IRenderer<Widget> {
   render(mimetype: string, text: string): Widget {
     let data = removeMath(text);
     let html = marked(data['text']);
-    return new HTMLWidget(replaceMath(html, data['math']));
+    let sanitized = defaultSanitizer.sanitize(replaceMath(html, data['math']));
+    return new HTMLWidget(sanitized);
   }
 }

+ 21 - 0
src/sanitizer/index.ts

@@ -0,0 +1,21 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+import * as sanitize from 'sanitize-html';
+
+export
+class Sanitizer {
+  sanitize(dirty: string): string {
+    return sanitize(dirty, this._options);
+  }
+
+  private _options: sanitize.IOptions = {
+    allowedTags: sanitize.defaults.allowedTags.concat('img'),
+    transformTags: {
+      'a': sanitize.simpleTransform('a', { 'rel': 'nofollow' })
+    }
+  };
+}
+
+export
+const defaultSanitizer = new Sanitizer();

+ 61 - 0
typings/sanitize-html/sanitize-html.d.ts

@@ -0,0 +1,61 @@
+// Type definitions for sanitize-html 1.12.0
+// Project: https://github.com/punkave/sanitize-html
+declare function sanitize(dirty: string, options?: sanitize.IOptions): string;
+
+
+declare namespace sanitize {
+  export
+  type Attributes = { [attr: string]: string };
+
+
+  export
+  type Tag = { tagName: string; attributes: Attributes; };
+
+
+  export
+  type Transformer = (tagName: string, attributes: Attributes) => Tag;
+
+
+  export
+  interface IDefaults {
+    allowedAttributes: { [index: string]: string[] };
+    allowedSchemes: string[];
+    allowedSchemesByTag: { [index: string]: string[] };
+    allowedTags: string[];
+    selfClosing: string[];
+  }
+
+
+  export
+  interface IFrame {
+    tag: string;
+    attributes: { [index: string]: string };
+    text: string;
+    tagPosition: number;
+  }
+
+
+  export
+  interface IOptions {
+    allowedAttributes?: { [index: string]: string[] };
+    allowedClasses?: { [index: string]: string[] };
+    allowedSchemes?: string[];
+    allowedTags?: string[];
+    exclusiveFilter?: (frame: IFrame) => boolean;
+    selfClosing?: string[];
+    transformTags?: { [tagName: string]: string | Transformer; };
+  }
+
+
+  export
+  var defaults: IDefaults;
+
+
+  export
+  function simpleTransform(tagName: string, attributes: Attributes, merge?: boolean): Transformer;
+}
+
+
+declare module 'sanitize-html' {
+  export = sanitize;
+}

+ 0 - 27
typings/sanitizer/sanitizer.d.ts

@@ -1,27 +0,0 @@
-// Type definitions for Sanitizer
-// Project: https://github.com/theSmaw/Caja-HTML-Sanitizer
-// Definitions by: Dave Taylor <http://davetayls.me>
-// Definitions: https://github.com/borisyankov/DefinitelyTyped
-
-declare module 'sanitizer' {
-  export interface ISaxHandler {
-    startTag(name:string, attribs:string[], param:any):void;
-    endTag(name:string, param:any):void;
-    pcdata(text:string, param:any):void;
-    cdata(text:string, param:any):void;
-    rcdata(text:string, param:any):void;
-    comment(text:string, param:any):void;
-    startDoc(param:any):void;
-    endDoc(param:any):void;
-  }
-
-  export function escape(s:string):string;
-
-  export function makeSaxParser(yourHandler:ISaxHandler):(...any:any[])=>any;
-
-  export function normalizeRCData(s:string):string;
-
-  export function sanitize(s:string):string;
-
-  export function unescapeEntities(s:string):string;
-}