return AML status together with KYC status

This commit is contained in:
Christian Grothoff 2023-04-10 10:48:32 +02:00
parent 677ac4a5c8
commit 090c532b3a
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
6 changed files with 104 additions and 6 deletions

View File

@ -112,6 +112,11 @@ struct KycPoller
*/ */
const char *section_name; const char *section_name;
/**
* Set to AML status of the account.
*/
enum TALER_AmlDecisionState aml_status;
/** /**
* Set to error encountered with KYC logic, if any. * Set to error encountered with KYC logic, if any.
*/ */
@ -303,6 +308,7 @@ kyc_check (void *cls,
TEH_plugin->cls, TEH_plugin->cls,
kyp->requirement_row, kyp->requirement_row,
&requirements, &requirements,
&kyp->aml_status,
&h_payto); &h_payto);
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
{ {
@ -580,6 +586,17 @@ TEH_handler_kyc_check (
if ( (NULL == kyp->ih) && if ( (NULL == kyp->ih) &&
(! kyp->kyc_required) ) (! kyp->kyc_required) )
{ {
if (TALER_AML_NORMAL != kyp->aml_status)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"KYC is OK, but AML active: %d\n",
(int) kyp->aml_status);
return TALER_MHD_REPLY_JSON_PACK (
rc->connection,
MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
GNUNET_JSON_pack_uint64 ("aml_status",
kyp->aml_status));
}
/* 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",
@ -628,6 +645,8 @@ TEH_handler_kyc_check (
return TALER_MHD_REPLY_JSON_PACK ( return TALER_MHD_REPLY_JSON_PACK (
rc->connection, rc->connection,
MHD_HTTP_ACCEPTED, MHD_HTTP_ACCEPTED,
GNUNET_JSON_pack_uint64 ("aml_status",
kyp->aml_status),
GNUNET_JSON_pack_string ("kyc_url", GNUNET_JSON_pack_string ("kyc_url",
kyp->kyc_url)); kyp->kyc_url));
} }
@ -665,6 +684,8 @@ TEH_handler_kyc_check (
&sig), &sig),
GNUNET_JSON_pack_data_auto ("exchange_pub", GNUNET_JSON_pack_data_auto ("exchange_pub",
&pub), &pub),
GNUNET_JSON_pack_uint64 ("aml_status",
kyp->aml_status),
GNUNET_JSON_pack_object_incref ("kyc_details", GNUNET_JSON_pack_object_incref ("kyc_details",
kyp->kyc_details), kyp->kyc_details),
GNUNET_JSON_pack_timestamp ("now", GNUNET_JSON_pack_timestamp ("now",

View File

@ -30,9 +30,11 @@ TEH_PG_lookup_kyc_requirement_by_row (
void *cls, void *cls,
uint64_t requirement_row, uint64_t requirement_row,
char **requirements, char **requirements,
enum TALER_AmlDecisionState *aml_status,
struct TALER_PaytoHashP *h_payto) struct TALER_PaytoHashP *h_payto)
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;
uint32_t status;
struct GNUNET_PQ_QueryParam params[] = { struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_uint64 (&requirement_row), GNUNET_PQ_query_param_uint64 (&requirement_row),
GNUNET_PQ_query_param_end GNUNET_PQ_query_param_end
@ -42,19 +44,26 @@ TEH_PG_lookup_kyc_requirement_by_row (
requirements), 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_uint32 ("status",
&status),
GNUNET_PQ_result_spec_end GNUNET_PQ_result_spec_end
}; };
/* Used in #postgres_lookup_kyc_requirement_by_row() */ enum GNUNET_DB_QueryStatus qs;
PREPARE (pg, PREPARE (pg,
"lookup_legitimization_requirement_by_row", "lookup_legitimization_requirement_by_row",
"SELECT " "SELECT "
" required_checks" " lr.required_checks"
",h_payto" ",lr.h_payto"
" FROM legitimization_requirements" ",aml.status"
" FROM legitimization_requirements lr"
" JOIN aml_status aml USING (h_payto)"
" WHERE legitimization_requirement_serial_id=$1;"); " WHERE legitimization_requirement_serial_id=$1;");
return GNUNET_PQ_eval_prepared_singleton_select ( qs = GNUNET_PQ_eval_prepared_singleton_select (
pg->conn, pg->conn,
"lookup_legitimization_requirement_by_row", "lookup_legitimization_requirement_by_row",
params, params,
rs); rs);
*aml_status = (enum TALER_AmlDecisionState) status;
return qs;
} }

View File

@ -32,6 +32,7 @@
* @param cls closure * @param cls closure
* @param requirement_row identifies requirement to look up * @param requirement_row identifies requirement to look up
* @param[out] requirements provider that must be checked * @param[out] requirements provider that must be checked
* @param[out] aml_status set to the AML status of the account
* @param[out] h_payto account that must be KYC'ed * @param[out] h_payto account that must be KYC'ed
* @return database transaction status * @return database transaction status
*/ */
@ -40,5 +41,7 @@ TEH_PG_lookup_kyc_requirement_by_row (
void *cls, void *cls,
uint64_t requirement_row, uint64_t requirement_row,
char **requirements, char **requirements,
enum TALER_AmlDecisionState *aml_status,
struct TALER_PaytoHashP *h_payto); struct TALER_PaytoHashP *h_payto);
#endif #endif

