h*Q$M      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRST0.2.4 Safe-Inferred"U domain-authremoveBtagValue "DKIM-Signature: a=rsa-sha256; d=example.net; s=brisbane;\n c=simple; q=dns/txt; i=@eng.example.net;\n t=1117574938; x=1118006938;\n h=from:to:subject:date;\n z=From:foo@eng.example.net|To:joe@example.com|\n Subject:demo=20run|Date:July=205,=202005=203:44:08=20PM=20-0700;\n bh=MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=;\n b=dzdVyOfAKCdLXdJOc9G2q8LoXSlEniSbav+yuU4zGeeruD00lszZ\n VoG4ZHRNiYzR;\n""DKIM-Signature: a=rsa-sha256; d=example.net; s=brisbane;\n c=simple; q=dns/txt; i=@eng.example.net;\n t=1117574938; x=1118006938;\n h=from:to:subject:date;\n z=From:foo@eng.example.net|To:joe@example.com|\n Subject:demo=20run|Date:July=205,=202005=203:44:08=20PM=20-0700;\n bh=MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=;\n b=;\n"U  Safe-Inferred  domain-auth'Type for body of parsed e-mail message. domain-auth.Type for field value of parsed e-mail message. domain-auth,Type for field key of parsed e-mail message. domain-auth:Type for canonicalized field key of parsed e-mail message. domain-auth%Field type for parsed e-mail message.  domain-auth&Header type for parsed e-mail message.  domain-authType for parsed e-mail message. domain-auth"Body chunk for raw e-mail message. domain-auth#Field value for raw e-mail message. domain-auth!Field key for raw e-mail message. domain-authType for raw e-mail message. domain-authCanonicalizing  for search. VWX  Safe-Inferred" sY domain-authP.parseOnly structured "From: Kazu Yamamoto (=?iso-2022-jp?B?GyRCOzNLXE9CSScbKEI=?=)\n "Right ["From",":","Kazu","Yamamoto","<","kazu","@","example",".","net",">"]P.parseOnly structured "To:A Group(Some people)\n :Chris Jones ,\n joe@example.org,\n John (my dear friend); (the end of the group)\n"Right ["To",":","A","Group",":","Chris","Jones","<","c","@","public",".","example",">",",","joe","@","example",".","org",",","John","<","jdoe","@","one",".","test",">",";"]P.parseOnly structured "Date: Thu,\n 13\n Feb\n 1969\n 23:32\n -0330 (Newfoundland Time)\n"Right ["Date",":","Thu",",","13","Feb","1969","23",":","32","-0330"]P.parseOnly structured "From: Pete(A nice \\) chap) \n"?Right ["From",":","Pete","<","pete","@","silly",".","test",">"]Y  Safe-Inferred" Z[\]^_`abcdefghijklmno  Safe-Inferred" p  Safe-Inferred" q Safe-Inferred  domain-authThe result of domain authentication. For more information, see  #http://www.ietf.org/rfc/rfc5451.txt.     Safe-Inferred% domain-authLimit for SPF authentication.' domain-auth5How many "redirect"/"include" should be followed. & is returned if reached to this limit.( domain-auth;Ignoring IPv4 range whose mask length is shorter than this.) domain-auth;Ignoring IPv6 range whose mask length is shorter than this.* domain-auth"Whether or not "+all" is rejected.+ domain-authDefault value for %. defaultLimitLimit {limit = 10, ipv4_masklen = 16, ipv6_masklen = 48, reject_plus_all = True}r%&'()*+ Safe-Inferred,, domain-authProcess SPF authentication. s) is an IP address of an SMTP peer. If t is specified from SMTP MAIL FROM, authentication is based on SPF. If t is specified from the From field of mail header, authentication is based on SenderID. If condition reaches %,  SpfPermError is returned.&rs <- makeResolvSeed defaultResolvConfpass (IPv4 & IPv6):withResolver rs $ \rslv -> runSPF defaultLimit rslv "mew.org" "202.238.220.92"passwithResolver rs $ \rslv -> runSPF defaultLimit rslv "iij.ad.jp" "2001:240:bb5f:86c::1:41"pass hardfail:withResolver rs $ \rslv -> runSPF defaultLimit rslv "example.org" "192.0.2.1"hardfailredirect and include:withResolver rs $ \rslv -> runSPF defaultLimit rslv "gmail.com" "72.14.192.1"passwithResolver rs $ \rslv -> runSPF defaultLimit rslv "gmail.com" "72.14.128.1"softfaillimit:/let limit1 = defaultLimit { ipv4_masklen = 24 }withResolver rs $ \rslv -> runSPF limit1 rslv "gmail.com" "72.14.192.1"softfail,%&'()*+,%&'()*+ Safe-Inferred"u domain-auth&Replaces multiple WPSs to a single SP.v domain-authblines "foo\r\n\r\nbar\r\nbaz"["foo","","bar","baz"]blines "foo\r\n"["foo"]%wxyz{|}~uv Safe-Inferred"d Safe-Inferred- domain-auth0Type for temporary data to parse e-mail message.1 domain-authInitial value for -.2 domain-auth8Storing field key and field value to the temporary data.3 domain-auth)Storing body chunk to the temporary data.4 domain-auth Converting - to  .-./01234 Safe-Inferred"25 domain-authObtain   from a file.6 domain-authObtain   from .let out1 = finalizeMail $ pushBody "body" $ pushField "to" "val" $ pushField "from" "val" initialXMail,getMail "from: val\nto: val\n\nbody" == out1Truelet out2 = finalizeMail $ pushBody "body" $ pushField "to" "val" $ pushField "from" "val\tval" initialXMail1getMail "from: val\tval\nto: val\n\nbody" == out2Truelet out3 = finalizeMail $ pushBody "" $ pushField "to" "val" $ pushField "from" "val" initialXMail&getMail "from: val\nto: val\n" == out3True7 domain-auth!Parsing field value of tag=value. lookupPublicKey rslv "dk200510._domainkey.yahoo.co.jp"Just (PublicKey {public_size = 128, public_n = 124495277115430906234131617223399742059624761592171426860362133400468320289284068350453787798555522712914036293436636386707903510390018044090096883314714401752103035965668114514933570840775088208966674120428191313530595210688523478828022953238411688594634270571841869051696953556782155414877029327479844990933, public_e = 65537})withResolver rs $ \rslv -> lookupPublicKey rslv "20230601._domainkey.gmail.com"Just (PublicKey {public_size = 256, public_n = 20054049931062868895890884170436368122145070743595938421415808271536128118589158095389269883866014690926251520949836343482211446965168263353397278625494421205505467588876376305465260221818103647257858226961376710643349248303872103127777544119851941320649869060657585270523355729363214754986381410240666592048188131951162530964876952500210032559004364102337827202989395200573305906145708107347940692172630683838117810759589085094521858867092874903269345174914871903592244831151967447426692922405241398232069182007622735165026000699140578092635934951967194944536539675594791745699200646238889064236642593556016708235359, public_e = 65537}) Safe-Inferred"+A domain-auth0Extract a domain from a value of a header field.5extractDomain "Alice Brown "Just "example.com"extractDomain "\"Alice . Brown\" (Nickname here)"Just "example.com"'extractDomain "alice.brown@example.com"Just "example.com")extractDomain "Alice Brown "NothingA Safe-Inferred"4'B domain-authAbstract type for context to decide PRD(purported responsible domain) according to RFC 4407.C domain-authInitial context of PRD.D domain-auth8Pushing a field key and its value in to the PRD context.E domain-auth"Deciding PRD from the RPD context.%let maddr1 = "alice@alice.example.jp"!let maddr2 = "bob@bob.example.jp"%let maddr3 = "chris@chris.example.jp"#let maddr4 = "dave@dave.example.jp">decidePRD (pushPRD "from" "alice@alice.example.jp" initialPRD)Just "alice.example.jp":{ decidePRD (pushPRD "from" maddr1, $ pushPRD "from" maddr1 initialPRD):}Nothing:{"decidePRD (pushPRD "sender" maddr2 $ pushPRD "from" maddr1, $ pushPRD "from" maddr1 initialPRD):}Just "bob.example.jp":{"decidePRD (pushPRD "sender" maddr2" $ pushPRD "sender" maddr2 $ pushPRD "from" maddr1, $ pushPRD "from" maddr1 initialPRD):}Nothing:{'decidePRD (pushPRD "resent-from" maddr3" $ pushPRD "sender" maddr2" $ pushPRD "sender" maddr2 $ pushPRD "from" maddr1, $ pushPRD "from" maddr1 initialPRD):}Just "chris.example.jp":{)decidePRD (pushPRD "resent-sender" maddr4( $ pushPRD "resent-from" maddr3# $ pushPRD "sender" maddr2# $ pushPRD "sender" maddr2! $ pushPRD "from" maddr1- $ pushPRD "from" maddr1 initialPRD):}Just "dave.example.jp":{)decidePRD (pushPRD "resent-sender" maddr4' $ pushPRD "resent-from" maddr3" $ pushPRD "sender" maddr2% $ pushPRD "received" "dummy", $ pushPRD "from" maddr1 initialPRD):}Just "dave.example.jp":{)decidePRD (pushPRD "resent-sender" maddr4% $ pushPRD "received" "dummy"' $ pushPRD "resent-from" maddr3" $ pushPRD "sender" maddr2, $ pushPRD "from" maddr1 initialPRD):}Just "chris.example.jp":{%decidePRD (pushPRD "received" "dummy"* $ pushPRD "resent-sender" maddr4( $ pushPRD "resent-from" maddr3# $ pushPRD "sender" maddr2- $ pushPRD "from" maddr1 initialPRD):}Just "dave.example.jp"F domain-auth/Taking the value of From: from the RPD context.?decideFrom (pushPRD "from" "alice@alice.example.jp" initialPRD)Just "alice.example.jp"BCDEF Safe-Inferred4SBCDEFABCDEFA Safe-Inferred"5PH domain-auth&Canonicalized key for DKIM-Signature:.I domain-auth7Getting of the value of the "d" tag in DKIM-Signature:.J domain-auth7Getting of the value of the "s" tag in DKIM-Signature:.GHIJ Safe-Inferred"AK domain-authParsing DKIM-Signature:.:{!let dkim = BS8.concat [ "v=1; a=rsa-sha256; s=brisbane; d=example.com;\n" , " c=relaxed/simple; q=dns/txt; i=joe@football.example.com;\n" , " h=Received : From : To : Subject : Date : Message-ID;\n" , " bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=;\n" , " b=AuUoFEfDxTDkHlLXSZEpZj79LICEps6eda7W3deTVFOk4yAUoqOB\n" , " 4nujc7YopdG5dWLSdNg6xNAZpOPr+kHxt1IrE+NahM6L/LbvaHut\n" , " KVdkLLkpVaVVQPzeRDI009SO2Il5Lu7rDNH6mZckBdrIx0orEtZV\n"0 , " 4bmp/YzhwvcubU4=;" ]!in pPrintNoColor $ parseDKIM dkim:}Just ( DKIM { dkimVersion = "1"" , dkimSigAlgo = RSA_SHA256 , dkimSignature = "AuUoFEfDxTDkHlLXSZEpZj79LICEps6eda7W3deTVFOk4yAUoqOB4nujc7YopdG5dWLSdNg6xNAZpOPr+kHxt1IrE+NahM6L/LbvaHutKVdkLLkpVaVVQPzeRDI009SO2Il5Lu7rDNH6mZckBdrIx0orEtZV4bmp/YzhwvcubU4=" , dkimBodyHash = "2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8="( , dkimHeaderCanon = DKIM_RELAXED% , dkimBodyCanon = DKIM_SIMPLE% , dkimDomain0 = "example.com" , dkimFields = [ "received" , "from" , "to" , "subject" , "date" , "message-id" ] , dkimLength = Nothing$ , dkimSelector0 = "brisbane" } ):{!let dkim = BS8.concat [ "v=1; a=rsa-sha256; s=brisbane; d=example.com;\n" , " q=dns/txt; i=joe@football.example.com;\n" , " h=Received : From : To : Subject : Date : Message-ID;\n" , " bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=;\n" , " b=AuUoFEfDxTDkHlLXSZEpZj79LICEps6eda7W3deTVFOk4yAUoqOB\n" , " 4nujc7YopdG5dWLSdNg6xNAZpOPr+kHxt1IrE+NahM6L/LbvaHut\n" , " KVdkLLkpVaVVQPzeRDI009SO2Il5Lu7rDNH6mZckBdrIx0orEtZV\n"/ , " 4bmp/YzhwvcubU4=;" ]!in pPrintNoColor $ parseDKIM dkim:}Just ( DKIM { dkimVersion = "1"" , dkimSigAlgo = RSA_SHA256 , dkimSignature = "AuUoFEfDxTDkHlLXSZEpZj79LICEps6eda7W3deTVFOk4yAUoqOB4nujc7YopdG5dWLSdNg6xNAZpOPr+kHxt1IrE+NahM6L/LbvaHutKVdkLLkpVaVVQPzeRDI009SO2Il5Lu7rDNH6mZckBdrIx0orEtZV4bmp/YzhwvcubU4=" , dkimBodyHash = "2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8="' , dkimHeaderCanon = DKIM_SIMPLE% , dkimBodyCanon = DKIM_SIMPLE% , dkimDomain0 = "example.com" , dkimFields = [ "received" , "from" , "to" , "subject" , "date" , "message-id" ] , dkimLength = Nothing$ , dkimSelector0 = "brisbane" } )K Safe-Inferred"B:L domain-auth&Abstract type for DomainKey-Signature:M domain-auth+Canonicalized key for DomainKey-Signature:.N domain-auth"1 ,"Date: Thu, 4 Apr 2024 10:53:59 +0900": ,"From: Kazu Yamamoto " ,"MIME-Version: 1.0"8 ,"Content-Type: text/plain; charset=\"UTF-8\"" ,"" ,"test" ]/ mail = getMail $ BS8.intercalate "\r\n" lst/in withResolver rs $ \rslv -> runDKIM rslv mail:}passR domain-auth Verifying   with DKIM. The value of DKIM-Signature: should be parsed beforehand.QRKGIJHQRKGIJH Safe-Inferred"K Safe-Inferred"L|S domain-auth Verifying   with DomainKeys.T domain-auth Verifying   with DomainKeys. The value of DomainKey-Signature: should be parsed beforehand.STPLNOMSTPLNOM Safe-InferredL -./056123489:;<=>?@7LSTPNOMGQRKIJHBACDEF%&'()*,+     ! " " # $ % & ' ' ( ) * + , - . /0123456789:;<=>?@AABCDEFGHHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmno p q r s t u v w x y z { | } ~             af(domain-auth-0.2.4-LLXu3zpuVG15oUWvpqMosXNetwork.DomainAuth.MailNetwork.DomainAuth.TypesNetwork.DomainAuth.SPFNetwork.DomainAuth.PRDNetwork.DomainAuth.DKIMNetwork.DomainAuth.DK domain-authNetwork.DomainAuth.DKIM.BtagNetwork.DomainAuth.Mail.TypesNetwork.DomainAuth.PRD.LexerNetwork.DomainAuth.SPF.TypesNetwork.DomainAuth.SPF.ParserNetwork.DomainAuth.SPF.ResolverNetwork.DomainAuth.SPF.EvalNetwork.DomainAuth.Utils Network.DomainAuth.Pubkey.Base64Network.DomainAuth.Mail.XMailNetwork.DomainAuth.Mail.ParserNetwork.DomainAuth.Mail.Mail Network.DomainAuth.Pubkey.RSAPubNetwork.DomainAuth.PRD.DomainNetwork.DomainAuth.PRD.PRDNetwork.DomainAuth.DKIM.TypesNetwork.DomainAuth.DKIM.ParserNetwork.DomainAuth.DK.TypesNetwork.DomainAuth.DK.ParserNetwork.DomainAuth.DKIM.VerifyNetwork.DomainAuth.DK.VerifyNetwork.DomainAuthBody FieldValueFieldKey CanonFieldKeyFieldfieldSearchKeyfieldKey fieldValueHeaderMail mailHeadermailBody RawBodyChunk RawFieldValue RawFieldKeyRawMailisEmptycanonicalizeKeyDAResultDAPass DAHardFail DASoftFail DANeutralDAFail DATempError DAPermErrorDANoneDAPolicy DANxDomain DADiscard DAUnknown$fShowDAResult $fEqDAResult$fEnumDAResult$fBoundedDAResultLimitlimit ipv4_masklen ipv6_masklenreject_plus_all defaultLimitrunSPFXMail xmailHeader xmailBody initialXMail pushFieldpushBody finalizeMailreadMailgetMailparseTaggedValue lookupField fieldsFrom fieldsAfter fieldsWithfieldValueFoldedfieldValueUnfoldedfromBody fromBodyWithremoveTrailingEmptyLine extractDomainPRD initialPRDpushPRD decidePRD decideFromDKIM dkimFieldKey dkimDomain dkimSelector parseDKIMDK dkFieldKeydkDomain dkSelectorparseDKrunDKIMrunDKIM'runDKrunDK'removeBtagValueRawFieldRawBody RawHeader structuredSpfSeq SS_SpfSeq SS_IF_Pass SS_IPv6Ranges SS_IPv4Ranges SS_IPv6Range SS_IPv4RangeSS_AllSPF SPF_RedirectSPF_All SPF_IncludeSPF_MX SPF_Address SPF_IPv6Range SPF_IPv4Range Qualifier Q_Neutral Q_Softfail Q_HardFailQ_PassqualifierSymbolparseSPF resolveSPFevalSPF%iproute-1.7.12-8t5slXIMmiWIRW8BtxLxxV Data.IP.AddrIP-dns-4.2.0-E9iB8Lj4tuS9qshflsOIue-dns-internalNetwork.DNS.Types.InternalDomain reduceWSPblinesCook FWSRemovercrlf+++empty!!! appendCRLF appendCRLF'appendCRLFWith concatCRLFconcatCRLFWithinSPoutSP removeFWSremoveTrailingWSPhasTrailingWSPchopbreak' isAlphaNumisDigitisUpperisLowerisSpacecCRcLFcSPcTBcPluscSlashcEqualcSmallAcAcZerocColon cSemiColondecodedecode'enmlookupPublicKey dkimSelector0 dkimLength dkimFields dkimDomain0 dkimBodyCanondkimHeaderCanon dkimBodyHash dkimSignature dkimSigAlgo dkimVersion DkimCanonAlgo DKIM_RELAXED DKIM_SIMPLE DkimSigAlgo RSA_SHA256RSA_SHA1 dkSelector0dkFields dkDomain0 dkCanonAlgo dkSignature dkAlgorithmDkFields DkCanonAlgoDK_NOFWS DK_SIMPLE DkAlgorithm DK_RSA_SHA1 verifyDKIM prepareDKIMverifyDK prepareDK