aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2024-09-07 23:21:17 +0200
committerChristian Grothoff <christian@grothoff.org>2024-09-07 23:21:17 +0200
commit23812272e6445aed81c4caefb59053ff0b597431 (patch)
treeeb307244b67f9336004c8686eaf4e7df37fb1fcd
parent4131cf69ce62dc3b79c7d27d992a9a5f8d934c1c (diff)
work towards taler-merchant-kyccheck helper
-rw-r--r--src/backend/taler-merchant-depositcheck.c4
-rw-r--r--src/backend/taler-merchant-httpd.c3
-rw-r--r--src/backend/taler-merchant-httpd_private-get-accounts.c3
-rw-r--r--src/backend/taler-merchant-httpd_private-get-instances-ID-kyc.c140
-rw-r--r--src/backend/taler-merchant-httpd_private-patch-token-families-SLUG.c7
-rw-r--r--src/backend/taler-merchant-httpd_private-post-account.c2
-rw-r--r--src/backend/taler-merchant-httpd_private-post-orders.c178
-rw-r--r--src/backend/taler-merchant-httpd_statics.c4
-rw-r--r--src/backend/taler-merchant-kyccheck.c510
-rw-r--r--src/backenddb/Makefile.am2
-rw-r--r--src/backenddb/merchant-0010.sql2
-rw-r--r--src/backenddb/pg_account_kyc_get_status.c5
-rw-r--r--src/backenddb/pg_account_kyc_set_status.c41
-rw-r--r--src/backenddb/pg_account_kyc_set_status.h8
-rw-r--r--src/backenddb/pg_account_kyc_set_status.sql84
-rw-r--r--src/backenddb/pg_get_kyc_status.c109
-rw-r--r--src/backenddb/pg_get_kyc_status.h62
-rw-r--r--src/backenddb/pg_insert_account.c3
-rw-r--r--src/backenddb/pg_insert_account.h2
-rw-r--r--src/backenddb/pg_select_account.c1
-rw-r--r--src/backenddb/pg_select_account_by_uri.c1
-rw-r--r--src/backenddb/pg_select_accounts.c35
-rw-r--r--src/backenddb/plugin_merchantdb_postgres.c3
-rw-r--r--src/backenddb/test_merchantdb.c21
-rw-r--r--src/include/taler_merchantdb_plugin.h52
25 files changed, 962 insertions, 320 deletions
diff --git a/src/backend/taler-merchant-depositcheck.c b/src/backend/taler-merchant-depositcheck.c
index ff90c505..3b725596 100644
--- a/src/backend/taler-merchant-depositcheck.c
+++ b/src/backend/taler-merchant-depositcheck.c
@@ -463,17 +463,17 @@ deposit_get_cb (
dr->details.accepted.kyc_ok,
TALER_B2S (&w->coin_pub));
now = GNUNET_TIME_timestamp_get ();
+ /* FIXME: probably should NOT clobber limits, etc, and
+ ONLY set kyc_ok (always to false?) */
qs = db_plugin->account_kyc_set_status (
db_plugin->cls,
w->instance_id,
&w->h_wire,
exchange_url,
- dr->details.accepted.requirement_row,
now,
MHD_HTTP_ACCEPTED,
TALER_EC_NONE,
NULL,
- 0,
NULL,
false,
dr->details.accepted.kyc_ok);
diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c
index a121251e..e46a2db5 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -2011,15 +2011,18 @@ url_handler (void *cls,
* Callback invoked with information about a bank account.
*
* @param cls closure with a `struct TMH_MerchantInstance *`
+ * @param merchant_priv private key of the merchant instance
* @param acc details about the account
*/
static void
add_account_cb (void *cls,
+ const struct TALER_MerchantPrivateKeyP *merchant_priv,
const struct TALER_MERCHANTDB_AccountDetails *acc)
{
struct TMH_MerchantInstance *mi = cls;
struct TMH_WireMethod *wm;
+ (void) merchant_priv;
wm = GNUNET_new (struct TMH_WireMethod);
wm->h_wire = acc->h_wire;
wm->payto_uri = GNUNET_strdup (acc->payto_uri);
diff --git a/src/backend/taler-merchant-httpd_private-get-accounts.c b/src/backend/taler-merchant-httpd_private-get-accounts.c
index e420a0e8..a5791960 100644
--- a/src/backend/taler-merchant-httpd_private-get-accounts.c
+++ b/src/backend/taler-merchant-httpd_private-get-accounts.c
@@ -26,14 +26,17 @@
* Add account details to our JSON array.
*
* @param cls a `json_t *` JSON array to build
+ * @param merchant_priv private key of the merchant instance
* @param ad details about the account
*/
static void
add_account (void *cls,
+ const struct TALER_MerchantPrivateKeyP *merchant_priv,
const struct TALER_MERCHANTDB_AccountDetails *ad)
{
json_t *pa = cls;
+ (void) merchant_priv;
GNUNET_assert (0 ==
json_array_append_new (
pa,
diff --git a/src/backend/taler-merchant-httpd_private-get-instances-ID-kyc.c b/src/backend/taler-merchant-httpd_private-get-instances-ID-kyc.c
index f8bad978..69e962d0 100644
--- a/src/backend/taler-merchant-httpd_private-get-instances-ID-kyc.c
+++ b/src/backend/taler-merchant-httpd_private-get-instances-ID-kyc.c
@@ -102,11 +102,6 @@ struct ExchangeKycRequest
struct TALER_EXCHANGE_KycCheckHandle *kyc;
/**
- * KYC number used by the exchange.
- */
- uint64_t exchange_kyc_serial;
-
- /**
* Our account's payto URI.
*/
char *payto_uri;
@@ -449,6 +444,34 @@ handle_kyc_timeout (void *cls)
/**
+ * Pack the given @a limit into the JSON @a limits array.
+ *
+ * @param limit account limit to pack
+ * @param[in,out] limits JSON array to extend
+ */
+static void
+pack_limit (const struct TALER_EXCHANGE_AccountLimit *limit,
+ json_t *limits)
+{
+ json_t *jl;
+
+ jl = GNUNET_JSON_PACK (
+ TALER_JSON_pack_kycte ("operation_type",
+ limit->operation_type),
+ GNUNET_JSON_pack_time_rel ("timeframe",
+ limit->timeframe),
+ TALER_JSON_pack_amount ("threshold",
+ &limit->threshold),
+ GNUNET_JSON_pack_bool ("soft_limit",
+ limit->soft_limit)
+ );
+ GNUNET_assert (0 ==
+ json_array_append_new (limits,
+ jl));
+}
+
+
+/**
* We are done with the KYC request @a ekr. Remove it from the work list and
* check if we are done overall.
*
@@ -512,92 +535,44 @@ store_kyc_status (
const struct TALER_EXCHANGE_KycStatus *ks,
const struct TALER_EXCHANGE_AccountKycStatus *account_kyc_status)
{
- unsigned int dl_cnt = 0;
+ json_t *jlimits;
+ enum GNUNET_DB_QueryStatus qs;
+ jlimits = json_array ();
+ GNUNET_assert (NULL != jlimits);
for (unsigned int i = 0; i<account_kyc_status->limits_length; i++)
{
const struct TALER_EXCHANGE_AccountLimit *limit
= &account_kyc_status->limits[i];
- if (TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT ==
- limit->operation_type)
- dl_cnt++;
+ pack_limit (limit,
+ jlimits);
}
+ qs = TMH_db->account_kyc_set_status (
+ TMH_db->cls,
+ ekr->kc->mi->settings.id,
+ &ekr->h_wire,
+ ekr->exchange_url,
+ GNUNET_TIME_timestamp_get (),
+ ks->hr.http_status,
+ ks->hr.ec,
+ &account_kyc_status->access_token,
+ jlimits,
+ account_kyc_status->aml_review,
+ false);
+ json_decref (jlimits);
+ if (qs < 0)
{
- struct TALER_MERCHANTDB_DepositLimits dls[GNUNET_NZL (dl_cnt)];
- enum GNUNET_DB_QueryStatus qs;
- unsigned int off = 0;
-
- for (unsigned int i = 0; i<account_kyc_status->limits_length; i++)
- {
- const struct TALER_EXCHANGE_AccountLimit *limit
- = &account_kyc_status->limits[i];
- struct TALER_MERCHANTDB_DepositLimits *dl
- = &dls[off];
-
- if (TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT !=
- limit->operation_type)
- continue;
- dl->timeframe = limit->timeframe;
- dl->threshold = limit->threshold;
- dl->soft_limit = limit->soft_limit;
- off++;
- }
- qs = TMH_db->account_kyc_set_status (
- TMH_db->cls,
- ekr->kc->mi->settings.id,
- &ekr->h_wire,
- ekr->exchange_url,
- ekr->exchange_kyc_serial,
- GNUNET_TIME_timestamp_get (),
- ks->hr.http_status,
- ks->hr.ec,
- &account_kyc_status->access_token,
- dl_cnt,
- dls,
- account_kyc_status->aml_review,
- false);
- if (qs < 0)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Failed to store KYC status in database!\n");
- return false;
- }
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Failed to store KYC status in database!\n");
+ return false;
}
return true;
}
/**
- * Pack the given @a limit into the JSON @a limits array.
- *
- * @param limit account limit to pack
- * @param[in,out] limits JSON array to extend
- */
-static void
-pack_limit (const struct TALER_EXCHANGE_AccountLimit *limit,
- json_t *limits)
-{
- json_t *jl;
-
- jl = GNUNET_JSON_PACK (
- TALER_JSON_pack_kycte ("operation_type",
- limit->operation_type),
- GNUNET_JSON_pack_time_rel ("timeframe",
- limit->timeframe),
- TALER_JSON_pack_amount ("threshold",
- &limit->threshold),
- GNUNET_JSON_pack_bool ("soft_limit",
- limit->soft_limit)
- );
- GNUNET_assert (0 ==
- json_array_append_new (limits,
- jl));
-}
-
-
-/**
* Return JSON array with AccountLimit objects giving
* the current limits for this exchange.
*
@@ -753,12 +728,10 @@ return_auth_required (
kc->mi->settings.id,
&ekr->h_wire,
ekr->exchange_url,
- ekr->exchange_kyc_serial,
GNUNET_TIME_timestamp_get (),
ks->hr.http_status,
ks->hr.ec,
NULL,
- 0,
NULL,
false,
true);
@@ -838,12 +811,10 @@ exchange_check_cb (
kc->mi->settings.id,
&ekr->h_wire,
ekr->exchange_url,
- ekr->exchange_kyc_serial,
GNUNET_TIME_timestamp_get (),
MHD_HTTP_NO_CONTENT,
TALER_EC_NONE,
NULL,
- 0,
NULL,
false,
true);
@@ -885,12 +856,10 @@ exchange_check_cb (
kc->mi->settings.id,
&ekr->h_wire,
ekr->exchange_url,
- ekr->exchange_kyc_serial,
GNUNET_TIME_timestamp_get (),
ks->hr.http_status,
ks->hr.ec,
NULL,
- 0,
NULL,
false,
true);
@@ -951,6 +920,7 @@ determine_eligible_accounts (
/* For all accounts of the exchange */
for (unsigned int i = 0; i<keys->accounts_len; i++)
{
+ /* FIXME: move into convenience function in libtalerexchange? See also taler-merchant-kyccheck.c! */
struct TALER_EXCHANGE_WireAccount *account
= &keys->accounts[i];
bool account_restricted = false;
@@ -1138,18 +1108,12 @@ kyc_status_cb (
<,
STALE_KYC_TIMEOUT)) )
return; /* KYC ok, ignore! */
- if (0 == exchange_kyc_serial)
- {
- kc->kyc_serial_pending = true;
- return;
- }
kc->response_code = MHD_HTTP_OK;
ekr = GNUNET_new (struct ExchangeKycRequest);
GNUNET_CONTAINER_DLL_insert (kc->exchange_pending_head,
kc->exchange_pending_tail,
ekr);
ekr->h_wire = *h_wire;
- ekr->exchange_kyc_serial = exchange_kyc_serial;
ekr->exchange_url = GNUNET_strdup (exchange_url);
ekr->payto_uri = GNUNET_strdup (payto_uri);
ekr->last_check = last_check;
diff --git a/src/backend/taler-merchant-httpd_private-patch-token-families-SLUG.c b/src/backend/taler-merchant-httpd_private-patch-token-families-SLUG.c
index 755ed4c9..56235514 100644
--- a/src/backend/taler-merchant-httpd_private-patch-token-families-SLUG.c
+++ b/src/backend/taler-merchant-httpd_private-patch-token-families-SLUG.c
@@ -67,6 +67,7 @@ TMH_private_patch_token_family_SLUG (const struct TMH_RequestHandler *rh,
&details.duration),
GNUNET_JSON_spec_end ()
};
+ struct GNUNET_TIME_Relative validity;
GNUNET_assert (NULL != mi);
GNUNET_assert (NULL != slug);
@@ -82,12 +83,12 @@ TMH_private_patch_token_family_SLUG (const struct TMH_RequestHandler *rh,
: MHD_NO;
}
- struct GNUNET_TIME_Relative validity = GNUNET_TIME_absolute_get_difference (
+ validity = GNUNET_TIME_absolute_get_difference (
details.valid_after.abs_time,
details.valid_before.abs_time);
- // Check if start_time is before valid_before
- if (0 == validity.rel_value_us)
+ /* Check if start_time is before valid_before */
+ if (GNUNET_TIME_relative_is_zero (validity))
{
GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
diff --git a/src/backend/taler-merchant-httpd_private-post-account.c b/src/backend/taler-merchant-httpd_private-post-account.c
index dbaac7ba..44d9f084 100644
--- a/src/backend/taler-merchant-httpd_private-post-account.c
+++ b/src/backend/taler-merchant-httpd_private-post-account.c
@@ -123,6 +123,7 @@ TMH_private_post_account (const struct TMH_RequestHandler *rh,
struct TALER_MERCHANTDB_AccountDetails ad = {
.payto_uri = wm->payto_uri,
.salt = wm->wire_salt,
+ .instance_id = mi->settings.id,
.h_wire = wm->h_wire,
.credit_facade_url = wm->credit_facade_url,
.credit_facade_credentials = wm->credit_facade_credentials,
@@ -131,7 +132,6 @@ TMH_private_post_account (const struct TMH_RequestHandler *rh,
enum GNUNET_DB_QueryStatus qs;
qs = TMH_db->insert_account (TMH_db->cls,
- mi->settings.id,
&ad);
switch (qs)
{
diff --git a/src/backend/taler-merchant-httpd_private-post-orders.c b/src/backend/taler-merchant-httpd_private-post-orders.c
index 4761fbdc..8fcbf7c4 100644
--- a/src/backend/taler-merchant-httpd_private-post-orders.c
+++ b/src/backend/taler-merchant-httpd_private-post-orders.c
@@ -1544,23 +1544,26 @@ set_token_family (struct OrderContext *oc,
return GNUNET_SYSERR;
}
- struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get ();
-
- /* Verify that the token family is valid right now. */
- if (GNUNET_TIME_timestamp_cmp (key_details.token_family.valid_after, >, now)
- ||
- GNUNET_TIME_timestamp_cmp (key_details.token_family.valid_before, <=, now)
- )
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Token family expired or not yet valid\n");
- reply_with_error (oc,
- /* TODO: HTTP Status Code GONE would be more elegant,
- but that is already used to indicate that a product is out of stock. */
- MHD_HTTP_CONFLICT,
- TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_TOKEN_FAMILY_NOT_VALID,
- key_details.token_family.slug);
- return GNUNET_SYSERR;
+ struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get ();
+
+ /* Verify that the token family is valid right now. */
+ if (GNUNET_TIME_timestamp_cmp (key_details.token_family.valid_after, >, now)
+ ||
+ GNUNET_TIME_timestamp_cmp (key_details.token_family.valid_before, <=,
+ now)
+ )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Token family expired or not yet valid\n");
+ reply_with_error (oc,
+ /* TODO: HTTP Status Code GONE would be more elegant,
+ but that is already used to indicate that a product is out of stock. */
+ MHD_HTTP_CONFLICT,
+ TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_TOKEN_FAMILY_NOT_VALID,
+ key_details.token_family.slug);
+ return GNUNET_SYSERR;
+ }
}
/* slug is not needed */
@@ -1607,8 +1610,6 @@ set_token_family (struct OrderContext *oc,
/* There is no matching key for this token family yet. */
/* We have to generate a fresh key pair. */
/* If public key is NULL, private key must also be NULL */
- GNUNET_assert (NULL == key_details.priv.private_key);
-
enum GNUNET_DB_QueryStatus iqs;
struct GNUNET_CRYPTO_BlindSignPrivateKey *priv;
struct GNUNET_CRYPTO_BlindSignPublicKey *pub;
@@ -1617,6 +1618,7 @@ set_token_family (struct OrderContext *oc,
GNUNET_TIME_absolute_add (min_valid_after.abs_time,
key_details.token_family.duration));
+ GNUNET_assert (NULL == key_details.priv.private_key);
if (GNUNET_TIME_timestamp_cmp (min_valid_after,
<,
key_details.token_family.valid_after))
@@ -1640,55 +1642,55 @@ set_token_family (struct OrderContext *oc,
/* TODO: Make cipher and key length configurable */
GNUNET_CRYPTO_BSA_RSA,
4096);
-
- struct TALER_TokenIssuePublicKeyP token_pub = {
- .public_key = pub,
- };
- struct TALER_TokenIssuePrivateKeyP token_priv = {
- .private_key = priv,
- };
-
- iqs = TMH_db->insert_token_family_key (TMH_db->cls,
- slug,
- &token_pub,
- &token_priv,
- min_valid_after,
- valid_before);
-
- GNUNET_CRYPTO_blind_sign_priv_decref (priv);
-
- if (iqs <= 0)
{
- enum TALER_ErrorCode ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
- unsigned int http_status = 0;
+ struct TALER_TokenIssuePublicKeyP token_pub = {
+ .public_key = pub,
+ };
+ struct TALER_TokenIssuePrivateKeyP token_priv = {
+ .private_key = priv,
+ };
- switch (iqs)
+ iqs = TMH_db->insert_token_family_key (TMH_db->cls,
+ slug,
+ &token_pub,
+ &token_priv,
+ min_valid_after,
+ valid_before);
+ GNUNET_CRYPTO_blind_sign_priv_decref (priv);
+
+ if (iqs <= 0)
{
- case GNUNET_DB_STATUS_HARD_ERROR:
- http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
- ec = TALER_EC_GENERIC_DB_STORE_FAILED;
- break;
- case GNUNET_DB_STATUS_SOFT_ERROR:
- case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
- http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
- ec = TALER_EC_GENERIC_DB_SOFT_FAILURE;
- break;
- case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
- /* case listed to make compilers happy */
- GNUNET_assert (0);
+ enum TALER_ErrorCode ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
+ unsigned int http_status = 0;
+
+ switch (iqs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ ec = TALER_EC_GENERIC_DB_STORE_FAILED;
+ break;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ ec = TALER_EC_GENERIC_DB_SOFT_FAILURE;
+ break;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ /* case listed to make compilers happy */
+ GNUNET_assert (0);
+ }
+
+ GNUNET_break (0);
+ reply_with_error (oc,
+ http_status,
+ ec,
+ "token_family_slug");
+ return GNUNET_SYSERR;
}
- GNUNET_break (0);
- reply_with_error (oc,
- http_status,
- ec,
- "token_family_slug");
- return GNUNET_SYSERR;
+ key.pub = token_pub;
+ key.valid_after = min_valid_after;
+ key.valid_before = valid_before;
}
-
- key.pub = token_pub;
- key.valid_after = min_valid_after;
- key.valid_before = valid_before;
}
else
{
@@ -1771,8 +1773,9 @@ serialize_order (struct OrderContext *oc)
for (unsigned int i = 0; i<oc->parse_choices.token_families_len; i++)
{
json_t *keys = json_array ();
- struct TALER_MerchantContractTokenFamily *family = &oc->parse_choices.
- token_families[i];
+ struct TALER_MerchantContractTokenFamily *family
+ = &oc->parse_choices.token_families[i];
+ json_t *jfamily;
for (unsigned int j = 0; j<family->keys_len; j++)
{
@@ -1797,11 +1800,13 @@ serialize_order (struct OrderContext *oc)
key.valid_before)
);
- GNUNET_assert (0 == json_array_append_new (keys, jkey));
+ GNUNET_assert (0 ==
+ json_array_append_new (keys,
+ jkey));
}
/* TODO: Add 'details' field. */
- json_t *jfamily = GNUNET_JSON_PACK (
+ jfamily = GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("name",
family->name),
GNUNET_JSON_pack_string ("description",
@@ -1822,19 +1827,22 @@ serialize_order (struct OrderContext *oc)
for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
{
- struct TALER_MerchantContractChoice *choice = &oc->parse_choices.choices[i];
-
+ const struct TALER_MerchantContractChoice *choice
+ = &oc->parse_choices.choices[i];
json_t *inputs = json_array ();
json_t *outputs = json_array ();
+ GNUNET_assert (NULL != inputs);
+ GNUNET_assert (NULL != outputs);
for (unsigned int j = 0; j<choice->inputs_len; j++)
{
- struct TALER_MerchantContractInput *input = &choice->inputs[j];
+ const struct TALER_MerchantContractInput *input
+ = &choice->inputs[j];
+ json_t *jinput;
/* For now, only tokens are supported */
GNUNET_assert (TALER_MCIT_TOKEN == input->type);
-
- json_t *jinput = GNUNET_JSON_PACK (
+ jinput = GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("kind",
TMH_string_from_contract_input_type (input->
type)),
@@ -1846,17 +1854,20 @@ serialize_order (struct OrderContext *oc)
input->details.token.valid_after)
);
- GNUNET_assert (0 == json_array_append_new (inputs, jinput));
+ GNUNET_assert (0 ==
+ json_array_append_new (inputs,
+ jinput));
}
for (unsigned int j = 0; j<choice->outputs_len; j++)
{
struct TALER_MerchantContractOutput *output = &choice->outputs[j];
+ json_t *joutput;
/* For now, only tokens are supported */
GNUNET_assert (TALER_MCOT_TOKEN == output->type);
- json_t *joutput = GNUNET_JSON_PACK (
+ joutput = GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("kind",
TMH_string_from_contract_output_type (output->
type)),
@@ -1868,17 +1879,24 @@ serialize_order (struct OrderContext *oc)
output->details.token.valid_after)
);
- GNUNET_assert (0 == json_array_append (outputs, joutput));
+ GNUNET_assert (0 ==
+ json_array_append_new (outputs,
+ joutput));
}
- json_t *jchoice = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_array_incref ("inputs",
- inputs),
- GNUNET_JSON_pack_array_incref ("outputs",
- outputs)
- );
+ {
+ json_t *jchoice
+ = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_array_incref ("inputs",
+ inputs),
+ GNUNET_JSON_pack_array_incref ("outputs",
+ outputs)
+ );
- GNUNET_assert (0 == json_array_append (choices, jchoice));
+ GNUNET_assert (0 ==
+ json_array_append_new (choices,
+ jchoice));
+ }
}
oc->serialize_order.contract = GNUNET_JSON_PACK (
diff --git a/src/backend/taler-merchant-httpd_statics.c b/src/backend/taler-merchant-httpd_statics.c
index 72f81d85..a82dafba 100644
--- a/src/backend/taler-merchant-httpd_statics.c
+++ b/src/backend/taler-merchant-httpd_statics.c
@@ -316,6 +316,10 @@ TMH_statics_init ()
* Nicely shut down.
*/
void __attribute__ ((destructor))
+get_statics_fini (void);
+
+/* Declaration avoids compiler warning */
+void __attribute__ ((destructor))
get_statics_fini ()
{
for (unsigned int i = 0; i<loaded_length; i++)
diff --git a/src/backend/taler-merchant-kyccheck.c b/src/backend/taler-merchant-kyccheck.c
index 297106de..dfb2be53 100644
--- a/src/backend/taler-merchant-kyccheck.c
+++ b/src/backend/taler-merchant-kyccheck.c
@@ -22,7 +22,10 @@
#include <gnunet/gnunet_util_lib.h>
#include <jansson.h>
#include <pthread.h>
+#include <regex.h>
#include <taler/taler_dbevents.h>
+#include <taler/taler_json_lib.h>
+#include <taler/taler_exchange_service.h>
#include "taler_merchant_bank_lib.h"
#include "taler_merchantdb_lib.h"
#include "taler_merchantdb_plugin.h"
@@ -90,11 +93,32 @@ struct Account
struct Inquiry *i_tail;
/**
+ * Merchant instance this account belongs to.
+ */
+ char *instance_id;
+
+ /**
* The payto-URI of this account.
*/
char *merchant_account_uri;
/**
+ * Wire hash of the merchant bank account (with the
+ * respective salt).
+ */
+ struct TALER_MerchantWireHashP h_wire;
+
+ /**
+ * Private key of the instance.
+ */
+ union TALER_AccountPrivateKeyP ap;
+
+ /**
+ * Hash of the @e merchant_account_uri.
+ */
+ struct TALER_PaytoHashP h_payto;
+
+ /**
* Database generation when this account
* was last active.
*/
@@ -133,6 +157,54 @@ struct Inquiry
struct Account *a;
/**
+ * AccountLimits that apply to the account, NULL
+ * if unknown.
+ */
+ json_t *jlimits;
+
+ /**
+ * Handle for the actual HTTP request to the exchange.
+ */
+ struct TALER_EXCHANGE_KycCheckHandle *kyc;
+
+ /**
+ * Access token for the /kyc-info API.
+ */
+ struct TALER_AccountAccessTokenP access_token;
+
+ /**
+ * Last time we called the /kyc-check endpoint.
+ */
+ struct GNUNET_TIME_Timestamp last_kyc_check;
+
+ /**
+ * When is the next KYC check due?
+ */
+ struct GNUNET_TIME_Absolute due;
+
+ /**
+ * When should the current KYC time out?
+ */
+ struct GNUNET_TIME_Absolute timeout;
+
+ /**
+ * Current exponential backoff.
+ */
+ struct GNUNET_TIME_Relative backoff;
+
+ /**
+ * Last HTTP status returned by the exchange from
+ * the /kyc-check endpoint.
+ */
+ unsigned int last_http_status;
+
+ /**
+ * Last Taler error code returned by the exchange from
+ * the /kyc-check endpoint.
+ */
+ enum TALER_ErrorCode last_ec;
+
+ /**
* Did we not run this inquiry due to limits?
*/
bool limited;
@@ -143,10 +215,16 @@ struct Inquiry
bool kyc_ok;
/**
- * True if we did this account's KYC AUTH transfer.
+ * True if merchant did perform this account's KYC AUTH transfer and @e access_token is set.
*/
bool auth_ok;
+ /**
+ * True if the account is known to be currently under
+ * investigation by AML staff.
+ */
+ bool aml_review;
+
};
@@ -238,12 +316,13 @@ static bool at_limit;
/**
- * Do KYC check work for the give inquiry in @a i.
+ * Check about performing a /kyc-check request with the
+ * exchange for the given inquiry.
*
- * @param i inquiry to work on
+ * @param cls a `struct Inquiry` to process
*/
static void
-inquiry_work (struct Inquiry *i);
+inquiry_work (void *cls);
/**
@@ -292,10 +371,216 @@ end_inquiry (void)
}
+/**
+ * Pack the given @a limit into the JSON @a limits array.
+ *
+ * @param limit account limit to pack
+ * @param[in,out] limits JSON array to extend
+ */
+static void
+pack_limit (const struct TALER_EXCHANGE_AccountLimit *limit,
+ json_t *limits)
+{
+ json_t *jl;
+
+ jl = GNUNET_JSON_PACK (
+ TALER_JSON_pack_kycte ("operation_type",
+ limit->operation_type),
+ GNUNET_JSON_pack_time_rel ("timeframe",
+ limit->timeframe),
+ TALER_JSON_pack_amount ("threshold",
+ &limit->threshold),
+ GNUNET_JSON_pack_bool ("soft_limit",
+ limit->soft_limit)
+ );
+ GNUNET_assert (0 ==
+ json_array_append_new (limits,
+ jl));
+}
+
+
+/**
+ * Store KYC response from the exchange in the
+ * local database.
+ *
+ * @param[in,out] i inquiry context, jlimits is updated
+ * @param ks HTTP response details
+ * @param account_kyc_status account KYC status details
+ */
static void
-inquiry_work (struct Inquiry *i)
+store_kyc_status (
+ struct Inquiry *i,
+ const struct TALER_EXCHANGE_KycStatus *ks,
+ const struct TALER_EXCHANGE_AccountKycStatus *account_kyc_status)
{
- // enum GNUNET_DB_QueryStatus qs;
+ enum GNUNET_DB_QueryStatus qs;
+ json_t *jlimits;
+
+ jlimits = json_array ();
+ GNUNET_assert (NULL != jlimits);
+ for (unsigned int j = 0; j<account_kyc_status->limits_length; j++)
+ {
+ const struct TALER_EXCHANGE_AccountLimit *limit
+ = &account_kyc_status->limits[j];
+
+ pack_limit (limit,
+ jlimits);
+ }
+ json_decref (i->jlimits);
+ i->jlimits = jlimits;
+ // FIXME: update more of i?
+
+ qs = db_plugin->account_kyc_set_status (
+ db_plugin->cls,
+ i->a->instance_id,
+ &i->a->h_wire,
+ i->e->keys->exchange_url,
+ GNUNET_TIME_timestamp_get (),
+ ks->hr.http_status,
+ ks->hr.ec,
+ &account_kyc_status->access_token,
+ jlimits,
+ account_kyc_status->aml_review,
+ MHD_HTTP_OK == ks->hr.http_status);
+ if (qs < 0)
+ {
+ GNUNET_break (0);
+ global_ret = EXIT_FAILURE;
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+}
+
+
+/**
+ * Function called with the result of a KYC check.
+ *
+ * @param cls a `struct Inquiry *`
+ * @param ks the account's KYC status details
+ */
+static void
+exchange_check_cb (
+ void *cls,
+ const struct TALER_EXCHANGE_KycStatus *ks)
+{
+ struct Inquiry *i = cls;
+
+ i->kyc = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Checking KYC status of `%s' at `%s' is %u\n",
+ i->a->merchant_account_uri,
+ i->e->keys->exchange_url,
+ ks->hr.http_status);
+ switch (ks->hr.http_status)
+ {
+ case MHD_HTTP_OK:
+ store_kyc_status (i,
+ ks,
+ &ks->details.ok);
+ break;
+ case MHD_HTTP_ACCEPTED:
+ store_kyc_status (i,
+ ks,
+ &ks->details.accepted);
+ break;
+ case MHD_HTTP_NO_CONTENT:
+ {
+ enum GNUNET_DB_QueryStatus qs;
+
+ // FIXME: update i?
+ qs = db_plugin->account_kyc_set_status (
+ db_plugin->cls,
+ i->a->instance_id,
+ &i->a->h_wire,
+ i->e->keys->exchange_url,
+ GNUNET_TIME_timestamp_get (),
+ MHD_HTTP_NO_CONTENT,
+ TALER_EC_NONE,
+ NULL,
+ NULL,
+ false,
+ true);
+ if (qs < 0)
+ {
+ GNUNET_break (0);
+ global_ret = EXIT_FAILURE;
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ }
+ break;
+ case MHD_HTTP_FORBIDDEN: /* bad signature */
+ case MHD_HTTP_NOT_FOUND: /* account unknown */
+ case MHD_HTTP_CONFLICT: /* no account_pub known */
+ {
+ enum GNUNET_DB_QueryStatus qs;
+
+ // FIXME: update i?
+ qs = db_plugin->account_kyc_set_status (
+ db_plugin->cls,
+ i->a->instance_id,
+ &i->a->h_wire,
+ i->e->keys->exchange_url,
+ GNUNET_TIME_timestamp_get (),
+ ks->hr.http_status,
+ ks->hr.ec,
+ NULL,
+ NULL,
+ false,
+ true);
+ if (qs < 0)
+ {
+ GNUNET_break (0);
+ global_ret = EXIT_FAILURE;
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ }
+ break;
+ default:
+ {
+ enum GNUNET_DB_QueryStatus qs;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Exchange responded with HTTP status %u (%d) to /kyc-check request!\n",
+ ks->hr.http_status,
+ ks->hr.ec);
+ // FIXME: update i?
+ qs = db_plugin->account_kyc_set_status (
+ db_plugin->cls,
+ i->a->instance_id,
+ &i->a->h_wire,
+ i->e->keys->exchange_url,
+ GNUNET_TIME_timestamp_get (),
+ ks->hr.http_status,
+ ks->hr.ec,
+ NULL /* access token */,
+ NULL /* jlimits */,
+ false /* in_aml_review? well, unknown... */,
+ true /* kyc_ok? well, unknown... */);
+ if (qs < 0)
+ {
+ GNUNET_break (0);
+ global_ret = EXIT_FAILURE;
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ break;
+ }
+ }
+ end_inquiry ();
+}
+
+
+static void
+inquiry_work (void *cls)
+{
+ struct Inquiry *i = cls;
+
+ i->task = NULL;
+ // FIXME: update i->due, i->timeout, i->backoff
+ if (! GNUNET_TIME_absolute_is_past (i->due))
+ goto finish;
GNUNET_assert (OPEN_INQUIRY_LIMIT >= active_inquiries);
if (OPEN_INQUIRY_LIMIT <= active_inquiries)
@@ -308,21 +593,29 @@ inquiry_work (struct Inquiry *i)
}
at_limit = false;
-#if 0
- active_inquiries++;
- // FIXME: do actual work!
- qs = db_plugin->select_open_transfers (db_plugin->cls,
- limit,
- &start_inquiry,
- NULL);
- if (qs < 0)
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Checking KYC status of `%s' at `%s'\n",
+ i->a->merchant_account_uri,
+ i->e->keys->exchange_url);
+ i->kyc = TALER_EXCHANGE_kyc_check (
+ ctx,
+ i->e->keys->exchange_url,
+ &i->a->h_payto,
+ &i->a->ap,
+ GNUNET_TIME_absolute_get_remaining (i->timeout),
+ &exchange_check_cb,
+ i);
+ if (NULL == i->kyc)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to obtain open transfers from database\n");
- GNUNET_SCHEDULER_shutdown ();
- return;
+ GNUNET_break (0);
+ i->task
+ = GNUNET_SCHEDULER_add_at (i->timeout,
+ &inquiry_work,
+ i);
+ goto finish;
}
-#endif
+ active_inquiries++;
+finish:
if ( (0 == active_inquiries) &&
(test_mode) )
{
@@ -335,6 +628,80 @@ inquiry_work (struct Inquiry *i)
/**
+ * Check if the account @a could work with exchange that
+ * has keys @a keys.
+ *
+ * @param keys the keys of an exchange
+ * @param a an account
+ */
+static bool
+is_eligible (struct TALER_EXCHANGE_Keys *keys,
+ struct Account *a)
+{
+ /* For all accounts of the exchange */
+ for (unsigned int i = 0; i<keys->accounts_len; i++)
+ {
+ /* FIXME: move into convenience function in libtalerexchange? See also taler-merchant-httpd_private-get-instances-ID-kyc.c*/
+ struct TALER_EXCHANGE_WireAccount *account
+ = &keys->accounts[i];
+ bool account_restricted = false;
+
+ /* KYC auth transfers are never supported with conversion */
+ if (NULL != account->conversion_url)
+ continue;
+
+ /* filter by source account by credit_restrictions */
+ for (unsigned int j = 0; j<account->credit_restrictions_length; j++)
+ {
+ const struct TALER_EXCHANGE_AccountRestriction *ar
+ = &account->credit_restrictions[j];
+
+ switch (ar->type)
+ {
+ case TALER_EXCHANGE_AR_INVALID:
+ continue;
+ case TALER_EXCHANGE_AR_DENY:
+ account_restricted = true;
+ break;
+ case TALER_EXCHANGE_AR_REGEX:
+ {
+ regex_t ex;
+ bool allowed = false;
+
+ if (0 != regcomp (&ex,
+ ar->details.regex.posix_egrep,
+ REG_NOSUB | REG_EXTENDED))
+ {
+ GNUNET_break_op (0);
+ continue;
+ }
+ if (regexec (&ex,
+ a->merchant_account_uri,
+ 0, NULL,
+ REG_STARTEND))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Merchant account `%s' allowed by regex\n",
+ a->merchant_account_uri);
+ allowed = true;
+ }
+ regfree (&ex);
+ if (! allowed)
+ account_restricted = true;
+ break;
+ }
+ } /* end switch */
+ } /* end loop over credit restrictions */
+ if (account_restricted)
+ continue;
+ /* exchange account is allowed, add it */
+ return true;
+ }
+ return false;
+}
+
+
+/**
* Start the KYC checking for account @a at exchange @a e.
*
* @param e an exchange
@@ -345,6 +712,7 @@ start_inquiry (struct Exchange *e,
struct Account *a)
{
struct Inquiry *i;
+ enum GNUNET_DB_QueryStatus qs;
i = GNUNET_new (struct Inquiry);
i->e = e;
@@ -352,7 +720,25 @@ start_inquiry (struct Exchange *e,
GNUNET_CONTAINER_DLL_insert (a->i_head,
a->i_tail,
i);
- // FIXME: initial import from DB here!?
+ qs = db_plugin->get_kyc_status (db_plugin->cls,
+ a->merchant_account_uri,
+ a->instance_id,
+ e->keys->exchange_url,
+ &i->auth_ok,
+ &i->access_token,
+ &i->kyc_ok,
+ &i->last_http_status,
+ &i->last_ec,
+ &i->last_kyc_check,
+ &i->aml_review,
+ &i->jlimits);
+ if (qs < 0)
+ {
+ GNUNET_break (0);
+ global_ret = EXIT_FAILURE;
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
inquiry_work (i);
}
@@ -375,12 +761,46 @@ stop_inquiry (struct Inquiry *i)
GNUNET_SCHEDULER_cancel (i->task);
i->task = NULL;
}
- // FIXME: other clean-ups related to i here!
+ if (NULL != i->kyc)
+ {
+ TALER_EXCHANGE_kyc_check_cancel (i->kyc);
+ i->kyc = NULL;
+ }
+ if (NULL != i->jlimits)
+ {
+ json_decref (i->jlimits);
+ i->jlimits = NULL;
+ }
GNUNET_free (i);
}
/**
+ * Stop KYC inquiry for account @a at exchange @a e.
+ *
+ * @param e an exchange
+ * @param a an account
+ */
+static void
+stop_inquiry_at (struct Exchange *e,
+ struct Account *a)
+{
+ for (struct Inquiry *i = a->i_head;
+ NULL != i;
+ i = i->next)
+ {
+ if (e == i->e)
+ {
+ stop_inquiry (i);
+ return;
+ }
+ }
+ /* strange, there should have been a match! */
+ GNUNET_break (0);
+}
+
+
+/**
* Start inquries for all exchanges on account @a a.
*
* @param a an account
@@ -391,8 +811,10 @@ start_inquiries (struct Account *a)
for (struct Exchange *e = e_head;
NULL != e;
e = e->next)
- start_inquiry (e,
- a);
+ if (is_eligible (e->keys,
+ a))
+ start_inquiry (e,
+ a);
}
@@ -415,17 +837,21 @@ stop_inquiries (struct Account *a)
* Callback invoked with information about a bank account.
*
* @param cls closure
+ * @param merchant_priv private key of the merchant instance
* @param ad details about the account
*/
static void
account_cb (
void *cls,
+ const struct TALER_MerchantPrivateKeyP *merchant_priv,
const struct TALER_MERCHANTDB_AccountDetails *ad)
{
const char *payto_uri = ad->payto_uri;
if (! ad->active)
return;
+ if (NULL == merchant_priv)
+ return; /* instance was deleted */
for (struct Account *a = a_head;
NULL != a;
a = a->next)
@@ -442,7 +868,17 @@ account_cb (
struct Account *a = GNUNET_new (struct Account);
a->account_gen = database_gen;
- a->merchant_account_uri = GNUNET_strdup (payto_uri);
+ a->merchant_account_uri
+ = GNUNET_strdup (ad->payto_uri);
+ a->instance_id
+ = GNUNET_strdup (ad->instance_id);
+ a->h_wire
+ = ad->h_wire;
+ a->ap.merchant_priv
+ = *merchant_priv;
+ TALER_payto_hash (a->merchant_account_uri,
+ &a->h_payto);
+
GNUNET_CONTAINER_DLL_insert (a_head,
a_tail,
a);
@@ -537,8 +973,28 @@ find_keys (const char *exchange_url)
if (0 == strcmp (e->keys->exchange_url,
keys->exchange_url))
{
- TALER_EXCHANGE_keys_decref (e->keys);
+ struct TALER_EXCHANGE_Keys *old_keys = e->keys;
+
e->keys = keys;
+ for (struct Account *a = a_head;
+ NULL != a;
+ a = a->next)
+ {
+ bool was_eligible = is_eligible (old_keys,
+ a);
+ bool now_eligible = is_eligible (keys,
+ a);
+
+ if (was_eligible == now_eligible)
+ continue; /* no change, do nothing */
+ if (was_eligible)
+ stop_inquiry_at (e,
+ a);
+ else /* is_eligible */
+ start_inquiry (e,
+ a);
+ }
+ TALER_EXCHANGE_keys_decref (old_keys);
return;
}
}
@@ -551,7 +1007,9 @@ find_keys (const char *exchange_url)
NULL != a;
a = a->next)
{
- if (a->account_gen < database_gen)
+ if ( (a->account_gen == database_gen) &&
+ (is_eligible (e->keys,
+ a)) )
start_inquiry (e,
a);
}
diff --git a/src/backenddb/Makefile.am b/src/backenddb/Makefile.am
index 1703f20c..792bfb53 100644
--- a/src/backenddb/Makefile.am
+++ b/src/backenddb/Makefile.am
@@ -27,6 +27,7 @@ sql_DATA = \
merchant-0008.sql \
merchant-0009.sql \
merchant-0010.sql \
+ merchant-0011.sql \
drop.sql
BUILT_SOURCES = \
@@ -102,6 +103,7 @@ libtaler_plugin_merchantdb_postgres_la_SOURCES = \
pg_lookup_pending_deposits.h pg_lookup_pending_deposits.c \
pg_insert_instance.h pg_insert_instance.c \
pg_account_kyc_set_status.h pg_account_kyc_set_status.c \
+ pg_get_kyc_status.h pg_get_kyc_status.c \
pg_account_kyc_get_status.h pg_account_kyc_get_status.c \
pg_delete_instance_private_key.h pg_delete_instance_private_key.c \
pg_purge_instance.h pg_purge_instance.c \
diff --git a/src/backenddb/merchant-0010.sql b/src/backenddb/merchant-0010.sql
index e2839aa4..44a2a113 100644
--- a/src/backenddb/merchant-0010.sql
+++ b/src/backenddb/merchant-0010.sql
@@ -15,7 +15,7 @@
--
-- @file merchant-0010.sql
--- @brief Remove dead aml_decision column
+-- @brief Remove dead aml_decision column and add new ones
-- @author Christian Grothoff
-- Everything in one big transaction
diff --git a/src/backenddb/pg_account_kyc_get_status.c b/src/backenddb/pg_account_kyc_get_status.c
index c2e97276..1eee0416 100644
--- a/src/backenddb/pg_account_kyc_get_status.c
+++ b/src/backenddb/pg_account_kyc_get_status.c
@@ -80,7 +80,7 @@ kyc_status_cb (void *cls,
for (unsigned int i = 0; i < num_results; i++)
{
struct TALER_MerchantWireHashP h_wire;
- uint64_t kyc_serial;
+ uint64_t kyc_serial = 0; /* deprecated */
char *exchange_url;
char *payto_uri;
struct GNUNET_TIME_Timestamp last_check;
@@ -88,8 +88,6 @@ kyc_status_cb (void *cls,
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_auto_from_type ("h_wire",
&h_wire),
- GNUNET_PQ_result_spec_uint64 ("exchange_kyc_serial",
- &kyc_serial),
GNUNET_PQ_result_spec_string ("payto_uri",
&payto_uri),
GNUNET_PQ_result_spec_string ("exchange_url",
@@ -164,7 +162,6 @@ TMH_PG_account_kyc_get_status (
"lookup_kyc_status",
"SELECT"
" h_wire"
- ",exchange_kyc_serial"
",payto_uri"
",exchange_url"
",kyc_timestamp"
diff --git a/src/backenddb/pg_account_kyc_set_status.c b/src/backenddb/pg_account_kyc_set_status.c
index 2e2b7911..c4e8bd97 100644
--- a/src/backenddb/pg_account_kyc_set_status.c
+++ b/src/backenddb/pg_account_kyc_set_status.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
+ Copyright (C) 2022-2024 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -17,6 +17,7 @@
* @file backenddb/pg_account_kyc_set_status.c
* @brief Implementation of the account_kyc_set_status function for Postgres
* @author Iván Ávalos
+ * @author Christian Grothoff
*/
#include "platform.h"
#include <taler/taler_error_codes.h>
@@ -32,43 +33,30 @@ TMH_PG_account_kyc_set_status (
const char *merchant_id,
const struct TALER_MerchantWireHashP *h_wire,
const char *exchange_url,
- uint64_t exchange_kyc_serial,
struct GNUNET_TIME_Timestamp timestamp,
unsigned int exchange_http_status,
enum TALER_ErrorCode exchange_ec_code,
const struct TALER_AccountAccessTokenP *access_token,
- unsigned int num_limits,
- const struct TALER_MERCHANTDB_DepositLimits *limits,
+ const json_t *jlimits,
bool in_aml_review,
bool kyc_ok)
{
struct PostgresClosure *pg = cls;
uint32_t http_status32 = (uint32_t) exchange_http_status;
uint32_t ec_code32 = (uint32_t) exchange_ec_code;
- struct TALER_Amount thresholds[GNUNET_NZL (num_limits)];
- struct GNUNET_TIME_Relative timeframes[GNUNET_NZL (num_limits)];
- bool soft_limits[GNUNET_NZL (num_limits)];
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_string (merchant_id),
GNUNET_PQ_query_param_auto_from_type (h_wire),
GNUNET_PQ_query_param_string (exchange_url),
GNUNET_PQ_query_param_timestamp (&timestamp),
- GNUNET_PQ_query_param_uint64 (&exchange_kyc_serial),
GNUNET_PQ_query_param_uint32 (&http_status32),
GNUNET_PQ_query_param_uint32 (&ec_code32),
NULL != access_token
? GNUNET_PQ_query_param_auto_from_type (access_token)
: GNUNET_PQ_query_param_null (),
- TALER_PQ_query_param_array_amount_with_currency (
- num_limits,
- thresholds,
- pg->conn),
- GNUNET_PQ_query_param_array_rel_time (num_limits,
- timeframes,
- pg->conn),
- GNUNET_PQ_query_param_array_bool (num_limits,
- soft_limits,
- pg->conn),
+ NULL != jlimits
+ ? TALER_PQ_query_param_json (jlimits)
+ : GNUNET_PQ_query_param_null (),
GNUNET_PQ_query_param_bool (in_aml_review),
GNUNET_PQ_query_param_bool (kyc_ok),
GNUNET_PQ_query_param_end
@@ -91,24 +79,19 @@ TMH_PG_account_kyc_set_status (
" out_no_instance AS no_instance"
" ,out_no_account AS no_account"
" FROM merchant_do_account_kyc_set_status"
- "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13);");
- for (unsigned int i=0; i<num_limits; i++)
- {
- const struct TALER_MERCHANTDB_DepositLimits *limit
- = &limits[i];
-
- thresholds[i] = limit->threshold;
- timeframes[i] = limit->timeframe;
- soft_limits[i] = limit->soft_limit;
- }
+ "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);");
qs = GNUNET_PQ_eval_prepared_singleton_select (
pg->conn,
"account_kyc_set_status",
params,
rs);
- GNUNET_PQ_cleanup_query_params_closures (params);
if (qs <= 0)
+ {
+ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
+ GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs);
+ GNUNET_break (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs);
return qs;
+ }
GNUNET_break (! no_instance);
GNUNET_break (! no_account);
return qs;
diff --git a/src/backenddb/pg_account_kyc_set_status.h b/src/backenddb/pg_account_kyc_set_status.h
index 3c5891b3..d970c62e 100644
--- a/src/backenddb/pg_account_kyc_set_status.h
+++ b/src/backenddb/pg_account_kyc_set_status.h
@@ -32,13 +32,11 @@
* @param merchant_id merchant backend instance ID
* @param h_wire hash of the wire account to check
* @param exchange_url base URL of the exchange to check
- * @param exchange_kyc_serial serial number for our account at the exchange (0 if unknown)
* @param timestamp timestamp to store
* @param exchange_http_status HTTP status code returned last by the exchange
* @param exchange_ec_code Taler error code returned last by the exchange
* @param access_token access token for the KYC process, NULL for none
- * @param num_limits length of the @a limits array
- * @param limits array with deposit limits returned by the exchange
+ * @param jlimits JSON array with AccountLimits returned by the exchange
* @param in_aml_review true if the exchange says the account is under review
* @param kyc_ok current KYC status (true for satisfied)
* @return database result code
@@ -49,13 +47,11 @@ TMH_PG_account_kyc_set_status (
const char *merchant_id,
const struct TALER_MerchantWireHashP *h_wire,
const char *exchange_url,
- uint64_t exchange_kyc_serial,
struct GNUNET_TIME_Timestamp timestamp,
unsigned int exchange_http_status,
enum TALER_ErrorCode exchange_ec_code,
const struct TALER_AccountAccessTokenP *access_token,
- unsigned int num_limits,
- const struct TALER_MERCHANTDB_DepositLimits *limits,
+ const json_t *jlimits,
bool in_aml_review,
bool kyc_ok);
diff --git a/src/backenddb/pg_account_kyc_set_status.sql b/src/backenddb/pg_account_kyc_set_status.sql
index f72ab6ec..ce86a764 100644
--- a/src/backenddb/pg_account_kyc_set_status.sql
+++ b/src/backenddb/pg_account_kyc_set_status.sql
@@ -15,18 +15,17 @@
--
-CREATE OR REPLACE FUNCTION merchant_do_account_kyc_set_status (
+DROP FUNCTION IF EXISTS merchant_do_account_kyc_set_status;
+
+CREATE FUNCTION merchant_do_account_kyc_set_status (
IN in_merchant_id TEXT,
IN in_h_wire BYTEA,
IN in_exchange_url TEXT,
IN in_timestamp INT8,
- IN in_exchange_kyc_serial INT8,
IN in_exchange_http_status INT4,
IN in_exchange_ec_code INT4,
- IN in_access_token BYTEA,
- IN ina_thresholds taler_amount_currency[],
- IN ina_timeframes INT8[],
- IN ina_soft_limits BOOL[],
+ IN in_access_token BYTEA, -- can be NULL
+ IN in_jlimits TEXT,
IN in_aml_active BOOL,
IN in_kyc_ok BOOL,
OUT out_no_instance BOOL,
@@ -36,8 +35,6 @@ AS $$
DECLARE
my_merchant_id INT8;
my_account_serial INT8;
- ini_cat INT8;
- rec RECORD;
BEGIN
out_no_instance=FALSE;
@@ -67,49 +64,40 @@ THEN
RETURN;
END IF;
-INSERT INTO merchant_kyc
- (kyc_timestamp
- ,kyc_ok
- ,exchange_kyc_serial
- ,account_serial
- ,exchange_url
- ,deposit_thresholds
- ,deposit_timeframes
- ,deposit_limits_are_soft
- ,aml_review
- ,exchange_http_status
- ,exchange_ec_code
- ,access_token)
-VALUES
- (in_timestamp
- ,in_kyc_ok
- ,in_exchange_kyc_serial
- ,my_account_serial
- ,in_exchange_url
- ,ina_thresholds
- ,ina_timeframes
- ,ina_soft_limits
- ,in_aml_active
- ,in_exchange_http_status
- ,in_exchange_ec_code
- ,in_access_token)
- ON CONFLICT DO NOTHING;
+UPDATE merchant_kyc
+ SET kyc_timestamp=in_timestamp
+ ,kyc_ok=in_kyc_ok
+ ,jaccount_limits=in_jlimits
+ ,aml_review=in_aml_active
+ ,exchange_http_status=in_exchange_http_status
+ ,exchange_ec_code=in_exchange_ec_code
+ ,access_token=in_access_token
+ WHERE account_serial=my_account_serial
+ AND exchange_url=in_exchange_url;
IF NOT FOUND
THEN
- UPDATE merchant_kyc
- SET exchange_kyc_serial=in_exchange_kyc_serial
- ,kyc_timestamp=in_timestamp
- ,kyc_ok=in_kyc_ok
- ,deposit_thresholds=ina_thresholds
- ,deposit_timeframes=ina_timeframes
- ,deposit_limits_are_soft=ina_soft_limits
- ,aml_review=in_aml_active
- ,exchange_http_status=in_exchange_http_status
- ,exchange_ec_code=in_exchange_ec_code
- ,access_token=in_access_token
- WHERE account_serial=my_account_serial
- AND exchange_url=in_exchange_url;
+
+ INSERT INTO merchant_kyc
+ (kyc_timestamp
+ ,kyc_ok
+ ,account_serial
+ ,exchange_url
+ ,jaccount_limits
+ ,aml_review
+ ,exchange_http_status
+ ,exchange_ec_code
+ ,access_token)
+ VALUES
+ (in_timestamp
+ ,in_kyc_ok
+ ,my_account_serial
+ ,in_exchange_url
+ ,in_jlimits
+ ,in_aml_active
+ ,in_exchange_http_status
+ ,in_exchange_ec_code
+ ,in_access_token);
END IF;
-- Success!
diff --git a/src/backenddb/pg_get_kyc_status.c b/src/backenddb/pg_get_kyc_status.c
new file mode 100644
index 00000000..5c980bfd
--- /dev/null
+++ b/src/backenddb/pg_get_kyc_status.c
@@ -0,0 +1,109 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2024 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_get_kyc_status.c
+ * @brief Implementation of the get_kyc_status function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_get_kyc_status.h"
+#include "pg_helper.h"
+
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_get_kyc_status (
+ void *cls,
+ const char *merchant_account_uri,
+ const char *instance_id,
+ const char *exchange_url,
+ bool *auth_ok,
+ struct TALER_AccountAccessTokenP *access_token,
+ bool *kyc_ok,
+ unsigned int *last_http_status,
+ enum TALER_ErrorCode *last_ec,
+ struct GNUNET_TIME_Timestamp *last_kyc_check,
+ bool *aml_review,
+ json_t **jlimits)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (merchant_account_uri),
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (exchange_url),
+ GNUNET_PQ_query_param_end
+ };
+ uint32_t h32 = 0;
+ uint32_t e32 = 0;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_auto_from_type ("access_token",
+ &access_token),
+ auth_ok),
+ GNUNET_PQ_result_spec_uint32 ("exchange_http_status",
+ &h32),
+ GNUNET_PQ_result_spec_uint32 ("exchange_ec_code",
+ &e32),
+ GNUNET_PQ_result_spec_bool ("kyc_ok",
+ kyc_ok),
+ GNUNET_PQ_result_spec_timestamp ("kyc_timestamp",
+ last_kyc_check),
+ GNUNET_PQ_result_spec_bool ("aml_review",
+ aml_review),
+ GNUNET_PQ_result_spec_allow_null (
+ TALER_PQ_result_spec_json ("jaccount_limits",
+ jlimits),
+ NULL),
+ GNUNET_PQ_result_spec_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ check_connection (pg);
+ PREPARE (pg,
+ "get_kyc_status",
+ "SELECT"
+ " access_token"
+ ",exchange_http_status"
+ ",exchange_ec_code"
+ ",kyc_ok"
+ ",kyc_timestamp"
+ ",aml_review"
+ ",jaccount_limits"
+ " FROM merchant_kyc mk"
+ " JOIN merchant_accounts"
+ " USING (merchant_serial)"
+ " JOIN merchant_kyc"
+ " USING (account_serial)"
+ " WHERE exchange_url=$3"
+ " AND account_serial="
+ " (SELECT account_serial"
+ " FROM merchant_accounts"
+ " WHERE payto_uri=$1"
+ " AND merchant_serial="
+ " (SELECT merchant_serial"
+ " FROM merchant_instances"
+ " WHERE merchant_id=$2));");
+ *jlimits = NULL;
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "get_kyc_status",
+ params,
+ rs);
+ *last_ec = (enum TALER_ErrorCode) (int) e32;
+ *last_http_status = (unsigned int) h32;
+ return qs;
+}
diff --git a/src/backenddb/pg_get_kyc_status.h b/src/backenddb/pg_get_kyc_status.h
new file mode 100644
index 00000000..729f37d5
--- /dev/null
+++ b/src/backenddb/pg_get_kyc_status.h
@@ -0,0 +1,62 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2024 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_get_kyc_status.h
+ * @brief implementation of the get_kyc_status function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_GET_KYC_STATUS_H
+#define PG_GET_KYC_STATUS_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+
+/**
+ * Check an account's KYC status at an exchange.
+ *
+ * @param cls closure
+ * @param merchant_payto_uri merchant backend instance ID
+ * @param instance_id the instance for which to check
+ * @param exchange_url base URL of the exchange
+ * @param[out] auth_ok true if @a access_token was set
+ * @param[out] access_token set to access token for /kyc-info
+ * @param[out] kyc_ok true if no urgent KYC work must be done for this account
+ * @param[out] last_http_status set to last HTTP status from exchange on /kyc-check
+ * @param[out] last_ec set to last Taler error code from exchange on /kyc-check
+ * @param[out] last_kyc_check set to time of last KYC check
+ * @param[out] aml_review set to true if the account is under AML review (if this exposed)
+ * @param[out] jlimits set to JSON array with AccountLimits, NULL if unknown (and likely defaults apply or KYC auth is urgently needed, see @a auth_ok)
+ * @return database result code
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_get_kyc_status (
+ void *cls,
+ const char *merchant_account_uri,
+ const char *instance_id,
+ const char *exchange_url,
+ bool *auth_ok,
+ struct TALER_AccountAccessTokenP *access_token,
+ bool *kyc_ok,
+ unsigned int *last_http_status,
+ enum TALER_ErrorCode *last_ec,
+ struct GNUNET_TIME_Timestamp *last_kyc_check,
+ bool *aml_review,
+ json_t **jlimits);
+
+
+#endif
diff --git a/src/backenddb/pg_insert_account.c b/src/backenddb/pg_insert_account.c
index 04b0637c..504c4da5 100644
--- a/src/backenddb/pg_insert_account.c
+++ b/src/backenddb/pg_insert_account.c
@@ -29,12 +29,11 @@
enum GNUNET_DB_QueryStatus
TMH_PG_insert_account (
void *cls,
- const char *id,
const struct TALER_MERCHANTDB_AccountDetails *account_details)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (id),
+ GNUNET_PQ_query_param_string (account_details->instance_id),
GNUNET_PQ_query_param_auto_from_type (&account_details->h_wire),
GNUNET_PQ_query_param_auto_from_type (&account_details->salt),
GNUNET_PQ_query_param_string (account_details->payto_uri),
diff --git a/src/backenddb/pg_insert_account.h b/src/backenddb/pg_insert_account.h
index 463bc527..758ce59e 100644
--- a/src/backenddb/pg_insert_account.h
+++ b/src/backenddb/pg_insert_account.h
@@ -29,14 +29,12 @@
* Insert information about an instance's account into our database.
*
* @param cls closure
- * @param id identifier of the instance
* @param account_details details about the account
* @return database result code
*/
enum GNUNET_DB_QueryStatus
TMH_PG_insert_account (
void *cls,
- const char *id,
const struct TALER_MERCHANTDB_AccountDetails *account_details);
diff --git a/src/backenddb/pg_select_account.c b/src/backenddb/pg_select_account.c
index 9d48e421..eab30377 100644
--- a/src/backenddb/pg_select_account.c
+++ b/src/backenddb/pg_select_account.c
@@ -57,6 +57,7 @@ TMH_PG_select_account (void *cls,
};
ad->h_wire = *h_wire;
+ ad->instance_id = id;
check_connection (pg);
PREPARE (pg,
"select_account",
diff --git a/src/backenddb/pg_select_account_by_uri.c b/src/backenddb/pg_select_account_by_uri.c
index fafae088..70471eb4 100644
--- a/src/backenddb/pg_select_account_by_uri.c
+++ b/src/backenddb/pg_select_account_by_uri.c
@@ -59,6 +59,7 @@ TMH_PG_select_account_by_uri (void *cls,
ad->credit_facade_url = NULL;
ad->credit_facade_credentials = NULL;
ad->payto_uri = GNUNET_strdup (payto_uri);
+ ad->instance_id = id;
check_connection (pg);
PREPARE (pg,
"select_account_by_uri",
diff --git a/src/backenddb/pg_select_accounts.c b/src/backenddb/pg_select_accounts.c
index eaf26015..672db926 100644
--- a/src/backenddb/pg_select_accounts.c
+++ b/src/backenddb/pg_select_accounts.c
@@ -72,9 +72,12 @@ select_account_cb (void *cls,
for (unsigned int i = 0; i < num_results; i++)
{
char *payto;
+ char *instance_id;
char *facade_url = NULL;
json_t *credential = NULL;
struct TALER_MERCHANTDB_AccountDetails acc;
+ struct TALER_MerchantPrivateKeyP merchant_priv;
+ bool no_priv;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_auto_from_type ("h_wire",
&acc.h_wire),
@@ -82,6 +85,8 @@ select_account_cb (void *cls,
&acc.salt),
GNUNET_PQ_result_spec_string ("payto_uri",
&payto),
+ GNUNET_PQ_result_spec_string ("merchant_id",
+ &instance_id),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_string ("credit_facade_url",
&facade_url),
@@ -92,6 +97,10 @@ select_account_cb (void *cls,
NULL),
GNUNET_PQ_result_spec_bool ("active",
&acc.active),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_auto_from_type ("merchant_priv",
+ &merchant_priv),
+ &no_priv),
GNUNET_PQ_result_spec_end
};
@@ -104,10 +113,12 @@ select_account_cb (void *cls,
lic->qs = GNUNET_DB_STATUS_HARD_ERROR;
return;
}
+ acc.instance_id = instance_id;
acc.payto_uri = payto;
acc.credit_facade_url = facade_url;
acc.credit_facade_credentials = credential;
lic->cb (lic->cb_cls,
+ no_priv ? NULL : &merchant_priv,
&acc);
GNUNET_PQ_cleanup_result (rs);
}
@@ -138,16 +149,22 @@ TMH_PG_select_accounts (void *cls,
PREPARE (pg,
"select_accounts",
"SELECT"
- " h_wire"
- ",salt"
- ",payto_uri"
- ",credit_facade_url"
- ",credit_facade_credentials"
- ",active"
- " FROM merchant_accounts"
+ " ma.h_wire"
+ ",ma.salt"
+ ",ma.payto_uri"
+ ",ma.credit_facade_url"
+ ",ma.credit_facade_credentials"
+ ",ma.active"
+ ",mk.merchant_priv"
+ ",mi.merchant_id"
+ " FROM merchant_accounts ma"
+ " JOIN merchant_instances mi"
+ " ON (mi.merchant_serial=ma.merchant_serial)"
+ " LEFT JOIN merchant_keys mk"
+ " ON (mk.merchant_serial=ma.merchant_serial)"
" WHERE"
- " ($1 IS NULL) OR"
- " (merchant_serial="
+ " ($1::TEXT IS NULL) OR"
+ " (ma.merchant_serial="
" (SELECT merchant_serial "
" FROM merchant_instances"
" WHERE merchant_id=$1));");
diff --git a/src/backenddb/plugin_merchantdb_postgres.c b/src/backenddb/plugin_merchantdb_postgres.c
index 2bb74d32..690f066e 100644
--- a/src/backenddb/plugin_merchantdb_postgres.c
+++ b/src/backenddb/plugin_merchantdb_postgres.c
@@ -32,6 +32,7 @@
#include "taler_merchantdb_plugin.h"
#include "pg_helper.h"
#include "pg_insert_otp.h"
+#include "pg_get_kyc_status.h"
#include "pg_delete_otp.h"
#include "pg_update_otp.h"
#include "pg_select_otp.h"
@@ -581,6 +582,8 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
= &TMH_PG_lookup_categories;
plugin->select_category_by_name
= &TMH_PG_select_category_by_name;
+ plugin->get_kyc_status
+ = &TMH_PG_get_kyc_status;
plugin->select_category
= &TMH_PG_select_category;
plugin->update_category
diff --git a/src/backenddb/test_merchantdb.c b/src/backenddb/test_merchantdb.c
index c2028261..392511e1 100644
--- a/src/backenddb/test_merchantdb.c
+++ b/src/backenddb/test_merchantdb.c
@@ -98,7 +98,7 @@ struct InstanceData
* @param instance the instance data to be filled.
*/
static void
-make_instance (char *instance_id,
+make_instance (const char *instance_id,
struct InstanceData *instance)
{
memset (instance,
@@ -451,7 +451,6 @@ test_insert_account (const struct InstanceData *instance,
{
TEST_COND_RET_ON_FAIL (expected_result ==
plugin->insert_account (plugin->cls,
- instance->instance.id,
account),
"Insert account failed\n");
return 0;
@@ -513,7 +512,11 @@ pre_test_instances (struct TestInstances_Closure *cls)
/* Accounts */
make_account (&cls->accounts[0]);
+ cls->accounts[0].instance_id
+ = cls->instances[0].instance.id;
make_account (&cls->accounts[1]);
+ cls->accounts[1].instance_id
+ = cls->instances[1].instance.id;
}
@@ -3207,7 +3210,7 @@ pre_test_deposits (struct TestDeposits_Closure *cls)
/* Account */
make_account (&cls->account);
-
+ cls->account.instance_id = cls->instance.instance.id;
/* Signing key */
make_exchange_signkey (&cls->signkey);
@@ -4325,7 +4328,7 @@ pre_test_transfers (struct TestTransfers_Closure *cls)
/* Account */
make_account (&cls->account);
-
+ cls->account.instance_id = cls->instance.instance.id;
/* Order */
make_order ("test_transfers_od_1",
&cls->order);
@@ -5039,7 +5042,7 @@ pre_test_refunds (struct TestRefunds_Closure *cls)
/* Account */
make_account (&cls->account);
-
+ cls->account.instance_id = cls->instance.instance.id;
/* Signing key */
make_exchange_signkey (&cls->signkey);
@@ -5357,6 +5360,7 @@ pre_test_lookup_orders_all_filters (
make_instance ("test_inst_lookup_orders_all_filters",
&cls->instance);
make_account (&cls->account);
+ cls->account.instance_id = cls->instance.instance.id;
make_exchange_signkey (&cls->signkey);
for (unsigned int i = 0; i < 64; ++i)
{
@@ -5613,6 +5617,7 @@ test_kyc (void)
make_instance ("test_kyc",
&instance);
make_account (&account);
+ account.instance_id = instance.instance.id;
TEST_RET_ON_FAIL (test_insert_instance (&instance,
GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
TEST_RET_ON_FAIL (test_insert_account (&instance,
@@ -5624,12 +5629,10 @@ test_kyc (void)
instance.instance.id,
&account.h_wire,
"https://exchange.net/",
- 1LLU,
now,
MHD_HTTP_OK,
TALER_EC_NONE,
NULL,
- 0,
NULL,
false,
false));
@@ -5638,12 +5641,10 @@ test_kyc (void)
instance.instance.id,
&account.h_wire,
"https://exchange2.com/",
- 1LLU,
now,
MHD_HTTP_OK,
TALER_EC_NONE,
NULL,
- 0,
NULL,
false,
false));
@@ -5652,12 +5653,10 @@ test_kyc (void)
instance.instance.id,
&account.h_wire,
"https://exchange.net/",
- 1LLU,
now,
MHD_HTTP_OK,
TALER_EC_NONE,
NULL,
- 0,
NULL,
false,
true));
diff --git a/src/include/taler_merchantdb_plugin.h b/src/include/taler_merchantdb_plugin.h
index 7882f789..00fe71fe 100644
--- a/src/include/taler_merchantdb_plugin.h
+++ b/src/include/taler_merchantdb_plugin.h
@@ -118,6 +118,13 @@ struct TALER_MERCHANTDB_AccountDetails
struct TALER_WireSaltP salt;
/**
+ * Instance ID. Do not free (may be aliased with
+ * the instance ID given in the query!).
+ * FIXME: set in all functions involving this struct!
+ */
+ const char *instance_id;
+
+ /**
* Actual account address as a payto://-URI.
*/
char *payto_uri;
@@ -257,11 +264,13 @@ typedef void
* Callback invoked with information about a bank account.
*
* @param cls closure
+ * @param merchant_priv private key of the merchant instance
* @param ad details about the account
*/
typedef void
(*TALER_MERCHANTDB_AccountCallback)(
void *cls,
+ const struct TALER_MerchantPrivateKeyP *merchant_priv,
const struct TALER_MERCHANTDB_AccountDetails *ad);
@@ -1463,14 +1472,12 @@ struct TALER_MERCHANTDB_Plugin
* Insert information about an instance's account into our database.
*
* @param cls closure
- * @param id identifier of the instance
* @param account_details details about the account
* @return database result code
*/
enum GNUNET_DB_QueryStatus
(*insert_account)(
void *cls,
- const char *id,
const struct TALER_MERCHANTDB_AccountDetails *account_details);
@@ -1700,19 +1707,50 @@ struct TALER_MERCHANTDB_Plugin
void *kyc_cb_cls);
/**
+ * Check an account's KYC status at an exchange.
+ *
+ * @param cls closure
+ * @param merchant_payto_uri merchant backend instance ID
+ * @param instance_id the instance for which to check
+ * @param exchange_url base URL of the exchange
+ * @param[out] auth_ok true if @a access_token was set
+ * @param[out] access_token set to access token for /kyc-info
+ * @param[out] kyc_ok true if no urgent KYC work must be done for this account
+ * @param[out] last_http_status set to last HTTP status from exchange on /kyc-check
+ * @param[out] last_ec set to last Taler error code from exchange on /kyc-check
+ * @param[out] last_kyc_check set to time of last KYC check
+ * @param[out] aml_review set to true if the account is under AML review (if this exposed)
+ * @param[out] jlimits set to JSON array with AccountLimits, NULL if unknown (and likely defaults apply or KYC auth is urgently needed, see @a auth_ok)
+ * @return database result code
+ */
+ enum GNUNET_DB_QueryStatus
+ (*get_kyc_status)(
+ void *cls,
+ const char *merchant_account_uri,
+ const char *instance_id,
+ const char *exchange_url,
+ bool *auth_ok,
+ struct TALER_AccountAccessTokenP *access_token,
+ bool *kyc_ok,
+ unsigned int *last_http_status,
+ enum TALER_ErrorCode *last_ec,
+ struct GNUNET_TIME_Timestamp *last_kyc_check,
+ bool *aml_review,
+ json_t **jlimits);
+
+
+ /**
* Update an instance's account's KYC status.
*
* @param cls closure
* @param merchant_id merchant backend instance ID
* @param h_wire hash of the wire account to check
* @param exchange_url base URL of the exchange to check
- * @param exchange_kyc_serial serial number for our account at the exchange (0 if unknown)
* @param timestamp timestamp to store
* @param exchange_http_status HTTP status code returned last by the exchange
* @param exchange_ec_code Taler error code returned last by the exchange
* @param access_token access token for the KYC process, NULL for none
- * @param num_limits length of the @a limits array
- * @param limits array with deposit limits returned by the exchange
+ * @param jlimits JSON array with AccountLimits returned by the exchange
* @param in_aml_review true if the exchange says the account is under review
* @param kyc_ok current KYC status (true for satisfied)
* @return database result code
@@ -1723,13 +1761,11 @@ struct TALER_MERCHANTDB_Plugin
const char *merchant_id,
const struct TALER_MerchantWireHashP *h_wire,
const char *exchange_url,
- uint64_t exchange_kyc_serial,
struct GNUNET_TIME_Timestamp timestamp,
unsigned int exchange_http_status,
enum TALER_ErrorCode exchange_ec_code,
const struct TALER_AccountAccessTokenP *access_token,
- unsigned int num_limits,
- const struct TALER_MERCHANTDB_DepositLimits *limits,
+ const json_t *jlimits,
bool in_aml_review,
bool kyc_ok);