diff options
author | Christian Grothoff <christian@grothoff.org> | 2020-04-27 04:53:17 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2020-04-27 04:53:17 +0200 |
commit | 20853863335ee4cd6a43044bfa1c8b38361cbc1f (patch) | |
tree | bb9edca91007d98f93d6ef1439e6d038fa7533cd /src/backend/taler-merchant-httpd_private-post-reserves-ID-authorize-tip.c | |
parent | 68c440b0eb385ad80dec73843e021039b91b913c (diff) |
rename fest to match new structure
Diffstat (limited to 'src/backend/taler-merchant-httpd_private-post-reserves-ID-authorize-tip.c')
-rw-r--r-- | src/backend/taler-merchant-httpd_private-post-reserves-ID-authorize-tip.c | 306 |
1 files changed, 306 insertions, 0 deletions
diff --git a/src/backend/taler-merchant-httpd_private-post-reserves-ID-authorize-tip.c b/src/backend/taler-merchant-httpd_private-post-reserves-ID-authorize-tip.c new file mode 100644 index 00000000..569cf0ab --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-post-reserves-ID-authorize-tip.c @@ -0,0 +1,306 @@ +/* + This file is part of TALER + (C) 2014-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 + 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 backend/taler-merchant-httpd_tip-authorize.c + * @brief implement API for authorizing tips to be paid to visitors + * @author Christian Grothoff + */ +#include "platform.h" +#include <jansson.h> +#include <taler/taler_util.h> +#include <taler/taler_json_lib.h> +#include "taler-merchant-httpd.h" +#include "taler-merchant-httpd_mhd.h" +#include "taler-merchant-httpd_exchanges.h" +#include "taler-merchant-httpd_tip-authorize.h" +#include "taler-merchant-httpd_tip-reserve-helper.h" + + +struct TipAuthContext +{ + /** + * This field MUST be first for handle_mhd_completion_callback() to work + * when it treats this struct as a `struct TM_HandlerContext`. + */ + struct TM_HandlerContext hc; + + /** + * Placeholder for #TALER_MHD_parse_post_json() to keep its internal state. + */ + void *json_parse_context; + + /** + * Justification to use. + */ + const char *justification; + + /** + * JSON request received. + */ + json_t *root; + + /** + * Context for checking the tipping reserve's status. + */ + struct TMH_CheckTipReserve ctr; + + /** + * Tip amount requested. + */ + struct TALER_Amount amount; + + /** + * Flag set to #GNUNET_YES when we have tried /reserve/status of the + * tipping reserve already. + */ + int checked_status; + + /** + * Flag set to #GNUNET_YES when we have parsed the incoming JSON already. + */ + int parsed_json; + +}; + + +/** + * Custom cleanup routine for a `struct TipAuthContext`. + * + * @param hc the `struct TMH_JsonParseContext` to clean up. + */ +static void +cleanup_tac (struct TM_HandlerContext *hc) +{ + struct TipAuthContext *tac = (struct TipAuthContext *) hc; + + if (NULL != tac->root) + { + json_decref (tac->root); + tac->root = NULL; + } + TMH_check_tip_reserve_cleanup (&tac->ctr); + TALER_MHD_parse_post_cleanup_callback (tac->json_parse_context); + GNUNET_free (tac); +} + + +/** + * Handle a "/tip-authorize" request. + * + * @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 + * @param mi merchant backend instance, never NULL + * @return MHD result code + */ +MHD_RESULT +MH_handler_tip_authorize (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size, + struct MerchantInstance *mi) +{ + struct TipAuthContext *tac; + enum GNUNET_GenericReturnValue res; + enum TALER_ErrorCode ec; + struct GNUNET_TIME_Absolute expiration; + struct GNUNET_HashCode tip_id; + json_t *extra; + + if (NULL == *connection_cls) + { + tac = GNUNET_new (struct TipAuthContext); + tac->hc.cc = &cleanup_tac; + tac->ctr.connection = connection; + *connection_cls = tac; + } + else + { + tac = *connection_cls; + } + if (NULL != tac->ctr.response) + { + MHD_RESULT ret; + + ret = MHD_queue_response (connection, + tac->ctr.response_code, + tac->ctr.response); + MHD_destroy_response (tac->ctr.response); + tac->ctr.response = NULL; + return ret; + } + if (GNUNET_NO == tac->parsed_json) + { + struct GNUNET_JSON_Specification spec[] = { + TALER_JSON_spec_amount ("amount", &tac->amount), + GNUNET_JSON_spec_string ("justification", &tac->justification), + GNUNET_JSON_spec_end () + }; + + res = TALER_MHD_parse_post_json (connection, + &tac->json_parse_context, + upload_data, + upload_data_size, + &tac->root); + if (GNUNET_SYSERR == res) + return MHD_NO; + /* the POST's body has to be further fetched */ + if ( (GNUNET_NO == res) || + (NULL == tac->root) ) + return MHD_YES; + + res = TALER_MHD_parse_json_data (connection, + tac->root, + spec); + if (GNUNET_YES != res) + { + GNUNET_break_op (0); + return (GNUNET_NO == res) ? MHD_YES : MHD_NO; + } + tac->parsed_json = GNUNET_YES; + } + + if (NULL == mi->tip_exchange) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Instance `%s' not configured for tipping\n", + mi->id); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_PRECONDITION_FAILED, + TALER_EC_TIP_AUTHORIZE_INSTANCE_DOES_NOT_TIP, + "exchange for tipping not configured for the instance"); + } + tac->ctr.reserve_priv = mi->tip_reserve; + extra = json_object_get (tac->root, "extra"); + if (NULL == extra) + extra = json_object (); + else + json_incref (extra); + + + db->preflight (db->cls); + ec = db->authorize_tip_TR (db->cls, + tac->justification, + extra, + &tac->amount, + &mi->tip_reserve, + mi->tip_exchange, + &expiration, + &tip_id); + json_decref (extra); + /* If we have insufficient funds according to OUR database, + check with exchange to see if the reserve has been topped up + in the meantime (or if tips were not withdrawn yet). */ + if ( (TALER_EC_TIP_AUTHORIZE_INSUFFICIENT_FUNDS == ec) && + (GNUNET_NO == tac->checked_status) ) + { + tac->checked_status = GNUNET_YES; + tac->ctr.none_authorized = GNUNET_YES; + TMH_check_tip_reserve (&tac->ctr, + mi->tip_exchange); + return MHD_YES; + } + + /* handle irrecoverable errors */ + if (TALER_EC_NONE != ec) + { + unsigned int rc; + const char *msg; + + switch (ec) + { + case TALER_EC_TIP_AUTHORIZE_INSUFFICIENT_FUNDS: + rc = MHD_HTTP_PRECONDITION_FAILED; + msg = "Failed to approve tip: merchant has insufficient tipping funds"; + break; + case TALER_EC_TIP_AUTHORIZE_RESERVE_EXPIRED: + msg = "Failed to approve tip: merchant's tipping reserve expired"; + rc = MHD_HTTP_PRECONDITION_FAILED; + break; + case TALER_EC_TIP_AUTHORIZE_RESERVE_UNKNOWN: + msg = "Failed to approve tip: merchant's tipping reserve does not exist"; + rc = MHD_HTTP_SERVICE_UNAVAILABLE; + break; + default: + rc = MHD_HTTP_INTERNAL_SERVER_ERROR; + msg = "Failed to approve tip: internal server error"; + break; + } + + return TALER_MHD_reply_with_error (connection, + rc, + ec, + msg); + } + + /* generate success response */ + { + char *taler_tip_uri; + const char *host; + const char *forwarded_host; + const char *uri_path; + const char *uri_instance_id; + struct GNUNET_CRYPTO_HashAsciiEncoded hash_enc; + + host = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, "Host"); + forwarded_host = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, + "X-Forwarded-Host"); + + uri_path = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, + "X-Forwarded-Prefix"); + if (NULL == uri_path) + uri_path = "-"; + + if (NULL != forwarded_host) + host = forwarded_host; + + if (NULL == host) + { + /* Should never happen, at last the host header should be defined */ + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_INTERNAL_INVARIANT_FAILURE, + "unable to identify backend host"); + } + + if (0 == strcmp (mi->id, "default")) + uri_instance_id = "-"; + else + uri_instance_id = mi->id; + + GNUNET_CRYPTO_hash_to_enc (&tip_id, &hash_enc); + + GNUNET_assert (0 < GNUNET_asprintf (&taler_tip_uri, + "taler://tip/%s/%s/%s/%s", + host, + uri_path, + uri_instance_id, + hash_enc.encoding)); + + return TALER_MHD_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:s, s:s}", + "taler_tip_uri", taler_tip_uri, + "tip_id", hash_enc.encoding); + } +} + + +/* end of taler-merchant-httpd_tip-authorize.c */ |