From a1ecc4a85e1634a0c02ac84f140195040138a254 Mon Sep 17 00:00:00 2001 From: Marcello Stanisci Date: Wed, 25 May 2016 00:13:37 +0200 Subject: adding scaffold for integrating /track/{deposit,wtid} API calls --- src/backend/Makefile.am | 1 + src/backend/merchant.conf | 3 +- src/backend/taler-merchant-httpd.c | 11 ++ src/backend/taler-merchant-httpd_mhd.c | 8 +- src/backend/taler-merchant-httpd_parsing.c | 45 +++++++ src/backend/taler-merchant-httpd_responses.c | 36 +++++ src/backend/taler-merchant-httpd_responses.h | 21 +++ src/backend/taler-merchant-httpd_track.c | 58 +++++++++ src/backend/taler-merchant-httpd_track.h | 41 ++++++ src/include/taler_merchant_service.h | 68 +++++++++- src/lib/Makefile.am | 3 +- src/lib/merchant_api_track.c | 188 +++++++++++++++++++++++++++ src/lib/test_merchant_api.c | 62 ++++++++- 13 files changed, 535 insertions(+), 10 deletions(-) create mode 100644 src/backend/taler-merchant-httpd_track.c create mode 100644 src/backend/taler-merchant-httpd_track.h create mode 100644 src/lib/merchant_api_track.c (limited to 'src') diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index 7436eaa2..877fb269 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -21,6 +21,7 @@ taler_merchant_httpd_SOURCES = \ taler-merchant-httpd_exchanges.c taler-merchant-httpd_exchanges.h \ taler-merchant-httpd_contract.c taler-merchant-httpd_contract.h \ taler-merchant-httpd_pay.c taler-merchant-httpd_pay.h \ + taler-merchant-httpd_track.c taler-merchant-httpd_track.h \ taler-merchant-httpd_util.c taler-merchant-httpd_util.h taler_merchant_httpd_LDADD = \ diff --git a/src/backend/merchant.conf b/src/backend/merchant.conf index eee0dfef..3f0b1e9d 100644 --- a/src/backend/merchant.conf +++ b/src/backend/merchant.conf @@ -20,10 +20,11 @@ KEYFILE = ${TALER_DATA_HOME}/merchant/merchant.priv DB = postgres # Which wireformat does this merchant use? (test/sepa/etc.) -# WIREFORMAT = "test" +WIREFORMAT = test # Determines which wire plugin will be used. We currently only # support one wire plugin at a time! +EDATE = 3 week # Configuration for postgres database. [merchantdb-postgres] diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c index c02d5610..c286ed81 100644 --- a/src/backend/taler-merchant-httpd.c +++ b/src/backend/taler-merchant-httpd.c @@ -37,6 +37,7 @@ #include "taler-merchant-httpd_exchanges.h" #include "taler-merchant-httpd_contract.h" #include "taler-merchant-httpd_pay.h" +#include "taler-merchant-httpd_track.h" #include "taler-merchant-httpd_util.h" @@ -193,6 +194,12 @@ url_handler (void *cls, { "/pay", NULL, "text/plain", "Only POST is allowed", 0, &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + { "/track/deposit", MHD_HTTP_METHOD_GET, "application/json", + NULL, 0, + &MH_handler_track_deposit, MHD_HTTP_OK}, + { "/track/deposit", NULL, "text/plain", + "Only GET is allowed", 0, + &TMH_MHD_handler_static_response, MHD_HTTP_OK}, {NULL, NULL, NULL, NULL, 0, 0 } }; @@ -483,6 +490,10 @@ run (void *cls, result = GNUNET_SYSERR; GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL); + GNUNET_assert (GNUNET_OK == + GNUNET_log_setup ("taler-merchant-httpd", + "INFO", + NULL)); if (GNUNET_SYSERR == TMH_EXCHANGES_init (config)) { diff --git a/src/backend/taler-merchant-httpd_mhd.c b/src/backend/taler-merchant-httpd_mhd.c index 23a47707..34fdb113 100644 --- a/src/backend/taler-merchant-httpd_mhd.c +++ b/src/backend/taler-merchant-httpd_mhd.c @@ -41,10 +41,10 @@ */ int TMH_MHD_handler_static_response (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) { struct MHD_Response *response; int ret; diff --git a/src/backend/taler-merchant-httpd_parsing.c b/src/backend/taler-merchant-httpd_parsing.c index 9b0a3863..18bccb5d 100644 --- a/src/backend/taler-merchant-httpd_parsing.c +++ b/src/backend/taler-merchant-httpd_parsing.c @@ -313,4 +313,49 @@ TMH_PARSE_json_data (struct MHD_Connection *connection, } + +/** + * Extract base32crockford encoded data from request. + * + * Queues an error response to the connection if the parameter is + * missing or invalid. + * + * @param connection the MHD connection + * @param param_name the name of the parameter with the key + * @param[out] out_data pointer to store the result + * @param out_size expected size of data + * @return + * #GNUNET_YES if the the argument is present + * #GNUNET_NO if the argument is absent or malformed + * #GNUNET_SYSERR on internal error (error response could not be sent) + */ +int +TMH_PARSE_mhd_request_arg_data (struct MHD_Connection *connection, + const char *param_name, + void *out_data, + size_t out_size) +{ + const char *str; + + str = MHD_lookup_connection_value (connection, + MHD_GET_ARGUMENT_KIND, + param_name); + if (NULL == str) + { + return (MHD_NO == + TMH_RESPONSE_reply_arg_missing (connection, param_name)) + ? GNUNET_SYSERR : GNUNET_NO; + } + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data (str, + strlen (str), + out_data, + out_size)) + return (MHD_NO == + TMH_RESPONSE_reply_arg_invalid (connection, param_name)) + ? GNUNET_SYSERR : GNUNET_NO; + return GNUNET_OK; +} + + /* end of taler-merchant-httpd_parsing.c */ diff --git a/src/backend/taler-merchant-httpd_responses.c b/src/backend/taler-merchant-httpd_responses.c index 0f066ba9..d63eacb5 100644 --- a/src/backend/taler-merchant-httpd_responses.c +++ b/src/backend/taler-merchant-httpd_responses.c @@ -289,5 +289,41 @@ TMH_RESPONSE_make_external_error (const char *hint) "hint", hint); } +/** + * Send a response indicating a missing argument. + * + * @param connection the MHD connection to use + * @param param_name the parameter that is missing + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection, + const char *param_name) +{ + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{ s:s, s:s}", + "error", "missing parameter", + "parameter", param_name); +} + + +/** + * Send a response indicating an invalid argument. + * + * @param connection the MHD connection to use + * @param param_name the parameter that is invalid + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection, + const char *param_name) +{ + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:s}", + "error", "invalid parameter", + "parameter", param_name); +} /* end of taler-exchange-httpd_responses.c */ diff --git a/src/backend/taler-merchant-httpd_responses.h b/src/backend/taler-merchant-httpd_responses.h index abf90949..7314e0bb 100644 --- a/src/backend/taler-merchant-httpd_responses.h +++ b/src/backend/taler-merchant-httpd_responses.h @@ -157,4 +157,25 @@ TMH_RESPONSE_reply_request_too_large (struct MHD_Connection *connection); void TMH_RESPONSE_add_global_headers (struct MHD_Response *response); +/** + * Send a response indicating a missing argument. + * + * @param connection the MHD connection to use + * @param param_name the parameter that is missing + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection, + const char *param_name); + +/** + * Send a response indicating an invalid argument. + * + * @param connection the MHD connection to use + * @param param_name the parameter that is invalid + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection, + const char *param_name); #endif diff --git a/src/backend/taler-merchant-httpd_track.c b/src/backend/taler-merchant-httpd_track.c new file mode 100644 index 00000000..b17a40e3 --- /dev/null +++ b/src/backend/taler-merchant-httpd_track.c @@ -0,0 +1,58 @@ +/* + This file is part of TALER + (C) 2014, 2015, 2016 INRIA + + 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 + 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, If not, see +*/ +/** + * @file backend/taler-merchant-httpd_track.c + * @brief implement API for tracking deposits and wire transfers + * @author Marcello Stanisci + */ +#include "platform.h" +#include +#include +#include +#include "taler-merchant-httpd.h" +#include "taler-merchant-httpd_parsing.h" +#include "taler-merchant-httpd_auditors.h" +#include "taler-merchant-httpd_exchanges.h" +#include "taler-merchant-httpd_responses.h" + + +extern char *TMH_merchant_currency_string; + + +/** + * Manages a /track/deposit call, thus it calls the /wire/deposit + * offered by the exchange in order to return the set of deposits + * (of coins) associated with a given wire transfer + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +MH_handler_track_deposit (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "serving /track/deposit\n"); + return MHD_YES; +} + +/* end of taler-merchant-httpd_contract.c */ diff --git a/src/backend/taler-merchant-httpd_track.h b/src/backend/taler-merchant-httpd_track.h new file mode 100644 index 00000000..51dde1b9 --- /dev/null +++ b/src/backend/taler-merchant-httpd_track.h @@ -0,0 +1,41 @@ +/* + This file is part of TALER + (C) 2014, 2015 GNUnet e.V. + + 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, If not, see +*/ +/** + * @file backend/taler-merchant-httpd_track.h + * @brief headers for /track/{deposit,wtid} handler + * @author Marcello Stanisci + */ +#include +#include "taler-merchant-httpd.h" + +/** + * Manages a /track/deposit call, thus it calls the /wire/deposit + * offered by the exchange in order to return the set of deposits + * (of coins) associated with a given wire transfer + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +MH_handler_track_deposit (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size); diff --git a/src/include/taler_merchant_service.h b/src/include/taler_merchant_service.h index 52070860..540261b9 100644 --- a/src/include/taler_merchant_service.h +++ b/src/include/taler_merchant_service.h @@ -17,6 +17,7 @@ * @file include/taler_merchant_service.h * @brief C interface of libtalermerchant, a C library to use merchant's HTTP API * @author Christian Grothoff + * @author Marcello Stanisci */ #ifndef _TALER_MERCHANT_SERVICE_H #define _TALER_MERCHANT_SERVICE_H @@ -25,6 +26,49 @@ #include #include +/* ********************* /track/deposit *********************** */ + +/** + * @brief Handle to a /contract operation at a merchant's backend. + */ +struct TALER_MERCHANT_TrackDepositOperation; + +/** + * Callbacks of this type are used to work the result of submitting a /track/deposit request to a merchant + */ +typedef void +(*TALER_MERCHANT_TrackDepositCallback) (void *cls, + unsigned int http_status, + const json_t *obj); + +/** + * Request backend to return deposits associated with a given wtid. + * + * @param ctx execution context + * @param backend_uri URI of the backend (having /track/deposit appended) + * @param wtid base32 string indicating a wtid + * @param exchange base URL of the exchange in charge of returning the wanted information + * @param trackdeposit_cb the callback to call when a reply for this request is available + * @param trackdeposit_cb_cls closure for @a contract_cb + * @return a handle for this request + */ +struct TALER_MERCHANT_TrackDepositOperation * +TALER_MERCHANT_track_deposit (struct GNUNET_CURL_Context *ctx, + const char *backend_uri, + const char *wtid, + const char *exchange_uri, + TALER_MERCHANT_TrackDepositCallback trackdeposit_cb, + void *trackdeposit_cb_cls); + +/** + * Cancel a /track/deposit request. This function cannot be used + * on a request handle if a response is already served for it. + * + * @param co the deposit's tracking operation + */ +void +TALER_MERCHANT_track_deposit_cancel (struct TALER_MERCHANT_TrackDepositOperation *tdo); + /* ********************* /contract *********************** */ @@ -196,8 +240,8 @@ TALER_MERCHANT_pay_wallet (struct GNUNET_CURL_Context *ctx, /** - * Information we need from the frontend when forwarding - * a payment to the backend. + * Information we need from the frontend (ok, the frontend sends just JSON) + * when forwarding a payment to the backend. */ struct TALER_MERCHANT_PaidCoin { @@ -295,4 +339,24 @@ void TALER_MERCHANT_pay_cancel (struct TALER_MERCHANT_Pay *ph); + +/** + * Request backend to return deposits associated with a given wtid. + * + * @param ctx execution context + * @param backend_uri URI of the backend + * @param wtid base32 string indicating a wtid + * @param exchange_uri base URL of the exchange in charge of returning the wanted information + * @param trackdeposit_cb the callback to call when a reply for this request is available + * @param trackdeposit_cb_cls closure for @a contract_cb + * @return a handle for this request + */ +struct TALER_MERCHANT_TrackDepositOperation * +TALER_MERCHANT_track_deposit (struct GNUNET_CURL_Context *ctx, + const char *backend_uri, + const char *wtid, + const char *exchange_uri, + TALER_MERCHANT_TrackDepositCallback trackdeposit_cb, + void *trackdeposit_cb_cls); + #endif /* _TALER_MERCHANT_SERVICE_H */ diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 467c6a70..29a6f89d 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -15,7 +15,8 @@ libtalermerchant_la_LDFLAGS = \ libtalermerchant_la_SOURCES = \ merchant_api_contract.c \ - merchant_api_pay.c + merchant_api_pay.c \ + merchant_api_track.c libtalermerchant_la_LIBADD = \ -ltalerexchange \ diff --git a/src/lib/merchant_api_track.c b/src/lib/merchant_api_track.c new file mode 100644 index 00000000..118da638 --- /dev/null +++ b/src/lib/merchant_api_track.c @@ -0,0 +1,188 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015, 2016 GNUnet e.V. and INRIA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 2.1, 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along with + TALER; see the file COPYING.LGPL. If not, If not, see + +*/ +/** + * @file lib/merchant_api_contract.c + * @brief Implementation of the /track/deposit and /track/wtid request of the + * merchant's HTTP API + * @author Marcello Stanisci + */ +#include "platform.h" +#include +#include +#include /* just for HTTP status codes */ +#include +#include +#include "taler_merchant_service.h" +#include +#include + + +/** + * @brief A Contract Operation Handle + */ +struct TALER_MERCHANT_TrackDepositOperation +{ + + /** + * The url for this request. + */ + char *url; + + /** + * base32 identifier being the 'witd' parameter required by the + * exchange + */ + char *wtid; + + /** + * Handle for the request. + */ + struct GNUNET_CURL_Job *job; + + /** + * Function to call with the result. + */ + TALER_MERCHANT_TrackDepositCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; + + /** + * Reference to the execution context. + */ + struct GNUNET_CURL_Context *ctx; +}; + + +/** + * Function called when we're done processing the + * HTTP /track/deposit request. + * + * @param cls the `struct TALER_MERCHANT_TrackDepositOperation` + * @param response_code HTTP response code, 0 on error + * @param json response body, NULL if not in JSON + */ +static void +handle_trackdeposit_finished (void *cls, + long response_code, + const json_t *json) // body +{ + struct TALER_MERCHANT_TrackDepositOperation *tdo = cls; + + tdo->job = NULL; + switch (response_code) + { + case 0: + break; + case MHD_HTTP_OK: + { + /* Work out argument for external callback from the body .. */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "200 returned from /track/deposit"); + } + break; + case MHD_HTTP_NOT_FOUND: + /* Nothing really to verify, this should never + happen, we should pass the JSON reply to the application */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "track deposit URI not found"); + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* Server had an internal issue; we should retry, but this API + leaves this to the application */ + break; + default: + /* unexpected response code */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u\n", + (unsigned int) response_code); + GNUNET_break (0); + response_code = 0; + break; + } + /* FIXME figure out wich parameters ought to be passed back */ + tdo->cb (tdo->cb_cls, + response_code, + json); +} + + +/** + * Request backend to return deposits associated with a given wtid. + * + * @param ctx execution context + * @param backend_uri URI of the backend (having /track/deposit appended) + * @param wtid base32 string indicating a wtid + * @param exchange base URL of the exchange in charge of returning the wanted information + * @param trackdeposit_cb the callback to call when a reply for this request is available + * @param trackdeposit_cb_cls closure for @a contract_cb + * @return a handle for this request + */ +struct TALER_MERCHANT_TrackDepositOperation * +TALER_MERCHANT_track_deposit (struct GNUNET_CURL_Context *ctx, + const char *backend_uri, + const char *wtid, + const char *exchange_uri, + TALER_MERCHANT_TrackDepositCallback trackdeposit_cb, + void *trackdeposit_cb_cls) +{ + struct TALER_MERCHANT_TrackDepositOperation *tdo; + CURL *eh; + + tdo = GNUNET_new (struct TALER_MERCHANT_TrackDepositOperation); + tdo->ctx = ctx; + tdo->cb = trackdeposit_cb; + tdo->cb_cls = trackdeposit_cb_cls; + /* TO BE FREED SOMEWHERE. GOTTEN WITH /track/deposit ALREADY APPENDED */ + GNUNET_asprintf (&tdo->url, + "%s?wtid=%s&exchange=%s", + backend_uri, + wtid, + exchange_uri); + eh = curl_easy_init (); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_URL, + tdo->url)); + tdo->job = GNUNET_CURL_job_add (ctx, + eh, + GNUNET_YES, + &handle_trackdeposit_finished, + tdo); + return tdo; +} + +/** + * Cancel a /track/deposit request. This function cannot be used + * on a request handle if a response is already served for it. + * + * @param co the deposit's tracking operation + */ +void +TALER_MERCHANT_track_deposit_cancel (struct TALER_MERCHANT_TrackDepositOperation *tdo) +{ + if (NULL != tdo->job) + { + GNUNET_CURL_job_cancel (tdo->job); + tdo->job = NULL; + } + GNUNET_free (tdo->url); + GNUNET_free (tdo->wtid); + GNUNET_free (tdo); +} + +/* end of merchant_api_track.c */ diff --git a/src/lib/test_merchant_api.c b/src/lib/test_merchant_api.c index 360a6924..a9081bae 100644 --- a/src/lib/test_merchant_api.c +++ b/src/lib/test_merchant_api.c @@ -104,7 +104,12 @@ enum OpCode /** * Pay with coins. */ - OC_PAY + OC_PAY, + + /** + * Retrieve deposit permissions for a given wire transfer + */ + OC_TRACK_DEPOSIT }; @@ -370,6 +375,20 @@ struct Command } pay; + struct { + + /** + * Wire transfer ID whose deposit permissions are to be retrieved + */ + char *wtid; + + /** + * Handle to a /track/deposit operation + */ + struct TALER_MERCHANT_TrackDepositOperation *tdo; + + } track_deposit; + } details; }; @@ -813,6 +832,21 @@ pay_cb (void *cls, is); } +/** + * Callback for a /track/deposit operation + * + * @param cls closure for this function + * @param http_status HTTP response code returned by the server + * @param obj server response's body + */ +static void +track_deposit_cb (void *cls, + unsigned int http_status, + const json_t *obj) +{ + return; +} + /** * Find denomination key matching the given amount. @@ -1194,6 +1228,14 @@ interpreter_run (void *cls) return; } return; + case OC_TRACK_DEPOSIT: + TALER_MERCHANT_track_deposit (ctx, + MERCHANT_URI "/track/deposit", + cmd->details.track_deposit.wtid, + EXCHANGE_URI, + track_deposit_cb, + is); + return; default: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unknown instruction %d at %u (%s)\n", @@ -1318,9 +1360,17 @@ do_shutdown (void *cls) cmd->details.pay.ph = NULL; } break; + case OC_TRACK_DEPOSIT: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shutting down /track/deposit\n"); + if (NULL != cmd->details.track_deposit.tdo) + { + TALER_MERCHANT_track_deposit_cancel (cmd->details.track_deposit.tdo); + cmd->details.track_deposit.tdo = NULL; + } + break; default: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unknown instruction %d at %u (%s)\n", + "Shutdown: unknown instruction %d at %u (%s)\n", cmd->oc, i, cmd->label); @@ -1398,6 +1448,14 @@ run (void *cls) struct InterpreterState *is; static struct Command commands[] = { + + { .oc = OC_TRACK_DEPOSIT, + .label = "track-deposit-1", + .expected_response_code = MHD_HTTP_OK, + .details.track_deposit.wtid = "TESTWTID"}, + + { .oc = OC_END }, + /* Fill reserve with EUR:5.01, as withdraw fee is 1 ct per config */ { .oc = OC_ADMIN_ADD_INCOMING, .label = "create-reserve-1", -- cgit v1.2.3