Show More
@@ -67,3 +67,4 b' a84d40e9481fcea4dafadee86b03f0dd401527d6' | |||
|
67 | 67 | 64ea7ea0923618a0c117acebb816a6f0d162bfdb 0.3.3 |
|
68 | 68 | cf635c823ea059cc3a1581b82d8672e46b682384 0.3.4 |
|
69 | 69 | 4cca4cc6a0a97f4c4763317184cd41aca4297630 0.3.5 |
|
70 | 082c9b8f0f17bd34740eb90c69bdc4c80d4b5b31 0.3.6 |
@@ -328,7 +328,7 b' class BaseVCSController(object):' | |||
|
328 | 328 | Checks permissions using action (push/pull) user and repository |
|
329 | 329 | name |
|
330 | 330 | |
|
331 | :param action: push or pull action | |
|
331 | :param action: 'push' or 'pull' action | |
|
332 | 332 | :param user: `User` instance |
|
333 | 333 | :param repo_name: repository name |
|
334 | 334 | """ |
@@ -30,6 +30,9 b' import re' | |||
|
30 | 30 | import logging |
|
31 | 31 | import traceback |
|
32 | 32 | |
|
33 | import markdown as markdown_mod | |
|
34 | import bleach | |
|
35 | ||
|
33 | 36 | from kallithea.lib.utils2 import safe_unicode, MENTIONS_REGEX |
|
34 | 37 | |
|
35 | 38 | log = logging.getLogger(__name__) |
@@ -138,17 +141,43 b' class MarkupRenderer(object):' | |||
|
138 | 141 | |
|
139 | 142 | @classmethod |
|
140 | 143 | def markdown(cls, source, safe=True, flavored=False): |
|
144 | """ | |
|
145 | Convert Markdown (possibly GitHub Flavored) to XSS safe HTML, possibly | |
|
146 | with "safe" fall-back to plaintext. | |
|
147 | ||
|
148 | >>> MarkupRenderer.markdown('''<img id="a" style="margin-top:-1000px;color:red" src="http://example.com/test.jpg">''') | |
|
149 | 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 | u'<p><img class="c d"></p>' | |
|
152 | >>> MarkupRenderer.markdown('''<a href="foo">foo</a>''') | |
|
153 | u'<p><a href="foo">foo</a></p>' | |
|
154 | >>> MarkupRenderer.markdown('''<script>alert(1)</script>''') | |
|
155 | u'<script>alert(1)</script>' | |
|
156 | >>> MarkupRenderer.markdown('''<div onclick="alert(2)">yo</div>''') | |
|
157 | u'<div>yo</div>' | |
|
158 | >>> MarkupRenderer.markdown('''<a href="javascript:alert(3)">yo</a>''') | |
|
159 | u'<p><a>yo</a></p>' | |
|
160 | """ | |
|
141 | 161 | source = safe_unicode(source) |
|
142 | 162 | try: |
|
143 | import markdown as __markdown | |
|
144 | 163 | if flavored: |
|
145 | 164 | source = cls._flavored_markdown(source) |
|
146 |
|
|
|
165 | markdown_html = markdown_mod.markdown(source, | |
|
147 | 166 | extensions=['codehilite', 'extra'], |
|
148 | 167 | extension_configs={'codehilite': {'css_class': 'code-highlight'}}) |
|
149 | except ImportError: | |
|
150 | log.warning('Install markdown to use this function') | |
|
151 | return cls.plain(source) | |
|
168 | # Allow most HTML, while preventing XSS issues: | |
|
169 | # no <script> tags, no onclick attributes, no javascript | |
|
170 | # "protocol", and also limit styling to prevent defacing. | |
|
171 | return bleach.clean(markdown_html, | |
|
172 | tags=['a', 'abbr', 'b', 'blockquote', 'br', 'code', 'dd', | |
|
173 | 'div', 'dl', 'dt', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', | |
|
174 | 'h6', 'hr', 'i', 'img', 'li', 'ol', 'p', 'pre', 'span', | |
|
175 | 'strong', 'sub', 'sup', 'table', 'tbody', 'td', 'th', | |
|
176 | 'thead', 'tr', 'ul'], | |
|
177 | attributes=['class', 'id', 'style', 'label', 'title', 'alt', 'href', 'src'], | |
|
178 | styles=['color'], | |
|
179 | protocols=['http', 'https', 'mailto'], | |
|
180 | ) | |
|
152 | 181 | except Exception: |
|
153 | 182 | log.error(traceback.format_exc()) |
|
154 | 183 | if safe: |
@@ -31,6 +31,7 b' Original author and date, and relevant c' | |||
|
31 | 31 | import os |
|
32 | 32 | import logging |
|
33 | 33 | import traceback |
|
34 | import urllib | |
|
34 | 35 | |
|
35 | 36 | from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError, \ |
|
36 | 37 | HTTPNotAcceptable, HTTPBadRequest |
@@ -63,6 +64,24 b' def is_mercurial(environ):' | |||
|
63 | 64 | return ishg_path |
|
64 | 65 | |
|
65 | 66 | |
|
67 | def get_header_hgarg(environ): | |
|
68 | """Decode the special Mercurial encoding of big requests over multiple headers. | |
|
69 | >>> get_header_hgarg({}) | |
|
70 | '' | |
|
71 | >>> get_header_hgarg({'HTTP_X_HGARG_0': ' ', 'HTTP_X_HGARG_1': 'a','HTTP_X_HGARG_2': '','HTTP_X_HGARG_3': 'b+c %20'}) | |
|
72 | 'ab+c %20' | |
|
73 | """ | |
|
74 | chunks = [] | |
|
75 | i = 1 | |
|
76 | while True: | |
|
77 | v = environ.get('HTTP_X_HGARG_%d' % i) | |
|
78 | if v is None: | |
|
79 | break | |
|
80 | chunks.append(v) | |
|
81 | i += 1 | |
|
82 | return ''.join(chunks) | |
|
83 | ||
|
84 | ||
|
66 | 85 | class SimpleHg(BaseVCSController): |
|
67 | 86 | |
|
68 | 87 | def _handle_request(self, environ, start_response): |
@@ -205,16 +224,55 b' class SimpleHg(BaseVCSController):' | |||
|
205 | 224 | |
|
206 | 225 | def __get_action(self, environ): |
|
207 | 226 | """ |
|
208 |
Maps Mercurial request commands into |
|
|
227 | Maps Mercurial request commands into 'pull' or 'push'. | |
|
209 | 228 | |
|
210 | 229 | Raises HTTPBadRequest if the request environment doesn't look like a hg client. |
|
211 | 230 | """ |
|
212 |
mapping = { |
|
|
213 | 'pushkey': 'push'} | |
|
231 | mapping = { | |
|
232 | # 'batch' is not in this list - it is handled explicitly | |
|
233 | 'between': 'pull', | |
|
234 | 'branches': 'pull', | |
|
235 | 'branchmap': 'pull', | |
|
236 | 'capabilities': 'pull', | |
|
237 | 'changegroup': 'pull', | |
|
238 | 'changegroupsubset': 'pull', | |
|
239 | 'changesetdata': 'pull', | |
|
240 | 'clonebundles': 'pull', | |
|
241 | 'debugwireargs': 'pull', | |
|
242 | 'filedata': 'pull', | |
|
243 | 'getbundle': 'pull', | |
|
244 | 'getlfile': 'pull', | |
|
245 | 'heads': 'pull', | |
|
246 | 'hello': 'pull', | |
|
247 | 'known': 'pull', | |
|
248 | 'lheads': 'pull', | |
|
249 | 'listkeys': 'pull', | |
|
250 | 'lookup': 'pull', | |
|
251 | 'manifestdata': 'pull', | |
|
252 | 'narrow_widen': 'pull', | |
|
253 | 'protocaps': 'pull', | |
|
254 | 'statlfile': 'pull', | |
|
255 | 'stream_out': 'pull', | |
|
256 | 'pushkey': 'push', | |
|
257 | 'putlfile': 'push', | |
|
258 | 'unbundle': 'push', | |
|
259 | } | |
|
214 | 260 | for qry in environ['QUERY_STRING'].split('&'): |
|
215 |
|
|
|
216 | cmd = qry.split('=')[-1] | |
|
217 | return mapping.get(cmd, 'pull') | |
|
261 | parts = qry.split('=', 1) | |
|
262 | if len(parts) == 2 and parts[0] == 'cmd': | |
|
263 | cmd = parts[1] | |
|
264 | if cmd == 'batch': | |
|
265 | hgarg = get_header_hgarg(environ) | |
|
266 | if not hgarg.startswith('cmds='): | |
|
267 | return 'push' # paranoid and safe | |
|
268 | for cmd_arg in hgarg[5:].split(';'): | |
|
269 | cmd, _args = urllib.unquote_plus(cmd_arg).split(' ', 1) | |
|
270 | op = mapping.get(cmd, 'push') | |
|
271 | if op != 'pull': | |
|
272 | assert op == 'push' | |
|
273 | return 'push' | |
|
274 | return 'pull' | |
|
275 | return mapping.get(cmd, 'push') | |
|
218 | 276 | |
|
219 | 277 | # Note: the client doesn't get the helpful error message |
|
220 | 278 | raise HTTPBadRequest('Unable to detect pull/push action! Are you using non standard command or client?') |
General Comments 0
You need to be logged in to leave comments.
Login now