-- | Data structures to define and manipulate tokens
module Gamgee.Token
    ( TokenType (..)
    , TokenLabel (..)
    , TokenSecret (..)
    , TokenIssuer (..)
    , TokenAlgorithm (..)
    , TokenDigits (..)
    , TokenPeriod (..)
    , TokenSpec (..)
    , TokenIdentifier (..)
    , Tokens
    , Config(..)
    , getIdentifier
    , currentConfigVersion
    , initialConfig
    ) where

import qualified Data.Aeson as Aeson
import qualified Data.Text  as Text
import           Relude


-- | Type of token TOTP or HOTP (not supported yet)
data TokenType = TOTP
  deriving stock Int -> TokenType -> ShowS
[TokenType] -> ShowS
TokenType -> String
(Int -> TokenType -> ShowS)
-> (TokenType -> String)
-> ([TokenType] -> ShowS)
-> Show TokenType
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [TokenType] -> ShowS
$cshowList :: [TokenType] -> ShowS
show :: TokenType -> String
$cshow :: TokenType -> String
showsPrec :: Int -> TokenType -> ShowS
$cshowsPrec :: Int -> TokenType -> ShowS
Show

instance Aeson.FromJSON TokenType where
  parseJSON :: Value -> Parser TokenType
parseJSON (Aeson.String Text
"totp") = TokenType -> Parser TokenType
forall (m :: * -> *) a. Monad m => a -> m a
return TokenType
TOTP
  parseJSON Value
invalid               = String -> Parser TokenType
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Parser TokenType) -> String -> Parser TokenType
forall a b. (a -> b) -> a -> b
$ String
"Invalid token type: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Value -> String
forall b a. (Show a, IsString b) => a -> b
show Value
invalid

instance Aeson.ToJSON TokenType where
  toJSON :: TokenType -> Value
toJSON TokenType
TOTP = Text -> Value
Aeson.String Text
"totp"

-- | Label of the token
newtype TokenLabel = TokenLabel {
  TokenLabel -> Text
unTokenLabel :: Text
  }
  deriving newtype (Int -> TokenLabel -> ShowS
[TokenLabel] -> ShowS
TokenLabel -> String
(Int -> TokenLabel -> ShowS)
-> (TokenLabel -> String)
-> ([TokenLabel] -> ShowS)
-> Show TokenLabel
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [TokenLabel] -> ShowS
$cshowList :: [TokenLabel] -> ShowS
show :: TokenLabel -> String
$cshow :: TokenLabel -> String
showsPrec :: Int -> TokenLabel -> ShowS
$cshowsPrec :: Int -> TokenLabel -> ShowS
Show, String -> TokenLabel
(String -> TokenLabel) -> IsString TokenLabel
forall a. (String -> a) -> IsString a
fromString :: String -> TokenLabel
$cfromString :: String -> TokenLabel
IsString, Value -> Parser [TokenLabel]
Value -> Parser TokenLabel
(Value -> Parser TokenLabel)
-> (Value -> Parser [TokenLabel]) -> FromJSON TokenLabel
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
parseJSONList :: Value -> Parser [TokenLabel]
$cparseJSONList :: Value -> Parser [TokenLabel]
parseJSON :: Value -> Parser TokenLabel
$cparseJSON :: Value -> Parser TokenLabel
Aeson.FromJSON, [TokenLabel] -> Encoding
[TokenLabel] -> Value
TokenLabel -> Encoding
TokenLabel -> Value
(TokenLabel -> Value)
-> (TokenLabel -> Encoding)
-> ([TokenLabel] -> Value)
-> ([TokenLabel] -> Encoding)
-> ToJSON TokenLabel
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [TokenLabel] -> Encoding
$ctoEncodingList :: [TokenLabel] -> Encoding
toJSONList :: [TokenLabel] -> Value
$ctoJSONList :: [TokenLabel] -> Value
toEncoding :: TokenLabel -> Encoding
$ctoEncoding :: TokenLabel -> Encoding
toJSON :: TokenLabel -> Value
$ctoJSON :: TokenLabel -> Value
Aeson.ToJSON)

