fmt: proper use of lower case to have consistent warning messages
[gigi.git] / src / club / wpia / gigi / passwords / PasswordStrengthChecker.java
1 package club.wpia.gigi.passwords;
2
3 import java.util.Arrays;
4 import java.util.regex.Pattern;
5
6 import club.wpia.gigi.GigiApiException;
7 import club.wpia.gigi.output.template.SprintfCommand;
8
9 public class PasswordStrengthChecker implements PasswordChecker {
10
11     private static Pattern digits = Pattern.compile("\\d");
12
13     private static Pattern lower = Pattern.compile("[a-z]");
14
15     private static Pattern upper = Pattern.compile("[A-Z]");
16
17     private static Pattern whitespace = Pattern.compile("\\s");
18
19     private static Pattern special = Pattern.compile("(?!\\s)\\W");
20
21     public PasswordStrengthChecker() {}
22
23     /**
24      * @param pw The password.
25      * @return Estimate of the password’s strength (positive).
26      */
27     private int ratePasswordStrength(String pw) {
28         int points = 0;
29         if (pw.length() > 15) {
30             points++;
31         }
32         if (pw.length() > 20) {
33             points++;
34         }
35         if (pw.length() > 25) {
36             points++;
37         }
38         if (pw.length() > 30) {
39             points++;
40         }
41         if (digits.matcher(pw).find()) {
42             points++;
43         }
44         if (lower.matcher(pw).find()) {
45             points++;
46         }
47         if (upper.matcher(pw).find()) {
48             points++;
49         }
50         if (special.matcher(pw).find()) {
51             points++;
52         }
53         if (whitespace.matcher(pw).find()) {
54             points++;
55         }
56         return points;
57     }
58
59     /**
60      * @param pw The password.
61      * @param nameParts The name parts of the user.
62      * @param email The email address of the user.
63      * @return Estimate of the password’s weakness (negative).
64      */
65     private int ratePasswordWeakness(String pw, String[] nameParts, String email) {
66         int points = 0;
67         if (contained(pw, email)) {
68             points -= 2;
69         }
70         for (int i = 0; i < nameParts.length; i++) {
71             if (contained(pw, nameParts[i])) {
72                 points -= 2;
73             }
74         }
75         return points;
76     }
77
78     public int ratePassword(String pw, String[] nameParts, String email) {
79         return ratePasswordStrength(pw) + ratePasswordWeakness(pw, nameParts, email);
80     }
81
82     @Override
83     public GigiApiException checkPassword(String password, String[] nameParts, String email) {
84         int points = ratePassword(password, nameParts, email);
85         if (points < 3) {
86             return new GigiApiException(new SprintfCommand(
87                 "The password you submitted failed to contain enough differing characters and/or contained words from your name and/or email address. For the current requirements and to learn more, visit our {0}FAQ{1}.",
88                 Arrays.asList("!(/kb/goodPassword", "!'</a>'")
89             ));
90         } else {
91             return null;
92         }
93     }
94
95     private static boolean contained(String pw, String check) {
96         if (check == null || check.equals("")) {
97             return false;
98         }
99         if (pw.contains(check)) {
100             return true;
101         }
102         if (check.contains(pw)) {
103             return true;
104         }
105         return false;
106     }
107
108 }