-major KYC update, fixes misc. issues

This commit is contained in:
Christian Grothoff 2022-08-20 21:29:29 +02:00
parent 516d8e30ed
commit a046899b2c
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
56 changed files with 3685 additions and 2881 deletions

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
1660654426
1660992723

View File

@ -3,7 +3,7 @@ KEYFILE = ${TALER_DATA_HOME}/merchant/default.priv
NAME = Merchant Inc.
[exchange-account-1]
PAYTO_URI = payto://iban/SANDBOXX/DE471160?receiver-name=Exchange+Company
PAYTO_URI = payto://iban/SANDBOXX/DE989651?receiver-name=Exchange+Company
enable_debit = yes
enable_credit = yes
@ -19,7 +19,7 @@ HONOR_default = YES
ACTIVE_default = YES
[merchant-exchange-default]
MASTER_KEY = 3NVBGMW8SVMKA4BSBCX9HZ23V7KBXR0ZZ02JWVXBCRH6RNYSM57G
MASTER_KEY = RKNMPRGXCX35H11WEYXDXYHPR7NX2QK9BG15MT0QEF75PC5KR470
EXCHANGE_BASE_URL = http://localhost:8081/
CURRENCY = TESTKUDOS
@ -155,7 +155,7 @@ UNIXPATH = ${TALER_RUNTIME_DIR}/merchant.http
CONFIG = postgres:///auditor-basedb
[exchange]
MASTER_PUBLIC_KEY = 3NVBGMW8SVMKA4BSBCX9HZ23V7KBXR0ZZ02JWVXBCRH6RNYSM57G
MASTER_PUBLIC_KEY = RKNMPRGXCX35H11WEYXDXYHPR7NX2QK9BG15MT0QEF75PC5KR470
SIGNKEY_DURATION = 4 weeks
LOOKAHEAD_SIGN = 32 weeks 1 day
SIGNKEY_LEGAL_DURATION = 4 weeks
@ -177,7 +177,7 @@ CONFIG = postgres:///auditor-basedb
[auditor]
BASE_URL = http://localhost:8083/
TINY_AMOUNT = TESTKUDOS:0.01
PUBLIC_KEY = 8X7G2HSYZXK7HW18Y24GF2TTV5QTN1DPET4TG8KR65P54990EAMG
PUBLIC_KEY = 0EHPW5WEKHXPPN4MPJNGA7Z6D29JP21GKVNV8ARFB1YW7WWJX20G
[PATHS]
TALER_CACHE_HOME = $TALER_HOME/.cache/taler/

View File

@ -1 +1 @@
łmH;§'űŢŁš¶fÍ/CęźwŚwX3Â.í%¨
m<EFBFBD>c<01><50><D4A0>k<>J<EFBFBD>F<15>x<><17><1A>@~<7E>

View File

@ -1 +1 @@
3NVBGMW8SVMKA4BSBCX9HZ23V7KBXR0ZZ02JWVXBCRH6RNYSM57G
RKNMPRGXCX35H11WEYXDXYHPR7NX2QK9BG15MT0QEF75PC5KR470

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
1660654556
1660992814

View File

@ -1 +1 @@
31R45JTGD05G4DMD0HQSDVJ4NBMQSVFBCMBFVV52YK9J4C4MC9ZG
7WGDAMGZX7JDVWSQ4XY23WJZ0SQJ8A16YYFZZD1K8EKH3G08M2MG

File diff suppressed because it is too large Load Diff

View File

