Software Freedom Law Center

root/trunk/trac/contrib/htpasswd.py

Revision 57, 3.9 kB (checked in by bkuhn, 10 months ago)

r60@hughes: bkuhn | 2008-03-19 17:59:34 -0400

  • Brought in sync with r6719 of Trac upstream, which was accomplished via:

svk smerge /loblaw/local/branches/trac.upstream-r6719 .

  • Property svn:executable set to *
Line 
1 #!/usr/bin/python
2 """Replacement for htpasswd"""
3 # Original author: Eli Carter
4
5 import os
6 import sys
7 import random
8 from optparse import OptionParser
9
10 # We need a crypt module, but Windows doesn't have one by default.  Try to find
11 # one, and tell the user if we can't.
12 try:
13     import crypt
14 except ImportError:
15     try:
16         import fcrypt as crypt
17     except ImportError:
18         sys.stderr.write("Cannot find a crypt module.  "
19                          "Possibly http://carey.geek.nz/code/python-fcrypt/\n")
20         sys.exit(1)
21
22
23 def salt():
24     """Returns a string of 2 randome letters"""
25     letters = 'abcdefghijklmnopqrstuvwxyz' \
26               'ABCDEFGHIJKLMNOPQRSTUVWXYZ' \
27               '0123456789/.'
28     return random.choice(letters) + random.choice(letters)
29
30
31 class HtpasswdFile:
32     """A class for manipulating htpasswd files."""
33
34     def __init__(self, filename, create=False):
35         self.entries = []
36         self.filename = filename
37         if not create:
38             if os.path.exists(self.filename):
39                 self.load()
40             else:
41                 raise Exception("%s does not exist" % self.filename)
42
43     def load(self):
44         """Read the htpasswd file into memory."""
45         lines = open(self.filename, 'r').readlines()
46         self.entries = []
47         for line in lines:
48             username, pwhash = line.split(':')
49             entry = [username, pwhash.rstrip()]
50             self.entries.append(entry)
51
52     def save(self):
53         """Write the htpasswd file to disk"""
54         open(self.filename, 'w').writelines(["%s:%s\n" % (entry[0], entry[1])
55                                              for entry in self.entries])
56
57     def update(self, username, password):
58         """Replace the entry for the given user, or add it if new."""
59         pwhash = crypt.crypt(password, salt())
60         matching_entries = [entry for entry in self.entries
61                             if entry[0] == username]
62         if matching_entries:
63             matching_entries[0][1] = pwhash
64         else:
65             self.entries.append([username, pwhash])
66
67     def delete(self, username):
68         """Remove the entry for the given user."""
69         self.entries = [entry for entry in self.entries
70                         if entry[0] != username]
71
72
73 def main():
74     """%prog [-c] -b filename username password
75     Create or update an htpasswd file"""
76     # For now, we only care about the use cases that affect tests/functional.py
77     parser = OptionParser(usage=main.__doc__)
78     parser.add_option('-b', action='store_true', dest='batch', default=False,
79         help='Batch mode; password is passed on the command line IN THE CLEAR.'
80         )
81     parser.add_option('-c', action='store_true', dest='create', default=False,
82         help='Create a new htpasswd file, overwriting any existing file.')
83     parser.add_option('-D', action='store_true', dest='delete_user',
84         default=False, help='Remove the given user from the password file.')
85
86     options, args = parser.parse_args()
87
88     def syntax_error(msg):
89         """Utility function for displaying fatal error messages with usage
90         help.
91         """
92         sys.stderr.write("Syntax error: " + msg)
93         sys.stderr.write(parser.get_usage())
94         sys.exit(1)
95
96     if not options.batch:
97         syntax_error("Only batch mode is supported\n")
98
99     # Non-option arguments
100     if len(args) < 2:
101         syntax_error("Insufficient number of arguments.\n")
102     filename, username = args[:2]
103     if options.delete_user:
104         if len(args) != 2:
105             syntax_error("Incorrect number of arguments.\n")
106         password = None
107     else:
108         if len(args) != 3:
109             syntax_error("Incorrect number of arguments.\n")
110         password = args[2]
111
112     passwdfile = HtpasswdFile(filename, create=options.create)
113
114     if options.delete_user:
115         passwdfile.delete(username)
116     else:
117         passwdfile.update(username, password)
118
119     passwdfile.save()
120
121
122 if __name__ == '__main__':
123     main()
Note: See TracBrowser for help on using the browser.

SFLC Main Page

[frdm] Support SFLC