diff options
author | Christian Grothoff <christian@grothoff.org> | 2017-12-06 19:24:00 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2017-12-06 19:24:00 +0100 |
commit | 042616899f89d38167632e3ff24b16469a27fbef (patch) | |
tree | cd0bfb86882f3cc8cd493e7fb3cb0e5ea00e356c /src/bank-lib/fakebank.c | |
parent | 5540747ca2e5f37f2df504d689b850d1078fcdc5 (diff) |
largely fix #5077
Diffstat (limited to 'src/bank-lib/fakebank.c')
-rw-r--r-- | src/bank-lib/fakebank.c | 256 |
1 files changed, 242 insertions, 14 deletions
diff --git a/src/bank-lib/fakebank.c b/src/bank-lib/fakebank.c index 268924151..67175721a 100644 --- a/src/bank-lib/fakebank.c +++ b/src/bank-lib/fakebank.c @@ -81,6 +81,11 @@ struct Transaction * Number of this transaction. */ uint64_t serial_id; + + /** + * Flag set if the transfer was rejected. + */ + int rejected; }; @@ -220,6 +225,31 @@ TALER_FAKEBANK_make_transfer (struct TALER_FAKEBANK_Handle *h, /** + * Reject incoming wire transfer to account @a credit_account + * as identified by @a rowid. + * + * @param h fake bank handle + * @param rowid identifies transfer to reject + * @param credit_account account number of owner of credited account + * @return #GNUNET_YES on success, #GNUNET_NO if the wire transfer was not found + */ +int +TALER_FAKEBANK_reject_transfer (struct TALER_FAKEBANK_Handle *h, + uint64_t rowid, + uint64_t credit_account) +{ + for (struct Transaction *t = h->transactions_head; NULL != t; t = t->next) + if ( (t->serial_id == rowid) && + (t->credit_account == credit_account) ) + { + t->rejected = GNUNET_YES; + return GNUNET_YES; + } + return GNUNET_NO; +} + + +/** * Check that no wire transfers were ordered (or at least none * that have not been taken care of via #TALER_FAKEBANK_check()). * If any transactions are onrecord, return #GNUNET_SYSERR. @@ -288,6 +318,62 @@ TALER_FAKEBANK_stop (struct TALER_FAKEBANK_Handle *h) /** + * Create and queue a bank error message with the HTTP response + * code @a response_code on connection @a connection. + * + * @param connection where to queue the reply + * @param response_code http status code to use + * @param ec taler error code to use + * @param message human readable error message + * @return MHD status code + */ +static int +create_bank_error (struct MHD_Connection *connection, + unsigned int response_code, + enum TALER_ErrorCode ec, + const char *message) +{ + json_t *json; + struct MHD_Response *resp; + void *json_str; + size_t json_len; + int ret; + + json = json_pack ("{s:s, s:I}", + "error", + message, + "ec", + (json_int_t) ec); + json_str = json_dumps (json, + JSON_INDENT(2)); + json_decref (json); + if (NULL == json_str) + { + GNUNET_break (0); + return MHD_NO; + } + json_len = strlen (json_str); + resp = MHD_create_response_from_buffer (json_len, + json_str, + MHD_RESPMEM_MUST_FREE); + if (NULL == resp) + { + GNUNET_break (0); + free (json_str); + return MHD_NO; + } + (void) MHD_add_response_header (resp, + MHD_HTTP_HEADER_CONTENT_TYPE, + "application/json"); + ret = MHD_queue_response (connection, + response_code, + resp); + MHD_destroy_response (resp); + return ret; +} + + +/** * Function called whenever MHD is done with a request. If the * request was a POST, we may have stored a `struct Buffer *` in the * @a con_cls that might still need to be cleaned up. Call the @@ -359,13 +445,13 @@ handle_admin_add_incoming (struct TALER_FAKEBANK_Handle *h, break; } { - const char *wtid; + const char *subject; uint64_t debit_account; uint64_t credit_account; const char *base_url; struct TALER_Amount amount; struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_string ("wtid", &wtid), + GNUNET_JSON_spec_string ("subject", &subject), GNUNET_JSON_spec_uint64 ("debit_account", &debit_account), GNUNET_JSON_spec_uint64 ("credit_account", &credit_account), TALER_JSON_spec_amount ("amount", &amount), @@ -385,7 +471,7 @@ handle_admin_add_incoming (struct TALER_FAKEBANK_Handle *h, debit_account, credit_account, &amount, - wtid, + subject, base_url); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Receiving incoming wire transfer: %llu->%llu from %s\n", @@ -434,6 +520,94 @@ handle_admin_add_incoming (struct TALER_FAKEBANK_Handle *h, /** + * Handle incoming HTTP request for /reject. + * + * @param h the fakebank handle + * @param connection the connection + * @param upload_data request data + * @param upload_data_size size of @a upload_data in bytes + * @param con_cls closure for request (a `struct Buffer *`) + * @return MHD result code + */ +static int +handle_reject (struct TALER_FAKEBANK_Handle *h, + struct MHD_Connection *connection, + const char *upload_data, + size_t *upload_data_size, + void **con_cls) +{ + enum GNUNET_JSON_PostResult pr; + json_t *json; + struct MHD_Response *resp; + int ret; + int found; + + pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX, + con_cls, + upload_data, + upload_data_size, + &json); + switch (pr) + { + case GNUNET_JSON_PR_OUT_OF_MEMORY: + GNUNET_break (0); + return MHD_NO; + case GNUNET_JSON_PR_CONTINUE: + return MHD_YES; + case GNUNET_JSON_PR_REQUEST_TOO_LARGE: + GNUNET_break (0); + return MHD_NO; + case GNUNET_JSON_PR_JSON_INVALID: + GNUNET_break (0); + return MHD_NO; + case GNUNET_JSON_PR_SUCCESS: + break; + } + { + uint64_t serial_id; + uint64_t credit_account; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_uint64 ("row_id", &serial_id), + GNUNET_JSON_spec_uint64 ("credit_account", &credit_account), + GNUNET_JSON_spec_end () + }; + if (GNUNET_OK != + GNUNET_JSON_parse (json, + spec, + NULL, NULL)) + { + GNUNET_break (0); + json_decref (json); + return MHD_NO; + } + found = TALER_FAKEBANK_reject_transfer (h, + serial_id, + credit_account); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Rejected wire transfer #%llu (to %llu)\n", + (unsigned long long) serial_id, + (unsigned long long) credit_account); + } + json_decref (json); + + if (GNUNET_OK != found) + return create_bank_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_BANK_REJECT_NOT_FOUND, + "transaction unknown"); + /* finally build regular response */ + resp = MHD_create_response_from_buffer (0, + NULL, + MHD_RESPMEM_PERSISTENT); + ret = MHD_queue_response (connection, + MHD_HTTP_NO_CONTENT, + resp); + MHD_destroy_response (resp); + return ret; +} + + +/** * Handle incoming HTTP request for /history * * @param h the fakebank handle @@ -451,6 +625,7 @@ handle_history (struct TALER_FAKEBANK_Handle *h, const char *start; const char *dir; const char *acc; + const char *cancelled; unsigned long long account_number; unsigned long long start_number; long long count; @@ -469,6 +644,9 @@ handle_history (struct TALER_FAKEBANK_Handle *h, dir = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "direction"); + cancelled = MHD_lookup_connection_value (connection, + MHD_GET_ARGUMENT_KIND, + "cancelled"); start = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "start"); @@ -496,7 +674,14 @@ handle_history (struct TALER_FAKEBANK_Handle *h, (1 != sscanf (start, "%llu", &start_number)) ) || - ( (NULL != dir) && + (NULL == dir) || + (NULL == cancelled) || + ( (0 != strcasecmp (cancelled, + "OMIT")) && + (0 != strcasecmp (cancelled, + "SHOW")) ) || + ( (0 != strcasecmp (dir, + "BOTH")) && (0 != strcasecmp (dir, "CREDIT")) && (0 != strcasecmp (dir, @@ -513,13 +698,40 @@ handle_history (struct TALER_FAKEBANK_Handle *h, dir, (unsigned long long) account_number, start); - if (NULL == dir) - direction = TALER_BANK_DIRECTION_BOTH; - else if (0 == strcasecmp (dir, - "CREDIT")) + if (0 == strcasecmp (dir, + "CREDIT")) + { direction = TALER_BANK_DIRECTION_CREDIT; - else + } + else if (0 == strcasecmp (dir, + "DEBIT")) + { direction = TALER_BANK_DIRECTION_DEBIT; + } + else if (0 == strcasecmp (dir, + "BOTH")) + { + direction = TALER_BANK_DIRECTION_BOTH; + } + else + { + GNUNET_assert (0); + return MHD_NO; + } + if (0 == strcasecmp (cancelled, + "OMIT")) + { + /* nothing */ + } else if (0 == strcasecmp (cancelled, + "SHOW")) + { + direction |= TALER_BANK_DIRECTION_CANCEL; + } + else + { + GNUNET_assert (0); + return MHD_NO; + } if (NULL == start) { if (count > 0) @@ -557,6 +769,7 @@ handle_history (struct TALER_FAKEBANK_Handle *h, { json_t *trans; char *subject; + const char *sign; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Found transaction over %s from %llu to %llu\n", @@ -564,10 +777,12 @@ handle_history (struct TALER_FAKEBANK_Handle *h, (unsigned long long) pos->debit_account, (unsigned long long) pos->credit_account); - if (! ( ( (account_number == pos->debit_account) && - (0 != (direction & TALER_BANK_DIRECTION_DEBIT)) ) || - ( (account_number == pos->credit_account) && - (0 != (direction & TALER_BANK_DIRECTION_CREDIT) ) ) ) ) + if ( (! ( ( (account_number == pos->debit_account) && + (0 != (direction & TALER_BANK_DIRECTION_DEBIT)) ) || + ( (account_number == pos->credit_account) && + (0 != (direction & TALER_BANK_DIRECTION_CREDIT) ) ) ) ) || + ( (0 == (direction & TALER_BANK_DIRECTION_CANCEL)) && + (GNUNET_YES == pos->rejected) ) ) { if (count > 0) pos = pos->next; @@ -580,11 +795,15 @@ handle_history (struct TALER_FAKEBANK_Handle *h, "%s %s", pos->subject, pos->exchange_base_url); + sign = + (account_number == pos->debit_account) + ? (pos->rejected ? "cancel-" : "-") + : (pos->rejected ? "cancel+" : "+"); trans = json_pack ("{s:I, s:o, s:o, s:s, s:I, s:s}", "row_id", (json_int_t) pos->serial_id, "date", GNUNET_JSON_from_time_abs (pos->date), "amount", TALER_JSON_from_amount (&pos->amount), - "sign", (account_number == pos->debit_account) ? "-" : "+", + "sign", sign, "counterpart", (json_int_t) ( (account_number == pos->debit_account) ? pos->credit_account : pos->debit_account), @@ -699,6 +918,15 @@ handle_mhd_request (void *cls, upload_data_size, con_cls); if ( (0 == strcasecmp (url, + "/reject")) && + (0 == strcasecmp (method, + MHD_HTTP_METHOD_POST)) ) + return handle_reject (h, + connection, + upload_data, + upload_data_size, + con_cls); + if ( (0 == strcasecmp (url, "/history")) && (0 == strcasecmp (method, MHD_HTTP_METHOD_GET)) ) |