aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Blättler <blatc2@bfh.ch>2024-04-27 10:12:16 +0200
committerChristian Blättler <blatc2@bfh.ch>2024-04-27 10:12:24 +0200
commitd50651cdfa34213d33c5f8651cbeeba10cc37cfd (patch)
treee83c4bf82b46a6aa75c03b669f697d2b1128d564
parent0df606b95f01408d39adc5b0f24a21b6962950d2 (diff)
work on testing orders with tokens
-rw-r--r--src/include/taler_merchant_service.h43
-rw-r--r--src/include/taler_merchant_testing_lib.h4
-rw-r--r--src/lib/merchant_api_post_order_pay.c77
-rw-r--r--src/testing/test_merchant_api.c45
-rw-r--r--src/testing/testing_api_cmd_pay_order.c63
-rw-r--r--src/testing/testing_api_cmd_post_orders.c23
6 files changed, 230 insertions, 25 deletions
diff --git a/src/include/taler_merchant_service.h b/src/include/taler_merchant_service.h
index 180df516..e3d65188 100644
--- a/src/include/taler_merchant_service.h
+++ b/src/include/taler_merchant_service.h
@@ -3086,6 +3086,39 @@ TALER_MERCHANT_order_claim_cancel (struct TALER_MERCHANT_OrderClaimHandle *och);
/**
+ * All the details about a token that are generated during issuance and
+ * that may be needed for future operations on the coin.
+ */
+struct TALER_MERCHANT_PrivateTokenDetails
+{
+ /**
+ * Private key of the token.
+ */
+ struct TALER_TokenUsePrivateKeyP token_priv;
+
+ /**
+ * Value used to blind the key for the signature.
+ */
+ union GNUNET_CRYPTO_BlindingSecretP blinding_secret;
+
+ /**
+ * Unblinded token issue signature made by the merchant.
+ */
+ struct TALER_TokenIssueSignatureP issue_sig;
+
+ /**
+ * Token issue public key.
+ */
+ struct TALER_TokenIssuePublicKeyP issue_pub;
+
+ /**
+ * Inputs needed from the merchant for blind signing.
+ */
+ struct GNUNET_CRYPTO_BlindingInputValues *blinding_inputs;
+
+};
+
+/**
* @brief Handle to a POST /orders/$ID/pay operation at a merchant. Note that
* we use the same handle for interactions with frontends (API for wallets) or
* backends (API for frontends). The difference is that for the frontend API,
@@ -3128,6 +3161,16 @@ struct TALER_MERCHANT_PayResponse
*/
const char *pos_confirmation;
+ /**
+ * Array of tokens that were issued for the payment.
+ */
+ struct TALER_MERCHANT_PrivateTokenDetails *tokens;
+
+ /**
+ * Length of the @e tokens array.
+ */
+ unsigned int num_tokens;
+
} ok;
// TODO: might want to return further details on errors,
diff --git a/src/include/taler_merchant_testing_lib.h b/src/include/taler_merchant_testing_lib.h
index 12d38fb5..20ac3076 100644
--- a/src/include/taler_merchant_testing_lib.h
+++ b/src/include/taler_merchant_testing_lib.h
@@ -614,6 +614,8 @@ TALER_TESTING_cmd_merchant_post_orders3 (
* the proposal request.
* @param http_status expected HTTP status.
* @param token_family_reference label of the POST /tokenfamilies cmd.
+ * @param num_inputs number of input tokens.
+ * @param num_outputs number of output tokens.
* @param order_id the name of the order to add.
* @param refund_deadline the deadline for refunds on this order.
* @param pay_deadline the deadline for payment on this order.
@@ -628,6 +630,8 @@ TALER_TESTING_cmd_merchant_post_orders_choices (
const char *merchant_url,
unsigned int http_status,
const char *token_family_reference,
+ unsigned int num_inputs,
+ unsigned int num_outputs,
const char *order_id,
struct GNUNET_TIME_Timestamp refund_deadline,
struct GNUNET_TIME_Timestamp pay_deadline,
diff --git a/src/lib/merchant_api_post_order_pay.c b/src/lib/merchant_api_post_order_pay.c
index e56bac60..c74113b6 100644
--- a/src/lib/merchant_api_post_order_pay.c
+++ b/src/lib/merchant_api_post_order_pay.c
@@ -25,6 +25,8 @@
*/
#include "platform.h"
#include <curl/curl.h>
+#include <gnunet/gnunet_common.h>
+#include <gnunet/gnunet_json_lib.h>
#include <jansson.h>
#include <microhttpd.h> /* just for HTTP status codes */
#include <gnunet/gnunet_util_lib.h>
@@ -80,7 +82,7 @@ struct TALER_MERCHANT_OrderPayHandle
struct TALER_MERCHANT_PaidCoin *coins;
/**
- * The tokens we are using.
+ * The tokens we are using as inputs.
*/
struct TALER_MERCHANT_UsedToken *tokens;
@@ -133,6 +135,48 @@ struct TALER_MERCHANT_OrderPayHandle
/**
+ * Parse blindly signed output tokens from response.
+ */
+static enum GNUNET_GenericReturnValue
+parse_tokens (const json_t *token_sigs,
+ struct TALER_MERCHANT_PrivateTokenDetails **tokens,
+ unsigned int *num_tokens)
+{
+ GNUNET_array_grow (*tokens,
+ *num_tokens,
+ json_array_size (token_sigs));
+
+ for (unsigned int i = 0; i<(*num_tokens); i++)
+ {
+ struct TALER_MERCHANT_PrivateTokenDetails *token = &(*tokens)[i];
+ const json_t *js = json_array_get (token_sigs,
+ i);
+
+ if (NULL == js)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ struct GNUNET_JSON_Specification spec[] = {
+ TALER_JSON_spec_token_issue_sig ("blind_sig",
+ &token->issue_sig),
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (js,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ }
+
+ return GNUNET_NO;
+}
+
+
+/**
* Function called when we're done processing the
* HTTP /pay request.
*
@@ -164,15 +208,17 @@ handle_pay_finished (void *cls,
case MHD_HTTP_OK:
if (oph->am_wallet)
{
- /* Here we can (and should) verify the merchant's signature */
+ const json_t *token_sigs = NULL;
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_fixed_auto (
- "sig",
- &pr.details.ok.merchant_sig),
+ GNUNET_JSON_spec_fixed_auto ("sig",
+ &pr.details.ok.merchant_sig),
GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string (
- "pos_confirmation",
- &pr.details.ok.pos_confirmation),
+ GNUNET_JSON_spec_string ("pos_confirmation",
+ &pr.details.ok.pos_confirmation),
+ NULL),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_array_const ("token_sigs",
+ &token_sigs),
NULL),
GNUNET_JSON_spec_end ()
};
@@ -189,6 +235,21 @@ handle_pay_finished (void *cls,
break;
}
+ if (NULL != token_sigs)
+ {
+ if (GNUNET_OK !=
+ parse_tokens (token_sigs,
+ &pr.details.ok.tokens,
+ &pr.details.ok.num_tokens))
+ {
+ GNUNET_break_op (0);
+ pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ pr.hr.http_status = 0;
+ pr.hr.hint = "failed to parse token_sigs field in response";
+ break;
+ }
+ }
+
if (GNUNET_OK !=
TALER_merchant_pay_verify (&oph->h_contract_terms,
&oph->merchant_pub,
diff --git a/src/testing/test_merchant_api.c b/src/testing/test_merchant_api.c
index e71d0002..9f687588 100644
--- a/src/testing/test_merchant_api.c
+++ b/src/testing/test_merchant_api.c
@@ -1693,23 +1693,48 @@ run (void *cls,
GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_YEARS),
GNUNET_TIME_UNIT_MONTHS,
"subscription"),
- TALER_TESTING_cmd_merchant_post_orders_choices ("create-order-with-choices",
+ TALER_TESTING_cmd_merchant_post_orders_choices ("create-order-with-output",
cred.cfg,
merchant_url,
MHD_HTTP_OK,
"create-tokenfamily",
- "5-choices",
+ 0,
+ 1,
+ "5-output",
GNUNET_TIME_UNIT_ZERO_TS,
GNUNET_TIME_UNIT_FOREVER_TS,
"EUR:5.0"),
- TALER_TESTING_cmd_merchant_pay_order ("pay-order-with-choices",
- merchant_url,
- MHD_HTTP_OK,
- "create-order-with-choices",
- "withdraw-coin-1",
- "EUR:5",
- "EUR:4.99",
- NULL),
+ TALER_TESTING_cmd_merchant_pay_order_choices ("pay-order-with-output",
+ merchant_url,
+ MHD_HTTP_OK,
+ "create-order-with-output",
+ "withdraw-coin-1",
+ "EUR:5",
+ "EUR:4.99",
+ NULL,
+ 0,
+ NULL),
+ TALER_TESTING_cmd_merchant_post_orders_choices ("create-order-with-input-and-output",
+ cred.cfg,
+ merchant_url,
+ MHD_HTTP_OK,
+ "create-tokenfamily",
+ 1,
+ 1,
+ "5-input-output",
+ GNUNET_TIME_UNIT_ZERO_TS,
+ GNUNET_TIME_UNIT_FOREVER_TS,
+ "EUR:0.0"),
+ TALER_TESTING_cmd_merchant_pay_order_choices ("pay-order-with-output",
+ merchant_url,
+ MHD_HTTP_OK,
+ "create-order-with-output",
+ "withdraw-coin-1",
+ "EUR:5",
+ "EUR:4.99",
+ NULL,
+ 0,
+ "pay-order-with-output"),
TALER_TESTING_cmd_end ()
};
diff --git a/src/testing/testing_api_cmd_pay_order.c b/src/testing/testing_api_cmd_pay_order.c
index 071a9a23..12653ebc 100644
--- a/src/testing/testing_api_cmd_pay_order.c
+++ b/src/testing/testing_api_cmd_pay_order.c
@@ -65,6 +65,13 @@ struct PayState
const char *coin_reference;
/**
+ * Reference to a command that can provide one or
+ * multiple tokens used as inputs for the payment.
+ * In the form "LABEL0[/INDEX];LABEL1[/INDEX];..."
+ */
+ const char *token_reference;
+
+ /**
* The merchant base URL.
*/
const char *merchant_url;
@@ -95,6 +102,16 @@ struct PayState
struct TALER_MerchantSignatureP merchant_sig;
/**
+ * Array of issued tokens, set on success.
+ */
+ struct TALER_MERCHANT_PrivateTokenDetails *issued_tokens;
+
+ /**
+ * Number of tokens in @e issued_tokens.
+ */
+ unsigned int num_issued_tokens;
+
+ /**
* The session for which the payment is made.
*/
const char *session_id;
@@ -349,15 +366,18 @@ pay_cb (void *cls,
if (ps->http_status != pr->hr.http_status)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u (%d) to command %s\n",
+ "Unexpected response code %u (%d) to command (%s) %s\n",
pr->hr.http_status,
(int) pr->hr.ec,
+ pr->hr.hint,
TALER_TESTING_interpreter_get_current_label (ps->is));
TALER_TESTING_FAIL (ps->is);
}
if (MHD_HTTP_OK == pr->hr.http_status)
{
ps->merchant_sig = pr->details.ok.merchant_sig;
+ ps->issued_tokens = pr->details.ok.tokens;
+ ps->num_issued_tokens = pr->details.ok.num_tokens;
if (NULL != ps->pos_key)
{
char *pc;
@@ -426,6 +446,8 @@ pay_run (void *cls,
unsigned int error_line = 0;
struct TALER_MERCHANT_PayCoin *pay_coins;
unsigned int npay_coins;
+ struct TALER_MERCHANT_UseToken *use_tokens = NULL;
+ unsigned int len_use_tokens = 0;
const struct TALER_MerchantSignatureP *merchant_sig;
const enum TALER_MerchantConfirmationAlgorithm *alg_ptr;
@@ -518,6 +540,25 @@ pay_run (void *cls,
}
GNUNET_free (cr);
}
+ if (NULL != ps->token_reference)
+ {
+ char *tr;
+
+ tr = GNUNET_strdup (ps->token_reference);
+ if (GNUNET_OK !=
+ build_tokens (&use_tokens,
+ &len_use_tokens,
+ tr,
+ is))
+ {
+ GNUNET_array_grow (use_tokens,
+ len_use_tokens,
+ 0);
+ GNUNET_free (tr);
+ TALER_TESTING_FAIL (is);
+ }
+ GNUNET_free (tr);
+ }
if (GNUNET_OK !=
TALER_TESTING_get_trait_merchant_sig (proposal_cmd,
&merchant_sig))
@@ -545,8 +586,8 @@ pay_run (void *cls,
order_id,
npay_coins,
pay_coins,
- 0,
- NULL,
+ len_use_tokens,
+ use_tokens,
&pay_cb,
ps);
GNUNET_array_grow (pay_coins,
@@ -603,6 +644,13 @@ pay_traits (void *cls,
const struct TALER_TESTING_Command *proposal_cmd;
const struct TALER_MerchantPublicKeyP *merchant_pub;
+ if (NULL != ps->token_reference &&
+ index >= ps->num_issued_tokens)
+ {
+ GNUNET_break (0);
+ return GNUNET_NO;
+ }
+
if (NULL ==
(proposal_cmd =
TALER_TESTING_interpreter_lookup_command (ps->is,
@@ -644,6 +692,12 @@ pay_traits (void *cls,
TALER_TESTING_make_trait_amount (&amount_with_fee),
TALER_TESTING_make_trait_otp_key (ps->pos_key),
TALER_TESTING_make_trait_otp_alg (&ps->pos_alg),
+ TALER_TESTING_make_trait_token_priv (index,
+ &ps->issued_tokens[index].token_priv),
+ TALER_TESTING_make_trait_token_issue_pub (index,
+ &ps->issued_tokens[index].issue_pub),
+ TALER_TESTING_make_trait_token_issue_sig (index,
+ &ps->issued_tokens[index].issue_sig),
TALER_TESTING_trait_end ()
};
@@ -666,7 +720,7 @@ TALER_TESTING_cmd_merchant_pay_order_choices (const char *label,
const char *amount_without_fee,
const char *session_id,
int choice_index,
- const char *input_reference)
+ const char *token_reference)
{
struct PayState *ps;
@@ -678,6 +732,7 @@ TALER_TESTING_cmd_merchant_pay_order_choices (const char *label,
ps->amount_with_fee = amount_with_fee;
ps->amount_without_fee = amount_without_fee;
ps->session_id = session_id;
+ ps->token_reference = token_reference;
if (0 <= choice_index)
{
ps->wallet_data = json_pack ("{s:i}",
diff --git a/src/testing/testing_api_cmd_post_orders.c b/src/testing/testing_api_cmd_post_orders.c
index 8f7bd46d..a0f2941c 100644
--- a/src/testing/testing_api_cmd_post_orders.c
+++ b/src/testing/testing_api_cmd_post_orders.c
@@ -65,6 +65,18 @@ struct OrdersState
const char *token_family_reference;
/**
+ * How many tokens of the token family created in
+ * @a token_family_reference are required as inputs.
+ */
+ unsigned int num_inputs;
+
+ /**
+ * How many tokens of the token family created in
+ * @a token_family_reference should be issued as outputs.
+ */
+ unsigned int num_outputs;
+
+ /**
* Contract terms obtained from the backend.
*/
json_t *contract_terms;
@@ -657,9 +669,10 @@ orders_run3 (void *cls,
TALER_TESTING_FAIL (is);
}
make_choices_json (slug, slug,
- 1, 1,
- GNUNET_TIME_absolute_to_timestamp(now),
- GNUNET_TIME_absolute_to_timestamp(now),
+ ps->num_inputs,
+ ps->num_outputs,
+ GNUNET_TIME_absolute_to_timestamp (now),
+ GNUNET_TIME_absolute_to_timestamp (now),
&ps->choices);
GNUNET_assert (0 ==
@@ -962,6 +975,8 @@ TALER_TESTING_cmd_merchant_post_orders_choices (
const char *merchant_url,
unsigned int http_status,
const char *token_family_reference,
+ unsigned int num_inputs,
+ unsigned int num_outputs,
const char *order_id,
struct GNUNET_TIME_Timestamp refund_deadline,
struct GNUNET_TIME_Timestamp pay_deadline,
@@ -978,6 +993,8 @@ TALER_TESTING_cmd_merchant_post_orders_choices (
&ps->order_terms);
ps->http_status = http_status;
ps->token_family_reference = token_family_reference;
+ ps->num_inputs = num_inputs;
+ ps->num_outputs = num_outputs;
ps->expected_order_id = order_id;
ps->merchant_url = merchant_url;
ps->with_claim = true;