Source

trac-ticketlinks / contrib / htpasswd.py

ecarter 0fd9f46 

ecarter f80d36c 
ecarter 0fd9f46 

ecarter 8db41ac 
ecarter 0fd9f46 
ecarter 8db41ac 



ecarter 0fd9f46 


ecarter 8db41ac 


ecarter f80d36c 

ecarter 8db41ac 
ecarter 0fd9f46 



ecarter f80d36c 


ecarter 0fd9f46 



ecarter f80d36c 

ecarter 0fd9f46 









ecarter f80d36c 
ecarter 0fd9f46 


ecarter f80d36c 

ecarter 0fd9f46 


ecarter f80d36c 


ecarter 0fd9f46 

ecarter f80d36c 



ecarter 0fd9f46 
ecarter f80d36c 
ecarter 0fd9f46 
ecarter f80d36c 
ecarter 0fd9f46 

ecarter f80d36c 



ecarter 0fd9f46 






ecarter f80d36c 

ecarter 0fd9f46 

ecarter f80d36c 

ecarter 0fd9f46 


ecarter 675ee53 




ecarter f80d36c 

ecarter 0fd9f46 
ecarter 675ee53 


ecarter 0fd9f46 
ecarter f80d36c 
ecarter 675ee53 
ecarter 0fd9f46 

ecarter f80d36c 
ecarter 675ee53 
ecarter 0fd9f46 

ecarter f80d36c 
ecarter 675ee53 
ecarter 0fd9f46 












#!/usr/bin/python
"""Replacement for htpasswd"""
# Original author: Eli Carter

import os
import sys
import random
from optparse import OptionParser

# We need a crypt module, but Windows doesn't have one by default.  Try to find
# one, and tell the user if we can't.
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"""
    # For now, we only care about the use cases that affect tests/functional.py
    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")

    # Non-option arguments
    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()
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.