implement #4937: allow extraction of fees

This commit is contained in:
Christian Grothoff 2017-03-04 18:45:25 +01:00
parent 1c84b3d4af
commit 0e15a99504
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
2 changed files with 225 additions and 7 deletions

View File

@ -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,19 +178,32 @@ 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;
}
}
break;
case MHD_HTTP_BAD_REQUEST:
/* This should never happen, either us or the exchange is buggy
@ -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 */

View File

@ -340,6 +340,69 @@ TALER_EXCHANGE_get_denomination_key_by_hash (const struct TALER_EXCHANGE_Keys *k
/* ********************* /wire *********************** */
/**
* 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
*/