Show More
@@ -16,6 +16,13 b' from common import HTTP_OK, HTTP_BAD_REQ' | |||
|
16 | 16 | from request import wsgirequest |
|
17 | 17 | import webcommands, protocol, webutil |
|
18 | 18 | |
|
19 | perms = { | |
|
20 | 'changegroup': 'pull', | |
|
21 | 'changegroupsubset': 'pull', | |
|
22 | 'unbundle': 'push', | |
|
23 | 'stream_out': 'pull', | |
|
24 | } | |
|
25 | ||
|
19 | 26 | class hgweb(object): |
|
20 | 27 | def __init__(self, repo, name=None): |
|
21 | 28 | if isinstance(repo, str): |
@@ -95,6 +102,8 b' class hgweb(object):' | |||
|
95 | 102 | |
|
96 | 103 | cmd = req.form.get('cmd', [''])[0] |
|
97 | 104 | if cmd and cmd in protocol.__all__: |
|
105 | if cmd in perms and not self.check_perm(req, perms[cmd]): | |
|
106 | return | |
|
98 | 107 | method = getattr(protocol, cmd) |
|
99 | 108 | method(self, req) |
|
100 | 109 | return |
@@ -343,16 +352,39 b' class hgweb(object):' | |||
|
343 | 352 | 'zip': ('application/zip', 'zip', '.zip', None), |
|
344 | 353 | } |
|
345 | 354 | |
|
346 |
def check_perm(self, req, op |
|
|
347 |
''' |
|
|
348 |
|
|
|
349 | default is policy to use if no config given.''' | |
|
355 | def check_perm(self, req, op): | |
|
356 | '''Check permission for operation based on request data (including | |
|
357 | authentication info. Return true if op allowed, else false.''' | |
|
358 | ||
|
359 | def error(status, message): | |
|
360 | req.respond(status, protocol.HGTYPE) | |
|
361 | req.write('0\n%s\n' % message) | |
|
362 | ||
|
363 | if op == 'pull': | |
|
364 | return self.allowpull | |
|
365 | ||
|
366 | # enforce that you can only push using POST requests | |
|
367 | if req.env['REQUEST_METHOD'] != 'POST': | |
|
368 | error('405 Method Not Allowed', 'push requires POST request') | |
|
369 | return False | |
|
370 | ||
|
371 | # require ssl by default for pushing, auth info cannot be sniffed | |
|
372 | # and replayed | |
|
373 | scheme = req.env.get('wsgi.url_scheme') | |
|
374 | if self.configbool('web', 'push_ssl', True) and scheme != 'https': | |
|
375 | error(HTTP_OK, 'ssl required') | |
|
376 | return False | |
|
350 | 377 | |
|
351 | 378 | user = req.env.get('REMOTE_USER') |
|
352 | 379 | |
|
353 |
deny = self.configlist('web', 'deny_' |
|
|
380 | deny = self.configlist('web', 'deny_push') | |
|
354 | 381 | if deny and (not user or deny == ['*'] or user in deny): |
|
382 | error('401 Unauthorized', 'push not authorized') | |
|
355 | 383 | return False |
|
356 | 384 | |
|
357 |
allow = self.configlist('web', 'allow_' |
|
|
358 |
re |
|
|
385 | allow = self.configlist('web', 'allow_push') | |
|
386 | result = allow and (allow == ['*'] or user in allow) | |
|
387 | if not result: | |
|
388 | error('401 Unauthorized', 'push not authorized') | |
|
389 | ||
|
390 | return result |
@@ -62,8 +62,6 b' def between(web, req):' | |||
|
62 | 62 | def changegroup(web, req): |
|
63 | 63 | req.respond(HTTP_OK, HGTYPE) |
|
64 | 64 | nodes = [] |
|
65 | if not web.allowpull: | |
|
66 | return | |
|
67 | 65 | |
|
68 | 66 | if 'roots' in req.form: |
|
69 | 67 | nodes = map(bin, req.form['roots'][0].split(" ")) |
@@ -82,8 +80,6 b' def changegroupsubset(web, req):' | |||
|
82 | 80 | req.respond(HTTP_OK, HGTYPE) |
|
83 | 81 | bases = [] |
|
84 | 82 | heads = [] |
|
85 | if not web.allowpull: | |
|
86 | return | |
|
87 | 83 | |
|
88 | 84 | if 'bases' in req.form: |
|
89 | 85 | bases = [bin(x) for x in req.form['bases'][0].split(' ')] |
@@ -120,28 +116,7 b' def unbundle(web, req):' | |||
|
120 | 116 | req.write('0\n') |
|
121 | 117 | req.write(response) |
|
122 | 118 | |
|
123 | # enforce that you can only unbundle with POST requests | |
|
124 | if req.env['REQUEST_METHOD'] != 'POST': | |
|
125 | headers = {'status': '405 Method Not Allowed'} | |
|
126 | bail('unbundle requires POST request\n', headers) | |
|
127 | return | |
|
128 | ||
|
129 | # require ssl by default, auth info cannot be sniffed and | |
|
130 | # replayed | |
|
131 | ssl_req = web.configbool('web', 'push_ssl', True) | |
|
132 | if ssl_req: | |
|
133 | if req.env.get('wsgi.url_scheme') != 'https': | |
|
134 | bail('ssl required\n') | |
|
135 | return | |
|
136 | proto = 'https' | |
|
137 | else: | |
|
138 | proto = 'http' | |
|
139 | ||
|
140 | # do not allow push unless explicitly allowed | |
|
141 | if not web.check_perm(req, 'push', False): | |
|
142 | bail('push not authorized\n', headers={'status': '401 Unauthorized'}) | |
|
143 | return | |
|
144 | ||
|
119 | proto = req.env.get('wsgi.url_scheme') or 'http' | |
|
145 | 120 | their_heads = req.form['heads'][0].split(' ') |
|
146 | 121 | |
|
147 | 122 | def check_heads(): |
@@ -224,7 +199,5 b' def unbundle(web, req):' | |||
|
224 | 199 | os.unlink(tempname) |
|
225 | 200 | |
|
226 | 201 | def stream_out(web, req): |
|
227 | if not web.allowpull: | |
|
228 | return | |
|
229 | 202 | req.respond(HTTP_OK, HGTYPE) |
|
230 | 203 | streamclone.stream_out(web.repo, req, untrusted=True) |
|
1 | NO CONTENT: modified file, binary diff hidden |
General Comments 0
You need to be logged in to leave comments.
Login now