summaryrefslogtreecommitdiff
path: root/src/exchange
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2022-08-02 12:05:57 +0200
committerChristian Grothoff <christian@grothoff.org>2022-08-02 12:05:57 +0200
commit266068c96cbe64d84da2c79fc6db56e8c56ba6b5 (patch)
tree8a25917523f0b160fb91f0951827f3a6adbacaef /src/exchange
parent0835669986f11dfdbcae5b069990286ae8784f21 (diff)
downloadexchange-266068c96cbe64d84da2c79fc6db56e8c56ba6b5.tar.gz
exchange-266068c96cbe64d84da2c79fc6db56e8c56ba6b5.tar.bz2
exchange-266068c96cbe64d84da2c79fc6db56e8c56ba6b5.zip
work on KYC configuration parsing logic
Diffstat (limited to 'src/exchange')
-rw-r--r--src/exchange/taler-exchange-httpd_kyc.c490
-rw-r--r--src/exchange/taler-exchange-httpd_kyc.h4
2 files changed, 472 insertions, 22 deletions
diff --git a/src/exchange/taler-exchange-httpd_kyc.c b/src/exchange/taler-exchange-httpd_kyc.c
index dd5a334bd..cb7f73c65 100644
--- a/src/exchange/taler-exchange-httpd_kyc.c
+++ b/src/exchange/taler-exchange-httpd_kyc.c
@@ -60,7 +60,7 @@ struct TEH_KycProvider
/**
* Array of @e num_checks checks performed by this provider.
*/
- struct TEH_KycCheck *provided_checks;
+ struct TEH_KycCheck **provided_checks;
/**
* Logic to run for this provider.
@@ -102,12 +102,12 @@ struct TEH_KycTrigger
* Maximum amount that can be transacted until
* the rule triggers.
*/
- struct TALER_Amount limit;
+ struct TALER_Amount threshold;
/**
* Array of @e num_checks checks to apply on this trigger.
*/
- struct TEH_KycCheck *required_checks;
+ struct TEH_KycCheck **required_checks;
/**
* Length of the @e checks array.
@@ -125,7 +125,7 @@ struct TEH_KycTrigger
/**
* Array of @e num_kyc_logics KYC logic plugins we have loaded.
*/
-static struct TEH_KYCLOGIC_Plugin *kyc_logics;
+static struct TEH_KYCLOGIC_Plugin **kyc_logics;
/**
* Length of the #kyc_logics array.
@@ -136,7 +136,7 @@ static unsigned in num_kyc_logics;
* Array of @e num_kyc_checks known types of
* KYC checks.
*/
-static struct TEH_KycCheck *kyc_checks;
+static struct TEH_KycCheck **kyc_checks;
/**
* Length of the #kyc_checks array.
@@ -146,7 +146,7 @@ static unsigned int num_kyc_checks;
/**
* Array of configured triggers.
*/
-static struct TEH_KycTrigger *kyc_triggers;
+static struct TEH_KycTrigger **kyc_triggers;
/**
* Length of the #kyc_triggers array.
@@ -156,7 +156,7 @@ static unsigned int num_kyc_triggers;
/**
* Array of configured providers.
*/
-static struct TEH_KycProviders *kyc_providers;
+static struct TEH_KycProvider *kyc_providers;
/**
* Length of the #kyc_providers array.
@@ -168,7 +168,28 @@ enum GNUNET_GenericReturnValue
TEH_kyc_trigger_from_string (const char *trigger_s,
enum TEH_KycTriggerEvent *trigger)
{
- GNUNET_break (0);
+ struct
+ {
+ const char *in;
+ enum TEH_KycTriggerEvent out;
+ } map [] = {
+ { "withdraw", TEH_KYC_TRIGGER_WITHDRAW },
+ { "deposit", TEH_KYC_TRIGGER_DEPOSIT },
+ { "merge", TEH_KYC_TRIGGER_P2P_RECEIVE },
+ { "balance", TEH_KYC_TRIGGER_WALLET_BALANCE },
+ { NULL, 0 }
+ };
+
+ for (unsigned int i = 0; NULL != map[i].in; i++)
+ if (0 == strcasecmp (map[i].in,
+ trigger_s))
+ {
+ *trigger = map[i].out;
+ return GNUNET_OK;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Invalid KYC trigger `%s'\n",
+ trigger_s);
return GNUNET_SYSERR;
}
@@ -176,6 +197,17 @@ TEH_kyc_trigger_from_string (const char *trigger_s,
const char *
TEH_kyc_trigger2s (enum TEH_KycTriggerEvent trigger)
{
+ switch (trigger)
+ {
+ case TEH_KYC_TRIGGER_WITHDRAW:
+ return "withdraw";
+ case TEH_KYC_TRIGGER_DEPOSIT:
+ return "deposit";
+ case TEH_KYC_TRIGGER_P2P_RECEIVE:
+ return "merge";
+ case TEH_KYC_TRIGGER_WALLET_BALANCE:
+ return "balance";
+ }
GNUNET_break (0);
return NULL;
}
@@ -185,7 +217,26 @@ enum GNUNET_GenericReturnValue
TEH_kyc_user_type_from_string (const char *ut_s,
enum TEH_KycUserType *ut)
{
- GNUNET_break (0);
+ struct
+ {
+ const char *in;
+ enum TEH_KycTriggerEvent out;
+ } map [] = {
+ { "individual", TEH_KYC_UT_INDIVIDUAL },
+ { "business", TEH_KYC_UT_BUSINESS },
+ { NULL, 0 }
+ };
+
+ for (unsigned int i = 0; NULL != map[i].in; i++)
+ if (0 == strcasecmp (map[i].in,
+ ut_s))
+ {
+ *ut = map[i].out;
+ return GNUNET_OK;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Invalid user type `%s'\n",
+ ut_s);
return GNUNET_SYSERR;
}
@@ -193,19 +244,361 @@ TEH_kyc_user_type_from_string (const char *ut_s,
const char *
TEH_kyc_user_type2s (enum TEH_KycUserType ut)
{
+ switch (ut)
+ {
+ case TEH_KYC_UT_INDIVIDUAL:
+ return "individual";
+ case TEH_KYC_UT_BUSINESS:
+ return "business";
+ }
+ GNUNET_break (0);
+ return NULL;
+}
+
+
+/**
+ * Load KYC logic plugin.
+ *
+ * @param name name of the plugin
+ * @return NULL on error
+ */
+static struct TEH_KYCLOGIC_Plugin *
+load_logic (const char *name)
+{
GNUNET_break (0);
return NULL;
}
+/**
+ * Add check type to global array of checks.
+ * First checks if the type already exists, otherwise
+ * adds a new one.
+ *
+ * @param check name of the check
+ * @return pointer into the global list
+ */
+static struct TEH_KycCheck *
+add_check (const char *check)
+{
+ struct TEH_KycCheck *kc;
+
+ for (unsigned int i = 0; i<num_kyc_checks; i++)
+ if (0 == strcasecmp (check,
+ kyc_checks[i]->name))
+ return kyc_checks[i];
+ kc = GNUNET_new (struct TEH_KycCheck);
+ kc->name = GNUNET_strdup (check);
+ GNUNET_array_append (kyc_checks,
+ num_kyc_checks,
+ kc);
+ return kc;
+}
+
+
+/**
+ * Parse list of checks from @a checks and build an
+ * array of aliases into the global checks array
+ * in @a provided_checks.
+ *
+ * @param[in,out] checks list of checks; clobbered
+ * @param[out] p_checks where to put array of aliases
+ * @param[out] num_p_checks set to length of @a p_checks array
+ */
+static void
+add_checks (char *checks,
+ struct TEH_KycCheck **p_checks,
+ unsigned int *num_p_checks)
+{
+ char *sptr;
+ struct TEH_KycCheck *rchecks = NULL;
+ unsigned int num_rchecks = 0;
+
+ for (char *tok = strtok_r (checks, " ", &sptr);
+ NULL != tok;
+ tok = strtok_r (checks, NULL, &sptr))
+ {
+ struct TEH_KycCheck *kc;
+
+ kc = add_check (tok);
+ GNUNET_array_append (rchecks,
+ num_rchecks,
+ kc);
+ }
+ *p_checks = rchecks;
+ *num_p_checks = num_rchecks;
+}
+
+
+/**
+ * Parse configuration of a KYC provider.
+ *
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+add_provider (const char *section)
+{
+ unsigned long long cost;
+ char *logic;
+ char *ut_s;
+ enum TEH_KycUserType ut;
+ char *checks;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (TEH_cfg,
+ section,
+ "COST",
+ &cost))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ section,
+ "COST",
+ "number required");
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (TEH_cfg,
+ section,
+ "USER_TYPE",
+ &ut_s))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ section,
+ "USER_TYPE");
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ TEH_kyc_user_type_from_string (ut_s,
+ &ut))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ section,
+ "USER_TYPE",
+ "valid user type required");
+ GNUNET_free (ut_s);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_free (ut_s);
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (TEH_cfg,
+ section,
+ "LOGIC",
+ &logic))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ section,
+ "LOGIC");
+ return GNUNET_SYSERR;
+ }
+ lp = load_logic (logic);
+ if (NULL == lp)
+ {
+ GNUNET_free (logic);
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ section,
+ "LOGIC",
+ "logic plugin could not be loaded");
+ return GNUNET_SYSERR;
+ }
+ GNUNET_free (logic);
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (TEH_cfg,
+ section,
+ "PROVIDED_CHECKS",
+ &checks))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ section,
+ "PROVIDED_CHECKS");
+ return GNUNET_SYSERR;
+ }
+ {
+ struct TEH_KycProvider *kp;
+
+ kp = GNUNET_new (struct TEH_KycProvider);
+ kp->provider_section_name = section;
+ kp->user_type = ut;
+ kp->logic = lp;
+ add_checks (checks,
+ &kp->provided_checks,
+ &kp->num_checks);
+ GNUNET_free (checks);
+ kp->pd = lp->load (lp->cls,
+ section);
+ if (NULL == kp->pd)
+ {
+ GNUNET_free (kp);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_array_append (kyc_providers,
+ num_kyc_providers,
+ kp);
+ for (unsigned int i = 0; i<kp->num_checks; i++)
+ {
+ struct TEH_KycCheck *kc = kp->provided_checks[i];
+
+ GNUNET_array_append (kc->providers,
+ kc->num_providers,
+ kp);
+ }
+ }
+ return GNUNET_OK;
+}
+
+
+static enum GNUNET_GenericReturnValue
+add_trigger (const char *section)
+{
+ char *ot_s;
+ struct TALER_Amount threshold;
+ struct GNUNET_TIME_Relative timeframe;
+ char *checks;
+ enum TEH_KycTriggerEvent ot;
+
+ if (GNUNET_OK !=
+ TALER_CONFIGURATION_get_value_amount (TEH_cfg,
+ section,
+ "THRESHOLD",
+ &threshold))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ section,
+ "THRESHOLD",
+ "amount required");
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (TEH_cfg,
+ section,
+ "OPERATION_TYPE",
+ &ot_s))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ section,
+ "OPERATION_TYPE");
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ TEH_kyc_trigger_from_string (ot_s,
+ &ot))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ section,
+ "OPERATION_TYPE",
+ "valid trigger type required");
+ GNUNET_free (ot_s);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_free (ot_s);
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
+ section,
+ "TIMEFRAME",
+ &timeframe))
+ {
+ if (TEH_KYC_TRIGGER_WALLET_BALANCE == ot)
+ {
+ timeframe = GNUNET_TIME_UNIT_ZERO;
+ }
+ else
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ section,
+ "TIMEFRAME",
+ "duration required");
+ return GNUNET_SYSERR;
+ }
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (TEH_cfg,
+ section,
+ "REQUIRED_CHECKS",
+ &checks))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ section,
+ "REQUIRED_CHECKS");
+ return GNUNET_SYSERR;
+ }
+
+ {
+ struct TEH_KycTrigger *kt;
+
+ kt = GNUNET_new (struct TEH_KycTrigger);
+ kt->timeframe = timeframe;
+ kt->threshold = threshold;
+ kt->trigger = ot;
+ add_checks (checks,
+ &kt->required_checks,
+ &kt->num_checks);
+ GNUNET_free (checks);
+ GNUNET_array_append (kyc_checks,
+ num_kyc_checks,
+ kt);
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function to iterate over configuration sections.
+ *
+ * @param cls closure, `boolean *`, set to false on failure
+ * @param section name of the section
+ */
+static void
+handle_section (void *cls,
+ const char *section)
+{
+ bool *ok = cls;
+
+ if (0 == strncasecmp (section,
+ "kyc-provider-",
+ strlen ("kyc-provider-")))
+ {
+ if (GNUNET_OK !=
+ add_provider (section))
+ *ok = false;
+ return;
+ }
+ if (0 == strncasecmp (section,
+ "kyc-legitimization-",
+ strlen ("kyc-legitimization-")))
+ {
+ if (GNUNET_OK !=
+ add_trigger (section))
+ *ok = false;
+ return;
+ }
+}
+
+
enum GNUNET_GenericReturnValue
TEH_kyc_init (void)
{
- GNUNET_break (0);
- // iterate over configuration sections,
- // initialize arrays above
- // sanity check: ensure at least one provider exists
- // for any trigger and indidivual or business.
+ book ok = true;
+
+ GNUNET_CONFIGURATION_iterate_sections (TEH_cfg,
+ &handle_section,
+ &ok);
+ if (! ok)
+ {
+ TEH_kyc_done ();
+ return GNUNET_SYSERR;
+ }
+
+ /* sanity check: ensure at least one provider exists
+ for any trigger and indidivual or business. */
+ for (unsigned int i = 0; i<num_kyc_checks; i++)
+ if (0 == kyc_checks[i]->num_providers)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "No provider available for required KYC check `%s'\n",
+ kyc_checks[i]->name);
+ TEH_kyc_done ();
+ return GNUNET_SYSERR;
+ }
return GNUNET_OK;
}
@@ -214,8 +607,50 @@ TEH_kyc_init (void)
void
TEH_kyc_done (void)
{
- // unload plugins
- // free arrays
+ for (unsigned int i = 0; i<num_kyc_triggers; i++)
+ {
+ struct TEH_KycTrigger *kt = kyc_triggers[i];
+
+ GNUNET_array_grow (kt->required_checks,
+ kt->num_checks,
+ 0);
+ GNUNET_free (kt);
+ }
+ GNUNET_array_grow (kyc_triggers,
+ num_kyc_triggers,
+ 0);
+ for (unsigned int i = 0; i<num_kyc_providers; i++)
+ {
+ struct TEH_KycProvider *kp = kyc_providers[i];
+
+ kp->logic->unload (kp->pd);
+ GNUNET_array_grow (kp->provided_checks,
+ kp->num_checks,
+ 0);
+ GNUNET_free (kp);
+ }
+ GNUNET_array_grow (kyc_providers,
+ num_kyc_providers,
+ 0);
+ for (unsigned int i = 0; i<num_kyc_logics; i++)
+ {
+ struct TEH_KYCLOGIC_Plugin *lp = kyc_logics[i];
+
+ unload_plugin (lp);
+ }
+ GNUNET_array_grow (kyc_logics,
+ num_kyc_logics,
+ 0);
+ for (unsigned int i = 0; i<num_kyc_checks; i++)
+ {
+ struct TEH_KycCheck *kc = kyc_checks[i];
+
+ GNUNET_free (kc->name);
+ GNUNET_free (kc);
+ }
+ GNUNET_array_grow (kyc_checks,
+ num_kyc_checks,
+ 0);
}
@@ -227,7 +662,7 @@ TEH_kyc_test_required (enum TEH_KycTriggerEvent event,
{
// Check if event(s) may at all require KYC.
// If so, check what provider checks are
- // already satisified for h_payto (with database)
+ // already satisfied for h_payto (with database)
// If unsatisfied checks are left, use 'ai'
// to check if amount is high enough to trigger them.
// If it is, find cheapest provider that satisfies
@@ -243,8 +678,23 @@ TEH_kyc_get_logic (const char *provider_section_name,
struct TEH_KYCLOGIC_Plugin **plugin,
struct TEH_KYCLOGIC_ProviderDetails **pd)
{
- // lookup provider by section name in array,
- // return internal plugin/pd fields.
- GNUNET_break (0);
+ for (unsigned int i = 0; i<num_kyc_providers; i++)
+ {
+ struct TEH_KycProvider *kp = kyc_providers[i];
+
+ if (0 !=
+ strcasecmp (provider_section_name,
+ kp->provider_section_name))
+ continue;
+ *plugin = kp->logic;
+ *pd = kp->pd;
+ return GNUNET_OK;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Provider `%s' unknown\n",
+ provider_section_name);
return GNUNET_SYSERR;
}
+
+
+/* end of taler-exchange-httpd_kyc.c */
diff --git a/src/exchange/taler-exchange-httpd_kyc.h b/src/exchange/taler-exchange-httpd_kyc.h
index 51883caca..0061f6584 100644
--- a/src/exchange/taler-exchange-httpd_kyc.h
+++ b/src/exchange/taler-exchange-httpd_kyc.h
@@ -33,12 +33,12 @@ enum TEH_KycUserType
/**
* KYC rule is for an individual.
*/
- TEH_KYC_INDIVIDUAL = 0,
+ TEH_KYC_UT_INDIVIDUAL = 0,
/**
* KYC rule is for a business.
*/
- TEH_KYC_BUSINESS = 1
+ TEH_KYC_UT_BUSINESS = 1
};