mercurial/hgweb/hgweb_mod.py
changeset 6779 d3147b4e3e8a
parent 6777 44c5157474e7
child 6780 4c1d67e0fa8c
--- 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