summaryrefslogtreecommitdiff
path: root/src/backend/taler-merchant-httpd_private-post-orders.c
diff options
context:
space:
mode:
authorChristian Blättler <blatc2@bfh.ch>2024-03-10 19:52:44 +0100
committerChristian Blättler <blatc2@bfh.ch>2024-03-10 19:52:44 +0100
commitf6cb7a8193a01f9d3c050631cea181b8864162db (patch)
tree3c38498188eb4b00b7463c05349bc0c4b3cca3cb /src/backend/taler-merchant-httpd_private-post-orders.c
parenta290b4b02940bd702720b469a8c88a6ee931813b (diff)
downloadmerchant-f6cb7a8193a01f9d3c050631cea181b8864162db.tar.gz
merchant-f6cb7a8193a01f9d3c050631cea181b8864162db.tar.bz2
merchant-f6cb7a8193a01f9d3c050631cea181b8864162db.zip
first shot at v1 contract serialization
Diffstat (limited to 'src/backend/taler-merchant-httpd_private-post-orders.c')
-rw-r--r--src/backend/taler-merchant-httpd_private-post-orders.c353
1 files changed, 303 insertions, 50 deletions
diff --git a/src/backend/taler-merchant-httpd_private-post-orders.c b/src/backend/taler-merchant-httpd_private-post-orders.c
index 1c25da4e..d8120e91 100644
--- a/src/backend/taler-merchant-httpd_private-post-orders.c
+++ b/src/backend/taler-merchant-httpd_private-post-orders.c
@@ -243,7 +243,7 @@ struct OrderContext
const char *public_reorder_url;
/**
- * Optional array of contract choices. Is null for v0 contracts.
+ * Array of contract choices. Is null for v0 contracts.
*/
const json_t *choices;
@@ -289,6 +289,18 @@ struct OrderContext
struct TALER_Amount brutto;
/**
+ * Array of limits per currency. Is null for v0 contracts.
+ * See @e max_fees for v0 contracts.
+ */
+ // const json_t *limits;
+
+ /**
+ * Maximum fee as given by the client request. Only used in v0 contracts.
+ * See @e limits for v1 contracts.
+ */
+ // struct TALER_Amount max_fee;
+
+ /**
* Array of fee limits and wire account details by currency.
*/
struct TALER_MerchantContractLimits *limits;
@@ -1246,20 +1258,12 @@ get_exchange_keys (void *cls,
rx);
}
-
-/**
- * Serialize order into @a oc->serialize_order.contract,
- * ready to be stored in the database. Upon success, continue
- * processing with check_contract().
- *
- * @param[in,out] oc order context
- */
static void
-serialize_order (struct OrderContext *oc)
+serialize_order_v0 (struct OrderContext *oc)
{
const struct TALER_MERCHANTDB_InstanceSettings *settings =
&oc->hc->instance->settings;
- struct TALER_MerchantContractChoice *choice = oc->parse_order.choices;
+ struct TALER_MerchantContractChoice *choice = oc->parse_choices.choices;
struct TALER_MerchantContractLimits *limits = oc->set_max_fee.limits;
json_t *merchant = NULL;
@@ -1393,10 +1397,195 @@ serialize_order (struct OrderContext *oc)
GNUNET_JSON_from_time_rel (
oc->parse_order.auto_refund)));
}
+}
- oc->phase++;
+static void
+serialize_order_v1 (struct OrderContext *oc)
+{
+ const struct TALER_MERCHANTDB_InstanceSettings *settings =
+ &oc->hc->instance->settings;
+ json_t *merchant = NULL;
+ json_t *limits = json_object ();
+ json_t *choices = json_array ();
+
+ {
+ merchant = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("name",
+ settings->name),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("website",
+ settings->website)),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("email",
+ settings->email)),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("logo",
+ settings->logo)));
+ GNUNET_assert (NULL != merchant);
+ {
+ json_t *loca;
+
+ /* Handle merchant address */
+ loca = 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 = settings->jurisdiction;
+ if (NULL != juri)
+ {
+ juri = json_deep_copy (juri);
+ GNUNET_assert (NULL != juri);
+ GNUNET_assert (0 ==
+ json_object_set_new (merchant,
+ "jurisdiction",
+ juri));
+ }
+ }
+ }
+
+ for (unsigned int i = 0; i<oc->set_max_fee.limits_len; i++)
+ {
+ struct TALER_MerchantContractLimits l = oc->set_max_fee.limits[i];
+ GNUNET_assert (0 ==
+ json_object_set_new(
+ limits,
+ l.currency,
+ GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_data_auto ("h_wire",
+ &l.h_wire),
+ GNUNET_JSON_pack_string ("wire_method",
+ l.wire_method),
+ TALER_JSON_pack_amount("max_fee",
+ &l.max_fee))));
+ }
+
+ for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
+ {
+ struct TALER_MerchantContractChoice choice = oc->parse_choices.choices[i];
+ GNUNET_assert (0 ==
+ json_array_append_new(
+ choices,
+ 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 ("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)))));
+ }
+
+ oc->serialize_order.contract = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_object_incref ("choices",
+ choices)),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_object_incref ("limits",
+ limits)),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("public_reorder_url",
+ oc->parse_order.public_reorder_url)),
+ GNUNET_JSON_pack_array_incref ("products",
+ oc->merge_inventory.products),
+ GNUNET_JSON_pack_data_auto ("h_wire",
+ &oc->add_payment_details.wm->h_wire),
+ GNUNET_JSON_pack_string ("wire_method",
+ oc->add_payment_details.wm->wire_method),
+ GNUNET_JSON_pack_string ("order_id",
+ oc->parse_order.order_id),
+ GNUNET_JSON_pack_timestamp ("timestamp",
+ oc->parse_order.timestamp),
+ GNUNET_JSON_pack_timestamp ("pay_deadline",
+ oc->parse_order.pay_deadline),
+ GNUNET_JSON_pack_timestamp ("wire_transfer_deadline",
+ oc->parse_order.wire_deadline),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_timestamp ("delivery_date",
+ oc->parse_order.delivery_date)),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_object_incref ("delivery_location",
+ oc->parse_order.delivery_location)),
+ GNUNET_JSON_pack_string ("merchant_base_url",
+ oc->parse_order.merchant_base_url),
+ GNUNET_JSON_pack_object_incref ("merchant",
+ merchant),
+ GNUNET_JSON_pack_data_auto ("merchant_pub",
+ &oc->hc->instance->merchant_pub),
+ GNUNET_JSON_pack_array_incref ("exchanges",
+ oc->set_exchanges.exchanges),
+ TALER_JSON_pack_amount ("amount",
+ &oc->parse_order.brutto),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_object_incref ("extra",
+ (json_t *) oc->parse_order.extra))
+ );
+
+ /* Pack does not work here, because it doesn't set zero-values for timestamps */
+ GNUNET_assert (0 ==
+ json_object_set_new (oc->serialize_order.contract,
+ "refund_deadline",
+ GNUNET_JSON_from_timestamp (
+ oc->parse_order.refund_deadline)));
+ GNUNET_log (
+ GNUNET_ERROR_TYPE_INFO,
+ "Refund deadline for contact is %llu\n",
+ (unsigned long long) oc->parse_order.refund_deadline.abs_time.abs_value_us);
+ GNUNET_log (
+ GNUNET_ERROR_TYPE_INFO,
+ "Wallet timestamp for contact is %llu\n",
+ (unsigned long long) oc->parse_order.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 (oc->parse_order.auto_refund))
+ {
+ GNUNET_assert (0 ==
+ json_object_set_new (oc->serialize_order.contract,
+ "auto_refund",
+ GNUNET_JSON_from_time_rel (
+ oc->parse_order.auto_refund)));
+ }
}
+/**
+ * Serialize order into @a oc->serialize_order.contract,
+ * ready to be stored in the database. Upon success, continue
+ * processing with check_contract().
+ *
+ * @param[in,out] oc order context
+ */
+static void
+serialize_order (struct OrderContext *oc)
+{
+ if (TALER_MCV_V0 == oc->parse_order.version)
+ {
+ serialize_order_v0 (oc);
+ }
+ else
+ {
+ serialize_order_v1 (oc);
+ }
+
+ oc->phase++;
+}
/**
* Set max_fee in @a oc based on STEFAN value if
@@ -1410,27 +1599,30 @@ set_max_fee (struct OrderContext *oc)
{
const struct TALER_MERCHANTDB_InstanceSettings *settings =
&oc->hc->instance->settings;
- struct TALER_MerchantContractLimits *parsed_limits = oc->parse_order.limits;
- struct TALER_MerchantContractLimits *limits = oc->set_max_fee.limits;
- GNUNET_assert (1 == oc->parse_order.limits_len && NULL != parsed_limits);
- GNUNET_assert (1 == oc->set_max_fee.limits_len && NULL != limits);
+ GNUNET_array_grow(oc->set_max_fee.limits,
+ oc->set_max_fee.limits_len,
+ oc->parse_order.limits_len);
- if (GNUNET_OK !=
- TALER_amount_is_valid (&parsed_limits->max_fee))
+ for (unsigned int i = 0; i<oc->parse_order.limits_len; i++)
{
- struct TALER_Amount stefan;
+ if (GNUNET_OK !=
+ TALER_amount_is_valid (&oc->parse_order.limits[i].max_fee))
+ {
+ struct TALER_Amount stefan;
- if ( (settings->use_stefan) &&
- (GNUNET_OK ==
- TALER_amount_is_valid (&oc->set_exchanges.max_stefan_fee)) )
- stefan = oc->set_exchanges.max_stefan_fee;
- else
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_zero (oc->parse_order.brutto.currency,
- &stefan));
- limits->max_fee = stefan;
+ if ( (settings->use_stefan) &&
+ (GNUNET_OK ==
+ TALER_amount_is_valid (&oc->set_exchanges.max_stefan_fee)) )
+ stefan = oc->set_exchanges.max_stefan_fee;
+ else
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_set_zero (oc->parse_order.brutto.currency,
+ &stefan));
+ oc->set_max_fee.limits[i].max_fee = stefan;
+ }
}
+
oc->phase++;
}
@@ -1508,18 +1700,21 @@ set_exchanges (struct OrderContext *oc)
static void
parse_order (struct OrderContext *oc)
{
- struct TALER_MerchantContractLimits *limits;
+ // struct TALER_MerchantContractLimits *limits;
const struct TALER_MERCHANTDB_InstanceSettings *settings =
&oc->hc->instance->settings;
const char *merchant_base_url = NULL;
const char *version = NULL;
const json_t *jmerchant = NULL;
- limits = GNUNET_new (struct TALER_MerchantContractLimits);
+ const json_t *jlimits;
+ struct TALER_Amount max_fee;
+ // limits = GNUNET_new (struct TALER_MerchantContractLimits);
/* auto_refund only needs to be type-checked,
* mostly because in GNUnet relative times can't
* be negative. */
bool no_fee;
+ bool no_limits;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_string ("version",
@@ -1565,9 +1760,13 @@ parse_order (struct OrderContext *oc)
NULL),
GNUNET_JSON_spec_mark_optional (
TALER_JSON_spec_amount_any ("max_fee",
- &limits->max_fee),
+ &max_fee),
&no_fee),
GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_array_const ("limits",
+ &jlimits),
+ &no_limits),
+ GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_json ("delivery_location",
&oc->parse_order.delivery_location),
NULL),
@@ -1602,10 +1801,83 @@ parse_order (struct OrderContext *oc)
if (NULL == version || 0 == strcmp("v0", version))
{
oc->parse_order.version = TALER_MCV_V0;
+
+ if ( (! no_fee) &&
+ (GNUNET_OK !=
+ TALER_amount_cmp_currency (&oc->parse_order.brutto,
+ &max_fee)) )
+ {
+ GNUNET_break_op (0);
+ GNUNET_JSON_parse_free (spec);
+ reply_with_error (oc,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_CURRENCY_MISMATCH,
+ "different currencies used for 'max_fee' and 'amount' currency");
+ return;
+ }
+
+ /**
+ * v0 only supports one currency. For the sake of simplicity,
+ * we still use the limits array with just one item.
+ */
+ GNUNET_array_grow (oc->parse_order.limits,
+ oc->parse_order.limits_len,
+ 1);
+
+ oc->parse_order.limits->max_fee = max_fee;
+
+ /* Copy currency of max_fee into limits label */
+ GNUNET_snprintf (oc->parse_order.limits->currency,
+ sizeof (oc->parse_order.limits->currency),
+ "%s",
+ oc->parse_order.limits->max_fee.currency);
}
else if (0 != strcmp("v1", version))
{
oc->parse_order.version = TALER_MCV_V1;
+
+ GNUNET_array_grow (oc->parse_order.limits,
+ oc->parse_order.limits_len,
+ json_array_size (jlimits));
+
+ for (unsigned int i = 0; i<oc->parse_order.limits_len; i++)
+ {
+ struct TALER_MerchantContractLimits *limits = &oc->parse_order.limits[i];
+ const char *error_name;
+ unsigned int error_line;
+ struct GNUNET_JSON_Specification ispec[] = {
+ TALER_JSON_spec_amount_any ("max_fee",
+ &limits->max_fee),
+ // TODO: Add the rest of the fields
+ GNUNET_JSON_spec_end ()
+ };
+
+ ret = GNUNET_JSON_parse (json_array_get (jlimits,
+ i),
+ ispec,
+ &error_name,
+ &error_line);
+ if (GNUNET_OK != ret)
+ {
+ GNUNET_break_op (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Limits parsing failed at #%u: %s:%u\n",
+ i,
+ error_name,
+ error_line);
+ reply_with_error (oc,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ "order.limits");
+ return;
+ }
+
+ /* Copy currency of max_fee into limits label */
+ GNUNET_snprintf (limits->currency,
+ sizeof (limits->currency),
+ "%s",
+ limits->max_fee.currency);
+ }
}
else
{
@@ -1638,25 +1910,6 @@ parse_order (struct OrderContext *oc)
"no trusted exchange for this currency");
return;
}
- if ( (! no_fee) &&
- (GNUNET_OK !=
- TALER_amount_cmp_currency (&oc->parse_order.brutto,
- &limits->max_fee)) )
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- reply_with_error (oc,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_CURRENCY_MISMATCH,
- "different currencies used for 'max_fee' and 'amount' currency");
- return;
- }
-
- /* Copy currency of max_fee into limits label */
- GNUNET_snprintf (limits->currency,
- sizeof (limits->currency),
- "%s",
- limits->max_fee.currency);
/* Add order_id if it doesn't exist. */
if (NULL == oc->parse_order.order_id)