--- /dev/null
-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")
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):
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):