diff options
Diffstat (limited to 'makepass.py')
l---------[-rwxr-xr-x] | makepass.py | 319 |
1 files changed, 1 insertions, 318 deletions
diff --git a/makepass.py b/makepass.py index 233ae7d..b6e1064 100755..120000 --- a/makepass.py +++ b/makepass.py @@ -1,318 +1 @@ -#!/usr/bin/env python3 -# -# Author : Dennis Eriksen <d@ennis.no> -# File : makepass.py -# Created : 2023-09-14 -# License : BSD-3-Clause -# -# Copyright (c) 2018-2023 Dennis Eriksen <d@ennis.no> - -import argparse -import os -import random -import sys - -# Global variables - -MAX = 255 -RANGE_MAX = 42 -RANGE_MIN = 8 -PASS_WORDS = 8 - -LOWER = "abcdefghijklmnopqrstuvwxyz" -UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" -DIGIT = "0123456789" -OTHER = "!$%&#/()=?+-_,.;:<>[]{}|@*" - -ALPHA = LOWER + UPPER -ALNUM = ALPHA + DIGIT -EVERY = ALNUM + OTHER - -NORMAL = ALNUM + "_-" -SPECIAL = EVERY - -DEFAULT_LENGTH = 0 -DEFAULT_NUMBER = 10 -DEFAULT_WORDLIST = "/usr/share/dict/words" - - -class CommonPrintData: - def __init__(self, length, printbool, printlen, col_width, col_num): - self.length = length - self.printbool = printbool - self.printlen = printlen - self.col_num = col_num - self.col_width = col_width - - -# -# Main function -# -def main(): - normal = os.getenv("MAKEPASS_NORMAL") or NORMAL - special = os.getenv("MAKEPASS_SPECIAL") or SPECIAL - wordlist_file = os.getenv("MAKEPASS_WORDLIST") or DEFAULT_WORDLIST - - # Initialize parser - parser = argparse.ArgumentParser( - description="Process some strings.", add_help=False - ) - - # Add arguments - parser.add_argument("-h", "--help", action="store_true") - parser.add_argument("-l", "--length", type=int, help="Length of strings") - parser.add_argument("-n", "--number", type=int, help="Number of strings") - parser.add_argument("-p", "--printlen", action="store_true") - parser.add_argument("arg_length", type=int, nargs="?") - - # Parse arguments - args = parser.parse_args() - - if args.help: - usage() - - # Some error-checking - # length - try: - # env or default - length = int(os.getenv("MAKEPASS_LENGTH") or DEFAULT_LENGTH) - - # -l flag - if args.length is not None: - if args.length < 0 or MAX < args.length: - raise ValueError("-l") - length = args.length - - # solo argument - if args.arg_length is not None: - length = args.arg_length - - # check result - if length < 0 or MAX < length: - raise ValueError("length") - except ValueError as e: - print(f"{e} must be a number between 0 and {MAX}") - sys.exit(1) - - # number - try: - # env or default - number = int(os.getenv("MAKEPASS_NUMBER") or DEFAULT_NUMBER) - - # -n flag - if args.number is not None: - if args.number < 1 or MAX < args.number: - raise ValueError("-n") - number = args.number - - # check result - if number < 1 or MAX < number: - raise ValueError("number") - except ValueError as e: - print(f"{e} must be a number between 1 and {MAX}") - sys.exit(1) - - # Set some other stuff - - printbool = args.printlen - if printbool: - printlen = 3 if length < 100 else 4 - else: - printlen = 0 - - # get terminal width - try: - xwidth = os.get_terminal_size().columns - except Exception as _: - xwidth = 1 - - # get width of columns to print - if length == 0: - col_width = RANGE_MAX + 2 - else: - col_width = length + 2 - - # number of columns to print - col_num = int(xwidth / (col_width + printlen)) - if col_num == 0: - col_num = 1 - - # config - config = CommonPrintData( - length=length, - printbool=printbool, - printlen=printlen, - col_width=col_width, - col_num=col_num, - ) - - # - # print passwords - # - - # Generate and print normal and special passwords - print_columns("Normal passwords", number, normal, config) - - print() - - print_columns( - "Passwords with special characters", int(number / 3 * 2 + 1), special, config - ) - - # Generate and print passphrases if wordlist exists - if os.path.isfile(wordlist_file): - print() - - print("Generating passphrases: ") - passphrase(int(number / 2), wordlist_file) - - -# -# Print passwords in neat columns -# -def print_columns(title: str, num: int, chars: str, c: CommonPrintData): - # Generate random strings - strings = [randstring(c.length, chars) for _ in range(num)] - - print(f"{title}:") - - for i in range(num): - # Print the length of the string if printlen is set - if c.printbool: - print(f"{len(strings[i]):0{c.printlen-1}}", end=" ") - - # Print the string, left justified based on column width - print(f"{strings[i]:<{c.col_width}}", end="") - - # If we have printed enough strings for a single line or the - # rest of strings are fewer than column number, we break lines. - i += 1 - if i % c.col_num == 0 or (i == num and i % c.col_num > 0): - print() - - -# -# Generate random strings that can work as passwords -# -def randstring(length, chars): - """ - Generate a random password of the specified length. Use special - characters if special_chars option is True. - """ - if length == 0: - length = random.randint(RANGE_MIN, RANGE_MAX) - - password = [] - password.append(random.choice(ALPHA)) - for i in range(length - 2): - password.append(random.choice(chars)) - password.append(random.choice(ALNUM)) - - # Randomly reorder the characters - return "".join(password) - - -# -# Passphrases! -# -def passphrase(number, file_name): - """ - Generate a number of random passphrases from the wordlist. - """ - try: - with open(file_name, "r") as f: - lines = f.read().splitlines() - except IOError: - print(f"Cannot open file: {file_name}") - sys.exit(1) - - for i in range(number): - word_list = random.choices(lines, k=5) - passphrase = "-".join(word_list) - print(passphrase) - - -def usage(): - text = """NAME - makepass - create several random passwords - -SYNOPSIS - makepass [OPTIONS] [NUM] - - If a NUM is provided, passwords will be NUM characters long. - - By default `makepass` will output passwords from the three following classes: - - - Normal passwords - random strings with letters (both lower and upper - case), numbers, and dashes and underscores. - - - Passwords with special characters - random strings generated from lower - and upper case letters, numbers, and the following characters: - !#$%&/()=?+-_,.;:<>[]{}|@* - - - Passphrases - if we find a dictionary, a series of eight random words - from the dictionary, separated by dashes. The number of words can not be - changed, but you do not have to use all of them. Use as mane as you want. - - The first character will always be alphabetic, and the last will always be - alphanumeric. - -DESCRIPTION - makepass has the following options: - - -h - output this help-text - -l - length of passwords. See MAKEPASS_LENGTH below - -n - number of passwords. See MAKEPASS_NUMBER below - -p - print length of number - -ENVIRONMENT - makepass examines the following environmental variables. - - MAKEPASS_LENGTH - Specifies the length of passwords. Valid values are 0-255. If 0, a - random value between 8 and 42 will be used for each password. -l - overrides this environmental variable, and the argument NUM overrides - that again. So `MAKEPASS_LENGTH=10 makepass -l 12 14` will give - passwords that are 14 characters long, even though both -l and - MAKEPASS_LENGTH also specifies a length. - - MAKEPASS_NUMBER - The number of passwords to generate. This formula is used to determine - how many passwords from each group should be generated: - - (n) normal passwords - - (n / 3 * 2 + 1) special passwords - - (n / 2) passphrases - Where n is 10 by default. Valid values for n are 1-255. Floating-poing - math is not used, so results may vary. - - MAKEPASS_PRINTLEN - If 1, print length of all passwords. If 0, don\'t. - - MAKEPASS_NORMAL - String of characters from which to generate "normal" passwords. - Defaults to: - abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_ - - MAKEPASS_SPECIAL - String of characters from which to generate passwords with special - characters. Defaults to the same characters as in MAKEPASS_NORMAL, plus - these: - !#$%&/()=?+-_,.;:<>[]{}|@* - - MAKEPASS_WORDLIST - Specifies the dictionary we find words for passphrases in. If this is - unset or empty, we try "/usr/share/dict/words". If that file does not - exist, no passphrases will be provided. - -AUTHOR - Dennis Eriksen <https://dnns.no>""" - print(text) - sys.exit(0) - - -if __name__ == "__main__": - main() +src/python/makepass.py
\ No newline at end of file |