summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/include/taler_merchant_service.h45
-rw-r--r--src/lib/merchant_api_tip_pickup.c341
-rw-r--r--src/testing/testing_api_cmd_tip_pickup.c74
3 files changed, 341 insertions, 119 deletions
diff --git a/src/include/taler_merchant_service.h b/src/include/taler_merchant_service.h
index 89f550b7..408020b3 100644
--- a/src/include/taler_merchant_service.h
+++ b/src/include/taler_merchant_service.h
@@ -3602,6 +3602,44 @@ struct TALER_MERCHANT_TipPickupHandle;
/**
+ * Details about a pickup operation, as returned to the application.
+ */
+struct TALER_MERCHANT_PickupDetails
+{
+ /**
+ * HTTP response data.
+ */
+ struct TALER_MERCHANT_HttpResponse hr;
+
+ /**
+ * Details about the response.
+ */
+ union
+ {
+ /**
+ * Details if the status is #MHD_HTTP_OK.
+ */
+ struct
+ {
+
+ /**
+ * Array of length @e num_sigs with details about each of the coins that
+ * were picked up.
+ */
+ struct TALER_EXCHANGE_PrivateCoinDetails *pcds;
+
+ /**
+ * Length of the @e pcds array.
+ */
+ unsigned int num_sigs;
+ } success;
+
+ } details;
+
+};
+
+
+/**
* Callback for a POST /tips/$TIP_ID/pickup request. Returns the result of
* the operation.
*
@@ -3613,10 +3651,7 @@ struct TALER_MERCHANT_TipPickupHandle;
typedef void
(*TALER_MERCHANT_TipPickupCallback) (
void *cls,
- const struct TALER_MERCHANT_HttpResponse *hr,
- unsigned int num_sigs,
- const struct TALER_DenominationSignature sigs[],
- const struct TALER_CoinSpendPrivateKeyP coin_privs[]);
+ const struct TALER_MERCHANT_PickupDetails *pd);
/**
@@ -3641,6 +3676,7 @@ struct TALER_MERCHANT_PlanchetData
* backend that a customer wants to pick up a tip.
*
* @param ctx execution context
+ * @param exchange handle to the exchange we are picking up the tip from
* @param backend_url base URL of the merchant backend
* @param tip_id unique identifier for the tip
* @param num_planchets number of planchets provided in @a pds
@@ -3651,6 +3687,7 @@ struct TALER_MERCHANT_PlanchetData
*/
struct TALER_MERCHANT_TipPickupHandle *
TALER_MERCHANT_tip_pickup (struct GNUNET_CURL_Context *ctx,
+ struct TALER_EXCHANGE_Handle *exchange,
const char *backend_url,
const struct TALER_TipIdentifierP *tip_id,
unsigned int num_planchets,
diff --git a/src/lib/merchant_api_tip_pickup.c b/src/lib/merchant_api_tip_pickup.c
index 315f2ba9..b9ca9d59 100644
--- a/src/lib/merchant_api_tip_pickup.c
+++ b/src/lib/merchant_api_tip_pickup.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2017, 2020 Taler Systems SA
+ Copyright (C) 2014-2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Lesser General Public License as published by the Free Software
@@ -52,10 +52,6 @@ struct PlanchetData
*/
struct TALER_CoinPubHash c_hash;
- // FIXME: initialize these:
- struct TALER_ExchangeWithdrawValues alg_values;
- union TALER_DenominationBlindingKeyP bks;
- struct TALER_CoinSpendPrivateKeyP coin_priv;
};
@@ -81,19 +77,65 @@ struct TALER_MERCHANT_TipPickupHandle
struct TALER_MERCHANT_TipPickup2Handle *tpo2;
/**
- * Number of planchets/coins used for this operation.
+ * Array of length @e num_planchets.
*/
- unsigned int num_planchets;
+ struct PlanchetData *planchets;
/**
* Array of length @e num_planchets.
*/
- struct PlanchetData *planchets;
+ struct TALER_EXCHANGE_PrivateCoinDetails *pcds;
+
+ /**
+ * Handle for a /csr request we may optionally need
+ * to trigger.
+ */
+ struct TALER_EXCHANGE_CsRHandle *csr;
+
+ /**
+ * Context for making HTTP requests.
+ */
+ struct GNUNET_CURL_Context *ctx;
+
+ /**
+ * URL of the merchant backend.
+ */
+ char *backend_url;
+ /**
+ * ID of the tip we are picking up.
+ */
+ struct TALER_TipIdentifierP tip_id;
+
+ /**
+ * Number of planchets/coins used for this operation.
+ */
+ unsigned int num_planchets;
};
/**
+ * Fail the pickup operation @a tp, returning @a ec.
+ * Also cancels @a tp.
+ *
+ * @param[in] tp operation to fail
+ * @param ec reason for the failure
+ */
+static void
+fail_pickup (struct TALER_MERCHANT_TipPickupHandle *tp,
+ enum TALER_ErrorCode ec)
+{
+ struct TALER_MERCHANT_PickupDetails pd = {
+ .hr.ec = ec
+ };
+
+ tp->cb (tp->cb_cls,
+ &pd);
+ TALER_MERCHANT_tip_pickup_cancel (tp);
+}
+
+
+/**
* Callback for a /tip-pickup request. Returns the result of the operation.
* Note that the client MUST still do the unblinding of the @a blind_sigs.
*
@@ -109,75 +151,190 @@ pickup_done_cb (void *cls,
const struct TALER_BlindedDenominationSignature *blind_sigs)
{
struct TALER_MERCHANT_TipPickupHandle *tp = cls;
+ struct TALER_MERCHANT_PickupDetails pd = {
+ .hr = *hr
+ };
tp->tpo2 = NULL;
if (NULL == blind_sigs)
{
tp->cb (tp->cb_cls,
- hr,
- 0,
- NULL,
- NULL);
+ &pd);
TALER_MERCHANT_tip_pickup_cancel (tp);
return;
}
{
- struct TALER_DenominationSignature sigs[num_blind_sigs];
- enum GNUNET_GenericReturnValue ok;
+ enum GNUNET_GenericReturnValue ok = GNUNET_OK;
- ok = GNUNET_OK;
- memset (sigs,
- 0,
- sizeof (sigs));
for (unsigned int i = 0; i<num_blind_sigs; i++)
{
+ struct TALER_EXCHANGE_PrivateCoinDetails *pcd = &tp->pcds[i];
struct TALER_FreshCoin fc;
if (GNUNET_OK !=
TALER_planchet_to_coin (&tp->planchets[i].pk.key,
&blind_sigs[i],
- &tp->planchets[i].bks,
- &tp->planchets[i].coin_priv,
+ &pcd->bks,
+ &pcd->coin_priv,
&tp->planchets[i].c_hash,
- &tp->planchets[i].alg_values,
+ &pcd->exchange_vals,
&fc))
{
ok = GNUNET_SYSERR;
break;
}
- sigs[i] = fc.sig;
+ pcd->sig = fc.sig;
}
- if (GNUNET_OK == ok)
- {
- tp->cb (tp->cb_cls,
- hr,
- num_blind_sigs,
- sigs,
- NULL /* FIXME: pass coin_privs! */);
- }
- else
+ if (GNUNET_OK != ok)
{
struct TALER_MERCHANT_HttpResponse hrx = {
.reply = hr->reply,
- .http_status = 0,
.ec = TALER_EC_MERCHANT_TIP_PICKUP_UNBLIND_FAILURE
};
+ pd.hr = hrx;
tp->cb (tp->cb_cls,
- &hrx,
- 0,
- NULL,
- NULL);
+ &pd);
+ }
+ else
+ {
+ pd.details.success.num_sigs = num_blind_sigs;
+ pd.details.success.pcds = tp->pcds;
+ tp->cb (tp->cb_cls,
+ &pd);
}
- for (unsigned int i = 0; i<num_blind_sigs; i++)
- TALER_denom_sig_free (&sigs[i]);
}
TALER_MERCHANT_tip_pickup_cancel (tp);
}
+/**
+ * We have obtained all of the exchange inputs. Continue the pickup.
+ *
+ * @param[in,out] tp operation to continue
+ */
+static void
+pickup_post_csr (struct TALER_MERCHANT_TipPickupHandle *tp)
+{
+ struct TALER_PlanchetDetail details[tp->num_planchets];
+
+ for (unsigned int i = 0; i<tp->num_planchets; i++)
+ {
+ const struct PlanchetData *pd = &tp->planchets[i];
+ struct TALER_EXCHANGE_PrivateCoinDetails *pcd = &tp->pcds[i];
+
+ TALER_planchet_setup_coin_priv (&pd->ps,
+ &pcd->exchange_vals,
+ &pcd->coin_priv);
+ TALER_planchet_blinding_secret_create (&pd->ps,
+ &pcd->exchange_vals,
+ &pcd->bks);
+ if (GNUNET_OK !=
+ TALER_planchet_prepare (&pd->pk.key,
+ &pcd->exchange_vals,
+ &pcd->bks,
+ &pcd->coin_priv,
+ &tp->planchets[i].c_hash,
+ &details[i]))
+ {
+ GNUNET_break (0);
+ for (unsigned int j = 0; j<i; j++)
+ TALER_planchet_detail_free (&details[j]);
+ fail_pickup (tp,
+ TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE);
+ return;
+ }
+ }
+ tp->tpo2 = TALER_MERCHANT_tip_pickup2 (tp->ctx,
+ tp->backend_url,
+ &tp->tip_id,
+ tp->num_planchets,
+ details,
+ &pickup_done_cb,
+ tp);
+ for (unsigned int j = 0; j<tp->num_planchets; j++)
+ TALER_planchet_detail_free (&details[j]);
+ if (NULL == tp->tpo2)
+ {
+ GNUNET_break (0);
+ fail_pickup (tp,
+ TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE);
+ return;
+ }
+}
+
+
+/**
+ * Callbacks of this type are used to serve the result of submitting a
+ * CS R request to a exchange.
+ *
+ * @param cls a `struct TALER_MERCHANT_TipPickupHandle`
+ * @param csrr response details
+ */
+static void
+csr_cb (void *cls,
+ const struct TALER_EXCHANGE_CsRResponse *csrr)
+{
+ struct TALER_MERCHANT_TipPickupHandle *tp = cls;
+
+ switch (csrr->hr.http_status)
+ {
+ case MHD_HTTP_OK:
+ {
+ unsigned int off = 0;
+
+ for (unsigned int i = 0; i<tp->num_planchets; i++)
+ {
+ const struct PlanchetData *pd = &tp->planchets[i];
+ struct TALER_EXCHANGE_PrivateCoinDetails *pcd = &tp->pcds[i];
+
+ switch (pd->pk.key.cipher)
+ {
+ case TALER_DENOMINATION_INVALID:
+ GNUNET_assert (0);
+ break;
+ case TALER_DENOMINATION_RSA:
+ continue;
+ case TALER_DENOMINATION_CS:
+ if (off >= csrr->details.success.alg_values_len)
+ {
+ struct TALER_MERCHANT_PickupDetails pd = {
+ .hr.http_status = 0
+ };
+
+ GNUNET_break (0);
+ tp->cb (tp->cb_cls,
+ &pd);
+ TALER_MERCHANT_tip_pickup_cancel (tp);
+ return;
+ }
+ pcd->exchange_vals = csrr->details.success.alg_values[off];
+ off++;
+ break;
+ }
+ }
+ }
+ pickup_post_csr (tp);
+ return;
+ default:
+ {
+ struct TALER_MERCHANT_PickupDetails pd = {
+ .hr.hint = "/csr failed",
+ .hr.exchange_http_status = csrr->hr.http_status
+ };
+
+ tp->cb (tp->cb_cls,
+ &pd);
+ TALER_MERCHANT_tip_pickup_cancel (tp);
+ return;
+ }
+ }
+}
+
+
struct TALER_MERCHANT_TipPickupHandle *
TALER_MERCHANT_tip_pickup (struct GNUNET_CURL_Context *ctx,
+ struct TALER_EXCHANGE_Handle *exchange,
const char *backend_url,
const struct TALER_TipIdentifierP *tip_id,
unsigned int num_planchets,
@@ -186,7 +343,7 @@ TALER_MERCHANT_tip_pickup (struct GNUNET_CURL_Context *ctx,
void *pickup_cb_cls)
{
struct TALER_MERCHANT_TipPickupHandle *tp;
- struct TALER_PlanchetDetail details[GNUNET_NZL (num_planchets)];
+ unsigned int num_csr;
if (0 == num_planchets)
{
@@ -194,52 +351,80 @@ TALER_MERCHANT_tip_pickup (struct GNUNET_CURL_Context *ctx,
return NULL;
}
tp = GNUNET_new (struct TALER_MERCHANT_TipPickupHandle);
+ tp->cb = pickup_cb;
+ tp->cb_cls = pickup_cb_cls;
+ tp->ctx = ctx;
+ tp->backend_url = GNUNET_strdup (backend_url);
+ tp->tip_id = *tip_id;
GNUNET_array_grow (tp->planchets,
tp->num_planchets,
num_planchets);
+ tp->pcds = GNUNET_new_array (num_planchets,
+ struct TALER_EXCHANGE_PrivateCoinDetails);
+ num_csr = 0;
for (unsigned int i = 0; i<num_planchets; i++)
{
- tp->planchets[i].ps = pds[i].ps;
- if (GNUNET_OK !=
- TALER_planchet_prepare (&pds[i].pk->key,
- &tp->planchets[i].alg_values,
- &tp->planchets[i].bks,
- &tp->planchets[i].coin_priv,
- &tp->planchets[i].c_hash,
- &details[i]))
+ const struct TALER_MERCHANT_PlanchetData *pd = &pds[i];
+ const struct TALER_EXCHANGE_DenomPublicKey *pk = pd->pk;
+ struct TALER_EXCHANGE_PrivateCoinDetails *pcd = &tp->pcds[i];
+
+ tp->planchets[i].ps = pd->ps;
+ tp->planchets[i].pk = *pds[i].pk;
+ TALER_denom_pub_deep_copy (&tp->planchets[i].pk.key,
+ &pds[i].pk->key);
+ switch (pk->key.cipher)
{
+ case TALER_DENOMINATION_RSA:
+ pcd->exchange_vals.cipher = TALER_DENOMINATION_RSA;
+ break;
+ case TALER_DENOMINATION_CS:
+ num_csr++;
+ break;
+ default:
GNUNET_break (0);
- for (unsigned int j = 0; j<i; j++)
- TALER_planchet_detail_free (&details[j]);
- GNUNET_array_grow (tp->planchets,
- tp->num_planchets,
- 0);
- GNUNET_free (tp);
+ TALER_MERCHANT_tip_pickup_cancel (tp);
return NULL;
}
}
- for (unsigned int i = 0; i<num_planchets; i++)
+ if (0 == num_csr)
{
- tp->planchets[i].pk = *pds[i].pk;
- TALER_denom_pub_deep_copy (&tp->planchets[i].pk.key,
- &pds[i].pk->key);
+ pickup_post_csr (tp);
+ return tp;
}
- tp->cb = pickup_cb;
- tp->cb_cls = pickup_cb_cls;
- tp->tpo2 = TALER_MERCHANT_tip_pickup2 (ctx,
- backend_url,
- tip_id,
- num_planchets,
- details,
- &pickup_done_cb,
- tp);
- for (unsigned int j = 0; j<num_planchets; j++)
- TALER_planchet_detail_free (&details[j]);
- if (NULL == tp->tpo2)
{
- GNUNET_break (0);
- TALER_MERCHANT_tip_pickup_cancel (tp);
- return NULL;
+ struct TALER_EXCHANGE_NonceKey nks[num_csr];
+ unsigned int off = 0;
+
+ for (unsigned int i = 0; i<tp->num_planchets; i++)
+ {
+ const struct PlanchetData *pd = &tp->planchets[i];
+
+ switch (pd->pk.key.cipher)
+ {
+ case TALER_DENOMINATION_INVALID:
+ GNUNET_assert (0);
+ break;
+ case TALER_DENOMINATION_RSA:
+ break;
+ case TALER_DENOMINATION_CS:
+ nks[off].pk = &pd->pk;
+ TALER_cs_withdraw_nonce_derive (&pd->ps,
+ &nks[off].nonce);
+ off++;
+ break;
+ }
+ }
+ tp->csr = TALER_EXCHANGE_csr (exchange,
+ off,
+ nks,
+ &csr_cb,
+ tp);
+ if (NULL == tp->csr)
+ {
+ GNUNET_break (0);
+ TALER_MERCHANT_tip_pickup_cancel (tp);
+ return NULL;
+ }
}
return tp;
}
@@ -249,7 +434,12 @@ void
TALER_MERCHANT_tip_pickup_cancel (struct TALER_MERCHANT_TipPickupHandle *tp)
{
for (unsigned int i = 0; i<tp->num_planchets; i++)
+ {
+ struct TALER_EXCHANGE_PrivateCoinDetails *pcd = &tp->pcds[i];
+
+ TALER_denom_sig_free (&pcd->sig);
TALER_denom_pub_free (&tp->planchets[i].pk.key);
+ }
GNUNET_array_grow (tp->planchets,
tp->num_planchets,
0);
@@ -258,6 +448,13 @@ TALER_MERCHANT_tip_pickup_cancel (struct TALER_MERCHANT_TipPickupHandle *tp)
TALER_MERCHANT_tip_pickup2_cancel (tp->tpo2);
tp->tpo2 = NULL;
}
+ if (NULL != tp->csr)
+ {
+ TALER_EXCHANGE_csr_cancel (tp->csr);
+ tp->csr = NULL;
+ }
+ GNUNET_free (tp->backend_url);
+ GNUNET_free (tp->pcds);
GNUNET_free (tp);
}
diff --git a/src/testing/testing_api_cmd_tip_pickup.c b/src/testing/testing_api_cmd_tip_pickup.c
index 229ba301..c7dec778 100644
--- a/src/testing/testing_api_cmd_tip_pickup.c
+++ b/src/testing/testing_api_cmd_tip_pickup.c
@@ -22,7 +22,6 @@
* @brief command to test the tipping.
* @author Marcello Stanisci
*/
-
#include "platform.h"
#include <taler/taler_exchange_service.h>
#include <taler/taler_testing_lib.h>
@@ -90,11 +89,6 @@ struct TipPickupState
struct TALER_Amount total_amount;
/**
- * How many coins are involved in the tipping operation.
- */
- uint32_t num_coins;
-
- /**
* The array of denomination keys, in the same order of @a
* amounts.
*/
@@ -107,17 +101,15 @@ struct TipPickupState
struct TALER_PlanchetMasterSecretP *psa;
/**
- * The array of coin private keys, in the same order of @a
- * amounts.
+ * Set (by the interpreter) to an array of @a num_coins
+ * details on coins created from the (successful) tip operation.
*/
- // FIXME: initialize!
- struct TALER_CoinSpendPrivateKeyP *coin_privs;
+ struct TALER_EXCHANGE_PrivateCoinDetails *pcds;
/**
- * Set (by the interpreter) to an array of @a num_coins
- * signatures created from the (successful) tip operation.
+ * How many coins are involved in the tipping operation.
*/
- struct TALER_DenominationSignature *sigs;
+ uint32_t num_coins;
/**
* Expected Taler error code (NOTE: this is NOT the HTTP
@@ -133,52 +125,48 @@ struct TipPickupState
* (and if the status was 200 OK) proceede with the withdrawal.
*
* @param cls closure
- * @param hr HTTP response
- * @param num_sigs length of the @a sigs array,
- * 0 on error
- * @param sigs array of signatures over the coins, NULL on error
+ * @param pd details about the result of the operation
*/
static void
pickup_cb (void *cls,
- const struct TALER_MERCHANT_HttpResponse *hr,
- unsigned int num_sigs,
- const struct TALER_DenominationSignature *sigs,
- const struct TALER_CoinSpendPrivateKeyP *coin_privs)
+ const struct TALER_MERCHANT_PickupDetails *pd)
{
struct TipPickupState *tps = cls;
tps->tpo = NULL;
- if (hr->http_status != tps->http_status)
+ if (pd->hr.http_status != tps->http_status)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u (%d) to command %s\n",
- hr->http_status,
- (int) hr->ec,
+ pd->hr.http_status,
+ (int) pd->hr.ec,
TALER_TESTING_interpreter_get_current_label (tps->is));
TALER_TESTING_FAIL (tps->is);
}
- if (hr->ec != tps->expected_ec)
+ if (pd->hr.ec != tps->expected_ec)
TALER_TESTING_FAIL (tps->is);
/* Safe to go ahead: http status was expected. */
- if ( (MHD_HTTP_OK != hr->http_status) ||
- (TALER_EC_NONE != hr->ec) )
+ if ( (MHD_HTTP_OK != pd->hr.http_status) ||
+ (TALER_EC_NONE != pd->hr.ec) )
{
TALER_TESTING_interpreter_next (tps->is);
return;
}
- if (num_sigs != tps->num_coins)
+ if (pd->details.success.num_sigs != tps->num_coins)
TALER_TESTING_FAIL (tps->is);
- tps->sigs = GNUNET_new_array (tps->num_coins,
- struct TALER_DenominationSignature);
- for (unsigned int i = 0; i<num_sigs; i++)
- TALER_denom_sig_deep_copy (&tps->sigs[i],
- &sigs[i]);
- tps->coin_privs
- = GNUNET_memdup (coin_privs,
- num_sigs
- * sizeof (struct TALER_CoinSpendPrivateKeyP));
+ tps->pcds = GNUNET_new_array (tps->num_coins,
+ struct TALER_EXCHANGE_PrivateCoinDetails);
+ for (unsigned int i = 0; i<tps->num_coins; i++)
+ {
+ struct TALER_EXCHANGE_PrivateCoinDetails *pcd =
+ &pd->details.success.pcds[i];
+
+ tps->pcds[i] = *pcd;
+ TALER_denom_sig_deep_copy (&tps->pcds[i].sig,
+ &pcd->sig);
+ }
TALER_TESTING_interpreter_next (tps->is);
}
@@ -292,6 +280,7 @@ tip_pickup_run (void *cls,
&tip_id))
TALER_TESTING_FAIL (is);
tps->tpo = TALER_MERCHANT_tip_pickup (is->ctx,
+ is->exchange,
tps->merchant_url,
tip_id,
num_planchets,
@@ -319,12 +308,11 @@ tip_pickup_cleanup (void *cls,
GNUNET_free (tps->amounts_obj);
GNUNET_free (tps->dks);
GNUNET_free (tps->psa);
- GNUNET_free (tps->coin_privs);
- if (NULL != tps->sigs)
+ if (NULL != tps->pcds)
{
for (unsigned int i = 0; i<tps->num_coins; i++)
- TALER_denom_sig_free (&tps->sigs[i]);
- GNUNET_free (tps->sigs);
+ TALER_denom_sig_free (&tps->pcds[i].sig);
+ GNUNET_free (tps->pcds);
}
if (NULL != tps->tpo)
{
@@ -350,11 +338,11 @@ tip_pickup_traits (void *cls,
TALER_TESTING_make_trait_planchet_secrets (index,
&tps->psa[index]),
TALER_TESTING_make_trait_coin_priv (index,
- &tps->coin_privs[index]),
+ &tps->pcds[index].coin_priv),
TALER_TESTING_make_trait_denom_pub (index,
tps->dks[index]),
TALER_TESTING_make_trait_denom_sig (index,
- &tps->sigs[index]),
+ &tps->pcds[index].sig),
TALER_TESTING_make_trait_amounts (index,
&tps->amounts_obj[index]),
TALER_TESTING_make_trait_amount (&tps->total_amount),