-- | Secret used to generate OTPs
data TokenSecret = TokenSecretPlainText Text
                 | TokenSecretAES256 {
                     TokenSecret -> Text
tokenSecretAES256IV     :: Text
                     , TokenSecret -> Text
tokenSecretAES256Data :: Text
                     }
                 deriving stock    (Int -> TokenSecret -> ShowS
[TokenSecret] -> ShowS
TokenSecret -> String
(Int -> TokenSecret -> ShowS)
-> (TokenSecret -> String)
-> ([TokenSecret] -> ShowS)
-> Show TokenSecret
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [TokenSecret] -> ShowS
$cshowList :: [TokenSecret] -> ShowS
show :: TokenSecret -> String
$cshow :: TokenSecret -> String
showsPrec :: Int -> TokenSecret -> ShowS
$cshowsPrec :: Int -> TokenSecret -> ShowS
Show, (forall x. TokenSecret -> Rep TokenSecret x)
-> (forall x. Rep TokenSecret x -> TokenSecret)
-> Generic TokenSecret
forall x. Rep TokenSecret x -> TokenSecret
forall x. TokenSecret -> Rep TokenSecret x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep TokenSecret x -> TokenSecret
$cfrom :: forall x. TokenSecret -> Rep TokenSecret x
Generic)
                 deriving anyclass (Value -> Parser [TokenSecret]
Value -> Parser TokenSecret
(Value -> Parser TokenSecret)
-> (Value -> Parser [TokenSecret]) -> FromJSON TokenSecret
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
parseJSONList :: Value -> Parser [TokenSecret]
$cparseJSONList :: Value -> Parser [TokenSecret]
parseJSON :: Value -> Parser TokenSecret
$cparseJSON :: Value -> Parser TokenSecret
Aeson.FromJSON, [TokenSecret] -> Encoding
[TokenSecret] -> Value
TokenSecret -> Encoding
TokenSecret -> Value
(TokenSecret -> Value)
-> (TokenSecret -> Encoding)
-> ([TokenSecret] -> Value)
-> ([TokenSecret] -> Encoding)
-> ToJSON TokenSecret
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [TokenSecret] -> Encoding
$ctoEncodingList :: [TokenSecret] -> Encoding
toJSONList :: [TokenSecret] -> Value
$ctoJSONList :: [TokenSecret] -> Value
toEncoding :: TokenSecret -> Encoding
$ctoEncoding :: TokenSecret -> Encoding
toJSON :: TokenSecret -> Value
$ctoJSON :: TokenSecret -> Value
Aeson.ToJSON)

-- | Optional issuer of this token
newtype TokenIssuer = TokenIssuer {
  TokenIssuer -> Text
unTokenIssuer :: Text
  }
  deriving newtype (Int -> TokenIssuer -> ShowS
[TokenIssuer] -> ShowS
TokenIssuer -> String
(Int -> TokenIssuer -> ShowS)
-> (TokenIssuer -> String)
-> ([TokenIssuer] -> ShowS)
-> Show TokenIssuer
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [TokenIssuer] -> ShowS
$cshowList :: [TokenIssuer] -> ShowS
show :: TokenIssuer -> String
$cshow :: TokenIssuer -> String
showsPrec :: Int -> TokenIssuer -> ShowS
$cshowsPrec :: Int -> TokenIssuer -> ShowS
Show, String -> TokenIssuer
(String -> TokenIssuer) -> IsString TokenIssuer
forall a. (String -> a) -> IsString a
fromString :: String -> TokenIssuer
$cfromString :: String -> TokenIssuer
IsString, Value -> Parser [TokenIssuer]
Value -> Parser TokenIssuer
(Value -> Parser TokenIssuer)
-> (Value -> Parser [TokenIssuer]) -> FromJSON TokenIssuer
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
parseJSONList :: Value -> Parser [TokenIssuer]
$cparseJSONList :: Value -> Parser [TokenIssuer]
parseJSON :: Value -> Parser TokenIssuer
$cparseJSON :: Value -> Parser TokenIssuer
Aeson.FromJSON, [TokenIssuer] -> Encoding
[TokenIssuer] -> Value
TokenIssuer -> Encoding
TokenIssuer -> Value
(TokenIssuer -> Value)
-> (TokenIssuer -> Encoding)
-> ([TokenIssuer] -> Value)
-> ([TokenIssuer] -> Encoding)
-> ToJSON TokenIssuer
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [TokenIssuer] -> Encoding
$ctoEncodingList :: [TokenIssuer] -> Encoding
toJSONList :: [TokenIssuer] -> Value
$ctoJSONList :: [TokenIssuer] -> Value
toEncoding :: TokenIssuer -> Encoding
$ctoEncoding :: TokenIssuer -> Encoding
toJSON :: TokenIssuer -> Value
$ctoJSON :: TokenIssuer -> Value
Aeson.ToJSON)

