##// END OF EJS Templates
Merge stable
Mads Kiilerich -
r7325:22c8f23c merge default
parent child Browse files
Show More
@@ -67,3 +67,4 b' a84d40e9481fcea4dafadee86b03f0dd401527d6'
67 64ea7ea0923618a0c117acebb816a6f0d162bfdb 0.3.3
67 64ea7ea0923618a0c117acebb816a6f0d162bfdb 0.3.3
68 cf635c823ea059cc3a1581b82d8672e46b682384 0.3.4
68 cf635c823ea059cc3a1581b82d8672e46b682384 0.3.4
69 4cca4cc6a0a97f4c4763317184cd41aca4297630 0.3.5
69 4cca4cc6a0a97f4c4763317184cd41aca4297630 0.3.5
70 082c9b8f0f17bd34740eb90c69bdc4c80d4b5b31 0.3.6
@@ -328,7 +328,7 b' class BaseVCSController(object):'
328 Checks permissions using action (push/pull) user and repository
328 Checks permissions using action (push/pull) user and repository
329 name
329 name
330
330
331 :param action: push or pull action
331 :param action: 'push' or 'pull' action
332 :param user: `User` instance
332 :param user: `User` instance
333 :param repo_name: repository name
333 :param repo_name: repository name
334 """
334 """
@@ -30,6 +30,9 b' import re'
30 import logging
30 import logging
31 import traceback
31 import traceback
32
32
33 import markdown as markdown_mod
34 import bleach
35
33 from kallithea.lib.utils2 import safe_unicode, MENTIONS_REGEX
36 from kallithea.lib.utils2 import safe_unicode, MENTIONS_REGEX
34
37
35 log = logging.getLogger(__name__)
38 log = logging.getLogger(__name__)
@@ -138,17 +141,43 b' class MarkupRenderer(object):'
138
141
139 @classmethod
142 @classmethod
140 def markdown(cls, source, safe=True, flavored=False):
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'&lt;script&gt;alert(1)&lt;/script&gt;'
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 source = safe_unicode(source)
161 source = safe_unicode(source)
142 try:
162 try:
143 import markdown as __markdown
144 if flavored:
163 if flavored:
145 source = cls._flavored_markdown(source)
164 source = cls._flavored_markdown(source)
146 return __markdown.markdown(source,
165 markdown_html = markdown_mod.markdown(source,
147 extensions=['codehilite', 'extra'],
166 extensions=['codehilite', 'extra'],
148 extension_configs={'codehilite': {'css_class': 'code-highlight'}})
167 extension_configs={'codehilite': {'css_class': 'code-highlight'}})
149 except ImportError:
168 # Allow most HTML, while preventing XSS issues:
150 log.warning('Install markdown to use this function')
169 # no <script> tags, no onclick attributes, no javascript
151 return cls.plain(source)
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 except Exception:
181 except Exception:
153 log.error(traceback.format_exc())
182 log.error(traceback.format_exc())
154 if safe:
183 if safe:
@@ -31,6 +31,7 b' Original author and date, and relevant c'
31 import os
31 import os
32 import logging
32 import logging
33 import traceback
33 import traceback
34 import urllib
34
35
35 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError, \
36 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError, \
36 HTTPNotAcceptable, HTTPBadRequest
37 HTTPNotAcceptable, HTTPBadRequest
@@ -63,6 +64,24 b' def is_mercurial(environ):'
63 return ishg_path
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 class SimpleHg(BaseVCSController):
85 class SimpleHg(BaseVCSController):
67
86
68 def _handle_request(self, environ, start_response):
87 def _handle_request(self, environ, start_response):
@@ -205,16 +224,55 b' class SimpleHg(BaseVCSController):'
205
224
206 def __get_action(self, environ):
225 def __get_action(self, environ):
207 """
226 """
208 Maps Mercurial request commands into a pull or push command.
227 Maps Mercurial request commands into 'pull' or 'push'.
209
228
210 Raises HTTPBadRequest if the request environment doesn't look like a hg client.
229 Raises HTTPBadRequest if the request environment doesn't look like a hg client.
211 """
230 """
212 mapping = {'unbundle': 'push',
231 mapping = {
213 'pushkey': 'push'}
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 for qry in environ['QUERY_STRING'].split('&'):
260 for qry in environ['QUERY_STRING'].split('&'):
215 if qry.startswith('cmd'):
261 parts = qry.split('=', 1)
216 cmd = qry.split('=')[-1]
262 if len(parts) == 2 and parts[0] == 'cmd':
217 return mapping.get(cmd, 'pull')
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 # Note: the client doesn't get the helpful error message
277 # Note: the client doesn't get the helpful error message
220 raise HTTPBadRequest('Unable to detect pull/push action! Are you using non standard command or client?')
278 raise HTTPBadRequest('Unable to detect pull/push action! Are you using non standard command or client?')
@@ -60,6 +60,7 b' requirements = ['
60 "mercurial >= 4.1.1, < 4.9",
60 "mercurial >= 4.1.1, < 4.9",
61 "decorator >= 3.3.2, < 4.4",
61 "decorator >= 3.3.2, < 4.4",
62 "Paste >= 2.0.3, < 3",
62 "Paste >= 2.0.3, < 3",
63 "bleach >= 3.0, < 3.1",
63 ]
64 ]
64
65
65 if sys.version_info < (2, 7):
66 if sys.version_info < (2, 7):
General Comments 0
You need to be logged in to leave comments. Login now