summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2015-11-17 16:52:29 +0100
committerChristian Grothoff <christian@grothoff.org>2015-11-17 16:52:29 +0100
commita1de67c3e70ac52d65794ce3ae5228c11e42e3c1 (patch)
treec04ccc9fb78979d8f8da93efddf8513708bef198
parentf95cfd95547a96c2d398dc1032b2e6071185c848 (diff)
parent965cefde1f05541ac113ad37bc798d1e8f115293 (diff)
downloadmerchant-a1de67c3e70ac52d65794ce3ae5228c11e42e3c1.tar.gz
merchant-a1de67c3e70ac52d65794ce3ae5228c11e42e3c1.tar.bz2
merchant-a1de67c3e70ac52d65794ce3ae5228c11e42e3c1.zip
update documentation and logic for checkout page
-rw-r--r--src/backend/taler-merchant-httpd.c4
-rw-r--r--src/backend/taler-merchant-httpd_contract.c11
-rw-r--r--src/backend/taler-merchant-httpd_obsolete.c986
-rw-r--r--src/backend/taler-merchant-httpd_pay.c117
-rw-r--r--src/frontend/checkout.php17
-rw-r--r--src/frontend/pay.php3
-rw-r--r--src/include/merchant.h9
7 files changed, 92 insertions, 1055 deletions
diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c
index 9c1c2257..ba359bd1 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -289,7 +289,6 @@ keys_mgmt_cb (void *cls, const struct TALER_MINT_Keys *keys)
else
printf ("no keys gotten\n");
- printf ("cb: poller_task [%p]\n", poller_task);
}
@@ -391,7 +390,6 @@ context_task (void *cls,
ws,
&context_task,
cls);
- printf ("scheduling poller_task [%p]\n", poller_task);
GNUNET_NETWORK_fdset_destroy (rs);
GNUNET_NETWORK_fdset_destroy (ws);
}
@@ -417,7 +415,7 @@ handle_mhd_completion_callback (void *cls,
void **con_cls,
enum MHD_RequestTerminationCode toe)
{
- struct TM_HandlerContext *hc = *con_cls;
+ struct TM_HandlerContext *hc = *con_cls; /* 'hc' is also a 'struct PayContext' */
if (NULL == hc)
return;
diff --git a/src/backend/taler-merchant-httpd_contract.c b/src/backend/taler-merchant-httpd_contract.c
index e4b556a4..c42a8b37 100644
--- a/src/backend/taler-merchant-httpd_contract.c
+++ b/src/backend/taler-merchant-httpd_contract.c
@@ -35,15 +35,10 @@
#include "merchant_db.h"
#include "merchant.h"
#include "taler_merchant_lib.h"
+#include "taler-merchant-httpd.h"
-extern struct MERCHANT_Mint *mints;
extern struct MERCHANT_Auditor *auditors;
-extern struct GNUNET_CRYPTO_EddsaPrivateKey privkey;
-extern const struct MERCHANT_WIREFORMAT_Sepa *wire;
-extern unsigned int nmints;
extern unsigned int nauditors;
-extern PGconn *db_conn;
-extern long long salt;
/**
* Manage a contract request. In practical terms, it adds the fields 'mints',
@@ -148,7 +143,7 @@ MH_handler_contract (struct TMH_RequestHandler *rh,
"H_wire",
TALER_json_from_data (&h_wire, sizeof (h_wire)));
- GNUNET_CRYPTO_eddsa_key_get_public (&privkey, &pubkey);
+ GNUNET_CRYPTO_eddsa_key_get_public (privkey, &pubkey);
json_object_set_new (root,
"merchant_pub",
TALER_json_from_data (&pubkey, sizeof (pubkey)));
@@ -158,7 +153,7 @@ MH_handler_contract (struct TMH_RequestHandler *rh,
GNUNET_CRYPTO_hash (contract_str, strlen (contract_str), &contract.h_contract);
contract.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_CONTRACT);
contract.purpose.size = htonl (sizeof (contract));
- GNUNET_CRYPTO_eddsa_sign (&privkey, &contract.purpose, &contract_sig);
+ GNUNET_CRYPTO_eddsa_sign (privkey, &contract.purpose, &contract_sig);
return TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_OK,
diff --git a/src/backend/taler-merchant-httpd_obsolete.c b/src/backend/taler-merchant-httpd_obsolete.c
deleted file mode 100644
index a96dad59..00000000
--- a/src/backend/taler-merchant-httpd_obsolete.c
+++ /dev/null
@@ -1,986 +0,0 @@
-/*
- This file is part of TALER
- (C) 2014 Christian Grothoff (and other contributing authors)
-
- 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, If not, see <http://www.gnu.org/licenses/>
-*/
-
-/**
- * @file merchant/backend/taler-merchant-httpd.c
- * @brief HTTP serving layer mainly intended to communicate with the frontend
- * @author Marcello Stanisci
- */
-
-#include "platform.h"
-#include <microhttpd.h>
-#include <jansson.h>
-#include <gnunet/gnunet_util_lib.h>
-#include <curl/curl.h>
-#include <taler/taler_signatures.h>
-#include <taler/taler_json_lib.h>
-#include <taler/taler_mint_service.h>
-#include "taler-mint-httpd_parsing.h"
-#include "taler-mint-httpd_responses.h"
-#include "merchant_db.h"
-#include "merchant.h"
-#include "taler_merchant_lib.h"
-
-extern struct MERCHANT_WIREFORMAT_Sepa *
-TALER_MERCHANT_parse_wireformat_sepa (const struct GNUNET_CONFIGURATION_Handle *cfg);
-
-/**
- * Shorthand for exit jumps.
- */
-#define EXITIF(cond) \
- do { \
- if (cond) { GNUNET_break (0); goto EXITIF_exit; } \
- } while (0)
-
-/**
- * Our hostname
- */
-static char *hostname;
-
-/**
- * The port we are running on
- */
-static long long unsigned port;
-
-/**
- * Merchant's private key
- */
-struct GNUNET_CRYPTO_EddsaPrivateKey *privkey;
-
-/**
- * File holding the merchant's private key
- */
-char *keyfile;
-
-/**
- * The MHD Daemon
- */
-static struct MHD_Daemon *mhd;
-
-/**
- * Connection handle to the our database
- */
-PGconn *db_conn;
-
-/**
- * merchant's conf handle
- */
-struct GNUNET_CONFIGURATION_Handle *cfg;
-
-/**
- * Shutdown task identifier
- */
-static struct GNUNET_SCHEDULER_Task *shutdown_task;
-
-/**
- * Our wireformat
- */
-static struct MERCHANT_WIREFORMAT_Sepa *wire;
-
-/**
- * Should we do a dry run where temporary tables are used for storing the data.
- */
-static int dry;
-
-/**
- * Global return code
- */
-static int result;
-
-/**
- * Mint context
- */
-static struct TALER_MINT_Context *mctx;
-
-/**
- * Context information of the mints we trust
- */
-struct Mint
-{
- /**
- * Public key of this mint
- */
- struct GNUNET_CRYPTO_EddsaPublicKey pubkey;
-
- /**
- * Connection handle to this mint
- */
- struct TALER_MINT_Handle *conn;
-};
-
-/**
- * Hashmap to store the mint context information
- */
-static struct GNUNET_CONTAINER_MultiPeerMap *mints_map;
-
-/**
- * Hashmap (with 'big entries') to make a mint's base URL
- * to point to some mint-describing structure
- */
-static struct GNUNET_CONTAINER_MultiHashMap *mints_hashmap;
-
-/**
- * Mints' URL,port,key triples
- */
-struct MERCHANT_MintInfo *mint_infos;
-
-/**
- * The number of accepted mints
- */
-unsigned int nmints;
-
-struct Mint_Response
-{
- char *ptr;
- size_t size;
-
-};
-
-
-/**
- * Generate the 'hello world' response
- * @param connection a MHD connection
- * @param resp where to store the response for the calling function.
- * Note that in its original implementation this parameter was preceeded
- * by a '_'. Still not clear why.
- * @return HTTP status code reflecting the operation outcome
- *
- */
-static unsigned int
-generate_hello (struct MHD_Response **resp)
-{
-
- const char *hello = "Hello customer\n";
- unsigned int ret;
-
- *resp = MHD_create_response_from_buffer (strlen (hello), (void *) hello,
- MHD_RESPMEM_PERSISTENT);
- ret = 200;
- return ret;
-}
-
-/**
- * Return the given message to the other end of connection
- * @msg (0-terminated) message to show
- * @param connection a MHD connection
- * @param resp where to store the response for the calling function
- * @return HTTP status code reflecting the operation outcome
- *
- */
-static unsigned int
-generate_message (struct MHD_Response **resp, const char *msg)
-{
-
- unsigned int ret;
-
- *resp = MHD_create_response_from_buffer (strlen (msg), (void *) msg,
- MHD_RESPMEM_MUST_FREE);
- ret = 200;
- return ret;
-}
-
-/**
- * Callback to pass to curl used to store a HTTP response
- * in a custom memory location.
- * See http://curl.haxx.se/libcurl/c/getinmemory.html for a
- * detailed example
- *
- * @param contents the data gotten so far from the server
- * @param size symbolic (arbitrarily chosen by libcurl) unit
- * of bytes
- * @param nmemb factor to multiply by @a size to get the real
- * size of @a contents
- * @param userdata a pointer to a memory location which remains
- * the same across all the calls to this callback (i.e. it has
- * to be grown at each invocation of this callback)
- * @return number of written bytes
- * See http://curl.haxx.se/libcurl/c/CURLOPT_WRITEFUNCTION.html
- * for official documentation
- *
- */
-size_t
-get_response_in_memory (char *contents,
- size_t size,
- size_t nmemb,
- void *userdata)
-{
- struct Mint_Response *mr;
- size_t realsize;
-
- realsize = size * nmemb;
- mr = userdata;
- mr->ptr = realloc (mr->ptr, mr->size + realsize + 1);
-
- if (mr->ptr == NULL) {
- printf ("Out of memory, could not get in memory mint's"
- "response");
- return 0;
- }
- memcpy(&(mr->ptr[mr->size]), contents, realsize);
- mr->size += realsize;
- mr->ptr[mr->size] = 0;
-
- return realsize;
-
-}
-
-#ifdef PANIC_MGMT
-/**
- * Callback for catching serious error conditions from MHD.
- *
- * @param cls user specified value
- * @param file where the error occured
- * @param line where the error occured
- * @param reason error detail, may be NULL
- */
-static void
-mhd_panic_cb (void *cls,
- const char *file,
- unsigned int line,
- const char *reason)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "MHD panicked at %s:%u: %s",
- file, line, reason);
- result = GNUNET_SYSERR;
- GNUNET_SCHEDULER_shutdown ();
-}
-#endif
-
-/**
- * Manage a non 200 HTTP status. I.e. it shows a 'failure' page to
- * the client
- * @param connection the channel thorugh which send the message
- * @status the HTTP status to examine
- * @return GNUNET_OK on successful message sending, GNUNET_SYSERR upon error
- */
-static int
-failure_resp (struct MHD_Connection *connection, unsigned int status)
-{
- static char page_MHD_HTTP_NOT_FOUND[]="\
-<!DOCTYPE html> \
-<html><title>Resource not found</title><body><center> \
-<h3>The resource you are looking for is not found.</h3> \
-</center></body></html>";
- static char page_MHD_HTTP_BAD_REQUEST[]="\
-<!DOCTYPE html> \
-<html><title>Bad request</title><body><center> \
-<h3>Malformed POSTed JSON.</h3> \
-</center></body></html>";
-static char page_MHD_HTTP_METHOD_NOT_ALLOWED[]="\
-<!DOCTYPE html> \
-<html><title>Method NOT allowed</title><body><center> \
-<h3>ONLY POSTs are allowed.</h3> \
-</center></body></html>";
- static char page_MHD_HTTP_INTERNAL_SERVER_ERROR[]="\
-<!DOCTYPE html> <html><title>Internal Server Error</title><body><center> \
-<h3>The server experienced an internal error and hence cannot serve your \
-request</h3></center></body></html>";
- struct MHD_Response *resp;
- char *page;
- size_t size;
-#define PAGE(number) \
- do {page=page_ ## number; size=sizeof(page_ ## number)-1;} while(0)
-
- GNUNET_assert (MHD_HTTP_BAD_REQUEST <= status);
- resp = NULL;
- switch (status)
- {
- case MHD_HTTP_NOT_FOUND :
- PAGE(MHD_HTTP_NOT_FOUND);
- break;
- case MHD_HTTP_BAD_REQUEST:
- PAGE(MHD_HTTP_BAD_REQUEST);
- break;
- case MHD_HTTP_METHOD_NOT_ALLOWED:
- PAGE(MHD_HTTP_METHOD_NOT_ALLOWED);
- break;
- default:
- status = MHD_HTTP_INTERNAL_SERVER_ERROR;
- case MHD_HTTP_INTERNAL_SERVER_ERROR:
- PAGE(MHD_HTTP_INTERNAL_SERVER_ERROR);
- }
-#undef PAGE
-
- EXITIF (NULL == (resp = MHD_create_response_from_buffer (size,
- page,
- MHD_RESPMEM_PERSISTENT)));
- EXITIF (MHD_YES != MHD_queue_response (connection, status, resp));
- MHD_destroy_response (resp);
- return GNUNET_OK;
-
- EXITIF_exit:
- if (NULL != resp)
- MHD_destroy_response (resp);
- return GNUNET_SYSERR;
-}
-
-
-/**
- * A client has requested the given url using the given method
- * (#MHD_HTTP_METHOD_GET, #MHD_HTTP_METHOD_PUT,
- * #MHD_HTTP_METHOD_DELETE, #MHD_HTTP_METHOD_POST, etc). The callback
- * must call MHD callbacks to provide content to give back to the
- * client and return an HTTP status code (i.e. #MHD_HTTP_OK,
- * #MHD_HTTP_NOT_FOUND, etc.).
- *
- * @param cls argument given together with the function
- * pointer when the handler was registered with MHD
- * @param url the requested url
- * @param method the HTTP method used (#MHD_HTTP_METHOD_GET,
- * #MHD_HTTP_METHOD_PUT, etc.)
- * @param version the HTTP version string (i.e.
- * #MHD_HTTP_VERSION_1_1)
- * @param upload_data the data being uploaded (excluding HEADERS,
- * for a POST that fits into memory and that is encoded
- * with a supported encoding, the POST data will NOT be
- * given in upload_data and is instead available as
- * part of #MHD_get_connection_values; very large POST
- * data *will* be made available incrementally in
- * @a upload_data)
- * @param upload_data_size set initially to the size of the
- * @a upload_data provided; the method must update this
- * value to the number of bytes NOT processed;
- * @param con_cls pointer that the callback can set to some
- * address and that will be preserved by MHD for future
- * calls for this request; since the access handler may
- * be called many times (i.e., for a PUT/POST operation
- * with plenty of upload data) this allows the application
- * to easily associate some request-specific state.
- * If necessary, this state can be cleaned up in the
- * global #MHD_RequestCompletedCallback (which
- * can be set with the #MHD_OPTION_NOTIFY_COMPLETED).
- * Initially, `*con_cls` will be NULL.
- * @return #MHD_YES if the connection was handled successfully,
- * #MHD_NO if the socket must be closed due to a serios
- * error while handling the request
- */
-static int
-url_handler (void *cls,
- struct MHD_Connection *connection,
- const char *url,
- const char *method,
- const char *version,
- const char *upload_data,
- size_t *upload_data_size,
- void **connection_cls)
-{
-
- /*printf ("%s\n", url);*/
- unsigned long status;
- unsigned int no_destroy;
- struct GNUNET_CRYPTO_EddsaSignature c_sig;
- struct GNUNET_CRYPTO_EddsaSignature deposit_confirm_sig;
- struct GNUNET_CRYPTO_EddsaPublicKey pub;
- #ifdef OBSOLETE
- struct ContractNBO contract;
- #else
- struct Contract contract;
- #endif
- struct MHD_Response *resp;
- json_t *root;
- json_t *j_sig_enc;
- json_t *j_h_contract;
- json_t *j_tmp;
- json_t *eddsa_pub_enc;
- json_t *response;
- json_t *j_mints;
- json_t *j_mint;
- json_t *j_wire;
- int cnt; /* loop counter */
- char *deposit_body;
- json_t *j_contract_add;
- struct GNUNET_TIME_Absolute now;
- struct GNUNET_TIME_Absolute expiry;
- struct GNUNET_TIME_Absolute edate;
- struct GNUNET_TIME_Absolute refund;
- struct GNUNET_HashCode h_json_wire;
- json_t *j_h_json_wire;
- struct curl_slist *slist;
- char *contract_str;
- struct GNUNET_HashCode h_contract_str;
- struct MERCHANT_contract_handle ch;
- struct TALER_MintPublicKeyP mint_pub;
- uint64_t nounce;
-
- CURL *curl;
- CURLcode curl_res;
-
- uint32_t res = GNUNET_SYSERR;
-
- #define URL_HELLO "/hello"
- #define URL_CONTRACT "/contract"
- #define URL_PAY "/pay"
- no_destroy = 0;
- resp = NULL;
- status = MHD_HTTP_INTERNAL_SERVER_ERROR;
-
- if (0 == strncasecmp (url, URL_HELLO, sizeof (URL_HELLO)))
- {
- if (0 == strcmp (MHD_HTTP_METHOD_GET, method))
- status = generate_hello (&resp);
- else
- {
- status = MHD_HTTP_METHOD_NOT_ALLOWED;
- }
- }
-
- if (0 == strncasecmp (url, URL_PAY, sizeof (URL_PAY)))
- {
- if (0 == strcmp (MHD_HTTP_METHOD_GET, method))
- {
- status = MHD_HTTP_METHOD_NOT_ALLOWED;
- goto end;
-
- }
- else
- res = TMH_PARSE_post_json (connection,
- connection_cls,
- upload_data,
- upload_data_size,
- &root);
- if (GNUNET_SYSERR == res)
- {
- status = MHD_HTTP_BAD_REQUEST;
- goto end;
- }
-
- /* the POST's body has to be further fetched */
- if ((GNUNET_NO == res) || (NULL == root))
- return MHD_YES;
-
- /* Firstly, check if the wallet is paying against an approved
- mint */
- json_t *j_chosen_mint;
- j_chosen_mint = json_object_get (root, "mint");
- struct GNUNET_HashCode hash_key;
- char *chosen_mint;
-
- chosen_mint = json_string_value (j_chosen_mint);
- GNUNET_CRYPTO_hash (chosen_mint, strlen (chosen_mint), &hash_key);
-
- if (NULL ==
- GNUNET_CONTAINER_multihashmap_get (mints_hashmap, &hash_key))
- {
- printf ("Untrusted mint\n");
- status = MHD_HTTP_FORBIDDEN;
- goto end;
-
- }
-
- /* NOTE: from now on, the mint's base URL is pointed by 'chosen_mint' */
-
- /* The merchant will only add its 'wire' object to the JSON
- it got from the wallet */
-
- /* Get this dep. perm.'s H_contract */
-
- if (NULL == (j_h_contract = json_object_get (root, "H_contract")))
- {
- printf ("H_contract field missing\n");
- status = MHD_HTTP_INTERNAL_SERVER_ERROR;
- goto end;
- }
- TALER_json_to_data (j_h_contract, &h_contract_str, sizeof (struct GNUNET_HashCode));
-
- nounce = 0;
- edate.abs_value_us = 0;
-
- if (GNUNET_SYSERR ==
- MERCHANT_DB_get_contract_values (db_conn,
- &h_contract_str,
- &nounce,
- &edate))
- {
- printf ("not existing contract\n");
- status = MHD_HTTP_INTERNAL_SERVER_ERROR;
- goto end;
- }
-
- /* Reproducing the wire object */
- if (NULL == (j_wire = MERCHANT_get_wire_json (wire,
- nounce,
- edate)))
-
- {
- printf ("wire object not reproduced\n");
- status = MHD_HTTP_INTERNAL_SERVER_ERROR;
- goto end;
- }
-
- if (-1 == json_object_set (root, "wire", j_wire))
- {
- printf ("depperm not augmented\n");
- status = MHD_HTTP_INTERNAL_SERVER_ERROR;
- goto end;
- }
-
- /* POST to mint's "/deposit" */
- curl = curl_easy_init ();
-
- struct Mint_Response mr;
- mr.ptr = malloc(1);
- mr.size = 0;
-
- if (curl)
- {
-
- char deposit_url[strlen (chosen_mint) + strlen ("http://") + strlen ("/deposit") + 1];
- sprintf (deposit_url, "http://%s/deposit", chosen_mint);
- slist = curl_slist_append (slist, "Content-type: application/json");
- curl_easy_setopt (curl, CURLOPT_HTTPHEADER, slist);
-
- curl_easy_setopt (curl, CURLOPT_URL, deposit_url);
- curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, get_response_in_memory);
- curl_easy_setopt (curl, CURLOPT_WRITEDATA, (void *) &mr);
-
- /* NOTE: hopefully, this string won't need any URL-encoding, since as for the
- Jansson specs, any space and-or newline are not in place using JSON_COMPACT
- flag */
- deposit_body = json_dumps (root, JSON_COMPACT | JSON_PRESERVE_ORDER);
- curl_easy_setopt(curl, CURLOPT_POSTFIELDS, deposit_body);
-
- curl_res = curl_easy_perform (curl);
-
- curl_slist_free_all(slist);
- if(curl_res != CURLE_OK)
- {
- printf ("deposit not sent\n");
- goto end;
- }
- else
- printf ("\ndeposit request issued\n");
-
- curl_easy_cleanup(curl);
-
- curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &status);
-
- /* If the request was successful, the deposit confirmation
- has to be verified*/
-
- if (MHD_HTTP_OK != result)
- /* Jump here to error mgmt, see issue #3800 (TODO) */
-
- if (GNUNET_SYSERR ==
- MERCHANT_DB_get_contract_handle (db_conn, &h_contract_str, &ch))
- {
- status = MHD_HTTP_INTERNAL_SERVER_ERROR;
- goto end;
- }
-
- root = json_loads (mr.ptr, 0, NULL);
- j_tmp = json_object_get (root, "sig");
- TALER_json_to_data (j_tmp,
- &deposit_confirm_sig,
- sizeof (struct GNUNET_CRYPTO_EddsaSignature));
- j_tmp = json_object_get (root, "pub");
-
- TALER_json_to_data (j_tmp,
- &mint_pub.eddsa_pub,
- sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
-
- GNUNET_CRYPTO_eddsa_key_get_public (privkey, &pub);
-
-
- /* The following check could be done once the merchant is able to
- retrieve the deposit fee for each coin it gets a payment with.
- That happens because the signature made on a deposit confirmation
- uses, among its values of interest, the subtraction of the deposit
- fee from the used coin. That fee is never communicated by the wallet
- to the merchant, so the only way for the merchant to get this
- information is to fetch all the mint's keys, namely it needs to
- invoke "/keys", and store what gotten in its DB */
-
- #ifdef DENOMMGMT
- if (GNUNET_NO ==
- MERCHANT_verify_confirmation (&h_contract_str,
- &h_json_wire,
- ch.timestamp,
- ch.refund_deadline,
- ch.contract_id,
- amount_minus_fee, /* MISSING */
- coin_pub, /* MISSING */
- &pub,
- &deposit_confirm_sig,
- &mint_pub))
- {
- status = MHD_HTTP_INTERNAL_SERVER_ERROR;
- goto end;
-
- }
-
- #endif
-
- /* Place here the successful message to issue to the frontend */
- status = MHD_HTTP_OK;
- generate_message (&resp, "fullfillment page here");
- GNUNET_free (mr.ptr);
-
- }
-
-
- }
-
- /*
- * To be called by the frontend passing the contract with some "holes"
- * which will be completed, stored in DB, signed, and returned
- *
- */
-
- if (0 == strncasecmp (url, URL_CONTRACT, sizeof (URL_CONTRACT)))
- {
- if (0 == strcmp (MHD_HTTP_METHOD_GET, method))
- {
- status = MHD_HTTP_METHOD_NOT_ALLOWED;
- goto end;
-
- }
- else
- res = TMH_PARSE_post_json (connection,
- connection_cls,
- upload_data,
- upload_data_size,
- &root);
- if (GNUNET_SYSERR == res)
- {
- status = MHD_HTTP_BAD_REQUEST;
- goto end;
- }
-
-
- /* the POST's body has to be fetched furthermore */
- if ((GNUNET_NO == res) || (NULL == root))
- return MHD_YES;
-
- j_mints = json_array ();
- for (cnt = 0; cnt < nmints; cnt++)
- {
- j_mint = json_pack ("{s:s}",
- mint_infos[cnt].hostname,
- GNUNET_CRYPTO_eddsa_public_key_to_string (&mint_infos[cnt].pubkey));
- json_array_append_new (j_mints, j_mint);
-
- }
-
- /* timestamp */
- now = GNUNET_TIME_absolute_get ();
- /* expiry */
- expiry = GNUNET_TIME_absolute_add (now, GNUNET_TIME_UNIT_WEEKS);
- /* edate, note: this value must be generated now (and not when the
- wallet sends back a deposit permission because the hashed 'wire' object,
- which carries this values in it, has to be included in the signed bundle
- by the wallet) */
- edate = GNUNET_TIME_absolute_add (now, GNUNET_TIME_UNIT_WEEKS);
- refund = GNUNET_TIME_absolute_add (now, GNUNET_TIME_UNIT_WEEKS);
-
- TALER_round_abs_time (&now);
- TALER_round_abs_time (&expiry);
- TALER_round_abs_time (&edate);
- TALER_round_abs_time (&refund);
-
- /* getting the SEPA-aware JSON */
- /* nounce for hashing the wire object */
- nounce = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX);
-
- /* get wire object */
-
- if (NULL == (j_wire = MERCHANT_get_wire_json (wire,
- nounce,
- edate)))
- {
- status = MHD_HTTP_INTERNAL_SERVER_ERROR;
- goto end;
- }
-
- /* hash wire objcet */
- if (GNUNET_SYSERR == TALER_hash_json (j_wire, &h_json_wire))
- goto end;
-
- j_h_json_wire = TALER_json_from_data ((void *) &h_json_wire, sizeof (struct GNUNET_HashCode));
-
- GNUNET_CRYPTO_eddsa_key_get_public (privkey, &pub);
- eddsa_pub_enc = TALER_json_from_data ((void *) &pub, sizeof (pub));
-
- if (NULL == (j_contract_add = json_pack ("{s:s, s:s, s:o, s:o, s:o}",
- "merchant_pub", json_string_value (eddsa_pub_enc),
- "H_wire", json_string_value (j_h_json_wire),
- "timestamp", TALER_json_from_abs (now),
- "refund", TALER_json_from_abs (refund),
- "mints", j_mints)))
- {
- printf ("BAD contract enhancement\n");
- goto end;
- }
-
- /* melt to what received from the wallet */
- if (-1 == json_object_update (root, j_contract_add))
- {
- printf ("depperm response not built\n");
- goto end;
- }
-
- res = MERCHANT_handle_contract (root,
- db_conn,
- &contract,
- now,
- expiry,
- edate,
- refund,
- &contract_str,
- nounce);
- if (GNUNET_SYSERR == res)
- {
- status = MHD_HTTP_INTERNAL_SERVER_ERROR;
- goto end;
- }
- if (GNUNET_NO == res)
- {
- status = MHD_HTTP_METHOD_NOT_ACCEPTABLE;
- goto end;
- }
-
- GNUNET_CRYPTO_eddsa_sign (privkey, &contract.purpose, &c_sig);
- GNUNET_CRYPTO_hash (contract_str, strlen (contract_str) + 1, &h_contract_str);
-
- j_sig_enc = TALER_json_from_eddsa_sig (&contract.purpose, &c_sig);
-
- response = json_pack ("{s:o, s:o, s:o}",
- "contract", root,
- "sig", j_sig_enc,
- "h_contract",
- TALER_json_from_data ((void *) &h_contract_str, sizeof (struct GNUNET_HashCode)));
-
- GNUNET_free (contract_str);
-
- TMH_RESPONSE_reply_json (connection, response, MHD_HTTP_OK);
- return MHD_YES;
-
- }
-
- end:
-
- if (NULL != resp)
- {
- EXITIF (MHD_YES != MHD_queue_response (connection, status, resp));
- return MHD_YES;
- if (!no_destroy)
- MHD_destroy_response (resp);
- }
- else
- {
-
- EXITIF (GNUNET_OK != failure_resp (connection, status));
- return MHD_YES;
-
- }
-
- EXITIF_exit:
- result = GNUNET_SYSERR;
- GNUNET_SCHEDULER_shutdown ();
- return MHD_NO;
-}
-
-/**
- * Shutdown task (magically invoked when the application is being
- * quit)
- *
- * @param cls NULL
- * @param tc scheduler task context
- */
-static void
-do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
-
- if (NULL != mhd)
- {
- MHD_stop_daemon (mhd);
- mhd = NULL;
- }
-
- if (NULL != db_conn)
- {
- MERCHANT_DB_disconnect (db_conn);
- db_conn = NULL;
- }
- if (keyfile != NULL)
- GNUNET_free (privkey);
-
-
-}
-
-/**
- * Function called with information about who is auditing
- * a particular mint and what key the mint is using.
- *
- * @param cls closure
- * @param keys information about the various keys used
- * by the mint
- */
-static void
-keys_mgmt_cb (void *cls, const struct TALER_MINT_Keys *keys)
-{
- /* which kind of mint's keys a merchant should need? Sign
- keys? It has already the mint's master key from the conf file */
-
- /* HOT UPDATE: the merchants needs the denomination keys!
- Because it wants to (firstly) verify the deposit confirmation
- sent by the mint, and the signed blob depends (among the
- other things) on the coin's deposit fee. That information
- is never communicated by the wallet to the merchant.
- Again, the merchant needs it because it wants to verify that
- the wallet didn't exceede the limit imposed by the merchant
- on the total deposit fee for a purchase */
-
-
- return;
-
-}
-
-/**
- * Main function that will be run by the scheduler.
- *
- * @param cls closure
- * @param args remaining command-line arguments
- * @param cfgfile name of the configuration file used (for saving, can be NULL!)
- * @param config configuration
- */
-void
-run (void *cls, char *const *args, const char *cfgfile,
- const struct GNUNET_CONFIGURATION_Handle *config)
-{
-
- unsigned int cnt;
- void *keys_mgmt_cls;
-
- keys_mgmt_cls = NULL;
- mint_infos = NULL;
- keyfile = NULL;
- result = GNUNET_SYSERR;
- shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
- &do_shutdown, NULL);
- EXITIF (GNUNET_SYSERR == (nmints = TALER_MERCHANT_parse_mints (config,
- &mint_infos)));
- EXITIF (NULL == (wire = TALER_MERCHANT_parse_wireformat_sepa (config)));
- EXITIF (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (config,
- "merchant",
- "KEYFILE",
- &keyfile));
- EXITIF (NULL == (privkey = GNUNET_CRYPTO_eddsa_key_create_from_file (keyfile)));
- EXITIF (NULL == (db_conn = MERCHANT_DB_connect (config)));
- EXITIF (GNUNET_OK != MERCHANT_DB_initialize (db_conn, GNUNET_YES));
- EXITIF (GNUNET_SYSERR ==
- GNUNET_CONFIGURATION_get_value_number (config,
- "merchant",
- "port",
- &port));
- EXITIF (GNUNET_SYSERR ==
- GNUNET_CONFIGURATION_get_value_string (config,
- "merchant",
- "hostname",
- &hostname));
-
- EXITIF (NULL == (mctx = TALER_MINT_init ()));
- /* Still not used */
- EXITIF (NULL == (mints_map = GNUNET_CONTAINER_multipeermap_create (nmints, GNUNET_YES)));
- /* Used when the wallet points out which mint it want to deal with.
- That indication is made through the mint's base URL, which will be
- the hash-key for this table */
- EXITIF (NULL == (mints_hashmap = GNUNET_CONTAINER_multihashmap_create (nmints, GNUNET_NO)));
-
- for (cnt = 0; cnt < nmints; cnt++)
- {
- struct Mint *mint;
- struct GNUNET_HashCode mint_key;
-
- mint = GNUNET_new (struct Mint);
- mint->pubkey = mint_infos[cnt].pubkey;
- /* port this to the new API */
- mint->conn = TALER_MINT_connect (mctx,
- mint_infos[cnt].hostname,
- &keys_mgmt_cb,
- keys_mgmt_cls); /*<- safe?segfault friendly?*/
-
- /* NOTE: the keys mgmt callback should roughly do what the following lines do */
- EXITIF (NULL == mint->conn);
-
- EXITIF (GNUNET_SYSERR == GNUNET_CONTAINER_multipeermap_put
- (mints_map,
- (struct GNUNET_PeerIdentity *) /* to retrieve now from cb's args -> */&mint->pubkey,
- mint,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
-
- /* 1 create hash key
- 2 create big entry
- 3 put
- */
- GNUNET_CRYPTO_hash (mint_infos[cnt].hostname,
- strlen (mint_infos[cnt].hostname),
- &mint_key);
- GNUNET_CONTAINER_multihashmap_put (mints_hashmap,
- &mint_key,
- &mint_infos[cnt],
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
- }
-
- mhd = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY,
- port,
- NULL, NULL,
- &url_handler, NULL,
- MHD_OPTION_END);
-
- EXITIF (NULL == mhd);
-
- /* WARNING: a 'poll_mhd ()' call is here in the original merchant. Is that
- mandatory ? */
- result = GNUNET_OK;
-
- EXITIF_exit:
- if (GNUNET_OK != result)
- GNUNET_SCHEDULER_shutdown ();
- GNUNET_free_non_null (keyfile);
- if (GNUNET_OK != result)
- GNUNET_SCHEDULER_shutdown ();
-
-}
-
-/**
- * The main function of the serve tool
- *
- * @param argc number of arguments from the command line
- * @param argv command line arguments
- * @return 0 ok, 1 on error
- */
-int
-main (int argc, char *const *argv)
-{
-
- static const struct GNUNET_GETOPT_CommandLineOption options[] = {
- {'t', "temp", NULL,
- gettext_noop ("Use temporary database tables"), GNUNET_NO,
- &GNUNET_GETOPT_set_one, &dry},
- GNUNET_GETOPT_OPTION_END
- };
-
-
- if (GNUNET_OK !=
- GNUNET_PROGRAM_run (argc, argv,
- "taler-merchant-serve",
- "Serve merchant's HTTP interface",
- options, &run, NULL))
- return 3;
- return (GNUNET_OK == result) ? 0 : 1;
-
-}
diff --git a/src/backend/taler-merchant-httpd_pay.c b/src/backend/taler-merchant-httpd_pay.c
index 4644354f..7b524b6a 100644
--- a/src/backend/taler-merchant-httpd_pay.c
+++ b/src/backend/taler-merchant-httpd_pay.c
@@ -73,11 +73,6 @@ deposit_fee_from_coin_aggregate (struct MHD_Connection *connection,
if (GNUNET_OK != res)
return res; /* may return GNUNET_NO */
- /*printf ("mint %s (%d), pends: %d\n",
- mints[mint_index].hostname,
- mint_index,
- mints[mint_index].pending);*/
-
if (1 == mints[mint_index].pending)
return GNUNET_SYSERR;
keys = TALER_MINT_get_keys (mints[mint_index].conn);
@@ -133,11 +128,6 @@ struct PayContext
uint64_t transaction_id;
/**
- * Offset of this coin into the array of all coins outcomes
- */
- unsigned int index;
-
- /**
* How many coins this paymen is made of.
*/
unsigned int coins_cnt;
@@ -151,6 +141,25 @@ struct PayContext
};
+/**
+ * Information needed by a single /deposit callback to refer to its
+ * own coin inside the confirmations array, namely `struct MERCHANT_DepositConfirmation *dc`
+ * above. Note: this information can NOT be shared between all the callbacks.
+ */
+struct DepositCallbackContext
+{
+
+ /**
+ * Offset of this coin into the array of all coins outcomes
+ */
+ unsigned int index;
+
+ /**
+ * Reference to the main PayContext
+ */
+ struct PayContext *pc;
+
+};
/**
* Callback to handle a deposit permission's response.
@@ -169,50 +178,40 @@ deposit_cb (void *cls,
unsigned int http_status,
json_t *proof)
{
- struct PayContext *pc = cls;
- /* NOTE: what if the mint doesn't respond? Does this callback get
- called? */
+ struct DepositCallbackContext *dcc = cls;
int i;
- printf ("deposit cb\n");
+ /*FIXME the index is the same for every individual cb */
if (GNUNET_SYSERR ==
MERCHANT_DB_update_deposit_permission (db_conn,
- pc->transaction_id,
+ dcc->pc->transaction_id,
0))
/* TODO */
printf ("db error\n");
- printf ("/deposit ack'd\n");
- pc->dc[pc->index].ackd = 1;
- pc->dc[pc->index].exit_status = http_status;
- pc->dc[pc->index].proof = proof;
+ dcc->pc->dc[dcc->index].ackd = 1;
+ dcc->pc->dc[dcc->index].exit_status = http_status;
+ dcc->pc->dc[dcc->index].proof = proof;
/* loop through the confirmation array and return accordingly */
- for (i = 0; i < pc->coins_cnt; i++)
+ for (i = 0; i < dcc->pc->coins_cnt; i++)
{
/* just return if there is at least one coin to be still
confirmed */
- if (! pc->dc[i].ackd)
+ if (! dcc->pc->dc[i].ackd)
{
printf ("still vacant coins\n");
return;
}
}
- /* Clean up what we can already */
- GNUNET_free (pc->dc);
- pc->dc = NULL;
-
+
printf ("All /deposit(s) ack'd\n");
- pc->response = NULL; /* FIXME; */
- /*
- i = TMH_RESPONSE_reply_json_pack (pc->connection,
- MHD_HTTP_OK,
- "{s:s}",
- "result", "all conins ack'd (and connection resumed)");
- printf ("mhd res %d\n", i);
- */
-
- pc->response_code = MHD_HTTP_OK;
- MHD_resume_connection (pc->connection);
+
+ dcc->pc->response = MHD_create_response_from_buffer (strlen ("All coins ack'd by the mint\n"),
+ "All coins ack'd by the mint\n",
+ MHD_RESPMEM_MUST_COPY);
+ dcc->pc->response_code = MHD_HTTP_OK;
+ /* Clean up what we can already */
+ MHD_resume_connection (dcc->pc->connection);
TM_trigger_daemon (); /* we resumed, kick MHD */
}
@@ -220,14 +219,25 @@ deposit_cb (void *cls,
static void
pay_context_cleanup (struct TM_HandlerContext *hc)
{
+ int i;
struct PayContext *pc = (struct PayContext *) hc;
+ for (i = 0; i < pc->coins_cnt; i++)
+ GNUNET_free_non_null (pc->dc[i].dcc);
+
TMH_PARSE_post_cleanup_callback (pc->json_parse_context);
+
+ #if 0
if (NULL != pc->response)
{
+ /* undestroyable regardless of the other MHD_destroy_response called
+ in this source, FIXME */
+
MHD_destroy_response (pc->response);
pc->response = NULL;
}
+ #endif
+
GNUNET_free_non_null (pc->dc);
GNUNET_free (pc);
}
@@ -299,7 +309,7 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
TMH_PARSE_MEMBER_END
};
- if (NULL == connection_cls)
+ if (NULL == *connection_cls)
{
pc = GNUNET_new (struct PayContext);
pc->hc.cc = &pay_context_cleanup;
@@ -311,7 +321,6 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
/* not the first call, recover state */
pc = *connection_cls;
}
-
if (0 != pc->response_code)
{
if (UINT_MAX == pc->response_code)
@@ -320,13 +329,20 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
res = MHD_queue_response (connection,
pc->response_code,
pc->response);
- MHD_destroy_response (pc->response);
- pc->response = NULL;
+ #if 0
+ if (pc->response != NULL)
+ {
+ /* undestroyable regardless of the other MHD_destroy_response called
+ in this source, FIXME */
+ MHD_destroy_response (pc->response);
+ pc->response = NULL;
+ }
+ #endif
return res;
}
res = TMH_PARSE_post_json (connection,
- connection_cls,
+ &pc->json_parse_context,
upload_data,
upload_data_size,
&root);
@@ -453,6 +469,11 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
That last cb will finally resume the connection and send back a response */
MHD_suspend_connection (connection);
+ pc->dc = dc;
+ pc->coins_cnt = coins_cnt;
+ pc->transaction_id = transaction_id;
+
+
json_array_foreach (coins, coins_index, coin_aggregate)
{
@@ -483,10 +504,11 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
if (GNUNET_OK != res)
return res; /* may return GNUNET_NO */
- pc->index = coins_index;
- pc->dc = dc;
- pc->coins_cnt = coins_cnt;
- pc->transaction_id = transaction_id;
+ /* c */
+ struct DepositCallbackContext *percoin_dcc = GNUNET_new (struct DepositCallbackContext);
+ pc->dc[coins_index].dcc = percoin_dcc;
+ percoin_dcc->index = coins_index;
+ percoin_dcc->pc = pc;
dh = TALER_MINT_deposit (mints[mint_index].conn,
&amount,
@@ -502,7 +524,9 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
refund_deadline,
&coin_sig,
&deposit_cb,
- pc); /*may be destroyed by the time the cb gets called..*/
+ percoin_dcc); /*FIXME TODO instantiate an individual cls for each
+ cb: each of them needs an index which points the
+ array of all the confirmations */
if (NULL == dh)
{
MHD_resume_connection (connection);
@@ -514,7 +538,6 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
}
}
- printf ("poller task: %p\n", poller_task);
GNUNET_SCHEDULER_cancel (poller_task);
GNUNET_SCHEDULER_add_now (context_task, mints[mint_index].ctx);
return MHD_YES;
diff --git a/src/frontend/checkout.php b/src/frontend/checkout.php
index b152fc65..157bd25f 100644
--- a/src/frontend/checkout.php
+++ b/src/frontend/checkout.php
@@ -29,7 +29,7 @@
*/
</script>
</head>
-<body onload="signal_me()">
+<body onload="signal_taler_wallet_onload()">
<!--
This page's main aim is to show to the customer all the accepted
payments methods and actually implementing just Taler; technically
@@ -204,8 +204,11 @@ function taler_wallet_unload_cb(aEvent)
/* The merchant signals its taler-friendlyness to the wallet,
- thereby causing the wallet to make itself more visible in the menu. */
-function signal_me()
+ thereby causing the wallet to make itself more visible in the menu.
+ This function should be called both when the page is loaded
+ (i.e. via body's onload) and when we receive a "taler-load" signal
+ (as the extension may be loaded/enabled after the page was loaded) */
+function signal_taler_wallet_onload()
{
var eve = new Event('taler-checkout-probe');
document.body.dispatchEvent(eve);
@@ -221,7 +224,7 @@ function test_without_wallet(){
};
-// /////////////// Main logic run on load ////////////////////////
+// /////////////// Main logic run first ////////////////////////
// Register event to be triggered by the wallet as a response to our
// first event
@@ -229,14 +232,10 @@ document.body.addEventListener("taler-wallet-present",
has_taler_wallet_cb,
false);
-// event awaited by the wallet to change its button's color
-// var eve = new Event('taler-payment-mfirst');
-// document.body.dispatchEvent(eve);
-
// Register event to be triggered by the wallet when it gets enabled while
// the user is on the payment page
document.body.addEventListener("taler-load",
- signal_me,
+ signal_taler_wallet_onload,
false);
// Register event to be triggered by the wallet when it is unloaded
diff --git a/src/frontend/pay.php b/src/frontend/pay.php
index 33f3b712..946cb160 100644
--- a/src/frontend/pay.php
+++ b/src/frontend/pay.php
@@ -92,7 +92,8 @@ if ($status_code != 200)
}
else
{
- echo "Payment succedeed!\n";
+ echo $resp->body->toString ();
+ //echo "Payment succeeded!\n";
}
?>
diff --git a/src/include/merchant.h b/src/include/merchant.h
index 582c4cf1..eb430360 100644
--- a/src/include/merchant.h
+++ b/src/include/merchant.h
@@ -41,11 +41,18 @@
} while (0)
/**
- * Outcome of a /deposit request for a coin
+ * Outcome of a /deposit request for a coin. Typically forming an array enclosed
+ * into the unique PayContext
*/
struct MERCHANT_DepositConfirmation
{
/**
+ * Reference to the per-deposit-handler Context. Needed by the
+ * cleanup function to get it freed
+ */
+ struct DepositCallbackContext *dcc;
+
+ /**
* True if this coin's outcome has been read from
* its cb
*/