{-| Copyright: This file is part of the package zxcvbn-hs. It is subject to the license terms in the LICENSE file found in the top-level directory of this distribution and at: https://code.devalot.com/sthenauth/zxcvbn-hs No part of this package, including this file, may be copied, modified, propagated, or distributed except according to the terms contained in the LICENSE file. License: MIT -} module Text.Password.Strength.Internal.Math ( variations , variations' , bruteForce , caps ) where -------------------------------------------------------------------------------- -- Library Imports: import Control.Lens ((^.)) import Data.Char (isUpper) import qualified Data.Text as Text import Numeric.SpecFunctions (choose) -------------------------------------------------------------------------------- -- Project Imports: import Text.Password.Strength.Internal.Token -------------------------------------------------------------------------------- -- | Equation 2, section 4, page 163 (8/18) -- -- NOTE: The other implementations don't seem to divide the sum by two -- but the equation in the paper clearly does. variations :: Int -> Int -> Integer variations 0 _ = 1 variations _ 0 = 1 variations u l = max 1 (sum (floor . choose (u+l) <$> [1 .. min u l]) `div` 2) -------------------------------------------------------------------------------- -- | Like equation 2, but modified for l33t and keyboard variations. -- -- This equation does not appear in the 2016 paper although it is -- mentioned. Therefore it was adapted from the CoffeeScript and -- Python implementations. variations' :: Int -> Int -> Integer variations' 0 _ = 2 variations' _ 0 = 2 variations' u l = variations u l -------------------------------------------------------------------------------- -- | Calculate the brute force score for text with the given length. bruteForce :: Int -> Integer bruteForce = (10 ^) -------------------------------------------------------------------------------- -- | Score the use of uppercase letters according to the paper. This -- is specified in the paragraph preceding equation 2. caps :: Token -> Integer -> Integer caps token n = let text = token ^. tokenChars upper = Text.length (Text.filter isUpper text) lower = Text.length text - upper allLower = lower == Text.length text allUpper = lower == 0 firstUpper = upper == 1 && Text.all isUpper (Text.take 1 text) lastUpper = upper == 1 && Text.all isUpper (Text.takeEnd 1 text) in case () of () | allLower -> n | firstUpper -> n * 2 | lastUpper -> n * 2 | allUpper -> n * 2 | otherwise -> n * variations upper lower -------------------------------------------------------------------------------- -- NOTE: Equation 3 is in Keybaord.hs.