refinements of policy extension APIs

This commit is contained in:
Özgür Kesim 2022-10-06 21:11:47 +02:00
parent 086c4a243f
commit b447506342
Signed by: oec
GPG Key ID: 3D76A56D79EDD9D7
5 changed files with 232 additions and 142 deletions

View File

@ -114,6 +114,11 @@ struct DepositContext
*/
const struct TALER_EXCHANGEDB_Deposit *deposit;
/**
* Extension handler for policy, maybe NULL.
*/
const struct TALER_Extension *policy_extension;
/**
* Our timestamp (when we received the request).
* Possibly updated by the transaction if the
@ -156,6 +161,7 @@ deposit_transaction (void *cls,
enum GNUNET_DB_QueryStatus qs;
bool balance_ok;
bool in_conflict;
bool blocked_by_policy = false;
qs = TEH_make_coin_known (&dc->deposit->coin,
connection,
@ -163,11 +169,30 @@ deposit_transaction (void *cls,
mhd_ret);
if (qs < 0)
return qs;
/* Check and apply policies, if applicable */
if (NULL != dc->policy_extension)
{
const struct TALER_Extension *ext = dc->policy_extension;
struct TALER_ExtensionsPolicySerialID serialID;
struct GNUNET_TIME_Timestamp deadline;
GNUNET_assert (ext->parse_policy_details);
qs = ext->parse_policy_details (dc->deposit->policy_details,
&serialID,
&deadline);
if (qs < 0)
return qs;
blocked_by_policy = true;
}
qs = TEH_plugin->do_deposit (TEH_plugin->cls,
dc->deposit,
dc->known_coin_id,
&dc->h_payto,
false, /* FIXME-OEC: extension blocked #7270 */
blocked_by_policy,
&dc->exchange_timestamp,
&balance_ok,
&in_conflict);
@ -208,86 +233,6 @@ deposit_transaction (void *cls,
}
/**
* @brief check the provided policy
*
* @param[in] policy_details JSON object provided by the client with prolicy
* @param[out] hc On success, will contain the hash of the normalized policy_details object
* @param[out] handler_out On success, the handler might provide an output
* @param[out] error_hint On failure, might contain a hint of the error from the extension
* @return GNUNET_OK on success.
*/
enum GNUNET_GenericReturnValue
check_policy_details (
json_t *policy_details,
struct TALER_ExtensionPolicyHashP *hc,
json_t **handler_out,
char **error_hint)
{
const char *type = NULL;
const struct TALER_Extension *extension;
enum GNUNET_GenericReturnValue ret;
*error_hint = NULL;
if ((NULL == policy_details) ||
(! json_is_object (policy_details)))
{
*error_hint = "invalid policy object";
return GNUNET_SYSERR;
}
// parse and evaluate the object
{
json_t *jtype = json_object_get (
policy_details,
"type");
if (NULL == jtype)
{
*error_hint = "no type in policy object";
return GNUNET_SYSERR;
}
type = json_string_value (jtype);
if (NULL == type)
{
*error_hint = "invalid type in policy object";
return GNUNET_SYSERR;
}
extension = TALER_extensions_get_by_name (type);
if ((NULL == extension) ||
(NULL == extension->deposit_handler))
{
GNUNET_break (0);
*error_hint = "no such policy";
return GNUNET_SYSERR;
}
ret = extension->deposit_handler (policy_details,
handler_out);
if (GNUNET_OK != ret)
{
GNUNET_break (0);
if (NULL != *handler_out)
{
*error_hint = json_dumps (*handler_out, JSON_INDENT (2));
}
else
{
GNUNET_break (1);
*error_hint = "unknown error with the policy";
}
return ret;
}
}
TALER_deposit_policy_hash (policy_details,
hc);
return GNUNET_OK;
}
MHD_RESULT
TEH_handler_deposit (struct MHD_Connection *connection,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
@ -296,9 +241,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
struct DepositContext dc;
struct TALER_EXCHANGEDB_Deposit deposit;
const char *payto_uri;
struct TALER_ExtensionPolicyHashP h_policy;
struct TALER_ExtensionPolicyHashP *ph_policy = NULL;
bool no_policy;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_string ("merchant_payto_uri",
&payto_uri),
@ -311,8 +254,6 @@ TEH_handler_deposit (struct MHD_Connection *connection,
&deposit.coin.denom_pub_hash),
TALER_JSON_spec_denom_sig ("ub_sig",
&deposit.coin.denom_sig),
GNUNET_JSON_spec_fixed_auto ("merchant_pub",
&deposit.merchant_pub),
GNUNET_JSON_spec_fixed_auto ("h_contract_terms",
&deposit.h_contract_terms),
GNUNET_JSON_spec_mark_optional (
@ -324,17 +265,20 @@ TEH_handler_deposit (struct MHD_Connection *connection,
GNUNET_JSON_spec_timestamp ("timestamp",
&deposit.timestamp),
/* TODO: this will move to an extension for refunds */
/* TODO: refund_deadline and merchant_pub will move into the
* extension policy_merchant_refunds */
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_timestamp ("refund_deadline",
&deposit.refund_deadline),
NULL),
GNUNET_JSON_spec_fixed_auto ("merchant_pub",
&deposit.merchant_pub),
GNUNET_JSON_spec_timestamp ("wire_transfer_deadline",
&deposit.wire_deadline),
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_json ("policy",
&deposit.policy_details),
&no_policy),
GNUNET_JSON_spec_timestamp ("wire_transfer_deadline",
&deposit.wire_deadline),
&deposit.no_policy_details),
GNUNET_JSON_spec_end ()
};
struct TALER_MerchantWireHashP h_wire;
@ -472,29 +416,11 @@ TEH_handler_deposit (struct MHD_Connection *connection,
NULL);
}
/* TODO: check policy_details */
if (! no_policy)
if (! deposit.no_policy_details)
{
char *hint;
json_t *out;
MHD_RESULT res;
if (GNUNET_OK !=
check_policy_details (dc.deposit->policy_details,
&h_policy,
&out,
&hint))
{
res = TALER_MHD_reply_with_error (connection,
MHD_HTTP_BAD_REQUEST,
/* TODO: new error type needed */
TALER_EC_EXCHANGE_GENERIC_OPERATION_UNKNOWN,
hint);
GNUNET_free (hint);
return res;
}
ph_policy = &h_policy;
TALER_deposit_policy_hash (deposit.policy_details,
&deposit.h_policy);
ph_policy = &deposit.h_policy;
}
deposit.deposit_fee = dk->meta.fees.deposit;

