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 Unified Diffs Ignore Whitespace Patch

Added cgi-bin/auth.py.



















































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
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

<html>
"""

    # Authentication
    uname = authen_cookie()
    if uname is None:
	print """<head>
	<title>Bad Webcalendar Session</title>
	<meta http-equiv="REFRESH" content="1;url=/webcal" />
       </head>
       <body>
	Redirecting you to Webcalendar for login...
       </body>
    </html>
    """
	return None
    return uname

Changes to cgi-bin/today.py.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
...
173
174
175
176
177
178
179
180

181
#!/usr/bin/python
#
# today.py
#	Display events for today
#
import sys, time, os
from webcal import cmp_time
import webcal

# 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

<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 """<head>
	<title>Bad Webcalendar Session</title>
	<meta http-equiv="REFRESH" content="1;url=/webcal" />
       </head>
       <body>
	Redirecting you to Webcalendar for login...
       </body>
    </html>
    """
	sys.exit(0)

# Set up when we're manually invoked (for testing)
def init_cli():
    global uname, Target

    if not os.isatty(0):
	raise Exception, "Bad CLI invocation"
    uname = sys.argv[1]
................................................................................
</html>
""")

if __name__ == "__main__":
    if len(sys.argv) > 1:
	init_cli()
    else:
	init_cgi()

    run()







|







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







|
>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15



































16
17
18
19
20
21
22
...
138
139
140
141
142
143
144
145
146
147
#!/usr/bin/python
#
# today.py
#	Display events for today
#
import sys, time, os
from webcal import cmp_time
import webcal, auth

# By default, display events for Today
Target = webcal.Today

# Filled in by authen (or debug)
uname = None




































# Set up when we're manually invoked (for testing)
def init_cli():
    global uname, Target

    if not os.isatty(0):
	raise Exception, "Bad CLI invocation"
    uname = sys.argv[1]
................................................................................
</html>
""")

if __name__ == "__main__":
    if len(sys.argv) > 1:
	init_cli()
    else:
	uname = auth.init_cgi()
    if uname:
	run()

Changes to cgi-bin/webcal.py.

1
2
3
4
5
6
7
8
9
10
11
12
...
445
446
447
448
449
450
451








































#
# today.py
#	Pull all events from a icalendar, display today's
#
import time, os, calendar
import MySQLdb as mysql
import pdb

# Indices into webcal_entry
WE_ID = 0	# Entry's ID
WE_WHEN = 4	# Date (and time at 5)
WE_DUR = 8	# Duration (minutes)
................................................................................
    for tup in c:
	for ev in load_cal(tup[0], filter):
	    ev.color = tup[1]
	    entries.add(ev)
    c.close()

    return entries












































|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
...
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
#
# today.py
#	Pull all events from a icalendar, display today's
#
import time, os, calendar, hashlib
import MySQLdb as mysql
import pdb

# Indices into webcal_entry
WE_ID = 0	# Entry's ID
WE_WHEN = 4	# Date (and time at 5)
WE_DUR = 8	# Duration (minutes)
................................................................................
    for tup in c:
	for ev in load_cal(tup[0], filter):
	    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