-work on new KYC logic: tests pass again

This commit is contained in:
Christian Grothoff 2022-08-14 18:04:09 +02:00
parent 913eacf506
commit 74ba46db39
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
38 changed files with 2650 additions and 2735 deletions

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
1660251795
1660491075

View File

@ -3,7 +3,7 @@ KEYFILE = ${TALER_DATA_HOME}/merchant/default.priv
NAME = Merchant Inc.
[exchange-account-1]
PAYTO_URI = payto://iban/SANDBOXX/DE546854?receiver-name=Exchange+Company
PAYTO_URI = payto://iban/SANDBOXX/DE128580?receiver-name=Exchange+Company
enable_debit = yes
enable_credit = yes
@ -19,7 +19,7 @@ HONOR_default = YES
ACTIVE_default = YES
[merchant-exchange-default]
MASTER_KEY = SA4PMGHM403V1F2TQVFRVKH9BTZ2FBG3V6R7FFVVTYFEFDYG3AX0
MASTER_KEY = EHBD7SW56Y5KD1VT7YVSWJ3MMB7ZNASXE4NMEGE82D8RZ413GWR0
EXCHANGE_BASE_URL = http://localhost:8081/
CURRENCY = TESTKUDOS
@ -155,7 +155,7 @@ UNIXPATH = ${TALER_RUNTIME_DIR}/merchant.http
CONFIG = postgres:///auditor-basedb
[exchange]
MASTER_PUBLIC_KEY = SA4PMGHM403V1F2TQVFRVKH9BTZ2FBG3V6R7FFVVTYFEFDYG3AX0
MASTER_PUBLIC_KEY = EHBD7SW56Y5KD1VT7YVSWJ3MMB7ZNASXE4NMEGE82D8RZ413GWR0
SIGNKEY_DURATION = 4 weeks
LOOKAHEAD_SIGN = 32 weeks 1 day
SIGNKEY_LEGAL_DURATION = 4 weeks
@ -177,7 +177,7 @@ CONFIG = postgres:///auditor-basedb
[auditor]
BASE_URL = http://localhost:8083/
TINY_AMOUNT = TESTKUDOS:0.01
PUBLIC_KEY = JZYPE53YY23MQ0HTTV3DYHRABW4RM6SJS1Y0HF2HMSEPEPRJ77WG
PUBLIC_KEY = RPBANQQH936J5S6Q61A58WA9R92WKXPBZNYWFZ5YXNZB0NFV78NG
[PATHS]
TALER_CACHE_HOME = $TALER_HOME/.cache/taler/

View File

@ -1 +1 @@
SA4PMGHM403V1F2TQVFRVKH9BTZ2FBG3V6R7FFVVTYFEFDYG3AX0
EHBD7SW56Y5KD1VT7YVSWJ3MMB7ZNASXE4NMEGE82D8RZ413GWR0

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 @@
1660252041
1660491749

View File

@ -1 +1 @@
QKEQ98KRJ7RGKBZ2FSW0S0Y07G1AVJMBDHPZ23098JC5731MNYY0
78C7KGQ7780CDXG1MKTFVHHWQ32DNJ7TDFVJX4FB8ZVB6ZXK1Y6G

File diff suppressed because it is too large Load Diff

View File

@ -1020,13 +1020,10 @@ verify_reserve_balance (void *cls,
internal audit, as otherwise the balance of the 'reserves' table
is not replicated at the auditor. */
struct TALER_EXCHANGEDB_Reserve reserve;
struct TALER_EXCHANGEDB_KycStatus kyc;
reserve.pub = rs->reserve_pub;
qs = TALER_ARL_edb->reserves_get (TALER_ARL_edb->cls,
&reserve,
&kyc);
// FIXME: figure out what to do with KYC status!
&reserve);
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
{
/* If the exchange doesn't have this reserve in the summary, it

View File

@ -327,11 +327,8 @@ generate_reply_success (const struct TEH_RequestContext *rc,
if (! wc->kyc.ok)
{
/* KYC required */
return TALER_MHD_REPLY_JSON_PACK (
rc->connection,
MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
GNUNET_JSON_pack_uint64 ("payment_target_uuid",
wc->kyc.payment_target_uuid));
return TEH_RESPONSE_reply_kyc_required (rc->connection,
&wc->kyc);
}
sigs = json_array ();

View File

