{-# LANGUAGE RecordWildCards #-}

-- | Stability: experimental
-- This module contains functions to further decode
-- [FIDO Metadata Service](https://fidoalliance.org/specs/mds/fido-metadata-service-v3.0-ps-20210518.html)
-- IDL types defined in 'Crypto.WebAuthn.Metadata.Service.WebIDL' into the Haskell-specific types defined in 'Crypto.WebAuthn.Metadata.Service.Types'
module Crypto.WebAuthn.Metadata.Service.Decode
  ( decodeMetadataPayload,
    decodeMetadataEntry,
  )
where

import qualified Crypto.WebAuthn.Metadata.Service.Types as ServiceTypes
import qualified Crypto.WebAuthn.Metadata.Service.WebIDL as ServiceIDL
import Crypto.WebAuthn.Metadata.Statement.Decode (decodeAAGUID, decodeCertificate, decodeMetadataStatement, decodeSubjectKeyIdentifier)
import qualified Crypto.WebAuthn.Metadata.WebIDL as IDL
import Data.Bifunctor (first)
import Data.Either (lefts, rights)
import Data.Hourglass (Date, DateTime (dtDate), ISO8601_Date (ISO8601_Date), timeParse)
import qualified Data.List.NonEmpty as NE
import Data.Maybe (mapMaybe)
import Data.Text (Text)
import qualified Data.Text as Text
import Data.These (These (That, These, This))

-- | Decodes a 'ServiceTypes.MetadataPayload' from a 'ServiceIDL.MetadataBLOBPayload',
-- discarding any 'ServiceIDL.MetadataBLOBPayloadEntry' that are not relevant to webauthn.
-- This includes entries of the protocol family 'StatementIDL.ProtocolFamilyUAF'
-- and entries whose 'StatementIDL.attestationTypes' doesn't include either
-- 'Registry.ATTESTATION_BASIC_FULL' or 'Registry.ATTESTATION_ATTCA'
decodeMetadataPayload :: ServiceIDL.MetadataBLOBPayload -> These (NE.NonEmpty Text) ServiceTypes.MetadataPayload
decodeMetadataPayload :: MetadataBLOBPayload -> These (NonEmpty Text) MetadataPayload
decodeMetadataPayload ServiceIDL.MetadataBLOBPayload {Int
[MetadataBLOBPayloadEntry]
Maybe Text
Text
legalHeader :: Maybe Text
no :: Int
nextUpdate :: Text
entries :: [MetadataBLOBPayloadEntry]
$sel:legalHeader:MetadataBLOBPayload :: MetadataBLOBPayload -> Maybe Text
$sel:no:MetadataBLOBPayload :: MetadataBLOBPayload -> Int
$sel:nextUpdate:MetadataBLOBPayload :: MetadataBLOBPayload -> Text
$sel:entries:MetadataBLOBPayload :: MetadataBLOBPayload -> [MetadataBLOBPayloadEntry]
..} = do
  let mpLegalHeader :: Maybe Text
mpLegalHeader = Maybe Text
legalHeader
      mpNo :: Int
mpNo = Int
no
  Date
mpNextUpdate <- (Text -> These (NonEmpty Text) Date)
-> (Date -> These (NonEmpty Text) Date)
-> Either Text Date
-> These (NonEmpty Text) Date
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (NonEmpty Text -> These (NonEmpty Text) Date
forall a b. a -> These a b
This (NonEmpty Text -> These (NonEmpty Text) Date)
-> (Text -> NonEmpty Text) -> Text -> These (NonEmpty Text) Date
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> [Text] -> NonEmpty Text
forall a. a -> [a] -> NonEmpty a
NE.:| [])) Date -> These (NonEmpty Text) Date
forall a b. b -> These a b
That (Either Text Date -> These (NonEmpty Text) Date)
-> Either Text Date -> These (NonEmpty Text) Date
forall a b. (a -> b) -> a -> b
$ Text -> Either Text Date
decodeDate Text
nextUpdate
  let errorOrEntries :: [Either Text (NonEmpty SomeMetadataEntry)]
errorOrEntries = (MetadataBLOBPayloadEntry
 -> Maybe (Either Text (NonEmpty SomeMetadataEntry)))
-> [MetadataBLOBPayloadEntry]
-> [Either Text (NonEmpty SomeMetadataEntry)]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe MetadataBLOBPayloadEntry
-> Maybe (Either Text (NonEmpty SomeMetadataEntry))
decodeMetadataEntry [MetadataBLOBPayloadEntry]
entries
  let errors :: [Text]
errors = [Either Text (NonEmpty SomeMetadataEntry)] -> [Text]
forall a b. [Either a b] -> [a]
lefts [Either Text (NonEmpty SomeMetadataEntry)]
errorOrEntries
  let decodedEntries :: [NonEmpty SomeMetadataEntry]
decodedEntries = [Either Text (NonEmpty SomeMetadataEntry)]
-> [NonEmpty SomeMetadataEntry]
forall a b. [Either a b] -> [b]
rights [Either Text (NonEmpty SomeMetadataEntry)]
errorOrEntries
  let mpEntries :: [SomeMetadataEntry]
mpEntries = (NonEmpty SomeMetadataEntry -> [SomeMetadataEntry])
-> [NonEmpty SomeMetadataEntry] -> [SomeMetadataEntry]
forall m a. Monoid m => (a -> m) -> [a] -> m
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap NonEmpty SomeMetadataEntry -> [SomeMetadataEntry]
forall a. NonEmpty a -> [a]
NE.toList [NonEmpty SomeMetadataEntry]
decodedEntries
  case [Text] -> Maybe (NonEmpty Text)
forall a. [a] -> Maybe (NonEmpty a)
NE.nonEmpty [Text]
errors of
    Maybe (NonEmpty Text)
Nothing -> MetadataPayload -> These (NonEmpty Text) MetadataPayload
forall a b. b -> These a b
That (ServiceTypes.MetadataPayload {Int
[SomeMetadataEntry]
Maybe Text
Date
mpLegalHeader :: Maybe Text
mpNo :: Int
mpNextUpdate :: Date
mpEntries :: [SomeMetadataEntry]
mpLegalHeader :: Maybe Text
mpNo :: Int
mpNextUpdate :: Date
mpEntries :: [SomeMetadataEntry]
..})
    Just NonEmpty Text
a -> NonEmpty Text
-> MetadataPayload -> These (NonEmpty Text) MetadataPayload
forall a b. a -> b -> These a b
These NonEmpty Text
a (ServiceTypes.MetadataPayload {Int
[SomeMetadataEntry]
Maybe Text
Date
mpLegalHeader :: Maybe Text
mpNo :: Int
mpNextUpdate :: Date
mpEntries :: [SomeMetadataEntry]
mpLegalHeader :: Maybe Text
mpNo :: Int
mpNextUpdate :: Date
mpEntries :: [SomeMetadataEntry]
..})

liftEitherMaybe :: Either (Maybe a) b -> Maybe (Either a b)
liftEitherMaybe :: forall a b. Either (Maybe a) b -> Maybe (Either a b)
liftEitherMaybe (Left Maybe a
Nothing) = Maybe (Either a b)
forall a. Maybe a
Nothing
liftEitherMaybe (Left (Just a
a)) = Either a b -> Maybe (Either a b)
forall a. a -> Maybe a
Just (Either a b -> Maybe (Either a b))
-> Either a b -> Maybe (Either a b)
forall a b. (a -> b) -> a -> b
$ a -> Either a b
forall a b. a -> Either a b
Left a
a
liftEitherMaybe (Right b
b) = Either a b -> Maybe (Either a b)
forall a. a -> Maybe a
Just (Either a b -> Maybe (Either a b))
-> Either a b -> Maybe (Either a b)
forall a b. (a -> b) -> a -> b
$ b -> Either a b
forall a b. b -> Either a b
Right b
b

-- | [(spec)](https://fidoalliance.org/specs/mds/fido-metadata-service-v3.0-ps-20210518.html#metadata-blob-payload-entry-dictionary)
-- | Decodes a 'ServiceIDL.MetadataBLOBPayloadEntry' into one or more
-- 'ServiceTypes.SomeMetadataEntry'. If the entry is not relevant for webauthn
-- (i.e. UAF authenticators or FIDO2 authenticators that only support basic
-- surrogate attestation), then this function returns 'Nothing'. If an error
-- occured during decoding, 'Left' is returned.
decodeMetadataEntry :: ServiceIDL.MetadataBLOBPayloadEntry -> Maybe (Either Text (NE.NonEmpty ServiceTypes.SomeMetadataEntry))
decodeMetadataEntry :: MetadataBLOBPayloadEntry
-> Maybe (Either Text (NonEmpty SomeMetadataEntry))
decodeMetadataEntry ServiceIDL.MetadataBLOBPayloadEntry {Maybe (NonEmpty Text)
Maybe (NonEmpty BiometricStatusReport)
Maybe AAID
Maybe MetadataStatement
Maybe AAGUID
NonEmpty StatusReport
Text
aaid :: Maybe AAID
aaguid :: Maybe AAGUID
attestationCertificateKeyIdentifiers :: Maybe (NonEmpty Text)
metadataStatement :: Maybe MetadataStatement
biometricStatusReports :: Maybe (NonEmpty BiometricStatusReport)
statusReports :: NonEmpty StatusReport
timeOfLastStatusChange :: Text
$sel:aaid:MetadataBLOBPayloadEntry :: MetadataBLOBPayloadEntry -> Maybe AAID
$sel:aaguid:MetadataBLOBPayloadEntry :: MetadataBLOBPayloadEntry -> Maybe AAGUID
$sel:attestationCertificateKeyIdentifiers:MetadataBLOBPayloadEntry :: MetadataBLOBPayloadEntry -> Maybe (NonEmpty Text)
$sel:metadataStatement:MetadataBLOBPayloadEntry :: MetadataBLOBPayloadEntry -> Maybe MetadataStatement
$sel:biometricStatusReports:MetadataBLOBPayloadEntry :: MetadataBLOBPayloadEntry -> Maybe (NonEmpty BiometricStatusReport)
$sel:statusReports:MetadataBLOBPayloadEntry :: MetadataBLOBPayloadEntry -> NonEmpty StatusReport
$sel:timeOfLastStatusChange:MetadataBLOBPayloadEntry :: MetadataBLOBPayloadEntry -> Text
..} = Either (Maybe Text) (NonEmpty SomeMetadataEntry)
-> Maybe (Either Text (NonEmpty SomeMetadataEntry))
forall a b. Either (Maybe a) b -> Maybe (Either a b)
liftEitherMaybe (Either (Maybe Text) (NonEmpty SomeMetadataEntry)
 -> Maybe (Either Text (NonEmpty SomeMetadataEntry)))
-> Either (Maybe Text) (NonEmpty SomeMetadataEntry)
-> Maybe (Either Text (NonEmpty SomeMetadataEntry))
forall a b. (a -> b) -> a -> b
$
  case (Maybe AAID
aaid, Maybe AAGUID
aaguid, Maybe (NonEmpty Text)
attestationCertificateKeyIdentifiers) of
    (Just AAID
_aaid, Maybe AAGUID
Nothing, Maybe (NonEmpty Text)
Nothing) ->
      -- This is an UAF entry, we can skip it since it's not relevant for webauthn
      Maybe Text -> Either (Maybe Text) (NonEmpty SomeMetadataEntry)
forall a b. a -> Either a b
Left Maybe Text
forall a. Maybe a
Nothing
    (Maybe AAID
Nothing, Just AAGUID
aaguid, Maybe (NonEmpty Text)
Nothing) -> do
      -- This is a FIDO 2 entry
      AuthenticatorIdentifier 'Fido2
meIdentifier <- (Text -> Maybe Text)
-> Either Text (AuthenticatorIdentifier 'Fido2)
-> Either (Maybe Text) (AuthenticatorIdentifier 'Fido2)
forall a b c. (a -> b) -> Either a c -> Either b c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first Text -> Maybe Text
forall a. a -> Maybe a
Just (Either Text (AuthenticatorIdentifier 'Fido2)
 -> Either (Maybe Text) (AuthenticatorIdentifier 'Fido2))
-> Either Text (AuthenticatorIdentifier 'Fido2)
-> Either (Maybe Text) (AuthenticatorIdentifier 'Fido2)
forall a b. (a -> b) -> a -> b
$ AAGUID -> Either Text (AuthenticatorIdentifier 'Fido2)
decodeAAGUID AAGUID
aaguid
      Maybe MetadataStatement
meMetadataStatement <- (MetadataStatement -> Either (Maybe Text) MetadataStatement)
-> Maybe MetadataStatement
-> Either (Maybe Text) (Maybe MetadataStatement)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> Maybe a -> f (Maybe b)
traverse MetadataStatement -> Either (Maybe Text) MetadataStatement
decodeMetadataStatement Maybe MetadataStatement
metadataStatement
      NonEmpty StatusReport
meStatusReports <- (Text -> Maybe Text)
-> Either Text (NonEmpty StatusReport)
-> Either (Maybe Text) (NonEmpty StatusReport)
forall a b c. (a -> b) -> Either a c -> Either b c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first Text -> Maybe Text
forall a. a -> Maybe a
Just (Either Text (NonEmpty StatusReport)
 -> Either (Maybe Text) (NonEmpty StatusReport))
-> Either Text (NonEmpty StatusReport)
-> Either (Maybe Text) (NonEmpty StatusReport)
forall a b. (a -> b) -> a -> b
$ (StatusReport -> Either Text StatusReport)
-> NonEmpty StatusReport -> Either Text (NonEmpty StatusReport)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> NonEmpty a -> f (NonEmpty b)
traverse StatusReport -> Either Text StatusReport
decodeStatusReport NonEmpty StatusReport
statusReports
      Date
meTimeOfLastStatusChange <- (Text -> Maybe Text)
-> Either Text Date -> Either (Maybe Text) Date
forall a b c. (a -> b) -> Either a c -> Either b c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first Text -> Maybe Text
forall a. a -> Maybe a
Just (Either Text Date -> Either (Maybe Text) Date)
-> Either Text Date -> Either (Maybe Text) Date
forall a b. (a -> b) -> a -> b
$ Text -> Either Text Date
decodeDate Text
timeOfLastStatusChange
      NonEmpty SomeMetadataEntry
-> Either (Maybe Text) (NonEmpty SomeMetadataEntry)
forall a b. b -> Either a b
Right (NonEmpty SomeMetadataEntry
 -> Either (Maybe Text) (NonEmpty SomeMetadataEntry))
-> NonEmpty SomeMetadataEntry
-> Either (Maybe Text) (NonEmpty SomeMetadataEntry)
forall a b. (a -> b) -> a -> b
$ SomeMetadataEntry -> NonEmpty SomeMetadataEntry
forall a. a -> NonEmpty a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (SomeMetadataEntry -> NonEmpty SomeMetadataEntry)
-> SomeMetadataEntry -> NonEmpty SomeMetadataEntry
forall a b. (a -> b) -> a -> b
$ MetadataEntry 'Fido2 -> SomeMetadataEntry
forall (p :: ProtocolKind).
SingI p =>
MetadataEntry p -> SomeMetadataEntry
ServiceTypes.SomeMetadataEntry ServiceTypes.MetadataEntry {Maybe MetadataStatement
NonEmpty StatusReport
Date
AuthenticatorIdentifier 'Fido2
meIdentifier :: AuthenticatorIdentifier 'Fido2
meMetadataStatement :: Maybe MetadataStatement
meStatusReports :: NonEmpty StatusReport
meTimeOfLastStatusChange :: Date
meIdentifier :: AuthenticatorIdentifier 'Fido2
meMetadataStatement :: Maybe MetadataStatement
meStatusReports :: NonEmpty StatusReport
meTimeOfLastStatusChange :: Date
..}
    (Maybe AAID
Nothing, Maybe AAGUID
Nothing, Just NonEmpty Text
attestationCertificateKeyIdentifiers) -> do
      -- This is a FIDO U2F entry
      NonEmpty (AuthenticatorIdentifier 'FidoU2F)
identifiers <- (Text -> Maybe Text)
-> Either Text (NonEmpty (AuthenticatorIdentifier 'FidoU2F))
-> Either
     (Maybe Text) (NonEmpty (AuthenticatorIdentifier 'FidoU2F))
forall a b c. (a -> b) -> Either a c -> Either b c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first Text -> Maybe Text
forall a. a -> Maybe a
Just (Either Text (NonEmpty (AuthenticatorIdentifier 'FidoU2F))
 -> Either
      (Maybe Text) (NonEmpty (AuthenticatorIdentifier 'FidoU2F)))
-> Either Text (NonEmpty (AuthenticatorIdentifier 'FidoU2F))
-> Either
     (Maybe Text) (NonEmpty (AuthenticatorIdentifier 'FidoU2F))
forall a b. (a -> b) -> a -> b
$ (Text -> Either Text (AuthenticatorIdentifier 'FidoU2F))
-> NonEmpty Text
-> Either Text (NonEmpty (AuthenticatorIdentifier 'FidoU2F))
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> NonEmpty a -> f (NonEmpty b)
traverse Text -> Either Text (AuthenticatorIdentifier 'FidoU2F)
decodeSubjectKeyIdentifier NonEmpty Text
attestationCertificateKeyIdentifiers
      Maybe MetadataStatement
meMetadataStatement <- (MetadataStatement -> Either (Maybe Text) MetadataStatement)
-> Maybe MetadataStatement
-> Either (Maybe Text) (Maybe MetadataStatement)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> Maybe a -> f (Maybe b)
traverse MetadataStatement -> Either (Maybe Text) MetadataStatement
decodeMetadataStatement Maybe MetadataStatement
metadataStatement
      NonEmpty StatusReport
meStatusReports <- (Text -> Maybe Text)
-> Either Text (NonEmpty StatusReport)
-> Either (Maybe Text) (NonEmpty StatusReport)
forall a b c. (a -> b) -> Either a c -> Either b c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first Text -> Maybe Text
forall a. a -> Maybe a
Just (Either Text (NonEmpty StatusReport)
 -> Either (Maybe Text) (NonEmpty StatusReport))
-> Either Text (NonEmpty StatusReport)
-> Either (Maybe Text) (NonEmpty StatusReport)
forall a b. (a -> b) -> a -> b
$ (StatusReport -> Either Text StatusReport)
-> NonEmpty StatusReport -> Either Text (NonEmpty StatusReport)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> NonEmpty a -> f (NonEmpty b)
traverse StatusReport -> Either Text StatusReport
decodeStatusReport NonEmpty StatusReport
statusReports
      Date
meTimeOfLastStatusChange <- (Text -> Maybe Text)
-> Either Text Date -> Either (Maybe Text) Date
forall a b c. (a -> b) -> Either a c -> Either b c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first Text -> Maybe Text
forall a. a -> Maybe a
Just (Either Text Date -> Either (Maybe Text) Date)
-> Either Text Date -> Either (Maybe Text) Date
forall a b. (a -> b) -> a -> b
$ Text -> Either Text Date
decodeDate Text
timeOfLastStatusChange
      NonEmpty SomeMetadataEntry
-> Either (Maybe Text) (NonEmpty SomeMetadataEntry)
forall a b. b -> Either a b
Right (NonEmpty SomeMetadataEntry
 -> Either (Maybe Text) (NonEmpty SomeMetadataEntry))
-> NonEmpty SomeMetadataEntry
-> Either (Maybe Text) (NonEmpty SomeMetadataEntry)
forall a b. (a -> b) -> a -> b
$ (AuthenticatorIdentifier 'FidoU2F -> SomeMetadataEntry)
-> NonEmpty (AuthenticatorIdentifier 'FidoU2F)
-> NonEmpty SomeMetadataEntry
forall a b. (a -> b) -> NonEmpty a -> NonEmpty b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\AuthenticatorIdentifier 'FidoU2F
meIdentifier -> MetadataEntry 'FidoU2F -> SomeMetadataEntry
forall (p :: ProtocolKind).
SingI p =>
MetadataEntry p -> SomeMetadataEntry
ServiceTypes.SomeMetadataEntry ServiceTypes.MetadataEntry {Maybe MetadataStatement
NonEmpty StatusReport
Date
AuthenticatorIdentifier 'FidoU2F
meIdentifier :: AuthenticatorIdentifier 'FidoU2F
meMetadataStatement :: Maybe MetadataStatement
meStatusReports :: NonEmpty StatusReport
meTimeOfLastStatusChange :: Date
meMetadataStatement :: Maybe MetadataStatement
meStatusReports :: NonEmpty StatusReport
meTimeOfLastStatusChange :: Date
meIdentifier :: AuthenticatorIdentifier 'FidoU2F
..}) NonEmpty (AuthenticatorIdentifier 'FidoU2F)
identifiers
    (Maybe AAID
Nothing, Maybe AAGUID
Nothing, Maybe (NonEmpty Text)
Nothing) ->
      Maybe Text -> Either (Maybe Text) (NonEmpty SomeMetadataEntry)
forall a b. a -> Either a b
Left (Maybe Text -> Either (Maybe Text) (NonEmpty SomeMetadataEntry))
-> Maybe Text -> Either (Maybe Text) (NonEmpty SomeMetadataEntry)
forall a b. (a -> b) -> a -> b
$ Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"None of aaid, aaguid or attestationCertificateKeyIdentifiers are set for this entry"
    (Maybe AAID, Maybe AAGUID, Maybe (NonEmpty Text))
_ ->
      Maybe Text -> Either (Maybe Text) (NonEmpty SomeMetadataEntry)
forall a b. a -> Either a b
Left (Maybe Text -> Either (Maybe Text) (NonEmpty SomeMetadataEntry))
-> Maybe Text -> Either (Maybe Text) (NonEmpty SomeMetadataEntry)
forall a b. (a -> b) -> a -> b
$ Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"Multiple of aaid, aaguid and/or attestationCertificateKeyIdentifiers are set for this entry"

decodeStatusReport :: ServiceIDL.StatusReport -> Either Text ServiceTypes.StatusReport
decodeStatusReport :: StatusReport -> Either Text StatusReport
decodeStatusReport ServiceIDL.StatusReport {Maybe UnsignedLong
Maybe Text
AuthenticatorStatus
status :: AuthenticatorStatus
effectiveDate :: Maybe Text
authenticatorVersion :: Maybe UnsignedLong
certificate :: Maybe Text
url :: Maybe Text
certificationDescriptor :: Maybe Text
certificateNumber :: Maybe Text
certificationPolicyVersion :: Maybe Text
certificationRequirementsVersion :: Maybe Text
$sel:status:StatusReport :: StatusReport -> AuthenticatorStatus
$sel:effectiveDate:StatusReport :: StatusReport -> Maybe Text
$sel:authenticatorVersion:StatusReport :: StatusReport -> Maybe UnsignedLong
$sel:certificate:StatusReport :: StatusReport -> Maybe Text
$sel:url:StatusReport :: StatusReport -> Maybe Text
$sel:certificationDescriptor:StatusReport :: StatusReport -> Maybe Text
$sel:certificateNumber:StatusReport :: StatusReport -> Maybe Text
$sel:certificationPolicyVersion:StatusReport :: StatusReport -> Maybe Text
$sel:certificationRequirementsVersion:StatusReport :: StatusReport -> Maybe Text
..} = do
  let srStatus :: AuthenticatorStatus
srStatus = AuthenticatorStatus
status
  Maybe Date
srEffectiveDate <- (Text -> Either Text Date)
-> Maybe Text -> Either Text (Maybe Date)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> Maybe a -> f (Maybe b)
traverse Text -> Either Text Date
decodeDate Maybe Text
effectiveDate
  let srAuthenticatorVersion :: Maybe UnsignedLong
srAuthenticatorVersion = Maybe UnsignedLong
authenticatorVersion
  Maybe SignedCertificate
srCertificate <- (Text -> Either Text SignedCertificate)
-> Maybe Text -> Either Text (Maybe SignedCertificate)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> Maybe a -> f (Maybe b)
traverse Text -> Either Text SignedCertificate
decodeCertificate Maybe Text
certificate
  let srUrl :: Maybe Text
srUrl = Maybe Text
url
      srCertificationDescriptor :: Maybe Text
srCertificationDescriptor = Maybe Text
certificationDescriptor
      srCertificateNumber :: Maybe Text
srCertificateNumber = Maybe Text
certificateNumber
      srCertificationPolicyVersion :: Maybe Text
srCertificationPolicyVersion = Maybe Text
certificationPolicyVersion
      srCertificationRequirementsVersion :: Maybe Text
srCertificationRequirementsVersion = Maybe Text
certificationRequirementsVersion
  StatusReport -> Either Text StatusReport
forall a. a -> Either Text a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ServiceTypes.StatusReport {Maybe UnsignedLong
Maybe Text
Maybe SignedCertificate
Maybe Date
AuthenticatorStatus
srStatus :: AuthenticatorStatus
srEffectiveDate :: Maybe Date
srAuthenticatorVersion :: Maybe UnsignedLong
srCertificate :: Maybe SignedCertificate
srUrl :: Maybe Text
srCertificationDescriptor :: Maybe Text
srCertificateNumber :: Maybe Text
srCertificationPolicyVersion :: Maybe Text
srCertificationRequirementsVersion :: Maybe Text
srStatus :: AuthenticatorStatus
srEffectiveDate :: Maybe Date
srAuthenticatorVersion :: Maybe UnsignedLong
srCertificate :: Maybe SignedCertificate
srUrl :: Maybe Text
srCertificationDescriptor :: Maybe Text
srCertificateNumber :: Maybe Text
srCertificationPolicyVersion :: Maybe Text
srCertificationRequirementsVersion :: Maybe Text
..}

decodeDate :: IDL.DOMString -> Either Text Date
decodeDate :: Text -> Either Text Date
decodeDate Text
text = case ISO8601_Date -> String -> Maybe DateTime
forall format.
TimeFormat format =>
format -> String -> Maybe DateTime
timeParse ISO8601_Date
ISO8601_Date (Text -> String
Text.unpack Text
text) of
  Maybe DateTime
Nothing -> Text -> Either Text Date
forall a b. a -> Either a b
Left (Text -> Either Text Date) -> Text -> Either Text Date
forall a b. (a -> b) -> a -> b
$ Text
"Could not parse ISO 8601 date: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
text
  Just DateTime
dt -> Date -> Either Text Date
forall a b. b -> Either a b
Right (Date -> Either Text Date) -> Date -> Either Text Date
forall a b. (a -> b) -> a -> b
$ DateTime -> Date
dtDate DateTime
dt