Merge branch 'master' into age-withdraw

This commit is contained in:
Özgür Kesim 2023-01-21 10:14:05 +01:00
commit aeef0330b0
24 changed files with 1790 additions and 34 deletions

View File

@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
#
# This file is part of TALER
# Copyright (C) 2014-2021 Taler Systems SA
# Copyright (C) 2014-2023 Taler Systems SA
#
# TALER is free software; you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
@ -17,7 +17,7 @@
#
#
AC_PREREQ([2.69])
AC_INIT([taler-exchange],[0.9.0],[taler-bug@gnunet.org])
AC_INIT([taler-exchange],[0.9.1],[taler-bug@gnunet.org])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_SRCDIR([src/util/util.c])
AC_CONFIG_HEADERS([taler_config.h])

6
debian/changelog vendored
View File

@ -1,3 +1,9 @@
taler-exchange (0.9.1) unstable; urgency=low
* Packaging latest release.
-- Christian Grothoff <grothoff@gnu.org> Tue, 17 Jan 2023 11:50:12 +0200
taler-exchange (0.9.0) unstable; urgency=low
* Packaging latest release.

View File

@ -301,9 +301,9 @@ function run_audit () {
echo -n "Running taler-exchange-offline drain "
taler-exchange-offline -L DEBUG -c "${CONF}" \
drain TESTKUDOS:0.1 exchange-account-1 payto://iban/SANDBOXX/DE360679?receiver-name=Exchange+Drain \
upload \
2> ${MY_TMP_DIR}/taler-exchange-offline-drain.log || exit_fail "offline draining failed"
drain TESTKUDOS:0.1 exchange-account-1 payto://iban/SANDBOXX/DE360679?receiver-name=Exchange+Drain \
upload \
2> ${MY_TMP_DIR}/taler-exchange-offline-drain.log || exit_fail "offline draining failed"
kill -TERM $EPID
wait $EPID || true
unset EPID
@ -325,11 +325,15 @@ function run_audit () {
echo -n "Payment likely already submitted, running submit-payments without UUID anyway ..."
libeufin-cli accounts submit-payments exchange-nexus
else
echo -n "Running submitting payment ${PAIN_UUID} ..."
echo -n "Running payment submission for transaction ${PAIN_UUID} ..."
libeufin-cli accounts submit-payments --payment-uuid ${PAIN_UUID} exchange-nexus
fi
cd $ORIGIN
echo " DONE"
echo -n "Import outgoing transactions..."
libeufin-cli accounts fetch-transactions \
--range-type since-last --level report exchange-nexus
echo " DONE"
cd $ORIGIN
fi
audit_only
post_audit

View File

@ -3322,7 +3322,7 @@ tofu_check (const struct TALER_SecurityModulePublicKeySetP *secmset)
* @param signkeys keys to output
* @return #GNUNET_OK on success
*/
static int
static enum GNUNET_GenericReturnValue
show_signkeys (const struct TALER_SecurityModulePublicKeyP *secm_pub,
const json_t *signkeys)
{
@ -4353,6 +4353,9 @@ cmd_handler (char *const *args,
cmds[i].name,
cmds[i].help);
}
json_decref (out);
out = NULL;
GNUNET_SCHEDULER_shutdown ();
}

View File

@ -0,0 +1,149 @@
/*
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.c
* @brief Handle request about an AML decision.
* @author Christian Grothoff
*/
#include "platform.h"
#include <gnunet/gnunet_util_lib.h>
#include <gnunet/gnunet_json_lib.h>
#include <jansson.h>
#include <microhttpd.h>
#include <pthread.h>
#include "taler_json_lib.h"
#include "taler_mhd_lib.h"
#include "taler_signatures.h"
#include "taler-exchange-httpd_responses.h"
MHD_RESULT
TEH_handler_management_post_aml_decision (
struct MHD_Connection *connection,
const json_t *root)
{
const char *justification;
struct GNUNET_TIME_Timestamp decision_time;
struct TALER_Amount new_threshold;
struct TALER_PaytoHashP h_payto;
uint32_t new_state32;
enum TALER_AmlDecisionState new_state;
struct TALER_AmlOfficerPublicKeyP officer_pub;
struct TALER_AmlOfficerSignatureP officer_sig;
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",
&officer_sig),
GNUNET_JSON_spec_fixed_auto ("h_payto",
&h_payto),
TALER_JSON_spec_amount ("new_threshold",
&new_threshold),
GNUNET_JSON_spec_string ("justification",
&justification),
GNUNET_JSON_spec_timestamp ("decision_time",
&decision_time),
GNUNET_JSON_spec_uint32 ("new_state",
&new_state32),
GNUNET_JSON_spec_end ()
};
{
enum GNUNET_GenericReturnValue res;
res = TALER_MHD_parse_json_data (connection,
root,
spec);
if (GNUNET_SYSERR == res)
return MHD_NO; /* hard failure */
if (GNUNET_NO == res)
return MHD_YES; /* failure */
}
new_state = (enum TALER_AmlDecisionState) new_state32;
TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
if (GNUNET_OK !=
TALER_exchange_aml_decision_verify (justification,
decision_time,
&new_threshold,
&h_payto,
new_state,
&officer_pub,
&officer_sig))
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (
connection,
MHD_HTTP_FORBIDDEN,
TALER_EC_EXCHANGE_AML_DECISION_ADD_SIGNATURE_INVALID,
NULL);
}
{
enum GNUNET_DB_QueryStatus qs;
struct GNUNET_TIME_Timestamp last_date;
bool invalid_officer;
do {
qs = TEH_plugin->add_aml_decision (TEH_plugin->cls,
justification,
decision_time,
&new_threshold,
&h_payto,
new_state,
&officer_pub,
&officer_sig,
&invalid_officer,
&last_date);
} while (GNUNET_DB_STATUS_SOFT_ERROR == qs);
if (qs < 0)
{
GNUNET_break (0);
*mhd_ret = TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_STORE_FAILED,
"add aml_decision");
return qs;
}
if (invalid_officer)
{
return TALER_MHD_reply_with_error (
connection,
MHD_HTTP_FORBIDDEN,
TALER_EC_EXCHANGE_AML_DECISION_INVALID_OFFICER,
NULL);
}
if (GNUNET_TIME_timestamp_cmp (last_date,
>,
validity_start))
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (
connection,
MHD_HTTP_CONFLICT,
TALER_EC_EXCHANGE_AML_DECISION_MORE_RECENT_PRESENT,
NULL);
}
}
return TALER_MHD_reply_static (
connection,
MHD_HTTP_NO_CONTENT,
NULL,
NULL,
0);
}
/* end of taler-exchange-httpd_aml-decision.c */