@ -247,7 +247,7 @@ handle_track_transaction_request (
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_INVARIANT_FAILURE,
"wire fees exceed aggregate in database");
if (GNUNET_YES == ctx->pending)
if (ctx->pending)
return TALER_MHD_REPLY_JSON_PACK (
connection,
MHD_HTTP_ACCEPTED,

View File

@ -227,7 +227,7 @@ TEH_handler_kyc_wallet (
return TALER_MHD_REPLY_JSON_PACK (
rc->connection,
MHD_HTTP_OK,
GNUNET_JSON_pack_uint64 ("payment_target_uuid",
GNUNET_JSON_pack_uint64 ("legitimization_uuid",
krc.legi_row));
}

View File

@ -28,6 +28,7 @@
#include <pthread.h>
#include "taler_dbevents.h"
#include "taler_json_lib.h"
#include "taler_kyclogic_lib.h"
#include "taler_mhd_lib.h"
#include "taler-exchange-httpd_purses_merge.h"
#include "taler-exchange-httpd_responses.h"
@ -103,10 +104,20 @@ struct PurseMergeContext
/**
* URI of the account the purse is to be merged into.
* Must be of the form 'payto://taler/$EXCHANGE_URL/RESERVE_PUB'.
* Must be of the form 'payto://taler-reserve/$EXCHANGE_URL/RESERVE_PUB'.
*/
const char *payto_uri;
/**
* Hash of the @e payto_uri.
*/
struct TALER_PaytoHashP h_payto;
/**
* KYC status of the operation.
*/
struct TALER_EXCHANGEDB_KycStatus kyc;
/**
* Base URL of the exchange provider hosting the reserve.
*/
@ -201,6 +212,46 @@ reply_merge_success (struct MHD_Connection *connection,
}
/**
* Function called to iterate over KYC-relevant
* transaction amounts for a particular time range.
* Called within a database transaction, so must
* not start a new one.
*
* @param cls a `struct PurseMergeContext`
* @param limit maximum time-range for which events
* should be fetched (timestamp in the past)
* @param cb function to call on each event found,
* events must be returned in reverse chronological
* order
* @param cb_cls closure for @a cb
*/
static void
amount_iterator (void *cls,
struct GNUNET_TIME_Absolute limit,
TALER_EXCHANGEDB_KycAmountCallback cb,
void *cb_cls)
{
struct PurseMergeContext *pcc = cls;
enum GNUNET_DB_QueryStatus qs;
cb (cb_cls,
&pcc->target_amount,
GNUNET_TIME_absolute_get ());
qs = TEH_plugin->select_merge_amounts_for_kyc_check (
TEH_plugin->cls,
&pcc->h_payto,
limit,
cb,
cb_cls);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Got %d additional transactions for this merge and limit %llu\n",
qs,
(unsigned long long) limit.abs_value_us);
GNUNET_break (qs >= 0);
}
/**
* Execute database transaction for /purses/$PID/merge. Runs the transaction
* logic; IF it returns a non-error code, the transaction logic MUST NOT queue
@ -224,9 +275,26 @@ merge_transaction (void *cls,
bool in_conflict = true;
bool no_balance = true;
bool no_partner = true;
bool no_kyc = true;
bool no_reserve = true;
const char *required;
required = TALER_KYCLOGIC_kyc_test_required (
TALER_KYCLOGIC_KYC_TRIGGER_P2P_RECEIVE,
&pcc->h_payto,
TEH_plugin->select_satisfied_kyc_processes,
TEH_plugin->cls,
&amount_iterator,
pcc);
if (NULL != required)
{
pcc->kyc.ok = false;
return TEH_plugin->insert_kyc_requirement_for_account (
TEH_plugin->cls,
required,
&pcc->h_payto,
&pcc->kyc.payment_target_uuid);
}
pcc->kyc.ok = true;
qs = TEH_plugin->do_purse_merge (
TEH_plugin->cls,
pcc->purse_pub,
@ -235,11 +303,9 @@ merge_transaction (void *cls,
&pcc->reserve_sig,
pcc->provider_url,
&pcc->reserve_pub,
TEH_KYC_NONE != TEH_kyc_config.mode,
&no_partner,
&no_balance,
&no_reserve,
&no_kyc,
&in_conflict);
if (qs < 0)
{
@ -272,17 +338,6 @@ merge_transaction (void *cls,
NULL);
return GNUNET_DB_STATUS_HARD_ERROR;
}
if ( (no_kyc) &&
(TEH_KYC_NONE != TEH_kyc_config.mode) )
{
*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 =
@ -333,6 +388,7 @@ merge_transaction (void *cls,
GNUNET_free (partner_url);
return GNUNET_DB_STATUS_HARD_ERROR;
}
return qs;
}
@ -434,7 +490,6 @@ TEH_handler_purses_merge (
TALER_EC_GENERIC_PARAMETER_MALFORMED,
"payto_uri");
}
http = (0 == strncmp (pcc.payto_uri,
"payto://taler-reserve+http/",
strlen ("payto://taler-reserve+http/")));
@ -477,6 +532,8 @@ TEH_handler_purses_merge (
}
slash++;
}
TALER_payto_hash (pcc.payto_uri,
&pcc.h_payto);
if (0 == strcmp (pcc.provider_url,
TEH_base_url))
{
@ -615,6 +672,12 @@ TEH_handler_purses_merge (
}
}
GNUNET_free (pcc.provider_url);
if (! pcc.kyc.ok)
return TEH_RESPONSE_reply_kyc_required (connection,
&pcc.kyc);
{
struct TALER_PurseEventP rep = {
.header.size = htons (sizeof (rep)),
@ -630,7 +693,6 @@ TEH_handler_purses_merge (
0);
}
GNUNET_free (pcc.provider_url);
/* generate regular response */
return reply_merge_success (connection,
&pcc);

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2014-2021 Taler Systems SA
Copyright (C) 2014-2022 Taler Systems SA
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

View File

@ -27,6 +27,7 @@
#include <microhttpd.h>
#include <pthread.h>
#include "taler_json_lib.h"
#include "taler_kyclogic_lib.h"
#include "taler_mhd_lib.h"
#include "taler-exchange-httpd_reserves_purse.h"
#include "taler-exchange-httpd_responses.h"
@ -100,6 +101,16 @@ struct ReservePurseContext
*/
struct TEH_PurseDetails pd;
/**
* Hash of the @e payto_uri.
*/
struct TALER_PaytoHashP h_payto;
/**
* KYC status of the operation.
*/
struct TALER_EXCHANGEDB_KycStatus kyc;
/**
* Minimum age for deposits into this purse.
*/
@ -118,6 +129,46 @@ struct ReservePurseContext
};
/**
* Function called to iterate over KYC-relevant
* transaction amounts for a particular time range.
* Called within a database transaction, so must
* not start a new one.
*
* @param cls a `struct ReservePurseContext`
* @param limit maximum time-range for which events
* should be fetched (timestamp in the past)
* @param cb function to call on each event found,
* events must be returned in reverse chronological
* order
* @param cb_cls closure for @a cb
*/
static void
amount_iterator (void *cls,
struct GNUNET_TIME_Absolute limit,
TALER_EXCHANGEDB_KycAmountCallback cb,
void *cb_cls)
{
struct ReservePurseContext *rpc = cls;
enum GNUNET_DB_QueryStatus qs;
cb (cb_cls,
&rpc->deposit_total,
GNUNET_TIME_absolute_get ());
qs = TEH_plugin->select_merge_amounts_for_kyc_check (
TEH_plugin->cls,
&rpc->h_payto,
limit,
cb,
cb_cls);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Got %d additional transactions for this merge and limit %llu\n",
qs,
(unsigned long long) limit.abs_value_us);
GNUNET_break (qs >= 0);
}
/**
* Execute database transaction for /reserves/$PID/purse. Runs the transaction
* logic; IF it returns a non-error code, the transaction logic MUST NOT queue
@ -139,6 +190,26 @@ purse_transaction (void *cls,
struct ReservePurseContext *rpc = cls;
enum GNUNET_DB_QueryStatus qs;
const char *required;
required = TALER_KYCLOGIC_kyc_test_required (
TALER_KYCLOGIC_KYC_TRIGGER_P2P_RECEIVE,
&rpc->h_payto,
TEH_plugin->select_satisfied_kyc_processes,
TEH_plugin->cls,
&amount_iterator,
rpc);
if (NULL != required)
{
rpc->kyc.ok = false;
return TEH_plugin->insert_kyc_requirement_for_account (
TEH_plugin->cls,
required,
&rpc->h_payto,
&rpc->kyc.payment_target_uuid);
}
rpc->kyc.ok = true;
{
bool in_conflict = true;
@ -230,7 +301,6 @@ purse_transaction (void *cls,
bool in_conflict = true;
bool insufficient_funds = true;
bool no_reserve = true;
bool no_kyc = true;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Creating purse with flags %d\n",
@ -246,10 +316,8 @@ purse_transaction (void *cls,
? NULL
: &rpc->gf->fees.purse,
rpc->reserve_pub,
TEH_KYC_NONE != TEH_kyc_config.mode,
&in_conflict,
&no_reserve,
&no_kyc,
&insufficient_funds);
if (qs < 0)
{
@ -322,17 +390,6 @@ purse_transaction (void *cls,
TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN));
return GNUNET_DB_STATUS_HARD_ERROR;
}
if ( (no_kyc) &&
(TEH_KYC_NONE != TEH_kyc_config.mode) )
{
*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
@ -472,6 +529,15 @@ TEH_handler_reserves_purse (
return MHD_YES; /* failure */
}
}
{
char *payto_uri;
payto_uri = TALER_reserve_make_payto (TEH_base_url,
reserve_pub);
TALER_payto_hash (payto_uri,
&rpc.h_payto);
GNUNET_free (payto_uri);
}
GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (TEH_currency,
&rpc.deposit_total));
@ -641,6 +707,9 @@ TEH_handler_reserves_purse (
}
}
if (! rpc.kyc.ok)
return TEH_RESPONSE_reply_kyc_required (connection,
&rpc.kyc);
/* generate regular response */
{
MHD_RESULT res;

View File

@ -53,11 +53,6 @@ struct ReserveStatusContext
*/
struct TALER_EXCHANGEDB_ReserveHistory *rh;
/**
* Current KYC status.
*/
struct TALER_EXCHANGEDB_KycStatus kyc;
/**
* Sum of incoming transactions within the returned history.
* (currently not used).
@ -102,8 +97,6 @@ reply_reserve_status_success (struct MHD_Connection *connection,
MHD_HTTP_OK,
TALER_JSON_pack_amount ("balance",
&rhc->balance),
GNUNET_JSON_pack_bool ("kyc_passed",
rhc->kyc.ok),
GNUNET_JSON_pack_array_steal ("history",
json_history));
}
@ -133,20 +126,6 @@ reserve_status_transaction (void *cls,
struct ReserveStatusContext *rsc = cls;
enum GNUNET_DB_QueryStatus qs;
qs = TEH_plugin->inselect_wallet_kyc_status (TEH_plugin->cls,
rsc->reserve_pub,
&rsc->kyc);
if (qs < 0)
{
if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
return qs;
GNUNET_break (0);
*mhd_ret = TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_FETCH_FAILED,
"inselect_wallet_status");
return qs;
}
qs = TEH_plugin->get_reserve_status (TEH_plugin->cls,
rsc->reserve_pub,
&rsc->balance_in,

View File

@ -977,4 +977,16 @@ TEH_RESPONSE_reply_purse_created (
}
MHD_RESULT
TEH_RESPONSE_reply_kyc_required (struct MHD_Connection *connection,
const struct TALER_EXCHANGEDB_KycStatus *kyc)
{
return TALER_MHD_REPLY_JSON_PACK (
connection,
MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
GNUNET_JSON_pack_uint64 ("legitimization_uuid",
kyc->payment_target_uuid));
}
/* end of taler-exchange-httpd_responses.c */

View File

@ -74,6 +74,19 @@ TEH_RESPONSE_reply_reserve_insufficient_balance (
const struct TALER_ReservePublicKeyP *reserve_pub);
/**
* Send information that a KYC check must be
* satisfied to proceed to client.
*
* @param connection connection to the client
* @param pcc details about the request that succeeded
* @return MHD result code
*/
MHD_RESULT
TEH_RESPONSE_reply_kyc_required (struct MHD_Connection *connection,
const struct TALER_EXCHANGEDB_KycStatus *kyc);
/**
* Send assertion that the given denomination key hash
* is not usable (typically expired) at this time.

View File

@ -490,13 +490,8 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
GNUNET_JSON_parse_free (spec);
if (! wc.kyc.ok)
{
return TALER_MHD_REPLY_JSON_PACK (
rc->connection,
MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
GNUNET_JSON_pack_uint64 ("payment_target_uuid",
wc.kyc.payment_target_uuid));
}
return TEH_RESPONSE_reply_kyc_required (rc->connection,
&wc.kyc);
{
MHD_RESULT ret;

View File

@ -572,23 +572,6 @@ prepare_statements (struct PostgresClosure *pg)
" FROM denominations"
" WHERE denom_pub_hash=$1);",
1),
/* Used in #postgres_reserves_get() */
GNUNET_PQ_make_prepare (
"reserves_get_with_kyc",
"SELECT"
" current_balance_val"
",current_balance_frac"
",expiration_date"
",gc_date"
",kyc_ok"
",wire_target_serial_id AS payment_target_uuid"
" FROM reserves"
" JOIN reserves_in ri USING (reserve_pub)"
" JOIN wire_targets wt "
" ON (ri.wire_source_h_payto = wt.wire_target_h_payto)"
" WHERE reserve_pub=$1"
" LIMIT 1;",
1),
/* Used in #postgres_reserves_get_origin() */
GNUNET_PQ_make_prepare (
"get_h_wire_source_of_reserve",
@ -658,7 +641,7 @@ prepare_statements (struct PostgresClosure *pg)
" LIMIT 1)"
" RETURNING h_payto;",
1),
/* Used in #reserves_get() */
/* Used in #postgres_reserves_get() */
GNUNET_PQ_make_prepare (
"reserves_get",
"SELECT"
@ -4497,11 +4480,10 @@ 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, $7, $8);",
" ($1, $2, $3, $4, $5, $6, $7);",
7),
/* Used in #postgres_do_reserve_purse() */
GNUNET_PQ_make_prepare (
@ -4509,11 +4491,10 @@ prepare_statements (struct PostgresClosure *pg)
"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, $9, $10);",
10),
" ($1, $2, $3, $4, $5, $6, $7, $8, $9);",
9),
/* Used in #postgres_select_purse_merge */
GNUNET_PQ_make_prepare (
"select_purse_merge",
@ -5721,13 +5702,11 @@ postgres_iterate_auditor_denominations (
* @param[in,out] reserve the reserve data. The public key of the reserve should be
* set in this structure; it is used to query the database. The balance
* and expiration are then filled accordingly.
* @param[out] kyc set to the KYC status of the reserve
* @return transaction status
*/
static enum GNUNET_DB_QueryStatus
postgres_reserves_get (void *cls,
struct TALER_EXCHANGEDB_Reserve *reserve,
struct TALER_EXCHANGEDB_KycStatus *kyc)
struct TALER_EXCHANGEDB_Reserve *reserve)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
@ -5741,15 +5720,11 @@ postgres_reserves_get (void *cls,
&reserve->expiry),
GNUNET_PQ_result_spec_timestamp ("gc_date",
&reserve->gc),
GNUNET_PQ_result_spec_uint64 ("payment_target_uuid",
&kyc->payment_target_uuid),
GNUNET_PQ_result_spec_bool ("kyc_ok",
&kyc->ok),
GNUNET_PQ_result_spec_end
};
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"reserves_get_with_kyc",
"reserves_get",
params,
rs);
}
@ -5871,39 +5846,6 @@ postgres_drain_kyc_alert (void *cls,
}
/**
* Get the @a kyc status and @a h_payto by UUID.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param h_payto set to the hash of the account's payto URI (unsalted)
* @param[out] kyc set to the KYC status of the account
* @return transaction status
*/
static enum GNUNET_DB_QueryStatus
postgres_select_kyc_status (void *cls,
const struct TALER_PaytoHashP *h_payto,
struct TALER_EXCHANGEDB_KycStatus *kyc)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (h_payto),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_uint64 ("wire_target_serial_id",
&kyc->payment_target_uuid),
GNUNET_PQ_result_spec_bool ("kyc_ok",
&kyc->ok),
GNUNET_PQ_result_spec_end
};
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"select_kyc_status_by_payto",
params,
rs);
}
/**
* Compute the hash of the @a payto_uri and use it to get the KYC status for a
* wallet. If the status is unknown, inserts a new status record (hence
@ -5971,76 +5913,6 @@ inselect_account_kyc_status (
}
/**
* Get the KYC status for a wallet. If the status is unknown,
* inserts a new status record (hence INsertSELECT).
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param reserve_pub public key of the wallet
* @param[out] kyc set to the KYC status of the wallet
* @return transaction status
*/
static enum GNUNET_DB_QueryStatus
postgres_inselect_wallet_kyc_status (
void *cls,
const struct TALER_ReservePublicKeyP *reserve_pub,
struct TALER_EXCHANGEDB_KycStatus *kyc)
{
struct PostgresClosure *pg = cls;
char *payto_uri;
enum GNUNET_DB_QueryStatus qs;
struct TALER_PaytoHashP h_payto;
payto_uri = TALER_reserve_make_payto (pg->exchange_url,
reserve_pub);
qs = inselect_account_kyc_status (pg,
payto_uri,
&h_payto,
kyc);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Wire account for `%s' is %llu\n",
payto_uri,
(unsigned long long) kyc->payment_target_uuid);
GNUNET_free (payto_uri);
return qs;
}
/**
* Get the summary of a reserve.
*
* @param cls the `struct PostgresClosure` with the plugin-specific state
* @param[in,out] reserve the reserve data. The public key of the reserve should be
* set in this structure; it is used to query the database. The balance
* and expiration are then filled accordingly.
* @return transaction status
*/
static enum GNUNET_DB_QueryStatus
reserves_get_internal (void *cls,
struct TALER_EXCHANGEDB_Reserve *reserve)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (&reserve->pub),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
TALER_PQ_RESULT_SPEC_AMOUNT ("current_balance",
&reserve->balance),
GNUNET_PQ_result_spec_timestamp ("expiration_date",
&reserve->expiry),
GNUNET_PQ_result_spec_timestamp ("gc_date",
&reserve->gc),
GNUNET_PQ_result_spec_end
};
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"reserves_get",
params,
rs);
}
/**
* Updates a reserve with the data from the given reserve structure.
*
@ -6248,7 +6120,7 @@ postgres_reserves_in_insert (void *cls,
{
enum GNUNET_DB_QueryStatus reserve_exists;
reserve_exists = reserves_get_internal (pg,
reserve_exists = postgres_reserves_get (pg,
&reserve);
switch (reserve_exists)
{
@ -10610,7 +10482,7 @@ postgres_insert_reserve_closed (
/* update reserve balance */
reserve.pub = *reserve_pub;
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
(qs = reserves_get_internal (cls,
(qs = postgres_reserves_get (cls,
&reserve)))
{
/* Existence should have been checked before we got here... */
@ -16316,11 +16188,9 @@ postgres_get_purse_deposit (
* @param reserve_sig signature of the reserve affirming the merge
* @param partner_url URL of the partner exchange, can be NULL if the reserves lives with us
* @param reserve_pub public key of the reserve to credit
* @param require_kyc true if we should check for KYC
* @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
*/
@ -16333,11 +16203,9 @@ postgres_do_purse_merge (
const struct TALER_ReserveSignatureP *reserve_sig,
const char *partner_url,
const struct TALER_ReservePublicKeyP *reserve_pub,
bool require_kyc,
bool *no_partner,
bool *no_balance,
bool *no_reserve,
bool *no_kyc,
bool *in_conflict)
{
struct PostgresClosure *pg = cls;
@ -16352,7 +16220,6 @@ postgres_do_purse_merge (
: GNUNET_PQ_query_param_string (partner_url),
GNUNET_PQ_query_param_auto_from_type (reserve_pub),
GNUNET_PQ_query_param_auto_from_type (&h_payto),
GNUNET_PQ_query_param_bool (require_kyc),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
@ -16360,8 +16227,6 @@ 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",
@ -16397,10 +16262,8 @@ postgres_do_purse_merge (
* @param reserve_sig signature of the reserve affirming the merge
* @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 require_kyc true if we should check for KYC
* @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
*/
@ -16413,10 +16276,8 @@ postgres_do_reserve_purse (
const struct TALER_ReserveSignatureP *reserve_sig,
const struct TALER_Amount *purse_fee,
const struct TALER_ReservePublicKeyP *reserve_pub,
bool require_kyc,
bool *in_conflict,
bool *no_reserve,
bool *no_kyc,
bool *insufficient_funds)
{
struct PostgresClosure *pg = cls;
@ -16433,7 +16294,6 @@ postgres_do_reserve_purse (
: purse_fee),
GNUNET_PQ_query_param_auto_from_type (reserve_pub),
GNUNET_PQ_query_param_auto_from_type (&h_payto),
GNUNET_PQ_query_param_bool (require_kyc),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
@ -16441,8 +16301,6 @@ 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
@ -17488,12 +17346,10 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
plugin->iterate_active_auditors = &postgres_iterate_active_auditors;
plugin->iterate_auditor_denominations =
&postgres_iterate_auditor_denominations;
plugin->select_kyc_status = &postgres_select_kyc_status;
plugin->reserves_get = &postgres_reserves_get;
plugin->reserves_get_origin = &postgres_reserves_get_origin;
plugin->set_kyc_ok = &postgres_set_kyc_ok;
plugin->drain_kyc_alert = &postgres_drain_kyc_alert;
plugin->inselect_wallet_kyc_status = &postgres_inselect_wallet_kyc_status;
plugin->reserves_in_insert = &postgres_reserves_in_insert;
plugin->get_withdraw_info = &postgres_get_withdraw_info;
plugin->do_withdraw = &postgres_do_withdraw;

View File

@ -1648,10 +1648,8 @@ CREATE OR REPLACE FUNCTION exchange_do_purse_merge(
IN in_partner_url VARCHAR,
IN in_reserve_pub BYTEA,
IN in_wallet_h_payto BYTEA,
IN in_require_kyc BOOLEAN,
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
@ -1686,7 +1684,6 @@ ELSE
THEN
out_no_partner=TRUE;
out_conflict=FALSE;
out_no_kyc=FALSE;
out_no_reserve=FALSE;
RETURN;
END IF;
@ -1715,7 +1712,6 @@ IF NOT FOUND
THEN
out_no_balance=TRUE;
out_conflict=FALSE;
out_no_kyc=FALSE;
out_no_reserve=FALSE;
RETURN;
END IF;
@ -1749,14 +1745,12 @@ 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;
@ -1764,33 +1758,16 @@ out_conflict=FALSE;
ASSERT NOT my_finished, 'internal invariant failed';
IF ( (in_partner_url IS NULL) AND
(in_require_kyc) )
PERFORM
FROM exchange.reserves
WHERE reserve_pub=in_reserve_pub;
IF NOT FOUND
THEN
-- Need to do KYC check.
SELECT NOT kyc_passed
INTO out_no_kyc
FROM exchange.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;
out_no_reserve=TRUE;
RETURN;
END IF;
out_no_reserve=FALSE;
-- Store account merge signature.
@ -1850,7 +1827,7 @@ RETURN;
END $$;
COMMENT ON FUNCTION exchange_do_purse_merge(BYTEA, BYTEA, INT8, BYTEA, VARCHAR, BYTEA, BYTEA, BOOLEAN)
COMMENT ON FUNCTION exchange_do_purse_merge(BYTEA, BYTEA, INT8, BYTEA, VARCHAR, BYTEA, BYTEA)
IS 'Checks that the partner exists, the purse has not been merged with a different reserve and that the purse is full. If so, persists the merge data and either merges the purse with the reserve or marks it as ready for the taler-exchange-router. Caller MUST abort the transaction on failures so as to not persist data by accident.';
@ -1864,9 +1841,7 @@ CREATE OR REPLACE FUNCTION exchange_do_reserve_purse(
IN in_purse_fee_frac INT4,
IN in_reserve_pub BYTEA,
IN in_wallet_h_payto BYTEA,
IN in_require_kyc BOOLEAN,
OUT out_no_funds BOOLEAN,
OUT out_no_kyc BOOLEAN,
OUT out_no_reserve BOOLEAN,
OUT out_conflict BOOLEAN)
LANGUAGE plpgsql
@ -1901,7 +1876,6 @@ 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;
@ -1910,38 +1884,28 @@ THEN
-- "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
PERFORM
FROM exchange.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 AND in_require_kyc)
THEN
out_no_funds=FALSE;
RETURN;
END IF;
IF (in_reserve_quota)
THEN
-- Increment active purses per reserve (and check this is allowed)
UPDATE reserves
SET purses_active=purses_active+1
,kyc_required=TRUE
WHERE reserve_pub=in_reserve_pub
AND purses_active < purses_allowed;
IF NOT FOUND
@ -1965,7 +1929,6 @@ ELSE
THEN 1
ELSE 0
END
,kyc_required=TRUE
WHERE reserve_pub=in_reserve_pub
AND ( (current_balance_val > in_purse_fee_val) OR
( (current_balance_frac >= in_purse_fee_frac) AND
@ -1994,7 +1957,7 @@ INSERT INTO exchange.account_merges
END $$;
COMMENT ON FUNCTION exchange_do_reserve_purse(BYTEA, BYTEA, INT8, BYTEA, BOOLEAN, INT8, INT4, BYTEA, BYTEA, BOOLEAN)
COMMENT ON FUNCTION exchange_do_reserve_purse(BYTEA, BYTEA, INT8, BYTEA, BOOLEAN, INT8, INT4, BYTEA, BYTEA)
IS 'Create a purse for a reserve.';

View File

@ -220,18 +220,15 @@ check_reserve (const struct TALER_ReservePublicKeyP *pub,
const char *currency)
{
struct TALER_EXCHANGEDB_Reserve reserve;
struct TALER_EXCHANGEDB_KycStatus kyc;
reserve.pub = *pub;
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->reserves_get (plugin->cls,
&reserve,
&kyc));
&reserve));
FAILIF (value != reserve.balance.value);
FAILIF (fraction != reserve.balance.fraction);
FAILIF (0 != strcmp (currency,
reserve.balance.currency));
FAILIF (kyc.ok);
return GNUNET_OK;
drop:
return GNUNET_SYSERR;
@ -1001,15 +998,10 @@ test_wire_out (const struct TALER_EXCHANGEDB_Deposit *deposit)
}
{
struct TALER_ReservePublicKeyP rpub;
struct TALER_EXCHANGEDB_KycStatus kyc;
memset (&rpub,
44,
sizeof (rpub));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->inselect_wallet_kyc_status (plugin->cls,
&rpub,
&kyc));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->store_wire_transfer_out (plugin->cls,
wire_out_date,
@ -1755,7 +1747,6 @@ run (void *cls)
struct TALER_EXCHANGEDB_Reserve pre_reserve;
struct TALER_EXCHANGEDB_Reserve post_reserve;
struct TALER_Amount delta;
struct TALER_EXCHANGEDB_KycStatus kyc;
bool recoup_ok;
bool internal_failure;
struct GNUNET_TIME_Timestamp recoup_timestamp
@ -1764,8 +1755,7 @@ run (void *cls)
pre_reserve.pub = reserve_pub;
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->reserves_get (plugin->cls,
&pre_reserve,
&kyc));
&pre_reserve));
FAILIF (! TALER_amount_is_zero (&pre_reserve.balance));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->do_recoup (plugin->cls,
@ -1783,8 +1773,7 @@ run (void *cls)
post_reserve.pub = reserve_pub;
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->reserves_get (plugin->cls,
&post_reserve,
&kyc));
&post_reserve));
FAILIF (0 >=
TALER_amount_subtract (&delta,
&post_reserve.balance,

View File

@ -1883,11 +1883,6 @@ struct TALER_EXCHANGE_ReserveStatus
*/
unsigned int history_len;
/**
* KYC passed?
*/
bool kyc_ok;
} ok;
} details;
@ -2138,7 +2133,7 @@ struct TALER_EXCHANGE_WithdrawResponse
struct TALER_EXCHANGE_PrivateCoinDetails success;
/**
* Details if the status is #MHD_HTTP_ACCEPTED.
* Details if the status is #MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS.
*/
struct
{
@ -2147,7 +2142,7 @@ struct TALER_EXCHANGE_WithdrawResponse
* to check for its KYC status.
*/
uint64_t payment_target_uuid;
} accepted;
} unavailable_for_legal_reasons;
/**
* Details if the status is #MHD_HTTP_CONFLICT.
@ -4875,6 +4870,19 @@ struct TALER_EXCHANGE_AccountMergeResponse
} success;
/**
* Details if the status is #MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS.
*/
struct
{
/**
* Payment target that the merchant should use
* to check for its KYC status.
*/
uint64_t payment_target_uuid;
} unavailable_for_legal_reasons;
} details;
};
@ -4970,6 +4978,19 @@ struct TALER_EXCHANGE_PurseCreateMergeResponse
{
} success;
/**
* Details if the status is #MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS.
*/
struct
{
/**
* Payment target that the merchant should use
* to check for its KYC status.
*/
uint64_t payment_target_uuid;
} unavailable_for_legal_reasons;
} details;
};

View File

@ -2273,50 +2273,6 @@ struct TALER_EXCHANGEDB_CsRevealFreshCoinData
};
/**
* Types of operations that require KYC checks.
* @deprecated FIXME - remove with new KYC logic
*/
enum TALER_EXCHANGEDB_KycType
{
/**
* It is unclear for which type of KYC operation
* this information is.
*/
TALER_EXCHANGEDB_KYC_UNKNOWN = 0,
/**
* KYC to be applied for simple withdraws without
* the involvement of wallet-to-wallet payments.
* Tied to the payto:// of the debited account.
*/
TALER_EXCHANGEDB_KYC_WITHDRAW = 1,
/**
* KYC to be applied for simple deposits to a
* merchant's bank account. Tied to the payto://
* of the credited account.
*/
TALER_EXCHANGEDB_KYC_DEPOSIT = 2,
/**
* KYC that is self-applied by a wallet that is exceeding the amount
* threshold. Tied to the reserve-account public key that identifies the
* funds-holding wallet.
*/
TALER_EXCHANGEDB_KYC_BALANCE = 3,
/**
* KYC that is triggered upon wallet-to-wallet
* payments for the recipient of funds. Tied to the
* reserve public key that identifies the receiving
* wallet.
*/
TALER_EXCHANGEDB_KYC_W2W = 4
};
/**
* Generic KYC status for some operation.
* @deprecated FIXME - remove with new KYC logic
@ -2330,12 +2286,6 @@ struct TALER_EXCHANGEDB_KycStatus
// FIXME: rename to 'legitimization_uuid'
uint64_t payment_target_uuid;
/**
* What kind of KYC operation is this?
*/
// FIXME: kill!
enum TALER_EXCHANGEDB_KycType type;
/**
* True if the KYC status is "satisfied".
*/
@ -3110,13 +3060,11 @@ struct TALER_EXCHANGEDB_Plugin
* @param[in,out] reserve the reserve data. The public key of the reserve should be set
* in this structure; it is used to query the database. The balance
* and expiration are then filled accordingly.
* @param[out] kyc set to the KYC status of the reserve
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
(*reserves_get)(void *cls,
struct TALER_EXCHANGEDB_Reserve *reserve,
struct TALER_EXCHANGEDB_KycStatus *kyc);
struct TALER_EXCHANGEDB_Reserve *reserve);
/**
@ -3162,36 +3110,6 @@ struct TALER_EXCHANGEDB_Plugin
struct TALER_PaytoHashP *h_payto);
/**
* Get the @a kyc status and @a h_payto by UUID.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param h_payto set to the hash of the account's payto URI (unsalted)
* @param[out] kyc set to the KYC status of the account
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
(*select_kyc_status)(void *cls,
const struct TALER_PaytoHashP *h_payto,
struct TALER_EXCHANGEDB_KycStatus *kyc);
/**
* Get the KYC status for a wallet. If the status is unknown,
* inserts a new status record (hence INsertSELECT).
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param reserve_pub public key of the wallet
* @param[out] kyc set to the KYC status of the wallet
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
(*inselect_wallet_kyc_status)(
void *cls,
const struct TALER_ReservePublicKeyP *reserve_pub,
struct TALER_EXCHANGEDB_KycStatus *kyc);
/**
* Insert a incoming transaction into reserves. New reserves are
* also created through this function.
@ -5496,11 +5414,9 @@ struct TALER_EXCHANGEDB_Plugin
* @param reserve_sig signature of the reserve affirming the merge
* @param partner_url URL of the partner exchange, can be NULL if the reserves lives with us
* @param reserve_pub public key of the reserve to credit
* @param require_kyc true if we should check for KYC
* @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
*/
@ -5513,11 +5429,9 @@ struct TALER_EXCHANGEDB_Plugin
const struct TALER_ReserveSignatureP *reserve_sig,
const char *partner_url,
const struct TALER_ReservePublicKeyP *reserve_pub,
bool require_kyc,
bool *no_partner,
bool *no_balance,
bool *no_reserve,
bool *no_kyc,
bool *in_conflict);
@ -5533,10 +5447,8 @@ struct TALER_EXCHANGEDB_Plugin
* @param reserve_sig signature of the reserve affirming the merge
* @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 require_kyc true if we should check for KYC
* @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
*/
@ -5549,10 +5461,8 @@ struct TALER_EXCHANGEDB_Plugin
const struct TALER_ReserveSignatureP *reserve_sig,
const struct TALER_Amount *purse_fee,
const struct TALER_ReservePublicKeyP *reserve_pub,
bool require_kyc,
bool *in_conflict,
bool *no_reserve,
bool *no_kyc,
bool *insufficient_funds);

View File

@ -207,7 +207,7 @@ handle_reserve_batch_withdraw_finished (
case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
{
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_uint64 ("payment_target_uuid",
GNUNET_JSON_spec_uint64 ("legitimization_uuid",
&wr.details.accepted.payment_target_uuid),
GNUNET_JSON_spec_end ()
};

View File

@ -288,12 +288,12 @@ handle_reserve_batch_withdraw_finished (void *cls,
GNUNET_assert (NULL == wh->cb);
TALER_EXCHANGE_batch_withdraw2_cancel (wh);
return;
case MHD_HTTP_ACCEPTED:
case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
/* only validate reply is well-formed */
{
uint64_t ptu;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_uint64 ("payment_target_uuid",
GNUNET_JSON_spec_uint64 ("legitimization_uuid",
&ptu),
GNUNET_JSON_spec_end ()
};

View File

@ -98,7 +98,7 @@ handle_kyc_wallet_finished (void *cls,
case MHD_HTTP_OK:
{
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_uint64 ("payment_target_uuid",
GNUNET_JSON_spec_uint64 ("legitimization_uuid",
&ks.payment_target_uuid),
GNUNET_JSON_spec_end ()
};

View File

@ -295,9 +295,25 @@ handle_purse_create_with_merge_finished (void *cls,
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);
{
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_uint64 (
"legitimization_uuid",
&dr.details.unavailable_for_legal_reasons.payment_target_uuid),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (j,
spec,
NULL, NULL))
{
GNUNET_break_op (0);
dr.hr.http_status = 0;
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
break;
}
}
break;
case MHD_HTTP_INTERNAL_SERVER_ERROR:
dr.hr.ec = TALER_JSON_get_error_code (j);

View File

@ -256,6 +256,27 @@ handle_purse_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:
{
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_uint64 (
"legitimization_uuid",
&dr.details.unavailable_for_legal_reasons.payment_target_uuid),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (j,
spec,
NULL, NULL))
{
GNUNET_break_op (0);
dr.hr.http_status = 0;
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
break;
}
}
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

@ -98,8 +98,6 @@ handle_reserves_status_ok (struct TALER_EXCHANGE_ReservesStatusHandle *rsh,
struct GNUNET_JSON_Specification spec[] = {
TALER_JSON_spec_amount_any ("balance",
&rs.details.ok.balance),
GNUNET_JSON_spec_bool ("kyc_passed",
&rs.details.ok.kyc_ok),
GNUNET_JSON_spec_json ("history",
&history),
GNUNET_JSON_spec_end ()

View File

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

View File

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

View File

@ -231,6 +231,8 @@ run (void *cls,
"EUR:5.04"),
CMD_TRANSFER_TO_EXCHANGE ("p2p_create-reserve-2",
"EUR:5.01"),
CMD_TRANSFER_TO_EXCHANGE ("p2p_create-reserve-3",
"EUR:0.03"),
TALER_TESTING_cmd_reserve_poll ("p2p_poll-reserve-1",
"p2p_create-reserve-1",
"EUR:5.04",
@ -293,6 +295,17 @@ run (void *cls,
MHD_HTTP_OK,
true, /* for merge */
"purse-with-deposit"),
TALER_TESTING_cmd_purse_merge (
"purse-merge-into-reserve",
MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
"push-get-contract",
"p2p_create-reserve-1"),
TALER_TESTING_cmd_proof_kyc_oauth2 ("p2p_proof-kyc",
"purse-merge-into-reserve",
"kyc-provider-test-oauth2",
"pass",
"state",
MHD_HTTP_SEE_OTHER),
TALER_TESTING_cmd_purse_merge (
"purse-merge-into-reserve",
MHD_HTTP_OK,
@ -318,13 +331,26 @@ run (void *cls,
TALER_TESTING_cmd_end ()
};
struct TALER_TESTING_Command pull[] = {
TALER_TESTING_cmd_purse_create_with_reserve (
"purse-create-with-reserve",
MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
"{\"amount\":\"EUR:1\",\"summary\":\"ice cream\"}",
true /* upload contract */,
GNUNET_TIME_UNIT_MINUTES, /* expiration */
"p2p_create-reserve-3"),
TALER_TESTING_cmd_proof_kyc_oauth2 ("p2p_proof-kyc-pull",
"purse-create-with-reserve",
"kyc-provider-test-oauth2",
"pass",
"state",
MHD_HTTP_SEE_OTHER),
TALER_TESTING_cmd_purse_create_with_reserve (
"purse-create-with-reserve",
MHD_HTTP_OK,
"{\"amount\":\"EUR:1\",\"summary\":\"ice cream\"}",
true /* upload contract */,
GNUNET_TIME_UNIT_MINUTES, /* expiration */
"p2p_create-reserve-1"),
"p2p_create-reserve-3"),
TALER_TESTING_cmd_contract_get (
"pull-get-contract",
MHD_HTTP_OK,
@ -353,23 +379,14 @@ run (void *cls,
"pull-poll-purse-before-deposit"),
TALER_TESTING_cmd_status (
"pull-check-post-merge-reserve-balance-get",
"p2p_create-reserve-1",
"EUR:2.02",
"p2p_create-reserve-3",
"EUR:1.02",
MHD_HTTP_OK),
/* POST history doesn't yet support P2P transfers */
TALER_TESTING_cmd_reserve_status (
"push-check-post-merge-reserve-balance-post",
"p2p_create-reserve-1",
"EUR:2.02",
"p2p_create-reserve-3",
"EUR:1.02",
MHD_HTTP_OK),
/* create 2nd purse for a deposit conflict */
TALER_TESTING_cmd_purse_create_with_reserve (
"purse-create-with-reserve-2",
MHD_HTTP_OK,
"{\"amount\":\"EUR:4\",\"summary\":\"beer\"}",
true /* upload contract */,
GNUNET_TIME_UNIT_MINUTES, /* expiration */
"p2p_create-reserve-1"),
TALER_TESTING_cmd_end ()
};
@ -401,7 +418,6 @@ run (void *cls,
CONFIG_FILE),
TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys",
2),
#if 1
TALER_TESTING_cmd_batch ("withdraw",
withdraw),
TALER_TESTING_cmd_batch ("spend",
@ -412,15 +428,12 @@ run (void *cls,
withdraw_kyc),
TALER_TESTING_cmd_batch ("wallet-kyc",
wallet_kyc),
#endif
TALER_TESTING_cmd_batch ("p2p_withdraw",
p2p_withdraw),
#if 0
TALER_TESTING_cmd_batch ("push",
push),
TALER_TESTING_cmd_batch ("pull",
pull),
#endif
TALER_TESTING_cmd_end ()
};

View File

@ -91,6 +91,12 @@ REQUIRED_CHECKS = DUMMY
THRESHOLD = EUR:8
TIMEFRAME = 1d
[kyc-legitimization-merge]
OPERATION_TYPE = MERGE
REQUIRED_CHECKS = DUMMY
THRESHOLD = EUR:0
TIMEFRAME = 1d
[exchangedb-postgres]
CONFIG = "postgres:///talercheck"

View File

@ -71,6 +71,18 @@ struct PurseMergeState
*/
struct TALER_TESTING_Interpreter *is;
/**
* Hash of the payto://-URI for the reserve we are
* merging into.
*/
struct TALER_PaytoHashP h_payto;
/**
* Set to the KYC UUID *if* the exchange replied with
* a request for KYC.
*/
uint64_t kyc_uuid;
/**
* Reserve history entry that corresponds to this operation.
* Will be of type #TALER_EXCHANGE_RTT_MERGE.
@ -129,8 +141,9 @@ merge_cb (void *cls,
struct PurseMergeState *ds = cls;
ds->dh = NULL;
if (MHD_HTTP_OK == dr->hr.http_status)
switch (dr->hr.http_status)
{
case MHD_HTTP_OK:
ds->reserve_history.type = TALER_EXCHANGE_RTT_MERGE;
ds->reserve_history.amount = ds->value_after_fees;
GNUNET_assert (GNUNET_OK ==
@ -153,6 +166,12 @@ merge_cb (void *cls,
= ds->min_age;
ds->reserve_history.details.merge_details.flags
= TALER_WAMF_MODE_MERGE_FULLY_PAID_PURSE;
break;
case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
/* KYC required */
ds->kyc_uuid =
dr->details.unavailable_for_legal_reasons.payment_target_uuid;
break;
}
@ -281,6 +300,15 @@ merge_run (void *cls,
}
GNUNET_CRYPTO_eddsa_key_get_public (&ds->reserve_priv.eddsa_priv,
&ds->reserve_pub.eddsa_pub);
{
char *payto_uri;
payto_uri = TALER_reserve_make_payto (is->exchange_url,
&ds->reserve_pub);
TALER_payto_hash (payto_uri,
&ds->h_payto);
GNUNET_free (payto_uri);
}
GNUNET_CRYPTO_eddsa_key_get_public (&merge_priv->eddsa_priv,
&ds->merge_pub.eddsa_pub);
ds->merge_timestamp = GNUNET_TIME_timestamp_get ();
@ -357,6 +385,8 @@ merge_traits (void *cls,
TALER_TESTING_make_trait_reserve_pub (&ds->reserve_pub),
TALER_TESTING_make_trait_timestamp (0,
&ds->merge_timestamp),
TALER_TESTING_make_trait_payment_target_uuid (&ds->kyc_uuid),
TALER_TESTING_make_trait_h_payto (&ds->h_payto),
TALER_TESTING_trait_end ()
};

View File

@ -97,6 +97,18 @@ struct ReservePurseState
*/
struct GNUNET_TIME_Timestamp purse_expiration;
/**
* Hash of the payto://-URI for the reserve we are
* merging into.
*/
struct TALER_PaytoHashP h_payto;
/**
* Set to the KYC UUID *if* the exchange replied with
* a request for KYC.
*/
uint64_t kyc_uuid;
/**
* Contract terms for the purse.
*/
@ -149,6 +161,14 @@ purse_cb (void *cls,
TALER_TESTING_interpreter_fail (ds->is);
return;
}
switch (dr->hr.http_status)
{
case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
/* KYC required */
ds->kyc_uuid =
dr->details.unavailable_for_legal_reasons.payment_target_uuid;
break;
}
TALER_TESTING_interpreter_next (ds->is);
}
@ -194,6 +214,17 @@ purse_run (void *cls,
GNUNET_CRYPTO_ecdhe_key_create (&ds->contract_priv.ecdhe_priv);
ds->purse_expiration = GNUNET_TIME_absolute_to_timestamp (
GNUNET_TIME_relative_to_absolute (ds->expiration_rel));
{
char *payto_uri;
payto_uri = TALER_reserve_make_payto (is->exchange_url,
&ds->reserve_pub);
TALER_payto_hash (payto_uri,
&ds->h_payto);
GNUNET_free (payto_uri);
}
GNUNET_assert (0 ==
json_object_set_new (
ds->contract_terms,
@ -278,6 +309,8 @@ purse_traits (void *cls,
TALER_TESTING_make_trait_reserve_priv (&ds->reserve_priv),
TALER_TESTING_make_trait_reserve_pub (&ds->reserve_pub),
TALER_TESTING_make_trait_reserve_sig (&ds->reserve_sig),
TALER_TESTING_make_trait_payment_target_uuid (&ds->kyc_uuid),
TALER_TESTING_make_trait_h_payto (&ds->h_payto),
TALER_TESTING_trait_end ()
};

View File

@ -304,10 +304,6 @@ reserve_withdraw_cb (void *cls,
GNUNET_YES));
}
break;
case MHD_HTTP_ACCEPTED:
/* nothing to check */
ws->kyc_uuid = wr->details.accepted.payment_target_uuid;
break;
case MHD_HTTP_FORBIDDEN:
/* nothing to check */
break;
@ -322,6 +318,8 @@ reserve_withdraw_cb (void *cls,
break;
case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
/* KYC required */
ws->kyc_uuid =
wr->details.unavailable_for_legal_reasons.payment_target_uuid;
break;
default:
/* Unsupported status code (by test harness) */
@ -545,8 +543,10 @@ withdraw_traits (void *cls,
(const char **) &ws->reserve_payto_uri),
TALER_TESTING_make_trait_exchange_url (
(const char **) &ws->exchange_url),
TALER_TESTING_make_trait_age_commitment_proof (0, ws->age_commitment_proof),
TALER_TESTING_make_trait_h_age_commitment (0, ws->h_age_commitment),
TALER_TESTING_make_trait_age_commitment_proof (0,
ws->age_commitment_proof),
TALER_TESTING_make_trait_h_age_commitment (0,
ws->h_age_commitment),
TALER_TESTING_trait_end ()
};