src/mercurialserver/ruleset.py
changeset 106 0519745e7a57
parent 78 2a3407a14654
child 109 72100d3ed1bd
equal deleted inserted replaced
105:cd3da73cdf63 106:0519745e7a57
    10 import os
    10 import os
    11 import os.path
    11 import os.path
    12 
    12 
    13 allowedchars = "A-Za-z0-9_-"
    13 allowedchars = "A-Za-z0-9_-"
    14 
    14 
    15 goodpathre = re.compile("([%s]+/)*[%s]+$" % (allowedchars, allowedchars))
       
    16 def goodpath(path):
       
    17     return goodpathre.match(path) is not None
       
    18 
       
    19 goodglobre = re.compile("[*/%s]+$" % allowedchars)
       
    20 
       
    21 def goodglob(pattern):
       
    22     return goodglobre.match(pattern) is not None
       
    23 
       
    24 # Don't put anything except *A-Za-z0-9_- in rule globs or   
       
    25 # it will match nothing.  No regexp metachars, not even .
       
    26 # We may fix this later.
       
    27 def globmatcher(pattern):
    15 def globmatcher(pattern):
    28     if not goodglob(pattern):
    16     p = "[^/]*".join(re.escape(c) for c in pattern.split("*"))
    29         #fail("Bad glob pattern in auth config: %s" % pattern)
    17     # ** means "match recursively" ie "ignore directories"
    30         # FIXME: report it somehow
    18     rex = re.compile(p.replace("[^/]*[^/]*", ".*") + "$")
    31         return lambda x: False
       
    32     # Substitution cunning so ** can be different from *
       
    33     pattern = pattern.replace("*", "[]")
       
    34     pattern = pattern.replace("[][]", "[/%s]*" % allowedchars)
       
    35     pattern = pattern.replace("[]", "[%s]*" % allowedchars)
       
    36     rex = re.compile(pattern + "$")
       
    37     # None matches everything
    19     # None matches everything
    38     return lambda x: x is None or rex.match(x) is not None
    20     return lambda x: x is None or rex.match(x) is not None
    39 
    21 
    40 def rule(pairs):
    22 def rule(pairs):
    41     matchers = [(k, globmatcher(v)) for k, v in pairs]
    23     matchers = [(k, globmatcher(v)) for k, v in pairs]
    43         for k, m in matchers:
    25         for k, m in matchers:
    44             if k not in kw or not m(kw[k]):
    26             if k not in kw or not m(kw[k]):
    45                 return False
    27                 return False
    46         return True
    28         return True
    47     return c
    29     return c
       
    30 
       
    31 class AccessException(Exception):
       
    32     pass
    48 
    33 
    49 class Ruleset(object):
    34 class Ruleset(object):
    50     '''Class representing the rules in a rule file'''
    35     '''Class representing the rules in a rule file'''
    51     
    36     
    52     levels = ["init", "write", "read", "deny"]
    37     levels = ["init", "write", "read", "deny"]
    74 
    59 
    75     def allow(self, level, **kw):
    60     def allow(self, level, **kw):
    76         a = self.matchrule(kw)
    61         a = self.matchrule(kw)
    77         return a in self.levels and self.levels.index(a) <= self.levels.index(level)
    62         return a in self.levels and self.levels.index(a) <= self.levels.index(level)
    78     
    63     
       
    64     def check(self, level, **kw):
       
    65         if not self.allow(level, **kw):
       
    66             raise AccessException()
       
    67     
    79     def readfile(self, fn):
    68     def readfile(self, fn):
    80         try:
    69         try:
    81             f = open(fn)
    70             f = open(fn)
    82             try:
    71             try:
    83                 for l in f:
    72                 for l in f: