diff -r 959efdac4a9c -r d3147b4e3e8a mercurial/hgweb/hgweb_mod.py --- a/mercurial/hgweb/hgweb_mod.py Sun Jun 29 11:02:19 2008 +0200 +++ b/mercurial/hgweb/hgweb_mod.py Sun Jun 29 11:35:06 2008 +0200 @@ -16,6 +16,13 @@ from request import wsgirequest import webcommands, protocol, webutil +perms = { + 'changegroup': 'pull', + 'changegroupsubset': 'pull', + 'unbundle': 'push', + 'stream_out': 'pull', +} + class hgweb(object): def __init__(self, repo, name=None): if isinstance(repo, str): @@ -95,6 +102,8 @@ cmd = req.form.get('cmd', [''])[0] if cmd and cmd in protocol.__all__: + if cmd in perms and not self.check_perm(req, perms[cmd]): + return method = getattr(protocol, cmd) method(self, req) return @@ -343,16 +352,39 @@ 'zip': ('application/zip', 'zip', '.zip', None), } - def check_perm(self, req, op, default): - '''check permission for operation based on user auth. - return true if op allowed, else false. - default is policy to use if no config given.''' + def check_perm(self, req, op): + '''Check permission for operation based on request data (including + authentication info. Return true if op allowed, else false.''' + + def error(status, message): + req.respond(status, protocol.HGTYPE) + req.write('0\n%s\n' % message) + + if op == 'pull': + return self.allowpull + + # enforce that you can only push using POST requests + if req.env['REQUEST_METHOD'] != 'POST': + error('405 Method Not Allowed', 'push requires POST request') + return False + + # require ssl by default for pushing, auth info cannot be sniffed + # and replayed + scheme = req.env.get('wsgi.url_scheme') + if self.configbool('web', 'push_ssl', True) and scheme != 'https': + error(HTTP_OK, 'ssl required') + return False user = req.env.get('REMOTE_USER') - deny = self.configlist('web', 'deny_' + op) + deny = self.configlist('web', 'deny_push') if deny and (not user or deny == ['*'] or user in deny): + error('401 Unauthorized', 'push not authorized') return False - allow = self.configlist('web', 'allow_' + op) - return (allow and (allow == ['*'] or user in allow)) or default + allow = self.configlist('web', 'allow_push') + result = allow and (allow == ['*'] or user in allow) + if not result: + error('401 Unauthorized', 'push not authorized') + + return result