summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/taler-merchant-httpd_proposal.c104
-rw-r--r--src/backenddb/plugin_merchantdb_postgres.c107
-rw-r--r--src/include/taler_merchantdb_plugin.h33
3 files changed, 230 insertions, 14 deletions
diff --git a/src/backend/taler-merchant-httpd_proposal.c b/src/backend/taler-merchant-httpd_proposal.c
index bbd7d39c..c79e2a81 100644
--- a/src/backend/taler-merchant-httpd_proposal.c
+++ b/src/backend/taler-merchant-httpd_proposal.c
@@ -357,11 +357,11 @@ proposal_put (struct MHD_Connection *connection,
for (unsigned int i=0;i<MAX_RETRIES;i++)
{
- qs = db->insert_contract_terms (db->cls,
- order_id,
- &mi->pubkey,
- timestamp,
- order);
+ qs = db->insert_order (db->cls,
+ order_id,
+ &mi->pubkey,
+ timestamp,
+ order);
if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
break;
}
@@ -377,12 +377,9 @@ proposal_put (struct MHD_Connection *connection,
"db error: could not store this proposal's data into db");
}
- res = TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_OK,
- "{s:O, s:o s:o}",
- "data", order,
- "sig", GNUNET_JSON_from_data_auto (&merchant_sig),
- "hash", GNUNET_JSON_from_data_auto (&pdps.hash));
+ res = TMH_RESPONSE_reply_json (connection,
+ json_object (),
+ MHD_HTTP_OK);
GNUNET_JSON_parse_free (spec);
return res;
}
@@ -458,6 +455,8 @@ MH_handler_proposal_put (struct TMH_RequestHandler *rh,
* proposal's data related to the transaction id given as the URL's
* parameter.
*
+ * Binds the proposal to a nonce.
+ *
* @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)
@@ -474,6 +473,7 @@ MH_handler_proposal_lookup (struct TMH_RequestHandler *rh,
{
const char *order_id;
const char *instance;
+ const char *nonce;
int res;
enum GNUNET_DB_QueryStatus qs;
json_t *contract_terms;
@@ -500,6 +500,14 @@ MH_handler_proposal_lookup (struct TMH_RequestHandler *rh,
TALER_EC_PARAMETER_MISSING,
"order_id");
+ nonce = MHD_lookup_connection_value (connection,
+ MHD_GET_ARGUMENT_KIND,
+ "nonce");
+ if (NULL == nonce)
+ return TMH_RESPONSE_reply_arg_missing (connection,
+ TALER_EC_PARAMETER_MISSING,
+ "nonce");
+
qs = db->find_contract_terms (db->cls,
&contract_terms,
order_id,
@@ -516,9 +524,77 @@ MH_handler_proposal_lookup (struct TMH_RequestHandler *rh,
"An error occurred while retrieving proposal data from db");
}
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
- return TMH_RESPONSE_reply_not_found (connection,
- TALER_EC_PROPOSAL_LOOKUP_NOT_FOUND,
- "unknown transaction id");
+ {
+ qs = db->find_orders (db->cls,
+ &contract_terms,
+ order_id,
+ &mi->pubkey);
+ if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+ {
+ return TMH_RESPONSE_reply_not_found (connection,
+ TALER_EC_PROPOSAL_LOOKUP_NOT_FOUND,
+ "unknown order id");
+ }
+ GNUNET_assert (NULL != contract_terms);
+ // FIXME: now we can delete (merchant_pub, order_id) from the merchant_orders table
+ json_object_set_new (contract_terms, "nonce", json_string (nonce));
+
+ struct GNUNET_TIME_Absolute timestamp;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_absolute_time ("timestamp", &timestamp),
+ GNUNET_JSON_spec_end ()
+ };
+ /* extract fields we need to sign separately */
+ res = TMH_PARSE_json_data (connection, contract_terms, spec);
+ if (GNUNET_NO == res)
+ {
+ return MHD_YES;
+ }
+ if (GNUNET_SYSERR == res)
+ {
+ return TMH_RESPONSE_reply_internal_error (connection,
+ TALER_EC_PROPOSAL_ORDER_PARSE_ERROR,
+ "Impossible to parse the order");
+ }
+
+ for (unsigned int i=0;i<MAX_RETRIES;i++)
+ {
+ qs = db->insert_contract_terms (db->cls,
+ order_id,
+ &mi->pubkey,
+ timestamp,
+ contract_terms);
+ if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
+ break;
+ }
+ if (0 > qs)
+ {
+ /* Special report if retries insufficient */
+ 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_PROPOSAL_STORE_DB_ERROR,
+ "db error: could not store this proposal's data into db");
+ }
+ }
+
+ const char *stored_nonce = json_string_value (json_object_get(contract_terms, "nonce"));
+
+ if (NULL == stored_nonce)
+ {
+ GNUNET_break (0);
+ return TMH_RESPONSE_reply_internal_error (connection,
+ TALER_EC_PROPOSAL_ORDER_PARSE_ERROR,
+ "existing proposal has non nonce");
+ }
+
+ if (0 != strcmp (stored_nonce, nonce))
+ {
+ return TMH_RESPONSE_reply_bad_request (connection,
+ TALER_EC_PROPOSAL_LOOKUP_NOT_FOUND,
+ "mismatched nonce");
+ }
res = TMH_RESPONSE_reply_json (connection,
contract_terms,
diff --git a/src/backenddb/plugin_merchantdb_postgres.c b/src/backenddb/plugin_merchantdb_postgres.c
index 54d532fc..5b14d316 100644
--- a/src/backenddb/plugin_merchantdb_postgres.c
+++ b/src/backenddb/plugin_merchantdb_postgres.c
@@ -95,6 +95,16 @@ postgres_initialize (void *cls)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_ExecuteStatement es[] = {
+ /* Orders created by the frontend, not signed or given a nonce yet.
+ The contract terms will change (nonce will be added) when moved to the
+ contract terms table */
+ GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_orders ("
+ "order_id VARCHAR NOT NULL"
+ ",merchant_pub BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=32)"
+ ",contract_terms BYTEA NOT NULL"
+ ",timestamp INT8 NOT NULL"
+ ",PRIMARY KEY (order_id, merchant_pub)"
+ ");"),
/* Offers we made to customers */
GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_contract_terms ("
"order_id VARCHAR NOT NULL"
@@ -313,6 +323,15 @@ postgres_initialize (void *cls)
" VALUES "
"($1, $2, $3, $4, $5)",
5),
+ GNUNET_PQ_make_prepare ("insert_order",
+ "INSERT INTO merchant_orders"
+ "(order_id"
+ ",merchant_pub"
+ ",timestamp"
+ ",contract_terms"
+ " VALUES "
+ "($1, $2, $3, $4)",
+ 4),
GNUNET_PQ_make_prepare ("mark_proposal_paid",
"UPDATE merchant_contract_terms SET"
" paid=TRUE WHERE h_contract_terms=$1"
@@ -388,6 +407,14 @@ postgres_initialize (void *cls)
" order_id=$1"
" AND merchant_pub=$2",
2),
+ GNUNET_PQ_make_prepare ("find_orders",
+ "SELECT"
+ " contract_terms"
+ " FROM merchant_orders"
+ " WHERE"
+ " order_id=$1"
+ " AND merchant_pub=$2",
+ 2),
GNUNET_PQ_make_prepare ("find_contract_terms_by_date",
"SELECT"
" contract_terms"
@@ -834,6 +861,47 @@ postgres_find_contract_terms (void *cls,
/**
+ * Retrieve order given its order id and the instance's merchant public key.
+ *
+ * @param cls closure
+ * @param[out] contract_terms where to store the retrieved contract terms
+ * @param order id order id used to perform the lookup
+ * @param merchant_pub merchant public key that identifies the instance
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_find_orders (void *cls,
+ json_t **contract_terms,
+ const char *order_id,
+ const struct TALER_MerchantPublicKeyP *merchant_pub)
+{
+ struct PostgresClosure *pg = cls;
+
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (order_id),
+ GNUNET_PQ_query_param_auto_from_type (merchant_pub),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ TALER_PQ_result_spec_json ("contract_terms",
+ contract_terms),
+ GNUNET_PQ_result_spec_end
+ };
+
+ *contract_terms = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Finding contract term, order_id: '%s', merchant_pub: '%s'.\n",
+ order_id,
+ TALER_B2S (merchant_pub));
+ check_connection (pg);
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "find_orders",
+ params,
+ rs);
+}
+
+
+/**
* Insert proposal data and its hashcode into db
*
* @param cls closure
@@ -881,6 +949,43 @@ postgres_insert_contract_terms (void *cls,
/**
+ * Insert order into the DB.
+ *
+ * @param cls closure
+ * @param order_id identificator of the proposal being stored
+ * @param merchant_pub merchant's public key
+ * @param timestamp timestamp of this proposal data
+ * @param contract_terms proposal data to store
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_insert_order (void *cls,
+ const char *order_id,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ struct GNUNET_TIME_Absolute timestamp,
+ const json_t *contract_terms)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (order_id),
+ GNUNET_PQ_query_param_auto_from_type (merchant_pub),
+ GNUNET_PQ_query_param_absolute_time (&timestamp),
+ TALER_PQ_query_param_json (contract_terms),
+ GNUNET_PQ_query_param_end
+ };
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "inserting order: order_id: %s, merchant_pub: %s.\n",
+ order_id,
+ TALER_B2S (merchant_pub));
+ check_connection (pg);
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "insert_order",
+ params);
+}
+
+
+/**
* Mark contract terms as payed. Needed by /history as only payed
* contracts must be shown.
*
@@ -3250,6 +3355,8 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
plugin->find_deposits_by_wtid = &postgres_find_deposits_by_wtid;
plugin->find_proof_by_wtid = &postgres_find_proof_by_wtid;
plugin->insert_contract_terms = &postgres_insert_contract_terms;
+ plugin->insert_order = &postgres_insert_order;
+ plugin->find_orders = &postgres_find_orders;
plugin->find_contract_terms = &postgres_find_contract_terms;
plugin->find_contract_terms_history = &postgres_find_contract_terms_history;
plugin->find_contract_terms_by_date = &postgres_find_contract_terms_by_date;
diff --git a/src/include/taler_merchantdb_plugin.h b/src/include/taler_merchantdb_plugin.h
index 228fa90b..85cadd8a 100644
--- a/src/include/taler_merchantdb_plugin.h
+++ b/src/include/taler_merchantdb_plugin.h
@@ -184,6 +184,23 @@ struct TALER_MERCHANTDB_Plugin
int
(*initialize) (void *cls);
+ /**
+ * Insert order into db.
+ *
+ * @param cls closure
+ * @param order_id alphanumeric string that uniquely identifies the proposal
+ * @param merchant_pub merchant's public key
+ * @param timestamp timestamp of this proposal data
+ * @param contract_terms proposal data to store
+ * @return transaction status
+ */
+ enum GNUNET_DB_QueryStatus
+ (*insert_order) (void *cls,
+ const char *order_id,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ struct GNUNET_TIME_Absolute timestamp,
+ const json_t *contract_terms);
+
/**
* Insert proposal data into db; the routine will internally hash and
@@ -238,6 +255,22 @@ struct TALER_MERCHANTDB_Plugin
const char *order_id,
const struct TALER_MerchantPublicKeyP *merchant_pub);
+ /**
+ * Retrieve order given its order id and the instance's merchant public key.
+ *
+ * @param cls closure
+ * @param[out] contract_terms where to store the retrieved contract terms
+ * @param order id order id used to perform the lookup
+ * @param merchant_pub merchant public key that identifies the instance
+ * @return transaction status
+ */
+ enum GNUNET_DB_QueryStatus
+ (*find_orders) (void *cls,
+ json_t **contract_terms,
+ const char *order_id,
+ const struct TALER_MerchantPublicKeyP *merchant_pub);
+
+
/**
* Retrieve proposal data given its hashcode