{-# LANGUAGE OverloadedStrings #-}
-- {-# LANGUAGE ExplicitForAll    #-}
-- {-# LANGUAGE RankNTypes #-}

module Database.Vault.KVv2.Client.Lens (

    current,
    list,
    metadata,
    maybeError,
    secret,
    version

  ) where

import           Control.Lens
import qualified Data.Aeson                          as A
import           Data.Aeson.Lens
import qualified Data.Text                           as T
import qualified Data.Vector                         as V

import           Database.Vault.KVv2.Client.Internal
import           Database.Vault.KVv2.Client.Types

secret
  :: A.Value
  -> Either String SecretData
secret :: Value -> Either String SecretData
secret =
  Text
-> (Value -> Either String SecretData)
-> Value
-> Either String SecretData
forall a.
Text -> (Value -> Either String a) -> Value -> Either String a
fromVaultResponse Text
"data" Value -> Either String SecretData
forall b. FromJSON b => Value -> Either String b
toSecretData
  where
  toSecretData :: Value -> Either String b
toSecretData o :: Value
o@(A.Object Object
_) =
    case Value -> Result b
forall a. FromJSON a => Value -> Result a
A.fromJSON Value
o of
      A.Success b
sd -> b -> Either String b
forall a b. b -> Either a b
Right b
sd
      A.Error String
e    -> String -> Either String b
forall a b. a -> Either a b
Left String
e
  toSecretData Value
A.Null         = String -> Either String b
forall a b. a -> Either a b
Left String
"No current secret version"
  toSecretData Value
_              = String -> Either String b
forall a b. a -> Either a b
Left String
"Unexpected JSON type"

version
  :: A.Value
  -> Either String SecretVersion
version :: Value -> Either String SecretVersion
version =
  Text
-> (Value -> Either String SecretVersion)
-> Value
-> Either String SecretVersion
forall a.
Text -> (Value -> Either String a) -> Value -> Either String a
fromVaultResponse Text
"version" Value -> Either String SecretVersion
forall a. Value -> Either a SecretVersion
toSecretVersion
  where
  toSecretVersion :: Value -> Either a SecretVersion
toSecretVersion (A.Number Scientific
n) = SecretVersion -> Either a SecretVersion
forall a b. b -> Either a b
Right (Int -> SecretVersion
SecretVersion (Int -> SecretVersion) -> Int -> SecretVersion
forall a b. (a -> b) -> a -> b
$ Scientific -> Int
toInt Scientific
n)
  toSecretVersion Value
_            = Either a SecretVersion
forall a. HasCallStack => a
undefined

current
  :: A.Value
  -> Either String SecretVersion
current :: Value -> Either String SecretVersion
current =
  Text
-> (Value -> Either String SecretVersion)
-> Value
-> Either String SecretVersion
forall a.
Text -> (Value -> Either String a) -> Value -> Either String a
fromVaultResponse Text
"current_version" Value -> Either String SecretVersion
forall a. Value -> Either a SecretVersion
toSecretVersion
  where
  toSecretVersion :: Value -> Either a SecretVersion
toSecretVersion (A.Number Scientific
n) = SecretVersion -> Either a SecretVersion
forall a b. b -> Either a b
Right (Int -> SecretVersion
SecretVersion (Int -> SecretVersion) -> Int -> SecretVersion
forall a b. (a -> b) -> a -> b
$ Scientific -> Int
toInt Scientific
n)
  toSecretVersion Value
_            = Either a SecretVersion
forall a. HasCallStack => a
undefined

metadata
  :: A.Value
  -> Either String SecretMetadata
metadata :: Value -> Either String SecretMetadata
metadata =
  Text
-> (Value -> Either String SecretMetadata)
-> Value
-> Either String SecretMetadata
forall a.
Text -> (Value -> Either String a) -> Value -> Either String a
fromVaultResponse Text
"versions" Value -> Either String SecretMetadata
forall b. FromJSON b => Value -> Either String b
toSecretMetadata
  where
  toSecretMetadata :: Value -> Either String b
toSecretMetadata o :: Value
o@(A.Object Object
_) =
    case Value -> Result b
forall a. FromJSON a => Value -> Result a
A.fromJSON Value
o of
      A.Success b
vs -> b -> Either String b
forall a b. b -> Either a b
Right b
vs
      A.Error String
e    -> String -> Either String b
forall a b. a -> Either a b
Left String
e
  toSecretMetadata Value
_            = Either String b
forall a. HasCallStack => a
undefined

list
  :: A.Value
  -> Either String [VaultKey]
list :: Value -> Either String [VaultKey]
list =
  Text
-> (Value -> Either String [VaultKey])
-> Value
-> Either String [VaultKey]
forall a.
Text -> (Value -> Either String a) -> Value -> Either String a
fromVaultResponse Text
"keys" Value -> Either String [VaultKey]
forall a. Value -> Either a [VaultKey]
toListKeys
  where
    toListKeys :: Value -> Either a [VaultKey]
toListKeys (A.Array Array
a) =
      [VaultKey] -> Either a [VaultKey]
forall a b. b -> Either a b
Right (([VaultKey] -> Value -> [VaultKey])
-> [VaultKey] -> Array -> [VaultKey]
forall a b. (a -> b -> a) -> a -> Vector b -> a
V.foldl [VaultKey] -> Value -> [VaultKey]
lks [VaultKey]
forall a. Monoid a => a
mempty Array
a)
      where
        lks :: [VaultKey] -> Value -> [VaultKey]
lks [VaultKey]
ks (A.String Text
t) =
          let s :: String
s = Text -> String
T.unpack Text
t in
          (if String -> Bool
hasTrailingSlash String
s
             then String -> VaultKey
VaultFolder String
s
             else String -> VaultKey
VaultKey String
s) VaultKey -> [VaultKey] -> [VaultKey]
forall a. a -> [a] -> [a]
: [VaultKey]
ks
        lks [VaultKey]
p       Value
_       = [VaultKey]
p
    toListKeys Value
_            = Either a [VaultKey]
forall a. HasCallStack => a
undefined
 
maybeError
  :: Either String A.Value
  -> Maybe Error
maybeError :: Either String Value -> Maybe String
maybeError (Left String
s)  = String -> Maybe String
forall a. a -> Maybe a
Just String
s
maybeError (Right Value
v) =
  case Value
v Value -> Getting (First Value) Value Value -> Maybe Value
forall s a. s -> Getting (First a) s a -> Maybe a
^? Text -> Traversal' Value Value
forall t. AsValue t => Text -> Traversal' t Value
key Text
"data" Getting (First Value) Value Value
-> Getting (First Value) Value Value
-> Getting (First Value) Value Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Traversal' Value Value
forall t. AsValue t => Text -> Traversal' t Value
key Text
"version" of
    Just Value
A.Null -> Maybe String
forall a. Maybe a
Nothing
    Just Value
_      -> String -> Maybe String
forall a. a -> Maybe a
Just String
"Unexpected JSON type"
    Maybe Value
Nothing     -> String -> Maybe String
forall a. a -> Maybe a
Just (Value -> String
jsonErrors Value
v)