-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. NAME = Merchant Inc.
[exchange-account-1] [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_debit = yes
enable_credit = yes enable_credit = yes
@ -19,7 +19,7 @@ HONOR_default = YES
ACTIVE_default = YES ACTIVE_default = YES
[merchant-exchange-default] [merchant-exchange-default]
MASTER_KEY = 3NVBGMW8SVMKA4BSBCX9HZ23V7KBXR0ZZ02JWVXBCRH6RNYSM57G MASTER_KEY = RKNMPRGXCX35H11WEYXDXYHPR7NX2QK9BG15MT0QEF75PC5KR470
EXCHANGE_BASE_URL = http://localhost:8081/ EXCHANGE_BASE_URL = http://localhost:8081/
CURRENCY = TESTKUDOS CURRENCY = TESTKUDOS
@ -155,7 +155,7 @@ UNIXPATH = ${TALER_RUNTIME_DIR}/merchant.http
CONFIG = postgres:///auditor-basedb CONFIG = postgres:///auditor-basedb
[exchange] [exchange]
MASTER_PUBLIC_KEY = 3NVBGMW8SVMKA4BSBCX9HZ23V7KBXR0ZZ02JWVXBCRH6RNYSM57G MASTER_PUBLIC_KEY = RKNMPRGXCX35H11WEYXDXYHPR7NX2QK9BG15MT0QEF75PC5KR470
SIGNKEY_DURATION = 4 weeks SIGNKEY_DURATION = 4 weeks
LOOKAHEAD_SIGN = 32 weeks 1 day LOOKAHEAD_SIGN = 32 weeks 1 day
SIGNKEY_LEGAL_DURATION = 4 weeks SIGNKEY_LEGAL_DURATION = 4 weeks
@ -177,7 +177,7 @@ CONFIG = postgres:///auditor-basedb
[auditor] [auditor]
BASE_URL = http://localhost:8083/ BASE_URL = http://localhost:8083/
TINY_AMOUNT = TESTKUDOS:0.01 TINY_AMOUNT = TESTKUDOS:0.01
PUBLIC_KEY = 8X7G2HSYZXK7HW18Y24GF2TTV5QTN1DPET4TG8KR65P54990EAMG PUBLIC_KEY = 0EHPW5WEKHXPPN4MPJNGA7Z6D29JP21GKVNV8ARFB1YW7WWJX20G
[PATHS] [PATHS]
TALER_CACHE_HOME = $TALER_HOME/.cache/taler/ 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; 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 * Set to #GNUNET_OK during transient checking
* while everything is OK. Otherwise see return * 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. * 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 * @return true if KYC checks are satisfied
*/ */
static bool static bool
kyc_satisfied (const struct AggregationUnit *au_active) kyc_satisfied (struct AggregationUnit *au_active)
{ {
const char *requirement; const char *requirement;
uint64_t legi_row;
enum GNUNET_DB_QueryStatus qs; enum GNUNET_DB_QueryStatus qs;
requirement = TALER_KYCLOGIC_kyc_test_required ( requirement = TALER_KYCLOGIC_kyc_test_required (
@ -496,7 +501,7 @@ kyc_satisfied (const struct AggregationUnit *au_active)
db_plugin->cls, db_plugin->cls,
requirement, requirement,
&au_active->h_payto, &au_active->h_payto,
&legi_row); &au_active->requirement_row);
if (qs < 0) if (qs < 0)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@ -506,8 +511,8 @@ kyc_satisfied (const struct AggregationUnit *au_active)
else else
{ {
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"New legitimization process %llu started\n", "Legitimization process %llu started\n",
(unsigned long long) legi_row); (unsigned long long) au_active->requirement_row);
} }
return false; return false;
} }
@ -649,6 +654,7 @@ do_aggregate (struct AggregationUnit *au)
qs = db_plugin->update_aggregation_transient (db_plugin->cls, qs = db_plugin->update_aggregation_transient (db_plugin->cls,
&au->h_payto, &au->h_payto,
&au->wtid, &au->wtid,
au->requirement_row,
&au->total_amount); &au->total_amount);
else else
qs = db_plugin->create_aggregation_transient (db_plugin->cls, qs = db_plugin->create_aggregation_transient (db_plugin->cls,
@ -656,6 +662,7 @@ do_aggregate (struct AggregationUnit *au)
au->wa->section_name, au->wa->section_name,
&au->merchant_pub, &au->merchant_pub,
&au->wtid, &au->wtid,
au->requirement_row,
&au->total_amount); &au->total_amount);
if (GNUNET_DB_STATUS_SOFT_ERROR == qs) if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
{ {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -979,13 +979,16 @@ TEH_RESPONSE_reply_purse_created (
MHD_RESULT MHD_RESULT
TEH_RESPONSE_reply_kyc_required (struct MHD_Connection *connection, TEH_RESPONSE_reply_kyc_required (struct MHD_Connection *connection,
const struct TALER_PaytoHashP *h_payto,
const struct TALER_EXCHANGEDB_KycStatus *kyc) const struct TALER_EXCHANGEDB_KycStatus *kyc)
{ {
return TALER_MHD_REPLY_JSON_PACK ( return TALER_MHD_REPLY_JSON_PACK (
connection, connection,
MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS, MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
GNUNET_JSON_pack_uint64 ("legitimization_uuid", GNUNET_JSON_pack_data_auto ("h_payto",
kyc->legitimization_uuid)); 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. * satisfied to proceed to client.
* *
* @param connection connection to the client * @param connection connection to the client
* @param h_payto account identifier to include in reply
* @param kyc details about the KYC requirements * @param kyc details about the KYC requirements
* @return MHD result code * @return MHD result code
*/ */
MHD_RESULT MHD_RESULT
TEH_RESPONSE_reply_kyc_required (struct MHD_Connection *connection, TEH_RESPONSE_reply_kyc_required (struct MHD_Connection *connection,
const struct TALER_PaytoHashP *h_payto,
const struct TALER_EXCHANGEDB_KycStatus *kyc); const struct TALER_EXCHANGEDB_KycStatus *kyc);

View File

@ -179,7 +179,7 @@ withdraw_transaction (void *cls,
TEH_plugin->cls, TEH_plugin->cls,
kyc_required, kyc_required,
&wc->h_payto, &wc->h_payto,
&wc->kyc.legitimization_uuid); &wc->kyc.requirement_row);
} }
} }
wc->kyc.ok = true; wc->kyc.ok = true;
@ -489,6 +489,7 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
if (! wc.kyc.ok) if (! wc.kyc.ok)
return TEH_RESPONSE_reply_kyc_required (rc->connection, return TEH_RESPONSE_reply_kyc_required (rc->connection,
&wc.h_payto,
&wc.kyc); &wc.kyc);
{ {
MHD_RESULT ret; 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 IN shard_suffix VARCHAR DEFAULT NULL
) )
RETURNS VOID RETURNS VOID
@ -96,7 +96,7 @@ BEGIN
PERFORM create_partitioned_table( PERFORM create_partitioned_table(
'CREATE TABLE IF NOT EXISTS %I' '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)' ',h_payto BYTEA NOT NULL CHECK (LENGTH(h_payto)=32)'
',expiration_time INT8 NOT NULL DEFAULT (0)' ',expiration_time INT8 NOT NULL DEFAULT (0)'
',provider_section VARCHAR NOT NULL' ',provider_section VARCHAR NOT NULL'
@ -104,7 +104,7 @@ BEGIN
',provider_legitimization_id VARCHAR DEFAULT NULL' ',provider_legitimization_id VARCHAR DEFAULT NULL'
',UNIQUE (h_payto, provider_section)' ',UNIQUE (h_payto, provider_section)'
') %s ;' ') %s ;'
,'legitimizations' ,'legitimization_processes'
,'PARTITION BY HASH (h_payto)' ,'PARTITION BY HASH (h_payto)'
,shard_suffix ,shard_suffix
); );
@ -114,7 +114,7 @@ $$;
-- We need a separate function for this, as we call create_table only once but need to add -- 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 -- 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 IN partition_suffix VARCHAR
) )
RETURNS void RETURNS void
@ -124,13 +124,13 @@ DECLARE
partition_name VARCHAR; partition_name VARCHAR;
BEGIN BEGIN
partition_name = concat_ws('_', 'legitimizations', partition_suffix); partition_name = concat_ws('_', 'legitimization_processes', partition_suffix);
EXECUTE FORMAT ( EXECUTE FORMAT (
'ALTER TABLE ' || partition_name 'ALTER TABLE ' || partition_name
|| ' ' || ' '
'ADD CONSTRAINT ' || partition_name || '_legitimization_serial_id_key ' 'ADD CONSTRAINT ' || partition_name || '_serial_key '
'UNIQUE (legitimization_serial_id)'); 'UNIQUE (legitimization_process_serial_id)');
EXECUTE FORMAT ( EXECUTE FORMAT (
'CREATE INDEX IF NOT EXISTS ' || partition_name || '_by_provider_and_legi_index ' 'CREATE INDEX IF NOT EXISTS ' || partition_name || '_by_provider_and_legi_index '
'ON '|| partition_name || ' ' 'ON '|| partition_name || ' '
@ -143,6 +143,55 @@ BEGIN
END 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 ------------------------------- ------------------------ reserves -------------------------------
CREATE OR REPLACE FUNCTION create_table_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)' ',wire_target_h_payto BYTEA CHECK (LENGTH(wire_target_h_payto)=32)'
',merchant_pub BYTEA CHECK (LENGTH(merchant_pub)=32)' ',merchant_pub BYTEA CHECK (LENGTH(merchant_pub)=32)'
',exchange_account_section TEXT NOT NULL' ',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)' ',wtid_raw BYTEA NOT NULL CHECK (LENGTH(wtid_raw)=32)'
') %s ;' ') %s ;'
,table_name ,table_name

View File

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

View File

@ -31,6 +31,13 @@ BEGIN
PERFORM create_table_reserves(shard_suffix); 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 create_table_reserves_in(shard_suffix);
PERFORM add_constraints_to_reserves_in_partition(shard_suffix); PERFORM add_constraints_to_reserves_in_partition(shard_suffix);

View File

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

View File

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

View File

@ -2273,15 +2273,14 @@ struct TALER_EXCHANGEDB_CsRevealFreshCoinData
/** /**
* Generic KYC status for some operation. * Generic KYC status for some operation.
* @deprecated FIXME - remove with new KYC logic
*/ */
struct TALER_EXCHANGEDB_KycStatus struct TALER_EXCHANGEDB_KycStatus
{ {
/** /**
* Number that identifies the KYC target the operation * Number that identifies the KYC requirement the operation
* was about. * was about.
*/ */
uint64_t legitimization_uuid; uint64_t requirement_row;
/** /**
* True if the KYC status is "satisfied". * True if the KYC status is "satisfied".
@ -3667,6 +3666,7 @@ struct TALER_EXCHANGEDB_Plugin
* @param exchange_account_section exchange account to use * @param exchange_account_section exchange account to use
* @param merchant_pub public key of the merchant * @param merchant_pub public key of the merchant
* @param wtid the raw wire transfer identifier to be used * @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 * @param total amount to be wired in the future
* @return transaction status * @return transaction status
*/ */
@ -3677,6 +3677,7 @@ struct TALER_EXCHANGEDB_Plugin
const char *exchange_account_section, const char *exchange_account_section,
const struct TALER_MerchantPublicKeyP *merchant_pub, const struct TALER_MerchantPublicKeyP *merchant_pub,
const struct TALER_WireTransferIdentifierRawP *wtid, const struct TALER_WireTransferIdentifierRawP *wtid,
uint64_t kyc_requirement_row,
const struct TALER_Amount *total); 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 cls the @e cls of this struct with the plugin-specific state
* @param h_payto destination of the wire transfer * @param h_payto destination of the wire transfer
* @param wtid the raw wire transfer identifier to update * @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 * @param total new total amount to be wired in the future
* @return transaction status * @return transaction status
*/ */
@ -3733,6 +3735,7 @@ struct TALER_EXCHANGEDB_Plugin
void *cls, void *cls,
const struct TALER_PaytoHashP *h_payto, const struct TALER_PaytoHashP *h_payto,
const struct TALER_WireTransferIdentifierRawP *wtid, const struct TALER_WireTransferIdentifierRawP *wtid,
uint64_t kyc_requirement_row,
const struct TALER_Amount *total); const struct TALER_Amount *total);
@ -5583,36 +5586,57 @@ struct TALER_EXCHANGEDB_Plugin
* Insert KYC requirement for @a h_payto account into table. * Insert KYC requirement for @a h_payto account into table.
* *
* @param cls closure * @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 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 * @return database transaction status
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
(*insert_kyc_requirement_for_account)( (*insert_kyc_requirement_for_account)(
void *cls, void *cls,
const char *provider_section, const char *requirements,
const struct TALER_PaytoHashP *h_payto, 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. * expiration data.
* *
* @param cls closure * @param cls closure
* @param legi_row row to select by * @param process_row row to select by
* @param provider_section provider that must be checked * @param provider_section provider that must be checked (technically redundant)
* @param h_payto account that must be KYC'ed * @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_account_id provider account ID
* @param provider_legitimization_id provider legitimization 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) * @param expiration how long is this KYC check set to be valid (in the past if invalid)
* @return database transaction status * @return database transaction status
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
(*update_kyc_requirement_by_row)( (*update_kyc_process_by_row)(
void *cls, void *cls,
uint64_t legi_row, uint64_t process_row,
const char *provider_section, const char *provider_section,
const struct TALER_PaytoHashP *h_payto, const struct TALER_PaytoHashP *h_payto,
const char *provider_account_id, 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 cls closure
* @param legi_row legitimization row to lookup * @param legi_row identifies requirement to look up
* @param[out] provider_section provider that must be checked * @param[out] requirements space-separated list of requirements
* @param[out] h_payto account that must be KYC'ed * @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 * @return database transaction status
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
(*lookup_kyc_requirement_by_row)( (*lookup_kyc_requirement_by_row)(
void *cls, void *cls,
uint64_t legi_row, uint64_t requirement_row,
char **provider_section, char **requirements,
struct TALER_PaytoHashP *h_payto, struct TALER_PaytoHashP *h_payto);
struct GNUNET_TIME_Absolute *expiration,
char **provider_account_id,
char **provider_legitimization_id);
/** /**
* Lookup KYC provider meta data. * Lookup KYC process meta data.
* *
* @param cls closure * @param cls closure
* @param provider_section provider that must be checked * @param provider_section provider that must be checked
* @param h_payto account that must be KYC'ed * @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] 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_account_id provider account ID
* @param[out] provider_legitimization_id provider legitimization ID * @param[out] provider_legitimization_id provider legitimization ID
* @return database transaction status * @return database transaction status
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
(*lookup_kyc_requirement_by_account)( (*lookup_kyc_process_by_account)(
void *cls, void *cls,
const char *provider_section, const char *provider_section,
const struct TALER_PaytoHashP *h_payto, const struct TALER_PaytoHashP *h_payto,
uint64_t *legi_row, uint64_t *process_row,
struct GNUNET_TIME_Absolute *expiration, struct GNUNET_TIME_Absolute *expiration,
char **provider_account_id, char **provider_account_id,
char **provider_legitimization_id); char **provider_legitimization_id);
@ -5674,7 +5692,7 @@ struct TALER_EXCHANGEDB_Plugin
* @param provider_section * @param provider_section
* @param provider_legitimization_id legi to look up * @param provider_legitimization_id legi to look up
* @param[out] h_payto where to write the result * @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 * @return database transaction status
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
@ -5683,7 +5701,7 @@ struct TALER_EXCHANGEDB_Plugin
const char *provider_section, const char *provider_section,
const char *provider_legitimization_id, const char *provider_legitimization_id,
struct TALER_PaytoHashP *h_payto, 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 * Check if KYC is provided for a particular operation. Returns the set of checks that still need to be satisfied.
* provider (configuration section name) that could perform the required
* check.
* *
* Called within a database transaction, so must * Called within a database transaction, so must
* not start a new one. * not start a new one.
@ -211,7 +209,8 @@ typedef enum GNUNET_DB_QueryStatus
* amounts involved in this type of operation * amounts involved in this type of operation
* at the given account * at the given account
* @param ai_cls closure for @a ai * @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 * const char *
TALER_KYCLOGIC_kyc_test_required (enum TALER_KYCLOGIC_KycTriggerEvent event, 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); 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 * Iterate over all thresholds that are applicable
* to a particular type of @a event * 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] plugin set to the KYC logic API
* @param[out] pd set to the specific operation context * @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 * @return #GNUNET_OK on success
*/ */
enum GNUNET_GenericReturnValue enum GNUNET_GenericReturnValue
TALER_KYCLOGIC_kyc_get_logic (const char *provider_section_name, TALER_KYCLOGIC_lookup_logic (const char *name,
struct TALER_KYCLOGIC_Plugin **plugin, struct TALER_KYCLOGIC_Plugin **plugin,
struct TALER_KYCLOGIC_ProviderDetails **pd); struct TALER_KYCLOGIC_ProviderDetails **pd,
const char **configuration_section);
#endif #endif

View File

@ -180,8 +180,9 @@ typedef void
* MUST NOT be done by the plugin! * MUST NOT be done by the plugin!
* *
* @param cls closure * @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 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_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 provider_legitimization_id set to legitimization process ID at the provider, or NULL if not supported or unknown
* @param status KYC status * @param status KYC status
@ -192,8 +193,9 @@ typedef void
typedef void typedef void
(*TALER_KYCLOGIC_WebhookCallback)( (*TALER_KYCLOGIC_WebhookCallback)(
void *cls, void *cls,
uint64_t legi_row, uint64_t process_row,
const struct TALER_PaytoHashP *account_id, const struct TALER_PaytoHashP *account_id,
const char *provider_section,
const char *provider_user_id, const char *provider_user_id,
const char *provider_legitimization_id, const char *provider_legitimization_id,
enum TALER_KYCLOGIC_KycStatus status, enum TALER_KYCLOGIC_KycStatus status,
@ -203,16 +205,15 @@ typedef void
/** /**
* Function the plugin can use to lookup an * Function the plugin can use to lookup an @a h_payto by @a
* @a h_payto by @a provider_legitimization_id. * provider_legitimization_id. Must match the `kyc_provider_account_lookup`
* Must match the `kyc_provider_account_lookup`
* of the exchange's database plugin. * of the exchange's database plugin.
* *
* @param cls closure * @param cls closure
* @param provider_section * @param provider_section
* @param provider_legitimization_id legi to look up * @param provider_legitimization_id legi to look up
* @param[out] h_payto where to write the result * @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 * @return database transaction status
*/ */
typedef enum GNUNET_DB_QueryStatus typedef enum GNUNET_DB_QueryStatus
@ -221,7 +222,7 @@ typedef enum GNUNET_DB_QueryStatus
const char *provider_section, const char *provider_section,
const char *provider_legitimization_id, const char *provider_legitimization_id,
struct TALER_PaytoHashP *h_payto, 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 cls the @e cls of this struct with the plugin-specific state
* @param pd provider configuration details * @param pd provider configuration details
* @param account_id which account to trigger process for * @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 function to call with the result
* @param cb_cls closure for @a cb * @param cb_cls closure for @a cb
* @return handle to cancel operation early * @return handle to cancel operation early
@ -283,7 +284,7 @@ struct TALER_KYCLOGIC_Plugin
(*initiate)(void *cls, (*initiate)(void *cls,
const struct TALER_KYCLOGIC_ProviderDetails *pd, const struct TALER_KYCLOGIC_ProviderDetails *pd,
const struct TALER_PaytoHashP *account_id, const struct TALER_PaytoHashP *account_id,
uint64_t legitimization_uuid, uint64_t process_row,
TALER_KYCLOGIC_InitiateCallback cb, TALER_KYCLOGIC_InitiateCallback cb,
void *cb_cls); 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 url_path rest of the URL after `/kyc-webhook/$H_PAYTO/$LOGIC`
* @param connection MHD connection object (for HTTP headers) * @param connection MHD connection object (for HTTP headers)
* @param account_id which account to trigger process for * @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_user_id user ID (or NULL) the proof is for
* @param provider_legitimization_id legitimization ID the proof is for * @param provider_legitimization_id legitimization ID the proof is for
* @param cb function to call with the result * @param cb function to call with the result
@ -318,7 +319,7 @@ struct TALER_KYCLOGIC_Plugin
const char *const url_path[], const char *const url_path[],
struct MHD_Connection *connection, struct MHD_Connection *connection,
const struct TALER_PaytoHashP *account_id, const struct TALER_PaytoHashP *account_id,
uint64_t legi_row, uint64_t process_row,
const char *provider_user_id, const char *provider_user_id,
const char *provider_legitimization_id, const char *provider_legitimization_id,
TALER_KYCLOGIC_ProofCallback cb, 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 (kyc_url, const char *) \
op (web_url, const char *) \ op (web_url, const char *) \
op (row, const uint64_t) \ 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 (array_length, const unsigned int) \
op (credit_payto_uri, const char *) \ op (credit_payto_uri, const char *) \
op (debit_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]; struct TALER_KYCLOGIC_KycCheck *needed[num_kyc_checks];
unsigned int needed_cnt = 0; unsigned int needed_cnt = 0;
char *ret;
struct GNUNET_TIME_Relative timeframe; 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; timeframe = GNUNET_TIME_UNIT_ZERO;
for (unsigned int i = 0; i<num_kyc_triggers; i++) 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) if (0 == needed_cnt)
return NULL; 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]; struct RemoveContext rc = {
unsigned int matched = 0; .needed = needed,
.needed_cnt = &needed_cnt
};
enum GNUNET_DB_QueryStatus qs;
for (unsigned int j = 0; j<kp->num_checks; j++) /* Check what provider checks are already satisfied for h_payto (with
{ database), remove those from the 'needed' array. */
const struct TALER_KYCLOGIC_KycCheck *kc = kp->provided_checks[j]; qs = ki (ki_cls,
h_payto,
for (unsigned int k = 0; k<needed_cnt; k++) &remove_satisfied,
if (kc == needed[k]) &rc);
{ GNUNET_break (qs >= 0); // FIXME: handle DB failure more nicely?
matched++;
break;
}
}
max_checks = GNUNET_MAX (max_checks,
matched);
} }
if (0 == needed_cnt)
/* Find min-cost provider covering max_checks. */ return NULL;
for (unsigned int i = 0; i<num_kyc_providers; i++) ret = NULL;
for (unsigned int k = 0; k<needed_cnt; k++)
{ {
const struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i]; const struct TALER_KYCLOGIC_KycCheck *kc = needed[k];
unsigned int matched = 0;
for (unsigned int j = 0; j<kp->num_checks; j++) if (NULL == ret)
{ {
const struct TALER_KYCLOGIC_KycCheck *kc = kp->provided_checks[j]; ret = GNUNET_strdup (kc->name);
for (unsigned int k = 0; k<needed_cnt; k++)
if (kc == needed[k])
{
matched++;
break;
}
} }
if ( (max_checks == matched) && else /* append */
(kp->cost < min_cost) )
{ {
min_cost = kp->cost; char *tmp = ret;
kp_best = kp;
GNUNET_asprintf (&ret,
"%s %s",
tmp,
kc->name);
GNUNET_free (tmp);
} }
} }
return ret;
GNUNET_assert (NULL != kp_best);
return kp_best->provider_section_name;
} }
@ -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 enum GNUNET_GenericReturnValue
TALER_KYCLOGIC_kyc_get_logic (const char *provider_section_name, TALER_KYCLOGIC_requirements_to_logic (const char *requirements,
struct TALER_KYCLOGIC_Plugin **plugin, enum TALER_KYCLOGIC_KycUserType ut,
struct TALER_KYCLOGIC_ProviderDetails **pd) 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++) for (unsigned int i = 0; i<num_kyc_providers; i++)
{ {
struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i]; struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
if (0 != if (0 !=
strcasecmp (provider_section_name, strcasecmp (name,
kp->provider_section_name)) kp->provider_section_name))
continue; continue;
*plugin = kp->logic; *plugin = kp->logic;
*pd = kp->pd; *pd = kp->pd;
*provider_section = kp->provider_section_name;
return GNUNET_OK; return GNUNET_OK;
} }
for (unsigned int i = 0; i<num_kyc_logics; i++) 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 != if (0 !=
strcasecmp (logic->name, strcasecmp (logic->name,
provider_section_name)) name))
continue; continue;
*plugin = logic; *plugin = logic;
*pd = NULL; *pd = NULL;
*provider_section = NULL;
return GNUNET_OK; return GNUNET_OK;
} }
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Provider `%s' unknown\n", "Provider `%s' unknown\n",
provider_section_name); name);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }

