Code

Added module docstrings to all modules.
[roundup.git] / roundup / password.py
1 #
2 # Copyright (c) 2001 Bizar Software Pty Ltd (http://www.bizarsoftware.com.au/)
3 # This module is free software, and you may redistribute it and/or modify
4 # under the same terms as Python, so long as this copyright message and
5 # disclaimer are retained in their original form.
6 #
7 # IN NO EVENT SHALL BIZAR SOFTWARE PTY LTD BE LIABLE TO ANY PARTY FOR
8 # DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING
9 # OUT OF THE USE OF THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE
10 # POSSIBILITY OF SUCH DAMAGE.
11 #
12 # BIZAR SOFTWARE PTY LTD SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
13 # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
14 # FOR A PARTICULAR PURPOSE.  THE CODE PROVIDED HEREUNDER IS ON AN "AS IS"
15 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
16 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
17
18 # $Id: password.py,v 1.4 2001-11-22 15:46:42 jhermann Exp $
20 __doc__ = """
21 Password handling (encoding, decoding).
22 """
24 import sha, re
26 def encodePassword(plaintext, scheme):
27     '''Encrypt the plaintext password.
28     '''
29     if scheme == 'SHA':
30         s = sha.sha(plaintext).hexdigest()
31     elif scheme == 'plaintext':
32         pass
33     else:
34         raise ValueError, 'Unknown encryption scheme "%s"'%scheme
35     return s
37 class Password:
38     '''The class encapsulates a Password property type value in the database. 
40     The encoding of the password is one if None, 'SHA' or 'plaintext'. The
41     encodePassword function is used to actually encode the password from
42     plaintext. The None encoding is used in legacy databases where no
43     encoding scheme is identified.
45     The scheme is stored with the encoded data in the database:
46         {scheme}data
48     Example usage:
49     >>> p = Password('sekrit')
50     >>> p == 'sekrit'
51     1
52     >>> p != 'not sekrit'
53     1
54     >>> 'sekrit' == p
55     1
56     >>> 'not sekrit' != p
57     1
58     '''
60     default_scheme = 'SHA'        # new encryptions use this scheme
61     pwre = re.compile(r'{(\w+)}(.+)')
63     def __init__(self, plaintext=None):
64         '''Call setPassword if plaintext is not None.'''
65         if plaintext is not None:
66             self.password = encodePassword(plaintext, self.default_scheme)
67             self.scheme = self.default_scheme
68         else:
69             self.password = None
70             self.scheme = self.default_scheme
72     def unpack(self, encrypted):
73         '''Set the password info from the scheme:<encryted info> string
74            (the inverse of __str__)
75         '''
76         m = self.pwre.match(encrypted)
77         if m:
78             self.scheme = m.group(1)
79             self.password = m.group(2)
80         else:
81             # currently plaintext - encrypt
82             self.password = encodePassword(encrypted, self.default_scheme)
83             self.scheme = self.default_scheme
85     def setPassword(self, plaintext):
86         '''Sets encrypts plaintext.'''
87         self.password = encodePassword(plaintext, self.scheme)
89     def __cmp__(self, other):
90         '''Compare this password against another password.'''
91         # check to see if we're comparing instances
92         if isinstance(other, Password):
93             if self.scheme != other.scheme:
94                 return
95             return cmp(self.password, other.password)
97         # assume password is plaintext
98         if self.password is None:
99             raise ValueError, 'Password not set'
100         return cmp(self.password, encodePassword(other, self.scheme))
102     def __str__(self):
103         '''Stringify the encrypted password for database storage.'''
104         if self.password is None:
105             raise ValueError, 'Password not set'
106         return '{%s}%s'%(self.scheme, self.password)
108 def test():
109     p = Password('sekrit')
110     assert p == 'sekrit'
111     assert p != 'not sekrit'
112     assert 'sekrit' == p
113     assert 'not sekrit' != p
115 if __name__ == '__main__':
116     test()
119 # $Log: not supported by cvs2svn $
120 # Revision 1.3  2001/10/20 11:58:48  richard
121 # Catch errors in login - no username or password supplied.
122 # Fixed editing of password (Password property type) thanks Roch'e Compaan.
124 # Revision 1.2  2001/10/09 23:58:10  richard
125 # Moved the data stringification up into the hyperdb.Class class' get, set
126 # and create methods. This means that the data is also stringified for the
127 # journal call, and removes duplication of code from the backends. The
128 # backend code now only sees strings.
130 # Revision 1.1  2001/10/09 07:25:59  richard
131 # Added the Password property type. See "pydoc roundup.password" for
132 # implementation details. Have updated some of the documentation too.
136 # vim: set filetype=python ts=4 sw=4 et si