LCOV - code coverage report
Current view: top level - kyclogic - plugin_kyclogic_kycaid.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 36 409 8.8 %
Date: 2022-08-25 06:15:09 Functions: 2 15 13.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of GNU 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.GPL.  If not, see <http://www.gnu.org/licenses/>
      15             : */
      16             : /**
      17             :  * @file plugin_kyclogic_kycaid.c
      18             :  * @brief kycaid for an authentication flow logic
      19             :  * @author Christian Grothoff
      20             :  */
      21             : #include "platform.h"
      22             : #include "taler_kyclogic_plugin.h"
      23             : #include "taler_mhd_lib.h"
      24             : #include "taler_curl_lib.h"
      25             : #include "taler_json_lib.h"
      26             : #include <regex.h>
      27             : #include "taler_util.h"
      28             : 
      29             : 
      30             : /**
      31             :  * Saves the state of a plugin.
      32             :  */
      33             : struct PluginState
      34             : {
      35             : 
      36             :   /**
      37             :    * Our base URL.
      38             :    */
      39             :   char *exchange_base_url;
      40             : 
      41             :   /**
      42             :    * Our global configuration.
      43             :    */
      44             :   const struct GNUNET_CONFIGURATION_Handle *cfg;
      45             : 
      46             :   /**
      47             :    * Context for CURL operations (useful to the event loop)
      48             :    */
      49             :   struct GNUNET_CURL_Context *curl_ctx;
      50             : 
      51             :   /**
      52             :    * Context for integrating @e curl_ctx with the
      53             :    * GNUnet event loop.
      54             :    */
      55             :   struct GNUNET_CURL_RescheduleContext *curl_rc;
      56             : 
      57             : };
      58             : 
      59             : 
      60             : /**
      61             :  * Keeps the plugin-specific state for
      62             :  * a given configuration section.
      63             :  */
      64             : struct TALER_KYCLOGIC_ProviderDetails
      65             : {
      66             : 
      67             :   /**
      68             :    * Overall plugin state.
      69             :    */
      70             :   struct PluginState *ps;
      71             : 
      72             :   /**
      73             :    * Configuration section that configured us.
      74             :    */
      75             :   char *section;
      76             : 
      77             :   /**
      78             :    * Authorization token to use when talking
      79             :    * to the service.
      80             :    */
      81             :   char *auth_token;
      82             : 
      83             :   /**
      84             :    * Form ID for the KYC check to perform.
      85             :    */
      86             :   char *form_id;
      87             : 
      88             :   /**
      89             :    * Validity time for a successful KYC process.
      90             :    */
      91             :   struct GNUNET_TIME_Relative validity;
      92             : 
      93             :   /**
      94             :    * Curl-ready authentication header to use.
      95             :    */
      96             :   struct curl_slist *slist;
      97             : 
      98             : };
      99             : 
     100             : 
     101             : /**
     102             :  * Handle for an initiation operation.
     103             :  */
     104             : struct TALER_KYCLOGIC_InitiateHandle
     105             : {
     106             : 
     107             :   /**
     108             :    * Hash of the payto:// URI we are initiating
     109             :    * the KYC for.
     110             :    */
     111             :   struct TALER_PaytoHashP h_payto;
     112             : 
     113             :   /**
     114             :    * UUID being checked.
     115             :    */
     116             :   uint64_t legitimization_uuid;
     117             : 
     118             :   /**
     119             :    * Our configuration details.
     120             :    */
     121             :   const struct TALER_KYCLOGIC_ProviderDetails *pd;
     122             : 
     123             :   /**
     124             :    * Continuation to call.
     125             :    */
     126             :   TALER_KYCLOGIC_InitiateCallback cb;
     127             : 
     128             :   /**
     129             :    * Closure for @a cb.
     130             :    */
     131             :   void *cb_cls;
     132             : 
     133             :   /**
     134             :    * Context for #TEH_curl_easy_post(). Keeps the data that must
     135             :    * persist for Curl to make the upload.
     136             :    */
     137             :   struct TALER_CURL_PostContext ctx;
     138             : 
     139             :   /**
     140             :    * Handle for the request.
     141             :    */
     142             :   struct GNUNET_CURL_Job *job;
     143             : 
     144             :   /**
     145             :    * URL of the cURL request.
     146             :    */
     147             :   char *url;
     148             : 
     149             : };
     150             : 
     151             : 
     152             : /**
     153             :  * Handle for an KYC proof operation.
     154             :  */
     155             : struct TALER_KYCLOGIC_ProofHandle
     156             : {
     157             : 
     158             :   /**
     159             :    * Overall plugin state.
     160             :    */
     161             :   struct PluginState *ps;
     162             : 
     163             :   /**
     164             :    * Our configuration details.
     165             :    */
     166             :   const struct TALER_KYCLOGIC_ProviderDetails *pd;
     167             : 
     168             :   /**
     169             :    * Continuation to call.
     170             :    */
     171             :   TALER_KYCLOGIC_ProofCallback cb;
     172             : 
     173             :   /**
     174             :    * Closure for @e cb.
     175             :    */
     176             :   void *cb_cls;
     177             : 
     178             :   /**
     179             :    * Connection we are handling.
     180             :    */
     181             :   struct MHD_Connection *connection;
     182             : 
     183             :   /**
     184             :    * Task for asynchronous execution.
     185             :    */
     186             :   struct GNUNET_SCHEDULER_Task *task;
     187             : };
     188             : 
     189             : 
     190             : /**
     191             :  * Handle for an KYC Web hook operation.
     192             :  */
     193             : struct TALER_KYCLOGIC_WebhookHandle
     194             : {
     195             : 
     196             :   /**
     197             :    * Continuation to call when done.
     198             :    */
     199             :   TALER_KYCLOGIC_WebhookCallback cb;
     200             : 
     201             :   /**
     202             :    * Closure for @a cb.
     203             :    */
     204             :   void *cb_cls;
     205             : 
     206             :   /**
     207             :    * Task for asynchronous execution.
     208             :    */
     209             :   struct GNUNET_SCHEDULER_Task *task;
     210             : 
     211             :   /**
     212             :    * Overall plugin state.
     213             :    */
     214             :   struct PluginState *ps;
     215             : 
     216             :   /**
     217             :    * Our configuration details.
     218             :    */
     219             :   const struct TALER_KYCLOGIC_ProviderDetails *pd;
     220             : 
     221             :   /**
     222             :    * Connection we are handling.
     223             :    */
     224             :   struct MHD_Connection *connection;
     225             : 
     226             :   /**
     227             :    * Verification ID from the service.
     228             :    */
     229             :   char *verification_id;
     230             : 
     231             :   /**
     232             :    * Applicant ID from the service.
     233             :    */
     234             :   char *applicant_id;
     235             : 
     236             :   /**
     237             :    * URL of the cURL request.
     238             :    */
     239             :   char *url;
     240             : 
     241             :   /**
     242             :    * Handle for the request.
     243             :    */
     244             :   struct GNUNET_CURL_Job *job;
     245             : 
     246             :   /**
     247             :    * Response to return asynchronously.
     248             :    */
     249             :   struct MHD_Response *resp;
     250             : 
     251             :   /**
     252             :    * Our account ID.
     253             :    */
     254             :   struct TALER_PaytoHashP h_payto;
     255             : 
     256             :   /**
     257             :    * Row in legitimizations for the given
     258             :    * @e verification_id.
     259             :    */
     260             :   uint64_t process_row;
     261             : 
     262             :   /**
     263             :    * HTTP response code to return asynchronously.
     264             :    */
     265             :   unsigned int response_code;
     266             : };
     267             : 
     268             : 
     269             : /**
     270             :  * Release configuration resources previously loaded
     271             :  *
     272             :  * @param[in] pd configuration to release
     273             :  */
     274             : static void
     275           0 : kycaid_unload_configuration (struct TALER_KYCLOGIC_ProviderDetails *pd)
     276             : {
     277           0 :   curl_slist_free_all (pd->slist);
     278           0 :   GNUNET_free (pd->auth_token);
     279           0 :   GNUNET_free (pd->form_id);
     280           0 :   GNUNET_free (pd->section);
     281           0 :   GNUNET_free (pd);
     282           0 : }
     283             : 
     284             : 
     285             : /**
     286             :  * Load the configuration of the KYC provider.
     287             :  *
     288             :  * @param cls closure
     289             :  * @param provider_section_name configuration section to parse
     290             :  * @return NULL if configuration is invalid
     291             :  */
     292             : static struct TALER_KYCLOGIC_ProviderDetails *
     293           1 : kycaid_load_configuration (void *cls,
     294             :                            const char *provider_section_name)
     295             : {
     296           1 :   struct PluginState *ps = cls;
     297             :   struct TALER_KYCLOGIC_ProviderDetails *pd;
     298             : 
     299           1 :   pd = GNUNET_new (struct TALER_KYCLOGIC_ProviderDetails);
     300           1 :   pd->ps = ps;
     301           1 :   pd->section = GNUNET_strdup (provider_section_name);
     302           1 :   if (GNUNET_OK !=
     303           1 :       GNUNET_CONFIGURATION_get_value_time (ps->cfg,
     304             :                                            provider_section_name,
     305             :                                            "KYC_KYCAID_VALIDITY",
     306             :                                            &pd->validity))
     307             :   {
     308           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     309             :                                provider_section_name,
     310             :                                "KYC_KYCAID_VALIDITY");
     311           0 :     kycaid_unload_configuration (pd);
     312           0 :     return NULL;
     313             :   }
     314           1 :   if (GNUNET_OK !=
     315           1 :       GNUNET_CONFIGURATION_get_value_string (ps->cfg,
     316             :                                              provider_section_name,
     317             :                                              "KYC_KYCAID_AUTH_TOKEN",
     318             :                                              &pd->auth_token))
     319             :   {
     320           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     321             :                                provider_section_name,
     322             :                                "KYC_KYCAID_AUTH_TOKEN");
     323           0 :     kycaid_unload_configuration (pd);
     324           0 :     return NULL;
     325             :   }
     326           1 :   if (GNUNET_OK !=
     327           1 :       GNUNET_CONFIGURATION_get_value_string (ps->cfg,
     328             :                                              provider_section_name,
     329             :                                              "KYC_KYCAID_FORM_ID",
     330             :                                              &pd->form_id))
     331             :   {
     332           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     333             :                                provider_section_name,
     334             :                                "KYC_KYCAID_FORM_ID");
     335           0 :     kycaid_unload_configuration (pd);
     336           0 :     return NULL;
     337             :   }
     338             :   {
     339             :     char *auth;
     340             : 
     341           1 :     GNUNET_asprintf (&auth,
     342             :                      "%s: Token %s",
     343             :                      MHD_HTTP_HEADER_AUTHORIZATION,
     344             :                      pd->auth_token);
     345           1 :     pd->slist = curl_slist_append (NULL,
     346             :                                    auth);
     347           1 :     GNUNET_free (auth);
     348             :   }
     349           1 :   return pd;
     350             : }
     351             : 
     352             : 
     353             : /**
     354             :  * Cancel KYC check initiation.
     355             :  *
     356             :  * @param[in] ih handle of operation to cancel
     357             :  */
     358             : static void
     359           0 : kycaid_initiate_cancel (struct TALER_KYCLOGIC_InitiateHandle *ih)
     360             : {
     361           0 :   if (NULL != ih->job)
     362             :   {
     363           0 :     GNUNET_CURL_job_cancel (ih->job);
     364           0 :     ih->job = NULL;
     365             :   }
     366           0 :   GNUNET_free (ih->url);
     367           0 :   TALER_curl_easy_post_finished (&ih->ctx);
     368           0 :   GNUNET_free (ih);
     369           0 : }
     370             : 
     371             : 
     372             : /**
     373             :  * Function called when we're done processing the
     374             :  * HTTP "/forms/{form_id}/urls" request.
     375             :  *
     376             :  * @param cls the `struct TALER_KYCLOGIC_InitiateHandle`
     377             :  * @param response_code HTTP response code, 0 on error
     378             :  * @param response parsed JSON result, NULL on error
     379             :  */
     380             : static void
     381           0 : handle_initiate_finished (void *cls,
     382             :                           long response_code,
     383             :                           const void *response)
     384             : {
     385           0 :   struct TALER_KYCLOGIC_InitiateHandle *ih = cls;
     386           0 :   const json_t *j = response;
     387             : 
     388           0 :   ih->job = NULL;
     389           0 :   switch (response_code)
     390             :   {
     391           0 :   case MHD_HTTP_OK:
     392             :     {
     393             :       const char *verification_id;
     394             :       const char *form_url;
     395             :       struct GNUNET_JSON_Specification spec[] = {
     396           0 :         GNUNET_JSON_spec_string ("verification_id",
     397             :                                  &verification_id),
     398           0 :         GNUNET_JSON_spec_string ("form_url",
     399             :                                  &form_url),
     400           0 :         GNUNET_JSON_spec_end ()
     401             :       };
     402             : 
     403           0 :       if (GNUNET_OK !=
     404           0 :           GNUNET_JSON_parse (j,
     405             :                              spec,
     406             :                              NULL, NULL))
     407             :       {
     408           0 :         GNUNET_break_op (0);
     409           0 :         json_dumpf (j,
     410             :                     stderr,
     411             :                     JSON_INDENT (2));
     412           0 :         ih->cb (ih->cb_cls,
     413             :                 TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_UNEXPECTED_REPLY,
     414             :                 NULL,
     415             :                 NULL,
     416             :                 NULL,
     417           0 :                 json_string_value (json_object_get (j,
     418             :                                                     "type")));
     419           0 :         break;
     420             :       }
     421           0 :       ih->cb (ih->cb_cls,
     422             :               TALER_EC_NONE,
     423             :               form_url,
     424             :               NULL, /* no provider_user_id */
     425             :               verification_id,
     426             :               NULL /* no error */);
     427           0 :       GNUNET_JSON_parse_free (spec);
     428             :     }
     429           0 :     break;
     430           0 :   case MHD_HTTP_BAD_REQUEST:
     431             :   case MHD_HTTP_NOT_FOUND:
     432             :   case MHD_HTTP_CONFLICT:
     433           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     434             :                 "KYCAID failed with response %u:\n",
     435             :                 (unsigned int) response_code);
     436           0 :     json_dumpf (j,
     437             :                 stderr,
     438             :                 JSON_INDENT (2));
     439           0 :     ih->cb (ih->cb_cls,
     440             :             TALER_EC_EXCHANGE_KYC_GENERIC_LOGIC_BUG,
     441             :             NULL,
     442             :             NULL,
     443             :             NULL,
     444           0 :             json_string_value (json_object_get (j,
     445             :                                                 "type")));
     446           0 :     break;
     447           0 :   case MHD_HTTP_UNAUTHORIZED:
     448             :   case MHD_HTTP_PAYMENT_REQUIRED:
     449           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     450             :                 "Refused access with HTTP status code %u\n",
     451             :                 (unsigned int) response_code);
     452           0 :     ih->cb (ih->cb_cls,
     453             :             TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_ACCESS_REFUSED,
     454             :             NULL,
     455             :             NULL,
     456             :             NULL,
     457           0 :             json_string_value (json_object_get (j,
     458             :                                                 "type")));
     459           0 :     break;
     460           0 :   case MHD_HTTP_REQUEST_TIMEOUT:
     461           0 :     ih->cb (ih->cb_cls,
     462             :             TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_TIMEOUT,
     463             :             NULL,
     464             :             NULL,
     465             :             NULL,
     466           0 :             json_string_value (json_object_get (j,
     467             :                                                 "type")));
     468           0 :     break;
     469           0 :   case MHD_HTTP_UNPROCESSABLE_ENTITY: /* validation */
     470           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     471             :                 "KYCAID failed with response %u:\n",
     472             :                 (unsigned int) response_code);
     473           0 :     json_dumpf (j,
     474             :                 stderr,
     475             :                 JSON_INDENT (2));
     476           0 :     ih->cb (ih->cb_cls,
     477             :             TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_UNEXPECTED_REPLY,
     478             :             NULL,
     479             :             NULL,
     480             :             NULL,
     481           0 :             json_string_value (json_object_get (j,
     482             :                                                 "type")));
     483           0 :     break;
     484           0 :   case MHD_HTTP_TOO_MANY_REQUESTS:
     485           0 :     ih->cb (ih->cb_cls,
     486             :             TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_RATE_LIMIT_EXCEEDED,
     487             :             NULL,
     488             :             NULL,
     489             :             NULL,
     490           0 :             json_string_value (json_object_get (j,
     491             :                                                 "type")));
     492           0 :     break;
     493           0 :   case MHD_HTTP_INTERNAL_SERVER_ERROR:
     494           0 :     ih->cb (ih->cb_cls,
     495             :             TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_UNEXPECTED_REPLY,
     496             :             NULL,
     497             :             NULL,
     498             :             NULL,
     499           0 :             json_string_value (json_object_get (j,
     500             :                                                 "type")));
     501           0 :     break;
     502           0 :   default:
     503           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     504             :                 "Unexpected KYCAID response %u:\n",
     505             :                 (unsigned int) response_code);
     506           0 :     json_dumpf (j,
     507             :                 stderr,
     508             :                 JSON_INDENT (2));
     509           0 :     ih->cb (ih->cb_cls,
     510             :             TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_UNEXPECTED_REPLY,
     511             :             NULL,
     512             :             NULL,
     513             :             NULL,
     514           0 :             json_string_value (json_object_get (j,
     515             :                                                 "type")));
     516           0 :     break;
     517             :   }
     518           0 :   kycaid_initiate_cancel (ih);
     519           0 : }
     520             : 
     521             : 
     522             : /**
     523             :  * Initiate KYC check.
     524             :  *
     525             :  * @param cls the @e cls of this struct with the plugin-specific state
     526             :  * @param pd provider configuration details
     527             :  * @param account_id which account to trigger process for
     528             :  * @param legitimization_uuid unique ID for the legitimization process
     529             :  * @param cb function to call with the result
     530             :  * @param cb_cls closure for @a cb
     531             :  * @return handle to cancel operation early
     532             :  */
     533             : static struct TALER_KYCLOGIC_InitiateHandle *
     534           0 : kycaid_initiate (void *cls,
     535             :                  const struct TALER_KYCLOGIC_ProviderDetails *pd,
     536             :                  const struct TALER_PaytoHashP *account_id,
     537             :                  uint64_t legitimization_uuid,
     538             :                  TALER_KYCLOGIC_InitiateCallback cb,
     539             :                  void *cb_cls)
     540             : {
     541           0 :   struct PluginState *ps = cls;
     542             :   struct TALER_KYCLOGIC_InitiateHandle *ih;
     543             :   json_t *body;
     544             :   CURL *eh;
     545             : 
     546           0 :   eh = curl_easy_init ();
     547           0 :   if (NULL == eh)
     548             :   {
     549           0 :     GNUNET_break (0);
     550           0 :     return NULL;
     551             :   }
     552           0 :   ih = GNUNET_new (struct TALER_KYCLOGIC_InitiateHandle);
     553           0 :   ih->legitimization_uuid = legitimization_uuid;
     554           0 :   ih->cb = cb;
     555           0 :   ih->cb_cls = cb_cls;
     556           0 :   ih->h_payto = *account_id;
     557           0 :   ih->pd = pd;
     558           0 :   GNUNET_asprintf (&ih->url,
     559             :                    "https://api.kycaid.com/forms/%s/urls",
     560             :                    pd->form_id);
     561           0 :   body = GNUNET_JSON_PACK (
     562             :     GNUNET_JSON_pack_data64_auto ("external_applicant_id",
     563             :                                   account_id)
     564             :     );
     565           0 :   GNUNET_break (CURLE_OK ==
     566             :                 curl_easy_setopt (eh,
     567             :                                   CURLOPT_VERBOSE,
     568             :                                   0));
     569           0 :   GNUNET_assert (CURLE_OK ==
     570             :                  curl_easy_setopt (eh,
     571             :                                    CURLOPT_MAXREDIRS,
     572             :                                    1L));
     573           0 :   GNUNET_break (CURLE_OK ==
     574             :                 curl_easy_setopt (eh,
     575             :                                   CURLOPT_URL,
     576             :                                   ih->url));
     577           0 :   if (GNUNET_OK !=
     578           0 :       TALER_curl_easy_post (&ih->ctx,
     579             :                             eh,
     580             :                             body))
     581             :   {
     582           0 :     GNUNET_break (0);
     583           0 :     GNUNET_free (ih->url);
     584           0 :     GNUNET_free (ih);
     585           0 :     curl_easy_cleanup (eh);
     586           0 :     json_decref (body);
     587           0 :     return NULL;
     588             :   }
     589           0 :   ih->job = GNUNET_CURL_job_add2 (ps->curl_ctx,
     590             :                                   eh,
     591           0 :                                   ih->ctx.headers,
     592             :                                   &handle_initiate_finished,
     593             :                                   ih);
     594           0 :   GNUNET_CURL_extend_headers (ih->job,
     595           0 :                               pd->slist);
     596           0 :   return ih;
     597             : }
     598             : 
     599             : 
     600             : /**
     601             :  * Cancel KYC proof.
     602             :  *
     603             :  * @param[in] ph handle of operation to cancel
     604             :  */
     605             : static void
     606           0 : kycaid_proof_cancel (struct TALER_KYCLOGIC_ProofHandle *ph)
     607             : {
     608           0 :   if (NULL != ph->task)
     609             :   {
     610           0 :     GNUNET_SCHEDULER_cancel (ph->task);
     611           0 :     ph->task = NULL;
     612             :   }
     613           0 :   GNUNET_free (ph);
     614           0 : }
     615             : 
     616             : 
     617             : /**
     618             :  * Call @a ph callback with HTTP error response.
     619             :  *
     620             :  * @param cls proof handle to generate reply for
     621             :  */
     622             : static void
     623           0 : proof_reply (void *cls)
     624             : {
     625           0 :   struct TALER_KYCLOGIC_ProofHandle *ph = cls;
     626             :   struct MHD_Response *resp;
     627             : 
     628           0 :   resp = TALER_MHD_make_error (TALER_EC_GENERIC_ENDPOINT_UNKNOWN,
     629             :                                "there is no '/kyc-proof' for kycaid");
     630           0 :   ph->cb (ph->cb_cls,
     631             :           TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
     632             :           NULL, /* user id */
     633             :           NULL, /* provider legi ID */
     634           0 :           GNUNET_TIME_UNIT_ZERO_ABS, /* expiration */
     635             :           MHD_HTTP_BAD_REQUEST,
     636             :           resp);
     637           0 : }
     638             : 
     639             : 
     640             : /**
     641             :  * Check KYC status and return status to human. Not
     642             :  * used by KYC AID!
     643             :  *
     644             :  * @param cls the @e cls of this struct with the plugin-specific state
     645             :  * @param pd provider configuration details
     646             :  * @param url_path rest of the URL after `/kyc-webhook/`
     647             :  * @param connection MHD connection object (for HTTP headers)
     648             :  * @param account_id which account to trigger process for
     649             :  * @param process_row row in the legitimization processes table the legitimization is for
     650             :  * @param provider_user_id user ID (or NULL) the proof is for
     651             :  * @param provider_legitimization_id legitimization ID the proof is for
     652             :  * @param cb function to call with the result
     653             :  * @param cb_cls closure for @a cb
     654             :  * @return handle to cancel operation early
     655             :  */
     656             : static struct TALER_KYCLOGIC_ProofHandle *
     657           0 : kycaid_proof (void *cls,
     658             :               const struct TALER_KYCLOGIC_ProviderDetails *pd,
     659             :               const char *const url_path[],
     660             :               struct MHD_Connection *connection,
     661             :               const struct TALER_PaytoHashP *account_id,
     662             :               uint64_t process_row,
     663             :               const char *provider_user_id,
     664             :               const char *provider_legitimization_id,
     665             :               TALER_KYCLOGIC_ProofCallback cb,
     666             :               void *cb_cls)
     667             : {
     668           0 :   struct PluginState *ps = cls;
     669             :   struct TALER_KYCLOGIC_ProofHandle *ph;
     670             : 
     671           0 :   ph = GNUNET_new (struct TALER_KYCLOGIC_ProofHandle);
     672           0 :   ph->ps = ps;
     673           0 :   ph->pd = pd;
     674           0 :   ph->cb = cb;
     675           0 :   ph->cb_cls = cb_cls;
     676           0 :   ph->connection = connection;
     677           0 :   ph->task = GNUNET_SCHEDULER_add_now (&proof_reply,
     678             :                                        ph);
     679           0 :   return ph;
     680             : }
     681             : 
     682             : 
     683             : /**
     684             :  * Cancel KYC webhook execution.
     685             :  *
     686             :  * @param[in] wh handle of operation to cancel
     687             :  */
     688             : static void
     689           0 : kycaid_webhook_cancel (struct TALER_KYCLOGIC_WebhookHandle *wh)
     690             : {
     691           0 :   if (NULL != wh->task)
     692             :   {
     693           0 :     GNUNET_SCHEDULER_cancel (wh->task);
     694           0 :     wh->task = NULL;
     695             :   }
     696           0 :   if (NULL != wh->job)
     697             :   {
     698           0 :     GNUNET_CURL_job_cancel (wh->job);
     699           0 :     wh->job = NULL;
     700             :   }
     701           0 :   GNUNET_free (wh->verification_id);
     702           0 :   GNUNET_free (wh->applicant_id);
     703           0 :   GNUNET_free (wh->url);
     704           0 :   GNUNET_free (wh);
     705           0 : }
     706             : 
     707             : 
     708             : /**
     709             :  * Extract KYC failure reasons and log those
     710             :  *
     711             :  * @param verifications JSON object with failure details
     712             :  */
     713             : static void
     714           0 : log_failure (json_t *verifications)
     715             : {
     716             :   json_t *member;
     717             :   const char *name;
     718           0 :   json_object_foreach (verifications, name, member)
     719             :   {
     720             :     bool iverified;
     721             :     const char *comment;
     722             :     struct GNUNET_JSON_Specification spec[] = {
     723           0 :       GNUNET_JSON_spec_bool ("verified",
     724             :                              &iverified),
     725           0 :       GNUNET_JSON_spec_string ("comment",
     726             :                                &comment),
     727           0 :       GNUNET_JSON_spec_end ()
     728             :     };
     729             : 
     730           0 :     if (GNUNET_OK !=
     731           0 :         GNUNET_JSON_parse (member,
     732             :                            spec,
     733             :                            NULL, NULL))
     734             :     {
     735           0 :       GNUNET_break_op (0);
     736           0 :       json_dumpf (member,
     737             :                   stderr,
     738             :                   JSON_INDENT (2));
     739           0 :       continue;
     740             :     }
     741           0 :     if (iverified)
     742           0 :       continue;
     743           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     744             :                 "KYC verification of attribute `%s' failed: %s\n",
     745             :                 name,
     746             :                 comment);
     747             :   }
     748           0 : }
     749             : 
     750             : 
     751             : /**
     752             :  * Function called when we're done processing the
     753             :  * HTTP "/verifications/{verification_id}" request.
     754             :  *
     755             :  * @param cls the `struct TALER_KYCLOGIC_WebhookHandle`
     756             :  * @param response_code HTTP response code, 0 on error
     757             :  * @param response parsed JSON result, NULL on error
     758             :  */
     759             : static void
     760           0 : handle_webhook_finished (void *cls,
     761             :                          long response_code,
     762             :                          const void *response)
     763             : {
     764           0 :   struct TALER_KYCLOGIC_WebhookHandle *wh = cls;
     765           0 :   const json_t *j = response;
     766             :   struct MHD_Response *resp;
     767             : 
     768           0 :   wh->job = NULL;
     769           0 :   switch (response_code)
     770             :   {
     771           0 :   case MHD_HTTP_OK:
     772             :     {
     773             :       const char *applicant_id;
     774             :       const char *verification_id;
     775             :       const char *status;
     776             :       bool verified;
     777             :       json_t *verifications;
     778             :       struct GNUNET_JSON_Specification spec[] = {
     779           0 :         GNUNET_JSON_spec_string ("applicant_id",
     780             :                                  &applicant_id),
     781           0 :         GNUNET_JSON_spec_string ("verification_id",
     782             :                                  &verification_id),
     783           0 :         GNUNET_JSON_spec_string ("status",
     784             :                                  &status), /* completed, pending, ... */
     785           0 :         GNUNET_JSON_spec_bool ("verified",
     786             :                                &verified),
     787           0 :         GNUNET_JSON_spec_json ("verifications",
     788             :                                &verifications),
     789           0 :         GNUNET_JSON_spec_end ()
     790             :       };
     791             :       struct GNUNET_TIME_Absolute expiration;
     792             : 
     793           0 :       if (GNUNET_OK !=
     794           0 :           GNUNET_JSON_parse (j,
     795             :                              spec,
     796             :                              NULL, NULL))
     797             :       {
     798           0 :         GNUNET_break_op (0);
     799           0 :         json_dumpf (j,
     800             :                     stderr,
     801             :                     JSON_INDENT (2));
     802           0 :         resp = TALER_MHD_MAKE_JSON_PACK (
     803             :           GNUNET_JSON_pack_uint64 ("kycaid_http_status",
     804             :                                    response_code),
     805             :           GNUNET_JSON_pack_object_incref ("kycaid_body",
     806             :                                           (json_t *) j));
     807           0 :         wh->cb (wh->cb_cls,
     808             :                 wh->process_row,
     809           0 :                 &wh->h_payto,
     810           0 :                 wh->pd->section,
     811           0 :                 wh->applicant_id,
     812           0 :                 wh->verification_id,
     813             :                 TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
     814           0 :                 GNUNET_TIME_UNIT_ZERO_ABS, /* expiration */
     815             :                 MHD_HTTP_BAD_GATEWAY,
     816             :                 resp);
     817           0 :         break;
     818             :       }
     819           0 :       if (! verified)
     820             :       {
     821           0 :         log_failure (verifications);
     822             :       }
     823           0 :       resp = MHD_create_response_from_buffer (0,
     824             :                                               "",
     825             :                                               MHD_RESPMEM_PERSISTENT);
     826           0 :       if (verified)
     827             :       {
     828           0 :         expiration = GNUNET_TIME_relative_to_absolute (wh->pd->validity);
     829           0 :         wh->cb (wh->cb_cls,
     830             :                 wh->process_row,
     831           0 :                 &wh->h_payto,
     832           0 :                 wh->pd->section,
     833           0 :                 wh->applicant_id,
     834           0 :                 wh->verification_id,
     835             :                 TALER_KYCLOGIC_STATUS_SUCCESS,
     836             :                 expiration,
     837             :                 MHD_HTTP_NO_CONTENT,
     838             :                 resp);
     839             :       }
     840             :       else
     841             :       {
     842           0 :         wh->cb (wh->cb_cls,
     843             :                 wh->process_row,
     844           0 :                 &wh->h_payto,
     845           0 :                 wh->pd->section,
     846           0 :                 wh->applicant_id,
     847           0 :                 wh->verification_id,
     848             :                 TALER_KYCLOGIC_STATUS_USER_ABORTED,
     849           0 :                 GNUNET_TIME_UNIT_ZERO_ABS,
     850             :                 MHD_HTTP_NO_CONTENT,
     851             :                 resp);
     852             :       }
     853           0 :       GNUNET_JSON_parse_free (spec);
     854             :     }
     855           0 :     break;
     856           0 :   case MHD_HTTP_BAD_REQUEST:
     857             :   case MHD_HTTP_NOT_FOUND:
     858             :   case MHD_HTTP_CONFLICT:
     859           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     860             :                 "KYCAID failed with response %u:\n",
     861             :                 (unsigned int) response_code);
     862           0 :     json_dumpf (j,
     863             :                 stderr,
     864             :                 JSON_INDENT (2));
     865           0 :     resp = TALER_MHD_MAKE_JSON_PACK (
     866             :       GNUNET_JSON_pack_uint64 ("kycaid_http_status",
     867             :                                response_code));
     868           0 :     wh->cb (wh->cb_cls,
     869             :             wh->process_row,
     870           0 :             &wh->h_payto,
     871           0 :             wh->pd->section,
     872           0 :             wh->applicant_id,
     873           0 :             wh->verification_id,
     874             :             TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
     875           0 :             GNUNET_TIME_UNIT_ZERO_ABS, /* expiration */
     876             :             MHD_HTTP_INTERNAL_SERVER_ERROR,
     877             :             resp);
     878           0 :     break;
     879           0 :   case MHD_HTTP_UNAUTHORIZED:
     880             :   case MHD_HTTP_PAYMENT_REQUIRED:
     881           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     882             :                 "Refused access with HTTP status code %u\n",
     883             :                 (unsigned int) response_code);
     884           0 :     resp = TALER_MHD_MAKE_JSON_PACK (
     885             :       GNUNET_JSON_pack_uint64 ("kycaid_http_status",
     886             :                                response_code),
     887             :       GNUNET_JSON_pack_object_incref ("kycaid_body",
     888             :                                       (json_t *) j));
     889           0 :     wh->cb (wh->cb_cls,
     890             :             wh->process_row,
     891           0 :             &wh->h_payto,
     892           0 :             wh->pd->section,
     893           0 :             wh->applicant_id,
     894           0 :             wh->verification_id,
     895             :             TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
     896           0 :             GNUNET_TIME_UNIT_ZERO_ABS, /* expiration */
     897             :             MHD_HTTP_NETWORK_AUTHENTICATION_REQUIRED,
     898             :             resp);
     899           0 :     break;
     900           0 :   case MHD_HTTP_REQUEST_TIMEOUT:
     901           0 :     resp = TALER_MHD_MAKE_JSON_PACK (
     902             :       GNUNET_JSON_pack_uint64 ("kycaid_http_status",
     903             :                                response_code),
     904             :       GNUNET_JSON_pack_object_incref ("kycaid_body",
     905             :                                       (json_t *) j));
     906           0 :     wh->cb (wh->cb_cls,
     907             :             wh->process_row,
     908           0 :             &wh->h_payto,
     909           0 :             wh->pd->section,
     910           0 :             wh->applicant_id,
     911           0 :             wh->verification_id,
     912             :             TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
     913           0 :             GNUNET_TIME_UNIT_ZERO_ABS, /* expiration */
     914             :             MHD_HTTP_GATEWAY_TIMEOUT,
     915             :             resp);
     916           0 :     break;
     917           0 :   case MHD_HTTP_UNPROCESSABLE_ENTITY: /* validation */
     918           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     919             :                 "KYCAID failed with response %u:\n",
     920             :                 (unsigned int) response_code);
     921           0 :     json_dumpf (j,
     922             :                 stderr,
     923             :                 JSON_INDENT (2));
     924           0 :     resp = TALER_MHD_MAKE_JSON_PACK (
     925             :       GNUNET_JSON_pack_uint64 ("kycaid_http_status",
     926             :                                response_code),
     927             :       GNUNET_JSON_pack_object_incref ("kycaid_body",
     928             :                                       (json_t *) j));
     929           0 :     wh->cb (wh->cb_cls,
     930             :             wh->process_row,
     931           0 :             &wh->h_payto,
     932           0 :             wh->pd->section,
     933           0 :             wh->applicant_id,
     934           0 :             wh->verification_id,
     935             :             TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
     936           0 :             GNUNET_TIME_UNIT_ZERO_ABS, /* expiration */
     937             :             MHD_HTTP_BAD_GATEWAY,
     938             :             resp);
     939           0 :     break;
     940           0 :   case MHD_HTTP_TOO_MANY_REQUESTS:
     941           0 :     resp = TALER_MHD_MAKE_JSON_PACK (
     942             :       GNUNET_JSON_pack_uint64 ("kycaid_http_status",
     943             :                                response_code),
     944             :       GNUNET_JSON_pack_object_incref ("kycaid_body",
     945             :                                       (json_t *) j));
     946           0 :     wh->cb (wh->cb_cls,
     947             :             wh->process_row,
     948           0 :             &wh->h_payto,
     949           0 :             wh->pd->section,
     950           0 :             wh->applicant_id,
     951           0 :             wh->verification_id,
     952             :             TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
     953           0 :             GNUNET_TIME_UNIT_ZERO_ABS, /* expiration */
     954             :             MHD_HTTP_SERVICE_UNAVAILABLE,
     955             :             resp);
     956           0 :     break;
     957           0 :   case MHD_HTTP_INTERNAL_SERVER_ERROR:
     958           0 :     resp = TALER_MHD_MAKE_JSON_PACK (
     959             :       GNUNET_JSON_pack_uint64 ("kycaid_http_status",
     960             :                                response_code),
     961             :       GNUNET_JSON_pack_object_incref ("kycaid_body",
     962             :                                       (json_t *) j));
     963           0 :     wh->cb (wh->cb_cls,
     964             :             wh->process_row,
     965           0 :             &wh->h_payto,
     966           0 :             wh->pd->section,
     967           0 :             wh->applicant_id,
     968           0 :             wh->verification_id,
     969             :             TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
     970           0 :             GNUNET_TIME_UNIT_ZERO_ABS, /* expiration */
     971             :             MHD_HTTP_BAD_GATEWAY,
     972             :             resp);
     973           0 :     break;
     974           0 :   default:
     975           0 :     resp = TALER_MHD_MAKE_JSON_PACK (
     976             :       GNUNET_JSON_pack_uint64 ("kycaid_http_status",
     977             :                                response_code),
     978             :       GNUNET_JSON_pack_object_incref ("kycaid_body",
     979             :                                       (json_t *) j));
     980           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     981             :                 "Unexpected KYCAID response %u:\n",
     982             :                 (unsigned int) response_code);
     983           0 :     json_dumpf (j,
     984             :                 stderr,
     985             :                 JSON_INDENT (2));
     986           0 :     wh->cb (wh->cb_cls,
     987             :             wh->process_row,
     988           0 :             &wh->h_payto,
     989           0 :             wh->pd->section,
     990           0 :             wh->applicant_id,
     991           0 :             wh->verification_id,
     992             :             TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
     993           0 :             GNUNET_TIME_UNIT_ZERO_ABS, /* expiration */
     994             :             MHD_HTTP_BAD_GATEWAY,
     995             :             resp);
     996           0 :     break;
     997             :   }
     998           0 :   kycaid_webhook_cancel (wh);
     999           0 : }
    1000             : 
    1001             : 
    1002             : /**
    1003             :  * Asynchronously return a reply for the webhook.
    1004             :  *
    1005             :  * @param cls a `struct TALER_KYCLOGIC_WebhookHandle *`
    1006             :  */
    1007             : static void
    1008           0 : async_webhook_reply (void *cls)
    1009             : {
    1010           0 :   struct TALER_KYCLOGIC_WebhookHandle *wh = cls;
    1011             : 
    1012           0 :   wh->cb (wh->cb_cls,
    1013             :           wh->process_row,
    1014           0 :           (0 == wh->process_row)
    1015             :           ? NULL
    1016             :           : &wh->h_payto,
    1017           0 :           wh->pd->section,
    1018           0 :           wh->applicant_id, /* provider user ID */
    1019           0 :           wh->verification_id, /* provider legi ID */
    1020             :           TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
    1021           0 :           GNUNET_TIME_UNIT_ZERO_ABS, /* expiration */
    1022             :           wh->response_code,
    1023             :           wh->resp);
    1024           0 :   kycaid_webhook_cancel (wh);
    1025           0 : }
    1026             : 
    1027             : 
    1028             : /**
    1029             :  * Check KYC status and return result for Webhook.  We do NOT implement the
    1030             :  * authentication check proposed by the KYCAID documentation, as it would
    1031             :  * allow an attacker who learns the access token to easily bypass the KYC
    1032             :  * checks. Instead, we insist on explicitly requesting the KYC status from the
    1033             :  * provider (at least on success).
    1034             :  *
    1035             :  * @param cls the @e cls of this struct with the plugin-specific state
    1036             :  * @param pd provider configuration details
    1037             :  * @param plc callback to lookup accounts with
    1038             :  * @param plc_cls closure for @a plc
    1039             :  * @param http_method HTTP method used for the webhook
    1040             :  * @param url_path rest of the URL after `/kyc-webhook/`
    1041             :  * @param connection MHD connection object (for HTTP headers)
    1042             :  * @param body HTTP request body
    1043             :  * @param cb function to call with the result
    1044             :  * @param cb_cls closure for @a cb
    1045             :  * @return handle to cancel operation early
    1046             :  */
    1047             : static struct TALER_KYCLOGIC_WebhookHandle *
    1048           0 : kycaid_webhook (void *cls,
    1049             :                 const struct TALER_KYCLOGIC_ProviderDetails *pd,
    1050             :                 TALER_KYCLOGIC_ProviderLookupCallback plc,
    1051             :                 void *plc_cls,
    1052             :                 const char *http_method,
    1053             :                 const char *const url_path[],
    1054             :                 struct MHD_Connection *connection,
    1055             :                 const json_t *body,
    1056             :                 TALER_KYCLOGIC_WebhookCallback cb,
    1057             :                 void *cb_cls)
    1058             : {
    1059           0 :   struct PluginState *ps = cls;
    1060             :   struct TALER_KYCLOGIC_WebhookHandle *wh;
    1061             :   CURL *eh;
    1062             :   const char *request_id;
    1063             :   const char *type;
    1064             :   const char *verification_id;
    1065             :   const char *applicant_id;
    1066             :   const char *status;
    1067             :   bool verified;
    1068             :   json_t *verifications;
    1069             :   struct GNUNET_JSON_Specification spec[] = {
    1070           0 :     GNUNET_JSON_spec_string ("request_id",
    1071             :                              &request_id),
    1072           0 :     GNUNET_JSON_spec_string ("type",
    1073             :                              &type),
    1074           0 :     GNUNET_JSON_spec_string ("verification_id",
    1075             :                              &verification_id),
    1076           0 :     GNUNET_JSON_spec_string ("applicant_id",
    1077             :                              &applicant_id),
    1078           0 :     GNUNET_JSON_spec_string ("status",
    1079             :                              &status),
    1080           0 :     GNUNET_JSON_spec_bool ("verified",
    1081             :                            &verified),
    1082           0 :     GNUNET_JSON_spec_json ("verifications",
    1083             :                            &verifications),
    1084           0 :     GNUNET_JSON_spec_end ()
    1085             :   };
    1086             :   enum GNUNET_DB_QueryStatus qs;
    1087             : 
    1088           0 :   wh = GNUNET_new (struct TALER_KYCLOGIC_WebhookHandle);
    1089           0 :   wh->cb = cb;
    1090           0 :   wh->cb_cls = cb_cls;
    1091           0 :   wh->ps = ps;
    1092           0 :   wh->pd = pd;
    1093           0 :   wh->connection = connection;
    1094             : 
    1095           0 :   if (NULL == pd)
    1096             :   {
    1097           0 :     GNUNET_break_op (0);
    1098           0 :     json_dumpf (body,
    1099             :                 stderr,
    1100             :                 JSON_INDENT (2));
    1101           0 :     wh->resp = TALER_MHD_make_error (
    1102             :       TALER_EC_EXCHANGE_KYC_GENERIC_LOGIC_UNKNOWN,
    1103             :       "kycaid");
    1104           0 :     wh->response_code = MHD_HTTP_NOT_FOUND;
    1105           0 :     wh->task = GNUNET_SCHEDULER_add_now (&async_webhook_reply,
    1106             :                                          wh);
    1107           0 :     return wh;
    1108             :   }
    1109             : 
    1110           0 :   if (GNUNET_OK !=
    1111           0 :       GNUNET_JSON_parse (body,
    1112             :                          spec,
    1113             :                          NULL, NULL))
    1114             :   {
    1115           0 :     GNUNET_break_op (0);
    1116           0 :     json_dumpf (body,
    1117             :                 stderr,
    1118             :                 JSON_INDENT (2));
    1119           0 :     wh->resp = TALER_MHD_MAKE_JSON_PACK (
    1120             :       GNUNET_JSON_pack_object_incref ("webhook_body",
    1121             :                                       (json_t *) body));
    1122           0 :     wh->response_code = MHD_HTTP_BAD_REQUEST;
    1123           0 :     wh->task = GNUNET_SCHEDULER_add_now (&async_webhook_reply,
    1124             :                                          wh);
    1125           0 :     return wh;
    1126             :   }
    1127           0 :   qs = plc (plc_cls,
    1128           0 :             pd->section,
    1129             :             verification_id,
    1130             :             &wh->h_payto,
    1131             :             &wh->process_row);
    1132           0 :   if (qs < 0)
    1133             :   {
    1134           0 :     wh->resp = TALER_MHD_make_error (TALER_EC_GENERIC_DB_FETCH_FAILED,
    1135             :                                      "provider-legitimization-lookup");
    1136           0 :     wh->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
    1137           0 :     wh->task = GNUNET_SCHEDULER_add_now (&async_webhook_reply,
    1138             :                                          wh);
    1139           0 :     GNUNET_JSON_parse_free (spec);
    1140           0 :     return wh;
    1141             :   }
    1142           0 :   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
    1143             :   {
    1144           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1145             :                 "Received webhook for unknown verification ID `%s'\n",
    1146             :                 verification_id);
    1147           0 :     wh->resp = TALER_MHD_make_error (
    1148             :       TALER_EC_EXCHANGE_KYC_PROOF_REQUEST_UNKNOWN,
    1149             :       verification_id);
    1150           0 :     wh->response_code = MHD_HTTP_NOT_FOUND;
    1151           0 :     wh->task = GNUNET_SCHEDULER_add_now (&async_webhook_reply,
    1152             :                                          wh);
    1153           0 :     GNUNET_JSON_parse_free (spec);
    1154           0 :     return wh;
    1155             :   }
    1156           0 :   wh->verification_id = GNUNET_strdup (verification_id);
    1157           0 :   wh->applicant_id = GNUNET_strdup (applicant_id);
    1158           0 :   if (! verified)
    1159             :   {
    1160             :     /* We don't need to re-confirm the failure by
    1161             :        asking the API again. */
    1162           0 :     log_failure (verifications);
    1163           0 :     wh->response_code = MHD_HTTP_NO_CONTENT;
    1164           0 :     wh->resp = MHD_create_response_from_buffer (0,
    1165             :                                                 "",
    1166             :                                                 MHD_RESPMEM_PERSISTENT);
    1167           0 :     wh->task = GNUNET_SCHEDULER_add_now (&async_webhook_reply,
    1168             :                                          wh);
    1169           0 :     GNUNET_JSON_parse_free (spec);
    1170           0 :     return wh;
    1171             :   }
    1172             : 
    1173           0 :   eh = curl_easy_init ();
    1174           0 :   if (NULL == eh)
    1175             :   {
    1176           0 :     GNUNET_break (0);
    1177           0 :     wh->resp = TALER_MHD_make_error (
    1178             :       TALER_EC_GENERIC_ALLOCATION_FAILURE,
    1179             :       NULL);
    1180           0 :     wh->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
    1181           0 :     wh->task = GNUNET_SCHEDULER_add_now (&async_webhook_reply,
    1182             :                                          wh);
    1183           0 :     GNUNET_JSON_parse_free (spec);
    1184           0 :     return wh;
    1185             :   }
    1186             : 
    1187           0 :   GNUNET_asprintf (&wh->url,
    1188             :                    "https://api.kycaid.com/verifications/%s",
    1189             :                    verification_id);
    1190           0 :   GNUNET_break (CURLE_OK ==
    1191             :                 curl_easy_setopt (eh,
    1192             :                                   CURLOPT_VERBOSE,
    1193             :                                   0));
    1194           0 :   GNUNET_assert (CURLE_OK ==
    1195             :                  curl_easy_setopt (eh,
    1196             :                                    CURLOPT_MAXREDIRS,
    1197             :                                    1L));
    1198           0 :   GNUNET_break (CURLE_OK ==
    1199             :                 curl_easy_setopt (eh,
    1200             :                                   CURLOPT_URL,
    1201             :                                   wh->url));
    1202           0 :   wh->job = GNUNET_CURL_job_add2 (ps->curl_ctx,
    1203             :                                   eh,
    1204           0 :                                   pd->slist,
    1205             :                                   &handle_webhook_finished,
    1206             :                                   wh);
    1207           0 :   GNUNET_JSON_parse_free (spec);
    1208           0 :   return wh;
    1209             : }
    1210             : 
    1211             : 
    1212             : /**
    1213             :  * Initialize kycaid logic plugin
    1214             :  *
    1215             :  * @param cls a configuration instance
    1216             :  * @return NULL on error, otherwise a `struct TALER_KYCLOGIC_Plugin`
    1217             :  */
    1218             : void *
    1219           1 : libtaler_plugin_kyclogic_kycaid_init (void *cls)
    1220             : {
    1221           1 :   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
    1222             :   struct TALER_KYCLOGIC_Plugin *plugin;
    1223             :   struct PluginState *ps;
    1224             : 
    1225           1 :   ps = GNUNET_new (struct PluginState);
    1226           1 :   ps->cfg = cfg;
    1227           1 :   if (GNUNET_OK !=
    1228           1 :       GNUNET_CONFIGURATION_get_value_string (cfg,
    1229             :                                              "exchange",
    1230             :                                              "BASE_URL",
    1231             :                                              &ps->exchange_base_url))
    1232             :   {
    1233           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1234             :                                "exchange",
    1235             :                                "BASE_URL");
    1236           0 :     GNUNET_free (ps);
    1237           0 :     return NULL;
    1238             :   }
    1239             : 
    1240             :   ps->curl_ctx
    1241           2 :     = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
    1242           1 :                         &ps->curl_rc);
    1243           1 :   if (NULL == ps->curl_ctx)
    1244             :   {
    1245           0 :     GNUNET_break (0);
    1246           0 :     GNUNET_free (ps->exchange_base_url);
    1247           0 :     GNUNET_free (ps);
    1248           0 :     return NULL;
    1249             :   }
    1250           1 :   ps->curl_rc = GNUNET_CURL_gnunet_rc_create (ps->curl_ctx);
    1251             : 
    1252           1 :   plugin = GNUNET_new (struct TALER_KYCLOGIC_Plugin);
    1253           1 :   plugin->cls = ps;
    1254             :   plugin->load_configuration
    1255           1 :     = &kycaid_load_configuration;
    1256             :   plugin->unload_configuration
    1257           1 :     = &kycaid_unload_configuration;
    1258             :   plugin->initiate
    1259           1 :     = &kycaid_initiate;
    1260             :   plugin->initiate_cancel
    1261           1 :     = &kycaid_initiate_cancel;
    1262             :   plugin->proof
    1263           1 :     = &kycaid_proof;
    1264             :   plugin->proof_cancel
    1265           1 :     = &kycaid_proof_cancel;
    1266             :   plugin->webhook
    1267           1 :     = &kycaid_webhook;
    1268             :   plugin->webhook_cancel
    1269           1 :     = &kycaid_webhook_cancel;
    1270           1 :   return plugin;
    1271             : }
    1272             : 
    1273             : 
    1274             : /**
    1275             :  * Unload authorization plugin
    1276             :  *
    1277             :  * @param cls a `struct TALER_KYCLOGIC_Plugin`
    1278             :  * @return NULL (always)
    1279             :  */
    1280             : void *
    1281           0 : libtaler_plugin_kyclogic_kycaid_done (void *cls)
    1282             : {
    1283           0 :   struct TALER_KYCLOGIC_Plugin *plugin = cls;
    1284           0 :   struct PluginState *ps = plugin->cls;
    1285             : 
    1286           0 :   if (NULL != ps->curl_ctx)
    1287             :   {
    1288           0 :     GNUNET_CURL_fini (ps->curl_ctx);
    1289           0 :     ps->curl_ctx = NULL;
    1290             :   }
    1291           0 :   if (NULL != ps->curl_rc)
    1292             :   {
    1293           0 :     GNUNET_CURL_gnunet_rc_destroy (ps->curl_rc);
    1294           0 :     ps->curl_rc = NULL;
    1295             :   }
    1296           0 :   GNUNET_free (ps->exchange_base_url);
    1297           0 :   GNUNET_free (ps);
    1298           0 :   GNUNET_free (plugin);
    1299           0 :   return NULL;
    1300             : }

Generated by: LCOV version 1.14