summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/exchange/taler-exchange-httpd_aml-decision.c14
-rw-r--r--src/exchangedb/0003-aml_history.sql8
-rw-r--r--src/exchangedb/exchange_do_insert_aml_decision.sql7
-rw-r--r--src/exchangedb/pg_insert_aml_decision.c11
-rw-r--r--src/exchangedb/pg_insert_aml_decision.h2
-rw-r--r--src/include/taler_crypto_lib.h6
-rw-r--r--src/include/taler_exchange_service.h2
-rw-r--r--src/include/taler_exchangedb_plugin.h1
-rw-r--r--src/include/taler_testing_lib.h2
-rw-r--r--src/lib/exchange_api_add_aml_decision.c5
-rw-r--r--src/testing/test_kyc_api.c3
-rw-r--r--src/testing/testing_api_cmd_take_aml_decision.c19
-rw-r--r--src/util/aml_signatures.c14
13 files changed, 90 insertions, 4 deletions
diff --git a/src/exchange/taler-exchange-httpd_aml-decision.c b/src/exchange/taler-exchange-httpd_aml-decision.c
index 56935df55..0f586279b 100644
--- a/src/exchange/taler-exchange-httpd_aml-decision.c
+++ b/src/exchange/taler-exchange-httpd_aml-decision.c
@@ -50,6 +50,7 @@ TEH_handler_post_aml_decision (
uint32_t new_state32;
enum TALER_AmlDecisionState new_state;
struct TALER_AmlOfficerSignatureP officer_sig;
+ json_t *kyc_requirements = NULL;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("officer_sig",
&officer_sig),
@@ -64,6 +65,10 @@ TEH_handler_post_aml_decision (
&decision_time),
GNUNET_JSON_spec_uint32 ("new_state",
&new_state32),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_json ("kyc_requirements",
+ &kyc_requirements),
+ NULL),
GNUNET_JSON_spec_end ()
};
@@ -89,6 +94,7 @@ TEH_handler_post_aml_decision (
&new_threshold,
&h_payto,
new_state,
+ kyc_requirements,
officer_pub,
&officer_sig))
{
@@ -99,6 +105,8 @@ TEH_handler_post_aml_decision (
TALER_EC_EXCHANGE_AML_DECISION_ADD_SIGNATURE_INVALID,
NULL);
}
+
+ // FIXME: check kyc_requirements is well-formed!
{
enum GNUNET_DB_QueryStatus qs;
struct GNUNET_TIME_Timestamp last_date;
@@ -112,6 +120,7 @@ TEH_handler_post_aml_decision (
new_state,
decision_time,
justification,
+ kyc_requirements,
officer_pub,
&officer_sig,
&invalid_officer,
@@ -127,6 +136,11 @@ TEH_handler_post_aml_decision (
TALER_EC_GENERIC_DB_STORE_FAILED,
"add aml_decision");
}
+ if (NULL != kyc_requirements)
+ {
+ // FIXME: act on these!
+ }
+
if (invalid_officer)
{
GNUNET_break_op (0);
diff --git a/src/exchangedb/0003-aml_history.sql b/src/exchangedb/0003-aml_history.sql
index 36c0b3865..b411a6fb1 100644
--- a/src/exchangedb/0003-aml_history.sql
+++ b/src/exchangedb/0003-aml_history.sql
@@ -32,6 +32,7 @@ BEGIN
',new_status INT4 NOT NULL DEFAULT(0)'
',decision_time INT8 NOT NULL DEFAULT(0)'
',justification VARCHAR NOT NULL'
+ ',kyc_requirements VARCHAR'
',decider_pub BYTEA CHECK (LENGTH(decider_pub)=32)'
',decider_sig BYTEA CHECK (LENGTH(decider_sig)=64)'
') %s ;'
@@ -81,6 +82,12 @@ BEGIN
,partition_suffix
);
PERFORM comment_partitioned_column(
+ 'Additional KYC requirements imposed by the AML staff member. Serialized JSON array of strings.'
+ ,'kyc_requirements'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
'Signature key of the staff member affirming the AML decision; of type AML_DECISION'
,'decider_sig'
,table_name
@@ -114,7 +121,6 @@ BEGIN
);
END $$;
--- FIXME: also have INSERT on AML decisions to update AML status!
INSERT INTO exchange_tables
(name
diff --git a/src/exchangedb/exchange_do_insert_aml_decision.sql b/src/exchangedb/exchange_do_insert_aml_decision.sql
index 0009ecb40..8e22c57f8 100644
--- a/src/exchangedb/exchange_do_insert_aml_decision.sql
+++ b/src/exchangedb/exchange_do_insert_aml_decision.sql
@@ -24,6 +24,7 @@ CREATE OR REPLACE FUNCTION exchange_do_insert_aml_decision(
IN in_decider_pub BYTEA,
IN in_decider_sig BYTEA,
IN in_notify_s VARCHAR,
+ IN in_kyc_requirements VARCHAR,
OUT out_invalid_officer BOOLEAN,
OUT out_last_date INT8)
LANGUAGE plpgsql
@@ -84,6 +85,7 @@ INSERT INTO exchange.aml_history
,new_status
,decision_time
,justification
+ ,kyc_requirements
,decider_pub
,decider_sig
) VALUES
@@ -93,6 +95,7 @@ INSERT INTO exchange.aml_history
,in_new_status
,in_decision_time
,in_justification
+ ,in_kyc_requirements
,in_decider_pub
,in_decider_sig);
@@ -105,7 +108,7 @@ THEN
,trigger_type)
VALUES
(in_h_payto,1);
-
+
EXECUTE FORMAT (
'NOTIFY %s'
,in_notify_s);
@@ -116,5 +119,5 @@ END IF;
END $$;
-COMMENT ON FUNCTION exchange_do_insert_aml_decision(BYTEA, INT8, INT4, INT4, INT8, VARCHAR, BYTEA, BYTEA, VARCHAR)
+COMMENT ON FUNCTION exchange_do_insert_aml_decision(BYTEA, INT8, INT4, INT4, INT8, VARCHAR, BYTEA, BYTEA, VARCHAR, VARCHAR)
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/pg_insert_aml_decision.c b/src/exchangedb/pg_insert_aml_decision.c
index 7bdd0f575..5a1b71235 100644
--- a/src/exchangedb/pg_insert_aml_decision.c
+++ b/src/exchangedb/pg_insert_aml_decision.c
@@ -35,6 +35,7 @@ TEH_PG_insert_aml_decision (
enum TALER_AmlDecisionState new_status,
struct GNUNET_TIME_Timestamp decision_time,
const char *justification,
+ const json_t *kyc_requirements,
const struct TALER_AmlOfficerPublicKeyP *decider_pub,
const struct TALER_AmlOfficerSignatureP *decider_sig,
bool *invalid_officer,
@@ -48,6 +49,9 @@ TEH_PG_insert_aml_decision (
.h_payto = *h_payto
};
char *notify_s = GNUNET_PG_get_event_notify_channel (&rep.header);
+ char *kyc_s = (NULL != kyc_requirements)
+ ? json_dumps (kyc_requirements, JSON_COMPACT)
+ : NULL;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (h_payto),
TALER_PQ_query_param_amount (new_threshold),
@@ -57,6 +61,9 @@ TEH_PG_insert_aml_decision (
GNUNET_PQ_query_param_auto_from_type (decider_pub),
GNUNET_PQ_query_param_auto_from_type (decider_sig),
GNUNET_PQ_query_param_string (notify_s),
+ NULL != kyc_requirements
+ ? GNUNET_PQ_query_param_string (kyc_s)
+ : GNUNET_PQ_query_param_null (),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
@@ -74,11 +81,13 @@ TEH_PG_insert_aml_decision (
" out_invalid_officer"
",out_last_date"
" FROM exchange_do_insert_aml_decision"
- "($1, $2, $3, $4, $5, $6, $7, $8, $9);");
+ "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);");
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"do_insert_aml_decision",
params,
rs);
GNUNET_free (notify_s);
+ if (NULL != kyc_s)
+ free (kyc_s);
return qs;
}
diff --git a/src/exchangedb/pg_insert_aml_decision.h b/src/exchangedb/pg_insert_aml_decision.h
index b539945a7..4d4ca6e54 100644
--- a/src/exchangedb/pg_insert_aml_decision.h
+++ b/src/exchangedb/pg_insert_aml_decision.h
@@ -36,6 +36,7 @@
* @param new_status AML decision status
* @param decision_time when was the decision made
* @param justification human-readable text justifying the decision
+ * @param kyc_requirements JSON array with KYC requirements
* @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
@@ -51,6 +52,7 @@ TEH_PG_insert_aml_decision (
enum TALER_AmlDecisionState new_status,
struct GNUNET_TIME_Timestamp decision_time,
const char *justification,
+ const json_t *kyc_requirements,
const struct TALER_AmlOfficerPublicKeyP *decider_pub,
const struct TALER_AmlOfficerSignatureP *decider_sig,
bool *invalid_officer,
diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h
index 5f6274919..20ffaf0cd 100644
--- a/src/include/taler_crypto_lib.h
+++ b/src/include/taler_crypto_lib.h
@@ -2406,6 +2406,8 @@ TALER_officer_aml_query_verify (
* @param h_payto payto URI hash of the account the
* decision is about
* @param new_state updated AML state
+ * @param kyc_requirements additional KYC requirements to
+ * impose, can be NULL
* @param officer_priv private key of AML officer
* @param[out] officer_sig where to write the signature
*/
@@ -2416,6 +2418,7 @@ TALER_officer_aml_decision_sign (
const struct TALER_Amount *new_threshold,
const struct TALER_PaytoHashP *h_payto,
enum TALER_AmlDecisionState new_state,
+ const json_t *kyc_requirements,
const struct TALER_AmlOfficerPrivateKeyP *officer_priv,
struct TALER_AmlOfficerSignatureP *officer_sig);
@@ -2430,6 +2433,8 @@ TALER_officer_aml_decision_sign (
* @param h_payto payto URI hash of the account the
* decision is about
* @param new_state updated AML state
+ * @param kyc_requirements additional KYC requirements to
+ * impose, can be NULL
* @param officer_pub public key of AML officer
* @param officer_sig signature to verify
* @return #GNUNET_OK if the signature is valid
@@ -2441,6 +2446,7 @@ TALER_officer_aml_decision_verify (
const struct TALER_Amount *new_threshold,
const struct TALER_PaytoHashP *h_payto,
enum TALER_AmlDecisionState new_state,
+ const json_t *kyc_requirements,
const struct TALER_AmlOfficerPublicKeyP *officer_pub,
const struct TALER_AmlOfficerSignatureP *officer_sig);
diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h
index 15329ad1c..5cfe6a98e 100644
--- a/src/include/taler_exchange_service.h
+++ b/src/include/taler_exchange_service.h
@@ -4608,6 +4608,7 @@ typedef void
* @param h_payto payto URI hash of the account the
* decision is about
* @param new_state updated AML state
+ * @param kyc_requirements JSON array of KYC requirements being imposed, NULL for none
* @param officer_priv private key of the deciding AML officer
* @param cb function to call with the exchange's result
* @param cb_cls closure for @a cb
@@ -4622,6 +4623,7 @@ TALER_EXCHANGE_add_aml_decision (
const struct TALER_Amount *new_threshold,
const struct TALER_PaytoHashP *h_payto,
enum TALER_AmlDecisionState new_state,
+ const json_t *kyc_requirements,
const struct TALER_AmlOfficerPrivateKeyP *officer_priv,
TALER_EXCHANGE_AddAmlDecisionCallback cb,
void *cb_cls);
diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h
index 0a389bd6e..f4397e296 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -6704,6 +6704,7 @@ struct TALER_EXCHANGEDB_Plugin
enum TALER_AmlDecisionState new_status,
struct GNUNET_TIME_Timestamp decision_time,
const char *justification,
+ const json_t *kyc_requirements,
const struct TALER_AmlOfficerPublicKeyP *decider_pub,
const struct TALER_AmlOfficerSignatureP *decider_sig,
bool *invalid_officer,
diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h
index cf4279514..37d347c30 100644
--- a/src/include/taler_testing_lib.h
+++ b/src/include/taler_testing_lib.h
@@ -2741,6 +2741,7 @@ TALER_TESTING_cmd_set_officer (
* @param new_threshold new threshold to set
* @param justification justification given for the decision
* @param new_state new AML state for the account
+ * @param kyc_requirement KYC requirement to impose
* @param expected_response expected HTTP return status
* @return the command
*/
@@ -2752,6 +2753,7 @@ TALER_TESTING_cmd_take_aml_decision (
const char *new_threshold,
const char *justification,
enum TALER_AmlDecisionState new_state,
+ const char *kyc_requirement,
unsigned int expected_response);
diff --git a/src/lib/exchange_api_add_aml_decision.c b/src/lib/exchange_api_add_aml_decision.c
index 5e5383f25..7245db3b1 100644
--- a/src/lib/exchange_api_add_aml_decision.c
+++ b/src/lib/exchange_api_add_aml_decision.c
@@ -132,6 +132,7 @@ TALER_EXCHANGE_add_aml_decision (
const struct TALER_Amount *new_threshold,
const struct TALER_PaytoHashP *h_payto,
enum TALER_AmlDecisionState new_state,
+ const json_t *kyc_requirements,
const struct TALER_AmlOfficerPrivateKeyP *officer_priv,
TALER_EXCHANGE_AddAmlDecisionCallback cb,
void *cb_cls)
@@ -149,6 +150,7 @@ TALER_EXCHANGE_add_aml_decision (
new_threshold,
h_payto,
new_state,
+ kyc_requirements,
officer_priv,
&officer_sig);
wh = GNUNET_new (struct TALER_EXCHANGE_AddAmlDecision);
@@ -190,6 +192,9 @@ TALER_EXCHANGE_add_aml_decision (
h_payto),
GNUNET_JSON_pack_uint64 ("new_state",
(uint32_t) new_state),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_array_incref ("kyc_requirements",
+ (json_t *) kyc_requirements)),
TALER_JSON_pack_amount ("new_threshold",
new_threshold),
GNUNET_JSON_pack_timestamp ("decision_time",
diff --git a/src/testing/test_kyc_api.c b/src/testing/test_kyc_api.c
index feeed3c78..12f695690 100644
--- a/src/testing/test_kyc_api.c
+++ b/src/testing/test_kyc_api.c
@@ -448,6 +448,7 @@ run (void *cls,
"EUR:10000",
"party time",
TALER_AML_NORMAL,
+ NULL,
MHD_HTTP_FORBIDDEN),
/* Check that no decision was taken, but that we are allowed
to read this information */
@@ -468,6 +469,7 @@ run (void *cls,
"EUR:10000",
"party time",
TALER_AML_NORMAL,
+ NULL,
MHD_HTTP_NO_CONTENT),
TALER_TESTING_cmd_check_aml_decisions ("check-decisions-one-normal",
"create-aml-officer-1",
@@ -489,6 +491,7 @@ run (void *cls,
"EUR:1000",
"party over",
TALER_AML_FROZEN,
+ NULL,
MHD_HTTP_NO_CONTENT),
TALER_TESTING_cmd_check_aml_decisions ("check-decisions-one-frozen",
"create-aml-officer-1",
diff --git a/src/testing/testing_api_cmd_take_aml_decision.c b/src/testing/testing_api_cmd_take_aml_decision.c
index 0992945d6..871cdb712 100644
--- a/src/testing/testing_api_cmd_take_aml_decision.c
+++ b/src/testing/testing_api_cmd_take_aml_decision.c
@@ -73,6 +73,11 @@ struct AmlDecisionState
const char *justification;
/**
+ * KYC requirement to add.
+ */
+ const char *kyc_requirement;
+
+ /**
* Threshold transaction amount.
*/
struct TALER_Amount new_threshold;
@@ -133,6 +138,7 @@ take_aml_decision_run (void *cls,
const struct TALER_PaytoHashP *h_payto;
const struct TALER_AmlOfficerPrivateKeyP *officer_priv;
const struct TALER_TESTING_Command *ref;
+ json_t *kyc_requirements = NULL;
(void) cmd;
now = GNUNET_TIME_timestamp_get ();
@@ -160,6 +166,15 @@ take_aml_decision_run (void *cls,
TALER_TESTING_get_trait_officer_priv (ref,
&officer_priv));
ds->h_payto = *h_payto;
+ if (NULL != ds->kyc_requirement)
+ {
+ kyc_requirements = json_array ();
+ GNUNET_assert (NULL != kyc_requirements);
+ GNUNET_assert (0 ==
+ json_array_append (kyc_requirements,
+ json_string (ds->kyc_requirement)));
+ }
+
ds->dh = TALER_EXCHANGE_add_aml_decision (
is->ctx,
is->exchange_url,
@@ -168,9 +183,11 @@ take_aml_decision_run (void *cls,
&ds->new_threshold,
h_payto,
ds->new_state,
+ kyc_requirements,
officer_priv,
&take_aml_decision_cb,
ds);
+ json_decref (kyc_requirements);
if (NULL == ds->dh)
{
GNUNET_break (0);
@@ -246,6 +263,7 @@ TALER_TESTING_cmd_take_aml_decision (
const char *new_threshold,
const char *justification,
enum TALER_AmlDecisionState new_state,
+ const char *kyc_requirement,
unsigned int expected_response)
{
struct AmlDecisionState *ds;
@@ -253,6 +271,7 @@ TALER_TESTING_cmd_take_aml_decision (
ds = GNUNET_new (struct AmlDecisionState);
ds->officer_ref_cmd = ref_officer;
ds->account_ref_cmd = ref_operation;
+ ds->kyc_requirement = kyc_requirement;
if (GNUNET_OK !=
TALER_string_to_amount (new_threshold,
&ds->new_threshold))
diff --git a/src/util/aml_signatures.c b/src/util/aml_signatures.c
index cad2e7488..6d90b25c2 100644
--- a/src/util/aml_signatures.c
+++ b/src/util/aml_signatures.c
@@ -57,6 +57,12 @@ struct TALER_AmlDecisionPS
struct TALER_PaytoHashP h_payto GNUNET_PACKED;
/**
+ * Hash over JSON array with KYC requirements that were imposed. All zeros
+ * for none.
+ */
+ struct GNUNET_HashCode h_kyc_requirements;
+
+ /**
* What is the new AML status?
*/
uint32_t new_state GNUNET_PACKED;
@@ -72,6 +78,7 @@ TALER_officer_aml_decision_sign (
const struct TALER_Amount *new_threshold,
const struct TALER_PaytoHashP *h_payto,
enum TALER_AmlDecisionState new_state,
+ const json_t *kyc_requirements,
const struct TALER_AmlOfficerPrivateKeyP *officer_priv,
struct TALER_AmlOfficerSignatureP *officer_sig)
{
@@ -87,6 +94,9 @@ TALER_officer_aml_decision_sign (
&ad.h_justification);
TALER_amount_hton (&ad.new_threshold,
new_threshold);
+ if (NULL != kyc_requirements)
+ TALER_json_hash (kyc_requirements,
+ &ad.h_kyc_requirements);
GNUNET_CRYPTO_eddsa_sign (&officer_priv->eddsa_priv,
&ad,
&officer_sig->eddsa_signature);
@@ -100,6 +110,7 @@ TALER_officer_aml_decision_verify (
const struct TALER_Amount *new_threshold,
const struct TALER_PaytoHashP *h_payto,
enum TALER_AmlDecisionState new_state,
+ const json_t *kyc_requirements,
const struct TALER_AmlOfficerPublicKeyP *officer_pub,
const struct TALER_AmlOfficerSignatureP *officer_sig)
{
@@ -115,6 +126,9 @@ TALER_officer_aml_decision_verify (
&ad.h_justification);
TALER_amount_hton (&ad.new_threshold,
new_threshold);
+ if (NULL != kyc_requirements)
+ TALER_json_hash (kyc_requirements,
+ &ad.h_kyc_requirements);
return GNUNET_CRYPTO_eddsa_verify (
TALER_SIGNATURE_AML_DECISION,
&ad,