signet (empty) → 0.2025.5.5
raw patch · 74 files changed
+2125/−0 lines, 74 filesdep +basedep +bytestringdep +case-insensitive
Dependencies added: base, bytestring, case-insensitive, crypton, exceptions, http-types, memory, signet, tasty, tasty-hunit, text, time, transformers
Files
- CHANGELOG.md +4/−0
- LICENSE.txt +14/−0
- README.md +4/−0
- signet.cabal +165/−0
- source/libraries/signet/Signet.hs +88/−0
- source/libraries/test/Signet/Unstable/Exception/InvalidAsymmetricSignatureTest.hs +7/−0
- source/libraries/test/Signet/Unstable/Exception/InvalidIdTest.hs +7/−0
- source/libraries/test/Signet/Unstable/Exception/InvalidMessageTest.hs +7/−0
- source/libraries/test/Signet/Unstable/Exception/InvalidPublicKeyTest.hs +7/−0
- source/libraries/test/Signet/Unstable/Exception/InvalidSecretKeyTest.hs +7/−0
- source/libraries/test/Signet/Unstable/Exception/InvalidSecretTest.hs +7/−0
- source/libraries/test/Signet/Unstable/Exception/InvalidSignatureTest.hs +7/−0
- source/libraries/test/Signet/Unstable/Exception/InvalidSignerTest.hs +7/−0
- source/libraries/test/Signet/Unstable/Exception/InvalidSymmetricSignatureTest.hs +7/−0
- source/libraries/test/Signet/Unstable/Exception/InvalidTimestampTest.hs +7/−0
- source/libraries/test/Signet/Unstable/Exception/InvalidVerifierTest.hs +7/−0
- source/libraries/test/Signet/Unstable/Exception/SignetExceptionTest.hs +7/−0
- source/libraries/test/Signet/Unstable/Exception/ToleranceExceptionTest.hs +7/−0
- source/libraries/test/Signet/Unstable/Exception/VerificationExceptionTest.hs +7/−0
- source/libraries/test/Signet/Unstable/Extra/EitherTest.hs +31/−0
- source/libraries/test/Signet/Unstable/Extra/HttpTest.hs +21/−0
- source/libraries/test/Signet/Unstable/Extra/MaybeTest.hs +15/−0
- source/libraries/test/Signet/Unstable/Extra/Tasty.hs +13/−0
- source/libraries/test/Signet/Unstable/Type/AsymmetricSignatureTest.hs +27/−0
- source/libraries/test/Signet/Unstable/Type/IdTest.hs +26/−0
- source/libraries/test/Signet/Unstable/Type/MessageTest.hs +47/−0
- source/libraries/test/Signet/Unstable/Type/PayloadTest.hs +7/−0
- source/libraries/test/Signet/Unstable/Type/PublicKeyTest.hs +32/−0
- source/libraries/test/Signet/Unstable/Type/SecretKeyTest.hs +32/−0
- source/libraries/test/Signet/Unstable/Type/SecretTest.hs +31/−0
- source/libraries/test/Signet/Unstable/Type/SignatureTest.hs +53/−0
- source/libraries/test/Signet/Unstable/Type/SignaturesTest.hs +72/−0
- source/libraries/test/Signet/Unstable/Type/SignerTest.hs +76/−0
- source/libraries/test/Signet/Unstable/Type/SymmetricSignatureTest.hs +27/−0
- source/libraries/test/Signet/Unstable/Type/TimestampTest.hs +33/−0
- source/libraries/test/Signet/Unstable/Type/ToleranceTest.hs +34/−0
- source/libraries/test/Signet/Unstable/Type/UnknownSignatureTest.hs +7/−0
- source/libraries/test/Signet/Unstable/Type/VerifierTest.hs +110/−0
- source/libraries/test/Signet/UnstableTest.hs +57/−0
- source/libraries/test/SignetTest.hs +73/−0
- source/libraries/unstable/Signet/Unstable.hs +196/−0
- source/libraries/unstable/Signet/Unstable/Exception/InvalidAsymmetricSignature.hs +14/−0
- source/libraries/unstable/Signet/Unstable/Exception/InvalidId.hs +14/−0
- source/libraries/unstable/Signet/Unstable/Exception/InvalidMessage.hs +18/−0
- source/libraries/unstable/Signet/Unstable/Exception/InvalidPublicKey.hs +14/−0
- source/libraries/unstable/Signet/Unstable/Exception/InvalidSecret.hs +14/−0
- source/libraries/unstable/Signet/Unstable/Exception/InvalidSecretKey.hs +14/−0
- source/libraries/unstable/Signet/Unstable/Exception/InvalidSignature.hs +18/−0
- source/libraries/unstable/Signet/Unstable/Exception/InvalidSigner.hs +14/−0
- source/libraries/unstable/Signet/Unstable/Exception/InvalidSymmetricSignature.hs +14/−0
- source/libraries/unstable/Signet/Unstable/Exception/InvalidTimestamp.hs +14/−0
- source/libraries/unstable/Signet/Unstable/Exception/InvalidVerifier.hs +14/−0
- source/libraries/unstable/Signet/Unstable/Exception/SignetException.hs +18/−0
- source/libraries/unstable/Signet/Unstable/Exception/ToleranceException.hs +14/−0
- source/libraries/unstable/Signet/Unstable/Exception/VerificationException.hs +14/−0
- source/libraries/unstable/Signet/Unstable/Extra/Either.hs +9/−0
- source/libraries/unstable/Signet/Unstable/Extra/Http.hs +14/−0
- source/libraries/unstable/Signet/Unstable/Extra/Maybe.hs +4/−0
- source/libraries/unstable/Signet/Unstable/Type/AsymmetricSignature.hs +28/−0
- source/libraries/unstable/Signet/Unstable/Type/Id.hs +26/−0
- source/libraries/unstable/Signet/Unstable/Type/Message.hs +36/−0
- source/libraries/unstable/Signet/Unstable/Type/Payload.hs +10/−0
- source/libraries/unstable/Signet/Unstable/Type/PublicKey.hs +31/−0
- source/libraries/unstable/Signet/Unstable/Type/Secret.hs +27/−0
- source/libraries/unstable/Signet/Unstable/Type/SecretKey.hs +31/−0
- source/libraries/unstable/Signet/Unstable/Type/Signature.hs +49/−0
- source/libraries/unstable/Signet/Unstable/Type/Signatures.hs +30/−0
- source/libraries/unstable/Signet/Unstable/Type/Signer.hs +49/−0
- source/libraries/unstable/Signet/Unstable/Type/SymmetricSignature.hs +28/−0
- source/libraries/unstable/Signet/Unstable/Type/Timestamp.hs +33/−0
- source/libraries/unstable/Signet/Unstable/Type/Tolerance.hs +29/−0
- source/libraries/unstable/Signet/Unstable/Type/UnknownSignature.hs +10/−0
- source/libraries/unstable/Signet/Unstable/Type/Verifier.hs +75/−0
- source/test-suite/Main.hs +5/−0
+ CHANGELOG.md view
@@ -0,0 +1,4 @@+# Change log++Signet follows the [Package Versioning Policy](https://pvp.haskell.org). You can+find release notes [on GitHub](https://github.com/MercuryTechnologies/signet/releases).
+ LICENSE.txt view
@@ -0,0 +1,14 @@+BSD Zero Clause License++Copyright (c) 2025 Mercury Technologies, Inc.++Permission to use, copy, modify, and/or distribute this software for any+purpose with or without fee is hereby granted.++THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY+AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR+PERFORMANCE OF THIS SOFTWARE.
+ README.md view
@@ -0,0 +1,4 @@+# Signet++Signet is a Haskell library for working with+[Standard Webhooks](https://www.standardwebhooks.com).
+ signet.cabal view
@@ -0,0 +1,165 @@+cabal-version: 3.0+name: signet+version: 0.2025.5.5+synopsis: Standard Webhooks+description:+ Signet is a Haskell library for working with Standard Webhooks.++category: Web+license: 0BSD+license-file: LICENSE.txt+maintainer: Mercury Technologies, Inc.+extra-doc-files:+ CHANGELOG.md+ README.md++source-repository head+ location: https://github.com/MercuryTechnologies/signet+ type: git++flag pedantic+ default: False+ manual: True++common library+ build-depends: base ^>=4.19 || ^>=4.20 || ^>=4.21+ default-language: Haskell2010+ ghc-options:+ -Weverything+ -Wno-all-missed-specialisations+ -Wno-implicit-prelude+ -Wno-missed-specialisations+ -Wno-missing-deriving-strategies+ -Wno-missing-export-lists+ -Wno-missing-kind-signatures+ -Wno-missing-safe-haskell-mode+ -Wno-prepositive-qualified-module+ -Wno-safe+ -Wno-unsafe++ if flag(pedantic)+ ghc-options: -Werror++common executable+ import: library+ ghc-options:+ -rtsopts+ -threaded++common dependencies+ build-depends:+ bytestring ^>=0.12,+ case-insensitive ^>=1.2.1.0,+ crypton ^>=0.34 || ^>=1.0.4,+ exceptions ^>=0.10.7,+ memory ^>=0.18.0,+ time ^>=1.12.2,++library unstable+ import: library, dependencies+ build-depends:+ http-types ^>=0.12.4,+ text ^>=2.0 || ^>=2.1,++ -- cabal-gild: discover source/libraries/unstable+ exposed-modules:+ Signet.Unstable+ Signet.Unstable.Exception.InvalidAsymmetricSignature+ Signet.Unstable.Exception.InvalidId+ Signet.Unstable.Exception.InvalidMessage+ Signet.Unstable.Exception.InvalidPublicKey+ Signet.Unstable.Exception.InvalidSecret+ Signet.Unstable.Exception.InvalidSecretKey+ Signet.Unstable.Exception.InvalidSignature+ Signet.Unstable.Exception.InvalidSigner+ Signet.Unstable.Exception.InvalidSymmetricSignature+ Signet.Unstable.Exception.InvalidTimestamp+ Signet.Unstable.Exception.InvalidVerifier+ Signet.Unstable.Exception.SignetException+ Signet.Unstable.Exception.ToleranceException+ Signet.Unstable.Exception.VerificationException+ Signet.Unstable.Extra.Either+ Signet.Unstable.Extra.Http+ Signet.Unstable.Extra.Maybe+ Signet.Unstable.Type.AsymmetricSignature+ Signet.Unstable.Type.Id+ Signet.Unstable.Type.Message+ Signet.Unstable.Type.Payload+ Signet.Unstable.Type.PublicKey+ Signet.Unstable.Type.Secret+ Signet.Unstable.Type.SecretKey+ Signet.Unstable.Type.Signature+ Signet.Unstable.Type.Signatures+ Signet.Unstable.Type.Signer+ Signet.Unstable.Type.SymmetricSignature+ Signet.Unstable.Type.Timestamp+ Signet.Unstable.Type.Tolerance+ Signet.Unstable.Type.UnknownSignature+ Signet.Unstable.Type.Verifier++ hs-source-dirs: source/libraries/unstable++library+ import: library+ build-depends: signet:unstable+ -- cabal-gild: discover source/libraries/signet+ exposed-modules: Signet+ hs-source-dirs: source/libraries/signet++library test+ import: library, dependencies+ build-depends:+ signet:unstable,+ tasty ^>=1.4 || ^>=1.5.3,+ tasty-hunit ^>=0.10.2,+ transformers ^>=0.6.1.0,++ -- cabal-gild: discover source/libraries/test+ exposed-modules:+ Signet.Unstable.Exception.InvalidAsymmetricSignatureTest+ Signet.Unstable.Exception.InvalidIdTest+ Signet.Unstable.Exception.InvalidMessageTest+ Signet.Unstable.Exception.InvalidPublicKeyTest+ Signet.Unstable.Exception.InvalidSecretKeyTest+ Signet.Unstable.Exception.InvalidSecretTest+ Signet.Unstable.Exception.InvalidSignatureTest+ Signet.Unstable.Exception.InvalidSignerTest+ Signet.Unstable.Exception.InvalidSymmetricSignatureTest+ Signet.Unstable.Exception.InvalidTimestampTest+ Signet.Unstable.Exception.InvalidVerifierTest+ Signet.Unstable.Exception.SignetExceptionTest+ Signet.Unstable.Exception.ToleranceExceptionTest+ Signet.Unstable.Exception.VerificationExceptionTest+ Signet.Unstable.Extra.EitherTest+ Signet.Unstable.Extra.HttpTest+ Signet.Unstable.Extra.MaybeTest+ Signet.Unstable.Extra.Tasty+ Signet.Unstable.Type.AsymmetricSignatureTest+ Signet.Unstable.Type.IdTest+ Signet.Unstable.Type.MessageTest+ Signet.Unstable.Type.PayloadTest+ Signet.Unstable.Type.PublicKeyTest+ Signet.Unstable.Type.SecretKeyTest+ Signet.Unstable.Type.SecretTest+ Signet.Unstable.Type.SignatureTest+ Signet.Unstable.Type.SignaturesTest+ Signet.Unstable.Type.SignerTest+ Signet.Unstable.Type.SymmetricSignatureTest+ Signet.Unstable.Type.TimestampTest+ Signet.Unstable.Type.ToleranceTest+ Signet.Unstable.Type.UnknownSignatureTest+ Signet.Unstable.Type.VerifierTest+ Signet.UnstableTest+ SignetTest++ hs-source-dirs: source/libraries/test++test-suite signet-test-suite+ import: executable+ build-depends:+ signet:test,+ tasty,++ hs-source-dirs: source/test-suite+ main-is: Main.hs+ type: exitcode-stdio-1.0
+ source/libraries/signet/Signet.hs view
@@ -0,0 +1,88 @@+module Signet+ ( -- * Verification+ Signet.Unstable.verifyWebhookText,+ Signet.Unstable.verifyWebhookByteString,+ Signet.Unstable.verifyWebhook,+ Signet.Unstable.verifyWebhookWith,++ -- * Signing+ Signet.Unstable.signWebhook,++ -- * Headers+ Signet.Unstable.Extra.Http.hWebhookId,+ Signet.Unstable.Extra.Http.hWebhookTimestamp,+ Signet.Unstable.Extra.Http.hWebhookSignature,++ -- * Types+ Signet.Unstable.Type.AsymmetricSignature.AsymmetricSignature (..),+ Signet.Unstable.Type.Id.Id (..),+ Signet.Unstable.parseId,+ Signet.Unstable.Type.Message.Message (..),+ Signet.Unstable.parseMessage,+ Signet.Unstable.Type.Payload.Payload (..),+ Signet.Unstable.Type.PublicKey.PublicKey (..),+ Signet.Unstable.Type.Secret.Secret (..),+ Signet.Unstable.Type.SecretKey.SecretKey (..),+ Signet.Unstable.Type.Signature.Signature (Signet.Unstable.AsymmetricSignature, Signet.Unstable.SymmetricSignature),+ Signet.Unstable.Type.Signatures.Signatures (..),+ Signet.Unstable.parseSignatures,+ Signet.Unstable.Type.Signer.Signer (Signet.Unstable.AsymmetricSigner, Signet.Unstable.SymmetricSigner),+ Signet.Unstable.parseSigner,+ Signet.Unstable.Type.SymmetricSignature.SymmetricSignature (..),+ Signet.Unstable.Type.Timestamp.Timestamp (..),+ Signet.Unstable.parseTimestamp,+ Signet.Unstable.Type.Tolerance.Tolerance (..),+ Signet.Unstable.typicalTolerance,+ Signet.Unstable.Type.UnknownSignature.UnknownSignature (..),+ Signet.Unstable.Type.Verifier.Verifier (Signet.Unstable.AsymmetricVerifier, Signet.Unstable.SymmetricVerifier),+ Signet.Unstable.parseVerifier,++ -- * Exceptions+ Signet.Unstable.Exception.InvalidAsymmetricSignature.InvalidAsymmetricSignature (..),+ Signet.Unstable.Exception.InvalidId.InvalidId (..),+ Signet.Unstable.Exception.InvalidMessage.InvalidMessage (..),+ Signet.Unstable.Exception.InvalidPublicKey.InvalidPublicKey (..),+ Signet.Unstable.Exception.InvalidSecret.InvalidSecret (..),+ Signet.Unstable.Exception.InvalidSecretKey.InvalidSecretKey (..),+ Signet.Unstable.Exception.InvalidSignature.InvalidSignature (..),+ Signet.Unstable.Exception.InvalidSigner.InvalidSigner (..),+ Signet.Unstable.Exception.InvalidSymmetricSignature.InvalidSymmetricSignature (..),+ Signet.Unstable.Exception.InvalidTimestamp.InvalidTimestamp (..),+ Signet.Unstable.Exception.InvalidVerifier.InvalidVerifier (..),+ Signet.Unstable.Exception.SignetException.SignetException (..),+ Signet.Unstable.Exception.ToleranceException.ToleranceException (..),+ Signet.Unstable.Exception.VerificationException.VerificationException (..),+ )+where++import qualified Signet.Unstable+import qualified Signet.Unstable.Exception.InvalidAsymmetricSignature+import qualified Signet.Unstable.Exception.InvalidId+import qualified Signet.Unstable.Exception.InvalidMessage+import qualified Signet.Unstable.Exception.InvalidPublicKey+import qualified Signet.Unstable.Exception.InvalidSecret+import qualified Signet.Unstable.Exception.InvalidSecretKey+import qualified Signet.Unstable.Exception.InvalidSignature+import qualified Signet.Unstable.Exception.InvalidSigner+import qualified Signet.Unstable.Exception.InvalidSymmetricSignature+import qualified Signet.Unstable.Exception.InvalidTimestamp+import qualified Signet.Unstable.Exception.InvalidVerifier+import qualified Signet.Unstable.Exception.SignetException+import qualified Signet.Unstable.Exception.ToleranceException+import qualified Signet.Unstable.Exception.VerificationException+import qualified Signet.Unstable.Extra.Http+import qualified Signet.Unstable.Type.AsymmetricSignature+import qualified Signet.Unstable.Type.Id+import qualified Signet.Unstable.Type.Message+import qualified Signet.Unstable.Type.Payload+import qualified Signet.Unstable.Type.PublicKey+import qualified Signet.Unstable.Type.Secret+import qualified Signet.Unstable.Type.SecretKey+import qualified Signet.Unstable.Type.Signature+import qualified Signet.Unstable.Type.Signatures+import qualified Signet.Unstable.Type.Signer+import qualified Signet.Unstable.Type.SymmetricSignature+import qualified Signet.Unstable.Type.Timestamp+import qualified Signet.Unstable.Type.Tolerance+import qualified Signet.Unstable.Type.UnknownSignature+import qualified Signet.Unstable.Type.Verifier
+ source/libraries/test/Signet/Unstable/Exception/InvalidAsymmetricSignatureTest.hs view
@@ -0,0 +1,7 @@+module Signet.Unstable.Exception.InvalidAsymmetricSignatureTest where++import qualified Signet.Unstable.Extra.Tasty as Tasty++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Exception.InvalidAsymmetricSignature" $ do+ pure ()
+ source/libraries/test/Signet/Unstable/Exception/InvalidIdTest.hs view
@@ -0,0 +1,7 @@+module Signet.Unstable.Exception.InvalidIdTest where++import qualified Signet.Unstable.Extra.Tasty as Tasty++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Exception.InvalidId" $ do+ pure ()
+ source/libraries/test/Signet/Unstable/Exception/InvalidMessageTest.hs view
@@ -0,0 +1,7 @@+module Signet.Unstable.Exception.InvalidMessageTest where++import qualified Signet.Unstable.Extra.Tasty as Tasty++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Exception.InvalidMessage" $ do+ pure ()
+ source/libraries/test/Signet/Unstable/Exception/InvalidPublicKeyTest.hs view
@@ -0,0 +1,7 @@+module Signet.Unstable.Exception.InvalidPublicKeyTest where++import qualified Signet.Unstable.Extra.Tasty as Tasty++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Exception.InvalidPublicKey" $ do+ pure ()
+ source/libraries/test/Signet/Unstable/Exception/InvalidSecretKeyTest.hs view
@@ -0,0 +1,7 @@+module Signet.Unstable.Exception.InvalidSecretKeyTest where++import qualified Signet.Unstable.Extra.Tasty as Tasty++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Exception.InvalidSecretKey" $ do+ pure ()
+ source/libraries/test/Signet/Unstable/Exception/InvalidSecretTest.hs view
@@ -0,0 +1,7 @@+module Signet.Unstable.Exception.InvalidSecretTest where++import qualified Signet.Unstable.Extra.Tasty as Tasty++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Exception.InvalidSecret" $ do+ pure ()
+ source/libraries/test/Signet/Unstable/Exception/InvalidSignatureTest.hs view
@@ -0,0 +1,7 @@+module Signet.Unstable.Exception.InvalidSignatureTest where++import qualified Signet.Unstable.Extra.Tasty as Tasty++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Exception.InvalidSignature" $ do+ pure ()
+ source/libraries/test/Signet/Unstable/Exception/InvalidSignerTest.hs view
@@ -0,0 +1,7 @@+module Signet.Unstable.Exception.InvalidSignerTest where++import qualified Signet.Unstable.Extra.Tasty as Tasty++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Exception.InvalidSigner" $ do+ pure ()
+ source/libraries/test/Signet/Unstable/Exception/InvalidSymmetricSignatureTest.hs view
@@ -0,0 +1,7 @@+module Signet.Unstable.Exception.InvalidSymmetricSignatureTest where++import qualified Signet.Unstable.Extra.Tasty as Tasty++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Exception.InvalidSymmetricSignature" $ do+ pure ()
+ source/libraries/test/Signet/Unstable/Exception/InvalidTimestampTest.hs view
@@ -0,0 +1,7 @@+module Signet.Unstable.Exception.InvalidTimestampTest where++import qualified Signet.Unstable.Extra.Tasty as Tasty++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Exception.InvalidTimestamp" $ do+ pure ()
+ source/libraries/test/Signet/Unstable/Exception/InvalidVerifierTest.hs view
@@ -0,0 +1,7 @@+module Signet.Unstable.Exception.InvalidVerifierTest where++import qualified Signet.Unstable.Extra.Tasty as Tasty++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Exception.InvalidVerifier" $ do+ pure ()
+ source/libraries/test/Signet/Unstable/Exception/SignetExceptionTest.hs view
@@ -0,0 +1,7 @@+module Signet.Unstable.Exception.SignetExceptionTest where++import qualified Signet.Unstable.Extra.Tasty as Tasty++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Exception.SignetException" $ do+ pure ()
+ source/libraries/test/Signet/Unstable/Exception/ToleranceExceptionTest.hs view
@@ -0,0 +1,7 @@+module Signet.Unstable.Exception.ToleranceExceptionTest where++import qualified Signet.Unstable.Extra.Tasty as Tasty++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Exception.ToleranceException" $ do+ pure ()
+ source/libraries/test/Signet/Unstable/Exception/VerificationExceptionTest.hs view
@@ -0,0 +1,7 @@+module Signet.Unstable.Exception.VerificationExceptionTest where++import qualified Signet.Unstable.Extra.Tasty as Tasty++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Exception.VerificationException" $ do+ pure ()
+ source/libraries/test/Signet/Unstable/Extra/EitherTest.hs view
@@ -0,0 +1,31 @@+module Signet.Unstable.Extra.EitherTest where++import qualified Control.Monad.Catch as Exception+import qualified Data.Void as Void+import qualified Signet.Unstable.Extra.Either as Either+import qualified Signet.Unstable.Extra.Tasty as Tasty+import Test.Tasty.HUnit ((@?=))++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Extra.Either" $ do+ Tasty.describe "hush" $ do+ Tasty.it "works with Left" $ do+ Either.hush (Left () :: Either () Void.Void) @?= Nothing++ Tasty.it "works with Right" $ do+ Either.hush (Right () :: Either Void.Void ()) @?= Just ()++ Tasty.describe "throw" $ do+ Tasty.it "throws an exception for Left" $ do+ result <- Exception.try . Either.throw $ Left MkTestException+ result @?= (Left MkTestException :: Either TestException Void.Void)++ Tasty.it "returns the value for Right" $ do+ value <- Either.throw (Right () :: Either Void.Void ())+ value @?= ()++data TestException+ = MkTestException+ deriving (Eq, Show)++instance Exception.Exception TestException
+ source/libraries/test/Signet/Unstable/Extra/HttpTest.hs view
@@ -0,0 +1,21 @@+module Signet.Unstable.Extra.HttpTest where++import qualified Data.ByteString.Char8 as Ascii+import qualified Data.CaseInsensitive as CI+import qualified Signet.Unstable.Extra.Http as Http+import qualified Signet.Unstable.Extra.Tasty as Tasty+import Test.Tasty.HUnit ((@?=))++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Extra.Http" $ do+ Tasty.describe "hWebhookId" $ do+ Tasty.it "creates the correct header name" $ do+ Http.hWebhookId @?= CI.mk (Ascii.pack "webhook-id")++ Tasty.describe "hWebhookSignature" $ do+ Tasty.it "creates the correct header name" $ do+ Http.hWebhookSignature @?= CI.mk (Ascii.pack "webhook-signature")++ Tasty.describe "hWebhookTimestamp" $ do+ Tasty.it "creates the correct header name" $ do+ Http.hWebhookTimestamp @?= CI.mk (Ascii.pack "webhook-timestamp")
+ source/libraries/test/Signet/Unstable/Extra/MaybeTest.hs view
@@ -0,0 +1,15 @@+module Signet.Unstable.Extra.MaybeTest where++import qualified Data.Void as Void+import qualified Signet.Unstable.Extra.Maybe as Maybe+import qualified Signet.Unstable.Extra.Tasty as Tasty+import Test.Tasty.HUnit ((@?=))++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Extra.Maybe" $ do+ Tasty.describe "note" $ do+ Tasty.it "works with nothing" $ do+ Maybe.note () (Nothing :: Maybe Void.Void) @?= Left ()++ Tasty.it "works with just" $ do+ Maybe.note () (Just True) @?= Right True
+ source/libraries/test/Signet/Unstable/Extra/Tasty.hs view
@@ -0,0 +1,13 @@+module Signet.Unstable.Extra.Tasty where++import qualified Control.Monad.Trans.Writer as Writer+import qualified Test.Tasty as Tasty+import qualified Test.Tasty.HUnit as Tasty++type Spec = Writer.Writer [Tasty.TestTree] ()++describe :: Tasty.TestName -> Spec -> Spec+describe testName = Writer.tell . pure . Tasty.testGroup testName . Writer.execWriter++it :: Tasty.TestName -> Tasty.Assertion -> Spec+it testName = Writer.tell . pure . Tasty.testCase testName
+ source/libraries/test/Signet/Unstable/Type/AsymmetricSignatureTest.hs view
@@ -0,0 +1,27 @@+module Signet.Unstable.Type.AsymmetricSignatureTest where++import qualified Crypto.Error as Error+import qualified Crypto.PubKey.Ed25519 as Ed25519+import qualified Data.ByteString.Char8 as Ascii+import qualified Signet.Unstable.Exception.InvalidAsymmetricSignature as InvalidAsymmetricSignature+import qualified Signet.Unstable.Extra.Tasty as Tasty+import qualified Signet.Unstable.Type.AsymmetricSignature as AsymmetricSignature+import Test.Tasty.HUnit ((@?=))++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Type.AsymmetricSignature" $ do+ Tasty.describe "parse" $ do+ Tasty.it "fails with invalid input" $ do+ let byteString = Ascii.pack "invalid"+ let result = AsymmetricSignature.parse byteString+ result @?= Left (InvalidAsymmetricSignature.MkInvalidAsymmetricSignature byteString)++ Tasty.it "succeeds with valid input" $ do+ let result = AsymmetricSignature.parse $ Ascii.pack "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVotMDEyMzQ1Njc4OS1hYmNkZWZnaGlqa2xtbm9wcXJzdHV2cXh5eg=="+ signature <- Error.throwCryptoErrorIO . Ed25519.signature $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789-abcdefghijklmnopqrstuvqxyz"+ result @?= Right (AsymmetricSignature.MkAsymmetricSignature signature)++ Tasty.describe "render" $ do+ Tasty.it "works" $ do+ asymmetricSignature <- fmap AsymmetricSignature.MkAsymmetricSignature . Error.throwCryptoErrorIO . Ed25519.signature $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789-abcdefghijklmnopqrstuvqxyz"+ AsymmetricSignature.render asymmetricSignature @?= Ascii.pack "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVotMDEyMzQ1Njc4OS1hYmNkZWZnaGlqa2xtbm9wcXJzdHV2cXh5eg=="
+ source/libraries/test/Signet/Unstable/Type/IdTest.hs view
@@ -0,0 +1,26 @@+module Signet.Unstable.Type.IdTest where++import qualified Data.ByteString.Char8 as Ascii+import qualified Signet.Unstable.Exception.InvalidId as InvalidId+import qualified Signet.Unstable.Extra.Tasty as Tasty+import qualified Signet.Unstable.Type.Id as Id+import Test.Tasty.HUnit ((@?=))++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Type.Id" $ do+ Tasty.describe "parse" $ do+ Tasty.it "fails with input containing separator" $ do+ let byteString = Ascii.pack "invalid.id"+ let result = Id.parse byteString+ result @?= Left (InvalidId.MkInvalidId byteString)++ Tasty.it "succeeds with valid input" $ do+ let byteString = Ascii.pack "valid-id"+ let result = Id.parse byteString+ result @?= Right (Id.MkId byteString)++ Tasty.describe "render" $ do+ Tasty.it "returns the original ByteString" $ do+ let byteString = Ascii.pack "valid-id"+ let id_ = Id.MkId byteString+ Id.render id_ @?= byteString
+ source/libraries/test/Signet/Unstable/Type/MessageTest.hs view
@@ -0,0 +1,47 @@+module Signet.Unstable.Type.MessageTest where++import qualified Data.ByteString.Char8 as Ascii+import qualified Signet.Unstable.Exception.InvalidMessage as InvalidMessage+import qualified Signet.Unstable.Exception.InvalidTimestamp as InvalidTimestamp+import qualified Signet.Unstable.Extra.Either as Either+import qualified Signet.Unstable.Extra.Tasty as Tasty+import qualified Signet.Unstable.Type.Id as Id+import qualified Signet.Unstable.Type.Message as Message+import qualified Signet.Unstable.Type.Payload as Payload+import qualified Signet.Unstable.Type.Timestamp as Timestamp+import Test.Tasty.HUnit ((@?=))++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Type.Message" $ do+ Tasty.describe "parse" $ do+ Tasty.it "fails with invalid timestamp" $ do+ let timestamp = Ascii.pack "invalid"+ let byteString = Ascii.pack "i." <> timestamp <> Ascii.pack ".p"+ let result = Message.parse byteString+ result @?= Left (InvalidMessage.InvalidTimestamp $ InvalidTimestamp.MkInvalidTimestamp timestamp)++ Tasty.it "succeeds with valid input" $ do+ let result = Message.parse $ Ascii.pack "i.0.p"+ id_ <- Either.throw . Id.parse $ Ascii.pack "i"+ timestamp <- Either.throw . Timestamp.parse $ Ascii.pack "0"+ let payload = Payload.MkPayload $ Ascii.pack "p"+ result+ @?= Right+ Message.MkMessage+ { Message.id_ = id_,+ Message.timestamp = timestamp,+ Message.payload = payload+ }++ Tasty.describe "render" $ do+ Tasty.it "returns the correct ByteString representation" $ do+ id_ <- Either.throw . Id.parse $ Ascii.pack "i"+ timestamp <- Either.throw . Timestamp.parse $ Ascii.pack "0"+ let payload = Payload.MkPayload $ Ascii.pack "p"+ let message =+ Message.MkMessage+ { Message.id_ = id_,+ Message.timestamp = timestamp,+ Message.payload = payload+ }+ Message.render message @?= Ascii.pack "i.0.p"
+ source/libraries/test/Signet/Unstable/Type/PayloadTest.hs view
@@ -0,0 +1,7 @@+module Signet.Unstable.Type.PayloadTest where++import qualified Signet.Unstable.Extra.Tasty as Tasty++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Type.Payload" $ do+ pure ()
+ source/libraries/test/Signet/Unstable/Type/PublicKeyTest.hs view
@@ -0,0 +1,32 @@+module Signet.Unstable.Type.PublicKeyTest where++import qualified Crypto.Error as Error+import qualified Crypto.PubKey.Ed25519 as Ed25519+import qualified Data.ByteString.Char8 as Ascii+import qualified Signet.Unstable.Exception.InvalidPublicKey as InvalidPublicKey+import qualified Signet.Unstable.Extra.Tasty as Tasty+import qualified Signet.Unstable.Type.PublicKey as PublicKey+import Test.Tasty.HUnit ((@?=))++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Type.PublicKey" $ do+ Tasty.describe "parse" $ do+ Tasty.it "fails with invalid prefix" $ do+ let byteString = Ascii.pack "invalid"+ let result = PublicKey.parse byteString+ result @?= Left (InvalidPublicKey.MkInvalidPublicKey byteString)++ Tasty.it "fails with invalid input" $ do+ let byteString = Ascii.pack "whpk_invalid"+ let result = PublicKey.parse byteString+ result @?= Left (InvalidPublicKey.MkInvalidPublicKey byteString)++ Tasty.it "succeeds with valid input" $ do+ let result = PublicKey.parse $ Ascii.pack "whpk_QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIzNDU="+ publicKey <- fmap PublicKey.MkPublicKey . Error.throwCryptoErrorIO . Ed25519.publicKey $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"+ result @?= Right publicKey++ Tasty.describe "render" $ do+ Tasty.it "works" $ do+ publicKey <- fmap PublicKey.MkPublicKey . Error.throwCryptoErrorIO . Ed25519.publicKey $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"+ PublicKey.render publicKey @?= Ascii.pack "whpk_QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIzNDU="
+ source/libraries/test/Signet/Unstable/Type/SecretKeyTest.hs view
@@ -0,0 +1,32 @@+module Signet.Unstable.Type.SecretKeyTest where++import qualified Crypto.Error as Error+import qualified Crypto.PubKey.Ed25519 as Ed25519+import qualified Data.ByteString.Char8 as Ascii+import qualified Signet.Unstable.Exception.InvalidSecretKey as InvalidSecretKey+import qualified Signet.Unstable.Extra.Tasty as Tasty+import qualified Signet.Unstable.Type.SecretKey as SecretKey+import Test.Tasty.HUnit ((@?=))++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Type.SecretKey" $ do+ Tasty.describe "parse" $ do+ Tasty.it "fails with invalid prefix" $ do+ let byteString = Ascii.pack "invalid"+ let result = SecretKey.parse byteString+ result @?= Left (InvalidSecretKey.MkInvalidSecretKey byteString)++ Tasty.it "fails with invalid input" $ do+ let byteString = Ascii.pack "whsk_invalid"+ let result = SecretKey.parse byteString+ result @?= Left (InvalidSecretKey.MkInvalidSecretKey byteString)++ Tasty.it "succeeds with valid input" $ do+ let result = SecretKey.parse $ Ascii.pack "whsk_QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIzNDU="+ secretKey <- fmap SecretKey.MkSecretKey . Error.throwCryptoErrorIO . Ed25519.secretKey $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"+ result @?= Right secretKey++ Tasty.describe "render" $ do+ Tasty.it "works" $ do+ secretKey <- fmap SecretKey.MkSecretKey . Error.throwCryptoErrorIO . Ed25519.secretKey $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"+ SecretKey.render secretKey @?= Ascii.pack "whsk_QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIzNDU="
+ source/libraries/test/Signet/Unstable/Type/SecretTest.hs view
@@ -0,0 +1,31 @@+module Signet.Unstable.Type.SecretTest where++import qualified Data.ByteArray as ByteArray+import qualified Data.ByteString.Char8 as Ascii+import qualified Signet.Unstable.Exception.InvalidSecret as InvalidSecret+import qualified Signet.Unstable.Extra.Tasty as Tasty+import qualified Signet.Unstable.Type.Secret as Secret+import Test.Tasty.HUnit ((@?=))++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Type.Secret" $ do+ Tasty.describe "parse" $ do+ Tasty.it "fails with invalid prefix" $ do+ let byteString = Ascii.pack "invalid"+ let result = Secret.parse byteString+ result @?= Left (InvalidSecret.MkInvalidSecret byteString)++ Tasty.it "fails with invalid input" $ do+ let byteString = Ascii.pack "whsec_invalid"+ let result = Secret.parse byteString+ result @?= Left (InvalidSecret.MkInvalidSecret byteString)++ Tasty.it "succeeds with valid input" $ do+ let result = Secret.parse $ Ascii.pack "whsec_MDEyMzQ1Njc4OQ=="+ let secret = Secret.MkSecret . ByteArray.convert $ Ascii.pack "0123456789"+ result @?= Right secret++ Tasty.describe "render" $ do+ Tasty.it "works" $ do+ let secret = Secret.MkSecret . ByteArray.convert $ Ascii.pack "0123456789"+ Secret.render secret @?= Ascii.pack "whsec_MDEyMzQ1Njc4OQ=="
+ source/libraries/test/Signet/Unstable/Type/SignatureTest.hs view
@@ -0,0 +1,53 @@+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 = Tasty.describe "Signet.Unstable.Type.Signature" $ do+ Tasty.describe "parse" $ do+ Tasty.it "fails with invalid asymmetric signature" $ do+ let byteString = Ascii.pack "invalid"+ let result = Signature.parse $ Ascii.pack "v1a," <> byteString+ result @?= Left (InvalidSignature.InvalidAsymmetricSignature $ InvalidAsymmetricSignature.MkInvalidAsymmetricSignature byteString)++ Tasty.it "fails with invalid symmetric signature" $ do+ let byteString = Ascii.pack "invalid"+ let result = Signature.parse $ Ascii.pack "v1," <> byteString+ result @?= Left (InvalidSignature.InvalidSymmetricSignature $ InvalidSymmetricSignature.MkInvalidSymmetricSignature byteString)++ Tasty.it "returns unknown signature with unrecognized prefix" $ do+ let byteString = Ascii.pack "unknown"+ let result = Signature.parse byteString+ result @?= Right (Left $ UnknownSignature.MkUnknownSignature byteString)++ Tasty.it "succeeds with valid asymmetric signature" $ do+ let byteString = Ascii.pack "v1a,QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVotMDEyMzQ1Njc4OS1hYmNkZWZnaGlqa2xtbm9wcXJzdHV2cXh5eg=="+ signature <- fmap (Signature.Asymmetric . AsymmetricSignature.MkAsymmetricSignature) . Error.throwCryptoErrorIO . Ed25519.signature $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789-abcdefghijklmnopqrstuvqxyz"+ Signature.parse byteString @?= Right (Right signature)++ Tasty.it "succeeds with valid symmetric signature" $ do+ let byteString = Ascii.pack "v1,47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU="+ let signature = Signature.Symmetric . SymmetricSignature.MkSymmetricSignature $ Hash.hash ByteString.empty+ Signature.parse byteString @?= Right (Right signature)++ Tasty.describe "render" $ do+ Tasty.it "renders asymmetric signature correctly" $ do+ signature <- fmap (Signature.Asymmetric . AsymmetricSignature.MkAsymmetricSignature) . Error.throwCryptoErrorIO . Ed25519.signature $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789-abcdefghijklmnopqrstuvqxyz"+ Signature.render signature @?= Ascii.pack "v1a,QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVotMDEyMzQ1Njc4OS1hYmNkZWZnaGlqa2xtbm9wcXJzdHV2cXh5eg=="++ Tasty.it "renders symmetric signature correctly" $ do+ let signature = Signature.Symmetric . SymmetricSignature.MkSymmetricSignature $ Hash.hash ByteString.empty+ Signature.render signature @?= Ascii.pack "v1,47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU="
+ source/libraries/test/Signet/Unstable/Type/SignaturesTest.hs view
@@ -0,0 +1,72 @@+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 = Tasty.describe "Signet.Unstable.Type.Signatures" $ do+ Tasty.describe "parse" $ do+ Tasty.it "succeeds with no signatures" $ do+ Signatures.parse ByteString.empty @?= Right ([], Signatures.MkSignatures [])++ Tasty.it "succeeds with one signature" $ do+ let signature = Signature.Symmetric . SymmetricSignature.MkSymmetricSignature $ Hash.hash ByteString.empty+ let byteString = Ascii.pack "v1,47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU="+ Signatures.parse byteString @?= Right ([], Signatures.MkSignatures [signature])++ Tasty.it "succeeds with many signatures" $ do+ let symmetricSignature = SymmetricSignature.MkSymmetricSignature $ Hash.hash ByteString.empty+ asymmetricSignature <- fmap AsymmetricSignature.MkAsymmetricSignature . Error.throwCryptoErrorIO . Ed25519.signature $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789-abcdefghijklmnopqrstuvqxyz"+ let byteString = Ascii.pack "v1,47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= v1a,QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVotMDEyMzQ1Njc4OS1hYmNkZWZnaGlqa2xtbm9wcXJzdHV2cXh5eg=="+ let signatures =+ Signatures.MkSignatures+ [ Signature.Symmetric symmetricSignature,+ Signature.Asymmetric asymmetricSignature+ ]+ Signatures.parse byteString @?= Right ([], signatures)++ Tasty.it "fails with an invalid symmetric signature" $ do+ let x = Ascii.pack "invalid"+ let byteString = Ascii.pack "v1," <> x+ Signatures.parse byteString @?= Left (InvalidSignature.InvalidSymmetricSignature $ InvalidSymmetricSignature.MkInvalidSymmetricSignature x)++ Tasty.it "fails with an invalid asymmetric signature" $ do+ let x = Ascii.pack "invalid"+ let byteString = Ascii.pack "v1a," <> x+ Signatures.parse byteString @?= Left (InvalidSignature.InvalidAsymmetricSignature $ InvalidAsymmetricSignature.MkInvalidAsymmetricSignature x)++ Tasty.it "succeeds with an unknown signature" $ do+ let byteString = Ascii.pack "unknown"+ Signatures.parse byteString @?= Right ([UnknownSignature.MkUnknownSignature byteString], Signatures.MkSignatures [])++ Tasty.describe "render" $ do+ Tasty.it "renders no signatures" $ do+ let signatures = Signatures.MkSignatures []+ Signatures.render signatures @?= ByteString.empty++ Tasty.it "renders one signature" $ do+ let signatures = Signatures.MkSignatures . pure . Signature.Symmetric . SymmetricSignature.MkSymmetricSignature $ Hash.hash ByteString.empty+ Signatures.render signatures @?= Ascii.pack "v1,47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU="++ Tasty.it "renders many signatures" $ do+ let symmetricSignature = SymmetricSignature.MkSymmetricSignature $ Hash.hash ByteString.empty+ asymmetricSignature <- fmap AsymmetricSignature.MkAsymmetricSignature . Error.throwCryptoErrorIO . Ed25519.signature $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789-abcdefghijklmnopqrstuvqxyz"+ let signatures =+ Signatures.MkSignatures+ [ Signature.Symmetric symmetricSignature,+ Signature.Asymmetric asymmetricSignature+ ]+ Signatures.render signatures @?= Ascii.pack "v1,47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= v1a,QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVotMDEyMzQ1Njc4OS1hYmNkZWZnaGlqa2xtbm9wcXJzdHV2cXh5eg=="
+ source/libraries/test/Signet/Unstable/Type/SignerTest.hs view
@@ -0,0 +1,76 @@+module Signet.Unstable.Type.SignerTest where++import qualified Data.ByteString.Char8 as Ascii+import qualified Signet.Unstable.Exception.InvalidSigner as InvalidSigner+import qualified Signet.Unstable.Extra.Either as Either+import qualified Signet.Unstable.Extra.Tasty as Tasty+import qualified Signet.Unstable.Type.AsymmetricSignature as AsymmetricSignature+import qualified Signet.Unstable.Type.Message as Message+import qualified Signet.Unstable.Type.Secret as Secret+import qualified Signet.Unstable.Type.SecretKey as SecretKey+import qualified Signet.Unstable.Type.Signature as Signature+import qualified Signet.Unstable.Type.Signer as Signer+import qualified Signet.Unstable.Type.SymmetricSignature as SymmetricSignature+import Test.Tasty.HUnit ((@?=))++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Type.Signer" $ do+ Tasty.describe "parse" $ do+ Tasty.it "succeeds with a valid secret key" $ do+ let byteString = Ascii.pack "whsk_QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIzNDU="+ let actual = Signer.parse byteString+ secretKey <- Either.throw $ SecretKey.parse byteString+ actual @?= Right (Signer.Asymmetric secretKey)++ Tasty.it "succeeds with a valid secret" $ do+ let byteString = Ascii.pack "whsec_bXlzZWNyZXRrZXkxMjM0NQ=="+ let actual = Signer.parse byteString+ secret <- Either.throw $ Secret.parse byteString+ actual @?= Right (Signer.Symmetric secret)++ Tasty.it "fails with invalid input" $ do+ let byteString = Ascii.pack "invalid"+ let actual = Signer.parse byteString+ actual @?= Left (InvalidSigner.MkInvalidSigner byteString)++ Tasty.describe "render" $ do+ Tasty.it "works with a secret key" $ do+ let byteString = Ascii.pack "whsk_QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIzNDU="+ secretKey <- Either.throw . SecretKey.parse $ byteString+ Signer.render (Signer.Asymmetric secretKey) @?= byteString++ Tasty.it "works with a secret" $ do+ let byteString = Ascii.pack "whsec_bXlzZWNyZXRrZXkxMjM0NQ=="+ secret <- Either.throw . Secret.parse $ byteString+ Signer.render (Signer.Symmetric secret) @?= byteString++ Tasty.describe "sign" $ do+ Tasty.it "works with asymmetric" $ do+ signer <- Either.throw . Signer.parse $ Ascii.pack "whsk_QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIzNDU="+ message <- Either.throw . Message.parse $ Ascii.pack "i.0.Hello, world!"+ let actual = Signer.sign signer message+ Right expected <- Either.throw . Signature.parse $ Ascii.pack "v1a,CV1O+PvrwXM42OMUX+tmm6bA3cS0tgLp0qo3YKuu0MGmBrsUhA0MHXF11HsEUJtPfTKs80WE7WUKVt9TueLDCQ=="+ actual @?= expected++ Tasty.it "works with symmetric" $ do+ signer <- Either.throw . Signer.parse $ Ascii.pack "whsec_bXlzZWNyZXRrZXkxMjM0NQ=="+ message <- Either.throw . Message.parse $ Ascii.pack "i.0.Hello, world!"+ let actual = Signer.sign signer message+ Right expected <- Either.throw . Signature.parse $ Ascii.pack "v1,IywpE5NXy+JdAScgR7j5Pt59GjmazD7iJuVsQoRZFyw="+ actual @?= expected++ Tasty.describe "asymmetric" $ do+ Tasty.it "creates correct asymmetric signature" $ do+ secretKey <- Either.throw . SecretKey.parse $ Ascii.pack "whsk_QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIzNDU="+ message <- Either.throw . Message.parse $ Ascii.pack "i.0.Hello, world!"+ let actual = Signer.asymmetric secretKey message+ expected <- Either.throw . AsymmetricSignature.parse $ Ascii.pack "CV1O+PvrwXM42OMUX+tmm6bA3cS0tgLp0qo3YKuu0MGmBrsUhA0MHXF11HsEUJtPfTKs80WE7WUKVt9TueLDCQ=="+ actual @?= expected++ Tasty.describe "symmetric" $ do+ Tasty.it "creates correct symmetric signature" $ do+ secret <- Either.throw . Secret.parse $ Ascii.pack "whsec_bXlzZWNyZXRrZXkxMjM0NQ=="+ message <- Either.throw . Message.parse $ Ascii.pack "i.0.Hello, world!"+ let actual = Signer.symmetric secret message+ expected <- Either.throw . SymmetricSignature.parse $ Ascii.pack "IywpE5NXy+JdAScgR7j5Pt59GjmazD7iJuVsQoRZFyw="+ actual @?= expected
+ source/libraries/test/Signet/Unstable/Type/SymmetricSignatureTest.hs view
@@ -0,0 +1,27 @@+module Signet.Unstable.Type.SymmetricSignatureTest where++import qualified Crypto.Hash as Hash+import qualified Data.ByteString as ByteString+import qualified Data.ByteString.Char8 as Ascii+import qualified Signet.Unstable.Exception.InvalidSymmetricSignature as InvalidSymmetricSignature+import qualified Signet.Unstable.Extra.Tasty as Tasty+import qualified Signet.Unstable.Type.SymmetricSignature as SymmetricSignature+import Test.Tasty.HUnit ((@?=))++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Type.SymmetricSignature" $ do+ Tasty.describe "parse" $ do+ Tasty.it "fails with invalid symmetric signature" $ do+ let byteString = Ascii.pack "invalid"+ let result = SymmetricSignature.parse byteString+ result @?= Left (InvalidSymmetricSignature.MkInvalidSymmetricSignature byteString)++ Tasty.it "succeeds with valid symmetric signature" $ do+ let byteString = Ascii.pack "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU="+ let signature = SymmetricSignature.MkSymmetricSignature $ Hash.hash ByteString.empty+ SymmetricSignature.parse byteString @?= Right signature++ Tasty.describe "render" $ do+ Tasty.it "renders symmetric signature correctly" $ do+ let signature = SymmetricSignature.MkSymmetricSignature $ Hash.hash ByteString.empty+ SymmetricSignature.render signature @?= Ascii.pack "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU="
+ source/libraries/test/Signet/Unstable/Type/TimestampTest.hs view
@@ -0,0 +1,33 @@+module Signet.Unstable.Type.TimestampTest where++import qualified Data.ByteString.Char8 as Ascii+import qualified Data.Time as Time+import qualified Signet.Unstable.Exception.InvalidTimestamp as InvalidTimestamp+import qualified Signet.Unstable.Extra.Tasty as Tasty+import qualified Signet.Unstable.Type.Timestamp as Timestamp+import Test.Tasty.HUnit ((@?=))++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Type.Timestamp" $ do+ Tasty.describe "parse" $ do+ Tasty.it "fails with invalid timestamp format" $ do+ let byteString = Ascii.pack "invalid-timestamp"+ let result = Timestamp.parse byteString+ result @?= Left (InvalidTimestamp.MkInvalidTimestamp byteString)++ Tasty.it "succeeds with valid timestamp format" $ do+ let byteString = Ascii.pack "1617235200"+ let result = Timestamp.parse byteString+ case result of+ Right timestamp -> do+ let utcTime = Timestamp.unwrap timestamp+ let expectedTime = Time.UTCTime (Time.fromGregorian 2021 4 1) 0+ utcTime @?= expectedTime+ Left _ -> fail "Expected Right but got Left"++ Tasty.describe "render" $ do+ Tasty.it "returns the correct ByteString representation" $ do+ let utcTime = Time.UTCTime (Time.fromGregorian 2021 4 1) 0+ let timestamp = Timestamp.MkTimestamp utcTime+ let expected = Ascii.pack "1617235200"+ Timestamp.render timestamp @?= expected
+ source/libraries/test/Signet/Unstable/Type/ToleranceTest.hs view
@@ -0,0 +1,34 @@+module Signet.Unstable.Type.ToleranceTest where++import qualified Data.Time as Time+import qualified Signet.Unstable.Exception.ToleranceException as ToleranceException+import qualified Signet.Unstable.Extra.Tasty as Tasty+import qualified Signet.Unstable.Type.Timestamp as Timestamp+import qualified Signet.Unstable.Type.Tolerance as Tolerance+import Test.Tasty.HUnit ((@?=))++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Type.Tolerance" $ do+ Tasty.describe "check" $ do+ Tasty.it "succeeds when timestamp is within tolerance" $ do+ let tolerance = Tolerance.MkTolerance 1+ let utcTime = Time.UTCTime (Time.fromGregorian 2001 1 1) 60+ let timestamp = Timestamp.MkTimestamp utcTime+ let result = Tolerance.check tolerance utcTime timestamp+ result @?= Right ()++ Tasty.it "fails when timestamp is too old" $ do+ let tolerance = Tolerance.MkTolerance 1+ let utcTime = Time.UTCTime (Time.fromGregorian 2001 1 1) 60+ let timestamp = Timestamp.MkTimestamp utcTime+ let now = Time.addUTCTime 2 utcTime+ let result = Tolerance.check tolerance now timestamp+ result @?= Left (ToleranceException.MkToleranceException timestamp)++ Tasty.it "fails when timestamp is in the future" $ do+ let tolerance = Tolerance.MkTolerance 1+ let utcTime = Time.UTCTime (Time.fromGregorian 2001 1 1) 60+ let timestamp = Timestamp.MkTimestamp utcTime+ let now = Time.addUTCTime (-2) utcTime+ let result = Tolerance.check tolerance now timestamp+ result @?= Left (ToleranceException.MkToleranceException timestamp)
+ source/libraries/test/Signet/Unstable/Type/UnknownSignatureTest.hs view
@@ -0,0 +1,7 @@+module Signet.Unstable.Type.UnknownSignatureTest where++import qualified Signet.Unstable.Extra.Tasty as Tasty++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Type.UnknownSignature" $ do+ pure ()
+ source/libraries/test/Signet/Unstable/Type/VerifierTest.hs view
@@ -0,0 +1,110 @@+module Signet.Unstable.Type.VerifierTest where++import qualified Data.ByteString.Char8 as Ascii+import qualified Signet.Unstable.Exception.InvalidVerifier as InvalidVerifier+import qualified Signet.Unstable.Exception.VerificationException as VerificationException+import qualified Signet.Unstable.Extra.Either as Either+import qualified Signet.Unstable.Extra.Tasty as Tasty+import qualified Signet.Unstable.Type.AsymmetricSignature as AsymmetricSignature+import qualified Signet.Unstable.Type.Message as Message+import qualified Signet.Unstable.Type.PublicKey as PublicKey+import qualified Signet.Unstable.Type.Secret as Secret+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.Verifier as Verifier+import Test.Tasty.HUnit ((@?=))++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable.Type.Verifier" $ do+ Tasty.describe "parse" $ do+ Tasty.it "succeeds with a valid public key" $ do+ let byteString = Ascii.pack "whpk_wuzPrKxPfWpJSsXgyg/MEoMGvjs5SjDO4ad6X4ZYqqg="+ let actual = Verifier.parse byteString+ publicKey <- Either.throw $ PublicKey.parse byteString+ actual @?= Right (Verifier.Asymmetric publicKey)++ Tasty.it "succeeds with a valid secret" $ do+ let byteString = Ascii.pack "whsec_bXlzZWNyZXRrZXkxMjM0NQ=="+ let actual = Verifier.parse byteString+ secret <- Either.throw $ Secret.parse byteString+ actual @?= Right (Verifier.Symmetric secret)++ Tasty.it "fails with invalid input" $ do+ let byteString = Ascii.pack "invalid"+ let actual = Verifier.parse byteString+ actual @?= Left (InvalidVerifier.MkInvalidVerifier byteString)++ Tasty.describe "render" $ do+ Tasty.it "works with a public key" $ do+ let byteString = Ascii.pack "whpk_wuzPrKxPfWpJSsXgyg/MEoMGvjs5SjDO4ad6X4ZYqqg="+ publicKey <- Either.throw . PublicKey.parse $ byteString+ Verifier.render (Verifier.Asymmetric publicKey) @?= byteString++ Tasty.it "works with a secret" $ do+ let byteString = Ascii.pack "whsec_bXlzZWNyZXRrZXkxMjM0NQ=="+ secret <- Either.throw . Secret.parse $ byteString+ Verifier.render (Verifier.Symmetric secret) @?= byteString++ Tasty.describe "verify" $ do+ Tasty.it "succeeds with a valid asymmetric signature" $ do+ verifier <- Either.throw . Verifier.parse $ Ascii.pack "whpk_wuzPrKxPfWpJSsXgyg/MEoMGvjs5SjDO4ad6X4ZYqqg="+ message <- Either.throw . Message.parse $ Ascii.pack "i.0.Hello, world!"+ (_, signatures) <- Either.throw . Signatures.parse $ Ascii.pack "v1a,CV1O+PvrwXM42OMUX+tmm6bA3cS0tgLp0qo3YKuu0MGmBrsUhA0MHXF11HsEUJtPfTKs80WE7WUKVt9TueLDCQ=="+ let actual = Verifier.verify verifier message signatures+ Right signature <- Either.throw . Signature.parse $ Ascii.pack "v1a,CV1O+PvrwXM42OMUX+tmm6bA3cS0tgLp0qo3YKuu0MGmBrsUhA0MHXF11HsEUJtPfTKs80WE7WUKVt9TueLDCQ=="+ actual @?= Right signature++ Tasty.it "fails with an invalid asymmetric signature" $ do+ verifier <- Either.throw . Verifier.parse $ Ascii.pack "whpk_wuzPrKxPfWpJSsXgyg/MEoMGvjs5SjDO4ad6X4ZYqqg="+ message <- Either.throw . Message.parse $ Ascii.pack "i.0.Hello, world!"+ (_, signatures) <- Either.throw . Signatures.parse $ Ascii.pack "v1a,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000=="+ let actual = Verifier.verify verifier message signatures+ actual @?= Left (VerificationException.MkVerificationException $ Message.id_ message)++ Tasty.it "succeeds with a valid symmetric signature" $ do+ verifier <- Either.throw . Verifier.parse $ Ascii.pack "whsec_bXlzZWNyZXRrZXkxMjM0NQ=="+ message <- Either.throw . Message.parse $ Ascii.pack "i.0.Hello, world!"+ (_, signatures) <- Either.throw . Signatures.parse $ Ascii.pack "v1,IywpE5NXy+JdAScgR7j5Pt59GjmazD7iJuVsQoRZFyw="+ let actual = Verifier.verify verifier message signatures+ Right signature <- Either.throw . Signature.parse $ Ascii.pack "v1,IywpE5NXy+JdAScgR7j5Pt59GjmazD7iJuVsQoRZFyw="+ actual @?= Right signature++ Tasty.it "fails with an invalid symmetric signature" $ do+ verifier <- Either.throw . Verifier.parse $ Ascii.pack "whsec_bXlzZWNyZXRrZXkxMjM0NQ=="+ message <- Either.throw . Message.parse $ Ascii.pack "i.0.Hello, world!"+ (_, signatures) <- Either.throw . Signatures.parse $ Ascii.pack "v1,0000000000000000000000000000000000000000000="+ let actual = Verifier.verify verifier message signatures+ actual @?= Left (VerificationException.MkVerificationException $ Message.id_ message)++ Tasty.describe "asymmetric" $ do+ Tasty.it "succeeds with a valid signature" $ do+ publicKey <- Either.throw . PublicKey.parse $ Ascii.pack "whpk_wuzPrKxPfWpJSsXgyg/MEoMGvjs5SjDO4ad6X4ZYqqg="+ message <- Either.throw . Message.parse $ Ascii.pack "i.0.Hello, world!"+ (_, signatures) <- Either.throw . Signatures.parse $ Ascii.pack "v1a,CV1O+PvrwXM42OMUX+tmm6bA3cS0tgLp0qo3YKuu0MGmBrsUhA0MHXF11HsEUJtPfTKs80WE7WUKVt9TueLDCQ=="+ let actual = Verifier.asymmetric publicKey message signatures+ asymmetricSignature <- Either.throw . AsymmetricSignature.parse $ Ascii.pack "CV1O+PvrwXM42OMUX+tmm6bA3cS0tgLp0qo3YKuu0MGmBrsUhA0MHXF11HsEUJtPfTKs80WE7WUKVt9TueLDCQ=="+ actual @?= Right asymmetricSignature++ Tasty.it "fails with an invalid signature" $ do+ publicKey <- Either.throw . PublicKey.parse $ Ascii.pack "whpk_wuzPrKxPfWpJSsXgyg/MEoMGvjs5SjDO4ad6X4ZYqqg="+ message <- Either.throw . Message.parse $ Ascii.pack "i.0.Hello, world!"+ (_, signatures) <- Either.throw . Signatures.parse $ Ascii.pack "v1a,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000=="+ let actual = Verifier.asymmetric publicKey message signatures+ actual @?= Left (VerificationException.MkVerificationException $ Message.id_ message)++ Tasty.describe "symmetric" $ do+ Tasty.it "succeeds with a valid signature" $ do+ secret <- Either.throw . Secret.parse $ Ascii.pack "whsec_bXlzZWNyZXRrZXkxMjM0NQ=="+ message <- Either.throw . Message.parse $ Ascii.pack "i.0.Hello, world!"+ (_, signatures) <- Either.throw . Signatures.parse $ Ascii.pack "v1,IywpE5NXy+JdAScgR7j5Pt59GjmazD7iJuVsQoRZFyw="+ let actual = Verifier.symmetric secret message signatures+ symmetricSignature <- Either.throw . SymmetricSignature.parse $ Ascii.pack "IywpE5NXy+JdAScgR7j5Pt59GjmazD7iJuVsQoRZFyw="+ actual @?= Right symmetricSignature++ Tasty.it "fails with an invalid signature" $ do+ secret <- Either.throw . Secret.parse $ Ascii.pack "whsec_bXlzZWNyZXRrZXkxMjM0NQ=="+ message <- Either.throw . Message.parse $ Ascii.pack "i.0.Hello, world!"+ (_, signatures) <- Either.throw . Signatures.parse $ Ascii.pack "v1,0000000000000000000000000000000000000000000="+ let actual = Verifier.symmetric secret message signatures+ actual @?= Left (VerificationException.MkVerificationException $ Message.id_ message)
+ source/libraries/test/Signet/UnstableTest.hs view
@@ -0,0 +1,57 @@+module Signet.UnstableTest where++import qualified Data.ByteString.Char8 as Ascii+import qualified Data.Time as Time+import qualified Signet.Unstable as Signet+import qualified Signet.Unstable.Exception.SignetException as SignetException+import qualified Signet.Unstable.Exception.ToleranceException as ToleranceException+import qualified Signet.Unstable.Exception.VerificationException as VerificationException+import qualified Signet.Unstable.Extra.Either as Either+import qualified Signet.Unstable.Extra.Tasty as Tasty+import qualified Signet.Unstable.Type.Message as Message+import qualified Signet.Unstable.Type.Signature as Signature+import qualified Signet.Unstable.Type.Signatures as Signatures+import qualified Signet.Unstable.Type.Tolerance as Tolerance+import qualified Signet.Unstable.Type.Verifier as Verifier+import Test.Tasty.HUnit ((@?=))++spec :: Tasty.Spec+spec = Tasty.describe "Signet.Unstable" $ do+ Tasty.describe "verifyWebhookText" $ do+ pure ()++ Tasty.describe "verifyWebhookByteString" $ do+ pure ()++ Tasty.describe "verifyWebhook" $ do+ pure ()++ Tasty.describe "verifyWebhookWith" $ do+ Tasty.it "succeeds with a valid symmetric signature" $ do+ let tolerance = Tolerance.typical+ let now = Time.UTCTime (Time.fromGregorian 1970 1 1) 0+ verifier <- Either.throw . Verifier.parse $ Ascii.pack "whsec_bXlzZWNyZXRrZXkxMjM0NQ=="+ message <- Either.throw . Message.parse $ Ascii.pack "i.0.Hello, world!"+ let byteString = Ascii.pack "v1,IywpE5NXy+JdAScgR7j5Pt59GjmazD7iJuVsQoRZFyw="+ (_, signatures) <- Either.throw $ Signatures.parse byteString+ let result = Signet.verifyWebhookWith tolerance now verifier message signatures+ Right signature <- Either.throw $ Signature.parse byteString+ result @?= Right signature++ Tasty.it "fails with an invalid timestamp" $ do+ let tolerance = Tolerance.typical+ let now = Time.UTCTime (Time.fromGregorian 1970 1 1) 0+ verifier <- Either.throw . Verifier.parse $ Ascii.pack "whsec_bXlzZWNyZXRrZXkxMjM0NQ=="+ message <- Either.throw . Message.parse $ Ascii.pack "i.301.Hello, world!"+ (_, signatures) <- Either.throw . Signatures.parse $ Ascii.pack "v1,IywpE5NXy+JdAScgR7j5Pt59GjmazD7iJuVsQoRZFyw="+ let result = Signet.verifyWebhookWith tolerance now verifier message signatures+ result @?= Left (SignetException.ToleranceException . ToleranceException.MkToleranceException $ Message.timestamp message)++ Tasty.it "fails with an invalid symmetric signature" $ do+ let tolerance = Tolerance.typical+ let now = Time.UTCTime (Time.fromGregorian 1970 1 1) 0+ verifier <- Either.throw . Verifier.parse $ Ascii.pack "whsec_bXlzZWNyZXRrZXkxMjM0NQ=="+ message <- Either.throw . Message.parse $ Ascii.pack "i.0.Hello, world!"+ (_, signatures) <- Either.throw . Signatures.parse $ Ascii.pack "v1,0000000000000000000000000000000000000000000="+ let result = Signet.verifyWebhookWith tolerance now verifier message signatures+ result @?= Left (SignetException.VerificationException . VerificationException.MkVerificationException $ Message.id_ message)
+ source/libraries/test/SignetTest.hs view
@@ -0,0 +1,73 @@+module SignetTest where++import qualified Control.Monad.Trans.Writer as Writer+import qualified Signet.Unstable.Exception.InvalidAsymmetricSignatureTest+import qualified Signet.Unstable.Exception.InvalidIdTest+import qualified Signet.Unstable.Exception.InvalidMessageTest+import qualified Signet.Unstable.Exception.InvalidPublicKeyTest+import qualified Signet.Unstable.Exception.InvalidSecretKeyTest+import qualified Signet.Unstable.Exception.InvalidSecretTest+import qualified Signet.Unstable.Exception.InvalidSignatureTest+import qualified Signet.Unstable.Exception.InvalidSignerTest+import qualified Signet.Unstable.Exception.InvalidSymmetricSignatureTest+import qualified Signet.Unstable.Exception.InvalidTimestampTest+import qualified Signet.Unstable.Exception.InvalidVerifierTest+import qualified Signet.Unstable.Exception.SignetExceptionTest+import qualified Signet.Unstable.Exception.ToleranceExceptionTest+import qualified Signet.Unstable.Exception.VerificationExceptionTest+import qualified Signet.Unstable.Extra.EitherTest+import qualified Signet.Unstable.Extra.HttpTest+import qualified Signet.Unstable.Extra.MaybeTest+import qualified Signet.Unstable.Type.AsymmetricSignatureTest+import qualified Signet.Unstable.Type.IdTest+import qualified Signet.Unstable.Type.MessageTest+import qualified Signet.Unstable.Type.PayloadTest+import qualified Signet.Unstable.Type.PublicKeyTest+import qualified Signet.Unstable.Type.SecretKeyTest+import qualified Signet.Unstable.Type.SecretTest+import qualified Signet.Unstable.Type.SignatureTest+import qualified Signet.Unstable.Type.SignaturesTest+import qualified Signet.Unstable.Type.SignerTest+import qualified Signet.Unstable.Type.SymmetricSignatureTest+import qualified Signet.Unstable.Type.TimestampTest+import qualified Signet.Unstable.Type.ToleranceTest+import qualified Signet.Unstable.Type.UnknownSignatureTest+import qualified Signet.Unstable.Type.VerifierTest+import qualified Signet.UnstableTest+import qualified Test.Tasty as Tasty++testTree :: Tasty.TestTree+testTree = Tasty.testGroup "signet" . Writer.execWriter $ do+ Signet.Unstable.Exception.InvalidAsymmetricSignatureTest.spec+ Signet.Unstable.Exception.InvalidIdTest.spec+ Signet.Unstable.Exception.InvalidMessageTest.spec+ Signet.Unstable.Exception.InvalidPublicKeyTest.spec+ Signet.Unstable.Exception.InvalidSecretKeyTest.spec+ Signet.Unstable.Exception.InvalidSecretTest.spec+ Signet.Unstable.Exception.InvalidSignatureTest.spec+ Signet.Unstable.Exception.InvalidSignerTest.spec+ Signet.Unstable.Exception.InvalidSymmetricSignatureTest.spec+ Signet.Unstable.Exception.InvalidTimestampTest.spec+ Signet.Unstable.Exception.InvalidVerifierTest.spec+ Signet.Unstable.Exception.SignetExceptionTest.spec+ Signet.Unstable.Exception.ToleranceExceptionTest.spec+ Signet.Unstable.Exception.VerificationExceptionTest.spec+ Signet.Unstable.Extra.EitherTest.spec+ Signet.Unstable.Extra.HttpTest.spec+ Signet.Unstable.Extra.MaybeTest.spec+ Signet.Unstable.Type.AsymmetricSignatureTest.spec+ Signet.Unstable.Type.IdTest.spec+ Signet.Unstable.Type.MessageTest.spec+ Signet.Unstable.Type.PayloadTest.spec+ Signet.Unstable.Type.PublicKeyTest.spec+ Signet.Unstable.Type.SecretKeyTest.spec+ Signet.Unstable.Type.SecretTest.spec+ Signet.Unstable.Type.SignaturesTest.spec+ Signet.Unstable.Type.SignatureTest.spec+ Signet.Unstable.Type.SignerTest.spec+ Signet.Unstable.Type.SymmetricSignatureTest.spec+ Signet.Unstable.Type.TimestampTest.spec+ Signet.Unstable.Type.ToleranceTest.spec+ Signet.Unstable.Type.UnknownSignatureTest.spec+ Signet.Unstable.Type.VerifierTest.spec+ Signet.UnstableTest.spec
+ source/libraries/unstable/Signet/Unstable.hs view
@@ -0,0 +1,196 @@+{-# LANGUAGE PatternSynonyms #-}++module Signet.Unstable where++import qualified Control.Monad.Catch as Exception+import qualified Control.Monad.IO.Class as MonadIO+import qualified Data.Bifunctor as Bifunctor+import qualified Data.ByteString as ByteString+import qualified Data.Text as Text+import qualified Data.Text.Encoding as Text+import qualified Data.Time as Time+import qualified Signet.Unstable.Exception.InvalidId as InvalidId+import qualified Signet.Unstable.Exception.InvalidMessage as InvalidMessage+import qualified Signet.Unstable.Exception.InvalidSignature as InvalidSignature+import qualified Signet.Unstable.Exception.InvalidSigner as InvalidSigner+import qualified Signet.Unstable.Exception.InvalidTimestamp as InvalidTimestamp+import qualified Signet.Unstable.Exception.InvalidVerifier as InvalidVerifier+import qualified Signet.Unstable.Exception.SignetException as SignetException+import qualified Signet.Unstable.Extra.Either as Either+import qualified Signet.Unstable.Type.AsymmetricSignature as AsymmetricSignature+import qualified Signet.Unstable.Type.Id as Id+import qualified Signet.Unstable.Type.Message as Message+import qualified Signet.Unstable.Type.Payload as Payload+import qualified Signet.Unstable.Type.PublicKey as PublicKey+import qualified Signet.Unstable.Type.Secret as Secret+import qualified Signet.Unstable.Type.SecretKey as SecretKey+import qualified Signet.Unstable.Type.Signature as Signature+import qualified Signet.Unstable.Type.Signatures as Signatures+import qualified Signet.Unstable.Type.Signer as Signer+import qualified Signet.Unstable.Type.SymmetricSignature as SymmetricSignature+import qualified Signet.Unstable.Type.Timestamp as Timestamp+import qualified Signet.Unstable.Type.Tolerance as Tolerance+import qualified Signet.Unstable.Type.UnknownSignature as UnknownSignature+import qualified Signet.Unstable.Type.Verifier as Verifier++-- | Verifies a webhook with 'Text.Text' values. This is a wrapper around+-- 'verifyWebhookByteString' that assumes all values are encoded as UTF-8.+verifyWebhookText ::+ (MonadIO.MonadIO m, Exception.MonadThrow m) =>+ -- | A 'Verifier.Verifier' for the webhook. Typically this will be+ -- @"whsec_..."@ or @"whpk_..."@.+ Text.Text ->+ -- | The webhook's unique 'Id.Id'. Typically this will come from the+ -- 'Signet.Unstable.Extra.Http.hWebhookId' header and look like @"msg_..."@.+ Text.Text ->+ -- | The webhook's 'Timestamp.Timestamp'. This is an integer number of+ -- seconds since the Unix epoch. Typically this will come from the+ -- 'Signet.Unstable.Extra.Http.hWebhookTimestamp' header. For example+ -- @"981173106"@ for @2001-02-03T04:05:06Z@.+ Text.Text ->+ -- | The webhook's raw 'Payload.Payload'. Typically this will be a JSON+ -- object like @{"event_type":"ping",...}@.+ Text.Text ->+ -- | The webhook's 'Signatures.Signatures'. Typically this will come from the+ -- 'Signet.Unstable.Extra.Http.hWebhookSignature' header and look like+ -- @"v1_..."@ or @"v1a_..."@.+ Text.Text ->+ m Signature.Signature+verifyWebhookText v i t p s =+ verifyWebhookByteString+ (Text.encodeUtf8 v)+ (Text.encodeUtf8 i)+ (Text.encodeUtf8 t)+ (Text.encodeUtf8 p)+ (Text.encodeUtf8 s)++-- | Verifies a webhook with 'ByteString.ByteString' values. This is a+-- wrapper around 'verifyWebhook'. See 'verifyWebhookText' for a description of+-- the arguments.+verifyWebhookByteString ::+ (MonadIO.MonadIO m, Exception.MonadThrow m) =>+ -- | 'Verifier.Verifier'+ ByteString.ByteString ->+ -- | 'Id.Id'+ ByteString.ByteString ->+ -- | 'Timestamp.Timestamp'+ ByteString.ByteString ->+ -- | 'Payload.Payload'+ ByteString.ByteString ->+ -- | 'Signatures.Signatures'+ ByteString.ByteString ->+ m Signature.Signature+verifyWebhookByteString v i t p s = do+ verifier <- Either.throw $ parseVerifier v+ id_ <- Either.throw $ parseId i+ timestamp <- Either.throw $ parseTimestamp t+ let payload = Payload.MkPayload p+ let message =+ Message.MkMessage+ { Message.id_ = id_,+ Message.timestamp = timestamp,+ Message.payload = payload+ }+ (_, signatures) <- Either.throw $ parseSignatures s+ verifyWebhook verifier message signatures++-- | Verifies a webhook. This is a wrapper around 'verifyWebhookWith' that uses+-- 'typicalTolerance' and the current time.+--+-- Throws an exception if the webhook is invalid.+verifyWebhook ::+ (MonadIO.MonadIO m, Exception.MonadThrow m) =>+ Verifier.Verifier ->+ Message.Message ->+ Signatures.Signatures ->+ m Signature.Signature+verifyWebhook verifier message signatures = do+ now <- MonadIO.liftIO Time.getCurrentTime+ Either.throw $ verifyWebhookWith typicalTolerance now verifier message signatures++-- | Verifies a webhook. This is the lowest-level function that gives you the+-- most control. If you're looking for something that's easier to use and+-- assumes some reasonable defaults, consider 'verifyWebhook'.+verifyWebhookWith ::+ -- | Often 'typicalTolerance'.+ Tolerance.Tolerance ->+ -- | Usually 'Time.getCurrentTime'.+ Time.UTCTime ->+ -- | See 'parseVerifier'.+ Verifier.Verifier ->+ -- | See 'parseMessage'. Or 'Message.MkMessage' along with 'parseId',+ -- 'parseTimestamp', and 'Payload.MkPayload'.+ Message.Message ->+ -- | See 'parseSignatures'.+ Signatures.Signatures ->+ Either SignetException.SignetException Signature.Signature+verifyWebhookWith tolerance now verifier message signatures = do+ Bifunctor.first SignetException.ToleranceException+ . Tolerance.check tolerance now+ $ Message.timestamp message+ Bifunctor.first SignetException.VerificationException $+ Verifier.verify verifier message signatures++-- | Alias for 'Tolerance.typical'.+typicalTolerance :: Tolerance.Tolerance+typicalTolerance = Tolerance.typical++-- | Alias for 'Verifier.parse'.+parseVerifier :: ByteString.ByteString -> Either InvalidVerifier.InvalidVerifier Verifier.Verifier+parseVerifier = Verifier.parse++-- | Alias for 'Id.parse'.+parseId :: ByteString.ByteString -> Either InvalidId.InvalidId Id.Id+parseId = Id.parse++-- | Alias for 'Timestamp.parse'.+parseTimestamp :: ByteString.ByteString -> Either InvalidTimestamp.InvalidTimestamp Timestamp.Timestamp+parseTimestamp = Timestamp.parse++-- | Alias for 'Message.parse'.+parseMessage :: ByteString.ByteString -> Either InvalidMessage.InvalidMessage Message.Message+parseMessage = Message.parse++-- | Alias for 'Signatures.parse'.+parseSignatures ::+ ByteString.ByteString ->+ Either InvalidSignature.InvalidSignature ([UnknownSignature.UnknownSignature], Signatures.Signatures)+parseSignatures = Signatures.parse++-- | Alias for 'Verifier.Asymmetric'.+pattern AsymmetricVerifier :: PublicKey.PublicKey -> Verifier.Verifier+pattern AsymmetricVerifier publicKey = Verifier.Asymmetric publicKey++-- | Alias for 'Verifier.Symmetric'.+pattern SymmetricVerifier :: Secret.Secret -> Verifier.Verifier+pattern SymmetricVerifier secret = Verifier.Symmetric secret++{-# COMPLETE AsymmetricVerifier, SymmetricVerifier #-}++-- | Alias for 'Signer.sign'.+signWebhook :: Signer.Signer -> Message.Message -> Signature.Signature+signWebhook = Signer.sign++-- | Alias for 'Signer.parse'.+parseSigner :: ByteString.ByteString -> Either InvalidSigner.InvalidSigner Signer.Signer+parseSigner = Signer.parse++-- | Alias for 'Signer.Asymmetric'.+pattern AsymmetricSigner :: SecretKey.SecretKey -> Signer.Signer+pattern AsymmetricSigner secretKey = Signer.Asymmetric secretKey++-- | Alias for 'Signer.Symmetric'.+pattern SymmetricSigner :: Secret.Secret -> Signer.Signer+pattern SymmetricSigner secret = Signer.Symmetric secret++{-# COMPLETE AsymmetricSigner, SymmetricSigner #-}++-- | Alias for 'Signature.Asymmetric'.+pattern AsymmetricSignature :: AsymmetricSignature.AsymmetricSignature -> Signature.Signature+pattern AsymmetricSignature asymmetricSignature = Signature.Asymmetric asymmetricSignature++-- | Alias for 'Signature.Symmetric'.+pattern SymmetricSignature :: SymmetricSignature.SymmetricSignature -> Signature.Signature+pattern SymmetricSignature symmetricSignature = Signature.Symmetric symmetricSignature++{-# COMPLETE AsymmetricSignature, SymmetricSignature #-}
+ source/libraries/unstable/Signet/Unstable/Exception/InvalidAsymmetricSignature.hs view
@@ -0,0 +1,14 @@+module Signet.Unstable.Exception.InvalidAsymmetricSignature where++import qualified Control.Monad.Catch as Exception+import qualified Data.ByteString as ByteString++newtype InvalidAsymmetricSignature+ = MkInvalidAsymmetricSignature ByteString.ByteString+ deriving (Eq, Show)++instance Exception.Exception InvalidAsymmetricSignature where+ displayException = mappend "invalid asymmetric signature: " . show . unwrap++unwrap :: InvalidAsymmetricSignature -> ByteString.ByteString+unwrap (MkInvalidAsymmetricSignature byteString) = byteString
+ source/libraries/unstable/Signet/Unstable/Exception/InvalidId.hs view
@@ -0,0 +1,14 @@+module Signet.Unstable.Exception.InvalidId where++import qualified Control.Monad.Catch as Exception+import qualified Data.ByteString as ByteString++newtype InvalidId+ = MkInvalidId ByteString.ByteString+ deriving (Eq, Show)++instance Exception.Exception InvalidId where+ displayException = mappend "invalid ID: " . show . unwrap++unwrap :: InvalidId -> ByteString.ByteString+unwrap (MkInvalidId byteString) = byteString
+ source/libraries/unstable/Signet/Unstable/Exception/InvalidMessage.hs view
@@ -0,0 +1,18 @@+module Signet.Unstable.Exception.InvalidMessage where++import qualified Control.Monad.Catch as Exception+import qualified Signet.Unstable.Exception.InvalidId as InvalidId+import qualified Signet.Unstable.Exception.InvalidTimestamp as InvalidTimestamp++data InvalidMessage+ = InvalidId InvalidId.InvalidId+ | InvalidTimestamp InvalidTimestamp.InvalidTimestamp+ deriving (Eq, Show)++instance Exception.Exception InvalidMessage where+ displayException invalidMessage =+ "invalid message: " <> case invalidMessage of+ InvalidId invalidId ->+ Exception.displayException invalidId+ InvalidTimestamp invalidTimestamp ->+ Exception.displayException invalidTimestamp
+ source/libraries/unstable/Signet/Unstable/Exception/InvalidPublicKey.hs view
@@ -0,0 +1,14 @@+module Signet.Unstable.Exception.InvalidPublicKey where++import qualified Control.Monad.Catch as Exception+import qualified Data.ByteString as ByteString++newtype InvalidPublicKey+ = MkInvalidPublicKey ByteString.ByteString+ deriving (Eq, Show)++instance Exception.Exception InvalidPublicKey where+ displayException = mappend "invalid public key: " . show . unwrap++unwrap :: InvalidPublicKey -> ByteString.ByteString+unwrap (MkInvalidPublicKey byteString) = byteString
+ source/libraries/unstable/Signet/Unstable/Exception/InvalidSecret.hs view
@@ -0,0 +1,14 @@+module Signet.Unstable.Exception.InvalidSecret where++import qualified Control.Monad.Catch as Exception+import qualified Data.ByteString as ByteString++newtype InvalidSecret+ = MkInvalidSecret ByteString.ByteString+ deriving (Eq, Show)++instance Exception.Exception InvalidSecret where+ displayException = mappend "invalid secret: " . show . unwrap++unwrap :: InvalidSecret -> ByteString.ByteString+unwrap (MkInvalidSecret byteString) = byteString
+ source/libraries/unstable/Signet/Unstable/Exception/InvalidSecretKey.hs view
@@ -0,0 +1,14 @@+module Signet.Unstable.Exception.InvalidSecretKey where++import qualified Control.Monad.Catch as Exception+import qualified Data.ByteString as ByteString++newtype InvalidSecretKey+ = MkInvalidSecretKey ByteString.ByteString+ deriving (Eq, Show)++instance Exception.Exception InvalidSecretKey where+ displayException = mappend "invalid secret key: " . show . unwrap++unwrap :: InvalidSecretKey -> ByteString.ByteString+unwrap (MkInvalidSecretKey byteString) = byteString
+ source/libraries/unstable/Signet/Unstable/Exception/InvalidSignature.hs view
@@ -0,0 +1,18 @@+module Signet.Unstable.Exception.InvalidSignature where++import qualified Control.Monad.Catch as Exception+import qualified Signet.Unstable.Exception.InvalidAsymmetricSignature as InvalidAsymmetricSignature+import qualified Signet.Unstable.Exception.InvalidSymmetricSignature as InvalidSymmetricSignature++data InvalidSignature+ = InvalidAsymmetricSignature InvalidAsymmetricSignature.InvalidAsymmetricSignature+ | InvalidSymmetricSignature InvalidSymmetricSignature.InvalidSymmetricSignature+ deriving (Eq, Show)++instance Exception.Exception InvalidSignature where+ displayException invalidSignature =+ "invalid signature: " <> case invalidSignature of+ InvalidAsymmetricSignature invalidAsymmetricSignature ->+ Exception.displayException invalidAsymmetricSignature+ InvalidSymmetricSignature invalidSymmetricSignature ->+ Exception.displayException invalidSymmetricSignature
+ source/libraries/unstable/Signet/Unstable/Exception/InvalidSigner.hs view
@@ -0,0 +1,14 @@+module Signet.Unstable.Exception.InvalidSigner where++import qualified Control.Monad.Catch as Exception+import qualified Data.ByteString as ByteString++newtype InvalidSigner+ = MkInvalidSigner ByteString.ByteString+ deriving (Eq, Show)++instance Exception.Exception InvalidSigner where+ displayException = mappend "invalid signer: " . show . unwrap++unwrap :: InvalidSigner -> ByteString.ByteString+unwrap (MkInvalidSigner byteString) = byteString
+ source/libraries/unstable/Signet/Unstable/Exception/InvalidSymmetricSignature.hs view
@@ -0,0 +1,14 @@+module Signet.Unstable.Exception.InvalidSymmetricSignature where++import qualified Control.Monad.Catch as Exception+import qualified Data.ByteString as ByteString++newtype InvalidSymmetricSignature+ = MkInvalidSymmetricSignature ByteString.ByteString+ deriving (Eq, Show)++instance Exception.Exception InvalidSymmetricSignature where+ displayException = mappend "invalid symmetric signature: " . show . unwrap++unwrap :: InvalidSymmetricSignature -> ByteString.ByteString+unwrap (MkInvalidSymmetricSignature byteString) = byteString
+ source/libraries/unstable/Signet/Unstable/Exception/InvalidTimestamp.hs view
@@ -0,0 +1,14 @@+module Signet.Unstable.Exception.InvalidTimestamp where++import qualified Control.Monad.Catch as Exception+import qualified Data.ByteString as ByteString++newtype InvalidTimestamp+ = MkInvalidTimestamp ByteString.ByteString+ deriving (Eq, Show)++instance Exception.Exception InvalidTimestamp where+ displayException = mappend "invalid timestamp: " . show . unwrap++unwrap :: InvalidTimestamp -> ByteString.ByteString+unwrap (MkInvalidTimestamp byteString) = byteString
+ source/libraries/unstable/Signet/Unstable/Exception/InvalidVerifier.hs view
@@ -0,0 +1,14 @@+module Signet.Unstable.Exception.InvalidVerifier where++import qualified Control.Monad.Catch as Exception+import qualified Data.ByteString as ByteString++newtype InvalidVerifier+ = MkInvalidVerifier ByteString.ByteString+ deriving (Eq, Show)++instance Exception.Exception InvalidVerifier where+ displayException = mappend "invalid verifier: " . show . unwrap++unwrap :: InvalidVerifier -> ByteString.ByteString+unwrap (MkInvalidVerifier byteString) = byteString
+ source/libraries/unstable/Signet/Unstable/Exception/SignetException.hs view
@@ -0,0 +1,18 @@+module Signet.Unstable.Exception.SignetException where++import qualified Control.Monad.Catch as Exception+import qualified Signet.Unstable.Exception.ToleranceException as ToleranceException+import qualified Signet.Unstable.Exception.VerificationException as VerificationException++data SignetException+ = ToleranceException ToleranceException.ToleranceException+ | VerificationException VerificationException.VerificationException+ deriving (Eq, Show)++instance Exception.Exception SignetException where+ displayException signetException =+ "failed to verify webhook: " <> case signetException of+ ToleranceException toleranceException ->+ Exception.displayException toleranceException+ VerificationException verificationException ->+ Exception.displayException verificationException
+ source/libraries/unstable/Signet/Unstable/Exception/ToleranceException.hs view
@@ -0,0 +1,14 @@+module Signet.Unstable.Exception.ToleranceException where++import qualified Control.Monad.Catch as Exception+import qualified Signet.Unstable.Type.Timestamp as Timestamp++newtype ToleranceException+ = MkToleranceException Timestamp.Timestamp+ deriving (Eq, Show)++instance Exception.Exception ToleranceException where+ displayException = mappend "timestamp out of tolerance: " . show . unwrap++unwrap :: ToleranceException -> Timestamp.Timestamp+unwrap (MkToleranceException timestamp) = timestamp
+ source/libraries/unstable/Signet/Unstable/Exception/VerificationException.hs view
@@ -0,0 +1,14 @@+module Signet.Unstable.Exception.VerificationException where++import qualified Control.Monad.Catch as Exception+import qualified Signet.Unstable.Type.Id as Id++newtype VerificationException+ = MkVerificationException Id.Id+ deriving (Eq, Show)++instance Exception.Exception VerificationException where+ displayException = mappend "verification failed: " . show . unwrap++unwrap :: VerificationException -> Id.Id+unwrap (MkVerificationException id_) = id_
+ source/libraries/unstable/Signet/Unstable/Extra/Either.hs view
@@ -0,0 +1,9 @@+module Signet.Unstable.Extra.Either where++import qualified Control.Monad.Catch as Exception++hush :: Either x a -> Maybe a+hush = either (const Nothing) Just++throw :: (Exception.Exception e, Exception.MonadThrow m) => Either e a -> m a+throw = either Exception.throwM pure
+ source/libraries/unstable/Signet/Unstable/Extra/Http.hs view
@@ -0,0 +1,14 @@+module Signet.Unstable.Extra.Http where++import qualified Data.ByteString.Char8 as Ascii+import qualified Data.CaseInsensitive as CI+import qualified Network.HTTP.Types as Http++hWebhookId :: Http.HeaderName+hWebhookId = CI.mk $ Ascii.pack "webhook-id"++hWebhookSignature :: Http.HeaderName+hWebhookSignature = CI.mk $ Ascii.pack "webhook-signature"++hWebhookTimestamp :: Http.HeaderName+hWebhookTimestamp = CI.mk $ Ascii.pack "webhook-timestamp"
+ source/libraries/unstable/Signet/Unstable/Extra/Maybe.hs view
@@ -0,0 +1,4 @@+module Signet.Unstable.Extra.Maybe where++note :: e -> Maybe a -> Either e a+note = flip maybe Right . Left
+ source/libraries/unstable/Signet/Unstable/Type/AsymmetricSignature.hs view
@@ -0,0 +1,28 @@+module Signet.Unstable.Type.AsymmetricSignature where++import qualified Crypto.Error as Error+import qualified Crypto.PubKey.Ed25519 as Ed25519+import qualified Data.ByteArray.Encoding as Encoding+import qualified Data.ByteString as ByteString+import qualified Signet.Unstable.Exception.InvalidAsymmetricSignature as InvalidAsymmetricSignature+import qualified Signet.Unstable.Extra.Either as Either+import qualified Signet.Unstable.Extra.Maybe as Maybe++newtype AsymmetricSignature+ = MkAsymmetricSignature Ed25519.Signature+ deriving (Eq, Show)++unwrap :: AsymmetricSignature -> Ed25519.Signature+unwrap (MkAsymmetricSignature signature) = signature++parse ::+ ByteString.ByteString ->+ Either InvalidAsymmetricSignature.InvalidAsymmetricSignature AsymmetricSignature+parse encoded = Maybe.note (InvalidAsymmetricSignature.MkInvalidAsymmetricSignature encoded) $ do+ byteString <- Either.hush $ Encoding.convertFromBase Encoding.Base64 encoded+ fmap MkAsymmetricSignature+ . Error.maybeCryptoError+ $ Ed25519.signature (byteString :: ByteString.ByteString)++render :: AsymmetricSignature -> ByteString.ByteString+render = Encoding.convertToBase Encoding.Base64 . unwrap
+ source/libraries/unstable/Signet/Unstable/Type/Id.hs view
@@ -0,0 +1,26 @@+module Signet.Unstable.Type.Id where++import qualified Control.Monad as Monad+import qualified Data.ByteString as ByteString+import qualified Data.Word as Word+import qualified Signet.Unstable.Exception.InvalidId as InvalidId++newtype Id+ = MkId ByteString.ByteString+ deriving (Eq, Show)++unwrap :: Id -> ByteString.ByteString+unwrap (MkId byteString) = byteString++separator :: Word.Word8+separator = 0x2e++parse :: ByteString.ByteString -> Either InvalidId.InvalidId Id+parse byteString = do+ Monad.when (ByteString.any (== separator) byteString)+ . Left+ $ InvalidId.MkInvalidId byteString+ Right $ MkId byteString++render :: Id -> ByteString.ByteString+render = unwrap
+ source/libraries/unstable/Signet/Unstable/Type/Message.hs view
@@ -0,0 +1,36 @@+module Signet.Unstable.Type.Message where++import qualified Data.Bifunctor as Bifunctor+import qualified Data.ByteString as ByteString+import qualified Signet.Unstable.Exception.InvalidMessage as InvalidMessage+import qualified Signet.Unstable.Type.Id as Id+import qualified Signet.Unstable.Type.Payload as Payload+import qualified Signet.Unstable.Type.Timestamp as Timestamp++data Message = MkMessage+ { id_ :: Id.Id,+ timestamp :: Timestamp.Timestamp,+ payload :: Payload.Payload+ }+ deriving (Eq, Show)++parse :: ByteString.ByteString -> Either InvalidMessage.InvalidMessage Message+parse x = do+ let (rawId, y) = ByteString.break (== Id.separator) x+ theId <- Bifunctor.first InvalidMessage.InvalidId $ Id.parse rawId+ let (rawTimestamp, z) =+ ByteString.break (== Id.separator) $+ ByteString.drop 1 y+ theTimestamp <-+ Bifunctor.first InvalidMessage.InvalidTimestamp $+ Timestamp.parse rawTimestamp+ let thePayload = Payload.MkPayload $ ByteString.drop 1 z+ pure MkMessage {id_ = theId, timestamp = theTimestamp, payload = thePayload}++render :: Message -> ByteString.ByteString+render message =+ Id.render (id_ message)+ <> ByteString.singleton Id.separator+ <> Timestamp.render (timestamp message)+ <> ByteString.singleton Id.separator+ <> Payload.unwrap (payload message)
+ source/libraries/unstable/Signet/Unstable/Type/Payload.hs view
@@ -0,0 +1,10 @@+module Signet.Unstable.Type.Payload where++import qualified Data.ByteString as ByteString++newtype Payload+ = MkPayload ByteString.ByteString+ deriving (Eq, Show)++unwrap :: Payload -> ByteString.ByteString+unwrap (MkPayload byteString) = byteString
+ source/libraries/unstable/Signet/Unstable/Type/PublicKey.hs view
@@ -0,0 +1,31 @@+module Signet.Unstable.Type.PublicKey where++import qualified Crypto.Error as Error+import qualified Crypto.PubKey.Ed25519 as Ed25519+import qualified Data.ByteArray.Encoding as Encoding+import qualified Data.ByteString as ByteString+import qualified Data.ByteString.Char8 as Ascii+import qualified Signet.Unstable.Exception.InvalidPublicKey as InvalidPublicKey+import qualified Signet.Unstable.Extra.Either as Either+import qualified Signet.Unstable.Extra.Maybe as Maybe++newtype PublicKey+ = MkPublicKey Ed25519.PublicKey+ deriving (Eq, Show)++unwrap :: PublicKey -> Ed25519.PublicKey+unwrap (MkPublicKey publicKey) = publicKey++prefix :: ByteString.ByteString+prefix = Ascii.pack "whpk_"++parse :: ByteString.ByteString -> Either InvalidPublicKey.InvalidPublicKey PublicKey+parse prefixed = Maybe.note (InvalidPublicKey.MkInvalidPublicKey prefixed) $ do+ encoded <- ByteString.stripPrefix prefix prefixed+ byteString <- Either.hush $ Encoding.convertFromBase Encoding.Base64 encoded+ fmap MkPublicKey+ . Error.maybeCryptoError+ $ Ed25519.publicKey (byteString :: ByteString.ByteString)++render :: PublicKey -> ByteString.ByteString+render = mappend prefix . Encoding.convertToBase Encoding.Base64 . unwrap
+ source/libraries/unstable/Signet/Unstable/Type/Secret.hs view
@@ -0,0 +1,27 @@+module Signet.Unstable.Type.Secret where++import qualified Data.ByteArray as ByteArray+import qualified Data.ByteArray.Encoding as Encoding+import qualified Data.ByteString as ByteString+import qualified Data.ByteString.Char8 as Ascii+import qualified Signet.Unstable.Exception.InvalidSecret as InvalidSecret+import qualified Signet.Unstable.Extra.Either as Either+import qualified Signet.Unstable.Extra.Maybe as Maybe++newtype Secret+ = MkSecret ByteArray.ScrubbedBytes+ deriving (Eq, Show)++unwrap :: Secret -> ByteArray.ScrubbedBytes+unwrap (MkSecret scrubbedBytes) = scrubbedBytes++prefix :: ByteString.ByteString+prefix = Ascii.pack "whsec_"++parse :: ByteString.ByteString -> Either InvalidSecret.InvalidSecret Secret+parse prefixed = Maybe.note (InvalidSecret.MkInvalidSecret prefixed) $ do+ encoded <- ByteString.stripPrefix prefix prefixed+ fmap MkSecret . Either.hush $ Encoding.convertFromBase Encoding.Base64 encoded++render :: Secret -> ByteString.ByteString+render = mappend prefix . Encoding.convertToBase Encoding.Base64 . unwrap
+ source/libraries/unstable/Signet/Unstable/Type/SecretKey.hs view
@@ -0,0 +1,31 @@+module Signet.Unstable.Type.SecretKey where++import qualified Crypto.Error as Error+import qualified Crypto.PubKey.Ed25519 as Ed25519+import qualified Data.ByteArray.Encoding as Encoding+import qualified Data.ByteString as ByteString+import qualified Data.ByteString.Char8 as Ascii+import qualified Signet.Unstable.Exception.InvalidSecretKey as InvalidSecretKey+import qualified Signet.Unstable.Extra.Either as Either+import qualified Signet.Unstable.Extra.Maybe as Maybe++newtype SecretKey+ = MkSecretKey Ed25519.SecretKey+ deriving (Eq, Show)++unwrap :: SecretKey -> Ed25519.SecretKey+unwrap (MkSecretKey secretKey) = secretKey++prefix :: ByteString.ByteString+prefix = Ascii.pack "whsk_"++parse :: ByteString.ByteString -> Either InvalidSecretKey.InvalidSecretKey SecretKey+parse prefixed = Maybe.note (InvalidSecretKey.MkInvalidSecretKey prefixed) $ do+ encoded <- ByteString.stripPrefix prefix prefixed+ byteString <- Either.hush $ Encoding.convertFromBase Encoding.Base64 encoded+ fmap MkSecretKey+ . Error.maybeCryptoError+ $ Ed25519.secretKey (byteString :: ByteString.ByteString)++render :: SecretKey -> ByteString.ByteString+render = mappend prefix . Encoding.convertToBase Encoding.Base64 . unwrap
+ source/libraries/unstable/Signet/Unstable/Type/Signature.hs view
@@ -0,0 +1,49 @@+module Signet.Unstable.Type.Signature where++import qualified Data.Bifunctor as Bifunctor+import qualified Data.ByteString as ByteString+import qualified Data.ByteString.Char8 as Ascii+import qualified Data.Word as Word+import qualified Signet.Unstable.Exception.InvalidSignature as InvalidSignature+import qualified Signet.Unstable.Type.AsymmetricSignature as AsymmetricSignature+import qualified Signet.Unstable.Type.SymmetricSignature as SymmetricSignature+import qualified Signet.Unstable.Type.UnknownSignature as UnknownSignature++data Signature+ = Asymmetric AsymmetricSignature.AsymmetricSignature+ | Symmetric SymmetricSignature.SymmetricSignature+ deriving (Eq, Show)++separator :: Word.Word8+separator = 0x2c++asymmetricPrefix :: ByteString.ByteString+asymmetricPrefix = Ascii.pack "v1a"++symmetricPrefix :: ByteString.ByteString+symmetricPrefix = Ascii.pack "v1"++parse :: ByteString.ByteString -> Either InvalidSignature.InvalidSignature (Either UnknownSignature.UnknownSignature Signature)+parse prefixed = do+ let (prefix, rest) = ByteString.break (== separator) prefixed+ case ByteString.drop 1 rest of+ byteString+ | prefix == asymmetricPrefix ->+ Bifunctor.bimap InvalidSignature.InvalidAsymmetricSignature (Right . Asymmetric) $+ AsymmetricSignature.parse byteString+ | prefix == symmetricPrefix ->+ Bifunctor.bimap InvalidSignature.InvalidSymmetricSignature (Right . Symmetric) $+ SymmetricSignature.parse byteString+ _ -> Right . Left $ UnknownSignature.MkUnknownSignature prefixed++render :: Signature -> ByteString.ByteString+render signature =+ case signature of+ Asymmetric asymmetricSignature ->+ asymmetricPrefix+ <> ByteString.singleton separator+ <> AsymmetricSignature.render asymmetricSignature+ Symmetric symmetricSignature ->+ symmetricPrefix+ <> ByteString.singleton separator+ <> SymmetricSignature.render symmetricSignature
+ source/libraries/unstable/Signet/Unstable/Type/Signatures.hs view
@@ -0,0 +1,30 @@+module Signet.Unstable.Type.Signatures where++import qualified Data.ByteString as ByteString+import qualified Data.Either as Either+import qualified Data.Word as Word+import qualified Signet.Unstable.Exception.InvalidSignature as InvalidSignature+import qualified Signet.Unstable.Type.Signature as Signature+import qualified Signet.Unstable.Type.UnknownSignature as UnknownSignature++newtype Signatures+ = MkSignatures [Signature.Signature]+ deriving (Eq, Show)++unwrap :: Signatures -> [Signature.Signature]+unwrap (MkSignatures signatures) = signatures++separator :: Word.Word8+separator = 0x20++parse :: ByteString.ByteString -> Either InvalidSignature.InvalidSignature ([UnknownSignature.UnknownSignature], Signatures)+parse =+ fmap (fmap MkSignatures . Either.partitionEithers)+ . traverse Signature.parse+ . ByteString.split separator++render :: Signatures -> ByteString.ByteString+render =+ ByteString.intercalate (ByteString.singleton separator)+ . fmap Signature.render+ . unwrap
+ source/libraries/unstable/Signet/Unstable/Type/Signer.hs view
@@ -0,0 +1,49 @@+module Signet.Unstable.Type.Signer where++import qualified Crypto.MAC.HMAC as Hmac+import qualified Crypto.PubKey.Ed25519 as Ed25519+import qualified Data.ByteString as ByteString+import qualified Signet.Unstable.Exception.InvalidSigner as InvalidSigner+import qualified Signet.Unstable.Type.AsymmetricSignature as AsymmetricSignature+import qualified Signet.Unstable.Type.Message as Message+import qualified Signet.Unstable.Type.Secret as Secret+import qualified Signet.Unstable.Type.SecretKey as SecretKey+import qualified Signet.Unstable.Type.Signature as Signature+import qualified Signet.Unstable.Type.SymmetricSignature as SymmetricSignature++data Signer+ = Asymmetric SecretKey.SecretKey+ | Symmetric Secret.Secret+ deriving (Eq, Show)++parse :: ByteString.ByteString -> Either InvalidSigner.InvalidSigner Signer+parse byteString = case SecretKey.parse byteString of+ Right secretKey -> Right $ Asymmetric secretKey+ Left _ -> case Secret.parse byteString of+ Right secret -> Right $ Symmetric secret+ Left _ -> Left $ InvalidSigner.MkInvalidSigner byteString++render :: Signer -> ByteString.ByteString+render signer = case signer of+ Asymmetric secretKey -> SecretKey.render secretKey+ Symmetric secret -> Secret.render secret++sign :: Signer -> Message.Message -> Signature.Signature+sign signer = case signer of+ Asymmetric secretKey -> Signature.Asymmetric . asymmetric secretKey+ Symmetric secret -> Signature.Symmetric . symmetric secret++asymmetric :: SecretKey.SecretKey -> Message.Message -> AsymmetricSignature.AsymmetricSignature+asymmetric secretKey =+ let sk = SecretKey.unwrap secretKey+ pk = Ed25519.toPublic sk+ in AsymmetricSignature.MkAsymmetricSignature+ . Ed25519.sign sk pk+ . Message.render++symmetric :: Secret.Secret -> Message.Message -> SymmetricSignature.SymmetricSignature+symmetric secret =+ SymmetricSignature.MkSymmetricSignature+ . Hmac.hmacGetDigest+ . Hmac.hmac (Secret.unwrap secret)+ . Message.render
+ source/libraries/unstable/Signet/Unstable/Type/SymmetricSignature.hs view
@@ -0,0 +1,28 @@+module Signet.Unstable.Type.SymmetricSignature where++import qualified Crypto.Hash as Hash+import qualified Data.ByteArray as ByteArray+import qualified Data.ByteArray.Encoding as Encoding+import qualified Data.ByteString as ByteString+import qualified Data.Function as Function+import qualified Signet.Unstable.Exception.InvalidSymmetricSignature as InvalidSymmetricSignature+import qualified Signet.Unstable.Extra.Either as Either+import qualified Signet.Unstable.Extra.Maybe as Maybe++newtype SymmetricSignature+ = MkSymmetricSignature (Hash.Digest Hash.SHA256)+ deriving (Show)++instance Eq SymmetricSignature where+ (==) = Function.on ByteArray.constEq unwrap++unwrap :: SymmetricSignature -> Hash.Digest Hash.SHA256+unwrap (MkSymmetricSignature digest) = digest++parse :: ByteString.ByteString -> Either InvalidSymmetricSignature.InvalidSymmetricSignature SymmetricSignature+parse encoded = Maybe.note (InvalidSymmetricSignature.MkInvalidSymmetricSignature encoded) $ do+ byteString <- Either.hush $ Encoding.convertFromBase Encoding.Base64 encoded+ MkSymmetricSignature <$> Hash.digestFromByteString (byteString :: ByteString.ByteString)++render :: SymmetricSignature -> ByteString.ByteString+render = Encoding.convertToBase Encoding.Base64 . unwrap
+ source/libraries/unstable/Signet/Unstable/Type/Timestamp.hs view
@@ -0,0 +1,33 @@+module Signet.Unstable.Type.Timestamp where++import qualified Data.ByteString as ByteString+import qualified Data.Text as Text+import qualified Data.Text.Encoding as Text+import qualified Data.Time as Time+import qualified Signet.Unstable.Exception.InvalidTimestamp as InvalidTimestamp+import qualified Signet.Unstable.Extra.Either as Either+import qualified Signet.Unstable.Extra.Maybe as Maybe++newtype Timestamp+ = MkTimestamp Time.UTCTime+ deriving (Eq, Show)++unwrap :: Timestamp -> Time.UTCTime+unwrap (MkTimestamp utcTime) = utcTime++format :: String+format = "%s"++parse :: ByteString.ByteString -> Either InvalidTimestamp.InvalidTimestamp Timestamp+parse byteString = Maybe.note (InvalidTimestamp.MkInvalidTimestamp byteString) $ do+ text <- Either.hush $ Text.decodeUtf8' byteString+ fmap MkTimestamp+ . Time.parseTimeM False Time.defaultTimeLocale format+ $ Text.unpack text++render :: Timestamp -> ByteString.ByteString+render =+ Text.encodeUtf8+ . Text.pack+ . Time.formatTime Time.defaultTimeLocale format+ . unwrap
+ source/libraries/unstable/Signet/Unstable/Type/Tolerance.hs view
@@ -0,0 +1,29 @@+module Signet.Unstable.Type.Tolerance where++import qualified Control.Monad as Monad+import qualified Data.Time as Time+import qualified Signet.Unstable.Exception.ToleranceException as ToleranceException+import qualified Signet.Unstable.Type.Timestamp as Timestamp++newtype Tolerance+ = MkTolerance Time.NominalDiffTime+ deriving (Eq, Show)++unwrap :: Tolerance -> Time.NominalDiffTime+unwrap (MkTolerance nominalDiffTime) = nominalDiffTime++typical :: Tolerance+typical = MkTolerance 300++check ::+ Tolerance ->+ Time.UTCTime ->+ Timestamp.Timestamp ->+ Either ToleranceException.ToleranceException ()+check tolerance utcTime timestamp = do+ let diff = Time.diffUTCTime utcTime $ Timestamp.unwrap timestamp+ let hi = unwrap tolerance+ let lo = negate hi+ Monad.when (lo > diff || diff > hi)+ . Left+ $ ToleranceException.MkToleranceException timestamp
+ source/libraries/unstable/Signet/Unstable/Type/UnknownSignature.hs view
@@ -0,0 +1,10 @@+module Signet.Unstable.Type.UnknownSignature where++import qualified Data.ByteString as ByteString++newtype UnknownSignature+ = MkUnknownSignature ByteString.ByteString+ deriving (Eq, Show)++unwrap :: UnknownSignature -> ByteString.ByteString+unwrap (MkUnknownSignature byteString) = byteString
+ source/libraries/unstable/Signet/Unstable/Type/Verifier.hs view
@@ -0,0 +1,75 @@+module Signet.Unstable.Type.Verifier where++import qualified Crypto.PubKey.Ed25519 as Ed25519+import qualified Data.ByteString as ByteString+import qualified Data.List as List+import qualified Data.Maybe as Maybe+import qualified Signet.Unstable.Exception.InvalidVerifier as InvalidVerifier+import qualified Signet.Unstable.Exception.VerificationException as VerificationException+import qualified Signet.Unstable.Extra.Maybe as Maybe+import qualified Signet.Unstable.Type.AsymmetricSignature as AsymmetricSignature+import qualified Signet.Unstable.Type.Message as Message+import qualified Signet.Unstable.Type.PublicKey as PublicKey+import qualified Signet.Unstable.Type.Secret as Secret+import qualified Signet.Unstable.Type.Signature as Signature+import qualified Signet.Unstable.Type.Signatures as Signatures+import qualified Signet.Unstable.Type.Signer as Signer+import qualified Signet.Unstable.Type.SymmetricSignature as SymmetricSignature++data Verifier+ = Asymmetric PublicKey.PublicKey+ | Symmetric Secret.Secret+ deriving (Eq, Show)++parse :: ByteString.ByteString -> Either InvalidVerifier.InvalidVerifier Verifier+parse byteString = case PublicKey.parse byteString of+ Right publicKey -> Right $ Asymmetric publicKey+ Left _ -> case Secret.parse byteString of+ Right secret -> Right $ Symmetric secret+ Left _ -> Left $ InvalidVerifier.MkInvalidVerifier byteString++render :: Verifier -> ByteString.ByteString+render verifier = case verifier of+ Asymmetric publicKey -> PublicKey.render publicKey+ Symmetric secret -> Secret.render secret++verify ::+ Verifier ->+ Message.Message ->+ Signatures.Signatures ->+ Either VerificationException.VerificationException Signature.Signature+verify verifier message =+ case verifier of+ Asymmetric publicKey -> fmap Signature.Asymmetric . asymmetric publicKey message+ Symmetric secret -> fmap Signature.Symmetric . symmetric secret message++asymmetric ::+ PublicKey.PublicKey ->+ Message.Message ->+ Signatures.Signatures ->+ Either VerificationException.VerificationException AsymmetricSignature.AsymmetricSignature+asymmetric publicKey message =+ let toAsymmetric signature = case signature of+ Signature.Asymmetric asymmetricSignature -> Just asymmetricSignature+ Signature.Symmetric _ -> Nothing+ pk = PublicKey.unwrap publicKey+ bs = Message.render message+ in Maybe.note (VerificationException.MkVerificationException $ Message.id_ message)+ . List.find (Ed25519.verify pk bs . AsymmetricSignature.unwrap)+ . Maybe.mapMaybe toAsymmetric+ . Signatures.unwrap++symmetric ::+ Secret.Secret ->+ Message.Message ->+ Signatures.Signatures ->+ Either VerificationException.VerificationException SymmetricSignature.SymmetricSignature+symmetric secret message =+ let toSymmetric signature = case signature of+ Signature.Asymmetric _ -> Nothing+ Signature.Symmetric symmetricSignature -> Just symmetricSignature+ expected = Signer.symmetric secret message+ in Maybe.note (VerificationException.MkVerificationException $ Message.id_ message)+ . List.find (expected ==)+ . Maybe.mapMaybe toSymmetric+ . Signatures.unwrap
+ source/test-suite/Main.hs view
@@ -0,0 +1,5 @@+import qualified SignetTest+import qualified Test.Tasty as Tasty++main :: IO ()+main = Tasty.defaultMain SignetTest.testTree