policy extensions and age restriction refactoring
- refactoring of extension-plugin-mechanism - refactoring of age restriction extension - added policy extensions plugin plumbing - added DB schema and api - policy_details - policy_fulfillments
This commit is contained in:
parent
c89bfa9026
commit
752f102738
@ -532,6 +532,7 @@ AC_CONFIG_FILES([Makefile
|
||||
src/exchangedb/Makefile
|
||||
src/exchange-tools/Makefile
|
||||
src/extensions/Makefile
|
||||
src/extensions/age_restriction/Makefile
|
||||
src/lib/Makefile
|
||||
src/kyclogic/Makefile
|
||||
src/testing/Makefile
|
||||
|
@ -32,5 +32,6 @@ SUBDIRS = \
|
||||
auditor \
|
||||
lib \
|
||||
exchange-tools \
|
||||
extensions/age_restriction \
|
||||
testing \
|
||||
benchmark
|
||||
|
@ -227,7 +227,7 @@ verify_and_execute_deposit_confirmation (
|
||||
TALER_exchange_online_deposit_confirmation_verify (
|
||||
&dc->h_contract_terms,
|
||||
&dc->h_wire,
|
||||
NULL /* h_extensions! */,
|
||||
&dc->h_policy,
|
||||
dc->exchange_timestamp,
|
||||
dc->wire_deadline,
|
||||
dc->refund_deadline,
|
||||
@ -276,8 +276,8 @@ TAH_DEPOSIT_CONFIRMATION_handler (struct TAH_RequestHandler *rh,
|
||||
struct GNUNET_JSON_Specification spec[] = {
|
||||
GNUNET_JSON_spec_fixed_auto ("h_contract_terms",
|
||||
&dc.h_contract_terms),
|
||||
GNUNET_JSON_spec_fixed_auto ("h_extensions",
|
||||
&dc.h_extensions),
|
||||
GNUNET_JSON_spec_fixed_auto ("h_policy",
|
||||
&dc.h_policy),
|
||||
GNUNET_JSON_spec_fixed_auto ("h_wire",
|
||||
&dc.h_wire),
|
||||
GNUNET_JSON_spec_timestamp ("exchange_timestamp",
|
||||
|
@ -117,7 +117,8 @@ static struct Table tables[] = {
|
||||
{ .rt = TALER_EXCHANGEDB_RT_RECOUP},
|
||||
{ .rt = TALER_EXCHANGEDB_RT_RECOUP_REFRESH },
|
||||
{ .rt = TALER_EXCHANGEDB_RT_EXTENSIONS},
|
||||
{ .rt = TALER_EXCHANGEDB_RT_EXTENSION_DETAILS },
|
||||
{ .rt = TALER_EXCHANGEDB_RT_POLICY_DETAILS },
|
||||
{ .rt = TALER_EXCHANGEDB_RT_POLICY_FULFILLMENTS },
|
||||
{ .rt = TALER_EXCHANGEDB_RT_PURSE_REQUESTS},
|
||||
{ .rt = TALER_EXCHANGEDB_RT_PURSE_DECISION},
|
||||
{ .rt = TALER_EXCHANGEDB_RT_PURSE_MERGES},
|
||||
|
@ -1566,7 +1566,7 @@ deposit_cb (void *cls,
|
||||
&h_wire,
|
||||
&deposit->h_contract_terms,
|
||||
&deposit->coin.h_age_commitment,
|
||||
NULL /* FIXME-Oec: #7270: h_extensions! */,
|
||||
&deposit->h_policy,
|
||||
&h_denom_pub,
|
||||
deposit->timestamp,
|
||||
&deposit->merchant_pub,
|
||||
|
@ -87,7 +87,7 @@ function stop_libeufin()
|
||||
# Cleanup exchange and libeufin between runs.
|
||||
function cleanup()
|
||||
{
|
||||
if test ! -z ${EPID:-}
|
||||
if test ! -z "${EPID:-}"
|
||||
then
|
||||
echo -n "Stopping exchange $EPID..."
|
||||
kill -TERM $EPID
|
||||
@ -102,7 +102,7 @@ function cleanup()
|
||||
function exit_cleanup()
|
||||
{
|
||||
echo "Running exit-cleanup"
|
||||
if test ! -z ${POSTGRES_PATH:-}
|
||||
if test ! -z "${POSTGRES_PATH:-}"
|
||||
then
|
||||
echo "Stopping Postgres at ${POSTGRES_PATH}"
|
||||
${POSTGRES_PATH}/pg_ctl -D $TMPDIR -l /dev/null stop &> /dev/null || true
|
||||
@ -2047,10 +2047,10 @@ taler-wallet-cli -h >/dev/null </dev/null 2>/dev/null || exit_skip "taler-wallet
|
||||
echo -n "Testing for Postgres"
|
||||
# Available directly in path?
|
||||
INITDB_BIN=$(command -v initdb) || true
|
||||
if [[ ! -z $INITDB_BIN ]]; then
|
||||
if [[ ! -z "$INITDB_BIN" ]]; then
|
||||
echo " FOUND (in path) at" $INITDB_BIN
|
||||
else
|
||||
HAVE_INITDB=`find /usr -name "initdb" 2> /dev/null | grep postgres` || exit_skip " MISSING"
|
||||
HAVE_INITDB=`find /usr -name "initdb" | head -1 2> /dev/null | grep postgres` || exit_skip " MISSING"
|
||||
echo " FOUND at" `dirname $HAVE_INITDB`
|
||||
INITDB_BIN=`echo $HAVE_INITDB | grep bin/initdb | grep postgres | sort -n | tail -n1`
|
||||
fi
|
||||
|
@ -81,7 +81,7 @@ function stop_libeufin()
|
||||
# Cleanup to run whenever we exit
|
||||
function cleanup()
|
||||
{
|
||||
if test ! -z ${EPID:-}
|
||||
if test ! -z "${EPID:-}"
|
||||
then
|
||||
echo -n "Stopping exchange $EPID..."
|
||||
kill -TERM $EPID
|
||||
@ -96,7 +96,7 @@ function cleanup()
|
||||
function exit_cleanup()
|
||||
{
|
||||
echo "Running exit-cleanup"
|
||||
if test ! -z ${POSTGRES_PATH:-}
|
||||
if test -z "${POSTGRES_PATH:-}"
|
||||
then
|
||||
echo "Stopping Postgres at ${POSTGRES_PATH}"
|
||||
${POSTGRES_PATH}/pg_ctl -D $TMPDIR -l /dev/null stop &> /dev/null || true
|
||||
@ -640,10 +640,10 @@ taler-wallet-cli -h >/dev/null </dev/null 2>/dev/null || exit_skip "taler-wallet
|
||||
echo -n "Testing for Postgres"
|
||||
# Available directly in path?
|
||||
INITDB_BIN=$(command -v initdb) || true
|
||||
if [[ ! -z $INITDB_BIN ]]; then
|
||||
if [[ ! -z "$INITDB_BIN" ]]; then
|
||||
echo " FOUND (in path) at" $INITDB_BIN
|
||||
else
|
||||
HAVE_INITDB=`find /usr -name "initdb" 2> /dev/null | grep postgres` || exit_skip " MISSING"
|
||||
HAVE_INITDB=`find /usr -name "initdb" | head -1 2> /dev/null | grep postgres` || exit_skip " MISSING"
|
||||
echo " FOUND at" `dirname $HAVE_INITDB`
|
||||
INITDB_BIN=`echo $HAVE_INITDB | grep bin/initdb | grep postgres | sort -n | tail -n1`
|
||||
fi
|
||||
|
@ -32,7 +32,7 @@ function exit_fail() {
|
||||
|
||||
# Cleanup to run whenever we exit
|
||||
function cleanup() {
|
||||
if test ! -z ${POSTGRES_PATH:-}
|
||||
if test ! -z "${POSTGRES_PATH:-}"
|
||||
then
|
||||
${POSTGRES_PATH}/pg_ctl -D $TMPDIR stop &> /dev/null || true
|
||||
fi
|
||||
@ -111,10 +111,10 @@ taler-wallet-cli -h >/dev/null </dev/null 2>/dev/null || exit_skip "taler-wallet
|
||||
echo -n "Testing for Postgres"
|
||||
# Available directly in path?
|
||||
INITDB_BIN=$(command -v initdb) || true
|
||||
if [[ ! -z $INITDB_BIN ]]; then
|
||||
if [[ ! -z "$INITDB_BIN" ]]; then
|
||||
echo " FOUND (in path) at" $INITDB_BIN
|
||||
else
|
||||
HAVE_INITDB=`find /usr -name "initdb" 2> /dev/null | grep postgres` || exit_skip " MISSING"
|
||||
HAVE_INITDB=`find /usr -name "initdb" | head -1 2> /dev/null | grep postgres` || exit_skip " MISSING"
|
||||
echo " FOUND at" `dirname $HAVE_INITDB`
|
||||
INITDB_BIN=`echo $HAVE_INITDB | grep bin/initdb | grep postgres | sort -n | tail -n1`
|
||||
fi
|
||||
|
@ -315,7 +315,7 @@ CREATE TABLE IF NOT EXISTS deposit_confirmations
|
||||
(master_pub BYTEA NOT NULL CONSTRAINT master_pub_ref REFERENCES auditor_exchanges(master_pub) ON DELETE CASCADE
|
||||
,serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY UNIQUE
|
||||
,h_contract_terms BYTEA NOT NULL CHECK (LENGTH(h_contract_terms)=64)
|
||||
,h_extensions BYTEA NOT NULL CHECK (LENGTH(h_contract_terms)=64)
|
||||
,h_policy BYTEA NOT NULL CHECK (LENGTH(h_policy)=64)
|
||||
,h_wire BYTEA NOT NULL CHECK (LENGTH(h_wire)=64)
|
||||
,exchange_timestamp INT8 NOT NULL
|
||||
,refund_deadline INT8 NOT NULL
|
||||
|
@ -87,8 +87,8 @@ deposit_confirmation_cb (void *cls,
|
||||
&serial_id),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
|
||||
&dc.h_contract_terms),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("h_extensions",
|
||||
&dc.h_extensions),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("h_policy",
|
||||
&dc.h_policy),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("h_wire",
|
||||
&dc.h_wire),
|
||||
GNUNET_PQ_result_spec_timestamp ("exchange_timestamp",
|
||||
@ -158,7 +158,7 @@ TAH_PG_get_deposit_confirmations (
|
||||
"SELECT"
|
||||
" serial_id"
|
||||
",h_contract_terms"
|
||||
",h_extensions"
|
||||
",h_policy"
|
||||
",h_wire"
|
||||
",exchange_timestamp"
|
||||
",wire_deadline"
|
||||
|
@ -35,7 +35,7 @@ TAH_PG_insert_deposit_confirmation (
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_auto_from_type (&dc->master_public_key),
|
||||
GNUNET_PQ_query_param_auto_from_type (&dc->h_contract_terms),
|
||||
GNUNET_PQ_query_param_auto_from_type (&dc->h_extensions),
|
||||
GNUNET_PQ_query_param_auto_from_type (&dc->h_policy),
|
||||
GNUNET_PQ_query_param_auto_from_type (&dc->h_wire),
|
||||
GNUNET_PQ_query_param_timestamp (&dc->exchange_timestamp),
|
||||
GNUNET_PQ_query_param_timestamp (&dc->wire_deadline),
|
||||
@ -54,7 +54,7 @@ TAH_PG_insert_deposit_confirmation (
|
||||
"INSERT INTO deposit_confirmations "
|
||||
"(master_pub"
|
||||
",h_contract_terms"
|
||||
",h_extensions"
|
||||
",h_policy"
|
||||
",h_wire"
|
||||
",exchange_timestamp"
|
||||
",wire_deadline"
|
||||
|
@ -137,6 +137,12 @@ static struct GNUNET_CURL_RescheduleContext *rc;
|
||||
*/
|
||||
static const struct GNUNET_CONFIGURATION_Handle *kcfg;
|
||||
|
||||
/**
|
||||
* Age restriction configuration
|
||||
*/
|
||||
static bool ar_enabled = false;
|
||||
static struct TALER_AgeRestrictionConfig ar_config = {0};
|
||||
|
||||
/**
|
||||
* Return value from main().
|
||||
*/
|
||||
@ -163,11 +169,6 @@ static char *currency;
|
||||
*/
|
||||
static char *CFG_exchange_url;
|
||||
|
||||
/**
|
||||
* If age restriction is enabled, the age mask to be used
|
||||
*/
|
||||
static struct TALER_AgeMask age_mask = {0};
|
||||
|
||||
/**
|
||||
* A subcommand supported by this program.
|
||||
*/
|
||||
@ -2159,14 +2160,14 @@ upload_extensions (const char *exchange_url,
|
||||
|
||||
/* 2. Verify the signature */
|
||||
{
|
||||
struct TALER_ExtensionConfigHashP h_config;
|
||||
struct TALER_ExtensionManifestsHashP h_manifests;
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TALER_JSON_extensions_config_hash (extensions, &h_config))
|
||||
TALER_JSON_extensions_manifests_hash (extensions, &h_manifests))
|
||||
{
|
||||
GNUNET_JSON_parse_free (spec);
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"couldn't hash extensions\n");
|
||||
"couldn't hash extensions' manifests\n");
|
||||
global_ret = EXIT_FAILURE;
|
||||
test_shutdown ();
|
||||
return;
|
||||
@ -2176,8 +2177,8 @@ upload_extensions (const char *exchange_url,
|
||||
load_offline_key (GNUNET_NO))
|
||||
return;
|
||||
|
||||
if (GNUNET_OK != TALER_exchange_offline_extension_config_hash_verify (
|
||||
&h_config,
|
||||
if (GNUNET_OK != TALER_exchange_offline_extension_manifests_hash_verify (
|
||||
&h_manifests,
|
||||
&master_pub,
|
||||
&sig))
|
||||
{
|
||||
@ -3858,7 +3859,7 @@ load_age_mask (const char*section_name)
|
||||
static const struct TALER_AgeMask null_mask = {0};
|
||||
enum GNUNET_GenericReturnValue ret;
|
||||
|
||||
if (age_mask.bits == 0)
|
||||
if (! ar_enabled)
|
||||
return null_mask;
|
||||
|
||||
if (GNUNET_OK != (GNUNET_CONFIGURATION_have_value (
|
||||
@ -3870,14 +3871,14 @@ load_age_mask (const char*section_name)
|
||||
ret = GNUNET_CONFIGURATION_get_value_yesno (kcfg,
|
||||
section_name,
|
||||
"AGE_RESTRICTED");
|
||||
if (GNUNET_YES == ret)
|
||||
return age_mask;
|
||||
|
||||
if (GNUNET_SYSERR == ret)
|
||||
GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
|
||||
section_name,
|
||||
"AGE_RESTRICTED",
|
||||
"Value must be YES or NO\n");
|
||||
if (GNUNET_YES == ret)
|
||||
return ar_config.mask;
|
||||
|
||||
return null_mask;
|
||||
}
|
||||
|
||||
@ -4218,18 +4219,24 @@ do_setup (char *const *args)
|
||||
static void
|
||||
do_extensions_show (char *const *args)
|
||||
{
|
||||
const struct TALER_Extension *it;
|
||||
const struct TALER_Extensions *it;
|
||||
json_t *exts = json_object ();
|
||||
json_t *obj;
|
||||
|
||||
GNUNET_assert (NULL != exts);
|
||||
for (it = TALER_extensions_get_head ();
|
||||
NULL != it;
|
||||
NULL != it && NULL != it->extension;
|
||||
it = it->next)
|
||||
GNUNET_assert (0 ==
|
||||
json_object_set_new (exts,
|
||||
it->name,
|
||||
it->config_to_json (it)));
|
||||
{
|
||||
const struct TALER_Extension *extension = it->extension;
|
||||
int ret;
|
||||
|
||||
ret = json_object_set_new (exts,
|
||||
extension->name,
|
||||
extension->manifest (extension));
|
||||
GNUNET_assert (-1 != ret);
|
||||
}
|
||||
|
||||
obj = GNUNET_JSON_PACK (
|
||||
GNUNET_JSON_pack_object_steal ("extensions",
|
||||
exts));
|
||||
@ -4238,7 +4245,7 @@ do_extensions_show (char *const *args)
|
||||
json_dumps (obj,
|
||||
JSON_INDENT (2)));
|
||||
json_decref (obj);
|
||||
next (args + 1);
|
||||
next (args);
|
||||
}
|
||||
|
||||
|
||||
@ -4249,35 +4256,38 @@ static void
|
||||
do_extensions_sign (char *const *args)
|
||||
{
|
||||
json_t *extensions = json_object ();
|
||||
struct TALER_ExtensionConfigHashP h_config;
|
||||
struct TALER_ExtensionManifestsHashP h_manifests;
|
||||
struct TALER_MasterSignatureP sig;
|
||||
const struct TALER_Extension *it;
|
||||
const struct TALER_Extensions *it;
|
||||
bool found = false;
|
||||
json_t *obj;
|
||||
|
||||
GNUNET_assert (NULL != extensions);
|
||||
if (GNUNET_OK !=
|
||||
TALER_extensions_load_taler_config (kcfg))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"error while loading taler config for extensions\n");
|
||||
json_decref (extensions);
|
||||
return;
|
||||
}
|
||||
for (it = TALER_extensions_get_head ();
|
||||
NULL != it;
|
||||
NULL != it && NULL != it->extension;
|
||||
it = it->next)
|
||||
{
|
||||
const struct TALER_Extension *ext = it->extension;
|
||||
GNUNET_assert (ext);
|
||||
|
||||
found = true;
|
||||
|
||||
GNUNET_assert (0 ==
|
||||
json_object_set_new (extensions,
|
||||
it->name,
|
||||
it->config_to_json (it)));
|
||||
ext->name,
|
||||
ext->manifest (ext)));
|
||||
}
|
||||
|
||||
if (! found)
|
||||
return;
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TALER_JSON_extensions_config_hash (extensions,
|
||||
&h_config))
|
||||
TALER_JSON_extensions_manifests_hash (extensions,
|
||||
&h_manifests))
|
||||
{
|
||||
json_decref (extensions);
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"error while hashing config for extensions\n");
|
||||
"error while hashing manifest for extensions\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -4288,7 +4298,7 @@ do_extensions_sign (char *const *args)
|
||||
return;
|
||||
}
|
||||
|
||||
TALER_exchange_offline_extension_config_hash_sign (&h_config,
|
||||
TALER_exchange_offline_extension_manifests_hash_sign (&h_manifests,
|
||||
&master_priv,
|
||||
&sig);
|
||||
obj = GNUNET_JSON_PACK (
|
||||
@ -4297,9 +4307,10 @@ do_extensions_sign (char *const *args)
|
||||
GNUNET_JSON_pack_data_auto (
|
||||
"extensions_sig",
|
||||
&sig));
|
||||
|
||||
output_operation (OP_EXTENSIONS,
|
||||
obj);
|
||||
next (args + 1);
|
||||
next (args);
|
||||
}
|
||||
|
||||
|
||||
@ -4500,6 +4511,24 @@ run (void *cls,
|
||||
(void) cls;
|
||||
(void) cfgfile;
|
||||
kcfg = cfg;
|
||||
|
||||
/* load extensions */
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_extensions_init (kcfg));
|
||||
|
||||
/* setup age restriction, if applicable */
|
||||
{
|
||||
const struct TALER_AgeRestrictionConfig *arc;
|
||||
|
||||
if (NULL !=
|
||||
(arc = TALER_extensions_get_age_restriction_config ()))
|
||||
{
|
||||
ar_config = *arc;
|
||||
ar_enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TALER_config_get_currency (kcfg,
|
||||
¤cy))
|
||||
@ -4508,18 +4537,6 @@ run (void *cls,
|
||||
return;
|
||||
}
|
||||
|
||||
/* load age mask, if age restriction is enabled */
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_extension_age_restriction_register ());
|
||||
|
||||
if (GNUNET_OK != TALER_extensions_load_taler_config (kcfg))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"error while loading taler config for extensions\n");
|
||||
return;
|
||||
}
|
||||
age_mask = TALER_extensions_age_restriction_ageMask ();
|
||||
|
||||
ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
|
||||
&rc);
|
||||
rc = GNUNET_CURL_gnunet_rc_create (ctx);
|
||||
|
@ -101,6 +101,14 @@ static int allow_address_reuse;
|
||||
*/
|
||||
const struct GNUNET_CONFIGURATION_Handle *TEH_cfg;
|
||||
|
||||
/**
|
||||
* Configuration of age restriction
|
||||
*
|
||||
* Set after loading the library, enabled in database event handler.
|
||||
*/
|
||||
bool TEH_age_restriction_enabled = false;
|
||||
struct TALER_AgeRestrictionConfig TEH_age_restriction_config = {0};
|
||||
|
||||
/**
|
||||
* Handle to the HTTP server.
|
||||
*/
|
||||
@ -142,11 +150,6 @@ char *TEH_currency;
|
||||
*/
|
||||
char *TEH_base_url;
|
||||
|
||||
/**
|
||||
* Age restriction flags and mask
|
||||
*/
|
||||
bool TEH_age_restriction_enabled = true;
|
||||
|
||||
/**
|
||||
* Default timeout in seconds for HTTP requests.
|
||||
*/
|
||||
@ -174,6 +177,7 @@ bool TEH_suicide;
|
||||
* TALER_SIGNATURE_MASTER_EXTENSION.
|
||||
*/
|
||||
struct TALER_MasterSignatureP TEH_extensions_sig;
|
||||
bool TEH_extensions_signed = false;
|
||||
|
||||
/**
|
||||
* Value to return from main()
|
||||
|
@ -197,11 +197,6 @@ extern struct TALER_EXCHANGEDB_Plugin *TEH_plugin;
|
||||
*/
|
||||
extern char *TEH_currency;
|
||||
|
||||
/*
|
||||
* Age restriction extension state
|
||||
*/
|
||||
extern bool TEH_age_restriction_enabled;
|
||||
|
||||
/**
|
||||
* Our (externally visible) base URL.
|
||||
*/
|
||||
@ -221,6 +216,7 @@ extern struct GNUNET_CURL_Context *TEH_curl_ctx;
|
||||
* Signature of the offline master key of all enabled extensions' configuration
|
||||
*/
|
||||
extern struct TALER_MasterSignatureP TEH_extensions_sig;
|
||||
extern bool TEH_extensions_signed;
|
||||
|
||||
/**
|
||||
* @brief Struct describing an URL and the handler for it.
|
||||
@ -366,4 +362,8 @@ struct TEH_RequestHandler
|
||||
};
|
||||
|
||||
|
||||
/* Age restriction configuration */
|
||||
extern bool TEH_age_restriction_enabled;
|
||||
extern struct TALER_AgeRestrictionConfig TEH_age_restriction_config;
|
||||
|
||||
#endif
|
||||
|
@ -87,15 +87,27 @@ struct BatchDepositContext
|
||||
const char *payto_uri;
|
||||
|
||||
/**
|
||||
* Additional details for extensions relevant for this
|
||||
* Additional details for policy extension relevant for this
|
||||
* deposit operation, possibly NULL!
|
||||
*/
|
||||
json_t *extension_details;
|
||||
json_t *policy_json;
|
||||
|
||||
/**
|
||||
* Hash over @e extension_details.
|
||||
* Will be true if policy_json were provided
|
||||
*/
|
||||
struct TALER_ExtensionContractHashP h_extensions;
|
||||
bool has_policy;
|
||||
|
||||
/**
|
||||
* If @e policy_json was present, the corresponding policy extension
|
||||
* calculates these details. These will be persisted in the policy_details
|
||||
* table.
|
||||
*/
|
||||
struct TALER_PolicyDetails policy_details;
|
||||
|
||||
/**
|
||||
* Hash over @e policy_details.
|
||||
*/
|
||||
struct TALER_ExtensionPolicyHashP h_policy;
|
||||
|
||||
/**
|
||||
* Time when this request was generated. Used, for example, to
|
||||
@ -173,7 +185,7 @@ again:
|
||||
&TEH_keys_exchange_sign_,
|
||||
&bdc->h_contract_terms,
|
||||
&bdc->h_wire,
|
||||
&bdc->h_extensions,
|
||||
bdc->has_policy ? &bdc->h_policy: NULL,
|
||||
bdc->exchange_timestamp,
|
||||
bdc->wire_deadline,
|
||||
bdc->refund_deadline,
|
||||
@ -242,7 +254,7 @@ batch_deposit_transaction (void *cls,
|
||||
MHD_RESULT *mhd_ret)
|
||||
{
|
||||
struct BatchDepositContext *dc = cls;
|
||||
enum GNUNET_DB_QueryStatus qs;
|
||||
enum GNUNET_DB_QueryStatus qs = GNUNET_SYSERR;
|
||||
bool balance_ok;
|
||||
bool in_conflict;
|
||||
|
||||
@ -469,12 +481,13 @@ parse_coin (struct MHD_Connection *connection,
|
||||
|
||||
TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
|
||||
if (GNUNET_OK !=
|
||||
TALER_wallet_deposit_verify (&deposit->amount_with_fee,
|
||||
TALER_wallet_deposit_verify (
|
||||
&deposit->amount_with_fee,
|
||||
&deposit->deposit_fee,
|
||||
&dc->h_wire,
|
||||
&dc->h_contract_terms,
|
||||
&deposit->coin.h_age_commitment,
|
||||
&dc->h_extensions,
|
||||
dc->has_policy ? &dc->h_policy : NULL,
|
||||
&deposit->coin.denom_pub_hash,
|
||||
dc->timestamp,
|
||||
&dc->merchant_pub,
|
||||
@ -496,11 +509,6 @@ parse_coin (struct MHD_Connection *connection,
|
||||
deposit->h_contract_terms = dc->h_contract_terms;
|
||||
deposit->wire_salt = dc->wire_salt;
|
||||
deposit->receiver_wire_account = (char *) dc->payto_uri;
|
||||
/* FIXME-OEC: #7270 should NOT insert the extension details N times,
|
||||
but rather insert them ONCE and then per-coin only use
|
||||
the resulting extension UUID/serial; so the data structure
|
||||
here should be changed once we look at extensions in earnest. */
|
||||
deposit->extension_details = dc->extension_details;
|
||||
deposit->timestamp = dc->timestamp;
|
||||
deposit->refund_deadline = dc->refund_deadline;
|
||||
deposit->wire_deadline = dc->wire_deadline;
|
||||
@ -517,7 +525,7 @@ TEH_handler_batch_deposit (struct TEH_RequestContext *rc,
|
||||
struct BatchDepositContext dc;
|
||||
json_t *coins;
|
||||
bool no_refund_deadline = true;
|
||||
bool no_extensions = true;
|
||||
bool no_policy_json = true;
|
||||
struct GNUNET_JSON_Specification spec[] = {
|
||||
GNUNET_JSON_spec_string ("merchant_payto_uri",
|
||||
&dc.payto_uri),
|
||||
@ -530,9 +538,9 @@ TEH_handler_batch_deposit (struct TEH_RequestContext *rc,
|
||||
GNUNET_JSON_spec_json ("coins",
|
||||
&coins),
|
||||
GNUNET_JSON_spec_mark_optional (
|
||||
GNUNET_JSON_spec_json ("extension_details",
|
||||
&dc.extension_details),
|
||||
&no_extensions),
|
||||
GNUNET_JSON_spec_json ("policy",
|
||||
&dc.policy_json),
|
||||
&no_policy_json),
|
||||
GNUNET_JSON_spec_timestamp ("timestamp",
|
||||
&dc.timestamp),
|
||||
GNUNET_JSON_spec_mark_optional (
|
||||
@ -563,6 +571,8 @@ TEH_handler_batch_deposit (struct TEH_RequestContext *rc,
|
||||
return MHD_YES; /* failure */
|
||||
}
|
||||
|
||||
dc.has_policy = ! no_policy_json;
|
||||
|
||||
/* validate merchant's wire details (as far as we can) */
|
||||
{
|
||||
char *emsg;
|
||||
@ -607,11 +617,26 @@ TEH_handler_batch_deposit (struct TEH_RequestContext *rc,
|
||||
TALER_merchant_wire_signature_hash (dc.payto_uri,
|
||||
&dc.wire_salt,
|
||||
&dc.h_wire);
|
||||
/* FIXME-OEC: #7270 hash actual extension JSON object here */
|
||||
// if (! no_extensions)
|
||||
memset (&dc.h_extensions,
|
||||
0,
|
||||
sizeof (dc.h_extensions));
|
||||
|
||||
/* handle policy, if present */
|
||||
if (dc.has_policy)
|
||||
{
|
||||
const char *error_hint = NULL;
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TALER_extensions_create_policy_details (
|
||||
dc.policy_json,
|
||||
&dc.policy_details,
|
||||
&error_hint))
|
||||
return TALER_MHD_reply_with_error (connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
TALER_EC_EXCHANGE_DEPOSITS_POLICY_NOT_ACCEPTED,
|
||||
error_hint);
|
||||
|
||||
TALER_deposit_policy_hash (dc.policy_json,
|
||||
&dc.h_policy);
|
||||
}
|
||||
|
||||
dc.num_coins = json_array_size (coins);
|
||||
if (0 == dc.num_coins)
|
||||
{
|
||||
@ -635,12 +660,32 @@ TEH_handler_batch_deposit (struct TEH_RequestContext *rc,
|
||||
struct TALER_EXCHANGEDB_Deposit);
|
||||
for (unsigned int i = 0; i<dc.num_coins; i++)
|
||||
{
|
||||
if (GNUNET_OK !=
|
||||
(res = parse_coin (connection,
|
||||
json_array_get (coins,
|
||||
i),
|
||||
do {
|
||||
res = parse_coin (connection,
|
||||
json_array_get (coins, i),
|
||||
&dc,
|
||||
&dc.deposits[i])))
|
||||
&dc.deposits[i]);
|
||||
if (GNUNET_OK != res)
|
||||
break;
|
||||
|
||||
/* If applicable, accumulate all contributions into the policy_details */
|
||||
if (dc.has_policy)
|
||||
{
|
||||
/* FIXME: how do deposit-fee and policy-fee interact? */
|
||||
struct TALER_Amount amount_without_fee;
|
||||
|
||||
res = TALER_amount_subtract (&amount_without_fee,
|
||||
&dc.deposits[i].amount_with_fee,
|
||||
&dc.deposits[i].deposit_fee
|
||||
);
|
||||
res = TALER_amount_add (
|
||||
&dc.policy_details.accumulated_total,
|
||||
&dc.policy_details.accumulated_total,
|
||||
&amount_without_fee);
|
||||
}
|
||||
} while(0);
|
||||
|
||||
if (GNUNET_OK != res)
|
||||
{
|
||||
for (unsigned int j = 0; j<i; j++)
|
||||
TALER_denom_sig_free (&dc.deposits[j].coin.denom_sig);
|
||||
|
@ -21,6 +21,7 @@
|
||||
* @author Florian Dold
|
||||
* @author Benedikt Mueller
|
||||
* @author Christian Grothoff
|
||||
* @author Özgür Kesim
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
@ -47,7 +48,7 @@
|
||||
* @param connection connection to the client
|
||||
* @param coin_pub public key of the coin
|
||||
* @param h_wire hash of wire details
|
||||
* @param h_extensions hash of applicable extensions
|
||||
* @param h_policy hash of applicable policy extension
|
||||
* @param h_contract_terms hash of contract details
|
||||
* @param exchange_timestamp exchange's timestamp
|
||||
* @param refund_deadline until when this deposit be refunded
|
||||
@ -61,7 +62,7 @@ reply_deposit_success (
|
||||
struct MHD_Connection *connection,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
const struct TALER_MerchantWireHashP *h_wire,
|
||||
const struct TALER_ExtensionContractHashP *h_extensions,
|
||||
const struct TALER_ExtensionPolicyHashP *h_policy,
|
||||
const struct TALER_PrivateContractHashP *h_contract_terms,
|
||||
struct GNUNET_TIME_Timestamp exchange_timestamp,
|
||||
struct GNUNET_TIME_Timestamp refund_deadline,
|
||||
@ -78,7 +79,7 @@ reply_deposit_success (
|
||||
&TEH_keys_exchange_sign_,
|
||||
h_contract_terms,
|
||||
h_wire,
|
||||
h_extensions,
|
||||
h_policy,
|
||||
exchange_timestamp,
|
||||
wire_deadline,
|
||||
refund_deadline,
|
||||
@ -131,6 +132,29 @@ struct DepositContext
|
||||
*/
|
||||
uint64_t known_coin_id;
|
||||
|
||||
/*
|
||||
* True if @e policy_json was provided
|
||||
*/
|
||||
bool has_policy;
|
||||
|
||||
/**
|
||||
* If @e has_policy is true, the corresponding policy extension calculates
|
||||
* these details. These will be persisted in the policy_details table.
|
||||
*/
|
||||
struct TALER_PolicyDetails policy_details;
|
||||
|
||||
/**
|
||||
* Hash over the policy data for this deposit (remains unknown to the
|
||||
* Exchange). Needed for the verification of the deposit's signature
|
||||
*/
|
||||
struct TALER_ExtensionPolicyHashP h_policy;
|
||||
|
||||
/**
|
||||
* When has_policy is true, and deposit->policy_details are
|
||||
* persisted, this contains the id of the record in the policy_details table.
|
||||
*/
|
||||
uint64_t policy_details_serial_id;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -163,11 +187,32 @@ deposit_transaction (void *cls,
|
||||
mhd_ret);
|
||||
if (qs < 0)
|
||||
return qs;
|
||||
qs = TEH_plugin->do_deposit (TEH_plugin->cls,
|
||||
|
||||
|
||||
/* If the deposit has a policy associated to it, persist it. This will
|
||||
* insert or update the record. */
|
||||
if (dc->has_policy)
|
||||
{
|
||||
qs = TEH_plugin->persist_policy_details (
|
||||
TEH_plugin->cls,
|
||||
&dc->policy_details,
|
||||
&dc->policy_details_serial_id,
|
||||
&dc->policy_details.accumulated_total,
|
||||
&dc->policy_details.fulfillment_state);
|
||||
|
||||
if (qs < 0)
|
||||
return qs;
|
||||
}
|
||||
|
||||
|
||||
qs = TEH_plugin->do_deposit (
|
||||
TEH_plugin->cls,
|
||||
dc->deposit,
|
||||
dc->known_coin_id,
|
||||
&dc->h_payto,
|
||||
false, /* FIXME-OEC: extension blocked #7270 */
|
||||
(dc->has_policy)
|
||||
? &dc->policy_details_serial_id
|
||||
: NULL,
|
||||
&dc->exchange_timestamp,
|
||||
&balance_ok,
|
||||
&in_conflict);
|
||||
@ -216,6 +261,8 @@ TEH_handler_deposit (struct MHD_Connection *connection,
|
||||
struct DepositContext dc;
|
||||
struct TALER_EXCHANGEDB_Deposit deposit;
|
||||
const char *payto_uri;
|
||||
struct TALER_ExtensionPolicyHashP *ph_policy = NULL;
|
||||
bool no_policy_json;
|
||||
struct GNUNET_JSON_Specification spec[] = {
|
||||
GNUNET_JSON_spec_string ("merchant_payto_uri",
|
||||
&payto_uri),
|
||||
@ -240,12 +287,18 @@ TEH_handler_deposit (struct MHD_Connection *connection,
|
||||
&deposit.csig),
|
||||
GNUNET_JSON_spec_timestamp ("timestamp",
|
||||
&deposit.timestamp),
|
||||
/* 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_timestamp ("wire_transfer_deadline",
|
||||
&deposit.wire_deadline),
|
||||
GNUNET_JSON_spec_mark_optional (
|
||||
GNUNET_JSON_spec_json ("policy",
|
||||
&dc.policy_details.policy_json),
|
||||
&no_policy_json),
|
||||
GNUNET_JSON_spec_end ()
|
||||
};
|
||||
struct TALER_MerchantWireHashP h_wire;
|
||||
@ -271,6 +324,9 @@ TEH_handler_deposit (struct MHD_Connection *connection,
|
||||
return MHD_YES; /* failure */
|
||||
}
|
||||
}
|
||||
|
||||
dc.has_policy = ! no_policy_json;
|
||||
|
||||
/* validate merchant's wire details (as far as we can) */
|
||||
{
|
||||
char *emsg;
|
||||
@ -419,6 +475,26 @@ TEH_handler_deposit (struct MHD_Connection *connection,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/* Check policy input and create policy details */
|
||||
if (dc.has_policy)
|
||||
{
|
||||
const char *error_hint = NULL;
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TALER_extensions_create_policy_details (
|
||||
dc.policy_details.policy_json,
|
||||
&dc.policy_details,
|
||||
&error_hint))
|
||||
return TALER_MHD_reply_with_error (connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
TALER_EC_EXCHANGE_DEPOSITS_POLICY_NOT_ACCEPTED,
|
||||
error_hint);
|
||||
|
||||
TALER_deposit_policy_hash (dc.policy_details.policy_json,
|
||||
&dc.h_policy);
|
||||
ph_policy = &dc.h_policy;
|
||||
}
|
||||
|
||||
TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
|
||||
if (GNUNET_OK !=
|
||||
TALER_wallet_deposit_verify (&deposit.amount_with_fee,
|
||||
@ -426,7 +502,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
|
||||
&h_wire,
|
||||
&deposit.h_contract_terms,
|
||||
&deposit.coin.h_age_commitment,
|
||||
NULL /* FIXME: h_extensions! */,
|
||||
ph_policy,
|
||||
&deposit.coin.denom_pub_hash,
|
||||
deposit.timestamp,
|
||||
&deposit.merchant_pub,
|
||||
@ -481,7 +557,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
|
||||
res = reply_deposit_success (connection,
|
||||
&deposit.coin.coin_pub,
|
||||
&h_wire,
|
||||
NULL /* FIXME: h_extensions! */,
|
||||
ph_policy,
|
||||
&deposit.h_contract_terms,
|
||||
dc.exchange_timestamp,
|
||||
deposit.refund_deadline,
|
||||
|
@ -14,7 +14,7 @@
|
||||
*/
|
||||
/**
|
||||
* @file taler-exchange-httpd_extensions.c
|
||||
* @brief Handle extensions (age-restriction, peer2peer)
|
||||
* @brief Handle extensions (age-restriction, policy extensions)
|
||||
* @author Özgür Kesim
|
||||
*/
|
||||
#include "platform.h"
|
||||
@ -77,65 +77,84 @@ extension_update_event_cb (void *cls,
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the config from the database as string
|
||||
// Get the manifest from the database as string
|
||||
{
|
||||
char *config_str = NULL;
|
||||
char *manifest_str = NULL;
|
||||
enum GNUNET_DB_QueryStatus qs;
|
||||
json_error_t err;
|
||||
json_t *config;
|
||||
json_t *manifest_js;
|
||||
enum GNUNET_GenericReturnValue ret;
|
||||
|
||||
qs = TEH_plugin->get_extension_config (TEH_plugin->cls,
|
||||
qs = TEH_plugin->get_extension_manifest (TEH_plugin->cls,
|
||||
extension->name,
|
||||
&config_str);
|
||||
&manifest_str);
|
||||
|
||||
if (qs < 0)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Couldn't get extension config\n");
|
||||
"Couldn't get extension manifest\n");
|
||||
GNUNET_break (0);
|
||||
return;
|
||||
}
|
||||
|
||||
// No config found -> disable extension
|
||||
if (NULL == config_str)
|
||||
if (NULL == manifest_str)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"No manifest found for extension %s, disabling it\n",
|
||||
extension->name);
|
||||
extension->disable ((struct TALER_Extension *) extension);
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the string as JSON
|
||||
config = json_loads (config_str, JSON_DECODE_ANY, &err);
|
||||
if (NULL == config)
|
||||
manifest_js = json_loads (manifest_str, JSON_DECODE_ANY, &err);
|
||||
if (NULL == manifest_js)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to parse config for extension `%s' as JSON: %s (%s)\n",
|
||||
"Failed to parse manifest for extension `%s' as JSON: %s (%s)\n",
|
||||
extension->name,
|
||||
err.text,
|
||||
err.source);
|
||||
GNUNET_break (0);
|
||||
free (manifest_js);
|
||||
return;
|
||||
}
|
||||
|
||||
// Call the parser for the extension
|
||||
ret = extension->load_json_config (
|
||||
ret = extension->load_config (
|
||||
(struct TALER_Extension *) extension,
|
||||
config);
|
||||
json_object_get (manifest_js, "config"));
|
||||
|
||||
if (GNUNET_OK != ret)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Couldn't parse configuration for extension %s from the database",
|
||||
extension->name);
|
||||
"Couldn't parse configuration for extension %s from the manifest in the database: %s\n",
|
||||
extension->name,
|
||||
manifest_str);
|
||||
GNUNET_break (0);
|
||||
}
|
||||
|
||||
free (manifest_str);
|
||||
json_decref (manifest_js);
|
||||
}
|
||||
|
||||
/* Special case age restriction: Update global flag and mask */
|
||||
if (TALER_Extension_AgeRestriction == type)
|
||||
{
|
||||
TEH_age_restriction_enabled =
|
||||
TALER_extensions_age_restriction_is_enabled ();
|
||||
const struct TALER_AgeRestrictionConfig *conf =
|
||||
TALER_extensions_get_age_restriction_config ();
|
||||
TEH_age_restriction_enabled = false;
|
||||
if (NULL != conf)
|
||||
{
|
||||
TEH_age_restriction_enabled = true;
|
||||
TEH_age_restriction_config = *conf;
|
||||
}
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"[age restriction] DB event has changed the config to %s with mask: %s\n",
|
||||
TEH_age_restriction_enabled ? "enabled": "DISABLED",
|
||||
TALER_age_mask_to_string (&conf->mask));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -143,14 +162,30 @@ extension_update_event_cb (void *cls,
|
||||
enum GNUNET_GenericReturnValue
|
||||
TEH_extensions_init ()
|
||||
{
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_extension_age_restriction_register ());
|
||||
|
||||
/* Set the event handler for updates */
|
||||
struct GNUNET_DB_EventHeaderP ev = {
|
||||
.size = htons (sizeof (ev)),
|
||||
.type = htons (TALER_DBEVENT_EXCHANGE_EXTENSIONS_UPDATED),
|
||||
};
|
||||
|
||||
/* Load the shared libraries first */
|
||||
if (GNUNET_OK !=
|
||||
TALER_extensions_init (TEH_cfg))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"failed to load extensions");
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
/* Check for age restriction */
|
||||
{
|
||||
const struct TALER_AgeRestrictionConfig *arc;
|
||||
|
||||
if (NULL !=
|
||||
(arc = TALER_extensions_get_age_restriction_config ()))
|
||||
TEH_age_restriction_config = *arc;
|
||||
}
|
||||
|
||||
extensions_eh = TEH_plugin->event_listen (TEH_plugin->cls,
|
||||
GNUNET_TIME_UNIT_FOREVER_REL,
|
||||
&ev,
|
||||
@ -162,17 +197,24 @@ TEH_extensions_init ()
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
/* FIXME #7270: shall we load the extensions from the config right away?
|
||||
* We do have to for now, as otherwise denominations with age restriction
|
||||
* will not have the age mask set right upon initial generation.
|
||||
*/
|
||||
TALER_extensions_load_taler_config (TEH_cfg);
|
||||
|
||||
/* Trigger the initial load of configuration from the db */
|
||||
for (const struct TALER_Extension *it = TALER_extensions_get_head ();
|
||||
NULL != it->next;
|
||||
for (const struct TALER_Extensions *it = TALER_extensions_get_head ();
|
||||
NULL != it && NULL != it->extension;
|
||||
it = it->next)
|
||||
extension_update_event_cb (NULL, &it->type, sizeof(it->type));
|
||||
{
|
||||
const struct TALER_Extension *ext = it->extension;
|
||||
uint32_t typ = htonl (ext->type);
|
||||
char *manifest = json_dumps (ext->manifest (ext), JSON_COMPACT);
|
||||
|
||||
TEH_plugin->set_extension_manifest (TEH_plugin->cls,
|
||||
ext->name,
|
||||
manifest);
|
||||
|
||||
extension_update_event_cb (NULL,
|
||||
&typ,
|
||||
sizeof(typ));
|
||||
free (manifest);
|
||||
}
|
||||
|
||||
return GNUNET_OK;
|
||||
}
|
||||
@ -190,4 +232,168 @@ TEH_extensions_done ()
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @brief Execute database transactions for /extensions/policy_* POST requests.
|
||||
*
|
||||
* @param cls a `struct TALER_PolicyFulfillmentOutcome`
|
||||
* @param connection MHD request context
|
||||
* @param[out] mhd_ret set to MHD status on error
|
||||
* @return transaction status
|
||||
*/
|
||||
static enum GNUNET_DB_QueryStatus
|
||||
policy_fulfillment_transaction (
|
||||
void *cls,
|
||||
struct MHD_Connection *connection,
|
||||
MHD_RESULT *mhd_ret)
|
||||
{
|
||||
struct TALER_PolicyFulfillmentTransactionData *fulfillment = cls;
|
||||
|
||||
return TEH_plugin->add_policy_fulfillment_proof (TEH_plugin->cls,
|
||||
fulfillment);
|
||||
}
|
||||
|
||||
|
||||
MHD_RESULT
|
||||
TEH_extensions_post_handler (
|
||||
struct TEH_RequestContext *rc,
|
||||
const json_t *root,
|
||||
const char *const args[])
|
||||
{
|
||||
const struct TALER_Extension *ext = NULL;
|
||||
json_t *output;
|
||||
struct TALER_PolicyDetails *policy_details = NULL;
|
||||
size_t policy_details_count = 0;
|
||||
|
||||
|
||||
if (NULL == args[0])
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return TALER_MHD_reply_with_error (rc->connection,
|
||||
MHD_HTTP_NOT_FOUND,
|
||||
TALER_EC_EXCHANGE_GENERIC_OPERATION_UNKNOWN,
|
||||
"/extensions/$EXTENSION");
|
||||
}
|
||||
|
||||
ext = TALER_extensions_get_by_name (args[0]);
|
||||
if (NULL == ext)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return TALER_MHD_reply_with_error (rc->connection,
|
||||
MHD_HTTP_NOT_FOUND,
|
||||
TALER_EC_EXCHANGE_GENERIC_OPERATION_UNKNOWN,
|
||||
"/extensions/$EXTENSION unknown");
|
||||
}
|
||||
|
||||
if (NULL == ext->policy_post_handler)
|
||||
return TALER_MHD_reply_with_error (rc->connection,
|
||||
MHD_HTTP_NOT_IMPLEMENTED,
|
||||
TALER_EC_EXCHANGE_GENERIC_OPERATION_UNKNOWN,
|
||||
"POST /extensions/$EXTENSION not supported");
|
||||
|
||||
/* Extract hash_codes and retrieve related policy_details from the DB */
|
||||
{
|
||||
enum GNUNET_GenericReturnValue ret;
|
||||
enum GNUNET_DB_QueryStatus qs;
|
||||
const char *error_msg;
|
||||
struct GNUNET_HashCode *hcs;
|
||||
size_t len;
|
||||
json_t*val;
|
||||
size_t idx;
|
||||
json_t *jhash_codes = json_object_get (root,
|
||||
"policy_hash_codes");
|
||||
if (! json_is_array (jhash_codes))
|
||||
return TALER_MHD_reply_with_error (rc->connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
TALER_EC_EXCHANGE_GENERIC_OPERATION_UNKNOWN,
|
||||
"policy_hash_codes are missing");
|
||||
|
||||
len = json_array_size (jhash_codes);
|
||||
hcs = GNUNET_new_array (len,
|
||||
struct GNUNET_HashCode);
|
||||
policy_details = GNUNET_new_array (len,
|
||||
struct TALER_PolicyDetails);
|
||||
|
||||
json_array_foreach (jhash_codes, idx, val)
|
||||
{
|
||||
struct GNUNET_JSON_Specification spec[] = {
|
||||
GNUNET_JSON_spec_fixed_auto (NULL, &hcs[idx]),
|
||||
GNUNET_JSON_spec_end ()
|
||||
};
|
||||
|
||||
ret = GNUNET_JSON_parse (val,
|
||||
spec,
|
||||
&error_msg,
|
||||
NULL);
|
||||
if (GNUNET_OK != ret)
|
||||
break;
|
||||
|
||||
qs = TEH_plugin->get_policy_details (TEH_plugin->cls,
|
||||
&hcs[idx],
|
||||
&policy_details[idx]);
|
||||
if (qs < 0)
|
||||
{
|
||||
error_msg = "a policy_hash_code couldn't be found";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GNUNET_free (hcs);
|
||||
if (GNUNET_OK != ret)
|
||||
{
|
||||
GNUNET_free (policy_details);
|
||||
return TALER_MHD_reply_with_error (rc->connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
TALER_EC_EXCHANGE_GENERIC_OPERATION_UNKNOWN,
|
||||
error_msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
enum GNUNET_GenericReturnValue ret;
|
||||
|
||||
ret = ext->policy_post_handler (root,
|
||||
&args[1],
|
||||
policy_details,
|
||||
policy_details_count,
|
||||
&output);
|
||||
|
||||
if (GNUNET_OK != ret)
|
||||
{
|
||||
TALER_MHD_reply_json_steal (
|
||||
rc->connection,
|
||||
output,
|
||||
MHD_HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
/* execute fulfillment transaction */
|
||||
{
|
||||
MHD_RESULT mhd_ret;
|
||||
struct TALER_PolicyFulfillmentTransactionData fulfillment = {
|
||||
.proof = root,
|
||||
.timestamp = GNUNET_TIME_timestamp_get (),
|
||||
.details = policy_details,
|
||||
.details_count = policy_details_count
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TEH_DB_run_transaction (rc->connection,
|
||||
"execute policy fulfillment",
|
||||
TEH_MT_REQUEST_POLICY_FULFILLMENT,
|
||||
&mhd_ret,
|
||||
&policy_fulfillment_transaction,
|
||||
&fulfillment))
|
||||
{
|
||||
json_decref (output);
|
||||
return mhd_ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TALER_MHD_reply_json_steal (rc->connection,
|
||||
output,
|
||||
MHD_HTTP_OK);
|
||||
}
|
||||
|
||||
|
||||
/* end of taler-exchange-httpd_extensions.c */
|
||||
|
@ -40,4 +40,19 @@ TEH_extensions_init (void);
|
||||
void
|
||||
TEH_extensions_done (void);
|
||||
|
||||
|
||||
/**
|
||||
* Handle POST "/extensions/..." requests.
|
||||
*
|
||||
* @param rc request context
|
||||
* @param root uploaded JSON data
|
||||
* @param args array of additional options
|
||||
* @return MHD result code
|
||||
*/
|
||||
MHD_RESULT
|
||||
TEH_extensions_post_handler (
|
||||
struct TEH_RequestContext *rc,
|
||||
const json_t *root,
|
||||
const char *const args[]);
|
||||
|
||||
#endif
|
||||
|
@ -17,6 +17,7 @@
|
||||
* @file taler-exchange-httpd_keys.c
|
||||
* @brief management of our various keys
|
||||
* @author Christian Grothoff
|
||||
* @author Özgür Kesim
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include "taler_json_lib.h"
|
||||
@ -815,10 +816,7 @@ static struct TALER_AgeMask
|
||||
load_age_mask (const char*section_name)
|
||||
{
|
||||
static const struct TALER_AgeMask null_mask = {0};
|
||||
struct TALER_AgeMask age_mask = TALER_extensions_age_restriction_ageMask ();
|
||||
|
||||
if (age_mask.bits == 0)
|
||||
return null_mask;
|
||||
enum GNUNET_GenericReturnValue ret;
|
||||
|
||||
if (GNUNET_OK != (GNUNET_CONFIGURATION_have_value (
|
||||
TEH_cfg,
|
||||
@ -826,9 +824,6 @@ load_age_mask (const char*section_name)
|
||||
"AGE_RESTRICTED")))
|
||||
return null_mask;
|
||||
|
||||
{
|
||||
enum GNUNET_GenericReturnValue ret;
|
||||
|
||||
if (GNUNET_SYSERR ==
|
||||
(ret = GNUNET_CONFIGURATION_get_value_yesno (TEH_cfg,
|
||||
section_name,
|
||||
@ -840,8 +835,18 @@ load_age_mask (const char*section_name)
|
||||
"Value must be YES or NO\n");
|
||||
return null_mask;
|
||||
}
|
||||
|
||||
if (GNUNET_OK == ret)
|
||||
{
|
||||
if (! TEH_age_restriction_enabled)
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
"age restriction set in section %s, yet, age restriction is not enabled\n",
|
||||
section_name);
|
||||
return TEH_age_restriction_config.mask;
|
||||
}
|
||||
return age_mask;
|
||||
|
||||
|
||||
return null_mask;
|
||||
}
|
||||
|
||||
|
||||
@ -1898,41 +1903,29 @@ create_krd (struct TEH_KeyStateHandle *ksh,
|
||||
bool has_extensions = false;
|
||||
|
||||
/* Fill in the configurations of the enabled extensions */
|
||||
for (const struct TALER_Extension *extension = TALER_extensions_get_head ();
|
||||
NULL != extension;
|
||||
extension = extension->next)
|
||||
for (const struct TALER_Extensions *iter = TALER_extensions_get_head ();
|
||||
NULL != iter && NULL != iter->extension;
|
||||
iter = iter->next)
|
||||
{
|
||||
json_t *ext;
|
||||
json_t *config_json;
|
||||
const struct TALER_Extension *extension = iter->extension;
|
||||
json_t *manifest;
|
||||
int r;
|
||||
|
||||
/* skip if not configured == disabled */
|
||||
if (NULL == extension->config ||
|
||||
NULL == extension->config_json)
|
||||
/* skip if not enabled */
|
||||
if (! extension->enabled)
|
||||
continue;
|
||||
|
||||
/* flag our findings so far */
|
||||
has_extensions = true;
|
||||
|
||||
GNUNET_assert (NULL != extension->config_json);
|
||||
|
||||
config_json = json_copy (extension->config_json);
|
||||
GNUNET_assert (NULL != config_json);
|
||||
|
||||
ext = GNUNET_JSON_PACK (
|
||||
GNUNET_JSON_pack_bool ("critical",
|
||||
extension->critical),
|
||||
GNUNET_JSON_pack_string ("version",
|
||||
extension->version),
|
||||
GNUNET_JSON_pack_object_steal ("config",
|
||||
config_json)
|
||||
);
|
||||
GNUNET_assert (NULL != ext);
|
||||
manifest = extension->manifest (extension);
|
||||
GNUNET_assert (manifest);
|
||||
|
||||
r = json_object_set_new (
|
||||
extensions,
|
||||
extension->name,
|
||||
ext);
|
||||
manifest);
|
||||
GNUNET_assert (0 == r);
|
||||
}
|
||||
|
||||
@ -1948,6 +1941,9 @@ create_krd (struct TEH_KeyStateHandle *ksh,
|
||||
extensions);
|
||||
GNUNET_assert (0 == r);
|
||||
|
||||
/* Add the signature of the extensions, if it is not zero */
|
||||
if (TEH_extensions_signed)
|
||||
{
|
||||
sig = GNUNET_JSON_PACK (
|
||||
GNUNET_JSON_pack_data_auto ("extensions_sig",
|
||||
&TEH_extensions_sig));
|
||||
@ -1955,6 +1951,7 @@ create_krd (struct TEH_KeyStateHandle *ksh,
|
||||
r = json_object_update (keys, sig);
|
||||
GNUNET_assert (0 == r);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
json_decref (extensions);
|
||||
|
@ -38,7 +38,7 @@
|
||||
struct Extension
|
||||
{
|
||||
enum TALER_Extension_Type type;
|
||||
json_t *config;
|
||||
json_t *manifest;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -52,7 +52,7 @@ struct SetExtensionsContext
|
||||
};
|
||||
|
||||
/**
|
||||
* Function implementing database transaction to set the configuration of
|
||||
* Function implementing database transaction to set the manifests of
|
||||
* extensions. It runs the transaction logic.
|
||||
* - IF it returns a non-error code, the transaction logic MUST NOT queue a
|
||||
* MHD response.
|
||||
@ -74,13 +74,13 @@ set_extensions (void *cls,
|
||||
{
|
||||
struct SetExtensionsContext *sec = cls;
|
||||
|
||||
/* save the configurations of all extensions */
|
||||
/* save the manifests of all extensions */
|
||||
for (uint32_t i = 0; i<sec->num_extensions; i++)
|
||||
{
|
||||
struct Extension *ext = &sec->extensions[i];
|
||||
const struct TALER_Extension *taler_ext;
|
||||
enum GNUNET_DB_QueryStatus qs;
|
||||
char *config;
|
||||
char *manifest;
|
||||
|
||||
taler_ext = TALER_extensions_get_by_type (ext->type);
|
||||
if (NULL == taler_ext)
|
||||
@ -90,10 +90,8 @@ set_extensions (void *cls,
|
||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||
}
|
||||
|
||||
GNUNET_assert (NULL != ext->config);
|
||||
|
||||
config = json_dumps (ext->config, JSON_COMPACT | JSON_SORT_KEYS);
|
||||
if (NULL == config)
|
||||
manifest = json_dumps (ext->manifest, JSON_COMPACT | JSON_SORT_KEYS);
|
||||
if (NULL == manifest)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
*mhd_ret = TALER_MHD_reply_with_error (connection,
|
||||
@ -103,10 +101,12 @@ set_extensions (void *cls,
|
||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||
}
|
||||
|
||||
qs = TEH_plugin->set_extension_config (
|
||||
qs = TEH_plugin->set_extension_manifest (
|
||||
TEH_plugin->cls,
|
||||
taler_ext->name,
|
||||
config);
|
||||
manifest);
|
||||
|
||||
free (manifest);
|
||||
|
||||
if (qs < 0)
|
||||
{
|
||||
@ -137,6 +137,7 @@ set_extensions (void *cls,
|
||||
|
||||
/* All extensions configured, update the signature */
|
||||
TEH_extensions_sig = sec->extensions_sig;
|
||||
TEH_extensions_signed = true;
|
||||
|
||||
return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; /* only 'success', so >=0, matters here */
|
||||
}
|
||||
@ -150,7 +151,7 @@ verify_extensions_from_json (
|
||||
const char*name;
|
||||
const struct TALER_Extension *extension;
|
||||
size_t i = 0;
|
||||
json_t *blob;
|
||||
json_t *manifest;
|
||||
|
||||
GNUNET_assert (NULL != extensions);
|
||||
GNUNET_assert (json_is_object (extensions));
|
||||
@ -159,7 +160,7 @@ verify_extensions_from_json (
|
||||
sec->extensions = GNUNET_new_array (sec->num_extensions,
|
||||
struct Extension);
|
||||
|
||||
json_object_foreach (extensions, name, blob)
|
||||
json_object_foreach (extensions, name, manifest)
|
||||
{
|
||||
int critical = 0;
|
||||
json_t *config;
|
||||
@ -175,18 +176,18 @@ verify_extensions_from_json (
|
||||
}
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TALER_extensions_is_json_config (
|
||||
blob, &critical, &version, &config))
|
||||
TALER_extensions_parse_manifest (
|
||||
manifest, &critical, &version, &config))
|
||||
return GNUNET_SYSERR;
|
||||
|
||||
if (critical != extension->critical
|
||||
|| 0 != strcmp (version, extension->version) // FIXME-oec: libtool compare
|
||||
|| NULL == config
|
||||
|| GNUNET_OK != extension->test_json_config (config))
|
||||
|| GNUNET_OK != extension->load_config (NULL, config))
|
||||
return GNUNET_SYSERR;
|
||||
|
||||
sec->extensions[i].type = extension->type;
|
||||
sec->extensions[i].config = config;
|
||||
sec->extensions[i].manifest = json_copy (manifest);
|
||||
}
|
||||
|
||||
return GNUNET_OK;
|
||||
@ -223,7 +224,8 @@ TEH_handler_management_post_extensions (
|
||||
}
|
||||
|
||||
/* Ensure we have an object */
|
||||
if (! json_is_object (extensions))
|
||||
if ((! json_is_object (extensions)) &&
|
||||
(! json_is_null (extensions)))
|
||||
{
|
||||
GNUNET_JSON_parse_free (top_spec);
|
||||
return TALER_MHD_reply_with_error (
|
||||
@ -235,13 +237,13 @@ TEH_handler_management_post_extensions (
|
||||
|
||||
/* Verify the signature */
|
||||
{
|
||||
struct TALER_ExtensionConfigHashP h_config;
|
||||
struct TALER_ExtensionManifestsHashP h_manifests;
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TALER_JSON_extensions_config_hash (extensions, &h_config) ||
|
||||
TALER_JSON_extensions_manifests_hash (extensions, &h_manifests) ||
|
||||
GNUNET_OK !=
|
||||
TALER_exchange_offline_extension_config_hash_verify (
|
||||
&h_config,
|
||||
TALER_exchange_offline_extension_manifests_hash_verify (
|
||||
&h_manifests,
|
||||
&TEH_master_public_key,
|
||||
&sec.extensions_sig))
|
||||
{
|
||||
@ -298,9 +300,9 @@ TEH_handler_management_post_extensions (
|
||||
CLEANUP:
|
||||
for (unsigned int i = 0; i < sec.num_extensions; i++)
|
||||
{
|
||||
if (NULL != sec.extensions[i].config)
|
||||
if (NULL != sec.extensions[i].manifest)
|
||||
{
|
||||
json_decref (sec.extensions[i].config);
|
||||
json_decref (sec.extensions[i].manifest);
|
||||
}
|
||||
}
|
||||
GNUNET_free (sec.extensions);
|
||||
|
@ -44,7 +44,8 @@ enum TEH_MetricTypeRequest
|
||||
TEH_MT_REQUEST_IDEMPOTENT_MELT = 10,
|
||||
TEH_MT_REQUEST_IDEMPOTENT_BATCH_WITHDRAW = 11,
|
||||
TEH_MT_REQUEST_BATCH_DEPOSIT = 12,
|
||||
TEH_MT_REQUEST_COUNT = 13 /* MUST BE LAST! */
|
||||
TEH_MT_REQUEST_POLICY_FULFILLMENT = 13,
|
||||
TEH_MT_REQUEST_COUNT = 14 /* MUST BE LAST! */
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -623,8 +623,7 @@ resolve_refreshes_reveal_denominations (
|
||||
bool failed = true;
|
||||
|
||||
/* Has been checked in handle_refreshes_reveal_json() */
|
||||
GNUNET_assert (ng ==
|
||||
TALER_extensions_age_restriction_num_groups ());
|
||||
GNUNET_assert (ng == TEH_age_restriction_config.num_groups);
|
||||
|
||||
rctx->old_age_commitment = GNUNET_new (struct TALER_AgeCommitment);
|
||||
oac = rctx->old_age_commitment;
|
||||
@ -931,7 +930,7 @@ handle_refreshes_reveal_json (struct MHD_Connection *connection,
|
||||
/* Sanity check of age commitment: If it was provided, it _must_ be an array
|
||||
* of the size the # of age groups */
|
||||
if (NULL != old_age_commitment_json
|
||||
&& TALER_extensions_age_restriction_num_groups () !=
|
||||
&& TEH_age_restriction_config.num_groups !=
|
||||
json_array_size (old_age_commitment_json))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
|
@ -76,7 +76,7 @@ TEH_RESPONSE_compile_transaction_history (
|
||||
&h_wire,
|
||||
&deposit->h_contract_terms,
|
||||
&deposit->h_age_commitment,
|
||||
NULL /* h_extensions! */,
|
||||
&deposit->h_policy,
|
||||
&deposit->h_denom_pub,
|
||||
deposit->timestamp,
|
||||
&deposit->merchant_pub,
|
||||
|
@ -907,8 +907,8 @@ BEGIN
|
||||
',wire_salt BYTEA NOT NULL CHECK (LENGTH(wire_salt)=16)'
|
||||
',wire_target_h_payto BYTEA CHECK (LENGTH(wire_target_h_payto)=32)'
|
||||
',done BOOLEAN NOT NULL DEFAULT FALSE'
|
||||
',extension_blocked BOOLEAN NOT NULL DEFAULT FALSE'
|
||||
',extension_details_serial_id INT8' -- REFERENCES extension_details (extension_details_serial_id) ON DELETE CASCADE'
|
||||
',policy_blocked BOOLEAN NOT NULL DEFAULT FALSE'
|
||||
',policy_details_serial_id INT8' -- REFERENCES policy_details (policy_details_serial_id) ON DELETE CASCADE'
|
||||
') %s ;'
|
||||
,table_name
|
||||
,'PARTITION BY HASH (coin_pub)'
|
||||
@ -2619,7 +2619,7 @@ BEGIN
|
||||
|
||||
ALTER TABLE IF EXISTS deposits
|
||||
DROP CONSTRAINT IF EXISTS deposits_pkey CASCADE
|
||||
,DROP CONSTRAINT IF EXISTS deposits_extension_details_serial_id_fkey
|
||||
,DROP CONSTRAINT IF EXISTS deposits_policy_details_serial_id_fkey
|
||||
,DROP CONSTRAINT IF EXISTS deposits_coin_pub_merchant_pub_h_contract_terms_key CASCADE
|
||||
;
|
||||
|
||||
|
@ -411,19 +411,19 @@ COMMENT ON TABLE signkey_revocations
|
||||
IS 'Table storing which online signing keys have been revoked';
|
||||
|
||||
|
||||
-- ------------------------------ extension ----------------------------------------
|
||||
-- ------------------------------ extensions ----------------------------------------
|
||||
|
||||
CREATE TABLE IF NOT EXISTS extensions
|
||||
(extension_id BIGINT GENERATED BY DEFAULT AS IDENTITY UNIQUE
|
||||
,name VARCHAR NOT NULL UNIQUE
|
||||
,config BYTEA
|
||||
,manifest BYTEA
|
||||
);
|
||||
COMMENT ON TABLE extensions
|
||||
IS 'Configurations of the activated extensions';
|
||||
COMMENT ON COLUMN extensions.name
|
||||
IS 'Name of the extension';
|
||||
COMMENT ON COLUMN extensions.config
|
||||
IS 'Configuration of the extension as JSON-blob, maybe NULL';
|
||||
COMMENT ON COLUMN extensions.manifest
|
||||
IS 'Manifest of the extension as JSON-blob, maybe NULL. It contains common meta-information and extension-specific configuration.';
|
||||
|
||||
|
||||
-- ------------------------------ known_coins ----------------------------------------
|
||||
@ -520,21 +520,69 @@ CREATE TABLE IF NOT EXISTS refresh_transfer_keys_default
|
||||
SELECT add_constraints_to_refresh_transfer_keys_partition('default');
|
||||
|
||||
|
||||
-- ------------------------------ extension_details ----------------------------------------
|
||||
-- ------------------------------ policy_fulfillments -------------------------------------
|
||||
|
||||
CREATE TABLE IF NOT EXISTS extension_details
|
||||
(extension_details_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY
|
||||
,extension_options VARCHAR)
|
||||
PARTITION BY HASH (extension_details_serial_id);
|
||||
COMMENT ON TABLE extension_details
|
||||
IS 'Extensions that were provided with deposits (not yet used).';
|
||||
COMMENT ON COLUMN extension_details.extension_options
|
||||
IS 'JSON object with options set that the exchange needs to consider when executing a deposit. Supported details depend on the extensions supported by the exchange.';
|
||||
CREATE TABLE IF NOT EXISTS policy_fulfillments
|
||||
(fulfillment_id BIGINT GENERATED BY DEFAULT AS IDENTITY UNIQUE PRIMARY KEY
|
||||
,fulfillment_timestamp INT8 NOT NULL
|
||||
,fulfillment_proof VARCHAR
|
||||
,h_fulfillment_proof BYTEA NOT NULL CHECK(LENGTH(h_fulfillment_proof) = 64) UNIQUE
|
||||
,policy_hash_codes BYTEA NOT NULL CHECK(0 = MOD(LENGTH(policy_hash_codes), 16))
|
||||
);
|
||||
COMMENT ON TABLE policy_fulfillments
|
||||
IS 'Proofs of fulfillment of policies that were set in deposits';
|
||||
COMMENT ON COLUMN policy_fulfillments.fulfillment_timestamp
|
||||
IS 'Timestamp of the arrival of a proof of fulfillment';
|
||||
COMMENT ON COLUMN policy_fulfillments.fulfillment_proof
|
||||
IS 'JSON object with a proof of the fulfillment of a policy. Supported details depend on the policy extensions supported by the exchange.';
|
||||
COMMENT ON COLUMN policy_fulfillments.h_fulfillment_proof
|
||||
IS 'Hash of the fulfillment_proof';
|
||||
COMMENT ON COLUMN policy_fulfillments.policy_hash_codes
|
||||
IS 'Concatenation of the policy_hash_code of all policy_details that are fulfilled by this proof';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS extension_details_default
|
||||
PARTITION OF extension_details
|
||||
FOR VALUES WITH (MODULUS 1, REMAINDER 0);
|
||||
-- ------------------------------ policy_details ----------------------------------------
|
||||
|
||||
CREATE TABLE IF NOT EXISTS policy_details
|
||||
(policy_details_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY
|
||||
,policy_hash_code BYTEA PRIMARY KEY CHECK(LENGTH(policy_hash_code)=16)
|
||||
,policy_json VARCHAR
|
||||
,deadline INT8 NOT NULL
|
||||
,commitment_val INT8 NOT NULL
|
||||
,commitment_frac INT4 NOT NULL
|
||||
,accumulated_total_val INT8 NOT NULL
|
||||
,accumulated_total_frac INT4 NOT NULL
|
||||
,fee_val INT8 NOT NULL
|
||||
,fee_frac INT4 NOT NULL
|
||||
,transferable_val INT8 NOT NULL
|
||||
,transferable_frac INT8 NOT NULL
|
||||
,fulfillment_state smallint NOT NULL CHECK(fulfillment_state between 0 and 5)
|
||||
,fulfillment_id BIGINT NULL REFERENCES policy_fulfillments (fulfillment_id) ON DELETE CASCADE
|
||||
);
|
||||
COMMENT ON TABLE policy_details
|
||||
IS 'Policies that were provided with deposits via policy extensions.';
|
||||
COMMENT ON COLUMN policy_details.policy_hash_code
|
||||
IS 'ID (GNUNET_HashCode) that identifies a policy. Will be calculated by the policy extension based on the content';
|
||||
COMMENT ON COLUMN policy_details.policy_json
|
||||
IS 'JSON object with options set that the exchange needs to consider when executing a deposit. Supported details depend on the policy extensions supported by the exchange.';
|
||||
COMMENT ON COLUMN policy_details.deadline
|
||||
IS 'Deadline until the policy must be marked as fulfilled (maybe "forever")';
|
||||
COMMENT ON COLUMN policy_details.commitment_val
|
||||
IS 'The amount that this policy commits to. Invariant: commitment >= fee';
|
||||
COMMENT ON COLUMN policy_details.accumulated_total_val
|
||||
IS 'The sum of all contributions of all deposit that reference this policy. Invariant: The fulfilment_state must be Insufficient as long as accumulated_total < commitment';
|
||||
COMMENT ON COLUMN policy_details.fee_val
|
||||
IS 'The fee for this policy, due when the policy is fulfilled or timed out';
|
||||
COMMENT ON COLUMN policy_details.transferable_val
|
||||
IS 'The amount that on fulfilment or timeout will be transfered to the payto-URI''s of the corresponding deposit''s. The policy fees must have been already deducted from it. Invariant: fee+transferable <= accumulated_total. The remaining amount (accumulated_total - fee - transferable) can be refreshed by the owner of the coins when the state is Timeout or Success.';
|
||||
COMMENT ON COLUMN policy_details.fulfillment_state
|
||||
IS 'State of the fulfillment:
|
||||
- 0 (Failure)
|
||||
- 1 (Insufficient)
|
||||
- 2 (Ready)
|
||||
- 4 (Success)
|
||||
- 5 (Timeout)';
|
||||
COMMENT ON COLUMN policy_details.fulfillment_id
|
||||
IS 'Reference to the proof of the fulfillment of this policy, if it exists. Invariant: If not NULL, this entry''s .hash_code MUST be part of the corresponding policy_fulfillments.policy_hash_codes array.';
|
||||
|
||||
-- ------------------------------ deposits ----------------------------------------
|
||||
|
||||
@ -552,10 +600,10 @@ COMMENT ON COLUMN deposits.wire_salt
|
||||
IS 'Salt used when hashing the payto://-URI to get the h_wire';
|
||||
COMMENT ON COLUMN deposits.done
|
||||
IS 'Set to TRUE once we have included this deposit in some aggregate wire transfer to the merchant';
|
||||
COMMENT ON COLUMN deposits.extension_blocked
|
||||
IS 'True if the aggregation of the deposit is currently blocked by some extension mechanism. Used to filter out deposits that must not be processed by the canonical deposit logic.';
|
||||
COMMENT ON COLUMN deposits.extension_details_serial_id
|
||||
IS 'References extensions table, NULL if extensions are not used';
|
||||
COMMENT ON COLUMN deposits.policy_blocked
|
||||
IS 'True if the aggregation of the deposit is currently blocked by some policy extension mechanism. Used to filter out deposits that must not be processed by the canonical deposit logic.';
|
||||
COMMENT ON COLUMN deposits.policy_details_serial_id
|
||||
IS 'References policy extensions table, NULL if extensions are not used';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS deposits_default
|
||||
PARTITION OF deposits
|
||||
@ -591,7 +639,7 @@ CREATE OR REPLACE FUNCTION deposits_insert_trigger()
|
||||
DECLARE
|
||||
is_ready BOOLEAN;
|
||||
BEGIN
|
||||
is_ready = NOT (NEW.done OR NEW.extension_blocked);
|
||||
is_ready = NOT (NEW.done OR NEW.policy_blocked);
|
||||
|
||||
IF (is_ready)
|
||||
THEN
|
||||
@ -635,8 +683,8 @@ DECLARE
|
||||
DECLARE
|
||||
is_ready BOOLEAN;
|
||||
BEGIN
|
||||
was_ready = NOT (OLD.done OR OLD.extension_blocked);
|
||||
is_ready = NOT (NEW.done OR NEW.extension_blocked);
|
||||
was_ready = NOT (OLD.done OR OLD.policy_blocked);
|
||||
is_ready = NOT (NEW.done OR NEW.policy_blocked);
|
||||
IF (was_ready AND NOT is_ready)
|
||||
THEN
|
||||
DELETE FROM exchange.deposits_by_ready
|
||||
@ -690,7 +738,7 @@ CREATE OR REPLACE FUNCTION deposits_delete_trigger()
|
||||
DECLARE
|
||||
was_ready BOOLEAN;
|
||||
BEGIN
|
||||
was_ready = NOT (OLD.done OR OLD.extension_blocked);
|
||||
was_ready = NOT (OLD.done OR OLD.policy_blocked);
|
||||
|
||||
IF (was_ready)
|
||||
THEN
|
||||
|
@ -872,11 +872,11 @@ irbt_cb_table_deposits (struct PostgresClosure *pg,
|
||||
GNUNET_PQ_query_param_auto_from_type (&td->details.deposits.wire_salt),
|
||||
GNUNET_PQ_query_param_auto_from_type (
|
||||
&td->details.deposits.wire_target_h_payto),
|
||||
GNUNET_PQ_query_param_bool (td->details.deposits.extension_blocked),
|
||||
0 == td->details.deposits.extension_details_serial_id
|
||||
GNUNET_PQ_query_param_bool (td->details.deposits.policy_blocked),
|
||||
0 == td->details.deposits.policy_details_serial_id
|
||||
? GNUNET_PQ_query_param_null ()
|
||||
: GNUNET_PQ_query_param_uint64 (
|
||||
&td->details.deposits.extension_details_serial_id),
|
||||
&td->details.deposits.policy_details_serial_id),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
|
||||
@ -898,8 +898,8 @@ irbt_cb_table_deposits (struct PostgresClosure *pg,
|
||||
",coin_sig"
|
||||
",wire_salt"
|
||||
",wire_target_h_payto"
|
||||
",extension_blocked"
|
||||
",extension_details_serial_id"
|
||||
",policy_blocked"
|
||||
",policy_details_serial_id"
|
||||
") VALUES "
|
||||
"($1, $2, $3, $4, $5, $6, $7, $8, $9, $10,"
|
||||
" $11, $12, $13, $14, $15, $16, $17);");
|
||||
@ -1217,9 +1217,9 @@ irbt_cb_table_extensions (struct PostgresClosure *pg,
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_uint64 (&td->serial),
|
||||
GNUNET_PQ_query_param_string (td->details.extensions.name),
|
||||
NULL == td->details.extensions.config ?
|
||||
NULL == td->details.extensions.manifest ?
|
||||
GNUNET_PQ_query_param_null () :
|
||||
GNUNET_PQ_query_param_string (td->details.extensions.config),
|
||||
GNUNET_PQ_query_param_string (td->details.extensions.manifest),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
|
||||
@ -1228,7 +1228,7 @@ irbt_cb_table_extensions (struct PostgresClosure *pg,
|
||||
"INSERT INTO extensions"
|
||||
"(extension_id"
|
||||
",name"
|
||||
",config"
|
||||
",manifest"
|
||||
") VALUES "
|
||||
"($1, $2, $3);");
|
||||
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
|
||||
@ -1238,34 +1238,99 @@ irbt_cb_table_extensions (struct PostgresClosure *pg,
|
||||
|
||||
|
||||
/**
|
||||
* Function called with extension_details records to insert into table.
|
||||
* Function called with policy_details records to insert into table.
|
||||
*
|
||||
* @param pg plugin context
|
||||
* @param td record to insert
|
||||
*/
|
||||
static enum GNUNET_DB_QueryStatus
|
||||
irbt_cb_table_extension_details (struct PostgresClosure *pg,
|
||||
irbt_cb_table_policy_details (struct PostgresClosure *pg,
|
||||
const struct TALER_EXCHANGEDB_TableData *td)
|
||||
{
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_uint64 (&td->serial),
|
||||
NULL ==
|
||||
td->details.extension_details.extension_options ?
|
||||
GNUNET_PQ_query_param_null () :
|
||||
GNUNET_PQ_query_param_string (
|
||||
td->details.extension_details.extension_options),
|
||||
GNUNET_PQ_query_param_auto_from_type (
|
||||
&td->details.policy_details.hash_code),
|
||||
(td->details.policy_details.no_policy_json)
|
||||
? GNUNET_PQ_query_param_null ()
|
||||
: TALER_PQ_query_param_json (td->details.policy_details.policy_json),
|
||||
TALER_PQ_query_param_amount (&td->details.policy_details.commitment),
|
||||
TALER_PQ_query_param_amount (&td->details.policy_details.accumulated_total),
|
||||
TALER_PQ_query_param_amount (&td->details.policy_details.fee),
|
||||
TALER_PQ_query_param_amount (&td->details.policy_details.transferable),
|
||||
GNUNET_PQ_query_param_timestamp (&td->details.policy_details.deadline),
|
||||
GNUNET_PQ_query_param_uint16 (
|
||||
&td->details.policy_details.fulfillment_state),
|
||||
(td->details.policy_details.no_fulfillment_id)
|
||||
? GNUNET_PQ_query_param_null ()
|
||||
: GNUNET_PQ_query_param_uint64 (
|
||||
&td->details.policy_details.fulfillment_id),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
|
||||
PREPARE (pg,
|
||||
"insert_into_table_extension_details",
|
||||
"INSERT INTO extension_details"
|
||||
"(extension_details_serial_id"
|
||||
",extension_options"
|
||||
"insert_into_table_policy_details",
|
||||
"INSERT INTO policy_details"
|
||||
"(policy_details_serial_id"
|
||||
",policy_hash_code"
|
||||
",policy_json"
|
||||
",deadline"
|
||||
",commitment_val"
|
||||
",commitment_frac"
|
||||
",accumulated_total_val"
|
||||
",accumulated_total_frac"
|
||||
",fee_val"
|
||||
",fee_frac"
|
||||
",transferable_val"
|
||||
",transferable_frac"
|
||||
",fulfillment_state"
|
||||
",fulfillment_id"
|
||||
") VALUES "
|
||||
"($1, $2);");
|
||||
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
|
||||
"insert_into_table_extension_details",
|
||||
"insert_into_table_policy_details",
|
||||
params);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function called with policy_fulfillment records to insert into table.
|
||||
*
|
||||
* @param pg plugin context
|
||||
* @param td record to insert
|
||||
*/
|
||||
static enum GNUNET_DB_QueryStatus
|
||||
irbt_cb_table_policy_fulfillments (struct PostgresClosure *pg,
|
||||
const struct TALER_EXCHANGEDB_TableData *td)
|
||||
{
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_uint64 (&td->serial),
|
||||
GNUNET_PQ_query_param_timestamp (
|
||||
&td->details.policy_fulfillments.fulfillment_timestamp),
|
||||
(NULL == td->details.policy_fulfillments.fulfillment_proof)
|
||||
? GNUNET_PQ_query_param_null ()
|
||||
: GNUNET_PQ_query_param_string (
|
||||
td->details.policy_fulfillments.fulfillment_proof),
|
||||
GNUNET_PQ_query_param_auto_from_type (
|
||||
&td->details.policy_fulfillments.h_fulfillment_proof),
|
||||
GNUNET_PQ_query_param_fixed_size (
|
||||
td->details.policy_fulfillments.policy_hash_codes,
|
||||
td->details.policy_fulfillments.policy_hash_codes_count),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
|
||||
PREPARE (pg,
|
||||
"insert_into_table_policy_fulfillments",
|
||||
"INSERT INTO policy_fulfillments "
|
||||
"(fulfillment_id"
|
||||
",fulfillment_timestamp"
|
||||
",fulfillment_proof"
|
||||
",h_fulfillment_proof"
|
||||
",policy_hash_codes"
|
||||
") VALUES "
|
||||
"($1, $2, $3, $4, $5);");
|
||||
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
|
||||
"insert_into_table_policy_fulfillments",
|
||||
params);
|
||||
}
|
||||
|
||||
@ -1900,8 +1965,11 @@ TEH_PG_insert_records_by_table (void *cls,
|
||||
case TALER_EXCHANGEDB_RT_EXTENSIONS:
|
||||
rh = &irbt_cb_table_extensions;
|
||||
break;
|
||||
case TALER_EXCHANGEDB_RT_EXTENSION_DETAILS:
|
||||
rh = &irbt_cb_table_extension_details;
|
||||
case TALER_EXCHANGEDB_RT_POLICY_DETAILS:
|
||||
rh = &irbt_cb_table_policy_details;
|
||||
break;
|
||||
case TALER_EXCHANGEDB_RT_POLICY_FULFILLMENTS:
|
||||
rh = &irbt_cb_table_policy_fulfillments;
|
||||
break;
|
||||
case TALER_EXCHANGEDB_RT_PURSE_REQUESTS:
|
||||
rh = &irbt_cb_table_purse_requests;
|
||||
|
@ -927,7 +927,7 @@ lrbt_cb_table_deposits (void *cls,
|
||||
|
||||
for (unsigned int i = 0; i<num_results; i++)
|
||||
{
|
||||
bool no_extension;
|
||||
bool no_policy;
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_uint64 (
|
||||
"serial",
|
||||
@ -972,13 +972,13 @@ lrbt_cb_table_deposits (void *cls,
|
||||
"wire_target_h_payto",
|
||||
&td.details.deposits.wire_target_h_payto),
|
||||
GNUNET_PQ_result_spec_auto_from_type (
|
||||
"extension_blocked",
|
||||
&td.details.deposits.extension_blocked),
|
||||
"policy_blocked",
|
||||
&td.details.deposits.policy_blocked),
|
||||
GNUNET_PQ_result_spec_allow_null (
|
||||
GNUNET_PQ_result_spec_uint64 (
|
||||
"extension_details_serial_id",
|
||||
&td.details.deposits.extension_details_serial_id),
|
||||
&no_extension),
|
||||
"policy_details_serial_id",
|
||||
&td.details.deposits.policy_details_serial_id),
|
||||
&no_policy),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
@ -1414,7 +1414,7 @@ lrbt_cb_table_extensions (void *cls,
|
||||
struct TALER_EXCHANGEDB_TableData td = {
|
||||
.table = TALER_EXCHANGEDB_RT_EXTENSIONS
|
||||
};
|
||||
bool no_config = false;
|
||||
bool no_manifest = false;
|
||||
|
||||
for (unsigned int i = 0; i<num_results; i++)
|
||||
{
|
||||
@ -1424,9 +1424,9 @@ lrbt_cb_table_extensions (void *cls,
|
||||
GNUNET_PQ_result_spec_string ("name",
|
||||
&td.details.extensions.name),
|
||||
GNUNET_PQ_result_spec_allow_null (
|
||||
GNUNET_PQ_result_spec_string ("config",
|
||||
&td.details.extensions.config),
|
||||
&no_config),
|
||||
GNUNET_PQ_result_spec_string ("manifest",
|
||||
&td.details.extensions.manifest),
|
||||
&no_manifest),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
@ -1447,33 +1447,112 @@ lrbt_cb_table_extensions (void *cls,
|
||||
|
||||
|
||||
/**
|
||||
* Function called with extension_details table entries.
|
||||
* Function called with policy_details table entries.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param result the postgres result
|
||||
* @param num_results the number of results in @a result
|
||||
*/
|
||||
static void
|
||||
lrbt_cb_table_extension_details (void *cls,
|
||||
lrbt_cb_table_policy_details (void *cls,
|
||||
PGresult *result,
|
||||
unsigned int num_results)
|
||||
{
|
||||
struct LookupRecordsByTableContext *ctx = cls;
|
||||
struct PostgresClosure *pg = ctx->pg;
|
||||
struct TALER_EXCHANGEDB_TableData td = {
|
||||
.table = TALER_EXCHANGEDB_RT_POLICY_DETAILS
|
||||
};
|
||||
|
||||
for (unsigned int i = 0; i<num_results; i++)
|
||||
{
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_uint64 ("policy_details_serial_id",
|
||||
&td.serial),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("hash_code",
|
||||
&td.details.policy_details.
|
||||
hash_code),
|
||||
GNUNET_PQ_result_spec_allow_null (
|
||||
TALER_PQ_result_spec_json ("policy_json",
|
||||
&td.details.policy_details.
|
||||
policy_json),
|
||||
&td.details.policy_details.no_policy_json),
|
||||
GNUNET_PQ_result_spec_timestamp ("deadline",
|
||||
&td.details.policy_details.
|
||||
deadline),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("commitment",
|
||||
&td.details.policy_details.
|
||||
commitment),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("accumulated_total",
|
||||
&td.details.policy_details.
|
||||
accumulated_total),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("fee",
|
||||
&td.details.policy_details.
|
||||
fee),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("transferable",
|
||||
&td.details.policy_details.
|
||||
transferable),
|
||||
GNUNET_PQ_result_spec_uint16 ("fulfillment_state",
|
||||
&td.details.policy_details.
|
||||
fulfillment_state),
|
||||
GNUNET_PQ_result_spec_allow_null (
|
||||
GNUNET_PQ_result_spec_uint64 ("fulfillment_id",
|
||||
&td.details.policy_details.
|
||||
fulfillment_id),
|
||||
&td.details.policy_details.no_fulfillment_id),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_PQ_extract_result (result,
|
||||
rs,
|
||||
i))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
ctx->error = true;
|
||||
return;
|
||||
}
|
||||
ctx->cb (ctx->cb_cls,
|
||||
&td);
|
||||
GNUNET_PQ_cleanup_result (rs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function called with policy_fulfillments table entries.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param result the postgres result
|
||||
* @param num_results the number of results in @a result
|
||||
*/
|
||||
static void
|
||||
lrbt_cb_table_policy_fulfillments (void *cls,
|
||||
PGresult *result,
|
||||
unsigned int num_results)
|
||||
{
|
||||
struct LookupRecordsByTableContext *ctx = cls;
|
||||
struct TALER_EXCHANGEDB_TableData td = {
|
||||
.table = TALER_EXCHANGEDB_RT_EXTENSION_DETAILS
|
||||
.table = TALER_EXCHANGEDB_RT_POLICY_FULFILLMENTS
|
||||
};
|
||||
|
||||
for (unsigned int i = 0; i<num_results; i++)
|
||||
{
|
||||
bool no_config = false;
|
||||
bool no_proof = false;
|
||||
bool no_timestamp = false;
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_uint64 ("extension_details_serial_id",
|
||||
GNUNET_PQ_result_spec_uint64 ("fulfillment_id",
|
||||
&td.serial),
|
||||
GNUNET_PQ_result_spec_allow_null (
|
||||
GNUNET_PQ_result_spec_string ("extension_options",
|
||||
&td.details.extension_details.
|
||||
extension_options),
|
||||
&no_config),
|
||||
GNUNET_PQ_result_spec_timestamp ("fulfillment_timestamp",
|
||||
&td.details.policy_fulfillments.
|
||||
fulfillment_timestamp),
|
||||
&no_timestamp),
|
||||
GNUNET_PQ_result_spec_allow_null (
|
||||
GNUNET_PQ_result_spec_string ("fulfillment_proof",
|
||||
&td.details.policy_fulfillments.
|
||||
fulfillment_proof),
|
||||
&no_proof),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
@ -2607,9 +2686,13 @@ TEH_PG_lookup_records_by_table (void *cls,
|
||||
statement = "select_above_serial_by_table_extensions";
|
||||
rh = &lrbt_cb_table_extensions;
|
||||
break;
|
||||
case TALER_EXCHANGEDB_RT_EXTENSION_DETAILS:
|
||||
statement = "select_above_serial_by_table_extension_details";
|
||||
rh = &lrbt_cb_table_extension_details;
|
||||
case TALER_EXCHANGEDB_RT_POLICY_DETAILS:
|
||||
statement = "select_above_serial_by_table_policy_details";
|
||||
rh = &lrbt_cb_table_policy_details;
|
||||
break;
|
||||
case TALER_EXCHANGEDB_RT_POLICY_FULFILLMENTS:
|
||||
statement = "select_above_serial_by_table_policy_fulfillments";
|
||||
rh = &lrbt_cb_table_policy_fulfillments;
|
||||
break;
|
||||
case TALER_EXCHANGEDB_RT_PURSE_REQUESTS:
|
||||
XPREPARE ("select_above_serial_by_table_purse_requests",
|
||||
|
@ -277,12 +277,20 @@ TEH_PG_lookup_serial_by_table (void *cls,
|
||||
" ORDER BY extension_id DESC"
|
||||
" LIMIT 1;");
|
||||
break;
|
||||
case TALER_EXCHANGEDB_RT_EXTENSION_DETAILS:
|
||||
XPREPARE ("select_serial_by_table_extension_details",
|
||||
case TALER_EXCHANGEDB_RT_POLICY_DETAILS:
|
||||
XPREPARE ("select_serial_by_table_policy_details",
|
||||
"SELECT"
|
||||
" extension_details_serial_id AS serial"
|
||||
" FROM extension_details"
|
||||
" ORDER BY extension_details_serial_id DESC"
|
||||
" policy_details_serial_id AS serial"
|
||||
" FROM policy_details"
|
||||
" ORDER BY policy_details_serial_id DESC"
|
||||
" LIMIT 1;");
|
||||
break;
|
||||
case TALER_EXCHANGEDB_RT_POLICY_FULFILLMENTS:
|
||||
XPREPARE ("select_serial_by_table_policy_fulfillments",
|
||||
"SELECT"
|
||||
" fulfillment_id AS serial"
|
||||
" FROM policy_fulfillments"
|
||||
" ORDER BY fulfillment_id DESC"
|
||||
" LIMIT 1;");
|
||||
break;
|
||||
case TALER_EXCHANGEDB_RT_PURSE_REQUESTS:
|
||||
|
@ -2099,17 +2099,17 @@ prepare_statements (struct PostgresClosure *pg)
|
||||
" WHERE job_name=$1"
|
||||
" AND start_row=$2"
|
||||
" AND end_row=$3"),
|
||||
/* Used in #postgres_set_extension_config */
|
||||
/* Used in #postgres_set_extension_manifest */
|
||||
GNUNET_PQ_make_prepare (
|
||||
"set_extension_config",
|
||||
"INSERT INTO extensions (name, config) VALUES ($1, $2) "
|
||||
"set_extension_manifest",
|
||||
"INSERT INTO extensions (name, manifest) VALUES ($1, $2) "
|
||||
"ON CONFLICT (name) "
|
||||
"DO UPDATE SET config=$2"),
|
||||
/* Used in #postgres_get_extension_config */
|
||||
"DO UPDATE SET manifest=$2"),
|
||||
/* Used in #postgres_get_extension_manifest */
|
||||
GNUNET_PQ_make_prepare (
|
||||
"get_extension_config",
|
||||
"get_extension_manifest",
|
||||
"SELECT "
|
||||
" config "
|
||||
" manifest "
|
||||
"FROM extensions"
|
||||
" WHERE name=$1;"),
|
||||
/* Used in #postgres_insert_contract() */
|
||||
@ -4083,7 +4083,7 @@ compute_shard (const struct TALER_MerchantPublicKeyP *merchant_pub)
|
||||
* @param deposit deposit operation details
|
||||
* @param known_coin_id row of the coin in the known_coins table
|
||||
* @param h_payto hash of the merchant's bank account details
|
||||
* @param extension_blocked true if an extension is blocking the wire transfer
|
||||
* @param _blocked true if an extension is blocking the wire transfer
|
||||
* @param[in,out] exchange_timestamp time to use for the deposit (possibly updated)
|
||||
* @param[out] balance_ok set to true if the balance was sufficient
|
||||
* @param[out] in_conflict set to true if the deposit conflicted
|
||||
@ -4095,7 +4095,7 @@ postgres_do_deposit (
|
||||
const struct TALER_EXCHANGEDB_Deposit *deposit,
|
||||
uint64_t known_coin_id,
|
||||
const struct TALER_PaytoHashP *h_payto,
|
||||
bool extension_blocked,
|
||||
uint64_t *policy_details_serial_id,
|
||||
struct GNUNET_TIME_Timestamp *exchange_timestamp,
|
||||
bool *balance_ok,
|
||||
bool *in_conflict)
|
||||
@ -4117,10 +4117,10 @@ postgres_do_deposit (
|
||||
GNUNET_PQ_query_param_auto_from_type (&deposit->coin.coin_pub),
|
||||
GNUNET_PQ_query_param_auto_from_type (&deposit->csig),
|
||||
GNUNET_PQ_query_param_uint64 (&deposit_shard),
|
||||
GNUNET_PQ_query_param_bool (extension_blocked),
|
||||
(NULL == deposit->extension_details)
|
||||
GNUNET_PQ_query_param_bool (deposit->has_policy),
|
||||
(NULL == policy_details_serial_id)
|
||||
? GNUNET_PQ_query_param_null ()
|
||||
: TALER_PQ_query_param_json (deposit->extension_details),
|
||||
: GNUNET_PQ_query_param_uint64 (policy_details_serial_id),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
@ -4140,6 +4140,101 @@ postgres_do_deposit (
|
||||
}
|
||||
|
||||
|
||||
/* Get the details of a policy, referenced by its hash code
|
||||
*
|
||||
* @param cls the `struct PostgresClosure` with the plugin-specific state
|
||||
* @param hc The hash code under which the details to a particular policy should be found
|
||||
* @param[out] details The found details
|
||||
* @return query execution status
|
||||
* */
|
||||
static enum GNUNET_DB_QueryStatus
|
||||
postgres_get_policy_details (
|
||||
void *cls,
|
||||
const struct GNUNET_HashCode *hc,
|
||||
struct TALER_PolicyDetails *details)
|
||||
{
|
||||
struct PostgresClosure *pg = cls;
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_auto_from_type (hc),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_timestamp ("deadline",
|
||||
&details->deadline),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("commitment",
|
||||
&details->commitment),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("accumulated_total",
|
||||
&details->accumulated_total),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("policy_fee",
|
||||
&details->policy_fee),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("transferable_amount",
|
||||
&details->transferable_amount),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("state",
|
||||
&details->fulfillment_state),
|
||||
GNUNET_PQ_result_spec_allow_null (
|
||||
GNUNET_PQ_result_spec_uint64 ("policy_fulfillment_id",
|
||||
&details->policy_fulfillment_id),
|
||||
&details->no_policy_fulfillment_id),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
||||
"get_policy_details",
|
||||
params,
|
||||
rs);
|
||||
}
|
||||
|
||||
|
||||
/* Persist the details to a policy in the policy_details table. If there
|
||||
* already exists a policy, update the fields accordingly.
|
||||
*
|
||||
* @param details The policy details that should be persisted. If an entry for
|
||||
* the given details->hash_code exists, the values will be updated.
|
||||
* @param[out] policy_details_serial_id The row ID of the policy details
|
||||
* @param[out] accumulated_total The total amount accumulated in that policy
|
||||
* @param[out] fulfillment_state The state of policy. If the state was Insufficient prior to the call and the provided deposit raises the accumulated_total above the commitment, it will be set to Ready.
|
||||
* @return query execution status
|
||||
*/
|
||||
static enum GNUNET_DB_QueryStatus
|
||||
postgres_persist_policy_details (
|
||||
void *cls,
|
||||
const struct TALER_PolicyDetails *details,
|
||||
uint64_t *policy_details_serial_id,
|
||||
struct TALER_Amount *accumulated_total,
|
||||
enum TALER_PolicyFulfillmentState *fulfillment_state)
|
||||
{
|
||||
struct PostgresClosure *pg = cls;
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_auto_from_type (&details->hash_code),
|
||||
TALER_PQ_query_param_json (details->policy_json),
|
||||
GNUNET_PQ_query_param_timestamp (&details->deadline),
|
||||
TALER_PQ_query_param_amount (&details->commitment),
|
||||
TALER_PQ_query_param_amount (&details->accumulated_total),
|
||||
TALER_PQ_query_param_amount (&details->policy_fee),
|
||||
TALER_PQ_query_param_amount (&details->transferable_amount),
|
||||
GNUNET_PQ_query_param_auto_from_type (&details->fulfillment_state),
|
||||
(details->no_policy_fulfillment_id)
|
||||
? GNUNET_PQ_query_param_null ()
|
||||
: GNUNET_PQ_query_param_uint64 (&details->policy_fulfillment_id),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_uint64 ("policy_details_serial_id",
|
||||
policy_details_serial_id),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("accumulated_total",
|
||||
accumulated_total),
|
||||
GNUNET_PQ_result_spec_uint32 ("fulfillment_state",
|
||||
fulfillment_state),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
||||
"call_insert_or_update_policy_details",
|
||||
params,
|
||||
rs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Perform melt operation, checking for sufficient balance
|
||||
* of the coin and possibly persisting the melt details.
|
||||
@ -4394,6 +4489,118 @@ postgres_do_recoup_refresh (
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Compares two indices into an array of hash codes according to
|
||||
* GNUNET_CRYPTO_hash_cmp of the content at those index positions.
|
||||
*
|
||||
* Used in a call qsort_t in order to generate sorted policy_hash_codes.
|
||||
*/
|
||||
static int
|
||||
hash_code_cmp (
|
||||
const void *hc1,
|
||||
const void *hc2,
|
||||
void *arg)
|
||||
{
|
||||
size_t i1 = *(size_t *) hc1;
|
||||
size_t i2 = *(size_t *) hc2;
|
||||
const struct TALER_PolicyDetails *d = arg;
|
||||
|
||||
return GNUNET_CRYPTO_hash_cmp (&d[i1].hash_code,
|
||||
&d[i2].hash_code);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a proof of fulfillment into the policy_fulfillments table
|
||||
*
|
||||
* @param cls the `struct PostgresClosure` with the plugin-specific state
|
||||
* @param[out] proof_id set record id for the proof
|
||||
* @return query execution status
|
||||
*/
|
||||
static enum GNUNET_DB_QueryStatus
|
||||
postgres_add_policy_fulfillment_proof (
|
||||
void *cls,
|
||||
struct TALER_PolicyFulfillmentTransactionData *fulfillment)
|
||||
{
|
||||
enum GNUNET_DB_QueryStatus qs;
|
||||
struct PostgresClosure *pg = cls;
|
||||
size_t count = fulfillment->details_count;
|
||||
struct GNUNET_HashCode hcs[count];
|
||||
|
||||
/* Create the sorted policy_hash_codes */
|
||||
{
|
||||
size_t idx[count];
|
||||
for (size_t i = 0; i < count; i++)
|
||||
idx[i] = i;
|
||||
|
||||
/* Sort the indices according to the hash codes of the corresponding
|
||||
* details. */
|
||||
qsort_r (idx,
|
||||
count,
|
||||
sizeof(size_t),
|
||||
hash_code_cmp,
|
||||
fulfillment->details);
|
||||
|
||||
/* Finally, concatenate all hash_codes in sorted order */
|
||||
for (size_t i = 0; i < count; i++)
|
||||
hcs[i] = fulfillment->details[idx[i]].hash_code;
|
||||
}
|
||||
|
||||
|
||||
/* Now, add the proof to the policy_fulfillments table, retrieve the
|
||||
* record_id */
|
||||
{
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_timestamp (&fulfillment->timestamp),
|
||||
TALER_PQ_query_param_json (fulfillment->proof),
|
||||
GNUNET_PQ_query_param_auto_from_type (&fulfillment->h_proof),
|
||||
GNUNET_PQ_query_param_fixed_size (hcs,
|
||||
count * sizeof(struct GNUNET_HashCode)),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_uint64 ("fulfillment_id",
|
||||
&fulfillment->fulfillment_id),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
||||
"insert_proof_into_policy_fulfillments",
|
||||
params,
|
||||
rs);
|
||||
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
|
||||
return qs;
|
||||
}
|
||||
|
||||
/* Now, set the states of each entry corresponding to the hash_codes in
|
||||
* policy_details accordingly */
|
||||
for (size_t i = 0; i < count; i++)
|
||||
{
|
||||
struct TALER_PolicyDetails *pos = &fulfillment->details[i];
|
||||
{
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_auto_from_type (&pos->hash_code),
|
||||
GNUNET_PQ_query_param_timestamp (&pos->deadline),
|
||||
TALER_PQ_query_param_amount (&pos->commitment),
|
||||
TALER_PQ_query_param_amount (&pos->accumulated_total),
|
||||
TALER_PQ_query_param_amount (&pos->policy_fee),
|
||||
TALER_PQ_query_param_amount (&pos->transferable_amount),
|
||||
GNUNET_PQ_query_param_auto_from_type (&pos->fulfillment_state),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
|
||||
qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
|
||||
"update_policy_details",
|
||||
params);
|
||||
if (qs < 0)
|
||||
return qs;
|
||||
}
|
||||
}
|
||||
|
||||
return qs;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the balance of the specified reserve.
|
||||
*
|
||||
@ -10465,8 +10672,8 @@ postgres_delete_shard_locks (void *cls)
|
||||
|
||||
|
||||
/**
|
||||
* Function called to save the configuration of an extension
|
||||
* (age-restriction, peer2peer, ...). After successful storage of the
|
||||
* Function called to save the manifest of an extension
|
||||
* (age-restriction, policy_extension_...) After successful storage of the
|
||||
* configuration it triggers the corresponding event.
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
@ -10475,15 +10682,15 @@ postgres_delete_shard_locks (void *cls)
|
||||
* @return transaction status code
|
||||
*/
|
||||
enum GNUNET_DB_QueryStatus
|
||||
postgres_set_extension_config (void *cls,
|
||||
postgres_set_extension_manifest (void *cls,
|
||||
const char *extension_name,
|
||||
const char *config)
|
||||
const char *manifest)
|
||||
{
|
||||
struct PostgresClosure *pg = cls;
|
||||
struct GNUNET_PQ_QueryParam pcfg =
|
||||
(NULL == config || 0 == *config)
|
||||
(NULL == manifest || 0 == *manifest)
|
||||
? GNUNET_PQ_query_param_null ()
|
||||
: GNUNET_PQ_query_param_string (config);
|
||||
: GNUNET_PQ_query_param_string (manifest);
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_string (extension_name),
|
||||
pcfg,
|
||||
@ -10491,24 +10698,24 @@ postgres_set_extension_config (void *cls,
|
||||
};
|
||||
|
||||
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
|
||||
"set_extension_config",
|
||||
"set_extension_manifest",
|
||||
params);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function called to get the configuration of an extension
|
||||
* (age-restriction, peer2peer, ...)
|
||||
* Function called to get the manifest of an extension
|
||||
* (age-restriction, policy_extension_...)
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param extension_name the name of the extension
|
||||
* @param[out] config JSON object of the configuration as string
|
||||
* @param[out] manifest JSON object of the manifest as string
|
||||
* @return transaction status code
|
||||
*/
|
||||
enum GNUNET_DB_QueryStatus
|
||||
postgres_get_extension_config (void *cls,
|
||||
postgres_get_extension_manifest (void *cls,
|
||||
const char *extension_name,
|
||||
char **config)
|
||||
char **manifest)
|
||||
{
|
||||
struct PostgresClosure *pg = cls;
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
@ -10518,15 +10725,15 @@ postgres_get_extension_config (void *cls,
|
||||
bool is_null;
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_allow_null (
|
||||
GNUNET_PQ_result_spec_string ("config",
|
||||
config),
|
||||
GNUNET_PQ_result_spec_string ("manifest",
|
||||
manifest),
|
||||
&is_null),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
*config = NULL;
|
||||
*manifest = NULL;
|
||||
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
||||
"get_extension_config",
|
||||
"get_extension_manifest",
|
||||
params,
|
||||
rs);
|
||||
}
|
||||
@ -12311,8 +12518,11 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
|
||||
plugin->get_withdraw_info = &postgres_get_withdraw_info;
|
||||
plugin->do_withdraw = &postgres_do_withdraw;
|
||||
plugin->do_batch_withdraw = &postgres_do_batch_withdraw;
|
||||
plugin->get_policy_details = &postgres_get_policy_details;
|
||||
plugin->persist_policy_details = &postgres_persist_policy_details;
|
||||
plugin->do_batch_withdraw_insert = &postgres_do_batch_withdraw_insert;
|
||||
plugin->do_deposit = &postgres_do_deposit;
|
||||
plugin->add_policy_fulfillment_proof = &postgres_add_policy_fulfillment_proof;
|
||||
plugin->do_melt = &postgres_do_melt;
|
||||
plugin->do_refund = &postgres_do_refund;
|
||||
plugin->do_recoup = &postgres_do_recoup;
|
||||
@ -12446,10 +12656,10 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
|
||||
= &postgres_release_revolving_shard;
|
||||
plugin->delete_shard_locks
|
||||
= &postgres_delete_shard_locks;
|
||||
plugin->set_extension_config
|
||||
= &postgres_set_extension_config;
|
||||
plugin->get_extension_config
|
||||
= &postgres_get_extension_config;
|
||||
plugin->set_extension_manifest
|
||||
= &postgres_set_extension_manifest;
|
||||
plugin->get_extension_manifest
|
||||
= &postgres_get_extension_manifest;
|
||||
plugin->insert_partner
|
||||
= &postgres_insert_partner;
|
||||
plugin->insert_contract
|
||||
|
@ -510,8 +510,8 @@ CREATE OR REPLACE FUNCTION exchange_do_deposit(
|
||||
IN in_coin_pub BYTEA,
|
||||
IN in_coin_sig BYTEA,
|
||||
IN in_shard INT8,
|
||||
IN in_extension_blocked BOOLEAN,
|
||||
IN in_extension_details VARCHAR,
|
||||
IN in_policy_blocked BOOLEAN,
|
||||
IN in_policy_details_serial_id INT8,
|
||||
OUT out_exchange_timestamp INT8,
|
||||
OUT out_balance_ok BOOLEAN,
|
||||
OUT out_conflict BOOLEAN)
|
||||
@ -519,26 +519,12 @@ LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
wtsi INT8; -- wire target serial id
|
||||
DECLARE
|
||||
xdi INT8; -- eXstension details serial id
|
||||
BEGIN
|
||||
-- Shards: INSERT extension_details (by extension_details_serial_id)
|
||||
-- INSERT wire_targets (by h_payto), on CONFLICT DO NOTHING;
|
||||
-- INSERT deposits (by coin_pub, shard), ON CONFLICT DO NOTHING;
|
||||
-- UPDATE known_coins (by coin_pub)
|
||||
|
||||
IF NOT NULL in_extension_details
|
||||
THEN
|
||||
INSERT INTO exchange.extension_details
|
||||
(extension_options)
|
||||
VALUES
|
||||
(in_extension_details)
|
||||
RETURNING extension_details_serial_id INTO xdi;
|
||||
ELSE
|
||||
xdi=NULL;
|
||||
END IF;
|
||||
|
||||
|
||||
INSERT INTO exchange.wire_targets
|
||||
(wire_target_h_payto
|
||||
,payto_uri)
|
||||
@ -572,8 +558,8 @@ INSERT INTO exchange.deposits
|
||||
,coin_sig
|
||||
,wire_salt
|
||||
,wire_target_h_payto
|
||||
,extension_blocked
|
||||
,extension_details_serial_id
|
||||
,policy_blocked
|
||||
,policy_details_serial_id
|
||||
)
|
||||
VALUES
|
||||
(in_shard
|
||||
@ -590,8 +576,8 @@ INSERT INTO exchange.deposits
|
||||
,in_coin_sig
|
||||
,in_wire_salt
|
||||
,in_h_payto
|
||||
,in_extension_blocked
|
||||
,xdi)
|
||||
,in_policy_blocked
|
||||
,in_policy_details_serial_id)
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
IF NOT FOUND
|
||||
@ -611,6 +597,7 @@ THEN
|
||||
AND wire_target_h_payto=in_h_payto
|
||||
AND coin_pub=in_coin_pub
|
||||
AND coin_sig=in_coin_sig;
|
||||
-- AND policy_details_serial_id=in_policy_details_serial_id; -- FIXME: is this required for idempotency?
|
||||
|
||||
IF NOT FOUND
|
||||
THEN
|
||||
@ -2420,5 +2407,117 @@ RETURN;
|
||||
|
||||
END $$;
|
||||
|
||||
CREATE OR REPLACE FUNCTION insert_or_update_policy_details(
|
||||
IN in_policy_hash_code BYTEA,
|
||||
IN in_policy_json VARCHAR,
|
||||
IN in_deadline INT8,
|
||||
IN in_commitment_val INT8,
|
||||
IN in_commitment_frac INT4,
|
||||
IN in_accumulated_total_val INT8,
|
||||
IN in_accumulated_total_frac INT4,
|
||||
IN in_fee_val INT8,
|
||||
IN in_fee_frac INT4,
|
||||
IN in_transferable_val INT8,
|
||||
IN in_transferable_frac INT4,
|
||||
IN in_fulfillment_state SMALLINT,
|
||||
OUT out_policy_details_serial_id INT8,
|
||||
OUT out_accumulated_total_val INT8,
|
||||
OUT out_accumulated_total_frac INT4,
|
||||
OUT out_fulfillment_state SMALLINT)
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
cur_commitment_val INT8;
|
||||
cur_commitment_frac INT4;
|
||||
cur_accumulated_total_val INT8;
|
||||
cur_accumulated_total_frac INT4;
|
||||
BEGIN
|
||||
-- First, try to create a new entry.
|
||||
INSERT INTO policy_details
|
||||
(policy_hash_code,
|
||||
policy_json,
|
||||
deadline,
|
||||
commitment_val,
|
||||
commitment_frac,
|
||||
accumulated_total_val,
|
||||
accumulated_total_frac,
|
||||
fee_val,
|
||||
fee_frac,
|
||||
transferable_val,
|
||||
transferable_frac,
|
||||
fulfillment_state)
|
||||
VALUES (in_policy_hash_code,
|
||||
in_policy_json,
|
||||
in_deadline,
|
||||
in_commitment_val,
|
||||
in_commitment_frac,
|
||||
in_accumulated_total_val,
|
||||
in_accumulated_total_frac,
|
||||
in_fee_val,
|
||||
in_fee_frac,
|
||||
in_transferable_val,
|
||||
in_transferable_frac,
|
||||
in_fulfillment_state)
|
||||
ON CONFLICT (policy_hash_code) DO NOTHING
|
||||
RETURNING policy_details_serial_id INTO out_policy_details_serial_id;
|
||||
|
||||
-- If the insert was successful, return
|
||||
-- We assume that the fullfilment_state was correct in first place.
|
||||
IF FOUND THEN
|
||||
out_accumulated_total_val = in_accumulated_total_val;
|
||||
out_accumulated_total_frac = in_accumulated_total_frac;
|
||||
out_fulfillment_state = in_fulfillment_state;
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
-- We had a conflict, grab the parts we need to update.
|
||||
SELECT policy_details_serial_id,
|
||||
commitment_val,
|
||||
commitment_frac,
|
||||
accumulated_total_val,
|
||||
accumulated_total_frac
|
||||
INTO out_policy_details_serial_id,
|
||||
cur_commitment_val,
|
||||
cur_commitment_frac,
|
||||
cur_accumulated_total_val,
|
||||
cur_accumulated_total_frac
|
||||
FROM policy_details
|
||||
WHERE policy_hash_code = in_policy_hash_code;
|
||||
|
||||
-- calculate the new values (overflows throws exception)
|
||||
out_accumulated_total_val = cur_accumulated_total_val + in_accumulated_total_val;
|
||||
out_accumulated_total_frac = cur_accumulated_total_frac + in_accumulated_total_frac;
|
||||
-- normalize
|
||||
out_accumulated_total_val = out_accumulated_total_val + out_accumulated_total_frac / 100000000;
|
||||
out_accumulated_total_frac = out_accumulated_total_frac % 100000000;
|
||||
|
||||
IF (out_accumulated_total_val > (1 << 52))
|
||||
THEN
|
||||
RAISE EXCEPTION 'accumulation overflow';
|
||||
END IF;
|
||||
|
||||
|
||||
-- Set the fulfillment_state according to the values.
|
||||
-- For now, we only update the state when it was INSUFFICIENT.
|
||||
-- FIXME: What to do in case of Failure or other state?
|
||||
IF (out_fullfillment_state = 1) -- INSUFFICIENT
|
||||
THEN
|
||||
IF (out_accumulated_total_val >= cur_commitment_val OR
|
||||
(out_accumulated_total_val = cur_commitment_val AND
|
||||
out_accumulated_total_frac >= cur_commitment_frac))
|
||||
THEN
|
||||
out_fulfillment_state = 2; -- READY
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
-- Now, update the record
|
||||
UPDATE exchange.policy_details
|
||||
SET
|
||||
accumulated_val = out_accumulated_total_val,
|
||||
accumulated_frac = out_accumulated_total_frac,
|
||||
fulfillment_state = out_fulfillment_state
|
||||
WHERE
|
||||
policy_details_serial_id = out_policy_details_serial_id;
|
||||
END $$;
|
||||
|
||||
COMMIT;
|
||||
|
@ -112,53 +112,53 @@ mark_prepare_cb (void *cls,
|
||||
* Simple check that config retrieval and setting for extensions work
|
||||
*/
|
||||
static enum GNUNET_GenericReturnValue
|
||||
test_extension_config (void)
|
||||
test_extension_manifest (void)
|
||||
{
|
||||
char *config;
|
||||
char *manifest;
|
||||
|
||||
FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
|
||||
plugin->get_extension_config (plugin->cls,
|
||||
plugin->get_extension_manifest (plugin->cls,
|
||||
"fnord",
|
||||
&config));
|
||||
&manifest));
|
||||
|
||||
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
|
||||
plugin->set_extension_config (plugin->cls,
|
||||
plugin->set_extension_manifest (plugin->cls,
|
||||
"fnord",
|
||||
"bar"));
|
||||
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
|
||||
plugin->get_extension_config (plugin->cls,
|
||||
plugin->get_extension_manifest (plugin->cls,
|
||||
"fnord",
|
||||
&config));
|
||||
&manifest));
|
||||
|
||||
FAILIF (0 != strcmp ("bar", config));
|
||||
GNUNET_free (config);
|
||||
FAILIF (0 != strcmp ("bar", manifest));
|
||||
GNUNET_free (manifest);
|
||||
|
||||
/* let's do this again! */
|
||||
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
|
||||
plugin->set_extension_config (plugin->cls,
|
||||
plugin->set_extension_manifest (plugin->cls,
|
||||
"fnord",
|
||||
"buzz"));
|
||||
|
||||
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
|
||||
plugin->get_extension_config (plugin->cls,
|
||||
plugin->get_extension_manifest (plugin->cls,
|
||||
"fnord",
|
||||
&config));
|
||||
&manifest));
|
||||
|
||||
FAILIF (0 != strcmp ("buzz", config));
|
||||
GNUNET_free (config);
|
||||
FAILIF (0 != strcmp ("buzz", manifest));
|
||||
GNUNET_free (manifest);
|
||||
|
||||
/* let's do this again, with NULL */
|
||||
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
|
||||
plugin->set_extension_config (plugin->cls,
|
||||
plugin->set_extension_manifest (plugin->cls,
|
||||
"fnord",
|
||||
NULL));
|
||||
|
||||
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
|
||||
plugin->get_extension_config (plugin->cls,
|
||||
plugin->get_extension_manifest (plugin->cls,
|
||||
"fnord",
|
||||
&config));
|
||||
&manifest));
|
||||
|
||||
FAILIF (NULL != config);
|
||||
FAILIF (NULL != manifest);
|
||||
|
||||
return GNUNET_OK;
|
||||
drop:
|
||||
@ -1269,7 +1269,7 @@ run (void *cls)
|
||||
NULL));
|
||||
/* simple extension check */
|
||||
FAILIF (GNUNET_OK !=
|
||||
test_extension_config ());
|
||||
test_extension_manifest ());
|
||||
|
||||
RND_BLK (&reserve_pub);
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
|
@ -11,7 +11,7 @@ if USE_COVERAGE
|
||||
endif
|
||||
|
||||
|
||||
# Libraries
|
||||
# Basic extension handling library
|
||||
|
||||
lib_LTLIBRARIES = \
|
||||
libtalerextensions.la
|
||||
@ -22,7 +22,7 @@ libtalerextensions_la_LDFLAGS = \
|
||||
|
||||
libtalerextensions_la_SOURCES = \
|
||||
extensions.c \
|
||||
extension_age_restriction.c
|
||||
age_restriction_helper.c
|
||||
|
||||
libtalerextensions_la_LIBADD = \
|
||||
$(top_builddir)/src/json/libtalerjson.la \
|
||||
@ -31,3 +31,4 @@ libtalerextensions_la_LIBADD = \
|
||||
-lgnunetutil \
|
||||
-ljansson \
|
||||
$(XLIB)
|
||||
|
||||
|
33
src/extensions/age_restriction/Makefile.am
Normal file
33
src/extensions/age_restriction/Makefile.am
Normal file
@ -0,0 +1,33 @@
|
||||
# This Makefile.am is in the public domain
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/src/include \
|
||||
$(LIBGCRYPT_CFLAGS) \
|
||||
$(POSTGRESQL_CPPFLAGS)
|
||||
|
||||
if USE_COVERAGE
|
||||
AM_CFLAGS = --coverage -O0
|
||||
XLIB = -lgcov
|
||||
endif
|
||||
|
||||
# Age restriction as extension library
|
||||
|
||||
plugindir = $(libdir)/taler
|
||||
|
||||
plugin_LTLIBRARIES = \
|
||||
libtaler_extension_age_restriction.la
|
||||
|
||||
libtaler_extension_age_restriction_la_LDFLAGS = \
|
||||
-version-info 0:0:0 \
|
||||
-no-undefined
|
||||
|
||||
libtaler_extension_age_restriction_la_SOURCES = \
|
||||
age_restriction.c
|
||||
|
||||
libtaler_extension_age_restriction_la_LIBADD = \
|
||||
$(top_builddir)/src/json/libtalerjson.la \
|
||||
$(top_builddir)/src/util/libtalerutil.la \
|
||||
-lgnunetjson \
|
||||
-lgnunetutil \
|
||||
-ljansson \
|
||||
$(XLIB)
|
258
src/extensions/age_restriction/age_restriction.c
Normal file
258
src/extensions/age_restriction/age_restriction.c
Normal file
@ -0,0 +1,258 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2021-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
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file age_restriction.c
|
||||
* @brief Utility functions regarding age restriction
|
||||
* @author Özgür Kesim
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include "taler_util.h"
|
||||
#include "taler_extensions.h"
|
||||
#include "stdint.h"
|
||||
|
||||
/* ==================================================
|
||||
*
|
||||
* Age Restriction TALER_Extension implementation
|
||||
*
|
||||
* ==================================================
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief local configuration
|
||||
*/
|
||||
|
||||
static struct TALER_AgeRestrictionConfig AR_config = {0};
|
||||
|
||||
/**
|
||||
* @brief implements the TALER_Extension.disable interface.
|
||||
*
|
||||
* @param ext Pointer to the current extension
|
||||
*/
|
||||
static void
|
||||
age_restriction_disable (
|
||||
struct TALER_Extension *ext)
|
||||
{
|
||||
if (NULL == ext)
|
||||
return;
|
||||
|
||||
ext->enabled = false;
|
||||
ext->config = NULL;
|
||||
|
||||
AR_config.mask.bits = 0;
|
||||
AR_config.num_groups = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief implements the TALER_Extension.load_config interface.
|
||||
*
|
||||
* @param ext if NULL, only tests the configuration
|
||||
* @param jconfig the configuration as json
|
||||
*/
|
||||
static enum GNUNET_GenericReturnValue
|
||||
age_restriction_load_config (
|
||||
struct TALER_Extension *ext,
|
||||
json_t *jconfig)
|
||||
{
|
||||
struct TALER_AgeMask mask = {0};
|
||||
enum GNUNET_GenericReturnValue ret;
|
||||
|
||||
ret = TALER_JSON_parse_age_groups (jconfig, &mask);
|
||||
if (GNUNET_OK != ret)
|
||||
return ret;
|
||||
|
||||
/* only testing the parser */
|
||||
if (ext == NULL)
|
||||
return GNUNET_OK;
|
||||
|
||||
if (TALER_Extension_AgeRestriction != ext->type)
|
||||
return GNUNET_SYSERR;
|
||||
|
||||
if (mask.bits > 0)
|
||||
{
|
||||
/* if the mask is not zero, the first bit MUST be set */
|
||||
if (0 == (mask.bits & 1))
|
||||
return GNUNET_SYSERR;
|
||||
|
||||
AR_config.mask.bits = mask.bits;
|
||||
AR_config.num_groups = __builtin_popcount (mask.bits) - 1;
|
||||
}
|
||||
|
||||
ext->config = &AR_config;
|
||||
ext->enabled = true;
|
||||
json_decref (jconfig);
|
||||
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
"loaded new age restriction config with age groups: %s\n",
|
||||
TALER_age_mask_to_string (&mask));
|
||||
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief implements the TALER_Extension.manifest interface.
|
||||
*
|
||||
* @param ext if NULL, only tests the configuration
|
||||
* @return configuration as json_t* object, maybe NULL
|
||||
*/
|
||||
static json_t *
|
||||
age_restriction_manifest (
|
||||
const struct TALER_Extension *ext)
|
||||
{
|
||||
char *mask_str;
|
||||
json_t *conf;
|
||||
|
||||
GNUNET_assert (NULL != ext);
|
||||
|
||||
if (NULL == ext->config)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
"age restriction not configured");
|
||||
return json_null ();
|
||||
}
|
||||
|
||||
mask_str = TALER_age_mask_to_string (&AR_config.mask);
|
||||
conf = GNUNET_JSON_PACK (
|
||||
GNUNET_JSON_pack_string ("age_groups", mask_str)
|
||||
);
|
||||
|
||||
free (mask_str);
|
||||
|
||||
return GNUNET_JSON_PACK (
|
||||
GNUNET_JSON_pack_bool ("critical", ext->critical),
|
||||
GNUNET_JSON_pack_string ("version", ext->version),
|
||||
GNUNET_JSON_pack_object_steal ("config", conf)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/* The extension for age restriction */
|
||||
struct TALER_Extension TE_age_restriction = {
|
||||
.type = TALER_Extension_AgeRestriction,
|
||||
.name = "age_restriction",
|
||||
.critical = false,
|
||||
.version = "1",
|
||||
.enabled = false, /* disabled per default */
|
||||
.config = NULL,
|
||||
.disable = &age_restriction_disable,
|
||||
.load_config = &age_restriction_load_config,
|
||||
.manifest = &age_restriction_manifest,
|
||||
|
||||
/* This extension is not a policy extension */
|
||||
.create_policy_details = NULL,
|
||||
.policy_get_handler = NULL,
|
||||
.policy_post_handler = NULL,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief implements the init() function for GNUNET_PLUGIN_load
|
||||
*
|
||||
* @param arg Pointer to the GNUNET_CONFIGURATION_Handle
|
||||
* @return pointer to TALER_Extension on success or NULL otherwise.
|
||||
*/
|
||||
void *
|
||||
libtaler_extension_age_restriction_init (void *arg)
|
||||
{
|
||||
const struct GNUNET_CONFIGURATION_Handle *cfg = arg;
|
||||
char *groups = NULL;
|
||||
struct TALER_AgeMask mask = {0};
|
||||
|
||||
if ((GNUNET_YES !=
|
||||
GNUNET_CONFIGURATION_have_value (cfg,
|
||||
TALER_EXTENSION_SECTION_AGE_RESTRICTION,
|
||||
"ENABLED"))
|
||||
||
|
||||
(GNUNET_YES !=
|
||||
GNUNET_CONFIGURATION_get_value_yesno (cfg,
|
||||
TALER_EXTENSION_SECTION_AGE_RESTRICTION,
|
||||
"ENABLED")))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"[age restriction] no section %s found in configuration\n",
|
||||
TALER_EXTENSION_SECTION_AGE_RESTRICTION);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Age restriction is enabled, extract age groups */
|
||||
if ((GNUNET_YES ==
|
||||
GNUNET_CONFIGURATION_have_value (cfg,
|
||||
TALER_EXTENSION_SECTION_AGE_RESTRICTION,
|
||||
"AGE_GROUPS"))
|
||||
&&
|
||||
(GNUNET_YES !=
|
||||
GNUNET_CONFIGURATION_get_value_string (cfg,
|
||||
TALER_EXTENSION_SECTION_AGE_RESTRICTION,
|
||||
"AGE_GROUPS",
|
||||
&groups)))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"[age restriction] AGE_GROUPS in %s is not a string\n",
|
||||
TALER_EXTENSION_SECTION_AGE_RESTRICTION);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mask.bits = TALER_EXTENSION_AGE_RESTRICTION_DEFAULT_AGE_MASK;
|
||||
|
||||
if ((groups != NULL) &&
|
||||
(GNUNET_OK != TALER_parse_age_group_string (groups, &mask)))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"[age restriction] couldn't parse age groups: '%s'\n",
|
||||
groups);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AR_config.mask = mask;
|
||||
AR_config.num_groups = __builtin_popcount (mask.bits) - 1; /* no underflow, first bit always set */
|
||||
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"[age restriction] setting age mask to %s with #groups: %d\n",
|
||||
TALER_age_mask_to_string (&AR_config.mask),
|
||||
__builtin_popcount (AR_config.mask.bits) - 1);
|
||||
|
||||
TE_age_restriction.config = &AR_config;
|
||||
|
||||
/* Note: we do now have TE_age_restriction_config set, however the extension
|
||||
* is not yet enabled! For age restriction to become active, load_config must
|
||||
* have been called. */
|
||||
|
||||
GNUNET_free (groups);
|
||||
return &TE_age_restriction;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief implements the done() function for GNUNET_PLUGIN_load
|
||||
*
|
||||
* @param cfg unsued
|
||||
* @return pointer to TALER_Extension on success or NULL otherwise.
|
||||
*/
|
||||
void *
|
||||
libtaler_extension_age_restriction_done (void *arg)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"[age restriction] disabling and unloading");
|
||||
AR_config.mask.bits = 0;
|
||||
AR_config.num_groups = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* end of age_restriction.c */
|
73
src/extensions/age_restriction_helper.c
Normal file
73
src/extensions/age_restriction_helper.c
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
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
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file age_restriction_helper.c
|
||||
* @brief Helper functions for age restriction
|
||||
* @author Özgür Kesim
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#include "taler_util.h"
|
||||
#include "taler_signatures.h"
|
||||
#include "taler_extensions.h"
|
||||
#include "stdint.h"
|
||||
|
||||
|
||||
const struct TALER_AgeRestrictionConfig *
|
||||
TALER_extensions_get_age_restriction_config ()
|
||||
{
|
||||
const struct TALER_Extension *ext;
|
||||
|
||||
ext = TALER_extensions_get_by_type (TALER_Extension_AgeRestriction);
|
||||
if (NULL == ext)
|
||||
return NULL;
|
||||
|
||||
return ext->config;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TALER_extensions_is_age_restriction_enabled ()
|
||||
{
|
||||
const struct TALER_Extension *ext;
|
||||
|
||||
ext = TALER_extensions_get_by_type (TALER_Extension_AgeRestriction);
|
||||
if (NULL == ext)
|
||||
return false;
|
||||
|
||||
return ext->enabled;
|
||||
}
|
||||
|
||||
|
||||
struct TALER_AgeMask
|
||||
TALER_extensions_get_age_restriction_mask ()
|
||||
{
|
||||
const struct TALER_Extension *ext;
|
||||
const struct TALER_AgeRestrictionConfig *conf;
|
||||
|
||||
ext = TALER_extensions_get_by_type (TALER_Extension_AgeRestriction);
|
||||
|
||||
if ((NULL == ext) ||
|
||||
(NULL == ext->config))
|
||||
return (struct TALER_AgeMask) {0}
|
||||
;
|
||||
|
||||
conf = ext->config;
|
||||
return conf->mask;
|
||||
}
|
||||
|
||||
|
||||
/* end age_restriction_helper.c */
|
@ -1,409 +0,0 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2021-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
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file extension_age_restriction.c
|
||||
* @brief Utility functions regarding age restriction
|
||||
* @author Özgür Kesim
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include "taler_util.h"
|
||||
#include "taler_extensions.h"
|
||||
#include "stdint.h"
|
||||
|
||||
/**
|
||||
* Carries all the information we need for age restriction
|
||||
*/
|
||||
struct age_restriction_config
|
||||
{
|
||||
struct TALER_AgeMask mask;
|
||||
size_t num_groups;
|
||||
};
|
||||
|
||||
/**
|
||||
* Global config for this extension
|
||||
*/
|
||||
static struct age_restriction_config TE_age_restriction_config = {0};
|
||||
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_parse_age_group_string (
|
||||
const char *groups,
|
||||
struct TALER_AgeMask *mask)
|
||||
{
|
||||
|
||||
const char *pos = groups;
|
||||
unsigned int prev = 0;
|
||||
unsigned int val = 0;
|
||||
char c;
|
||||
|
||||
while (*pos)
|
||||
{
|
||||
c = *pos++;
|
||||
if (':' == c)
|
||||
{
|
||||
if (prev >= val)
|
||||
return GNUNET_SYSERR;
|
||||
|
||||
mask->bits |= 1 << val;
|
||||
prev = val;
|
||||
val = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ('0'>c || '9'<c)
|
||||
return GNUNET_SYSERR;
|
||||
|
||||
val = 10 * val + c - '0';
|
||||
|
||||
if (0>=val || 32<=val)
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
if (32<=val || prev>=val)
|
||||
return GNUNET_SYSERR;
|
||||
|
||||
mask->bits |= (1 << val);
|
||||
mask->bits |= 1; // mark zeroth group, too
|
||||
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
TALER_age_mask_to_string (
|
||||
const struct TALER_AgeMask *mask)
|
||||
{
|
||||
uint32_t bits = mask->bits;
|
||||
unsigned int n = 0;
|
||||
char *buf = GNUNET_malloc (32 * 3); // max characters possible
|
||||
char *pos = buf;
|
||||
|
||||
if (NULL == buf)
|
||||
{
|
||||
return buf;
|
||||
}
|
||||
|
||||
while (bits != 0)
|
||||
{
|
||||
bits >>= 1;
|
||||
n++;
|
||||
if (0 == (bits & 1))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (n > 9)
|
||||
{
|
||||
*(pos++) = '0' + n / 10;
|
||||
}
|
||||
*(pos++) = '0' + n % 10;
|
||||
|
||||
if (0 != (bits >> 1))
|
||||
{
|
||||
*(pos++) = ':';
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
/* ==================================================
|
||||
*
|
||||
* Age Restriction TALER_Extension implementation
|
||||
*
|
||||
* ==================================================
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief implements the TALER_Extension.disable interface.
|
||||
*
|
||||
* @param ext Pointer to the current extension
|
||||
*/
|
||||
static void
|
||||
age_restriction_disable (
|
||||
struct TALER_Extension *ext)
|
||||
{
|
||||
if (NULL == ext)
|
||||
return;
|
||||
|
||||
ext->config = NULL;
|
||||
|
||||
if (NULL != ext->config_json)
|
||||
{
|
||||
json_decref (ext->config_json);
|
||||
ext->config_json = NULL;
|
||||
}
|
||||
|
||||
TE_age_restriction_config.mask.bits = 0;
|
||||
TE_age_restriction_config.num_groups = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief implements the TALER_Extension.load_taler_config interface.
|
||||
*
|
||||
* @param ext Pointer to the current extension
|
||||
* @param cfg Handle to the GNUNET configuration
|
||||
* @return Error if extension for age restriction was set, but age groups were
|
||||
* invalid, OK otherwise.
|
||||
*/
|
||||
static enum GNUNET_GenericReturnValue
|
||||
age_restriction_load_taler_config (
|
||||
struct TALER_Extension *ext,
|
||||
const struct GNUNET_CONFIGURATION_Handle *cfg)
|
||||
{
|
||||
char *groups = NULL;
|
||||
enum GNUNET_GenericReturnValue ret = GNUNET_SYSERR;
|
||||
struct TALER_AgeMask mask = {0};
|
||||
|
||||
if ((GNUNET_YES !=
|
||||
GNUNET_CONFIGURATION_have_value (cfg,
|
||||
TALER_EXTENSION_SECTION_AGE_RESTRICTION,
|
||||
"ENABLED"))
|
||||
||
|
||||
(GNUNET_YES !=
|
||||
GNUNET_CONFIGURATION_get_value_yesno (cfg,
|
||||
TALER_EXTENSION_SECTION_AGE_RESTRICTION,
|
||||
"ENABLED")))
|
||||
{
|
||||
/* Age restriction is not enabled */
|
||||
ext->config = NULL;
|
||||
ext->config_json = NULL;
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
/* Age restriction is enabled, extract age groups */
|
||||
if ((GNUNET_YES ==
|
||||
GNUNET_CONFIGURATION_have_value (cfg,
|
||||
TALER_EXTENSION_SECTION_AGE_RESTRICTION,
|
||||
"AGE_GROUPS"))
|
||||
&&
|
||||
(GNUNET_YES !=
|
||||
GNUNET_CONFIGURATION_get_value_string (cfg,
|
||||
TALER_EXTENSION_SECTION_AGE_RESTRICTION,
|
||||
"AGE_GROUPS",
|
||||
&groups)))
|
||||
return GNUNET_SYSERR;
|
||||
|
||||
|
||||
mask.bits = TALER_EXTENSION_AGE_RESTRICTION_DEFAULT_AGE_MASK;
|
||||
ret = GNUNET_OK;
|
||||
|
||||
if (groups != NULL)
|
||||
{
|
||||
ret = TALER_parse_age_group_string (groups, &mask);
|
||||
if (GNUNET_OK != ret)
|
||||
mask.bits = TALER_EXTENSION_AGE_RESTRICTION_DEFAULT_AGE_MASK;
|
||||
}
|
||||
|
||||
if (GNUNET_OK == ret)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"setting age mask to %x with #groups: %d\n", mask.bits,
|
||||
__builtin_popcount (mask.bits) - 1);
|
||||
TE_age_restriction_config.mask.bits = mask.bits;
|
||||
TE_age_restriction_config.num_groups = __builtin_popcount (mask.bits) - 1; /* no underflow, first bit always set */
|
||||
ext->config = &TE_age_restriction_config;
|
||||
|
||||
/* Note: we do now have TE_age_restriction_config set, however
|
||||
* ext->config_json is NOT set, i.e. the extension is not yet active! For
|
||||
* age restriction to become active, load_json_config must have been
|
||||
* called. */
|
||||
}
|
||||
|
||||
|
||||
GNUNET_free (groups);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief implements the TALER_Extension.load_json_config interface.
|
||||
*
|
||||
* @param ext if NULL, only tests the configuration
|
||||
* @param jconfig the configuration as json
|
||||
*/
|
||||
static enum GNUNET_GenericReturnValue
|
||||
age_restriction_load_json_config (
|
||||
struct TALER_Extension *ext,
|
||||
json_t *jconfig)
|
||||
{
|
||||
struct TALER_AgeMask mask = {0};
|
||||
enum GNUNET_GenericReturnValue ret;
|
||||
|
||||
ret = TALER_JSON_parse_age_groups (jconfig, &mask);
|
||||
if (GNUNET_OK != ret)
|
||||
return ret;
|
||||
|
||||
/* only testing the parser */
|
||||
if (ext == NULL)
|
||||
return GNUNET_OK;
|
||||
|
||||
if (TALER_Extension_AgeRestriction != ext->type)
|
||||
return GNUNET_SYSERR;
|
||||
|
||||
TE_age_restriction_config.mask.bits = mask.bits;
|
||||
TE_age_restriction_config.num_groups = 0;
|
||||
|
||||
if (mask.bits > 0)
|
||||
{
|
||||
/* if the mask is not zero, the first bit MUST be set */
|
||||
if (0 == (mask.bits & 1))
|
||||
return GNUNET_SYSERR;
|
||||
|
||||
TE_age_restriction_config.num_groups = __builtin_popcount (mask.bits) - 1;
|
||||
}
|
||||
|
||||
ext->config = &TE_age_restriction_config;
|
||||
|
||||
if (NULL != ext->config_json)
|
||||
json_decref (ext->config_json);
|
||||
|
||||
ext->config_json = jconfig;
|
||||
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
"loaded new age restriction config with age groups: %s\n",
|
||||
TALER_age_mask_to_string (&mask));
|
||||
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief implements the TALER_Extension.config_to_json interface.
|
||||
*
|
||||
* @param ext if NULL, only tests the configuration
|
||||
* @return configuration as json_t* object, maybe NULL
|
||||
*/
|
||||
static json_t *
|
||||
age_restriction_config_to_json (
|
||||
const struct TALER_Extension *ext)
|
||||
{
|
||||
char *mask_str;
|
||||
json_t *conf;
|
||||
|
||||
GNUNET_assert (NULL != ext);
|
||||
|
||||
if (NULL == ext->config)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
"age restriction not configured");
|
||||
return json_null ();
|
||||
}
|
||||
|
||||
if (NULL != ext->config_json)
|
||||
{
|
||||
return json_copy (ext->config_json);
|
||||
}
|
||||
|
||||
mask_str = TALER_age_mask_to_string (&TE_age_restriction_config.mask);
|
||||
conf = GNUNET_JSON_PACK (
|
||||
GNUNET_JSON_pack_string ("age_groups", mask_str)
|
||||
);
|
||||
|
||||
return GNUNET_JSON_PACK (
|
||||
GNUNET_JSON_pack_bool ("critical", ext->critical),
|
||||
GNUNET_JSON_pack_string ("version", ext->version),
|
||||
GNUNET_JSON_pack_object_steal ("config", conf)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief implements the TALER_Extension.test_json_config interface.
|
||||
*
|
||||
* @param config configuration as json_t* to test
|
||||
* @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise.
|
||||
*/
|
||||
static enum GNUNET_GenericReturnValue
|
||||
age_restriction_test_json_config (
|
||||
const json_t *config)
|
||||
{
|
||||
struct TALER_AgeMask mask = {0};
|
||||
|
||||
return TALER_JSON_parse_age_groups (config, &mask);
|
||||
}
|
||||
|
||||
|
||||
/* The extension for age restriction */
|
||||
struct TALER_Extension TE_age_restriction = {
|
||||
.next = NULL,
|
||||
.type = TALER_Extension_AgeRestriction,
|
||||
.name = "age_restriction",
|
||||
.critical = false,
|
||||
.version = "1",
|
||||
.config = NULL, // disabled per default
|
||||
.config_json = NULL,
|
||||
.disable = &age_restriction_disable,
|
||||
.test_json_config = &age_restriction_test_json_config,
|
||||
.load_json_config = &age_restriction_load_json_config,
|
||||
.config_to_json = &age_restriction_config_to_json,
|
||||
.load_taler_config = &age_restriction_load_taler_config,
|
||||
};
|
||||
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_extension_age_restriction_register ()
|
||||
{
|
||||
return TALER_extensions_add (&TE_age_restriction);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TALER_extensions_age_restriction_is_configured ()
|
||||
{
|
||||
return (0 != TE_age_restriction_config.mask.bits);
|
||||
}
|
||||
|
||||
|
||||
struct TALER_AgeMask
|
||||
TALER_extensions_age_restriction_ageMask ()
|
||||
{
|
||||
return TE_age_restriction_config.mask;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
TALER_extensions_age_restriction_num_groups ()
|
||||
{
|
||||
return TE_age_restriction_config.num_groups;
|
||||
}
|
||||
|
||||
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_JSON_parse_age_groups (const json_t *root,
|
||||
struct TALER_AgeMask *mask)
|
||||
{
|
||||
enum GNUNET_GenericReturnValue ret;
|
||||
const char *str;
|
||||
struct GNUNET_JSON_Specification spec[] = {
|
||||
GNUNET_JSON_spec_string ("age_groups",
|
||||
&str),
|
||||
GNUNET_JSON_spec_end ()
|
||||
};
|
||||
|
||||
ret = GNUNET_JSON_parse (root,
|
||||
spec,
|
||||
NULL,
|
||||
NULL);
|
||||
if (GNUNET_OK == ret)
|
||||
TALER_parse_age_group_string (str, mask);
|
||||
|
||||
GNUNET_JSON_parse_free (spec);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* end of extension_age_restriction.c */
|
@ -24,51 +24,53 @@
|
||||
#include "taler_extensions.h"
|
||||
#include "stdint.h"
|
||||
|
||||
|
||||
/* head of the list of all registered extensions */
|
||||
static struct TALER_Extension *TE_extensions = NULL;
|
||||
static struct TALER_Extensions TE_extensions = {
|
||||
.next = NULL,
|
||||
.extension = NULL,
|
||||
};
|
||||
|
||||
|
||||
const struct TALER_Extension *
|
||||
const struct TALER_Extensions *
|
||||
TALER_extensions_get_head ()
|
||||
{
|
||||
return TE_extensions;
|
||||
return &TE_extensions;
|
||||
}
|
||||
|
||||
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_extensions_add (
|
||||
struct TALER_Extension *extension)
|
||||
static enum GNUNET_GenericReturnValue
|
||||
add_extension (
|
||||
const struct TALER_Extension *extension)
|
||||
{
|
||||
/* Sanity checks */
|
||||
if ((NULL == extension) ||
|
||||
(NULL == extension->name) ||
|
||||
(NULL == extension->version) ||
|
||||
(NULL == extension->disable) ||
|
||||
(NULL == extension->test_json_config) ||
|
||||
(NULL == extension->load_json_config) ||
|
||||
(NULL == extension->config_to_json) ||
|
||||
(NULL == extension->load_taler_config))
|
||||
(NULL == extension->load_config) ||
|
||||
(NULL == extension->manifest))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"invalid extension\n");
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
if (NULL == TE_extensions) /* first extension ?*/
|
||||
TE_extensions = (struct TALER_Extension *) extension;
|
||||
if (NULL == TE_extensions.extension) /* first extension ?*/
|
||||
TE_extensions.extension = extension;
|
||||
else
|
||||
{
|
||||
struct TALER_Extension *iter;
|
||||
struct TALER_Extension *last;
|
||||
struct TALER_Extensions *iter;
|
||||
struct TALER_Extensions *last;
|
||||
|
||||
/* Check for collisions */
|
||||
for (iter = TE_extensions; NULL != iter; iter = iter->next)
|
||||
for (iter = &TE_extensions;
|
||||
NULL != iter && NULL != iter->extension;
|
||||
iter = iter->next)
|
||||
{
|
||||
const struct TALER_Extension *ext = iter->extension;
|
||||
last = iter;
|
||||
if (extension->type == iter->type ||
|
||||
if (extension->type == ext->type ||
|
||||
0 == strcasecmp (extension->name,
|
||||
iter->name))
|
||||
ext->name))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"extension collision for `%s'\n",
|
||||
@ -78,7 +80,11 @@ TALER_extensions_add (
|
||||
}
|
||||
|
||||
/* No collisions found, so add this extension to the list */
|
||||
last->next = extension;
|
||||
{
|
||||
struct TALER_Extensions *extn = GNUNET_new (struct TALER_Extensions);
|
||||
extn->extension = extension;
|
||||
last->next = extn;
|
||||
}
|
||||
}
|
||||
|
||||
return GNUNET_OK;
|
||||
@ -89,12 +95,12 @@ const struct TALER_Extension *
|
||||
TALER_extensions_get_by_type (
|
||||
enum TALER_Extension_Type type)
|
||||
{
|
||||
for (const struct TALER_Extension *it = TE_extensions;
|
||||
NULL != it;
|
||||
for (const struct TALER_Extensions *it = &TE_extensions;
|
||||
NULL != it && NULL != it->extension;
|
||||
it = it->next)
|
||||
{
|
||||
if (it->type == type)
|
||||
return it;
|
||||
if (it->extension->type == type)
|
||||
return it->extension;
|
||||
}
|
||||
|
||||
/* No extension found. */
|
||||
@ -109,8 +115,7 @@ TALER_extensions_is_enabled_type (
|
||||
const struct TALER_Extension *ext =
|
||||
TALER_extensions_get_by_type (type);
|
||||
|
||||
return (NULL != ext &&
|
||||
TALER_extensions_is_enabled (ext));
|
||||
return (NULL != ext && ext->enabled);
|
||||
}
|
||||
|
||||
|
||||
@ -118,33 +123,34 @@ const struct TALER_Extension *
|
||||
TALER_extensions_get_by_name (
|
||||
const char *name)
|
||||
{
|
||||
for (const struct TALER_Extension *it = TE_extensions;
|
||||
for (const struct TALER_Extensions *it = &TE_extensions;
|
||||
NULL != it;
|
||||
it = it->next)
|
||||
{
|
||||
if (0 == strcasecmp (name, it->name))
|
||||
return it;
|
||||
if (0 == strcasecmp (name, it->extension->name))
|
||||
return it->extension;
|
||||
}
|
||||
/* No extension found. */
|
||||
/* No extension found, try to load it. */
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_extensions_verify_json_config_signature (
|
||||
json_t *extensions,
|
||||
TALER_extensions_verify_manifests_signature (
|
||||
json_t *manifests,
|
||||
struct TALER_MasterSignatureP *extensions_sig,
|
||||
struct TALER_MasterPublicKeyP *master_pub)
|
||||
{
|
||||
struct TALER_ExtensionConfigHashP h_config;
|
||||
struct TALER_ExtensionManifestsHashP h_manifests;
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TALER_JSON_extensions_config_hash (extensions,
|
||||
&h_config))
|
||||
TALER_JSON_extensions_manifests_hash (manifests,
|
||||
&h_manifests))
|
||||
return GNUNET_SYSERR;
|
||||
if (GNUNET_OK !=
|
||||
TALER_exchange_offline_extension_config_hash_verify (
|
||||
&h_config,
|
||||
TALER_exchange_offline_extension_manifests_hash_verify (
|
||||
&h_manifests,
|
||||
master_pub,
|
||||
extensions_sig))
|
||||
return GNUNET_NO;
|
||||
@ -178,7 +184,8 @@ configure_extension (
|
||||
{
|
||||
struct LoadConfClosure *col = cls;
|
||||
const char *name;
|
||||
const struct TALER_Extension *extension;
|
||||
char *lib_name;
|
||||
struct TALER_Extension *extension;
|
||||
|
||||
if (GNUNET_OK != col->error)
|
||||
return;
|
||||
@ -190,33 +197,49 @@ configure_extension (
|
||||
|
||||
name = section + sizeof(TALER_EXTENSION_SECTION_PREFIX) - 1;
|
||||
|
||||
if (NULL ==
|
||||
(extension = TALER_extensions_get_by_name (name)))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Unsupported extension `%s` (section [%s]).\n", name,
|
||||
section);
|
||||
col->error = GNUNET_SYSERR;
|
||||
return;
|
||||
}
|
||||
|
||||
if (GNUNET_OK !=
|
||||
extension->load_taler_config (
|
||||
(struct TALER_Extension *) extension,
|
||||
col->cfg))
|
||||
/* Load the extension library */
|
||||
GNUNET_asprintf (&lib_name,
|
||||
"libtaler_extension_%s",
|
||||
name);
|
||||
extension = GNUNET_PLUGIN_load (
|
||||
lib_name,
|
||||
(void *) col->cfg);
|
||||
if (NULL == extension)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Couldn't parse configuration for extension `%s` (section [%s]).\n",
|
||||
"Couldn't load extension library to `%s` (section [%s]).\n",
|
||||
name,
|
||||
section);
|
||||
col->error = GNUNET_SYSERR;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (GNUNET_OK != add_extension (extension))
|
||||
{
|
||||
/* TODO: Ignoring return values here */
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Couldn't add extension `%s` (section [%s]).\n",
|
||||
name,
|
||||
section);
|
||||
col->error = GNUNET_SYSERR;
|
||||
GNUNET_PLUGIN_unload (
|
||||
lib_name,
|
||||
(void *) col->cfg);
|
||||
return;
|
||||
}
|
||||
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"extension library '%s' loaded\n",
|
||||
lib_name);
|
||||
}
|
||||
|
||||
|
||||
static bool extensions_loaded = false;
|
||||
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_extensions_load_taler_config (
|
||||
TALER_extensions_init (
|
||||
const struct GNUNET_CONFIGURATION_Handle *cfg)
|
||||
{
|
||||
struct LoadConfClosure col = {
|
||||
@ -224,15 +247,22 @@ TALER_extensions_load_taler_config (
|
||||
.error = GNUNET_OK,
|
||||
};
|
||||
|
||||
if (extensions_loaded)
|
||||
return GNUNET_OK;
|
||||
|
||||
GNUNET_CONFIGURATION_iterate_sections (cfg,
|
||||
&configure_extension,
|
||||
&col);
|
||||
|
||||
if (GNUNET_OK == col.error)
|
||||
extensions_loaded = true;
|
||||
|
||||
return col.error;
|
||||
}
|
||||
|
||||
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_extensions_is_json_config (
|
||||
TALER_extensions_parse_manifest (
|
||||
json_t *obj,
|
||||
int *critical,
|
||||
const char **version,
|
||||
@ -265,21 +295,22 @@ TALER_extensions_is_json_config (
|
||||
|
||||
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_extensions_load_json_config (
|
||||
TALER_extensions_load_manifests (
|
||||
json_t *extensions)
|
||||
{
|
||||
const char*name;
|
||||
json_t *blob;
|
||||
json_t *manifest;
|
||||
|
||||
GNUNET_assert (NULL != extensions);
|
||||
GNUNET_assert (json_is_object (extensions));
|
||||
|
||||
json_object_foreach (extensions, name, blob)
|
||||
json_object_foreach (extensions, name, manifest)
|
||||
{
|
||||
int critical;
|
||||
const char *version;
|
||||
json_t *config;
|
||||
const struct TALER_Extension *extension =
|
||||
struct TALER_Extension *extension = (struct
|
||||
TALER_Extension *)
|
||||
TALER_extensions_get_by_name (name);
|
||||
|
||||
if (NULL == extension)
|
||||
@ -291,45 +322,109 @@ TALER_extensions_load_json_config (
|
||||
|
||||
/* load and verify criticality, version, etc. */
|
||||
if (GNUNET_OK !=
|
||||
TALER_extensions_is_json_config (
|
||||
blob, &critical, &version, &config))
|
||||
TALER_extensions_parse_manifest (
|
||||
manifest, &critical, &version, &config))
|
||||
return GNUNET_SYSERR;
|
||||
|
||||
if (critical != extension->critical
|
||||
|| 0 != strcmp (version, extension->version) // TODO: libtool compare?
|
||||
|| NULL == config
|
||||
|| GNUNET_OK != extension->test_json_config (config))
|
||||
|| GNUNET_OK != extension->load_config (NULL, config))
|
||||
return GNUNET_SYSERR;
|
||||
|
||||
/* This _should_ work now */
|
||||
if (GNUNET_OK !=
|
||||
extension->load_json_config ((struct TALER_Extension *) extension,
|
||||
config))
|
||||
extension->load_config (extension, config))
|
||||
return GNUNET_SYSERR;
|
||||
|
||||
extension->enabled = true;
|
||||
}
|
||||
|
||||
/* make sure to disable all extensions that weren't mentioned in the json */
|
||||
for (const struct TALER_Extension *it = TALER_extensions_get_head ();
|
||||
for (const struct TALER_Extensions *it = TALER_extensions_get_head ();
|
||||
NULL != it;
|
||||
it = it->next)
|
||||
{
|
||||
if (NULL == json_object_get (extensions, it->name))
|
||||
it->disable ((struct TALER_Extension *) it);
|
||||
if (NULL == json_object_get (extensions, it->extension->name))
|
||||
it->extension->disable ((struct TALER_Extension *) it);
|
||||
}
|
||||
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TALER_extensions_age_restriction_is_enabled ()
|
||||
{
|
||||
const struct TALER_Extension *age =
|
||||
TALER_extensions_get_by_type (TALER_Extension_AgeRestriction);
|
||||
/*
|
||||
* Policy related
|
||||
*/
|
||||
|
||||
static char *fulfillment2str[] = {
|
||||
[TALER_PolicyFulfillmentReady] = "Ready",
|
||||
[TALER_PolicyFulfillmentSuccess] = "Success",
|
||||
[TALER_PolicyFulfillmentFailure] = "Failure",
|
||||
[TALER_PolicyFulfillmentTimeout] = "Timeout",
|
||||
[TALER_PolicyFulfillmentInsufficient] = "Insufficient",
|
||||
};
|
||||
|
||||
const char *
|
||||
TALER_policy_fulfillment_state_str (
|
||||
enum TALER_PolicyFulfillmentState state)
|
||||
{
|
||||
GNUNET_assert (TALER_PolicyFulfillmentStateCount > state);
|
||||
return fulfillment2str[state];
|
||||
}
|
||||
|
||||
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_extensions_create_policy_details (
|
||||
const json_t *policy_options,
|
||||
struct TALER_PolicyDetails *details,
|
||||
const char **error_hint)
|
||||
{
|
||||
enum GNUNET_GenericReturnValue ret;
|
||||
const struct TALER_Extension *extension;
|
||||
const json_t *jtype;
|
||||
const char *type;
|
||||
|
||||
*error_hint = NULL;
|
||||
|
||||
if ((NULL == policy_options) ||
|
||||
(! json_is_object (policy_options)))
|
||||
{
|
||||
*error_hint = "invalid policy object";
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
jtype = json_object_get (policy_options, "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->create_policy_details))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
"Unsupported extension policy '%s' requested\n",
|
||||
type);
|
||||
return GNUNET_NO;
|
||||
}
|
||||
|
||||
details->deadline = GNUNET_TIME_UNIT_FOREVER_TS;
|
||||
ret = extension->create_policy_details (policy_options,
|
||||
details,
|
||||
error_hint);
|
||||
return ret;
|
||||
|
||||
return (NULL != age &&
|
||||
NULL != age->config_json &&
|
||||
TALER_extensions_age_restriction_is_configured ());
|
||||
}
|
||||
|
||||
|
||||
|
@ -233,7 +233,7 @@ typedef void
|
||||
*
|
||||
* @param auditor the auditor handle; the auditor must be ready to operate
|
||||
* @param h_wire hash of merchant wire details
|
||||
* @param h_extensions hash over the extensions, if any
|
||||
* @param h_policy hash over the policy, if any
|
||||
* @param h_contract_terms hash of the contact of the merchant with the customer (further details are never disclosed to the auditor)
|
||||
* @param exchange_timestamp timestamp when the contract was finalized, must not be too far in the future
|
||||
* @param wire_deadline date until which the exchange should wire the funds
|
||||
@ -257,7 +257,7 @@ struct TALER_AUDITOR_DepositConfirmationHandle *
|
||||
TALER_AUDITOR_deposit_confirmation (
|
||||
struct TALER_AUDITOR_Handle *auditor,
|
||||
const struct TALER_MerchantWireHashP *h_wire,
|
||||
const struct TALER_ExtensionContractHashP *h_extensions,
|
||||
const struct TALER_ExtensionPolicyHashP *h_policy,
|
||||
const struct TALER_PrivateContractHashP *h_contract_terms,
|
||||
struct GNUNET_TIME_Timestamp exchange_timestamp,
|
||||
struct GNUNET_TIME_Timestamp wire_deadline,
|
||||
|
@ -382,9 +382,9 @@ struct TALER_AUDITORDB_DepositConfirmation
|
||||
struct TALER_PrivateContractHashP h_contract_terms;
|
||||
|
||||
/**
|
||||
* Hash over the extensions for the deposit.
|
||||
* Hash over the policy extension for the deposit.
|
||||
*/
|
||||
struct TALER_ExtensionContractHashP h_extensions;
|
||||
struct TALER_ExtensionPolicyHashP h_policy;
|
||||
|
||||
/**
|
||||
* Hash over the wiring information of the merchant.
|
||||
|
@ -638,10 +638,9 @@ struct TALER_PrivateContractHashP
|
||||
|
||||
|
||||
/**
|
||||
* Hash used to represent the "public" extensions to
|
||||
* a contract that is shared with the exchange.
|
||||
* Hash used to represent the policy extension to a deposit
|
||||
*/
|
||||
struct TALER_ExtensionContractHashP
|
||||
struct TALER_ExtensionPolicyHashP
|
||||
{
|
||||
/**
|
||||
* Actual hash value.
|
||||
@ -727,10 +726,10 @@ struct TALER_PickupIdentifierP
|
||||
|
||||
|
||||
/**
|
||||
* @brief Salted hash over the JSON object representing the configuration of an
|
||||
* extension.
|
||||
* @brief Salted hash over the JSON object representing the manifests of
|
||||
* extensions.
|
||||
*/
|
||||
struct TALER_ExtensionConfigHashP
|
||||
struct TALER_ExtensionManifestsHashP
|
||||
{
|
||||
/**
|
||||
* Actual hash value.
|
||||
@ -3213,7 +3212,7 @@ TALER_wallet_reserve_attest_request_verify (
|
||||
* @param h_wire hash of the merchant’s account details
|
||||
* @param h_contract_terms hash of the contact of the merchant with the customer (further details are never disclosed to the exchange)
|
||||
* @param h_age_commitment hash over the age commitment, if applicable to the denomination (maybe NULL)
|
||||
* @param h_extensions hash over the extensions
|
||||
* @param h_policy hash over the policy extension
|
||||
* @param h_denom_pub hash of the coin denomination's public key
|
||||
* @param coin_priv coin’s private key
|
||||
* @param wallet_timestamp timestamp when the contract was finalized, must not be too far in the future
|
||||
@ -3228,7 +3227,7 @@ TALER_wallet_deposit_sign (
|
||||
const struct TALER_MerchantWireHashP *h_wire,
|
||||
const struct TALER_PrivateContractHashP *h_contract_terms,
|
||||
const struct TALER_AgeCommitmentHash *h_age_commitment,
|
||||
const struct TALER_ExtensionContractHashP *h_extensions,
|
||||
const struct TALER_ExtensionPolicyHashP *h_policy,
|
||||
const struct TALER_DenominationHashP *h_denom_pub,
|
||||
struct GNUNET_TIME_Timestamp wallet_timestamp,
|
||||
const struct TALER_MerchantPublicKeyP *merchant_pub,
|
||||
@ -3245,7 +3244,7 @@ TALER_wallet_deposit_sign (
|
||||
* @param h_wire hash of the merchant’s account details
|
||||
* @param h_contract_terms hash of the contact of the merchant with the customer (further details are never disclosed to the exchange)
|
||||
* @param h_age_commitment hash over the age commitment (maybe all zeroes, if not applicable to the denomination)
|
||||
* @param h_extensions hash over the extensions
|
||||
* @param h_policy hash over the policy extension
|
||||
* @param h_denom_pub hash of the coin denomination's public key
|
||||
* @param wallet_timestamp timestamp when the contract was finalized, must not be too far in the future
|
||||
* @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests)
|
||||
@ -3261,7 +3260,7 @@ TALER_wallet_deposit_verify (
|
||||
const struct TALER_MerchantWireHashP *h_wire,
|
||||
const struct TALER_PrivateContractHashP *h_contract_terms,
|
||||
const struct TALER_AgeCommitmentHash *h_age_commitment,
|
||||
const struct TALER_ExtensionContractHashP *h_extensions,
|
||||
const struct TALER_ExtensionPolicyHashP *h_policy,
|
||||
const struct TALER_DenominationHashP *h_denom_pub,
|
||||
struct GNUNET_TIME_Timestamp wallet_timestamp,
|
||||
const struct TALER_MerchantPublicKeyP *merchant_pub,
|
||||
@ -3666,7 +3665,7 @@ typedef enum TALER_ErrorCode
|
||||
* @param scb function to call to create the signature
|
||||
* @param h_contract_terms hash of the contact of the merchant with the customer (further details are never disclosed to the exchange)
|
||||
* @param h_wire hash of the merchant’s account details
|
||||
* @param h_extensions hash over the extensions, can be NULL
|
||||
* @param h_policy hash over the policy extension, can be NULL
|
||||
* @param exchange_timestamp timestamp when the contract was finalized, must not be too far off
|
||||
* @param wire_deadline date until which the exchange should wire the funds
|
||||
* @param refund_deadline date until which the merchant can issue a refund to the customer via the exchange (can be zero if refunds are not allowed); must not be after the @a wire_deadline
|
||||
@ -3682,7 +3681,7 @@ TALER_exchange_online_deposit_confirmation_sign (
|
||||
TALER_ExchangeSignCallback scb,
|
||||
const struct TALER_PrivateContractHashP *h_contract_terms,
|
||||
const struct TALER_MerchantWireHashP *h_wire,
|
||||
const struct TALER_ExtensionContractHashP *h_extensions,
|
||||
const struct TALER_ExtensionPolicyHashP *h_policy,
|
||||
struct GNUNET_TIME_Timestamp exchange_timestamp,
|
||||
struct GNUNET_TIME_Timestamp wire_deadline,
|
||||
struct GNUNET_TIME_Timestamp refund_deadline,
|
||||
@ -3698,7 +3697,7 @@ TALER_exchange_online_deposit_confirmation_sign (
|
||||
*
|
||||
* @param h_contract_terms hash of the contact of the merchant with the customer (further details are never disclosed to the exchange)
|
||||
* @param h_wire hash of the merchant’s account details
|
||||
* @param h_extensions hash over the extensions, can be NULL
|
||||
* @param h_policy hash over the policy extension, can be NULL
|
||||
* @param exchange_timestamp timestamp when the contract was finalized, must not be too far off
|
||||
* @param wire_deadline date until which the exchange should wire the funds
|
||||
* @param refund_deadline date until which the merchant can issue a refund to the customer via the exchange (can be zero if refunds are not allowed); must not be after the @a wire_deadline
|
||||
@ -3713,7 +3712,7 @@ enum GNUNET_GenericReturnValue
|
||||
TALER_exchange_online_deposit_confirmation_verify (
|
||||
const struct TALER_PrivateContractHashP *h_contract_terms,
|
||||
const struct TALER_MerchantWireHashP *h_wire,
|
||||
const struct TALER_ExtensionContractHashP *h_extensions,
|
||||
const struct TALER_ExtensionPolicyHashP *h_policy,
|
||||
struct GNUNET_TIME_Timestamp exchange_timestamp,
|
||||
struct GNUNET_TIME_Timestamp wire_deadline,
|
||||
struct GNUNET_TIME_Timestamp refund_deadline,
|
||||
@ -5257,31 +5256,31 @@ TALER_merchant_contract_sign (
|
||||
/* **************** /management/extensions offline signing **************** */
|
||||
|
||||
/**
|
||||
* Create a signature for the hash of the configuration of an extension
|
||||
* Create a signature for the hash of the manifests of extensions
|
||||
*
|
||||
* @param h_config hash of the JSON object representing the configuration
|
||||
* @param h_manifests hash of the JSON object representing the manifests
|
||||
* @param master_priv private key to sign with
|
||||
* @param[out] master_sig where to write the signature
|
||||
*/
|
||||
void
|
||||
TALER_exchange_offline_extension_config_hash_sign (
|
||||
const struct TALER_ExtensionConfigHashP *h_config,
|
||||
TALER_exchange_offline_extension_manifests_hash_sign (
|
||||
const struct TALER_ExtensionManifestsHashP *h_manifests,
|
||||
const struct TALER_MasterPrivateKeyP *master_priv,
|
||||
struct TALER_MasterSignatureP *master_sig);
|
||||
|
||||
|
||||
/**
|
||||
* Verify the signature in @a master_sig of the given hash, taken over the JSON
|
||||
* blob representing the configuration of an extension
|
||||
* blob representing the manifests of extensions
|
||||
*
|
||||
* @param h_config hash of the JSON blob of a configuration of an extension
|
||||
* @param h_manifest hash of the JSON blob of manifests of extensions
|
||||
* @param master_pub master public key of the exchange
|
||||
* @param master_sig signature of the exchange
|
||||
* @return #GNUNET_OK if signature is valid
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_exchange_offline_extension_config_hash_verify (
|
||||
const struct TALER_ExtensionConfigHashP *h_config,
|
||||
TALER_exchange_offline_extension_manifests_hash_verify (
|
||||
const struct TALER_ExtensionManifestsHashP *h_manifest,
|
||||
const struct TALER_MasterPublicKeyP *master_pub,
|
||||
const struct TALER_MasterSignatureP *master_sig
|
||||
);
|
||||
|
@ -894,9 +894,9 @@ struct TALER_EXCHANGE_DepositContractDetail
|
||||
struct TALER_PrivateContractHashP h_contract_terms;
|
||||
|
||||
/**
|
||||
* Extension-specific details about the deposit relevant to the exchange.
|
||||
* Policy extension specific details about the deposit relevant to the exchange.
|
||||
*/
|
||||
const json_t *extension_details;
|
||||
json_t *policy_details;
|
||||
|
||||
/**
|
||||
* Timestamp when the contract was finalized, must match approximately the
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <gnunet/gnunet_db_lib.h>
|
||||
#include "taler_json_lib.h"
|
||||
#include "taler_signatures.h"
|
||||
#include "taler_extensions_policy.h"
|
||||
|
||||
|
||||
/**
|
||||
@ -220,7 +221,8 @@ enum TALER_EXCHANGEDB_ReplicatedTable
|
||||
TALER_EXCHANGEDB_RT_RECOUP,
|
||||
TALER_EXCHANGEDB_RT_RECOUP_REFRESH,
|
||||
TALER_EXCHANGEDB_RT_EXTENSIONS,
|
||||
TALER_EXCHANGEDB_RT_EXTENSION_DETAILS,
|
||||
TALER_EXCHANGEDB_RT_POLICY_DETAILS,
|
||||
TALER_EXCHANGEDB_RT_POLICY_FULFILLMENTS,
|
||||
TALER_EXCHANGEDB_RT_PURSE_REQUESTS,
|
||||
TALER_EXCHANGEDB_RT_PURSE_DECISION,
|
||||
TALER_EXCHANGEDB_RT_PURSE_MERGES,
|
||||
@ -438,8 +440,8 @@ struct TALER_EXCHANGEDB_TableData
|
||||
struct TALER_CoinSpendSignatureP coin_sig;
|
||||
struct TALER_WireSaltP wire_salt;
|
||||
struct TALER_PaytoHashP wire_target_h_payto;
|
||||
bool extension_blocked;
|
||||
uint64_t extension_details_serial_id;
|
||||
bool policy_blocked;
|
||||
uint64_t policy_details_serial_id;
|
||||
} deposits;
|
||||
|
||||
struct
|
||||
@ -510,13 +512,32 @@ struct TALER_EXCHANGEDB_TableData
|
||||
struct
|
||||
{
|
||||
char *name;
|
||||
char *config;
|
||||
char *manifest;
|
||||
} extensions;
|
||||
|
||||
struct
|
||||
{
|
||||
char *extension_options;
|
||||
} extension_details;
|
||||
struct GNUNET_HashCode hash_code;
|
||||
json_t *policy_json;
|
||||
bool no_policy_json;
|
||||
struct GNUNET_TIME_Timestamp deadline;
|
||||
struct TALER_Amount commitment;
|
||||
struct TALER_Amount accumulated_total;
|
||||
struct TALER_Amount fee;
|
||||
struct TALER_Amount transferable;
|
||||
uint16_t fulfillment_state; /* will also be recomputed */
|
||||
uint64_t fulfillment_id;
|
||||
bool no_fulfillment_id;
|
||||
} policy_details;
|
||||
|
||||
struct
|
||||
{
|
||||
struct GNUNET_TIME_Timestamp fulfillment_timestamp;
|
||||
char *fulfillment_proof;
|
||||
struct GNUNET_HashCode h_fulfillment_proof;
|
||||
struct GNUNET_HashCode *policy_hash_codes;
|
||||
size_t policy_hash_codes_count;
|
||||
} policy_fulfillments;
|
||||
|
||||
struct
|
||||
{
|
||||
@ -1511,12 +1532,6 @@ struct TALER_EXCHANGEDB_Deposit
|
||||
*/
|
||||
char *receiver_wire_account;
|
||||
|
||||
/**
|
||||
* Additional details for extensions relevant for this
|
||||
* deposit operation, possibly NULL!
|
||||
*/
|
||||
json_t *extension_details;
|
||||
|
||||
/**
|
||||
* Time when this request was generated. Used, for example, to
|
||||
* assess when (roughly) the income was achieved for tax purposes.
|
||||
@ -1558,6 +1573,16 @@ struct TALER_EXCHANGEDB_Deposit
|
||||
*/
|
||||
struct TALER_Amount deposit_fee;
|
||||
|
||||
/*
|
||||
* True if @e policy_json was provided
|
||||
*/
|
||||
bool has_policy;
|
||||
|
||||
/**
|
||||
* Hash over the policy data for this deposit (remains unknown to the
|
||||
* Exchange). Needed for the verification of the deposit's signature
|
||||
*/
|
||||
struct TALER_ExtensionPolicyHashP h_policy;
|
||||
};
|
||||
|
||||
|
||||
@ -1656,6 +1681,17 @@ struct TALER_EXCHANGEDB_DepositListEntry
|
||||
*/
|
||||
struct TALER_Amount deposit_fee;
|
||||
|
||||
/*
|
||||
* True if a policy was provided with the deposit request
|
||||
*/
|
||||
bool has_policy;
|
||||
|
||||
/**
|
||||
* Hash over the policy data for this deposit (remains unknown to the
|
||||
* Exchange). Needed for the verification of the deposit's signature
|
||||
*/
|
||||
struct TALER_ExtensionPolicyHashP h_policy;
|
||||
|
||||
/**
|
||||
* Has the deposit been wired?
|
||||
*/
|
||||
@ -3530,6 +3566,40 @@ struct TALER_EXCHANGEDB_Plugin
|
||||
bool *conflict,
|
||||
bool *nonce_reuse);
|
||||
|
||||
/**
|
||||
* Retrieve the details to a policy given by its hash_code
|
||||
*
|
||||
* @param cls the `struct PostgresClosure` with the plugin-specific state
|
||||
* @param hc Hash code that identifies the policy
|
||||
* @param[out] detail retrieved policy details
|
||||
* @return query execution status
|
||||
*/
|
||||
enum GNUNET_DB_QueryStatus
|
||||
(*get_policy_details)(
|
||||
void *cls,
|
||||
const struct GNUNET_HashCode *hc,
|
||||
struct TALER_PolicyDetails *detail);
|
||||
|
||||
/**
|
||||
* Persist the policy details that extends a deposit. The particular policy
|
||||
* - referenced by details->hash_code - might already exist in the table, in
|
||||
* which case the call will update the contents of the record with @e details
|
||||
*
|
||||
* @param cls the `struct PostgresClosure` with the plugin-specific state
|
||||
* @param details The parsed `struct TALER_PolicyDetails` according to the responsible policy extension.
|
||||
* @param[out] policy_details_serial_id The ID of the entry in the policy_details table
|
||||
* @param[out] accumulated_total The total amount accumulated in that policy
|
||||
* @param[out] fulfillment_state The state of policy. If the state was Insufficient prior to the call and the provided deposit raises the accumulated_total above the commitment, it will be set to Ready.
|
||||
* @return query execution status
|
||||
*/
|
||||
enum GNUNET_DB_QueryStatus
|
||||
(*persist_policy_details)(
|
||||
void *cls,
|
||||
const struct TALER_PolicyDetails *details,
|
||||
uint64_t *policy_details_serial_id,
|
||||
struct TALER_Amount *accumulated_total,
|
||||
enum TALER_PolicyFulfillmentState *fulfillment_state);
|
||||
|
||||
|
||||
/**
|
||||
* Perform deposit operation, checking for sufficient balance
|
||||
@ -3539,7 +3609,7 @@ struct TALER_EXCHANGEDB_Plugin
|
||||
* @param deposit deposit operation details
|
||||
* @param known_coin_id row of the coin in the known_coins table
|
||||
* @param h_payto hash of the merchant's payto URI
|
||||
* @param extension_blocked true if an extension is blocking the wire transfer
|
||||
* @param policy_details_serial_id (pointer to) the row ID of the policy details, maybe NULL
|
||||
* @param[in,out] exchange_timestamp time to use for the deposit (possibly updated)
|
||||
* @param[out] balance_ok set to true if the balance was sufficient
|
||||
* @param[out] in_conflict set to true if the deposit conflicted
|
||||
@ -3551,7 +3621,7 @@ struct TALER_EXCHANGEDB_Plugin
|
||||
const struct TALER_EXCHANGEDB_Deposit *deposit,
|
||||
uint64_t known_coin_id,
|
||||
const struct TALER_PaytoHashP *h_payto,
|
||||
bool extension_blocked,
|
||||
uint64_t *policy_details_serial_id,
|
||||
struct GNUNET_TIME_Timestamp *exchange_timestamp,
|
||||
bool *balance_ok,
|
||||
bool *in_conflict);
|
||||
@ -3580,6 +3650,19 @@ struct TALER_EXCHANGEDB_Plugin
|
||||
bool *balance_ok);
|
||||
|
||||
|
||||
/**
|
||||
* Add a proof of fulfillment of an policy
|
||||
*
|
||||
* @param cls the plugin-specific state
|
||||
* @param[in,out] fulfillment The proof of fulfillment and serial_ids of the policy_details along with their new state and potential new amounts.
|
||||
* @return query execution status
|
||||
*/
|
||||
enum GNUNET_DB_QueryStatus
|
||||
(*add_policy_fulfillment_proof)(
|
||||
void *cls,
|
||||
struct TALER_PolicyFulfillmentTransactionData *fulfillment);
|
||||
|
||||
|
||||
/**
|
||||
* Check if the given @a nonce was properly locked to the given @a old_coin_pub. If so, check if we already
|
||||
* created CS signatures for the given @a nonce and @a new_denom_pub_hashes,
|
||||
@ -5559,33 +5642,33 @@ struct TALER_EXCHANGEDB_Plugin
|
||||
|
||||
|
||||
/**
|
||||
* Function called to save the configuration of an extension
|
||||
* (age-restriction, peer2peer, ...)
|
||||
* Function called to save the manifest of an extension
|
||||
* (age-restriction, policy-extension, ...)
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param extension_name the name of the extension
|
||||
* @param config JSON object of the configuration as string, maybe NULL (== disabled extension)
|
||||
* @param manifest JSON object of the Manifest as string, maybe NULL (== disabled extension)
|
||||
* @return transaction status code
|
||||
*/
|
||||
enum GNUNET_DB_QueryStatus
|
||||
(*set_extension_config)(void *cls,
|
||||
(*set_extension_manifest)(void *cls,
|
||||
const char *extension_name,
|
||||
const char *config);
|
||||
const char *manifest);
|
||||
|
||||
|
||||
/**
|
||||
* Function called to retrieve the configuration of an extension
|
||||
* (age-restriction, peer2peer, ...)
|
||||
* Function called to retrieve the manifest of an extension
|
||||
* (age-restriction, policy-extension, ...)
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param extension_name the name of the extension
|
||||
* @param[out] config JSON object of the configuration as string, maybe NULL (== disabled extension)
|
||||
* @param[out] manifest Manifest of the extension in JSON encoding, maybe NULL (== disabled extension)
|
||||
* @return transaction status code
|
||||
*/
|
||||
enum GNUNET_DB_QueryStatus
|
||||
(*get_extension_config)(void *cls,
|
||||
(*get_extension_manifest)(void *cls,
|
||||
const char *extension_name,
|
||||
char **config);
|
||||
char **manifest);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014-2021 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
|
||||
@ -24,48 +24,195 @@
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include "taler_crypto_lib.h"
|
||||
#include "taler_json_lib.h"
|
||||
#include "taler_mhd_lib.h"
|
||||
#include "taler_extensions_policy.h"
|
||||
|
||||
|
||||
#define TALER_EXTENSION_SECTION_PREFIX "exchange-extension-"
|
||||
|
||||
enum TALER_Extension_Type
|
||||
{
|
||||
TALER_Extension_AgeRestriction = 0,
|
||||
TALER_Extension_MaxPredefined = 1 // 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
|
||||
};
|
||||
|
||||
|
||||
/* Forward declarations */
|
||||
enum TALER_PolicyFulfillmentState;
|
||||
struct TALER_PolicyFulfillmentOutcome;
|
||||
|
||||
/*
|
||||
* @brief Represents the implementation of an extension.
|
||||
*
|
||||
* TODO: add documentation
|
||||
* An "Extension" is an optional feature for the Exchange.
|
||||
* There are only two types of extensions:
|
||||
*
|
||||
* a) Age restriction: This is a special feature that directly interacts with
|
||||
* denominations and coins, but is not define policies during deposits, see b).
|
||||
* The implementation of this extension doesn't have to implement any of the
|
||||
* http- or depost-handlers in the struct.
|
||||
*
|
||||
* b) Policies for deposits: These are extensions that define policies (such
|
||||
* as refund, escrow or auctions) for deposit requests. These extensions have
|
||||
* to implement at least the deposit- and post-http-handler in the struct to be
|
||||
* functional.
|
||||
*
|
||||
* In addition to the handlers defined in this struct, an extension must also
|
||||
* be a plugin in the GNUNET_Plugin sense. That is, it must implement the
|
||||
* functions
|
||||
* 1: (void *ext)libtaler_extension_<name>_init(void *cfg)
|
||||
* and
|
||||
* 2: (void *)libtaler_extension_<name>_done(void *)
|
||||
*
|
||||
* In 1:, the input will be the GNUNET_CONFIGURATION_Handle to the TALER
|
||||
* configuration and the output must be the struct TALER_Extension * on
|
||||
* success, NULL otherwise.
|
||||
*
|
||||
* In 2:, no arguments are passed and NULL is expected to be returned.
|
||||
*/
|
||||
struct TALER_Extension
|
||||
{
|
||||
/* simple linked list */
|
||||
struct TALER_Extension *next;
|
||||
|
||||
/**
|
||||
* Type of the extension. Only one extension of a type can be loaded
|
||||
* at any time.
|
||||
*/
|
||||
enum TALER_Extension_Type type;
|
||||
char *name;
|
||||
bool critical;
|
||||
char *version;
|
||||
void *config;
|
||||
json_t *config_json;
|
||||
|
||||
/**
|
||||
* The name of the extension, must be unique among all loaded extensions. It
|
||||
* is used in URLs for /extension/$NAME as well.
|
||||
*/
|
||||
char *name;
|
||||
|
||||
/**
|
||||
* Criticality of the extension. It has the same semantics as "critical" has
|
||||
* for extensions in X.509:
|
||||
* - if "true", the client must "understand" the extension before proceeding,
|
||||
* - if "false", clients can safely skip extensions they do not understand.
|
||||
* (see https://datatracker.ietf.org/doc/html/rfc5280#section-4.2)
|
||||
*/
|
||||
bool critical;
|
||||
|
||||
/**
|
||||
* Version of the extension must be provided in Taler's protocol verison ranges notation, see
|
||||
* https://docs.taler.net/core/api-common.html#protocol-version-ranges
|
||||
*/
|
||||
char *version;
|
||||
|
||||
/**
|
||||
* If the extension is marked as enabled, it will be listed in the
|
||||
* "extensions" field in the "/keys" response.
|
||||
*/
|
||||
bool enabled;
|
||||
|
||||
/**
|
||||
* Opaque (public) configuration object, set by the extension.
|
||||
*/
|
||||
void *config;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Handler to to disable the extension.
|
||||
*
|
||||
* @param ext The current extension object
|
||||
*/
|
||||
void (*disable)(struct TALER_Extension *ext);
|
||||
|
||||
enum GNUNET_GenericReturnValue (*test_json_config)(
|
||||
const json_t *config);
|
||||
|
||||
enum GNUNET_GenericReturnValue (*load_json_config)(
|
||||
/**
|
||||
* @brief Handler to read an extension-specific configuration in JSON
|
||||
* encoding and enable the extension. Must be implemented by the extension.
|
||||
*
|
||||
* @param ext The extension object. If NULL, the configuration will only be checked.
|
||||
* @param config A JSON blob
|
||||
* @return GNUNET_OK if the json was a valid configuration for the extension.
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue (*load_config)(
|
||||
struct TALER_Extension *ext,
|
||||
json_t *config);
|
||||
|
||||
json_t *(*config_to_json)(
|
||||
/**
|
||||
* @brief Handler to return the manifest of the extension in JSON encoding.
|
||||
*
|
||||
* See
|
||||
* https://docs.taler.net/design-documents/006-extensions.html#tsref-type-Extension
|
||||
* for the definition.
|
||||
*
|
||||
* @param ext The extension object
|
||||
* @return The JSON encoding of the extension, if enabled, NULL otherwise.
|
||||
*/
|
||||
json_t *(*manifest)(
|
||||
const struct TALER_Extension *ext);
|
||||
|
||||
enum GNUNET_GenericReturnValue (*load_taler_config)(
|
||||
struct TALER_Extension *ext,
|
||||
const struct GNUNET_CONFIGURATION_Handle *cfg);
|
||||
/* =========================
|
||||
* Policy related handlers
|
||||
* =========================
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Handler to check an incoming policy and create a
|
||||
* TALER_PolicyDetails. 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 before the deposit transaction.
|
||||
*
|
||||
* @param[in] policy_json Details about the policy, provided by the client
|
||||
* during a deposit request.
|
||||
* @param[out] details On success, will contain the details to the policy,
|
||||
* evaluated by the corresponding policy handler.
|
||||
* @param[out] error_hint On error, will contain a hint
|
||||
* @return GNUNET_OK if the data was accepted by the extension.
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue (*create_policy_details)(
|
||||
const json_t *policy_json,
|
||||
struct TALER_PolicyDetails *details,
|
||||
const char **error_hint);
|
||||
|
||||
/**
|
||||
* @brief Handler for POST-requests to the /extensions/$name endpoint. Can be NULL.
|
||||
*
|
||||
* @param[in] root The JSON body from the request
|
||||
* @param[in] args Additional query parameters of the request.
|
||||
* @param[in,out] details List of policy details related to the incoming fulfillment proof
|
||||
* @param[in] details_len Size of the list @e details
|
||||
* @param[out] output JSON output to return to the client
|
||||
* @return GNUNET_OK on success.
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue (*policy_post_handler)(
|
||||
const json_t *root,
|
||||
const char *const args[],
|
||||
struct TALER_PolicyDetails *details,
|
||||
size_t details_len,
|
||||
json_t **output);
|
||||
|
||||
/**
|
||||
* @brief Handler for GET-requests to the /extensions/$name endpoint. Can be NULL.
|
||||
*
|
||||
* @param connection The current connection
|
||||
* @param root The JSON body from the request
|
||||
* @param args Additional query parameters of the request.
|
||||
* @return MDH result
|
||||
*/
|
||||
MHD_RESULT (*policy_get_handler)(
|
||||
struct MHD_Connection *connection,
|
||||
const char *const args[]);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* @brief simply linked list of extensions
|
||||
*/
|
||||
|
||||
struct TALER_Extensions
|
||||
{
|
||||
struct TALER_Extensions *next;
|
||||
const struct TALER_Extension *extension;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -73,70 +220,57 @@ struct TALER_Extension
|
||||
*/
|
||||
|
||||
/*
|
||||
* @brief Sets the configuration of the extensions from the given TALER
|
||||
* configuration.
|
||||
* @brief Loads the extensions as shared libraries, as specified in the given
|
||||
* TALER configuration.
|
||||
*
|
||||
* @param cfg Handle to the TALER configuration
|
||||
* @return GNUNET_OK on success, GNUNET_SYSERR if unknown extensions were found
|
||||
* or any particular configuration couldn't be parsed.
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_extensions_load_taler_config (
|
||||
TALER_extensions_init (
|
||||
const struct GNUNET_CONFIGURATION_Handle *cfg);
|
||||
|
||||
/*
|
||||
* @brief Checks the given obj to be a valid extension object and fill the
|
||||
* fields accordingly.
|
||||
* @brief Parses a given JSON object as an extension manifest.
|
||||
*
|
||||
* @param[in] obj Object to verify is a valid extension
|
||||
* @param[in] obj JSON object to parse as an extension manifest
|
||||
* @param{out] critical will be set to 1 if the extension is critical according to obj
|
||||
* @param[out] version will be set to the version of the extension according to obj
|
||||
* @param[out] config will be set to the configuration of the extension according to obj
|
||||
* @return OK on success, Error otherwise
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_extensions_is_json_config (
|
||||
TALER_extensions_parse_manifest (
|
||||
json_t *obj,
|
||||
int *critical,
|
||||
const char **version,
|
||||
json_t **config);
|
||||
|
||||
/*
|
||||
* @brief Sets the configuration of the extensions from a given JSON object.
|
||||
* @brief Loads extensions according to the manifests.
|
||||
*
|
||||
* The JSON object must be of type ExchangeKeysResponse as described in
|
||||
* https://docs.taler.net/design-documents/006-extensions.html#exchange
|
||||
* The JSON object must be of type ExtensionsManifestsResponse as described
|
||||
* in https://docs.taler.net/design-documents/006-extensions.html#exchange
|
||||
*
|
||||
* @param cfg JSON object containing the configuration for all extensions
|
||||
* @param cfg JSON object containing the manifests for all extensions
|
||||
* @return #GNUNET_OK on success, #GNUNET_SYSERR if unknown extensions were
|
||||
* found or any particular configuration couldn't be parsed.
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_extensions_load_json_config (
|
||||
json_t *cfg);
|
||||
TALER_extensions_load_manifests (
|
||||
json_t *manifests);
|
||||
|
||||
/*
|
||||
* @brief Returns the head of the linked list of extensions.
|
||||
*/
|
||||
const struct TALER_Extension *
|
||||
const struct TALER_Extensions *
|
||||
TALER_extensions_get_head ();
|
||||
|
||||
/*
|
||||
* @brief Adds an extension to the linked list of extensions.
|
||||
*
|
||||
* @param new_extension the new extension to be added
|
||||
* @return GNUNET_OK on success, GNUNET_SYSERR if the extension is invalid
|
||||
* (missing fields), GNUNET_NO if there is already an extension with that name
|
||||
* or type.
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_extensions_add (
|
||||
struct TALER_Extension *new_extension);
|
||||
|
||||
/**
|
||||
* @brief Finds and returns a supported extension by a given type.
|
||||
*
|
||||
* @param type type of the extension to lookup
|
||||
* @param type of the extension to lookup
|
||||
* @return extension found, or NULL (should not happen!)
|
||||
*/
|
||||
const struct TALER_Extension *
|
||||
@ -154,8 +288,6 @@ const struct TALER_Extension *
|
||||
TALER_extensions_get_by_name (
|
||||
const char *name);
|
||||
|
||||
#define TALER_extensions_is_enabled(ext) (NULL != (ext)->config)
|
||||
|
||||
/**
|
||||
* @brief Check if a given type of an extension is enabled
|
||||
*
|
||||
@ -166,12 +298,21 @@ bool
|
||||
TALER_extensions_is_enabled_type (
|
||||
enum TALER_Extension_Type type);
|
||||
|
||||
/**
|
||||
* @brief Check if an extension is enabled
|
||||
*
|
||||
* @param extension The extension handler.
|
||||
* @return true enabled, false if not enabled, will assert if type is not found.
|
||||
*/
|
||||
bool
|
||||
TALER_extensions_is_enabled (
|
||||
const struct TALER_Extension *extension);
|
||||
|
||||
/*
|
||||
* Verify the signature of a given JSON object for extensions with the master
|
||||
* key of the exchange.
|
||||
*
|
||||
* The JSON object must be of type ExchangeKeysResponse as described in
|
||||
* The JSON object must be of type ExtensionsManifestsResponse as described in
|
||||
* https://docs.taler.net/design-documents/006-extensions.html#exchange
|
||||
*
|
||||
* @param extensions JSON object with the extension configuration
|
||||
@ -181,14 +322,19 @@ TALER_extensions_is_enabled_type (
|
||||
* and GNUNET_NO if the signature couldn't be verified.
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_extensions_verify_json_config_signature (
|
||||
json_t *extensions,
|
||||
TALER_extensions_verify_manifests_signature (
|
||||
json_t *manifests,
|
||||
struct TALER_MasterSignatureP *extensions_sig,
|
||||
struct TALER_MasterPublicKeyP *master_pub);
|
||||
|
||||
|
||||
/*
|
||||
* TALER Age Restriction Extension
|
||||
*
|
||||
* This extension is special insofar as it directly interacts with coins and
|
||||
* denominations.
|
||||
*
|
||||
* At the same time, it doesn't implement and http- or deposit-handlers.
|
||||
*/
|
||||
|
||||
#define TALER_EXTENSION_SECTION_AGE_RESTRICTION (TALER_EXTENSION_SECTION_PREFIX \
|
||||
@ -204,102 +350,39 @@ TALER_extensions_verify_json_config_signature (
|
||||
| 1 << 21)
|
||||
#define TALER_EXTENSION_AGE_RESTRICTION_DEFAULT_AGE_GROUPS "8:10:12:14:16:18:21"
|
||||
|
||||
/**
|
||||
* @brief Registers the extension for age restriction to the list extensions
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_extension_age_restriction_register ();
|
||||
|
||||
/**
|
||||
* @brief Parses a string as a list of age groups.
|
||||
*
|
||||
* The string must consist of a colon-separated list of increasing integers
|
||||
* between 0 and 31. Each entry represents the beginning of a new age group.
|
||||
* F.e. the string
|
||||
*
|
||||
* "8:10:12:14:16:18:21"
|
||||
*
|
||||
* represents the following list of eight age groups:
|
||||
*
|
||||
* | Group | Ages |
|
||||
* | -----:|:------------- |
|
||||
* | 0 | 0, 1, ..., 7 |
|
||||
* | 1 | 8, 9 |
|
||||
* | 2 | 10, 11 |
|
||||
* | 3 | 12, 13 |
|
||||
* | 4 | 14, 15 |
|
||||
* | 5 | 16, 17 |
|
||||
* | 6 | 18, 19, 20 |
|
||||
* | 7 | 21, ... |
|
||||
*
|
||||
* which is then encoded as a bit mask with the corresponding bits set:
|
||||
*
|
||||
* 31 24 16 8 0
|
||||
* | | | | |
|
||||
* oooooooo oo1oo1o1 o1o1o1o1 ooooooo1
|
||||
*
|
||||
* @param groups String representation of age groups
|
||||
* @param[out] mask Mask representation for age restriction.
|
||||
* @return Error, if age groups were invalid, OK otherwise.
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_parse_age_group_string (
|
||||
const char *groups,
|
||||
struct TALER_AgeMask *mask);
|
||||
|
||||
/**
|
||||
* @brief Encodes the age mask into a string, like "8:10:12:14:16:18:21"
|
||||
*
|
||||
* @param mask Age mask
|
||||
* @return String representation of the age mask, allocated by GNUNET_malloc.
|
||||
* Can be used as value in the TALER config.
|
||||
*/
|
||||
char *
|
||||
TALER_age_mask_to_string (
|
||||
const struct TALER_AgeMask *mask);
|
||||
|
||||
/**
|
||||
* @brief Returns true when age restriction is configured and enabled.
|
||||
*/
|
||||
bool
|
||||
TALER_extensions_age_restriction_is_enabled ();
|
||||
|
||||
/**
|
||||
* @brief Returns true when age restriction is configured (might not be
|
||||
* _enabled_, though).
|
||||
*/
|
||||
bool
|
||||
TALER_extensions_age_restriction_is_configured ();
|
||||
|
||||
/**
|
||||
* @brief Returns the currently set age mask. Note that even if age
|
||||
* restriction is not enabled, the age mask might be have a non-zero value.
|
||||
*/
|
||||
struct TALER_AgeMask
|
||||
TALER_extensions_age_restriction_ageMask ();
|
||||
|
||||
|
||||
/**
|
||||
* @brief Returns the amount of age groups defined. 0 means no age restriction
|
||||
* enabled.
|
||||
*/
|
||||
size_t
|
||||
TALER_extensions_age_restriction_num_groups ();
|
||||
|
||||
/**
|
||||
* @brief Parses a JSON object { "age_groups": "a:b:...y:z" }.
|
||||
*
|
||||
* @param root is the json object
|
||||
* @param[out] mask on success, will contain the age mask
|
||||
* @return #GNUNET_OK on success and #GNUNET_SYSERR on failure.
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_JSON_parse_age_groups (const json_t *root,
|
||||
struct TALER_AgeMask *mask);
|
||||
|
||||
|
||||
/*
|
||||
* TODO: Add Peer2Peer Extension
|
||||
* @brief Configuration for Age Restriction
|
||||
*/
|
||||
struct TALER_AgeRestrictionConfig
|
||||
{
|
||||
struct TALER_AgeMask mask;
|
||||
uint8_t num_groups;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve the age restriction configuration
|
||||
*
|
||||
* @return age restriction configuration if present, otherwise NULL.
|
||||
*/
|
||||
const struct TALER_AgeRestrictionConfig *
|
||||
TALER_extensions_get_age_restriction_config ();
|
||||
|
||||
/**
|
||||
* @brief Check if age restriction is enabled
|
||||
*
|
||||
* @return true, if age restriction is loaded, configured and enabled; otherwise false.
|
||||
*/
|
||||
bool
|
||||
TALER_extensions_is_age_restriction_enabled ();
|
||||
|
||||
/**
|
||||
* @brief Return the age mask for age restriction
|
||||
*
|
||||
* @return configured age mask, if age restriction is loaded, configured and enabled; otherwise zero mask.
|
||||
*/
|
||||
struct TALER_AgeMask
|
||||
TALER_extensions_get_age_restriction_mask ();
|
||||
|
||||
#endif
|
||||
|
198
src/include/taler_extensions_policy.h
Normal file
198
src/include/taler_extensions_policy.h
Normal file
@ -0,0 +1,198 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
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
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file include/taler_extensions_policy.h
|
||||
* @brief Interface for policy extensions
|
||||
* @author Özgür Kesim
|
||||
*/
|
||||
#ifndef TALER_EXTENSIONS_POLICY_H
|
||||
#define TALER_EXTENSIONS_POLICY_H
|
||||
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include "taler_crypto_lib.h"
|
||||
#include "taler_json_lib.h"
|
||||
#include "taler_mhd_lib.h"
|
||||
|
||||
/*
|
||||
* @brief Describes the states of fulfillment of a policy bound to a deposit
|
||||
*/
|
||||
enum TALER_PolicyFulfillmentState
|
||||
{
|
||||
/* General error state of an fulfillment. */
|
||||
TALER_PolicyFulfillmentFailure = 0,
|
||||
|
||||
/* The policy is not yet ready due to insufficient funding. More deposits are
|
||||
* necessary for it to become ready . */
|
||||
TALER_PolicyFulfillmentInsufficient = 1,
|
||||
|
||||
/* The policy is funded and ready, pending */
|
||||
TALER_PolicyFulfillmentReady = 2,
|
||||
|
||||
/* Policy is provably fulfilled. */
|
||||
TALER_PolicyFulfillmentSuccess = 3,
|
||||
|
||||
/* Policy fulfillment has timed out */
|
||||
TALER_PolicyFulfillmentTimeout = 4,
|
||||
|
||||
TALER_PolicyFulfillmentStateCount = TALER_PolicyFulfillmentTimeout + 1
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* @brief Returns a string representation of the state of a policy fulfillment
|
||||
*/
|
||||
const char *
|
||||
TALER_policy_fulfillment_state_str (enum TALER_PolicyFulfillmentState state);
|
||||
|
||||
|
||||
/* @brief Details of a policy for a deposit request */
|
||||
struct TALER_PolicyDetails
|
||||
{
|
||||
/* Hash code that should be used for the .policy_hash_code field when
|
||||
* this policy is saved in the policy_details table. */
|
||||
struct GNUNET_HashCode hash_code;
|
||||
|
||||
/* Content of the policy in its original JSON form */
|
||||
json_t *policy_json;
|
||||
|
||||
/* When the deadline is meat and the policy is still in "Ready" state,
|
||||
* a timeout-handler will transfer the amount
|
||||
* (total_amount - policy_fee - refreshable_amount)
|
||||
* to the payto-URI from the corresponding deposit. The value
|
||||
* amount_refreshable will be refreshable by the owner of the
|
||||
* associated deposits's coins */
|
||||
struct GNUNET_TIME_Timestamp deadline;
|
||||
|
||||
/* The amount to which this policy commits to. It must be at least as
|
||||
* large as @e policy_fee. */
|
||||
struct TALER_Amount commitment;
|
||||
|
||||
/* The total sum of contributions from coins so far to fund this
|
||||
* policy. It must be at least as large as @commitment in order to be
|
||||
* sufficiently funded. */
|
||||
struct TALER_Amount accumulated_total;
|
||||
|
||||
/* The fee from the exchange for handling the policy. It is due when
|
||||
* the state changes to Timeout or Success. */
|
||||
struct TALER_Amount policy_fee;
|
||||
|
||||
/* The amount that will be transfered to the payto-URIs from the
|
||||
* corresponding deposits when the fulfillment state changes to Timeout
|
||||
* or Success. Note that a fulfillment handler can alter this upon
|
||||
* arrival of a proof of fulfillment. The remaining amount
|
||||
* (accumulated_amount - policy_amount - transferable_amount) */
|
||||
struct TALER_Amount transferable_amount;
|
||||
|
||||
/* The state of fulfillment of a policy.
|
||||
* - If the state is Insufficient, the client is required to call
|
||||
* /deposit -maybe multiple times- with enough coins and the same
|
||||
* policy details in order to reach the required amount. The state is
|
||||
* then changed to Ready.
|
||||
* - If the state changes to Timeout or Success, a handler will transfer
|
||||
* the amount (total_amount - policy_fee - refreshable_amount) to the
|
||||
* payto-URI from the corresponding deposit. The value
|
||||
* amount_refreshable will be refreshable by the owner of the
|
||||
* associated deposits's coins. */
|
||||
enum TALER_PolicyFulfillmentState fulfillment_state;
|
||||
|
||||
/* If there is a proof of fulfillment, the row ID from the
|
||||
* policy_fulfillment table */
|
||||
uint64_t policy_fulfillment_id;
|
||||
bool no_policy_fulfillment_id;
|
||||
};
|
||||
|
||||
/*
|
||||
* @brief All information required for the database transaction when handling a
|
||||
* proof of fulfillment request.
|
||||
*/
|
||||
struct TALER_PolicyFulfillmentTransactionData
|
||||
{
|
||||
/* The incoming proof, provided by a client */
|
||||
const json_t *proof;
|
||||
|
||||
/* The Hash of the proof */
|
||||
struct GNUNET_HashCode h_proof;
|
||||
|
||||
/* The timestamp of retrieval of the proof */
|
||||
struct GNUNET_TIME_Timestamp timestamp;
|
||||
|
||||
/* The ID of the proof in the policy_fulfillment table. Will be set
|
||||
* during the transaction. Needed to fill the table
|
||||
* policy_details_fulfillments. */
|
||||
uint64_t fulfillment_id;
|
||||
|
||||
/* The list of policy details. Will be updated by the policy handler */
|
||||
struct TALER_PolicyDetails *details;
|
||||
size_t details_count;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* @brief Extracts policy details from the deposit's policy options and the policy extensions
|
||||
*
|
||||
* @param[in] policy_options JSON of the policy options from a deposit request
|
||||
* @param[out] details On GNUNET_OK, the parsed details
|
||||
* @param[out] error_hint On GNUNET_SYSERR, will contain a hint for the reason why it failed
|
||||
* @return GNUNET_OK on success, 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_create_policy_details (
|
||||
const json_t *policy_options,
|
||||
struct TALER_PolicyDetails *details,
|
||||
const char **error_hint);
|
||||
|
||||
|
||||
/*
|
||||
* ================================
|
||||
* Merchant refund policy
|
||||
* ================================
|
||||
*/
|
||||
struct TALER_ExtensionPolicyMerchantRefundPolicyConfig
|
||||
{
|
||||
struct GNUNET_TIME_Relative max_timeout;
|
||||
};
|
||||
|
||||
/*
|
||||
* ================================
|
||||
* Brandt-Vickrey Auctions policy
|
||||
* ================================
|
||||
*/
|
||||
/*
|
||||
* @brief Configuration for Brandt-Vickrey auctions policy
|
||||
*/
|
||||
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
|
@ -765,25 +765,25 @@ TALER_JSON_wire_to_payto (const json_t *wire_s);
|
||||
|
||||
|
||||
/**
|
||||
* Hash @a extensions in deposits.
|
||||
* Hash @a policy extensions in deposits.
|
||||
*
|
||||
* @param extensions contract extensions to hash
|
||||
* @param[out] ech where to write the extension hash
|
||||
* @param policy contract policy extension to hash
|
||||
* @param[out] ech where to write the policy hash
|
||||
*/
|
||||
void
|
||||
TALER_deposit_extension_hash (const json_t *extensions,
|
||||
struct TALER_ExtensionContractHashP *ech);
|
||||
TALER_deposit_policy_hash (const json_t *extensions,
|
||||
struct TALER_ExtensionPolicyHashP *ech);
|
||||
|
||||
/**
|
||||
* Hash the @a config of an extension, given as JSON
|
||||
* Hash the @a manifests of extensions, given as JSON
|
||||
*
|
||||
* @param config configuration of the extension
|
||||
* @param[out] eh where to write the extension hash
|
||||
* @param manifests Manifests of the extensions
|
||||
* @param[out] eh where to write the hash
|
||||
* @return GNUNET_OK on success, GNUNET_SYSERR on failure
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_JSON_extensions_config_hash (const json_t *config,
|
||||
struct TALER_ExtensionConfigHashP *eh);
|
||||
TALER_JSON_extensions_manifests_hash (const json_t *manifests,
|
||||
struct TALER_ExtensionManifestsHashP *eh);
|
||||
|
||||
/**
|
||||
* Canonicalize a JSON input to a string according to RFC 8785.
|
||||
|
@ -492,5 +492,63 @@ char *strchrnul (const char *s, int c);
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Parses a string as a list of age groups.
|
||||
*
|
||||
* The string must consist of a colon-separated list of increasing integers
|
||||
* between 0 and 31. Each entry represents the beginning of a new age group.
|
||||
* F.e. the string
|
||||
*
|
||||
* "8:10:12:14:16:18:21"
|
||||
*
|
||||
* represents the following list of eight age groups:
|
||||
*
|
||||
* | Group | Ages |
|
||||
* | -----:|:------------- |
|
||||
* | 0 | 0, 1, ..., 7 |
|
||||
* | 1 | 8, 9 |
|
||||
* | 2 | 10, 11 |
|
||||
* | 3 | 12, 13 |
|
||||
* | 4 | 14, 15 |
|
||||
* | 5 | 16, 17 |
|
||||
* | 6 | 18, 19, 20 |
|
||||
* | 7 | 21, ... |
|
||||
*
|
||||
* which is then encoded as a bit mask with the corresponding bits set:
|
||||
*
|
||||
* 31 24 16 8 0
|
||||
* | | | | |
|
||||
* oooooooo oo1oo1o1 o1o1o1o1 ooooooo1
|
||||
*
|
||||
* @param groups String representation of age groups
|
||||
* @param[out] mask Mask representation for age restriction.
|
||||
* @return Error, if age groups were invalid, OK otherwise.
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_parse_age_group_string (
|
||||
const char *groups,
|
||||
struct TALER_AgeMask *mask);
|
||||
|
||||
/**
|
||||
* @brief Encodes the age mask into a string, like "8:10:12:14:16:18:21"
|
||||
*
|
||||
* @param mask Age mask
|
||||
* @return String representation of the age mask, allocated by GNUNET_malloc.
|
||||
* Can be used as value in the TALER config.
|
||||
*/
|
||||
char *
|
||||
TALER_age_mask_to_string (
|
||||
const struct TALER_AgeMask *mask);
|
||||
|
||||
/**
|
||||
* @brief Parses a JSON object { "age_groups": "a:b:...y:z" }.
|
||||
*
|
||||
* @param root is the json object
|
||||
* @param[out] mask on success, will contain the age mask
|
||||
* @return #GNUNET_OK on success and #GNUNET_SYSERR on failure.
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_JSON_parse_age_groups (const json_t *root,
|
||||
struct TALER_AgeMask *mask);
|
||||
|
||||
#endif
|
||||
|
@ -1008,12 +1008,12 @@ TALER_JSON_get_error_code2 (const void *data,
|
||||
|
||||
|
||||
void
|
||||
TALER_deposit_extension_hash (const json_t *extensions,
|
||||
struct TALER_ExtensionContractHashP *ech)
|
||||
TALER_deposit_policy_hash (const json_t *policy,
|
||||
struct TALER_ExtensionPolicyHashP *ech)
|
||||
{
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
dump_and_hash (extensions,
|
||||
"taler-contract-extensions",
|
||||
dump_and_hash (policy,
|
||||
"taler-extensions-policy",
|
||||
&ech->hash));
|
||||
}
|
||||
|
||||
@ -1037,11 +1037,11 @@ TALER_JSON_canonicalize (const json_t *input)
|
||||
|
||||
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_JSON_extensions_config_hash (const json_t *config,
|
||||
struct TALER_ExtensionConfigHashP *ech)
|
||||
TALER_JSON_extensions_manifests_hash (const json_t *manifests,
|
||||
struct TALER_ExtensionManifestsHashP *ech)
|
||||
{
|
||||
return dump_and_hash (config,
|
||||
"taler-extension-configuration",
|
||||
return dump_and_hash (manifests,
|
||||
"taler-extensions-manifests",
|
||||
&ech->hash);
|
||||
}
|
||||
|
||||
|
@ -153,7 +153,7 @@ handle_deposit_confirmation_finished (void *cls,
|
||||
* Verify signature information about the deposit-confirmation.
|
||||
*
|
||||
* @param h_wire hash of merchant wire details
|
||||
* @param h_extensions hash over the extensions, if any
|
||||
* @param h_policy hash over the policy extension, if any
|
||||
* @param h_contract_terms hash of the contact of the merchant with the customer (further details are never disclosed to the auditor)
|
||||
* @param exchange_timestamp timestamp when the deposit was received by the wallet
|
||||
* @param wire_deadline by what time must the amount be wired to the merchant
|
||||
@ -172,7 +172,7 @@ handle_deposit_confirmation_finished (void *cls,
|
||||
*/
|
||||
static enum GNUNET_GenericReturnValue
|
||||
verify_signatures (const struct TALER_MerchantWireHashP *h_wire,
|
||||
const struct TALER_ExtensionContractHashP *h_extensions,
|
||||
const struct TALER_ExtensionPolicyHashP *h_policy,
|
||||
const struct TALER_PrivateContractHashP *h_contract_terms,
|
||||
struct GNUNET_TIME_Timestamp exchange_timestamp,
|
||||
struct GNUNET_TIME_Timestamp wire_deadline,
|
||||
@ -192,7 +192,7 @@ verify_signatures (const struct TALER_MerchantWireHashP *h_wire,
|
||||
TALER_exchange_online_deposit_confirmation_verify (
|
||||
h_contract_terms,
|
||||
h_wire,
|
||||
h_extensions,
|
||||
h_policy,
|
||||
exchange_timestamp,
|
||||
wire_deadline,
|
||||
refund_deadline,
|
||||
@ -239,7 +239,7 @@ struct TALER_AUDITOR_DepositConfirmationHandle *
|
||||
TALER_AUDITOR_deposit_confirmation (
|
||||
struct TALER_AUDITOR_Handle *auditor,
|
||||
const struct TALER_MerchantWireHashP *h_wire,
|
||||
const struct TALER_ExtensionContractHashP *h_extensions,
|
||||
const struct TALER_ExtensionPolicyHashP *h_policy,
|
||||
const struct TALER_PrivateContractHashP *h_contract_terms,
|
||||
struct GNUNET_TIME_Timestamp exchange_timestamp,
|
||||
struct GNUNET_TIME_Timestamp wire_deadline,
|
||||
@ -266,7 +266,7 @@ TALER_AUDITOR_deposit_confirmation (
|
||||
TALER_AUDITOR_handle_is_ready_ (auditor));
|
||||
if (GNUNET_OK !=
|
||||
verify_signatures (h_wire,
|
||||
h_extensions,
|
||||
h_policy,
|
||||
h_contract_terms,
|
||||
exchange_timestamp,
|
||||
wire_deadline,
|
||||
@ -290,8 +290,8 @@ TALER_AUDITOR_deposit_confirmation (
|
||||
= GNUNET_JSON_PACK (
|
||||
GNUNET_JSON_pack_data_auto ("h_wire",
|
||||
h_wire),
|
||||
GNUNET_JSON_pack_data_auto ("h_extensions",
|
||||
h_extensions),
|
||||
GNUNET_JSON_pack_data_auto ("h_policy",
|
||||
h_policy),
|
||||
GNUNET_JSON_pack_data_auto ("h_contract_terms",
|
||||
h_contract_terms),
|
||||
GNUNET_JSON_pack_timestamp ("exchange_timestamp",
|
||||
|
@ -99,7 +99,7 @@ struct TALER_EXCHANGE_BatchDepositHandle
|
||||
/**
|
||||
* Hash over the extensions, or all zero.
|
||||
*/
|
||||
struct TALER_ExtensionContractHashP h_extensions;
|
||||
struct TALER_ExtensionPolicyHashP h_policy;
|
||||
|
||||
/**
|
||||
* Time when this confirmation was generated / when the exchange received
|
||||
@ -185,7 +185,7 @@ auditor_cb (void *cls,
|
||||
aie->dch = TALER_AUDITOR_deposit_confirmation (
|
||||
ah,
|
||||
&dh->h_wire,
|
||||
&dh->h_extensions,
|
||||
&dh->h_policy,
|
||||
&dh->dcd.h_contract_terms,
|
||||
dh->exchange_timestamp,
|
||||
dh->dcd.wire_deadline,
|
||||
@ -317,7 +317,7 @@ handle_deposit_finished (void *cls,
|
||||
TALER_exchange_online_deposit_confirmation_verify (
|
||||
&dh->dcd.h_contract_terms,
|
||||
&dh->h_wire,
|
||||
&dh->h_extensions,
|
||||
&dh->h_policy,
|
||||
dh->exchange_timestamp,
|
||||
dh->dcd.wire_deadline,
|
||||
dh->dcd.refund_deadline,
|
||||
@ -492,9 +492,9 @@ TALER_EXCHANGE_batch_deposit (
|
||||
* sizeof (*cdds));
|
||||
dh->num_cdds = num_cdds;
|
||||
dh->dcd = *dcd;
|
||||
if (NULL != dcd->extension_details)
|
||||
TALER_deposit_extension_hash (dcd->extension_details,
|
||||
&dh->h_extensions);
|
||||
if (NULL != dcd->policy_details)
|
||||
TALER_deposit_policy_hash (dcd->policy_details,
|
||||
&dh->h_policy);
|
||||
TALER_merchant_wire_signature_hash (dcd->merchant_payto_uri,
|
||||
&dcd->wire_salt,
|
||||
&dh->h_wire);
|
||||
@ -533,7 +533,7 @@ TALER_EXCHANGE_batch_deposit (
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TALER_EXCHANGE_verify_deposit_signature_ (dcd,
|
||||
&dh->h_extensions,
|
||||
&dh->h_policy,
|
||||
&dh->h_wire,
|
||||
cdd,
|
||||
dki))
|
||||
@ -586,8 +586,8 @@ TALER_EXCHANGE_batch_deposit (
|
||||
GNUNET_JSON_pack_array_steal ("coins",
|
||||
deposits),
|
||||
GNUNET_JSON_pack_allow_null (
|
||||
GNUNET_JSON_pack_object_steal ("extension_details",
|
||||
NULL)), /* FIXME #7270-Oec */
|
||||
GNUNET_JSON_pack_object_steal ("policy_details",
|
||||
dcd->policy_details)),
|
||||
GNUNET_JSON_pack_timestamp ("timestamp",
|
||||
dcd->timestamp),
|
||||
GNUNET_JSON_pack_data_auto ("merchant_pub",
|
||||
|
@ -844,7 +844,8 @@ help_deposit (struct CoinHistoryParseContext *pc,
|
||||
{
|
||||
struct TALER_MerchantWireHashP h_wire;
|
||||
struct TALER_PrivateContractHashP h_contract_terms;
|
||||
// struct TALER_ExtensionContractHashP h_extensions; // FIXME #7270!
|
||||
struct TALER_ExtensionPolicyHashP h_policy;
|
||||
bool no_h_policy;
|
||||
struct GNUNET_TIME_Timestamp wallet_timestamp;
|
||||
struct TALER_MerchantPublicKeyP merchant_pub;
|
||||
struct GNUNET_TIME_Timestamp refund_deadline = {0};
|
||||
@ -863,6 +864,10 @@ help_deposit (struct CoinHistoryParseContext *pc,
|
||||
GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
|
||||
&hac),
|
||||
&no_hac),
|
||||
GNUNET_JSON_spec_mark_optional (
|
||||
GNUNET_JSON_spec_fixed_auto ("h_policy",
|
||||
&h_policy),
|
||||
&no_h_policy),
|
||||
GNUNET_JSON_spec_timestamp ("timestamp",
|
||||
&wallet_timestamp),
|
||||
GNUNET_JSON_spec_mark_optional (
|
||||
@ -891,7 +896,7 @@ help_deposit (struct CoinHistoryParseContext *pc,
|
||||
&h_wire,
|
||||
&h_contract_terms,
|
||||
no_hac ? NULL : &hac,
|
||||
NULL /* h_extensions! */,
|
||||
no_h_policy ? NULL : &h_policy,
|
||||
&pc->dk->h_key,
|
||||
wallet_timestamp,
|
||||
&merchant_pub,
|
||||
@ -2143,7 +2148,7 @@ TALER_EXCHANGE_get_min_denomination_ (
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_EXCHANGE_verify_deposit_signature_ (
|
||||
const struct TALER_EXCHANGE_DepositContractDetail *dcd,
|
||||
const struct TALER_ExtensionContractHashP *ech,
|
||||
const struct TALER_ExtensionPolicyHashP *ech,
|
||||
const struct TALER_MerchantWireHashP *h_wire,
|
||||
const struct TALER_EXCHANGE_CoinDepositDetail *cdd,
|
||||
const struct TALER_EXCHANGE_DenomPublicKey *dki)
|
||||
|
@ -203,7 +203,7 @@ TALER_EXCHANGE_get_min_denomination_ (
|
||||
* Verify signature information about the deposit.
|
||||
*
|
||||
* @param dcd contract details
|
||||
* @param ech hashed contract (passed to avoid recomputation)
|
||||
* @param ech hashed policy (passed to avoid recomputation)
|
||||
* @param h_wire hashed wire details (passed to avoid recomputation)
|
||||
* @param cdd coin-specific details
|
||||
* @param dki denomination of the coin
|
||||
@ -212,7 +212,7 @@ TALER_EXCHANGE_get_min_denomination_ (
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_EXCHANGE_verify_deposit_signature_ (
|
||||
const struct TALER_EXCHANGE_DepositContractDetail *dcd,
|
||||
const struct TALER_ExtensionContractHashP *ech,
|
||||
const struct TALER_ExtensionPolicyHashP *ech,
|
||||
const struct TALER_MerchantWireHashP *h_wire,
|
||||
const struct TALER_EXCHANGE_CoinDepositDetail *cdd,
|
||||
const struct TALER_EXCHANGE_DenomPublicKey *dki);
|
||||
|
@ -97,9 +97,9 @@ struct TALER_EXCHANGE_DepositHandle
|
||||
struct TALER_MerchantWireHashP h_wire;
|
||||
|
||||
/**
|
||||
* Hash over the extensions, or all zero.
|
||||
* Hash over the policy extension, or all zero.
|
||||
*/
|
||||
struct TALER_ExtensionContractHashP h_extensions;
|
||||
struct TALER_ExtensionPolicyHashP h_policy;
|
||||
|
||||
/**
|
||||
* Time when this confirmation was generated / when the exchange received
|
||||
@ -177,7 +177,7 @@ auditor_cb (void *cls,
|
||||
aie->dch = TALER_AUDITOR_deposit_confirmation (
|
||||
ah,
|
||||
&dh->h_wire,
|
||||
&dh->h_extensions,
|
||||
&dh->h_policy,
|
||||
&dh->dcd.h_contract_terms,
|
||||
dh->exchange_timestamp,
|
||||
dh->dcd.wire_deadline,
|
||||
@ -277,7 +277,7 @@ handle_deposit_finished (void *cls,
|
||||
TALER_exchange_online_deposit_confirmation_verify (
|
||||
&dh->dcd.h_contract_terms,
|
||||
&dh->h_wire,
|
||||
&dh->h_extensions,
|
||||
&dh->h_policy,
|
||||
dh->exchange_timestamp,
|
||||
dh->dcd.wire_deadline,
|
||||
dh->dcd.refund_deadline,
|
||||
@ -446,15 +446,15 @@ TALER_EXCHANGE_deposit (
|
||||
dh->cb_cls = cb_cls;
|
||||
dh->cdd = *cdd;
|
||||
dh->dcd = *dcd;
|
||||
if (NULL != dcd->extension_details)
|
||||
TALER_deposit_extension_hash (dcd->extension_details,
|
||||
&dh->h_extensions);
|
||||
if (NULL != dcd->policy_details)
|
||||
TALER_deposit_policy_hash (dcd->policy_details,
|
||||
&dh->h_policy);
|
||||
TALER_merchant_wire_signature_hash (dcd->merchant_payto_uri,
|
||||
&dcd->wire_salt,
|
||||
&dh->h_wire);
|
||||
if (GNUNET_OK !=
|
||||
TALER_EXCHANGE_verify_deposit_signature_ (dcd,
|
||||
&dh->h_extensions,
|
||||
&dh->h_policy,
|
||||
&dh->h_wire,
|
||||
cdd,
|
||||
dki))
|
||||
|
@ -898,17 +898,20 @@ decode_keys_json (const json_t *resp_obj,
|
||||
/* TODO: maybe lift all this into a FP in TALER_Extension ? */
|
||||
{
|
||||
struct TALER_MasterSignatureP extensions_sig = {0};
|
||||
json_t *extensions = NULL;
|
||||
json_t *manifests = NULL;
|
||||
bool no_extensions = false;
|
||||
bool no_signature = false;
|
||||
|
||||
struct GNUNET_JSON_Specification ext_spec[] = {
|
||||
GNUNET_JSON_spec_mark_optional (
|
||||
GNUNET_JSON_spec_json ("extensions",
|
||||
&extensions),
|
||||
NULL),
|
||||
&manifests),
|
||||
&no_extensions),
|
||||
GNUNET_JSON_spec_mark_optional (
|
||||
GNUNET_JSON_spec_fixed_auto (
|
||||
"extensions_sig",
|
||||
&extensions_sig),
|
||||
NULL),
|
||||
&no_signature),
|
||||
GNUNET_JSON_spec_end ()
|
||||
};
|
||||
|
||||
@ -918,22 +921,27 @@ decode_keys_json (const json_t *resp_obj,
|
||||
ext_spec,
|
||||
NULL, NULL));
|
||||
|
||||
if (NULL != extensions)
|
||||
|
||||
if (! no_extensions && no_signature)
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
"found extensions without signature\n");
|
||||
|
||||
if (! no_extensions && ! no_signature)
|
||||
{
|
||||
/* 2. We have an extensions object. Verify its signature. */
|
||||
EXITIF (GNUNET_OK !=
|
||||
TALER_extensions_verify_json_config_signature (
|
||||
extensions,
|
||||
TALER_extensions_verify_manifests_signature (
|
||||
manifests,
|
||||
&extensions_sig,
|
||||
&key_data->master_pub));
|
||||
|
||||
/* 3. Parse and set the the configuration of the extensions accordingly */
|
||||
EXITIF (GNUNET_OK !=
|
||||
TALER_extensions_load_json_config (extensions));
|
||||
TALER_extensions_load_manifests (manifests));
|
||||
}
|
||||
|
||||
/* 4. assuming we might have now a new value for age_mask, set it in key_data */
|
||||
key_data->age_mask = TALER_extensions_age_restriction_ageMask ();
|
||||
key_data->age_mask = TALER_extensions_get_age_restriction_mask ();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -236,7 +236,8 @@ verify_conflict_history_ok (struct TALER_EXCHANGE_RefundHandle *rh,
|
||||
struct TALER_PrivateContractHashP h_contract_terms;
|
||||
struct TALER_AgeCommitmentHash h_age_commitment;
|
||||
bool no_hac;
|
||||
// struct TALER_ExtensionContractHashP h_extensions; // FIXME #7270!
|
||||
struct TALER_ExtensionPolicyHashP h_policy;
|
||||
bool no_h_policy;
|
||||
struct GNUNET_TIME_Timestamp wallet_timestamp;
|
||||
struct TALER_MerchantPublicKeyP merchant_pub;
|
||||
struct GNUNET_TIME_Timestamp refund_deadline;
|
||||
@ -252,6 +253,10 @@ verify_conflict_history_ok (struct TALER_EXCHANGE_RefundHandle *rh,
|
||||
GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
|
||||
&h_age_commitment),
|
||||
&no_hac),
|
||||
GNUNET_JSON_spec_mark_optional (
|
||||
GNUNET_JSON_spec_fixed_auto ("h_policy",
|
||||
&h_policy),
|
||||
&no_h_policy),
|
||||
GNUNET_JSON_spec_timestamp ("timestamp",
|
||||
&wallet_timestamp),
|
||||
GNUNET_JSON_spec_timestamp ("refund_deadline",
|
||||
@ -277,10 +282,8 @@ verify_conflict_history_ok (struct TALER_EXCHANGE_RefundHandle *rh,
|
||||
&deposit_fee,
|
||||
&h_wire,
|
||||
&h_contract_terms,
|
||||
no_hac
|
||||
? NULL
|
||||
: &h_age_commitment,
|
||||
NULL /* FIXME #7270-OEC: h_extensions! */,
|
||||
no_hac ? NULL : &h_age_commitment,
|
||||
no_h_policy ? NULL: &h_policy,
|
||||
&h_denom_pub,
|
||||
wallet_timestamp,
|
||||
&merchant_pub,
|
||||
|
@ -1312,9 +1312,6 @@ main (int argc,
|
||||
"INFO",
|
||||
NULL);
|
||||
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_extension_age_restriction_register ());
|
||||
|
||||
cipher = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
|
||||
GNUNET_assert (NULL != cipher);
|
||||
uses_cs = (0 == strcmp (cipher, "cs"));
|
||||
|
@ -522,9 +522,6 @@ main (int argc,
|
||||
"INFO",
|
||||
NULL);
|
||||
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_extension_age_restriction_register ());
|
||||
|
||||
cipher = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
|
||||
GNUNET_assert (NULL != cipher);
|
||||
uses_cs = (0 == strcmp (cipher, "cs"));
|
||||
|
@ -199,7 +199,7 @@ deposit_confirmation_run (void *cls,
|
||||
const struct TALER_TESTING_Command *cmd,
|
||||
struct TALER_TESTING_Interpreter *is)
|
||||
{
|
||||
static struct TALER_ExtensionContractHashP no_h_extensions;
|
||||
static struct TALER_ExtensionPolicyHashP no_h_policy;
|
||||
struct DepositConfirmationState *dcs = cls;
|
||||
const struct TALER_TESTING_Command *deposit_cmd;
|
||||
struct TALER_MerchantWireHashP h_wire;
|
||||
@ -310,7 +310,7 @@ deposit_confirmation_run (void *cls,
|
||||
}
|
||||
dcs->dc = TALER_AUDITOR_deposit_confirmation (dcs->auditor,
|
||||
&h_wire,
|
||||
&no_h_extensions,
|
||||
&no_h_policy,
|
||||
&h_contract_terms,
|
||||
*exchange_timestamp,
|
||||
*wire_deadline,
|
||||
|
@ -381,7 +381,7 @@ batch_deposit_run (void *cls,
|
||||
.merchant_payto_uri = payto_uri,
|
||||
.wire_salt = wire_salt,
|
||||
.h_contract_terms = h_contract_terms,
|
||||
.extension_details = NULL /* FIXME #7270-OEC */,
|
||||
.policy_details = NULL /* FIXME #7270-OEC */,
|
||||
.timestamp = ds->wallet_timestamp,
|
||||
.merchant_pub = merchant_pub,
|
||||
.refund_deadline = ds->refund_deadline
|
||||
|
@ -490,7 +490,7 @@ TALER_TESTING_cmd_batch_withdraw (const char *label,
|
||||
|
||||
acp = GNUNET_new (struct TALER_AgeCommitmentProof);
|
||||
hac = GNUNET_new (struct TALER_AgeCommitmentHash);
|
||||
mask = TALER_extensions_age_restriction_ageMask ();
|
||||
mask = TALER_extensions_get_age_restriction_mask ();
|
||||
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
|
||||
&seed,
|
||||
sizeof(seed));
|
||||
|
@ -468,7 +468,7 @@ deposit_run (void *cls,
|
||||
.merchant_payto_uri = payto_uri,
|
||||
.wire_salt = wire_salt,
|
||||
.h_contract_terms = h_contract_terms,
|
||||
.extension_details = NULL /* FIXME #7270-OEC */,
|
||||
.policy_details = NULL /* FIXME #7270-OEC */,
|
||||
.timestamp = ds->wallet_timestamp,
|
||||
.merchant_pub = merchant_pub,
|
||||
.refund_deadline = ds->refund_deadline
|
||||
|
@ -590,7 +590,7 @@ TALER_TESTING_cmd_withdraw_amount (const char *label,
|
||||
|
||||
acp = GNUNET_new (struct TALER_AgeCommitmentProof);
|
||||
hac = GNUNET_new (struct TALER_AgeCommitmentHash);
|
||||
mask = TALER_extensions_age_restriction_ageMask ();
|
||||
mask = TALER_extensions_get_age_restriction_mask ();
|
||||
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
|
||||
&seed,
|
||||
sizeof(seed));
|
||||
|
@ -314,8 +314,13 @@ sign_keys_for_exchange (void *cls,
|
||||
char *exchange_master_pub;
|
||||
int ret;
|
||||
|
||||
/* Load the age restriction mask from the configuration */
|
||||
TALER_extensions_load_taler_config (cfg);
|
||||
/* Load the extensions */
|
||||
if (GNUNET_OK != TALER_extensions_init (cfg))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"couldn't load extensions");
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CONFIGURATION_get_value_string (cfg,
|
||||
|
@ -105,6 +105,7 @@ libtalerutil_la_SOURCES = \
|
||||
|
||||
libtalerutil_la_LIBADD = \
|
||||
-lgnunetutil \
|
||||
-lgnunetjson \
|
||||
-lsodium \
|
||||
-ljansson \
|
||||
$(LIBGCRYPT_LIBS) \
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "platform.h"
|
||||
#include "taler_util.h"
|
||||
#include "taler_signatures.h"
|
||||
#include <gnunet/gnunet_json_lib.h>
|
||||
#include <gcrypt.h>
|
||||
|
||||
void
|
||||
@ -436,3 +437,113 @@ TALER_age_commitment_proof_free (
|
||||
cp->commitment.keys = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_JSON_parse_age_groups (const json_t *root,
|
||||
struct TALER_AgeMask *mask)
|
||||
{
|
||||
enum GNUNET_GenericReturnValue ret;
|
||||
const char *str;
|
||||
struct GNUNET_JSON_Specification spec[] = {
|
||||
GNUNET_JSON_spec_string ("age_groups",
|
||||
&str),
|
||||
GNUNET_JSON_spec_end ()
|
||||
};
|
||||
|
||||
ret = GNUNET_JSON_parse (root,
|
||||
spec,
|
||||
NULL,
|
||||
NULL);
|
||||
if (GNUNET_OK == ret)
|
||||
TALER_parse_age_group_string (str, mask);
|
||||
|
||||
GNUNET_JSON_parse_free (spec);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_parse_age_group_string (
|
||||
const char *groups,
|
||||
struct TALER_AgeMask *mask)
|
||||
{
|
||||
|
||||
const char *pos = groups;
|
||||
unsigned int prev = 0;
|
||||
unsigned int val = 0;
|
||||
char c;
|
||||
|
||||
while (*pos)
|
||||
{
|
||||
c = *pos++;
|
||||
if (':' == c)
|
||||
{
|
||||
if (prev >= val)
|
||||
return GNUNET_SYSERR;
|
||||
|
||||
mask->bits |= 1 << val;
|
||||
prev = val;
|
||||
val = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ('0'>c || '9'<c)
|
||||
return GNUNET_SYSERR;
|
||||
|
||||
val = 10 * val + c - '0';
|
||||
|
||||
if (0>=val || 32<=val)
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
if (32<=val || prev>=val)
|
||||
return GNUNET_SYSERR;
|
||||
|
||||
mask->bits |= (1 << val);
|
||||
mask->bits |= 1; // mark zeroth group, too
|
||||
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
TALER_age_mask_to_string (
|
||||
const struct TALER_AgeMask *mask)
|
||||
{
|
||||
uint32_t bits = mask->bits;
|
||||
unsigned int n = 0;
|
||||
char *buf = GNUNET_malloc (32 * 3); // max characters possible
|
||||
char *pos = buf;
|
||||
|
||||
if (NULL == buf)
|
||||
{
|
||||
return buf;
|
||||
}
|
||||
|
||||
while (bits != 0)
|
||||
{
|
||||
bits >>= 1;
|
||||
n++;
|
||||
if (0 == (bits & 1))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (n > 9)
|
||||
{
|
||||
*(pos++) = '0' + n / 10;
|
||||
}
|
||||
*(pos++) = '0' + n % 10;
|
||||
|
||||
if (0 != (bits >> 1))
|
||||
{
|
||||
*(pos++) = ':';
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
/* end util/age_restriction.c */
|
||||
|
@ -48,10 +48,10 @@ struct TALER_DepositConfirmationPS
|
||||
struct TALER_MerchantWireHashP h_wire GNUNET_PACKED;
|
||||
|
||||
/**
|
||||
* Hash over the extension options of the deposit, 0 if there
|
||||
* were not extension options.
|
||||
* Hash over the optional policy extension of the deposit, 0 if there
|
||||
* was no policy.
|
||||
*/
|
||||
struct TALER_ExtensionContractHashP h_extensions GNUNET_PACKED;
|
||||
struct TALER_ExtensionPolicyHashP h_policy GNUNET_PACKED;
|
||||
|
||||
/**
|
||||
* Time when this confirmation was generated / when the exchange received
|
||||
@ -101,7 +101,7 @@ TALER_exchange_online_deposit_confirmation_sign (
|
||||
TALER_ExchangeSignCallback scb,
|
||||
const struct TALER_PrivateContractHashP *h_contract_terms,
|
||||
const struct TALER_MerchantWireHashP *h_wire,
|
||||
const struct TALER_ExtensionContractHashP *h_extensions,
|
||||
const struct TALER_ExtensionPolicyHashP *h_policy,
|
||||
struct GNUNET_TIME_Timestamp exchange_timestamp,
|
||||
struct GNUNET_TIME_Timestamp wire_deadline,
|
||||
struct GNUNET_TIME_Timestamp refund_deadline,
|
||||
@ -123,8 +123,8 @@ TALER_exchange_online_deposit_confirmation_sign (
|
||||
.merchant_pub = *merchant_pub
|
||||
};
|
||||
|
||||
if (NULL != h_extensions)
|
||||
dcs.h_extensions = *h_extensions;
|
||||
if (NULL != h_policy)
|
||||
dcs.h_policy = *h_policy;
|
||||
TALER_amount_hton (&dcs.amount_without_fee,
|
||||
amount_without_fee);
|
||||
return scb (&dcs.purpose,
|
||||
@ -137,7 +137,7 @@ enum GNUNET_GenericReturnValue
|
||||
TALER_exchange_online_deposit_confirmation_verify (
|
||||
const struct TALER_PrivateContractHashP *h_contract_terms,
|
||||
const struct TALER_MerchantWireHashP *h_wire,
|
||||
const struct TALER_ExtensionContractHashP *h_extensions,
|
||||
const struct TALER_ExtensionPolicyHashP *h_policy,
|
||||
struct GNUNET_TIME_Timestamp exchange_timestamp,
|
||||
struct GNUNET_TIME_Timestamp wire_deadline,
|
||||
struct GNUNET_TIME_Timestamp refund_deadline,
|
||||
@ -159,8 +159,8 @@ TALER_exchange_online_deposit_confirmation_verify (
|
||||
.merchant_pub = *merchant_pub
|
||||
};
|
||||
|
||||
if (NULL != h_extensions)
|
||||
dcs.h_extensions = *h_extensions;
|
||||
if (NULL != h_policy)
|
||||
dcs.h_policy = *h_policy;
|
||||
TALER_amount_hton (&dcs.amount_without_fee,
|
||||
amount_without_fee);
|
||||
if (GNUNET_OK !=
|
||||
|
@ -926,10 +926,10 @@ TALER_exchange_offline_global_fee_verify (
|
||||
GNUNET_NETWORK_STRUCT_BEGIN
|
||||
|
||||
/**
|
||||
* @brief Signature made by the exchange offline key over the
|
||||
* configuration of an extension.
|
||||
* @brief Signature made by the exchange offline key over the manifest of
|
||||
* an extension.
|
||||
*/
|
||||
struct TALER_MasterExtensionConfigurationPS
|
||||
struct TALER_MasterExtensionManifestPS
|
||||
{
|
||||
/**
|
||||
* Purpose is #TALER_SIGNATURE_MASTER_EXTENSION. Signed
|
||||
@ -938,24 +938,24 @@ struct TALER_MasterExtensionConfigurationPS
|
||||
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
|
||||
|
||||
/**
|
||||
* Hash of the JSON object that represents the configuration of an extension.
|
||||
* Hash of the JSON object that represents the manifests of extensions.
|
||||
*/
|
||||
struct TALER_ExtensionConfigHashP h_config GNUNET_PACKED;
|
||||
struct TALER_ExtensionManifestsHashP h_manifest GNUNET_PACKED;
|
||||
};
|
||||
|
||||
GNUNET_NETWORK_STRUCT_END
|
||||
|
||||
|
||||
void
|
||||
TALER_exchange_offline_extension_config_hash_sign (
|
||||
const struct TALER_ExtensionConfigHashP *h_config,
|
||||
TALER_exchange_offline_extension_manifests_hash_sign (
|
||||
const struct TALER_ExtensionManifestsHashP *h_manifest,
|
||||
const struct TALER_MasterPrivateKeyP *master_priv,
|
||||
struct TALER_MasterSignatureP *master_sig)
|
||||
{
|
||||
struct TALER_MasterExtensionConfigurationPS ec = {
|
||||
struct TALER_MasterExtensionManifestPS ec = {
|
||||
.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_EXTENSION),
|
||||
.purpose.size = htonl (sizeof(ec)),
|
||||
.h_config = *h_config
|
||||
.h_manifest = *h_manifest
|
||||
};
|
||||
GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv,
|
||||
&ec,
|
||||
@ -964,16 +964,16 @@ TALER_exchange_offline_extension_config_hash_sign (
|
||||
|
||||
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_exchange_offline_extension_config_hash_verify (
|
||||
const struct TALER_ExtensionConfigHashP *h_config,
|
||||
TALER_exchange_offline_extension_manifests_hash_verify (
|
||||
const struct TALER_ExtensionManifestsHashP *h_manifest,
|
||||
const struct TALER_MasterPublicKeyP *master_pub,
|
||||
const struct TALER_MasterSignatureP *master_sig
|
||||
)
|
||||
{
|
||||
struct TALER_MasterExtensionConfigurationPS ec = {
|
||||
struct TALER_MasterExtensionManifestPS ec = {
|
||||
.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_EXTENSION),
|
||||
.purpose.size = htonl (sizeof(ec)),
|
||||
.h_config = *h_config
|
||||
.h_manifest = *h_manifest
|
||||
};
|
||||
|
||||
return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_EXTENSION,
|
||||
|
@ -49,9 +49,9 @@ struct TALER_DepositRequestPS
|
||||
struct TALER_AgeCommitmentHash h_age_commitment GNUNET_PACKED;
|
||||
|
||||
/**
|
||||
* Hash over extension attributes shared with the exchange.
|
||||
* Hash over optional policy extension attributes shared with the exchange.
|
||||
*/
|
||||
struct TALER_ExtensionContractHashP h_extensions GNUNET_PACKED;
|
||||
struct TALER_ExtensionPolicyHashP h_policy GNUNET_PACKED;
|
||||
|
||||
/**
|
||||
* Hash over the wiring information of the merchant.
|
||||
@ -120,7 +120,7 @@ TALER_wallet_deposit_sign (
|
||||
const struct TALER_MerchantWireHashP *h_wire,
|
||||
const struct TALER_PrivateContractHashP *h_contract_terms,
|
||||
const struct TALER_AgeCommitmentHash *h_age_commitment,
|
||||
const struct TALER_ExtensionContractHashP *h_extensions,
|
||||
const struct TALER_ExtensionPolicyHashP *h_policy,
|
||||
const struct TALER_DenominationHashP *h_denom_pub,
|
||||
const struct GNUNET_TIME_Timestamp wallet_timestamp,
|
||||
const struct TALER_MerchantPublicKeyP *merchant_pub,
|
||||
@ -141,8 +141,8 @@ TALER_wallet_deposit_sign (
|
||||
|
||||
if (NULL != h_age_commitment)
|
||||
dr.h_age_commitment = *h_age_commitment;
|
||||
if (NULL != h_extensions)
|
||||
dr.h_extensions = *h_extensions;
|
||||
if (NULL != h_policy)
|
||||
dr.h_policy = *h_policy;
|
||||
TALER_amount_hton (&dr.amount_with_fee,
|
||||
amount);
|
||||
TALER_amount_hton (&dr.deposit_fee,
|
||||
@ -160,7 +160,7 @@ TALER_wallet_deposit_verify (
|
||||
const struct TALER_MerchantWireHashP *h_wire,
|
||||
const struct TALER_PrivateContractHashP *h_contract_terms,
|
||||
const struct TALER_AgeCommitmentHash *h_age_commitment,
|
||||
const struct TALER_ExtensionContractHashP *h_extensions,
|
||||
const struct TALER_ExtensionPolicyHashP *h_policy,
|
||||
const struct TALER_DenominationHashP *h_denom_pub,
|
||||
struct GNUNET_TIME_Timestamp wallet_timestamp,
|
||||
const struct TALER_MerchantPublicKeyP *merchant_pub,
|
||||
@ -178,13 +178,13 @@ TALER_wallet_deposit_verify (
|
||||
.refund_deadline = GNUNET_TIME_timestamp_hton (refund_deadline),
|
||||
.merchant = *merchant_pub,
|
||||
.h_age_commitment = {{{0}}},
|
||||
.h_extensions = {{{0}}}
|
||||
.h_policy = {{{0}}}
|
||||
};
|
||||
|
||||
if (NULL != h_age_commitment)
|
||||
dr.h_age_commitment = *h_age_commitment;
|
||||
if (NULL != h_extensions)
|
||||
dr.h_extensions = *h_extensions;
|
||||
if (NULL != h_policy)
|
||||
dr.h_policy = *h_policy;
|
||||
TALER_amount_hton (&dr.amount_with_fee,
|
||||
amount);
|
||||
TALER_amount_hton (&dr.deposit_fee,
|
||||
|
Loading…
Reference in New Issue
Block a user