lib/zxcvbn/matching.rb in zxcvbn-0.1.8 vs lib/zxcvbn/matching.rb in zxcvbn-0.1.9
- old
+ new
@@ -13,10 +13,14 @@
RANKED_DICTIONARIES = FREQUENCY_LISTS.transform_values do |lst|
build_ranked_dict(lst)
end
+ RANKED_DICTIONARIES_MAX_WORD_SIZE = RANKED_DICTIONARIES.transform_values do |word_scores|
+ word_scores.keys.max_by(&:size).size
+ end
+
GRAPHS = {
"qwerty" => ADJACENCY_GRAPHS["qwerty"],
"dvorak" => ADJACENCY_GRAPHS["dvorak"],
"keypad" => ADJACENCY_GRAPHS["keypad"],
"mac_keypad" => ADJACENCY_GRAPHS["mac_keypad"]
@@ -149,12 +153,17 @@
# _ranked_dictionaries variable is for unit testing purposes
matches = []
len = password.length
password_lower = password.downcase
_ranked_dictionaries.each do |dictionary_name, ranked_dict|
+ longest_dict_word_size = RANKED_DICTIONARIES_MAX_WORD_SIZE.fetch(dictionary_name) do
+ ranked_dict.keys.max_by(&:size)&.size || 0
+ end
+ search_width = [longest_dict_word_size, len].min
(0...len).each do |i|
- (i...len).each do |j|
+ search_end = [i + search_width, len].min
+ (i...search_end).each do |j|
if ranked_dict.key?(password_lower[i..j])
word = password_lower[i..j]
rank = ranked_dict[word]
matches << {
"pattern" => "dictionary",
@@ -185,10 +194,12 @@
end
sorted(matches)
end
def self.user_input_dictionary=(ordered_list)
- RANKED_DICTIONARIES["user_inputs"] = build_ranked_dict(ordered_list.dup)
+ ranked_dict = build_ranked_dict(ordered_list.dup)
+ RANKED_DICTIONARIES["user_inputs"] = ranked_dict
+ RANKED_DICTIONARIES_MAX_WORD_SIZE["user_inputs"] = ranked_dict.keys.max_by(&:size)&.size || 0
end
#-------------------------------------------------------------------------------
# dictionary match with common l33t substitutions ------------------------------
#-------------------------------------------------------------------------------