merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

commit 5453309a27e2d3621225ac10785707b02459b51e
parent e84d5dc451ad9fe214a3014457a1cf0c0e504e9a
Author: Marcello Stanisci <marcello.stanisci@inria.fr>
Date:   Wed, 23 Sep 2015 10:21:05 +0200

adding column hash(a) in contracts table, plus
a few cleanings on the JSON manipulations.

Diffstat:
Msrc/Makefile.am | 2+-
Msrc/backend-lib/merchant_db.c | 23++++++++---------------
Msrc/backend-lib/merchant_db.h | 2++
Msrc/backend-lib/taler-merchant-httpd_contract.c | 86+++++++++++++++++++++++++++++++++++++------------------------------------------
Msrc/backend-lib/taler_merchant_contract_lib.h | 5+++--
Msrc/backend/Makefile.am | 3++-
Dsrc/backend/merchant_db.c | 354-------------------------------------------------------------------------------
Dsrc/backend/merchant_db.h | 101-------------------------------------------------------------------------------
Msrc/backend/taler-merchant-httpd.c | 266++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Msrc/frontend/fake_wire_transfer.php | 2+-
Msrc/frontend/generate_taler_contract.php | 2+-
Msrc/tests/Makefile.am | 4++--
Msrc/tests/merchant-contract-test.c | 28+++++++++++++++-------------
Dsrc/tests/merchant_db.c | 354-------------------------------------------------------------------------------
Dsrc/tests/merchant_db.h | 101-------------------------------------------------------------------------------
15 files changed, 306 insertions(+), 1027 deletions(-)