View File

@ -3232,7 +3232,8 @@ TEH_keys_get_handler (struct TEH_RequestContext *rc,
const struct KeysResponseData *krd;
ksh = TEH_keys_get_state ();
if (NULL == ksh)
if ( (NULL == ksh) ||
(0 == ksh->krd_array_length) )
{
if ( ( (SKR_LIMIT == skr_size) &&
(rc->connection == skr_connection) ) ||

View File

@ -43,7 +43,7 @@ TEH_kyc_proof_cleanup (void);
MHD_RESULT
TEH_handler_kyc_proof (
struct TEH_RequestContext *rc,
const char *const args[3]);
const char *const args[1]);
#endif

View File

@ -0,0 +1,133 @@
/*
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_management_aml-officers.c
* @brief Handle request to update AML officer status
* @author Christian Grothoff
*/
#include "platform.h"
#include <gnunet/gnunet_util_lib.h>
#include <gnunet/gnunet_json_lib.h>
#include <jansson.h>
#include <microhttpd.h>
#include <pthread.h>
#include "taler_json_lib.h"
#include "taler_mhd_lib.h"
#include "taler_signatures.h"
#include "taler-exchange-httpd_management.h"
#include "taler-exchange-httpd_responses.h"
MHD_RESULT
TEH_handler_management_aml_officers (
struct MHD_Connection *connection,
const json_t *root)
{
struct TALER_AmlOfficerPublicKeyP officer_pub;
const char *officer_name;
struct GNUNET_TIME_Timestamp change_date;
bool is_active;
bool read_only;
struct TALER_MasterSignatureP master_sig;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("officer_pub",
&officer_pub),
GNUNET_JSON_spec_fixed_auto ("master_sig",
&master_sig),
GNUNET_JSON_spec_bool ("is_active",
&is_active),
GNUNET_JSON_spec_bool ("read_only",
&read_only),
GNUNET_JSON_spec_string ("officer_name",
&officer_name),
GNUNET_JSON_spec_timestamp ("change_date",
&change_date),
GNUNET_JSON_spec_end ()
};
{
enum GNUNET_GenericReturnValue res;
res = TALER_MHD_parse_json_data (connection,
root,
spec);
if (GNUNET_SYSERR == res)
return MHD_NO; /* hard failure */
if (GNUNET_NO == res)
return MHD_YES; /* failure */
}
TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
if (GNUNET_OK !=
TALER_exchange_offline_aml_officer_status_verify (
&officer_pub,
officer_name,
change_date,
is_active,
read_only,
&TEH_master_public_key,
&master_sig))
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (
connection,
MHD_HTTP_FORBIDDEN,
TALER_EC_EXCHANGE_MANAGEMENT_UPDATE_AML_OFFICER_SIGNATURE_INVALID,
NULL);
}
{
enum GNUNET_DB_QueryStatus qs;
struct GNUNET_TIME_Timestamp last_date;
do {
qs = TEH_plugin->set_aml_officer (TEH_plugin->cls,
&officer_pub,
officer_name,
change_date,
is_active,
read_only,
&master_sig,
&last_date);
} while (GNUNET_DB_STATUS_SOFT_ERROR == qs);
if (qs < 0)
{
GNUNET_break (0);
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_STORE_FAILED,
"XXX");
}
if (GNUNET_TIME_timestamp_cmp (last_date,
>,
change_date))
{
GNUNER_break_op (0);
return TALER_MHD_reply_with_error (
connection,
MHD_HTTP_CONFLICT,
TALER_EC_EXCHANGE_MANAGEMENT_AML_OFFICERS_MORE_RECENT_PRESENT,
NULL);
}
}
return TALER_MHD_reply_static (
connection,
MHD_HTTP_NO_CONTENT,
NULL,
NULL,
0);
}
/* end of taler-exchange-httpd_management_aml-officers.c */

View File

@ -0,0 +1,123 @@
/*
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_management_partners.c
* @brief Handle request to add exchange partner
* @author Christian Grothoff
*/
#include "platform.h"
#include <gnunet/gnunet_util_lib.h>
#include <gnunet/gnunet_json_lib.h>
#include <jansson.h>
#include <microhttpd.h>
#include <pthread.h>
#include "taler_json_lib.h"
#include "taler_mhd_lib.h"
#include "taler_signatures.h"
#include "taler-exchange-httpd_management.h"
#include "taler-exchange-httpd_responses.h"
MHD_RESULT
TEH_handler_management_partners (
struct MHD_Connection *connection,
const json_t *root)
{
struct TALER_MasterPublicKeyP partner_pub;
struct GNUNET_TIME_Timestamp start_date;
struct GNUNET_TIME_Timestamp end_date;
struct GNUNET_TIME_Relative wad_frequency;
struct TALER_Amount wad_fee;
const char *partner_base_url;
struct TALER_MasterSignatureP master_sig;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("partner_pub",
&partner_pub),
GNUNET_JSON_spec_fixed_auto ("master_sig",
&master_sig),
GNUNET_JSON_spec_string ("partner_base_url",
&partner_base_url),
TALER_JSON_spec_amount ("wad_fee",
&wad_fee),
GNUNET_JSON_spec_timestamp ("start_date",
&start_date),
GNUNET_JSON_spec_timestamp ("end_date",
&start_date),
GNUNET_JSON_spec_time_rel ("wad_frequency",
&wad_frequency),
GNUNET_JSON_spec_end ()
};
{
enum GNUNET_GenericReturnValue res;
res = TALER_MHD_parse_json_data (connection,
root,
spec);
if (GNUNET_SYSERR == res)
return MHD_NO; /* hard failure */
if (GNUNET_NO == res)
return MHD_YES; /* failure */
}
TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
if (GNUNET_OK !=
TALER_exchange_offline_partner_details_verify (
&partner_pub,
start_date,
end_date,
wad_frequency,
&wad_fee,
partner_base_url,
&TEH_master_public_key,
&master_sig))
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (
connection,
MHD_HTTP_FORBIDDEN,
TALER_EC_EXCHANGE_MANAGEMENT_ADD_PARTNER_SIGNATURE_INVALID,
NULL);
}
{
enum GNUNET_DB_QueryStatus qs;
qs = TEH_plugin->add_partner (TEH_plugin->cls,
&partner_pub,
start_date,
end_date,
wad_frequency,
&wad_fee,
partner_base_url,
&master_sig);
if (qs < 0)
{
GNUNET_break (0);
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_STORE_FAILED,
"add_partner");
}
}
return TALER_MHD_reply_static (
connection,
MHD_HTTP_NO_CONTENT,
NULL,
NULL,
0);
}
/* end of taler-exchange-httpd_management_partners.c */

