add new endpoints to main dispatcher

This commit is contained in:
Christian Grothoff 2023-01-21 23:08:29 +01:00
parent 31286b66f2
commit d131951fbe
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
19 changed files with 419 additions and 117 deletions

@ -1 +1 @@
Subproject commit 66228b8a4306f028d843d78fbfcca54260539ff9 Subproject commit 7884adf99ec4d5ccf52b1a5a251b99fb6ab9c2f6

View File

@ -123,6 +123,7 @@ taler_exchange_wirewatch_LDADD = \
taler_exchange_httpd_SOURCES = \ taler_exchange_httpd_SOURCES = \
taler-exchange-httpd.c taler-exchange-httpd.h \ taler-exchange-httpd.c taler-exchange-httpd.h \
taler-exchange-httpd_auditors.c taler-exchange-httpd_auditors.h \ taler-exchange-httpd_auditors.c taler-exchange-httpd_auditors.h \
taler-exchange-httpd_aml-decision.c taler-exchange-httpd_aml-decision.h \
taler-exchange-httpd_batch-deposit.c taler-exchange-httpd_batch-deposit.h \ taler-exchange-httpd_batch-deposit.c taler-exchange-httpd_batch-deposit.h \
taler-exchange-httpd_batch-withdraw.c taler-exchange-httpd_batch-withdraw.h \ taler-exchange-httpd_batch-withdraw.c taler-exchange-httpd_batch-withdraw.h \
taler-exchange-httpd_common_deposit.c taler-exchange-httpd_common_deposit.h \ taler-exchange-httpd_common_deposit.c taler-exchange-httpd_common_deposit.h \
@ -139,12 +140,14 @@ taler_exchange_httpd_SOURCES = \
taler-exchange-httpd_kyc-webhook.c taler-exchange-httpd_kyc-webhook.h \ taler-exchange-httpd_kyc-webhook.c taler-exchange-httpd_kyc-webhook.h \
taler-exchange-httpd_link.c taler-exchange-httpd_link.h \ taler-exchange-httpd_link.c taler-exchange-httpd_link.h \
taler-exchange-httpd_management.h \ taler-exchange-httpd_management.h \
taler-exchange-httpd_management_aml-officers.c \
taler-exchange-httpd_management_auditors.c \ taler-exchange-httpd_management_auditors.c \
taler-exchange-httpd_management_auditors_AP_disable.c \ taler-exchange-httpd_management_auditors_AP_disable.c \
taler-exchange-httpd_management_denominations_HDP_revoke.c \ taler-exchange-httpd_management_denominations_HDP_revoke.c \
taler-exchange-httpd_management_drain.c \ taler-exchange-httpd_management_drain.c \
taler-exchange-httpd_management_extensions.c \ taler-exchange-httpd_management_extensions.c \
taler-exchange-httpd_management_global_fees.c \ taler-exchange-httpd_management_global_fees.c \
taler-exchange-httpd_management_partners.c \
taler-exchange-httpd_management_post_keys.c \ taler-exchange-httpd_management_post_keys.c \
taler-exchange-httpd_management_signkey_EP_revoke.c \ taler-exchange-httpd_management_signkey_EP_revoke.c \
taler-exchange-httpd_management_wire_enable.c \ taler-exchange-httpd_management_wire_enable.c \

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2014-2022 Taler Systems SA Copyright (C) 2014-2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software terms of the GNU Affero General Public License as published by the Free Software
@ -30,6 +30,7 @@
#include "taler_kyclogic_lib.h" #include "taler_kyclogic_lib.h"
#include "taler_templating_lib.h" #include "taler_templating_lib.h"
#include "taler_mhd_lib.h" #include "taler_mhd_lib.h"
#include "taler-exchange-httpd_aml-decision.h"
#include "taler-exchange-httpd_auditors.h" #include "taler-exchange-httpd_auditors.h"
#include "taler-exchange-httpd_batch-deposit.h" #include "taler-exchange-httpd_batch-deposit.h"
#include "taler-exchange-httpd_batch-withdraw.h" #include "taler-exchange-httpd_batch-withdraw.h"
@ -322,6 +323,187 @@ handle_post_coins (struct TEH_RequestContext *rc,
} }
/**
* Signature of functions that handle operations
* authorized by AML officers.
*
* @param rc request context
* @param officer_pub the public key of the AML officer
* @param root uploaded JSON data
* @return MHD result code
*/
typedef MHD_RESULT
(*AmlOpPostHandler)(struct TEH_RequestContext *rc,
const struct TALER_AmlOfficerPublicKeyP *officer_pub,
const json_t *root);
/**
* Handle a "/aml/$OFFICER_PUB/$OP" POST request. Parses the "officer_pub"
* EdDSA key of the officer and demultiplexes based on $OP.
*
* @param rc request context
* @param root uploaded JSON data
* @param args array of additional options
* @return MHD result code
*/
static MHD_RESULT
handle_post_aml (struct TEH_RequestContext *rc,
const json_t *root,
const char *const args[2])
{
struct TALER_AmlOfficerPublicKeyP officer_pub;
static const struct
{
/**
* Name of the operation (args[1])
*/
const char *op;
/**
* Function to call to perform the operation.
*/
AmlOpPostHandler handler;
} h[] = {
{
.op = "decision",
.handler = &TEH_handler_post_aml_decision
},
{
.op = NULL,
.handler = NULL
},
};
if (GNUNET_OK !=
GNUNET_STRINGS_string_to_data (args[0],
strlen (args[0]),
&officer_pub,
sizeof (officer_pub)))
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_EXCHANGE_GENERIC_AML_OFFICER_PUB_MALFORMED,
args[0]);
}
for (unsigned int i = 0; NULL != h[i].op; i++)
if (0 == strcmp (h[i].op,
args[1]))
return h[i].handler (rc,
&officer_pub,
root);
return r404 (rc->connection,
args[1]);
}
/**
* Signature of functions that handle operations
* authorized by AML officers.
*
* @param rc request context
* @param officer_pub the public key of the AML officer
* @param args remaining arguments
* @return MHD result code
*/
typedef MHD_RESULT
(*AmlOpGetHandler)(struct TEH_RequestContext *rc,
const struct TALER_AmlOfficerPublicKeyP *officer_pub,
const char *const args[]);
/**
* Handle a "/aml/$OFFICER_PUB/$OP" GET request. Parses the "officer_pub"
* EdDSA key of the officer, checks the authentication signature, and
* demultiplexes based on $OP.
*
* @param rc request context
* @param args array of additional options
* @return MHD result code
*/
static MHD_RESULT
handle_get_aml (struct TEH_RequestContext *rc,
const char *const args[])
{
struct TALER_AmlOfficerPublicKeyP officer_pub;
static const struct
{
/**
* Name of the operation (args[1])
*/
const char *op;
/**
* Function to call to perform the operation.
*/
AmlOpGetHandler handler;
} h[] = {
#if FIXME_AML_GET_DECISIONS_NOT_IMPLEMENTED
{
.op = "decisions",
.handler = &TEH_handler_get_aml_decisions
},
{
.op = "decision",
.handler = &TEH_handler_get_aml_decision
},
#endif
{
.op = NULL,
.handler = NULL
},
};
if (NULL == args[0])
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_EXCHANGE_GENERIC_AML_OFFICER_PUB_MALFORMED,
"argument missing");
}
if (GNUNET_OK !=
GNUNET_STRINGS_string_to_data (args[0],
strlen (args[0]),
&officer_pub,
sizeof (officer_pub)))
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_EXCHANGE_GENERIC_AML_OFFICER_PUB_MALFORMED,
args[0]);
}
if (NULL == args[1])
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_NOT_FOUND,
TALER_EC_EXCHANGE_GENERIC_WRONG_NUMBER_OF_SEGMENTS,
"AML GET operations must specify an operation identifier");
}
if (1) // FIXME: check AML officer GET signature!
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_FORBIDDEN,
TALER_EC_EXCHANGE_GENERIC_AML_OFFICER_GET_SIGNATURE_INVALID,
NULL);
}
for (unsigned int i = 0; NULL != h[i].op; i++)
if (0 == strcmp (h[i].op,
args[1]))
return h[i].handler (rc,
&officer_pub,
&args[2]);
return r404 (rc->connection,
args[1]);
}
/** /**
* Signature of functions that handle operations on reserves. * Signature of functions that handle operations on reserves.
* *
@ -890,6 +1072,8 @@ handle_post_management (struct TEH_RequestContext *rc,
&exchange_pub, &exchange_pub,
root); root);
} }
/* FIXME-STYLE: all of the following can likely be nicely combined
into an array-based dispatcher to deduplicate the logic... */
if (0 == strcmp (args[0], if (0 == strcmp (args[0],
"keys")) "keys"))
{ {
@ -967,6 +1151,30 @@ handle_post_management (struct TEH_RequestContext *rc,
return TEH_handler_management_post_drain (rc->connection, return TEH_handler_management_post_drain (rc->connection,
root); root);
} }
if (0 == strcmp (args[0],
"aml-officers"))
{
if (NULL != args[1])
{
GNUNET_break_op (0);
return r404 (rc->connection,
"/management/aml-officers/*");
}
return TEH_handler_management_aml_officers (rc->connection,
root);
}
if (0 == strcmp (args[0],
"partners"))
{
if (NULL != args[1])
{
GNUNET_break_op (0);
return r404 (rc->connection,
"/management/partners/*");
}
return TEH_handler_management_partners (rc->connection,
root);
}
GNUNET_break_op (0); GNUNET_break_op (0);
return r404 (rc->connection, return r404 (rc->connection,
"/management/*"); "/management/*");
@ -1289,6 +1497,22 @@ handle_mhd_request (void *cls,
.nargs = 4, .nargs = 4,
.nargs_is_upper_bound = true .nargs_is_upper_bound = true
}, },
/* AML endpoints */
{
.url = "aml",
.method = MHD_HTTP_METHOD_GET,
.handler.get = &handle_get_aml,
.nargs = 4,
.nargs_is_upper_bound = true
},
{
.url = "aml",
.method = MHD_HTTP_METHOD_POST,
.handler.post = &handle_post_aml,
.nargs = 2
},
/* mark end of list */ /* mark end of list */
{ {
.url = NULL .url = NULL

View File

@ -213,7 +213,7 @@ struct TEH_RequestHandler
* *
* @param rc context for the request * @param rc context for the request
* @param json uploaded JSON data * @param json uploaded JSON data
* @param args array of arguments, needs to be of length @e args_expected * @param args array of arguments, needs to be of length @e nargs
* @return MHD result code * @return MHD result code
*/ */
MHD_RESULT MHD_RESULT
@ -225,7 +225,7 @@ struct TEH_RequestHandler
* Function to call to handle DELETE requests. * Function to call to handle DELETE requests.
* *
* @param rc context for the request * @param rc context for the request
* @param args array of arguments, needs to be of length @e args_expected * @param args array of arguments, needs to be of length @e nargs
* @return MHD result code * @return MHD result code
*/ */
MHD_RESULT MHD_RESULT

View File

@ -31,27 +31,26 @@
MHD_RESULT MHD_RESULT
TEH_handler_management_post_aml_decision ( TEH_handler_post_aml_decision (
struct MHD_Connection *connection, struct TEH_RequestContext *rc,
const struct TALER_AmlOfficerPublicKeyP *officer_pub,
const json_t *root) const json_t *root)
{ {
struct MHD_Connection *connection = rc->connection;
const char *justification; const char *justification;
struct GNUNET_TIME_Timestamp decision_time; struct GNUNET_TIME_Timestamp decision_time;
struct TALER_Amount new_threshold; struct TALER_Amount new_threshold;
struct TALER_PaytoHashP h_payto; struct TALER_PaytoHashP h_payto;
uint32_t new_state32; uint32_t new_state32;
enum TALER_AmlDecisionState new_state; enum TALER_AmlDecisionState new_state;
struct TALER_AmlOfficerPublicKeyP officer_pub;
struct TALER_AmlOfficerSignatureP officer_sig; struct TALER_AmlOfficerSignatureP officer_sig;
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
// FIXME: officer_pub is in URL path, not in JSON body!
GNUNET_JSON_spec_fixed_auto ("officer_pub",
&officer_pub),
GNUNET_JSON_spec_fixed_auto ("officer_sig", GNUNET_JSON_spec_fixed_auto ("officer_sig",
&officer_sig), &officer_sig),
GNUNET_JSON_spec_fixed_auto ("h_payto", GNUNET_JSON_spec_fixed_auto ("h_payto",
&h_payto), &h_payto),
TALER_JSON_spec_amount ("new_threshold", TALER_JSON_spec_amount ("new_threshold",
TEH_currency,
&new_threshold), &new_threshold),
GNUNET_JSON_spec_string ("justification", GNUNET_JSON_spec_string ("justification",
&justification), &justification),
@ -76,13 +75,13 @@ TEH_handler_management_post_aml_decision (
new_state = (enum TALER_AmlDecisionState) new_state32; new_state = (enum TALER_AmlDecisionState) new_state32;
TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++; TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
if (GNUNET_OK != if (GNUNET_OK !=
TALER_exchange_aml_decision_verify (justification, TALER_officer_aml_decision_verify (justification,
decision_time, decision_time,
&new_threshold, &new_threshold,
&h_payto, &h_payto,
new_state, new_state,
&officer_pub, &officer_pub,
&officer_sig)) &officer_sig))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
return TALER_MHD_reply_with_error ( return TALER_MHD_reply_with_error (
@ -97,25 +96,25 @@ TEH_handler_management_post_aml_decision (
bool invalid_officer; bool invalid_officer;
do { do {
qs = TEH_plugin->add_aml_decision (TEH_plugin->cls, // FIXME: bound loop?
justification, qs = TEH_plugin->insert_aml_decision (TEH_plugin->cls,
decision_time, &h_payto,
&new_threshold, &new_threshold,
&h_payto, new_state,
new_state, decision_time,
&officer_pub, justification,
&officer_sig, &officer_pub,
&invalid_officer, &officer_sig,
&last_date); &invalid_officer,
&last_date);
} while (GNUNET_DB_STATUS_SOFT_ERROR == qs); } while (GNUNET_DB_STATUS_SOFT_ERROR == qs);
if (qs < 0) if (qs < 0)
{ {
GNUNET_break (0); GNUNET_break (0);
*mhd_ret = TALER_MHD_reply_with_error (connection, return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR, MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_STORE_FAILED, TALER_EC_GENERIC_DB_STORE_FAILED,
"add aml_decision"); "add aml_decision");
return qs;
} }
if (invalid_officer) if (invalid_officer)
{ {
@ -127,7 +126,7 @@ TEH_handler_management_post_aml_decision (
} }
if (GNUNET_TIME_timestamp_cmp (last_date, if (GNUNET_TIME_timestamp_cmp (last_date,
>, >,
validity_start)) decision_time))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
return TALER_MHD_reply_with_error ( return TALER_MHD_reply_with_error (

View File

@ -0,0 +1,45 @@
/*
This file is part of TALER
Copyright (C) 2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along with
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file taler-exchange-httpd_aml_decision.h
* @brief Handle /aml/$OFFICER_PUB/decision requests
* @author Christian Grothoff
*/
#ifndef TALER_EXCHANGE_HTTPD_AML_DECISION_H
#define TALER_EXCHANGE_HTTPD_AML_DECISION_H
#include <microhttpd.h>
#include "taler-exchange-httpd.h"
/**
* Handle an "/aml/$OFFICER_PUB/decision" request. Parses the decision
* details, checks the signatures and if appropriately authorized excecutes
* the decision.
*
* @param rc request context
* @param officer_pub public key of the AML officer who made the request
* @param root uploaded JSON data
* @return MHD result code
*/
MHD_RESULT
TEH_handler_post_aml_decision (
struct TEH_RequestContext *rc,
const struct TALER_AmlOfficerPublicKeyP *officer_pub,
const json_t *root);
#endif

View File

@ -174,6 +174,32 @@ TEH_handler_management_post_drain (
const json_t *root); const json_t *root);
/**
* Handle a POST "/management/aml-officers" request.
*
* @param connection the MHD connection to handle
* @param root uploaded JSON data
* @return MHD result code
*/
MHD_RESULT
TEH_handler_management_aml_officers (
struct MHD_Connection *connection,
const json_t *root);
/**
* Handle a POST "/management/partners" request.
*
* @param connection the MHD connection to handle
* @param root uploaded JSON data
* @return MHD result code
*/
MHD_RESULT
TEH_handler_management_partners (
struct MHD_Connection *connection,
const json_t *root);
/** /**
* Initialize extension configuration handling. * Initialize extension configuration handling.
* *

View File

@ -92,14 +92,15 @@ TEH_handler_management_aml_officers (
struct GNUNET_TIME_Timestamp last_date; struct GNUNET_TIME_Timestamp last_date;
do { do {
qs = TEH_plugin->set_aml_officer (TEH_plugin->cls, // FIXME: bound loop!
&officer_pub, qs = TEH_plugin->insert_aml_officer (TEH_plugin->cls,
officer_name, &officer_pub,
change_date, &master_sig,
is_active, officer_name,
read_only, is_active,
&master_sig, read_only,
&last_date); change_date,
&last_date);
} while (GNUNET_DB_STATUS_SOFT_ERROR == qs); } while (GNUNET_DB_STATUS_SOFT_ERROR == qs);
if (qs < 0) if (qs < 0)
{ {
@ -107,13 +108,13 @@ TEH_handler_management_aml_officers (
return TALER_MHD_reply_with_error (connection, return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR, MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_STORE_FAILED, TALER_EC_GENERIC_DB_STORE_FAILED,
"XXX"); "insert_aml_officer");
} }
if (GNUNET_TIME_timestamp_cmp (last_date, if (GNUNET_TIME_timestamp_cmp (last_date,
>, >,
change_date)) change_date))
{ {
GNUNER_break_op (0); GNUNET_break_op (0);
return TALER_MHD_reply_with_error ( return TALER_MHD_reply_with_error (
connection, connection,
MHD_HTTP_CONFLICT, MHD_HTTP_CONFLICT,

View File

@ -51,13 +51,14 @@ TEH_handler_management_partners (
GNUNET_JSON_spec_string ("partner_base_url", GNUNET_JSON_spec_string ("partner_base_url",
&partner_base_url), &partner_base_url),
TALER_JSON_spec_amount ("wad_fee", TALER_JSON_spec_amount ("wad_fee",
TEH_currency,
&wad_fee), &wad_fee),
GNUNET_JSON_spec_timestamp ("start_date", GNUNET_JSON_spec_timestamp ("start_date",
&start_date), &start_date),
GNUNET_JSON_spec_timestamp ("end_date", GNUNET_JSON_spec_timestamp ("end_date",
&start_date), &start_date),
GNUNET_JSON_spec_time_rel ("wad_frequency", GNUNET_JSON_spec_relative_time ("wad_frequency",
&wad_frequency), &wad_frequency),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
}; };
@ -94,14 +95,14 @@ TEH_handler_management_partners (
{ {
enum GNUNET_DB_QueryStatus qs; enum GNUNET_DB_QueryStatus qs;
qs = TEH_plugin->add_partner (TEH_plugin->cls, qs = TEH_plugin->insert_partner (TEH_plugin->cls,
&partner_pub, &partner_pub,
start_date, start_date,
end_date, end_date,
wad_frequency, wad_frequency,
&wad_fee, &wad_fee,
partner_base_url, partner_base_url,
&master_sig); &master_sig);
if (qs < 0) if (qs < 0)
{ {
GNUNET_break (0); GNUNET_break (0);
@ -110,6 +111,14 @@ TEH_handler_management_partners (
TALER_EC_GENERIC_DB_STORE_FAILED, TALER_EC_GENERIC_DB_STORE_FAILED,
"add_partner"); "add_partner");
} }
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
{
/* FIXME: check for idempotency! */
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_CONFLICT,
TALER_EC_EXCHANGE_MANAGEMENT_ADD_PARTNER_DATA_CONFLICT,
NULL);
}
} }
return TALER_MHD_reply_static ( return TALER_MHD_reply_static (
connection, connection,

View File

@ -25,6 +25,7 @@ CREATE TABLE partners
,wad_fee_frac INT4 NOT NULL ,wad_fee_frac INT4 NOT NULL
,master_sig BYTEA NOT NULL CHECK (LENGTH(master_sig)=64) ,master_sig BYTEA NOT NULL CHECK (LENGTH(master_sig)=64)
,partner_base_url TEXT NOT NULL ,partner_base_url TEXT NOT NULL
,PRIMARY KEY (partner_master_pub, start_date)
); );
COMMENT ON TABLE partners COMMENT ON TABLE partners
IS 'exchanges we do wad transfers to'; IS 'exchanges we do wad transfers to';

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2022 Taler Systems SA Copyright (C) 2022, 2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the 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 terms of the GNU General Public License as published by the Free Software
@ -32,10 +32,12 @@ TEH_PG_insert_aml_decision (
const struct TALER_PaytoHashP *h_payto, const struct TALER_PaytoHashP *h_payto,
const struct TALER_Amount *new_threshold, const struct TALER_Amount *new_threshold,
enum TALER_AmlDecisionState new_status, enum TALER_AmlDecisionState new_status,
struct GNUNET_TIME_Absolute decision_time, struct GNUNET_TIME_Timestamp decision_time,
const char *justification, const char *justification,
const struct TALER_AmlOfficerPublicKeyP *decider_pub, const struct TALER_AmlOfficerPublicKeyP *decider_pub,
const struct TALER_AmlOfficerSignatureP *decider_sig) const struct TALER_AmlOfficerSignatureP *decider_sig,
bool *invalid_officer,
struct GNUNET_TIME_Timestamp *last_date)
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;
uint32_t ns = (uint32_t) new_status; uint32_t ns = (uint32_t) new_status;
@ -43,13 +45,15 @@ TEH_PG_insert_aml_decision (
GNUNET_PQ_query_param_auto_from_type (h_payto), GNUNET_PQ_query_param_auto_from_type (h_payto),
TALER_PQ_query_param_amount (new_threshold), TALER_PQ_query_param_amount (new_threshold),
GNUNET_PQ_query_param_uint32 (&ns), GNUNET_PQ_query_param_uint32 (&ns),
GNUNET_PQ_query_param_absolute_time (&decision_time), GNUNET_PQ_query_param_timestamp (&decision_time),
GNUNET_PQ_query_param_string (justification), GNUNET_PQ_query_param_string (justification),
GNUNET_PQ_query_param_auto_from_type (decider_pub), GNUNET_PQ_query_param_auto_from_type (decider_pub),
GNUNET_PQ_query_param_auto_from_type (decider_sig), GNUNET_PQ_query_param_auto_from_type (decider_sig),
GNUNET_PQ_query_param_end GNUNET_PQ_query_param_end
}; };
// FIXME: set invalid_officer
// FIXME: set last_date!
PREPARE (pg, PREPARE (pg,
"insert_aml_decision", "insert_aml_decision",
"INSERT INTO aml_history " "INSERT INTO aml_history "

View File

@ -38,6 +38,9 @@
* @param justification human-readable text justifying the decision * @param justification human-readable text justifying the decision
* @param decider_pub public key of the staff member * @param decider_pub public key of the staff member
* @param decider_sig signature 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] 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 * @return database transaction status
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
@ -46,10 +49,12 @@ TEH_PG_insert_aml_decision (
const struct TALER_PaytoHashP *h_payto, const struct TALER_PaytoHashP *h_payto,
const struct TALER_Amount *new_threshold, const struct TALER_Amount *new_threshold,
enum TALER_AmlDecisionState new_status, enum TALER_AmlDecisionState new_status,
struct GNUNET_TIME_Absolute decision_time, struct GNUNET_TIME_Timestamp decision_time,
const char *justification, const char *justification,
const struct TALER_AmlOfficerPublicKeyP *decider_pub, const struct TALER_AmlOfficerPublicKeyP *decider_pub,
const struct TALER_AmlOfficerSignatureP *decider_sig); const struct TALER_AmlOfficerSignatureP *decider_sig,
bool *invalid_officer,
struct GNUNET_TIME_Timestamp *last_date);
#endif #endif

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2022 Taler Systems SA Copyright (C) 2022, 2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the 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 terms of the GNU General Public License as published by the Free Software
@ -34,7 +34,8 @@ TEH_PG_insert_aml_officer (
const char *decider_name, const char *decider_name,
bool is_active, bool is_active,
bool read_only, bool read_only,
struct GNUNET_TIME_Absolute last_change) struct GNUNET_TIME_Timestamp last_change,
struct GNUNET_TIME_Timestamp *previous_change)
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = { struct GNUNET_PQ_QueryParam params[] = {
@ -43,10 +44,11 @@ TEH_PG_insert_aml_officer (
GNUNET_PQ_query_param_string (decider_name), GNUNET_PQ_query_param_string (decider_name),
GNUNET_PQ_query_param_bool (is_active), GNUNET_PQ_query_param_bool (is_active),
GNUNET_PQ_query_param_bool (read_only), GNUNET_PQ_query_param_bool (read_only),
GNUNET_PQ_query_param_absolute_time (&last_change), GNUNET_PQ_query_param_timestamp (&last_change),
GNUNET_PQ_query_param_end GNUNET_PQ_query_param_end
}; };
// FIXME: need to check for previous record!
PREPARE (pg, PREPARE (pg,
"insert_aml_staff", "insert_aml_staff",
"INSERT INTO aml_staff " "INSERT INTO aml_staff "

View File

@ -27,7 +27,10 @@
/** /**
* Insert AML staff record. * Insert AML staff record. If the time given in
* @a last_change is before the previous change in the
* database, only @e previous_change is returned and
* no actual change is committed to the database.
* *
* @param cls closure * @param cls closure
* @param decider_pub public key of the staff member * @param decider_pub public key of the staff member
@ -36,6 +39,7 @@
* @param is_active true to enable, false to set as inactive * @param is_active true to enable, false to set as inactive
* @param read_only true to set read-only access * @param read_only true to set read-only access
* @param last_change when was the change made effective * @param last_change when was the change made effective
* @param[out] previous_change set to the time of the previous change
* @return database transaction status * @return database transaction status
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
@ -46,6 +50,7 @@ TEH_PG_insert_aml_officer (
const char *decider_name, const char *decider_name,
bool is_active, bool is_active,
bool read_only, bool read_only,
struct GNUNET_TIME_Absolute last_change); struct GNUNET_TIME_Timestamp last_change,
struct GNUNET_TIME_Timestamp *previous_change);
#endif #endif

View File

@ -28,13 +28,13 @@
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_insert_partner (void *cls, TEH_PG_insert_partner (void *cls,
const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterPublicKeyP *master_pub,
struct GNUNET_TIME_Timestamp start_date, struct GNUNET_TIME_Timestamp start_date,
struct GNUNET_TIME_Timestamp end_date, struct GNUNET_TIME_Timestamp end_date,
struct GNUNET_TIME_Relative wad_frequency, struct GNUNET_TIME_Relative wad_frequency,
const struct TALER_Amount *wad_fee, const struct TALER_Amount *wad_fee,
const char *partner_base_url, const char *partner_base_url,
const struct TALER_MasterSignatureP *master_sig) const struct TALER_MasterSignatureP *master_sig)
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = { struct GNUNET_PQ_QueryParam params[] = {
@ -61,10 +61,9 @@ TEH_PG_insert_partner (void *cls,
" ,master_sig" " ,master_sig"
" ,partner_base_url" " ,partner_base_url"
" ) VALUES " " ) VALUES "
" ($1, $2, $3, $4, $5, $6, $7, $8);"); " ($1, $2, $3, $4, $5, $6, $7, $8)"
" ON CONFLICT DO NOTHING;");
return GNUNET_PQ_eval_prepared_non_select (pg->conn, return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_partner", "insert_partner",
params); params);
} }

View File

@ -6602,6 +6602,7 @@ struct TALER_EXCHANGEDB_Plugin
* @param is_active true to enable, false to set as inactive * @param is_active true to enable, false to set as inactive
* @param read_only true to set read-only access * @param read_only true to set read-only access
* @param last_change when was the change made effective * @param last_change when was the change made effective
* @param[out] previous_change when was the previous change made
* @return database transaction status * @return database transaction status
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
@ -6612,7 +6613,8 @@ struct TALER_EXCHANGEDB_Plugin
const char *decider_name, const char *decider_name,
bool is_active, bool is_active,
bool read_only, bool read_only,
struct GNUNET_TIME_Absolute last_change); struct GNUNET_TIME_Timestamp last_change,
struct GNUNET_TIME_Timestamp *previous_change);
/** /**
@ -6727,6 +6729,9 @@ struct TALER_EXCHANGEDB_Plugin
* @param justification human-readable text justifying the decision * @param justification human-readable text justifying the decision
* @param decider_pub public key of the staff member * @param decider_pub public key of the staff member
* @param decider_sig signature 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] 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 * @return database transaction status
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
@ -6735,10 +6740,12 @@ struct TALER_EXCHANGEDB_Plugin
const struct TALER_PaytoHashP *h_payto, const struct TALER_PaytoHashP *h_payto,
const struct TALER_Amount *new_threshold, const struct TALER_Amount *new_threshold,
enum TALER_AmlDecisionState new_status, enum TALER_AmlDecisionState new_status,
struct GNUNET_TIME_Absolute decision_time, struct GNUNET_TIME_Timestamp decision_time,
const char *justification, const char *justification,
const struct TALER_AmlOfficerPublicKeyP *decider_pub, const struct TALER_AmlOfficerPublicKeyP *decider_pub,
const struct TALER_AmlOfficerSignatureP *decider_sig); const struct TALER_AmlOfficerSignatureP *decider_sig,
bool *invalid_officer,
struct GNUNET_TIME_Timestamp *last_date);
}; };

View File

@ -167,7 +167,7 @@ TALER_EXCHANGE_add_aml_decision (
sizeof (opus)); sizeof (opus));
*end = '\0'; *end = '\0';
GNUNET_asprintf (&path, GNUNET_asprintf (&path,
"aml-decision/%s", "aml/%s/decision",
opus); opus);
wh->url = TALER_url_join (url, wh->url = TALER_url_join (url,
path, path,

View File

@ -66,7 +66,7 @@ struct TALER_EXCHANGE_ManagementAddPartner
/** /**
* Function called when we're done processing the * Function called when we're done processing the
* HTTP POST /aml-decision/$OFFICER_PUB request. * HTTP POST /management/partners request.
* *
* @param cls the `struct TALER_EXCHANGE_ManagementAddPartner *` * @param cls the `struct TALER_EXCHANGE_ManagementAddPartner *`
* @param response_code HTTP response code, 0 on error * @param response_code HTTP response code, 0 on error
@ -145,25 +145,9 @@ TALER_EXCHANGE_management_add_partner (
wh->cb = cb; wh->cb = cb;
wh->cb_cls = cb_cls; wh->cb_cls = cb_cls;
wh->ctx = ctx; wh->ctx = ctx;
{ wh->url = TALER_url_join (url,
char *path; "management/partners",
char opus[sizeof (*partner_pub) * 2]; NULL);
char *end;
end = GNUNET_STRINGS_data_to_string (
partner_pub,
sizeof (*partner_pub),
opus,
sizeof (opus));
*end = '\0';
GNUNET_asprintf (&path,
"management/partners/%s",
opus);
wh->url = TALER_url_join (url,
path,
NULL);
GNUNET_free (path);
}
if (NULL == wh->url) if (NULL == wh->url)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@ -180,6 +164,8 @@ TALER_EXCHANGE_management_add_partner (
end_date), end_date),
GNUNET_JSON_pack_time_rel ("wad_frequency", GNUNET_JSON_pack_time_rel ("wad_frequency",
wad_frequency), wad_frequency),
GNUNET_JSON_pack_data_auto ("partner_pub",
&partner_pub),
GNUNET_JSON_pack_data_auto ("master_sig", GNUNET_JSON_pack_data_auto ("master_sig",
&master_sig), &master_sig),
TALER_JSON_pack_amount ("wad_fee", TALER_JSON_pack_amount ("wad_fee",

View File

@ -144,25 +144,9 @@ TALER_EXCHANGE_management_update_aml_officer (
wh->cb = cb; wh->cb = cb;
wh->cb_cls = cb_cls; wh->cb_cls = cb_cls;
wh->ctx = ctx; wh->ctx = ctx;
{ wh->url = TALER_url_join (url,
char *path; "management/aml-officers",
char opus[sizeof (*officer_pub) * 2]; NULL);
char *end;
end = GNUNET_STRINGS_data_to_string (
officer_pub,
sizeof (*officer_pub),
opus,
sizeof (opus));
*end = '\0';
GNUNET_asprintf (&path,
"management/aml-officers/%s",
opus);
wh->url = TALER_url_join (url,
path,
NULL);
GNUNET_free (path);
}
if (NULL == wh->url) if (NULL == wh->url)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@ -173,6 +157,8 @@ TALER_EXCHANGE_management_update_aml_officer (
body = GNUNET_JSON_PACK ( body = GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("officer_name", GNUNET_JSON_pack_string ("officer_name",
officer_name), officer_name),
GNUNET_JSON_pack_data_auto ("officer_pub",
officer_pub),
GNUNET_JSON_pack_data_auto ("master_sig", GNUNET_JSON_pack_data_auto ("master_sig",
master_sig), master_sig),
GNUNET_JSON_pack_bool ("is_active", GNUNET_JSON_pack_bool ("is_active",