Show More
@@ -1,122 +1,126 b'' | |||
|
1 | 1 | //---------------------------------------------------------------------------- |
|
2 | 2 | // Copyright (C) 2014 The IPython Development Team |
|
3 | 3 | // |
|
4 | 4 | // Distributed under the terms of the BSD License. The full license is in |
|
5 | 5 | // the file COPYING, distributed as part of this software. |
|
6 | 6 | //---------------------------------------------------------------------------- |
|
7 | 7 | |
|
8 | 8 | //============================================================================ |
|
9 | 9 | // Utilities |
|
10 | 10 | //============================================================================ |
|
11 | 11 | IPython.namespace('IPython.security'); |
|
12 | 12 | |
|
13 | 13 | IPython.security = (function (IPython) { |
|
14 | 14 | "use strict"; |
|
15 | 15 | |
|
16 | 16 | var utils = IPython.utils; |
|
17 | 17 | |
|
18 | 18 | var noop = function (x) { return x; }; |
|
19 | 19 | |
|
20 | 20 | var cmp_tree = function (a, b) { |
|
21 | 21 | // compare two HTML trees |
|
22 | 22 | // only checks the tag structure is preserved, |
|
23 | 23 | // not any attributes or contents |
|
24 | 24 | if (a.length !== b.length) { |
|
25 | 25 | return false; |
|
26 | 26 | } |
|
27 | 27 | |
|
28 | 28 | for (var i = a.length - 1; i >= 0; i--) { |
|
29 | 29 | if ((a[i].tagName || '').toLowerCase() != (b[i].tagName || '').toLowerCase()) { |
|
30 | 30 | return false; |
|
31 | 31 | } |
|
32 | 32 | } |
|
33 | 33 | var ac = a.children(); |
|
34 | 34 | var bc = b.children(); |
|
35 | 35 | if (ac.length === 0 && bc.length === 0) { |
|
36 | 36 | return true; |
|
37 | 37 | } |
|
38 | 38 | return cmp_tree(ac, bc); |
|
39 | 39 | }; |
|
40 | 40 | |
|
41 | 41 | var caja; |
|
42 | 42 | if (window && window.html) { |
|
43 | 43 | caja = window.html; |
|
44 | 44 | caja.html4 = window.html4; |
|
45 | 45 | } |
|
46 | 46 | |
|
47 | 47 | var sanitizeAttribs = function (tagName, attribs, opt_naiveUriRewriter, opt_nmTokenPolicy, opt_logger) { |
|
48 | 48 | // wrap sanitizeAttribs into trusting data-attributes |
|
49 | 49 | var ATTRIBS = caja.html4.ATTRIBS; |
|
50 | 50 | for (var i = 0; i < attribs.length; i += 2) { |
|
51 | 51 | var attribName = attribs[i]; |
|
52 | 52 | if (attribName.substr(0,5) == 'data-') { |
|
53 | 53 | var attribKey = '*::' + attribName; |
|
54 | 54 | if (!ATTRIBS.hasOwnProperty(attribKey)) { |
|
55 | 55 | ATTRIBS[attribKey] = 0; |
|
56 | 56 | } |
|
57 | 57 | } |
|
58 | 58 | } |
|
59 | 59 | return caja.sanitizeAttribs(tagName, attribs, opt_naiveUriRewriter, opt_nmTokenPolicy, opt_logger); |
|
60 | 60 | }; |
|
61 | 61 | |
|
62 | 62 | var sanitize = function (html, log) { |
|
63 | 63 | // sanitize HTML |
|
64 | 64 | // returns a struct of |
|
65 | 65 | // { |
|
66 | 66 | // src: original_html, |
|
67 | 67 | // sanitized: the_sanitized_html, |
|
68 |
// safe: bool // false if the sanitizer |
|
|
68 | // _maybe_safe: bool // false if the sanitizer definitely made changes. | |
|
69 | // This is an incomplete indication, | |
|
70 | // only used to indicate whether further verification is necessary. | |
|
69 | 71 | // } |
|
70 | 72 | var result = { |
|
71 | 73 | src : html, |
|
72 | safe : true | |
|
74 | _maybe_safe : true | |
|
73 | 75 | }; |
|
74 | 76 | var record_messages = function (msg, opts) { |
|
75 | 77 | console.log("HTML Sanitizer", msg, opts); |
|
76 | result.safe = false; | |
|
78 | result._maybe_safe = false; | |
|
77 | 79 | }; |
|
78 | 80 | |
|
79 | 81 | var html4 = caja.html4; |
|
80 | 82 | var policy = function (tagName, attribs) { |
|
81 | 83 | if (!(html4.ELEMENTS[tagName] & html4.eflags.UNSAFE)) { |
|
82 | 84 | return { |
|
83 | 85 | 'attribs': sanitizeAttribs(tagName, attribs, |
|
84 | 86 | noop, noop, record_messages) |
|
85 | 87 | }; |
|
86 | 88 | } else { |
|
87 | 89 | record_messages(tagName + " removed", { |
|
88 | 90 | change: "removed", |
|
89 | 91 | tagName: tagName |
|
90 | 92 | }); |
|
91 | 93 | } |
|
92 | 94 | }; |
|
93 | 95 | |
|
94 | 96 | result.sanitized = caja.sanitizeWithPolicy(html, policy); |
|
95 | 97 | return result; |
|
96 | 98 | }; |
|
97 | 99 | |
|
98 | 100 | var sanitize_html = function (html) { |
|
99 | 101 | // shorthand for str-to-str conversion, dropping the struct |
|
100 | 102 | return sanitize(html).sanitized; |
|
101 | 103 | }; |
|
102 | 104 | |
|
103 | 105 | var is_safe = function (html) { |
|
104 | 106 | // just return bool for whether an HTML string is safe |
|
105 | 107 | var result = sanitize(html); |
|
106 | 108 | |
|
107 | 109 | // caja can strip whole elements without logging, |
|
108 | 110 | // so double-check that node structure didn't change |
|
109 | if (result.safe) { | |
|
111 | if (result._maybe_safe) { | |
|
110 | 112 | result.safe = cmp_tree($(result.sanitized), $(html)); |
|
113 | } else { | |
|
114 | result.safe = false; | |
|
111 | 115 | } |
|
112 | 116 | return result.safe; |
|
113 | 117 | }; |
|
114 | 118 | |
|
115 | 119 | return { |
|
116 | 120 | is_safe: is_safe, |
|
117 | 121 | sanitize: sanitize, |
|
118 | 122 | sanitize_html: sanitize_html |
|
119 | 123 | }; |
|
120 | 124 | |
|
121 | 125 | }(IPython)); |
|
122 | 126 |
General Comments 0
You need to be logged in to leave comments.
Login now