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 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
|
"""Replacement for htpasswd"""
import os import sys import random from optparse import OptionParser
try: import crypt except ImportError: try: import fcrypt as crypt except ImportError: sys.stderr.write("Cannot find a crypt module. " "Possibly http://carey.geek.nz/code/python-fcrypt/\n") sys.exit(1)
def salt(): """Returns a string of 2 randome letters""" letters = 'abcdefghijklmnopqrstuvwxyz' \ 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' \ '0123456789/.' return random.choice(letters) + random.choice(letters)
class HtpasswdFile: """A class for manipulating htpasswd files."""
def __init__(self, filename, create=False): self.entries = [] self.filename = filename if not create: if os.path.exists(self.filename): self.load() else: raise Exception("%s does not exist" % self.filename)
def load(self): """Read the htpasswd file into memory.""" lines = open(self.filename, 'r').readlines() self.entries = [] for line in lines: username, pwhash = line.split(':') entry = [username, pwhash.rstrip()] self.entries.append(entry)
def save(self): """Write the htpasswd file to disk""" open(self.filename, 'w').writelines(["%s:%s\n" % (entry[0], entry[1]) for entry in self.entries])
def update(self, username, password): """Replace the entry for the given user, or add it if new.""" pwhash = crypt.crypt(password, salt()) matching_entries = [entry for entry in self.entries if entry[0] == username] if matching_entries: matching_entries[0][1] = pwhash else: self.entries.append([username, pwhash])
def delete(self, username): """Remove the entry for the given user.""" self.entries = [entry for entry in self.entries if entry[0] != username]
def main(): """%prog [-c] -b filename username password Create or update an htpasswd file""" parser = OptionParser(usage=main.__doc__) parser.add_option('-b', action='store_true', dest='batch', default=False, help='Batch mode; password is passed on the command line IN THE CLEAR.' ) parser.add_option('-c', action='store_true', dest='create', default=False, help='Create a new htpasswd file, overwriting any existing file.') parser.add_option('-D', action='store_true', dest='delete_user', default=False, help='Remove the given user from the password file.')
options, args = parser.parse_args()
def syntax_error(msg): """Utility function for displaying fatal error messages with usage help. """ sys.stderr.write("Syntax error: " + msg) sys.stderr.write(parser.get_usage()) sys.exit(1)
if not options.batch: syntax_error("Only batch mode is supported\n")
if len(args) < 2: syntax_error("Insufficient number of arguments.\n") filename, username = args[:2] if options.delete_user: if len(args) != 2: syntax_error("Incorrect number of arguments.\n") password = None else: if len(args) != 3: syntax_error("Incorrect number of arguments.\n") password = args[2]
passwdfile = HtpasswdFile(filename, create=options.create)
if options.delete_user: passwdfile.delete(username) else: passwdfile.update(username, password)
passwdfile.save()
if __name__ == '__main__': main()
|