View File

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

View File

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

View File

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

View File

@ -207,8 +207,12 @@ handle_reserve_batch_withdraw_finished (
case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
{ {
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_uint64 ("legitimization_uuid", GNUNET_JSON_spec_fixed_auto (
&wr.details.accepted.legitimization_uuid), "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 () GNUNET_JSON_spec_end ()
}; };

View File

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

View File

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

View File

@ -95,11 +95,28 @@ handle_kyc_wallet_finished (void *cls,
case 0: case 0:
ks.ec = TALER_EC_GENERIC_INVALID_RESPONSE; ks.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break; 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[] = { struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_uint64 ("legitimization_uuid", GNUNET_JSON_spec_fixed_auto (
&ks.legitimization_uuid), "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 () GNUNET_JSON_spec_end ()
}; };
@ -115,19 +132,6 @@ handle_kyc_wallet_finished (void *cls,
} }
break; 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: case MHD_HTTP_INTERNAL_SERVER_ERROR:
ks.ec = TALER_JSON_get_error_code (j); ks.ec = TALER_JSON_get_error_code (j);
/* Server had an internal issue; we should retry, but this API /* 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[] = { struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_uint64 ( GNUNET_JSON_spec_uint64 (
"legitimization_uuid", "requirement_row",
&dr.details.unavailable_for_legal_reasons.legitimization_uuid), &dr.details.unavailable_for_legal_reasons.requirement_row),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
}; };

View File

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

View File

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

View File

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

View File

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

View File

@ -141,10 +141,16 @@ struct BatchWithdrawState
struct CoinState *coins; 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. * a request for KYC.
*/ */
uint64_t kyc_uuid; uint64_t requirement_row;
/** /**
* Length of the @e coins array. * Length of the @e coins array.
@ -213,10 +219,6 @@ reserve_batch_withdraw_cb (void *cls,
cs->exchange_vals = pcd->exchange_vals; cs->exchange_vals = pcd->exchange_vals;
} }
break; break;
case MHD_HTTP_ACCEPTED:
/* nothing to check */
ws->kyc_uuid = wr->details.accepted.legitimization_uuid;
break;
case MHD_HTTP_FORBIDDEN: case MHD_HTTP_FORBIDDEN:
/* nothing to check */ /* nothing to check */
break; break;
@ -229,6 +231,13 @@ reserve_batch_withdraw_cb (void *cls,
case MHD_HTTP_GONE: case MHD_HTTP_GONE:
/* theoretically could check that the key was actually */ /* theoretically could check that the key was actually */
break; 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: default:
/* Unsupported status code (by test harness) */ /* Unsupported status code (by test harness) */
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 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_reserve_pub (&ws->reserve_pub),
TALER_TESTING_make_trait_amounts (index, TALER_TESTING_make_trait_amounts (index,
&cs->amount), &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 ( TALER_TESTING_make_trait_payto_uri (
(const char **) &ws->reserve_payto_uri), (const char **) &ws->reserve_payto_uri),
TALER_TESTING_make_trait_exchange_url ( TALER_TESTING_make_trait_exchange_url (

View File

@ -50,10 +50,18 @@ struct TrackTransactionState
unsigned int expected_response_code; 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). * a request for KYC (#MHD_HTTP_ACCEPTED).
*/ */
uint64_t kyc_uuid; uint64_t requirement_row;
/** /**
* Reference to any operation that can provide a transaction. * Reference to any operation that can provide a transaction.
@ -158,7 +166,10 @@ deposit_wtid_cb (void *cls,
break; break;
case MHD_HTTP_ACCEPTED: case MHD_HTTP_ACCEPTED:
/* allowed, nothing to check here */ /* 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; break;
case MHD_HTTP_NOT_FOUND: case MHD_HTTP_NOT_FOUND:
/* allowed, nothing to check here */ /* allowed, nothing to check here */
@ -321,7 +332,10 @@ track_transaction_traits (void *cls,
struct TrackTransactionState *tts = cls; struct TrackTransactionState *tts = cls;
struct TALER_TESTING_Trait traits[] = { struct TALER_TESTING_Trait traits[] = {
TALER_TESTING_make_trait_wtid (&tts->wtid), 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 ( TALER_TESTING_make_trait_payto_uri (
(const char **) &tts->merchant_payto_uri), (const char **) &tts->merchant_payto_uri),
TALER_TESTING_trait_end () TALER_TESTING_trait_end ()

View File

@ -93,7 +93,7 @@ check_kyc_cb (void *cls,
case MHD_HTTP_OK: case MHD_HTTP_OK:
break; break;
case MHD_HTTP_ACCEPTED: case MHD_HTTP_ACCEPTED:
kcg->kyc_url = GNUNET_strdup (ks->details.kyc_url); kcg->kyc_url = GNUNET_strdup (ks->details.accepted.kyc_url);
break; break;
case MHD_HTTP_NO_CONTENT: case MHD_HTTP_NO_CONTENT:
break; break;
@ -119,9 +119,8 @@ check_kyc_run (void *cls,
{ {
struct KycCheckGetState *kcg = cls; struct KycCheckGetState *kcg = cls;
const struct TALER_TESTING_Command *res_cmd; const struct TALER_TESTING_Command *res_cmd;
const char **payto_uri; const uint64_t *requirement_row;
const uint64_t *payment_target; const struct TALER_PaytoHashP *h_payto;
struct TALER_PaytoHashP h_payto;
(void) cmd; (void) cmd;
kcg->is = is; kcg->is = is;
@ -135,36 +134,30 @@ check_kyc_run (void *cls,
return; return;
} }
if (GNUNET_OK != if (GNUNET_OK !=
TALER_TESTING_get_trait_payto_uri (res_cmd, TALER_TESTING_get_trait_legi_requirement_row (res_cmd,
&payto_uri)) &requirement_row))
{ {
GNUNET_break (0); GNUNET_break (0);
TALER_TESTING_interpreter_fail (kcg->is); TALER_TESTING_interpreter_fail (kcg->is);
return; return;
} }
if (GNUNET_OK != if (GNUNET_OK !=
TALER_TESTING_get_trait_legitimization_uuid (res_cmd, TALER_TESTING_get_trait_h_payto (res_cmd,
&payment_target)) &h_payto))
{ {
GNUNET_break (0); GNUNET_break (0);
TALER_TESTING_interpreter_fail (kcg->is); TALER_TESTING_interpreter_fail (kcg->is);
return; return;
} }
if ( (NULL == *payto_uri) || if (0 == *requirement_row)
(0 == *payment_target) )
{ {
GNUNET_break (0); GNUNET_break (0);
TALER_TESTING_interpreter_fail (kcg->is); TALER_TESTING_interpreter_fail (kcg->is);
return; 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, kcg->kwh = TALER_EXCHANGE_kyc_check (is->exchange,
*payment_target, *requirement_row,
&h_payto, h_payto,
TALER_KYCLOGIC_KYC_UT_INDIVIDUAL, TALER_KYCLOGIC_KYC_UT_INDIVIDUAL,
GNUNET_TIME_UNIT_SECONDS, GNUNET_TIME_UNIT_SECONDS,
&check_kyc_cb, &check_kyc_cb,

View File

@ -136,8 +136,7 @@ proof_kyc_run (void *cls,
{ {
struct KycProofGetState *kps = cls; struct KycProofGetState *kps = cls;
const struct TALER_TESTING_Command *res_cmd; const struct TALER_TESTING_Command *res_cmd;
const char **payto_uri; const struct TALER_PaytoHashP *h_payto;
struct TALER_PaytoHashP h_payto;
char *uargs; char *uargs;
(void) cmd; (void) cmd;
@ -152,35 +151,19 @@ proof_kyc_run (void *cls,
return; return;
} }
if (GNUNET_OK != if (GNUNET_OK !=
TALER_TESTING_get_trait_payto_uri (res_cmd, TALER_TESTING_get_trait_h_payto (res_cmd,
&payto_uri)) &h_payto))
{ {
const struct TALER_PaytoHashP *hpt; GNUNET_break (0);
TALER_TESTING_interpreter_fail (kps->is);
if (GNUNET_OK != return;
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_asprintf (&uargs, GNUNET_asprintf (&uargs,
"?code=%s&state=%s", "?code=%s&state=%s",
kps->code, kps->code,
kps->state); kps->state);
kps->kph = TALER_EXCHANGE_kyc_proof (is->exchange, kps->kph = TALER_EXCHANGE_kyc_proof (is->exchange,
&h_payto, h_payto,
kps->logic, kps->logic,
uargs, uargs,
&proof_kyc_cb, &proof_kyc_cb,

View File

@ -59,10 +59,16 @@ struct KycWalletGetState
unsigned int expected_response_code; 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
* a request for KYC (#MHD_HTTP_ACCEPTED). * 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. * Handle to the "track transaction" pending operation.
@ -111,15 +117,18 @@ wallet_kyc_cb (void *cls,
} }
switch (wkr->http_status) switch (wkr->http_status)
{ {
case MHD_HTTP_OK:
kwg->kyc_uuid = wkr->legitimization_uuid;
break;
case MHD_HTTP_NO_CONTENT: case MHD_HTTP_NO_CONTENT:
break; break;
case MHD_HTTP_FORBIDDEN: case MHD_HTTP_FORBIDDEN:
GNUNET_break (0); GNUNET_break (0);
TALER_TESTING_interpreter_fail (is); TALER_TESTING_interpreter_fail (is);
return; 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: default:
GNUNET_break (0); GNUNET_break (0);
break; break;
@ -232,7 +241,8 @@ wallet_kyc_traits (void *cls,
struct TALER_TESTING_Trait traits[] = { struct TALER_TESTING_Trait traits[] = {
TALER_TESTING_make_trait_reserve_priv (&kwg->reserve_priv), TALER_TESTING_make_trait_reserve_priv (&kwg->reserve_priv),
TALER_TESTING_make_trait_reserve_pub (&kwg->reserve_pub), 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 ( TALER_TESTING_make_trait_payto_uri (
(const char **) &kwg->reserve_payto_uri), (const char **) &kwg->reserve_payto_uri),
TALER_TESTING_trait_end () TALER_TESTING_trait_end ()

View File

@ -78,10 +78,10 @@ struct PurseMergeState
struct TALER_PaytoHashP h_payto; 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. * a request for KYC.
*/ */
uint64_t kyc_uuid; uint64_t requirement_row;
/** /**
* Reserve history entry that corresponds to this operation. * Reserve history entry that corresponds to this operation.
@ -169,8 +169,8 @@ merge_cb (void *cls,
break; break;
case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
/* KYC required */ /* KYC required */
ds->kyc_uuid = ds->requirement_row =
dr->details.unavailable_for_legal_reasons.legitimization_uuid; dr->details.unavailable_for_legal_reasons.requirement_row;
break; break;
} }
@ -385,7 +385,7 @@ merge_traits (void *cls,
TALER_TESTING_make_trait_reserve_pub (&ds->reserve_pub), TALER_TESTING_make_trait_reserve_pub (&ds->reserve_pub),
TALER_TESTING_make_trait_timestamp (0, TALER_TESTING_make_trait_timestamp (0,
&ds->merge_timestamp), &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_make_trait_h_payto (&ds->h_payto),
TALER_TESTING_trait_end () TALER_TESTING_trait_end ()
}; };

View File

@ -104,10 +104,10 @@ struct ReservePurseState
struct TALER_PaytoHashP h_payto; 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. * a request for KYC.
*/ */
uint64_t kyc_uuid; uint64_t requirement_row;
/** /**
* Contract terms for the purse. * Contract terms for the purse.
@ -165,8 +165,8 @@ purse_cb (void *cls,
{ {
case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
/* KYC required */ /* KYC required */
ds->kyc_uuid = ds->requirement_row =
dr->details.unavailable_for_legal_reasons.legitimization_uuid; dr->details.unavailable_for_legal_reasons.requirement_row;
break; break;
} }
TALER_TESTING_interpreter_next (ds->is); 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_priv (&ds->reserve_priv),
TALER_TESTING_make_trait_reserve_pub (&ds->reserve_pub), TALER_TESTING_make_trait_reserve_pub (&ds->reserve_pub),
TALER_TESTING_make_trait_reserve_sig (&ds->reserve_sig), 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_make_trait_h_payto (&ds->h_payto),
TALER_TESTING_trait_end () TALER_TESTING_trait_end ()
}; };

View File

@ -171,10 +171,16 @@ struct WithdrawState
struct GNUNET_TIME_Relative total_backoff; 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. * a request for KYC.
*/ */
uint64_t kyc_uuid; uint64_t requirement_row;
/** /**
* Expected HTTP response code to the request. * Expected HTTP response code to the request.
@ -318,8 +324,10 @@ reserve_withdraw_cb (void *cls,
break; break;
case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
/* KYC required */ /* KYC required */
ws->kyc_uuid = ws->requirement_row =
wr->details.unavailable_for_legal_reasons.legitimization_uuid; wr->details.unavailable_for_legal_reasons.requirement_row;
ws->h_payto
= wr->details.unavailable_for_legal_reasons.h_payto;
break; break;
default: default:
/* Unsupported status code (by test harness) */ /* 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_priv (&ws->reserve_priv),
TALER_TESTING_make_trait_reserve_pub (&ws->reserve_pub), TALER_TESTING_make_trait_reserve_pub (&ws->reserve_pub),
TALER_TESTING_make_trait_amount (&ws->amount), 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 ( TALER_TESTING_make_trait_payto_uri (
(const char **) &ws->reserve_payto_uri), (const char **) &ws->reserve_payto_uri),
TALER_TESTING_make_trait_exchange_url ( TALER_TESTING_make_trait_exchange_url (