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

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 (NonEmpty ServiceTypes.SomeMetadataEntry))
decodeMetadataEntry :: MetadataBLOBPayloadEntry
-> Maybe (Either DOMString (NonEmpty SomeMetadataEntry))
decodeMetadataEntry ServiceIDL.MetadataBLOBPayloadEntry {Maybe (NonEmpty DOMString)
Maybe (NonEmpty BiometricStatusReport)
Maybe AAID
Maybe MetadataStatement
Maybe AAGUID
DOMString
NonEmpty StatusReport
$sel:timeOfLastStatusChange:MetadataBLOBPayloadEntry :: MetadataBLOBPayloadEntry -> DOMString
$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 DOMString)
$sel:aaguid:MetadataBLOBPayloadEntry :: MetadataBLOBPayloadEntry -> Maybe AAGUID
$sel:aaid:MetadataBLOBPayloadEntry :: MetadataBLOBPayloadEntry -> Maybe AAID
timeOfLastStatusChange :: DOMString
statusReports :: NonEmpty StatusReport
biometricStatusReports :: Maybe (NonEmpty BiometricStatusReport)
metadataStatement :: Maybe MetadataStatement
attestationCertificateKeyIdentifiers :: Maybe (NonEmpty DOMString)
aaguid :: Maybe AAGUID
aaid :: Maybe AAID
..} = Either (Maybe DOMString) (NonEmpty SomeMetadataEntry)
-> Maybe (Either DOMString (NonEmpty SomeMetadataEntry))
forall a b. Either (Maybe a) b -> Maybe (Either a b)
liftEitherMaybe (Either (Maybe DOMString) (NonEmpty SomeMetadataEntry)
 -> Maybe (Either DOMString (NonEmpty SomeMetadataEntry)))
-> Either (Maybe DOMString) (NonEmpty SomeMetadataEntry)
-> Maybe (Either DOMString (NonEmpty SomeMetadataEntry))
forall a b. (a -> b) -> a -> b
$
  case (Maybe AAID
aaid, Maybe AAGUID
aaguid, Maybe (NonEmpty DOMString)
attestationCertificateKeyIdentifiers) of
    (Just AAID
_aaid, Maybe AAGUID
Nothing, Maybe (NonEmpty DOMString)
Nothing) ->
      -- This is an UAF entry, we can skip it since it's not relevant for webauthn
      Maybe DOMString
-> Either (Maybe DOMString) (NonEmpty SomeMetadataEntry)
forall a b. a -> Either a b
Left Maybe DOMString
forall a. Maybe a
Nothing
    (Maybe AAID
Nothing, Just AAGUID
aaguid, Maybe (NonEmpty DOMString)
Nothing) -> do
      -- This is a FIDO 2 entry
      AuthenticatorIdentifier 'Fido2
