Skip to content

Commit

Permalink
Merge pull request #161 from nulab/fix-sonarcloud-maintainability-2
Browse files Browse the repository at this point in the history
Fix sonar cloud maintainability phase 2
  • Loading branch information
vvatanabe authored Aug 30, 2023
2 parents 3c53416 + ab9a402 commit a4f95da
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 61 deletions.
14 changes: 7 additions & 7 deletions src/main/java/com/nulabinc/zxcvbn/Pattern.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
package com.nulabinc.zxcvbn;

public enum Pattern {
@SuppressWarnings("squid:S115")
@SuppressWarnings("java:S115")
Bruteforce("bruteforce"),
@SuppressWarnings("squid:S115")
@SuppressWarnings("java:S115")
Dictionary("dictionary"),
@SuppressWarnings("squid:S115")
@SuppressWarnings("java:S115")
Spatial("spatial"),
@SuppressWarnings("squid:S115")
@SuppressWarnings("java:S115")
Repeat("repeat"),
@SuppressWarnings("squid:S115")
@SuppressWarnings("java:S115")
Sequence("sequence"),
@SuppressWarnings("squid:S115")
@SuppressWarnings("java:S115")
Regex("regex"),
@SuppressWarnings("squid:S115")
@SuppressWarnings("java:S115")
Date("date");

private final String value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

public class StandardDictionaries {

@SuppressWarnings("squid:S1075")
@SuppressWarnings("java:S1075")
private static final String BASE_PATH = "/com/nulabinc/zxcvbn/matchers/dictionaries/";

public static final String US_TV_AND_FILM = "us_tv_and_film";
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/nulabinc/zxcvbn/StandardKeyboards.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

public class StandardKeyboards {

@SuppressWarnings("squid:S1075")
@SuppressWarnings("java:S1075")
private static final String RESOURCES_PACKAGE_PATH = "/com/nulabinc/zxcvbn/matchers/keyboards/";

public static final String QWERTY = "qwerty";
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/nulabinc/zxcvbn/WipeableString.java
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ public static int parseInt(CharSequence s) throws NumberFormatException {
}

/** A version of Integer.parse(String) that accepts CharSequence as parameter. */
@SuppressWarnings("squid:S3776")
@SuppressWarnings("java:S3776")
public static int parseInt(CharSequence s, int radix) throws NumberFormatException {
if (s == null) {
throw new NumberFormatException("null");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public InputStream getInputStream() throws IOException {
* available; Next, the ClassLoader that loaded the ResourceLoader class will be used as fallback.
* Finally, if even the system ClassLoader could not access resource as stream, return null.
*/
@SuppressWarnings("squid:S1181")
@SuppressWarnings("java:S1181")
private InputStream getResourceAsStreamWithFallback(String path) {
// Try loading the resource from the same artifact as this class
InputStream in = getClass().getResourceAsStream(path);
Expand Down
127 changes: 77 additions & 50 deletions src/main/java/com/nulabinc/zxcvbn/matchers/DateMatcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ public List<Match> execute(CharSequence password) {
return filterSubMatches(matches);
}

@SuppressWarnings("java:S135")
private void findDatesWithoutSeparator(CharSequence password, List<Match> matches) {
// dates without separators are between length 4 '1191' and 8 '11111991'
for (int startIndex = 0; startIndex <= password.length() - 4; startIndex++) {
Expand Down Expand Up @@ -138,25 +139,23 @@ private List<Dmy> generateDateCandidates(WipeableString token) {
List<Dmy> candidates = new ArrayList<>();
for (int[] date : DATE_SPLITS[token.length()]) {
int[] extractedInts = extractIntsFromToken(token, date);
if (extractedInts != null) {
Dmy dmy = mapIntsToDmy(extractedInts);
if (dmy != null) {
candidates.add(dmy);
}
Dmy dmy = mapIntsToDmy(extractedInts);
if (dmy != null) {
candidates.add(dmy);
}
}
return candidates;
}

private int[] extractIntsFromToken(WipeableString token, int[] date) {
int[] ints = new int[3];
try {
int[] ints = new int[3];
ints[0] = WipeableString.parseInt(token.subSequence(0, date[0]));
ints[1] = WipeableString.parseInt(token.subSequence(date[0], date[1]));
ints[2] = WipeableString.parseInt(token.subSequence(date[1], token.length()));
return ints;
} catch (NumberFormatException e) {
return null;
return new int[] {};
}
}

Expand All @@ -176,52 +175,47 @@ private Dmy selectBestDateCandidate(List<Dmy> candidates) {
private void findDatesWithSeparator(CharSequence password, List<Match> matches) {
// dates with separators are between length 6 '1/1/91' and 10 '11/11/1991'
for (int startIndex = 0; startIndex <= password.length() - 6; startIndex++) {
for (int endIndex = startIndex + 5; endIndex <= startIndex + 9; endIndex++) {
if (endIndex >= password.length()) {
break;
}
for (int endIndex = startIndex + 5;
endIndex <= startIndex + 9 && endIndex < password.length();
endIndex++) {
WipeableString token = WipeableString.copy(password, startIndex, endIndex + 1);
java.util.regex.Matcher rxMatch = MAYBE_DATE_WITH_SEPARATOR.matcher(token);
if (!rxMatch.find()) {
token.wipe();
continue;
}
int[] extractedInts = extractIntsFromMatcher(rxMatch);
if (extractedInts != null) {

if (rxMatch.find()) {
int[] extractedInts = extractIntsFromMatcher(rxMatch);
Dmy dmy = mapIntsToDmy(extractedInts);
if (dmy == null) {
if (dmy != null) {
matches.add(
MatchFactory.createDateMatch(
startIndex, endIndex, token, rxMatch.group(2), dmy.year, dmy.month, dmy.day));
} else {
token.wipe();
continue;
}
matches.add(
MatchFactory.createDateMatch(
startIndex, endIndex, token, rxMatch.group(2), dmy.year, dmy.month, dmy.day));
} else {
token.wipe();
}
}
}
}

private int[] extractIntsFromMatcher(java.util.regex.Matcher matcher) {
int[] ints = new int[3];
try {
int[] ints = new int[3];
ints[0] = WipeableString.parseInt(matcher.group(1));
ints[1] = WipeableString.parseInt(matcher.group(3));
ints[2] = WipeableString.parseInt(matcher.group(4));
return ints;
} catch (NumberFormatException e) {
return null;
return new int[] {};
}
return ints;
}

private List<Match> filterSubMatches(List<Match> matches) {
List<Match> targetMatches = new ArrayList<>();
for (Match match : matches) {
boolean isSubMatch = false;
for (Match otherMatch : matches) {
if (match.equals(otherMatch)) {
continue;
}
if (otherMatch.i <= match.i && otherMatch.j >= match.j) {
if (!match.equals(otherMatch) && otherMatch.i <= match.i && otherMatch.j >= match.j) {
isSubMatch = true;
break;
}
Expand All @@ -238,48 +232,46 @@ private int metric(Dmy candidate) {
}

private Dmy mapIntsToDmy(int[] ints) {
if (ints[1] > 31 || ints[1] <= 0) {
if (ints.length == 0 || ints[1] > 31 || ints[1] <= 0) {
return null;
}
int over12 = 0;
int over31 = 0;
int under1 = 0;

for (int i : ints) {
if ((99 < i && i < DATE_MIN_YEAR) || i > DATE_MAX_YEAR) {
return null;
}
if (i > 31) {
over31 += 1;
}
if (i > 12) {
over12 += 1;
}
if (i <= 0) {
under1 += 1;
}
}
if (over31 >= 2 || over12 == 3 || under1 >= 2) {

ThresholdCounts counts = calculateThresholdCounts(ints);
if (counts.over31 >= 2 || counts.over12 == 3 || counts.under1 >= 2) {
return null;
}

// first look for a four digit year: yyyy + daymonth or daymonth + yyyy
int[][] possibleYearSplits = {
{ints[2], ints[0], ints[1]},
{ints[0], ints[1], ints[2]}
{ints[2], ints[0], ints[1]}, // year last
{ints[0], ints[1], ints[2]} // year first
};

for (int[] split : possibleYearSplits) {
int y = split[0];
int[] rest = new int[] {split[1], split[2]};
if (DATE_MIN_YEAR <= y && y <= DATE_MAX_YEAR) {
Dm dm = mapIntsToDm(rest);
if (isYearInRange(y)) {
Dm dm = mapIntsToDm(new int[] {split[1], split[2]});
if (dm != null) {
return new Dmy(dm.day, dm.month, y);
} else {
// for a candidate that includes a four-digit year,
// when the remaining ints don't match to a day and month,
// it is not a date.
return null;
}
}
}

// given no four-digit year, two digit years are the most flexible int to match, so
// try to parse a day-month out of ints[0..1] or ints[1..0]
for (int[] split : possibleYearSplits) {
int[] rest = new int[] {split[1], split[2]};
Dm dm = mapIntsToDm(rest);
Dm dm = mapIntsToDm(new int[] {split[1], split[2]});
if (dm != null) {
int y = twoToFourDigitYear(split[0]);
return new Dmy(dm.day, dm.month, y);
Expand All @@ -288,6 +280,28 @@ private Dmy mapIntsToDmy(int[] ints) {
return null;
}

private ThresholdCounts calculateThresholdCounts(int[] ints) {
int over12 = 0;
int over31 = 0;
int under1 = 0;
for (int i : ints) {
if (i > 31) {
over31 += 1;
}
if (i > 12) {
over12 += 1;
}
if (i <= 0) {
under1 += 1;
}
}
return new ThresholdCounts(over31, over12, under1);
}

private boolean isYearInRange(int year) {
return DATE_MIN_YEAR <= year && year <= DATE_MAX_YEAR;
}

private Dm mapIntsToDm(int[] ints) {
int[] copy = Arrays.copyOf(ints, ints.length);
reverse(copy);
Expand Down Expand Up @@ -339,4 +353,17 @@ public Dmy(int day, int month, int year) {
this.year = year;
}
}

private static class ThresholdCounts {

int over31;
int over12;
int under1;

ThresholdCounts(int over31, int over12, int under1) {
this.over31 = over31;
this.over12 = over12;
this.under1 = under1;
}
}
}

0 comments on commit a4f95da

Please sign in to comment.