/*
  This file is part of TALER
  Copyright (C) 2014-2025 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 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 <taler/taler_mhd_lib.h>
#include <gnunet/gnunet_mhd_compat.h>
#include "taler_merchant_bank_lib.h"
#include <regex.h>


/**
 * 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 payto_uri using?
   */
  char *wire_method;

  /**
   * Wire details for this instance
   */
  struct TALER_FullPayto payto_uri;

  /**
   * Salt to use when computing @e h_wire from @e payto_uri.
   */
  struct TALER_WireSaltP wire_salt;

  /**
   * Hash of our wire format details as given in @e payto_uri
   */
  struct TALER_MerchantWireHashP h_wire;

  /**
   * Base URL of the credit facade.
   */
  char *credit_facade_url;

  /**
   * Authentication data to access the credit facade.
   * May be uninitialized if not provided by the client.
   */
  json_t *credit_facade_credentials;

  /**
   * 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;

  /**
   * Hash of the instance ID, key for the DHT.
   */
  struct GNUNET_HashCode h_instance;

  /**
   * 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;

  /**
   * Database event we are waiting on to be resuming
   * long-polling requests from the @e po_head.
   */
  struct GNUNET_DB_EventHandler *po_eh;

  /**
   * 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;

  /**
   * True if this instance was deleted (but not yet purged).
   */
  bool deleted;

  /**
   * True if email/sms validation is needed before the
   * instance can be used.
   */
  bool validation_needed;
};


GNUNET_NETWORK_STRUCT_BEGIN


/**
 * Event triggered when an order is paid.
 */
struct TMH_OrderPayEventP
{
  /**
   * Type is #TALER_DBEVENT_MERCHANT_ORDER_PAID
   */
  struct GNUNET_DB_EventHeaderP header;

  /**
   * Always zero (for alignment).
   */
  uint32_t reserved GNUNET_PACKED;

  /**
   * Merchant's public key
   */
  struct TALER_MerchantPublicKeyP merchant_pub;

  /**
   * Hash of the order ID.
   */
  struct GNUNET_HashCode h_order_id;
};


/**
 * Event triggered when a fulfillment URL is
 * bound to a session (as paid).
 */
struct TMH_SessionEventP
{
  /**
   * Type is #TALER_DBEVENT_MERCHANT_SESSION_CAPTURED
   */
  struct GNUNET_DB_EventHeaderP header;

  /**
   * Always zero (for alignment).
   */
  uint32_t reserved GNUNET_PACKED;

  /**
   * Merchant's public key
   */
  struct TALER_MerchantPublicKeyP merchant_pub;

  /**
   * Hash of the fulfillment URL.
   */
  struct GNUNET_HashCode h_fulfillment_url;

  /**
   * Hash of the session ID
   */
  struct GNUNET_HashCode h_session_id;
};


/**
 * Event triggered when an order's refund is increased
 * or obtained by the respective wallet.
 *
 * Extra arguments are the amount (as a string).
 */
struct TMH_OrderRefundEventP
{
  /**
   * Type is #TALER_DBEVENT_MERCHANT_ORDER_REFUND or
   * #TALER_DBEVENT_MERCHANT_REFUND_OBTAINED
   */
  struct GNUNET_DB_EventHeaderP header;

  /**
   * Always zero (for alignment).
   */
  uint32_t reserved GNUNET_PACKED;

  /**
   * Merchant's public key
   */
  struct TALER_MerchantPublicKeyP merchant_pub;

  /**
   * Hash of the order ID.
   */
  struct GNUNET_HashCode h_order_id;
};


/**
 * Event generated when a client picks up a reward.
 */
struct TMH_RewardPickupEventP
{
  /**
   * Type is #TALER_DBEVENT_MERCHANT_REWARD_PICKUP.
   */
  struct GNUNET_DB_EventHeaderP header;

  /**
   * Always zero (for alignment).
   */
  uint32_t reserved GNUNET_PACKED;

  /**
   * Reward ID.
   */
  struct TALER_RewardIdentifierP reward_id;

  /**
   * Hash of the instance ID.
   */
  struct GNUNET_HashCode h_instance;

};

/**
 * Possible flags indicating the state of an order.
 */
enum TMH_OrderStateFlags
{
  TMH_OSF_NONE = 0,

  /**
   * Not yet used.
   */
  TMH_OSF_CLAIMED = 1,

  /**
   * Customer paid the order.
   */
  TMH_OSF_PAID = 2,

  /**
   * Merchant granted (possibly partial) refund.
   */
  TMH_OSF_REFUNDED = 4,

  /**
   * Merchant received the payment from the exchange.
   * FIXME: not triggered yet!
   */
  TMH_OSF_WIRED = 8
};


/**
 * Extra information passed for a
 * #TALER_DBEVENT_MERCHANT_ORDERS_CHANGE.
 */
