largely fix #5077
This commit is contained in:
parent
5540747ca2
commit
042616899f
@ -830,6 +830,7 @@ check_exchange_wire_out ()
|
||||
* transactions).
|
||||
*
|
||||
* @param cls closure
|
||||
* @param ec error code in case something went wrong
|
||||
* @param dir direction of the transfer
|
||||
* @param row_off identification of the position at which we are querying
|
||||
* @param row_off_size number of bytes in @a row_off
|
||||
@ -838,6 +839,7 @@ check_exchange_wire_out ()
|
||||
*/
|
||||
static int
|
||||
history_debit_cb (void *cls,
|
||||
enum TALER_ErrorCode ec,
|
||||
enum TALER_BANK_Direction dir,
|
||||
const void *row_off,
|
||||
size_t row_off_size,
|
||||
@ -848,6 +850,13 @@ history_debit_cb (void *cls,
|
||||
|
||||
if (TALER_BANK_DIRECTION_NONE == dir)
|
||||
{
|
||||
if (TALER_EC_NONE != ec)
|
||||
{
|
||||
/* FIXME: log properly to audit report! */
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"Error fetching history: %u!\n",
|
||||
(unsigned int) ec);
|
||||
}
|
||||
/* end of iteration, now check wire_out to see
|
||||
if it matches #out_map */
|
||||
hh = NULL;
|
||||
@ -1069,6 +1078,7 @@ conclude_credit_history ()
|
||||
* transactions).
|
||||
*
|
||||
* @param cls closure
|
||||
* @param ec error code in case something went wrong
|
||||
* @param dir direction of the transfer
|
||||
* @param row_off identification of the position at which we are querying
|
||||
* @param row_off_size number of bytes in @a row_off
|
||||
@ -1077,6 +1087,7 @@ conclude_credit_history ()
|
||||
*/
|
||||
static int
|
||||
history_credit_cb (void *cls,
|
||||
enum TALER_ErrorCode ec,
|
||||
enum TALER_BANK_Direction dir,
|
||||
const void *row_off,
|
||||
size_t row_off_size,
|
||||
@ -1087,6 +1098,13 @@ history_credit_cb (void *cls,
|
||||
|
||||
if (TALER_BANK_DIRECTION_NONE == dir)
|
||||
{
|
||||
if (TALER_EC_NONE != ec)
|
||||
{
|
||||
/* FIXME: log properly to audit report! */
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"Error fetching history: %u!\n",
|
||||
(unsigned int) ec);
|
||||
}
|
||||
/* end of operation */
|
||||
hh = NULL;
|
||||
conclude_credit_history ();
|
||||
|
@ -17,7 +17,8 @@ libtalerbank_la_LDFLAGS = \
|
||||
libtalerbank_la_SOURCES = \
|
||||
bank_api_admin.c \
|
||||
bank_api_common.c bank_api_common.h \
|
||||
bank_api_history.c
|
||||
bank_api_history.c \
|
||||
bank_api_reject.c
|
||||
|
||||
libtalerbank_la_LIBADD = \
|
||||
$(top_builddir)/src/json/libtalerjson.la \
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2015, 2016, 2017 GNUnet e.V.
|
||||
Copyright (C) 2015, 2016, 2017 Taler Systems SA
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
@ -79,11 +79,13 @@ handle_admin_add_incoming_finished (void *cls,
|
||||
{
|
||||
struct TALER_BANK_AdminAddIncomingHandle *aai = cls;
|
||||
uint64_t serial_id = UINT64_MAX;
|
||||
enum TALER_ErrorCode ec;
|
||||
|
||||
aai->job = NULL;
|
||||
switch (response_code)
|
||||
{
|
||||
case 0:
|
||||
ec = TALER_EC_INVALID_RESPONSE;
|
||||
break;
|
||||
case MHD_HTTP_OK:
|
||||
{
|
||||
@ -100,29 +102,36 @@ handle_admin_add_incoming_finished (void *cls,
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
response_code = 0;
|
||||
ec = TALER_EC_INVALID_RESPONSE;
|
||||
break;
|
||||
}
|
||||
ec = TALER_EC_NONE;
|
||||
}
|
||||
break;
|
||||
case MHD_HTTP_BAD_REQUEST:
|
||||
/* This should never happen, either us or the bank is buggy
|
||||
(or API version conflict); just pass JSON reply to the application */
|
||||
ec = TALER_BANK_parse_ec_ (json);
|
||||
break;
|
||||
case MHD_HTTP_FORBIDDEN:
|
||||
/* Access denied */
|
||||
ec = TALER_BANK_parse_ec_ (json);
|
||||
break;
|
||||
case MHD_HTTP_UNAUTHORIZED:
|
||||
/* Nothing really to verify, bank says one of the signatures is
|
||||
invalid; as we checked them, this should never happen, we
|
||||
should pass the JSON reply to the application */
|
||||
ec = TALER_BANK_parse_ec_ (json);
|
||||
break;
|
||||
case MHD_HTTP_NOT_FOUND:
|
||||
/* Nothing really to verify, this should never
|
||||
happen, we should pass the JSON reply to the application */
|
||||
ec = TALER_BANK_parse_ec_ (json);
|
||||
break;
|
||||
case MHD_HTTP_INTERNAL_SERVER_ERROR:
|
||||
/* Server had an internal issue; we should retry, but this API
|
||||
leaves this to the application */
|
||||
ec = TALER_BANK_parse_ec_ (json);
|
||||
break;
|
||||
default:
|
||||
/* unexpected response code */
|
||||
@ -130,11 +139,13 @@ handle_admin_add_incoming_finished (void *cls,
|
||||
"Unexpected response code %u\n",
|
||||
(unsigned int) response_code);
|
||||
GNUNET_break (0);
|
||||
ec = TALER_BANK_parse_ec_ (json);
|
||||
response_code = 0;
|
||||
break;
|
||||
}
|
||||
aai->cb (aai->cb_cls,
|
||||
response_code,
|
||||
ec,
|
||||
serial_id,
|
||||
json);
|
||||
TALER_BANK_admin_add_incoming_cancel (aai);
|
||||
@ -151,7 +162,7 @@ handle_admin_add_incoming_finished (void *cls,
|
||||
* @param bank_base_url URL of the bank (used to execute this request)
|
||||
* @param auth authentication data to send to the bank
|
||||
* @param exchange_base_url base URL of the exchange (for tracking)
|
||||
* @param wtid wire transfer identifier for the transfer
|
||||
* @param subject wire transfer subject for the transfer
|
||||
* @param amount amount that was deposited
|
||||
* @param debit_account_no account number to withdraw from (53 bits at most)
|
||||
* @param credit_account_no account number to deposit into (53 bits at most)
|
||||
@ -166,7 +177,7 @@ TALER_BANK_admin_add_incoming (struct GNUNET_CURL_Context *ctx,
|
||||
const char *bank_base_url,
|
||||
const struct TALER_BANK_AuthenticationData *auth,
|
||||
const char *exchange_base_url,
|
||||
const struct TALER_WireTransferIdentifierRawP *wtid,
|
||||
const char *subject,
|
||||
const struct TALER_Amount *amount,
|
||||
uint64_t debit_account_no,
|
||||
uint64_t credit_account_no,
|
||||
@ -182,10 +193,10 @@ TALER_BANK_admin_add_incoming (struct GNUNET_CURL_Context *ctx,
|
||||
GNUNET_break (0);
|
||||
return NULL;
|
||||
}
|
||||
admin_obj = json_pack ("{s:{s:s}, s:s, s:o, s:o, s:I, s:I}",
|
||||
admin_obj = json_pack ("{s:{s:s}, s:s, s:s, s:o, s:I, s:I}",
|
||||
"auth", "type", "basic",
|
||||
"exchange_url", exchange_base_url,
|
||||
"wtid", GNUNET_JSON_from_data_auto (wtid),
|
||||
"subject", subject,
|
||||
"amount", TALER_JSON_from_amount (amount),
|
||||
"debit_account", (json_int_t) debit_account_no,
|
||||
"credit_account", (json_int_t) credit_account_no);
|
||||
|
@ -80,7 +80,7 @@ TALER_BANK_make_auth_header_ (const struct TALER_BANK_AuthenticationData *auth)
|
||||
authh = append (authh,
|
||||
"X-Taler-Bank-Password",
|
||||
auth->details.basic.password);
|
||||
return authh;
|
||||
return authh;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -111,5 +111,33 @@ TALER_BANK_path_to_url_ (const char *u,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse error code given in @a json.
|
||||
*
|
||||
* @param json the json to parse
|
||||
* @return error code, or #TALER_EC_INVALID if not found
|
||||
*/
|
||||
enum TALER_ErrorCode
|
||||
TALER_BANK_parse_ec_ (const json_t *json)
|
||||
{
|
||||
uint32_t ec;
|
||||
|
||||
struct GNUNET_JSON_Specification spec[] = {
|
||||
GNUNET_JSON_spec_uint32 ("ec",
|
||||
&ec),
|
||||
GNUNET_JSON_spec_end()
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_JSON_parse (json,
|
||||
spec,
|
||||
NULL, NULL))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return TALER_EC_INVALID;
|
||||
}
|
||||
return (enum TALER_ErrorCode) ec;
|
||||
}
|
||||
|
||||
|
||||
/* end of bank_api_common.c */
|
||||
|
@ -51,4 +51,14 @@ TALER_BANK_path_to_url_ (const char *u,
|
||||
const char *path);
|
||||
|
||||
|
||||
/**
|
||||
* Parse error code given in @a json.
|
||||
*
|
||||
* @param json the json to parse
|
||||
* @return error code, or #TALER_EC_INVALID if not found
|
||||
*/
|
||||
enum TALER_ErrorCode
|
||||
TALER_BANK_parse_ec_ (const json_t *json);
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -118,22 +118,37 @@ parse_account_history (struct TALER_BANK_HistoryHandle *hh,
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
if (0 == strcasecmp (sign,
|
||||
"+"))
|
||||
direction = TALER_BANK_DIRECTION_CREDIT;
|
||||
else if (0 == strcasecmp (sign,
|
||||
"-"))
|
||||
direction = TALER_BANK_DIRECTION_DEBIT;
|
||||
else if (0 == strcasecmp (sign,
|
||||
"cancel+"))
|
||||
direction = TALER_BANK_DIRECTION_CREDIT | TALER_BANK_DIRECTION_CANCEL;
|
||||
else if (0 == strcasecmp (sign,
|
||||
"cancel-"))
|
||||
direction = TALER_BANK_DIRECTION_DEBIT | TALER_BANK_DIRECTION_CANCEL;
|
||||
else
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
GNUNET_JSON_parse_free (hist_spec);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
td.account_details = json_pack ("{s:s, s:s, s:I}",
|
||||
"type", "test",
|
||||
"bank_uri", hh->bank_base_url,
|
||||
"account_number", (json_int_t) other_account);
|
||||
direction = (0 == strcasecmp (sign,
|
||||
"+"))
|
||||
? TALER_BANK_DIRECTION_CREDIT
|
||||
: TALER_BANK_DIRECTION_DEBIT;
|
||||
hh->hcb (hh->hcb_cls,
|
||||
MHD_HTTP_OK,
|
||||
TALER_EC_NONE,
|
||||
direction,
|
||||
serial_id,
|
||||
&td,
|
||||
transaction);
|
||||
GNUNET_JSON_parse_free (hist_spec);
|
||||
json_decref (td.account_details);
|
||||
GNUNET_JSON_parse_free (hist_spec);
|
||||
}
|
||||
return GNUNET_OK;
|
||||
}
|
||||
@ -153,6 +168,7 @@ handle_history_finished (void *cls,
|
||||
const json_t *json)
|
||||
{
|
||||
struct TALER_BANK_HistoryHandle *hh = cls;
|
||||
enum TALER_ErrorCode ec;
|
||||
|
||||
hh->job = NULL;
|
||||
switch (response_code)
|
||||
@ -166,31 +182,38 @@ handle_history_finished (void *cls,
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
response_code = 0;
|
||||
ec = TALER_EC_INVALID_RESPONSE;
|
||||
break;
|
||||
}
|
||||
response_code = MHD_HTTP_NO_CONTENT; /* signal end of list */
|
||||
break;
|
||||
case MHD_HTTP_NO_CONTENT:
|
||||
ec = TALER_EC_NONE;
|
||||
break;
|
||||
case MHD_HTTP_BAD_REQUEST:
|
||||
/* This should never happen, either us or the bank is buggy
|
||||
(or API version conflict); just pass JSON reply to the application */
|
||||
ec = TALER_BANK_parse_ec_ (json);
|
||||
break;
|
||||
case MHD_HTTP_FORBIDDEN:
|
||||
/* Access denied */
|
||||
ec = TALER_BANK_parse_ec_ (json);
|
||||
break;
|
||||
case MHD_HTTP_UNAUTHORIZED:
|
||||
/* Nothing really to verify, bank says one of the signatures is
|
||||
invalid; as we checked them, this should never happen, we
|
||||
should pass the JSON reply to the application */
|
||||
ec = TALER_BANK_parse_ec_ (json);
|
||||
break;
|
||||
case MHD_HTTP_NOT_FOUND:
|
||||
/* Nothing really to verify, this should never
|
||||
happen, we should pass the JSON reply to the application */
|
||||
ec = TALER_BANK_parse_ec_ (json);
|
||||
break;
|
||||
case MHD_HTTP_INTERNAL_SERVER_ERROR:
|
||||
/* Server had an internal issue; we should retry, but this API
|
||||
leaves this to the application */
|
||||
ec = TALER_BANK_parse_ec_ (json);
|
||||
break;
|
||||
default:
|
||||
/* unexpected response code */
|
||||
@ -198,11 +221,13 @@ handle_history_finished (void *cls,
|
||||
"Unexpected response code %u\n",
|
||||
(unsigned int) response_code);
|
||||
GNUNET_break (0);
|
||||
ec = TALER_BANK_parse_ec_ (json);
|
||||
response_code = 0;
|
||||
break;
|
||||
}
|
||||
hh->hcb (hh->hcb_cls,
|
||||
response_code,
|
||||
ec,
|
||||
TALER_BANK_DIRECTION_NONE,
|
||||
0LLU,
|
||||
NULL,
|
||||
@ -243,6 +268,8 @@ TALER_BANK_history (struct GNUNET_CURL_Context *ctx,
|
||||
struct TALER_BANK_HistoryHandle *hh;
|
||||
CURL *eh;
|
||||
char *url;
|
||||
const char *dir;
|
||||
const char *can;
|
||||
|
||||
if (0 == num_results)
|
||||
{
|
||||
@ -254,36 +281,42 @@ TALER_BANK_history (struct GNUNET_CURL_Context *ctx,
|
||||
GNUNET_break (0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dir = NULL;
|
||||
if (TALER_BANK_DIRECTION_BOTH == (TALER_BANK_DIRECTION_BOTH & direction))
|
||||
dir = "both";
|
||||
else if (TALER_BANK_DIRECTION_CREDIT == (TALER_BANK_DIRECTION_CREDIT & direction))
|
||||
dir = "credit";
|
||||
else if (TALER_BANK_DIRECTION_DEBIT == (TALER_BANK_DIRECTION_BOTH & direction))
|
||||
dir = "debit";
|
||||
if (NULL == dir)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return NULL;
|
||||
}
|
||||
if (TALER_BANK_DIRECTION_CANCEL == (TALER_BANK_DIRECTION_CANCEL & direction))
|
||||
can = "show";
|
||||
else
|
||||
can = "omit";
|
||||
if (UINT64_MAX == start_row)
|
||||
{
|
||||
if (TALER_BANK_DIRECTION_BOTH == direction)
|
||||
GNUNET_asprintf (&url,
|
||||
"/history?auth=basic&account_number=%llu&delta=%lld",
|
||||
(unsigned long long) account_number,
|
||||
(long long) num_results);
|
||||
else
|
||||
GNUNET_asprintf (&url,
|
||||
"/history?auth=basic&account_number=%llu&delta=%lld&direction=%s",
|
||||
(unsigned long long) account_number,
|
||||
(long long) num_results,
|
||||
(TALER_BANK_DIRECTION_CREDIT == direction) ? "credit" : "debit");
|
||||
GNUNET_asprintf (&url,
|
||||
"/history?auth=basic&account_number=%llu&delta=%lld&direction=%s&cancelled=%s",
|
||||
(unsigned long long) account_number,
|
||||
(long long) num_results,
|
||||
dir,
|
||||
can);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (TALER_BANK_DIRECTION_BOTH == direction)
|
||||
GNUNET_asprintf (&url,
|
||||
"/history?auth=basic&account_number=%llu&delta=%lld&start=%llu",
|
||||
(unsigned long long) account_number,
|
||||
(long long) num_results,
|
||||
(unsigned long long) start_row);
|
||||
else
|
||||
GNUNET_asprintf (&url,
|
||||
"/history?auth=basic&account_number=%llu&delta=%lld&start=%llu&direction=%s",
|
||||
(unsigned long long) account_number,
|
||||
(long long) num_results,
|
||||
(unsigned long long) start_row,
|
||||
(TALER_BANK_DIRECTION_CREDIT == direction) ? "credit" : "debit");
|
||||
GNUNET_asprintf (&url,
|
||||
"/history?auth=basic&account_number=%llu&delta=%lld&start=%llu&direction=%s&cancelled=%s",
|
||||
(unsigned long long) account_number,
|
||||
(long long) num_results,
|
||||
(unsigned long long) start_row,
|
||||
dir,
|
||||
can);
|
||||
}
|
||||
|
||||
hh = GNUNET_new (struct TALER_BANK_HistoryHandle);
|
||||
|
245
src/bank-lib/bank_api_reject.c
Normal file
245
src/bank-lib/bank_api_reject.c
Normal file
@ -0,0 +1,245 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2015, 2016, 2017 Taler Systems SA
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
TALER; see the file COPYING. If not, see
|
||||
<http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file bank-lib/bank_api_reject.c
|
||||
* @brief Implementation of the /reject request of the bank's HTTP API
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include "bank_api_common.h"
|
||||
#include <microhttpd.h> /* just for HTTP status codes */
|
||||
#include "taler_signatures.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief A /reject Handle
|
||||
*/
|
||||
struct TALER_BANK_RejectHandle
|
||||
{
|
||||
|
||||
/**
|
||||
* The url for this request.
|
||||
*/
|
||||
char *request_url;
|
||||
|
||||
/**
|
||||
* JSON encoding of the request to POST.
|
||||
*/
|
||||
char *json_enc;
|
||||
|
||||
/**
|
||||
* Handle for the request.
|
||||
*/
|
||||
struct GNUNET_CURL_Job *job;
|
||||
|
||||
/**
|
||||
* HTTP authentication-related headers for the request.
|
||||
*/
|
||||
struct curl_slist *authh;
|
||||
|
||||
/**
|
||||
* Function to call with the result.
|
||||
*/
|
||||
TALER_BANK_RejectResultCallback cb;
|
||||
|
||||
/**
|
||||
* Closure for @a cb.
|
||||
*/
|
||||
void *cb_cls;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Function called when we're done processing the
|
||||
* HTTP /reject request.
|
||||
*
|
||||
* @param cls the `struct TALER_BANK_RejectHandle`
|
||||
* @param response_code HTTP response code, 0 on error
|
||||
* @param json parsed JSON result, NULL on error
|
||||
*/
|
||||
static void
|
||||
handle_reject_finished (void *cls,
|
||||
long response_code,
|
||||
const json_t *json)
|
||||
{
|
||||
struct TALER_BANK_RejectHandle *rh = cls;
|
||||
enum TALER_ErrorCode ec;
|
||||
|
||||
rh->job = NULL;
|
||||
switch (response_code)
|
||||
{
|
||||
case 0:
|
||||
ec = TALER_EC_INVALID_RESPONSE;
|
||||
break;
|
||||
case MHD_HTTP_OK:
|
||||
GNUNET_break_op (0);
|
||||
response_code = 0;
|
||||
ec = TALER_EC_INVALID_RESPONSE;
|
||||
break;
|
||||
case MHD_HTTP_NO_CONTENT:
|
||||
ec = TALER_EC_NONE;
|
||||
break;
|
||||
case MHD_HTTP_BAD_REQUEST:
|
||||
/* This should never happen, either us or the bank is buggy
|
||||
(or API version conflict); just pass JSON reply to the application */
|
||||
ec = TALER_BANK_parse_ec_ (json);
|
||||
break;
|
||||
case MHD_HTTP_FORBIDDEN:
|
||||
/* Access denied */
|
||||
ec = TALER_BANK_parse_ec_ (json);
|
||||
break;
|
||||
case MHD_HTTP_UNAUTHORIZED:
|
||||
/* Nothing really to verify, bank says one of the signatures is
|
||||
invalid; as we checked them, this should never happen, we
|
||||
should pass the JSON reply to the application */
|
||||
ec = TALER_BANK_parse_ec_ (json);
|
||||
break;
|
||||
case MHD_HTTP_NOT_FOUND:
|
||||
/* Nothing really to verify, this should never
|
||||
happen, we should pass the JSON reply to the application */
|
||||
ec = TALER_BANK_parse_ec_ (json);
|
||||
break;
|
||||
case MHD_HTTP_INTERNAL_SERVER_ERROR:
|
||||
/* Server had an internal issue; we should retry, but this API
|
||||
leaves this to the application */
|
||||
ec = TALER_BANK_parse_ec_ (json);
|
||||
break;
|
||||
default:
|
||||
/* unexpected response code */
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Unexpected response code %u\n",
|
||||
(unsigned int) response_code);
|
||||
GNUNET_break (0);
|
||||
ec = TALER_BANK_parse_ec_ (json);
|
||||
response_code = 0;
|
||||
break;
|
||||
}
|
||||
rh->cb (rh->cb_cls,
|
||||
response_code,
|
||||
ec);
|
||||
TALER_BANK_reject_cancel (rh);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Request rejection of a wire transfer, marking it as cancelled and voiding
|
||||
* its effects.
|
||||
*
|
||||
* @param ctx curl context for the event loop
|
||||
* @param bank_base_url URL of the bank (used to execute this request)
|
||||
* @param auth authentication data to use
|
||||
* @param account_number which account number should we query
|
||||
* @param rowid transfer to reject
|
||||
* @param rcb the callback to call with the operation result
|
||||
* @param rcb_cls closure for @a rcb
|
||||
* @return NULL
|
||||
* if the inputs are invalid.
|
||||
* In this case, the callback is not called.
|
||||
*/
|
||||
struct TALER_BANK_RejectHandle *
|
||||
TALER_BANK_reject (struct GNUNET_CURL_Context *ctx,
|
||||
const char *bank_base_url,
|
||||
const struct TALER_BANK_AuthenticationData *auth,
|
||||
uint64_t account_number,
|
||||
uint64_t rowid,
|
||||
TALER_BANK_RejectResultCallback rcb,
|
||||
void *rcb_cls)
|
||||
{
|
||||
struct TALER_BANK_RejectHandle *rh;
|
||||
json_t *reject_obj;
|
||||
CURL *eh;
|
||||
|
||||
reject_obj = json_pack ("{s:{s:s}, s:I, s:I}",
|
||||
"auth", "type", "basic",
|
||||
"row_id", (json_int_t) rowid,
|
||||
"credit_account", (json_int_t) account_number);
|
||||
if (NULL == reject_obj)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return NULL;
|
||||
}
|
||||
rh = GNUNET_new (struct TALER_BANK_RejectHandle);
|
||||
rh->cb = rcb;
|
||||
rh->cb_cls = rcb_cls;
|
||||
rh->request_url = TALER_BANK_path_to_url_ (bank_base_url,
|
||||
"/reject");
|
||||
rh->authh = TALER_BANK_make_auth_header_ (auth);
|
||||
/* Append content type header here, can't do it in GNUNET_CURL_job_add
|
||||
as that would override the CURLOPT_HTTPHEADER instead of appending. */
|
||||
{
|
||||
struct curl_slist *ext;
|
||||
|
||||
ext = curl_slist_append (rh->authh,
|
||||
"Content-Type: application/json");
|
||||
if (NULL == ext)
|
||||
GNUNET_break (0);
|
||||
else
|
||||
rh->authh = ext;
|
||||
}
|
||||
eh = curl_easy_init ();
|
||||
GNUNET_assert (NULL != (rh->json_enc =
|
||||
json_dumps (reject_obj,
|
||||
JSON_COMPACT)));
|
||||
json_decref (reject_obj);
|
||||
GNUNET_assert (CURLE_OK ==
|
||||
curl_easy_setopt (eh,
|
||||
CURLOPT_HTTPHEADER,
|
||||
rh->authh));
|
||||
GNUNET_assert (CURLE_OK ==
|
||||
curl_easy_setopt (eh,
|
||||
CURLOPT_URL,
|
||||
rh->request_url));
|
||||
GNUNET_assert (CURLE_OK ==
|
||||
curl_easy_setopt (eh,
|
||||
CURLOPT_POSTFIELDS,
|
||||
rh->json_enc));
|
||||
GNUNET_assert (CURLE_OK ==
|
||||
curl_easy_setopt (eh,
|
||||
CURLOPT_POSTFIELDSIZE,
|
||||
strlen (rh->json_enc)));
|
||||
rh->job = GNUNET_CURL_job_add (ctx,
|
||||
eh,
|
||||
GNUNET_NO,
|
||||
&handle_reject_finished,
|
||||
rh);
|
||||
return rh;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cancel an reject request. This function cannot be used on a request
|
||||
* handle if the response was is already served for it.
|
||||
*
|
||||
* @param rh the reject request handle
|
||||
*/
|
||||
void
|
||||
TALER_BANK_reject_cancel (struct TALER_BANK_RejectHandle *rh)
|
||||
{
|
||||
if (NULL != rh->job)
|
||||
{
|
||||
GNUNET_CURL_job_cancel (rh->job);
|
||||
rh->job = NULL;
|
||||
}
|
||||
curl_slist_free_all (rh->authh);
|
||||
GNUNET_free (rh->request_url);
|
||||
GNUNET_free (rh->json_enc);
|
||||
GNUNET_free (rh);
|
||||
}
|
||||
|
||||
|
||||
/* end of bank_api_reject.c */
|
@ -81,6 +81,11 @@ struct Transaction
|
||||
* Number of this transaction.
|
||||
*/
|
||||
uint64_t serial_id;
|
||||
|
||||
/**
|
||||
* Flag set if the transfer was rejected.
|
||||
*/
|
||||
int rejected;
|
||||
};
|
||||
|
||||
|
||||
@ -219,6 +224,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()).
|
||||
@ -287,6 +317,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
|
||||
@ -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",
|
||||
@ -433,6 +519,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
|
||||
*
|
||||
@ -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),
|
||||
@ -698,6 +917,15 @@ handle_mhd_request (void *cls,
|
||||
upload_data,
|
||||
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,
|
||||
|
@ -50,6 +50,7 @@ run (void *cls)
|
||||
{ .oc = TBI_OC_ADMIN_ADD_INCOMING,
|
||||
.label = "deposit-1",
|
||||
.details.admin_add_incoming.exchange_base_url = "https://exchange.net/", /* bogus */
|
||||
.details.admin_add_incoming.subject = "subject 1",
|
||||
.details.admin_add_incoming.expected_response_code = MHD_HTTP_OK,
|
||||
.details.admin_add_incoming.credit_account_no = 1,
|
||||
.details.admin_add_incoming.debit_account_no = 2, /* Ignored */
|
||||
@ -58,6 +59,7 @@ run (void *cls)
|
||||
{ .oc = TBI_OC_ADMIN_ADD_INCOMING,
|
||||
.label = "deposit-2",
|
||||
.details.admin_add_incoming.exchange_base_url = "https://exchange.net/", /* bogus */
|
||||
.details.admin_add_incoming.subject = "subject 2",
|
||||
.details.admin_add_incoming.expected_response_code = MHD_HTTP_OK,
|
||||
.details.admin_add_incoming.credit_account_no = 1,
|
||||
.details.admin_add_incoming.debit_account_no = 2, /* Ignored */
|
||||
@ -89,6 +91,27 @@ run (void *cls)
|
||||
.details.history.direction = TALER_BANK_DIRECTION_DEBIT,
|
||||
.details.history.start_row_ref = "deposit-1",
|
||||
.details.history.num_results = 5 },
|
||||
{ .oc = TBI_OC_REJECT,
|
||||
.label = "reject-1",
|
||||
.details.reject.cmd_ref = "deposit-1" },
|
||||
{ .oc = TBI_OC_HISTORY,
|
||||
.label = "history-r1",
|
||||
.details.history.account_number = 2,
|
||||
.details.history.direction = TALER_BANK_DIRECTION_CREDIT,
|
||||
.details.history.start_row_ref = NULL,
|
||||
.details.history.num_results = 5 },
|
||||
{ .oc = TBI_OC_HISTORY,
|
||||
.label = "history-r2",
|
||||
.details.history.account_number = 2,
|
||||
.details.history.direction = TALER_BANK_DIRECTION_DEBIT,
|
||||
.details.history.start_row_ref = NULL,
|
||||
.details.history.num_results = 5 },
|
||||
{ .oc = TBI_OC_HISTORY,
|
||||
.label = "history-r3",
|
||||
.details.history.account_number = 2,
|
||||
.details.history.direction = TALER_BANK_DIRECTION_BOTH | TALER_BANK_DIRECTION_CANCEL,
|
||||
.details.history.start_row_ref = NULL,
|
||||
.details.history.num_results = 5 },
|
||||
{ .oc = TBI_OC_END }
|
||||
};
|
||||
|
||||
|
@ -48,6 +48,7 @@ run (void *cls)
|
||||
/* Add EUR:5.01 to account 1 */
|
||||
{ .oc = TBI_OC_ADMIN_ADD_INCOMING,
|
||||
.label = "debit-1",
|
||||
.details.admin_add_incoming.subject = "subject 1",
|
||||
.details.admin_add_incoming.expected_response_code = MHD_HTTP_OK,
|
||||
.details.admin_add_incoming.credit_account_no = 1,
|
||||
.details.admin_add_incoming.debit_account_no = 2,
|
||||
@ -68,6 +69,7 @@ run (void *cls)
|
||||
.details.history.num_results = 5 },
|
||||
{ .oc = TBI_OC_ADMIN_ADD_INCOMING,
|
||||
.label = "debit-2",
|
||||
.details.admin_add_incoming.subject = "subject 2",
|
||||
.details.admin_add_incoming.expected_response_code = MHD_HTTP_OK,
|
||||
.details.admin_add_incoming.credit_account_no = 3,
|
||||
.details.admin_add_incoming.debit_account_no = 2,
|
||||
@ -75,6 +77,7 @@ run (void *cls)
|
||||
.details.admin_add_incoming.amount = "KUDOS:3.21" },
|
||||
{ .oc = TBI_OC_ADMIN_ADD_INCOMING,
|
||||
.label = "credit-2",
|
||||
.details.admin_add_incoming.subject = "credit 2",
|
||||
.details.admin_add_incoming.expected_response_code = MHD_HTTP_OK,
|
||||
.details.admin_add_incoming.credit_account_no = 2,
|
||||
.details.admin_add_incoming.debit_account_no = 3,
|
||||
@ -105,6 +108,40 @@ run (void *cls)
|
||||
/* check transfer list is now empty */
|
||||
{ .oc = TBI_OC_EXPECT_TRANSFERS_EMPTY,
|
||||
.label = "expect-empty" },
|
||||
/* Add EUR:5.01 to account 1 */
|
||||
{ .oc = TBI_OC_ADMIN_ADD_INCOMING,
|
||||
.label = "credit-for-reject-1",
|
||||
.details.admin_add_incoming.subject = "subject 3",
|
||||
.details.admin_add_incoming.expected_response_code = MHD_HTTP_OK,
|
||||
.details.admin_add_incoming.credit_account_no = 1,
|
||||
.details.admin_add_incoming.debit_account_no = 2,
|
||||
.details.admin_add_incoming.exchange_base_url = "https://exchange.net/",
|
||||
.details.admin_add_incoming.amount = "KUDOS:5.01" },
|
||||
{ .oc = TBI_OC_REJECT,
|
||||
.label = "reject-1",
|
||||
.details.reject.cmd_ref = "credit-for-reject-1" },
|
||||
{ .oc = TBI_OC_HISTORY,
|
||||
.label = "history-r1",
|
||||
.details.history.account_number = 1,
|
||||
.details.history.direction = TALER_BANK_DIRECTION_BOTH,
|
||||
/* range is exclusive, and everything up to and including "credit-2"
|
||||
was already killed via TBI_OC_EXPECT_TRANSFER and thus won't show
|
||||
in the history. So to see the rejected transfer, we need to start
|
||||
looking after "credit-2" */
|
||||
.details.history.start_row_ref = NULL,
|
||||
.details.history.num_results = 5 },
|
||||
{ .oc = TBI_OC_HISTORY,
|
||||
.label = "history-r1c",
|
||||
.details.history.account_number = 1,
|
||||
.details.history.direction = TALER_BANK_DIRECTION_BOTH | TALER_BANK_DIRECTION_CANCEL,
|
||||
.details.history.start_row_ref = NULL,
|
||||
.details.history.num_results = 5 },
|
||||
{ .oc = TBI_OC_EXPECT_TRANSFER,
|
||||
.label = "expect-credit-reject-1",
|
||||
.details.expect_transfer.cmd_ref = "credit-for-reject-1" },
|
||||
/* check transfer list is now empty */
|
||||
{ .oc = TBI_OC_EXPECT_TRANSFERS_EMPTY,
|
||||
.label = "expect-empty-2" },
|
||||
{ .oc = TBI_OC_END }
|
||||
};
|
||||
|
||||
|
@ -110,7 +110,6 @@ static const struct TBI_Command *
|
||||
find_command (const struct InterpreterState *is,
|
||||
const char *label)
|
||||
{
|
||||
unsigned int i;
|
||||
const struct TBI_Command *cmd;
|
||||
|
||||
if (NULL == label)
|
||||
@ -119,7 +118,7 @@ find_command (const struct InterpreterState *is,
|
||||
"Attempt to lookup command for empty label\n");
|
||||
return NULL;
|
||||
}
|
||||
for (i=0;TBI_OC_END != (cmd = &is->commands[i])->oc;i++)
|
||||
for (unsigned int i=0;TBI_OC_END != (cmd = &is->commands[i])->oc;i++)
|
||||
if ( (NULL != cmd->label) &&
|
||||
(0 == strcmp (cmd->label,
|
||||
label)) )
|
||||
@ -131,6 +130,63 @@ find_command (const struct InterpreterState *is,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test if the /admin/add/incoming transaction at offset @a off
|
||||
* has been /rejected.
|
||||
*
|
||||
* @param is interpreter state (where we are right now)
|
||||
* @param off offset of the command to test for rejection
|
||||
* @return #GNUNET_YES if the command at @a off was cancelled
|
||||
*/
|
||||
static int
|
||||
test_cancelled (struct InterpreterState *is,
|
||||
unsigned int off)
|
||||
{
|
||||
const struct TBI_Command *cmd = &is->commands[off];
|
||||
|
||||
for (unsigned int i=0;i<is->ip;i++)
|
||||
{
|
||||
const struct TBI_Command *c = &is->commands[i];
|
||||
|
||||
if (TBI_OC_REJECT != c->oc)
|
||||
continue;
|
||||
if (0 == strcmp (c->details.reject.cmd_ref,
|
||||
cmd->label))
|
||||
return GNUNET_YES;
|
||||
}
|
||||
return GNUNET_NO;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test if the /admin/add/incoming transaction at offset @a off
|
||||
* has been #TBI_OC_EXPECT_TRANSFER treated, and thus been
|
||||
* forgotten by the fakebank.
|
||||
*
|
||||
* @param is interpreter state (where we are right now)
|
||||
* @param off offset of the command to test for rejection
|
||||
* @return #GNUNET_YES if the command at @a off was cancelled
|
||||
*/
|
||||
static int
|
||||
test_deleted_by_expected (struct InterpreterState *is,
|
||||
unsigned int off)
|
||||
{
|
||||
const struct TBI_Command *cmd = &is->commands[off];
|
||||
|
||||
for (unsigned int i=0;i<is->ip;i++)
|
||||
{
|
||||
const struct TBI_Command *c = &is->commands[i];
|
||||
|
||||
if (TBI_OC_EXPECT_TRANSFER != c->oc)
|
||||
continue;
|
||||
if (0 == strcmp (c->details.expect_transfer.cmd_ref,
|
||||
cmd->label))
|
||||
return GNUNET_YES;
|
||||
}
|
||||
return GNUNET_NO;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Item in the transaction history, as reconstructed from the
|
||||
* command history.
|
||||
@ -214,6 +270,7 @@ build_history (struct InterpreterState *is,
|
||||
for (unsigned int off = start;off != end + inc; off += inc)
|
||||
{
|
||||
const struct TBI_Command *pos = &is->commands[off];
|
||||
int cancelled;
|
||||
|
||||
if (TBI_OC_ADMIN_ADD_INCOMING != pos->oc)
|
||||
continue;
|
||||
@ -229,6 +286,15 @@ build_history (struct InterpreterState *is,
|
||||
continue; /* skip until we find the marker */
|
||||
if (total >= cmd->details.history.num_results * inc)
|
||||
break; /* hit limit specified by command */
|
||||
if (GNUNET_YES ==
|
||||
test_deleted_by_expected (is,
|
||||
off))
|
||||
continue;
|
||||
cancelled = test_cancelled (is,
|
||||
off);
|
||||
if ( (GNUNET_YES == cancelled) &&
|
||||
(0 == (cmd->details.history.direction & TALER_BANK_DIRECTION_CANCEL)) )
|
||||
continue;
|
||||
if ( ( (0 != (cmd->details.history.direction & TALER_BANK_DIRECTION_CREDIT)) &&
|
||||
(cmd->details.history.account_number ==
|
||||
pos->details.admin_add_incoming.credit_account_no)) ||
|
||||
@ -253,6 +319,7 @@ build_history (struct InterpreterState *is,
|
||||
for (unsigned int off = start;off != end + inc; off += inc)
|
||||
{
|
||||
const struct TBI_Command *pos = &is->commands[off];
|
||||
int cancelled;
|
||||
|
||||
if (TBI_OC_ADMIN_ADD_INCOMING != pos->oc)
|
||||
continue;
|
||||
@ -268,6 +335,10 @@ build_history (struct InterpreterState *is,
|
||||
continue; /* skip until we find the marker */
|
||||
if (total >= cmd->details.history.num_results * inc)
|
||||
break; /* hit limit specified by command */
|
||||
if (GNUNET_YES ==
|
||||
test_deleted_by_expected (is,
|
||||
off))
|
||||
continue;
|
||||
|
||||
if ( ( (0 != (cmd->details.history.direction & TALER_BANK_DIRECTION_CREDIT)) &&
|
||||
(cmd->details.history.account_number ==
|
||||
@ -280,11 +351,19 @@ build_history (struct InterpreterState *is,
|
||||
continue;
|
||||
}
|
||||
|
||||
cancelled = test_cancelled (is,
|
||||
off);
|
||||
if ( (GNUNET_YES == cancelled) &&
|
||||
(0 == (cmd->details.history.direction & TALER_BANK_DIRECTION_CANCEL)) )
|
||||
continue;
|
||||
|
||||
if ( (0 != (cmd->details.history.direction & TALER_BANK_DIRECTION_CREDIT)) &&
|
||||
(cmd->details.history.account_number ==
|
||||
pos->details.admin_add_incoming.credit_account_no))
|
||||
{
|
||||
h[total].direction = TALER_BANK_DIRECTION_CREDIT;
|
||||
if (GNUNET_YES == cancelled)
|
||||
h[total].direction |= TALER_BANK_DIRECTION_CANCEL;
|
||||
h[total].details.account_details
|
||||
= json_pack ("{s:s, s:s, s:I}",
|
||||
"type",
|
||||
@ -300,6 +379,8 @@ build_history (struct InterpreterState *is,
|
||||
pos->details.admin_add_incoming.debit_account_no))
|
||||
{
|
||||
h[total].direction = TALER_BANK_DIRECTION_DEBIT;
|
||||
if (GNUNET_YES == cancelled)
|
||||
h[total].direction |= TALER_BANK_DIRECTION_CANCEL;
|
||||
h[total].details.account_details
|
||||
= json_pack ("{s:s, s:s, s:I}",
|
||||
"type",
|
||||
@ -323,17 +404,10 @@ build_history (struct InterpreterState *is,
|
||||
/* h[total].execution_date; // unknown here */
|
||||
h[total].serial_id
|
||||
= pos->details.admin_add_incoming.serial_id;
|
||||
{
|
||||
char *ws;
|
||||
|
||||
ws = GNUNET_STRINGS_data_to_string_alloc (&pos->details.admin_add_incoming.wtid,
|
||||
sizeof (struct TALER_WireTransferIdentifierRawP));
|
||||
GNUNET_asprintf (&h[total].details.wire_transfer_subject,
|
||||
"%s %s",
|
||||
ws,
|
||||
pos->details.admin_add_incoming.exchange_base_url);
|
||||
GNUNET_free (ws);
|
||||
}
|
||||
GNUNET_asprintf (&h[total].details.wire_transfer_subject,
|
||||
"%s %s",
|
||||
pos->details.admin_add_incoming.subject,
|
||||
pos->details.admin_add_incoming.exchange_base_url);
|
||||
total++;
|
||||
}
|
||||
}
|
||||
@ -488,18 +562,34 @@ static void
|
||||
interpreter_run (void *cls);
|
||||
|
||||
|
||||
/**
|
||||
* Run the next command.
|
||||
*
|
||||
* @param is interpreter to progress
|
||||
*/
|
||||
static void
|
||||
next (struct InterpreterState *is)
|
||||
{
|
||||
is->ip++;
|
||||
is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
|
||||
is);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function called upon completion of our /admin/add/incoming request.
|
||||
*
|
||||
* @param cls closure with the interpreter state
|
||||
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
|
||||
* 0 if the bank's reply is bogus (fails to follow the protocol)
|
||||
* @param ec taler status code
|
||||
* @param serial_id unique ID of the wire transfer in the bank's records; UINT64_MAX on error
|
||||
* @param json detailed response from the HTTPD, or NULL if reply was not in JSON
|
||||
*/
|
||||
static void
|
||||
add_incoming_cb (void *cls,
|
||||
unsigned int http_status,
|
||||
enum TALER_ErrorCode ec,
|
||||
uint64_t serial_id,
|
||||
const json_t *json)
|
||||
{
|
||||
@ -522,9 +612,7 @@ add_incoming_cb (void *cls,
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
is->ip++;
|
||||
is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
|
||||
is);
|
||||
next (is);
|
||||
}
|
||||
|
||||
|
||||
@ -538,6 +626,7 @@ add_incoming_cb (void *cls,
|
||||
* #MHD_HTTP_NO_CONTENT if there are no more results; on success the
|
||||
* last callback is always of this status (even if `abs(num_results)` were
|
||||
* already returned).
|
||||
* @param ec taler status code
|
||||
* @param dir direction of the transfer
|
||||
* @param serial_id monotonically increasing counter corresponding to the transaction
|
||||
* @param details details about the wire transfer
|
||||
@ -546,6 +635,7 @@ add_incoming_cb (void *cls,
|
||||
static void
|
||||
history_cb (void *cls,
|
||||
unsigned int http_status,
|
||||
enum TALER_ErrorCode ec,
|
||||
enum TALER_BANK_Direction dir,
|
||||
uint64_t serial_id,
|
||||
const struct TALER_BANK_TransferDetails *details,
|
||||
@ -580,9 +670,7 @@ history_cb (void *cls,
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
is->ip++;
|
||||
is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
|
||||
is);
|
||||
next (is);
|
||||
return;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
@ -612,6 +700,38 @@ history_cb (void *cls,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callbacks of this type are used to serve the result of asking
|
||||
* the bank to reject an incoming wire transfer.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param http_status HTTP response code, #MHD_HTTP_NO_CONTENT (204) for successful status request;
|
||||
* #MHD_HTTP_NOT_FOUND if the rowid is unknown;
|
||||
* 0 if the bank's reply is bogus (fails to follow the protocol),
|
||||
* @param ec detailed error code
|
||||
*/
|
||||
static void
|
||||
reject_cb (void *cls,
|
||||
unsigned int http_status,
|
||||
enum TALER_ErrorCode ec)
|
||||
{
|
||||
struct InterpreterState *is = cls;
|
||||
struct TBI_Command *cmd = &is->commands[is->ip];
|
||||
|
||||
cmd->details.reject.rh = NULL;
|
||||
if (MHD_HTTP_NO_CONTENT != http_status)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
fprintf (stderr,
|
||||
"Unexpected response code %u:\n",
|
||||
http_status);
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
next (is);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Run the main interpreter loop that performs bank operations.
|
||||
*
|
||||
@ -658,15 +778,13 @@ interpreter_run (void *cls)
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
|
||||
&cmd->details.admin_add_incoming.wtid,
|
||||
sizeof (cmd->details.admin_add_incoming.wtid));
|
||||
GNUNET_break (NULL != cmd->details.admin_add_incoming.subject);
|
||||
cmd->details.admin_add_incoming.aih
|
||||
= TALER_BANK_admin_add_incoming (is->ctx,
|
||||
"http://localhost:8080",
|
||||
&auth,
|
||||
cmd->details.admin_add_incoming.exchange_base_url,
|
||||
&cmd->details.admin_add_incoming.wtid,
|
||||
cmd->details.admin_add_incoming.subject,
|
||||
&amount,
|
||||
cmd->details.admin_add_incoming.debit_account_no,
|
||||
cmd->details.admin_add_incoming.credit_account_no,
|
||||
@ -722,7 +840,6 @@ interpreter_run (void *cls)
|
||||
&amount));
|
||||
{
|
||||
char *subject;
|
||||
char *expect;
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TALER_FAKEBANK_check (is->fakebank,
|
||||
@ -736,22 +853,17 @@ interpreter_run (void *cls)
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
expect = GNUNET_STRINGS_data_to_string_alloc (&ref->details.admin_add_incoming.wtid,
|
||||
sizeof (ref->details.admin_add_incoming.wtid));
|
||||
if (0 != strcmp (subject, expect))
|
||||
if (0 != strcmp (ref->details.admin_add_incoming.subject,
|
||||
subject))
|
||||
{
|
||||
GNUNET_free (expect);
|
||||
GNUNET_free (subject);
|
||||
GNUNET_break (0);
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
GNUNET_free (subject);
|
||||
GNUNET_free (expect);
|
||||
}
|
||||
is->ip++;
|
||||
is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
|
||||
is);
|
||||
next (is);
|
||||
return;
|
||||
case TBI_OC_EXPECT_TRANSFERS_EMPTY:
|
||||
if (GNUNET_OK != TALER_FAKEBANK_check_empty (is->fakebank))
|
||||
@ -760,9 +872,27 @@ interpreter_run (void *cls)
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
is->ip++;
|
||||
is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
|
||||
is);
|
||||
next (is);
|
||||
return;
|
||||
case TBI_OC_REJECT:
|
||||
ref = find_command (is,
|
||||
cmd->details.reject.cmd_ref);
|
||||
GNUNET_assert (NULL != ref);
|
||||
GNUNET_assert (TBI_OC_ADMIN_ADD_INCOMING == ref->oc);
|
||||
cmd->details.reject.rh
|
||||
= TALER_BANK_reject (is->ctx,
|
||||
"http://localhost:8080",
|
||||
&auth,
|
||||
ref->details.admin_add_incoming.credit_account_no,
|
||||
ref->details.admin_add_incoming.serial_id,
|
||||
&reject_cb,
|
||||
is);
|
||||
if (NULL == cmd->details.reject.rh)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
default:
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
@ -802,7 +932,6 @@ do_shutdown (void *cls)
|
||||
{
|
||||
struct InterpreterState *is = cls;
|
||||
struct TBI_Command *cmd;
|
||||
unsigned int i;
|
||||
|
||||
if (NULL != is->timeout_task)
|
||||
{
|
||||
@ -810,7 +939,7 @@ do_shutdown (void *cls)
|
||||
is->timeout_task = NULL;
|
||||
}
|
||||
|
||||
for (i=0;TBI_OC_END != (cmd = &is->commands[i])->oc;i++)
|
||||
for (unsigned int i=0;TBI_OC_END != (cmd = &is->commands[i])->oc;i++)
|
||||
{
|
||||
switch (cmd->oc)
|
||||
{
|
||||
@ -843,6 +972,17 @@ do_shutdown (void *cls)
|
||||
break;
|
||||
case TBI_OC_EXPECT_TRANSFERS_EMPTY:
|
||||
break;
|
||||
case TBI_OC_REJECT:
|
||||
if (NULL != cmd->details.reject.rh)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
"Command %u (%s) did not complete\n",
|
||||
i,
|
||||
cmd->label);
|
||||
TALER_BANK_reject_cancel (cmd->details.reject.rh);
|
||||
cmd->details.reject.rh = NULL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Unknown instruction %d at %u (%s)\n",
|
||||
|
@ -57,7 +57,12 @@ enum TBI_OpCode
|
||||
/**
|
||||
* Expect that we have exhaustively gone over all transfers at fakebank.
|
||||
*/
|
||||
TBI_OC_EXPECT_TRANSFERS_EMPTY
|
||||
TBI_OC_EXPECT_TRANSFERS_EMPTY,
|
||||
|
||||
/**
|
||||
* Reject incoming transfer.
|
||||
*/
|
||||
TBI_OC_REJECT
|
||||
|
||||
};
|
||||
|
||||
@ -110,10 +115,9 @@ struct TBI_Command
|
||||
const char *exchange_base_url;
|
||||
|
||||
/**
|
||||
* Wire transfer identifier to use. Initialized to
|
||||
* a random value.
|
||||
* Wire transfer subject to use.
|
||||
*/
|
||||
struct TALER_WireTransferIdentifierRawP wtid;
|
||||
const char *subject;
|
||||
|
||||
/**
|
||||
* Which response code do we expect for this command?
|
||||
@ -186,6 +190,23 @@ struct TBI_Command
|
||||
|
||||
} expect_transfer;
|
||||
|
||||
/**
|
||||
* Execute /reject operation.
|
||||
*/
|
||||
struct {
|
||||
|
||||
/**
|
||||
* Reference to the matching transfer that is now to be rejected.
|
||||
*/
|
||||
const char *cmd_ref;
|
||||
|
||||
/**
|
||||
* Set to the API's handle during the operation.
|
||||
*/
|
||||
struct TALER_BANK_RejectHandle *rh;
|
||||
|
||||
} reject;
|
||||
|
||||
} details;
|
||||
|
||||
};
|
||||
|
@ -282,6 +282,7 @@ reject_cb (void *cls,
|
||||
* the bank for the transaction history.
|
||||
*
|
||||
* @param cls closure with the `struct TALER_EXCHANGEDB_Session *`
|
||||
* @param ec taler error code
|
||||
* @param dir direction of the transfer
|
||||
* @param row_off identification of the position at which we are querying
|
||||
* @param row_off_size number of bytes in @a row_off
|
||||
@ -290,6 +291,7 @@ reject_cb (void *cls,
|
||||
*/
|
||||
static int
|
||||
history_cb (void *cls,
|
||||
enum TALER_ErrorCode ec,
|
||||
enum TALER_BANK_Direction dir,
|
||||
const void *row_off,
|
||||
size_t row_off_size,
|
||||
@ -303,6 +305,12 @@ history_cb (void *cls,
|
||||
{
|
||||
hh = NULL;
|
||||
|
||||
if (TALER_EC_NONE != ec)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"Error fetching history: %u!\n",
|
||||
(unsigned int) ec);
|
||||
}
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"End of list. Committing progress!\n");
|
||||
qs = db_plugin->commit (db_plugin->cls,
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2015, 2016, 2017 GNUnet e.V. & Inria
|
||||
Copyright (C) 2015, 2016, 2017 Taler Systems SA
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU Affero General Public License as published by the Free Software
|
||||
@ -25,6 +25,7 @@
|
||||
#include <jansson.h>
|
||||
#include <gnunet/gnunet_curl_lib.h>
|
||||
#include "taler_util.h"
|
||||
#include "taler_error_codes.h"
|
||||
|
||||
|
||||
/**
|
||||
@ -98,12 +99,14 @@ struct TALER_BANK_AdminAddIncomingHandle;
|
||||
* @param cls closure
|
||||
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
|
||||
* 0 if the bank's reply is bogus (fails to follow the protocol)
|
||||
* @param ec detailed error code
|
||||
* @param serial_id unique ID of the wire transfer in the bank's records; UINT64_MAX on error
|
||||
* @param json detailed response from the HTTPD, or NULL if reply was not in JSON
|
||||
*/
|
||||
typedef void
|
||||
(*TALER_BANK_AdminAddIncomingResultCallback) (void *cls,
|
||||
unsigned int http_status,
|
||||
enum TALER_ErrorCode ec,
|
||||
uint64_t serial_id,
|
||||
const json_t *json);
|
||||
|
||||
@ -118,7 +121,7 @@ typedef void
|
||||
* @param bank_base_url URL of the bank (used to execute this request)
|
||||
* @param auth authentication data to use
|
||||
* @param exchange_base_url base URL of the exchange (for tracking)
|
||||
* @param wtid wire transfer identifier for the transfer
|
||||
* @param subject wire transfer subject for the transfer
|
||||
* @param amount amount that was deposited
|
||||
* @param debit_account_no account number to withdraw from (53 bits at most)
|
||||
* @param credit_account_no account number to deposit into (53 bits at most)
|
||||
@ -133,7 +136,7 @@ TALER_BANK_admin_add_incoming (struct GNUNET_CURL_Context *ctx,
|
||||
const char *bank_base_url,
|
||||
const struct TALER_BANK_AuthenticationData *auth,
|
||||
const char *exchange_base_url,
|
||||
const struct TALER_WireTransferIdentifierRawP *wtid,
|
||||
const char *subject,
|
||||
const struct TALER_Amount *amount,
|
||||
uint64_t debit_account_no,
|
||||
uint64_t credit_account_no,
|
||||
@ -174,7 +177,15 @@ enum TALER_BANK_Direction {
|
||||
/**
|
||||
* Return both types of transactions.
|
||||
*/
|
||||
TALER_BANK_DIRECTION_BOTH = (TALER_BANK_DIRECTION_CREDIT | TALER_BANK_DIRECTION_DEBIT)
|
||||
TALER_BANK_DIRECTION_BOTH = (TALER_BANK_DIRECTION_CREDIT | TALER_BANK_DIRECTION_DEBIT),
|
||||
|
||||
/**
|
||||
* Bit mask that is applied to view transactions that have been
|
||||
* cancelled. The bit is set for cancelled transactions that are
|
||||
* returned from /history, and must also be set in order for
|
||||
* cancelled transactions to show up in the /history.
|
||||
*/
|
||||
TALER_BANK_DIRECTION_CANCEL = 4
|
||||
|
||||
};
|
||||
|
||||
@ -222,6 +233,7 @@ struct TALER_BANK_TransferDetails
|
||||
* #MHD_HTTP_NO_CONTENT if there are no more results; on success the
|
||||
* last callback is always of this status (even if `abs(num_results)` were
|
||||
* already returned).
|
||||
* @param ec detailed error code
|
||||
* @param dir direction of the transfer
|
||||
* @param serial_id monotonically increasing counter corresponding to the transaction
|
||||
* @param details details about the wire transfer
|
||||
@ -230,6 +242,7 @@ struct TALER_BANK_TransferDetails
|
||||
typedef void
|
||||
(*TALER_BANK_HistoryResultCallback) (void *cls,
|
||||
unsigned int http_status,
|
||||
enum TALER_ErrorCode ec,
|
||||
enum TALER_BANK_Direction dir,
|
||||
uint64_t serial_id,
|
||||
const struct TALER_BANK_TransferDetails *details,
|
||||
@ -277,5 +290,61 @@ void
|
||||
TALER_BANK_history_cancel (struct TALER_BANK_HistoryHandle *hh);
|
||||
|
||||
|
||||
/**
|
||||
* Handle for #TALER_BANK_reject() operation.
|
||||
*/
|
||||
struct TALER_BANK_RejectHandle;
|
||||
|
||||
|
||||
/**
|
||||
* Callbacks of this type are used to serve the result of asking
|
||||
* the bank to reject an incoming wire transfer.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param http_status HTTP response code, #MHD_HTTP_NO_CONTENT (204) for successful status request;
|
||||
* #MHD_HTTP_NOT_FOUND if the rowid is unknown;
|
||||
* 0 if the bank's reply is bogus (fails to follow the protocol),
|
||||
* @param ec detailed error code
|
||||
*/
|
||||
typedef void
|
||||
(*TALER_BANK_RejectResultCallback) (void *cls,
|
||||
unsigned int http_status,
|
||||
enum TALER_ErrorCode ec);
|
||||
|
||||
|
||||
/**
|
||||
* Request rejection of a wire transfer, marking it as cancelled and voiding
|
||||
* its effects.
|
||||
*
|
||||
* @param ctx curl context for the event loop
|
||||
* @param bank_base_url URL of the bank (used to execute this request)
|
||||
* @param auth authentication data to use
|
||||
* @param account_number which account number should we query
|
||||
* @param rowid transfer to reject
|
||||
* @param rcb the callback to call with the operation result
|
||||
* @param rcb_cls closure for @a rcb
|
||||
* @return NULL
|
||||
* if the inputs are invalid.
|
||||
* In this case, the callback is not called.
|
||||
*/
|
||||
struct TALER_BANK_RejectHandle *
|
||||
TALER_BANK_reject (struct GNUNET_CURL_Context *ctx,
|
||||
const char *bank_base_url,
|
||||
const struct TALER_BANK_AuthenticationData *auth,
|
||||
uint64_t account_number,
|
||||
uint64_t rowid,
|
||||
TALER_BANK_RejectResultCallback rcb,
|
||||
void *rcb_cls);
|
||||
|
||||
|
||||
/**
|
||||
* Cancel an reject request. This function cannot be used on a request
|
||||
* handle if the response was is already served for it.
|
||||
*
|
||||
* @param rh the reject request handle
|
||||
*/
|
||||
void
|
||||
TALER_BANK_reject_cancel (struct TALER_BANK_RejectHandle *rh);
|
||||
|
||||
|
||||
#endif /* _TALER_BANK_SERVICE_H */
|
||||
|
@ -1488,6 +1488,34 @@ enum TALER_ErrorCode
|
||||
*/
|
||||
TALER_EC_TEST_RSA_SIGN_ERROR = 4005,
|
||||
|
||||
/* *************** Taler BANK/FAKEBANK error codes *************** */
|
||||
|
||||
|
||||
/**
|
||||
* Authentication failed for the /admin/add/incoming request.
|
||||
* Returned with a status code of MHD_HTTP_FORBIDDEN.
|
||||
*/
|
||||
TALER_EC_BANK_TRANSFER_NOT_AUHTORIZED = 4101,
|
||||
|
||||
/**
|
||||
* Authentication failed for the /history request.
|
||||
* Returned with a status code of MHD_HTTP_FORBIDDEN.
|
||||
*/
|
||||
TALER_EC_BANK_HISTORY_NOT_AUHTORIZED = 4151,
|
||||
|
||||
/**
|
||||
* The bank could not find the wire transfer that was supposed to
|
||||
* be rejected.
|
||||
* Returned with a status code of MHD_HTTP_NOT_FOUND.
|
||||
*/
|
||||
TALER_EC_BANK_REJECT_NOT_FOUND = 4250,
|
||||
|
||||
/**
|
||||
* Authentication failed for the /reject request.
|
||||
* Returned with a status code of MHD_HTTP_FORBIDDEN.
|
||||
*/
|
||||
TALER_EC_BANK_REJECT_NOT_AUHTORIZED = 4251,
|
||||
|
||||
|
||||
/**
|
||||
* End of error code range.
|
||||
|
@ -88,6 +88,8 @@ TALER_FAKEBANK_make_transfer (struct TALER_FAKEBANK_Handle *h,
|
||||
* to the transfer identifier and remove the transaction from the
|
||||
* list. If the transaction was not recorded, return #GNUNET_SYSERR.
|
||||
*
|
||||
* Rejected transfers do NOT show with "check".
|
||||
*
|
||||
* @param h bank instance
|
||||
* @param want_amount transfer amount desired
|
||||
* @param want_debit account that should have been debited
|
||||
@ -106,6 +108,21 @@ TALER_FAKEBANK_check (struct TALER_FAKEBANK_Handle *h,
|
||||
char **subject);
|
||||
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
|
||||
/**
|
||||
* Stop running the fake bank.
|
||||
*
|
||||
|
@ -83,6 +83,7 @@ struct TALER_WIRE_TransferDetails
|
||||
* the bank for the transaction history.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param ec taler error code
|
||||
* @param dir direction of the transfer
|
||||
* @param row_off identification of the position at which we are querying
|
||||
* @param row_off_size number of bytes in @a row_off
|
||||
@ -91,6 +92,7 @@ struct TALER_WIRE_TransferDetails
|
||||
*/
|
||||
typedef int
|
||||
(*TALER_WIRE_HistoryResultCallback) (void *cls,
|
||||
enum TALER_ErrorCode ec,
|
||||
enum TALER_BANK_Direction dir,
|
||||
const void *row_off,
|
||||
size_t row_off_size,
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2016 GNUnet e.V. & Inria
|
||||
Copyright (C) 2017 Taler Systems SA
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
@ -553,12 +553,14 @@ test_prepare_wire_transfer (void *cls,
|
||||
* @param cls closure with the `struct TALER_WIRE_ExecuteHandle`
|
||||
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
|
||||
* 0 if the bank's reply is bogus (fails to follow the protocol)
|
||||
* @param ec error code from the bank
|
||||
* @param serial_id unique ID of the wire transfer in the bank's records; UINT64_MAX on error
|
||||
* @param json detailed response from the HTTPD, or NULL if reply was not JSON
|
||||
*/
|
||||
static void
|
||||
execute_cb (void *cls,
|
||||
unsigned int http_status,
|
||||
enum TALER_ErrorCode ec,
|
||||
uint64_t serial_id,
|
||||
const json_t *json)
|
||||
{
|
||||
@ -578,13 +580,15 @@ execute_cb (void *cls,
|
||||
}
|
||||
if (NULL != emsg)
|
||||
GNUNET_asprintf (&s,
|
||||
"%u (%s)",
|
||||
"%u/%u (%s)",
|
||||
http_status,
|
||||
(unsigned int) ec,
|
||||
emsg);
|
||||
else
|
||||
GNUNET_asprintf (&s,
|
||||
"%u",
|
||||
http_status);
|
||||
"%u/%u",
|
||||
http_status,
|
||||
(unsigned int) ec);
|
||||
eh->cc (eh->cc_cls,
|
||||
(MHD_HTTP_OK == http_status) ? GNUNET_OK : GNUNET_SYSERR,
|
||||
serial_id,
|
||||
@ -676,6 +680,7 @@ test_execute_wire_transfer (void *cls,
|
||||
char *emsg;
|
||||
const char *json_s;
|
||||
const char *exchange_base_url;
|
||||
char *wire_s;
|
||||
|
||||
if (NULL == tc->ctx)
|
||||
{
|
||||
@ -728,16 +733,19 @@ test_execute_wire_transfer (void *cls,
|
||||
eh = GNUNET_new (struct TALER_WIRE_ExecuteHandle);
|
||||
eh->cc = cc;
|
||||
eh->cc_cls = cc_cls;
|
||||
wire_s = GNUNET_STRINGS_data_to_string_alloc (&bf.wtid,
|
||||
sizeof (bf.wtid));
|
||||
eh->aaih = TALER_BANK_admin_add_incoming (tc->ctx,
|
||||
tc->bank_uri,
|
||||
&tc->auth,
|
||||
exchange_base_url,
|
||||
&bf.wtid,
|
||||
wire_s,
|
||||
&amount,
|
||||
(uint64_t) tc->exchange_account_no,
|
||||
(uint64_t) account_no,
|
||||
&execute_cb,
|
||||
eh);
|
||||
GNUNET_free (wire_s);
|
||||
json_decref (wire);
|
||||
if (NULL == eh->aaih)
|
||||
{
|
||||
@ -803,6 +811,7 @@ struct TALER_WIRE_HistoryHandle
|
||||
* #MHD_HTTP_NO_CONTENT if there are no more results; on success the
|
||||
* last callback is always of this status (even if `abs(num_results)` were
|
||||
* already returned).
|
||||
* @param ec taler error code
|
||||
* @param dir direction of the transfer
|
||||
* @param serial_id monotonically increasing counter corresponding to the transaction
|
||||
* @param details details about the wire transfer
|
||||
@ -811,6 +820,7 @@ struct TALER_WIRE_HistoryHandle
|
||||
static void
|
||||
bhist_cb (void *cls,
|
||||
unsigned int http_status,
|
||||
enum TALER_ErrorCode ec,
|
||||
enum TALER_BANK_Direction dir,
|
||||
uint64_t serial_id,
|
||||
const struct TALER_BANK_TransferDetails *details,
|
||||
@ -852,12 +862,17 @@ bhist_cb (void *cls,
|
||||
sizeof (wd.wtid));
|
||||
wd.wtid_s = details->wire_transfer_subject;
|
||||
}
|
||||
else
|
||||
{
|
||||
wd.wtid_s = NULL;
|
||||
}
|
||||
GNUNET_free (subject);
|
||||
wd.account_details = details->account_details;
|
||||
|
||||
if ( (NULL != whh->hres_cb) &&
|
||||
(GNUNET_OK !=
|
||||
whh->hres_cb (whh->hres_cb_cls,
|
||||
TALER_EC_NONE,
|
||||
dir,
|
||||
&bserial_id,
|
||||
sizeof (bserial_id),
|
||||
@ -868,6 +883,7 @@ bhist_cb (void *cls,
|
||||
case MHD_HTTP_NO_CONTENT:
|
||||
if (NULL != whh->hres_cb)
|
||||
(void) whh->hres_cb (whh->hres_cb_cls,
|
||||
ec,
|
||||
TALER_BANK_DIRECTION_NONE,
|
||||
NULL,
|
||||
0,
|
||||
@ -880,6 +896,7 @@ bhist_cb (void *cls,
|
||||
GNUNET_break (0);
|
||||
if (NULL != whh->hres_cb)
|
||||
(void) whh->hres_cb (whh->hres_cb_cls,
|
||||
ec,
|
||||
TALER_BANK_DIRECTION_NONE,
|
||||
NULL,
|
||||
0,
|
||||
@ -1004,26 +1021,32 @@ struct TALER_WIRE_RejectHandle
|
||||
void *rej_cb_cls;
|
||||
|
||||
/**
|
||||
* Handle to task for timeout of operation.
|
||||
* Handle for the reject operation.
|
||||
*/
|
||||
struct GNUNET_SCHEDULER_Task *timeout_task;
|
||||
struct TALER_BANK_RejectHandle *brh;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Rejection operation failed with timeout, notify callback
|
||||
* and clean up.
|
||||
* Callbacks of this type are used to serve the result of asking
|
||||
* the bank to reject an incoming wire transfer.
|
||||
*
|
||||
* @param cls closure with `struct TALER_WIRE_RejectHandle`
|
||||
* @param cls closure
|
||||
* @param http_status HTTP response code, #MHD_HTTP_NO_CONTENT (204) for successful status request;
|
||||
* #MHD_HTTP_NOT_FOUND if the rowid is unknown;
|
||||
* 0 if the bank's reply is bogus (fails to follow the protocol),
|
||||
* @param ec detailed error code
|
||||
*/
|
||||
static void
|
||||
timeout_reject (void *cls)
|
||||
reject_cb (void *cls,
|
||||
unsigned int http_status,
|
||||
enum TALER_ErrorCode ec)
|
||||
{
|
||||
struct TALER_WIRE_RejectHandle *rh = cls;
|
||||
|
||||
rh->timeout_task = NULL;
|
||||
rh->brh = NULL;
|
||||
rh->rej_cb (rh->rej_cb_cls,
|
||||
TALER_EC_NOT_IMPLEMENTED /* in the future: TALER_EC_TIMEOUT */);
|
||||
ec);
|
||||
GNUNET_free (rh);
|
||||
}
|
||||
|
||||
@ -1052,14 +1075,30 @@ test_reject_transfer (void *cls,
|
||||
TALER_WIRE_RejectTransferCallback rej_cb,
|
||||
void *rej_cb_cls)
|
||||
{
|
||||
struct TestClosure *tc = cls;
|
||||
const uint64_t *rowid_b64 = start_off;
|
||||
struct TALER_WIRE_RejectHandle *rh;
|
||||
|
||||
GNUNET_break (0); /* not implemented, just a stub! */
|
||||
if (sizeof (uint64_t) != start_off_len)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return NULL;
|
||||
}
|
||||
rh = GNUNET_new (struct TALER_WIRE_RejectHandle);
|
||||
rh->rej_cb = rej_cb;
|
||||
rh->rej_cb_cls = rej_cb_cls;
|
||||
rh->timeout_task = GNUNET_SCHEDULER_add_now (&timeout_reject,
|
||||
rh);
|
||||
rh->brh = TALER_BANK_reject (tc->ctx,
|
||||
tc->bank_uri,
|
||||
&tc->auth,
|
||||
(uint64_t) tc->exchange_account_no,
|
||||
GNUNET_ntohll (*rowid_b64),
|
||||
&reject_cb,
|
||||
rh);
|
||||
if (NULL == rh->brh)
|
||||
{
|
||||
GNUNET_free (rh);
|
||||
return NULL;
|
||||
}
|
||||
return rh;
|
||||
}
|
||||
|
||||
@ -1082,7 +1121,8 @@ test_reject_transfer_cancel (void *cls,
|
||||
{
|
||||
void *ret = rh->rej_cb_cls;
|
||||
|
||||
GNUNET_SCHEDULER_cancel (rh->timeout_task);
|
||||
if (NULL != rh->brh)
|
||||
TALER_BANK_reject_cancel (rh->brh);
|
||||
GNUNET_free (rh);
|
||||
return ret;
|
||||
}
|
||||
|
@ -159,6 +159,7 @@ timeout_cb (void *cls)
|
||||
* the bank for the transaction history.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param ec taler status code
|
||||
* @param dir direction of the transfer
|
||||
* @param row_off identification of the position at which we are querying
|
||||
* @param row_off_size number of bytes in @a row_off
|
||||
@ -167,6 +168,7 @@ timeout_cb (void *cls)
|
||||
*/
|
||||
static int
|
||||
history_result_cb (void *cls,
|
||||
enum TALER_ErrorCode ec,
|
||||
enum TALER_BANK_Direction dir,
|
||||
const void *row_off,
|
||||
size_t row_off_size,
|
||||
|
Loading…
Reference in New Issue
Block a user