diff options
Diffstat (limited to 'src/exchange')
| -rw-r--r-- | src/exchange/Makefile.am | 1 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd.c | 2 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd_aml-decision-get.c | 258 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd_aml-decision.h | 18 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd_aml-decisions-get.c | 44 | 
5 files changed, 300 insertions, 23 deletions
| diff --git a/src/exchange/Makefile.am b/src/exchange/Makefile.am index bf6b1b1a..364ab396 100644 --- a/src/exchange/Makefile.am +++ b/src/exchange/Makefile.am @@ -124,6 +124,7 @@ 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_aml-decision-get.c \    taler-exchange-httpd_aml-decisions-get.c \    taler-exchange-httpd_batch-deposit.c taler-exchange-httpd_batch-deposit.h \    taler-exchange-httpd_batch-withdraw.c taler-exchange-httpd_batch-withdraw.h \ diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c index 11b2d35f..4bab9afa 100644 --- a/src/exchange/taler-exchange-httpd.c +++ b/src/exchange/taler-exchange-httpd.c @@ -450,12 +450,10 @@ handle_get_aml (struct TEH_RequestContext *rc,        .op = "decisions",        .handler = &TEH_handler_aml_decisions_get      }, -#if FIXME_AML_GET_DECISIONS_NOT_IMPLEMENTED      {        .op = "decision",        .handler = &TEH_handler_aml_decision_get      }, -#endif      {        .op = NULL,        .handler = NULL diff --git a/src/exchange/taler-exchange-httpd_aml-decision-get.c b/src/exchange/taler-exchange-httpd_aml-decision-get.c new file mode 100644 index 00000000..0754c0b8 --- /dev/null +++ b/src/exchange/taler-exchange-httpd_aml-decision-get.c @@ -0,0 +1,258 @@ +/* +  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-get.c + * @brief Return summary information about AML decision + * @author Christian Grothoff + */ +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include <jansson.h> +#include <microhttpd.h> +#include <pthread.h> +#include "taler_json_lib.h" +#include "taler_mhd_lib.h" +#include "taler_signatures.h" +#include "taler-exchange-httpd.h" +#include "taler_exchangedb_plugin.h" +#include "taler-exchange-httpd_aml-decision.h" +#include "taler-exchange-httpd_metrics.h" + + +/** + * Maximum number of records we return per request. + */ +#define MAX_RECORDS 1024 + +/** + * Callback with KYC attributes about a particular user. + * + * @param[in,out] cls closure with a `json_t *` array to update + * @param h_payto account for which the attribute data is stored + * @param provider_section provider that must be checked + * @param birthdate birthdate of user, in format YYYY-MM-DD; can be NULL; + *        digits can be 0 if exact day, month or year are unknown + * @param collection_time when was the data collected + * @param expiration_time when does the data expire + * @param enc_attributes_size number of bytes in @a enc_attributes + * @param enc_attributes encrypted attribute data + */ +static void +kyc_attribute_cb ( +  void *cls, +  const struct TALER_PaytoHashP *h_payto, +  const char *provider_section, +  const char *birthdate, +  struct GNUNET_TIME_Timestamp collection_time, +  struct GNUNET_TIME_Timestamp expiration_time, +  size_t enc_attributes_size, +  const void *enc_attributes) +{ +  json_t *kyc_attributes = cls; +  json_t *attributes; + +  attributes = NULL; // FIXME + +  GNUNET_assert ( +    0 == +    json_array_append ( +      kyc_attributes, +      GNUNET_JSON_PACK ( +        GNUNET_JSON_pack_string ("provider_section", +                                 provider_section), +        GNUNET_JSON_pack_timestamp ("collection_time", +                                    collection_time), +        GNUNET_JSON_pack_timestamp ("expiration_time", +                                    expiration_time), +        GNUNET_JSON_pack_object_steal ("attributes", +                                       attributes) +        ))); +} + + +/** + * Return historic AML decision(s). + * + * @param[in,out] cls closure with a `json_t *` array to update + * @param new_threshold new monthly threshold that would trigger an AML check + * @param new_status AML decision status + * @param decision_time when was the decision made + * @param justification human-readable text justifying the decision + * @param decider_pub public key of the staff member + * @param decider_sig signature of the staff member + */ +static void +aml_history_cb ( +  void *cls, +  const struct TALER_Amount *new_threshold, +  enum TALER_AmlDecisionState new_status, +  struct GNUNET_TIME_Timestamp decision_time, +  const char *justification, +  const struct TALER_AmlOfficerPublicKeyP *decider_pub, +  const struct TALER_AmlOfficerSignatureP *decider_sig) +{ +  json_t *aml_history = cls; + +  GNUNET_assert ( +    0 == +    json_array_append ( +      aml_history, +      GNUNET_JSON_PACK ( +        GNUNET_JSON_pack_data_auto ("decider_pub", +                                    decider_pub), +        GNUNET_JSON_pack_string ("justification", +                                 justification), +        TALER_JSON_pack_amount ("new_threshold", +                                new_threshold), +        GNUNET_JSON_pack_int64 ("new_status", +                                new_status), +        GNUNET_JSON_pack_timestamp ("decision_time", +                                    decision_time) +        ))); +} + + +MHD_RESULT +TEH_handler_aml_decision_get ( +  struct TEH_RequestContext *rc, +  const struct TALER_AmlOfficerPublicKeyP *officer_pub, +  const char *const args[]) +{ +  struct TALER_AmlOfficerSignatureP officer_sig; +  struct TALER_PaytoHashP h_payto; + +  if ( (NULL == args[0]) || +       (GNUNET_OK != +        GNUNET_STRINGS_string_to_data (args[0], +                                       strlen (args[0]), +                                       &h_payto, +                                       sizeof (h_payto))) ) +  { +    GNUNET_break_op (0); +    return TALER_MHD_reply_with_error (rc->connection, +                                       MHD_HTTP_BAD_REQUEST, +                                       TALER_EC_GENERIC_PARAMETER_MALFORMED, +                                       "h_payto"); +  } + +  if (NULL != args[1]) +  { +    GNUNET_break_op (0); +    return TALER_MHD_reply_with_error (rc->connection, +                                       MHD_HTTP_BAD_REQUEST, +                                       TALER_EC_GENERIC_ENDPOINT_UNKNOWN, +                                       args[1]); +  } +  { +    const char *sig_hdr; + +    sig_hdr = MHD_lookup_connection_value (rc->connection, +                                           MHD_HEADER_KIND, +                                           TALER_AML_OFFICER_SIGNATURE_HEADER); +    if ( (NULL == sig_hdr) || +         (GNUNET_OK != +          GNUNET_STRINGS_string_to_data (sig_hdr, +                                         strlen (sig_hdr), +                                         &officer_sig, +                                         sizeof (officer_sig))) || +         (GNUNET_OK != +          TALER_officer_aml_query_verify (officer_pub, +                                          &officer_sig)) ) +    { +      GNUNET_break_op (0); +      return TALER_MHD_reply_with_error (rc->connection, +                                         MHD_HTTP_BAD_REQUEST, +                                         TALER_EC_EXCHANGE_GENERIC_AML_OFFICER_GET_SIGNATURE_INVALID, +                                         sig_hdr); +    } +    TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++; +  } + +  { +    json_t *aml_history; +    json_t *kyc_attributes; +    enum GNUNET_DB_QueryStatus qs; +    bool none; + +    aml_history = json_array (); +    GNUNET_assert (NULL != aml_history); +    qs = TEH_plugin->select_aml_history (TEH_plugin->cls, +                                         &h_payto, +                                         &aml_history_cb, +                                         aml_history); +    switch (qs) +    { +    case GNUNET_DB_STATUS_HARD_ERROR: +    case GNUNET_DB_STATUS_SOFT_ERROR: +      json_decref (aml_history); +      GNUNET_break (0); +      return TALER_MHD_reply_with_error (rc->connection, +                                         MHD_HTTP_INTERNAL_SERVER_ERROR, +                                         TALER_EC_GENERIC_DB_FETCH_FAILED, +                                         NULL); +    case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: +      none = true; +      break; +    case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: +      none = false; +      break; +    } + +    kyc_attributes = json_array (); +    GNUNET_assert (NULL != kyc_attributes); +    qs = TEH_plugin->select_kyc_attributes (TEH_plugin->cls, +                                            &h_payto, +                                            &kyc_attribute_cb, +                                            kyc_attributes); +    switch (qs) +    { +    case GNUNET_DB_STATUS_HARD_ERROR: +    case GNUNET_DB_STATUS_SOFT_ERROR: +      json_decref (aml_history); +      json_decref (kyc_attributes); +      GNUNET_break (0); +      return TALER_MHD_reply_with_error (rc->connection, +                                         MHD_HTTP_INTERNAL_SERVER_ERROR, +                                         TALER_EC_GENERIC_DB_FETCH_FAILED, +                                         NULL); +    case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: +      if (none) +      { +        json_decref (aml_history); +        json_decref (kyc_attributes); +        return TALER_MHD_reply_static ( +          rc->connection, +          MHD_HTTP_NO_CONTENT, +          NULL, +          NULL, +          0); +      } +      break; +    case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: +      break; +    } +    return TALER_MHD_REPLY_JSON_PACK ( +      rc->connection, +      MHD_HTTP_OK, +      GNUNET_JSON_pack_array_steal ("aml_history", +                                    aml_history), +      GNUNET_JSON_pack_array_steal ("kyc_attributes", +                                    kyc_attributes)); +  } +} + + +/* end of taler-exchange-httpd_aml-decision_get.c */ diff --git a/src/exchange/taler-exchange-httpd_aml-decision.h b/src/exchange/taler-exchange-httpd_aml-decision.h index e31cfdfa..033db4a8 100644 --- a/src/exchange/taler-exchange-httpd_aml-decision.h +++ b/src/exchange/taler-exchange-httpd_aml-decision.h @@ -58,4 +58,22 @@ TEH_handler_aml_decisions_get (    const struct TALER_AmlOfficerPublicKeyP *officer_pub,    const char *const args[]); + +/** + * Handle a GET "/aml/$OFFICER_PUB/decision/$H_PAYTO" request.  Parses the request + * details, checks the signatures and if appropriately authorized returns + * the AML history and KYC attributes for the account. + * + * @param rc request context + * @param officer_pub public key of the AML officer who made the request + * @param args GET arguments (should be one) + * @return MHD result code + */ +MHD_RESULT +TEH_handler_aml_decision_get ( +  struct TEH_RequestContext *rc, +  const struct TALER_AmlOfficerPublicKeyP *officer_pub, +  const char *const args[]); + +  #endif diff --git a/src/exchange/taler-exchange-httpd_aml-decisions-get.c b/src/exchange/taler-exchange-httpd_aml-decisions-get.c index 091e7a67..9f2fae3b 100644 --- a/src/exchange/taler-exchange-httpd_aml-decisions-get.c +++ b/src/exchange/taler-exchange-httpd_aml-decisions-get.c @@ -79,8 +79,6 @@ TEH_handler_aml_decisions_get (    const struct TALER_AmlOfficerPublicKeyP *officer_pub,    const char *const args[])  { -  enum GNUNET_GenericReturnValue res; -  const char *sig_hdr;    struct TALER_AmlOfficerSignatureP officer_sig;    bool frozen = false;    bool pending = false; @@ -96,26 +94,30 @@ TEH_handler_aml_decisions_get (                                         TALER_EC_GENERIC_ENDPOINT_UNKNOWN,                                         args[0]);    } -  sig_hdr = MHD_lookup_connection_value (rc->connection, -                                         MHD_HEADER_KIND, -                                         TALER_AML_OFFICER_SIGNATURE_HEADER); -  if ( (NULL == sig_hdr) || -       (GNUNET_OK != -        GNUNET_STRINGS_string_to_data (sig_hdr, -                                       strlen (sig_hdr), -                                       &officer_sig, -                                       sizeof (officer_sig))) || -       (GNUNET_OK != -        TALER_officer_aml_query_verify (officer_pub, -                                        &officer_sig)) )    { -    GNUNET_break_op (0); -    return TALER_MHD_reply_with_error (rc->connection, -                                       MHD_HTTP_BAD_REQUEST, -                                       TALER_EC_EXCHANGE_GENERIC_AML_OFFICER_GET_SIGNATURE_INVALID, -                                       sig_hdr); +    const char *sig_hdr; + +    sig_hdr = MHD_lookup_connection_value (rc->connection, +                                           MHD_HEADER_KIND, +                                           TALER_AML_OFFICER_SIGNATURE_HEADER); +    if ( (NULL == sig_hdr) || +         (GNUNET_OK != +          GNUNET_STRINGS_string_to_data (sig_hdr, +                                         strlen (sig_hdr), +                                         &officer_sig, +                                         sizeof (officer_sig))) || +         (GNUNET_OK != +          TALER_officer_aml_query_verify (officer_pub, +                                          &officer_sig)) ) +    { +      GNUNET_break_op (0); +      return TALER_MHD_reply_with_error (rc->connection, +                                         MHD_HTTP_BAD_REQUEST, +                                         TALER_EC_EXCHANGE_GENERIC_AML_OFFICER_GET_SIGNATURE_INVALID, +                                         sig_hdr); +    } +    TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;    } -  TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;    {      const char *p; @@ -225,4 +227,4 @@ TEH_handler_aml_decisions_get (  } -/* end of taler-exchange-httpd_deposits_get.c */ +/* end of taler-exchange-httpd_aml-decisions_get.c */ | 
