{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}
module Text.Password.Strength.Internal.Config (
Config,
HasConfig,
Dictionary,
en_US,
dictionaries,
passwordLists,
wordFrequencyLists,
customFrequencyLists,
keyboardGraphs,
obviousSequenceStart,
addCustomFrequencyList
) where
import Control.Lens ((&), (^.), (.~), (%~))
import Control.Lens.TH (makeClassy)
import Control.Monad (join)
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import Data.Text (Text)
import Data.Vector (Vector)
import qualified Data.Vector as Vector
import qualified Text.Password.Strength.Generated.Adjacency as Adjc
import qualified Text.Password.Strength.Generated.Frequency as Freq
import Text.Password.Strength.Internal.Adjacency (AdjacencyTable)
type Dictionary = HashMap Text Int
data Config = Config
{ _passwordLists :: [Dictionary]
, _wordFrequencyLists :: [Dictionary]
, _customFrequencyLists :: [Dictionary]
, _keyboardGraphs :: [AdjacencyTable]
, _obviousSequenceStart :: Char -> Bool
}
makeClassy ''Config
instance Semigroup Config where
(<>) x y =
x & passwordLists %~ (++ (y ^. passwordLists))
& wordFrequencyLists %~ (++ (y ^. wordFrequencyLists))
& customFrequencyLists %~ (++ (y ^. customFrequencyLists))
& keyboardGraphs %~ (++ (y ^. keyboardGraphs))
& obviousSequenceStart .~ oss
where
oss :: Char -> Bool
oss c = (x ^. obviousSequenceStart) c
|| (y ^. obviousSequenceStart) c
instance Monoid Config where
mempty = Config [] [] [] [] (const False)
en_US :: Config
en_US = Config{..}
where
_customFrequencyLists = []
_passwordLists = [ Freq.xato ]
_wordFrequencyLists = [ Freq.english_wikipedia
, Freq.female_names
, Freq.male_names
, Freq.surnames
, Freq.us_tv_and_film
]
_keyboardGraphs = [ Adjc.qwerty
, Adjc.numpad
]
_obviousSequenceStart c =
c == 'a' || c == 'A' ||
c == 'z' || c == 'Z' ||
c == '0' || c == '1' || c == '9'
dictionaries :: Config -> [Dictionary]
dictionaries c = join [ c ^. passwordLists
, c ^. wordFrequencyLists
, c ^. customFrequencyLists
]
addCustomFrequencyList :: Vector Text -> Config -> Config
addCustomFrequencyList v = addDict (mkDict v)
where
mkDict :: Vector Text -> Dictionary
mkDict = Vector.ifoldr (\i x -> HashMap.insert x (i+1)) HashMap.empty
addDict :: Dictionary -> Config -> Config
addDict d = customFrequencyLists %~ (d:)