/* This file is part of TALER Copyright (C) 2020 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 merchant-tools/taler-merchant-setup-reserve.c * @brief Create reserve for tipping * @author Christian Grothoff */ #include "platform.h" #include #include #include #include "taler_merchant_service.h" /** * Return value from main(). */ static int global_ret; /** * Initial amount the reserve will be filled with. */ static struct TALER_Amount initial_amount; /** * Base URL of the merchant (with instance) to create the reserve for. */ static char *merchant_base_url; /** * Base URL of the exchange to create the reserve at. */ static char *exchange_base_url; /** * Wire method to use. */ static char *wire_method; /** * Operation handle. */ static struct TALER_MERCHANT_PostReservesHandle *prh; /** * Our context for making HTTP requests. */ static struct GNUNET_CURL_Context *ctx; /** * Reschedule context for #SH_ctx. */ static struct GNUNET_CURL_RescheduleContext *rc; /** * Username and password to use for client authentication * (optional). */ static char *userpass; /** * Type of the client's TLS certificate (optional). */ static char *certtype; /** * File with the client's TLS certificate (optional). */ static char *certfile; /** * File with the client's TLS private key (optional). */ static char *keyfile; /** * This value goes in the Authorization:-header. */ static char *apikey; /** * Passphrase to decrypt client's TLS private key file (optional). */ static char *keypass; /** * Shutdown task (invoked when the process is being terminated) * * @param cls NULL */ static void do_shutdown (void *cls) { if (NULL != ctx) { GNUNET_CURL_fini (ctx); ctx = NULL; } if (NULL != rc) { GNUNET_CURL_gnunet_rc_destroy (rc); rc = NULL; } if (NULL != prh) { TALER_MERCHANT_reserves_post_cancel (prh); prh = NULL; } } /** * Callbacks of this type are used to work the result of submitting a * POST /reserves request to a merchant * * @param cls closure * @param hr HTTP response details * @param reserve_pub public key of the created reserve, NULL on error * @param payto_uri where to make the payment to for filling the reserve, NULL on error */ static void result_cb (void *cls, const struct TALER_MERCHANT_HttpResponse *hr, const struct TALER_ReservePublicKeyP *reserve_pub, const char *payto_uri) { (void) cls; prh = NULL; switch (hr->http_status) { case MHD_HTTP_OK: { char res_str[sizeof (*reserve_pub) * 2 + 1]; GNUNET_STRINGS_data_to_string (reserve_pub, sizeof (*reserve_pub), res_str, sizeof (res_str)); fprintf (stdout, "%s?subject=%s\n", payto_uri, res_str); } break; default: fprintf (stderr, "Unexpected backend failure: %u/%d\n", hr->http_status, (int) hr->ec); global_ret = 1; break; } GNUNET_SCHEDULER_shutdown (); } /** * Main function that will be run. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param config configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *config) { /* setup HTTP client event loop */ ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, &rc); rc = GNUNET_CURL_gnunet_rc_create (ctx); if (NULL != userpass) GNUNET_CURL_set_userpass (ctx, userpass); if (NULL != keyfile) GNUNET_CURL_set_tlscert (ctx, certtype, certfile, keyfile, keypass); if (NULL != apikey) { char *auth_header; GNUNET_asprintf (&auth_header, "%s: %s", MHD_HTTP_HEADER_AUTHORIZATION, apikey); if (GNUNET_OK != GNUNET_CURL_append_header (ctx, auth_header)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed so sett %s header, trying without\n", MHD_HTTP_HEADER_AUTHORIZATION); } GNUNET_free (auth_header); } /* setup termination logic */ GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL); /* run actual (async) operation */ prh = TALER_MERCHANT_reserves_post (ctx, merchant_base_url, &initial_amount, exchange_base_url, wire_method, &result_cb, NULL); if (NULL == prh) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to begin operation with merchant backend!\n"); global_ret = 2; GNUNET_SCHEDULER_shutdown (); return; } } /** * The main function for setting up reserves for tipping. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_option_mandatory ( TALER_getopt_get_amount ('a', "amount", "VALUE", "amount to be transferred into the reserve", &initial_amount)), GNUNET_GETOPT_option_string ('A', "auth", "USERNAME:PASSWORD", "use the given USERNAME and PASSWORD for client authentication", &userpass), GNUNET_GETOPT_option_string ('C', "cert", "CERTFILE", "name of the TLS client certificate file", &certfile), GNUNET_GETOPT_option_mandatory ( GNUNET_GETOPT_option_string ('e', "exchange-url", "URL", "base URL of the exchange to create the reserve at", &exchange_base_url)), GNUNET_GETOPT_option_string ('k', "key", "KEYFILE", "file with the private TLS key for TLS client authentication", &keyfile), GNUNET_GETOPT_option_mandatory ( GNUNET_GETOPT_option_string ('m', "merchant-url", "URL", "base URL of the merchant backend's REST API", &merchant_base_url)), GNUNET_GETOPT_option_string ('p', "pass", "KEYFILEPASSPHRASE", "passphrase needed to decrypt the TLS client private key file", &keypass), GNUNET_GETOPT_option_string ('K', "apikey", "APIKEY", "API key to use in the HTTP request", &apikey), GNUNET_GETOPT_option_string ('t', "type", "CERTTYPE", "type of the TLS client certificate, defaults to PEM if not specified", &certtype), GNUNET_GETOPT_option_mandatory ( GNUNET_GETOPT_option_string ('w', "wire-method", "METHOD", "wire method to use for the wire transfer (i.e. IBAN)", &wire_method)), GNUNET_GETOPT_OPTION_END }; /* force linker to link against libtalerutil; if we do not do this, the linker may "optimize" libtalerutil away and skip #TALER_OS_init(), which we do need */ (void) TALER_project_data_default (); GNUNET_assert (GNUNET_OK == GNUNET_log_setup ("taler-merchant-setup-reserve", "INFO", NULL)); if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "taler-merchant-setup-reserve", "Setup reserve for tipping", options, &run, NULL)) return 3; return global_ret; } /* end of taler-merchant-setup-reserve.c */