module Serokell.Util.Base64
( encode
, decode
, encodeUrl
, decodeUrl
, formatBase64
, base64F
, JsonByteString (..)
) where
import Universum hiding (fail)
import Control.Monad (fail)
import Data.Aeson (FromJSON (parseJSON), ToJSON (toJSON))
import Data.Aeson.Types (FromJSONKey (..), FromJSONKeyFunction (FromJSONKeyTextParser),
ToJSONKey (..), toJSONKeyText)
import Data.Text.Lazy.Builder (Builder, fromText)
import Formatting (Format, later)
import qualified Data.ByteString.Base64 as B64
import qualified Data.ByteString.Base64.URL as B64url
import qualified Fmt as Fmt
encode :: ByteString -> Text
encode = Fmt.fmt . Fmt.base64F
decode :: Text -> Either Text ByteString
decode = first toText . B64.decode . encodeUtf8
encodeUrl :: ByteString -> Text
encodeUrl = Fmt.fmt . Fmt.base64UrlF
decodeUrl :: Text -> Either Text ByteString
decodeUrl = first toText . B64url.decode . encodeUtf8
formatBase64 :: ByteString -> Builder
formatBase64 = fromText . encode
base64F :: Format r (ByteString -> r)
base64F = later formatBase64
newtype JsonByteString = JsonByteString
{ getJsonByteString :: ByteString
} deriving (Show, Eq, Ord, Hashable)
instance ToJSON JsonByteString where
toJSON = toJSON . encode . getJsonByteString
instance ToJSONKey JsonByteString where
toJSONKey = toJSONKeyText (encode . getJsonByteString)
instance FromJSON JsonByteString where
parseJSON = parseJSON >=> jsonBSParser
instance FromJSONKey JsonByteString where
fromJSONKey = FromJSONKeyTextParser jsonBSParser
jsonBSParser :: MonadFail m => Text -> m JsonByteString
jsonBSParser = either (fail . toString) (pure . JsonByteString) . decode