commit 71b4c20fdd898c500f2d88d72348125ef7ee7c60
parent 75cac8340a41c5d8b1057d31feeb7877c91a7839
Author: Christian Grothoff <christian@grothoff.org>
Date: Wed, 1 Apr 2026 14:29:30 +0200
minor consistency fixes, enforce AML officer read-only access semantics
Diffstat:
13 files changed, 76 insertions(+), 23 deletions(-)
diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c
@@ -481,6 +481,42 @@ handle_post_aml (struct TEH_RequestContext *rc,
TALER_EC_EXCHANGE_GENERIC_AML_OFFICER_PUB_MALFORMED,
args[0]);
}
+
+ {
+ enum GNUNET_DB_QueryStatus qs;
+ bool ro;
+
+ qs = TEH_plugin->test_aml_officer (TEH_plugin->cls,
+ &officer_pub,
+ &ro);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (rc->connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ NULL);
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (rc->connection,
+ MHD_HTTP_FORBIDDEN,
+ TALER_EC_EXCHANGE_GENERIC_AML_OFFICER_ACCESS_DENIED,
+ "unknown or inactive");
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ break;
+ }
+ if (ro)
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (rc->connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_EXCHANGE_GENERIC_AML_OFFICER_ACCESS_DENIED,
+ "read-only");
+ }
+ }
+
for (unsigned int i = 0; NULL != h[i].op; i++)
if (0 == strcmp (h[i].op,
args[1]))
@@ -638,9 +674,11 @@ handle_get_aml (struct TEH_RequestContext *rc,
{
enum GNUNET_DB_QueryStatus qs;
+ bool ro;
qs = TEH_plugin->test_aml_officer (TEH_plugin->cls,
- &officer_pub);
+ &officer_pub,
+ &ro);
switch (qs)
{
case GNUNET_DB_STATUS_HARD_ERROR:
diff --git a/src/exchange/taler-exchange-httpd_get-aml-OFFICER_PUB-attributes-H_NORMALIZED_PAYTO.c b/src/exchange/taler-exchange-httpd_get-aml-OFFICER_PUB-attributes-H_NORMALIZED_PAYTO.c
@@ -372,8 +372,8 @@ detail_cb (
json_array_append_new (
rc->details.json,
GNUNET_JSON_PACK (
- GNUNET_JSON_pack_int64 ("rowid",
- row_id),
+ GNUNET_JSON_pack_uint64 ("rowid",
+ row_id),
GNUNET_JSON_pack_bool ("by_aml_officer",
by_aml_officer),
GNUNET_JSON_pack_allow_null (
diff --git a/src/exchange/taler-exchange-httpd_get-aml-OFFICER_PUB-decisions.c b/src/exchange/taler-exchange-httpd_get-aml-OFFICER_PUB-decisions.c
@@ -81,8 +81,8 @@ record_cb (
payto),
GNUNET_JSON_pack_bool ("is_wallet",
is_wallet),
- GNUNET_JSON_pack_int64 ("rowid",
- row_id),
+ GNUNET_JSON_pack_uint64 ("rowid",
+ row_id),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_string ("justification",
justification)),
diff --git a/src/exchange/taler-exchange-httpd_get-aml-OFFICER_PUB-legitimizations.c b/src/exchange/taler-exchange-httpd_get-aml-OFFICER_PUB-legitimizations.c
@@ -69,9 +69,8 @@ record_cb (
GNUNET_JSON_pack_timestamp ("start_time",
GNUNET_TIME_absolute_to_timestamp (
start_time)),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_object_incref ("measures",
- (json_t *) jmeasures)),
+ GNUNET_JSON_pack_object_incref ("measures",
+ (json_t *) jmeasures),
GNUNET_JSON_pack_bool ("is_finished",
is_finished)
)));
diff --git a/src/exchange/taler-exchange-httpd_get-coins-COIN_PUB-history.c b/src/exchange/taler-exchange-httpd_get-coins-COIN_PUB-history.c
@@ -382,8 +382,6 @@ compile_transaction_history (
&recoup->coin_blind),
// FIXME-9828: spec says we should have h_commitment?
// FIXME-9828: spec says we should have coin_index?
- GNUNET_JSON_pack_data_auto ("reserve_pub",
- &recoup->reserve_pub),
GNUNET_JSON_pack_timestamp ("timestamp",
recoup->timestamp))))
{
diff --git a/src/exchangedb/pg_select_aml_measures.c b/src/exchangedb/pg_select_aml_measures.c
@@ -74,7 +74,7 @@ handle_aml_result (void *cls,
struct TALER_NormalizedPaytoHashP h_payto;
uint64_t rowid;
struct GNUNET_TIME_Absolute start_time;
- json_t *jmeasures = NULL;
+ json_t *jmeasures;
bool is_finished;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_uint64 ("legitimization_measure_serial_id",
diff --git a/src/exchangedb/pg_test_aml_officer.c b/src/exchangedb/pg_test_aml_officer.c
@@ -29,20 +29,28 @@
enum GNUNET_DB_QueryStatus
TEH_PG_test_aml_officer (
void *cls,
- const struct TALER_AmlOfficerPublicKeyP *decider_pub)
+ const struct TALER_AmlOfficerPublicKeyP *decider_pub,
+ bool *read_only)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (decider_pub),
GNUNET_PQ_query_param_end
};
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_bool ("read_only",
+ read_only),
+ GNUNET_PQ_result_spec_end
+ };
PREPARE (pg,
"test_aml_staff",
- "SELECT 1 FROM aml_staff"
+ "SELECT read_only"
+ " FROM aml_staff"
" WHERE decider_pub=$1"
" AND is_active;");
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "test_aml_staff",
- params);
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "test_aml_staff",
+ params,
+ rs);
}
diff --git a/src/exchangedb/pg_test_aml_officer.h b/src/exchangedb/pg_test_aml_officer.h
@@ -32,12 +32,14 @@
*
* @param cls closure
* @param decider_pub public key of the staff member
+ * @param[out] read_only set to true if the member is read-only
* @return database transaction status, if member is unknown or not active, 1 if member is active
*/
enum GNUNET_DB_QueryStatus
TEH_PG_test_aml_officer (
void *cls,
- const struct TALER_AmlOfficerPublicKeyP *decider_pub);
+ const struct TALER_AmlOfficerPublicKeyP *decider_pub,
+ bool *read_only);
#endif
diff --git a/src/include/taler/taler-exchange/get-coins-COIN_PUB-history.h b/src/include/taler/taler-exchange/get-coins-COIN_PUB-history.h
@@ -210,6 +210,7 @@ struct TALER_EXCHANGE_CoinHistoryEntry
{
struct TALER_ReserveSignatureP reserve_sig;
struct TALER_CoinSpendSignatureP coin_sig;
+ struct TALER_Amount coin_contribution;
} reserve_open_deposit;
} details;
diff --git a/src/include/taler/taler_exchangedb_plugin.h b/src/include/taler/taler_exchangedb_plugin.h
@@ -7649,12 +7649,14 @@ struct TALER_EXCHANGEDB_Plugin
*
* @param cls closure
* @param decider_pub public key of the staff member
+ * @param[out] read_only set to true if the member is read-only
* @return database transaction status, if member is unknown or not active, 1 if member is active
*/
enum GNUNET_DB_QueryStatus
(*test_aml_officer)(
void *cls,
- const struct TALER_AmlOfficerPublicKeyP *decider_pub);
+ const struct TALER_AmlOfficerPublicKeyP *decider_pub,
+ bool *read_only);
/**
diff --git a/src/lib/exchange_api_get-aml-OFFICER_PUB-attributes-H_NORMALIZED_PAYTO.c b/src/lib/exchange_api_get-aml-OFFICER_PUB-attributes-H_NORMALIZED_PAYTO.c
@@ -440,8 +440,6 @@ TALER_EXCHANGE_get_aml_attributes_start (
job_headers = curl_slist_append (NULL,
hdr);
GNUNET_free (hdr);
- job_headers = curl_slist_append (job_headers,
- "Content-type: application/json");
aagh->job = GNUNET_CURL_job_add2 (aagh->ctx,
eh,
job_headers,
diff --git a/src/lib/exchange_api_get-coins-COIN_PUB-history.c b/src/lib/exchange_api_get-coins-COIN_PUB-history.c
@@ -722,6 +722,9 @@ help_reserve_open_deposit (struct CoinHistoryParseContext *pc,
&rh->details.reserve_open_deposit.reserve_sig),
GNUNET_JSON_spec_fixed_auto ("coin_sig",
&rh->details.reserve_open_deposit.coin_sig),
+ TALER_JSON_spec_amount_any ("coin_contribution",
+ &rh->details.reserve_open_deposit.
+ coin_contribution),
GNUNET_JSON_spec_end ()
};
@@ -773,13 +776,13 @@ TALER_EXCHANGE_parse_coin_history (
{ "REFUND",
&help_refund,
TALER_EXCHANGE_CTT_REFUND },
- { "RECOUP",
+ { "RECOUP-WITHDRAW",
&help_recoup,
TALER_EXCHANGE_CTT_RECOUP },
{ "RECOUP-REFRESH",
&help_recoup_refresh,
TALER_EXCHANGE_CTT_RECOUP_REFRESH },
- { "OLD-COIN-RECOUP",
+ { "RECOUP-REFRESH-RECEIVER",
&help_old_coin_recoup,
TALER_EXCHANGE_CTT_OLD_COIN_RECOUP },
{ "PURSE-DEPOSIT",
@@ -986,6 +989,10 @@ handle_coins_history_finished (void *cls,
rs.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
}
break;
+ case MHD_HTTP_NO_CONTENT:
+ break;
+ case MHD_HTTP_NOT_MODIFIED:
+ break;
case MHD_HTTP_BAD_REQUEST:
/* This should never happen, either us or the exchange is buggy
(or API version conflict); just pass JSON reply to the application */
diff --git a/src/util/wallet_signatures.c b/src/util/wallet_signatures.c
@@ -1759,7 +1759,7 @@ struct TALER_ReserveOpenDepositPS
GNUNET_NETWORK_STRUCT_END
-// FIXME-#7267: add h_age_commitment, h_denom_pub to have proof!
+// FIXME-#11318: add h_age_commitment, h_denom_pub to have proof!
void
TALER_wallet_reserve_open_deposit_sign (
const struct TALER_Amount *coin_contribution,