domain-auth-0.2.4: Network/DomainAuth/DK/Parser.hs
{-# LANGUAGE OverloadedStrings #-}
module Network.DomainAuth.DK.Parser (
parseDK,
) where
import Data.ByteString (ByteString)
import qualified Data.ByteString.Char8 as BS
import Data.List
import qualified Data.Map as M
import Data.Maybe
import Network.DomainAuth.DK.Types
import Network.DomainAuth.Mail
-- $setup
-- >>> import Text.Pretty.Simple
-- >>> import Data.ByteString.Char8 as BS8
-- | Parsing DomainKey-Signature:.
--
-- >>> :{
-- let dk = BS8.concat [
-- "a=rsa-sha1; s=brisbane; d=football.example.com;\n"
-- , " c=simple; q=dns;\n"
-- , " b=dzdVyOfAKCdLXdJOc9G2q8LoXSlEniSbav+yuU4zGeeruD00lszZ\n"
-- , " VoG4ZHRNiYzR;"
-- ]
-- in pPrintNoColor $ parseDK dk
-- :}
-- Just
-- ( DK
-- { dkAlgorithm = DK_RSA_SHA1
-- , dkSignature = "dzdVyOfAKCdLXdJOc9G2q8LoXSlEniSbav+yuU4zGeeruD00lszZVoG4ZHRNiYzR"
-- , dkCanonAlgo = DK_SIMPLE
-- , dkDomain0 = "football.example.com"
-- , dkFields = Nothing
-- , dkSelector0 = "brisbane"
-- }
-- )
parseDK :: RawFieldValue -> Maybe DK
parseDK val = toDK domkey
where
(ts, vs) = unzip $ parseTaggedValue val
fs = map tagToSetter ts
tagToSetter tag = fromMaybe (\_ mdk -> mdk) $ lookup (BS.head tag) dkTagDB
pfs = zipWith ($) fs vs
domkey = foldr ($) initialMDK pfs
toDK mdk = do
alg <- mdkAlgorithm mdk
sig <- mdkSignature mdk
cal <- mdkCanonAlgo mdk
dom <- mdkDomain mdk
sel <- mdkSelector mdk
return
DK
{ dkAlgorithm = alg
, dkSignature = sig
, dkCanonAlgo = cal
, dkDomain0 = dom
, dkFields = mdkFields mdk
, dkSelector0 = sel
}
data MDK = MDK
{ mdkAlgorithm :: Maybe DkAlgorithm
, mdkSignature :: Maybe ByteString
, mdkCanonAlgo :: Maybe DkCanonAlgo
, mdkDomain :: Maybe ByteString
, mdkFields :: Maybe DkFields
, mdkSelector :: Maybe ByteString
}
deriving (Eq, Show)
initialMDK :: MDK
initialMDK =
MDK
{ mdkAlgorithm = Just DK_RSA_SHA1
, mdkSignature = Nothing
, mdkCanonAlgo = Nothing
, mdkDomain = Nothing
, mdkFields = Nothing
, mdkSelector = Nothing
}
type DKSetter = ByteString -> MDK -> MDK
dkTagDB :: [(Char, DKSetter)]
dkTagDB =
[ ('a', setDkAlgorithm)
, ('b', setDkSignature)
, ('c', setDkCanonAlgo)
, ('d', setDkDomain)
, ('h', setDkFields)
, -- , ('q',setDkQuery)
('s', setDkSelector)
]
setDkAlgorithm :: DKSetter
setDkAlgorithm "rsa-sha1" dk = dk{mdkAlgorithm = Just DK_RSA_SHA1}
setDkAlgorithm _ _ = error "setDkAlgorithm"
setDkSignature :: DKSetter
setDkSignature sig dk = dk{mdkSignature = Just sig}
setDkCanonAlgo :: DKSetter
setDkCanonAlgo "simple" dk = dk{mdkCanonAlgo = Just DK_SIMPLE}
setDkCanonAlgo "nofws" dk = dk{mdkCanonAlgo = Just DK_NOFWS}
setDkCanonAlgo _ _ = error "setDkCanonAlgo"
setDkDomain :: DKSetter
setDkDomain dom dk = dk{mdkDomain = Just dom}
setDkFields :: DKSetter
setDkFields keys dk = dk{mdkFields = Just mx}
where
flds = BS.split ':' keys
mx = foldl' func M.empty flds
func m fld = M.insert fld True m
{-
setDkQuery :: DKSetter
setDkQuery "dns" dk = dk { mdkQuery = Just DK_DNS }
setDkQuery _ _ = error "setDkQuery"
-}
setDkSelector :: DKSetter
setDkSelector sel dk = dk{mdkSelector = Just sel}