Code

Fix first part of Password handling security issue2550688 (thanks
[roundup.git] / roundup / backends / back_anydbm.py
index 3d132ec672062730b2446ee3dd1ac6d369588ed2..f8ba81399c6a232a9c9642f22260facdff304d5c 100644 (file)
@@ -49,6 +49,87 @@ def db_exists(config):
 def db_nuke(config):
     shutil.rmtree(config.DATABASE)
 
+class Binary:
+
+    def __init__(self, x, y):
+        self.x = x
+        self.y = y
+
+    def visit(self, visitor):
+        self.x.visit(visitor)
+        self.y.visit(visitor)
+
+class Unary:
+
+    def __init__(self, x):
+        self.x = x
+
+    def generate(self, atom):
+        return atom(self)
+
+    def visit(self, visitor):
+        self.x.visit(visitor)
+
+class Equals(Unary):
+
+    def evaluate(self, v):
+        return self.x in v
+
+    def visit(self, visitor):
+        visitor(self)
+
+class Not(Unary):
+
+    def evaluate(self, v):
+        return not self.x.evaluate(v)
+
+    def generate(self, atom):
+        return "NOT(%s)" % self.x.generate(atom)
+
+class Or(Binary):
+
+    def evaluate(self, v):
+        return self.x.evaluate(v) or self.y.evaluate(v)
+
+    def generate(self, atom):
+        return "(%s)OR(%s)" % (
+            self.x.generate(atom),
+            self.y.generate(atom))
+
+class And(Binary):
+
+    def evaluate(self, v):
+        return self.x.evaluate(v) and self.y.evaluate(v)
+
+    def generate(self, atom):
+        return "(%s)AND(%s)" % (
+            self.x.generate(atom),
+            self.y.generate(atom))
+
+def compile_expression(opcodes):
+
+    stack = []
+    push, pop = stack.append, stack.pop
+    for opcode in opcodes:
+        if   opcode == -2: push(Not(pop()))
+        elif opcode == -3: push(And(pop(), pop()))
+        elif opcode == -4: push(Or(pop(), pop()))
+        else:              push(Equals(opcode))
+
+    return pop()
+
+class Expression:
+
+    def __init__(self, v):
+        try:
+            opcodes = [int(x) for x in v]
+            if min(opcodes) >= -1: raise ValueError()
+
+            compiled = compile_expression(opcodes)
+            self.evaluate = lambda x: compiled.evaluate([int(y) for y in x])
+        except:
+            self.evaluate = lambda x: bool(set(x) & set(v))
+
 #
 # Now the database
 #
@@ -158,7 +239,9 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database):
 
     def getclasses(self):
         """Return a list of the names of all existing classes."""
-        return sorted(self.classes)
+        l = self.classes.keys()
+        l.sort()
+        return l
 
     def getclass(self, classname):
         """Get the Class object representing a particular class.
@@ -421,9 +504,7 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database):
             elif isinstance(prop, hyperdb.Interval) and v is not None:
                 d[k] = date.Interval(v)
             elif isinstance(prop, hyperdb.Password) and v is not None:
-                p = password.Password()
-                p.unpack(v)
-                d[k] = p
+                d[k] = password.Password(encrypted=v)
             else:
                 d[k] = v
         return d
@@ -1661,7 +1742,7 @@ class Class(hyperdb.Class):
                 l.append((OTHER, k, [float(val) for val in v]))
 
         filterspec = l
-        
+
         # now, find all the nodes that are active and pass filtering
         matches = []
         cldb = self.db.getclassdb(cn)
@@ -1700,12 +1781,10 @@ class Class(hyperdb.Class):
                         if not v:
                             match = not nv
                         else:
-                            # othewise, make sure this node has each of the
+                            # otherwise, make sure this node has each of the
                             # required values
-                            for want in v:
-                                if want in nv:
-                                    match = 1
-                                    break
+                            expr = Expression(v)
+                            if expr.evaluate(nv): match = 1
                     elif t == STRING:
                         if nv is None:
                             nv = ''
@@ -1947,9 +2026,7 @@ class Class(hyperdb.Class):
             elif isinstance(prop, hyperdb.Interval):
                 value = date.Interval(value)
             elif isinstance(prop, hyperdb.Password):
-                pwd = password.Password()
-                pwd.unpack(value)
-                value = pwd
+                value = password.Password(encrypted=value)
             d[propname] = value
 
         # get a new id if necessary