exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

commit 0cae15196ceb54817b33c6889aeb0322f431fff4
parent 20a7fc60c486342b5203ce9e1467bc111b51f47b
Author: Christian Grothoff <christian@grothoff.org>
Date:   Tue,  3 Nov 2026 23:00:34 +0100

do not skip check if merely the timestamp matches

Diffstat:
Msrc/auditor/taler-helper-auditor-aml.c | 47+++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 43 insertions(+), 4 deletions(-)

diff --git a/src/auditor/taler-helper-auditor-aml.c b/src/auditor/taler-helper-auditor-aml.c @@ -157,6 +157,12 @@ struct StaffStatus bool read_only; /** + * Hash of the legal name of the member at this status. Kept instead of + * the name itself so that the entry owns no memory. + */ + struct GNUNET_HashCode h_name; + + /** * Did the exchange's offline master key actually sign this status? * A status that fails this check confers no authority. */ @@ -221,6 +227,24 @@ staff_key (const struct TALER_AmlOfficerPublicKeyP *decider_pub, /** + * Compute the hash of the legal name @a decider_name. + * + * @param decider_name legal name of the staff member, NULL if not given + * @param[out] h_name set to the hash to use + */ +static void +staff_name_hash (const char *decider_name, + struct GNUNET_HashCode *h_name) +{ + if (NULL == decider_name) + decider_name = ""; + GNUNET_CRYPTO_hash (decider_name, + strlen (decider_name), + h_name); +} + + +/** * Look up @a decider_pub in #staff_map, creating the entry if needed. * * @param decider_pub public key of the staff member @@ -375,7 +399,8 @@ known_staff_cb (void *cls, }; (void) cls; - (void) decider_name; + staff_name_hash (decider_name, + &ss.h_name); staff_member_add (sm, &ss); /* We are called oldest-first, so the last call for a member leaves the @@ -423,13 +448,27 @@ check_staff_cb (void *cls, (void) cls; TALER_ARL_USE_PP (aml_staff_uuid) = rowid + 1; + staff_name_hash (decider_name, + &ss.h_name); for (unsigned int i = 0; i < sm->num_statuses; i++) { - if (GNUNET_TIME_timestamp_cmp (sm->statuses[i].last_change, + const struct StaffStatus *os = &sm->statuses[i]; + + if (GNUNET_TIME_timestamp_cmp (os->last_change, ==, last_change)) - return GNUNET_OK; /* already seen and judged in an earlier round */ - if (GNUNET_TIME_timestamp_cmp (sm->statuses[i].last_change, + { + if ( (os->is_active == is_active) && + (os->read_only == read_only) && + (0 == GNUNET_memcmp (&os->h_name, + &ss.h_name)) ) + return GNUNET_OK; /* already seen and judged in an earlier round */ + /* Same timestamp, but a different status: this widens (or narrows) the + officer's authority and must be judged and recorded like any other + status change. */ + continue; + } + if (GNUNET_TIME_timestamp_cmp (os->last_change, >, last_change)) regression = true;