diff --git a/cupp.py b/cupp.py index 32d24ee..92315c2 100755 --- a/cupp.py +++ b/cupp.py @@ -90,14 +90,42 @@ def read_config(filename): print("Configuration file " + filename + " not found!") sys.exit("Exiting.") - return False +def replace_str(in_str: str, pattern: str, indices: [int], char_replacer: {str: int}) -> str: + assert len(pattern) == len(indices) + result_str = list(in_str) + for patt_index in range(len(indices)): + if pattern[patt_index] == "1": + str_index = indices[patt_index] + result_str[str_index] = str(char_replacer[result_str[str_index]]) + return "".join(result_str) -def make_leet(x): - """convert string to leet""" - for letter, leetletter in CONFIG["LEET"].items(): - x = x.replace(letter, leetletter) - return x + +def make_leet(in_str: str) -> [str]: + """convert string to list of leet""" + + # map to replace a singe char with it's leet equivalent + char_replacer = { + letter: leet_letter + for letter, leet_letter in CONFIG["LEET"].items() + } + # list of indices of replaceable chars + indices = [ + index + for index in range(len(in_str)) + if in_str[index] in char_replacer.keys() + ] + ind_len = len(indices) + # A replacement could be represented by a binary number + # E.g. 1001 would mean that the first and the last replaceable char is replaced. + # Such a Number has 2^len(indices) possibilities and the 000... possibility is not fulfilled, + # because it has no leet replaced chars in it. + count_of_replaced_strings = 2**ind_len + + return [ + replace_str(in_str, f'{pattern:0{ind_len}b}', indices, char_replacer) + for pattern in range(1, count_of_replaced_strings) + ] # for concatenations... @@ -284,16 +312,14 @@ def improve_dictionary(file_to_open): unique_lista ): # if you want to add more leet chars, you will need to add more lines in cupp.cfg too... x = make_leet(x) # convert to leet - unique_leet.append(x) + unique_leet.extend(x) unique_list = unique_lista + unique_leet - unique_list_finished = [] - unique_list_finished = [ x for x in unique_list - if len(x) > CONFIG["global"]["wcfrom"] and len(x) < CONFIG["global"]["wcto"] + if CONFIG["global"]["wcfrom"] < len(x) < CONFIG["global"]["wcto"] ] print_to_file(file_to_open + ".cupp.txt", unique_list_finished) @@ -433,7 +459,6 @@ def generate_wordlist_from_profile(profile): petup = profile["pet"].title() companyup = profile["company"].title() - wordsup = [] wordsup = list(map(str.title, profile["words"])) word = profile["words"] + wordsup @@ -694,7 +719,7 @@ def generate_wordlist_from_profile(profile): ): # if you want to add more leet chars, you will need to add more lines in cupp.cfg too... x = make_leet(x) # convert to leet - unique_leet.append(x) + unique_leet.extend(x) unique_list = unique_lista + unique_leet @@ -702,7 +727,7 @@ def generate_wordlist_from_profile(profile): unique_list_finished = [ x for x in unique_list - if len(x) < CONFIG["global"]["wcto"] and len(x) > CONFIG["global"]["wcfrom"] + if CONFIG["global"]["wcto"] > len(x) > CONFIG["global"]["wcfrom"] ] print_to_file(profile["name"] + ".txt", unique_list_finished) diff --git a/test_cupp.py b/test_cupp.py index ea06ad1..189d1c5 100755 --- a/test_cupp.py +++ b/test_cupp.py @@ -145,6 +145,57 @@ def test_interactive(self): self.assertTrue(test_ok, "interactive generation works") + def test_make_leet(self): + """ test the make leet function """ + test_data = [ + ("", []), + ("q", []), + ("äö~#-_:_:", []), + ("0123456789", []), + ("!§$%&()=", []), + ("²³`´énµ€@", []), + ("a", ["4"]), + ("aa", ["a4", "4a", "44"]), + ("aaa", ["aa4", "a4a", "a44", "4aa", "4a4", "44a", "444"]), + ("aietosgz", [ + "aietosg2", "aietos9z", "aietos92", "aieto5gz", "aieto5g2", "aieto59z", "aieto592", "aiet0sgz", + "aiet0sg2", "aiet0s9z", "aiet0s92", "aiet05gz", "aiet05g2", "aiet059z", "aiet0592", "aie7osgz", + "aie7osg2", "aie7os9z", "aie7os92", "aie7o5gz", "aie7o5g2", "aie7o59z", "aie7o592", "aie70sgz", + "aie70sg2", "aie70s9z", "aie70s92", "aie705gz", "aie705g2", "aie7059z", "aie70592", "ai3tosgz", + "ai3tosg2", "ai3tos9z", "ai3tos92", "ai3to5gz", "ai3to5g2", "ai3to59z", "ai3to592", "ai3t0sgz", + "ai3t0sg2", "ai3t0s9z", "ai3t0s92", "ai3t05gz", "ai3t05g2", "ai3t059z", "ai3t0592", "ai37osgz", + "ai37osg2", "ai37os9z", "ai37os92", "ai37o5gz", "ai37o5g2", "ai37o59z", "ai37o592", "ai370sgz", + "ai370sg2", "ai370s9z", "ai370s92", "ai3705gz", "ai3705g2", "ai37059z", "ai370592", "a1etosgz", + "a1etosg2", "a1etos9z", "a1etos92", "a1eto5gz", "a1eto5g2", "a1eto59z", "a1eto592", "a1et0sgz", + "a1et0sg2", "a1et0s9z", "a1et0s92", "a1et05gz", "a1et05g2", "a1et059z", "a1et0592", "a1e7osgz", + "a1e7osg2", "a1e7os9z", "a1e7os92", "a1e7o5gz", "a1e7o5g2", "a1e7o59z", "a1e7o592", "a1e70sgz", + "a1e70sg2", "a1e70s9z", "a1e70s92", "a1e705gz", "a1e705g2", "a1e7059z", "a1e70592", "a13tosgz", + "a13tosg2", "a13tos9z", "a13tos92", "a13to5gz", "a13to5g2", "a13to59z", "a13to592", "a13t0sgz", + "a13t0sg2", "a13t0s9z", "a13t0s92", "a13t05gz", "a13t05g2", "a13t059z", "a13t0592", "a137osgz", + "a137osg2", "a137os9z", "a137os92", "a137o5gz", "a137o5g2", "a137o59z", "a137o592", "a1370sgz", + "a1370sg2", "a1370s9z", "a1370s92", "a13705gz", "a13705g2", "a137059z", "a1370592", "4ietosgz", + "4ietosg2", "4ietos9z", "4ietos92", "4ieto5gz", "4ieto5g2", "4ieto59z", "4ieto592", "4iet0sgz", + "4iet0sg2", "4iet0s9z", "4iet0s92", "4iet05gz", "4iet05g2", "4iet059z", "4iet0592", "4ie7osgz", + "4ie7osg2", "4ie7os9z", "4ie7os92", "4ie7o5gz", "4ie7o5g2", "4ie7o59z", "4ie7o592", "4ie70sgz", + "4ie70sg2", "4ie70s9z", "4ie70s92", "4ie705gz", "4ie705g2", "4ie7059z", "4ie70592", "4i3tosgz", + "4i3tosg2", "4i3tos9z", "4i3tos92", "4i3to5gz", "4i3to5g2", "4i3to59z", "4i3to592", "4i3t0sgz", + "4i3t0sg2", "4i3t0s9z", "4i3t0s92", "4i3t05gz", "4i3t05g2", "4i3t059z", "4i3t0592", "4i37osgz", + "4i37osg2", "4i37os9z", "4i37os92", "4i37o5gz", "4i37o5g2", "4i37o59z", "4i37o592", "4i370sgz", + "4i370sg2", "4i370s9z", "4i370s92", "4i3705gz", "4i3705g2", "4i37059z", "4i370592", "41etosgz", + "41etosg2", "41etos9z", "41etos92", "41eto5gz", "41eto5g2", "41eto59z", "41eto592", "41et0sgz", + "41et0sg2", "41et0s9z", "41et0s92", "41et05gz", "41et05g2", "41et059z", "41et0592", "41e7osgz", + "41e7osg2", "41e7os9z", "41e7os92", "41e7o5gz", "41e7o5g2", "41e7o59z", "41e7o592", "41e70sgz", + "41e70sg2", "41e70s9z", "41e70s92", "41e705gz", "41e705g2", "41e7059z", "41e70592", "413tosgz", + "413tosg2", "413tos9z", "413tos92", "413to5gz", "413to5g2", "413to59z", "413to592", "413t0sgz", + "413t0sg2", "413t0s9z", "413t0s92", "413t05gz", "413t05g2", "413t059z", "413t0592", "4137osgz", + "4137osg2", "4137os9z", "4137os92", "4137o5gz", "4137o5g2", "4137o59z", "4137o592", "41370sgz", + "41370sg2", "41370s9z", "41370s92", "413705gz", "413705g2", "4137059z", "41370592" + ]) + ] + for data_tuple in test_data: + output_leet = make_leet(data_tuple[0]) + self.assertEqual(output_leet, data_tuple[1]) + def test_main(self): """ test run for the main function """ main()