contrib/htdigest.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2006-2023 Edgewall Software
# Copyright (C) 2006 Matthew Good <matt@matt-good.net>
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at https://trac.edgewall.org/wiki/TracLicense.
#
# This software consists of voluntary contributions made by many
# individuals. For the exact contribution history, see the revision
# history and logs, available at https://trac.edgewall.org/log/.
#
# Author: Matthew Good <matt@matt-good.net>
import argparse
import errno
import fileinput
import getpass
import hashlib
import sys
from trac.util.text import printerr
def ask_pass():
pass1 = getpass.getpass('New password: ')
pass2 = getpass.getpass('Re-type new password: ')
if pass1 != pass2:
printerr("htdigest: password verification error")
sys.exit(1)
return pass1
def get_digest(userprefix, password=None):
if password is None:
password = ask_pass()
return make_digest(userprefix, password)
def make_digest(userprefix, password):
value = (userprefix + password).encode('utf-8')
return userprefix + hashlib.md5(value).hexdigest()
def main():
"""
%(prog)s [-c] passwordfile realm username
%(prog)s -b[c] passwordfile realm username password\
"""
parser = argparse.ArgumentParser(usage=main.__doc__)
parser.add_argument('-b', action='store_true', dest='batch',
help="batch mode; password is passed on the command "
"line IN THE CLEAR")
parser.add_argument('-c', action='store_true', dest='create',
help="create a new htdigest file, overwriting any "
"existing file")
parser.add_argument('passwordfile', help=argparse.SUPPRESS)
parser.add_argument('realm', help=argparse.SUPPRESS)
parser.add_argument('username', help=argparse.SUPPRESS)
parser.add_argument('password', nargs='?', help=argparse.SUPPRESS)
args = parser.parse_args()
if args.batch and args.password is None:
parser.error("too few arguments")
elif not args.batch and args.password is not None:
parser.error("too many arguments")
prefix = '%s:%s:' % (args.username, args.realm)
if args.create:
try:
with open(args.passwordfile, 'w', encoding='utf-8') as f:
print(get_digest(prefix, args.password), file=f)
except EnvironmentError as e:
if e.errno == errno.EACCES:
printerr("Unable to update file %s" % args.passwordfile)
sys.exit(1)
else:
raise
else:
matched = False
try:
for line in fileinput.input(args.passwordfile, inplace=True):
if line.startswith(prefix):
if not matched:
print(get_digest(prefix, args.password))
matched = True
else:
print(line.rstrip())
if not matched:
with open(args.passwordfile, 'a', encoding='utf-8') as f:
print(get_digest(prefix, args.password), file=f)
except EnvironmentError as e:
if e.errno == errno.ENOENT:
printerr("Could not open password file %s for reading. "
"Use -c option to create a new one."
% args.passwordfile)
sys.exit(1)
elif e.errno == errno.EACCES:
printerr("Unable to update file %s" % args.passwordfile)
sys.exit(1)
else:
raise
if __name__ == '__main__':
main()