gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] [taler-merchant] branch master updated: add missing check-p


From: gnunet
Subject: [GNUnet-SVN] [taler-merchant] branch master updated: add missing check-payment implementation
Date: Thu, 04 Jan 2018 17:57:41 +0100

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

dold pushed a commit to branch master
in repository merchant.

The following commit(s) were added to refs/heads/master by this push:
     new 10cd6a5  add missing check-payment implementation
10cd6a5 is described below

commit 10cd6a5c9ceaa52f0c74f6992bc41cfe114c94dc
Author: Florian Dold <address@hidden>
AuthorDate: Thu Jan 4 17:57:36 2018 +0100

    add missing check-payment implementation
---
 src/backend/taler-merchant-httpd_check-payment.c | 309 +++++++++++++++++++++++
 src/backend/taler-merchant-httpd_check-payment.h |  46 ++++
 2 files changed, 355 insertions(+)

diff --git a/src/backend/taler-merchant-httpd_check-payment.c 
b/src/backend/taler-merchant-httpd_check-payment.c
new file mode 100644
index 0000000..af5eee1
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_check-payment.c
@@ -0,0 +1,309 @@
+/*
+  This file is part of TALER
+  (C) 2017 Taler Systems SA
+
+  TALER is free software; you can redistribute it and/or modify it under the
+  terms of the GNU General Public License as published by the Free Software
+  Foundation; either version 3, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along with
+  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file backend/taler-merchant-httpd_check-payment.c
+ * @brief implementation of /check-payment handler
+ * @author Florian Dold
+ */
+#include "platform.h"
+#include <string.h>
+#include <microhttpd.h>
+#include <jansson.h>
+#include <taler/taler_json_lib.h>
+#include <taler/taler_signatures.h>
+#include "taler-merchant-httpd.h"
+#include "taler-merchant-httpd_mhd.h"
+#include "taler-merchant-httpd_parsing.h"
+#include "taler-merchant-httpd_exchanges.h"
+#include "taler-merchant-httpd_responses.h"
+#include "taler-merchant-httpd_check-payment.h"
+
+
+/**
+ * Concatenate two strings and grow the first buffer (of size n)
+ * if necessary.
+ */
+#define STR_CAT_GROW(s, p, n) do { \
+    for (; strlen (s) + strlen (p) >= n; (n) = (n) * 2); \
+    (s) = GNUNET_realloc ((s), (n)); \
+    GNUNET_assert (NULL != (s)); \
+    strncat (s, p, n); \
+  } while (0)
+
+
+/**
+ * Make an absolute URL to the backend.
+ *
+ * @param connection MHD connection to take header values from
+ * @param path path of the url
+ * @param ... NULL-terminated key-value pairs (char *) for query parameters
+ */
+static char *
+make_absolute_backend_url (struct MHD_Connection *connection, char *path, ...)
+{
+  static CURL *curl = NULL;
+  if (NULL == curl)
+  {
+    curl = curl_easy_init();
+    GNUNET_assert (NULL != curl);
+  }
+
+  size_t n = 256;
+  char *res = GNUNET_malloc (n);
+
+  GNUNET_assert (NULL != res);
+
+  // By default we assume we're running under HTTP
+  const char *proto = "http";
+  const char *forwarded_proto = MHD_lookup_connection_value (connection, 
MHD_HEADER_KIND, "X-Forwarded-Proto");
+
+  if (NULL != forwarded_proto)
+    proto = forwarded_proto;
+
+  const char *host = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, 
"Host");
+  const char *forwarded_host = MHD_lookup_connection_value (connection, 
MHD_HEADER_KIND, "X-Forwarded-Host");
+
+  if (NULL != forwarded_host)
+    host = forwarded_host;
+
+  if (NULL == host)
+  {
+    // Should never happen, at last the host header should be defined
+    GNUNET_break (0);
+    return NULL;
+  }
+
+  STR_CAT_GROW (res, proto, n);
+  STR_CAT_GROW (res, "://", n);
+  STR_CAT_GROW (res, host, n);
+  STR_CAT_GROW (res, "/", n);
+  STR_CAT_GROW (res, path, n);
+
+  va_list args;
+  va_start (args, path);
+
+  unsigned int iparam = 0;
+
+  while (1) {
+    char *key = va_arg (args, char *);
+    if (NULL == key)
+      break;
+    char *value = va_arg (args, char *);
+    if (NULL == value)
+      continue;
+    if (0 == iparam)
+      STR_CAT_GROW (res, "?", n);
+    else
+      STR_CAT_GROW (res, "&", n);
+    iparam++;
+    char *urlencoded_value = curl_easy_escape (curl, value, strlen (value));
+    STR_CAT_GROW (res, key, n);
+    STR_CAT_GROW (res, "=", n);
+    STR_CAT_GROW (res, urlencoded_value, n);
+    curl_free (urlencoded_value);
+  }
+
+  va_end (args);
+
+  return res;
+}
+
+
+/**
+ * Manages a /check-payment call, checking the status
+ * of a payment and, if necessary, constructing the URL
+ * for a payment redirect URL.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+MH_handler_check_payment (struct TMH_RequestHandler *rh,
+                          struct MHD_Connection *connection,
+                          void **connection_cls,
+                          const char *upload_data,
+                          size_t *upload_data_size)
+{
+  const char *order_id;
+  const char *contract_url;
+  const char *session_id;
+  const char *session_sig_str;
+  const char *instance_str;
+
+  order_id = MHD_lookup_connection_value (connection,
+                                          MHD_GET_ARGUMENT_KIND,
+                                          "order_id");
+  contract_url = MHD_lookup_connection_value (connection,
+                                              MHD_GET_ARGUMENT_KIND,
+                                              "contract_url");
+  session_id = MHD_lookup_connection_value (connection,
+                                                MHD_GET_ARGUMENT_KIND,
+                                                "session_id");
+  session_sig_str = MHD_lookup_connection_value (connection,
+                                                MHD_GET_ARGUMENT_KIND,
+                                                "session_sig");
+  instance_str = MHD_lookup_connection_value (connection,
+                                              MHD_GET_ARGUMENT_KIND,
+                                              "instance");
+
+  if (NULL == instance_str)
+    instance_str = "default";
+
+  struct MerchantInstance *mi = TMH_lookup_instance (instance_str);
+  if (NULL == mi)
+    return TMH_RESPONSE_reply_bad_request (connection,
+                                           TALER_EC_PAY_INSTANCE_UNKNOWN,
+                                           "merchant instance unknown");
+
+  if (NULL == order_id)
+  {
+    if (NULL == contract_url)
+      return TMH_RESPONSE_reply_bad_request (connection,
+                                             TALER_EC_PARAMETER_MISSING,
+                                             "either order_id or contract_url 
must be given");
+    goto do_pay;
+    // No order_id given, redirect to a page that gives the wallet a new
+    // contract.
+  }
+
+  if (NULL != session_id)
+  {
+    // If the session id is given, the frontend wants us
+    // to verify the session signature.
+    if (NULL == session_sig_str)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "pay session signature required but 
missing\n");
+      goto do_pay;
+    }
+
+    struct GNUNET_CRYPTO_EddsaSignature sig;
+    if (GNUNET_OK !=
+        GNUNET_STRINGS_string_to_data (session_sig_str,
+                                       strlen (session_sig_str),
+                                       &sig,
+                                       sizeof (struct 
GNUNET_CRYPTO_EddsaSignature)))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "pay session signature 
malformed\n");
+      goto do_pay;
+    }
+    struct TALER_MerchantPaySessionSigPS mps;
+    mps.purpose.size = htonl (sizeof (struct TALER_MerchantPaySessionSigPS));
+    mps.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_PAY_SESSION);
+    GNUNET_assert (NULL != order_id);
+    GNUNET_assert (NULL != session_id);
+    GNUNET_CRYPTO_hash (order_id, strlen (order_id), &mps.h_order_id);
+    GNUNET_CRYPTO_hash (session_id, strlen (session_id), &mps.h_session_id);
+    if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify 
(TALER_SIGNATURE_MERCHANT_PAY_SESSION,
+                                                 &mps.purpose,
+                                                 &sig,
+                                                 &mi->pubkey.eddsa_pub))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "pay session signature invalid\n");
+      goto do_pay;
+    }
+  }
+
+  GNUNET_assert (NULL != order_id);
+
+  enum GNUNET_DB_QueryStatus qs;
+  json_t *contract_terms;
+  struct GNUNET_HashCode h_contract_terms;
+
+  qs = db->find_contract_terms (db->cls,
+                                &contract_terms,
+                                order_id,
+                                &mi->pubkey);
+  if (0 > qs)
+  {
+    /* single, read-only SQL statements should never cause
+       serialization problems */
+    GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
+    /* Always report on hard error as well to enable diagnostics */
+    GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
+    return TMH_RESPONSE_reply_internal_error (connection,
+                                             TALER_EC_PAY_DB_FETCH_PAY_ERROR,
+                                             "db error to previous /pay data");
+
+  }
+  if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+  {
+    return TMH_RESPONSE_reply_not_found (connection,
+                                         TALER_EC_PAY_DB_STORE_PAY_ERROR,
+                                         "Proposal not found");
+  }
+
+  if (GNUNET_OK !=
+      TALER_JSON_hash (contract_terms,
+                       &h_contract_terms))
+  {
+    GNUNET_break (0);
+    return TMH_RESPONSE_reply_internal_error (connection,
+                                              
TALER_EC_PAY_FAILED_COMPUTE_PROPOSAL_HASH,
+                                              "Failed to hash proposal");
+  }
+
+  /* Check if transaction is already known, if not store it. */
+  {
+    struct GNUNET_HashCode h_xwire;
+    struct GNUNET_TIME_Absolute xtimestamp;
+    struct GNUNET_TIME_Absolute xrefund;
+    struct TALER_Amount xtotal_amount;
+    
+    qs = db->find_transaction (db->cls,
+                              &h_contract_terms,
+                              &mi->pubkey,
+                              &h_xwire,
+                              &xtimestamp,
+                              &xrefund,
+                              &xtotal_amount);
+    if (0 > qs)
+    {
+      /* Always report on hard error as well to enable diagnostics */
+      GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
+      return TMH_RESPONSE_reply_internal_error (connection,
+                                         
TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR,
+                                         "Merchant database error");
+    }
+    if (0 == qs)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "not paid yet\n");
+      goto do_pay;
+    }
+    GNUNET_break (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs);
+  }
+
+  return TMH_RESPONSE_reply_json_pack (connection,
+                                       MHD_HTTP_OK,
+                                       "{s:b}",
+                                       "paid",
+                                       1);
+
+do_pay:
+  {
+    char *url = make_absolute_backend_url (connection, "show-contract", 
"contract_url", contract_url, "session_id", session_id, NULL);
+    int ret = TMH_RESPONSE_reply_json_pack (connection,
+                                            MHD_HTTP_OK,
+                                            "{s:s}",
+                                            "payment_redirect_url",
+                                            url);
+    GNUNET_free (url);
+    return ret;
+  }
+}
diff --git a/src/backend/taler-merchant-httpd_check-payment.h 
b/src/backend/taler-merchant-httpd_check-payment.h
new file mode 100644
index 0000000..14c2a67
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_check-payment.h
@@ -0,0 +1,46 @@
+/*
+  This file is part of TALER
+  (C) 2017 Taler Systems SA
+
+  TALER is free software; you can redistribute it and/or modify it under the
+  terms of the GNU General Public License as published by the Free Software
+  Foundation; either version 3, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along with
+  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file backend/taler-merchant-httpd_tip-query.h
+ * @brief headers for /tip-query handler
+ * @author Christian Grothoff
+ * @author Florian Dold
+ */
+#ifndef TALER_MERCHANT_HTTPD_CHECK_PAYMENT_H
+#define TALER_MERCHANT_HTTPD_CHECK_PAYMENT_H
+#include <microhttpd.h>
+#include "taler-merchant-httpd.h"
+
+/**
+ * Manages a /check-payment call, checking the status
+ * of a payment and, if necessary, constructing the URL
+ * for a payment redirect URL.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+MH_handler_check_payment (struct TMH_RequestHandler *rh,
+                          struct MHD_Connection *connection,
+                          void **connection_cls,
+                          const char *upload_data,
+                          size_t *upload_data_size);
+
+#endif

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

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