--- /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 <paul@lshift.net>
+#
+# 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