data TokenAlgorithm = AlgorithmSHA1
                    | AlgorithmSHA256
                    | AlgorithmSHA512
                    deriving stock    (Int -> TokenAlgorithm -> ShowS
[TokenAlgorithm] -> ShowS
TokenAlgorithm -> String
(Int -> TokenAlgorithm -> ShowS)
-> (TokenAlgorithm -> String)
-> ([TokenAlgorithm] -> ShowS)
-> Show TokenAlgorithm
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [TokenAlgorithm] -> ShowS
$cshowList :: [TokenAlgorithm] -> ShowS
show :: TokenAlgorithm -> String
$cshow :: TokenAlgorithm -> String
showsPrec :: Int -> TokenAlgorithm -> ShowS
$cshowsPrec :: Int -> TokenAlgorithm -> ShowS
Show, (forall x. TokenAlgorithm -> Rep TokenAlgorithm x)
-> (forall x. Rep TokenAlgorithm x -> TokenAlgorithm)
-> Generic TokenAlgorithm
forall x. Rep TokenAlgorithm x -> TokenAlgorithm
forall x. TokenAlgorithm -> Rep TokenAlgorithm x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep TokenAlgorithm x -> TokenAlgorithm
$cfrom :: forall x. TokenAlgorithm -> Rep TokenAlgorithm x
Generic)
                    deriving anyclass (Value -> Parser [TokenAlgorithm]
Value -> Parser TokenAlgorithm
(Value -> Parser TokenAlgorithm)
-> (Value -> Parser [TokenAlgorithm]) -> FromJSON TokenAlgorithm
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
parseJSONList :: Value -> Parser [TokenAlgorithm]
$cparseJSONList :: Value -> Parser [TokenAlgorithm]
parseJSON :: Value -> Parser TokenAlgorithm
$cparseJSON :: Value -> Parser TokenAlgorithm
Aeson.FromJSON, [TokenAlgorithm] -> Encoding
[TokenAlgorithm] -> Value
TokenAlgorithm -> Encoding
TokenAlgorithm -> Value
(TokenAlgorithm -> Value)
-> (TokenAlgorithm -> Encoding)
-> ([TokenAlgorithm] -> Value)
-> ([TokenAlgorithm] -> Encoding)
-> ToJSON TokenAlgorithm
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [TokenAlgorithm] -> Encoding
$ctoEncodingList :: [TokenAlgorithm] -> Encoding
toJSONList :: [TokenAlgorithm] -> Value
$ctoJSONList :: [TokenAlgorithm] -> Value
toEncoding :: TokenAlgorithm -> Encoding
$ctoEncoding :: TokenAlgorithm -> Encoding
toJSON :: TokenAlgorithm -> Value
$ctoJSON :: TokenAlgorithm -> Value
Aeson.ToJSON)

data TokenDigits = Digits6
                 | Digits8
                 deriving stock Int -> TokenDigits -> ShowS
[TokenDigits] -> ShowS
TokenDigits -> String
(Int -> TokenDigits -> ShowS)
-> (TokenDigits -> String)
-> ([TokenDigits] -> ShowS)
-> Show TokenDigits
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [TokenDigits] -> ShowS
$cshowList :: [TokenDigits] -> ShowS
show :: TokenDigits -> String
$cshow :: TokenDigits -> String
showsPrec :: Int -> TokenDigits -> ShowS
$cshowsPrec :: Int -> TokenDigits -> ShowS
Show

instance Aeson.FromJSON TokenDigits where
  parseJSON :: Value -> Parser TokenDigits
parseJSON (Aeson.Number Scientific
6) = TokenDigits -> Parser TokenDigits
forall (m :: * -> *) a. Monad m => a -> m a
return TokenDigits
Digits6
  parseJSON (Aeson.Number Scientific
8) = TokenDigits -> Parser TokenDigits
forall (m :: * -> *) a. Monad m => a -> m a
return TokenDigits
Digits8
  parseJSON Value
invalid          = String -> Parser TokenDigits
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Parser TokenDigits) -> String -> Parser TokenDigits
forall a b. (a -> b) -> a -> b
$ String
"Invalid number of digits: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Value -> String
forall b a. (Show a, IsString b) => a -> b
show Value
invalid String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
". Must be 6 or 8."

instance Aeson.ToJSON TokenDigits where
  toJSON :: TokenDigits -> Value
toJSON TokenDigits
Digits6 = Scientific -> Value
Aeson.Number Scientific
6
  toJSON TokenDigits
Digits8 = Scientific -> Value
Aeson.Number Scientific
8

