summaryrefslogtreecommitdiffstats
path: root/py-bin/lib/jon/session.py
diff options
context:
space:
mode:
Diffstat (limited to 'py-bin/lib/jon/session.py')
-rw-r--r--py-bin/lib/jon/session.py209
1 files changed, 209 insertions, 0 deletions
diff --git a/py-bin/lib/jon/session.py b/py-bin/lib/jon/session.py
new file mode 100644
index 0000000..7a253ab
--- /dev/null
+++ b/py-bin/lib/jon/session.py
@@ -0,0 +1,209 @@
+# $Id: session.py,v 1.9 2003/01/02 23:24:44 jribbens Exp $
+
+import time, hmac, sha, Cookie, re, random, os, errno, fcntl
+try:
+ import cPickle as pickle
+except ImportError:
+ import pickle
+
+
+class Error(Exception):
+ pass
+
+
+class Session(dict):
+ def _make_hash(self, sid, secret):
+ """Create a hash for 'sid'
+
+ This function may be overridden by subclasses."""
+ return hmac.new(secret, sid, sha).hexdigest()[:8]
+
+ def _create(self, secret):
+ """Create a new session ID and, optionally hash
+
+ This function must insert the new session ID (which must be 8 hexadecimal
+ characters) into self["id"].
+
+ It may optionally insert the hash into self["hash"]. If it doesn't, then
+ _make_hash will automatically be called later.
+
+ This function may be overridden by subclasses.
+ """
+ rnd = str(time.time()) + str(random.random()) + \
+ str(self._req.environ.get("UNIQUE_ID"))
+ self["id"] = sha.new(rnd).hexdigest()[:8]
+
+ def _load(self):
+ """Load the session dictionary from somewhere
+
+ This function may be overridden by subclasses.
+ It should return 1 if the load was successful, or 0 if the session could
+ not be found. Any other type of error should raise an exception as usual."""
+ return 1
+
+ def save(self):
+ """Save the session dictionary to somewhere
+
+ This function may be overridden by subclasses."""
+ pass
+
+ def tidy():
+ pass
+ tidy = staticmethod(tidy)
+
+ def __init__(self, req, secret, cookie="jonsid", url=0, root="",
+ referer=None, sid=None, shash=None):
+ dict.__init__(self)
+ self["id"] = None
+ self._req = req
+ self.relocated = 0
+ self.new = 0
+
+ # try and determine existing session id
+
+ if sid is not None:
+ self["id"] = sid
+ if shash is None:
+ self["hash"] = self._make_hash(self["id"], secret)
+ else:
+ self["hash"] = shash
+ if self["hash"] != self._make_hash(self["id"], secret):
+ self["id"] = None
+
+ if cookie and self._req.cookies.has_key(cookie):
+ self["id"] = self._req.cookies[cookie].value[:8]
+ self["hash"] = self._req.cookies[cookie].value[8:]
+ if self["hash"] != self._make_hash(self["id"], secret):
+ self["id"] = None
+
+ if url:
+ for i in xrange(1, 4):
+ requrl = self._req.environ.get("REDIRECT_" * i + "SESSION")
+ if requrl:
+ break
+ if requrl and self["id"] is None:
+ self["id"] = requrl[:8]
+ self["hash"] = requrl[8:]
+ if self["hash"] != self._make_hash(self["id"], secret):
+ self["id"] = None
+
+ # check the session
+
+ if referer:
+ if self._req.environ.has_key("HTTP_REFERER"):
+ if self._req.environ["HTTP_REFERER"].find(referer) == -1:
+ self["id"] = None
+
+ # try and load the session
+
+ if self["id"] is not None:
+ if not self._load():
+ self["id"] = None
+
+ # if no session was available and loaded, create a new one
+
+ if self["id"] is None:
+ if self.has_key("hash"):
+ del self["hash"]
+ self.created = time.time()
+ self.new = 1
+ self._create(secret)
+ if not self.has_key("hash"):
+ self["hash"] = self._make_hash(self["id"], secret)
+ if cookie:
+ c = Cookie.SimpleCookie()
+ c[cookie] = self["id"] + self["hash"]
+ c[cookie]["path"] = root + "/"
+ self._req.add_header("Set-Cookie", c[cookie].OutputString())
+
+ # if using url-based sessions, redirect if necessary
+
+ if url:
+ if not requrl or self["id"] != requrl[:8] or self["hash"] != requrl[8:]:
+ requrl = self._req.environ["REQUEST_URI"][len(root):]
+ requrl = re.sub("^/[A-Fa-f0-9]{16}/", "/", requrl)
+ self._req.add_header("Location", "http://" +
+ self._req.environ["SERVER_NAME"] + root + "/" + self["id"] +
+ self["hash"] + requrl)
+ self.relocated = 1
+ self.surl = root + "/" + self["id"] + self["hash"] + "/"
+
+class FileSession(Session):
+ def _create(self, secret):
+ while 1:
+ Session._create(self, secret)
+ try:
+ os.lstat("%s/%s" % (self.basedir, self["id"][:2]))
+ except OSError, x:
+ if x[0] == errno.ENOENT:
+ os.mkdir("%s/%s" % (self.basedir, self["id"][:2]), 0700)
+ try:
+ fd = os.open("%s/%s/%s" % (self.basedir, self["id"][:2],
+ self["id"][2:]), os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0700)
+ except OSError, x:
+ if x[0] != errno.EEXIST:
+ raise
+ continue
+ f = os.fdopen(fd, "wb")
+ f.write("%d\n" % self.created)
+ pickle.dump({}, f, 1)
+ f.flush()
+ break
+
+ def _load(self):
+ try:
+ f = open("%s/%s/%s" % (self.basedir, self["id"][:2], self["id"][2:]),
+ "r+b")
+ except IOError, x:
+ if x[0] != errno.ENOENT:
+ raise
+ return 0
+ fcntl.lockf(f.fileno(), fcntl.LOCK_EX)
+ self.created = int(f.readline().strip())
+ self.update(pickle.load(f))
+ return 1
+
+ def save(self):
+ f = open("%s/%s/%s" % (self.basedir, self["id"][:2], self["id"][2:]), "r+b")
+ fcntl.lockf(f.fileno(), fcntl.LOCK_EX)
+ f.write("%d\n" % self.created)
+ pickle.dump(self.copy(), f, 1)
+ f.flush()
+ f.truncate()
+
+ def tidy(cls, max_idle=0, max_age=0, basedir=None):
+ if not max_idle and not max_age:
+ return
+ basedir = cls._find_basedir(basedir)
+ now = time.time()
+ for d in os.listdir(basedir):
+ if len(d) != 2 or not d.isalnum():
+ continue
+ for f in os.listdir("%s/%s" % (basedir, d)):
+ if len(f) != 6 or not f.isalnum():
+ continue
+ p = "%s/%s/%s" % (basedir, d, f)
+ if (max_idle and os.lstat(p).st_mtime < now - max_idle) or \
+ (max_age and int(open(p, "rb").readline().strip()) < now - max_age):
+ os.remove(p)
+ tidy = classmethod(tidy)
+
+ def _find_basedir(basedir):
+ if basedir is None:
+ basedir = os.environ.get("TMPDIR", "/tmp")
+ while basedir[-1] == "/":
+ basedir = basedir[:-1]
+ basedir = "%s/jon-sessions-%d" % (basedir, os.getuid())
+ try:
+ st = os.lstat(basedir)
+ if st[4] != os.getuid():
+ raise Error, "Sessions basedir is not owned by user %d" % os.getuid()
+ except OSError, x:
+ if x[0] == errno.ENOENT:
+ os.mkdir(basedir, 0700)
+ return basedir
+ _find_basedir = staticmethod(_find_basedir)
+
+ def __init__(self, req, secret, basedir=None, **kwargs):
+ self.basedir = self._find_basedir(basedir)
+ Session.__init__(self, req, secret, **kwargs)