zxcvbn-hs 0.2.1.0 → 0.3.0.0
raw patch · 8 files changed
+129/−115 lines, 8 filesdep +aesondep ~attoparsecdep ~base64-bytestringdep ~binary-instancesPVP ok
version bump matches the API change (PVP)
Dependencies added: aeson
Dependency ranges changed: attoparsec, base64-bytestring, binary-instances, containers, criterion, fgl, filepath, lens, math-functions, mtl, pipes, pipes-safe, pipes-text, tasty, tasty-hunit, text, unordered-containers, vector, zlib
API changes (from Hackage documentation)
- Text.Password.Strength.Internal: Score :: Integer -> Score
- Text.Password.Strength.Internal: [getScore] :: Score -> Integer
- Text.Password.Strength.Internal: newtype Score
+ Text.Password.Strength: instance Data.Aeson.Types.ToJSON.ToJSON Text.Password.Strength.Score
+ Text.Password.Strength: instance GHC.Classes.Eq Text.Password.Strength.Score
+ Text.Password.Strength: instance GHC.Classes.Ord Text.Password.Strength.Score
+ Text.Password.Strength: instance GHC.Show.Show Text.Password.Strength.Score
- Text.Password.Strength.Config: class HasConfig c_ayAx
+ Text.Password.Strength.Config: class HasConfig c_apeL
- Text.Password.Strength.Config: config :: HasConfig c_ayAx => Lens' c_ayAx Config
+ Text.Password.Strength.Config: config :: HasConfig c_apeL => Lens' c_apeL Config
- Text.Password.Strength.Config: customFrequencyLists :: HasConfig c_ayAx => Lens' c_ayAx [Dictionary]
+ Text.Password.Strength.Config: customFrequencyLists :: HasConfig c_apeL => Lens' c_apeL [Dictionary]
- Text.Password.Strength.Config: keyboardGraphs :: HasConfig c_ayAx => Lens' c_ayAx [AdjacencyTable]
+ Text.Password.Strength.Config: keyboardGraphs :: HasConfig c_apeL => Lens' c_apeL [AdjacencyTable]
- Text.Password.Strength.Config: obviousSequenceStart :: HasConfig c_ayAx => Lens' c_ayAx (Char -> Bool)
+ Text.Password.Strength.Config: obviousSequenceStart :: HasConfig c_apeL => Lens' c_apeL (Char -> Bool)
- Text.Password.Strength.Config: passwordLists :: HasConfig c_ayAx => Lens' c_ayAx [Dictionary]
+ Text.Password.Strength.Config: passwordLists :: HasConfig c_apeL => Lens' c_apeL [Dictionary]
- Text.Password.Strength.Config: wordFrequencyLists :: HasConfig c_ayAx => Lens' c_ayAx [Dictionary]
+ Text.Password.Strength.Config: wordFrequencyLists :: HasConfig c_apeL => Lens' c_apeL [Dictionary]
- Text.Password.Strength.Internal: class HasConfig c_ayAx
+ Text.Password.Strength.Internal: class HasConfig c_apeL
- Text.Password.Strength.Internal: config :: HasConfig c_ayAx => Lens' c_ayAx Config
+ Text.Password.Strength.Internal: config :: HasConfig c_apeL => Lens' c_apeL Config
- Text.Password.Strength.Internal: customFrequencyLists :: HasConfig c_ayAx => Lens' c_ayAx [Dictionary]
+ Text.Password.Strength.Internal: customFrequencyLists :: HasConfig c_apeL => Lens' c_apeL [Dictionary]
- Text.Password.Strength.Internal: keyboardGraphs :: HasConfig c_ayAx => Lens' c_ayAx [AdjacencyTable]
+ Text.Password.Strength.Internal: keyboardGraphs :: HasConfig c_apeL => Lens' c_apeL [AdjacencyTable]
- Text.Password.Strength.Internal: obviousSequenceStart :: HasConfig c_ayAx => Lens' c_ayAx (Char -> Bool)
+ Text.Password.Strength.Internal: obviousSequenceStart :: HasConfig c_apeL => Lens' c_apeL (Char -> Bool)
- Text.Password.Strength.Internal: passwordLists :: HasConfig c_ayAx => Lens' c_ayAx [Dictionary]
+ Text.Password.Strength.Internal: passwordLists :: HasConfig c_apeL => Lens' c_apeL [Dictionary]
- Text.Password.Strength.Internal: score :: Graph -> Score
+ Text.Password.Strength.Internal: score :: Graph -> Integer
- Text.Password.Strength.Internal: wordFrequencyLists :: HasConfig c_ayAx => Lens' c_ayAx [Dictionary]
+ Text.Password.Strength.Internal: wordFrequencyLists :: HasConfig c_apeL => Lens' c_apeL [Dictionary]
Files
- CHANGELOG.md +8/−8
- LICENSE +1/−1
- README.md +15/−16
- src/Text/Password/Strength.hs +21/−5
- src/Text/Password/Strength/Internal/Date.hs +1/−2
- src/Text/Password/Strength/Internal/L33t.hs +1/−1
- src/Text/Password/Strength/Internal/Search.hs +4/−11
- zxcvbn-hs.cabal +78/−71
CHANGELOG.md view
@@ -1,14 +1,15 @@-Revision History for zxcvbn-hs-==============================+# Revision History -0.2.1.0 (September 25, 2019)-----------------------------+## 0.3.0.0 (October 29, 2020) + * Added a `ToJSON` instance to the `Score` type.++## 0.2.1.0 (September 25, 2019)+ * Export the entire `HasConfig` class so external code can use the `config` lens. -0.2.0.0 (September 12, 2019)-----------------------------+## 0.2.0.0 (September 12, 2019) * Make it possible for external projects to use the code generation tool (`zxcvbn-tools`)@@ -16,7 +17,6 @@ * Due to the `binary-orphans -> binary-instances` rename this package now only compiles under `nixpkgs-unstable`. -0.1.0.0 (September 10, 2019)-----------------------------+## 0.1.0.0 (September 10, 2019) * Initial (unreleased) version
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2019 Peter J. Jones <pjones@devalot.com>+Copyright (c) 2019-2020 Peter J. Jones <pjones@devalot.com> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the
README.md view
@@ -1,13 +1,17 @@-What?------+# Password Strength Estimation +[](https://github.com/sthenauth/zxcvbn-hs/actions)+[](https://github.com/pjones/nix-hs/releases)+[](https://hackage.haskell.org/package/zxcvbn-hs)++## What?+ This is a native Haskell implementation of the [zxcvbn][] password strength estimation algorithm as it appears in the 2016 USENIX Security [paper and presentation][paper] (with some small modifications). -Why?-----+## Why? The [zxcvbn][] algorithm is a major improvement over traditional password strength estimators. Instead of counting the occurrence of@@ -15,8 +19,7 @@ zxcvbn analyzes a plain text password and estimates the number of guesses that an attacker would need to make in order to crack it. -How?-----+## How? A plain text password is broken into a list of substrings called tokens and each token is analyzed as follows:@@ -43,8 +46,7 @@ of guesses and then the entire password is scored based on the weakest path. -Usage------+## Usage A complete example can be found in the [example/Main.hs](example/Main.hs) file. That said, it's pretty easy@@ -65,14 +67,12 @@ print (strength guesses) -- Sum type describing the password strength (Risky) ``` -Demo App---------+## Demo App If you want to play with an interactive demo take a look at the [zxcvbn-ws repository][zxcvbn-ws]. -Customization--------------+## Customization You'll most likely want to add custom words to the frequency dictionaries. For example, the name of your application, your domain@@ -83,7 +83,7 @@ `addCustomFrequencyList` function which can be used to easily add words to the frequency dictionary. -### Localization ###+### Localization Unlike other implementations of the [zxcvbn][] algorithm, this version fully supports localization. It's easy to augment or completely@@ -112,12 +112,11 @@ * Number pad keyboard layout -### Existing Localization Packages ###+### Existing Localization Packages * [zxcvbn-dvorak][] Dvorak keyboard layout -Performance------------+## Performance It takes approximately 1.5 ms to process a 30-character password. Performance degrades as the length of the password increases (e.g., a
src/Text/Password/Strength.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE OverloadedStrings #-}+ {-| Copyright:@@ -23,7 +25,7 @@ module Text.Password.Strength ( -- * Estimating Guesses score,- Search.Score(..),+ Score(..), -- * Calculating Password Strength strength,@@ -38,6 +40,8 @@ -- Library Imports: import Data.Text (Text) import Data.Time.Calendar (Day)+import Data.Aeson (ToJSON(..), (.=))+import qualified Data.Aeson as Aeson -------------------------------------------------------------------------------- -- Project Imports:@@ -45,13 +49,25 @@ import qualified Text.Password.Strength.Internal.Search as Search --------------------------------------------------------------------------------+-- | A score is an estimate of the number of guesses it would take to+-- crack a password.+newtype Score = Score { getScore :: Integer }+ deriving (Show, Eq, Ord)++instance ToJSON Score where+ toJSON s = Aeson.object+ [ "score" .= getScore s+ , "strength" .= show (strength s)+ ]++-------------------------------------------------------------------------------- -- | Estimate the number of guesses an attacker would need to make to -- crack the given password. score :: Config -- ^ Which dictionaries, keyboards, etc. to use. -> Day -- ^ Reference day for date matches (should be current day). -> Text -- ^ The password to score.- -> Search.Score -- ^ Estimate.-score c d p = Search.score (Search.graph c d p)+ -> Score -- ^ Estimate.+score c d p = Score $ Search.score (Search.graph c d p) -------------------------------------------------------------------------------- -- | Measurement of password strength.@@ -79,8 +95,8 @@ -------------------------------------------------------------------------------- -- | Calculate the strength of a password given its score.-strength :: Search.Score -> Strength-strength (Search.Score n)+strength :: Score -> Strength+strength (Score n) | n < 10 ^ ( 3 :: Int) = Risky | n < 10 ^ ( 6 :: Int) = Weak | n < 10 ^ ( 8 :: Int) = Moderate
src/Text/Password/Strength/Internal/Date.hs view
@@ -30,8 +30,7 @@ import Control.Lens ((&), (^.), (+~), _1) import Control.Lens.TH (makeLenses) import qualified Data.Attoparsec.Text as Atto-import Data.Char (isDigit)-import Data.Char (isSpace)+import Data.Char (isDigit, isSpace) import Data.Function (on) import Data.List (sortBy) import Data.Maybe (catMaybes, listToMaybe)
src/Text/Password/Strength/Internal/L33t.hs view
@@ -67,7 +67,7 @@ hasSubs L33t{..} = _l33tSub > 0 || _l33tUnsub > 0 chars :: Text- chars = (token ^. tokenLower)+ chars = token ^. tokenLower trans :: [(Token, Text)] trans = case translateMap l33t2Eng chars of
src/Text/Password/Strength/Internal/Search.hs view
@@ -24,7 +24,6 @@ edges, bfEdges, graph,- Score(..), score, shortestPath ) where@@ -114,7 +113,7 @@ -- list. In the guessing graph the nodes are the characters in the -- password and the edges are the estimated guesses. graph :: Config -> Day -> Text -> Graph-graph config day password =+graph cfg day password = Graph exit edges' (Graph.mkGraph nodes (flatten edges')) where exit :: Int@@ -125,23 +124,17 @@ edges' :: Map (Int, Int) Integer edges' =- let es = edges config day password+ let es = edges cfg day password in es `Map.union` Map.fromList (bfEdges password es) flatten :: Map (Int, Int) Integer -> [(Int, Int, Integer)] flatten = map (\((x, y), z) -> (x, y, z)) . Map.assocs ----------------------------------------------------------------------------------- | A score is an estimate of the number of guesses it would take to--- crack a password.-newtype Score = Score { getScore :: Integer }- deriving (Show, Eq, Ord)---------------------------------------------------------------------------------- -- | Collapse a graph down to a single score which represents the -- estimated number of guesses it would take to crack the password.-score :: Graph -> Score-score g@Graph{..} = Score $+score :: Graph -> Integer+score g@Graph{..} = case shortestPath g of Nothing -> worstCase Just path -> maybe worstCase product (scores (nodes path))
zxcvbn-hs.cabal view
@@ -1,18 +1,21 @@-cabal-version: 2.2-----------------------------------------------------------------------------------name: zxcvbn-hs-version: 0.2.1.0-synopsis: Password strength estimation based on zxcvbn.-description: Please see the README below.-license: MIT-license-file: LICENSE-author: Peter Jones <pjones@devalot.com>-maintainer: Peter Jones <pjones@devalot.com>-copyright: Copyright (c) 2019 Peter Jones-homepage: https://code.devalot.com/sthenauth/zxcvbn-hs-bug-reports: https://github.com/sthenauth/zxcvbn-hs/issues-category: System+cabal-version: 2.2+name: zxcvbn-hs+version: 0.3.0.0+synopsis: Password strength estimation based on zxcvbn.+license: MIT+license-file: LICENSE+author: Peter Jones <pjones@devalot.com>+maintainer: Peter Jones <pjones@devalot.com>+copyright: Copyright (c) 2019-2020 Peter Jones+homepage: https://github.com/sthenauth/zxcvbn-hs+bug-reports: https://github.com/sthenauth/zxcvbn-hs/issues+category: System+tested-with: GHC ==8.6.5 || ==8.8.4 || ==8.10.2+description:+ This is a native Haskell implementation of the zxcvbn password+ strength estimation algorithm as it appears in the 2016 USENIX Security+ <https://www.usenix.org/conference/usenixsecurity16/technical-sessions/presentation/wheeler paper>+ and presentation (with some small modifications). -------------------------------------------------------------------------------- extra-source-files:@@ -22,62 +25,62 @@ -------------------------------------------------------------------------------- flag tools description: Build the data processing tools (i.e. dictionary compilers)- default: False- manual: True+ default: False+ manual: True -------------------------------------------------------------------------------- source-repository head- type: git- location: https://code.devalot.com/sthenauth/zxcvbn-hs.git+ type: git+ location: https://github.com/sthenauth/zxcvbn-hs.git -------------------------------------------------------------------------------- common options default-language: Haskell2010- ghc-options: -Wall- -Werror=incomplete-record-updates- -Werror=incomplete-uni-patterns- -Werror=missing-home-modules- -Widentities- -Wmissing-export-lists- -Wredundant-constraints+ ghc-options:+ -Wall -Werror=incomplete-record-updates+ -Werror=incomplete-uni-patterns -Werror=missing-home-modules+ -Widentities -Wmissing-export-lists -Wredundant-constraints -------------------------------------------------------------------------------- common dependencies- build-depends: base >= 4.9 && < 5.0- , attoparsec >= 0.13 && < 0.14- , base64-bytestring >= 1.0 && < 1.1- , binary >= 0.8 && < 0.11- , binary-instances >= 0.1 && < 1.0- , containers >= 0.6 && < 0.7- , fgl >= 5.7 && < 5.8- , lens >= 4.17 && < 4.18- , math-functions >= 0.3 && < 0.4- , text >= 1.2 && < 1.3- , time >= 1.8 && < 2.0- , unordered-containers >= 0.2 && < 0.3- , vector >= 0.12 && < 0.13- , zlib >= 0.6 && < 0.7+ build-depends:+ , aeson >=1.3 && <1.6+ , attoparsec ^>=0.13+ , base >=4.9 && <5.0+ , base64-bytestring >=1.0 && <1.3+ , binary >=0.8 && <0.11+ , binary-instances ^>=1+ , containers ^>=0.6+ , fgl ^>=5.7+ , lens >=4.17 && <5+ , math-functions ^>=0.3+ , text ^>=1.2+ , time >=1.8 && <2.0+ , unordered-containers ^>=0.2+ , vector ^>=0.12+ , zlib ^>=0.6 -------------------------------------------------------------------------------- common tool-dependencies- build-depends: filepath >= 1.4 && < 1.5- , mtl >= 2.2 && < 2.3- , optparse-applicative >= 0.14 && < 0.15- , pipes >= 4.3 && < 4.4- , pipes-safe >= 2.3 && < 2.4- , pipes-text >= 0.0 && < 0.1+ build-depends:+ , filepath ^>=1.4+ , mtl ^>=2.2+ , optparse-applicative >=0.14 && <0.16+ , pipes ^>=4.3+ , pipes-safe ^>=2.3+ , pipes-text >=0.0 && <1.1 -------------------------------------------------------------------------------- library- import: options, dependencies- -- ghc-prof-options: -fprof-auto -fprof-cafs- hs-source-dirs: src+ import: options, dependencies + -- ghc-prof-options: -fprof-auto -fprof-cafs+ hs-source-dirs: src exposed-modules: Text.Password.Strength Text.Password.Strength.Config- Text.Password.Strength.Types Text.Password.Strength.Internal+ Text.Password.Strength.Types other-modules: Text.Password.Strength.Generated.Adjacency@@ -98,37 +101,40 @@ -------------------------------------------------------------------------------- executable zxcvbn-tools- import: options, dependencies, tool-dependencies- main-is: Main.hs+ import: options, dependencies, tool-dependencies+ main-is: Main.hs hs-source-dirs: tools other-modules: Zxcvbn.Adjacency Zxcvbn.Encode Zxcvbn.Freq Zxcvbn.Global- build-depends: zxcvbn-hs++ build-depends: zxcvbn-hs+ if !flag(tools) buildable: False -------------------------------------------------------------------------------- executable zxcvbn-example- import: options, dependencies- main-is: Main.hs- hs-source-dirs: example+ import: options, dependencies+ main-is: Main.hs+ hs-source-dirs: example ghc-prof-options: -rtsopts- build-depends: zxcvbn-hs+ build-depends: zxcvbn-hs -------------------------------------------------------------------------------- test-suite test- import: options, dependencies- type: exitcode-stdio-1.0+ import: options, dependencies+ type: exitcode-stdio-1.0 hs-source-dirs: test- main-is: Main.hs- build-depends: hedgehog >= 0.6 && < 1.1- , tasty >= 1.1 && < 1.3- , tasty-hedgehog >= 0.2 && < 1.1- , tasty-hunit >= 0.10 && < 0.11- , zxcvbn-hs+ main-is: Main.hs+ build-depends:+ , hedgehog >=0.6 && <1.1+ , tasty >=1.1 && <1.5+ , tasty-hedgehog >=0.2 && <1.1+ , tasty-hunit ^>=0.10+ , zxcvbn-hs other-modules: Zxcvbn.Adjacency@@ -141,10 +147,11 @@ -------------------------------------------------------------------------------- benchmark bench- import: options, dependencies- type: exitcode-stdio-1.0- hs-source-dirs: benchmark- main-is: Main.hs+ import: options, dependencies+ type: exitcode-stdio-1.0+ hs-source-dirs: benchmark+ main-is: Main.hs ghc-prof-options: -rtsopts- build-depends: criterion >= 1.5 && < 1.6- , zxcvbn-hs+ build-depends:+ , criterion ^>=1.5+ , zxcvbn-hs