From 44dda11f3b7defa3b3d81b99d73316fc53fcd86e Mon Sep 17 00:00:00 2001 From: vvatanabe Date: Mon, 21 Aug 2023 14:35:34 +0900 Subject: [PATCH] fix: fix the discrepancy in password guesses between zxcvbn and zxcvbn4j (#105) --- src/main/java/com/nulabinc/zxcvbn/Guess.java | 3 +- .../nulabinc/zxcvbn/matchers/DateMatcher.java | 20 ++++---- .../com/nulabinc/zxcvbn/JavaPortTest.java | 2 + .../com/nulabinc/zxcvbn/MatchingTest.java | 7 +++ .../java/com/nulabinc/zxcvbn/ScoringTest.java | 48 +++++++++++++++++++ 5 files changed, 69 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/nulabinc/zxcvbn/Guess.java b/src/main/java/com/nulabinc/zxcvbn/Guess.java index 1e66cd2..1d78fc5 100644 --- a/src/main/java/com/nulabinc/zxcvbn/Guess.java +++ b/src/main/java/com/nulabinc/zxcvbn/Guess.java @@ -1,6 +1,7 @@ package com.nulabinc.zxcvbn; import com.nulabinc.zxcvbn.matchers.Match; +import java.util.Calendar; public interface Guess { @@ -8,7 +9,7 @@ public interface Guess { public static final int MIN_SUBMATCH_GUESSES_SINGLE_CHAR = 10; public static final int MIN_SUBMATCH_GUESSES_MULTI_CHAR = 50; public static final int MIN_YEAR_SPACE = 20; - public static final int REFERENCE_YEAR = 2000; + public static final int REFERENCE_YEAR = Calendar.getInstance().get(Calendar.YEAR); public double exec(Match match); } diff --git a/src/main/java/com/nulabinc/zxcvbn/matchers/DateMatcher.java b/src/main/java/com/nulabinc/zxcvbn/matchers/DateMatcher.java index aa01eb2..b1aef05 100644 --- a/src/main/java/com/nulabinc/zxcvbn/matchers/DateMatcher.java +++ b/src/main/java/com/nulabinc/zxcvbn/matchers/DateMatcher.java @@ -259,12 +259,13 @@ private Dmy mapIntsToDmy(int[] ints) { if (over31 >= 2 || over12 == 3 || under1 >= 2) { return null; } - Map possibleYearSplits = new HashMap<>(); - possibleYearSplits.put(ints[2], Arrays.copyOfRange(ints, 0, 1 + 1)); - possibleYearSplits.put(ints[0], Arrays.copyOfRange(ints, 1, 2 + 1)); - for (Map.Entry possibleYearSplitRef : possibleYearSplits.entrySet()) { - int y = possibleYearSplitRef.getKey(); - int[] rest = possibleYearSplitRef.getValue(); + int[][] possibleYearSplits = { + {ints[2], ints[0], ints[1]}, + {ints[0], ints[1], ints[2]} + }; + 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 (dm != null) { @@ -274,12 +275,11 @@ private Dmy mapIntsToDmy(int[] ints) { } } } - for (Map.Entry possibleYearSplitRef : possibleYearSplits.entrySet()) { - int y = possibleYearSplitRef.getKey(); - int[] rest = possibleYearSplitRef.getValue(); + for (int[] split : possibleYearSplits) { + int[] rest = new int[] {split[1], split[2]}; Dm dm = mapIntsToDm(rest); if (dm != null) { - y = twoToFourDigitYear(y); + int y = twoToFourDigitYear(split[0]); return new Dmy(dm.day, dm.month, y); } } diff --git a/src/test/java/com/nulabinc/zxcvbn/JavaPortTest.java b/src/test/java/com/nulabinc/zxcvbn/JavaPortTest.java index 0cdc3d6..8d49fb4 100644 --- a/src/test/java/com/nulabinc/zxcvbn/JavaPortTest.java +++ b/src/test/java/com/nulabinc/zxcvbn/JavaPortTest.java @@ -92,6 +92,8 @@ public static Iterable data() { {"password@123"}, {"lkjhgfdsa"}, {"hGFd"}, + {"2352523452bd dhf"}, + {"23525"}, // the following password fails in version 4.4.1 // https://github.com/dropbox/zxcvbn/issues/174 // diff --git a/src/test/java/com/nulabinc/zxcvbn/MatchingTest.java b/src/test/java/com/nulabinc/zxcvbn/MatchingTest.java index 491d720..79464d3 100644 --- a/src/test/java/com/nulabinc/zxcvbn/MatchingTest.java +++ b/src/test/java/com/nulabinc/zxcvbn/MatchingTest.java @@ -437,6 +437,13 @@ public static Collection data() { new ExpectedMatch("111504").separator("").year(2004).month(11).day(15) }); + data.add( + new Object[] { + "23525", + "matches as 23/5/2025, not 25/5/2023", + new ExpectedMatch("23525").separator("").year(2025).month(5).day(23) + }); + return data; } } diff --git a/src/test/java/com/nulabinc/zxcvbn/ScoringTest.java b/src/test/java/com/nulabinc/zxcvbn/ScoringTest.java index 5d5bf98..e66ff48 100644 --- a/src/test/java/com/nulabinc/zxcvbn/ScoringTest.java +++ b/src/test/java/com/nulabinc/zxcvbn/ScoringTest.java @@ -398,4 +398,52 @@ public void testL33tVariants() throws Exception { 0.0); } } + + @RunWith(Parameterized.class) + public static class DateGuessTest { + + private final String token; + private final int i; + private final int j; + private final String separator; + private final int year; + private final int month; + private final int day; + private final double expectedGuesses; + + public DateGuessTest( + String token, + int i, + int j, + String separator, + int year, + int month, + int day, + double expectedGuesses) { + this.token = token; + this.i = i; + this.j = j; + this.separator = separator; + this.year = year; + this.month = month; + this.day = day; + this.expectedGuesses = expectedGuesses; + } + + @Test + public void testDateGuess() throws Exception { + Context context = StandardContext.build(); + Match match = MatchFactory.createDateMatch(i, j, token, separator, year, month, day); + String msg = String.format("the date pattern '%s' has guesses of %s", token, expectedGuesses); + assertEquals(msg, expectedGuesses, new DateGuess(context).exec(match), 0.0); + } + + @Parameterized.Parameters(name = "{0}") + public static Collection data() { + return Arrays.asList( + new Object[][] { + {"23525", 0, 4, "", 2025, 5, 23, 7300.0}, + }); + } + } }