webcalendar

Check-in [d8a95c83d6]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Switch from PHP session stuff to basic cookie authen. Implement all the goop to play with the rest of the calendar's cookie management.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | master | trunk
Files: files | file ages | folders
SHA3-256:d8a95c83d6e03dafe7fef5ce3360517e5cbee1ed8729008644b3629cff461219
User & Date: ajv-899-334-8894@vsta.org 2017-06-01 03:34:04
Context
2017-06-01
03:35
Not using PHP session stuff any more check-in: c0466bed2f user: ajv-899-334-8894@vsta.org tags: master, trunk
03:34
Switch from PHP session stuff to basic cookie authen. Implement all the goop to play with the rest of the calendar's cookie management. check-in: d8a95c83d6 user: ajv-899-334-8894@vsta.org tags: master, trunk
2017-05-30
19:45
Add a debug startup to "today" so I can play with its function in the CLI. Fix timezone treatment so daylight savings state for the start date of a repeat is calculated correctly. Streamline elems, use a CSS rule instead. check-in: 7470f6e3bf user: ajv-899-334-8894@vsta.org tags: master, trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Added cgi-bin/auth.py.

            1  +#!/usr/bin/python
            2  +#
            3  +# auth.py
            4  +#	Deal with cookies, passwords, and all that stuff
            5  +#
            6  +import os, Cookie
            7  +from passlib.hash import md5_crypt
            8  +import webcal
            9  +
           10  +# CGI environment variable for cookies, and the one we want
           11  +CGICOOK = "HTTP_COOKIE"
           12  +SESSCOOK = "webcalendar_session"
           13  +
           14  +# Set up, when we're invoked as a CGI under a web server
           15  +# Return None for failure, or the authenticated user name
           16  +def authen_cookie():
           17  +
           18  +    # Pull cookie which proves who we are
           19  +    if CGICOOK not in os.environ:
           20  +	# Didn't present any cookies
           21  +	return None
           22  +    cookies = Cookie.SimpleCookie(os.environ[CGICOOK])
           23  +    if SESSCOOK not in cookies:
           24  +	# Didn't present a session cookie
           25  +	return None
           26  +    cookie = cookies[SESSCOOK].value
           27  +    tup = webcal.decode_string(cookie).split("|")
           28  +    if (not tup) or (len(tup) != 2):
           29  +	# Malformed cookie
           30  +	return None
           31  +    uname,cryptpw = tup
           32  +
           33  +    # Pull our DB record for this guy
           34  +    c = webcal.db.cursor()
           35  +    c.execute("select cal_passwd from webcal_user where cal_login = %s",
           36  +	(uname,))
           37  +    tup = c.fetchone()
           38  +    c.close()
           39  +    if tup is None:
           40  +	return None
           41  +    dbpw = tup[0]
           42  +
           43  +    # Tell if it matches
           44  +    if not md5_crypt.verify(dbpw, cryptpw):
           45  +	return None
           46  +
           47  +    return uname
           48  +
           49  +# Run this as a part of the CGI startup.  It'll push out a
           50  +#  redir (so they can log in) and return None, otherwise
           51  +#  it'll return the authenticated user's name
           52  +def init_cgi():
           53  +    # Common header
           54  +    print """Content-Type: text/html
           55  +
           56  +<html>
           57  +"""
           58  +
           59  +    # Authentication
           60  +    uname = authen_cookie()
           61  +    if uname is None:
           62  +	print """<head>
           63  +	<title>Bad Webcalendar Session</title>
           64  +	<meta http-equiv="REFRESH" content="1;url=/webcal" />
           65  +       </head>
           66  +       <body>
           67  +	Redirecting you to Webcalendar for login...
           68  +       </body>
           69  +    </html>
           70  +    """
           71  +	return None
           72  +    return uname
           73  +

