Merge pull request #9 from nbutton23/button-wip

Fixed the spatial match issue. Added more test
This commit is contained in:
Nathan Button 2016-01-19 12:00:56 -07:00
commit ad6ec61db4
14 changed files with 114 additions and 32 deletions

View File

@ -92,7 +92,7 @@ func dataDvorakJson() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "data/Dvorak.json", size: 8398, mode: os.FileMode(420), modTime: time.Unix(1444169890, 0)}
info := bindataFileInfo{name: "data/Dvorak.json", size: 8398, mode: os.FileMode(420), modTime: time.Unix(1452717629, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -112,7 +112,7 @@ func dataEnglishJson() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "data/English.json", size: 341560, mode: os.FileMode(420), modTime: time.Unix(1444169890, 0)}
info := bindataFileInfo{name: "data/English.json", size: 341560, mode: os.FileMode(420), modTime: time.Unix(1452717629, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -132,7 +132,7 @@ func dataFemalenamesJson() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "data/FemaleNames.json", size: 53909, mode: os.FileMode(420), modTime: time.Unix(1444169890, 0)}
info := bindataFileInfo{name: "data/FemaleNames.json", size: 53909, mode: os.FileMode(420), modTime: time.Unix(1452717629, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -152,7 +152,7 @@ func dataKeypadJson() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "data/Keypad.json", size: 1639, mode: os.FileMode(420), modTime: time.Unix(1444169890, 0)}
info := bindataFileInfo{name: "data/Keypad.json", size: 1639, mode: os.FileMode(420), modTime: time.Unix(1452717629, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -172,7 +172,7 @@ func dataL33tJson() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "data/L33t.json", size: 477, mode: os.FileMode(420), modTime: time.Unix(1444170193, 0)}
info := bindataFileInfo{name: "data/L33t.json", size: 477, mode: os.FileMode(420), modTime: time.Unix(1452717629, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -192,7 +192,7 @@ func dataMackeypadJson() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "data/MacKeypad.json", size: 1744, mode: os.FileMode(420), modTime: time.Unix(1444169890, 0)}
info := bindataFileInfo{name: "data/MacKeypad.json", size: 1744, mode: os.FileMode(420), modTime: time.Unix(1452717629, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -212,7 +212,7 @@ func dataMalenamesJson() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "data/MaleNames.json", size: 11791, mode: os.FileMode(420), modTime: time.Unix(1444169890, 0)}
info := bindataFileInfo{name: "data/MaleNames.json", size: 11791, mode: os.FileMode(420), modTime: time.Unix(1452717629, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -232,7 +232,7 @@ func dataPasswordsJson() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "data/Passwords.json", size: 67534, mode: os.FileMode(420), modTime: time.Unix(1444169890, 0)}
info := bindataFileInfo{name: "data/Passwords.json", size: 67534, mode: os.FileMode(420), modTime: time.Unix(1452717629, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -252,7 +252,7 @@ func dataQwertyJson() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "data/Qwerty.json", size: 8398, mode: os.FileMode(420), modTime: time.Unix(1444169890, 0)}
info := bindataFileInfo{name: "data/Qwerty.json", size: 8398, mode: os.FileMode(420), modTime: time.Unix(1452717629, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -272,7 +272,7 @@ func dataSurnamesJson() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "data/Surnames.json", size: 396413, mode: os.FileMode(420), modTime: time.Unix(1444169890, 0)}
info := bindataFileInfo{name: "data/Surnames.json", size: 396413, mode: os.FileMode(420), modTime: time.Unix(1452717629, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}

View File

@ -65,13 +65,13 @@ func loadFrequencyList() {
KEYPAD_AVG_DEGREE = adjacency.AdjacencyGph["keypad"].CalculateAvgDegree()
KEYPAD_STARTING_POSITIONS = len(adjacency.AdjacencyGph["keypad"].Graph)
ADJACENCY_GRAPHS = append(ADJACENCY_GRAPHS, adjacency.AdjacencyGph["querty"])
ADJACENCY_GRAPHS = append(ADJACENCY_GRAPHS, adjacency.AdjacencyGph["qwerty"])
ADJACENCY_GRAPHS = append(ADJACENCY_GRAPHS, adjacency.AdjacencyGph["dvorak"])
ADJACENCY_GRAPHS = append(ADJACENCY_GRAPHS, adjacency.AdjacencyGph["keypad"])
ADJACENCY_GRAPHS = append(ADJACENCY_GRAPHS, adjacency.AdjacencyGph["macKeypad"])
//
// l33tFilePath, _ := filepath.Abs("adjacency/L33t.json")
// L33T_TABLE = adjacency.GetAdjancencyGraphFromFile(l33tFilePath, "l33t")
//l33tFilePath, _ := filepath.Abs("adjacency/L33t.json")
//L33T_TABLE = adjacency.GetAdjancencyGraphFromFile(l33tFilePath, "l33t")
SEQUENCES = make(map[string]string)
SEQUENCES["lower"] = "abcdefghijklmnopqrstuvwxyz"
@ -79,8 +79,8 @@ func loadFrequencyList() {
SEQUENCES["digits"] = "0123456789"
MATCHERS = append(MATCHERS, DICTIONARY_MATCHERS...)
MATCHERS = append(MATCHERS, spatialMatch)
MATCHERS = append(MATCHERS, repeatMatch)
MATCHERS = append(MATCHERS, SpatialMatch)
MATCHERS = append(MATCHERS, RepeatMatch)
MATCHERS = append(MATCHERS, SequenceMatch)
}
@ -244,17 +244,22 @@ func buildDateMatchCandidateTwo(day, month byte, year string, i, j int) match.Da
return match.DateMatch{Day: intDay, Month: intMonth, Year: intYear, I: i, J: j}
}
func spatialMatch(password string) (matches []match.Match) {
//TODO: This is not working.
//It appears that the Adjacency graph data is incorrect. Need to get a new copy from python-zxcvbn.
func SpatialMatch(password string) (matches []match.Match) {
for _, graph := range ADJACENCY_GRAPHS {
matches = append(matches, spatialMatchHelper(password, graph)...)
if graph.Graph != nil {
matches = append(matches, spatialMatchHelper(password, graph)...)
}
}
return matches
}
func spatialMatchHelper(password string, graph adjacency.AdjacencyGraph) (matches []match.Match) {
for i := 0; i < len(password)-1; {
j := i + 1
lastDirection := -99 //and int that it should never be!
lastDirection := -99 //an int that it should never be!
turns := 0
shiftedCount := 0
@ -263,8 +268,9 @@ func spatialMatchHelper(password string, graph adjacency.AdjacencyGraph) (matche
found := false
foundDirection := -1
curDirection := -1
//My graphs seem to be wrong. . . and where the hell is qwerty
adjacents := graph.Graph[string(prevChar)]
// Consider growing pattern by one character if j hasn't gone over the edge
//Consider growing pattern by one character if j hasn't gone over the edge
if j < len(password) {
curChar := password[j]
for _, adj := range adjacents {
@ -275,15 +281,14 @@ func spatialMatchHelper(password string, graph adjacency.AdjacencyGraph) (matche
foundDirection = curDirection
if strings.Index(adj, string(curChar)) == 1 {
// index 1 in the adjacency means the key is shifted, 0 means unshifted: A vs a, % vs 5, etc.
// for example, 'q' is adjacent to the entry '2@'. @ is shifted w/ index 1, 2 is unshifted.
//index 1 in the adjacency means the key is shifted, 0 means unshifted: A vs a, % vs 5, etc.
//for example, 'q' is adjacent to the entry '2@'. @ is shifted w/ index 1, 2 is unshifted.
shiftedCount += 1
}
if lastDirection != foundDirection {
// adding a turn is correct even in the initial case when last_direction is null:
// every spatial pattern starts with a turn.
//adding a turn is correct even in the initial case when last_direction is null:
//every spatial pattern starts with a turn.
turns += 1
lastDirection = foundDirection
}
@ -292,16 +297,16 @@ func spatialMatchHelper(password string, graph adjacency.AdjacencyGraph) (matche
}
}
// if the current pattern continued, extend j and try to grow again
//if the current pattern continued, extend j and try to grow again
if found {
j += 1
} else {
// otherwise push the pattern discovered so far, if any...
// don't consider length 1 or 2 chains.
//otherwise push the pattern discovered so far, if any...
//don't consider length 1 or 2 chains.
if j-i > 2 {
matches = append(matches, match.Match{Pattern: "spatial", I: i, J: j - 1, Token: password[i:j], DictionaryName: graph.Name, Turns: turns, ShiftedCount: shiftedCount})
}
// . . . and then start a new search from the rest of the password
//. . . and then start a new search from the rest of the password
i = j
break
}
@ -340,7 +345,7 @@ func relevantL33tSubtable(password string) adjacency.AdjacencyGraph {
// }
//}
func repeatMatch(password string) []match.Match {
func RepeatMatch(password string) []match.Match {
var matches []match.Match
//Loop through password. if current == prev currentStreak++ else if currentStreak > 2 {buildMatch; currentStreak = 1} prev = current
@ -355,7 +360,7 @@ func repeatMatch(password string) []match.Match {
continue
}
if current == prev {
if strings.ToLower(current) == strings.ToLower(prev) {
currentStreak++
} else if currentStreak > 2 {

View File

@ -2,6 +2,8 @@ package matching
import (
"github.com/nbutton23/zxcvbn-go/Godeps/_workspace/src/github.com/stretchr/testify/assert"
"github.com/nbutton23/zxcvbn-go/match"
"strings"
"testing"
)
@ -30,3 +32,78 @@ func TestDateSepMatch(t *testing.T) {
}
}
func TestRepeatMatch(t *testing.T) {
//aaaBbBb
matches := RepeatMatch("aaabBbB")
assert.Len(t, matches, 2, "Lenght should be 2")
for _, match := range matches {
if strings.ToLower(match.RepeatedChar) == "b" {
assert.Equal(t, 3, match.I)
assert.Equal(t, 6, match.J)
assert.Equal(t, "bBbB", match.Token)
} else {
assert.Equal(t, 0, match.I)
assert.Equal(t, 2, match.J)
assert.Equal(t, "aaa", match.Token)
}
}
}
func TestSequenceMatch(t *testing.T) {
//abcdjibjacLMNOPjibjac1234 => abcd LMNOP 1234
matches := SequenceMatch("abcdjibjacLMNOPjibjac1234")
assert.Len(t, matches, 3, "Lenght should be 2")
for _, match := range matches {
if match.DictionaryName == "lower" {
assert.Equal(t, 0, match.I)
assert.Equal(t, 3, match.J)
assert.Equal(t, "abcd", match.Token)
} else if match.DictionaryName == "upper" {
assert.Equal(t, 10, match.I)
assert.Equal(t, 14, match.J)
assert.Equal(t, "LMNOP", match.Token)
} else if match.DictionaryName == "digits" {
assert.Equal(t, 21, match.I)
assert.Equal(t, 24, match.J)
assert.Equal(t, "1234", match.Token)
} else {
assert.True(t, false, "Unknow dictionary")
}
}
}
func TestSpatialMatchQwerty(t *testing.T) {
matches := SpatialMatch("qwerty")
assert.Len(t, matches, 1, "Lenght should be 1")
matches = SpatialMatch("asdf")
assert.Len(t, matches, 1, "Lenght should be 1")
}
func TestSpatialMatchDvorak(t *testing.T) {
matches := SpatialMatch("aoeuidhtns")
assert.Len(t, matches, 1, "Lenght should be 1")
}
func TestDictionaryMatch(t *testing.T) {
var matches []match.Match
for _, dicMatcher := range DICTIONARY_MATCHERS {
matchesTemp := dicMatcher("first")
matches = append(matches, matchesTemp...)
}
assert.Len(t, matches, 4, "Lenght should be 4")
}
func TestDateWithoutSepMatch(t *testing.T) {
matches := dateWithoutSepMatch("11091991")
assert.Len(t, matches, 1, "Lenght should be 1")
}

View File

@ -70,7 +70,7 @@ func MinimumEntropyMatchSequence(password string, matches []match.Match) MinEntr
}
}
// walk backwards and decode the best sequence
//walk backwards and decode the best sequence
var matchSequence []match.Match
passwordLen := len(password)
passwordLen--