packages feed

shomei-core-0.2.0.0: src/Shomei/Session/Token/Generator.hs

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeFamilies #-}

-- | The opaque-token-generation port: minting a fresh random refresh token and hashing
-- a refresh token for storage. Production (EP-3/EP-6) uses crypton @getRandomBytes 32@
-- base64url-encoded plus SHA-256; the test interpreter is deterministic.
module Shomei.Session.Token.Generator
  ( TokenGen (..),
    generateOpaqueToken,
    hashRefreshToken,
    generateRandomBytes,
  )
where

import Data.ByteString (ByteString)
import Effectful (Dispatch (..), DispatchOf, Eff, Effect, (:>))
import Effectful.Dispatch.Dynamic (send)
import Shomei.Session.RefreshToken.Domain (RefreshToken, RefreshTokenHash)

data TokenGen :: Effect where
  GenerateOpaqueToken :: TokenGen m RefreshToken
  HashRefreshToken :: RefreshToken -> TokenGen m RefreshTokenHash
  -- | @n@ cryptographically random bytes (EP-7: TOTP secrets and recovery codes). The test
  -- interpreter is deterministic.
  GenerateRandomBytes :: Int -> TokenGen m ByteString

type instance DispatchOf TokenGen = Dynamic

generateOpaqueToken :: (TokenGen :> es) => Eff es RefreshToken
generateOpaqueToken = send GenerateOpaqueToken

hashRefreshToken :: (TokenGen :> es) => RefreshToken -> Eff es RefreshTokenHash
hashRefreshToken = send . HashRefreshToken

generateRandomBytes :: (TokenGen :> es) => Int -> Eff es ByteString
generateRandomBytes = send . GenerateRandomBytes