1 | scoring = require('./scoring')
|
2 |
|
3 | feedback =
|
4 | default_feedback:
|
5 | warning: ''
|
6 | suggestions: [
|
7 | "Use a few words, avoid common phrases"
|
8 | "No need for symbols, digits, or uppercase letters"
|
9 | ]
|
10 |
|
11 | get_feedback: (score, sequence) ->
|
12 |
|
13 | return @default_feedback if sequence.length == 0
|
14 |
|
15 |
|
16 | return if score > 2
|
17 | warning: ''
|
18 | suggestions: []
|
19 |
|
20 |
|
21 | longest_match = sequence[0]
|
22 | for match in sequence[1..]
|
23 | longest_match = match if match.token.length > longest_match.token.length
|
24 | feedback = @get_match_feedback(longest_match, sequence.length == 1)
|
25 | extra_feedback = 'Add another word or two. Uncommon words are better.'
|
26 | if feedback?
|
27 | feedback.suggestions.unshift extra_feedback
|
28 | feedback.warning = '' unless feedback.warning?
|
29 | else
|
30 | feedback =
|
31 | warning: ''
|
32 | suggestions: [extra_feedback]
|
33 | feedback
|
34 |
|
35 | get_match_feedback: (match, is_sole_match) ->
|
36 | switch match.pattern
|
37 | when 'dictionary'
|
38 | @get_dictionary_match_feedback match, is_sole_match
|
39 |
|
40 | when 'spatial'
|
41 | layout = match.graph.toUpperCase()
|
42 | warning = if match.turns == 1
|
43 | 'Straight rows of keys are easy to guess'
|
44 | else
|
45 | 'Short keyboard patterns are easy to guess'
|
46 | warning: warning
|
47 | suggestions: [
|
48 | 'Use a longer keyboard pattern with more turns'
|
49 | ]
|
50 |
|
51 | when 'repeat'
|
52 | warning = if match.base_token.length == 1
|
53 | 'Repeats like "aaa" are easy to guess'
|
54 | else
|
55 | 'Repeats like "abcabcabc" are only slightly harder to guess than "abc"'
|
56 | warning: warning
|
57 | suggestions: [
|
58 | 'Avoid repeated words and characters'
|
59 | ]
|
60 |
|
61 | when 'sequence'
|
62 | warning: "Sequences like abc or 6543 are easy to guess"
|
63 | suggestions: [
|
64 | 'Avoid sequences'
|
65 | ]
|
66 |
|
67 | when 'regex'
|
68 | if match.regex_name == 'recent_year'
|
69 | warning: "Recent years are easy to guess"
|
70 | suggestions: [
|
71 | 'Avoid recent years'
|
72 | 'Avoid years that are associated with you'
|
73 | ]
|
74 |
|
75 | when 'date'
|
76 | warning: "Dates are often easy to guess"
|
77 | suggestions: [
|
78 | 'Avoid dates and years that are associated with you'
|
79 | ]
|
80 |
|
81 | get_dictionary_match_feedback: (match, is_sole_match) ->
|
82 | warning = if match.dictionary_name == 'passwords'
|
83 | if is_sole_match and not match.l33t and not match.reversed
|
84 | if match.rank <= 10
|
85 | 'This is a top-10 common password'
|
86 | else if match.rank <= 100
|
87 | 'This is a top-100 common password'
|
88 | else
|
89 | 'This is a very common password'
|
90 | else if match.guesses_log10 <= 4
|
91 | 'This is similar to a commonly used password'
|
92 | else if match.dictionary_name == 'english'
|
93 | if is_sole_match
|
94 | 'A word by itself is easy to guess'
|
95 | else if match.dictionary_name in ['surnames', 'male_names', 'female_names']
|
96 | if is_sole_match
|
97 | 'Names and surnames by themselves are easy to guess'
|
98 | else
|
99 | 'Common names and surnames are easy to guess'
|
100 | else
|
101 | ''
|
102 |
|
103 | suggestions = []
|
104 | word = match.token
|
105 | if word.match(scoring.START_UPPER)
|
106 | suggestions.push "Capitalization doesn't help very much"
|
107 | else if word.match(scoring.ALL_UPPER)
|
108 | suggestions.push "All-uppercase is almost as easy to guess as all-lowercase"
|
109 |
|
110 | if match.reversed and match.token.length >= 4
|
111 | suggestions.push "Reversed words aren't much harder to guess"
|
112 | if match.l33t
|
113 | suggestions.push "Predictable substitutions like '@' instead of 'a' don't help very much"
|
114 |
|
115 | result =
|
116 | warning: warning
|
117 | suggestions: suggestions
|
118 | result
|
119 |
|
120 | module.exports = feedback
|