module Authorize.Macaroon.Serialize (
    fieldEOS,
    fieldLocation,
    fieldIdentifier,
    fieldVerificationId,
    fieldSignature,
    putField,
    getField,
    getOptionalField,
    getEOS,
    atEOS,
) where

import Data.ByteString (ByteString)
import Data.ByteString qualified as BS
import Data.Bytes.Serial qualified as By
import Data.Bytes.VarInt (VarInt (..))
import Data.Serialize (Get, Put, Serialize (..))
import Data.Serialize qualified as S
import Data.Word (Word8)

fieldEOS :: Word8
fieldEOS :: Word8
fieldEOS = Word8
0

fieldLocation :: Word8
fieldLocation :: Word8
fieldLocation = Word8
1

fieldIdentifier :: Word8
fieldIdentifier :: Word8
fieldIdentifier = Word8
2

fieldVerificationId :: Word8
fieldVerificationId :: Word8
fieldVerificationId = Word8
4

fieldSignature :: Word8
fieldSignature :: Word8
fieldSignature = Word8
6

putField :: Word8 -> ByteString -> Put
putField :: Word8 -> ByteString -> Put
putField Word8
fieldId ByteString
dat =
    Putter Word8
forall t. Serialize t => Putter t
put Word8
fieldId Put -> Put -> Put
forall a b. PutM a -> PutM b -> PutM b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> VarInt Int -> Put
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
forall (m :: * -> *). MonadPut m => VarInt Int -> m ()
By.serialize (Int -> VarInt Int
forall n. n -> VarInt n
VarInt (Int -> VarInt Int) -> Int -> VarInt Int
forall a b. (a -> b) -> a -> b
$ ByteString -> Int
BS.length ByteString
dat) Put -> Put -> Put
forall a b. PutM a -> PutM b -> PutM b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> ByteString -> Put
S.putByteString ByteString
dat

getOptionalField :: Word8 -> Get (Maybe ByteString)
getOptionalField :: Word8 -> Get (Maybe ByteString)
getOptionalField Word8
f = do
    Word8
n <- Get Word8 -> Get Word8
forall a. Get a -> Get a
S.lookAhead Get Word8
S.getWord8
    if Word8
n Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
f
        then Get Word8
S.getWord8 Get Word8 -> Get (Maybe ByteString) -> Get (Maybe ByteString)
forall a b. Get a -> Get b -> Get b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (ByteString -> Maybe ByteString)
-> Get ByteString -> Get (Maybe ByteString)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get ByteString
getFieldData
        else Maybe ByteString -> Get (Maybe ByteString)
forall a. a -> Get a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe ByteString
forall a. Maybe a
Nothing

getField :: Word8 -> Get ByteString
getField :: Word8 -> Get ByteString
getField Word8
f = do
    Word8
n <- Get Word8
S.getWord8
    if Word8
n Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
f then Get ByteString
getFieldData else String -> Get ByteString
forall a. String -> Get a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Get ByteString) -> String -> Get ByteString
forall a b. (a -> b) -> a -> b
$ String
"Expecting field " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Word8 -> String
forall a. Show a => a -> String
show Word8
f String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
" but got " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Word8 -> String
forall a. Show a => a -> String
show Word8
n

getFieldData :: Get ByteString
getFieldData :: Get ByteString
getFieldData = do
    VarInt Int
n <- Get (VarInt Int)
forall a (m :: * -> *). (Serial a, MonadGet m) => m a
forall (m :: * -> *). MonadGet m => m (VarInt Int)
By.deserialize
    Int -> Get ByteString
S.getBytes Int
n

getEOS :: Get ()
getEOS :: Get ()
getEOS = do
    Word8
f <- Get Word8
S.getWord8
    if Word8
f Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
fieldEOS then () -> Get ()
forall a. a -> Get a
forall (m :: * -> *) a. Monad m => a -> m a
return () else String -> Get ()
forall a. String -> Get a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Expecting EOS"

atEOS :: Get Bool
atEOS :: Get Bool
atEOS = (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
fieldEOS) (Word8 -> Bool) -> Get Word8 -> Get Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get Word8 -> Get Word8
forall a. Get a -> Get a
S.lookAhead Get Word8
S.getWord8