14 | | class SessionManager(models.Manager): |
15 | | def encode(self, session_dict): |
16 | | "Returns the given session dictionary pickled and encoded as a string." |
17 | | pickled = pickle.dumps(session_dict) |
18 | | pickled_md5 = md5.new(pickled + settings.SECRET_KEY).hexdigest() |
19 | | return base64.encodestring(pickled + pickled_md5) |
20 | | |
21 | | def get_new_session_key(self): |
22 | | "Returns session key that isn't being used." |
23 | | # The random module is seeded when this Apache child is created. |
24 | | # Use SECRET_KEY as added salt. |
25 | | try: |
26 | | pid = os.getpid() |
27 | | except AttributeError: |
28 | | # No getpid() in Jython, for example |
29 | | pid = 1 |
30 | | while 1: |
31 | | session_key = md5.new("%s%s%s%s" % (random.randint(0, sys.maxint - 1), pid, time.time(), settings.SECRET_KEY)).hexdigest() |
32 | | try: |
33 | | self.get(session_key=session_key) |
34 | | except self.model.DoesNotExist: |
35 | | break |
36 | | return session_key |
37 | | |
38 | | def get_new_session_object(self): |
39 | | """ |
40 | | Returns a new session object. |
41 | | """ |
42 | | # FIXME: There is a *small* chance of collision here, meaning we will |
43 | | # return an existing object. That can be fixed when we add a way to |
44 | | # validate (and guarantee) that non-auto primary keys are unique. For |
45 | | # now, we save immediately in order to reduce the "window of |
46 | | # misfortune" as much as possible. |
47 | | created = False |
48 | | while not created: |
49 | | obj, created = self.get_or_create(session_key=self.get_new_session_key(), |
50 | | expire_date = datetime.datetime.now()) |
51 | | # Collision in key generation, so re-seed the generator |
52 | | random.seed() |
53 | | return obj |
54 | | |
55 | | def save(self, session_key, session_dict, expire_date): |
56 | | s = self.model(session_key, self.encode(session_dict), expire_date) |
57 | | if session_dict: |
58 | | s.save() |
59 | | else: |
60 | | s.delete() # Clear sessions with no data. |
61 | | return s |
62 | | |
65 | | Django provides full support for anonymous sessions. The session |
66 | | framework lets you store and retrieve arbitrary data on a |
67 | | per-site-visitor basis. It stores data on the server side and |
68 | | abstracts the sending and receiving of cookies. Cookies contain a |
69 | | session ID -- not the data itself. |
70 | | |
71 | | The Django sessions framework is entirely cookie-based. It does |
72 | | not fall back to putting session IDs in URLs. This is an intentional |
73 | | design decision. Not only does that behavior make URLs ugly, it makes |
74 | | your site vulnerable to session-ID theft via the "Referer" header. |
75 | | |
| 6 | Saves sessions in database. |
| 7 | |
| 8 | Not for direct usage, please use SessionStore class |
| 9 | in django.contrib.sessions.backends.db module to access sessions. |
| 10 | |
89 | | |
90 | | def get_decoded(self): |
91 | | encoded_data = base64.decodestring(self.session_data) |
92 | | pickled, tamper_check = encoded_data[:-32], encoded_data[-32:] |
93 | | if md5.new(pickled + settings.SECRET_KEY).hexdigest() != tamper_check: |
94 | | from django.core.exceptions import SuspiciousOperation |
95 | | raise SuspiciousOperation, "User tampered with session cookie." |
96 | | try: |
97 | | return pickle.loads(pickled) |
98 | | # Unpickling can cause a variety of exceptions. If something happens, |
99 | | # just return an empty dictionary (an empty session). |
100 | | except: |
101 | | return {} |