/* This file is part of TALER Copyright (C) 2014-2018 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 */ /** * @file taler-merchant-httpd.h * @brief HTTP serving layer mainly intended to communicate with the frontend * @author Marcello Stanisci */ #ifndef TALER_MERCHANT_HTTPD_H #define TALER_MERCHANT_HTTPD_H #include "platform.h" #include "taler_merchantdb_lib.h" #include #include /** * Shorthand for exit jumps. */ #define EXITIF(cond) \ do { \ if (cond) { GNUNET_break (0); goto EXITIF_exit; } \ } while (0) /** * Supported wire method. Kept in a DLL. */ struct TMH_WireMethod { /** * Next entry in DLL. */ struct TMH_WireMethod *next; /** * Previous entry in DLL. */ struct TMH_WireMethod *prev; /** * Which wire method / payment target identifier is @e j_wire using? */ char *wire_method; /** * Wire details for this instance */ struct json_t *j_wire; /** * Hash of our wire format details as given in #j_wire. */ struct GNUNET_HashCode h_wire; /** * Is this wire method active (should it be included in new contracts)? */ bool active; /** * Are we currently in a transaction to delete this account? */ bool deleting; /** * Are we currently in a transaction to enable this account? */ bool enabling; }; /** * A pending GET /orders request that is in long polling mode. */ struct TMH_PendingOrder; /** * Information that defines a merchant "instance". That way, a single * backend can account for several merchants, as used to do in donation * shops */ struct TMH_MerchantInstance { /** * Next entry in DLL. */ struct TMH_WireMethod *wm_head; /** * Previous entry in DLL. */ struct TMH_WireMethod *wm_tail; /** * Head of DLL of long-polling GET /orders requests of this instance. */ struct TMH_PendingOrder *po_head; /** * Tail of DLL of long-polling GET /orders requests of this instance. */ struct TMH_PendingOrder *po_tail; /** * Merchant's private key. */ struct TALER_MerchantPrivateKeyP merchant_priv; /** * Merchant's public key */ struct TALER_MerchantPublicKeyP merchant_pub; /** * General settings for an instance. */ struct TALER_MERCHANTDB_InstanceSettings settings; /** * General settings for an instance. */ struct TALER_MERCHANTDB_InstanceAuthSettings auth; /** * Reference counter on this structure. Only destroyed if the * counter hits zero. */ unsigned int rc; }; /** * @brief Struct describing an URL and the handler for it. * * The overall URL is always @e url_prefix, optionally followed by the * id_segment, which is optionally followed by the @e url_suffix. It is NOT * allowed for the @e url_prefix to be directly followed by the @e url_suffix. * A @e url_suffix SHOULD only be used with a @e method of #MHD_HTTP_METHOD_POST. */ struct TMH_RequestHandler; /** * This information is stored in the "connection_cls" of MHD for * every request that we process. * Individual handlers can evaluate its members and * are allowed to update @e cc and @e ctx to store and clean up * handler-specific data. */ struct TMH_HandlerContext; /** * @brief Struct describing an URL and the handler for it. * * The overall URL is always @e url_prefix, optionally followed by the * id_segment, which is optionally followed by the @e url_suffix. It is NOT * allowed for the @e url_prefix to be directly followed by the @e url_suffix. * A @e url_suffix SHOULD only be used with a @e method of #MHD_HTTP_METHOD_POST. */ struct TMH_RequestHandler { /** * URL prefix the handler is for, includes the '/', * so "/orders" or "/products". Does *not* include * "/private", that is controlled by the array in which * the handler is defined. Must not contain any * '/' except for the leading '/'. */ const char *url_prefix; /** * Does this request include an identifier segment * (product_id, reserve_pub, order_id, tip_id) in the * second segment? */ bool have_id_segment; /** * Does this request handler work without an instance? */ bool skip_instance; /** * URL suffix the handler is for, excludes the '/', * so "pay" or "claim", not "/pay". */ const char *url_suffix; /** * Method the handler is for, NULL for "all". */ const char *method; /** * Mime type to use in reply (hint, can be NULL). */ const char *mime_type; /** * Raw data for the @e handler (can be NULL). */ const void *data; /** * Number of bytes in @e data. */ size_t data_size; /** * Maximum upload size allowed for this handler. * 0 for DEFAULT_MAX_UPLOAD_SIZE */ size_t max_upload; /** * Handler to be called for this URL/METHOD combination. * * @param rh this struct * @param connection the MHD connection to handle * @param[in,out] hc context with further information about the request * @return MHD result code */ MHD_RESULT (*handler)(const struct TMH_RequestHandler *rh, struct MHD_Connection *connection, struct TMH_HandlerContext *hc); /** * Default response code to use. */ unsigned int response_code; }; /** * Signature of a function used to clean up the context * we keep in the "connection_cls" of MHD when handling * a request. * * @param ctxt the context to clean up. */ typedef void (*TMH_ContextCleanup)(void *ctx); /** * This information is stored in the "connection_cls" of MHD for * every request that we process. * Individual handlers can evaluate its members and * are allowed to update @e cc and @e ctx to store and clean up * handler-specific data. */ struct TMH_HandlerContext { /** * Function to execute the handler-specific cleanup of the * (request-specific) context in @e ctx. */ TMH_ContextCleanup cc; /** * Client-specific context we keep. Passed to @e cc. */ void *ctx; /** * Which request handler is handling this request? */ const struct TMH_RequestHandler *rh; /** * Which instance is handling this request? */ struct TMH_MerchantInstance *instance; /** * Asynchronous request context id. */ struct GNUNET_AsyncScopeId async_scope_id; /** * Our original URL, for logging. */ const char *url; /** * Infix part of @a url. */ char *infix; /** * JSON body that was uploaded, NULL if @e has_body is false. */ json_t *request_body; /** * Placeholder for #TALER_MHD_parse_post_json() to keep its internal state. * Used when we parse the POSTed data. */ void *json_parse_context; /** * Total size of the upload so far. */ uint64_t total_upload; /** * Set to true if this is an #MHD_HTTP_METHOD_POST or #MHD_HTTP_METHOD_PATCH request. * (In principle #MHD_HTTP_METHOD_PUT may also belong, but we do not have PUTs * in the API today, so we do not test for PUT.) */ bool has_body; }; /** * Entry in a #resume_timeout_heap. */ struct TMH_SuspendedConnection { /** * Which connection was suspended. */ struct MHD_Connection *con; /** * Associated heap node. Used internally by #TMH_long_poll_suspend() * and TMH_long_poll_resume(). */ struct GNUNET_CONTAINER_HeapNode *hn; /** * Key of this entry in the #payment_trigger_map. Used internally by * #TMH_long_poll_suspend() and TMH_long_poll_resume(). */ struct GNUNET_HashCode key; /** * Optional session/fulfillment URI-based key * of this entry in the #payment_trigger_map. Used internally by * TMH_long_poll_resume2(). */ struct GNUNET_HashCode key2; /** * At what time does this request expire? If set in the future, we * may wait this long for a payment to arrive before responding. */ struct GNUNET_TIME_Absolute long_poll_timeout; /** * Minimum refund amount to be exceeded (exclusive this value!) for resume. */ struct TALER_Amount refund_expected; /** * true if we are waiting for a refund. */ bool awaiting_refund; /** * Whether we're waiting for the refunds to be obtained. */ bool awaiting_refund_obtained; /** * True if @a key2 is set. */ bool has_key2; }; /** * Which currency do we use? */ extern char *TMH_currency; /** * Inform the auditor for all deposit confirmations (global option) */ extern int TMH_force_audit; /** * Handle to the database backend. */ extern struct TALER_MERCHANTDB_Plugin *TMH_db; /** * Hashmap pointing at merchant instances by 'id'. An 'id' is * just a string that identifies a merchant instance. When a frontend * needs to specify an instance to the backend, it does so by 'id' */ extern struct GNUNET_CONTAINER_MultiHashMap *TMH_by_id_map; /** * How long do we need to keep information on paid contracts on file for tax * or other legal reasons? Used to block deletions for younger transaction * data. */ extern struct GNUNET_TIME_Relative TMH_legal_expiration; /** * Initial authorization token. */ extern char *TMH_default_auth; /** * Kick MHD to run now, to be called after MHD_resume_connection(). * Basically, we need to explicitly resume MHD's event loop whenever * we made progress serving a request. This function re-schedules * the task processing MHD's activities to run immediately. */ void TMH_trigger_daemon (void); /** * Suspend connection from @a sc until payment has been received. * * @param order_id the order that we are waiting on * @param session_id session ID of the requester * @param fulfillment_url fulfillment URL of the contract * @param mi the merchant instance we are waiting on * @param sc connection to suspend * @param min_refund refund amount we are waiting on to be exceeded before resuming, * NULL if we are not waiting for refunds */ void TMH_long_poll_suspend (const char *order_id, const char *session_id, const char *fulfillment_url, const struct TMH_MerchantInstance *mi, struct TMH_SuspendedConnection *sc, const struct TALER_Amount *min_refund); /** * Find out if we have any clients long-polling for @a order_id to be * confirmed at merchant @a mpub, and if so, tell them to resume. * * @param order_id the order that was paid or refunded * @param mi the merchant instance where the payment or refund happened * @param refund_amount refunded amount, if the trigger was a refund, otherwise NULL * @param obtained if true, the wallet has obtained the refunds for the order */ void TMH_long_poll_resume (const char *order_id, const struct TMH_MerchantInstance *mi, const struct TALER_Amount *refund_amount, bool obtained); /** * Find out if we have any clients long-polling for @a order_id to be * confirmed at merchant @a mpub, and if so, tell them to resume. * * @param session_id the session for which @a fulfillment_url became paid * @param fulfillment_url fullfillment URL of which an order was paid */ void TMH_long_poll_resume2 (const char *session_id, const char *fulfillment_url); /** * Decrement reference counter of @a mi, and free if it hits zero. * * @param[in,out] mi merchant instance to update and possibly free */ void TMH_instance_decref (struct TMH_MerchantInstance *mi); /** * Add instance definition to our active set of instances. * * @param[in,out] mi merchant instance details to define * @return #GNUNET_OK on success, #GNUNET_NO if the same ID is in use already */ int TMH_add_instance (struct TMH_MerchantInstance *mi); /** * Lookup a merchant instance by its instance ID. * * @param instance_id identifier of the instance to resolve * @return NULL if that instance is unknown to us */ struct TMH_MerchantInstance * TMH_lookup_instance (const char *instance_id); /** * Check that @a token hashes to @a hash under @a salt for * merchant instance authentication. * * @param token the token to check * @param salt the salt to use when hashing * @param hash the hash to check against * @return #GNUNET_OK if the @a token matches */ int TMH_check_auth (const char *token, const struct GNUNET_ShortHashCode *salt, const struct GNUNET_HashCode *hash); /** * Compute a @a hash from @a token hashes for * merchant instance authentication. * * @param token the token to check * @param[out] salt set to a fresh random salt * @param[out] hash set to the hash of @a token under @a salt */ void TMH_compute_auth (const char *token, struct GNUNET_ShortHashCode *salt, struct GNUNET_HashCode *hash); #endif