summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2017-02-12 02:55:12 +0100
committerFlorian Dold <florian.dold@gmail.com>2017-02-12 02:55:12 +0100
commit053798e564dcaf640e26208078293268362b9dcc (patch)
tree2fbac76397285bfa714d12890511503351fa3f64 /src
parent5b1d9c51f78a827b80fc8ad7e737ac98d02b06bb (diff)
downloadmerchant-053798e564dcaf640e26208078293268362b9dcc.tar.gz
merchant-053798e564dcaf640e26208078293268362b9dcc.tar.bz2
merchant-053798e564dcaf640e26208078293268362b9dcc.zip
Change '/pay' API according to #4891
Diffstat (limited to 'src')
-rw-r--r--src/backend/taler-merchant-httpd_pay.c523
-rw-r--r--src/backend/taler-merchant-httpd_proposal.c2
-rw-r--r--src/include/taler_merchant_service.h12
-rw-r--r--src/lib/merchant_api_pay.c158
-rw-r--r--src/lib/test_merchant_api.c1
5 files changed, 316 insertions, 380 deletions
diff --git a/src/backend/taler-merchant-httpd_pay.c b/src/backend/taler-merchant-httpd_pay.c
index 052d2aa9..89039edb 100644
--- a/src/backend/taler-merchant-httpd_pay.c
+++ b/src/backend/taler-merchant-httpd_pay.c
@@ -38,11 +38,6 @@
*/
#define PAY_TIMEOUT (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30))
-/**
- * The instance which is working this request
- */
-struct MerchantInstance *mi;
-
/**
* Information we keep for an individual call to the /pay handler.
@@ -247,6 +242,12 @@ struct PayContext
*/
struct MerchantInstance *mi;
+ /**
+ * Proposal data for the proposal that is being
+ * payed for in this context.
+ */
+ json_t *proposal_data;
+
};
@@ -428,12 +429,13 @@ deposit_cb (void *cls,
mr.purpose.size = htonl (sizeof (mr));
mr.h_proposal_data = pc->h_proposal_data;
- GNUNET_CRYPTO_eddsa_sign (&mi->privkey.eddsa_priv,
+ GNUNET_CRYPTO_eddsa_sign (&pc->mi->privkey.eddsa_priv,
&mr.purpose,
&sig);
resume_pay_with_response (pc,
MHD_HTTP_OK,
- TMH_RESPONSE_make_json_pack ("{s:s, s:o}",
+ TMH_RESPONSE_make_json_pack ("{s:o, s:s, s:o}",
+ "proposal_data", pc->proposal_data,
"sig",
json_string_value (GNUNET_JSON_from_data_auto (&sig)),
"h_proposal_data",
@@ -496,6 +498,11 @@ pay_context_cleanup (struct TM_HandlerContext *hc)
GNUNET_free (pc->chosen_exchange);
pc->chosen_exchange = NULL;
}
+ if (NULL != pc->proposal_data)
+ {
+ json_decref (pc->proposal_data);
+ pc->proposal_data = NULL;
+ }
GNUNET_free (pc);
}
@@ -884,277 +891,241 @@ transaction_double_check (void *cls,
return;
}
+
+
/**
- * Accomplish this payment.
+ * Try to parse the pay request into the given pay context.
*
- * @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
+ * Schedules an error response in the connection on failure.
+ *
+ * @return #GNUNET_YES on success
*/
-int
-MH_handler_pay (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
+static int
+parse_pay (struct MHD_Connection *connection, json_t *root, struct PayContext *pc)
{
- struct PayContext *pc;
+ json_t *coins;
+ json_t *coin;
+ json_t *merchant;
+ unsigned int coins_index;
+ const char *chosen_exchange;
+ const char *order_id;
+ struct GNUNET_HashCode h_oid;
+ struct TALER_MerchantPublicKeyP merchant_pub;
int res;
- json_t *root;
- struct GNUNET_TIME_Absolute now;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "In handler for /pay.\n");
- if (NULL == *connection_cls)
- {
- pc = GNUNET_new (struct PayContext);
- pc->hc.cc = &pay_context_cleanup;
- pc->connection = connection;
- *connection_cls = pc;
- }
- else
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_json ("coins", &coins),
+ GNUNET_JSON_spec_string ("exchange", &chosen_exchange),
+ GNUNET_JSON_spec_string ("order_id", &order_id),
+ GNUNET_JSON_spec_fixed_auto ("merchant_pub", &merchant_pub),
+ GNUNET_JSON_spec_end()
+ };
+
+ res = TMH_PARSE_json_data (connection,
+ root,
+ spec);
+ if (GNUNET_YES != res)
{
- /* not the first call, recover state */
- pc = *connection_cls;
+ GNUNET_break (0);
+ return res;
}
- if (0 != pc->response_code)
+
+ GNUNET_CRYPTO_hash (order_id,
+ strlen (order_id),
+ &h_oid);
+
+ res = db->find_proposal_data (db->cls,
+ &pc->proposal_data,
+ &h_oid,
+ &merchant_pub);
+
+
+ if (GNUNET_OK != res)
{
- /* We are *done* processing the request, just queue the response (!) */
- if (UINT_MAX == pc->response_code)
+
+ if (MHD_YES != TMH_RESPONSE_reply_not_found (connection,
+ TALER_EC_PAY_DB_STORE_PAY_ERROR,
+ "Proposal not found"))
{
GNUNET_break (0);
- return MHD_NO; /* hard error */
+ return GNUNET_SYSERR;
}
- res = MHD_queue_response (connection,
- pc->response_code,
- pc->response);
- if (NULL != pc->response)
+ return GNUNET_NO;
+ }
+
+
+ if (GNUNET_OK != TALER_JSON_hash (pc->proposal_data, &pc->h_proposal_data))
+ {
+ if (MHD_YES != TMH_RESPONSE_reply_internal_error (connection,
+ TALER_EC_NONE,
+ "Can not hash proposal"))
{
- MHD_destroy_response (pc->response);
- pc->response = NULL;
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
}
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Queueing response (%u) for /pay (%s).\n",
- (unsigned int) pc->response_code,
- res ? "OK" : "FAILED");
- return res;
+ return GNUNET_NO;
}
- if (NULL != pc->chosen_exchange)
+
+
+ merchant = json_object_get (pc->proposal_data, "merchant");
+ if (NULL == merchant)
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Shouldn't be here. Old MHD version?\n");
- return MHD_YES;
+ // invalid contract:
+ GNUNET_break (0);
+ if (MHD_YES != TMH_RESPONSE_reply_internal_error (connection,
+ TALER_EC_NONE,
+ "No merchant field in contract"))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_NO;
}
- res = TMH_PARSE_post_json (connection,
- &pc->json_parse_context,
- upload_data,
- upload_data_size,
- &root);
- if (GNUNET_SYSERR == res)
+ pc->mi = get_instance (merchant);
+
+ if (NULL == pc->mi)
{
- GNUNET_break (0);
- return TMH_RESPONSE_reply_invalid_json (connection);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Not able to find the specified instance\n");
+ if (MHD_NO == TMH_RESPONSE_reply_not_found (connection,
+ TALER_EC_PAY_INSTANCE_UNKNOWN,
+ "Unknown instance given"))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_NO;
}
- if ((GNUNET_NO == res) || (NULL == root))
- return MHD_YES; /* the POST's body has to be further fetched */
- mi = get_instance (root);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "/pay: picked instance %s with key %s\n",
+ pc->mi->id,
+ GNUNET_STRINGS_data_to_string_alloc (&pc->mi->pubkey, sizeof (pc->mi->pubkey)));
+
+ pc->chosen_exchange = GNUNET_strdup (chosen_exchange);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Parsed JSON for /pay.\n");
+
+
- /* Got the JSON upload, parse it */
{
- json_t *coins;
- json_t *coin;
- unsigned int coins_index;
- struct TALER_MerchantSignatureP merchant_sig;
- struct TALER_ProposalDataPS pdps;
- const char *chosen_exchange;
- struct GNUNET_JSON_Specification spec[] = {
- TALER_JSON_spec_amount ("amount", &pc->amount),
- GNUNET_JSON_spec_json ("coins", &coins),
- GNUNET_JSON_spec_fixed_auto ("h_proposal_data", &pc->h_proposal_data),
- TALER_JSON_spec_amount ("max_fee", &pc->max_fee),
- GNUNET_JSON_spec_fixed_auto ("merchant_sig", &merchant_sig),
- GNUNET_JSON_spec_string ("exchange", &chosen_exchange),
- GNUNET_JSON_spec_absolute_time ("refund_deadline", &pc->refund_deadline),
- GNUNET_JSON_spec_absolute_time ("pay_deadline", &pc->pay_deadline),
- GNUNET_JSON_spec_absolute_time ("timestamp", &pc->timestamp),
+ struct GNUNET_JSON_Specification espec[] = {
+ GNUNET_JSON_spec_absolute_time ("refund_deadline",
+ &pc->refund_deadline),
+ GNUNET_JSON_spec_absolute_time ("pay_deadline",
+ &pc->pay_deadline),
+ GNUNET_JSON_spec_absolute_time ("timestamp",
+ &pc->timestamp),
+ TALER_JSON_spec_amount ("max_fee",
+ &pc->max_fee),
+ TALER_JSON_spec_amount ("amount",
+ &pc->amount),
GNUNET_JSON_spec_end()
};
res = TMH_PARSE_json_data (connection,
- root,
- spec);
+ pc->proposal_data,
+ espec);
if (GNUNET_YES != res)
{
- json_decref (root);
+ GNUNET_JSON_parse_free (spec);
GNUNET_break (0);
return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
}
- pc->mi = get_instance (root);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "/pay: picked instance %s\n",
- pc->mi->id);
-
- if (NULL == pc->mi)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Not able to find the specified instance\n");
- json_decref (root);
- return TMH_RESPONSE_reply_not_found (connection,
- TALER_EC_PAY_INSTANCE_UNKNOWN,
- "Unknown instance given");
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "The instance for this deposit is '%s', whose bank details are '%s'\n",
- pc->mi->id,
- json_dumps (pc->mi->j_wire,
- JSON_COMPACT));
- pc->chosen_exchange = GNUNET_strdup (chosen_exchange);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Parsed JSON for /pay.\n");
- pdps.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_CONTRACT);
- pdps.purpose.size = htonl (sizeof (pdps));
- pdps.hash = pc->h_proposal_data;
- struct GNUNET_HashCode dummy;
+ pc->wire_transfer_deadline = GNUNET_TIME_absolute_add (pc->timestamp, wire_transfer_delay);
- GNUNET_CRYPTO_hash (&merchant_sig.eddsa_sig,
- sizeof (merchant_sig.eddsa_sig),
- &dummy);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Verifying signature '%s'\n",
- GNUNET_h2s (&dummy));
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "of hashed data '%s'\n",
- GNUNET_h2s (&pc->h_proposal_data));
-
- GNUNET_CRYPTO_hash (&pc->mi->privkey.eddsa_priv,
- sizeof (pc->mi->privkey.eddsa_priv),
- &dummy);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "with private key '%s'\n",
- GNUNET_h2s (&dummy));
-
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_CONTRACT,
- &pdps.purpose,
- &merchant_sig.eddsa_sig,
- &pc->mi->pubkey.eddsa_pub))
+ if (pc->wire_transfer_deadline.abs_value_us < pc->refund_deadline.abs_value_us)
{
GNUNET_break (0);
GNUNET_JSON_parse_free (spec);
- json_decref (root);
return TMH_RESPONSE_reply_external_error (connection,
- TALER_EC_PAY_MERCHANT_SIGNATURE_INVALID,
- "invalid merchant signature supplied");
+ TALER_EC_PAY_REFUND_DEADLINE_PAST_WIRE_TRANSFER_DEADLINE,
+ "refund deadline after wire transfer deadline");
}
+ }
- /* 'wire_transfer_deadline' is optional, if it is not present,
- generate it here; it will be timestamp plus the
- wire_transfer_delay supplied in config file */
- if (NULL == json_object_get (root,
- "wire_transfer_deadline"))
- {
- pc->wire_transfer_deadline
- = GNUNET_TIME_absolute_add (pc->timestamp,
- wire_transfer_delay);
- if (pc->wire_transfer_deadline.abs_value_us < pc->refund_deadline.abs_value_us)
- {
- /* Refund value very large, delay wire transfer accordingly */
- pc->wire_transfer_deadline = pc->refund_deadline;
- }
- }
- else
- {
- struct GNUNET_JSON_Specification espec[] = {
- GNUNET_JSON_spec_absolute_time ("wire_transfer_deadline",
- &pc->wire_transfer_deadline),
- GNUNET_JSON_spec_end()
- };
-
- res = TMH_PARSE_json_data (connection,
- root,
- espec);
- if (GNUNET_YES != res)
- {
- GNUNET_JSON_parse_free (spec);
- json_decref (root);
- GNUNET_break (0);
- return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
- }
- if (pc->wire_transfer_deadline.abs_value_us < pc->refund_deadline.abs_value_us)
- {
- GNUNET_break (0);
- GNUNET_JSON_parse_free (spec);
- json_decref (root);
- return TMH_RESPONSE_reply_external_error (connection,
- TALER_EC_PAY_REFUND_DEADLINE_PAST_WIRE_TRANSFER_DEADLINE,
- "refund deadline after wire transfer deadline");
- }
- }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "parsed timestamps\n");
+
+
+ pc->coins_cnt = json_array_size (coins);
+ if (0 == pc->coins_cnt)
+ {
+ GNUNET_JSON_parse_free (spec);
+ return TMH_RESPONSE_reply_arg_invalid (connection,
+ TALER_EC_PAY_COINS_ARRAY_EMPTY,
+ "coins");
+ }
+ /* note: 1 coin = 1 deposit confirmation expected */
+ pc->dc = GNUNET_new_array (pc->coins_cnt,
+ struct DepositConfirmation);
+ /* This loop populates the array 'dc' in 'pc' */
+ json_array_foreach (coins, coins_index, coin)
+ {
+ struct DepositConfirmation *dc = &pc->dc[coins_index];
+ struct GNUNET_JSON_Specification spec[] = {
+ TALER_JSON_spec_denomination_public_key ("denom_pub", &dc->denom),
+ TALER_JSON_spec_amount ("f" /* FIXME */, &dc->amount_with_fee),
+ GNUNET_JSON_spec_fixed_auto ("coin_pub", &dc->coin_pub),
+ TALER_JSON_spec_denomination_signature ("ub_sig", &dc->ub_sig),
+ GNUNET_JSON_spec_fixed_auto ("coin_sig", &dc->coin_sig),
+ GNUNET_JSON_spec_end()
+ };
- pc->coins_cnt = json_array_size (coins);
- if (0 == pc->coins_cnt)
+ res = TMH_PARSE_json_data (connection,
+ coin,
+ spec);
+ if (GNUNET_YES != res)
{
GNUNET_JSON_parse_free (spec);
json_decref (root);
- return TMH_RESPONSE_reply_arg_invalid (connection,
- TALER_EC_PAY_COINS_ARRAY_EMPTY,
- "coins");
+ GNUNET_break (0);
+ return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
}
- /* note: 1 coin = 1 deposit confirmation expected */
- pc->dc = GNUNET_new_array (pc->coins_cnt,
- struct DepositConfirmation);
- /* This loop populates the array 'dc' in 'pc' */
- json_array_foreach (coins, coins_index, coin)
{
- struct DepositConfirmation *dc = &pc->dc[coins_index];
- struct GNUNET_JSON_Specification spec[] = {
- TALER_JSON_spec_denomination_public_key ("denom_pub", &dc->denom),
- TALER_JSON_spec_amount ("f" /* FIXME */, &dc->amount_with_fee),
- GNUNET_JSON_spec_fixed_auto ("coin_pub", &dc->coin_pub),
- TALER_JSON_spec_denomination_signature ("ub_sig", &dc->ub_sig),
- GNUNET_JSON_spec_fixed_auto ("coin_sig", &dc->coin_sig),
- GNUNET_JSON_spec_end()
- };
-
- res = TMH_PARSE_json_data (connection,
- coin,
- spec);
- if (GNUNET_YES != res)
- {
- GNUNET_JSON_parse_free (spec);
- json_decref (root);
- GNUNET_break (0);
- return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
- }
+ char *s;
+
+ s = TALER_amount_to_string (&dc->amount_with_fee);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Coin #%i has f %s\n",
+ coins_index,
+ s);
+ GNUNET_free (s);
+ }
+
+ dc->index = coins_index;
+ dc->pc = pc;
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "parsed coins\n");
- {
- char *s;
-
- s = TALER_amount_to_string (&dc->amount_with_fee);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Coin #%i has f %s\n",
- coins_index,
- s);
- GNUNET_free (s);
- }
-
- dc->index = coins_index;
- dc->pc = pc;
- }
- GNUNET_JSON_parse_free (spec);
- } /* end of parsing of JSON upload */
pc->pending = pc->coins_cnt;
+ GNUNET_JSON_parse_free (spec);
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Process a payment for a proposal.
+ */
+static int
+handler_pay_json (struct MHD_Connection *connection,
+ json_t *root,
+ struct PayContext *pc)
+{
+ int ret;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "about to parse '/pay' body\n");
+
+ ret = parse_pay (connection, root, pc);
+ if (GNUNET_OK != ret)
+ return ret;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "parsed '/pay' body\n");
+
/* Check if this payment attempt has already succeeded */
if (GNUNET_SYSERR ==
db->find_payments (db->cls,
@@ -1164,7 +1135,6 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
pc))
{
GNUNET_break (0);
- json_decref (root);
return TMH_RESPONSE_reply_internal_error (connection,
TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR,
"Merchant database error");
@@ -1183,7 +1153,6 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
MHD_HTTP_OK,
resp);
MHD_destroy_response (resp);
- json_decref (root);
return ret;
}
/* Check if transaction is already known, if not store it. */
@@ -1195,7 +1164,6 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
pc))
{
GNUNET_break (0);
- json_decref (root);
return TMH_RESPONSE_reply_internal_error (connection,
TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR,
"Merchant database error");
@@ -1203,16 +1171,17 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
if (GNUNET_SYSERR == pc->transaction_exits)
{
GNUNET_break (0);
- json_decref (root);
return TMH_RESPONSE_reply_external_error (connection,
TALER_EC_PAY_DB_TRANSACTION_ID_CONFLICT,
"Transaction ID reused with different transaction details");
}
if (GNUNET_NO == pc->transaction_exits)
{
+ struct GNUNET_TIME_Absolute now;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Dealing with new transaction '%s'\n",
GNUNET_h2s (&pc->h_proposal_data));
+
now = GNUNET_TIME_absolute_get ();
if (now.abs_value_us > pc->pay_deadline.abs_value_us)
{
@@ -1243,7 +1212,6 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
&pc->amount))
{
GNUNET_break (0);
- json_decref (root);
return TMH_RESPONSE_reply_internal_error (connection,
TALER_EC_PAY_DB_STORE_TRANSACTION_ERROR,
"Merchant database error");
@@ -1272,7 +1240,94 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
pc->timeout_task = GNUNET_SCHEDULER_add_delayed (PAY_TIMEOUT,
&handle_pay_timeout,
pc);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Process a payment for a proposal.
+ * Takes data from the given MHD connection.
+ *
+ * @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_pay (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ struct PayContext *pc;
+ int res;
+ json_t *root;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "In handler for /pay.\n");
+ if (NULL == *connection_cls)
+ {
+ pc = GNUNET_new (struct PayContext);
+ pc->hc.cc = &pay_context_cleanup;
+ pc->connection = connection;
+ *connection_cls = pc;
+ }
+ else
+ {
+ /* not the first call, recover state */
+ pc = *connection_cls;
+ }
+ if (0 != pc->response_code)
+ {
+ /* We are *done* processing the request, just queue the response (!) */
+ if (UINT_MAX == pc->response_code)
+ {
+ GNUNET_break (0);
+ return MHD_NO; /* hard error */
+ }
+ res = MHD_queue_response (connection,
+ pc->response_code,
+ pc->response);
+ if (NULL != pc->response)
+ {
+ MHD_destroy_response (pc->response);
+ pc->response = NULL;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Queueing response (%u) for /pay (%s).\n",
+ (unsigned int) pc->response_code,
+ res ? "OK" : "FAILED");
+ return res;
+ }
+ if (NULL != pc->chosen_exchange)
+ {
+ // FIXME: explain in comment why this could happen!
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Shouldn't be here. Old MHD version?\n");
+ return MHD_YES;
+ }
+ res = TMH_PARSE_post_json (connection,
+ &pc->json_parse_context,
+ upload_data,
+ upload_data_size,
+ &root);
+ if (GNUNET_SYSERR == res)
+ {
+ GNUNET_break (0);
+ return TMH_RESPONSE_reply_invalid_json (connection);
+ }
+ if ((GNUNET_NO == res) || (NULL == root))
+ return MHD_YES; /* the POST's body has to be further fetched */
+
+ res = handler_pay_json (connection, root, pc);
json_decref (root);
+ if (GNUNET_SYSERR == res)
+ return MHD_NO;
return MHD_YES;
}
diff --git a/src/backend/taler-merchant-httpd_proposal.c b/src/backend/taler-merchant-httpd_proposal.c
index 0ee23c8f..3b5660d1 100644
--- a/src/backend/taler-merchant-httpd_proposal.c
+++ b/src/backend/taler-merchant-httpd_proposal.c
@@ -289,6 +289,8 @@ MH_handler_proposal_put (struct TMH_RequestHandler *rh,
GNUNET_CRYPTO_hash (order_id,
strlen (order_id),
&h_oid);
+
+
if (GNUNET_OK !=
db->insert_proposal_data (db->cls,
&h_oid,
diff --git a/src/include/taler_merchant_service.h b/src/include/taler_merchant_service.h
index 6c549c8d..99bab17b 100644
--- a/src/include/taler_merchant_service.h
+++ b/src/include/taler_merchant_service.h
@@ -248,6 +248,7 @@ TALER_MERCHANT_pay_wallet (struct GNUNET_CURL_Context *ctx,
struct GNUNET_TIME_Absolute pay_deadline,
const struct GNUNET_HashCode *h_wire,
const char *exchange_uri,
+ const char *order_id,
unsigned int num_coins,
const struct TALER_MERCHANT_PayCoin *coins,
TALER_MERCHANT_PayCallback pay_cb,
@@ -327,15 +328,8 @@ struct TALER_MERCHANT_PaidCoin
struct TALER_MERCHANT_Pay *
TALER_MERCHANT_pay_frontend (struct GNUNET_CURL_Context *ctx,
const char *merchant_uri,
- const char *instance,
- const struct GNUNET_HashCode *h_contract,
- const struct TALER_Amount *amount,
- const struct TALER_Amount *max_fee,
- const struct TALER_MerchantSignatureP *merchant_sig,
- struct GNUNET_TIME_Absolute refund_deadline,
- struct GNUNET_TIME_Absolute pay_deadline,
- struct GNUNET_TIME_Absolute timestamp,
- struct GNUNET_TIME_Absolute wire_transfer_deadline,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const char *order_id,
const char *exchange_uri,
unsigned int num_coins,
const struct TALER_MERCHANT_PaidCoin *coins,
diff --git a/src/lib/merchant_api_pay.c b/src/lib/merchant_api_pay.c
index 76c247ab..6910bdec 100644
--- a/src/lib/merchant_api_pay.c
+++ b/src/lib/merchant_api_pay.c
@@ -288,6 +288,7 @@ TALER_MERCHANT_pay_wallet (struct GNUNET_CURL_Context *ctx,
struct GNUNET_TIME_Absolute pay_deadline,
const struct GNUNET_HashCode *h_wire,
const char *exchange_uri,
+ const char *order_id,
unsigned int num_coins,
const struct TALER_MERCHANT_PayCoin *coins,
TALER_MERCHANT_PayCallback pay_cb,
@@ -301,6 +302,14 @@ TALER_MERCHANT_pay_wallet (struct GNUNET_CURL_Context *ctx,
(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_break (0);
+ return NULL;
+ }
+
dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT);
dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS));
dr.h_proposal_data = *h_proposal_data;
@@ -331,6 +340,7 @@ TALER_MERCHANT_pay_wallet (struct GNUNET_CURL_Context *ctx,
}
TALER_amount_hton (&dr.deposit_fee,
&fee);
+
GNUNET_CRYPTO_eddsa_sign (&coin->coin_priv.eddsa_priv,
&dr.purpose,
&p->coin_sig.eddsa_signature);
@@ -343,15 +353,8 @@ TALER_MERCHANT_pay_wallet (struct GNUNET_CURL_Context *ctx,
}
return TALER_MERCHANT_pay_frontend (ctx,
merchant_uri,
- instance,
- h_proposal_data,
- amount,
- max_fee,
- merchant_sig,
- refund_deadline,
- pay_deadline,
- timestamp,
- GNUNET_TIME_UNIT_ZERO_ABS,
+ merchant_pub,
+ order_id,
exchange_uri,
num_coins,
pc,
@@ -368,19 +371,9 @@ TALER_MERCHANT_pay_wallet (struct GNUNET_CURL_Context *ctx,
*
* @param ctx the execution loop context
* @param merchant_uri base URI of the merchant's backend
- * @param instance which merchant instance will receive this payment
- * @param h_contract hash of the contact of the merchant with the customer
- * @param timestamp timestamp when the contract was finalized, must match approximately the current time of the merchant
- * @param transaction_id transaction id for the transaction between merchant and customer
- * @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 deadline to pay for this contract
- * @param wire_transfer_deadline date by which the merchant would like the exchange to execute the wire transfer (can be zero if there is no specific date desired by the frontend). If non-zero, must be larger than @a refund_deadline.
* @param exchange_uri URI of the exchange that the coins belong to
* @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 max_fee maximum fee covered by the merchant (according to the contract)
- * @param amount total value of the contract to be paid to the merchant
* @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
@@ -388,15 +381,8 @@ TALER_MERCHANT_pay_wallet (struct GNUNET_CURL_Context *ctx,
struct TALER_MERCHANT_Pay *
TALER_MERCHANT_pay_frontend (struct GNUNET_CURL_Context *ctx,
const char *merchant_uri,
- const char *instance,
- const struct GNUNET_HashCode *h_proposal_data,
- const struct TALER_Amount *amount,
- const struct TALER_Amount *max_fee,
- const struct TALER_MerchantSignatureP *merchant_sig,
- struct GNUNET_TIME_Absolute refund_deadline,
- struct GNUNET_TIME_Absolute pay_deadline,
- struct GNUNET_TIME_Absolute timestamp,
- struct GNUNET_TIME_Absolute wire_transfer_deadline,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const char *order_id,
const char *exchange_uri,
unsigned int num_coins,
const struct TALER_MERCHANT_PaidCoin *coins,
@@ -411,23 +397,6 @@ TALER_MERCHANT_pay_frontend (struct GNUNET_CURL_Context *ctx,
struct TALER_Amount total_amount;
unsigned int i;
- (void) GNUNET_TIME_round_abs (&timestamp);
- (void) GNUNET_TIME_round_abs (&refund_deadline);
- (void) GNUNET_TIME_round_abs (&wire_transfer_deadline);
-
- if (GNUNET_YES !=
- TALER_amount_cmp_currency (amount,
- max_fee))
- {
- GNUNET_break (0);
- return NULL;
- }
- if ( (0 != wire_transfer_deadline.abs_value_us) &&
- (wire_transfer_deadline.abs_value_us < refund_deadline.abs_value_us) )
- {
- GNUNET_break (0);
- return NULL;
- }
if (0 == num_coins)
{
GNUNET_break (0);
@@ -489,101 +458,16 @@ TALER_MERCHANT_pay_frontend (struct GNUNET_CURL_Context *ctx,
j_coin));
}
- { /* Sanity check that total_amount and total_fee
- match amount/max_fee requirements */
- struct TALER_Amount fee_left;
-
- if (GNUNET_OK ==
- TALER_amount_subtract (&fee_left,
- &total_fee,
- max_fee))
- {
- /* Wallet must cover part of the fee! */
- struct TALER_Amount new_amount;
-
- if (GNUNET_OK !=
- TALER_amount_add (&new_amount,
- &fee_left,
- amount))
- {
- /* integer overflow */
- GNUNET_break (0);
- json_decref (j_coins);
- return NULL;
- }
- if (GNUNET_YES !=
- TALER_amount_cmp_currency (&new_amount,
- &total_amount))
- {
- GNUNET_break (0);
- json_decref (j_coins);
- return NULL;
- }
- if (1 ==
- TALER_amount_cmp (&new_amount,
- &total_amount))
- {
- /* new_amount > total_amount: all of the coins (total_amount)
- do not add up to at least the new_amount owed to the
- merchant, this request is bogus, abort */
- GNUNET_break (0);
- json_decref (j_coins);
- return NULL;
- }
- }
- else
- {
- /* Full fee covered by merchant, but our total
- must at least cover the total contract amount */
- if (GNUNET_YES !=
- TALER_amount_cmp_currency (amount,
- &total_amount))
- {
- GNUNET_break (0);
- json_decref (j_coins);
- return NULL;
- }
- if (1 ==
- TALER_amount_cmp (amount,
- &total_amount))
- {
- /* amount > total_amount: all of the coins (total_amount) do
- not add up to at least the amount owed to the merchant,
- this request is bogus, abort */
- GNUNET_break (0);
- json_decref (j_coins);
- return NULL;
- }
- }
- } /* end of sanity check */
-
- pay_obj = json_pack ("{s:o," /* h_proposal_data */
- " s:o," /* timestamp */
- " s:o, s:o," /* refund_deadline, pay_deadline */
+ pay_obj = json_pack ("{"
" s:s," /* exchange */
- " s:o, s:o," /* coins, max_fee */
- " s:o, s:o}",/* amount, signature */
- "h_proposal_data", GNUNET_JSON_from_data_auto (h_proposal_data),
- "timestamp", GNUNET_JSON_from_time_abs (timestamp),
- "refund_deadline", GNUNET_JSON_from_time_abs (refund_deadline),
- "pay_deadline", GNUNET_JSON_from_time_abs (pay_deadline),
+ " s:o," /* coins */
+ " s:s," /* order_id */
+ " s:o," /* merchant_pub */
+ "}",
"exchange", exchange_uri,
"coins", j_coins,
- "max_fee", TALER_JSON_from_amount (max_fee),
- "amount", TALER_JSON_from_amount (amount),
- "merchant_sig", GNUNET_JSON_from_data_auto (merchant_sig));
- if (NULL != instance)
- json_object_set_new (pay_obj,
- "instance",
- json_string (instance));
-
- if (0 != wire_transfer_deadline.abs_value_us)
- {
- /* Frontend did have an execution date in mind, add it */
- json_object_set_new (pay_obj,
- "wire_transfer_deadline",
- GNUNET_JSON_from_time_abs (wire_transfer_deadline));
- }
+ "order_id", order_id,
+ "merchant_pub", GNUNET_JSON_from_data_auto (merchant_pub));
ph = GNUNET_new (struct TALER_MERCHANT_Pay);
ph->ctx = ctx;
diff --git a/src/lib/test_merchant_api.c b/src/lib/test_merchant_api.c
index 0588b5e0..679e41a4 100644
--- a/src/lib/test_merchant_api.c
+++ b/src/lib/test_merchant_api.c
@@ -1857,6 +1857,7 @@ interpreter_run (void *cls)
pay_deadline,
&h_wire,
EXCHANGE_URI,
+ order_id,
1 /* num_coins */,
&pc /* coins */,
&pay_cb,