diff options
Diffstat (limited to 'src/exchange')
| -rw-r--r-- | src/exchange/Makefile.am | 3 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd.c | 226 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd.h | 4 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd_aml-decision.c | 57 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd_aml-decision.h | 45 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd_management.h | 26 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd_management_aml-officers.c | 21 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd_management_partners.c | 29 | 
8 files changed, 359 insertions, 52 deletions
| diff --git a/src/exchange/Makefile.am b/src/exchange/Makefile.am index 29596c38..ffcfc5e9 100644 --- a/src/exchange/Makefile.am +++ b/src/exchange/Makefile.am @@ -123,6 +123,7 @@ taler_exchange_wirewatch_LDADD = \  taler_exchange_httpd_SOURCES = \    taler-exchange-httpd.c taler-exchange-httpd.h \    taler-exchange-httpd_auditors.c taler-exchange-httpd_auditors.h \ +  taler-exchange-httpd_aml-decision.c taler-exchange-httpd_aml-decision.h \    taler-exchange-httpd_batch-deposit.c taler-exchange-httpd_batch-deposit.h \    taler-exchange-httpd_batch-withdraw.c taler-exchange-httpd_batch-withdraw.h \    taler-exchange-httpd_common_deposit.c taler-exchange-httpd_common_deposit.h \ @@ -139,12 +140,14 @@ taler_exchange_httpd_SOURCES = \    taler-exchange-httpd_kyc-webhook.c taler-exchange-httpd_kyc-webhook.h \    taler-exchange-httpd_link.c taler-exchange-httpd_link.h \    taler-exchange-httpd_management.h \ +  taler-exchange-httpd_management_aml-officers.c \    taler-exchange-httpd_management_auditors.c \    taler-exchange-httpd_management_auditors_AP_disable.c \    taler-exchange-httpd_management_denominations_HDP_revoke.c \    taler-exchange-httpd_management_drain.c \    taler-exchange-httpd_management_extensions.c \    taler-exchange-httpd_management_global_fees.c \ +  taler-exchange-httpd_management_partners.c \    taler-exchange-httpd_management_post_keys.c \    taler-exchange-httpd_management_signkey_EP_revoke.c \    taler-exchange-httpd_management_wire_enable.c \ diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c index def4fd4a..5501687f 100644 --- a/src/exchange/taler-exchange-httpd.c +++ b/src/exchange/taler-exchange-httpd.c @@ -1,6 +1,6 @@  /*     This file is part of TALER -   Copyright (C) 2014-2022 Taler Systems SA +   Copyright (C) 2014-2023 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 @@ -30,6 +30,7 @@  #include "taler_kyclogic_lib.h"  #include "taler_templating_lib.h"  #include "taler_mhd_lib.h" +#include "taler-exchange-httpd_aml-decision.h"  #include "taler-exchange-httpd_auditors.h"  #include "taler-exchange-httpd_batch-deposit.h"  #include "taler-exchange-httpd_batch-withdraw.h" @@ -323,6 +324,187 @@ handle_post_coins (struct TEH_RequestContext *rc,  /** + * Signature of functions that handle operations + * authorized by AML officers. + * + * @param rc request context + * @param officer_pub the public key of the AML officer + * @param root uploaded JSON data + * @return MHD result code + */ +typedef MHD_RESULT +(*AmlOpPostHandler)(struct TEH_RequestContext *rc, +                    const struct TALER_AmlOfficerPublicKeyP *officer_pub, +                    const json_t *root); + + +/** + * Handle a "/aml/$OFFICER_PUB/$OP" POST request.  Parses the "officer_pub" + * EdDSA key of the officer and demultiplexes based on $OP. + * + * @param rc request context + * @param root uploaded JSON data + * @param args array of additional options + * @return MHD result code + */ +static MHD_RESULT +handle_post_aml (struct TEH_RequestContext *rc, +                 const json_t *root, +                 const char *const args[2]) +{ +  struct TALER_AmlOfficerPublicKeyP officer_pub; +  static const struct +  { +    /** +     * Name of the operation (args[1]) +     */ +    const char *op; + +    /** +     * Function to call to perform the operation. +     */ +    AmlOpPostHandler handler; + +  } h[] = { +    { +      .op = "decision", +      .handler = &TEH_handler_post_aml_decision +    }, +    { +      .op = NULL, +      .handler = NULL +    }, +  }; + +  if (GNUNET_OK != +      GNUNET_STRINGS_string_to_data (args[0], +                                     strlen (args[0]), +                                     &officer_pub, +                                     sizeof (officer_pub))) +  { +    GNUNET_break_op (0); +    return TALER_MHD_reply_with_error (rc->connection, +                                       MHD_HTTP_BAD_REQUEST, +                                       TALER_EC_EXCHANGE_GENERIC_AML_OFFICER_PUB_MALFORMED, +                                       args[0]); +  } +  for (unsigned int i = 0; NULL != h[i].op; i++) +    if (0 == strcmp (h[i].op, +                     args[1])) +      return h[i].handler (rc, +                           &officer_pub, +                           root); +  return r404 (rc->connection, +               args[1]); +} + + +/** + * Signature of functions that handle operations + * authorized by AML officers. + * + * @param rc request context + * @param officer_pub the public key of the AML officer + * @param args remaining arguments + * @return MHD result code + */ +typedef MHD_RESULT +(*AmlOpGetHandler)(struct TEH_RequestContext *rc, +                   const struct TALER_AmlOfficerPublicKeyP *officer_pub, +                   const char *const args[]); + + +/** + * Handle a "/aml/$OFFICER_PUB/$OP" GET request.  Parses the "officer_pub" + * EdDSA key of the officer, checks the authentication signature, and + * demultiplexes based on $OP. + * + * @param rc request context + * @param args array of additional options + * @return MHD result code + */ +static MHD_RESULT +handle_get_aml (struct TEH_RequestContext *rc, +                const char *const args[]) +{ +  struct TALER_AmlOfficerPublicKeyP officer_pub; +  static const struct +  { +    /** +     * Name of the operation (args[1]) +     */ +    const char *op; + +    /** +     * Function to call to perform the operation. +     */ +    AmlOpGetHandler handler; + +  } h[] = { +#if FIXME_AML_GET_DECISIONS_NOT_IMPLEMENTED +    { +      .op = "decisions", +      .handler = &TEH_handler_get_aml_decisions +    }, +    { +      .op = "decision", +      .handler = &TEH_handler_get_aml_decision +    }, +#endif +    { +      .op = NULL, +      .handler = NULL +    }, +  }; + +  if (NULL == args[0]) +  { +    GNUNET_break_op (0); +    return TALER_MHD_reply_with_error (rc->connection, +                                       MHD_HTTP_BAD_REQUEST, +                                       TALER_EC_EXCHANGE_GENERIC_AML_OFFICER_PUB_MALFORMED, +                                       "argument missing"); +  } +  if (GNUNET_OK != +      GNUNET_STRINGS_string_to_data (args[0], +                                     strlen (args[0]), +                                     &officer_pub, +                                     sizeof (officer_pub))) +  { +    GNUNET_break_op (0); +    return TALER_MHD_reply_with_error (rc->connection, +                                       MHD_HTTP_BAD_REQUEST, +                                       TALER_EC_EXCHANGE_GENERIC_AML_OFFICER_PUB_MALFORMED, +                                       args[0]); +  } +  if (NULL == args[1]) +  { +    GNUNET_break_op (0); +    return TALER_MHD_reply_with_error (rc->connection, +                                       MHD_HTTP_NOT_FOUND, +                                       TALER_EC_EXCHANGE_GENERIC_WRONG_NUMBER_OF_SEGMENTS, +                                       "AML GET operations must specify an operation identifier"); +  } +  if (1)   // FIXME: check AML officer GET signature! +  { +    GNUNET_break_op (0); +    return TALER_MHD_reply_with_error (rc->connection, +                                       MHD_HTTP_FORBIDDEN, +                                       TALER_EC_EXCHANGE_GENERIC_AML_OFFICER_GET_SIGNATURE_INVALID, +                                       NULL); +  } +  for (unsigned int i = 0; NULL != h[i].op; i++) +    if (0 == strcmp (h[i].op, +                     args[1])) +      return h[i].handler (rc, +                           &officer_pub, +                           &args[2]); +  return r404 (rc->connection, +               args[1]); +} + + +/**   * Signature of functions that handle operations on reserves.   *   * @param rc request context @@ -890,6 +1072,8 @@ handle_post_management (struct TEH_RequestContext *rc,                                                        &exchange_pub,                                                        root);    } +  /* FIXME-STYLE: all of the following can likely be nicely combined +     into an array-based dispatcher to deduplicate the logic... */    if (0 == strcmp (args[0],                     "keys"))    { @@ -967,6 +1151,30 @@ handle_post_management (struct TEH_RequestContext *rc,      return TEH_handler_management_post_drain (rc->connection,                                                root);    } +  if (0 == strcmp (args[0], +                   "aml-officers")) +  { +    if (NULL != args[1]) +    { +      GNUNET_break_op (0); +      return r404 (rc->connection, +                   "/management/aml-officers/*"); +    } +    return TEH_handler_management_aml_officers (rc->connection, +                                                root); +  } +  if (0 == strcmp (args[0], +                   "partners")) +  { +    if (NULL != args[1]) +    { +      GNUNET_break_op (0); +      return r404 (rc->connection, +                   "/management/partners/*"); +    } +    return TEH_handler_management_partners (rc->connection, +                                            root); +  }    GNUNET_break_op (0);    return r404 (rc->connection,                 "/management/*"); @@ -1289,6 +1497,22 @@ handle_mhd_request (void *cls,        .nargs = 4,        .nargs_is_upper_bound = true      }, +    /* AML endpoints */ +    { +      .url = "aml", +      .method = MHD_HTTP_METHOD_GET, +      .handler.get = &handle_get_aml, +      .nargs = 4, +      .nargs_is_upper_bound = true +    }, +    { +      .url = "aml", +      .method = MHD_HTTP_METHOD_POST, +      .handler.post = &handle_post_aml, +      .nargs = 2 +    }, + +      /* mark end of list */      {        .url = NULL diff --git a/src/exchange/taler-exchange-httpd.h b/src/exchange/taler-exchange-httpd.h index 2be26f14..7715444a 100644 --- a/src/exchange/taler-exchange-httpd.h +++ b/src/exchange/taler-exchange-httpd.h @@ -213,7 +213,7 @@ struct TEH_RequestHandler       *       * @param rc context for the request       * @param json uploaded JSON data -     * @param args array of arguments, needs to be of length @e args_expected +     * @param args array of arguments, needs to be of length @e nargs       * @return MHD result code       */      MHD_RESULT @@ -225,7 +225,7 @@ struct TEH_RequestHandler       * Function to call to handle DELETE requests.       *       * @param rc context for the request -     * @param args array of arguments, needs to be of length @e args_expected +     * @param args array of arguments, needs to be of length @e nargs       * @return MHD result code       */      MHD_RESULT diff --git a/src/exchange/taler-exchange-httpd_aml-decision.c b/src/exchange/taler-exchange-httpd_aml-decision.c index c93c1066..4589c8eb 100644 --- a/src/exchange/taler-exchange-httpd_aml-decision.c +++ b/src/exchange/taler-exchange-httpd_aml-decision.c @@ -31,27 +31,26 @@  MHD_RESULT -TEH_handler_management_post_aml_decision ( -  struct MHD_Connection *connection, +TEH_handler_post_aml_decision ( +  struct TEH_RequestContext *rc, +  const struct TALER_AmlOfficerPublicKeyP *officer_pub,    const json_t *root)  { +  struct MHD_Connection *connection = rc->connection;    const char *justification;    struct GNUNET_TIME_Timestamp decision_time;    struct TALER_Amount new_threshold;    struct TALER_PaytoHashP h_payto;    uint32_t new_state32;    enum TALER_AmlDecisionState new_state; -  struct TALER_AmlOfficerPublicKeyP officer_pub;    struct TALER_AmlOfficerSignatureP officer_sig;    struct GNUNET_JSON_Specification spec[] = { -    // FIXME: officer_pub is in URL path, not in JSON body! -    GNUNET_JSON_spec_fixed_auto ("officer_pub", -                                 &officer_pub),      GNUNET_JSON_spec_fixed_auto ("officer_sig",                                   &officer_sig),      GNUNET_JSON_spec_fixed_auto ("h_payto",                                   &h_payto),      TALER_JSON_spec_amount ("new_threshold", +                            TEH_currency,                              &new_threshold),      GNUNET_JSON_spec_string ("justification",                               &justification), @@ -76,13 +75,13 @@ TEH_handler_management_post_aml_decision (    new_state = (enum TALER_AmlDecisionState) new_state32;    TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;    if (GNUNET_OK != -      TALER_exchange_aml_decision_verify (justification, -                                          decision_time, -                                          &new_threshold, -                                          &h_payto, -                                          new_state, -                                          &officer_pub, -                                          &officer_sig)) +      TALER_officer_aml_decision_verify (justification, +                                         decision_time, +                                         &new_threshold, +                                         &h_payto, +                                         new_state, +                                         &officer_pub, +                                         &officer_sig))    {      GNUNET_break_op (0);      return TALER_MHD_reply_with_error ( @@ -97,25 +96,25 @@ TEH_handler_management_post_aml_decision (      bool invalid_officer;      do { -      qs = TEH_plugin->add_aml_decision (TEH_plugin->cls, -                                         justification, -                                         decision_time, -                                         &new_threshold, -                                         &h_payto, -                                         new_state, -                                         &officer_pub, -                                         &officer_sig, -                                         &invalid_officer, -                                         &last_date); +      // FIXME: bound loop? +      qs = TEH_plugin->insert_aml_decision (TEH_plugin->cls, +                                            &h_payto, +                                            &new_threshold, +                                            new_state, +                                            decision_time, +                                            justification, +                                            &officer_pub, +                                            &officer_sig, +                                            &invalid_officer, +                                            &last_date);      } while (GNUNET_DB_STATUS_SOFT_ERROR == qs);      if (qs < 0)      {        GNUNET_break (0); -      *mhd_ret = TALER_MHD_reply_with_error (connection, -                                             MHD_HTTP_INTERNAL_SERVER_ERROR, -                                             TALER_EC_GENERIC_DB_STORE_FAILED, -                                             "add aml_decision"); -      return qs; +      return TALER_MHD_reply_with_error (connection, +                                         MHD_HTTP_INTERNAL_SERVER_ERROR, +                                         TALER_EC_GENERIC_DB_STORE_FAILED, +                                         "add aml_decision");      }      if (invalid_officer)      { @@ -127,7 +126,7 @@ TEH_handler_management_post_aml_decision (      }      if (GNUNET_TIME_timestamp_cmp (last_date,                                     >, -                                   validity_start)) +                                   decision_time))      {        GNUNET_break_op (0);        return TALER_MHD_reply_with_error ( diff --git a/src/exchange/taler-exchange-httpd_aml-decision.h b/src/exchange/taler-exchange-httpd_aml-decision.h new file mode 100644 index 00000000..e6e35552 --- /dev/null +++ b/src/exchange/taler-exchange-httpd_aml-decision.h @@ -0,0 +1,45 @@ +/* +  This file is part of TALER +  Copyright (C) 2023 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 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, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-exchange-httpd_aml_decision.h + * @brief Handle /aml/$OFFICER_PUB/decision requests + * @author Christian Grothoff + */ +#ifndef TALER_EXCHANGE_HTTPD_AML_DECISION_H +#define TALER_EXCHANGE_HTTPD_AML_DECISION_H + +#include <microhttpd.h> +#include "taler-exchange-httpd.h" + + +/** + * Handle an "/aml/$OFFICER_PUB/decision" request.  Parses the decision + * details, checks the signatures and if appropriately authorized excecutes + * the decision. + * + * @param rc request context + * @param officer_pub public key of the AML officer who made the request + * @param root uploaded JSON data + * @return MHD result code +  */ +MHD_RESULT +TEH_handler_post_aml_decision ( +  struct TEH_RequestContext *rc, +  const struct TALER_AmlOfficerPublicKeyP *officer_pub, +  const json_t *root); + + +#endif diff --git a/src/exchange/taler-exchange-httpd_management.h b/src/exchange/taler-exchange-httpd_management.h index a5a8b0e7..2fc1fe8d 100644 --- a/src/exchange/taler-exchange-httpd_management.h +++ b/src/exchange/taler-exchange-httpd_management.h @@ -175,6 +175,32 @@ TEH_handler_management_post_drain (  /** + * Handle a POST "/management/aml-officers" request. + * + * @param connection the MHD connection to handle + * @param root uploaded JSON data + * @return MHD result code + */ +MHD_RESULT +TEH_handler_management_aml_officers ( +  struct MHD_Connection *connection, +  const json_t *root); + + +/** + * Handle a POST "/management/partners" request. + * + * @param connection the MHD connection to handle + * @param root uploaded JSON data + * @return MHD result code + */ +MHD_RESULT +TEH_handler_management_partners ( +  struct MHD_Connection *connection, +  const json_t *root); + + +/**   * Initialize extension configuration handling.   *   * @return #GNUNET_OK on success diff --git a/src/exchange/taler-exchange-httpd_management_aml-officers.c b/src/exchange/taler-exchange-httpd_management_aml-officers.c index 139ccdb2..b82c18d4 100644 --- a/src/exchange/taler-exchange-httpd_management_aml-officers.c +++ b/src/exchange/taler-exchange-httpd_management_aml-officers.c @@ -92,14 +92,15 @@ TEH_handler_management_aml_officers (      struct GNUNET_TIME_Timestamp last_date;      do { -      qs = TEH_plugin->set_aml_officer (TEH_plugin->cls, -                                        &officer_pub, -                                        officer_name, -                                        change_date, -                                        is_active, -                                        read_only, -                                        &master_sig, -                                        &last_date); +      // FIXME: bound loop! +      qs = TEH_plugin->insert_aml_officer (TEH_plugin->cls, +                                           &officer_pub, +                                           &master_sig, +                                           officer_name, +                                           is_active, +                                           read_only, +                                           change_date, +                                           &last_date);      } while (GNUNET_DB_STATUS_SOFT_ERROR == qs);      if (qs < 0)      { @@ -107,13 +108,13 @@ TEH_handler_management_aml_officers (        return TALER_MHD_reply_with_error (connection,                                           MHD_HTTP_INTERNAL_SERVER_ERROR,                                           TALER_EC_GENERIC_DB_STORE_FAILED, -                                         "XXX"); +                                         "insert_aml_officer");      }      if (GNUNET_TIME_timestamp_cmp (last_date,                                     >,                                     change_date))      { -      GNUNER_break_op (0); +      GNUNET_break_op (0);        return TALER_MHD_reply_with_error (          connection,          MHD_HTTP_CONFLICT, diff --git a/src/exchange/taler-exchange-httpd_management_partners.c b/src/exchange/taler-exchange-httpd_management_partners.c index 5d860120..1c0d4a9a 100644 --- a/src/exchange/taler-exchange-httpd_management_partners.c +++ b/src/exchange/taler-exchange-httpd_management_partners.c @@ -51,13 +51,14 @@ TEH_handler_management_partners (      GNUNET_JSON_spec_string ("partner_base_url",                               &partner_base_url),      TALER_JSON_spec_amount ("wad_fee", +                            TEH_currency,                              &wad_fee),      GNUNET_JSON_spec_timestamp ("start_date",                                  &start_date),      GNUNET_JSON_spec_timestamp ("end_date",                                  &start_date), -    GNUNET_JSON_spec_time_rel ("wad_frequency", -                               &wad_frequency), +    GNUNET_JSON_spec_relative_time ("wad_frequency", +                                    &wad_frequency),      GNUNET_JSON_spec_end ()    }; @@ -94,14 +95,14 @@ TEH_handler_management_partners (    {      enum GNUNET_DB_QueryStatus qs; -    qs = TEH_plugin->add_partner (TEH_plugin->cls, -                                  &partner_pub, -                                  start_date, -                                  end_date, -                                  wad_frequency, -                                  &wad_fee, -                                  partner_base_url, -                                  &master_sig); +    qs = TEH_plugin->insert_partner (TEH_plugin->cls, +                                     &partner_pub, +                                     start_date, +                                     end_date, +                                     wad_frequency, +                                     &wad_fee, +                                     partner_base_url, +                                     &master_sig);      if (qs < 0)      {        GNUNET_break (0); @@ -110,6 +111,14 @@ TEH_handler_management_partners (                                           TALER_EC_GENERIC_DB_STORE_FAILED,                                           "add_partner");      } +    if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) +    { +      /* FIXME: check for idempotency! */ +      return TALER_MHD_reply_with_error (connection, +                                         MHD_HTTP_CONFLICT, +                                         TALER_EC_EXCHANGE_MANAGEMENT_ADD_PARTNER_DATA_CONFLICT, +                                         NULL); +    }    }    return TALER_MHD_reply_static (      connection, | 
