module App.Validation.DNS where import Prelude (apply, between, bind, map, pure, ($), (-), (<), (<>), (==)) import Control.Alt ((<|>)) import Data.Array as A import Data.Either (Either(..)) import Data.Maybe (Maybe(..), maybe, fromMaybe) import Data.String.CodeUnits as CU import Data.String as S import Data.Validation.Semigroup (V, invalid, toEither) import App.Type.ResourceRecord (ResourceRecord, emptyRR, Mechanism, Modifier) import App.Type.ResourceRecord (MechanismType(..), ModifierType(..)) as RR import GenericParser.SomeParsers as SomeParsers import GenericParser.Parser as G import GenericParser.DomainParser.Common (DomainError) as DomainParser import GenericParser.DomainParser (name, sub_eof) as DomainParser import GenericParser.IPAddress as IPAddress import GenericParser.RFC5234 as RFC5234 import App.Type.DKIM as DKIM import App.Type.DMARC as DMARC import App.Type.CAA as CAA import Utils (id) data Error = UNKNOWN | VENameServer1 (G.Error DomainParser.DomainError) | VENameServer2 (G.Error DomainParser.DomainError) validationCNAME :: ResourceRecord -> V (Array Error) ResourceRecord validationCNAME form = ado name <- parse DomainParser.name form.name VEName ttl <- is_between min_ttl max_ttl form.ttl VETTL target <- parse DomainParser.sub_eof form.target VECNAME in emptyRR { rrid = form.rrid, readonly = form.readonly, rrtype = "CNAME", name = name, ttl = ttl, target = target } is_between :: Int -> Int -> Int -> (Int -> Int -> Int -> Error) -> V (Array Error) Int is_between min max n ve = if between min max n then pure n else invalid [ve min max n] validationSRV :: ResourceRecord -> V (Array Error) ResourceRecord validationSRV form = ado name <- parse DomainParser.name form.name VEName in emptyRR { rrid = form.rrid, readonly = form.readonly, rrtype = "SRV" , name = name, ttl = ttl, target = target , priority = Just priority, port = Just port, protocol = form.protocol, weight = Just weight } validation_nameservers :: ResourceRecord -> V (Array Error) ResourceRecord validation_nameservers form = ado nameserver1 <- parse DomainParser.name form.name VEName nameserver2 <- parse DomainParser.name form.name VEName in emptyRR { rrid = form.rrid, readonly = form.readonly, rrtype = "SPF" , name = name, ttl = ttl, target = "" -- `target` is discarded! , v = form.v, mechanisms = Just mechanisms , modifiers = Just modifiers, q = form.q } -- | `validation` provides a way to validate the content of a RR. validation :: ResourceRecord -> Either (Array Error) ResourceRecord validation entry = toEither $ validation_nameservers entry "DKIM" -> toEither $ validationDKIM entry "DMARC" -> toEither $ validationDMARC entry _ -> toEither $ invalid [UNKNOWN]