From 346c351e5ff2fc184f1c044f4ffbf82bc80fe655 Mon Sep 17 00:00:00 2001 From: Marcello Stanisci Date: Fri, 22 Dec 2017 21:22:57 +0100 Subject: redefining/adding bank error codes --- src/include/taler_error_codes.h | 83 +++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 33 deletions(-) (limited to 'src/include') diff --git a/src/include/taler_error_codes.h b/src/include/taler_error_codes.h index 2d0c8325..759e6fc7 100644 --- a/src/include/taler_error_codes.h +++ b/src/include/taler_error_codes.h @@ -1503,67 +1503,84 @@ enum TALER_ErrorCode /* *************** Taler BANK/FAKEBANK error codes *************** */ /** - * Authentication failed for an unspecified request. - * To return when the view name is not available, or - * no specific error code is defined yet. + * The request cannot be served because the client failed to + * login. To be returned along HTTP 401 Unauthorized. */ - TALER_EC_BANK_NOT_AUTHORIZED = 5000, + TALER_EC_BANK_REJECT_LOGIN_FAILED = 5312, /** - * The bank could not find the bank account specified - * in the request. Returned with a status code of MHD_HTTP_NOT_FOUND. + * The transaction cannot be rejected becasue it does not exist + * at the bank. To be returned along HTTP 404 Not Found. */ - TALER_EC_BANK_UNKNOWN_ACCOUNT = 5001, + TALER_EC_BANK_REJECT_TRANSACTION_NOT_FOUND = 5301, /** - * Authentication failed for the /admin/add/incoming request. - * Returned with a status code of MHD_HTTP_FORBIDDEN. + * The client does not own the account credited by the transaction + * which is to be rejected, so it has no rights do reject it. To be + * returned along HTTP 403 Forbidden. */ - TALER_EC_BANK_TRANSFER_NOT_AUHTORIZED = 5100, + TALER_EC_BANK_REJECT_NO_RIGHTS = 5313, /** - * The wire transfer cannot be done because the debitor would - * reach a unallowed debit. + * The POSTed JSON at /reject was invalid. To be returned along + * HTTP 400 Bad Request. */ - TALER_EC_BANK_TRANSFER_DEBIT = 5101, + TALER_EC_BANK_REJECT_JSON_INVALID = 5306, /** - * The wire transfer cannot be done because the credit and - * debit account are the same. + * A URL parameter for /history was missing. To be returned along + * HTTP 400 Bad Request. */ - TALER_EC_BANK_TRANSFER_SAME_ACCOUNT = 5102, + TALER_EC_BANK_HISTORY_PARAMETER_MISSING = 5208, /** - * Authentication failed for the /history request. - * Returned with a status code of MHD_HTTP_FORBIDDEN. + * A URL parameter for /history was malformed. To be returned along + * HTTP 400 Bad Request. */ - TALER_EC_BANK_HISTORY_NOT_AUHTORIZED = 5200, + TALER_EC_BANK_HISTORY_PARAMETER_MALFORMED = 5209, /** - * The bank library had trouble obtaining a valid - * HTTP response. - * Returned with a status code of 0. + * The client failed to login for /history. To be returned along + * HTTP 401 Unauthorized. */ - TALER_EC_BANK_HISTORY_HTTP_FAILURE = 5201, + TALER_EC_BANK_HISTORY_LOGIN_FAILED = 5212, /** - * The bank could not find the wire transfer that was supposed to - * be rejected. - * Returned with a status code of MHD_HTTP_NOT_FOUND. + * The bank had trouble obtaining a valid HTTP response. To be returned + * along status code 0. */ - TALER_EC_BANK_REJECT_NOT_FOUND = 5300, + TALER_EC_BANK_HISTORY_HTTP_FAILURE = 5213, /** - * Authentication failed for the /reject request. - * Returned with a status code of MHD_HTTP_FORBIDDEN. + * The debit account for /admin/add/incoming is not known to the + * bank. To be returned along HTTP 404 Not Found. */ - TALER_EC_BANK_REJECT_NOT_AUTHORIZED = 5301, + TALER_EC_BANK_ADD_INCOMING_UNKNOWN_ACCOUNT = 5100, /** - * The client wants to reject a transaction where they are - * not the _credit_ party, impossible! + * The client specified the same bank account for both the credit + * and the debit account. The bank will not accomplish this operation. + * To be returned along HTTP 403 Forbidden. */ - TALER_EC_BANK_REJECT_NO_RIGHTS = 5302, + TALER_EC_BANK_ADD_INCOMING_SAME_ACCOUNT = 5102, + + /** + * The operation would put the client in a debit situation which is + * forbidden to them. To return along HTTP 403 Forbidden. + */ + TALER_EC_BANK_ADD_INCOMING_UNALLOWED_DEBIT = 5103, + + /** + * The client POSTed an invalid JSON. To be returned along HTTP + * 400 Bad Request. + */ + TALER_EC_BANK_ADD_INCOMING_JSON_INVALID = 5106, + + /** + * The client failed to login for /admin/add/incoming. To be returned + * along HTTP 401 Unauthorized. + */ + TALER_EC_BANK_ADD_INCOMING_LOGIN_FAILED = 5112, /** * End of error code range. -- cgit v1.2.3 From 4f2ad1051b1433974e5d598b1546202797729e31 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 1 Jan 2018 22:10:26 +0100 Subject: change 'f' to 'contribution' in /deposit --- src/exchange-lib/exchange_api_deposit.c | 2 +- src/exchange/taler-exchange-httpd_deposit.c | 6 +++++- src/include/taler_error_codes.h | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) (limited to 'src/include') diff --git a/src/exchange-lib/exchange_api_deposit.c b/src/exchange-lib/exchange_api_deposit.c index d90b1aa7..76e3e4da 100644 --- a/src/exchange-lib/exchange_api_deposit.c +++ b/src/exchange-lib/exchange_api_deposit.c @@ -454,7 +454,7 @@ TALER_EXCHANGE_deposit (struct TALER_EXCHANGE_Handle *exchange, " s:o," /* merchant_pub */ " s:o, s:o," /* refund_deadline, wire_deadline */ " s:o}", /* coin_sig */ - "f", TALER_JSON_from_amount (amount), + "contribution", TALER_JSON_from_amount (amount), "wire", wire_details, "H_wire", GNUNET_JSON_from_data_auto (&h_wire), "h_contract_terms", GNUNET_JSON_from_data_auto (h_contract_terms), diff --git a/src/exchange/taler-exchange-httpd_deposit.c b/src/exchange/taler-exchange-httpd_deposit.c index b7fb3452..542c56c9 100644 --- a/src/exchange/taler-exchange-httpd_deposit.c +++ b/src/exchange/taler-exchange-httpd_deposit.c @@ -149,6 +149,8 @@ deposit_transaction (void *cls, { struct TALER_Amount amount_without_fee; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "/deposit replay, accepting again!\n"); GNUNET_assert (GNUNET_OK == TALER_amount_subtract (&amount_without_fee, &deposit->amount_with_fee, @@ -191,6 +193,8 @@ deposit_transaction (void *cls, if (0 < TALER_amount_cmp (&spent, &dc->value)) { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Deposited coin has insufficient funds left!\n"); *mhd_ret = TEH_RESPONSE_reply_coin_insufficient_funds (connection, TALER_EC_DEPOSIT_INSUFFICIENT_FUNDS, tl); @@ -376,7 +380,7 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh, struct GNUNET_HashCode my_h_wire; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_json ("wire", &wire), - TALER_JSON_spec_amount ("f", &deposit.amount_with_fee), + TALER_JSON_spec_amount ("contribution", &deposit.amount_with_fee), TALER_JSON_spec_denomination_public_key ("denom_pub", &deposit.coin.denom_pub), TALER_JSON_spec_denomination_signature ("ub_sig", &deposit.coin.denom_sig), GNUNET_JSON_spec_fixed_auto ("coin_pub", &deposit.coin.coin_pub), diff --git a/src/include/taler_error_codes.h b/src/include/taler_error_codes.h index 759e6fc7..d90bd4f3 100644 --- a/src/include/taler_error_codes.h +++ b/src/include/taler_error_codes.h @@ -1001,6 +1001,7 @@ enum TALER_ErrorCode TALER_EC_PAY_REFUND_DEADLINE_PAST_WIRE_TRANSFER_DEADLINE = 2114, /** + * The request fails to provide coins for the payment. * This response is provided with HTTP status code * MHD_HTTP_BAD_REQUEST. -- cgit v1.2.3 From ff0d4bb6eb99d446a891b97b9fa48027b3b553b2 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 1 Jan 2018 23:26:34 +0100 Subject: add TALER_EXCHANGE_refund2, make sure fee test initializes all amounts; update ChangeLog --- ChangeLog | 10 +++++ src/exchange-lib/exchange_api_refund.c | 73 ++++++++++++++++++++++++++++++---- src/exchangedb/test_exchangedb_fees.c | 6 +++ src/include/taler_exchange_service.h | 44 ++++++++++++++++++++ 4 files changed, 125 insertions(+), 8 deletions(-) (limited to 'src/include') diff --git a/ChangeLog b/ChangeLog index 2948a76c..2c18ef5a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +Mon Jan 1 23:15:37 CET 2018 + Add TALER_EXCHANGE_refund2() API call to libtalerexchange. -CG + +Tue Dec 14 23:15:37 CET 2018 + Eliminated /admin/add/incoming. + Add taler-bank-transfer tool. -CG + +Sun Dec 10 19:03:11 CET 2018 + Implement support for optimized refresh protocol. -CG + Thu Nov 2 17:39:40 CET 2017 Limit amount values to 2^53 as we always wanted (#5167). -CG diff --git a/src/exchange-lib/exchange_api_refund.c b/src/exchange-lib/exchange_api_refund.c index a39dd23a..ef1d66b9 100644 --- a/src/exchange-lib/exchange_api_refund.c +++ b/src/exchange-lib/exchange_api_refund.c @@ -243,12 +243,8 @@ TALER_EXCHANGE_refund (struct TALER_EXCHANGE_Handle *exchange, TALER_EXCHANGE_RefundResultCallback cb, void *cb_cls) { - struct TALER_EXCHANGE_RefundHandle *rh; - struct GNUNET_CURL_Context *ctx; struct TALER_RefundRequestPS rr; struct TALER_MerchantSignatureP merchant_sig; - json_t *refund_obj; - CURL *eh; GNUNET_assert (GNUNET_YES == MAH_handle_is_ready (exchange)); @@ -267,7 +263,68 @@ TALER_EXCHANGE_refund (struct TALER_EXCHANGE_Handle *exchange, GNUNET_CRYPTO_eddsa_sign (&merchant_priv->eddsa_priv, &rr.purpose, &merchant_sig.eddsa_sig)); - refund_obj = json_pack ("{s:o, s:o," /* amount/fee */ + return TALER_EXCHANGE_refund2 (exchange, + amount, + refund_fee, + h_contract_terms, + coin_pub, + rtransaction_id, + &rr.merchant, + &merchant_sig, + cb, + cb_cls); +} + + +/** + * Submit a refund request to the exchange and get the exchange's + * response. This API is used by a merchant. Note that + * while we return the response verbatim to the caller for further + * processing, we do already verify that the response is well-formed + * (i.e. that signatures included in the response are all valid). If + * the exchange's reply is not well-formed, we return an HTTP status code + * of zero to @a cb. + * + * The @a exchange must be ready to operate (i.e. have + * finished processing the /keys reply). If this check fails, we do + * NOT initiate the transaction with the exchange and instead return NULL. + * + * @param exchange the exchange handle; the exchange must be ready to operate + * @param amount the amount to be refunded; must be larger than the refund fee + * (as that fee is still being subtracted), and smaller than the amount + * (with deposit fee) of the original deposit contribution of this coin + * @param refund_fee fee applicable to this coin for the refund + * @param h_contract_terms hash of the contact of the merchant with the customer that is being refunded + * @param coin_pub coin’s public key of the coin from the original deposit operation + * @param rtransaction_id transaction id for the transaction between merchant and customer (of refunding operation); + * this is needed as we may first do a partial refund and later a full refund. If both + * refunds are also over the same amount, we need the @a rtransaction_id to make the disjoint + * refund requests different (as requests are idempotent and otherwise the 2nd refund might not work). + * @param merchant_pub public key of the merchant + * @param merchant_sig signature affirming the refund from the merchant + * @param cb the callback to call when a reply for this request is available + * @param cb_cls closure for the above callback + * @return a handle for this request; NULL if the inputs are invalid (i.e. + * signatures fail to verify). In this case, the callback is not called. + */ +struct TALER_EXCHANGE_RefundHandle * +TALER_EXCHANGE_refund2 (struct TALER_EXCHANGE_Handle *exchange, + const struct TALER_Amount *amount, + const struct TALER_Amount *refund_fee, + const struct GNUNET_HashCode *h_contract_terms, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + uint64_t rtransaction_id, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const struct TALER_MerchantSignatureP *merchant_sig, + TALER_EXCHANGE_RefundResultCallback cb, + void *cb_cls) +{ + struct TALER_EXCHANGE_RefundHandle *rh; + struct GNUNET_CURL_Context *ctx; + json_t *refund_obj; + CURL *eh; + +refund_obj = json_pack ("{s:o, s:o," /* amount/fee */ " s:o, s:o," /* h_contract_terms, coin_pub */ " s:I," /* rtransaction id */ " s:o, s:o}", /* merchant_pub, merchant_sig */ @@ -276,8 +333,8 @@ TALER_EXCHANGE_refund (struct TALER_EXCHANGE_Handle *exchange, "h_contract_terms", GNUNET_JSON_from_data_auto (h_contract_terms), "coin_pub", GNUNET_JSON_from_data_auto (coin_pub), "rtransaction_id", (json_int_t) rtransaction_id, - "merchant_pub", GNUNET_JSON_from_data_auto (&rr.merchant), - "merchant_sig", GNUNET_JSON_from_data_auto (&merchant_sig) + "merchant_pub", GNUNET_JSON_from_data_auto (merchant_pub), + "merchant_sig", GNUNET_JSON_from_data_auto (merchant_sig) ); if (NULL == refund_obj) { @@ -294,7 +351,7 @@ TALER_EXCHANGE_refund (struct TALER_EXCHANGE_Handle *exchange, rh->depconf.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND); rh->depconf.h_contract_terms = *h_contract_terms; rh->depconf.coin_pub = *coin_pub; - rh->depconf.merchant = rr.merchant; + rh->depconf.merchant = *merchant_pub; rh->depconf.rtransaction_id = GNUNET_htonll (rtransaction_id); TALER_amount_hton (&rh->depconf.refund_amount, amount); diff --git a/src/exchangedb/test_exchangedb_fees.c b/src/exchangedb/test_exchangedb_fees.c index 2bee7745..0c9eceaf 100644 --- a/src/exchangedb/test_exchangedb_fees.c +++ b/src/exchangedb/test_exchangedb_fees.c @@ -86,6 +86,9 @@ main (int argc, GNUNET_assert (GNUNET_OK == TALER_string_to_amount ("EUR:1.0", &af->wire_fee)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount ("EUR:1.0", + &af->closing_fee)); sign_af (af, priv); n = GNUNET_new (struct TALER_EXCHANGEDB_AggregateFees); @@ -94,6 +97,9 @@ main (int argc, GNUNET_assert (GNUNET_OK == TALER_string_to_amount ("EUR:0.1", &n->wire_fee)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount ("EUR:0.1", + &n->closing_fee)); sign_af (n, priv); af->next = n; diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index da39a179..f1af114c 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -716,6 +716,50 @@ TALER_EXCHANGE_refund (struct TALER_EXCHANGE_Handle *exchange, void *cb_cls); +/** + * Submit a refund request to the exchange and get the exchange's + * response. This API is used by a merchant. Note that + * while we return the response verbatim to the caller for further + * processing, we do already verify that the response is well-formed + * (i.e. that signatures included in the response are all valid). If + * the exchange's reply is not well-formed, we return an HTTP status code + * of zero to @a cb. + * + * The @a exchange must be ready to operate (i.e. have + * finished processing the /keys reply). If this check fails, we do + * NOT initiate the transaction with the exchange and instead return NULL. + * + * @param exchange the exchange handle; the exchange must be ready to operate + * @param amount the amount to be refunded; must be larger than the refund fee + * (as that fee is still being subtracted), and smaller than the amount + * (with deposit fee) of the original deposit contribution of this coin + * @param refund_fee fee applicable to this coin for the refund + * @param h_contract_terms hash of the contact of the merchant with the customer that is being refunded + * @param coin_pub coin’s public key of the coin from the original deposit operation + * @param rtransaction_id transaction id for the transaction between merchant and customer (of refunding operation); + * this is needed as we may first do a partial refund and later a full refund. If both + * refunds are also over the same amount, we need the @a rtransaction_id to make the disjoint + * refund requests different (as requests are idempotent and otherwise the 2nd refund might not work). + * @param merchant_pub public key of the merchant + * @param merchant_sig signature affirming the refund from the merchant + * @param cb the callback to call when a reply for this request is available + * @param cb_cls closure for the above callback + * @return a handle for this request; NULL if the inputs are invalid (i.e. + * signatures fail to verify). In this case, the callback is not called. + */ +struct TALER_EXCHANGE_RefundHandle * +TALER_EXCHANGE_refund2 (struct TALER_EXCHANGE_Handle *exchange, + const struct TALER_Amount *amount, + const struct TALER_Amount *refund_fee, + const struct GNUNET_HashCode *h_contract_terms, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + uint64_t rtransaction_id, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const struct TALER_MerchantSignatureP *merchant_sig, + TALER_EXCHANGE_RefundResultCallback cb, + void *cb_cls); + + /** * Cancel a refund permission request. This function cannot be used * on a request handle if a response is already served for it. If -- cgit v1.2.3 From 41b5dde70945b6cb468e412caf6ab7ecd7f56651 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Tue, 2 Jan 2018 14:43:15 +0100 Subject: implement select_refunds_by_coin in exchangedb plugin --- src/exchangedb/plugin_exchangedb_postgres.c | 123 ++++++++++++++++++++++++++++ src/include/taler_exchangedb_plugin.h | 40 +++++++++ 2 files changed, 163 insertions(+) (limited to 'src/include') diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index 36ae3e54..9c91259b 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -3032,6 +3032,128 @@ postgres_insert_refund (void *cls, } +/** + * Closure for #get_refunds_cb(). + */ +struct SelectRefundContext +{ + /** + * Function to call on each result. + */ + TALER_EXCHANGEDB_RefundCoinCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; + + /** + * Set to #GNUNET_SYSERR on error. + */ + int status; +}; + + +/** + * Function to be called with the results of a SELECT statement + * that has returned @a num_results results. + * + * @param cls closure of type `struct SelectRefundContext *` + * @param result the postgres result + * @param num_result the number of results in @a result + */ +static void +get_refunds_cb (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct SelectRefundContext *srctx = cls; + + for (unsigned int i=0;istatus = GNUNET_SYSERR; + return; + } + if (GNUNET_OK != + srctx->cb (srctx->cb_cls, + &merchant_pub, + &merchant_sig, + &h_contract, + rtransaction_id, + &amount_with_fee, + &refund_fee)) + return; + } +} + + +/** + * Select refunds by @a coin_pub. + * + * @param cls closure of plugin + * @param session database handle to use + * @param coin_pub coin to get refunds for + * @param cb function to call for each refund found + * @param cb_cls closure for @a cb + * @return query result status + */ +static enum GNUNET_DB_QueryStatus +postgres_select_refunds_by_coin (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + TALER_EXCHANGEDB_RefundCoinCallback cb, + void *cb_cls) +{ + enum GNUNET_DB_QueryStatus qs; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (coin_pub), + GNUNET_PQ_query_param_end + }; + struct SelectRefundContext srctx = { + .cb = cb, + .cb_cls = cb_cls, + .status = GNUNET_OK + }; + + qs = GNUNET_PQ_eval_prepared_multi_select (session->conn, + "get_refunds_by_coin", + params, + &get_refunds_cb, + &srctx); + if (GNUNET_SYSERR == srctx.status) + return GNUNET_DB_STATUS_HARD_ERROR; + return qs; +} + + /** * Lookup refresh melt commitment data under the given @a rc. * @@ -6236,6 +6358,7 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) plugin->iterate_matching_deposits = &postgres_iterate_matching_deposits; plugin->insert_deposit = &postgres_insert_deposit; plugin->insert_refund = &postgres_insert_refund; + plugin->select_refunds_by_coin = &postgres_select_refunds_by_coin; plugin->insert_melt = &postgres_insert_melt; plugin->get_melt = &postgres_get_melt; plugin->insert_refresh_reveal = &postgres_insert_refresh_reveal; diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index e64b0ad4..c531d838 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -732,6 +732,29 @@ typedef int const struct TALER_RefreshCommitmentP *rc); +/** + * Callback invoked with information about refunds applicable + * to a particular coin. + * + * @param cls closure + * @param merchant_pub public key of merchant who authorized refund + * @param merchant_sig signature of merchant authorizing refund + * @param h_contract hash of contract being refunded + * @param rtransaction_id refund transaction ID + * @param amount_with_fee amount being refunded + * @param refund_fee fee the exchange keeps for the refund processing + * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop + */ +typedef int +(*TALER_EXCHANGEDB_RefundCoinCallback)(void *cls, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const struct TALER_MerchantSignatureP *merchant_sig, + const struct GNUNET_HashCode *h_contract, + uint64_t rtransaction_id, + const struct TALER_Amount *amount_with_fee, + const struct TALER_Amount *refund_fee); + + /** * Information about a coin that was revealed to the exchange * during /refresh/reveal. @@ -1358,6 +1381,23 @@ struct TALER_EXCHANGEDB_Plugin struct TALER_EXCHANGEDB_Session *session, const struct TALER_EXCHANGEDB_Refund *refund); + /** + * Select refunds by @a coin_pub. + * + * @param cls closure of plugin + * @param session database handle to use + * @param coin_pub coin to get refunds for + * @param cb function to call for each refund found + * @param cb_cls closure for @a cb + * @return query result status + */ + enum GNUNET_DB_QueryStatus + (*select_refunds_by_coin)(void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + TALER_EXCHANGEDB_RefundCoinCallback cb, + void *cb_cls); + /** * Mark a deposit as tiny, thereby declaring that it cannot be -- cgit v1.2.3 From 5587732f5276621ada83a53d1fb0ee8b6f80032b Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 4 Jan 2018 00:41:19 +0100 Subject: fix auditor to properly verify wire fee signatures and more gracefully handle arithmetic amount issue --- src/auditor/taler-auditor.c | 14 +++++++++-- src/exchange-lib/test_exchange_api.c | 2 +- src/exchange/taler-exchange-aggregator.c | 1 + src/exchange/taler-exchange-httpd_track_transfer.c | 2 ++ src/exchangedb/plugin_exchangedb_postgres.c | 27 ++++++++++++++++++++-- src/exchangedb/test_exchangedb.c | 23 ++++++++++++++---- src/include/taler_exchangedb_plugin.h | 4 ++++ 7 files changed, 64 insertions(+), 9 deletions(-) (limited to 'src/include') diff --git a/src/auditor/taler-auditor.c b/src/auditor/taler-auditor.c index 870a81a4..89f04460 100644 --- a/src/auditor/taler-auditor.c +++ b/src/auditor/taler-auditor.c @@ -1664,10 +1664,15 @@ struct WireFeeInfo struct GNUNET_TIME_Absolute end_date; /** - * How high is the fee. + * How high is the wire fee. */ struct TALER_Amount wire_fee; + /** + * How high is the closing fee. + */ + struct TALER_Amount closing_fee; + }; @@ -1815,6 +1820,7 @@ check_transaction_history (const struct TALER_CoinSpendPublicKeyP *coin_pub, struct TALER_Amount spent; struct TALER_Amount value; struct TALER_Amount merchant_loss; + struct TALER_Amount merchant_delta; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Checking transaction history of coin %s\n", @@ -2043,7 +2049,7 @@ check_transaction_history (const struct TALER_CoinSpendPublicKeyP *coin_pub, /* Finally, update @a merchant_gain by subtracting what he "lost" from refunds */ if (GNUNET_SYSERR == - TALER_amount_subtract (merchant_gain, + TALER_amount_subtract (&merchant_delta, merchant_gain, &merchant_loss)) { @@ -2055,6 +2061,7 @@ check_transaction_history (const struct TALER_CoinSpendPublicKeyP *coin_pub, 0); return GNUNET_SYSERR; } + *merchant_gain = merchant_delta; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Coin %s contributes %s to contract %s\n", TALER_B2S (coin_pub), @@ -2276,6 +2283,7 @@ get_wire_fee (struct AggregationContext *ac, &wfi->start_date, &wfi->end_date, &wfi->wire_fee, + &wfi->closing_fee, &master_sig)) { GNUNET_break (0); @@ -2299,6 +2307,8 @@ get_wire_fee (struct AggregationContext *ac, wp.end_date = GNUNET_TIME_absolute_hton (wfi->end_date); TALER_amount_hton (&wp.wire_fee, &wfi->wire_fee); + TALER_amount_hton (&wp.closing_fee, + &wfi->closing_fee); if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_WIRE_FEES, &wp.purpose, diff --git a/src/exchange-lib/test_exchange_api.c b/src/exchange-lib/test_exchange_api.c index a1aa38c7..3a9cfd1a 100644 --- a/src/exchange-lib/test_exchange_api.c +++ b/src/exchange-lib/test_exchange_api.c @@ -3566,7 +3566,7 @@ run (void *cls) .label = "check-empty-after-refund" }, -#if 0 +#if 1 /* Test refunded coins are never executed, even past refund deadline */ { .oc = OC_ADMIN_ADD_INCOMING, diff --git a/src/exchange/taler-exchange-aggregator.c b/src/exchange/taler-exchange-aggregator.c index 3de5630d..c9ff958f 100644 --- a/src/exchange/taler-exchange-aggregator.c +++ b/src/exchange/taler-exchange-aggregator.c @@ -374,6 +374,7 @@ update_fees (struct WirePlugin *wp, p->start_date, p->end_date, &p->wire_fee, + &p->closing_fee, &p->master_sig); if (qs < 0) { diff --git a/src/exchange/taler-exchange-httpd_track_transfer.c b/src/exchange/taler-exchange-httpd_track_transfer.c index 4d28096b..38c6c29e 100644 --- a/src/exchange/taler-exchange-httpd_track_transfer.c +++ b/src/exchange/taler-exchange-httpd_track_transfer.c @@ -352,6 +352,7 @@ track_transfer_transaction (void *cls, struct GNUNET_TIME_Absolute wire_fee_start_date; struct GNUNET_TIME_Absolute wire_fee_end_date; struct TALER_MasterSignatureP wire_fee_master_sig; + struct TALER_Amount closing_fee; ctx->is_valid = GNUNET_NO; ctx->wdd_head = NULL; @@ -393,6 +394,7 @@ track_transfer_transaction (void *cls, &wire_fee_start_date, &wire_fee_end_date, &ctx->wire_fee, + &closing_fee, &wire_fee_master_sig); if (0 >= qs) { diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index 7e1ef54e..84774641 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -383,6 +383,9 @@ postgres_create_tables (void *cls) ",wire_fee_val INT8 NOT NULL" ",wire_fee_frac INT4 NOT NULL" ",wire_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ",closing_fee_val INT8 NOT NULL" + ",closing_fee_frac INT4 NOT NULL" + ",closing_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" ",master_sig BYTEA NOT NULL CHECK (LENGTH(master_sig)=64)" ",PRIMARY KEY (wire_method, start_date)" /* this combo must be unique */ ");"), @@ -1170,6 +1173,9 @@ postgres_prepare (PGconn *db_conn) ",wire_fee_val" ",wire_fee_frac" ",wire_fee_curr" + ",closing_fee_val" + ",closing_fee_frac" + ",closing_fee_curr" ",master_sig" " FROM wire_fee" " WHERE wire_method=$1" @@ -1185,10 +1191,13 @@ postgres_prepare (PGconn *db_conn) ",wire_fee_val" ",wire_fee_frac" ",wire_fee_curr" + ",closing_fee_val" + ",closing_fee_frac" + ",closing_fee_curr" ",master_sig" ") VALUES " - "($1, $2, $3, $4, $5, $6, $7);", - 7), + "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);", + 19), /* Used in #postgres_store_wire_transfer_out */ GNUNET_PQ_make_prepare ("insert_wire_out", "INSERT INTO wire_out " @@ -4356,6 +4365,7 @@ postgres_insert_aggregation_tracking (void *cls, * @param[out] start_date when does the fee go into effect * @param[out] end_date when does the fee end being valid * @param[out] wire_fee how high is the wire transfer fee + * @param[out] closing_fee how high is the closing fee * @param[out] master_sig signature over the above by the exchange master key * @return status of the transaction */ @@ -4367,6 +4377,7 @@ postgres_get_wire_fee (void *cls, struct GNUNET_TIME_Absolute *start_date, struct GNUNET_TIME_Absolute *end_date, struct TALER_Amount *wire_fee, + struct TALER_Amount *closing_fee, struct TALER_MasterSignatureP *master_sig) { struct GNUNET_PQ_QueryParam params[] = { @@ -4378,6 +4389,7 @@ postgres_get_wire_fee (void *cls, TALER_PQ_result_spec_absolute_time ("start_date", start_date), TALER_PQ_result_spec_absolute_time ("end_date", end_date), TALER_PQ_result_spec_amount ("wire_fee", wire_fee), + TALER_PQ_result_spec_amount ("closing_fee", closing_fee), GNUNET_PQ_result_spec_auto_from_type ("master_sig", master_sig), GNUNET_PQ_result_spec_end }; @@ -4398,6 +4410,7 @@ postgres_get_wire_fee (void *cls, * @param start_date when does the fee go into effect * @param end_date when does the fee end being valid * @param wire_fee how high is the wire transfer fee + * @param closing_fee how high is the closing fee * @param master_sig signature over the above by the exchange master key * @return transaction status code */ @@ -4408,6 +4421,7 @@ postgres_insert_wire_fee (void *cls, struct GNUNET_TIME_Absolute start_date, struct GNUNET_TIME_Absolute end_date, const struct TALER_Amount *wire_fee, + const struct TALER_Amount *closing_fee, const struct TALER_MasterSignatureP *master_sig) { struct GNUNET_PQ_QueryParam params[] = { @@ -4415,10 +4429,12 @@ postgres_insert_wire_fee (void *cls, TALER_PQ_query_param_absolute_time (&start_date), TALER_PQ_query_param_absolute_time (&end_date), TALER_PQ_query_param_amount (wire_fee), + TALER_PQ_query_param_amount (closing_fee), GNUNET_PQ_query_param_auto_from_type (master_sig), GNUNET_PQ_query_param_end }; struct TALER_Amount wf; + struct TALER_Amount cf; struct TALER_MasterSignatureP sig; struct GNUNET_TIME_Absolute sd; struct GNUNET_TIME_Absolute ed; @@ -4431,6 +4447,7 @@ postgres_insert_wire_fee (void *cls, &sd, &ed, &wf, + &cf, &sig); if (qs < 0) return qs; @@ -4449,6 +4466,12 @@ postgres_insert_wire_fee (void *cls, GNUNET_break (0); return GNUNET_DB_STATUS_HARD_ERROR; } + if (0 != TALER_amount_cmp (closing_fee, + &cf)) + { + GNUNET_break (0); + return GNUNET_DB_STATUS_HARD_ERROR; + } if ( (sd.abs_value_us != start_date.abs_value_us) || (ed.abs_value_us != end_date.abs_value_us) ) { diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c index 62ff2a74..a0eb50f0 100644 --- a/src/exchangedb/test_exchangedb.c +++ b/src/exchangedb/test_exchangedb.c @@ -1062,10 +1062,12 @@ test_wire_fees (struct TALER_EXCHANGEDB_Session *session) struct GNUNET_TIME_Absolute start_date; struct GNUNET_TIME_Absolute end_date; struct TALER_Amount wire_fee; + struct TALER_Amount closing_fee; struct TALER_MasterSignatureP master_sig; struct GNUNET_TIME_Absolute sd; struct GNUNET_TIME_Absolute ed; struct TALER_Amount fee; + struct TALER_Amount fee2; struct TALER_MasterSignatureP ms; start_date = GNUNET_TIME_absolute_get (); @@ -1075,6 +1077,9 @@ test_wire_fees (struct TALER_EXCHANGEDB_Session *session) GNUNET_assert (GNUNET_OK == TALER_string_to_amount (CURRENCY ":1.424242", &wire_fee)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":2.424242", + &closing_fee)); GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, &master_sig, sizeof (master_sig)); @@ -1085,6 +1090,7 @@ test_wire_fees (struct TALER_EXCHANGEDB_Session *session) start_date, end_date, &wire_fee, + &closing_fee, &master_sig)) { GNUNET_break (0); @@ -1097,6 +1103,7 @@ test_wire_fees (struct TALER_EXCHANGEDB_Session *session) start_date, end_date, &wire_fee, + &closing_fee, &master_sig)) { GNUNET_break (0); @@ -1112,6 +1119,7 @@ test_wire_fees (struct TALER_EXCHANGEDB_Session *session) &sd, &ed, &fee, + &fee2, &ms)) { GNUNET_break (0); @@ -1125,6 +1133,7 @@ test_wire_fees (struct TALER_EXCHANGEDB_Session *session) &sd, &ed, &fee, + &fee2, &ms)) { GNUNET_break (0); @@ -1134,6 +1143,8 @@ test_wire_fees (struct TALER_EXCHANGEDB_Session *session) (ed.abs_value_us != end_date.abs_value_us) || (0 != TALER_amount_cmp (&fee, &wire_fee)) || + (0 != TALER_amount_cmp (&fee2, + &closing_fee)) || (0 != memcmp (&ms, &master_sig, sizeof (ms))) ) @@ -1956,7 +1967,8 @@ run (void *cls) refund.merchant_pub = deposit.merchant_pub; RND_BLK (&refund.merchant_sig); refund.h_contract_terms = deposit.h_contract_terms; - refund.rtransaction_id = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); + refund.rtransaction_id = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + UINT64_MAX); refund.refund_amount = deposit.amount_with_fee; refund.refund_fee = fee_refund; FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != @@ -2198,9 +2210,11 @@ main (int argc, NULL); plugin_name++; (void) GNUNET_asprintf (&testname, - "test-exchange-db-%s", plugin_name); + "test-exchange-db-%s", + plugin_name); (void) GNUNET_asprintf (&config_filename, - "%s.conf", testname); + "%s.conf", + testname); cfg = GNUNET_CONFIGURATION_create (); if (GNUNET_OK != GNUNET_CONFIGURATION_parse (cfg, @@ -2211,7 +2225,8 @@ main (int argc, GNUNET_free (testname); return 2; } - GNUNET_SCHEDULER_run (&run, cfg); + GNUNET_SCHEDULER_run (&run, + cfg); GNUNET_CONFIGURATION_destroy (cfg); GNUNET_free (config_filename); GNUNET_free (testname); diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index c531d838..ae38856a 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -1698,6 +1698,7 @@ struct TALER_EXCHANGEDB_Plugin * @param start_date when does the fee go into effect * @param end_date when does the fee end being valid * @param wire_fee how high is the wire transfer fee + * @param closing_fee how high is the closing fee * @param master_sig signature over the above by the exchange master key * @return transaction status code */ @@ -1708,6 +1709,7 @@ struct TALER_EXCHANGEDB_Plugin struct GNUNET_TIME_Absolute start_date, struct GNUNET_TIME_Absolute end_date, const struct TALER_Amount *wire_fee, + const struct TALER_Amount *closing_fee, const struct TALER_MasterSignatureP *master_sig); @@ -1721,6 +1723,7 @@ struct TALER_EXCHANGEDB_Plugin * @param[out] start_date when does the fee go into effect * @param[out] end_date when does the fee end being valid * @param[out] wire_fee how high is the wire transfer fee + * @param[out] closing_fee how high is the closing fee * @param[out] master_sig signature over the above by the exchange master key * @return query status of the transaction */ @@ -1732,6 +1735,7 @@ struct TALER_EXCHANGEDB_Plugin struct GNUNET_TIME_Absolute *start_date, struct GNUNET_TIME_Absolute *end_date, struct TALER_Amount *wire_fee, + struct TALER_Amount *closing_fee, struct TALER_MasterSignatureP *master_sig); -- cgit v1.2.3 From acc3a41df812b59a1775d3fc0697a0b73d847963 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Thu, 4 Jan 2018 13:47:03 +0100 Subject: add pay session signature --- src/include/taler_signatures.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'src/include') diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h index 6355303a..c281d21f 100644 --- a/src/include/taler_signatures.h +++ b/src/include/taler_signatures.h @@ -178,6 +178,12 @@ */ #define TALER_SIGNATURE_MERCHANT_REFUND_OK 1105 +/** + * Signature where the merchant confirms that the user replayed + * a payment for a browser session. + */ +#define TALER_SIGNATURE_MERCHANT_PAY_SESSION 1106 + /*********************/ /* Wallet signatures */ @@ -1291,6 +1297,31 @@ struct TALER_MerchantRefundConfirmationPS }; +/** + * Used by the merchant to confirm to the frontend that + * the user did a payment replay with the current browser session. + */ +struct TALER_MerchantPaySessionSigPS +{ + /** + * Set to #TALER_SIGNATURE_MERCHANT_PAY_SESSION. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Hashed order id. + * Hashed without the 0-termination. + */ + struct GNUNET_HashCode h_order_id GNUNET_PACKED; + + /** + * Hashed session id. + * Hashed without the 0-termination. + */ + struct GNUNET_HashCode h_session_id GNUNET_PACKED; + +}; + GNUNET_NETWORK_STRUCT_END #endif -- cgit v1.2.3