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 }