aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Blättler <blatc2@bfh.ch>2024-04-10 07:50:56 +0200
committerChristian Blättler <blatc2@bfh.ch>2024-04-10 07:50:56 +0200
commit983ad0943b4f0b9ddf7d1b7a14693e4b69395ea6 (patch)
treeb925a0058d56b43ac4aa2bcad45c24572c92c58d /src
parent53cdcd6cb3aadbeac7d878e817c1314c6fc7c63c (diff)
serialize v1 orders
Diffstat (limited to 'src')
-rw-r--r--src/backend/Makefile.am1
-rw-r--r--src/backend/taler-merchant-httpd_contract.c182
-rw-r--r--src/backend/taler-merchant-httpd_contract.h39
-rw-r--r--src/backend/taler-merchant-httpd_private-post-orders.c495
4 files changed, 260 insertions, 457 deletions
diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am
index d521608d..dbc7cde8 100644
--- a/src/backend/Makefile.am
+++ b/src/backend/Makefile.am
@@ -25,6 +25,7 @@ bin_PROGRAMS = \
taler_merchant_httpd_SOURCES = \
taler-merchant-httpd.c taler-merchant-httpd.h \
taler-merchant-httpd_config.c taler-merchant-httpd_config.h \
+ taler-merchant-httpd_contract.c taler-merchant-httpd_contract.h \
taler-merchant-httpd_exchanges.c taler-merchant-httpd_exchanges.h \
taler-merchant-httpd_get-orders-ID.c \
taler-merchant-httpd_get-orders-ID.h \
diff --git a/src/backend/taler-merchant-httpd_contract.c b/src/backend/taler-merchant-httpd_contract.c
index f850f94d..38c82e70 100644
--- a/src/backend/taler-merchant-httpd_contract.c
+++ b/src/backend/taler-merchant-httpd_contract.c
@@ -45,185 +45,3 @@ TMH_string_to_contract_output_type (const char *str)
return TALER_MCOT_INVALID;
}
-
-enum GNUNET_GenericReturnValue
-TMH_serialize_contract (const struct TALER_MerchantContract *contract,
- const struct TMH_MerchantInstance *instance,
- json_t *exchanges,
- json_t **out)
-{
- if (TALER_MCV_V0 == contract->version)
- {
- return TMH_serialize_contract_v0 (contract, instance, exchanges, out);
- }
-
- if (TALER_MCV_V1 == contract->version)
- {
- return TMH_serialize_contract_v1 (contract, instance, exchanges, out);
- }
-
- GNUNET_break (0);
- return GNUNET_SYSERR;
-}
-
-enum GNUNET_GenericReturnValue
-TMH_serialize_contract_v0 (const struct TALER_MerchantContract *contract,
- const struct TMH_MerchantInstance *instance,
- json_t *exchanges,
- json_t **out)
-{
- json_t *merchant;
-
- {
- merchant = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("name",
- instance->settings.name),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("website",
- instance->settings.website)),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("email",
- instance->settings.email)),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("logo",
- instance->settings.logo)));
- GNUNET_assert (NULL != merchant);
- {
- json_t *loca;
-
- /* Handle merchant address */
- loca = instance->settings.address;
- if (NULL != loca)
- {
- loca = json_deep_copy (loca);
- GNUNET_assert (NULL != loca);
- GNUNET_assert (0 ==
- json_object_set_new (merchant,
- "address",
- loca));
- }
- }
- {
- json_t *juri;
-
- /* Handle merchant jurisdiction */
- juri = instance->settings.jurisdiction;
- if (NULL != juri)
- {
- juri = json_deep_copy (juri);
- GNUNET_assert (NULL != juri);
- GNUNET_assert (0 ==
- json_object_set_new (merchant,
- "jurisdiction",
- juri));
- }
- }
- }
-
- if (1 != contract->choices_len || NULL == contract->choices)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
-
- if (1 != contract->limits_len || NULL == contract->limits)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
-
- struct TALER_MerchantContractChoice *choice = contract->choices;
-
- *out = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("summary",
- choice->summary),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_object_incref ("summary_i18n",
- choice->summary_i18n)),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("public_reorder_url",
- contract->public_reorder_url)),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("fulfillment_message",
- choice->fulfillment_message)),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_object_incref ("fulfillment_message_i18n",
- choice->fulfillment_message_i18n)),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("fulfillment_url",
- choice->fulfillment_url)),
- GNUNET_JSON_pack_array_incref ("products",
- choice->products),
- GNUNET_JSON_pack_data_auto ("h_wire",
- &contract->limits->h_wire),
- GNUNET_JSON_pack_string ("wire_method",
- contract->limits->wire_method),
- GNUNET_JSON_pack_string ("order_id",
- contract->order_id),
- GNUNET_JSON_pack_timestamp ("timestamp",
- contract->timestamp),
- GNUNET_JSON_pack_timestamp ("pay_deadline",
- contract->pay_deadline),
- GNUNET_JSON_pack_timestamp ("wire_transfer_deadline",
- contract->wire_deadline),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_timestamp ("delivery_date",
- contract->delivery_date)),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_object_incref ("delivery_location",
- contract->delivery_location)),
- GNUNET_JSON_pack_string ("merchant_base_url",
- contract->merchant_base_url),
- GNUNET_JSON_pack_object_incref ("merchant",
- merchant),
- GNUNET_JSON_pack_data_auto ("merchant_pub",
- &instance->merchant_pub),
- GNUNET_JSON_pack_array_incref ("exchanges",
- exchanges),
- TALER_JSON_pack_amount ("max_fee",
- &contract->limits->max_fee),
- TALER_JSON_pack_amount ("amount",
- &contract->brutto),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_object_incref ("extra",
- (json_t *) contract->extra))
- );
-
- /* Pack does not work here, because it doesn't set zero-values for timestamps */
- GNUNET_assert (0 ==
- json_object_set_new (*out,
- "refund_deadline",
- GNUNET_JSON_from_timestamp (
- contract->refund_deadline)));
- GNUNET_log (
- GNUNET_ERROR_TYPE_INFO,
- "Refund deadline for contact is %llu\n",
- (unsigned long long) contract->refund_deadline.abs_time.abs_value_us);
- GNUNET_log (
- GNUNET_ERROR_TYPE_INFO,
- "Wallet timestamp for contact is %llu\n",
- (unsigned long long) contract->timestamp.abs_time.abs_value_us);
-
- /* Pack does not work here, because it sets zero-values for relative times */
- /* auto_refund should only be set if it is not 0 */
- if (! GNUNET_TIME_relative_is_zero (contract->auto_refund))
- {
- GNUNET_assert (0 ==
- json_object_set_new (*out,
- "auto_refund",
- GNUNET_JSON_from_time_rel (
- contract->auto_refund)));
- }
-
- return GNUNET_OK;
-}
-
-enum GNUNET_GenericReturnValue
-TMH_serialize_contract_v1 (const struct TALER_MerchantContract *contract,
- const struct TMH_MerchantInstance *instance,
- json_t *exchanges,
- json_t **out)
-{
- // TODO: Implement v1 serializer
- return GNUNET_SYSERR;
-}
diff --git a/src/backend/taler-merchant-httpd_contract.h b/src/backend/taler-merchant-httpd_contract.h
index 06cc8bfe..defe6479 100644
--- a/src/backend/taler-merchant-httpd_contract.h
+++ b/src/backend/taler-merchant-httpd_contract.h
@@ -19,6 +19,7 @@
* @author Christian Blättler
*/
#include "taler-merchant-httpd.h"
+#include <gnunet/gnunet_time_lib.h>
#include <jansson.h>
@@ -112,16 +113,21 @@ struct TALER_MerchantContractInput
struct
{
/**
- * Label of the token authority in the 'token_authorities'
- * array on the top-level.
+ * Slug of the token family to be used.
*/
- const char *token_authority_label;
+ const char *token_family_slug;
+
+ /**
+ * Start time of the validity period of the token. Base on this timestamp
+ * the wallet can find the correct key for this token in token_authorities.
+ */
+ struct GNUNET_TIME_Timestamp valid_after;
/**
* Number of tokens of this type required. Defaults to one if the
* field is not provided.
*/
- unsigned int number;
+ unsigned int count;
} token;
} details;
};
@@ -198,16 +204,21 @@ struct TALER_MerchantContractOutput
struct
{
/**
- * Label of the token authority in the 'token_authorities'
- * array on the top-level.
+ * Slug of the token family to be issued.
*/
- const char *token_authority_label;
+ const char *token_family_slug;
+
+ /**
+ * Start time of the validity period of the token. Base on this timestamp
+ * the wallet can find the correct key for this token in token_authorities.
+ */
+ struct GNUNET_TIME_Timestamp valid_after;
/**
* Number of tokens of this type required. Defaults to one if the
* field is not provided.
*/
- unsigned int number;
+ unsigned int count;
} token;
} details;
};
@@ -277,17 +288,17 @@ struct TALER_MerchantContractTokenAuthority
* Human-readable description of the semantics of the tokens issued by
* this authority.
*/
- char *summary;
+ char *description;
/**
- * Map from IETF BCP 47 language tags to localized summaries.
+ * Map from IETF BCP 47 language tags to localized description.
*/
- json_t *summary_i18n;
+ json_t *description_i18n;
/**
* Public key used to validate tokens signed by this authority.
*/
- struct TALER_TokenFamilyPublicKey key;
+ struct TALER_TokenFamilyPublicKey *pub;
/**
* When will tokens signed by this key expire?
@@ -318,12 +329,12 @@ struct TALER_MerchantContractTokenAuthority
/**
* When does the subscription period start?
*/
- struct GNUNET_TIME_Absolute start_date;
+ struct GNUNET_TIME_Timestamp start_date;
/**
* When does the subscription period end?
*/
- struct GNUNET_TIME_Absolute end_date;
+ struct GNUNET_TIME_Timestamp end_date;
/**
* Array of domain names where this subscription can be safely used
diff --git a/src/backend/taler-merchant-httpd_private-post-orders.c b/src/backend/taler-merchant-httpd_private-post-orders.c
index 1488fe0d..8a093813 100644
--- a/src/backend/taler-merchant-httpd_private-post-orders.c
+++ b/src/backend/taler-merchant-httpd_private-post-orders.c
@@ -29,6 +29,7 @@
#include <gnunet/gnunet_json_lib.h>
#include <gnunet/gnunet_time_lib.h>
#include <jansson.h>
+#include <microhttpd.h>
#include <string.h>
#include <taler/taler_error_codes.h>
#include <taler/taler_signatures.h>
@@ -283,11 +284,6 @@ struct OrderContext
const json_t *choices;
/**
- * Maps authority labels to token details. Is null for v0 contracts.
- */
- const json_t *token_types;
-
- /**
* Merchant base URL.
*/
char *merchant_base_url;
@@ -353,22 +349,6 @@ struct OrderContext
} parse_order;
/**
- * Information set in the ORDER_PHASE_PARSE_TOKEN_TYPES phase.
- */
- struct
- {
- /**
- * Array of token types referenced in the contract.
- */
- struct TALER_MerchantContractTokenAuthority *authorities;
-
- /**
- * Length of the @e authorities array.
- */
- unsigned int authorities_len;
- } parse_token_types;
-
- /**
* Information set in the ORDER_PHASE_PARSE_CHOICES phase.
*/
struct
@@ -384,6 +364,16 @@ struct OrderContext
* Length of the @e choices array.
*/
unsigned int choices_len;
+
+ /**
+ * Array of token types referenced in the contract.
+ */
+ struct TALER_MerchantContractTokenAuthority *authorities;
+
+ /**
+ * Length of the @e authorities array.
+ */
+ unsigned int authorities_len;
} parse_choices;
/**
@@ -503,7 +493,6 @@ struct OrderContext
{
ORDER_PHASE_PARSE_REQUEST,
ORDER_PHASE_PARSE_ORDER,
- ORDER_PHASE_PARSE_TOKEN_TYPES,
ORDER_PHASE_PARSE_CHOICES,
ORDER_PHASE_MERGE_INVENTORY,
ORDER_PHASE_ADD_PAYMENT_DETAILS,
@@ -1296,6 +1285,146 @@ get_exchange_keys (void *cls,
}
/**
+ * Fetch details about the token family with the given @a slug
+ * and add them to the list of token authorities. Check if the
+ * token family already has a valid key configured and if not,
+ * create a new one.
+ *
+ * @param[in,out] oc order context
+ * @param slug slug of the token family
+ * @param start_date validity start date of the token
+ */
+static MHD_RESULT
+set_token_authority (struct OrderContext *oc,
+ const char *slug,
+ struct GNUNET_TIME_Timestamp start_date)
+{
+ struct TALER_MERCHANTDB_TokenFamilyKeyDetails key_details;
+ struct TALER_MerchantContractTokenAuthority authority;
+ enum GNUNET_DB_QueryStatus qs;
+ struct GNUNET_TIME_Absolute min_start_date = GNUNET_TIME_absolute_subtract (
+ start_date.abs_time,
+ // TODO: make this configurable. This is the granularity of token
+ // expiration dates.
+ GNUNET_TIME_UNIT_DAYS
+ );
+
+ qs = TMH_db->lookup_token_family_key (TMH_db->cls,
+ oc->hc->instance->settings.id,
+ slug,
+ GNUNET_TIME_absolute_to_timestamp (min_start_date),
+ start_date,
+ &key_details);
+
+ if (qs <= 0)
+ {
+ enum TALER_ErrorCode ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
+ unsigned int http_status = 0;
+
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ ec = TALER_EC_GENERIC_DB_FETCH_FAILED;
+ break;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ ec = TALER_EC_GENERIC_DB_SOFT_FAILURE;
+ break;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Token family slug unknown\n");
+ http_status = MHD_HTTP_NOT_FOUND;
+ /* TODO: Add specific error code */
+ ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
+ break;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ /* case listed to make compilers happy */
+ GNUNET_assert (0);
+ }
+ GNUNET_break (0);
+ reply_with_error (oc,
+ http_status,
+ ec,
+ "authority_label");
+ return MHD_NO;
+ }
+
+ if (NULL == key_details.pub)
+ {
+ /* If public key is NULL, private key must also be NULL */
+ GNUNET_assert (NULL == key_details.priv);
+
+ struct GNUNET_CRYPTO_BlindSignPrivateKey *priv;
+ struct GNUNET_CRYPTO_BlindSignPublicKey *pub;
+ struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
+ struct GNUNET_TIME_Timestamp valid_before = GNUNET_TIME_absolute_to_timestamp(
+ GNUNET_TIME_absolute_add (now,
+ key_details.token_family.duration));
+
+ // TODO: Should I add a wrapper around this, so it directly accepts structs of type
+ // TALER_TokenFamilyPublicKey and TALER_TokenFamilyPrivateKey?
+ GNUNET_CRYPTO_blind_sign_keys_create (&priv,
+ &pub,
+ // TODO: Make cipher and key length configurable
+ GNUNET_CRYPTO_BSA_RSA,
+ 4096);
+
+ struct TALER_TokenFamilyPublicKey token_pub = {
+ .public_key = *pub,
+ };
+ struct TALER_TokenFamilyPrivateKey token_priv = {
+ .private_key = *priv,
+ };
+
+ qs = TMH_db->insert_token_family_key (TMH_db->cls,
+ slug,
+ &token_pub,
+ &token_priv,
+ GNUNET_TIME_absolute_to_timestamp (now),
+ valid_before);
+
+ authority.token_expiration = valid_before;
+ authority.pub = &token_pub;
+ // GNUNET_CRYPTO_blind_sign_priv_decref (&token_priv.private_key);
+ } else {
+ authority.token_expiration = key_details.valid_before;
+ authority.pub = key_details.pub;
+ }
+
+ authority.label = slug;
+ authority.description = key_details.token_family.description;
+ authority.description_i18n = key_details.token_family.description_i18n;
+
+ GNUNET_free (key_details.token_family.slug);
+ GNUNET_free (key_details.token_family.name);
+ if (NULL != key_details.priv) {
+ GNUNET_CRYPTO_blind_sign_priv_decref (&key_details.priv->private_key);
+ }
+
+ switch (key_details.token_family.kind) {
+ case TALER_MERCHANTDB_TFK_Subscription:
+ authority.kind = TALER_MCTK_SUBSCRIPTION;
+ authority.details.subscription.start_date = key_details.valid_after;
+ authority.details.subscription.end_date = key_details.valid_before;
+ authority.critical = true;
+ // TODO: Set trusted domains
+ break;
+ case TALER_MERCHANTDB_TFK_Discount:
+ authority.kind = TALER_MCTK_DISCOUNT;
+ authority.critical = false;
+ // TODO: Set expected domains
+ break;
+ }
+
+ GNUNET_array_append (oc->parse_choices.authorities,
+ oc->parse_choices.authorities_len,
+ authority);
+
+ return MHD_YES;
+}
+
+/**
* Serialize order into @a oc->serialize_order.contract,
* ready to be stored in the database. Upon success, continue
* processing with check_contract().
@@ -1308,8 +1437,8 @@ serialize_order (struct OrderContext *oc)
const struct TALER_MERCHANTDB_InstanceSettings *settings =
&oc->hc->instance->settings;
json_t *merchant = NULL;
- json_t *token_types = NULL;
- json_t *choices = NULL;
+ json_t *token_types = json_object ();
+ json_t *choices = json_array ();
{
merchant = GNUNET_JSON_PACK (
@@ -1358,21 +1487,37 @@ serialize_order (struct OrderContext *oc)
}
{
- for (unsigned int i = 0; i<oc->parse_token_types.authorities_len; i++)
+ for (unsigned int i = 0; i<oc->parse_choices.authorities_len; i++)
{
- struct TALER_MerchantContractTokenAuthority *authority = &oc->parse_token_types.authorities[i];
-
- // TODO: What information about a token family do we want to store in the db?
+ struct TALER_MerchantContractTokenAuthority *authority = &oc->parse_choices.authorities[i];
+
+ // TODO: Finish spec to clearly define how token families are stored in
+ // ContractTerms.
+ // Here are some thoughts:
+ // - Multiple keys of the same token family can be referrenced in
+ // one contract. E.g. exchanging old subscription for new.
+ // - TokenAuthority should be renamed to TokenFamily for consistency.
+ // - TokenFamilySlug can be used instead of TokenAuthorityLabel, but
+ // every token-based in- or ouput needs to have a valid_after date,
+ // so it's clear with key is referenced.
json_t *jauthority = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("summary",
- authority->summary),
+ GNUNET_JSON_pack_string ("description",
+ authority->description),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_object_incref ("description_i18n",
+ authority->description_i18n)),
GNUNET_JSON_pack_data_auto ("h_pub",
- &authority->key.public_key.pub_key_hash),
+ &authority->pub->public_key.pub_key_hash),
+ GNUNET_JSON_pack_data_auto ("pub",
+ &authority->pub->public_key.pub_key_hash),
GNUNET_JSON_pack_timestamp ("token_expiration",
authority->token_expiration)
);
- json_object_set_new (token_types, authority->label, jauthority);
+ GNUNET_assert (0 ==
+ json_object_set_new (token_types,
+ authority->label,
+ jauthority));
}
}
@@ -1381,8 +1526,8 @@ serialize_order (struct OrderContext *oc)
{
struct TALER_MerchantContractChoice *choice = &oc->parse_choices.choices[i];
- json_t *inputs = NULL;
- json_t *outputs = NULL;
+ json_t *inputs = json_array ();
+ json_t *outputs = json_array ();
for (unsigned int j = 0; j<choice->inputs_len; j++)
{
@@ -1399,15 +1544,15 @@ serialize_order (struct OrderContext *oc)
json_object_set_new(jinput,
"number",
json_integer (
- input->details.token.number)));
+ input->details.token.count)));
GNUNET_assert(0 ==
json_object_set_new(jinput,
- "token_authority_label",
+ "token_family_slug",
json_string (
- input->details.token.token_authority_label)));
+ input->details.token.token_family_slug)));
}
- json_array_append_new (inputs, jinput);
+ GNUNET_assert (0 == json_array_append_new (inputs, jinput));
}
for (unsigned int j = 0; j<choice->outputs_len; j++)
@@ -1425,16 +1570,16 @@ serialize_order (struct OrderContext *oc)
json_object_set_new(joutput,
"number",
json_integer (
- output->details.token.number)));
+ output->details.token.count)));
GNUNET_assert(0 ==
json_object_set_new(joutput,
- "token_authority_label",
+ "token_family_slug",
json_string (
- output->details.token.token_authority_label)));
+ output->details.token.token_family_slug)));
}
- json_array_append_new (outputs, joutput);
+ GNUNET_assert (0 == json_array_append (outputs, joutput));
}
json_t *jchoice = GNUNET_JSON_PACK (
@@ -1444,7 +1589,7 @@ serialize_order (struct OrderContext *oc)
outputs)
);
- json_array_append_new (choices, jchoice);
+ GNUNET_assert (0 == json_array_append (choices, jchoice));
}
}
@@ -1501,12 +1646,12 @@ serialize_order (struct OrderContext *oc)
TALER_JSON_pack_amount ("amount",
&oc->parse_order.brutto),
GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_object_incref("choices",
- choices)
+ GNUNET_JSON_pack_array_incref ("choices",
+ choices)
),
GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_object_incref("token_types",
- token_types)
+ GNUNET_JSON_pack_object_incref ("token_types",
+ token_types)
),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_object_incref ("extra",
@@ -1644,7 +1789,7 @@ set_exchanges (struct OrderContext *oc)
/**
* Parse the order field of the request. Upon success, continue
- * processing with parse_token_types().
+ * processing with parse_choices().
*
* @param[in,out] oc order context
*/
@@ -1710,10 +1855,6 @@ parse_order (struct OrderContext *oc)
&jmerchant),
NULL),
GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_object_const ("token_types",
- &oc->parse_order.token_types),
- NULL),
- GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_timestamp ("timestamp",
&oc->parse_order.timestamp),
NULL),
@@ -1779,17 +1920,6 @@ parse_order (struct OrderContext *oc)
"choices array must be null for v0 contracts");
return;
}
-
- if (NULL != oc->parse_order.token_types)
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- reply_with_error (oc,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_UNEXPECTED_REQUEST_ERROR,
- "token_types object must be null for v0 contracts");
- return;
- }
}
else if (0 == strcmp("1", version))
{
@@ -1805,18 +1935,6 @@ parse_order (struct OrderContext *oc)
"order.choices is not a valid array");
return;
}
-
- if (oc->parse_order.token_types != NULL &&
- ! json_is_object(oc->parse_order.token_types))
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- reply_with_error (oc,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_PARAMETER_MALFORMED,
- "order.token_types is not a valid object");
- return;
- }
}
else
{
@@ -2120,153 +2238,6 @@ parse_order (struct OrderContext *oc)
}
/**
- * Parse the token_types map of the request. Upon success, continue
- * processing with parse_choices().
- */
-static void
-parse_token_types (struct OrderContext *oc)
-{
- if (NULL == oc->parse_order.token_types)
- {
- oc->phase++;
- return;
- }
-
- const char *key;
- json_t *value;
-
- json_object_foreach ((json_t*) oc->parse_order.token_types,
- key,
- value)
- {
- struct TALER_MerchantContractTokenAuthority authority;
- const char *error_name;
- unsigned int error_line;
- // const json_t *jpublic_key = NULL;
-
- {
- struct GNUNET_JSON_Specification spec[] = {
- // GNUNET_JSON_spec_object_const ("key", &jpublic_key),
- GNUNET_JSON_spec_bool ("critical", &authority.critical),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (value,
- spec,
- &error_name,
- &error_line))
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- reply_with_error (oc,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_PARAMETER_MALFORMED,
- error_name);
- return;
- }
- }
-
-
- {
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_rsa_public_key ("rsa_pub", &authority.key.public_key.details.rsa_public_key),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (jpublic_key,
- spec,
- NULL,
- NULL))
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- reply_with_error (oc,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_PARAMETER_MALFORMED,
- "key object of token type is invalid");
- return;
- }
- }
-
- authority.key.public_key.cipher = GNUNET_CRYPTO_BSA_RSA;
-
- GNUNET_CRYPTO_rsa_public_key_hash (
- authority.key.public_key.details.rsa_public_key,
- &authority.key.public_key.pub_key_hash);
-
- {
- struct TALER_MERCHANTDB_TokenFamilyKeyDetails key_details;
- enum GNUNET_DB_QueryStatus qs;
-
- qs = TMH_db->lookup_token_family_key (TMH_db->cls,
- oc->hc->instance->settings.id,
- &authority.key.public_key.pub_key_hash,
- &key_details);
-
- if (qs <= 0)
- {
- enum TALER_ErrorCode ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
- unsigned int http_status = 0;
-
- switch (qs)
- {
- case GNUNET_DB_STATUS_HARD_ERROR:
- GNUNET_break (0);
- http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
- ec = TALER_EC_GENERIC_DB_FETCH_FAILED;
- break;
- case GNUNET_DB_STATUS_SOFT_ERROR:
- GNUNET_break (0);
- http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
- ec = TALER_EC_GENERIC_DB_SOFT_FAILURE;
- break;
- case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Token family public key unknown\n");
- http_status = MHD_HTTP_NOT_FOUND;
- // TODO: Add error code
- ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
- break;
- case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
- /* case listed to make compilers happy */
- GNUNET_assert (0);
- }
- reply_with_error (oc,
- http_status,
- ec,
- "token type public key unknown");
- return;
- }
-
- // TODO: Copy relevant fields from key_details to authority
- // TODO: Don't free key_details.token_family, because we steal the references here
- authority.label = key;
- authority.summary = key_details.token_family.description;
- authority.summary_i18n = key_details.token_family.description_i18n;
-
- switch (key_details.token_family.kind) {
- case TALER_MERCHANTDB_TFK_Subscription:
- authority.kind = TALER_MCTK_SUBSCRIPTION;
- break;
- case TALER_MERCHANTDB_TFK_Discount:
- authority.kind = TALER_MCTK_DISCOUNT;
- break;
- }
-
- // TODO: Free members of key_details which I didn't steal (private key)
- }
-
- GNUNET_array_append (oc->parse_token_types.authorities,
- oc->parse_token_types.authorities_len,
- authority);
- }
-
- oc->phase++;
-}
-
-/**
* Parse contract choices. Upon success, continue
* processing with merge_inventory().
*
@@ -2305,7 +2276,6 @@ parse_choices (struct OrderContext *oc)
&error_line);
if (GNUNET_OK != ret)
{
- GNUNET_JSON_parse_free (spec);
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Choice parsing failed: %s:%u\n",
error_name,
@@ -2320,7 +2290,6 @@ parse_choices (struct OrderContext *oc)
if (! json_is_array (jinputs) ||
! json_is_array (joutputs))
{
- GNUNET_JSON_parse_free (spec);
GNUNET_break_op (0);
reply_with_error (oc,
MHD_HTTP_BAD_REQUEST,
@@ -2339,7 +2308,7 @@ parse_choices (struct OrderContext *oc)
// Or should i use GNUNET_grow first and then get the element using the index?
// Assuming you add a field in the future, it's easier to that way, so you don't
// free it.
- struct TALER_MerchantContractInput input = {.details.token.number = 1};
+ struct TALER_MerchantContractInput input = {.details.token.count = 1};
const char *kind;
const char *ierror_name;
unsigned int ierror_line;
@@ -2347,11 +2316,13 @@ parse_choices (struct OrderContext *oc)
struct GNUNET_JSON_Specification ispec[] = {
GNUNET_JSON_spec_string ("kind",
&kind),
- GNUNET_JSON_spec_string ("authority_label",
- &input.details.token.token_authority_label),
+ GNUNET_JSON_spec_string ("token_family_slug",
+ &input.details.token.token_family_slug),
+ GNUNET_JSON_spec_timestamp ("valid_after",
+ &input.details.token.valid_after),
GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_uint32 ("number",
- &input.details.token.number),
+ GNUNET_JSON_spec_uint32 ("count",
+ &input.details.token.count),
NULL),
GNUNET_JSON_spec_end()
};
@@ -2362,10 +2333,6 @@ parse_choices (struct OrderContext *oc)
&ierror_name,
&ierror_line))
{
- // TODO: I have to call free here beucase the input is not yet appended to the array.
- // So its lifecycle ends here.
- GNUNET_JSON_parse_free (spec);
- GNUNET_JSON_parse_free (ispec);
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Invalid input #%u for field %s\n",
(unsigned int) idx,
@@ -2378,12 +2345,9 @@ parse_choices (struct OrderContext *oc)
}
input.type = TMH_string_to_contract_input_type (kind);
- // TODO: Where / when do I have to free kind?
if (TALER_MCIT_INVALID == input.type)
{
- GNUNET_JSON_parse_free (spec);
- GNUNET_JSON_parse_free (ispec);
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Field 'kind' invalid in input #%u\n",
(unsigned int) idx);
@@ -2394,7 +2358,7 @@ parse_choices (struct OrderContext *oc)
return;
}
- if (0 == input.details.token.number)
+ if (0 == input.details.token.count)
{
/* Ignore inputs with 'number' field set to 0 */
continue;
@@ -2402,10 +2366,10 @@ parse_choices (struct OrderContext *oc)
bool found = false;
- for (unsigned int i = 0; i<oc->parse_token_types.authorities_len; i++)
+ for (unsigned int i = 0; i<oc->parse_choices.authorities_len; i++)
{
- if (0 == strcmp (oc->parse_token_types.authorities[i].label,
- input.details.token.token_authority_label))
+ if (0 == strcmp (oc->parse_choices.authorities[i].label,
+ input.details.token.token_family_slug))
{
found = true;
break;
@@ -2414,8 +2378,15 @@ parse_choices (struct OrderContext *oc)
if (! found)
{
- // TODO: Lookup token family by token_authority_label (slug),
- // append to authorities array.
+ MHD_RESULT res;
+ res = set_token_authority (oc,
+ input.details.token.token_family_slug,
+ input.details.token.valid_after);
+
+ if (MHD_NO == res)
+ {
+ return;
+ }
}
GNUNET_array_append (oc->parse_choices.choices[i].inputs,
@@ -2429,19 +2400,21 @@ parse_choices (struct OrderContext *oc)
size_t idx;
json_array_foreach ((json_t *) joutputs, idx, joutput)
{
- struct TALER_MerchantContractOutput output = { .details.token.number = 1 };
+ struct TALER_MerchantContractOutput output = { .details.token.count = 1 };
const char *kind;
const char *ierror_name;
unsigned int ierror_line;
struct GNUNET_JSON_Specification ispec[] = {
GNUNET_JSON_spec_string ("kind",
- &kind),
- GNUNET_JSON_spec_string ("authority_label",
- &output.details.token.token_authority_label),
+ &kind),
+ GNUNET_JSON_spec_string ("token_family_slug",
+ &output.details.token.token_family_slug),
+ GNUNET_JSON_spec_timestamp ("valid_after",
+ &output.details.token.valid_after),
GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_uint32 ("number",
- &output.details.token.number),
+ GNUNET_JSON_spec_uint32 ("count",
+ &output.details.token.count),
NULL),
GNUNET_JSON_spec_end()
};
@@ -2481,7 +2454,7 @@ parse_choices (struct OrderContext *oc)
return;
}
- if (0 == output.details.token.number)
+ if (0 == output.details.token.count)
{
/* Ignore outputs with 'number' field set to 0 */
continue;
@@ -2489,10 +2462,10 @@ parse_choices (struct OrderContext *oc)
bool found = false;
- for (unsigned int i = 0; i<oc->parse_token_types.authorities_len; i++)
+ for (unsigned int i = 0; i<oc->parse_choices.authorities_len; i++)
{
- if (0 == strcmp (oc->parse_token_types.authorities[i].label,
- output.details.token.token_authority_label))
+ if (0 == strcmp (oc->parse_choices.authorities[i].label,
+ output.details.token.token_family_slug))
{
found = true;
break;
@@ -2501,8 +2474,15 @@ parse_choices (struct OrderContext *oc)
if (! found)
{
- // TODO: Lookup token family by token_authority_label (slug),
- // append to authorities array.
+ MHD_RESULT res;
+ res = set_token_authority (oc,
+ output.details.token.token_family_slug,
+ output.details.token.valid_after);
+
+ if (MHD_NO == res)
+ {
+ return;
+ }
}
GNUNET_array_append (oc->parse_choices.choices[i].outputs,
@@ -2510,8 +2490,6 @@ parse_choices (struct OrderContext *oc)
output);
}
}
-
- // TODO: Do I have to free spec here?
}
oc->phase++;
@@ -2719,8 +2697,6 @@ parse_request (struct OrderContext *oc)
spec);
if (GNUNET_OK != ret)
{
- // TODO: Question: Why no GNUNET_JSON_parse_free (spec) here?
- // How are e.g. oc->parse_request.payment_target or otp_id freed?
GNUNET_break_op (0);
finalize_order2 (oc,
ret);
@@ -2900,9 +2876,6 @@ TMH_private_post_orders (
case ORDER_PHASE_PARSE_ORDER:
parse_order (oc);
break;
- case ORDER_PHASE_PARSE_TOKEN_TYPES:
- parse_token_types (oc);
- break;
case ORDER_PHASE_PARSE_CHOICES:
parse_choices (oc);
break;