@ -91,6 +91,12 @@ struct AggregationUnit
*/
const struct TALER_EXCHANGEDB_AccountInfo *wa;
/**
* Row in KYC table for legitimization requirements
* that are pending for this aggregation, or 0 if none.
*/
uint64_t requirement_row;
/**
* Set to #GNUNET_OK during transient checking
* while everything is OK. Otherwise see return
@ -469,14 +475,13 @@ return_relevant_amounts (void *cls,
/**
* Test if KYC is required for a transfer to @a h_payto.
*
* @param au_active aggregation unit to check for
* @param[in,out] au_active aggregation unit to check for
* @return true if KYC checks are satisfied
*/
static bool
kyc_satisfied (const struct AggregationUnit *au_active)
kyc_satisfied (struct AggregationUnit *au_active)
{
const char *requirement;
uint64_t legi_row;
enum GNUNET_DB_QueryStatus qs;
requirement = TALER_KYCLOGIC_kyc_test_required (
@ -496,7 +501,7 @@ kyc_satisfied (const struct AggregationUnit *au_active)
db_plugin->cls,
requirement,
&au_active->h_payto,
&legi_row);
&au_active->requirement_row);
if (qs < 0)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@ -506,8 +511,8 @@ kyc_satisfied (const struct AggregationUnit *au_active)
else
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"New legitimization process %llu started\n",
(unsigned long long) legi_row);
"Legitimization process %llu started\n",
(unsigned long long) au_active->requirement_row);
}
return false;
}
@ -649,6 +654,7 @@ do_aggregate (struct AggregationUnit *au)
qs = db_plugin->update_aggregation_transient (db_plugin->cls,
&au->h_payto,
&au->wtid,
au->requirement_row,
&au->total_amount);
else
qs = db_plugin->create_aggregation_transient (db_plugin->cls,
@ -656,6 +662,7 @@ do_aggregate (struct AggregationUnit *au)
au->wa->section_name,
&au->merchant_pub,
&au->wtid,
au->requirement_row,
&au->total_amount);
if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
{

View File

@ -209,7 +209,7 @@ batch_withdraw_transaction (void *cls,
TEH_plugin->cls,
kyc_required,
&wc->h_payto,
&wc->kyc.legitimization_uuid);
&wc->kyc.requirement_row);
}
wc->kyc.ok = true;
qs = TEH_plugin->do_batch_withdraw (TEH_plugin->cls,
@ -328,6 +328,7 @@ generate_reply_success (const struct TEH_RequestContext *rc,
{
/* KYC required */
return TEH_RESPONSE_reply_kyc_required (rc->connection,
&wc->h_payto,
&wc->kyc);
}

View File

@ -252,11 +252,11 @@ handle_track_transaction_request (
connection,
MHD_HTTP_ACCEPTED,
GNUNET_JSON_pack_allow_null (
(0 == ctx->kyc.legitimization_uuid)
? GNUNET_JSON_pack_string ("legitimization_uuid",
(0 == ctx->kyc.requirement_row)
? GNUNET_JSON_pack_string ("requirement_row",
NULL)
: GNUNET_JSON_pack_uint64 ("legitimization_uuid",
ctx->kyc.legitimization_uuid)),
: GNUNET_JSON_pack_uint64 ("requirement_row",
ctx->kyc.requirement_row)),
GNUNET_JSON_pack_bool ("kyc_ok",
ctx->kyc.ok),
GNUNET_JSON_pack_timestamp ("execution_time",

View File

@ -72,9 +72,14 @@ struct KycPoller
struct GNUNET_DB_EventHandler *eh;
/**
* UUID being checked.
* Row of the requirement being checked.
*/
uint64_t legitimization_uuid;
uint64_t requirement_row;
/**
* Row of KYC process being initiated.
*/
uint64_t process_row;
/**
* Hash of the payto:// URI we are confirming to
@ -87,11 +92,6 @@ struct KycPoller
*/
struct GNUNET_TIME_Absolute timeout;
/**
* Type of KYC check required for this client.
*/
char *required;
/**
* Set to starting URL of KYC process if KYC is required.
*/
@ -102,6 +102,11 @@ struct KycPoller
*/
char *hint;
/**
* Name of the section of the provider in the configuration.
*/
const char *section_name;
/**
* Set to error encountered with KYC logic, if any.
*/
@ -118,9 +123,9 @@ struct KycPoller
bool suspended;
/**
* True if KYC was required but is fully satisfied.
* False if KYC is not required.
*/
bool found;
bool kyc_required;
/**
* True if we once tried the KYC initiation.
@ -192,7 +197,6 @@ kyp_cleanup (struct TEH_RequestContext *rc)
}
GNUNET_free (kyp->kyc_url);
GNUNET_free (kyp->hint);
GNUNET_free (kyp->required);
GNUNET_free (kyp);
}
@ -237,10 +241,10 @@ initiate_cb (
{
kyp->hint = GNUNET_strdup (error_msg_hint);
}
qs = TEH_plugin->update_kyc_requirement_by_row (
qs = TEH_plugin->update_kyc_process_by_row (
TEH_plugin->cls,
kyp->legitimization_uuid,
kyp->required,
kyp->process_row,
kyp->section_name,
&kyp->h_payto,
provider_user_id,
provider_legitimization_id,
@ -286,23 +290,18 @@ kyc_check (void *cls,
struct TALER_KYCLOGIC_ProviderDetails *pd;
enum GNUNET_GenericReturnValue ret;
struct TALER_PaytoHashP h_payto;
struct GNUNET_TIME_Absolute expiration;
char *provider_account_id;
char *provider_legitimization_id;
char *requirements;
qs = TEH_plugin->lookup_kyc_requirement_by_row (
TEH_plugin->cls,
kyp->legitimization_uuid,
&kyp->required,
&h_payto,
&expiration,
&provider_account_id,
&provider_legitimization_id);
kyp->requirement_row,
&requirements,
&h_payto);
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"No KYC requirements open for %llu\n",
(unsigned long long) kyp->legitimization_uuid);
(unsigned long long) kyp->requirement_row);
return qs;
}
if (qs < 0)
@ -310,52 +309,65 @@ kyc_check (void *cls,
GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs);
return qs;
}
GNUNET_free (provider_account_id);
GNUNET_free (provider_legitimization_id);
if (0 !=
GNUNET_memcmp (&kyp->h_payto,
&h_payto))
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Account %llu provided, but h_payto does not match\n",
(unsigned long long) kyp->legitimization_uuid);
"Requirement %llu provided, but h_payto does not match\n",
(unsigned long long) kyp->requirement_row);
GNUNET_break_op (0);
*mhd_ret = TALER_MHD_reply_with_error (connection,
MHD_HTTP_FORBIDDEN,
TALER_EC_EXCHANGE_KYC_CHECK_AUTHORIZATION_FAILED,
"h_payto");
GNUNET_free (requirements);
return GNUNET_DB_STATUS_HARD_ERROR;
}
kyp->found = true;
if (GNUNET_TIME_absolute_is_future (expiration))
{
/* kyc not required, we are done */
return qs;
}
if (TALER_KYCLOGIC_check_satisfied (
requirements,
&h_payto,
TEH_plugin->select_satisfied_kyc_processes,
TEH_plugin->cls))
return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
ret = TALER_KYCLOGIC_kyc_get_logic (kyp->required,
&kyp->ih_logic,
&pd);
kyp->kyc_required = true;
ret = TALER_KYCLOGIC_requirements_to_logic (requirements,
kyp->ut,
&kyp->ih_logic,
&pd,
&kyp->section_name);
if (GNUNET_OK != ret)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"KYC logic for `%s' not configured but used in database!\n",
kyp->required);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"KYC requirements `%s' cannot be checked, but are set as required in database!\n",
requirements);
*mhd_ret = TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_EXCHANGE_KYC_GENERIC_LOGIC_GONE,
kyp->required);
requirements);
GNUNET_free (requirements);
return GNUNET_DB_STATUS_HARD_ERROR;
}
GNUNET_free (requirements);
if (kyp->ih_done)
return qs;
qs = TEH_plugin->insert_kyc_requirement_process (
TEH_plugin->cls,
&h_payto,
kyp->section_name,
NULL,
NULL,
&kyp->process_row);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Initiating KYC check with logic %s\n",
kyp->required);
kyp->ih_logic->name);
kyp->ih = kyp->ih_logic->initiate (kyp->ih_logic->cls,
pd,
&h_payto,
kyp->legitimization_uuid,
kyp->process_row,
&initiate_cb,
kyp);
GNUNET_break (NULL != kyp->ih);
@ -421,22 +433,22 @@ TEH_handler_kyc_check (
rc->rh_cleaner = &kyp_cleanup;
{
unsigned long long legitimization_uuid;
unsigned long long requirement_row;
char dummy;
if (1 !=
sscanf (args[0],
"%llu%c",
&legitimization_uuid,
&requirement_row,
&dummy))
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MALFORMED,
"legitimization_uuid");
"requirement_row");
}
kyp->legitimization_uuid = (uint64_t) legitimization_uuid;
kyp->requirement_row = (uint64_t) requirement_row;
}
if (GNUNET_OK !=
@ -527,12 +539,12 @@ TEH_handler_kyc_check (
}
if ( (NULL == kyp->ih) &&
(! kyp->found) )
(! kyp->kyc_required) )
{
/* KYC not required */
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"KYC not required %llu\n",
(unsigned long long) kyp->legitimization_uuid);
(unsigned long long) kyp->requirement_row);
return TALER_MHD_reply_static (
rc->connection,
MHD_HTTP_NO_CONTENT,
@ -554,7 +566,7 @@ TEH_handler_kyc_check (
}
/* long polling? */
if ( (NULL != kyp->required) &&
if ( (NULL != kyp->section_name) &&
GNUNET_TIME_absolute_is_future (kyp->timeout))
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,

View File

@ -90,14 +90,14 @@ struct KycProofContext
struct MHD_Response *response;
/**
* Configuration section for the logic we are running.
* Provider configuration section name of the logic we are running.
*/
char *provider_section;
const char *provider_section;
/**
* Row in the database for this legitimization operation.
*/
uint64_t legi_row;
uint64_t process_row;
/**
* HTTP response code to return.
@ -194,13 +194,13 @@ proof_cb (
{
enum GNUNET_DB_QueryStatus qs;
qs = TEH_plugin->update_kyc_requirement_by_row (TEH_plugin->cls,
kpc->legi_row,
kpc->provider_section,
&kpc->h_payto,
provider_user_id,
provider_legitimization_id,
expiration);
qs = TEH_plugin->update_kyc_process_by_row (TEH_plugin->cls,
kpc->process_row,
kpc->provider_section,
&kpc->h_payto,
provider_user_id,
provider_legitimization_id,
expiration);
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
{
GNUNET_break (0);
@ -216,8 +216,8 @@ proof_cb (
else
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"KYC logic #%llu failed with status %d\n",
(unsigned long long) kpc->legi_row,
"KYC process #%llu failed with status %d\n",
(unsigned long long) kpc->process_row,
status);
}
kpc->response_code = http_status;
@ -249,7 +249,6 @@ clean_kpc (struct TEH_RequestContext *rc)
}
GNUNET_free (kpc->provider_user_id);
GNUNET_free (kpc->provider_legitimization_id);
GNUNET_free (kpc->provider_section);
GNUNET_free (kpc);
}
@ -257,7 +256,7 @@ clean_kpc (struct TEH_RequestContext *rc)
MHD_RESULT
TEH_handler_kyc_proof (
struct TEH_RequestContext *rc,
const char *const args[])
const char *const args[3])
{
struct KycProofContext *kpc = rc->rh_ctx;
@ -290,28 +289,38 @@ TEH_handler_kyc_proof (
TALER_EC_GENERIC_PARAMETER_MALFORMED,
"h_payto");
}
kpc->provider_section = GNUNET_strdup (args[1]);
if (GNUNET_OK !=
TALER_KYCLOGIC_kyc_get_logic (kpc->provider_section,
&kpc->logic,
&kpc->pd))
TALER_KYCLOGIC_lookup_logic (args[1],
&kpc->logic,
&kpc->pd,
&kpc->provider_section))
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_NOT_FOUND,
TALER_EC_EXCHANGE_KYC_GENERIC_LOGIC_UNKNOWN,
kpc->provider_section);
args[1]);
}
if (0 != strcmp (args[1],
kpc->provider_section))
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MALFORMED,
"PROVIDER_SECTION");
}
if (NULL != kpc->provider_section)
{
enum GNUNET_DB_QueryStatus qs;
struct GNUNET_TIME_Absolute expiration;
qs = TEH_plugin->lookup_kyc_requirement_by_account (
qs = TEH_plugin->lookup_kyc_process_by_account (
TEH_plugin->cls,
kpc->provider_section,
&kpc->h_payto,
&kpc->legi_row,
&kpc->process_row,
&expiration,
&kpc->provider_user_id,
&kpc->provider_legitimization_id);
@ -346,7 +355,7 @@ TEH_handler_kyc_proof (
&args[2],
rc->connection,
&kpc->h_payto,
kpc->legi_row,
kpc->process_row,
kpc->provider_user_id,
kpc->provider_legitimization_id,
&proof_cb,

View File

@ -43,7 +43,7 @@ TEH_kyc_proof_cleanup (void);
MHD_RESULT
TEH_handler_kyc_proof (
struct TEH_RequestContext *rc,
const char *const args[]);
const char *const args[3]);
#endif

View File

@ -42,9 +42,9 @@ struct KycRequestContext
struct TALER_PaytoHashP h_payto;
/**
* Row with the legitimization requirement.
* KYC status, with row with the legitimization requirement.
*/
uint64_t legi_row;
struct TALER_EXCHANGEDB_KycStatus kyc;
/**
* Balance threshold crossed by the wallet.
@ -116,16 +116,20 @@ wallet_kyc_check (void *cls,
TEH_plugin->cls,
&balance_iterator,
krc);
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"KYC check required at %s is `%s'\n",
TALER_amount2s (&krc->balance),
krc->required);
if (NULL == krc->required)
{
krc->kyc.ok = true;
return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
}
krc->kyc.ok = false;
qs = TEH_plugin->insert_kyc_requirement_for_account (TEH_plugin->cls,
krc->required,
&krc->h_payto,
&krc->legi_row);
&krc->kyc.requirement_row);
if (qs < 0)
{
if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
@ -140,7 +144,7 @@ wallet_kyc_check (void *cls,
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"KYC requirement inserted for wallet %s (%llu, %d)\n",
TALER_B2S (&krc->h_payto),
(unsigned long long) krc->legi_row,
(unsigned long long) krc->kyc.requirement_row,
qs);
return qs;
}
@ -200,7 +204,7 @@ TEH_handler_kyc_wallet (
&reserve_pub);
TALER_payto_hash (payto_uri,
&krc.h_payto);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"h_payto of wallet %s is %s\n",
payto_uri,
TALER_B2S (&krc.h_payto));
@ -224,11 +228,9 @@ TEH_handler_kyc_wallet (
NULL,
0);
}
return TALER_MHD_REPLY_JSON_PACK (
rc->connection,
MHD_HTTP_OK,
GNUNET_JSON_pack_uint64 ("legitimization_uuid",
krc.legi_row));
return TEH_RESPONSE_reply_kyc_required (rc->connection,
&krc.h_payto,
&krc.kyc);
}

View File

@ -57,6 +57,12 @@ struct KycWebhookContext
*/
struct TALER_KYCLOGIC_Plugin *plugin;
/**
* Section in the configuration of the configured
* KYC provider.
*/
const char *provider_section;
/**
* Configuration for the specific action.
*/
@ -72,12 +78,6 @@ struct KycWebhookContext
*/
struct MHD_Response *response;
/**
* Logic the request is for. Name of the configuration
* section defining the KYC logic.
*/
char *logic;
/**
* HTTP response code to return.
*/
@ -147,8 +147,9 @@ TEH_kyc_webhook_cleanup (void)
* will be done by the plugin.
*
* @param cls closure
* @param legi_row legitimization request the webhook was about
* @param process_row legitimization process the webhook was about
* @param account_id account the webhook was about
* @param provider_section name of the configuration section of the logic that was run
* @param provider_user_id set to user ID at the provider, or NULL if not supported or unknown
* @param provider_legitimization_id set to legitimization process ID at the provider, or NULL if not supported or unknown
* @param status KYC status
@ -159,8 +160,9 @@ TEH_kyc_webhook_cleanup (void)
static void
webhook_finished_cb (
void *cls,
uint64_t legi_row,
uint64_t process_row,
const struct TALER_PaytoHashP *account_id,
const char *provider_section,
const char *provider_user_id,
const char *provider_legitimization_id,
enum TALER_KYCLOGIC_KycStatus status,
@ -178,13 +180,13 @@ webhook_finished_cb (
{
enum GNUNET_DB_QueryStatus qs;
qs = TEH_plugin->update_kyc_requirement_by_row (TEH_plugin->cls,
legi_row,
kwh->logic,
account_id,
provider_user_id,
provider_legitimization_id,
expiration);
qs = TEH_plugin->update_kyc_process_by_row (TEH_plugin->cls,
process_row,
provider_section,
account_id,
provider_user_id,
provider_legitimization_id,
expiration);
if (qs < 0)
{
GNUNET_break (0);
@ -201,7 +203,7 @@ webhook_finished_cb (
"KYC status of %s/%s (Row #%llu) is %d\n",
provider_user_id,
provider_legitimization_id,
(unsigned long long) legi_row,
(unsigned long long) process_row,
status);
break;
}
@ -231,7 +233,6 @@ clean_kwh (struct TEH_RequestContext *rc)
MHD_destroy_response (kwh->response);
kwh->response = NULL;
}
GNUNET_free (kwh->logic);
GNUNET_free (kwh);
}
@ -257,23 +258,23 @@ handler_kyc_webhook_generic (
if (NULL == kwh)
{ /* first time */
kwh = GNUNET_new (struct KycWebhookContext);
kwh->logic = GNUNET_strdup (args[0]);
kwh->rc = rc;
rc->rh_ctx = kwh;
rc->rh_cleaner = &clean_kwh;
if (GNUNET_OK !=
TALER_KYCLOGIC_kyc_get_logic (kwh->logic,
&kwh->plugin,
&kwh->pd))
TALER_KYCLOGIC_lookup_logic (args[0],
&kwh->plugin,
&kwh->pd,
&kwh->provider_section))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"KYC logic `%s' unknown (check KYC provider configuration)\n",
kwh->logic);
args[0]);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_NOT_FOUND,
TALER_EC_EXCHANGE_KYC_GENERIC_LOGIC_UNKNOWN,
"$LOGIC");
"$NAME");
}
kwh->wh = kwh->plugin->webhook (kwh->plugin->cls,
kwh->pd,

View File

@ -291,7 +291,7 @@ merge_transaction (void *cls,
TEH_plugin->cls,
required,
&pcc->h_payto,
&pcc->kyc.legitimization_uuid);
&pcc->kyc.requirement_row);
}
pcc->kyc.ok = true;
qs = TEH_plugin->do_purse_merge (
@ -665,6 +665,7 @@ TEH_handler_purses_merge (
GNUNET_free (pcc.provider_url);
if (! pcc.kyc.ok)
return TEH_RESPONSE_reply_kyc_required (connection,
&pcc.h_payto,
&pcc.kyc);
{

View File

@ -206,7 +206,7 @@ purse_transaction (void *cls,
TEH_plugin->cls,
required,
&rpc->h_payto,
&rpc->kyc.legitimization_uuid);
&rpc->kyc.requirement_row);
}
rpc->kyc.ok = true;
@ -709,6 +709,7 @@ TEH_handler_reserves_purse (
if (! rpc.kyc.ok)
return TEH_RESPONSE_reply_kyc_required (connection,
&rpc.h_payto,
&rpc.kyc);
/* generate regular response */
{

View File

@ -979,13 +979,16 @@ TEH_RESPONSE_reply_purse_created (
MHD_RESULT
TEH_RESPONSE_reply_kyc_required (struct MHD_Connection *connection,
const struct TALER_PaytoHashP *h_payto,
const struct TALER_EXCHANGEDB_KycStatus *kyc)
{
return TALER_MHD_REPLY_JSON_PACK (
connection,
MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
GNUNET_JSON_pack_uint64 ("legitimization_uuid",
kyc->legitimization_uuid));
GNUNET_JSON_pack_data_auto ("h_payto",
h_payto),
GNUNET_JSON_pack_uint64 ("requirement_row",
kyc->requirement_row));
}

View File

@ -79,11 +79,13 @@ TEH_RESPONSE_reply_reserve_insufficient_balance (
* satisfied to proceed to client.
*
* @param connection connection to the client
* @param h_payto account identifier to include in reply
* @param kyc details about the KYC requirements
* @return MHD result code
*/
MHD_RESULT
TEH_RESPONSE_reply_kyc_required (struct MHD_Connection *connection,
const struct TALER_PaytoHashP *h_payto,
const struct TALER_EXCHANGEDB_KycStatus *kyc);

View File

@ -179,7 +179,7 @@ withdraw_transaction (void *cls,
TEH_plugin->cls,
kyc_required,
&wc->h_payto,
&wc->kyc.legitimization_uuid);
&wc->kyc.requirement_row);
}
}
wc->kyc.ok = true;
@ -489,6 +489,7 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
if (! wc.kyc.ok)
return TEH_RESPONSE_reply_kyc_required (rc->connection,
&wc.h_payto,
&wc.kyc);
{
MHD_RESULT ret;

View File

@ -84,9 +84,9 @@ END
$$;
----------------------- legitimizations ---------------------------
----------------------- legitimization_processes ---------------------------
CREATE OR REPLACE FUNCTION create_table_legitimizations(
CREATE OR REPLACE FUNCTION create_table_legitimization_processes(
IN shard_suffix VARCHAR DEFAULT NULL
)
RETURNS VOID
@ -96,7 +96,7 @@ BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE IF NOT EXISTS %I'
'(legitimization_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY' -- UNIQUE'
'(legitimization_process_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY' -- UNIQUE'
',h_payto BYTEA NOT NULL CHECK (LENGTH(h_payto)=32)'
',expiration_time INT8 NOT NULL DEFAULT (0)'
',provider_section VARCHAR NOT NULL'
@ -104,7 +104,7 @@ BEGIN
',provider_legitimization_id VARCHAR DEFAULT NULL'
',UNIQUE (h_payto, provider_section)'
') %s ;'
,'legitimizations'
,'legitimization_processes'
,'PARTITION BY HASH (h_payto)'
,shard_suffix
);
@ -114,7 +114,7 @@ $$;
-- We need a separate function for this, as we call create_table only once but need to add
-- those constraints to each partition which gets created
CREATE OR REPLACE FUNCTION add_constraints_to_legitimizations_partition(
CREATE OR REPLACE FUNCTION add_constraints_to_legitimization_processes_partition(
IN partition_suffix VARCHAR
)
RETURNS void
@ -124,13 +124,13 @@ DECLARE
partition_name VARCHAR;
BEGIN
partition_name = concat_ws('_', 'legitimizations', partition_suffix);
partition_name = concat_ws('_', 'legitimization_processes', partition_suffix);
EXECUTE FORMAT (
'ALTER TABLE ' || partition_name
|| ' '
'ADD CONSTRAINT ' || partition_name || '_legitimization_serial_id_key '
'UNIQUE (legitimization_serial_id)');
'ADD CONSTRAINT ' || partition_name || '_serial_key '
'UNIQUE (legitimization_process_serial_id)');
EXECUTE FORMAT (
'CREATE INDEX IF NOT EXISTS ' || partition_name || '_by_provider_and_legi_index '
'ON '|| partition_name || ' '
@ -143,6 +143,55 @@ BEGIN
END
$$;
----------------------- legitimization_requirements ---------------------------
CREATE OR REPLACE FUNCTION create_table_legitimization_requirements(
IN shard_suffix VARCHAR DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE IF NOT EXISTS %I'
'(legitimization_requirement_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY' -- UNIQUE'
',h_payto BYTEA NOT NULL CHECK (LENGTH(h_payto)=32)'
',required_checks VARCHAR NOT NULL'
',UNIQUE (h_payto, required_checks)'
') %s ;'
,'legitimization_requirements'
,'PARTITION BY HASH (h_payto)'
,shard_suffix
);
END
$$;
-- We need a separate function for this, as we call create_table only once but need to add
-- those constraints to each partition which gets created
CREATE OR REPLACE FUNCTION add_constraints_to_legitimization_requirements_partition(
IN partition_suffix VARCHAR
)
RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
partition_name VARCHAR;
BEGIN
partition_name = concat_ws('_', 'legitimization_requirements', partition_suffix);
EXECUTE FORMAT (
'ALTER TABLE ' || partition_name
|| ' '
'ADD CONSTRAINT ' || partition_name || '_serial_id_key '
'UNIQUE (legitimization_requirement_serial_id)');
END
$$;
------------------------ reserves -------------------------------
CREATE OR REPLACE FUNCTION create_table_reserves(
@ -895,6 +944,7 @@ BEGIN
',wire_target_h_payto BYTEA CHECK (LENGTH(wire_target_h_payto)=32)'
',merchant_pub BYTEA CHECK (LENGTH(merchant_pub)=32)'
',exchange_account_section TEXT NOT NULL'
',legitimization_requirement_serial_id INT8 NOT NULL DEFAULT(0)'
',wtid_raw BYTEA NOT NULL CHECK (LENGTH(wtid_raw)=32)'
') %s ;'
,table_name

View File

@ -128,30 +128,50 @@ CREATE TABLE IF NOT EXISTS wire_targets_default
SELECT add_constraints_to_wire_targets_partition('default');
-- ------------------------------ legitimizations ----------------------------------------
-- ------------------------------ legitimization_processes ----------------------------------------
SELECT create_table_legitimizations();
SELECT create_table_legitimization_processes();
COMMENT ON TABLE legitimizations
IS 'List of legitimizations (required and completed) by account and provider';
COMMENT ON COLUMN legitimizations.legitimization_serial_id
COMMENT ON TABLE legitimization_processes
IS 'List of legitimization processes (ongoing and completed) by account and provider';
COMMENT ON COLUMN legitimization_processes.legitimization_process_serial_id
IS 'unique ID for this legitimization process at the exchange';
COMMENT ON COLUMN legitimizations.h_payto
COMMENT ON COLUMN legitimization_processes.h_payto
IS 'foreign key linking the entry to the wire_targets table, NOT a primary key (multiple legitimizations are possible per wire target)';
COMMENT ON COLUMN legitimizations.expiration_time
COMMENT ON COLUMN legitimization_processes.expiration_time
IS 'in the future if the respective KYC check was passed successfully';
COMMENT ON COLUMN legitimizations.provider_section
COMMENT ON COLUMN legitimization_processes.provider_section
IS 'Configuration file section with details about this provider';
COMMENT ON COLUMN legitimizations.provider_user_id
COMMENT ON COLUMN legitimization_processes.provider_user_id
IS 'Identifier for the user at the provider that was used for the legitimization. NULL if provider is unaware.';
COMMENT ON COLUMN legitimizations.provider_legitimization_id
COMMENT ON COLUMN legitimization_processes.provider_legitimization_id
IS 'Identifier for the specific legitimization process at the provider. NULL if legitimization was not started.';
CREATE TABLE IF NOT EXISTS legitimizations_default
PARTITION OF legitimizations
CREATE TABLE IF NOT EXISTS legitimization_processes_default
PARTITION OF legitimization_processes
FOR VALUES WITH (MODULUS 1, REMAINDER 0);
SELECT add_constraints_to_legitimizations_partition('default');
SELECT add_constraints_to_legitimization_processes_partition('default');
-- ------------------------------ legitimization_requirements_ ----------------------------------------
SELECT create_table_legitimization_requirements();
COMMENT ON TABLE legitimization_requirements
IS 'List of required legitimization by account';
COMMENT ON COLUMN legitimization_requirements.legitimization_requirement_serial_id
IS 'unique ID for this legitimization requirement at the exchange';
COMMENT ON COLUMN legitimization_requirements.h_payto
IS 'foreign key linking the entry to the wire_targets table, NOT a primary key (multiple legitimizations are possible per wire target)';
COMMENT ON COLUMN legitimization_requirements.required_checks
IS 'space-separated list of required checks';
CREATE TABLE IF NOT EXISTS legitimization_requirements_default
PARTITION OF legitimization_requirements
FOR VALUES WITH (MODULUS 1, REMAINDER 0);
SELECT add_constraints_to_legitimization_requirements_partition('default');

View File

@ -1692,8 +1692,7 @@ prepare_statements (struct PostgresClosure *pg)
GNUNET_PQ_make_prepare (
"get_deposit_without_wtid",
"SELECT"
" legi.expiration_time"
",legi.legitimization_serial_id"
" agt.legitimization_requirement_serial_id"
",dep.wire_salt"
",wt.payto_uri"
",dep.amount_with_fee_val"
@ -1702,14 +1701,18 @@ prepare_statements (struct PostgresClosure *pg)
",denom.fee_deposit_frac"
",dep.wire_deadline"
" FROM deposits dep"
" JOIN wire_targets wt USING (wire_target_h_payto)"
" JOIN known_coins kc ON (kc.coin_pub = dep.coin_pub)"
" JOIN denominations denom USING (denominations_serial)"
" LEFT JOIN legitimizations legi ON (wt.wire_target_h_payto = legi.h_payto)"
" JOIN wire_targets wt"
" USING (wire_target_h_payto)"
" JOIN known_coins kc"
" ON (kc.coin_pub = dep.coin_pub)"
" JOIN denominations denom"
" USING (denominations_serial)"
" LEFT JOIN aggregation_transient agt "
" ON ( (dep.wire_target_h_payto = agt.wire_target_h_payto) AND"
" (dep.merchant_pub = agt.merchant_pub) )"
" WHERE dep.coin_pub=$1"
" AND dep.merchant_pub=$3"
" AND dep.h_contract_terms=$2"
" ORDER BY legi.expiration_time ASC"
" LIMIT 1;",
3),
/* Used in #postgres_get_ready_deposit() */
@ -1828,10 +1831,11 @@ prepare_statements (struct PostgresClosure *pg)
" ,amount_frac"
" ,merchant_pub"
" ,wire_target_h_payto"
" ,legitimization_requirement_serial_id"
" ,exchange_account_section"
" ,wtid_raw)"
" VALUES ($1, $2, $3, $4, $5, $6);",
6),
" VALUES ($1, $2, $3, $4, $5, $6, $7);",
7),
/* Used in #postgres_select_aggregation_transient() */
GNUNET_PQ_make_prepare (
"select_aggregation_transient",
@ -1863,9 +1867,10 @@ prepare_statements (struct PostgresClosure *pg)
"UPDATE aggregation_transient"
" SET amount_val=$1"
" ,amount_frac=$2"
" ,legitimization_requirement_serial_id=$5"
" WHERE wire_target_h_payto=$3"
" AND wtid_raw=$4",
4),
5),
/* Used in #postgres_delete_aggregation_transient() */
GNUNET_PQ_make_prepare (
"delete_aggregation_transient",
@ -4504,25 +4509,41 @@ prepare_statements (struct PostgresClosure *pg)
/* Used in #postgres_insert_kyc_requirement_for_account() */
GNUNET_PQ_make_prepare (
"insert_legitimization_requirement",
"INSERT INTO legitimizations"
"INSERT INTO legitimization_requirements"
" (h_payto"
" ,provider_section"
" ,required_checks"
" ) VALUES "
" ($1, $2)"
" ON CONFLICT (h_payto,provider_section) "
" ON CONFLICT (h_payto,required_checks) "
" DO UPDATE SET h_payto=$1" /* syntax requirement: dummy op */
" RETURNING legitimization_serial_id",
" RETURNING legitimization_requirement_serial_id",
2),
/* Used in #postgres_insert_kyc_requirement_process() */
GNUNET_PQ_make_prepare (
"insert_legitimization_process",
"INSERT INTO legitimization_processes"
" (h_payto"
" ,provider_section"
" ,provider_user_id"
" ,provider_legitimization_id"
" ) VALUES "
" ($1, $2, $3, $4)"
" ON CONFLICT (h_payto,provider_section) "
" DO UPDATE SET"
" provider_user_id=$3"
" ,provider_legitimization_id=$4"
" RETURNING legitimization_process_serial_id",
4),
/* Used in #postgres_update_kyc_requirement_by_row() */
GNUNET_PQ_make_prepare (
"update_legitimization_requirement",
"UPDATE legitimizations"
"update_legitimization_process",
"UPDATE legitimization_processes"
" SET provider_user_id=$4"
" ,provider_legitimization_id=$5"
" ,expiration_time=GREATEST(expiration_time,$6)"
" WHERE"
" h_payto=$3"
" AND legitimization_serial_id=$1"
" AND legitimization_process_serial_id=$1"
" AND provider_section=$2;",
6),
GNUNET_PQ_make_prepare (
@ -4535,25 +4556,22 @@ prepare_statements (struct PostgresClosure *pg)
2),
/* Used in #postgres_lookup_kyc_requirement_by_row() */
GNUNET_PQ_make_prepare (
"lookup_legitimization_by_row",
"lookup_legitimization_requirement_by_row",
"SELECT "
" provider_section"
" required_checks"
",h_payto"
",expiration_time"
",provider_user_id"
",provider_legitimization_id"
" FROM legitimizations"
" WHERE legitimization_serial_id=$1;",
" FROM legitimization_requirements"
" WHERE legitimization_requirement_serial_id=$1;",
1),
/* Used in #postgres_lookup_kyc_requirement_by_account() */
/* Used in #postgres_lookup_kyc_process_by_account() */
GNUNET_PQ_make_prepare (
"lookup_legitimization_by_account",
"lookup_process_by_account",
"SELECT "
" legitimization_serial_id"
" legitimization_process_serial_id"
",expiration_time"
",provider_user_id"
",provider_legitimization_id"
" FROM legitimizations"
" FROM legitimization_processes"
" WHERE h_payto=$1"
" AND provider_section=$2;",
2),
@ -4562,8 +4580,8 @@ prepare_statements (struct PostgresClosure *pg)
"get_wire_target_by_legitimization_id",
"SELECT "
" h_payto"
",legitimization_serial_id"
" FROM legitimizations"
",legitimization_process_serial_id"
" FROM legitimization_processes"
" WHERE provider_legitimization_id=$1"
" AND provider_section=$2;",
2),
@ -4572,7 +4590,7 @@ prepare_statements (struct PostgresClosure *pg)
"get_satisfied_legitimizations",
"SELECT "
" provider_section"
" FROM legitimizations"
" FROM legitimization_processes"
" WHERE h_payto=$1"
" AND expiration_time>=$2;",
2),
@ -7527,6 +7545,7 @@ postgres_aggregate (
* @param exchange_account_section exchange account to use
* @param merchant_pub public key of the merchant receiving the transfer
* @param wtid the raw wire transfer identifier to be used
* @param kyc_requirement_row row in legitimization_requirements that need to be satisfied to continue, or 0 for none
* @param total amount to be wired in the future
* @return transaction status
*/
@ -7537,6 +7556,7 @@ postgres_create_aggregation_transient (
const char *exchange_account_section,
const struct TALER_MerchantPublicKeyP *merchant_pub,
const struct TALER_WireTransferIdentifierRawP *wtid,
uint64_t kyc_requirement_row,
const struct TALER_Amount *total)
{
struct PostgresClosure *pg = cls;
@ -7544,6 +7564,7 @@ postgres_create_aggregation_transient (
TALER_PQ_query_param_amount (total),
GNUNET_PQ_query_param_auto_from_type (merchant_pub),
GNUNET_PQ_query_param_auto_from_type (h_payto),
GNUNET_PQ_query_param_uint64 (&kyc_requirement_row),
GNUNET_PQ_query_param_string (exchange_account_section),
GNUNET_PQ_query_param_auto_from_type (wtid),
GNUNET_PQ_query_param_end
@ -7727,6 +7748,7 @@ postgres_find_aggregation_transient (
* @param cls the @e cls of this struct with the plugin-specific state
* @param h_payto destination of the wire transfer
* @param wtid the raw wire transfer identifier to update
* @param kyc_requirement_row row in legitimization_requirements that need to be satisfied to continue, or 0 for none
* @param total new total amount to be wired in the future
* @return transaction status
*/
@ -7735,6 +7757,7 @@ postgres_update_aggregation_transient (
void *cls,
const struct TALER_PaytoHashP *h_payto,
const struct TALER_WireTransferIdentifierRawP *wtid,
uint64_t kyc_requirement_row,
const struct TALER_Amount *total)
{
struct PostgresClosure *pg = cls;
@ -7742,6 +7765,7 @@ postgres_update_aggregation_transient (
TALER_PQ_query_param_amount (total),
GNUNET_PQ_query_param_auto_from_type (h_payto),
GNUNET_PQ_query_param_auto_from_type (wtid),
GNUNET_PQ_query_param_uint64 (&kyc_requirement_row),
GNUNET_PQ_query_param_end
};
@ -9555,7 +9579,6 @@ postgres_lookup_transfer_by_deposit (
deposit_fee),
GNUNET_PQ_result_spec_end
};
struct GNUNET_TIME_Absolute expiration;
memset (kyc,
0,
@ -9596,21 +9619,15 @@ postgres_lookup_transfer_by_deposit (
/* Check if transaction exists in deposits, so that we just
do not have a WTID yet. In that case, return without wtid
(by setting 'pending' true). */
bool no_kyc = false;
struct GNUNET_PQ_ResultSpec rs2[] = {
GNUNET_PQ_result_spec_auto_from_type ("wire_salt",
&wire_salt),
GNUNET_PQ_result_spec_string ("payto_uri",
&payto_uri),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_uint64 ("legitimization_serial_id",
&kyc->legitimization_uuid),
&no_kyc),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_absolute_time ("expiration_time",
&expiration),
&no_kyc),
GNUNET_PQ_result_spec_uint64 ("legitimization_requirement_serial_id",
&kyc->requirement_row),
NULL),
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
amount_with_fee),
TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
@ -9628,10 +9645,8 @@ postgres_lookup_transfer_by_deposit (
{
struct TALER_MerchantWireHashP wh;
if (no_kyc)
kyc->legitimization_uuid = 0;
else
kyc->ok = GNUNET_TIME_absolute_is_future (expiration);
if (0 == kyc->requirement_row)
kyc->ok = true; /* technically: unknown */
TALER_merchant_wire_signature_hash (payto_uri,
&wire_salt,
&wh);
@ -16450,7 +16465,7 @@ postgres_profit_drains_set_finished (
* @param cls closure
* @param provider_section provider that must be checked
* @param h_payto account that must be KYC'ed
* @param[out] legi_row set to legitimization row for this check
* @param[out] requirement_row set to legitimization requirement row for this check
* @return database transaction status
*/
static enum GNUNET_DB_QueryStatus
@ -16458,7 +16473,7 @@ postgres_insert_kyc_requirement_for_account (
void *cls,
const char *provider_section,
const struct TALER_PaytoHashP *h_payto,
uint64_t *legi_row)
uint64_t *requirement_row)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
@ -16467,8 +16482,8 @@ postgres_insert_kyc_requirement_for_account (
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_uint64 ("legitimization_serial_id",
legi_row),
GNUNET_PQ_result_spec_uint64 ("legitimization_requirement_serial_id",
requirement_row),
GNUNET_PQ_result_spec_end
};
@ -16480,23 +16495,69 @@ postgres_insert_kyc_requirement_for_account (
}
/**
* Begin KYC requirement process.
*
* @param cls closure
* @param h_payto account that must be KYC'ed
* @param provider_section provider that must be checked
* @param provider_account_id provider account ID
* @param provider_legitimization_id provider legitimization ID
* @param[out] process_row row the process is stored under
* @return database transaction status
*/
static enum GNUNET_DB_QueryStatus
postgres_insert_kyc_requirement_process (
void *cls,
const struct TALER_PaytoHashP *h_payto,
const char *provider_section,
const char *provider_account_id,
const char *provider_legitimization_id,
uint64_t *process_row)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (h_payto),
GNUNET_PQ_query_param_string (provider_section),
(NULL != provider_account_id)
? GNUNET_PQ_query_param_string (provider_account_id)
: GNUNET_PQ_query_param_null (),
(NULL != provider_legitimization_id)
? GNUNET_PQ_query_param_string (provider_legitimization_id)
: GNUNET_PQ_query_param_null (),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_uint64 ("legitimization_process_serial_id",
process_row),
GNUNET_PQ_result_spec_end
};
return GNUNET_PQ_eval_prepared_singleton_select (
pg->conn,
"insert_legitimization_process",
params,
rs);
}
/**
* Update KYC requirement check with provider-linkage and/or
* expiration data.
*
* @param cls closure
* @param legi_row row to select by
* @param provider_section provider that must be checked
* @param h_payto account that must be KYC'ed
* @param provider_section provider that must be checked (technically redundant)
* @param h_payto account that must be KYC'ed (helps access by shard, otherwise also redundant)
* @param provider_account_id provider account ID
* @param provider_legitimization_id provider legitimization ID
* @param expiration how long is this KYC check set to be valid (in the past if invalid)
* @return database transaction status
*/
static enum GNUNET_DB_QueryStatus
postgres_update_kyc_requirement_by_row (
postgres_update_kyc_process_by_row (
void *cls,
uint64_t legi_row,
uint64_t process_row,
const char *provider_section,
const struct TALER_PaytoHashP *h_payto,
const char *provider_account_id,
@ -16505,7 +16566,7 @@ postgres_update_kyc_requirement_by_row (
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_uint64 (&legi_row),
GNUNET_PQ_query_param_uint64 (&process_row),
GNUNET_PQ_query_param_string (provider_section),
GNUNET_PQ_query_param_auto_from_type (h_payto),
(NULL != provider_account_id)
@ -16521,12 +16582,12 @@ postgres_update_kyc_requirement_by_row (
qs = GNUNET_PQ_eval_prepared_non_select (
pg->conn,
"update_legitimization_requirement",
"update_legitimization_process",
params);
if (qs <= 0)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to update legitimization: %d\n",
"Failed to update legitimization process: %d\n",
qs);
return qs;
}
@ -16563,55 +16624,37 @@ postgres_update_kyc_requirement_by_row (
/**
* Lookup KYC provider meta data.
* Lookup KYC requirement.
*
* @param cls closure
* @param legi_row legitimization row to lookup
* @param requirement_row identifies requirement to look up
* @param[out] provider_section provider that must be checked
* @param[out] h_payto account that must be KYC'ed
* @param[out] expiration how long is this KYC check set to be valid (in the past if invalid)
* @param[out] provider_account_id provider account ID
* @param[out] provider_legitimization_id provider legitimization ID
* @return database transaction status
*/
static enum GNUNET_DB_QueryStatus
postgres_lookup_kyc_requirement_by_row (
void *cls,
uint64_t legi_row,
char **provider_section,
struct TALER_PaytoHashP *h_payto,
struct GNUNET_TIME_Absolute *expiration,
char **provider_account_id,
char **provider_legitimization_id)
uint64_t requirement_row,
char **requirements,
struct TALER_PaytoHashP *h_payto)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_uint64 (&legi_row),
GNUNET_PQ_query_param_uint64 (&requirement_row),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_string ("provider_section",
provider_section),
GNUNET_PQ_result_spec_string ("required_checks",
requirements),
GNUNET_PQ_result_spec_auto_from_type ("h_payto",
h_payto),
GNUNET_PQ_result_spec_absolute_time ("expiration_time",
expiration),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_string ("provider_user_id",
provider_account_id),
NULL),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_string ("provider_legitimization_id",
provider_legitimization_id),
NULL),
GNUNET_PQ_result_spec_end
};
*provider_account_id = NULL;
*provider_legitimization_id = NULL;
return GNUNET_PQ_eval_prepared_singleton_select (
pg->conn,
"lookup_legitimization_by_row",
"lookup_legitimization_requirement_by_row",
params,
rs);
}
@ -16623,18 +16666,18 @@ postgres_lookup_kyc_requirement_by_row (
* @param cls closure
* @param provider_section provider that must be checked
* @param h_payto account that must be KYC'ed
* @param[out] legi_row row with the legitimization data
* @param[out] process_row row with the legitimization data
* @param[out] expiration how long is this KYC check set to be valid (in the past if invalid)
* @param[out] provider_account_id provider account ID
* @param[out] provider_legitimization_id provider legitimization ID
* @return database transaction status
*/
static enum GNUNET_DB_QueryStatus
postgres_lookup_kyc_requirement_by_account (
postgres_lookup_kyc_process_by_account (
void *cls,
const char *provider_section,
const struct TALER_PaytoHashP *h_payto,
uint64_t *legi_row,
uint64_t *process_row,
struct GNUNET_TIME_Absolute *expiration,
char **provider_account_id,
char **provider_legitimization_id)
@ -16646,8 +16689,8 @@ postgres_lookup_kyc_requirement_by_account (
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_uint64 ("legitimization_serial_id",
legi_row),
GNUNET_PQ_result_spec_uint64 ("legitimization_process_serial_id",
process_row),
GNUNET_PQ_result_spec_absolute_time ("expiration_time",
expiration),
GNUNET_PQ_result_spec_allow_null (
@ -16665,7 +16708,7 @@ postgres_lookup_kyc_requirement_by_account (
*provider_legitimization_id = NULL;
return GNUNET_PQ_eval_prepared_singleton_select (
pg->conn,
"lookup_legitimization_by_account",
"lookup_process_by_account",
params,
rs);
}
@ -16688,7 +16731,7 @@ postgres_kyc_provider_account_lookup (
const char *provider_section,
const char *provider_legitimization_id,
struct TALER_PaytoHashP *h_payto,
uint64_t *legi_row)
uint64_t *process_row)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
@ -16699,8 +16742,8 @@ postgres_kyc_provider_account_lookup (
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_auto_from_type ("h_payto",
h_payto),
GNUNET_PQ_result_spec_uint64 ("legitimization_serial_id",
legi_row),
GNUNET_PQ_result_spec_uint64 ("legitimization_process_serial_id",
process_row),
GNUNET_PQ_result_spec_end
};
@ -17375,12 +17418,14 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
= &postgres_profit_drains_set_finished;
plugin->insert_kyc_requirement_for_account
= &postgres_insert_kyc_requirement_for_account;
plugin->update_kyc_requirement_by_row
= &postgres_update_kyc_requirement_by_row;
plugin->insert_kyc_requirement_process
= &postgres_insert_kyc_requirement_process;
plugin->update_kyc_process_by_row
= &postgres_update_kyc_process_by_row;
plugin->lookup_kyc_requirement_by_row
= &postgres_lookup_kyc_requirement_by_row;
plugin->lookup_kyc_requirement_by_account
= &postgres_lookup_kyc_requirement_by_account;
plugin->lookup_kyc_process_by_account
= &postgres_lookup_kyc_process_by_account;
plugin->kyc_provider_account_lookup
= &postgres_kyc_provider_account_lookup;
plugin->select_satisfied_kyc_processes

View File

@ -31,6 +31,13 @@ BEGIN
PERFORM create_table_reserves(shard_suffix);
PERFORM create_table_legitimization_requirements(shard_suffix);
PERFORM add_constraints_to_legitimization_requirements_partition(shard_suffix);
PERFORM create_table_legitimization_processes(shard_suffix);
PERFORM add_constraints_to_legitimization_processes_partition(shard_suffix);
PERFORM create_table_reserves_in(shard_suffix);
PERFORM add_constraints_to_reserves_in_partition(shard_suffix);

View File

@ -2203,6 +2203,7 @@ run (void *cls)
"x-bank",
&deposit.merchant_pub,
&wtid,
0,
&total));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->select_aggregation_transient (plugin->cls,
@ -2224,6 +2225,7 @@ run (void *cls)
plugin->update_aggregation_transient (plugin->cls,
&wire_target_h_payto,
&wtid,
0,
&total));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->select_aggregation_transient (plugin->cls,

View File

@ -2139,10 +2139,16 @@ struct TALER_EXCHANGE_WithdrawResponse
struct
{
/**
* Payment target that the merchant should use
* Requirement row that the merchant should use
* to check for its KYC status.
*/
uint64_t legitimization_uuid;
uint64_t requirement_row;
/**
* Hash of the payto-URI of the account to KYC;
*/
struct TALER_PaytoHashP h_payto;
} unavailable_for_legal_reasons;
/**
@ -2255,16 +2261,22 @@ struct TALER_EXCHANGE_BatchWithdrawResponse
} success;
/**
* Details if the status is #MHD_HTTP_ACCEPTED.
* Details if the status is #MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS.
*/
struct
{
/**
* Payment target that the merchant should use
* to check for its KYC status.
* Hash of the payto-URI of the account to KYC;
*/
uint64_t legitimization_uuid;
} accepted;
struct TALER_PaytoHashP h_payto;
/**
* Legitimization requirement that the merchant should use
* to check for its KYC status, 0 if not known.
*/
uint64_t requirement_row;
} unavailable_for_legal_reasons;
/**
* Details if the status is #MHD_HTTP_CONFLICT.
@ -3073,11 +3085,6 @@ struct TALER_EXCHANGE_GetDepositResponse
*/
struct TALER_Amount coin_contribution;
/**
* Payment target that the merchant should use
* to check for its KYC status.
*/
uint64_t legitimization_uuid;
} success;
/**
@ -3092,10 +3099,10 @@ struct TALER_EXCHANGE_GetDepositResponse
struct GNUNET_TIME_Timestamp execution_time;
/**
* Payment target that the merchant should use
* to check for its KYC status.
* KYC legitimization requirement that the merchant should use to check
* for its KYC status.
*/
uint64_t legitimization_uuid;
uint64_t requirement_row;
/**
* Set to 'true' if the KYC check is already finished and
@ -3394,14 +3401,19 @@ struct TALER_EXCHANGE_KycStatus
*/
struct TALER_ExchangeSignatureP exchange_sig;
} kyc_ok;
} success;
/**
* URL the user should open in a browser if
* the KYC process is to be run. Returned if
* @e http_status is #MHD_HTTP_ACCEPTED.
*/
const char *kyc_url;
struct
{
/**
* URL the user should open in a browser if
* the KYC process is to be run. Returned if
* @e http_status is #MHD_HTTP_ACCEPTED.
*/
const char *kyc_url;
} accepted;
} details;
@ -3424,7 +3436,7 @@ typedef void
* of a merchant.
*
* @param eh exchange handle to use
* @param legitimization_uuid number identifying the legitimization process
* @param requirement_row number identifying the KYC requirement
* @param h_payto hash of the payto:// URI at @a payment_target
* @param ut type of the entity performing the KYC check
* @param timeout how long to wait for a positive KYC status
@ -3434,7 +3446,7 @@ typedef void
*/
struct TALER_EXCHANGE_KycCheckHandle *
TALER_EXCHANGE_kyc_check (struct TALER_EXCHANGE_Handle *eh,
uint64_t legitimization_uuid,
uint64_t requirement_row,
const struct TALER_PaytoHashP *h_payto,
enum TALER_KYCLOGIC_KycUserType ut,
struct GNUNET_TIME_Relative timeout,
@ -3553,10 +3565,29 @@ struct TALER_EXCHANGE_WalletKycResponse
enum TALER_ErrorCode ec;
/**
* Wallet's payment target UUID. Only valid if
* @e http_status is #MHD_HTTP_OK
* Variants depending on @e http_status.
*/
uint64_t legitimization_uuid;
union
{
/**
* In case @e http_status is #MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS.
*/
struct
{
/**
* Wallet's KYC requirement row.
*/
uint64_t requirement_row;
/**
* Hash of the payto-URI identifying the wallet to KYC.
*/
struct TALER_PaytoHashP h_payto;
} unavailable_for_legal_reasons;
} details;
};
@ -4879,10 +4910,10 @@ struct TALER_EXCHANGE_AccountMergeResponse
struct
{
/**
* Payment target that the merchant should use
* Requirement row target that the merchant should use
* to check for its KYC status.
*/
uint64_t legitimization_uuid;
uint64_t requirement_row;
} unavailable_for_legal_reasons;
@ -4988,10 +5019,10 @@ struct TALER_EXCHANGE_PurseCreateMergeResponse
struct
{
/**
* Payment target that the merchant should use
* Requirement row that the merchant should use
* to check for its KYC status.
*/
uint64_t legitimization_uuid;
uint64_t requirement_row;
} unavailable_for_legal_reasons;
} details;