-- | Refresh interval of the token in seconds
newtype TokenPeriod = TokenPeriod {
  TokenPeriod -> Word16
unTokenPeriod :: Word16
  }
  deriving newtype (TokenPeriod -> TokenPeriod -> Bool
(TokenPeriod -> TokenPeriod -> Bool)
-> (TokenPeriod -> TokenPeriod -> Bool) -> Eq TokenPeriod
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: TokenPeriod -> TokenPeriod -> Bool
$c/= :: TokenPeriod -> TokenPeriod -> Bool
== :: TokenPeriod -> TokenPeriod -> Bool
$c== :: TokenPeriod -> TokenPeriod -> Bool
Eq, Eq TokenPeriod
Eq TokenPeriod
-> (TokenPeriod -> TokenPeriod -> Ordering)
-> (TokenPeriod -> TokenPeriod -> Bool)
-> (TokenPeriod -> TokenPeriod -> Bool)
-> (TokenPeriod -> TokenPeriod -> Bool)
-> (TokenPeriod -> TokenPeriod -> Bool)
-> (TokenPeriod -> TokenPeriod -> TokenPeriod)
-> (TokenPeriod -> TokenPeriod -> TokenPeriod)
-> Ord TokenPeriod
TokenPeriod -> TokenPeriod -> Bool
TokenPeriod -> TokenPeriod -> Ordering
TokenPeriod -> TokenPeriod -> TokenPeriod
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: TokenPeriod -> TokenPeriod -> TokenPeriod
$cmin :: TokenPeriod -> TokenPeriod -> TokenPeriod
max :: TokenPeriod -> TokenPeriod -> TokenPeriod
$cmax :: TokenPeriod -> TokenPeriod -> TokenPeriod
>= :: TokenPeriod -> TokenPeriod -> Bool
$c>= :: TokenPeriod -> TokenPeriod -> Bool
> :: TokenPeriod -> TokenPeriod -> Bool
$c> :: TokenPeriod -> TokenPeriod -> Bool
<= :: TokenPeriod -> TokenPeriod -> Bool
$c<= :: TokenPeriod -> TokenPeriod -> Bool
< :: TokenPeriod -> TokenPeriod -> Bool
$c< :: TokenPeriod -> TokenPeriod -> Bool
compare :: TokenPeriod -> TokenPeriod -> Ordering
$ccompare :: TokenPeriod -> TokenPeriod -> Ordering
$cp1Ord :: Eq TokenPeriod
Ord, Int -> TokenPeriod
TokenPeriod -> Int
TokenPeriod -> [TokenPeriod]
TokenPeriod -> TokenPeriod
TokenPeriod -> TokenPeriod -> [TokenPeriod]
TokenPeriod -> TokenPeriod -> TokenPeriod -> [TokenPeriod]
(TokenPeriod -> TokenPeriod)
-> (TokenPeriod -> TokenPeriod)
-> (Int -> TokenPeriod)
-> (TokenPeriod -> Int)
-> (TokenPeriod -> [TokenPeriod])
-> (TokenPeriod -> TokenPeriod -> [TokenPeriod])
-> (TokenPeriod -> TokenPeriod -> [TokenPeriod])
-> (TokenPeriod -> TokenPeriod -> TokenPeriod -> [TokenPeriod])
-> Enum TokenPeriod
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: TokenPeriod -> TokenPeriod -> TokenPeriod -> [TokenPeriod]
$cenumFromThenTo :: TokenPeriod -> TokenPeriod -> TokenPeriod -> [TokenPeriod]
enumFromTo :: TokenPeriod -> TokenPeriod -> [TokenPeriod]
$cenumFromTo :: TokenPeriod -> TokenPeriod -> [TokenPeriod]
enumFromThen :: TokenPeriod -> TokenPeriod -> [TokenPeriod]
$cenumFromThen :: TokenPeriod -> TokenPeriod -> [TokenPeriod]
enumFrom :: TokenPeriod -> [TokenPeriod]
$cenumFrom :: TokenPeriod -> [TokenPeriod]
fromEnum :: TokenPeriod -> Int
$cfromEnum :: TokenPeriod -> Int
toEnum :: Int -> TokenPeriod
$ctoEnum :: Int -> TokenPeriod
pred :: TokenPeriod -> TokenPeriod
$cpred :: TokenPeriod -> TokenPeriod
succ :: TokenPeriod -> TokenPeriod
$csucc :: TokenPeriod -> TokenPeriod
Enum, Integer -> TokenPeriod
TokenPeriod -> TokenPeriod
TokenPeriod -> TokenPeriod -> TokenPeriod
(TokenPeriod -> TokenPeriod -> TokenPeriod)
-> (TokenPeriod -> TokenPeriod -> TokenPeriod)
-> (TokenPeriod -> TokenPeriod -> TokenPeriod)
-> (TokenPeriod -> TokenPeriod)
-> (TokenPeriod -> TokenPeriod)
-> (TokenPeriod -> TokenPeriod)
-> (Integer -> TokenPeriod)
-> Num TokenPeriod
forall a.
(a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (Integer -> a)
-> Num a
fromInteger :: Integer -> TokenPeriod
$cfromInteger :: Integer -> TokenPeriod
signum :: TokenPeriod -> TokenPeriod
$csignum :: TokenPeriod -> TokenPeriod
abs :: TokenPeriod -> TokenPeriod
$cabs :: TokenPeriod -> TokenPeriod
negate :: TokenPeriod -> TokenPeriod
$cnegate :: TokenPeriod -> TokenPeriod
* :: TokenPeriod -> TokenPeriod -> TokenPeriod
$c* :: TokenPeriod -> TokenPeriod -> TokenPeriod
- :: TokenPeriod -> TokenPeriod -> TokenPeriod
$c- :: TokenPeriod -> TokenPeriod -> TokenPeriod
+ :: TokenPeriod -> TokenPeriod -> TokenPeriod
$c+ :: TokenPeriod -> TokenPeriod -> TokenPeriod
Num, Num TokenPeriod
Ord TokenPeriod
Num TokenPeriod
-> Ord TokenPeriod -> (TokenPeriod -> Rational) -> Real TokenPeriod
TokenPeriod -> Rational
forall a. Num a -> Ord a -> (a -> Rational) -> Real a
toRational :: TokenPeriod -> Rational
$ctoRational :: TokenPeriod -> Rational
$cp2Real :: Ord TokenPeriod
$cp1Real :: Num TokenPeriod
Real, Enum TokenPeriod
Real TokenPeriod
Real TokenPeriod
-> Enum TokenPeriod
-> (TokenPeriod -> TokenPeriod -> TokenPeriod)
-> (TokenPeriod -> TokenPeriod -> TokenPeriod)
-> (TokenPeriod -> TokenPeriod -> TokenPeriod)
-> (TokenPeriod -> TokenPeriod -> TokenPeriod)
-> (TokenPeriod -> TokenPeriod -> (TokenPeriod, TokenPeriod))
-> (TokenPeriod -> TokenPeriod -> (TokenPeriod, TokenPeriod))
-> (TokenPeriod -> Integer)
-> Integral TokenPeriod
TokenPeriod -> Integer
TokenPeriod -> TokenPeriod -> (TokenPeriod, TokenPeriod)
TokenPeriod -> TokenPeriod -> TokenPeriod
forall a.
Real a
-> Enum a
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> (a, a))
-> (a -> a -> (a, a))
-> (a -> Integer)
-> Integral a
toInteger :: TokenPeriod -> Integer
$ctoInteger :: TokenPeriod -> Integer
divMod :: TokenPeriod -> TokenPeriod -> (TokenPeriod, TokenPeriod)
$cdivMod :: TokenPeriod -> TokenPeriod -> (TokenPeriod, TokenPeriod)
quotRem :: TokenPeriod -> TokenPeriod -> (TokenPeriod, TokenPeriod)
$cquotRem :: TokenPeriod -> TokenPeriod -> (TokenPeriod, TokenPeriod)
mod :: TokenPeriod -> TokenPeriod -> TokenPeriod
$cmod :: TokenPeriod -> TokenPeriod -> TokenPeriod
div :: TokenPeriod -> TokenPeriod -> TokenPeriod
$cdiv :: TokenPeriod -> TokenPeriod -> TokenPeriod
rem :: TokenPeriod -> TokenPeriod -> TokenPeriod
$crem :: TokenPeriod -> TokenPeriod -> TokenPeriod
quot :: TokenPeriod -> TokenPeriod -> TokenPeriod
$cquot :: TokenPeriod -> TokenPeriod -> TokenPeriod
$cp2Integral :: Enum TokenPeriod
$cp1Integral :: Real TokenPeriod
Integral, Int -> TokenPeriod -> ShowS
[TokenPeriod] -> ShowS
TokenPeriod -> String
(Int -> TokenPeriod -> ShowS)
-> (TokenPeriod -> String)
-> ([TokenPeriod] -> ShowS)
-> Show TokenPeriod
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [TokenPeriod] -> ShowS
$cshowList :: [TokenPeriod] -> ShowS
show :: TokenPeriod -> String
$cshow :: TokenPeriod -> String
showsPrec :: Int -> TokenPeriod -> ShowS
$cshowsPrec :: Int -> TokenPeriod -> ShowS
Show, Value -> Parser [TokenPeriod]
Value -> Parser TokenPeriod
(Value -> Parser TokenPeriod)
-> (Value -> Parser [TokenPeriod]) -> FromJSON TokenPeriod
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
parseJSONList :: Value -> Parser [TokenPeriod]
$cparseJSONList :: Value -> Parser [TokenPeriod]
parseJSON :: Value -> Parser TokenPeriod
$cparseJSON :: Value -> Parser TokenPeriod
Aeson.FromJSON, [TokenPeriod] -> Encoding
[TokenPeriod] -> Value
TokenPeriod -> Encoding
TokenPeriod -> Value
(TokenPeriod -> Value)
-> (TokenPeriod -> Encoding)
-> ([TokenPeriod] -> Value)
-> ([TokenPeriod] -> Encoding)
-> ToJSON TokenPeriod
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [TokenPeriod] -> Encoding
$ctoEncodingList :: [TokenPeriod] -> Encoding
toJSONList :: [TokenPeriod] -> Value
$ctoJSONList :: [TokenPeriod] -> Value
toEncoding :: TokenPeriod -> Encoding
$ctoEncoding :: TokenPeriod -> Encoding
toJSON :: TokenPeriod -> Value
$ctoJSON :: TokenPeriod -> Value
Aeson.ToJSON)