View File

@ -151,7 +151,9 @@ struct TALER_Extension TE_age_restriction = {
.disable = &age_restriction_disable,
.load_config = &age_restriction_load_config,
.manifest = &age_restriction_manifest,
.deposit_handler = NULL,
/* This extension is not a policy extension */
.parse_policy_details = NULL,
.http_get_handler = NULL,
.http_post_handler = NULL,
};

View File

@ -353,4 +353,53 @@ TALER_extensions_load_manifests (
}
enum GNUNET_GenericReturnValue
TALER_extensions_from_policy_details (
const json_t *policy_details,
const struct TALER_Extension **extension,
char **error_hint)
{
const json_t *jtype;
const char *type;
*extension = NULL;
*error_hint = NULL;
if ((NULL == policy_details) ||
(! json_is_object (policy_details)))
{
*error_hint = "invalid policy object";
return GNUNET_SYSERR;
}
jtype = json_object_get (policy_details, "type");
if (NULL == jtype)
{
*error_hint = "no type in policy object";
return GNUNET_SYSERR;
}
type = json_string_value (jtype);
if (NULL == type)
{
*error_hint = "invalid type in policy object";
return GNUNET_SYSERR;
}
*extension = TALER_extensions_get_by_name (type);
if ((NULL == *extension) ||
(NULL == (*extension)->parse_policy_details))
{
GNUNET_break (0);
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Unsupported extension policy '%s' requested\n",
type);
*extension = NULL;
return GNUNET_NO;
}
return GNUNET_OK;
}
/* end of extensions.c */

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2021-2022 Taler Systems SA
Copyright (C) 2022 Taler Systems SA
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
@ -32,7 +32,7 @@
/* (public) configuration of this extension */
/* TODO: these fields need to be set in the init handler */
static struct TALER_BrandtVickreyAuction BV_config = {
static struct TALER_ExtensionPolicyBrandtVickreyAuctionConfig BV_config = {
.max_bidders = 10,
.max_prices = 10,
.auction_fee = {
@ -497,7 +497,7 @@ static json_t *
auction_manifest (
const struct TALER_Extension *ext)
{
struct TALER_BrandtVickreyAuction *conf = ext->config;
struct TALER_ExtensionPolicyBrandtVickreyAuctionConfig *conf = ext->config;
GNUNET_assert (conf);
json_t *config = GNUNET_JSON_PACK (
@ -589,20 +589,66 @@ auction_http_post_handler (
/**
* @brief implements the TALER_Extensions.deposit_handler interface.
* @brief implements the TALER_Extensions.parse_policy_details interface.
*
* @param[in] input JSON input from the client during a deposit request
* @param[out] output by this extension
* @param[in] input The policy_details for this handler during deposit
* @param[out] serial On success will contain the serial-ID under which the
* @param[out] deadline On success will contain a deadline, might be "forever"
* exchange should store the policy_details in the policy_details table.
* @return GNUNET_OK if the request was OK
*/
enum GNUNET_GenericReturnValue
auction_deposit_handler (
json_t *input,
json_t **output)
auction_parse_policy_details (
const json_t *input,
struct TALER_ExtensionsPolicySerialID *serial,
struct GNUNET_TIME_Timestamp *deadline)
{
/* TODO */
*output = NULL;
return GNUNET_OK;
enum GNUNET_GenericReturnValue ret = GNUNET_NO;
struct GNUNET_CRYPTO_EddsaPublicKey pub;
struct GNUNET_HashCode hc;
struct GNUNET_JSON_Specification spec[] = {
/* We ignore the "type" field as it must have been parsed already upstream
* - or this handler wouldn't have been called in first place. */
GNUNET_JSON_spec_fixed_auto ("bidder_pub", &pub),
GNUNET_JSON_spec_fixed_auto ("h_auction", &hc),
GNUNET_JSON_spec_timestamp ("deadline", deadline),
GNUNET_JSON_spec_end (),
};
GNUNET_assert (serial);
GNUNET_assert (deadline);
do {
ret = GNUNET_JSON_parse (input,
spec,
NULL,
NULL);
if (GNUNET_OK != ret)
break;
/* FIXME: check the deadline */
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
LOG_PREFIX "check of deadline %ld not implemented!\n",
deadline->abs_time.abs_value_us);
/* Create serial as H(bidder_pub, h_auction) */
{
struct GNUNET_HashContext *hc = GNUNET_CRYPTO_hash_context_start ();
GNUNET_CRYPTO_hash_context_read (hc,
&pub,
sizeof(pub));
GNUNET_CRYPTO_hash_context_read (hc,
&hc,
sizeof(hc));
GNUNET_CRYPTO_hash_context_finish (hc,
&serial->hash);
}
ret = GNUNET_OK;
} while(0);
return ret;
}
@ -617,7 +663,7 @@ struct TALER_Extension TE_auction_brandt = {
.disable = &auction_disable,
.load_config = &auction_load_config,
.manifest = &auction_manifest,
.deposit_handler = &auction_deposit_handler,
.parse_policy_details = &auction_parse_policy_details,
.http_get_handler = &auction_http_get_handler,
.http_post_handler = &auction_http_post_handler,
};

View File

@ -25,17 +25,21 @@
#include "taler_crypto_lib.h"
#include "taler_json_lib.h"
#include "taler_mhd_lib.h"
#include "taler_exchangedb_plugin.h"
#define TALER_EXTENSION_SECTION_PREFIX "exchange-extension-"
enum TALER_Extension_Type
{
TALER_Extension_AgeRestriction = 0,
TALER_Extension_PolicyMerchantRefund = 1,
TALER_Extension_PolicyBrandtVickeryAuction = 2,
TALER_Extension_PolicyEscrowedPayment = 3,
TALER_Extension_MaxPredefined = 4 // Must be last of the predefined
TALER_Extension_PolicyNull = 0,
TALER_Extension_AgeRestriction = 1,
TALER_Extension_PolicyMerchantRefund = 2,
TALER_Extension_PolicyBrandtVickeryAuction = 3,
TALER_Extension_PolicyEscrowedPayment = 4,
TALER_Extension_MaxPredefined = 5 // Must be last of the predefined
};
@ -49,6 +53,15 @@ struct TALER_Extensions
const struct TALER_Extension *extension;
};
/*
* @brief Serial ID under which the policy details to an deposit are stored in
* the policy_details table.
*/
struct TALER_ExtensionsPolicySerialID
{
struct GNUNET_HashCode hash;
};
/*
* @brief Represents the implementation of an extension.
*
@ -151,22 +164,30 @@ struct TALER_Extension
json_t *(*manifest)(
const struct TALER_Extension *ext);
/* =========================
* Policy related handlers
* =========================
*/
/**
* @brief Handler for /{batch}-deposit requests. Can be NULL.
* @brief Handler to check a policy. Can be NULL;
*
* When a deposit request refers to this extension in its policy
* (see https://docs.taler.net/core/api-exchange.html#deposit), this handler
* will be called during the deposit operation.
* will be called before the deposit transaction.
*
* @param[in] input The policy/extension specific data, provided by the client in
* the policy-field of the deposit request.
* @param[out] output Potential output by the extension to be provided to the
* client as part of the response to the deposit request. Can be NULL.
* @param[in] policy_details Details about the policy, provided by the client
* during a deposit request.
* @param[out] serial On success, will contain the serial-ID under which the
* exchange should save the policy_details in the deposit table.
* @param[out] deadline On sucess, set to the deadline until the policy must
* be fulfilled. Might be "forever". This value is used by an external
* mechanism to detect timeouts.
* @return GNUNET_OK if the data was accepted by the extension.
*/
enum GNUNET_GenericReturnValue (*deposit_handler)(
json_t *input,
json_t **output);
enum GNUNET_GenericReturnValue (*parse_policy_details)(
const json_t *policy_details,
struct TALER_ExtensionsPolicySerialID *serial,
struct GNUNET_TIME_Timestamp *deadline);
/**
* @brief Handler for POST-requests to the /policy/$name endpoint. Can be NULL.
@ -366,19 +387,65 @@ struct TALER_AgeMask
TALER_extensions_get_age_restriction_mask ();
/*
* ===================================
* Policy extensions related functions
* ===================================
*/
/*
* @brief Finds the extension for a given policy
*
* @param[in] policy_details JSON of the policy detail from a deposit request
* @param[out] extension On GNUNET_OK, the exentions handling the given policy
* @param[out] error_hint On GNUNET_SYSERR, will contain a hint for the reason why it failed
* @return GNUNET_OK on success, with *extension set to the correct extension.
* GNUNET_NO, when no extension was found. GNUNET_SYSERR when the JSON was
* invalid, with *error_hint maybe non-NULL.
*/
enum GNUNET_GenericReturnValue
TALER_extensions_from_policy_details (
const json_t *policy_details,
const struct TALER_Extension **extension,
char **error_hint);
/*
* ================================
* Brandt-Vickrey Auctions
* Merchant refund policy
* ================================
*/
struct TALER_ExtensionPolicyMerchantRefundPolicyConfig
{
struct GNUNET_TIME_Relative max_timeout;
};
/*
* ================================
* Brandt-Vickrey Auctions policy
* ================================
*/
/*
* @brief Configuration for Brandt-Vickrey auctions
* @brief Configuration for Brandt-Vickrey auctions policy
*/
struct TALER_BrandtVickreyAuction
struct TALER_ExtensionPolicyBrandtVickreyAuctionConfig
{
uint16_t max_bidders;
uint16_t max_prices;
struct TALER_Amount auction_fee;
};
/*
* ================================
* Escrowed Payments policy
* ================================
*/
/*
* @brief Configuration for escrowed payments policy
*/
struct TALER_ExtensionPolicyEscrowedPaymentsConfig
{
struct GNUNET_TIME_Relative max_timeout;
};
#endif