diff options
Diffstat (limited to 'src/mint/taler-mint-httpd.c')
-rw-r--r-- | src/mint/taler-mint-httpd.c | 376 |
1 files changed, 376 insertions, 0 deletions
diff --git a/src/mint/taler-mint-httpd.c b/src/mint/taler-mint-httpd.c new file mode 100644 index 00000000..6d69813c --- /dev/null +++ b/src/mint/taler-mint-httpd.c @@ -0,0 +1,376 @@ +/* + This file is part of TALER + (C) 2014 GNUnet e.V. + + 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 Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ + +/** + * @file taler-mint-httpd.c + * @brief Serve the HTTP interface of the mint + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include <jansson.h> +#include <microhttpd.h> +#include <libpq-fe.h> +#include <pthread.h> +#include "mint.h" +#include "mint_db.h" +#include "taler_types.h" +#include "taler_signatures.h" +#include "taler_rsa.h" +#include "taler_json_lib.h" +#include "taler_microhttpd_lib.h" +#include "taler-mint-httpd_mhd.h" +#include "taler-mint-httpd_keys.h" +#include "taler-mint-httpd_deposit.h" +#include "taler-mint-httpd_withdraw.h" +#include "taler-mint-httpd_refresh.h" + + +/** + * Base directory of the mint (global) + */ +char *mintdir; + +/** + * The mint's configuration (global) + */ +struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * Master public key (according to the + * configuration in the mint directory). + */ +struct GNUNET_CRYPTO_EddsaPublicKey master_pub; + +/** + * The HTTP Daemon. + */ +static struct MHD_Daemon *mydaemon; + +/** + * The kappa value for refreshing. + */ +static unsigned int refresh_security_parameter; + +/** + * Port to run the daemon on. + */ +static uint16_t serve_port; + + +/** + * Convert a string representing an EdDSA signature to an EdDSA + * signature. + * + * FIXME: this should be in GNUnet. + * FIXME: why? this code is dead, even here! + * + * @param enc encoded EdDSA signature + * @param enclen number of bytes in @a enc (without 0-terminator) + * @param pub where to store the EdDSA signature + * @return #GNUNET_OK on success + */ +int +TALER_eddsa_signature_from_string (const char *enc, + size_t enclen, + struct GNUNET_CRYPTO_EddsaSignature *sig) +{ + size_t keylen = (sizeof (struct GNUNET_CRYPTO_EddsaSignature)) * 8; + + if (keylen % 5 > 0) + keylen += 5 - keylen % 5; + keylen /= 5; + if (enclen != keylen) + return GNUNET_SYSERR; + + if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen, + sig, + sizeof (struct GNUNET_CRYPTO_EddsaSignature))) + return GNUNET_SYSERR; + return GNUNET_OK; +} + + +/** + * Handle a request coming from libmicrohttpd. + * + * @param cls closure for MHD daemon (unused) + * @param connection the connection + * @param url the requested url + * @param method the method (POST, GET, ...) + * @param upload_data request data + * @param upload_data_size size of @a upload_data in bytes + * @param con_cls closure for request (a `struct Buffer *`) + * @return MHD result code + */ +static int +handle_mhd_request (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, + size_t *upload_data_size, + void **con_cls) +{ + static struct RequestHandler handlers[] = + { + { "/", MHD_HTTP_METHOD_GET, "text/plain", + "Hello, I'm the mint\n", 0, + &TALER_MINT_handler_static_response, MHD_HTTP_OK }, + { "/agpl", MHD_HTTP_METHOD_GET, "text/plain", + NULL, 0, + &TALER_MINT_handler_agpl_redirect, MHD_HTTP_FOUND }, + { "/keys", MHD_HTTP_METHOD_GET, "application/json", + NULL, 0, + &TALER_MINT_handler_keys, MHD_HTTP_OK }, + { "/keys", NULL, "text/plain", + "Only GET is allowed", 0, + &TALER_MINT_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + { "/withdraw/status", MHD_HTTP_METHOD_GET, "application/json", + NULL, 0, + &TALER_MINT_handler_withdraw_status, MHD_HTTP_OK }, + { "/withdraw/status", NULL, "text/plain", + "Only GET is allowed", 0, + &TALER_MINT_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + { "/withdraw/sign", MHD_HTTP_METHOD_GET, "application/json", + NULL, 0, + &TALER_MINT_handler_withdraw_sign, MHD_HTTP_OK }, + { "/withdraw/sign", NULL, "text/plain", + "Only GET is allowed", 0, + &TALER_MINT_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + { "/refresh/melt", MHD_HTTP_METHOD_POST, "application/json", + NULL, 0, + &TALER_MINT_handler_refresh_melt, MHD_HTTP_OK }, + { "/refresh/melt", NULL, "text/plain", + "Only POST is allowed", 0, + &TALER_MINT_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + { "/refresh/commit", MHD_HTTP_METHOD_POST, "application/json", + NULL, 0, + &TALER_MINT_handler_refresh_commit, MHD_HTTP_OK }, + { "/refresh/commit", NULL, "text/plain", + "Only POST is allowed", 0, + &TALER_MINT_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + { "/refresh/reveal", MHD_HTTP_METHOD_POST, "application/json", + NULL, 0, + &TALER_MINT_handler_refresh_melt, MHD_HTTP_OK }, + { "/refresh/reveal", NULL, "text/plain", + "Only POST is allowed", 0, + &TALER_MINT_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + { "/refresh/link", MHD_HTTP_METHOD_GET, "application/json", + NULL, 0, + &TALER_MINT_handler_refresh_link, MHD_HTTP_OK }, + { "/refresh/link", NULL, "text/plain", + "Only GET is allowed", 0, + &TALER_MINT_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + { "/refresh/reveal", MHD_HTTP_METHOD_GET, "application/json", + NULL, 0, + &TALER_MINT_handler_refresh_reveal, MHD_HTTP_OK }, + { "/refresh/reveal", NULL, "text/plain", + "Only GET is allowed", 0, + &TALER_MINT_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + { "/deposit", MHD_HTTP_METHOD_POST, "application/json", + NULL, 0, + &TALER_MINT_handler_deposit, MHD_HTTP_OK }, + { "/deposit", NULL, "text/plain", + "Only POST is allowed", 0, + &TALER_MINT_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + { NULL, NULL, NULL, NULL, 0, 0 } + }; + static struct RequestHandler h404 = + { + "", NULL, "text/html", + "<html><title>404: not found</title></html>", 0, + &TALER_MINT_handler_static_response, MHD_HTTP_NOT_FOUND + }; + struct RequestHandler *rh; + unsigned int i; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Handling request for URL '%s'\n", + url); + for (i=0;NULL != handlers[i].url;i++) + { + rh = &handlers[i]; + if ( (0 == strcasecmp (url, + rh->url)) && + ( (NULL == rh->method) || + (0 == strcasecmp (method, + rh->method)) ) ) + return rh->handler (rh, + connection, + con_cls, + upload_data, + upload_data_size); + } + return TALER_MINT_handler_static_response (&h404, + connection, + con_cls, + upload_data, + upload_data_size); +} + + + +/** + * Load configuration parameters for the mint + * server into the corresponding global variables. + * + * @param param mint_directory the mint's directory + * @return GNUNET_OK on success + */ +static int +mint_serve_process_config (const char *mint_directory) +{ + unsigned long long port; + unsigned long long kappa; + char *master_pub_str; + char *db_cfg; + + cfg = TALER_MINT_config_load (mint_directory); + if (NULL == cfg) + { + fprintf (stderr, + "can't load mint configuration\n"); + return 1; + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "mint", "master_pub", + &master_pub_str)) + { + fprintf (stderr, + "No master public key given in mint configuration."); + return GNUNET_NO; + } + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_public_key_from_string (master_pub_str, + strlen (master_pub_str), + &master_pub)) + { + fprintf (stderr, + "Invalid master public key given in mint configuration."); + return GNUNET_NO; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "mint", "db", + &db_cfg)) + { + fprintf (stderr, + "invalid configuration: mint.db\n"); + return GNUNET_NO; + } + if (GNUNET_OK != + TALER_MINT_DB_init (db_cfg)) + { + fprintf (stderr, + "failed to initialize DB subsystem\n"); + return GNUNET_NO; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, + "mint", "port", + &port)) + { + fprintf (stderr, + "invalid configuration: mint.port\n"); + return GNUNET_NO; + } + + if ((port == 0) || (port > UINT16_MAX)) + { + fprintf (stderr, + "invalid configuration (value out of range): mint.port\n"); + return GNUNET_NO; + } + serve_port = port; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, + "mint", "refresh_security_parameter", + &kappa)) + { + fprintf (stderr, + "invalid configuration: mint.refresh_security_parameter\n"); + return GNUNET_NO; + } + refresh_security_parameter = kappa; + + return GNUNET_OK; +} + + +/** + * The main function of the serve tool + * + * @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) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_HELP ("gnunet-mint-keyup OPTIONS"), + {'d', "mint-dir", "DIR", + "mint directory", 1, + &GNUNET_GETOPT_set_filename, &mintdir}, + GNUNET_GETOPT_OPTION_END + }; + int ret; + + GNUNET_assert (GNUNET_OK == + GNUNET_log_setup ("taler-mint-serve", + "INFO", + NULL)); + if (GNUNET_GETOPT_run ("taler-mint-serve", + options, + argc, argv) < 0) + return 1; + if (NULL == mintdir) + { + fprintf (stderr, + "no mint dir given\n"); + return 1; + } + + if (GNUNET_OK != mint_serve_process_config (mintdir)) + return 1; + + + mydaemon = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, + serve_port, + NULL, NULL, + &handle_mhd_request, NULL, + MHD_OPTION_END); + + if (NULL == mydaemon) + { + fprintf (stderr, + "Failed to start MHD.\n"); + return 1; + } + + ret = TALER_MINT_key_reload_loop (); + MHD_stop_daemon (mydaemon); + return (GNUNET_OK == ret) ? 0 : 1; +} + |