packages feed

keystore-0.1.0.0: src/Data/KeyStore/Opt.hs

{-# LANGUAGE ExistentialQuantification  #-}
{-# LANGUAGE RecordWildCards            #-}
{-# LANGUAGE OverloadedStrings          #-}

module Data.KeyStore.Opt
    ( Opt
    , getSettingsOpt
    , setSettingsOpt
    , opt__debug_enabled
    , opt__verify_enabled
    , opt__backup_keys
    , opt__hash_comment
    , opt__hash_prf
    , opt__hash_iterations
    , opt__hash_width_octets
    , opt__hash_salt_octets
    , opt__crypt_cipher
    , opt__crypt_prf
    , opt__crypt_iterations
    , opt__crypt_salt_octets
    , Opt_(..)
    , opt_
    ) where

import           Data.KeyStore.Types
import           Data.Aeson
import qualified Data.Vector                    as V
import qualified Data.Map                       as Map
import qualified Data.HashMap.Strict            as HM
import           Data.Attoparsec.Number
import qualified Data.Text                      as T
import           Data.Maybe
import           Data.Char


data Opt a
    = Opt
        { opt_enum    :: OptEnum
        , opt_default :: a
        , opt_from    :: Value -> a
        , opt_to      :: a -> Value
        }


getSettingsOpt :: Opt a -> Settings -> a
getSettingsOpt Opt{..} (Settings hm) =
                maybe opt_default opt_from $ HM.lookup (opt_name opt_enum) hm

setSettingsOpt :: Opt a -> a -> Settings -> Settings
setSettingsOpt Opt{..} x (Settings hm) =
                  Settings $ HM.insert (opt_name opt_enum) (opt_to x) hm


opt__debug_enabled        :: Opt Bool
opt__debug_enabled        = bool_opt                            False       Debug__enabled

opt__verify_enabled       :: Opt Bool
opt__verify_enabled       = bool_opt                            False       Verify__enabled

opt__backup_keys          :: Opt [Name]
opt__backup_keys          = backup_opt                                      Backup__keys

opt__hash_comment         :: Opt Comment
opt__hash_comment         = text_opt (Comment   ,_Comment)      ""          Hash__comment

opt__hash_prf             :: Opt HashPRF
opt__hash_prf             = enum_opt  _text_HashPRF             PRF_sha512  Hash__prf

opt__hash_iterations      :: Opt Iterations
opt__hash_iterations      = intg_opt (Iterations,_Iterations)   5000        Hash__iterations

opt__hash_width_octets    :: Opt Octets
opt__hash_width_octets    = intg_opt (Octets    ,_Octets    )   64          Hash__width_octets

opt__hash_salt_octets     :: Opt Octets
opt__hash_salt_octets     = intg_opt (Octets    ,_Octets    )   16          Hash__salt_octets

opt__crypt_cipher         :: Opt Cipher
opt__crypt_cipher         = enum_opt  _text_Cipher              CPH_aes256  Crypt__cipher

opt__crypt_prf            :: Opt HashPRF
opt__crypt_prf            = enum_opt  _text_HashPRF             PRF_sha512  Crypt__prf

opt__crypt_iterations     :: Opt Iterations
opt__crypt_iterations     = intg_opt (Iterations,_Iterations)   5000        Crypt__iterations

opt__crypt_salt_octets    :: Opt Octets
opt__crypt_salt_octets    = intg_opt (Octets    ,_Octets    )   16          Crypt__salt_octets


data OptEnum
    = Debug__enabled
    | Verify__enabled
    | Backup__keys
    | Hash__comment
    | Hash__prf
    | Hash__iterations
    | Hash__width_octets
    | Hash__salt_octets
    | Crypt__cipher
    | Crypt__prf
    | Crypt__iterations
    | Crypt__salt_octets
    deriving (Bounded,Enum,Eq,Ord,Show)

data Opt_ = forall a. Opt_ (Opt a)

opt_ :: OptEnum -> Opt_
opt_ enm =
    case enm of
      Debug__enabled        -> Opt_ $ opt__debug_enabled
      Verify__enabled       -> Opt_ $ opt__verify_enabled
      Backup__keys          -> Opt_ $ opt__backup_keys
      Hash__comment         -> Opt_ $ opt__hash_comment
      Hash__prf             -> Opt_ $ opt__hash_prf
      Hash__iterations      -> Opt_ $ opt__hash_iterations
      Hash__width_octets    -> Opt_ $ opt__hash_width_octets
      Hash__salt_octets     -> Opt_ $ opt__hash_salt_octets
      Crypt__cipher         -> Opt_ $ opt__crypt_cipher
      Crypt__prf            -> Opt_ $ opt__crypt_prf
      Crypt__iterations     -> Opt_ $ opt__crypt_iterations
      Crypt__salt_octets    -> Opt_ $ opt__crypt_salt_octets


opt_name :: OptEnum -> T.Text
opt_name opt = T.pack $ map toLower grp ++ "." ++ drop 2 __nme
  where
    (grp,__nme) = splitAt (f (-1) ' ' so) so
      where
        f i _   []      = i+1
        f i '_' ('_':_) = i
        f i _    (h:t)  = f (i+1) h t

        so              = show opt

backup_opt :: OptEnum -> Opt [Name]
backup_opt ce =
    Opt
        { opt_enum    = ce
        , opt_default = []
        , opt_from    = frm
        , opt_to      = Array . V.fromList . map (String . T.pack . _name)
        }
  where
    frm  val =
        case val of
          Array v -> catMaybes $ map extr $ V.toList v
          _       -> []

    extr val =
        case val of
          String t | Right nm <- name $ T.unpack t -> Just nm
          _                                        -> Nothing

bool_opt ::     Bool -> OptEnum -> Opt Bool
bool_opt x0 ce =
    Opt
        { opt_enum    = ce
        , opt_default = x0
        , opt_from    = frm
        , opt_to      = Bool
        }
  where
    frm v =
        case v of
          Bool b -> b
          _      -> x0

intg_opt :: (Int->a,a->Int) -> a -> OptEnum -> Opt a
intg_opt (inj,prj) x0 ce =
    Opt
        { opt_enum    = ce
        , opt_default = x0
        , opt_from    = frm
        , opt_to      = Number . I . toInteger . prj
        }
  where
    frm v =
        case v of
          Number (I i) -> inj $ fromInteger i
          _            -> x0

text_opt :: (T.Text->a,a->T.Text) -> a -> OptEnum -> Opt a
text_opt (inj,prj) x0 ce =
    Opt
        { opt_enum    = ce
        , opt_default = x0
        , opt_from    = frm
        , opt_to      = String . prj
        }
  where
    frm v =
        case v of
          String t -> inj t
          _        -> x0

enum_opt :: (Bounded a,Enum a) => (a->T.Text) -> a -> OptEnum -> Opt a
enum_opt shw x0 ce =
    Opt
        { opt_enum    = ce
        , opt_default = x0
        , opt_from    = frm
        , opt_to      = String . shw
        }
  where
    frm v =
        case v of
          String s | Just x <- Map.lookup s mp -> x
          _                                    -> x0

    mp = Map.fromList [ (shw v,v) | v<-[minBound..maxBound] ]