gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-merchant] 75/277: work on abort


From: gnunet
Subject: [taler-merchant] 75/277: work on abort
Date: Sun, 05 Jul 2020 20:49:48 +0200

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository merchant.

commit 9b18406bc43bb2bb2d0c62526f2dcf9d1a4c043c
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Fri May 1 16:47:06 2020 +0200

    work on abort
---
 src/include/taler_merchant_service.h    |  18 +-
 src/lib/merchant_api_post_order_abort.c | 943 ++++++++------------------------
 2 files changed, 236 insertions(+), 725 deletions(-)

diff --git a/src/include/taler_merchant_service.h 
b/src/include/taler_merchant_service.h
index d5edcff..5aa5522 100644
--- a/src/include/taler_merchant_service.h
+++ b/src/include/taler_merchant_service.h
@@ -1648,19 +1648,15 @@ struct TALER_MERCHANT_OrderAbortHandle;
 struct TALER_MERCHANT_AbortedCoin
 {
   /**
-   * Merchant signature affirming the refund.
+   * Exchange signature affirming the refund.
    */
-  struct TALER_MerchantSignatureP merchant_sig;
+  struct TALER_ExchangeSignatureP exchange_sig;
 
   /**
-   * Public key of the refunded coin.
+   * Exchange public key affirming the refund.
    */
-  struct TALER_CoinSpendPublicKeyP coin_pub;
+  struct TALER_ExchangePublicKeyP exchange_pub;
 
-  /**
-   * Refund transaction ID.
-   */
-  uint64_t rtransaction_id;
 };
 
 
@@ -1671,16 +1667,14 @@ struct TALER_MERCHANT_AbortedCoin
  * @param cls closure
  * @param hr HTTP response details
  * @param merchant_pub public key of the merchant
- * @param h_contract hash of the contract
  * @param num_aborts size of the @a res array, 0 on errors
  * @param aborts merchant signatures refunding coins, NULL on errors
  */
 typedef void
