{-# 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.WebIDL as IDL
import Data.Bifunctor (first)
import Data.Hourglass (Date, DateTime (dtDate), ISO8601_Date (ISO8601_Date), timeParse)
import Data.List.NonEmpty (NonEmpty)
import qualified Data.List.NonEmpty as NE
import Data.Maybe (mapMaybe)
import Data.Text (Text)
import qualified Data.Text as Text

-- | 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 -> Either Text ServiceTypes.MetadataPayload
decodeMetadataPayload :: MetadataBLOBPayload -> Either Text MetadataPayload
decodeMetadataPayload ServiceIDL.MetadataBLOBPayload {Int
[MetadataBLOBPayloadEntry]
Maybe Text
Text
$sel:entries:MetadataBLOBPayload :: MetadataBLOBPayload -> [MetadataBLOBPayloadEntry]
$sel:nextUpdate:MetadataBLOBPayload :: MetadataBLOBPayload -> Text
$sel:no:MetadataBLOBPayload :: MetadataBLOBPayload -> Int
$sel:legalHeader:MetadataBLOBPayload :: MetadataBLOBPayload -> Maybe Text
entries :: [MetadataBLOBPayloadEntry]
nextUpdate :: Text
no :: Int
legalHeader :: Maybe Text
..} = do
  let mpLegalHeader :: Maybe Text
mpLegalHeader = Maybe Text
legalHeader
      mpNo :: Int
mpNo = Int
no
  Date
mpNextUpdate <- Text -> Either Text Date
decodeDate Text
nextUpdate
  [NonEmpty SomeMetadataEntry]
decodedEntries <- [Either Text (NonEmpty SomeMetadataEntry)]
-> Either Text [NonEmpty SomeMetadataEntry]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence ([Either Text (NonEmpty SomeMetadataEntry)]
 -> Either Text [NonEmpty SomeMetadataEntry])
-> [Either Text (NonEmpty SomeMetadataEntry)]
-> Either Text [NonEmpty SomeMetadataEntry]
forall a b. (a -> b) -> a -> b
$ (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 mpEntries :: [SomeMetadataEntry]
mpEntries = (NonEmpty SomeMetadataEntry -> [SomeMetadataEntry])
-> [NonEmpty SomeMetadataEntry] -> [SomeMetadataEntry]
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
  MetadataPayload -> Either Text MetadataPayload
forall (f :: * -> *) a. Applicative f => a -> f a
pure MetadataPayload :: Maybe Text -> Int -> Date -> [SomeMetadataEntry] -> MetadataPayload
ServiceTypes.MetadataPayload {Int
[SomeMetadataEntry]
Maybe Text
Date
mpEntries :: [SomeMetadataEntry]
mpNextUpdate :: Date
mpNo :: Int
mpLegalHeader :: Maybe Text
mpEntries :: [SomeMetadataEntry]
mpNextUpdate :: Date
mpNo :: Int
mpLegalHeader :: Maybe Text
..}

liftEitherMaybe :: Either (Maybe a) b -> Maybe (Either a b)
liftEitherMaybe :: 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 (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
Text
NonEmpty StatusReport
$sel:timeOfLastStatusChange:MetadataBLOBPayloadEntry :: MetadataBLOBPayloadEntry -> Text
$sel:statusReports:MetadataBLOBPayloadEntry :: MetadataBLOBPayloadEntry -> NonEmpty StatusReport
$sel:biometricStatusReports:MetadataBLOBPayloadEntry :: MetadataBLOBPayloadEntry -> Maybe (NonEmpty BiometricStatusReport)
$sel:metadataStatement:MetadataBLOBPayloadEntry :: MetadataBLOBPayloadEntry -> Maybe MetadataStatement
$sel:attestationCertificateKeyIdentifiers:MetadataBLOBPayloadEntry :: MetadataBLOBPayloadEntry -> Maybe (NonEmpty Text)
$sel:aaguid:MetadataBLOBPayloadEntry :: MetadataBLOBPayloadEntry -> Maybe AAGUID
$sel:aaid:MetadataBLOBPayloadEntry :: MetadataBLOBPayloadEntry -> Maybe AAID
timeOfLastStatusChange :: Text
statusReports :: NonEmpty StatusReport
biometricStatusReports :: Maybe (NonEmpty BiometricStatusReport)
metadataStatement :: Maybe MetadataStatement
attestationCertificateKeyIdentifiers :: Maybe (NonEmpty Text)
aaguid :: Maybe AAGUID
aaid :: Maybe AAID
..} = 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
identifier <- (Text -> Maybe Text)
-> Either Text (AuthenticatorIdentifier 'Fido2)
-> Either (Maybe Text) (AuthenticatorIdentifier 'Fido2)
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 'Fido2)
meMetadataStatement <- (MetadataStatement
 -> Either (Maybe Text) (MetadataStatement 'Fido2))
-> Maybe MetadataStatement
-> Either (Maybe Text) (Maybe (MetadataStatement 'Fido2))
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse MetadataStatement -> Either (Maybe Text) (MetadataStatement 'Fido2)
forall (p :: ProtocolKind).
SingI p =>
MetadataStatement -> Either (Maybe Text) (MetadataStatement p)
decodeMetadataStatement Maybe MetadataStatement
metadataStatement
      NonEmpty StatusReport
meStatusReports <- (Text -> Maybe Text)
-> Either Text (NonEmpty StatusReport)
-> Either (Maybe Text) (NonEmpty StatusReport)
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)
traverse StatusReport -> Either Text StatusReport
decodeStatusReport NonEmpty StatusReport
statusReports
      Date
meTimeOfLastStatusChange <- (Text -> Maybe Text)
-> Either Text Date -> Either (Maybe Text) Date
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 (f :: * -> *) a. Applicative f => a -> f a
pure (SomeMetadataEntry -> NonEmpty SomeMetadataEntry)
-> SomeMetadataEntry -> NonEmpty SomeMetadataEntry
forall a b. (a -> b) -> a -> b
$ AuthenticatorIdentifier 'Fido2
-> MetadataEntry 'Fido2 -> SomeMetadataEntry
forall (p :: ProtocolKind).
SingI p =>
AuthenticatorIdentifier p -> MetadataEntry p -> SomeMetadataEntry
ServiceTypes.SomeMetadataEntry AuthenticatorIdentifier 'Fido2
identifier MetadataEntry :: forall (p :: ProtocolKind).
Maybe (MetadataStatement p)
-> NonEmpty StatusReport -> Date -> MetadataEntry p
ServiceTypes.MetadataEntry {Maybe (MetadataStatement 'Fido2)
NonEmpty StatusReport
Date
meTimeOfLastStatusChange :: Date
meStatusReports :: NonEmpty StatusReport
meMetadataStatement :: Maybe (MetadataStatement 'Fido2)
meTimeOfLastStatusChange :: Date
meStatusReports :: NonEmpty StatusReport
meMetadataStatement :: Maybe (MetadataStatement 'Fido2)
..}
    (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 (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)
traverse Text -> Either Text (AuthenticatorIdentifier 'FidoU2F)
decodeSubjectKeyIdentifier NonEmpty Text
attestationCertificateKeyIdentifiers
      Maybe (MetadataStatement 'FidoU2F)
meMetadataStatement <- (MetadataStatement
 -> Either (Maybe Text) (MetadataStatement 'FidoU2F))
-> Maybe MetadataStatement
-> Either (Maybe Text) (Maybe (MetadataStatement 'FidoU2F))
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse MetadataStatement
-> Either (Maybe Text) (MetadataStatement 'FidoU2F)
forall (p :: ProtocolKind).
SingI p =>
MetadataStatement -> Either (Maybe Text) (MetadataStatement p)
decodeMetadataStatement Maybe MetadataStatement
metadataStatement
      NonEmpty StatusReport
meStatusReports <- (Text -> Maybe Text)
-> Either Text (NonEmpty StatusReport)
-> Either (Maybe Text) (NonEmpty StatusReport)
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)
traverse StatusReport -> Either Text StatusReport
decodeStatusReport NonEmpty StatusReport
statusReports
      Date
meTimeOfLastStatusChange <- (Text -> Maybe Text)
-> Either Text Date -> Either (Maybe Text) Date
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
      let entry :: MetadataEntry 'FidoU2F
entry = MetadataEntry :: forall (p :: ProtocolKind).
Maybe (MetadataStatement p)
-> NonEmpty StatusReport -> Date -> MetadataEntry p
ServiceTypes.MetadataEntry {Maybe (MetadataStatement 'FidoU2F)
NonEmpty StatusReport
Date
meTimeOfLastStatusChange :: Date
meStatusReports :: NonEmpty StatusReport
meMetadataStatement :: Maybe (MetadataStatement 'FidoU2F)
meTimeOfLastStatusChange :: Date
meStatusReports :: NonEmpty StatusReport
meMetadataStatement :: Maybe (MetadataStatement 'FidoU2F)
..}
      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 (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (AuthenticatorIdentifier 'FidoU2F
-> MetadataEntry 'FidoU2F -> SomeMetadataEntry
forall (p :: ProtocolKind).
SingI p =>
AuthenticatorIdentifier p -> MetadataEntry p -> SomeMetadataEntry
`ServiceTypes.SomeMetadataEntry` MetadataEntry 'FidoU2F
entry) 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
$sel:certificationRequirementsVersion:StatusReport :: StatusReport -> Maybe Text
$sel:certificationPolicyVersion:StatusReport :: StatusReport -> Maybe Text
$sel:certificateNumber:StatusReport :: StatusReport -> Maybe Text
$sel:certificationDescriptor:StatusReport :: StatusReport -> Maybe Text
$sel:url:StatusReport :: StatusReport -> Maybe Text
$sel:certificate:StatusReport :: StatusReport -> Maybe Text
$sel:authenticatorVersion:StatusReport :: StatusReport -> Maybe UnsignedLong
$sel:effectiveDate:StatusReport :: StatusReport -> Maybe Text
$sel:status:StatusReport :: StatusReport -> AuthenticatorStatus
certificationRequirementsVersion :: Maybe Text
certificationPolicyVersion :: Maybe Text
certificateNumber :: Maybe Text
certificationDescriptor :: Maybe Text
url :: Maybe Text
certificate :: Maybe Text
authenticatorVersion :: Maybe UnsignedLong
effectiveDate :: Maybe Text
status :: AuthenticatorStatus
..} = 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)
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)
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 (f :: * -> *) a. Applicative f => a -> f a
pure StatusReport :: AuthenticatorStatus
-> Maybe Date
-> Maybe UnsignedLong
-> Maybe SignedCertificate
-> Maybe Text
-> Maybe Text
-> Maybe Text
-> Maybe Text
-> Maybe Text
-> StatusReport
ServiceTypes.StatusReport {Maybe UnsignedLong
Maybe Text
Maybe Date
Maybe SignedCertificate
AuthenticatorStatus
srCertificationRequirementsVersion :: Maybe Text
srCertificationPolicyVersion :: Maybe Text
srCertificateNumber :: Maybe Text
srCertificationDescriptor :: Maybe Text
srUrl :: Maybe Text
srCertificate :: Maybe SignedCertificate
srAuthenticatorVersion :: Maybe UnsignedLong
srEffectiveDate :: Maybe Date
srStatus :: AuthenticatorStatus
srCertificationRequirementsVersion :: Maybe Text
srCertificationPolicyVersion :: Maybe Text
srCertificateNumber :: Maybe Text
srCertificationDescriptor :: Maybe Text
srUrl :: Maybe Text
srCertificate :: Maybe SignedCertificate
srAuthenticatorVersion :: Maybe UnsignedLong
srEffectiveDate :: Maybe Date
srStatus :: AuthenticatorStatus
..}

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