diff --git a/src/Makefile.am b/src/Makefile.am @@ -1,2 +1,2 @@ AM_CPPFLAGS = -I$(top_srcdir)/src/include -SUBDIRS = include backend-lib backend +SUBDIRS = include backend-lib backend tests diff --git a/src/backend-lib/merchant_db.c b/src/backend-lib/merchant_db.c @@ -88,6 +88,7 @@ MERCHANT_DB_initialize (PGconn *conn, int tmp) "BEGIN TRANSACTION;" "CREATE %1$s TABLE IF NOT EXISTS contracts (" "contract_id INT8 PRIMARY KEY," + "hash BYTEA NOT NULL," "amount INT8 NOT NULL," "amount_fraction INT4 NOT NULL," "amount_currency VARCHAR(" TALER_CURRENCY_LEN_STR ") NOT NULL," @@ -119,10 +120,10 @@ MERCHANT_DB_initialize (PGconn *conn, int tmp) (conn, "contract_create", "INSERT INTO contracts" - "(contract_id, amount, amount_fraction, amount_currency," + "(contract_id, hash, amount, amount_fraction, amount_currency," "description, nounce, expiry, product) VALUES" - "($1, $2, $3, $4, $5, $6, $7, $8)", - 8, NULL))); + "($1, $2, $3, $4, $5, $6, $7, $8, $9)", + 9, NULL))); EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus(res))); PQclear (res); @@ -189,6 +190,7 @@ MERCHANT_DB_initialize (PGconn *conn, int tmp) * @param conn the database connection * @param expiry the time when the contract will expire * @param amount the taler amount corresponding to the contract + * @param hash of the stringified JSON corresponding to this contract * @param c_id contract's id * @param desc descripition of the contract * @param nounce a random 64-bit nounce @@ -200,6 +202,7 @@ uint32_t MERCHANT_DB_contract_create (PGconn *conn, const struct GNUNET_TIME_Absolute *expiry, const struct TALER_Amount *amount, + const struct GNUNET_HashCode *h_contract, uint64_t c_id, const char *desc, uint64_t nounce, @@ -214,26 +217,16 @@ MERCHANT_DB_contract_create (PGconn *conn, #endif ExecStatusType status; - #if 0 - /* - NOTE: the conversion to nl(l) happens *inside* the query param helpers; since - the policy imposes this format for storing values. */ - value_nbo = GNUNET_htonll (amount->value); - fraction_nbo = GNUNET_htonll (amount->fraction); - nounce_nbo = GNUNET_htonll (nounce); - expiry_ms_nbo = GNUNET_htonll (expiry.abs_value_us); - product = GNUNET_htonll (product); - #endif - /* ported. To be tested/compiled */ struct TALER_PQ_QueryParam params[] = { TALER_PQ_query_param_uint64 (&c_id), + TALER_PQ_query_param_fixed_size (h_contract, sizeof (struct GNUNET_HashCode)), TALER_PQ_query_param_amount (amount), /* a *string* is being put in the following statement, though the API talks about a *blob*. Will this be liked by the DB ? */ // the following inserts a string as a blob. Will Taler provide a param-from-string helper? - TALER_PQ_query_param_fixed_size (desc, strlen(desc)), + TALER_PQ_query_param_fixed_size (desc, strlen (desc)), TALER_PQ_query_param_uint64 (&nounce), TALER_PQ_query_param_absolute_time (expiry), TALER_PQ_query_param_uint64 (&product), diff --git a/src/backend-lib/merchant_db.h b/src/backend-lib/merchant_db.h @@ -64,6 +64,7 @@ MERCHANT_DB_initialize (PGconn *conn, int tmp); * @param conn the database connection * @param expiry the time when the contract will expire * @param amount the taler amount corresponding to the contract + * @param hash of the stringified JSON corresponding to this contract * @param c_id this contract's identification number * @param desc descripition of the contract * @param nounce a random 64-bit nounce @@ -75,6 +76,7 @@ uint32_t MERCHANT_DB_contract_create (PGconn *conn, const struct GNUNET_TIME_Absolute *expiry, const struct TALER_Amount *amount, + const struct GNUNET_HashCode *h_contract, uint64_t c_id, const char *desc, uint64_t nounce, diff --git a/src/backend-lib/taler-merchant-httpd_contract.c b/src/backend-lib/taler-merchant-httpd_contract.c @@ -50,26 +50,27 @@ hash_wireformat (uint64_t nounce, const struct MERCHANT_WIREFORMAT_Sepa *wire) /** * Take from the frontend the (partly) generated contract and fill -* the missing values in it; for example, the SEPA-aware values. +* the missing values in it; for example, the SEPA details. * Moreover, it stores the contract in the DB. -* @param j_contract parsed contract, originated by the frontend +* @param j_contract parsed contract, originated by the frontend. It will be +* hold the new values. * @param db_conn the handle to the local DB * @param wire merchant's bank's details -* @param where to store the (subset of the) contract to be (still) signed -* @return pointer to the complete JSON; NULL upon errors +* @param contract where to store the (subset of the) contract to be (still) signed +* @return GNUNET_OK on success; GNUNET_SYSERR upon errors */ /** -* TODO: inspection of reference counting and, accordingly, free those json_t*(s) +* TODO: inspect reference counting and, accordingly, free those json_t*(s) * still allocated */ -json_t * +uint32_t MERCHANT_handle_contract (json_t *j_contract, PGconn *db_conn, const struct MERCHANT_WIREFORMAT_Sepa *wire, struct Contract *contract) { - json_t *root; + json_t *j_tmp; json_t *j_details; json_t *j_timestamp; json_t *jh_wire; @@ -82,7 +83,7 @@ MERCHANT_handle_contract (json_t *j_contract, json_t *j_product_id; json_t *j_items_tmp; char *a; - char *h_wire_enc; + #define DaEBUG #ifdef DEBUG char *str; #endif @@ -97,54 +98,53 @@ MERCHANT_handle_contract (json_t *j_contract, GNUNET_TIME_UNIT_DAYS); ROUND_TO_SECS (timestamp, abs_value_us); j_timestamp = TALER_json_from_abs (timestamp); - // wireformat mgmt h_wire = hash_wireformat (nounce, wire); - h_wire_enc = GNUNET_STRINGS_data_to_string_alloc (&h_wire, - sizeof (struct GNUNET_HashCode)); - jh_wire = json_string (h_wire_enc); - if (-1 == json_unpack (j_contract, "{s:o, s:o, s:I, s:o, s:o}", - "amount", &j_amount, - "max fee", &j_max_fee, - "trans_id", &j_trans_id, - "mints", &j_mints, - "details", &j_details)) - - return NULL; - - /* needed for DB stuff */ - TALER_json_to_amount (j_amount, &amount); - j_items_tmp = json_object_get (j_details, "items"); - j_product_id = json_object_get (j_items_tmp, "product_id"); + jh_wire = TALER_json_from_data (&h_wire, sizeof (struct GNUNET_HashCode)); + /* adding the generated values in this JSON */ + if (NULL == (j_tmp = json_pack ("{s:o, s:o}", + "h_wire", jh_wire, + "timestamp", j_timestamp))) + return GNUNET_SYSERR; + + if (-1 == json_object_update (j_contract, j_tmp)) + return GNUNET_SYSERR; + /* needed for DB work */ + j_amount = json_object_get (j_contract, "amount"); + TALER_json_to_amount (j_amount, &amount); // produces a WARNING.. + + a = json_dumps (j_contract, JSON_COMPACT | JSON_PRESERVE_ORDER); #ifdef DEBUG - printf ("prod id is at %p, eval to %d\n", j_product_id, json_integer_value (j_product_id)); - return NULL; + str = json_dumps (j_amount, JSON_COMPACT | JSON_PRESERVE_ORDER); + printf ("amount : \n%s", str); + return GNUNET_SYSERR; #endif + /* TODO + Add a further field to the 'contract' table, indicating the timestamp + of this contract being finalized + */ - /* adding the generated values in this JSON */ - root = json_pack ("{s:o, s:o, s:I, s:s, s:o, s:o, s:o}", - "amount", j_amount, - "max fee", j_max_fee, - "trans_id", j_trans_id, - "h_wire", jh_wire, - "timestamp", j_timestamp, - "mints", j_mints, - "details", j_details); - - a = json_dumps (root, JSON_COMPACT | JSON_PRESERVE_ORDER); + GNUNET_CRYPTO_hash (a, strlen (a) + 1, &contract->h_contract_details); + contract->purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_CONTRACT); + contract->purpose.size = htonl (sizeof (struct Contract)); // DB mgmt if (GNUNET_SYSERR == MERCHANT_DB_contract_create (db_conn, &timestamp, &amount, + &contract->h_contract_details, (uint64_t) j_trans_id, // safe? a, nounce, - json_integer_value (j_product_id))); + json_integer_value (j_product_id))) + return GNUNET_SYSERR; + + free (a); + #ifdef OBSOLETE contract->h_wire = h_wire; TALER_amount_hton (&amount_nbo, &amount); @@ -153,15 +153,9 @@ MERCHANT_handle_contract (json_t *j_contract, contract->m = GNUNET_htonll ((uint64_t) j_trans_id); // safe? #endif - GNUNET_CRYPTO_hash (a, strlen (a) + 1, &contract->h_contract_details); - free (a); - contract->purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_CONTRACT); - #ifdef OBSOLETE contract->purpose.size = htonl (sizeof (struct ContractNBO)); #endif - contract->purpose.size = htonl (sizeof (struct Contract)); - - return root; + return GNUNET_OK; } diff --git a/src/backend-lib/taler_merchant_contract_lib.h b/src/backend-lib/taler_merchant_contract_lib.h @@ -66,13 +66,14 @@ GNUNET_NETWORK_STRUCT_END * @param kpriv merchant's private key * @param wire merchant's bank's details * @param sig where to store the signature -* @return pointer to the complete JSON; NULL upon errors +* @return GNUNET_OK if successful, GNUNET_SYSERR upon errors +* */ /* TODO: this handles a simplified version (for debugging purposes) of the contract. To expand to the full fledged version */ -json_t * +uint32_t MERCHANT_handle_contract (json_t *j_contract, PGconn *db_conn, const struct MERCHANT_WIREFORMAT_Sepa *wire, diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am @@ -7,7 +7,7 @@ bin_PROGRAMS = \ taler_merchant_httpd_SOURCES = \ taler-merchant-httpd.c \ merchant.c merchant.h \ - merchant_db.c merchant_db.h \ + ../backend-lib/merchant_db.c ../backend-lib/merchant_db.h \ taler-mint-httpd_parsing.c taler-mint-httpd_parsing.h \ taler-mint-httpd_responses.c taler-mint-httpd_responses.h \ ../backend-lib/taler-merchant-httpd_contract.h @@ -17,6 +17,7 @@ taler_merchant_httpd_LDADD = \ -ltalerutil \ -lmicrohttpd \ -ljansson \ + -lcurl \ -lgnunetutil \ $(top_srcdir)/src/backend-lib/libtalermerchant.la \ -ltalermint \ diff --git a/src/backend/merchant_db.c b/src/backend/merchant_db.c @@ -1,354 +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/merchant_db.c - * @brief database helper functions used by the merchant - * @author Sree Harsha Totakura <sreeharsha@totakura.in> - */ - -#include "platform.h" -#include <gnunet/gnunet_util_lib.h> -#include <taler/taler_util.h> -#include <taler/taler_pq_lib.h> -#include "merchant_db.h" - - -#define PQSQL_strerror(kind, cmd, res) \ - GNUNET_log_from (kind, "merchant-db", \ - "SQL %s failed at %s:%u with error: %s", \ - cmd, __FILE__, __LINE__, PQresultErrorMessage (res)); - -/** - * Shorthand for exit jumps. - */ -#define EXITIF(cond) \ - do { \ - if (cond) { GNUNET_break (0); goto EXITIF_exit; } \ - } while (0) - - -/** - * Connect to postgresql database - * - * @param cfg the configuration handle - * @return connection to the postgresql database; NULL upon error - */ -PGconn * -MERCHANT_DB_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - return GNUNET_POSTGRES_connect (cfg, "merchant-db"); -} - - -/** - * Disconnect from the database - * - * @param conn database handle to close - */ -void -MERCHANT_DB_disconnect (PGconn *conn) -{ - PQfinish (conn); -} - - -/** - * Initialize merchant tables - * - * @param conn the connection handle to postgres db. - * @param tmp GNUNET_YES if the tables are to be made temporary i.e. their - * contents are dropped when the @a conn is closed - * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure - */ -int -MERCHANT_DB_initialize (PGconn *conn, int tmp) -{ - const char *tmp_str = (1 == tmp) ? "TEMPORARY" : ""; - char *sql; - PGresult *res; - ExecStatusType status; - int ret; - - res = NULL; - (void) GNUNET_asprintf (&sql, - "BEGIN TRANSACTION;" - "CREATE %1$s TABLE IF NOT EXISTS contracts (" - "contract_id INT8 PRIMARY KEY," - "amount INT8 NOT NULL," - "amount_fraction INT4 NOT NULL," - "amount_currency VARCHAR(" TALER_CURRENCY_LEN_STR ") NOT NULL," - "description TEXT NOT NULL," - "nounce INT8 NOT NULL," - "expiry INT8 NOT NULL," - "product INT8 NOT NULL);" - "CREATE %1$s TABLE IF NOT EXISTS checkouts (" - "coin_pub BYTEA PRIMARY KEY," - "contract_id INT8 REFERENCES contracts(contract_id)," - "amount INT4 NOT NULL," - "amount_fraction INT4 NOT NULL," - "coin_sig BYTEA NOT NULL);", - tmp_str); - ret = GNUNET_POSTGRES_exec (conn, sql); - (void) GNUNET_POSTGRES_exec (conn, - (GNUNET_OK == ret) ? "COMMIT;" : "ROLLBACK;"); - GNUNET_free (sql); - if (GNUNET_OK != ret) - return ret; - - while (NULL != (res = PQgetResult (conn))) - { - status = PQresultStatus (res); - PQclear (res); - } - - EXITIF (NULL == (res = PQprepare - (conn, - "contract_create", - "INSERT INTO contracts" - "(contract_id, amount, amount_fraction, amount_currency," - "description, nounce, expiry, product) VALUES" - "($1, $2, $3, $4, $5, $6, $7, $8)", - 8, NULL))); - EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus(res))); - PQclear (res); - - EXITIF (NULL == (res = PQprepare - (conn, - "get_contract_product", - "SELECT (" - "product" - ") FROM contracts " - "WHERE (" - "contract_id=$1" - ")", - 1, NULL))); - EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus(res))); - PQclear (res); - - EXITIF (NULL == (res = PQprepare - (conn, - "checkout_create", - "INSERT INTO checkouts (" - "coin_pub," - "contract_id," - "amount," - "amount_fraction," - "coin_sig" - ") VALUES (" - "$1, $2, $3, $4, $5" - ")", - 5, NULL))); - EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus (res))); - PQclear (res); - - EXITIF (NULL == (res = PQprepare - (conn, - "get_checkout_product", - "SELECT (" - "product" - ") FROM contracts " - "WHERE " - "contract_id IN (" - "SELECT (contract_id) FROM checkouts " - "WHERE coin_pub=$1" - ")", - 1, NULL))); - EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus (res))); - PQclear (res); - - return GNUNET_OK; - - EXITIF_exit: - if (NULL != res) - { - PQSQL_strerror (GNUNET_ERROR_TYPE_ERROR, "PQprepare", res); - PQclear (res); - } - return GNUNET_SYSERR; -} - - -/** - * Inserts a contract record into the database and if successfull returns the - * serial number of the inserted row. - * - * @param conn the database connection - * @param expiry the time when the contract will expire - * @param amount the taler amount corresponding to the contract - * @param c_id contract's id - * @param desc descripition of the contract - * @param nounce a random 64-bit nounce - * @param product description to identify a product - * @return GNUNET_OK on success, GNUNET_SYSERR upon error - */ - -uint32_t -MERCHANT_DB_contract_create (PGconn *conn, - const struct GNUNET_TIME_Absolute *expiry, - const struct TALER_Amount *amount, - uint64_t c_id, - const char *desc, - uint64_t nounce, - uint64_t product) -{ - PGresult *res; - #if 0 - uint64_t expiry_ms_nbo; - uint64_t value_nbo; - uint32_t fraction_nbo; - uint64_t nounce_nbo; - #endif - ExecStatusType status; - - #if 0 - /* - NOTE: the conversion to nl(l) happens *inside* the query param helpers; since - the policy imposes this format for storing values. */ - value_nbo = GNUNET_htonll (amount->value); - fraction_nbo = GNUNET_htonll (amount->fraction); - nounce_nbo = GNUNET_htonll (nounce); - expiry_ms_nbo = GNUNET_htonll (expiry.abs_value_us); - product = GNUNET_htonll (product); - #endif - - /* ported. To be tested/compiled */ - struct TALER_PQ_QueryParam params[] = { - TALER_PQ_query_param_uint64 (&c_id), - TALER_PQ_query_param_amount (amount), - /* a *string* is being put in the following statement, - though the API talks about a *blob*. Will this be liked by - the DB ? */ - // the following inserts a string as a blob. Will Taler provide a param-from-string helper? - TALER_PQ_query_param_fixed_size (desc, strlen(desc)), - TALER_PQ_query_param_uint64 (&nounce), - TALER_PQ_query_param_absolute_time (expiry), - TALER_PQ_query_param_uint64 (&product), - TALER_PQ_query_param_end - }; - - /* NOTE: the statement is prepared by MERCHANT_DB_initialize function */ - res = TALER_PQ_exec_prepared (conn, "contract_create", params); - status = PQresultStatus (res); - EXITIF (PGRES_COMMAND_OK != status); - PQclear (res); - return GNUNET_OK; - - EXITIF_exit: - PQclear (res); - return GNUNET_SYSERR; -} - -long long -MERCHANT_DB_get_contract_product (PGconn *conn, - uint64_t contract_id) -{ - PGresult *res; - uint64_t product; - ExecStatusType status; - struct TALER_PQ_QueryParam params[] = { - TALER_PQ_query_param_uint64 (&contract_id), - TALER_PQ_query_param_end - }; - struct TALER_PQ_ResultSpec rs[] = { - TALER_PQ_result_spec_uint64 ("product", &product), - TALER_PQ_result_spec_end - }; - - contract_id = GNUNET_htonll (contract_id); - res = TALER_PQ_exec_prepared (conn, "get_contract_product", params); - status = PQresultStatus (res); - EXITIF (PGRES_TUPLES_OK != status); - EXITIF (1 != PQntuples (res)); - EXITIF (GNUNET_YES != TALER_PQ_extract_result (res, rs, 0)); - PQclear (res); - return GNUNET_ntohll ((uint64_t) product); - - EXITIF_exit: - PQclear (res); - return -1; -} - -unsigned int -MERCHANT_DB_checkout_create (PGconn *conn, - struct GNUNET_CRYPTO_rsa_PublicKey *coin_pub, - uint64_t transaction_id, - struct TALER_Amount *amount, - struct GNUNET_CRYPTO_rsa_Signature *coin_sig) -{ - PGresult *res; - ExecStatusType status; - uint32_t value_nbo; - uint32_t fraction_nbo; - struct TALER_PQ_QueryParam params[] = { - TALER_PQ_query_param_rsa_public_key (coin_pub), - TALER_PQ_query_param_uint64 (&transaction_id), - TALER_PQ_query_param_uint32 (&value_nbo), - TALER_PQ_query_param_uint32 (&fraction_nbo), - TALER_PQ_query_param_rsa_signature (coin_sig), - TALER_PQ_query_param_end - }; - - transaction_id = GNUNET_htonll (transaction_id); - value_nbo = htonl (amount->value); - fraction_nbo = htonl (amount->fraction); - res = TALER_PQ_exec_prepared (conn, "checkout_create", params); - status = PQresultStatus (res); - EXITIF (PGRES_COMMAND_OK != status); - PQclear (res); - return GNUNET_OK; - - EXITIF_exit: - PQclear (res); - return GNUNET_SYSERR; -} - - -long long -MERCHANT_DB_get_checkout_product (PGconn *conn, - struct GNUNET_CRYPTO_rsa_PublicKey *coin_pub) -{ - PGresult *res; - ExecStatusType status; - uint64_t product; - struct TALER_PQ_QueryParam params[] = { - TALER_PQ_query_param_rsa_public_key (coin_pub), - TALER_PQ_query_param_end - }; - struct TALER_PQ_ResultSpec rs[] = { - TALER_PQ_result_spec_uint64 ("product", &product), - TALER_PQ_result_spec_end - }; - - product = -1; - res = TALER_PQ_exec_prepared (conn, "get_checkout_product", params); - status = PQresultStatus (res); - EXITIF (PGRES_TUPLES_OK != status); - if (0 == PQntuples (res)) - { - TALER_LOG_DEBUG ("Checkout not found for given coin"); - goto EXITIF_exit; - } - EXITIF (1 != PQntuples (res)); - EXITIF (GNUNET_YES != TALER_PQ_extract_result (res, rs, 0)); - PQclear (res); - return GNUNET_ntohll ((uint64_t) product); - - EXITIF_exit: - PQclear (res); - return -1; -} -/* end of merchant-db.c */ diff --git a/src/backend/merchant_db.h b/src/backend/merchant_db.h @@ -1,101 +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/merchant_db.h - * @brief database helper functions used by the merchant - * @author Sree Harsha Totakura <sreeharsha@totakura.in> - */ - -#ifndef MERCHANT_DB_H -#define MERCHANT_DB_H - -#include <gnunet/gnunet_postgres_lib.h> -#include <taler/taler_util.h> - -/** - * Connect to postgresql database - * - * @param cfg the configuration handle - * @return connection to the postgresql database; NULL upon error - */ -PGconn * -MERCHANT_DB_connect (const struct GNUNET_CONFIGURATION_Handle *cfg); - - -/** - * Disconnect from the database - * - * @param conn database handle to close - */ -void -MERCHANT_DB_disconnect (PGconn *conn); - - -/** - * Initialize merchant tables - * - * @param conn the connection handle to postgres db. - * @param tmp GNUNET_YES if the tables are to be made temporary i.e. their - * contents are dropped when the @a conn is closed - * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure - */ -int -MERCHANT_DB_initialize (PGconn *conn, int tmp); - - -/** - * Inserts a contract record into the database and if successfull returns the - * serial number of the inserted row. - * - * @param conn the database connection - * @param expiry the time when the contract will expire - * @param amount the taler amount corresponding to the contract - * @param c_id this contract's identification number - * @param desc descripition of the contract - * @param nounce a random 64-bit nounce - * @param product description to identify a product - * @return GNUNET_OK on success, GNUNET_SYSERR upon error - */ - -uint32_t -MERCHANT_DB_contract_create (PGconn *conn, - const struct GNUNET_TIME_Absolute *expiry, - const struct TALER_Amount *amount, - uint64_t c_id, - const char *desc, - uint64_t nounce, - uint64_t product); - -long long -MERCHANT_DB_get_contract_product (PGconn *conn, - uint64_t contract_id); - -unsigned int -MERCHANT_DB_checkout_create (PGconn *conn, - struct GNUNET_CRYPTO_rsa_PublicKey *coin_pub, - uint64_t transaction_id, - struct TALER_Amount *amount, - struct GNUNET_CRYPTO_rsa_Signature *coin_sig); - - -long long -MERCHANT_DB_get_checkout_product (PGconn *conn, - struct GNUNET_CRYPTO_rsa_PublicKey *coin_pub); - -#endif /* MERCHANT_DB_H */ - -/* end of merchant-db.h */ diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c @@ -24,6 +24,7 @@ #include <microhttpd.h> #include <jansson.h> #include <gnunet/gnunet_util_lib.h> +#include <curl/curl.h> #include <taler/taler_json_lib.h> #include <taler/taler_mint_service.h> #include "taler-mint-httpd_parsing.h" @@ -151,7 +152,7 @@ unsigned int nmints; */ static unsigned int -generate_message (struct MHD_Response **resp, const char *msg) // this parameter was preceded by a '_' in its original file. Why? +generate_message (struct MHD_Response **resp, const char *msg) { unsigned int ret; @@ -281,6 +282,38 @@ request</h3></center></body></html>"; return GNUNET_SYSERR; } +/** + * Take the global wire details and return a JSON containing them, + * compliantly with the Taler's API. + * @param edate when the beneficiary wants this transfer to take place + * @return JSON representation of the wire details, NULL upon errors + */ + +static json_t * +get_wire_json (struct GNUNET_TIME_Absolute edate) +{ + + json_t *root; + json_t *j_edate; + json_t *j_nounce; + uint64_t nounce; + + nounce = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX); + j_nounce = json_integer (nounce); + + j_edate = TALER_json_from_abs (edate); + if (NULL == (root = json_pack ("{s:s, s:s, s:s, s:s, s:o}", + "type", "SEPA", + "IBAN", wire->iban, + "name", wire->name, + "BIC", wire->bic, + "edate", j_edate, + "r", json_integer_value (j_nounce)))) + return NULL; + + return root; +} + /** * A client has requested the given url using the given method @@ -344,27 +377,46 @@ url_handler (void *cls, struct Contract contract; #endif struct MHD_Response *resp; - json_t *j_contract_complete; json_t *root; + json_t *j_contract_complete; json_t *j_sig_enc; 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 *str; /* to debug JSONs */ - #if 1 + char *deposit_body; json_t *root_tmp; + json_t *j_refund_deadline; json_t *j_amount_tmp; + json_t *j_depperm; json_t *j_details_tmp; json_t *j_max_fee_tmp; - json_int_t j_trans_id_tmp; - #endif + json_int_t j_int_trans_id_tmp; + json_t *j_trans_id_tmp; + int64_t trans_id_tmp; + char *ub_sig; + char *coin_pub; + char *denom_key; + char *contract_sig; + char *h_contract; + struct GNUNET_HashCode h_json_wire; + struct TALER_Amount amount_tmp; + json_t *j_h_json_wire; + struct curl_slist *slist; + + struct GNUNET_TIME_Absolute now; + + CURL *curl; + CURLcode curl_res; int res = GNUNET_SYSERR; #define URL_HELLO "/hello" #define URL_CONTRACT "/contract" + #define URL_DEPPERM "/pay" no_destroy = 0; resp = NULL; status = MHD_HTTP_INTERNAL_SERVER_ERROR; @@ -379,6 +431,172 @@ url_handler (void *cls, } } + if (0 == strncasecmp (url, URL_DEPPERM, sizeof (URL_DEPPERM))) + { + 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; + + /* The frontend should supply a JSON in the format described in + http://link-to-specs : .. In practice, it just forwards what it + received from the wallet. + + Roughly, the backend must add to this JSON: + + 1. The merchant's public key + 2. A timestamp (?) + 3. wire (see mint's specs) + 4. h_wire + 5. refund deadline (?) + + (?) : may the frontend will handle dates ? + + */ + + #ifdef DEBUG + /* NOTE: there is no need to thoroughly unpack this JSON, since + the backend must just *add* fields to it */ + if (-1 == (json_unpack (root, + "{s:s, s:I, s:s, s:s, s:s}", + "ub_sig", &ub_sig, + "coin_pub", &coin_pub, + "denom_pub", &denom_key, + "H_contract", &h_contract, + "sig", &contract_sig))) + { + printf ("no unpack\n"); + status = MHD_HTTP_INTERNAL_SERVER_ERROR; + goto end; + } + + printf ("Got this deposit permission:\nub_sig: %s\ncoin_pub: %s\ndenom_key: %s\nsig: %s\n", + ub_sig, coin_pub, denom_key, contract_sig); + + return MHD_NO; + #endif + + /* TODO: Check if there is a row in 'contracts' table corresponding to this + contract ('s hash). This query has to return the trans_id and the amount for + this contract - faked values for now. See bug #XXXX */ + + /* FIXME fake trans_id */ + trans_id_tmp = (int64_t) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX); + + if (trans_id_tmp < 0) + j_trans_id_tmp = json_integer ((-1) * trans_id_tmp); + else + j_trans_id_tmp = json_integer (trans_id_tmp); + + /* FIXME fake amount to redeem */ + TALER_amount_get_zero ("EUR", &amount_tmp); + amount_tmp.value = 5; + j_amount_tmp = TALER_json_from_amount (&amount_tmp); + + /* Encoding merchant's key */ + GNUNET_CRYPTO_eddsa_key_get_public (privkey, &pub); + eddsa_pub_enc = TALER_json_from_data ((void *) &pub, sizeof (pub)); + + /* Timestamping 'now' */ + now = GNUNET_TIME_absolute_get (); + + /* getting the SEPA-aware JSON */ + if (NULL == (j_wire = get_wire_json (GNUNET_TIME_absolute_add (now, GNUNET_TIME_UNIT_WEEKS)))) + goto end; + + /* hash it*/ + if (GNUNET_SYSERR == TALER_hash_json (j_wire, &h_json_wire)) + goto end; + + j_h_json_wire = TALER_json_from_data (&h_json_wire, sizeof (struct GNUNET_HashCode)); + /* refund deadline */ + j_refund_deadline = TALER_json_from_abs (GNUNET_TIME_absolute_add (now, GNUNET_TIME_UNIT_WEEKS)); + + /* pack it!*/ + eddsa_pub_enc = TALER_json_from_data ((void *) &pub, sizeof (pub)); + + if (NULL == (j_depperm = json_pack ("{s:o, s:o, s:o, s:o, s:o, s:I, s:o}", + "merchant_pub", eddsa_pub_enc, + "timestamp", TALER_json_from_abs (now), + "wire", j_wire, + "H_wire", j_h_json_wire, + "refund_deadline", j_refund_deadline, + "transaction_id", json_integer_value (j_trans_id_tmp), + "f", j_amount_tmp))) + { + printf ("BAD depperm packaging\n"); + goto end; + } + + + /* melt to what received from the wallet */ + if (-1 == json_object_update (j_depperm, root)) + { + printf ("depperm response not built\n"); + goto end; + } + + #define DEBUGG + #ifdef DEBUG + str = json_dumps (j_depperm, JSON_INDENT(2) | JSON_PRESERVE_ORDER); + printf ("Depperm is: \n%s", str); + return MHD_NO; + #endif + + /* POST to mint's "/deposit" */ + curl = curl_easy_init (); + + if (curl) + { + + slist = curl_slist_append (slist, "Content-type: application/json"); + curl_easy_setopt (curl, CURLOPT_HTTPHEADER, slist); + + /* FIXME the mint's URL is be retrieved from the partial deposit permission + (received by the wallet) */ + curl_easy_setopt (curl, CURLOPT_URL, "http://demo.taler.net/deposit"); + + /* 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 (j_depperm, 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 rejected by mint\n"); + goto end; + } + else + printf ("deposit ok\n"); + + curl_easy_cleanup(curl); + + + } + + } + /* * To be called by the frontend passing the contract with some "holes" * which will be completed, stored in DB, signed, and returned @@ -431,32 +649,14 @@ url_handler (void *cls, } - if (-1 == (json_unpack (root, - "{s:o, s:o, s:I, s:o}", - "amount", &j_amount_tmp, - "max fee", &j_max_fee_tmp, - "trans_id", &j_trans_id_tmp, - "details", &j_details_tmp))) + if (-1 == (json_object_update (root, j_mints))) { - printf ("no unpack\n"); - status = MHD_HTTP_INTERNAL_SERVER_ERROR; + printf ("no mints specified in contract\n"); goto end; - } - - if (NULL == (root_tmp = json_pack ("{s:o, s:o, s:I, s:o, s:o}", - "amount", j_amount_tmp, - "max fee", j_max_fee_tmp, - "trans_id", j_trans_id_tmp, - "mints", j_mints, - "details", j_details_tmp))) - { - printf ("no pack\n"); - status = MHD_HTTP_INTERNAL_SERVER_ERROR; - goto end; - } - if (NULL == (j_contract_complete = MERCHANT_handle_contract (root_tmp, + } + if (NULL == (j_contract_complete = MERCHANT_handle_contract (root, db_conn, wire, &contract))) @@ -540,8 +740,6 @@ do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) } - - /** * Function called with information about who is auditing * a particular mint and what key the mint is using. @@ -550,7 +748,7 @@ do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) * @param keys information about the various keys used * by the mint */ -void +static void keys_mgmt_cb (void *cls, const struct TALER_MINT_Keys *keys) { /* which kind of mint's keys a merchant should need? Sign @@ -569,7 +767,7 @@ keys_mgmt_cb (void *cls, const struct TALER_MINT_Keys *keys) * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param config configuration */ -static void +void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *config) { @@ -592,7 +790,7 @@ run (void *cls, char *const *args, const char *cfgfile, &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_NO)); + EXITIF (GNUNET_OK != MERCHANT_DB_initialize (db_conn, GNUNET_YES)); EXITIF (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (config, "merchant", @@ -661,7 +859,7 @@ int main (int argc, char *const *argv) { - static const struct GNUNET_GETOPT_CommandLineOption options[] = { + static const struct GNUNET_GETOPT_CommandLineOption options[] = { {'t', "temp", NULL, gettext_noop ("Use temporary database tables"), GNUNET_NO, &GNUNET_GETOPT_set_one, &dry}, @@ -677,6 +875,4 @@ main (int argc, char *const *argv) return 3; return (GNUNET_OK == result) ? 0 : 1; - - } diff --git a/src/frontend/fake_wire_transfer.php b/src/frontend/fake_wire_transfer.php @@ -48,7 +48,7 @@ $json = json_encode (array ('reserve_pub' => $reserve_pk, 'wire' => array ('type' => 'test'), 'amount' => array ('value' => intval($kudos_amount), 'fraction' => 0, - 'currency' => 'KUDOS'))); + 'currency' => 'EUR'))); // TODO 'KUDOS' example needs 'KUDOS' denom keys .. // craft the HTTP request $req = new http\Client\Request ("POST", diff --git a/src/frontend/generate_taler_contract.php b/src/frontend/generate_taler_contract.php @@ -69,7 +69,7 @@ $value = $amount; // We don't have a fraction. $fraction = 0; // This is our 'toy' currency -$currency = "KUDOS"; +$currency = "EUR"; // NOTE: mint does NOT generate KUDOS denom. keys // The tax for this deal $teatax = array ('value' => 1, 'fraction' => 0, diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am @@ -1,5 +1,5 @@ # This Makefile.am is in the public domain -AM_CPPFLAGS = -I$(top_srcdir)/src/include +AM_CPPFLAGS = -I$(top_srcdir)/src/include -I$(top_srcdir)/src/backend-lib/ bin_PROGRAMS = \ merchant-contract-test @@ -10,7 +10,7 @@ bin_PROGRAMS = \ merchant_contract_test_SOURCES = \ merchant-contract-test.c \ merchant.c \ - merchant_db.c merchant_db.h + ../backend-lib/merchant_db.c ../backend-lib/merchant_db.h merchant_contract_test_LDADD = \ $(LIBGCRYPT_LIBS) \ diff --git a/src/tests/merchant-contract-test.c b/src/tests/merchant-contract-test.c @@ -109,7 +109,7 @@ run (void *cls, char *const *args, const char *cfgfile, db_conn = MERCHANT_DB_connect (config); - if (GNUNET_OK != MERCHANT_DB_initialize (db_conn, GNUNET_NO)) + if (GNUNET_OK != MERCHANT_DB_initialize (db_conn, GNUNET_YES)) { printf ("no db init'd\n"); result = GNUNET_SYSERR; @@ -135,7 +135,7 @@ run (void *cls, char *const *args, const char *cfgfile, */ /* Amount */ - TALER_amount_get_zero ("KUDOS", &amount); + TALER_amount_get_zero ("EUR", &amount); j_amount = TALER_json_from_amount (&amount); /* Transaction ID*/ @@ -203,11 +203,12 @@ run (void *cls, char *const *args, const char *cfgfile, /* End of 'item' object definition */ printf ("[j_item address: %p]\n", j_item); - + /* Delivery date: OPTIONAL FIELD */ deldate = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), GNUNET_TIME_UNIT_WEEKS); j_deldate = TALER_json_from_abs (deldate); + /* Delivery location: OPTIONAL FIELD */ @@ -252,28 +253,29 @@ run (void *cls, char *const *args, const char *cfgfile, "Q1WVGRGC1F4W7RYC6M23AEGFEXQEHQ730K3GG0B67VPHQSRR75H0"); j_fake_contract = json_pack ("{s:o, s:o, s:I, s:o, s:o}", - "amount", j_amount, - "max fee", j_max_fee, - "trans_id", json_integer_value (j_id), - "mints", j_mints, - "details", j_details); + "amount", j_amount, + "max fee", j_max_fee, + "trans_id", json_integer_value (j_id), + "mints", j_mints, + "details", j_details); #if 0 str = json_dumps (j_fake_contract, JSON_INDENT(2) | JSON_PRESERVE_ORDER); printf ("%s\n", str); return; #endif - if (NULL == (j_root = MERCHANT_handle_contract (j_fake_contract, - db_conn, - wire, - &contract))) + + if (GNUNET_SYSERR == MERCHANT_handle_contract (j_fake_contract, + db_conn, + wire, + &contract)) { printf ("errors in contract handling\n"); return; } #if 1 - str = json_dumps (j_root, JSON_INDENT(2) | JSON_PRESERVE_ORDER); + str = json_dumps (j_fake_contract, JSON_INDENT(2) | JSON_PRESERVE_ORDER); printf ("%s\n", str); return; #endif diff --git a/src/tests/merchant_db.c b/src/tests/merchant_db.c @@ -1,354 +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/merchant_db.c - * @brief database helper functions used by the merchant - * @author Sree Harsha Totakura <sreeharsha@totakura.in> - */ - -#include "platform.h" -#include <gnunet/gnunet_util_lib.h> -#include <taler/taler_util.h> -#include <taler/taler_pq_lib.h> -#include "merchant_db.h" - - -#define PQSQL_strerror(kind, cmd, res) \ - GNUNET_log_from (kind, "merchant-db", \ - "SQL %s failed at %s:%u with error: %s", \ - cmd, __FILE__, __LINE__, PQresultErrorMessage (res)); - -/** - * Shorthand for exit jumps. - */ -#define EXITIF(cond) \ - do { \ - if (cond) { GNUNET_break (0); goto EXITIF_exit; } \ - } while (0) - - -/** - * Connect to postgresql database - * - * @param cfg the configuration handle - * @return connection to the postgresql database; NULL upon error - */ -PGconn * -MERCHANT_DB_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - return GNUNET_POSTGRES_connect (cfg, "merchant-db"); -} - - -/** - * Disconnect from the database - * - * @param conn database handle to close - */ -void -MERCHANT_DB_disconnect (PGconn *conn) -{ - PQfinish (conn); -} - - -/** - * Initialize merchant tables - * - * @param conn the connection handle to postgres db. - * @param tmp GNUNET_YES if the tables are to be made temporary i.e. their - * contents are dropped when the @a conn is closed - * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure - */ -int -MERCHANT_DB_initialize (PGconn *conn, int tmp) -{ - const char *tmp_str = (1 == tmp) ? "TEMPORARY" : ""; - char *sql; - PGresult *res; - ExecStatusType status; - int ret; - - res = NULL; - (void) GNUNET_asprintf (&sql, - "BEGIN TRANSACTION;" - "CREATE %1$s TABLE IF NOT EXISTS contracts (" - "contract_id INT8 PRIMARY KEY," - "amount INT8 NOT NULL," - "amount_fraction INT4 NOT NULL," - "amount_currency VARCHAR(" TALER_CURRENCY_LEN_STR ") NOT NULL," - "description TEXT NOT NULL," - "nounce INT8 NOT NULL," - "expiry INT8 NOT NULL," - "product INT8 NOT NULL);" - "CREATE %1$s TABLE IF NOT EXISTS checkouts (" - "coin_pub BYTEA PRIMARY KEY," - "contract_id INT8 REFERENCES contracts(contract_id)," - "amount INT4 NOT NULL," - "amount_fraction INT4 NOT NULL," - "coin_sig BYTEA NOT NULL);", - tmp_str); - ret = GNUNET_POSTGRES_exec (conn, sql); - (void) GNUNET_POSTGRES_exec (conn, - (GNUNET_OK == ret) ? "COMMIT;" : "ROLLBACK;"); - GNUNET_free (sql); - if (GNUNET_OK != ret) - return ret; - - while (NULL != (res = PQgetResult (conn))) - { - status = PQresultStatus (res); - PQclear (res); - } - - EXITIF (NULL == (res = PQprepare - (conn, - "contract_create", - "INSERT INTO contracts" - "(contract_id, amount, amount_fraction, amount_currency," - "description, nounce, expiry, product) VALUES" - "($1, $2, $3, $4, $5, $6, $7, $8)", - 8, NULL))); - EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus(res))); - PQclear (res); - - EXITIF (NULL == (res = PQprepare - (conn, - "get_contract_product", - "SELECT (" - "product" - ") FROM contracts " - "WHERE (" - "contract_id=$1" - ")", - 1, NULL))); - EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus(res))); - PQclear (res); - - EXITIF (NULL == (res = PQprepare - (conn, - "checkout_create", - "INSERT INTO checkouts (" - "coin_pub," - "contract_id," - "amount," - "amount_fraction," - "coin_sig" - ") VALUES (" - "$1, $2, $3, $4, $5" - ")", - 5, NULL))); - EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus (res))); - PQclear (res); - - EXITIF (NULL == (res = PQprepare - (conn, - "get_checkout_product", - "SELECT (" - "product" - ") FROM contracts " - "WHERE " - "contract_id IN (" - "SELECT (contract_id) FROM checkouts " - "WHERE coin_pub=$1" - ")", - 1, NULL))); - EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus (res))); - PQclear (res); - - return GNUNET_OK; - - EXITIF_exit: - if (NULL != res) - { - PQSQL_strerror (GNUNET_ERROR_TYPE_ERROR, "PQprepare", res); - PQclear (res); - } - return GNUNET_SYSERR; -} - - -/** - * Inserts a contract record into the database and if successfull returns the - * serial number of the inserted row. - * - * @param conn the database connection - * @param expiry the time when the contract will expire - * @param amount the taler amount corresponding to the contract - * @param c_id contract's id - * @param desc descripition of the contract - * @param nounce a random 64-bit nounce - * @param product description to identify a product - * @return GNUNET_OK on success, GNUNET_SYSERR upon error - */ - -uint32_t -MERCHANT_DB_contract_create (PGconn *conn, - const struct GNUNET_TIME_Absolute *expiry, - const struct TALER_Amount *amount, - uint64_t c_id, - const char *desc, - uint64_t nounce, - uint64_t product) -{ - PGresult *res; - #if 0 - uint64_t expiry_ms_nbo; - uint64_t value_nbo; - uint32_t fraction_nbo; - uint64_t nounce_nbo; - #endif - ExecStatusType status; - - #if 0 - /* - NOTE: the conversion to nl(l) happens *inside* the query param helpers; since - the policy imposes this format for storing values. */ - value_nbo = GNUNET_htonll (amount->value); - fraction_nbo = GNUNET_htonll (amount->fraction); - nounce_nbo = GNUNET_htonll (nounce); - expiry_ms_nbo = GNUNET_htonll (expiry.abs_value_us); - product = GNUNET_htonll (product); - #endif - - /* ported. To be tested/compiled */ - struct TALER_PQ_QueryParam params[] = { - TALER_PQ_query_param_uint64 (&c_id), - TALER_PQ_query_param_amount (amount), - /* a *string* is being put in the following statement, - though the API talks about a *blob*. Will this be liked by - the DB ? */ - // the following inserts a string as a blob. Will Taler provide a param-from-string helper? - TALER_PQ_query_param_fixed_size (desc, strlen(desc)), - TALER_PQ_query_param_uint64 (&nounce), - TALER_PQ_query_param_absolute_time (expiry), - TALER_PQ_query_param_uint64 (&product), - TALER_PQ_query_param_end - }; - - /* NOTE: the statement is prepared by MERCHANT_DB_initialize function */ - res = TALER_PQ_exec_prepared (conn, "contract_create", params); - status = PQresultStatus (res); - EXITIF (PGRES_COMMAND_OK != status); - PQclear (res); - return GNUNET_OK; - - EXITIF_exit: - PQclear (res); - return GNUNET_SYSERR; -} - -long long -MERCHANT_DB_get_contract_product (PGconn *conn, - uint64_t contract_id) -{ - PGresult *res; - uint64_t product; - ExecStatusType status; - struct TALER_PQ_QueryParam params[] = { - TALER_PQ_query_param_uint64 (&contract_id), - TALER_PQ_query_param_end - }; - struct TALER_PQ_ResultSpec rs[] = { - TALER_PQ_result_spec_uint64 ("product", &product), - TALER_PQ_result_spec_end - }; - - contract_id = GNUNET_htonll (contract_id); - res = TALER_PQ_exec_prepared (conn, "get_contract_product", params); - status = PQresultStatus (res); - EXITIF (PGRES_TUPLES_OK != status); - EXITIF (1 != PQntuples (res)); - EXITIF (GNUNET_YES != TALER_PQ_extract_result (res, rs, 0)); - PQclear (res); - return GNUNET_ntohll ((uint64_t) product); - - EXITIF_exit: - PQclear (res); - return -1; -} - -unsigned int -MERCHANT_DB_checkout_create (PGconn *conn, - struct GNUNET_CRYPTO_rsa_PublicKey *coin_pub, - uint64_t transaction_id, - struct TALER_Amount *amount, - struct GNUNET_CRYPTO_rsa_Signature *coin_sig) -{ - PGresult *res; - ExecStatusType status; - uint32_t value_nbo; - uint32_t fraction_nbo; - struct TALER_PQ_QueryParam params[] = { - TALER_PQ_query_param_rsa_public_key (coin_pub), - TALER_PQ_query_param_uint64 (&transaction_id), - TALER_PQ_query_param_uint32 (&value_nbo), - TALER_PQ_query_param_uint32 (&fraction_nbo), - TALER_PQ_query_param_rsa_signature (coin_sig), - TALER_PQ_query_param_end - }; - - transaction_id = GNUNET_htonll (transaction_id); - value_nbo = htonl (amount->value); - fraction_nbo = htonl (amount->fraction); - res = TALER_PQ_exec_prepared (conn, "checkout_create", params); - status = PQresultStatus (res); - EXITIF (PGRES_COMMAND_OK != status); - PQclear (res); - return GNUNET_OK; - - EXITIF_exit: - PQclear (res); - return GNUNET_SYSERR; -} - - -long long -MERCHANT_DB_get_checkout_product (PGconn *conn, - struct GNUNET_CRYPTO_rsa_PublicKey *coin_pub) -{ - PGresult *res; - ExecStatusType status; - uint64_t product; - struct TALER_PQ_QueryParam params[] = { - TALER_PQ_query_param_rsa_public_key (coin_pub), - TALER_PQ_query_param_end - }; - struct TALER_PQ_ResultSpec rs[] = { - TALER_PQ_result_spec_uint64 ("product", &product), - TALER_PQ_result_spec_end - }; - - product = -1; - res = TALER_PQ_exec_prepared (conn, "get_checkout_product", params); - status = PQresultStatus (res); - EXITIF (PGRES_TUPLES_OK != status); - if (0 == PQntuples (res)) - { - TALER_LOG_DEBUG ("Checkout not found for given coin"); - goto EXITIF_exit; - } - EXITIF (1 != PQntuples (res)); - EXITIF (GNUNET_YES != TALER_PQ_extract_result (res, rs, 0)); - PQclear (res); - return GNUNET_ntohll ((uint64_t) product); - - EXITIF_exit: - PQclear (res); - return -1; -} -/* end of merchant-db.c */ diff --git a/src/tests/merchant_db.h b/src/tests/merchant_db.h @@ -1,101 +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/merchant_db.h - * @brief database helper functions used by the merchant - * @author Sree Harsha Totakura <sreeharsha@totakura.in> - */ - -#ifndef MERCHANT_DB_H -#define MERCHANT_DB_H - -#include <gnunet/gnunet_postgres_lib.h> -#include <taler/taler_util.h> - -/** - * Connect to postgresql database - * - * @param cfg the configuration handle - * @return connection to the postgresql database; NULL upon error - */ -PGconn * -MERCHANT_DB_connect (const struct GNUNET_CONFIGURATION_Handle *cfg); - - -/** - * Disconnect from the database - * - * @param conn database handle to close - */ -void -MERCHANT_DB_disconnect (PGconn *conn); - - -/** - * Initialize merchant tables - * - * @param conn the connection handle to postgres db. - * @param tmp GNUNET_YES if the tables are to be made temporary i.e. their - * contents are dropped when the @a conn is closed - * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure - */ -int -MERCHANT_DB_initialize (PGconn *conn, int tmp); - - -/** - * Inserts a contract record into the database and if successfull returns the - * serial number of the inserted row. - * - * @param conn the database connection - * @param expiry the time when the contract will expire - * @param amount the taler amount corresponding to the contract - * @param c_id this contract's identification number - * @param desc descripition of the contract - * @param nounce a random 64-bit nounce - * @param product description to identify a product - * @return GNUNET_OK on success, GNUNET_SYSERR upon error - */ - -uint32_t -MERCHANT_DB_contract_create (PGconn *conn, - const struct GNUNET_TIME_Absolute *expiry, - const struct TALER_Amount *amount, - uint64_t c_id, - const char *desc, - uint64_t nounce, - uint64_t product); - -long long -MERCHANT_DB_get_contract_product (PGconn *conn, - uint64_t contract_id); - -unsigned int -MERCHANT_DB_checkout_create (PGconn *conn, - struct GNUNET_CRYPTO_rsa_PublicKey *coin_pub, - uint64_t transaction_id, - struct TALER_Amount *amount, - struct GNUNET_CRYPTO_rsa_Signature *coin_sig); - - -long long -MERCHANT_DB_get_checkout_product (PGconn *conn, - struct GNUNET_CRYPTO_rsa_PublicKey *coin_pub); - -#endif /* MERCHANT_DB_H */ - -/* end of merchant-db.h */