View File

@ -2273,15 +2273,14 @@ struct TALER_EXCHANGEDB_CsRevealFreshCoinData
/**
* Generic KYC status for some operation.
* @deprecated FIXME - remove with new KYC logic
*/
struct TALER_EXCHANGEDB_KycStatus
{
/**
* Number that identifies the KYC target the operation
* Number that identifies the KYC requirement the operation
* was about.
*/
uint64_t legitimization_uuid;
uint64_t requirement_row;
/**
* True if the KYC status is "satisfied".
@ -3667,6 +3666,7 @@ struct TALER_EXCHANGEDB_Plugin
* @param exchange_account_section exchange account to use
* @param merchant_pub public key of the merchant
* @param wtid the raw wire transfer identifier to be used
* @param kyc_requirement_row row in legitimization_requirements that need to be satisfied to continue, or 0 for none
* @param total amount to be wired in the future
* @return transaction status
*/
@ -3677,6 +3677,7 @@ struct TALER_EXCHANGEDB_Plugin
const char *exchange_account_section,
const struct TALER_MerchantPublicKeyP *merchant_pub,
const struct TALER_WireTransferIdentifierRawP *wtid,
uint64_t kyc_requirement_row,
const struct TALER_Amount *total);
@ -3725,6 +3726,7 @@ struct TALER_EXCHANGEDB_Plugin
* @param cls the @e cls of this struct with the plugin-specific state
* @param h_payto destination of the wire transfer
* @param wtid the raw wire transfer identifier to update
* @param kyc_requirement_row row in legitimization_requirements that need to be satisfied to continue, or 0 for none
* @param total new total amount to be wired in the future
* @return transaction status
*/
@ -3733,6 +3735,7 @@ struct TALER_EXCHANGEDB_Plugin
void *cls,
const struct TALER_PaytoHashP *h_payto,
const struct TALER_WireTransferIdentifierRawP *wtid,
uint64_t kyc_requirement_row,
const struct TALER_Amount *total);
@ -5583,36 +5586,57 @@ struct TALER_EXCHANGEDB_Plugin
* Insert KYC requirement for @a h_payto account into table.
*
* @param cls closure
* @param provider_section provider that must be checked
* @param requirements requirements that must be checked
* @param h_payto account that must be KYC'ed
* @param[out] legi_row set to legitimization row for this check
* @param[out] requirement_row set to legitimization requirement row for this check
* @return database transaction status
*/
enum GNUNET_DB_QueryStatus
(*insert_kyc_requirement_for_account)(
void *cls,
const char *provider_section,
const char *requirements,
const struct TALER_PaytoHashP *h_payto,
uint64_t *legi_row);
uint64_t *requirement_row);
/**
* Update KYC requirement check with provider-linkage and/or
* Begin KYC requirement process.
*
* @param cls closure
* @param h_payto account that must be KYC'ed
* @param provider_section provider that must be checked
* @param provider_account_id provider account ID
* @param provider_legitimization_id provider legitimization ID
* @param[out] process_row row the process is stored under
* @return database transaction status
*/
enum GNUNET_DB_QueryStatus
(*insert_kyc_requirement_process)(
void *cls,
const struct TALER_PaytoHashP *h_payto,
const char *provider_section,
const char *provider_account_id,
const char *provider_legitimization_id,
uint64_t *process_row);
/**
* Update KYC process with updated provider-linkage and/or
* expiration data.
*
* @param cls closure
* @param legi_row row to select by
* @param provider_section provider that must be checked
* @param h_payto account that must be KYC'ed
* @param process_row row to select by
* @param provider_section provider that must be checked (technically redundant)
* @param h_payto account that must be KYC'ed (helps access by shard, otherwise also redundant)
* @param provider_account_id provider account ID
* @param provider_legitimization_id provider legitimization ID
* @param expiration how long is this KYC check set to be valid (in the past if invalid)
* @return database transaction status
*/
enum GNUNET_DB_QueryStatus
(*update_kyc_requirement_by_row)(
(*update_kyc_process_by_row)(
void *cls,
uint64_t legi_row,
uint64_t process_row,
const char *provider_section,
const struct TALER_PaytoHashP *h_payto,
const char *provider_account_id,
@ -5621,46 +5645,40 @@ struct TALER_EXCHANGEDB_Plugin
/**
* Lookup KYC provider meta data.
* Lookup KYC requirement.
*
* @param cls closure
* @param legi_row legitimization row to lookup
* @param[out] provider_section provider that must be checked
* @param legi_row identifies requirement to look up
* @param[out] requirements space-separated list of requirements
* @param[out] h_payto account that must be KYC'ed
* @param[out] expiration how long is this KYC check set to be valid (in the past if invalid)
* @param[out] provider_account_id provider account ID
* @param[out] provider_legitimization_id provider legitimization ID
* @return database transaction status
*/
enum GNUNET_DB_QueryStatus
(*lookup_kyc_requirement_by_row)(
void *cls,
uint64_t legi_row,
char **provider_section,
struct TALER_PaytoHashP *h_payto,
struct GNUNET_TIME_Absolute *expiration,
char **provider_account_id,
char **provider_legitimization_id);
uint64_t requirement_row,
char **requirements,
struct TALER_PaytoHashP *h_payto);
/**
* Lookup KYC provider meta data.
* Lookup KYC process meta data.
*
* @param cls closure
* @param provider_section provider that must be checked
* @param h_payto account that must be KYC'ed
* @param[out] legi_row row with the legitimization data
* @param[out] process_row set to row with the legitimization data
* @param[out] expiration how long is this KYC check set to be valid (in the past if invalid)
* @param[out] provider_account_id provider account ID
* @param[out] provider_legitimization_id provider legitimization ID
* @return database transaction status
*/
enum GNUNET_DB_QueryStatus
(*lookup_kyc_requirement_by_account)(
(*lookup_kyc_process_by_account)(
void *cls,
const char *provider_section,
const struct TALER_PaytoHashP *h_payto,
uint64_t *legi_row,
uint64_t *process_row,
struct GNUNET_TIME_Absolute *expiration,
char **provider_account_id,
char **provider_legitimization_id);
@ -5674,7 +5692,7 @@ struct TALER_EXCHANGEDB_Plugin
* @param provider_section
* @param provider_legitimization_id legi to look up
* @param[out] h_payto where to write the result
* @param[out] legi_row where to write the row of the entry
* @param[out] process_row identifies the legitimization process on our end
* @return database transaction status
*/
enum GNUNET_DB_QueryStatus
@ -5683,7 +5701,7 @@ struct TALER_EXCHANGEDB_Plugin
const char *provider_section,
const char *provider_legitimization_id,
struct TALER_PaytoHashP *h_payto,
uint64_t *legi_row);
uint64_t *process_row);
/**

View File

@ -194,9 +194,7 @@ typedef enum GNUNET_DB_QueryStatus
/**
* Check if KYC is provided for a particular operation. Returns the best
* provider (configuration section name) that could perform the required
* check.
* Check if KYC is provided for a particular operation. Returns the set of checks that still need to be satisfied.
*
* Called within a database transaction, so must
* not start a new one.
@ -211,7 +209,8 @@ typedef enum GNUNET_DB_QueryStatus
* amounts involved in this type of operation
* at the given account
* @param ai_cls closure for @a ai
* @return NULL if no check is needed
* @return NULL if no check is needed,
* otherwise space-separated list of required checks
*/
const char *
TALER_KYCLOGIC_kyc_test_required (enum TALER_KYCLOGIC_KycTriggerEvent event,
@ -222,6 +221,23 @@ TALER_KYCLOGIC_kyc_test_required (enum TALER_KYCLOGIC_KycTriggerEvent event,
void *ai_cls);
/**
* Check if the @a requirements are now satsified for
* @a h_payto account.
*
* @param requirements space-spearated list of requirements
* @param h_payto hash over the account
* @param ki iterator over satisfied providers
* @param ki_cls closure for @a ki
* @return true if the KYC check was satisfied
*/
bool
TALER_KYCLOGIC_check_satisfied (const char *requirements,
const struct TALER_PaytoHashP *h_payto,
TALER_KYCLOGIC_KycSatisfiedIterator ki,
void *ki_cls);
/**
* Iterate over all thresholds that are applicable
* to a particular type of @a event
@ -269,17 +285,36 @@ TALER_KYCLOGIC_kyc_get_details (
/**
* Obtain the provider logic for a given @a provider_section_name.
* Obtain the provider logic for a given set of @a requirments.
*
* @param provider_section_name identifies a KYC provider process
* @param requirements space-separated list of required checks
* @param ut type of the entity performing the check
* @param[out] plugin set to the KYC logic API
* @param[out] pd set to the specific operation context
* @param[out] configuration_section set to the name of the KYC logic configuration section * @return #GNUNET_OK on success
*/
enum GNUNET_GenericReturnValue
TALER_KYCLOGIC_requirements_to_logic (const char *requirements,
enum TALER_KYCLOGIC_KycUserType ut,
struct TALER_KYCLOGIC_Plugin **plugin,
struct TALER_KYCLOGIC_ProviderDetails **pd,
const char **configuration_section);
/**
* Obtain the provider logic for a given @a name.
*
* @param name name of the logic or provider section
* @param[out] plugin set to the KYC logic API
* @param[out] pd set to the specific operation context
* @param[out] configuration_section set to the name of the KYC logic configuration section
* @return #GNUNET_OK on success
*/
enum GNUNET_GenericReturnValue
TALER_KYCLOGIC_kyc_get_logic (const char *provider_section_name,
struct TALER_KYCLOGIC_Plugin **plugin,
struct TALER_KYCLOGIC_ProviderDetails **pd);
TALER_KYCLOGIC_lookup_logic (const char *name,
struct TALER_KYCLOGIC_Plugin **plugin,
struct TALER_KYCLOGIC_ProviderDetails **pd,
const char **configuration_section);
#endif

View File

@ -180,8 +180,9 @@ typedef void
* MUST NOT be done by the plugin!
*
* @param cls closure
* @param legi_row legitimization request the webhook was about
* @param process_row legitimization process the webhook was about
* @param account_id account the webhook was about
* @param provider_section name of the configuration section of the logic that was run
* @param provider_user_id set to user ID at the provider, or NULL if not supported or unknown
* @param provider_legitimization_id set to legitimization process ID at the provider, or NULL if not supported or unknown
* @param status KYC status
@ -192,8 +193,9 @@ typedef void
typedef void
(*TALER_KYCLOGIC_WebhookCallback)(
void *cls,
uint64_t legi_row,
uint64_t process_row,
const struct TALER_PaytoHashP *account_id,
const char *provider_section,
const char *provider_user_id,
const char *provider_legitimization_id,
enum TALER_KYCLOGIC_KycStatus status,
@ -203,16 +205,15 @@ typedef void
/**
* Function the plugin can use to lookup an
* @a h_payto by @a provider_legitimization_id.
* Must match the `kyc_provider_account_lookup`
* Function the plugin can use to lookup an @a h_payto by @a
* provider_legitimization_id. Must match the `kyc_provider_account_lookup`
* of the exchange's database plugin.
*
* @param cls closure
* @param provider_section
* @param provider_legitimization_id legi to look up
* @param[out] h_payto where to write the result
* @param[out] legi_row where to write the row of the entry
* @param[out] process_row where to write the row of the entry
* @return database transaction status
*/
typedef enum GNUNET_DB_QueryStatus
@ -221,7 +222,7 @@ typedef enum GNUNET_DB_QueryStatus
const char *provider_section,
const char *provider_legitimization_id,
struct TALER_PaytoHashP *h_payto,
uint64_t *legi_row);
uint64_t *process_row);
/**
@ -274,7 +275,7 @@ struct TALER_KYCLOGIC_Plugin
* @param cls the @e cls of this struct with the plugin-specific state
* @param pd provider configuration details
* @param account_id which account to trigger process for
* @param legitimization_uuid unique ID for the legitimization process
* @param process_row unique ID for the legitimization process
* @param cb function to call with the result
* @param cb_cls closure for @a cb
* @return handle to cancel operation early
@ -283,7 +284,7 @@ struct TALER_KYCLOGIC_Plugin
(*initiate)(void *cls,
const struct TALER_KYCLOGIC_ProviderDetails *pd,
const struct TALER_PaytoHashP *account_id,
uint64_t legitimization_uuid,
uint64_t process_row,
TALER_KYCLOGIC_InitiateCallback cb,
void *cb_cls);
@ -305,7 +306,7 @@ struct TALER_KYCLOGIC_Plugin
* @param url_path rest of the URL after `/kyc-webhook/$H_PAYTO/$LOGIC`
* @param connection MHD connection object (for HTTP headers)
* @param account_id which account to trigger process for
* @param legi_row row in the table the legitimization is for
* @param process_row row in the legitimization processes table the legitimization is for
* @param provider_user_id user ID (or NULL) the proof is for
* @param provider_legitimization_id legitimization ID the proof is for
* @param cb function to call with the result
@ -318,7 +319,7 @@ struct TALER_KYCLOGIC_Plugin
const char *const url_path[],
struct MHD_Connection *connection,
const struct TALER_PaytoHashP *account_id,
uint64_t legi_row,
uint64_t process_row,
const char *provider_user_id,
const char *provider_legitimization_id,
TALER_KYCLOGIC_ProofCallback cb,

View File

@ -2796,7 +2796,7 @@ TALER_TESTING_get_trait (const struct TALER_TESTING_Trait *traits,
op (kyc_url, const char *) \
op (web_url, const char *) \
op (row, const uint64_t) \
op (legitimization_uuid, const uint64_t) \
op (legi_requirement_row, const uint64_t) \
op (array_length, const unsigned int) \
op (credit_payto_uri, const char *) \
op (debit_payto_uri, const char *) \

View File

@ -992,11 +992,36 @@ TALER_KYCLOGIC_kyc_test_required (enum TALER_KYCLOGIC_KycTriggerEvent event,
{
struct TALER_KYCLOGIC_KycCheck *needed[num_kyc_checks];
unsigned int needed_cnt = 0;
char *ret;
struct GNUNET_TIME_Relative timeframe;
unsigned long long min_cost = ULONG_LONG_MAX;
unsigned int max_checks = 0;
const struct TALER_KYCLOGIC_KycProvider *kp_best = NULL;
timeframe = GNUNET_TIME_UNIT_ZERO;
for (unsigned int i = 0; i<num_kyc_triggers; i++)
{
const struct TALER_KYCLOGIC_KycTrigger *kt = kyc_triggers[i];
if (event != kt->trigger)
continue;
timeframe = GNUNET_TIME_relative_max (timeframe,
kt->timeframe);
}
{
struct GNUNET_TIME_Absolute now;
struct ThresholdTestContext ttc = {
.event = event,
.needed = needed,
.needed_cnt = &needed_cnt
};
now = GNUNET_TIME_absolute_get ();
ai (ai_cls,
GNUNET_TIME_absolute_subtract (now,
timeframe),
&eval_trigger,
&ttc);
}
if (0 == needed_cnt)
return NULL;
timeframe = GNUNET_TIME_UNIT_ZERO;
for (unsigned int i = 0; i<num_kyc_triggers; i++)
{
@ -1041,56 +1066,44 @@ TALER_KYCLOGIC_kyc_test_required (enum TALER_KYCLOGIC_KycTriggerEvent event,
}
if (0 == needed_cnt)
return NULL;
/* Count maximum number of remaining checks covered by any
provider */
for (unsigned int i = 0; i<num_kyc_providers; i++)
{
const struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
unsigned int matched = 0;
struct RemoveContext rc = {
.needed = needed,
.needed_cnt = &needed_cnt
};
enum GNUNET_DB_QueryStatus qs;
for (unsigned int j = 0; j<kp->num_checks; j++)
{
const struct TALER_KYCLOGIC_KycCheck *kc = kp->provided_checks[j];
for (unsigned int k = 0; k<needed_cnt; k++)
if (kc == needed[k])
{
matched++;
break;
}
}
max_checks = GNUNET_MAX (max_checks,
matched);
/* Check what provider checks are already satisfied for h_payto (with
database), remove those from the 'needed' array. */
qs = ki (ki_cls,
h_payto,
&remove_satisfied,
&rc);
GNUNET_break (qs >= 0); // FIXME: handle DB failure more nicely?
}
/* Find min-cost provider covering max_checks. */
for (unsigned int i = 0; i<num_kyc_providers; i++)
if (0 == needed_cnt)
return NULL;
ret = NULL;
for (unsigned int k = 0; k<needed_cnt; k++)
{
const struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
unsigned int matched = 0;
const struct TALER_KYCLOGIC_KycCheck *kc = needed[k];
for (unsigned int j = 0; j<kp->num_checks; j++)
if (NULL == ret)
{
const struct TALER_KYCLOGIC_KycCheck *kc = kp->provided_checks[j];
for (unsigned int k = 0; k<needed_cnt; k++)
if (kc == needed[k])
{
matched++;
break;
}
ret = GNUNET_strdup (kc->name);
}
if ( (max_checks == matched) &&
(kp->cost < min_cost) )
else /* append */
{
min_cost = kp->cost;
kp_best = kp;
char *tmp = ret;
GNUNET_asprintf (&ret,
"%s %s",
tmp,
kc->name);
GNUNET_free (tmp);
}
}
GNUNET_assert (NULL != kp_best);
return kp_best->provider_section_name;
return ret;
}
@ -1117,21 +1130,143 @@ TALER_KYCLOGIC_kyc_get_details (
}
bool
TALER_KYCLOGIC_check_satisfied (const char *requirements,
const struct TALER_PaytoHashP *h_payto,
TALER_KYCLOGIC_KycSatisfiedIterator ki,
void *ki_cls)
{
struct TALER_KYCLOGIC_KycCheck *needed[num_kyc_checks];
unsigned int needed_cnt = 0;
if (NULL == requirements)
return true;
{
char *req = GNUNET_strdup (requirements);
for (const char *tok = strtok (req, " ");
NULL != tok;
tok = strtok (NULL, " "))
needed[needed_cnt++] = add_check (tok);
GNUNET_free (req);
}
{
struct RemoveContext rc = {
.needed = needed,
.needed_cnt = &needed_cnt
};
enum GNUNET_DB_QueryStatus qs;
/* Check what provider checks are already satisfied for h_payto (with
database), remove those from the 'needed' array. */
qs = ki (ki_cls,
h_payto,
&remove_satisfied,
&rc);
GNUNET_break (qs >= 0); // FIXME: handle DB failure more nicely?
}
return (0 == needed_cnt);
}
enum GNUNET_GenericReturnValue
TALER_KYCLOGIC_kyc_get_logic (const char *provider_section_name,
struct TALER_KYCLOGIC_Plugin **plugin,
struct TALER_KYCLOGIC_ProviderDetails **pd)
TALER_KYCLOGIC_requirements_to_logic (const char *requirements,
enum TALER_KYCLOGIC_KycUserType ut,
struct TALER_KYCLOGIC_Plugin **plugin,
struct TALER_KYCLOGIC_ProviderDetails **pd,
const char **configuration_section)
{
struct TALER_KYCLOGIC_KycCheck *needed[num_kyc_checks];
unsigned int needed_cnt = 0;
unsigned long long min_cost = ULONG_LONG_MAX;
unsigned int max_checks = 0;
const struct TALER_KYCLOGIC_KycProvider *kp_best = NULL;
if (NULL == requirements)
return GNUNET_NO;
{
char *req = GNUNET_strdup (requirements);
for (const char *tok = strtok (req, " ");
NULL != tok;
tok = strtok (NULL, " "))
needed[needed_cnt++] = add_check (tok);
GNUNET_free (req);
}
/* Count maximum number of remaining checks covered by any
provider */
for (unsigned int i = 0; i<num_kyc_providers; i++)
{
const struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
unsigned int matched = 0;
for (unsigned int j = 0; j<kp->num_checks; j++)
{
const struct TALER_KYCLOGIC_KycCheck *kc = kp->provided_checks[j];
for (unsigned int k = 0; k<needed_cnt; k++)
if (kc == needed[k])
{
matched++;
break;
}
}
max_checks = GNUNET_MAX (max_checks,
matched);
}
if (0 == max_checks)
return GNUNET_SYSERR;
/* Find min-cost provider covering max_checks. */
for (unsigned int i = 0; i<num_kyc_providers; i++)
{
const struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
unsigned int matched = 0;
for (unsigned int j = 0; j<kp->num_checks; j++)
{
const struct TALER_KYCLOGIC_KycCheck *kc = kp->provided_checks[j];
for (unsigned int k = 0; k<needed_cnt; k++)
if (kc == needed[k])
{
matched++;
break;
}
}
if ( (max_checks == matched) &&
(kp->cost < min_cost) )
{
min_cost = kp->cost;
kp_best = kp;
}
}
*plugin = kp_best->logic;
*pd = kp_best->pd;
*configuration_section = kp_best->provider_section_name;
return GNUNET_OK;
}
enum GNUNET_GenericReturnValue
TALER_KYCLOGIC_lookup_logic (const char *name,
struct TALER_KYCLOGIC_Plugin **plugin,
struct TALER_KYCLOGIC_ProviderDetails **pd,
const char **provider_section)
{
for (unsigned int i = 0; i<num_kyc_providers; i++)
{
struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
if (0 !=
strcasecmp (provider_section_name,
strcasecmp (name,
kp->provider_section_name))
continue;
*plugin = kp->logic;
*pd = kp->pd;
*provider_section = kp->provider_section_name;
return GNUNET_OK;
}
for (unsigned int i = 0; i<num_kyc_logics; i++)
@ -1140,15 +1275,16 @@ TALER_KYCLOGIC_kyc_get_logic (const char *provider_section_name,
if (0 !=
strcasecmp (logic->name,
provider_section_name))
name))
continue;
*plugin = logic;
*pd = NULL;
*provider_section = NULL;
return GNUNET_OK;
}
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Provider `%s' unknown\n",
provider_section_name);
name);
return GNUNET_SYSERR;
}

View File

@ -257,7 +257,7 @@ struct TALER_KYCLOGIC_WebhookHandle
* Row in legitimizations for the given
* @e verification_id.
*/
uint64_t legi_row;
uint64_t process_row;
/**
* HTTP response code to return asynchronously.
@ -646,7 +646,7 @@ proof_reply (void *cls)
* @param url_path rest of the URL after `/kyc-webhook/`
* @param connection MHD connection object (for HTTP headers)
* @param account_id which account to trigger process for
* @param legi_row row in the table the legitimization is for
* @param process_row row in the legitimization processes table the legitimization is for
* @param provider_user_id user ID (or NULL) the proof is for
* @param provider_legitimization_id legitimization ID the proof is for
* @param cb function to call with the result
@ -659,7 +659,7 @@ kycaid_proof (void *cls,
const char *const url_path[],
struct MHD_Connection *connection,
const struct TALER_PaytoHashP *account_id,
uint64_t legi_row,
uint64_t process_row,
const char *provider_user_id,
const char *provider_legitimization_id,
TALER_KYCLOGIC_ProofCallback cb,
@ -805,8 +805,9 @@ handle_webhook_finished (void *cls,
GNUNET_JSON_pack_object_incref ("kycaid_body",
(json_t *) j));
wh->cb (wh->cb_cls,
wh->legi_row,
wh->process_row,
&wh->h_payto,
wh->pd->section,
wh->applicant_id,
wh->verification_id,
TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
@ -826,8 +827,9 @@ handle_webhook_finished (void *cls,
{
expiration = GNUNET_TIME_relative_to_absolute (wh->pd->validity);
wh->cb (wh->cb_cls,
wh->legi_row,
wh->process_row,
&wh->h_payto,
wh->pd->section,
wh->applicant_id,
wh->verification_id,
TALER_KYCLOGIC_STATUS_SUCCESS,
@ -838,8 +840,9 @@ handle_webhook_finished (void *cls,
else
{
wh->cb (wh->cb_cls,
wh->legi_row,
wh->process_row,
&wh->h_payto,
wh->pd->section,
wh->applicant_id,
wh->verification_id,
TALER_KYCLOGIC_STATUS_USER_ABORTED,
@ -863,8 +866,9 @@ handle_webhook_finished (void *cls,
GNUNET_JSON_pack_uint64 ("kycaid_http_status",
response_code));
wh->cb (wh->cb_cls,
wh->legi_row,
wh->process_row,
&wh->h_payto,
wh->pd->section,
wh->applicant_id,
wh->verification_id,
TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
@ -883,8 +887,9 @@ handle_webhook_finished (void *cls,
GNUNET_JSON_pack_object_incref ("kycaid_body",
(json_t *) j));
wh->cb (wh->cb_cls,
wh->legi_row,
wh->process_row,
&wh->h_payto,
wh->pd->section,
wh->applicant_id,
wh->verification_id,
TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
@ -899,8 +904,9 @@ handle_webhook_finished (void *cls,
GNUNET_JSON_pack_object_incref ("kycaid_body",
(json_t *) j));
wh->cb (wh->cb_cls,
wh->legi_row,
wh->process_row,
&wh->h_payto,
wh->pd->section,
wh->applicant_id,
wh->verification_id,
TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
@ -921,8 +927,9 @@ handle_webhook_finished (void *cls,
GNUNET_JSON_pack_object_incref ("kycaid_body",
(json_t *) j));
wh->cb (wh->cb_cls,
wh->legi_row,
wh->process_row,
&wh->h_payto,
wh->pd->section,
wh->applicant_id,
wh->verification_id,
TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
@ -937,8 +944,9 @@ handle_webhook_finished (void *cls,
GNUNET_JSON_pack_object_incref ("kycaid_body",
(json_t *) j));
wh->cb (wh->cb_cls,
wh->legi_row,
wh->process_row,
&wh->h_payto,
wh->pd->section,
wh->applicant_id,
wh->verification_id,
TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
@ -953,8 +961,9 @@ handle_webhook_finished (void *cls,
GNUNET_JSON_pack_object_incref ("kycaid_body",
(json_t *) j));
wh->cb (wh->cb_cls,
wh->legi_row,
wh->process_row,
&wh->h_payto,
wh->pd->section,
wh->applicant_id,
wh->verification_id,
TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
@ -975,8 +984,9 @@ handle_webhook_finished (void *cls,
stderr,
JSON_INDENT (2));
wh->cb (wh->cb_cls,
wh->legi_row,
wh->process_row,
&wh->h_payto,
wh->pd->section,
wh->applicant_id,
wh->verification_id,
TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
@ -1000,10 +1010,11 @@ async_webhook_reply (void *cls)
struct TALER_KYCLOGIC_WebhookHandle *wh = cls;
wh->cb (wh->cb_cls,
wh->legi_row,
(0 == wh->legi_row)
wh->process_row,
(0 == wh->process_row)
? NULL
: &wh->h_payto,
wh->pd->section,
wh->applicant_id, /* provider user ID */
wh->verification_id, /* provider legi ID */
TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
@ -1117,7 +1128,7 @@ kycaid_webhook (void *cls,
pd->section,
verification_id,
&wh->h_payto,
&wh->legi_row);
&wh->process_row);
if (qs < 0)
{
wh->resp = TALER_MHD_make_error (TALER_EC_GENERIC_DB_FETCH_FAILED,

View File

@ -920,7 +920,7 @@ handle_curl_login_finished (void *cls,
* @param url_path rest of the URL after `/kyc-webhook/`
* @param connection MHD connection object (for HTTP headers)
* @param account_id which account to trigger process for
* @param legi_row row in the table the legitimization is for
* @param process_row row in the legitimization processes table the legitimization is for
* @param provider_user_id user ID (or NULL) the proof is for
* @param provider_legitimization_id legitimization ID the proof is for
* @param cb function to call with the result
@ -933,7 +933,7 @@ oauth2_proof (void *cls,
const char *const url_path[],
struct MHD_Connection *connection,
const struct TALER_PaytoHashP *account_id,
uint64_t legi_row,
uint64_t process_row,
const char *provider_user_id,
const char *provider_legitimization_id,
TALER_KYCLOGIC_ProofCallback cb,
@ -948,7 +948,7 @@ oauth2_proof (void *cls,
GNUNET_snprintf (ph->provider_legitimization_id,
sizeof (ph->provider_legitimization_id),
"%llu",
(unsigned long long) legi_row);
(unsigned long long) process_row);
if ( (NULL != provider_legitimization_id) &&
(0 != strcmp (provider_legitimization_id,
ph->provider_legitimization_id)))
@ -1114,6 +1114,7 @@ wh_return_not_found (void *cls)
NULL,
NULL,
NULL,
NULL,
TALER_KYCLOGIC_STATUS_KEEP,
GNUNET_TIME_UNIT_ZERO_ABS,
MHD_HTTP_NOT_FOUND,

View File

@ -234,9 +234,10 @@ struct TALER_KYCLOGIC_ProofHandle
struct TALER_PaytoHashP h_payto;
/**
* UUID being checked.
* Row in the legitimization processes of the
* legitimization proof that is being checked.
*/
uint64_t legitimization_uuid;
uint64_t process_row;
/**
* Account ID at the provider.
@ -320,7 +321,7 @@ struct TALER_KYCLOGIC_WebhookHandle
/**
* UUID being checked.
*/
uint64_t legitimization_uuid;
uint64_t process_row;
/**
* HTTP response code to return asynchronously.
@ -1041,7 +1042,7 @@ handle_proof_finished (void *cls,
"%llu%c",
&idr,
&dummy)) ||
(idr != ph->legitimization_uuid) )
(idr != ph->process_row) )
{
GNUNET_break_op (0);
proof_reply_error (ph,
@ -1347,7 +1348,7 @@ handle_proof_finished (void *cls,
* @param url_path rest of the URL after `/kyc-webhook/`
* @param connection MHD connection object (for HTTP headers)
* @param account_id which account to trigger process for
* @param legi_row row in the table the legitimization is for
* @param process_row row in the legitimization processes table the legitimization is for
* @param provider_user_id user ID (or NULL) the proof is for
* @param inquiry_id legitimization ID the proof is for
* @param cb function to call with the result
@ -1360,7 +1361,7 @@ persona_proof (void *cls,
const char *const url_path[],
struct MHD_Connection *connection,
const struct TALER_PaytoHashP *account_id,
uint64_t legi_row,
uint64_t process_row,
const char *provider_user_id,
const char *inquiry_id,
TALER_KYCLOGIC_ProofCallback cb,
@ -1382,7 +1383,7 @@ persona_proof (void *cls,
ph->cb = cb;
ph->cb_cls = cb_cls;
ph->connection = connection;
ph->legitimization_uuid = legi_row;
ph->process_row = process_row;
ph->h_payto = *account_id;
/* Note: we do not expect this to be non-NULL */
if (NULL != provider_user_id)
@ -1465,9 +1466,10 @@ webhook_generic_reply (struct TALER_KYCLOGIC_WebhookHandle *wh,
MHD_RESPMEM_PERSISTENT);
TALER_MHD_add_global_headers (resp);
wh->cb (wh->cb_cls,
wh->legitimization_uuid,
wh->process_row,
&wh->h_payto,
account_id,
wh->pd->section,
inquiry_id,
status,
expiration,
@ -1591,7 +1593,7 @@ handle_webhook_finished (void *cls,
"%llu%c",
&idr,
&dummy)) ||
(idr != wh->legitimization_uuid) )
(idr != wh->process_row) )
{
GNUNET_break_op (0);
webhook_reply_error (wh,
@ -1761,10 +1763,11 @@ async_webhook_reply (void *cls)
wh->task = NULL;
wh->cb (wh->cb_cls,
wh->legitimization_uuid,
(0 == wh->legitimization_uuid)
wh->process_row,
(0 == wh->process_row)
? NULL
: &wh->h_payto,
wh->pd->section,
NULL,
wh->inquiry_id, /* provider legi ID */
TALER_KYCLOGIC_STATUS_PROVIDER_FAILED,
@ -1967,7 +1970,7 @@ persona_webhook (void *cls,
wh->pd->section,
persona_inquiry_id,
&wh->h_payto,
&wh->legitimization_uuid);
&wh->process_row);
if (qs < 0)
{
wh->resp = TALER_MHD_make_error (TALER_EC_GENERIC_DB_FETCH_FAILED,

View File

@ -281,7 +281,7 @@ template_proof_cancel (struct TALER_KYCLOGIC_ProofHandle *ph)
* @param url_path rest of the URL after `/kyc-webhook/`
* @param connection MHD connection object (for HTTP headers)
* @param account_id which account to trigger process for
* @param legi_row row in the table the legitimization is for
* @param process_row row in the legitimization processes table the legitimization is for
* @param provider_user_id user ID (or NULL) the proof is for
* @param provider_legitimization_id legitimization ID the proof is for
* @param cb function to call with the result
@ -294,7 +294,7 @@ template_proof (void *cls,
const char *const url_path[],
struct MHD_Connection *connection,
const struct TALER_PaytoHashP *account_id,
uint64_t legi_row,
uint64_t process_row,
const char *provider_user_id,
const char *provider_legitimization_id,
TALER_KYCLOGIC_ProofCallback cb,

View File

@ -251,6 +251,12 @@ static char *cmd_provider_user_id;
*/
static char *cmd_provider_legitimization_id;
/**
* Name of the configuration section with the
* configuration data of the selected provider.
*/
static const char *provider_section_name;
/**
* Row ID to use, override with '-r'
*/
@ -271,10 +277,15 @@ static int run_webservice;
*/
static int global_ret;
/**
* -r command-line flag.
*/
static char *requirements;
/**
* -i command-line flag.
*/
static char *initiate_section;
static char *ut_s = "individual";
/**
* Handle for ongoing initiation operation.
@ -345,10 +356,10 @@ struct KycWebhookContext
struct MHD_Response *response;
/**
* Logic the request is for. Name of the configuration
* Name of the configuration
* section defining the KYC logic.
*/
char *logic;
const char *section_name;
/**
* HTTP response code to return.
@ -418,8 +429,9 @@ kyc_webhook_cleanup (void)
* will be done by the plugin.
*
* @param cls closure
* @param legi_row legitimization request the webhook was about
* @param process_row legitimization process request the webhook was about
* @param account_id account the webhook was about
* @param provider_section configuration section of the logic
* @param provider_user_id set to user ID at the provider, or NULL if not supported or unknown
* @param provider_legitimization_id set to legitimization process ID at the provider, or NULL if not supported or unknown
* @param status KYC status
@ -430,8 +442,9 @@ kyc_webhook_cleanup (void)
static void
webhook_finished_cb (
void *cls,
uint64_t legi_row,
uint64_t process_row,
const struct TALER_PaytoHashP *account_id,
const char *provider_section,
const char *provider_user_id,
const char *provider_legitimization_id,
enum TALER_KYCLOGIC_KycStatus status,
@ -442,6 +455,7 @@ webhook_finished_cb (
struct KycWebhookContext *kwh = cls;
kwh->wh = NULL;
// FIXME: check arguments for validity?
switch (status)
{
case TALER_KYCLOGIC_STATUS_SUCCESS:
@ -453,10 +467,10 @@ webhook_finished_cb (
break;
default:
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"KYC status of %s/%s (Row #%llu) is %d\n",
"KYC status of %s/%s (process #%llu) is %d\n",
provider_user_id,
provider_legitimization_id,
(unsigned long long) legi_row,
(unsigned long long) process_row,
status);
break;
}
@ -487,7 +501,6 @@ clean_kwh (struct TEKT_RequestContext *rc)
MHD_destroy_response (kwh->response);
kwh->response = NULL;
}
GNUNET_free (kwh->logic);
GNUNET_free (kwh);
}
@ -542,23 +555,31 @@ handler_kyc_webhook_generic (
if (NULL == kwh)
{ /* first time */
kwh = GNUNET_new (struct KycWebhookContext);
kwh->logic = GNUNET_strdup (args[0]);
kwh->rc = rc;
rc->rh_ctx = kwh;
rc->rh_cleaner = &clean_kwh;
if (GNUNET_OK !=
TALER_KYCLOGIC_kyc_get_logic (kwh->logic,
&kwh->plugin,
&kwh->pd))
TALER_KYCLOGIC_lookup_logic (args[0],
&kwh->plugin,
&kwh->pd,
&kwh->section_name))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"KYC logic `%s' unknown (check KYC provider configuration)\n",
kwh->logic);
args[0]);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_NOT_FOUND,
TALER_EC_EXCHANGE_KYC_GENERIC_LOGIC_UNKNOWN,
"$LOGIC");
args[0]);
}
if (0 != strcmp (args[0],
kwh->section_name))
{
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MALFORMED,
"$PROVIDER_SECTION");
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Calling KYC provider specific webhook\n");
@ -709,6 +730,7 @@ handler_kyc_proof_get (
struct TALER_KYCLOGIC_ProviderDetails *pd;
struct TALER_KYCLOGIC_Plugin *logic;
struct ProofRequestState *rs;
const char *section_name;
if ( (NULL == args[0]) ||
(NULL == args[1]) )
@ -743,13 +765,14 @@ handler_kyc_proof_get (
}
if (GNUNET_OK !=
TALER_KYCLOGIC_kyc_get_logic (args[1],
&logic,
&pd))
TALER_KYCLOGIC_lookup_logic (args[1],
&logic,
&pd,
&section_name))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Could not initiate KYC with provider `%s' (configuration error?)\n",
initiate_section);
args[1]);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_NOT_FOUND,
TALER_EC_EXCHANGE_KYC_GENERIC_LOGIC_UNKNOWN,
@ -1366,18 +1389,31 @@ run (void *cls,
return;
}
global_ret = EXIT_SUCCESS;
if (NULL != initiate_section)
if (NULL != requirements)
{
struct TALER_KYCLOGIC_ProviderDetails *pd;
enum TALER_KYCLOGIC_KycUserType ut;
if (GNUNET_OK !=
TALER_KYCLOGIC_kyc_get_logic (initiate_section,
&ih_logic,
&pd))
TALER_KYCLOGIC_kyc_user_type_from_string (ut_s,
&ut))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Could not initiate KYC with provider `%s' (configuration error?)\n",
initiate_section);
"Invalid user type specified ('-i')\n");
global_ret = EXIT_INVALIDARGUMENT;
GNUNET_SCHEDULER_shutdown ();
return;
}
if (GNUNET_OK !=
TALER_KYCLOGIC_requirements_to_logic (requirements,
ut,
&ih_logic,
&pd,
&provider_section_name))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Could not initiate KYC for requirements `%s' (configuration error?)\n",
requirements);
global_ret = EXIT_NOTCONFIGURED;
GNUNET_SCHEDULER_shutdown ();
return;
@ -1473,12 +1509,18 @@ main (int argc,
"run-webservice",
"run the integrated HTTP service",
&run_webservice),
GNUNET_GETOPT_option_string (
'R',
"requirements",
"CHECKS",
"initiate KYC check for the given list of (space-separated) checks",
&requirements),
GNUNET_GETOPT_option_string (
'i',
"initiate",
"SECTION_NAME",
"initiate KYC check using provider configured in SECTION_NAME of the configuration",
&initiate_section),
"identify",
"USERTYPE",
"self-identify as USERTYPE 'business' or 'individual' (defaults to 'individual')",
&requirements),
GNUNET_GETOPT_option_string (
'u',
"user",

View File

@ -207,8 +207,12 @@ handle_reserve_batch_withdraw_finished (
case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
{
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_uint64 ("legitimization_uuid",
&wr.details.accepted.legitimization_uuid),
GNUNET_JSON_spec_fixed_auto (
"h_payto",
&wr.details.unavailable_for_legal_reasons.h_payto),
GNUNET_JSON_spec_uint64 (
"requirement_row",
&wr.details.unavailable_for_legal_reasons.requirement_row),
GNUNET_JSON_spec_end ()
};

View File

@ -181,8 +181,8 @@ handle_deposit_wtid_finished (void *cls,
GNUNET_JSON_spec_timestamp ("execution_time",
&dr.details.accepted.execution_time),
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_uint64 ("legitimization_uuid",
&dr.details.accepted.legitimization_uuid),
GNUNET_JSON_spec_uint64 ("requirement_row",
&dr.details.accepted.requirement_row),
&no_legi),
GNUNET_JSON_spec_bool ("kyc_ok",
&dr.details.accepted.kyc_ok),
@ -200,7 +200,7 @@ handle_deposit_wtid_finished (void *cls,
break;
}
if (no_legi)
dr.details.accepted.legitimization_uuid = 0;
dr.details.accepted.requirement_row = 0;
dwh->cb (dwh->cb_cls,
&dr);
TALER_EXCHANGE_deposits_get_cancel (dwh);

View File

@ -98,11 +98,11 @@ handle_kyc_check_finished (void *cls,
{
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("exchange_sig",
&ks.details.kyc_ok.exchange_sig),
&ks.details.success.exchange_sig),
GNUNET_JSON_spec_fixed_auto ("exchange_pub",
&ks.details.kyc_ok.exchange_pub),
&ks.details.success.exchange_pub),
GNUNET_JSON_spec_timestamp ("now",
&ks.details.kyc_ok.timestamp),
&ks.details.success.timestamp),
GNUNET_JSON_spec_end ()
};
const struct TALER_EXCHANGE_Keys *key_state;
@ -120,7 +120,7 @@ handle_kyc_check_finished (void *cls,
key_state = TALER_EXCHANGE_get_keys (kch->exchange);
if (GNUNET_OK !=
TALER_EXCHANGE_test_signing_key (key_state,
&ks.details.kyc_ok.exchange_pub))
&ks.details.success.exchange_pub))
{
GNUNET_break_op (0);
ks.http_status = 0;
@ -132,9 +132,9 @@ handle_kyc_check_finished (void *cls,
if (GNUNET_OK !=
TALER_exchange_online_account_setup_success_verify (
&kch->h_payto,
ks.details.kyc_ok.timestamp,
&ks.details.kyc_ok.exchange_pub,
&ks.details.kyc_ok.exchange_sig))
ks.details.success.timestamp,
&ks.details.success.exchange_pub,
&ks.details.success.exchange_sig))
{
GNUNET_break_op (0);
ks.http_status = 0;
@ -152,7 +152,7 @@ handle_kyc_check_finished (void *cls,
{
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_string ("kyc_url",
&ks.details.kyc_url),
&ks.details.accepted.kyc_url),
GNUNET_JSON_spec_end ()
};
@ -208,7 +208,7 @@ handle_kyc_check_finished (void *cls,
struct TALER_EXCHANGE_KycCheckHandle *
TALER_EXCHANGE_kyc_check (struct TALER_EXCHANGE_Handle *exchange,
uint64_t legitimization_uuid,
uint64_t requirement_row,
const struct TALER_PaytoHashP *h_payto,
enum TALER_KYCLOGIC_KycUserType ut,
struct GNUNET_TIME_Relative timeout,
@ -241,7 +241,7 @@ TALER_EXCHANGE_kyc_check (struct TALER_EXCHANGE_Handle *exchange,
/ GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us;
GNUNET_asprintf (&arg_str,
"/kyc-check/%llu/%s/%s?timeout_ms=%llu",
(unsigned long long) legitimization_uuid,
(unsigned long long) requirement_row,
payto_str,
TALER_KYCLOGIC_kyc_user_type2s (ut),
timeout_ms);

View File

@ -95,11 +95,28 @@ handle_kyc_wallet_finished (void *cls,
case 0:
ks.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
case MHD_HTTP_OK:
case MHD_HTTP_NO_CONTENT:
break;
case MHD_HTTP_BAD_REQUEST:
ks.ec = TALER_JSON_get_error_code (j);
/* This should never happen, either us or the exchange is buggy
(or API version conflict); just pass JSON reply to the application */
break;
case MHD_HTTP_FORBIDDEN:
ks.ec = TALER_JSON_get_error_code (j);
break;
case MHD_HTTP_NOT_FOUND:
ks.ec = TALER_JSON_get_error_code (j);
break;
case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
{
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_uint64 ("legitimization_uuid",
&ks.legitimization_uuid),
GNUNET_JSON_spec_fixed_auto (
"h_payto",
&ks.details.unavailable_for_legal_reasons.h_payto),
GNUNET_JSON_spec_uint64 (
"requirement_row",
&ks.details.unavailable_for_legal_reasons.requirement_row),
GNUNET_JSON_spec_end ()
};
@ -115,19 +132,6 @@ handle_kyc_wallet_finished (void *cls,
}
break;
}
case MHD_HTTP_NO_CONTENT:
break;
case MHD_HTTP_BAD_REQUEST:
ks.ec = TALER_JSON_get_error_code (j);
/* This should never happen, either us or the exchange is buggy
(or API version conflict); just pass JSON reply to the application */
break;
case MHD_HTTP_FORBIDDEN:
ks.ec = TALER_JSON_get_error_code (j);
break;
case MHD_HTTP_NOT_FOUND:
ks.ec = TALER_JSON_get_error_code (j);
break;
case MHD_HTTP_INTERNAL_SERVER_ERROR:
ks.ec = TALER_JSON_get_error_code (j);
/* Server had an internal issue; we should retry, but this API

View File

@ -298,8 +298,8 @@ handle_purse_create_with_merge_finished (void *cls,
{
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_uint64 (
"legitimization_uuid",
&dr.details.unavailable_for_legal_reasons.legitimization_uuid),
"requirement_row",
&dr.details.unavailable_for_legal_reasons.requirement_row),
GNUNET_JSON_spec_end ()
};

View File

@ -260,8 +260,8 @@ handle_purse_merge_finished (void *cls,
{
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_uint64 (
"legitimization_uuid",
&dr.details.unavailable_for_legal_reasons.legitimization_uuid),
"requirement_row",
&dr.details.unavailable_for_legal_reasons.requirement_row),
GNUNET_JSON_spec_end ()
};

View File

@ -160,9 +160,12 @@ handle_reserve_withdraw_finished (
case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
{
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto (
"h_payto",
&wr.details.unavailable_for_legal_reasons.h_payto),
GNUNET_JSON_spec_uint64 (
"legitimization_uuid",
&wr.details.unavailable_for_legal_reasons.legitimization_uuid),
"requirement_row",
&wr.details.unavailable_for_legal_reasons.requirement_row),
GNUNET_JSON_spec_end ()
};

View File

@ -316,7 +316,7 @@ handle_reserve_withdraw_finished (void *cls,
{
uint64_t ptu;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_uint64 ("legitimization_uuid",
GNUNET_JSON_spec_uint64 ("requirement_row",
&ptu),
GNUNET_JSON_spec_end ()
};

View File

@ -124,8 +124,11 @@ run (void *cls,
"EUR:5",
0, /* age restriction off */
MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS),
TALER_TESTING_cmd_check_kyc_get ("check-kyc-withdraw",
"withdraw-coin-1-lacking-kyc",
MHD_HTTP_ACCEPTED),
TALER_TESTING_cmd_proof_kyc_oauth2 ("proof-kyc",
"create-reserve-1",
"withdraw-coin-1-lacking-kyc",
"kyc-provider-test-oauth2",
"pass",
"state",
@ -202,21 +205,22 @@ run (void *cls,
struct TALER_TESTING_Command wallet_kyc[] = {
TALER_TESTING_cmd_oauth ("start-oauth-service",
6666),
TALER_TESTING_cmd_wallet_kyc_get (
"wallet-kyc-fail",
NULL,
"EUR:1000000",
MHD_HTTP_OK),
TALER_TESTING_cmd_wallet_kyc_get ("wallet-kyc-fail",
NULL,
"EUR:1000000",
MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS),
TALER_TESTING_cmd_check_kyc_get ("check-kyc-wallet",
"wallet-kyc-fail",
MHD_HTTP_ACCEPTED),
TALER_TESTING_cmd_proof_kyc_oauth2 ("proof-wallet-kyc",
"wallet-kyc-fail",
"kyc-provider-test-oauth2",
"pass",
"state",
MHD_HTTP_SEE_OTHER),
TALER_TESTING_cmd_check_kyc_get (
"wallet-kyc-check",
"wallet-kyc-fail",
MHD_HTTP_OK),
TALER_TESTING_cmd_check_kyc_get ("wallet-kyc-check",
"wallet-kyc-fail",
MHD_HTTP_NO_CONTENT),
TALER_TESTING_cmd_end ()
};
@ -300,6 +304,9 @@ run (void *cls,
MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
"push-get-contract",
"p2p_create-reserve-1"),
TALER_TESTING_cmd_check_kyc_get ("check-kyc-purse-merge",
"purse-merge-into-reserve",
MHD_HTTP_ACCEPTED),
TALER_TESTING_cmd_proof_kyc_oauth2 ("p2p_proof-kyc",
"purse-merge-into-reserve",
"kyc-provider-test-oauth2",
@ -338,6 +345,9 @@ run (void *cls,
true /* upload contract */,
GNUNET_TIME_UNIT_MINUTES, /* expiration */
"p2p_create-reserve-3"),
TALER_TESTING_cmd_check_kyc_get ("check-kyc-purse-create",
"purse-create-with-reserve",
MHD_HTTP_ACCEPTED),
TALER_TESTING_cmd_proof_kyc_oauth2 ("p2p_proof-kyc-pull",
"purse-create-with-reserve",
"kyc-provider-test-oauth2",

View File

@ -141,10 +141,16 @@ struct BatchWithdrawState
struct CoinState *coins;
/**
* Set to the KYC UUID *if* the exchange replied with
* Set to the KYC requirement payto hash *if* the exchange replied with a
* request for KYC.
*/
struct TALER_PaytoHashP h_payto;
/**
* Set to the KYC requirement row *if* the exchange replied with
* a request for KYC.
*/
uint64_t kyc_uuid;
uint64_t requirement_row;
/**
* Length of the @e coins array.
@ -213,10 +219,6 @@ reserve_batch_withdraw_cb (void *cls,
cs->exchange_vals = pcd->exchange_vals;
}
break;
case MHD_HTTP_ACCEPTED:
/* nothing to check */
ws->kyc_uuid = wr->details.accepted.legitimization_uuid;
break;
case MHD_HTTP_FORBIDDEN:
/* nothing to check */
break;
@ -229,6 +231,13 @@ reserve_batch_withdraw_cb (void *cls,
case MHD_HTTP_GONE:
/* theoretically could check that the key was actually */
break;
case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
/* nothing to check */
ws->requirement_row
= wr->details.unavailable_for_legal_reasons.requirement_row;
ws->h_payto
= wr->details.unavailable_for_legal_reasons.h_payto;
break;
default:
/* Unsupported status code (by test harness) */
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
@ -417,7 +426,9 @@ batch_withdraw_traits (void *cls,
TALER_TESTING_make_trait_reserve_pub (&ws->reserve_pub),
TALER_TESTING_make_trait_amounts (index,
&cs->amount),
TALER_TESTING_make_trait_legitimization_uuid (&ws->kyc_uuid),
TALER_TESTING_make_trait_legi_requirement_row (&ws->requirement_row),
TALER_TESTING_make_trait_h_payto (
&ws->h_payto),
TALER_TESTING_make_trait_payto_uri (
(const char **) &ws->reserve_payto_uri),
TALER_TESTING_make_trait_exchange_url (

View File

@ -50,10 +50,18 @@ struct TrackTransactionState
unsigned int expected_response_code;
/**
* Set to the KYC UUID *if* the exchange replied with
* Set to the KYC requirement payto hash *if* the exchange replied with a
* request for KYC (#MHD_HTTP_ACCEPTED).
* Note: set based on our @e merchant_payto_uri, as
* the exchange does not respond with the payto hash.
*/
struct TALER_PaytoHashP h_payto;
/**
* Set to the KYC requirement row *if* the exchange replied with
* a request for KYC (#MHD_HTTP_ACCEPTED).
*/
uint64_t kyc_uuid;
uint64_t requirement_row;
/**
* Reference to any operation that can provide a transaction.
@ -158,7 +166,10 @@ deposit_wtid_cb (void *cls,
break;
case MHD_HTTP_ACCEPTED:
/* allowed, nothing to check here */
tts->kyc_uuid = dr->details.accepted.legitimization_uuid;
TALER_payto_hash (tts->merchant_payto_uri,
&tts->h_payto);
tts->requirement_row
= dr->details.accepted.requirement_row;
break;
case MHD_HTTP_NOT_FOUND:
/* allowed, nothing to check here */
@ -321,7 +332,10 @@ track_transaction_traits (void *cls,
struct TrackTransactionState *tts = cls;
struct TALER_TESTING_Trait traits[] = {
TALER_TESTING_make_trait_wtid (&tts->wtid),
TALER_TESTING_make_trait_legitimization_uuid (&tts->kyc_uuid),
TALER_TESTING_make_trait_legi_requirement_row (
&tts->requirement_row),
TALER_TESTING_make_trait_h_payto (
&tts->h_payto),
TALER_TESTING_make_trait_payto_uri (
(const char **) &tts->merchant_payto_uri),
TALER_TESTING_trait_end ()

View File

@ -93,7 +93,7 @@ check_kyc_cb (void *cls,
case MHD_HTTP_OK:
break;
case MHD_HTTP_ACCEPTED:
kcg->kyc_url = GNUNET_strdup (ks->details.kyc_url);
kcg->kyc_url = GNUNET_strdup (ks->details.accepted.kyc_url);
break;
case MHD_HTTP_NO_CONTENT:
break;
@ -119,9 +119,8 @@ check_kyc_run (void *cls,
{
struct KycCheckGetState *kcg = cls;
const struct TALER_TESTING_Command *res_cmd;
const char **payto_uri;
const uint64_t *payment_target;
struct TALER_PaytoHashP h_payto;
const uint64_t *requirement_row;
const struct TALER_PaytoHashP *h_payto;
(void) cmd;
kcg->is = is;
@ -135,36 +134,30 @@ check_kyc_run (void *cls,
return;
}
if (GNUNET_OK !=
TALER_TESTING_get_trait_payto_uri (res_cmd,
&payto_uri))
TALER_TESTING_get_trait_legi_requirement_row (res_cmd,
&requirement_row))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (kcg->is);
return;
}
if (GNUNET_OK !=
TALER_TESTING_get_trait_legitimization_uuid (res_cmd,
&payment_target))
TALER_TESTING_get_trait_h_payto (res_cmd,
&h_payto))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (kcg->is);
return;
}
if ( (NULL == *payto_uri) ||
(0 == *payment_target) )
if (0 == *requirement_row)
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (kcg->is);
return;
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Running KYC check for payto URI: %s\n",
*payto_uri);
TALER_payto_hash (*payto_uri,
&h_payto);
kcg->kwh = TALER_EXCHANGE_kyc_check (is->exchange,
*payment_target,
&h_payto,
*requirement_row,
h_payto,
TALER_KYCLOGIC_KYC_UT_INDIVIDUAL,
GNUNET_TIME_UNIT_SECONDS,
&check_kyc_cb,

View File

@ -136,8 +136,7 @@ proof_kyc_run (void *cls,
{
struct KycProofGetState *kps = cls;
const struct TALER_TESTING_Command *res_cmd;
const char **payto_uri;
struct TALER_PaytoHashP h_payto;
const struct TALER_PaytoHashP *h_payto;
char *uargs;
(void) cmd;
@ -152,35 +151,19 @@ proof_kyc_run (void *cls,
return;
}
if (GNUNET_OK !=
TALER_TESTING_get_trait_payto_uri (res_cmd,
&payto_uri))
TALER_TESTING_get_trait_h_payto (res_cmd,
&h_payto))
{
const struct TALER_PaytoHashP *hpt;
if (GNUNET_OK !=
TALER_TESTING_get_trait_h_payto (res_cmd,
&hpt))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (kps->is);
return;
}
h_payto = *hpt;
}
else
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Triggering KYC proof for %s\n",
*payto_uri);
TALER_payto_hash (*payto_uri,
&h_payto);
GNUNET_break (0);
TALER_TESTING_interpreter_fail (kps->is);
return;
}
GNUNET_asprintf (&uargs,
"?code=%s&state=%s",
kps->code,
kps->state);
kps->kph = TALER_EXCHANGE_kyc_proof (is->exchange,
&h_payto,
h_payto,
kps->logic,
uargs,
&proof_kyc_cb,

View File

@ -59,10 +59,16 @@ struct KycWalletGetState
unsigned int expected_response_code;
/**
* Set to the KYC UUID *if* the exchange replied with
* a request for KYC (#MHD_HTTP_ACCEPTED).
* Set to the KYC requirement payto hash *if* the exchange replied with a
* request for KYC (#MHD_HTTP_OK).
*/
uint64_t kyc_uuid;
struct TALER_PaytoHashP h_payto;
/**
* Set to the KYC requirement row *if* the exchange replied with
* a request for KYC (#MHD_HTTP_OK).
*/
uint64_t requirement_row;
/**
* Handle to the "track transaction" pending operation.
@ -111,15 +117,18 @@ wallet_kyc_cb (void *cls,
}
switch (wkr->http_status)
{
case MHD_HTTP_OK:
kwg->kyc_uuid = wkr->legitimization_uuid;
break;
case MHD_HTTP_NO_CONTENT:
break;
case MHD_HTTP_FORBIDDEN:
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
kwg->requirement_row
= wkr->details.unavailable_for_legal_reasons.requirement_row;
kwg->h_payto
= wkr->details.unavailable_for_legal_reasons.h_payto;
break;
default:
GNUNET_break (0);
break;
@ -232,7 +241,8 @@ wallet_kyc_traits (void *cls,
struct TALER_TESTING_Trait traits[] = {
TALER_TESTING_make_trait_reserve_priv (&kwg->reserve_priv),
TALER_TESTING_make_trait_reserve_pub (&kwg->reserve_pub),
TALER_TESTING_make_trait_legitimization_uuid (&kwg->kyc_uuid),
TALER_TESTING_make_trait_legi_requirement_row (&kwg->requirement_row),
TALER_TESTING_make_trait_h_payto (&kwg->h_payto),
TALER_TESTING_make_trait_payto_uri (
(const char **) &kwg->reserve_payto_uri),
TALER_TESTING_trait_end ()

View File

@ -78,10 +78,10 @@ struct PurseMergeState
struct TALER_PaytoHashP h_payto;
/**
* Set to the KYC UUID *if* the exchange replied with
* Set to the KYC requirement row *if* the exchange replied with
* a request for KYC.
*/
uint64_t kyc_uuid;
uint64_t requirement_row;
/**
* Reserve history entry that corresponds to this operation.
@ -169,8 +169,8 @@ merge_cb (void *cls,
break;
case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
/* KYC required */
ds->kyc_uuid =
dr->details.unavailable_for_legal_reasons.legitimization_uuid;
ds->requirement_row =
dr->details.unavailable_for_legal_reasons.requirement_row;
break;
}
@ -385,7 +385,7 @@ merge_traits (void *cls,
TALER_TESTING_make_trait_reserve_pub (&ds->reserve_pub),
TALER_TESTING_make_trait_timestamp (0,
&ds->merge_timestamp),
TALER_TESTING_make_trait_legitimization_uuid (&ds->kyc_uuid),
TALER_TESTING_make_trait_legi_requirement_row (&ds->requirement_row),
TALER_TESTING_make_trait_h_payto (&ds->h_payto),
TALER_TESTING_trait_end ()
};

View File

@ -104,10 +104,10 @@ struct ReservePurseState
struct TALER_PaytoHashP h_payto;
/**
* Set to the KYC UUID *if* the exchange replied with
* Set to the KYC requirement row *if* the exchange replied with
* a request for KYC.
*/
uint64_t kyc_uuid;
uint64_t requirement_row;
/**
* Contract terms for the purse.
@ -165,8 +165,8 @@ purse_cb (void *cls,
{
case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
/* KYC required */
ds->kyc_uuid =
dr->details.unavailable_for_legal_reasons.legitimization_uuid;
ds->requirement_row =
dr->details.unavailable_for_legal_reasons.requirement_row;
break;
}
TALER_TESTING_interpreter_next (ds->is);
@ -309,7 +309,7 @@ purse_traits (void *cls,
TALER_TESTING_make_trait_reserve_priv (&ds->reserve_priv),
TALER_TESTING_make_trait_reserve_pub (&ds->reserve_pub),
TALER_TESTING_make_trait_reserve_sig (&ds->reserve_sig),
TALER_TESTING_make_trait_legitimization_uuid (&ds->kyc_uuid),
TALER_TESTING_make_trait_legi_requirement_row (&ds->requirement_row),
TALER_TESTING_make_trait_h_payto (&ds->h_payto),
TALER_TESTING_trait_end ()
};

View File

@ -171,10 +171,16 @@ struct WithdrawState
struct GNUNET_TIME_Relative total_backoff;
/**
* Set to the KYC UUID *if* the exchange replied with
* Set to the KYC requirement payto hash *if* the exchange replied with a
* request for KYC.
*/
struct TALER_PaytoHashP h_payto;
/**
* Set to the KYC requirement row *if* the exchange replied with
* a request for KYC.
*/
uint64_t kyc_uuid;
uint64_t requirement_row;
/**
* Expected HTTP response code to the request.
@ -318,8 +324,10 @@ reserve_withdraw_cb (void *cls,
break;
case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
/* KYC required */
ws->kyc_uuid =
wr->details.unavailable_for_legal_reasons.legitimization_uuid;
ws->requirement_row =
wr->details.unavailable_for_legal_reasons.requirement_row;
ws->h_payto
= wr->details.unavailable_for_legal_reasons.h_payto;
break;
default:
/* Unsupported status code (by test harness) */
@ -538,7 +546,9 @@ withdraw_traits (void *cls,
TALER_TESTING_make_trait_reserve_priv (&ws->reserve_priv),
TALER_TESTING_make_trait_reserve_pub (&ws->reserve_pub),
TALER_TESTING_make_trait_amount (&ws->amount),
TALER_TESTING_make_trait_legitimization_uuid (&ws->kyc_uuid),
TALER_TESTING_make_trait_legi_requirement_row (&ws->requirement_row),
TALER_TESTING_make_trait_h_payto (
&ws->h_payto),
TALER_TESTING_make_trait_payto_uri (
(const char **) &ws->reserve_payto_uri),
TALER_TESTING_make_trait_exchange_url (