data TokenSpec = TokenSpec {
  -- | TOTP/HOTP token
  TokenSpec -> TokenType
tokenType        :: TokenType
  -- | A short unique label for this token used to identify it
  , TokenSpec -> TokenLabel
tokenLabel     :: TokenLabel
  -- | The secret provided by the issuer to generate tokens
  , TokenSpec -> TokenSecret
tokenSecret    :: TokenSecret
  -- | The name of the issuer
  , TokenSpec -> TokenIssuer
tokenIssuer    :: TokenIssuer
  -- | SHA algorithm used to generate tokens
  , TokenSpec -> TokenAlgorithm
tokenAlgorithm :: TokenAlgorithm
  -- | Number of digits in the token - 6 or 8
  , TokenSpec -> TokenDigits
tokenDigits    :: TokenDigits
  -- | Refresh interval of the token - typically 30 sec
  , TokenSpec -> TokenPeriod
tokenPeriod    :: TokenPeriod
  }
  deriving stock    ((forall x. TokenSpec -> Rep TokenSpec x)
-> (forall x. Rep TokenSpec x -> TokenSpec) -> Generic TokenSpec
forall x. Rep TokenSpec x -> TokenSpec
forall x. TokenSpec -> Rep TokenSpec x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep TokenSpec x -> TokenSpec
$cfrom :: forall x. TokenSpec -> Rep TokenSpec x
Generic, Int -> TokenSpec -> ShowS
[TokenSpec] -> ShowS
TokenSpec -> String
(Int -> TokenSpec -> ShowS)
-> (TokenSpec -> String)
-> ([TokenSpec] -> ShowS)
-> Show TokenSpec
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [TokenSpec] -> ShowS
$cshowList :: [TokenSpec] -> ShowS
show :: TokenSpec -> String
$cshow :: TokenSpec -> String
showsPrec :: Int -> TokenSpec -> ShowS
$cshowsPrec :: Int -> TokenSpec -> ShowS
Show)
  deriving anyclass (Value -> Parser [TokenSpec]
Value -> Parser TokenSpec
(Value -> Parser TokenSpec)
-> (Value -> Parser [TokenSpec]) -> FromJSON TokenSpec
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
parseJSONList :: Value -> Parser [TokenSpec]
$cparseJSONList :: Value -> Parser [TokenSpec]
parseJSON :: Value -> Parser TokenSpec
$cparseJSON :: Value -> Parser TokenSpec
Aeson.FromJSON, [TokenSpec] -> Encoding
[TokenSpec] -> Value
TokenSpec -> Encoding
TokenSpec -> Value
(TokenSpec -> Value)
-> (TokenSpec -> Encoding)
-> ([TokenSpec] -> Value)
-> ([TokenSpec] -> Encoding)
-> ToJSON TokenSpec
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [TokenSpec] -> Encoding
$ctoEncodingList :: [TokenSpec] -> Encoding
toJSONList :: [TokenSpec] -> Value
$ctoJSONList :: [TokenSpec] -> Value
toEncoding :: TokenSpec -> Encoding
$ctoEncoding :: TokenSpec -> Encoding
toJSON :: TokenSpec -> Value
$ctoJSON :: TokenSpec -> Value
Aeson.ToJSON)

