diff options
Diffstat (limited to 'src/backend-lib')
-rw-r--r-- | src/backend-lib/merchant_db.c | 127 | ||||
-rw-r--r-- | src/backend-lib/merchant_db.h | 51 | ||||
-rw-r--r-- | src/backend-lib/taler-merchant-httpd_contract.c | 142 | ||||
-rw-r--r-- | src/backend-lib/taler_merchant_contract_lib.h | 51 |
4 files changed, 250 insertions, 121 deletions
diff --git a/src/backend-lib/merchant_db.c b/src/backend-lib/merchant_db.c index 539af683..eef10f22 100644 --- a/src/backend-lib/merchant_db.c +++ b/src/backend-lib/merchant_db.c @@ -94,7 +94,9 @@ MERCHANT_DB_initialize (PGconn *conn, int tmp) "amount_currency VARCHAR(" TALER_CURRENCY_LEN_STR ") NOT NULL," "description TEXT NOT NULL," "nounce INT8 NOT NULL," + "timestamp INT8 NOT NULL," "expiry INT8 NOT NULL," + "edate INT8 NOT NULL," "product INT8 NOT NULL);" "CREATE %1$s TABLE IF NOT EXISTS checkouts (" "coin_pub BYTEA PRIMARY KEY," @@ -120,13 +122,33 @@ MERCHANT_DB_initialize (PGconn *conn, int tmp) (conn, "contract_create", "INSERT INTO contracts" - "(contract_id, hash, amount, amount_fraction, amount_currency," - "description, nounce, expiry, product) VALUES" - "($1, $2, $3, $4, $5, $6, $7, $8, $9)", - 9, NULL))); + "(contract_id, hash, timestamp, expiry, edate, amount, amount_fraction, amount_currency," + "description, nounce, product) VALUES" + "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", + 11, NULL))); EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus(res))); PQclear (res); + + /* Query aimed to get the contract's nounce and edate which will be + both used for regenerating a 'wire' JSON object to insert into the + deposit permission. Implicitly, this query will tell whether a contract + was created or not */ + + EXITIF (NULL == (res = PQprepare + (conn, + "get_contract_hash", + "SELECT (" + "nounce, edate" + ") FROM contracts " + "WHERE (" + "hash=$1" + ")", + 1, NULL))); + EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus(res))); + PQclear (res); + + EXITIF (NULL == (res = PQprepare (conn, "get_contract_product", @@ -184,23 +206,28 @@ 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 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 - * @param product description to identify a product - * @return GNUNET_OK on success, GNUNET_SYSERR upon error - */ +* Inserts a contract record into the database and if successfull returns the +* serial number of the inserted row. +* +* @param conn the database connection +* @param timestamp the timestamp of this contract +* @param expiry the time when the contract will expire +* @param edate when the merchant wants to receive the wire transfer corresponding +* to this deal (this value is also a field inside the 'wire' JSON format) +* @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 +* @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 GNUNET_TIME_Absolute timestamp, + const struct GNUNET_TIME_Absolute expiry, + struct GNUNET_TIME_Absolute edate, const struct TALER_Amount *amount, const struct GNUNET_HashCode *h_contract, uint64_t c_id, @@ -217,18 +244,18 @@ MERCHANT_DB_contract_create (PGconn *conn, #endif ExecStatusType status; - /* 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_absolute_time (×tamp), + TALER_PQ_query_param_absolute_time (&expiry), + TALER_PQ_query_param_absolute_time (&edate), 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? + /* A *string* is being put in the following statement, + though the column is declared as *blob*. Will this be + liked by the DB ? */ 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 }; @@ -345,3 +372,55 @@ MERCHANT_DB_get_checkout_product (PGconn *conn, return -1; } /* end of merchant-db.c */ + + +/** +* The query gets a contract's nounce and edate used to reproduce +* a 'wire' JSON object. This function is also useful to check whether +* a claimed contract existed or not. +* @param conn handle to the DB +* @param h_contract the parameter for the row to match against +* @param nounce where to store the found nounce +* @param edate where to store the found edate +* @return GNUNET_OK on success, GNUNET_SYSERR upon errors +* +*/ + +uint32_t +MERCHANT_DB_get_contract_values (PGconn *conn, + const struct GNUNET_HashCode *h_contract, + uint64_t *nounce, + struct GNUNET_TIME_Absolute *edate) +{ + PGresult *res; + ExecStatusType status; + + struct TALER_PQ_QueryParam params[] = { + TALER_PQ_query_param_fixed_size (h_contract, sizeof (struct GNUNET_HashCode)), + TALER_PQ_query_param_end + }; + + struct TALER_PQ_ResultSpec rs[] = { + TALER_PQ_result_spec_uint64 ("nounce", nounce), + TALER_PQ_result_spec_absolute_time ("edate", edate), + TALER_PQ_result_spec_end + }; + + 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 ("Contract not found"); + goto EXITIF_exit; + } + EXITIF (1 != PQntuples (res)); + EXITIF (GNUNET_YES != TALER_PQ_extract_result (res, rs, 0)); + PQclear (res); + return GNUNET_OK; + + EXITIF_exit: + PQclear (res); + return GNUNET_SYSERR; +} diff --git a/src/backend-lib/merchant_db.h b/src/backend-lib/merchant_db.h index 2b00f325..4c4577c7 100644 --- a/src/backend-lib/merchant_db.h +++ b/src/backend-lib/merchant_db.h @@ -58,23 +58,28 @@ 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 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 - * @param product description to identify a product - * @return GNUNET_OK on success, GNUNET_SYSERR upon error - */ +* Inserts a contract record into the database and if successfull returns the +* serial number of the inserted row. +* +* @param conn the database connection +* @param timestamp the timestamp of this contract +* @param expiry the time when the contract will expire +* @param edate when the merchant wants to receive the wire transfer corresponding +* to this deal (this value is also a field inside the 'wire' JSON format) +* @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 +* @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 GNUNET_TIME_Absolute timestamp, + const struct GNUNET_TIME_Absolute expiry, + struct GNUNET_TIME_Absolute edate, const struct TALER_Amount *amount, const struct GNUNET_HashCode *h_contract, uint64_t c_id, @@ -98,6 +103,24 @@ long long MERCHANT_DB_get_checkout_product (PGconn *conn, struct GNUNET_CRYPTO_rsa_PublicKey *coin_pub); +/** +* The query gets a contract's nounce and edate used to reproduce +* a 'wire' JSON object. This function is also useful to check whether +* a claimed contract existed or not. +* @param conn handle to the DB +* @param h_contract the parameter for the row to match against +* @param nounce where to store the found nounce +* @param edate where to store the found edate +* @return GNUNET_OK on success, GNUNET_SYSERR upon errors +* +*/ + +uint32_t +MERCHANT_DB_get_contract_values (PGconn *conn, + const struct GNUNET_HashCode *h_contract, + uint64_t *nounce, + struct GNUNET_TIME_Absolute *edate); + #endif /* MERCHANT_DB_H */ /* end of merchant-db.h */ diff --git a/src/backend-lib/taler-merchant-httpd_contract.c b/src/backend-lib/taler-merchant-httpd_contract.c index 6a008455..7cfda21c 100644 --- a/src/backend-lib/taler-merchant-httpd_contract.c +++ b/src/backend-lib/taler-merchant-httpd_contract.c @@ -49,14 +49,57 @@ hash_wireformat (uint64_t nounce, const struct MERCHANT_WIREFORMAT_Sepa *wire) } /** + * Take the global wire details and return a JSON containing them, + * compliantly with the Taler's API. + * @param wire the merchant's wire details + * @param nounce the nounce for hashing the wire details with + * @param edate when the beneficiary wants this transfer to take place + * @return JSON representation of the wire details, NULL upon errors + */ + +json_t * +MERCHANT_get_wire_json (const struct MERCHANT_WIREFORMAT_Sepa *wire, + uint64_t nounce, + const struct GNUNET_TIME_Absolute edate) + +{ + + json_t *root; + json_t *j_edate; + json_t *j_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; +} + + + +/** * Take from the frontend the (partly) generated contract and fill * 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. It will be * hold the new values. * @param db_conn the handle to the local DB -* @param wire merchant's bank's details * @param contract where to store the (subset of the) contract to be (still) signed +* @param timestamp contract's timestamp (shall be generated by the merchant) +* @param expiry the time when the contract will expire +* @param edate when the merchant wants to receive the wire transfer corresponding +* to this deal (this value is also a field inside the 'wire' JSON format) +* @param nounce the nounce used to hash the wire details +* @param contract_str where to store the (stringified) contract * @return GNUNET_OK on success; GNUNET_SYSERR upon errors */ @@ -65,97 +108,56 @@ hash_wireformat (uint64_t nounce, const struct MERCHANT_WIREFORMAT_Sepa *wire) * still allocated */ uint32_t -MERCHANT_handle_contract (json_t *j_contract, +MERCHANT_handle_contract (const json_t *j_contract, PGconn *db_conn, - const struct MERCHANT_WIREFORMAT_Sepa *wire, - struct Contract *contract) + struct Contract *contract, + struct GNUNET_TIME_Absolute timestamp, + struct GNUNET_TIME_Absolute expiry, + struct GNUNET_TIME_Absolute edate, + uint64_t nounce, + const char *contract_str) { - json_t *j_tmp; - json_t *j_details; - json_t *j_timestamp; - json_t *jh_wire; json_t *j_amount; - json_t *j_mints; - json_t *j_max_fee; + json_int_t j_product_id; json_int_t j_trans_id; - uint64_t nounce; - json_t *j_product_id; - json_t *j_items_tmp; - char *a; - #define DaEBUG - #ifdef DEBUG - char *str; - #endif - struct GNUNET_HashCode h_wire; - struct GNUNET_TIME_Absolute timestamp; struct TALER_Amount amount; - struct TALER_AmountNBO amount_nbo; - nounce = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX); - // timing mgmt - timestamp = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), - 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); - 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)) + + /* Extracting values useful for DB work. Only gettable from the JSON + since they are generated by the frontend */ + if (-1 == json_unpack (j_contract, "{s:o, s:I, s:{s:{s:I}}}", + "amount", &j_amount, + "trans_id", &j_trans_id, + "details", "items", + "product_id", &j_product_id)) + { + printf ("no unpacking\n"); 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 - 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 - - */ - - GNUNET_CRYPTO_hash (a, strlen (a) + 1, &contract->h_contract_details); + contract_str = json_dumps (j_contract, JSON_COMPACT | JSON_PRESERVE_ORDER); + GNUNET_CRYPTO_hash (contract_str, strlen (contract_str) + 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, - ×tamp, + timestamp, + expiry, + edate, &amount, &contract->h_contract_details, (uint64_t) j_trans_id, // safe? - a, + contract_str, nounce, - json_integer_value (j_product_id))) + (uint64_t) j_product_id)) return GNUNET_SYSERR; - free (a); - - #ifdef OBSOLETE - contract->h_wire = h_wire; - TALER_amount_hton (&amount_nbo, &amount); - contract->amount = amount_nbo; - contract->t = GNUNET_TIME_absolute_hton (timestamp); - contract->m = GNUNET_htonll ((uint64_t) j_trans_id); // safe? - #endif - - #ifdef OBSOLETE - contract->purpose.size = htonl (sizeof (struct ContractNBO)); - #endif - return GNUNET_OK; } diff --git a/src/backend-lib/taler_merchant_contract_lib.h b/src/backend-lib/taler_merchant_contract_lib.h index 19fbe2f0..9094e223 100644 --- a/src/backend-lib/taler_merchant_contract_lib.h +++ b/src/backend-lib/taler_merchant_contract_lib.h @@ -57,24 +57,49 @@ struct ContractNBO GNUNET_NETWORK_STRUCT_END + +/** + * Take the global wire details and return a JSON containing them, + * compliantly with the Taler's API. + * @param wire the merchant's wire details + * @param nounce the nounce for hashing the wire details with + * @param edate when the beneficiary wants this transfer to take place + * @return JSON representation of the wire details, NULL upon errors + */ + +json_t * +MERCHANT_get_wire_json (const struct MERCHANT_WIREFORMAT_Sepa *wire, + uint64_t nounce, + struct GNUNET_TIME_Absolute edate); + /** * Take from the frontend the (partly) generated contract and fill -* the missing values in it; for example, the SEPA-aware values. -* Moreover, it stores the contract in the DB and does the signature of it. -* @param contract parsed contract, originated by the frontend +* 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. It will be +* hold the new values. * @param db_conn the handle to the local DB -* @param kpriv merchant's private key -* @param wire merchant's bank's details -* @param sig where to store the signature -* @return GNUNET_OK if successful, GNUNET_SYSERR upon errors -* +* @param contract where to store the (subset of the) contract to be (still) signed +* @param timestamp contract's timestamp (shall be generated by the merchant) +* @param expiry the time when the contract will expire +* @param edate when the merchant wants to receive the wire transfer corresponding +* to this deal (this value is also a field inside the 'wire' JSON format) +* @param nounce the nounce used to hash the wire details +* @param contract_str where to store the hashed (stringified) contract +* @return GNUNET_OK on success; GNUNET_SYSERR upon errors */ -/* TODO: this handles a simplified version (for debugging purposes) - of the contract. To expand to the full fledged version */ +/** +* TODO: inspect reference counting and, accordingly, free those json_t*(s) +* still allocated */ uint32_t -MERCHANT_handle_contract (json_t *j_contract, +MERCHANT_handle_contract (const json_t *j_contract, PGconn *db_conn, - const struct MERCHANT_WIREFORMAT_Sepa *wire, - struct Contract *contract); + struct Contract *contract, + struct GNUNET_TIME_Absolute timestamp, + struct GNUNET_TIME_Absolute expiry, + struct GNUNET_TIME_Absolute edate, + uint64_t nounce, + const char *contract_str); + |