From 112d8b2f7e6d972bb40b52e34cdc1c8c3057dd5b Mon Sep 17 00:00:00 2001 From: Rick Cogley Date: Mon, 1 May 2023 20:10:19 +0900 Subject: [PATCH] Nupass refactor 20230501 (#473) * Refactor nupass.nu Major refactor for more flexibility To allow number of words to be specified, one solution is to add random words, symbols, & numbers to lists, then operate on the lists. You can combine lists with the ++ operator, then use shuffle on them, as well as various other methods. * Update ReadMe.md Updated to match latest version, adding some new sample commands Last version `nupass 4` meant "generate password with 3 words of length <=4". This version `nupass 4` means "generate password with 4 words". Length can be specified with `-l`, so: `nupass 4 -l 8` means "generate password with 4 words of length <=8". * Update ReadMe.md Screenshot showing new version's output --- sourced/misc/password_generator/ReadMe.md | 22 +++++---- sourced/misc/password_generator/nupass.nu | 57 ++++++++++++++++------- 2 files changed, 53 insertions(+), 26 deletions(-) diff --git a/sourced/misc/password_generator/ReadMe.md b/sourced/misc/password_generator/ReadMe.md index b98eab04..c056590e 100644 --- a/sourced/misc/password_generator/ReadMe.md +++ b/sourced/misc/password_generator/ReadMe.md @@ -1,6 +1,6 @@ # Nushell Password Generator "nupass" -This nushell command randomly retrieves three words from a dictionary file (English with Japanese words added by @rickcogley) less than or equal to a given parameter's length, formats the words randomly with capitalization, then separates the words with some random symbols and numbers to return a password. +This nushell command randomly retrieves a specified number of words from a dictionary file (English with Japanese words added by @rickcogley) less than or equal to a given parameter's length, formats the words randomly with capitalization, then separates the words with some random symbols and numbers to return a password. To use: @@ -20,10 +20,11 @@ http get https://raw.githubusercontent.com/RickCogley/jpassgen/master/genpass-di let dictfile = $"/path/to/my/genpass-dict-jp" ``` -5. Confirm the symbols are what you want to use, and edit to taste: +5. Confirm and edit the default symbols list and diceware delimiter: ``` -let symbolchars = "!@#$%^&*()_-+[]" +--symbols (-s): string = "!@#$%^&()_-+[]{}" # Symbols to use in password +--delimiter (-m): string = "-" # Delimiter for diceware ``` 6. Load the script with `use` in your `config.nu`, something like: @@ -40,12 +41,16 @@ Reload nu, then run it to test: nupass -h nupass 5 nupass 6 --debug -nupass 3 -d +nupass 8 -v diceware +nupass 8 -v diceware -m _ +nupass 4 -v mixnmatch +nupass 6 -v alphanum +nupass 5 -l 8 ``` ### Testing -If you're making changes to the script while testing, just re-source the script by doing: +If you're making changes to the script while testing, you can just re-source the script by doing: `use nupass.nu` @@ -53,7 +58,7 @@ If you're making changes to the script while testing, just re-source the script ### Caveats -I've been scripting for quite a long time, but not in nu. Input appreciated to make this more nu-esque! +I've been scripting for quite a long time, but not in nu. Input appreciated to make this more nu-esque! The script is in a decent place as of the 20230501 version. Obviously you can just use the `random chars` or `random integers` commands but I like to have words I can read in my passwords, and I think those generated by this script have sufficient entropy. @@ -61,6 +66,7 @@ This command doesn't let you specify a precise length. ### Acknowledgements -Thanks everyone on Discord for putting up with and answering my nubie questions @amtoine, @fdncred, @jelle, and for the feedback after try number 1. +Thanks everyone on Discord for putting up with and answering my nubie questions @amtoine, @fdncred, @jelle, @sygmei, @kubouch and for the feedback after try number 1. + +image -image diff --git a/sourced/misc/password_generator/nupass.nu b/sourced/misc/password_generator/nupass.nu index 331f50b1..49e58d04 100755 --- a/sourced/misc/password_generator/nupass.nu +++ b/sourced/misc/password_generator/nupass.nu @@ -1,15 +1,21 @@ # Script to generate a password from a dictionary file # Author: @rickcogley -# Thanks: @amtoine, @fdncred, @jelle +# Thanks: @amtoine, @fdncred, @jelle, @sygmei, @kubouch # Updates: 20230415 - initial version # 20230416 - added @amtoine's slick probabilistic "random decimal" char capitalization # 20230417 - added script duration output in debug block # 20230421 - added length of symbol chars to get-random-symbol function +# 20230422 - added variant flag to generate different styles of passwords +# 20230501 - refactor to allow number of words to be specified, use list manipulation and reduce to string #======= NUPASS PASSWORD GENERATOR ======= # Generate password of 3 dictionary file words, numbers and symbols export def main [ - word_length: int = 4 # Max length of 3 words in password + words: int = 3 # Number of words in password + --word_length (-l): int = 5 # Max length of words in password + --symbols (-s): string = "!@#$%^&()_-+[]{}" # Symbols to use in password + --variant (-v): string = "regular" # Password style to generate in regular, mixnmatch, alphanum, alpha, diceware + --delimiter (-m): string = "-" # Delimiter for diceware --debug (-d) # Include debug info ] { ##### Main function ##### @@ -23,18 +29,15 @@ export def main [ let num_lines = (open ($dictfile) | lines | wrap word | upsert len {|it| $it.word | split chars | length} | where len <= ($word_length) | length) # Get random words from dictionary file - let randword1 = ($dictfile | get-random-word $word_length $num_lines | random-format-word) - let randword2 = ($dictfile | get-random-word $word_length $num_lines | random-format-word) - let randword3 = ($dictfile | get-random-word $word_length $num_lines | random-format-word) + let random_words = (1..$words | each { |i| $dictfile | get-random-word $word_length $num_lines | random-format-word }) # Get some symbols to sprinkle like salt bae - # Update symbol chars as needed - let symbol_chars = "!@#$%^&()_-+[]{}" - let symbol_chars_len = ($symbol_chars | str length) - let symb1 = (get-random-symbol $symbol_chars $symbol_chars_len) - let symb2 = (get-random-symbol $symbol_chars $symbol_chars_len) - let symb3 = (get-random-symbol $symbol_chars $symbol_chars_len) - let symb4 = (get-random-symbol $symbol_chars $symbol_chars_len) + # Update default symbol chars in symbols flag + let symbols_len = ($symbols | str length) + let random_symbols = (1..$words | each { |i| $symbols | get-random-symbol $symbols $symbols_len }) + + # Get some random numbers + let random_numbers = (1..$words |each { |i| (random integer 0..99) }) # Print some vars if debug flag is set if $debug { @@ -42,16 +45,34 @@ export def main [ print $"(ansi bg_blue) 🔔 Number of lines in dict with words under ($word_length) chars: (ansi reset)" print $num_lines print $"(ansi bg_blue) 🔔 Words from randomly selected lines: (ansi reset)" - print $randword1 $randword2 $randword3 + print $random_words print $"(ansi bg_blue) 🔔 Randomly selected symbols: (ansi reset)" - print $symb1 $symb2 $symb3 $symb4 + print $random_symbols + print $"(ansi bg_blue) 🔔 Randomly selected numbers: (ansi reset)" + print $random_numbers let endtime = (date now) print $"(ansi bg_green) 🔔 Generated password in ($endtime - $starttime): (ansi reset)" } - # Return password - return $"($symb1)(random integer 1..99)($randword1)($symb2)($randword2)($symb3)(random integer 1..99)($randword3)($symb4)" - + # Return password in selected variant + if $variant == "regular" { + # Default variant, with regular distribution + # Generate new list w symbol, words, numbers, then reduce to string + return (0..($words - 1) | each { |it| ($random_symbols | get $it) + ($random_words | get $it) + ($random_numbers | get $it | into string) } | reduce { |it, acc| $acc + $it }) + + } else if $variant == "mixnmatch" { + # Combine lists, shuffle randomly, reduce to string + return (($random_words ++ $random_symbols ++ $random_numbers | shuffle) | reduce { |it, acc| ($acc | into string) + ($it | into string) }) + } else if $variant == "alphanum" { + # Combined random int and random word, reduce to string + return (0..($words - 1) | each { |it| (random integer 0..99 | into string) + ($random_words | get $it) } | reduce { |it, acc| $acc + $it }) + } else if $variant == "alpha" { + # Reduce random words only to string + return ($random_words | reduce { |it, acc| $acc + $it }) + } else if $variant == "diceware" { + # Reduce to string with hyphen between words + return ($random_words | reduce { |it, acc| $acc + $"($delimiter)($it)" }) + } } ##### Utility functions ##### @@ -71,7 +92,7 @@ def get-random-word [ # Function to format a word randomly def random-format-word [] { - each {|it| + par-each {|it| let rint = (random integer 1..4) if $rint == 1 { ($it | str capitalize)