[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [pygame] Networking library



Patrick Mullen wrote:
On Sat, Apr 11, 2009 at 2:55 AM, Chris McCormick <chris@xxxxxxxxxxxx> wrote:
Hi,

On Fri, Apr 10, 2009 at 04:44:30PM -0700, Patrick Mullen wrote:
Python2.6 comes with json.  Other than that, it is a small thing to include.

The library seems to be built around json, so removing it as a
dependency doesn't make much sense.
Actually I don't think it would be a huge job to change the serialisation
method to something else, optionally. I'll have a look it and see. My only
concern is about security - I chose JSON serialisation over something like
pickling because there's no way a client can inject malicious code using JSON.
I wonder if there's some other safe, built-in, pythonic way of serialising data
structures that I don't know about?

True. You could probably make the serialization abstract and allow
other methods, by plugging in a different Serializer class of some
sort.  Other than json, yaml, xml, etc I don't know any other good
serialization for python, and everything I can think of is a
dependency. Maybe for easy testing it could work with repr/eval, but
prefers json if it is there.  (Repr/eval can serialize the same
dictionaries that json can, and I think it's a bit faster too, its
just a bit more dangerous)

I'm not exactly sure how `safe` they really are but I found a recipe for `safe eval` (I think on activestate) using the built in compiler module that I iirc works on >= 2.4 python. Only about 70 lines of code or so. The eval only work on literals ala JSON

I wrote some tests somewhere but I can't seem to place them. Anway, in todays broadband world what's a few K for simpleson included.


import compiler

class Unsafe_Source_Error(Exception):
   def __init__(self,error,descr = None,node = None):
       self.error = error
       self.descr = descr
       self.node = node
       self.lineno = getattr(node,"lineno",None)
def __repr__(self):
       return "Line %d.  %s: %s" % (self.lineno, self.error, self.descr)
__str__ = __repr__ class SafeEval(object):
   def visit(self, node,**kw):
       cls = node.__class__
       meth = getattr(self,'visit'+cls.__name__,self.default)
       return meth(node, **kw)
def default(self, node, **kw):
       for child in node.getChildNodes():
           return self.visit(child, **kw)
visitExpression = default def visitConst(self, node, **kw):
       return node.value

   def visitDict(self,node,**kw):
       return dict([(self.visit(k),self.visit(v)) for k,v in node.items])
def visitUnarySub(self, node, **kw):
       return -self.visit(node.getChildNodes()[0])
def visitTuple(self,node, **kw):
       return tuple(self.visit(i) for i in node.nodes)
def visitList(self,node, **kw):
       return [self.visit(i) for i in node.nodes]

class SafeEvalWithErrors(SafeEval):
   def default(self, node, **kw):
       raise Unsafe_Source_Error("Unsupported source construct",
                               node.__class__,node)

   def visitName(self,node, **kw):
       if node.name == 'None':
           return None

       if node.name == 'True':
           return True

       if node.name == 'False':
           return False
raise Unsafe_Source_Error("Strings must be quoted",
                                node.name, node)

   # Add more specific errors if desired

def safe_eval(source, fail_on_error = True):
   walker = fail_on_error and SafeEvalWithErrors() or SafeEval()
   try:
       ast = compiler.parse(source,"eval")
   except SyntaxError, err:
       raise
   try:
       return walker.visit(ast)
   except Unsafe_Source_Error, err:
       raise