meIdentifier <- (DOMString -> Maybe DOMString)
-> Either DOMString (AuthenticatorIdentifier 'Fido2)
-> Either (Maybe DOMString) (AuthenticatorIdentifier 'Fido2)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first DOMString -> Maybe DOMString
forall a. a -> Maybe a
Just (Either DOMString (AuthenticatorIdentifier 'Fido2)
 -> Either (Maybe DOMString) (AuthenticatorIdentifier 'Fido2))
-> Either DOMString (AuthenticatorIdentifier 'Fido2)
-> Either (Maybe DOMString) (AuthenticatorIdentifier 'Fido2)
forall a b. (a -> b) -> a -> b
$ AAGUID -> Either DOMString (AuthenticatorIdentifier 'Fido2)
decodeAAGUID AAGUID
aaguid
      Maybe MetadataStatement
meMetadataStatement <- (MetadataStatement -> Either (Maybe DOMString) MetadataStatement)
-> Maybe MetadataStatement
-> Either (Maybe DOMString) (Maybe MetadataStatement)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse MetadataStatement -> Either (Maybe DOMString) MetadataStatement
decodeMetadataStatement Maybe MetadataStatement
metadataStatement
      NonEmpty StatusReport
meStatusReports <- (DOMString -> Maybe DOMString)
-> Either DOMString (NonEmpty StatusReport)
-> Either (Maybe DOMString) (NonEmpty StatusReport)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first DOMString -> Maybe DOMString
forall a. a -> Maybe a
Just (Either DOMString (NonEmpty StatusReport)
 -> Either (Maybe DOMString) (NonEmpty StatusReport))
-> Either DOMString (NonEmpty StatusReport)
-> Either (Maybe DOMString) (NonEmpty StatusReport)
forall a b. (a -> b) -> a -> b
$ (StatusReport -> Either DOMString StatusReport)
-> NonEmpty StatusReport
-> Either DOMString (NonEmpty StatusReport)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse StatusReport -> Either DOMString StatusReport
decodeStatusReport NonEmpty StatusReport
statusReports
      Date
meTimeOfLastStatusChange <- (DOMString -> Maybe DOMString)
-> Either DOMString Date -> Either (Maybe DOMString) Date
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first DOMString -> Maybe DOMString
forall a. a -> Maybe a
Just (Either DOMString Date -> Either (Maybe DOMString) Date)
-> Either DOMString Date -> Either (Maybe DOMString) Date
forall a b. (a -> b) -> a -> b
$ DOMString -> Either DOMString Date
decodeDate DOMString
timeOfLastStatusChange
      NonEmpty SomeMetadataEntry
-> Either (Maybe DOMString) (NonEmpty SomeMetadataEntry)
forall a b. b -> Either a b
Right (NonEmpty SomeMetadataEntry
 -> Either (Maybe DOMString) (NonEmpty SomeMetadataEntry))
-> NonEmpty SomeMetadataEntry
-> Either (Maybe DOMString) (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
$ MetadataEntry 'Fido2 -> SomeMetadataEntry
forall (p :: ProtocolKind).
SingI p =>
MetadataEntry p -> SomeMetadataEntry
ServiceTypes.SomeMetadataEntry MetadataEntry :: forall (p :: ProtocolKind).
AuthenticatorIdentifier p
-> Maybe MetadataStatement
-> NonEmpty StatusReport
-> Date
-> MetadataEntry p
ServiceTypes.MetadataEntry {Maybe MetadataStatement
NonEmpty StatusReport
Date
AuthenticatorIdentifier 'Fido2
meTimeOfLastStatusChange :: Date
meStatusReports :: NonEmpty StatusReport
meMetadataStatement :: Maybe MetadataStatement
meIdentifier :: AuthenticatorIdentifier 'Fido2
meTimeOfLastStatusChange :: Date
meStatusReports :: NonEmpty StatusReport
meMetadataStatement :: Maybe MetadataStatement
meIdentifier :: AuthenticatorIdentifier 'Fido2
..}
    (Maybe AAID
Nothing, Maybe AAGUID
Nothing, Just NonEmpty DOMString
attestationCertificateKeyIdentifiers) -> do
      -- This is a FIDO U2F entry
      NonEmpty (AuthenticatorIdentifier 'FidoU2F)
identifiers <- (DOMString -> Maybe DOMString)
-> Either DOMString (NonEmpty (AuthenticatorIdentifier 'FidoU2F))
-> Either
     (Maybe DOMString) (NonEmpty (AuthenticatorIdentifier 'FidoU2F))
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first DOMString -> Maybe DOMString
forall a. a -> Maybe a
Just (Either DOMString (NonEmpty (AuthenticatorIdentifier 'FidoU2F))
 -> Either
      (Maybe DOMString) (NonEmpty (AuthenticatorIdentifier 'FidoU2F)))
-> Either DOMString (NonEmpty (AuthenticatorIdentifier 'FidoU2F))
-> Either
     (Maybe DOMString) (NonEmpty (AuthenticatorIdentifier 'FidoU2F))
forall a b. (a -> b) -> a -> b
$ (DOMString -> Either DOMString (AuthenticatorIdentifier 'FidoU2F))
-> NonEmpty DOMString
-> Either DOMString (NonEmpty (AuthenticatorIdentifier 'FidoU2F))
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse DOMString -> Either DOMString (AuthenticatorIdentifier 'FidoU2F)
decodeSubjectKeyIdentifier NonEmpty DOMString
attestationCertificateKeyIdentifiers
      Maybe MetadataStatement
meMetadataStatement <- (MetadataStatement -> Either (Maybe DOMString) MetadataStatement)
-> Maybe MetadataStatement
-> Either (Maybe DOMString) (Maybe MetadataStatement)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse MetadataStatement -> Either (Maybe DOMString) MetadataStatement
decodeMetadataStatement Maybe MetadataStatement
metadataStatement
      NonEmpty StatusReport
meStatusReports <- (DOMString -> Maybe DOMString)
-> Either DOMString (NonEmpty StatusReport)
-> Either (Maybe DOMString) (NonEmpty StatusReport)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first DOMString -> Maybe DOMString
forall a. a -> Maybe a
Just (Either DOMString (NonEmpty StatusReport)
 -> Either (Maybe DOMString) (NonEmpty StatusReport))
-> Either DOMString (NonEmpty StatusReport)
-> Either (Maybe DOMString) (NonEmpty StatusReport)
forall a b. (a -> b) -> a -> b
$ (StatusReport -> Either DOMString StatusReport)
-> NonEmpty StatusReport
-> Either DOMString (NonEmpty StatusReport)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse StatusReport -> Either DOMString StatusReport
decodeStatusReport NonEmpty StatusReport
statusReports
      Date
meTimeOfLastStatusChange <- (DOMString -> Maybe DOMString)
-> Either DOMString Date -> Either (Maybe DOMString) Date
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first DOMString -> Maybe DOMString
forall a. a -> Maybe a
Just (Either DOMString Date -> Either (Maybe DOMString) Date)
-> Either DOMString Date -> Either (Maybe DOMString) Date
forall a b. (a -> b) -> a -> b
$ DOMString -> Either DOMString Date
decodeDate DOMString
timeOfLastStatusChange
      NonEmpty SomeMetadataEntry
-> Either (Maybe DOMString) (NonEmpty SomeMetadataEntry)
forall a b. b -> Either a b
Right (NonEmpty SomeMetadataEntry
 -> Either (Maybe DOMString) (NonEmpty SomeMetadataEntry))
-> NonEmpty SomeMetadataEntry
-> Either (Maybe DOMString) (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
meIdentifier -> MetadataEntry 'FidoU2F -> SomeMetadataEntry
forall (p :: ProtocolKind).
SingI p =>
MetadataEntry p -> SomeMetadataEntry
ServiceTypes.SomeMetadataEntry MetadataEntry :: forall (p :: ProtocolKind).
AuthenticatorIdentifier p
-> Maybe MetadataStatement
-> NonEmpty StatusReport
-> Date
-> MetadataEntry p
ServiceTypes.MetadataEntry {Maybe MetadataStatement
NonEmpty StatusReport
Date
AuthenticatorIdentifier 'FidoU2F
meIdentifier :: AuthenticatorIdentifier 'FidoU2F
meTimeOfLastStatusChange :: Date
meStatusReports :: NonEmpty StatusReport
meMetadataStatement :: Maybe MetadataStatement
meTimeOfLastStatusChange :: Date
meStatusReports :: NonEmpty StatusReport
meMetadataStatement :: Maybe MetadataStatement
meIdentifier :: AuthenticatorIdentifier 'FidoU2F
..}) NonEmpty (AuthenticatorIdentifier 'FidoU2F)
identifiers
    (Maybe AAID
Nothing, Maybe AAGUID
Nothing, Maybe (NonEmpty DOMString)
Nothing) ->
      Maybe DOMString
-> Either (Maybe DOMString) (NonEmpty SomeMetadataEntry)
forall a b. a -> Either a b
Left (Maybe DOMString
 -> Either (Maybe DOMString) (NonEmpty SomeMetadataEntry))
-> Maybe DOMString
-> Either (Maybe DOMString) (NonEmpty SomeMetadataEntry)
forall a b. (a -> b) -> a -> b
$ DOMString -> Maybe DOMString
forall a. a -> Maybe a
Just DOMString
"None of aaid, aaguid or attestationCertificateKeyIdentifiers are set for this entry"
    (Maybe AAID, Maybe AAGUID, Maybe (NonEmpty DOMString))
_ ->
      Maybe DOMString
-> Either (Maybe DOMString) (NonEmpty SomeMetadataEntry)
forall a b. a -> Either a b
Left (Maybe DOMString
 -> Either (Maybe DOMString) (NonEmpty SomeMetadataEntry))
-> Maybe DOMString
-> Either (Maybe DOMString) (NonEmpty SomeMetadataEntry)
forall a b. (a -> b) -> a -> b
$ DOMString -> Maybe DOMString
forall a. a -> Maybe a
Just DOMString
"Multiple of aaid, aaguid and/or attestationCertificateKeyIdentifiers are set for this entry"

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

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