diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/taler-merchant-httpd_proposal.c | 104 | ||||
-rw-r--r-- | src/backenddb/plugin_merchantdb_postgres.c | 107 | ||||
-rw-r--r-- | src/include/taler_merchantdb_plugin.h | 33 |
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", ×tamp), + 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 (×tamp), + 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 |