-- An identifier for a token. This is derived from the label and issuer
newtype TokenIdentifier = TokenIdentifier {
  TokenIdentifier -> Text
unTokenIdentifier :: Text
  }
  deriving newtype (TokenIdentifier -> TokenIdentifier -> Bool
(TokenIdentifier -> TokenIdentifier -> Bool)
-> (TokenIdentifier -> TokenIdentifier -> Bool)
-> Eq TokenIdentifier
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: TokenIdentifier -> TokenIdentifier -> Bool
$c/= :: TokenIdentifier -> TokenIdentifier -> Bool
== :: TokenIdentifier -> TokenIdentifier -> Bool
$c== :: TokenIdentifier -> TokenIdentifier -> Bool
Eq, Int -> TokenIdentifier -> ShowS
[TokenIdentifier] -> ShowS
TokenIdentifier -> String
(Int -> TokenIdentifier -> ShowS)
-> (TokenIdentifier -> String)
-> ([TokenIdentifier] -> ShowS)
-> Show TokenIdentifier
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [TokenIdentifier] -> ShowS
$cshowList :: [TokenIdentifier] -> ShowS
show :: TokenIdentifier -> String
$cshow :: TokenIdentifier -> String
showsPrec :: Int -> TokenIdentifier -> ShowS
$cshowsPrec :: Int -> TokenIdentifier -> ShowS
Show, Int -> TokenIdentifier -> Int
TokenIdentifier -> Int
(Int -> TokenIdentifier -> Int)
-> (TokenIdentifier -> Int) -> Hashable TokenIdentifier
forall a. (Int -> a -> Int) -> (a -> Int) -> Hashable a
hash :: TokenIdentifier -> Int
$chash :: TokenIdentifier -> Int
hashWithSalt :: Int -> TokenIdentifier -> Int
$chashWithSalt :: Int -> TokenIdentifier -> Int
Hashable, String -> TokenIdentifier
(String -> TokenIdentifier) -> IsString TokenIdentifier
forall a. (String -> a) -> IsString a
fromString :: String -> TokenIdentifier
$cfromString :: String -> TokenIdentifier
IsString, b -> TokenIdentifier -> TokenIdentifier
NonEmpty TokenIdentifier -> TokenIdentifier
TokenIdentifier -> TokenIdentifier -> TokenIdentifier
(TokenIdentifier -> TokenIdentifier -> TokenIdentifier)
-> (NonEmpty TokenIdentifier -> TokenIdentifier)
-> (forall b.
    Integral b =>
    b -> TokenIdentifier -> TokenIdentifier)
-> Semigroup TokenIdentifier
forall b. Integral b => b -> TokenIdentifier -> TokenIdentifier
forall a.
(a -> a -> a)
-> (NonEmpty a -> a)
-> (forall b. Integral b => b -> a -> a)
-> Semigroup a
stimes :: b -> TokenIdentifier -> TokenIdentifier
$cstimes :: forall b. Integral b => b -> TokenIdentifier -> TokenIdentifier
sconcat :: NonEmpty TokenIdentifier -> TokenIdentifier
$csconcat :: NonEmpty TokenIdentifier -> TokenIdentifier
<> :: TokenIdentifier -> TokenIdentifier -> TokenIdentifier
$c<> :: TokenIdentifier -> TokenIdentifier -> TokenIdentifier
Semigroup, TokenIdentifier -> String
(TokenIdentifier -> String) -> ToString TokenIdentifier
forall a. (a -> String) -> ToString a
toString :: TokenIdentifier -> String
$ctoString :: TokenIdentifier -> String
ToString
                   , Value -> Parser [TokenIdentifier]
Value -> Parser TokenIdentifier
(Value -> Parser TokenIdentifier)
-> (Value -> Parser [TokenIdentifier]) -> FromJSON TokenIdentifier
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
parseJSONList :: Value -> Parser [TokenIdentifier]
$cparseJSONList :: Value -> Parser [TokenIdentifier]
parseJSON :: Value -> Parser TokenIdentifier
$cparseJSON :: Value -> Parser TokenIdentifier
Aeson.FromJSON, [TokenIdentifier] -> Encoding
[TokenIdentifier] -> Value
TokenIdentifier -> Encoding
TokenIdentifier -> Value
(TokenIdentifier -> Value)
-> (TokenIdentifier -> Encoding)
-> ([TokenIdentifier] -> Value)
-> ([TokenIdentifier] -> Encoding)
-> ToJSON TokenIdentifier
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [TokenIdentifier] -> Encoding
$ctoEncodingList :: [TokenIdentifier] -> Encoding
toJSONList :: [TokenIdentifier] -> Value
$ctoJSONList :: [TokenIdentifier] -> Value
toEncoding :: TokenIdentifier -> Encoding
$ctoEncoding :: TokenIdentifier -> Encoding
toJSON :: TokenIdentifier -> Value
$ctoJSON :: TokenIdentifier -> Value
Aeson.ToJSON
                   , FromJSONKeyFunction [TokenIdentifier]
FromJSONKeyFunction TokenIdentifier
FromJSONKeyFunction TokenIdentifier
-> FromJSONKeyFunction [TokenIdentifier]
-> FromJSONKey TokenIdentifier
forall a.
FromJSONKeyFunction a -> FromJSONKeyFunction [a] -> FromJSONKey a
fromJSONKeyList :: FromJSONKeyFunction [TokenIdentifier]
$cfromJSONKeyList :: FromJSONKeyFunction [TokenIdentifier]
fromJSONKey :: FromJSONKeyFunction TokenIdentifier
$cfromJSONKey :: FromJSONKeyFunction TokenIdentifier
Aeson.FromJSONKey, ToJSONKeyFunction [TokenIdentifier]
ToJSONKeyFunction TokenIdentifier
ToJSONKeyFunction TokenIdentifier
-> ToJSONKeyFunction [TokenIdentifier] -> ToJSONKey TokenIdentifier
forall a.
ToJSONKeyFunction a -> ToJSONKeyFunction [a] -> ToJSONKey a
toJSONKeyList :: ToJSONKeyFunction [TokenIdentifier]
$ctoJSONKeyList :: ToJSONKeyFunction [TokenIdentifier]
toJSONKey :: ToJSONKeyFunction TokenIdentifier
$ctoJSONKey :: ToJSONKeyFunction TokenIdentifier
Aeson.ToJSONKey)

