From 922323b4104abfaef2a11fed4e5e8292344a3bcd Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 5 Jul 2015 16:55:01 +0200 Subject: misc bugfixes from tests --- src/include/taler_mint_service.h | 2 +- src/include/taler_util.h | 24 ++++++ src/mint-lib/mint_api_admin.c | 4 +- src/mint-lib/mint_api_deposit.c | 20 ++--- .../test-mint-home/config/mint-common.conf | 5 +- src/mint-lib/test_mint_api.c | 50 ++++++++++-- src/mint-tools/taler-mint-keyup.c | 28 ++----- src/mint/taler-mint-httpd_db.c | 8 +- src/mint/taler-mint-httpd_deposit.c | 17 ++-- src/mint/taler-mint-httpd_keystate.c | 1 + src/mint/taler-mint-httpd_parsing.c | 95 +++++++++++++++------- src/mint/taler-mint-httpd_parsing.h | 30 +++++-- src/mint/taler-mint-httpd_responses.c | 21 +++-- src/mint/taler-mint-httpd_responses.h | 5 +- src/util/json.c | 25 ++---- src/util/test_json.c | 4 +- src/util/util.c | 40 +++++++++ src/util/wireformats.c | 39 ++++++++- 18 files changed, 301 insertions(+), 117 deletions(-) (limited to 'src') diff --git a/src/include/taler_mint_service.h b/src/include/taler_mint_service.h index 132dfa31d..5ee2331f4 100644 --- a/src/include/taler_mint_service.h +++ b/src/include/taler_mint_service.h @@ -651,7 +651,7 @@ struct TALER_MINT_AdminAddIncomingHandle * TALER_MINT_admin_add_incoming (struct TALER_MINT_Handle *mint, const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_Amount *amount, - const struct GNUNET_TIME_Absolute execution_date, + struct GNUNET_TIME_Absolute execution_date, const json_t *wire, TALER_MINT_AdminAddIncomingResultCallback res_cb, void *res_cb_cls); diff --git a/src/include/taler_util.h b/src/include/taler_util.h index c9db9f789..00397cc88 100644 --- a/src/include/taler_util.h +++ b/src/include/taler_util.h @@ -73,6 +73,30 @@ void TALER_gcrypt_init (void); +/** + * Round a time value so that it is suitable for transmission + * via JSON encodings. + * + * @param at time to round + * @return #GNUNET_OK if time was already rounded, #GNUNET_NO if + * it was just now rounded + */ +int +TALER_round_abs_time (struct GNUNET_TIME_Absolute *at); + + +/** + * Round a time value so that it is suitable for transmission + * via JSON encodings. + * + * @param rt time to round + * @return #GNUNET_OK if time was already rounded, #GNUNET_NO if + * it was just now rounded + */ +int +TALER_round_rel_time (struct GNUNET_TIME_Relative *rt); + + /** * Load configuration by parsing all configuration * files in the given directory. diff --git a/src/mint-lib/mint_api_admin.c b/src/mint-lib/mint_api_admin.c index 0169f8e7d..47158665a 100644 --- a/src/mint-lib/mint_api_admin.c +++ b/src/mint-lib/mint_api_admin.c @@ -246,7 +246,7 @@ struct TALER_MINT_AdminAddIncomingHandle * TALER_MINT_admin_add_incoming (struct TALER_MINT_Handle *mint, const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_Amount *amount, - const struct GNUNET_TIME_Absolute execution_date, + struct GNUNET_TIME_Absolute execution_date, const json_t *wire, TALER_MINT_AdminAddIncomingResultCallback res_cb, void *res_cb_cls) @@ -256,6 +256,8 @@ TALER_MINT_admin_add_incoming (struct TALER_MINT_Handle *mint, json_t *admin_obj; CURL *eh; + GNUNET_assert (GNUNET_OK == + TALER_round_abs_time (&execution_date)); if (GNUNET_YES != MAH_handle_is_ready (mint)) { diff --git a/src/mint-lib/mint_api_deposit.c b/src/mint-lib/mint_api_deposit.c index 3c6939668..008634f20 100644 --- a/src/mint-lib/mint_api_deposit.c +++ b/src/mint-lib/mint_api_deposit.c @@ -37,7 +37,7 @@ */ #define JSON_WARN(error) \ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, \ - "JSON parsing failed at %s:%u: %s (%s)", \ + "JSON parsing failed at %s:%u: %s (%s)\n", \ __FILE__, __LINE__, error.text, error.source) @@ -464,8 +464,8 @@ verify_signatures (const struct TALER_MINT_DenomPublicKey *dki, TALER_LOG_WARNING ("Invalid coin passed for /deposit\n"); return GNUNET_SYSERR; } - if (TALER_amount_cmp (&dki->fee_deposit, - amount) < 0) + if (0 < TALER_amount_cmp (&dki->fee_deposit, + amount)) { TALER_LOG_WARNING ("Deposit amount smaller than fee\n"); return GNUNET_SYSERR; @@ -615,17 +615,17 @@ TALER_MINT_deposit (struct TALER_MINT_Handle *mint, } deposit_obj = json_pack ("{s:o, s:o," /* f/wire */ - " s:s, s:s," /* H_wire, H_contract */ - " s:s, s:s," /* coin_pub, denom_pub */ - " s:s, s:s," /* ub_sig, timestamp */ - " s:I, s:s," /* transaction id, merchant_pub */ - " s:s, s:s}", /* refund_deadline, coin_sig */ + " s:o, s:o," /* H_wire, H_contract */ + " s:o, s:o," /* coin_pub, denom_pub */ + " s:o, s:o," /* ub_sig, timestamp */ + " s:I, s:o," /* transaction id, merchant_pub */ + " s:o, s:o}", /* refund_deadline, coin_sig */ "f", TALER_json_from_amount (amount), "wire", wire_details, "H_wire", TALER_json_from_data (&h_wire, sizeof (h_wire)), - "H_contract", TALER_json_from_data (&h_contract, - sizeof (h_contract)), + "H_contract", TALER_json_from_data (h_contract, + sizeof (struct GNUNET_HashCode)), "coin_pub", TALER_json_from_data (coin_pub, sizeof (*coin_pub)), "denom_pub", TALER_json_from_rsa_public_key (denom_pub->rsa_public_key), diff --git a/src/mint-lib/test-mint-home/config/mint-common.conf b/src/mint-lib/test-mint-home/config/mint-common.conf index 6d03c2a5b..1b8aa4218 100644 --- a/src/mint-lib/test-mint-home/config/mint-common.conf +++ b/src/mint-lib/test-mint-home/config/mint-common.conf @@ -2,8 +2,9 @@ # Currency supported by the mint (can only be one) CURRENCY = EUR -# Wire format supproted by the mint (currently only SEPA is implemented) -WIREFORMAT = SEPA +# Wire format supproted by the mint +# TEST is used for testing... (what a shock) +WIREFORMAT = TEST # HTTP port the mint listens to PORT = 8081 diff --git a/src/mint-lib/test_mint_api.c b/src/mint-lib/test_mint_api.c index c59d4a03b..58f502bae 100644 --- a/src/mint-lib/test_mint_api.c +++ b/src/mint-lib/test_mint_api.c @@ -27,6 +27,7 @@ */ #include "platform.h" #include "taler_util.h" +#include "taler_signatures.h" #include "taler_mint_service.h" #include @@ -506,6 +507,7 @@ interpreter_run (void *cls, struct TALER_ReservePublicKeyP reserve_pub; struct TALER_CoinSpendPublicKeyP coin_pub; struct TALER_Amount amount; + struct GNUNET_TIME_Absolute execution_date; json_t *wire; is->task = NULL; @@ -566,14 +568,22 @@ interpreter_run (void *cls, fail (is); return; } + execution_date = GNUNET_TIME_absolute_get (); + TALER_round_abs_time (&execution_date); cmd->details.admin_add_incoming.aih = TALER_MINT_admin_add_incoming (mint, &reserve_pub, &amount, - GNUNET_TIME_absolute_get (), + execution_date, wire, &add_incoming_cb, is); + if (NULL == cmd->details.admin_add_incoming.aih) + { + GNUNET_break (0); + fail (is); + return; + } trigger_context_task (); return; case OC_WITHDRAW_SIGN: @@ -629,6 +639,12 @@ interpreter_run (void *cls, &cmd->details.withdraw_sign.blinding_key, &withdraw_sign_cb, is); + if (NULL == cmd->details.withdraw_sign.wsh) + { + GNUNET_break (0); + fail (is); + return; + } trigger_context_task (); return; case OC_DEPOSIT: @@ -690,9 +706,30 @@ interpreter_run (void *cls, refund_deadline = GNUNET_TIME_UNIT_ZERO_ABS; } timestamp = GNUNET_TIME_absolute_get (); + TALER_round_abs_time (×tamp); + { + struct TALER_DepositRequestPS dr; + + dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS)); + dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT); + dr.h_contract = h_contract; + TALER_hash_json (wire, + &dr.h_wire); + dr.timestamp = GNUNET_TIME_absolute_hton (timestamp); + dr.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline); + dr.transaction_id = GNUNET_htonll (cmd->details.deposit.transaction_id); + TALER_amount_hton (&dr.amount_with_fee, + &amount); + TALER_amount_hton (&dr.deposit_fee, + &ref->details.withdraw_sign.pk->fee_deposit); + dr.merchant = merchant_pub; + dr.coin_pub = coin_pub; + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_eddsa_sign (&ref->details.withdraw_sign.coin_priv.eddsa_priv, + &dr.purpose, + &coin_sig.eddsa_signature)); - /* FIXME: init "coin_sig" here! */ - + } cmd->details.deposit.dh = TALER_MINT_deposit (mint, &amount, @@ -715,6 +752,7 @@ interpreter_run (void *cls, fail (is); return; } + trigger_context_task (); return; } default: @@ -938,7 +976,7 @@ run (void *cls, /* Fill reserve with EUR:5.01, as withdraw fee is 1 ct per config */ { .oc = OC_ADMIN_ADD_INCOMING, .label = "create-reserve-1", - .details.admin_add_incoming.wire = "{ \"bank\":\"source bank\", \"account\":42 }", + .details.admin_add_incoming.wire = "{ \"type\":\"TEST\", \"bank\":\"source bank\", \"account\":42 }", .details.admin_add_incoming.amount = "EUR:5.01" }, { .oc = OC_WITHDRAW_SIGN, .label = "withdraw-coin-1", @@ -948,7 +986,7 @@ run (void *cls, .label = "deposit-simple", .details.deposit.amount = "EUR:5", .details.deposit.coin_ref = "withdraw-coin-1", - .details.deposit.wire_details = "{ \"bank\":\"dest bank\", \"account\":42 }", + .details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":42 }", .details.deposit.contract = "{ \"items\"={ \"name\":\"ice cream\", \"value\":1 } }", .details.deposit.transaction_id = 1 }, { .oc = OC_END } @@ -1007,7 +1045,7 @@ main (int argc, "-d", "test-mint-home", NULL); /* give child time to start and bind against the socket */ - sleep (1); + sleep (5); result = GNUNET_SYSERR; GNUNET_SCHEDULER_run (&run, NULL); GNUNET_OS_process_kill (mintd, diff --git a/src/mint-tools/taler-mint-keyup.c b/src/mint-tools/taler-mint-keyup.c index 468bd7766..7b9388573 100644 --- a/src/mint-tools/taler-mint-keyup.c +++ b/src/mint-tools/taler-mint-keyup.c @@ -34,14 +34,6 @@ */ #define HASH_CUTOFF 20 -/** - * Macro to round microseconds to seconds in GNUNET_TIME_* structs. - * - * @param name value to round - * @param us_field rel_value_us or abs_value_us - */ -#define ROUND_TO_SECS(name,us_field) name.us_field -= name.us_field % (1000 * 1000); - GNUNET_NETWORK_STRUCT_BEGIN @@ -515,8 +507,7 @@ mint_keys_update_signkeys () "must be longer than signkey_duration"); return GNUNET_SYSERR; } - ROUND_TO_SECS (signkey_duration, - rel_value_us); + TALER_round_rel_time (&signkey_duration); GNUNET_asprintf (&signkey_dir, "%s" DIR_SEPARATOR_STR TALER_MINTDB_DIR_SIGNING_KEYS, mint_directory); @@ -598,8 +589,7 @@ get_cointype_params (const char *ct, "duration_withdraw"); return GNUNET_SYSERR; } - ROUND_TO_SECS (params->duration_withdraw, - rel_value_us); + TALER_round_rel_time (¶ms->duration_withdraw); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (kcfg, ct, @@ -611,8 +601,7 @@ get_cointype_params (const char *ct, "duration_spend"); return GNUNET_SYSERR; } - ROUND_TO_SECS (params->duration_spend, - rel_value_us); + TALER_round_rel_time (¶ms->duration_spend); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (kcfg, ct, @@ -624,8 +613,7 @@ get_cointype_params (const char *ct, "duration_legal"); return GNUNET_SYSERR; } - ROUND_TO_SECS (params->duration_legal, - rel_value_us); + TALER_round_rel_time (¶ms->duration_legal); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (kcfg, ct, @@ -637,8 +625,7 @@ get_cointype_params (const char *ct, "mint_denom_duration_overlap"); return GNUNET_SYSERR; } - ROUND_TO_SECS (params->duration_overlap, - rel_value_us); + TALER_round_rel_time (¶ms->duration_overlap); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (kcfg, ct, @@ -914,7 +901,7 @@ main (int argc, { now = GNUNET_TIME_absolute_get (); } - ROUND_TO_SECS (now, abs_value_us); + TALER_round_abs_time (&now); kcfg = TALER_config_load (mint_directory); if (NULL == kcfg) @@ -990,8 +977,7 @@ main (int argc, _("must not be zero")); return GNUNET_SYSERR; } - ROUND_TO_SECS (lookahead_sign, - rel_value_us); + TALER_round_rel_time (&lookahead_sign); lookahead_sign_stamp = GNUNET_TIME_absolute_add (now, lookahead_sign); diff --git a/src/mint/taler-mint-httpd_db.c b/src/mint/taler-mint-httpd_db.c index 5afc104f5..2ac3defde 100644 --- a/src/mint/taler-mint-httpd_db.c +++ b/src/mint/taler-mint-httpd_db.c @@ -126,6 +126,7 @@ TMH_DB_execute_deposit (struct MHD_Connection *connection, &deposit->h_wire, &deposit->h_contract, deposit->transaction_id, + deposit->timestamp, deposit->refund_deadline, &deposit->merchant_pub, &amount_without_fee); @@ -194,14 +195,19 @@ TMH_DB_execute_deposit (struct MHD_Connection *connection, TALER_LOG_WARNING ("/deposit transaction commit failed\n"); return TMH_RESPONSE_reply_commit_error (connection); } + GNUNET_assert (GNUNET_OK == + TALER_amount_subtract (&amount_without_fee, + &deposit->amount_with_fee, + &deposit->deposit_fee)); return TMH_RESPONSE_reply_deposit_success (connection, &deposit->coin.coin_pub, &deposit->h_wire, &deposit->h_contract, deposit->transaction_id, + deposit->timestamp, deposit->refund_deadline, &deposit->merchant_pub, - &deposit->amount_with_fee); + &amount_without_fee); } diff --git a/src/mint/taler-mint-httpd_deposit.c b/src/mint/taler-mint-httpd_deposit.c index 19ea9cb50..782d05a8b 100644 --- a/src/mint/taler-mint-httpd_deposit.c +++ b/src/mint/taler-mint-httpd_deposit.c @@ -101,14 +101,12 @@ verify_and_execute_deposit (struct MHD_Connection *connection, } TALER_amount_ntoh (&fee_deposit, &dki->issue.fee_deposit); - if (TALER_amount_cmp (&fee_deposit, - &deposit->amount_with_fee) < 0) + if (0 < TALER_amount_cmp (&fee_deposit, + &deposit->amount_with_fee)) { TMH_KS_release (key_state); - return (MHD_YES == - TMH_RESPONSE_reply_external_error (connection, - "deposited amount smaller than depositing fee")) - ? GNUNET_NO : GNUNET_SYSERR; + return TMH_RESPONSE_reply_external_error (connection, + "deposited amount smaller than depositing fee"); } TMH_KS_release (key_state); @@ -146,7 +144,7 @@ parse_and_handle_deposit_request (struct MHD_Connection *connection, TMH_PARSE_MEMBER_FIXED ("H_contract", &deposit.h_contract), TMH_PARSE_MEMBER_FIXED ("H_wire", &deposit.h_wire), TMH_PARSE_MEMBER_FIXED ("coin_sig", &deposit.csig), - TMH_PARSE_MEMBER_FIXED ("transaction_id", &deposit.transaction_id), + TMH_PARSE_member_uint64 ("transaction_id", &deposit.transaction_id), TMH_PARSE_member_time_abs ("timestamp", &deposit.timestamp), TMH_PARSE_member_time_abs ("refund_deadline", &deposit.refund_deadline), TMH_PARSE_MEMBER_END @@ -160,6 +158,7 @@ parse_and_handle_deposit_request (struct MHD_Connection *connection, return MHD_NO; /* hard failure */ if (GNUNET_NO == res) return MHD_YES; /* failure */ + if (GNUNET_YES != TALER_json_validate_wireformat (TMH_expected_wire_format, wire)) @@ -197,7 +196,7 @@ parse_and_handle_deposit_request (struct MHD_Connection *connection, &deposit.deposit_fee)) { /* Total amount smaller than fee, invalid */ - TMH_PARSE_release_data (spec); + TMH_PARSE_release_data (spec); return TMH_RESPONSE_reply_arg_invalid (connection, "f"); } @@ -247,7 +246,7 @@ TMH_DEPOSIT_handler_deposit (struct TMH_RequestHandler *rh, if ( (GNUNET_NO == res) || (NULL == json) ) return MHD_YES; if (-1 == json_unpack (json, - "{s:s, s:o, f:o}", + "{s:o, s:o}", "wire", &wire, "f", &f)) { diff --git a/src/mint/taler-mint-httpd_keystate.c b/src/mint/taler-mint-httpd_keystate.c index 2e81c8064..096023ac5 100644 --- a/src/mint/taler-mint-httpd_keystate.c +++ b/src/mint/taler-mint-httpd_keystate.c @@ -494,6 +494,7 @@ TMH_KS_acquire (void) key_state->denomkey_map = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_NO); key_state->reload_time = GNUNET_TIME_absolute_get (); + TALER_round_abs_time (&key_state->reload_time); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Loading keys from `%s'\n", TMH_mint_directory); diff --git a/src/mint/taler-mint-httpd_parsing.c b/src/mint/taler-mint-httpd_parsing.c index 1a4215ba0..c5827da7e 100644 --- a/src/mint/taler-mint-httpd_parsing.c +++ b/src/mint/taler-mint-httpd_parsing.c @@ -549,6 +549,28 @@ TMH_PARSE_navigate_json (struct MHD_Connection *connection, } break; + case TMH_PARSE_JNC_RET_UINT64: + { + uint64_t *r_u64 = va_arg (argp, uint64_t *); + + if (json_typeof (root) != JSON_INTEGER) + { + ret = (MHD_YES == + TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:s, s:i, s:o}", + "error", "wrong JSON field type", + "type_expected", "integer", + "type_actual", json_typeof (root), + "path", path)) + ? GNUNET_NO : GNUNET_SYSERR; + break; + } + *r_u64 = (uint64_t) json_integer_value (root); + ret = GNUNET_OK; + } + break; + case TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY: { struct TALER_DenominationPublicKey *where; @@ -803,6 +825,16 @@ TMH_PARSE_json_data (struct MHD_Connection *connection, TMH_PARSE_JNC_RET_TIME_ABSOLUTE, spec[i].destination); break; + case TMH_PARSE_JNC_RET_UINT64: + GNUNET_assert (sizeof (uint64_t) == + spec[i].destination_size_in); + ret = TMH_PARSE_navigate_json (connection, + root, + TMH_PARSE_JNC_FIELD, + spec[i].field_name, + TMH_PARSE_JNC_RET_UINT64, + spec[i].destination); + break; } } if (GNUNET_YES != ret) @@ -882,6 +914,8 @@ TMH_PARSE_release_data (struct TMH_PARSE_FieldSpecification *spec) break; case TMH_PARSE_JNC_RET_TIME_ABSOLUTE: break; + case TMH_PARSE_JNC_RET_UINT64: + break; } } } @@ -889,8 +923,9 @@ TMH_PARSE_release_data (struct TMH_PARSE_FieldSpecification *spec) /** * Parse absolute time specified in JSON format. The JSON format is - * "/TIMEVAL/" where TIMEVAL is in milliseconds. Additionally, we - * support "/forever/" to represent the end of time. + * "/Date(TIMEVAL)/" where TIMEVAL is in seconds after the Unix Epoch. + * Additionally, we support "/forever/" and "/never/" to represent the + * end of time. * * @param connection the MHD connection (to report errors) * @param f json specification of the amount @@ -906,9 +941,7 @@ TMH_PARSE_time_abs_json (struct MHD_Connection *connection, struct GNUNET_TIME_Absolute *time) { const char *val; - size_t slen; - unsigned long long int tval; - char *endp; + unsigned long long tval; val = json_string_value (f); if (NULL == val) @@ -921,30 +954,18 @@ TMH_PARSE_time_abs_json (struct MHD_Connection *connection, return GNUNET_SYSERR; return GNUNET_NO; } - slen = strlen (val); - if ( (slen <= 2) || - ('/' != val[0]) || - ('/' != val[slen - 1]) ) - { - if (MHD_YES != - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:s}", - "error", "timestamp expected", - "value", val)) - return GNUNET_SYSERR; - return GNUNET_NO; - } - if (0 == strcasecmp (val, - "/forever/")) + if ( (0 == strcasecmp (val, + "/forever/")) || + (0 == strcasecmp (val, + "/never/")) ) + { *time = GNUNET_TIME_UNIT_FOREVER_ABS; return GNUNET_OK; } - tval = strtoull (&val[1], - &endp, - 10); - if (&val[slen - 1] != endp) + if (1 != sscanf (val, + "/Date(%llu)/", + &tval)) { if (MHD_YES != TMH_RESPONSE_reply_json_pack (connection, @@ -955,9 +976,9 @@ TMH_PARSE_time_abs_json (struct MHD_Connection *connection, return GNUNET_SYSERR; return GNUNET_NO; } - /* Time is in 'ms' in JSON, but in microseconds in GNUNET_TIME_Absolute */ - time->abs_value_us = tval * 1000LL; - if ( (time->abs_value_us) / 1000LL != tval) + /* Time is in seconds in JSON, but in microseconds in GNUNET_TIME_Absolute */ + time->abs_value_us = tval * 1000LL * 1000LL; + if ( (time->abs_value_us) / 1000LL / 1000LL != tval) { /* Integer overflow */ if (MHD_YES != @@ -1047,6 +1068,24 @@ TMH_PARSE_amount_json (struct MHD_Connection *connection, } +/** + * Generate line in parser specification for 64-bit integer + * given as an integer in JSON. + * + * @param field name of the field + * @param[out] u64 integer to initialize + * @return corresponding field spec + */ +struct TMH_PARSE_FieldSpecification +TMH_PARSE_member_uint64 (const char *field, + uint64_t *u64) +{ + struct TMH_PARSE_FieldSpecification ret = + { field, (void *) u64, sizeof (uint64_t), 0, TMH_PARSE_JNC_RET_UINT64, 0 }; + return ret; +} + + /** * Generate line in parser specification for JSON object value. * diff --git a/src/mint/taler-mint-httpd_parsing.h b/src/mint/taler-mint-httpd_parsing.h index 44e74d27c..7d37bb18c 100644 --- a/src/mint/taler-mint-httpd_parsing.h +++ b/src/mint/taler-mint-httpd_parsing.h @@ -133,7 +133,14 @@ enum TMH_PARSE_JsonNavigationCommand * encoded within its own json object. * Param: struct GNUNET_TIME_Absolute * */ - TMH_PARSE_JNC_RET_TIME_ABSOLUTE + TMH_PARSE_JNC_RET_TIME_ABSOLUTE, + + /** + * Return a `uint64_t` which was + * encoded as a JSON integer. + * Param: uint64_t * + */ + TMH_PARSE_JNC_RET_UINT64 }; @@ -253,11 +260,24 @@ TMH_PARSE_release_data (struct TMH_PARSE_FieldSpecification *spec); #define TMH_PARSE_MEMBER_VARIABLE(field) { field, NULL, 0, 0, TMH_PARSE_JNC_RET_DATA_VAR, 0 } +/** + * Generate line in parser specification for 64-bit integer + * given as an integer in JSON. + * + * @param field name of the field + * @param[out] u64 integer to initialize + * @return corresponding field spec + */ +struct TMH_PARSE_FieldSpecification +TMH_PARSE_member_uint64 (const char *field, + uint64_t *u64); + + /** * Generate line in parser specification for JSON array value. * * @param field name of the field - * @param ptraddr address of JSON pointer to initialize + * @param[out] jsonp address of JSON pointer to initialize * @return corresponding field spec */ struct TMH_PARSE_FieldSpecification @@ -269,7 +289,7 @@ TMH_PARSE_member_array (const char *field, * Generate line in parser specification for JSON object value. * * @param field name of the field - * @param jsonp address of pointer to JSON to initialize + * @param[out] jsonp address of pointer to JSON to initialize * @return corresponding field spec */ struct TMH_PARSE_FieldSpecification @@ -351,8 +371,8 @@ TMH_PARSE_amount_json (struct MHD_Connection *connection, /** * Parse absolute time specified in JSON format. The JSON format is - * "/TIMEVAL/" where TIMEVAL is in milliseconds. Additionally, we - * support "/forever/" to represent the end of time. + * "/TIMEVAL/" where TIMEVAL is in seconds. Additionally, we + * support "/forever/" and "/never/" to represent the end of time. * * @param connection the MHD connection (to report errors) * @param f json specification of the amount diff --git a/src/mint/taler-mint-httpd_responses.c b/src/mint/taler-mint-httpd_responses.c index f36369984..bb7a72f8e 100644 --- a/src/mint/taler-mint-httpd_responses.c +++ b/src/mint/taler-mint-httpd_responses.c @@ -330,6 +330,7 @@ TMH_RESPONSE_reply_invalid_json (struct MHD_Connection *connection) * @param h_wire hash of wire details * @param h_contract hash of contract details * @param transaction_id transaction ID + * @param timestamp client's timestamp * @param refund_deadline until when this deposit be refunded * @param merchant merchant public key * @param amount_without_fee fraction of coin value to deposit, without the fee @@ -341,6 +342,7 @@ TMH_RESPONSE_reply_deposit_success (struct MHD_Connection *connection, const struct GNUNET_HashCode *h_wire, const struct GNUNET_HashCode *h_contract, uint64_t transaction_id, + struct GNUNET_TIME_Absolute timestamp, struct GNUNET_TIME_Absolute refund_deadline, const struct TALER_MerchantPublicKeyP *merchant, const struct TALER_Amount *amount_without_fee) @@ -348,14 +350,13 @@ TMH_RESPONSE_reply_deposit_success (struct MHD_Connection *connection, struct TALER_DepositConfirmationPS dc; struct TALER_MintSignatureP sig; json_t *sig_json; - int ret; dc.purpose.purpose = htonl (TALER_SIGNATURE_MINT_CONFIRM_DEPOSIT); dc.purpose.size = htonl (sizeof (struct TALER_DepositConfirmationPS)); dc.h_contract = *h_contract; dc.h_wire = *h_wire; dc.transaction_id = GNUNET_htonll (transaction_id); - dc.timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); + dc.timestamp = GNUNET_TIME_absolute_hton (timestamp); dc.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline); TALER_amount_hton (&dc.amount_without_fee, amount_without_fee); @@ -363,15 +364,13 @@ TMH_RESPONSE_reply_deposit_success (struct MHD_Connection *connection, dc.merchant = *merchant; TMH_KS_sign (&dc.purpose, &sig); - sig_json = TALER_json_from_eddsa_sig (&dc.purpose, - &sig.eddsa_signature); - ret = TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:s, s:o}", - "status", "DEPOSIT_OK", - "signature", sig_json); - json_decref (sig_json); - return ret; + sig_json = TALER_json_from_data (&sig, + sizeof (sig)); + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:s, s:o}", + "status", "DEPOSIT_OK", + "sig", sig_json); } diff --git a/src/mint/taler-mint-httpd_responses.h b/src/mint/taler-mint-httpd_responses.h index 1f8e1e44c..7afd01884 100644 --- a/src/mint/taler-mint-httpd_responses.h +++ b/src/mint/taler-mint-httpd_responses.h @@ -205,6 +205,7 @@ TMH_RESPONSE_reply_invalid_json (struct MHD_Connection *connection); * @param h_wire hash of wire details * @param h_contract hash of contract details * @param transaction_id transaction ID + * @param timestamp client's timestamp * @param refund_deadline until when this deposit be refunded * @param merchant merchant public key * @param amount_without_fee fraction of coin value to deposit (without fee) @@ -216,7 +217,9 @@ TMH_RESPONSE_reply_deposit_success (struct MHD_Connection *connection, const struct GNUNET_HashCode *h_wire, const struct GNUNET_HashCode *h_contract, uint64_t transaction_id, - struct GNUNET_TIME_Absolute refund_deadline, const struct TALER_MerchantPublicKeyP *merchant, + struct GNUNET_TIME_Absolute timestamp, + struct GNUNET_TIME_Absolute refund_deadline, + const struct TALER_MerchantPublicKeyP *merchant, const struct TALER_Amount *amount_without_fee); diff --git a/src/util/json.c b/src/util/json.c index 1c7cb7520..42f146463 100644 --- a/src/util/json.c +++ b/src/util/json.c @@ -89,11 +89,13 @@ TALER_json_from_abs (struct GNUNET_TIME_Absolute stamp) char *mystr; int ret; + GNUNET_assert (GNUNET_OK == + TALER_round_abs_time (&stamp)); if (stamp.abs_value_us == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us) return json_string ("/never/"); ret = GNUNET_asprintf (&mystr, - "/%llu/", - (long long) (stamp.abs_value_us / (1000LL * 1000LL))); + "/Date(%llu)/", + (unsigned long long) (stamp.abs_value_us / (1000LL * 1000LL))); GNUNET_assert (ret > 0); j = json_string (mystr); GNUNET_free (mystr); @@ -320,7 +322,7 @@ TALER_json_to_amount (json_t *json, /** - * Parse given JSON object to Amount + * Parse given JSON object to absolute time. * * @param json the json object representing Amount * @param[out] abs where the amount has to be written @@ -331,9 +333,7 @@ TALER_json_to_abs (json_t *json, struct GNUNET_TIME_Absolute *abs) { const char *val; - size_t slen; unsigned long long int tval; - char *endp; val = json_string_value (json); if (NULL == val) @@ -341,14 +341,6 @@ TALER_json_to_abs (json_t *json, GNUNET_break_op (0); return GNUNET_SYSERR; } - slen = strlen (val); - if ( (slen <= 2) || - ('/' != val[0]) || - ('/' != val[slen - 1]) ) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } if ( (0 == strcasecmp (val, "/forever/")) || (0 == strcasecmp (val, @@ -357,10 +349,9 @@ TALER_json_to_abs (json_t *json, *abs = GNUNET_TIME_UNIT_FOREVER_ABS; return GNUNET_OK; } - tval = strtoull (&val[1], - &endp, - 10); - if (&val[slen - 1] != endp) + if (1 != sscanf (val, + "/Date(%llu)/", + &tval)) { GNUNET_break_op (0); return GNUNET_SYSERR; diff --git a/src/util/test_json.c b/src/util/test_json.c index 6d887f489..c48fe68bd 100644 --- a/src/util/test_json.c +++ b/src/util/test_json.c @@ -65,7 +65,7 @@ test_time () struct GNUNET_TIME_Absolute a2; a1 = GNUNET_TIME_absolute_get (); - a1.abs_value_us -= a1.abs_value_us % 1000000; /* round! */ + TALER_round_abs_time (&a1); j = TALER_json_from_abs (a1); GNUNET_assert (NULL != j); GNUNET_assert (GNUNET_OK == @@ -110,7 +110,7 @@ test_raw () TALER_json_to_data (j, blob2, i)); - GNUNET_assert (0 == + GNUNET_assert (0 == memcmp (blob, blob2, i)); diff --git a/src/util/util.c b/src/util/util.c index 6da2f3f78..1d8b09c4d 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -63,6 +63,46 @@ TALER_config_get_denom (struct GNUNET_CONFIGURATION_Handle *cfg, } +/** + * Round a time value so that it is suitable for transmission + * via JSON encodings. + * + * @param at time to round + * @return #GNUNET_OK if time was already rounded, #GNUNET_NO if + * it was just now rounded + */ +int +TALER_round_abs_time (struct GNUNET_TIME_Absolute *at) +{ + if (at->abs_value_us == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us) + return GNUNET_OK; + if (0 == at->abs_value_us % 1000000) + return GNUNET_OK; + at->abs_value_us -= at->abs_value_us % 1000000; + return GNUNET_NO; +} + + +/** + * Round a time value so that it is suitable for transmission + * via JSON encodings. + * + * @param rt time to round + * @return #GNUNET_OK if time was already rounded, #GNUNET_NO if + * it was just now rounded + */ +int +TALER_round_rel_time (struct GNUNET_TIME_Relative *rt) +{ + if (rt->rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us) + return GNUNET_OK; + if (0 == rt->rel_value_us % 1000000) + return GNUNET_OK; + rt->rel_value_us -= rt->rel_value_us % 1000000; + return GNUNET_NO; +} + + /** * Load configuration by parsing all configuration * files in the given directory. diff --git a/src/util/wireformats.c b/src/util/wireformats.c index 7ea4fd067..88af4a438 100644 --- a/src/util/wireformats.c +++ b/src/util/wireformats.c @@ -330,7 +330,7 @@ validate_sepa (const json_t *wire) ((json_t *) wire, &error, JSON_STRICT, "{" - "s:s " /* type: "SEPA" */ + "s:s " /* TYPE: sepa */ "s:s " /* IBAN: iban */ "s:s " /* name: beneficiary name */ "s:s " /* BIC: beneficiary bank's BIC */ @@ -345,7 +345,6 @@ validate_sepa (const json_t *wire) "edate", &edate, "r", &r, "address", &address)); - EXITIF (0 != strcmp (type, "SEPA")); if (1 != validate_iban (iban)) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, @@ -359,6 +358,20 @@ validate_sepa (const json_t *wire) } +/** + * Validate TEST account details. The "test" format is used + * for testing, so this validator does nothing. + * + * @param wire JSON with the TEST details + * @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not + */ +static int +validate_test (const json_t *wire) +{ + return GNUNET_YES; +} + + /** * Handler for a wire format. */ @@ -392,9 +405,29 @@ TALER_json_validate_wireformat (const char *type, { static const struct FormatHandler format_handlers[] = { { "SEPA", &validate_sepa }, + { "TEST", &validate_test }, { NULL, NULL} }; unsigned int i; + char *stype; + json_error_t error; + + UNPACK_EXITIF (0 != json_unpack_ex + ((json_t *) wire, + &error, 0, + "{" + "s:s " /* TYPE: type */ + "}", + "type", &stype)); + if (0 != strcasecmp (type, + stype)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Wireformat `%s' does not match mint's expected `%s' format\n", + stype, + type); + return GNUNET_NO; + } for (i=0;NULL != format_handlers[i].type;i++) if (0 == strcasecmp (format_handlers[i].type, @@ -404,6 +437,8 @@ TALER_json_validate_wireformat (const char *type, "Wireformat `%s' not supported\n", type); return GNUNET_NO; + EXITIF_exit: + return GNUNET_NO; } /* end of wireformats.c */ -- cgit v1.2.3