From 52f063044f698ff6ef5c22009912651478b77884 Mon Sep 17 00:00:00 2001 From: Jake Wnuk Date: Sat, 5 Oct 2024 12:51:15 -0400 Subject: [PATCH] v0.3.6 (#41) * Change default passphrase transformations * Update defaults for passphrases * Stub markdown output * Add markdown table output - added the -md flag which allows output formatting as a markdown table with the command used - linted --- README.md | 4 ++- docs/USAGE.md | 2 +- main.go | 19 +++++++--- pkg/format/format.go | 77 ++++++++++++++++++++++++++++------------- pkg/utils/utils.go | 31 ++++------------- pkg/utils/utils_test.go | 2 +- 6 files changed, 80 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index 79f2014..249afd1 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ git clone https://github.com/JakeWnuk/ptt && cd ptt && docker build -t ptt . && ### Usage: ``` -Usage of Password Transformation Tool (ptt) version (0.3.5): +Usage of Password Transformation Tool (ptt) version (0.3.6): ptt [options] [...] Accepts standard input and/or additonal arguments. @@ -63,6 +63,8 @@ These modify or filter the transformation mode. Only output items of a certain length (does not adjust for rules). Accepts ranges separated by '-'. -m int Minimum numerical frequency to include in output. + -md + If Markdown format should be used for output instead. -n int Maximum number of items to return in output. -o string diff --git a/docs/USAGE.md b/docs/USAGE.md index ae90d82..4f90db2 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -1,5 +1,5 @@ # Password Transformation Tool (PTT) Usage Guide -## Version 0.3.5 +## Version 0.3.6 ### Table of Contents #### Getting Started diff --git a/main.go b/main.go index 9a8f9bb..0b8026c 100644 --- a/main.go +++ b/main.go @@ -15,7 +15,7 @@ import ( "github.com/jakewnuk/ptt/pkg/utils" ) -var version = "0.3.5" +var version = "0.3.6" var wg sync.WaitGroup var mutex = &sync.Mutex{} var retain models.FileArgumentFlag @@ -88,6 +88,7 @@ func main() { verbose2 := flag.Bool("vv", false, "Show statistics output when possible.") verbose3 := flag.Bool("vvv", false, "Show verbose statistics output when possible.") minimum := flag.Int("m", 0, "Minimum numerical frequency to include in output.") + markDownOutput := flag.Bool("md", false, "If Markdown format should be used for output instead.") outputVerboseMax := flag.Int("n", 0, "Maximum number of items to return in output.") transformation := flag.String("t", "", "Transformation to apply to input.") replacementMask := flag.String("rm", "uldsbt", "Replacement mask for transformations if applicable.") @@ -238,12 +239,22 @@ func main() { fmt.Fprintf(os.Stderr, "[*] Task complete with %d unique results.\n", len(primaryMap)) + // Print in markdown if provided + if *markDownOutput { + command := "ptt " + for _, arg := range os.Args[1:] { + command += arg + " " + } + + format.PrintArrayToMarkdown(primaryMap, command) + } + // Print output to stdout - if *verbose3 { + if *verbose3 && !*markDownOutput { format.PrintStatsToSTDOUT(primaryMap, *verbose3, *outputVerboseMax) - } else if *verbose2 { + } else if *verbose2 && !*markDownOutput { format.PrintStatsToSTDOUT(primaryMap, *verbose3, *outputVerboseMax) - } else { + } else if !*markDownOutput { format.PrintArrayToSTDOUT(primaryMap, *verbose) } diff --git a/pkg/format/format.go b/pkg/format/format.go index 84bb1af..9fcbab2 100644 --- a/pkg/format/format.go +++ b/pkg/format/format.go @@ -49,6 +49,35 @@ func PrintArrayToSTDOUT(freq map[string]int, verbose bool) { } } +// PrintArrayToMarkdown prints an array of items to stdout in markdown format +// including the item and the frequency. +// +// Args: +// freq (map[string]int): A map of item frequencies +// command (string): The command that was run +// +// Returns: +// None +func PrintArrayToMarkdown(freq map[string]int, command string) { + + fmt.Println("| Item | Frequency |") + fmt.Println("| ---- | --------- |") + + p := make(models.PairList, len(freq)) + i := 0 + for k, v := range freq { + p[i] = models.Pair{k, v} + i++ + } + sort.Sort(sort.Reverse(p)) + for _, pair := range p { + fmt.Printf("| %s | %d |\n", pair.Key, pair.Value) + } + + fmt.Println(fmt.Sprintf("Command: %s\n", command)) + +} + // PrintStatsToSTDOUT prints statistics about the frequency map to stdout // including several statistics about the frequency map. If verbose is true, // additional information is printed and increased number of items are @@ -58,12 +87,12 @@ func PrintArrayToSTDOUT(freq map[string]int, verbose bool) { // // freq (map[string]int): A map of item frequencies // verbose (bool): If true, additional information is printed -// max (int): The maximum number of items to print +// maxItems (int): The maximum number of items to print // // Returns: // // None -func PrintStatsToSTDOUT(freq map[string]int, verbose bool, max int) { +func PrintStatsToSTDOUT(freq map[string]int, verbose bool, maxItems int) { // Sort by frequency p := make(models.PairList, len(freq)) @@ -77,12 +106,12 @@ func PrintStatsToSTDOUT(freq map[string]int, verbose bool, max int) { sort.Sort(sort.Reverse(p)) sort.Sort(sort.Reverse(normalizedP)) - if max == 0 { - max = 25 + if maxItems == 0 { + maxItems = 25 } - if max > len(p) { - max = len(p) + if maxItems > len(p) { + maxItems = len(p) } if len(p) == 0 { @@ -93,7 +122,7 @@ func PrintStatsToSTDOUT(freq map[string]int, verbose bool, max int) { // Print the statistics if verbose { fmt.Fprintf(os.Stderr, "[*] Starting statistics generation. Please wait...\n") - fmt.Println(fmt.Sprintf("Verbose Statistics: max=%d", max)) + fmt.Println(fmt.Sprintf("Verbose Statistics: max=%d", maxItems)) fmt.Println("--------------------------------------------------") fmt.Println(CreateVerboseStats(freq)) fmt.Println("--------------------------------------------------") @@ -108,14 +137,14 @@ func PrintStatsToSTDOUT(freq map[string]int, verbose bool, max int) { // Use the longest key to normalize padding for the graph longest := 0 - for _, value := range p[0:max] { + for _, value := range p[0:maxItems] { if len(value.Key) > longest { longest = len(value.Key) } } // Print the top items - for index, value := range p[0:max] { + for index, value := range p[0:maxItems] { if value.Value == 1 && index == 0 { fmt.Println("[!] No items with a frequency greater than 1!") break @@ -179,15 +208,15 @@ func CreateVerboseStats(freq map[string]int) string { stats += fmt.Sprintf("Smallest frequency: %d\n", p[len(p)-1].Value) stats += "\nPlots:\n" - plot, min, q1, q2, q3, max := CreateBoxAndWhiskersPlot(lengths) + plot, minBW, q1, q2, q3, maxBW := CreateBoxAndWhiskersPlot(lengths) stats += fmt.Sprintf("Item Length: %s\n", plot) - stats += fmt.Sprintf("Min: %d, Q1: %d, Q2: %d, Q3: %d, Max: %d\n", min, q1, q2, q3, max) - plot, min, q1, q2, q3, max = CreateBoxAndWhiskersPlot(frequencies) + stats += fmt.Sprintf("Min: %d, Q1: %d, Q2: %d, Q3: %d, Max: %d\n", minBW, q1, q2, q3, maxBW) + plot, minBW, q1, q2, q3, maxBW = CreateBoxAndWhiskersPlot(frequencies) stats += fmt.Sprintf("Item Frequency: %s\n", plot) - stats += fmt.Sprintf("Min: %d, Q1: %d, Q2: %d, Q3: %d, Max: %d\n", min, q1, q2, q3, max) - plot, min, q1, q2, q3, max = CreateBoxAndWhiskersPlot(complexities) + stats += fmt.Sprintf("Min: %d, Q1: %d, Q2: %d, Q3: %d, Max: %d\n", minBW, q1, q2, q3, maxBW) + plot, minBW, q1, q2, q3, maxBW = CreateBoxAndWhiskersPlot(complexities) stats += fmt.Sprintf("Item Complexity: %s\n", plot) - stats += fmt.Sprintf("Min: %d, Q1: %d, Q2: %d, Q3: %d, Max: %d\n", min, q1, q2, q3, max) + stats += fmt.Sprintf("Min: %d, Q1: %d, Q2: %d, Q3: %d, Max: %d\n", minBW, q1, q2, q3, maxBW) stats += "\nCategory Counts:\n" for category, count := range categoryCounts { @@ -384,19 +413,19 @@ func CalculateQuartiles(data []int) (int, int, int) { // int: The maximum value func CreateBoxAndWhiskersPlot(data []int) (string, int, int, int, int, int) { q1, q2, q3 := CalculateQuartiles(data) - min := data[0] - max := data[len(data)-1] + minBW := data[0] + maxBW := data[len(data)-1] // Normalize the plot - largest := max + largest := maxBW normalizedQ1 := q1 * 50 / largest normalizedQ2 := q2 * 50 / largest normalizedQ3 := q3 * 50 / largest - normalizedMin := min * 50 / largest - normalizedMax := max * 50 / largest + normalizedMin := minBW * 50 / largest + normalizedMax := maxBW * 50 / largest plot := fmt.Sprintf("|%s[%s|%s]%s|", strings.Repeat("-", normalizedQ1-normalizedMin), strings.Repeat("=", normalizedQ2-normalizedQ1), strings.Repeat("=", normalizedQ3-normalizedQ2), strings.Repeat("-", normalizedMax-normalizedQ3)) - return plot, min, q1, q2, q3, max + return plot, minBW, q1, q2, q3, maxBW } // SaveArrayToJSON saves an array of items to a JSON file at the specified path @@ -488,15 +517,15 @@ func RetainRemove(textMap map[string]int, retainMap map[string]int, removeMap ma // Args: // // freq (map[string]int): A map of item frequencies -// min (int): The minimum frequency threshold +// minF (int): The minimum frequency threshold // // Returns: // // (map[string]int): A new map of item frequencies above the minimum threshold -func RemoveMinimumFrequency(freq map[string]int, min int) map[string]int { +func RemoveMinimumFrequency(freq map[string]int, minF int) map[string]int { newFreq := make(map[string]int) for key, value := range freq { - if value >= min { + if value >= minF { newFreq[key] = value } } diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 5fd49b1..7d60f92 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -1004,10 +1004,6 @@ func GeneratePassphrase(text string, n int) []string { var turkTitleCaseWords string var CAPSlowerWords []string var lowerCAPSWords []string - var lowerl33tWords []string - var l33tlowerWords []string - var CAPSl33tWords []string - var l33tCAPSWords []string tick := false titleCaseWords = cases.Title(language.Und, cases.NoLower).String(text) turkTitleCaseWords = cases.Upper(language.Turkish, cases.NoLower).String(text) @@ -1017,28 +1013,14 @@ func GeneratePassphrase(text string, n int) []string { if tick { CAPSlowerWords = append(CAPSlowerWords, strings.ToUpper(word)) lowerCAPSWords = append(lowerCAPSWords, strings.ToLower(word)) - lowerl33tWords = append(lowerl33tWords, strings.ToLower(word)) - l33tlowerWords = append(l33tlowerWords, strings.ToLower(strings.ReplaceAll(strings.ReplaceAll(word, "a", "4"), "e", "3"))) - CAPSl33tWords = append(CAPSl33tWords, strings.ToUpper(word)) - l33tCAPSWords = append(l33tCAPSWords, strings.ReplaceAll(strings.ReplaceAll(word, "a", "4"), "e", "3")) } else { CAPSlowerWords = append(CAPSlowerWords, strings.ToLower(word)) lowerCAPSWords = append(lowerCAPSWords, strings.ToUpper(word)) - lowerl33tWords = append(lowerl33tWords, strings.ToLower(strings.ReplaceAll(strings.ReplaceAll(word, "a", "4"), "e", "3"))) - l33tlowerWords = append(l33tlowerWords, strings.ToLower(word)) - CAPSl33tWords = append(CAPSl33tWords, strings.ReplaceAll(strings.ReplaceAll(word, "a", "4"), "e", "3")) - l33tCAPSWords = append(l33tCAPSWords, strings.ToUpper(word)) } tick = !tick } - CAPSlowerPassphrase := strings.Join(CAPSlowerWords, "") - lowerCAPSPassphrase := strings.Join(lowerCAPSWords, "") - lowerl33tPassphrase := strings.Join(lowerl33tWords, "") - l33tlowerPassphrase := strings.Join(l33tlowerWords, "") - CAPSl33tPassphrase := strings.Join(CAPSl33tWords, "") - l33tCAPSPassphrase := strings.Join(l33tCAPSWords, "") passphrases = append(passphrases, strings.ReplaceAll(titleCaseWords, " ", "")) passphrases = append(passphrases, strings.ReplaceAll(turkTitleCaseWords, " ", "")) @@ -1046,12 +1028,13 @@ func GeneratePassphrase(text string, n int) []string { passphrases = append(passphrases, strings.ReplaceAll(turkTitleCaseWords, " ", "-")) passphrases = append(passphrases, strings.ReplaceAll(titleCaseWords, " ", "_")) passphrases = append(passphrases, strings.ReplaceAll(turkTitleCaseWords, " ", "_")) - passphrases = append(passphrases, CAPSlowerPassphrase) - passphrases = append(passphrases, lowerCAPSPassphrase) - passphrases = append(passphrases, lowerl33tPassphrase) - passphrases = append(passphrases, l33tlowerPassphrase) - passphrases = append(passphrases, CAPSl33tPassphrase) - passphrases = append(passphrases, l33tCAPSPassphrase) + passphrases = append(passphrases, strings.Join(CAPSlowerWords, " ")) + passphrases = append(passphrases, strings.Join(CAPSlowerWords, "")) + passphrases = append(passphrases, strings.Join(lowerCAPSWords, " ")) + passphrases = append(passphrases, strings.Join(lowerCAPSWords, "")) + passphrases = append(passphrases, strings.ReplaceAll(text, " ", "")) + passphrases = append(passphrases, titleCaseWords) + passphrases = append(passphrases, turkTitleCaseWords) return passphrases } diff --git a/pkg/utils/utils_test.go b/pkg/utils/utils_test.go index 33ba377..fcae6f2 100644 --- a/pkg/utils/utils_test.go +++ b/pkg/utils/utils_test.go @@ -674,7 +674,7 @@ func TestGeneratePassphrase(t *testing.T) { // Define test cases testCases := TestCases{ - {"I <3 you", 3, []string{"I<3you", "I<3YOU", "i<3you", "I<3YOU", "I<3You", "i<3you", "i<3you", "I<3YOU", "I-<3-You", "I-<3-YOU", "I_<3_YOU", "I_<3_You"}}, + {"I <3 you", 3, []string{"I<3You", "I<3YOU", "I-<3-You", "I-<3-YOU", "I_<3_You", "I_<3_YOU", "i <3 you", "i<3you", "I <3 YOU", "I<3YOU", "I<3you", "I <3 You", "I <3 YOU"}}, } // Run test cases