add KYC logic for /deposit handling (DB part incomplete)

This commit is contained in:
Christian Grothoff 2021-10-15 23:34:23 +02:00
parent ca12adced4
commit a48db85013
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
3 changed files with 121 additions and 8 deletions

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2014-2020 Taler Systems SA Copyright (C) 2014-2021 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 Affero General Public License as published by the Free Software terms of the GNU Affero General Public License as published by the Free Software
@ -45,6 +45,7 @@
* operation with the given wiring details. * operation with the given wiring details.
* *
* @param connection connection to the client * @param connection connection to the client
* @param kyc KYC status for the credited account
* @param coin_pub public key of the coin * @param coin_pub public key of the coin
* @param h_wire hash of wire details * @param h_wire hash of wire details
* @param h_contract_terms hash of contract details * @param h_contract_terms hash of contract details
@ -56,6 +57,7 @@
*/ */
static MHD_RESULT static MHD_RESULT
reply_deposit_success (struct MHD_Connection *connection, reply_deposit_success (struct MHD_Connection *connection,
const struct TALER_EXCHANGEDB_KycStatus *kyc,
const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_CoinSpendPublicKeyP *coin_pub,
const struct GNUNET_HashCode *h_wire, const struct GNUNET_HashCode *h_wire,
const struct GNUNET_HashCode *h_contract_terms, const struct GNUNET_HashCode *h_contract_terms,
@ -92,6 +94,10 @@ reply_deposit_success (struct MHD_Connection *connection,
return TALER_MHD_REPLY_JSON_PACK ( return TALER_MHD_REPLY_JSON_PACK (
connection, connection,
MHD_HTTP_OK, MHD_HTTP_OK,
GNUNET_JSON_pack_uint64 ("payment_target_uuid",
kyc->payment_target_uuid),
GNUNET_JSON_pack_bool ("kyc_ok",
kyc->ok),
GNUNET_JSON_pack_time_abs ("exchange_timestamp", GNUNET_JSON_pack_time_abs ("exchange_timestamp",
exchange_timestamp), exchange_timestamp),
GNUNET_JSON_pack_data_auto ("exchange_sig", GNUNET_JSON_pack_data_auto ("exchange_sig",
@ -121,6 +127,15 @@ struct DepositContext
*/ */
struct TALER_Amount value; struct TALER_Amount value;
/**
* KYC status for the receiving account.
*/
struct TALER_EXCHANGEDB_KycStatus kyc;
/**
* payto:// URI of the credited account.
*/
char *payto_uri;
}; };
@ -146,6 +161,21 @@ deposit_precheck (void *cls,
struct TALER_Amount deposit_fee; struct TALER_Amount deposit_fee;
enum GNUNET_DB_QueryStatus qs; enum GNUNET_DB_QueryStatus qs;
qs = TEH_plugin->get_kyc_status (TEH_plugin->cls,
dc->payto_uri,
&dc->kyc);
if (qs < 0)
{
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
{
*mhd_ret = TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_FETCH_FAILED,
"get_kyc_status");
return GNUNET_DB_STATUS_HARD_ERROR;
}
return qs;
}
qs = TEH_plugin->have_deposit (TEH_plugin->cls, qs = TEH_plugin->have_deposit (TEH_plugin->cls,
deposit, deposit,
GNUNET_YES /* check refund deadline */, GNUNET_YES /* check refund deadline */,
@ -158,7 +188,7 @@ deposit_precheck (void *cls,
*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_GENERIC_DB_FETCH_FAILED, TALER_EC_GENERIC_DB_FETCH_FAILED,
NULL); "have_deposit");
return GNUNET_DB_STATUS_HARD_ERROR; return GNUNET_DB_STATUS_HARD_ERROR;
} }
return qs; return qs;
@ -174,6 +204,7 @@ deposit_precheck (void *cls,
&deposit->amount_with_fee, &deposit->amount_with_fee,
&deposit_fee)); &deposit_fee));
*mhd_ret = reply_deposit_success (connection, *mhd_ret = reply_deposit_success (connection,
&dc->kyc,
&deposit->coin.coin_pub, &deposit->coin.coin_pub,
&deposit->h_wire, &deposit->h_wire,
&deposit->h_contract_terms, &deposit->h_contract_terms,
@ -218,7 +249,6 @@ deposit_transaction (void *cls,
mhd_ret); mhd_ret);
if (qs < 0) if (qs < 0)
return qs; return qs;
/* Theoretically, someone other threat may have received /* Theoretically, someone other threat may have received
and committed the deposit in the meantime. Check now and committed the deposit in the meantime. Check now
that we are in the transaction scope. */ that we are in the transaction scope. */
@ -369,11 +399,10 @@ TEH_handler_deposit (struct MHD_Connection *connection,
} }
/* validate merchant's wire details (as far as we can) */ /* validate merchant's wire details (as far as we can) */
{ {
char *payto;
char *emsg; char *emsg;
payto = TALER_JSON_wire_to_payto (wire); dc.payto_uri = TALER_JSON_wire_to_payto (wire);
if (NULL == payto) if (NULL == dc.payto_uri)
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
@ -382,8 +411,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
TALER_EC_GENERIC_PARAMETER_MALFORMED, TALER_EC_GENERIC_PARAMETER_MALFORMED,
"wire"); "wire");
} }
emsg = TALER_payto_validate (payto); emsg = TALER_payto_validate (dc.payto_uri);
GNUNET_free (payto);
if (NULL != emsg) if (NULL != emsg)
{ {
MHD_RESULT ret; MHD_RESULT ret;
@ -395,6 +423,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
TALER_EC_GENERIC_PARAMETER_MALFORMED, TALER_EC_GENERIC_PARAMETER_MALFORMED,
emsg); emsg);
GNUNET_free (emsg); GNUNET_free (emsg);
GNUNET_free (dc.payto_uri);
return ret; return ret;
} }
} }
@ -403,6 +432,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
GNUNET_free (dc.payto_uri);
return TALER_MHD_reply_with_error (connection, return TALER_MHD_reply_with_error (connection,
MHD_HTTP_BAD_REQUEST, MHD_HTTP_BAD_REQUEST,
TALER_EC_EXCHANGE_DEPOSIT_REFUND_DEADLINE_AFTER_WIRE_DEADLINE, TALER_EC_EXCHANGE_DEPOSIT_REFUND_DEADLINE_AFTER_WIRE_DEADLINE,
@ -415,6 +445,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
TALER_LOG_WARNING ( TALER_LOG_WARNING (
"Failed to parse JSON wire format specification for /deposit request\n"); "Failed to parse JSON wire format specification for /deposit request\n");
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
GNUNET_free (dc.payto_uri);
return TALER_MHD_reply_with_error (connection, return TALER_MHD_reply_with_error (connection,
MHD_HTTP_BAD_REQUEST, MHD_HTTP_BAD_REQUEST,
TALER_EC_EXCHANGE_DEPOSIT_INVALID_WIRE_FORMAT_JSON, TALER_EC_EXCHANGE_DEPOSIT_INVALID_WIRE_FORMAT_JSON,
@ -425,6 +456,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
{ {
/* Client hashed wire details differently than we did, reject */ /* Client hashed wire details differently than we did, reject */
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
GNUNET_free (dc.payto_uri);
return TALER_MHD_reply_with_error (connection, return TALER_MHD_reply_with_error (connection,
MHD_HTTP_BAD_REQUEST, MHD_HTTP_BAD_REQUEST,
TALER_EC_EXCHANGE_DEPOSIT_INVALID_WIRE_FORMAT_CONTRACT_HASH_CONFLICT, TALER_EC_EXCHANGE_DEPOSIT_INVALID_WIRE_FORMAT_CONTRACT_HASH_CONFLICT,
@ -444,6 +476,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
&dc)) &dc))
{ {
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
GNUNET_free (dc.payto_uri);
return mhd_ret; return mhd_ret;
} }
} }
@ -462,6 +495,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
if (NULL == dk) if (NULL == dk)
{ {
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
GNUNET_free (dc.payto_uri);
return mret; return mret;
} }
if (GNUNET_TIME_absolute_is_past (dk->meta.expire_deposit)) if (GNUNET_TIME_absolute_is_past (dk->meta.expire_deposit))
@ -472,6 +506,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
now = GNUNET_TIME_absolute_get (); now = GNUNET_TIME_absolute_get ();
(void) GNUNET_TIME_round_abs (&now); (void) GNUNET_TIME_round_abs (&now);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
GNUNET_free (dc.payto_uri);
return TEH_RESPONSE_reply_expired_denom_pub_hash ( return TEH_RESPONSE_reply_expired_denom_pub_hash (
connection, connection,
&deposit.coin.denom_pub_hash, &deposit.coin.denom_pub_hash,
@ -487,6 +522,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
now = GNUNET_TIME_absolute_get (); now = GNUNET_TIME_absolute_get ();
(void) GNUNET_TIME_round_abs (&now); (void) GNUNET_TIME_round_abs (&now);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
GNUNET_free (dc.payto_uri);
return TEH_RESPONSE_reply_expired_denom_pub_hash ( return TEH_RESPONSE_reply_expired_denom_pub_hash (
connection, connection,
&deposit.coin.denom_pub_hash, &deposit.coin.denom_pub_hash,
@ -502,6 +538,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
(void) GNUNET_TIME_round_abs (&now); (void) GNUNET_TIME_round_abs (&now);
/* This denomination has been revoked */ /* This denomination has been revoked */
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
GNUNET_free (dc.payto_uri);
return TEH_RESPONSE_reply_expired_denom_pub_hash ( return TEH_RESPONSE_reply_expired_denom_pub_hash (
connection, connection,
&deposit.coin.denom_pub_hash, &deposit.coin.denom_pub_hash,
@ -518,6 +555,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
{ {
TALER_LOG_WARNING ("Invalid coin passed for /deposit\n"); TALER_LOG_WARNING ("Invalid coin passed for /deposit\n");
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
GNUNET_free (dc.payto_uri);
return TALER_MHD_reply_with_error (connection, return TALER_MHD_reply_with_error (connection,
MHD_HTTP_UNAUTHORIZED, MHD_HTTP_UNAUTHORIZED,
TALER_EC_EXCHANGE_DENOMINATION_SIGNATURE_INVALID, TALER_EC_EXCHANGE_DENOMINATION_SIGNATURE_INVALID,
@ -530,6 +568,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
GNUNET_free (dc.payto_uri);
return TALER_MHD_reply_with_error (connection, return TALER_MHD_reply_with_error (connection,
MHD_HTTP_BAD_REQUEST, MHD_HTTP_BAD_REQUEST,
TALER_EC_EXCHANGE_DEPOSIT_NEGATIVE_VALUE_AFTER_FEE, TALER_EC_EXCHANGE_DEPOSIT_NEGATIVE_VALUE_AFTER_FEE,
@ -562,6 +601,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
{ {
TALER_LOG_WARNING ("Invalid signature on /deposit request\n"); TALER_LOG_WARNING ("Invalid signature on /deposit request\n");
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
GNUNET_free (dc.payto_uri);
return TALER_MHD_reply_with_error (connection, return TALER_MHD_reply_with_error (connection,
MHD_HTTP_UNAUTHORIZED, MHD_HTTP_UNAUTHORIZED,
TALER_EC_EXCHANGE_DEPOSIT_COIN_SIGNATURE_INVALID, TALER_EC_EXCHANGE_DEPOSIT_COIN_SIGNATURE_INVALID,
@ -581,9 +621,11 @@ TEH_handler_deposit (struct MHD_Connection *connection,
&dc)) &dc))
{ {
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
GNUNET_free (dc.payto_uri);
return mhd_ret; return mhd_ret;
} }
} }
GNUNET_free (dc.payto_uri);
/* generate regular response */ /* generate regular response */
{ {
@ -595,6 +637,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
&deposit.amount_with_fee, &deposit.amount_with_fee,
&deposit.deposit_fee)); &deposit.deposit_fee));
res = reply_deposit_success (connection, res = reply_deposit_success (connection,
&dc.kyc,
&deposit.coin.coin_pub, &deposit.coin.coin_pub,
&deposit.h_wire, &deposit.h_wire,
&deposit.h_contract_terms, &deposit.h_contract_terms,

View File

@ -359,6 +359,17 @@ prepare_statements (struct PostgresClosure *pg)
" WHERE reserve_pub=$1" " WHERE reserve_pub=$1"
" LIMIT 1;", " LIMIT 1;",
1), 1),
#if FIXME_DD23
/* Used in #postgres_get_kyc_status() */
GNUNET_PQ_make_prepare ("get_kyc_status",
"SELECT"
",kyc_ok"
",wire_target_serial_id AS payment_target_uuid"
" FROM wire_targets"
" WHERE payto_uri=$1"
" LIMIT 1;",
1),
#endif
/* Used in #reserves_get() */ /* Used in #reserves_get() */
GNUNET_PQ_make_prepare ("reserves_get", GNUNET_PQ_make_prepare ("reserves_get",
"SELECT" "SELECT"
@ -3516,6 +3527,50 @@ postgres_reserves_get (void *cls,
} }
/**
* Get the KYC status for a bank account.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param payto_uri payto:// URI that identifies the bank account
* @param[out] kyc set to the KYC status of the reserve
* @return transaction status
*/
static enum GNUNET_DB_QueryStatus
postgres_get_kyc_status (void *cls,
const char *payto_uri,
struct TALER_EXCHANGEDB_KycStatus *kyc)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_string (payto_uri),
GNUNET_PQ_query_param_end
};
uint8_t ok8;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_uint64 ("payment_target_uuid",
&kyc->payment_target_uuid),
GNUNET_PQ_result_spec_auto_from_type ("kyc_ok",
&ok8),
GNUNET_PQ_result_spec_end
};
enum GNUNET_DB_QueryStatus qs;
#if FIXME_DD23
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"get_kyc_status",
params,
rs);
#else
qs = 1;
ok8 = 0;
kyc->payment_target_uuid = 0;
#endif
kyc->type = TALER_EXCHANGEDB_KYC_DEPOSIT;
kyc->ok = (0 != ok8);
return qs;
}
/** /**
* Get the summary of a reserve. * Get the summary of a reserve.
* *
@ -11071,6 +11126,7 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
plugin->iterate_auditor_denominations = plugin->iterate_auditor_denominations =
&postgres_iterate_auditor_denominations; &postgres_iterate_auditor_denominations;
plugin->reserves_get = &postgres_reserves_get; plugin->reserves_get = &postgres_reserves_get;
plugin->get_kyc_status = &postgres_get_kyc_status;
plugin->reserves_in_insert = &postgres_reserves_in_insert; plugin->reserves_in_insert = &postgres_reserves_in_insert;
plugin->get_latest_reserve_in_reference = plugin->get_latest_reserve_in_reference =
&postgres_get_latest_reserve_in_reference; &postgres_get_latest_reserve_in_reference;

View File

@ -2376,6 +2376,20 @@ struct TALER_EXCHANGEDB_Plugin
struct TALER_EXCHANGEDB_KycStatus *kyc); struct TALER_EXCHANGEDB_KycStatus *kyc);
/**
* Get the KYC status for a bank account.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param payto_uri payto:// URI that identifies the bank account
* @param[out] kyc set to the KYC status of the reserve
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
(*get_kyc_status)(void *cls,
const char *payto_uri,
struct TALER_EXCHANGEDB_KycStatus *kyc);
/** /**
* Insert a incoming transaction into reserves. New reserves are * Insert a incoming transaction into reserves. New reserves are
* also created through this function. * also created through this function.