##// END OF EJS Templates
acl: support evolve subcommands when checking for permissions.
marcink -
r3229:a91339bd default
parent child Browse files
Show More
@@ -1,152 +1,157 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2018 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 SimpleHG middleware for handling mercurial protocol request
22 SimpleHG middleware for handling mercurial protocol request
23 (push/clone etc.). It's implemented with basic auth function
23 (push/clone etc.). It's implemented with basic auth function
24 """
24 """
25
25
26 import logging
26 import logging
27 import urlparse
27 import urlparse
28 import urllib
28 import urllib
29
29
30 from rhodecode.lib import utils
30 from rhodecode.lib import utils
31 from rhodecode.lib.ext_json import json
31 from rhodecode.lib.ext_json import json
32 from rhodecode.lib.middleware import simplevcs
32 from rhodecode.lib.middleware import simplevcs
33
33
34 log = logging.getLogger(__name__)
34 log = logging.getLogger(__name__)
35
35
36
36
37 class SimpleHg(simplevcs.SimpleVCS):
37 class SimpleHg(simplevcs.SimpleVCS):
38
38
39 SCM = 'hg'
39 SCM = 'hg'
40
40
41 def _get_repository_name(self, environ):
41 def _get_repository_name(self, environ):
42 """
42 """
43 Gets repository name out of PATH_INFO header
43 Gets repository name out of PATH_INFO header
44
44
45 :param environ: environ where PATH_INFO is stored
45 :param environ: environ where PATH_INFO is stored
46 """
46 """
47 return environ['PATH_INFO'].strip('/')
47 return environ['PATH_INFO'].strip('/')
48
48
49 _ACTION_MAPPING = {
49 _ACTION_MAPPING = {
50 'changegroup': 'pull',
50 'changegroup': 'pull',
51 'changegroupsubset': 'pull',
51 'changegroupsubset': 'pull',
52 'getbundle': 'pull',
52 'getbundle': 'pull',
53 'stream_out': 'pull',
53 'stream_out': 'pull',
54 'listkeys': 'pull',
54 'listkeys': 'pull',
55 'between': 'pull',
55 'between': 'pull',
56 'branchmap': 'pull',
56 'branchmap': 'pull',
57 'branches': 'pull',
57 'branches': 'pull',
58 'clonebundles': 'pull',
58 'clonebundles': 'pull',
59 'capabilities': 'pull',
59 'capabilities': 'pull',
60 'debugwireargs': 'pull',
60 'debugwireargs': 'pull',
61 'heads': 'pull',
61 'heads': 'pull',
62 'lookup': 'pull',
62 'lookup': 'pull',
63 'hello': 'pull',
63 'hello': 'pull',
64 'known': 'pull',
64 'known': 'pull',
65
65
66 # largefiles
66 # largefiles
67 'putlfile': 'push',
67 'putlfile': 'push',
68 'getlfile': 'pull',
68 'getlfile': 'pull',
69 'statlfile': 'pull',
69 'statlfile': 'pull',
70 'lheads': 'pull',
70 'lheads': 'pull',
71
71
72 # evolve
73 'evoext_obshashrange_v1': 'pull',
74 'evoext_obshash': 'pull',
75 'evoext_obshash1': 'pull',
76
72 'unbundle': 'push',
77 'unbundle': 'push',
73 'pushkey': 'push',
78 'pushkey': 'push',
74 }
79 }
75
80
76 @classmethod
81 @classmethod
77 def _get_xarg_headers(cls, environ):
82 def _get_xarg_headers(cls, environ):
78 i = 1
83 i = 1
79 chunks = [] # gather chunks stored in multiple 'hgarg_N'
84 chunks = [] # gather chunks stored in multiple 'hgarg_N'
80 while True:
85 while True:
81 head = environ.get('HTTP_X_HGARG_{}'.format(i))
86 head = environ.get('HTTP_X_HGARG_{}'.format(i))
82 if not head:
87 if not head:
83 break
88 break
84 i += 1
89 i += 1
85 chunks.append(urllib.unquote_plus(head))
90 chunks.append(urllib.unquote_plus(head))
86 full_arg = ''.join(chunks)
91 full_arg = ''.join(chunks)
87 pref = 'cmds='
92 pref = 'cmds='
88 if full_arg.startswith(pref):
93 if full_arg.startswith(pref):
89 # strip the cmds= header defining our batch commands
94 # strip the cmds= header defining our batch commands
90 full_arg = full_arg[len(pref):]
95 full_arg = full_arg[len(pref):]
91 cmds = full_arg.split(';')
96 cmds = full_arg.split(';')
92 return cmds
97 return cmds
93
98
94 @classmethod
99 @classmethod
95 def _get_batch_cmd(cls, environ):
100 def _get_batch_cmd(cls, environ):
96 """
101 """
97 Handle batch command send commands. Those are ';' separated commands
102 Handle batch command send commands. Those are ';' separated commands
98 sent by batch command that server needs to execute. We need to extract
103 sent by batch command that server needs to execute. We need to extract
99 those, and map them to our ACTION_MAPPING to get all push/pull commands
104 those, and map them to our ACTION_MAPPING to get all push/pull commands
100 specified in the batch
105 specified in the batch
101 """
106 """
102 default = 'push'
107 default = 'push'
103 batch_cmds = []
108 batch_cmds = []
104 try:
109 try:
105 cmds = cls._get_xarg_headers(environ)
110 cmds = cls._get_xarg_headers(environ)
106 for pair in cmds:
111 for pair in cmds:
107 parts = pair.split(' ', 1)
112 parts = pair.split(' ', 1)
108 if len(parts) != 2:
113 if len(parts) != 2:
109 continue
114 continue
110 # entry should be in a format `key ARGS`
115 # entry should be in a format `key ARGS`
111 cmd, args = parts
116 cmd, args = parts
112 action = cls._ACTION_MAPPING.get(cmd, default)
117 action = cls._ACTION_MAPPING.get(cmd, default)
113 batch_cmds.append(action)
118 batch_cmds.append(action)
114 except Exception:
119 except Exception:
115 log.exception('Failed to extract batch commands operations')
120 log.exception('Failed to extract batch commands operations')
116
121
117 # in case we failed, (e.g malformed data) assume it's PUSH sub-command
122 # in case we failed, (e.g malformed data) assume it's PUSH sub-command
118 # for safety
123 # for safety
119 return batch_cmds or [default]
124 return batch_cmds or [default]
120
125
121 def _get_action(self, environ):
126 def _get_action(self, environ):
122 """
127 """
123 Maps mercurial request commands into a pull or push command.
128 Maps mercurial request commands into a pull or push command.
124 In case of unknown/unexpected data, it returns 'push' to be safe.
129 In case of unknown/unexpected data, it returns 'push' to be safe.
125
130
126 :param environ:
131 :param environ:
127 """
132 """
128 default = 'push'
133 default = 'push'
129 query = urlparse.parse_qs(environ['QUERY_STRING'],
134 query = urlparse.parse_qs(environ['QUERY_STRING'],
130 keep_blank_values=True)
135 keep_blank_values=True)
131
136
132 if 'cmd' in query:
137 if 'cmd' in query:
133 cmd = query['cmd'][0]
138 cmd = query['cmd'][0]
134 if cmd == 'batch':
139 if cmd == 'batch':
135 cmds = self._get_batch_cmd(environ)
140 cmds = self._get_batch_cmd(environ)
136 if 'push' in cmds:
141 if 'push' in cmds:
137 return 'push'
142 return 'push'
138 else:
143 else:
139 return 'pull'
144 return 'pull'
140 return self._ACTION_MAPPING.get(cmd, default)
145 return self._ACTION_MAPPING.get(cmd, default)
141
146
142 return default
147 return default
143
148
144 def _create_wsgi_app(self, repo_path, repo_name, config):
149 def _create_wsgi_app(self, repo_path, repo_name, config):
145 return self.scm_app.create_hg_wsgi_app(
150 return self.scm_app.create_hg_wsgi_app(
146 repo_path, repo_name, config)
151 repo_path, repo_name, config)
147
152
148 def _create_config(self, extras, repo_name):
153 def _create_config(self, extras, repo_name):
149 config = utils.make_db_config(repo=repo_name)
154 config = utils.make_db_config(repo=repo_name)
150 config.set('rhodecode', 'RC_SCM_DATA', json.dumps(extras))
155 config.set('rhodecode', 'RC_SCM_DATA', json.dumps(extras))
151
156
152 return config.serialize()
157 return config.serialize()
General Comments 0
You need to be logged in to leave comments. Login now