aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
m---------contrib/gana0
-rw-r--r--src/exchange/taler-exchange-httpd_age-withdraw.c8
-rw-r--r--src/exchange/taler-exchange-httpd_aml-decision.c41
-rw-r--r--src/exchange/taler-exchange-httpd_aml-decisions-get.c2
-rw-r--r--src/exchange/taler-exchange-httpd_kyc-info.c2
-rw-r--r--src/exchange/taler-exchange-httpd_kyc-proof.c1
-rw-r--r--src/exchange/taler-exchange-httpd_kyc-upload.c10
-rw-r--r--src/exchange/taler-exchange-httpd_kyc-webhook.c1
-rw-r--r--src/exchange/taler-exchange-httpd_reserves_get_attest.c5
-rw-r--r--src/exchange/taler-exchange-httpd_reserves_purse.c3
-rw-r--r--src/exchangedb/exchange_do_insert_aml_decision.sql60
-rw-r--r--src/exchangedb/exchange_do_insert_kyc_attributes.sql14
-rw-r--r--src/exchangedb/pg_insert_aml_decision.c10
-rw-r--r--src/exchangedb/pg_insert_aml_decision.h5
-rw-r--r--src/exchangedb/pg_insert_kyc_attributes.c2
-rw-r--r--src/exchangedb/pg_lookup_aml_history.c4
-rw-r--r--src/include/taler_crypto_lib.h4
-rw-r--r--src/include/taler_exchangedb_plugin.h12
-rw-r--r--src/include/taler_kyclogic_lib.h13
-rw-r--r--src/kyclogic/kyclogic_api.c132
-rw-r--r--src/lib/exchange_api_add_aml_decision.c9
-rw-r--r--src/testing/test_kyc_api.c5
-rw-r--r--src/testing/testing_api_cmd_take_aml_decision.c8
-rw-r--r--src/util/aml_signatures.c15
24 files changed, 285 insertions, 81 deletions
diff --git a/contrib/gana b/contrib/gana
-Subproject d0a05d57c856c8b68342ac075fb8d5f0f26f5df
+Subproject 3ae4bcc5c40d63d91c5248311b93419e4faabf8
diff --git a/src/exchange/taler-exchange-httpd_age-withdraw.c b/src/exchange/taler-exchange-httpd_age-withdraw.c
index 9102fa346..dba4b9bef 100644
--- a/src/exchange/taler-exchange-httpd_age-withdraw.c
+++ b/src/exchange/taler-exchange-httpd_age-withdraw.c
@@ -92,6 +92,13 @@ static void
free_age_withdraw_context_resources (struct AgeWithdrawContext *awc)
{
GNUNET_free (awc->denom_hs);
+ for (unsigned int i = 0; i<awc->num_coins; i++)
+ {
+ for (unsigned int kappa = 0; kappa<TALER_CNC_KAPPA; kappa++)
+ {
+ TALER_blinded_planchet_free (&awc->coin_evs[i][kappa]);
+ }
+ }
GNUNET_free (awc->coin_evs);
GNUNET_free (awc->commitment.denom_serials);
/*
@@ -204,6 +211,7 @@ parse_age_withdraw_json (
/* Parse blinded envelopes. */
json_array_foreach (j_blinded_coin_evs, idx, value) {
const json_t *j_kappa_coin_evs = value;
+
if (! json_is_array (j_kappa_coin_evs))
{
GNUNET_snprintf (buf,
diff --git a/src/exchange/taler-exchange-httpd_aml-decision.c b/src/exchange/taler-exchange-httpd_aml-decision.c
index eef1e9ead..67e1246eb 100644
--- a/src/exchange/taler-exchange-httpd_aml-decision.c
+++ b/src/exchange/taler-exchange-httpd_aml-decision.c
@@ -39,6 +39,7 @@ TEH_handler_post_aml_decision (
{
struct MHD_Connection *connection = rc->connection;
const char *justification;
+ const char *new_measure = NULL;
bool to_investigate;
struct GNUNET_TIME_Timestamp decision_time;
const json_t *new_rules;
@@ -46,6 +47,11 @@ TEH_handler_post_aml_decision (
struct TALER_PaytoHashP h_payto;
struct TALER_AmlOfficerSignatureP officer_sig;
struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_string (
+ "new_measure",
+ &new_measure),
+ NULL),
GNUNET_JSON_spec_string ("justification",
&justification),
GNUNET_JSON_spec_fixed_auto ("h_payto",
@@ -65,6 +71,7 @@ TEH_handler_post_aml_decision (
GNUNET_JSON_spec_end ()
};
struct GNUNET_TIME_Timestamp expiration_time;
+ json_t *jmeasures = NULL;
{
enum GNUNET_GenericReturnValue res;
@@ -88,6 +95,7 @@ TEH_handler_post_aml_decision (
&h_payto,
new_rules,
properties,
+ new_measure,
to_investigate,
officer_pub,
&officer_sig))
@@ -114,7 +122,22 @@ TEH_handler_post_aml_decision (
"legitimization rule malformed");
}
expiration_time = TALER_KYCLOGIC_rules_get_expiration (lrs);
-
+ if (NULL != new_measure)
+ {
+ jmeasures = TALER_KYCLOGIC_get_measure (lrs,
+ new_measure);
+ if (NULL == jmeasures)
+ {
+ GNUNET_break_op (0);
+ /* Request specified a new_measure for which the given
+ rule set does not work as it does not define the measure */
+ return TALER_MHD_reply_with_error (
+ connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ "new_measure/new_rules");
+ }
+ }
TALER_KYCLOGIC_rules_free (lrs);
}
@@ -122,6 +145,7 @@ TEH_handler_post_aml_decision (
enum GNUNET_DB_QueryStatus qs;
struct GNUNET_TIME_Timestamp last_date;
bool invalid_officer = true;
+ bool unknown_account = false;
qs = TEH_plugin->insert_aml_decision (TEH_plugin->cls,
&h_payto,
@@ -130,11 +154,14 @@ TEH_handler_post_aml_decision (
properties,
new_rules,
to_investigate,
+ jmeasures,
justification,
officer_pub,
&officer_sig,
&invalid_officer,
+ &unknown_account,
&last_date);
+ json_decref (jmeasures);
if (qs <= 0)
{
GNUNET_break (0);
@@ -152,7 +179,15 @@ TEH_handler_post_aml_decision (
MHD_HTTP_FORBIDDEN,
TALER_EC_EXCHANGE_AML_DECISION_INVALID_OFFICER,
NULL);
- return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+ if (unknown_account)
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (
+ connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_EXCHANGE_GENERIC_BANK_ACCOUNT_UNKNOWN,
+ "h_payto");
}
if (GNUNET_TIME_timestamp_cmp (last_date,
>=,
@@ -165,6 +200,8 @@ TEH_handler_post_aml_decision (
TALER_EC_EXCHANGE_AML_DECISION_MORE_RECENT_PRESENT,
NULL);
}
+
+
}
return TALER_MHD_reply_static (
connection,
diff --git a/src/exchange/taler-exchange-httpd_aml-decisions-get.c b/src/exchange/taler-exchange-httpd_aml-decisions-get.c
index 2d1c1192e..9059d1437 100644
--- a/src/exchange/taler-exchange-httpd_aml-decisions-get.c
+++ b/src/exchange/taler-exchange-httpd_aml-decisions-get.c
@@ -68,7 +68,7 @@ record_cb (
GNUNET_assert (
0 ==
- json_array_append (
+ json_array_append_new (
records,
GNUNET_JSON_PACK (
GNUNET_JSON_pack_data_auto ("h_payto",
diff --git a/src/exchange/taler-exchange-httpd_kyc-info.c b/src/exchange/taler-exchange-httpd_kyc-info.c
index 768703690..88c9fc579 100644
--- a/src/exchange/taler-exchange-httpd_kyc-info.c
+++ b/src/exchange/taler-exchange-httpd_kyc-info.c
@@ -424,7 +424,7 @@ TEH_handler_kyc_info (
GNUNET_JSON_pack_object_steal ("voluntary_checks",
NULL)));
}
- if ( (last_row == kyp->etag_in) &&
+ if ( (legitimization_measure_last_row == kyp->etag_in) &&
GNUNET_TIME_absolute_is_future (kyp->timeout) )
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
diff --git a/src/exchange/taler-exchange-httpd_kyc-proof.c b/src/exchange/taler-exchange-httpd_kyc-proof.c
index 2539dd614..657c28c6a 100644
--- a/src/exchange/taler-exchange-httpd_kyc-proof.c
+++ b/src/exchange/taler-exchange-httpd_kyc-proof.c
@@ -181,6 +181,7 @@ proof_finish (
struct KycProofContext *kpc = cls;
kpc->kat = NULL;
+ GNUNET_assert (NULL == kpc->response);
kpc->response_code = http_status;
kpc->response = response;
kpc_resume (kpc);
diff --git a/src/exchange/taler-exchange-httpd_kyc-upload.c b/src/exchange/taler-exchange-httpd_kyc-upload.c
index 2b870249d..9dd16b0cb 100644
--- a/src/exchange/taler-exchange-httpd_kyc-upload.c
+++ b/src/exchange/taler-exchange-httpd_kyc-upload.c
@@ -242,6 +242,11 @@ upload_cleaner (struct TEH_RequestContext *rc)
TEH_kyc_finished_cancel (uc->kat);
uc->kat = NULL;
}
+ if (NULL != uc->response)
+ {
+ MHD_destroy_response (uc->response);
+ uc->response = NULL;
+ }
MHD_destroy_post_processor (uc->pp);
GNUNET_free (uc->filename);
GNUNET_free (uc->content_type);
@@ -340,6 +345,9 @@ aml_trigger_callback (
{
struct UploadContext *uc = cls;
+ uc->kat = NULL;
+ GNUNET_assert (NULL == uc->response);
+ GNUNET_assert (NULL != response);
uc->response_code = http_status;
uc->response = response;
MHD_resume_connection (uc->rc->connection);
@@ -443,6 +451,7 @@ TEH_handler_kyc_upload (
return mres;
}
finish_key (uc);
+ GNUNET_assert (NULL == uc->kat);
{
uint64_t legi_process_row;
@@ -584,6 +593,7 @@ TEH_handler_kyc_upload (
TALER_EC_EXCHANGE_KYC_GENERIC_AML_LOGIC_BUG,
"TEH_kyc_finished");
}
+ MHD_suspend_connection (uc->rc->connection);
GNUNET_CONTAINER_DLL_insert (uc_head,
uc_tail,
uc);
diff --git a/src/exchange/taler-exchange-httpd_kyc-webhook.c b/src/exchange/taler-exchange-httpd_kyc-webhook.c
index 67e28276d..9cdcfb66b 100644
--- a/src/exchange/taler-exchange-httpd_kyc-webhook.c
+++ b/src/exchange/taler-exchange-httpd_kyc-webhook.c
@@ -162,6 +162,7 @@ kyc_aml_webhook_finished (
struct KycWebhookContext *kwh = cls;
kwh->kat = NULL;
+ GNUNET_assert (NULL == kwh->response);
kwh->response = response;
kwh->response_code = http_status;
kwh_resume (kwh);
diff --git a/src/exchange/taler-exchange-httpd_reserves_get_attest.c b/src/exchange/taler-exchange-httpd_reserves_get_attest.c
index ca671f621..c3cb7bc16 100644
--- a/src/exchange/taler-exchange-httpd_reserves_get_attest.c
+++ b/src/exchange/taler-exchange-httpd_reserves_get_attest.c
@@ -104,9 +104,10 @@ kyc_process_cb (void *cls,
if (duplicate)
continue;
GNUNET_assert (0 ==
- json_array_append (rsc->attributes,
- json_string (name)));
+ json_array_append_new (rsc->attributes,
+ json_string (name)));
}
+ json_decref (attrs);
}
diff --git a/src/exchange/taler-exchange-httpd_reserves_purse.c b/src/exchange/taler-exchange-httpd_reserves_purse.c
index bb635c3cc..6186afe4e 100644
--- a/src/exchange/taler-exchange-httpd_reserves_purse.c
+++ b/src/exchange/taler-exchange-httpd_reserves_purse.c
@@ -744,9 +744,12 @@ TEH_handler_reserves_purse (
GNUNET_free (rpc.payto_uri);
if (! rpc.kyc.ok)
+ {
+ GNUNET_JSON_parse_free (spec);
return TEH_RESPONSE_reply_kyc_required (connection,
&rpc.h_payto,
&rpc.kyc);
+ }
/* generate regular response */
{
MHD_RESULT res;
diff --git a/src/exchangedb/exchange_do_insert_aml_decision.sql b/src/exchangedb/exchange_do_insert_aml_decision.sql
index 59c62d55b..9c86f13f3 100644
--- a/src/exchangedb/exchange_do_insert_aml_decision.sql
+++ b/src/exchangedb/exchange_do_insert_aml_decision.sql
@@ -22,17 +22,25 @@ CREATE OR REPLACE FUNCTION exchange_do_insert_aml_decision(
IN in_properties TEXT,
IN in_new_rules TEXT,
IN in_to_investigate BOOLEAN,
+ IN in_jmeasures TEXT,
IN in_justification TEXT,
IN in_decider_pub BYTEA,
IN in_decider_sig BYTEA,
IN in_notify_s TEXT,
OUT out_invalid_officer BOOLEAN,
+ OUT out_account_unknown BOOLEAN,
OUT out_last_date INT8)
LANGUAGE plpgsql
AS $$
DECLARE
my_outcome_serial_id INT8;
+ my_access_token BYTEA;
+ my_max_dp INT4;
BEGIN
+
+out_account_unknown=FALSE;
+
+
-- Check officer is eligible to make decisions.
PERFORM
FROM aml_staff
@@ -70,6 +78,56 @@ ELSE
out_last_date = 0;
END IF;
+-- Only do this if we have in_jmeasures to trigger
+IF in_jmeasures IS NOT NULL
+THEN
+
+ -- Note: in_payto_uri is allowed to be NULL *if*
+ -- in_h_payto is already in wire_targets
+ SELECT
+ access_token
+ INTO
+ my_access_token
+ FROM wire_targets
+ WHERE wire_target_h_payto=in_h_payto;
+
+ -- Very strange, should never happen that we
+ -- take an AML decision on an unknown account!
+ IF NOT FOUND
+ THEN
+ out_account_unknown=TRUE;
+ RETURN;
+ END IF;
+
+ -- Find current maximum DP
+ SELECT COALESCE(MAX(display_priority),0)
+ INTO my_max_dp
+ FROM legitimization_measures
+ WHERE access_token=my_access_token
+ AND NOT is_finished;
+
+ -- Enable legitimization measure
+ INSERT INTO legitimization_measures
+ (access_token
+ ,start_time
+ ,jmeasures
+ ,display_priority)
+ VALUES
+ (my_access_token
+ ,in_decision_time
+ ,in_jmeasures
+ ,my_max_dp + 1);
+
+ -- end if for where we had non-NULL in_jmeasures
+END IF;
+
+UPDATE legitimization_outcomes
+ SET is_active=FALSE
+ WHERE h_payto=in_h_payto
+ -- this clause is a minor optimization to avoid
+ -- updating outcomes that have long expired.
+ AND expiration_time >= in_decision_time;
+
INSERT INTO legitimization_outcomes
(h_payto
,decision_time
@@ -120,5 +178,5 @@ INSERT INTO kyc_alerts
END $$;
-COMMENT ON FUNCTION exchange_do_insert_aml_decision(BYTEA, INT8, INT8, TEXT, TEXT, BOOLEAN, TEXT, BYTEA, BYTEA, TEXT)
+COMMENT ON FUNCTION exchange_do_insert_aml_decision(BYTEA, INT8, INT8, TEXT, TEXT, BOOLEAN, TEXT, TEXT, BYTEA, BYTEA, TEXT)
IS 'Checks whether the AML officer is eligible to make AML decisions and if so inserts the decision into the table';
diff --git a/src/exchangedb/exchange_do_insert_kyc_attributes.sql b/src/exchangedb/exchange_do_insert_kyc_attributes.sql
index 12f76c17d..0c907f279 100644
--- a/src/exchangedb/exchange_do_insert_kyc_attributes.sql
+++ b/src/exchangedb/exchange_do_insert_kyc_attributes.sql
@@ -41,6 +41,14 @@ DECLARE
ini_event TEXT;
BEGIN
+
+UPDATE legitimization_outcomes
+ SET is_active=FALSE
+ WHERE h_payto=in_h_payto
+ -- this clause is a minor optimization to avoid
+ -- updating outcomes that have long expired.
+ AND expiration_time >= in_collection_time_ts;
+
INSERT INTO legitimization_outcomes
(h_payto
,decision_time
@@ -107,7 +115,6 @@ UPDATE reserves
((current_balance).val > 0 ) )
AND (expiration_date > in_collection_time_ts);
-
IF in_to_investigate
THEN
INSERT INTO aml_status
@@ -135,13 +142,12 @@ EXECUTE FORMAT (
'NOTIFY %s'
,in_kyc_completed_notify_s);
-
INSERT INTO kyc_alerts
(h_payto
,trigger_type)
VALUES
- (in_h_payto,1);
-
+ (in_h_payto,1)
+ ON CONFLICT DO NOTHING;
END $$;
diff --git a/src/exchangedb/pg_insert_aml_decision.c b/src/exchangedb/pg_insert_aml_decision.c
index d1e618282..f33aa0a01 100644
--- a/src/exchangedb/pg_insert_aml_decision.c
+++ b/src/exchangedb/pg_insert_aml_decision.c
@@ -36,10 +36,12 @@ TEH_PG_insert_aml_decision (
const json_t *properties,
const json_t *new_rules,
bool to_investigate,
+ const json_t *jmeasures,
const char *justification,
const struct TALER_AmlOfficerPublicKeyP *decider_pub,
const struct TALER_AmlOfficerSignatureP *decider_sig,
bool *invalid_officer,
+ bool *unknown_account,
struct GNUNET_TIME_Timestamp *last_date)
{
struct PostgresClosure *pg = cls;
@@ -59,6 +61,9 @@ TEH_PG_insert_aml_decision (
: GNUNET_PQ_query_param_null (),
TALER_PQ_query_param_json (new_rules),
GNUNET_PQ_query_param_bool (to_investigate),
+ NULL != jmeasures
+ ? TALER_PQ_query_param_json (jmeasures)
+ : GNUNET_PQ_query_param_null (),
GNUNET_PQ_query_param_string (justification),
GNUNET_PQ_query_param_auto_from_type (decider_pub),
GNUNET_PQ_query_param_auto_from_type (decider_sig),
@@ -68,6 +73,8 @@ TEH_PG_insert_aml_decision (
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_bool ("out_invalid_officer",
invalid_officer),
+ GNUNET_PQ_result_spec_bool ("out_account_unknown",
+ unknown_account),
GNUNET_PQ_result_spec_timestamp ("out_last_date",
last_date),
GNUNET_PQ_result_spec_end
@@ -78,9 +85,10 @@ TEH_PG_insert_aml_decision (
"do_insert_aml_decision",
"SELECT"
" out_invalid_officer"
+ ",out_account_unknown"
",out_last_date"
" FROM exchange_do_insert_aml_decision"
- "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);");
+ "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11);");
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"do_insert_aml_decision",
params,
diff --git a/src/exchangedb/pg_insert_aml_decision.h b/src/exchangedb/pg_insert_aml_decision.h
index 84fc4387c..ab75845ff 100644
--- a/src/exchangedb/pg_insert_aml_decision.h
+++ b/src/exchangedb/pg_insert_aml_decision.h
@@ -37,10 +37,13 @@
* @param properties JSON object with properties to set for the account
* @param new_rules JSON array with new AML/KYC rules
* @param to_investigate true if AML staff should look more into this account
+ * @param jmeasures a JSON with LegitimizationMeasures to apply to the
+ * account, or NULL to not apply any measure right now
* @param justification human-readable text justifying the decision
* @param decider_pub public key of the staff member
* @param decider_sig signature of the staff member
* @param[out] invalid_officer set to TRUE if @a decider_pub is not allowed to make decisions right now
+ * @param[out] unknown_account set to TRUE if @a h_payto does not refer to a known account and @a jmeasures was given
* @param[out] last_date set to the previous decision time;
* the INSERT is not performed if @a last_date is not before @a decision_time
* @return database transaction status
@@ -54,10 +57,12 @@ TEH_PG_insert_aml_decision (
const json_t *properties,
const json_t *new_rules,
bool to_investigate,
+ const json_t *jmeasures,
const char *justification,
const struct TALER_AmlOfficerPublicKeyP *decider_pub,
const struct TALER_AmlOfficerSignatureP *decider_sig,
bool *invalid_officer,
+ bool *unknown_account,
struct GNUNET_TIME_Timestamp *last_date);
diff --git a/src/exchangedb/pg_insert_kyc_attributes.c b/src/exchangedb/pg_insert_kyc_attributes.c
index cbdcb7c63..e7a0c12bd 100644
--- a/src/exchangedb/pg_insert_kyc_attributes.c
+++ b/src/exchangedb/pg_insert_kyc_attributes.c
@@ -109,7 +109,7 @@ TEH_PG_insert_kyc_attributes (
GNUNET_PQ_cleanup_query_params_closures (params);
GNUNET_free (kyc_completed_notify_s);
GNUNET_PQ_event_do_poll (pg->conn);
- if (qs < 0)
+ if (qs <= 0)
return qs;
if (! ok)
return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
diff --git a/src/exchangedb/pg_lookup_aml_history.c b/src/exchangedb/pg_lookup_aml_history.c
index 077e2781c..0eab9a2a2 100644
--- a/src/exchangedb/pg_lookup_aml_history.c
+++ b/src/exchangedb/pg_lookup_aml_history.c
@@ -86,9 +86,9 @@ handle_aml_entry (void *cls,
&justification),
GNUNET_PQ_result_spec_auto_from_type ("decider_pub",
&decider_pub),
- TALER_PQ_result_spec_json ("properties",
+ TALER_PQ_result_spec_json ("jproperties",
&jproperties),
- TALER_PQ_result_spec_json ("new_rules",
+ TALER_PQ_result_spec_json ("jnew_rules",
&jnew_rules),
GNUNET_PQ_result_spec_bool ("to_investigate",
&to_investigate),
diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h
index 11ab2bce8..ac95e4756 100644
--- a/src/include/taler_crypto_lib.h
+++ b/src/include/taler_crypto_lib.h
@@ -2668,6 +2668,7 @@ TALER_officer_aml_query_verify (
* @param new_rules new KYC rules to apply to the account
* Must be a "LegitimizationRuleSet".
* @param properties properties of the account, can be NULL
+ * @param new_check new KYC check to run, NULL for none
* @param to_investigate true if the account should be investigated by AML staff
* @param officer_priv private key of AML officer
* @param[out] officer_sig where to write the signature
@@ -2679,6 +2680,7 @@ TALER_officer_aml_decision_sign (
const struct TALER_PaytoHashP *h_payto,
const json_t *new_rules,
const json_t *properties,
+ const char *new_check,
bool to_investigate,
const struct TALER_AmlOfficerPrivateKeyP *officer_priv,
struct TALER_AmlOfficerSignatureP *officer_sig);
@@ -2693,6 +2695,7 @@ TALER_officer_aml_decision_sign (
* decision is about
* @param new_rules new KYC rules to apply to the account
* @param properties properties of the account, can be NULL
+ * @param new_check new KYC check to run, NULL for none
* @param to_investigate true if the account should be investigated by AML staff
* @param officer_pub public key of AML officer
* @param officer_sig signature to verify
@@ -2705,6 +2708,7 @@ TALER_officer_aml_decision_verify (
const struct TALER_PaytoHashP *h_payto,
const json_t *new_rules,
const json_t *properties,
+ const char *new_check,
bool to_investigate,
const struct TALER_AmlOfficerPublicKeyP *officer_pub,
const struct TALER_AmlOfficerSignatureP *officer_sig);
diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h
index 98596382c..3a6610f3d 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -7490,14 +7490,18 @@ struct TALER_EXCHANGEDB_Plugin
*
* @param cls closure
* @param h_payto account for which the attribute data is stored
- * @param new_rules new rules to apply
* @param decision_time when was the decision made
+ * @param expiration_time when does the decision expire
+ * @param properties JSON object with properties to set for the account
+ * @param new_rules JSON array with new AML/KYC rules
+ * @param to_investigate true if AML staff should look more into this account
+ * @param jmeasures a JSON with LegitimizationMeasures to apply to the
+ * account, or NULL to not apply any measure right now
* @param justification human-readable text justifying the decision
- * @param kyc_requirements specific KYC requirements being imposed
- * @param requirements_row row in the KYC table for this process, 0 for none
* @param decider_pub public key of the staff member
* @param decider_sig signature of the staff member
* @param[out] invalid_officer set to TRUE if @a decider_pub is not allowed to make decisions right now
+ * @param[out] unknown_account set to TRUE if @a h_payto does not refer to a known account and @a jmeasures was given
* @param[out] last_date set to the previous decision time;
* the INSERT is not performed if @a last_date is not before @a decision_time
* @return database transaction status
@@ -7511,10 +7515,12 @@ struct TALER_EXCHANGEDB_Plugin
const json_t *properties,
const json_t *new_rules,
bool to_investigate,
+ const json_t *jmeasures,
const char *justification,
const struct TALER_AmlOfficerPublicKeyP *decider_pub,
const struct TALER_AmlOfficerSignatureP *decider_sig,
bool *invalid_officer,
+ bool *unknown_account,
struct GNUNET_TIME_Timestamp *last_date);
diff --git a/src/include/taler_kyclogic_lib.h b/src/include/taler_kyclogic_lib.h
index 1fcf65ace..e99a3f2a9 100644
--- a/src/include/taler_kyclogic_lib.h
+++ b/src/include/taler_kyclogic_lib.h
@@ -534,6 +534,19 @@ TALER_KYCLOGIC_measure_to_requirement (
/**
+ * Lookup @a measure_name in @a lrs and create JSON
+ * object with the corresponding LegitimizationMeasures.
+ *
+ * @param lrs set of legitimization rules
+ * @param measure_name name of a measure to trigger from @a lrs
+ * @return JSON object of type LegitimizationMeasures
+ */
+json_t *
+TALER_KYCLOGIC_get_measure (
+ const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs,
+ const char *measure_name);
+
+/**
* Lookup the provider for the given @a check_name.
*
* @param check_name check to lookup provider for
diff --git a/src/kyclogic/kyclogic_api.c b/src/kyclogic/kyclogic_api.c
index 0930371c6..fad66e914 100644
--- a/src/kyclogic/kyclogic_api.c
+++ b/src/kyclogic/kyclogic_api.c
@@ -176,13 +176,6 @@ struct TALER_KYCLOGIC_LegitimizationRuleSet
char *successor_measure;
/**
- * Name of the check that becomes active when this
- * measure is triggered.
- * NULL for no check (allowed, but should be rare).
- */
- char *new_check;
-
- /**
* Array of the rules.
*/
struct TALER_KYCLOGIC_KycRule *kyc_rules;
@@ -487,7 +480,6 @@ TALER_KYCLOGIC_rules_parse (const json_t *jlrs)
struct GNUNET_TIME_Timestamp expiration_time;
const char *successor_measure = NULL;
const json_t *jrules;
- const char *new_check = NULL;
const json_t *jcustom_measures = NULL;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_timestamp (
@@ -498,11 +490,6 @@ TALER_KYCLOGIC_rules_parse (const json_t *jlrs)
"successor_measure",
&successor_measure),
NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string (
- "new_check",
- &new_check),
- NULL),
GNUNET_JSON_spec_array_const ("rules",
&jrules),
GNUNET_JSON_spec_mark_optional (
@@ -541,10 +528,6 @@ TALER_KYCLOGIC_rules_parse (const json_t *jlrs)
= (NULL == successor_measure)
? NULL
: GNUNET_strdup (successor_measure);
- lrs->new_check
- = (NULL == new_check)
- ? NULL
- : GNUNET_strdup (new_check);
lrs->num_kyc_rules
= (unsigned int) json_array_size (jrules);
if (((size_t) lrs->num_kyc_rules) !=
@@ -606,10 +589,10 @@ TALER_KYCLOGIC_rules_parse (const json_t *jlrs)
goto cleanup;
}
rule->lrs = lrs;
+ rule->num_measures = json_array_size (jmeasures);
rule->next_measures
= GNUNET_new_array (rule->num_measures,
char *);
- rule->num_measures = json_array_size (jmeasures);
if (((size_t) rule->num_measures) !=
json_array_size (jmeasures))
{
@@ -727,7 +710,6 @@ TALER_KYCLOGIC_rules_free (struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs)
GNUNET_free (lrs->kyc_rules);
GNUNET_free (lrs->custom_measures);
GNUNET_free (lrs->successor_measure);
- GNUNET_free (lrs->new_check);
GNUNET_free (lrs);
}
@@ -883,15 +865,18 @@ find_measure (const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs,
return cm;
}
}
- /* Try measures from default rules */
- for (unsigned int i = 0; i<default_rules.num_custom_measures; i++)
+ if (lrs != &default_rules)
{
- const struct TALER_KYCLOGIC_Measure *cm
- = &default_rules.custom_measures[i];
+ /* Try measures from default rules */
+ for (unsigned int i = 0; i<default_rules.num_custom_measures; i++)
+ {
+ const struct TALER_KYCLOGIC_Measure *cm
+ = &default_rules.custom_measures[i];
- if (0 == strcmp (measure_name,
- cm->measure_name))
- return cm;
+ if (0 == strcmp (measure_name,
+ cm->measure_name))
+ return cm;
+ }
}
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Measure `%s' not found\n",
@@ -950,6 +935,58 @@ TALER_KYCLOGIC_rule_to_measures (const struct TALER_KYCLOGIC_KycRule *r)
json_t *
+TALER_KYCLOGIC_get_measure (
+ const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs,
+ const char *measure_name)
+{
+ const struct TALER_KYCLOGIC_Measure *ms;
+ json_t *mi;
+ json_t *jmeasures;
+
+ if (0 == strcmp ("verboten",
+ measure_name))
+ {
+ jmeasures = json_array ();
+ GNUNET_assert (NULL != jmeasures);
+ return GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_array_steal ("measures",
+ jmeasures),
+ GNUNET_JSON_pack_bool ("is_and_combinator",
+ false),
+ GNUNET_JSON_pack_bool ("verboten",
+ true));
+ }
+ ms = find_measure (lrs,
+ measure_name);
+ if (NULL == ms)
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ mi = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("check_name",
+ ms->check_name),
+ GNUNET_JSON_pack_string ("prog_name",
+ ms->prog_name),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_object_incref ("context",
+ ms->context)));
+ jmeasures = json_array ();
+ GNUNET_assert (NULL != jmeasures);
+ GNUNET_assert (0 ==
+ json_array_append_new (jmeasures,
+ mi));
+ return GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_array_steal ("measures",
+ jmeasures),
+ GNUNET_JSON_pack_bool ("is_and_combinator",
+ false),
+ GNUNET_JSON_pack_bool ("verboten",
+ false));
+}
+
+
+json_t *
TALER_KYCLOGIC_check_to_measures (
const struct TALER_KYCLOGIC_KycCheckContext *kcc)
{
@@ -2109,18 +2146,18 @@ static int
sort_by_timeframe (const void *p1,
const void *p2)
{
- struct TALER_KYCLOGIC_KycRule **r1
- = (struct TALER_KYCLOGIC_KycRule **) p1;
- struct TALER_KYCLOGIC_KycRule **r2
- = (struct TALER_KYCLOGIC_KycRule **) p2;
+ struct TALER_KYCLOGIC_KycRule *r1
+ = (struct TALER_KYCLOGIC_KycRule *) p1;
+ struct TALER_KYCLOGIC_KycRule *r2
+ = (struct TALER_KYCLOGIC_KycRule *) p2;
- if (GNUNET_TIME_relative_cmp ((*r1)->timeframe,
+ if (GNUNET_TIME_relative_cmp (r1->timeframe,
<,
- (*r2)->timeframe))
+ r2->timeframe))
return -1;
- if (GNUNET_TIME_relative_cmp ((*r1)->timeframe,
+ if (GNUNET_TIME_relative_cmp (r1->timeframe,
>,
- (*r2)->timeframe))
+ r2->timeframe))
return 1;
return 0;
}
@@ -2439,20 +2476,8 @@ TALER_KYCLOGIC_requirements_to_check (
lrs = &default_rules;
if (NULL == measure_name)
{
- /* No measure selected, return the "new_check" */
- if (0 != strcasecmp (lrs->new_check,
- "SKIP"))
- {
- kcc->check = find_check (lrs->new_check);
- GNUNET_break (NULL != kcc->check);
- }
- else
- {
- kcc->check = NULL;
- }
- kcc->prog_name = measure->prog_name;
- kcc->context = measure->context;
- return GNUNET_OK;
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
}
for (unsigned int i = 0; i<kyc_rule->num_measures; i++)
{
@@ -2976,8 +3001,10 @@ TALER_KYCLOGIC_select_measure (
check_name),
GNUNET_JSON_spec_string ("prog_name",
prog_name),
- GNUNET_JSON_spec_object_const ("context",
- context),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_object_const ("context",
+ context),
+ NULL),
GNUNET_JSON_spec_end ()
};
@@ -3414,8 +3441,9 @@ TALER_KYCLOGIC_run_aml_program2 (
json_t *input;
input = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_object_incref ("context",
- (json_t *) context),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_object_incref ("context",
+ (json_t *) context)),
GNUNET_JSON_pack_object_incref ("attributes",
(json_t *) attributes),
GNUNET_JSON_pack_array_incref ("aml_history",
diff --git a/src/lib/exchange_api_add_aml_decision.c b/src/lib/exchange_api_add_aml_decision.c
index 1fee742b8..53cd04eb5 100644
--- a/src/lib/exchange_api_add_aml_decision.c
+++ b/src/lib/exchange_api_add_aml_decision.c
@@ -130,7 +130,7 @@ TALER_EXCHANGE_add_aml_decision (
const struct TALER_PaytoHashP *h_payto,
struct GNUNET_TIME_Timestamp decision_time,
const char *successor_measure,
- const char *new_check,
+ const char *new_measure,
struct GNUNET_TIME_Timestamp expiration_time,
unsigned int num_rules,
const struct TALER_EXCHANGE_AccountRule *rules,
@@ -216,9 +216,6 @@ TALER_EXCHANGE_add_aml_decision (
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_string ("successor_measure",
successor_measure)),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("new_check",
- new_check)),
GNUNET_JSON_pack_array_steal ("rules",
jrules),
GNUNET_JSON_pack_object_steal ("custom_measures",
@@ -233,6 +230,7 @@ TALER_EXCHANGE_add_aml_decision (
h_payto,
new_rules,
properties,
+ new_measure,
keep_investigating,
officer_priv,
&officer_sig);
@@ -276,6 +274,9 @@ TALER_EXCHANGE_add_aml_decision (
new_rules),
GNUNET_JSON_pack_object_incref ("properties",
(json_t *) properties),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("new_measure",
+ new_measure)),
GNUNET_JSON_pack_bool ("keep_investigating",
keep_investigating),
GNUNET_JSON_pack_data_auto ("officer_sig",
diff --git a/src/testing/test_kyc_api.c b/src/testing/test_kyc_api.c
index 2b19e33f0..423198433 100644
--- a/src/testing/test_kyc_api.c
+++ b/src/testing/test_kyc_api.c
@@ -699,11 +699,12 @@ run (void *cls,
" \"timeframe\":{\"d_us\":3600000000}"
" ,\"threshold\":\"EUR:0\""
" ,\"operation_type\":\"BALANCE\""
+ " ,\"display_priority\":65536"
" ,\"measures\":[\"form-measure\"]"
" ,\"verboten\":false"
" }"
" ]" /* end new rules */
- ",\"new_check\":\"form-check\"" // FIXME: do we need this?
+ ",\"new_measure\":\"form-measure\""
",\"custom_measures\":"
" {"
" \"form-measure\":"
@@ -726,7 +727,6 @@ run (void *cls,
"get-kyc-info-form",
"check-kyc-form",
MHD_HTTP_OK),
-#if FIXME
TALER_TESTING_cmd_post_kyc_form (
"wallet-post-kyc-form",
"get-kyc-info-form",
@@ -740,7 +740,6 @@ run (void *cls,
"wallet-trigger-kyc-for-form-aml",
"EUR:500",
MHD_HTTP_NO_CONTENT),
-#endif
TALER_TESTING_cmd_end ()
};
diff --git a/src/testing/testing_api_cmd_take_aml_decision.c b/src/testing/testing_api_cmd_take_aml_decision.c
index f0eca3e39..e61c03efa 100644
--- a/src/testing/testing_api_cmd_take_aml_decision.c
+++ b/src/testing/testing_api_cmd_take_aml_decision.c
@@ -149,7 +149,7 @@ take_aml_decision_run (void *cls,
const json_t *jmeasures = NULL;
struct GNUNET_TIME_Timestamp expiration_time
= GNUNET_TIME_relative_to_timestamp (ds->expiration_delay);
- const char *new_check = NULL;
+ const char *new_measure = NULL;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_array_const ("rules",
&jrules),
@@ -158,8 +158,8 @@ take_aml_decision_run (void *cls,
&jmeasures),
NULL),
GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string ("new_check",
- &new_check),
+ GNUNET_JSON_spec_string ("new_measure",
+ &new_measure),
NULL),
GNUNET_JSON_spec_end ()
};
@@ -356,7 +356,7 @@ take_aml_decision_run (void *cls,
h_payto,
now,
ds->successor_measure,
- new_check,
+ new_measure,
expiration_time,
num_rules,
rules,
diff --git a/src/util/aml_signatures.c b/src/util/aml_signatures.c
index 49859ef79..a41a0126c 100644
--- a/src/util/aml_signatures.c
+++ b/src/util/aml_signatures.c
@@ -62,6 +62,11 @@ struct TALER_AmlDecisionPS
struct GNUNET_HashCode h_new_rules;
/**
+ * Hash over string with new check.
+ */
+ struct GNUNET_HashCode h_new_measure;
+
+ /**
* 0: no investigation, 1: yes investigation.
*/
uint64_t flags;
@@ -76,6 +81,7 @@ TALER_officer_aml_decision_sign (
const struct TALER_PaytoHashP *h_payto,
const json_t *new_rules,
const json_t *properties,
+ const char *new_measure,
bool to_investigate,
const struct TALER_AmlOfficerPrivateKeyP *officer_priv,
struct TALER_AmlOfficerSignatureP *officer_sig)
@@ -96,6 +102,10 @@ TALER_officer_aml_decision_sign (
&ad.h_properties);
TALER_json_hash (new_rules,
&ad.h_new_rules);
+ if (NULL != new_measure)
+ GNUNET_CRYPTO_hash (new_measure,
+ strlen (new_measure),
+ &ad.h_new_measure);
GNUNET_CRYPTO_eddsa_sign (&officer_priv->eddsa_priv,
&ad,
&officer_sig->eddsa_signature);
@@ -109,6 +119,7 @@ TALER_officer_aml_decision_verify (
const struct TALER_PaytoHashP *h_payto,
const json_t *new_rules,
const json_t *properties,
+ const char *new_measure,
bool to_investigate,
const struct TALER_AmlOfficerPublicKeyP *officer_pub,
const struct TALER_AmlOfficerSignatureP *officer_sig)
@@ -129,6 +140,10 @@ TALER_officer_aml_decision_verify (
&ad.h_properties);
TALER_json_hash (new_rules,
&ad.h_new_rules);
+ if (NULL != new_measure)
+ GNUNET_CRYPTO_hash (new_measure,
+ strlen (new_measure),
+ &ad.h_new_measure);
return GNUNET_CRYPTO_eddsa_verify (
TALER_SIGNATURE_AML_DECISION,
&ad,