gitee.com/lonely0422/gometalinter.git@v3.0.1-0.20190307123442-32416ab75314+incompatible/_linters/src/github.com/nbutton23/zxcvbn-go/matching/leet.go (about)

     1  package matching
     2  
     3  import (
     4  	"strings"
     5  
     6  	"github.com/nbutton23/zxcvbn-go/entropy"
     7  	"github.com/nbutton23/zxcvbn-go/match"
     8  )
     9  
    10  const L33T_MATCHER_NAME = "l33t"
    11  
    12  func FilterL33tMatcher(m match.Matcher) bool {
    13  	return m.ID == L33T_MATCHER_NAME
    14  }
    15  
    16  func l33tMatch(password string) []match.Match {
    17  	permutations := getPermutations(password)
    18  
    19  	var matches []match.Match
    20  
    21  	for _, permutation := range permutations {
    22  		for _, mather := range DICTIONARY_MATCHERS {
    23  			matches = append(matches, mather.MatchingFunc(permutation)...)
    24  		}
    25  	}
    26  
    27  	for _, match := range matches {
    28  		match.Entropy += entropy.ExtraLeetEntropy(match, password)
    29  		match.DictionaryName = match.DictionaryName + "_3117"
    30  	}
    31  
    32  	return matches
    33  }
    34  
    35  // This function creates a list of permutations based on a fixed table stored on data. The table
    36  // will be reduced in order to proceed in the function using only relevant values (see
    37  // relevantL33tSubtable).
    38  func getPermutations(password string) []string {
    39  	substitutions := relevantL33tSubtable(password)
    40  	permutations := getAllPermutationsOfLeetSubstitutions(password, substitutions)
    41  	return permutations
    42  }
    43  
    44  // This function loads the table from data but only keep in memory the values that are present
    45  // inside the provided password.
    46  func relevantL33tSubtable(password string) map[string][]string {
    47  	relevantSubs := make(map[string][]string)
    48  	for key, values := range L33T_TABLE.Graph {
    49  		for _, value := range values {
    50  			if strings.Contains(password, value) {
    51  				relevantSubs[key] = append(relevantSubs[key], value)
    52  			}
    53  		}
    54  	}
    55  
    56  	return relevantSubs
    57  }
    58  
    59  // This function creates the list of permutations of a given password using the provided table as
    60  // reference for its operation.
    61  func getAllPermutationsOfLeetSubstitutions(password string, table map[string][]string) []string {
    62  	result := []string{}
    63  
    64  	// create a list of tables without conflicting keys/values (this happens for "|", "7" and "1")
    65  	noConflictsTables := createListOfMapsWithoutConflicts(table)
    66  	for _, noConflictsTable := range noConflictsTables {
    67  		substitutionsMaps := createSubstitutionsMapsFromTable(noConflictsTable)
    68  		for _, substitutionsMap := range substitutionsMaps {
    69  			newValue := createWordForSubstitutionMap(password, substitutionsMap)
    70  			if !stringSliceContainsValue(result, newValue) {
    71  				result = append(result, newValue)
    72  			}
    73  		}
    74  	}
    75  
    76  	return result
    77  }
    78  
    79  // Create the possible list of maps removing the conflicts from it. As an example, the value "|"
    80  // may represent "i" and "l". For each representation of the conflicting value, a new map is
    81  // created. This may grow exponencialy according to the number of conflicts. The number of maps
    82  // returned by this function may be reduced if the relevantL33tSubtable function was called to
    83  // identify only relevant items.
    84  func createListOfMapsWithoutConflicts(table map[string][]string) []map[string][]string {
    85  	// the resulting list starts with the provided table
    86  	result := []map[string][]string{}
    87  	result = append(result, table)
    88  
    89  	// iterate over the list of conflicts in order to expand the maps for each one
    90  	conflicts := retrieveConflictsListFromTable(table)
    91  	for _, value := range conflicts {
    92  		newMapList := []map[string][]string{}
    93  
    94  		// for each conflict a new list of maps will be created for every already known map
    95  		for _, currentMap := range result {
    96  			newMaps := createDifferentMapsForLeetChar(currentMap, value)
    97  			newMapList = append(newMapList, newMaps...)
    98  		}
    99  
   100  		result = newMapList
   101  	}
   102  
   103  	return result
   104  }
   105  
   106  // This function retrieves the list of values that appear for one or more keys. This is usefull to
   107  // know which l33t chars can represent more than one letter.
   108  func retrieveConflictsListFromTable(table map[string][]string) []string {
   109  	result := []string{}
   110  	foundValues := []string{}
   111  
   112  	for _, values := range table {
   113  		for _, value := range values {
   114  			if stringSliceContainsValue(foundValues, value) {
   115  				// only add on results if it was not identified as conflict before
   116  				if !stringSliceContainsValue(result, value) {
   117  					result = append(result, value)
   118  				}
   119  			} else {
   120  				foundValues = append(foundValues, value)
   121  			}
   122  		}
   123  	}
   124  
   125  	return result
   126  }
   127  
   128  // This function aims to create different maps for a given char if this char represents a conflict.
   129  // If the specified char is not a conflit one, the same map will be returned. In scenarios which
   130  // the provided char can not be found on map, an empty list will be returned. This function was
   131  // designed to be used on conflicts situations.
   132  func createDifferentMapsForLeetChar(table map[string][]string, leetChar string) []map[string][]string {
   133  	result := []map[string][]string{}
   134  
   135  	keysWithSameValue := retrieveListOfKeysWithSpecificValueFromTable(table, leetChar)
   136  	for _, key := range keysWithSameValue {
   137  		newMap := copyMapRemovingSameValueFromOtherKeys(table, key, leetChar)
   138  		result = append(result, newMap)
   139  	}
   140  
   141  	return result
   142  }
   143  
   144  // This function retrieves the list of keys that can be represented using the given value.
   145  func retrieveListOfKeysWithSpecificValueFromTable(table map[string][]string, valueToFind string) []string {
   146  	result := []string{}
   147  
   148  	for key, values := range table {
   149  		for _, value := range values {
   150  			if value == valueToFind && !stringSliceContainsValue(result, key) {
   151  				result = append(result, key)
   152  			}
   153  		}
   154  	}
   155  
   156  	return result
   157  }
   158  
   159  // This function returns a lsit of substitution map from a given table. Each map in the result will
   160  // provide only one representation for each value. As an example, if the provided map contains the
   161  // values "@" and "4" in the possibilities to represent "a", two maps will be created where one
   162  // will contain "a" mapping to "@" and the other one will provide "a" mapping to "4".
   163  func createSubstitutionsMapsFromTable(table map[string][]string) []map[string]string {
   164  	result := []map[string]string{{"": ""}}
   165  
   166  	for key, values := range table {
   167  		newResult := []map[string]string{}
   168  
   169  		for _, mapInCurrentResult := range result {
   170  			for _, value := range values {
   171  				newMapForValue := copyMap(mapInCurrentResult)
   172  				newMapForValue[key] = value
   173  				newResult = append(newResult, newMapForValue)
   174  			}
   175  		}
   176  
   177  		result = newResult
   178  	}
   179  
   180  	// verification to make sure that the slice was filled
   181  	if len(result) == 1 && len(result[0]) == 1 && result[0][""] == "" {
   182  		return []map[string]string{}
   183  	}
   184  
   185  	return result
   186  }
   187  
   188  // This function replaces the values provided on substitution map over the provided word.
   189  func createWordForSubstitutionMap(word string, substitutionMap map[string]string) string {
   190  	result := word
   191  	for key, value := range substitutionMap {
   192  		result = strings.Replace(result, value, key, -1)
   193  	}
   194  
   195  	return result
   196  }
   197  
   198  func stringSliceContainsValue(slice []string, value string) bool {
   199  	for _, valueInSlice := range slice {
   200  		if valueInSlice == value {
   201  			return true
   202  		}
   203  	}
   204  
   205  	return false
   206  }
   207  
   208  func copyMap(table map[string]string) map[string]string {
   209  	result := make(map[string]string)
   210  
   211  	for key, value := range table {
   212  		result[key] = value
   213  	}
   214  
   215  	return result
   216  }
   217  
   218  // This function creates a new map based on the one provided but excluding possible representations
   219  // of the same value on other keys.
   220  func copyMapRemovingSameValueFromOtherKeys(table map[string][]string, keyToFix string, valueToFix string) map[string][]string {
   221  	result := make(map[string][]string)
   222  
   223  	for key, values := range table {
   224  		for _, value := range values {
   225  			if !(value == valueToFix && key != keyToFix) {
   226  				result[key] = append(result[key], value)
   227  			}
   228  		}
   229  	}
   230  
   231  	return result
   232  }