add KYC errors for p2p payments

This commit is contained in:
Christian Grothoff 2022-06-04 15:19:57 +02:00
parent 3e99c50c0f
commit 93943bdb5b
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
13 changed files with 158 additions and 18 deletions

@ -1 +1 @@
Subproject commit aebd5420308d7599aadb8818a82d9ffc89492334
Subproject commit d4234f340c6e7261de36ab5fad3d53597ea8ecd0

View File

@ -150,7 +150,7 @@ batch_withdraw_transaction (void *cls,
{
*mhd_ret = TALER_MHD_reply_with_error (connection,
MHD_HTTP_NOT_FOUND,
TALER_EC_EXCHANGE_WITHDRAW_RESERVE_UNKNOWN,
TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN,
NULL);
return GNUNET_DB_STATUS_HARD_ERROR;
}
@ -171,7 +171,7 @@ batch_withdraw_transaction (void *cls,
/* Wallet-to-wallet payments _always_ require KYC */
*mhd_ret = TALER_MHD_REPLY_JSON_PACK (
connection,
MHD_HTTP_ACCEPTED,
MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
GNUNET_JSON_pack_uint64 ("payment_target_uuid",
wc->kyc.payment_target_uuid));
return GNUNET_DB_STATUS_HARD_ERROR;
@ -206,7 +206,7 @@ batch_withdraw_transaction (void *cls,
{
*mhd_ret = TALER_MHD_REPLY_JSON_PACK (
connection,
MHD_HTTP_ACCEPTED,
MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
GNUNET_JSON_pack_uint64 ("payment_target_uuid",
wc->kyc.payment_target_uuid));
return GNUNET_DB_STATUS_HARD_ERROR;

View File

@ -223,6 +223,8 @@ merge_transaction (void *cls,
bool in_conflict = true;
bool no_balance = true;
bool no_partner = true;
bool no_kyc = true;
bool no_reserve = true;
// FIXME: add KYC-check logic!
qs = TEH_plugin->do_purse_merge (TEH_plugin->cls,
@ -234,6 +236,8 @@ merge_transaction (void *cls,
&pcc->reserve_pub,
&no_partner,
&no_balance,
&no_reserve,
&no_kyc,
&in_conflict);
if (qs < 0)
{
@ -257,6 +261,25 @@ merge_transaction (void *cls,
pcc->provider_url);
return GNUNET_DB_STATUS_HARD_ERROR;
}
if (no_reserve)
{
*mhd_ret =
TALER_MHD_reply_with_error (connection,
MHD_HTTP_NOT_FOUND,
TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN,
NULL);
return GNUNET_DB_STATUS_HARD_ERROR;
}
if (no_kyc)
{
*mhd_ret
= TALER_MHD_REPLY_JSON_PACK (
connection,
MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
TALER_JSON_pack_ec (
TALER_EC_EXCHANGE_GENERIC_KYC_REQUIRED));
return GNUNET_DB_STATUS_HARD_ERROR;
}
if (no_balance)
{
*mhd_ret =

View File

@ -213,8 +213,6 @@ purse_transaction (void *cls,
{
bool in_conflict = true;
// FIXME: also check KYC state of the account
// FIXME: distinguish reserve-not-found!
/* 1) store purse */
qs = TEH_plugin->insert_purse_request (TEH_plugin->cls,
&rpc->purse_pub,
@ -294,14 +292,14 @@ purse_transaction (void *cls,
return GNUNET_DB_STATUS_HARD_ERROR;
}
// FIXME: return 404 if reserve-not-found!
// FIXME: if KYC check failed, generate 451 response!
}
/* 2) create purse with reserve (and debit reserve for purse creation!) */
{
bool in_conflict = true;
bool insufficient_funds = true;
bool no_reserve = true;
bool no_kyc = true;
qs = TEH_plugin->do_reserve_purse (
TEH_plugin->cls,
@ -315,6 +313,8 @@ purse_transaction (void *cls,
: &rpc->gf->fees.purse,
rpc->reserve_pub,
&in_conflict,
&no_reserve,
&no_kyc,
&insufficient_funds);
if (qs < 0)
{
@ -377,6 +377,26 @@ purse_transaction (void *cls,
GNUNET_free (partner_url);
return GNUNET_DB_STATUS_HARD_ERROR;
}
if (no_reserve)
{
*mhd_ret
= TALER_MHD_REPLY_JSON_PACK (
connection,
MHD_HTTP_NOT_FOUND,
TALER_JSON_pack_ec (
TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN));
return GNUNET_DB_STATUS_HARD_ERROR;
}
if (no_kyc)
{
*mhd_ret
= TALER_MHD_REPLY_JSON_PACK (
connection,
MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
TALER_JSON_pack_ec (
TALER_EC_EXCHANGE_GENERIC_KYC_REQUIRED));
return GNUNET_DB_STATUS_HARD_ERROR;
}
if (insufficient_funds)
{
*mhd_ret

View File

@ -133,7 +133,7 @@ withdraw_transaction (void *cls,
{
*mhd_ret = TALER_MHD_reply_with_error (connection,
MHD_HTTP_NOT_FOUND,
TALER_EC_EXCHANGE_WITHDRAW_RESERVE_UNKNOWN,
TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN,
NULL);
return GNUNET_DB_STATUS_HARD_ERROR;
}
@ -153,7 +153,7 @@ withdraw_transaction (void *cls,
/* Wallet-to-wallet payments _always_ require KYC */
*mhd_ret = TALER_MHD_REPLY_JSON_PACK (
connection,
MHD_HTTP_ACCEPTED,
MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
GNUNET_JSON_pack_uint64 ("payment_target_uuid",
wc->kyc.payment_target_uuid));
return GNUNET_DB_STATUS_HARD_ERROR;
@ -188,7 +188,7 @@ withdraw_transaction (void *cls,
{
*mhd_ret = TALER_MHD_REPLY_JSON_PACK (
connection,
MHD_HTTP_ACCEPTED,
MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
GNUNET_JSON_pack_uint64 ("payment_target_uuid",
wc->kyc.payment_target_uuid));
return GNUNET_DB_STATUS_HARD_ERROR;

View File

@ -3092,6 +3092,8 @@ CREATE OR REPLACE FUNCTION exchange_do_purse_merge(
IN in_reserve_pub BYTEA,
OUT out_no_partner BOOLEAN,
OUT out_no_balance BOOLEAN,
OUT out_no_kyc BOOLEAN,
OUT out_no_reserve BOOLEAN,
OUT out_conflict BOOLEAN)
LANGUAGE plpgsql
AS $$
@ -3121,6 +3123,8 @@ ELSE
THEN
out_no_partner=TRUE;
out_conflict=FALSE;
out_no_kyc=FALSE;
out_no_reserve=FALSE;
RETURN;
END IF;
END IF;
@ -3144,6 +3148,8 @@ IF NOT FOUND
THEN
out_no_balance=TRUE;
out_conflict=FALSE;
out_no_kyc=FALSE;
out_no_reserve=FALSE;
RETURN;
END IF;
out_no_balance=FALSE;
@ -3176,17 +3182,49 @@ THEN
THEN
-- Purse was merged, but to some other reserve. Not allowed.
out_conflict=TRUE;
out_no_kyc=FALSE;
out_no_reserve=FALSE;
RETURN;
END IF;
-- "success"
out_conflict=FALSE;
out_no_kyc=FALSE;
out_no_reserve=FALSE;
RETURN;
END IF;
out_conflict=FALSE;
ASSERT NOT my_finished, 'internal invariant failed';
IF in_partner_url IS NULL
THEN
-- Need to do KYC check.
SELECT NOT kyc_passed
INTO out_no_kyc
FROM reserves
WHERE reserve_pub=in_reserve_pub;
IF NOT FOUND
THEN
out_no_kyc=TRUE;
out_no_reserve=TRUE;
RETURN;
END IF;
out_no_reserve=FALSE;
IF (out_no_kyc)
THEN
RETURN;
END IF;
ELSE
-- KYC is not our responsibility
out_no_reserve=FALSE;
out_no_kyc=FALSE;
END IF;
-- Store account merge signature.
INSERT INTO account_merges
(reserve_pub
@ -3248,6 +3286,8 @@ CREATE OR REPLACE FUNCTION exchange_do_reserve_purse(
IN in_purse_fee_frac INT4,
IN in_reserve_pub BYTEA,
OUT out_no_funds BOOLEAN,
OUT out_no_kyc BOOLEAN,
OUT out_no_reserve BOOLEAN,
OUT out_conflict BOOLEAN)
LANGUAGE plpgsql
AS $$
@ -3281,16 +3321,40 @@ THEN
THEN
-- Purse was merged, but to some other reserve. Not allowed.
out_conflict=TRUE;
out_no_kyc=FALSE;
out_no_reserve=FALSE;
out_no_funds=FALSE;
RETURN;
END IF;
-- "success"
out_conflict=FALSE;
out_no_funds=FALSE;
out_no_kyc=FALSE;
out_no_reserve=FALSE;
RETURN;
END IF;
out_conflict=FALSE;
SELECT NOT kyc_passed
INTO out_no_kyc
FROM reserves
WHERE reserve_pub=in_reserve_pub;
IF NOT FOUND
THEN
out_no_kyc=TRUE;
out_no_reserve=TRUE;
out_no_funds=TRUE;
RETURN;
END IF;
out_no_reserve=FALSE;
IF (out_no_kyc)
THEN
out_no_funds=FALSE;
RETURN;
END IF;
IF (in_reserve_quota)
THEN
@ -3303,6 +3367,7 @@ THEN
IF NOT FOUND
THEN
out_no_funds=TRUE;
RETURN;
END IF;
ELSE
-- UPDATE reserves balance (and check if balance is enough to pay the fee)
@ -3328,6 +3393,7 @@ ELSE
IF NOT FOUND
THEN
out_no_funds=TRUE;
RETURN;
END IF;
END IF;

View File

@ -3973,6 +3973,8 @@ prepare_statements (struct PostgresClosure *pg)
"SELECT"
" out_no_partner AS no_partner"
",out_no_balance AS no_balance"
",out_no_kyc AS no_kyc"
",out_no_reserve AS no_reserve"
",out_conflict AS conflict"
" FROM exchange_do_purse_merge"
" ($1, $2, $3, $4, $5, $6);",
@ -3982,6 +3984,8 @@ prepare_statements (struct PostgresClosure *pg)
"call_reserve_purse",
"SELECT"
" out_no_funds AS insufficient_funds"
",out_no_reserve AS no_reserve"
",out_no_kyc AS no_kyc"
",out_conflict AS conflict"
" FROM exchange_do_reserve_purse"
" ($1, $2, $3, $4, $5, $6, $7, $8);",
@ -14490,6 +14494,8 @@ postgres_get_purse_deposit (
* @param reserve_pub public key of the reserve to credit
* @param[out] no_partner set to true if @a partner_url is unknown
* @param[out] no_balance set to true if the @a purse_pub is not paid up yet
* @param[out] no_reserve set to true if the @a reserve_pub is not known
* @param[out] no_kyc set to true if the @a reserve_pub lacks KYC
* @param[out] in_conflict set to true if @a purse_pub was merged into a different reserve already
* @return transaction status code
*/
@ -14504,6 +14510,8 @@ postgres_do_purse_merge (
const struct TALER_ReservePublicKeyP *reserve_pub,
bool *no_partner,
bool *no_balance,
bool *no_reserve,
bool *no_kyc,
bool *in_conflict)
{
struct PostgresClosure *pg = cls;
@ -14523,6 +14531,10 @@ postgres_do_purse_merge (
no_partner),
GNUNET_PQ_result_spec_bool ("no_balance",
no_balance),
GNUNET_PQ_result_spec_bool ("no_kyc",
no_kyc),
GNUNET_PQ_result_spec_bool ("no_reserve",
no_reserve),
GNUNET_PQ_result_spec_bool ("conflict",
in_conflict),
GNUNET_PQ_result_spec_end
@ -14561,6 +14573,8 @@ postgres_do_reserve_purse (
const struct TALER_Amount *purse_fee,
const struct TALER_ReservePublicKeyP *reserve_pub,
bool *in_conflict,
bool *no_reserve,
bool *no_kyc,
bool *insufficient_funds)
{
struct PostgresClosure *pg = cls;
@ -14582,6 +14596,10 @@ postgres_do_reserve_purse (
insufficient_funds),
GNUNET_PQ_result_spec_bool ("conflict",
in_conflict),
GNUNET_PQ_result_spec_bool ("no_kyc",
no_kyc),
GNUNET_PQ_result_spec_bool ("no_reserve",
no_reserve),
GNUNET_PQ_result_spec_end
};

View File

@ -5039,6 +5039,8 @@ struct TALER_EXCHANGEDB_Plugin
* @param reserve_pub public key of the reserve to credit
* @param[out] no_partner set to true if @a partner_url is unknown
* @param[out] no_balance set to true if the @a purse_pub is not paid up yet
* @param[out] no_reserve set to true if the @a reserve_pub is not known
* @param[out] no_kyc set to true if the @a reserve_pub lacks KYC
* @param[out] in_conflict set to true if @a purse_pub was merged into a different reserve already
* @return transaction status code
*/
@ -5053,6 +5055,8 @@ struct TALER_EXCHANGEDB_Plugin
const struct TALER_ReservePublicKeyP *reserve_pub,
bool *no_partner,
bool *no_balance,
bool *no_reserve,
bool *no_kyc,
bool *in_conflict);
@ -5069,6 +5073,8 @@ struct TALER_EXCHANGEDB_Plugin
* @param purse_fee amount to charge the reserve for the purse creation, NULL to use the quota
* @param reserve_pub public key of the reserve to credit
* @param[out] in_conflict set to true if @a purse_pub was merged into a different reserve already
* @param[out] no_reserve set to true if @a reserve_pub is not a known reserve
* @param[out] no_kyc set to true if @a reserve_pub has not passed KYC checks
* @param[out] insufficient_funds set to true if @a reserve_pub has insufficient capacity to create another purse
* @return transaction status code
*/
@ -5082,6 +5088,8 @@ struct TALER_EXCHANGEDB_Plugin
const struct TALER_Amount *purse_fee,
const struct TALER_ReservePublicKeyP *reserve_pub,
bool *in_conflict,
bool *no_reserve,
bool *no_kyc,
bool *insufficient_funds);

View File

@ -203,7 +203,7 @@ handle_reserve_batch_withdraw_finished (
wr.details.success.num_coins = wh->num_coins;
break;
}
case MHD_HTTP_ACCEPTED:
case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
{
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_uint64 ("payment_target_uuid",

View File

@ -224,6 +224,11 @@ handle_purse_create_with_merge_finished (void *cls,
dr.hr.ec = TALER_JSON_get_error_code (j);
dr.hr.hint = TALER_JSON_get_error_hint (j);
break;
case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
/* aka KYC required */
dr.hr.ec = TALER_JSON_get_error_code (j);
dr.hr.hint = TALER_JSON_get_error_hint (j);
break;
case MHD_HTTP_INTERNAL_SERVER_ERROR:
dr.hr.ec = TALER_JSON_get_error_code (j);
dr.hr.hint = TALER_JSON_get_error_hint (j);

View File

@ -157,7 +157,7 @@ handle_reserve_withdraw_finished (
wr.details.success.exchange_vals = wh->alg_values;
break;
}
case MHD_HTTP_ACCEPTED:
case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
{
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_uint64 ("payment_target_uuid",

View File

@ -106,7 +106,7 @@ run (void *cls,
"create-reserve-1",
"EUR:10",
0, /* age restriction off */
MHD_HTTP_ACCEPTED),
MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS),
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1",
"create-reserve-1",
"EUR:5",
@ -123,7 +123,7 @@ run (void *cls,
"create-reserve-1",
"EUR:5",
0, /* age restriction off */
MHD_HTTP_ACCEPTED),
MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS),
TALER_TESTING_cmd_proof_kyc ("proof-kyc",
"create-reserve-1",
"pass",

View File

@ -242,12 +242,12 @@ reserve_withdraw_cb (void *cls,
{
if (0 != ws->do_retry)
{
if (TALER_EC_EXCHANGE_WITHDRAW_RESERVE_UNKNOWN != wr->hr.ec)
if (TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN != wr->hr.ec)
ws->do_retry--; /* we don't count reserve unknown as failures here */
if ( (0 == wr->hr.http_status) ||
(TALER_EC_GENERIC_DB_SOFT_FAILURE == wr->hr.ec) ||
(TALER_EC_EXCHANGE_WITHDRAW_INSUFFICIENT_FUNDS == wr->hr.ec) ||
(TALER_EC_EXCHANGE_WITHDRAW_RESERVE_UNKNOWN == wr->hr.ec) ||
(TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN == wr->hr.ec) ||
(MHD_HTTP_INTERNAL_SERVER_ERROR == wr->hr.http_status) )
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@ -257,7 +257,7 @@ reserve_withdraw_cb (void *cls,
/* on DB conflicts, do not use backoff */
if (TALER_EC_GENERIC_DB_SOFT_FAILURE == wr->hr.ec)
ws->backoff = GNUNET_TIME_UNIT_ZERO;
else if (TALER_EC_EXCHANGE_WITHDRAW_RESERVE_UNKNOWN != wr->hr.ec)
else if (TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN != wr->hr.ec)
ws->backoff = EXCHANGE_LIB_BACKOFF (ws->backoff);
else
ws->backoff = GNUNET_TIME_relative_max (UNKNOWN_MIN_BACKOFF,