module Hackage.Security.Util.Base64 (
    Base64 -- opaque
  , fromByteString
  , toByteString
  ) where

import Prelude
import Data.ByteString (ByteString)
import qualified Data.ByteString.Char8  as C8  -- only called on B64-enc strings
import qualified Data.ByteString.Base64 as B64

import Hackage.Security.Util.JSON

-- | Simple wrapper around bytestring with ToJSON and FromJSON instances that
-- use base64 encoding.
newtype Base64 = Base64 ByteString

fromByteString :: ByteString -> Base64
fromByteString :: ByteString -> Base64
fromByteString = ByteString -> Base64
Base64

toByteString :: Base64 -> ByteString
toByteString :: Base64 -> ByteString
toByteString (Base64 ByteString
bs) = ByteString
bs

instance Monad m => ToJSON m Base64 where
  toJSON :: Base64 -> m JSValue
toJSON (Base64 ByteString
bs) = [Char] -> m JSValue
forall (m :: * -> *) a. ToJSON m a => a -> m JSValue
toJSON (ByteString -> [Char]
C8.unpack (ByteString -> ByteString
B64.encode ByteString
bs))

instance ReportSchemaErrors m => FromJSON m Base64 where
  fromJSON :: JSValue -> m Base64
fromJSON JSValue
val = do
    [Char]
str <- JSValue -> m [Char]
forall (m :: * -> *) a. FromJSON m a => JSValue -> m a
fromJSON JSValue
val
    case ByteString -> Either [Char] ByteString
B64.decode ([Char] -> ByteString
C8.pack [Char]
str) of
      Left [Char]
_err -> [Char] -> Maybe [Char] -> m Base64
forall a. [Char] -> Maybe [Char] -> m a
forall (m :: * -> *) a.
ReportSchemaErrors m =>
[Char] -> Maybe [Char] -> m a
expected [Char]
"base-64 encoded string" Maybe [Char]
forall a. Maybe a
Nothing
      Right ByteString
bs  -> Base64 -> m Base64
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Base64 -> m Base64) -> Base64 -> m Base64
forall a b. (a -> b) -> a -> b
$ ByteString -> Base64
Base64 ByteString
bs