packages feed

hyperbole-0.5.0: src/Web/Hyperbole/Data/Cookie.hs

{-# LANGUAGE AllowAmbiguousTypes #-}

module Web.Hyperbole.Data.Cookie where

import Data.ByteString (ByteString)
import Data.Map.Strict (Map)
import Data.Map.Strict qualified as M
import Data.Maybe (fromMaybe)
import Data.String.Conversions (cs)
import Data.Text (Text)
import Network.HTTP.Types (urlDecode, urlEncode)
import Web.Hyperbole.Data.URI


type Key = Text


data Cookie = Cookie
  { key :: Key
  , path :: Maybe Path
  , value :: Maybe CookieValue
  }
  deriving (Show, Eq)


newtype Cookies = Cookies (Map Key Cookie)
  deriving newtype (Monoid, Semigroup, Show, Eq)


newtype CookieValue = CookieValue ByteString
  deriving newtype (Show, Eq)


insert :: Cookie -> Cookies -> Cookies
insert cookie (Cookies m) =
  Cookies $ M.insert cookie.key cookie m


delete :: Key -> Cookies -> Cookies
delete key (Cookies m) =
  Cookies $ M.delete key m


lookup :: Key -> Cookies -> Maybe CookieValue
lookup key (Cookies m) = do
  cook <- M.lookup key m
  cook.value


fromList :: [Cookie] -> Cookies
fromList cks = Cookies $ M.fromList (fmap keyValue cks)
 where
  keyValue c = (c.key, c)


toList :: Cookies -> [Cookie]
toList (Cookies m) = M.elems m


render :: Path -> Cookie -> ByteString
render requestPath cookie =
  let p = fromMaybe requestPath cookie.path
   in cs cookie.key <> "=" <> value cookie.value <> "; SameSite=None; secure; path=" <> cs (uriToText (pathUri p))
 where
  value Nothing = "; expires=Thu, 01 Jan 1970 00:00:00 GMT"
  value (Just (CookieValue val)) = urlEncode True $ cs val


parse :: [(ByteString, ByteString)] -> Either String Cookies
parse kvs = do
  cks <- mapM (uncurry parseValue) kvs
  pure $ fromList cks


parseValue :: ByteString -> ByteString -> Either String Cookie
parseValue k val = do
  let cval = CookieValue $ cs $ urlDecode True val
  pure $ Cookie (cs k) Nothing (Just $ cval)