# HG changeset patch # User Mads Kiilerich # Date 2019-01-07 01:58:16 # Node ID a444c46a06490bbca383207112b383eed3b3fb85 # Parent ce2a4ef8cd5f4a8481885845367b6a574ce0d716 middleware: fix handling of Git 'info/refs' command to give correct access control For a pull, the Git client first sends an 'info/refs' command with a 'service=git-upload-pack' query, then it sends the actual 'git-upload-pack' command. For a push, the Git client first sends an 'info/refs' command with a 'service=git-receive-pack' query, then it sends the actual 'git-receive-pack' command. Before, the 'info/refs' commands would fall back to the default of trying to use the action of the previous request. That seems wrong. Instead, authorize the 'info/refs' command just like the actual command it references. path_info will now be checked more than before. Mainly because that is more correct and more explicit and "better" to do it that way. It might also give some safety. diff --git a/kallithea/lib/middleware/simplegit.py b/kallithea/lib/middleware/simplegit.py --- a/kallithea/lib/middleware/simplegit.py +++ b/kallithea/lib/middleware/simplegit.py @@ -148,22 +148,25 @@ class SimpleGit(BaseVCSController): def __get_action(self, environ): """ - Maps Git request commands into a pull or push command. - - :param environ: + Maps Git request commands into 'pull' or 'push'. """ - service = environ['QUERY_STRING'].split('=') - - if len(service) > 1: - service_cmd = service[1] - mapping = { - 'git-receive-pack': 'push', - 'git-upload-pack': 'pull', - } - op = mapping[service_cmd] - self._git_stored_op = op - # try to fallback to stored variable as we don't know if the last - # operation is pull/push + mapping = { + 'git-receive-pack': 'push', + 'git-upload-pack': 'pull', + } + path_info = environ.get('PATH_INFO', '') + m = GIT_PROTO_PAT.match(path_info) + if m is not None: + cmd = m.group(2) + if cmd == 'info/refs': + service = environ['QUERY_STRING'].split('=') + cmd = service[1] if len(service) > 1 else None + if cmd in mapping: + self._git_stored_op = mapping[cmd] + elif cmd in mapping: + self._git_stored_op = mapping[cmd] + # fallback to stored variable as we don't know if the last + # operation is pull/push return self._git_stored_op def _handle_githooks(self, repo_name, action, baseui, environ):