View File

@ -704,6 +704,7 @@ TEH_RESPONSE_compile_reserve_history (
json_t *json_history;
json_history = json_array ();
GNUNET_assert (NULL != json_history);
for (const struct TALER_EXCHANGEDB_ReserveHistory *pos = rh;
NULL != pos;
pos = pos->next)
@ -1012,10 +1013,14 @@ reply_reserve_insufficient_funds (
json_history = TEH_RESPONSE_compile_reserve_history (rh);
if (NULL == json_history)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to compile reserve history\n");
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_EXCHANGE_RESERVE_HISTORY_ERROR_INSUFFICIENT_FUNDS,
NULL);
}
return TALER_MHD_REPLY_JSON_PACK (
connection,
MHD_HTTP_CONFLICT,
@ -1061,6 +1066,7 @@ TEH_RESPONSE_reply_reserve_insufficient_balance (
if ( (qs < 0) ||
(NULL == rh) )
{
GNUNET_break (0);
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_FETCH_FAILED,

View File

@ -215,6 +215,8 @@ withdraw_transaction (void *cls,
if (! balance_ok)
{
TEH_plugin->rollback (TEH_plugin->cls);
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Balance insufficient for /withdraw\n");
*mhd_ret = TEH_RESPONSE_reply_reserve_insufficient_balance (
connection,
TALER_EC_EXCHANGE_WITHDRAW_INSUFFICIENT_FUNDS,

View File

@ -1,7 +1,7 @@
#!/bin/bash
#
# This file is part of TALER
# Copyright (C) 2015-2020 Taler Systems SA
# Copyright (C) 2015-2020, 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
@ -23,6 +23,8 @@
# Clear environment from variables that override config.
unset XDG_DATA_HOME
unset XDG_CONFIG_HOME
set -eu
#
echo -n "Launching exchange ..."
PREFIX=
@ -30,7 +32,7 @@ PREFIX=
#PREFIX="valgrind --leak-check=yes --track-fds=yes --error-exitcode=1 --log-file=valgrind.%p"
# Setup database
taler-exchange-dbinit -c test_taler_exchange_httpd.conf &> /dev/null
taler-exchange-dbinit -c test_taler_exchange_httpd.conf &> /dev/null || exit 77
# Run Exchange HTTPD (in background)
$PREFIX taler-exchange-httpd -c test_taler_exchange_httpd.conf 2> test-exchange.log &

View File

@ -75,7 +75,7 @@ BEGIN
,partition_suffix
);
PERFORM comment_partitioned_column(
'Timestamp of when the withdraw-age resquest was received by the exchange'
'Timestamp with the time when the withdraw-age request was received by the exchange'
,'timestamp'
,table_name
,partition_suffix

View File

@ -267,7 +267,7 @@ BEGIN
END IF;
k=k+1;
END LOOP;
/**ROLLBACK TRANSACTION IN SOTRED PROCEDURE IS IT PROSSIBLE ?**/
/**ROLLBACK TRANSACTION IN SORTED PROCEDURE IS IT PROSSIBLE ?**/
/*IF transaction_duplicate
OR transaction_duplicate2
OR transaction_duplicate3

View File

@ -161,7 +161,3 @@ END $$;
COMMENT ON FUNCTION exchange_do_reserve_purse(BYTEA, BYTEA, INT8, INT8, INT8, BYTEA, BOOLEAN, INT8, INT4, BYTEA, BYTEA)
IS 'Create a purse for a reserve.';

View File

@ -797,14 +797,14 @@ TEH_PG_get_reserve_history (void *cls,
" FROM purse_merges pm"
" JOIN purse_requests pr"
" USING (purse_pub)"
" JOIN purse_decision pdes"
" LEFT JOIN purse_decision pdes"
" USING (purse_pub)"
" JOIN account_merges am"
" ON (am.purse_pub = pm.purse_pub AND"
" am.reserve_pub = pm.reserve_pub)"
" WHERE pm.reserve_pub=$1"
" AND COALESCE(pm.partner_serial_id,0)=0" /* must be local! */
" AND NOT pdes.refunded;");
" AND NOT COALESCE (pdes.refunded, FALSE);");
PREPARE (pg,
"history_by_reserve",
"SELECT"
@ -855,7 +855,12 @@ TEH_PG_get_reserve_history (void *cls,
&rhc);
if ( (0 > qs) ||
(GNUNET_OK != rhc.status) )
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to compile reserve history at `%s'\n",
work[i].statement);
break;
}
}
if ( (qs < 0) ||
(rhc.status != GNUNET_OK) )

View File

@ -1,6 +1,6 @@
/*
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
terms of the GNU Affero General Public License as published by the Free Software
@ -4240,6 +4240,185 @@ TALER_EXCHANGE_management_revoke_signing_key_cancel (
struct TALER_EXCHANGE_ManagementRevokeSigningKeyHandle *rh);
/**
* Function called with information about the change to
* an AML officer status.
*
* @param cls closure
* @param hr HTTP response data
*/
typedef void
(*TALER_EXCHANGE_ManagementUpdateAmlOfficerCallback) (
void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr);
/**
* @brief Handle for a POST /management/aml-officers/$OFFICER_PUB request.
*/
struct TALER_EXCHANGE_ManagementUpdateAmlOfficer;
/**
* Inform the exchange that the status of an AML officer has changed.
*
* @param ctx the context
* @param url HTTP base URL for the exchange
* @param officer_pub the public signing key of the officer
* @param officer_name name of the officer
* @param change_date when to affect the status change
* @param is_active true to enable the officer
* @param read_only true to only allow read-only access
* @param master_sig signature affirming the change
* @param cb function to call with the exchange's result
* @param cb_cls closure for @a cb
* @return the request handle; NULL upon error
*/
struct TALER_EXCHANGE_ManagementUpdateAmlOfficer *
TALER_EXCHANGE_management_update_aml_officer (
struct GNUNET_CURL_Context *ctx,
const char *url,
const struct TALER_AmlOfficerPublicKeyP *officer_pub,
const char *officer_name,
struct GNUNET_TIME_Timestamp change_date,
bool is_active,
bool read_only,
const struct TALER_MasterSignatureP *master_sig,
TALER_EXCHANGE_ManagementUpdateAmlOfficerCallback cb,
void *cb_cls);
/**
* Cancel #TALER_EXCHANGE_management_update_aml_officer() operation.
*
* @param rh handle of the operation to cancel
*/
void
TALER_EXCHANGE_management_update_aml_officer_cancel (
struct TALER_EXCHANGE_ManagementUpdateAmlOfficer *rh);
/**
* Function called with information about storing an
* an AML decision.
*
* @param cls closure
* @param hr HTTP response data
*/
typedef void
(*TALER_EXCHANGE_AddAmlDecisionCallback) (
void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr);
/**
* @brief Handle for a POST /aml-decision/$OFFICER_PUB request.
*/
struct TALER_EXCHANGE_AddAmlDecision;
/**
* Inform the exchange that an AML decision has been taken.
*
* @param ctx the context
* @param url HTTP base URL for the exchange
* @param justification human-readable justification
* @param decision_time when was the decision made
* @param new_threshold at what monthly amount threshold
* should a revision be triggered
* @param h_payto payto URI hash of the account the
* decision is about
* @param new_state updated AML state
* @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
* @return the request handle; NULL upon error
*/
struct TALER_EXCHANGE_AddAmlDecision *
TALER_EXCHANGE_add_aml_decision (
struct GNUNET_CURL_Context *ctx,
const char *url,
const char *justification,
struct GNUNET_TIME_Timestamp decision_time,
const struct TALER_Amount *new_threshold,
const struct TALER_PaytoHashP *h_payto,
enum TALER_AmlDecisionState new_state,
const struct TALER_AmlOfficerPrivateKeyP *officer_priv,
TALER_EXCHANGE_AddAmlDecisionCallback cb,
void *cb_cls);
/**
* Cancel #TALER_EXCHANGE_add_aml_decision() operation.
*
* @param rh handle of the operation to cancel
*/
void
TALER_EXCHANGE_add_aml_decision_cancel (
struct TALER_EXCHANGE_AddAmlDecision *rh);
/**
* Function called with information about the change to
* an AML officer status.
*
* @param cls closure
* @param hr HTTP response data
*/
typedef void
(*TALER_EXCHANGE_ManagementAddPartnerCallback) (
void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr);
/**
* @brief Handle for a POST /management/partners/$PARTNER_PUB request.
*/
struct TALER_EXCHANGE_ManagementAddPartner;
/**
* Inform the exchange that the status of a partnering
* exchange was defined.
*
* @param ctx the context
* @param url HTTP base URL for the exchange
* @param partner_pub the offline signing key of the partner
* @param start_date validity period start
* @param end_date validity period end
* @param wad_frequency how often will we do wad transfers to this partner
* @param wad_fee what is the wad fee to this partner
* @param partner_base_url what is the base URL of the @a partner_pub exchange
* @param master_sig the signature the signature
* @param cb function to call with the exchange's result
* @param cb_cls closure for @a cb
* @return the request handle; NULL upon error
*/
struct TALER_EXCHANGE_ManagementAddPartner *
TALER_EXCHANGE_management_add_partner (
struct GNUNET_CURL_Context *ctx,
const char *url,
const struct TALER_MasterPublicKeyP *partner_pub,
struct GNUNET_TIME_Timestamp start_date,
struct GNUNET_TIME_Timestamp end_date,
struct GNUNET_TIME_Relative wad_frequency,
const struct TALER_Amount *wad_fee,
const char *partner_base_url,
const struct TALER_MasterSignatureP *master_sig,
TALER_EXCHANGE_ManagementAddPartnerCallback cb,
void *cb_cls);
/**
* Cancel #TALER_EXCHANGE_management_update_aml_officer() operation.
*
* @param rh handle of the operation to cancel
*/
void
TALER_EXCHANGE_management_add_partner_cancel (
struct TALER_EXCHANGE_ManagementAddPartner *rh);
/**
* Function called with information about the auditor setup operation result.
*

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
(C) 2018-2022 Taler Systems SA
(C) 2018-2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as
@ -2710,6 +2710,47 @@ TALER_TESTING_cmd_purse_deposit_coins (
...);
/**
* Setup AML officer.
*
* @param label command label
* @param ref_cmd command that previously created the
* officer, NULL to create one this time
* @param name full legal name of the officer to use
* @param is_active true to set the officer to active
* @param read_only true to restrict the officer to read-only
* @return the command
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_set_officer (
const char *label,
const char *ref_cmd,
const char *name,
bool is_active,
bool read_only);
/**
* Make AML decision.
*
* @param label command label
* @param ref_officer command that previously created an
* officer
* @param ref_operation command that previously created an
* h_payto which to make an AML decision about
* @param new_threshold new threshold to set
* @param block set to true to block the account
* @return the command
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_take_aml_decision (
const char *label,
const char *ref_officer,
const char *ref_operation,
const char *new_threshold,
bool block);
/* *** Generic trait logic for implementing traits ********* */

View File

@ -474,17 +474,17 @@ initiate_task (void *cls)
hps = GNUNET_STRINGS_data_to_string_alloc (&ih->h_payto,
sizeof (ih->h_payto));
GNUNET_asprintf (&redirect_uri,
"%skyc-proof/%s",
"%skyc-proof/%s?state=%s",
ps->exchange_base_url,
pd->section);
pd->section,
hps);
redirect_uri_encoded = TALER_urlencode (redirect_uri);
GNUNET_free (redirect_uri);
GNUNET_asprintf (&url,
"%s?response_type=code&client_id=%s&redirect_uri=%s&state=%s",
"%s?response_type=code&client_id=%s&redirect_uri=%s",
pd->login_url,
pd->client_id,
redirect_uri_encoded,
hps);
redirect_uri_encoded);
GNUNET_free (redirect_uri_encoded);
ih->cb (ih->cb_cls,
TALER_EC_NONE,
@ -1012,21 +1012,19 @@ oauth2_proof (void *cls,
char *redirect_uri;
char *client_secret;
char *authorization_code;
char *redirect_uri_encoded;
char *hps;
hps = GNUNET_STRINGS_data_to_string_alloc (&ph->h_payto,
sizeof (ph->h_payto));
GNUNET_asprintf (&redirect_uri,
"%skyc-proof/%s",
"%skyc-proof/%s?state=%s",
ps->exchange_base_url,
pd->section);
pd->section,
hps);
redirect_uri_encoded = TALER_urlencode (redirect_uri);
GNUNET_free (redirect_uri);
GNUNET_assert (NULL != redirect_uri_encoded);
client_id = curl_easy_escape (ph->eh,
pd->client_id,
0);
@ -1047,8 +1045,8 @@ oauth2_proof (void *cls,
authorization_code);
curl_free (authorization_code);
curl_free (client_secret);
curl_free (redirect_uri_encoded);
curl_free (hps);
GNUNET_free (redirect_uri_encoded);
GNUNET_free (hps);
curl_free (client_id);
}
GNUNET_assert (CURLE_OK ==

View File

@ -0,0 +1,240 @@
/*
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 General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>
*/
/**
* @file lib/exchange_api_add_aml_decision.c
* @brief functions to add an AML decision by an AML officer
* @author Christian Grothoff
*/
#include "platform.h"
#include "taler_json_lib.h"
#include <gnunet/gnunet_curl_lib.h>
#include "taler_exchange_service.h"
#include "exchange_api_curl_defaults.h"
#include "taler_signatures.h"
#include "taler_curl_lib.h"
#include "taler_json_lib.h"
struct TALER_EXCHANGE_AddAmlDecision
{
/**
* The url for this request.
*/
char *url;
/**
* Minor context that holds body and headers.
*/
struct TALER_CURL_PostContext post_ctx;
/**
* Handle for the request.
*/
struct GNUNET_CURL_Job *job;
/**
* Function to call with the result.
*/
TALER_EXCHANGE_AddAmlDecisionCallback cb;
/**
* Closure for @a cb.
*/
void *cb_cls;
/**
* Reference to the execution context.
*/
struct GNUNET_CURL_Context *ctx;
};
/**
* Function called when we're done processing the
* HTTP POST /aml-decision/$OFFICER_PUB request.
*
* @param cls the `struct TALER_EXCHANGE_AddAmlDecision *`
* @param response_code HTTP response code, 0 on error
* @param response response body, NULL if not in JSON
*/
static void
handle_add_aml_decision_finished (void *cls,
long response_code,
const void *response)
{
struct TALER_EXCHANGE_AddAmlDecision *wh = cls;
const json_t *json = response;
struct TALER_EXCHANGE_HttpResponse hr = {
.http_status = (unsigned int) response_code,
.reply = json
};
wh->job = NULL;
switch (response_code)
{
case 0:
/* no reply */
hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
hr.hint = "server offline?";
break;
case MHD_HTTP_NO_CONTENT:
break;
case MHD_HTTP_FORBIDDEN:
hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json);
break;
case MHD_HTTP_CONFLICT:
hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json);
break;
default:
/* unexpected response code */
GNUNET_break_op (0);
hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d for exchange AML decision\n",
(unsigned int) response_code,
(int) hr.ec);
break;
}
if (NULL != wh->cb)
{
wh->cb (wh->cb_cls,
&hr);
wh->cb = NULL;
}
TALER_EXCHANGE_add_aml_decision_cancel (wh);
}
struct TALER_EXCHANGE_AddAmlDecision *
TALER_EXCHANGE_add_aml_decision (
struct GNUNET_CURL_Context *ctx,
const char *url,
const char *justification,
struct GNUNET_TIME_Timestamp decision_time,
const struct TALER_Amount *new_threshold,
const struct TALER_PaytoHashP *h_payto,
enum TALER_AmlDecisionState new_state,
const struct TALER_AmlOfficerPrivateKeyP *officer_priv,
TALER_EXCHANGE_AddAmlDecisionCallback cb,
void *cb_cls)
{
struct TALER_AmlOfficerPrivateKeyP officer_pub;
struct TALER_AmlOfficerSignatureP officer_sig;
struct TALER_EXCHANGE_AddAmlDecision *wh;
CURL *eh;
json_t *body;
GNUNET_CRYPTO_eddsa_key_get_public (&officer_priv->eddsa_priv,
&officer_pub.eddsa_pub);
TALER_officer_aml_decision_sign (justification,
decision_time,
h_payto,
new_state,
officer_priv,
&officer_sig);
wh = GNUNET_new (struct TALER_EXCHANGE_AddAmlDecision);
wh->cb = cb;
wh->cb_cls = cb_cls;
wh->ctx = ctx;
{
char *path;
char opus[sizeof (officer_pub) * 2];
char *end;
end = GNUNET_STRINGS_data_to_string (
&officer_pub,
sizeof (officer_pub),
opus,
sizeof (opus));
*end = '\0';
GNUNET_asprintf (&path,
"aml-decision/%s",
opus);
wh->url = TALER_url_join (url,
path,
NULL);
GNUNET_free (path);
}
if (NULL == wh->url)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Could not construct request URL.\n");
GNUNET_free (wh);
return NULL;
}
body = GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("justification",
justification),
GNUNET_JSON_pack_data_auto ("officer_sig",
&officer_sig),
GNUNET_JSON_pack_data_auto ("h_payto",
h_payto),
GNUNET_JSON_pack_data_uint64 ("state",
(uint32_t) new_state),
TALER_JSON_pack_amount ("new_threshold",
new_threshold),
GNUNET_JSON_pack_timestamp ("decision_time",
decision_time));
eh = TALER_EXCHANGE_curl_easy_get_ (wh->url);
if ( (NULL == eh) ||
(GNUNET_OK !=
TALER_curl_easy_post (&wh->post_ctx,
eh,
body)) )
{
GNUNET_break (0);
if (NULL != eh)
curl_easy_cleanup (eh);
json_decref (body);
GNUNET_free (wh->url);
return NULL;
}
json_decref (body);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Requesting URL '%s'\n",
wh->url);
wh->job = GNUNET_CURL_job_add2 (ctx,
eh,
wh->post_ctx.headers,
&handle_add_aml_decision_finished,
wh);
if (NULL == wh->job)
{
TALER_EXCHANGE_add_aml_decision_cancel (wh);
return NULL;
}
return wh;
}
void
TALER_EXCHANGE_add_aml_decision_cancel (
struct TALER_EXCHANGE_AddAmlDecision *wh)
{
if (NULL != wh->job)
{
GNUNET_CURL_job_cancel (wh->job);
wh->job = NULL;
}
TALER_curl_easy_post_finished (&wh->post_ctx);
GNUNET_free (wh->url);
GNUNET_free (wh);
}

View File

@ -0,0 +1,232 @@
/*
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 General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>
*/
/**
* @file lib/exchange_api_management_add_partner.c
* @brief functions to add an partner by an AML officer
* @author Christian Grothoff
*/
#include "platform.h"
#include "taler_json_lib.h"
#include <gnunet/gnunet_curl_lib.h>
#include "taler_exchange_service.h"
#include "exchange_api_curl_defaults.h"
#include "taler_signatures.h"
#include "taler_curl_lib.h"
#include "taler_json_lib.h"
struct TALER_EXCHANGE_ManagementAddPartner
{
/**
* The url for this request.
*/
char *url;
/**
* Minor context that holds body and headers.
*/
struct TALER_CURL_PostContext post_ctx;
/**
* Handle for the request.
*/
struct GNUNET_CURL_Job *job;
/**
* Function to call with the result.
*/
TALER_EXCHANGE_ManagementAddPartnerCallback cb;
/**
* Closure for @a cb.
*/
void *cb_cls;
/**
* Reference to the execution context.
*/
struct GNUNET_CURL_Context *ctx;
};
/**
* Function called when we're done processing the
* HTTP POST /aml-decision/$OFFICER_PUB request.
*
* @param cls the `struct TALER_EXCHANGE_ManagementAddPartner *`
* @param response_code HTTP response code, 0 on error
* @param response response body, NULL if not in JSON
*/
static void
handle_add_partner_finished (void *cls,
long response_code,
const void *response)
{
struct TALER_EXCHANGE_ManagementAddPartner *wh = cls;
const json_t *json = response;
struct TALER_EXCHANGE_HttpResponse hr = {
.http_status = (unsigned int) response_code,
.reply = json
};
wh->job = NULL;
switch (response_code)
{
case 0:
/* no reply */
hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
hr.hint = "server offline?";
break;
case MHD_HTTP_NO_CONTENT:
break;
case MHD_HTTP_FORBIDDEN:
hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json);
break;
case MHD_HTTP_CONFLICT:
hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json);
break;
default:
/* unexpected response code */
GNUNET_break_op (0);
hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d for adding exchange partner\n",
(unsigned int) response_code,
(int) hr.ec);
break;
}
if (NULL != wh->cb)
{
wh->cb (wh->cb_cls,
&hr);
wh->cb = NULL;
}
TALER_EXCHANGE_management_add_partner_cancel (wh);
}
struct TALER_EXCHANGE_ManagementAddPartner *
TALER_EXCHANGE_management_add_partner (
struct GNUNET_CURL_Context *ctx,
const char *url,
const struct TALER_MasterPublicKeyP *partner_pub,
struct GNUNET_TIME_Timestamp start_date,
struct GNUNET_TIME_Timestamp end_date,
struct GNUNET_TIME_Relative wad_frequency,
const struct TALER_Amount *wad_fee,
const char *partner_base_url,
const struct TALER_MasterSignatureP *master_sig,
TALER_EXCHANGE_ManagementAddPartnerCallback cb,
void *cb_cls)
{
struct TALER_EXCHANGE_ManagementAddPartner *wh;
CURL *eh;
json_t *body;
wh = GNUNET_new (struct TALER_EXCHANGE_ManagementAddPartner);
wh->cb = cb;
wh->cb_cls = cb_cls;
wh->ctx = ctx;
{
char *path;
char opus[sizeof (*partner_pub) * 2];
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)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Could not construct request URL.\n");
GNUNET_free (wh);
return NULL;
}
body = GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("partner_base_url",
partner_base_url),
GNUNET_JSON_pack_timestamp ("start_date",
start_date),
GNUNET_JSON_pack_timestamp ("end_date",
end_date),
GNUNET_JSON_pack_time_rel ("wad_frequency",
wad_frequency),
GNUNET_JSON_pack_data_auto ("master_sig",
&master_sig),
TALER_JSON_pack_amount ("wad_fee",
wad_fee)
);
eh = TALER_EXCHANGE_curl_easy_get_ (wh->url);
if ( (NULL == eh) ||
(GNUNET_OK !=
TALER_curl_easy_post (&wh->post_ctx,
eh,
body)) )
{
GNUNET_break (0);
if (NULL != eh)
curl_easy_cleanup (eh);
json_decref (body);
GNUNET_free (wh->url);
return NULL;
}
json_decref (body);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Requesting URL '%s'\n",
wh->url);
wh->job = GNUNET_CURL_job_add2 (ctx,
eh,
wh->post_ctx.headers,
&handle_add_partner_finished,
wh);
if (NULL == wh->job)
{
TALER_EXCHANGE_management_add_partner_cancel (wh);
return NULL;
}
return wh;
}
void
TALER_EXCHANGE_management_add_partner_cancel (
struct TALER_EXCHANGE_ManagementAddPartner *wh)
{
if (NULL != wh->job)
{
GNUNET_CURL_job_cancel (wh->job);
wh->job = NULL;
}
TALER_curl_easy_post_finished (&wh->post_ctx);
GNUNET_free (wh->url);
GNUNET_free (wh);
}

View File

@ -0,0 +1,228 @@
/*
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 General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>
*/
/**
* @file lib/exchange_api_management_update_aml_officer.c
* @brief functions to update AML officer status
* @author Christian Grothoff
*/
#include "platform.h"
#include "taler_json_lib.h"
#include <gnunet/gnunet_curl_lib.h>
#include "taler_exchange_service.h"
#include "exchange_api_curl_defaults.h"
#include "taler_signatures.h"
#include "taler_curl_lib.h"
#include "taler_json_lib.h"
struct TALER_EXCHANGE_ManagementUpdateAmlOfficer
{
/**
* The url for this request.
*/
char *url;
/**
* Minor context that holds body and headers.
*/
struct TALER_CURL_PostContext post_ctx;
/**
* Handle for the request.
*/
struct GNUNET_CURL_Job *job;
/**
* Function to call with the result.
*/
TALER_EXCHANGE_ManagementUpdateAmlOfficerCallback cb;
/**
* Closure for @a cb.
*/
void *cb_cls;
/**
* Reference to the execution context.
*/
struct GNUNET_CURL_Context *ctx;
};
/**
* Function called when we're done processing the
* HTTP /management/wire request.
*
* @param cls the `struct TALER_EXCHANGE_ManagementAuditorEnableHandle *`
* @param response_code HTTP response code, 0 on error
* @param response response body, NULL if not in JSON
*/
static void
handle_update_aml_officer_finished (void *cls,
long response_code,
const void *response)
{
struct TALER_EXCHANGE_ManagementUpdateAmlOfficer *wh = cls;
const json_t *json = response;
struct TALER_EXCHANGE_HttpResponse hr = {
.http_status = (unsigned int) response_code,
.reply = json
};
wh->job = NULL;
switch (response_code)
{
case 0:
/* no reply */
hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
hr.hint = "server offline?";
break;
case MHD_HTTP_NO_CONTENT:
break;
case MHD_HTTP_FORBIDDEN:
hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json);
break;
case MHD_HTTP_CONFLICT:
hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json);
break;
default:
/* unexpected response code */
GNUNET_break_op (0);
hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d for exchange management update AML officer\n",
(unsigned int) response_code,
(int) hr.ec);
break;
}
if (NULL != wh->cb)
{
wh->cb (wh->cb_cls,
&hr);
wh->cb = NULL;
}
TALER_EXCHANGE_management_update_aml_officer_cancel (wh);
}
struct TALER_EXCHANGE_ManagementUpdateAmlOfficer *
TALER_EXCHANGE_management_update_aml_officer (
struct GNUNET_CURL_Context *ctx,
const char *url,
const struct TALER_AmlOfficerPublicKeyP *officer_pub,
const char *officer_name,
struct GNUNET_TIME_Timestamp change_date,
bool is_active,
bool read_only,
const struct TALER_MasterSignatureP *master_sig,
TALER_EXCHANGE_ManagementUpdateAmlOfficerCallback cb,
void *cb_cls)
{
struct TALER_EXCHANGE_ManagementUpdateAmlOfficer *wh;
CURL *eh;
json_t *body;
wh = GNUNET_new (struct TALER_EXCHANGE_ManagementUpdateAmlOfficer);
wh->cb = cb;
wh->cb_cls = cb_cls;
wh->ctx = ctx;
{
char *path;
char opus[sizeof (*officer_pub) * 2];
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)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Could not construct request URL.\n");
GNUNET_free (wh);
return NULL;
}
body = GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("officer_name",
officer_name),
GNUNET_JSON_pack_data_auto ("master_sig",
master_sig),
GNUNET_JSON_pack_data_bool ("is_active",
is_active),
GNUNET_JSON_pack_data_bool ("read_only",
read_only),
GNUNET_JSON_pack_timestamp ("change_date",
change_date));
eh = TALER_EXCHANGE_curl_easy_get_ (wh->url);
if ( (NULL == eh) ||
(GNUNET_OK !=
TALER_curl_easy_post (&wh->post_ctx,
eh,
body)) )
{
GNUNET_break (0);
if (NULL != eh)
curl_easy_cleanup (eh);
json_decref (body);
GNUNET_free (wh->url);
return NULL;
}
json_decref (body);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Requesting URL '%s'\n",
wh->url);
wh->job = GNUNET_CURL_job_add2 (ctx,
eh,
wh->post_ctx.headers,
&handle_update_aml_officer_finished,
wh);
if (NULL == wh->job)
{
TALER_EXCHANGE_management_update_aml_officer_cancel (wh);
return NULL;
}
return wh;
}
void
TALER_EXCHANGE_management_update_aml_officer_cancel (
struct TALER_EXCHANGE_ManagementUpdateAmlOfficer *wh)
{
if (NULL != wh->job)
{
GNUNET_CURL_job_cancel (wh->job);
wh->job = NULL;
}
TALER_curl_easy_post_finished (&wh->post_ctx);
GNUNET_free (wh->url);
GNUNET_free (wh);
}

View File

@ -0,0 +1,204 @@
/*
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 General Public License as published by
the Free Software Foundation; either version 3, or (at your
option) any later version.
TALER is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public
License along with TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>
*/
/**
* @file testing/testing_api_cmd_set_officer.c
* @brief command for testing /management/XXX
* @author Christian Grothoff
*/
#include "platform.h"
#include "taler_json_lib.h"
#include <gnunet/gnunet_curl_lib.h>
#include "taler_testing_lib.h"
#include "taler_signatures.h"
#include "backoff.h"
/**
* State for a "set_officer" CMD.
*/
struct SetOfficerState
{
/**
* Auditor enable handle while operation is running.
*/
struct TALER_EXCHANGE_ManagementAuditorEnableHandle *dh;
/**
* Our interpreter.
*/
struct TALER_TESTING_Interpreter *is;
/**
* Reference to command to previous set officer
* to update, or NULL.
*/
const char *ref_cmd;
/**
* Name to use for the officer.
*/
const char *name;
// FIXME: add trait with officer-priv here!
/**
* Is the officer supposed to be enabled?
*/
bool is_active;
/**
* Is access supposed to be read-only?
*/
bool read_only;
};
/**
* Callback to analyze the /management/XXX response, just used to check
* if the response code is acceptable.
*
* @param cls closure.
* @param hr HTTP response details
*/
static void
set_officer_cb (void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr)
{
struct SetOfficerState *ds = cls;
ds->dh = NULL;
if (MHD_HTTP_NO_CONTENT != hr->response_code)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Unexpected response code %u to command %s in %s:%u\n",
hr->http_status,
ds->is->commands[ds->is->ip].label,
__FILE__,
__LINE__);
json_dumpf (hr->reply,
stderr,
0);
TALER_TESTING_interpreter_fail (ds->is);
return;
}
TALER_TESTING_interpreter_next (ds->is);
}
/**
* Run the command.
*
* @param cls closure.
* @param cmd the command to execute.
* @param is the interpreter state.
*/
static void
set_officer_run (void *cls,
const struct TALER_TESTING_Command *cmd,
struct TALER_TESTING_Interpreter *is)
{
struct SetOfficerState *ds = cls;
struct GNUNET_TIME_Timestamp now;
struct TALER_MasterSignatureP master_sig;
(void) cmd;
now = GNUNET_TIME_timestamp_get ();
ds->is = is;
TALER_exchange_offline_set_officer_sign (&is->auditor_pub,
is->auditor_url,
now,
&is->master_priv,
&master_sig);
ds->dh = TALER_EXCHANGE_management_enable_auditor (
is->ctx,
is->exchange_url,
&is->auditor_pub,
is->auditor_url,
"test-case auditor", /* human-readable auditor name */
now,
&master_sig,
&set_officer_cb,
ds);
if (NULL == ds->dh)
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
}
/**
* Free the state of a "set_officer" CMD, and possibly cancel a
* pending operation thereof.
*
* @param cls closure, must be a `struct SetOfficerState`.
* @param cmd the command which is being cleaned up.
*/
static void
set_officer_cleanup (void *cls,
const struct TALER_TESTING_Command *cmd)
{
struct SetOfficerState *ds = cls;
if (NULL != ds->dh)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Command %u (%s) did not complete\n",
ds->is->ip,
cmd->label);
TALER_EXCHANGE_management_enable_auditor_cancel (ds->dh);
ds->dh = NULL;
}
GNUNET_free (ds);
}
struct TALER_TESTING_Command
TALER_TESTING_cmd_set_officer (
const char *label,
const char *ref_cmd,
const char *name,
bool is_active,
bool read_only)
{
struct SetOfficerState *ds;
ds = GNUNET_new (struct SetOfficerState);
ds->ref_cmd = ref_cmd;
ds->name = name;
ds->is_active = is_active;
ds->read_only = read_only;
{
struct TALER_TESTING_Command cmd = {
.cls = ds,
.label = label,
.run = &set_officer_run,
.cleanup = &set_officer_cleanup
// FIXME: expose trait with officer-priv here!
};
return cmd;
}
}
/* end of testing_api_cmd_set_officer.c */

View File

@ -0,0 +1,204 @@
/*
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 General Public License as published by
the Free Software Foundation; either version 3, or (at your
option) any later version.
TALER is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public
License along with TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>
*/
/**
* @file testing/testing_api_cmd_take_aml_decision.c
* @brief command for testing /management/XXX
* @author Christian Grothoff
*/
#include "platform.h"
#include "taler_json_lib.h"
#include <gnunet/gnunet_curl_lib.h>
#include "taler_testing_lib.h"
#include "taler_signatures.h"
#include "backoff.h"
/**
* State for a "take_aml_decision" CMD.
*/
struct AmlDecisionState
{
/**
* Auditor enable handle while operation is running.
*/
struct TALER_EXCHANGE_ManagementAuditorEnableHandle *dh;
/**
* Our interpreter.
*/
struct TALER_TESTING_Interpreter *is;
/**
* Reference to command to previous set officer
* to update, or NULL.
*/
const char *ref_cmd;
/**
* Name to use for the officer.
*/
const char *name;
// FIXME: add trait with officer-priv here!
/**
* Is the officer supposed to be enabled?
*/
bool is_active;
/**
* Is access supposed to be read-only?
*/
bool read_only;
};
/**
* Callback to analyze the /management/XXX response, just used to check
* if the response code is acceptable.
*
* @param cls closure.
* @param hr HTTP response details
*/
static void
take_aml_decision_cb (void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr)
{
struct AmlDecisionState *ds = cls;
ds->dh = NULL;
if (MHD_HTTP_NO_CONTENT != hr->response_code)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Unexpected response code %u to command %s in %s:%u\n",
hr->http_status,
ds->is->commands[ds->is->ip].label,
__FILE__,
__LINE__);
json_dumpf (hr->reply,
stderr,
0);
TALER_TESTING_interpreter_fail (ds->is);
return;
}
TALER_TESTING_interpreter_next (ds->is);
}
/**
* Run the command.
*
* @param cls closure.
* @param cmd the command to execute.
* @param is the interpreter state.
*/
static void
take_aml_decision_run (void *cls,
const struct TALER_TESTING_Command *cmd,
struct TALER_TESTING_Interpreter *is)
{
struct AmlDecisionState *ds = cls;
struct GNUNET_TIME_Timestamp now;
struct TALER_MasterSignatureP master_sig;
(void) cmd;
now = GNUNET_TIME_timestamp_get ();
ds->is = is;
TALER_exchange_offline_take_aml_decision_sign (&is->auditor_pub,
is->auditor_url,
now,
&is->master_priv,
&master_sig);
ds->dh = TALER_EXCHANGE_management_enable_auditor (
is->ctx,
is->exchange_url,
&is->auditor_pub,
is->auditor_url,
"test-case auditor", /* human-readable auditor name */
now,
&master_sig,
&take_aml_decision_cb,
ds);
if (NULL == ds->dh)
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
}
/**
* Free the state of a "take_aml_decision" CMD, and possibly cancel a
* pending operation thereof.
*
* @param cls closure, must be a `struct AmlDecisionState`.
* @param cmd the command which is being cleaned up.
*/
static void
take_aml_decision_cleanup (void *cls,
const struct TALER_TESTING_Command *cmd)
{
struct AmlDecisionState *ds = cls;
if (NULL != ds->dh)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Command %u (%s) did not complete\n",
ds->is->ip,
cmd->label);
TALER_EXCHANGE_management_enable_auditor_cancel (ds->dh);
ds->dh = NULL;
}
GNUNET_free (ds);
}
struct TALER_TESTING_Command
TALER_TESTING_cmd_take_aml_decision (
const char *label,
const char *ref_officer,
const char *ref_operation,
const char *new_threshold,
bool block)
{
struct AmlDecisionState *ds;
ds = GNUNET_new (struct AmlDecisionState);
ds->ref_cmd = ref_cmd;
ds->name = name;
ds->is_active = is_active;
ds->read_only = read_only;
{
struct TALER_TESTING_Command cmd = {
.cls = ds,
.label = label,
.run = &take_aml_decision_run,
.cleanup = &take_aml_decision_cleanup
// FIXME: expose trait with officer-priv here!
};
return cmd;
}
}
/* end of testing_api_cmd_take_aml_decision.c */