aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2022-06-04 15:19:57 +0200
committerChristian Grothoff <christian@grothoff.org>2022-06-04 15:19:57 +0200
commit93943bdb5b6ab43b6bcfdb721f67674cc89250d6 (patch)
tree17e98a062ba886f1389ce99f5cb2fecb242a5f76
parent3e99c50c0f940fda34585225c38c9014cc1110d0 (diff)
add KYC errors for p2p payments
m---------contrib/gana0
-rw-r--r--src/exchange/taler-exchange-httpd_batch-withdraw.c6
-rw-r--r--src/exchange/taler-exchange-httpd_purses_merge.c23
-rw-r--r--src/exchange/taler-exchange-httpd_reserves_purse.c28
-rw-r--r--src/exchange/taler-exchange-httpd_withdraw.c6
-rw-r--r--src/exchangedb/exchange-0001-part.sql66
-rw-r--r--src/exchangedb/plugin_exchangedb_postgres.c18
-rw-r--r--src/include/taler_exchangedb_plugin.h8
-rw-r--r--src/lib/exchange_api_batch_withdraw.c2
-rw-r--r--src/lib/exchange_api_purse_create_with_merge.c5
-rw-r--r--src/lib/exchange_api_withdraw.c2
-rw-r--r--src/testing/test_kyc_api.c4
-rw-r--r--src/testing/testing_api_cmd_withdraw.c6
13 files changed, 157 insertions, 17 deletions
diff --git a/contrib/gana b/contrib/gana
-Subproject aebd5420308d7599aadb8818a82d9ffc8949233
+Subproject d4234f340c6e7261de36ab5fad3d53597ea8ecd
diff --git a/src/exchange/taler-exchange-httpd_batch-withdraw.c b/src/exchange/taler-exchange-httpd_batch-withdraw.c
index f4276ef67..d1311f8ad 100644
--- a/src/exchange/taler-exchange-httpd_batch-withdraw.c
+++ b/src/exchange/taler-exchange-httpd_batch-withdraw.c
@@ -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;
diff --git a/src/exchange/taler-exchange-httpd_purses_merge.c b/src/exchange/taler-exchange-httpd_purses_merge.c
index b0055edab..14dba5232 100644
--- a/src/exchange/taler-exchange-httpd_purses_merge.c
+++ b/src/exchange/taler-exchange-httpd_purses_merge.c
@@ -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 =
diff --git a/src/exchange/taler-exchange-httpd_reserves_purse.c b/src/exchange/taler-exchange-httpd_reserves_purse.c
index 09ef3b373..f56852d53 100644
--- a/src/exchange/taler-exchange-httpd_reserves_purse.c
+++ b/src/exchange/taler-exchange-httpd_reserves_purse.c
@@ -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
diff --git a/src/exchange/taler-exchange-httpd_withdraw.c b/src/exchange/taler-exchange-httpd_withdraw.c
index ca4ed9a71..1d48045b6 100644
--- a/src/exchange/taler-exchange-httpd_withdraw.c
+++ b/src/exchange/taler-exchange-httpd_withdraw.c
@@ -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;
diff --git a/src/exchangedb/exchange-0001-part.sql b/src/exchangedb/exchange-0001-part.sql
index 52a16cd9a..0b99e25f9 100644
--- a/src/exchangedb/exchange-0001-part.sql
+++ b/src/exchangedb/exchange-0001-part.sql
@@ -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;
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c
index 3a269c6de..01869d592 100644
--- a/src/exchangedb/plugin_exchangedb_postgres.c
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -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
};
diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h
index 707ce311f..a88f34b01 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -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);
diff --git a/src/lib/exchange_api_batch_withdraw.c b/src/lib/exchange_api_batch_withdraw.c
index 295695d8f..e5d3c7f9c 100644
--- a/src/lib/exchange_api_batch_withdraw.c
+++ b/src/lib/exchange_api_batch_withdraw.c
@@ -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",
diff --git a/src/lib/exchange_api_purse_create_with_merge.c b/src/lib/exchange_api_purse_create_with_merge.c
index 32b88c597..af5b554e4 100644
--- a/src/lib/exchange_api_purse_create_with_merge.c
+++ b/src/lib/exchange_api_purse_create_with_merge.c
@@ -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);
diff --git a/src/lib/exchange_api_withdraw.c b/src/lib/exchange_api_withdraw.c
index 6bb579c2c..b8ab1df44 100644
--- a/src/lib/exchange_api_withdraw.c
+++ b/src/lib/exchange_api_withdraw.c
@@ -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",
diff --git a/src/testing/test_kyc_api.c b/src/testing/test_kyc_api.c
index 13244993b..303c7e11a 100644
--- a/src/testing/test_kyc_api.c
+++ b/src/testing/test_kyc_api.c
@@ -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",
diff --git a/src/testing/testing_api_cmd_withdraw.c b/src/testing/testing_api_cmd_withdraw.c
index 019c08de4..44e295338 100644
--- a/src/testing/testing_api_cmd_withdraw.c
+++ b/src/testing/testing_api_cmd_withdraw.c
@@ -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,