comparison hgext/acl.py @ 43076:2372284d9457

formatting: blacken the codebase This is using my patch to black (https://github.com/psf/black/pull/826) so we don't un-wrap collection literals. Done with: hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S # skip-blame mass-reformatting only # no-check-commit reformats foo_bar functions Differential Revision: https://phab.mercurial-scm.org/D6971
author Augie Fackler <augie@google.com>
date Sun, 06 Oct 2019 09:45:02 -0400
parents aaad36b88298
children 687b865b95ad
comparison
equal deleted inserted replaced
43075:57875cf423c9 43076:2372284d9457
222 match, 222 match,
223 pycompat, 223 pycompat,
224 registrar, 224 registrar,
225 util, 225 util,
226 ) 226 )
227 from mercurial.utils import ( 227 from mercurial.utils import procutil
228 procutil,
229 )
230 228
231 urlreq = util.urlreq 229 urlreq = util.urlreq
232 230
233 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for 231 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
234 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should 232 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
238 236
239 configtable = {} 237 configtable = {}
240 configitem = registrar.configitem(configtable) 238 configitem = registrar.configitem(configtable)
241 239
242 # deprecated config: acl.config 240 # deprecated config: acl.config
243 configitem('acl', 'config', 241 configitem(
244 default=None, 242 'acl', 'config', default=None,
245 ) 243 )
246 configitem('acl.groups', '.*', 244 configitem(
247 default=None, 245 'acl.groups', '.*', default=None, generic=True,
248 generic=True, 246 )
249 ) 247 configitem(
250 configitem('acl.deny.branches', '.*', 248 'acl.deny.branches', '.*', default=None, generic=True,
251 default=None, 249 )
252 generic=True, 250 configitem(
253 ) 251 'acl.allow.branches', '.*', default=None, generic=True,
254 configitem('acl.allow.branches', '.*', 252 )
255 default=None, 253 configitem(
256 generic=True, 254 'acl.deny', '.*', default=None, generic=True,
257 ) 255 )
258 configitem('acl.deny', '.*', 256 configitem(
259 default=None, 257 'acl.allow', '.*', default=None, generic=True,
260 generic=True, 258 )
261 ) 259 configitem(
262 configitem('acl.allow', '.*', 260 'acl', 'sources', default=lambda: ['serve'],
263 default=None, 261 )
264 generic=True, 262
265 )
266 configitem('acl', 'sources',
267 default=lambda: ['serve'],
268 )
269 263
270 def _getusers(ui, group): 264 def _getusers(ui, group):
271 265
272 # First, try to use group definition from section [acl.groups] 266 # First, try to use group definition from section [acl.groups]
273 hgrcusers = ui.configlist('acl.groups', group) 267 hgrcusers = ui.configlist('acl.groups', group)
279 try: 273 try:
280 return util.groupmembers(group) 274 return util.groupmembers(group)
281 except KeyError: 275 except KeyError:
282 raise error.Abort(_("group '%s' is undefined") % group) 276 raise error.Abort(_("group '%s' is undefined") % group)
283 277
278
284 def _usermatch(ui, user, usersorgroups): 279 def _usermatch(ui, user, usersorgroups):
285 280
286 if usersorgroups == '*': 281 if usersorgroups == '*':
287 return True 282 return True
288 283
291 if ug.startswith('!'): 286 if ug.startswith('!'):
292 # Test for excluded user or group. Format: 287 # Test for excluded user or group. Format:
293 # if ug is a user name: !username 288 # if ug is a user name: !username
294 # if ug is a group name: !@groupname 289 # if ug is a group name: !@groupname
295 ug = ug[1:] 290 ug = ug[1:]
296 if (not ug.startswith('@') and user != ug 291 if (
297 or ug.startswith('@') and user not in _getusers(ui, ug[1:])): 292 not ug.startswith('@')
293 and user != ug
294 or ug.startswith('@')
295 and user not in _getusers(ui, ug[1:])
296 ):
298 return True 297 return True
299 298
300 # Test for user or group. Format: 299 # Test for user or group. Format:
301 # if ug is a user name: username 300 # if ug is a user name: username
302 # if ug is a group name: @groupname 301 # if ug is a group name: @groupname
303 elif (user == ug 302 elif user == ug or ug.startswith('@') and user in _getusers(ui, ug[1:]):
304 or ug.startswith('@') and user in _getusers(ui, ug[1:])):
305 return True 303 return True
306 304
307 return False 305 return False
306
308 307
309 def buildmatch(ui, repo, user, key): 308 def buildmatch(ui, repo, user, key):
310 '''return tuple of (match function, list enabled).''' 309 '''return tuple of (match function, list enabled).'''
311 if not ui.has_section(key): 310 if not ui.has_section(key):
312 ui.debug('acl: %s not enabled\n' % key) 311 ui.debug('acl: %s not enabled\n' % key)
313 return None 312 return None
314 313
315 pats = [pat for pat, users in ui.configitems(key) 314 pats = [
316 if _usermatch(ui, user, users)] 315 pat for pat, users in ui.configitems(key) if _usermatch(ui, user, users)
317 ui.debug('acl: %s enabled, %d entries for user %s\n' % 316 ]
318 (key, len(pats), user)) 317 ui.debug(
318 'acl: %s enabled, %d entries for user %s\n' % (key, len(pats), user)
319 )
319 320
320 # Branch-based ACL 321 # Branch-based ACL
321 if not repo: 322 if not repo:
322 if pats: 323 if pats:
323 # If there's an asterisk (meaning "any branch"), always return True; 324 # If there's an asterisk (meaning "any branch"), always return True;
330 # Path-based ACL 331 # Path-based ACL
331 if pats: 332 if pats:
332 return match.match(repo.root, '', pats) 333 return match.match(repo.root, '', pats)
333 return util.never 334 return util.never
334 335
336
335 def ensureenabled(ui): 337 def ensureenabled(ui):
336 """make sure the extension is enabled when used as hook 338 """make sure the extension is enabled when used as hook
337 339
338 When acl is used through hooks, the extension is never formally loaded and 340 When acl is used through hooks, the extension is never formally loaded and
339 enabled. This has some side effect, for example the config declaration is 341 enabled. This has some side effect, for example the config declaration is
343 if 'acl' in ui._knownconfig: 345 if 'acl' in ui._knownconfig:
344 return 346 return
345 ui.setconfig('extensions', 'acl', '', source='internal') 347 ui.setconfig('extensions', 'acl', '', source='internal')
346 extensions.loadall(ui, ['acl']) 348 extensions.loadall(ui, ['acl'])
347 349
350
348 def hook(ui, repo, hooktype, node=None, source=None, **kwargs): 351 def hook(ui, repo, hooktype, node=None, source=None, **kwargs):
349 352
350 ensureenabled(ui) 353 ensureenabled(ui)
351 354
352 if hooktype not in ['pretxnchangegroup', 'pretxncommit', 'prepushkey']: 355 if hooktype not in ['pretxnchangegroup', 'pretxncommit', 'prepushkey']:
353 raise error.Abort( 356 raise error.Abort(
354 _('config error - hook type "%s" cannot stop ' 357 _(
355 'incoming changesets, commits, nor bookmarks') % hooktype) 358 'config error - hook type "%s" cannot stop '
356 if (hooktype == 'pretxnchangegroup' and 359 'incoming changesets, commits, nor bookmarks'
357 source not in ui.configlist('acl', 'sources')): 360 )
361 % hooktype
362 )
363 if hooktype == 'pretxnchangegroup' and source not in ui.configlist(
364 'acl', 'sources'
365 ):
358 ui.debug('acl: changes have source "%s" - skipping\n' % source) 366 ui.debug('acl: changes have source "%s" - skipping\n' % source)
359 return 367 return
360 368
361 user = None 369 user = None
362 if source == 'serve' and r'url' in kwargs: 370 if source == 'serve' and r'url' in kwargs:
371 379
372 if hooktype == 'prepushkey': 380 if hooktype == 'prepushkey':
373 _pkhook(ui, repo, hooktype, node, source, user, **kwargs) 381 _pkhook(ui, repo, hooktype, node, source, user, **kwargs)
374 else: 382 else:
375 _txnhook(ui, repo, hooktype, node, source, user, **kwargs) 383 _txnhook(ui, repo, hooktype, node, source, user, **kwargs)
384
376 385
377 def _pkhook(ui, repo, hooktype, node, source, user, **kwargs): 386 def _pkhook(ui, repo, hooktype, node, source, user, **kwargs):
378 if kwargs[r'namespace'] == 'bookmarks': 387 if kwargs[r'namespace'] == 'bookmarks':
379 bookmark = kwargs[r'key'] 388 bookmark = kwargs[r'key']
380 ctx = kwargs[r'new'] 389 ctx = kwargs[r'new']
381 allowbookmarks = buildmatch(ui, None, user, 'acl.allow.bookmarks') 390 allowbookmarks = buildmatch(ui, None, user, 'acl.allow.bookmarks')
382 denybookmarks = buildmatch(ui, None, user, 'acl.deny.bookmarks') 391 denybookmarks = buildmatch(ui, None, user, 'acl.deny.bookmarks')
383 392
384 if denybookmarks and denybookmarks(bookmark): 393 if denybookmarks and denybookmarks(bookmark):
385 raise error.Abort(_('acl: user "%s" denied on bookmark "%s"' 394 raise error.Abort(
386 ' (changeset "%s")') 395 _('acl: user "%s" denied on bookmark "%s"' ' (changeset "%s")')
387 % (user, bookmark, ctx)) 396 % (user, bookmark, ctx)
397 )
388 if allowbookmarks and not allowbookmarks(bookmark): 398 if allowbookmarks and not allowbookmarks(bookmark):
389 raise error.Abort(_('acl: user "%s" not allowed on bookmark "%s"' 399 raise error.Abort(
390 ' (changeset "%s")') 400 _(
391 % (user, bookmark, ctx)) 401 'acl: user "%s" not allowed on bookmark "%s"'
392 ui.debug('acl: bookmark access granted: "%s" on bookmark "%s"\n' 402 ' (changeset "%s")'
393 % (ctx, bookmark)) 403 )
404 % (user, bookmark, ctx)
405 )
406 ui.debug(
407 'acl: bookmark access granted: "%s" on bookmark "%s"\n'
408 % (ctx, bookmark)
409 )
410
394 411
395 def _txnhook(ui, repo, hooktype, node, source, user, **kwargs): 412 def _txnhook(ui, repo, hooktype, node, source, user, **kwargs):
396 # deprecated config: acl.config 413 # deprecated config: acl.config
397 cfg = ui.config('acl', 'config') 414 cfg = ui.config('acl', 'config')
398 if cfg: 415 if cfg:
399 ui.readconfig(cfg, sections=['acl.groups', 'acl.allow.branches', 416 ui.readconfig(
400 'acl.deny.branches', 'acl.allow', 'acl.deny']) 417 cfg,
418 sections=[
419 'acl.groups',
420 'acl.allow.branches',
421 'acl.deny.branches',
422 'acl.allow',
423 'acl.deny',
424 ],
425 )
401 426
402 allowbranches = buildmatch(ui, None, user, 'acl.allow.branches') 427 allowbranches = buildmatch(ui, None, user, 'acl.allow.branches')
403 denybranches = buildmatch(ui, None, user, 'acl.deny.branches') 428 denybranches = buildmatch(ui, None, user, 'acl.deny.branches')
404 allow = buildmatch(ui, repo, user, 'acl.allow') 429 allow = buildmatch(ui, repo, user, 'acl.allow')
405 deny = buildmatch(ui, repo, user, 'acl.deny') 430 deny = buildmatch(ui, repo, user, 'acl.deny')
406 431
407 for rev in pycompat.xrange(repo[node].rev(), len(repo)): 432 for rev in pycompat.xrange(repo[node].rev(), len(repo)):
408 ctx = repo[rev] 433 ctx = repo[rev]
409 branch = ctx.branch() 434 branch = ctx.branch()
410 if denybranches and denybranches(branch): 435 if denybranches and denybranches(branch):
411 raise error.Abort(_('acl: user "%s" denied on branch "%s"' 436 raise error.Abort(
412 ' (changeset "%s")') 437 _('acl: user "%s" denied on branch "%s"' ' (changeset "%s")')
413 % (user, branch, ctx)) 438 % (user, branch, ctx)
439 )
414 if allowbranches and not allowbranches(branch): 440 if allowbranches and not allowbranches(branch):
415 raise error.Abort(_('acl: user "%s" not allowed on branch "%s"' 441 raise error.Abort(
416 ' (changeset "%s")') 442 _(
417 % (user, branch, ctx)) 443 'acl: user "%s" not allowed on branch "%s"'
418 ui.debug('acl: branch access granted: "%s" on branch "%s"\n' 444 ' (changeset "%s")'
419 % (ctx, branch)) 445 )
446 % (user, branch, ctx)
447 )
448 ui.debug(
449 'acl: branch access granted: "%s" on branch "%s"\n' % (ctx, branch)
450 )
420 451
421 for f in ctx.files(): 452 for f in ctx.files():
422 if deny and deny(f): 453 if deny and deny(f):
423 raise error.Abort(_('acl: user "%s" denied on "%s"' 454 raise error.Abort(
424 ' (changeset "%s")') % (user, f, ctx)) 455 _('acl: user "%s" denied on "%s"' ' (changeset "%s")')
456 % (user, f, ctx)
457 )
425 if allow and not allow(f): 458 if allow and not allow(f):
426 raise error.Abort(_('acl: user "%s" not allowed on "%s"' 459 raise error.Abort(
427 ' (changeset "%s")') % (user, f, ctx)) 460 _('acl: user "%s" not allowed on "%s"' ' (changeset "%s")')
461 % (user, f, ctx)
462 )
428 ui.debug('acl: path access granted: "%s"\n' % ctx) 463 ui.debug('acl: path access granted: "%s"\n' % ctx)