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