diff options
-rw-r--r-- | src/backend/taler-merchant-httpd_contract.c | 229 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_contract.h | 26 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_post-orders-ID-pay.c | 21 |
3 files changed, 269 insertions, 7 deletions
diff --git a/src/backend/taler-merchant-httpd_contract.c b/src/backend/taler-merchant-httpd_contract.c index 38c82e70..60f45776 100644 --- a/src/backend/taler-merchant-httpd_contract.c +++ b/src/backend/taler-merchant-httpd_contract.c @@ -23,7 +23,7 @@ #include "taler-merchant-httpd_contract.h" enum TALER_MerchantContractInputType -TMH_string_to_contract_input_type (const char *str) +TMH_contract_input_type_from_string (const char *str) { /* For now, only 'token' is the only supported option. */ if (0 == strcmp("token", str)) @@ -35,7 +35,7 @@ TMH_string_to_contract_input_type (const char *str) } enum TALER_MerchantContractOutputType -TMH_string_to_contract_output_type (const char *str) +TMH_contract_output_type_from_string (const char *str) { /* For now, only 'token' is the only supported option. */ if (0 == strcmp("token", str)) @@ -45,3 +45,228 @@ TMH_string_to_contract_output_type (const char *str) return TALER_MCOT_INVALID; } + +const char * +TMH_string_from_contract_input_type (enum TALER_MerchantContractInputType t) +{ + switch (t) { + case TALER_MCIT_TOKEN: + return "token"; + case TALER_MCIT_COIN: + return "coin"; + default: + return "invalid"; + } +} + +const char * +TMH_string_from_contract_output_type (enum TALER_MerchantContractOutputType t) +{ + switch (t) { + case TALER_MCOT_TOKEN: + return "token"; + case TALER_MCOT_COIN: + return "coin"; + case TALER_MCOT_TAX_RECEIPT: + return "tax_receipt"; + default: + return "invalid"; + } +} + +/** + * Parse given JSON object to choices array. + * + * @param cls closure, pointer to array length + * @param root the json array representing the choices + * @param[out] spec where to write the data + * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error + */ +static enum GNUNET_GenericReturnValue +parse_choice (void *cls, + json_t *root, + struct GNUNET_JSON_Specification *spec) +{ + struct TALER_MerchantContractChoice **choices = spec->ptr; + unsigned int *choices_len = cls; + if (!json_is_array (root)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + GNUNET_array_grow (*choices, + *choices_len, + json_array_size (root)); + + for (unsigned int i = 0; i<*choices_len; i++) + { + const json_t *jinputs; + const json_t *joutputs; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_array_const ("inputs", + &jinputs), + GNUNET_JSON_spec_array_const ("outputs", + &joutputs), + GNUNET_JSON_spec_end () + }; + const char *error_name; + unsigned int error_line; + struct TALER_MerchantContractChoice *choice = &(*choices)[i]; + + if (GNUNET_OK != + GNUNET_JSON_parse (json_array_get (root, i), + spec, + &error_name, + &error_line)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to parse %s at %u: %s\n", + spec[error_line].field, + error_line, + error_name); + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + { + const json_t *jinput; + size_t idx; + json_array_foreach ((json_t *) jinputs, idx, jinput) + { + struct TALER_MerchantContractInput input = {.details.token.count = 1}; + const char *kind; + struct GNUNET_JSON_Specification ispec[] = { + GNUNET_JSON_spec_string ("kind", + &kind), + 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 ("count", + &input.details.token.count), + NULL), + GNUNET_JSON_spec_end() + }; + const char *ierror_name; + unsigned int ierror_line; + + if (GNUNET_OK != + GNUNET_JSON_parse (jinput, + ispec, + &ierror_name, + &ierror_line)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to parse %s at %u: %s\n", + spec[ierror_line].field, + ierror_line, + ierror_name); + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + input.type = TMH_contract_input_type_from_string (kind); + + if (TALER_MCIT_INVALID == input.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Field 'kind' invalid in input #%u\n", + (unsigned int) idx); + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + if (0 == input.details.token.count) + { + /* Ignore inputs with 'number' field set to 0 */ + continue; + } + + GNUNET_array_append (choice->inputs, + choice->inputs_len, + input); + } + } + + { + const json_t *joutput; + size_t idx; + json_array_foreach ((json_t *) joutputs, idx, joutput) + { + struct TALER_MerchantContractOutput output = {.details.token.count = 1}; + const char *kind; + struct GNUNET_JSON_Specification ispec[] = { + GNUNET_JSON_spec_string ("kind", + &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 ("count", + &output.details.token.count), + NULL), + GNUNET_JSON_spec_end() + }; + const char *ierror_name; + unsigned int ierror_line; + + if (GNUNET_OK != + GNUNET_JSON_parse (joutput, + ispec, + &ierror_name, + &ierror_line)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to parse %s at %u: %s\n", + spec[ierror_line].field, + ierror_line, + ierror_name); + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + output.type = TMH_contract_output_type_from_string (kind); + + if (TALER_MCOT_INVALID == output.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Field 'kind' invalid in output #%u\n", + (unsigned int) idx); + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + if (0 == output.details.token.count) + { + /* Ignore outputs with 'number' field set to 0 */ + continue; + } + + GNUNET_array_append (choice->outputs, + choice->outputs_len, + output); + } + } + } + + return GNUNET_OK; +} + + +struct GNUNET_JSON_Specification +TALER_JSON_spec_choices (const char *name, + struct TALER_MerchantContractChoice **choices, + unsigned int *choices_len) +{ + struct GNUNET_JSON_Specification ret = { + .cls = (void *) choices_len, + .parser = &parse_choice, + .field = name, + .ptr = choices, + }; + + return ret; +}
\ No newline at end of file diff --git a/src/backend/taler-merchant-httpd_contract.h b/src/backend/taler-merchant-httpd_contract.h index b231d732..ee77b4c1 100644 --- a/src/backend/taler-merchant-httpd_contract.h +++ b/src/backend/taler-merchant-httpd_contract.h @@ -551,10 +551,16 @@ struct TALER_MerchantContract }; enum TALER_MerchantContractInputType -TMH_string_to_contract_input_type (const char *str); +TMH_contract_input_type_from_string (const char *str); enum TALER_MerchantContractOutputType -TMH_string_to_contract_output_type (const char *str); +TMH_contract_output_type_from_string (const char *str); + +const char * +TMH_string_from_contract_input_type (enum TALER_MerchantContractInputType t); + +const char * +TMH_string_from_contract_output_type (enum TALER_MerchantContractOutputType t); /** * Serialize @a contract to a JSON object, ready to be stored in the database. @@ -584,4 +590,18 @@ enum GNUNET_GenericReturnValue TMH_serialize_contract_v1 (const struct TALER_MerchantContract *contract, const struct TMH_MerchantInstance *instance, json_t *exchanges, - json_t **out);
\ No newline at end of file + json_t **out); + +/** + * Provide specification to parse given JSON array to an array + * of contract choices. + * + * @param name name of the choices field in the JSON + * @param[out] choices pointer to the first element of the array + * @param[out] choices_len pointer to the length of the array + * @return spec for parsing a choices array + */ +struct GNUNET_JSON_Specification +TALER_JSON_spec_choices (const char *name, + struct TALER_MerchantContractChoice **choices, + unsigned int *choices_len); diff --git a/src/backend/taler-merchant-httpd_post-orders-ID-pay.c b/src/backend/taler-merchant-httpd_post-orders-ID-pay.c index 2bdf891f..5532f1ab 100644 --- a/src/backend/taler-merchant-httpd_post-orders-ID-pay.c +++ b/src/backend/taler-merchant-httpd_post-orders-ID-pay.c @@ -26,12 +26,14 @@ */ #include "platform.h" #include <gnunet/gnunet_json_lib.h> +#include <jansson.h> #include <stdint.h> #include <taler/taler_dbevents.h> #include <taler/taler_signatures.h> #include <taler/taler_json_lib.h> #include <taler/taler_exchange_service.h> #include "taler-merchant-httpd_exchanges.h" +#include "taler-merchant-httpd_contract.h" #include "taler-merchant-httpd_helper.h" #include "taler-merchant-httpd_post-orders-ID-pay.h" #include "taler-merchant-httpd_private-get-orders.h" @@ -317,6 +319,11 @@ struct PayContext struct TokenUseConfirmation *tokens; /** + * Array with @e choices_cnt choices from the contract terms. + */ + struct TALER_MerchantContractChoice *choices; + + /** * MHD connection to return to */ struct MHD_Connection *connection; @@ -475,6 +482,11 @@ struct PayContext size_t tokens_cnt; /** + * Length of the @e choices array. + */ + unsigned int choices_len; + + /** * Number of exchanges involved in the payment. Length * of the @e eg array. */ @@ -2342,6 +2354,11 @@ phase_check_contract (struct PayContext *pc) &pc->pay_deadline), GNUNET_JSON_spec_timestamp ("wire_transfer_deadline", &pc->wire_transfer_deadline), + GNUNET_JSON_spec_mark_optional ( + TALER_JSON_spec_choices ("choices", + &pc->choices, + &pc->choices_len), + NULL), GNUNET_JSON_spec_fixed_auto ("h_wire", &pc->h_wire), GNUNET_JSON_spec_mark_optional ( @@ -2667,8 +2684,8 @@ phase_parse_pay (struct PayContext *pc) &tuc->sig), GNUNET_JSON_spec_fixed_auto ("token_pub", &tuc->pub), - // TALER_JSON_spec_denom_sig ("ub_sig", - // &tuc->unblinded_sig), + TALER_JSON_spec_token_issue_sig ("ub_sig", + &tuc->unblinded_sig), GNUNET_JSON_spec_fixed_auto ("h_issue", &tuc->h_issue), GNUNET_JSON_spec_end () |