LCOV - code coverage report
Current view: top level - kyclogic - plugin_kyclogic_oauth2.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 295 532 55.5 %
Date: 2025-06-05 21:03:14 Functions: 16 20 80.0 %

          Line data    Source code
       1             : /*
       2             :   This file is part of GNU Taler
       3             :   Copyright (C) 2022-2024 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_oauth2.c
      18             :  * @brief oauth2.0 based 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_templating_lib.h"
      25             : #include "taler_curl_lib.h"
      26             : #include "taler_json_lib.h"
      27             : #include <regex.h>
      28             : #include "taler_util.h"
      29             : 
      30             : /**
      31             :  * Set to 1 to get extra-verbose, possibly privacy-sensitive
      32             :  * data in the logs.
      33             :  */
      34             : #define DEBUG 0
      35             : 
      36             : /**
      37             :  * Saves the state of a plugin.
      38             :  */
      39             : struct PluginState
      40             : {
      41             : 
      42             :   /**
      43             :    * Our global configuration.
      44             :    */
      45             :   const struct GNUNET_CONFIGURATION_Handle *cfg;
      46             : 
      47             :   /**
      48             :    * Our base URL.
      49             :    */
      50             :   char *exchange_base_url;
      51             : 
      52             :   /**
      53             :    * Context for CURL operations (useful to the event loop)
      54             :    */
      55             :   struct GNUNET_CURL_Context *curl_ctx;
      56             : 
      57             :   /**
      58             :    * Context for integrating @e curl_ctx with the
      59             :    * GNUnet event loop.
      60             :    */
      61             :   struct GNUNET_CURL_RescheduleContext *curl_rc;
      62             : 
      63             : };
      64             : 
      65             : 
      66             : /**
      67             :  * Keeps the plugin-specific state for
      68             :  * a given configuration section.
      69             :  */
      70             : struct TALER_KYCLOGIC_ProviderDetails
      71             : {
      72             : 
      73             :   /**
      74             :    * Overall plugin state.
      75             :    */
      76             :   struct PluginState *ps;
      77             : 
      78             :   /**
      79             :    * Configuration section that configured us.
      80             :    */
      81             :   char *section;
      82             : 
      83             :   /**
      84             :    * URL of the Challenger ``/setup`` endpoint for
      85             :    * approving address validations. NULL if not used.
      86             :    */
      87             :   char *setup_url;
      88             : 
      89             :   /**
      90             :    * URL of the OAuth2.0 endpoint for KYC checks.
      91             :    */
      92             :   char *authorize_url;
      93             : 
      94             :   /**
      95             :    * URL of the OAuth2.0 endpoint for KYC checks.
      96             :    * (token/auth)
      97             :    */
      98             :   char *token_url;
      99             : 
     100             :   /**
     101             :    * URL of the user info access endpoint.
     102             :    */
     103             :   char *info_url;
     104             : 
     105             :   /**
     106             :    * Our client ID for OAuth2.0.
     107             :    */
     108             :   char *client_id;
     109             : 
     110             :   /**
     111             :    * Our client secret for OAuth2.0.
     112             :    */
     113             :   char *client_secret;
     114             : 
     115             :   /**
     116             :    * Where to redirect clients after the
     117             :    * Web-based KYC process is done?
     118             :    */
     119             :   char *post_kyc_redirect_url;
     120             : 
     121             :   /**
     122             :    * Name of the program we use to convert outputs
     123             :    * from OAuth2 outputs into our JSON inputs.
     124             :    */
     125             :   char *conversion_binary;
     126             : 
     127             :   /**
     128             :    * Validity time for a successful KYC process.
     129             :    */
     130             :   struct GNUNET_TIME_Relative validity;
     131             : 
     132             :   /**
     133             :    * Set to true if we are operating in DEBUG
     134             :    * mode and may return private details in HTML
     135             :    * responses to make diagnostics easier.
     136             :    */
     137             :   bool debug_mode;
     138             : };
     139             : 
     140             : 
     141             : /**
     142             :  * Handle for an initiation operation.
     143             :  */
     144             : struct TALER_KYCLOGIC_InitiateHandle
     145             : {
     146             : 
     147             :   /**
     148             :    * Hash of the payto:// URI we are initiating
     149             :    * the KYC for.
     150             :    */
     151             :   struct TALER_NormalizedPaytoHashP h_payto;
     152             : 
     153             :   /**
     154             :    * UUID being checked.
     155             :    */
     156             :   uint64_t legitimization_uuid;
     157             : 
     158             :   /**
     159             :    * Our configuration details.
     160             :    */
     161             :   const struct TALER_KYCLOGIC_ProviderDetails *pd;
     162             : 
     163             :   /**
     164             :    * The task for asynchronous response generation.
     165             :    */
     166             :   struct GNUNET_SCHEDULER_Task *task;
     167             : 
     168             :   /**
     169             :    * Handle for the OAuth 2.0 setup request.
     170             :    */
     171             :   struct GNUNET_CURL_Job *job;
     172             : 
     173             :   /**
     174             :    * Continuation to call.
     175             :    */
     176             :   TALER_KYCLOGIC_InitiateCallback cb;
     177             : 
     178             :   /**
     179             :    * Closure for @a cb.
     180             :    */
     181             :   void *cb_cls;
     182             : 
     183             :   /**
     184             :    * Initial address to pass to the KYC provider on ``/setup``.
     185             :    */
     186             :   json_t *initial_address;
     187             : 
     188             :   /**
     189             :    * Context for #TEH_curl_easy_post(). Keeps the data that must
     190             :    * persist for Curl to make the upload.
     191             :    */
     192             :   struct TALER_CURL_PostContext ctx;
     193             : 
     194             : };
     195             : 
     196             : 
     197             : /**
     198             :  * Handle for an KYC proof operation.
     199             :  */
     200             : struct TALER_KYCLOGIC_ProofHandle
     201             : {
     202             : 
     203             :   /**
     204             :    * Our configuration details.
     205             :    */
     206             :   const struct TALER_KYCLOGIC_ProviderDetails *pd;
     207             : 
     208             :   /**
     209             :    * HTTP connection we are processing.
     210             :    */
     211             :   struct MHD_Connection *connection;
     212             : 
     213             :   /**
     214             :    * Handle to an external process that converts the
     215             :    * Persona response to our internal format.
     216             :    */
     217             :   struct TALER_JSON_ExternalConversion *ec;
     218             : 
     219             :   /**
     220             :    * Hash of the payto URI that this is about.
     221             :    */
     222             :   struct TALER_NormalizedPaytoHashP h_payto;
     223             : 
     224             :   /**
     225             :    * Continuation to call.
     226             :    */
     227             :   TALER_KYCLOGIC_ProofCallback cb;
     228             : 
     229             :   /**
     230             :    * Closure for @e cb.
     231             :    */
     232             :   void *cb_cls;
     233             : 
     234             :   /**
     235             :    * Curl request we are running to the OAuth 2.0 service.
     236             :    */
     237             :   CURL *eh;
     238             : 
     239             :   /**
     240             :    * Body for the @e eh POST request.
     241             :    */
     242             :   char *post_body;
     243             : 
     244             :   /**
     245             :    * KYC attributes returned about the user by the OAuth 2.0 server.
     246             :    */
     247             :   json_t *attributes;
     248             : 
     249             :   /**
     250             :    * Response to return.
     251             :    */
     252             :   struct MHD_Response *response;
     253             : 
     254             :   /**
     255             :    * The task for asynchronous response generation.
     256             :    */
     257             :   struct GNUNET_SCHEDULER_Task *task;
     258             : 
     259             :   /**
     260             :    * Handle for the OAuth 2.0 CURL request.
     261             :    */
     262             :   struct GNUNET_CURL_Job *job;
     263             : 
     264             :   /**
     265             :    * User ID to return, the 'id' from OAuth.
     266             :    */
     267             :   char *provider_user_id;
     268             : 
     269             :   /**
     270             :    * Legitimization ID to return, the 64-bit row ID
     271             :    * as a string.
     272             :    */
     273             :   char provider_legitimization_id[32];
     274             : 
     275             :   /**
     276             :    * KYC status to return.
     277             :    */
     278             :   enum TALER_KYCLOGIC_KycStatus status;
     279             : 
     280             :   /**
     281             :    * HTTP status to return.
     282             :    */
     283             :   unsigned int http_status;
     284             : 
     285             : 
     286             : };
     287             : 
     288             : 
     289             : /**
     290             :  * Handle for an KYC Web hook operation.
     291             :  */
     292             : struct TALER_KYCLOGIC_WebhookHandle
     293             : {
     294             : 
     295             :   /**
     296             :    * Continuation to call when done.
     297             :    */
     298             :   TALER_KYCLOGIC_WebhookCallback cb;
     299             : 
     300             :   /**
     301             :    * Closure for @a cb.
     302             :    */
     303             :   void *cb_cls;
     304             : 
     305             :   /**
     306             :    * Task for asynchronous execution.
     307             :    */
     308             :   struct GNUNET_SCHEDULER_Task *task;
     309             : 
     310             :   /**
     311             :    * Overall plugin state.
     312             :    */
     313             :   struct PluginState *ps;
     314             : };
     315             : 
     316             : 
     317             : /**
     318             :  * Release configuration resources previously loaded
     319             :  *
     320             :  * @param[in] pd configuration to release
     321             :  */
     322             : static void
     323         107 : oauth2_unload_configuration (struct TALER_KYCLOGIC_ProviderDetails *pd)
     324             : {
     325         107 :   GNUNET_free (pd->section);
     326         107 :   GNUNET_free (pd->token_url);
     327         107 :   GNUNET_free (pd->setup_url);
     328         107 :   GNUNET_free (pd->authorize_url);
     329         107 :   GNUNET_free (pd->info_url);
     330         107 :   GNUNET_free (pd->client_id);
     331         107 :   GNUNET_free (pd->client_secret);
     332         107 :   GNUNET_free (pd->post_kyc_redirect_url);
     333         107 :   GNUNET_free (pd->conversion_binary);
     334         107 :   GNUNET_free (pd);
     335         107 : }
     336             : 
     337             : 
     338             : /**
     339             :  * Load the configuration of the KYC provider.
     340             :  *
     341             :  * @param cls closure
     342             :  * @param provider_section_name configuration section to parse
     343             :  * @return NULL if configuration is invalid
     344             :  */
     345             : static struct TALER_KYCLOGIC_ProviderDetails *
     346         107 : oauth2_load_configuration (void *cls,
     347             :                            const char *provider_section_name)
     348             : {
     349         107 :   struct PluginState *ps = cls;
     350             :   struct TALER_KYCLOGIC_ProviderDetails *pd;
     351             :   char *s;
     352             : 
     353         107 :   pd = GNUNET_new (struct TALER_KYCLOGIC_ProviderDetails);
     354         107 :   pd->ps = ps;
     355         107 :   pd->section = GNUNET_strdup (provider_section_name);
     356         107 :   if (GNUNET_OK !=
     357         107 :       GNUNET_CONFIGURATION_get_value_time (ps->cfg,
     358             :                                            provider_section_name,
     359             :                                            "KYC_OAUTH2_VALIDITY",
     360             :                                            &pd->validity))
     361             :   {
     362           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     363             :                                provider_section_name,
     364             :                                "KYC_OAUTH2_VALIDITY");
     365           0 :     oauth2_unload_configuration (pd);
     366           0 :     return NULL;
     367             :   }
     368             : 
     369         107 :   if (GNUNET_OK !=
     370         107 :       GNUNET_CONFIGURATION_get_value_string (ps->cfg,
     371             :                                              provider_section_name,
     372             :                                              "KYC_OAUTH2_CLIENT_ID",
     373             :                                              &s))
     374             :   {
     375           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     376             :                                provider_section_name,
     377             :                                "KYC_OAUTH2_CLIENT_ID");
     378           0 :     oauth2_unload_configuration (pd);
     379           0 :     return NULL;
     380             :   }
     381         107 :   pd->client_id = s;
     382             : 
     383         107 :   if (GNUNET_OK !=
     384         107 :       GNUNET_CONFIGURATION_get_value_string (ps->cfg,
     385             :                                              provider_section_name,
     386             :                                              "KYC_OAUTH2_TOKEN_URL",
     387             :                                              &s))
     388             :   {
     389           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     390             :                                provider_section_name,
     391             :                                "KYC_OAUTH2_TOKEN_URL");
     392           0 :     oauth2_unload_configuration (pd);
     393           0 :     return NULL;
     394             :   }
     395         107 :   if ( (! TALER_url_valid_charset (s)) ||
     396         107 :        ( (0 != strncasecmp (s,
     397             :                             "http://",
     398          76 :                             strlen ("http://"))) &&
     399          76 :          (0 != strncasecmp (s,
     400             :                             "https://",
     401             :                             strlen ("https://"))) ) )
     402             :   {
     403           0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
     404             :                                provider_section_name,
     405             :                                "KYC_OAUTH2_TOKEN_URL",
     406             :                                "not a valid URL");
     407           0 :     GNUNET_free (s);
     408           0 :     oauth2_unload_configuration (pd);
     409           0 :     return NULL;
     410             :   }
     411         107 :   pd->token_url = s;
     412             : 
     413         107 :   if (GNUNET_OK !=
     414         107 :       GNUNET_CONFIGURATION_get_value_string (ps->cfg,
     415             :                                              provider_section_name,
     416             :                                              "KYC_OAUTH2_AUTHORIZE_URL",
     417             :                                              &s))
     418             :   {
     419           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     420             :                                provider_section_name,
     421             :                                "KYC_OAUTH2_AUTHORIZE_URL");
     422           0 :     oauth2_unload_configuration (pd);
     423           0 :     return NULL;
     424             :   }
     425         107 :   if ( (! TALER_url_valid_charset (s)) ||
     426         107 :        ( (0 != strncasecmp (s,
     427             :                             "http://",
     428          76 :                             strlen ("http://"))) &&
     429          76 :          (0 != strncasecmp (s,
     430             :                             "https://",
     431             :                             strlen ("https://"))) ) )
     432             :   {
     433           0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
     434             :                                provider_section_name,
     435             :                                "KYC_OAUTH2_AUTHORIZE_URL",
     436             :                                "not a valid URL");
     437           0 :     oauth2_unload_configuration (pd);
     438           0 :     GNUNET_free (s);
     439           0 :     return NULL;
     440             :   }
     441         107 :   if (NULL != strchr (s, '#'))
     442             :   {
     443           0 :     const char *extra = strchr (s, '#');
     444           0 :     const char *slash = strrchr (s, '/');
     445             : 
     446           0 :     if ( (0 != strcasecmp (extra,
     447           0 :                            "#setup")) ||
     448             :          (NULL == slash) )
     449             :     {
     450           0 :       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
     451             :                                  provider_section_name,
     452             :                                  "KYC_OAUTH2_AUTHORIZE_URL",
     453             :                                  "not a valid authorze URL (bad fragment)");
     454           0 :       oauth2_unload_configuration (pd);
     455           0 :       GNUNET_free (s);
     456           0 :       return NULL;
     457             :     }
     458           0 :     pd->authorize_url = GNUNET_strndup (s,
     459             :                                         extra - s);
     460           0 :     GNUNET_asprintf (&pd->setup_url,
     461             :                      "%.*s/setup/%s",
     462           0 :                      (int) (slash - s),
     463             :                      s,
     464             :                      pd->client_id);
     465           0 :     GNUNET_free (s);
     466             :   }
     467             :   else
     468             :   {
     469         107 :     pd->authorize_url = s;
     470             :   }
     471             : 
     472         107 :   if (GNUNET_OK !=
     473         107 :       GNUNET_CONFIGURATION_get_value_string (ps->cfg,
     474             :                                              provider_section_name,
     475             :                                              "KYC_OAUTH2_INFO_URL",
     476             :                                              &s))
     477             :   {
     478           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     479             :                                provider_section_name,
     480             :                                "KYC_OAUTH2_INFO_URL");
     481           0 :     oauth2_unload_configuration (pd);
     482           0 :     return NULL;
     483             :   }
     484         107 :   if ( (! TALER_url_valid_charset (s)) ||
     485         107 :        ( (0 != strncasecmp (s,
     486             :                             "http://",
     487          76 :                             strlen ("http://"))) &&
     488          76 :          (0 != strncasecmp (s,
     489             :                             "https://",
     490             :                             strlen ("https://"))) ) )
     491             :   {
     492           0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
     493             :                                provider_section_name,
     494             :                                "KYC_INFO_URL",
     495             :                                "not a valid URL");
     496           0 :     GNUNET_free (s);
     497           0 :     oauth2_unload_configuration (pd);
     498           0 :     return NULL;
     499             :   }
     500         107 :   pd->info_url = s;
     501             : 
     502         107 :   if (GNUNET_OK !=
     503         107 :       GNUNET_CONFIGURATION_get_value_string (ps->cfg,
     504             :                                              provider_section_name,
     505             :                                              "KYC_OAUTH2_CLIENT_SECRET",
     506             :                                              &s))
     507             :   {
     508           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     509             :                                provider_section_name,
     510             :                                "KYC_OAUTH2_CLIENT_SECRET");
     511           0 :     oauth2_unload_configuration (pd);
     512           0 :     return NULL;
     513             :   }
     514         107 :   pd->client_secret = s;
     515             : 
     516         107 :   if (GNUNET_OK !=
     517         107 :       GNUNET_CONFIGURATION_get_value_string (ps->cfg,
     518             :                                              provider_section_name,
     519             :                                              "KYC_OAUTH2_POST_URL",
     520             :                                              &s))
     521             :   {
     522           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     523             :                                provider_section_name,
     524             :                                "KYC_OAUTH2_POST_URL");
     525           0 :     oauth2_unload_configuration (pd);
     526           0 :     return NULL;
     527             :   }
     528         107 :   pd->post_kyc_redirect_url = s;
     529             : 
     530         107 :   if (GNUNET_OK !=
     531         107 :       GNUNET_CONFIGURATION_get_value_string (ps->cfg,
     532             :                                              provider_section_name,
     533             :                                              "KYC_OAUTH2_CONVERTER_HELPER",
     534             :                                              &pd->conversion_binary))
     535             :   {
     536           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     537             :                                provider_section_name,
     538             :                                "KYC_OAUTH2_CONVERTER_HELPER");
     539           0 :     oauth2_unload_configuration (pd);
     540           0 :     return NULL;
     541             :   }
     542         107 :   if (GNUNET_OK ==
     543         107 :       GNUNET_CONFIGURATION_get_value_yesno (ps->cfg,
     544             :                                             provider_section_name,
     545             :                                             "KYC_OAUTH2_DEBUG_MODE"))
     546           0 :     pd->debug_mode = true;
     547             : 
     548         107 :   return pd;
     549             : }
     550             : 
     551             : 
     552             : /**
     553             :  * Cancel KYC check initiation.
     554             :  *
     555             :  * @param[in] ih handle of operation to cancel
     556             :  */
     557             : static void
     558          10 : oauth2_initiate_cancel (struct TALER_KYCLOGIC_InitiateHandle *ih)
     559             : {
     560          10 :   if (NULL != ih->task)
     561             :   {
     562           0 :     GNUNET_SCHEDULER_cancel (ih->task);
     563           0 :     ih->task = NULL;
     564             :   }
     565          10 :   if (NULL != ih->job)
     566             :   {
     567           0 :     GNUNET_CURL_job_cancel (ih->job);
     568           0 :     ih->job = NULL;
     569             :   }
     570          10 :   TALER_curl_easy_post_finished (&ih->ctx);
     571          10 :   json_decref (ih->initial_address);
     572          10 :   GNUNET_free (ih);
     573          10 : }
     574             : 
     575             : 
     576             : /**
     577             :  * Logic to asynchronously return the response for
     578             :  * how to begin the OAuth2.0 checking process to
     579             :  * the client.
     580             :  *
     581             :  * @param ih process to redirect for
     582             :  * @param authorize_url authorization URL to use
     583             :  */
     584             : static void
     585          10 : initiate_with_url (struct TALER_KYCLOGIC_InitiateHandle *ih,
     586             :                    const char *authorize_url)
     587             : {
     588             : 
     589          10 :   const struct TALER_KYCLOGIC_ProviderDetails *pd = ih->pd;
     590          10 :   struct PluginState *ps = pd->ps;
     591             :   char *hps;
     592             :   char *url;
     593             :   char legi_s[42];
     594             : 
     595          10 :   GNUNET_snprintf (legi_s,
     596             :                    sizeof (legi_s),
     597             :                    "%llu",
     598          10 :                    (unsigned long long) ih->legitimization_uuid);
     599          10 :   hps = GNUNET_STRINGS_data_to_string_alloc (&ih->h_payto,
     600             :                                              sizeof (ih->h_payto));
     601             :   {
     602             :     char *redirect_uri_encoded;
     603             : 
     604             :     {
     605             :       char *redirect_uri;
     606             : 
     607          10 :       GNUNET_asprintf (&redirect_uri,
     608             :                        "%skyc-proof/%s",
     609             :                        ps->exchange_base_url,
     610          10 :                        &pd->section[strlen ("kyc-provider-")]);
     611          10 :       redirect_uri_encoded = TALER_urlencode (redirect_uri);
     612          10 :       GNUNET_free (redirect_uri);
     613             :     }
     614          10 :     GNUNET_asprintf (&url,
     615             :                      "%s?response_type=code&client_id=%s&redirect_uri=%s&state=%s",
     616             :                      authorize_url,
     617          10 :                      pd->client_id,
     618             :                      redirect_uri_encoded,
     619             :                      hps);
     620          10 :     GNUNET_free (redirect_uri_encoded);
     621             :   }
     622          10 :   ih->cb (ih->cb_cls,
     623             :           TALER_EC_NONE,
     624             :           url,
     625             :           NULL /* unknown user_id here */,
     626             :           legi_s,
     627             :           NULL /* no error */);
     628          10 :   GNUNET_free (url);
     629          10 :   GNUNET_free (hps);
     630          10 :   oauth2_initiate_cancel (ih);
     631          10 : }
     632             : 
     633             : 
     634             : /**
     635             :  * After we are done with the CURL interaction we
     636             :  * need to update our database state with the information
     637             :  * retrieved.
     638             :  *
     639             :  * @param cls a `struct TALER_KYCLOGIC_InitiateHandle *`
     640             :  * @param response_code HTTP response code from server, 0 on hard error
     641             :  * @param response in JSON, NULL if response was not in JSON format
     642             :  */
     643             : static void
     644           0 : handle_curl_setup_finished (void *cls,
     645             :                             long response_code,
     646             :                             const void *response)
     647             : {
     648           0 :   struct TALER_KYCLOGIC_InitiateHandle *ih = cls;
     649           0 :   const struct TALER_KYCLOGIC_ProviderDetails *pd = ih->pd;
     650           0 :   const json_t *j = response;
     651             : 
     652           0 :   ih->job = NULL;
     653           0 :   switch (response_code)
     654             :   {
     655           0 :   case 0:
     656           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     657             :                 "/setup URL failed to return HTTP response\n");
     658           0 :     ih->cb (ih->cb_cls,
     659             :             TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_INVALID_RESPONSE,
     660             :             NULL,
     661             :             NULL,
     662             :             NULL,
     663             :             "/setup request to OAuth 2.0 backend returned no response");
     664           0 :     oauth2_initiate_cancel (ih);
     665           0 :     return;
     666           0 :   case MHD_HTTP_OK:
     667             :     {
     668             :       const char *nonce;
     669             :       struct GNUNET_JSON_Specification spec[] = {
     670           0 :         GNUNET_JSON_spec_string ("nonce",
     671             :                                  &nonce),
     672           0 :         GNUNET_JSON_spec_end ()
     673             :       };
     674             :       enum GNUNET_GenericReturnValue res;
     675             :       const char *emsg;
     676             :       unsigned int line;
     677             :       char *url;
     678             : 
     679           0 :       res = GNUNET_JSON_parse (j,
     680             :                                spec,
     681             :                                &emsg,
     682             :                                &line);
     683           0 :       if (GNUNET_OK != res)
     684             :       {
     685           0 :         GNUNET_break_op (0);
     686           0 :         json_dumpf (j,
     687             :                     stderr,
     688             :                     JSON_INDENT (2));
     689           0 :         ih->cb (ih->cb_cls,
     690             :                 TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_INVALID_RESPONSE,
     691             :                 NULL,
     692             :                 NULL,
     693             :                 NULL,
     694             :                 "Unexpected response from KYC gateway: setup must return a nonce");
     695           0 :         oauth2_initiate_cancel (ih);
     696           0 :         return;
     697             :       }
     698           0 :       GNUNET_asprintf (&url,
     699             :                        "%s/%s",
     700           0 :                        pd->authorize_url,
     701             :                        nonce);
     702           0 :       initiate_with_url (ih,
     703             :                          url);
     704           0 :       GNUNET_free (url);
     705           0 :       return;
     706             :     }
     707             :     break;
     708           0 :   default:
     709           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     710             :                 "/setup URL returned HTTP status %u\n",
     711             :                 (unsigned int) response_code);
     712           0 :     ih->cb (ih->cb_cls,
     713             :             TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_INVALID_RESPONSE,
     714             :             NULL,
     715             :             NULL,
     716             :             NULL,
     717             :             "/setup request to OAuth 2.0 backend returned unexpected HTTP status code");
     718           0 :     oauth2_initiate_cancel (ih);
     719           0 :     return;
     720             :   }
     721             : }
     722             : 
     723             : 
     724             : /**
     725             :  * Logic to asynchronously return the response for how to begin the OAuth2.0
     726             :  * checking process to the client.  May first request a dynamic URL via
     727             :  * ``/setup`` if configured to use a client-authenticated setup process.
     728             :  *
     729             :  * @param cls a `struct TALER_KYCLOGIC_InitiateHandle *`
     730             :  */
     731             : static void
     732          10 : initiate_task (void *cls)
     733             : {
     734          10 :   struct TALER_KYCLOGIC_InitiateHandle *ih = cls;
     735          10 :   const struct TALER_KYCLOGIC_ProviderDetails *pd = ih->pd;
     736          10 :   struct PluginState *ps = pd->ps;
     737             :   CURL *eh;
     738             : 
     739          10 :   ih->task = NULL;
     740          10 :   if (NULL == pd->setup_url)
     741             :   {
     742          10 :     initiate_with_url (ih,
     743          10 :                        pd->authorize_url);
     744          10 :     return;
     745             :   }
     746           0 :   eh = curl_easy_init ();
     747           0 :   if (NULL == eh)
     748             :   {
     749           0 :     GNUNET_break (0);
     750           0 :     ih->cb (ih->cb_cls,
     751             :             TALER_EC_GENERIC_ALLOCATION_FAILURE,
     752             :             NULL,
     753             :             NULL,
     754             :             NULL,
     755             :             "curl_easy_init() failed");
     756           0 :     oauth2_initiate_cancel (ih);
     757           0 :     return;
     758             :   }
     759           0 :   GNUNET_assert (CURLE_OK ==
     760             :                  curl_easy_setopt (eh,
     761             :                                    CURLOPT_URL,
     762             :                                    pd->setup_url));
     763             : #if DEBUG
     764             :   GNUNET_assert (CURLE_OK ==
     765             :                  curl_easy_setopt (eh,
     766             :                                    CURLOPT_VERBOSE,
     767             :                                    1));
     768             : #endif
     769           0 :   if (NULL == ih->initial_address)
     770             :   {
     771           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     772             :                 "Staring OAuth 2.0 without initial address\n");
     773           0 :     GNUNET_assert (CURLE_OK ==
     774             :                    curl_easy_setopt (eh,
     775             :                                      CURLOPT_POST,
     776             :                                      1));
     777           0 :     GNUNET_assert (CURLE_OK ==
     778             :                    curl_easy_setopt (eh,
     779             :                                      CURLOPT_POSTFIELDS,
     780             :                                      ""));
     781           0 :     GNUNET_assert (CURLE_OK ==
     782             :                    curl_easy_setopt (eh,
     783             :                                      CURLOPT_POSTFIELDSIZE,
     784             :                                      (long) 0));
     785             :   }
     786             :   else
     787             :   {
     788           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     789             :                 "Staring OAuth 2.0 with initial address\n");
     790             : #if DEBUG
     791             :     json_dumpf (ih->initial_address,
     792             :                 stderr,
     793             :                 JSON_INDENT (2));
     794             :     fprintf (stderr,
     795             :              "\n");
     796             : #endif
     797           0 :     if (GNUNET_OK !=
     798           0 :         TALER_curl_easy_post (&ih->ctx,
     799             :                               eh,
     800           0 :                               ih->initial_address))
     801             :     {
     802           0 :       curl_easy_cleanup (eh);
     803           0 :       ih->cb (ih->cb_cls,
     804             :               TALER_EC_GENERIC_ALLOCATION_FAILURE,
     805             :               NULL,
     806             :               NULL,
     807             :               NULL,
     808             :               "TALER_curl_easy_post() failed");
     809           0 :       oauth2_initiate_cancel (ih);
     810           0 :       return;
     811             :     }
     812             :   }
     813           0 :   GNUNET_assert (CURLE_OK ==
     814             :                  curl_easy_setopt (eh,
     815             :                                    CURLOPT_FOLLOWLOCATION,
     816             :                                    1L));
     817           0 :   GNUNET_assert (CURLE_OK ==
     818             :                  curl_easy_setopt (eh,
     819             :                                    CURLOPT_MAXREDIRS,
     820             :                                    5L));
     821           0 :   ih->job = GNUNET_CURL_job_add2 (ps->curl_ctx,
     822             :                                   eh,
     823           0 :                                   ih->ctx.headers,
     824             :                                   &handle_curl_setup_finished,
     825             :                                   ih);
     826             :   {
     827             :     char *hdr;
     828             :     struct curl_slist *slist;
     829             : 
     830           0 :     GNUNET_asprintf (&hdr,
     831             :                      "%s: Bearer %s",
     832             :                      MHD_HTTP_HEADER_AUTHORIZATION,
     833           0 :                      pd->client_secret);
     834           0 :     slist = curl_slist_append (NULL,
     835             :                                hdr);
     836           0 :     GNUNET_CURL_extend_headers (ih->job,
     837             :                                 slist);
     838           0 :     curl_slist_free_all (slist);
     839           0 :     GNUNET_free (hdr);
     840             :   }
     841             : }
     842             : 
     843             : 
     844             : /**
     845             :  * Initiate KYC check.
     846             :  *
     847             :  * @param cls the @e cls of this struct with the plugin-specific state
     848             :  * @param pd provider configuration details
     849             :  * @param account_id which account to trigger process for
     850             :  * @param legitimization_uuid unique ID for the legitimization process
     851             :  * @param context additional contextual information for the legi process
     852             :  * @param cb function to call with the result
     853             :  * @param cb_cls closure for @a cb
     854             :  * @return handle to cancel operation early
     855             :  */
     856             : static struct TALER_KYCLOGIC_InitiateHandle *
     857          10 : oauth2_initiate (void *cls,
     858             :                  const struct TALER_KYCLOGIC_ProviderDetails *pd,
     859             :                  const struct TALER_NormalizedPaytoHashP *account_id,
     860             :                  uint64_t legitimization_uuid,
     861             :                  const json_t *context,
     862             :                  TALER_KYCLOGIC_InitiateCallback cb,
     863             :                  void *cb_cls)
     864             : {
     865             :   struct TALER_KYCLOGIC_InitiateHandle *ih;
     866             : 
     867             :   (void) cls;
     868          10 :   ih = GNUNET_new (struct TALER_KYCLOGIC_InitiateHandle);
     869          10 :   ih->legitimization_uuid = legitimization_uuid;
     870          10 :   ih->cb = cb;
     871          10 :   ih->cb_cls = cb_cls;
     872          10 :   ih->h_payto = *account_id;
     873          10 :   ih->pd = pd;
     874          10 :   ih->task = GNUNET_SCHEDULER_add_now (&initiate_task,
     875             :                                        ih);
     876          10 :   if (NULL != context)
     877             :   {
     878          10 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     879             :                 "Initiating OAuth2 validation with context\n");
     880             : #if DEBUG
     881             :     json_dumpf (context,
     882             :                 stderr,
     883             :                 JSON_INDENT (2));
     884             :     fprintf (stderr,
     885             :              "\n");
     886             : #endif
     887          10 :     ih->initial_address = json_incref (json_object_get (context,
     888             :                                                         "initial_address"));
     889             :   }
     890          10 :   return ih;
     891             : }
     892             : 
     893             : 
     894             : /**
     895             :  * Cancel KYC proof.
     896             :  *
     897             :  * @param[in] ph handle of operation to cancel
     898             :  */
     899             : static void
     900          11 : oauth2_proof_cancel (struct TALER_KYCLOGIC_ProofHandle *ph)
     901             : {
     902          11 :   if (NULL != ph->ec)
     903             :   {
     904           0 :     TALER_JSON_external_conversion_stop (ph->ec);
     905           0 :     ph->ec = NULL;
     906             :   }
     907          11 :   if (NULL != ph->task)
     908             :   {
     909           0 :     GNUNET_SCHEDULER_cancel (ph->task);
     910           0 :     ph->task = NULL;
     911             :   }
     912          11 :   if (NULL != ph->job)
     913             :   {
     914           0 :     GNUNET_CURL_job_cancel (ph->job);
     915           0 :     ph->job = NULL;
     916             :   }
     917          11 :   if (NULL != ph->response)
     918             :   {
     919           0 :     MHD_destroy_response (ph->response);
     920           0 :     ph->response = NULL;
     921             :   }
     922          11 :   GNUNET_free (ph->provider_user_id);
     923          11 :   if (NULL != ph->attributes)
     924           9 :     json_decref (ph->attributes);
     925          11 :   GNUNET_free (ph->post_body);
     926          11 :   GNUNET_free (ph);
     927          11 : }
     928             : 
     929             : 
     930             : /**
     931             :  * Function called to asynchronously return the final
     932             :  * result to the callback.
     933             :  *
     934             :  * @param cls a `struct TALER_KYCLOGIC_ProofHandle`
     935             :  */
     936             : static void
     937          11 : return_proof_response (void *cls)
     938             : {
     939          11 :   struct TALER_KYCLOGIC_ProofHandle *ph = cls;
     940             :   const char *provider_name;
     941             : 
     942          11 :   ph->task = NULL;
     943          11 :   provider_name = ph->pd->section;
     944          11 :   if (0 !=
     945          11 :       strncasecmp (provider_name,
     946             :                    "KYC-PROVIDER-",
     947             :                    strlen ("KYC-PROVIDER-")))
     948             :   {
     949           0 :     GNUNET_break (0);
     950             :   }
     951             :   else
     952             :   {
     953          11 :     provider_name += strlen ("KYC-PROVIDER-");
     954             :   }
     955          11 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     956             :               "Returning KYC proof from `%s'\n",
     957             :               provider_name);
     958          22 :   ph->cb (ph->cb_cls,
     959             :           ph->status,
     960             :           provider_name,
     961          11 :           ph->provider_user_id,
     962          11 :           ph->provider_legitimization_id,
     963          11 :           GNUNET_TIME_relative_to_absolute (ph->pd->validity),
     964          11 :           ph->attributes,
     965             :           ph->http_status,
     966             :           ph->response);
     967          11 :   ph->response = NULL; /*Ownership passed to 'ph->cb'!*/
     968          11 :   oauth2_proof_cancel (ph);
     969          11 : }
     970             : 
     971             : 
     972             : /**
     973             :  * The request for @a ph failed. We may have gotten a useful error
     974             :  * message in @a j. Generate a failure response.
     975             :  *
     976             :  * @param[in,out] ph request that failed
     977             :  * @param j reply from the server (or NULL)
     978             :  */
     979             : static void
     980           2 : handle_proof_error (struct TALER_KYCLOGIC_ProofHandle *ph,
     981             :                     const json_t *j)
     982             : {
     983             :   enum GNUNET_GenericReturnValue res;
     984             : 
     985             :   {
     986             :     const char *msg;
     987             :     const char *desc;
     988             :     struct GNUNET_JSON_Specification spec[] = {
     989           2 :       GNUNET_JSON_spec_string ("error",
     990             :                                &msg),
     991           2 :       GNUNET_JSON_spec_string ("error_description",
     992             :                                &desc),
     993           2 :       GNUNET_JSON_spec_end ()
     994             :     };
     995             :     const char *emsg;
     996             :     unsigned int line;
     997             : 
     998           2 :     res = GNUNET_JSON_parse (j,
     999             :                              spec,
    1000             :                              &emsg,
    1001             :                              &line);
    1002             :   }
    1003             : 
    1004           2 :   if (GNUNET_OK != res)
    1005             :   {
    1006             :     json_t *body;
    1007             : 
    1008           1 :     GNUNET_break_op (0);
    1009           1 :     ph->status = TALER_KYCLOGIC_STATUS_PROVIDER_FAILED;
    1010             :     ph->http_status
    1011           1 :       = MHD_HTTP_BAD_GATEWAY;
    1012           1 :     body = GNUNET_JSON_PACK (
    1013             :       GNUNET_JSON_pack_allow_null (
    1014             :         GNUNET_JSON_pack_object_incref ("server_response",
    1015             :                                         (json_t *) j)),
    1016             :       GNUNET_JSON_pack_bool ("debug",
    1017             :                              ph->pd->debug_mode),
    1018             :       TALER_JSON_pack_ec (
    1019             :         TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_INVALID_RESPONSE));
    1020           1 :     GNUNET_assert (NULL != body);
    1021           1 :     GNUNET_break (
    1022             :       GNUNET_SYSERR !=
    1023             :       TALER_TEMPLATING_build (ph->connection,
    1024             :                               &ph->http_status,
    1025             :                               "oauth2-authorization-failure-malformed",
    1026             :                               NULL,
    1027             :                               NULL,
    1028             :                               body,
    1029             :                               &ph->response));
    1030           1 :     json_decref (body);
    1031           1 :     return;
    1032             :   }
    1033           1 :   ph->status = TALER_KYCLOGIC_STATUS_USER_ABORTED;
    1034           1 :   ph->http_status = MHD_HTTP_FORBIDDEN;
    1035           1 :   GNUNET_break (
    1036             :     GNUNET_SYSERR !=
    1037             :     TALER_TEMPLATING_build (ph->connection,
    1038             :                             &ph->http_status,
    1039             :                             "oauth2-authorization-failure",
    1040             :                             NULL,
    1041             :                             NULL,
    1042             :                             j,
    1043             :                             &ph->response));
    1044             : }
    1045             : 
    1046             : 
    1047             : /**
    1048             :  * Type of a callback that receives a JSON @a result.
    1049             :  *
    1050             :  * @param cls closure with a `struct TALER_KYCLOGIC_ProofHandle *`
    1051             :  * @param status_type how did the process die
    1052             :  * @param code termination status code from the process
    1053             :  * @param attr result some JSON result, NULL if we failed to get an JSON output
    1054             :  */
    1055             : static void
    1056           9 : converted_proof_cb (void *cls,
    1057             :                     enum GNUNET_OS_ProcessStatusType status_type,
    1058             :                     unsigned long code,
    1059             :                     const json_t *attr)
    1060             : {
    1061           9 :   struct TALER_KYCLOGIC_ProofHandle *ph = cls;
    1062           9 :   const struct TALER_KYCLOGIC_ProviderDetails *pd = ph->pd;
    1063             : 
    1064           9 :   ph->ec = NULL;
    1065           9 :   if ( (NULL == attr) ||
    1066             :        (0 != code) )
    1067             :   {
    1068             :     json_t *body;
    1069             :     char *msg;
    1070             : 
    1071           0 :     GNUNET_break_op (0);
    1072           0 :     ph->status = TALER_KYCLOGIC_STATUS_PROVIDER_FAILED;
    1073           0 :     ph->http_status = MHD_HTTP_BAD_GATEWAY;
    1074           0 :     if (0 != code)
    1075           0 :       GNUNET_asprintf (&msg,
    1076             :                        "Attribute converter exited with status %ld",
    1077             :                        code);
    1078             :     else
    1079           0 :       msg = GNUNET_strdup (
    1080             :         "Attribute converter response was not in JSON format");
    1081           0 :     body = GNUNET_JSON_PACK (
    1082             :       GNUNET_JSON_pack_string ("converter",
    1083             :                                pd->conversion_binary),
    1084             :       GNUNET_JSON_pack_allow_null (
    1085             :         GNUNET_JSON_pack_object_incref ("attributes",
    1086             :                                         (json_t *) attr)),
    1087             :       GNUNET_JSON_pack_bool ("debug",
    1088             :                              ph->pd->debug_mode),
    1089             :       GNUNET_JSON_pack_string ("message",
    1090             :                                msg),
    1091             :       TALER_JSON_pack_ec (
    1092             :         TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_INVALID_RESPONSE));
    1093           0 :     GNUNET_free (msg);
    1094           0 :     GNUNET_break (
    1095             :       GNUNET_SYSERR !=
    1096             :       TALER_TEMPLATING_build (ph->connection,
    1097             :                               &ph->http_status,
    1098             :                               "oauth2-conversion-failure",
    1099             :                               NULL,
    1100             :                               NULL,
    1101             :                               body,
    1102             :                               &ph->response));
    1103           0 :     json_decref (body);
    1104           0 :     ph->task = GNUNET_SCHEDULER_add_now (&return_proof_response,
    1105             :                                          ph);
    1106           0 :     return;
    1107             :   }
    1108           9 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1109             :               "Attribute conversion output is:\n");
    1110             : #if DEBUG
    1111             :   json_dumpf (attr,
    1112             :               stderr,
    1113             :               JSON_INDENT (2));
    1114             :   fprintf (stderr,
    1115             :            "\n");
    1116             : #endif
    1117             :   {
    1118             :     const char *id;
    1119             :     struct GNUNET_JSON_Specification ispec[] = {
    1120           9 :       GNUNET_JSON_spec_string ("id",
    1121             :                                &id),
    1122           9 :       GNUNET_JSON_spec_end ()
    1123             :     };
    1124             :     enum GNUNET_GenericReturnValue res;
    1125             :     const char *emsg;
    1126             :     unsigned int line;
    1127             : 
    1128           9 :     res = GNUNET_JSON_parse (attr,
    1129             :                              ispec,
    1130             :                              &emsg,
    1131             :                              &line);
    1132           9 :     if (GNUNET_OK != res)
    1133             :     {
    1134             :       json_t *body;
    1135             : 
    1136           0 :       GNUNET_break_op (0);
    1137           0 :       ph->status = TALER_KYCLOGIC_STATUS_PROVIDER_FAILED;
    1138           0 :       ph->http_status = MHD_HTTP_BAD_GATEWAY;
    1139           0 :       body = GNUNET_JSON_PACK (
    1140             :         GNUNET_JSON_pack_string ("converter",
    1141             :                                  pd->conversion_binary),
    1142             :         GNUNET_JSON_pack_string ("message",
    1143             :                                  "Unexpected response from KYC attribute converter: returned JSON data must contain 'id' field"),
    1144             :         GNUNET_JSON_pack_bool ("debug",
    1145             :                                ph->pd->debug_mode),
    1146             :         GNUNET_JSON_pack_object_incref ("attributes",
    1147             :                                         (json_t *) attr),
    1148             :         TALER_JSON_pack_ec (
    1149             :           TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_INVALID_RESPONSE));
    1150           0 :       GNUNET_break (
    1151             :         GNUNET_SYSERR !=
    1152             :         TALER_TEMPLATING_build (ph->connection,
    1153             :                                 &ph->http_status,
    1154             :                                 "oauth2-conversion-failure",
    1155             :                                 NULL,
    1156             :                                 NULL,
    1157             :                                 body,
    1158             :                                 &ph->response));
    1159           0 :       json_decref (body);
    1160           0 :       ph->task = GNUNET_SCHEDULER_add_now (&return_proof_response,
    1161             :                                            ph);
    1162           0 :       return;
    1163             :     }
    1164           9 :     ph->provider_user_id = GNUNET_strdup (id);
    1165             :   }
    1166           9 :   ph->status = TALER_KYCLOGIC_STATUS_SUCCESS;
    1167           9 :   ph->response = MHD_create_response_from_buffer_static (0,
    1168             :                                                          "");
    1169           9 :   GNUNET_assert (NULL != ph->response);
    1170           9 :   GNUNET_break (MHD_YES ==
    1171             :                 MHD_add_response_header (
    1172             :                   ph->response,
    1173             :                   MHD_HTTP_HEADER_LOCATION,
    1174             :                   ph->pd->post_kyc_redirect_url));
    1175           9 :   ph->http_status = MHD_HTTP_SEE_OTHER;
    1176           9 :   ph->attributes = json_incref ((json_t *) attr);
    1177           9 :   ph->task = GNUNET_SCHEDULER_add_now (&return_proof_response,
    1178             :                                        ph);
    1179             : }
    1180             : 
    1181             : 
    1182             : /**
    1183             :  * The request for @a ph succeeded (presumably).
    1184             :  * Call continuation with the result.
    1185             :  *
    1186             :  * @param[in,out] ph request that succeeded
    1187             :  * @param j reply from the server
    1188             :  */
    1189             : static void
    1190           9 : parse_proof_success_reply (struct TALER_KYCLOGIC_ProofHandle *ph,
    1191             :                            const json_t *j)
    1192             : {
    1193           9 :   const struct TALER_KYCLOGIC_ProviderDetails *pd = ph->pd;
    1194           9 :   const char *argv[] = {
    1195           9 :     pd->conversion_binary,
    1196             :     NULL,
    1197             :   };
    1198             : 
    1199           9 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1200             :               "Calling converter `%s' with JSON\n",
    1201             :               pd->conversion_binary);
    1202             : #if DEBUG
    1203             :   json_dumpf (j,
    1204             :               stderr,
    1205             :               JSON_INDENT (2));
    1206             : #endif
    1207          18 :   ph->ec = TALER_JSON_external_conversion_start (
    1208             :     j,
    1209             :     &converted_proof_cb,
    1210             :     ph,
    1211           9 :     pd->conversion_binary,
    1212             :     argv);
    1213           9 :   if (NULL != ph->ec)
    1214           9 :     return;
    1215           0 :   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1216             :               "Failed to start OAUTH2 conversion helper `%s'\n",
    1217             :               pd->conversion_binary);
    1218           0 :   ph->status = TALER_KYCLOGIC_STATUS_INTERNAL_ERROR;
    1219           0 :   ph->http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
    1220             :   {
    1221             :     json_t *body;
    1222             : 
    1223           0 :     body = GNUNET_JSON_PACK (
    1224             :       GNUNET_JSON_pack_string ("converter",
    1225             :                                pd->conversion_binary),
    1226             :       GNUNET_JSON_pack_bool ("debug",
    1227             :                              ph->pd->debug_mode),
    1228             :       GNUNET_JSON_pack_string ("message",
    1229             :                                "Failed to launch KYC conversion helper process."),
    1230             :       TALER_JSON_pack_ec (
    1231             :         TALER_EC_EXCHANGE_GENERIC_KYC_CONVERTER_FAILED));
    1232           0 :     GNUNET_break (
    1233             :       GNUNET_SYSERR !=
    1234             :       TALER_TEMPLATING_build (ph->connection,
    1235             :                               &ph->http_status,
    1236             :                               "oauth2-conversion-failure",
    1237             :                               NULL,
    1238             :                               NULL,
    1239             :                               body,
    1240             :                               &ph->response));
    1241           0 :     json_decref (body);
    1242             :   }
    1243           0 :   ph->task = GNUNET_SCHEDULER_add_now (&return_proof_response,
    1244             :                                        ph);
    1245             : }
    1246             : 
    1247             : 
    1248             : /**
    1249             :  * After we are done with the CURL interaction we
    1250             :  * need to update our database state with the information
    1251             :  * retrieved.
    1252             :  *
    1253             :  * @param cls our `struct TALER_KYCLOGIC_ProofHandle`
    1254             :  * @param response_code HTTP response code from server, 0 on hard error
    1255             :  * @param response in JSON, NULL if response was not in JSON format
    1256             :  */
    1257             : static void
    1258           9 : handle_curl_proof_finished (void *cls,
    1259             :                             long response_code,
    1260             :                             const void *response)
    1261             : {
    1262           9 :   struct TALER_KYCLOGIC_ProofHandle *ph = cls;
    1263           9 :   const json_t *j = response;
    1264             : 
    1265           9 :   ph->job = NULL;
    1266           9 :   switch (response_code)
    1267             :   {
    1268           0 :   case 0:
    1269             :     {
    1270             :       json_t *body;
    1271             : 
    1272           0 :       ph->status = TALER_KYCLOGIC_STATUS_PROVIDER_FAILED;
    1273           0 :       ph->http_status = MHD_HTTP_BAD_GATEWAY;
    1274             : 
    1275           0 :       body = GNUNET_JSON_PACK (
    1276             :         GNUNET_JSON_pack_string ("message",
    1277             :                                  "No response from KYC gateway"),
    1278             :         TALER_JSON_pack_ec (
    1279             :           TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_INVALID_RESPONSE));
    1280           0 :       GNUNET_break (
    1281             :         GNUNET_SYSERR !=
    1282             :         TALER_TEMPLATING_build (ph->connection,
    1283             :                                 &ph->http_status,
    1284             :                                 "oauth2-provider-failure",
    1285             :                                 NULL,
    1286             :                                 NULL,
    1287             :                                 body,
    1288             :                                 &ph->response));
    1289           0 :       json_decref (body);
    1290             :     }
    1291           0 :     break;
    1292           9 :   case MHD_HTTP_OK:
    1293           9 :     parse_proof_success_reply (ph,
    1294             :                                j);
    1295           9 :     return;
    1296           0 :   default:
    1297           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1298             :                 "OAuth2.0 info URL returned HTTP status %u\n",
    1299             :                 (unsigned int) response_code);
    1300           0 :     handle_proof_error (ph,
    1301             :                         j);
    1302           0 :     break;
    1303             :   }
    1304           0 :   ph->task = GNUNET_SCHEDULER_add_now (&return_proof_response,
    1305             :                                        ph);
    1306             : }
    1307             : 
    1308             : 
    1309             : /**
    1310             :  * After we are done with the CURL interaction we
    1311             :  * need to fetch the user's account details.
    1312             :  *
    1313             :  * @param cls our `struct KycProofContext`
    1314             :  * @param response_code HTTP response code from server, 0 on hard error
    1315             :  * @param response in JSON, NULL if response was not in JSON format
    1316             :  */
    1317             : static void
    1318          11 : handle_curl_login_finished (void *cls,
    1319             :                             long response_code,
    1320             :                             const void *response)
    1321             : {
    1322          11 :   struct TALER_KYCLOGIC_ProofHandle *ph = cls;
    1323          11 :   const json_t *j = response;
    1324             : 
    1325          11 :   ph->job = NULL;
    1326          11 :   switch (response_code)
    1327             :   {
    1328           9 :   case MHD_HTTP_OK:
    1329             :     {
    1330             :       const char *access_token;
    1331             :       const char *token_type;
    1332             :       uint64_t expires_in_s;
    1333             :       const char *refresh_token;
    1334             :       bool no_expires;
    1335             :       bool no_refresh;
    1336             :       struct GNUNET_JSON_Specification spec[] = {
    1337           9 :         GNUNET_JSON_spec_string ("access_token",
    1338             :                                  &access_token),
    1339           9 :         GNUNET_JSON_spec_string ("token_type",
    1340             :                                  &token_type),
    1341           9 :         GNUNET_JSON_spec_mark_optional (
    1342             :           GNUNET_JSON_spec_uint64 ("expires_in",
    1343             :                                    &expires_in_s),
    1344             :           &no_expires),
    1345           9 :         GNUNET_JSON_spec_mark_optional (
    1346             :           GNUNET_JSON_spec_string ("refresh_token",
    1347             :                                    &refresh_token),
    1348             :           &no_refresh),
    1349           9 :         GNUNET_JSON_spec_end ()
    1350             :       };
    1351             :       CURL *eh;
    1352             : 
    1353             :       {
    1354             :         enum GNUNET_GenericReturnValue res;
    1355             :         const char *emsg;
    1356             :         unsigned int line;
    1357             : 
    1358           9 :         res = GNUNET_JSON_parse (j,
    1359             :                                  spec,
    1360             :                                  &emsg,
    1361             :                                  &line);
    1362           9 :         if (GNUNET_OK != res)
    1363             :         {
    1364             :           json_t *body;
    1365             : 
    1366           0 :           GNUNET_break_op (0);
    1367             :           ph->http_status
    1368           0 :             = MHD_HTTP_BAD_GATEWAY;
    1369           0 :           body = GNUNET_JSON_PACK (
    1370             :             GNUNET_JSON_pack_object_incref ("server_response",
    1371             :                                             (json_t *) j),
    1372             :             GNUNET_JSON_pack_bool ("debug",
    1373             :                                    ph->pd->debug_mode),
    1374             :             GNUNET_JSON_pack_string ("message",
    1375             :                                      "Unexpected response from KYC gateway: required fields missing or malformed"),
    1376             :             TALER_JSON_pack_ec (
    1377             :               TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_INVALID_RESPONSE));
    1378           0 :           GNUNET_break (
    1379             :             GNUNET_SYSERR !=
    1380             :             TALER_TEMPLATING_build (ph->connection,
    1381             :                                     &ph->http_status,
    1382             :                                     "oauth2-provider-failure",
    1383             :                                     NULL,
    1384             :                                     NULL,
    1385             :                                     body,
    1386             :                                     &ph->response));
    1387           0 :           json_decref (body);
    1388           0 :           break;
    1389             :         }
    1390             :       }
    1391           9 :       if (0 != strcasecmp (token_type,
    1392             :                            "bearer"))
    1393             :       {
    1394             :         json_t *body;
    1395             : 
    1396           0 :         GNUNET_break_op (0);
    1397           0 :         ph->http_status = MHD_HTTP_BAD_GATEWAY;
    1398           0 :         body = GNUNET_JSON_PACK (
    1399             :           GNUNET_JSON_pack_object_incref ("server_response",
    1400             :                                           (json_t *) j),
    1401             :           GNUNET_JSON_pack_bool ("debug",
    1402             :                                  ph->pd->debug_mode),
    1403             :           GNUNET_JSON_pack_string ("message",
    1404             :                                    "Unexpected 'token_type' in response from KYC gateway: 'bearer' token required"),
    1405             :           TALER_JSON_pack_ec (
    1406             :             TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_INVALID_RESPONSE));
    1407           0 :         GNUNET_break (
    1408             :           GNUNET_SYSERR !=
    1409             :           TALER_TEMPLATING_build (ph->connection,
    1410             :                                   &ph->http_status,
    1411             :                                   "oauth2-provider-failure",
    1412             :                                   NULL,
    1413             :                                   NULL,
    1414             :                                   body,
    1415             :                                   &ph->response));
    1416           0 :         json_decref (body);
    1417           0 :         break;
    1418             :       }
    1419             : 
    1420             :       /* We guard against a few characters that could
    1421             :          conceivably be abused to mess with the HTTP header */
    1422           9 :       if ( (NULL != strchr (access_token,
    1423           9 :                             '\n')) ||
    1424           9 :            (NULL != strchr (access_token,
    1425           9 :                             '\r')) ||
    1426           9 :            (NULL != strchr (access_token,
    1427           9 :                             ' ')) ||
    1428           9 :            (NULL != strchr (access_token,
    1429             :                             ';')) )
    1430             :       {
    1431             :         json_t *body;
    1432             : 
    1433           0 :         GNUNET_break_op (0);
    1434           0 :         ph->http_status = MHD_HTTP_BAD_GATEWAY;
    1435           0 :         body = GNUNET_JSON_PACK (
    1436             :           GNUNET_JSON_pack_object_incref ("server_response",
    1437             :                                           (json_t *) j),
    1438             :           GNUNET_JSON_pack_bool ("debug",
    1439             :                                  ph->pd->debug_mode),
    1440             :           GNUNET_JSON_pack_string ("message",
    1441             :                                    "Illegal character in access token"),
    1442             :           TALER_JSON_pack_ec (
    1443             :             TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_INVALID_RESPONSE));
    1444           0 :         GNUNET_break (
    1445             :           GNUNET_SYSERR !=
    1446             :           TALER_TEMPLATING_build (ph->connection,
    1447             :                                   &ph->http_status,
    1448             :                                   "oauth2-provider-failure",
    1449             :                                   NULL,
    1450             :                                   NULL,
    1451             :                                   body,
    1452             :                                   &ph->response));
    1453           0 :         json_decref (body);
    1454           0 :         break;
    1455             :       }
    1456             : 
    1457           9 :       eh = curl_easy_init ();
    1458           9 :       GNUNET_assert (NULL != eh);
    1459           9 :       GNUNET_assert (CURLE_OK ==
    1460             :                      curl_easy_setopt (eh,
    1461             :                                        CURLOPT_URL,
    1462             :                                        ph->pd->info_url));
    1463             :       {
    1464             :         char *hdr;
    1465             :         struct curl_slist *slist;
    1466             : 
    1467           9 :         GNUNET_asprintf (&hdr,
    1468             :                          "%s: Bearer %s",
    1469             :                          MHD_HTTP_HEADER_AUTHORIZATION,
    1470             :                          access_token);
    1471           9 :         slist = curl_slist_append (NULL,
    1472             :                                    hdr);
    1473           9 :         ph->job = GNUNET_CURL_job_add2 (ph->pd->ps->curl_ctx,
    1474             :                                         eh,
    1475             :                                         slist,
    1476             :                                         &handle_curl_proof_finished,
    1477             :                                         ph);
    1478           9 :         curl_slist_free_all (slist);
    1479           9 :         GNUNET_free (hdr);
    1480             :       }
    1481           9 :       return;
    1482             :     }
    1483           2 :   default:
    1484           2 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1485             :                 "OAuth2.0 login URL returned HTTP status %u\n",
    1486             :                 (unsigned int) response_code);
    1487           2 :     handle_proof_error (ph,
    1488             :                         j);
    1489           2 :     break;
    1490             :   }
    1491           2 :   return_proof_response (ph);
    1492             : }
    1493             : 
    1494             : 
    1495             : /**
    1496             :  * Check KYC status and return status to human.
    1497             :  *
    1498             :  * @param cls the @e cls of this struct with the plugin-specific state
    1499             :  * @param pd provider configuration details
    1500             :  * @param connection MHD connection object (for HTTP headers)
    1501             :  * @param account_id which account to trigger process for
    1502             :  * @param process_row row in the legitimization processes table the legitimization is for
    1503             :  * @param provider_user_id user ID (or NULL) the proof is for
    1504             :  * @param provider_legitimization_id legitimization ID the proof is for
    1505             :  * @param cb function to call with the result
    1506             :  * @param cb_cls closure for @a cb
    1507             :  * @return handle to cancel operation early
    1508             :  */
    1509             : static struct TALER_KYCLOGIC_ProofHandle *
    1510          11 : oauth2_proof (void *cls,
    1511             :               const struct TALER_KYCLOGIC_ProviderDetails *pd,
    1512             :               struct MHD_Connection *connection,
    1513             :               const struct TALER_NormalizedPaytoHashP *account_id,
    1514             :               uint64_t process_row,
    1515             :               const char *provider_user_id,
    1516             :               const char *provider_legitimization_id,
    1517             :               TALER_KYCLOGIC_ProofCallback cb,
    1518             :               void *cb_cls)
    1519             : {
    1520          11 :   struct PluginState *ps = cls;
    1521             :   struct TALER_KYCLOGIC_ProofHandle *ph;
    1522             :   const char *code;
    1523             : 
    1524          11 :   GNUNET_break (NULL == provider_user_id);
    1525          11 :   ph = GNUNET_new (struct TALER_KYCLOGIC_ProofHandle);
    1526          11 :   GNUNET_snprintf (ph->provider_legitimization_id,
    1527             :                    sizeof (ph->provider_legitimization_id),
    1528             :                    "%llu",
    1529             :                    (unsigned long long) process_row);
    1530          11 :   if ( (NULL != provider_legitimization_id) &&
    1531          11 :        (0 != strcmp (provider_legitimization_id,
    1532          11 :                      ph->provider_legitimization_id)))
    1533             :   {
    1534           0 :     GNUNET_break (0);
    1535           0 :     GNUNET_free (ph);
    1536           0 :     return NULL;
    1537             :   }
    1538             : 
    1539          11 :   ph->pd = pd;
    1540          11 :   ph->connection = connection;
    1541          11 :   ph->h_payto = *account_id;
    1542          11 :   ph->cb = cb;
    1543          11 :   ph->cb_cls = cb_cls;
    1544          11 :   code = MHD_lookup_connection_value (connection,
    1545             :                                       MHD_GET_ARGUMENT_KIND,
    1546             :                                       "code");
    1547          11 :   if (NULL == code)
    1548             :   {
    1549             :     const char *err;
    1550             :     const char *desc;
    1551             :     const char *euri;
    1552             :     json_t *body;
    1553             : 
    1554           0 :     err = MHD_lookup_connection_value (connection,
    1555             :                                        MHD_GET_ARGUMENT_KIND,
    1556             :                                        "error");
    1557           0 :     if (NULL == err)
    1558             :     {
    1559           0 :       GNUNET_break_op (0);
    1560           0 :       ph->status = TALER_KYCLOGIC_STATUS_USER_PENDING;
    1561           0 :       ph->http_status = MHD_HTTP_BAD_REQUEST;
    1562           0 :       body = GNUNET_JSON_PACK (
    1563             :         GNUNET_JSON_pack_string ("message",
    1564             :                                  "'code' parameter malformed"),
    1565             :         TALER_JSON_pack_ec (
    1566             :           TALER_EC_GENERIC_PARAMETER_MALFORMED));
    1567           0 :       GNUNET_break (
    1568             :         GNUNET_SYSERR !=
    1569             :         TALER_TEMPLATING_build (ph->connection,
    1570             :                                 &ph->http_status,
    1571             :                                 "oauth2-bad-request",
    1572             :                                 NULL,
    1573             :                                 NULL,
    1574             :                                 body,
    1575             :                                 &ph->response));
    1576           0 :       json_decref (body);
    1577           0 :       ph->task = GNUNET_SCHEDULER_add_now (&return_proof_response,
    1578             :                                            ph);
    1579           0 :       return ph;
    1580             :     }
    1581           0 :     desc = MHD_lookup_connection_value (connection,
    1582             :                                         MHD_GET_ARGUMENT_KIND,
    1583             :                                         "error_description");
    1584           0 :     euri = MHD_lookup_connection_value (connection,
    1585             :                                         MHD_GET_ARGUMENT_KIND,
    1586             :                                         "error_uri");
    1587           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1588             :                 "OAuth2 process %llu failed with error `%s'\n",
    1589             :                 (unsigned long long) process_row,
    1590             :                 err);
    1591           0 :     if (0 == strcasecmp (err,
    1592             :                          "server_error"))
    1593           0 :       ph->status = TALER_KYCLOGIC_STATUS_PROVIDER_FAILED;
    1594           0 :     else if (0 == strcasecmp (err,
    1595             :                               "unauthorized_client"))
    1596           0 :       ph->status = TALER_KYCLOGIC_STATUS_FAILED;
    1597           0 :     else if (0 == strcasecmp (err,
    1598             :                               "temporarily_unavailable"))
    1599           0 :       ph->status = TALER_KYCLOGIC_STATUS_PENDING;
    1600             :     else
    1601           0 :       ph->status = TALER_KYCLOGIC_STATUS_INTERNAL_ERROR;
    1602           0 :     ph->http_status = MHD_HTTP_FORBIDDEN;
    1603           0 :     body = GNUNET_JSON_PACK (
    1604             :       GNUNET_JSON_pack_string ("error",
    1605             :                                err),
    1606             :       GNUNET_JSON_pack_allow_null (
    1607             :         GNUNET_JSON_pack_string ("error_details",
    1608             :                                  desc)),
    1609             :       GNUNET_JSON_pack_allow_null (
    1610             :         GNUNET_JSON_pack_string ("error_uri",
    1611             :                                  euri)));
    1612           0 :     GNUNET_break (
    1613             :       GNUNET_SYSERR !=
    1614             :       TALER_TEMPLATING_build (ph->connection,
    1615             :                               &ph->http_status,
    1616             :                               "oauth2-authentication-failure",
    1617             :                               NULL,
    1618             :                               NULL,
    1619             :                               body,
    1620             :                               &ph->response));
    1621           0 :     json_decref (body);
    1622           0 :     ph->task = GNUNET_SCHEDULER_add_now (&return_proof_response,
    1623             :                                          ph);
    1624           0 :     return ph;
    1625             : 
    1626             :   }
    1627             : 
    1628          11 :   ph->eh = curl_easy_init ();
    1629          11 :   GNUNET_assert (NULL != ph->eh);
    1630          11 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1631             :               "Requesting OAuth 2.0 data via HTTP POST `%s'\n",
    1632             :               pd->token_url);
    1633          11 :   GNUNET_assert (CURLE_OK ==
    1634             :                  curl_easy_setopt (ph->eh,
    1635             :                                    CURLOPT_URL,
    1636             :                                    pd->token_url));
    1637          11 :   GNUNET_assert (CURLE_OK ==
    1638             :                  curl_easy_setopt (ph->eh,
    1639             :                                    CURLOPT_VERBOSE,
    1640             :                                    1));
    1641          11 :   GNUNET_assert (CURLE_OK ==
    1642             :                  curl_easy_setopt (ph->eh,
    1643             :                                    CURLOPT_POST,
    1644             :                                    1));
    1645             :   {
    1646             :     char *client_id;
    1647             :     char *client_secret;
    1648             :     char *authorization_code;
    1649             :     char *redirect_uri_encoded;
    1650             :     char *hps;
    1651             : 
    1652          11 :     hps = GNUNET_STRINGS_data_to_string_alloc (&ph->h_payto,
    1653             :                                                sizeof (ph->h_payto));
    1654             :     {
    1655             :       char *redirect_uri;
    1656             : 
    1657          11 :       GNUNET_asprintf (&redirect_uri,
    1658             :                        "%skyc-proof/%s",
    1659             :                        ps->exchange_base_url,
    1660          11 :                        &pd->section[strlen ("kyc-provider-")]);
    1661          11 :       redirect_uri_encoded = TALER_urlencode (redirect_uri);
    1662          11 :       GNUNET_free (redirect_uri);
    1663             :     }
    1664          11 :     GNUNET_assert (NULL != redirect_uri_encoded);
    1665          11 :     client_id = curl_easy_escape (ph->eh,
    1666          11 :                                   pd->client_id,
    1667             :                                   0);
    1668          11 :     GNUNET_assert (NULL != client_id);
    1669          11 :     client_secret = curl_easy_escape (ph->eh,
    1670          11 :                                       pd->client_secret,
    1671             :                                       0);
    1672          11 :     GNUNET_assert (NULL != client_secret);
    1673          11 :     authorization_code = curl_easy_escape (ph->eh,
    1674             :                                            code,
    1675             :                                            0);
    1676          11 :     GNUNET_assert (NULL != authorization_code);
    1677          11 :     GNUNET_asprintf (&ph->post_body,
    1678             :                      "client_id=%s&redirect_uri=%s&state=%s&client_secret=%s&code=%s&grant_type=authorization_code",
    1679             :                      client_id,
    1680             :                      redirect_uri_encoded,
    1681             :                      hps,
    1682             :                      client_secret,
    1683             :                      authorization_code);
    1684          11 :     curl_free (authorization_code);
    1685          11 :     curl_free (client_secret);
    1686          11 :     GNUNET_free (redirect_uri_encoded);
    1687          11 :     GNUNET_free (hps);
    1688          11 :     curl_free (client_id);
    1689             :   }
    1690          11 :   GNUNET_assert (CURLE_OK ==
    1691             :                  curl_easy_setopt (ph->eh,
    1692             :                                    CURLOPT_POSTFIELDS,
    1693             :                                    ph->post_body));
    1694          11 :   GNUNET_assert (CURLE_OK ==
    1695             :                  curl_easy_setopt (ph->eh,
    1696             :                                    CURLOPT_FOLLOWLOCATION,
    1697             :                                    1L));
    1698             :   /* limit MAXREDIRS to 5 as a simple security measure against
    1699             :      a potential infinite loop caused by a malicious target */
    1700          11 :   GNUNET_assert (CURLE_OK ==
    1701             :                  curl_easy_setopt (ph->eh,
    1702             :                                    CURLOPT_MAXREDIRS,
    1703             :                                    5L));
    1704             : 
    1705          11 :   ph->job = GNUNET_CURL_job_add (ps->curl_ctx,
    1706             :                                  ph->eh,
    1707             :                                  &handle_curl_login_finished,
    1708             :                                  ph);
    1709          11 :   return ph;
    1710             : }
    1711             : 
    1712             : 
    1713             : /**
    1714             :  * Function to asynchronously return the 404 not found
    1715             :  * page for the webhook.
    1716             :  *
    1717             :  * @param cls the `struct TALER_KYCLOGIC_WebhookHandle *`
    1718             :  */
    1719             : static void
    1720           0 : wh_return_not_found (void *cls)
    1721             : {
    1722           0 :   struct TALER_KYCLOGIC_WebhookHandle *wh = cls;
    1723             :   struct MHD_Response *response;
    1724             : 
    1725           0 :   wh->task = NULL;
    1726           0 :   response = MHD_create_response_from_buffer_static (0,
    1727             :                                                      "");
    1728           0 :   wh->cb (wh->cb_cls,
    1729             :           0LLU,
    1730             :           NULL,
    1731             :           false,
    1732             :           NULL,
    1733             :           NULL,
    1734             :           NULL,
    1735             :           TALER_KYCLOGIC_STATUS_KEEP,
    1736           0 :           GNUNET_TIME_UNIT_ZERO_ABS,
    1737             :           NULL,
    1738             :           MHD_HTTP_NOT_FOUND,
    1739             :           response);
    1740           0 :   GNUNET_free (wh);
    1741           0 : }
    1742             : 
    1743             : 
    1744             : /**
    1745             :  * Check KYC status and return result for Webhook.
    1746             :  *
    1747             :  * @param cls the @e cls of this struct with the plugin-specific state
    1748             :  * @param pd provider configuration details
    1749             :  * @param plc callback to lookup accounts with
    1750             :  * @param plc_cls closure for @a plc
    1751             :  * @param http_method HTTP method used for the webhook
    1752             :  * @param url_path rest of the URL after `/kyc-webhook/$LOGIC/`, as NULL-terminated array
    1753             :  * @param connection MHD connection object (for HTTP headers)
    1754             :  * @param body HTTP request body, or NULL if not available
    1755             :  * @param cb function to call with the result
    1756             :  * @param cb_cls closure for @a cb
    1757             :  * @return handle to cancel operation early
    1758             :  */
    1759             : static struct TALER_KYCLOGIC_WebhookHandle *
    1760           0 : oauth2_webhook (void *cls,
    1761             :                 const struct TALER_KYCLOGIC_ProviderDetails *pd,
    1762             :                 TALER_KYCLOGIC_ProviderLookupCallback plc,
    1763             :                 void *plc_cls,
    1764             :                 const char *http_method,
    1765             :                 const char *const url_path[],
    1766             :                 struct MHD_Connection *connection,
    1767             :                 const json_t *body,
    1768             :                 TALER_KYCLOGIC_WebhookCallback cb,
    1769             :                 void *cb_cls)
    1770             : {
    1771           0 :   struct PluginState *ps = cls;
    1772             :   struct TALER_KYCLOGIC_WebhookHandle *wh;
    1773             : 
    1774             :   (void) pd;
    1775             :   (void) plc;
    1776             :   (void) plc_cls;
    1777             :   (void) http_method;
    1778             :   (void) url_path;
    1779             :   (void) connection;
    1780             :   (void) body;
    1781           0 :   GNUNET_break_op (0);
    1782           0 :   wh = GNUNET_new (struct TALER_KYCLOGIC_WebhookHandle);
    1783           0 :   wh->cb = cb;
    1784           0 :   wh->cb_cls = cb_cls;
    1785           0 :   wh->ps = ps;
    1786           0 :   wh->task = GNUNET_SCHEDULER_add_now (&wh_return_not_found,
    1787             :                                        wh);
    1788           0 :   return wh;
    1789             : }
    1790             : 
    1791             : 
    1792             : /**
    1793             :  * Cancel KYC webhook execution.
    1794             :  *
    1795             :  * @param[in] wh handle of operation to cancel
    1796             :  */
    1797             : static void
    1798           0 : oauth2_webhook_cancel (struct TALER_KYCLOGIC_WebhookHandle *wh)
    1799             : {
    1800           0 :   GNUNET_SCHEDULER_cancel (wh->task);
    1801           0 :   GNUNET_free (wh);
    1802           0 : }
    1803             : 
    1804             : 
    1805             : /**
    1806             :  * Initialize OAuth2.0 KYC logic plugin
    1807             :  *
    1808             :  * @param cls a configuration instance
    1809             :  * @return NULL on error, otherwise a `struct TALER_KYCLOGIC_Plugin`
    1810             :  */
    1811             : void *
    1812             : libtaler_plugin_kyclogic_oauth2_init (void *cls);
    1813             : 
    1814             : /* declaration to avoid compiler warning */
    1815             : void *
    1816          76 : libtaler_plugin_kyclogic_oauth2_init (void *cls)
    1817             : {
    1818          76 :   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
    1819             :   struct TALER_KYCLOGIC_Plugin *plugin;
    1820             :   struct PluginState *ps;
    1821             : 
    1822          76 :   ps = GNUNET_new (struct PluginState);
    1823          76 :   ps->cfg = cfg;
    1824          76 :   if (GNUNET_OK !=
    1825          76 :       GNUNET_CONFIGURATION_get_value_string (cfg,
    1826             :                                              "exchange",
    1827             :                                              "BASE_URL",
    1828             :                                              &ps->exchange_base_url))
    1829             :   {
    1830           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1831             :                                "exchange",
    1832             :                                "BASE_URL");
    1833           0 :     GNUNET_free (ps);
    1834           0 :     return NULL;
    1835             :   }
    1836             :   ps->curl_ctx
    1837         152 :     = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
    1838          76 :                         &ps->curl_rc);
    1839          76 :   if (NULL == ps->curl_ctx)
    1840             :   {
    1841           0 :     GNUNET_break (0);
    1842           0 :     GNUNET_free (ps->exchange_base_url);
    1843           0 :     GNUNET_free (ps);
    1844           0 :     return NULL;
    1845             :   }
    1846          76 :   ps->curl_rc = GNUNET_CURL_gnunet_rc_create (ps->curl_ctx);
    1847             : 
    1848          76 :   plugin = GNUNET_new (struct TALER_KYCLOGIC_Plugin);
    1849          76 :   plugin->cls = ps;
    1850             :   plugin->load_configuration
    1851          76 :     = &oauth2_load_configuration;
    1852             :   plugin->unload_configuration
    1853          76 :     = &oauth2_unload_configuration;
    1854             :   plugin->initiate
    1855          76 :     = &oauth2_initiate;
    1856             :   plugin->initiate_cancel
    1857          76 :     = &oauth2_initiate_cancel;
    1858             :   plugin->proof
    1859          76 :     = &oauth2_proof;
    1860             :   plugin->proof_cancel
    1861          76 :     = &oauth2_proof_cancel;
    1862             :   plugin->webhook
    1863          76 :     = &oauth2_webhook;
    1864             :   plugin->webhook_cancel
    1865          76 :     = &oauth2_webhook_cancel;
    1866          76 :   return plugin;
    1867             : }
    1868             : 
    1869             : 
    1870             : /**
    1871             :  * Unload authorization plugin
    1872             :  *
    1873             :  * @param cls a `struct TALER_KYCLOGIC_Plugin`
    1874             :  * @return NULL (always)
    1875             :  */
    1876             : void *
    1877             : libtaler_plugin_kyclogic_oauth2_done (void *cls);
    1878             : 
    1879             : /* declaration to avoid compiler warning */
    1880             : void *
    1881          76 : libtaler_plugin_kyclogic_oauth2_done (void *cls)
    1882             : {
    1883          76 :   struct TALER_KYCLOGIC_Plugin *plugin = cls;
    1884          76 :   struct PluginState *ps = plugin->cls;
    1885             : 
    1886          76 :   if (NULL != ps->curl_ctx)
    1887             :   {
    1888          76 :     GNUNET_CURL_fini (ps->curl_ctx);
    1889          76 :     ps->curl_ctx = NULL;
    1890             :   }
    1891          76 :   if (NULL != ps->curl_rc)
    1892             :   {
    1893          76 :     GNUNET_CURL_gnunet_rc_destroy (ps->curl_rc);
    1894          76 :     ps->curl_rc = NULL;
    1895             :   }
    1896          76 :   GNUNET_free (ps->exchange_base_url);
    1897          76 :   GNUNET_free (ps);
    1898          76 :   GNUNET_free (plugin);
    1899          76 :   return NULL;
    1900             : }

Generated by: LCOV version 1.16