donau

Donation authority for GNU Taler (experimental)
Log | Files | Refs | Submodules | README | LICENSE

commit a32de704f62ff324d3daaa1fd3293a71680ad8c1
parent 14d08c0bb8a3121abde4a2a117ac1f7349540146
Author: Matyja Lukas Adam <lukas.matyja@students.bfh.ch>
Date:   Tue, 28 May 2024 16:05:19 +0200

[lib][include] add new client

Diffstat:
Msrc/include/donau_crypto_lib.h | 36++++++++++++++++++++++++++++--------
Msrc/include/donau_service.h | 120++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Msrc/lib/Makefile.am | 3++-
Asrc/lib/donau_api_donation_statement_get.c | 256+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 380 insertions(+), 35 deletions(-)

diff --git a/src/include/donau_crypto_lib.h b/src/include/donau_crypto_lib.h @@ -23,6 +23,7 @@ * @author Lukas Matyja * @author Pius Loosli */ + #if ! defined (__DONAU_UTIL_LIB_H_INSIDE__) #error "Only <donau_util.h> can be included directly." #endif @@ -323,14 +324,6 @@ struct DONAU_BkpSignData const struct DONAU_BlindedUniqueDonorIdentifier *budi; }; -/** USED? - * Hash of a budikeypair array - */ -// struct DONAU_BudiHashP -// { -// struct GNUNET_HashCode hash; -// }; - /** * Hash of a Unique Donor Identifier (h_donor_tax_id + nonce) */ @@ -372,6 +365,33 @@ struct DONAU_BudiMasterSecretP }; +/** + * Donation Statement + */ +struct DONAU_DonationStatement +{ + /** + * The corresponding year. + */ + uint64_t year; + + /** + * The salted and hashed donor id. + */ + struct DONAU_HashDonorTaxId *h_donor_tax_id; + + /** + * The total donated amount. + */ + struct TALER_Amount total_amount; + + /** + * The donation statement signature over @year, @h_donor_tax_id and @total_amount. + */ + struct DONAU_DonauSignatureP *donation_statement_sig; + +}; + /* ********************* charity eddsa signing ************************** */ diff --git a/src/include/donau_service.h b/src/include/donau_service.h @@ -584,6 +584,89 @@ struct DONAU_DonorReceiptsToStatementResult */ struct DONAU_HttpResponse hr; +}; + + +/** + * Callbacks of this type are used to serve the result of submitting a + * permission request to a donau. + * + * @param cls closure + * @param dr response details + */ +typedef void +(*DONAU_DonorReceiptsToStatementResultCallback) ( + void *cls, + const struct DONAU_DonorReceiptsToStatementResult *dr); + + +/** + * Submit a batch of receipts to the donau and get the + * donau's response. This API is typically used by a donor. Note that + * while we return the response verbatim to the caller for further processing, + * we do already verify that the response is well-formed (i.e. that signatures + * included in the response are all valid). If the donau's reply is not + * well-formed, we return an HTTP status code of zero to @a cb. + * + * We also verify that the signature of the charity is valid for this + * request. Also, the @a donau must be ready to operate (i.e. have + * finished processing the /keys reply). If either check fails, we do + * NOT initiate the receipts with the donau and instead return NULL. + * + * @param ctx curl context + * @param url donau base URL + * @param num_drs length of the @a drs array + * @param drs array with details about the donation receipts + * @param year corresponding year + * @param h_donor_tax_id salted and hashed tax id + * @param cb the callback to call when a reply for this request is available + * @param cls closure for the above callback + * @param[out] ec if NULL is returned, set to the error code explaining why the operation failed + * @return a handle for this request; NULL if the inputs are invalid (i.e. + * signatures fail to verify). In this case, the callback is not called. + */ +struct DONAU_DonorReceiptsToStatementHandle * +DONAU_donor_receipts_to_statement ( + struct GNUNET_CURL_Context *ctx, + const char *url, + const size_t num_drs, + const struct DONAU_DonationReceipt drs[num_drs], + const uint64_t year, + const struct DONAU_HashDonorTaxId *h_donor_tax_id, + DONAU_DonorReceiptsToStatementResultCallback cb, + void *cls); + +/** + * Cancel a batch permission request. This function cannot be used + * on a request handle if a response is already served for it. + * + * @param[in] the Batch Submit recipts handle + */ +void +DONAU_donor_receipts_to_statement_cancel ( + struct DONAU_DonorReceiptsToStatementHandle *); + + +/* ********************* GET /donation-statement *********************** */ + + +/** + * @brief A get donation statement Handle + */ +struct DONAU_DonationStatementGetHandle; + + +/** + * Structure with information about a + * operation's result. + */ +struct DONAU_DonationStatementResponse +{ + /** + * HTTP response data + */ + struct DONAU_HttpResponse hr; + union { @@ -602,15 +685,10 @@ struct DONAU_DonorReceiptsToStatementResult * The donation statment for a requested year. Signature over the total amount, * the year, the unique identifier hash */ - struct DONAU_DonauSignatureP *sig; + struct DONAU_DonauSignatureP *donation_statement_sig; } ok; - struct - { - /* TODO: returning full details is not implemented */ - } conflict; - } details; }; @@ -623,28 +701,20 @@ struct DONAU_DonorReceiptsToStatementResult * @param dr response details */ typedef void -(*DONAU_DonorReceiptsToStatementResultCallback) ( +(*DONAU_GetDonationStatmentResponseCallback) ( void *cls, - const struct DONAU_DonorReceiptsToStatementResult *dr); + const struct DONAU_DonationStatementResponse *dr); /** - * Submit a batch of receipts to the donau and get the - * donau's response. This API is typically used by a donor. Note that - * while we return the response verbatim to the caller for further processing, + * Get a specific donation statement from the donau. This API is typically used by a donor. + * Note that while we return the response verbatim to the caller for further processing, * we do already verify that the response is well-formed (i.e. that signatures * included in the response are all valid). If the donau's reply is not * well-formed, we return an HTTP status code of zero to @a cb. * - * We also verify that the signature of the charity is valid for this - * request. Also, the @a donau must be ready to operate (i.e. have - * finished processing the /keys reply). If either check fails, we do - * NOT initiate the receipts with the donau and instead return NULL. - * * @param ctx curl context * @param url donau base URL - * @param num_drs length of the @a drs array - * @param drs array with details about the donation receipts * @param year corresponding year * @param h_donor_tax_id salted and hashed tax id * @param cb the callback to call when a reply for this request is available @@ -653,16 +723,14 @@ typedef void * @return a handle for this request; NULL if the inputs are invalid (i.e. * signatures fail to verify). In this case, the callback is not called. */ -struct DONAU_DonorReceiptsToStatementHandle * -DONAU_donor_receipts_to_statement ( +struct DONAU_DonationStatementGetHandle * +DONAU_donation_statement_get ( struct GNUNET_CURL_Context *ctx, const char *url, - const size_t num_drs, - const struct DONAU_DonationReceipt drs[num_drs], const uint64_t year, const struct DONAU_HashDonorTaxId *h_donor_tax_id, - DONAU_DonorReceiptsToStatementResultCallback cb, - void *cls); + DONAU_GetDonationStatmentResponseCallback cb, + void *cb_cls); /** * Cancel a batch permission request. This function cannot be used @@ -671,8 +739,8 @@ DONAU_donor_receipts_to_statement ( * @param[in] the Batch Submit recipts handle */ void -DONAU_donor_receipts_to_statement_cancel ( - struct DONAU_DonorReceiptsToStatementHandle *); +DONAU_donation_statement_get_cancel ( + struct DONAU_DonationStatementGetHandle *); /* ********************* POST /csr batch-issue *********************** */ diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am @@ -28,7 +28,8 @@ libdonau_la_SOURCES = \ donau_api_curl_defaults.c donau_api_curl_defaults.h \ donau_api_batch_issue_receipts.c \ donau_api_batch_submit_receipts.c \ - donau_api_csr_post.c + donau_api_csr_post.c \ + donau_api_donation_statement_get.c ## maybe need libtalercurl libdonau_la_LIBADD = \ diff --git a/src/lib/donau_api_donation_statement_get.c b/src/lib/donau_api_donation_statement_get.c @@ -0,0 +1,256 @@ +/* + This file is part of TALER + Copyright (C) 2024 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/donau_api_donation_statement_get.c + * @brief Implementation of the "handle" component of the donau's HTTP API + * @author Lukas Matyja + */ +#include <gnunet/gnunet_curl_lib.h> +#include <taler/taler_json_lib.h> +#include "donau_service.h" +#include "donau_api_curl_defaults.h" +#include "donau_json_lib.h" + + +/** + * Handle for a GET /donation-statement/$YEAR/$HASH_DONOR_ID request. + */ +struct DONAU_DonationStatementGetHandle +{ + /** + * The url for the /donation-statement/$YEAR/$HASH_DONOR_ID request. + */ + char *url; + + /** + * Entry for this request with the `struct GNUNET_CURL_Context`. + */ + struct GNUNET_CURL_Job *job; + + /** + * Function to call with the result. + */ + DONAU_GetDonationStatmentResponseCallback cb; + + /** + * Salted and hashed donor id + */ + const struct DONAU_HashDonorTaxId *h_donor_tax_id; + + /** + * year + */ + uint64_t year; + + /** + * Closure to pass to @e cb. + */ + void *cb_cls; + +}; + + +/** + * Callback used when downloading the reply to a /donation-statement/$YEAR/$HASH_DONOR_ID request + * is complete. + * + * @param cls the `struct KeysRequest` + * @param response_code HTTP response code, 0 on error + * @param resp_obj parsed JSON result, NULL on error + */ +static void +handle_donation_statement_get_finished (void *cls, + long response_code, + const void *resp_obj) +{ + struct DONAU_DonationStatementGetHandle *dsgh = cls; + const json_t *j = resp_obj; + struct DONAU_DonationStatementResponse dsresp = { + .hr.reply = j, + .hr.http_status = (unsigned int) response_code + }; + + dsgh->job = NULL; + switch (response_code) + { + case 0: + dsresp.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + break; + case MHD_HTTP_OK: + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_fixed_auto ( + "donation_statement", + dsresp.details.ok.donation_statement_sig), + TALER_JSON_spec_amount_any ("total_amount", + &dsresp.details.ok.total_amount), + GNUNET_JSON_spec_end () + }; + if (GNUNET_OK != + GNUNET_JSON_parse (j, + spec, + NULL, + NULL)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not parse response from donation-statement GET\n"); + GNUNET_break_op (0); + dsresp.hr.http_status = 0; + dsresp.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + } + dsgh->cb (dsgh->cb_cls, + &dsresp); + dsgh->cb = NULL; + case MHD_HTTP_BAD_REQUEST: + /* This should never happen, either us or the donau is buggy + (or API version conflict); just pass JSON reply to the application */ + dsresp.hr.ec = TALER_JSON_get_error_code (j); + dsresp.hr.hint = TALER_JSON_get_error_hint (j); + break; + case MHD_HTTP_NOT_FOUND: + /* Nothing really to verify, this should never + happen, we should pass the JSON reply to the application */ + dsresp.hr.ec = TALER_JSON_get_error_code (j); + dsresp.hr.hint = TALER_JSON_get_error_hint (j); + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* Server had an internal issue; we should retry, but this API + leaves this to the application */ + dsresp.hr.ec = TALER_JSON_get_error_code (j); + dsresp.hr.hint = TALER_JSON_get_error_hint (j); + break; + default: + /* unexpected response code */ + GNUNET_break_op (0); + dsresp.hr.ec = TALER_JSON_get_error_code (j); + dsresp.hr.hint = TALER_JSON_get_error_hint (j); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u/%d for GET %s\n", + (unsigned int) response_code, + (int) dsresp.hr.ec, + dsgh->url); + break; + } + if (NULL != dsgh->cb) + { + dsgh->cb (dsgh->cb_cls, + &dsresp); + dsgh->cb = NULL; + } + DONAU_donation_statement_get_cancel (dsgh); +} + + +/** + * Prepares the request URL for the age-withdraw request + * + * @param awbh The handler + * @param donau_url The base-URL to the donau + */ +static +enum GNUNET_GenericReturnValue +prepare_url ( + struct DONAU_DonationStatementGetHandle *dsgh, + const char *donau_url) +{ + char arg_str[sizeof (struct DONAU_HashDonorTaxId) * 2 + 32]; + char donor_id_hash_str[sizeof (struct DONAU_HashDonorTaxId) * 2]; + char *end; + + end = GNUNET_STRINGS_data_to_string ( + &dsgh->h_donor_tax_id, + sizeof (struct DONAU_HashDonorTaxId), + donor_id_hash_str, + sizeof (donor_id_hash_str)); + *end = '\0'; + GNUNET_snprintf (arg_str, + sizeof (arg_str), + "donation-statement/%lu/%s", + dsgh->year, + donor_id_hash_str); + + dsgh->url = TALER_url_join (donau_url, + arg_str, + NULL); + if (NULL == dsgh->url) + { + GNUNET_break (0); + DONAU_donation_statement_get_cancel (dsgh); + return GNUNET_SYSERR; + } + + return GNUNET_OK; +} + + +struct DONAU_DonationStatementGetHandle * +DONAU_donation_statement_get ( + struct GNUNET_CURL_Context *ctx, + const char *url, // FIXME change the name of every api function call base url to donau_url. + const uint64_t year, + const struct DONAU_HashDonorTaxId *h_donor_tax_id, + DONAU_GetDonationStatmentResponseCallback cb, + void *cb_cls) +{ + struct DONAU_DonationStatementGetHandle *dsgh; + CURL *eh; + + TALER_LOG_DEBUG ("Connecting to the donau (%s)\n", + url); + dsgh = GNUNET_new (struct DONAU_DonationStatementGetHandle); + // dsgh->url = GNUNET_strdup (url); + dsgh->cb = cb; + dsgh->cb_cls = cb_cls; + dsgh->year = year; + dsgh->h_donor_tax_id = h_donor_tax_id; + if (GNUNET_OK != prepare_url (dsgh, + url)) + return NULL; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Requesting a charity with URL `%s'.\n", + dsgh->url); + eh = DONAU_curl_easy_get_ (dsgh->url); + if (NULL == eh) + { + GNUNET_break (0); + GNUNET_free (dsgh->url); + GNUNET_free (dsgh); + return NULL; + } + dsgh->job = GNUNET_CURL_job_add_with_ct_json (ctx, + eh, + & + handle_donation_statement_get_finished, + dsgh); + return dsgh; +} + + +void +DONAU_donation_statement_get_cancel ( + struct DONAU_DonationStatementGetHandle *dsgh) +{ + if (NULL != dsgh->job) + { + GNUNET_CURL_job_cancel (dsgh->job); + dsgh->job = NULL; + } + GNUNET_free (dsgh->url); + GNUNET_free (dsgh); +}