module Signet.Unstable.Type.SignaturesTest where

import qualified Crypto.Error as Error
import qualified Crypto.Hash as Hash
import qualified Crypto.PubKey.Ed25519 as Ed25519
import qualified Data.ByteString as ByteString
import qualified Data.ByteString.Char8 as Ascii
import qualified Signet.Unstable.Exception.InvalidAsymmetricSignature as InvalidAsymmetricSignature
import qualified Signet.Unstable.Exception.InvalidSignature as InvalidSignature
import qualified Signet.Unstable.Exception.InvalidSymmetricSignature as InvalidSymmetricSignature
import qualified Signet.Unstable.Extra.Tasty as Tasty
import qualified Signet.Unstable.Type.AsymmetricSignature as AsymmetricSignature
import qualified Signet.Unstable.Type.Signature as Signature
import qualified Signet.Unstable.Type.Signatures as Signatures
import qualified Signet.Unstable.Type.SymmetricSignature as SymmetricSignature
import qualified Signet.Unstable.Type.UnknownSignature as UnknownSignature
import Test.Tasty.HUnit ((@?=))

spec :: Tasty.Spec
spec :: Spec
spec = TestName -> Spec -> Spec
Tasty.describe TestName
"Signet.Unstable.Type.Signatures" (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
  TestName -> Spec -> Spec
Tasty.describe TestName
"parse" (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
    TestName -> Assertion -> Spec
Tasty.it TestName
"succeeds with no signatures" (Assertion -> Spec) -> Assertion -> Spec
forall a b. (a -> b) -> a -> b
$ do
      ByteString
-> Either InvalidSignature ([UnknownSignature], Signatures)
Signatures.parse ByteString
ByteString.empty Either InvalidSignature ([UnknownSignature], Signatures)
-> Either InvalidSignature ([UnknownSignature], Signatures)
-> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= ([UnknownSignature], Signatures)
-> Either InvalidSignature ([UnknownSignature], Signatures)
forall a b. b -> Either a b
Right ([], [Signature] -> Signatures
Signatures.MkSignatures [])

    TestName -> Assertion -> Spec
Tasty.it TestName
"succeeds with one signature" (Assertion -> Spec) -> Assertion -> Spec
forall a b. (a -> b) -> a -> b
$ do
      let signature :: Signature
signature = SymmetricSignature -> Signature
Signature.Symmetric (SymmetricSignature -> Signature)
-> (Digest SHA256 -> SymmetricSignature)
-> Digest SHA256
-> Signature
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Digest SHA256 -> SymmetricSignature
SymmetricSignature.MkSymmetricSignature (Digest SHA256 -> Signature) -> Digest SHA256 -> Signature
forall a b. (a -> b) -> a -> b
$ ByteString -> Digest SHA256
forall ba a.
(ByteArrayAccess ba, HashAlgorithm a) =>
ba -> Digest a
Hash.hash ByteString
ByteString.empty
      let byteString :: ByteString
byteString = TestName -> ByteString
Ascii.pack TestName
"v1,47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU="
      ByteString
-> Either InvalidSignature ([UnknownSignature], Signatures)
Signatures.parse ByteString
byteString Either InvalidSignature ([UnknownSignature], Signatures)
-> Either InvalidSignature ([UnknownSignature], Signatures)
-> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= ([UnknownSignature], Signatures)
-> Either InvalidSignature ([UnknownSignature], Signatures)
forall a b. b -> Either a b
Right ([], [Signature] -> Signatures
Signatures.MkSignatures [Signature
signature])

    TestName -> Assertion -> Spec
Tasty.it TestName
"succeeds with many signatures" (Assertion -> Spec) -> Assertion -> Spec
forall a b. (a -> b) -> a -> b
$ do
      let symmetricSignature :: SymmetricSignature
symmetricSignature = Digest SHA256 -> SymmetricSignature
SymmetricSignature.MkSymmetricSignature (Digest SHA256 -> SymmetricSignature)
-> Digest SHA256 -> SymmetricSignature
forall a b. (a -> b) -> a -> b
$ ByteString -> Digest SHA256
forall ba a.
(ByteArrayAccess ba, HashAlgorithm a) =>
ba -> Digest a
Hash.hash ByteString
ByteString.empty
      AsymmetricSignature
asymmetricSignature <- (Signature -> AsymmetricSignature)
-> IO Signature -> IO AsymmetricSignature
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Signature -> AsymmetricSignature
AsymmetricSignature.MkAsymmetricSignature (IO Signature -> IO AsymmetricSignature)
-> (ByteString -> IO Signature)
-> ByteString
-> IO AsymmetricSignature
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CryptoFailable Signature -> IO Signature
forall a. CryptoFailable a -> IO a
Error.throwCryptoErrorIO (CryptoFailable Signature -> IO Signature)
-> (ByteString -> CryptoFailable Signature)
-> ByteString
-> IO Signature
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> CryptoFailable Signature
forall ba. ByteArrayAccess ba => ba -> CryptoFailable Signature
Ed25519.signature (ByteString -> IO AsymmetricSignature)
-> ByteString -> IO AsymmetricSignature
forall a b. (a -> b) -> a -> b
$ TestName -> ByteString
Ascii.pack TestName
"ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789-abcdefghijklmnopqrstuvqxyz"
      let byteString :: ByteString
byteString = TestName -> ByteString
Ascii.pack TestName
"v1,47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= v1a,QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVotMDEyMzQ1Njc4OS1hYmNkZWZnaGlqa2xtbm9wcXJzdHV2cXh5eg=="
      let signatures :: Signatures
signatures =
            [Signature] -> Signatures
Signatures.MkSignatures
              [ SymmetricSignature -> Signature
Signature.Symmetric SymmetricSignature
symmetricSignature,
                AsymmetricSignature -> Signature
Signature.Asymmetric AsymmetricSignature
asymmetricSignature
              ]
      ByteString
-> Either InvalidSignature ([UnknownSignature], Signatures)
Signatures.parse ByteString
byteString Either InvalidSignature ([UnknownSignature], Signatures)
-> Either InvalidSignature ([UnknownSignature], Signatures)
-> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= ([UnknownSignature], Signatures)
-> Either InvalidSignature ([UnknownSignature], Signatures)
forall a b. b -> Either a b
Right ([], Signatures
signatures)

    TestName -> Assertion -> Spec
Tasty.it TestName
"fails with an invalid symmetric signature" (Assertion -> Spec) -> Assertion -> Spec
forall a b. (a -> b) -> a -> b
$ do
      let x :: ByteString
x = TestName -> ByteString
Ascii.pack TestName
"invalid"
      let byteString :: ByteString
byteString = TestName -> ByteString
Ascii.pack TestName
"v1," ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
x
      ByteString
-> Either InvalidSignature ([UnknownSignature], Signatures)
Signatures.parse ByteString
byteString Either InvalidSignature ([UnknownSignature], Signatures)
-> Either InvalidSignature ([UnknownSignature], Signatures)
-> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= InvalidSignature
-> Either InvalidSignature ([UnknownSignature], Signatures)
forall a b. a -> Either a b
Left (InvalidSymmetricSignature -> InvalidSignature
InvalidSignature.InvalidSymmetricSignature (InvalidSymmetricSignature -> InvalidSignature)
-> InvalidSymmetricSignature -> InvalidSignature
forall a b. (a -> b) -> a -> b
$ ByteString -> InvalidSymmetricSignature
InvalidSymmetricSignature.MkInvalidSymmetricSignature ByteString
x)

    TestName -> Assertion -> Spec
Tasty.it TestName
"fails with an invalid asymmetric signature" (Assertion -> Spec) -> Assertion -> Spec
forall a b. (a -> b) -> a -> b
$ do
      let x :: ByteString
x = TestName -> ByteString
Ascii.pack TestName
"invalid"
      let byteString :: ByteString
byteString = TestName -> ByteString
Ascii.pack TestName
"v1a," ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
x
      ByteString
-> Either InvalidSignature ([UnknownSignature], Signatures)
Signatures.parse ByteString
byteString Either InvalidSignature ([UnknownSignature], Signatures)
-> Either InvalidSignature ([UnknownSignature], Signatures)
-> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= InvalidSignature
-> Either InvalidSignature ([UnknownSignature], Signatures)
forall a b. a -> Either a b
Left (InvalidAsymmetricSignature -> InvalidSignature
InvalidSignature.InvalidAsymmetricSignature (InvalidAsymmetricSignature -> InvalidSignature)
-> InvalidAsymmetricSignature -> InvalidSignature
forall a b. (a -> b) -> a -> b
$ ByteString -> InvalidAsymmetricSignature
InvalidAsymmetricSignature.MkInvalidAsymmetricSignature ByteString
x)

    TestName -> Assertion -> Spec
Tasty.it TestName
"succeeds with an unknown signature" (Assertion -> Spec) -> Assertion -> Spec
forall a b. (a -> b) -> a -> b
$ do
      let byteString :: ByteString
byteString = TestName -> ByteString
Ascii.pack TestName
"unknown"
      ByteString
-> Either InvalidSignature ([UnknownSignature], Signatures)
Signatures.parse ByteString
byteString Either InvalidSignature ([UnknownSignature], Signatures)
-> Either InvalidSignature ([UnknownSignature], Signatures)
-> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= ([UnknownSignature], Signatures)
-> Either InvalidSignature ([UnknownSignature], Signatures)
forall a b. b -> Either a b
Right ([ByteString -> UnknownSignature
UnknownSignature.MkUnknownSignature ByteString
byteString], [Signature] -> Signatures
Signatures.MkSignatures [])

  TestName -> Spec -> Spec
Tasty.describe TestName
"render" (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
    TestName -> Assertion -> Spec
Tasty.it TestName
"renders no signatures" (Assertion -> Spec) -> Assertion -> Spec
forall a b. (a -> b) -> a -> b
$ do
      let signatures :: Signatures
signatures = [Signature] -> Signatures
Signatures.MkSignatures []
      Signatures -> ByteString
Signatures.render Signatures
signatures ByteString -> ByteString -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= ByteString
ByteString.empty

    TestName -> Assertion -> Spec
Tasty.it TestName
"renders one signature" (Assertion -> Spec) -> Assertion -> Spec
forall a b. (a -> b) -> a -> b
$ do
      let signatures :: Signatures
signatures = [Signature] -> Signatures
Signatures.MkSignatures ([Signature] -> Signatures)
-> (Digest SHA256 -> [Signature]) -> Digest SHA256 -> Signatures
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Signature -> [Signature]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Signature -> [Signature])
-> (Digest SHA256 -> Signature) -> Digest SHA256 -> [Signature]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SymmetricSignature -> Signature
Signature.Symmetric (SymmetricSignature -> Signature)
-> (Digest SHA256 -> SymmetricSignature)
-> Digest SHA256
-> Signature
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Digest SHA256 -> SymmetricSignature
SymmetricSignature.MkSymmetricSignature (Digest SHA256 -> Signatures) -> Digest SHA256 -> Signatures
forall a b. (a -> b) -> a -> b
$ ByteString -> Digest SHA256
forall ba a.
(ByteArrayAccess ba, HashAlgorithm a) =>
ba -> Digest a
Hash.hash ByteString
ByteString.empty
      Signatures -> ByteString
Signatures.render Signatures
signatures ByteString -> ByteString -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= TestName -> ByteString
Ascii.pack TestName
"v1,47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU="

    TestName -> Assertion -> Spec
Tasty.it TestName
"renders many signatures" (Assertion -> Spec) -> Assertion -> Spec
forall a b. (a -> b) -> a -> b
$ do
      let symmetricSignature :: SymmetricSignature
symmetricSignature = Digest SHA256 -> SymmetricSignature
SymmetricSignature.MkSymmetricSignature (Digest SHA256 -> SymmetricSignature)
-> Digest SHA256 -> SymmetricSignature
forall a b. (a -> b) -> a -> b
$ ByteString -> Digest SHA256
forall ba a.
(ByteArrayAccess ba, HashAlgorithm a) =>
ba -> Digest a
Hash.hash ByteString
ByteString.empty
      AsymmetricSignature
asymmetricSignature <- (Signature -> AsymmetricSignature)
-> IO Signature -> IO AsymmetricSignature
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Signature -> AsymmetricSignature
AsymmetricSignature.MkAsymmetricSignature (IO Signature -> IO AsymmetricSignature)
-> (ByteString -> IO Signature)
-> ByteString
-> IO AsymmetricSignature
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CryptoFailable Signature -> IO Signature
forall a. CryptoFailable a -> IO a
Error.throwCryptoErrorIO (CryptoFailable Signature -> IO Signature)
-> (ByteString -> CryptoFailable Signature)
-> ByteString
-> IO Signature
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> CryptoFailable Signature
forall ba. ByteArrayAccess ba => ba -> CryptoFailable Signature
Ed25519.signature (ByteString -> IO AsymmetricSignature)
-> ByteString -> IO AsymmetricSignature
forall a b. (a -> b) -> a -> b
$ TestName -> ByteString
Ascii.pack TestName
"ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789-abcdefghijklmnopqrstuvqxyz"
      let signatures :: Signatures
signatures =
            [Signature] -> Signatures
Signatures.MkSignatures
              [ SymmetricSignature -> Signature
Signature.Symmetric SymmetricSignature
symmetricSignature,
                AsymmetricSignature -> Signature
Signature.Asymmetric AsymmetricSignature
asymmetricSignature
              ]
      Signatures -> ByteString
Signatures.render Signatures
signatures ByteString -> ByteString -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= TestName -> ByteString
Ascii.pack TestName
"v1,47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= v1a,QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVotMDEyMzQ1Njc4OS1hYmNkZWZnaGlqa2xtbm9wcXJzdHV2cXh5eg=="