@@ -67,6 +67,10 @@ type Config struct {
6767 upgrade bool
6868 showVersion bool
6969 Rules []string // Ordered list of rules to apply
70+ seedWords string
71+ keyboardWalks bool
72+ smartAffix bool
73+ toggleVariations bool
7074}
7175
7276// ruleFlag is a custom flag type that appends the rule name to the config's Rules list
@@ -92,15 +96,32 @@ func (f *ruleFlag) IsBoolFlag() bool {
9296
9397// LeetMap defines character substitutions for leet speak
9498var leetMap = map [rune ][]rune {
95- 's' : {'$' , 'z' },
96- 'e' : {'3' },
97- 'a' : {'4' , '@' },
98- 'o' : {'0' },
99- 'i' : {'1' , '!' },
100- 'l' : {'1' , '!' },
101- 't' : {'7' },
102- 'b' : {'8' },
103- 'z' : {'2' },
99+ 'a' : {'4' , '@' , '^' },
100+ 'b' : {'8' , '6' },
101+ 'c' : {'(' , '<' , '[' , '{' },
102+ 'd' : {'|' , ')' , '?' },
103+ 'e' : {'3' , '&' },
104+ 'f' : {'|' },
105+ 'g' : {'9' , '6' , '&' },
106+ 'h' : {'#' , '4' },
107+ 'i' : {'1' , '!' , '|' },
108+ 'j' : {'|' , ';' },
109+ 'k' : {'<' , '|' , '{' },
110+ 'l' : {'1' , '!' , '|' },
111+ 'm' : {'|' , 'v' , 'M' },
112+ 'n' : {'^' , '~' },
113+ 'o' : {'0' , '*' },
114+ 'p' : {'|' , '*' },
115+ 'q' : {'9' , '0' },
116+ 'r' : {'2' },
117+ 's' : {'5' , '$' , 'z' },
118+ 't' : {'7' , '+' },
119+ 'u' : {'v' },
120+ 'v' : {'\\' , '/' , '^' },
121+ 'w' : {'v' },
122+ 'x' : {'%' , '×' },
123+ 'y' : {'j' },
124+ 'z' : {'2' , '%' , '7' },
104125}
105126
106127// CommonWords to append/prepend
@@ -505,6 +526,11 @@ func parseFlags(args []string) *Config {
505526 fs .BoolVar (& config .checkUpdates , "check-updates" , false , "check for updates" )
506527 fs .BoolVar (& config .upgrade , "upgrade" , false , "perform self-upgrade" )
507528
529+ fs .StringVar (& config .seedWords , "seed" , "" , "comma-separated seed words" )
530+ fs .BoolVar (& config .keyboardWalks , "walks" , false , "add common keyboard walks" )
531+ fs .BoolVar (& config .smartAffix , "smart-affix" , false , "add smart affixes (years, 123, symbols)" )
532+ fs .BoolVar (& config .toggleVariations , "toggle-variations" , false , "add toggle case permutations" )
533+
508534 fs .Parse (args )
509535 return config
510536}
@@ -545,6 +571,10 @@ func showUsage() {
545571 fmt .Fprintf (os .Stderr , "\t %s-ss%s, %s--suffix-strings%s %s<S>%s: add strings to the end (comma-separated)\n " , y , r , y , r , b , r )
546572 fmt .Fprintf (os .Stderr , "\t %s-t%s, %s--leet%s: l33t speak the word\n " , y , r , y , r )
547573 fmt .Fprintf (os .Stderr , "\t %s-T%s, %s--full-leet%s: all possibilities l33t\n " , y , r , y , r )
574+ fmt .Fprintf (os .Stderr , "\t %s--seed%s %s<words>%s: inject seed words (comma-separated)\n " , y , r , b , r )
575+ fmt .Fprintf (os .Stderr , "\t %s--walks%s: add common keyboard walks\n " , y , r )
576+ fmt .Fprintf (os .Stderr , "\t %s--smart-affix%s: add smart affixes (years, 123, symbols)\n " , y , r )
577+ fmt .Fprintf (os .Stderr , "\t %s--toggle-variations%s: add toggle case permutations\n " , y , r )
548578 fmt .Fprintf (os .Stderr , "\t %s-u%s, %s--upper%s: uppercase the word\n " , y , r , y , r )
549579 fmt .Fprintf (os .Stderr , "\t %s-v%s: show version\n " , y , r )
550580 fmt .Fprintf (os .Stderr , "\t %s-x%s, %s--max%s %s<N>%s: maximum word length\n " , y , r , y , r , b , r )
@@ -645,12 +675,17 @@ func showLongUsage() {
645675 fmt .Fprintf (os .Stderr , " %s-ac%s, %s--all-cases%s Generate all case permutations (warning: huge output).\n " , y , r , y , r )
646676 fmt .Fprintf (os .Stderr , " %s-d%s, %s--double%s Append word to itself.\n " , y , r , y , r )
647677 fmt .Fprintf (os .Stderr , " %s-A%s, %s--acronym%s Create acronyms from input words.\n " , y , r , y , r )
648- fmt .Fprintf (os .Stderr , " %s--space%s Add spaces between words (for permutations).\n \n " , y , r )
678+ fmt .Fprintf (os .Stderr , " %s--space%s Add spaces between words (for permutations).\n " , y , r )
679+ fmt .Fprintf (os .Stderr , " %s--seed%s %s<words>%s Inject seed words (comma-separated).\n " , y , r , b , r )
680+ fmt .Fprintf (os .Stderr , " %s--walks%s Add common keyboard walks.\n " , y , r )
681+ fmt .Fprintf (os .Stderr , " %s--toggle-variations%s Add toggle case permutations.\n \n " , y , r )
649682
650683 // TEXT MANIPULATION (APPEND/PREPEND)
651684 fmt .Fprintf (os .Stderr , "TEXT MANIPULATION (APPEND/PREPEND):\n " )
652685 fmt .Fprintf (os .Stderr , " %s-C%s, %s--common%s %s[file]%s\n " , y , r , y , r , b , r )
653686 fmt .Fprintf (os .Stderr , "\t Add common words (admin, sys, etc) or load from file.\n " )
687+ fmt .Fprintf (os .Stderr , " %s--smart-affix%s\n " , y , r )
688+ fmt .Fprintf (os .Stderr , "\t Add smart affixes (years, 123, symbols).\n " )
654689 fmt .Fprintf (os .Stderr , " %s-ps%s, %s--prefix-strings%s %s<S>%s\n " , y , r , y , r , b , r )
655690 fmt .Fprintf (os .Stderr , "\t Add comma-separated strings to the start of each word.\n " )
656691 fmt .Fprintf (os .Stderr , " %s-ss%s, %s--suffix-strings%s %s<S>%s\n " , y , r , y , r , b , r )
@@ -703,6 +738,20 @@ func run(config *Config, inputPaths []string) error {
703738 }
704739 }
705740
741+ if config .seedWords != "" {
742+ seeds := strings .Split (config .seedWords , "," )
743+ for _ , s := range seeds {
744+ s = strings .TrimSpace (s )
745+ if s != "" {
746+ allWords = append (allWords , s )
747+ }
748+ }
749+ }
750+
751+ if config .keyboardWalks {
752+ allWords = append (allWords , getKeyboardWalks ()... )
753+ }
754+
706755 if len (allWords ) == 0 {
707756 return fmt .Errorf ("no words loaded from input" )
708757 }
@@ -1013,6 +1062,14 @@ func (m *Mangler) mangleWord(word string) {
10131062 res [word + string (p )] = struct {}{}
10141063 }
10151064 }
1065+ if m .config .smartAffix {
1066+ m .addSmartAffixes (word , res )
1067+ }
1068+ if m .config .toggleVariations {
1069+ for _ , v := range generateToggleVariations (word ) {
1070+ res [v ] = struct {}{}
1071+ }
1072+ }
10161073 if m .config .yearsCount != "" {
10171074 m .addNumberRange (word , m .config .yearsCount , true , res )
10181075 m .addNumberRange (word , m .config .yearsCount , false , res )
@@ -1580,5 +1637,102 @@ var lengthChances = map[int]float64{
15801637var comboChances = map [int ]float64 {
15811638 16 : 0.78 , 4 : 0.76 , 20 : 0.76 , 256 : 0.49 , 272 : 0.29 , 260 : 0.29 , 276 : 0.29 ,
15821639 32 : 0.28 , 288 : 0.28 , 48 : 0.27 , 304 : 0.27 , 36 : 0.27 , 52 : 0.27 , 292 : 0.27 ,
1583- 1024 : 0.19 , 1280 : 0.19 , 8 : 0.03 , 1 : 0.02 , 9 : 0.02 , 128 : 0.019 ,
1640+ 1024 : 0.19 , 1280 : 0.19 , 8 : 0.03 , 1 : 0.02 , 9 : 0.02 , 128 : 0.019 ,
1641+ }
1642+
1643+ func getKeyboardWalks () []string {
1644+ return []string {
1645+ "qwerty" , "asdfgh" , "zxcvbn" , "123456" , "qazwsx" ,
1646+ "qwer" , "asdf" , "zxcv" , "1234" , "1qaz" , "zaq1" ,
1647+ "wsx" , "edc" , "rfv" , "tgb" , "yhn" , "ujm" , "ik," , "ol." , "p;/" ,
1648+ "plm" , "okn" , "ijb" , "uhv" , "ygc" , "tfx" , "rdz" , "esz" , "waq" ,
1649+ "!@#$" , "!@#$%" , "qwertyuiop" , "asdfghjkl" , "zxcvbnm" ,
1650+ }
1651+ }
1652+
1653+ func (m * Mangler ) addSmartAffixes (word string , res map [string ]struct {}) {
1654+ // Years: current and past 5
1655+ cur := time .Now ().Year ()
1656+ for i := 0 ; i <= 5 ; i ++ {
1657+ y := cur - i
1658+ ys := fmt .Sprintf ("%d" , y )
1659+ res [word + ys ] = struct {}{}
1660+ res [ys + word ] = struct {}{}
1661+ // Short year
1662+ if len (ys ) >= 4 {
1663+ sys := ys [2 :]
1664+ res [word + sys ] = struct {}{}
1665+ res [sys + word ] = struct {}{}
1666+ }
1667+ }
1668+
1669+ // 123 variations
1670+ seqs := []string {"1" , "12" , "123" , "1234" , "12345" , "123456" , "0" , "01" , "012" }
1671+ for _ , s := range seqs {
1672+ res [word + s ] = struct {}{}
1673+ res [s + word ] = struct {}{}
1674+ }
1675+
1676+ // Common symbols
1677+ syms := []string {"!" , "." , "?" , "*" , "#" , "@" , "$" }
1678+ for _ , s := range syms {
1679+ res [word + s ] = struct {}{}
1680+ res [s + word ] = struct {}{}
1681+ }
1682+ }
1683+
1684+ func generateToggleVariations (word string ) []string {
1685+ if len (word ) == 0 {
1686+ return nil
1687+ }
1688+ var res []string
1689+
1690+ // Toggle first char
1691+ runes := []rune (word )
1692+ if len (runes ) > 0 {
1693+ r0 := runes [0 ]
1694+ if r0 >= 'a' && r0 <= 'z' {
1695+ runes [0 ] = r0 - 32
1696+ } else if r0 >= 'A' && r0 <= 'Z' {
1697+ runes [0 ] = r0 + 32
1698+ }
1699+ res = append (res , string (runes ))
1700+ }
1701+
1702+ // Toggle last char
1703+ runes = []rune (word )
1704+ if len (runes ) > 0 {
1705+ last := len (runes ) - 1
1706+ rl := runes [last ]
1707+ if rl >= 'a' && rl <= 'z' {
1708+ runes [last ] = rl - 32
1709+ } else if rl >= 'A' && rl <= 'Z' {
1710+ runes [last ] = rl + 32
1711+ }
1712+ res = append (res , string (runes ))
1713+ }
1714+
1715+ // Alternating case 1: aBcD
1716+ runes = []rune (word )
1717+ for i := range runes {
1718+ if i % 2 == 0 {
1719+ runes [i ] = []rune (strings .ToLower (string (runes [i ])))[0 ]
1720+ } else {
1721+ runes [i ] = []rune (strings .ToUpper (string (runes [i ])))[0 ]
1722+ }
1723+ }
1724+ res = append (res , string (runes ))
1725+
1726+ // Alternating case 2: AbCd
1727+ runes = []rune (word )
1728+ for i := range runes {
1729+ if i % 2 != 0 {
1730+ runes [i ] = []rune (strings .ToLower (string (runes [i ])))[0 ]
1731+ } else {
1732+ runes [i ] = []rune (strings .ToUpper (string (runes [i ])))[0 ]
1733+ }
1734+ }
1735+ res = append (res , string (runes ))
1736+
1737+ return res
15841738}
0 commit comments