Show More
@@ -350,18 +350,15 b' class hgweb(object):' | |||||
350 |
|
350 | |||
351 | # Route it to a wire protocol handler if it looks like a wire protocol |
|
351 | # Route it to a wire protocol handler if it looks like a wire protocol | |
352 | # request. |
|
352 | # request. | |
353 |
protohandler = wireprotoserver.parsehttprequest(rctx |
|
353 | protohandler = wireprotoserver.parsehttprequest(rctx, req, query, | |
|
354 | self.check_perm) | |||
354 |
|
355 | |||
355 | if protohandler: |
|
356 | if protohandler: | |
356 | try: |
|
357 | try: | |
357 | if query: |
|
358 | if query: | |
358 | raise ErrorResponse(HTTP_NOT_FOUND) |
|
359 | raise ErrorResponse(HTTP_NOT_FOUND) | |
359 |
|
360 | |||
360 | # TODO fold this into parsehttprequest |
|
361 | return protohandler['dispatch']() | |
361 | checkperm = lambda op: self.check_perm(rctx, req, op) |
|
|||
362 | protohandler['proto'].checkperm = checkperm |
|
|||
363 |
|
||||
364 | return protohandler['dispatch'](checkperm) |
|
|||
365 | except ErrorResponse as inst: |
|
362 | except ErrorResponse as inst: | |
366 | return protohandler['handleerror'](inst) |
|
363 | return protohandler['handleerror'](inst) | |
367 |
|
364 |
@@ -731,13 +731,10 b' def batch(repo, proto, cmds, others):' | |||||
731 | vals[unescapearg(n)] = unescapearg(v) |
|
731 | vals[unescapearg(n)] = unescapearg(v) | |
732 | func, spec = commands[op] |
|
732 | func, spec = commands[op] | |
733 |
|
733 | |||
734 | # If the protocol supports permissions checking, perform that |
|
734 | # Validate that client has permissions to perform this command. | |
735 | # checking on each batched command. |
|
735 | perm = commands[op].permission | |
736 | # TODO formalize permission checking as part of protocol interface. |
|
736 | assert perm in ('push', 'pull') | |
737 | if util.safehasattr(proto, 'checkperm'): |
|
737 | proto.checkperm(perm) | |
738 | perm = commands[op].permission |
|
|||
739 | assert perm in ('push', 'pull') |
|
|||
740 | proto.checkperm(perm) |
|
|||
741 |
|
738 | |||
742 | if spec: |
|
739 | if spec: | |
743 | keys = spec.split() |
|
740 | keys = spec.split() |
@@ -54,9 +54,10 b' def decodevaluefromheaders(req, headerpr' | |||||
54 | return ''.join(chunks) |
|
54 | return ''.join(chunks) | |
55 |
|
55 | |||
56 | class httpv1protocolhandler(wireprototypes.baseprotocolhandler): |
|
56 | class httpv1protocolhandler(wireprototypes.baseprotocolhandler): | |
57 | def __init__(self, req, ui): |
|
57 | def __init__(self, req, ui, checkperm): | |
58 | self._req = req |
|
58 | self._req = req | |
59 | self._ui = ui |
|
59 | self._ui = ui | |
|
60 | self._checkperm = checkperm | |||
60 |
|
61 | |||
61 | @property |
|
62 | @property | |
62 | def name(self): |
|
63 | def name(self): | |
@@ -139,6 +140,9 b' class httpv1protocolhandler(wireprototyp' | |||||
139 |
|
140 | |||
140 | return caps |
|
141 | return caps | |
141 |
|
142 | |||
|
143 | def checkperm(self, perm): | |||
|
144 | return self._checkperm(perm) | |||
|
145 | ||||
142 | # This method exists mostly so that extensions like remotefilelog can |
|
146 | # This method exists mostly so that extensions like remotefilelog can | |
143 | # disable a kludgey legacy method only over http. As of early 2018, |
|
147 | # disable a kludgey legacy method only over http. As of early 2018, | |
144 | # there are no other known users, so with any luck we can discard this |
|
148 | # there are no other known users, so with any luck we can discard this | |
@@ -146,7 +150,7 b' class httpv1protocolhandler(wireprototyp' | |||||
146 | def iscmd(cmd): |
|
150 | def iscmd(cmd): | |
147 | return cmd in wireproto.commands |
|
151 | return cmd in wireproto.commands | |
148 |
|
152 | |||
149 |
def parsehttprequest(r |
|
153 | def parsehttprequest(rctx, req, query, checkperm): | |
150 | """Parse the HTTP request for a wire protocol request. |
|
154 | """Parse the HTTP request for a wire protocol request. | |
151 |
|
155 | |||
152 | If the current request appears to be a wire protocol request, this |
|
156 | If the current request appears to be a wire protocol request, this | |
@@ -156,6 +160,8 b' def parsehttprequest(repo, req, query):' | |||||
156 |
|
160 | |||
157 | ``req`` is a ``wsgirequest`` instance. |
|
161 | ``req`` is a ``wsgirequest`` instance. | |
158 | """ |
|
162 | """ | |
|
163 | repo = rctx.repo | |||
|
164 | ||||
159 | # HTTP version 1 wire protocol requests are denoted by a "cmd" query |
|
165 | # HTTP version 1 wire protocol requests are denoted by a "cmd" query | |
160 | # string parameter. If it isn't present, this isn't a wire protocol |
|
166 | # string parameter. If it isn't present, this isn't a wire protocol | |
161 | # request. |
|
167 | # request. | |
@@ -174,13 +180,13 b' def parsehttprequest(repo, req, query):' | |||||
174 | if not iscmd(cmd): |
|
180 | if not iscmd(cmd): | |
175 | return None |
|
181 | return None | |
176 |
|
182 | |||
177 |
proto = httpv1protocolhandler(req, repo.ui |
|
183 | proto = httpv1protocolhandler(req, repo.ui, | |
|
184 | lambda perm: checkperm(rctx, req, perm)) | |||
178 |
|
185 | |||
179 | return { |
|
186 | return { | |
180 | 'cmd': cmd, |
|
187 | 'cmd': cmd, | |
181 | 'proto': proto, |
|
188 | 'proto': proto, | |
182 |
'dispatch': lambda |
|
189 | 'dispatch': lambda: _callhttp(repo, req, proto, cmd), | |
183 | checkperm), |
|
|||
184 | 'handleerror': lambda ex: _handlehttperror(ex, req, cmd), |
|
190 | 'handleerror': lambda ex: _handlehttperror(ex, req, cmd), | |
185 | } |
|
191 | } | |
186 |
|
192 | |||
@@ -224,7 +230,7 b' def _httpresponsetype(ui, req, prefer_un' | |||||
224 | opts = {'level': ui.configint('server', 'zliblevel')} |
|
230 | opts = {'level': ui.configint('server', 'zliblevel')} | |
225 | return HGTYPE, util.compengines['zlib'], opts |
|
231 | return HGTYPE, util.compengines['zlib'], opts | |
226 |
|
232 | |||
227 |
def _callhttp(repo, req, proto, cmd |
|
233 | def _callhttp(repo, req, proto, cmd): | |
228 | def genversion2(gen, engine, engineopts): |
|
234 | def genversion2(gen, engine, engineopts): | |
229 | # application/mercurial-0.2 always sends a payload header |
|
235 | # application/mercurial-0.2 always sends a payload header | |
230 | # identifying the compression engine. |
|
236 | # identifying the compression engine. | |
@@ -242,7 +248,7 b' def _callhttp(repo, req, proto, cmd, che' | |||||
242 | 'over HTTP')) |
|
248 | 'over HTTP')) | |
243 | return [] |
|
249 | return [] | |
244 |
|
250 | |||
245 | checkperm(wireproto.commands[cmd].permission) |
|
251 | proto.checkperm(wireproto.commands[cmd].permission) | |
246 |
|
252 | |||
247 | rsp = wireproto.dispatch(repo, proto, cmd) |
|
253 | rsp = wireproto.dispatch(repo, proto, cmd) | |
248 |
|
254 | |||
@@ -392,6 +398,9 b' class sshv1protocolhandler(wireprototype' | |||||
392 | def addcapabilities(self, repo, caps): |
|
398 | def addcapabilities(self, repo, caps): | |
393 | return caps |
|
399 | return caps | |
394 |
|
400 | |||
|
401 | def checkperm(self, perm): | |||
|
402 | pass | |||
|
403 | ||||
395 | class sshv2protocolhandler(sshv1protocolhandler): |
|
404 | class sshv2protocolhandler(sshv1protocolhandler): | |
396 | """Protocol handler for version 2 of the SSH protocol.""" |
|
405 | """Protocol handler for version 2 of the SSH protocol.""" | |
397 |
|
406 |
@@ -146,3 +146,12 b' class baseprotocolhandler(object):' | |||||
146 |
|
146 | |||
147 | Returns a list of capabilities. The passed in argument can be returned. |
|
147 | Returns a list of capabilities. The passed in argument can be returned. | |
148 | """ |
|
148 | """ | |
|
149 | ||||
|
150 | @abc.abstractmethod | |||
|
151 | def checkperm(self, perm): | |||
|
152 | """Validate that the client has permissions to perform a request. | |||
|
153 | ||||
|
154 | The argument is the permission required to proceed. If the client | |||
|
155 | doesn't have that permission, the exception should raise or abort | |||
|
156 | in a protocol specific manner. | |||
|
157 | """ |
@@ -18,6 +18,9 b' class proto(object):' | |||||
18 | names = spec.split() |
|
18 | names = spec.split() | |
19 | return [args[n] for n in names] |
|
19 | return [args[n] for n in names] | |
20 |
|
20 | |||
|
21 | def checkperm(self, perm): | |||
|
22 | pass | |||
|
23 | ||||
21 | class clientpeer(wireproto.wirepeer): |
|
24 | class clientpeer(wireproto.wirepeer): | |
22 | def __init__(self, serverrepo): |
|
25 | def __init__(self, serverrepo): | |
23 | self.serverrepo = serverrepo |
|
26 | self.serverrepo = serverrepo |
General Comments 0
You need to be logged in to leave comments.
Login now