avoid duplication

This commit is contained in:
Christian Grothoff 2021-11-15 14:39:18 +01:00
parent c67df63699
commit 0325a79631
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
5 changed files with 204 additions and 90 deletions

@ -1 +1 @@
Subproject commit 15a8cae393bf35f95ae15836c4ec4b2b22e42604 Subproject commit 597e273cc73122ba5cd0023f37b43b4f3784fe0c

View File

@ -27,6 +27,7 @@
#include "taler_json_lib.h" #include "taler_json_lib.h"
#include "taler_mhd_lib.h" #include "taler_mhd_lib.h"
#include "taler_signatures.h" #include "taler_signatures.h"
#include "taler_dbevents.h"
#include "taler-exchange-httpd_keys.h" #include "taler-exchange-httpd_keys.h"
#include "taler-exchange-httpd_kyc-wallet.h" #include "taler-exchange-httpd_kyc-wallet.h"
#include "taler-exchange-httpd_responses.h" #include "taler-exchange-httpd_responses.h"
@ -187,6 +188,42 @@ kyc_check (void *cls,
} }
/**
* Function called on events received from Postgres.
* Wakes up long pollers.
*
* @param cls the `struct TEH_RequestContext *`
* @param extra additional event data provided
* @param extra_size number of bytes in @a extra
*/
static void
db_event_cb (void *cls,
const void *extra,
size_t extra_size)
{
struct TEH_RequestContext *rc = cls;
struct KycPoller *kyp = rc->rh_ctx;
struct GNUNET_AsyncScopeSave old_scope;
(void) extra;
(void) extra_size;
if (! kyp->suspended)
return; /* event triggered while main transaction
was still running, or got multiple wake-up events */
kyp->suspended = false;
GNUNET_async_scope_enter (&rc->async_scope_id,
&old_scope);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Resuming from long-polling on KYC status\n");
GNUNET_CONTAINER_DLL_remove (kyp_head,
kyp_tail,
kyp);
MHD_resume_connection (kyp->connection);
TALER_MHD_daemon_trigger ();
GNUNET_async_scope_restore (&old_scope);
}
MHD_RESULT MHD_RESULT
TEH_handler_kyc_check ( TEH_handler_kyc_check (
struct TEH_RequestContext *rc, struct TEH_RequestContext *rc,
@ -195,6 +232,7 @@ TEH_handler_kyc_check (
struct KycPoller *kyp = rc->rh_ctx; struct KycPoller *kyp = rc->rh_ctx;
MHD_RESULT res; MHD_RESULT res;
enum GNUNET_GenericReturnValue ret; enum GNUNET_GenericReturnValue ret;
struct GNUNET_TIME_Absolute now;
if (NULL == kyp) if (NULL == kyp)
{ {
@ -285,87 +323,120 @@ TEH_handler_kyc_check (
NULL, NULL,
NULL, NULL,
0); 0);
if ( (NULL == kyp->eh) &&
GNUNET_TIME_absolute_is_future (kyp->timeout) )
{ {
struct GNUNET_TIME_Absolute now; struct TALER_KycCompletedEventP rep = {
.header.size = htons (sizeof (rep)),
.header.type = htons (TALER_DBEVENT_EXCHANGE_KYC_COMPLETED),
.h_payto = kyp->auth_h_payto
};
now = GNUNET_TIME_absolute_get (); GNUNET_log (GNUNET_ERROR_TYPE_INFO,
(void) GNUNET_TIME_round_abs (&now); "Starting DB event listening\n");
ret = TEH_DB_run_transaction (rc->connection, kyp->eh = TEH_plugin->event_listen (
"kyc check", TEH_plugin->cls,
&res, GNUNET_TIME_absolute_get_remaining (kyp->timeout),
&kyc_check, &rep.header,
kyp); &db_event_cb,
if (GNUNET_SYSERR == ret) rc);
return res; }
if (0 !=
GNUNET_memcmp (&kyp->h_payto, now = GNUNET_TIME_absolute_get ();
&kyp->auth_h_payto)) (void) GNUNET_TIME_round_abs (&now);
ret = TEH_DB_run_transaction (rc->connection,
"kyc check",
&res,
&kyc_check,
kyp);
if (GNUNET_SYSERR == ret)
return res;
if (0 !=
GNUNET_memcmp (&kyp->h_payto,
&kyp->auth_h_payto))
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_UNAUTHORIZED,
TALER_EC_EXCHANGE_KYC_CHECK_AUTHORIZATION_FAILED,
"h_payto");
}
/* long polling? */
if ( (! kyp->kyc.ok) &&
GNUNET_TIME_absolute_is_future (kyp->timeout))
{
GNUNET_assert (NULL != kyp->eh);
kyp->suspended = true;
GNUNET_CONTAINER_DLL_insert (kyp_head,
kyp_tail,
kyp);
MHD_suspend_connection (kyp->connection);
return MHD_YES;
}
/* KYC failed? */
if (! kyp->kyc.ok)
{
char *url;
char *redirect_uri;
char *redirect_uri_encoded;
GNUNET_assert (TEH_KYC_OAUTH2 == TEH_kyc_config.mode);
GNUNET_asprintf (&redirect_uri,
"%s/kyc-proof/%llu",
TEH_base_url,
(unsigned long long) kyp->payment_target_uuid);
redirect_uri_encoded = TALER_urlencode (redirect_uri);
GNUNET_free (redirect_uri);
GNUNET_asprintf (&url,
"%s/login?client_id=%s&redirect_uri=%s",
TEH_kyc_config.details.oauth2.url,
TEH_kyc_config.details.oauth2.client_id,
redirect_uri_encoded);
GNUNET_free (redirect_uri_encoded);
res = TALER_MHD_REPLY_JSON_PACK (
rc->connection,
MHD_HTTP_ACCEPTED,
GNUNET_JSON_pack_string ("kyc_url",
url));
GNUNET_free (url);
return res;
}
/* KYC succeeded! */
{
struct TALER_ExchangePublicKeyP pub;
struct TALER_ExchangeSignatureP sig;
struct TALER_ExchangeAccountSetupSuccessPS as = {
.purpose.purpose = htonl (
TALER_SIGNATURE_EXCHANGE_ACCOUNT_SETUP_SUCCESS),
.purpose.size = htonl (sizeof (as)),
.h_payto = kyp->h_payto,
.timestamp = GNUNET_TIME_absolute_hton (now)
};
enum TALER_ErrorCode ec;
if (TALER_EC_NONE !=
(ec = TEH_keys_exchange_sign (&as,
&pub,
&sig)))
{ {
GNUNET_break_op (0); return TALER_MHD_reply_with_ec (rc->connection,
return TALER_MHD_reply_with_error (rc->connection, ec,
MHD_HTTP_UNAUTHORIZED, NULL);
TALER_EC_EXCHANGE_KYC_CHECK_AUTHORIZATION_FAILED,
"h_payto");
}
if (! kyp->kyc.ok)
{
char *url;
char *redirect_uri;
char *redirect_uri_encoded;
GNUNET_assert (TEH_KYC_OAUTH2 == TEH_kyc_config.mode);
GNUNET_asprintf (&redirect_uri,
"%s/kyc-proof/%llu",
TEH_base_url,
(unsigned long long) kyp->payment_target_uuid);
redirect_uri_encoded = TALER_urlencode (redirect_uri);
GNUNET_free (redirect_uri);
GNUNET_asprintf (&url,
"%s/login?client_id=%s&redirect_uri=%s",
TEH_kyc_config.details.oauth2.url,
TEH_kyc_config.details.oauth2.client_id,
redirect_uri_encoded);
GNUNET_free (redirect_uri_encoded);
res = TALER_MHD_REPLY_JSON_PACK (
rc->connection,
MHD_HTTP_ACCEPTED,
GNUNET_JSON_pack_string ("kyc_url",
url));
GNUNET_free (url);
return res;
}
{
struct TALER_ExchangePublicKeyP pub;
struct TALER_ExchangeSignatureP sig;
struct TALER_ExchangeAccountSetupSuccessPS as = {
.purpose.purpose = htonl (
TALER_SIGNATURE_EXCHANGE_ACCOUNT_SETUP_SUCCESS),
.purpose.size = htonl (sizeof (as)),
.h_payto = kyp->h_payto,
.timestamp = GNUNET_TIME_absolute_hton (now)
};
enum TALER_ErrorCode ec;
if (TALER_EC_NONE !=
(ec = TEH_keys_exchange_sign (&as,
&pub,
&sig)))
{
return TALER_MHD_reply_with_ec (rc->connection,
ec,
NULL);
}
return TALER_MHD_REPLY_JSON_PACK (
rc->connection,
MHD_HTTP_OK,
GNUNET_JSON_pack_data_auto ("exchange_sig",
&sig),
GNUNET_JSON_pack_data_auto ("exchange_pub",
&pub),
GNUNET_JSON_pack_time_abs ("now",
now));
} }
return TALER_MHD_REPLY_JSON_PACK (
rc->connection,
MHD_HTTP_OK,
GNUNET_JSON_pack_data_auto ("exchange_sig",
&sig),
GNUNET_JSON_pack_data_auto ("exchange_pub",
&pub),
GNUNET_JSON_pack_time_abs ("now",
now));
} }
} }

