diff options
| author | Christian Grothoff <christian@grothoff.org> | 2023-02-14 14:26:00 +0100 | 
|---|---|---|
| committer | Christian Grothoff <christian@grothoff.org> | 2023-02-14 14:26:00 +0100 | 
| commit | afe3f70d336e151598e02ebedb6498e13122530e (patch) | |
| tree | 16b28b9fec850465e963dd1eb2acee796d86d9f2 | |
| parent | 437e6ec86a1cd3a391de437999ad21ac5e256e68 (diff) | |
begin API change to allow AML officers to trigger KYC process
| -rw-r--r-- | src/exchange/taler-exchange-httpd_aml-decision.c | 14 | ||||
| -rw-r--r-- | src/exchangedb/0003-aml_history.sql | 8 | ||||
| -rw-r--r-- | src/exchangedb/exchange_do_insert_aml_decision.sql | 7 | ||||
| -rw-r--r-- | src/exchangedb/pg_insert_aml_decision.c | 11 | ||||
| -rw-r--r-- | src/exchangedb/pg_insert_aml_decision.h | 2 | ||||
| -rw-r--r-- | src/include/taler_crypto_lib.h | 6 | ||||
| -rw-r--r-- | src/include/taler_exchange_service.h | 2 | ||||
| -rw-r--r-- | src/include/taler_exchangedb_plugin.h | 1 | ||||
| -rw-r--r-- | src/include/taler_testing_lib.h | 2 | ||||
| -rw-r--r-- | src/lib/exchange_api_add_aml_decision.c | 5 | ||||
| -rw-r--r-- | src/testing/test_kyc_api.c | 3 | ||||
| -rw-r--r-- | src/testing/testing_api_cmd_take_aml_decision.c | 19 | ||||
| -rw-r--r-- | src/util/aml_signatures.c | 14 | 
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 56935df5..0f586279 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 36c0b386..b411a6fb 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 0009ecb4..8e22c57f 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 7bdd0f57..5a1b7123 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 b539945a..4d4ca6e5 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 5f627491..20ffaf0c 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 15329ad1..5cfe6a98 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 0a389bd6..f4397e29 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 cf427951..37d347c3 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 5e5383f2..7245db3b 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 feeed3c7..12f69569 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 0992945d..871cdb71 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 cad2e748..6d90b25c 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, | 
