LCOV - code coverage report
Current view: top level - exchange - taler-exchange-httpd_kyc-webhook.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 0 73 0.0 %
Date: 2022-08-25 06:15:09 Functions: 0 7 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2022 Taler Systems SA
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it under the
       6             :   terms of the GNU Affero General Public License as published by the Free Software
       7             :   Foundation; either version 3, or (at your option) any later version.
       8             : 
       9             :   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
      10             :   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
      11             :   A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
      12             : 
      13             :   You should have received a copy of the GNU Affero General Public License along with
      14             :   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15             : */
      16             : /**
      17             :  * @file taler-exchange-httpd_kyc-webhook.c
      18             :  * @brief Handle notification of KYC completion via webhook.
      19             :  * @author Christian Grothoff
      20             :  */
      21             : #include "platform.h"
      22             : #include <gnunet/gnunet_util_lib.h>
      23             : #include <gnunet/gnunet_json_lib.h>
      24             : #include <jansson.h>
      25             : #include <microhttpd.h>
      26             : #include <pthread.h>
      27             : #include "taler_json_lib.h"
      28             : #include "taler_mhd_lib.h"
      29             : #include "taler_kyclogic_lib.h"
      30             : #include "taler-exchange-httpd_kyc-webhook.h"
      31             : #include "taler-exchange-httpd_responses.h"
      32             : 
      33             : 
      34             : /**
      35             :  * Context for the webhook.
      36             :  */
      37             : struct KycWebhookContext
      38             : {
      39             : 
      40             :   /**
      41             :    * Kept in a DLL while suspended.
      42             :    */
      43             :   struct KycWebhookContext *next;
      44             : 
      45             :   /**
      46             :    * Kept in a DLL while suspended.
      47             :    */
      48             :   struct KycWebhookContext *prev;
      49             : 
      50             :   /**
      51             :    * Details about the connection we are processing.
      52             :    */
      53             :   struct TEH_RequestContext *rc;
      54             : 
      55             :   /**
      56             :    * Plugin responsible for the webhook.
      57             :    */
      58             :   struct TALER_KYCLOGIC_Plugin *plugin;
      59             : 
      60             :   /**
      61             :    * Section in the configuration of the configured
      62             :    * KYC provider.
      63             :    */
      64             :   const char *provider_section;
      65             : 
      66             :   /**
      67             :    * Configuration for the specific action.
      68             :    */
      69             :   struct TALER_KYCLOGIC_ProviderDetails *pd;
      70             : 
      71             :   /**
      72             :    * Webhook activity.
      73             :    */
      74             :   struct TALER_KYCLOGIC_WebhookHandle *wh;
      75             : 
      76             :   /**
      77             :    * HTTP response to return.
      78             :    */
      79             :   struct MHD_Response *response;
      80             : 
      81             :   /**
      82             :    * HTTP response code to return.
      83             :    */
      84             :   unsigned int response_code;
      85             : 
      86             :   /**
      87             :    * #GNUNET_YES if we are suspended,
      88             :    * #GNUNET_NO if not.
      89             :    * #GNUNET_SYSERR if we had some error.
      90             :    */
      91             :   enum GNUNET_GenericReturnValue suspended;
      92             : 
      93             : };
      94             : 
      95             : 
      96             : /**
      97             :  * Contexts are kept in a DLL while suspended.
      98             :  */
      99             : static struct KycWebhookContext *kwh_head;
     100             : 
     101             : /**
     102             :  * Contexts are kept in a DLL while suspended.
     103             :  */
     104             : static struct KycWebhookContext *kwh_tail;
     105             : 
     106             : 
     107             : /**
     108             :  * Resume processing the @a kwh request.
     109             :  *
     110             :  * @param kwh request to resume
     111             :  */
     112             : static void
     113           0 : kwh_resume (struct KycWebhookContext *kwh)
     114             : {
     115           0 :   GNUNET_assert (GNUNET_YES == kwh->suspended);
     116           0 :   kwh->suspended = GNUNET_NO;
     117           0 :   GNUNET_CONTAINER_DLL_remove (kwh_head,
     118             :                                kwh_tail,
     119             :                                kwh);
     120           0 :   MHD_resume_connection (kwh->rc->connection);
     121           0 :   TALER_MHD_daemon_trigger ();
     122           0 : }
     123             : 
     124             : 
     125             : void
     126           0 : TEH_kyc_webhook_cleanup (void)
     127             : {
     128             :   struct KycWebhookContext *kwh;
     129             : 
     130           0 :   while (NULL != (kwh = kwh_head))
     131             :   {
     132           0 :     if (NULL != kwh->wh)
     133             :     {
     134           0 :       kwh->plugin->webhook_cancel (kwh->wh);
     135           0 :       kwh->wh = NULL;
     136             :     }
     137           0 :     kwh_resume (kwh);
     138             :   }
     139           0 : }
     140             : 
     141             : 
     142             : /**
     143             :  * Function called with the result of a webhook
     144             :  * operation.
     145             :  *
     146             :  * Note that the "decref" for the @a response
     147             :  * will be done by the plugin.
     148             :  *
     149             :  * @param cls closure
     150             :  * @param process_row legitimization process the webhook was about
     151             :  * @param account_id account the webhook was about
     152             :  * @param provider_section name of the configuration section of the logic that was run
     153             :  * @param provider_user_id set to user ID at the provider, or NULL if not supported or unknown
     154             :  * @param provider_legitimization_id set to legitimization process ID at the provider, or NULL if not supported or unknown
     155             :  * @param status KYC status
     156             :  * @param expiration until when is the KYC check valid
     157             :  * @param http_status HTTP status code of @a response
     158             :  * @param[in] response to return to the HTTP client
     159             :  */
     160             : static void
     161           0 : webhook_finished_cb (
     162             :   void *cls,
     163             :   uint64_t process_row,
     164             :   const struct TALER_PaytoHashP *account_id,
     165             :   const char *provider_section,
     166             :   const char *provider_user_id,
     167             :   const char *provider_legitimization_id,
     168             :   enum TALER_KYCLOGIC_KycStatus status,
     169             :   struct GNUNET_TIME_Absolute expiration,
     170             :   unsigned int http_status,
     171             :   struct MHD_Response *response)
     172             : {
     173           0 :   struct KycWebhookContext *kwh = cls;
     174             : 
     175           0 :   kwh->wh = NULL;
     176           0 :   switch (status)
     177             :   {
     178           0 :   case TALER_KYCLOGIC_STATUS_SUCCESS:
     179             :     /* _successfully_ resumed case */
     180             :     {
     181             :       enum GNUNET_DB_QueryStatus qs;
     182             : 
     183           0 :       qs = TEH_plugin->update_kyc_process_by_row (TEH_plugin->cls,
     184             :                                                   process_row,
     185             :                                                   provider_section,
     186             :                                                   account_id,
     187             :                                                   provider_user_id,
     188             :                                                   provider_legitimization_id,
     189             :                                                   expiration);
     190           0 :       if (qs < 0)
     191             :       {
     192           0 :         GNUNET_break (0);
     193           0 :         kwh->response = TALER_MHD_make_error (TALER_EC_GENERIC_DB_STORE_FAILED,
     194             :                                               "set_kyc_ok");
     195           0 :         kwh->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
     196           0 :         kwh_resume (kwh);
     197           0 :         return;
     198             :       }
     199             :     }
     200           0 :     break;
     201           0 :   default:
     202           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     203             :                 "KYC status of %s/%s (Row #%llu) is %d\n",
     204             :                 provider_user_id,
     205             :                 provider_legitimization_id,
     206             :                 (unsigned long long) process_row,
     207             :                 status);
     208           0 :     break;
     209             :   }
     210           0 :   kwh->response = response;
     211           0 :   kwh->response_code = http_status;
     212           0 :   kwh_resume (kwh);
     213             : }
     214             : 
     215             : 
     216             : /**
     217             :  * Function called to clean up a context.
     218             :  *
     219             :  * @param rc request context
     220             :  */
     221             : static void
     222           0 : clean_kwh (struct TEH_RequestContext *rc)
     223             : {
     224           0 :   struct KycWebhookContext *kwh = rc->rh_ctx;
     225             : 
     226           0 :   if (NULL != kwh->wh)
     227             :   {
     228           0 :     kwh->plugin->webhook_cancel (kwh->wh);
     229           0 :     kwh->wh = NULL;
     230             :   }
     231           0 :   if (NULL != kwh->response)
     232             :   {
     233           0 :     MHD_destroy_response (kwh->response);
     234           0 :     kwh->response = NULL;
     235             :   }
     236           0 :   GNUNET_free (kwh);
     237           0 : }
     238             : 
     239             : 
     240             : /**
     241             :  * Handle a (GET or POST) "/kyc-webhook" request.
     242             :  *
     243             :  * @param rc request to handle
     244             :  * @param method HTTP request method used by the client
     245             :  * @param root uploaded JSON body (can be NULL)
     246             :  * @param args one argument with the legitimization_uuid
     247             :  * @return MHD result code
     248             :  */
     249             : static MHD_RESULT
     250           0 : handler_kyc_webhook_generic (
     251             :   struct TEH_RequestContext *rc,
     252             :   const char *method,
     253             :   const json_t *root,
     254             :   const char *const args[])
     255             : {
     256           0 :   struct KycWebhookContext *kwh = rc->rh_ctx;
     257             : 
     258           0 :   if (NULL == kwh)
     259             :   { /* first time */
     260           0 :     kwh = GNUNET_new (struct KycWebhookContext);
     261           0 :     kwh->rc = rc;
     262           0 :     rc->rh_ctx = kwh;
     263           0 :     rc->rh_cleaner = &clean_kwh;
     264             : 
     265           0 :     if (GNUNET_OK !=
     266           0 :         TALER_KYCLOGIC_lookup_logic (args[0],
     267             :                                      &kwh->plugin,
     268             :                                      &kwh->pd,
     269             :                                      &kwh->provider_section))
     270             :     {
     271           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     272             :                   "KYC logic `%s' unknown (check KYC provider configuration)\n",
     273             :                   args[0]);
     274           0 :       return TALER_MHD_reply_with_error (rc->connection,
     275             :                                          MHD_HTTP_NOT_FOUND,
     276             :                                          TALER_EC_EXCHANGE_KYC_GENERIC_LOGIC_UNKNOWN,
     277             :                                          "$NAME");
     278             :     }
     279           0 :     kwh->wh = kwh->plugin->webhook (kwh->plugin->cls,
     280           0 :                                     kwh->pd,
     281           0 :                                     TEH_plugin->kyc_provider_account_lookup,
     282           0 :                                     TEH_plugin->cls,
     283             :                                     method,
     284             :                                     &args[1],
     285             :                                     rc->connection,
     286             :                                     root,
     287             :                                     &webhook_finished_cb,
     288             :                                     kwh);
     289           0 :     if (NULL == kwh->wh)
     290             :     {
     291           0 :       GNUNET_break_op (0);
     292           0 :       return TALER_MHD_reply_with_error (rc->connection,
     293             :                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
     294             :                                          TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
     295             :                                          "failed to run webhook logic");
     296             :     }
     297           0 :     kwh->suspended = GNUNET_YES;
     298           0 :     GNUNET_CONTAINER_DLL_insert (kwh_head,
     299             :                                  kwh_tail,
     300             :                                  kwh);
     301           0 :     MHD_suspend_connection (rc->connection);
     302           0 :     return MHD_YES;
     303             :   }
     304             : 
     305           0 :   if (NULL != kwh->response)
     306             :   {
     307             :     /* handle _failed_ resumed cases */
     308           0 :     return MHD_queue_response (rc->connection,
     309             :                                kwh->response_code,
     310             :                                kwh->response);
     311             :   }
     312             : 
     313             :   /* We resumed, but got no response? This should
     314             :      not happen. */
     315           0 :   GNUNET_break (0);
     316           0 :   return TALER_MHD_reply_with_error (rc->connection,
     317             :                                      MHD_HTTP_INTERNAL_SERVER_ERROR,
     318             :                                      TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
     319             :                                      "resumed without response");
     320             : }
     321             : 
     322             : 
     323             : MHD_RESULT
     324           0 : TEH_handler_kyc_webhook_get (
     325             :   struct TEH_RequestContext *rc,
     326             :   const char *const args[])
     327             : {
     328           0 :   return handler_kyc_webhook_generic (rc,
     329             :                                       MHD_HTTP_METHOD_GET,
     330             :                                       NULL,
     331             :                                       args);
     332             : }
     333             : 
     334             : 
     335             : MHD_RESULT
     336           0 : TEH_handler_kyc_webhook_post (
     337             :   struct TEH_RequestContext *rc,
     338             :   const json_t *root,
     339             :   const char *const args[])
     340             : {
     341           0 :   return handler_kyc_webhook_generic (rc,
     342             :                                       MHD_HTTP_METHOD_POST,
     343             :                                       root,
     344             :                                       args);
     345             : }
     346             : 
     347             : 
     348             : /* end of taler-exchange-httpd_kyc-webhook.c */

Generated by: LCOV version 1.14