getIdentifier :: TokenSpec -> TokenIdentifier
getIdentifier :: TokenSpec -> TokenIdentifier
getIdentifier TokenSpec
spec =
  let
    TokenLabel Text
label = TokenSpec -> TokenLabel
tokenLabel TokenSpec
spec
    TokenIssuer Text
issuer = TokenSpec -> TokenIssuer
tokenIssuer TokenSpec
spec
  in
    Text -> TokenIdentifier
TokenIdentifier (Text -> TokenIdentifier) -> Text -> TokenIdentifier
forall a b. (a -> b) -> a -> b
$ if | Text -> Bool
Text.null Text
issuer                      -> Text
label
                         | Text -> Text -> Bool
Text.isPrefixOf (Text
issuer Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
":") Text
label -> Text
label
                         | Bool
otherwise                             -> Text
issuer Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
":" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
label

type Tokens = HashMap TokenIdentifier TokenSpec

----------------------------------------------------------------------------------------------------
-- Gamgee Configuration
----------------------------------------------------------------------------------------------------

data Config = Config {
  Config -> Word32
configVersion  :: Word32
  , Config -> Tokens
configTokens :: Tokens
  }
  deriving stock    ((forall x. Config -> Rep Config x)
-> (forall x. Rep Config x -> Config) -> Generic Config
forall x. Rep Config x -> Config
forall x. Config -> Rep Config x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Config x -> Config
$cfrom :: forall x. Config -> Rep Config x
Generic)
  deriving anyclass (Value -> Parser [Config]
Value -> Parser Config
(Value -> Parser Config)
-> (Value -> Parser [Config]) -> FromJSON Config
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
parseJSONList :: Value -> Parser [Config]
$cparseJSONList :: Value -> Parser [Config]
parseJSON :: Value -> Parser Config
$cparseJSON :: Value -> Parser Config
Aeson.FromJSON, [Config] -> Encoding
[Config] -> Value
Config -> Encoding
Config -> Value
(Config -> Value)
-> (Config -> Encoding)
-> ([Config] -> Value)
-> ([Config] -> Encoding)
-> ToJSON Config
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [Config] -> Encoding
$ctoEncodingList :: [Config] -> Encoding
toJSONList :: [Config] -> Value
$ctoJSONList :: [Config] -> Value
toEncoding :: Config -> Encoding
$ctoEncoding :: Config -> Encoding
toJSON :: Config -> Value
$ctoJSON :: Config -> Value
Aeson.ToJSON)

currentConfigVersion :: Word32
currentConfigVersion :: Word32
currentConfigVersion = Word32
1

initialConfig :: Config
initialConfig :: Config
initialConfig = Config :: Word32 -> Tokens -> Config
Config {
  configVersion :: Word32
configVersion = Word32
currentConfigVersion
  , configTokens :: Tokens
configTokens = [Item Tokens] -> Tokens
forall l. IsList l => [Item l] -> l
fromList []
  }