module Signet.Unstable.Type.SignatureTest 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.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.Signature" (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
"fails with invalid asymmetric signature" (Assertion -> Spec) -> Assertion -> Spec
forall a b. (a -> b) -> a -> b
$ do
      let byteString :: ByteString
byteString = TestName -> ByteString
Ascii.pack TestName
"invalid"
      let result :: Either InvalidSignature (Either UnknownSignature Signature)
result = ByteString
-> Either InvalidSignature (Either UnknownSignature Signature)
Signature.parse (ByteString
 -> Either InvalidSignature (Either UnknownSignature Signature))
-> ByteString
-> Either InvalidSignature (Either UnknownSignature Signature)
forall a b. (a -> b) -> a -> b
$ TestName -> ByteString
Ascii.pack TestName
"v1a," ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
byteString
      Either InvalidSignature (Either UnknownSignature Signature)
result Either InvalidSignature (Either UnknownSignature Signature)
-> Either InvalidSignature (Either UnknownSignature Signature)
-> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= InvalidSignature
-> Either InvalidSignature (Either UnknownSignature Signature)
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
byteString)

    TestName -> Assertion -> Spec
Tasty.it TestName
"fails with invalid symmetric signature" (Assertion -> Spec) -> Assertion -> Spec
forall a b. (a -> b) -> a -> b
$ do
      let byteString :: ByteString
byteString = TestName -> ByteString
Ascii.pack TestName
"invalid"
      let result :: Either InvalidSignature (Either UnknownSignature Signature)
result = ByteString
-> Either InvalidSignature (Either UnknownSignature Signature)
Signature.parse (ByteString
 -> Either InvalidSignature (Either UnknownSignature Signature))
-> ByteString
-> Either InvalidSignature (Either UnknownSignature Signature)
forall a b. (a -> b) -> a -> b
$ TestName -> ByteString
Ascii.pack TestName
"v1," ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
byteString
      Either InvalidSignature (Either UnknownSignature Signature)
result Either InvalidSignature (Either UnknownSignature Signature)
-> Either InvalidSignature (Either UnknownSignature Signature)
-> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= InvalidSignature
-> Either InvalidSignature (Either UnknownSignature Signature)
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
byteString)

    TestName -> Assertion -> Spec
Tasty.it TestName
"returns unknown signature with unrecognized prefix" (Assertion -> Spec) -> Assertion -> Spec
forall a b. (a -> b) -> a -> b
$ do
      let byteString :: ByteString
byteString = TestName -> ByteString
Ascii.pack TestName
"unknown"
      let result :: Either InvalidSignature (Either UnknownSignature Signature)
result = ByteString
-> Either InvalidSignature (Either UnknownSignature Signature)
Signature.parse ByteString
byteString
      Either InvalidSignature (Either UnknownSignature Signature)
result Either InvalidSignature (Either UnknownSignature Signature)
-> Either InvalidSignature (Either UnknownSignature Signature)
-> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= Either UnknownSignature Signature
-> Either InvalidSignature (Either UnknownSignature Signature)
forall a b. b -> Either a b
Right (UnknownSignature -> Either UnknownSignature Signature
forall a b. a -> Either a b
Left (UnknownSignature -> Either UnknownSignature Signature)
-> UnknownSignature -> Either UnknownSignature Signature
forall a b. (a -> b) -> a -> b
$ ByteString -> UnknownSignature
UnknownSignature.MkUnknownSignature ByteString
byteString)

    TestName -> Assertion -> Spec
Tasty.it TestName
"succeeds with valid asymmetric signature" (Assertion -> Spec) -> Assertion -> Spec
forall a b. (a -> b) -> a -> b
$ do
      let byteString :: ByteString
byteString = TestName -> ByteString
Ascii.pack TestName
"v1a,QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVotMDEyMzQ1Njc4OS1hYmNkZWZnaGlqa2xtbm9wcXJzdHV2cXh5eg=="
      Signature
signature <- (Signature -> Signature) -> IO Signature -> IO Signature
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (AsymmetricSignature -> Signature
Signature.Asymmetric (AsymmetricSignature -> Signature)
-> (Signature -> AsymmetricSignature) -> Signature -> Signature
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Signature -> AsymmetricSignature
AsymmetricSignature.MkAsymmetricSignature) (IO Signature -> IO Signature)
-> (ByteString -> IO Signature) -> ByteString -> IO Signature
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 Signature) -> ByteString -> IO Signature
forall a b. (a -> b) -> a -> b
$ TestName -> ByteString
Ascii.pack TestName
"ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789-abcdefghijklmnopqrstuvqxyz"
      ByteString
-> Either InvalidSignature (Either UnknownSignature Signature)
Signature.parse ByteString
byteString Either InvalidSignature (Either UnknownSignature Signature)
-> Either InvalidSignature (Either UnknownSignature Signature)
-> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= Either UnknownSignature Signature
-> Either InvalidSignature (Either UnknownSignature Signature)
forall a b. b -> Either a b
Right (Signature -> Either UnknownSignature Signature
forall a b. b -> Either a b
Right Signature
signature)

    TestName -> Assertion -> Spec
Tasty.it TestName
"succeeds with valid symmetric signature" (Assertion -> Spec) -> Assertion -> Spec
forall a b. (a -> b) -> a -> b
$ do
      let byteString :: ByteString
byteString = TestName -> ByteString
Ascii.pack TestName
"v1,47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU="
      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
      ByteString
-> Either InvalidSignature (Either UnknownSignature Signature)
Signature.parse ByteString
byteString Either InvalidSignature (Either UnknownSignature Signature)
-> Either InvalidSignature (Either UnknownSignature Signature)
-> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= Either UnknownSignature Signature
-> Either InvalidSignature (Either UnknownSignature Signature)
forall a b. b -> Either a b
Right (Signature -> Either UnknownSignature Signature
forall a b. b -> Either a b
Right Signature
signature)

  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 asymmetric signature correctly" (Assertion -> Spec) -> Assertion -> Spec
forall a b. (a -> b) -> a -> b
$ do
      Signature
signature <- (Signature -> Signature) -> IO Signature -> IO Signature
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (AsymmetricSignature -> Signature
Signature.Asymmetric (AsymmetricSignature -> Signature)
-> (Signature -> AsymmetricSignature) -> Signature -> Signature
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Signature -> AsymmetricSignature
AsymmetricSignature.MkAsymmetricSignature) (IO Signature -> IO Signature)
-> (ByteString -> IO Signature) -> ByteString -> IO Signature
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 Signature) -> ByteString -> IO Signature
forall a b. (a -> b) -> a -> b
$ TestName -> ByteString
Ascii.pack TestName
"ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789-abcdefghijklmnopqrstuvqxyz"
      Signature -> ByteString
Signature.render Signature
signature ByteString -> ByteString -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= TestName -> ByteString
Ascii.pack TestName
"v1a,QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVotMDEyMzQ1Njc4OS1hYmNkZWZnaGlqa2xtbm9wcXJzdHV2cXh5eg=="

    TestName -> Assertion -> Spec
Tasty.it TestName
"renders symmetric signature correctly" (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
      Signature -> ByteString
Signature.render Signature
signature ByteString -> ByteString -> Assertion
forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
@?= TestName -> ByteString
Ascii.pack TestName
"v1,47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU="