annotate wiki/middleware.py @ 792:7429c98c8ece

Issue #71: use relative URLs for smileys on the web and absolute for RSS.
author Brian Neal <bgneal@gmail.com>
date Mon, 26 May 2014 14:59:55 -0500
parents efac466a05d4
children 47521d9e94bd
rev   line source
bgneal@626 1 """Middleware for wiki integration.
bgneal@626 2
bgneal@626 3 """
bgneal@626 4 import datetime
bgneal@626 5 import hashlib
bgneal@626 6 import logging
bgneal@626 7 import random
bgneal@626 8 import string
bgneal@626 9 import time
bgneal@626 10
bgneal@626 11 from django.conf import settings
bgneal@626 12 import redis
bgneal@626 13
bgneal@626 14 from core.services import get_redis_connection
bgneal@629 15 from wiki.constants import SESSION_SET_MEMBER
bgneal@626 16
bgneal@626 17
bgneal@626 18 logger = logging.getLogger(__name__)
bgneal@626 19
bgneal@626 20
bgneal@626 21 def cookie_value(user, now):
bgneal@626 22 """Creates the value for the external wiki cookie."""
bgneal@626 23
bgneal@626 24 # The key part of the cookie is just a string that would make things
bgneal@626 25 # difficult for a spoofer; something that can't be easily made up:
bgneal@626 26
bgneal@626 27 h = hashlib.sha256()
bgneal@626 28 h.update(user.username + user.email)
bgneal@626 29 h.update(now.isoformat())
bgneal@626 30 h.update(''.join(random.sample(string.printable, 64)))
bgneal@626 31 h.update(settings.SECRET_KEY)
bgneal@626 32 key = h.hexdigest()
bgneal@626 33
bgneal@626 34 parts = (user.username, user.email, key)
bgneal@626 35 return '#'.join(parts)
bgneal@626 36
bgneal@626 37
bgneal@626 38 def create_wiki_session(request, response):
bgneal@626 39 """Sets up the session for the external wiki application.
bgneal@626 40
bgneal@626 41 Creates the external cookie for the Wiki.
bgneal@626 42 Updates the Redis set so the Wiki can verify the cookie.
bgneal@626 43
bgneal@626 44 """
bgneal@626 45 now = datetime.datetime.utcnow()
bgneal@626 46 value = cookie_value(request.user, now)
bgneal@626 47 response.set_cookie(settings.WIKI_COOKIE_NAME,
bgneal@626 48 value=value,
bgneal@626 49 max_age=settings.WIKI_COOKIE_AGE,
bgneal@626 50 domain=settings.WIKI_COOKIE_DOMAIN)
bgneal@626 51
bgneal@626 52 # Update a sorted set in Redis with a hash of our cookie and a score
bgneal@626 53 # of the current time as a timestamp. This allows us to delete old
bgneal@626 54 # entries by score periodically. To verify the cookie, the external wiki
bgneal@626 55 # application computes a hash of the cookie value and checks to see if
bgneal@626 56 # it is in our Redis set.
bgneal@626 57
bgneal@626 58 h = hashlib.sha256()
bgneal@626 59 h.update(value)
bgneal@626 60 name = h.hexdigest()
bgneal@626 61 score = time.mktime(now.utctimetuple())
bgneal@626 62 conn = get_redis_connection()
bgneal@626 63
bgneal@626 64 try:
bgneal@626 65 conn.zadd(settings.WIKI_REDIS_SET, score, name)
bgneal@626 66 except redis.RedisError:
bgneal@626 67 logger.error("Error adding wiki cookie key")
bgneal@626 68
bgneal@626 69 # Store the set member name in the session so we can delete it when the
bgneal@626 70 # user logs out:
bgneal@627 71 request.session[SESSION_SET_MEMBER] = name
bgneal@626 72
bgneal@626 73
bgneal@627 74 def destroy_wiki_session(set_member, response):
bgneal@626 75 """Destroys the session for the external wiki application.
bgneal@626 76
bgneal@626 77 Delete the external cookie.
bgneal@627 78 Deletes the member from the Redis set as this entry is no longer valid.
bgneal@626 79
bgneal@626 80 """
bgneal@626 81 response.delete_cookie(settings.WIKI_COOKIE_NAME,
bgneal@626 82 domain=settings.WIKI_COOKIE_DOMAIN)
bgneal@626 83
bgneal@627 84 if set_member:
bgneal@627 85 conn = get_redis_connection()
bgneal@627 86 try:
bgneal@627 87 conn.zrem(settings.WIKI_REDIS_SET, set_member)
bgneal@627 88 except redis.RedisError:
bgneal@627 89 logger.error("Error deleting wiki cookie set member")
bgneal@626 90
bgneal@626 91
bgneal@626 92 class WikiMiddleware(object):
bgneal@626 93 """
bgneal@633 94 Check for flags on the request object to determine when to set or delete an
bgneal@626 95 external cookie for the wiki application. When creating a cookie, also
bgneal@626 96 set an entry in Redis that the wiki application can validate to prevent
bgneal@626 97 spoofing.
bgneal@626 98
bgneal@626 99 """
bgneal@626 100
bgneal@626 101 def process_response(self, request, response):
bgneal@626 102
bgneal@629 103 if hasattr(request, 'wiki_set_cookie'):
bgneal@626 104 create_wiki_session(request, response)
bgneal@627 105 elif hasattr(request, 'wiki_delete_cookie'):
bgneal@627 106 destroy_wiki_session(request.wiki_delete_cookie, response)
bgneal@626 107
bgneal@626 108 return response