From 1bb8b935658929d377859404d04c0b2db50f5c4b Mon Sep 17 00:00:00 2001
From: Jean-Paul Calderone <exarkun@twistedmatrix.com>
Date: Thu, 5 Sep 2019 10:52:42 -0400
Subject: [PATCH] Get key/signatures/proof values into a result

---
 PaymentServer.cabal             |  1 +
 src/PaymentServer/Issuer.hs     | 50 +++++++++++++++++++++++++++++++++
 src/PaymentServer/Redemption.hs | 33 +++++++++-------------
 test/SpecRedemption.hs          | 21 +++++++++-----
 4 files changed, 79 insertions(+), 26 deletions(-)
 create mode 100644 src/PaymentServer/Issuer.hs

diff --git a/PaymentServer.cabal b/PaymentServer.cabal
index 56d7c01..5910ce7 100644
--- a/PaymentServer.cabal
+++ b/PaymentServer.cabal
@@ -16,6 +16,7 @@ cabal-version:       >=1.10
 library
   hs-source-dirs:      src
   exposed-modules:     PaymentServer.Processors.Stripe
+                     , PaymentServer.Issuer
                      , PaymentServer.Persistence
                      , PaymentServer.Redemption
                      , PaymentServer.Server
diff --git a/src/PaymentServer/Issuer.hs b/src/PaymentServer/Issuer.hs
new file mode 100644
index 0000000..0f47c47
--- /dev/null
+++ b/src/PaymentServer/Issuer.hs
@@ -0,0 +1,50 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+-- | This module can issue signatures of blinded tokens which can be used to
+-- construct passes.
+module PaymentServer.Issuer
+  ( PublicKey
+  , Signature
+  , BlindedToken
+  , Proof
+  , ChallengeBypass(ChallengeBypass)
+  , Issuer
+  , trivialIssue
+  ) where
+
+import Data.Text
+  ( Text
+  )
+
+-- | A public key corresponding to our private key.
+type PublicKey = Text
+
+-- | A cryptographic signature of a blinded token created using our private
+-- key.
+type Signature = Text
+
+-- | This is the blinded token for which we create signatures.
+type BlindedToken = Text
+
+-- | A zero-knowledge proof that signatures were created of the corresponding
+-- blinded tokens using the corresponding public key's private key.
+type Proof = Text
+
+-- | This bundles up all of the values needed to verify the privacy-respecting
+-- operation of the issuer and then construct passes.
+data ChallengeBypass =
+  ChallengeBypass PublicKey [Signature] Proof
+
+-- | An issuer accepts a list of blinded tokens and returns signatures of
+-- those tokens along with proof that it used a particular key to construct
+-- the signatures.
+type Issuer = [BlindedToken] -> ChallengeBypass
+
+-- | trivialIssue makes up and returns some nonsense values that satisfy the
+-- structural requirements but not the semantic ones.
+trivialIssue :: Issuer
+trivialIssue tokens =
+  ChallengeBypass
+  "fake-public-key"
+  (replicate (length tokens) "fake-signature")
+  "fake-proof"
diff --git a/src/PaymentServer/Redemption.hs b/src/PaymentServer/Redemption.hs
index 23dfbc8..96dcdaf 100644
--- a/src/PaymentServer/Redemption.hs
+++ b/src/PaymentServer/Redemption.hs
@@ -7,7 +7,6 @@
 -- signatures.
 module PaymentServer.Redemption
   ( RedemptionAPI
-  , BlindedToken
   , Redeem(Redeem)
   , Result(Failed, Succeeded)
   , redemptionServer
@@ -20,8 +19,7 @@ import Control.Monad.IO.Class
   ( liftIO
   )
 import Data.Text
-  ( Text
-  , pack
+  ( pack
   )
 import Data.Text.Encoding
   ( encodeUtf8
@@ -59,27 +57,20 @@ import PaymentServer.Persistence
   , Fingerprint
   , Voucher
   )
-
--- | A cryptographic signature of a blinded token created using our private
--- key.
-type Signature = Text
-
--- | A public key corresponding to our private key.
-type PublicKey = Text
-
--- | A zero-knowledge proof that signatures were created of the corresponding
--- blinded tokens using the corresponding public key's private key.
-type Proof = Text
+import PaymentServer.Issuer
+  ( Signature
+  , PublicKey
+  , Proof
+  , BlindedToken
+  , ChallengeBypass(ChallengeBypass)
+  , trivialIssue
+  )
 
 data Result
   = Failed
   | Succeeded PublicKey [Signature] Proof
   deriving (Show, Eq)
 
--- | A blinded token is presented along with a voucher to be signed and the
--- signatures returned to the caller.
-type BlindedToken = Text
-
 -- | A complete redemption attempt which can be presented at the redemption
 -- endpoint.
 data Redeem
@@ -132,7 +123,11 @@ redeem database (Redeem voucher tokens) = do
   result <- liftIO $ PaymentServer.Persistence.redeemVoucher database voucher fingerprint
   case result of
     Left err -> throwError jsonErr400
-    Right () -> return $ Succeeded "" [] ""
+    Right () ->
+      let
+        (ChallengeBypass key signatures proof) = trivialIssue tokens
+      in
+        return $ Succeeded key signatures proof
 
 -- | Compute a cryptographic hash (fingerprint) of a list of tokens which can
 -- be used as an identifier for this exact sequence of tokens.
diff --git a/test/SpecRedemption.hs b/test/SpecRedemption.hs
index e9c0510..1017fa1 100644
--- a/test/SpecRedemption.hs
+++ b/test/SpecRedemption.hs
@@ -52,9 +52,13 @@ import Util.Spec
 import Util.WAI
   ( postJSON
   )
+import PaymentServer.Issuer
+  ( BlindedToken
+  , ChallengeBypass(ChallengeBypass)
+  , trivialIssue
+  )
 import PaymentServer.Redemption
   ( RedemptionAPI
-  , BlindedToken
   , Redeem(Redeem)
   , Result(Failed, Succeeded)
   , redemptionServer
@@ -138,12 +142,15 @@ spec_redemption = parallel $ do
     with (return $ app PermitRedemption) $
       it "receive a success response when redemption succeeds" $ property $
         \(voucher :: Voucher) (tokens :: [BlindedToken]) ->
-          propertyRedeem path voucher tokens 200
-          -- TODO: Get some real crypto involved to be able to replace these
-          -- dummy values.
-          { matchBody = matchJSONBody $ Succeeded "" [] ""
-          , matchHeaders = ["Content-Type" <:> "application/json;charset=utf-8"]
-          }
+          let
+            (ChallengeBypass key signatures proof) = trivialIssue tokens
+          in
+            propertyRedeem path voucher tokens 200
+            -- TODO: Get some real crypto involved to be able to replace these
+            -- dummy values.
+            { matchBody = matchJSONBody $ Succeeded key signatures proof
+            , matchHeaders = ["Content-Type" <:> "application/json;charset=utf-8"]
+            }
 
     -- it "receive 200 (OK) when the voucher is paid and previously redeemed with the same tokens" $
     --   property $ \(voucher :: Voucher) (tokens :: [BlindedToken]) ->
-- 
GitLab