Merge branch 'master' into python3
authorFredrik Tolf <fredrik@dolda2000.com>
Sun, 3 Nov 2013 14:10:10 +0000 (15:10 +0100)
committerFredrik Tolf <fredrik@dolda2000.com>
Sun, 3 Nov 2013 14:17:43 +0000 (15:17 +0100)
1  2 
wrw/auth.py
wrw/sp/cons.py

diff --combined wrw/auth.py
index 0000000,4ae292d..1858214
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,90 +1,98 @@@
 -import resp
+ import binascii, hashlib, threading, time
 -        super(unauthorized, self).__init__(401, message, detail)
++from . import resp
+ class unauthorized(resp.httperror):
+     def __init__(self, challenge, message=None, detail=None):
 -        return super(unauthorized, self).handle(req)
++        super().__init__(401, message, detail)
+         if isinstance(challenge, str):
+             challenge = [challenge]
+         self.challenge = challenge
+     def handle(self, req):
+         for challenge in self.challenge:
+             req.ohead.add("WWW-Authenticate", challenge)
 -        super(forbidden, self).__init__(403, message, detail)
++        return super().handle(req)
+ class forbidden(resp.httperror):
+     def __init__(self, message=None, detail=None):
 -        dig.update(self.realm)
 -        dig.update(nm)
 -        dig.update(pw)
++        super().__init__(403, message, detail)
+ def parsemech(req):
+     h = req.ihead.get("Authorization", None)
+     if h is None:
+         return None, None
+     p = h.find(" ")
+     if p < 0:
+         return None, None
+     return h[:p].strip().lower(), h[p + 1:].strip()
+ def parsebasic(req):
+     mech, data = parsemech(req)
+     if mech != "basic":
+         return None, None
+     try:
++        data = data.encode("us-ascii")
++    except UnicodeError:
++        return None, None
++    try:
+         raw = binascii.a2b_base64(data)
+     except binascii.Error:
+         return None, None
++    try:
++        raw = raw.decode("utf-8")
++    except UnicodeError:
++        raw = raw.decode("latin1")
+     p = raw.find(":")
+     if p < 0:
+         return None, None
+     return raw[:p], raw[p + 1:]
+ class basiccache(object):
+     cachetime = 300
+     def __init__(self, realm, authfn=None):
+         self._lock = threading.Lock()
+         self._cache = {}
+         self.realm = realm
+         if authfn is not None:
+             self.auth = authfn
+     def _obscure(self, nm, pw):
+         dig = hashlib.sha256()
 -            except forbidden, exc:
++        dig.update(self.realm.encode("utf-8"))
++        dig.update(nm.encode("utf-8"))
++        dig.update(pw.encode("utf-8"))
+         return dig.digest()
+     def check(self, req):
+         nm, pw = parsebasic(req)
+         if nm is None:
+             raise unauthorized("Basic Realm=\"%s\"" % self.realm)
+         pwh = self._obscure(nm, pw)
+         now = time.time()
+         with self._lock:
+             if (nm, pwh) in self._cache:
+                 lock, atime, res, resob = self._cache[nm, pwh]
+                 if now - atime < self.cachetime:
+                     if res == "s":
+                         return resob
+                     elif res == "f":
+                         raise resob
+             else:
+                 lock = threading.Lock()
+                 self._cache[nm, pwh] = (lock, now, None, None)
+         with lock:
+             try:
+                 ret = self.auth(req, nm, pw)
++            except forbidden as exc:
+                 with self._lock:
+                     self._cache[nm, pwh] = (lock, now, "f", exc)
+                 raise
+             if ret is None:
+                 raise forbidden()
+             with self._lock:
+                 self._cache[nm, pwh] = (lock, now, "s", ret)
+             return ret
+     def auth(self, req, nm, pw):
+         raise Exception("authentication function neither supplied nor overridden")
diff --combined wrw/sp/cons.py
@@@ -4,18 -4,18 +4,18 @@@ import xml.dom.minido
  class node(object):
      pass
  
 -class text(node, unicode):
 +class text(node, str):
      def __todom__(self, doc):
          return doc.createTextNode(self)
  
 -class raw(node, unicode):
 +class raw(node, str):
      def __todom__(self, doc):
          raise Exception("Cannot convert raw code to DOM objects")
  
  class element(node):
      def __init__(self, ns, name, ctx):
          self.ns = ns
 -        self.name = unicode(name)
 +        self.name = str(name)
          self.ctx = ctx
          self.attrs = {}
          self.children = []
      def __call__(self, *children, **attrs):
          for child in children:
              self.ctx.addchild(self, child)
 -        for k, v in attrs.iteritems():
 +        for k, v in attrs.items():
              self.ctx.addattr(self, k, v)
          return self
  
      def __todom__(self, doc):
          el = doc.createElementNS(self.ns, self.name)
 -        for k, v in self.attrs.iteritems():
 +        for k, v in self.attrs.items():
              el.setAttribute(k, v)
          for child in self.children:
              el.appendChild(child.__todom__(doc))
          return self.__todom__(doc).toxml()
  
  class context(object):
-     charset = sys.getfilesystemencoding()
+     charset = (sys.getfilesystemencoding() or "ascii")
  
      def __init__(self):
          self.nodeconv = {}
 -        self.nodeconv[str] = lambda ob: text(ob, self.charset)
 -        self.nodeconv[unicode] = text
 +        self.nodeconv[bytes] = lambda ob: text(ob, self.charset)
 +        self.nodeconv[str] = text
          self.nodeconv[int] = text
 -        self.nodeconv[long] = text
          self.nodeconv[float] = text
  
      def nodefrom(self, ob):
@@@ -63,7 -64,7 +63,7 @@@
  
      def addattr(self, node, k, v):
          if v is not None:
 -            node.attrs[unicode(k)] = unicode(v)
 +            node.attrs[str(k)] = str(v)
  
  class constructor(object):
      def __init__(self, ns, elcls=element, ctx=None):