View File

@ -385,6 +385,14 @@ prepare_statements (struct PostgresClosure *pg)
" SET kyc_ok=TRUE" " SET kyc_ok=TRUE"
" WHERE wire_target_serial_id=$1", " WHERE wire_target_serial_id=$1",
1), 1),
GNUNET_PQ_make_prepare (
"get_kyc_h_payto",
"SELECT"
" h_payto"
" FROM wire_targets"
" WHERE wire_target_serial_id=$1"
" LIMIT 1;",
1),
/* Used in #postgres_get_kyc_status() */ /* Used in #postgres_get_kyc_status() */
GNUNET_PQ_make_prepare ( GNUNET_PQ_make_prepare (
"get_kyc_status", "get_kyc_status",
@ -3804,10 +3812,33 @@ postgres_set_kyc_ok (void *cls,
GNUNET_PQ_query_param_uint64 (&payment_target_uuid), GNUNET_PQ_query_param_uint64 (&payment_target_uuid),
GNUNET_PQ_query_param_end GNUNET_PQ_query_param_end
}; };
struct TALER_KycCompletedEventP rep = {
.header.size = htons (sizeof (rep)),
.header.type = htons (TALER_DBEVENT_EXCHANGE_KYC_COMPLETED)
};
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_auto_from_type ("h_payto",
&rep.h_payto),
GNUNET_PQ_result_spec_end
};
enum GNUNET_DB_QueryStatus qs;
return GNUNET_PQ_eval_prepared_non_select (pg->conn, qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
"set_kyc_ok", "set_kyc_ok",
params); params);
if (qs <= 0)
return qs;
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"get_kyc_h_payto",
params,
rs);
if (qs <= 0)
return qs;
postgres_event_notify (pg,
&rep.header,
NULL,
0);
return qs;
} }
@ -5684,9 +5715,10 @@ postgres_ensure_coin_known (void *cls,
switch (qs) switch (qs)
{ {
case GNUNET_DB_STATUS_HARD_ERROR: case GNUNET_DB_STATUS_HARD_ERROR:
return TALER_EXCHANGEDB_CKS_SOFT_FAIL; GNUNET_break (0);
case GNUNET_DB_STATUS_SOFT_ERROR:
return TALER_EXCHANGEDB_CKS_HARD_FAIL; return TALER_EXCHANGEDB_CKS_HARD_FAIL;
case GNUNET_DB_STATUS_SOFT_ERROR:
return TALER_EXCHANGEDB_CKS_SOFT_FAIL;
case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
GNUNET_break (0); GNUNET_break (0);
return TALER_EXCHANGEDB_CKS_HARD_FAIL; return TALER_EXCHANGEDB_CKS_HARD_FAIL;

View File

@ -323,12 +323,6 @@ struct TALER_CoinSpendPublicKeyP
*/ */
struct GNUNET_CRYPTO_EddsaPublicKey eddsa_pub; struct GNUNET_CRYPTO_EddsaPublicKey eddsa_pub;
/*
* If age restriction applies to the coin, it must come with a hash of the
* age commitment. A zero value indicates that the coin has no age
* commitment set.
*/
struct TALER_AgeHash age_commitment_hash;
}; };

View File

@ -74,7 +74,7 @@ struct TALER_EXCHANGEDB_DenominationKeyInformationP
/** /**
* Signature of events signalling a reseve got funding. * Signature of events signalling a reserve got funding.
*/ */
struct TALER_ReserveEventP struct TALER_ReserveEventP
{ {
@ -90,6 +90,23 @@ struct TALER_ReserveEventP
}; };
/**
* Signature of events signalling a KYC process was completed.
*/
struct TALER_KycCompletedEventP
{
/**
* Of type #TALER_DBEVENT_EXCHANGE_KYC_COMPLETED.
*/
struct GNUNET_DB_EventHeaderP header;
/**
* Public key of the reserve the event is about.
*/
struct TALER_PaytoHash h_payto;
};
GNUNET_NETWORK_STRUCT_END GNUNET_NETWORK_STRUCT_END
/** /**