diff --git a/match/match.go b/match/match.go index b79129f..0523943 100644 --- a/match/match.go +++ b/match/match.go @@ -33,3 +33,8 @@ type DateMatch struct { Separator string Day, Month, Year int64 } + +type Matcher struct { + MatchingFunc func(password string) []Match + ID string +} diff --git a/matching/dateMatchers.go b/matching/dateMatchers.go index dc5c7ac..e55b3da 100644 --- a/matching/dateMatchers.go +++ b/matching/dateMatchers.go @@ -1,13 +1,27 @@ package matching import ( - "github.com/nbutton23/zxcvbn-go/entropy" - "github.com/nbutton23/zxcvbn-go/match" "regexp" "strconv" "strings" + + "github.com/nbutton23/zxcvbn-go/entropy" + "github.com/nbutton23/zxcvbn-go/match" ) +const ( + DATESEP_MATCHER_NAME = "DATESEP" + DATEWITHOUTSEP_MATCHER_NAME = "DATEWITHOUT" +) + +func FilterDateSepMatcher(m match.Matcher) bool { + return m.ID == DATESEP_MATCHER_NAME +} + +func FilterDateWithoutSepMatcher(m match.Matcher) bool { + return m.ID == DATEWITHOUTSEP_MATCHER_NAME +} + func checkDate(day, month, year int64) (bool, int64, int64, int64) { if (12 <= month && month <= 31) && day <= 12 { day, month = month, day @@ -23,6 +37,7 @@ func checkDate(day, month, year int64) (bool, int64, int64, int64) { return true, day, month, year } + func dateSepMatcher(password string) []match.Match { dateMatches := dateSepMatchHelper(password) diff --git a/matching/leet.go b/matching/leet.go index 29700e8..7185744 100644 --- a/matching/leet.go +++ b/matching/leet.go @@ -1,11 +1,18 @@ package matching import ( + "strings" + "github.com/nbutton23/zxcvbn-go/entropy" "github.com/nbutton23/zxcvbn-go/match" - "strings" ) +const L33T_MATCHER_NAME = "l33t" + +func FilterL33tMatcher(m match.Matcher) bool { + return m.ID == L33T_MATCHER_NAME +} + func l33tMatch(password string) []match.Match { substitutions := relevantL33tSubtable(password) @@ -16,7 +23,7 @@ func l33tMatch(password string) []match.Match { for _, permutation := range permutations { for _, mather := range DICTIONARY_MATCHERS { - matches = append(matches, mather(permutation)...) + matches = append(matches, mather.MatchingFunc(permutation)...) } } diff --git a/matching/matching.go b/matching/matching.go index 024a284..70f1631 100644 --- a/matching/matching.go +++ b/matching/matching.go @@ -1,15 +1,16 @@ package matching import ( + "sort" + "github.com/nbutton23/zxcvbn-go/adjacency" "github.com/nbutton23/zxcvbn-go/frequency" "github.com/nbutton23/zxcvbn-go/match" - "sort" ) var ( - DICTIONARY_MATCHERS []func(password string) []match.Match - MATCHERS []func(password string) []match.Match + DICTIONARY_MATCHERS []match.Matcher + MATCHERS []match.Matcher ADJACENCY_GRAPHS []adjacency.AdjacencyGraph L33T_TABLE adjacency.AdjacencyGraph @@ -26,7 +27,7 @@ func init() { loadFrequencyList() } -func Omnimatch(password string, userInputs []string) (matches []match.Match) { +func Omnimatch(password string, userInputs []string, filters ...func(match.Matcher) bool) (matches []match.Match) { //Can I run into the issue where nil is not equal to nil? if DICTIONARY_MATCHERS == nil || ADJACENCY_GRAPHS == nil { @@ -39,7 +40,16 @@ func Omnimatch(password string, userInputs []string) (matches []match.Match) { } for _, matcher := range MATCHERS { - matches = append(matches, matcher(password)...) + shouldBeFiltered := false + for i := range filters { + if filters[i](matcher) { + shouldBeFiltered = true + break + } + } + if !shouldBeFiltered { + matches = append(matches, matcher.MatchingFunc(password)...) + } } sort.Sort(match.Matches(matches)) return matches @@ -48,7 +58,7 @@ func Omnimatch(password string, userInputs []string) (matches []match.Match) { func loadFrequencyList() { for n, list := range frequency.FrequencyLists { - DICTIONARY_MATCHERS = append(DICTIONARY_MATCHERS, buildDictMatcher(n, buildRankedDict(list.List))) + DICTIONARY_MATCHERS = append(DICTIONARY_MATCHERS, match.Matcher{MatchingFunc: buildDictMatcher(n, buildRankedDict(list.List)), ID: n}) } L33T_TABLE = adjacency.AdjacencyGph["l33t"] @@ -67,11 +77,11 @@ func loadFrequencyList() { SEQUENCES["digits"] = "0123456789" MATCHERS = append(MATCHERS, DICTIONARY_MATCHERS...) - MATCHERS = append(MATCHERS, spatialMatch) - MATCHERS = append(MATCHERS, repeatMatch) - MATCHERS = append(MATCHERS, sequenceMatch) - MATCHERS = append(MATCHERS, l33tMatch) - MATCHERS = append(MATCHERS, dateSepMatcher) - MATCHERS = append(MATCHERS, dateWithoutSepMatch) + MATCHERS = append(MATCHERS, match.Matcher{MatchingFunc: spatialMatch, ID: SPATIAL_MATCHER_NAME}) + MATCHERS = append(MATCHERS, match.Matcher{MatchingFunc: repeatMatch, ID: REPEAT_MATCHER_NAME}) + MATCHERS = append(MATCHERS, match.Matcher{MatchingFunc: sequenceMatch, ID: SEQUENCE_MATCHER_NAME}) + MATCHERS = append(MATCHERS, match.Matcher{MatchingFunc: l33tMatch, ID: L33T_MATCHER_NAME}) + MATCHERS = append(MATCHERS, match.Matcher{MatchingFunc: dateSepMatcher, ID: DATESEP_MATCHER_NAME}) + MATCHERS = append(MATCHERS, match.Matcher{MatchingFunc: dateWithoutSepMatch, ID: DATEWITHOUTSEP_MATCHER_NAME}) } diff --git a/matching/repeatMatch.go b/matching/repeatMatch.go index eed7186..97bd33b 100644 --- a/matching/repeatMatch.go +++ b/matching/repeatMatch.go @@ -1,11 +1,18 @@ package matching import ( + "strings" + "github.com/nbutton23/zxcvbn-go/entropy" "github.com/nbutton23/zxcvbn-go/match" - "strings" ) +const REPEAT_MATCHER_NAME = "REPEAT" + +func FilterRepeatMatcher(m match.Matcher) bool { + return m.ID == REPEAT_MATCHER_NAME +} + func repeatMatch(password string) []match.Match { var matches []match.Match diff --git a/matching/sequenceMatch.go b/matching/sequenceMatch.go index f75aebf..89f1526 100644 --- a/matching/sequenceMatch.go +++ b/matching/sequenceMatch.go @@ -1,11 +1,18 @@ package matching import ( + "strings" + "github.com/nbutton23/zxcvbn-go/entropy" "github.com/nbutton23/zxcvbn-go/match" - "strings" ) +const SEQUENCE_MATCHER_NAME = "SEQ" + +func FilterSequenceMatcher(m match.Matcher) bool { + return m.ID == SEQUENCE_MATCHER_NAME +} + func sequenceMatch(password string) []match.Match { var matches []match.Match for i := 0; i < len(password); { diff --git a/matching/spatialMatch.go b/matching/spatialMatch.go index e2db0f3..145cfb8 100644 --- a/matching/spatialMatch.go +++ b/matching/spatialMatch.go @@ -1,12 +1,19 @@ package matching import ( + "strings" + "github.com/nbutton23/zxcvbn-go/adjacency" "github.com/nbutton23/zxcvbn-go/entropy" "github.com/nbutton23/zxcvbn-go/match" - "strings" ) +const SPATIAL_MATCHER_NAME = "SPATIAL" + +func FilterSpatialMatcher(m match.Matcher) bool { + return m.ID == SPATIAL_MATCHER_NAME +} + func spatialMatch(password string) (matches []match.Match) { for _, graph := range ADJACENCY_GRAPHS { if graph.Graph != nil { diff --git a/zxcvbn.go b/zxcvbn.go index 510fe96..086270c 100644 --- a/zxcvbn.go +++ b/zxcvbn.go @@ -1,15 +1,17 @@ package zxcvbn import ( + "time" + + "github.com/nbutton23/zxcvbn-go/match" "github.com/nbutton23/zxcvbn-go/matching" "github.com/nbutton23/zxcvbn-go/scoring" "github.com/nbutton23/zxcvbn-go/utils/math" - "time" ) -func PasswordStrength(password string, userInputs []string) scoring.MinEntropyMatch { +func PasswordStrength(password string, userInputs []string, filters ...func(match.Matcher) bool) scoring.MinEntropyMatch { start := time.Now() - matches := matching.Omnimatch(password, userInputs) + matches := matching.Omnimatch(password, userInputs, filters...) result := scoring.MinimumEntropyMatchSequence(password, matches) end := time.Now()