-(*TALER_MERCHANT_PayAbortCallback) (
+(*TALER_MERCHANT_AbortCallback) (
   void *cls,
   const struct TALER_MERCHANT_HttpResponse *hr,
   const struct TALER_MerchantPublicKeyP *merchant_pub,
-  const struct GNUNET_HashCode *h_contract,
   unsigned int num_aborts,
   const struct TALER_MERCHANT_AbortedCoin aborts[]);
 
@@ -1726,7 +1720,7 @@ TALER_MERCHANT_order_abort (struct GNUNET_CURL_Context 
*ctx,
                             const char *order_id,
                             unsigned int num_coins,
                             const struct TALER_MERCHANT_PayCoin coins[],
-                            TALER_MERCHANT_PayAbortCallback cb,
+                            TALER_MERCHANT_AbortCallback cb,
                             void *cb_cls);
 
 
diff --git a/src/lib/merchant_api_post_order_abort.c 
b/src/lib/merchant_api_post_order_abort.c
index f860f3a..9b45e38 100644
--- a/src/lib/merchant_api_post_order_abort.c
+++ b/src/lib/merchant_api_post_order_abort.c
@@ -17,8 +17,8 @@
   If not, see <http://www.gnu.org/licenses/>
 */
 /**
- * @file lib/merchant_api_pay.c
- * @brief Implementation of the /pay request
+ * @file lib/merchant_api_post_order_abort.c
+ * @brief Implementation of the POST /orders/$ID/abort request
  *        of the merchant's HTTP API
  * @author Christian Grothoff
  * @author Marcello Stanisci
@@ -37,46 +37,40 @@
 
 
 /**
- * @brief A Pay Handle
+ * @brief An abort Handle
  */
-struct TALER_MERCHANT_Pay
+struct TALER_MERCHANT_OrderAbortHandle
 {
-
   /**
-   * The url for this request.
+   * Hash of the contract.
    */
-  char *url;
+  struct GNUNET_HashCode h_contract_terms;
 
   /**
-   * Handle for the request.
+   * Public key of the merchant.
    */
-  struct GNUNET_CURL_Job *job;
+  struct TALER_MerchantPublicKeyP merchant_pub;
 
   /**
-   * Function to call with the result in "pay" @e mode.
+   * The url for this request.
    */
-  TALER_MERCHANT_OrderPayCallback pay_cb;
+  char *url;
 
   /**
-   * Closure for @a pay_cb.
+   * Handle for the request.
    */
-  void *pay_cb_cls;
+  struct GNUNET_CURL_Job *job;
 
   /**
-   * Function to call with the result in "abort-refund" @e mode.
+   * Function to call with the result.
    */
-  TALER_MERCHANT_PayRefundCallback abort_cb;
+  TALER_MERCHANT_AbortCallback abort_cb;
 
   /**
    * Closure for @a abort_cb.
    */
   void *abort_cb_cls;
 
-  /**
-   * Operational mode, either "pay" or "abort-refund".
-   */
-  const char *mode;
-
   /**
    * Reference to the execution context.
    */
@@ -88,20 +82,15 @@ struct TALER_MERCHANT_Pay
   struct TALER_CURL_PostContext post_ctx;
 
   /**
-   * The coins we are paying with.
+   * The coins we are aborting on.
    */
-  struct TALER_MERCHANT_PaidCoin *coins;
+  struct TALER_MERCHANT_AbortCoin *coins;
 
   /**
    * Number of @e coins we are paying with.
    */
   unsigned int num_coins;
 
-  /**
-   * Hash of the contract, only available in "abort-refund" mode.
-   */
-  struct GNUNET_HashCode h_contract_terms;
-
 };
 
 
@@ -115,15 +104,13 @@ struct TALER_MERCHANT_Pay
  * @return #GNUNET_OK on success
  */
 static int
-check_abort_refund (struct TALER_MERCHANT_Pay *ph,
+check_abort_refund (struct TALER_MERCHANT_OrderAbortHandle *ph,
                     const json_t *json)
 {
   json_t *refunds;
   unsigned int num_refunds;
-  struct TALER_MerchantPublicKeyP merchant_pub;
   struct GNUNET_JSON_Specification spec[] = {
-    GNUNET_JSON_spec_json ("refund_permissions", &refunds),
-    GNUNET_JSON_spec_fixed_auto ("merchant_pub", &merchant_pub),
+    GNUNET_JSON_spec_json ("refunds", &refunds),
     GNUNET_JSON_spec_end ()
   };
 
@@ -136,67 +123,68 @@ check_abort_refund (struct TALER_MERCHANT_Pay *ph,
     return GNUNET_SYSERR;
   }
   num_refunds = json_array_size (refunds);
+  // FIXME: test for array first!
   {
-    struct TALER_MERCHANT_RefundEntry res[GNUNET_NZL (num_refunds)];
+    struct TALER_MERCHANT_AbortedCoin res[GNUNET_NZL (num_refunds)];
 
     for (unsigned int i = 0; i<num_refunds; i++)
     {
-      struct TALER_MerchantSignatureP *sig = &res[i].merchant_sig;
       json_t *refund = json_array_get (refunds, i);
-      struct GNUNET_JSON_Specification spec_detail[] = {
-        GNUNET_JSON_spec_fixed_auto ("merchant_sig",
-                                     sig),
-        GNUNET_JSON_spec_fixed_auto ("coin_pub",
-                                     &res[i].coin_pub),
-        GNUNET_JSON_spec_uint64 ("rtransaction_id",
-                                 &res[i].rtransaction_id),
+      uint32_t exchange_status;
+      json_t *exchange_reply;
+      struct GNUNET_JSON_Specification spec_es[] = {
+        GNUNET_JSON_spec_uint32 ("exchange_status",
+                                 &exchange_status),
+        GNUNET_JSON_spec_json ("exchange_reply",
+                               &exchange_reply),
         GNUNET_JSON_spec_end ()
       };
-      int found;
 
       if (GNUNET_OK !=
           GNUNET_JSON_parse (refund,
-                             spec_detail,
+                             spec_es,
                              NULL, NULL))
       {
         GNUNET_break_op (0);
         GNUNET_JSON_parse_free (spec);
         return GNUNET_SYSERR;
       }
-
-      found = -1;
-      for (unsigned int j = 0; j<ph->num_coins; j++)
+      if (MHD_HTTP_OK == exchange_status)
       {
-        if (0 == memcmp (&ph->coins[j].coin_pub,
-                         &res[i].coin_pub,
-                         sizeof
-                         (struct TALER_CoinSpendPublicKeyP)))
+        struct GNUNET_JSON_Specification spec_detail[] = {
+          GNUNET_JSON_spec_fixed_auto ("exchange_sig",
+                                       &res[i].exchange_sig),
+          GNUNET_JSON_spec_fixed_auto ("exchange_pub",
+                                       &res[i].exchange_pub),
+          GNUNET_JSON_spec_end ()
+        };
+        int found;
+
+        if (GNUNET_OK !=
+            GNUNET_JSON_parse (exchange_reply,
+                               spec_detail,
+                               NULL, NULL))
         {
-          found = j;
-          break;
+          GNUNET_break_op (0);
+          GNUNET_JSON_parse_free (spec);
+          return GNUNET_SYSERR;
         }
       }
-      if (-1 == found)
-      {
-        GNUNET_break_op (0);
-        GNUNET_JSON_parse_free (spec);
-        return GNUNET_SYSERR;
-      }
 
       {
         struct TALER_RefundRequestPS rr = {
           .purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_REFUND),
-          .purpose.size = htonl (sizeof (struct TALER_RefundRequestPS)),
-          .h_contract_terms = ph->h_contract_terms,
-          .coin_pub = res[i].coin_pub,
-          .merchant = merchant_pub,
-          .rtransaction_id = GNUNET_htonll (res[i].rtransaction_id)
+          .purpose.size = htonl (sizeof (rr)),
+          .h_contract_terms = oah->h_contract_terms,
+          .coin_pub = oah->coins[i].coin_pub,
+          .merchant = oah->merchant_pub,
+          .rtransaction_id = GNUNET_htonll (0)
         };
 
         TALER_amount_hton (&rr.refund_amount,
-                           &ph->coins[found].amount_with_fee);
+                           &oah->coins[i].amount_with_fee);
         TALER_amount_hton (&rr.refund_fee,
-                           &ph->coins[found].refund_fee);
+                           &oah->coins[i].refund_fee);
         if (GNUNET_OK !=
             GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_REFUND,
                                         &rr,
@@ -215,14 +203,12 @@ check_abort_refund (struct TALER_MERCHANT_Pay *ph,
         .http_status = MHD_HTTP_OK
       };
 
-      ph->abort_cb (ph->abort_cb_cls,
-                    &hr,
-                    &merchant_pub,
-                    &ph->h_contract_terms,
-                    num_refunds,
-                    res);
+      oah->abort_cb (oah->abort_cb_cls,
+                     &hr,
+                     num_refunds,
+                     res);
     }
-    ph->abort_cb = NULL;
+    oah->abort_cb = NULL;
   }
   GNUNET_JSON_parse_free (spec);
   return GNUNET_OK;
@@ -326,15 +312,15 @@ check_conflict (struct TALER_MERCHANT_Pay *ph,
   }
   GNUNET_JSON_parse_free (spec);
 
-  for (unsigned int i = 0; i<ph->num_coins; i++)
+  for (unsigned int i = 0; i<oah->num_coins; i++)
   {
-    if (0 == memcmp (&ph->coins[i].coin_pub,
+    if (0 == memcmp (&oah->coins[i].coin_pub,
                      &coin_pub,
                      sizeof (struct TALER_CoinSpendPublicKeyP)))
     {
       int ret;
 
-      ret = check_coin_history (&ph->coins[i],
+      ret = check_coin_history (&oah->coins[i],
                                 history);
       GNUNET_JSON_parse_free (hspec);
       return ret;
@@ -349,719 +335,250 @@ check_conflict (struct TALER_MERCHANT_Pay *ph,
 
 /**
  * Function called when we're done processing the
- * HTTP /pay request.
+ * abort request.
  *
- * @param cls the `struct TALER_MERCHANT_Pay`
+ * @param cls the `struct TALER_MERCHANT_OrderAbortHandle`
  * @param response_code HTTP response code, 0 on error
  * @param json response body, NULL if not in JSON
  */
 static void
-handle_pay_finished (void *cls,
-                     long response_code,
-                     const void *response)
+handle_abort_finished (void *cls,
+                       long response_code,
+                       const void *response)
 {
-  struct TALER_MERCHANT_Pay *ph = cls;
+  struct TALER_MERCHANT_OrderAbortHandle *oah = cls;
   const json_t *json = response;
   struct TALER_MERCHANT_HttpResponse hr = {
     .http_status = (unsigned int) response_code,
     .reply = json
   };
 
-  ph->job = NULL;
+  oah->job = NULL;
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               "/pay completed with response code %u\n",
               (unsigned int) response_code);
-  if (0 == strcasecmp (ph->mode,
-                       "pay"))
+  switch (response_code)
   {
-    switch (response_code)
+  case 0:
+    hr.ec = TALER_EC_INVALID_RESPONSE;
+    break;
+  case MHD_HTTP_OK:
+    if (GNUNET_OK ==
+        check_abort_refund (oah,
+                            json))
     {
-    case 0:
-      hr.ec = TALER_EC_INVALID_RESPONSE;
-      break;
-    case MHD_HTTP_OK:
-      break;
-    /* Tolerating Not Acceptable because sometimes
-     * - especially in tests - we might want to POST
-     * coins one at a time.  */
-    case MHD_HTTP_NOT_ACCEPTABLE:
-      hr.ec = TALER_JSON_get_error_code (json);
-      hr.hint = TALER_JSON_get_error_hint (json);
-      break;
-    case MHD_HTTP_BAD_REQUEST:
-      hr.ec = TALER_JSON_get_error_code (json);
-      hr.hint = TALER_JSON_get_error_hint (json);
-      /* This should never happen, either us
-       * or the merchant is buggy (or API version conflict);
-       * just pass JSON reply to the application */
-      break;
-    case MHD_HTTP_FORBIDDEN:
-      hr.ec = TALER_JSON_get_error_code (json);
-      hr.hint = TALER_JSON_get_error_hint (json);
-      /* Nothing really to verify, merchant says we tried to abort the payment
-       * after it was successful. We should pass the JSON reply to the
-       * application */
-      break;
-    case MHD_HTTP_NOT_FOUND:
-      hr.ec = TALER_JSON_get_error_code (json);
-      hr.hint = TALER_JSON_get_error_hint (json);
-      /* Nothing really to verify, this should never
-         happen, we should pass the JSON reply to the
-         application */
-      break;
-    case MHD_HTTP_PRECONDITION_FAILED:
-      TALER_MERCHANT_parse_error_details_ (json,
-                                           response_code,
-                                           &hr);
-      /* Nothing really to verify, the merchant is blaming us for failing to
-         satisfy some constraint (likely it does not like our exchange because
-         of some disagreement on the PKI).  We should pass the JSON reply to 
the
-         application */
-      break;
-    case MHD_HTTP_REQUEST_TIMEOUT:
-      hr.ec = TALER_JSON_get_error_code (json);
-      hr.hint = TALER_JSON_get_error_hint (json);
-      /* The merchant couldn't generate a timely response, likely because
-         it itself waited too long on the exchange.
-         Pass on to application. */
-      break;
-    case MHD_HTTP_CONFLICT:
-      hr.ec = TALER_JSON_get_error_code (json);
-      hr.hint = TALER_JSON_get_error_hint (json);
-      if (GNUNET_OK != check_conflict (ph,
-                                       json))
-      {
-        GNUNET_break_op (0);
-        response_code = 0;
-      }
-      break;
-    case MHD_HTTP_GONE:
-      hr.ec = TALER_JSON_get_error_code (json);
-      hr.hint = TALER_JSON_get_error_hint (json);
-      /* The merchant says we are too late, the offer has expired or some
-         denomination key of a coin involved has expired.
-         Might be a disagreement in timestamps? Still, pass on to application. 
*/
-      break;
-    case MHD_HTTP_FAILED_DEPENDENCY:
-      TALER_MERCHANT_parse_error_details_ (json,
-                                           response_code,
-                                           &hr);
-      /* Nothing really to verify, the merchant is blaming the exchange.
-         We should pass the JSON reply to the application */
-      break;
-    case MHD_HTTP_INTERNAL_SERVER_ERROR:
-      hr.ec = TALER_JSON_get_error_code (json);
-      hr.hint = TALER_JSON_get_error_hint (json);
-      /* Server had an internal issue; we should retry,
-         but this API leaves this to the application */
-      break;
-    case MHD_HTTP_SERVICE_UNAVAILABLE:
-      TALER_MERCHANT_parse_error_details_ (json,
-                                           response_code,
-                                           &hr);
-      /* Exchange couldn't respond properly; the retry is
-         left to the application */
-      break;
-    default:
-      TALER_MERCHANT_parse_error_details_ (json,
-                                           response_code,
-                                           &hr);
-      /* unexpected response code */
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  "Unexpected response code %u/%d\n",
-                  (unsigned int) response_code,
-                  (int) hr.ec);
-      GNUNET_break_op (0);
-      break;
+      TALER_MERCHANT_order_abort_cancel (oah);
+      return;
     }
-    ph->pay_cb (ph->pay_cb_cls,
-                &hr);
-  }
-  else
-  {
-    GNUNET_assert (0 == strcasecmp (ph->mode,
-                                    "abort-refund"));
-
-    switch (response_code)
-    {
-    case 0:
-      hr.ec = TALER_EC_INVALID_RESPONSE;
-      break;
-    case MHD_HTTP_OK:
-      if (GNUNET_OK ==
-          check_abort_refund (ph,
-                              json))
-      {
-        TALER_MERCHANT_pay_cancel (ph);
-        return;
-      }
-      hr.http_status = 0;
-      hr.ec = TALER_EC_PAY_MERCHANT_INVALID_RESPONSE;
-      break;
-    case MHD_HTTP_BAD_REQUEST:
-      hr.ec = TALER_JSON_get_error_code (json);
-      hr.hint = TALER_JSON_get_error_hint (json);
-      /* This should never happen, either us or the
-         merchant is buggy (or API version conflict); just
-         pass JSON reply to the application */
-      break;
-    case MHD_HTTP_CONFLICT:
-      hr.ec = TALER_JSON_get_error_code (json);
-      hr.hint = TALER_JSON_get_error_hint (json);
-      break;
-    case MHD_HTTP_FORBIDDEN:
-      hr.ec = TALER_JSON_get_error_code (json);
-      hr.hint = TALER_JSON_get_error_hint (json);
-      /* Nothing really to verify, merchant says one of
-         the signatures is invalid; as we checked them,
-         this should never happen, we should pass the JSON
-         reply to the application */
-      break;
-    case MHD_HTTP_NOT_FOUND:
-      hr.ec = TALER_JSON_get_error_code (json);
-      hr.hint = TALER_JSON_get_error_hint (json);
-      /* Nothing really to verify, this should never
-   happen, we should pass the JSON reply to the
-         application */
-      break;
-    case MHD_HTTP_FAILED_DEPENDENCY:
-      TALER_MERCHANT_parse_error_details_ (json,
-                                           response_code,
-                                           &hr);
-      /* Nothing really to verify, the merchant is blaming the exchange.
-         We should pass the JSON reply to the application */
-      break;
-    case MHD_HTTP_INTERNAL_SERVER_ERROR:
-      hr.ec = TALER_JSON_get_error_code (json);
-      hr.hint = TALER_JSON_get_error_hint (json);
-      /* Server had an internal issue; we should retry,
-         but this API leaves this to the application */
-      break;
-    default:
-      /* unexpected response code */
-      TALER_MERCHANT_parse_error_details_ (json,
-                                           response_code,
-                                           &hr);
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  "Unexpected response code %u/%d\n",
-                  (unsigned int) response_code,
-                  (int) hr.ec);
-      GNUNET_break_op (0);
-      break;
-    }
-    ph->abort_cb (ph->abort_cb_cls,
-                  &hr,
-                  NULL,
-                  NULL,
-                  0,
-                  NULL);
+    hr.http_status = 0;
+    hr.ec = TALER_EC_PAY_MERCHANT_INVALID_RESPONSE;
+    break;
+  case MHD_HTTP_BAD_REQUEST:
+    hr.ec = TALER_JSON_get_error_code (json);
+    hr.hint = TALER_JSON_get_error_hint (json);
+    /* This should never happen, either us or the
+       merchant is buggy (or API version conflict); just
+       pass JSON reply to the application */
+    break;
+  case MHD_HTTP_CONFLICT:
+    hr.ec = TALER_JSON_get_error_code (json);
+    hr.hint = TALER_JSON_get_error_hint (json);
+    break;
+  case MHD_HTTP_FORBIDDEN:
+    hr.ec = TALER_JSON_get_error_code (json);
+    hr.hint = TALER_JSON_get_error_hint (json);
+    /* Nothing really to verify, merchant says one of
+       the signatures is invalid; as we checked them,
+       this should never happen, we should pass the JSON
+       reply to the application */
+    break;
+  case MHD_HTTP_NOT_FOUND:
+    hr.ec = TALER_JSON_get_error_code (json);
+    hr.hint = TALER_JSON_get_error_hint (json);
+    /* Nothing really to verify, this should never
+ happen, we should pass the JSON reply to the
+       application */
+    break;
+  case MHD_HTTP_FAILED_DEPENDENCY:
+    TALER_MERCHANT_parse_error_details_ (json,
+                                         response_code,
+                                         &hr);
+    /* Nothing really to verify, the merchant is blaming the exchange.
+       We should pass the JSON reply to the application */
+    break;
+  case MHD_HTTP_INTERNAL_SERVER_ERROR:
+    hr.ec = TALER_JSON_get_error_code (json);
+    hr.hint = TALER_JSON_get_error_hint (json);
+    /* Server had an internal issue; we should retry,
+       but this API leaves this to the application */
+    break;
+  default:
+    /* unexpected response code */
+    TALER_MERCHANT_parse_error_details_ (json,
+                                         response_code,
+                                         &hr);
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Unexpected response code %u/%d\n",
+                (unsigned int) response_code,
+                (int) hr.ec);
+    GNUNET_break_op (0);
+    break;
   }
-  TALER_MERCHANT_pay_cancel (ph);
+  oah->abort_cb (oah->abort_cb_cls,
+                 &hr,
+                 0,
+                 NULL);
+  TALER_MERCHANT_abort_cancel (oah);
 }
 
 
 /**
- * Issue /pay request. Generic version for the various
- * variants of the API.
+ * Run an abort operation, asking for refunds for coins
+ * that were previously spend on a/pay that failed to go through.
  *
- * @param ctx the execution loop context
- * @param merchant_url base URL of the merchant's backend
- * @param merchant_pub public key of the merchant
+ * @param ctx execution context
+ * @param merchant_url base URL of the merchant
+ * @param order_id order to abort
+ * @param h_contract hash of the contact of the merchant with the customer
+ * @param merchant_pub the public key of the merchant (used to identify the 
merchant for refund requests)
  * @param num_coins number of coins used to pay
  * @param coins array of coins we use to pay
- * @param mode mode string to use ("pay" or "abort-refund").
- * @param pay_cb the callback to call when a reply for this
- *        request is available
- * @param pay_cb_cls closure for @a pay_cb
- * @param abort_cb callback to call for the abort-refund variant
- * @param abort_cb_cls closure for @a abort_cb
+ * @param cb the callback to call when a reply for this request is available
+ * @param cb_cls closure for @a pay_cb
  * @return a handle for this request
  */
-static struct TALER_MERCHANT_Pay *
-request_pay_generic (
-  struct GNUNET_CURL_Context *ctx,
-  const char *merchant_url,
-  const struct TALER_MerchantPublicKeyP *merchant_pub,
-  const char *order_id,
-  unsigned int num_coins,
-  const struct TALER_MERCHANT_PaidCoin *coins,
-  const char *mode,
-  TALER_MERCHANT_OrderPayCallback pay_cb,
-  void *pay_cb_cls,
-  TALER_MERCHANT_PayRefundCallback abort_cb,
-  void *abort_cb_cls)
+struct TALER_MERCHANT_OrderAbortHandle *
+TALER_MERCHANT_order_abort (struct GNUNET_CURL_Context *ctx,
+                            const char *merchant_url,
+                            const char *order_id,
+                            const struct TALER_MerchantPublicKeyP 
*merchant_pub,
+                            const struct GNUNET_HashCode *h_contract,
+                            unsigned int num_coins,
+                            const struct TALER_MERCHANT_AbortCoin coins[],
+                            TALER_MERCHANT_AbortCallback cb,
+                            void *cb_cls)
 {
-  struct TALER_MERCHANT_Pay *ph;
-  json_t *pay_obj;
-  json_t *j_coins;
-  CURL *eh;
-  struct TALER_Amount total_fee;
-  struct TALER_Amount total_amount;
+  struct TALER_MERCHANT_OrderAbortHandle *oah;
+  json_t *abort_obj;
 
-  if (0 == num_coins)
+  j_coins = json_array ();
+  if (NULL == j_coins)
   {
     GNUNET_break (0);
     return NULL;
   }
-  j_coins = json_array ();
   for (unsigned int i = 0; i<num_coins; i++)
   {
+    const struct TALER_MERCHANT_AbortCoin *ac = &coins[i];
     json_t *j_coin;
-    const struct TALER_MERCHANT_PaidCoin *pc = &coins[i];
-    struct TALER_Amount fee;
-
-    if (0 >
-        TALER_amount_subtract (&fee,
-                               &pc->amount_with_fee,
-                               &pc->amount_without_fee))
-    {
-      /* Integer underflow, fee larger than total amount?
-         This should not happen (client violated API!) */
-      GNUNET_break (0);
-      json_decref (j_coins);
-      return NULL;
-    }
-    if (0 == i)
-    {
-      total_fee = fee;
-      total_amount = pc->amount_with_fee;
-    }
-    else
-    {
-      if ( (0 >
-            TALER_amount_add (&total_fee,
-                              &total_fee,
-                              &fee)) ||
-           (0 >
-            TALER_amount_add (&total_amount,
-                              &total_amount,
-                              &pc->amount_with_fee)) )
-      {
-        /* integer overflow */
-        GNUNET_break (0);
-        json_decref (j_coins);
-        return NULL;
-      }
-    }
 
     /* create JSON for this coin */
     j_coin = json_pack (
-      "{s:o, s:o,"                   /* contribution/coin_pub */
-      " s:s, s:o,"          /* exchange_url / denom_pub */
-      " s:o, s:o}",          /* ub_sig / coin_sig */
-      "contribution",
-      TALER_JSON_from_amount (&pc->amount_with_fee),
+      "{s:o, s:o,s:s}",
       "coin_pub",
-      GNUNET_JSON_from_data_auto (&pc->coin_pub),
+      GNUNET_JSON_from_data_auto (&ac->coin_pub),
+      "contribution",
+      TALER_JSON_from_amount (&ac->amount_with_fee),
       "exchange_url",
-      pc->exchange_url,
-      "denom_pub",
-      GNUNET_JSON_from_rsa_public_key (pc->denom_pub.rsa_public_key),
-      "ub_sig",
-      GNUNET_JSON_from_rsa_signature (pc->denom_sig.rsa_signature),
-      "coin_sig",
-      GNUNET_JSON_from_data_auto (&pc->coin_sig));
-    if (0 !=
-        json_array_append_new (j_coins,
-                               j_coin))
+      ac->exchange_url);
+    if ( (NULL == j_coin) ||
+         (0 !=
+          json_array_append_new (j_coins,
+                                 j_coin)) )
     {
       GNUNET_break (0);
       json_decref (j_coins);
       return NULL;
     }
   }
-
-  pay_obj = json_pack ("{"
-                       " s:s," /* mode */
-                       " s:o," /* coins */
-                       " s:s," /* order_id */
-                       " s:o," /* merchant_pub */
-                       "}",
-                       "mode",
-                       mode,
-                       "coins",
-                       j_coins, /* reference consumed! */
-                       "order_id",
-                       order_id,
-                       "merchant_pub",
-                       GNUNET_JSON_from_data_auto (merchant_pub));
-  if (NULL == pay_obj)
+  abort_obj = json_pack ("{s:o,s:o}",
+                         "coins",
+                         j_coins, /* reference consumed! */
+                         "h_contract",
+                         GNUNET_JSON_from_data_auto (h_contract));
+  if (NULL == abort_obj)
   {
     GNUNET_break (0);
     return NULL;
   }
-  ph = GNUNET_new (struct TALER_MERCHANT_Pay);
-  ph->ctx = ctx;
-  ph->mode = mode;
-  ph->abort_cb = abort_cb;
-  ph->abort_cb_cls = abort_cb_cls;
-  ph->pay_cb = pay_cb;
-  ph->pay_cb_cls = pay_cb_cls;
-  ph->url = TALER_url_join (merchant_url, "pay", NULL);
-  if (NULL == ph->url)
+  oah = GNUNET_new (struct TALER_MERCHANT_OrderAbortHandle);
+  oah->h_contract_terms = *h_contract;
+  oah->merchant_pub = *merchant_pub;
+  oah->ctx = ctx;
+  oah->abort_cb = cb;
+  oah->abort_cb_cls = cb_cls;
+  {
+    char *path;
+
+    GNUNET_asprintf (&path,
+                     "orders/%s/abort",
+                     order_id);
+    oah->url = TALER_url_join (merchant_url,
+                               path,
+                               NULL);
+    GNUNET_free (path);
+  }
+  if (NULL == oah->url)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "Could not construct request URL.\n");
-    json_decref (pay_obj);
-    GNUNET_free (ph);
+    json_decref (abort_obj);
+    GNUNET_free (oah);
     return NULL;
   }
-  ph->num_coins = num_coins;
-  ph->coins = GNUNET_new_array (num_coins,
-                                struct TALER_MERCHANT_PaidCoin);
-  memcpy (ph->coins,
+  oah->num_coins = num_coins;
+  oah->coins = GNUNET_new_array (num_coins,
+                                 struct TALER_MERCHANT_AbortCoin);
+  memcpy (oah->coins,
           coins,
-          num_coins * sizeof (struct TALER_MERCHANT_PaidCoin));
+          num_coins * sizeof (struct TALER_MERCHANT_AbortCoin));
 
   eh = curl_easy_init ();
-  if (GNUNET_OK != TALER_curl_easy_post (&ph->post_ctx,
-                                         eh,
-                                         pay_obj))
-  {
-    GNUNET_break (0);
-    json_decref (pay_obj);
-    GNUNET_free (ph);
-    return NULL;
-  }
-
-  json_decref (pay_obj);
-  GNUNET_assert (CURLE_OK == curl_easy_setopt (eh,
-                                               CURLOPT_URL,
-                                               ph->url));
-  ph->job = GNUNET_CURL_job_add2 (ctx,
-                                  eh,
-                                  ph->post_ctx.headers,
-                                  &handle_pay_finished,
-                                  ph);
-  return ph;
-}
-
-
-/**
- * Pay a merchant.  API for wallets that have the coin's private
- * keys.
- * _NOTE_: this function does NOT calculate each coin amount in
- * order to match the contract total price.  This calculation is
- * to be made by the logic using this library.
- *
- * @param ctx the execution loop context
- * @param merchant_url base URL of the merchant's backend
- * @param h_contract_terms hashcode of the proposal being paid
- * @param amount total value of the contract to be paid to the
- *        merchant
- * @param max_fee maximum fee covered by the merchant
- *        (according to the contract)
- * @param merchant_pub the public key of the merchant
- *        (used to identify the merchant for refund requests)
- * @param merchant_sig signature from the merchant over the
- *        original contract
- * @param timestamp timestamp when the contract was finalized,
- *        must match approximately the current time of the merchant
- * @param refund_deadline date until which the merchant can issue
- *        a refund to the customer via the merchant (can be zero
- *        if refunds are not allowed)
- * @param pay_deadline maximum time limit to pay for this contract
- * @param h_wire hash of the merchant’s account details
- * @param order_id order id of the proposal being paid
- * @param num_coins number of coins used to pay
- * @param coins array of coins we use to pay
- * @param pay_cb the callback to call when a reply for this
- *        request is available
- * @param pay_cb_cls closure for @a pay_cb
- * @return a handle for this request
- */
-static struct TALER_MERCHANT_Pay *
-prepare_pay_generic (struct GNUNET_CURL_Context *ctx,
-                     const char *merchant_url,
-                     const struct GNUNET_HashCode *h_contract_terms,
-                     const struct TALER_Amount *amount,
-                     const struct TALER_Amount *max_fee,
-                     const struct TALER_MerchantPublicKeyP *merchant_pub,
-                     const struct TALER_MerchantSignatureP *merchant_sig,
-                     struct GNUNET_TIME_Absolute timestamp,
-                     struct GNUNET_TIME_Absolute refund_deadline,
-                     struct GNUNET_TIME_Absolute pay_deadline,
-                     const struct GNUNET_HashCode *h_wire,
-                     const char *order_id,
-                     unsigned int num_coins,
-                     const struct TALER_MERCHANT_PayCoin *coins,
-                     const char *mode,
-                     TALER_MERCHANT_PayCallback pay_cb,
-                     void *pay_cb_cls,
-                     TALER_MERCHANT_PayRefundCallback abort_cb,
-                     void *abort_cb_cls)
-{
-  struct TALER_DepositRequestPS dr;
-  struct TALER_MERCHANT_PaidCoin pc[num_coins];
-
-  (void) GNUNET_TIME_round_abs (&timestamp);
-  (void) GNUNET_TIME_round_abs (&pay_deadline);
-  (void) GNUNET_TIME_round_abs (&refund_deadline);
-
-  if (GNUNET_YES !=
-      TALER_amount_cmp_currency (amount,
-                                 max_fee))
+  GNUNET_assert (NULL != eh);
+  if (GNUNET_OK !=
+      TALER_curl_easy_post (&oah->post_ctx,
+                            eh,
+                            abort_obj))
   {
     GNUNET_break (0);
+    json_decref (abort_obj);
+    GNUNET_free (oah);
     return NULL;
   }
-
-  dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT);
-  dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS));
-  dr.h_contract_terms = *h_contract_terms;
-  dr.h_wire = *h_wire;
-  dr.timestamp = GNUNET_TIME_absolute_hton (timestamp);
-  dr.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline);
-  dr.merchant = *merchant_pub;
-
-  for (unsigned int i = 0; i<num_coins; i++)
-  {
-    const struct TALER_MERCHANT_PayCoin *coin = &coins[i]; // coin priv.
-    struct TALER_MERCHANT_PaidCoin *p = &pc[i]; // coin pub.
-    struct TALER_Amount fee;
-
-    /* prepare 'dr' for this coin to generate coin signature */
-    GNUNET_CRYPTO_eddsa_key_get_public (&coin->coin_priv.eddsa_priv,
-                                        &dr.coin_pub.eddsa_pub);
-    TALER_amount_hton (&dr.amount_with_fee,
-                       &coin->amount_with_fee);
-    if (0 >
-        TALER_amount_subtract (&fee,
-                               &coin->amount_with_fee,
-                               &coin->amount_without_fee))
-    {
-      /* Integer underflow, fee larger than total amount?
-         This should not happen (client violated API!) */
-      GNUNET_break (0);
-      return NULL;
-    }
-    TALER_amount_hton (&dr.deposit_fee,
-                       &fee);
-    {
-      TALER_LOG_DEBUG ("... amount_with_fee was %s\n",
-                       TALER_amount2s (&coin->amount_with_fee));
-      TALER_LOG_DEBUG ("... fee was %s\n",
-                       TALER_amount2s (&fee));
-    }
-
-    GNUNET_CRYPTO_eddsa_sign (&coin->coin_priv.eddsa_priv,
-                              &dr,
-                              &p->coin_sig.eddsa_signature);
-    p->denom_pub = coin->denom_pub;
-    p->denom_sig = coin->denom_sig;
-    p->denom_value = coin->denom_value;
-    p->coin_pub = dr.coin_pub;
-    p->amount_with_fee = coin->amount_with_fee;
-    p->amount_without_fee = coin->amount_without_fee;
-    p->refund_fee = coin->refund_fee;
-    p->exchange_url = coin->exchange_url;
-  }
-  return request_pay_generic (ctx,
-                              merchant_url,
-                              merchant_pub,
-                              order_id,
-                              num_coins,
-                              pc,
-                              mode,
-                              pay_cb,
-                              pay_cb_cls,
-                              abort_cb,
-                              abort_cb_cls);
-}
-
-
-/**
- * Pay a merchant.  API for wallets that have the coin's private keys.
- * _NOTE_: this function does NOT calculate each coin amount in order
- * to match the contract total price.  This calculation is to be made
- * by the logic using this library.
- *
- * @param ctx the execution loop context
- * @param merchant_url base URL of the merchant's backend
- * @param h_contract_terms hashcode of the proposal being paid
- * @param amount total value of the contract to be paid to the merchant
- * @param max_fee maximum fee covered by the merchant (according to the 
contract)
- * @param merchant_pub the public key of the merchant (used to identify the 
merchant for refund requests)
- * @param merchant_sig signature from the merchant over the original contract
- * @param timestamp timestamp when the contract was finalized, must match 
approximately the current time of the merchant
- * @param refund_deadline date until which the merchant can issue a refund to 
the customer via the merchant (can be zero if refunds are not allowed)
- * @param pay_deadline maximum time limit to pay for this contract
- * @param h_wire hash of the merchant’s account details
- * @param order_id order id of the proposal being paid
- * @param num_coins number of coins used to pay
- * @param coins array of coins we use to pay
- * @param pay_cb the callback to call when a reply for this request is 
available
- * @param pay_cb_cls closure for @a pay_cb
- * @return a handle for this request
- */
-struct TALER_MERCHANT_Pay *
-TALER_MERCHANT_pay_wallet (struct GNUNET_CURL_Context *ctx,
-                           const char *merchant_url,
-                           const struct GNUNET_HashCode *h_contract_terms,
-                           const struct TALER_Amount *amount,
-                           const struct TALER_Amount *max_fee,
-                           const struct TALER_MerchantPublicKeyP *merchant_pub,
-                           const struct TALER_MerchantSignatureP *merchant_sig,
-                           struct GNUNET_TIME_Absolute timestamp,
-                           struct GNUNET_TIME_Absolute refund_deadline,
-                           struct GNUNET_TIME_Absolute pay_deadline,
-                           const struct GNUNET_HashCode *h_wire,
-                           const char *order_id,
-                           unsigned int num_coins,
-                           const struct TALER_MERCHANT_PayCoin *coins,
-                           TALER_MERCHANT_PayCallback pay_cb,
-                           void *pay_cb_cls)
-{
-  return prepare_pay_generic (ctx,
-                              merchant_url,
-                              h_contract_terms,
-                              amount,
-                              max_fee,
-                              merchant_pub,
-                              merchant_sig,
-                              timestamp,
-                              refund_deadline,
-                              pay_deadline,
-                              h_wire,
-                              order_id,
-                              num_coins,
-                              coins,
-                              "pay",
-                              pay_cb,
-                              pay_cb_cls,
-                              NULL,
-                              NULL);
-}
-
-
-/**
- * Run a payment abort operation, asking for refunds for coins
- * that were previously spend on a /pay that failed to go through.
- *
- * @param ctx execution context
- * @param merchant_url base URL of the merchant
- * @param h_wire hash of the merchant’s account details
- * @param h_contract hash of the contact of the merchant with the customer
- * @param transaction_id transaction id for the transaction between merchant 
and customer
- * @param amount total value of the contract to be paid to the merchant
- * @param max_fee maximum fee covered by the merchant (according to the 
contract)
- * @param merchant_pub the public key of the merchant (used to identify the 
merchant for refund requests)
- * @param merchant_sig signature from the merchant over the original contract
- * @param timestamp timestamp when the contract was finalized, must match 
approximately the current time of the merchant
- * @param refund_deadline date until which the merchant can issue a refund to 
the customer via the merchant (can be zero if refunds are not allowed)
- * @param pay_deadline maximum time limit to pay for this contract
- * @param num_coins number of coins used to pay
- * @param coins array of coins we use to pay
- * @param coin_sig the signature made with purpose 
#TALER_SIGNATURE_WALLET_COIN_DEPOSIT made by the customer with the coin’s 
private key.
- * @param payref_cb the callback to call when a reply for this request is 
available
- * @param payref_cb_cls closure for @a pay_cb
- * @return a handle for this request
- */
-struct TALER_MERCHANT_Pay *
-TALER_MERCHANT_pay_abort (struct GNUNET_CURL_Context *ctx,
-                          const char *merchant_url,
-                          const struct GNUNET_HashCode *h_contract,
-                          const struct TALER_Amount *amount,
-                          const struct TALER_Amount *max_fee,
-                          const struct TALER_MerchantPublicKeyP *merchant_pub,
-                          const struct TALER_MerchantSignatureP *merchant_sig,
-                          struct GNUNET_TIME_Absolute timestamp,
-                          struct GNUNET_TIME_Absolute refund_deadline,
-                          struct GNUNET_TIME_Absolute pay_deadline,
-                          const struct GNUNET_HashCode *h_wire,
-                          const char *order_id,
-                          unsigned int num_coins,
-                          const struct TALER_MERCHANT_PayCoin *coins,
-                          TALER_MERCHANT_PayRefundCallback payref_cb,
-                          void *payref_cb_cls)
-{
-  struct TALER_MERCHANT_Pay *ph;
-
-  ph = prepare_pay_generic (ctx,
-                            merchant_url,
-                            h_contract,
-                            amount,
-                            max_fee,
-                            merchant_pub,
-                            merchant_sig,
-                            timestamp,
-                            refund_deadline,
-                            pay_deadline,
-                            h_wire,
-                            order_id,
-                            num_coins,
-                            coins,
-                            "abort-refund",
-                            NULL,
-                            NULL,
-                            payref_cb,
-                            payref_cb_cls);
-  if (NULL == ph)
-    return NULL;
-  ph->h_contract_terms = *h_contract;
-  return ph;
-}
-
-
-/**
- * PAY a merchant.  API for frontends talking to backends. Here,
- * the frontend does not have the coin's private keys, but just
- * the public keys and signatures.  Note the subtle difference
- * in the type of @a coins compared to #TALER_MERCHANT_pay().
- *
- * @param ctx the execution loop context
- * @param merchant_url base URL of the merchant's backend
- * @param merchant_pub public key of the merchant
- * @param num_coins number of coins used to pay
- * @param coins array of coins we use to pay
- * @param pay_cb the callback to call when a reply for this request is 
available
- * @param pay_cb_cls closure for @a pay_cb
- * @return a handle for this request
- */
-struct TALER_MERCHANT_Pay *
-TALER_MERCHANT_pay_frontend (
-  struct GNUNET_CURL_Context *ctx,
-  const char *merchant_url,
-  const struct TALER_MerchantPublicKeyP *merchant_pub,
-  const char *order_id,
-  unsigned int num_coins,
-  const struct TALER_MERCHANT_PaidCoin *coins,
-  TALER_MERCHANT_PayCallback pay_cb,
-  void *pay_cb_cls)
-{
-  return request_pay_generic (ctx,
-                              merchant_url,
-                              merchant_pub,
-                              order_id,
-                              num_coins,
-                              coins,
-                              "pay",
-                              pay_cb,
-                              pay_cb_cls,
-                              NULL,
-                              NULL);
+  json_decref (abort_obj);
+  GNUNET_assert (CURLE_OK ==
+                 curl_easy_setopt (eh,
+                                   CURLOPT_URL,
+                                   oah->url));
+  oah->job = GNUNET_CURL_job_add2 (ctx,
+                                   eh,
+                                   oah->post_ctx.headers,
+                                   &handle_abort_finished,
+                                   oah);
+
+  return oah;
 }
 
 
 /**
- * Cancel a pay permission request.  This function cannot be used
- * on a request handle if a response is already served for it.
+ * Cancel an abort request.  This function cannot be used on a request handle
+ * if a response is already served for it.
  *
- * @param pay the pay permission request handle
+ * @param oah the pay permission request handle
  */
 void
-TALER_MERCHANT_pay_cancel (struct TALER_MERCHANT_Pay *pay)
+TALER_MERCHANT_abort_cancel (struct TALER_MERCHANT_OrderAbortHandle *oah)
 {
-  if (NULL != pay->job)
+  if (NULL != oah->job)
   {
-    GNUNET_CURL_job_cancel (pay->job);
-    pay->job = NULL;
+    GNUNET_CURL_job_cancel (oah->job);
+    oah->job = NULL;
   }
-  TALER_curl_easy_post_finished (&pay->post_ctx);
-  GNUNET_free (pay->coins);
-  GNUNET_free (pay->url);
-  GNUNET_free (pay);
+  TALER_curl_easy_post_finished (&oah->post_ctx);
+  GNUNET_free (oah->coins);
+  GNUNET_free (oah->url);
+  GNUNET_free (oah);
 }
 
 
-/* end of merchant_api_pay.c */
+/* end of merchant_api_post_order_abort.c */

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]