diff -r 2f0ea1163b9e -r fd16d9a1234b src/mercurialserver/ruleset.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mercurialserver/ruleset.py Fri Mar 06 09:15:00 2009 +0000 @@ -0,0 +1,96 @@ +# Copyright 2008-2009 LShift Ltd +# Author(s): +# Paul Crowley +# +# This software may be used and distributed according to the terms +# of the GNU General Public License, incorporated herein by reference. + +import sys +import re +import os +import os.path + +allowedchars = "A-Za-z0-9_-" + +goodpathre = re.compile("([%s]+/)*[%s]+$" % (allowedchars, allowedchars)) +def goodpath(path): + return goodpathre.match(path) is not None + +goodglobre = re.compile("[*/%s]+$" % allowedchars) + +def goodglob(pattern): + return goodglobre.match(pattern) is not None + +# Don't put anything except *A-Za-z0-9_- in rule globs or +# it will match nothing. No regexp metachars, not even . +# We may fix this later. +def globmatcher(pattern): + if not goodglob(pattern): + #fail("Bad glob pattern in auth config: %s" % pattern) + # FIXME: report it somehow + return lambda x: False + # Substitution cunning so ** can be different from * + pattern = pattern.replace("*", "[]") + pattern = pattern.replace("[][]", "[/%s]*" % allowedchars) + pattern = pattern.replace("[]", "[%s]*" % allowedchars) + rex = re.compile(pattern + "$") + # None matches everything + return lambda x: x is None or rex.match(x) is not None + +def rule(pairs): + matchers = [(k, globmatcher(v)) for k, v in pairs] + def c(kw): + for k, m in matchers: + if k not in kw or not m(kw[k]): + return False + return True + return c + +class Ruleset(object): + '''Class representing the rules in a rule file''' + + levels = ["init", "write", "read", "deny"] + + def __init__(self): + self.rules = [] + self.preset = {} + + def add(self, action, conditions): + self.rules.append((action, conditions)) + + def set(self, **kw): + self.preset.update(kw) + + def matchrule(self, kw): + d = self.preset.copy() + d.update(kw) + for a, c in self.rules: + if c(d): + return a + return None + + def allow(self, level, **kw): + a = self.matchrule(kw) + return a in self.levels and self.levels.index(a) <= self.levels.index(level) + + def readfile(self, fn): + try: + f = open(fn) + try: + for l in f: + l = l.strip() + if len(l) == 0 or l.startswith("#"): + continue + l = l.split() + self.add(l[0], rule([c.split("=", 1) for c in l[1:]])) + finally: + f.close() + except Exception, e: + print >> sys.stderr, "Failure reading rules file:", e + +def rules_from_env(): + res = Ruleset() + for f in os.environ['HG_ACCESS_RULES_PATH'].split(os.pathsep): + if os.path.isfile(f): + res.readfile(f) + return res