spatialMatch.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. package matching
  2. import (
  3. "strings"
  4. "github.com/nbutton23/zxcvbn-go/adjacency"
  5. "github.com/nbutton23/zxcvbn-go/entropy"
  6. "github.com/nbutton23/zxcvbn-go/match"
  7. )
  8. const SPATIAL_MATCHER_NAME = "SPATIAL"
  9. func FilterSpatialMatcher(m match.Matcher) bool {
  10. return m.ID == SPATIAL_MATCHER_NAME
  11. }
  12. func spatialMatch(password string) (matches []match.Match) {
  13. for _, graph := range ADJACENCY_GRAPHS {
  14. if graph.Graph != nil {
  15. matches = append(matches, spatialMatchHelper(password, graph)...)
  16. }
  17. }
  18. return matches
  19. }
  20. func spatialMatchHelper(password string, graph adjacency.AdjacencyGraph) (matches []match.Match) {
  21. for i := 0; i < len(password)-1; {
  22. j := i + 1
  23. lastDirection := -99 //an int that it should never be!
  24. turns := 0
  25. shiftedCount := 0
  26. for {
  27. prevChar := password[j-1]
  28. found := false
  29. foundDirection := -1
  30. curDirection := -1
  31. //My graphs seem to be wrong. . . and where the hell is qwerty
  32. adjacents := graph.Graph[string(prevChar)]
  33. //Consider growing pattern by one character if j hasn't gone over the edge
  34. if j < len(password) {
  35. curChar := password[j]
  36. for _, adj := range adjacents {
  37. curDirection += 1
  38. if strings.Index(adj, string(curChar)) != -1 {
  39. found = true
  40. foundDirection = curDirection
  41. if strings.Index(adj, string(curChar)) == 1 {
  42. //index 1 in the adjacency means the key is shifted, 0 means unshifted: A vs a, % vs 5, etc.
  43. //for example, 'q' is adjacent to the entry '2@'. @ is shifted w/ index 1, 2 is unshifted.
  44. shiftedCount += 1
  45. }
  46. if lastDirection != foundDirection {
  47. //adding a turn is correct even in the initial case when last_direction is null:
  48. //every spatial pattern starts with a turn.
  49. turns += 1
  50. lastDirection = foundDirection
  51. }
  52. break
  53. }
  54. }
  55. }
  56. //if the current pattern continued, extend j and try to grow again
  57. if found {
  58. j += 1
  59. } else {
  60. //otherwise push the pattern discovered so far, if any...
  61. //don't consider length 1 or 2 chains.
  62. if j-i > 2 {
  63. matchSpc := match.Match{Pattern: "spatial", I: i, J: j - 1, Token: password[i:j], DictionaryName: graph.Name}
  64. matchSpc.Entropy = entropy.SpatialEntropy(matchSpc, turns, shiftedCount)
  65. matches = append(matches, matchSpc)
  66. }
  67. //. . . and then start a new search from the rest of the password
  68. i = j
  69. break
  70. }
  71. }
  72. }
  73. return matches
  74. }