breaking protocol changes towards fixing #7810 (incomplete, taler-exchange-offline still unfinished)

This commit is contained in:
Christian Grothoff 2023-04-30 16:21:07 +02:00
parent 5ee567d1ba
commit 75f75c4a51
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
91 changed files with 2077 additions and 1302 deletions

@ -1 +1 @@
Subproject commit bd4e73b2ed06269fdee42eaad21acb5be8be9302 Subproject commit 5cfe18c5bbfd404a5f7cf27a78577c881ddb9ebd

View File

@ -1483,10 +1483,10 @@ history_debit_cb (void *cls,
switch (dhr->http_status) switch (dhr->http_status)
{ {
case MHD_HTTP_OK: case MHD_HTTP_OK:
for (unsigned int i = 0; i<dhr->details.success.details_length; i++) for (unsigned int i = 0; i<dhr->details.ok.details_length; i++)
{ {
const struct TALER_BANK_DebitDetails *dd const struct TALER_BANK_DebitDetails *dd
= &dhr->details.success.details[i]; = &dhr->details.ok.details[i];
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Analyzing bank DEBIT at %s of %s with WTID %s\n", "Analyzing bank DEBIT at %s of %s with WTID %s\n",
GNUNET_TIME_timestamp2s (dd->execution_date), GNUNET_TIME_timestamp2s (dd->execution_date),
@ -1978,10 +1978,10 @@ history_credit_cb (void *cls,
switch (chr->http_status) switch (chr->http_status)
{ {
case MHD_HTTP_OK: case MHD_HTTP_OK:
for (unsigned int i = 0; i<chr->details.success.details_length; i++) for (unsigned int i = 0; i<chr->details.ok.details_length; i++)
{ {
const struct TALER_BANK_CreditDetails *cd const struct TALER_BANK_CreditDetails *cd
= &chr->details.success.details[i]; = &chr->details.ok.details[i];
if (! analyze_credit (wa, if (! analyze_credit (wa,
cd)) cd))

View File

@ -131,8 +131,8 @@ parse_account_history (struct TALER_BANK_CreditHistoryHandle *hh,
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
} }
chr.details.success.details_length = len; chr.details.ok.details_length = len;
chr.details.success.details = cd; chr.details.ok.details = cd;
hh->hcb (hh->hcb_cls, hh->hcb (hh->hcb_cls,
&chr); &chr);
} }

View File

@ -133,8 +133,8 @@ parse_account_history (struct TALER_BANK_DebitHistoryHandle *hh,
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
} }
dhr.details.success.details_length = len; dhr.details.ok.details_length = len;
dhr.details.success.details = dd; dhr.details.ok.details = dd;
hh->hcb (hh->hcb_cls, hh->hcb (hh->hcb_cls,
&dhr); &dhr);
} }

View File

@ -179,10 +179,10 @@ credit_history_cb (void *cls,
global_ret = 0; global_ret = 0;
break; break;
case MHD_HTTP_OK: case MHD_HTTP_OK:
for (unsigned int i = 0; i<reply->details.success.details_length; i++) for (unsigned int i = 0; i<reply->details.ok.details_length; i++)
{ {
const struct TALER_BANK_CreditDetails *cd = const struct TALER_BANK_CreditDetails *cd =
&reply->details.success.details[i]; &reply->details.ok.details[i];
/* If credit/debit accounts were specified, use as a filter */ /* If credit/debit accounts were specified, use as a filter */
if ( (NULL != credit_account) && if ( (NULL != credit_account) &&
@ -279,10 +279,10 @@ debit_history_cb (void *cls,
global_ret = 0; global_ret = 0;
break; break;
case MHD_HTTP_OK: case MHD_HTTP_OK:
for (unsigned int i = 0; i<reply->details.success.details_length; i++) for (unsigned int i = 0; i<reply->details.ok.details_length; i++)
{ {
const struct TALER_BANK_DebitDetails *dd = const struct TALER_BANK_DebitDetails *dd =
&reply->details.success.details[i]; &reply->details.ok.details[i];
/* If credit/debit accounts were specified, use as a filter */ /* If credit/debit accounts were specified, use as a filter */
if ( (NULL != credit_account) && if ( (NULL != credit_account) &&

View File

@ -644,26 +644,19 @@ do_upload (char *const *args)
* a particular exchange and what keys the exchange is using. * a particular exchange and what keys the exchange is using.
* *
* @param cls closure with the `char **` remaining args * @param cls closure with the `char **` remaining args
* @param hr HTTP response data * @param kr response data
* @param keys information about the various keys used
* by the exchange, NULL if /keys failed
* @param compat protocol compatibility information
*/ */
static void static void
keys_cb ( keys_cb (
void *cls, void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr, const struct TALER_EXCHANGE_KeysResponse *kr)
const struct TALER_EXCHANGE_Keys *keys,
enum TALER_EXCHANGE_VersionCompatibility compat)
{ {
char *const *args = cls; char *const *args = cls;
(void) keys; switch (kr->hr.http_status)
(void) compat;
switch (hr->http_status)
{ {
case MHD_HTTP_OK: case MHD_HTTP_OK:
if (! json_is_object (hr->reply)) if (! json_is_object (kr->hr.reply))
{ {
GNUNET_break (0); GNUNET_break (0);
TALER_EXCHANGE_disconnect (exchange); TALER_EXCHANGE_disconnect (exchange);
@ -676,9 +669,9 @@ keys_cb (
default: default:
fprintf (stderr, fprintf (stderr,
"Failed to download keys: %s (HTTP status: %u/%u)\n", "Failed to download keys: %s (HTTP status: %u/%u)\n",
hr->hint, kr->hr.hint,
hr->http_status, kr->hr.http_status,
(unsigned int) hr->ec); (unsigned int) kr->hr.ec);
TALER_EXCHANGE_disconnect (exchange); TALER_EXCHANGE_disconnect (exchange);
exchange = NULL; exchange = NULL;
test_shutdown (); test_shutdown ();
@ -689,7 +682,7 @@ keys_cb (
GNUNET_JSON_pack_string ("operation", GNUNET_JSON_pack_string ("operation",
OP_INPUT_KEYS), OP_INPUT_KEYS),
GNUNET_JSON_pack_object_incref ("arguments", GNUNET_JSON_pack_object_incref ("arguments",
(json_t *) hr->reply)); (json_t *) kr->hr.reply));
if (NULL == args[0]) if (NULL == args[0])
{ {
json_dumpf (in, json_dumpf (in,

View File

@ -1119,14 +1119,15 @@ load_offline_key (int do_create)
* Function called with information about the post revocation operation result. * Function called with information about the post revocation operation result.
* *
* @param cls closure with a `struct DenomRevocationRequest` * @param cls closure with a `struct DenomRevocationRequest`
* @param hr HTTP response data * @param dr response data
*/ */
static void static void
denom_revocation_cb ( denom_revocation_cb (
void *cls, void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr) const struct TALER_EXCHANGE_ManagementRevokeDenominationResponse *dr)
{ {
struct DenomRevocationRequest *drr = cls; struct DenomRevocationRequest *drr = cls;
const struct TALER_EXCHANGE_HttpResponse *hr = &dr->hr;
if (MHD_HTTP_NO_CONTENT != hr->http_status) if (MHD_HTTP_NO_CONTENT != hr->http_status)
{ {
@ -1208,14 +1209,15 @@ upload_denom_revocation (const char *exchange_url,
* Function called with information about the post revocation operation result. * Function called with information about the post revocation operation result.
* *
* @param cls closure with a `struct SignkeyRevocationRequest` * @param cls closure with a `struct SignkeyRevocationRequest`
* @param hr HTTP response data * @param sr response data
*/ */
static void static void
signkey_revocation_cb ( signkey_revocation_cb (
void *cls, void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr) const struct TALER_EXCHANGE_ManagementRevokeSigningKeyResponse *sr)
{ {
struct SignkeyRevocationRequest *srr = cls; struct SignkeyRevocationRequest *srr = cls;
const struct TALER_EXCHANGE_HttpResponse *hr = &sr->hr;
if (MHD_HTTP_NO_CONTENT != hr->http_status) if (MHD_HTTP_NO_CONTENT != hr->http_status)
{ {
@ -1489,13 +1491,14 @@ upload_auditor_del (const char *exchange_url,
* Function called with information about the post wire add operation result. * Function called with information about the post wire add operation result.
* *
* @param cls closure with a `struct WireAddRequest` * @param cls closure with a `struct WireAddRequest`
* @param hr HTTP response data * @param wer response data
*/ */
static void static void
wire_add_cb (void *cls, wire_add_cb (void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr) const struct TALER_EXCHANGE_ManagementWireEnableResponse *wer)
{ {
struct WireAddRequest *war = cls; struct WireAddRequest *war = cls;
const struct TALER_EXCHANGE_HttpResponse *hr = &wer->hr;
if (MHD_HTTP_NO_CONTENT != hr->http_status) if (MHD_HTTP_NO_CONTENT != hr->http_status)
{ {
@ -1533,10 +1536,21 @@ upload_wire_add (const char *exchange_url,
struct GNUNET_TIME_Timestamp start_time; struct GNUNET_TIME_Timestamp start_time;
struct WireAddRequest *war; struct WireAddRequest *war;
const char *err_name; const char *err_name;
const char *conversion_url = NULL;
json_t *debit_restrictions;
json_t *credit_restrictions;
unsigned int err_line; unsigned int err_line;
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_string ("payto_uri", GNUNET_JSON_spec_string ("payto_uri",
&payto_uri), &payto_uri),
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_string ("conversion_url",
&conversion_url),
NULL),
GNUNET_JSON_spec_json ("debit_restrictions",
&debit_restrictions),
GNUNET_JSON_spec_json ("credit_restrictions",
&credit_restrictions),
GNUNET_JSON_spec_timestamp ("validity_start", GNUNET_JSON_spec_timestamp ("validity_start",
&start_time), &start_time),
GNUNET_JSON_spec_fixed_auto ("master_sig_add", GNUNET_JSON_spec_fixed_auto ("master_sig_add",
@ -1561,6 +1575,7 @@ upload_wire_add (const char *exchange_url,
stderr, stderr,
JSON_INDENT (2)); JSON_INDENT (2));
global_ret = EXIT_FAILURE; global_ret = EXIT_FAILURE;
GNUNET_JSON_parse_free (spec);
test_shutdown (); test_shutdown ();
return; return;
} }
@ -1574,6 +1589,7 @@ upload_wire_add (const char *exchange_url,
"payto:// URI `%s' is malformed\n", "payto:// URI `%s' is malformed\n",
payto_uri); payto_uri);
global_ret = EXIT_FAILURE; global_ret = EXIT_FAILURE;
GNUNET_JSON_parse_free (spec);
test_shutdown (); test_shutdown ();
return; return;
} }
@ -1588,6 +1604,7 @@ upload_wire_add (const char *exchange_url,
"payto URI is malformed: %s\n", "payto URI is malformed: %s\n",
msg); msg);
GNUNET_free (msg); GNUNET_free (msg);
GNUNET_JSON_parse_free (spec);
test_shutdown (); test_shutdown ();
global_ret = EXIT_INVALIDARGUMENT; global_ret = EXIT_INVALIDARGUMENT;
return; return;
@ -1599,6 +1616,9 @@ upload_wire_add (const char *exchange_url,
TALER_EXCHANGE_management_enable_wire (ctx, TALER_EXCHANGE_management_enable_wire (ctx,
exchange_url, exchange_url,
payto_uri, payto_uri,
conversion_url,
debit_restrictions,
credit_restrictions,
start_time, start_time,
&master_sig_add, &master_sig_add,
&master_sig_wire, &master_sig_wire,
@ -1607,6 +1627,7 @@ upload_wire_add (const char *exchange_url,
GNUNET_CONTAINER_DLL_insert (war_head, GNUNET_CONTAINER_DLL_insert (war_head,
war_tail, war_tail,
war); war);
GNUNET_JSON_parse_free (spec);
} }
@ -1614,13 +1635,14 @@ upload_wire_add (const char *exchange_url,
* Function called with information about the post wire del operation result. * Function called with information about the post wire del operation result.
* *
* @param cls closure with a `struct WireDelRequest` * @param cls closure with a `struct WireDelRequest`
* @param hr HTTP response data * @param wdres response data
*/ */
static void static void
wire_del_cb (void *cls, wire_del_cb (void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr) const struct TALER_EXCHANGE_ManagementWireDisableResponse *wdres)
{ {
struct WireDelRequest *wdr = cls; struct WireDelRequest *wdr = cls;
const struct TALER_EXCHANGE_HttpResponse *hr = &wdres->hr;
if (MHD_HTTP_NO_CONTENT != hr->http_status) if (MHD_HTTP_NO_CONTENT != hr->http_status)
{ {
@ -1927,14 +1949,15 @@ upload_global_fee (const char *exchange_url,
* Function called with information about the drain profits operation. * Function called with information about the drain profits operation.
* *
* @param cls closure with a `struct DrainProfitsRequest` * @param cls closure with a `struct DrainProfitsRequest`
* @param hr HTTP response data * @param mdr response data
*/ */
static void static void
drain_profits_cb ( drain_profits_cb (
void *cls, void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr) const struct TALER_EXCHANGE_ManagementDrainResponse *mdr)
{ {
struct DrainProfitsRequest *dpr = cls; struct DrainProfitsRequest *dpr = cls;
const struct TALER_EXCHANGE_HttpResponse *hr = &mdr->hr;
if (MHD_HTTP_NO_CONTENT != hr->http_status) if (MHD_HTTP_NO_CONTENT != hr->http_status)
{ {
@ -2033,14 +2056,15 @@ upload_drain (const char *exchange_url,
* Function called with information about the post upload keys operation result. * Function called with information about the post upload keys operation result.
* *
* @param cls closure with a `struct UploadKeysRequest` * @param cls closure with a `struct UploadKeysRequest`
* @param hr HTTP response data * @param mr response data
*/ */
static void static void
keys_cb ( keys_cb (
void *cls, void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr) const struct TALER_EXCHANGE_ManagementPostKeysResponse *mr)
{ {
struct UploadKeysRequest *ukr = cls; struct UploadKeysRequest *ukr = cls;
const struct TALER_EXCHANGE_HttpResponse *hr = &mr->hr;
if (MHD_HTTP_NO_CONTENT != hr->http_status) if (MHD_HTTP_NO_CONTENT != hr->http_status)
{ {
@ -2206,14 +2230,15 @@ upload_keys (const char *exchange_url,
* Function called with information about the post upload extensions operation result. * Function called with information about the post upload extensions operation result.
* *
* @param cls closure with a `struct UploadExtensionsRequest` * @param cls closure with a `struct UploadExtensionsRequest`
* @param hr HTTP response data * @param er response data
*/ */
static void static void
extensions_cb ( extensions_cb (
void *cls, void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr) const struct TALER_EXCHANGE_ManagementPostExtensionsResponse *er)
{ {
struct UploadExtensionsRequest *uer = cls; struct UploadExtensionsRequest *uer = cls;
const struct TALER_EXCHANGE_HttpResponse *hr = &er->hr;
if (MHD_HTTP_NO_CONTENT != hr->http_status) if (MHD_HTTP_NO_CONTENT != hr->http_status)
{ {
@ -2447,14 +2472,15 @@ add_partner (const char *exchange_url,
* Function called with information about the AML officer update operation. * Function called with information about the AML officer update operation.
* *
* @param cls closure with a `struct AmlStaffRequest` * @param cls closure with a `struct AmlStaffRequest`
* @param hr HTTP response data * @param ar response data
*/ */
static void static void
update_aml_officer_cb ( update_aml_officer_cb (
void *cls, void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr) const struct TALER_EXCHANGE_ManagementUpdateAmlOfficerResponse *ar)
{ {
struct AmlStaffRequest *asr = cls; struct AmlStaffRequest *asr = cls;
const struct TALER_EXCHANGE_HttpResponse *hr = &ar->hr;
if (MHD_HTTP_NO_CONTENT != hr->http_status) if (MHD_HTTP_NO_CONTENT != hr->http_status)
{ {
@ -2961,6 +2987,10 @@ do_add_wire (char *const *args)
struct TALER_MasterSignatureP master_sig_add; struct TALER_MasterSignatureP master_sig_add;
struct TALER_MasterSignatureP master_sig_wire; struct TALER_MasterSignatureP master_sig_wire;
struct GNUNET_TIME_Timestamp now; struct GNUNET_TIME_Timestamp now;
const char *conversion_url = NULL;
json_t *debit_restrictions;
json_t *credit_restrictions;
unsigned int num_args = 1;
if (NULL != in) if (NULL != in)
{ {
@ -3011,24 +3041,43 @@ do_add_wire (char *const *args)
} }
GNUNET_free (wire_method); GNUNET_free (wire_method);
} }
// FIXME: init new args properly!
debit_restrictions = json_array ();
GNUNET_assert (NULL != debit_restrictions);
credit_restrictions = json_array ();
GNUNET_assert (NULL != credit_restrictions);
TALER_exchange_offline_wire_add_sign (args[0], TALER_exchange_offline_wire_add_sign (args[0],
conversion_url,
debit_restrictions,
credit_restrictions,
now, now,
&master_priv, &master_priv,
&master_sig_add); &master_sig_add);
TALER_exchange_wire_signature_make (args[0], TALER_exchange_wire_signature_make (args[0],
conversion_url,
debit_restrictions,
credit_restrictions,
&master_priv, &master_priv,
&master_sig_wire); &master_sig_wire);
output_operation (OP_ENABLE_WIRE, output_operation (OP_ENABLE_WIRE,
GNUNET_JSON_PACK ( GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("payto_uri", GNUNET_JSON_pack_string ("payto_uri",
args[0]), args[0]),
GNUNET_JSON_pack_array_steal ("debit_restrictions",
debit_restrictions),
GNUNET_JSON_pack_array_steal ("credit_restrictions",
credit_restrictions),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_string ("conversion_url",
conversion_url)),
GNUNET_JSON_pack_timestamp ("validity_start", GNUNET_JSON_pack_timestamp ("validity_start",
now), now),
GNUNET_JSON_pack_data_auto ("master_sig_add", GNUNET_JSON_pack_data_auto ("master_sig_add",
&master_sig_add), &master_sig_add),
GNUNET_JSON_pack_data_auto ("master_sig_wire", GNUNET_JSON_pack_data_auto ("master_sig_wire",
&master_sig_wire))); &master_sig_wire)));
next (args + 1); next (args + num_args);
} }
@ -3643,18 +3692,15 @@ enable_aml_staff (char *const *args)
* whether there are subsequent commands). * whether there are subsequent commands).
* *
* @param cls closure with the `char **` remaining args * @param cls closure with the `char **` remaining args
* @param hr HTTP response data * @param mgr response data
* @param keys information about the various keys used
* by the exchange, NULL if /management/keys failed
*/ */
static void static void
download_cb (void *cls, download_cb (void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr, const struct TALER_EXCHANGE_ManagementGetKeysResponse *mgr)
const struct TALER_EXCHANGE_FutureKeys *keys)
{ {
char *const *args = cls; char *const *args = cls;
const struct TALER_EXCHANGE_HttpResponse *hr = &mgr->hr;
(void) keys;
mgkh = NULL; mgkh = NULL;
switch (hr->http_status) switch (hr->http_status)
{ {

View File

@ -41,7 +41,7 @@
* *
* Returned via both /config and /keys endpoints. * Returned via both /config and /keys endpoints.
*/ */
#define EXCHANGE_PROTOCOL_VERSION "14:0:2" #define EXCHANGE_PROTOCOL_VERSION "15:0:0"
/** /**

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2020 Taler Systems SA Copyright (C) 2020-2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software terms of the GNU Affero General Public License as published by the Free Software
@ -114,6 +114,9 @@ del_wire (void *cls,
} }
qs = TEH_plugin->update_wire (TEH_plugin->cls, qs = TEH_plugin->update_wire (TEH_plugin->cls,
awc->payto_uri, awc->payto_uri,
NULL,
NULL,
NULL,
awc->validity_end, awc->validity_end,
false); false);
if (qs < 0) if (qs < 0)

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2020 Taler Systems SA Copyright (C) 2020-2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software terms of the GNU Affero General Public License as published by the Free Software
@ -54,6 +54,21 @@ struct AddWireContext
*/ */
const char *payto_uri; const char *payto_uri;
/**
* (optional) address of a conversion service for this account.
*/
const char *conversion_url;
/**
* Restrictions imposed when crediting this account.
*/
json_t *credit_restrictions;
/**
* Restrictions imposed when debiting this account.
*/
json_t *debit_restrictions;
/** /**
* Timestamp for checking against replay attacks. * Timestamp for checking against replay attacks.
*/ */
@ -114,11 +129,17 @@ add_wire (void *cls,
if (0 == qs) if (0 == qs)
qs = TEH_plugin->insert_wire (TEH_plugin->cls, qs = TEH_plugin->insert_wire (TEH_plugin->cls,
awc->payto_uri, awc->payto_uri,
awc->conversion_url,
awc->debit_restrictions,
awc->credit_restrictions,
awc->validity_start, awc->validity_start,
&awc->master_sig_wire); &awc->master_sig_wire);
else else
qs = TEH_plugin->update_wire (TEH_plugin->cls, qs = TEH_plugin->update_wire (TEH_plugin->cls,
awc->payto_uri, awc->payto_uri,
awc->conversion_url,
awc->debit_restrictions,
awc->credit_restrictions,
awc->validity_start, awc->validity_start,
true); true);
if (qs < 0) if (qs < 0)
@ -141,7 +162,9 @@ TEH_handler_management_post_wire (
struct MHD_Connection *connection, struct MHD_Connection *connection,
const json_t *root) const json_t *root)
{ {
struct AddWireContext awc; struct AddWireContext awc = {
.conversion_url = NULL
};
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("master_sig_wire", GNUNET_JSON_spec_fixed_auto ("master_sig_wire",
&awc.master_sig_wire), &awc.master_sig_wire),
@ -149,6 +172,14 @@ TEH_handler_management_post_wire (
&awc.master_sig_add), &awc.master_sig_add),
GNUNET_JSON_spec_string ("payto_uri", GNUNET_JSON_spec_string ("payto_uri",
&awc.payto_uri), &awc.payto_uri),
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_string ("conversion_url",
&awc.conversion_url),
NULL),
GNUNET_JSON_spec_json ("credit_restrictions",
&awc.credit_restrictions),
GNUNET_JSON_spec_json ("debit_restrictions",
&awc.debit_restrictions),
GNUNET_JSON_spec_timestamp ("validity_start", GNUNET_JSON_spec_timestamp ("validity_start",
&awc.validity_start), &awc.validity_start),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
@ -179,17 +210,22 @@ TEH_handler_management_post_wire (
MHD_HTTP_BAD_REQUEST, MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PAYTO_URI_MALFORMED, TALER_EC_GENERIC_PAYTO_URI_MALFORMED,
msg); msg);
GNUNET_JSON_parse_free (spec);
GNUNET_free (msg); GNUNET_free (msg);
return ret; return ret;
} }
} }
if (GNUNET_OK != if (GNUNET_OK !=
TALER_exchange_offline_wire_add_verify (awc.payto_uri, TALER_exchange_offline_wire_add_verify (awc.payto_uri,
awc.conversion_url,
awc.debit_restrictions,
awc.credit_restrictions,
awc.validity_start, awc.validity_start,
&TEH_master_public_key, &TEH_master_public_key,
&awc.master_sig_add)) &awc.master_sig_add))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return TALER_MHD_reply_with_error ( return TALER_MHD_reply_with_error (
connection, connection,
MHD_HTTP_FORBIDDEN, MHD_HTTP_FORBIDDEN,
@ -199,10 +235,14 @@ TEH_handler_management_post_wire (
TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++; TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
if (GNUNET_OK != if (GNUNET_OK !=
TALER_exchange_wire_signature_check (awc.payto_uri, TALER_exchange_wire_signature_check (awc.payto_uri,
awc.conversion_url,
awc.debit_restrictions,
awc.credit_restrictions,
&TEH_master_public_key, &TEH_master_public_key,
&awc.master_sig_wire)) &awc.master_sig_wire))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return TALER_MHD_reply_with_error ( return TALER_MHD_reply_with_error (
connection, connection,
MHD_HTTP_FORBIDDEN, MHD_HTTP_FORBIDDEN,
@ -218,6 +258,7 @@ TEH_handler_management_post_wire (
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"payto:// URI `%s' is malformed\n", "payto:// URI `%s' is malformed\n",
awc.payto_uri); awc.payto_uri);
GNUNET_JSON_parse_free (spec);
return TALER_MHD_reply_with_error ( return TALER_MHD_reply_with_error (
connection, connection,
MHD_HTTP_BAD_REQUEST, MHD_HTTP_BAD_REQUEST,
@ -237,6 +278,7 @@ TEH_handler_management_post_wire (
&ret, &ret,
&add_wire, &add_wire,
&awc); &awc);
GNUNET_JSON_parse_free (spec);
if (GNUNET_SYSERR == res) if (GNUNET_SYSERR == res)
return ret; return ret;
} }

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2015-2022 Taler Systems SA Copyright (C) 2015-2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software terms of the GNU Affero General Public License as published by the Free Software
@ -224,12 +224,18 @@ TEH_wire_done ()
* *
* @param cls a `json_t *` object to expand with wire account details * @param cls a `json_t *` object to expand with wire account details
* @param payto_uri the exchange bank account URI to add * @param payto_uri the exchange bank account URI to add
* @param conversion_url URL of a conversion service, NULL if there is no conversion
* @param debit_restrictions JSON array with debit restrictions on the account
* @param credit_restrictions JSON array with credit restrictions on the account
* @param master_sig master key signature affirming that this is a bank * @param master_sig master key signature affirming that this is a bank
* account of the exchange (of purpose #TALER_SIGNATURE_MASTER_WIRE_DETAILS) * account of the exchange (of purpose #TALER_SIGNATURE_MASTER_WIRE_DETAILS)
*/ */
static void static void
add_wire_account (void *cls, add_wire_account (void *cls,
const char *payto_uri, const char *payto_uri,
const char *conversion_url,
const json_t *debit_restrictions,
const json_t *credit_restrictions,
const struct TALER_MasterSignatureP *master_sig) const struct TALER_MasterSignatureP *master_sig)
{ {
json_t *a = cls; json_t *a = cls;
@ -240,6 +246,13 @@ add_wire_account (void *cls,
GNUNET_JSON_PACK ( GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("payto_uri", GNUNET_JSON_pack_string ("payto_uri",
payto_uri), payto_uri),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_string ("conversion_url",
conversion_url)),
GNUNET_JSON_pack_array_incref ("debit_restrictions",
(json_t *) debit_restrictions),
GNUNET_JSON_pack_array_incref ("credit_restrictions",
(json_t *) credit_restrictions),
GNUNET_JSON_pack_data_auto ("master_sig", GNUNET_JSON_pack_data_auto ("master_sig",
master_sig)))) master_sig))))
{ {
@ -462,6 +475,8 @@ build_wire_state (void)
wsh->wire_reply = TALER_MHD_MAKE_JSON_PACK ( wsh->wire_reply = TALER_MHD_MAKE_JSON_PACK (
GNUNET_JSON_pack_array_steal ("accounts", GNUNET_JSON_pack_array_steal ("accounts",
wire_accounts_array), wire_accounts_array),
GNUNET_JSON_pack_array_steal ("wads", /* #7271 */
json_array ()),
GNUNET_JSON_pack_object_steal ("fees", GNUNET_JSON_pack_object_steal ("fees",
wire_fee_object), wire_fee_object),
GNUNET_JSON_pack_data_auto ("master_public_key", GNUNET_JSON_pack_data_auto ("master_public_key",

View File

@ -731,8 +731,8 @@ history_cb (void *cls,
{ {
case MHD_HTTP_OK: case MHD_HTTP_OK:
process_reply (wrap_size, process_reply (wrap_size,
reply->details.success.details, reply->details.ok.details,
reply->details.success.details_length); reply->details.ok.details_length);
return; return;
case MHD_HTTP_NO_CONTENT: case MHD_HTTP_NO_CONTENT:
transaction_completed (); transaction_completed ();

View File

@ -12,4 +12,5 @@ test-exchangedb-batch-reserves-in-insert-postgres
test-exchangedb-by-j-postgres test-exchangedb-by-j-postgres
test-exchangedb-populate-link-data-postgres test-exchangedb-populate-link-data-postgres
test-exchangedb-populate-ready-deposit-postgres test-exchangedb-populate-ready-deposit-postgres
test-exchangedb-populate-select-refunds-by-coin-postgres test-exchangedb-populate-select-refunds-by-coin-postgres
exchange-0004.sql

View File

@ -0,0 +1,26 @@
--
-- This file is part of TALER
-- Copyright (C) 2023 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/>
--
ALTER TABLE wire_accounts
ADD COLUMN conversion_url VARCHAR DEFAULT (NULL),
ADD COLUMN debit_restrictions VARCHAR DEFAULT (NULL),
ADD COLUMN credit_restrictions VARCHAR DEFAULT (NULL);
COMMENT ON COLUMN wire_accounts.conversion_url
IS 'URL of a currency conversion service if conversion is needed when this account is used; NULL if there is no conversion.';
COMMENT ON COLUMN wire_accounts.debit_restrictions
IS 'JSON array describing restrictions imposed when debiting this account. Empty for no restrictions, NULL if account was migrated from previous database revision or account is disabled.';
COMMENT ON COLUMN wire_accounts.credit_restrictions
IS 'JSON array describing restrictions imposed when crediting this account. Empty for no restrictions, NULL if account was migrated from previous database revision or account is disabled.';

View File

@ -20,7 +20,9 @@ sqlinputs = \
0002-*.sql \ 0002-*.sql \
exchange-0002.sql.in \ exchange-0002.sql.in \
0003-*.sql \ 0003-*.sql \
exchange-0003.sql.in exchange-0003.sql.in \
0004-*.sql \
exchange-0004.sql.in
sql_DATA = \ sql_DATA = \
benchmark-0001.sql \ benchmark-0001.sql \
@ -28,6 +30,7 @@ sql_DATA = \
exchange-0001.sql \ exchange-0001.sql \
exchange-0002.sql \ exchange-0002.sql \
exchange-0003.sql \ exchange-0003.sql \
exchange-0004.sql \
drop.sql \ drop.sql \
procedures.sql procedures.sql
@ -39,7 +42,8 @@ BUILT_SOURCES = \
CLEANFILES = \ CLEANFILES = \
exchange-0002.sql \ exchange-0002.sql \
exchange-0003.sql exchange-0003.sql \
exchange-0004.sql
procedures.sql: procedures.sql.in exchange_do_*.sql procedures.sql: procedures.sql.in exchange_do_*.sql
chmod +w $@ || true chmod +w $@ || true
@ -56,6 +60,11 @@ exchange-0003.sql: exchange-0003.sql.in 0003-*.sql
gcc -E -P -undef - < exchange-0003.sql.in 2>/dev/null | sed -e "s/--.*//" | awk 'NF' - >$@ gcc -E -P -undef - < exchange-0003.sql.in 2>/dev/null | sed -e "s/--.*//" | awk 'NF' - >$@
chmod ugo-w $@ chmod ugo-w $@
exchange-0004.sql: exchange-0004.sql.in 0004-*.sql
chmod +w $@ || true
gcc -E -P -undef - < exchange-0004.sql.in 2>/dev/null | sed -e "s/--.*//" | awk 'NF' - >$@
chmod ugo-w $@
EXTRA_DIST = \ EXTRA_DIST = \
exchangedb.conf \ exchangedb.conf \
exchangedb-postgres.conf \ exchangedb-postgres.conf \

View File

@ -21,6 +21,7 @@ BEGIN;
SELECT _v.unregister_patch('exchange-0001'); SELECT _v.unregister_patch('exchange-0001');
SELECT _v.unregister_patch('exchange-0002'); SELECT _v.unregister_patch('exchange-0002');
SELECT _v.unregister_patch('exchange-0003'); SELECT _v.unregister_patch('exchange-0003');
SELECT _v.unregister_patch('exchange-0004');
DROP SCHEMA exchange CASCADE; DROP SCHEMA exchange CASCADE;

View File

@ -0,0 +1,24 @@
--
-- This file is part of TALER
-- Copyright (C) 2014--2023 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/>
--
BEGIN;
SELECT _v.register_patch('exchange-0004', NULL, NULL);
SET search_path TO exchange;
#include "0004-wire_accounts.sql"
COMMIT;

View File

@ -66,10 +66,25 @@ get_wire_accounts_cb (void *cls,
for (unsigned int i = 0; i < num_results; i++) for (unsigned int i = 0; i < num_results; i++)
{ {
char *payto_uri; char *payto_uri;
char *conversion_url = NULL;
json_t *debit_restrictions = NULL;
json_t *credit_restrictions = NULL;
struct TALER_MasterSignatureP master_sig; struct TALER_MasterSignatureP master_sig;
struct GNUNET_PQ_ResultSpec rs[] = { struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_string ("payto_uri", GNUNET_PQ_result_spec_string ("payto_uri",
&payto_uri), &payto_uri),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_string ("conversion_url",
&conversion_url),
NULL),
GNUNET_PQ_result_spec_allow_null (
TALER_PQ_result_spec_json ("debit_restrictions",
&debit_restrictions),
NULL),
GNUNET_PQ_result_spec_allow_null (
TALER_PQ_result_spec_json ("credit_restrictions",
&credit_restrictions),
NULL),
GNUNET_PQ_result_spec_auto_from_type ("master_sig", GNUNET_PQ_result_spec_auto_from_type ("master_sig",
&master_sig), &master_sig),
GNUNET_PQ_result_spec_end GNUNET_PQ_result_spec_end
@ -84,8 +99,21 @@ get_wire_accounts_cb (void *cls,
ctx->status = GNUNET_SYSERR; ctx->status = GNUNET_SYSERR;
return; return;
} }
if (NULL == debit_restrictions)
{
debit_restrictions = json_array ();
GNUNET_assert (NULL != debit_restrictions);
}
if (NULL == credit_restrictions)
{
credit_restrictions = json_array ();
GNUNET_assert (NULL != credit_restrictions);
}
ctx->cb (ctx->cb_cls, ctx->cb (ctx->cb_cls,
payto_uri, payto_uri,
conversion_url,
debit_restrictions,
credit_restrictions,
&master_sig); &master_sig);
GNUNET_PQ_cleanup_result (rs); GNUNET_PQ_cleanup_result (rs);
} }
@ -112,6 +140,9 @@ TEH_PG_get_wire_accounts (void *cls,
"get_wire_accounts", "get_wire_accounts",
"SELECT" "SELECT"
" payto_uri" " payto_uri"
",conversion_url"
",debit_restrictions"
",credit_restrictions"
",master_sig" ",master_sig"
" FROM wire_accounts" " FROM wire_accounts"
" WHERE is_active"); " WHERE is_active");
@ -123,5 +154,4 @@ TEH_PG_get_wire_accounts (void *cls,
if (GNUNET_OK != ctx.status) if (GNUNET_OK != ctx.status)
return GNUNET_DB_STATUS_HARD_ERROR; return GNUNET_DB_STATUS_HARD_ERROR;
return qs; return qs;
} }

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2022 Taler Systems SA Copyright (C) 2022, 2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the 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 terms of the GNU General Public License as published by the Free Software
@ -29,12 +29,20 @@
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_insert_wire (void *cls, TEH_PG_insert_wire (void *cls,
const char *payto_uri, const char *payto_uri,
const char *conversion_url,
json_t *debit_restrictions,
json_t *credit_restrictions,
struct GNUNET_TIME_Timestamp start_date, struct GNUNET_TIME_Timestamp start_date,
const struct TALER_MasterSignatureP *master_sig) const struct TALER_MasterSignatureP *master_sig)
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = { struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_string (payto_uri), GNUNET_PQ_query_param_string (payto_uri),
NULL == conversion_url
? GNUNET_PQ_query_param_null ()
: GNUNET_PQ_query_param_string (conversion_url),
TALER_PQ_query_param_json (debit_restrictions),
TALER_PQ_query_param_json (credit_restrictions),
GNUNET_PQ_query_param_auto_from_type (master_sig), GNUNET_PQ_query_param_auto_from_type (master_sig),
GNUNET_PQ_query_param_timestamp (&start_date), GNUNET_PQ_query_param_timestamp (&start_date),
GNUNET_PQ_query_param_end GNUNET_PQ_query_param_end
@ -44,11 +52,14 @@ TEH_PG_insert_wire (void *cls,
"insert_wire", "insert_wire",
"INSERT INTO wire_accounts " "INSERT INTO wire_accounts "
"(payto_uri" "(payto_uri"
",conversion_url"
",debit_restrictions"
",credit_restrictions"
",master_sig" ",master_sig"
",is_active" ",is_active"
",last_change" ",last_change"
") VALUES " ") VALUES "
"($1, $2, true, $3);"); "($1, $2, $3, $4, $5, true, $6);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn, return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_wire", "insert_wire",
params); params);

View File

@ -29,6 +29,9 @@
* *
* @param cls closure * @param cls closure
* @param payto_uri wire account of the exchange * @param payto_uri wire account of the exchange
* @param conversion_url URL of a conversion service, NULL if there is no conversion
* @param debit_restrictions JSON array with debit restrictions on the account
* @param credit_restrictions JSON array with credit restrictions on the account
* @param start_date date when the account was added by the offline system * @param start_date date when the account was added by the offline system
* (only to be used for replay detection) * (only to be used for replay detection)
* @param master_sig public signature affirming the existence of the account, * @param master_sig public signature affirming the existence of the account,
@ -38,6 +41,9 @@
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_insert_wire (void *cls, TEH_PG_insert_wire (void *cls,
const char *payto_uri, const char *payto_uri,
const char *conversion_url,
json_t *debit_restrictions,
json_t *credit_restrictions,
struct GNUNET_TIME_Timestamp start_date, struct GNUNET_TIME_Timestamp start_date,
const struct TALER_MasterSignatureP *master_sig); const struct TALER_MasterSignatureP *master_sig);

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2022 Taler Systems SA Copyright (C) 2022, 2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the 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 terms of the GNU General Public License as published by the Free Software
@ -29,6 +29,9 @@
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_update_wire (void *cls, TEH_PG_update_wire (void *cls,
const char *payto_uri, const char *payto_uri,
const char *conversion_url,
json_t *debit_restrictions,
json_t *credit_restrictions,
struct GNUNET_TIME_Timestamp change_date, struct GNUNET_TIME_Timestamp change_date,
bool enabled) bool enabled)
{ {
@ -36,17 +39,28 @@ TEH_PG_update_wire (void *cls,
struct GNUNET_PQ_QueryParam params[] = { struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_string (payto_uri), GNUNET_PQ_query_param_string (payto_uri),
GNUNET_PQ_query_param_bool (enabled), GNUNET_PQ_query_param_bool (enabled),
NULL == conversion_url
? GNUNET_PQ_query_param_null ()
: GNUNET_PQ_query_param_string (conversion_url),
enabled
? TALER_PQ_query_param_json (debit_restrictions)
: GNUNET_PQ_query_param_null (),
enabled
? TALER_PQ_query_param_json (credit_restrictions)
: GNUNET_PQ_query_param_null (),
GNUNET_PQ_query_param_timestamp (&change_date), GNUNET_PQ_query_param_timestamp (&change_date),
GNUNET_PQ_query_param_end GNUNET_PQ_query_param_end
}; };
/* used in #postgres_update_wire() */
PREPARE (pg, PREPARE (pg,
"update_wire", "update_wire",
"UPDATE wire_accounts" "UPDATE wire_accounts"
" SET" " SET"
" is_active=$2" " is_active=$2"
" ,last_change=$3" " ,conversion_url=$3"
" ,debit_restrictions=$4"
" ,credit_restrictions=$5"
" ,last_change=$6"
" WHERE payto_uri=$1"); " WHERE payto_uri=$1");
return GNUNET_PQ_eval_prepared_non_select (pg->conn, return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"update_wire", "update_wire",

View File

@ -24,11 +24,16 @@
#include "taler_util.h" #include "taler_util.h"
#include "taler_json_lib.h" #include "taler_json_lib.h"
#include "taler_exchangedb_plugin.h" #include "taler_exchangedb_plugin.h"
/** /**
* Update information about a wire account of the exchange. * Update information about a wire account of the exchange.
* *
* @param cls closure * @param cls closure
* @param payto_uri account the update is about * @param payto_uri account the update is about
* @param conversion_url URL of a conversion service, NULL if there is no conversion
* @param debit_restrictions JSON array with debit restrictions on the account; NULL allowed if not @a enabled
* @param credit_restrictions JSON array with credit restrictions on the account; NULL allowed if not @a enabled
* @param change_date date when the account status was last changed * @param change_date date when the account status was last changed
* (only to be used for replay detection) * (only to be used for replay detection)
* @param enabled true to enable, false to disable (the actual change) * @param enabled true to enable, false to disable (the actual change)
@ -37,6 +42,9 @@
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_update_wire (void *cls, TEH_PG_update_wire (void *cls,
const char *payto_uri, const char *payto_uri,
const char *conversion_url,
json_t *debit_restrictions,
json_t *credit_restrictions,
struct GNUNET_TIME_Timestamp change_date, struct GNUNET_TIME_Timestamp change_date,
bool enabled); bool enabled);

View File

@ -111,6 +111,7 @@ struct TALER_BANK_AdminAddIncomingHandle;
* @param timestamp time when the transaction was made. * @param timestamp time when the transaction was made.
* @param json detailed response from the HTTPD, or NULL if reply was not in JSON * @param json detailed response from the HTTPD, or NULL if reply was not in JSON
*/ */
// FIXME: bad API
typedef void typedef void
(*TALER_BANK_AdminAddIncomingCallback) ( (*TALER_BANK_AdminAddIncomingCallback) (
void *cls, void *cls,
@ -199,6 +200,7 @@ struct TALER_BANK_TransferHandle;
* @param row_id unique ID of the wire transfer in the bank's records * @param row_id unique ID of the wire transfer in the bank's records
* @param timestamp when did the transaction go into effect * @param timestamp when did the transaction go into effect
*/ */
// FIXME: bad API
typedef void typedef void
(*TALER_BANK_TransferCallback)( (*TALER_BANK_TransferCallback)(
void *cls, void *cls,
@ -337,7 +339,7 @@ struct TALER_BANK_CreditHistoryResponse
*/ */
unsigned int details_length; unsigned int details_length;
} success; } ok;
} details; } details;
@ -493,7 +495,7 @@ struct TALER_BANK_DebitHistoryResponse
*/ */
unsigned int details_length; unsigned int details_length;
} success; } ok;
} details; } details;

View File

@ -5512,6 +5512,9 @@ TALER_exchange_offline_global_fee_verify (
* Create wire account addition signature. * Create wire account addition signature.
* *
* @param payto_uri bank account * @param payto_uri bank account
* @param conversion_url URL of the conversion service, or NULL if none
* @param debit_restrictions JSON encoding of debit restrictions on the account; see AccountRestriction in the spec
* @param credit_restrictions JSON encoding of credit restrictions on the account; see AccountRestriction in the spec
* @param now timestamp to use for the signature (rounded) * @param now timestamp to use for the signature (rounded)
* @param master_priv private key to sign with * @param master_priv private key to sign with
* @param[out] master_sig where to write the signature * @param[out] master_sig where to write the signature
@ -5519,6 +5522,9 @@ TALER_exchange_offline_global_fee_verify (
void void
TALER_exchange_offline_wire_add_sign ( TALER_exchange_offline_wire_add_sign (
const char *payto_uri, const char *payto_uri,
const char *conversion_url,
const json_t *debit_restrictions,
const json_t *credit_restrictions,
struct GNUNET_TIME_Timestamp now, struct GNUNET_TIME_Timestamp now,
const struct TALER_MasterPrivateKeyP *master_priv, const struct TALER_MasterPrivateKeyP *master_priv,
struct TALER_MasterSignatureP *master_sig); struct TALER_MasterSignatureP *master_sig);
@ -5528,6 +5534,9 @@ TALER_exchange_offline_wire_add_sign (
* Verify wire account addition signature. * Verify wire account addition signature.
* *
* @param payto_uri bank account * @param payto_uri bank account
* @param conversion_url URL of the conversion service, or NULL if none
* @param debit_restrictions JSON encoding of debit restrictions on the account; see AccountRestriction in the spec
* @param credit_restrictions JSON encoding of credit restrictions on the account; see AccountRestriction in the spec
* @param sign_time timestamp when signature was created * @param sign_time timestamp when signature was created
* @param master_pub public key to verify against * @param master_pub public key to verify against
* @param master_sig the signature the signature * @param master_sig the signature the signature
@ -5536,6 +5545,9 @@ TALER_exchange_offline_wire_add_sign (
enum GNUNET_GenericReturnValue enum GNUNET_GenericReturnValue
TALER_exchange_offline_wire_add_verify ( TALER_exchange_offline_wire_add_verify (
const char *payto_uri, const char *payto_uri,
const char *conversion_url,
const json_t *debit_restrictions,
const json_t *credit_restrictions,
struct GNUNET_TIME_Timestamp sign_time, struct GNUNET_TIME_Timestamp sign_time,
const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterPublicKeyP *master_pub,
const struct TALER_MasterSignatureP *master_sig); const struct TALER_MasterSignatureP *master_sig);
@ -5578,6 +5590,9 @@ TALER_exchange_offline_wire_del_verify (
* Check the signature in @a master_sig. * Check the signature in @a master_sig.
* *
* @param payto_uri URI that is signed * @param payto_uri URI that is signed
* @param conversion_url URL of the conversion service, or NULL if none
* @param debit_restrictions JSON encoding of debit restrictions on the account; see AccountRestriction in the spec
* @param credit_restrictions JSON encoding of credit restrictions on the account; see AccountRestriction in the spec
* @param master_pub master public key of the exchange * @param master_pub master public key of the exchange
* @param master_sig signature of the exchange * @param master_sig signature of the exchange
* @return #GNUNET_OK if signature is valid * @return #GNUNET_OK if signature is valid
@ -5585,6 +5600,9 @@ TALER_exchange_offline_wire_del_verify (
enum GNUNET_GenericReturnValue enum GNUNET_GenericReturnValue
TALER_exchange_wire_signature_check ( TALER_exchange_wire_signature_check (
const char *payto_uri, const char *payto_uri,
const char *conversion_url,
const json_t *debit_restrictions,
const json_t *credit_restrictions,
const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterPublicKeyP *master_pub,
const struct TALER_MasterSignatureP *master_sig); const struct TALER_MasterSignatureP *master_sig);
@ -5593,12 +5611,18 @@ TALER_exchange_wire_signature_check (
* Create a signed wire statement for the given account. * Create a signed wire statement for the given account.
* *
* @param payto_uri account specification * @param payto_uri account specification
* @param conversion_url URL of the conversion service, or NULL if none
* @param debit_restrictions JSON encoding of debit restrictions on the account; see AccountRestriction in the spec
* @param credit_restrictions JSON encoding of credit restrictions on the account; see AccountRestriction in the spec
* @param master_priv private key to sign with * @param master_priv private key to sign with
* @param[out] master_sig where to write the signature * @param[out] master_sig where to write the signature
*/ */
void void
TALER_exchange_wire_signature_make ( TALER_exchange_wire_signature_make (
const char *payto_uri, const char *payto_uri,
const char *conversion_url,
const json_t *debit_restrictions,
const json_t *credit_restrictions,
const struct TALER_MasterPrivateKeyP *master_priv, const struct TALER_MasterPrivateKeyP *master_priv,
struct TALER_MasterSignatureP *master_sig); struct TALER_MasterSignatureP *master_sig);

File diff suppressed because it is too large Load Diff

View File

@ -2881,6 +2881,9 @@ typedef enum GNUNET_GenericReturnValue
* *
* @param cls closure * @param cls closure
* @param payto_uri the exchange bank account URI * @param payto_uri the exchange bank account URI
* @param conversion_url URL of a conversion service, NULL if there is no conversion
* @param debit_restrictions JSON array with debit restrictions on the account
* @param credit_restrictions JSON array with credit restrictions on the account
* @param master_sig master key signature affirming that this is a bank * @param master_sig master key signature affirming that this is a bank
* account of the exchange (of purpose #TALER_SIGNATURE_MASTER_WIRE_DETAILS) * account of the exchange (of purpose #TALER_SIGNATURE_MASTER_WIRE_DETAILS)
*/ */
@ -2888,6 +2891,9 @@ typedef void
(*TALER_EXCHANGEDB_WireAccountCallback)( (*TALER_EXCHANGEDB_WireAccountCallback)(
void *cls, void *cls,
const char *payto_uri, const char *payto_uri,
const char *conversion_url,
const json_t *debit_restrictions,
const json_t *credit_restrictions,
const struct TALER_MasterSignatureP *master_sig); const struct TALER_MasterSignatureP *master_sig);
@ -5544,6 +5550,9 @@ struct TALER_EXCHANGEDB_Plugin
* *
* @param cls closure * @param cls closure
* @param payto_uri wire account of the exchange * @param payto_uri wire account of the exchange
* @param conversion_url URL of a conversion service, NULL if there is no conversion
* @param debit_restrictions JSON array with debit restrictions on the account
* @param credit_restrictions JSON array with credit restrictions on the account
* @param start_date date when the account was added by the offline system * @param start_date date when the account was added by the offline system
* (only to be used for replay detection) * (only to be used for replay detection)
* @param master_sig public signature affirming the existence of the account, * @param master_sig public signature affirming the existence of the account,
@ -5553,6 +5562,9 @@ struct TALER_EXCHANGEDB_Plugin
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
(*insert_wire)(void *cls, (*insert_wire)(void *cls,
const char *payto_uri, const char *payto_uri,
const char *conversion_url,
json_t *debit_restrictions,
json_t *credit_restrictions,
struct GNUNET_TIME_Timestamp start_date, struct GNUNET_TIME_Timestamp start_date,
const struct TALER_MasterSignatureP *master_sig); const struct TALER_MasterSignatureP *master_sig);
@ -5562,6 +5574,9 @@ struct TALER_EXCHANGEDB_Plugin
* *
* @param cls closure * @param cls closure
* @param payto_uri account the update is about * @param payto_uri account the update is about
* @param conversion_url URL of a conversion service, NULL if there is no conversion
* @param debit_restrictions JSON array with debit restrictions on the account; NULL allowed if not @a enabled
* @param credit_restrictions JSON array with credit restrictions on the account; NULL allowed if not @a enabled
* @param change_date date when the account status was last changed * @param change_date date when the account status was last changed
* (only to be used for replay detection) * (only to be used for replay detection)
* @param enabled true to enable, false to disable (the actual change) * @param enabled true to enable, false to disable (the actual change)
@ -5570,6 +5585,9 @@ struct TALER_EXCHANGEDB_Plugin
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
(*update_wire)(void *cls, (*update_wire)(void *cls,
const char *payto_uri, const char *payto_uri,
const char *conversion_url,
json_t *debit_restrictions,
json_t *credit_restrictions,
struct GNUNET_TIME_Timestamp change_date, struct GNUNET_TIME_Timestamp change_date,
bool enabled); bool enabled);

View File

@ -674,33 +674,6 @@ TALER_JSON_merchant_wire_signature_hash (const json_t *wire_s,
struct TALER_MerchantWireHashP *hc); struct TALER_MerchantWireHashP *hc);
/**
* Check the signature in @a wire_s. Also performs rudimentary
* checks on the account data *if* supported.
*
* @param wire_s signed wire information of an exchange
* @param master_pub master public key of the exchange
* @return #GNUNET_OK if signature is valid
*/
enum GNUNET_GenericReturnValue
TALER_JSON_exchange_wire_signature_check (
const json_t *wire_s,
const struct TALER_MasterPublicKeyP *master_pub);
/**
* Create a signed wire statement for the given account.
*
* @param payto_uri account specification
* @param master_priv private key to sign with
* @return NULL if @a payto_uri is malformed
*/
json_t *
TALER_JSON_exchange_wire_signature_make (
const char *payto_uri,
const struct TALER_MasterPrivateKeyP *master_priv);
/** /**
* Extract a string from @a object under the field @a field, but respecting * Extract a string from @a object under the field @a field, but respecting
* the Taler i18n rules and the language preferences expressed in @a * the Taler i18n rules and the language preferences expressed in @a

View File

@ -147,15 +147,11 @@ TALER_TESTING_prepare_exchange (const char *config_filename,
* *
* @param cls closure, typically, the "run" method containing * @param cls closure, typically, the "run" method containing
* all the commands to be run, and a closure for it. * all the commands to be run, and a closure for it.
* @param hr http response details * @param kr response details
* @param keys the exchange's keys.
* @param compat protocol compatibility information.
*/ */
void void
TALER_TESTING_cert_cb (void *cls, TALER_TESTING_cert_cb (void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr, const struct TALER_EXCHANGE_KeysResponse *kr);
const struct TALER_EXCHANGE_Keys *keys,
enum TALER_EXCHANGE_VersionCompatibility compat);
/** /**

View File

@ -28,12 +28,10 @@ libtalerjson_la_LIBADD = \
$(XLIB) $(XLIB)
TESTS = \ TESTS = \
test_json \ test_json
test_json_wire
check_PROGRAMS= \ check_PROGRAMS= \
test_json \ test_json
test_json_wire
test_json_SOURCES = \ test_json_SOURCES = \
test_json.c test_json.c
@ -43,13 +41,3 @@ test_json_LDADD = \
$(top_builddir)/src/util/libtalerutil.la \ $(top_builddir)/src/util/libtalerutil.la \
-lgnunetutil \ -lgnunetutil \
-ljansson -ljansson
test_json_wire_SOURCES = \
test_json_wire.c
test_json_wire_LDADD = \
$(top_builddir)/src/json/libtalerjson.la \
-lgnunetjson \
$(top_builddir)/src/util/libtalerutil.la \
-lgnunetutil \
-ljansson

View File

@ -70,80 +70,6 @@ TALER_JSON_merchant_wire_signature_hash (const json_t *wire_s,
} }
enum GNUNET_GenericReturnValue
TALER_JSON_exchange_wire_signature_check (
const json_t *wire_s,
const struct TALER_MasterPublicKeyP *master_pub)
{
const char *payto_uri;
struct TALER_MasterSignatureP master_sig;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_string ("payto_uri",
&payto_uri),
GNUNET_JSON_spec_fixed_auto ("master_sig",
&master_sig),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (wire_s,
spec,
NULL, NULL))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
{
char *err;
err = TALER_payto_validate (payto_uri);
if (NULL != err)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"URI `%s' ill-formed: %s\n",
payto_uri,
err);
GNUNET_free (err);
return GNUNET_SYSERR;
}
}
return TALER_exchange_wire_signature_check (payto_uri,
master_pub,
&master_sig);
}
json_t *
TALER_JSON_exchange_wire_signature_make (
const char *payto_uri,
const struct TALER_MasterPrivateKeyP *master_priv)
{
struct TALER_MasterSignatureP master_sig;
char *err;
if (NULL !=
(err = TALER_payto_validate (payto_uri)))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Invalid payto URI `%s': %s\n",
payto_uri,
err);
GNUNET_free (err);
return NULL;
}
TALER_exchange_wire_signature_make (payto_uri,
master_priv,
&master_sig);
return GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("payto_uri",
payto_uri),
GNUNET_JSON_pack_data_auto ("master_sig",
&master_sig));
}
char * char *
TALER_JSON_wire_to_payto (const json_t *wire_s) TALER_JSON_wire_to_payto (const json_t *wire_s)
{ {

View File

@ -1,80 +0,0 @@
/*
This file is part of TALER
(C) 2015, 2016 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 json/test_json_wire.c
* @brief Tests for Taler-specific crypto logic
* @author Christian Grothoff <christian@grothoff.org>
*/
#include "platform.h"
#include "taler_util.h"
#include "taler_json_lib.h"
int
main (int argc,
const char *const argv[])
{
struct TALER_MasterPublicKeyP master_pub;
struct TALER_MasterPrivateKeyP master_priv;
json_t *wire_xtalerbank;
json_t *wire_iban;
const char *payto_xtalerbank = "payto://x-taler-bank/42";
const char *payto_iban =
"payto://iban/BIC-TO-BE-SKIPPED/DE89370400440532013000?receiver-name=Test";
char *p_xtalerbank;
char *p_iban;
(void) argc;
(void) argv;
GNUNET_log_setup ("test-json-wire",
"WARNING",
NULL);
GNUNET_CRYPTO_eddsa_key_create (&master_priv.eddsa_priv);
GNUNET_CRYPTO_eddsa_key_get_public (&master_priv.eddsa_priv,
&master_pub.eddsa_pub);
wire_xtalerbank = TALER_JSON_exchange_wire_signature_make (payto_xtalerbank,
&master_priv);
wire_iban = TALER_JSON_exchange_wire_signature_make (payto_iban,
&master_priv);
if (NULL == wire_iban)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Could not parse payto/IBAN (%s) into 'wire object'\n",
payto_iban);
return 1;
}
p_xtalerbank = TALER_JSON_wire_to_payto (wire_xtalerbank);
p_iban = TALER_JSON_wire_to_payto (wire_iban);
GNUNET_assert (0 == strcmp (p_xtalerbank, payto_xtalerbank));
GNUNET_assert (0 == strcmp (p_iban, payto_iban));
GNUNET_free (p_xtalerbank);
GNUNET_free (p_iban);
GNUNET_assert (GNUNET_OK ==
TALER_JSON_exchange_wire_signature_check (wire_xtalerbank,
&master_pub));
GNUNET_assert (GNUNET_OK ==
TALER_JSON_exchange_wire_signature_check (wire_iban,
&master_pub));
json_decref (wire_xtalerbank);
json_decref (wire_iban);
return 0;
}
/* end of test_json_wire.c */

View File

@ -247,7 +247,7 @@ handle_deposit_finished (void *cls,
&dh->exchange_pub), &dh->exchange_pub),
GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_string ("transaction_base_url", GNUNET_JSON_spec_string ("transaction_base_url",
&dr.details.success.transaction_base_url), &dr.details.ok.transaction_base_url),
NULL), NULL),
GNUNET_JSON_spec_timestamp ("exchange_timestamp", GNUNET_JSON_spec_timestamp ("exchange_timestamp",
&dh->exchange_timestamp), &dh->exchange_timestamp),
@ -332,7 +332,7 @@ handle_deposit_finished (void *cls,
GNUNET_break_op (0); GNUNET_break_op (0);
dr.hr.http_status = 0; dr.hr.http_status = 0;
dr.hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE; dr.hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE;
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
break; break;
} }
} }
@ -341,10 +341,10 @@ handle_deposit_finished (void *cls,
dh); dh);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
} }
dr.details.success.exchange_sigs = dh->exchange_sigs; dr.details.ok.exchange_sigs = dh->exchange_sigs;
dr.details.success.exchange_pub = &dh->exchange_pub; dr.details.ok.exchange_pub = &dh->exchange_pub;
dr.details.success.deposit_timestamp = dh->exchange_timestamp; dr.details.ok.deposit_timestamp = dh->exchange_timestamp;
dr.details.success.num_signatures = dh->num_cdds; dr.details.ok.num_signatures = dh->num_cdds;
break; break;
case MHD_HTTP_BAD_REQUEST: case MHD_HTTP_BAD_REQUEST:
/* This should never happen, either us or the exchange is buggy /* This should never happen, either us or the exchange is buggy

View File

@ -144,37 +144,34 @@ struct TALER_EXCHANGE_BatchWithdrawHandle
* HTTP /reserves/$RESERVE_PUB/batch-withdraw request. * HTTP /reserves/$RESERVE_PUB/batch-withdraw request.
* *
* @param cls the `struct TALER_EXCHANGE_BatchWithdrawHandle` * @param cls the `struct TALER_EXCHANGE_BatchWithdrawHandle`
* @param hr HTTP response data * @param bw2r response data
* @param blind_sigs array of blind signatures over the coins, NULL on error
* @param blind_sigs_length length of the @a blind_sigs array
*/ */
static void static void
handle_reserve_batch_withdraw_finished ( handle_reserve_batch_withdraw_finished (
void *cls, void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr, const struct TALER_EXCHANGE_BatchWithdraw2Response *bw2r)
const struct TALER_BlindedDenominationSignature *blind_sigs,
unsigned int blind_sigs_length)
{ {
struct TALER_EXCHANGE_BatchWithdrawHandle *wh = cls; struct TALER_EXCHANGE_BatchWithdrawHandle *wh = cls;
struct TALER_EXCHANGE_BatchWithdrawResponse wr = { struct TALER_EXCHANGE_BatchWithdrawResponse wr = {
.hr = *hr .hr = bw2r->hr
}; };
struct TALER_EXCHANGE_PrivateCoinDetails coins[wh->num_coins]; struct TALER_EXCHANGE_PrivateCoinDetails coins[GNUNET_NZL (wh->num_coins)];
wh->wh2 = NULL; wh->wh2 = NULL;
memset (coins, memset (coins,
0, 0,
sizeof (coins)); sizeof (coins));
if (blind_sigs_length != wh->num_coins) switch (bw2r->hr.http_status)
{
GNUNET_break_op (0);
wr.hr.http_status = 0;
wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
}
switch (hr->http_status)
{ {
case MHD_HTTP_OK: case MHD_HTTP_OK:
{ {
if (bw2r->details.ok.blind_sigs_length != wh->num_coins)
{
GNUNET_break_op (0);
wr.hr.http_status = 0;
wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
break;
}
for (unsigned int i = 0; i<wh->num_coins; i++) for (unsigned int i = 0; i<wh->num_coins; i++)
{ {
struct CoinData *cd = &wh->coins[i]; struct CoinData *cd = &wh->coins[i];
@ -183,7 +180,7 @@ handle_reserve_batch_withdraw_finished (
if (GNUNET_OK != if (GNUNET_OK !=
TALER_planchet_to_coin (&cd->pk.key, TALER_planchet_to_coin (&cd->pk.key,
&blind_sigs[i], &bw2r->details.ok.blind_sigs[i],
&cd->bks, &cd->bks,
&cd->priv, &cd->priv,
cd->ach, cd->ach,
@ -200,8 +197,8 @@ handle_reserve_batch_withdraw_finished (
coin->sig = fc.sig; coin->sig = fc.sig;
coin->exchange_vals = cd->alg_values; coin->exchange_vals = cd->alg_values;
} }
wr.details.success.coins = coins; wr.details.ok.coins = coins;
wr.details.success.num_coins = wh->num_coins; wr.details.ok.num_coins = wh->num_coins;
break; break;
} }
case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
@ -217,7 +214,7 @@ handle_reserve_batch_withdraw_finished (
}; };
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_JSON_parse (hr->reply, GNUNET_JSON_parse (bw2r->hr.reply,
spec, spec,
NULL, NULL)) NULL, NULL))
{ {
@ -289,7 +286,7 @@ withdraw_cs_stage_two_callback (
switch (csrr->hr.http_status) switch (csrr->hr.http_status)
{ {
case MHD_HTTP_OK: case MHD_HTTP_OK:
cd->alg_values = csrr->details.success.alg_values; cd->alg_values = csrr->details.ok.alg_values;
TALER_planchet_setup_coin_priv (&cd->ps, TALER_planchet_setup_coin_priv (&cd->ps,
&cd->alg_values, &cd->alg_values,
&cd->priv); &cd->priv);

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2014-2022 Taler Systems SA Copyright (C) 2014-2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the 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 terms of the GNU General Public License as published by the Free Software
@ -108,9 +108,9 @@ reserve_batch_withdraw_ok (struct TALER_EXCHANGE_BatchWithdraw2Handle *wh,
"ev_sigs"); "ev_sigs");
const json_t *j; const json_t *j;
unsigned int index; unsigned int index;
struct TALER_EXCHANGE_HttpResponse hr = { struct TALER_EXCHANGE_BatchWithdraw2Response bwr = {
.reply = json, .hr.reply = json,
.http_status = MHD_HTTP_OK .hr.http_status = MHD_HTTP_OK
}; };
if ( (NULL == ja) || if ( (NULL == ja) ||
@ -141,10 +141,10 @@ reserve_batch_withdraw_ok (struct TALER_EXCHANGE_BatchWithdraw2Handle *wh,
} }
/* signature is valid, return it to the application */ /* signature is valid, return it to the application */
bwr.details.ok.blind_sigs = blind_sigs;
bwr.details.ok.blind_sigs_length = wh->num_coins;
wh->cb (wh->cb_cls, wh->cb (wh->cb_cls,
&hr, &bwr);
blind_sigs,
wh->num_coins);
/* make sure callback isn't called again after return */ /* make sure callback isn't called again after return */
wh->cb = NULL; wh->cb = NULL;
for (unsigned int i = 0; i<wh->num_coins; i++) for (unsigned int i = 0; i<wh->num_coins; i++)
@ -264,16 +264,16 @@ handle_reserve_batch_withdraw_finished (void *cls,
{ {
struct TALER_EXCHANGE_BatchWithdraw2Handle *wh = cls; struct TALER_EXCHANGE_BatchWithdraw2Handle *wh = cls;
const json_t *j = response; const json_t *j = response;
struct TALER_EXCHANGE_HttpResponse hr = { struct TALER_EXCHANGE_BatchWithdraw2Response bwr = {
.reply = j, .hr.reply = j,
.http_status = (unsigned int) response_code .hr.http_status = (unsigned int) response_code
}; };
wh->job = NULL; wh->job = NULL;
switch (response_code) switch (response_code)
{ {
case 0: case 0:
hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; bwr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break; break;
case MHD_HTTP_OK: case MHD_HTTP_OK:
if (GNUNET_OK != if (GNUNET_OK !=
@ -281,8 +281,8 @@ handle_reserve_batch_withdraw_finished (void *cls,
j)) j))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
hr.http_status = 0; bwr.hr.http_status = 0;
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; bwr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
break; break;
} }
GNUNET_assert (NULL == wh->cb); GNUNET_assert (NULL == wh->cb);
@ -304,8 +304,8 @@ handle_reserve_batch_withdraw_finished (void *cls,
NULL, NULL)) NULL, NULL))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
hr.http_status = 0; bwr.hr.http_status = 0;
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; bwr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
break; break;
} }
} }
@ -313,24 +313,24 @@ handle_reserve_batch_withdraw_finished (void *cls,
case MHD_HTTP_BAD_REQUEST: case MHD_HTTP_BAD_REQUEST:
/* This should never happen, either us or the exchange is buggy /* This should never happen, either us or the exchange is buggy
(or API version conflict); just pass JSON reply to the application */ (or API version conflict); just pass JSON reply to the application */
hr.ec = TALER_JSON_get_error_code (j); bwr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); bwr.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
case MHD_HTTP_FORBIDDEN: case MHD_HTTP_FORBIDDEN:
GNUNET_break_op (0); GNUNET_break_op (0);
/* Nothing really to verify, exchange says one of the signatures is /* Nothing really to verify, exchange says one of the signatures is
invalid; as we checked them, this should never happen, we invalid; as we checked them, this should never happen, we
should pass the JSON reply to the application */ should pass the JSON reply to the application */
hr.ec = TALER_JSON_get_error_code (j); bwr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); bwr.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
case MHD_HTTP_NOT_FOUND: case MHD_HTTP_NOT_FOUND:
/* Nothing really to verify, the exchange basically just says /* Nothing really to verify, the exchange basically just says
that it doesn't know this reserve. Can happen if we that it doesn't know this reserve. Can happen if we
query before the wire transfer went through. query before the wire transfer went through.
We should simply pass the JSON reply to the application. */ We should simply pass the JSON reply to the application. */
hr.ec = TALER_JSON_get_error_code (j); bwr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); bwr.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
case MHD_HTTP_CONFLICT: case MHD_HTTP_CONFLICT:
/* The exchange says that the reserve has insufficient funds; /* The exchange says that the reserve has insufficient funds;
@ -340,13 +340,13 @@ handle_reserve_batch_withdraw_finished (void *cls,
j)) j))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
hr.http_status = 0; bwr.hr.http_status = 0;
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; bwr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
} }
else else
{ {
hr.ec = TALER_JSON_get_error_code (j); bwr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); bwr.hr.hint = TALER_JSON_get_error_hint (j);
} }
break; break;
case MHD_HTTP_GONE: case MHD_HTTP_GONE:
@ -354,32 +354,30 @@ handle_reserve_batch_withdraw_finished (void *cls,
/* Note: one might want to check /keys for revocation /* Note: one might want to check /keys for revocation
signature here, alas tricky in case our /keys signature here, alas tricky in case our /keys
is outdated => left to clients */ is outdated => left to clients */
hr.ec = TALER_JSON_get_error_code (j); bwr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); bwr.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
case MHD_HTTP_INTERNAL_SERVER_ERROR: case MHD_HTTP_INTERNAL_SERVER_ERROR:
/* Server had an internal issue; we should retry, but this API /* Server had an internal issue; we should retry, but this API
leaves this to the application */ leaves this to the application */
hr.ec = TALER_JSON_get_error_code (j); bwr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); bwr.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
default: default:
/* unexpected response code */ /* unexpected response code */
GNUNET_break_op (0); GNUNET_break_op (0);
hr.ec = TALER_JSON_get_error_code (j); bwr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); bwr.hr.hint = TALER_JSON_get_error_hint (j);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d for exchange batch withdraw\n", "Unexpected response code %u/%d for exchange batch withdraw\n",
(unsigned int) response_code, (unsigned int) response_code,
(int) hr.ec); (int) bwr.hr.ec);
break; break;
} }
if (NULL != wh->cb) if (NULL != wh->cb)
{ {
wh->cb (wh->cb_cls, wh->cb (wh->cb_cls,
&hr, &bwr);
NULL,
0);
wh->cb = NULL; wh->cb = NULL;
} }
TALER_EXCHANGE_batch_withdraw2_cancel (wh); TALER_EXCHANGE_batch_withdraw2_cancel (wh);

View File

@ -109,7 +109,7 @@ handle_contract_get_finished (void *cls,
struct TALER_PurseContractSignatureP econtract_sig; struct TALER_PurseContractSignatureP econtract_sig;
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("purse_pub", GNUNET_JSON_spec_fixed_auto ("purse_pub",
&dr.details.success.purse_pub), &dr.details.ok.purse_pub),
GNUNET_JSON_spec_fixed_auto ("econtract_sig", GNUNET_JSON_spec_fixed_auto ("econtract_sig",
&econtract_sig), &econtract_sig),
GNUNET_JSON_spec_varsize ("econtract", GNUNET_JSON_spec_varsize ("econtract",
@ -133,7 +133,7 @@ handle_contract_get_finished (void *cls,
econtract, econtract,
econtract_size, econtract_size,
&cgh->cpub, &cgh->cpub,
&dr.details.success.purse_pub, &dr.details.ok.purse_pub,
&econtract_sig)) &econtract_sig))
{ {
GNUNET_break (0); GNUNET_break (0);
@ -142,8 +142,8 @@ handle_contract_get_finished (void *cls,
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
break; break;
} }
dr.details.success.econtract = econtract; dr.details.ok.econtract = econtract;
dr.details.success.econtract_size = econtract_size; dr.details.ok.econtract_size = econtract_size;
cgh->cb (cgh->cb_cls, cgh->cb (cgh->cb_cls,
&dr); &dr);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);

View File

@ -94,8 +94,8 @@ csr_ok (struct TALER_EXCHANGE_CsRMeltHandle *csrh,
struct TALER_ExchangeWithdrawValues alg_values[GNUNET_NZL (alen)]; struct TALER_ExchangeWithdrawValues alg_values[GNUNET_NZL (alen)];
struct TALER_EXCHANGE_CsRMeltResponse csrr = { struct TALER_EXCHANGE_CsRMeltResponse csrr = {
.hr = *hr, .hr = *hr,
.details.success.alg_values_len = alen, .details.ok.alg_values_len = alen,
.details.success.alg_values = alg_values .details.ok.alg_values = alg_values
}; };
for (unsigned int i = 0; i<alen; i++) for (unsigned int i = 0; i<alen; i++)

View File

@ -96,7 +96,7 @@ csr_ok (struct TALER_EXCHANGE_CsRWithdrawHandle *csrh,
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
TALER_JSON_spec_exchange_withdraw_values ( TALER_JSON_spec_exchange_withdraw_values (
"ewv", "ewv",
&csrr.details.success.alg_values), &csrr.details.ok.alg_values),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
}; };

View File

@ -236,7 +236,7 @@ handle_deposit_finished (void *cls,
&dh->exchange_pub), &dh->exchange_pub),
GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_string ("transaction_base_url", GNUNET_JSON_spec_string ("transaction_base_url",
&dr.details.success.transaction_base_url), &dr.details.ok.transaction_base_url),
NULL), NULL),
GNUNET_JSON_spec_timestamp ("exchange_timestamp", GNUNET_JSON_spec_timestamp ("exchange_timestamp",
&dh->exchange_timestamp), &dh->exchange_timestamp),
@ -297,9 +297,9 @@ handle_deposit_finished (void *cls,
&auditor_cb, &auditor_cb,
dh); dh);
} }
dr.details.success.exchange_sig = &dh->exchange_sig; dr.details.ok.exchange_sig = &dh->exchange_sig;
dr.details.success.exchange_pub = &dh->exchange_pub; dr.details.ok.exchange_pub = &dh->exchange_pub;
dr.details.success.deposit_timestamp = dh->exchange_timestamp; dr.details.ok.deposit_timestamp = dh->exchange_timestamp;
break; break;
case MHD_HTTP_BAD_REQUEST: case MHD_HTTP_BAD_REQUEST:
/* This should never happen, either us or the exchange is buggy /* This should never happen, either us or the exchange is buggy

View File

@ -118,15 +118,15 @@ handle_deposit_wtid_finished (void *cls,
{ {
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("wtid", GNUNET_JSON_spec_fixed_auto ("wtid",
&dr.details.success.wtid), &dr.details.ok.wtid),
GNUNET_JSON_spec_timestamp ("execution_time", GNUNET_JSON_spec_timestamp ("execution_time",
&dr.details.success.execution_time), &dr.details.ok.execution_time),
TALER_JSON_spec_amount_any ("coin_contribution", TALER_JSON_spec_amount_any ("coin_contribution",
&dr.details.success.coin_contribution), &dr.details.ok.coin_contribution),
GNUNET_JSON_spec_fixed_auto ("exchange_sig", GNUNET_JSON_spec_fixed_auto ("exchange_sig",
&dr.details.success.exchange_sig), &dr.details.ok.exchange_sig),
GNUNET_JSON_spec_fixed_auto ("exchange_pub", GNUNET_JSON_spec_fixed_auto ("exchange_pub",
&dr.details.success.exchange_pub), &dr.details.ok.exchange_pub),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
}; };
const struct TALER_EXCHANGE_Keys *key_state; const struct TALER_EXCHANGE_Keys *key_state;
@ -145,7 +145,7 @@ handle_deposit_wtid_finished (void *cls,
} }
if (GNUNET_OK != if (GNUNET_OK !=
TALER_EXCHANGE_test_signing_key (key_state, TALER_EXCHANGE_test_signing_key (key_state,
&dr.details.success.exchange_pub)) &dr.details.ok.exchange_pub))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
dr.hr.http_status = 0; dr.hr.http_status = 0;
@ -156,12 +156,12 @@ handle_deposit_wtid_finished (void *cls,
TALER_exchange_online_confirm_wire_verify ( TALER_exchange_online_confirm_wire_verify (
&dwh->h_wire, &dwh->h_wire,
&dwh->h_contract_terms, &dwh->h_contract_terms,
&dr.details.success.wtid, &dr.details.ok.wtid,
&dwh->coin_pub, &dwh->coin_pub,
dr.details.success.execution_time, dr.details.ok.execution_time,
&dr.details.success.coin_contribution, &dr.details.ok.coin_contribution,
&dr.details.success.exchange_pub, &dr.details.ok.exchange_pub,
&dr.details.success.exchange_sig)) &dr.details.ok.exchange_sig))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
dr.hr.http_status = 0; dr.hr.http_status = 0;

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2014-2022 Taler Systems SA Copyright (C) 2014-2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it TALER is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published under the terms of the GNU General Public License as published
@ -40,7 +40,7 @@
* Which version of the Taler protocol is implemented * Which version of the Taler protocol is implemented
* by this library? Used to determine compatibility. * by this library? Used to determine compatibility.
*/ */
#define EXCHANGE_PROTOCOL_CURRENT 14 #define EXCHANGE_PROTOCOL_CURRENT 15
/** /**
* How many versions are we backwards compatible with? * How many versions are we backwards compatible with?
@ -1305,15 +1305,18 @@ keys_completed_cb (void *cls,
{ {
struct KeysRequest *kr = cls; struct KeysRequest *kr = cls;
struct TALER_EXCHANGE_Handle *exchange = kr->exchange; struct TALER_EXCHANGE_Handle *exchange = kr->exchange;
struct TALER_EXCHANGE_Keys kd;
struct TALER_EXCHANGE_Keys kd_old; struct TALER_EXCHANGE_Keys kd_old;
enum TALER_EXCHANGE_VersionCompatibility vc;
const json_t *j = resp_obj; const json_t *j = resp_obj;
struct TALER_EXCHANGE_HttpResponse hr = { struct TALER_EXCHANGE_Keys kd;
.reply = j, struct TALER_EXCHANGE_KeysResponse kresp = {
.http_status = (unsigned int) response_code .hr.reply = j,
.hr.http_status = (unsigned int) response_code,
.details.ok.compat = TALER_EXCHANGE_VC_PROTOCOL_ERROR,
}; };
memset (&kd,
0,
sizeof (kd));
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Received keys from URL `%s' with status %ld and expiration %s.\n", "Received keys from URL `%s' with status %ld and expiration %s.\n",
kr->url, kr->url,
@ -1330,10 +1333,6 @@ keys_completed_cb (void *cls,
GNUNET_TIME_relative_to_absolute (DEFAULT_EXPIRATION)); GNUNET_TIME_relative_to_absolute (DEFAULT_EXPIRATION));
} }
kd_old = exchange->key_data; kd_old = exchange->key_data;
memset (&kd,
0,
sizeof (struct TALER_EXCHANGE_Keys));
vc = TALER_EXCHANGE_VC_PROTOCOL_ERROR;
switch (response_code) switch (response_code)
{ {
case 0: case 0:
@ -1358,8 +1357,10 @@ keys_completed_cb (void *cls,
} }
/* We keep the denomination keys and auditor signatures from the /* We keep the denomination keys and auditor signatures from the
previous iteration (/keys cherry picking) */ previous iteration (/keys cherry picking) */
kd.num_denom_keys = kd_old.num_denom_keys; kd.num_denom_keys
kd.last_denom_issue_date = kd_old.last_denom_issue_date; = kd_old.num_denom_keys;
kd.last_denom_issue_date
= kd_old.last_denom_issue_date;
GNUNET_array_grow (kd.denom_keys, GNUNET_array_grow (kd.denom_keys,
kd.denom_keys_size, kd.denom_keys_size,
kd.num_denom_keys); kd.num_denom_keys);
@ -1401,11 +1402,11 @@ keys_completed_cb (void *cls,
decode_keys_json (j, decode_keys_json (j,
true, true,
&kd, &kd,
&vc)) &kresp.details.ok.compat))
{ {
TALER_LOG_ERROR ("Could not decode /keys response\n"); TALER_LOG_ERROR ("Could not decode /keys response\n");
hr.http_status = 0; kresp.hr.http_status = 0;
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; kresp.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
for (unsigned int i = 0; i<kd.num_auditors; i++) for (unsigned int i = 0; i<kd.num_auditors; i++)
{ {
struct TALER_EXCHANGE_AuditorInformation *anew = &kd.auditors[i]; struct TALER_EXCHANGE_AuditorInformation *anew = &kd.auditors[i];
@ -1436,13 +1437,13 @@ keys_completed_cb (void *cls,
case MHD_HTTP_NOT_FOUND: case MHD_HTTP_NOT_FOUND:
if (NULL == j) if (NULL == j)
{ {
hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; kresp.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
hr.hint = TALER_ErrorCode_get_hint (hr.ec); kresp.hr.hint = TALER_ErrorCode_get_hint (kresp.hr.ec);
} }
else else
{ {
hr.ec = TALER_JSON_get_error_code (j); kresp.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); kresp.hr.hint = TALER_JSON_get_error_hint (j);
} }
break; break;
default: default:
@ -1450,18 +1451,18 @@ keys_completed_cb (void *cls,
exchange->keys_error_count++; exchange->keys_error_count++;
if (NULL == j) if (NULL == j)
{ {
hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; kresp.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
hr.hint = TALER_ErrorCode_get_hint (hr.ec); kresp.hr.hint = TALER_ErrorCode_get_hint (kresp.hr.ec);
} }
else else
{ {
hr.ec = TALER_JSON_get_error_code (j); kresp.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); kresp.hr.hint = TALER_JSON_get_error_hint (j);
} }
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d\n", "Unexpected response code %u/%d\n",
(unsigned int) response_code, (unsigned int) response_code,
(int) hr.ec); (int) kresp.hr.ec);
break; break;
} }
exchange->key_data = kd; exchange->key_data = kd;
@ -1491,9 +1492,7 @@ keys_completed_cb (void *cls,
free_key_data (&kd_old); free_key_data (&kd_old);
/* notify application that we failed */ /* notify application that we failed */
exchange->cert_cb (exchange->cert_cb_cls, exchange->cert_cb (exchange->cert_cb_cls,
&hr, &kresp);
NULL,
vc);
return; return;
} }
@ -1504,11 +1503,11 @@ keys_completed_cb (void *cls,
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Successfully downloaded exchange's keys\n"); "Successfully downloaded exchange's keys\n");
update_auditors (exchange); update_auditors (exchange);
kresp.details.ok.keys = &exchange->key_data;
/* notify application about the key information */ /* notify application about the key information */
exchange->cert_cb (exchange->cert_cb_cls, exchange->cert_cb (exchange->cert_cb_cls,
&hr, &kresp);
&exchange->key_data,
vc);
free_key_data (&kd_old); free_key_data (&kd_old);
} }
@ -1702,7 +1701,6 @@ static void
deserialize_data (struct TALER_EXCHANGE_Handle *exchange, deserialize_data (struct TALER_EXCHANGE_Handle *exchange,
const json_t *data) const json_t *data)
{ {
enum TALER_EXCHANGE_VersionCompatibility vc;
json_t *keys; json_t *keys;
const char *url; const char *url;
uint32_t version; uint32_t version;
@ -1719,10 +1717,11 @@ deserialize_data (struct TALER_EXCHANGE_Handle *exchange,
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
}; };
struct TALER_EXCHANGE_Keys key_data; struct TALER_EXCHANGE_Keys key_data;
struct TALER_EXCHANGE_HttpResponse hr = { struct TALER_EXCHANGE_KeysResponse kresp = {
.ec = TALER_EC_NONE, .hr.ec = TALER_EC_NONE,
.http_status = MHD_HTTP_OK, .hr.http_status = MHD_HTTP_OK,
.reply = data .hr.reply = data,
.details.ok.keys = &exchange->key_data
}; };
if (NULL == data) if (NULL == data)
@ -1754,7 +1753,7 @@ deserialize_data (struct TALER_EXCHANGE_Handle *exchange,
decode_keys_json (keys, decode_keys_json (keys,
false, false,
&key_data, &key_data,
&vc)) &kresp.details.ok.compat))
{ {
GNUNET_break (0); GNUNET_break (0);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
@ -1771,9 +1770,7 @@ deserialize_data (struct TALER_EXCHANGE_Handle *exchange,
update_auditors (exchange); update_auditors (exchange);
/* notify application about the key information */ /* notify application about the key information */
exchange->cert_cb (exchange->cert_cb_cls, exchange->cert_cb (exchange->cert_cb_cls,
&hr, &kresp);
&exchange->key_data,
vc);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
} }
@ -2056,17 +2053,18 @@ request_keys (void *cls)
url); url);
if (NULL == kr->url) if (NULL == kr->url)
{ {
struct TALER_EXCHANGE_HttpResponse hr = { struct TALER_EXCHANGE_KeysResponse kresp = {
.ec = TALER_EC_GENERIC_CONFIGURATION_INVALID .hr.ec = TALER_EC_GENERIC_CONFIGURATION_INVALID,
/* Next line is technically unnecessary, as the
http status we set is 0 */
.details.ok.compat = TALER_EXCHANGE_VC_PROTOCOL_ERROR
}; };
GNUNET_free (kr); GNUNET_free (kr);
exchange->keys_error_count++; exchange->keys_error_count++;
exchange->state = MHS_FAILED; exchange->state = MHS_FAILED;
exchange->cert_cb (exchange->cert_cb_cls, exchange->cert_cb (exchange->cert_cb_cls,
&hr, &kresp);
NULL,
TALER_EXCHANGE_VC_PROTOCOL_ERROR);
return; return;
} }

View File

@ -100,11 +100,11 @@ handle_kyc_check_finished (void *cls,
uint32_t status; uint32_t status;
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("exchange_sig", GNUNET_JSON_spec_fixed_auto ("exchange_sig",
&ks.details.success.exchange_sig), &ks.details.ok.exchange_sig),
GNUNET_JSON_spec_fixed_auto ("exchange_pub", GNUNET_JSON_spec_fixed_auto ("exchange_pub",
&ks.details.success.exchange_pub), &ks.details.ok.exchange_pub),
GNUNET_JSON_spec_timestamp ("now", GNUNET_JSON_spec_timestamp ("now",
&ks.details.success.timestamp), &ks.details.ok.timestamp),
GNUNET_JSON_spec_json ("kyc_details", GNUNET_JSON_spec_json ("kyc_details",
&kyc_details), &kyc_details),
GNUNET_JSON_spec_uint32 ("aml_status", GNUNET_JSON_spec_uint32 ("aml_status",
@ -123,13 +123,13 @@ handle_kyc_check_finished (void *cls,
ks.ec = TALER_EC_GENERIC_INVALID_RESPONSE; ks.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break; break;
} }
ks.details.success.kyc_details = kyc_details; ks.details.ok.kyc_details = kyc_details;
ks.details.success.aml_status ks.details.ok.aml_status
= (enum TALER_AmlDecisionState) status; = (enum TALER_AmlDecisionState) status;
key_state = TALER_EXCHANGE_get_keys (kch->exchange); key_state = TALER_EXCHANGE_get_keys (kch->exchange);
if (GNUNET_OK != if (GNUNET_OK !=
TALER_EXCHANGE_test_signing_key (key_state, TALER_EXCHANGE_test_signing_key (key_state,
&ks.details.success.exchange_pub)) &ks.details.ok.exchange_pub))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
ks.http_status = 0; ks.http_status = 0;
@ -141,10 +141,10 @@ handle_kyc_check_finished (void *cls,
if (GNUNET_OK != if (GNUNET_OK !=
TALER_exchange_online_account_setup_success_verify ( TALER_exchange_online_account_setup_success_verify (
&kch->h_payto, &kch->h_payto,
ks.details.success.kyc_details, ks.details.ok.kyc_details,
ks.details.success.timestamp, ks.details.ok.timestamp,
&ks.details.success.exchange_pub, &ks.details.ok.exchange_pub,
&ks.details.success.exchange_sig)) &ks.details.ok.exchange_sig))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
ks.http_status = 0; ks.http_status = 0;

View File

@ -365,8 +365,8 @@ parse_link_ok (struct TALER_EXCHANGE_LinkHandle *lh,
if (off_coin == num_coins) if (off_coin == num_coins)
{ {
lr.details.success.num_coins = num_coins; lr.details.ok.num_coins = num_coins;
lr.details.success.coins = lcis; lr.details.ok.coins = lcis;
lh->link_cb (lh->link_cb_cls, lh->link_cb (lh->link_cb_cls,
&lr); &lr);
lh->link_cb = NULL; lh->link_cb = NULL;

View File

@ -190,17 +190,17 @@ parse_decision_ok (struct TALER_EXCHANGE_LookupAmlDecision *lh,
GNUNET_break_op (0); GNUNET_break_op (0);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
lr.details.success.aml_history_length = json_array_size (aml_history); lr.details.ok.aml_history_length = json_array_size (aml_history);
lr.details.success.kyc_attributes_length = json_array_size (kyc_attributes); lr.details.ok.kyc_attributes_length = json_array_size (kyc_attributes);
{ {
struct TALER_EXCHANGE_AmlDecisionDetail aml_history_ar[ struct TALER_EXCHANGE_AmlDecisionDetail aml_history_ar[
GNUNET_NZL (lr.details.success.aml_history_length)]; GNUNET_NZL (lr.details.ok.aml_history_length)];
struct TALER_EXCHANGE_KycHistoryDetail kyc_attributes_ar[ struct TALER_EXCHANGE_KycHistoryDetail kyc_attributes_ar[
lr.details.success.kyc_attributes_length]; lr.details.ok.kyc_attributes_length];
enum GNUNET_GenericReturnValue ret = GNUNET_SYSERR; enum GNUNET_GenericReturnValue ret = GNUNET_SYSERR;
lr.details.success.aml_history = aml_history_ar; lr.details.ok.aml_history = aml_history_ar;
lr.details.success.kyc_attributes = kyc_attributes_ar; lr.details.ok.kyc_attributes = kyc_attributes_ar;
ret = parse_aml_history (aml_history, ret = parse_aml_history (aml_history,
aml_history_ar); aml_history_ar);
if (GNUNET_OK == ret) if (GNUNET_OK == ret)

View File

@ -139,13 +139,13 @@ parse_decisions_ok (struct TALER_EXCHANGE_LookupAmlDecisions *lh,
GNUNET_break_op (0); GNUNET_break_op (0);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
lr.details.success.decisions_length = json_array_size (records); lr.details.ok.decisions_length = json_array_size (records);
{ {
struct TALER_EXCHANGE_AmlDecisionSummary decisions[ struct TALER_EXCHANGE_AmlDecisionSummary decisions[
GNUNET_NZL (lr.details.success.decisions_length)]; GNUNET_NZL (lr.details.ok.decisions_length)];
enum GNUNET_GenericReturnValue ret = GNUNET_SYSERR; enum GNUNET_GenericReturnValue ret = GNUNET_SYSERR;
lr.details.success.decisions = decisions; lr.details.ok.decisions = decisions;
ret = parse_aml_decisions (records, ret = parse_aml_decisions (records,
decisions); decisions);
if (GNUNET_OK == ret) if (GNUNET_OK == ret)

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2020-2022 Taler Systems SA Copyright (C) 2020-2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the 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 terms of the GNU General Public License as published by the Free Software
@ -79,9 +79,9 @@ handle_drain_profits_finished (void *cls,
{ {
struct TALER_EXCHANGE_ManagementDrainProfitsHandle *dp = cls; struct TALER_EXCHANGE_ManagementDrainProfitsHandle *dp = cls;
const json_t *json = response; const json_t *json = response;
struct TALER_EXCHANGE_HttpResponse hr = { struct TALER_EXCHANGE_ManagementDrainResponse dr = {
.http_status = (unsigned int) response_code, .hr.http_status = (unsigned int) response_code,
.reply = json .hr.reply = json
}; };
dp->job = NULL; dp->job = NULL;
@ -90,32 +90,32 @@ handle_drain_profits_finished (void *cls,
case MHD_HTTP_NO_CONTENT: case MHD_HTTP_NO_CONTENT:
break; break;
case MHD_HTTP_FORBIDDEN: case MHD_HTTP_FORBIDDEN:
hr.ec = TALER_JSON_get_error_code (json); dr.hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json); dr.hr.hint = TALER_JSON_get_error_hint (json);
break; break;
case MHD_HTTP_CONFLICT: case MHD_HTTP_CONFLICT:
hr.ec = TALER_JSON_get_error_code (json); dr.hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json); dr.hr.hint = TALER_JSON_get_error_hint (json);
break; break;
case MHD_HTTP_PRECONDITION_FAILED: case MHD_HTTP_PRECONDITION_FAILED:
hr.ec = TALER_JSON_get_error_code (json); dr.hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json); dr.hr.hint = TALER_JSON_get_error_hint (json);
break; break;
default: default:
/* unexpected response code */ /* unexpected response code */
GNUNET_break_op (0); GNUNET_break_op (0);
hr.ec = TALER_JSON_get_error_code (json); dr.hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json); dr.hr.hint = TALER_JSON_get_error_hint (json);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d for exchange management drain profits\n", "Unexpected response code %u/%d for exchange management drain profits\n",
(unsigned int) response_code, (unsigned int) response_code,
(int) hr.ec); (int) dr.hr.ec);
break; break;
} }
if (NULL != dp->cb) if (NULL != dp->cb)
{ {
dp->cb (dp->cb_cls, dp->cb (dp->cb_cls,
&hr); &dr);
dp->cb = NULL; dp->cb = NULL;
} }
TALER_EXCHANGE_management_drain_profits_cancel (dp); TALER_EXCHANGE_management_drain_profits_cancel (dp);

View File

@ -75,11 +75,16 @@ struct TALER_EXCHANGE_ManagementGetKeysHandle
* @param response the response * @param response the response
* @return #GNUNET_OK if the response was well-formed * @return #GNUNET_OK if the response was well-formed
*/ */
static int static enum GNUNET_GenericReturnValue
handle_ok (struct TALER_EXCHANGE_ManagementGetKeysHandle *gh, handle_ok (struct TALER_EXCHANGE_ManagementGetKeysHandle *gh,
const json_t *response) const json_t *response)
{ {
struct TALER_EXCHANGE_FutureKeys fk; struct TALER_EXCHANGE_ManagementGetKeysResponse gkr = {
.hr.http_status = MHD_HTTP_OK,
.hr.reply = response,
};
struct TALER_EXCHANGE_FutureKeys *fk
= &gkr.details.ok.keys;
json_t *sk; json_t *sk;
json_t *dk; json_t *dk;
bool ok; bool ok;
@ -89,13 +94,13 @@ handle_ok (struct TALER_EXCHANGE_ManagementGetKeysHandle *gh,
GNUNET_JSON_spec_json ("future_signkeys", GNUNET_JSON_spec_json ("future_signkeys",
&sk), &sk),
GNUNET_JSON_spec_fixed_auto ("master_pub", GNUNET_JSON_spec_fixed_auto ("master_pub",
&fk.master_pub), &fk->master_pub),
GNUNET_JSON_spec_fixed_auto ("denom_secmod_public_key", GNUNET_JSON_spec_fixed_auto ("denom_secmod_public_key",
&fk.denom_secmod_public_key), &fk->denom_secmod_public_key),
GNUNET_JSON_spec_fixed_auto ("denom_secmod_cs_public_key", GNUNET_JSON_spec_fixed_auto ("denom_secmod_cs_public_key",
&fk.denom_secmod_cs_public_key), &fk->denom_secmod_cs_public_key),
GNUNET_JSON_spec_fixed_auto ("signkey_secmod_public_key", GNUNET_JSON_spec_fixed_auto ("signkey_secmod_public_key",
&fk.signkey_secmod_public_key), &fk->signkey_secmod_public_key),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
}; };
@ -107,21 +112,21 @@ handle_ok (struct TALER_EXCHANGE_ManagementGetKeysHandle *gh,
GNUNET_break_op (0); GNUNET_break_op (0);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
fk.num_sign_keys = json_array_size (sk); fk->num_sign_keys = json_array_size (sk);
fk.num_denom_keys = json_array_size (dk); fk->num_denom_keys = json_array_size (dk);
fk.sign_keys = GNUNET_new_array ( fk->sign_keys = GNUNET_new_array (
fk.num_sign_keys, fk->num_sign_keys,
struct TALER_EXCHANGE_FutureSigningPublicKey); struct TALER_EXCHANGE_FutureSigningPublicKey);
fk.denom_keys = GNUNET_new_array ( fk->denom_keys = GNUNET_new_array (
fk.num_denom_keys, fk->num_denom_keys,
struct TALER_EXCHANGE_FutureDenomPublicKey); struct TALER_EXCHANGE_FutureDenomPublicKey);
ok = true; ok = true;
for (unsigned int i = 0; i<fk.num_sign_keys; i++) for (unsigned int i = 0; i<fk->num_sign_keys; i++)
{ {
json_t *j = json_array_get (sk, json_t *j = json_array_get (sk,
i); i);
struct TALER_EXCHANGE_FutureSigningPublicKey *sign_key struct TALER_EXCHANGE_FutureSigningPublicKey *sign_key
= &fk.sign_keys[i]; = &fk->sign_keys[i];
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("key", GNUNET_JSON_spec_fixed_auto ("key",
&sign_key->key), &sign_key->key),
@ -155,7 +160,7 @@ handle_ok (struct TALER_EXCHANGE_ManagementGetKeysHandle *gh,
&sign_key->key, &sign_key->key,
sign_key->valid_from, sign_key->valid_from,
duration, duration,
&fk.signkey_secmod_public_key, &fk->signkey_secmod_public_key,
&sign_key->signkey_secmod_sig)) &sign_key->signkey_secmod_sig))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
@ -164,12 +169,12 @@ handle_ok (struct TALER_EXCHANGE_ManagementGetKeysHandle *gh,
} }
} }
} }
for (unsigned int i = 0; i<fk.num_denom_keys; i++) for (unsigned int i = 0; i<fk->num_denom_keys; i++)
{ {
json_t *j = json_array_get (dk, json_t *j = json_array_get (dk,
i); i);
struct TALER_EXCHANGE_FutureDenomPublicKey *denom_key struct TALER_EXCHANGE_FutureDenomPublicKey *denom_key
= &fk.denom_keys[i]; = &fk->denom_keys[i];
const char *section_name; const char *section_name;
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
TALER_JSON_spec_amount_any ("value", TALER_JSON_spec_amount_any ("value",
@ -236,7 +241,7 @@ handle_ok (struct TALER_EXCHANGE_ManagementGetKeysHandle *gh,
section_name, section_name,
denom_key->valid_from, denom_key->valid_from,
duration, duration,
&fk.denom_secmod_public_key, &fk->denom_secmod_public_key,
&denom_key->denom_secmod_sig)) &denom_key->denom_secmod_sig))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
@ -256,7 +261,7 @@ handle_ok (struct TALER_EXCHANGE_ManagementGetKeysHandle *gh,
section_name, section_name,
denom_key->valid_from, denom_key->valid_from,
duration, duration,
&fk.denom_secmod_cs_public_key, &fk->denom_secmod_cs_public_key,
&denom_key->denom_secmod_sig)) &denom_key->denom_secmod_sig))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
@ -277,19 +282,13 @@ handle_ok (struct TALER_EXCHANGE_ManagementGetKeysHandle *gh,
} }
if (ok) if (ok)
{ {
struct TALER_EXCHANGE_HttpResponse hr = {
.http_status = MHD_HTTP_OK,
.reply = response
};
gh->cb (gh->cb_cls, gh->cb (gh->cb_cls,
&hr, &gkr);
&fk);
} }
for (unsigned int i = 0; i<fk.num_denom_keys; i++) for (unsigned int i = 0; i<fk->num_denom_keys; i++)
TALER_denom_pub_free (&fk.denom_keys[i].key); TALER_denom_pub_free (&fk->denom_keys[i].key);
GNUNET_free (fk.sign_keys); GNUNET_free (fk->sign_keys);
GNUNET_free (fk.denom_keys); GNUNET_free (fk->denom_keys);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
return (ok) ? GNUNET_OK : GNUNET_SYSERR; return (ok) ? GNUNET_OK : GNUNET_SYSERR;
} }
@ -310,9 +309,9 @@ handle_get_keys_finished (void *cls,
{ {
struct TALER_EXCHANGE_ManagementGetKeysHandle *gh = cls; struct TALER_EXCHANGE_ManagementGetKeysHandle *gh = cls;
const json_t *json = response; const json_t *json = response;
struct TALER_EXCHANGE_HttpResponse hr = { struct TALER_EXCHANGE_ManagementGetKeysResponse gkr = {
.http_status = (unsigned int) response_code, .hr.http_status = (unsigned int) response_code,
.reply = json .hr.reply = json
}; };
gh->job = NULL; gh->job = NULL;
@ -334,25 +333,24 @@ handle_get_keys_finished (void *cls,
/* unexpected response code */ /* unexpected response code */
if (NULL != json) if (NULL != json)
{ {
hr.ec = TALER_JSON_get_error_code (json); gkr.hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json); gkr.hr.hint = TALER_JSON_get_error_hint (json);
} }
else else
{ {
hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; gkr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
hr.hint = TALER_ErrorCode_get_hint (hr.ec); gkr.hr.hint = TALER_ErrorCode_get_hint (gkr.hr.ec);
} }
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d for exchange management get keys\n", "Unexpected response code %u/%d for exchange management get keys\n",
(unsigned int) response_code, (unsigned int) response_code,
(int) hr.ec); (int) gkr.hr.ec);
break; break;
} }
if (NULL != gh->cb) if (NULL != gh->cb)
{ {
gh->cb (gh->cb_cls, gh->cb (gh->cb_cls,
&hr, &gkr);
NULL);
gh->cb = NULL; gh->cb = NULL;
} }
TALER_EXCHANGE_get_management_keys_cancel (gh); TALER_EXCHANGE_get_management_keys_cancel (gh);

View File

@ -83,9 +83,9 @@ handle_post_extensions_finished (void *cls,
{ {
struct TALER_EXCHANGE_ManagementPostExtensionsHandle *ph = cls; struct TALER_EXCHANGE_ManagementPostExtensionsHandle *ph = cls;
const json_t *json = response; const json_t *json = response;
struct TALER_EXCHANGE_HttpResponse hr = { struct TALER_EXCHANGE_ManagementPostExtensionsResponse per = {
.http_status = (unsigned int) response_code, .hr.http_status = (unsigned int) response_code,
.reply = json .hr.reply = json
}; };
ph->job = NULL; ph->job = NULL;
@ -94,28 +94,28 @@ handle_post_extensions_finished (void *cls,
case MHD_HTTP_NO_CONTENT: case MHD_HTTP_NO_CONTENT:
break; break;
case MHD_HTTP_FORBIDDEN: case MHD_HTTP_FORBIDDEN:
hr.ec = TALER_JSON_get_error_code (json); per.hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json); per.hr.hint = TALER_JSON_get_error_hint (json);
break; break;
case MHD_HTTP_NOT_FOUND: case MHD_HTTP_NOT_FOUND:
hr.ec = TALER_JSON_get_error_code (json); per.hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json); per.hr.hint = TALER_JSON_get_error_hint (json);
break; break;
default: default:
/* unexpected response code */ /* unexpected response code */
GNUNET_break_op (0); GNUNET_break_op (0);
hr.ec = TALER_JSON_get_error_code (json); per.hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json); per.hr.hint = TALER_JSON_get_error_hint (json);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d for exchange management post extensions\n", "Unexpected response code %u/%d for exchange management post extensions\n",
(unsigned int) response_code, (unsigned int) response_code,
(int) hr.ec); (int) per.hr.ec);
break; break;
} }
if (NULL != ph->cb) if (NULL != ph->cb)
{ {
ph->cb (ph->cb_cls, ph->cb (ph->cb_cls,
&hr); &per);
ph->cb = NULL; ph->cb = NULL;
} }
TALER_EXCHANGE_management_post_extensions_cancel (ph); TALER_EXCHANGE_management_post_extensions_cancel (ph);

View File

@ -82,9 +82,9 @@ handle_post_keys_finished (void *cls,
{ {
struct TALER_EXCHANGE_ManagementPostKeysHandle *ph = cls; struct TALER_EXCHANGE_ManagementPostKeysHandle *ph = cls;
const json_t *json = response; const json_t *json = response;
struct TALER_EXCHANGE_HttpResponse hr = { struct TALER_EXCHANGE_ManagementPostKeysResponse pkr = {
.http_status = (unsigned int) response_code, .hr.http_status = (unsigned int) response_code,
.reply = json .hr.reply = json
}; };
ph->job = NULL; ph->job = NULL;
@ -93,32 +93,32 @@ handle_post_keys_finished (void *cls,
case MHD_HTTP_NO_CONTENT: case MHD_HTTP_NO_CONTENT:
break; break;
case MHD_HTTP_FORBIDDEN: case MHD_HTTP_FORBIDDEN:
hr.ec = TALER_JSON_get_error_code (json); pkr.hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json); pkr.hr.hint = TALER_JSON_get_error_hint (json);
break; break;
case MHD_HTTP_NOT_FOUND: case MHD_HTTP_NOT_FOUND:
hr.ec = TALER_JSON_get_error_code (json); pkr.hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json); pkr.hr.hint = TALER_JSON_get_error_hint (json);
break; break;
case MHD_HTTP_REQUEST_ENTITY_TOO_LARGE: case MHD_HTTP_REQUEST_ENTITY_TOO_LARGE:
hr.ec = TALER_JSON_get_error_code (json); pkr.hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json); pkr.hr.hint = TALER_JSON_get_error_hint (json);
break; break;
default: default:
/* unexpected response code */ /* unexpected response code */
GNUNET_break_op (0); GNUNET_break_op (0);
hr.ec = TALER_JSON_get_error_code (json); pkr.hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json); pkr.hr.hint = TALER_JSON_get_error_hint (json);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d for exchange management post keys\n", "Unexpected response code %u/%d for exchange management post keys\n",
(unsigned int) response_code, (unsigned int) response_code,
(int) hr.ec); (int) pkr.hr.ec);
break; break;
} }
if (NULL != ph->cb) if (NULL != ph->cb)
{ {
ph->cb (ph->cb_cls, ph->cb (ph->cb_cls,
&hr); &pkr);
ph->cb = NULL; ph->cb = NULL;
} }
TALER_EXCHANGE_post_management_keys_cancel (ph); TALER_EXCHANGE_post_management_keys_cancel (ph);

View File

@ -82,9 +82,9 @@ handle_revoke_denomination_finished (void *cls,
{ {
struct TALER_EXCHANGE_ManagementRevokeDenominationKeyHandle *rh = cls; struct TALER_EXCHANGE_ManagementRevokeDenominationKeyHandle *rh = cls;
const json_t *json = response; const json_t *json = response;
struct TALER_EXCHANGE_HttpResponse hr = { struct TALER_EXCHANGE_ManagementRevokeDenominationResponse rdr = {
.http_status = (unsigned int) response_code, .hr.http_status = (unsigned int) response_code,
.reply = json .hr.reply = json
}; };
rh->job = NULL; rh->job = NULL;
@ -92,30 +92,30 @@ handle_revoke_denomination_finished (void *cls,
{ {
case 0: case 0:
/* no reply */ /* no reply */
hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; rdr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
hr.hint = "server offline?"; rdr.hr.hint = "server offline?";
break; break;
case MHD_HTTP_NO_CONTENT: case MHD_HTTP_NO_CONTENT:
break; break;
case MHD_HTTP_FORBIDDEN: case MHD_HTTP_FORBIDDEN:
hr.ec = TALER_JSON_get_error_code (json); rdr.hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json); rdr.hr.hint = TALER_JSON_get_error_hint (json);
break; break;
default: default:
/* unexpected response code */ /* unexpected response code */
GNUNET_break_op (0); GNUNET_break_op (0);
hr.ec = TALER_JSON_get_error_code (json); rdr.hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json); rdr.hr.hint = TALER_JSON_get_error_hint (json);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d for exchange management revoke denomination\n", "Unexpected response code %u/%d for exchange management revoke denomination\n",
(unsigned int) response_code, (unsigned int) response_code,
(int) hr.ec); (int) rdr.hr.ec);
break; break;
} }
if (NULL != rh->cb) if (NULL != rh->cb)
{ {
rh->cb (rh->cb_cls, rh->cb (rh->cb_cls,
&hr); &rdr);
rh->cb = NULL; rh->cb = NULL;
} }
TALER_EXCHANGE_management_revoke_denomination_key_cancel (rh); TALER_EXCHANGE_management_revoke_denomination_key_cancel (rh);

View File

@ -79,9 +79,9 @@ handle_revoke_signing_finished (void *cls,
{ {
struct TALER_EXCHANGE_ManagementRevokeSigningKeyHandle *rh = cls; struct TALER_EXCHANGE_ManagementRevokeSigningKeyHandle *rh = cls;
const json_t *json = response; const json_t *json = response;
struct TALER_EXCHANGE_HttpResponse hr = { struct TALER_EXCHANGE_ManagementRevokeSigningKeyResponse rsr = {
.http_status = (unsigned int) response_code, .hr.http_status = (unsigned int) response_code,
.reply = json .hr.reply = json
}; };
rh->job = NULL; rh->job = NULL;
@ -89,30 +89,30 @@ handle_revoke_signing_finished (void *cls,
{ {
case 0: case 0:
/* no reply */ /* no reply */
hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; rsr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
hr.hint = "server offline?"; rsr.hr.hint = "server offline?";
break; break;
case MHD_HTTP_NO_CONTENT: case MHD_HTTP_NO_CONTENT:
break; break;
case MHD_HTTP_FORBIDDEN: case MHD_HTTP_FORBIDDEN:
hr.ec = TALER_JSON_get_error_code (json); rsr.hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json); rsr.hr.hint = TALER_JSON_get_error_hint (json);
break; break;
default: default:
/* unexpected response code */ /* unexpected response code */
GNUNET_break_op (0); GNUNET_break_op (0);
hr.ec = TALER_JSON_get_error_code (json); rsr.hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json); rsr.hr.hint = TALER_JSON_get_error_hint (json);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d for exchange management revoke signkey\n", "Unexpected response code %u/%d for exchange management revoke signkey\n",
(unsigned int) response_code, (unsigned int) response_code,
(int) hr.ec); (int) rsr.hr.ec);
break; break;
} }
if (NULL != rh->cb) if (NULL != rh->cb)
{ {
rh->cb (rh->cb_cls, rh->cb (rh->cb_cls,
&hr); &rsr);
rh->cb = NULL; rh->cb = NULL;
} }
TALER_EXCHANGE_management_revoke_signing_key_cancel (rh); TALER_EXCHANGE_management_revoke_signing_key_cancel (rh);

View File

@ -79,9 +79,9 @@ handle_update_aml_officer_finished (void *cls,
{ {
struct TALER_EXCHANGE_ManagementUpdateAmlOfficer *wh = cls; struct TALER_EXCHANGE_ManagementUpdateAmlOfficer *wh = cls;
const json_t *json = response; const json_t *json = response;
struct TALER_EXCHANGE_HttpResponse hr = { struct TALER_EXCHANGE_ManagementUpdateAmlOfficerResponse uar = {
.http_status = (unsigned int) response_code, .hr.http_status = (unsigned int) response_code,
.reply = json .hr.reply = json
}; };
wh->job = NULL; wh->job = NULL;
@ -89,34 +89,34 @@ handle_update_aml_officer_finished (void *cls,
{ {
case 0: case 0:
/* no reply */ /* no reply */
hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; uar.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
hr.hint = "server offline?"; uar.hr.hint = "server offline?";
break; break;
case MHD_HTTP_NO_CONTENT: case MHD_HTTP_NO_CONTENT:
break; break;
case MHD_HTTP_FORBIDDEN: case MHD_HTTP_FORBIDDEN:
hr.ec = TALER_JSON_get_error_code (json); uar.hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json); uar.hr.hint = TALER_JSON_get_error_hint (json);
break; break;
case MHD_HTTP_CONFLICT: case MHD_HTTP_CONFLICT:
hr.ec = TALER_JSON_get_error_code (json); uar.hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json); uar.hr.hint = TALER_JSON_get_error_hint (json);
break; break;
default: default:
/* unexpected response code */ /* unexpected response code */
GNUNET_break_op (0); GNUNET_break_op (0);
hr.ec = TALER_JSON_get_error_code (json); uar.hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json); uar.hr.hint = TALER_JSON_get_error_hint (json);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d for exchange management update AML officer\n", "Unexpected response code %u/%d for exchange management update AML officer\n",
(unsigned int) response_code, (unsigned int) response_code,
(int) hr.ec); (int) uar.hr.ec);
break; break;
} }
if (NULL != wh->cb) if (NULL != wh->cb)
{ {
wh->cb (wh->cb_cls, wh->cb (wh->cb_cls,
&hr); &uar);
wh->cb = NULL; wh->cb = NULL;
} }
TALER_EXCHANGE_management_update_aml_officer_cancel (wh); TALER_EXCHANGE_management_update_aml_officer_cancel (wh);

View File

@ -79,9 +79,9 @@ handle_auditor_disable_finished (void *cls,
{ {
struct TALER_EXCHANGE_ManagementWireDisableHandle *wh = cls; struct TALER_EXCHANGE_ManagementWireDisableHandle *wh = cls;
const json_t *json = response; const json_t *json = response;
struct TALER_EXCHANGE_HttpResponse hr = { struct TALER_EXCHANGE_ManagementWireDisableResponse wdr = {
.http_status = (unsigned int) response_code, .hr.http_status = (unsigned int) response_code,
.reply = json .hr.reply = json
}; };
wh->job = NULL; wh->job = NULL;
@ -89,38 +89,38 @@ handle_auditor_disable_finished (void *cls,
{ {
case 0: case 0:
/* no reply */ /* no reply */
hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; wdr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
hr.hint = "server offline?"; wdr.hr.hint = "server offline?";
break; break;
case MHD_HTTP_NO_CONTENT: case MHD_HTTP_NO_CONTENT:
break; break;
case MHD_HTTP_FORBIDDEN: case MHD_HTTP_FORBIDDEN:
hr.ec = TALER_JSON_get_error_code (json); wdr.hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json); wdr.hr.hint = TALER_JSON_get_error_hint (json);
break; break;
case MHD_HTTP_NOT_FOUND: case MHD_HTTP_NOT_FOUND:
hr.ec = TALER_JSON_get_error_code (json); wdr.hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json); wdr.hr.hint = TALER_JSON_get_error_hint (json);
break; break;
case MHD_HTTP_CONFLICT: case MHD_HTTP_CONFLICT:
hr.ec = TALER_JSON_get_error_code (json); wdr.hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json); wdr.hr.hint = TALER_JSON_get_error_hint (json);
break; break;
default: default:
/* unexpected response code */ /* unexpected response code */
GNUNET_break_op (0); GNUNET_break_op (0);
hr.ec = TALER_JSON_get_error_code (json); wdr.hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json); wdr.hr.hint = TALER_JSON_get_error_hint (json);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d exchange management disable wire\n", "Unexpected response code %u/%d exchange management disable wire\n",
(unsigned int) response_code, (unsigned int) response_code,
(int) hr.ec); (int) wdr.hr.ec);
break; break;
} }
if (NULL != wh->cb) if (NULL != wh->cb)
{ {
wh->cb (wh->cb_cls, wh->cb (wh->cb_cls,
&hr); &wdr);
wh->cb = NULL; wh->cb = NULL;
} }
TALER_EXCHANGE_management_disable_wire_cancel (wh); TALER_EXCHANGE_management_disable_wire_cancel (wh);

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2015-2021 Taler Systems SA Copyright (C) 2015-2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the 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 terms of the GNU General Public License as published by the Free Software
@ -79,9 +79,9 @@ handle_auditor_enable_finished (void *cls,
{ {
struct TALER_EXCHANGE_ManagementWireEnableHandle *wh = cls; struct TALER_EXCHANGE_ManagementWireEnableHandle *wh = cls;
const json_t *json = response; const json_t *json = response;
struct TALER_EXCHANGE_HttpResponse hr = { struct TALER_EXCHANGE_ManagementWireEnableResponse wer = {
.http_status = (unsigned int) response_code, .hr.http_status = (unsigned int) response_code,
.reply = json .hr.reply = json
}; };
wh->job = NULL; wh->job = NULL;
@ -89,34 +89,34 @@ handle_auditor_enable_finished (void *cls,
{ {
case 0: case 0:
/* no reply */ /* no reply */
hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; wer.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
hr.hint = "server offline?"; wer.hr.hint = "server offline?";
break; break;
case MHD_HTTP_NO_CONTENT: case MHD_HTTP_NO_CONTENT:
break; break;
case MHD_HTTP_FORBIDDEN: case MHD_HTTP_FORBIDDEN:
hr.ec = TALER_JSON_get_error_code (json); wer.hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json); wer.hr.hint = TALER_JSON_get_error_hint (json);
break; break;
case MHD_HTTP_CONFLICT: case MHD_HTTP_CONFLICT:
hr.ec = TALER_JSON_get_error_code (json); wer.hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json); wer.hr.hint = TALER_JSON_get_error_hint (json);
break; break;
default: default:
/* unexpected response code */ /* unexpected response code */
GNUNET_break_op (0); GNUNET_break_op (0);
hr.ec = TALER_JSON_get_error_code (json); wer.hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json); wer.hr.hint = TALER_JSON_get_error_hint (json);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d for exchange management enable wire\n", "Unexpected response code %u/%d for exchange management enable wire\n",
(unsigned int) response_code, (unsigned int) response_code,
(int) hr.ec); (int) wer.hr.ec);
break; break;
} }
if (NULL != wh->cb) if (NULL != wh->cb)
{ {
wh->cb (wh->cb_cls, wh->cb (wh->cb_cls,
&hr); &wer);
wh->cb = NULL; wh->cb = NULL;
} }
TALER_EXCHANGE_management_enable_wire_cancel (wh); TALER_EXCHANGE_management_enable_wire_cancel (wh);
@ -128,6 +128,9 @@ TALER_EXCHANGE_management_enable_wire (
struct GNUNET_CURL_Context *ctx, struct GNUNET_CURL_Context *ctx,
const char *url, const char *url,
const char *payto_uri, const char *payto_uri,
const char *conversion_url,
const json_t *debit_restrictions,
const json_t *credit_restrictions,
struct GNUNET_TIME_Timestamp validity_start, struct GNUNET_TIME_Timestamp validity_start,
const struct TALER_MasterSignatureP *master_sig1, const struct TALER_MasterSignatureP *master_sig1,
const struct TALER_MasterSignatureP *master_sig2, const struct TALER_MasterSignatureP *master_sig2,
@ -167,6 +170,13 @@ TALER_EXCHANGE_management_enable_wire (
body = GNUNET_JSON_PACK ( body = GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("payto_uri", GNUNET_JSON_pack_string ("payto_uri",
payto_uri), payto_uri),
GNUNET_JSON_pack_array_incref ("debit_restrictions",
(json_t *) debit_restrictions),
GNUNET_JSON_pack_array_incref ("credit_restrictions",
(json_t *) credit_restrictions),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_string ("conversion_url",
conversion_url)),
GNUNET_JSON_pack_data_auto ("master_sig_add", GNUNET_JSON_pack_data_auto ("master_sig_add",
master_sig1), master_sig1),
GNUNET_JSON_pack_data_auto ("master_sig_wire", GNUNET_JSON_pack_data_auto ("master_sig_wire",

View File

@ -221,16 +221,16 @@ handle_melt_finished (void *cls,
if (GNUNET_OK != if (GNUNET_OK !=
verify_melt_signature_ok (mh, verify_melt_signature_ok (mh,
j, j,
&mr.details.success.sign_key)) &mr.details.ok.sign_key))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
mr.hr.http_status = 0; mr.hr.http_status = 0;
mr.hr.ec = TALER_EC_EXCHANGE_MELT_INVALID_SIGNATURE_BY_EXCHANGE; mr.hr.ec = TALER_EC_EXCHANGE_MELT_INVALID_SIGNATURE_BY_EXCHANGE;
break; break;
} }
mr.details.success.noreveal_index = mh->noreveal_index; mr.details.ok.noreveal_index = mh->noreveal_index;
mr.details.success.num_mbds = mh->rd->fresh_pks_len; mr.details.ok.num_mbds = mh->rd->fresh_pks_len;
mr.details.success.mbds = mh->mbds; mr.details.ok.mbds = mh->mbds;
mh->melt_cb (mh->melt_cb_cls, mh->melt_cb (mh->melt_cb_cls,
&mr); &mr);
mh->melt_cb = NULL; mh->melt_cb = NULL;
@ -478,7 +478,7 @@ csr_cb (void *cls,
break; break;
case TALER_DENOMINATION_CS: case TALER_DENOMINATION_CS:
GNUNET_assert (TALER_DENOMINATION_CS == wv->cipher); GNUNET_assert (TALER_DENOMINATION_CS == wv->cipher);
*wv = csrr->details.success.alg_values[nks_off]; *wv = csrr->details.ok.alg_values[nks_off];
nks_off++; nks_off++;
break; break;
} }

View File

@ -164,17 +164,17 @@ handle_purse_deposit_finished (void *cls,
GNUNET_JSON_spec_fixed_auto ("exchange_pub", GNUNET_JSON_spec_fixed_auto ("exchange_pub",
&exchange_pub), &exchange_pub),
GNUNET_JSON_spec_fixed_auto ("h_contract_terms", GNUNET_JSON_spec_fixed_auto ("h_contract_terms",
&dr.details.success.h_contract_terms), &dr.details.ok.h_contract_terms),
GNUNET_JSON_spec_timestamp ("exchange_timestamp", GNUNET_JSON_spec_timestamp ("exchange_timestamp",
&etime), &etime),
GNUNET_JSON_spec_timestamp ("purse_expiration", GNUNET_JSON_spec_timestamp ("purse_expiration",
&dr.details.success.purse_expiration), &dr.details.ok.purse_expiration),
TALER_JSON_spec_amount ("total_deposited", TALER_JSON_spec_amount ("total_deposited",
keys->currency, keys->currency,
&dr.details.success.total_deposited), &dr.details.ok.total_deposited),
TALER_JSON_spec_amount ("purse_value_after_fees", TALER_JSON_spec_amount ("purse_value_after_fees",
keys->currency, keys->currency,
&dr.details.success.purse_value_after_fees), &dr.details.ok.purse_value_after_fees),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
}; };
@ -200,11 +200,11 @@ handle_purse_deposit_finished (void *cls,
if (GNUNET_OK != if (GNUNET_OK !=
TALER_exchange_online_purse_created_verify ( TALER_exchange_online_purse_created_verify (
etime, etime,
dr.details.success.purse_expiration, dr.details.ok.purse_expiration,
&dr.details.success.purse_value_after_fees, &dr.details.ok.purse_value_after_fees,
&dr.details.success.total_deposited, &dr.details.ok.total_deposited,
&pch->purse_pub, &pch->purse_pub,
&dr.details.success.h_contract_terms, &dr.details.ok.h_contract_terms,
&exchange_pub, &exchange_pub,
&exchange_sig)) &exchange_sig))
{ {

View File

@ -152,11 +152,11 @@ handle_purse_merge_finished (void *cls,
struct TALER_Amount total_deposited; struct TALER_Amount total_deposited;
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("exchange_sig", GNUNET_JSON_spec_fixed_auto ("exchange_sig",
&dr.details.success.exchange_sig), &dr.details.ok.exchange_sig),
GNUNET_JSON_spec_fixed_auto ("exchange_pub", GNUNET_JSON_spec_fixed_auto ("exchange_pub",
&dr.details.success.exchange_pub), &dr.details.ok.exchange_pub),
GNUNET_JSON_spec_timestamp ("exchange_timestamp", GNUNET_JSON_spec_timestamp ("exchange_timestamp",
&dr.details.success.etime), &dr.details.ok.etime),
TALER_JSON_spec_amount ("merge_amount", TALER_JSON_spec_amount ("merge_amount",
pch->purse_value_after_fees.currency, pch->purse_value_after_fees.currency,
&total_deposited), &total_deposited),
@ -176,7 +176,7 @@ handle_purse_merge_finished (void *cls,
key_state = TALER_EXCHANGE_get_keys (pch->exchange); key_state = TALER_EXCHANGE_get_keys (pch->exchange);
if (GNUNET_OK != if (GNUNET_OK !=
TALER_EXCHANGE_test_signing_key (key_state, TALER_EXCHANGE_test_signing_key (key_state,
&dr.details.success.exchange_pub)) &dr.details.ok.exchange_pub))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
dr.hr.http_status = 0; dr.hr.http_status = 0;
@ -185,15 +185,15 @@ handle_purse_merge_finished (void *cls,
} }
if (GNUNET_OK != if (GNUNET_OK !=
TALER_exchange_online_purse_merged_verify ( TALER_exchange_online_purse_merged_verify (
dr.details.success.etime, dr.details.ok.etime,
pch->purse_expiration, pch->purse_expiration,
&pch->purse_value_after_fees, &pch->purse_value_after_fees,
&pch->purse_pub, &pch->purse_pub,
&pch->h_contract_terms, &pch->h_contract_terms,
&pch->reserve_pub, &pch->reserve_pub,
pch->provider_url, pch->provider_url,
&dr.details.success.exchange_pub, &dr.details.ok.exchange_pub,
&dr.details.success.exchange_sig)) &dr.details.ok.exchange_sig))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
dr.hr.http_status = 0; dr.hr.http_status = 0;

View File

@ -101,16 +101,16 @@ handle_purse_get_finished (void *cls,
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_timestamp ("merge_timestamp", GNUNET_JSON_spec_timestamp ("merge_timestamp",
&dr.details.success.merge_timestamp), &dr.details.ok.merge_timestamp),
&no_merge), &no_merge),
GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_timestamp ("deposit_timestamp", GNUNET_JSON_spec_timestamp ("deposit_timestamp",
&dr.details.success.deposit_timestamp), &dr.details.ok.deposit_timestamp),
&no_deposit), &no_deposit),
TALER_JSON_spec_amount_any ("balance", TALER_JSON_spec_amount_any ("balance",
&dr.details.success.balance), &dr.details.ok.balance),
GNUNET_JSON_spec_timestamp ("purse_expiration", GNUNET_JSON_spec_timestamp ("purse_expiration",
&dr.details.success.purse_expiration), &dr.details.ok.purse_expiration),
GNUNET_JSON_spec_fixed_auto ("exchange_pub", GNUNET_JSON_spec_fixed_auto ("exchange_pub",
&exchange_pub), &exchange_pub),
GNUNET_JSON_spec_fixed_auto ("exchange_sig", GNUNET_JSON_spec_fixed_auto ("exchange_sig",
@ -142,9 +142,9 @@ handle_purse_get_finished (void *cls,
} }
if (GNUNET_OK != if (GNUNET_OK !=
TALER_exchange_online_purse_status_verify ( TALER_exchange_online_purse_status_verify (
dr.details.success.merge_timestamp, dr.details.ok.merge_timestamp,
dr.details.success.deposit_timestamp, dr.details.ok.deposit_timestamp,
&dr.details.success.balance, &dr.details.ok.balance,
&exchange_pub, &exchange_pub,
&exchange_sig)) &exchange_sig))
{ {

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2017-2022 Taler Systems SA Copyright (C) 2017-2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the 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 terms of the GNU General Public License as published by the Free Software
@ -100,16 +100,15 @@ static enum GNUNET_GenericReturnValue
process_recoup_response (const struct TALER_EXCHANGE_RecoupHandle *ph, process_recoup_response (const struct TALER_EXCHANGE_RecoupHandle *ph,
const json_t *json) const json_t *json)
{ {
struct TALER_ReservePublicKeyP reserve_pub; struct TALER_EXCHANGE_RecoupResponse rr = {
.hr.reply = json,
.hr.http_status = MHD_HTTP_OK
};
struct GNUNET_JSON_Specification spec_withdraw[] = { struct GNUNET_JSON_Specification spec_withdraw[] = {
GNUNET_JSON_spec_fixed_auto ("reserve_pub", GNUNET_JSON_spec_fixed_auto ("reserve_pub",
&reserve_pub), &rr.details.ok.reserve_pub),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
}; };
struct TALER_EXCHANGE_HttpResponse hr = {
.reply = json,
.http_status = MHD_HTTP_OK
};
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_JSON_parse (json, GNUNET_JSON_parse (json,
@ -120,8 +119,7 @@ process_recoup_response (const struct TALER_EXCHANGE_RecoupHandle *ph,
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
ph->cb (ph->cb_cls, ph->cb (ph->cb_cls,
&hr, &rr);
&reserve_pub);
return GNUNET_OK; return GNUNET_OK;
} }
@ -141,9 +139,9 @@ handle_recoup_finished (void *cls,
{ {
struct TALER_EXCHANGE_RecoupHandle *ph = cls; struct TALER_EXCHANGE_RecoupHandle *ph = cls;
const json_t *j = response; const json_t *j = response;
struct TALER_EXCHANGE_HttpResponse hr = { struct TALER_EXCHANGE_RecoupResponse rr = {
.reply = j, .hr.reply = j,
.http_status = (unsigned int) response_code .hr.http_status = (unsigned int) response_code
}; };
const struct TALER_EXCHANGE_Keys *keys; const struct TALER_EXCHANGE_Keys *keys;
@ -152,7 +150,7 @@ handle_recoup_finished (void *cls,
switch (response_code) switch (response_code)
{ {
case 0: case 0:
hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; rr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break; break;
case MHD_HTTP_OK: case MHD_HTTP_OK:
if (GNUNET_OK != if (GNUNET_OK !=
@ -160,8 +158,8 @@ handle_recoup_finished (void *cls,
j)) j))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; rr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
hr.http_status = 0; rr.hr.http_status = 0;
break; break;
} }
TALER_EXCHANGE_recoup_cancel (ph); TALER_EXCHANGE_recoup_cancel (ph);
@ -169,22 +167,22 @@ handle_recoup_finished (void *cls,
case MHD_HTTP_BAD_REQUEST: case MHD_HTTP_BAD_REQUEST:
/* This should never happen, either us or the exchange is buggy /* This should never happen, either us or the exchange is buggy
(or API version conflict); just pass JSON reply to the application */ (or API version conflict); just pass JSON reply to the application */
hr.ec = TALER_JSON_get_error_code (j); rr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); rr.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
case MHD_HTTP_CONFLICT: case MHD_HTTP_CONFLICT:
{ {
struct TALER_Amount min_key; struct TALER_Amount min_key;
hr.ec = TALER_JSON_get_error_code (j); rr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); rr.hr.hint = TALER_JSON_get_error_hint (j);
if (GNUNET_OK != if (GNUNET_OK !=
TALER_EXCHANGE_get_min_denomination_ (keys, TALER_EXCHANGE_get_min_denomination_ (keys,
&min_key)) &min_key))
{ {
GNUNET_break (0); GNUNET_break (0);
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; rr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
hr.http_status = 0; rr.hr.http_status = 0;
break; break;
} }
if (GNUNET_OK != if (GNUNET_OK !=
@ -197,8 +195,8 @@ handle_recoup_finished (void *cls,
&min_key)) &min_key))
{ {
GNUNET_break (0); GNUNET_break (0);
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; rr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
hr.http_status = 0; rr.hr.http_status = 0;
break; break;
} }
break; break;
@ -207,41 +205,40 @@ handle_recoup_finished (void *cls,
/* Nothing really to verify, exchange says one of the signatures is /* Nothing really to verify, exchange says one of the signatures is
invalid; as we checked them, this should never happen, we invalid; as we checked them, this should never happen, we
should pass the JSON reply to the application */ should pass the JSON reply to the application */
hr.ec = TALER_JSON_get_error_code (j); rr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); rr.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
case MHD_HTTP_NOT_FOUND: case MHD_HTTP_NOT_FOUND:
/* Nothing really to verify, this should never /* Nothing really to verify, this should never
happen, we should pass the JSON reply to the application */ happen, we should pass the JSON reply to the application */
hr.ec = TALER_JSON_get_error_code (j); rr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); rr.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
case MHD_HTTP_GONE: case MHD_HTTP_GONE:
/* Kind of normal: the money was already sent to the merchant /* Kind of normal: the money was already sent to the merchant
(it was too late for the refund). */ (it was too late for the refund). */
hr.ec = TALER_JSON_get_error_code (j); rr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); rr.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
case MHD_HTTP_INTERNAL_SERVER_ERROR: case MHD_HTTP_INTERNAL_SERVER_ERROR:
/* Server had an internal issue; we should retry, but this API /* Server had an internal issue; we should retry, but this API
leaves this to the application */ leaves this to the application */
hr.ec = TALER_JSON_get_error_code (j); rr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); rr.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
default: default:
/* unexpected response code */ /* unexpected response code */
hr.ec = TALER_JSON_get_error_code (j); rr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); rr.hr.hint = TALER_JSON_get_error_hint (j);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d for exchange recoup\n", "Unexpected response code %u/%d for exchange recoup\n",
(unsigned int) response_code, (unsigned int) response_code,
(int) hr.ec); (int) rr.hr.ec);
GNUNET_break (0); GNUNET_break (0);
break; break;
} }
ph->cb (ph->cb_cls, ph->cb (ph->cb_cls,
&hr, &rr);
NULL);
TALER_EXCHANGE_recoup_cancel (ph); TALER_EXCHANGE_recoup_cancel (ph);
} }

View File

@ -101,16 +101,15 @@ process_recoup_response (
const struct TALER_EXCHANGE_RecoupRefreshHandle *ph, const struct TALER_EXCHANGE_RecoupRefreshHandle *ph,
const json_t *json) const json_t *json)
{ {
struct TALER_CoinSpendPublicKeyP old_coin_pub; struct TALER_EXCHANGE_RecoupRefreshResponse rrr = {
.hr.reply = json,
.hr.http_status = MHD_HTTP_OK
};
struct GNUNET_JSON_Specification spec_refresh[] = { struct GNUNET_JSON_Specification spec_refresh[] = {
GNUNET_JSON_spec_fixed_auto ("old_coin_pub", GNUNET_JSON_spec_fixed_auto ("old_coin_pub",
&old_coin_pub), &rrr.details.ok.old_coin_pub),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
}; };
struct TALER_EXCHANGE_HttpResponse hr = {
.reply = json,
.http_status = MHD_HTTP_OK
};
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_JSON_parse (json, GNUNET_JSON_parse (json,
@ -121,8 +120,7 @@ process_recoup_response (
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
ph->cb (ph->cb_cls, ph->cb (ph->cb_cls,
&hr, &rrr);
&old_coin_pub);
return GNUNET_OK; return GNUNET_OK;
} }
@ -142,9 +140,9 @@ handle_recoup_refresh_finished (void *cls,
{ {
struct TALER_EXCHANGE_RecoupRefreshHandle *ph = cls; struct TALER_EXCHANGE_RecoupRefreshHandle *ph = cls;
const json_t *j = response; const json_t *j = response;
struct TALER_EXCHANGE_HttpResponse hr = { struct TALER_EXCHANGE_RecoupRefreshResponse rrr = {
.reply = j, .hr.reply = j,
.http_status = (unsigned int) response_code .hr.http_status = (unsigned int) response_code
}; };
const struct TALER_EXCHANGE_Keys *keys; const struct TALER_EXCHANGE_Keys *keys;
@ -153,7 +151,7 @@ handle_recoup_refresh_finished (void *cls,
switch (response_code) switch (response_code)
{ {
case 0: case 0:
hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; rrr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break; break;
case MHD_HTTP_OK: case MHD_HTTP_OK:
if (GNUNET_OK != if (GNUNET_OK !=
@ -161,8 +159,8 @@ handle_recoup_refresh_finished (void *cls,
j)) j))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; rrr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
hr.http_status = 0; rrr.hr.http_status = 0;
break; break;
} }
TALER_EXCHANGE_recoup_refresh_cancel (ph); TALER_EXCHANGE_recoup_refresh_cancel (ph);
@ -170,35 +168,35 @@ handle_recoup_refresh_finished (void *cls,
case MHD_HTTP_BAD_REQUEST: case MHD_HTTP_BAD_REQUEST:
/* This should never happen, either us or the exchange is buggy /* This should never happen, either us or the exchange is buggy
(or API version conflict); just pass JSON reply to the application */ (or API version conflict); just pass JSON reply to the application */
hr.ec = TALER_JSON_get_error_code (j); rrr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); rrr.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
case MHD_HTTP_FORBIDDEN: case MHD_HTTP_FORBIDDEN:
/* Nothing really to verify, exchange says one of the signatures is /* Nothing really to verify, exchange says one of the signatures is
invalid; as we checked them, this should never happen, we invalid; as we checked them, this should never happen, we
should pass the JSON reply to the application */ should pass the JSON reply to the application */
hr.ec = TALER_JSON_get_error_code (j); rrr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); rrr.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
case MHD_HTTP_NOT_FOUND: case MHD_HTTP_NOT_FOUND:
/* Nothing really to verify, this should never /* Nothing really to verify, this should never
happen, we should pass the JSON reply to the application */ happen, we should pass the JSON reply to the application */
hr.ec = TALER_JSON_get_error_code (j); rrr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); rrr.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
case MHD_HTTP_CONFLICT: case MHD_HTTP_CONFLICT:
{ {
struct TALER_Amount min_key; struct TALER_Amount min_key;
hr.ec = TALER_JSON_get_error_code (j); rrr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); rrr.hr.hint = TALER_JSON_get_error_hint (j);
if (GNUNET_OK != if (GNUNET_OK !=
TALER_EXCHANGE_get_min_denomination_ (keys, TALER_EXCHANGE_get_min_denomination_ (keys,
&min_key)) &min_key))
{ {
GNUNET_break (0); GNUNET_break (0);
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; rrr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
hr.http_status = 0; rrr.hr.http_status = 0;
break; break;
} }
if (GNUNET_OK != if (GNUNET_OK !=
@ -211,8 +209,8 @@ handle_recoup_refresh_finished (void *cls,
&min_key)) &min_key))
{ {
GNUNET_break (0); GNUNET_break (0);
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; rrr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
hr.http_status = 0; rrr.hr.http_status = 0;
break; break;
} }
break; break;
@ -220,29 +218,28 @@ handle_recoup_refresh_finished (void *cls,
case MHD_HTTP_GONE: case MHD_HTTP_GONE:
/* Kind of normal: the money was already sent to the merchant /* Kind of normal: the money was already sent to the merchant
(it was too late for the refund). */ (it was too late for the refund). */
hr.ec = TALER_JSON_get_error_code (j); rrr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); rrr.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
case MHD_HTTP_INTERNAL_SERVER_ERROR: case MHD_HTTP_INTERNAL_SERVER_ERROR:
/* Server had an internal issue; we should retry, but this API /* Server had an internal issue; we should retry, but this API
leaves this to the application */ leaves this to the application */
hr.ec = TALER_JSON_get_error_code (j); rrr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); rrr.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
default: default:
/* unexpected response code */ /* unexpected response code */
hr.ec = TALER_JSON_get_error_code (j); rrr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); rrr.hr.hint = TALER_JSON_get_error_hint (j);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d for exchange recoup\n", "Unexpected response code %u/%d for exchange recoup\n",
(unsigned int) response_code, (unsigned int) response_code,
(int) hr.ec); (int) rrr.hr.ec);
GNUNET_break (0); GNUNET_break (0);
break; break;
} }
ph->cb (ph->cb_cls, ph->cb (ph->cb_cls,
&hr, &rrr);
NULL);
TALER_EXCHANGE_recoup_refresh_cancel (ph); TALER_EXCHANGE_recoup_refresh_cancel (ph);
} }

View File

@ -266,8 +266,8 @@ handle_refresh_reveal_finished (void *cls,
else else
{ {
GNUNET_assert (rrh->noreveal_index < TALER_CNC_KAPPA); GNUNET_assert (rrh->noreveal_index < TALER_CNC_KAPPA);
rr.details.success.num_coins = rrh->md.num_fresh_coins; rr.details.ok.num_coins = rrh->md.num_fresh_coins;
rr.details.success.coins = rcis; rr.details.ok.coins = rcis;
rrh->reveal_cb (rrh->reveal_cb_cls, rrh->reveal_cb (rrh->reveal_cb_cls,
&rr); &rr);
rrh->reveal_cb = NULL; rrh->reveal_cb = NULL;

View File

@ -585,37 +585,28 @@ handle_refund_finished (void *cls,
const void *response) const void *response)
{ {
struct TALER_EXCHANGE_RefundHandle *rh = cls; struct TALER_EXCHANGE_RefundHandle *rh = cls;
struct TALER_ExchangePublicKeyP exchange_pub;
struct TALER_ExchangeSignatureP exchange_sig;
struct TALER_ExchangePublicKeyP *ep = NULL;
struct TALER_ExchangeSignatureP *es = NULL;
const json_t *j = response; const json_t *j = response;
struct TALER_EXCHANGE_HttpResponse hr = { struct TALER_EXCHANGE_RefundResponse rr = {
.reply = j, .hr.reply = j,
.http_status = (unsigned int) response_code .hr.http_status = (unsigned int) response_code
}; };
rh->job = NULL; rh->job = NULL;
switch (response_code) switch (response_code)
{ {
case 0: case 0:
hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; rr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break; break;
case MHD_HTTP_OK: case MHD_HTTP_OK:
if (GNUNET_OK != if (GNUNET_OK !=
verify_refund_signature_ok (rh, verify_refund_signature_ok (rh,
j, j,
&exchange_pub, &rr.details.ok.exchange_pub,
&exchange_sig)) &rr.details.ok.exchange_sig))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
hr.http_status = 0; rr.hr.http_status = 0;
hr.ec = TALER_EC_EXCHANGE_REFUND_INVALID_SIGNATURE_BY_EXCHANGE; rr.hr.ec = TALER_EC_EXCHANGE_REFUND_INVALID_SIGNATURE_BY_EXCHANGE;
}
else
{
ep = &exchange_pub;
es = &exchange_sig;
} }
break; break;
case MHD_HTTP_BAD_REQUEST: case MHD_HTTP_BAD_REQUEST:
@ -623,21 +614,21 @@ handle_refund_finished (void *cls,
(or API version conflict); also can happen if the currency (or API version conflict); also can happen if the currency
differs (which we should obviously never support). differs (which we should obviously never support).
Just pass JSON reply to the application */ Just pass JSON reply to the application */
hr.ec = TALER_JSON_get_error_code (j); rr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); rr.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
case MHD_HTTP_FORBIDDEN: case MHD_HTTP_FORBIDDEN:
/* Nothing really to verify, exchange says one of the signatures is /* Nothing really to verify, exchange says one of the signatures is
invalid; as we checked them, this should never happen, we invalid; as we checked them, this should never happen, we
should pass the JSON reply to the application */ should pass the JSON reply to the application */
hr.ec = TALER_JSON_get_error_code (j); rr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); rr.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
case MHD_HTTP_NOT_FOUND: case MHD_HTTP_NOT_FOUND:
/* Nothing really to verify, this should never /* Nothing really to verify, this should never
happen, we should pass the JSON reply to the application */ happen, we should pass the JSON reply to the application */
hr.ec = TALER_JSON_get_error_code (j); rr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); rr.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
case MHD_HTTP_CONFLICT: case MHD_HTTP_CONFLICT:
/* Requested total refunds exceed deposited amount */ /* Requested total refunds exceed deposited amount */
@ -649,19 +640,19 @@ handle_refund_finished (void *cls,
json_dumpf (j, json_dumpf (j,
stderr, stderr,
JSON_INDENT (2)); JSON_INDENT (2));
hr.http_status = 0; rr.hr.http_status = 0;
hr.ec = TALER_EC_EXCHANGE_REFUND_INVALID_FAILURE_PROOF_BY_EXCHANGE; rr.hr.ec = TALER_EC_EXCHANGE_REFUND_INVALID_FAILURE_PROOF_BY_EXCHANGE;
hr.hint = "conflict information provided by exchange is invalid"; rr.hr.hint = "conflict information provided by exchange is invalid";
break; break;
} }
hr.ec = TALER_JSON_get_error_code (j); rr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); rr.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
case MHD_HTTP_GONE: case MHD_HTTP_GONE:
/* Kind of normal: the money was already sent to the merchant /* Kind of normal: the money was already sent to the merchant
(it was too late for the refund). */ (it was too late for the refund). */
hr.ec = TALER_JSON_get_error_code (j); rr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); rr.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
case MHD_HTTP_PRECONDITION_FAILED: case MHD_HTTP_PRECONDITION_FAILED:
if (GNUNET_OK != if (GNUNET_OK !=
@ -669,37 +660,35 @@ handle_refund_finished (void *cls,
j)) j))
{ {
GNUNET_break (0); GNUNET_break (0);
hr.http_status = 0; rr.hr.http_status = 0;
hr.ec = TALER_EC_EXCHANGE_REFUND_INVALID_FAILURE_PROOF_BY_EXCHANGE; rr.hr.ec = TALER_EC_EXCHANGE_REFUND_INVALID_FAILURE_PROOF_BY_EXCHANGE;
hr.hint = "failed precondition proof returned by exchange is invalid"; rr.hr.hint = "failed precondition proof returned by exchange is invalid";
break; break;
} }
/* Two different refund requests were made about the same deposit, but /* Two different refund requests were made about the same deposit, but
carrying identical refund transaction ids. */ carrying identical refund transaction ids. */
hr.ec = TALER_JSON_get_error_code (j); rr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); rr.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
case MHD_HTTP_INTERNAL_SERVER_ERROR: case MHD_HTTP_INTERNAL_SERVER_ERROR:
/* Server had an internal issue; we should retry, but this API /* Server had an internal issue; we should retry, but this API
leaves this to the application */ leaves this to the application */
hr.ec = TALER_JSON_get_error_code (j); rr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); rr.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
default: default:
/* unexpected response code */ /* unexpected response code */
GNUNET_break_op (0); GNUNET_break_op (0);
hr.ec = TALER_JSON_get_error_code (j); rr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); rr.hr.hint = TALER_JSON_get_error_hint (j);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d for exchange refund\n", "Unexpected response code %u/%d for exchange refund\n",
(unsigned int) response_code, (unsigned int) response_code,
hr.ec); rr.hr.ec);
break; break;
} }
rh->cb (rh->cb_cls, rh->cb (rh->cb_cls,
&hr, &rr);
ep,
es);
TALER_EXCHANGE_refund_cancel (rh); TALER_EXCHANGE_refund_cancel (rh);
} }

View File

@ -85,23 +85,32 @@ check_transfers_get_response_ok (
const json_t *json) const json_t *json)
{ {
json_t *details_j; json_t *details_j;
struct TALER_EXCHANGE_TransferData td;
struct TALER_Amount total_expected; struct TALER_Amount total_expected;
struct TALER_MerchantPublicKeyP merchant_pub; struct TALER_MerchantPublicKeyP merchant_pub;
struct GNUNET_JSON_Specification spec[] = { struct TALER_EXCHANGE_TransfersGetResponse tgr = {
TALER_JSON_spec_amount_any ("total", &td.total_amount), .hr.reply = json,
TALER_JSON_spec_amount_any ("wire_fee", &td.wire_fee), .hr.http_status = MHD_HTTP_OK
GNUNET_JSON_spec_fixed_auto ("merchant_pub", &merchant_pub),
GNUNET_JSON_spec_fixed_auto ("h_payto", &td.h_payto),
GNUNET_JSON_spec_timestamp ("execution_time", &td.execution_time),
GNUNET_JSON_spec_json ("deposits", &details_j),
GNUNET_JSON_spec_fixed_auto ("exchange_sig", &td.exchange_sig),
GNUNET_JSON_spec_fixed_auto ("exchange_pub", &td.exchange_pub),
GNUNET_JSON_spec_end ()
}; };
struct TALER_EXCHANGE_HttpResponse hr = { struct TALER_EXCHANGE_TransferData *td
.reply = json, = &tgr.details.ok.td;
.http_status = MHD_HTTP_OK struct GNUNET_JSON_Specification spec[] = {
TALER_JSON_spec_amount_any ("total",
&td->total_amount),
TALER_JSON_spec_amount_any ("wire_fee",
&td->wire_fee),
GNUNET_JSON_spec_fixed_auto ("merchant_pub",
&merchant_pub),
GNUNET_JSON_spec_fixed_auto ("h_payto",
&td->h_payto),
GNUNET_JSON_spec_timestamp ("execution_time",
&td->execution_time),
GNUNET_JSON_spec_json ("deposits",
&details_j),
GNUNET_JSON_spec_fixed_auto ("exchange_sig",
&td->exchange_sig),
GNUNET_JSON_spec_fixed_auto ("exchange_pub",
&td->exchange_pub),
GNUNET_JSON_spec_end ()
}; };
if (GNUNET_OK != if (GNUNET_OK !=
@ -113,7 +122,7 @@ check_transfers_get_response_ok (
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
if (GNUNET_OK != if (GNUNET_OK !=
TALER_amount_set_zero (td.total_amount.currency, TALER_amount_set_zero (td->total_amount.currency,
&total_expected)) &total_expected))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
@ -123,22 +132,22 @@ check_transfers_get_response_ok (
if (GNUNET_OK != if (GNUNET_OK !=
TALER_EXCHANGE_test_signing_key ( TALER_EXCHANGE_test_signing_key (
TALER_EXCHANGE_get_keys (wdh->exchange), TALER_EXCHANGE_get_keys (wdh->exchange),
&td.exchange_pub)) &td->exchange_pub))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
td.details_length = json_array_size (details_j); td->details_length = json_array_size (details_j);
{ {
struct GNUNET_HashContext *hash_context; struct GNUNET_HashContext *hash_context;
struct TALER_TrackTransferDetails *details; struct TALER_TrackTransferDetails *details;
details = GNUNET_new_array (td.details_length, details = GNUNET_new_array (td->details_length,
struct TALER_TrackTransferDetails); struct TALER_TrackTransferDetails);
td.details = details; td->details = details;
hash_context = GNUNET_CRYPTO_hash_context_start (); hash_context = GNUNET_CRYPTO_hash_context_start ();
for (unsigned int i = 0; i<td.details_length; i++) for (unsigned int i = 0; i<td->details_length; i++)
{ {
struct TALER_TrackTransferDetails *detail = &details[i]; struct TALER_TrackTransferDetails *detail = &details[i];
struct json_t *detail_j = json_array_get (details_j, i); struct json_t *detail_j = json_array_get (details_j, i);
@ -180,7 +189,7 @@ check_transfers_get_response_ok (
TALER_exchange_online_wire_deposit_append ( TALER_exchange_online_wire_deposit_append (
hash_context, hash_context,
&detail->h_contract_terms, &detail->h_contract_terms,
td.execution_time, td->execution_time,
&detail->coin_pub, &detail->coin_pub,
&detail->coin_value, &detail->coin_value,
&detail->coin_fee); &detail->coin_fee);
@ -193,13 +202,13 @@ check_transfers_get_response_ok (
&h_details); &h_details);
if (GNUNET_OK != if (GNUNET_OK !=
TALER_exchange_online_wire_deposit_verify ( TALER_exchange_online_wire_deposit_verify (
&td.total_amount, &td->total_amount,
&td.wire_fee, &td->wire_fee,
&merchant_pub, &merchant_pub,
&td.h_payto, &td->h_payto,
&h_details, &h_details,
&td.exchange_pub, &td->exchange_pub,
&td.exchange_sig)) &td->exchange_sig))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
@ -211,7 +220,7 @@ check_transfers_get_response_ok (
if (0 > if (0 >
TALER_amount_subtract (&total_expected, TALER_amount_subtract (&total_expected,
&total_expected, &total_expected,
&td.wire_fee)) &td->wire_fee))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
@ -220,7 +229,7 @@ check_transfers_get_response_ok (
} }
if (0 != if (0 !=
TALER_amount_cmp (&total_expected, TALER_amount_cmp (&total_expected,
&td.total_amount)) &td->total_amount))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
@ -228,8 +237,7 @@ check_transfers_get_response_ok (
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
wdh->cb (wdh->cb_cls, wdh->cb (wdh->cb_cls,
&hr, &tgr);
&td);
GNUNET_free (details); GNUNET_free (details);
} }
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
@ -253,16 +261,16 @@ handle_transfers_get_finished (void *cls,
{ {
struct TALER_EXCHANGE_TransfersGetHandle *wdh = cls; struct TALER_EXCHANGE_TransfersGetHandle *wdh = cls;
const json_t *j = response; const json_t *j = response;
struct TALER_EXCHANGE_HttpResponse hr = { struct TALER_EXCHANGE_TransfersGetResponse tgr = {
.reply = j, .hr.reply = j,
.http_status = (unsigned int) response_code .hr.http_status = (unsigned int) response_code
}; };
wdh->job = NULL; wdh->job = NULL;
switch (response_code) switch (response_code)
{ {
case 0: case 0:
hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; tgr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break; break;
case MHD_HTTP_OK: case MHD_HTTP_OK:
if (GNUNET_OK == if (GNUNET_OK ==
@ -270,48 +278,47 @@ handle_transfers_get_finished (void *cls,
j)) j))
return; return;
GNUNET_break_op (0); GNUNET_break_op (0);
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; tgr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
hr.http_status = 0; tgr.hr.http_status = 0;
break; break;
case MHD_HTTP_BAD_REQUEST: case MHD_HTTP_BAD_REQUEST:
/* This should never happen, either us or the exchange is buggy /* This should never happen, either us or the exchange is buggy
(or API version conflict); just pass JSON reply to the application */ (or API version conflict); just pass JSON reply to the application */
hr.ec = TALER_JSON_get_error_code (j); tgr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); tgr.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
case MHD_HTTP_FORBIDDEN: case MHD_HTTP_FORBIDDEN:
/* Nothing really to verify, exchange says one of the signatures is /* Nothing really to verify, exchange says one of the signatures is
invalid; as we checked them, this should never happen, we invalid; as we checked them, this should never happen, we
should pass the JSON reply to the application */ should pass the JSON reply to the application */
hr.ec = TALER_JSON_get_error_code (j); tgr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); tgr.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
case MHD_HTTP_NOT_FOUND: case MHD_HTTP_NOT_FOUND:
/* Exchange does not know about transaction; /* Exchange does not know about transaction;
we should pass the reply to the application */ we should pass the reply to the application */
hr.ec = TALER_JSON_get_error_code (j); tgr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); tgr.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
case MHD_HTTP_INTERNAL_SERVER_ERROR: case MHD_HTTP_INTERNAL_SERVER_ERROR:
/* Server had an internal issue; we should retry, but this API /* Server had an internal issue; we should retry, but this API
leaves this to the application */ leaves this to the application */
hr.ec = TALER_JSON_get_error_code (j); tgr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); tgr.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
default: default:
/* unexpected response code */ /* unexpected response code */
GNUNET_break_op (0); GNUNET_break_op (0);
hr.ec = TALER_JSON_get_error_code (j); tgr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); tgr.hr.hint = TALER_JSON_get_error_hint (j);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d for transfers get\n", "Unexpected response code %u/%d for transfers get\n",
(unsigned int) response_code, (unsigned int) response_code,
(int) hr.ec); (int) tgr.hr.ec);
break; break;
} }
wdh->cb (wdh->cb_cls, wdh->cb (wdh->cb_cls,
&hr, &tgr);
NULL);
TALER_EXCHANGE_transfers_get_cancel (wdh); TALER_EXCHANGE_transfers_get_cancel (wdh);
} }

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2014-2022 Taler Systems SA Copyright (C) 2014-2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the 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 terms of the GNU General Public License as published by the Free Software
@ -66,82 +66,65 @@ struct TALER_EXCHANGE_WireHandle
/** /**
* List of wire fees by method. * Frees @a wfm array.
*/
struct FeeMap
{
/**
* Next entry in list.
*/
struct FeeMap *next;
/**
* Wire method this fee structure is for.
*/
char *method;
/**
* Array of wire fees, also linked list, but allocated
* only once.
*/
struct TALER_EXCHANGE_WireAggregateFees *fee_list;
};
/**
* Frees @a fm.
* *
* @param fm memory to release * @param wfm fee array to release
* @param wfm_len length of the @a wfm array
*/ */
static void static void
free_fees (struct FeeMap *fm) free_fees (struct TALER_EXCHANGE_WireFeesByMethod *wfm,
unsigned int wfm_len)
{ {
while (NULL != fm) for (unsigned int i = 0; i<wfm_len; i++)
{ {
struct FeeMap *fe = fm->next; struct TALER_EXCHANGE_WireFeesByMethod *wfmi = &wfm[i];
GNUNET_free (fm->fee_list); while (NULL != wfmi->fees_head)
GNUNET_free (fm->method); {
GNUNET_free (fm); struct TALER_EXCHANGE_WireAggregateFees *fe
fm = fe; = wfmi->fees_head;
wfmi->fees_head = fe->next;
GNUNET_free (fe);
}
} }
GNUNET_free (wfm);
} }
/** /**
* Parse wire @a fees and return map. * Parse wire @a fees and return array.
* *
* @param master_pub master public key to use to check signatures * @param master_pub master public key to use to check signatures
* @param fees json AggregateTransferFee to parse * @param fees json AggregateTransferFee to parse
* @param[out] fees_len set to length of returned array
* @return NULL on error * @return NULL on error
*/ */
static struct FeeMap * static struct TALER_EXCHANGE_WireFeesByMethod *
parse_fees (const struct TALER_MasterPublicKeyP *master_pub, parse_fees (const struct TALER_MasterPublicKeyP *master_pub,
json_t *fees) const json_t *fees,
unsigned int *fees_len)
{ {
struct FeeMap *fm = NULL; struct TALER_EXCHANGE_WireFeesByMethod *fbm;
unsigned int fbml = json_object_size (fees);
unsigned int i = 0;
const char *key; const char *key;
json_t *fee_array; const json_t *fee_array;
json_object_foreach (fees, key, fee_array) { fbm = GNUNET_new_array (fbml,
struct FeeMap *fe = GNUNET_new (struct FeeMap); struct TALER_EXCHANGE_WireFeesByMethod);
unsigned int len; *fees_len = fbml;
json_object_foreach ((json_t *) fees, key, fee_array) {
struct TALER_EXCHANGE_WireFeesByMethod *fe = &fbm[i++];
unsigned int idx; unsigned int idx;
json_t *fee; json_t *fee;
if (0 == (len = json_array_size (fee_array))) fe->method = key;
{ fe->fees_head = NULL;
GNUNET_free (fe);
continue; /* skip */
}
fe->method = GNUNET_strdup (key);
fe->next = fm;
fe->fee_list = GNUNET_new_array (len,
struct TALER_EXCHANGE_WireAggregateFees);
fm = fe;
json_array_foreach (fee_array, idx, fee) json_array_foreach (fee_array, idx, fee)
{ {
struct TALER_EXCHANGE_WireAggregateFees *wa = &fe->fee_list[idx]; struct TALER_EXCHANGE_WireAggregateFees *wa
= GNUNET_new (struct TALER_EXCHANGE_WireAggregateFees);
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("sig", GNUNET_JSON_spec_fixed_auto ("sig",
&wa->master_sig), &wa->master_sig),
@ -156,6 +139,8 @@ parse_fees (const struct TALER_MasterPublicKeyP *master_pub,
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
}; };
wa->next = fe->fees_head;
fe->fees_head = wa;
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_JSON_parse (fee, GNUNET_JSON_parse (fee,
spec, spec,
@ -163,7 +148,8 @@ parse_fees (const struct TALER_MasterPublicKeyP *master_pub,
NULL)) NULL))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
free_fees (fm); free_fees (fbm,
i);
return NULL; return NULL;
} }
if (GNUNET_OK != if (GNUNET_OK !=
@ -176,35 +162,122 @@ parse_fees (const struct TALER_MasterPublicKeyP *master_pub,
&wa->master_sig)) &wa->master_sig))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
free_fees (fm); free_fees (fbm,
i);
return NULL; return NULL;
} }
if (idx + 1 < len) } /* for all fees over time */
wa->next = &fe->fee_list[idx + 1]; } /* for all methods */
else GNUNET_assert (i == fbml);
wa->next = NULL; return fbm;
}
}
return fm;
} }
/** /**
* Find fee by @a method. * Parse account restriction in @a jrest into @a rest.
* *
* @param fm map to look in * @param jrest array of account restrictions in JSON
* @param method key to look for * @param[out] resta_len set to length of @a resta
* @return NULL if fee is not specified in @a fm * @param[out] resta account restriction array to set
* @return #GNUNET_OK on success
*/ */
static const struct TALER_EXCHANGE_WireAggregateFees * static enum GNUNET_GenericReturnValue
lookup_fee (const struct FeeMap *fm, parse_restrictions (const json_t *jresta,
const char *method) unsigned int *resta_len,
struct TALER_EXCHANGE_AccountRestriction **resta)
{ {
for (; NULL != fm; fm = fm->next) if (! json_is_array (jresta))
if (0 == strcasecmp (fm->method, {
method)) GNUNET_break_op (0);
return fm->fee_list; return GNUNET_SYSERR;
return NULL; }
*resta_len = json_array_size (jresta);
if (0 == *resta_len)
{
/* no restrictions, perfectly OK */
*resta = NULL;
return GNUNET_OK;
}
*resta = GNUNET_new_array (*resta_len,
struct TALER_EXCHANGE_AccountRestriction);
for (unsigned int i = 0; i<*resta_len; i++)
{
const json_t *jr = json_array_get (jresta,
i);
struct TALER_EXCHANGE_AccountRestriction *ar = &(*resta)[i];
const char *type = json_string_value (json_object_get (jr,
"type"));
if (NULL == type)
{
GNUNET_break (0);
goto fail;
}
if (0 == strcmp (type,
"deny"))
{
ar->type = TALER_EXCHANGE_AR_DENY;
continue;
}
if (0 == strcmp (type,
"regex"))
{
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_string (
"payto_regex",
&ar->details.regex.posix_egrep),
GNUNET_JSON_spec_string (
"human_hint",
&ar->details.regex.human_hint),
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_object_const (
"human_hint_i18n",
&ar->details.regex.human_hint_i18n),
NULL),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (jr,
spec,
NULL, NULL))
{
/* bogus reply */
GNUNET_break_op (0);
goto fail;
}
ar->type = TALER_EXCHANGE_AR_REGEX;
continue;
}
/* unsupported type */
GNUNET_break (0);
return GNUNET_SYSERR;
}
return GNUNET_OK;
fail:
GNUNET_free (*resta);
*resta_len = 0;
return GNUNET_SYSERR;
}
/**
* Free data within @a was, but not @a was itself.
*
* @param was array of wire account data
* @param was_len length of the @a was array
*/
static void
free_accounts (struct TALER_EXCHANGE_WireAccount *was,
unsigned int was_len)
{
for (unsigned int i = 0; i<was_len; i++)
{
struct TALER_EXCHANGE_WireAccount *wa = &was[i];
GNUNET_free (wa->credit_restrictions);
GNUNET_free (wa->debit_restrictions);
}
} }
@ -223,9 +296,9 @@ handle_wire_finished (void *cls,
{ {
struct TALER_EXCHANGE_WireHandle *wh = cls; struct TALER_EXCHANGE_WireHandle *wh = cls;
const json_t *j = response; const json_t *j = response;
struct TALER_EXCHANGE_HttpResponse hr = { struct TALER_EXCHANGE_WireResponse wr = {
.reply = j, .hr.reply = j,
.http_status = (unsigned int) response_code .hr.http_status = (unsigned int) response_code
}; };
TALER_LOG_DEBUG ("Checking raw /wire response\n"); TALER_LOG_DEBUG ("Checking raw /wire response\n");
@ -233,28 +306,29 @@ handle_wire_finished (void *cls,
switch (response_code) switch (response_code)
{ {
case 0: case 0:
hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; wr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
wh->exchange->wire_error_count++; wh->exchange->wire_error_count++;
break; break;
case MHD_HTTP_OK: case MHD_HTTP_OK:
{ {
json_t *accounts; const json_t *accounts;
json_t *fees; const json_t *fees;
unsigned int num_accounts; const json_t *wads;
struct FeeMap *fm; struct TALER_EXCHANGE_WireFeesByMethod *fbm;
struct TALER_MasterPublicKeyP master_pub; struct TALER_MasterPublicKeyP master_pub;
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("master_public_key", GNUNET_JSON_spec_fixed_auto ("master_public_key",
&master_pub), &master_pub),
GNUNET_JSON_spec_json ("accounts", GNUNET_JSON_spec_array_const ("accounts",
&accounts), &accounts),
GNUNET_JSON_spec_json ("fees", GNUNET_JSON_spec_object_const ("fees",
&fees), &fees),
GNUNET_JSON_spec_array_const ("wads",
&wads),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
}; };
wh->exchange->wire_error_count = 0; wh->exchange->wire_error_count = 0;
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_JSON_parse (j, GNUNET_JSON_parse (j,
spec, spec,
@ -262,8 +336,8 @@ handle_wire_finished (void *cls,
{ {
/* bogus reply */ /* bogus reply */
GNUNET_break_op (0); GNUNET_break_op (0);
hr.http_status = 0; wr.hr.http_status = 0;
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
break; break;
} }
{ {
@ -275,61 +349,70 @@ handle_wire_finished (void *cls,
{ {
/* bogus reply: master public key in /wire differs from that in /keys */ /* bogus reply: master public key in /wire differs from that in /keys */
GNUNET_break_op (0); GNUNET_break_op (0);
hr.http_status = 0; wr.hr.http_status = 0;
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
break; break;
} }
} }
if (0 == (num_accounts = json_array_size (accounts))) wr.details.ok.accounts_len
= json_array_size (accounts);
if (0 == wr.details.ok.accounts_len)
{ {
/* bogus reply */ /* bogus reply */
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
hr.http_status = 0; wr.hr.http_status = 0;
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
break; break;
} }
if (NULL == (fm = parse_fees (&master_pub, fbm = parse_fees (&master_pub,
fees))) fees,
&wr.details.ok.fees_len);
if (NULL == fbm)
{ {
/* bogus reply */ /* bogus reply */
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
hr.http_status = 0; wr.hr.http_status = 0;
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
break; break;
} }
/* parse accounts */ /* parse accounts */
{ {
struct TALER_EXCHANGE_WireAccount was[num_accounts]; struct TALER_EXCHANGE_WireAccount was[wr.details.ok.accounts_len];
for (unsigned int i = 0; i<num_accounts; i++) memset (was,
0,
sizeof (was));
wr.details.ok.accounts = was;
for (unsigned int i = 0;
i<wr.details.ok.accounts_len;
i++)
{ {
struct TALER_EXCHANGE_WireAccount *wa = &was[i]; struct TALER_EXCHANGE_WireAccount *wa = &was[i];
json_t *account; json_t *credit_restrictions;
json_t *debit_restrictions;
struct GNUNET_JSON_Specification spec_account[] = { struct GNUNET_JSON_Specification spec_account[] = {
GNUNET_JSON_spec_string ("payto_uri", GNUNET_JSON_spec_string ("payto_uri",
&wa->payto_uri), &wa->payto_uri),
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_string ("conversion_url",
&wa->conversion_url),
NULL),
GNUNET_JSON_spec_json ("credit_restrictions",
&credit_restrictions),
GNUNET_JSON_spec_json ("debit_restrictions",
&debit_restrictions),
GNUNET_JSON_spec_fixed_auto ("master_sig", GNUNET_JSON_spec_fixed_auto ("master_sig",
&wa->master_sig), &wa->master_sig),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
}; };
char *method; json_t *account;
account = json_array_get (accounts, account = json_array_get (accounts,
i); i);
if (GNUNET_OK !=
TALER_JSON_exchange_wire_signature_check (account,
&master_pub))
{
/* bogus reply */
GNUNET_break_op (0);
hr.http_status = 0;
hr.ec = TALER_EC_EXCHANGE_WIRE_SIGNATURE_INVALID;
break;
}
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_JSON_parse (account, GNUNET_JSON_parse (account,
spec_account, spec_account,
@ -337,80 +420,104 @@ handle_wire_finished (void *cls,
{ {
/* bogus reply */ /* bogus reply */
GNUNET_break_op (0); GNUNET_break_op (0);
hr.http_status = 0; wr.hr.http_status = 0;
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
break; break;
} }
if (NULL == (method = TALER_payto_get_method (wa->payto_uri))) {
char *err;
err = TALER_payto_validate (wa->payto_uri);
if (NULL != err)
{
GNUNET_break_op (0);
wr.hr.http_status = 0;
wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
GNUNET_free (err);
break;
}
}
if (GNUNET_OK !=
TALER_exchange_wire_signature_check (wa->payto_uri,
wa->conversion_url,
debit_restrictions,
credit_restrictions,
&master_pub,
&wa->master_sig))
{ {
/* bogus reply */ /* bogus reply */
GNUNET_break_op (0); GNUNET_break_op (0);
hr.http_status = 0; wr.hr.http_status = 0;
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; wr.hr.ec = TALER_EC_EXCHANGE_WIRE_SIGNATURE_INVALID;
break; break;
} }
if (NULL == (wa->fees = lookup_fee (fm, if ( (GNUNET_OK !=
method))) parse_restrictions (credit_restrictions,
&wa->credit_restrictions_length,
&wa->credit_restrictions)) ||
(GNUNET_OK !=
parse_restrictions (debit_restrictions,
&wa->debit_restrictions_length,
&wa->debit_restrictions)) )
{ {
/* bogus reply */ /* bogus reply */
GNUNET_break_op (0); GNUNET_break_op (0);
hr.http_status = 0; wr.hr.http_status = 0;
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
GNUNET_free (method);
break; break;
} }
GNUNET_free (method); GNUNET_JSON_parse_free (spec_account);
} /* end 'for all accounts */ } /* end 'for all accounts */
if ( (0 != response_code) && if ( (0 != wr.hr.http_status) &&
(NULL != wh->cb) ) (NULL != wh->cb) )
{ {
wh->cb (wh->cb_cls, wh->cb (wh->cb_cls,
&hr, &wr);
num_accounts,
was);
wh->cb = NULL; wh->cb = NULL;
} }
free_accounts (was,
wr.details.ok.accounts_len);
} /* end of 'parse accounts */ } /* end of 'parse accounts */
free_fees (fm); free_fees (fbm,
wr.details.ok.fees_len);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
} /* end of MHD_HTTP_OK */ } /* end of MHD_HTTP_OK */
break; break;
case MHD_HTTP_BAD_REQUEST: case MHD_HTTP_BAD_REQUEST:
/* This should never happen, either us or the exchange is buggy /* This should never happen, either us or the exchange is buggy
(or API version conflict); just pass JSON reply to the application */ (or API version conflict); just pass JSON reply to the application */
hr.ec = TALER_JSON_get_error_code (j); wr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); wr.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
case MHD_HTTP_NOT_FOUND: case MHD_HTTP_NOT_FOUND:
/* Nothing really to verify, this should never /* Nothing really to verify, this should never
happen, we should pass the JSON reply to the application */ happen, we should pass the JSON reply to the application */
hr.ec = TALER_JSON_get_error_code (j); wr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); wr.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
case MHD_HTTP_INTERNAL_SERVER_ERROR: case MHD_HTTP_INTERNAL_SERVER_ERROR:
/* Server had an internal issue; we should retry, but this API /* Server had an internal issue; we should retry, but this API
leaves this to the application */ leaves this to the application */
hr.ec = TALER_JSON_get_error_code (j); wr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); wr.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
default: default:
/* unexpected response code */ /* unexpected response code */
if (MHD_HTTP_GATEWAY_TIMEOUT == response_code) if (MHD_HTTP_GATEWAY_TIMEOUT == response_code)
wh->exchange->wire_error_count++; wh->exchange->wire_error_count++;
GNUNET_break_op (0); GNUNET_break_op (0);
hr.ec = TALER_JSON_get_error_code (j); wr.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); wr.hr.hint = TALER_JSON_get_error_hint (j);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d for exchange wire\n", "Unexpected response code %u/%d for exchange wire\n",
(unsigned int) response_code, (unsigned int) response_code,
(int) hr.ec); (int) wr.hr.ec);
break; break;
} }
if (NULL != wh->cb) if (NULL != wh->cb)
wh->cb (wh->cb_cls, wh->cb (wh->cb_cls,
&hr, &wr);
0,
NULL);
TALER_EXCHANGE_wire_cancel (wh); TALER_EXCHANGE_wire_cancel (wh);
} }

View File

@ -116,22 +116,20 @@ struct TALER_EXCHANGE_WithdrawHandle
* HTTP /reserves/$RESERVE_PUB/withdraw request. * HTTP /reserves/$RESERVE_PUB/withdraw request.
* *
* @param cls the `struct TALER_EXCHANGE_WithdrawHandle` * @param cls the `struct TALER_EXCHANGE_WithdrawHandle`
* @param hr HTTP response data * @param w2r response data
* @param blind_sig blind signature over the coin, NULL on error
*/ */
static void static void
handle_reserve_withdraw_finished ( handle_reserve_withdraw_finished (
void *cls, void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr, const struct TALER_EXCHANGE_Withdraw2Response *w2r)
const struct TALER_BlindedDenominationSignature *blind_sig)
{ {
struct TALER_EXCHANGE_WithdrawHandle *wh = cls; struct TALER_EXCHANGE_WithdrawHandle *wh = cls;
struct TALER_EXCHANGE_WithdrawResponse wr = { struct TALER_EXCHANGE_WithdrawResponse wr = {
.hr = *hr .hr = w2r->hr
}; };
wh->wh2 = NULL; wh->wh2 = NULL;
switch (hr->http_status) switch (w2r->hr.http_status)
{ {
case MHD_HTTP_OK: case MHD_HTTP_OK:
{ {
@ -139,7 +137,7 @@ handle_reserve_withdraw_finished (
if (GNUNET_OK != if (GNUNET_OK !=
TALER_planchet_to_coin (&wh->pk.key, TALER_planchet_to_coin (&wh->pk.key,
blind_sig, &w2r->details.ok.blind_sig,
&wh->bks, &wh->bks,
&wh->priv, &wh->priv,
wh->ach, wh->ach,
@ -151,10 +149,10 @@ handle_reserve_withdraw_finished (
wr.hr.ec = TALER_EC_EXCHANGE_WITHDRAW_UNBLIND_FAILURE; wr.hr.ec = TALER_EC_EXCHANGE_WITHDRAW_UNBLIND_FAILURE;
break; break;
} }
wr.details.success.coin_priv = wh->priv; wr.details.ok.coin_priv = wh->priv;
wr.details.success.bks = wh->bks; wr.details.ok.bks = wh->bks;
wr.details.success.sig = fc.sig; wr.details.ok.sig = fc.sig;
wr.details.success.exchange_vals = wh->alg_values; wr.details.ok.exchange_vals = wh->alg_values;
break; break;
} }
case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
@ -170,7 +168,7 @@ handle_reserve_withdraw_finished (
}; };
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_JSON_parse (hr->reply, GNUNET_JSON_parse (w2r->hr.reply,
spec, spec,
NULL, NULL)) NULL, NULL))
{ {
@ -186,8 +184,8 @@ handle_reserve_withdraw_finished (
} }
wh->cb (wh->cb_cls, wh->cb (wh->cb_cls,
&wr); &wr);
if (MHD_HTTP_OK == hr->http_status) if (MHD_HTTP_OK == w2r->hr.http_status)
TALER_denom_sig_free (&wr.details.success.sig); TALER_denom_sig_free (&wr.details.ok.sig);
TALER_EXCHANGE_withdraw_cancel (wh); TALER_EXCHANGE_withdraw_cancel (wh);
} }
@ -213,7 +211,7 @@ withdraw_cs_stage_two_callback (
switch (csrr->hr.http_status) switch (csrr->hr.http_status)
{ {
case MHD_HTTP_OK: case MHD_HTTP_OK:
wh->alg_values = csrr->details.success.alg_values; wh->alg_values = csrr->details.ok.alg_values;
TALER_planchet_setup_coin_priv (&wh->ps, TALER_planchet_setup_coin_priv (&wh->ps,
&wh->alg_values, &wh->alg_values,
&wh->priv); &wh->priv);

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2014-2022 Taler Systems SA Copyright (C) 2014-2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the 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 terms of the GNU General Public License as published by the Free Software
@ -99,16 +99,15 @@ static enum GNUNET_GenericReturnValue
reserve_withdraw_ok (struct TALER_EXCHANGE_Withdraw2Handle *wh, reserve_withdraw_ok (struct TALER_EXCHANGE_Withdraw2Handle *wh,
const json_t *json) const json_t *json)
{ {
struct TALER_BlindedDenominationSignature blind_sig; struct TALER_EXCHANGE_Withdraw2Response w2r = {
.hr.reply = json,
.hr.http_status = MHD_HTTP_OK
};
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
TALER_JSON_spec_blinded_denom_sig ("ev_sig", TALER_JSON_spec_blinded_denom_sig ("ev_sig",
&blind_sig), &w2r.details.ok.blind_sig),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
}; };
struct TALER_EXCHANGE_HttpResponse hr = {
.reply = json,
.http_status = MHD_HTTP_OK
};
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_JSON_parse (json, GNUNET_JSON_parse (json,
@ -121,8 +120,7 @@ reserve_withdraw_ok (struct TALER_EXCHANGE_Withdraw2Handle *wh,
/* signature is valid, return it to the application */ /* signature is valid, return it to the application */
wh->cb (wh->cb_cls, wh->cb (wh->cb_cls,
&hr, &w2r);
&blind_sig);
/* make sure callback isn't called again after return */ /* make sure callback isn't called again after return */
wh->cb = NULL; wh->cb = NULL;
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
@ -240,16 +238,16 @@ handle_reserve_withdraw_finished (void *cls,
{ {
struct TALER_EXCHANGE_Withdraw2Handle *wh = cls; struct TALER_EXCHANGE_Withdraw2Handle *wh = cls;
const json_t *j = response; const json_t *j = response;
struct TALER_EXCHANGE_HttpResponse hr = { struct TALER_EXCHANGE_Withdraw2Response w2r = {
.reply = j, .hr.reply = j,
.http_status = (unsigned int) response_code .hr.http_status = (unsigned int) response_code
}; };
wh->job = NULL; wh->job = NULL;
switch (response_code) switch (response_code)
{ {
case 0: case 0:
hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; w2r.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break; break;
case MHD_HTTP_OK: case MHD_HTTP_OK:
if (GNUNET_OK != if (GNUNET_OK !=
@ -257,8 +255,8 @@ handle_reserve_withdraw_finished (void *cls,
j)) j))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
hr.http_status = 0; w2r.hr.http_status = 0;
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; w2r.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
break; break;
} }
GNUNET_assert (NULL == wh->cb); GNUNET_assert (NULL == wh->cb);
@ -267,24 +265,24 @@ handle_reserve_withdraw_finished (void *cls,
case MHD_HTTP_BAD_REQUEST: case MHD_HTTP_BAD_REQUEST:
/* This should never happen, either us or the exchange is buggy /* This should never happen, either us or the exchange is buggy
(or API version conflict); just pass JSON reply to the application */ (or API version conflict); just pass JSON reply to the application */
hr.ec = TALER_JSON_get_error_code (j); w2r.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); w2r.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
case MHD_HTTP_FORBIDDEN: case MHD_HTTP_FORBIDDEN:
GNUNET_break_op (0); GNUNET_break_op (0);
/* Nothing really to verify, exchange says one of the signatures is /* Nothing really to verify, exchange says one of the signatures is
invalid; as we checked them, this should never happen, we invalid; as we checked them, this should never happen, we
should pass the JSON reply to the application */ should pass the JSON reply to the application */
hr.ec = TALER_JSON_get_error_code (j); w2r.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); w2r.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
case MHD_HTTP_NOT_FOUND: case MHD_HTTP_NOT_FOUND:
/* Nothing really to verify, the exchange basically just says /* Nothing really to verify, the exchange basically just says
that it doesn't know this reserve. Can happen if we that it doesn't know this reserve. Can happen if we
query before the wire transfer went through. query before the wire transfer went through.
We should simply pass the JSON reply to the application. */ We should simply pass the JSON reply to the application. */
hr.ec = TALER_JSON_get_error_code (j); w2r.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); w2r.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
case MHD_HTTP_CONFLICT: case MHD_HTTP_CONFLICT:
/* The exchange says that the reserve has insufficient funds; /* The exchange says that the reserve has insufficient funds;
@ -294,13 +292,13 @@ handle_reserve_withdraw_finished (void *cls,
j)) j))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
hr.http_status = 0; w2r.hr.http_status = 0;
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; w2r.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
} }
else else
{ {
hr.ec = TALER_JSON_get_error_code (j); w2r.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); w2r.hr.hint = TALER_JSON_get_error_hint (j);
} }
break; break;
case MHD_HTTP_GONE: case MHD_HTTP_GONE:
@ -308,8 +306,8 @@ handle_reserve_withdraw_finished (void *cls,
/* Note: one might want to check /keys for revocation /* Note: one might want to check /keys for revocation
signature here, alas tricky in case our /keys signature here, alas tricky in case our /keys
is outdated => left to clients */ is outdated => left to clients */
hr.ec = TALER_JSON_get_error_code (j); w2r.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); w2r.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
/* only validate reply is well-formed */ /* only validate reply is well-formed */
@ -327,8 +325,8 @@ handle_reserve_withdraw_finished (void *cls,
NULL, NULL)) NULL, NULL))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
hr.http_status = 0; w2r.hr.http_status = 0;
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; w2r.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
break; break;
} }
} }
@ -336,25 +334,24 @@ handle_reserve_withdraw_finished (void *cls,
case MHD_HTTP_INTERNAL_SERVER_ERROR: case MHD_HTTP_INTERNAL_SERVER_ERROR:
/* Server had an internal issue; we should retry, but this API /* Server had an internal issue; we should retry, but this API
leaves this to the application */ leaves this to the application */
hr.ec = TALER_JSON_get_error_code (j); w2r.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); w2r.hr.hint = TALER_JSON_get_error_hint (j);
break; break;
default: default:
/* unexpected response code */ /* unexpected response code */
GNUNET_break_op (0); GNUNET_break_op (0);
hr.ec = TALER_JSON_get_error_code (j); w2r.hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j); w2r.hr.hint = TALER_JSON_get_error_hint (j);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d for exchange withdraw\n", "Unexpected response code %u/%d for exchange withdraw\n",
(unsigned int) response_code, (unsigned int) response_code,
(int) hr.ec); (int) w2r.hr.ec);
break; break;
} }
if (NULL != wh->cb) if (NULL != wh->cb)
{ {
wh->cb (wh->cb_cls, wh->cb (wh->cb_cls,
&hr, &w2r);
NULL);
wh->cb = NULL; wh->cb = NULL;
} }
TALER_EXCHANGE_withdraw2_cancel (wh); TALER_EXCHANGE_withdraw2_cancel (wh);

View File

@ -386,10 +386,10 @@ history_cb (void *cls,
GNUNET_break (0); GNUNET_break (0);
goto error; goto error;
case MHD_HTTP_OK: case MHD_HTTP_OK:
for (unsigned int i = 0; i<chr->details.success.details_length; i++) for (unsigned int i = 0; i<chr->details.ok.details_length; i++)
{ {
const struct TALER_BANK_CreditDetails *cd = const struct TALER_BANK_CreditDetails *cd =
&chr->details.success.details[i]; &chr->details.ok.details[i];
/* check current element */ /* check current element */
if (GNUNET_OK != if (GNUNET_OK !=

View File

@ -378,10 +378,10 @@ history_cb (void *cls,
GNUNET_break (0); GNUNET_break (0);
goto error; goto error;
case MHD_HTTP_OK: case MHD_HTTP_OK:
for (unsigned int i = 0; i<dhr->details.success.details_length; i++) for (unsigned int i = 0; i<dhr->details.ok.details_length; i++)
{ {
const struct TALER_BANK_DebitDetails *dd = const struct TALER_BANK_DebitDetails *dd =
&dhr->details.success.details[i]; &dhr->details.ok.details[i];
/* check current element */ /* check current element */
if (GNUNET_OK != if (GNUNET_OK !=

View File

@ -212,17 +212,17 @@ batch_deposit_cb (void *cls,
} }
if (MHD_HTTP_OK == dr->hr.http_status) if (MHD_HTTP_OK == dr->hr.http_status)
{ {
if (ds->num_coins != dr->details.success.num_signatures) if (ds->num_coins != dr->details.ok.num_signatures)
{ {
GNUNET_break (0); GNUNET_break (0);
TALER_TESTING_interpreter_fail (ds->is); TALER_TESTING_interpreter_fail (ds->is);
return; return;
} }
ds->deposit_succeeded = GNUNET_YES; ds->deposit_succeeded = GNUNET_YES;
ds->exchange_timestamp = dr->details.success.deposit_timestamp; ds->exchange_timestamp = dr->details.ok.deposit_timestamp;
ds->exchange_pub = *dr->details.success.exchange_pub; ds->exchange_pub = *dr->details.ok.exchange_pub;
ds->exchange_sigs = GNUNET_memdup (dr->details.success.exchange_sigs, ds->exchange_sigs = GNUNET_memdup (dr->details.ok.exchange_sigs,
dr->details.success.num_signatures dr->details.ok.num_signatures
* sizeof (struct * sizeof (struct
TALER_ExchangeSignatureP)); TALER_ExchangeSignatureP));
} }

View File

@ -210,7 +210,7 @@ reserve_batch_withdraw_cb (void *cls,
{ {
struct CoinState *cs = &ws->coins[i]; struct CoinState *cs = &ws->coins[i];
const struct TALER_EXCHANGE_PrivateCoinDetails *pcd const struct TALER_EXCHANGE_PrivateCoinDetails *pcd
= &wr->details.success.coins[i]; = &wr->details.ok.coins[i];
TALER_denom_sig_deep_copy (&cs->sig, TALER_denom_sig_deep_copy (&cs->sig,
&pcd->sig); &pcd->sig);

View File

@ -116,10 +116,10 @@ check_aml_decision_cb (void *cls,
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_TESTING_get_trait_amount (ref, TALER_TESTING_get_trait_amount (ref,
&amount)); &amount));
for (unsigned int i = 0; i<adr->details.success.aml_history_length; i++) for (unsigned int i = 0; i<adr->details.ok.aml_history_length; i++)
{ {
const struct TALER_EXCHANGE_AmlDecisionDetail *aml_history const struct TALER_EXCHANGE_AmlDecisionDetail *aml_history
= &adr->details.success.aml_history[i]; = &adr->details.ok.aml_history[i];
if ( (NULL == oldest) || if ( (NULL == oldest) ||
(0 != (0 !=

View File

@ -121,7 +121,7 @@ get_cb (void *cls,
const struct TALER_PurseMergePrivateKeyP *mp; const struct TALER_PurseMergePrivateKeyP *mp;
const json_t *ct; const json_t *ct;
ds->purse_pub = dr->details.success.purse_pub; ds->purse_pub = dr->details.ok.purse_pub;
if (ds->merge) if (ds->merge)
{ {
if (GNUNET_OK != if (GNUNET_OK !=
@ -136,8 +136,8 @@ get_cb (void *cls,
TALER_CRYPTO_contract_decrypt_for_merge ( TALER_CRYPTO_contract_decrypt_for_merge (
&ds->contract_priv, &ds->contract_priv,
&ds->purse_pub, &ds->purse_pub,
dr->details.success.econtract, dr->details.ok.econtract,
dr->details.success.econtract_size, dr->details.ok.econtract_size,
&ds->merge_priv); &ds->merge_priv);
if (0 != if (0 !=
GNUNET_memcmp (mp, GNUNET_memcmp (mp,
@ -153,8 +153,8 @@ get_cb (void *cls,
ds->contract_terms = ds->contract_terms =
TALER_CRYPTO_contract_decrypt_for_deposit ( TALER_CRYPTO_contract_decrypt_for_deposit (
&ds->contract_priv, &ds->contract_priv,
dr->details.success.econtract, dr->details.ok.econtract,
dr->details.success.econtract_size); dr->details.ok.econtract_size);
} }
if (NULL == ds->contract_terms) if (NULL == ds->contract_terms)
{ {

View File

@ -264,9 +264,9 @@ deposit_cb (void *cls,
if (MHD_HTTP_OK == dr->hr.http_status) if (MHD_HTTP_OK == dr->hr.http_status)
{ {
ds->deposit_succeeded = GNUNET_YES; ds->deposit_succeeded = GNUNET_YES;
ds->exchange_timestamp = dr->details.success.deposit_timestamp; ds->exchange_timestamp = dr->details.ok.deposit_timestamp;
ds->exchange_pub = *dr->details.success.exchange_pub; ds->exchange_pub = *dr->details.ok.exchange_pub;
ds->exchange_sig = *dr->details.success.exchange_sig; ds->exchange_sig = *dr->details.ok.exchange_sig;
} }
TALER_TESTING_interpreter_next (ds->is); TALER_TESTING_interpreter_next (ds->is);
} }

View File

@ -128,7 +128,7 @@ deposit_wtid_cb (void *cls,
switch (dr->hr.http_status) switch (dr->hr.http_status)
{ {
case MHD_HTTP_OK: case MHD_HTTP_OK:
tts->wtid = dr->details.success.wtid; tts->wtid = dr->details.ok.wtid;
if (NULL != tts->bank_transfer_reference) if (NULL != tts->bank_transfer_reference)
{ {
const struct TALER_TESTING_Command *bank_transfer_cmd; const struct TALER_TESTING_Command *bank_transfer_cmd;
@ -155,7 +155,7 @@ deposit_wtid_cb (void *cls,
} }
/* Compare that expected and gotten subjects match. */ /* Compare that expected and gotten subjects match. */
if (0 != GNUNET_memcmp (&dr->details.success.wtid, if (0 != GNUNET_memcmp (&dr->details.ok.wtid,
wtid_want)) wtid_want))
{ {
GNUNET_break (0); GNUNET_break (0);

View File

@ -80,6 +80,7 @@ nft_run (void *cls,
"wget", "wget",
"--header=Content-Type:application/json", "--header=Content-Type:application/json",
"--auth-no-challenge", "--auth-no-challenge",
"--output-file=/dev/null",
"--post-data={\"level\":\"all\",\"rangeType\":\"latest\"}", "--post-data={\"level\":\"all\",\"rangeType\":\"latest\"}",
user, user,
pass, pass,

View File

@ -176,8 +176,8 @@ deposit_cb (void *cls,
} }
if (MHD_HTTP_OK == dr->hr.http_status) if (MHD_HTTP_OK == dr->hr.http_status)
{ {
ds->exchange_pub = dr->details.success.exchange_pub; ds->exchange_pub = dr->details.ok.exchange_pub;
ds->exchange_sig = dr->details.success.exchange_sig; ds->exchange_sig = dr->details.ok.exchange_sig;
} }
TALER_TESTING_interpreter_next (ds->is); TALER_TESTING_interpreter_next (ds->is);
} }

View File

@ -152,8 +152,8 @@ deposit_cb (void *cls,
if (MHD_HTTP_OK == dr->hr.http_status) if (MHD_HTTP_OK == dr->hr.http_status)
{ {
if (-1 != if (-1 !=
TALER_amount_cmp (&dr->details.success.total_deposited, TALER_amount_cmp (&dr->details.ok.total_deposited,
&dr->details.success.purse_value_after_fees)) &dr->details.ok.purse_value_after_fees))
{ {
const struct TALER_TESTING_Command *purse_cmd; const struct TALER_TESTING_Command *purse_cmd;
const struct TALER_ReserveSignatureP *reserve_sig; const struct TALER_ReserveSignatureP *reserve_sig;
@ -213,7 +213,7 @@ deposit_cb (void *cls,
/* Note: change when flags below changes! */ /* Note: change when flags below changes! */
ds->reserve_history.amount ds->reserve_history.amount
= dr->details.success.purse_value_after_fees; = dr->details.ok.purse_value_after_fees;
if (true) if (true)
{ {
ds->reserve_history.details.merge_details.purse_fee = gf->fees.purse; ds->reserve_history.details.merge_details.purse_fee = gf->fees.purse;
@ -226,7 +226,7 @@ deposit_cb (void *cls,
} }
} }
ds->reserve_history.details.merge_details.h_contract_terms ds->reserve_history.details.merge_details.h_contract_terms
= dr->details.success.h_contract_terms; = dr->details.ok.h_contract_terms;
ds->reserve_history.details.merge_details.merge_pub ds->reserve_history.details.merge_details.merge_pub
= *merge_pub; = *merge_pub;
ds->reserve_history.details.merge_details.purse_pub ds->reserve_history.details.merge_details.purse_pub
@ -236,7 +236,7 @@ deposit_cb (void *cls,
ds->reserve_history.details.merge_details.merge_timestamp ds->reserve_history.details.merge_details.merge_timestamp
= *merge_timestamp; = *merge_timestamp;
ds->reserve_history.details.merge_details.purse_expiration ds->reserve_history.details.merge_details.purse_expiration
= dr->details.success.purse_expiration; = dr->details.ok.purse_expiration;
ds->reserve_history.details.merge_details.min_age ds->reserve_history.details.merge_details.min_age
= ds->min_age; = ds->min_age;
ds->reserve_history.details.merge_details.flags ds->reserve_history.details.merge_details.flags

View File

@ -147,11 +147,11 @@ purse_status_cb (void *cls,
TALER_string_to_amount (ss->expected_balance, TALER_string_to_amount (ss->expected_balance,
&eb)); &eb));
if (0 != TALER_amount_cmp (&eb, if (0 != TALER_amount_cmp (&eb,
&rs->details.success.balance)) &rs->details.ok.balance))
{ {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected amount in purse: %s\n", "Unexpected amount in purse: %s\n",
TALER_amount_to_string (&rs->details.success.balance)); TALER_amount_to_string (&rs->details.ok.balance));
TALER_TESTING_interpreter_fail (ss->is); TALER_TESTING_interpreter_fail (ss->is);
return; return;
} }

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2014-2018 Taler Systems SA Copyright (C) 2014-2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify TALER is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as it under the terms of the GNU General Public License as
@ -73,15 +73,14 @@ struct RecoupState
* was paid back belonged to the right reserve. * was paid back belonged to the right reserve.
* *
* @param cls closure * @param cls closure
* @param hr HTTP response details * @param rr response details
* @param reserve_pub public key of the reserve receiving the recoup
*/ */
static void static void
recoup_cb (void *cls, recoup_cb (void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr, const struct TALER_EXCHANGE_RecoupResponse *rr)
const struct TALER_ReservePublicKeyP *reserve_pub)
{ {
struct RecoupState *ps = cls; struct RecoupState *ps = cls;
const struct TALER_EXCHANGE_HttpResponse *hr = &rr->hr;
struct TALER_TESTING_Interpreter *is = ps->is; struct TALER_TESTING_Interpreter *is = ps->is;
struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
const struct TALER_TESTING_Command *reserve_cmd; const struct TALER_TESTING_Command *reserve_cmd;
@ -135,12 +134,6 @@ recoup_cb (void *cls,
{ {
const struct TALER_ReservePrivateKeyP *reserve_priv; const struct TALER_ReservePrivateKeyP *reserve_priv;
if (NULL == reserve_pub)
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
if (GNUNET_OK != if (GNUNET_OK !=
TALER_TESTING_get_trait_reserve_priv (reserve_cmd, TALER_TESTING_get_trait_reserve_priv (reserve_cmd,
&reserve_priv)) &reserve_priv))
@ -151,7 +144,7 @@ recoup_cb (void *cls,
} }
GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv, GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv,
&ps->reserve_pub.eddsa_pub); &ps->reserve_pub.eddsa_pub);
if (0 != GNUNET_memcmp (reserve_pub, if (0 != GNUNET_memcmp (&rr->details.ok.reserve_pub,
&ps->reserve_pub)) &ps->reserve_pub))
{ {
GNUNET_break (0); GNUNET_break (0);

View File

@ -73,15 +73,14 @@ struct RecoupRefreshState
* was paid back belonged to the right old coin. * was paid back belonged to the right old coin.
* *
* @param cls closure * @param cls closure
* @param hr HTTP response details * @param rrr response details
* @param old_coin_pub public key of the dirty coin
*/ */
static void static void
recoup_refresh_cb (void *cls, recoup_refresh_cb (void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr, const struct TALER_EXCHANGE_RecoupRefreshResponse *rrr)
const struct TALER_CoinSpendPublicKeyP *old_coin_pub)
{ {
struct RecoupRefreshState *rrs = cls; struct RecoupRefreshState *rrs = cls;
const struct TALER_EXCHANGE_HttpResponse *hr = &rrr->hr;
struct TALER_TESTING_Interpreter *is = rrs->is; struct TALER_TESTING_Interpreter *is = rrs->is;
struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
char *cref; char *cref;
@ -150,7 +149,7 @@ recoup_refresh_cb (void *cls,
GNUNET_CRYPTO_eddsa_key_get_public (&dirty_priv->eddsa_priv, GNUNET_CRYPTO_eddsa_key_get_public (&dirty_priv->eddsa_priv,
&oc.eddsa_pub); &oc.eddsa_pub);
if (0 != GNUNET_memcmp (&oc, if (0 != GNUNET_memcmp (&oc,
old_coin_pub)) &rrr->details.ok.old_coin_pub))
{ {
GNUNET_break (0); GNUNET_break (0);
TALER_TESTING_interpreter_fail (is); TALER_TESTING_interpreter_fail (is);

View File

@ -411,7 +411,7 @@ reveal_cb (void *cls,
switch (hr->http_status) switch (hr->http_status)
{ {
case MHD_HTTP_OK: case MHD_HTTP_OK:
rrs->num_fresh_coins = rr->details.success.num_coins; rrs->num_fresh_coins = rr->details.ok.num_coins;
rrs->psa = GNUNET_new_array (rrs->num_fresh_coins, rrs->psa = GNUNET_new_array (rrs->num_fresh_coins,
struct TALER_PlanchetMasterSecretP); struct TALER_PlanchetMasterSecretP);
rrs->fresh_coins = GNUNET_new_array (rrs->num_fresh_coins, rrs->fresh_coins = GNUNET_new_array (rrs->num_fresh_coins,
@ -419,7 +419,7 @@ reveal_cb (void *cls,
for (unsigned int i = 0; i<rrs->num_fresh_coins; i++) for (unsigned int i = 0; i<rrs->num_fresh_coins; i++)
{ {
const struct TALER_EXCHANGE_RevealedCoinInfo *coin const struct TALER_EXCHANGE_RevealedCoinInfo *coin
= &rr->details.success.coins[i]; = &rr->details.ok.coins[i];
struct TALER_TESTING_FreshCoinData *fc = &rrs->fresh_coins[i]; struct TALER_TESTING_FreshCoinData *fc = &rrs->fresh_coins[i];
rrs->psa[i] = coin->ps; rrs->psa[i] = coin->ps;
@ -675,11 +675,11 @@ link_cb (void *cls,
TALER_TESTING_interpreter_fail (rls->is); TALER_TESTING_interpreter_fail (rls->is);
return; return;
} }
if (lr->details.success.num_coins != *num_fresh_coins) if (lr->details.ok.num_coins != *num_fresh_coins)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected number of fresh coins: %d vs %d in %s:%u\n", "Unexpected number of fresh coins: %d vs %d in %s:%u\n",
lr->details.success.num_coins, lr->details.ok.num_coins,
*num_fresh_coins, *num_fresh_coins,
__FILE__, __FILE__,
__LINE__); __LINE__);
@ -687,11 +687,11 @@ link_cb (void *cls,
return; return;
} }
/* check that the coins match */ /* check that the coins match */
for (unsigned int i = 0; i<lr->details.success.num_coins; i++) for (unsigned int i = 0; i<lr->details.ok.num_coins; i++)
for (unsigned int j = i + 1; j<lr->details.success.num_coins; j++) for (unsigned int j = i + 1; j<lr->details.ok.num_coins; j++)
if (0 == if (0 ==
GNUNET_memcmp (&lr->details.success.coins[i].coin_priv, GNUNET_memcmp (&lr->details.ok.coins[i].coin_priv,
&lr->details.success.coins[j].coin_priv)) &lr->details.ok.coins[j].coin_priv))
GNUNET_break (0); GNUNET_break (0);
/* Note: coins might be legitimately permutated in here... */ /* Note: coins might be legitimately permutated in here... */
found = 0; found = 0;
@ -709,12 +709,12 @@ link_cb (void *cls,
return; return;
} }
for (unsigned int i = 0; i<lr->details.success.num_coins; i++) for (unsigned int i = 0; i<lr->details.ok.num_coins; i++)
{ {
const struct TALER_EXCHANGE_LinkedCoinInfo *lci_i const struct TALER_EXCHANGE_LinkedCoinInfo *lci_i
= &lr->details.success.coins[i]; = &lr->details.ok.coins[i];
for (unsigned int j = 0; j<lr->details.success.num_coins; j++) for (unsigned int j = 0; j<lr->details.ok.num_coins; j++)
{ {
const struct TALER_TESTING_FreshCoinData *fcj const struct TALER_TESTING_FreshCoinData *fcj
= &(*fc)[j]; = &(*fc)[j];
@ -735,12 +735,12 @@ link_cb (void *cls,
} /* for j*/ } /* for j*/
} /* for i */ } /* for i */
} }
if (found != lr->details.success.num_coins) if (found != lr->details.ok.num_coins)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Only %u/%u coins match expectations\n", "Only %u/%u coins match expectations\n",
found, found,
lr->details.success.num_coins); lr->details.ok.num_coins);
GNUNET_break (0); GNUNET_break (0);
TALER_TESTING_interpreter_fail (rls->is); TALER_TESTING_interpreter_fail (rls->is);
return; return;
@ -952,16 +952,16 @@ melt_cb (void *cls,
} }
if (MHD_HTTP_OK == hr->http_status) if (MHD_HTTP_OK == hr->http_status)
{ {
rms->noreveal_index = mr->details.success.noreveal_index; rms->noreveal_index = mr->details.ok.noreveal_index;
if (mr->details.success.num_mbds != rms->num_fresh_coins) if (mr->details.ok.num_mbds != rms->num_fresh_coins)
{ {
GNUNET_break (0); GNUNET_break (0);
TALER_TESTING_interpreter_fail (rms->is); TALER_TESTING_interpreter_fail (rms->is);
return; return;
} }
GNUNET_free (rms->mbds); GNUNET_free (rms->mbds);
rms->mbds = GNUNET_memdup (mr->details.success.mbds, rms->mbds = GNUNET_memdup (mr->details.ok.mbds,
mr->details.success.num_mbds mr->details.ok.num_mbds
* sizeof (struct * sizeof (struct
TALER_EXCHANGE_MeltBlindingDetail)); TALER_EXCHANGE_MeltBlindingDetail));
} }

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2014-2020 Taler Systems SA Copyright (C) 2014-2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify TALER is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as it under the terms of the GNU General Public License as
@ -75,19 +75,14 @@ struct RefundState
* response code is acceptable. * response code is acceptable.
* *
* @param cls closure * @param cls closure
* @param hr HTTP response details * @param rr response details
* @param exchange_pub public key the exchange
* used for signing @a obj.
* @param exchange_sig actual signature confirming the refund
*/ */
static void static void
refund_cb (void *cls, refund_cb (void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr, const struct TALER_EXCHANGE_RefundResponse *rr)
const struct TALER_ExchangePublicKeyP *exchange_pub,
const struct TALER_ExchangeSignatureP *exchange_sig)
{ {
struct RefundState *rs = cls; struct RefundState *rs = cls;
const struct TALER_EXCHANGE_HttpResponse *hr = &rr->hr;
struct TALER_TESTING_Command *refund_cmd; struct TALER_TESTING_Command *refund_cmd;
refund_cmd = &rs->is->commands[rs->is->ip]; refund_cmd = &rs->is->commands[rs->is->ip];

View File

@ -65,14 +65,15 @@ struct RevokeState
* Function called with information about the post revocation operation result. * Function called with information about the post revocation operation result.
* *
* @param cls closure with a `struct RevokeState *` * @param cls closure with a `struct RevokeState *`
* @param hr HTTP response data * @param rdr response data
*/ */
static void static void
success_cb ( success_cb (
void *cls, void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr) const struct TALER_EXCHANGE_ManagementRevokeDenominationResponse *rdr)
{ {
struct RevokeState *rs = cls; struct RevokeState *rs = cls;
const struct TALER_EXCHANGE_HttpResponse *hr = &rdr->hr;
rs->kh = NULL; rs->kh = NULL;
if (rs->expected_response_code != hr->http_status) if (rs->expected_response_code != hr->http_status)

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2014-2020 Taler Systems SA Copyright (C) 2014-2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify TALER is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as it under the terms of the GNU General Public License as
@ -65,14 +65,15 @@ struct RevokeState
* Function called with information about the post revocation operation result. * Function called with information about the post revocation operation result.
* *
* @param cls closure with a `struct RevokeState *` * @param cls closure with a `struct RevokeState *`
* @param hr HTTP response data * @param rsr response data
*/ */
static void static void
success_cb ( success_cb (
void *cls, void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr) const struct TALER_EXCHANGE_ManagementRevokeSigningKeyResponse *rsr)
{ {
struct RevokeState *rs = cls; struct RevokeState *rs = cls;
const struct TALER_EXCHANGE_HttpResponse *hr = &rsr->hr;
rs->kh = NULL; rs->kh = NULL;
if (rs->expected_response_code != hr->http_status) if (rs->expected_response_code != hr->http_status)

View File

@ -84,13 +84,15 @@ struct SetOfficerState
* if the response code is acceptable. * if the response code is acceptable.
* *
* @param cls closure. * @param cls closure.
* @param hr HTTP response details * @param ar response details
*/ */
static void static void
set_officer_cb (void *cls, set_officer_cb (void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr) const struct
TALER_EXCHANGE_ManagementUpdateAmlOfficerResponse *ar)
{ {
struct SetOfficerState *ds = cls; struct SetOfficerState *ds = cls;
const struct TALER_EXCHANGE_HttpResponse *hr = &ar->hr;
ds->dh = NULL; ds->dh = NULL;
if (MHD_HTTP_NO_CONTENT != hr->http_status) if (MHD_HTTP_NO_CONTENT != hr->http_status)

View File

@ -115,15 +115,14 @@ track_transfer_cleanup (void *cls,
* wire fees and hashed wire details as well. * wire fees and hashed wire details as well.
* *
* @param cls closure. * @param cls closure.
* @param hr HTTP response details * @param tgr response details
* @param ta transfer data returned by the exchange
*/ */
static void static void
track_transfer_cb (void *cls, track_transfer_cb (void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr, const struct TALER_EXCHANGE_TransfersGetResponse *tgr)
const struct TALER_EXCHANGE_TransferData *ta)
{ {
struct TrackTransferState *tts = cls; struct TrackTransferState *tts = cls;
const struct TALER_EXCHANGE_HttpResponse *hr = &tgr->hr;
struct TALER_TESTING_Interpreter *is = tts->is; struct TALER_TESTING_Interpreter *is = tts->is;
struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
struct TALER_Amount expected_amount; struct TALER_Amount expected_amount;
@ -148,138 +147,62 @@ track_transfer_cb (void *cls,
switch (hr->http_status) switch (hr->http_status)
{ {
case MHD_HTTP_OK: case MHD_HTTP_OK:
if (NULL == tts->expected_total_amount)
{ {
GNUNET_break (0); const struct TALER_EXCHANGE_TransferData *ta
TALER_TESTING_interpreter_fail (is); = &tgr->details.ok.td;
return;
}
if (NULL == tts->expected_wire_fee)
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
if (GNUNET_OK != if (NULL == tts->expected_total_amount)
TALER_string_to_amount (tts->expected_total_amount,
&expected_amount))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
if (0 != TALER_amount_cmp (&ta->total_amount,
&expected_amount))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Total amount mismatch to command %s - "
"%s vs %s\n",
cmd->label,
TALER_amount_to_string (&ta->total_amount),
TALER_amount_to_string (&expected_amount));
json_dumpf (hr->reply,
stderr,
0);
fprintf (stderr, "\n");
TALER_TESTING_interpreter_fail (is);
return;
}
if (GNUNET_OK !=
TALER_string_to_amount (tts->expected_wire_fee,
&expected_amount))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
if (0 != TALER_amount_cmp (&ta->wire_fee,
&expected_amount))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Wire fee mismatch to command %s\n",
cmd->label);
json_dumpf (hr->reply,
stderr,
0);
TALER_TESTING_interpreter_fail (is);
return;
}
/**
* Optionally checking: (1) wire-details for this transfer
* match the ones from a referenced "deposit" operation -
* or any operation that could provide wire-details. (2)
* Total amount for this transfer matches the one from any
* referenced command that could provide one.
*/
if (NULL != tts->wire_details_reference)
{
const struct TALER_TESTING_Command *wire_details_cmd;
const char **payto_uri;
struct TALER_PaytoHashP h_payto;
wire_details_cmd
= TALER_TESTING_interpreter_lookup_command (is,
tts->wire_details_reference);
if (NULL == wire_details_cmd)
{ {
GNUNET_break (0); GNUNET_break (0);
TALER_TESTING_interpreter_fail (is); TALER_TESTING_interpreter_fail (is);
return; return;
} }
if (NULL == tts->expected_wire_fee)
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
if (GNUNET_OK != if (GNUNET_OK !=
TALER_TESTING_get_trait_payto_uri (wire_details_cmd, TALER_string_to_amount (tts->expected_total_amount,
&payto_uri)) &expected_amount))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
TALER_payto_hash (*payto_uri,
&h_payto);
if (0 != GNUNET_memcmp (&h_payto,
&ta->h_payto))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Wire hash missmath to command %s\n",
cmd->label);
json_dumpf (hr->reply,
stderr,
0);
TALER_TESTING_interpreter_fail (is);
return;
}
}
if (NULL != tts->total_amount_reference)
{
const struct TALER_TESTING_Command *total_amount_cmd;
const struct TALER_Amount *total_amount_from_reference;
total_amount_cmd
= TALER_TESTING_interpreter_lookup_command (is,
tts->total_amount_reference);
if (NULL == total_amount_cmd)
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
if (GNUNET_OK !=
TALER_TESTING_get_trait_amount (total_amount_cmd,
&total_amount_from_reference))
{ {
GNUNET_break (0); GNUNET_break (0);
TALER_TESTING_interpreter_fail (is); TALER_TESTING_interpreter_fail (is);
return; return;
} }
if (0 != TALER_amount_cmp (&ta->total_amount, if (0 != TALER_amount_cmp (&ta->total_amount,
total_amount_from_reference)) &expected_amount))
{ {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Amount missmath to command %s\n", "Total amount mismatch to command %s - "
"%s vs %s\n",
cmd->label,
TALER_amount_to_string (&ta->total_amount),
TALER_amount_to_string (&expected_amount));
json_dumpf (hr->reply,
stderr,
0);
fprintf (stderr, "\n");
TALER_TESTING_interpreter_fail (is);
return;
}
if (GNUNET_OK !=
TALER_string_to_amount (tts->expected_wire_fee,
&expected_amount))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
if (0 != TALER_amount_cmp (&ta->wire_fee,
&expected_amount))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Wire fee mismatch to command %s\n",
cmd->label); cmd->label);
json_dumpf (hr->reply, json_dumpf (hr->reply,
stderr, stderr,
@ -287,8 +210,92 @@ track_transfer_cb (void *cls,
TALER_TESTING_interpreter_fail (is); TALER_TESTING_interpreter_fail (is);
return; return;
} }
}
} /**
* Optionally checking: (1) wire-details for this transfer
* match the ones from a referenced "deposit" operation -
* or any operation that could provide wire-details. (2)
* Total amount for this transfer matches the one from any
* referenced command that could provide one.
*/
if (NULL != tts->wire_details_reference)
{
const struct TALER_TESTING_Command *wire_details_cmd;
const char **payto_uri;
struct TALER_PaytoHashP h_payto;
wire_details_cmd
= TALER_TESTING_interpreter_lookup_command (is,
tts->
wire_details_reference);
if (NULL == wire_details_cmd)
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
if (GNUNET_OK !=
TALER_TESTING_get_trait_payto_uri (wire_details_cmd,
&payto_uri))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
TALER_payto_hash (*payto_uri,
&h_payto);
if (0 != GNUNET_memcmp (&h_payto,
&ta->h_payto))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Wire hash missmath to command %s\n",
cmd->label);
json_dumpf (hr->reply,
stderr,
0);
TALER_TESTING_interpreter_fail (is);
return;
}
}
if (NULL != tts->total_amount_reference)
{
const struct TALER_TESTING_Command *total_amount_cmd;
const struct TALER_Amount *total_amount_from_reference;
total_amount_cmd
= TALER_TESTING_interpreter_lookup_command (is,
tts->
total_amount_reference);
if (NULL == total_amount_cmd)
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
if (GNUNET_OK !=
TALER_TESTING_get_trait_amount (total_amount_cmd,
&total_amount_from_reference))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
if (0 != TALER_amount_cmp (&ta->total_amount,
total_amount_from_reference))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Amount missmath to command %s\n",
cmd->label);
json_dumpf (hr->reply,
stderr,
0);
TALER_TESTING_interpreter_fail (is);
return;
}
}
break;
} /* case OK */
} /* switch on status */
TALER_TESTING_interpreter_next (is); TALER_TESTING_interpreter_next (is);
} }

View File

@ -72,18 +72,14 @@ struct WireState
* that the wire fee is acceptable too. * that the wire fee is acceptable too.
* *
* @param cls closure. * @param cls closure.
* @param hr HTTP response details * @param wr response details
* @param accounts_len length of the @a accounts array.
* @param accounts list of wire accounts of the exchange,
* NULL on error.
*/ */
static void static void
wire_cb (void *cls, wire_cb (void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr, const struct TALER_EXCHANGE_WireResponse *wr)
unsigned int accounts_len,
const struct TALER_EXCHANGE_WireAccount *accounts)
{ {
struct WireState *ws = cls; struct WireState *ws = cls;
const struct TALER_EXCHANGE_HttpResponse *hr = &wr->hr;
struct TALER_TESTING_Command *cmd = &ws->is->commands[ws->is->ip]; struct TALER_TESTING_Command *cmd = &ws->is->commands[ws->is->ip];
struct TALER_Amount expected_fee; struct TALER_Amount expected_fee;
@ -100,6 +96,15 @@ wire_cb (void *cls,
if (MHD_HTTP_OK == hr->http_status) if (MHD_HTTP_OK == hr->http_status)
{ {
unsigned int accounts_len
= wr->details.ok.accounts_len;
unsigned int fees_len
= wr->details.ok.fees_len;
const struct TALER_EXCHANGE_WireAccount *accounts
= wr->details.ok.accounts;
const struct TALER_EXCHANGE_WireFeesByMethod *fees
= wr->details.ok.fees;
for (unsigned int i = 0; i<accounts_len; i++) for (unsigned int i = 0; i<accounts_len; i++)
{ {
char *method; char *method;
@ -115,32 +120,46 @@ wire_cb (void *cls,
method)) method))
{ {
ws->method_found = GNUNET_OK; ws->method_found = GNUNET_OK;
if (NULL != ws->expected_fee) }
GNUNET_free (method);
}
if (NULL != ws->expected_fee)
{
bool fee_found = false;
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (ws->expected_fee,
&expected_fee));
for (unsigned int i = 0; i<fees_len; i++)
{
if (0 != strcmp (fees[i].method,
ws->expected_method))
continue;
for (const struct TALER_EXCHANGE_WireAggregateFees *waf
= fees[i].fees_head;
NULL != waf;
waf = waf->next)
{ {
GNUNET_assert (GNUNET_OK == if (0 != TALER_amount_cmp (&waf->fees.wire,
TALER_string_to_amount (ws->expected_fee, &expected_fee))
&expected_fee));
for (const struct TALER_EXCHANGE_WireAggregateFees *waf
= accounts[i].fees;
NULL != waf;
waf = waf->next)
{ {
if (0 != TALER_amount_cmp (&waf->fees.wire, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
&expected_fee)) "Wire fee mismatch to command %s\n",
{ cmd->label);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, TALER_TESTING_interpreter_fail (ws->is);
"Wire fee mismatch to command %s\n", return;
cmd->label);
TALER_TESTING_interpreter_fail (ws->is);
GNUNET_free (method);
return;
}
} }
fee_found = true;
} }
} }
TALER_LOG_DEBUG ("Freeing method '%s'\n", if (! fee_found)
method); {
GNUNET_free (method); GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"/wire does not contain expected fee '%s'\n",
ws->expected_fee);
TALER_TESTING_interpreter_fail (ws->is);
return;
}
} }
if (GNUNET_OK != ws->method_found) if (GNUNET_OK != ws->method_found)
{ {

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2020 Taler Systems SA Copyright (C) 2020-2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it TALER is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by under the terms of the GNU General Public License as published by
@ -67,13 +67,14 @@ struct WireAddState
* if the response code is acceptable. * if the response code is acceptable.
* *
* @param cls closure. * @param cls closure.
* @param hr HTTP response details * @param wer response details
*/ */
static void static void
wire_add_cb (void *cls, wire_add_cb (void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr) const struct TALER_EXCHANGE_ManagementWireEnableResponse *wer)
{ {
struct WireAddState *ds = cls; struct WireAddState *ds = cls;
const struct TALER_EXCHANGE_HttpResponse *hr = &wer->hr;
ds->dh = NULL; ds->dh = NULL;
if (ds->expected_response_code != hr->http_status) if (ds->expected_response_code != hr->http_status)
@ -110,10 +111,14 @@ wire_add_run (void *cls,
struct TALER_MasterSignatureP master_sig1; struct TALER_MasterSignatureP master_sig1;
struct TALER_MasterSignatureP master_sig2; struct TALER_MasterSignatureP master_sig2;
struct GNUNET_TIME_Timestamp now; struct GNUNET_TIME_Timestamp now;
json_t *credit_rest;
json_t *debit_rest;
(void) cmd; (void) cmd;
now = GNUNET_TIME_timestamp_get (); now = GNUNET_TIME_timestamp_get ();
ds->is = is; ds->is = is;
debit_rest = json_array ();
credit_rest = json_array ();
if (ds->bad_sig) if (ds->bad_sig)
{ {
memset (&master_sig1, memset (&master_sig1,
@ -126,10 +131,16 @@ wire_add_run (void *cls,
else else
{ {
TALER_exchange_offline_wire_add_sign (ds->payto_uri, TALER_exchange_offline_wire_add_sign (ds->payto_uri,
NULL,
debit_rest,
credit_rest,
now, now,
&is->master_priv, &is->master_priv,
&master_sig1); &master_sig1);
TALER_exchange_wire_signature_make (ds->payto_uri, TALER_exchange_wire_signature_make (ds->payto_uri,
NULL,
debit_rest,
credit_rest,
&is->master_priv, &is->master_priv,
&master_sig2); &master_sig2);
} }
@ -137,11 +148,16 @@ wire_add_run (void *cls,
is->ctx, is->ctx,
is->exchange_url, is->exchange_url,
ds->payto_uri, ds->payto_uri,
NULL,
debit_rest,
credit_rest,
now, now,
&master_sig1, &master_sig1,
&master_sig2, &master_sig2,
&wire_add_cb, &wire_add_cb,
ds); ds);
json_decref (debit_rest);
json_decref (credit_rest);
if (NULL == ds->dh) if (NULL == ds->dh)
{ {
GNUNET_break (0); GNUNET_break (0);

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2020 Taler Systems SA Copyright (C) 2020, 2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it TALER is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by under the terms of the GNU General Public License as published by
@ -67,13 +67,14 @@ struct WireDelState
* if the response code is acceptable. * if the response code is acceptable.
* *
* @param cls closure. * @param cls closure.
* @param hr HTTP response details * @param wdr response details
*/ */
static void static void
wire_del_cb (void *cls, wire_del_cb (void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr) const struct TALER_EXCHANGE_ManagementWireDisableResponse *wdr)
{ {
struct WireDelState *ds = cls; struct WireDelState *ds = cls;
const struct TALER_EXCHANGE_HttpResponse *hr = &wdr->hr;
ds->dh = NULL; ds->dh = NULL;
if (ds->expected_response_code != hr->http_status) if (ds->expected_response_code != hr->http_status)

View File

@ -297,10 +297,10 @@ reserve_withdraw_cb (void *cls,
{ {
case MHD_HTTP_OK: case MHD_HTTP_OK:
TALER_denom_sig_deep_copy (&ws->sig, TALER_denom_sig_deep_copy (&ws->sig,
&wr->details.success.sig); &wr->details.ok.sig);
ws->coin_priv = wr->details.success.coin_priv; ws->coin_priv = wr->details.ok.coin_priv;
ws->bks = wr->details.success.bks; ws->bks = wr->details.ok.bks;
ws->exchange_vals = wr->details.success.exchange_vals; ws->exchange_vals = wr->details.ok.exchange_vals;
if (0 != ws->total_backoff.rel_value_us) if (0 != ws->total_backoff.rel_value_us)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,

View File

@ -526,49 +526,46 @@ sighandler_child_death (void)
void void
TALER_TESTING_cert_cb (void *cls, TALER_TESTING_cert_cb (void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr, const struct TALER_EXCHANGE_KeysResponse *kr)
const struct TALER_EXCHANGE_Keys *keys,
enum TALER_EXCHANGE_VersionCompatibility compat)
{ {
const struct TALER_EXCHANGE_HttpResponse *hr = &kr->hr;
struct MainContext *main_ctx = cls; struct MainContext *main_ctx = cls;
struct TALER_TESTING_Interpreter *is = main_ctx->is; struct TALER_TESTING_Interpreter *is = main_ctx->is;
(void) compat; switch (hr->http_status)
if (NULL == keys)
{ {
if (GNUNET_NO == is->working) case MHD_HTTP_OK:
{ /* dealt with below */
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, break;
"Got NULL response for /keys during startup (%u/%d), retrying!\n", default:
hr->http_status, if (GNUNET_YES == is->working)
(int) hr->ec);
TALER_EXCHANGE_disconnect (is->exchange);
GNUNET_assert (
NULL != (is->exchange
= TALER_EXCHANGE_connect (is->ctx,
main_ctx->exchange_url,
&TALER_TESTING_cert_cb,
main_ctx,
TALER_EXCHANGE_OPTION_END)));
return;
}
else
{ {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Got NULL response for /keys during execution (%u/%d)!\n", "Got NULL response for /keys during execution (%u/%d)!\n",
hr->http_status, hr->http_status,
(int) hr->ec); (int) hr->ec);
return;
} }
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Got failure response for /keys during startup (%u/%d), retrying!\n",
hr->http_status,
(int) hr->ec);
TALER_EXCHANGE_disconnect (is->exchange);
GNUNET_assert (
NULL != (is->exchange
= TALER_EXCHANGE_connect (is->ctx,
main_ctx->exchange_url,
&TALER_TESTING_cert_cb,
main_ctx,
TALER_EXCHANGE_OPTION_END)));
return;
} }
else GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
{ "Got %d DK from /keys in generation %u\n",
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, kr->details.ok.keys->num_denom_keys,
"Got %d DK from /keys in generation %u\n", is->key_generation + 1);
keys->num_denom_keys,
is->key_generation + 1);
}
is->key_generation++; is->key_generation++;
is->keys = keys; is->keys = kr->details.ok.keys;
/* /keys has been called for some reason and /* /keys has been called for some reason and
* the interpreter is already running. */ * the interpreter is already running. */

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2020-2022 Taler Systems SA Copyright (C) 2020-2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the 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 terms of the GNU General Public License as published by the Free Software
@ -677,6 +677,22 @@ struct TALER_MasterAddWirePS
* Hash over the exchange's payto URI. * Hash over the exchange's payto URI.
*/ */
struct TALER_PaytoHashP h_payto GNUNET_PACKED; struct TALER_PaytoHashP h_payto GNUNET_PACKED;
/**
* Hash over the conversion URL, all zeros if there
* is no conversion URL.
*/
struct GNUNET_HashCode h_conversion_url;
/**
* Hash over the debit restrictions.
*/
struct GNUNET_HashCode h_debit_restrictions;
/**
* Hash over the credit restrictions.
*/
struct GNUNET_HashCode h_credit_restrictions;
}; };
GNUNET_NETWORK_STRUCT_END GNUNET_NETWORK_STRUCT_END
@ -685,6 +701,9 @@ GNUNET_NETWORK_STRUCT_END
void void
TALER_exchange_offline_wire_add_sign ( TALER_exchange_offline_wire_add_sign (
const char *payto_uri, const char *payto_uri,
const char *conversion_url,
const json_t *debit_restrictions,
const json_t *credit_restrictions,
struct GNUNET_TIME_Timestamp now, struct GNUNET_TIME_Timestamp now,
const struct TALER_MasterPrivateKeyP *master_priv, const struct TALER_MasterPrivateKeyP *master_priv,
struct TALER_MasterSignatureP *master_sig) struct TALER_MasterSignatureP *master_sig)
@ -697,6 +716,14 @@ TALER_exchange_offline_wire_add_sign (
TALER_payto_hash (payto_uri, TALER_payto_hash (payto_uri,
&kv.h_payto); &kv.h_payto);
if (NULL != conversion_url)
GNUNET_CRYPTO_hash (conversion_url,
strlen (conversion_url),
&kv.h_conversion_url);
TALER_json_hash (debit_restrictions,
&kv.h_debit_restrictions);
TALER_json_hash (credit_restrictions,
&kv.h_credit_restrictions);
GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv, GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv,
&kv, &kv,
&master_sig->eddsa_signature); &master_sig->eddsa_signature);
@ -706,6 +733,9 @@ TALER_exchange_offline_wire_add_sign (
enum GNUNET_GenericReturnValue enum GNUNET_GenericReturnValue
TALER_exchange_offline_wire_add_verify ( TALER_exchange_offline_wire_add_verify (
const char *payto_uri, const char *payto_uri,
const char *conversion_url,
const json_t *debit_restrictions,
const json_t *credit_restrictions,
struct GNUNET_TIME_Timestamp sign_time, struct GNUNET_TIME_Timestamp sign_time,
const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterPublicKeyP *master_pub,
const struct TALER_MasterSignatureP *master_sig) const struct TALER_MasterSignatureP *master_sig)
@ -718,6 +748,14 @@ TALER_exchange_offline_wire_add_verify (
TALER_payto_hash (payto_uri, TALER_payto_hash (payto_uri,
&aw.h_payto); &aw.h_payto);
if (NULL != conversion_url)
GNUNET_CRYPTO_hash (conversion_url,
strlen (conversion_url),
&aw.h_conversion_url);
TALER_json_hash (debit_restrictions,
&aw.h_debit_restrictions);
TALER_json_hash (credit_restrictions,
&aw.h_credit_restrictions);
return return
GNUNET_CRYPTO_eddsa_verify ( GNUNET_CRYPTO_eddsa_verify (
TALER_SIGNATURE_MASTER_ADD_WIRE, TALER_SIGNATURE_MASTER_ADD_WIRE,
@ -1095,6 +1133,22 @@ struct TALER_MasterWireDetailsPS
*/ */
struct TALER_PaytoHashP h_wire_details GNUNET_PACKED; struct TALER_PaytoHashP h_wire_details GNUNET_PACKED;
/**
* Hash over the conversion URL, all zeros if there
* is no conversion URL.
*/
struct GNUNET_HashCode h_conversion_url;
/**
* Hash over the debit restrictions.
*/
struct GNUNET_HashCode h_debit_restrictions;
/**
* Hash over the credit restrictions.
*/
struct GNUNET_HashCode h_credit_restrictions;
}; };
GNUNET_NETWORK_STRUCT_END GNUNET_NETWORK_STRUCT_END
@ -1103,6 +1157,9 @@ GNUNET_NETWORK_STRUCT_END
enum GNUNET_GenericReturnValue enum GNUNET_GenericReturnValue
TALER_exchange_wire_signature_check ( TALER_exchange_wire_signature_check (
const char *payto_uri, const char *payto_uri,
const char *conversion_url,
const json_t *debit_restrictions,
const json_t *credit_restrictions,
const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterPublicKeyP *master_pub,
const struct TALER_MasterSignatureP *master_sig) const struct TALER_MasterSignatureP *master_sig)
{ {
@ -1113,6 +1170,14 @@ TALER_exchange_wire_signature_check (
TALER_payto_hash (payto_uri, TALER_payto_hash (payto_uri,
&wd.h_wire_details); &wd.h_wire_details);
if (NULL != conversion_url)
GNUNET_CRYPTO_hash (conversion_url,
strlen (conversion_url),
&wd.h_conversion_url);
TALER_json_hash (debit_restrictions,
&wd.h_debit_restrictions);
TALER_json_hash (credit_restrictions,
&wd.h_credit_restrictions);
return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_WIRE_DETAILS, return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_WIRE_DETAILS,
&wd, &wd,
&master_sig->eddsa_signature, &master_sig->eddsa_signature,
@ -1123,6 +1188,9 @@ TALER_exchange_wire_signature_check (
void void
TALER_exchange_wire_signature_make ( TALER_exchange_wire_signature_make (
const char *payto_uri, const char *payto_uri,
const char *conversion_url,
const json_t *debit_restrictions,
const json_t *credit_restrictions,
const struct TALER_MasterPrivateKeyP *master_priv, const struct TALER_MasterPrivateKeyP *master_priv,
struct TALER_MasterSignatureP *master_sig) struct TALER_MasterSignatureP *master_sig)
{ {
@ -1133,6 +1201,14 @@ TALER_exchange_wire_signature_make (
TALER_payto_hash (payto_uri, TALER_payto_hash (payto_uri,
&wd.h_wire_details); &wd.h_wire_details);
if (NULL != conversion_url)
GNUNET_CRYPTO_hash (conversion_url,
strlen (conversion_url),
&wd.h_conversion_url);
TALER_json_hash (debit_restrictions,
&wd.h_debit_restrictions);
TALER_json_hash (credit_restrictions,
&wd.h_credit_restrictions);
GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv, GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv,
&wd, &wd,
&master_sig->eddsa_signature); &master_sig->eddsa_signature);