diff --git a/xkcdpass/xkcd_password.py b/xkcdpass/xkcd_password.py index b8337b2..e6e9749 100755 --- a/xkcdpass/xkcd_password.py +++ b/xkcdpass/xkcd_password.py @@ -72,15 +72,10 @@ def validate_options(parser, options): """ if options.max_length < options.min_length: - sys.stderr.write("Warning: maximum word length less than minimum. " - "Setting maximum equal to minimum.\n") - # sys.exit(1) + raise SystemExit("Error: Maximum word length can't be less than minimum word length.\n") - wordfile = locate_wordfile(options.wordfile) - if not wordfile: - sys.stderr.write("Could not find a word file, or word file does " - "not exist.\n") - sys.exit(1) + if not locate_wordfile(options.wordfile): + raise SystemExit("Wordfile not found. Is the path correct?\n") def locate_wordfile(wordfile=None): @@ -119,10 +114,6 @@ def generate_wordlist(wordfile=None, valid_chars is a regular expression match condition (default - all chars) """ - # deal with inconsistent min and max, erring toward security - if min_length > max_length: - max_length = min_length - words = set() regexp = re.compile("^{0}{{{1},{2}}}$".format(valid_chars, @@ -141,7 +132,7 @@ def generate_wordlist(wordfile=None, if len(words): return list(words) # deduplicate, just in case else: - raise SystemExit("Error: provided arguments result in zero-length wordlist, exiting.") + raise SystemExit("Error: Provided arguments result in emtpy wordlist. (Probably because there aren't any words that match your --min and --max options) Exiting.") def wordlist_to_worddict(wordlist): @@ -201,8 +192,7 @@ def find_acrostic(acrostic, worddict): try: words.append(rng().choice(worddict[letter])) except KeyError: - sys.stderr.write("No words found starting with " + letter + "\n") - sys.exit(1) + raise SystemExit("No words found starting with " + letter + "\n") return words @@ -227,7 +217,6 @@ def try_input(prompt, validate): print("") sys.exit(0) - # validate input return validate(answer) @@ -346,14 +335,15 @@ def generate_xkcdpassword(wordlist, worddict = wordlist_to_worddict(wordlist) def gen_passwd(): - if not acrostic: - words = choose_words(wordlist, numwords) - else: + if acrostic: words = find_acrostic(acrostic, worddict) + else: + words = choose_words(wordlist, numwords) - if not random_delimiters: + if random_delimiters: + return randomized_delimiter_join(set_case(words, method=case), valid_delimiters) + else: return delimiter.join(set_case(words, method=case)) - return randomized_delimiter_join(set_case(words, method=case), valid_delimiters) # useful if driving the logic from other code if not interactive: @@ -408,8 +398,7 @@ def n_words_validator(answer): raise ValueError return number except ValueError: - sys.stderr.write("Please enter a positive integer\n") - sys.exit(1) + raise SystemExit("Please enter a positive integer\n") if not options.acrostic: n_words_prompt = ("Enter number of words (default {0}):\n".format(options.numwords)) @@ -419,26 +408,19 @@ def n_words_validator(answer): def emit_passwords(wordlist, options): - """ Generate the specified number of passwords and output them. """ - count = options.count - if options.valid_delimiters: - valid_delimiters = list(options.valid_delimiters) + [""] - else: - valid_delimiters = DEFAULT_DELIMITERS - while count > 0: - print( - generate_xkcdpassword( + """ Generate the specified number of passwords and output them to stdout. """ + + for _ in range(options.count): + print(generate_xkcdpassword( wordlist, interactive=options.interactive, numwords=options.numwords, acrostic=options.acrostic, delimiter=options.delimiter, random_delimiters=options.random_delimiters, - valid_delimiters=valid_delimiters, - case=options.case, - ), - end=options.separator) - count -= 1 + valid_delimiters=list(options.valid_delimiters) if options.valid_delimiters else DEFAULT_DELIMITERS, + case=options.case), + end=options.separator) class XkcdPassArgumentParser(argparse.ArgumentParser): @@ -510,12 +492,13 @@ def _add_arguments(self): self.add_argument( "-D", "--valid-delimiters", dest="valid_delimiters", default="", metavar="VALID_DELIMITERS", - help=("A string with all valid delimiter characters." - " For example, '^&*' would use ^, &, or *")) + help=("When --random-delimiters is specified, use ANY of these characters to separate words." + " For example, --random-delimiters='^&*' would use ^, &, or * as separators." + " This option has no effect if --random-delimiters is not supplied.")) self.add_argument( "-s", "--separator", dest="separator", default="\n", metavar="SEP", - help="Separate generated passphrases with SEP.") + help="Separate generated passphrases with SEP. (default: newline)") self.add_argument( "-C", "--case", dest="case", type=str, metavar="CASE", @@ -571,5 +554,5 @@ def main(argv=None): if __name__ == '__main__': - exit_status = main(sys.argv) + raise SystemExit(main(sys.argv)) sys.exit(exit_status)