{-# LANGUAGE DataKinds #-}
{-# LANGUAGE RecordWildCards #-}
module Crypto.WebAuthn.Metadata.Statement.Decode
( decodeMetadataStatement,
decodeAAGUID,
decodeSubjectKeyIdentifier,
decodeCertificate,
)
where
import Control.Monad (unless)
import Crypto.Hash (SHA1, digestFromByteString)
import qualified Crypto.WebAuthn.Metadata.FidoRegistry as Registry
import Crypto.WebAuthn.Metadata.Statement.Types (WebauthnAttestationType (WebauthnAttestationAttCA, WebauthnAttestationBasic))
import qualified Crypto.WebAuthn.Metadata.Statement.Types as StatementTypes
import qualified Crypto.WebAuthn.Metadata.Statement.WebIDL as StatementIDL
import qualified Crypto.WebAuthn.Metadata.WebIDL as IDL
import qualified Crypto.WebAuthn.Model as M
import Crypto.WebAuthn.Model.Identifier (AAGUID (AAGUID), AuthenticatorIdentifier (AuthenticatorIdentifierFido2, AuthenticatorIdentifierFidoU2F), SubjectKeyIdentifier (SubjectKeyIdentifier))
import Data.Bifunctor (first)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Base16 as Base16
import qualified Data.ByteString.Base64 as Base64
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
import Data.Text.Encoding (encodeUtf8)
import qualified Data.UUID as UUID
import qualified Data.X509 as X509
decodeAAGUID :: StatementIDL.AAGUID -> Either Text (AuthenticatorIdentifier 'M.Fido2)
decodeAAGUID :: AAGUID -> Either DOMString (AuthenticatorIdentifier 'Fido2)
decodeAAGUID (StatementIDL.AAGUID DOMString
aaguidText) = case DOMString -> Maybe UUID
UUID.fromText DOMString
aaguidText of
Maybe UUID
Nothing -> DOMString -> Either DOMString (AuthenticatorIdentifier 'Fido2)
forall a b. a -> Either a b
Left (DOMString -> Either DOMString (AuthenticatorIdentifier 'Fido2))
-> DOMString -> Either DOMString (AuthenticatorIdentifier 'Fido2)
forall a b. (a -> b) -> a -> b
$ DOMString
"Could not decode metadata aaguid: " DOMString -> DOMString -> DOMString
forall a. Semigroup a => a -> a -> a
<> DOMString
aaguidText
Just UUID
aaguid -> AuthenticatorIdentifier 'Fido2
-> Either DOMString (AuthenticatorIdentifier 'Fido2)
forall a b. b -> Either a b
Right (AuthenticatorIdentifier 'Fido2
-> Either DOMString (AuthenticatorIdentifier 'Fido2))
-> AuthenticatorIdentifier 'Fido2
-> Either DOMString (AuthenticatorIdentifier 'Fido2)
forall a b. (a -> b) -> a -> b
$ AAGUID -> AuthenticatorIdentifier 'Fido2
AuthenticatorIdentifierFido2 (AAGUID -> AuthenticatorIdentifier 'Fido2)
-> AAGUID -> AuthenticatorIdentifier 'Fido2
forall a b. (a -> b) -> a -> b
$ UUID -> AAGUID
AAGUID UUID
aaguid
decodeSubjectKeyIdentifier :: IDL.DOMString -> Either Text (AuthenticatorIdentifier 'M.FidoU2F)
decodeSubjectKeyIdentifier :: DOMString -> Either DOMString (AuthenticatorIdentifier 'FidoU2F)
decodeSubjectKeyIdentifier DOMString
subjectKeyIdentifierText = case ByteString -> Either String ByteString
Base16.decode (DOMString -> ByteString
encodeUtf8 DOMString
subjectKeyIdentifierText) of
Left String
err -> DOMString -> Either DOMString (AuthenticatorIdentifier 'FidoU2F)
forall a b. a -> Either a b
Left (DOMString -> Either DOMString (AuthenticatorIdentifier 'FidoU2F))
-> DOMString -> Either DOMString (AuthenticatorIdentifier 'FidoU2F)
forall a b. (a -> b) -> a -> b
$ DOMString
"A attestationCertificateKeyIdentifier failed to parse because it's not a valid base-16 encoding: " DOMString -> DOMString -> DOMString
forall a. Semigroup a => a -> a -> a
<> DOMString
subjectKeyIdentifierText DOMString -> DOMString -> DOMString
forall a. Semigroup a => a -> a -> a
<> DOMString
", error: " DOMString -> DOMString -> DOMString
forall a. Semigroup a => a -> a -> a
<> String -> DOMString
Text.pack String
err
Right ByteString
bytes -> case forall a ba.
(HashAlgorithm a, ByteArrayAccess ba) =>
ba -> Maybe (Digest a)
digestFromByteString @SHA1 ByteString
bytes of
Maybe (Digest SHA1)
Nothing -> DOMString -> Either DOMString (AuthenticatorIdentifier 'FidoU2F)
forall a b. a -> Either a b
Left (DOMString -> Either DOMString (AuthenticatorIdentifier 'FidoU2F))
-> DOMString -> Either DOMString (AuthenticatorIdentifier 'FidoU2F)
forall a b. (a -> b) -> a -> b
$ DOMString
"A attestationCertificateKeyIdentifier failed to parse because it has the wrong length for a SHA1 hash: " DOMString -> DOMString -> DOMString
forall a. Semigroup a => a -> a -> a
<> DOMString
subjectKeyIdentifierText
Just Digest SHA1
hash -> AuthenticatorIdentifier 'FidoU2F
-> Either DOMString (AuthenticatorIdentifier 'FidoU2F)
forall a b. b -> Either a b
Right (AuthenticatorIdentifier 'FidoU2F
-> Either DOMString (AuthenticatorIdentifier 'FidoU2F))
-> AuthenticatorIdentifier 'FidoU2F
-> Either DOMString (AuthenticatorIdentifier 'FidoU2F)
forall a b. (a -> b) -> a -> b
$ SubjectKeyIdentifier -> AuthenticatorIdentifier 'FidoU2F
AuthenticatorIdentifierFidoU2F (SubjectKeyIdentifier -> AuthenticatorIdentifier 'FidoU2F)
-> SubjectKeyIdentifier -> AuthenticatorIdentifier 'FidoU2F
forall a b. (a -> b) -> a -> b
$ Digest SHA1 -> SubjectKeyIdentifier
SubjectKeyIdentifier Digest SHA1
hash
decodeCertificate :: IDL.DOMString -> Either Text X509.SignedCertificate
decodeCertificate :: DOMString -> Either DOMString SignedCertificate
decodeCertificate DOMString
text =
let bytes :: ByteString
bytes = ByteString -> ByteString
Base64.decodeLenient (DOMString -> ByteString
encodeUtf8 (DOMString -> ByteString) -> DOMString -> ByteString
forall a b. (a -> b) -> a -> b
$ DOMString -> DOMString
Text.strip DOMString
text)
in case ByteString -> Either String SignedCertificate
X509.decodeSignedCertificate ByteString
bytes of
Left String
err -> DOMString -> Either DOMString SignedCertificate
forall a b. a -> Either a b
Left (DOMString -> Either DOMString SignedCertificate)
-> DOMString -> Either DOMString SignedCertificate
forall a b. (a -> b) -> a -> b
$ DOMString
"A certificate failed to parse because it's not a valid encoding: " DOMString -> DOMString -> DOMString
forall a. Semigroup a => a -> a -> a
<> DOMString
text DOMString -> DOMString -> DOMString
forall a. Semigroup a => a -> a -> a
<> DOMString
", error: " DOMString -> DOMString -> DOMString
forall a. Semigroup a => a -> a -> a
<> String -> DOMString
Text.pack String
err
Right SignedCertificate
certificate -> SignedCertificate -> Either DOMString SignedCertificate
forall a b. b -> Either a b
Right SignedCertificate
certificate
decodeMetadataStatement ::
StatementIDL.MetadataStatement ->
Either (Maybe Text) StatementTypes.MetadataStatement
decodeMetadataStatement :: MetadataStatement -> Either (Maybe DOMString) MetadataStatement
decodeMetadataStatement StatementIDL.MetadataStatement {[DOMString]
[TransactionConfirmationDisplayType]
Maybe Boolean
Maybe UnsignedShort
Maybe DOMString
Maybe (NonEmpty KeyIdentifier)
Maybe (NonEmpty ExtensionDescriptor)
Maybe (NonEmpty EcdaaTrustAnchor)
Maybe (NonEmpty DisplayPNGCharacteristicsDescriptor)
Maybe AAID
Maybe AuthenticatorGetInfo
Maybe AlternativeDescriptions
Maybe AAGUID
UnsignedShort
UnsignedLong
DOMString
NonEmpty Version
NonEmpty AuthenticatorAttestationType
NonEmpty PublicKeyRepresentationFormat
NonEmpty AuthenticationAlgorithm
NonEmpty AuthenticatorAttachmentHint
NonEmpty MatcherProtectionType
NonEmpty KeyProtectionType
NonEmpty VerificationMethodANDCombinations
ProtocolFamily
$sel:authenticatorGetInfo:MetadataStatement :: MetadataStatement -> Maybe AuthenticatorGetInfo
$sel:supportedExtensions:MetadataStatement :: MetadataStatement -> Maybe (NonEmpty ExtensionDescriptor)
$sel:icon:MetadataStatement :: MetadataStatement -> Maybe DOMString
$sel:ecdaaTrustAnchors:MetadataStatement :: MetadataStatement -> Maybe (NonEmpty EcdaaTrustAnchor)
$sel:attestationRootCertificates:MetadataStatement :: MetadataStatement -> [DOMString]
$sel:tcDisplayPNGCharacteristics:MetadataStatement :: MetadataStatement
-> Maybe (NonEmpty DisplayPNGCharacteristicsDescriptor)
$sel:tcDisplayContentType:MetadataStatement :: MetadataStatement -> Maybe DOMString
$sel:tcDisplay:MetadataStatement :: MetadataStatement -> [TransactionConfirmationDisplayType]
$sel:attachmentHint:MetadataStatement :: MetadataStatement -> NonEmpty AuthenticatorAttachmentHint
$sel:cryptoStrength:MetadataStatement :: MetadataStatement -> Maybe UnsignedShort
$sel:matcherProtection:MetadataStatement :: MetadataStatement -> NonEmpty MatcherProtectionType
$sel:isFreshUserVerificationRequired:MetadataStatement :: MetadataStatement -> Maybe Boolean
$sel:isKeyRestricted:MetadataStatement :: MetadataStatement -> Maybe Boolean
$sel:keyProtection:MetadataStatement :: MetadataStatement -> NonEmpty KeyProtectionType
$sel:userVerificationDetails:MetadataStatement :: MetadataStatement -> NonEmpty VerificationMethodANDCombinations
$sel:attestationTypes:MetadataStatement :: MetadataStatement -> NonEmpty AuthenticatorAttestationType
$sel:publicKeyAlgAndEncodings:MetadataStatement :: MetadataStatement -> NonEmpty PublicKeyRepresentationFormat
$sel:authenticationAlgorithms:MetadataStatement :: MetadataStatement -> NonEmpty AuthenticationAlgorithm
$sel:upv:MetadataStatement :: MetadataStatement -> NonEmpty Version
$sel:schema:MetadataStatement :: MetadataStatement -> UnsignedShort
$sel:protocolFamily:MetadataStatement :: MetadataStatement -> ProtocolFamily
$sel:authenticatorVersion:MetadataStatement :: MetadataStatement -> UnsignedLong
$sel:alternativeDescriptions:MetadataStatement :: MetadataStatement -> Maybe AlternativeDescriptions
$sel:description:MetadataStatement :: MetadataStatement -> DOMString
$sel:attestationCertificateKeyIdentifiers:MetadataStatement :: MetadataStatement -> Maybe (NonEmpty KeyIdentifier)
$sel:aaguid:MetadataStatement :: MetadataStatement -> Maybe AAGUID
$sel:aaid:MetadataStatement :: MetadataStatement -> Maybe AAID
$sel:legalHeader:MetadataStatement :: MetadataStatement -> DOMString
authenticatorGetInfo :: Maybe AuthenticatorGetInfo
supportedExtensions :: Maybe (NonEmpty ExtensionDescriptor)
icon :: Maybe DOMString
ecdaaTrustAnchors :: Maybe (NonEmpty EcdaaTrustAnchor)
attestationRootCertificates :: [DOMString]
tcDisplayPNGCharacteristics :: Maybe (NonEmpty DisplayPNGCharacteristicsDescriptor)
tcDisplayContentType :: Maybe DOMString
tcDisplay :: [TransactionConfirmationDisplayType]
attachmentHint :: NonEmpty AuthenticatorAttachmentHint
cryptoStrength :: Maybe UnsignedShort
matcherProtection :: NonEmpty MatcherProtectionType
isFreshUserVerificationRequired :: Maybe Boolean
isKeyRestricted :: Maybe Boolean
keyProtection :: NonEmpty KeyProtectionType
userVerificationDetails :: NonEmpty VerificationMethodANDCombinations
attestationTypes :: NonEmpty AuthenticatorAttestationType
publicKeyAlgAndEncodings :: NonEmpty PublicKeyRepresentationFormat
authenticationAlgorithms :: NonEmpty AuthenticationAlgorithm
upv :: NonEmpty Version
schema :: UnsignedShort
protocolFamily :: ProtocolFamily
authenticatorVersion :: UnsignedLong
alternativeDescriptions :: Maybe AlternativeDescriptions
description :: DOMString
attestationCertificateKeyIdentifiers :: Maybe (NonEmpty KeyIdentifier)
aaguid :: Maybe AAGUID
aaid :: Maybe AAID
legalHeader :: DOMString
..} = do
let msLegalHeader :: DOMString
msLegalHeader = DOMString
legalHeader
msDescription :: DOMString
msDescription = DOMString
description
msAlternativeDescriptions :: Maybe AlternativeDescriptions
msAlternativeDescriptions = Maybe AlternativeDescriptions
alternativeDescriptions
msAuthenticatorVersion :: UnsignedLong
msAuthenticatorVersion = UnsignedLong
authenticatorVersion
Boolean
-> Either (Maybe DOMString) () -> Either (Maybe DOMString) ()
forall (f :: * -> *). Applicative f => Boolean -> f () -> f ()
unless (UnsignedShort
schema UnsignedShort -> UnsignedShort -> Boolean
forall a. Eq a => a -> a -> Boolean
== UnsignedShort
3) (Either (Maybe DOMString) () -> Either (Maybe DOMString) ())
-> Either (Maybe DOMString) () -> Either (Maybe DOMString) ()
forall a b. (a -> b) -> a -> b
$ Maybe DOMString -> Either (Maybe DOMString) ()
forall a b. a -> Either a b
Left (Maybe DOMString -> Either (Maybe DOMString) ())
-> Maybe DOMString -> Either (Maybe DOMString) ()
forall a b. (a -> b) -> a -> b
$ DOMString -> Maybe DOMString
forall a. a -> Maybe a
Just (DOMString -> Maybe DOMString) -> DOMString -> Maybe DOMString
forall a b. (a -> b) -> a -> b
$ DOMString
"Schema version is not 3 but " DOMString -> DOMString -> DOMString
forall a. Semigroup a => a -> a -> a
<> String -> DOMString
Text.pack (UnsignedShort -> String
forall a. Show a => a -> String
show UnsignedShort
schema)
let msUpv :: NonEmpty Version
msUpv = NonEmpty Version
upv
msAuthenticationAlgorithms :: NonEmpty AuthenticationAlgorithm
msAuthenticationAlgorithms = NonEmpty AuthenticationAlgorithm
authenticationAlgorithms
msPublicKeyAlgAndEncodings :: NonEmpty PublicKeyRepresentationFormat
msPublicKeyAlgAndEncodings = NonEmpty PublicKeyRepresentationFormat
publicKeyAlgAndEncodings
NonEmpty WebauthnAttestationType
msAttestationTypes <- NonEmpty AuthenticatorAttestationType
-> Either (Maybe DOMString) (NonEmpty WebauthnAttestationType)
decodeAttestationTypes NonEmpty AuthenticatorAttestationType
attestationTypes
let msUserVerificationDetails :: NonEmpty VerificationMethodANDCombinations
msUserVerificationDetails = NonEmpty VerificationMethodANDCombinations
userVerificationDetails
msKeyProtection :: NonEmpty KeyProtectionType
msKeyProtection = NonEmpty KeyProtectionType
keyProtection
msIsKeyRestricted :: Maybe Boolean
msIsKeyRestricted = Maybe Boolean
isKeyRestricted
msIsFreshUserVerificationRequired :: Maybe Boolean
msIsFreshUserVerificationRequired = Maybe Boolean
isFreshUserVerificationRequired
msMatcherProtection :: NonEmpty MatcherProtectionType
msMatcherProtection = NonEmpty MatcherProtectionType
matcherProtection
msCryptoStrength :: Maybe UnsignedShort
msCryptoStrength = Maybe UnsignedShort
cryptoStrength
msAttachmentHint :: NonEmpty AuthenticatorAttachmentHint
msAttachmentHint = NonEmpty AuthenticatorAttachmentHint
attachmentHint
msTcDisplay :: [TransactionConfirmationDisplayType]
msTcDisplay = [TransactionConfirmationDisplayType]
tcDisplay
msTcDisplayContentType :: Maybe DOMString
msTcDisplayContentType = Maybe DOMString
tcDisplayContentType
msTcDisplayPNGCharacteristics :: Maybe (NonEmpty DisplayPNGCharacteristicsDescriptor)
msTcDisplayPNGCharacteristics = Maybe (NonEmpty DisplayPNGCharacteristicsDescriptor)
tcDisplayPNGCharacteristics
NonEmpty SignedCertificate
msAttestationRootCertificates <- case [DOMString] -> Maybe (NonEmpty DOMString)
forall a. [a] -> Maybe (NonEmpty a)
NE.nonEmpty [DOMString]
attestationRootCertificates of
Maybe (NonEmpty DOMString)
Nothing -> Maybe DOMString
-> Either (Maybe DOMString) (NonEmpty SignedCertificate)
forall a b. a -> Either a b
Left (Maybe DOMString
-> Either (Maybe DOMString) (NonEmpty SignedCertificate))
-> Maybe DOMString
-> Either (Maybe DOMString) (NonEmpty SignedCertificate)
forall a b. (a -> b) -> a -> b
$ DOMString -> Maybe DOMString
forall a. a -> Maybe a
Just DOMString
"attestationRootCertificates should not be empty"
Just NonEmpty DOMString
certs -> (DOMString -> Maybe DOMString)
-> Either DOMString (NonEmpty SignedCertificate)
-> Either (Maybe DOMString) (NonEmpty SignedCertificate)
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 SignedCertificate)
-> Either (Maybe DOMString) (NonEmpty SignedCertificate))
-> Either DOMString (NonEmpty SignedCertificate)
-> Either (Maybe DOMString) (NonEmpty SignedCertificate)
forall a b. (a -> b) -> a -> b
$ (DOMString -> Either DOMString SignedCertificate)
-> NonEmpty DOMString
-> Either DOMString (NonEmpty SignedCertificate)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse DOMString -> Either DOMString SignedCertificate
decodeCertificate NonEmpty DOMString
certs
Maybe ByteString
msIcon <- (DOMString -> Maybe DOMString)
-> Either DOMString (Maybe ByteString)
-> Either (Maybe DOMString) (Maybe ByteString)
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 (Maybe ByteString)
-> Either (Maybe DOMString) (Maybe ByteString))
-> Either DOMString (Maybe ByteString)
-> Either (Maybe DOMString) (Maybe ByteString)
forall a b. (a -> b) -> a -> b
$ (DOMString -> Either DOMString ByteString)
-> Maybe DOMString -> Either DOMString (Maybe ByteString)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse DOMString -> Either DOMString ByteString
decodeIcon Maybe DOMString
icon
let msSupportedExtensions :: Maybe (NonEmpty ExtensionDescriptor)
msSupportedExtensions = Maybe (NonEmpty ExtensionDescriptor)
supportedExtensions
msAuthenticatorGetInfo :: Maybe AuthenticatorGetInfo
msAuthenticatorGetInfo = Maybe AuthenticatorGetInfo
authenticatorGetInfo
MetadataStatement -> Either (Maybe DOMString) MetadataStatement
forall (f :: * -> *) a. Applicative f => a -> f a
pure (MetadataStatement -> Either (Maybe DOMString) MetadataStatement)
-> MetadataStatement -> Either (Maybe DOMString) MetadataStatement
forall a b. (a -> b) -> a -> b
$ MetadataStatement :: DOMString
-> DOMString
-> Maybe AlternativeDescriptions
-> UnsignedLong
-> NonEmpty Version
-> NonEmpty AuthenticationAlgorithm
-> NonEmpty PublicKeyRepresentationFormat
-> NonEmpty WebauthnAttestationType
-> NonEmpty VerificationMethodANDCombinations
-> NonEmpty KeyProtectionType
-> Maybe Boolean
-> Maybe Boolean
-> NonEmpty MatcherProtectionType
-> Maybe UnsignedShort
-> NonEmpty AuthenticatorAttachmentHint
-> [TransactionConfirmationDisplayType]
-> Maybe DOMString
-> Maybe (NonEmpty DisplayPNGCharacteristicsDescriptor)
-> NonEmpty SignedCertificate
-> Maybe ByteString
-> Maybe (NonEmpty ExtensionDescriptor)
-> Maybe AuthenticatorGetInfo
-> MetadataStatement
StatementTypes.MetadataStatement {[TransactionConfirmationDisplayType]
Maybe Boolean
Maybe UnsignedShort
Maybe ByteString
Maybe DOMString
Maybe (NonEmpty ExtensionDescriptor)
Maybe (NonEmpty DisplayPNGCharacteristicsDescriptor)
Maybe AuthenticatorGetInfo
Maybe AlternativeDescriptions
UnsignedLong
DOMString
NonEmpty SignedCertificate
NonEmpty Version
NonEmpty PublicKeyRepresentationFormat
NonEmpty AuthenticationAlgorithm
NonEmpty AuthenticatorAttachmentHint
NonEmpty MatcherProtectionType
NonEmpty KeyProtectionType
NonEmpty VerificationMethodANDCombinations
NonEmpty WebauthnAttestationType
msAuthenticatorGetInfo :: Maybe AuthenticatorGetInfo
msSupportedExtensions :: Maybe (NonEmpty ExtensionDescriptor)
msIcon :: Maybe ByteString
msAttestationRootCertificates :: NonEmpty SignedCertificate
msTcDisplayPNGCharacteristics :: Maybe (NonEmpty DisplayPNGCharacteristicsDescriptor)
msTcDisplayContentType :: Maybe DOMString
msTcDisplay :: [TransactionConfirmationDisplayType]
msAttachmentHint :: NonEmpty AuthenticatorAttachmentHint
msCryptoStrength :: Maybe UnsignedShort
msMatcherProtection :: NonEmpty MatcherProtectionType
msIsFreshUserVerificationRequired :: Maybe Boolean
msIsKeyRestricted :: Maybe Boolean
msKeyProtection :: NonEmpty KeyProtectionType
msUserVerificationDetails :: NonEmpty VerificationMethodANDCombinations
msAttestationTypes :: NonEmpty WebauthnAttestationType
msPublicKeyAlgAndEncodings :: NonEmpty PublicKeyRepresentationFormat
msAuthenticationAlgorithms :: NonEmpty AuthenticationAlgorithm
msUpv :: NonEmpty Version
msAuthenticatorVersion :: UnsignedLong
msAlternativeDescriptions :: Maybe AlternativeDescriptions
msDescription :: DOMString
msLegalHeader :: DOMString
msAuthenticatorGetInfo :: Maybe AuthenticatorGetInfo
msSupportedExtensions :: Maybe (NonEmpty ExtensionDescriptor)
msIcon :: Maybe ByteString
msAttestationRootCertificates :: NonEmpty SignedCertificate
msTcDisplayPNGCharacteristics :: Maybe (NonEmpty DisplayPNGCharacteristicsDescriptor)
msTcDisplayContentType :: Maybe DOMString
msTcDisplay :: [TransactionConfirmationDisplayType]
msAttachmentHint :: NonEmpty AuthenticatorAttachmentHint
msCryptoStrength :: Maybe UnsignedShort
msMatcherProtection :: NonEmpty MatcherProtectionType
msIsFreshUserVerificationRequired :: Maybe Boolean
msIsKeyRestricted :: Maybe Boolean
msKeyProtection :: NonEmpty KeyProtectionType
msUserVerificationDetails :: NonEmpty VerificationMethodANDCombinations
msAttestationTypes :: NonEmpty WebauthnAttestationType
msPublicKeyAlgAndEncodings :: NonEmpty PublicKeyRepresentationFormat
msAuthenticationAlgorithms :: NonEmpty AuthenticationAlgorithm
msUpv :: NonEmpty Version
msAuthenticatorVersion :: UnsignedLong
msAlternativeDescriptions :: Maybe AlternativeDescriptions
msDescription :: DOMString
msLegalHeader :: DOMString
..}
where
decodeAttestationTypes ::
NonEmpty Registry.AuthenticatorAttestationType ->
Either (Maybe Text) (NonEmpty WebauthnAttestationType)
decodeAttestationTypes :: NonEmpty AuthenticatorAttestationType
-> Either (Maybe DOMString) (NonEmpty WebauthnAttestationType)
decodeAttestationTypes NonEmpty AuthenticatorAttestationType
types = case [WebauthnAttestationType]
-> Maybe (NonEmpty WebauthnAttestationType)
forall a. [a] -> Maybe (NonEmpty a)
NE.nonEmpty ([WebauthnAttestationType]
-> Maybe (NonEmpty WebauthnAttestationType))
-> [WebauthnAttestationType]
-> Maybe (NonEmpty WebauthnAttestationType)
forall a b. (a -> b) -> a -> b
$ (AuthenticatorAttestationType -> Maybe WebauthnAttestationType)
-> [AuthenticatorAttestationType] -> [WebauthnAttestationType]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe AuthenticatorAttestationType -> Maybe WebauthnAttestationType
transform ([AuthenticatorAttestationType] -> [WebauthnAttestationType])
-> [AuthenticatorAttestationType] -> [WebauthnAttestationType]
forall a b. (a -> b) -> a -> b
$ NonEmpty AuthenticatorAttestationType
-> [AuthenticatorAttestationType]
forall a. NonEmpty a -> [a]
NE.toList NonEmpty AuthenticatorAttestationType
types of
Maybe (NonEmpty WebauthnAttestationType)
Nothing -> Maybe DOMString
-> Either (Maybe DOMString) (NonEmpty WebauthnAttestationType)
forall a b. a -> Either a b
Left Maybe DOMString
forall a. Maybe a
Nothing
Just NonEmpty WebauthnAttestationType
result -> NonEmpty WebauthnAttestationType
-> Either (Maybe DOMString) (NonEmpty WebauthnAttestationType)
forall a b. b -> Either a b
Right NonEmpty WebauthnAttestationType
result
where
transform :: Registry.AuthenticatorAttestationType -> Maybe WebauthnAttestationType
transform :: AuthenticatorAttestationType -> Maybe WebauthnAttestationType
transform AuthenticatorAttestationType
Registry.ATTESTATION_BASIC_FULL = WebauthnAttestationType -> Maybe WebauthnAttestationType
forall a. a -> Maybe a
Just WebauthnAttestationType
WebauthnAttestationBasic
transform AuthenticatorAttestationType
Registry.ATTESTATION_ATTCA = WebauthnAttestationType -> Maybe WebauthnAttestationType
forall a. a -> Maybe a
Just WebauthnAttestationType
WebauthnAttestationAttCA
transform AuthenticatorAttestationType
_ = Maybe WebauthnAttestationType
forall a. Maybe a
Nothing
decodeIcon :: IDL.DOMString -> Either Text BS.ByteString
decodeIcon :: DOMString -> Either DOMString ByteString
decodeIcon DOMString
dataUrl = case DOMString -> DOMString -> Maybe DOMString
Text.stripPrefix DOMString
"data:image/png;base64," DOMString
dataUrl of
Maybe DOMString
Nothing -> DOMString -> Either DOMString ByteString
forall a b. a -> Either a b
Left (DOMString -> Either DOMString ByteString)
-> DOMString -> Either DOMString ByteString
forall a b. (a -> b) -> a -> b
$ DOMString
"Icon decoding failed because there is no \"data:image/png;base64,\" prefix: " DOMString -> DOMString -> DOMString
forall a. Semigroup a => a -> a -> a
<> DOMString
dataUrl
Just DOMString
suffix ->
ByteString -> Either DOMString ByteString
forall a b. b -> Either a b
Right (ByteString -> Either DOMString ByteString)
-> ByteString -> Either DOMString ByteString
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString
Base64.decodeLenient (DOMString -> ByteString
encodeUtf8 DOMString
suffix)