diff options
author | Christian Grothoff <christian@grothoff.org> | 2017-03-04 18:45:25 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2017-03-04 18:45:25 +0100 |
commit | 0e15a995048f1653e92f762d983bf47b4fc6b39f (patch) | |
tree | 48e075ff6eb17d895f849d5cd5263a8e18da1d3a /src | |
parent | 1c84b3d4af1a2484e60a9071556d4690dd7aac33 (diff) |
implement #4937: allow extraction of fees
Diffstat (limited to 'src')
-rw-r--r-- | src/exchange-lib/exchange_api_wire.c | 169 | ||||
-rw-r--r-- | src/include/taler_exchange_service.h | 63 |
2 files changed, 225 insertions, 7 deletions
diff --git a/src/exchange-lib/exchange_api_wire.c b/src/exchange-lib/exchange_api_wire.c index fe60d664c..ae37741ff 100644 --- a/src/exchange-lib/exchange_api_wire.c +++ b/src/exchange-lib/exchange_api_wire.c @@ -27,6 +27,7 @@ #include <gnunet/gnunet_curl_lib.h> #include "taler_exchange_service.h" #include "taler_json_lib.h" +#include "taler_signatures.h" #include "taler_wire_plugin.h" #include "exchange_api_handle.h" @@ -148,6 +149,8 @@ handle_wire_finished (void *cls, break; case MHD_HTTP_OK: { + const struct TALER_EXCHANGE_Keys *keys; + const struct TALER_MasterPublicKeyP *master_pub; const char *key; json_t *method; int ret; @@ -175,18 +178,31 @@ handle_wire_finished (void *cls, method); } } + /* check fees */ + keys = TALER_EXCHANGE_get_keys (wh->exchange); + if (NULL == keys) + master_pub = NULL; + else + master_pub = &keys->master_pub; + if (GNUNET_OK != + TALER_EXCHANGE_wire_get_fees (master_pub, + keep, + NULL, + NULL)) + { + /* bogus reply */ + GNUNET_break_op (0); + response_code = 0; + } if (0 != response_code) { /* all supported methods were valid, use 'keep' for 'json' */ break; } - else - { - /* some supported methods were invalid, release 'keep', preserve - full 'json' for application-level error handling. */ - json_decref (keep); - keep = NULL; - } + /* some supported methods were invalid, release 'keep', preserve + full 'json' for application-level error handling. */ + json_decref (keep); + keep = NULL; } break; case MHD_HTTP_BAD_REQUEST: @@ -300,4 +316,143 @@ TALER_EXCHANGE_wire_cancel (struct TALER_EXCHANGE_WireHandle *wh) } +/** + * Parse wire @a fee and store the result in @a af. + * + * @param[out] af where to write the result + * @param fee json AggregateTransferFee to parse + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ +static int +parse_json_fees (struct TALER_EXCHANGE_WireAggregateFees *af, + json_t *fee) +{ + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_fixed_auto ("sig", + &af->master_sig), + TALER_JSON_spec_amount ("wire_fee", + &af->wire_fee), + GNUNET_JSON_spec_absolute_time ("start_date", + &af->start_date), + GNUNET_JSON_spec_absolute_time ("end_date", + &af->end_date), + GNUNET_JSON_spec_end() + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (fee, + spec, + NULL, + NULL)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Check the #TALER_SIGNATURE_MASTER_WIRE_FEES signature. + * + * @param af record to check + * @param wire_method wire method to check against + * @param master_pub expected signing key + * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure + */ +static int +check_sig (const struct TALER_EXCHANGE_WireAggregateFees *af, + const char *wire_method, + const struct TALER_MasterPublicKeyP *master_pub) +{ + struct TALER_MasterWireFeePS wp; + + wp.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_WIRE_FEES); + wp.purpose.size = htonl (sizeof (wp)); + GNUNET_CRYPTO_hash (wire_method, + strlen (wire_method) + 1, + &wp.h_wire_method); + wp.start_date = GNUNET_TIME_absolute_hton (af->start_date); + wp.end_date = GNUNET_TIME_absolute_hton (af->end_date); + TALER_amount_hton (&wp.wire_fee, + &af->wire_fee); + return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_WIRE_FEES, + &wp.purpose, + &af->master_sig.eddsa_signature, + &master_pub->eddsa_pub); +} + + +/** + * Obtain information about wire fees encoded in @a obj + * by wire method. + * + * @param master_pub public key to use to verify signatures, NULL to not verify + * @param obj wire information as encoded in the #TALER_EXCHANGE_WireResultCallback + * @param cb callback to invoke for the fees + * @param cb_cls closure for @a cb + * @return #GNUNET_OK in success, #GNUNET_SYSERR if @a obj is ill-formed + */ +int +TALER_EXCHANGE_wire_get_fees (const struct TALER_MasterPublicKeyP *master_pub, + const json_t *obj, + TALER_EXCHANGE_WireFeeCallback cb, + void *cb_cls) +{ + const char *wire_method; + json_t *value; + + json_object_foreach (((json_t *) obj), wire_method, value) + { + json_t *fees; + size_t num_fees; + + fees = json_object_get (value, "fees"); + if ( (NULL == fees) || + (! json_is_array (fees)) ) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + num_fees = json_array_size (fees); + if (num_fees > 1024) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + { + struct TALER_EXCHANGE_WireAggregateFees af[num_fees + 1]; + + for (size_t i=0;i<num_fees;i++) + { + af[i].next = &af[i+1]; + if (GNUNET_OK != + parse_json_fees (&af[i], + json_array_get (fees, + i))) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if ( (NULL != master_pub) && + (GNUNET_OK != + check_sig (&af[i], + wire_method, + master_pub)) ) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + } + af[num_fees].next = NULL; + if (NULL != cb) + cb (cb_cls, + wire_method, + &af[0]); + } + } + return GNUNET_OK; +} + + /* end of exchange_api_wire.c */ diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index 3ac4069f3..3b9058433 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -341,6 +341,69 @@ TALER_EXCHANGE_get_denomination_key_by_hash (const struct TALER_EXCHANGE_Keys *k /** + * Sorted list of fees to be paid for aggregate wire transfers. + */ +struct TALER_EXCHANGE_WireAggregateFees +{ + /** + * This is a linked list. + */ + struct TALER_EXCHANGE_WireAggregateFees *next; + + /** + * Fee to be paid. + */ + struct TALER_Amount wire_fee; + + /** + * Time when this fee goes into effect (inclusive) + */ + struct GNUNET_TIME_Absolute start_date; + + /** + * Time when this fee stops being in effect (exclusive). + */ + struct GNUNET_TIME_Absolute end_date; + + /** + * Signature affirming the above fee structure. + */ + struct TALER_MasterSignatureP master_sig; +}; + + +/** + * Function called with information about the wire fees + * for each wire method. + * + * @param cls closure + * @param wire_method name of the wire method (i.e. "sepa") + * @param fees fee structure for this method + */ +typedef void +(*TALER_EXCHANGE_WireFeeCallback)(void *cls, + const char *wire_method, + const struct TALER_EXCHANGE_WireAggregateFees *fees); + + +/** + * Obtain information about wire fees encoded in @a obj + * by wire method. + * + * @param master_pub public key to use to verify signatures, NULL to not verify + * @param obj wire information as encoded in the #TALER_EXCHANGE_WireResultCallback + * @param cb callback to invoke for the fees + * @param cb_cls closure for @a cb + * @return #GNUNET_OK in success, #GNUNET_SYSERR if @a obj is ill-formed + */ +int +TALER_EXCHANGE_wire_get_fees (const struct TALER_MasterPublicKeyP *master_pub, + const json_t *obj, + TALER_EXCHANGE_WireFeeCallback cb, + void *cb_cls); + + +/** * @brief A Wire format inquiry handle */ struct TALER_EXCHANGE_WireHandle; |