module Text.Password.Strength.Internal.Math
( variations
, variations'
, bruteForce
, caps
) where
import Control.Lens ((^.))
import Data.Char (isUpper)
import qualified Data.Text as Text
import Numeric.SpecFunctions (choose)
import Text.Password.Strength.Internal.Token
variations :: Int -> Int -> Integer
variations :: Int -> Int -> Integer
variations Int
0 Int
_ = Integer
1
variations Int
_ Int
0 = Integer
1
variations Int
u Int
l = Integer -> Integer -> Integer
forall a. Ord a => a -> a -> a
max Integer
1 ([Integer] -> Integer
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum (Double -> Integer
forall a b. (RealFrac a, Integral b) => a -> b
floor (Double -> Integer) -> (Int -> Double) -> Int -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Int -> Double
choose (Int
uInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
l) (Int -> Integer) -> [Int] -> [Integer]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Int
1 .. Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
u Int
l]) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`div` Integer
2)
variations' :: Int -> Int -> Integer
variations' :: Int -> Int -> Integer
variations' Int
0 Int
_ = Integer
2
variations' Int
_ Int
0 = Integer
2
variations' Int
u Int
l = Int -> Int -> Integer
variations Int
u Int
l
bruteForce :: Int -> Integer
bruteForce :: Int -> Integer
bruteForce = (Integer
10 Integer -> Int -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^)
caps :: Token -> Integer -> Integer
caps :: Token -> Integer -> Integer
caps Token
token Integer
n =
let text :: Text
text = Token
token Token -> Getting Text Token Text -> Text
forall s a. s -> Getting a s a -> a
^. Getting Text Token Text
Lens' Token Text
tokenChars
upper :: Int
upper = Text -> Int
Text.length ((Char -> Bool) -> Text -> Text
Text.filter Char -> Bool
isUpper Text
text)
lower :: Int
lower = Text -> Int
Text.length Text
text Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
upper
allLower :: Bool
allLower = Int
lower Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Text -> Int
Text.length Text
text
allUpper :: Bool
allUpper = Int
lower Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0
firstUpper :: Bool
firstUpper = Int
upper Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1 Bool -> Bool -> Bool
&& (Char -> Bool) -> Text -> Bool
Text.all Char -> Bool
isUpper (Int -> Text -> Text
Text.take Int
1 Text
text)
lastUpper :: Bool
lastUpper = Int
upper Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1 Bool -> Bool -> Bool
&& (Char -> Bool) -> Text -> Bool
Text.all Char -> Bool
isUpper (Int -> Text -> Text
Text.takeEnd Int
1 Text
text)
in case () of
() | Bool
allLower -> Integer
n
| Bool
firstUpper -> Integer
n Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
2
| Bool
lastUpper -> Integer
n Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
2
| Bool
allUpper -> Integer
n Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
2
| Bool
otherwise -> Integer
n Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Int -> Int -> Integer
variations Int
upper Int
lower