Show More
@@ -31,6 +31,7 b' import logging' | |||||
31 | import traceback |
|
31 | import traceback | |
32 |
|
32 | |||
33 | import markdown as markdown_mod |
|
33 | import markdown as markdown_mod | |
|
34 | import bleach | |||
34 |
|
35 | |||
35 | from kallithea.lib.utils2 import safe_unicode, MENTIONS_REGEX |
|
36 | from kallithea.lib.utils2 import safe_unicode, MENTIONS_REGEX | |
36 |
|
37 | |||
@@ -142,28 +143,40 b' class MarkupRenderer(object):' | |||||
142 | @classmethod |
|
143 | @classmethod | |
143 | def markdown(cls, source, safe=True, flavored=False): |
|
144 | def markdown(cls, source, safe=True, flavored=False): | |
144 | """ |
|
145 | """ | |
145 | Convert Markdown (possibly GitHub Flavored) to HTML, possibly |
|
146 | Convert Markdown (possibly GitHub Flavored) to XSS safe HTML, possibly | |
146 | with "safe" fall-back to plaintext. |
|
147 | with "safe" fall-back to plaintext. | |
147 |
|
148 | |||
148 | >>> MarkupRenderer.markdown('''<img id="a" style="margin-top:-1000px;color:red" src="http://example.com/test.jpg">''') |
|
149 | >>> MarkupRenderer.markdown('''<img id="a" style="margin-top:-1000px;color:red" src="http://example.com/test.jpg">''') | |
149 |
u'<p><img id="a" s |
|
150 | u'<p><img id="a" src="http://example.com/test.jpg" style="color: red;"></p>' | |
150 | >>> MarkupRenderer.markdown('''<img class="c d" src="file://localhost/test.jpg">''') |
|
151 | >>> MarkupRenderer.markdown('''<img class="c d" src="file://localhost/test.jpg">''') | |
151 |
u'<p><img class="c d" |
|
152 | u'<p><img class="c d"></p>' | |
152 | >>> MarkupRenderer.markdown('''<a href="foo">foo</a>''') |
|
153 | >>> MarkupRenderer.markdown('''<a href="foo">foo</a>''') | |
153 | u'<p><a href="foo">foo</a></p>' |
|
154 | u'<p><a href="foo">foo</a></p>' | |
154 | >>> MarkupRenderer.markdown('''<script>alert(1)</script>''') |
|
155 | >>> MarkupRenderer.markdown('''<script>alert(1)</script>''') | |
155 |
u' |
|
156 | u'<script>alert(1)</script>' | |
156 | >>> MarkupRenderer.markdown('''<div onclick="alert(2)">yo</div>''') |
|
157 | >>> MarkupRenderer.markdown('''<div onclick="alert(2)">yo</div>''') | |
157 |
u'<div |
|
158 | u'<div>yo</div>' | |
158 | >>> MarkupRenderer.markdown('''<a href="javascript:alert(3)">yo</a>''') |
|
159 | >>> MarkupRenderer.markdown('''<a href="javascript:alert(3)">yo</a>''') | |
159 |
u'<p><a |
|
160 | u'<p><a>yo</a></p>' | |
160 | """ |
|
161 | """ | |
161 | source = safe_unicode(source) |
|
162 | source = safe_unicode(source) | |
162 | try: |
|
163 | try: | |
163 | if flavored: |
|
164 | if flavored: | |
164 | source = cls._flavored_markdown(source) |
|
165 | source = cls._flavored_markdown(source) | |
165 | markdown_html = markdown_mod.markdown(source, ['codehilite', 'extra']) |
|
166 | markdown_html = markdown_mod.markdown(source, ['codehilite', 'extra']) | |
166 | return markdown_html |
|
167 | # Allow most HTML, while preventing XSS issues: | |
|
168 | # no <script> tags, no onclick attributes, no javascript | |||
|
169 | # "protocol", and also limit styling to prevent defacing. | |||
|
170 | return bleach.clean(markdown_html, | |||
|
171 | tags=['a', 'abbr', 'b', 'blockquote', 'br', 'code', 'dd', | |||
|
172 | 'div', 'dl', 'dt', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', | |||
|
173 | 'h6', 'hr', 'i', 'img', 'li', 'ol', 'p', 'pre', 'span', | |||
|
174 | 'strong', 'sub', 'sup', 'table', 'tbody', 'td', 'th', | |||
|
175 | 'thead', 'tr', 'ul'], | |||
|
176 | attributes=['class', 'id', 'style', 'label', 'title', 'alt', 'href', 'src'], | |||
|
177 | styles=['color'], | |||
|
178 | protocols=['http', 'https', 'mailto'], | |||
|
179 | ) | |||
167 | except Exception: |
|
180 | except Exception: | |
168 | log.error(traceback.format_exc()) |
|
181 | log.error(traceback.format_exc()) | |
169 | if safe: |
|
182 | if safe: |
General Comments 0
You need to be logged in to leave comments.
Login now