struct TMH_OrderChangeEventDetailsP
{
  /**
   * Order ID, in NBO.
   */
  uint64_t order_serial_id GNUNET_PACKED;

  /**
   * Execution date of the order.
   */
  struct GNUNET_TIME_TimestampNBO execution_date;

  /**
   * See `enum TMH_OrderStateFlags`. In NBO.
   */
  uint32_t order_state GNUNET_PACKED;

};


/**
 * Event triggered when an order's refund is increased
 * or obtained by the respective wallet.
 *
 * Extra arguments are the amount (as a string).
 */
struct TMH_OrderChangeEventP
{
  /**
   * Type is #TALER_DBEVENT_MERCHANT_ORDERS_CHANGE.
   */
  struct GNUNET_DB_EventHeaderP header;

  /**
   * Always zero (for alignment).
   */
  uint32_t reserved GNUNET_PACKED;

  /**
   * Merchant's public key
   */
  struct TALER_MerchantPublicKeyP merchant_pub;
};


GNUNET_NETWORK_STRUCT_END

/**
 * @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;


/**
 * Possible authorization scopes. This is a bit mask.
 */
enum TMH_AuthScope
{
  /**
   * Nothing is authorized.
   */
  TMH_AS_NONE = 0,

  /**
   * Read-only access is OK. Any GET request is
   * automatically OK.
   */
  TMH_AS_READ_ONLY = 1,

  /**
   * 2 is Reserved. Was refreshable pre v42
   */

  /**
   * Order creation and payment status check only
   */
  TMH_AS_ORDER_SIMPLE = 3,

  /**
   * Order creation and inventory locking,
   * includes #TMH_AS_ORDER_SIMPLE
   */
  TMH_AS_ORDER_POS = 4,

  /**
   * Order creation and refund
   */
  TMH_AS_ORDER_MGMT = 5,

  /**
   * Order full
   * Includes #TMH_AS_ORDER_POS and #TMH_AS_ORDER_MGMT
   */
  TMH_AS_ORDER_FULL = 6,

  /**
   * Full access is granted to everything.
   * We want to deprecate and remove this!
   * Old scope "write"
   */
  TMH_AS_ALL = 7 | 1 << 30,

  /**
   * Full access is granted to everything.
   */
  TMH_AS_SPA = 8,

  /**
   * /login access to renew the token is OK.
   * This is actually combined with other scopes
   * and not (usually) used as a scope itself.
   */
  TMH_AS_REFRESHABLE = 1 << 30,

};


/**
 * @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", "/templates", "/webhooks" 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;

  /**
   * Required access permission for this request.
   */
  const char *permission;

  /**
   * Does this request include an identifier segment
   * (product_id, reserve_pub, order_id, reward_id, template_id, webhook_id) in the
   * second segment?
   */
  bool have_id_segment;

  /**
   * Does this request handler work without an instance?
   */
  bool skip_instance;

  /**
   * Does this endpoint ONLY apply for the admin instance?
   */
  bool default_only;

  /**
   * Does this request handler work with a deleted instance?
   */
  bool allow_deleted_instance;

  /**
   * URL suffix the handler is for, excludes the '/',
   * so "pay" or "claim", not "/pay".
   */
  const char *url_suffix;

  /**
   * HTTP 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 ctx 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;

  /**
   * Copy of our original full URL with query parameters.
   */
  char *full_url;

  /**
   * Client-provided authentication token for this
   * request, can be NULL.
   *
   * Used to check for concurrent, conflicting updates of
   * the authentication information in the database.
   */
  const char *auth_token;

  /**
   * Infix part of @a url.
   */
  char *infix;

  /**
   * Which connection was suspended.
   */
  struct MHD_Connection *connection;

  /**
   * 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;

  /**
   * Actual authentication scope of this request.
   * Only set for ``/private/`` requests.
   */
  enum TMH_AuthScope auth_scope;

  /**
   * 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;
};


/**
 * Information common for suspended requests.
 */
struct TMH_SuspendedConnection
{
  /**
   * Which connection was suspended.
   */
  struct MHD_Connection *con;

