summaryrefslogtreecommitdiff
path: root/src/exchange/taler-exchange-httpd_purses_merge.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/exchange/taler-exchange-httpd_purses_merge.c')
-rw-r--r--src/exchange/taler-exchange-httpd_purses_merge.c240
1 files changed, 169 insertions, 71 deletions
diff --git a/src/exchange/taler-exchange-httpd_purses_merge.c b/src/exchange/taler-exchange-httpd_purses_merge.c
index 144571d22..fb5ce4d90 100644
--- a/src/exchange/taler-exchange-httpd_purses_merge.c
+++ b/src/exchange/taler-exchange-httpd_purses_merge.c
@@ -28,12 +28,12 @@
#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"
#include "taler_exchangedb_lib.h"
#include "taler-exchange-httpd_keys.h"
-#include "taler-exchange-httpd_wire.h"
/**
@@ -103,11 +103,21 @@ 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.
*/
char *provider_url;
@@ -157,15 +167,20 @@ reply_merge_success (struct MHD_Connection *connection,
}
else
{
+#if WAD_NOT_IMPLEMENTED
+ /* FIXME: figure out partner, lookup wad fee by partner! #7271 */
if (0 >
TALER_amount_subtract (&merge_amount,
&pcc->target_amount,
- &pcc->wf->wad))
+ &wad_fee))
{
GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (TEH_currency,
&merge_amount));
}
+#else
+ merge_amount = pcc->target_amount;
+#endif
}
if (TALER_EC_NONE !=
(ec = TALER_exchange_online_purse_merged_sign (
@@ -202,6 +217,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
* a MHD response. IF it returns an hard error, the transaction logic MUST
@@ -224,9 +279,50 @@ merge_transaction (void *cls,
bool in_conflict = true;
bool no_balance = true;
bool no_partner = true;
- bool no_kyc = true;
- bool no_reserve = true;
+ char *required;
+ qs = 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,
+ &required);
+ 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,
+ "kyc_test_required");
+ return qs;
+ }
+ if (NULL != required)
+ {
+ pcc->kyc.ok = false;
+ qs = TEH_plugin->insert_kyc_requirement_for_account (
+ TEH_plugin->cls,
+ required,
+ &pcc->h_payto,
+ &pcc->reserve_pub,
+ &pcc->kyc.requirement_row);
+ GNUNET_free (required);
+ if (GNUNET_DB_STATUS_HARD_ERROR == qs)
+ {
+ GNUNET_break (0);
+ *mhd_ret
+ = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_STORE_FAILED,
+ "insert_kyc_requirement_for_account");
+ }
+ return qs;
+ }
+ pcc->kyc.ok = true;
qs = TEH_plugin->do_purse_merge (
TEH_plugin->cls,
pcc->purse_pub,
@@ -235,18 +331,14 @@ 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)
{
if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
return qs;
- TALER_LOG_WARNING (
- "Failed to store merge purse information in database\n");
+ GNUNET_break (0);
*mhd_ret =
TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
@@ -263,26 +355,6 @@ 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) &&
- (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 =
@@ -298,13 +370,15 @@ merge_transaction (void *cls,
struct GNUNET_TIME_Timestamp merge_timestamp;
char *partner_url = NULL;
struct TALER_ReservePublicKeyP reserve_pub;
+ bool refunded;
qs = TEH_plugin->select_purse_merge (TEH_plugin->cls,
pcc->purse_pub,
&merge_sig,
&merge_timestamp,
&partner_url,
- &reserve_pub);
+ &reserve_pub,
+ &refunded);
if (qs <= 0)
{
if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
@@ -318,21 +392,43 @@ merge_transaction (void *cls,
"select purse merge");
return qs;
}
- *mhd_ret = TALER_MHD_REPLY_JSON_PACK (
- connection,
- MHD_HTTP_CONFLICT,
- GNUNET_JSON_pack_timestamp ("merge_timestamp",
- merge_timestamp),
- GNUNET_JSON_pack_data_auto ("merge_sig",
- &merge_sig),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("partner_url",
- partner_url)),
- GNUNET_JSON_pack_data_auto ("reserve_pub",
- &reserve_pub));
+ if (refunded)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Purse was already refunded\n");
+ *mhd_ret = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_GONE,
+ TALER_EC_EXCHANGE_GENERIC_PURSE_EXPIRED,
+ NULL);
+ GNUNET_free (partner_url);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+ if (0 !=
+ GNUNET_memcmp (&merge_sig,
+ &pcc->merge_sig))
+ {
+ *mhd_ret = TALER_MHD_REPLY_JSON_PACK (
+ connection,
+ MHD_HTTP_CONFLICT,
+ GNUNET_JSON_pack_timestamp ("merge_timestamp",
+ merge_timestamp),
+ GNUNET_JSON_pack_data_auto ("merge_sig",
+ &merge_sig),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("partner_url",
+ partner_url)),
+ GNUNET_JSON_pack_data_auto ("reserve_pub",
+ &reserve_pub));
+ GNUNET_free (partner_url);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+ /* idempotent! */
+ *mhd_ret = reply_merge_success (connection,
+ pcc);
GNUNET_free (partner_url);
return GNUNET_DB_STATUS_HARD_ERROR;
}
+
return qs;
}
@@ -348,8 +444,8 @@ TEH_handler_purses_merge (
.exchange_timestamp = GNUNET_TIME_timestamp_get ()
};
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("payto_uri",
- &pcc.payto_uri),
+ TALER_JSON_spec_payto_uri ("payto_uri",
+ &pcc.payto_uri),
GNUNET_JSON_spec_fixed_auto ("reserve_sig",
&pcc.reserve_sig),
GNUNET_JSON_spec_fixed_auto ("merge_sig",
@@ -381,15 +477,15 @@ TEH_handler_purses_merge (
}
/* Fetch purse details */
- qs = TEH_plugin->select_purse_request (TEH_plugin->cls,
- pcc.purse_pub,
- &pcc.merge_pub,
- &pcc.purse_expiration,
- &pcc.h_contract_terms,
- &pcc.min_age,
- &pcc.target_amount,
- &pcc.balance,
- &purse_sig);
+ qs = TEH_plugin->get_purse_request (TEH_plugin->cls,
+ pcc.purse_pub,
+ &pcc.merge_pub,
+ &pcc.purse_expiration,
+ &pcc.h_contract_terms,
+ &pcc.min_age,
+ &pcc.target_amount,
+ &pcc.balance,
+ &purse_sig);
switch (qs)
{
case GNUNET_DB_STATUS_HARD_ERROR:
@@ -421,11 +517,11 @@ TEH_handler_purses_merge (
"Received payto: `%s'\n",
pcc.payto_uri);
if ( (0 != strncmp (pcc.payto_uri,
- "payto://taler/",
- strlen ("payto://taler/"))) &&
+ "payto://taler-reserve/",
+ strlen ("payto://taler-reserve/"))) &&
(0 != strncmp (pcc.payto_uri,
- "payto://taler+http/",
- strlen ("payto://taler+http/"))) )
+ "payto://taler-reserve-http/",
+ strlen ("payto://taler-reserve+http/"))) )
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (
@@ -434,15 +530,14 @@ TEH_handler_purses_merge (
TALER_EC_GENERIC_PARAMETER_MALFORMED,
"payto_uri");
}
-
http = (0 == strncmp (pcc.payto_uri,
- "payto://taler+http/",
- strlen ("payto://taler+http/")));
+ "payto://taler-reserve-http/",
+ strlen ("payto://taler-reserve-http/")));
{
const char *host = &pcc.payto_uri[http
- ? strlen ("payto://taler+http/")
- : strlen ("payto://taler/")];
+ ? strlen ("payto://taler-reserve-http/")
+ : strlen ("payto://taler-reserve/")];
const char *slash = strchr (host,
'/');
@@ -477,6 +572,8 @@ TEH_handler_purses_merge (
}
slash++;
}
+ TALER_payto_hash (pcc.payto_uri,
+ &pcc.h_payto);
if (0 == strcmp (pcc.provider_url,
TEH_base_url))
{
@@ -485,9 +582,9 @@ TEH_handler_purses_merge (
}
else
{
- char *method = GNUNET_strdup ("FIXME-WAD");
+ char *method = GNUNET_strdup ("FIXME-WAD #7271");
- /* FIXME: lookup wire method by pcc.provider_url! */
+ /* FIXME-#7271: lookup wire method by pcc.provider_url! */
pcc.wf = TEH_wire_fees_by_time (pcc.exchange_timestamp,
method);
if (NULL == pcc.wf)
@@ -551,11 +648,6 @@ TEH_handler_purses_merge (
}
}
- if (GNUNET_TIME_absolute_is_past (pcc.purse_expiration.abs_time))
- {
- // FIXME: idempotency check, otherwise generate 410!
- }
-
/* execute transaction */
{
MHD_RESULT mhd_ret;
@@ -573,6 +665,13 @@ TEH_handler_purses_merge (
}
}
+
+ GNUNET_free (pcc.provider_url);
+ if (! pcc.kyc.ok)
+ return TEH_RESPONSE_reply_kyc_required (connection,
+ &pcc.h_payto,
+ &pcc.kyc);
+
{
struct TALER_PurseEventP rep = {
.header.size = htons (sizeof (rep)),
@@ -588,7 +687,6 @@ TEH_handler_purses_merge (
0);
}
- GNUNET_free (pcc.provider_url);
/* generate regular response */
return reply_merge_success (connection,
&pcc);