ADDED cgi-bin/auth.py
Index: cgi-bin/auth.py
==================================================================
--- cgi-bin/auth.py
+++ cgi-bin/auth.py
@@ -0,0 +1,73 @@
+#!/usr/bin/python
+#
+# auth.py
+# Deal with cookies, passwords, and all that stuff
+#
+import os, Cookie
+from passlib.hash import md5_crypt
+import webcal
+
+# CGI environment variable for cookies, and the one we want
+CGICOOK = "HTTP_COOKIE"
+SESSCOOK = "webcalendar_session"
+
+# Set up, when we're invoked as a CGI under a web server
+# Return None for failure, or the authenticated user name
+def authen_cookie():
+
+ # Pull cookie which proves who we are
+ if CGICOOK not in os.environ:
+ # Didn't present any cookies
+ return None
+ cookies = Cookie.SimpleCookie(os.environ[CGICOOK])
+ if SESSCOOK not in cookies:
+ # Didn't present a session cookie
+ return None
+ cookie = cookies[SESSCOOK].value
+ tup = webcal.decode_string(cookie).split("|")
+ if (not tup) or (len(tup) != 2):
+ # Malformed cookie
+ return None
+ uname,cryptpw = tup
+
+ # Pull our DB record for this guy
+ c = webcal.db.cursor()
+ c.execute("select cal_passwd from webcal_user where cal_login = %s",
+ (uname,))
+ tup = c.fetchone()
+ c.close()
+ if tup is None:
+ return None
+ dbpw = tup[0]
+
+ # Tell if it matches
+ if not md5_crypt.verify(dbpw, cryptpw):
+ return None
+
+ return uname
+
+# Run this as a part of the CGI startup. It'll push out a
+# redir (so they can log in) and return None, otherwise
+# it'll return the authenticated user's name
+def init_cgi():
+ # Common header
+ print """Content-Type: text/html
+
+
+"""
+
+ # Authentication
+ uname = authen_cookie()
+ if uname is None:
+ print """
+ Bad Webcalendar Session
+
+
+
+ Redirecting you to Webcalendar for login...
+
+
+ """
+ return None
+ return uname
+
Index: cgi-bin/today.py
==================================================================
--- cgi-bin/today.py
+++ cgi-bin/today.py
@@ -3,53 +3,18 @@
# today.py
# Display events for today
#
import sys, time, os
from webcal import cmp_time
-import webcal
+import webcal, auth
# By default, display events for Today
Target = webcal.Today
# Filled in by authen (or debug)
uname = None
-# Common HTTP response header
-print """Content-Type: text/html
-
-
-"""
-
-
-# Set up, when we're invoked as a CGI under a web server
-def init_cgi():
- global uname
- import Cookie, phpsession
-
- try:
- # Hopefully our PHP session cookie
- cookie = Cookie.SimpleCookie(os.environ["HTTP_COOKIE"])
- sessid = cookie["PHPSESSID"].value
- if ".." in sessid:
- sessid = "XXX"
- f = open("/var/lib/php5/sessions/sess_" + sessid, "r")
- sess = phpsession.load(f)
- uname = sess["webcal_login"]
- f.close()
-
- except:
- print """
- Bad Webcalendar Session
-
-
-
- Redirecting you to Webcalendar for login...
-
-
- """
- sys.exit(0)
-
# Set up when we're manually invoked (for testing)
def init_cli():
global uname, Target
if not os.isatty(0):
@@ -175,7 +140,8 @@
if __name__ == "__main__":
if len(sys.argv) > 1:
init_cli()
else:
- init_cgi()
- run()
+ uname = auth.init_cgi()
+ if uname:
+ run()
Index: cgi-bin/webcal.py
==================================================================
--- cgi-bin/webcal.py
+++ cgi-bin/webcal.py
@@ -1,10 +1,10 @@
#
# today.py
# Pull all events from a icalendar, display today's
#
-import time, os, calendar
+import time, os, calendar, hashlib
import MySQLdb as mysql
import pdb
# Indices into webcal_entry
WE_ID = 0 # Entry's ID
@@ -447,5 +447,45 @@
ev.color = tup[1]
entries.add(ev)
c.close()
return entries
+
+# The cookie value is hashed against a value derived from the
+# installation password. This table creates the values which
+# drive the hash.
+Offsets = []
+def md5(s):
+ m = hashlib.md5(s).digest()
+ return "".join(("%02x" % (ord(c),)) for c in m)
+def init_salt():
+ global cfg, Offsets
+
+ salt = cfg.get("install_password") or md5(cfg.get("db_login"))
+ salt2 = md5(cfg.get("db_password", "oogabooga"))
+ for i in xrange(max(len(salt), len(salt2))):
+ val = 0
+ if i < len(salt):
+ val += ord(salt[i])
+ if i < len(salt2):
+ val += ord(salt2[i])
+ Offsets.append(val & 0x7F)
+init_salt()
+
+# Decode a string ala PHP's function of the same name
+#
+# It's salted with the install password, available via the
+# system config which we've already pulled in.
+def decode_string(encoded):
+ global Offsets
+
+ ol = len(Offsets)
+ decoded = ""
+ idx = 0
+ while encoded:
+ val = ord(encoded[:2].decode("hex"))
+ encoded = encoded[2:]
+ val = (((val - Offsets[idx % ol]) + 256) & 0xFF)
+ decoded += chr(val)
+ idx += 1
+
+ return decoded