  /**
   * 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;

};


/**
 * Which currency do we use?
 */
extern char *TMH_currency;

/**
 * What is the base URL for this merchant backend?  NULL if it is not
 * configured and is to be determined from HTTP headers (X-Forwarded-Host and
 * X-Forwarded-Port and X-Forwarded-Prefix) of the reverse proxy.
 */
extern char *TMH_base_url;

/**
 * Name of helper program to send e-mail.
 */
extern char *TMH_helper_email;

/**
 * Name of helper program to send SMS.
 */
extern char *TMH_helper_sms;

/**
 * Space-separated list of allowed payment target types.
 * "*" for "all" (no restriction).
 */
extern char *TMH_allowed_payment_targets;

/**
 * Default persona to use for new browsers.
 */
extern char *TMH_default_persona;

/**
 * Regular expression further restricting payment target types.
 * Can be NULL/empty for no restrictions.
 */
extern char *TMH_payment_target_regex;

/**
 * Compiled regular expression, only valid if
 * #TMH_payment_target_regex is not NULL!
 */
extern regex_t TMH_payment_target_re;

/**
 * Length of the TMH_cspecs array.
 */
extern unsigned int TMH_num_cspecs;

/**
 * Rendering specs for currencies.
 */
extern struct TALER_CurrencySpecification *TMH_cspecs;

/**
 * Inform the auditor for all deposit confirmations (global option)
 */
extern int TMH_force_audit;

/**
 * Context for all CURL operations (useful to the event loop)
 */
extern struct GNUNET_CURL_Context *TMH_curl_ctx;

/**
 * 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;

/**
 * Default wire delay for new instances.
 */
extern struct GNUNET_TIME_Relative TMH_default_wire_transfer_delay;

/**
 * Default rounding interval to be applied to new instances.
 */
extern enum GNUNET_TIME_RounderInterval
  TMH_default_wire_transfer_rounding_interval;

/**
 * Default payment delay for new instances.
 */
extern struct GNUNET_TIME_Relative TMH_default_pay_delay;

/**
 * Default refund delay for new instances.
 */
extern struct GNUNET_TIME_Relative TMH_default_refund_delay;

/**
 * #GNUNET_YES if protocol version 19 is strictly enforced.
 * (Default is #GNUNET_NO)
 */
extern int TMH_strict_v19;

/**
 * #GNUNET_YES if authentication is disabled (For testing only!!).
 * (Default is #GNUNET_NO)
 */
extern int TMH_auth_disabled;

/**
 * #GNUNET_YES if self-provisioning is enabled.
 */
extern int TMH_have_self_provisioning;

/**
 * Set of TAN channels.
 */
enum TEH_TanChannelSet
{
  TEH_TCS_NONE = 0,
  TEH_TCS_SMS = 1,
  TEH_TCS_EMAIL = 2,
  TEH_TCS_EMAIL_AND_SMS = 3
};


/**
 * Which TAN channels are mandatory for self-provisioned
 * accounts and password resets? Bitmask.
 */
extern enum TEH_TanChannelSet TEH_mandatory_tan_channels;

/**
 * Callback that frees an instances removing
 * it from the global hashmap.
 *
 * @param cls closure, pass NULL
 * @param key current key (ignored)
 * @param value a `struct TMH_MerchantInstance`
 * @return #GNUNET_YES (always)
 */
enum GNUNET_GenericReturnValue
TMH_instance_free_cb (void *cls,
                      const struct GNUNET_HashCode *key,
                      void *value);


/**
 * 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
 */
enum GNUNET_GenericReturnValue
TMH_add_instance (struct TMH_MerchantInstance *mi);


/**
 * 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);


/**
 * Free memory allocated by @a wm.
 *
 * @param[in] wm wire method to free
 */
void
TMH_wire_method_free (struct TMH_WireMethod *wm);


/**
 * 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);


/**
 * A transaction modified an instance setting
 * (or created/deleted/purged one). Notify all
 * backends about the change.
 *
 * @param id ID of the instance that changed
 */
void
TMH_reload_instances (const char *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
 */
enum GNUNET_GenericReturnValue
TMH_check_auth (const char *token,
                struct TALER_MerchantAuthenticationSaltP *salt,
                struct TALER_MerchantAuthenticationHashP *hash);


/**
 * Compute a @a hash from @a token hashes for
 * merchant instance authentication.
 *
 * @param password the password 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 *password,
                  struct TALER_MerchantAuthenticationSaltP *salt,
                  struct TALER_MerchantAuthenticationHashP *hash);


/**
 * Check if @a candidate permissions are a subset of @a as permissions
 *
 * @param as scope to check against
 * @param candidate scope to check if its permissions are a subset of @a as permissions.
 * @return true if it was a subset, false otherwise.
 */
bool
TMH_scope_is_subset (enum TMH_AuthScope as,
                     enum TMH_AuthScope candidate);


/**
 * Return the TMH_AuthScope corresponding to @a name.
 *
 * @param name the name to look for
 * @return the scope corresponding to the name, or TMH_AS_NONE.
 */
enum TMH_AuthScope
TMH_get_scope_by_name (const char *name);


/**
 * Return the name corresponding to @a scop.
 *
 * @param scope the scope to look for
 * @param[out] refreshable outputs if scope value was refreshable
 * @return the name corresponding to the scope, or NULL.
 */
const char *
TMH_get_name_by_scope (enum TMH_AuthScope scope,
                       bool *refreshable);

#endif