Changes to cgi-bin/today.py.

     1      1   #!/usr/bin/python
     2      2   #
     3      3   # today.py
     4      4   #	Display events for today
     5      5   #
     6      6   import sys, time, os
     7      7   from webcal import cmp_time
     8         -import webcal
            8  +import webcal, auth
     9      9   
    10     10   # By default, display events for Today
    11     11   Target = webcal.Today
    12     12   
    13     13   # Filled in by authen (or debug)
    14     14   uname = None
    15     15   
    16         -# Common HTTP response header
    17         -print """Content-Type: text/html
    18         -
    19         -<html>
    20         -"""
    21         -
    22         -
    23         -# Set up, when we're invoked as a CGI under a web server
    24         -def init_cgi():
    25         -    global uname
    26         -    import Cookie, phpsession
    27         -
    28         -    try:
    29         -	# Hopefully our PHP session cookie
    30         -	cookie = Cookie.SimpleCookie(os.environ["HTTP_COOKIE"])
    31         -	sessid = cookie["PHPSESSID"].value
    32         -	if ".." in sessid:
    33         -	    sessid = "XXX"
    34         -	f = open("/var/lib/php5/sessions/sess_" + sessid, "r")
    35         -	sess = phpsession.load(f)
    36         -	uname = sess["webcal_login"]
    37         -	f.close()
    38         -
    39         -    except:
    40         -	print """<head>
    41         -	<title>Bad Webcalendar Session</title>
    42         -	<meta http-equiv="REFRESH" content="1;url=/webcal" />
    43         -       </head>
    44         -       <body>
    45         -	Redirecting you to Webcalendar for login...
    46         -       </body>
    47         -    </html>
    48         -    """
    49         -	sys.exit(0)
    50         -
    51     16   # Set up when we're manually invoked (for testing)
    52     17   def init_cli():
    53     18       global uname, Target
    54     19   
    55     20       if not os.isatty(0):
    56     21   	raise Exception, "Bad CLI invocation"
    57     22       uname = sys.argv[1]
................................................................................
   173    138   </html>
   174    139   """)
   175    140   
   176    141   if __name__ == "__main__":
   177    142       if len(sys.argv) > 1:
   178    143   	init_cli()
   179    144       else:
   180         -	init_cgi()
   181         -    run()
          145  +	uname = auth.init_cgi()
          146  +    if uname:
          147  +	run()

Changes to cgi-bin/webcal.py.

     1      1   #
     2      2   # today.py
     3      3   #	Pull all events from a icalendar, display today's
     4      4   #
     5         -import time, os, calendar
            5  +import time, os, calendar, hashlib
     6      6   import MySQLdb as mysql
     7      7   import pdb
     8      8   
     9      9   # Indices into webcal_entry
    10     10   WE_ID = 0	# Entry's ID
    11     11   WE_WHEN = 4	# Date (and time at 5)
    12     12   WE_DUR = 8	# Duration (minutes)
................................................................................
   445    445       for tup in c:
   446    446   	for ev in load_cal(tup[0], filter):
   447    447   	    ev.color = tup[1]
   448    448   	    entries.add(ev)
   449    449       c.close()
   450    450   
   451    451       return entries
          452  +
          453  +# The cookie value is hashed against a value derived from the
          454  +#  installation password.  This table creates the values which
          455  +#  drive the hash.
          456  +Offsets = []
          457  +def md5(s):
          458  +    m = hashlib.md5(s).digest()
          459  +    return "".join(("%02x" % (ord(c),)) for c in m)
          460  +def init_salt():
          461  +    global cfg, Offsets
          462  +
          463  +    salt = cfg.get("install_password") or md5(cfg.get("db_login"))
          464  +    salt2 = md5(cfg.get("db_password", "oogabooga"))
          465  +    for i in xrange(max(len(salt), len(salt2))):
          466  +	val = 0
          467  +	if i < len(salt):
          468  +	    val += ord(salt[i])
          469  +	if i < len(salt2):
          470  +	    val += ord(salt2[i])
          471  +	Offsets.append(val & 0x7F)
          472  +init_salt()
          473  +
          474  +# Decode a string ala PHP's function of the same name
          475  +#
          476  +# It's salted with the install password, available via the
          477  +#  system config which we've already pulled in.
          478  +def decode_string(encoded):
          479  +    global Offsets
          480  +
          481  +    ol = len(Offsets)
          482  +    decoded = ""
          483  +    idx = 0
          484  +    while encoded:
          485  +	val = ord(encoded[:2].decode("hex"))
          486  +	encoded = encoded[2:]
          487  +	val = (((val - Offsets[idx % ol]) + 256) & 0xFF)
          488  +	decoded += chr(val)
          489  +	idx += 1
          490  +
          491  +    return decoded