View File

@ -3490,8 +3490,16 @@ struct TALER_EXCHANGE_KycStatus
*/ */
struct TALER_ExchangeSignatureP exchange_sig; struct TALER_ExchangeSignatureP exchange_sig;
/**
* AML status for the account.
*/
enum TALER_AmlDecisionState aml_status;
} success; } success;
/**
* KYC is required.
*/
struct struct
{ {
@ -3502,8 +3510,26 @@ struct TALER_EXCHANGE_KycStatus
*/ */
const char *kyc_url; const char *kyc_url;
/**
* AML status for the account.
*/
enum TALER_AmlDecisionState aml_status;
} accepted; } accepted;
/**
* KYC is OK, but account needs positive AML decision.
*/
struct
{
/**
* AML status for the account.
*/
enum TALER_AmlDecisionState aml_status;
} unavailable_for_legal_reasons;
} details; } details;
}; };

View File

@ -6457,6 +6457,7 @@ struct TALER_EXCHANGEDB_Plugin
* @param cls closure * @param cls closure
* @param legi_row identifies requirement to look up * @param legi_row identifies requirement to look up
* @param[out] requirements space-separated list of requirements * @param[out] requirements space-separated list of requirements
* @param[out] aml_status set to the AML status of the account
* @param[out] h_payto account that must be KYC'ed * @param[out] h_payto account that must be KYC'ed
* @return database transaction status * @return database transaction status
*/ */
@ -6465,6 +6466,7 @@ struct TALER_EXCHANGEDB_Plugin
void *cls, void *cls,
uint64_t requirement_row, uint64_t requirement_row,
char **requirements, char **requirements,
enum TALER_AmlDecisionState *aml_status,
struct TALER_PaytoHashP *h_payto); struct TALER_PaytoHashP *h_payto);

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2021 Taler Systems SA Copyright (C) 2021-2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software terms of the GNU General Public License as published by the Free Software
@ -97,6 +97,7 @@ handle_kyc_check_finished (void *cls,
case MHD_HTTP_OK: case MHD_HTTP_OK:
{ {
json_t *kyc_details; json_t *kyc_details;
uint32_t status;
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.success.exchange_sig), &ks.details.success.exchange_sig),
@ -106,6 +107,8 @@ handle_kyc_check_finished (void *cls,
&ks.details.success.timestamp), &ks.details.success.timestamp),
GNUNET_JSON_spec_json ("kyc_details", GNUNET_JSON_spec_json ("kyc_details",
&kyc_details), &kyc_details),
GNUNET_JSON_spec_uint32 ("aml_status",
&status),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
}; };
const struct TALER_EXCHANGE_Keys *key_state; const struct TALER_EXCHANGE_Keys *key_state;
@ -121,6 +124,8 @@ handle_kyc_check_finished (void *cls,
break; break;
} }
ks.details.success.kyc_details = kyc_details; ks.details.success.kyc_details = kyc_details;
ks.details.success.aml_status
= (enum TALER_AmlDecisionState) status;
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,
@ -155,9 +160,12 @@ handle_kyc_check_finished (void *cls,
} }
case MHD_HTTP_ACCEPTED: case MHD_HTTP_ACCEPTED:
{ {
uint32_t status;
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_string ("kyc_url", GNUNET_JSON_spec_string ("kyc_url",
&ks.details.accepted.kyc_url), &ks.details.accepted.kyc_url),
GNUNET_JSON_spec_uint32 ("aml_status",
&status),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
}; };
@ -171,6 +179,8 @@ handle_kyc_check_finished (void *cls,
ks.ec = TALER_EC_GENERIC_INVALID_RESPONSE; ks.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break; break;
} }
ks.details.accepted.aml_status
= (enum TALER_AmlDecisionState) status;
kch->cb (kch->cb_cls, kch->cb (kch->cb_cls,
&ks); &ks);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
@ -190,6 +200,33 @@ handle_kyc_check_finished (void *cls,
case MHD_HTTP_NOT_FOUND: case MHD_HTTP_NOT_FOUND:
ks.ec = TALER_JSON_get_error_code (j); ks.ec = TALER_JSON_get_error_code (j);
break; break;
case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
{
uint32_t status;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_uint32 ("aml_status",
&status),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (j,
spec,
NULL, NULL))
{
GNUNET_break_op (0);
ks.http_status = 0;
ks.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
}
ks.details.unavailable_for_legal_reasons.aml_status
= (enum TALER_AmlDecisionState) status;
kch->cb (kch->cb_cls,
&ks);
GNUNET_JSON_parse_free (spec);
TALER_EXCHANGE_kyc_check_cancel (kch);
return;
}
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